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