Example #1
0
/* parses range-resp-spec and inits spec, returns true on success */
static int
httpHdrRangeRespSpecParseInit(HttpHdrRangeSpec * spec, const char *field, int flen)
{
    const char *p;
    assert(spec);
    spec->offset = spec->length = range_spec_unknown;
    if (flen < 2)
	return 0;
    /* is spec given ? */
    if (*field == '*')
	return 1;
    /* check format, must be %d-%d */
    if (!((p = strchr(field, '-')) && (p - field < flen))) {
	debug(68, 2) ("invalid (no '-') resp-range-spec near: '%s'\n", field);
	return 0;
    }
    /* parse offset */
    if (!httpHeaderParseSize(field, &spec->offset))
	return 0;
    p++;
    /* do we have last-pos ? */
    if (p - field < flen) {
	squid_off_t last_pos;
	if (!httpHeaderParseSize(p, &last_pos))
	    return 0;
	spec->length = size_diff(last_pos + 1, spec->offset);
    }
    /* we managed to parse, check if the result makes sence */
    if (known_spec(spec->length) && !spec->length) {
	debug(68, 2) ("invalid range (%ld += %ld) in resp-range-spec near: '%s'\n",
	    (long int) spec->offset, (long int) spec->length, field);
	return 0;
    }
    return 1;
}
Example #2
0
/* returns true if ranges are valid; inits HttpHdrContRange */
int
httpHdrContRangeParseInit(HttpHdrContRange * range, const char *str)
{
    const char *p;
    assert(range && str);
    debug(68, 8) ("parsing content-range field: '%s'\n", str);
    /* check range type */
    if (strncasecmp(str, "bytes ", 6))
	return 0;
    str += 6;
    /* split */
    if (!(p = strchr(str, '/')))
	return 0;
    if (*str == '*')
	range->spec.offset = range->spec.length = range_spec_unknown;
    else if (!httpHdrRangeRespSpecParseInit(&range->spec, str, p - str))
	return 0;
    p++;
    if (*p == '*')
	range->elength = range_spec_unknown;
    else if (!httpHeaderParseSize(p, &range->elength))
	return 0;
    debug(68, 8) ("parsed content-range field: %" PRINTF_OFF_T "-%" PRINTF_OFF_T " / %" PRINTF_OFF_T "\n",
	range->spec.offset, range->spec.offset + range->spec.length - 1,
	range->elength);
    return 1;
}
Example #3
0
squid_off_t
httpHeaderGetSize(const HttpHeader * hdr, http_hdr_type id)
{
    HttpHeaderEntry *e;
    squid_off_t value = -1;
    int ok;
    assert_eid(id);
    assert(Headers[id].type == ftSize);		/* must be of an appropriate type */
    if ((e = httpHeaderFindEntry(hdr, id))) {
	ok = httpHeaderParseSize(strBuf(e->value), &value);
	httpHeaderNoteParsedEntry(e->id, e->value, !ok);
    }
    return value;
}
Example #4
0
/* parses range-spec and returns new object on success */
static HttpHdrRangeSpec *
httpHdrRangeSpecParseCreate(const char *field, int flen)
{
    HttpHdrRangeSpec spec =
    {range_spec_unknown, range_spec_unknown};
    const char *p;
    if (flen < 2)
	return NULL;
    /* is it a suffix-byte-range-spec ? */
    if (*field == '-') {
	if (!httpHeaderParseSize(field + 1, &spec.length))
	    return NULL;
    } else
	/* must have a '-' somewhere in _this_ field */
    if (!((p = strchr(field, '-')) || (p - field >= flen))) {
	debug(64, 2) ("ignoring invalid (missing '-') range-spec near: '%s'\n", field);
	return NULL;
    } else {
	if (!httpHeaderParseSize(field, &spec.offset))
	    return NULL;
	p++;
	/* do we have last-pos ? */
	if (p - field < flen) {
	    ssize_t last_pos;
	    if (!httpHeaderParseSize(p, &last_pos))
		return NULL;
	    spec.length = size_diff(last_pos + 1, spec.offset);
	}
    }
    /* we managed to parse, check if the result makes sence */
    if (known_spec(spec.length) && !spec.length) {
	debug(64, 2) ("ignoring invalid (zero length) range-spec near: '%s'\n", field);
	return NULL;
    }
    return httpHdrRangeSpecDup(&spec);
}
Example #5
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 */
}