summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--http-internal.h23
-rw-r--r--http.c65
2 files changed, 64 insertions, 24 deletions
diff --git a/http-internal.h b/http-internal.h
index 073dd488..0a07643f 100644
--- a/http-internal.h
+++ b/http-internal.h
@@ -40,8 +40,6 @@ struct evbuffer;
struct addrinfo;
struct evhttp_request;
-/* A stupid connection object - maybe make this a bufferevent later */
-
enum evhttp_connection_state {
EVCON_DISCONNECTED, /**< not currently connected not trying either*/
EVCON_CONNECTING, /**< tries to currently connect */
@@ -56,8 +54,10 @@ enum evhttp_connection_state {
struct event_base;
+/* A client or server connection. */
struct evhttp_connection {
- /* we use tailq only if they were created for an http server */
+ /* we use this tailq only if this connection was created for an http
+ * server */
TAILQ_ENTRY(evhttp_connection) next;
evutil_socket_t fd;
@@ -100,6 +100,7 @@ struct evhttp_connection {
struct evdns_base *dns_base;
};
+/* A callback for an http server */
struct evhttp_cb {
TAILQ_ENTRY(evhttp_cb) next;
@@ -120,11 +121,15 @@ struct evhttp_bound_socket {
};
struct evhttp {
- TAILQ_ENTRY(evhttp) next;
+ /* Next vhost, if this is a vhost. */
+ TAILQ_ENTRY(evhttp) next_vhost;
+ /* All listeners for this host */
TAILQ_HEAD(boundq, evhttp_bound_socket) sockets;
TAILQ_HEAD(httpcbq, evhttp_cb) callbacks;
+
+ /* All live connections on this host. */
struct evconq connections;
TAILQ_HEAD(vhostsq, evhttp) virtualhosts;
@@ -137,12 +142,16 @@ struct evhttp {
size_t default_max_headers_size;
ev_uint64_t default_max_body_size;
+ /* Fallback callback if all the other callbacks for this connection
+ don't match. */
void (*gencb)(struct evhttp_request *req, void *);
void *gencbarg;
struct event_base *base;
};
+/* XXX most of these functions could be static. */
+
/* resets the connection; can be reused for more requests */
void evhttp_connection_reset(struct evhttp_connection *);
@@ -153,18 +162,12 @@ int evhttp_connection_connect(struct evhttp_connection *);
void evhttp_connection_fail(struct evhttp_connection *,
enum evhttp_connection_error error);
-void evhttp_get_request(struct evhttp *, evutil_socket_t, struct sockaddr *, ev_socklen_t);
-
enum message_read_status;
enum message_read_status evhttp_parse_firstline(struct evhttp_request *, struct evbuffer*);
enum message_read_status evhttp_parse_headers(struct evhttp_request *, struct evbuffer*);
void evhttp_start_read(struct evhttp_connection *);
-void evhttp_make_header(struct evhttp_connection *, struct evhttp_request *);
-
-void evhttp_write_buffer(struct evhttp_connection *,
- void (*)(struct evhttp_connection *, void *), void *);
/* response sending HTML the data in the buffer */
void evhttp_response_code(struct evhttp_request *, int, const char *);
diff --git a/http.c b/http.c
index aceff253..68fb7d84 100644
--- a/http.c
+++ b/http.c
@@ -172,6 +172,10 @@ static void evhttp_read_header(struct evhttp_connection *evcon,
static int evhttp_add_header_internal(struct evkeyvalq *headers,
const char *key, const char *value);
static const char *evhttp_response_phrase_internal(int code);
+static void evhttp_get_request(struct evhttp *, evutil_socket_t, struct sockaddr *, ev_socklen_t);
+static void evhttp_write_buffer(struct evhttp_connection *,
+ void (*)(struct evhttp_connection *, void *), void *);
+static void evhttp_make_header(struct evhttp_connection *, struct evhttp_request *);
/* callbacks for bufferevent */
static void evhttp_read_cb(struct bufferevent *, void *);
@@ -260,6 +264,9 @@ evhttp_htmlescape(const char *html)
return (escaped_html);
}
+/** Given an evhttp_cmd_type, returns a constant string containing the
+ * equivalent HTTP command, or NULL if the evhttp_command_type is
+ * unrecognized. */
static const char *
evhttp_method(enum evhttp_cmd_type type)
{
@@ -304,6 +311,9 @@ evhttp_response_needs_body(struct evhttp_request *req)
req->type != EVHTTP_REQ_HEAD);
}
+/** Helper: adds the event 'ev' with the timeout 'timeout', or with
+ * default_timeout if timeout is -1.
+ */
static int
evhttp_add_event(struct event *ev, int timeout, int default_timeout)
{
@@ -318,7 +328,11 @@ evhttp_add_event(struct event *ev, int timeout, int default_timeout)
}
}
-void
+/** Helper: called after we've added some data to an evcon's bufferevent's
+ * output buffer. Sets the evconn's writing-is-done callback, and puts
+ * the bufferevent into writing mode.
+ */
+static void
evhttp_write_buffer(struct evhttp_connection *evcon,
void (*cb)(struct evhttp_connection *, void *), void *arg)
{
@@ -332,6 +346,7 @@ evhttp_write_buffer(struct evhttp_connection *evcon,
bufferevent_enable(evcon->bufev, EV_WRITE);
}
+/** Helper: returns true iff evconn is in any connected state. */
static int
evhttp_connected(struct evhttp_connection *evcon)
{
@@ -350,8 +365,9 @@ evhttp_connected(struct evhttp_connection *evcon)
}
}
-/*
- * Create the headers needed for an HTTP request
+/* Create the headers needed for an outgoing HTTP request, adds them to
+ * the request's header list, and writes the request line to the
+ * connection's output buffer.
*/
static void
evhttp_make_header_request(struct evhttp_connection *evcon,
@@ -370,6 +386,7 @@ evhttp_make_header_request(struct evhttp_connection *evcon,
/* Add the content length on a post or put request if missing */
if ((req->type == EVHTTP_REQ_POST || req->type == EVHTTP_REQ_PUT) &&
evhttp_find_header(req->output_headers, "Content-Length") == NULL){
+ /* XXX what if long is 64 bits? -NM */
char size[12];
evutil_snprintf(size, sizeof(size), "%ld",
(long)evbuffer_get_length(req->output_buffer));
@@ -377,6 +394,9 @@ evhttp_make_header_request(struct evhttp_connection *evcon,
}
}
+/** Return true if the list of headers in 'headers', intepreted with respect
+ * to flags, means that we should send a "connection: close" when the request
+ * is done. */
static int
evhttp_is_connection_close(int flags, struct evkeyvalq* headers)
{
@@ -390,6 +410,7 @@ evhttp_is_connection_close(int flags, struct evkeyvalq* headers)
}
}
+/* Return true iff 'headers' contains 'Connection: keep-alive' */
static int
evhttp_is_connection_keepalive(struct evkeyvalq* headers)
{
@@ -398,6 +419,7 @@ evhttp_is_connection_keepalive(struct evkeyvalq* headers)
&& evutil_ascii_strncasecmp(connection, "keep-alive", 10) == 0);
}
+/* Add a correct "Date" header to headers, unless it already has one. */
static void
evhttp_maybe_add_date_header(struct evkeyvalq *headers)
{
@@ -421,22 +443,24 @@ evhttp_maybe_add_date_header(struct evkeyvalq *headers)
}
}
+/* Add a "Content-Length" header with value 'content_length' to headers,
+ * unless it already has a content-length or transfer-encoding header. */
static void
evhttp_maybe_add_content_length_header(struct evkeyvalq *headers,
- long content_length)
+ long content_length) /* XXX use size_t or int64, not long. */
{
if (evhttp_find_header(headers, "Transfer-Encoding") == NULL &&
evhttp_find_header(headers, "Content-Length") == NULL) {
- char len[12];
+ char len[12]; /* XXX what if long is 64 bits? -NM */
evutil_snprintf(len, sizeof(len), "%ld", content_length);
evhttp_add_header(headers, "Content-Length", len);
}
}
/*
- * Create the headers needed for an HTTP reply
+ * Create the headers needed for an HTTP reply in req->output_headers,
+ * and write the first HTTP response for req line to evcon.
*/
-
static void
evhttp_make_header_response(struct evhttp_connection *evcon,
struct evhttp_request *req)
@@ -447,6 +471,7 @@ evhttp_make_header_response(struct evhttp_connection *evcon,
req->major, req->minor, req->response_code,
req->response_code_line);
+ /* XXX shouldn't these check for >= rather than == ? - NM */
if (req->major == 1) {
if (req->minor == 1)
evhttp_maybe_add_date_header(req->output_headers);
@@ -490,7 +515,10 @@ evhttp_make_header_response(struct evhttp_connection *evcon,
}
}
-void
+/** Generate all headers appropriate for sending the http request in req (or
+ * the response, if we're sending a response), and write them to evcon's
+ * bufferevent. Also writes all data from req->output_buffer */
+static void
evhttp_make_header(struct evhttp_connection *evcon, struct evhttp_request *req)
{
struct evkeyval *header;
@@ -584,6 +612,10 @@ evhttp_connection_incoming_fail(struct evhttp_request *req,
return (0);
}
+/* Called when evcon has experienced a (non-recoverable? -NM) error, as
+ * given in error. If it's an outgoing connection, reset the connection,
+ * retry any pending requests, and inform the user. If it's incoming,
+ * delegates to evhttp_connection_incoming_fail(). */
void
evhttp_connection_fail(struct evhttp_connection *evcon,
enum evhttp_connection_error error)
@@ -638,6 +670,8 @@ evhttp_connection_fail(struct evhttp_connection *evcon,
(*cb)(NULL, cb_arg);
}
+/* Bufferevent callback: invoked when any data has been written from an
+ * http connection's bufferevent */
static void
evhttp_write_cb(struct bufferevent *bufev, void *arg)
{
@@ -1031,7 +1065,8 @@ evhttp_request_dispatch(struct evhttp_connection* evcon)
evhttp_write_buffer(evcon, evhttp_write_connectioncb, NULL);
}
-/* Reset our connection state */
+/* Reset our connection state: disables reading/writing, closes our fd (if
+* any), clears out buffers, and puts us in state DISCONNECTED. */
void
evhttp_connection_reset(struct evhttp_connection *evcon)
{
@@ -1338,6 +1373,7 @@ evhttp_parse_request_line(struct evhttp_request *req, char *line)
req->major = 1;
req->minor = 1;
} else {
+ /* XXX So, http/1.2 kills us? Is that right? -NM */
event_debug(("%s: bad version %s on request %p from %s",
__func__, version, req, req->remote_host));
return (-1);
@@ -2597,7 +2633,7 @@ evhttp_handle_request(struct evhttp_request *req, void *arg)
hostname = evhttp_find_header(req->input_headers, "Host");
if (hostname != NULL) {
struct evhttp *vhost;
- TAILQ_FOREACH(vhost, &http->virtualhosts, next) {
+ TAILQ_FOREACH(vhost, &http->virtualhosts, next_vhost) {
if (prefix_suffix_match(vhost->vhost_pattern, hostname,
1 /* ignorecase */)) {
evhttp_handle_request(req, vhost);
@@ -2651,6 +2687,7 @@ evhttp_handle_request(struct evhttp_request *req, void *arg)
}
}
+/* Listener callback when a connection arrives at a server. */
static void
accept_socket_cb(struct evconnlistener *listener, evutil_socket_t nfd, struct sockaddr *peer_sa, int peer_socklen, void *arg)
{
@@ -2824,7 +2861,7 @@ evhttp_free(struct evhttp* http)
}
while ((vhost = TAILQ_FIRST(&http->virtualhosts)) != NULL) {
- TAILQ_REMOVE(&http->virtualhosts, vhost, next);
+ TAILQ_REMOVE(&http->virtualhosts, vhost, next_vhost);
evhttp_free(vhost);
}
@@ -2848,7 +2885,7 @@ evhttp_add_virtual_host(struct evhttp* http, const char *pattern,
if (vhost->vhost_pattern == NULL)
return (-1);
- TAILQ_INSERT_TAIL(&http->virtualhosts, vhost, next);
+ TAILQ_INSERT_TAIL(&http->virtualhosts, vhost, next_vhost);
return (0);
}
@@ -2859,7 +2896,7 @@ evhttp_remove_virtual_host(struct evhttp* http, struct evhttp* vhost)
if (vhost->vhost_pattern == NULL)
return (-1);
- TAILQ_REMOVE(&http->virtualhosts, vhost, next);
+ TAILQ_REMOVE(&http->virtualhosts, vhost, next_vhost);
mm_free(vhost->vhost_pattern);
vhost->vhost_pattern = NULL;
@@ -3178,7 +3215,7 @@ evhttp_associate_new_request_with_connection(struct evhttp_connection *evcon)
return (0);
}
-void
+static void
evhttp_get_request(struct evhttp *http, evutil_socket_t fd,
struct sockaddr *sa, ev_socklen_t salen)
{