src/server/httprequest.c

changeset 14
b8bf95b39952
parent 13
1fdbf4170ef4
child 15
cff9c4101dd7
equal deleted inserted replaced
13:1fdbf4170ef4 14:b8bf95b39952
1 /*
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3 *
4 * Copyright 2011 Olaf Wintermann. All rights reserved.
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
33 #include "nsapi.h"
34 #include "pool.h"
35 #include "pblock.h"
36 #include "io.h"
37 #include "util.h"
38 #include "httprequest.h"
39 #include "conf.h"
40 #include "vserver.h"
41
42 HTTPRequest *http_request_new() {
43 HTTPRequest *req = malloc(sizeof(HTTPRequest));
44 req->connection = NULL;
45 req->uri.ptr = NULL;
46
47 HeaderArray *hd = malloc(sizeof(HeaderArray));
48 hd->next = NULL;
49 hd->len = 0;
50 hd->headers = calloc(16, sizeof(Header));
51 hd->alloc = 16;
52
53 req->headers = hd;
54
55 return req;
56 }
57
58 int handle_request(HTTPRequest *request) {
59 // handle nsapi request
60
61 // create pool
62 request->pool = pool_create();
63
64 // create nsapi data structures
65 NSAPISession *sn = malloc(sizeof(NSAPISession));
66 NSAPIRequest *rq = malloc(sizeof(NSAPIRequest));
67 request->rq = rq;
68 rq->phase = NSAPIAuthTrans;
69
70 // fill session structure
71 sn->sys_fd = request->connection->fd;
72 sn->sn.pool = pool_create();
73 sn->sn.csd = stream_new_from_fd(request->connection->fd);
74 sn->sn.client = pblock_create_pool(sn->sn.pool, 8);
75 sn->sn.next = NULL;
76 sn->sn.fill = 1;
77 sn->sn.subject = NULL;
78
79 /* add ip to sn->client pblock */
80 char ip_str[INET_ADDRSTRLEN];
81 if(inet_ntop(
82 AF_INET,
83 &request->connection->address.sin_addr,
84 ip_str,
85 INET_ADDRSTRLEN) != NULL)
86 {
87 pblock_kvinsert(pb_key_ip, ip_str, INET_ADDRSTRLEN, sn->sn.client);
88 }
89
90 // init NSAPI request structure
91 if(request_initialize(request->pool, request, rq) != 0) {
92 printf("Cannot initialize request structure\n");
93 return 1;
94 }
95
96 // set default virtual server
97 rq->vs = conf_get_default_vs();
98
99
100 /* Pass request line as "clf-request" */
101 pblock_kvinsert(
102 pb_key_clf_request,
103 request->request_line.ptr,
104 request->request_line.length,
105 rq->rq.reqpb);
106
107 /* Pass method as "method" in reqpb, and also as method_num */
108 pblock_kvinsert(
109 pb_key_method,
110 request->method.ptr,
111 request->method.length,
112 rq->rq.reqpb);
113 // TODO: method num
114 //rqRq.rq.method_num = rqHdr->GetMethodNumber();
115 //PR_ASSERT(rqRq.rq.method_num != -1 || iStatus);
116
117 /* Pass protocol as "protocol" in reqpb, and also in protv_num */
118 pblock_kvinsert(
119 pb_key_protocol,
120 request->httpv.ptr,
121 request->httpv.length,
122 rq->rq.reqpb);
123 // TODO: protocol num
124
125 /* Pass any query as "query" in reqpb */
126 // TODO: query
127
128 /* Get abs_path part of request URI, and canonicalize the path */
129 sstr_t absPath = request->uri;
130 // TODO: get abs_path
131 absPath.ptr = util_canonicalize_uri(
132 request->pool,
133 absPath.ptr,
134 absPath.length,
135 (int*)&absPath.length);
136
137 /* Decode the abs_path */
138 // TODO: decode abs_path
139
140 /* Pass the abs_path as "uri" in reqpb */
141 // TODO: pass abs_path to reqpb
142 // TODO: replace this code
143 pblock_kvinsert(
144 pb_key_uri,
145 absPath.ptr,
146 absPath.length,
147 rq->rq.reqpb);
148
149 // pass http header to the NSAPI request structure
150 int hlen = request->headers->len;
151 HeaderArray *ha = request->headers;
152 for(int i=0;i<=hlen;i++) {
153 if(i == hlen) {
154 ha = ha->next;
155 if(ha == NULL) {
156 break;
157 }
158 i = 0;
159 hlen = ha->len;
160 }
161
162 if(ha->headers[i].name[0] < 90) {
163 ha->headers[i].name[0] += 32;
164 }
165 pblock_nvinsert(ha->headers[i].name, ha->headers[i].value, rq->rq.headers);
166 }
167
168 /* check for request body and prepare input buffer */
169 char *ctlen_str = pblock_findkeyval(pb_key_content_length, rq->rq.headers);
170 if(ctlen_str) {
171 int ctlen = atoi(ctlen_str);
172
173 printf("request body length: %d\n", ctlen);
174
175 netbuf *nb = request->netbuf;
176
177 /* create new netbuf */
178 NetIOStream *net_io = (NetIOStream*)net_stream_from_fd(
179 request->connection->fd);
180 net_io->max_read = ctlen;
181
182 sn->sn.inbuf = malloc(sizeof(netbuf));
183 sn->sn.inbuf->sd = net_io;
184 sn->sn.inbuf->pos = 0;
185
186 /* prepare buffer */
187 int cur_input_len = nb->cursize - nb->pos;
188 if(cur_input_len >= ctlen) {
189
190 /*
191 * all data is already in the primary input buffer
192 * just link the new netbuf to the primary buffer
193 */
194 sn->sn.inbuf->maxsize = ctlen;
195 sn->sn.inbuf->cursize = ctlen;
196 sn->sn.inbuf->inbuf = nb->inbuf + nb->pos;
197 } else {
198 sn->sn.inbuf->maxsize = (ctlen > 2048) ? (2048) : (ctlen);
199 sn->sn.inbuf->inbuf = malloc(sizeof(sn->sn.inbuf->maxsize));
200
201 if(cur_input_len > 0) {
202 /* we have read a part of the request body -> copy to netbuf */
203 memcpy(sn->sn.inbuf->inbuf, nb->inbuf+nb->pos, cur_input_len);
204 }
205
206 sn->sn.inbuf->cursize = cur_input_len;
207 }
208 } else {
209 sn->sn.inbuf = NULL;
210 }
211
212
213 // Send the request to the NSAPI system
214 nsapi_handle_request(sn, rq);
215
216 return 0;
217 }
218
219
220
221 void header_add(HeaderArray *hd, char *name, char *value) {
222 while(hd->len >= hd->alloc) {
223 if(hd->next == NULL) {
224 HeaderArray *block = malloc(sizeof(HeaderArray));
225 block->next = NULL;
226 block->len = 0;
227 block->headers = calloc(16, sizeof(Header));
228 block->alloc = 16;
229 hd->next = block;
230 }
231 hd = hd->next;
232 }
233 hd->headers[hd->len].name = name;
234 hd->headers[hd->len].value = value;
235 hd->len++;
236 }
237
238
239 /*
240 * NSAPI Processing
241 * TODO: add this to new file
242 */
243
244 int nsapi_handle_request(NSAPISession *sn, NSAPIRequest *rq) {
245 // TODO: threadpool
246
247 int r = REQ_NOACTION;
248
249 do {
250 switch(rq->phase) {
251 case NSAPIAuthTrans: {
252 rq->phase++;
253 nsapi_context_next_stage(&rq->context);
254 }
255 case NSAPINameTrans: {
256 printf(">>> NameTrans\n");
257 r = nsapi_nametrans(sn, rq);
258 if(r != REQ_PROCEED) {
259 break;
260 }
261 rq->phase++;
262 nsapi_context_next_stage(&rq->context);
263 }
264 case NSAPIPathCheck: {
265 printf(">>> PathCheck\n");
266 rq->phase++;
267 nsapi_context_next_stage(&rq->context);
268 }
269 case NSAPIObjectType: {
270 printf(">>> ObjectType\n");
271 r = nsapi_objecttype(sn, rq);
272 if(r != REQ_PROCEED) {
273 break;
274 }
275 rq->phase++;
276 nsapi_context_next_stage(&rq->context);
277 }
278 case NSAPIService: {
279 printf(">>> Service\n");
280 r = nsapi_service(sn, rq);
281 if(r != REQ_PROCEED) {
282 break;
283 }
284 rq->phase++;
285 nsapi_context_next_stage(&rq->context);
286 }
287 case NSAPIAddLog: {
288 printf(">>> AddLog\n");
289 rq->phase++;
290 nsapi_context_next_stage(&rq->context);
291 }
292 case REQ_FINISH: {
293 printf(">>> Finish\n");
294 r = nsapi_finish_request(sn, rq);
295 }
296 }
297 } while (r == REQ_RESTART);
298
299
300 return r;
301 }
302
303 int nsapi_finish_request(NSAPISession *sn, NSAPIRequest *rq) {
304 // TODO: free memory
305 close(sn->sys_fd);
306
307 return 0;
308 }
309
310 int nsapi_nametrans(NSAPISession *sn, NSAPIRequest *rq) {
311 HTTPObjectConfig *objconf = rq->vs->objects;
312 printf("nsapi_nametrans\n");
313 httpd_objset *objset = objset_create(sn->sn.pool);
314 rq->rq.os = objset;
315 /* first object in objconf is the default object TODO: make sure it is */
316 objset_add_object(sn->sn.pool, objset, objconf->objects[0]);
317
318 httpd_object *obj = objset->obj[0]; /* nametrans only in default object */
319 dtable *dt = object_get_dtable(obj, NSAPINameTrans);
320
321 /* execute directives */
322 int ret = rq->context.last_req_code;
323 char *name = NULL;
324 char *ppath = NULL;
325 for(int i=NCX_DI(rq);i<dt->ndir;i++) {
326 directive *d = dt->dirs[i];
327
328 ret = d->func->func(d->param, (Session*)sn, (Request*)rq);
329
330 /* check for name or ppath */
331 name = pblock_findkeyval(pb_key_name, rq->rq.vars);
332 ppath = pblock_findkeyval(pb_key_ppath, rq->rq.vars);
333
334 /* add additional objects to the objset */
335 if(add_objects(objconf, objset, sn, rq, name, ppath) == REQ_ABORTED) {
336 fprintf(stderr, "add_objects failed\n");
337 return REQ_ABORTED;
338 }
339
340 if(ret != REQ_NOACTION) {
341 /*
342 * if a saf is still processing, we need to save the context, to
343 * process this object at a later time
344 */
345 if(ret == REQ_PROCESSING) {
346 /* save nsapi context */
347 /* add +1 to start next round with next function */
348 rq->context.dtable_index = i + 1;
349 }
350
351 return ret;
352 }
353 }
354
355 /* if no function has set the ppath var, translate it to docroot */
356 if(ret == REQ_NOACTION && ppath == NULL) {
357 sstr_t docroot = rq->vs->document_root;
358 if(docroot.length < 1) {
359 printf("docroot too short\n");
360 return REQ_ABORTED; /* docroot too short */
361 }
362 /* if there is a trailing '/', remove it */
363 if(docroot.ptr[docroot.length - 1] == '/') {
364 docroot.length--;
365 }
366
367 sstr_t uri = sstr(pblock_findkeyval(pb_key_uri, rq->rq.reqpb));
368
369 sstr_t translated;
370 translated.length = docroot.length + uri.length;
371 translated.ptr = alloca(translated.length + 1);
372 translated = sstrncat(2, translated, docroot, uri);
373
374 pblock_kvinsert(
375 pb_key_ppath,
376 translated.ptr,
377 translated.length,
378 rq->rq.vars);
379 }
380
381 return REQ_PROCEED;
382 }
383
384 int nsapi_objecttype(NSAPISession *sn, NSAPIRequest *rq) {
385 printf("nsapi_objecttype\n");
386 httpd_objset *objset = rq->rq.os;
387
388 if(NCX_OI(rq) == -1) {
389 /* object index is undefined -> define correct object index */
390 NCX_OI(rq) = objset->pos - 1;
391 }
392
393 int ret = rq->context.last_req_code;
394 for(int i=NCX_OI(rq);i>=0;i--) {
395 httpd_object *obj = objset->obj[i];
396 dtable *dt = object_get_dtable(obj, NSAPIObjectType);
397
398 // execute directives
399 for(int j=0;j<dt->ndir;j++) {
400 directive *d = dt->dirs[j];
401
402 ret = d->func->func(d->param, (Session*)sn, (Request*)rq);
403 switch(ret) {
404 case REQ_PROCEED: {
405 char *type = pblock_findkeyval(
406 pb_key_content_type,
407 rq->rq.srvhdrs);
408 if(type == NULL) {
409 ret = REQ_NOACTION;
410 break;
411 }
412 return ret;
413 }
414 case REQ_PROCESSING: {
415 /* save nsapi context */
416 rq->context.objset_index = i;
417
418 /* add +1 to start next round with next function */
419 rq->context.dtable_index = j + 1;
420 return ret;
421 }
422 case REQ_NOACTION: {
423 break;
424 }
425 default: {
426 return ret;
427 }
428 }
429 }
430 }
431
432 /*
433 * No function returned with REQ_PROCEED, but we need a content type.
434 * If the path ends with a '/', we set the content type to
435 * 'internal/directory' so that 'index-common' can serve the content.
436 * Otherwise we set the content type to text/plain
437 */
438 sstr_t path = sstr(pblock_findkeyval(pb_key_ppath, rq->rq.vars));
439 sstr_t ct;
440 if(path.ptr[path.length - 1] == '/') {
441 /* directory */
442 ct = sstrn("internal/directory", 18);
443 } else {
444 ct = sstrn("text/plain", 10);
445 }
446 pblock_kvinsert(pb_key_content_type, ct.ptr, ct.length, rq->rq.srvhdrs);
447
448 return REQ_PROCEED;
449 }
450
451 int nsapi_service(NSAPISession *sn, NSAPIRequest *rq) {
452 printf("nsapi_service\n");
453 httpd_objset *objset = rq->rq.os;
454
455 if(NCX_OI(rq) == -1) {
456 NCX_OI(rq) = objset->pos - 1;
457 }
458
459 int ret = rq->context.last_req_code;
460 char *content_type = NULL;
461 for(int i=NCX_OI(rq);i>=0;i--) {
462 httpd_object *obj = objset->obj[i];
463 dtable *dt = object_get_dtable(obj, NSAPIService);
464
465 // execute directives
466 for(int j=0;j<dt->ndir;j++) {
467 directive *d = dt->dirs[j];
468
469 /* check type parameter */
470 char *dtp = pblock_findkeyval(pb_key_type, d->param);
471 if(dtp) {
472 /* type parameter for directive */
473 if(!content_type) {
474 content_type = pblock_findkeyval(
475 pb_key_content_type,
476 rq->rq.srvhdrs);
477 }
478 /* compare types */
479 if(strcmp(dtp, content_type) != 0) {
480 continue;
481 }
482 }
483
484 ret = d->func->func(d->param, (Session*)sn, (Request*)rq);
485 if(ret != REQ_NOACTION) {
486 if(ret == REQ_PROCESSING) {
487 /* save nsapi context */
488 rq->context.objset_index = i;
489
490 /* add +1 to start next round with next function */
491 rq->context.dtable_index = j + 1;
492 }
493
494 return ret;
495 }
496 }
497 }
498
499 return ret;
500 }
501
502 /*
503 * adds objects with specific name or path to the httpd_objset
504 */
505 int add_objects(
506 HTTPObjectConfig *objs,
507 httpd_objset *os,
508 NSAPISession *sn,
509 NSAPIRequest *rq,
510 char *name,
511 char *path)
512 {
513 /* first, add all objects with a matching path */
514 /* TODO */
515
516
517 /* add object with object with matching name */
518 if(name == NULL) {
519 return REQ_PROCEED;
520 }
521
522 for(int i=0;i<objs->nobj;i++) {
523 httpd_object *obj = objs->objects[i];
524
525 if(obj->name && !strcmp(name, obj->name)) {
526 printf("name is %s -> add object %s\n", name, obj->name);
527 objset_add_object(sn->sn.pool, os, obj);
528 }
529 }
530
531 return REQ_PROCEED;
532 }

mercurial