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

Last change on this file since 16 was 16, checked in by Nishi, on Sep 14, 2024 at 12:09:52 AM

can parse http now

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