vcpe/srcs/httpserver/src/haywire/http_response.c

169 lines
5.5 KiB
C

#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"
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);
}