Merge branch 'http_small_tweaks'

Conflicts:
	http-internal.h
This commit is contained in:
Nick Mathewson 2010-10-21 12:23:10 -04:00
commit 2a3b5872fe
2 changed files with 64 additions and 24 deletions

View File

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

65
http.c
View File

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