⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 http-core.c

📁 Serveez是一个服务器框架
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * http-core.c - http core functionality * * 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-core.c,v 1.42 2001/08/03 18:09:04 ela Exp $ * */#if HAVE_CONFIG_H# include <config.h>#endif#if ENABLE_HTTP_PROTO#define _GNU_SOURCE#include <stdio.h>#include <stdlib.h>#include <string.h>#include <errno.h>#include <time.h>#include <sys/types.h>#if HAVE_UNISTD_H# include <unistd.h>#endif#if HAVE_PWD_H && !defined (__MINGW32__)# include <pwd.h>#endif#ifndef __MINGW32__# include <netinet/in.h>#endif#ifdef __MINGW32__# include <winsock2.h># include <io.h># include <lm.h># include <lmerr.h>#endif#include "libserveez.h"#include "http-proto.h"#include "http-core.h"/* the current http header structure */http_header_t http_header;/* * In Win32 OS's both of these defines are necessary for portability. */#if defined (__CYGWIN__) || defined (__MINGW32__)# define timezone _timezone# ifndef daylight#  define daylight _daylight# endif#elif !HAVE_TIMEZONE/* * For some reason FreeBSD 3.2 does not provide `timezone' and `daylight'. */# define timezone ((long int) 0)# define daylight ((int) 0)#endif#ifdef __MINGW32__/*  * Handle and function definitions for the NetApi interface.  */typedef NET_API_STATUS (__stdcall *GetUserInfoProc) (WCHAR *, WCHAR *,						     DWORD, LPBYTE *);typedef NET_API_STATUS (__stdcall *FreeUserInfoProc) (void *);static FreeUserInfoProc FreeUserInfo = NULL;static GetUserInfoProc GetUserInfo = NULL;static HMODULE netapiHandle = NULL;/*  * Unload the `netapi32.dll'. */voidhttp_stop_netapi (void){  if (netapiHandle)    {      FreeLibrary (netapiHandle);      netapiHandle = NULL;    }}/*  * Load `netapi32.dll' and get function pointers necessary to obtain * a user's home directory. */voidhttp_start_netapi (void){  if ((netapiHandle = LoadLibrary ("netapi32.dll")) != NULL)    {      FreeUserInfo = (FreeUserInfoProc) 	GetProcAddress (netapiHandle, "NetApiBufferFree");      GetUserInfo = (GetUserInfoProc) 	GetProcAddress (netapiHandle, "NetUserGetInfo");      if (GetUserInfo == NULL)	{	  svz_log (LOG_ERROR, "http: GetProcAddress: %s\n", SYS_ERROR);	  FreeLibrary (netapiHandle);	  netapiHandle = NULL;	}    }}#endif /* not __MINGW32__ *//* * If the given request has a leading `~' we try to get the appropriate * user's home directory and put it in front of the request. */char *http_userdir (svz_socket_t *sock, char *uri){  http_config_t *cfg = sock->cfg;  char *p = uri + 1;  char *user, *file;#if HAVE_GETPWNAM  struct passwd *entry;#elif defined (__MINGW32__)  USER_INFO_1 *entry = NULL;  NET_API_STATUS status;#endif  if (*uri && *p++ == '~' && cfg->userdir)    {      /* parse onto end of user name */      while (*p && *p != '/')	p++;      if (p - uri <= 2)	return NULL;      user = svz_malloc (p - uri - 1);      memcpy (user, uri + 2, p - uri - 2);      user[p - uri - 2] = '\0';      #if HAVE_GETPWNAM      if ((entry = getpwnam (user)) != NULL)	{	  file = svz_malloc (strlen (entry->pw_dir) + strlen (cfg->userdir) + 			     strlen (p) + 2);	  sprintf (file, "%s/%s%s", entry->pw_dir, cfg->userdir, p);	  svz_free (user);	  return file;	}#elif defined (__MINGW32__)      if (GetUserInfo == NULL)	{	  svz_free (user);	  return NULL;	}      status = GetUserInfo (NULL,                       /* server name */			    svz_windoze_asc2uni (user), /* user name */			    1,                          /* type of info */			    (LPBYTE *) &entry);         /* info buffer */      if (status != NERR_Success)	{	  char *error;	  switch (status)	    {	    case ERROR_ACCESS_DENIED:	      error = "The user does not have access to the requested "		"information.";	      break;	    case NERR_InvalidComputer:	      error = "The computer name is invalid.";	      break;	    case NERR_UserNotFound:	      error = "The user name could not be found.";	      break;	    default:	      error = "Unknown error.";	      break;	    }	  svz_log (LOG_ERROR, "NetUserGetInfo: %s\n", error);	}      /* successfully got the user information ? */      else if (entry && entry->usri1_home_dir && entry->usri1_home_dir[0])	{	  file = 	    svz_malloc (strlen (svz_windoze_uni2asc (entry->usri1_home_dir)) +			strlen (cfg->userdir) + strlen (p) + 2);	  sprintf (file, "%s/%s%s", 		   svz_windoze_uni2asc (entry->usri1_home_dir), 		   cfg->userdir, p);	  FreeUserInfo (entry);	  svz_free (user);	  return file;	}#if ENABLE_DEBUG      else if (entry)	{	  svz_log (LOG_DEBUG, "http: home directory for %s not set\n",		   svz_windoze_uni2asc (entry->usri1_name));	}#endif /* ENABLE_DEBUG */#endif /* not HAVE_GETPWNAM and not __MINGW32__ */      svz_free (user);    }  return NULL;}/* * When the http server has been configured to invoke identd request * this function is called for each client connection after successful * identification. */inthttp_identification (char *ident, int id, int version){  http_socket_t *http;  svz_socket_t *sock = svz_sock_find (id, version);  if (ident && sock)    {      http = sock->data;      if (!http->ident)	http->ident = svz_strdup (ident);    }   return 0;}/* * Each http client gets resolved by this callback. */inthttp_remotehost (char *host, int id, int version){  http_socket_t *http;  svz_socket_t *sock = svz_sock_find (id, version);  if (host && sock)    {      http = sock->data;      if (!http->host)	http->host = svz_strdup (host);    }   return 0;}/* * When the localhost has been resolved to a hostname this callback is * invoked by the main loop. Put the result into the http configuration. */inthttp_localhost (char *host, http_config_t *cfg){  if (host && !cfg->host)    {      cfg->host = svz_pstrdup (host);    }  return 0;}/* * Write a logging notification to the access logfile if possible * and necessary. */voidhttp_log (svz_socket_t *sock){  http_config_t *cfg = sock->cfg;  http_socket_t *http = sock->data;  static char line[1024];  char *referrer, *agent, *p, *start;  if (cfg->log && http->request)    {      referrer = http_find_property (http, "Referer");      agent = http_find_property (http, "User-Agent");      /* access logging format given ? */      if (cfg->logformat && *cfg->logformat)	start = cfg->logformat;      else	start = HTTP_CLF;      memset (line, 0, sizeof (line));      while (*start)	{	  /* parse until next format character */	  p = start;	  while (*p && *p != '%')	    p++;	  strncat (line, start, p - start);	  if (!*p)	    break;	  p++;	  switch (*p)	    {	      /* %i - identity information */	    case 'i':	      strcat (line, http->ident ? http->ident : "-");	      p++;	      break;	      /* %u - user authentication */	    case 'u':	      strcat (line, http->auth ? http->auth : "-");	      p++;	      break;	      /* %l - delivered content length */	    case 'l':	      strcat (line, svz_itoa (http->length));	      p++;	      break;	      /* %c - http response code */	    case 'c':	      strcat (line, svz_itoa (http->response));	      p++;	      break;	      /* %h - host name */	    case 'h':	      strcat (line, http->host ? http->host :		      svz_inet_ntoa (sock->remote_addr));	      p++;	      break;	      /* %t - request time stamp */	    case 't':	      strcat (line, http_clf_date (http->timestamp));	      p++;	      break;	      /* end of string */	    case '\0':	      break;	      /* %R - original http request uri */	    case 'R':	      strcat (line, http->request ? http->request : "-");	      p++;	      break;	      /* %r - referrer document */	    case 'r':	      strcat (line, referrer ? referrer : "-");	      p++;	      break;	      /* %a - user agent */	    case 'a':	      strcat (line, agent ? agent : "-");	      p++;	      break;	    default:	      p++;	      break;	    }	  start = p;	}      strcat (line, "\n");      if (!ferror (cfg->log) && !feof (cfg->log))	{	  fprintf (cfg->log, line);	  fflush (cfg->log);	}      else	{	  svz_log (LOG_ERROR, "http: access logfile died\n");	  svz_fclose (cfg->log);	  cfg->log = NULL;	}    }}/* * Reset the current http header structure. */voidhttp_reset_header (void){  http_header.code = 0;  http_header.field[0] = '\0';  http_header.response = NULL;}/* * Add a response header field to the current header. */voidhttp_add_header (const char *fmt, ...){  va_list args;  int len = strlen (http_header.field);  char *p = http_header.field + len;    if (len >= HTTP_HEADER_SIZE)    return;  va_start (args, fmt);  svz_vsnprintf (p, HTTP_HEADER_SIZE - len, fmt, args);  va_end (args);}/* * Send the http header. */inthttp_send_header (svz_socket_t *sock){  int ret = 0;  /* send first part of header including response field and static texts */  ret = svz_sock_printf (sock, 			 "%s"			 "Date: %s\r\n"			 "Server: %s/%s\r\n",			 http_header.response,			 http_asc_date (time (NULL)),			 svz_library, svz_version);  if (ret)    return ret;  /* send header fields and trailing line break */  ret = svz_sock_printf (sock, "%s\r\n", http_header.field);  if (ret)    return ret;    return 0;}/* * Set the current http header response. */voidhttp_set_header (char *response){  http_header.response = response;}/* * Create a http content range if the given line specifies a valid one. * Return zero on success and -1 on errors. */inthttp_get_range (char *line, http_range_t *range){  char *p = line;  off_t n;  /* parse until byte-range specifier */   if (!line || !range)    return -1;  while (*p && *p != ':')    p++;  if (!*p || *(p + 1) != ' ')    return -1;  p += 2;  /* check identifier */  if (memcmp (p, "bytes", 5))    {#if ENABLE_DEBUG      svz_log (LOG_DEBUG, "http: invalid byte-range specifier (%s)\n", p);#endif      return -1;    }  p += 5;  /* parse content range itself */  range->first = range->last = range->length = 0;  if (*p != '=')    return 0;  p++;  n = 0;   while (*p >= '0' && *p <= '9')    {       n *= 10;       n += (*p - '0');       p++;     }  range->first = n;  if (*p != '-')    return 0;   p++;  n = 0;   while (*p >= '0' && *p <= '9')     {       n *= 10;       n += (*p - '0');       p++;     }  range->last = n;  if (*p != '/')     return 0;   p++;  n = 0;   while (*p >= '0' && *p <= '9')     {       n *= 10;       n += (*p - '0');       p++;     }  range->length = n;  return 0;}/* * Send an error message response body to the http client connection. * This is not actually necessary, because an appropriate response header * should work out fine. But most browsers indicate "document contained * not data." if this occurs. */inthttp_error_response (svz_socket_t *sock, int response){  http_config_t *cfg = sock->cfg;  http_socket_t *http = sock->data;  char *txt;  /* Convert error code to text. */  switch (response)    {    case 400:      txt = "Bad Request";      break;    case 401:      txt = "Unauthorized";      break;    case 402:      txt = "Payment Required";

⌨️ 快捷键说明

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