mirror of
https://github.com/logicog/RTLPlayground.git
synced 2026-09-02 15:02:51 +08:00
httpd: match header field names case-insensitively
scan_header() found Content-Type and Cookie with is_word(), which compares bytes exactly and requires a separator after the pattern. Field names are case-insensitive (RFC 7230 section 3.2), and the whitespace after the colon is optional, so "content-type: multipart/..." and "Content-Type:multipart/..." were both treated as absent. The value pointers were then fixed offsets that assumed exactly one space. Add header_value(), which matches a lower-case name anchored at the line start, folds the request bytes to lower case as it compares, and returns the start of the value past any blanks, so a call site no longer adds the name length by hand. Cookie scanning reuses the returned pointer, and the end-of-header test becomes the strstart() the file already has.
This commit is contained in:
+28
-9
@@ -138,6 +138,24 @@ bool is_word(__xdata uint8_t *xdata_str_p, __code uint8_t * __xdata code_str_p)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* name must be lower-case, starting with the '\n' of the previous line's end */
|
||||||
|
__xdata uint8_t *header_value(__xdata uint8_t *p, __code uint8_t *name)
|
||||||
|
{
|
||||||
|
uint8_t u, c;
|
||||||
|
|
||||||
|
while ((c = *name++)) {
|
||||||
|
u = *p++;
|
||||||
|
if (u >= 'A' && u <= 'Z')
|
||||||
|
u += 'a' - 'A';
|
||||||
|
if (u != c)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
while (*p == ' ' || *p == '\t')
|
||||||
|
p++;
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool is_url_word_x(__xdata uint8_t *uri_str_p, __xdata uint8_t *src_str_p)
|
bool is_url_word_x(__xdata uint8_t *uri_str_p, __xdata uint8_t *src_str_p)
|
||||||
{
|
{
|
||||||
uint8_t u, s;
|
uint8_t u, s;
|
||||||
@@ -248,28 +266,29 @@ void send_unauthorized(void)
|
|||||||
|
|
||||||
__xdata uint8_t *scan_header(__xdata uint8_t * __xdata p)
|
__xdata uint8_t *scan_header(__xdata uint8_t * __xdata p)
|
||||||
{
|
{
|
||||||
|
__xdata uint8_t *v;
|
||||||
|
|
||||||
content_type = 0;
|
content_type = 0;
|
||||||
session = 0;
|
session = 0;
|
||||||
authenticated = 0;
|
authenticated = 0;
|
||||||
|
|
||||||
while (*p != '\r' || *(p + 1) != '\n' || *(p + 2) != '\r' || *(p + 3) != '\n') {
|
while (!strstart(p, "\r\n\r\n")) {
|
||||||
dbg_char(*p);
|
dbg_char(*p);
|
||||||
if (!*p++)
|
if (!*p++)
|
||||||
break;
|
break;
|
||||||
if (is_word(p, "\nContent-Type:"))
|
if ((v = header_value(p, "\ncontent-type:")))
|
||||||
content_type = p + 15;
|
content_type = v;
|
||||||
else if (is_word(p, "\nCookie:")) {
|
else if ((v = header_value(p, "\ncookie:"))) {
|
||||||
/* Scan for the "session" key: the header may hold several
|
/* Scan for the "session" key: the header may hold several
|
||||||
* cookies in any order. Match "session" not "session=" -
|
* cookies in any order. Match "session" not "session=" -
|
||||||
* is_word() requires a separator after the match and '=' is
|
* is_word() requires a separator after the match and '=' is
|
||||||
* one, so this also rejects a longer key like "sessionx". */
|
* one, so this also rejects a longer key like "sessionx". */
|
||||||
__xdata uint8_t *c = p + 8; /* past "\nCookie:" */
|
while (*v && *v != '\r' && *v != '\n') {
|
||||||
while (*c && *c != '\r' && *c != '\n') {
|
if (is_word(v, "session")) {
|
||||||
if (is_word(c, "session")) {
|
session = v + 8; /* past "session=" */
|
||||||
session = c + 8; /* past "session=" */
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
c++;
|
v++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user