Impl. handling HTTP/1.1 requests

TODO:
    Handle errors other than 404 Not Found.
This commit is contained in:
Stephen Seo 2024-09-06 11:53:28 +09:00
parent 3f70c52551
commit 9be6ac32bf
6 changed files with 91 additions and 7 deletions

View file

@ -0,0 +1,6 @@
PATH=/
HTML='''Test HTML
{{{Var}}}
'''
Var='''Test var value'''

View file

@ -24,6 +24,7 @@
void print_usage(void) { void print_usage(void) {
puts("Usage:"); puts("Usage:");
puts(" -p <port> | --port <port>"); puts(" -p <port> | --port <port>");
puts(" --config=<config_file>");
} }
Args parse_args(int argc, char **argv) { Args parse_args(int argc, char **argv) {
@ -42,6 +43,8 @@ Args parse_args(int argc, char **argv) {
} }
--argc; --argc;
++argv; ++argv;
} else if (strncmp(argv[0], "--config=", 9) == 0 && strlen(argv[0]) > 9) {
args.config_file = argv[0] + 9;
} else { } else {
puts("ERROR: Invalid args!\n"); puts("ERROR: Invalid args!\n");
print_usage(); print_usage();

View file

@ -20,6 +20,8 @@
typedef struct Args { typedef struct Args {
unsigned short flags; unsigned short flags;
unsigned short port; unsigned short port;
// Does not need to be free'd, this should point to a string in argv.
const char *config_file;
} Args; } Args;
void print_usage(void); void print_usage(void);

View file

@ -21,8 +21,12 @@
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
// Third party includes.
#include <SimpleArchiver/src/helpers.h>
// Local includes // Local includes
#include "constants.h" #include "constants.h"
#include "http_template.h"
#define REQUEST_TYPE_BUFFER_SIZE 16 #define REQUEST_TYPE_BUFFER_SIZE 16
#define REQUEST_PATH_BUFFER_SIZE 256 #define REQUEST_PATH_BUFFER_SIZE 256
@ -31,7 +35,11 @@
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) {
if (out_size) {
*out_size = 0;
}
// parse first line. // parse first line.
unsigned int idx = 0; unsigned int idx = 0;
char request_type[REQUEST_TYPE_BUFFER_SIZE] = {0}; char request_type[REQUEST_TYPE_BUFFER_SIZE] = {0};
@ -102,8 +110,26 @@ char *c_simple_http_request_response(
fprintf(stderr, "Parsing request: got http protocol \"%s\"\n", request_proto); fprintf(stderr, "Parsing request: got http protocol \"%s\"\n", request_proto);
#endif #endif
// TODO if (strcmp(request_type, "GET") != 0) {
return NULL; fprintf(stderr, "ERROR Only GET requests are allowed!\n");
return NULL;
}
size_t generated_size = 0;
char *generated_buf = c_simple_http_path_to_generated(
request_path,
templates,
&generated_size);
if (!generated_buf || generated_size == 0) {
fprintf(stderr, "ERROR Unable to generate response html for path \"%s\"!\n",
request_path);
return NULL;
}
if (out_size) {
*out_size = generated_size;
}
return generated_buf;
} }
// vim: ts=2 sts=2 sw=2 // vim: ts=2 sts=2 sw=2

View file

@ -17,6 +17,9 @@
#ifndef SEODISPARATE_COM_C_SIMPLE_HTTP_HTTP_H_ #ifndef SEODISPARATE_COM_C_SIMPLE_HTTP_HTTP_H_
#define SEODISPARATE_COM_C_SIMPLE_HTTP_HTTP_H_ #define SEODISPARATE_COM_C_SIMPLE_HTTP_HTTP_H_
// Standard library includes.
#include <stddef.h>
// Third party includes. // Third party includes.
#include <SimpleArchiver/src/data_structures/hash_map.h> #include <SimpleArchiver/src/data_structures/hash_map.h>
@ -30,7 +33,8 @@ typedef C_SIMPLE_HTTP_ParsedConfig C_SIMPLE_HTTP_HTTPTemplates;
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
); );
#endif #endif

View file

@ -27,6 +27,9 @@
#include <time.h> #include <time.h>
#include <errno.h> #include <errno.h>
// Third party includes.
#include <SimpleArchiver/src/helpers.h>
// Local includes. // Local includes.
#include "arg_parse.h" #include "arg_parse.h"
#include "big_endian.h" #include "big_endian.h"
@ -39,7 +42,21 @@
int main(int argc, char **argv) { int main(int argc, char **argv) {
Args args = parse_args(argc, argv); Args args = parse_args(argc, argv);
if (!args.config_file) {
fprintf(stderr, "ERROR Config file not specified!\n");
print_usage();
return 2;
}
printf("%u\n", args.port); printf("%u\n", args.port);
printf("config file is: %s\n", args.config_file);
__attribute__((cleanup(c_simple_http_clean_up_parsed_config)))
C_SIMPLE_HTTP_ParsedConfig parsed_config = c_simple_http_parse_config(
args.config_file,
"PATH",
NULL
);
__attribute__((cleanup(cleanup_tcp_socket))) int tcp_socket = __attribute__((cleanup(cleanup_tcp_socket))) int tcp_socket =
create_tcp_socket(args.port); create_tcp_socket(args.port);
@ -95,12 +112,38 @@ int main(int argc, char **argv) {
} }
} }
puts(""); puts("");
// TODO Validate request and send response.
// TODO WIP size_t response_size = 0;
const char *response = c_simple_http_request_response( const char *response = c_simple_http_request_response(
(const char*)recv_buf, read_ret, NULL); (const char*)recv_buf, read_ret, &parsed_config, &response_size);
if (response) { if (response) {
write(connection_fd, "HTTP/1.1 200 OK\n", 16);
write(connection_fd, "Allow: GET\n", 11);
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);
content_length_buf_size = 16;
int written = 0;
snprintf(
content_length_buf + content_length_buf_size,
127 - content_length_buf_size,
"%lu\n%n",
response_size,
&written);
content_length_buf_size += written;
write(connection_fd, content_length_buf, content_length_buf_size);
write(connection_fd, "\n", 1);
write(connection_fd, response, response_size);
free((void*)response); free((void*)response);
} else {
// TODO handle internal errors also.
write(connection_fd, "HTTP/1.1 404 Not Found\n", 23);
write(connection_fd, "Allow: GET\n", 11);
write(connection_fd, "Content-Type: text/html\n", 24);
write(connection_fd, "Content-Length: 14\n", 19);
write(connection_fd, "\n404 Not Found\n", 15);
} }
close(connection_fd); close(connection_fd);
} else { } else {