http-proto.c

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

C
1,324
字号
	   cfg->indexfile,	   cfg->docs,	   cfg->cgiurl,	   cfg->cgidir,	   cfg->cachesize,	   cfg->cacheentries,	   cfg->timeout,	   cfg->keepalive,	   cfg->default_type,	   cfg->type_file,	   svz_hash_size (cfg->types));  return info;}/* * Client info callback for the http protocol. */char *http_info_client (svz_server_t *server, svz_socket_t *sock){  http_socket_t *http = sock->data;  http_cache_t *cache = http->cache;  static char info[80 * 32], text[80 * 8];  int n;  sprintf (info, "This is a http client connection.\r\n\r\n");#if ENABLE_SENDFILE#if defined (HAVE_SENDFILE) || defined (__MINGW32__)  if (sock->userflags & HTTP_FLAG_SENDFILE)    {      sprintf (text, "  * delivering via sendfile() (offset: %lu)\r\n",	       (unsigned long) http->fileoffset);      strcat (info, text);    }#endif /* HAVE_SENDFILE || __MINGW32__ */#endif /* ENABLE_SENDFILE */  if (sock->userflags & HTTP_FLAG_KEEP)    {      sprintf (text, 	       "  * keeping connection alive, "	       "%d requests and %d secs left\r\n",	       http->keepalive, sock->idle_counter);      strcat (info, text);    }  if (sock->userflags & HTTP_FLAG_CACHE)    {      sprintf (text, 	       "  * sending cache entry\r\n"	       "    file    : %s\r\n"	       "    size    : %d of %d bytes sent\r\n"	       "    usage   : %d\r\n"	       "    hits    : %d\r\n"	       "    urgency : %d\r\n"	       "    ready   : %s\r\n"	       "    date    : %s\r\n",	       cache->entry->file,	       cache->entry->size - cache->size, cache->entry->size,	       cache->entry->usage,	       cache->entry->hits,	       http_cache_urgency (cache->entry) + 1,	       cache->entry->ready ? "yes" : "no",	       http_asc_date (cache->entry->date));      strcat (info, text);    }  if (sock->userflags & HTTP_FLAG_CGI)    {      sprintf (text, "  * sending cgi output (pid: %d)\r\n", (int) http->pid);      strcat (info, text);    }  if (sock->userflags & HTTP_FLAG_POST)    {      sprintf (text, 	       "  * receiving cgi input\r\n"	       "    pid            : %d\r\n"	       "    content-length : %d bytes left\r\n", 	       (int) http->pid, http->contentlength);      strcat (info, text);    }  sprintf (text, "  * %d bytes left of original file size\r\n",	   http->filelength);  strcat (info, text);  /* append http header properties is possible */  if (http->property)    {      strcat (info, "  * request property list:\r\n");      n = 0;      while (http->property[n])	{	  sprintf (text, "    %s => %s\r\n",		   http->property[n], http->property[n + 1]);	  n += 2;	  strcat (info, text);	}    }  return info;}/* * Respond to a http GET request. This could be either a usual file * request or a CGI request. */inthttp_get_response (svz_socket_t *sock, char *request, int flags){  int fd;  int size, status, partial = 0;  struct stat buf;  char *dir, *host, *p, *file;  time_t date;  http_cache_t *cache;  http_socket_t *http = sock->data;  http_config_t *cfg = sock->cfg;  /* reset current http header */  http_reset_header ();  /* check if this is a cgi request */  if ((status = http_cgi_get_response (sock, request, 0)) != -2)    return status;  /* check for "~user" syntax here */  if ((p = http_userdir (sock, request)) != NULL)    {      size = strlen (p) + strlen (cfg->indexfile) + 1;      file = svz_malloc (size);      strcpy (file, p);      svz_free (p);      status = 1;    }  /* this is a usual file request */  else    {      size = 	strlen (cfg->docs) + strlen (request) + strlen (cfg->indexfile) + 4;      file = svz_malloc (size);      strcpy (file, cfg->docs);      strcat (file, request);      status = 0;    }  /* concate the IndexFile if necessary */  if (file[strlen (file) - 1] == '/')    {      p = file + strlen (file);      strcat (file, cfg->indexfile);      /* get directory listing if there is no index file */      if ((fd = open (file, O_RDONLY)) == -1)	{	  *p = '\0';	  if ((dir = http_dirlist (file, cfg->docs, 				   status ? request : NULL)) == NULL)	    {	      svz_log (LOG_ERROR, "http: dirlist: %s: %s\n", file, SYS_ERROR);	      svz_sock_printf (sock, HTTP_FILE_NOT_FOUND "\r\n");	      http_error_response (sock, 404);	      sock->userflags |= HTTP_FLAG_DONE;	      svz_free (file);	      return -1;	    }	  /* send the directory listing */	  http->response = 200;	  http->length = strlen (dir);	  svz_free (sock->send_buffer);	  sock->send_buffer = dir;	  sock->send_buffer_size = http_dirlist_size;	  sock->send_buffer_fill = strlen (dir);	  sock->userflags |= HTTP_FLAG_DONE;	  svz_free (file);	  return 0;	}      close (fd);    }  /* check if there are '..' in the requested file's path */  if (strstr (request, "..") != NULL)    {      svz_sock_printf (sock, HTTP_ACCESS_DENIED "\r\n");      http_error_response (sock, 403);      sock->userflags |= HTTP_FLAG_DONE;      svz_free (file);      return -1;    }  /* get length of file and other properties */  if (stat (file, &buf) == -1)    {      svz_log (LOG_ERROR, "stat: %s (%s)\n", SYS_ERROR, file);      svz_sock_printf (sock, HTTP_FILE_NOT_FOUND "\r\n");      http_error_response (sock, 404);      sock->userflags |= HTTP_FLAG_DONE;      svz_free (file);      return -1;    }  /* make sure we do not send any devices or strange files */  if (!(S_ISREG (buf.st_mode) ||#ifdef S_ISLNK	S_ISLNK (buf.st_mode) ||#endif /* S_ISLNK */	S_ISDIR (buf.st_mode)))    {      svz_log (LOG_ERROR, "http: %s is not a regular file\n", file);      svz_sock_printf (sock, HTTP_ACCESS_DENIED "\r\n");      http_error_response (sock, 403);      sock->userflags |= HTTP_FLAG_DONE;      svz_free (file);      return -1;    }  /* if directory then relocate to it */  if (S_ISDIR (buf.st_mode))    {      host = http_find_property (http, "Host");      http->response = 302;      http_set_header (HTTP_RELOCATE);      http_add_header ("Location: %s%s%s/\r\n", 		       host ? "http://" : "", host ? host : "", request);      http_send_header (sock);      sock->userflags |= HTTP_FLAG_DONE;      svz_free (file);      return 0;    }  /* open the file for reading */  if ((fd = svz_open (file, O_RDONLY | O_BINARY, 0)) == -1)    {      svz_sock_printf (sock, HTTP_FILE_NOT_FOUND "\r\n");      http_error_response (sock, 404);      sock->userflags |= HTTP_FLAG_DONE;      svz_free (file);      return -1;    }  /* check if this it could be a Keep-Alive connection */  if ((p = http_find_property (http, "Connection")) != NULL)    {      if (strstr (p, "Keep-Alive"))	{	  sock->userflags |= HTTP_FLAG_KEEP;	}    }  /* check if this a If-Modified-Since request */  if ((p = http_find_property (http, "If-Modified-Since")) != NULL)    {      date = http_parse_date (p);      if (date >= buf.st_mtime)	{#if ENABLE_DEBUG	  svz_log (LOG_DEBUG, "http: %s not changed\n", file);#endif	  http->response = 304;	  http_set_header (HTTP_NOT_MODIFIED);	  http_check_keepalive (sock);	  http_send_header (sock);	  svz_close (fd);	  sock->userflags |= HTTP_FLAG_DONE;	  svz_free (file);	  return 0;	}    }  /* check content range requests */  if ((p = http_find_property (http, "Range")) != NULL)    {      if (http_get_range (p, &http->range) != -1)	partial = 1;    }  else if ((p = http_find_property (http, "Request-Range")) != NULL)    {      if (http_get_range (p, &http->range) != -1)	partial = 1;    }  /* check if partial content can be delivered or not */  if (partial)    {      if (http->range.first <= 0 || 	  (http->range.last && http->range.last <= http->range.first) ||	  http->range.last >= buf.st_size || http->range.length > buf.st_size)	partial = 0;      http->range.length = buf.st_size;#if ENABLE_DEBUG      svz_log (LOG_DEBUG, "http: partial content: %ld-%ld/%ld\n",	       http->range.first, http->range.last, http->range.length);#endif    }  /* send a http header to the client */  if (!(flags & HTTP_FLAG_SIMPLE))    {      http->response = 200;      http_set_header (HTTP_OK);      http_add_header ("Content-Type: %s\r\n",		       http_find_content_type (sock, file));      if (buf.st_size > 0)	http_add_header ("Content-Length: %d\r\n", buf.st_size);      http_add_header ("Last-Modified: %s\r\n", http_asc_date (buf.st_mtime));      http_add_header ("Accept-Ranges: bytes\r\n");      http_check_keepalive (sock);      http_send_header (sock);    }  /* just a HEAD response handled by this GET handler */  if (flags & HTTP_FLAG_NOFILE)    {      svz_close (fd);      sock->userflags |= HTTP_FLAG_DONE;      svz_free (file);      return 0;    }  /* create a cache structure for the http socket structure */  cache = svz_calloc (sizeof (http_cache_t));  http->cache = cache;        /* return the file's current cache status */  status = http_check_cache (file, cache);  /* is the requested file already fully in the cache ? */  if (status == HTTP_CACHE_COMPLETE)    {      if (buf.st_mtime > cache->entry->date ||	  buf.st_size != cache->entry->size)	{	  /* the file on disk has changed ? */#if ENABLE_DEBUG	  svz_log (LOG_DEBUG, "cache: %s has changed\n", file);#endif	  http_refresh_cache (cache);	  cache->entry->date = buf.st_mtime;	  sock->flags |= SOCK_FLAG_FILE;	  sock->file_desc = fd;	  http->filelength = buf.st_size;	  sock->read_socket = http_cache_read;	  sock->disconnected_socket = http_cache_disconnect;	}      else	{	  /* no, initialize the cache routines */	  cache->entry->hits++;	  cache->entry->usage++;	  sock->userflags |= HTTP_FLAG_CACHE;	  if (flags & HTTP_FLAG_SIMPLE)	    {	      sock->send_buffer_fill = 42;	      sock->write_socket = http_cache_write;	    }	  svz_close (fd);	}    }  /* the file is not in the cache structures yet */  else    {      sock->file_desc = fd;      http->filelength = buf.st_size;      sock->flags |= SOCK_FLAG_FILE;      /*        * find a free slot for the new file if it is not larger       * than a certain size and is not "partly" in the cache       */      if (status == HTTP_CACHE_NO && 	  buf.st_size > 0 && buf.st_size < cfg->cachesize &&	  http_init_cache (file, cache) != -1)	{	  sock->read_socket = http_cache_read;	  sock->disconnected_socket = http_cache_disconnect;	  cache->entry->date = buf.st_mtime;	}      /*       * either the file is not cacheable or it is currently       * going to be in the http cache (not yet cache->ready)       */      else	{#if ENABLE_SENDFILE && (HAVE_SENDFILE || defined (__MINGW32__))# ifdef __MINGW32__	  if (svz_os_version >= WinNT4x)	    {	      sock->read_socket = NULL;	      sock->flags &= ~SOCK_FLAG_FILE;	      sock->userflags |= HTTP_FLAG_SENDFILE;	    }	  else	    sock->read_socket = http_file_read;# else	  sock->read_socket = NULL;	  sock->flags &= ~SOCK_FLAG_FILE;	  sock->userflags |= HTTP_FLAG_SENDFILE;	  svz_tcp_cork (sock->sock_desc, 1);# endif#else /* not HAVE_SENDFILE */	  sock->read_socket = http_file_read;#endif /* HAVE_SENDFILE || __MINGW32__ && ENABLE_SENDFILE */	}    }  svz_free (file);  return 0;}/* * Respond to a http HEAD request. This is in particular the same as * GET but you do not respond with the file but with the header and all * the file info. */inthttp_head_response (svz_socket_t *sock, char *request, int flags){  http_get_response (sock, request, flags | HTTP_FLAG_NOFILE);  return 0;}/* * The default http response (Bad Request). */inthttp_default_response (svz_socket_t *sock, char *request, int flags){  svz_sock_printf (sock, HTTP_NOT_IMPLEMENTED "\r\n");  http_error_response (sock, 501);  sock->userflags |= HTTP_FLAG_DONE;  return 0;}int have_http = 1;#else /* ENABLE_HTTP_PROTO */int have_http = 0;	/* Shut compiler warnings up, remember for runtime */#endif /* not ENABLE_HTTP_PROTO */

⌨️ 快捷键说明

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