A small lightweight http server library in c
at master 4.1 kB view raw
1#include "stdarg.h" 2#include "stdbool.h" 3#include "stdio.h" 4#include "stdlib.h" 5#include "string.h" 6#include <prairie/lexer.h> 7#include <prairie/parser.h> 8#include <prairie/utils.h> 9 10void advance(prairie_parser_ctx_t *ctx) { 11 ctx->current_token = ctx->current_token->next; 12} 13 14/** 15 * Returns true if the assertion passes 16 */ 17bool assert(prairie_parser_ctx_t *ctx, prairie_token_type_t type) { 18 if (ctx->current_token->type != type) { 19 printf("unexpected token, expected %s, found %s\n", 20 prairie_token_type_to_string(type), 21 prairie_token_to_string(ctx->current_token)); 22 return false; 23 } 24 return true; 25} 26 27bool assert_advance(prairie_parser_ctx_t *ctx, prairie_token_type_t type) { 28 if (assert(ctx, type)) { 29 advance(ctx); 30 return true; 31 } 32 return false; 33} 34 35prairie_method_t string_to_method(char *value) { 36 if (strcmp(value, "GET") == 0) 37 return GET; 38 if (strcmp(value, "POST") == 0) 39 return POST; 40 41 // Might want to do some error handling here but default > crash 42 return GET; 43} 44 45prairie_protocol_t string_to_protocol(char *value) { 46 if (strcmp(value, "HTTP/1.0") == 0) 47 return HTTP_1_0; 48 if (strcmp(value, "HTTP/1.1") == 0) 49 return HTTP_1_1; 50 if (strcmp(value, "HTTP/2") == 0) 51 return HTTP_2; 52 53 // Might want to do some error handling here but default > crash 54 return HTTP_1_1; 55} 56 57#define free_and_return \ 58 { \ 59 printf("Error occured\n"); \ 60 free(ctx); \ 61 free(request); \ 62 return NULL; \ 63 } 64 65void prairie_print_request(prairie_request_t *request) { 66 printf("%d %s %d\n", request->method, request->route, request->protocol); 67 prairie_header_t *header = request->header_start; 68 while (header != NULL) { 69 printf("%s: %s\n", header->key, header->value); 70 header = header->next; 71 } 72 printf("%s\n", request->body); 73} 74 75prairie_request_t *prairie_parse_request(prairie_token_t *token_start) { 76 prairie_request_t *request = malloc(sizeof(prairie_request_t)); 77 prairie_parser_ctx_t *ctx = malloc(sizeof(prairie_parser_ctx_t)); 78 ctx->current_token = token_start; 79 ctx->request = request; 80 81 if (!assert(ctx, PRAIRIE_TOKEN_IDENTIFIER)) 82 free_and_return; 83 84 // printf("method: %s\n", ctx->current_token->lexeme); 85 ctx->request->method = string_to_method(ctx->current_token->lexeme); 86 advance(ctx); 87 88 if (!assert(ctx, PRAIRIE_TOKEN_IDENTIFIER)) 89 free_and_return; 90 91 // printf("route: %s\n", ctx->current_token->lexeme); 92 ctx->request->route = ctx->current_token->lexeme; 93 advance(ctx); 94 95 if (!assert(ctx, PRAIRIE_TOKEN_IDENTIFIER)) 96 free_and_return; 97 98 // printf("protocol: %s\n", ctx->current_token->lexeme); 99 ctx->request->protocol = string_to_protocol(ctx->current_token->lexeme); 100 advance(ctx); 101 102 while (ctx->current_token != NULL) { 103 if (ctx->current_token->type == PRAIRIE_TOKEN_IDENTIFIER) { 104 prairie_header_t *header = malloc(sizeof(prairie_header_t)); 105 header->key = ctx->current_token->lexeme; 106 header->next = NULL; 107 advance(ctx); 108 109 if (!assert_advance(ctx, PRAIRIE_TOKEN_COLON)) 110 free_and_return; 111 112 header->value = ctx->current_token->lexeme; 113 114 if (ctx->request->header_start == NULL) { 115 ctx->request->header_start = header; 116 ctx->request->header_end = header; 117 } else { 118 ctx->request->header_end->next = header; 119 ctx->request->header_end = header; 120 } 121 advance(ctx); 122 } else if (ctx->current_token->type == PRAIRIE_TOKEN_BODY) { 123 ctx->request->body = ctx->current_token->lexeme; 124 free(ctx); 125 126 return request; 127 } else { 128 printf("unexpected token. expected identifier or body, found %s\n", 129 prairie_token_to_string(ctx->current_token)); 130 free_and_return; 131 } 132 } 133 134 free(ctx); 135 return request; 136}