/* parses and inits header entry, returns new entry on success */
static HttpHeaderEntry *
httpHeaderEntryParseCreate(const char *field_start, const char *field_end)
{
    HttpHeaderEntry *e;
    int id;
    /* note: name_start == field_start */
    const char *name_end = strchr(field_start, ':');
    const int name_len = name_end ? name_end - field_start : 0;
    const char *value_start = field_start + name_len + 1;	/* skip ':' */
    /* note: value_end == field_end */

    HeaderEntryParsedCount++;

    /* do we have a valid field name within this field? */
    if (!name_len || name_end > field_end)
	return NULL;
    if (name_len > 65536) {
	/* String has a 64K limit */
	debug(55, 1) ("WARNING: ignoring header name of %d bytes\n", name_len);
	return NULL;
    }
    /* now we know we can parse it */
    e = memAllocate(MEM_HTTP_HDR_ENTRY);
    debug(55, 9) ("creating entry %p: near '%s'\n", e, getStringPrefix(field_start, field_end));
    /* is it a "known" field? */
    id = httpHeaderIdByName(field_start, name_len, Headers, HDR_ENUM_END);
    if (id < 0)
	id = HDR_OTHER;
    assert_eid(id);
    e->id = id;
    /* set field name */
    if (id == HDR_OTHER)
	stringLimitInit(&e->name, field_start, name_len);
    else
	e->name = Headers[id].name;
    /* trim field value */
    while (value_start < field_end && xisspace(*value_start))
	value_start++;
    if (field_end - value_start > 65536) {
	/* String has a 64K limit */
	debug(55, 1) ("WARNING: ignoring '%s' header of %d bytes\n",
	    strBuf(e->name), (int) (field_end - value_start));
	if (e->id == HDR_OTHER)
	    stringClean(&e->name);
	memFree(e, MEM_HTTP_HDR_ENTRY);
	return NULL;
    }
    /* set field value */
    stringLimitInit(&e->value, value_start, field_end - value_start);
    Headers[id].stat.seenCount++;
    Headers[id].stat.aliveCount++;
    debug(55, 9) ("created entry %p: '%s: %s'\n", e, strBuf(e->name), strBuf(e->value));
    return e;
}
int
httpHeaderParse(HttpHeader * hdr, const char *header_start, const char *header_end)
{
    const char *field_start = header_start;
    HttpHeaderEntry *e;

    assert(hdr);
    assert(header_start && header_end);
    debug(55, 7) ("parsing hdr: (%p)\n%s\n", hdr, getStringPrefix(header_start, header_end));
    HttpHeaderStats[hdr->owner].parsedCount++;
    /* commonn format headers are "<name>:[ws]<value>" lines delimited by <CRLF> */
    while (field_start < header_end) {
	const char *field_end;
	const char *field_ptr = field_start;
	do {
	    field_end = field_ptr = field_ptr + strcspn(field_ptr, "\r\n");
	    /* skip CRLF */
	    if (*field_ptr == '\r')
		field_ptr++;
	    if (*field_ptr == '\n')
		field_ptr++;
	}
	while (*field_ptr == ' ' || *field_ptr == '\t');
	if (!*field_end || field_end > header_end)
	    return httpHeaderReset(hdr);	/* missing <CRLF> */
	e = httpHeaderEntryParseCreate(field_start, field_end);
	if (e != NULL)
	    httpHeaderAddEntry(hdr, e);
	else
	    debug(55, 2) ("warning: ignoring unparseable http header field near '%s'\n",
		getStringPrefix(field_start, field_end));
	field_start = field_end;
	/* skip CRLF */
	if (*field_start == '\r')
	    field_start++;
	if (*field_start == '\n')
	    field_start++;
    }
    return 1;			/* even if no fields where found, it is a valid header */
}
示例#3
0
int
httpHeaderParse(HttpHeader * hdr, const char *header_start, const char *header_end)
{
    const char *field_ptr = header_start;
    HttpHeaderEntry *e;

    assert(hdr);
    assert(header_start && header_end);
    debug(55, 7) ("parsing hdr: (%p)\n%s\n", hdr, getStringPrefix(header_start, header_end));
    HttpHeaderStats[hdr->owner].parsedCount++;
    if (memchr(header_start, '\0', header_end - header_start)) {
	debug(55, 1) ("WARNING: HTTP header contains NULL characters {%s}\n",
	    getStringPrefix(header_start, header_end));
	return httpHeaderReset(hdr);
    }
    /* common format headers are "<name>:[ws]<value>" lines delimited by <CRLF>.
     * continuation lines start with a (single) space or tab */
    while (field_ptr < header_end) {
	const char *field_start = field_ptr;
	const char *field_end;
	do {
	    const char *this_line = field_ptr;
	    field_ptr = memchr(field_ptr, '\n', header_end - field_ptr);
	    if (!field_ptr)
		return httpHeaderReset(hdr);	/* missing <LF> */
	    field_end = field_ptr;
	    field_ptr++;	/* Move to next line */
	    if (field_end > this_line && field_end[-1] == '\r') {
		field_end--;	/* Ignore CR LF */
		/* Ignore CR CR LF in relaxed mode */
		if (Config.onoff.relaxed_header_parser && field_end > this_line + 1 && field_end[-1] == '\r') {
		    debug(55, Config.onoff.relaxed_header_parser <= 0 ? 1 : 2)
			("WARNING: Double CR characters in HTTP header {%s}\n", getStringPrefix(field_start, field_end));
		    field_end--;
		}
	    }
	    /* Barf on stray CR characters */
	    if (memchr(this_line, '\r', field_end - this_line)) {
		debug(55, 1) ("WARNING: suspicious CR characters in HTTP header {%s}\n",
		    getStringPrefix(field_start, field_end));
		if (Config.onoff.relaxed_header_parser) {
		    char *p = (char *) this_line;	/* XXX Warning! This destroys original header content and violates specifications somewhat */
		    while ((p = memchr(p, '\r', field_end - p)) != NULL)
			*p++ = ' ';
		} else
		    return httpHeaderReset(hdr);
	    }
	    if (this_line + 1 == field_end && this_line > field_start) {
		debug(55, 1) ("WARNING: Blank continuation line in HTTP header {%s}\n",
		    getStringPrefix(header_start, header_end));
		return httpHeaderReset(hdr);
	    }
	} while (field_ptr < header_end && (*field_ptr == ' ' || *field_ptr == '\t'));
	if (field_start == field_end) {
	    if (field_ptr < header_end) {
		debug(55, 1) ("WARNING: unparseable HTTP header field near {%s}\n",
		    getStringPrefix(field_start, header_end));
		return httpHeaderReset(hdr);
	    }
	    break;		/* terminating blank line */
	}
	e = httpHeaderEntryParseCreate(field_start, field_end);
	if (NULL == e) {
	    debug(55, 1) ("WARNING: unparseable HTTP header field {%s}\n",
		getStringPrefix(field_start, field_end));
	    debug(55, Config.onoff.relaxed_header_parser <= 0 ? 1 : 2)
		(" in {%s}\n", getStringPrefix(header_start, header_end));
	    if (Config.onoff.relaxed_header_parser)
		continue;
	    else
		return httpHeaderReset(hdr);
	}
	if (e->id == HDR_CONTENT_LENGTH) {
	    squid_off_t l1;
	    HttpHeaderEntry *e2;
	    if (!httpHeaderParseSize(strBuf(e->value), &l1)) {
		debug(55, 1) ("WARNING: Unparseable content-length '%s'\n", strBuf(e->value));
		httpHeaderEntryDestroy(e);
		return httpHeaderReset(hdr);
	    }
	    e2 = httpHeaderFindEntry(hdr, e->id);
	    if (e2 && strCmp(e->value, strBuf(e2->value)) != 0) {
		squid_off_t l2;
		debug(55, Config.onoff.relaxed_header_parser <= 0 ? 1 : 2) ("WARNING: found two conflicting content-length headers in {%s}\n", getStringPrefix(header_start, header_end));
		if (!Config.onoff.relaxed_header_parser) {
		    httpHeaderEntryDestroy(e);
		    return httpHeaderReset(hdr);
		}
		if (!httpHeaderParseSize(strBuf(e2->value), &l2)) {
		    debug(55, 1) ("WARNING: Unparseable content-length '%s'\n", strBuf(e->value));
		    httpHeaderEntryDestroy(e);
		    return httpHeaderReset(hdr);
		}
		if (l1 > l2) {
		    httpHeaderDelById(hdr, e2->id);
		} else {
		    httpHeaderEntryDestroy(e);
		    continue;
		}
	    } else if (e2) {
		debug(55, Config.onoff.relaxed_header_parser <= 0 ? 1 : 2)
		    ("NOTICE: found double content-length header\n");
		if (Config.onoff.relaxed_header_parser) {
		    httpHeaderEntryDestroy(e);
		    continue;
		} else {
		    httpHeaderEntryDestroy(e);
		    return httpHeaderReset(hdr);
		}
	    }
	}
	if (e->id == HDR_OTHER && stringHasWhitespace(strBuf(e->name))) {
	    debug(55, Config.onoff.relaxed_header_parser <= 0 ? 1 : 2)
		("WARNING: found whitespace in HTTP header name {%s}\n", getStringPrefix(field_start, field_end));
	    if (!Config.onoff.relaxed_header_parser) {
		httpHeaderEntryDestroy(e);
		return httpHeaderReset(hdr);
	    }
	}
	httpHeaderAddEntry(hdr, e);
    }
    return 1;			/* even if no fields where found, it is a valid header */
}
示例#4
0
/* parses and inits header entry, returns new entry on success */
static HttpHeaderEntry *
httpHeaderEntryParseCreate(const char *field_start, const char *field_end)
{
    HttpHeaderEntry *e;
    int id;
    /* note: name_start == field_start */
    const char *name_end = memchr(field_start, ':', field_end - field_start);
    int name_len = name_end ? name_end - field_start : 0;
    const char *value_start = field_start + name_len + 1;	/* skip ':' */
    /* note: value_end == field_end */

    HeaderEntryParsedCount++;

    /* do we have a valid field name within this field? */
    if (!name_len || name_end > field_end)
	return NULL;
    if (name_len > 65534) {
	/* String must be LESS THAN 64K and it adds a terminating NULL */
	debug(55, 1) ("WARNING: ignoring header name of %d bytes\n", name_len);
	return NULL;
    }
    if (Config.onoff.relaxed_header_parser && xisspace(field_start[name_len - 1])) {
	debug(55, Config.onoff.relaxed_header_parser <= 0 ? 1 : 2)
	    ("NOTICE: Whitespace after header name in '%s'\n", getStringPrefix(field_start, field_end));
	while (name_len > 0 && xisspace(field_start[name_len - 1]))
	    name_len--;
	if (!name_len)
	    return NULL;
    }
    /* now we know we can parse it */
    e = memAllocate(MEM_HTTP_HDR_ENTRY);
    debug(55, 9) ("creating entry %p: near '%s'\n", e, getStringPrefix(field_start, field_end));
    /* is it a "known" field? */
    id = httpHeaderIdByName(field_start, name_len, Headers, HDR_ENUM_END);
    if (id < 0)
	id = HDR_OTHER;
    assert_eid(id);
    e->id = id;
    /* set field name */
    if (id == HDR_OTHER)
	stringLimitInit(&e->name, field_start, name_len);
    else
	e->name = Headers[id].name;
    /* trim field value */
    while (value_start < field_end && xisspace(*value_start))
	value_start++;
    while (value_start < field_end && xisspace(field_end[-1]))
	field_end--;
    if (field_end - value_start > 65534) {
	/* String must be LESS THAN 64K and it adds a terminating NULL */
	debug(55, 1) ("WARNING: ignoring '%s' header of %d bytes\n",
	    strBuf(e->name), (int) (field_end - value_start));
	if (e->id == HDR_OTHER)
	    stringClean(&e->name);
	memFree(e, MEM_HTTP_HDR_ENTRY);
	return NULL;
    }
    /* set field value */
    stringLimitInit(&e->value, value_start, field_end - value_start);
    Headers[id].stat.seenCount++;
    Headers[id].stat.aliveCount++;
    debug(55, 9) ("created entry %p: '%s: %s'\n", e, strBuf(e->name), strBuf(e->value));
    return e;
}