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);
if (res == 0)
if (res == 0) {
/* We drain the input buffer on success */
evbuffer_drain(inbuf, inbuf->off);
}
return (res);
}

36
event.h
View File

@ -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

111
http.c
View File

@ -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;

View File

@ -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);
}