From: Niels Provos Date: Mon, 13 Feb 2006 02:22:48 +0000 (+0000) Subject: many changes for fixing a small bug: post requests would not send the post X-Git-Tag: release-2.0.1-alpha~746 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=896bf3a2607c25ded5b732de35da63bd8016f9ed;p=libevent many changes for fixing a small bug: post requests would not send the post data. I took the opportunity to reorganize a bit. svn:r201 --- diff --git a/buffer.c b/buffer.c index e3c0ef9a..e641e91f 100644 --- a/buffer.c +++ b/buffer.c @@ -117,8 +117,10 @@ evbuffer_add_buffer(struct evbuffer *outbuf, struct evbuffer *inbuf) } res = evbuffer_add(outbuf, inbuf->buffer, inbuf->off); - if (res == 0) + if (res == 0) { + /* We drain the input buffer on success */ evbuffer_drain(inbuf, inbuf->off); + } return (res); } diff --git a/event.h b/event.h index cf575061..4a14d5de 100644 --- a/event.h +++ b/event.h @@ -317,7 +317,13 @@ int evtag_unmarshal_timeval(struct evbuffer *evbuf, u_int8_t need_tag, struct timeval *ptv); /* - * Basic support for HTTP serving + * Basic support for HTTP serving. + * + * As libevent is a library for dealing with event notification and most + * interesting applications are networked today, I have often found the + * need to write HTTP code. The following prototypes and definitions provide + * an application with a minimal interface for making HTTP requests and for + * creating a very simple HTTP server. */ /* Response codes */ @@ -332,6 +338,10 @@ struct evhttp_request; /* Start an HTTP server on the specified address and port */ struct evhttp *evhttp_start(const char *address, u_short port); +/* + * Free the previously create HTTP server. Works only if not requests are + * currently being served. + */ void evhttp_free(struct evhttp* http); /* Set a callback for a specified URI */ @@ -348,12 +358,32 @@ void evhttp_send_reply(struct evhttp_request *, int, const char *, /* Interfaces for making requests */ enum evhttp_cmd_type { EVHTTP_REQ_GET, EVHTTP_REQ_POST, EVHTTP_REQ_HEAD }; -enum evhttp_request_kind { EVHTTP_REQUEST, EVHTTP_RESPONSE }; struct evhttp_request *evhttp_request_new( void (*cb)(struct evhttp_request *, void *), void *arg); void evhttp_request_free(struct evhttp_request *req); - + +/* Interfaces for dealing with HTTP headers */ + +/* + * Key-Value pairs. Can be used for HTTP headers but also for + * query argument parsing. + */ +struct evkeyval { + TAILQ_ENTRY(evkeyval) next; + + char *key; + char *value; +}; + +TAILQ_HEAD(evkeyvalq, evkeyval); + +char *evhttp_find_header(struct evkeyvalq *, const char *); +void evhttp_remove_header(struct evkeyvalq *, const char *); +int evhttp_add_header(struct evkeyvalq *, const char *, const char *); +void evhttp_clear_headers(struct evkeyvalq *); + +void evhttp_parse_query(const char *uri, struct evkeyvalq *); #ifdef __cplusplus } #endif diff --git a/http.c b/http.c index 9a700032..bc3042a1 100644 --- a/http.c +++ b/http.c @@ -177,49 +177,64 @@ evhttp_write_buffer(struct evhttp_request *req, struct evbuffer *buffer, event_add(&req->ev, &tv); } +static void +evhttp_make_header_request(struct evbuffer *buf, struct evhttp_request *req) +{ + static char line[1024]; + const char *method; + + evhttp_remove_header(req->output_headers, "Accept-Encoding"); + evhttp_remove_header(req->output_headers, "Proxy-Connection"); + evhttp_remove_header(req->output_headers, "Connection"); + evhttp_add_header(req->output_headers, "Connection", "close"); + req->minor = 0; + + /* Generate request line */ + method = evhttp_method(req->type); + snprintf(line, sizeof(line), "%s %s HTTP/%d.%d\r\n", + method, req->uri, req->major, req->minor); + evbuffer_add(buf, line, strlen(line)); + + /* Add the content length on a post request if missing */ + if (req->type == EVHTTP_REQ_POST && + evhttp_find_header(req->output_headers, "Content-Length") == NULL){ + char size[12]; + snprintf(size, sizeof(size), "%d", + EVBUFFER_LENGTH(req->buffer)); + evhttp_add_header(req->output_headers, "Content-Length", size); + } +} + +static void +evhttp_make_header_response(struct evbuffer *buf, struct evhttp_request *req) +{ + static char line[1024]; + snprintf(line, sizeof(line), "HTTP/%d.%d %d %s\r\n", + req->major, req->minor, req->response_code, + req->response_code_line); + evbuffer_add(buf, line, strlen(line)); + + /* Potentially add headers */ + if (evhttp_find_header(req->output_headers, "Content-Type") == NULL) { + evhttp_add_header(req->output_headers, + "Content-Type", "text/html; charset=ISO-8859-1"); + } +} + void evhttp_make_header(struct evbuffer *buf, struct evhttp_request *req) { - char line[1024]; + static char line[1024]; struct evkeyval *header; - const char *method; - /* First we make a few tiny modifications */ + /* + * Depending if this is a HTTP request or response, we might need to + * add some new headers or remove existing headers. + */ if (req->kind == EVHTTP_REQUEST) { - evhttp_remove_header(req->output_headers, "Accept-Encoding"); - evhttp_remove_header(req->output_headers, "Proxy-Connection"); - evhttp_remove_header(req->output_headers, "Connection"); - evhttp_add_header(req->output_headers, "Connection", "close"); - req->minor = 0; - - /* Generate request line */ - method = evhttp_method(req->type); - snprintf(line, sizeof(line), "%s %s HTTP/%d.%d\r\n", - method, req->uri, req->major, req->minor); - evbuffer_add(buf, line, strlen(line)); - - /* Add the content length on a post request if missing */ - if (req->type == EVHTTP_REQ_POST && - evhttp_find_header(req->output_headers, - "Content-Length") == NULL) { - char size[12]; - snprintf(size, sizeof(size), "%d", - EVBUFFER_LENGTH(req->buffer)); - evhttp_add_header(req->output_headers, - "Content-Length", size); - } + evhttp_make_header_request(buf, req); } else { - snprintf(line, sizeof(line), "HTTP/%d.%d %d %s\r\n", - req->major, req->minor, req->response_code, - req->response_code_line); - evbuffer_add(buf, line, strlen(line)); - - /* Potentially add headers */ - if (evhttp_find_header(req->output_headers, - "Content-Type") == NULL) { - evhttp_add_header(req->output_headers, - "Content-Type", "text/html; charset=ISO-8859-1"); - } + evhttp_make_header_response(buf, req); } TAILQ_FOREACH(header, req->output_headers, next) { @@ -230,7 +245,7 @@ evhttp_make_header(struct evbuffer *buf, struct evhttp_request *req) evbuffer_add(buf, "\r\n", 2); if (req->kind == EVHTTP_REQUEST) { - int len = req->buffer->off; + int len = EVBUFFER_LENGTH(req->buffer); /* Add the POST data */ if (len > 0) @@ -815,8 +830,12 @@ evhttp_read_header(int fd, short what, void *arg) /* * Creates a TCP connection to the specified port and executes a callback - * when finished. Failure of sucess is indicate by the passed connection + * when finished. Failure or sucess is indicate by the passed connection * object. + * + * Although this interface accepts a hostname, it is intended to take + * only numeric hostnames so that non-blocking DNS resolution can + * happen elsewhere. */ struct evhttp_connection * @@ -865,12 +884,14 @@ evhttp_connect(const char *address, unsigned short port, } /* - * Don't know if we just want to pass a file descriptor or the evcon object. - * In theory we might use this to queue requests on the connection object. + * Starts an HTTP request on the provided evhttp_connection object. + * + * In theory we might use this to queue requests on the connection + * object. */ int -evhttp_start_request(struct evhttp_connection *evcon, +evhttp_make_request(struct evhttp_connection *evcon, struct evhttp_request *req, enum evhttp_cmd_type type, const char *uri) { @@ -897,6 +918,13 @@ evhttp_start_request(struct evhttp_connection *evcon, /* Create the header from the store arguments */ evhttp_make_header(evbuf, req); + /* + * If this was a post request or for other reasons we need to append + * our post data to the request. + */ + evbuffer_add_buffer(evbuf, req->buffer); + + /* Schedule the write */ req->save_cb = req->cb; req->save_cbarg = req->cb_arg; @@ -1022,6 +1050,7 @@ evhttp_parse_query(const char *uri, struct evkeyvalq *headers) TAILQ_INIT(headers); + /* No arguments - we are done */ if (strchr(uri, '?') == NULL) return; diff --git a/test/regress_http.c b/test/regress_http.c index 9bb3b25f..17597e97 100644 --- a/test/regress_http.c +++ b/test/regress_http.c @@ -82,6 +82,7 @@ http_setup(short *pport) if (port == -1) event_errx(1, "Could not start web server"); + /* Register a callback for certain types of requests */ evhttp_set_cb(myhttp, "/test", http_basic_cb, NULL); *pport = port; @@ -264,7 +265,7 @@ http_connectcb(struct evhttp_connection *evcon, void *arg) /* Add the information that we care about */ evhttp_add_header(req->output_headers, "Host", "somehost"); - if (evhttp_start_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) { + if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) { fprintf(stdout, "FAILED\n"); exit(1); }