📄 request.c
字号:
RESP200 "Content-Length: 0\r\n" "\r\n", 4)); CALL(any_2xx_request(sess, "/first")); minisleep(); CALL(any_2xx_request_body(sess, "/second")); ONN("server died prematurely?", dead_server()); reap_server(); ne_session_destroy(sess); return OK;}/* TODO: add a ptimeout_reset too, if an RST can be reliably generated * mid-connection. *//* Emulates a persistent connection timeout on the server. This tests * the timeout occuring after between 1 and 10 requests down the * connection. */static int persist_timeout(void){ ne_session *sess = ne_session_create("http", "localhost", 7777); ne_buffer *buf = ne_buffer_create(); int n; struct many_serve_args args; ON(sess == NULL || buf == NULL); args.str = RESP200 "Content-Length: 5\r\n\r\n" "abcde"; for (args.count = 1; args.count < 10; args.count++) { ON(spawn_server(7777, many_serve_string, &args)); for (n = 0; n < args.count; n++) { ONV(run_request(sess, 200, construct_get, buf), ("%d of %d, request failed: %s", n, args.count, ne_get_error(sess))); ONV(strcmp(buf->data, "abcde"), ("%d of %d, response body mismatch", n, args.count)); /* Ready for next time. */ ne_buffer_clear(buf); } ON(await_server()); } ne_session_destroy(sess); ne_buffer_destroy(buf); return OK;} /* Test that an HTTP/1.0 server is not presumed to support persistent * connections by default. */static int no_persist_http10(void){ ne_session *sess = ne_session_create("http", "localhost", 7777); CALL(spawn_server_repeat(7777, single_serve_string, "HTTP/1.0 200 OK\r\n" "Content-Length: 5\r\n\r\n" "abcde" "Hello, world - what a nice day!\r\n", 4)); /* if the connection is treated as persistent, the status-line for * the second request will be "Hello, world...", which will * fail. */ ONREQ(any_request(sess, "/foobar")); ONREQ(any_request(sess, "/foobar")); ONN("server died prematurely?", dead_server()); CALL(reap_server()); ne_session_destroy(sess); return OK;}static int ignore_bad_headers(void){ return expect_response("abcde", single_serve_string, RESP200 "Stupid Header\r\n" "ReallyStupidHeader\r\n" "Content-Length: 5\r\n" "\r\n" "abcde");}static int fold_headers(void){ return expect_response("abcde", single_serve_string, RESP200 "Content-Length: \r\n 5\r\n" "\r\n" "abcde");}static int fold_many_headers(void){ return expect_response("abcde", single_serve_string, RESP200 "Content-Length: \r\n \r\n \r\n \r\n 5\r\n" "\r\n" "abcde");}#define NO_BODY "Content-Length: 0\r\n\r\n"static int empty_header(void){ return expect_header_value("ranDom-HEader", "", single_serve_string, RESP200 "RANDom-HeADEr:\r\n" NO_BODY);}static int ignore_header_case(void){ return expect_header_value("ranDom-HEader", "noddy", single_serve_string, RESP200 "RANDom-HeADEr: noddy\r\n" NO_BODY);}static int ignore_header_ws(void){ return expect_header_value("ranDom-HEader", "fishy", single_serve_string, RESP200 "RANDom-HeADEr: fishy\r\n" NO_BODY);}static int ignore_header_ws2(void){ return expect_header_value("ranDom-HEader", "fishy", single_serve_string, RESP200 "RANDom-HeADEr \t : fishy\r\n" NO_BODY);}static int ignore_header_ws3(void){ return expect_header_value("ranDom-HEader", "fishy", single_serve_string, RESP200 "RANDom-HeADEr: fishy \r\n" NO_BODY);}static int ignore_header_tabs(void){ return expect_header_value("ranDom-HEader", "geezer", single_serve_string, RESP200 "RANDom-HeADEr: \t \tgeezer\r\n" NO_BODY);}static int trailing_header(void){ return expect_header_value("gONe", "fishing", single_serve_string, RESP200 TE_CHUNKED "\r\n0\r\n" "Hello: world\r\n" "GONE: fishing\r\n" "\r\n");}static int continued_header(void){ return expect_header_value("hello", "w o r l d", single_serve_string, RESP200 "Hello: \n\tw\r\n\to r l\r\n\td \r\n" NO_BODY);}static void mh_header(void *ctx, const char *value){ int *state = ctx; static const char *hdrs[] = { "jim", "jab", "jar" }; if (*state < 0 || *state > 2) { /* already failed. */ return; } if (strcmp(value, hdrs[*state])) *state = -*state; else (*state)++;}/* check headers callbacks are working correctly. */static int multi_header(void){ ne_session *sess = ne_session_create("http", "localhost", 7777); ne_request *req; int state = 0; ON(sess == NULL); ON(spawn_server(7777, single_serve_string, RESP200 "X-Header: jim\r\n" "x-header: jab\r\n" "x-Header: jar\r\n" "Content-Length: 0\r\n\r\n")); req = ne_request_create(sess, "GET", "/"); ON(req == NULL); ne_add_response_header_handler(req, "x-header", mh_header, &state); ONREQ(ne_request_dispatch(req)); ON(await_server()); ON(state != 3); ne_request_destroy(req); ne_session_destroy(sess); return OK;}struct s1xx_args { int count; int hdrs;};static int serve_1xx(ne_socket *sock, void *ud){ struct s1xx_args *args = ud; CALL(discard_request(sock)); do { if (args->hdrs) { SEND_STRING(sock, "HTTP/1.1 100 Continue\r\n" "Random: header\r\n" "Another: header\r\n\r\n"); } else { SEND_STRING(sock, "HTTP/1.1 100 Continue\r\n\r\n"); } } while (--args->count > 0); SEND_STRING(sock, RESP200 "Content-Length: 0\r\n\r\n"); return OK;}#define sess def_sessstatic int skip_interim_1xx(void){ struct s1xx_args args = {0, 0}; ON(prepare_request(serve_1xx, &args)); ONREQ(ne_request_dispatch(def_req)); return finish_request();}static int skip_many_1xx(void){ struct s1xx_args args = {5, 0}; ON(prepare_request(serve_1xx, &args)); ONREQ(ne_request_dispatch(def_req)); return finish_request();}static int skip_1xx_hdrs(void){ struct s1xx_args args = {5, 5}; ON(prepare_request(serve_1xx, &args)); ONREQ(ne_request_dispatch(def_req)); return finish_request();}#undef sess/* server for expect_100_once: eats a dummy request, then serves a * 100-continue request, and fails if the request body is sent * twice. */static int serve_100_once(ne_socket *sock, void *ud){ struct s1xx_args args = {2, 0}; char ch; /* dummy first request. */ CALL(discard_request(sock)); CALL(SEND_STRING(sock, RESP200 "Content-Length: 0\r\n\r\n")); /* now the real 1xx request. */ CALL(serve_1xx(sock, &args)); CALL(discard_body(sock)); ONN("body was served twice", ne_sock_read(sock, &ch, 1) == 1); return OK;}/* regression test; fails with neon <0.22, where the request body was * served *every* time a 1xx response was received, rather than just * once. */static int expect_100_once(void){ ne_session *sess; ne_request *req; char body[BUFSIZ]; CALL(make_session(&sess, serve_100_once, NULL)); ne_set_expect100(sess, 1); /* 100-continue is only used if the server is known to claim * HTTP/1.1 compliance; make a dummy request on the socket first, * to trigger that logic. */ CALL(any_request(sess, "/foo")); /* now the real request. */ req = ne_request_create(sess, "GET", "/foo"); memset(body, 'A', sizeof(body)); ne_set_request_body_buffer(req, body, sizeof(body)); ONN("request failed", ne_request_dispatch(req)); ne_request_destroy(req); ne_session_destroy(sess); CALL(await_server()); return OK;}struct body { char *body; size_t size;};static int want_body(ne_socket *sock, void *userdata){ struct body *b = userdata; char *buf = ne_malloc(b->size); clength = 0; CALL(discard_request(sock)); ONN("request has c-l header", clength == 0); ONN("request length", clength != (int)b->size); NE_DEBUG(NE_DBG_HTTP, "reading body of %" NE_FMT_SIZE_T " bytes...\n", b->size); ON(ne_sock_fullread(sock, buf, b->size)); ON(SEND_STRING(sock, RESP200 "Content-Length: 0\r\n\r\n")); ON(memcmp(buf, b->body, b->size)); ne_free(buf); return OK;}static ssize_t provide_body(void *userdata, char *buf, size_t buflen){ static const char *pnt; static size_t left; struct body *b = userdata; if (buflen == 0) { pnt = b->body; left = b->size; } else { if (left < buflen) buflen = left; memcpy(buf, pnt, buflen); left -= buflen; } return buflen;}static int send_bodies(void){ unsigned int n, m; struct body bodies[] = { { "abcde", 5 }, { "\0\0\0\0\0\0", 6 }, { NULL, 50000 }, { NULL } };#define BIG 2 /* make the body with some cruft. */ bodies[BIG].body = ne_malloc(bodies[BIG].size); for (n = 0; n < bodies[BIG].size; n++) { bodies[BIG].body[n] = (char)n%80; } for (m = 0; m < 2; m++) { for (n = 0; bodies[n].body != NULL; n++) { ne_session *sess = ne_session_create("http", "localhost", 7777); ne_request *req; ON(sess == NULL); ON(spawn_server(7777, want_body, &(bodies[n]))); req = ne_request_create(sess, "PUT", "/"); ON(req == NULL); if (m == 0) { ne_set_request_body_buffer(req, bodies[n].body, bodies[n].size); } else { ne_set_request_body_provider(req, bodies[n].size, provide_body, &bodies[n]); } ONREQ(ne_request_dispatch(req)); CALL(await_server()); ne_request_destroy(req); ne_session_destroy(sess); } } ne_free(bodies[BIG].body); return OK;}static int serve_infinite_headers(ne_socket *sock, void *userdata){ CALL(discard_request(sock)); SEND_STRING(sock, RESP200); for (;;) { SEND_STRING(sock, "x-foo: bar\r\n"); } return 0; }/* Utility function: run a request using the given server fn, and the * request should fail. If 'error' is non-NULL, it must be a substring * of the error string. */static int fail_request_with_error(int with_body, server_fn fn, void *ud, int forever, const char *error){ ne_session *sess = ne_session_create("http", "localhost", 7777); ne_request *req; int ret; ON(sess == NULL); if (forever) { ON(spawn_server_repeat(7777, fn, ud, 100)); } else { ON(spawn_server(7777, fn, ud)); } req = ne_request_create(sess, "GET", "/"); ON(req == NULL); if (with_body) { static const char *body = "random stuff"; ne_set_request_body_buffer(req, body, strlen(body)); } /* request should fail. */ ret = ne_request_dispatch(req); ONN("request succeeded", ret == NE_OK); if (!forever) { /* reap the server, don't care what it's doing. */ reap_server(); } NE_DEBUG(NE_DBG_HTTP, "Response gave error `%s'\n", ne_get_error(sess)); ONV(error && strstr(ne_get_error(sess), error) == NULL, ("failed with error `%s', no `%s'", ne_get_error(sess), error)); if (!forever) ONV(any_request(sess, "/fail/to/connect") != NE_CONNECT, ("subsequent request re-used connection?")); ne_request_destroy(req); ne_session_destroy(sess); return OK; }/* Run a random GET request which is given 'body' as the response; the * request must fail, and 'error' must be found in the error * string. */static int invalid_response_gives_error(const char *resp, const char *error){ return fail_request_with_error(0, single_serve_string, (void *)resp, 0, error);}/* Utility function: run a request using the given server fn, and the * request must fail. */static int fail_request(int with_body, server_fn fn, void *ud, int forever){ return fail_request_with_error(with_body, fn, ud, forever, NULL);}static int unbounded_headers(void){ return fail_request(0, serve_infinite_headers, NULL, 0);}static int blank_response(void){ return fail_request(0, single_serve_string, "\r\n", 0);}static int serve_non_http(ne_socket *sock, void *ud){ SEND_STRING(sock, "Hello Mum.\n"); ne_sock_readline(sock, buffer, BUFSIZ); return OK;}/* Test behaviour when not speaking to an HTTP server. Regression test * for infinite loop. */static int not_http(void){ return fail_request(0, serve_non_http, NULL, 0);}static int serve_infinite_folds(ne_socket *sock, void *ud){ SEND_STRING(sock, "HTTP/1.0 200 OK\r\nFoo: bar\r\n"); for (;;) { SEND_STRING(sock, " hello there.\r\n"); } return OK;}static int unbounded_folding(void){ return fail_request(0, serve_infinite_folds, NULL, 0);}static int serve_close(ne_socket *sock, void *ud){ /* do nothing; the socket will be closed. */ return 0;}/* Returns non-zero if port is alive. */static int is_alive(int port){ ne_sock_addr *addr; ne_socket *sock = ne_sock_create(); const ne_inet_addr *ia; int connected = 0; addr = ne_addr_resolve("localhost", 0); for (ia = ne_addr_first(addr); ia && !connected; ia = ne_addr_next(addr))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -