From: Art Cancro Date: Mon, 6 Nov 2023 21:56:55 +0000 (-0500) Subject: webcit-ng: fixed the way HTTP uploads are fed into the MIME Parser. X-Git-Tag: v997~97 X-Git-Url: https://code.citadel.org/?p=citadel.git;a=commitdiff_plain;h=a054aa798b13cbc18e86b744357ec7a13932708c webcit-ng: fixed the way HTTP uploads are fed into the MIME Parser. mime_parser() expects HEADERS+CONTENT but our h.request_body only contains CONTENT. The fix: our transaction struct now has h.request_body_with_synth_headers that begins with a synthetic Content-Type: header followed by a blank line and then the request body. h.request_body is now just a pointer into that buffer, starting at the position where the actual body begins. This gives us the ability to supply the body with or without headers, without having to make two copies of it. --- diff --git a/libcitadel/lib/mime_parser.c b/libcitadel/lib/mime_parser.c index 65093a2fa..776e3fe4a 100644 --- a/libcitadel/lib/mime_parser.c +++ b/libcitadel/lib/mime_parser.c @@ -457,13 +457,14 @@ static int IsAsciiEncoding(interesting_mime_headers *m) { } -static char *FindNextContent(char *ptr, - char *content_end, - interesting_mime_headers *SubMimeHeaders, - interesting_mime_headers *m) -{ +static char *FindNextContent( + char *ptr, + char *content_end, + interesting_mime_headers *SubMimeHeaders, + interesting_mime_headers *m +) { char *next_boundary; - char tmp; + char tmp; if (IsAsciiEncoding(SubMimeHeaders)) { tmp = *content_end; @@ -482,8 +483,9 @@ static char *FindNextContent(char *ptr, lines = SubMimeHeaders->content_length / 80; pptr = ptr + SubMimeHeaders->content_length - lines - 10; - if (pptr < content_end) + if (pptr < content_end) { ptr = pptr; + } } next_boundary = strstr(ptr, m->b[startary].Key); @@ -512,8 +514,9 @@ static char *FindNextContent(char *ptr, next_boundary = srch; srch = content_end; } - else srch ++; - + else { + srch++; + } } } @@ -535,15 +538,15 @@ static void recurseable_mime_parser(char *partnum, interesting_mime_headers *m ) { interesting_mime_headers *SubMimeHeaders; - char *ptr; - char *part_start; - char *part_end = NULL; - char *evaluate_crlf_ptr = NULL; - char *next_boundary; - char nested_partnum[256]; - int crlf_in_use = 0; - int part_seq = 0; - CBufStr *chosen_name; + char *ptr; + char *part_start; + char *part_end = NULL; + char *evaluate_crlf_ptr = NULL; + char *next_boundary; + char nested_partnum[256]; + int crlf_in_use = 0; + int part_seq = 0; + CBufStr *chosen_name; // If this is a multipart message, then recursively process it ptr = content_start; @@ -568,7 +571,7 @@ static void recurseable_mime_parser(char *partnum, // Figure out where the boundaries are m->b[startary].len = snprintf(m->b[startary].Key, SIZ, "--%s", m->b[boundary].Key); - SubMimeHeaders = InitInterestingMimes (); + SubMimeHeaders = InitInterestingMimes(); while ((*ptr == '\r') || (*ptr == '\n')) { ptr++; @@ -610,14 +613,14 @@ static void recurseable_mime_parser(char *partnum, if (!IsEmptyStr(partnum)) { snprintf(nested_partnum, - sizeof nested_partnum, - "%s.%d", partnum, - ++part_seq); + sizeof nested_partnum, + "%s.%d", partnum, + ++part_seq); } else { snprintf(nested_partnum, - sizeof nested_partnum, - "%d", ++part_seq); + sizeof nested_partnum, + "%d", ++part_seq); } recurseable_mime_parser(nested_partnum, part_start, @@ -679,6 +682,7 @@ static void recurseable_mime_parser(char *partnum, ); } } + // If it's not a multipart message, then do something with it else { size_t length; @@ -803,9 +807,7 @@ void the_mime_parser(char *partnum, } m = InitInterestingMimes(); - if (!parse_MimeHeaders(m, &content_start, content_end)) { - recurseable_mime_parser(partnum, content_start, content_end, CallBack, diff --git a/webcit-ng/server/http.c b/webcit-ng/server/http.c index 82fd5f3c2..1740ccec8 100644 --- a/webcit-ng/server/http.c +++ b/webcit-ng/server/http.c @@ -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); diff --git a/webcit-ng/server/upload.c b/webcit-ng/server/upload.c index 356cd1d75..8c3fd44e0 100644 --- a/webcit-ng/server/upload.c +++ b/webcit-ng/server/upload.c @@ -26,6 +26,9 @@ void upload_handler(char *name, char *filename, char *partnum, char *disp, syslog(LOG_DEBUG, " length: %ld", length); syslog(LOG_DEBUG, " encoding: %s", encoding); syslog(LOG_DEBUG, " id: %s", cbid); + //fprintf(stderr, "\033[31m--------------------------------------------\n"); + //write(content, length, 1, stderr); // FIXME + //printf(stderr, "--------------------------------------------\033[0m\n"); struct uploaded_file u; @@ -85,8 +88,8 @@ void upload_files(struct http_transaction *h, struct ctdlsession *c) { // Normally the browser will upload only one file per transaction, but that behavior is not guaranteed. JsonValue *j_uploads = NewJsonArray(HKEY("")); - // h->request_body will contain the upload(s) in MIME format - mime_parser(h->request_body, (h->request_body + h->request_body_length), *upload_handler, NULL, NULL, j_uploads, 0); + // h->request_body_with_synth_headers will contain the upload(s) in MIME format including headers + mime_parser(h->request_body_with_synth_headers, (h->request_body+h->request_body_length), *upload_handler, NULL, NULL, j_uploads, 0); // probably do something more clever here h->response_code = 200; diff --git a/webcit-ng/server/webcit.h b/webcit-ng/server/webcit.h index a8c1275a8..8af98ec26 100644 --- a/webcit-ng/server/webcit.h +++ b/webcit-ng/server/webcit.h @@ -64,7 +64,8 @@ struct http_transaction { // The lifetime of an HTTP request goes through this char *http_version; // stack and sent back down to the web server, which transmits it to char *site_prefix; // the client. Array *request_headers; - char *request_body; + char *request_body_with_synth_headers; // This is the request body with some synthetic headers prepended into it. + char *request_body; // this is just going to be a pointer into request_body_with_synth_headers long request_body_length; Array *request_parms; // anything after the "?" in the URL int response_code;