source: Main/trunk/Server/http.c@ 86

Last change on this file since 86 was 70, checked in by Nishi, on Sep 19, 2024 at 6:23:45 PM

patch for windows xp

  • Property svn:keywords set to Id
File size: 7.0 KB
Line 
1/* $Id: http.c 70 2024-09-19 09:23:45Z nishi $ */
2
3#define SOURCE
4
5#include "../config.h"
6
7#include "tw_http.h"
8
9#include "tw_server.h"
10
11#include <cm_log.h>
12#include <cm_string.h>
13
14#include <stdbool.h>
15#include <stdlib.h>
16#include <string.h>
17
18#ifdef __MINGW32__
19#include <winsock2.h>
20#else
21#include <sys/select.h>
22#endif
23
24void tw_free_request(struct tw_http_request* req) {
25 if(req->method != NULL) free(req->method);
26 if(req->path != NULL) free(req->path);
27 if(req->query != NULL) free(req->query);
28 if(req->headers != NULL) {
29 int i;
30 for(i = 0; req->headers[i] != NULL; i++) free(req->headers[i]);
31 free(req->headers);
32 }
33 if(req->body != NULL) free(req->body);
34 if(req->version != NULL) free(req->version);
35
36 req->method = NULL;
37 req->path = NULL;
38 req->query = NULL;
39 req->headers = NULL;
40 req->body = NULL;
41 req->version = NULL;
42}
43
44int tw_http_parse(SSL* ssl, int sock, struct tw_http_request* req) {
45 char buffer[512];
46 char cbuf[2];
47 int phase = 0;
48 fd_set fds;
49
50 bool bad = false;
51
52 cbuf[1] = 0;
53
54 req->method = NULL;
55 req->path = NULL;
56 req->query = NULL;
57 req->headers = NULL;
58 req->body = NULL;
59 req->version = NULL;
60
61 char* header = malloc(1);
62 header[0] = 0;
63 int nl = 0;
64
65 while(1) {
66 FD_ZERO(&fds);
67 FD_SET(sock, &fds);
68 struct timeval tv;
69 tv.tv_sec = 5;
70 tv.tv_usec = 0;
71#ifndef NO_SSL
72 if(ssl == NULL || !SSL_has_pending(ssl)) {
73#endif
74 int n = select(FD_SETSIZE, &fds, NULL, NULL, &tv);
75 if(n <= 0) {
76 cm_log("HTTP", "Timeout, disconncting");
77 free(header);
78 tw_free_request(req);
79 return -1;
80 }
81#ifndef NO_SSL
82 }
83#endif
84 int len = tw_read(ssl, sock, buffer, 512);
85 if(len <= 0) {
86 bad = true;
87 break;
88 }
89 int i;
90 for(i = 0; i < len; i++) {
91 char c = buffer[i];
92 if(phase == 0) {
93 if(c == ' ') {
94 if(req->method == NULL) {
95 tw_free_request(req);
96 bad = true;
97 goto getout;
98 } else {
99 phase++;
100 }
101 } else {
102 if(req->method == NULL) {
103 req->method = malloc(1);
104 req->method[0] = 0;
105 }
106 cbuf[0] = c;
107 char* tmp = req->method;
108 req->method = cm_strcat(tmp, cbuf);
109 free(tmp);
110 }
111 } else if(phase == 1) {
112 if(c == ' ') {
113 if(req->path == NULL) {
114 tw_free_request(req);
115 bad = true;
116 goto getout;
117 } else {
118 phase++;
119 }
120 } else {
121 if(req->path == NULL) {
122 req->path = malloc(1);
123 req->path[0] = 0;
124 }
125 cbuf[0] = c;
126 char* tmp = req->path;
127 req->path = cm_strcat(tmp, cbuf);
128 free(tmp);
129 }
130 } else if(phase == 2) {
131 if(c == '\n') {
132 if(req->version == NULL) {
133 tw_free_request(req);
134 bad = true;
135 goto getout;
136 } else {
137 /* We have Method, Path, Version now */
138
139 if(strcmp(req->version, "HTTP/1.1") != 0 && strcmp(req->version, "HTTP/1.0") != 0) {
140 cm_log("HTTP", "Bad HTTP Version");
141 bad = true;
142 goto getout;
143 }
144
145 int j;
146 char* p = malloc(1);
147 p[0] = 0;
148 for(j = 0; req->path[j] != 0; j++) {
149 if(req->path[j] == '/') {
150 cbuf[0] = '/';
151 for(; req->path[j] != 0 && req->path[j] == '/'; j++)
152 ;
153 j--;
154 } else {
155 cbuf[0] = req->path[j];
156 }
157 char* tmp = p;
158 p = cm_strcat(tmp, cbuf);
159 free(tmp);
160 }
161 free(req->path);
162 req->path = p;
163
164 int incr = 0;
165 p = malloc(1);
166 p[0] = 0;
167 for(j = 0;; j++) {
168 if(req->path[j] == '/' || req->path[j] == 0) {
169 char oldc = req->path[j];
170 cbuf[0] = oldc;
171 req->path[j] = 0;
172
173 char* pth = req->path + incr;
174
175 if(strcmp(pth, "..") == 0) {
176 int k;
177 if(p[strlen(p) - 1] == '/') p[strlen(p) - 1] = 0;
178 for(k = strlen(p) - 1; k >= 0; k--) {
179 if(p[k] == '/') {
180 p[k + 1] = 0;
181 break;
182 }
183 }
184 if(strlen(p) == 0) {
185 free(p);
186 p = cm_strdup("/");
187 }
188 } else if(strcmp(pth, ".") == 0) {
189 } else {
190 char* tmp = p;
191 p = cm_strcat3(tmp, pth, cbuf);
192 free(tmp);
193 }
194
195 incr = j + 1;
196 if(oldc == 0) break;
197 }
198 }
199 free(req->path);
200 req->path = p;
201
202 cm_log("HTTP", "Request: %s %s %s", req->method, req->path, req->version);
203
204 phase++;
205 }
206 } else if(c != '\r') {
207 if(req->version == NULL) {
208 req->version = malloc(1);
209 req->version[0] = 0;
210 }
211 cbuf[0] = c;
212 char* tmp = req->version;
213 req->version = cm_strcat(tmp, cbuf);
214 free(tmp);
215 }
216 } else if(phase == 3) {
217 if(c == '\n') {
218 nl++;
219 if(nl == 2) {
220 phase++;
221 goto getout;
222 } else {
223 if(req->headers == NULL) {
224 req->headers = malloc(sizeof(*req->headers));
225 req->headers[0] = NULL;
226 }
227 int j;
228 for(j = 0; header[j] != 0; j++) {
229 if(header[j] == ':') {
230 header[j] = 0;
231 j++;
232 for(; header[j] != 0 && (header[j] == ' ' || header[j] == '\t'); j++)
233 ;
234 char* kv = header;
235 char* vv = header + j;
236
237 char** old = req->headers;
238 int k;
239 for(k = 0; old[k] != NULL; k++)
240 ;
241 req->headers = malloc(sizeof(*req->headers) * (k + 3));
242 for(k = 0; old[k] != NULL; k++) req->headers[k] = old[k];
243 req->headers[k] = cm_strdup(kv);
244 req->headers[k + 1] = cm_strdup(vv);
245 req->headers[k + 2] = NULL;
246 free(old);
247
248 cm_log("HTTP", "Header: %s: %s", kv, vv);
249
250 break;
251 }
252 }
253 free(header);
254 header = malloc(1);
255 header[0] = 0;
256 }
257 } else if(c != '\r') {
258 nl = 0;
259 cbuf[0] = c;
260 char* tmp = header;
261 header = cm_strcat(tmp, cbuf);
262 free(tmp);
263 }
264 }
265 }
266 }
267getout:
268 free(header);
269 if(bad) {
270 tw_free_request(req);
271 return 1;
272 }
273 char* result = malloc(1);
274 result[0] = 0;
275 int i;
276 for(i = 0; req->path[i] != 0; i++) {
277 if(req->path[i] == '?') {
278 req->path[i] = 0;
279 req->query = cm_strdup(req->path + i + 1);
280 break;
281 }
282 }
283 for(i = 0; req->path[i] != 0; i++) {
284 if(req->path[i] == '%') {
285 if(req->path[i + 1] == 0) continue;
286 cbuf[0] = cm_hex(req->path + i + 1, 2);
287 if(cbuf[0] != '\\') {
288 char* tmp = result;
289 result = cm_strcat(tmp, cbuf);
290 free(tmp);
291 }
292 i += 2;
293 } else if(req->path[i] != '\\') {
294 cbuf[0] = req->path[i];
295 char* tmp = result;
296 result = cm_strcat(tmp, cbuf);
297 free(tmp);
298 }
299 }
300 free(req->path);
301 req->path = result;
302
303 int incr = 0;
304 char* p = malloc(1);
305 p[0] = 0;
306 int j;
307 for(j = 0;; j++) {
308 if(req->path[j] == '/' || req->path[j] == 0) {
309 char oldc = req->path[j];
310 cbuf[0] = oldc;
311 req->path[j] = 0;
312
313 char* pth = req->path + incr;
314
315 if(strcmp(pth, "..") == 0) {
316 int k;
317 if(p[strlen(p) - 1] == '/') p[strlen(p) - 1] = 0;
318 for(k = strlen(p) - 1; k >= 0; k--) {
319 if(p[k] == '/') {
320 p[k + 1] = 0;
321 break;
322 }
323 }
324 if(strlen(p) == 0) {
325 free(p);
326 p = cm_strdup("/");
327 }
328 } else if(strcmp(pth, ".") == 0) {
329 } else {
330 char* tmp = p;
331 p = cm_strcat3(tmp, pth, cbuf);
332 free(tmp);
333 }
334
335 incr = j + 1;
336 if(oldc == 0) break;
337 }
338 }
339 free(req->path);
340 req->path = p;
341 return 0;
342}
Note: See TracBrowser for help on using the repository browser.