http.c

来自「开放源码实时操作系统源码.」· C语言 代码 · 共 1,057 行 · 第 1/3 页

C
1,057
字号
/* =================================================================
 *
 *      http.c
 *
 *      Handles the client requests.
 *
 * ================================================================= 
 * ####ECOSGPLCOPYRIGHTBEGIN####
 * -------------------------------------------
 * This file is part of eCos, the Embedded Configurable Operating
 * System.
 * Copyright (C) 2005, 2007 eCosCentric Ltd.
 * 
 * eCos is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 or (at your option)
 * any later version.
 * 
 * eCos is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with eCos; if not, write to the Free Software Foundation,
 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
 * 
 * As a special exception, if other files instantiate templates or
 * use macros or inline functions from this file, or you compile this
 * file and link it with other works to produce a work based on this
 * file, this file does not by itself cause the resulting work to be
 * covered by the GNU General Public License. However the source code
 * for this file must still be made available in accordance with
 * section (3) of the GNU General Public License.
 * 
 * This exception does not invalidate any other reasons why a work
 * based on this file might be covered by the GNU General Public
 * License.
 *
 * -------------------------------------------
 * ####ECOSGPLCOPYRIGHTEND####
 * =================================================================
 * #####DESCRIPTIONBEGIN####
 * 
 *  Author(s):    Anthony Tonizzo (atonizzo@gmail.com)
 *  Contributors: Sergei Gavrikov (w3sg@SoftHome.net)
 *                Lars Povlsen    (lpovlsen@vitesse.com)
 *  Date:         2006-06-12
 *  Purpose:      
 *  Description:  
 *               
 * ####DESCRIPTIONEND####
 * 
 * =================================================================
 */

#include <pkgconf/hal.h>
#include <pkgconf/kernel.h>
#include <cyg/kernel/kapi.h>           // Kernel API.
#include <cyg/infra/diag.h>            // For diagnostic printing.
#include <network.h>
#include <time.h>

#include <cyg/hal/hal_tables.h>
#include <cyg/fileio/fileio.h>
#include <stdio.h>                     // sprintf().
#include <stdlib.h>

#ifdef CYGOPT_NET_ATHTTPD_USE_CGIBIN_OBJLOADER
#include <cyg/objloader/elf.h>
#include <cyg/objloader/objelf.h>
#endif

#include <cyg/athttpd/http.h>
#include <cyg/athttpd/socket.h>
#include <cyg/athttpd/handler.h>
#include <cyg/athttpd/forms.h>

cyg_int32 debug_print = 0;

const char *day_of_week[7] = {"Sun", "Mon", "Tue", "Wed", 
                                 "Thu", "Fri", "Sat"};
