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.
}
-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;
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);
next_boundary = srch;
srch = content_end;
}
- else srch ++;
-
+ else {
+ srch++;
+ }
}
}
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;
// 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++;
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,
);
}
}
+
// If it's not a multipart message, then do something with it
else {
size_t length;
}
m = InitInterestingMimes();
-
if (!parse_MimeHeaders(m, &content_start, content_end)) {
-
recurseable_mime_parser(partnum,
content_start, content_end,
CallBack,
// 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.
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");
}
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
}
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.
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);
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;
// 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;
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;