1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <limits.h>
32
33 #include <arpa/inet.h>
34
35 #include "../public/nsapi.h"
36 #include "../util/pool.h"
37 #include "../util/pblock.h"
38 #include "../util/io.h"
39 #include "../util/util.h"
40 #include "httprequest.h"
41 #include "config.h"
42 #include "vserver.h"
43 #include "event.h"
44 #include "httplistener.h"
45 #include "func.h"
46 #include "error.h"
47
48 void http_request_init(HTTPRequest *req) {
49 memset(req,
0,
sizeof(HTTPRequest));
50
51 HeaderArray *hd = malloc(
sizeof(HeaderArray));
52 hd->next =
NULL;
53 hd->len =
0;
54 hd->headers = calloc(
16,
sizeof(Header));
55 hd->alloc =
16;
56
57 req->headers = hd;
58
59 req->req_start = time(
NULL);
60 }
61
62 void http_request_cleanup(HTTPRequest *req) {
63 header_array_free(req->headers);
64 free(req);
65 }
66
67 sstr_t http_request_get_abspath(HTTPRequest *req) {
68 sstr_t uri = req->uri;
69
70 int i =
0;
71 if(uri.ptr[
0] ==
'/') {
72 return uri;
73 }
else if(sstrprefix(uri,
S(
"http://"))) {
74 i =
7;
75 }
else if(sstrprefix(uri,
S(
"https://"))) {
76 i =
8;
77 }
else if(!sstrcmp(uri,
S(
"*"))) {
78 return uri;
79 }
80
81 for(;i<uri.length;i++) {
82 if(uri.ptr[i] ==
'/') {
83 return sstrsubs(uri, i);
84 }
85 }
86
87 return S(
"/");
88 }
89
90 int handle_request(HTTPRequest *request,
threadpool_t *thrpool, EventHandler *ev) {
91
92
93
94 pool_handle_t *pool = pool_create();
95
96
97 NSAPISession *sn = pool_malloc(pool,
sizeof(NSAPISession));
98 if(sn ==
NULL) {
99
100 }
101 ZERO(sn,
sizeof(NSAPISession));
102 NSAPIRequest *rq = pool_malloc(pool,
sizeof(NSAPIRequest));
103 if(rq ==
NULL) {
104
105 }
106 ZERO(rq,
sizeof(NSAPIRequest));
107 rq->rq.req_start = request->req_start;
108 rq->phase = NSAPIAuthTrans;
109
110
111 sn->connection = request->connection;
112 sn->netbuf = request->netbuf;
113 sn->sn.pool = pool;
114 SessionHandler *sh = request->connection->session_handler;
115 WSBool ssl;
116 IOStream *io = sh->create_iostream(sh, request->connection, pool, &ssl);
117 sn->sn.csd = httpstream_new(pool, io);
118 sn->sn.ssl = ssl;
119
120 sn->sn.client = pblock_create_pool(sn->sn.pool,
8);
121 sn->sn.next =
NULL;
122 sn->sn.fill =
1;
123 sn->sn.subject =
NULL;
124
125 if(!ev) {
126 ev = ev_instance(get_default_event_handler());
127 }
128 sn->sn.ev = ev;
129
130
131 sn->config = request->connection->listener->cfg;
132
133
134 char ip_str[
INET_ADDRSTRLEN];
135 if(inet_ntop(
136 AF_INET,
137 &request->connection->address.sin_addr,
138 ip_str,
139 INET_ADDRSTRLEN) !=
NULL)
140 {
141 pblock_kvinsert(pb_key_ip, ip_str,
INET_ADDRSTRLEN, sn->sn.client);
142 }
143
144
145 if(request_initialize(pool, request, rq) !=
0) {
146 log_ereport(
LOG_FAILURE,
"Cannot initialize request structure");
147 pool_destroy(pool);
148 return 1;
149 }
150
151
152 rq->vs = request->connection->listener->default_vs.vs;
153
154
155
156 sstr_t clfreq = request->request_line;
157 while(clfreq.length >
0 && clfreq.ptr[clfreq.length -
1] <
33) {
158 clfreq.length--;
159 }
160 pblock_kvinsert(
161 pb_key_clf_request,
162 clfreq.ptr,
163 clfreq.length,
164 rq->rq.reqpb);
165
166
167 pblock_kvinsert(
168 pb_key_method,
169 request->method.ptr,
170 request->method.length,
171 rq->rq.reqpb);
172
173
174
175
176
177 pblock_kvinsert(
178 pb_key_protocol,
179 request->httpv.ptr,
180 request->httpv.length,
181 rq->rq.reqpb);
182
183 if(!sstrcmp(request->httpv,
S(
"HTTP/1.1"))) {
184 rq->rq.protv_num =
PROTOCOL_VERSION_HTTP11;
185 }
else if(!sstrcmp(request->httpv,
S(
"HTTP/1.0"))) {
186 rq->rq.protv_num =
PROTOCOL_VERSION_HTTP10;
187 }
else {
188
189 log_ereport(
190 LOG_FAILURE,
191 "invalid protocol version: %.*s",
192 (
int)request->httpv.length,
193 request->httpv.ptr);
194 pool_destroy(pool);
195 return 1;
196 }
197
198
199
200
201
202 sstr_t absPath = http_request_get_abspath(request);
203 if(!absPath.ptr) {
204
205 return 1;
206 }
else if(absPath.ptr[
0] ==
'*') {
207
208 return 1;
209 }
210
211 sstr_t query;
212 query.length =
0;
213
214 for(
int i=
0;i<request->uri.length;i++) {
215 if(request->uri.ptr[i] ==
'?') {
216
217 if(absPath.length > i +
2) {
218 query.length = absPath.length - i -
1;
219 query.ptr = absPath.ptr + i +
1;
220 }
221 absPath.length = i;
222
223
224 pblock_kvinsert(
225 pb_key_query,
226 query.ptr,
227 query.length,
228 rq->rq.reqpb);
229
230 break;
231 }
232 }
233
234
235 sstr_t orig_path = absPath;
236 absPath.ptr = util_canonicalize_uri(
237 pool,
238 absPath.ptr,
239 absPath.length,
240 (
int*)&absPath.length);
241 if(!absPath.ptr) {
242 log_ereport(
243 LOG_WARN,
244 "invalid request path: {%.*s}",
245 (
int)orig_path.length,
246 orig_path.ptr);
247 pool_destroy(pool);
248
249 return 1;
250 }
251
252
253 if(util_uri_unescape_strict(absPath.ptr)) {
254
255 pblock_kvinsert(
256 pb_key_uri,
257 absPath.ptr,
258 absPath.length,
259 rq->rq.reqpb);
260 }
else {
261
262 log_ereport(
263 LOG_WARN,
264 "uri unescape failed: {%.*s}",
265 (
int)absPath.length,
266 absPath.ptr);
267
268 pblock_kvinsert(pb_key_uri,
"/",
1, rq->rq.reqpb);
269 }
270
271
272 int hlen = request->headers->len;
273 HeaderArray *ha = request->headers;
274 for(
int i=
0;i<=hlen;i++) {
275 if(i == hlen) {
276 ha = ha->next;
277 if(ha ==
NULL) {
278 break;
279 }
280 i =
0;
281 hlen = ha->len;
282 }
283
284 Header header = ha->headers[i];
285
286 if(header.name.ptr[
0] <
90) {
287 header.name.ptr[
0] +=
32;
288 }
289
290
291 for(
int j=
0;j<header.name.length;j++) {
292 if(header.name.ptr[j] >
64 && header.name.ptr[j] <
97) {
293 header.name.ptr[j] +=
32;
294 }
295 }
296
297 pblock_nvlinsert(
298 header.name.ptr,
299 header.name.length,
300 header.value.ptr,
301 header.value.length,
302 rq->rq.headers);
303 }
304
305
306 char *hosthdr = pblock_findkeyval(pb_key_host, rq->rq.headers);
307 if(hosthdr) {
308 char *host = pool_strdup(pool, hosthdr);
309 char *portstr = strchr(host,
':');
310 if(portstr) {
311 *portstr =
'\0';
312 }
313 rq->host = host;
314 }
else {
315 rq->host =
NULL;
316 }
317 rq->port = request->connection->listener->port;
318
319 if(rq->host) {
320 VirtualServer *vs = ucx_map_cstr_get(sn->config->host_vs, rq->host);
321 if(vs) {
322 rq->vs = vs;
323 }
else {
324 log_ereport(
325 LOG_VERBOSE,
326 "Unkown host ''%s'': using default virtual server",
327 rq->host);
328 }
329 }
330
331
332 rq->rq.rq_attr.keep_alive = (rq->rq.protv_num >=
PROTOCOL_VERSION_HTTP11);
333 char *conn_str = pblock_findkeyval(pb_key_connection, rq->rq.headers);
334 if(conn_str) {
335 if(!strcasecmp(conn_str,
"keep-alive")) {
336 rq->rq.rq_attr.keep_alive =
1;
337 }
else if(!strcasecmp(conn_str,
"close")) {
338 rq->rq.rq_attr.keep_alive =
0;
339 }
340 }
341
342
343 char *ctlen_str = pblock_findkeyval(pb_key_content_length, rq->rq.headers);
344 if(ctlen_str) {
345 int ctlen = atoi(ctlen_str);
346
347
348
349 netbuf *nb = request->netbuf;
350
351
352 HttpStream *net_io = (HttpStream*)httpstream_new(pool, io);
353 net_io->max_read = ctlen;
354
355 sn->sn.inbuf = pool_malloc(pool,
sizeof(netbuf));
356 sn->sn.inbuf->sd = net_io;
357 sn->sn.inbuf->pos =
0;
358
359
360 int cur_input_len = nb->cursize - nb->pos;
361
362 if(cur_input_len >= ctlen) {
363
364
365
366
367 sn->sn.inbuf->maxsize = ctlen;
368 sn->sn.inbuf->cursize = ctlen;
369 sn->sn.inbuf->inbuf = nb->inbuf + nb->pos;
370 }
else {
371 sn->sn.inbuf->maxsize = (ctlen >
2048) ? (
2048) : (ctlen);
372 sn->sn.inbuf->inbuf = pool_malloc(pool, sn->sn.inbuf->maxsize);
373
374 if(cur_input_len >
0) {
375
376 memcpy(sn->sn.inbuf->inbuf, nb->inbuf+nb->pos, cur_input_len);
377 }
378
379 sn->sn.inbuf->cursize = cur_input_len;
380 }
381 }
else {
382 sn->sn.inbuf =
NULL;
383 }
384
385
386
387
388
389
390 threadpool_t *lstp = request->connection->listener->threadpool;
391 sn->defaultpool = lstp;
392 if(lstp == thrpool) {
393 sn->currentpool = thrpool;
394 nsapi_handle_request(sn, rq);
395 }
else {
396
397 nsapi_change_threadpool(sn, rq, lstp);
398 }
399
400 return 0;
401 }
402
403
404
405 void header_add(HeaderArray *hd,
sstr_t name,
sstr_t value) {
406 while(hd->len >= hd->alloc) {
407 if(hd->next ==
NULL) {
408 HeaderArray *block = malloc(
sizeof(HeaderArray));
409 block->next =
NULL;
410 block->len =
0;
411 block->headers = calloc(
16,
sizeof(Header));
412 block->alloc =
16;
413 hd->next = block;
414 }
415 hd = hd->next;
416 }
417 hd->headers[hd->len].name = name;
418 hd->headers[hd->len].value = value;
419 hd->len++;
420 }
421
422 void header_array_free(HeaderArray *hd) {
423 HeaderArray *next;
424 while(hd) {
425 next = hd->next;
426 free(hd->headers);
427 free(hd);
428 hd = next;
429 }
430 }
431
432
433
434
435
436
437 int nsapi_handle_request(NSAPISession *sn, NSAPIRequest *rq) {
438 int r =
REQ_NOACTION;
439 do {
440 switch(rq->phase) {
441 case NSAPIAuthTrans: {
442 r = nsapi_authtrans(sn, rq);
443 if(r !=
REQ_PROCEED) {
444 break;
445 }
446 rq->phase++;
447 nsapi_context_next_stage(&rq->context);
448 }
449 case NSAPINameTrans: {
450
451 r = nsapi_nametrans(sn, rq);
452 if(r !=
REQ_PROCEED) {
453 break;
454 }
455 rq->phase++;
456 nsapi_context_next_stage(&rq->context);
457 }
458 case NSAPIPathCheck: {
459
460 r = nsapi_pathcheck(sn, rq);
461 if(r !=
REQ_PROCEED) {
462 break;
463 }
464 rq->phase++;
465 nsapi_context_next_stage(&rq->context);
466 }
467 case NSAPIObjectType: {
468
469 r = nsapi_objecttype(sn, rq);
470 if(r !=
REQ_PROCEED) {
471 break;
472 }
473 rq->phase++;
474 nsapi_context_next_stage(&rq->context);
475 }
476 case NSAPIService: {
477
478 r = nsapi_service(sn, rq);
479 if(r !=
REQ_PROCEED) {
480 break;
481 }
482 rq->phase = NSAPIAddLog;
483 nsapi_context_next_stage(&rq->context);
484 }
485 case NSAPIAddLog: {
486
487 r = nsapi_addlog(sn, rq);
488 if(r ==
REQ_PROCESSING) {
489 break;
490 }
491
492 r =
REQ_PROCEED;
493 break;
494 }
495 default:
496 case REQ_FINISH: {
497
498
499 r =
REQ_PROCEED;
500 break;
501 }
502 case NSAPIError: {
503
504 r = nsapi_error(sn, rq);
505 if(r ==
REQ_PROCEED) {
506
507 r =
REQ_RESTART;
508 rq->phase = NSAPIAddLog;
509 nsapi_context_next_stage(&rq->context);
510 }
else {
511
512
513
514
515 r =
REQ_PROCEED;
516 break;
517 }
518 }
519 }
520
521 if(r ==
REQ_ABORTED) {
522
523 rq->phase = NSAPIError;
524 nsapi_context_next_stage(&rq->context);
525 r =
REQ_RESTART;
526 }
527
528 }
while (r ==
REQ_RESTART);
529
530 if(r !=
REQ_PROCESSING) {
531 r = nsapi_finish_request(sn, rq);
532 }
533
534 return r;
535 }
536
537 int nsapi_finish_request(NSAPISession *sn, NSAPIRequest *rq) {
538 if(rq->rq.rq_attr.keep_alive) {
539 SessionHandler *sh = sn->connection->session_handler;
540 sh->keep_alive(sh, sn->connection);
541
542
543
544
545
546 }
else {
547 connection_destroy(sn->connection);
548 cfg_unref(sn->config);
549 }
550
551
552 free(sn->netbuf->inbuf);
553 free(sn->netbuf);
554
555 pool_destroy(sn->sn.pool);
556
557 return 0;
558 }
559
560 int nsapi_authtrans(NSAPISession *sn, NSAPIRequest *rq) {
561 HTTPObjectConfig *objconf = rq->vs->objects;
562 httpd_object *obj = objconf->objects[
0];
563 dtable *dt = object_get_dtable(obj, NSAPIAuthTrans);
564
565 int ret = rq->context.last_req_code;
566 for(
int i=
NCX_DI(rq);i<dt->ndir;i++) {
567 if(ret ==
REQ_NOACTION) {
568 directive *d = dt->dirs[i];
569 ret = nsapi_exec(d, sn, rq);
570 }
571
572 if(ret !=
REQ_NOACTION) {
573
574
575
576
577 if(ret ==
REQ_PROCESSING) {
578
579
580 rq->context.dtable_index = i +
1;
581 }
582
583 return ret;
584 }
585 }
586
587
588 return REQ_PROCEED;
589 }
590
591 int nsapi_nametrans(NSAPISession *sn, NSAPIRequest *rq) {
592 HTTPObjectConfig *objconf = rq->vs->objects;
593
594 httpd_objset *objset = objset_create(sn->sn.pool);
595 rq->rq.os = objset;
596
597 objset_add_object(sn->sn.pool, objset, objconf->objects[
0]);
598
599 httpd_object *obj = objset->obj[
0];
600 dtable *dt = object_get_dtable(obj, NSAPINameTrans);
601
602
603 int ret = rq->context.last_req_code;
604 char *name =
NULL;
605 char *ppath =
NULL;
606 for(
int i=
NCX_DI(rq);i<dt->ndir;i++) {
607 if(ret ==
REQ_NOACTION) {
608 directive *d = dt->dirs[i];
609 ret = nsapi_exec(d, sn, rq);
610 }
611
612
613 name = pblock_findkeyval(pb_key_name, rq->rq.vars);
614 ppath = pblock_findkeyval(pb_key_ppath, rq->rq.vars);
615
616
617 if(add_objects(objconf, objset, sn, rq, name, ppath) ==
REQ_ABORTED) {
618 log_ereport(
LOG_FAILURE,
"add_objects failed");
619 return REQ_ABORTED;
620 }
621
622 if(ret !=
REQ_NOACTION) {
623
624
625
626
627 if(ret ==
REQ_PROCESSING) {
628
629
630 rq->context.dtable_index = i +
1;
631 }
else if(ret ==
REQ_PROCEED) {
632 char *pp = pblock_findkeyval(pb_key_ppath, rq->rq.vars);
633 pblock_kvinsert(pb_key_path, pp, strlen(pp), rq->rq.vars);
634 }
635
636 return ret;
637 }
638 }
639
640
641 if(ret ==
REQ_NOACTION && ppath ==
NULL) {
642 sstr_t docroot = rq->vs->document_root;
643 if(docroot.length <
1) {
644 log_ereport(
645 LOG_WARN,
646 "VirtualServer(%.*s) docroot too short",
647 (
int)rq->vs->name.length,
648 rq->vs->name.ptr);
649 return REQ_ABORTED;
650 }
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671 sstr_t uri = sstr(pblock_findkeyval(pb_key_uri, rq->rq.reqpb));
672 request_set_path(docroot, uri, rq->rq.vars);
673 }
674
675
676 char *pp = pblock_findkeyval(pb_key_ppath, rq->rq.vars);
677 pblock_kvinsert(pb_key_path, pp, strlen(pp), rq->rq.vars);
678
679 return REQ_PROCEED;
680 }
681
682 int nsapi_pathcheck(NSAPISession *sn, NSAPIRequest *rq) {
683
684 httpd_objset *objset = rq->rq.os;
685
686 if(
NCX_OI(rq) == -
1) {
687 NCX_OI(rq) = objset->pos -
1;
688 }
689
690 int ret = rq->context.last_req_code;
691 for(
int i=
NCX_OI(rq);i>=
0;i--) {
692 httpd_object *obj = objset->obj[i];
693 dtable *dt = object_get_dtable(obj, NSAPIPathCheck);
694
695
696 for(
int j=
NCX_DI(rq);j<dt->ndir;j++) {
697 if(ret ==
REQ_NOACTION || ret ==
REQ_PROCEED) {
698 directive *d = dt->dirs[j];
699 ret = nsapi_exec(d, sn, rq);
700 }
else {
701 if(ret ==
REQ_PROCESSING) {
702
703 rq->context.objset_index = i;
704
705
706 rq->context.dtable_index = j +
1;
707 }
708
709 return ret;
710 }
711 }
712 }
713
714 return REQ_PROCEED;
715 }
716
717 int nsapi_objecttype(NSAPISession *sn, NSAPIRequest *rq) {
718
719 httpd_objset *objset = rq->rq.os;
720
721 if(
NCX_OI(rq) == -
1) {
722
723 NCX_OI(rq) = objset->pos -
1;
724 }
725
726 int ret = rq->context.last_req_code;
727 for(
int i=
NCX_OI(rq);i>=
0;i--) {
728 httpd_object *obj = objset->obj[i];
729 dtable *dt = object_get_dtable(obj, NSAPIObjectType);
730
731
732 for(
int j=
NCX_DI(rq);j<dt->ndir;j++) {
733 if(ret ==
REQ_NOACTION) {
734 directive *d = dt->dirs[j];
735 ret = nsapi_exec(d, sn, rq);
736 }
737
738 switch(ret) {
739 case REQ_PROCEED: {
740 char *type = pblock_findkeyval(
741 pb_key_content_type,
742 rq->rq.srvhdrs);
743 if(type ==
NULL) {
744 ret =
REQ_NOACTION;
745 break;
746 }
747 return ret;
748 }
749 case REQ_PROCESSING: {
750
751 rq->context.objset_index = i;
752
753
754 rq->context.dtable_index = j +
1;
755 return ret;
756 }
757 case REQ_NOACTION: {
758 break;
759 }
760 default: {
761 return ret;
762 }
763 }
764 }
765 }
766
767
768
769
770
771
772
773 sstr_t path = sstr(pblock_findkeyval(pb_key_ppath, rq->rq.vars));
774 sstr_t ct;
775 if(path.ptr[path.length -
1] ==
'/') {
776
777 ct = sstrn(
"internal/directory",
18);
778 }
else {
779 ct = sstrn(
"text/plain",
10);
780 }
781 pblock_kvinsert(pb_key_content_type, ct.ptr, ct.length, rq->rq.srvhdrs);
782
783 return REQ_PROCEED;
784 }
785
786 int nsapi_service(NSAPISession *sn, NSAPIRequest *rq) {
787
788 httpd_objset *objset = rq->rq.os;
789
790 if(
NCX_OI(rq) == -
1) {
791 NCX_OI(rq) = objset->pos -
1;
792 }
793
794 int ret = rq->context.last_req_code;
795 char *content_type =
NULL;
796 char *method =
NULL;
797 for(
int i=
NCX_OI(rq);i>=
0;i--) {
798 httpd_object *obj = objset->obj[i];
799 dtable *dt = object_get_dtable(obj, NSAPIService);
800
801
802 for(
int j=
NCX_DI(rq);j<dt->ndir;j++) {
803 if(ret ==
REQ_NOACTION) {
804 directive *d = dt->dirs[j];
805
806
807 char *dtp = pblock_findkeyval(pb_key_type, d->param);
808 if(dtp) {
809
810 if(!content_type) {
811 content_type = pblock_findkeyval(
812 pb_key_content_type,
813 rq->rq.srvhdrs);
814 }
815
816 if(!contenttype_match(sstr(dtp), sstr(content_type))) {
817 continue;
818 }
819 }
820
821
822 char *dmt = pblock_findkeyval(pb_key_method, d->param);
823 if(dmt) {
824 if(!method) {
825 method = pblock_findkeyval(pb_key_method, rq->rq.reqpb);
826 }
827
828 if(!method_match(dmt, method)) {
829 continue;
830 }
831 }
832
833
834 ret = nsapi_exec(d, sn, rq);
835 }
836
837 if(ret !=
REQ_NOACTION) {
838 if(ret ==
REQ_PROCEED) {
839
840
841
842
843 net_finish(sn->sn.csd);
844 }
else if(ret ==
REQ_PROCESSING) {
845
846 rq->context.objset_index = i;
847
848
849 rq->context.dtable_index = j +
1;
850 }
851
852 return ret;
853 }
854 }
855 }
856
857 return ret;
858 }
859
860 int nsapi_error(NSAPISession *sn, NSAPIRequest *rq) {
861
862 httpd_objset *objset = rq->rq.os;
863
864 if(
NCX_OI(rq) == -
1) {
865 NCX_OI(rq) = objset->pos -
1;
866 }
867
868 int ret = rq->context.last_req_code;
869 for(
int i=
NCX_OI(rq);i>=
0;i--) {
870 httpd_object *obj = objset->obj[i];
871 dtable *dt = object_get_dtable(obj, NSAPIError);
872
873
874 for(
int j=
NCX_DI(rq);j<dt->ndir;j++) {
875 if(ret ==
REQ_NOACTION) {
876 directive *d = dt->dirs[j];
877
878
879 char *status = pblock_findkeyval(pb_key_type, d->param);
880 if(status) {
881 int statuscode = atoi(status);
882 if(statuscode != rq->rq.status_num) {
883 continue;
884 }
885 }
886
887
888 ret = nsapi_exec(d, sn, rq);
889 }
890
891 if(ret ==
REQ_ABORTED) {
892
893
894 break;
895 }
896 if(ret !=
REQ_NOACTION) {
897 if(ret ==
REQ_PROCEED) {
898
899
900
901
902 net_finish(sn->sn.csd);
903 }
else if(ret ==
REQ_PROCESSING) {
904
905 rq->context.objset_index = i;
906
907
908 rq->context.dtable_index = j +
1;
909 }
910 return ret;
911 }
912 }
913 }
914
915 if(ret !=
REQ_PROCEED) {
916
917 nsapi_error_request((Session*)sn, (Request*)rq);
918 }
919
920 return ret;
921 }
922
923 int nsapi_addlog(NSAPISession *sn, NSAPIRequest *rq) {
924
925 httpd_objset *objset = rq->rq.os;
926
927 if(
NCX_OI(rq) == -
1) {
928 NCX_OI(rq) = objset->pos -
1;
929 }
930
931 int ret = rq->context.last_req_code;
932 for(
int i=
NCX_OI(rq);i>=
0;i--) {
933 httpd_object *obj = objset->obj[i];
934 dtable *dt = object_get_dtable(obj, NSAPIAddLog);
935
936
937 for(
int j=
NCX_DI(rq);j<dt->ndir;j++) {
938 if(ret ==
REQ_NOACTION) {
939 directive *d = dt->dirs[j];
940 ret = nsapi_exec(d, sn, rq);
941 }
942
943 if(ret !=
REQ_NOACTION) {
944 if(ret ==
REQ_PROCESSING) {
945
946 rq->context.objset_index = i;
947
948
949 rq->context.dtable_index = j +
1;
950 }
951
952 return ret;
953 }
954 }
955 }
956
957 return REQ_PROCEED;
958 }
959
960 struct _tpd_data {
961 NSAPISession *sn;
962 NSAPIRequest *rq;
963 directive *directive;
964 threadpool_t *threadpool;
965 };
966
967 int nsapi_exec(directive *d, NSAPISession *sn, NSAPIRequest *rq) {
968
969 if(d->cond) {
970 if(!condition_evaluate(d->cond, (Session*)sn, (Request*)rq)) {
971 return REQ_NOACTION;
972 }
973 }
974
975 char *poolname = pblock_findkeyval(pb_key_pool, d->param);
976 if(poolname) {
977 threadpool_t *pool = get_threadpool(sstr(poolname));
978 if(pool && pool != sn->currentpool) {
979
980 return nsapi_exec_tp(d, sn, rq, pool);
981 }
982 }
else if(sn->currentpool != sn->defaultpool) {
983
984 return nsapi_exec_tp(d, sn, rq, sn->defaultpool);
985 }
986
987 return SAF_EXEC(d->func, d->param, (Session*)sn, (Request*)rq);
988 }
989
990 int nsapi_exec_tp(
991 directive *d,
992 NSAPISession *sn,
993 NSAPIRequest *rq,
994 threadpool_t *pool)
995 {
996 struct _tpd_data *data = malloc(
sizeof(
struct _tpd_data));
997 if(data ==
NULL) {
998
999 return REQ_ABORTED;
1000 }
1001 data->sn = sn;
1002 data->rq = rq;
1003 data->directive = d;
1004 data->threadpool = pool;
1005
1006 sn->currentpool = pool;
1007 threadpool_run(pool, thrpool_exec, data);
1008
1009 return REQ_PROCESSING;
1010 }
1011
1012 void nsapi_function_return(Session *session, Request *request,
int ret) {
1013 NSAPISession *sn = (NSAPISession*)session;
1014 NSAPIRequest *rq = (NSAPIRequest*)request;
1015
1016 rq->context.last_req_code = ret;
1017
1018 if(sn->currentpool != sn->defaultpool) {
1019 nsapi_change_threadpool(sn, rq, sn->defaultpool);
1020 }
else {
1021 nsapi_handle_request(sn, rq);
1022 }
1023 }
1024
1025 void nsapi_change_threadpool(
1026 NSAPISession *sn,
1027 NSAPIRequest *rq,
1028 threadpool_t *thrpool)
1029 {
1030 struct _tpd_data *data = malloc(
sizeof(
struct _tpd_data));
1031 data->sn = sn;
1032 data->rq = rq;
1033 data->threadpool = thrpool;
1034
1035 threadpool_run(thrpool, thrpool_change, data);
1036 }
1037
1038 void* thrpool_exec(
void *d) {
1039 struct _tpd_data *data = d;
1040
1041 data->sn->currentpool = data->threadpool;
1042 int r =
SAF_EXEC(
1043 data->directive->func,
1044 data->directive->param,
1045 (Session*)data->sn,
1046 (Request*)data->rq);
1047
1048 nsapi_function_return((Session*)data->sn, (Request*)data->rq, r);
1049 free(data);
1050
1051 return NULL;
1052 }
1053
1054 void* thrpool_change(
void *d) {
1055 struct _tpd_data *data = d;
1056
1057 data->sn->currentpool = data->threadpool;
1058 nsapi_handle_request(data->sn, data->rq);
1059
1060 free(data);
1061 return NULL;
1062 }
1063
1064
1065
1066
1067
1068
1069
1070 int method_match(
char *cmp,
char *method) {
1071 if(cmp[
0] !=
'(') {
1072
1073 if(!strcmp(cmp, method)) {
1074 return 1;
1075 }
1076 }
else if(cmp[
0] ==
0) {
1077
1078 log_ereport(
1079 LOG_WARN,
1080 "Skipped service saf with empty method parameter");
1081 return 0;
1082 }
1083
1084 size_t method_len = strlen(method);
1085 size_t last_pos =
0;
1086 cmp++;
1087 for(
int i=
0;cmp[i]!=
0;i++) {
1088 char c = cmp[i];
1089 if(c ==
'|' || c ==
')') {
1090 size_t len = i - last_pos;
1091 if(len == method_len) {
1092 char *cp = cmp + last_pos;
1093 if(!memcmp(cp, method, len)) {
1094 return 1;
1095 }
1096 }
1097 last_pos = i +
1;
1098 }
1099 }
1100
1101 return 0;
1102 }
1103
1104
1105
1106
1107
1108
1109
1110 int contenttype_match(
sstr_t cmp,
sstr_t ctype) {
1111 if(cmp.ptr[
0] !=
'(') {
1112 if(cmp.ptr[
0] ==
'*') {
1113 cmp.ptr++;
1114 cmp.length--;
1115 return sstrsuffix(ctype, cmp);
1116 }
else if(cmp.ptr[cmp.length-
1] ==
'*') {
1117 cmp.length--;
1118 return sstrprefix(ctype, cmp);
1119 }
else {
1120 return !sstrcmp(cmp, ctype);
1121 }
1122 }
else if(cmp.ptr[
0] ==
0) {
1123 log_ereport(
LOG_WARN,
"Skipped service saf with empty type parameter");
1124 return 0;
1125 }
1126
1127 cmp = sstrsubsl(cmp,
1, cmp.length -
2);
1128
1129 int begin =
0;
1130 for(
int i=
0;i<cmp.length;i++) {
1131 if(cmp.ptr[i] ==
'|') {
1132 if(contenttype_match(sstrsubsl(cmp, begin, i-begin), ctype)) {
1133 return 1;
1134 }
1135 begin = i +
1;
1136 }
1137 }
1138 return contenttype_match(sstrsubs(cmp, begin), ctype);
1139 }
1140
1141
1142
1143
1144 int add_objects(
1145 HTTPObjectConfig *objs,
1146 httpd_objset *os,
1147 NSAPISession *sn,
1148 NSAPIRequest *rq,
1149 char *name,
1150 char *path)
1151 {
1152
1153
1154
1155
1156
1157 if(name ==
NULL) {
1158 return REQ_PROCEED;
1159 }
1160
1161 for(
int i=
0;i<objs->nobj;i++) {
1162 httpd_object *obj = objs->objects[i];
1163
1164 if(obj->name && !strcmp(name, obj->name)) {
1165 objset_add_object(sn->sn.pool, os, obj);
1166 }
1167 }
1168
1169 return REQ_PROCEED;
1170 }
1171