message::error_code request_header::end_of_request() { const header* const host_header = find_header_impl("host"); if ( host_header == 0 ) return bad_request(); const tools::substring host = host_header->value(); tools::substring::const_iterator pos = host.end(); for ( ; pos != host.begin() && std::isdigit(*(pos-1)) != 0; --pos ) ; if ( pos != host.begin() && *(pos-1) == ':' ) { if ( pos != host.end() && !parse_number(pos, host.end(), port_) || port_ > 0xffff ) return bad_request(); host_ = tools::substring(host.begin(), pos-1); } else { host_ = host; } return ok; }
void TCGI::start(TBuffer * rb_, TBuffer * wb_) { rb = rb_; wb = wb_; r = new TRequest(rb); if (r->status < 0) { bad_request(); } else { std::string path = r->path; std::string fpath = folder + path; std::ifstream * f = new std::ifstream(fpath, std::ios::in ); if (!f->is_open()) { wb->append(t404); } else { std::string content; getline(*f, content, '\0'); f->close(); std::stringstream ss; ss << "HTTP/1.0 200 OK\r\nContent-length: " << content.size() << "\r\nConnection: close\r\nContent-Type: text/html\r\n\r\n" << content; wb->append(ss.str()); } delete f; } return; }
/** * NAME: cgi_read * PURPOSE: read all the given CGI parameters * ARGS: charset - character set to report errors * RETURN: 0 - OK, * -1 - error * NOTE: parse routines write error messages directly to stderr */ int cgi_read(char const *charset) { char *ct = 0; query = getenv("QUERY_STRING"); if (query) { source = 0; if (do_cgi_read() < 0) return -1; } ct = getenv("CONTENT_TYPE"); if (ct && !strncmp(ct, multipart, sizeof(multipart) - 1)) { /* got a multipart/form-data */ return parse_multipart(charset); } const unsigned char *cl = getenv("CONTENT_LENGTH"); if (cl) { errno = 0; char *eptr = NULL; int val = strtol(cl, &eptr, 10); if (errno || *eptr || val < 0) { bad_request(charset); exit(0); } if (val > MAX_CONTENT_LENGTH) { request_too_large(charset); exit(0); } content_length = val; } source = 1; if (do_cgi_read() < 0) return -1; return 0; }
void accept_request(dino_http_site_t *dino_site, dino_handle_t *dhandle) { // Setup DHANDLE: // if (!read_request(&dhandle->http)) { bad_request(dhandle->http.socket); } else { // Parse the URL Parameters. // stack_char_ptr_t *url_stack = stack_ptr_parse(NULL, string_buffer_c_string(dhandle->http.request.url), "/"); // Search for a match... // dino_route_t *route = list_method_find(dino_site->list, dhandle->http.request.method, url_stack); // Do we have a route? // if (NULL != route) { invoke_method(route, &dhandle->http, url_stack); } else { fprintf(stderr, "[ERROR] Path %s not found; \n\r", string_buffer_c_string(dhandle->http.request.url)); } stack_ptr_free(url_stack); } }
int cmd_main(int argc, const char **argv) { char *method = getenv("REQUEST_METHOD"); char *dir; struct service_cmd *cmd = NULL; char *cmd_arg = NULL; int i; struct strbuf hdr = STRBUF_INIT; set_die_routine(die_webcgi); set_die_is_recursing_routine(die_webcgi_recursing); if (!method) die("No REQUEST_METHOD from server"); if (!strcmp(method, "HEAD")) method = "GET"; dir = getdir(); for (i = 0; i < ARRAY_SIZE(services); i++) { struct service_cmd *c = &services[i]; regex_t re; regmatch_t out[1]; if (regcomp(&re, c->pattern, REG_EXTENDED)) die("Bogus regex in service table: %s", c->pattern); if (!regexec(&re, dir, 1, out, 0)) { size_t n; if (strcmp(method, c->method)) return bad_request(&hdr, c); cmd = c; n = out[0].rm_eo - out[0].rm_so; cmd_arg = xmemdupz(dir + out[0].rm_so + 1, n - 1); dir[out[0].rm_so] = 0; break; } regfree(&re); } if (!cmd) not_found(&hdr, "Request not supported: '%s'", dir); setup_path(); if (!enter_repo(dir, 0)) not_found(&hdr, "Not a git repository: '%s'", dir); git_config(git_default_config, NULL); if (!getenv("GIT_HTTP_EXPORT_ALL") && access("git-daemon-export-ok", F_OK) ) not_found(&hdr, "Repository not exported: '%s'", dir); http_config(); max_request_buffer = git_env_ulong("GIT_HTTP_MAX_REQUEST_BUFFER", max_request_buffer); cmd->imp(&hdr, cmd_arg); return 0; }
void do_request(struct wen_request *request) { if(!parse_request(request)){ bad_request(request); wen_free(request); return ; } //wen_free(request); }
char * tracker_handle_request (char *pkey, char *req, announce_info_t *ai, char *info_hash) { if ((strcmp (pkey, "announce") == 0) || (strcmp (pkey, "scrape") == 0)) { return missing_pass_key (); } if ((strcmp (req, "announce") != 0) && (strcmp (req, "scrape") != 0)) { return bad_request (); } debug_unimplemented (); return NULL; }
/* Consumes connection file descriptors from the shared buffer and * processes them. */ void *thread(void *vargp){ // avoid memory leak Pthread_detach(pthread_self()); req_t request; int result; while(1){ int connfd = sbuf_remove(&sbuf); if((result = process_request(connfd, &request)) == -1){ fprintf(stderr,"process_request failed\n"); bad_request(connfd); free_req(request); Close(connfd); continue; } forward_request(connfd, request); Close(connfd); } }
void server::HttpServer::worker(server::TcpServerConnection* connection) { server::HttpServerSession session; session.connection = connection; try { process_request(&session); check_request(&session); prepare_session(&session); request_handler(session); check_session_response(&session); send_response(&session); } catch(Exception& e) { bad_request(&session, e); } catch(std::bad_alloc& e) { } }
void echo_error_to_client(int client, int error_code) { switch(error_code) { case 400: // request error bad_request(client); break; case 404: // not found not_found(client); break; case 500: // server error //server_error(client); break; case 503: // server unavailable //server_unavailable(client); break; //............................... default: //default_error(client); break; } }
void execute_cgi(int client, const char *path, const char *method, const char *query_string) { char buf[1024]; int cgi_output[2]; int cgi_input[2]; pid_t pid; int status; int i; char c; int numchars = 1; int content_length = -1; //往 buf 中填东西以保证能进入下面的 while buf[0] = 'A'; buf[1] = '\0'; //如果是 http 请求是 GET 方法的话读取并忽略请求剩下的内容 if (strcasecmp(method, "GET") == 0) while ((numchars > 0) && strcmp("\n", buf)) /* read & discard headers */ numchars = get_line(client, buf, sizeof(buf)); else /* POST */ { //只有 POST 方法才继续读内容 numchars = get_line(client, buf, sizeof(buf)); //这个循环的目的是读出指示 body 长度大小的参数,并记录 body 的长度大小。其余的 header 里面的参数一律忽略 //注意这里只读完 header 的内容,body 的内容没有读 while ((numchars > 0) && strcmp("\n", buf)) { buf[15] = '\0'; if (strcasecmp(buf, "Content-Length:") == 0) content_length = atoi(&(buf[16])); //记录 body 的长度大小 numchars = get_line(client, buf, sizeof(buf)); } //如果 http 请求的 header 没有指示 body 长度大小的参数,则报错返回 if (content_length == -1) { bad_request(client); return; } } sprintf(buf, "HTTP/1.0 200 OK\r\n"); send(client, buf, strlen(buf), 0); //下面这里创建两个管道,用于两个进程间通信 if (pipe(cgi_output) < 0) { cannot_execute(client); return; } if (pipe(cgi_input) < 0) { cannot_execute(client); return; } //创建一个子进程 if ( (pid = fork()) < 0 ) { cannot_execute(client); return; } //子进程用来执行 cgi 脚本 if (pid == 0) /* child: CGI script */ { char meth_env[255]; char query_env[255]; char length_env[255]; //dup2()包含<unistd.h>中,参读《TLPI》P97 //将子进程的输出由标准输出重定向到 cgi_ouput 的管道写端上 dup2(cgi_output[1], 1); //将子进程的输出由标准输入重定向到 cgi_ouput 的管道读端上 dup2(cgi_input[0], 0); //关闭 cgi_ouput 管道的读端与cgi_input 管道的写端 close(cgi_output[0]); close(cgi_input[1]); //构造一个环境变量 sprintf(meth_env, "REQUEST_METHOD=%s", method); //putenv()包含于<stdlib.h>中,参读《TLPI》P128 //将这个环境变量加进子进程的运行环境中 putenv(meth_env); //根据http 请求的不同方法,构造并存储不同的环境变量 if (strcasecmp(method, "GET") == 0) { sprintf(query_env, "QUERY_STRING=%s", query_string); putenv(query_env); } else { /* POST */ sprintf(length_env, "CONTENT_LENGTH=%d", content_length); putenv(length_env); } //execl()包含于<unistd.h>中,参读《TLPI》P567 //最后将子进程替换成另一个进程并执行 cgi 脚本 execl(path, path, NULL); exit(0); } else { /* parent */ //父进程则关闭了 cgi_output管道的写端和 cgi_input 管道的读端 close(cgi_output[1]); close(cgi_input[0]); //如果是 POST 方法的话就继续读 body 的内容,并写到 cgi_input 管道里让子进程去读 if (strcasecmp(method, "POST") == 0) for (i = 0; i < content_length; i++) { recv(client, &c, 1, 0); write(cgi_input[1], &c, 1); } //然后从 cgi_output 管道中读子进程的输出,并发送到客户端去 while (read(cgi_output[0], &c, 1) > 0) send(client, &c, 1, 0); //关闭管道 close(cgi_output[0]); close(cgi_input[1]); //等待子进程的退出 waitpid(pid, &status, 0); } }
int handle_client_connection() { char buffer[8096]; int buffer_len; // Length of buffer char method[256]; char url[256]; char version[256]; int i = 0, // Used to iterate over the first line to get method, url, version j = 0; // Read first line buffer_len = read_line(client_sockfd, buffer, sizeof(buffer)); // Unable to read from socket, not sure what to do in this case if (buffer_len <= 0) { return -1; } fprintf(stderr, "==== Read Next Request ====\n"); // Get Method (e.g. GET, POST, etc) while ((i < (sizeof(method) - 1)) && (!isspace(buffer[i]))) { method[i] = buffer[i]; i++; } method[i] = '\0'; // fprintf(stderr, "method: %s\n", method); // Skip over spaces while (i < buffer_len && isspace(buffer[i])) { i++; } // Get URL j = 0; while (i < buffer_len && (j < (sizeof(url) - 1)) && !isspace(buffer[i])) { url[j] = buffer[i]; i++; j++; } url[j] = '\0'; // fprintf(stderr, "url: %s\n", url); // Skip over spaces while (i < buffer_len && isspace(buffer[i])) { i++; } j = 0; while (j < sizeof(version) - 1 && !isspace(buffer[i])) { version[j] = buffer[i]; i++; j++; } version[j] = '\0'; // fprintf(stderr, "version: %s\n", version); read_headers(); if (header_err_flag) { keep_alive = FALSE; bad_request(); return -1; } if (content_length > 0) { content = (char*) malloc(content_length + 1); read_socket(client_sockfd, content, content_length); } // fprintf(stderr, "Content-Length: %d\n", content_length); // fprintf(stderr, "Connection (keep_alive): %d\n", keep_alive); // fprintf(stderr, "Cookie: %d\n", cookie); // fprintf(stderr, "If-Modified-Since Valid Time: %d\n", time_is_valid); // fprintf(stderr, "If-Modified-Since Time: %p\n", if_modified_since); if (content != NULL) { // fprintf(stderr, "Content: %s\n", content); } /***********************************************************/ /* Full message has been read, respond to client */ /***********************************************************/ if (strcmp(method, "GET") != 0) { // Inform client we don't support method fprintf(stderr, "Method Not Allowed: %s\n", method); method_not_allowed(); return 0; } if (cookie) { // Inform client we don't support cookies not_implemented(); return 0; } if (not_eng) { // Inform client we only support English not_implemented(); return 0; } if (!acceptable_text) { // Inform client we only support plain text not_implemented(); return 0; } if (!acceptable_charset) { // Inform client we only support ASCII not_implemented(); return 0; } // Fix filename char file_path[512]; sprintf(file_path, "htdocs%s", url); if (file_path[strlen(file_path)-1] == '/') { file_path[strlen(file_path)-1] = '\0'; } // fprintf(stderr, "%s\n", file_path); int fname_valid = is_valid_fname(file_path); struct stat file_info; if (!fname_valid) { // invalid filename fprintf(stderr, "403 Forbidden: Invalid file name\n"); forbidden(); return 0; } if (stat(file_path, &file_info)) { fprintf(stderr, "404 Not Found: Stat failed\n"); // Stat failed not_found(); return 1; } if (!S_ISREG(file_info.st_mode)) { // Not a file forbidden(); fprintf(stderr, "403 Forbidden: Not a regular file\n"); return 0; } if (!(file_info.st_mode & S_IRUSR)) { // No read permissions forbidden(); fprintf(stderr, "403 Forbidden: No read permissions\n"); return 0; } FILE *f = fopen(file_path, "r"); if (f == NULL) { // No file not_found(); fprintf(stderr, "404 Not Found: Unable to open file\n"); return 0; } if (if_modified_since != NULL) { struct tm *last_modified = gmtime(&file_info.st_mtime); time_t last = mktime(last_modified); time_t since = mktime(if_modified_since); double diff = difftime(last, since); if (diff <= 0) { fprintf(stderr, "304 Not Modified\n"); not_modified(); return 0; } } fprintf(stderr, "All looks good, serving up content in %s\n", file_path); char *file_contents = NULL; int contents_length = 0; char line[512]; while (fgets(line, sizeof(line), f) != NULL) { if (file_contents != NULL) { char *new_contents = (char*) malloc(contents_length + strlen(line) + 1); strcpy(new_contents, file_contents); strcpy(new_contents + strlen(new_contents), line); contents_length += strlen(line); free(file_contents); file_contents = new_contents; } else { file_contents = (char*) malloc(strlen(line) + 1); strcpy(file_contents, line); contents_length += strlen(line); } } fclose(f); // fprintf(stderr, "File Contents:\n"); // fprintf(stderr, "%s\n", file_contents); ok(file_contents); return 0; }
gboolean li_request_validate_header(liConnection *con) { liRequest *req = &con->mainvr->request; liHttpHeader *hh; GList *l; if (con->info.is_ssl) { g_string_append_len(req->uri.scheme, CONST_STR_LEN("https")); } else { g_string_append_len(req->uri.scheme, CONST_STR_LEN("http")); } switch (req->http_version) { case LI_HTTP_VERSION_1_0: if (!li_http_header_is(req->headers, CONST_STR_LEN("connection"), CONST_STR_LEN("keep-alive"))) con->info.keep_alive = FALSE; break; case LI_HTTP_VERSION_1_1: if (li_http_header_is(req->headers, CONST_STR_LEN("connection"), CONST_STR_LEN("close"))) con->info.keep_alive = FALSE; break; case LI_HTTP_VERSION_UNSET: bad_request(con, 505); /* Version not Supported */ return FALSE; } if (req->uri.raw->len == 0) { bad_request(con, 400); /* bad request */ return FALSE; } /* get hostname */ l = li_http_header_find_first(req->headers, CONST_STR_LEN("host")); if (NULL != l) { if (NULL != li_http_header_find_next(l, CONST_STR_LEN("host"))) { /* more than one "host" header */ bad_request(con, 400); /* bad request */ return FALSE; } hh = (liHttpHeader*) l->data; g_string_append_len(req->uri.authority, LI_HEADER_VALUE_LEN(hh)); /* check header after we parsed the url, as it may override uri.authority */ } /* Need hostname in HTTP/1.1 */ if (req->uri.authority->len == 0 && req->http_version == LI_HTTP_VERSION_1_1) { bad_request(con, 400); /* bad request */ return FALSE; } /* may override hostname */ if (!request_parse_url(con->mainvr)) { bad_request(con, 400); /* bad request */ return FALSE; } if (req->uri.host->len == 0 && req->uri.authority->len != 0) { if (!li_parse_hostname(&req->uri)) { bad_request(con, 400); /* bad request */ return FALSE; } } /* remove trailing dots from hostname */ { guint i = req->uri.host->len; while (i > 0 && req->uri.host->str[i-1] == '.') i--; g_string_truncate(req->uri.host, i); } /* content-length */ hh = li_http_header_lookup(req->headers, CONST_STR_LEN("content-length")); if (hh) { const gchar *val = LI_HEADER_VALUE(hh); gint64 r; char *err; r = g_ascii_strtoll(val, &err, 10); if (*err != '\0') { _VR_DEBUG(con->srv, con->mainvr, "content-length is not a number: %s (Status: 400)", err); bad_request(con, 400); /* bad request */ return FALSE; } /** * negative content-length is not supported * and is a bad request */ if (r < 0) { bad_request(con, 400); /* bad request */ return FALSE; } /** * check if we had a over- or underrun in the string conversion */ if (r == G_MININT64 || r == G_MAXINT64) { if (errno == ERANGE) { bad_request(con, 413); /* Request Entity Too Large */ return FALSE; } } con->mainvr->request.content_length = r; } /* Expect: 100-continue */ l = li_http_header_find_first(req->headers, CONST_STR_LEN("expect")); if (l) { gboolean expect_100_cont = FALSE; for ( ; l ; l = li_http_header_find_next(l, CONST_STR_LEN("expect")) ) { hh = (liHttpHeader*) l->data; if (0 == g_ascii_strcasecmp( LI_HEADER_VALUE(hh), "100-continue" )) { expect_100_cont = TRUE; } else { /* we only support 100-continue */ bad_request(con, 417); /* Expectation Failed */ return FALSE; } } if (expect_100_cont && req->http_version == LI_HTTP_VERSION_1_0) { /* only HTTP/1.1 clients can send us this header */ bad_request(con, 417); /* Expectation Failed */ return FALSE; } con->expect_100_cont = expect_100_cont; } /* TODO: headers: * - If-Modified-Since (different duplicate check) * - If-None-Match (different duplicate check) * - Range (duplicate check) */ switch(con->mainvr->request.http_method) { case LI_HTTP_METHOD_GET: case LI_HTTP_METHOD_HEAD: /* content-length is forbidden for those */ if (con->mainvr->request.content_length > 0) { VR_ERROR(con->mainvr, "%s", "GET/HEAD with content-length -> 400"); bad_request(con, 400); /* bad request */ return FALSE; } con->mainvr->request.content_length = 0; break; case LI_HTTP_METHOD_POST: /* content-length is required for them */ if (con->mainvr->request.content_length == -1) { /* content-length is missing */ VR_ERROR(con->mainvr, "%s", "POST-request, but content-length missing -> 411"); bad_request(con, 411); /* Length Required */ return FALSE; } break; default: if (con->mainvr->request.content_length == -1) con->mainvr->request.content_length = 0; /* the may have a content-length */ break; } return TRUE; }
int parse_request(struct wen_request *request) { char *head = NULL; struct stat sbuf; int remain_size; for(;;) { head = request->BUF[request->pos_last % MAX_REQUEST]; remain_size = MIN(MAX_REQUEST - (request->pos_last - request->pos_first) - 1,MAX_REQUEST\ - request->pos_last % MAX_REQUEST); int n = read(request->wen_fd,head,remain_size); if(n == 0){ wen_free(request); return 0; } else if(n < 0) { wen_free(request); return 0; } request->pos_last += n; int res_line = parse_http_request_line(request); if(res_line == AGAIN) { continue; } else if(res_line != OK) { wen_free(request); } int res_body = parse_http_request_body(request); if(res_body == AGAIN) continue; else if(res_body != OK) { wen_free(request); } /*handle http request*/ char filename[1024]; parse_http_uri(request,filename); if(stat(filename,&sbuf) < 0){ bad_request(request); return 0; } http_response(request,filename); wen_free(request); break; } return 1; }
void client_request(int clientsd, char * timec, char * clientip) { FILE * requestfile; FILE * logfile; char read_output[BUFFER_SIZE] = {0}; char method[80]; char dir[80]; char http[80]; char line[100]; char finaldir[BUFFER_SIZE] = {0}; struct stat buf; int httpint; int readint; int totalsize; char totalsizec[20]; int totalwrite; char totalwritec[20]; char okstr[80]; logfile = fopen(logdir, "a"); readint = read_request(clientsd, read_output); if (readint == -1) { internal_server_error(clientsd, timec); return; } getlinec(read_output, line); httpint = is_http_get(line, method, dir, http); if (httpint == -1) { bad_request(clientsd, timec); write_log(timec, line, "400 Bad Request", logfile, clientip); return; } getdir(docdir, dir, finaldir); requestfile = fopen(finaldir, "r"); if (requestfile == NULL) { file_not_found(clientsd, timec); write_log(timec, line, "404 Not Found", logfile, clientip); return; } if (errno = EACCES) { forbidden(clientsd, timec); write_log(timec, line, "403 Forbidden", logfile, clientip); return; } /* * Gets file size from buffer file to be used as total write size * for ok response * * Code adapted from * http://stackoverflow.com/a/238644 */ fstat(requestfile, &buf); totalsize = buf.st_size; /* * Converts int to char * * Code adapted from * http://stackoverflow.com/a/1114752 */ sprintf(totalsizec, "%d", totalsize); totalwrite = ok(clientsd, timec, requestfile, totalsizec); sprintf(totalwritec, "%d", totalwrite); strncat(okstr, "200 OK ", sizeof(okstr)); strncat(okstr, totalwritec, sizeof(okstr)); strncat(okstr, "/", sizeof(okstr)); strncat(okstr, totalsizec, sizeof(okstr)); write_log(timec, line, okstr, logfile, clientip); return; }
void execute_cgi(int client, const char *path, const char *method, const char *query_string) { char buf[1024]; int cgi_output[2]; int cgi_input[2]; pid_t pid; int status; int i; char c; int numchars = 1; int content_length = -1; buf[0] = 'A'; buf[1] = '\0'; if (strcasecmp(method, "GET") == 0) /*把所有的 HTTP header 读取并丢弃*/ while ((numchars > 0) && strcmp("\n", buf)) /* read & discard headers */ numchars = get_line(client, buf, sizeof(buf)); else /* POST */ { /* 对 POST 的 HTTP 请求中找出 content_length */ numchars = get_line(client, buf, sizeof(buf)); while ((numchars > 0) && strcmp("\n", buf)) { /*利用 \0 进行分隔 */ buf[15] = '\0'; /* HTTP 请求的特点*/ if (strcasecmp(buf, "Content-Length:") == 0) content_length = atoi(&(buf[16])); numchars = get_line(client, buf, sizeof(buf)); } /*没有找到 content_length */ if (content_length == -1) { /*错误请求*/ bad_request(client); return; } } /* 正确,HTTP 状态码 200 */ sprintf(buf, "HTTP/1.0 200 OK\r\n"); send(client, buf, strlen(buf), 0); /* 建立管道*/ if (pipe(cgi_output) < 0) { /*错误处理*/ cannot_execute(client); return; } /*建立管道*/ if (pipe(cgi_input) < 0) { /*错误处理*/ cannot_execute(client); return; } if ((pid = fork()) < 0 ) { /*错误处理*/ cannot_execute(client); return; } if (pid == 0) /* child: CGI script */ { char meth_env[255]; char query_env[255]; char length_env[255]; /* 把 STDOUT 重定向到 cgi_output 的写入端 */ dup2(cgi_output[1], 1); /* 把 STDIN 重定向到 cgi_input 的读取端 */ dup2(cgi_input[0], 0); /* 关闭 cgi_input 的写入端 和 cgi_output 的读取端 */ close(cgi_output[0]); close(cgi_input[1]); /*设置 request_method 的环境变量*/ sprintf(meth_env, "REQUEST_METHOD=%s", method); putenv(meth_env); if (strcasecmp(method, "GET") == 0) { /*设置 query_string 的环境变量*/ sprintf(query_env, "QUERY_STRING=%s", query_string); putenv(query_env); } else { /* POST */ /*设置 content_length 的环境变量*/ sprintf(length_env, "CONTENT_LENGTH=%d", content_length); putenv(length_env); } /*用 execl 运行 cgi 程序*/ execl(path, path, NULL); exit(0); } else { /* parent */ /* 关闭 cgi_input 的读取端 和 cgi_output 的写入端 */ close(cgi_output[1]); close(cgi_input[0]); if (strcasecmp(method, "POST") == 0) /*接收 POST 过来的数据*/ for (i = 0; i < content_length; i++) { recv(client, &c, 1, 0); /*把 POST 数据写入 cgi_input,现在重定向到 STDIN */ write(cgi_input[1], &c, 1); } /*读取 cgi_output 的管道输出到客户端,该管道输入是 STDOUT */ while (read(cgi_output[0], &c, 1) > 0) send(client, &c, 1, 0); /*关闭管道*/ close(cgi_output[0]); close(cgi_input[1]); /*等待子进程*/ waitpid(pid, &status, 0); } }
int main(int argc, char *argv[]) { int client_sock = -1; int client_name_len = sizeof (client_name); int request=0; struct nunetwork_headerstruct *header_buf; header_buf = (struct nunetwork_headerstruct*)malloc( sizeof(*header_buf) ); /******************** * Don't forget to make pointer to variable cast (*pointer) * When using sizeof(). Otherwise it may cost you a week of * debug time. *******************/ if (geteuid()) { printf("Netustad must be run as root.\n"); exit(1); } conffile = (char *)strdup(default_conf_file); /*setlocale (LC_ALL, "");*/ bindtextdomain (PACKAGE, PACKAGE_LOCALE_DIR); textdomain ( PACKAGE ); /*******************/ /* Check Arguments */ /*******************/ if (argc==2) { if (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0) { printf( gettext("\nnetUstad: Network Ustadi (Network Master)\n")); printf( gettext("Copyright (C) 2004 by Ozkan KIRIK\n")); printf( gettext("Usage: netustad [options]\n")); printf( gettext("\n")); printf( "%s:\n", gettext("Options")); printf( gettext("\t-h\tShow this help screen\n")); printf( gettext("\t-v\tShow version\n")); printf (gettext("\t-c\tUse following parameter as configuration file")); printf("\n"); exit(0); } else if (strcmp(argv[1], "-v") == 0 || strcmp(argv[1], "--version") == 0) { printf(gettext("\nnetUstad: Network Ustadi (Network Master)\n")); printf(gettext("Copyright (C) 2004 by Ozkan KIRIK\n\n")); printf(gettext("Version: %s\n\n"), NUVERSION); exit(0); } } else if (argc == 3 && strcmp(argv[1], "-c") == 0) { conffile = strdup(argv[2]); } else if (argc!=1) { if (strcmp(argv[1], "-c") == 0) { printf (gettext("\nnetUstad: Invalid Number Of Arguments\n\n")); } else { printf(gettext("\nnetUstad: Invalid Argument\n\n")); } exit(1); } /**********************/ /* Start Main Program */ /**********************/ readconfig(conffile); if (setlocale (LC_ALL, (const char*) lc_all) == NULL) { log_msg(mainlogfile, gettext("setlocale failed\n"), 1); printf(gettext("setlocale failed\n")); } bindtextdomain (PACKAGE, PACKAGE_LOCALE_DIR); textdomain ( PACKAGE ); nameoftty = ttyname(0); daemonize(); #ifndef WITHOUT_SSL ssl = nunetwork_init_ssl( nunetwork_init_ctx( cert_file, key_file) ); #endif server_sock = startup(&port); /* Open Socket & Listen */ log_msg(mainlogfile, "<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>\n", 0); snprintf(log_msg_text, sizeof(log_msg_text)-1, "netUstad-%s\n", NUVERSION); log_msg(mainlogfile, log_msg_text, 0); snprintf(log_msg_text, sizeof (log_msg_text)-1, "%s", gettext("netUstad is started\n")); log_msg(mainlogfile, log_msg_text, 1); snprintf(log_msg_text, sizeof (log_msg_text)-1, gettext("\nListening port %d\n"), port); log_msg(mainlogfile, log_msg_text, 0); log_msg(mainlogfile, gettext("Ready for requests...\n\n"), 0); snprintf(log_msg_text, sizeof(log_msg_text)-1, "netUstad-%s\n", NUVERSION); log_msg(nameoftty, log_msg_text, 0); snprintf(log_msg_text, sizeof (log_msg_text)-1, gettext("\nnetUstad is started\nListening port %d\n"), port); log_msg(nameoftty, log_msg_text, 0); while (1) { client_sock = accept(server_sock, (struct sockaddr *) &client_name, (socklen_t *)&client_name_len); if (client_sock == -1) continue; #ifndef WITHOUT_SSL SSL_set_fd(ssl, client_sock); sslerror = SSL_accept(ssl); if ( sslerror <= 0 ) { sslerror= SSL_get_error(ssl, sslerror); ERR_error_string(sslerror, log_msg_text); log_msg(mainlogfile, log_msg_text, 1); log_msg(mainlogfile, "\n",0); SSL_shutdown(ssl); SSL_free(ssl); close(client_sock); ssl = nunetwork_init_ssl(ctx); continue; } request = nunetwork_getheaders(ssl, header_buf, nu_acceptedheaders); if (request > 0) accept_request(ssl, header_buf); else if (request==-2 || request==0) bad_request(ssl); nunetwork_close(ssl); #else request = nunetwork_getheaders(client_sock, header_buf, nu_acceptedheaders); if (request > 0) accept_request(client_sock, header_buf); else if (request==-2 || request==0 ) bad_request(ssl); nunetwork_close(client_sock); #endif } #ifndef WITHOUT_SSL SSL_shutdown(ssl); SSL_free(ssl); SSL_CTX_free(ctx); #else close(server_sock); #endif return (0); }
static int parse_multipart(char const *charset) { static char const mp2[] = "multipart/form-data; boundary="; static char const s3[] = "content-disposition:"; static char const s4[] = "form-data;"; static char const s5[] = "name=\""; static char const s6[] = "content-type:"; char const *boundary; char *ct, *cl; int content_length, n; char lbuf[1024]; int llen; char *p, *q; int linestart; int boundary_len; int c; ct = getenv("CONTENT_TYPE"); if (!ct) return -1; if (strncmp(ct, mp2, sizeof(mp2) - 1)) { err("parse_multipart: cannot parse CONTENT_TYPE"); bad_request(charset); exit(0); } boundary = ct + sizeof(mp2) - 1; boundary_len = strlen(boundary); cl = getenv("CONTENT_LENGTH"); if (!cl || sscanf(cl, "%d%n", &content_length, &n) != 1 || cl[n]) { //err("parse_multipart: cannot parse CONTENT_LENGTH"); //bad_request(charset); //exit(0); return 0; } if (content_length > MAX_CONTENT_LENGTH) { request_too_large(charset); exit(0); } name_u = 0; value_u = 0; fgets(lbuf, sizeof(lbuf), stdin); llen = strlen(lbuf); if (llen == sizeof(lbuf) - 1 && lbuf[llen - 1] != '\n') { err("parse_multipart: boundary string too long"); bad_request(charset); exit(0); } lbuf[--llen] = 0; if (lbuf[llen - 1] == '\r') lbuf[--llen] = 0; if (lbuf[0] != '-' || lbuf[1] != '-' || strcmp(boundary, lbuf + 2)) { err("got: %s(%zu)", lbuf, strlen(lbuf)); bad_request(charset); exit(0); } while (1) { /* read and parse header lines */ while (1) { fgets(lbuf, sizeof(lbuf), stdin); //fprintf(stderr, ">>%s<\n", lbuf); llen = strlen(lbuf); if (llen == sizeof(lbuf) - 1 && lbuf[llen - 1] != '\n') { err("parse_multipart: header string too long"); bad_request(charset); exit(0); } lbuf[--llen] = 0; if (lbuf[llen - 1] == '\r') lbuf[--llen] = 0; if (!lbuf[0]) break; if (!strncasecmp(lbuf, s3, sizeof(s3) - 1)) { /* content-disposition header */ p = lbuf + sizeof(s3) - 1; while (*p == ' ' || *p == '\t') p++; if (!strncasecmp(p, s4, sizeof(s4) - 1)) { p += sizeof(s4) - 1; while (*p == ' ' || *p == '\t') p++; if (!strncasecmp(p, s5, sizeof(s5) - 1)) { p += sizeof(s5) - 1; q = p; while (*q != '\"' && *q != 0) q++; if (!*q) { err("unexpected EOLN: %s", lbuf); bad_request(charset); exit(0); } /* get parameter name */ if (q - p + 1 > name_a) { name_a = ((q - p + 1) + 3) & ~3; name_buf = xrealloc(name_buf, name_a); } name_u = q - p; memcpy(name_buf, p, name_u); name_buf[name_u] = 0; } else { err("name= expected: %s\n", lbuf); bad_request(charset); exit(0); } } else { err("unknown content disposition: %s", lbuf); bad_request(charset); exit(0); } } else if (!strncasecmp(s6, lbuf, sizeof(s6) - 1)) { //err("ignored header: %s", lbuf); } else { err("unknown header: <%s>", lbuf); bad_request(charset); exit(0); } } /* read and parse data stream */ linestart = 0; value_u = 0; if (!value_a) { value_a = 128; value_buf = xmalloc(value_a); } while (1) { c = getchar(); if (c == EOF) { err("unexpected EOF"); bad_request(charset); exit(0); } if (value_u >= value_a) { value_a *= 2; value_buf = xrealloc(value_buf, value_a); } value_buf[value_u++] = c; if (value_u - linestart - 2 == boundary_len && value_buf[linestart] == '-' && value_buf[linestart + 1] == '-' && !strncmp(value_buf + linestart + 2, boundary, boundary_len)) { /* data ended */ value_u = linestart; if (value_u > 0 && value_buf[value_u - 1] == '\n') value_u--; if (value_u > 0 && value_buf[value_u - 1] == '\r') value_u--; value_buf[value_u] = 0; break; } if (c == '\n') { linestart = value_u; } } /* add variable to list */ add_to_param_list(name_buf, value_buf, value_u); /* skip whitespaces */ c = getchar(); if (c == '-') { c = getchar(); if (c == '-') break; err("oops: only one '-' after boundary"); bad_request(charset); exit(0); } else { ungetc(c, stdin); } while ((c = getchar()) == ' ' || c == '\t' || c == '\n' || c == '\r'); ungetc(c, stdin); } #if 0 { int i; fprintf(stderr, "total: %d\n", param_u); for (i = 0; i < param_u; i++) { fprintf(stderr, "%s = '%s'\n", params[i].name, params[i].value); } } #endif return 0; }
void execute_cgi(int client, const char *path, const char *method, const char *query_string) { char buf[1024]; int cgi_output[2]; int cgi_input[2]; pid_t pid; int status; int i; char c; int numchars = 1; int content_length = -1; buf[0] = 'A'; buf[1] = '\0'; if (strcasecmp(method, "GET") == 0) while ((numchars > 0) && strcmp("\n", buf)) /* read & discard headers */ numchars = get_line(client, buf, sizeof(buf)); else /* POST */ { numchars = get_line(client, buf, sizeof(buf)); while ((numchars > 0) && strcmp("\n", buf)) { buf[15] = '\0'; if (strcasecmp(buf, "Content-Length:") == 0) content_length = atoi(&(buf[16])); numchars = get_line(client, buf, sizeof(buf)); } if (content_length == -1) { bad_request(client); return; } } sprintf(buf, "HTTP/1.0 200 OK\r\n"); send(client, buf, strlen(buf), 0); if (pipe(cgi_output) < 0) { cannot_execute(client); return; } if (pipe(cgi_input) < 0) { cannot_execute(client); return; } if ( (pid = fork()) < 0 ) { cannot_execute(client); return; } if (pid == 0) /* child: CGI script */ { char meth_env[255]; char query_env[255]; char length_env[255]; dup2(cgi_output[1], 1); dup2(cgi_input[0], 0); close(cgi_output[0]); close(cgi_input[1]); sprintf(meth_env, "REQUEST_METHOD=%s", method); putenv(meth_env); if (strcasecmp(method, "GET") == 0) { sprintf(query_env, "QUERY_STRING=%s", query_string); putenv(query_env); } else { /* POST */ sprintf(length_env, "CONTENT_LENGTH=%d", content_length); putenv(length_env); } execl(path, path, NULL); exit(0); } else { /* parent */ close(cgi_output[1]); close(cgi_input[0]); if (strcasecmp(method, "POST") == 0) for (i = 0; i < content_length; i++) { recv(client, &c, 1, 0); write(cgi_input[1], &c, 1); } while (read(cgi_output[0], &c, 1) > 0) send(client, &c, 1, 0); close(cgi_output[0]); close(cgi_input[1]); waitpid(pid, &status, 0); } }
/*-------------------------------------------------------------------------*/ void erq_cmd (void) /* There is data ready from the driver - read and execute it when complete. * The function maintains a static buffer for the data read - incomplete * messages are buffered until they are complete. */ { static char buf[ERQ_MAX_SEND]; static int pos = 0; /* Position in buf[]. If it extends beyond the end of buf, * it is because the message is too long and the function * is in the process of skipping the extraneous characters. */ int len, mesg_len; char request; /* Clear the buffer so that errors can be detected more easily */ memset(buf, 0, sizeof(buf)); /* Read the message header */ if (pos < 9) { len = read(0, buf+pos, 9-pos); if (len <= 0) { perror("[xerq] read"); die(); } XPRINTF((stderr, "%s Read %d of the missing %d header bytes.\n" , time_stamp(), len, 9-pos)); pos += len; if (pos < 9) return; } mesg_len = read_32(buf); if (mesg_len > sizeof(buf)) { /* This doesn't happen in a functioning system */ fprintf(stderr , "%s Received too long packet: %d bytes.\n" , time_stamp(), mesg_len); die(); } /* Get the rest of the message */ if (pos < mesg_len) { len = read(0, buf+pos, mesg_len-pos); if (len <= 0) { perror("read"); die(); } XPRINTF((stderr, "%s Read %d of the missing %d message bytes.\n" , time_stamp(), len, mesg_len-pos)); pos += len; if (pos < mesg_len) return; } XPRINTF((stderr, "%s Message complete.\n", time_stamp())); pos = 0; /* Message complete */ /* Branch on the request */ request = buf[8]; if (request <= ERQ_REQUEST_MAX) { #if ERQ_DEBUG > 0 char *mesg, *mesgs[]={ "rlookup","execute","fork","auth","spawn","send","kill", "open_udp","open_tcp","listen","accept","lookup", "rlookupv6"}; mesg=mesgs[(int)request]; fprintf(stderr, "%s command: %s\n", time_stamp(), mesg); #endif (*erq_table[(int)request])(buf, mesg_len); } else bad_request(buf); } /* erq_cmd() */
// 配置环境变量,创建子进程,执行cgi程序 void execute_cgi(int client, const char *path, const char *method, const char *query_string) { char buf[1024]; int cgi_output[2]; int cgi_input[2]; pid_t pid; int status; int i; char c; int numchars = 1; int content_length = -1; buf[0] = 'A'; buf[1] = '\0'; if (strcasecmp(method, "GET") == 0) // GET while ((numchars > 0) && strcmp("\n", buf)) /* read & discard headers */ numchars = get_line(client, buf, sizeof(buf)); // 只处理了请求首行,忽略后面的请求头 else /* POST */ { numchars = get_line(client, buf, sizeof(buf)); // 读取请求头中的header属性 while ((numchars > 0) && strcmp("\n", buf)) { buf[15] = '\0'; if (strcasecmp(buf, "Content-Length:") == 0) // Content-Length:后面的数字切出来 content_length = atoi(&(buf[16])); numchars = get_line(client, buf, sizeof(buf)); } if (content_length == -1) { // Content-Length获取失败,该请求有问题 bad_request(client); // 400 return; } } sprintf(buf, "HTTP/1.0 200 OK\r\n"); // 响应首行 send(client, buf, strlen(buf), 0); if (pipe(cgi_output) < 0) { // 打开管道 cannot_execute(client); return; } if (pipe(cgi_input) < 0) { // 打开管道 cannot_execute(client); return; } if ( (pid = fork()) < 0 ) { // 创建子进程 cannot_execute(client); return; } if (pid == 0) /* child: CGI script */ { // 子进程开始执行 char meth_env[255]; char query_env[255]; char length_env[255]; dup2(cgi_output[1], 1); // 复制到标准输出 dup2(cgi_input[0], 0); // 复制到标准输入 close(cgi_output[0]); close(cgi_input[1]); // 关闭不需要的描述符 // 添加几个环境变量 sprintf(meth_env, "REQUEST_METHOD=%s", method); putenv(meth_env); if (strcasecmp(method, "GET") == 0) { sprintf(query_env, "QUERY_STRING=%s", query_string); putenv(query_env); } else { /* POST */ sprintf(length_env, "CONTENT_LENGTH=%d", content_length); putenv(length_env); } // 准备工作完毕,开始执行cgi程序 execl(path, path, NULL); exit(0); } else { /* parent */ // 父进程代码 close(cgi_output[1]); close(cgi_input[0]); // 关闭不需要的描述符 if (strcasecmp(method, "POST") == 0) for (i = 0; i < content_length; i++) { recv(client, &c, 1, 0); write(cgi_input[1], &c, 1); // 读取剩下的请求头写给子进程的cgi程序 } while (read(cgi_output[0], &c, 1) > 0) send(client, &c, 1, 0); // 读取cgi程序的输出发送给客户端 close(cgi_output[0]); close(cgi_input[1]); // 使用完毕,关闭描述符 waitpid(pid, &status, 0); // 等待子进程退出 } }