static void ev_io_on_read(struct ev_loop* mainloop, ev_io* watcher, const int events) { static char read_buf[READ_BUFFER_SIZE]; Request* request = REQUEST_FROM_WATCHER(watcher); ssize_t read_bytes = read( request->client_fd, read_buf, READ_BUFFER_SIZE ); GIL_LOCK(0); if(read_bytes <= 0) { if(errno != EAGAIN && errno != EWOULDBLOCK) { if(read_bytes == 0) DBG_REQ(request, "Client disconnected"); else DBG_REQ(request, "Hit errno %d while read()ing", errno); close(request->client_fd); Request_free(request); ev_io_stop(mainloop, &request->ev_watcher); } goto out; } Request_parse(request, read_buf, (size_t)read_bytes); if(request->state.error_code) { DBG_REQ(request, "Parse error"); request->current_chunk = PyString_FromString( http_error_messages[request->state.error_code]); assert(request->iterator == NULL); } else if(request->state.parse_finished) { if(!wsgi_call_application(request)) { assert(PyErr_Occurred()); PyErr_Print(); assert(!request->state.chunked_response); Py_XCLEAR(request->iterator); request->current_chunk = PyString_FromString( http_error_messages[HTTP_SERVER_ERROR]); } } else { /* Wait for more data */ goto out; } ev_io_stop(mainloop, &request->ev_watcher); ev_io_init(&request->ev_watcher, &ev_io_on_write, request->client_fd, EV_WRITE); ev_io_start(mainloop, &request->ev_watcher); out: GIL_UNLOCK(0); return; }
char *test_Request_create() { int rc = 0; size_t nparsed = 0; bstring fake_sender = bfromcstr("FAKESENDER"); Request_init(); Request *req = Request_create(); mu_assert(req != NULL, "Failed to create parser for request."); FILE *infile = fopen("tests/and_suite/ex_httpd_tst_16", "r"); mu_assert(infile != NULL, "Failed to open test file."); bstring data = bread((bNread)fread, infile); fclose(infile); mu_assert(data != NULL, "Failed to read test file."); mu_assert(blength(data) > 0, "Nothing in that file."); Request_start(req); rc = Request_parse(req, bdata(data), blength(data), &nparsed); mu_assert(rc == 1, "It should parse."); mu_assert(nparsed > 0, "Should have parsed something."); bstring payload = Request_to_payload(req, fake_sender, 0, "", 0,conn, NULL); debug("PAYLOAD IS: %s", bdata(payload)); bdestroy(payload); payload = Request_to_tnetstring(req, fake_sender, 0, "", 0,conn, NULL); debug("TNETSTRING PAYLOAD: '%.*s'", blength(payload), bdata(payload)); mu_assert(Request_get(req, &HTTP_IF_MODIFIED_SINCE) != NULL, "Should have an if-modified-since header."); mu_assert(req->host != NULL, "Should have Host header."); mu_assert(Request_get_date(req, &HTTP_IF_MODIFIED_SINCE, RFC_822_TIME) > 0, "Wrong time from header."); mu_assert(Request_get_date(req, &HTTP_IF_UNMODIFIED_SINCE, RFC_822_TIME) == 0, "Unmodified since should be invalid."); mu_assert(Request_get_date(req, &HTTP_IF_NONE_MATCH, RFC_822_TIME) == 0, "None match shouldn't even be a date."); Request_start(req); Request_destroy(req); // test with null Request_destroy(NULL); bdestroy(payload); bdestroy(fake_sender); bdestroy(data); return NULL; }
char *test_Request_payloads() { glob_t test_files; bstring fake_sender = bfromcstr("FAKESENDER"); Request *req = Request_create(); //Connection *conn=Connection_create(NULL,0,1,""); size_t nparsed = 0; unsigned int i = 0; int rc = glob("tests/and_suite/*", 0, NULL, &test_files); mu_assert(rc == 0, "Failed to glob file sin tests/and_suite/*"); FILE *test_cases = fopen("tests/request_payloads.txt", "w"); mu_assert(test_cases != NULL, "Failed to create the tests/request_payloads.txt file."); for(i = 0; i < test_files.gl_pathc; i++) { nparsed = 0; FILE *infile = fopen(test_files.gl_pathv[i], "r"); mu_assert(infile != NULL, "Failed to open test file."); bstring data = bread((bNread)fread, infile); fclose(infile); mu_assert(data != NULL, "Failed to read test file."); Request_start(req); rc = Request_parse(req, bdata(data), blength(data), &nparsed); if(rc == 1) { mu_assert(nparsed > 0, "Should have parsed something."); // TODO: fix this up so that we never get a null for path if(req->path == NULL) req->path = bfromcstr("/"); bstring payload = Request_to_payload(req, fake_sender, 0, "", 0,conn, NULL); bconchar(payload, '\n'); fwrite(payload->data, blength(payload), 1, test_cases); bdestroy(payload); payload = Request_to_tnetstring(req, fake_sender, 0, "", 0,conn, NULL); debug("TNETSTRING PAYLOAD: '%.*s'", blength(payload), bdata(payload)); bconchar(payload, '\n'); fwrite(payload->data, blength(payload), 1, test_cases); bdestroy(payload); } bdestroy(data); } globfree(&test_files); fclose(test_cases); bdestroy(fake_sender); Request_destroy(req); return NULL; }
static void on_read(uv_stream_t* handle, ssize_t nread, uv_buf_t buf) { Request* request; dprint("go on_read"); request =(Request*)handle->data; GIL_LOCK(0); if (nread <= 0) { //@@@@@@@@@@@@@@@uv_err_t err = uv_last_error(loop); //@@@@@@@@@@@@@@@UVERR(err, "uv read error"); if(nread == 0) dprint("Client disconnected"); uv_close((uv_handle_t*)handle, on_close); Request_free(request); if (buf.base) { free(buf.base); } goto out; } Request_parse(request, buf.base, nread); //处理Request解析 free(buf.base); if(request->state.error_code) { DBG_REQ(request, "Parse error"); request->current_chunk = PyString_FromString(http_error_messages[request->state.error_code]);//处理有错误的信息返回 assert(request->iterator == NULL); //@@@@@@@@@ uv_close((uv_handle_t*) &request->ev_watcher, on_close);//解析有错误的请求直接关闭客户端连接 //@@@@@@@@@@ Request_free(request); //@@@@@@@@@ goto out; } else if(request->state.parse_finished) { // 解析好后 dprint("执行wsgi程序 >>>"); if(!wsgi_call_application(request)) { // 执行wsgi dprint("wsgi执行包含错误"); assert(PyErr_Occurred()); PyErr_Print(); //打印python错误的跟踪堆栈信息 assert(!request->state.chunked_response); Py_XCLEAR(request->iterator); request->current_chunk = PyString_FromString( //返回错误信息给客户端 http_error_messages[HTTP_SERVER_ERROR]); } } else { /* Wait for more data */ goto out; } dprint("开始客户端数据返回 >>>"); while(request->current_chunk){ //客户端返回循环 io_write(request); } out: GIL_UNLOCK(0); return; }
static void ev_io_on_read(struct ev_loop* mainloop, ev_io* watcher, const int events) { char read_buf[READ_BUFFER_SIZE]; Request* request = ADDR_FROM_MEMBER(watcher, Request, ev_watcher); ssize_t read_bytes = read(request->client_fd, read_buf, READ_BUFFER_SIZE); DBG_REQ(request, "read %zd bytes", read_bytes); GIL_LOCK(0); if(read_bytes == -1) { if(errno != EAGAIN && errno != EWOULDBLOCK) { close(request->client_fd); Request_free(request); ev_io_stop(mainloop, &request->ev_watcher); } goto out; } Request_parse(request, read_buf, read_bytes); if(request->state.error) { DBG_REQ(request, "Parse error"); set_error(request, request->state.error_code); } else if(request->state.parse_finished) { DBG_REQ(request, "Parse done"); if(!wsgi_call_application(request)) { assert(PyErr_Occurred()); PyErr_Print(); set_error(request, HTTP_SERVER_ERROR); } } else { DBG_REQ(request, "Waiting for more data"); goto out; } ev_io_stop(mainloop, &request->ev_watcher); ev_io_init(&request->ev_watcher, &ev_io_on_write, request->client_fd, EV_WRITE); ev_io_start(mainloop, &request->ev_watcher); out: GIL_UNLOCK(0); return; }
Request *fake_req(const char *method, const char *path) { int rc = 0; size_t nparsed = 0; Request *req = Request_create(); Request_start(req); bstring p = bfromcstr(path); bstring rp = bformat(REQ_PATTERN, method, bdata(p)); rc = Request_parse(req, bdata(rp), blength(rp), &nparsed); check(rc != 0, "Failed to parse request."); check(nparsed == blength(rp), "Failed to parse all of request."); return req; error: return NULL; }
char *test_Multiple_Header_Request() { int rc = 0; size_t nparsed = 0; Request_init(); Request *req = Request_create(); mu_assert(req != NULL, "Failed to create parser for request."); FILE *infile = fopen("tests/and_suite/ex_httpd_tst_21", "r"); mu_assert(infile != NULL, "Failed to open test file."); bstring data = bread((bNread)fread, infile); fclose(infile); mu_assert(data != NULL, "Failed to read test file."); mu_assert(blength(data) > 0, "Nothing in that file."); Request_start(req); rc = Request_parse(req, bdata(data), blength(data), &nparsed); mu_assert(rc == 1, "It should parse."); mu_assert(nparsed > 0, "Should have parsed something."); mu_assert(Request_get(req, &COOKIE_HEADER) != NULL, "Should have an cookie header."); bstring payload = Request_to_payload(req, &JSON_METHOD, 0, "", 0,conn, NULL); debug("PAYLOAD IS: %s", bdata(payload)); mu_assert(bstrcmp(payload, &EXPECTED_COOKIE_HEADER) == 0, "Expected header not in correct format."); Request_destroy(req); bdestroy(payload); bdestroy(data); return NULL; }
int Connection_read_header(Connection *conn, Request *req) { char *data = IOBuf_start(conn->iob); int avail = IOBuf_avail(conn->iob); int rc = 0; size_t nparsed = 0; int tries = 0; Request_start(req); for(tries = 0; rc == 0 && tries < CLIENT_READ_RETRIES; tries++) { if(avail > 0) { rc = Request_parse(req, data, avail, &nparsed); } if(rc == 0) { data = IOBuf_read_some(conn->iob, &avail); check_debug(!IOBuf_closed(conn->iob), "Client closed during read."); } } error_unless(tries < CLIENT_READ_RETRIES, conn, 400, "Too many small packet read attempts."); error_unless(rc == 1, conn, 400, "Error parsing request."); // add the x-forwarded-for header Request_set(conn->req, bstrcpy(&HTTP_X_FORWARDED_FOR), blk2bstr(conn->remote, IPADDR_SIZE), 1); check_should_close(conn, conn->req); return nparsed; error: return -1; }
static void ev_io_on_read(struct ev_loop* mainloop, ev_io* watcher, const int events) { static char read_buf[READ_BUFFER_SIZE]; Request* request = REQUEST_FROM_WATCHER(watcher); read_state read_state; ssize_t read_bytes = read( request->client_fd, read_buf, READ_BUFFER_SIZE ); GIL_LOCK(0); if (read_bytes == 0) { /* Client disconnected */ read_state = aborted; DBG_REQ(request, "Client disconnected"); } else if (read_bytes < 0) { /* Would block or error */ if(errno == EAGAIN || errno == EWOULDBLOCK) { read_state = not_yet_done; } else { read_state = aborted; DBG_REQ(request, "Hit errno %d while read()ing", errno); } } else { /* OK, either expect more data or done reading */ Request_parse(request, read_buf, (size_t)read_bytes); if(request->state.error_code) { /* HTTP parse error */ read_state = done; DBG_REQ(request, "Parse error"); request->current_chunk = PyString_FromString( http_error_messages[request->state.error_code]); assert(request->iterator == NULL); } else if(request->state.parse_finished) { /* HTTP parse successful */ read_state = done; bool wsgi_ok = wsgi_call_application(request); if (!wsgi_ok) { /* Response is "HTTP 500 Internal Server Error" */ DBG_REQ(request, "WSGI app error"); assert(PyErr_Occurred()); PyErr_Print(); assert(!request->state.chunked_response); Py_XCLEAR(request->iterator); request->current_chunk = PyString_FromString( http_error_messages[HTTP_SERVER_ERROR]); } } else { /* Wait for more data */ read_state = not_yet_done; } } switch (read_state) { case not_yet_done: break; case done: DBG_REQ(request, "Stop read watcher, start write watcher"); ev_io_stop(mainloop, &request->ev_watcher); ev_io_init(&request->ev_watcher, &ev_io_on_write, request->client_fd, EV_WRITE); ev_io_start(mainloop, &request->ev_watcher); break; case aborted: close_connection(mainloop, request); break; } GIL_UNLOCK(0); }