from trunk: always generate Date and Content-Length headers for HTTP/1.1

svn:r565
This commit is contained in:
Niels Provos 2007-11-29 06:09:30 +00:00
parent 567f681bf1
commit ef12a5a15a
3 changed files with 110 additions and 38 deletions

View File

@ -8,6 +8,7 @@ Changes in current version:
o Make kqueue restore signal handlers correctly when event_del() is called. o Make kqueue restore signal handlers correctly when event_del() is called.
o provide event_reinit() to reintialize an event_base after fork o provide event_reinit() to reintialize an event_base after fork
o small improvements to evhttp documentation o small improvements to evhttp documentation
o always generate Date and Content-Length headers for HTTP/1.1 replies
Changes in 1.4.0-beta: Changes in 1.4.0-beta:

82
http.c
View File

@ -302,7 +302,7 @@ evhttp_write_buffer(struct evhttp_connection *evcon,
} }
/* /*
* Create the headers need for an HTTP reply * Create the headers need for an HTTP request
*/ */
static void static void
evhttp_make_header_request(struct evhttp_connection *evcon, evhttp_make_header_request(struct evhttp_connection *evcon,
@ -351,9 +351,45 @@ evhttp_is_connection_keepalive(struct evkeyvalq* headers)
&& strncasecmp(connection, "keep-alive", 10) == 0); && strncasecmp(connection, "keep-alive", 10) == 0);
} }
static void
evhttp_maybe_add_date_header(struct evkeyvalq *headers)
{
if (evhttp_find_header(headers, "Date") == NULL) {
char date[50];
#ifndef WIN32
struct tm cur;
#endif
struct tm *cur_p;
time_t t = time(NULL);
#ifdef WIN32
cur_p = gmtime(&t);
#else
gmtime_r(&t, &cur);
cur_p = &cur;
#endif
if (strftime(date, sizeof(date),
"%a, %d %b %Y %H:%M:%S GMT", cur_p) != 0) {
evhttp_add_header(headers, "Date", date);
}
}
}
static void
evhttp_maybe_add_content_length_header(struct evkeyvalq *headers,
long content_length)
{
if (evhttp_find_header(headers, "Transfer-Encoding") == NULL &&
evhttp_find_header(headers, "Content-Length") == NULL) {
static char len[12]; /* XXX: not thread-safe */
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
*/ */
static void static void
evhttp_make_header_response(struct evhttp_connection *evcon, evhttp_make_header_response(struct evhttp_connection *evcon,
struct evhttp_request *req) struct evhttp_request *req)
@ -364,48 +400,24 @@ evhttp_make_header_response(struct evhttp_connection *evcon,
req->response_code_line); req->response_code_line);
evbuffer_add(evcon->output_buffer, line, strlen(line)); evbuffer_add(evcon->output_buffer, line, strlen(line));
/* Potentially add headers for unidentified content. */ if (req->major == 1 && req->minor == 1) {
if (EVBUFFER_LENGTH(req->output_buffer)) { evhttp_maybe_add_date_header(req->output_headers);
if (evhttp_find_header(req->output_headers,
"Date") == NULL) {
char date[50];
#ifndef WIN32
struct tm cur;
#endif
struct tm *cur_p;
time_t t = time(NULL);
#ifdef WIN32
cur_p = gmtime(&t);
#else
gmtime_r(&t, &cur);
cur_p = &cur;
#endif
if (strftime(date, sizeof(date),
"%a, %d %b %Y %H:%M:%S GMT", cur_p) != 0) {
evhttp_add_header(req->output_headers, "Date", date);
}
}
if (evhttp_find_header(req->output_headers,
"Content-Type") == NULL) {
evhttp_add_header(req->output_headers,
"Content-Type", "text/html; charset=ISO-8859-1");
}
/* /*
* we need to add the content length if the user did * we need to add the content length if the user did
* not give it, this is required for persistent * not give it, this is required for persistent
* connections to work. * connections to work.
*/ */
evhttp_maybe_add_content_length_header(req->output_headers,
(long)EVBUFFER_LENGTH(req->output_buffer));
}
/* Potentially add headers for unidentified content. */
if (EVBUFFER_LENGTH(req->output_buffer)) {
if (evhttp_find_header(req->output_headers, if (evhttp_find_header(req->output_headers,
"Transfer-Encoding") == NULL && "Content-Type") == NULL) {
evhttp_find_header(req->output_headers,
"Content-Length") == NULL) {
static char len[12];
snprintf(len, sizeof(len), "%ld",
(long)EVBUFFER_LENGTH(req->output_buffer));
evhttp_add_header(req->output_headers, evhttp_add_header(req->output_headers,
"Content-Length", len); "Content-Type", "text/html; charset=ISO-8859-1");
} }
} }

View File

@ -198,12 +198,14 @@ http_errorcb(struct bufferevent *bev, short what, void *arg)
void void
http_basic_cb(struct evhttp_request *req, void *arg) http_basic_cb(struct evhttp_request *req, void *arg)
{ {
struct evbuffer *evb = evbuffer_new(); struct evbuffer *evb = evbuffer_new();
int empty = evhttp_find_header(req->input_headers, "Empty") != NULL;
event_debug(("%s: called\n", __func__)); event_debug(("%s: called\n", __func__));
evbuffer_add_printf(evb, "This is funny"); evbuffer_add_printf(evb, "This is funny");
evhttp_send_reply(req, HTTP_OK, "Everything is fine", evb); /* allow sending of an empty reply */
evhttp_send_reply(req, HTTP_OK, "Everything is fine",
!empty ? evb : NULL);
evbuffer_free(evb); evbuffer_free(evb);
} }
@ -251,6 +253,7 @@ http_basic_test(void)
} }
void http_request_done(struct evhttp_request *, void *); void http_request_done(struct evhttp_request *, void *);
void http_request_empty_done(struct evhttp_request *, void *);
void void
http_connection_test(int persistent) http_connection_test(int persistent)
@ -317,6 +320,27 @@ http_connection_test(int persistent)
event_dispatch(); event_dispatch();
/* make another request: request empty reply */
test_ok = 0;
req = evhttp_request_new(http_request_empty_done, NULL);
/* Add the information that we care about */
evhttp_add_header(req->output_headers, "Empty", "itis");
/* We give ownership of the request to the connection */
if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
fprintf(stdout, "FAILED\n");
exit(1);
}
event_dispatch();
if (test_ok != 1) {
fprintf(stdout, "FAILED\n");
exit(1);
}
evhttp_connection_free(evcon); evhttp_connection_free(evcon);
evhttp_free(http); evhttp_free(http);
@ -329,7 +353,6 @@ http_request_done(struct evhttp_request *req, void *arg)
const char *what = "This is funny"; const char *what = "This is funny";
if (req->response_code != HTTP_OK) { if (req->response_code != HTTP_OK) {
fprintf(stderr, "FAILED\n"); fprintf(stderr, "FAILED\n");
exit(1); exit(1);
} }
@ -353,6 +376,42 @@ http_request_done(struct evhttp_request *req, void *arg)
event_loopexit(NULL); event_loopexit(NULL);
} }
/* test date header and content length */
void
http_request_empty_done(struct evhttp_request *req, void *arg)
{
if (req->response_code != HTTP_OK) {
fprintf(stderr, "FAILED\n");
exit(1);
}
if (evhttp_find_header(req->input_headers, "Date") == NULL) {
fprintf(stderr, "FAILED\n");
exit(1);
}
if (evhttp_find_header(req->input_headers, "Content-Length") == NULL) {
fprintf(stderr, "FAILED\n");
exit(1);
}
if (strcmp(evhttp_find_header(req->input_headers, "Content-Length"),
"0")) {
fprintf(stderr, "FAILED\n");
exit(1);
}
if (EVBUFFER_LENGTH(req->input_buffer) != 0) {
fprintf(stderr, "FAILED\n");
exit(1);
}
test_ok = 1;
event_loopexit(NULL);
}
/* /*
* HTTP DISPATCHER test * HTTP DISPATCHER test
*/ */