static int processreq(int fd) { lscgid_t cgi_req; int ret; ret = recv_req(fd, &cgi_req, 10); if (ret) cgiError(fd, ret); else { ret = execute_cgi(&cgi_req); if (ret) cgiError(fd, ret); } return ret; }
void accept_request(int client) { char buf[1024]; int numchars; char method[255]; char url[255]; char path[512]; size_t i, j; struct stat st; int cgi = 0; /* becomes true if server decides this is a CGI * program */ char *query_string = NULL; numchars = get_line(client, buf, sizeof(buf)); i = 0; j = 0; while (!ISspace(buf[j]) && (i < sizeof(method) - 1)) { method[i] = buf[j]; i++; j++; } method[i] = '\0'; if (strcasecmp(method, "GET") && strcasecmp(method, "POST")) { unimplemented(client); return; } if (strcasecmp(method, "POST") == 0) cgi = 1; i = 0; while (ISspace(buf[j]) && (j < sizeof(buf))) j++; while (!ISspace(buf[j]) && (i < sizeof(url) - 1) && (j < sizeof(buf))) { url[i] = buf[j]; i++; j++; } url[i] = '\0'; if (strcasecmp(method, "GET") == 0) { query_string = url; while ((*query_string != '?') && (*query_string != '\0')) query_string++; if (*query_string == '?') { cgi = 1; *query_string = '\0'; query_string++; } } //sprintf(path, "htdocs%s", url); sprintf(path, ".%s", url); if (path[strlen(path) - 1] == '/') strcat(path, "index.html"); if (stat(path, &st) == -1) { while ((numchars > 0) && strcmp("\n", buf)) /* read & discard headers */ numchars = get_line(client, buf, sizeof(buf)); not_found(client); } else { if ((st.st_mode & S_IFMT) == S_IFDIR) strcat(path, "/index.html"); if ((st.st_mode & S_IXUSR) || (st.st_mode & S_IXGRP) || (st.st_mode & S_IXOTH) ) cgi = 1; cgi = 0;//must not cgi if (!cgi) serve_file(client, path); else execute_cgi(client, path, method, query_string); } close(client); }
/* Serve the client that connected to the webserver */ static int serve_client(t_session *session) { int result, length, auth_result; char *qmark, chr, *header; t_host *host_record; t_access access; t_deny_body *deny_body; t_req_method request_method; t_ip_addr ip_addr; #ifdef ENABLE_XSLT char *xslt_file; #endif #ifdef ENABLE_TOOLKIT int i; t_toolkit_options toolkit_options; #endif #ifdef ENABLE_RPROXY t_rproxy *rproxy; #endif #ifdef ENABLE_DEBUG session->current_task = "fetch & parse request"; #endif if ((result = fetch_request(session)) != 200) { session->request_method = GET; return result; } else if ((result = parse_request(session, session->header_length + session->content_length)) != 200) { session->request_method = GET; return result; } #ifdef ENABLE_DEBUG session->current_task = "serve client"; #endif session->time = time(NULL); /* Hide reverse proxies */ if (in_iplist(session->config->hide_proxy, &(session->ip_address))) { if (last_forwarded_ip(session->http_headers, &ip_addr) == 0) { if (reposition_client(session, &ip_addr) != -1) { copy_ip(&(session->ip_address), &ip_addr); } } } /* SSH tunneling */ #ifdef ENABLE_RPROXY if (session->request_method == CONNECT) { if (in_iplist(session->config->tunnel_ssh, &(session->ip_address)) == false) { return 405; } #ifdef ENABLE_SSL if (session->binding->use_ssl) { return 405; } #endif if (strcmp(session->request_uri, "localhost:22") != 0) { if (strcmp(session->request_uri, "127.0.0.1:22") != 0) { if (strcmp(session->request_uri, "::1.22") != 0) { return 403; } } } log_system(session, "SSH tunnel requested"); if (tunnel_ssh_connection(session->client_socket) != 0) { log_system(session, "SSH tunnel failed"); } else { log_system(session, "SSH tunnel terminated"); } session->keep_alive = false; return 200; } #endif /* Find host record */ if (session->hostname != NULL) { if (remove_port_from_hostname(session) == -1) { log_error(session, "error removing port from hostname"); return 500; } if ((host_record = get_hostrecord(session->config->first_host, session->hostname, session->binding)) != NULL) { session->host = host_record; #ifdef ENABLE_TOMAHAWK session->last_host = host_record; #endif } } session->host->access_time = session->time; #ifdef ENABLE_SSL /* SSL client authentication */ if (session->binding->use_ssl) { if ((session->host->ca_certificate != NULL) && (ssl_has_peer_cert(&(session->ssl_context)) == false)) { log_error(session, "Missing client SSL certificate"); return 440; } } #endif /* Enforce usage of first hostname */ if (session->host->enforce_first_hostname && (session->hostname != NULL)) { if (**(session->host->hostname.item) != '*') { if (strcmp(session->hostname, *(session->host->hostname.item)) != 0) { session->cause_of_301 = enforce_first_hostname; return 301; } } } /* Enforce usage of SSL */ #ifdef ENABLE_SSL if (session->host->require_ssl && (session->binding->use_ssl == false)) { if ((qmark = strchr(session->uri, '?')) != NULL) { *qmark = '\0'; session->vars = qmark + 1; session->uri_len = strlen(session->uri); } session->cause_of_301 = require_ssl; return 301; } #endif /* Deny matching bodies */ if (session->body != NULL) { chr = *(session->body + session->content_length); *(session->body + session->content_length) = '\0'; deny_body = session->host->deny_body; while (deny_body != NULL) { if (strpcmp(session->body, &(deny_body->pattern)) == 0) { if ((session->config->ban_on_denied_body > 0) && (ip_allowed(&(session->ip_address), session->config->banlist_mask) != deny)) { ban_ip(&(session->ip_address), session->config->ban_on_denied_body, session->config->kick_on_ban); log_system(session, "Client banned because of denied body"); #ifdef ENABLE_MONITOR if (session->config->monitor_enabled) { monitor_count_ban(session); } #endif } log_exploit_attempt(session, "denied body", session->body); #ifdef ENABLE_TOMAHAWK increment_counter(COUNTER_EXPLOIT); #endif #ifdef ENABLE_MONITOR if (session->config->monitor_enabled) { monitor_count_exploit(session); monitor_event("Request body denied for %s", session->host->hostname.item[0]); } #endif *(session->body + session->content_length) = chr; return 403; } deny_body = deny_body->next; } *(session->body + session->content_length) = chr; } /* Websocket */ if (session->request_method == GET) { if ((header = get_http_header("Connection:", session->http_headers)) != NULL) { if (strcasestr(header, "upgrade") != NULL) { if ((header = get_http_header("Upgrade:", session->http_headers)) != NULL) { if (strcasecmp(header, "websocket") == 0) { switch (access = allow_client(session)) { case deny: log_error(session, fb_accesslist); return 403; case allow: break; case pwd: case unspecified: if ((auth_result = http_authentication_result(session, access == unspecified)) != 200) { return auth_result; } } session->keep_alive = false; if (forward_to_websocket(session) == -1) { return 500; } return 200; } } } } } #ifdef ENABLE_RPROXY /* Reverse proxy */ rproxy = session->host->rproxy; while (rproxy != NULL) { if (rproxy_match(rproxy, session->request_uri)) { if (rproxy_loop_detected(session->http_headers)) { return 508; } if ((qmark = strchr(session->uri, '?')) != NULL) { *qmark = '\0'; session->vars = qmark + 1; } if (validate_url(session) == false) { return -1; } if ((session->vars != NULL) && (session->host->secure_url)) { if (forbidden_chars_present(session->vars)) { log_error(session, "URL contains forbidden characters"); return 403; } } if (duplicate_host(session) == false) { log_error(session, "duplicate_host() error"); return 500; } if ((result = uri_to_path(session)) != 200) { return result; } if (session->host->ignore_dot_hiawatha == false) { if (load_user_config(session) == -1) { return 500; } } if ((result = copy_directory_settings(session)) != 200) { return result; } switch (access = allow_client(session)) { case deny: log_error(session, fb_accesslist); return 403; case allow: break; case pwd: case unspecified: if ((auth_result = http_authentication_result(session, access == unspecified)) != 200) { return auth_result; } } /* Prevent SQL injection */ if (session->host->prevent_sqli) { result = prevent_sqli(session); if (result == 1) { session->error_cause = ec_SQL_INJECTION; } if (result != 0) { return -1; } } /* Prevent Cross-site Scripting */ if (session->host->prevent_xss != p_no) { if (prevent_xss(session) > 0) { if (session->host->prevent_xss == p_block) { session->error_cause = ec_XSS; return -1; } } } /* Prevent Cross-site Request Forgery */ if (session->host->prevent_csrf != p_no) { if (prevent_csrf(session) > 0) { if (session->host->prevent_csrf == p_block) { session->error_cause = ec_CSRF; return -1; } } } return proxy_request(session, rproxy); } rproxy = rproxy->next; } #endif /* Actions based on request method */ switch (session->request_method) { case TRACE: if (session->binding->enable_trace == false) { return 501; } return handle_trace_request(session); case PUT: case DELETE: if ((session->binding->enable_alter == false) && (session->host->webdav_app == false)) { return 501; } break; case unknown: return 400; case unsupported: if (session->host->webdav_app == false) { return 501; } break; default: break; } if (duplicate_host(session) == false) { log_error(session, "duplicate_host() error"); return 500; } #ifdef ENABLE_TOOLKIT if (session->host->ignore_dot_hiawatha == false) { if (load_user_root_config(session) == -1) { return 500; } } /* URL toolkit */ init_toolkit_options(&toolkit_options); toolkit_options.method = session->method; toolkit_options.website_root = session->host->website_root; toolkit_options.url_toolkit = session->config->url_toolkit; toolkit_options.allow_dot_files = session->host->allow_dot_files; toolkit_options.http_headers = session->http_headers; #ifdef ENABLE_SSL toolkit_options.use_ssl = session->binding->use_ssl; #endif if (((session->request_method != PUT) && (session->request_method != DELETE)) || session->host->webdav_app) { for (i = 0; i < session->host->toolkit_rules.size; i++) { if ((result = use_toolkit(session->uri, session->host->toolkit_rules.item[i], &toolkit_options)) == UT_ERROR) { return 500; } if ((toolkit_options.ban > 0) && (ip_allowed(&(session->ip_address), session->config->banlist_mask) != deny)) { ban_ip(&(session->ip_address), toolkit_options.ban, session->config->kick_on_ban); log_system(session, "Client banned because of URL match in UrlToolkit rule"); #ifdef ENABLE_MONITOR if (session->config->monitor_enabled) { monitor_count_ban(session); } #endif return 403; } session->toolkit_fastcgi = toolkit_options.fastcgi_server; if (toolkit_options.new_url != NULL) { if (register_tempdata(&(session->tempdata), toolkit_options.new_url, tc_data) == -1) { free(toolkit_options.new_url); log_error(session, "error registering temporary data"); return 500; } session->uri = toolkit_options.new_url; } if (result == UT_REDIRECT) { if ((session->location = strdup(toolkit_options.new_url)) == NULL) { return -1; } session->cause_of_301 = location; return 301; } if (result == UT_DENY_ACCESS) { log_error(session, "access denied via URL toolkit rule"); return 403; } if (toolkit_options.expire > -1) { session->expires = toolkit_options.expire; session->caco_private = toolkit_options.caco_private; } } } #endif /* Find GET data */ if ((qmark = strchr(session->uri, '?')) != NULL) { *qmark = '\0'; session->vars = qmark + 1; } url_decode(session->uri); session->uri_len = strlen(session->uri); if ((session->vars != NULL) && (session->host->secure_url)) { if (forbidden_chars_present(session->vars)) { log_error(session, "URL contains forbidden characters"); return 403; } } if (validate_url(session) == false) { return -1; } if ((result = uri_to_path(session)) != 200) { return result; } /* Load configfile from directories */ if (session->host->ignore_dot_hiawatha == false) { if (load_user_config(session) == -1) { return 500; } } if ((result = copy_directory_settings(session)) != 200) { return result; } switch (access = allow_client(session)) { case deny: log_error(session, fb_accesslist); return 403; case allow: break; case pwd: case unspecified: if ((auth_result = http_authentication_result(session, access == unspecified)) != 200) { return auth_result; } } switch (is_directory(session->file_on_disk)) { case error: return 500; case yes: session->uri_is_dir = true; break; case no: if (((session->request_method != PUT) || session->host->webdav_app) && (session->host->enable_path_info)) { if ((result = get_path_info(session)) != 200) { return result; } } break; case no_access: log_error(session, fb_filesystem); return 403; case not_found: if (session->request_method == DELETE) { return 404; } } #ifdef ENABLE_TOOLKIT if ((session->toolkit_fastcgi == NULL) && session->uri_is_dir) { #else if (session->uri_is_dir) { #endif length = strlen(session->file_on_disk); if (*(session->file_on_disk + length - 1) == '/') { strcpy(session->file_on_disk + length, session->host->start_file); } else { return 301; } } if (get_target_extension(session) == -1) { log_error(session, "error getting extension"); return 500; } if (((session->request_method != PUT) && (session->request_method != DELETE)) || session->host->webdav_app) { check_target_is_cgi(session); } /* Handle request based on request method */ request_method = session->request_method; if (session->host->webdav_app) { if ((request_method == PUT) || (request_method == DELETE)) { request_method = POST; } } switch (request_method) { case GET: case HEAD: if (session->cgi_type != no_cgi) { session->body = NULL; result = execute_cgi(session); #ifdef ENABLE_XSLT } else if ((xslt_file = find_xslt_file(session)) != NULL) { result = handle_xml_file(session, xslt_file); free(xslt_file); #endif } else { result = send_file(session); } if (result == 404) { #ifdef ENABLE_XSLT if ((session->host->show_index != NULL) && (session->uri[session->uri_len - 1] == '/')) { result = show_index(session); } #endif #ifdef ENABLE_MONITOR } else if (session->config->monitor_enabled) { if ((result == 200) && (session->host->monitor_host)) { unlink(session->file_on_disk); } #endif } if ((session->request_method == GET) && (session->cgi_type == no_cgi) && (session->directory != NULL)) { if (session->directory->run_on_download != NULL) { run_program(session, session->directory->run_on_download, result); } } break; case POST: case unsupported: if (session->cgi_type != no_cgi) { result = execute_cgi(session); #ifdef ENABLE_XSLT } else if ((xslt_file = find_xslt_file(session)) != NULL) { result = handle_xml_file(session, xslt_file); free(xslt_file); #endif } else { result = 405; } break; case PUT: result = handle_put_request(session); if (((result == 201) || (result == 204)) && (session->host->run_on_alter != NULL)) { run_program(session, session->host->run_on_alter, result); } break; case DELETE: result = handle_delete_request(session); if ((result == 204) && (session->host->run_on_alter != NULL)) { run_program(session, session->host->run_on_alter, result); } break; case WHEN: send_code(session); break; default: result = 400; } return result; } /* Handle timeout upon sending request */ static void handle_timeout(t_session *session) { if ((session->config->ban_on_timeout > 0) && (ip_allowed(&(session->ip_address), session->config->banlist_mask) != deny)) { ban_ip(&(session->ip_address), session->config->ban_on_timeout, session->config->kick_on_ban); log_system(session, "Client banned because of connection timeout"); #ifdef ENABLE_MONITOR if (session->config->monitor_enabled) { monitor_count_ban(session); } #endif } else { log_system(session, "Timeout while waiting for first request"); } } /* Request has been handled, handle the return code. */ static void handle_request_result(t_session *session, int result) { char *hostname; #ifdef ENABLE_DEBUG session->current_task = "handle request result"; #endif if (result == -1) switch (session->error_cause) { case ec_MAX_REQUESTSIZE: log_system(session, "Maximum request size reached"); session->return_code = 413; send_code(session); if ((session->config->ban_on_max_request_size > 0) && (ip_allowed(&(session->ip_address), session->config->banlist_mask) != deny)) { ban_ip(&(session->ip_address), session->config->ban_on_max_request_size, session->config->kick_on_ban); log_system(session, "Client banned because of sending a too large request"); #ifdef ENABLE_MONITOR if (session->config->monitor_enabled) { monitor_count_ban(session); } #endif } break; case ec_TIMEOUT: if (session->kept_alive == 0) { session->return_code = 408; send_code(session); handle_timeout(session); } break; case ec_CLIENT_DISCONNECTED: if (session->kept_alive == 0) { log_system(session, "Silent client disconnected"); } break; case ec_SOCKET_READ_ERROR: if (errno != ECONNRESET) { log_system(session, "Error while reading request"); } break; case ec_SOCKET_WRITE_ERROR: log_request(session); break; case ec_FORCE_QUIT: log_system(session, "Client kicked"); break; case ec_SQL_INJECTION: if ((session->config->ban_on_sqli > 0) && (ip_allowed(&(session->ip_address), session->config->banlist_mask) != deny)) { ban_ip(&(session->ip_address), session->config->ban_on_sqli, session->config->kick_on_ban); hostname = (session->hostname != NULL) ? session->hostname : unknown_host; log_system(session, "Client banned because of SQL injection on %s", hostname); #ifdef ENABLE_MONITOR if (session->config->monitor_enabled) { monitor_count_ban(session); } #endif } session->return_code = 441; send_code(session); log_request(session); break; case ec_XSS: session->return_code = 442; send_code(session); log_request(session); break; case ec_CSRF: session->return_code = 443; send_code(session); log_request(session); break; case ec_INVALID_URL: if ((session->config->ban_on_invalid_url > 0) && (ip_allowed(&(session->ip_address), session->config->banlist_mask) != deny)) { ban_ip(&(session->ip_address), session->config->ban_on_invalid_url, session->config->kick_on_ban); hostname = (session->hostname != NULL) ? session->hostname : unknown_host; log_system(session, "Client banned because of invalid URL on %s", hostname); #ifdef ENABLE_MONITOR if (session->config->monitor_enabled) { monitor_count_ban(session); } #endif } send_code(session); break; default: if (session->data_sent == false) { session->return_code = 500; if (send_code(session) == -1) { session->keep_alive = false; } } } else switch (result) { case 200: break; case 201: case 204: case 304: case 412: if (session->data_sent == false) { session->return_code = result; if (send_header(session) == -1) { session->keep_alive = false; } else if (send_buffer(session, "Content-Length: 0\r\n\r\n", 21) == -1) { session->keep_alive = false; } } break; case 411: case 413: session->keep_alive = false; if (session->data_sent == false) { session->return_code = result; if (send_header(session) == -1) { session->keep_alive = false; } else if (send_buffer(session, "Content-Length: 0\r\n\r\n", 21) == -1) { session->keep_alive = false; } } break; case 400: log_garbage(session); if (session->data_sent == false) { session->return_code = 400; if (send_code(session) == -1) { session->keep_alive = false; } } if ((session->config->ban_on_garbage > 0) && (ip_allowed(&(session->ip_address), session->config->banlist_mask) != deny)) { ban_ip(&(session->ip_address), session->config->ban_on_garbage, session->config->kick_on_ban); log_system(session, "Client banned because of sending garbage"); #ifdef ENABLE_MONITOR if (session->config->monitor_enabled) { monitor_count_ban(session); } #endif } #ifdef ENABLE_MONITOR if (session->config->monitor_enabled) { monitor_count_bad_request(session); } #endif break; case 401: case 403: case 404: case 501: case 503: if (session->data_sent == false) { switch (handle_error(session, result)) { case -1: session->keep_alive = false; break; case 200: break; default: if (session->data_sent == false) { session->return_code = result; if (send_code(session) == -1) { session->keep_alive = false; } } } } break; case 500: session->keep_alive = false; default: if (session->data_sent == false) { session->return_code = result; send_code(session); } } if ((result > 0) && (result != 400)) { log_request(session); } else { session->keep_alive = false; } }
/* Handle an HTTP error. */ static int handle_error(t_session *session, int error_code) { t_error_handler *error_handler; char *new_fod; int result = -1; #ifdef ENABLE_XSLT char *xslt_file; #endif error_handler = session->host->error_handlers; while (error_handler != NULL) { if (error_handler->code == error_code) { break; } error_handler = error_handler->next; } if (error_handler == NULL) { return 0; } session->return_code = error_code; session->error_code = error_code; session->handling_error = true; session->mimetype = NULL; session->vars = error_handler->parameters; if ((new_fod = (char*)malloc(session->host->website_root_len + strlen(error_handler->handler) + 4)) == NULL) { /* + 3 for .gz (gzip encoding) */ log_error(session, "malloc() error while handling error"); return 500; } if (session->file_on_disk != NULL) { free(session->file_on_disk); } session->file_on_disk = new_fod; memcpy(session->file_on_disk, session->host->website_root, session->host->website_root_len); strcpy(session->file_on_disk + session->host->website_root_len, error_handler->handler); if (get_target_extension(session) == -1) { log_error(session, "error getting extension while handing error"); return 500; } check_target_is_cgi(session); if (session->cgi_type != no_cgi) { result = execute_cgi(session); #ifdef ENABLE_XSLT } else if ((xslt_file = find_xslt_file(session)) != NULL) { result = handle_xml_file(session, xslt_file); free(xslt_file); #endif } else switch (is_directory(session->file_on_disk)) { case error: result = 500; break; case yes: result = 301; break; case no: result = send_file(session); break; case no_access: result = 403; break; case not_found: result = 404; break; } switch (result) { case 301: log_error(session, "ErrorHandler is a directory"); break; case 403: log_error(session, "no access to ErrorHandler"); break; case 404: log_error(session, "ErrorHandler not found"); break; case 500: log_file_error(session, error_handler->handler, "internal error for ErrorHandler"); session->keep_alive = false; break; case 503: log_file_error(session, error_handler->handler, "FastCGI for ErrorHandler not available"); break; } return result; }
void* accept_request(void* client1) //accept_request解析header里面的第一行获得request method(get/post)和请求路径,映射到htdoc文件夹下的路径, //其中当对应的文件可执行的时候,就调用execute_cgi函数 { int client = (intptr_t)client1; char buf[1024]; int numchars; char method[255]; char url[255]; char path[512]; size_t i, j; struct stat st; int cgi = 0; /* becomes true if server decides this is a CGI * program */ char *query_string = NULL; numchars = get_line(client, buf, sizeof(buf)); i = 0; j = 0; while (!ISspace(buf[j]) && (i < sizeof(method) - 1)) { method[i] = buf[j]; i++; j++; } method[i] = '\0'; if (strcasecmp(method, "GET") && strcasecmp(method, "POST")) { unimplemented(client); // 仅仅支持GET和POST方法,否则抛出未支持的方法 return NULL; } if (strcasecmp(method, "POST") == 0) cgi = 1; i = 0; while (ISspace(buf[j]) && (j < sizeof(buf))) j++; while (!ISspace(buf[j]) && (i < sizeof(url) - 1) && (j < sizeof(buf))) { url[i] = buf[j]; i++; j++; } url[i] = '\0'; if (strcasecmp(method, "GET") == 0) { query_string = url; while ((*query_string != '?') && (*query_string != '\0')) query_string++; if (*query_string == '?') { cgi = 1; *query_string = '\0'; query_string++; } } sprintf(path, "htdocs%s", url); if (path[strlen(path) - 1] == '/') strcat(path, "index.html"); if (stat(path, &st) == -1) { while ((numchars > 0) && strcmp("\n", buf)) /* read & discard headers */ numchars = get_line(client, buf, sizeof(buf)); not_found(client); } else { if ((st.st_mode & S_IFMT) == S_IFDIR) strcat(path, "/index.html"); if ((st.st_mode & S_IXUSR) || (st.st_mode & S_IXGRP) || (st.st_mode & S_IXOTH) ) cgi = 1; if (!cgi) serve_file(client, path); else execute_cgi(client, path, method, query_string); } close(client); return NULL; }
void accept_request(int client) { char buf[1024]; int numchars; char method[255]; char url[255]; char path[512]; size_t i, j; struct stat st; int cgi = 0; /* becomes true if server decides this is a CGI * program */ char *query_string = NULL; numchars = get_line(client, buf, sizeof(buf));//把client里的\r都换成\n i = 0; j = 0; //找出method是get还是post,只支持这两种方法 while (!ISspace(buf[j]) && (i < sizeof(method) - 1)) { method[i] = buf[j]; i++; j++; } method[i] = '\0'; //函数说明 strcasecmp()用来比较参数s1和s2字符串,比较时会自动忽略大小写的差异。 //返回值 若参数s1和s2字符串相等则返回0。s1大于s2则返回大于0 的值,s1 小于s2 则返回小于0的值。 if (strcasecmp(method, "GET") && strcasecmp(method, "POST")) { unimplemented(client);//返回给浏览器表明收到的 HTTP 请求所用的 method 不被支持。 return; } if (strcasecmp(method, "POST") == 0) cgi = 1; i = 0; while (ISspace(buf[j]) && (j < sizeof(buf))) j++; //找出URL while (!ISspace(buf[j]) && (i < sizeof(url) - 1) && (j < sizeof(buf))) { url[i] = buf[j]; i++; j++; } url[i] = '\0'; if (strcasecmp(method, "GET") == 0) { query_string = url; while ((*query_string != '?') && (*query_string != '\0')) query_string++; if (*query_string == '?') { cgi = 1; *query_string = '\0'; query_string++; } } sprintf(path, "htdocs%s", url); if (path[strlen(path) - 1] == '/') strcat(path, "index.html"); if (stat(path, &st) == -1) { while ((numchars > 0) && strcmp("\n", buf)) /* read & discard headers */ numchars = get_line(client, buf, sizeof(buf)); not_found(client); } else { if ((st.st_mode & S_IFMT) == S_IFDIR) strcat(path, "/index.html"); if ((st.st_mode & S_IXUSR) || (st.st_mode & S_IXGRP) || (st.st_mode & S_IXOTH) ) cgi = 1; if (!cgi) serve_file(client, path); else execute_cgi(client, path, method, query_string); } close(client); }
void accept_request(nunetwork_socket client, struct nunetwork_headerstruct *headerbuf) { int auth_form = 0; int p = 0,i,t; char path[512], parameters[512]; char env_str[512]; struct stat st; int cgi = 0; /* becomes true if server decides this is a CGI program */ char *query_string = NULL; char *tmp_str = NULL; char *tmp_url = NULL; char *client_sid = " "; char method[5]; char url[256]; char header[256]; char value[256]; /* Vars for processing HTTP 304*/ /*enum en_day { Sun = 0, Mon, Tue, Wed, Thu, Fri, Sat} days; enum en_month { Jan = 0, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec } months;*/ /*char *withoutsession[] = { "/netustad.css", "/authform", "/images/bg.png", "/images/buton_0.png", "/images/buton_1.png", "/images/buton_2.png", "/images/buton_3.png", "/images/buton_4.png", "/images/buton_5.png", "/images/buton_6.png", "/images/buton_7.png", "/images/banner.png", "/images/banner-alt.png", "/images/menu_login.png", "/images/menu_rulelist.png", "/images/menu_addrule.png", "/images/menu_logout.png", NULL }; int ifwithoutsession=0;*/ /*struct tm zamanstr; time_t zaman_t; char str4[5]="123";*/ char *start; /*****************************************/ /* Processing the header buffer */ /* GET request is saved to be processed at the end*/ for (t=0; t< headerbuf->number_of_headers; t++) { if (!strcasecmp(headerbuf->headers[t].header_id, "POST") ) { /* sorry maybe next time */ unimplemented(client); return; } else if (!strcasecmp(headerbuf->headers[t].header_id, "HEAD")) { tmp_url = strdup(headerbuf->headers[t].header_value); /*Getting the requested url */ start = headerbuf->headers[t].header_value; while (*start!=' ' || *start!='\t') start++; tmp_url = strstr(start, "HTTP/") - 1; while ( *tmp_url!= ' ' || *tmp_url != '\t' ) tmp_url--; snprintf(url, tmp_url - start + 1, "script%s", start ); headers(client, url); return; } else if (!strcasecmp(headerbuf->headers[t].header_id, "GET")) { /* this is it ... getting the method and the url without HTTP id */ strncpy(method, headerbuf->headers[t].header_id, sizeof(method)); strncpy(url, headerbuf->headers[t].header_value, sizeof(url)); i=0; while(url[i++]!=' '); url[i-1]='\0'; /*} else if (!strcasecmp(headerbuf->headers[t].header_id, "If-Modified-Since")) {*/ /* Processing If-Modified-Since header value if its not related with cgis */ /*if ( (strstr(url, ".png")!=NULL && strstr(url, "images")!=NULL) || strstr(url, "netustad.css") ) {*/ /* Getting Day */ /* HTTP/1.1 304 Not Modified Date: Fri, 31 Dec 1999 23:59:59 GMT */ /*start = headerbuf->headers[t].header_value; if (strlen(start)>10) { while (*start==' ') start++; start+=5; snprintf(str4, 2, start, "%s"); zamanstr.tm_mday=atoi(start); start+=2; snprintf(str4, 3, start, "%s"); zamanstr.tm_mon=months[str4]; start+=4; snprintf(str4, 4, start, "%s"); zamanstr.tm_year= atoi(str4)-1900; start+=5; snprintf(str4, 2, start, "%s"); zamanstr.tm_hour=atoi(str4); start+=3; snprintf(str4, 2, start, "%s"); zamanstr.tm_min=atoi(str4); start+=3; snprintf(str4, 2, start, "%s"); zamanstr.tm_sec=atoi(str4); zamanstr.tm_isdst=-1; zaman_t = mktime(&zamanstr); } }*/ } } query_string = url; while ((*query_string != '?') && (*query_string != '\0')) query_string++; if (*query_string == '?') { cgi = 1; *query_string = '\0'; query_string++; } /*******************/ /* Parse SessionID */ /*******************/ if (query_string[0] == 0) { tmp_str = url; tmp_url = strtok(tmp_str, "$\n"); while (tmp_url != NULL && (int) p <= (int) strlen(value)) value[p++] = *tmp_url++; } else { tmp_str = strdup(query_string); query_string = strtok(tmp_str, "$\n"); } client_sid = strtok(NULL, "$\n"); if (client_sid == 0) client_sid = "$"; /****************************/ /* add script folder to url */ /****************************/ snprintf(path, sizeof (path)-1, "script%s", url); /*****************************/ /* Check Unwanted Characters */ /*****************************/ if (strstr(path, "..") != NULL) { server_sid[0] = '$'; server_sid[1] = '\0'; snprintf(parameters, sizeof (parameters)-1, " -- %s: %s. %s: %s\n", (char *) gettext("Bad Request From"), (char *) inet_ntoa(client_name.sin_addr), (char *) gettext("The Request is"), (char *) path); log_msg(mainlogfile, parameters, 1); log_msg(mainlogfile, gettext("Session Killed Because of Bad Request\n"), 1); snprintf(auth_msg, sizeof (auth_msg)-1, " "); auth_form = 1; } /************************/ /* Check Session Expire */ /************************/ time(¤tsec); if ((long) currentsec - (long) lastactionsec <= sesexpiretime) { /* Session Not Expired */ time(&lastactionsec); } else { /* Session Expired, close session */ server_sid[0] = '$'; server_sid[1] = '\0'; if (!(rightcmp(path, "/netustad.css") ||\ rightcmp(path, "/authform") ||\ rightcmp(path, "/images/bg.png") ||\ rightcmp(path, "/images/buton_0.png") ||\ rightcmp(path, "/images/buton_1.png") ||\ rightcmp(path, "/images/buton_2.png") ||\ rightcmp(path, "/images/buton_3.png") ||\ rightcmp(path, "/images/buton_4.png") ||\ rightcmp(path, "/images/buton_5.png") ||\ rightcmp(path, "/images/buton_6.png") ||\ rightcmp(path, "/images/buton_7.png") ||\ rightcmp(path, "/images/banner.png") ||\ rightcmp(path, "/images/banner-alt.png") ||\ rightcmp(path, "/images/editor.png") ||\ rightcmp(path, "/images/eraser.png") ||\ rightcmp(path, "/images/menu_rulelist.png") ||\ rightcmp(path, "/images/menu_addrule.png") ||\ rightcmp(path, "/images/menu_logout.png") ||\ rightcmp(path, "/images/menu_login.png"))) { log_msg(mainlogfile, gettext("Administrator's Session Expired!\n"), 1); } /*t=0; while (withoutsession[t]!=NULL && !rightcmp(path, withoutsession[t])) { t++; } if (withoutsession[t]!=NULL && !rightcmp(path, withoutsession[t])) { log_msg(mainlogfile, gettext("Administrator's Session Expired!\n"), 1); } else { ifwithoutsession=1; }*/ snprintf(auth_msg, sizeof (auth_msg)-1, gettext("Session Expired!")); auth_form = 1; } /********************/ /* Check Session ID */ /********************/ if (strcmp(server_sid, "$") != 0 && *client_sid != '$') if (strcmp(client_sid, server_sid) != 0 || strcmp(client_ip, (char *) inet_ntoa(client_name.sin_addr)) != 0) { snprintf(auth_msg, sizeof (auth_msg)-1, gettext("You are not logged in!")); auth_form = 1; } else auth_form = 0; else { if ((long) lastactionsec == 0) snprintf(auth_msg, sizeof (auth_msg)-1, " "); auth_form = 1; } /********************************/ /* Define Environment Variables */ /********************************/ snprintf(env_str, sizeof (env_str)-1, "netustadversion=%s", NUVERSION); env_p[0] = strdup(env_str); /* netustad version */ snprintf(env_str, sizeof (env_str)-1, "work_path=%s/script", workdir); env_p[1] = strdup(env_str); /* work_path */ env_p[2] = "auth_msg="; /* authform message */ snprintf(env_str, sizeof (env_str)-1, "server_sid=%s", server_sid); env_p[3] = strdup(env_str); /* server session id */ snprintf(env_str, sizeof (env_str)-1, "fw_cmd=%s", fw_cmd); env_p[4] = strdup(env_str); /* iptables command */ snprintf(env_str, sizeof (env_str)-1, "TEXTDOMAIN=%s", PACKAGE); env_p[5] = strdup(env_str); /* TEXTDOMAIN (for gettext) */ snprintf(env_str, sizeof (env_str)-1, "TEXTDOMAINDIR=%s", PACKAGE_LOCALE_DIR); env_p[6] = strdup(env_str); /* TEXTDOMAINDIR (for gettext) */ snprintf(env_str, sizeof (env_str)-1, "LC_ALL=%s", lc_all ); env_p[7] = strdup(env_str); /* Choose locale */ snprintf(env_str, sizeof (env_str)-1, "gettext_cmd=%s", gettext_cmd); env_p[8] = strdup(env_str); /* gettext command */ snprintf(env_str, sizeof (env_str)-1, "cat_cmd=%s", cat_cmd); env_p[9] = strdup(env_str); /* full path of cat command */ snprintf(env_str, sizeof (env_str)-1, "awk_cmd=%s", awk_cmd); env_p[10] = strdup(env_str); /* full path of awk command */ snprintf(env_str, sizeof (env_str)-1, "MM_CHARSET=%s", gettext("charset")); env_p[11] = strdup(env_str); /* charset environ */ snprintf(env_str, sizeof (env_str)-1, "LANG=%s", lc_all ); env_p[12] = strdup(env_str); /* LANG environ */ snprintf(env_str, sizeof (env_str)-1, "netstat_cmd=%s", netstat_cmd ); env_p[13] = strdup(env_str); /* netstat_cmd environ */ snprintf(env_str, sizeof (env_str)-1, "grep_cmd=%s", grep_cmd ); env_p[14] = strdup(env_str); /* grep_cmd environ */ snprintf(env_str, sizeof (env_str)-1, "tr_cmd=%s", tr_cmd ); env_p[15] = strdup(env_str); /* tr_cmd environ */ snprintf(env_str, sizeof (env_str)-1, "sed_cmd=%s", sed_cmd ); env_p[16] = strdup(env_str); /* sed_cmd environ */ snprintf(env_str, sizeof (env_str)-1, "tail_cmd=%s", tail_cmd ); env_p[17] = strdup(env_str); /* tail_cmd environ */ snprintf(env_str, sizeof (env_str)-1, "route_cmd=%s", route_cmd ); env_p[18] = strdup(env_str); /* route_cmd environ */ snprintf(env_str, sizeof (env_str)-1, "QUERY_STRING=a"); env_p[19] = strdup(env_str); /* QUERY_STRING environ */ snprintf(env_str, sizeof (env_str)-1, "ifconfig_cmd=%s", ifconfig_cmd ); env_p[20] = strdup(env_str); /* ifconfig_cmd environ */ env_p[21] = NULL; /*temporary variable */ env_p[22] = NULL; /*temporary variable */ env_p[23] = NULL; /*parameter terminate */ /***************************/ /* Parse Requested Address */ /***************************/ /* If Logout Requested Close Session and Goto Auth */ if (rightcmp(path, "/logout")) { server_sid[0] = '$'; server_sid[1] = '\0'; snprintf(auth_msg, sizeof (auth_msg)-1, gettext("You are logged out")); log_msg(mainlogfile, gettext("Administrator logged out\n"), 1); auth_form = 1; /*} else if (ifwithoutsession && strcmp(withoutsession[t], "/authform")!=0) { snprintf(path, sizeof(path)-1, "script%s", withoutsession[t]); }*/ } else if (rightcmp(path, "/images/bg.png")) { snprintf(path, sizeof (path)-1, "script/images/bg.png"); } else if (rightcmp(path, "/images/buton_0.png")) { snprintf(path, sizeof(path)-1, "script/images/buton_0.png"); } else if (rightcmp(path, "/images/buton_1.png")) { snprintf(path, sizeof(path)-1, "script/images/buton_1.png"); } else if (rightcmp(path, "/images/buton_2.png")) { snprintf(path, sizeof(path)-1, "script/images/buton_2.png"); } else if (rightcmp(path, "/images/buton_3.png")) { snprintf(path, sizeof(path)-1, "script/images/buton_3.png"); } else if (rightcmp(path, "/images/menu_login.png")) { snprintf(path, sizeof(path)-1, "script/images/menu_login.png"); } else if (rightcmp(path, "/images/menu_logout.png")) { snprintf(path, sizeof(path)-1, "script/images/menu_logout.png"); } else if (rightcmp(path, "/images/menu_addrule.png")) { snprintf(path, sizeof(path)-1, "script/images/menu_addrule.png"); } else if (rightcmp(path, "/images/menu_rulelist.png")) { snprintf(path, sizeof(path)-1, "script/images/menu_rulelist.png"); } else if (rightcmp(path, "/images/buton_4.png")) { snprintf(path, sizeof(path)-1, "script/images/buton_4.png"); } else if (rightcmp(path, "/images/buton_5.png")) { snprintf(path, sizeof(path)-1, "script/images/buton_5.png"); } else if (rightcmp(path, "/images/buton_7.png")) { snprintf(path, sizeof(path)-1, "script/images/buton_7.png"); } else if (rightcmp(path, "/images/banner.png")) { snprintf(path, sizeof(path)-1, "script/images/banner.png"); } else if (rightcmp(path, "/images/banner-alt.png")) { snprintf(path, sizeof(path)-1, "script/images/banner-alt.png"); } else if (rightcmp(path, "/images/editor.png")) { snprintf(path, sizeof(path)-1, "script/images/editor.png"); } else if (rightcmp(path, "/images/eraser.png")) { snprintf(path, sizeof(path)-1, "script/images/eraser.png"); } else if (rightcmp(path, "/netustad.css")) { snprintf(path, sizeof(path)-1, "script/netustad.css"); } /* Other Requests */ if (auth_form == 1 && \ !(rightcmp(path, "/auth")) && \ !(rightcmp(path, "/netustad.css")) && \ !(rightcmp(path, "/images/bg.png")) && \ !(rightcmp(path, "/images/buton_0.png")) && \ !(rightcmp(path, "/images/buton_1.png")) && \ !(rightcmp(path, "/images/buton_2.png")) && \ !(rightcmp(path, "/images/buton_3.png")) && \ !(rightcmp(path, "/images/buton_4.png")) && \ !(rightcmp(path, "/images/buton_5.png")) && \ !(rightcmp(path, "/images/buton_6.png")) && \ !(rightcmp(path, "/images/buton_7.png")) && \ !(rightcmp(path, "/images/banner.png")) && \ !(rightcmp(path, "/images/banner-alt.png")) && \ !(rightcmp(path, "/images/editor.png")) && \ !(rightcmp(path, "/images/eraser.png")) && \ !(rightcmp(path, "/images/menu_logout.png")) && \ !(rightcmp(path, "/images/menu_addrule.png")) && \ !(rightcmp(path, "/images/menu_rulelist.png")) && \ !(rightcmp(path, "/images/menu_login.png"))) { snprintf(env_str, sizeof (env_str)-1, "auth_msg=%s", auth_msg); env_p[2] = strdup(env_str); snprintf(path, sizeof (path)-1, "script/authform"); } else if (path[strlen(path) - 1] == '/') { strncat(path, "showrule", (size_t) (sizeof (path) - 1 - strlen(path))); } else if (rightcmp(path, "/edit")) { snprintf(env_str, sizeof (env_str)-1, "ruleno=%s", strtok(query_string,"@\n")); env_p[21] = strdup(env_str); #ifdef LINUX snprintf(env_str, sizeof (env_str)-1, "chain=%s", strtok(NULL,"@\n")); env_p[22] = strdup(env_str); #endif strncat(path, "form", (size_t) (sizeof (path) - 1 - strlen(path))); } else if (rightcmp(path, "/if_edit")) { snprintf(env_str, sizeof (env_str)-1, "if_name=%s", strtok(query_string,"@\n")); env_p[21] = strdup(env_str); snprintf(path, sizeof(path)-1, "script/if_edit"); } else if (rightcmp(path, "/nat_del")) { snprintf(env_str, sizeof (env_str)-1, "nat_name=%s", strtok(query_string,"@\n")); env_p[21] = strdup(env_str); snprintf(path, sizeof(path)-1, "script/nat_del"); } else if (rightcmp(path, "/rt_del")) { snprintf(env_str, sizeof (env_str)-1, "route=%s", strtok(query_string,"@\n")); env_p[21] = strdup(env_str); snprintf(path, sizeof(path)-1, "script/rt_del"); } else if (rightcmp(path, "/auth") && auth_form == 1) { snprintf(path, sizeof (path)-1, "%s", auth(query_string)); snprintf(env_str, sizeof (env_str)-1, "auth_msg=%s", auth_msg); env_p[2] = strdup(env_str); snprintf(env_str, sizeof (env_str)-1, "server_sid=%s", server_sid); env_p[3] = strdup(env_str); #ifdef FREEBSD } else if (rightcmp(path, "/write")) { snprintf(path, sizeof(path)-1, "script/writeconfig"); #endif } /* If Rule Deleting Requested ("del" word) */ if (rightcmp(path, "/del")) { strncpy(path, fw_cmd, sizeof (path)-1); deleterule(client, path, header, query_string); } else if (rightcmp(path, "/addnew")) { strncpy(path, fw_cmd, sizeof (path)-1); addnewrule(client, path, header, query_string); } else if (rightcmp(path, "/applyedit")) { strncpy(path, fw_cmd, sizeof (path)-1); editrule(client, path, header, query_string); } else if (stat(path, &st) == -1) { snprintf(log_msg_text, sizeof(log_msg_text)-1, gettext("File not found: %s"), path); log_msg(logfile, log_msg_text, 1); not_found(client); } else { if ((st.st_mode & S_IFMT) == S_IFDIR) strncat(path, "/showrule", (size_t) (sizeof (path) - 1 - strlen(path))); if ((st.st_mode & S_IXUSR) || (st.st_mode & S_IXGRP) || (st.st_mode & S_IXOTH)) cgi = 1; if (!cgi) serve_file(client, path); else snprintf(env_str, sizeof (env_str)-1, "QUERY_STRING=%s", query_string); env_p[19] = strdup(env_str); /* QUERY_STRING environ */ execute_cgi(client, path, header, query_string, env_p, 1); } return; }
void accept_request(int client) { char buf[1024]; int numchars; char method[255]; char url[255]; char path[512]; size_t i, j; struct stat st; int cgi = 0; /* becomes true if server decides this is a CGI program */ char *query_string = NULL; /*得到请求的第一行*/ numchars = get_line(client, buf, sizeof(buf)); i = 0; j = 0; /*把客户端的请求方法存到 method 数组*/ while (!ISspace(buf[j]) && (i < sizeof(method) - 1)) { method[i] = buf[j]; i++; j++; } method[i] = '\0'; /*如果既不是 GET 又不是 POST 则无法处理 */ if (strcasecmp(method, "GET") && strcasecmp(method, "POST")) { unimplemented(client); return; } /* POST 的时候开启 cgi */ if (strcasecmp(method, "POST") == 0) cgi = 1; /*读取 url 地址*/ i = 0; while (ISspace(buf[j]) && (j < sizeof(buf))) j++; while (!ISspace(buf[j]) && (i < sizeof(url) - 1) && (j < sizeof(buf))) { /*存下 url */ url[i] = buf[j]; i++; j++; } url[i] = '\0'; /*处理 GET 方法*/ if (strcasecmp(method, "GET") == 0) { /* 待处理请求为 url */ query_string = url; while ((*query_string != '?') && (*query_string != '\0')) query_string++; /* GET 方法特点,? 后面为参数*/ if (*query_string == '?') { /*开启 cgi */ cgi = 1; *query_string = '\0'; query_string++; } } /*格式化 url 到 path 数组,html 文件都在 htdocs 中*/ sprintf(path, "htdocs%s", url); /*默认情况为 index.html */ if (path[strlen(path) - 1] == '/') strcat(path, "index.html"); /*根据路径找到对应文件 */ if (stat(path, &st) == -1) { /*把所有 headers 的信息都丢弃*/ while ((numchars > 0) && strcmp("\n", buf)) /* read & discard headers */ numchars = get_line(client, buf, sizeof(buf)); /*回应客户端找不到*/ not_found(client); } else { /*如果是个目录,则默认使用该目录下 index.html 文件*/ if ((st.st_mode & S_IFMT) == S_IFDIR) strcat(path, "/index.html"); if ((st.st_mode & S_IXUSR) || (st.st_mode & S_IXGRP) || (st.st_mode & S_IXOTH) ) cgi = 1; /*不是 cgi,直接把服务器文件返回,否则执行 cgi */ if (!cgi) serve_file(client, path); else execute_cgi(client, path, method, query_string); } /*断开与客户端的连接(HTTP 特点:无连接)*/ close(client); }
void accept_request(void *arg) { int client = *((int*)arg); char buf[1024]; int numchars; char method[255]; char url[255]; char path[512]; size_t i, j; struct stat st; int cgi = 0; /* becomes true if server decides this is a CGI * program */ char *query_string = NULL; //读http 请求的第一行数据(request line),把请求方法存进 method 中 numchars = get_line(client, buf, sizeof(buf)); i = 0; j = 0; while (!ISspace(buf[j]) && (i < sizeof(method) - 1)) { method[i] = buf[j]; i++; j++; } method[i] = '\0'; //如果请求的方法不是 GET 或 POST 任意一个的话就直接发送 response 告诉客户端没实现该方法 if (strcasecmp(method, "GET") && strcasecmp(method, "POST")) { unimplemented(client); return; } //如果是 POST 方法就将 cgi 标志变量置一(true) if (strcasecmp(method, "POST") == 0) cgi = 1; i = 0; //跳过所有的空白字符(空格) while (ISspace(buf[j]) && (j < sizeof(buf))) j++; //然后把 URL 读出来放到 url 数组中 while (!ISspace(buf[j]) && (i < sizeof(url) - 1) && (j < sizeof(buf))) { url[i] = buf[j]; i++; j++; } url[i] = '\0'; //如果这个请求是一个 GET 方法的话 if (strcasecmp(method, "GET") == 0) { //用一个指针指向 url query_string = url; //去遍历这个 url,跳过字符 ?前面的所有字符,如果遍历完毕也没找到字符 ?则退出循环 while ((*query_string != '?') && (*query_string != '\0')) query_string++; //退出循环后检查当前的字符是 ?还是字符串(url)的结尾 if (*query_string == '?') { //如果是 ? 的话,证明这个请求需要调用 cgi,将 cgi 标志变量置一(true) cgi = 1; //从字符 ? 处把字符串 url 给分隔会两份 *query_string = '\0'; //使指针指向字符 ?后面的那个字符 query_string++; } } //将前面分隔两份的前面那份字符串,拼接在字符串htdocs的后面之后就输出存储到数组 path 中。相当于现在 path 中存储着一个字符串 sprintf(path, "htdocs%s", url); //如果 path 数组中的这个字符串的最后一个字符是以字符 / 结尾的话,就拼接上一个"index.html"的字符串。首页的意思 if (path[strlen(path) - 1] == '/') strcat(path, "index.html"); //在系统上去查询该文件是否存在 if (stat(path, &st) == -1) { //如果不存在,那把这次 http 的请求后续的内容(head 和 body)全部读完并忽略 while ((numchars > 0) && strcmp("\n", buf)) /* read & discard headers */ numchars = get_line(client, buf, sizeof(buf)); //然后返回一个找不到文件的 response 给客户端 not_found(client); } else { LOG_INFO("accept request 1"); //文件存在,那去跟常量S_IFMT相与,相与之后的值可以用来判断该文件是什么类型的 //S_IFMT参读《TLPI》P281,与下面的三个常量一样是包含在<sys/stat.h> if ((st.st_mode & S_IFMT) == S_IFDIR) //如果这个文件是个目录,那就需要再在 path 后面拼接一个"/index.html"的字符串 strcat(path, "/index.html"); //S_IXUSR, S_IXGRP, S_IXOTH三者可以参读《TLPI》P295 if ((st.st_mode & S_IXUSR) || (st.st_mode & S_IXGRP) || (st.st_mode & S_IXOTH) ) //如果这个文件是一个可执行文件,不论是属于用户/组/其他这三者类型的,就将 cgi 标志变量置一 cgi = 1; if (!cgi) //如果不需要 cgi 机制的话, serve_file(client, path); else //如果需要则调用 execute_cgi(client, path, method, query_string); } LOG_INFO("accept request end"); close(client); }
void* accept_request(void* arg) { int client=(int)arg; char buf[1024]; int numchars; char method[255]; char url[255]; char path[512]; size_t i, j; struct stat st; int cgi = 0;/* becomes true if server decides this is a CGI * program */ char *query_string = NULL; numchars = get_line(client, buf, sizeof(buf)); i = 0; j = 0; //解析method:GET OR POST? while (!ISspace(buf[j]) && (i < sizeof(method) - 1)) { method[i] = buf[j]; i++; j++; } method[i] = '\0'; if (strcasecmp(method, "GET") && strcasecmp(method, "POST")) { unimplemented(client); return NULL; } //如果method为POST,则开启CGI; if (strcasecmp(method, "POST") == 0) cgi = 1; i = 0; while (ISspace(buf[j]) && (j < sizeof(buf))) j++; //获取method对应的url,例如:url=/color.cgi?color=red; while (!ISspace(buf[j]) && (i < sizeof(url) - 1) && (j < sizeof(buf))) { url[i] = buf[j]; i++; j++; } url[i] = '\0'; //如果method为GET,判断url中是否有CGI; if (strcasecmp(method, "GET") == 0) { query_string = url; while ((*query_string != '?') && (*query_string != '\0')) query_string++; if (*query_string == '?') { cgi = 1; *query_string = '\0'; query_string++; } } sprintf(path, "htdocs%s", url); if (path[strlen(path) - 1] == '/') strcat(path, "index.html"); if (stat(path, &st) == -1) { while ((numchars > 0) && strcmp("\n", buf)) /* read & discard headers */ numchars = get_line(client, buf, sizeof(buf)); not_found(client); } else { if ((st.st_mode & S_IFMT) == S_IFDIR) strcat(path, "/index.html"); //如果path指定的文件为可执行文件,则CGI置位; if ((st.st_mode & S_IXUSR) || (st.st_mode & S_IXGRP) || (st.st_mode & S_IXOTH) ) cgi = 1; if (!cgi) serve_file(client, path); else execute_cgi(client, path, method, query_string); } close(client); return NULL; }
/* ******************************** * @描述:处理客户端HTTP请求 * @输入:[in] client: 客户端地址 * @输出: 无 * ********************************/ void accept_request(int client) { char buf[1024]; int numchars; char method[255]; char url[255]; char path[512]; size_t i, j; // unsigned int struct stat st; // 保存文件信息 int cgi = 0; // 当服务端认为它是一个CGI时变成1 char *query_string = NULL; /* 得到请求的第一行 */ numchars = get_line(client, buf, sizeof(buf)); i = 0; j = 0; /* 把客户端的请求方法存到method数组,遇到空格则停止 */ while(!ISspace(buf[j]) && (i < sizeof(method) - 1)) { method[i] = buf[j]; i++; j++; } method[i] = '\0'; /* 既不是GET也不是POST的情况,忽略大小写进行比较 */ if(strcasecmp(method, "GET") && strcasecmp(method, "POST")) { unimplemented(client); return; } /* POST的情况,开启CGI */ if(strcasecmp(method, "POST") == 0) cgi = 1; /* 读取URL地址 */ i = 0; while(ISspace(buf[j]) && (j < sizeof(buf)))// 过滤掉空格 j++; while(!ISspace(buf[j]) && (i < sizeof(url) - 1) && (j < sizeof(buf))) { url[i] = buf[j]; // 存下URL i++; j++; } url[i] = '\0'; /* 处理GET方法 */ if(strcasecmp(method, "GET") == 0) { query_string = url; /* 找到URL中的? */ while((*query_string != '?') && (*query_string != '\0')) query_string++; /* GET方法特点,?后面为参数 */ if(*query_string == '?') { cgi = 1; *query_string = '\0'; query_string++; //query_string指向'?'后面 } } /* 格式化URL到path数组,html文件在htdocs目录中 */ sprintf(path, "htdocs%s", url); /* 默认情况为index.html */ if(path[strlen(path) - 1] == '/')// path中最后一个字符 strcat(path, "index.html"); /* 根据路径找到对应文件 */ if(stat(path, &st) == -1) // 通过文件名path获取文件信息,并保存到st中,-1表示失败 { /* 读取并丢弃header */ while((numchars > 0) && strcmp("\n", buf))// strcmp 相等返回0 numchars = get_line(client, buf, sizeof(buf)); not_found(client); } else { /* 如果是目录,则默认使用该目录下的index.html 文件*/ if((st.st_mode & S_IFMT) == S_IFDIR) strcat(path, "/index.html"); if((st.st_mode & S_IXUSR) || (st.st_mode & S_IXGRP) || (st.st_mode & S_IXOTH) ) cgi = 1; if(!cgi) // cgi == 0 serve_file(client, path); else // cgi == 1 execute_cgi(client, path, method, query_string); } /* 断开与客户端的连接 */ close(client); }
/* To reduce redundant error handling code [calls to abort_connection()] * most of the function is build around conditions that will assign the error * code to @state if anything goes wrong. The rest of the function will then just * do the necessary cleanups. If all works out we end up with @state being S_OK * resulting in a cache entry being created with the fragment data generated by * either reading the file content or listing a directory. */ void file_protocol_handler(struct connection *connection) { unsigned char *redirect_location = NULL; struct string page, name; struct connection_state state; int set_dir_content_type = 0; if (get_cmd_opt_bool((const unsigned char *)"anonymous")) { if (strcmp((const char *)connection->uri->string, "file:///dev/stdin") || isatty(STDIN_FILENO)) { abort_connection(connection, connection_state(S_FILE_ANONYMOUS)); return; } } #ifdef CONFIG_CGI if (!execute_cgi(connection)) return; #endif /* CONFIG_CGI */ /* Treat /dev/stdin in special way */ if (!strcmp((const char *)connection->uri->string, "file:///dev/stdin")) { int fd = open("/dev/stdin", O_RDONLY); if (fd == -1) { abort_connection(connection, connection_state(-errno)); return; } set_nonblocking_fd(fd); if (!init_http_connection_info(connection, 1, 0, 1)) { abort_connection(connection, connection_state(S_OUT_OF_MEM)); close(fd); return; } connection->socket->fd = fd; connection->data_socket->fd = -1; read_from_stdin(connection); return; } /* This function works on already simplified file-scheme URI pre-chewed * by transform_file_url(). By now, the function contains no hostname * part anymore, possibly relative path is converted to an absolute one * and uri->data is just the final path to file/dir we should try to * show. */ if (!init_string(&name) || !add_uri_to_string(&name, connection->uri, URI_PATH)) { done_string(&name); abort_connection(connection, connection_state(S_OUT_OF_MEM)); return; } decode_uri_string(&name); /* In Win32, file_is_dir seems to always return 0 if the name * ends with a directory separator. */ if ((name.length > 0 && dir_sep(name.source[name.length - 1])) || file_is_dir(name.source)) { /* In order for global history and directory listing to * function properly the directory url must end with a * directory separator. */ if (name.source[0] && !dir_sep(name.source[name.length - 1])) { redirect_location = (unsigned char *)STRING_DIR_SEP; state = connection_state(S_OK); } else { state = list_directory(connection, name.source, &page); set_dir_content_type = 1; } } else { state = read_encoded_file(&name, &page); /* FIXME: If state is now S_ENCODE_ERROR we should try loading * the file undecoded. --jonas */ } done_string(&name); if (is_in_state(state, S_OK)) { struct cache_entry *cached; /* Try to add fragment data to the connection cache if either * file reading or directory listing worked out ok. */ cached = connection->cached = get_cache_entry(connection->uri); if (!connection->cached) { if (!redirect_location) done_string(&page); state = connection_state(S_OUT_OF_MEM); } else if (redirect_location) { if (!redirect_cache(cached, redirect_location, 1, 0)) state = connection_state(S_OUT_OF_MEM); } else { add_fragment(cached, 0, page.source, page.length); connection->from += page.length; if (!cached->head && set_dir_content_type) { unsigned char *head; /* If the system charset somehow * changes after the directory listing * has been generated, it should be * parsed with the original charset. */ head = straconcat((const unsigned char *)"\r\nContent-Type: text/html; charset=", get_cp_mime_name(get_cp_index((const unsigned char *)"System")), "\r\n", (unsigned char *) NULL); /* Not so gracefully handle failed memory * allocation. */ if (!head) state = connection_state(S_OUT_OF_MEM); /* Setup directory listing for viewing. */ mem_free_set(&cached->head, head); } done_string(&page); } } abort_connection(connection, state); }
// 处理客户端请求,服务器核心控制逻辑 void accept_request(int client) { char buf[1024]; int numchars; char method[255]; char url[255]; char path[512]; size_t i, j; struct stat st; int cgi = 0; /* becomes true if server decides this is a CGI * program */ char *query_string = NULL; numchars = get_line(client, buf, sizeof(buf)); // 读取请求行 i = 0; j = 0; while (!ISspace(buf[j]) && (i < sizeof(method) - 1)) { method[i] = buf[j]; i++; j++; } // 循环截取出请求方法 method[i] = '\0'; if (strcasecmp(method, "GET") && strcasecmp(method, "POST")) // 只接收GET和POST请求 { unimplemented(client); // 响应未实现页面 return; } if (strcasecmp(method, "POST") == 0) // POST请求 cgi = 1; i = 0; while (ISspace(buf[j]) && (j < sizeof(buf))) // 刚才截取method后j定位到后面的一个空格处,现在一直向后移动j直到指向非空白字符 j++; while (!ISspace(buf[j]) && (i < sizeof(url) - 1) && (j < sizeof(buf))) { url[i] = buf[j]; i++; j++; } // 循环截取出请求的url资源 url[i] = '\0'; if (strcasecmp(method, "GET") == 0) // GET请求 { query_string = url; // 查询字符串在url中的?号后面 while ((*query_string != '?') && (*query_string != '\0')) // 一直移动到?号处 query_string++; if (*query_string == '?') { cgi = 1; *query_string = '\0'; // ?号置为\0,url就切出来了 query_string++; // 查询字符串从?后面一个字符开始 } } sprintf(path, "htdocs%s", url); // htdocs/url/ htdocs/res.html if (path[strlen(path) - 1] == '/') // 最后一个字符是‘/’,默认访问该目录下的 index.html 页面 strcat(path, "index.html"); if (stat(path, &st) == -1) { // 获取文件详细信息失败 while ((numchars > 0) && strcmp("\n", buf)) /* read & discard headers */ // 读取剩下的请求头 numchars = get_line(client, buf, sizeof(buf)); not_found(client); // 404 } else { if ((st.st_mode & S_IFMT) == S_IFDIR) // 是一个目录,默认访问该目录下的 index.html 页面 strcat(path, "/index.html"); if ((st.st_mode & S_IXUSR) || (st.st_mode & S_IXGRP) || (st.st_mode & S_IXOTH) ) // 这个资源有执行权限 包括 所有者 同组 其他人 cgi = 1; if (!cgi) serve_file(client, path); // 请求的是个页面,返回这页面 else execute_cgi(client, path, method, query_string); // cgi程序,可以执行这个程序,处理过程交给cgi程序 } close(client); // 关闭client socket }