mirror of
https://github.com/oopuuu/zTC1.git
synced 2025-12-16 23:18:24 +08:00
692 lines
21 KiB
C
692 lines
21 KiB
C
/**
|
|
******************************************************************************
|
|
* @file http_parse.c
|
|
* @author QQ DING
|
|
* @version V1.0.0
|
|
* @date 1-September-2015
|
|
* @brief This maintains the functions that are commonly used by both the
|
|
* HTTP client and the HTTP server for parsing the HTTP requests.
|
|
******************************************************************************
|
|
*
|
|
* The MIT License
|
|
* Copyright (c) 2014 MXCHIP Inc.
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
* in the Software without restriction, including without limitation the rights
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the Software is furnished
|
|
* to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
|
* IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
******************************************************************************
|
|
*/
|
|
|
|
/* http_parse.c: This maintains the functions that are commonly used by both
|
|
* the HTTP client and the HTTP server for parsing the HTTP requests.
|
|
* A typical HTTP request looks like the following:
|
|
*
|
|
* -------------------------
|
|
* GET /index.html HTTP/1.1
|
|
* Content-Length: 35
|
|
* User-Agent: Mozilla/5.0 (Linux)
|
|
* Content-Type: text/html
|
|
* ------------------------
|
|
*
|
|
* The functions within this file do the following job:
|
|
* httpd_parse_hdr_main: parses the first line (starting with GET) into the
|
|
* httpd_request structure
|
|
* httpd_parse_hdr_tags: parses the other tags that carry the name/value pairs.
|
|
* httpd_parse_useragent: is internally used by httpd_parse_hdr_tags to parse
|
|
* the User-Agent line above.
|
|
*/
|
|
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
|
|
#include "httpd.h"
|
|
#include "http-strings.h"
|
|
|
|
#include "httpd_priv.h"
|
|
|
|
#define HTTP_CHUNKED "chunked"
|
|
|
|
#define iswhite(c) ((((c) == ISO_nl) || ((c) == ISO_cr) || \
|
|
((c) == ISO_space) || ((c) == ISO_tab)) ? TRUE : FALSE)
|
|
|
|
/* Find the next user agent product, version, and comment from hdrline. Set
|
|
* the pointers to NULL if not found. Return a pointer to the first unparsed
|
|
* char, or NULL if the whole string was consumed.
|
|
*
|
|
* Typically the product is followed by a version, followed by a comment.
|
|
*/
|
|
static char *__httpd_parse_useragent(char *hdrline, char **product,
|
|
char **version, char **comment)
|
|
{
|
|
char *token = hdrline;
|
|
|
|
*product = 0;
|
|
*version = 0;
|
|
*comment = 0;
|
|
|
|
/* User-Agent strings are composed of products and comments. These are
|
|
* space delimited. Comments start with '(' and end with ')'. Products
|
|
* are either of the form "product/version" or just "product".
|
|
*/
|
|
|
|
/* chomp any whitespace and find the beginning of the product */
|
|
while (*token == ' ') {
|
|
if (*token == 0)
|
|
return 0;
|
|
token++;
|
|
}
|
|
*product = token;
|
|
|
|
while (1) {
|
|
if (*token == 0) {
|
|
/* We reached the end of the string. */
|
|
return 0;
|
|
|
|
} else if (*token == ' ') {
|
|
/* We're done with this token. Terminate it. The next
|
|
* is either an associated comment or the next token.
|
|
*/
|
|
*token = 0;
|
|
if (*(token + 1) != '(')
|
|
return token + 1;
|
|
|
|
} else if (*token == '/') {
|
|
/* Found the version string. */
|
|
*token = 0;
|
|
*version = token + 1;
|
|
|
|
} else if (*token == '(') {
|
|
token++;
|
|
*comment = token;
|
|
/* comment may have embedded ' 's or '/', so find the
|
|
* end here before continuing.
|
|
*/
|
|
while (*token != ')') {
|
|
if (*token == 0) {
|
|
/* unexpected end of comment */
|
|
return 0;
|
|
}
|
|
token++;
|
|
}
|
|
*token = 0;
|
|
return token + 1;
|
|
|
|
} else if (*token == '[') {
|
|
/* non-standard legacy language code. Skip it. */
|
|
while (*token != ']') {
|
|
if (*token == 0) {
|
|
/* Unexpected end */
|
|
return 0;
|
|
}
|
|
token++;
|
|
}
|
|
}
|
|
token++;
|
|
}
|
|
}
|
|
|
|
/* Inspect the hdrline and populate the user agent data structure. */
|
|
|
|
/* Many many many browsers do not abide by the RFC to construct their user
|
|
* agent strings. As a result, parsing the user agent is quite tricky, and no
|
|
* authoritative algorithm exists. For some clues about parsing user agent
|
|
* strings, see:
|
|
*
|
|
* http://www.texsoft.it/index.php?c=software&m=sw.php.useragent&l=it
|
|
*
|
|
* For an expansive test vector, see:
|
|
*
|
|
* http://www.pgts.com.au/download/data/browser_list.txt strings that
|
|
*
|
|
* Note that this test vector is not authoritative; In fact, it often reports
|
|
* the incorrect output. However, it is highly useful as a list of real-life
|
|
* inputs.
|
|
*/
|
|
#define MOZ_COMPATIBLE "compatible;"
|
|
void httpd_parse_useragent(char *hdrline, httpd_useragent_t * agent)
|
|
{
|
|
char *token, *product, *p, *version, *v, *comment, *dummy;
|
|
int len;
|
|
|
|
/* Inpsect the first token. */
|
|
hdrline = __httpd_parse_useragent(hdrline, &product,
|
|
&version, &comment);
|
|
if (!product)
|
|
goto done;
|
|
|
|
if (strcmp(product, "Mozilla") == 0) {
|
|
if (comment && strncmp(comment, MOZ_COMPATIBLE, sizeof(MOZ_COMPATIBLE) - 1) == 0) {
|
|
/* If this is a "mozilla compatible" browser, parse it
|
|
* and be done. */
|
|
token = strstr(comment, " ") + 1;
|
|
token = __httpd_parse_useragent(token, &product,
|
|
&version, &comment);
|
|
/* Sometimes when the product and version are found
|
|
* within a comment, the version is separated by a space
|
|
* from the product, not the '/'. This appears as the
|
|
* next product to our token parser. If it is numeric,
|
|
* assume it's the version.
|
|
*/
|
|
if (product && !version && token) {
|
|
token = __httpd_parse_useragent(token, &version,
|
|
&dummy,
|
|
&comment);
|
|
if (*version < '0' || *version > '9')
|
|
version = 0;
|
|
}
|
|
|
|
/* Now, some browsers report Mozilla compatible MSIE,
|
|
* but are actually something else! Keep parsing these
|
|
* ones. Otherwise, we're done.
|
|
*/
|
|
if (strcmp(product, "MSIE") != 0)
|
|
goto done;
|
|
}
|
|
|
|
if (!hdrline)
|
|
goto done;
|
|
|
|
/* If this is not a "mozilla compatible" browser, step through
|
|
* the rest of the product/version (comment) tokens and try to
|
|
* figure out what it is.
|
|
*/
|
|
while (1) {
|
|
|
|
hdrline = __httpd_parse_useragent(hdrline, &p,
|
|
&v, &comment);
|
|
if (!p ||
|
|
strcmp(p, "Galeon") == 0 ||
|
|
strcmp(p, "safari") == 0 ||
|
|
strcmp(p, "Safari") == 0 ||
|
|
strcmp(p, "Shiira") == 0 ||
|
|
strcmp(p, "OmniWeb") == 0 ||
|
|
strcmp(p, "Firefox") == 0 ||
|
|
strcmp(p, "Camino") == 0 ||
|
|
strcmp(p, "Phoenix") == 0 ||
|
|
strcmp(p, "Netscape6") == 0 ||
|
|
strcmp(p, "Netscape") == 0 ||
|
|
strcmp(p, "NetFront") == 0 ||
|
|
strcmp(p, "WebTV") == 0) {
|
|
product = p;
|
|
version = v;
|
|
goto done;
|
|
} else if (strcmp(p, "Opera") == 0) {
|
|
/* Many Opera browsers say "Opera VER" instead
|
|
* of Opera/VER */
|
|
product = p;
|
|
version = v;
|
|
if (v == 0 && hdrline) {
|
|
hdrline =
|
|
__httpd_parse_useragent(hdrline,
|
|
&version,
|
|
&dummy,
|
|
&comment);
|
|
if (*version < '0' || *version > '9')
|
|
version = 0;
|
|
}
|
|
goto done;
|
|
}
|
|
|
|
if (!hdrline)
|
|
goto done;
|
|
}
|
|
} else if ((strcmp(product, "MSIE") == 0 ||
|
|
strcmp(product, "Netscape") == 0) &&
|
|
version == 0 && hdrline) {
|
|
/* Some MSIE and Netscape browsers report Mozilla compatbile.
|
|
* Others say PROD/VER. Others say PROD VER.
|
|
*/
|
|
hdrline = __httpd_parse_useragent(hdrline, &version,
|
|
&dummy, &comment);
|
|
if (*version < '0' || *version > '9')
|
|
version = 0;
|
|
}
|
|
|
|
done:
|
|
if (product) {
|
|
len = strlen(product);
|
|
if (product[len - 1] == ';')
|
|
product[len - 1] = 0;
|
|
strncpy(agent->product, product, HTTPD_MAX_VAL_LENGTH);
|
|
|
|
/* Sometimes if there's a comment but no version, the first
|
|
* token in the comment is the version.
|
|
*/
|
|
if (comment && !version && *comment >= '0' && *comment <= '9') {
|
|
version = comment;
|
|
while (*comment != ' ' && *comment != 0)
|
|
comment++;
|
|
*comment = 0;
|
|
}
|
|
} else
|
|
strncpy(agent->product, "unknown", HTTPD_MAX_VAL_LENGTH);
|
|
|
|
agent->product[HTTPD_MAX_VAL_LENGTH] = 0;
|
|
|
|
if (version) {
|
|
len = strlen(version);
|
|
if (version[len - 1] == ';')
|
|
version[len - 1] = 0;
|
|
/* Truncate version strings with unexpected chars */
|
|
dummy = strstr(version, ",");
|
|
if (dummy)
|
|
*dummy = 0;
|
|
dummy = strstr(version, "+");
|
|
if (dummy)
|
|
*dummy = 0;
|
|
strncpy(agent->version, version, HTTPD_MAX_VAL_LENGTH);
|
|
} else
|
|
memset(agent->version, 0, HTTPD_MAX_VAL_LENGTH + 1);
|
|
|
|
agent->version[HTTPD_MAX_VAL_LENGTH] = 0;
|
|
}
|
|
|
|
|
|
/* Parse the individual components of the HTTP header and reflect it in
|
|
* httpd_request_t structure. */
|
|
static int __httpd_parse_hdr_tags(char *data_p, int len,
|
|
httpd_request_t *req_p, uint8_t *done)
|
|
{
|
|
// ASSERT((data_p != NULL) && (req_p != NULL));
|
|
|
|
if ((*data_p == ISO_nl) || (*data_p == ISO_cr) || (*data_p == 0)) {
|
|
/* Indicate that the parsing is now complete */
|
|
*done = 1;
|
|
return kNoErr;
|
|
}
|
|
|
|
if (strncasecmp(data_p, http_content_len, sizeof(http_content_len) - 1) == 0) {
|
|
req_p->body_nbytes =
|
|
atol(&data_p[sizeof(http_content_len) - 1]);
|
|
if (req_p->body_nbytes == 0) {
|
|
httpd_d("got 0 for body length");
|
|
return kNoErr;
|
|
}
|
|
req_p->remaining_bytes = req_p->body_nbytes;
|
|
} else if (strncasecmp(data_p, http_user_agent, sizeof(http_user_agent) - 1) == 0) {
|
|
/* chomp the : and ' ' and pass it to the internal parser */
|
|
httpd_parse_useragent(data_p + sizeof(http_user_agent) + 1,
|
|
&req_p->agent);
|
|
} else if (strncasecmp(data_p, http_content_type, sizeof(http_content_type) - 1) == 0) {
|
|
memcpy(req_p->content_type, data_p + strlen(http_content_type),
|
|
strlen(data_p));
|
|
} else if (strncasecmp(data_p, "If-None-Match", sizeof("If-None-Match") - 1) == 0) {
|
|
/*
|
|
* We use the FTFS CRC to generate ETag. Hence, the ETag we
|
|
* receive is not expected to be more that 32 bits in value.
|
|
*/
|
|
const char *first_double_quote = strchr(data_p, '"');
|
|
if (!first_double_quote) {
|
|
httpd_d("If_None_Match has no double quote");
|
|
return -kInProgressErr;
|
|
}
|
|
|
|
const char *etag_start = ++first_double_quote;
|
|
req_p->etag_val = strtol(etag_start, NULL, 16);
|
|
req_p->if_none_match = TRUE;
|
|
} else if (strncasecmp(data_p, http_encoding, sizeof(http_encoding) - 1) == 0) {
|
|
if (!strncasecmp(&data_p[sizeof(http_encoding) - 1],
|
|
HTTP_CHUNKED, sizeof(HTTP_CHUNKED) - 1))
|
|
req_p->chunked = 1;
|
|
}
|
|
return kNoErr;
|
|
}
|
|
|
|
/* One-by-one read lines terminated by CR-LF from the socket, and
|
|
* parse the headers contained in them. */
|
|
int httpd_parse_hdr_tags(httpd_request_t *req, int sock, char *buffer, int len)
|
|
{
|
|
int req_line_len;
|
|
int err;
|
|
uint8_t done = 0;
|
|
|
|
while (TRUE) {
|
|
req_line_len = htsys_getln_soc(sock, buffer, len);
|
|
if (req_line_len == -kInProgressErr) {
|
|
httpd_d("Could not read line from socket");
|
|
return -kInProgressErr;
|
|
}
|
|
|
|
err = __httpd_parse_hdr_tags(buffer, req_line_len, req, &done);
|
|
if (err != kNoErr)
|
|
return err;
|
|
if (done == 1) {
|
|
if (req->agent.product[0] != 0) {
|
|
/* Populate the diagnostics statistics variable
|
|
* with the user agent string. Do not do
|
|
* anything if the agent string is NULL
|
|
* (http-client). This is required since this
|
|
* code is used by http server as well as client
|
|
* and we do not want the user agent diagnostics
|
|
* variable to change during the client code
|
|
* path
|
|
*/
|
|
/* Note that, currently wm_hd_useragent is
|
|
* populated only for file handling requests and
|
|
* HTTP POST requests and not for HTTP GET. This
|
|
* is because, in GET requests we directly purge
|
|
* all the headers without reading them and
|
|
* hence do not populate the useragent */
|
|
// memcpy(&g_wm_stats.wm_hd_useragent, &req->agent,
|
|
// sizeof(g_wm_stats.wm_hd_useragent));
|
|
// g_wm_stats.wm_hd_time = wmtime_time_get_posix();
|
|
}
|
|
return kNoErr;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/* Get a pointer to the next token in a request. A token is
|
|
* delimited by whitespace (tab space or newline cr or '\0'. We assume that
|
|
* all databuffers are null terminated
|
|
*/
|
|
static const char *httpd_next_token(const char *data_p)
|
|
{
|
|
// ASSERT(data_p != NULL);
|
|
char c;
|
|
|
|
/* skip over current token, but return if we're at the end of the
|
|
* data */
|
|
while (TRUE) {
|
|
c = *data_p;
|
|
if (c == '\0')
|
|
return data_p;
|
|
if (iswhite(c))
|
|
break;
|
|
data_p++;
|
|
}
|
|
|
|
/* skip over white spaces after last token */
|
|
while (TRUE) {
|
|
c = *data_p;
|
|
if ((c == '\0') || (!iswhite(c)))
|
|
break;
|
|
data_p++;
|
|
}
|
|
|
|
/* return the token */
|
|
return (char *)data_p;
|
|
}
|
|
|
|
/* Extract a token from data_p and copy it into dest_p.
|
|
*/
|
|
static int httpd_token_cpy(const char *data_p, char *dest_p, int dest_len)
|
|
{
|
|
int i = 0;
|
|
|
|
// ASSERT(data_p != NULL);
|
|
|
|
while (!iswhite(*data_p) && i < dest_len && *data_p != '\0') {
|
|
dest_p[i] = *data_p;
|
|
i++;
|
|
data_p++;
|
|
}
|
|
|
|
if (!iswhite(*data_p) && i == dest_len) {
|
|
/* Token too long to fit in dest_len */
|
|
return -kInProgressErr;
|
|
}
|
|
|
|
/* Add trailing \0 */
|
|
dest_p[i] = 0;
|
|
return kNoErr;
|
|
|
|
}
|
|
|
|
/* Verify that the request type is valid and then set the request in
|
|
* the request struct passed in.
|
|
*/
|
|
static int httpd_verify_req_type(const char *token_p, int *type)
|
|
{
|
|
// ASSERT(token_p != NULL);
|
|
|
|
if (strncmp(token_p, http_post, sizeof(http_post) - 1) == 0)
|
|
*type = HTTPD_REQ_TYPE_POST;
|
|
else if (strncmp(token_p, http_get, sizeof(http_get) - 1) == 0)
|
|
*type = HTTPD_REQ_TYPE_GET;
|
|
else if (strncmp(token_p, http_put, sizeof(http_put) - 1) == 0)
|
|
*type = HTTPD_REQ_TYPE_PUT;
|
|
else if (strncmp(token_p, http_delete, sizeof(http_delete) - 1) == 0)
|
|
*type = HTTPD_REQ_TYPE_DELETE;
|
|
else if (strncmp(token_p, http_head, sizeof(http_head) - 1) == 0)
|
|
*type = HTTPD_REQ_TYPE_HEAD;
|
|
else {
|
|
*type = HTTPD_REQ_TYPE_UNKNOWN;
|
|
return -kInProgressErr;
|
|
}
|
|
|
|
return kNoErr;
|
|
}
|
|
|
|
/* Parse the main header (GET /index.html HTTP/1.1) within the HTTP header and
|
|
* update the httpd_request structure with the same.
|
|
*/
|
|
int httpd_parse_hdr_main(const char *data_p, httpd_request_t * req_p)
|
|
{
|
|
const char *ptr, *next;
|
|
int err;
|
|
#define TOKEN_LEN 10
|
|
char token[TOKEN_LEN];
|
|
|
|
/* First token is usually GET/POST */
|
|
err = httpd_verify_req_type(data_p, &req_p->type);
|
|
if (err != kNoErr) {
|
|
httpd_d("Unknown request type %s", data_p);
|
|
httpd_purge_headers(req_p->sock);
|
|
return err;
|
|
}
|
|
|
|
/* Second token: Filename */
|
|
ptr = httpd_next_token(data_p);
|
|
next = ptr;
|
|
|
|
err = httpd_token_cpy(ptr, req_p->filename, HTTPD_MAX_URI_LENGTH);
|
|
if (err != kNoErr) {
|
|
httpd_set_error("Error processing token: filename. "
|
|
"Filename missing or too long?");
|
|
return -WM_E_HTTPD_HDR_FNAME;
|
|
}
|
|
|
|
/* Third token: HTTP version */
|
|
ptr = httpd_next_token(next);
|
|
next = ptr;
|
|
|
|
err = httpd_token_cpy(ptr, token, TOKEN_LEN);
|
|
if (!strncmp(token, http_10, TOKEN_LEN)) {
|
|
httpd_set_error("HTTP/1.0 clients are not supported");
|
|
return -WM_E_HTTPD_NOTSUPP;
|
|
}
|
|
|
|
return kNoErr;
|
|
}
|
|
|
|
|
|
|
|
/* Utility function to convert a character to the nibble. This is used for
|
|
* converting encoded characters to data. */
|
|
static int char2nibble(char c)
|
|
{
|
|
if (c >= '0' && c <= '9')
|
|
return c - '0';
|
|
else if (c >= 'A' && c <= 'F')
|
|
return c - 'A' + 0xA;
|
|
else if (c >= 'a' && c <= 'f')
|
|
return c - 'a' + 0xa;
|
|
|
|
return -1;
|
|
}
|
|
|
|
/* Parse a tag value pair. tag1=value1&tag2=value2
|
|
*/
|
|
static char *httpd_parse_msgbody(char *data_p, const char *tag,
|
|
char *val, unsigned val_len, short *found)
|
|
{
|
|
int i, c1, c2;
|
|
char *ptr;
|
|
const char *tag_p;
|
|
|
|
*found = 0;
|
|
|
|
if (data_p == NULL || *data_p == '\0')
|
|
return NULL;
|
|
|
|
ptr = data_p;
|
|
tag_p = tag;
|
|
while (1) {
|
|
if (*ptr == 0) {
|
|
httpd_d("End of string reached");
|
|
return NULL;
|
|
}
|
|
if (*ptr == '=') {
|
|
/* End of tag */
|
|
if (*tag_p != 0)
|
|
goto next_token;
|
|
else
|
|
break;
|
|
}
|
|
/* perform url decode */
|
|
if (*ptr == '%') {
|
|
ptr++;
|
|
c1 = char2nibble(*ptr++);
|
|
c2 = char2nibble(*ptr++);
|
|
if (c1 == -1 || c2 == -1) {
|
|
httpd_d("Invalid URL-encoded"
|
|
" string. Ignoring.");
|
|
return NULL;
|
|
}
|
|
if (*tag_p != ((c1 << 4) | c2))
|
|
goto next_token;
|
|
tag_p++;
|
|
} else if (*ptr == '+') {
|
|
if (*tag_p != ' ')
|
|
goto next_token;
|
|
tag_p++;
|
|
ptr++;
|
|
} else {
|
|
if (*tag_p != *ptr)
|
|
goto next_token;
|
|
ptr++;
|
|
tag_p++;
|
|
}
|
|
}
|
|
|
|
/* We come here only if tag was found */
|
|
*found = 1;
|
|
ptr = strchr(ptr, '='); /* skip to next token */
|
|
if (ptr == NULL) {
|
|
httpd_d("No = after tag");
|
|
return NULL;
|
|
}
|
|
ptr++;
|
|
|
|
for (i = 0; i < val_len; i++) {
|
|
if ((*ptr == '&') || (*ptr == 0)) {
|
|
val[i] = 0;
|
|
break;
|
|
}
|
|
|
|
/* perform url decode */
|
|
if (*ptr == '%') {
|
|
ptr++;
|
|
c1 = char2nibble(*ptr++);
|
|
c2 = char2nibble(*ptr++);
|
|
if (c1 == -1 || c2 == -1) {
|
|
httpd_d("Invalid URL-encoded"
|
|
" string. Ignoring.");
|
|
return NULL;
|
|
}
|
|
val[i] = (c1 << 4) | c2;
|
|
} else if (*ptr == '+') {
|
|
val[i] = ' ';
|
|
ptr++;
|
|
} else {
|
|
val[i] = *ptr++;
|
|
}
|
|
}
|
|
|
|
if (i == val_len) {
|
|
val[val_len] = 0;
|
|
if ((*ptr != '&') && (*ptr != 0))
|
|
httpd_d("Max val length exceeded. "
|
|
"Truncating value ");
|
|
}
|
|
|
|
next_token:
|
|
ptr = strchr(ptr, '&'); /* skip to next token */
|
|
|
|
if (ptr == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
return ptr + 1;
|
|
}
|
|
|
|
static int __httpd_parse_all_tags(char *inbuf, const char *tag,
|
|
char *val, unsigned val_len)
|
|
|
|
{
|
|
short found = 0;
|
|
char *ptr;
|
|
|
|
ptr = inbuf;
|
|
while (1) {
|
|
ptr = httpd_parse_msgbody(ptr, tag, val, val_len, &found);
|
|
if (ptr < 0) {
|
|
httpd_d("Failed to parse request");
|
|
return -kInProgressErr;
|
|
}
|
|
if (found)
|
|
return kNoErr;
|
|
|
|
if (ptr == NULL)
|
|
break;
|
|
}
|
|
|
|
return -kInProgressErr;
|
|
}
|
|
|
|
|
|
/* Lookup tags in HTTP POST Buffer
|
|
*/
|
|
int httpd_get_tag_from_post_data(char *inbuf, const char *tag,
|
|
char *val, unsigned val_len)
|
|
{
|
|
if (val_len <= 0)
|
|
return -kInProgressErr;
|
|
*val = '\0';
|
|
return __httpd_parse_all_tags(inbuf, tag, val, val_len);
|
|
}
|
|
|
|
/* Lookup tags in HTTP GET URL
|
|
*/
|
|
int httpd_get_tag_from_url(httpd_request_t *req_p, const char *tag,
|
|
char *val, unsigned val_len)
|
|
{
|
|
char *p;
|
|
|
|
if (val_len <= 0)
|
|
return -kInProgressErr;
|
|
|
|
*val = '\0';
|
|
p = strchr(req_p->filename, '?');
|
|
/* No tag=value pairs were present in the url */
|
|
if (!p)
|
|
return -kInProgressErr;
|
|
|
|
return __httpd_parse_all_tags(p + 1, tag, val, val_len);
|
|
}
|