Add support for different error responses

This commit is contained in:
Stephen Seo 2024-09-06 15:55:21 +09:00
parent 42d97e03b3
commit c194555527
4 changed files with 92 additions and 16 deletions

View file

@ -36,3 +36,5 @@ Var='''Test var value'''
PATH=/inner PATH=/inner
HTML_FILE='''example_config/inner.html''' HTML_FILE='''example_config/inner.html'''
VAR_FILE='''example_config/var.html''' VAR_FILE='''example_config/var.html'''
PATH=/error

View file

@ -32,11 +32,32 @@
#define REQUEST_PATH_BUFFER_SIZE 256 #define REQUEST_PATH_BUFFER_SIZE 256
#define REQUEST_PROTO_BUFFER_SIZE 16 #define REQUEST_PROTO_BUFFER_SIZE 16
const char *c_simple_http_response_code_error_to_response(
enum C_SIMPLE_HTTP_ResponseCode response_code) {
switch (response_code) {
case C_SIMPLE_HTTP_Response_400_Bad_Request:
return "HTTP/1.1 400 Bad Request\nAllow: GET\nContent-Type: text/html\n"
"Content-Length: 25\n\n"
"<h1>400 Bad Request</h1>\n";
case C_SIMPLE_HTTP_Response_404_Not_Found:
return "HTTP/1.1 404 Not Found\nAllow: GET\nContent-Type: text/html\n"
"Content-Length: 23\n\n"
"<h1>404 Not Found</h1>\n";
case C_SIMPLE_HTTP_Response_500_Internal_Server_Error:
default:
return "HTTP/1.1 500 Internal Server Error\nAllow: GET\n"
"Content-Type: text/html\n"
"Content-Length: 35\n\n"
"<h1>500 Internal Server Error</h1>\n";
}
}
char *c_simple_http_request_response( char *c_simple_http_request_response(
const char *request, const char *request,
unsigned int size, unsigned int size,
const C_SIMPLE_HTTP_HTTPTemplates *templates, const C_SIMPLE_HTTP_HTTPTemplates *templates,
size_t *out_size) { size_t *out_size,
enum C_SIMPLE_HTTP_ResponseCode *out_response_code) {
if (out_size) { if (out_size) {
*out_size = 0; *out_size = 0;
} }
@ -54,6 +75,9 @@ char *c_simple_http_request_response(
request_type[request_type_idx++] = request[idx]; request_type[request_type_idx++] = request[idx];
} }
if (request_type_idx == 0) { if (request_type_idx == 0) {
if (out_response_code) {
*out_response_code = C_SIMPLE_HTTP_Response_400_Bad_Request;
}
return NULL; return NULL;
} }
#ifndef NDEBUG #ifndef NDEBUG
@ -79,6 +103,9 @@ char *c_simple_http_request_response(
request_path[request_path_idx++] = request[idx]; request_path[request_path_idx++] = request[idx];
} }
if (request_path_idx == 0) { if (request_path_idx == 0) {
if (out_response_code) {
*out_response_code = C_SIMPLE_HTTP_Response_400_Bad_Request;
}
return NULL; return NULL;
} }
#ifndef NDEBUG #ifndef NDEBUG
@ -104,6 +131,9 @@ char *c_simple_http_request_response(
request_proto[request_proto_idx++] = request[idx]; request_proto[request_proto_idx++] = request[idx];
} }
if (request_proto_idx == 0) { if (request_proto_idx == 0) {
if (out_response_code) {
*out_response_code = C_SIMPLE_HTTP_Response_400_Bad_Request;
}
return NULL; return NULL;
} }
#ifndef NDEBUG #ifndef NDEBUG
@ -112,10 +142,14 @@ char *c_simple_http_request_response(
if (strcmp(request_type, "GET") != 0) { if (strcmp(request_type, "GET") != 0) {
fprintf(stderr, "ERROR Only GET requests are allowed!\n"); fprintf(stderr, "ERROR Only GET requests are allowed!\n");
if (out_response_code) {
*out_response_code = C_SIMPLE_HTTP_Response_400_Bad_Request;
}
return NULL; return NULL;
} }
size_t generated_size = 0; size_t generated_size = 0;
__attribute__((cleanup(simple_archiver_helper_cleanup_c_string)))
char *stripped_path = c_simple_http_strip_path( char *stripped_path = c_simple_http_strip_path(
request_path, request_path_idx); request_path, request_path_idx);
char *generated_buf = c_simple_http_path_to_generated( char *generated_buf = c_simple_http_path_to_generated(
@ -123,19 +157,30 @@ char *c_simple_http_request_response(
templates, templates,
&generated_size); &generated_size);
if (stripped_path) {
free(stripped_path);
}
if (!generated_buf || generated_size == 0) { if (!generated_buf || generated_size == 0) {
fprintf(stderr, "ERROR Unable to generate response html for path \"%s\"!\n", fprintf(stderr, "ERROR Unable to generate response html for path \"%s\"!\n",
request_path); request_path);
if (out_response_code) {
if (
simple_archiver_hash_map_get(
templates->hash_map,
stripped_path ? stripped_path : request_path,
stripped_path ? strlen(stripped_path) + 1 : request_path_idx + 1)
== NULL) {
*out_response_code = C_SIMPLE_HTTP_Response_404_Not_Found;
} else {
*out_response_code = C_SIMPLE_HTTP_Response_500_Internal_Server_Error;
}
}
return NULL; return NULL;
} }
if (out_size) { if (out_size) {
*out_size = generated_size; *out_size = generated_size;
} }
if (out_response_code) {
*out_response_code = C_SIMPLE_HTTP_Response_200_OK;
}
return generated_buf; return generated_buf;
} }

