summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/http/http_response_headers.cc84
-rw-r--r--net/http/http_response_headers.h13
-rw-r--r--net/http/http_response_headers_unittest.cc201
3 files changed, 295 insertions, 3 deletions
diff --git a/net/http/http_response_headers.cc b/net/http/http_response_headers.cc
index bc7ac62..59bd854 100644
--- a/net/http/http_response_headers.cc
+++ b/net/http/http_response_headers.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -969,4 +969,86 @@ int64 HttpResponseHeaders::GetContentLength() const {
return result;
}
+// From RFC 2616 14.16:
+// content-range-spec =
+// bytes-unit SP byte-range-resp-spec "/" ( instance-length | "*" )
+// byte-range-resp-spec = (first-byte-pos "-" last-byte-pos) | "*"
+// instance-length = 1*DIGIT
+// bytes-unit = "bytes"
+bool HttpResponseHeaders::GetContentRange(int64* first_byte_position,
+ int64* last_byte_position,
+ int64* instance_length) const {
+ void* iter = NULL;
+ std::string content_range_val;
+ if (!EnumerateHeader(&iter, "content-range", &content_range_val))
+ return false;
+
+ if (content_range_val.empty())
+ return false;
+
+ size_t space_position = content_range_val.find(' ');
+ if (space_position == std::string::npos)
+ return false;
+
+ if (!LowerCaseEqualsASCII(content_range_val.begin(),
+ content_range_val.begin() + space_position,
+ "bytes")) {
+ return false;
+ }
+
+ size_t slash_position = content_range_val.find('/', space_position + 1);
+ if (slash_position == std::string::npos)
+ return false;
+
+ // Parse the byte-range-resp-spec part.
+ std::string byte_range_resp_spec(
+ content_range_val.begin() + space_position + 1,
+ content_range_val.begin() + slash_position);
+ // If byte-range-resp-spec == "*".
+ if (LowerCaseEqualsASCII(byte_range_resp_spec, "*")) {
+ *first_byte_position = -1;
+ *last_byte_position = -1;
+ } else {
+ size_t minus_position = byte_range_resp_spec.find('-');
+ if (minus_position != std::string::npos) {
+ // Obtain first-byte-pos.
+ bool ok = StringToInt64(
+ std::string(byte_range_resp_spec.begin(),
+ byte_range_resp_spec.begin() + minus_position),
+ first_byte_position);
+ // Obtain last-byte-pos.
+ ok &= StringToInt64(
+ std::string(byte_range_resp_spec.begin() + minus_position + 1,
+ byte_range_resp_spec.end()),
+ last_byte_position);
+ if (!ok ||
+ *first_byte_position < 0 ||
+ *last_byte_position < 0 ||
+ *first_byte_position > *last_byte_position)
+ return false;
+ } else {
+ return false;
+ }
+ }
+
+ // Parse the instance-length part.
+ // If instance-length == "*".
+ if (LowerCaseEqualsASCII(content_range_val.begin() + slash_position + 1,
+ content_range_val.end(),
+ "*")) {
+ *instance_length = -1;
+ } else if (!StringToInt64(
+ std::string(content_range_val.begin() + slash_position + 1,
+ content_range_val.end()),
+ instance_length)) {
+ return false;
+ } else if (*instance_length < 0 ||
+ *instance_length <
+ *last_byte_position - *first_byte_position + 1) {
+ return false;
+ }
+
+ return true;
+}
+
} // namespace net
diff --git a/net/http/http_response_headers.h b/net/http/http_response_headers.h
index e9b2c4b..830c09c 100644
--- a/net/http/http_response_headers.h
+++ b/net/http/http_response_headers.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -196,6 +196,17 @@ class HttpResponseHeaders :
// no such header in the response.
int64 GetContentLength() const;
+ // Extracts the values in Content-Range header, if the header exists and is
+ // well formatted returns true, else returns false.
+ // The following values will be outputted:
+ // |*first_byte_position| = inclusive position of the first byte of the range
+ // |*last_byte_position| = inclusive position of the last byte of the range
+ // |*instance_length| = size in bytes of the object requested
+ // If any of the above values is unknown, its value will be -1.
+ bool GetContentRange(int64* first_byte_position,
+ int64* last_byte_position,
+ int64* instance_length) const;
+
// Returns the HTTP response code. This is 0 if the response code text seems
// to exist but could not be parsed. Otherwise, it defaults to 200 if the
// response code is not found in the raw headers.
diff --git a/net/http/http_response_headers_unittest.cc b/net/http/http_response_headers_unittest.cc
index ef7d8dc..c6382aa7 100644
--- a/net/http/http_response_headers_unittest.cc
+++ b/net/http/http_response_headers_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -1039,6 +1039,205 @@ TEST(HttpResponseHeadersTest, GetContentLength) {
}
}
+TEST(HttpResponseHeaders, GetContentRange) {
+ const struct {
+ const char* headers;
+ bool expected_return_value;
+ int64 expected_first_byte_position;
+ int64 expected_last_byte_position;
+ int64 expected_instance_size;
+ } tests[] = {
+ { "HTTP/1.1 206 Partial Content",
+ false,
+ -1,
+ -1,
+ -1
+ },
+ { "HTTP/1.1 206 Partial Content\n"
+ "Content-Range:",
+ false,
+ -1,
+ -1,
+ -1
+ },
+ { "HTTP/1.1 206 Partial Content\n"
+ "Content-Range: megabytes 0-10/50",
+ false,
+ -1,
+ -1,
+ -1
+ },
+ { "HTTP/1.1 206 Partial Content\n"
+ "Content-Range: 0-10/50",
+ false,
+ -1,
+ -1,
+ -1
+ },
+ { "HTTP/1.1 206 Partial Content\n"
+ "Content-Range: Bytes 0-50/51",
+ true,
+ 0,
+ 50,
+ 51
+ },
+ { "HTTP/1.1 206 Partial Content\n"
+ "Content-Range: bytes 0-50/51",
+ true,
+ 0,
+ 50,
+ 51
+ },
+ { "HTTP/1.1 206 Partial Content\n"
+ "Content-Range: bytes 0-50/51",
+ true,
+ 0,
+ 50,
+ 51
+ },
+ { "HTTP/1.1 206 Partial Content\n"
+ "Content-Range: bytes 0 - 50 / 51",
+ false,
+ -1,
+ -1,
+ -1
+ },
+ { "HTTP/1.1 206 Partial Content\n"
+ "Content-Range: bytes 50-0/51",
+ false,
+ -1,
+ -1,
+ -1
+ },
+ { "HTTP/1.1 416 Requested range not satisfiable\n"
+ "Content-Range: bytes */*",
+ true,
+ -1,
+ -1,
+ -1
+ },
+ { "HTTP/1.1 206 Partial Content\n"
+ "Content-Range: bytes 0-50/*",
+ true,
+ 0,
+ 50,
+ -1
+ },
+ { "HTTP/1.1 206 Partial Content\n"
+ "Content-Range: bytes 0-10000000000/10000000001",
+ true,
+ 0,
+ 10000000000ll,
+ 10000000001ll
+ },
+ { "HTTP/1.1 206 Partial Content\n"
+ "Content-Range: bytes 0-10000000000/10000000000",
+ false,
+ -1,
+ -1,
+ -1
+ },
+ // The following header is invalid for response code of 206, this should be
+ // verified by the user.
+ { "HTTP/1.1 206 Partial Content\n"
+ "Content-Range: bytes */50",
+ true,
+ -1,
+ -1,
+ 50
+ },
+ { "HTTP/1.1 206 Partial Content\n"
+ "Content-Range: bytes 0-50/10",
+ false,
+ -1,
+ -1,
+ -1
+ },
+ { "HTTP/1.1 206 Partial Content\n"
+ "Content-Range: bytes 0-50/-10",
+ false,
+ -1,
+ -1,
+ -1
+ },
+ { "HTTP/1.1 206 Partial Content\n"
+ "Content-Range: bytes 0-0/1",
+ true,
+ 0,
+ 0,
+ 1
+ },
+ { "HTTP/1.1 206 Partial Content\n"
+ "Content-Range: bytes 0-40000000000000000000/40000000000000000001",
+ false,
+ -1,
+ -1,
+ -1
+ },
+ { "HTTP/1.1 206 Partial Content\n"
+ "Content-Range: bytes 1-/100",
+ false,
+ -1,
+ -1,
+ -1
+ },
+ { "HTTP/1.1 206 Partial Content\n"
+ "Content-Range: bytes -/100",
+ false,
+ -1,
+ -1,
+ -1
+ },
+ { "HTTP/1.1 206 Partial Content\n"
+ "Content-Range: bytes -1/100",
+ false,
+ -1,
+ -1,
+ -1
+ },
+ { "HTTP/1.1 206 Partial Content\n"
+ "Content-Range: bytes 0-40000000000000000000/40000000000000000001",
+ false,
+ -1,
+ -1,
+ -1
+ },
+ { "HTTP/1.1 206 Partial Content\n"
+ "Content-Range: bytes 0-1233/*",
+ true,
+ 0,
+ 1233,
+ -1
+ },
+ { "HTTP/1.1 206 Partial Content\n"
+ "Content-Range: bytes -123 - -1/100",
+ false,
+ -1,
+ -1,
+ -1
+ },
+ };
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
+ string headers(tests[i].headers);
+ HeadersToRaw(&headers);
+ scoped_refptr<HttpResponseHeaders> parsed =
+ new HttpResponseHeaders(headers);
+
+ int64 first_byte_position;
+ int64 last_byte_position;
+ int64 instance_size;
+ bool return_value = parsed->GetContentRange(&first_byte_position,
+ &last_byte_position,
+ &instance_size);
+ EXPECT_EQ(tests[i].expected_return_value, return_value);
+ if (return_value) {
+ EXPECT_EQ(tests[i].expected_first_byte_position, first_byte_position);
+ EXPECT_EQ(tests[i].expected_last_byte_position, last_byte_position);
+ EXPECT_EQ(tests[i].expected_instance_size, instance_size);
+ }
+ }
+}
+
TEST(HttpResponseHeadersTest, IsKeepAlive) {
const struct {
const char* headers;