http_parse_c/main.c

160 lines
3.9 KiB
C

#include <stdio.h>
#include <stdint.h>
#include <strings.h>
#include <stdlib.h>
const char * http_version_str = "HTTP/1.1 ";
typedef struct http_header {
uint8_t * status_code_ptr;
size_t status_code_len;
size_t num_headers;
uint8_t ** header_key_ptrs;
size_t * header_key_lens;
uint8_t ** header_val_ptrs;
size_t * header_val_lens;
uint8_t * body_ptr;
size_t body_len;
} http_header_t;
http_header_t * parse_header(uint8_t * data, size_t len) {
http_header_t * ret = malloc(sizeof(http_header_t));
// Parse version
if(len < strlen(http_version_str)) {
fprintf(stderr, "Data shorter than version string\n");
return 0;
} else if(strncmp((const char *)data, http_version_str, strlen(http_version_str)) != 0) {
fprintf(stderr, "http_version_str did not match\n");
return 0;
}
size_t ptr = strlen(http_version_str);
// Prase status code
size_t status_code_start = ptr;
size_t status_code_end = 0;
while(ptr < len-1) {
if((data[ptr] == '\r') && (data[ptr+1] == '\n')) {
status_code_end = ptr;
ptr += 2;
break;
} else {
ptr += 1;
}
}
if(ptr >= (len-1)) {
fprintf(stderr, "Reached EOF while parsing status code\n");
return 0;
} else {
ret->status_code_ptr = data + status_code_start;
ret->status_code_len = status_code_end - status_code_start;
}
if(ptr < len-1) {
if((data[ptr] == '\r') && (data[ptr+1] == '\n')) {
ret->num_headers = 0;
return ret;
}
}
// Parse header
size_t num_headers = 0;
uint8_t * header_key_ptrs[1024];
uint8_t * header_val_ptrs[1024];
size_t header_key_lens[1024];
size_t header_val_lens[1024];
while(ptr < len-1) {
size_t key_start = ptr;
size_t key_len = 0;
while(ptr < len-1) {
if(data[ptr] == ':') {
key_len = ptr - key_start;
ptr += 1;
break;
} else {
ptr += 1;
}
}
if(ptr >= len-1) {
fprintf(stderr, "Reached EOF reading header key\n");
return 0;
}
size_t val_start = ptr;
size_t val_len = 0;
while(ptr < len-1) {
if((data[ptr] == '\r') && (data[ptr+1] == '\n')) {
val_len = ptr - val_start;
ptr += 2;
break;
} else {
ptr += 1;
}
}
if(ptr >= len-1) {
fprintf(stderr, "Reached EOF reading header val\n");
return 0;
}
header_key_ptrs[num_headers] = &data[key_start];
header_key_lens[num_headers] = key_len;
header_val_ptrs[num_headers] = &data[val_start];
header_val_lens[num_headers] = val_len;
num_headers += 1;
if(ptr < len-1) {
if((data[ptr] == '\r') && (data[ptr+1] == '\n')) {
ptr += 2;
break;
}
}
}
ret->num_headers = num_headers;
ret->header_key_ptrs = malloc(sizeof(uint8_t*)*num_headers);
ret->header_key_lens = malloc(sizeof(size_t)*num_headers);
ret->header_val_ptrs = malloc(sizeof(uint8_t*)*num_headers);
ret->header_val_lens = malloc(sizeof(size_t)*num_headers);
for(size_t i = 0; i < num_headers; i++) {
ret->header_key_ptrs[i] = header_key_ptrs[i];
ret->header_key_lens[i] = header_key_lens[i];
ret->header_val_ptrs[i] = header_val_ptrs[i];
ret->header_val_lens[i] = header_val_lens[i];
}
ret->body_ptr = data + ptr;
ret->body_len = len - ptr;
return ret;
}
int main(int argc, char ** argv) {
if(argc < 2) {
printf("Data to parse required as input\n");
return 1;
}
http_header_t * header = parse_header((uint8_t*)argv[1], strlen(argv[1]));
if(header == 0) {
fprintf(stderr, "no header returned from parse\n");
} else {
printf("Parsed header with code %.*s and %d headers\n", header->status_code_len, header->status_code_ptr, header->num_headers);
for(size_t i = 0; i < header->num_headers; i++) {
printf("Header %ld: %.*s - %.*s\n", i,header->header_key_lens[i], header->header_key_ptrs[i], header->header_val_lens[i], header->header_val_ptrs[i]);
}
}
return 0;
}