webcit-ng: fixed the way HTTP uploads are fed into the MIME Parser.
[citadel.git] / webcit-ng / server / http.c
index 82fd5f3c258cc07cbafcd3e2b71a23acfa2256d1..1740ccec83fdfac8456f84fa02d2a108e441adbd 100644 (file)
@@ -1,10 +1,15 @@
 // This module handles HTTP transactions.
 //
-// Copyright (c) 1996-2022 by the citadel.org team
+// Copyright (c) 1996-2023 by the citadel.org team
 //
 // This program is open source software.  Use, duplication, or
 // disclosure are subject to the GNU General Public License v3.
 
+// uncomment one or more of these to see raw http transactions
+//#define DEBUG_HTTP
+//#define REQUEST_BODY_TO_STDERR
+//#define RESPONSE_BODY_TO_STDERR
+
 #include "webcit.h"
 
 // Write data to the HTTP client.  Encrypt if necessary.
@@ -192,9 +197,9 @@ void perform_one_http_transaction(struct client_handle *ch) {
                syslog(LOG_DEBUG, "Client disconnected");
        }
        else {
-//#ifdef DEBUG_HTTP
+#ifdef DEBUG_HTTP
                syslog(LOG_DEBUG, "< %s %s", h.method, h.url);
-//#endif
+#endif
 
                // If there is a request body, read it now.
                char *ccl = header_val(&h, "Content-Length");
@@ -203,14 +208,30 @@ void perform_one_http_transaction(struct client_handle *ch) {
                }
                if (h.request_body_length > 0) {
                        syslog(LOG_DEBUG, "Reading request body (%ld bytes)", h.request_body_length);
-                       h.request_body = malloc(h.request_body_length);
+
+                       // Sometimes we need the request body by itself, sometimes we need it with headers.
+                       // So we save it with synthetic headers, and also provide a pointer into the place where the body begins.
+
+                       char *cct = header_val(&h, "Content-Type");
+                       if (cct) {
+                               h.request_body_with_synth_headers = malloc(h.request_body_length + 1024);
+                               memset(h.request_body_with_synth_headers, h.request_body_length + 1024, 0);
+                               sprintf(h.request_body_with_synth_headers, "Content-Type: %s\r\n\r\n", cct);
+                               h.request_body = h.request_body_with_synth_headers + strlen(h.request_body_with_synth_headers);
+                       }
+                       else {  // a request body absent a Content-Type: header is invalid, but handle it anyway.
+                               h.request_body_with_synth_headers = malloc(h.request_body_length);
+                               memset(h.request_body_with_synth_headers, h.request_body_length, 0);
+                               h.request_body = h.request_body_with_synth_headers;
+                       }
+
                        client_read(ch, h.request_body, h.request_body_length);
 
                        // Write the entire request body to stderr -- not what you want during normal operation.
-                       #ifdef BODY_TO_STDERR
-                       write(2, HKEY("---\n"));
+                       #ifdef REQUEST_BODY_TO_STDERR
+                       write(2, HKEY("--- REQUEST BODY BEGIN ---\n"));
                        write(2, h.request_body, h.request_body_length);
-                       write(2, HKEY("---\n"));
+                       write(2, HKEY("--- REQUEST BODY END ---\n"));
                        #endif
 
                }
@@ -219,10 +240,10 @@ void perform_one_http_transaction(struct client_handle *ch) {
                perform_request(&h);
 
                // Write the entire response body to stderr -- not what you want during normal operation.
-               #ifdef BODY_TO_STDERR
-               write(2, HKEY("---\n"));
+               #ifdef RESPONSE_BODY_TO_STDERR
+               write(2, HKEY("--- RESPONSE BODY BEGIN ---\n"));
                write(2, h.response_body, h.response_body_length);
-               write(2, HKEY("---\n"));
+               write(2, HKEY("--- RESPONSE BODY END ---\n"));
                #endif
 
                // Output the results back to the client.
@@ -281,8 +302,8 @@ void perform_one_http_transaction(struct client_handle *ch) {
        if (h.url) {
                free(h.url);
        }
-       if (h.request_body) {
-               free(h.request_body);
+       if (h.request_body_with_synth_headers) {
+               free(h.request_body_with_synth_headers);
        }
        if (h.response_string) {
                free(h.response_string);