tinywebd

view 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 source
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <ctype.h>
5 #include <alloca.h>
6 #include "http.h"
9 const char *http_method_str[] = {
10 "<unknown>",
11 "OPTIONS",
12 "GET",
13 "HEAD",
14 "POST",
15 "PUT",
16 "DELETE",
17 "TRACE",
18 "CONNECT",
19 0
20 };
23 /* HTTP 1xx message strings */
24 const char *http_msg1xx[] = {
25 "Continue", /* 100 */
26 "Switching Protocols" /* 101 */
27 };
29 /* HTTP 2xx message strings */
30 const char *http_msg2xx[] = {
31 "OK", /* 200 */
32 "Created", /* 201 */
33 "Accepted", /* 202 */
34 "Non-Authoritative Information", /* 203 */
35 "No Content", /* 204 */
36 "Reset Content", /* 205 */
37 "Partial Content" /* 206 */
38 };
40 /* HTTP 3xx message strings */
41 const char *http_msg3xx[] = {
42 "Multiple Choices", /* 300 */
43 "Moved Permanently", /* 301 */
44 "Found", /* 302 */
45 "See Other", /* 303 */
46 "Not Modified", /* 304 */
47 "Use Proxy", /* 305 */
48 "<unknown>", /* 306 is undefined? */
49 "Temporary Redirect" /* 307 */
50 };
52 /* HTTP 4xx error strings */
53 const char *http_msg4xx[] = {
54 "Bad Request", /* 400 */
55 "Unauthorized", /* 401 */
56 "What the Fuck?", /* 402 */
57 "Forbidden", /* 403 */
58 "Not Found", /* 404 */
59 "Method Not Allowed", /* 405 */
60 "Not Acceptable", /* 406 */
61 "Proxy Authentication Required", /* 407 */
62 "Request Time-out", /* 408 */
63 "Conflict", /* 409 */
64 "Gone", /* 410 */
65 "Length Required", /* 411 */
66 "Precondition Failed", /* 412 */
67 "Request Entity Too Large", /* 413 */
68 "Request-URI Too Large", /* 414 */
69 "Unsupported Media Type", /* 415 */
70 "Request range not satisfiable", /* 416 */
71 "Expectation Failed" /* 417 */
72 };
74 /* HTTP 5xx error strings */
75 const char *http_msg5xx[] = {
76 "Internal Server Error", /* 500 */
77 "Not Implemented", /* 501 */
78 "Bad Gateway", /* 502 */
79 "Service Unavailable", /* 503 */
80 "Gateway Time-out", /* 504 */
81 "HTTP Version not supported" /* 505 */
82 };
85 static enum http_method parse_method(const char *s);
88 int http_parse_header(struct http_req_header *hdr, const char *buf, int bufsz)
89 {
90 int i, nlines = 0;
91 char *rqline = 0;
92 char *method, *uri, *version, *ptr;
93 const char *startln, *endln;
95 memset(hdr, 0, sizeof *hdr);
97 for(i=1; i<bufsz; i++) {
98 if(buf[i] == '\n' && buf[i - 1] == '\r') {
99 if(!rqline) {
100 rqline = alloca(i);
101 memcpy(rqline, buf, i - 1);
102 rqline[i - 1] = 0;
103 }
104 ++nlines;
106 if(i > 4 && buf[i - 2] == '\n' && buf[i - 3] == '\r') {
107 hdr->body_offset = i + 1;
108 break;
109 }
110 }
111 }
113 if(!rqline) {
114 return HTTP_HDR_PARTIAL;
115 }
117 ptr = rqline;
118 while(*ptr && isspace(*ptr)) ++ptr;
119 method = ptr;
121 /* parse the request line */
122 while(*ptr && !isspace(*ptr)) ++ptr;
123 while(*ptr && isspace(*ptr)) *ptr++ = 0;
125 uri = ptr;
126 while(*ptr && !isspace(*ptr)) ++ptr;
127 while(*ptr && isspace(*ptr)) *ptr++ = 0;
129 version = ptr;
130 while(*ptr && !isspace(*ptr)) ++ptr;
131 while(*ptr && isspace(*ptr)) *ptr++ = 0;
133 hdr->method = parse_method(method);
134 hdr->uri = strdup(uri);
135 if(sscanf(version, "HTTP/%d.%d", &hdr->ver_major, &hdr->ver_minor) != 2) {
136 fprintf(stderr, "warning: failed to parse HTTP version \"%s\"\n", version);
137 hdr->ver_major = 1;
138 hdr->ver_minor = 1;
139 }
141 if(!(hdr->hdrfields = malloc(nlines * sizeof *hdr->hdrfields))) {
142 perror("failed to allocate memory for the header fields");
143 return HTTP_HDR_NOMEM;
144 }
145 hdr->num_hdrfields = 0;
147 startln = buf;
148 endln = buf;
149 for(i=1; i<hdr->body_offset; i++) {
150 if(buf[i] == '\n' && buf[i - 1] == '\r') {
151 int linesz;
152 endln = buf + i - 1;
153 linesz = endln - startln - 1;
155 if(startln > buf) { /* skip first line */
156 int idx = hdr->num_hdrfields++;
157 hdr->hdrfields[idx] = malloc(linesz + 1);
158 memcpy(hdr->hdrfields[idx], startln, linesz);
159 hdr->hdrfields[idx][linesz] = 0;
160 }
161 startln = endln = buf + i + 1;
162 }
163 }
165 return HTTP_HDR_OK;
166 }
168 void http_print_header(struct http_req_header *hdr)
169 {
170 int i;
172 printf("HTTP request header\n");
173 printf(" method: %s\n", http_method_str[hdr->method]);
174 printf(" uri: %s\n", hdr->uri);
175 printf(" version: %d.%d\n", hdr->ver_major, hdr->ver_minor);
176 printf(" fields (%d):\n", hdr->num_hdrfields);
178 for(i=0; i<hdr->num_hdrfields; i++) {
179 printf(" %s\n", hdr->hdrfields[i]);
180 }
181 putchar('\n');
182 }
184 void http_destroy_header(struct http_req_header *hdr)
185 {
186 int i;
188 if(hdr->hdrfields) {
189 for(i=0; i<hdr->num_hdrfields; i++) {
190 free(hdr->hdrfields[i]);
191 }
192 free(hdr->hdrfields);
193 }
194 free(hdr->uri);
195 }
197 const char *http_strmsg(int code)
198 {
199 static const char **msgxxx[] = {
200 0, http_msg1xx, http_msg2xx, http_msg3xx, http_msg4xx, http_msg5xx
201 };
202 static int msgcount[] = {
203 0,
204 sizeof http_msg1xx / sizeof *http_msg1xx,
205 sizeof http_msg2xx / sizeof *http_msg2xx,
206 sizeof http_msg3xx / sizeof *http_msg3xx,
207 sizeof http_msg4xx / sizeof *http_msg4xx,
208 sizeof http_msg5xx / sizeof *http_msg5xx
209 };
211 int type = code / 100;
212 int idx = code % 100;
214 if(type < 1 || type >= sizeof msgxxx / sizeof *msgxxx) {
215 return "Invalid HTTP Status";
216 }
218 if(idx < 0 || idx >= msgcount[type]) {
219 return "Unknown HTTP Status";
220 }
222 return msgxxx[type][idx];
223 }
225 static enum http_method parse_method(const char *s)
226 {
227 int i;
228 for(i=0; http_method_str[i]; i++) {
229 if(strcmp(s, http_method_str[i]) == 0) {
230 return (enum http_method)i;
231 }
232 }
233 return HTTP_UNKNOWN;
234 }