Merge remote-tracking branch 'origin/topic/jsiwek/http-multipart-byteranges'

* origin/topic/jsiwek/http-multipart-byteranges:
  Teach HTTP parser to derive content length of multipart/byteranges bodies.

Closes #448.
This commit is contained in:
Robin Sommer 2011-09-28 17:40:36 -07:00
commit 5f7aed6687
3 changed files with 67 additions and 2 deletions

View file

@ -5,6 +5,8 @@
#include <ctype.h>
#include <math.h>
#include <stdlib.h>
#include <string>
#include <algorithm>
#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();

View file

@ -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();

View file

@ -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; }