diff --git a/example_config/example.config b/example_config/example.config index 61f1dd7..77b8d17 100644 --- a/example_config/example.config +++ b/example_config/example.config @@ -36,3 +36,5 @@ Var='''Test var value''' PATH=/inner HTML_FILE='''example_config/inner.html''' VAR_FILE='''example_config/var.html''' + +PATH=/error diff --git a/src/http.c b/src/http.c index c2b3770..e2e39e4 100644 --- a/src/http.c +++ b/src/http.c @@ -32,11 +32,32 @@ #define REQUEST_PATH_BUFFER_SIZE 256 #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" + "

400 Bad Request

\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" + "

404 Not Found

\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" + "

500 Internal Server Error

\n"; + } +} + char *c_simple_http_request_response( const char *request, unsigned int size, 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) { *out_size = 0; } @@ -54,6 +75,9 @@ char *c_simple_http_request_response( request_type[request_type_idx++] = request[idx]; } if (request_type_idx == 0) { + if (out_response_code) { + *out_response_code = C_SIMPLE_HTTP_Response_400_Bad_Request; + } return NULL; } #ifndef NDEBUG @@ -79,6 +103,9 @@ char *c_simple_http_request_response( request_path[request_path_idx++] = request[idx]; } if (request_path_idx == 0) { + if (out_response_code) { + *out_response_code = C_SIMPLE_HTTP_Response_400_Bad_Request; + } return NULL; } #ifndef NDEBUG @@ -104,6 +131,9 @@ char *c_simple_http_request_response( request_proto[request_proto_idx++] = request[idx]; } if (request_proto_idx == 0) { + if (out_response_code) { + *out_response_code = C_SIMPLE_HTTP_Response_400_Bad_Request; + } return NULL; } #ifndef NDEBUG @@ -112,10 +142,14 @@ char *c_simple_http_request_response( if (strcmp(request_type, "GET") != 0) { 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; } size_t generated_size = 0; + __attribute__((cleanup(simple_archiver_helper_cleanup_c_string))) char *stripped_path = c_simple_http_strip_path( request_path, request_path_idx); char *generated_buf = c_simple_http_path_to_generated( @@ -123,19 +157,30 @@ char *c_simple_http_request_response( templates, &generated_size); - if (stripped_path) { - free(stripped_path); - } - if (!generated_buf || generated_size == 0) { fprintf(stderr, "ERROR Unable to generate response html for path \"%s\"!\n", 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; } if (out_size) { *out_size = generated_size; } + if (out_response_code) { + *out_response_code = C_SIMPLE_HTTP_Response_200_OK; + } return generated_buf; } diff --git a/src/http.h b/src/http.h index f1b7b05..115e8e1 100644 --- a/src/http.h +++ b/src/http.h @@ -28,13 +28,26 @@ 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. /// If the request is not valid, or 404, then the buffer will be NULL. char *c_simple_http_request_response( const char *request, unsigned int size, 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. diff --git a/src/main.c b/src/main.c index 1fc4c17..15fdb3c 100644 --- a/src/main.c +++ b/src/main.c @@ -141,12 +141,18 @@ int main(int argc, char **argv) { puts(""); size_t response_size = 0; + enum C_SIMPLE_HTTP_ResponseCode response_code; const char *response = c_simple_http_request_response( - (const char*)recv_buf, (unsigned int)read_ret, &parsed_config, &response_size); - if (response) { + (const char*)recv_buf, + (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, "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]; size_t content_length_buf_size = 0; memcpy(content_length_buf, "Content-Length: ", 16); @@ -166,18 +172,28 @@ int main(int argc, char **argv) { continue; } 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, response, response_size)); free((void*)response); } else { - // TODO handle internal errors also. - 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: 14\n", 19)); - CHECK_ERROR_WRITE(write(connection_fd, "\n404 Not Found\n", 15)); + const char *response = c_simple_http_response_code_error_to_response( + response_code); + size_t response_size = strlen(response); + if (response) { + CHECK_ERROR_WRITE(write(connection_fd, response, response_size)); + } 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

500 Internal Server Error

\n", 36)); + } } close(connection_fd); } else {