http-proto.c

来自「Serveez是一个服务器框架」· C语言 代码 · 共 1,324 行 · 第 1/3 页

C
1,324
字号
/* * http-proto.c - http protocol implementation * * Copyright (C) 2000, 2001 Stefan Jahn <stefan@lkcc.org> * * This 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. *  * This software 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 this package; see the file COPYING.  If not, write to * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA.   * * $Id: http-proto.c,v 1.76 2001/09/13 13:28:54 ela Exp $ * */#if HAVE_CONFIG_H# include <config.h>#endif#if ENABLE_HTTP_PROTO#define _GNU_SOURCE#include <assert.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <errno.h>#include <time.h>#if HAVE_STRINGS_H# include <strings.h>#endif#if HAVE_UNISTD_H# include <unistd.h>#endif#ifdef __MINGW32__# include <winsock2.h># include <io.h>#endif#ifndef __MINGW32__# include <sys/types.h># include <sys/socket.h># include <netinet/in.h>#endif#include "libserveez.h"#include "http-proto.h"#include "http-core.h"#include "http-cgi.h"#include "http-dirlist.h"#include "http-cache.h"/* * The HTTP server instance configuration. */http_config_t http_config ={  "index.html",       /* standard index file  for GET request */  "../show",          /* document root */  "/cgi-bin",         /* how cgi-requests are detected */  "./cgibin",         /* cgi script root */  MAX_CACHE_SIZE,     /* maximum file size to cache them */  MAX_CACHE,          /* maximum amount of cache entries */  HTTP_TIMEOUT,       /* server shuts connection down after x seconds */  HTTP_MAXKEEPALIVE,  /* how many files when using keep-alive */  "text/plain",       /* standard content type */  "/etc/mime.types",  /* standard content type file */  NULL,               /* current content type hash */  NULL,               /* cgi application associations */  "root@localhost",   /* email address of server administrator */  NULL,               /* host name of which is sent back to clients */  "public_html",      /* appended onto a user's home (~user request) */  0,                  /* enable reverse DNS lookups */  0,                  /* enable identd requests */  "http-access.log",  /* log file name */  HTTP_CLF,           /* custom log file format string */  NULL                /* log file stream */};/* * Definition of the configuration items processed by the configuration * callbacks. */svz_key_value_pair_t http_config_prototype[] ={  SVZ_REGISTER_STR ("indexfile", http_config.indexfile, SVZ_ITEM_DEFAULTABLE),  SVZ_REGISTER_STR ("docs", http_config.docs, SVZ_ITEM_DEFAULTABLE),  SVZ_REGISTER_STR ("cgi-url", http_config.cgiurl, SVZ_ITEM_DEFAULTABLE),  SVZ_REGISTER_STR ("cgi-dir", http_config.cgidir, SVZ_ITEM_DEFAULTABLE),  SVZ_REGISTER_INT ("cache-size", http_config.cachesize, SVZ_ITEM_DEFAULTABLE),  SVZ_REGISTER_INT ("cache-entries", http_config.cacheentries, 		    SVZ_ITEM_DEFAULTABLE),  SVZ_REGISTER_INT ("timeout", http_config.timeout, SVZ_ITEM_DEFAULTABLE),  SVZ_REGISTER_INT ("keepalive", http_config.keepalive, SVZ_ITEM_DEFAULTABLE),  SVZ_REGISTER_STR ("default-type", http_config.default_type, 		    SVZ_ITEM_DEFAULTABLE),  SVZ_REGISTER_STR ("type-file", http_config.type_file, SVZ_ITEM_DEFAULTABLE),  SVZ_REGISTER_HASH ("types", http_config.types, SVZ_ITEM_DEFAULTABLE),  SVZ_REGISTER_HASH ("cgi-application", http_config.cgiapps, 		     SVZ_ITEM_DEFAULTABLE),  SVZ_REGISTER_STR ("admin", http_config.admin, SVZ_ITEM_DEFAULTABLE),  SVZ_REGISTER_STR ("host", http_config.host, SVZ_ITEM_DEFAULTABLE),  SVZ_REGISTER_STR ("logfile", http_config.logfile, SVZ_ITEM_DEFAULTABLE),  SVZ_REGISTER_STR ("logformat", http_config.logformat, SVZ_ITEM_DEFAULTABLE),  SVZ_REGISTER_STR ("userdir", http_config.userdir, SVZ_ITEM_DEFAULTABLE),  SVZ_REGISTER_BOOL ("nslookup", http_config.nslookup, SVZ_ITEM_DEFAULTABLE),  SVZ_REGISTER_BOOL ("ident", http_config.ident, SVZ_ITEM_DEFAULTABLE),  SVZ_REGISTER_END ()};/* * Definition of the http server. */svz_servertype_t http_server_definition ={  "http server",         /* long server description */  "http",                /* short server description */  http_global_init,      /* global initializer */  http_init,             /* instance initializer */  http_detect_proto,     /* protocol detection routine */  http_connect_socket,   /* connection routine */  http_finalize,         /* instance finalization routine */  http_global_finalize,  /* global finalizer */  http_info_client,      /* client info */  http_info_server,      /* server info */  NULL,                  /* server timer */  NULL,                  /* handle request callback */  &http_config,          /* default configuration */  sizeof (http_config),  /* size of the configuration */  http_config_prototype  /* configuration prototypes */};/* * HTTP request types, their identification string (including its length) * and the appropriate callback routine itself. This array is used in * the HTTP_HANDLE_REQUEST function. */struct{  char *ident;                                  /* identification string */  int len;                                      /* the length of this string */  int (*response)(svz_socket_t *, char *, int); /* the callback routine */} http_request [HTTP_REQUESTS] = {  { "GET",     3, http_get_response     },  { "HEAD",    4, http_head_response    },  { "POST",    4, http_post_response    },  { "PUT",     3, http_default_response },  { "OPTIONS", 7, http_default_response },  { "DELETE",  6, http_default_response },  { "TRACE",   5, http_default_response },  { "CONNECT", 7, http_default_response }};/* * Global http server initializer. */inthttp_global_init (svz_servertype_t *server){#ifdef __MINGW32__  http_start_netapi ();#endif /* __MINGW32__ */  http_alloc_cache (MAX_CACHE);  return 0;}/* * Global http server finalizer. */inthttp_global_finalize (svz_servertype_t *server){  http_free_cache ();#ifdef __MINGW32__  http_stop_netapi ();#endif /* __MINGW32__ */  return 0;}/* * Local http server instance initializer. */inthttp_init (svz_server_t *server){  int types = 0;  char *p;  unsigned long host = INADDR_ANY;  http_config_t *cfg = server->cfg;  svz_array_t *ports;  struct sockaddr_in *addr;  /* resolve localhost if server name is not set */  if (!cfg->host)    {      if ((ports = svz_server_portcfg (server)) != NULL)	{	  addr = svz_portcfg_addr ((svz_portcfg_t *) svz_array_get (ports, 0));	  host = addr->sin_addr.s_addr;	  svz_array_destroy (ports);	}      if (host == INADDR_ANY)	host = htonl (INADDR_LOOPBACK);      svz_coserver_rdns (host, http_localhost, cfg, NULL);    }  /* start http logging system */  if (cfg->logfile)    {      if ((cfg->log = svz_fopen (cfg->logfile, "at")) == NULL)	{	  svz_log (LOG_ERROR, "http: cannot open access logfile %s\n",		   cfg->logfile);	}    }    /* create content type hash */  if (cfg->types)    types = svz_hash_size (cfg->types);    if (http_read_types (cfg))    {      svz_log (LOG_ERROR, "http: unable to load %s\n", cfg->type_file);    }  svz_log (LOG_NOTICE, "http: %d+%d known content types\n",	   types, svz_hash_size (cfg->types) - types);  /* check user directory path, snip trailing '/' or '\' */  if (!cfg->userdir || !strlen (cfg->userdir))    {      svz_log (LOG_ERROR, "http: not a valid user directory\n");      return -1;    }  p = cfg->userdir + strlen (cfg->userdir) - 1;  if (*p == '/' || *p == '\\')    *p = '\0';  /* check document root path */  if (!strlen (cfg->docs))    {      svz_log (LOG_ERROR, "http: not a valid document root\n");      return -1;    }  /* checking whether http doc root path ends in '/' or '\'. */  p = cfg->docs + strlen (cfg->docs) - 1;  if (*p == '/' || *p == '\\')    *p = '\0';  if (cfg->cacheentries > 0)    http_alloc_cache (cfg->cacheentries);  /* generate cgi associations */  http_gen_cgi_apps (cfg);    return 0;}/* * Local http server instance finalizer. */inthttp_finalize (svz_server_t *server){  http_config_t *cfg = server->cfg;  if (cfg->log)    svz_fclose (cfg->log);  return 0;}/* * This function frees all HTTP request properties previously reserved * and frees the cache structure if necessary. Nevertheless the  * socket structure SOCK should still be usable for keep-alive connections. */voidhttp_free_socket (svz_socket_t *sock){  http_socket_t *http = sock->data;  int n;  /* log this entry and free the request string */  http_log (sock);  if (http->request)    {      svz_free (http->request);      http->request = NULL;    }  http->timestamp = 0;  http->response = 0;  http->length = 0;  /* any property at all ? */  if (http->property)    {      /* go through all properties */      n = 0;      while (http->property[n])	{	  svz_free (http->property[n]);	  n++;	}      svz_free (http->property);      http->property = NULL;    }  /* decrement usage counter of the cache entry */  if (sock->userflags & HTTP_FLAG_CACHE)    {      http->cache->entry->usage--;    }  /* is the cache entry used ? */  if (http->cache)    svz_free_and_zero (http->cache);  /* close the file descriptor for usual http file transfer */  if (sock->file_desc != -1)    {      if (svz_close (sock->file_desc) == -1)	svz_log (LOG_ERROR, "close: %s\n", SYS_ERROR);      sock->file_desc = -1;    }}/* * Disconnects a HTTP connection. Callback routine for the * socket structure entry "disconnected_socket". */inthttp_disconnect (svz_socket_t *sock){  /* get http socket structure */  http_socket_t *http = sock->data;  /* free the http socket structures */  http_free_socket (sock);  if (http)    {      if (http->host)	svz_free (http->host);      if (http->ident)	svz_free (http->ident);      svz_free (http);      sock->data = NULL;    }  return 0;}/* * Idle function for HTTP Keep-Alive connections. It simply returns -1 * if a certain time has elapsed and the main server loop will shutdown * the connection therefore. */inthttp_idle (svz_socket_t *sock){  time_t now;  http_config_t *cfg = sock->cfg;  now = time (NULL);  if (now - sock->last_recv > cfg->timeout &&      now - sock->last_send > cfg->timeout)    return -1;  sock->idle_counter = 1;  return http_cgi_died (sock);}#if ENABLE_SENDFILE#if defined (HAVE_SENDFILE) || defined (__MINGW32__)/* * This routine is using sendfile() to transport large file's content * to a network socket. It is replacing HTTP_DEFAULT_WRITE on systems where * this function is implemented. Furthermore you do not need to set * the READ_SOCKET callback HTTP_FILE_READ. */inthttp_send_file (svz_socket_t *sock){  http_socket_t *http = sock->data;  int num_written, do_write;  /* Limitate the number of bytes to write at once. */  do_write = http->filelength > SOCK_MAX_WRITE     ? SOCK_MAX_WRITE : http->filelength;  /* Try sending throughout file descriptor to socket. */  num_written = svz_sendfile (sock->sock_desc, sock->file_desc,			      &http->fileoffset, do_write);  /* Some error occurred. */  if (num_written < 0)    {      svz_log (LOG_ERROR, "http: sendfile: %s\n", SYS_ERROR);      return -1;    }  /* Bogus file. File size from stat() was not true. */  if (num_written == 0 && http->filelength != 0)    {      return -1;    }  /* Data has been read or EOF reached, set the appropriate flags. */  http->filelength -= num_written;  http->length += num_written;  /* Read all file data ? */  if (http->filelength <= 0)    {#if ENABLE_DEBUG      svz_log (LOG_DEBUG, "http: file successfully sent\n");#endif      /*        * no further read()s from the file descriptor, signaling        * the writers there will not be additional data from now on       */      sock->read_socket = svz_tcp_read_socket;      sock->recv_buffer_fill = 0;

⌨️ 快捷键说明

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