diff --git a/src/HTTP.cc b/src/HTTP.cc index e94665bb2a..71fa1a3dd0 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,67 @@ 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"); + return; + } + + size_t p = byte_range.find("/"); + if ( p == string::npos ) + { + http_message->Weird("HTTP_content_range_cannot_parse"); + return; + } + + string byte_range_resp_spec = byte_range.substr(0, p); + string instance_length = byte_range.substr(p + 1); + + p = byte_range_resp_spec.find("-"); + if ( p == string::npos ) + { + http_message->Weird("HTTP_content_range_cannot_parse"); + return; + } + + 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"); + return; + } + } + 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..13b87d219f 100644 --- a/src/HTTP.h +++ b/src/HTTP.h @@ -163,6 +163,9 @@ public: void SkipEntityData(int is_orig); + int IsConnectionClose() { return connection_close; } + int HTTP_ReplyCode() const { return reply_code; }; + // Overriden from Analyzer. virtual void Done(); virtual void DeliverStream(int len, const u_char* data, bool orig); @@ -183,8 +186,6 @@ public: http_content_type || http_entity_data || http_message_done || http_event || http_stats) && !FLAGS_use_binpac; } - int IsConnectionClose() { return connection_close; } - 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; }