Very, very basic server responses

This commit is contained in:
2025-09-13 19:50:41 +03:00
parent eb5e420d41
commit 172665ed4d
6 changed files with 298 additions and 21 deletions

View File

@@ -5,17 +5,19 @@ project(SimpleHttpServer VERSION 1.0
LANGUAGES C)
add_library(
httpserverlib
STATIC
src/httpserver.h
src/httpserver.c
httpserverlib
STATIC
src/httpserver.h
src/httpserver.c
src/utils/hashmap.c
src/utils/hashmap.h
src/utils/string_builder.c
src/utils/string_builder.h
)
add_executable(
httpserver
app/main.c
httpserver
app/main.c
app/main.h
)

View File

@@ -7,7 +7,27 @@
http_response_t* handle_request(http_request_t* request)
{
http_response_t* http_response = {};
http_response_t* http_response = malloc(sizeof *http_response);
http_response->http_version.http_name = "HTTP\0";
http_response->http_version.http_name_len = 4;
http_response->http_version.major = 1;
http_response->http_version.minor = 1;
http_response->http_status_code = 200;
http_response->http_status_message = "OK\0";
http_response->http_status_message_len = 2;
char *length_str = malloc(20);
sprintf(length_str, "%ld", request->http_path_len);
http_response->http_headers = new_hash_map();
set(http_response->http_headers, "Server", "SimpleHttpServer");
set(http_response->http_headers, "Content-Length", length_str);
set(http_response->http_headers, "Content-Type", "text/plain");
http_response->http_content = request->http_path;
http_response->http_content_len = request->http_path_len;
return http_response;
}

View File

