httpd: scope the multipart parse cursors to their functions

cfg_pos, cfg_hdr, cfg_body, cfg_end, cfg_last and cfg_bl are used only
by config_take(), so move them out of file scope and into the function.
The five cursors stay static: SDCC register-caches automatic xdata
locals and spills them through DSEG slots, which costs 6 bytes of direct
RAM this build has no room for; static keeps the access pattern of the
old globals and the memory layout is unchanged. cfg_bl produces no spill
slot at the current register pressure, so it is a plain local. The
mechanism is recorded in issue #386.

handle_post() reused cfg_pos and cfg_end as scratch for unrelated
values; those uses get their own named locals, frag_len and
payload_start.
This commit is contained in:
bloqaudio
2026-09-01 09:59:52 -05:00
parent fc3c686564
commit daf9d8965a
+16 -13
View File
@@ -48,10 +48,8 @@ __xdata uint8_t boundary[72];
#define CONFIG_UPLOAD_BUF (CONFIG_LEN + 384) #define CONFIG_UPLOAD_BUF (CONFIG_LEN + 384)
__xdata uint8_t config_upload; __xdata uint8_t config_upload;
__xdata uint8_t config_buf[CONFIG_UPLOAD_BUF]; __xdata uint8_t config_buf[CONFIG_UPLOAD_BUF];
__xdata uint16_t cfg_pos, cfg_hdr, cfg_body, cfg_end, cfg_last;
// part-header bytes buffered so far; accumulates across TCP segments // part-header bytes buffered so far; accumulates across TCP segments
__xdata uint16_t pre_acc; __xdata uint16_t pre_acc;
__xdata uint8_t cfg_bl;
__xdata uint8_t * __xdata content_type = 0; __xdata uint8_t * __xdata content_type = 0;
__xdata uint8_t * __xdata session = 0; __xdata uint8_t * __xdata session = 0;
@@ -325,6 +323,10 @@ void gen_random_hex_chars(__xdata uint8_t * b, __xdata uint8_t bytes)
/* 0: body incomplete, 1: configuration stored, 2: malformed */ /* 0: body incomplete, 1: configuration stored, 2: malformed */
static uint8_t config_take(void) static uint8_t config_take(void)
{ {
// #386: needs static, otherwise it still lands in SRAM/DSEG
static __xdata uint16_t cfg_pos, cfg_hdr, cfg_body, cfg_end, cfg_last;
__xdata uint8_t cfg_bl;
cfg_bl = strlen_x(boundary); cfg_bl = strlen_x(boundary);
// the body is complete once the closing boundary has arrived // the body is complete once the closing boundary has arrived
@@ -505,6 +507,7 @@ void handle_post(void)
__xdata struct httpd_state * __xdata s = &(uip_conn->appstate); __xdata struct httpd_state * __xdata s = &(uip_conn->appstate);
__xdata uint8_t *p = uip_appdata; __xdata uint8_t *p = uip_appdata;
__xdata uint8_t *request_path = p + 6; __xdata uint8_t *request_path = p + 6;
__xdata uint16_t frag_len, payload_start;
// Was the multipart header sent in multiple packets? // Was the multipart header sent in multiple packets?
if (s->tstate != TSTATE_MULTIPART) { if (s->tstate != TSTATE_MULTIPART) {
@@ -600,16 +603,16 @@ void handle_post(void)
return; return;
} }
if (config_upload) { if (config_upload) {
cfg_pos = uip_len - (p - uip_appdata); frag_len = uip_len - (p - uip_appdata);
if (write_len + cfg_pos >= CONFIG_UPLOAD_BUF) { if (write_len + frag_len >= CONFIG_UPLOAD_BUF) {
print_string("Configuration too large, aborting.\n"); print_string("Configuration too large, aborting.\n");
config_upload = 0; config_upload = 0;
s->tstate = TSTATE_NONE; s->tstate = TSTATE_NONE;
send_bad_request(); send_bad_request();
return; return;
} }
memcpy(config_buf + write_len, p, cfg_pos); memcpy(config_buf + write_len, p, frag_len);
write_len += cfg_pos; write_len += frag_len;
uint8_t taken = config_take(); uint8_t taken = config_take();
if (!taken) { if (!taken) {
@@ -625,17 +628,17 @@ void handle_post(void)
slen = strtox(outbuf, "HTTP/1.1 200 OK\r\nConnection: close\r\n\r\n"); slen = strtox(outbuf, "HTTP/1.1 200 OK\r\nConnection: close\r\n\r\n");
return; return;
} }
cfg_pos = uip_len - (p - uip_appdata); frag_len = uip_len - (p - uip_appdata);
if (pre_acc + cfg_pos >= CONFIG_UPLOAD_BUF) { if (pre_acc + frag_len >= CONFIG_UPLOAD_BUF) {
print_string("Firmware upload header too large, aborting.\n"); print_string("Firmware upload header too large, aborting.\n");
s->tstate = TSTATE_NONE; s->tstate = TSTATE_NONE;
send_bad_request(); send_bad_request();
return; return;
} }
memcpy(config_buf + pre_acc, p, cfg_pos); memcpy(config_buf + pre_acc, p, frag_len);
pre_acc += cfg_pos; pre_acc += frag_len;
cfg_end = preamble_payload_start(pre_acc); payload_start = preamble_payload_start(pre_acc);
if (!cfg_end) { if (!payload_start) {
s->tstate = TSTATE_MULTIPART; s->tstate = TSTATE_MULTIPART;
return; return;
} }
@@ -652,7 +655,7 @@ void handle_post(void)
// appcall POST branch cannot send leftovers // appcall POST branch cannot send leftovers
slen = 0; slen = 0;
upload_settings.p = config_buf; upload_settings.p = config_buf;
upload_settings.bptr = cfg_end; upload_settings.bptr = payload_start;
upload_settings.plen = pre_acc; upload_settings.plen = pre_acc;
stream_upload(); stream_upload();