#include #include #include #include #include "http_response.h" #include "http_server.h" #include "http_response_cache.h" #include "hw_string.h" #define CRLF "\r\n" KHASH_MAP_INIT_STR(string_hashmap, char *) hw_http_response hw_create_http_response(http_connection *connection) { http_response *response = malloc(sizeof(http_response)); response->connection = connection; response->request = connection->request; response->http_major = 1; response->http_minor = 1; response->body.value = NULL; response->body.length = 0; response->number_of_headers = 0; return response; } void hw_free_http_response(hw_http_response *response) { http_response *resp = (http_response *)response; free(resp); } void hw_set_http_version(hw_http_response *response, unsigned short major, unsigned short minor) { http_response *resp = (http_response *)response; resp->http_major = major; resp->http_minor = minor; } void hw_set_response_status_code(hw_http_response *response, hw_string *status_code) { http_response *resp = (http_response *)response; resp->status_code = *status_code; } void hw_set_response_header(hw_http_response *response, hw_string *name, hw_string *value) { http_response *resp = (http_response *)response; http_header *header = &resp->headers[resp->number_of_headers]; header->name = *name; header->value = *value; resp->headers[resp->number_of_headers] = *header; resp->number_of_headers++; } void hw_set_body(hw_http_response *response, hw_string *body) { http_response *resp = (http_response *)response; resp->body = *body; } int num_chars(int n) { int r = 1; if (n < 0) { n = (n == INT_MIN) ? INT_MAX : -n; } while (n > 9) { n /= 10; r++; } return r; } hw_string *create_response_buffer(hw_http_response *response) { http_response *resp = (http_response *)response; hw_string *response_string = malloc(sizeof(hw_string)); hw_string *cached_entry = get_cached_request(resp->status_code.value); hw_string content_length; int i = 0; char length_header[] = "Content-Length: "; int line_sep_size = sizeof(CRLF); int header_buffer_incr = 512; int body_size = resp->body.length; int header_size_remaining = header_buffer_incr; int response_size = header_size_remaining + sizeof(length_header) + num_chars(resp->body.length) + 2 * line_sep_size + body_size + line_sep_size; response_string->value = malloc(response_size); response_string->length = 0; append_string(response_string, cached_entry); for (i = 0; i < resp->number_of_headers; i++) { http_header header = resp->headers[i]; header_size_remaining -= header.name.length + 2 + header.value.length + line_sep_size; if (header_size_remaining < 0) { header_size_remaining += header_buffer_incr * ((-header_size_remaining / header_buffer_incr) + 1); response_size += header_size_remaining; response_string->value = realloc(response_string->value, response_size); } append_string(response_string, &header.name); APPENDSTRING(response_string, ": "); append_string(response_string, &header.value); APPENDSTRING(response_string, CRLF); } /* Add the body */ APPENDSTRING(response_string, length_header); string_from_int(&content_length, body_size, 10); if (body_size > 0) { append_string(response_string, &content_length); } else { hw_string zero_content; zero_content.value = "0"; zero_content.length = 1; append_string(response_string, &zero_content); } APPENDSTRING(response_string, CRLF CRLF); if (body_size > 0) { append_string(response_string, &resp->body); } return response_string; } void hw_http_response_send(hw_http_response *response, void *user_data, http_response_complete_callback callback) { hw_write_context *write_context = malloc(sizeof(hw_write_context)); http_response *resp = (http_response *)response; hw_string *response_buffer = create_response_buffer(response); write_context->connection = resp->connection; write_context->user_data = user_data; write_context->callback = callback; write_context->request = resp->request; http_server_write_response(write_context, response_buffer); resp->sent = 1; free(response_buffer); hw_free_http_response(response); } void hw_http_response_send_error(hw_http_response *response, const char *error, const char *err_msg) { hw_string status_code; hw_string content_type_name; hw_string content_type_value; hw_string body; hw_string keep_alive_name; hw_string keep_alive_value; SETSTRING(content_type_name, "Content-Type"); SETSTRING(content_type_value, "text/html"); hw_set_response_header(response, &content_type_name, &content_type_value); SETSTRING(status_code, error); SETSTRING(body, err_msg); hw_set_body(response, &body); hw_set_response_status_code(response, &status_code); SETSTRING(keep_alive_name, "Connection"); SETSTRING(keep_alive_value, "close"); hw_set_response_header(response, &keep_alive_name, &keep_alive_value); hw_http_response_send(response, NULL, NULL); }