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