http-parser.c

Small C library to parse HTTP requests
Log | Files | Refs | README | LICENSE

test.c (8112B)


      1 #include <stdio.h>
      2 #include <string.h>
      3 
      4 #include "http-parser.h"
      5 
      6 #ifndef NULL
      7 #define NULL ((void*)0)
      8 #endif
      9 
     10 #define T_RED "\e[31m"
     11 #define T_LIME "\e[32m"
     12 #define T_MAGENTA "\e[35m"
     13 #define T_NORMAL "\e[00m"
     14 #define T_BOLD "\e[01m"
     15 
     16 #define ASSERT(M,c) (printf(((err|=!(c),(c)) ? (T_LIME " PASS " T_NORMAL " %s\n") : (T_RED " FAIL " T_NORMAL " %s\n")),M))
     17 
     18 #ifndef MIN
     19 #define MIN(a,b) ((a)<(b)?(a):(b))
     20 #endif
     21 #ifndef MAX
     22 #define MAX(a,b) ((a)>(b)?(a):(b))
     23 #endif
     24 
     25 /* static void onRequest(struct http_parser_event *ev) { */
     26 /*   // The request has been received */
     27 /*   // Answer the request directly or pass it to a route handler of sorts */
     28 
     29 /*   // Fetching the request */
     30 /*   // Has been wrapped in http_parser_event to support more features in the future */
     31 /*   struct http_parser_request *request = ev->request; */
     32 
     33 /*   // Basic http request data */
     34 /*   printf("Method: %s\n", request->method); */
     35 
     36 /*   // Reading headers are case-insensitive due to non-compliant clients/servers */
     37 /*   printf("Host:   %s\n", http_parser_header_get(request, "host")); */
     38 
     39 /*   // Once you're done with the request, you'll have to free it */
     40 /*   http_parser_request_free(request); */
     41 /* } */
     42 
     43 /* // Initialize a request */
     44 /* struct http_parser_request *request = http_parser_init(); */
     45 
     46 /* // Assign userdata into the request */
     47 /* // Use it to track whatever you need */
     48 /* request->udata = (void*)...; */
     49 
     50 /* // Attach a function */
     51 
     52 // Stored http messages
     53 char *getMessage =
     54   "GET /foobar HTTP/1.1\r\n"
     55   "Host: localhost\r\n"
     56   "\r\n"
     57 ;
     58 
     59 char *postMessage =
     60   "POST /foobar HTTP/1.1\r\n"
     61   "Host: localhost\r\n"
     62   "Content-Length: 13\r\n"
     63   "\r\n"
     64   "Hello World\r\n"
     65 ;
     66 
     67 char *postOrderedMessage = 
     68   "POST /foobar HTTP/1.1\r\n"
     69   "Content-Length: 13\r\n"
     70   "Host: localhost\r\n"
     71   "\r\n"
     72   "Hello World\r\n"
     73 ;
     74 
     75 char *postChunkedMessage =
     76   "POST /foobar?token=pizza HTTP/1.1\r\n"
     77   "Host: localhost\r\n"
     78   "Transfer-Encoding: chunked\r\n"
     79   "\r\n"
     80   "2\r\n"
     81   "He\r\n"
     82   "B\r\n"
     83   "llo World\r\n"
     84   "0\r\n"
     85 ;
     86 
     87 char *optionsRequest =
     88   "OPTIONS /hello/world HTTP/1.1\r\n"
     89   "Host: localhost\r\n"
     90   "\r\n"
     91 ;
     92 
     93 char *responseMessage =
     94   "HTTP/1.0 200 OK\r\n"
     95   "Content-Length: 13\r\n"
     96   "\r\n"
     97   "Hello World\r\n"
     98 ;
     99 
    100 char *responseChunkedMessage =
    101   "HTTP/1.0 200 OK\r\n"
    102   "Transfer-Encoding: chunked\r\n"
    103   "\r\n"
    104   "2\r\n"
    105   "He\r\n"
    106   "B\r\n"
    107   "llo World\r\n"
    108   "0\r\n"
    109 ;
    110 
    111 char *responseNotFoundMessage =
    112   "HTTP/1.0 404 Not Found\r\n"
    113   "Content-Length: 11\r\n"
    114   "\r\n"
    115   "Not Found\r\n"
    116 ;
    117 
    118 char *responseNotFoundExtendedMessage =
    119   "HTTP/1.0 404 Not Found\r\n"
    120   "Content-Length: 11\r\n"
    121   "Content-Type: text/plain\r\n"
    122   "\r\n"
    123   "Not Found\r\n"
    124 ;
    125 
    126 
    127 /* // Passing network data into it */
    128 /* http_parser_request_data(request, message, strlen(message)); */
    129 
    130 int main() {
    131   struct http_parser_message *request  = http_parser_request_init();
    132   struct http_parser_message *response = http_parser_response_init();
    133   struct buf *msgbuf;
    134 
    135   int err = 0;
    136 
    137   printf("# Pre-loaded request\n");
    138   ASSERT("request->method is null", request->method == NULL);
    139   ASSERT("request->body is null", request->body == NULL);
    140   ASSERT("request->chunksize is -1", request->chunksize == -1);
    141   ASSERT("request->header->host is NULL", http_parser_header_get(request, "host") == NULL);
    142 
    143   http_parser_message_free(request);
    144   request  = http_parser_request_init();
    145   http_parser_request_data(request, &((struct buf){
    146     .data = getMessage,
    147     .len  = strlen(getMessage),
    148     .cap  = strlen(getMessage)
    149   }));
    150 
    151   printf("# GET request\n");
    152   ASSERT("request->version is 1.1", strcmp(request->version, "1.1") == 0);
    153   ASSERT("request->method is GET", strcmp(request->method, "GET") == 0);
    154   ASSERT("request->path is /foobar", strcmp(request->path, "/foobar") == 0);
    155   msgbuf = http_parser_sprint_request(request);
    156   ASSERT("request->toString matches", strcmp(getMessage, msgbuf->data) == 0);
    157   ASSERT("request->header->host is localhost", strcmp(http_parser_header_get(request, "host"), "localhost") == 0);
    158 
    159   http_parser_message_free(request);
    160   request  = http_parser_request_init();
    161   http_parser_request_data(request, &((struct buf){
    162     .data = postMessage,
    163     .len  = strlen(postMessage),
    164     .cap  = strlen(postMessage)
    165   }));
    166 
    167   printf("# POST request\n");
    168   ASSERT("request->version is 1.1", strcmp(request->version, "1.1") == 0);
    169   ASSERT("request->method is POST", strcmp(request->method, "POST") == 0);
    170   ASSERT("request->path is /foobar", strcmp(request->path, "/foobar") == 0);
    171   ASSERT("request->body is \"Hello World\\r\\n\"", strcmp(request->body->data, "Hello World\r\n") == 0);
    172   msgbuf = http_parser_sprint_request(request);
    173   ASSERT("request->toString matches", strcmp(postOrderedMessage, msgbuf->data) == 0);
    174 
    175   http_parser_message_free(request);
    176   request  = http_parser_request_init();
    177   http_parser_request_data(request, &((struct buf){
    178     .data = postChunkedMessage,
    179     .len  = strlen(postChunkedMessage),
    180     .cap  = strlen(postChunkedMessage)
    181   }));
    182 
    183   printf("# POST request (chunked)\n");
    184   ASSERT("request->version is 1.1", strcmp(request->version, "1.1") == 0);
    185   ASSERT("request->method is POST", strcmp(request->method, "POST") == 0);
    186   ASSERT("request->path is /foobar", strcmp(request->path, "/foobar") == 0);
    187   ASSERT("request->body is \"Hello World\\r\\n\"", strcmp(request->body->data, "Hello World\r\n") == 0);
    188 
    189   http_parser_message_free(request);
    190   request = http_parser_request_init();
    191   http_parser_request_data(request, &((struct buf){
    192     .data = optionsRequest,
    193     .len  = strlen(optionsRequest),
    194     .cap  = strlen(optionsRequest)
    195   }));
    196 
    197   printf("# OPTIONS request\n");
    198   ASSERT("request->version is 1.1", strcmp(request->version, "1.1") == 0);
    199   ASSERT("request->method is OPTIONS", strcmp(request->method, "OPTIONS") == 0);
    200   ASSERT("request->path is /hello/world", strcmp(request->path, "/hello/world") == 0);
    201 
    202   printf("# Pre-loaded response\n");
    203   ASSERT("response->status = 200", response->status == 200);
    204 
    205   http_parser_message_free(response);
    206   response = http_parser_response_init();
    207   http_parser_response_data(response, &((struct buf){
    208     .data = responseMessage,
    209     .len  = strlen(responseMessage),
    210     .cap  = strlen(responseMessage)
    211   }));
    212 
    213   printf("# 200 OK response\n");
    214   ASSERT("response->status = 200", response->status == 200);
    215   ASSERT("response->statusmessage = \"OK\"", strcmp(response->statusMessage, "OK") == 0);
    216   ASSERT("response->body = \"Hello World\\r\\n\"", strcmp(response->body->data, "Hello World\r\n") == 0);
    217   ASSERT("response->toString matches", strcmp(responseMessage, http_parser_sprint_response(response)->data) == 0);
    218 
    219   http_parser_message_free(response);
    220   response = http_parser_response_init();
    221   http_parser_response_data(response, &((struct buf){
    222     .data = responseChunkedMessage,
    223     .len  = strlen(responseChunkedMessage),
    224     .cap  = strlen(responseChunkedMessage)
    225   }));
    226 
    227   printf("# 200 OK response (chunked)\n");
    228   ASSERT("response->status = 200", response->status == 200);
    229   ASSERT("response->statusmessage = \"OK\"", strcmp(response->statusMessage, "OK") == 0);
    230   ASSERT("response->body = \"Hello World\\r\\n\"", strcmp(response->body->data, "Hello World\r\n") == 0);
    231 
    232   http_parser_message_free(response);
    233   response = http_parser_response_init();
    234   http_parser_response_data(response, &((struct buf){
    235     .data = responseNotFoundMessage,
    236     .len  = strlen(responseNotFoundMessage),
    237     .cap  = strlen(responseNotFoundMessage)
    238   }));
    239 
    240   printf("# 404 Not Found response\n");
    241   ASSERT("response->status = 404", response->status == 404);
    242   ASSERT("response->statusmessage = \"Not Found\"", strcmp(response->statusMessage, "Not Found") == 0);
    243   ASSERT("response->body = \"Not Found\\r\\n\"", strcmp(response->body->data, "Not Found\r\n") == 0);
    244   ASSERT("response->toString matches", strcmp(responseNotFoundMessage, http_parser_sprint_response(response)->data) == 0);
    245 
    246   http_parser_header_set(response, "Content-Type", "text/plain");
    247 
    248   ASSERT("response->toString matches after header modification", strcmp(responseNotFoundExtendedMessage, http_parser_sprint_response(response)->data) == 0);
    249 
    250   return err;
    251 }