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

Last change on this file since 19 was 17, checked in by Nishi, on Sep 14, 2024 at 2:41:07 AM

module system kinda works

  • Property svn:keywords set to Id
File size: 5.2 KB
Line 
1/* $Id: http.c 17 2024-09-13 17:41:07Z nishi $ */
2
3#define SOURCE
4
5#include "tw_http.h"
6
7#include "tw_server.h"
8
9#include <cm_log.h>
10#include <cm_string.h>
11
12#include <stdbool.h>
13#include <stdlib.h>
14#include <string.h>
15
16#ifdef __MINGW32__
17#include <winsock2.h>
18#else
19#include <sys/select.h>
20#endif
21
22void tw_free_request(struct tw_http_request* req) {
23 if(req->method != NULL) free(req->method);
24 if(req->path != NULL) free(req->path);
25 if(req->headers != NULL) {
26 int i;
27 for(i = 0; req->headers[i] != NULL; i++) free(req->headers[i]);
28 free(req->headers);
29 }
30 if(req->body != NULL) free(req->body);
31 if(req->version != NULL) free(req->version);
32}
33
34int tw_http_parse(SSL* ssl, int sock, struct tw_http_request* req) {
35 char buffer[512];
36 char cbuf[2];
37 int phase = 0;
38 fd_set fds;
39
40 bool bad = false;
41
42 cbuf[1] = 0;
43
44 req->method = NULL;
45 req->path = NULL;
46 req->headers = NULL;
47 req->body = NULL;
48 req->version = NULL;
49
50 char* header = malloc(1);
51 header[0] = 0;
52 int nl = 0;
53
54 while(1) {
55 FD_ZERO(&fds);
56 FD_SET(sock, &fds);
57 struct timeval tv;
58 tv.tv_sec = 5;
59 tv.tv_usec = 0;
60 int n = select(FD_SETSIZE, &fds, NULL, NULL, &tv);
61 if(n == 0) break;
62 int len = tw_read(ssl, sock, buffer, 512);
63 if(len <= 0) break;
64 int i;
65 for(i = 0; i < len; i++) {
66 char c = buffer[i];
67 if(phase == 0) {
68 if(c == ' ') {
69 if(req->method == NULL) {
70 tw_free_request(req);
71 bad = true;
72 goto getout;
73 } else {
74 phase++;
75 }
76 } else {
77 if(req->method == NULL) {
78 req->method = malloc(1);
79 req->method[0] = 0;
80 }
81 cbuf[0] = c;
82 char* tmp = req->method;
83 req->method = cm_strcat(tmp, cbuf);
84 free(tmp);
85 }
86 } else if(phase == 1) {
87 if(c == ' ') {
88 if(req->path == NULL) {
89 tw_free_request(req);
90 bad = true;
91 goto getout;
92 } else {
93 phase++;
94 }
95 } else {
96 if(req->path == NULL) {
97 req->path = malloc(1);
98 req->path[0] = 0;
99 }
100 cbuf[0] = c;
101 char* tmp = req->path;
102 req->path = cm_strcat(tmp, cbuf);
103 free(tmp);
104 }
105 } else if(phase == 2) {
106 if(c == '\n') {
107 if(req->version == NULL) {
108 tw_free_request(req);
109 bad = true;
110 goto getout;
111 } else {
112 /* We have Method, Path, Version now */
113
114 if(strcmp(req->version, "HTTP/1.1") != 0 && strcmp(req->version, "HTTP/1.0") != 0) {
115 cm_log("HTTP", "Bad HTTP Version");
116 bad = true;
117 goto getout;
118 }
119
120 int j;
121 char* p = malloc(1);
122 p[0] = 0;
123 for(j = 0; req->path[j] != 0; j++) {
124 if(req->path[j] == '/') {
125 cbuf[0] = '/';
126 for(; req->path[j] != 0 && req->path[j] == '/'; j++)
127 ;
128 j--;
129 } else {
130 cbuf[0] = req->path[j];
131 }
132 char* tmp = p;
133 p = cm_strcat(tmp, cbuf);
134 free(tmp);
135 }
136 free(req->path);
137 req->path = p;
138
139 int incr = 0;
140 p = malloc(1);
141 p[0] = 0;
142 for(j = 0;; j++) {
143 if(req->path[j] == '/' || req->path[j] == 0) {
144 char oldc = req->path[j];
145 cbuf[0] = oldc;
146 req->path[j] = 0;
147
148 char* pth = req->path + incr;
149
150 if(strcmp(pth, "..") == 0) {
151 int k;
152 if(p[strlen(p) - 1] == '/') p[strlen(p) - 1] = 0;
153 for(k = strlen(p) - 1; k >= 0; k--) {
154 if(p[k] == '/') {
155 p[k + 1] = 0;
156 break;
157 }
158 }
159 if(strlen(p) == 0) {
160 free(p);
161 p = cm_strdup("/");
162 }
163 } else if(strcmp(pth, ".") == 0) {
164 } else {
165 char* tmp = p;
166 p = cm_strcat3(tmp, pth, cbuf);
167 free(tmp);
168 }
169
170 incr = j + 1;
171 if(oldc == 0) break;
172 }
173 }
174 free(req->path);
175 req->path = p;
176
177 cm_log("HTTP", "Request: %s %s %s", req->method, req->path, req->version);
178
179 phase++;
180 }
181 } else if(c != '\r') {
182 if(req->version == NULL) {
183 req->version = malloc(1);
184 req->version[0] = 0;
185 }
186 cbuf[0] = c;
187 char* tmp = req->version;
188 req->version = cm_strcat(tmp, cbuf);
189 free(tmp);
190 }
191 } else if(phase == 3) {
192 if(c == '\n') {
193 nl++;
194 if(nl == 2) {
195 phase++;
196 goto getout;
197 } else {
198 if(req->headers == NULL) {
199 req->headers = malloc(sizeof(*req->headers));
200 req->headers[0] = NULL;
201 }
202 int j;
203 for(j = 0; header[j] != 0; j++) {
204 if(header[j] == ':') {
205 header[j] = 0;
206 j++;
207 for(; header[j] != 0 && (header[j] == ' ' || header[j] == '\t'); j++)
208 ;
209 char* kv = header;
210 char* vv = header + j;
211
212 char** old = req->headers;
213 int k;
214 for(k = 0; old[k] != NULL; k++)
215 ;
216 req->headers = malloc(sizeof(*req->headers) * (k + 3));
217 for(k = 0; old[k] != NULL; k++) req->headers[k] = old[k];
218 req->headers[k] = cm_strdup(kv);
219 req->headers[k + 1] = cm_strdup(vv);
220 req->headers[k + 2] = NULL;
221 free(old);
222
223 cm_log("HTTP", "Header: %s: %s", kv, vv);
224
225 break;
226 }
227 }
228 free(header);
229 header = malloc(1);
230 header[0] = 0;
231 }
232 } else if(c != '\r') {
233 nl = 0;
234 cbuf[0] = c;
235 char* tmp = header;
236 header = cm_strcat(tmp, cbuf);
237 free(tmp);
238 }
239 }
240 }
241 }
242getout:
243 free(header);
244 if(bad) {
245 tw_free_request(req);
246 return 1;
247 }
248 return 0;
249}
Note: See TracBrowser for help on using the repository browser.