feat(LSP): Begin of header parsing

This commit is contained in:
overflowerror 2024-02-24 23:41:59 +01:00
parent c61076b835
commit 755bdcd189
6 changed files with 153 additions and 16 deletions

View file

@ -1,5 +1,5 @@
CC = gcc CC = gcc
CFLAGS = -std=c11 -D_POSIX_C_SOURCE=200809L -Wall -Wpedantic -g -I./src -I./gen CFLAGS = -std=c11 -D_POSIX_C_SOURCE=200809L -Wall -Wpedantic -g -I./src -I./../common/src/
LD = gcc LD = gcc
LDFLAGS = LDFLAGS =
YACC = bison YACC = bison
@ -8,7 +8,7 @@ LEX = lex
LEXFLAGS = LEXFLAGS =
OBJS = obj/networking.o obj/main.o OBJS = obj/networking.o obj/header.o obj/main.o
DEPS = $(OBJS:%.o=%.d) DEPS = $(OBJS:%.o=%.d)
-include $(DEPS) -include $(DEPS)
@ -18,12 +18,16 @@ all: macrofuck-lsp
obj/%.o: src/%.c obj/%.o: src/%.c
$(CC) $(CFLAGS) -c -o $@ $< $(CC) $(CFLAGS) -c -o $@ $<
macrofuck-lsp: $(OBJS) macrofuck-lsp: $(OBJS) ../common/common.a
$(LD) $(LDFLAGS) -o $@ $^ $(LD) $(LDFLAGS) -o $@ $^
../common/common.a: FORCE
cd ../common/ && $(MAKE) common.a
FORCE: ; FORCE: ;
clean: clean:
@cd ../common/ && $(MAKE) clean
@echo "Cleaning up" @echo "Cleaning up"
@rm -f obj/*.o @rm -f obj/*.o
@rm -f obj/*.d @rm -f obj/*.d

116
lsp/src/header.c Normal file
View file

@ -0,0 +1,116 @@
#include <stdio.h>
#include <alloca.h>
#include <stdbool.h>
#include <string.h>
#include <errno.h>
#include <alloc.h>
#include <dict.h>
#include "header.h"
header_t* header_new(void) {
header_t* header = safe_malloc(sizeof (header_t));
header->method = NULL;
header->uri = NULL;
header->headers = dict_new();
return header;
}
header_t* header_parse(FILE* conn) {
fprintf(stderr, "parsing headers\n");
header_t* header = header_new();
#define HEADER_BUFFER_LENGTH (1<<10)
char* buffer = alloca(HEADER_BUFFER_LENGTH);
size_t buffer_index = 0;
char* key = NULL;
char* value = NULL;
bool is_first_line = true;
bool last_line_was_empty = false;
while (true) {
int c = fgetc(conn);
fprintf(stderr, "c: %c, %d, %d, %s, %s, %s\n", c, is_first_line, last_line_was_empty, buffer, key, value);
if (c == EOF) {
break;
}
if (c == '\r') {
c = fgetc(conn);
if (c == '\n') {
if (last_line_was_empty) {
break;
} else {
if (is_first_line) {
char* method = strtok(buffer, " ");
char* uri = strtok(NULL, " ");
char* proto = strtok(NULL, " ");
// defer fail to when fields are read
if (method) {
header->method = strdup(method);
}
if (uri) {
header->uri = strdup(uri);
}
if (proto) {
header->proto = strdup(proto);
}
is_first_line = false;
} else {
if (!key) {
fprintf(stderr, "no key for value - ignoring\n");
} else {
value = strdup(buffer);
if (!value) {
fprintf(stderr, "unable to dup header value: %s\n", strerror(errno));
return NULL;
}
header_add(header, key, value);
}
}
}
} else {
fprintf(stderr, "header parse error, unexpected %d at header %s\n", c, key);
}
*buffer = '\0';
buffer_index = 0;
key = NULL;
value = NULL;
last_line_was_empty = true;
} else if (key == NULL && c == ':' && !is_first_line) {
c = fgetc(conn);
if (c == ' ') {
key = strdup(buffer);
if (!key) {
fprintf(stderr, "unable to dup header key: %s\n", strerror(errno));
return NULL;
}
*buffer = '\0';
buffer_index = 0;
}
} else {
last_line_was_empty = false;
if (buffer_index + 1 >= HEADER_BUFFER_LENGTH) {
fprintf(stderr, "header too long - truncating\n");
} else {
buffer[buffer_index] = c;
buffer[++buffer_index] = '\0';
}
}
}
return header;
}
void header_add(header_t* header, const char* key, const char* value) {
dict_put(header->headers, key, (void*) value);
}
const char* header_get(header_t* header, const char* key) {
return dict_get(header->headers, key);
}

20
lsp/src/header.h Normal file
View file

@ -0,0 +1,20 @@
#ifndef HEADER_H
#define HEADER_H
#include <stdio.h>
#include <dict.h>
typedef struct {
char* method;
char* uri;
char* proto;
dict_t* headers;
} header_t;
header_t* header_new(void);
header_t* header_parse(FILE*);
void header_add(header_t*, const char*, const char*);
const char* header_get(header_t*, const char*);
#endif

View file

@ -6,6 +6,10 @@ void hello_handler(request_t* request) {
fprintf(request->response_body, "HTTP/1.0 200 OK\r\n"); fprintf(request->response_body, "HTTP/1.0 200 OK\r\n");
fprintf(request->response_body, "\r\n"); fprintf(request->response_body, "\r\n");
fprintf(request->response_body, "Hello, World!\n"); fprintf(request->response_body, "Hello, World!\n");
fprintf(request->response_body, "Method: %s\n", request->request_header->method);
fprintf(request->response_body, "URI: %s\n", request->request_header->uri);
fprintf(request->response_body, "Host: %s\n", header_get(request->request_header, "Host"));
fprintf(request->response_body, "User-Agent: %s\n", header_get(request->request_header, "User-Agent"));
} }
int main(void) { int main(void) {

View file

@ -98,19 +98,7 @@ static request_t prepare_request_obj(int fd) {
request.request_body = fdopen(fd, "r"); request.request_body = fdopen(fd, "r");
request.response_body = fdopen(fd2, "w"); request.response_body = fdopen(fd2, "w");
#define HEADER_BUFFER_LENGTH (128) request.request_header = header_parse(request.request_body);
char* buffer = alloca(HEADER_BUFFER_LENGTH);
// skip headers (for now)
while (true) {
fgets(buffer, HEADER_BUFFER_LENGTH - 1, request.request_body);
if (strcmp(buffer, "\r\n")) {
break;
}
printf(" discarded header: %s\n", buffer);
}
return request; return request;
} }
@ -150,8 +138,10 @@ int run_server(const char* bind_addr, handler_t handler) {
while (true) { while (true) {
// we don't care for the remote address right now // we don't care for the remote address right now
int fd = accept(sock, NULL, 0); int fd = accept(sock, NULL, 0);
fprintf(stderr, "new connection: %d\n", fd);
if (fd < 0) { if (fd < 0) {
fprintf(stderr, "warn: accept failed: %s\n", strerror(errno)); fprintf(stderr, "warn: accept failed: %s\n", strerror(errno));
} }
handle_connection(fd, handler); handle_connection(fd, handler);

View file

@ -3,7 +3,10 @@
#include <stdio.h> #include <stdio.h>
#include "header.h"
typedef struct { typedef struct {
header_t* request_header;
FILE* request_body; FILE* request_body;
FILE* response_body; FILE* response_body;
} request_t; } request_t;