#include #include #include #include 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; }