tinywebd

view libtinyweb/src/http.c @ 17:2874f61a43b1

implementing the directory index generation
author John Tsiombikas <nuclear@member.fsf.org>
date Tue, 21 Apr 2015 04:33:02 +0300
parents 0dd50a23f3dd
children
line source
1 /* tinyweb - tiny web server library and daemon
2 * Author: John Tsiombikas <nuclear@member.fsf.org>
3 *
4 * This program is placed in the public domain. Feel free to use it any
5 * way you like. Mentions and retaining this attribution header will be
6 * appreciated, but not required.
7 */
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <stdarg.h>
12 #include <ctype.h>
13 #include <alloca.h>
14 #include "http.h"
15 #include "logger.h"
18 static const char *http_method_str[] = {
19 "<unknown>",
20 "OPTIONS",
21 "GET",
22 "HEAD",
23 "POST",
24 "PUT",
25 "DELETE",
26 "TRACE",
27 "CONNECT",
28 0
29 };
32 /* HTTP 1xx message strings */
33 static const char *http_msg1xx[] = {
34 "Continue", /* 100 */
35 "Switching Protocols" /* 101 */
36 };
38 /* HTTP 2xx message strings */
39 static const char *http_msg2xx[] = {
40 "OK", /* 200 */
41 "Created", /* 201 */
42 "Accepted", /* 202 */
43 "Non-Authoritative Information", /* 203 */
44 "No Content", /* 204 */
45 "Reset Content", /* 205 */
46 "Partial Content" /* 206 */
47 };
49 /* HTTP 3xx message strings */
50 static const char *http_msg3xx[] = {
51 "Multiple Choices", /* 300 */
52 "Moved Permanently", /* 301 */
53 "Found", /* 302 */
54 "See Other", /* 303 */
55 "Not Modified", /* 304 */
56 "Use Proxy", /* 305 */
57 "<unknown>", /* 306 is undefined? */
58 "Temporary Redirect" /* 307 */
59 };
61 /* HTTP 4xx error strings */
62 static const char *http_msg4xx[] = {
63 "Bad Request", /* 400 */
64 "Unauthorized", /* 401 */
65 "What the Fuck?", /* 402 */
66 "Forbidden", /* 403 */
67 "Not Found", /* 404 */
68 "Method Not Allowed", /* 405 */
69 "Not Acceptable", /* 406 */
70 "Proxy Authentication Required", /* 407 */
71 "Request Time-out", /* 408 */
72 "Conflict", /* 409 */
73 "Gone", /* 410 */
74 "Length Required", /* 411 */
75 "Precondition Failed", /* 412 */
76 "Request Entity Too Large", /* 413 */
77 "Request-URI Too Large", /* 414 */
78 "Unsupported Media Type", /* 415 */
79 "Request range not satisfiable", /* 416 */
80 "Expectation Failed" /* 417 */
81 };
83 /* HTTP 5xx error strings */
84 static const char *http_msg5xx[] = {
85 "Internal Server Error", /* 500 */
86 "Not Implemented", /* 501 */
87 "Bad Gateway", /* 502 */
88 "Service Unavailable", /* 503 */
89 "Gateway Time-out", /* 504 */
90 "HTTP Version not supported" /* 505 */
91 };
94 static enum http_method parse_method(const char *s);
97 int http_parse_request(struct http_req_header *hdr, const char *buf, int bufsz)
98 {
99 int i, nlines = 0;
100 char *rqline = 0;
101 char *method, *uri, *version, *ptr;
102 const char *startln, *endln;
104 memset(hdr, 0, sizeof *hdr);
106 for(i=1; i<bufsz; i++) {
107 if(buf[i] == '\n' && buf[i - 1] == '\r') {
108 if(!rqline) {
109 rqline = alloca(i);
110 memcpy(rqline, buf, i - 1);
111 rqline[i - 1] = 0;
112 }
113 ++nlines;
115 if(i > 4 && buf[i - 2] == '\n' && buf[i - 3] == '\r') {
116 hdr->body_offset = i + 1;
117 break;
118 }
119 }
120 }
122 if(!rqline) {
123 return HTTP_HDR_PARTIAL;
124 }
126 ptr = rqline;
127 while(*ptr && isspace(*ptr)) ++ptr;
128 method = ptr;
130 /* parse the request line */
131 while(*ptr && !isspace(*ptr)) ++ptr;
132 while(*ptr && isspace(*ptr)) *ptr++ = 0;
134 uri = ptr;
135 while(*ptr && !isspace(*ptr)) ++ptr;
136 while(*ptr && isspace(*ptr)) *ptr++ = 0;
138 version = ptr;
139 while(*ptr && !isspace(*ptr)) ++ptr;
140 while(*ptr && isspace(*ptr)) *ptr++ = 0;
142 hdr->method = parse_method(method);
143 hdr->uri = strdup(uri);
144 if(sscanf(version, "HTTP/%d.%d", &hdr->ver_major, &hdr->ver_minor) != 2) {
145 fprintf(stderr, "warning: failed to parse HTTP version \"%s\"\n", version);
146 hdr->ver_major = 1;
147 hdr->ver_minor = 1;
148 }
150 if(!(hdr->hdrfields = malloc(nlines * sizeof *hdr->hdrfields))) {
151 perror("failed to allocate memory for the header fields");
152 return HTTP_HDR_NOMEM;
153 }
154 hdr->num_hdrfields = 0;
156 startln = buf;
157 endln = buf;
158 for(i=1; i<hdr->body_offset - 2; i++) {
159 if(buf[i] == '\n' && buf[i - 1] == '\r') {
160 int linesz;
162 endln = buf + i - 1;
163 linesz = endln - startln;
165 if(startln > buf) { /* skip first line */
166 int idx = hdr->num_hdrfields++;
167 hdr->hdrfields[idx] = malloc(linesz + 1);
168 memcpy(hdr->hdrfields[idx], startln, linesz);
169 hdr->hdrfields[idx][linesz] = 0;
170 }
171 startln = endln = buf + i + 1;
172 }
173 }
175 return HTTP_HDR_OK;
176 }
178 void http_log_request(struct http_req_header *hdr)
179 {
180 int i;
182 logmsg("HTTP request header\n");
183 logmsg(" method: %s\n", http_method_str[hdr->method]);
184 logmsg(" uri: %s\n", hdr->uri);
185 logmsg(" version: %d.%d\n", hdr->ver_major, hdr->ver_minor);
186 logmsg(" fields (%d):\n", hdr->num_hdrfields);
188 for(i=0; i<hdr->num_hdrfields; i++) {
189 logmsg(" %s\n", hdr->hdrfields[i]);
190 }
191 logmsg("\n");
192 }
194 void http_destroy_request(struct http_req_header *hdr)
195 {
196 int i;
198 if(hdr->hdrfields) {
199 for(i=0; i<hdr->num_hdrfields; i++) {
200 free(hdr->hdrfields[i]);
201 }
202 free(hdr->hdrfields);
203 }
204 free(hdr->uri);
205 }
207 int http_init_resp(struct http_resp_header *resp)
208 {
209 memset(resp, 0, sizeof *resp);
210 resp->status = 200;
211 resp->ver_major = resp->ver_minor = 1;
212 resp->fields = 0;
213 resp->num_fields = 0;
215 return 0;
216 }
218 int http_add_resp_field(struct http_resp_header *resp, const char *fmt, ...)
219 {
220 int sz;
221 va_list ap;
222 char *field, **newarr, tmp;
224 va_start(ap, fmt);
225 sz = vsnprintf(&tmp, 0, fmt, ap);
226 va_end(ap);
228 if(sz <= 0) sz = 1023;
229 if(!(field = malloc(sz + 1))) {
230 return -1;
231 }
232 va_start(ap, fmt);
233 vsnprintf(field, sz + 1, fmt, ap);
234 va_end(ap);
236 if(!(newarr = realloc(resp->fields, (resp->num_fields + 1) * sizeof *resp->fields))) {
237 free(field);
238 return -1;
239 }
240 resp->fields = newarr;
242 resp->fields[resp->num_fields++] = field;
243 return 0;
244 }
246 void http_destroy_resp(struct http_resp_header *resp)
247 {
248 int i;
249 if(resp->fields) {
250 for(i=0; i<resp->num_fields; i++) {
251 free(resp->fields[i]);
252 }
253 free(resp->fields);
254 resp->fields = 0;
255 }
256 resp->num_fields = 0;
257 }
259 int http_serialize_resp(struct http_resp_header *resp, char *buf)
260 {
261 int i, stsize, size, *fsize;
262 char *ptr, tmp;
264 stsize = snprintf(&tmp, 0, "HTTP/%d.%d %d %s\r\n", resp->ver_major, resp->ver_minor,
265 resp->status, http_strmsg(resp->status));
267 fsize = alloca(resp->num_fields * sizeof *fsize);
269 size = stsize;
270 for(i=0; i<resp->num_fields; i++) {
271 int len = strlen(resp->fields[i]) + 2;
272 fsize[i] = len;
273 size += len;
274 }
275 size += 2; /* CRLF and null */
277 if(buf) {
278 sprintf(buf, "HTTP/%d.%d %d %s\r\n", resp->ver_major, resp->ver_minor,
279 resp->status, http_strmsg(resp->status));
281 ptr = buf + stsize;
282 for(i=0; i<resp->num_fields; i++) {
283 sprintf(ptr, "%s\r\n", resp->fields[i]);
284 ptr += fsize[i];
285 }
286 *ptr++ = '\r';
287 *ptr++ = '\n';
288 *ptr++ = 0;
289 }
291 return size;
292 }
294 const char *http_strmsg(int code)
295 {
296 static const char **msgxxx[] = {
297 0, http_msg1xx, http_msg2xx, http_msg3xx, http_msg4xx, http_msg5xx
298 };
299 static int msgcount[] = {
300 0,
301 sizeof http_msg1xx / sizeof *http_msg1xx,
302 sizeof http_msg2xx / sizeof *http_msg2xx,
303 sizeof http_msg3xx / sizeof *http_msg3xx,
304 sizeof http_msg4xx / sizeof *http_msg4xx,
305 sizeof http_msg5xx / sizeof *http_msg5xx
306 };
308 int type = code / 100;
309 int idx = code % 100;
311 if(type < 1 || type >= sizeof msgxxx / sizeof *msgxxx) {
312 return "Invalid HTTP Status";
313 }
315 if(idx < 0 || idx >= msgcount[type]) {
316 return "Unknown HTTP Status";
317 }
319 return msgxxx[type][idx];
320 }
322 static enum http_method parse_method(const char *s)
323 {
324 int i;
325 for(i=0; http_method_str[i]; i++) {
326 if(strcmp(s, http_method_str[i]) == 0) {
327 return (enum http_method)i;
328 }
329 }
330 return HTTP_UNKNOWN;
331 }