Wed, 27 Nov 2024 23:00:07 +0100
add TODO to use a future ucx feature
1 | 1 | /* |
2 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. | |
3 | * | |
44
3da1f7b6847f
added some error messages
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
25
diff
changeset
|
4 | * Copyright 2013 Olaf Wintermann. All rights reserved. |
1 | 5 | * |
6 | * Redistribution and use in source and binary forms, with or without | |
7 | * modification, are permitted provided that the following conditions are met: | |
8 | * | |
9 | * 1. Redistributions of source code must retain the above copyright | |
10 | * notice, this list of conditions and the following disclaimer. | |
11 | * | |
12 | * 2. Redistributions in binary form must reproduce the above copyright | |
13 | * notice, this list of conditions and the following disclaimer in the | |
14 | * documentation and/or other materials provided with the distribution. | |
15 | * | |
16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |
17 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
19 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE | |
20 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
21 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
22 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
23 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
24 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
25 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
26 | * POSSIBILITY OF SUCH DAMAGE. | |
27 | */ | |
28 | ||
29 | #include <stdio.h> | |
30 | #include <stdlib.h> | |
31 | ||
32 | #include "httpparser.h" | |
14
b8bf95b39952
New source folder layout
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
1
diff
changeset
|
33 | #include "../public/nsapi.h" |
1 | 34 | //include "request.h" |
35 | ||
36 | ||
37 | HttpParser* http_parser_new(HTTPRequest *request) { | |
183
f33974f0dce0
fixes http parser init
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
182
diff
changeset
|
38 | HttpParser *parser = calloc(1, sizeof(HttpParser)); |
1 | 39 | parser->request = request; |
40 | ||
41 | parser->state = 0; | |
42 | parser->start_line.ptr = (char*)request->netbuf->inbuf; | |
43 | parser->start_line.length = 0; | |
101
7fbcdbad0baa
added support for absolute URIs and improved keep alive
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
44
diff
changeset
|
44 | |
7fbcdbad0baa
added support for absolute URIs and improved keep alive
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
44
diff
changeset
|
45 | parser->offset = 0; |
1 | 46 | |
47 | return parser; | |
48 | } | |
49 | ||
50 | void http_parser_free(HttpParser *parser) { | |
51 | free(parser); | |
52 | } | |
53 | ||
54 | int http_parser_process(HttpParser *parser) { | |
55 | switch(parser->state) { | |
56 | case 0: { | |
57 | int r = get_start_line(parser); | |
58 | switch(r) { | |
59 | case 0: break; | |
60 | default: return r; | |
61 | } | |
62 | parse_request_line(parser); | |
63 | parser->state++; | |
64 | } | |
65 | case 1: { | |
66 | return http_parser_parse_header(parser); | |
67 | } | |
68 | case 2: { | |
69 | return 0; | |
70 | } | |
71 | } | |
25
5dee29c7c530
Fixed config parser bug
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
20
diff
changeset
|
72 | return -1; |
1 | 73 | } |
74 | ||
180
98462e878ca7
fixes crash with broken http requests
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
163
diff
changeset
|
75 | int http_parser_validate(HttpParser *parser) { |
98462e878ca7
fixes crash with broken http requests
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
163
diff
changeset
|
76 | HTTPRequest *req = parser->request; |
98462e878ca7
fixes crash with broken http requests
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
163
diff
changeset
|
77 | if( |
98462e878ca7
fixes crash with broken http requests
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
163
diff
changeset
|
78 | !req->method.ptr || req->method.length == 0 |
182
b982cc285c40
fixes http_parser_validate
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
180
diff
changeset
|
79 | || !req->uri.ptr || req->uri.length == 0 |
180
98462e878ca7
fixes crash with broken http requests
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
163
diff
changeset
|
80 | || !req->httpv.ptr || req->httpv.length == 0) |
98462e878ca7
fixes crash with broken http requests
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
163
diff
changeset
|
81 | { |
98462e878ca7
fixes crash with broken http requests
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
163
diff
changeset
|
82 | return 0; |
98462e878ca7
fixes crash with broken http requests
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
163
diff
changeset
|
83 | } |
98462e878ca7
fixes crash with broken http requests
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
163
diff
changeset
|
84 | return 1; |
98462e878ca7
fixes crash with broken http requests
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
163
diff
changeset
|
85 | } |
98462e878ca7
fixes crash with broken http requests
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
163
diff
changeset
|
86 | |
1 | 87 | int get_start_line(HttpParser *parser) { |
88 | netbuf *buf = parser->request->netbuf; | |
89 | while(buf->pos < buf->cursize) { | |
90 | unsigned char c = buf->inbuf[buf->pos]; | |
91 | if(c == '\n') { | |
101
7fbcdbad0baa
added support for absolute URIs and improved keep alive
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
44
diff
changeset
|
92 | size_t lnlen = buf->pos - parser->offset + 1; |
7fbcdbad0baa
added support for absolute URIs and improved keep alive
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
44
diff
changeset
|
93 | if(lnlen <= 2) { |
7fbcdbad0baa
added support for absolute URIs and improved keep alive
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
44
diff
changeset
|
94 | if(lnlen == 1 || buf->inbuf[buf->pos-1] == '\r') { |
7fbcdbad0baa
added support for absolute URIs and improved keep alive
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
44
diff
changeset
|
95 | // skip empty line |
7fbcdbad0baa
added support for absolute URIs and improved keep alive
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
44
diff
changeset
|
96 | buf->pos++; |
7fbcdbad0baa
added support for absolute URIs and improved keep alive
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
44
diff
changeset
|
97 | parser->offset = buf->pos; |
7fbcdbad0baa
added support for absolute URIs and improved keep alive
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
44
diff
changeset
|
98 | return 1; |
7fbcdbad0baa
added support for absolute URIs and improved keep alive
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
44
diff
changeset
|
99 | } |
1 | 100 | // insufficient chars for request, return error |
101 | return 2; | |
102 | } | |
103 | if(buf->inbuf[buf->pos - 1] == '\r') { | |
101
7fbcdbad0baa
added support for absolute URIs and improved keep alive
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
44
diff
changeset
|
104 | parser->start_line.length = lnlen - 1; |
1 | 105 | } else { |
101
7fbcdbad0baa
added support for absolute URIs and improved keep alive
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
44
diff
changeset
|
106 | parser->start_line.length = lnlen; |
1 | 107 | } |
101
7fbcdbad0baa
added support for absolute URIs and improved keep alive
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
44
diff
changeset
|
108 | parser->start_line.ptr = (char*)buf->inbuf + parser->offset; |
1 | 109 | buf->pos++; |
110 | return 0; | |
111 | } | |
112 | buf->pos++; | |
113 | } | |
114 | return 1; | |
115 | } | |
116 | ||
117 | int http_parser_parse_header(HttpParser *parser) { | |
118 | netbuf *buf = parser->request->netbuf; | |
119 | ||
120 | parser->offset = buf->pos; // line offset | |
121 | parser->name.ptr = NULL; | |
101
7fbcdbad0baa
added support for absolute URIs and improved keep alive
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
44
diff
changeset
|
122 | parser->name.length = 0; |
1 | 123 | parser->value.ptr = NULL; |
101
7fbcdbad0baa
added support for absolute URIs and improved keep alive
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
44
diff
changeset
|
124 | parser->value.length = 0; |
1 | 125 | while(1) { |
126 | if(buf->pos >= buf->cursize) { | |
127 | return 1; | |
128 | } | |
129 | char c = (char)buf->inbuf[buf->pos++]; | |
130 | ||
131 | if(c > 32) { | |
132 | parser->wl = 0; | |
133 | if(c == ':' && parser->value.ptr == NULL) { | |
134 | parser->name.ptr = (char*)buf->inbuf + parser->offset; | |
101
7fbcdbad0baa
added support for absolute URIs and improved keep alive
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
44
diff
changeset
|
135 | parser->name.length = buf->pos - parser->offset - 1; |
1 | 136 | } else if(parser->name.ptr != NULL && parser->value.ptr == NULL) { |
137 | parser->value.ptr = (char*)buf->inbuf + buf->pos - 1; | |
138 | } | |
139 | } else if(c == '\n') { | |
140 | if(parser->wl) { | |
141 | // line contains only white space -> end of request | |
142 | parser->state++; | |
143 | return 0; | |
144 | } else { | |
145 | parser->offset = buf->pos; | |
162
b169992137a8
improves cgi error handling and allows requests with empty headers
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
101
diff
changeset
|
146 | if(parser->name.length != 0) { |
b169992137a8
improves cgi error handling and allows requests with empty headers
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
101
diff
changeset
|
147 | if(parser->value.ptr) { |
b169992137a8
improves cgi error handling and allows requests with empty headers
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
101
diff
changeset
|
148 | parser->value.length = (buf->inbuf + buf->pos - 1) |
101
7fbcdbad0baa
added support for absolute URIs and improved keep alive
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
44
diff
changeset
|
149 | - (unsigned char*)parser->value.ptr; |
162
b169992137a8
improves cgi error handling and allows requests with empty headers
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
101
diff
changeset
|
150 | if(buf->inbuf[buf->pos-2] == '\r') { |
b169992137a8
improves cgi error handling and allows requests with empty headers
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
101
diff
changeset
|
151 | parser->value.length--; |
b169992137a8
improves cgi error handling and allows requests with empty headers
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
101
diff
changeset
|
152 | } |
163
3589ed579127
fixes empty headers
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
162
diff
changeset
|
153 | } else { |
3589ed579127
fixes empty headers
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
162
diff
changeset
|
154 | parser->value.ptr = ""; |
20
7b235fa88008
Some fixes for mod_jk
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
14
diff
changeset
|
155 | } |
1 | 156 | // add header |
157 | header_add( | |
158 | parser->request->headers, | |
101
7fbcdbad0baa
added support for absolute URIs and improved keep alive
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
44
diff
changeset
|
159 | parser->name, |
7fbcdbad0baa
added support for absolute URIs and improved keep alive
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
44
diff
changeset
|
160 | parser->value); |
1 | 161 | } else { |
162 | // error: no value | |
163 | return 2; | |
164 | } | |
165 | parser->name.ptr = NULL; | |
166 | parser->value.ptr = NULL; | |
101
7fbcdbad0baa
added support for absolute URIs and improved keep alive
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
44
diff
changeset
|
167 | parser->name.length = 0; |
7fbcdbad0baa
added support for absolute URIs and improved keep alive
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
44
diff
changeset
|
168 | parser->value.length = 0; |
1 | 169 | parser->wl = 1; |
170 | } | |
171 | } | |
172 | } | |
173 | } | |
174 | ||
175 | int parse_request_line(HttpParser *parser) { | |
415
d938228c382e
switch from ucx 2 to 3
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
351
diff
changeset
|
176 | cxmutstr line = parser->start_line; |
1 | 177 | parser->request->request_line = line; |
178 | ||
179 | /* | |
180 | * parse method, url and http version | |
181 | */ | |
182 | ||
183 | int i = 0; | |
184 | int ns = 0; | |
185 | ||
186 | parser->request->method.ptr = line.ptr; | |
187 | for(;i<line.length;i++) { | |
188 | if(!ns && line.ptr[i] == ' ') { | |
189 | ns = 1; | |
190 | parser->request->method.length = i; | |
191 | } else if(ns) { | |
192 | if(line.ptr[i] != ' ') { | |
193 | break; | |
194 | } | |
195 | } | |
196 | } | |
197 | ||
198 | parser->request->uri.ptr = line.ptr + i; | |
199 | ns = 0; | |
200 | int s = i; | |
201 | for(;i<line.length;i++) { | |
351
5533db9b64e2
fix parse_request_line not detecting the uri correctly in some cases
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
183
diff
changeset
|
202 | if(!ns && isspace(line.ptr[i])) { |
1 | 203 | ns = 1; |
204 | parser->request->uri.length = i - s; | |
205 | } else if(ns) { | |
206 | if(line.ptr[i] > 32) { | |
207 | break; | |
208 | } | |
209 | } | |
210 | } | |
211 | ||
212 | parser->request->httpv.ptr = line.ptr + i; | |
213 | ns = 0; | |
214 | s = i; | |
215 | for(;i<line.length;i++) { | |
351
5533db9b64e2
fix parse_request_line not detecting the uri correctly in some cases
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
183
diff
changeset
|
216 | if(!ns && isspace(line.ptr[i])) { |
1 | 217 | ns = 1; |
218 | parser->request->httpv.length = i - s; | |
219 | } else if(ns) { | |
220 | if(line.ptr[i] > 32) { | |
221 | break; | |
222 | } | |
223 | } | |
224 | } | |
225 | ||
226 | return 0; | |
227 | } |