2022-11-07 06:21:24 +00:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <limits.h>
|
|
|
|
#include "http_response.h"
|
|
|
|
#include "http_server.h"
|
|
|
|
#include "http_response_cache.h"
|
|
|
|
#include "hw_string.h"
|
|
|
|
|
|
|
|
#define CRLF "\r\n"
|
2022-11-08 02:37:52 +00:00
|
|
|
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;
|
2022-11-07 06:21:24 +00:00
|
|
|
response->number_of_headers = 0;
|
|
|
|
return response;
|
|
|
|
}
|
|
|
|
|
2022-11-08 02:37:52 +00:00
|
|
|
void hw_free_http_response(hw_http_response *response) {
|
|
|
|
http_response *resp = (http_response *)response;
|
2022-11-07 06:21:24 +00:00
|
|
|
free(resp);
|
|
|
|
}
|
|
|
|
|
2022-11-08 02:37:52 +00:00
|
|
|
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;
|
2022-11-07 06:21:24 +00:00
|
|
|
}
|
|
|
|
|
2022-11-08 02:37:52 +00:00
|
|
|
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;
|
2022-11-07 06:21:24 +00:00
|
|
|
}
|
|
|
|
|
2022-11-08 02:37:52 +00:00
|
|
|
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;
|
2022-11-07 06:21:24 +00:00
|
|
|
resp->headers[resp->number_of_headers] = *header;
|
|
|
|
resp->number_of_headers++;
|
|
|
|
}
|
|
|
|
|
2022-11-08 02:37:52 +00:00
|
|
|
void hw_set_body(hw_http_response *response, hw_string *body) {
|
|
|
|
http_response *resp = (http_response *)response;
|
|
|
|
resp->body = *body;
|
2022-11-07 06:21:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int num_chars(int n) {
|
|
|
|
int r = 1;
|
2022-11-08 10:09:54 +00:00
|
|
|
if (n < 0) {
|
2022-11-08 02:37:52 +00:00
|
|
|
n = (n == INT_MIN) ? INT_MAX : -n;
|
2022-11-08 10:09:54 +00:00
|
|
|
}
|
2022-11-07 06:21:24 +00:00
|
|
|
while (n > 9) {
|
|
|
|
n /= 10;
|
|
|
|
r++;
|
|
|
|
}
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2022-11-08 02:37:52 +00:00
|
|
|
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;
|
2022-11-07 06:21:24 +00:00
|
|
|
|
|
|
|
int i = 0;
|
|
|
|
|
|
|
|
char length_header[] = "Content-Length: ";
|
2022-11-08 02:37:52 +00:00
|
|
|
int line_sep_size = sizeof(CRLF);
|
2022-11-07 06:21:24 +00:00
|
|
|
|
2022-11-08 02:37:52 +00:00
|
|
|
int header_buffer_incr = 512;
|
|
|
|
int body_size = resp->body.length;
|
2022-11-07 06:21:24 +00:00
|
|
|
int header_size_remaining = header_buffer_incr;
|
2022-11-08 02:37:52 +00:00
|
|
|
int response_size = header_size_remaining + sizeof(length_header) + num_chars(resp->body.length) + 2 * line_sep_size
|
|
|
|
+ body_size + line_sep_size;
|
2022-11-07 06:21:24 +00:00
|
|
|
|
|
|
|
response_string->value = malloc(response_size);
|
|
|
|
|
|
|
|
response_string->length = 0;
|
|
|
|
append_string(response_string, cached_entry);
|
2022-11-08 02:37:52 +00:00
|
|
|
|
|
|
|
for (i = 0; i < resp->number_of_headers; i++) {
|
2022-11-07 06:21:24 +00:00
|
|
|
http_header header = resp->headers[i];
|
|
|
|
|
|
|
|
header_size_remaining -= header.name.length + 2 + header.value.length + line_sep_size;
|
|
|
|
if (header_size_remaining < 0) {
|
2022-11-08 02:37:52 +00:00
|
|
|
header_size_remaining += header_buffer_incr * ((-header_size_remaining / header_buffer_incr) + 1);
|
2022-11-07 06:21:24 +00:00
|
|
|
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);
|
|
|
|
}
|
2022-11-08 02:37:52 +00:00
|
|
|
|
2022-11-07 06:21:24 +00:00
|
|
|
/* Add the body */
|
|
|
|
APPENDSTRING(response_string, length_header);
|
|
|
|
|
|
|
|
string_from_int(&content_length, body_size, 10);
|
2022-11-08 02:37:52 +00:00
|
|
|
|
2022-11-07 06:21:24 +00:00
|
|
|
if (body_size > 0) {
|
|
|
|
append_string(response_string, &content_length);
|
2022-11-08 02:37:52 +00:00
|
|
|
} else {
|
2022-11-07 06:21:24 +00:00
|
|
|
hw_string zero_content;
|
2022-11-08 02:37:52 +00:00
|
|
|
zero_content.value = "0";
|
2022-11-07 06:21:24 +00:00
|
|
|
zero_content.length = 1;
|
|
|
|
append_string(response_string, &zero_content);
|
|
|
|
}
|
2022-11-08 02:37:52 +00:00
|
|
|
|
2022-11-07 06:21:24 +00:00
|
|
|
APPENDSTRING(response_string, CRLF CRLF);
|
2022-11-08 02:37:52 +00:00
|
|
|
|
|
|
|
if (body_size > 0) {
|
2022-11-07 06:21:24 +00:00
|
|
|
append_string(response_string, &resp->body);
|
|
|
|
}
|
|
|
|
|
|
|
|
return response_string;
|
|
|
|
}
|
|
|
|
|
2022-11-08 02:37:52 +00:00
|
|
|
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);
|
2022-11-07 06:21:24 +00:00
|
|
|
|
|
|
|
write_context->connection = resp->connection;
|
2022-11-08 02:37:52 +00:00
|
|
|
write_context->user_data = user_data;
|
|
|
|
write_context->callback = callback;
|
|
|
|
write_context->request = resp->request;
|
2022-11-07 06:21:24 +00:00
|
|
|
|
|
|
|
http_server_write_response(write_context, response_buffer);
|
|
|
|
resp->sent = 1;
|
|
|
|
|
|
|
|
free(response_buffer);
|
|
|
|
hw_free_http_response(response);
|
|
|
|
}
|
2022-11-08 02:37:52 +00:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|