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