diff options
Diffstat (limited to 'net/http')
-rw-r--r-- | net/http/http_response_headers.cc | 84 | ||||
-rw-r--r-- | net/http/http_response_headers.h | 13 | ||||
-rw-r--r-- | net/http/http_response_headers_unittest.cc | 201 |
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; |