unsigned char * parse_header(unsigned char *head, unsigned char *item, unsigned char **ptr) { unsigned char *pos = head; if (!pos) return NULL; while (*pos) { unsigned char *end, *itempos, *value; int len; /* Go for a newline. */ while (*pos && *pos != ASCII_LF) pos++; if (!*pos) break; pos++; /* Start of line now. */ /* Does item match header line ? */ for (itempos = item; *itempos && *pos; itempos++, pos++) if (c_toupper(*itempos) != c_toupper(*pos)) break; if (!*pos) break; /* Nothing left to parse. */ if (*itempos) continue; /* Do not match. */ /* Be tolerant: we accept headers with * weird syntax, since most browsers does it * anyway, ie: * name value * name :value * name = value * name[TAB]:[TAB]value */ end = pos; /* Skip leading whitespaces if any. */ while (LWS(*pos)) pos++; if (!*pos) break; /* Nothing left to parse. */ /* Eat ':' or '=' if any. */ if (*pos == ':' || *pos == '=') pos++; if (!*pos) break; /* Nothing left to parse. */ /* Skip whitespaces after separator if any. */ while (LWS(*pos)) pos++; if (!*pos) break; /* Nothing left to parse. */ if (pos == end) continue; /* Not an exact match (substring). */ /* Find the end of line/string. * We fail on control chars and DEL char. */ end = pos; while (*end != ASCII_DEL && (*end > ' ' || LWS(*end))) end++; if (!*end) break; /* No end of line, nothing left to parse. */ /* Ignore line if we encountered an unexpected char. */ if (*end != ASCII_CR && *end != ASCII_LF) continue; /* Strip trailing whitespaces. */ while (end > pos && LWS(end[-1])) end--; len = end - pos; assert(len >= 0); if_assert_failed break; if (!len) continue; /* Empty value. */ value = memacpy(pos, len); if (!value) break; /* Allocation failure, stop here. */ if (ptr) *ptr = pos; return value; } return NULL; }
/* Extract the value of name part of the value of attribute content. * Ie. @name = "charset" and @str = "text/html; charset=iso-8859-1" * will store in *@ret an allocated string containing "iso-8859-1". * It supposes that separator is ';' and ignore first element in the * list. (ie. '1' is ignored in "1; URL=xxx") * The return value is one of: * * - HEADER_PARAM_FOUND: the parameter was found, copied, and stored in *@ret. * - HEADER_PARAM_NOT_FOUND: the parameter is not there. *@ret is now NULL. * - HEADER_PARAM_OUT_OF_MEMORY: error. *@ret is now NULL. * * If @ret is NULL, then this function doesn't actually access *@ret, * and cannot fail with HEADER_PARAM_OUT_OF_MEMORY. Some callers may * rely on this. */ enum parse_header_param parse_header_param(unsigned char *str, unsigned char *name, unsigned char **ret) { unsigned char *p = str; int namelen, plen = 0; if (ret) *ret = NULL; /* default in case of early return */ assert(str && name && *name); if_assert_failed return HEADER_PARAM_NOT_FOUND; /* Returns now if string @str is empty. */ if (!*p) return HEADER_PARAM_NOT_FOUND; namelen = strlen((const char *)name); do { p = (unsigned char *)strchr((char *)p, ';'); if (!p) return HEADER_PARAM_NOT_FOUND; while (*p && (*p == ';' || *p <= ' ')) p++; if (strlen((const char *)p) < namelen) return HEADER_PARAM_NOT_FOUND; } while (c_strncasecmp((const char *)p, (const char *)name, namelen)); p += namelen; while (*p && (*p <= ' ' || *p == '=')) p++; if (!*p) { if (ret) { *ret = stracpy((const unsigned char *)""); if (!*ret) return HEADER_PARAM_OUT_OF_MEMORY; } return HEADER_PARAM_FOUND; } while ((p[plen] > ' ' || LWS(p[plen])) && p[plen] != ';') plen++; /* Trim ending spaces */ while (plen > 0 && LWS(p[plen - 1])) plen--; /* XXX: Drop enclosing single quotes if there's some. * * Some websites like newsnow.co.uk are using single quotes around url * in URL field in meta tag content attribute like this: * <meta http-equiv="Refresh" content="0; URL='http://www.site.com/path/xxx.htm'"> * * This is an attempt to handle that, but it may break something else. * We drop all pair of enclosing quotes found (eg. '''url''' => url). * Please report any issue related to this. --Zas */ while (plen > 1 && *p == '\'' && p[plen - 1] == '\'') { p++; plen -= 2; } if (ret) { *ret = memacpy(p, plen); if (!*ret) return HEADER_PARAM_OUT_OF_MEMORY; } return HEADER_PARAM_FOUND; }