mirror of
https://github.com/logicog/RTLPlayground.git
synced 2026-08-30 14:52:51 +08:00
Fix POST upload request handling for Chrome browser
Chrome sends upload requests using POST with multipart/form-data content type in multiple packets for the header part of the form-data. Introduce a TSTATE_MULTIPART for the httpd server states that denotes that so far only a part of the multipart header has been transmitted. Once the full header has been transmitted, we change to TSTATE_POST as for Firefox which sends all the multipart header in one piece. The main further change required then is to make sure that the parsing of the initial part of the multipart request is only parsed once and initially to distinguish between configuration and firmware uploads.
This commit is contained in:
+58
-43
@@ -60,11 +60,12 @@ __xdata uint32_t now;
|
||||
__xdata uint8_t *timeptr;
|
||||
__xdata uint32_t last_session_use;
|
||||
|
||||
#define TSTATE_NONE 0
|
||||
#define TSTATE_TX 1
|
||||
#define TSTATE_ACKED 2
|
||||
#define TSTATE_CLOSED 3
|
||||
#define TSTATE_POST 4
|
||||
#define TSTATE_NONE 0
|
||||
#define TSTATE_TX 1
|
||||
#define TSTATE_ACKED 2
|
||||
#define TSTATE_CLOSED 3
|
||||
#define TSTATE_POST 4
|
||||
#define TSTATE_MULTIPART 5
|
||||
|
||||
extern __xdata uint16_t crc_value;
|
||||
__xdata uint16_t crc_final;
|
||||
@@ -355,21 +356,46 @@ void handle_post(void)
|
||||
__xdata uint8_t *p = uip_appdata;
|
||||
__xdata uint8_t *request_path = p + 6;
|
||||
|
||||
dbg_string("Is POST\n");
|
||||
p += 5; // Skip post
|
||||
// Find end of request path
|
||||
while (*p && !is_separator(*p))
|
||||
p++;
|
||||
*p++ = '\0';
|
||||
// Was the multipart header sent in multiple packets?
|
||||
if (s->tstate != TSTATE_MULTIPART) {
|
||||
dbg_string("Is POST\n");
|
||||
p += 5; // Skip post
|
||||
// Find end of request path
|
||||
while (*p && !is_separator(*p))
|
||||
p++;
|
||||
*p++ = '\0';
|
||||
|
||||
// Find end of request header
|
||||
boundary[0] ='\0';
|
||||
p = scan_header(p);
|
||||
dbg_string("Boundary: >"); dbg_string_x(boundary); dbg_string("<\n");
|
||||
if (!*p || !content_type) {
|
||||
dbg_string("Bad Request!\n");
|
||||
send_not_found();
|
||||
return;
|
||||
// Find end of request header
|
||||
boundary[0] ='\0';
|
||||
p = scan_header(p);
|
||||
dbg_string("Boundary: >"); dbg_string_x(boundary); dbg_string("<\n");
|
||||
if (!*p || !content_type) {
|
||||
dbg_string("Bad Request!\n");
|
||||
send_not_found();
|
||||
return;
|
||||
}
|
||||
if (is_word(request_path, "upload")) {
|
||||
if (flash_size < FIRMWARE_UPLOAD_START*2)
|
||||
{
|
||||
print_string("Flash too small for firmware upload!\n");
|
||||
send_bad_request();
|
||||
return;
|
||||
}
|
||||
print_string("Firmware upload started.");
|
||||
uptr = FIRMWARE_UPLOAD_START;
|
||||
verify_crc = 1;
|
||||
max_upload = 1024576;
|
||||
} else if (is_word(request_path, "config")) {
|
||||
dbg_string("Configuration upload, erasing config mem!\n");
|
||||
uptr = CONFIG_START;
|
||||
verify_crc = 0;
|
||||
max_upload = 2048;
|
||||
flash_region.addr = CONFIG_START;
|
||||
flash_sector_erase();
|
||||
}
|
||||
// Check for other POST requests, which are not multipart, below
|
||||
} else {
|
||||
dbg_string("Multipart request\n");
|
||||
}
|
||||
|
||||
if (is_word(request_path, "cmd")) {
|
||||
@@ -401,7 +427,7 @@ void handle_post(void)
|
||||
slen = strtox(outbuf, "HTTP/1.1 302 Found\r\nLocation: login.html\r\n\r\n");
|
||||
}
|
||||
return;
|
||||
} else if (is_word(request_path, "upload") || is_word(request_path, "config")) {
|
||||
} else if (s->tstate == TSTATE_MULTIPART || is_word(request_path, "upload") || is_word(request_path, "config")) {
|
||||
dbg_string("POST upload/config request\n");
|
||||
if (!authenticated) {
|
||||
send_unauthorized();
|
||||
@@ -415,8 +441,10 @@ void handle_post(void)
|
||||
// We skip the intial parts as part of the header
|
||||
do {
|
||||
p = skip_boundary(p);
|
||||
if (!*p)
|
||||
goto bad_request;
|
||||
if (!*p) {
|
||||
s->tstate = TSTATE_MULTIPART;
|
||||
return;
|
||||
}
|
||||
p = scan_header(p);
|
||||
if (!*p)
|
||||
goto bad_request;
|
||||
@@ -426,25 +454,6 @@ void handle_post(void)
|
||||
dbg_string("Have content octets\n");
|
||||
p += 4; // Skip \r\n\r\n sequence at end of preamble of part
|
||||
|
||||
if (is_word(request_path, "upload")) {
|
||||
if (flash_size < FIRMWARE_UPLOAD_START*2)
|
||||
{
|
||||
print_string("Flash too small for firmware upload!\n");
|
||||
send_bad_request();
|
||||
return;
|
||||
}
|
||||
print_string("Firmware upload started.");
|
||||
uptr = FIRMWARE_UPLOAD_START;
|
||||
verify_crc = 1;
|
||||
max_upload = 1024576;
|
||||
} else {
|
||||
dbg_string("Configuration upload, erasing config mem!\n");
|
||||
uptr = CONFIG_START;
|
||||
verify_crc = 0;
|
||||
max_upload = 2048;
|
||||
flash_region.addr = CONFIG_START;
|
||||
flash_sector_erase();
|
||||
}
|
||||
flash_init(0); // Re-initialize flash for non-DIO operation, otherwise flashing fails
|
||||
set_sys_led_state(SYS_LED_FAST);
|
||||
|
||||
@@ -473,6 +482,12 @@ void httpd_appcall(void)
|
||||
__xdata struct httpd_state * __xdata s = &(uip_conn->appstate);
|
||||
|
||||
dbg_char('P');
|
||||
#ifdef DEBUG
|
||||
if (uip_newdata())
|
||||
write_char('N');
|
||||
print_byte(s->tstate);
|
||||
write_char(' ');
|
||||
#endif
|
||||
if(uip_connected() && s->tstate == TSTATE_CLOSED) {
|
||||
dbg_string("Connected...\n");
|
||||
s->tstate = TSTATE_NONE;
|
||||
@@ -544,10 +559,10 @@ void httpd_appcall(void)
|
||||
dbg_char('\n');
|
||||
#endif
|
||||
p = uip_appdata;
|
||||
if (is_word(p, "POST")) {
|
||||
if (is_word(p, "POST") || s->tstate == TSTATE_MULTIPART) {
|
||||
handle_post();
|
||||
// If this is an ongoing post stream, then wait for the next packet
|
||||
if (s->tstate == TSTATE_POST) {
|
||||
if (s->tstate == TSTATE_POST || s->tstate == TSTATE_MULTIPART) {
|
||||
uip_len = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user