View file

@ -28,13 +28,26 @@
typedef C_SIMPLE_HTTP_ParsedConfig C_SIMPLE_HTTP_HTTPTemplates; typedef C_SIMPLE_HTTP_ParsedConfig C_SIMPLE_HTTP_HTTPTemplates;
enum C_SIMPLE_HTTP_ResponseCode {
C_SIMPLE_HTTP_Response_200_OK,
C_SIMPLE_HTTP_Response_400_Bad_Request,
C_SIMPLE_HTTP_Response_404_Not_Found,
C_SIMPLE_HTTP_Response_500_Internal_Server_Error,
};
// If the response code is an error, returns a full response string that doesn't
// need to be free'd. Otherwise, returns as if error 500.
const char *c_simple_http_response_code_error_to_response(
enum C_SIMPLE_HTTP_ResponseCode response_code);
/// Returned buffer must be "free"d after use. /// Returned buffer must be "free"d after use.
/// If the request is not valid, or 404, then the buffer will be NULL. /// If the request is not valid, or 404, then the buffer will be NULL.
char *c_simple_http_request_response( char *c_simple_http_request_response(
const char *request, const char *request,
unsigned int size, unsigned int size,
const C_SIMPLE_HTTP_HTTPTemplates *templates, const C_SIMPLE_HTTP_HTTPTemplates *templates,
size_t *out_size size_t *out_size,
enum C_SIMPLE_HTTP_ResponseCode *out_response_code
); );
/// Takes a PATH string and returns a "bare" path. /// Takes a PATH string and returns a "bare" path.

View file

@ -141,12 +141,18 @@ int main(int argc, char **argv) {
puts(""); puts("");
size_t response_size = 0; size_t response_size = 0;
enum C_SIMPLE_HTTP_ResponseCode response_code;
const char *response = c_simple_http_request_response( const char *response = c_simple_http_request_response(
(const char*)recv_buf, (unsigned int)read_ret, &parsed_config, &response_size); (const char*)recv_buf,
if (response) { (unsigned int)read_ret,
&parsed_config,
&response_size,
&response_code);
if (response && response_code == C_SIMPLE_HTTP_Response_200_OK) {
CHECK_ERROR_WRITE(write(connection_fd, "HTTP/1.1 200 OK\n", 16)); CHECK_ERROR_WRITE(write(connection_fd, "HTTP/1.1 200 OK\n", 16));
CHECK_ERROR_WRITE(write(connection_fd, "Allow: GET\n", 11)); CHECK_ERROR_WRITE(write(connection_fd, "Allow: GET\n", 11));
CHECK_ERROR_WRITE(write(connection_fd, "Content-Type: text/html\n", 24)); CHECK_ERROR_WRITE(write(
connection_fd, "Content-Type: text/html\n", 24));
char content_length_buf[128]; char content_length_buf[128];
size_t content_length_buf_size = 0; size_t content_length_buf_size = 0;
memcpy(content_length_buf, "Content-Length: ", 16); memcpy(content_length_buf, "Content-Length: ", 16);
@ -166,18 +172,28 @@ int main(int argc, char **argv) {
continue; continue;
} }
content_length_buf_size += (size_t)written; content_length_buf_size += (size_t)written;
CHECK_ERROR_WRITE(write(connection_fd, content_length_buf, content_length_buf_size)); CHECK_ERROR_WRITE(write(
connection_fd, content_length_buf, content_length_buf_size));
CHECK_ERROR_WRITE(write(connection_fd, "\n", 1)); CHECK_ERROR_WRITE(write(connection_fd, "\n", 1));
CHECK_ERROR_WRITE(write(connection_fd, response, response_size)); CHECK_ERROR_WRITE(write(connection_fd, response, response_size));
free((void*)response); free((void*)response);
} else { } else {
// TODO handle internal errors also. const char *response = c_simple_http_response_code_error_to_response(
CHECK_ERROR_WRITE(write(connection_fd, "HTTP/1.1 404 Not Found\n", 23)); response_code);
CHECK_ERROR_WRITE(write(connection_fd, "Allow: GET\n", 11)); size_t response_size = strlen(response);
CHECK_ERROR_WRITE(write(connection_fd, "Content-Type: text/html\n", 24)); if (response) {
CHECK_ERROR_WRITE(write(connection_fd, "Content-Length: 14\n", 19)); CHECK_ERROR_WRITE(write(connection_fd, response, response_size));
CHECK_ERROR_WRITE(write(connection_fd, "\n404 Not Found\n", 15)); } else {
CHECK_ERROR_WRITE(write(
connection_fd, "HTTP/1.1 404 Not Found\n", 23));
CHECK_ERROR_WRITE(write(connection_fd, "Allow: GET\n", 11));
CHECK_ERROR_WRITE(write(
connection_fd, "Content-Type: text/html\n", 24));
CHECK_ERROR_WRITE(write(connection_fd, "Content-Length: 35\n", 19));
CHECK_ERROR_WRITE(write(
connection_fd, "\n<h1>500 Internal Server Error</h1>\n", 36));
}
} }
close(connection_fd); close(connection_fd);
} else { } else {