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