src/server/daemon/httprequest.c

changeset 385
a1f4cb076d2f
parent 361
570026d3a685
child 396
77d81f2bb9f7
--- a/src/server/daemon/httprequest.c	Tue Aug 13 22:14:32 2019 +0200
+++ b/src/server/daemon/httprequest.c	Sat Sep 24 16:26:10 2022 +0200
@@ -87,6 +87,48 @@
     return S("/");
 }
 
+NSAPISession* nsapisession_create(pool_handle_t *pool) {
+    NSAPISession *sn = pool_malloc(pool, sizeof(NSAPISession));
+    if(!sn) {
+        return NULL;
+    }
+    
+    ZERO(sn, sizeof(NSAPISession));
+    
+    sn->sn.pool = pool;
+    sn->allocator = util_pool_allocator(pool);
+    
+    sn->sn.client = pblock_create_pool(sn->sn.pool, 8);
+    if(!sn->sn.client) {
+        pool_free(pool, sn);
+        return NULL;
+    }
+    sn->sn.fill = 1;
+    
+    return sn;
+}
+
+int nsapisession_setconnection(NSAPISession *sn, Connection *conn, netbuf *inbuf, IOStream **io) {
+    SessionHandler *sh = conn->session_handler;
+    WSBool ssl;
+    IOStream *sio = sh->create_iostream(sh, conn, sn->sn.pool, &ssl);
+    if(!sio) {
+        return 1;
+    }
+    *io = sio;
+    IOStream *http = httpstream_new(sn->sn.pool, sio);
+    if(!http) {
+        return 1;
+    }
+    sn->connection = conn;
+    sn->netbuf = inbuf;
+    sn->sn.csd = http;
+    sn->sn.ssl = ssl;
+    sn->sn.inbuf = inbuf;
+    sn->sn.inbuf->sd = http;
+    return 0;
+}
+
 int handle_request(HTTPRequest *request, threadpool_t *thrpool, EventHandler *ev) {
     // handle nsapi request
      
@@ -94,11 +136,11 @@
     pool_handle_t *pool = pool_create();
 
     // create nsapi data structures
-    NSAPISession *sn = pool_malloc(pool, sizeof(NSAPISession));
+    NSAPISession *sn = nsapisession_create(pool);
     if(sn == NULL) {
         /* TODO: error */
     }
-    ZERO(sn, sizeof(NSAPISession));
+    
     NSAPIRequest *rq = pool_malloc(pool, sizeof(NSAPIRequest));
     if(rq == NULL) {
         /* TODO: error */
@@ -108,25 +150,16 @@
     rq->phase = NSAPIAuthTrans;
 
     // fill session structure
-    sn->connection = request->connection;
-    sn->netbuf = request->netbuf;
-    sn->sn.pool = pool;
-    SessionHandler *sh = request->connection->session_handler;
-    WSBool ssl;
-    IOStream *io = sh->create_iostream(sh, request->connection, pool, &ssl);
-    sn->sn.csd = httpstream_new(pool, io);
-    sn->sn.ssl = ssl;
-    
-    sn->sn.client = pblock_create_pool(sn->sn.pool, 8);
-    sn->sn.next = NULL;
-    sn->sn.fill = 1;
-    sn->sn.subject = NULL;
+    IOStream *io = NULL;
+    if(nsapisession_setconnection(sn, request->connection, request->netbuf, &io)) {
+        // TODO: error
+    }
     
     if(!ev) {
         ev = ev_instance(get_default_event_handler());
     }
     sn->sn.ev = ev;
-    
+      
     // the session needs the current server configuration
     sn->config = request->connection->listener->cfg;
 
@@ -198,13 +231,13 @@
     /*
      * get absolute path and query of the request uri
      */
-    // TODO: check for '#'
+    // TODO: check for '#' #72
     sstr_t absPath = http_request_get_abspath(request);
     if(!absPath.ptr) {
         // TODO: error msg
         return 1;
     } else if(absPath.ptr[0] == '*') {
-        // TODO: implement global OPTIONS
+        // TODO: implement global OPTIONS #71
         return 1;
     }
     
@@ -342,44 +375,42 @@
     // check for request body and prepare input buffer
     char *ctlen_str = pblock_findkeyval(pb_key_content_length, rq->rq.headers);
     if(ctlen_str) {
-        int ctlen = atoi(ctlen_str);
-              
-        //printf("request body length: %d\n", ctlen);
+        int64_t ctlen;
+        if(util_strtoint(ctlen_str, &ctlen)) {
+            netbuf *nb = sn->netbuf;
+            HttpStream *net_io = (HttpStream*)sn->sn.csd;
+            net_io->read_eof = WS_FALSE;
 
-        netbuf *nb = request->netbuf;
+            // how many bytes are already read and in the buffer
+            int cur_input_available = nb->cursize - nb->pos;
 
-        // create new netbuf
-        HttpStream *net_io = (HttpStream*)httpstream_new(pool, io);
-        net_io->max_read = ctlen;
-        
-        sn->sn.inbuf = pool_malloc(pool, sizeof(netbuf));
-        sn->sn.inbuf->sd = net_io;
-        sn->sn.inbuf->pos = 0;
-        
-        // prepare buffer
-        int cur_input_len = nb->cursize - nb->pos;
-        
-        if(cur_input_len >= ctlen) {
-            /*
-             * all data is already in the primary input buffer
-             * just link the new netbuf to the primary buffer
-             */
-            sn->sn.inbuf->maxsize = ctlen;
-            sn->sn.inbuf->cursize = ctlen;
-            sn->sn.inbuf->inbuf = nb->inbuf + nb->pos;
-        } else {
-            sn->sn.inbuf->maxsize = (ctlen > 2048) ? (2048) : (ctlen);
-            sn->sn.inbuf->inbuf = pool_malloc(pool, sn->sn.inbuf->maxsize);
-
-            if(cur_input_len > 0) {
-                // we have read a part of the request body -> copy to netbuf
-                memcpy(sn->sn.inbuf->inbuf, nb->inbuf+nb->pos, cur_input_len);
+            if(cur_input_available >= ctlen) {
+                // we have the whole request body in the buffer and
+                // maybe even more
+                // no more read from the socket is necessary to get the body,
+                // therefore disable it
+                net_io->max_read = 0;
+            } else {
+                // read still required to get the complete request body
+                net_io->max_read = ctlen - cur_input_available;
             }
-
-            sn->sn.inbuf->cursize = cur_input_len;
+            //printf("request body length: %d\n", ctlen);
+        } // else: should we abort?
+    }
+    char *transfer_encoding = pblock_findkeyval(pb_key_transfer_encoding, rq->rq.headers);
+    if(transfer_encoding) {
+        if(!strcmp(transfer_encoding, "chunked")) {
+            netbuf *nb = sn->netbuf;
+            sn->buffer = (char*)nb->inbuf;
+            sn->pos = nb->pos;
+            sn->cursize = nb->cursize;
+            
+            if(httpstream_enable_chunked_read(sn->sn.csd, sn->buffer, nb->maxsize, &sn->cursize, &sn->pos)) {
+                pool_destroy(pool);
+                // TODO: error 500 
+                return 1;
+            }
         }
-    } else {
-        sn->sn.inbuf = NULL;
     }
     
     //
@@ -535,6 +566,33 @@
 }
 
 int nsapi_finish_request(NSAPISession *sn, NSAPIRequest *rq) {
+    request_free_resources(sn, rq);
+    
+    WSBool read_stream_eof = httpstream_eof(sn->sn.csd);
+    if(!read_stream_eof) {
+        log_ereport(LOG_WARN, "request input stream not closed");
+        // TODO: clean stream
+        rq->rq.rq_attr.keep_alive = 0; // workaround
+    }
+    if(sn->pos < sn->cursize) {
+        log_ereport(LOG_WARN, "nsapi_finish_request: TODO: remaining bytes in buffer");
+        // TODO: reuse buffer in next request
+        rq->rq.rq_attr.keep_alive = 0; // workaround
+    }
+    
+    if(rq->rq.senthdrs) {
+        // flush buffer and add termination if chunked encoding
+        // is enabled
+         net_finish(sn->sn.csd);
+    } else {
+        // why was no response sent?
+        // something must have gone wrong
+        // terminate the session
+        char *clf_req = pblock_findkeyval(pb_key_clf_request, rq->rq.reqpb);
+        log_ereport(LOG_WARN, "nsapi_finish_request: no response header: request: %s", clf_req);
+        rq->rq.rq_attr.keep_alive = 0;
+    }
+    
     if(rq->rq.rq_attr.keep_alive) {
         SessionHandler *sh = sn->connection->session_handler;
         sh->keep_alive(sh, sn->connection);
@@ -557,6 +615,16 @@
     return 0;
 }
 
+void request_free_resources(NSAPISession *sn, NSAPIRequest *rq) {
+    if(!rq->resources) return;
+    
+    UcxMapIterator i = ucx_map_iterator(rq->resources);
+    ResourceData *resource;
+    UCX_MAP_FOREACH(key, resource, i) {
+        resourcepool_free(&sn->sn, &rq->rq, resource);
+    }
+}
+
 int nsapi_authtrans(NSAPISession *sn, NSAPIRequest *rq) {
     HTTPObjectConfig *objconf = rq->vs->objects;
     httpd_object *obj = objconf->objects[0];
@@ -835,12 +903,12 @@
             }
             
             if(ret != REQ_NOACTION) {
-                if(ret == REQ_PROCEED) {
-                    /*
-                     * flush buffer and add termination if chunked encoding
-                     * is enabled
-                     */
-                    net_finish(sn->sn.csd);
+                if(ret == REQ_PROCEED && !rq->rq.senthdrs) {
+                    // a service SAF must send a response
+                    // senthdrs == 0 indicators something has gone
+                    // wrong
+                    protocol_status(&sn->sn, &rq->rq, 500, NULL);
+                    ret = REQ_ABORTED;
                 } else if(ret == REQ_PROCESSING) {
                     // save nsapi context
                     rq->context.objset_index = i;
@@ -875,11 +943,18 @@
             if(ret == REQ_NOACTION) {
                 directive *d = dt->dirs[j];
 
-                // check status code parameter          
+                // check status code parameter
+                // Error SAFs can specify, for which status code they should
+                // be executed
                 char *status = pblock_findkeyval(pb_key_type, d->param);
                 if(status) {
-                    int statuscode = atoi(status);
-                    if(statuscode != rq->rq.status_num) {
+                    int64_t statuscode = -1;
+                    if(!util_strtoint(status, &statuscode)) {
+                        log_ereport(
+                                LOG_WARN,
+                                "nsapi_error: directive '%s' ignored: invalid type parameter: integer status code expected",
+                                d->func->name);
+                    } else if(statuscode != rq->rq.status_num) {
                         continue;
                     }
                 }
@@ -895,10 +970,8 @@
             }
             if(ret != REQ_NOACTION) {
                 if(ret == REQ_PROCEED) {
-                    /*
-                     * flush buffer and add termination if chunked encoding
-                     * is enabled
-                     */
+                    // flush buffer and add termination if chunked encoding
+                    // is enabled
                     net_finish(sn->sn.csd);
                 } else if(ret == REQ_PROCESSING) {
                     // save nsapi context
@@ -914,7 +987,9 @@
     
     if(ret != REQ_PROCEED) {
         // default error handler
-        nsapi_error_request((Session*)sn, (Request*)rq);
+        if(!rq->rq.senthdrs) {
+            nsapi_error_request((Session*)sn, (Request*)rq);
+        }
     }
 
     return ret;

mercurial