From ee302681649df3d3f0398fed560639c1321da636 Mon Sep 17 00:00:00 2001 From: Jon Siwek Date: Fri, 23 Sep 2011 10:31:20 -0500 Subject: [PATCH] Teach HTTP parser to derive content length of multipart/byteranges bodies. Addresses #488. --- src/HTTP.cc | 45 +++++++++++++++++++++++++++++++++++++++++++++ src/HTTP.h | 1 + src/MIME.h | 1 + 3 files changed, 47 insertions(+) diff --git a/src/HTTP.cc b/src/HTTP.cc index 0d154f1873..ee5ee5f1df 100644 --- a/src/HTTP.cc +++ b/src/HTTP.cc @@ -5,6 +5,8 @@ #include #include #include +#include +#include #include "NetVar.h" #include "HTTP.h" @@ -310,6 +312,49 @@ void HTTP_Entity::SubmitHeader(MIME_Header* h) } } + // Figure out content length for HTTP 206 Partial Content response + // that uses multipart/byteranges content-type + else if ( strcasecmp_n(h->get_name(), "content-range") == 0 && Parent() && + Parent()->MIMEContentType() == CONTENT_TYPE_MULTIPART && + http_message->MyHTTP_Analyzer()->HTTP_ReplyCode() == 206 ) + { + data_chunk_t vt = h->get_value_token(); + string byte_unit(vt.data, vt.length); + vt = h->get_value_after_token(); + string byte_range(vt.data, vt.length); + byte_range.erase(remove(byte_range.begin(), byte_range.end(), ' '), + byte_range.end()); + + if ( byte_unit != "bytes" ) + http_message->Weird("HTTP_content_range_unknown_byte_unit"); + + size_t p = byte_range.find("/"); + string byte_range_resp_spec = byte_range.substr(0, p); + string instance_length = byte_range.substr(p + 1); + + p = byte_range_resp_spec.find("-"); + string first_byte_pos = byte_range_resp_spec.substr(0, p); + string last_byte_pos = byte_range_resp_spec.substr(p + 1); + + if ( DEBUG_http ) + DEBUG_MSG("Parsed Content-Range: %s %s-%s/%s\n", byte_unit.c_str(), + first_byte_pos.c_str(), last_byte_pos.c_str(), + instance_length.c_str()); + + int64_t f, l; + atoi_n(first_byte_pos.size(), first_byte_pos.c_str(), 0, 10, f); + atoi_n(last_byte_pos.size(), last_byte_pos.c_str(), 0, 10, l); + int64_t len = l - f + 1; + + if ( DEBUG_http ) + DEBUG_MSG("Content-Range length = %"PRId64"\n", len); + + if ( len > 0 ) + content_length = len; + else + http_message->Weird("HTTP_non_positive_content_range"); + } + else if ( strcasecmp_n(h->get_name(), "transfer-encoding") == 0 ) { data_chunk_t vt = h->get_value_token(); diff --git a/src/HTTP.h b/src/HTTP.h index 6614886e44..373692c0c3 100644 --- a/src/HTTP.h +++ b/src/HTTP.h @@ -184,6 +184,7 @@ public: http_event || http_stats) && !FLAGS_use_binpac; } int IsConnectionClose() { return connection_close; } + int HTTP_ReplyCode() const { return reply_code; }; protected: void GenStats(); diff --git a/src/MIME.h b/src/MIME.h index c8c70cf65b..52d943fb15 100644 --- a/src/MIME.h +++ b/src/MIME.h @@ -95,6 +95,7 @@ public: virtual void EndOfData(); MIME_Entity* Parent() const { return parent; } + int MIMEContentType() const { return content_type; } StringVal* ContentType() const { return content_type_str; } StringVal* ContentSubType() const { return content_subtype_str; } int ContentTransferEncoding() const { return content_encoding; }