diff --git a/src/response.c b/src/response.c index 179102d..201ccbd 100644 --- a/src/response.c +++ b/src/response.c @@ -33,7 +33,8 @@ void response_send_headers(connection *con) { if (0 == con->out->length && con->content_handler == NULL && con->response.http_status >= 400 && con->response.http_status < 600) { - chunkqueue_append_mem(con->out, CONST_STR_LEN("Custom error\r\n")); + /*chunkqueue_append_mem(con->out, CONST_STR_LEN("Custom error\r\n"));*/ + response_send_error_page(con); } if (con->content_handler == NULL) { @@ -76,7 +77,17 @@ void response_send_headers(connection *con) { if (con->keep_alive) http_header_overwrite(con->response.headers, CONST_STR_LEN("Connection"), CONST_STR_LEN("keep-alive")); } - g_string_append_printf(head, "%i %s\r\n", con->response.http_status, http_status_string(con->response.http_status)); + + { + guint len; + gchar status_str[4]; + gchar *str = http_status_string(con->response.http_status, &len); + http_status_to_str(con->response.http_status, status_str); + status_str[3] = ' '; + g_string_append_len(head, status_str, 4); + g_string_append_len(head, str, len); + g_string_append_len(head, CONST_STR_LEN("\r\n")); + } /* Append headers */ { @@ -114,3 +125,45 @@ void response_send_headers(connection *con) { g_string_append_len(head, CONST_STR_LEN("\r\n")); chunkqueue_append_string(con->raw_out, head); } + + +void response_send_error_page(connection *con) { + gchar status_str[3]; + guint len; + gchar *str; + + chunkqueue_append_mem(con->out, CONST_STR_LEN( + "\n" + "\n" + "\n" + " \n" + " " + )); + + http_status_to_str(con->response.http_status, status_str); + + chunkqueue_append_mem(con->out, status_str, 3); + chunkqueue_append_mem(con->out, CONST_STR_LEN(" - ")); + str = http_status_string(con->response.http_status, &len); + chunkqueue_append_mem(con->out, str, len); + + chunkqueue_append_mem(con->out, CONST_STR_LEN( + "\n" + " \n" + " \n" + "

" + )); + + chunkqueue_append_mem(con->out, status_str, 3); + chunkqueue_append_mem(con->out, CONST_STR_LEN(" - ")); + chunkqueue_append_mem(con->out, str, len); + + chunkqueue_append_mem(con->out, CONST_STR_LEN( + "

\n" + " \n" + "\n" + )); + + g_printerr("%u\n", len); +} diff --git a/src/response.h b/src/response.h index 4f0960c..0e0a232 100644 --- a/src/response.h +++ b/src/response.h @@ -17,5 +17,6 @@ LI_API void response_reset(response *resp); LI_API void response_clear(response *resp); LI_API void response_send_headers(connection *con); +LI_API void response_send_error_page(connection *con); #endif diff --git a/src/utils.c b/src/utils.c index a8e4e95..e3980b1 100644 --- a/src/utils.c +++ b/src/utils.c @@ -171,73 +171,92 @@ void path_simplify(GString *path) { g_string_set_size(path, out - start); } - -gchar *http_status_string(guint status_code) { +#define SET_LEN_AND_RETURN_STR(x) \ + do { \ + *len = sizeof(x) - 1; \ + return x; \ + } while(0) +gchar *http_status_string(guint status_code, guint *len) { /* RFC 2616 (as well as RFC 2518, RFC 2817, RFC 2295, RFC 2774, RFC 4918) */ switch (status_code) { /* 1XX information */ - case 100: return "Continue"; - case 101: return "Switching Protocols"; - case 102: return "Processing"; + case 100: SET_LEN_AND_RETURN_STR("Continue"); + case 101: SET_LEN_AND_RETURN_STR("Switching Protocols"); + case 102: SET_LEN_AND_RETURN_STR("Processing"); /* 2XX successful operation */ - case 200: return "OK"; - case 201: return "Created"; - case 202: return "Accepted"; - case 203: return "Non-Authoritative Information"; - case 204: return "No Content"; - case 205: return "Reset Content"; - case 206: return "Partial Content"; - case 207: return "Multi-Status"; + case 200: SET_LEN_AND_RETURN_STR("OK"); + case 201: SET_LEN_AND_RETURN_STR("Created"); + case 202: SET_LEN_AND_RETURN_STR("Accepted"); + case 203: SET_LEN_AND_RETURN_STR("Non-Authoritative Information"); + case 204: SET_LEN_AND_RETURN_STR("No Content"); + case 205: SET_LEN_AND_RETURN_STR("Reset Content"); + case 206: SET_LEN_AND_RETURN_STR("Partial Content"); + case 207: SET_LEN_AND_RETURN_STR("Multi-Status"); /* 3XX redirect */ - case 300: return "Multiple Choice"; - case 301: return "Moved Permanently"; - case 302: return "Found"; - case 303: return "See Other"; - case 304: return "Not Modified"; - case 305: return "Use Proxy"; - case 306: return "(reserved)"; - case 307: return "Temporary Redirect"; + case 300: SET_LEN_AND_RETURN_STR("Multiple Choice"); + case 301: SET_LEN_AND_RETURN_STR("Moved Permanently"); + case 302: SET_LEN_AND_RETURN_STR("Found"); + case 303: SET_LEN_AND_RETURN_STR("See Other"); + case 304: SET_LEN_AND_RETURN_STR("Not Modified"); + case 305: SET_LEN_AND_RETURN_STR("Use Proxy"); + case 306: SET_LEN_AND_RETURN_STR("(reserved)"); + case 307: SET_LEN_AND_RETURN_STR("Temporary Redirect"); /* 4XX client error */ - case 400: return "Bad Request"; - case 401: return "Unauthorized"; - case 402: return "Payment Required"; - case 403: return "Forbidden"; - case 404: return "Not Found"; - case 405: return "Method Not Allowed"; - case 406: return "Not Acceptable"; - case 407: return "Proxy Authentication Required"; - case 408: return "Request Time-out"; - case 409: return "Conflict"; - case 410: return "Gone"; - case 411: return "Length Required"; - case 412: return "Precondition Failed"; - case 413: return "Request Entity Too Large"; - case 414: return "Request-URI Too Long"; - case 415: return "Unsupported Media Type"; - case 416: return "Request range not satisfiable"; - case 417: return "Expectation Failed"; - case 421: return "There are too many connections from your internet address"; - case 422: return "Unprocessable Entity"; - case 423: return "Locked"; - case 424: return "Failed Dependency"; - case 425: return "Unordered Collection"; - case 426: return "Upgrade Required"; + case 400: SET_LEN_AND_RETURN_STR("Bad Request"); + case 401: SET_LEN_AND_RETURN_STR("Unauthorized"); + case 402: SET_LEN_AND_RETURN_STR("Payment Required"); + case 403: SET_LEN_AND_RETURN_STR("Forbidden"); + case 404: SET_LEN_AND_RETURN_STR("Not Found"); + case 405: SET_LEN_AND_RETURN_STR("Method Not Allowed"); + case 406: SET_LEN_AND_RETURN_STR("Not Acceptable"); + case 407: SET_LEN_AND_RETURN_STR("Proxy Authentication Required"); + case 408: SET_LEN_AND_RETURN_STR("Request Time-out"); + case 409: SET_LEN_AND_RETURN_STR("Conflict"); + case 410: SET_LEN_AND_RETURN_STR("Gone"); + case 411: SET_LEN_AND_RETURN_STR("Length Required"); + case 412: SET_LEN_AND_RETURN_STR("Precondition Failed"); + case 413: SET_LEN_AND_RETURN_STR("Request Entity Too Large"); + case 414: SET_LEN_AND_RETURN_STR("Request-URI Too Long"); + case 415: SET_LEN_AND_RETURN_STR("Unsupported Media Type"); + case 416: SET_LEN_AND_RETURN_STR("Request range not satisfiable"); + case 417: SET_LEN_AND_RETURN_STR("Expectation Failed"); + case 421: SET_LEN_AND_RETURN_STR("There are too many connections from your internet address"); + case 422: SET_LEN_AND_RETURN_STR("Unprocessable Entity"); + case 423: SET_LEN_AND_RETURN_STR("Locked"); + case 424: SET_LEN_AND_RETURN_STR("Failed Dependency"); + case 425: SET_LEN_AND_RETURN_STR("Unordered Collection"); + case 426: SET_LEN_AND_RETURN_STR("Upgrade Required"); /* 5XX server error */ - case 500: return "Internal Server Error"; - case 501: return "Not Implemented"; - case 502: return "Bad Gateway"; - case 503: return "Service Unavailable"; - case 504: return "Gateway Time-out"; - case 505: return "HTTP Version not supported"; - case 506: return "Variant Also Negotiates"; - case 507: return "Insufficient Storage"; - case 509: return "Bandwidth Limit Exceeded"; - case 510: return "Not Extended"; + case 500: SET_LEN_AND_RETURN_STR("Internal Server Error"); + case 501: SET_LEN_AND_RETURN_STR("Not Implemented"); + case 502: SET_LEN_AND_RETURN_STR("Bad Gateway"); + case 503: SET_LEN_AND_RETURN_STR("Service Unavailable"); + case 504: SET_LEN_AND_RETURN_STR("Gateway Time-out"); + case 505: SET_LEN_AND_RETURN_STR("HTTP Version not supported"); + case 506: SET_LEN_AND_RETURN_STR("Variant Also Negotiates"); + case 507: SET_LEN_AND_RETURN_STR("Insufficient Storage"); + case 509: SET_LEN_AND_RETURN_STR("Bandwidth Limit Exceeded"); + case 510: SET_LEN_AND_RETURN_STR("Not Extended"); /* unknown */ - default: return "unknown status"; + default: SET_LEN_AND_RETURN_STR("unknown status"); } } +#undef SET_LEN_AND_RETURN_STR + +void http_status_to_str(gint status_code, gchar status_str[]) { + gint status_int; + + status_int = status_code; + status_str[0] = status_int / 100; + status_int -= 100 * status_str[0]; + status_str[1] = status_int / 10; + status_int -= 10 * status_str[1]; + status_str[2] = status_int; + status_str[0] += '0'; + status_str[1] += '0'; + status_str[2] += '0'; +} gchar counter_format(guint64 *count, guint factor) { diff --git a/src/utils.h b/src/utils.h index 2c71dbb..90312c4 100644 --- a/src/utils.h +++ b/src/utils.h @@ -17,7 +17,10 @@ LI_API void url_decode(GString *path); LI_API void path_simplify(GString *path); -LI_API gchar *http_status_string(guint status_code); +/* returns the description for a given http status code and sets the len to the length of the returned string */ +LI_API gchar *http_status_string(guint status_code, guint *len); +/* converts a given 3 digit http status code to a gchar[3] string. e.g. 403 to {'4','0','3'} */ +LI_API void http_status_to_str(gint status_code, gchar status_str[]); /* */ LI_API gchar counter_format(guint64 *count, guint factor);