⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 request.c

📁 linux subdivision ying gai ke yi le ba
💻 C
📖 第 1 页 / 共 3 页
字号:
/*    HTTP request handling tests   Copyright (C) 2001-2003, Joe Orton <joe@manyfish.co.uk>   This program is free software; you can redistribute it and/or modify   it under the terms of the GNU General Public License as published by   the Free Software Foundation; either version 2 of the License, or   (at your option) any later version.     This program is distributed in the hope that it will be useful,   but WITHOUT ANY WARRANTY; without even the implied warranty of   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the   GNU General Public License for more details.     You should have received a copy of the GNU General Public License   along with this program; if not, write to the Free Software   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.*/#include "config.h"#include <sys/types.h>#include <time.h> /* for time() */#ifdef HAVE_STDLIB_H#include <stdlib.h>#endif#ifdef HAVE_UNISTD_H#include <unistd.h>#endif#include "ne_request.h"#include "ne_socket.h"#include "tests.h"#include "child.h"#include "utils.h"static char buffer[BUFSIZ];static ne_session *def_sess;static ne_request *def_req;static int prepare_request(server_fn fn, void *ud){    static char uri[100];    def_sess = ne_session_create("http", "localhost", 7777);    sprintf(uri, "/test%d", test_num);    def_req = ne_request_create(def_sess, "GET", uri);    CALL(spawn_server(7777, fn, ud));    return OK;}static int finish_request(void){    ne_request_destroy(def_req);    ne_session_destroy(def_sess);    return await_server();}#define RESP200 "HTTP/1.1 200 OK\r\n" "Server: neon-test-server\r\n"#define TE_CHUNKED "Transfer-Encoding: chunked\r\n"/* takes response body chunks and appends them to a buffer. */static void collector(void *ud, const char *data, size_t len){    ne_buffer *buf = ud;    ne_buffer_append(buf, data, len);}typedef ne_request *(*construct_request)(ne_session *sess, void *userdata);/* construct a get request, callback for run_request. */static ne_request *construct_get(ne_session *sess, void *userdata){    ne_request *r = ne_request_create(sess, "GET", "/");    ne_buffer *buf = userdata;    ne_add_response_body_reader(r, ne_accept_2xx, collector, buf);    return r;}/* run a request created by callback 'cb' in session 'sess'. */static int run_request(ne_session *sess, int status,		       construct_request cb, void *userdata){    ne_request *req = cb(sess, userdata);    ON(req == NULL);        ONREQ(ne_request_dispatch(req));     ONV(ne_get_status(req)->code != status,	("response status-code was %d not %d",	 ne_get_status(req)->code, status));    ne_request_destroy(req);    return OK;}/* Runs a server function 'fn', expecting to get a header 'name' with value * 'value' in the response. */static int expect_header_value(const char *name, const char *value,			       server_fn fn, void *userdata){    ne_session *sess;    ne_request *req;    char *gotval = NULL;    CALL(make_session(&sess, fn, userdata));    req = ne_request_create(sess, "FOO", "/bar");    ne_add_response_header_handler(req, name, ne_duplicate_header, &gotval);    ONREQ(ne_request_dispatch(req));    CALL(await_server());        ONN("no header value set", gotval == NULL);    ONV(strcmp(gotval, value),	("header value mis-match: got [%s] not [%s]", gotval, value));        ne_request_destroy(req);    ne_session_destroy(sess);    ne_free(gotval);    return OK;}/* runs a server function 'fn', expecting response body to be equal to * 'expect' */static int expect_response(const char *expect, server_fn fn, void *userdata){    ne_session *sess = ne_session_create("http", "localhost", 7777);    ne_buffer *buf = ne_buffer_create();    ON(sess == NULL || buf == NULL);    ON(spawn_server(7777, fn, userdata));    CALL(run_request(sess, 200, construct_get, buf));    ON(await_server());    ONN("response body match", strcmp(buf->data, expect));    ne_session_destroy(sess);    ne_buffer_destroy(buf);        return OK;}#define EMPTY_RESP RESP200 "Content-Length: 0\r\n\r\n"/* Process a request with given method and response, expecting to get * a zero-length response body.  A second request is sent down the * connection (to ensure that the response isn't silently eaten), so * 'resp' must be an HTTP/1.1 response with no 'Connection: close' * header. */static int expect_no_body(const char *method, const char *resp){    ne_session *sess = ne_session_create("http", "localhost", 7777);    ne_request *req = ne_request_create(sess, method, "/first");    ssize_t ret;    char *r = ne_malloc(strlen(resp) + sizeof(EMPTY_RESP));        strcpy(r, resp);    strcat(r, EMPTY_RESP);    ON(spawn_server(7777, single_serve_string, r));    ne_free(r);    ONN("failed to begin request", ne_begin_request(req));    ret = ne_read_response_block(req, buffer, BUFSIZ);    ONV(ret != 0, ("got response block of size %" NE_FMT_SSIZE_T, ret));    ONN("failed to end request", ne_end_request(req));    /* process following request; makes sure that nothing extra has     * been eaten by the first request. */    ONV(any_request(sess, "/second"),	("second request on connection failed: %s",ne_get_error(sess)));    ON(await_server());    ne_request_destroy(req);    ne_session_destroy(sess);    return OK;}static int reason_phrase(void){    ne_session *sess;    CALL(make_session(&sess, single_serve_string, RESP200		      "Connection: close\r\n\r\n"));    CALL(any_request(sess, "/foo"));    CALL(await_server());        ONV(strcmp(ne_get_error(sess), "200 OK"),	("reason phrase mismatch: got `%s' not `200 OK'",	 ne_get_error(sess)));    ne_session_destroy(sess);    return OK;    }static int single_get_eof(void){    return expect_response("a", single_serve_string, 			   RESP200			   "Connection: close\r\n"			   "\r\n"			   "a");}static int single_get_clength(void){    return expect_response("a", single_serve_string,			   RESP200			   "Content-Length: 1\r\n"			   "\r\n"			   "a"			   "bbbbbbbbasdasd");}static int single_get_chunked(void) {    return expect_response("a", single_serve_string,			   RESP200 TE_CHUNKED			   "\r\n"			   "1\r\n"			   "a\r\n"			   "0\r\n" "\r\n"			   "g;lkjalskdjalksjd");}static int no_body_304(void){    return expect_no_body("GET", "HTTP/1.1 304 Not Mfodified\r\n"			  "Content-Length: 5\r\n\r\n");}static int no_body_204(void){    return expect_no_body("GET", "HTTP/1.1 204 Not Modified\r\n"			  "Content-Length: 5\r\n\r\n");}static int no_body_205(void){    return expect_no_body("GET", "HTTP/1.1 205 Reset Content\r\n"			  "Content-Length: 5\r\n\r\n");}static int no_body_HEAD(void){    return expect_no_body("HEAD", "HTTP/1.1 200 OK\r\n"			  "Content-Length: 5\r\n\r\n");}static int no_body_empty_clength(void){    return expect_no_body("GET", "HTTP/1.1 200 OK\r\n"			  "Content-Length:\r\n\r\n");}static int no_body_bad_clength(void){    return expect_no_body("GET", "HTTP/1.1 200 OK\r\n"			  "Content-Length: foobar\r\n\r\n");}static int no_headers(void){    return expect_response("abcde", single_serve_string,			   "HTTP/1.1 200 OK\r\n\r\n"			   "abcde");}#define CHUNK(len, data) #len "\r\n" data "\r\n"#define ABCDE_CHUNKS CHUNK(1, "a") CHUNK(1, "b") \ CHUNK(1, "c") CHUNK(1, "d") \ CHUNK(1, "e") CHUNK(0, "")static int chunks(void){    /* lots of little chunks. */    return expect_response("abcde", single_serve_string,			   RESP200 TE_CHUNKED			   "\r\n"			   ABCDE_CHUNKS);}static int te_header(void){    return expect_response("abcde", single_serve_string,			   RESP200 "Transfer-Encoding: CHUNKED\r\n"			   "\r\n" ABCDE_CHUNKS);}/* test that the presence of *any* t-e header implies a chunked * response. */static int any_te_header(void){    return expect_response("abcde", single_serve_string, RESP200                           "Transfer-Encoding: punked\r\n" "\r\n"                           ABCDE_CHUNKS);}static int chunk_numeric(void){        /* leading zero's */    return expect_response("0123456789abcdef", single_serve_string,			   RESP200 TE_CHUNKED			   "\r\n"			   "000000010\r\n" "0123456789abcdef\r\n"			   "000000000\r\n" "\r\n");}static int chunk_extensions(void){    /* chunk-extensions. */    return expect_response("0123456789abcdef", single_serve_string,			   RESP200 TE_CHUNKED			   "\r\n"			   "000000010; foo=bar; norm=fish\r\n" 			   "0123456789abcdef\r\n"			   "000000000\r\n" "\r\n");}static int chunk_trailers(void){    /* trailers. */    return expect_response("abcde", single_serve_string,			   RESP200 TE_CHUNKED			   "\r\n"			   "00000005; foo=bar; norm=fish\r\n" 			   "abcde\r\n"			   "000000000\r\n" 			   "X-Hello: world\r\n"			   "X-Another: header\r\n"			   "\r\n");}static int chunk_oversize(void){#define BIG (20000)    char *body = ne_malloc(BIG + 1);    static const char rnd[] = "abcdefghijklm";    int n;    ne_buffer *buf = ne_buffer_create();        for (n = 0; n < BIG; n++) {	body[n] = rnd[n % (sizeof(rnd) - 1)];    }    body[n] = '\0';#undef BIG    ne_buffer_concat(buf, RESP200 TE_CHUNKED "\r\n" 		     "4E20\r\n", body, "\r\n",		     "0\r\n\r\n", NULL);    CALL(expect_response(body, single_serve_string, buf->data));        ne_buffer_destroy(buf);    ne_free(body);    return OK;}static int te_over_clength(void){       /* T-E dominates over C-L. */    return expect_response("abcde", single_serve_string,			   RESP200 TE_CHUNKED			   "Content-Length: 300\r\n" 			   "\r\n"			   ABCDE_CHUNKS);}/* te_over_clength with the headers the other way round; check for * ordering problems. */static int te_over_clength2(void){       return expect_response("abcde", single_serve_string,			   RESP200 "Content-Length: 300\r\n" 			   TE_CHUNKED			   "\r\n"			   ABCDE_CHUNKS);}/* obscure case which is possibly a valid request by 2616, but should * be handled correctly in any case.  neon <0.22.0 tries to  * eat the response body, which is probably incorrect. */static int no_body_chunks(void){    return expect_no_body("HEAD", "HTTP/1.1 204 Not Modified\r\n"			  TE_CHUNKED "\r\n");}static int serve_twice(ne_socket *sock, void *userdata){    const char *resp = userdata;        CALL(discard_request(sock));    SEND_STRING(sock, resp);    CALL(discard_request(sock));    SEND_STRING(sock, resp);    return OK;}/* Test persistent connection handling: serve 'response' twice on a * single TCP connection, expecting to get a response body equal to * 'body' both times. */static int test_persist(const char *response, const char *body){    ne_session *sess = ne_session_create("http", "localhost", 7777);    ne_buffer *buf = ne_buffer_create();    ON(sess == NULL || buf == NULL);    ON(spawn_server(7777, serve_twice, (char *)response));        CALL(run_request(sess, 200, construct_get, buf));        ONV(strcmp(buf->data, body),	("response #1 mismatch: [%s] not [%s]", buf->data, body));    /* Run it again. */    ne_buffer_clear(buf);    CALL(run_request(sess, 200, construct_get, buf));    ON(await_server());    ONV(strcmp(buf->data, body),	("response #2 mismatch: [%s] not [%s]", buf->data, body));    ne_session_destroy(sess);    ne_buffer_destroy(buf);    return OK;}static int persist_http11(void){    return test_persist(RESP200 "Content-Length: 5\r\n\r\n" "abcde",			"abcde");}static int persist_chunked(void){    return test_persist(RESP200 TE_CHUNKED "\r\n" ABCDE_CHUNKS,			"abcde");}static int persist_http10(void){    return test_persist("HTTP/1.0 200 OK\r\n"			"Connection: keep-alive\r\n"			"Content-Length: 5\r\n\r\n" "abcde",			"abcde");}/* Server function for fail_early_eof */static int serve_eof(ne_socket *sock, void *ud){    const char *resp = ud;    /* dummy request/response. */    CALL(discard_request(sock));    CALL(SEND_STRING(sock, RESP200 "Content-Length: 0\r\n\r\n"));    /* real request/response. */    CALL(discard_request(sock));    CALL(SEND_STRING(sock, resp));    return OK;}/* Utility function: 'resp' is a truncated response; such that an EOF * arrives early during response processing; but NOT as a valid * premature EOF due to a persistent connection timeout.  It is an * error if the request is then retried, and the test fails. */static int fail_early_eof(const char *resp){    ne_session *sess = ne_session_create("http", "localhost", 7777);    CALL(spawn_server_repeat(7777, serve_eof, (char *)resp, 3));    ONREQ(any_request(sess, "/foo"));    ONN("request retried after early EOF",	any_request(sess, "/foobar") == NE_OK);        CALL(reap_server());    ne_session_destroy(sess);    return OK;}/* This failed with neon <0.22. */static int fail_eof_continued(void){    return fail_early_eof("HTTP/1.1 100 OK\r\n\r\n");}static int fail_eof_headers(void){    return fail_early_eof("HTTP/1.1 200 OK\r\nJimbob\r\n");}static int fail_eof_chunk(void){    return fail_early_eof(RESP200 TE_CHUNKED "\r\n" "1\r\n" "a");}static int fail_eof_badclen(void){    return fail_early_eof(RESP200 "Content-Length: 10\r\n\r\n" "abcde");}/* Persistent connection timeout where a FIN is sent to terminate the * connection, which is caught by a 0 return from the read() when the * second request reads the status-line. */static int ptimeout_eof(void){    ne_session *sess = ne_session_create("http", "localhost", 7777);    CALL(spawn_server_repeat(7777, single_serve_string, 			     RESP200 "Content-Length: 0\r\n" "\r\n", 4));        CALL(any_2xx_request(sess, "/first"));    CALL(any_2xx_request(sess, "/second"));        ONN("server died prematurely?", dead_server());    reap_server();    ne_session_destroy(sess);    return OK;}/* Persistent connection timeout where a FIN is sent to terminate the * connection, but the request fails in the write() call which sends * the body. */static int ptimeout_eof2(void){    ne_session *sess = ne_session_create("http", "localhost", 7777);    CALL(spawn_server_repeat(7777, single_serve_string, 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -