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
This commit is contained in:
Niels Provos 2006-02-13 02:22:48 +00:00
parent 7b78c82823
commit 896bf3a260
4 changed files with 108 additions and 46 deletions

View File

@ -117,8 +117,10 @@ evbuffer_add_buffer(struct evbuffer *outbuf, struct evbuffer *inbuf)
} }
res = evbuffer_add(outbuf, inbuf->buffer, inbuf->off); 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); evbuffer_drain(inbuf, inbuf->off);
}
return (res); return (res);
} }

34
event.h
View File

@ -317,7 +317,13 @@ int evtag_unmarshal_timeval(struct evbuffer *evbuf, u_int8_t need_tag,
struct timeval *ptv); 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 */ /* Response codes */
@ -332,6 +338,10 @@ struct evhttp_request;
/* Start an HTTP server on the specified address and port */ /* Start an HTTP server on the specified address and port */
struct evhttp *evhttp_start(const char *address, u_short 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); void evhttp_free(struct evhttp* http);
/* Set a callback for a specified URI */ /* 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 */ /* Interfaces for making requests */
enum evhttp_cmd_type { EVHTTP_REQ_GET, EVHTTP_REQ_POST, EVHTTP_REQ_HEAD }; 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( struct evhttp_request *evhttp_request_new(
void (*cb)(struct evhttp_request *, void *), void *arg); void (*cb)(struct evhttp_request *, void *), void *arg);
void evhttp_request_free(struct evhttp_request *req); 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 #ifdef __cplusplus
} }
#endif #endif

65
http.c
View File

@ -177,15 +177,12 @@ evhttp_write_buffer(struct evhttp_request *req, struct evbuffer *buffer,
event_add(&req->ev, &tv); event_add(&req->ev, &tv);
} }
void static void
evhttp_make_header(struct evbuffer *buf, struct evhttp_request *req) evhttp_make_header_request(struct evbuffer *buf, struct evhttp_request *req)
{ {
char line[1024]; static char line[1024];
struct evkeyval *header;
const char *method; const char *method;
/* First we make a few tiny modifications */
if (req->kind == EVHTTP_REQUEST) {
evhttp_remove_header(req->output_headers, "Accept-Encoding"); evhttp_remove_header(req->output_headers, "Accept-Encoding");
evhttp_remove_header(req->output_headers, "Proxy-Connection"); evhttp_remove_header(req->output_headers, "Proxy-Connection");
evhttp_remove_header(req->output_headers, "Connection"); evhttp_remove_header(req->output_headers, "Connection");
@ -200,26 +197,44 @@ evhttp_make_header(struct evbuffer *buf, struct evhttp_request *req)
/* Add the content length on a post request if missing */ /* Add the content length on a post request if missing */
if (req->type == EVHTTP_REQ_POST && if (req->type == EVHTTP_REQ_POST &&
evhttp_find_header(req->output_headers, evhttp_find_header(req->output_headers, "Content-Length") == NULL){
"Content-Length") == NULL) {
char size[12]; char size[12];
snprintf(size, sizeof(size), "%d", snprintf(size, sizeof(size), "%d",
EVBUFFER_LENGTH(req->buffer)); EVBUFFER_LENGTH(req->buffer));
evhttp_add_header(req->output_headers, evhttp_add_header(req->output_headers, "Content-Length", size);
"Content-Length", size);
} }
} else { }
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", snprintf(line, sizeof(line), "HTTP/%d.%d %d %s\r\n",
req->major, req->minor, req->response_code, req->major, req->minor, req->response_code,
req->response_code_line); req->response_code_line);
evbuffer_add(buf, line, strlen(line)); evbuffer_add(buf, line, strlen(line));
/* Potentially add headers */ /* Potentially add headers */
if (evhttp_find_header(req->output_headers, if (evhttp_find_header(req->output_headers, "Content-Type") == NULL) {
"Content-Type") == NULL) {
evhttp_add_header(req->output_headers, evhttp_add_header(req->output_headers,
"Content-Type", "text/html; charset=ISO-8859-1"); "Content-Type", "text/html; charset=ISO-8859-1");
} }
}
void
evhttp_make_header(struct evbuffer *buf, struct evhttp_request *req)
{
static char line[1024];
struct evkeyval *header;
/*
* 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_make_header_request(buf, req);
} else {
evhttp_make_header_response(buf, req);
} }
TAILQ_FOREACH(header, req->output_headers, next) { 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); evbuffer_add(buf, "\r\n", 2);
if (req->kind == EVHTTP_REQUEST) { if (req->kind == EVHTTP_REQUEST) {
int len = req->buffer->off; int len = EVBUFFER_LENGTH(req->buffer);
/* Add the POST data */ /* Add the POST data */
if (len > 0) 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 * 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. * 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 * 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. * Starts an HTTP request on the provided evhttp_connection object.
* In theory we might use this to queue requests on the connection object. *
* In theory we might use this to queue requests on the connection
* object.
*/ */
int int
evhttp_start_request(struct evhttp_connection *evcon, evhttp_make_request(struct evhttp_connection *evcon,
struct evhttp_request *req, struct evhttp_request *req,
enum evhttp_cmd_type type, const char *uri) 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 */ /* Create the header from the store arguments */
evhttp_make_header(evbuf, req); 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 */ /* Schedule the write */
req->save_cb = req->cb; req->save_cb = req->cb;
req->save_cbarg = req->cb_arg; req->save_cbarg = req->cb_arg;
@ -1022,6 +1050,7 @@ evhttp_parse_query(const char *uri, struct evkeyvalq *headers)
TAILQ_INIT(headers); TAILQ_INIT(headers);
/* No arguments - we are done */
if (strchr(uri, '?') == NULL) if (strchr(uri, '?') == NULL)
return; return;

View File

@ -82,6 +82,7 @@ http_setup(short *pport)
if (port == -1) if (port == -1)
event_errx(1, "Could not start web server"); 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); evhttp_set_cb(myhttp, "/test", http_basic_cb, NULL);
*pport = port; *pport = port;
@ -264,7 +265,7 @@ http_connectcb(struct evhttp_connection *evcon, void *arg)
/* Add the information that we care about */ /* Add the information that we care about */
evhttp_add_header(req->output_headers, "Host", "somehost"); 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"); fprintf(stdout, "FAILED\n");
exit(1); exit(1);
} }