]> granicus.if.org Git - libevent/commitdiff
many changes for fixing a small bug: post requests would not send the post
authorNiels Provos <provos@gmail.com>
Mon, 13 Feb 2006 02:22:48 +0000 (02:22 +0000)
committerNiels Provos <provos@gmail.com>
Mon, 13 Feb 2006 02:22:48 +0000 (02:22 +0000)
data.  I took the opportunity to reorganize a bit.

svn:r201

buffer.c
event.h
http.c
test/regress_http.c

index e3c0ef9a52f2cb3ba8e94eb24f95c1f6e04b8b1c..e641e91fe8c6832553b297a355674f93bd646fee 100644 (file)
--- 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 cf575061ccd8a3aaf4940bf6ab53ebf7a2340d55..4a14d5def74bfa7cde7baf7e6282b5db3677340f 100644 (file)
--- 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 9a700032c119a8b4405d6e9f008f363d433a79e1..bc3042a193f1c89d1a4b8befbbb8336ef6409e4e 100644 (file)
--- 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;
 
index 9bb3b25f05334fd326387dd10a6d77706740bb37..17597e97078a2be6e0d51e3a9f3a96a6f8d7e498 100644 (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);
        }