85 } |
85 } |
86 |
86 |
87 return S("/"); |
87 return S("/"); |
88 } |
88 } |
89 |
89 |
|
90 NSAPISession* nsapisession_create(pool_handle_t *pool) { |
|
91 NSAPISession *sn = pool_malloc(pool, sizeof(NSAPISession)); |
|
92 if(!sn) { |
|
93 return NULL; |
|
94 } |
|
95 |
|
96 ZERO(sn, sizeof(NSAPISession)); |
|
97 |
|
98 sn->sn.pool = pool; |
|
99 sn->allocator = util_pool_allocator(pool); |
|
100 |
|
101 sn->sn.client = pblock_create_pool(sn->sn.pool, 8); |
|
102 if(!sn->sn.client) { |
|
103 pool_free(pool, sn); |
|
104 return NULL; |
|
105 } |
|
106 sn->sn.fill = 1; |
|
107 |
|
108 return sn; |
|
109 } |
|
110 |
|
111 int nsapisession_setconnection(NSAPISession *sn, Connection *conn, netbuf *inbuf, IOStream **io) { |
|
112 SessionHandler *sh = conn->session_handler; |
|
113 WSBool ssl; |
|
114 IOStream *sio = sh->create_iostream(sh, conn, sn->sn.pool, &ssl); |
|
115 if(!sio) { |
|
116 return 1; |
|
117 } |
|
118 *io = sio; |
|
119 IOStream *http = httpstream_new(sn->sn.pool, sio); |
|
120 if(!http) { |
|
121 return 1; |
|
122 } |
|
123 sn->connection = conn; |
|
124 sn->netbuf = inbuf; |
|
125 sn->sn.csd = http; |
|
126 sn->sn.ssl = ssl; |
|
127 sn->sn.inbuf = inbuf; |
|
128 sn->sn.inbuf->sd = http; |
|
129 return 0; |
|
130 } |
|
131 |
90 int handle_request(HTTPRequest *request, threadpool_t *thrpool, EventHandler *ev) { |
132 int handle_request(HTTPRequest *request, threadpool_t *thrpool, EventHandler *ev) { |
91 // handle nsapi request |
133 // handle nsapi request |
92 |
134 |
93 // create pool |
135 // create pool |
94 pool_handle_t *pool = pool_create(); |
136 pool_handle_t *pool = pool_create(); |
95 |
137 |
96 // create nsapi data structures |
138 // create nsapi data structures |
97 NSAPISession *sn = pool_malloc(pool, sizeof(NSAPISession)); |
139 NSAPISession *sn = nsapisession_create(pool); |
98 if(sn == NULL) { |
140 if(sn == NULL) { |
99 /* TODO: error */ |
141 /* TODO: error */ |
100 } |
142 } |
101 ZERO(sn, sizeof(NSAPISession)); |
143 |
102 NSAPIRequest *rq = pool_malloc(pool, sizeof(NSAPIRequest)); |
144 NSAPIRequest *rq = pool_malloc(pool, sizeof(NSAPIRequest)); |
103 if(rq == NULL) { |
145 if(rq == NULL) { |
104 /* TODO: error */ |
146 /* TODO: error */ |
105 } |
147 } |
106 ZERO(rq, sizeof(NSAPIRequest)); |
148 ZERO(rq, sizeof(NSAPIRequest)); |
107 rq->rq.req_start = request->req_start; |
149 rq->rq.req_start = request->req_start; |
108 rq->phase = NSAPIAuthTrans; |
150 rq->phase = NSAPIAuthTrans; |
109 |
151 |
110 // fill session structure |
152 // fill session structure |
111 sn->connection = request->connection; |
153 IOStream *io = NULL; |
112 sn->netbuf = request->netbuf; |
154 if(nsapisession_setconnection(sn, request->connection, request->netbuf, &io)) { |
113 sn->sn.pool = pool; |
155 // TODO: error |
114 SessionHandler *sh = request->connection->session_handler; |
156 } |
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 |
157 |
125 if(!ev) { |
158 if(!ev) { |
126 ev = ev_instance(get_default_event_handler()); |
159 ev = ev_instance(get_default_event_handler()); |
127 } |
160 } |
128 sn->sn.ev = ev; |
161 sn->sn.ev = ev; |
129 |
162 |
130 // the session needs the current server configuration |
163 // the session needs the current server configuration |
131 sn->config = request->connection->listener->cfg; |
164 sn->config = request->connection->listener->cfg; |
132 |
165 |
133 // add ip to sn->client pblock |
166 // add ip to sn->client pblock |
134 char ip_str[INET_ADDRSTRLEN]; |
167 char ip_str[INET_ADDRSTRLEN]; |
340 } |
373 } |
341 |
374 |
342 // check for request body and prepare input buffer |
375 // check for request body and prepare input buffer |
343 char *ctlen_str = pblock_findkeyval(pb_key_content_length, rq->rq.headers); |
376 char *ctlen_str = pblock_findkeyval(pb_key_content_length, rq->rq.headers); |
344 if(ctlen_str) { |
377 if(ctlen_str) { |
345 int ctlen = atoi(ctlen_str); |
378 int64_t ctlen; |
346 |
379 if(util_strtoint(ctlen_str, &ctlen)) { |
347 //printf("request body length: %d\n", ctlen); |
380 netbuf *nb = sn->netbuf; |
348 |
381 HttpStream *net_io = (HttpStream*)sn->sn.csd; |
349 netbuf *nb = request->netbuf; |
382 net_io->read_eof = WS_FALSE; |
350 |
383 |
351 // create new netbuf |
384 // how many bytes are already read and in the buffer |
352 HttpStream *net_io = (HttpStream*)httpstream_new(pool, io); |
385 int cur_input_available = nb->cursize - nb->pos; |
353 net_io->max_read = ctlen; |
386 |
354 |
387 if(cur_input_available >= ctlen) { |
355 sn->sn.inbuf = pool_malloc(pool, sizeof(netbuf)); |
388 // we have the whole request body in the buffer and |
356 sn->sn.inbuf->sd = net_io; |
389 // maybe even more |
357 sn->sn.inbuf->pos = 0; |
390 // no more read from the socket is necessary to get the body, |
358 |
391 // therefore disable it |
359 // prepare buffer |
392 net_io->max_read = 0; |
360 int cur_input_len = nb->cursize - nb->pos; |
393 } else { |
361 |
394 // read still required to get the complete request body |
362 if(cur_input_len >= ctlen) { |
395 net_io->max_read = ctlen - cur_input_available; |
363 /* |
396 } |
364 * all data is already in the primary input buffer |
397 //printf("request body length: %d\n", ctlen); |
365 * just link the new netbuf to the primary buffer |
398 } // else: should we abort? |
366 */ |
399 } |
367 sn->sn.inbuf->maxsize = ctlen; |
400 char *transfer_encoding = pblock_findkeyval(pb_key_transfer_encoding, rq->rq.headers); |
368 sn->sn.inbuf->cursize = ctlen; |
401 if(transfer_encoding) { |
369 sn->sn.inbuf->inbuf = nb->inbuf + nb->pos; |
402 if(!strcmp(transfer_encoding, "chunked")) { |
370 } else { |
403 netbuf *nb = sn->netbuf; |
371 sn->sn.inbuf->maxsize = (ctlen > 2048) ? (2048) : (ctlen); |
404 sn->buffer = (char*)nb->inbuf; |
372 sn->sn.inbuf->inbuf = pool_malloc(pool, sn->sn.inbuf->maxsize); |
405 sn->pos = nb->pos; |
373 |
406 sn->cursize = nb->cursize; |
374 if(cur_input_len > 0) { |
407 |
375 // we have read a part of the request body -> copy to netbuf |
408 if(httpstream_enable_chunked_read(sn->sn.csd, sn->buffer, nb->maxsize, &sn->cursize, &sn->pos)) { |
376 memcpy(sn->sn.inbuf->inbuf, nb->inbuf+nb->pos, cur_input_len); |
409 pool_destroy(pool); |
377 } |
410 // TODO: error 500 |
378 |
411 return 1; |
379 sn->sn.inbuf->cursize = cur_input_len; |
412 } |
380 } |
413 } |
381 } else { |
|
382 sn->sn.inbuf = NULL; |
|
383 } |
414 } |
384 |
415 |
385 // |
416 // |
386 // Send the request to the NSAPI system |
417 // Send the request to the NSAPI system |
387 // |
418 // |
533 |
564 |
534 return r; |
565 return r; |
535 } |
566 } |
536 |
567 |
537 int nsapi_finish_request(NSAPISession *sn, NSAPIRequest *rq) { |
568 int nsapi_finish_request(NSAPISession *sn, NSAPIRequest *rq) { |
|
569 request_free_resources(sn, rq); |
|
570 |
|
571 WSBool read_stream_eof = httpstream_eof(sn->sn.csd); |
|
572 if(!read_stream_eof) { |
|
573 log_ereport(LOG_WARN, "request input stream not closed"); |
|
574 // TODO: clean stream |
|
575 rq->rq.rq_attr.keep_alive = 0; // workaround |
|
576 } |
|
577 if(sn->pos < sn->cursize) { |
|
578 log_ereport(LOG_WARN, "nsapi_finish_request: TODO: remaining bytes in buffer"); |
|
579 // TODO: reuse buffer in next request |
|
580 rq->rq.rq_attr.keep_alive = 0; // workaround |
|
581 } |
|
582 |
|
583 if(rq->rq.senthdrs) { |
|
584 // flush buffer and add termination if chunked encoding |
|
585 // is enabled |
|
586 net_finish(sn->sn.csd); |
|
587 } else { |
|
588 // why was no response sent? |
|
589 // something must have gone wrong |
|
590 // terminate the session |
|
591 char *clf_req = pblock_findkeyval(pb_key_clf_request, rq->rq.reqpb); |
|
592 log_ereport(LOG_WARN, "nsapi_finish_request: no response header: request: %s", clf_req); |
|
593 rq->rq.rq_attr.keep_alive = 0; |
|
594 } |
|
595 |
538 if(rq->rq.rq_attr.keep_alive) { |
596 if(rq->rq.rq_attr.keep_alive) { |
539 SessionHandler *sh = sn->connection->session_handler; |
597 SessionHandler *sh = sn->connection->session_handler; |
540 sh->keep_alive(sh, sn->connection); |
598 sh->keep_alive(sh, sn->connection); |
541 /* |
599 /* |
542 * keep the connection object |
600 * keep the connection object |
553 free(sn->netbuf); |
611 free(sn->netbuf); |
554 |
612 |
555 pool_destroy(sn->sn.pool); |
613 pool_destroy(sn->sn.pool); |
556 |
614 |
557 return 0; |
615 return 0; |
|
616 } |
|
617 |
|
618 void request_free_resources(NSAPISession *sn, NSAPIRequest *rq) { |
|
619 if(!rq->resources) return; |
|
620 |
|
621 UcxMapIterator i = ucx_map_iterator(rq->resources); |
|
622 ResourceData *resource; |
|
623 UCX_MAP_FOREACH(key, resource, i) { |
|
624 resourcepool_free(&sn->sn, &rq->rq, resource); |
|
625 } |
558 } |
626 } |
559 |
627 |
560 int nsapi_authtrans(NSAPISession *sn, NSAPIRequest *rq) { |
628 int nsapi_authtrans(NSAPISession *sn, NSAPIRequest *rq) { |
561 HTTPObjectConfig *objconf = rq->vs->objects; |
629 HTTPObjectConfig *objconf = rq->vs->objects; |
562 httpd_object *obj = objconf->objects[0]; |
630 httpd_object *obj = objconf->objects[0]; |
833 // execute the saf |
901 // execute the saf |
834 ret = nsapi_exec(d, sn, rq); |
902 ret = nsapi_exec(d, sn, rq); |
835 } |
903 } |
836 |
904 |
837 if(ret != REQ_NOACTION) { |
905 if(ret != REQ_NOACTION) { |
838 if(ret == REQ_PROCEED) { |
906 if(ret == REQ_PROCEED && !rq->rq.senthdrs) { |
839 /* |
907 // a service SAF must send a response |
840 * flush buffer and add termination if chunked encoding |
908 // senthdrs == 0 indicators something has gone |
841 * is enabled |
909 // wrong |
842 */ |
910 protocol_status(&sn->sn, &rq->rq, 500, NULL); |
843 net_finish(sn->sn.csd); |
911 ret = REQ_ABORTED; |
844 } else if(ret == REQ_PROCESSING) { |
912 } else if(ret == REQ_PROCESSING) { |
845 // save nsapi context |
913 // save nsapi context |
846 rq->context.objset_index = i; |
914 rq->context.objset_index = i; |
847 |
915 |
848 // add +1 to start next round with next function |
916 // add +1 to start next round with next function |
873 // execute directives |
941 // execute directives |
874 for(int j=NCX_DI(rq);j<dt->ndir;j++) { |
942 for(int j=NCX_DI(rq);j<dt->ndir;j++) { |
875 if(ret == REQ_NOACTION) { |
943 if(ret == REQ_NOACTION) { |
876 directive *d = dt->dirs[j]; |
944 directive *d = dt->dirs[j]; |
877 |
945 |
878 // check status code parameter |
946 // check status code parameter |
|
947 // Error SAFs can specify, for which status code they should |
|
948 // be executed |
879 char *status = pblock_findkeyval(pb_key_type, d->param); |
949 char *status = pblock_findkeyval(pb_key_type, d->param); |
880 if(status) { |
950 if(status) { |
881 int statuscode = atoi(status); |
951 int64_t statuscode = -1; |
882 if(statuscode != rq->rq.status_num) { |
952 if(!util_strtoint(status, &statuscode)) { |
|
953 log_ereport( |
|
954 LOG_WARN, |
|
955 "nsapi_error: directive '%s' ignored: invalid type parameter: integer status code expected", |
|
956 d->func->name); |
|
957 } else if(statuscode != rq->rq.status_num) { |
883 continue; |
958 continue; |
884 } |
959 } |
885 } |
960 } |
886 |
961 |
887 // execute the saf |
962 // execute the saf |
893 // error handler |
968 // error handler |
894 break; |
969 break; |
895 } |
970 } |
896 if(ret != REQ_NOACTION) { |
971 if(ret != REQ_NOACTION) { |
897 if(ret == REQ_PROCEED) { |
972 if(ret == REQ_PROCEED) { |
898 /* |
973 // flush buffer and add termination if chunked encoding |
899 * flush buffer and add termination if chunked encoding |
974 // is enabled |
900 * is enabled |
|
901 */ |
|
902 net_finish(sn->sn.csd); |
975 net_finish(sn->sn.csd); |
903 } else if(ret == REQ_PROCESSING) { |
976 } else if(ret == REQ_PROCESSING) { |
904 // save nsapi context |
977 // save nsapi context |
905 rq->context.objset_index = i; |
978 rq->context.objset_index = i; |
906 |
979 |