diff options
11 files changed, 121 insertions, 23 deletions
diff --git a/chrome/browser/extensions/api/streams_private/streams_private_api.cc b/chrome/browser/extensions/api/streams_private/streams_private_api.cc index 7909b11..9327399 100644 --- a/chrome/browser/extensions/api/streams_private/streams_private_api.cc +++ b/chrome/browser/extensions/api/streams_private/streams_private_api.cc @@ -19,6 +19,31 @@ #include "extensions/browser/event_router.h" #include "extensions/browser/extension_function_registry.h" #include "extensions/browser/extension_system.h" +#include "net/http/http_response_headers.h" + +namespace { + +void CreateResponseHeadersDictionary(const net::HttpResponseHeaders* headers, + base::DictionaryValue* result) { + if (!headers) + return; + + void* iter = NULL; + std::string header_name; + std::string header_value; + while (headers->EnumerateHeaderLines(&iter, &header_name, &header_value)) { + base::Value* existing_value = NULL; + if (result->Get(header_name, &existing_value)) { + base::StringValue* existing_string_value = + static_cast<base::StringValue*>(existing_value); + existing_string_value->GetString()->append(", ").append(header_value); + } else { + result->SetString(header_name, header_value); + } + } +} + +} // namespace namespace extensions { @@ -55,7 +80,9 @@ void StreamsPrivateAPI::ExecuteMimeTypeHandler( if (expected_content_size <= INT_MAX) size = expected_content_size; info.expected_content_size = size; - info.response_headers = stream->GetResponseHeaders(); + + CreateResponseHeadersDictionary(stream->GetResponseHeaders().get(), + &info.response_headers.additional_properties); scoped_ptr<Event> event( new Event(streams_private::OnExecuteMimeTypeHandler::kEventName, diff --git a/chrome/browser/extensions/api/streams_private/streams_private_apitest.cc b/chrome/browser/extensions/api/streams_private/streams_private_apitest.cc index 378b924..fd418c9 100644 --- a/chrome/browser/extensions/api/streams_private/streams_private_apitest.cc +++ b/chrome/browser/extensions/api/streams_private/streams_private_apitest.cc @@ -61,6 +61,17 @@ scoped_ptr<HttpResponse> HandleRequest(const HttpRequest& request) { return response.PassAs<HttpResponse>(); } + // For relative path "/spreadsheet_path.xls", return success response with + // MIME type "application/xls". + if (request.relative_url == "/spreadsheet_path.xls") { + response->set_code(net::HTTP_OK); + response->set_content_type("application/msexcel"); + // Test that multiple headers with the same name are merged. + response->AddCustomHeader("Test-Header", "part1"); + response->AddCustomHeader("Test-Header", "part2"); + return response.PassAs<HttpResponse>(); + } + // For relative path "/text_path_attch.txt", return success response with // MIME type "text/plain" and content "txt content". Also, set content // disposition to be attachment. @@ -380,4 +391,34 @@ IN_PROC_BROWSER_TEST_F(StreamsPrivateApiTest, DirectDownload) { EXPECT_TRUE(catcher.GetNextResult()); } +// Tests that response headers are correctly passed to the API and that multiple +// repsonse headers with the same name are merged correctly. +IN_PROC_BROWSER_TEST_F(StreamsPrivateApiTest, Headers) { +#if defined(OS_WIN) && defined(USE_ASH) + // Disable this test in Metro+Ash for now (http://crbug.com/262796). + if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests)) + return; +#endif + + ASSERT_TRUE(LoadTestExtension()) << message_; + + ResultCatcher catcher; + + ui_test_utils::NavigateToURL(browser(), + test_server_->GetURL("/spreadsheet_path.xls")); + + // Wait for the response from the test server. + base::MessageLoop::current()->RunUntilIdle(); + + // There should be no downloads started by the navigation. + DownloadManager* download_manager = GetDownloadManager(); + std::vector<DownloadItem*> downloads; + download_manager->GetAllDownloads(&downloads); + ASSERT_EQ(0u, downloads.size()); + + // The test extension should receive onExecuteContentHandler event with MIME + // type 'application/msexcel' (and call chrome.test.notifySuccess). + EXPECT_TRUE(catcher.GetNextResult()); +} + } // namespace diff --git a/chrome/common/extensions/api/streams_private.idl b/chrome/common/extensions/api/streams_private.idl index e566def..2d3bada 100644 --- a/chrome/common/extensions/api/streams_private.idl +++ b/chrome/common/extensions/api/streams_private.idl @@ -22,8 +22,11 @@ namespace streamsPrivate { // information on the size it will be -1. long expectedContentSize; - // The HTTP response headers of the intercepted request. - DOMString responseHeaders; + // The HTTP response headers of the intercepted request stored as a + // dictionary mapping header name to header value. If a header name appears + // multiple times, the header values are merged in the dictionary and + // separated by a ", ". + object responseHeaders; }; interface Events { diff --git a/chrome/test/data/extensions/api_test/streams_private/handle_mime_type/background.js b/chrome/test/data/extensions/api_test/streams_private/handle_mime_type/background.js index bb55f97..d7ccdd8 100644 --- a/chrome/test/data/extensions/api_test/streams_private/handle_mime_type/background.js +++ b/chrome/test/data/extensions/api_test/streams_private/handle_mime_type/background.js @@ -12,8 +12,24 @@ chrome.streamsPrivate.onExecuteMimeTypeHandler.addListener( // the MIME type 'application/msword' means the test has succeeded. if (params.mimeType == 'application/msword') { var headers = params.responseHeaders; - if (headers.indexOf('Content-Type: application/msword') == -1 || - headers.indexOf('HTTP/1.1 200 OK') == -1) { + if (headers['Content-Type'] != 'application/msword') { + chrome.test.notifyFail( + 'HTTP request header did not contain expected attributes.'); + hasFailed = true; + } else { + chrome.test.notifyPass(); + } + return; + } + + // The tests are setup so resources with MIME type 'application/msexcel' are + // meant to be handled by the extension. The extension getting an event with + // the MIME type 'application/msexcel' means the test has succeeded. This also + // tests that repeated headers are correctly merged. + if (params.mimeType == 'application/msexcel') { + var headers = params.responseHeaders; + if (headers['Content-Type'] != 'application/msexcel' || + headers['Test-Header'] != 'part1, part2') { chrome.test.notifyFail( 'HTTP request header did not contain expected attributes.'); hasFailed = true; diff --git a/chrome/test/data/extensions/api_test/streams_private/handle_mime_type/manifest.json b/chrome/test/data/extensions/api_test/streams_private/handle_mime_type/manifest.json index bc7758f..3de039c 100644 --- a/chrome/test/data/extensions/api_test/streams_private/handle_mime_type/manifest.json +++ b/chrome/test/data/extensions/api_test/streams_private/handle_mime_type/manifest.json @@ -8,6 +8,7 @@ }, "mime_types": [ "application/msword", + "application/msexcel", "text/plain" ], "permissions": [ diff --git a/content/browser/loader/resource_dispatcher_host_impl.cc b/content/browser/loader/resource_dispatcher_host_impl.cc index 1199957..9234315 100644 --- a/content/browser/loader/resource_dispatcher_host_impl.cc +++ b/content/browser/loader/resource_dispatcher_host_impl.cc @@ -610,9 +610,6 @@ ResourceDispatcherHostImpl::MaybeInterceptAsStream(net::URLRequest* request, ResourceResponse* response) { ResourceRequestInfoImpl* info = ResourceRequestInfoImpl::ForRequest(request); const std::string& mime_type = response->head.mime_type; - std::string response_headers; - if (response->head.headers) - response->head.headers->GetNormalizedHeaders(&response_headers); GURL origin; std::string target_id; @@ -639,8 +636,10 @@ ResourceDispatcherHostImpl::MaybeInterceptAsStream(net::URLRequest* request, info->GetChildID(), info->GetRouteID(), target_id, - handler->stream()->CreateHandle(request->url(), mime_type, - response_headers), + handler->stream()->CreateHandle( + request->url(), + mime_type, + response->head.headers), request->GetExpectedContentSize()); return handler.PassAs<ResourceHandler>(); } diff --git a/content/browser/streams/stream.cc b/content/browser/streams/stream.cc index ca0cf1b..d10770c 100644 --- a/content/browser/streams/stream.cc +++ b/content/browser/streams/stream.cc @@ -7,11 +7,13 @@ #include "base/bind.h" #include "base/location.h" #include "base/message_loop/message_loop_proxy.h" +#include "base/values.h" #include "content/browser/streams/stream_handle_impl.h" #include "content/browser/streams/stream_read_observer.h" #include "content/browser/streams/stream_registry.h" #include "content/browser/streams/stream_write_observer.h" #include "net/base/io_buffer.h" +#include "net/http/http_response_headers.h" namespace { // Start throttling the connection at about 1MB. @@ -161,7 +163,7 @@ Stream::StreamState Stream::ReadRawData(net::IOBuffer* buf, scoped_ptr<StreamHandle> Stream::CreateHandle( const GURL& original_url, const std::string& mime_type, - const std::string& response_headers) { + scoped_refptr<net::HttpResponseHeaders> response_headers) { CHECK(!stream_handle_); stream_handle_ = new StreamHandleImpl(weak_ptr_factory_.GetWeakPtr(), original_url, diff --git a/content/browser/streams/stream.h b/content/browser/streams/stream.h index e439b72..e7e9586 100644 --- a/content/browser/streams/stream.h +++ b/content/browser/streams/stream.h @@ -13,6 +13,7 @@ #include "url/gurl.h" namespace net { +class HttpResponseHeaders; class IOBuffer; } @@ -77,9 +78,10 @@ class CONTENT_EXPORT Stream : public base::RefCountedThreadSafe<Stream> { // and STREAM_COMPLETE if the stream is finalized and all data has been read. StreamState ReadRawData(net::IOBuffer* buf, int buf_size, int* bytes_read); - scoped_ptr<StreamHandle> CreateHandle(const GURL& original_url, - const std::string& mime_type, - const std::string& response_headers); + scoped_ptr<StreamHandle> CreateHandle( + const GURL& original_url, + const std::string& mime_type, + scoped_refptr<net::HttpResponseHeaders> response_headers); void CloseHandle(); // Indicates whether there is space in the buffer to add more data. diff --git a/content/browser/streams/stream_handle_impl.cc b/content/browser/streams/stream_handle_impl.cc index cdba12b..d13bdc6 100644 --- a/content/browser/streams/stream_handle_impl.cc +++ b/content/browser/streams/stream_handle_impl.cc @@ -8,13 +8,15 @@ #include "base/location.h" #include "base/message_loop/message_loop_proxy.h" #include "content/browser/streams/stream.h" +#include "net/http/http_response_headers.h" namespace content { -StreamHandleImpl::StreamHandleImpl(const base::WeakPtr<Stream>& stream, - const GURL& original_url, - const std::string& mime_type, - const std::string& response_headers) +StreamHandleImpl::StreamHandleImpl( + const base::WeakPtr<Stream>& stream, + const GURL& original_url, + const std::string& mime_type, + scoped_refptr<net::HttpResponseHeaders> response_headers) : stream_(stream), url_(stream->url()), original_url_(original_url), @@ -39,7 +41,7 @@ const std::string& StreamHandleImpl::GetMimeType() { return mime_type_; } -const std::string& StreamHandleImpl::GetResponseHeaders() { +scoped_refptr<net::HttpResponseHeaders> StreamHandleImpl::GetResponseHeaders() { return response_headers_; } diff --git a/content/browser/streams/stream_handle_impl.h b/content/browser/streams/stream_handle_impl.h index deb094f..fc8f5355 100644 --- a/content/browser/streams/stream_handle_impl.h +++ b/content/browser/streams/stream_handle_impl.h @@ -22,7 +22,7 @@ class StreamHandleImpl : public StreamHandle { StreamHandleImpl(const base::WeakPtr<Stream>& stream, const GURL& original_url, const std::string& mime_type, - const std::string& response_headers); + scoped_refptr<net::HttpResponseHeaders> response_headers); virtual ~StreamHandleImpl(); private: @@ -30,13 +30,13 @@ class StreamHandleImpl : public StreamHandle { virtual const GURL& GetURL() OVERRIDE; virtual const GURL& GetOriginalURL() OVERRIDE; virtual const std::string& GetMimeType() OVERRIDE; - virtual const std::string& GetResponseHeaders() OVERRIDE; + virtual scoped_refptr<net::HttpResponseHeaders> GetResponseHeaders() OVERRIDE; base::WeakPtr<Stream> stream_; GURL url_; GURL original_url_; std::string mime_type_; - std::string response_headers_; + scoped_refptr<net::HttpResponseHeaders> response_headers_; base::MessageLoopProxy* stream_message_loop_; }; diff --git a/content/public/browser/stream_handle.h b/content/public/browser/stream_handle.h index 877c51d..b87402e 100644 --- a/content/public/browser/stream_handle.h +++ b/content/public/browser/stream_handle.h @@ -6,9 +6,14 @@ #define CONTENT_PUBLIC_BROWSER_STREAM_HANDLE_H_ #include "base/callback.h" +#include "base/memory/ref_counted.h" #include "content/common/content_export.h" #include "url/gurl.h" +namespace net { +class HttpResponseHeaders; +} + namespace content { class CONTENT_EXPORT StreamHandle { @@ -25,7 +30,7 @@ class CONTENT_EXPORT StreamHandle { virtual const std::string& GetMimeType() = 0; // Get the HTTP response headers associated with this Stream. - virtual const std::string& GetResponseHeaders() = 0; + virtual scoped_refptr<net::HttpResponseHeaders> GetResponseHeaders() = 0; }; } // namespace content |