From: Felix Nawothnig Date: Wed, 26 May 2010 16:50:59 +0000 (-0400) Subject: Fix the default HTTP error template X-Git-Tag: release-2.0.6-rc~53 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=06bd05634d2f1d098b81859c7b7309a5a4b4a746;p=libevent Fix the default HTTP error template The current template... %s

Method Not Implemented

Invalid method in request

is highly confusing. The given title is easily overlooked and the hard-coded content is just plain wrong in most cases (I really read this as "the server did not understand the requested HTTP method) This patch changes the template to include the error reason in the body as well as in the header, and to infer the proper reason from the status code whenever the reason argument is NULL. This patch also removes a redundant evhttp_add_header from evhttp_send_error; evhttp_send_page already adds a "Connection: close" header. --- diff --git a/http.c b/http.c index c4fb09c5..71850bb8 100644 --- a/http.c +++ b/http.c @@ -171,6 +171,7 @@ static void evhttp_read_header(struct evhttp_connection *evcon, struct evhttp_request *req); static int evhttp_add_header_internal(struct evkeyvalq *headers, const char *key, const char *value); +static const char *evhttp_response_phrase_internal(int code); /* callbacks for bufferevent */ static void evhttp_read_cb(struct bufferevent *, void *); @@ -2030,11 +2031,11 @@ evhttp_send_done(struct evhttp_connection *evcon, void *arg) void evhttp_send_error(struct evhttp_request *req, int error, const char *reason) { + #define ERR_FORMAT "\n" \ "%d %s\n" \ "\n" \ - "

Method Not Implemented

\n" \ - "Invalid method in request

\n" \ + "

%s

\n" \ "\n" struct evbuffer *buf = evbuffer_new(); @@ -2043,13 +2044,13 @@ evhttp_send_error(struct evhttp_request *req, int error, const char *reason) evhttp_connection_free(req->evcon); return; } - - /* close the connection on error */ - evhttp_add_header(req->output_headers, "Connection", "close"); + if (reason == NULL) { + reason = evhttp_response_phrase_internal(error); + } evhttp_response_code(req, error, reason); - evbuffer_add_printf(buf, ERR_FORMAT, error, reason); + evbuffer_add_printf(buf, ERR_FORMAT, error, reason, reason); evhttp_send_page(req, buf); @@ -2168,6 +2169,96 @@ evhttp_send_reply_end(struct evhttp_request *req) } } +static const char *informational_phrases[] = { + /* 100 */ "Continue", + /* 101 */ "Switching Protocols" +}; + +static const char *success_phrases[] = { + /* 200 */ "OK", + /* 201 */ "Created", + /* 202 */ "Accepted", + /* 203 */ "Non-Authoritative Information", + /* 204 */ "No Content", + /* 205 */ "Reset Content", + /* 206 */ "Partial Content" +}; + +static const char *redirection_phrases[] = { + /* 300 */ "Multiple Choices", + /* 301 */ "Moved Permanently", + /* 302 */ "Found", + /* 303 */ "See Other", + /* 304 */ "Not Modified", + /* 305 */ "Use Proxy", + /* 307 */ "Temporary Redirect" +}; + +static const char *client_error_phrases[] = { + /* 400 */ "Bad Request", + /* 401 */ "Unauthorized", + /* 402 */ "Payment Required", + /* 403 */ "Forbidden", + /* 404 */ "Not Found", + /* 405 */ "Method Not Allowed", + /* 406 */ "Not Acceptable", + /* 407 */ "Proxy Authentication Required", + /* 408 */ "Request Time-out", + /* 409 */ "Conflict", + /* 410 */ "Gone", + /* 411 */ "Length Required", + /* 412 */ "Precondition Failed", + /* 413 */ "Request Entity Too Large", + /* 414 */ "Request-URI Too Large", + /* 415 */ "Unsupported Media Type", + /* 416 */ "Requested range not satisfiable", + /* 417 */ "Expectation Failed" +}; + +static const char *server_error_phrases[] = { + /* 500 */ "Internal Server Error", + /* 501 */ "Not Implemented", + /* 502 */ "Bad Gateway", + /* 503 */ "Service Unavailable", + /* 504 */ "Gateway Time-out", + /* 505 */ "HTTP Version not supported" +}; + +struct response_class { + const char *name; + size_t num_responses; + const char **responses; +}; + +#ifndef MEMBERSOF +#define MEMBERSOF(x) (sizeof(x)/sizeof(x[0])) +#endif + +static const struct response_class response_classes[] = { + /* 1xx */ { "Informational", MEMBERSOF(informational_phrases), informational_phrases }, + /* 2xx */ { "Success", MEMBERSOF(success_phrases), success_phrases }, + /* 3xx */ { "Redirection", MEMBERSOF(redirection_phrases), redirection_phrases }, + /* 4xx */ { "Client Error", MEMBERSOF(client_error_phrases), client_error_phrases }, + /* 5xx */ { "Server Error", MEMBERSOF(server_error_phrases), server_error_phrases } +}; + +static const char * +evhttp_response_phrase_internal(int code) +{ + int klass = code / 100 - 1; + int subcode = code % 100; + + /* Unknown class - can't do any better here */ + if (klass < 0 || klass >= MEMBERSOF(response_classes)) + return "Unknown Status Class"; + + /* Unknown sub-code, return class name at least */ + if (subcode >= response_classes[klass].num_responses) + return response_classes[klass].name; + + return response_classes[klass].responses[subcode]; +} + void evhttp_response_code(struct evhttp_request *req, int code, const char *reason) { @@ -2175,6 +2266,8 @@ evhttp_response_code(struct evhttp_request *req, int code, const char *reason) req->response_code = code; if (req->response_code_line != NULL) mm_free(req->response_code_line); + if (reason == NULL) + reason = evhttp_response_phrase_internal(code); req->response_code_line = mm_strdup(reason); } diff --git a/include/event2/http.h b/include/event2/http.h index b4176bf5..cab068a5 100644 --- a/include/event2/http.h +++ b/include/event2/http.h @@ -249,7 +249,8 @@ void evhttp_set_timeout(struct evhttp *http, int timeout_in_secs); * * @param req a request object * @param error the HTTP error code - * @param reason a brief explanation of the error + * @param reason a brief explanation of the error. If this is NULL, we'll + * just use the standard meaning of the error code. */ void evhttp_send_error(struct evhttp_request *req, int error, const char *reason);