const char *month_of_year[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", 
                                    "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
const char *home_pages[] = {"index.html",   "index.htm",
                            "default.html", "home.html"};
CYG_HAL_TABLE_BEGIN(cyg_httpd_mime_table, httpd_mime_table);
CYG_HAL_TABLE_END(cyg_httpd_mime_table_end, httpd_mime_table);

__externC cyg_httpd_mime_table_entry cyg_httpd_mime_table[];
__externC cyg_httpd_mime_table_entry cyg_httpd_mime_table_end[];

// Standard handlers added by default. Correspond to the most used extensions.
// The user can add his/her own later.
CYG_HTTPD_MIME_TABLE_ENTRY(hal_htm_entry, "htm",
                                       "text/html; charset=iso-8859-1");
CYG_HTTPD_MIME_TABLE_ENTRY(hal_html_entry, "html", 
                                       "text/html; charset=iso-8859-1");
CYG_HTTPD_MIME_TABLE_ENTRY(hal_gif_entry, "gif", "image/gif");
CYG_HTTPD_MIME_TABLE_ENTRY(hal_jpg_entry, "jpg", "image/jpg");
CYG_HTTPD_MIME_TABLE_ENTRY(hal_png_entry, "png", "image/png");
CYG_HTTPD_MIME_TABLE_ENTRY(hal_css_entry, "css", "text/css");
CYG_HTTPD_MIME_TABLE_ENTRY(hal_js_entry, "js", "application/x-javascript");

void 
cyg_httpd_send_error(cyg_int32 err_type)
{
    httpstate.status_code = err_type;
    
    // Errors pages close the socket and are never cached.
    httpstate.mode |= CYG_HTTPD_MODE_NO_CACHE;

#if CYGOPT_NET_ATHTTPD_DEBUG_LEVEL > 1
    diag_printf("Sending error: %d\n", err_type);
#endif    

#ifdef CYGOPT_NET_ATHTTPD_USE_FS
    // Check if the user has defines his own error pages.
    struct stat sp;
    char file_name[CYG_HTTPD_MAXPATH];
    strcpy(file_name, CYGDAT_NET_ATHTTPD_SERVEROPT_ROOTDIR);
    if (file_name[strlen(file_name)-1] != '/')
        strcat(file_name, "/");
    strcat(file_name, CYGDAT_NET_ATHTTPD_SERVEROPT_ERRORDIR);
    if (file_name[strlen(file_name)-1] != '/')
        strcat(file_name, "/");
    sprintf(file_name + strlen(file_name), "error_%d.html", err_type);
    cyg_httpd_cleanup_filename(file_name);
    cyg_int32 rc = stat(file_name, &sp);
    if (rc == 0)
    {
        char *extension = rindex(file_name, '.');
        if (extension == NULL)
            // No extension in the file name.
            httpstate.mime_type = 0;
        else
            httpstate.mime_type = cyg_httpd_find_mime_string(++extension);

        httpstate.payload_len  = sp.st_size;
        cyg_int32 header_length = cyg_httpd_format_header();
        cyg_httpd_write(httpstate.outbuffer, header_length);
    
        // File found.
        FILE *fp = fopen(file_name, "r");
        if(fp == NULL)
            return;

        ssize_t payload_size = fread(httpstate.outbuffer, 
                                     1, 
                                     CYG_HTTPD_MAXOUTBUFFER, 
                                     fp);
        while (payload_size > 0)
        {
            ssize_t bytes_written = cyg_httpd_write_chunked(httpstate.outbuffer, 
                                                            payload_size);
            if (bytes_written != payload_size)
                break;

            payload_size = fread(httpstate.outbuffer, 
                                 1, 
                                 CYG_HTTPD_MAXOUTBUFFER, 
                                 fp);
        }

        fclose(fp);
        return;
    }
#endif    

    // Because the size of the frame is not known upfront (every error message
    //  is different and thus has different length) we use chunked frames to
    //  send the message out.
#if defined(CYGOPT_NET_ATHTTPD_CLOSE_CHUNKED_CONNECTIONS)
    httpstate.mode |= CYG_HTTPD_MODE_CLOSE_CONN;
#endif
    
    httpstate.mode |= CYG_HTTPD_MODE_TRANSFER_CHUNKED;
    httpstate.status_code = err_type;
    httpstate.last_modified = -1;
    httpstate.mime_type = "text/html";
    cyg_int32 header_length = cyg_httpd_format_header();
    cyg_httpd_write(httpstate.outbuffer, header_length);
    
    // If no file has been defined, send a simple notification. We must use
    //  chunked frames, because we do not know upfron the length of the
    //  packet we have to send.
    strcpy(httpstate.outbuffer,
           "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\r\n");
    switch (err_type)
    {
    case CYG_HTTPD_STATUS_MOVED_PERMANENTLY:
        strcat(httpstate.outbuffer,
               "<html><head><title>301 Moved Permanently</title></head>\r\n"
               "<body><h1>Moved Permanently</h1>\r\n"
               "<p>The document has moved <a href=\"");
        strcat(httpstate.outbuffer, httpstate.url);
        strcat(httpstate.outbuffer, "\">here</a>.\r\n");
        break;
    case CYG_HTTPD_STATUS_MOVED_TEMPORARILY:
        strcat(httpstate.outbuffer, 
               "<html><head><title>302 Found</title></head>\r\n"
               "<body><h1>Redirect</h1>\r\n"
               "<p>Please continue <a href=\"");
        strcat(httpstate.outbuffer, httpstate.url);
        strcat(httpstate.outbuffer, "\">here</a>.\r\n");
        break;
    case CYG_HTTPD_STATUS_NOT_AUTHORIZED:
        strcat(httpstate.outbuffer, 
               "<html><head><title>401 Not Authorized</title></head>\r\n");
        strcat(httpstate.outbuffer, 
               "<body><p>Authorization required to access this URL.</p>\r\n");
        break;    
    case CYG_HTTPD_STATUS_NOT_MODIFIED:
        cyg_httpd_end_chunked();
        return;
    case CYG_HTTPD_STATUS_NOT_FOUND:
        strcat(httpstate.outbuffer, 
               "<html><head><title>404 Not Found</title></head>\r\n");
        sprintf(httpstate.outbuffer + strlen(httpstate.outbuffer),
                "<p>The requested URL: %s was not found on this server</p>\r\n",
                httpstate.url);
        break;
    case CYG_HTTPD_STATUS_SYSTEM_ERROR:
        strcat(httpstate.outbuffer, 
               "<html><head><title>500 Server Error</title></head>\r\n");
        strcat(httpstate.outbuffer, 
               "<p>The server encountered an unexpected condition that "
               "prevented it from fulfilling the request"
               " by the client</p>\r\n");
        break;
    case CYG_HTTPD_STATUS_NOT_IMPLEMENTED:
        strcat(httpstate.outbuffer, 
               "<html><head><title>501 Not Implemented</title></head>\r\n");
        strcat(httpstate.outbuffer, 
               "<p>The method requested is not implemented</p>\r\n");
        break;
    default:
        strcat(httpstate.outbuffer, 
               "<html><head><title>400 Bad Request</title></head>\r\n");
        strcat(httpstate.outbuffer, 
               "<p>Bad request</p>\r\n");
        break;
    }
    
    sprintf(httpstate.outbuffer + strlen(httpstate.outbuffer),
            "<hr>%s at %d.%d.%d.%d Port %d\r\n</body></html>\r\n",
            CYGDAT_NET_ATHTTPD_SERVEROPT_SERVERID,
            httpstate.host[0],
            httpstate.host[1],
            httpstate.host[2],
            httpstate.host[3],
            CYGNUM_NET_ATHTTPD_SERVEROPT_PORT);
    
    cyg_httpd_write_chunked(httpstate.outbuffer, strlen(httpstate.outbuffer));
    cyg_httpd_end_chunked();
}

// Return a time_t that is always UTC (aka GMT).
time_t
cyg_httpd_parse_date(char *time)
{
    int    i;
    char   month[4];
    struct tm tm_mod;

    // We are going to get rid of the day of the week. This is always the first
    //  part of the string, separated by a blank.
    time = strchr( time, ' ');
    if ( time == NULL)
        return 0;
    time++;

    /// RFC1123. The date is in the format: Sun, 06 Nov 1994 08:49:37 GMT.
    cyg_int32 rc = sscanf(time,
                          "%2d %3s %4d %2d:%2d:%2d GMT",
                          &tm_mod.tm_mday,
                          month,
                          &tm_mod.tm_year,
                          &tm_mod.tm_hour,
                          &tm_mod.tm_min,
                          &tm_mod.tm_sec);
    if (rc != 6)
    {
        // RFC1036. The date is in the format: Sunday, 06-Nov-94 08:49:37 GMT.
        rc = sscanf(time,
                    "%2d-%3s-%2d %2d:%2d:%2d GMT",
                    &tm_mod.tm_mday,
                    month,
                    &tm_mod.tm_year,
                    &tm_mod.tm_hour,
                    &tm_mod.tm_min,
                    &tm_mod.tm_sec);
        if (rc != 6)
        {
            // asctime() in the stdlibc library.
            // The date is in the format: Sun Nov 6 08:49:37 1994
            //  and needs to be converted to GMT.
            rc = sscanf(time,"%3s %2d %2d:%2d:%2d %4d",
                        month,
                        &tm_mod.tm_mday,
                        &tm_mod.tm_hour,
                        &tm_mod.tm_min,
                        &tm_mod.tm_sec,
                        &tm_mod.tm_year);
            if (rc != 6)
                return 0;
        }
    }

    for (i = 0; i < sizeof(month_of_year); i++)
        if (strcmp(month, month_of_year[i]) == 0)
        {
            tm_mod.tm_mon = i;
            if (tm_mod.tm_year > 1900)
                tm_mod.tm_year -= 1900;
            return mktime(&tm_mod);
        }

    return 0;
}

// Finds the mime string into the mime_table associated with a specific 
//  extension. Returns the MIME type to send in the header, or NULL if the
//  extension is not in the table.
char*
cyg_httpd_find_mime_string(char *ext)
{
    cyg_httpd_mime_table_entry *entry = cyg_httpd_mime_table;

    while (entry != cyg_httpd_mime_table_end)
    {
        if (!strcmp((const char*)ext, entry->extension))
            return entry->mime_string;
        entry++;
    }
            
    return (char*)0;
}

void
cyg_httpd_cleanup_filename(char *filename)
{
    char *src = strstr(filename, "//");
    while (src != 0)
    {
        strcpy(src + 1, src + 2);
        src = strstr(filename, "//");
    }

    src = strstr(filename, "/./");
    while (src != 0)
    {
        strcpy(src + 1, src + 3);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?