[go: nahoru, domu]

Http cache: Return valid Content-Range headers for a byte range request.

BUG=12258
TEST=unittests

Review URL: http://codereview.chromium.org/140015

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@18961 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/net/http/partial_data.cc b/net/http/partial_data.cc
index 44ba086..13cb377ec 100644
--- a/net/http/partial_data.cc
+++ b/net/http/partial_data.cc
@@ -8,8 +8,17 @@
 #include "base/string_util.h"
 #include "net/base/net_errors.h"
 #include "net/disk_cache/disk_cache.h"
+#include "net/http/http_response_headers.h"
 #include "net/http/http_util.h"
 
+namespace {
+
+// The headers that we have to process.
+const char kLengthHeader[] = "Content-Length";
+const char kRangeHeader[] = "Content-Range";
+
+}
+
 namespace net {
 
 bool PartialData::Init(const std::string& headers,
@@ -24,6 +33,7 @@
     return false;
 
   extra_headers_ = new_headers;
+  resource_size_ = 0;
 
   // TODO(rvargas): Handle requests without explicit start or end.
   DCHECK(byte_range_.HasFirstBytePosition());
@@ -92,6 +102,71 @@
   return final_range_;
 }
 
+void PartialData::UpdateFromStoredHeaders(const HttpResponseHeaders* headers) {
+  std::string length_value;
+  if (!headers->GetNormalizedHeader(kLengthHeader, &length_value)) {
+    // We must have stored the resource length.
+    NOTREACHED();
+    resource_size_ = 0;
+    return;
+  }
+  if (!StringToInt64(length_value, &resource_size_)) {
+    NOTREACHED();
+    resource_size_ = 0;
+  }
+}
+
+bool PartialData::ResponseHeadersOK(const HttpResponseHeaders* headers) {
+  int64 start, end, total_length;
+  if (!headers->GetContentRange(&start, &end, &total_length))
+    return false;
+  if (total_length <= 0)
+    return false;
+
+  if (!resource_size_) {
+    // First response. Update our values with the ones provided by the server.
+    resource_size_ = total_length;
+    if (!byte_range_.HasFirstBytePosition())
+      byte_range_.set_first_byte_position(start);
+    if (!byte_range_.HasLastBytePosition())
+      byte_range_.set_last_byte_position(end);
+  } else if (resource_size_ != total_length) {
+    return false;
+  }
+
+  if (start != current_range_start_)
+    return false;
+
+  if (end > byte_range_.last_byte_position())
+    return false;
+
+  return true;
+}
+
+// We are making multiple requests to complete the range requested by the user.
+// Just assume that everything is fine and say that we are returning what was
+// requested.
+void PartialData::FixResponseHeaders(HttpResponseHeaders* headers) {
+  headers->RemoveHeader(kLengthHeader);
+  headers->RemoveHeader(kRangeHeader);
+
+  DCHECK(byte_range_.HasFirstBytePosition());
+  DCHECK(byte_range_.HasLastBytePosition());
+  headers->AddHeader(StringPrintf("%s: bytes %lld-%lld/%lld", kRangeHeader,
+                                  byte_range_.first_byte_position(),
+                                  byte_range_.last_byte_position(),
+                                  resource_size_));
+
+  int64 range_len = byte_range_.last_byte_position() -
+                    byte_range_.first_byte_position() + 1;
+  headers->AddHeader(StringPrintf("%s: %lld", kLengthHeader, range_len));
+}
+
+void PartialData::FixContentLength(HttpResponseHeaders* headers) {
+  headers->RemoveHeader(kLengthHeader);
+  headers->AddHeader(StringPrintf("%s: %lld", kLengthHeader, resource_size_));
+}
+
 int PartialData::CacheRead(disk_cache::Entry* entry, IOBuffer* data,
                            int data_len, CompletionCallback* callback) {
   int read_len = std::min(data_len, cached_min_len_);