tinywebd
diff src/http.c @ 3:852a745503cf
http header parsing, not tested
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Thu, 16 Apr 2015 15:20:16 +0300 |
parents | 7bb4c2a0a360 |
children | 9e054c002489 |
line diff
1.1 --- a/src/http.c Wed Apr 15 23:44:22 2015 +0300 1.2 +++ b/src/http.c Thu Apr 16 15:20:16 2015 +0300 1.3 @@ -1,10 +1,98 @@ 1.4 +#include <stdio.h> 1.5 +#include <stdlib.h> 1.6 +#include <string.h> 1.7 +#include <ctype.h> 1.8 +#include <alloca.h> 1.9 #include "http.h" 1.10 1.11 + 1.12 +const char *http_method_str[] = { 1.13 + "<unknown>", 1.14 + "OPTIONS", 1.15 + "GET", 1.16 + "HEAD", 1.17 + "POST", 1.18 + "PUT", 1.19 + "DELETE", 1.20 + "TRACE", 1.21 + "CONNECT", 1.22 + 0 1.23 +}; 1.24 + 1.25 + 1.26 +/* HTTP 1xx message strings */ 1.27 +const char *http_msg1xx[] = { 1.28 + "Continue", /* 100 */ 1.29 + "Switching Protocols" /* 101 */ 1.30 +}; 1.31 + 1.32 +/* HTTP 2xx message strings */ 1.33 +const char *http_msg2xx[] = { 1.34 + "OK", /* 200 */ 1.35 + "Created", /* 201 */ 1.36 + "Accepted", /* 202 */ 1.37 + "Non-Authoritative Information", /* 203 */ 1.38 + "No Content", /* 204 */ 1.39 + "Reset Content", /* 205 */ 1.40 + "Partial Content" /* 206 */ 1.41 +}; 1.42 + 1.43 +/* HTTP 3xx message strings */ 1.44 +const char *http_msg3xx[] = { 1.45 + "Multiple Choices", /* 300 */ 1.46 + "Moved Permanently", /* 301 */ 1.47 + "Found", /* 302 */ 1.48 + "See Other", /* 303 */ 1.49 + "Not Modified", /* 304 */ 1.50 + "Use Proxy", /* 305 */ 1.51 + "<unknown>", /* 306 is undefined? */ 1.52 + "Temporary Redirect" /* 307 */ 1.53 +}; 1.54 + 1.55 +/* HTTP 4xx error strings */ 1.56 +const char *http_msg4xx[] = { 1.57 + "Bad Request", /* 400 */ 1.58 + "Unauthorized", /* 401 */ 1.59 + "What the Fuck?", /* 402 */ 1.60 + "Forbidden", /* 403 */ 1.61 + "Not Found", /* 404 */ 1.62 + "Method Not Allowed", /* 405 */ 1.63 + "Not Acceptable", /* 406 */ 1.64 + "Proxy Authentication Required", /* 407 */ 1.65 + "Request Time-out", /* 408 */ 1.66 + "Conflict", /* 409 */ 1.67 + "Gone", /* 410 */ 1.68 + "Length Required", /* 411 */ 1.69 + "Precondition Failed", /* 412 */ 1.70 + "Request Entity Too Large", /* 413 */ 1.71 + "Request-URI Too Large", /* 414 */ 1.72 + "Unsupported Media Type", /* 415 */ 1.73 + "Request range not satisfiable", /* 416 */ 1.74 + "Expectation Failed" /* 417 */ 1.75 +}; 1.76 + 1.77 +/* HTTP 5xx error strings */ 1.78 +const char *http_msg5xx[] = { 1.79 + "Internal Server Error", /* 500 */ 1.80 + "Not Implemented", /* 501 */ 1.81 + "Bad Gateway", /* 502 */ 1.82 + "Service Unavailable", /* 503 */ 1.83 + "Gateway Time-out", /* 504 */ 1.84 + "HTTP Version not supported" /* 505 */ 1.85 +}; 1.86 + 1.87 + 1.88 +static enum http_method parse_method(const char *s); 1.89 + 1.90 + 1.91 int http_parse_header(struct http_req_header *hdr, const char *buf, int bufsz) 1.92 { 1.93 int i, nlines = 0; 1.94 - char *endhdr; 1.95 char *rqline = 0; 1.96 + char *method, *uri, *version, *ptr; 1.97 + const char *startln, *endln; 1.98 + 1.99 + memset(hdr, 0, sizeof *hdr); 1.100 1.101 for(i=1; i<bufsz; i++) { 1.102 if(buf[i] == '\n' && buf[i - 1] == '\r') { 1.103 @@ -14,13 +102,96 @@ 1.104 rqline[i - 1] = 0; 1.105 } 1.106 ++nlines; 1.107 + 1.108 + if(i > 4 && buf[i - 2] == '\n' && buf[i - 3] == '\r') { 1.109 + hdr->body_offset = i + 1; 1.110 + break; 1.111 + } 1.112 } 1.113 } 1.114 1.115 - if(!rqline) 1.116 - return -1; 1.117 + if(!rqline) { 1.118 + return HTTP_HDR_PARTIAL; 1.119 + } 1.120 1.121 + ptr = rqline; 1.122 + while(*ptr && isspace(*ptr)) ++ptr; 1.123 + method = ptr; 1.124 1.125 + /* parse the request line */ 1.126 + while(*ptr && !isspace(*ptr)) ++ptr; 1.127 + while(*ptr && isspace(*ptr)) *ptr++ = 0; 1.128 + 1.129 + uri = ptr; 1.130 + while(*ptr && !isspace(*ptr)) ++ptr; 1.131 + while(*ptr && isspace(*ptr)) *ptr++ = 0; 1.132 + 1.133 + version = ptr; 1.134 + while(*ptr && !isspace(*ptr)) ++ptr; 1.135 + while(*ptr && isspace(*ptr)) *ptr++ = 0; 1.136 + 1.137 + hdr->method = parse_method(method); 1.138 + hdr->uri = strdup(uri); 1.139 + if(sscanf(version, "HTTP/%d.%d", &hdr->ver_major, &hdr->ver_minor) != 2) { 1.140 + fprintf(stderr, "warning: failed to parse HTTP version \"%s\"\n", version); 1.141 + hdr->ver_major = 1; 1.142 + hdr->ver_minor = 1; 1.143 + } 1.144 + 1.145 + if(!(hdr->hdrfields = malloc(nlines * sizeof *hdr->hdrfields))) { 1.146 + perror("failed to allocate memory for the header fields"); 1.147 + return HTTP_HDR_NOMEM; 1.148 + } 1.149 + hdr->num_hdrfields = 0; 1.150 + 1.151 + startln = buf; 1.152 + endln = buf; 1.153 + for(i=1; i<hdr->body_offset; i++) { 1.154 + if(buf[i] == '\n' && buf[i - 1] == '\r') { 1.155 + int linesz; 1.156 + endln = buf + i - 1; 1.157 + linesz = endln - startln - 1; 1.158 + 1.159 + if(startln > buf) { /* skip first line */ 1.160 + int idx = hdr->num_hdrfields++; 1.161 + hdr->hdrfields[idx] = malloc(linesz + 1); 1.162 + memcpy(hdr->hdrfields[idx], startln, linesz); 1.163 + hdr->hdrfields[idx][linesz] = 0; 1.164 + } 1.165 + startln = endln = buf + i + 1; 1.166 + } 1.167 + } 1.168 + 1.169 + return HTTP_HDR_OK; 1.170 +} 1.171 + 1.172 +void http_print_header(struct http_req_header *hdr) 1.173 +{ 1.174 + int i; 1.175 + 1.176 + printf("HTTP request header\n"); 1.177 + printf(" method: %s\n", http_method_str[hdr->method]); 1.178 + printf(" uri: %s\n", hdr->uri); 1.179 + printf(" version: %d.%d\n", hdr->ver_major, hdr->ver_minor); 1.180 + printf(" fields (%d):\n", hdr->num_hdrfields); 1.181 + 1.182 + for(i=0; i<hdr->num_hdrfields; i++) { 1.183 + printf(" %s\n", hdr->hdrfields[i]); 1.184 + } 1.185 + putchar('\n'); 1.186 +} 1.187 + 1.188 +void http_destroy_header(struct http_req_header *hdr) 1.189 +{ 1.190 + int i; 1.191 + 1.192 + if(hdr->hdrfields) { 1.193 + for(i=0; i<hdr->num_hdrfields; i++) { 1.194 + free(hdr->hdrfields[i]); 1.195 + } 1.196 + free(hdr->hdrfields); 1.197 + } 1.198 + free(hdr->uri); 1.199 } 1.200 1.201 const char *http_strmsg(int code) 1.202 @@ -50,3 +221,14 @@ 1.203 1.204 return msgxxx[type][idx]; 1.205 } 1.206 + 1.207 +static enum http_method parse_method(const char *s) 1.208 +{ 1.209 + int i; 1.210 + for(i=0; http_method_str[i]; i++) { 1.211 + if(strcmp(s, http_method_str[i]) == 0) { 1.212 + return (enum http_method)i; 1.213 + } 1.214 + } 1.215 + return HTTP_UNKNOWN; 1.216 +}