@@ -60,7 +60,7 @@ void start_http_server(http_server_t* http_server, const char *addr, const short
close(server_fd);
}
void process_conn(http_server_t* http_server, const int server_fd, struct sockaddr* address, socklen_t* addr_len)
void process_conn(const http_server_t* http_server, const int server_fd, struct sockaddr* address, socklen_t* addr_len)
{
const int socket_d = accept(server_fd, address, addr_len);
if (socket_d == -1)
@@ -92,18 +92,18 @@ void process_conn(http_server_t* http_server, const int server_fd, struct sockad
enum http_request_parsing_stage request_parsing_stage = START_LINE_METHOD;
http_request_t http_request = {};
char method_str[8];
char *method_str = malloc(8);
size_t method_str_len = 0;
char http_path[2048];
char *http_path = malloc(2048);
size_t http_path_len = 0;
char http_name[16];
char *http_name = malloc(16);
size_t http_name_len = 0;
char header_key[256];
char *header_key = malloc(256);
size_t header_key_length = 0;
char header_val[1024];
char *header_val = malloc(1024);
size_t header_val_length = 0;
http_request.http_content = nullptr;
@@ -203,10 +203,10 @@ void process_conn(http_server_t* http_server, const int server_fd, struct sockad
char* val = calloc(header_val_length + 1, sizeof(char));
strncpy(val, header_val, header_val_length);
printf(
"Setting header '%s' (hash %d per cap %d): '%s'\n",
key, hashcode(http_request.http_headers, key),
http_request.http_headers->cap, val);
// printf(
// "Setting header '%s' (hash %d per cap %d): '%s'\n",
// key, hashcode(http_request.http_headers, key),
// http_request.http_headers->cap, val);
set(http_request.http_headers, key, val);
header_key[0] = '\0';
@@ -231,8 +231,46 @@ void process_conn(http_server_t* http_server, const int server_fd, struct sockad
http_response_t* http_response = http_server->handle_request(&http_request);
// TODO: Send response
string_builder_t* response_sb = new_string_builder();
append_fmt(
response_sb,
"%s/%d.%d %d %s\r\n",
http_response->http_version.http_name,
http_response->http_version.major,
http_response->http_version.minor,
http_response->http_status_code,
http_response->http_status_message
);
for (int i = 0; i < http_response->http_headers->cap; i++)
{
const pair_t* iter = http_response->http_headers->list[i];
while (iter != nullptr)
{
append_fmt(response_sb, "%s: %s\r\n", iter->key, iter->val);
iter = iter->next;
}
}
append_crlf(response_sb, "");
append_nstr(response_sb, http_response->http_content, http_response->http_content_len);
char* response_str = string_builder_to_string(response_sb);
printf("\nServer response (%ld):\n", response_sb->char_count);
for (int i = 0; i < response_sb->char_count; i++)
{
if (response_str[i] != '\r')
putchar(response_str[i]);
}
putchar('\n');
fflush(stdout);
write(socket_d, response_str, response_sb->char_count);
free(response_str);
free_string_builder(response_sb);
free_hash_map(http_request.http_headers);
free(http_response);
@@ -251,3 +289,12 @@ enum http_method parse_method_str(const char* str, const size_t len)
return UNKNOWN;
}
const char* http_method_to_string(const enum http_method m)
{
for (size_t i = 0; i < sizeof(method_map)/sizeof(method_map[0]); i++) {
if (method_map[i].method == m)
return method_map[i].name;
}
return "UNKNOWN";
}

View File

@@ -16,6 +16,7 @@
#include <sys/socket.h>
#include <sys/types.h>
#include "utils/hashmap.h"
#include "utils/string_builder.h"
typedef struct http_version
{
@@ -65,7 +66,7 @@ typedef struct http_request
typedef struct http_response
{
http_version_t http_version;
u_short http_status_code;
unsigned short http_status_code;
char* http_status_message;
size_t http_status_message_len;
hashmap_t* http_headers;
@@ -79,7 +80,8 @@ typedef struct http_server
} http_server_t;
void start_http_server(http_server_t* http_server, const char *addr, short port);
void process_conn(http_server_t* http_server, int server_fd, struct sockaddr* address, socklen_t* addr_len);
void process_conn(const http_server_t* http_server, int server_fd, struct sockaddr* address, socklen_t* addr_len);
enum http_method parse_method_str(const char* str, size_t len);
const char* http_method_to_string(enum http_method m);
#endif //SIMPLEHTTPSERVER_H

163
src/utils/string_builder.c Normal file
View File

@@ -0,0 +1,163 @@
//
// Created by nazar on 13.09.2025.
//
#include "string_builder.h"
#include <stdio.h>
#include <string.h>
string_builder_t* new_string_builder()
{
string_builder_t* sb = malloc(sizeof *sb);
sb->first = nullptr;
sb->last = nullptr;
sb->char_count = 0;
return sb;
}
char* string_builder_to_string(const string_builder_t* sb)
{
char* str = malloc(sb->char_count + 1);
if (!str) return nullptr;
char* p = str;
for (const string_builder_part_t* part = sb->first; part; part = part->next) {
memcpy(p, part->data, part->len);
p += part->len;
}
*p = '\0';
return str;
}
void free_string_builder(string_builder_t* sb)
{
string_builder_part_t* iter = sb->first;
while (iter != nullptr)
{
string_builder_part_t* prev = iter;
iter = iter->next;
free(prev->data);
free(prev);
}
sb->first = nullptr;
sb->last = nullptr;
free(sb);
}
void append_part(string_builder_t* sb, string_builder_part_t* part)
{
sb->char_count += part->len;
if (sb->last == nullptr)
{
sb->first = part;
sb->last = part;
return;
}
sb->last->next = part;
sb->last = part;
}
void append_char(string_builder_t* sb, const char c)
{
char* str = malloc(2);
sprintf(str, "%c", c);
string_builder_part_t* part = malloc(sizeof *part);
part->data = str;
part->len = 1;
append_part(sb, part);
}
void append_int(string_builder_t* sb, const int i)
{
char* str = malloc(20);
sprintf(str, "%d", i);
string_builder_part_t* part = malloc(sizeof *part);
part->data = str;
part->len = strlen(str);
append_part(sb, part);
}
void append_str(string_builder_t* sb, char* str)
{
append_nstr(sb, str, strlen(str));
}
void append_nstr(string_builder_t* sb, char* str, size_t len)
{
string_builder_part_t* part = malloc(sizeof *part);
part->data = str;
part->len = len;
append_part(sb, part);
}
void append_fmt(string_builder_t* sb, const char* fmt, ...) {
va_list args = {};
va_start(args, fmt);
va_list args_copy;
va_copy(args_copy, args);
const int len = vsnprintf(nullptr, 0, fmt, args_copy);
va_end(args_copy);
if (len < 0) {
va_end(args);
return;
}
char* buf = malloc(len + 1);
if (!buf) {
va_end(args);
return;
}
vsnprintf(buf, len + 1, fmt, args);
va_end(args);
append_nstr(sb, buf, len);
}
void append_lf(string_builder_t* sb, char* str)
{
const size_t len = strlen(str);
append_nlf(sb, str, len);
}
void append_nlf(string_builder_t* sb, char* str, size_t len)
{
char* l = malloc(len + 2);
sprintf(l, "%s\n", str);
string_builder_part_t* part = malloc(sizeof *part);
part->data = l;
part->len = len + 1;
append_part(sb, part);
}
void append_crlf(string_builder_t* sb, char* str)
{
const size_t len = strlen(str);
append_ncrlf(sb, str, len);
}
void append_ncrlf(string_builder_t* sb, char* str, size_t len)
{
char* l = malloc(len + 3);
sprintf(l, "%s\r\n", str);
string_builder_part_t* part = malloc(sizeof *part);
part->data = l;
part->len = len + 2;
append_part(sb, part);
}

View File

@@ -0,0 +1,43 @@
//
// Created by nazar on 13.09.2025.
//
#ifndef SIMPLEHTTPSERVER_STRING_BUILDER_H
#define SIMPLEHTTPSERVER_STRING_BUILDER_H
#include <stddef.h>
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
typedef struct string_builder_part string_builder_part_t;
struct string_builder_part
{
char* data;
size_t len;
string_builder_part_t* next;
};
typedef struct string_builder
{
string_builder_part_t* first;
string_builder_part_t* last;
size_t char_count;
} string_builder_t;
string_builder_t* new_string_builder();
char* string_builder_to_string(const string_builder_t* sb);
void free_string_builder(string_builder_t* sb);
void append_part(string_builder_t* sb, string_builder_part_t* part);
void append_char(string_builder_t* sb, char c);
void append_int(string_builder_t* sb, int i);
void append_str(string_builder_t* sb, char* str);
void append_nstr(string_builder_t* sb, char* str, size_t len);
void append_fmt(string_builder_t* sb, const char* fmt, ...);
void append_lf(string_builder_t* sb, char* str);
void append_nlf(string_builder_t* sb, char* str, size_t len);
void append_crlf(string_builder_t* sb, char* str);
void append_ncrlf(string_builder_t* sb, char* str, size_t len);
#endif //SIMPLEHTTPSERVER_STRING_BUILDER_H