http-proto.c

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

C
1,324
字号
      sock->send_buffer_fill = 0;      sock->write_socket = http_default_write;      sock->userflags &= ~HTTP_FLAG_SENDFILE;      num_written = http_keep_alive (sock);      svz_tcp_cork (sock->sock_desc, 0);    }  return (num_written < 0) ? -1 : 0;}#endif /* HAVE_SENDFILE */#endif /* ENABLE_SENDFILE *//* * HTTP_DEFAULT_WRITE will shutdown the connection immediately when  * the whole response has been sent (indicated by the HTTP_FLAG_DONE * flag) with two exceptions. It will keep the connection if the * actual file is within the cache and if this is a keep-alive connection. */inthttp_default_write (svz_socket_t *sock){  int num_written;  /*    * Write as many bytes as possible, remember how many   * were actually sent.   */  num_written = send (sock->sock_desc, sock->send_buffer,		      sock->send_buffer_fill, 0);  /* some data has been written */  if (num_written > 0)    {      sock->last_send = time (NULL);      if (sock->send_buffer_fill > num_written)	{	  memmove (sock->send_buffer, 		   sock->send_buffer + num_written,		   sock->send_buffer_fill - num_written);	}      sock->send_buffer_fill -= num_written;    }  /* write error occurred */  else if (num_written < 0)    {      svz_log (LOG_ERROR, "http: send: %s\n", NET_ERROR);      if (svz_errno == SOCK_UNAVAILABLE)	{	  sock->unavailable = time (NULL) + RELAX_FD_TIME;	  num_written = 0;	}    }  /*   * Check if the http response has (success)fully been sent.   * If yes then return non-zero in order to shutdown the socket SOCK   * and return zero if it is a keep-alive connection.   */  if ((sock->userflags & HTTP_FLAG_DONE) && sock->send_buffer_fill == 0)    {#if ENABLE_DEBUG      svz_log (LOG_DEBUG, "http: response successfully sent\n");#endif      num_written = http_keep_alive (sock);    }  /*   * If the requested file is within the cache then start now the    * cache writer. Set SEND_BUFFER_FILL to something greater than zero.   */  if (sock->send_buffer_fill == 0)    {      if (sock->userflags & HTTP_FLAG_CACHE)	{	  sock->send_buffer_fill = 42;	  sock->write_socket = http_cache_write;	}#if ENABLE_SENDFILE#if defined (HAVE_SENDFILE) || defined (__MINGW32__)# ifdef __MINGW32__      else if (sock->userflags & HTTP_FLAG_SENDFILE && 	       svz_os_version >= WinNT4x)# else      else if (sock->userflags & HTTP_FLAG_SENDFILE)# endif	{	  sock->send_buffer_fill = 42;	  sock->write_socket = http_send_file;	}#endif /* HAVE_SENDFILE || __MINGW32__ */#endif /* ENABLE_SENDFILE */    }  /*   * Return a non-zero value if an error occurred.   */  return (num_written < 0) ? -1 : 0;}/* * The HTTP_FILE_READ reads as much data from a file as possible directly * into the send buffer of the socket SOCK. It returns a non-zero value  * on read errors. When all the file has been read then the socket flag  * HTTP_FLAG_DONE is set. */inthttp_file_read (svz_socket_t *sock){  int num_read;  int do_read;  http_socket_t *http;  http = sock->data;  do_read = sock->send_buffer_size - sock->send_buffer_fill;  /*    * This means the send buffer is currently full, we have to    * wait until some data has been send via the socket.   */  if (do_read <= 0)    {      return 0;    }#ifndef __MINGW32__  /*   * Try to read as much data as possible from the file.   */  num_read = read (sock->file_desc,		   sock->send_buffer + sock->send_buffer_fill, do_read);  /* Read error occurred. */  if (num_read < 0)    {      svz_log (LOG_ERROR, "http: read: %s\n", SYS_ERROR);      return -1;    }#else  if (!ReadFile ((HANDLE) sock->file_desc,		 sock->send_buffer + sock->send_buffer_fill,		 do_read, (DWORD *) &num_read, NULL))    {      svz_log (LOG_ERROR, "http: ReadFile: %s\n", SYS_ERROR);      return -1;    }#endif  /* Bogus file. File size from stat() was not true. */  if (num_read == 0 && http->filelength != 0)    {      return -1;    }  /* Data has been read or EOF reached, set the appropriate flags. */  sock->send_buffer_fill += num_read;  http->filelength -= num_read;  http->length += num_read;  /* Read all file data ? */  if (http->filelength <= 0)    {#if ENABLE_DEBUG      svz_log (LOG_DEBUG, "http: file successfully read\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->userflags |= HTTP_FLAG_DONE;      sock->flags &= ~SOCK_FLAG_FILE;    }  return 0;}/* * This function gets called for new sockets which are not yet * identified.  It returns a non-zero value when the content in * the receive buffer looks like an HTTP request. */inthttp_detect_proto (svz_server_t *server, svz_socket_t *sock){  int n;  /* go through all possible request types */  for (n = 0; n < HTTP_REQUESTS; n++)    {      if (sock->recv_buffer_fill >= http_request[n].len)	{	  if (!memcmp (sock->recv_buffer, http_request[n].ident, 		       http_request[n].len))	    {#if ENABLE_DEBUG	      svz_log (LOG_DEBUG, "http client detected\n");#endif	      return -1;	    }	}    }  return 0;}/* * When the http_detect_proto returns successfully this function must * be called to set all the appropriate callbacks and socket flags. */inthttp_connect_socket (svz_server_t *server, svz_socket_t *sock){  http_socket_t *http;  http_config_t *cfg = server->cfg;  /*   * initialize the http socket structure   */  http = svz_malloc (sizeof (http_socket_t));  memset (http, 0, sizeof (http_socket_t));  http->pid = INVALID_HANDLE;  http->keepalive = cfg->keepalive;  sock->data = http;  /* start reverse dns lookup for logging purposes if necessary */  if (cfg->nslookup)    {      svz_coserver_rdns (sock->remote_addr, http_remotehost, 			 sock->id, sock->version);    }  /* start user identification if necessary */  if (cfg->ident)    {      svz_coserver_ident (sock, http_identification, sock->id, sock->version);    }  /*    * set the socket flag, disable flood protection and   * set all the callback routines   */  sock->flags |= SOCK_FLAG_NOFLOOD;  sock->check_request = http_check_request;  sock->write_socket = http_default_write;  sock->disconnected_socket = http_disconnect;  sock->idle_func = http_cgi_died;  sock->idle_counter = 1;  return 0;}/* * This routine is called from http_check_request if there was * seen a full HTTP request (ends with a double CRLF). */inthttp_handle_request (svz_socket_t *sock, int len){  http_socket_t *http = sock->data;  int n;  char *p, *line, *end;  char *request;  char *uri;  int flag;  int version[2];    line = sock->recv_buffer;  end = sock->recv_buffer + len;  p = line;  flag = 0;  /* scan the request type */  while (*p != ' ' && p < end - 1)    p++;  if (p == end || *(p + 1) != '/')    {      return -1;    }  *p = 0;  request = svz_malloc (p - line + 1);  strcpy (request, line);  line = p + 1;  /* scan the URI (file), `line' points to first character */  while (*p != '\r' && p < end)    p++;  if (p == end)    {      svz_free (request);      return -1;    }  /* scan back until beginning of HTTP version */  while (*p != ' ' && *p)    p--;  /* is this a HTTP/0.9 request ? */  if (!memcmp (request, "GET", 3) && memcmp (p + 1, "HTTP/", 5))    {      flag |= HTTP_FLAG_SIMPLE;      while (*p != '\r')	p++;      uri = svz_malloc (p - line + 1);      strncpy (uri, line, p - line);      uri[p - line] = 0;      line = p;      version[MAJOR_VERSION] = 0;      version[MINOR_VERSION] = 9;    }  /* no, it is a real HTTP/1.x request */  else    {      if (p <= line)	{	  svz_free (request);	  return -1;	}      *p = 0;      uri = svz_malloc (p - line + 1);      strcpy (uri, line);      line = p + 1;        /* scan the version string of the HTTP request */      if (memcmp (line, "HTTP/", 5))	{	  svz_free (request);	  svz_free (uri);	  return -1;	}      line += 5;      version[MAJOR_VERSION] = *line - '0';      line += 2;      version[MINOR_VERSION] = *line - '0';      line++;    }  /* check the remaining part of the first line the version */  if (((version[MAJOR_VERSION] != HTTP_MAJOR_VERSION ||	version[MINOR_VERSION] > 1 || *(line - 2) != '.') && !flag) ||       SVZ_INT16 (line) != CRLF)    {      svz_free (request);      svz_free (uri);      return -1;    }  line += 2;  /* find out properties */  http_parse_property (sock, line, end);  /* convert URI if necessary */  http_process_uri (uri);  /* assign request properties to http structure */  http->timestamp = time (NULL);  http->request = svz_malloc (strlen (request) + strlen (uri) + 11);  sprintf (http->request, "%s %s HTTP/%d.%d",	   request, uri, version[MAJOR_VERSION], version[MINOR_VERSION]);  /* find an appropriate request callback */  for (n = 0; n < HTTP_REQUESTS; n++)    {      if (!memcmp (request, http_request[n].ident, http_request[n].len))	{#if ENABLE_DEBUG	  svz_log (LOG_DEBUG, "http: %s received\n", request);#endif	  http_request[n].response (sock, uri, flag);	  break;	}    }  /* Return a "404 Bad Request" if the request type is unknown. */  if (n == HTTP_REQUESTS)    {      http_default_response (sock, uri, 0);    }  svz_free (request);  svz_free (uri);  return 0;}/* * Check in the receive buffer of socket SOCK for full * http request and call http_handle_request if necessary. */int http_check_request (svz_socket_t *sock){  char *p;  int len;  p = sock->recv_buffer;  while (p < sock->recv_buffer + sock->recv_buffer_fill - 3 && 	 SVZ_INT32 (p) != CRLF2)    p++;    if (SVZ_INT32 (p) == CRLF2 &&       p < sock->recv_buffer + sock->recv_buffer_fill - 3)    {      len = p - sock->recv_buffer + 4;      if (http_handle_request (sock, len))	return -1;      if (sock->recv_buffer_fill > len)	{	  memmove (sock->recv_buffer, sock->recv_buffer + len,		   sock->recv_buffer_fill - len);	}      sock->recv_buffer_fill -= len;    }  return 0;}/* * Server info callback for the http protocol. We are currently using  * it for displaying the server configuration within the control protocol. */char *http_info_server (svz_server_t *server){  http_config_t *cfg = server->cfg;  static char info[80 * 12];    sprintf (info,	   " tcp bindings    : %s\r\n"	   " index file      : %s\r\n"	   " document root   : %s/\r\n"	   " cgi url         : %s/\r\n"	   " cgi directory   : %s/\r\n"	   " cache file size : %d byte\r\n"	   " cache entries   : %d files\r\n"	   " timeout         : after %d secs\r\n"	   " keep alive      : for %d requests\r\n"	   " default type    : %s\r\n"	   " type file       : %s\r\n"	   " content types   : %d",	   svz_server_bindings (server),

⌨️ 快捷键说明

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