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 + -
显示快捷键?