diff options
-rw-r--r-- | mojo/examples/html_viewer/html_document_view.cc | 4 | ||||
-rw-r--r-- | mojo/examples/html_viewer/html_document_view.h | 3 | ||||
-rw-r--r-- | mojo/examples/html_viewer/html_viewer.cc | 10 | ||||
-rw-r--r-- | mojo/examples/html_viewer/weburlloader_impl.cc | 73 | ||||
-rw-r--r-- | mojo/examples/html_viewer/weburlloader_impl.h | 16 | ||||
-rw-r--r-- | mojo/examples/png_viewer/png_viewer.cc | 4 | ||||
-rw-r--r-- | mojo/examples/wget/wget.cc | 110 | ||||
-rw-r--r-- | mojo/services/launcher/launcher.cc | 54 | ||||
-rw-r--r-- | mojo/services/network/url_loader_impl.cc | 106 | ||||
-rw-r--r-- | mojo/services/network/url_loader_impl.h | 14 | ||||
-rw-r--r-- | mojo/services/public/interfaces/navigation/navigation.mojom | 7 | ||||
-rw-r--r-- | mojo/services/public/interfaces/network/url_loader.mojom | 82 | ||||
-rw-r--r-- | mojo/shell/dynamic_service_loader.cc | 42 | ||||
-rw-r--r-- | mojo/shell/in_process_dynamic_service_runner.cc | 3 |
14 files changed, 287 insertions, 241 deletions
diff --git a/mojo/examples/html_viewer/html_document_view.cc b/mojo/examples/html_viewer/html_document_view.cc index cdc80cf..654161a 100644 --- a/mojo/examples/html_viewer/html_document_view.cc +++ b/mojo/examples/html_viewer/html_document_view.cc @@ -104,15 +104,13 @@ void HTMLDocumentView::AttachToNode(view_manager::Node* node) { web_view_->resize(gfx::Size(node->bounds().size())); } -void HTMLDocumentView::Load(URLResponsePtr response, - ScopedDataPipeConsumerHandle response_body_stream) { +void HTMLDocumentView::Load(URLResponsePtr response) { DCHECK(web_view_); GURL url(response->url); WebURLRequestExtraData* extra_data = new WebURLRequestExtraData; extra_data->synthetic_response = response.Pass(); - extra_data->synthetic_response_body_stream = response_body_stream.Pass(); blink::WebURLRequest web_request; web_request.initialize(); diff --git a/mojo/examples/html_viewer/html_document_view.h b/mojo/examples/html_viewer/html_document_view.h index 2f9f8e9..8c324a5 100644 --- a/mojo/examples/html_viewer/html_document_view.h +++ b/mojo/examples/html_viewer/html_document_view.h @@ -36,8 +36,7 @@ class HTMLDocumentView : public blink::WebViewClient, void AttachToNode(view_manager::Node* node); - void Load(URLResponsePtr response, - ScopedDataPipeConsumerHandle response_body_stream); + void Load(URLResponsePtr response); private: // WebViewClient methods: diff --git a/mojo/examples/html_viewer/html_viewer.cc b/mojo/examples/html_viewer/html_viewer.cc index 235d4ab..9a947f4 100644 --- a/mojo/examples/html_viewer/html_viewer.cc +++ b/mojo/examples/html_viewer/html_viewer.cc @@ -47,11 +47,9 @@ class HTMLViewer : public ApplicationDelegate, blink::shutdown(); } - void Load(URLResponsePtr response, - ScopedDataPipeConsumerHandle response_body_stream) { + void Load(URLResponsePtr response) { // Need to wait for OnRootAdded. response_ = response.Pass(); - response_body_stream_ = response_body_stream.Pass(); MaybeLoad(); } @@ -82,7 +80,7 @@ class HTMLViewer : public ApplicationDelegate, void MaybeLoad() { if (document_view_ && response_.get()) - document_view_->Load(response_.Pass(), response_body_stream_.Pass()); + document_view_->Load(response_.Pass()); } scoped_ptr<BlinkPlatformImpl> blink_platform_impl_; @@ -91,7 +89,6 @@ class HTMLViewer : public ApplicationDelegate, // TODO(darin): Figure out proper ownership of this instance. HTMLDocumentView* document_view_; URLResponsePtr response_; - ScopedDataPipeConsumerHandle response_body_stream_; DISALLOW_COPY_AND_ASSIGN(HTMLViewer); }; @@ -102,8 +99,7 @@ void NavigatorImpl::Navigate( navigation::ResponseDetailsPtr response_details) { printf("In HTMLViewer, rendering url: %s\n", response_details->response->url.data()); - viewer_->Load(response_details->response.Pass(), - response_details->response_body_stream.Pass()); + viewer_->Load(response_details->response.Pass()); } } diff --git a/mojo/examples/html_viewer/weburlloader_impl.cc b/mojo/examples/html_viewer/weburlloader_impl.cc index d2d4e36..ae0651d 100644 --- a/mojo/examples/html_viewer/weburlloader_impl.cc +++ b/mojo/examples/html_viewer/weburlloader_impl.cc @@ -47,7 +47,6 @@ WebURLLoaderImpl::WebURLLoaderImpl(NetworkService* network_service) : client_(NULL), weak_factory_(this) { network_service->CreateURLLoader(Get(&url_loader_)); - url_loader_.set_client(this); } WebURLLoaderImpl::~WebURLLoaderImpl() { @@ -64,25 +63,25 @@ void WebURLLoaderImpl::loadSynchronously( void WebURLLoaderImpl::loadAsynchronously(const blink::WebURLRequest& request, blink::WebURLLoaderClient* client) { client_ = client; + url_ = request.url(); URLRequestPtr url_request(URLRequest::New()); - url_request->url = request.url().spec(); + url_request->url = url_.spec(); url_request->auto_follow_redirects = false; // TODO(darin): Copy other fields. if (request.extraData()) { WebURLRequestExtraData* extra_data = static_cast<WebURLRequestExtraData*>(request.extraData()); - response_body_stream_ = extra_data->synthetic_response_body_stream.Pass(); base::ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE, base::Bind(&WebURLLoaderImpl::OnReceivedResponse, weak_factory_.GetWeakPtr(), base::Passed(&extra_data->synthetic_response))); } else { - DataPipe pipe; - url_loader_->Start(url_request.Pass(), pipe.producer_handle.Pass()); - response_body_stream_ = pipe.consumer_handle.Pass(); + url_loader_->Start(url_request.Pass(), + base::Bind(&WebURLLoaderImpl::OnReceivedResponse, + weak_factory_.GetWeakPtr())); } } @@ -90,53 +89,63 @@ void WebURLLoaderImpl::cancel() { url_loader_.reset(); response_body_stream_.reset(); - NetworkErrorPtr network_error(NetworkError::New()); - network_error->code = net::ERR_ABORTED; + URLResponsePtr failed_response(URLResponse::New()); + failed_response->url = url_.spec(); + failed_response->error = NetworkError::New(); + failed_response->error->code = net::ERR_ABORTED; base::ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE, - base::Bind(&WebURLLoaderImpl::OnReceivedError, + base::Bind(&WebURLLoaderImpl::OnReceivedResponse, weak_factory_.GetWeakPtr(), - base::Passed(&network_error))); + base::Passed(&failed_response))); } void WebURLLoaderImpl::setDefersLoading(bool defers_loading) { NOTIMPLEMENTED(); } -void WebURLLoaderImpl::OnReceivedRedirect(URLResponsePtr url_response, - const String& new_url, - const String& new_method) { - blink::WebURLRequest new_request; - new_request.initialize(); - new_request.setURL(GURL(new_url)); - - client_->willSendRequest(this, new_request, ToWebURLResponse(url_response)); - // TODO(darin): Check if new_request was rejected. - - url_loader_->FollowRedirect(); -} - void WebURLLoaderImpl::OnReceivedResponse(URLResponsePtr url_response) { - client_->didReceiveResponse(this, ToWebURLResponse(url_response)); + url_ = GURL(url_response->url); - // Start streaming data - ReadMore(); + if (url_response->error) { + OnReceivedError(url_response.Pass()); + } else if (url_response->redirect_url) { + OnReceivedRedirect(url_response.Pass()); + } else { + client_->didReceiveResponse(this, ToWebURLResponse(url_response)); + + // Start streaming data + response_body_stream_ = url_response->body.Pass(); + ReadMore(); + } } -void WebURLLoaderImpl::OnReceivedError(NetworkErrorPtr error) { +void WebURLLoaderImpl::OnReceivedError(URLResponsePtr url_response) { blink::WebURLError web_error; web_error.domain = blink::WebString::fromUTF8(net::kErrorDomain); - web_error.reason = error->code; - web_error.unreachableURL = GURL(); // TODO(darin): Record this. + web_error.reason = url_response->error->code; + web_error.unreachableURL = GURL(url_response->url); web_error.staleCopyInCache = false; - web_error.isCancellation = error->code == net::ERR_ABORTED ? true : false; + web_error.isCancellation = + url_response->error->code == net::ERR_ABORTED ? true : false; client_->didFail(this, web_error); } -void WebURLLoaderImpl::OnReceivedEndOfResponseBody() { - // This is the signal that the response body was not truncated. +void WebURLLoaderImpl::OnReceivedRedirect(URLResponsePtr url_response) { + blink::WebURLRequest new_request; + new_request.initialize(); + new_request.setURL(GURL(url_response->redirect_url)); + new_request.setHTTPMethod( + blink::WebString::fromUTF8(url_response->redirect_method)); + + client_->willSendRequest(this, new_request, ToWebURLResponse(url_response)); + // TODO(darin): Check if new_request was rejected. + + url_loader_->FollowRedirect( + base::Bind(&WebURLLoaderImpl::OnReceivedResponse, + weak_factory_.GetWeakPtr())); } void WebURLLoaderImpl::ReadMore() { diff --git a/mojo/examples/html_viewer/weburlloader_impl.h b/mojo/examples/html_viewer/weburlloader_impl.h index da30238..87d97e4 100644 --- a/mojo/examples/html_viewer/weburlloader_impl.h +++ b/mojo/examples/html_viewer/weburlloader_impl.h @@ -23,11 +23,9 @@ class WebURLRequestExtraData : public blink::WebURLRequest::ExtraData { virtual ~WebURLRequestExtraData(); URLResponsePtr synthetic_response; - ScopedDataPipeConsumerHandle synthetic_response_body_stream; }; -class WebURLLoaderImpl : public blink::WebURLLoader, - public URLLoaderClient { +class WebURLLoaderImpl : public blink::WebURLLoader { public: explicit WebURLLoaderImpl(NetworkService* network_service); @@ -43,19 +41,15 @@ class WebURLLoaderImpl : public blink::WebURLLoader, virtual void cancel() OVERRIDE; virtual void setDefersLoading(bool defers_loading) OVERRIDE; - // URLLoaderClient methods: - virtual void OnReceivedRedirect(URLResponsePtr response, - const String& new_url, - const String& new_method) OVERRIDE; - virtual void OnReceivedResponse(URLResponsePtr response) OVERRIDE; - virtual void OnReceivedError(NetworkErrorPtr error) OVERRIDE; - virtual void OnReceivedEndOfResponseBody() OVERRIDE; - + void OnReceivedResponse(URLResponsePtr response); + void OnReceivedError(URLResponsePtr response); + void OnReceivedRedirect(URLResponsePtr response); void ReadMore(); void WaitToReadMore(); void OnResponseBodyStreamReady(MojoResult result); blink::WebURLLoaderClient* client_; + GURL url_; URLLoaderPtr url_loader_; ScopedDataPipeConsumerHandle response_body_stream_; common::HandleWatcher handle_watcher_; diff --git a/mojo/examples/png_viewer/png_viewer.cc b/mojo/examples/png_viewer/png_viewer.cc index 62dcd2b..cc2cd5d 100644 --- a/mojo/examples/png_viewer/png_viewer.cc +++ b/mojo/examples/png_viewer/png_viewer.cc @@ -63,12 +63,12 @@ class NavigatorImpl : public InterfaceImpl<navigation::Navigator> { uint32_t num_bytes = bytes_remaining; while (bytes_remaining > 0) { MojoResult result = ReadDataRaw( - response_details->response_body_stream.get(), + response_details->response->body.get(), buf, &num_bytes, MOJO_READ_DATA_FLAG_NONE); if (result == MOJO_RESULT_SHOULD_WAIT) { - Wait(response_details->response_body_stream.get(), + Wait(response_details->response->body.get(), MOJO_HANDLE_SIGNAL_READABLE, MOJO_DEADLINE_INDEFINITE); } else if (result == MOJO_RESULT_OK) { diff --git a/mojo/examples/wget/wget.cc b/mojo/examples/wget/wget.cc index 9ec7e5c..55a8cb8 100644 --- a/mojo/examples/wget/wget.cc +++ b/mojo/examples/wget/wget.cc @@ -6,68 +6,29 @@ #include "mojo/public/cpp/application/application_delegate.h" #include "mojo/public/cpp/application/application_impl.h" +#include "mojo/public/cpp/utility/run_loop.h" #include "mojo/services/public/interfaces/network/network_service.mojom.h" #include "mojo/services/public/interfaces/network/url_loader.mojom.h" namespace mojo { namespace examples { +namespace { -class WGetApp : public ApplicationDelegate, public URLLoaderClient { +class ResponsePrinter { public: - virtual void Initialize(ApplicationImpl* app) MOJO_OVERRIDE { - app->ConnectToService("mojo:mojo_network_service", &network_service_); - Start(); - } - - private: - virtual void OnReceivedRedirect(URLResponsePtr response, - const String& new_url, - const String& new_method) MOJO_OVERRIDE { - PrintResponse(response); - } - - virtual void OnReceivedResponse(URLResponsePtr response) MOJO_OVERRIDE { - PrintResponse(response); - PrintResponseBody(); - Start(); - } - - virtual void OnReceivedError(NetworkErrorPtr error) MOJO_OVERRIDE { - printf("Got error: %d (%s)\n", - error->code, error->description.get().c_str()); - } - - virtual void OnReceivedEndOfResponseBody() MOJO_OVERRIDE { - // Ignored. - } - - void Start() { - std::string url = PromptForURL(); - printf("Loading: %s\n", url.c_str()); - - network_service_->CreateURLLoader(Get(&url_loader_)); - url_loader_.set_client(this); - - URLRequestPtr request(URLRequest::New()); - request->url = url; - request->method = "GET"; - request->auto_follow_redirects = true; - - DataPipe data_pipe; - response_body_stream_ = data_pipe.consumer_handle.Pass(); + void Run(URLResponsePtr response) const { + if (response->error) { + printf("Got error: %d (%s)\n", + response->error->code, response->error->description.get().c_str()); + } else { + PrintResponse(response); + PrintResponseBody(response->body.Pass()); + } - url_loader_->Start(request.Pass(), data_pipe.producer_handle.Pass()); + RunLoop::current()->Quit(); // All done! } - std::string PromptForURL() { - printf("Enter URL> "); - char buf[1024]; - if (scanf("%1023s", buf) != 1) - buf[0] = '\0'; - return buf; - } - - void PrintResponse(const URLResponsePtr& response) { + void PrintResponse(const URLResponsePtr& response) const { printf(">>> Headers <<< \n"); printf(" %s\n", response->status_line.get().c_str()); if (response->headers) { @@ -76,20 +37,17 @@ class WGetApp : public ApplicationDelegate, public URLLoaderClient { } } - void PrintResponseBody() { + void PrintResponseBody(ScopedDataPipeConsumerHandle body) const { // Read response body in blocking fashion. printf(">>> Body <<<\n"); for (;;) { char buf[512]; uint32_t num_bytes = sizeof(buf); - MojoResult result = ReadDataRaw( - response_body_stream_.get(), - buf, - &num_bytes, - MOJO_READ_DATA_FLAG_NONE); + MojoResult result = ReadDataRaw(body.get(), buf, &num_bytes, + MOJO_READ_DATA_FLAG_NONE); if (result == MOJO_RESULT_SHOULD_WAIT) { - Wait(response_body_stream_.get(), + Wait(body.get(), MOJO_HANDLE_SIGNAL_READABLE, MOJO_DEADLINE_INDEFINITE); } else if (result == MOJO_RESULT_OK) { @@ -104,10 +62,42 @@ class WGetApp : public ApplicationDelegate, public URLLoaderClient { printf("\n>>> EOF <<<\n"); } +}; + +} // namespace + +class WGetApp : public ApplicationDelegate { + public: + virtual void Initialize(ApplicationImpl* app) MOJO_OVERRIDE { + app->ConnectToService("mojo:mojo_network_service", &network_service_); + Start(); + } + + private: + void Start() { + std::string url = PromptForURL(); + printf("Loading: %s\n", url.c_str()); + + network_service_->CreateURLLoader(Get(&url_loader_)); + + URLRequestPtr request(URLRequest::New()); + request->url = url; + request->method = "GET"; + request->auto_follow_redirects = true; + + url_loader_->Start(request.Pass(), ResponsePrinter()); + } + + std::string PromptForURL() { + printf("Enter URL> "); + char buf[1024]; + if (scanf("%1023s", buf) != 1) + buf[0] = '\0'; + return buf; + } NetworkServicePtr network_service_; URLLoaderPtr url_loader_; - ScopedDataPipeConsumerHandle response_body_stream_; }; } // namespace examples diff --git a/mojo/services/launcher/launcher.cc b/mojo/services/launcher/launcher.cc index f9fc881..97a29c3 100644 --- a/mojo/services/launcher/launcher.cc +++ b/mojo/services/launcher/launcher.cc @@ -2,9 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "base/bind.h" #include "base/compiler_specific.h" #include "base/message_loop/message_loop.h" #include "base/strings/string_tokenizer.h" +#include "base/strings/string_util.h" #include "mojo/public/cpp/application/application_connection.h" #include "mojo/public/cpp/application/application_delegate.h" #include "mojo/public/cpp/application/application_impl.h" @@ -42,7 +44,7 @@ class LauncherConnection : public InterfaceImpl<Launcher> { DISALLOW_COPY_AND_ASSIGN(LauncherConnection); }; -class LaunchInstance : public URLLoaderClient { +class LaunchInstance { public: LaunchInstance(LauncherApp* app, const LaunchCallback& callback, @@ -50,24 +52,14 @@ class LaunchInstance : public URLLoaderClient { virtual ~LaunchInstance() {} private: - // Overridden from URLLoaderClient: - virtual void OnReceivedRedirect(URLResponsePtr response, - const String& new_url, - const String& new_method) OVERRIDE { - } - virtual void OnReceivedResponse(URLResponsePtr response) OVERRIDE; - virtual void OnReceivedError(NetworkErrorPtr error) OVERRIDE { - ScheduleDestroy(); - } - virtual void OnReceivedEndOfResponseBody() OVERRIDE { - ScheduleDestroy(); - } + void OnReceivedResponse(URLResponsePtr response); std::string GetContentType(const Array<String>& headers) { for (size_t i = 0; i < headers.size(); ++i) { base::StringTokenizer t(headers[i], ": ;="); while (t.GetNext()) { - if (!t.token_is_delim() && t.token() == "Content-Type") { + if (!t.token_is_delim() && + LowerCaseEqualsASCII(t.token(), "content-type")) { while (t.GetNext()) { if (!t.token_is_delim()) return t.token(); @@ -154,31 +146,33 @@ LaunchInstance::LaunchInstance(LauncherApp* app, : app_(app), destroy_scheduled_(false), callback_(callback) { - url_loader_ = app_->CreateURLLoader(); - url_loader_.set_client(this); - URLRequestPtr request(URLRequest::New()); request->url = url; request->method = "GET"; request->auto_follow_redirects = true; - DataPipe data_pipe; - response_body_stream_ = data_pipe.consumer_handle.Pass(); - - url_loader_->Start(request.Pass(), data_pipe.producer_handle.Pass()); + url_loader_ = app_->CreateURLLoader(); + url_loader_->Start(request.Pass(), + base::Bind(&LaunchInstance::OnReceivedResponse, + base::Unretained(this))); } void LaunchInstance::OnReceivedResponse(URLResponsePtr response) { - std::string content_type = GetContentType(response->headers); - std::string handler_url = app_->GetHandlerForContentType(content_type); - if (!handler_url.empty()) { - navigation::ResponseDetailsPtr nav_response( - navigation::ResponseDetails::New()); - nav_response->response = response.Pass(); - nav_response->response_body_stream = response_body_stream_.Pass(); - String response_url = nav_response->response->url; - callback_.Run(handler_url, response_url, nav_response.Pass()); + if (!response->error) { + std::string content_type = GetContentType(response->headers); + std::string handler_url = app_->GetHandlerForContentType(content_type); + if (handler_url.empty()) { + DLOG(WARNING) << "No handler for content type: " << content_type; + } else { + navigation::ResponseDetailsPtr nav_response( + navigation::ResponseDetails::New()); + nav_response->loader_handle = url_loader_.PassMessagePipe(); + nav_response->response = response.Pass(); + String response_url = nav_response->response->url; + callback_.Run(handler_url, response_url, nav_response.Pass()); + } } + ScheduleDestroy(); } } // namespace launcher diff --git a/mojo/services/network/url_loader_impl.cc b/mojo/services/network/url_loader_impl.cc index 88fdce8..fe490ab 100644 --- a/mojo/services/network/url_loader_impl.cc +++ b/mojo/services/network/url_loader_impl.cc @@ -46,6 +46,13 @@ URLResponsePtr MakeURLResponse(const net::URLRequest* url_request) { return response.Pass(); } +NetworkErrorPtr MakeNetworkError(int error_code) { + NetworkErrorPtr error = NetworkError::New(); + error->code = error_code; + error->description = net::ErrorToString(error_code); + return error.Pass(); +} + } // namespace // Keeps track of a pending two-phase write on a DataPipeProducerHandle. @@ -103,6 +110,7 @@ class URLLoaderImpl::DependentIOBuffer : public net::WrappedIOBuffer { URLLoaderImpl::URLLoaderImpl(NetworkContext* context) : context_(context), + response_body_buffer_size_(0), auto_follow_redirects_(true), weak_ptr_factory_(this) { } @@ -115,25 +123,19 @@ void URLLoaderImpl::OnConnectionError() { } void URLLoaderImpl::Start(URLRequestPtr request, - ScopedDataPipeProducerHandle response_body_stream) { - // Do not allow starting another request. + const Callback<void(URLResponsePtr)>& callback) { if (url_request_) { - SendError(net::ERR_UNEXPECTED); - url_request_.reset(); - response_body_stream_.reset(); + SendError(net::ERR_UNEXPECTED, callback); return; } if (!request) { - SendError(net::ERR_INVALID_ARGUMENT); + SendError(net::ERR_INVALID_ARGUMENT, callback); return; } - response_body_stream_ = response_body_stream.Pass(); - - GURL url(request->url); url_request_.reset( - new net::URLRequest(url, + new net::URLRequest(GURL(request->url), net::DEFAULT_PRIORITY, this, context_->url_request_context())); @@ -148,18 +150,42 @@ void URLLoaderImpl::Start(URLRequestPtr request, url_request_->SetLoadFlags(net::LOAD_BYPASS_CACHE); // TODO(darin): Handle request body. + callback_ = callback; + response_body_buffer_size_ = request->response_body_buffer_size; auto_follow_redirects_ = request->auto_follow_redirects; url_request_->Start(); } -void URLLoaderImpl::FollowRedirect() { +void URLLoaderImpl::FollowRedirect( + const Callback<void(URLResponsePtr)>& callback) { + if (!url_request_) { + SendError(net::ERR_UNEXPECTED, callback); + return; + } + if (auto_follow_redirects_) { DLOG(ERROR) << "Spurious call to FollowRedirect"; + SendError(net::ERR_UNEXPECTED, callback); + return; + } + + // TODO(darin): Verify that it makes sense to call FollowDeferredRedirect. + url_request_->FollowDeferredRedirect(); +} + +void URLLoaderImpl::QueryStatus( + const Callback<void(URLLoaderStatusPtr)>& callback) { + URLLoaderStatusPtr status(URLLoaderStatus::New()); + if (url_request_) { + status->is_loading = url_request_->is_pending(); + if (!url_request_->status().is_success()) + status->error = MakeNetworkError(url_request_->status().error()); } else { - if (url_request_) - url_request_->FollowDeferredRedirect(); + status->is_loading = false; } + // TODO(darin): Populate more status fields. + callback.Run(status.Pass()); } void URLLoaderImpl::OnReceivedRedirect(net::URLRequest* url_request, @@ -168,27 +194,41 @@ void URLLoaderImpl::OnReceivedRedirect(net::URLRequest* url_request, DCHECK(url_request == url_request_.get()); DCHECK(url_request->status().is_success()); + if (auto_follow_redirects_) + return; + + // Send the redirect response to the client, allowing them to inspect it and + // optionally follow the redirect. + *defer_redirect = true; + URLResponsePtr response = MakeURLResponse(url_request); - std::string redirect_method = + response->redirect_method = net::URLRequest::ComputeMethodForRedirect(url_request->method(), response->status_code); - client()->OnReceivedRedirect( - response.Pass(), new_url.spec(), redirect_method); + response->redirect_url = new_url.spec(); - *defer_redirect = !auto_follow_redirects_; + SendResponse(response.Pass()); } void URLLoaderImpl::OnResponseStarted(net::URLRequest* url_request) { DCHECK(url_request == url_request_.get()); if (!url_request->status().is_success()) { - SendError(url_request->status().error()); + SendError(url_request->status().error(), callback_); + callback_ = Callback<void(URLResponsePtr)>(); return; } // TODO(darin): Add support for optional MIME sniffing. - client()->OnReceivedResponse(MakeURLResponse(url_request)); + DataPipe data_pipe; + // TODO(darin): Honor given buffer size. + + URLResponsePtr response = MakeURLResponse(url_request); + response->body = data_pipe.consumer_handle.Pass(); + response_body_stream_ = data_pipe.producer_handle.Pass(); + + SendResponse(response.Pass()); // Start reading... ReadMore(); @@ -196,19 +236,29 @@ void URLLoaderImpl::OnResponseStarted(net::URLRequest* url_request) { void URLLoaderImpl::OnReadCompleted(net::URLRequest* url_request, int bytes_read) { + DCHECK(url_request == url_request_.get()); + if (url_request->status().is_success()) { DidRead(static_cast<uint32_t>(bytes_read), false); } else { pending_write_ = NULL; // This closes the data pipe. - // TODO(darin): Perhaps we should communicate this error to our client. } } -void URLLoaderImpl::SendError(int error_code) { - NetworkErrorPtr error(NetworkError::New()); - error->code = error_code; - error->description = net::ErrorToString(error_code); - client()->OnReceivedError(error.Pass()); +void URLLoaderImpl::SendError( + int error_code, + const Callback<void(URLResponsePtr)>& callback) { + URLResponsePtr response(URLResponse::New()); + if (url_request_) + response->url = url_request_->url().spec(); + response->error = MakeNetworkError(error_code); + callback.Run(response.Pass()); +} + +void URLLoaderImpl::SendResponse(URLResponsePtr response) { + Callback<void(URLResponsePtr)> callback; + std::swap(callback_, callback); + callback.Run(response.Pass()); } void URLLoaderImpl::OnResponseBodyStreamReady(MojoResult result) { @@ -260,12 +310,6 @@ void URLLoaderImpl::ReadMore() { } else { pending_write_->Complete(0); pending_write_ = NULL; // This closes the data pipe. - if (bytes_read == 0) { - client()->OnReceivedEndOfResponseBody(); - } else { - DCHECK(!url_request_->status().is_success()); - SendError(url_request_->status().error()); - } } } diff --git a/mojo/services/network/url_loader_impl.h b/mojo/services/network/url_loader_impl.h index 93af0d4..68bad9a 100644 --- a/mojo/services/network/url_loader_impl.h +++ b/mojo/services/network/url_loader_impl.h @@ -33,8 +33,11 @@ class URLLoaderImpl : public InterfaceImpl<URLLoader>, // URLLoader methods: virtual void Start( URLRequestPtr request, - ScopedDataPipeProducerHandle response_body_stream) OVERRIDE; - virtual void FollowRedirect() OVERRIDE; + const Callback<void(URLResponsePtr)>& callback) OVERRIDE; + virtual void FollowRedirect( + const Callback<void(URLResponsePtr)>& callback) OVERRIDE; + virtual void QueryStatus( + const Callback<void(URLLoaderStatusPtr)>& callback) OVERRIDE; // net::URLRequest::Delegate methods: virtual void OnReceivedRedirect(net::URLRequest* url_request, @@ -44,7 +47,10 @@ class URLLoaderImpl : public InterfaceImpl<URLLoader>, virtual void OnReadCompleted(net::URLRequest* url_request, int bytes_read) OVERRIDE; - void SendError(int error); + void SendError( + int error, + const Callback<void(URLResponsePtr)>& callback); + void SendResponse(URLResponsePtr response); void OnResponseBodyStreamReady(MojoResult result); void WaitToReadMore(); void ReadMore(); @@ -52,9 +58,11 @@ class URLLoaderImpl : public InterfaceImpl<URLLoader>, NetworkContext* context_; scoped_ptr<net::URLRequest> url_request_; + Callback<void(URLResponsePtr)> callback_; ScopedDataPipeProducerHandle response_body_stream_; scoped_refptr<PendingWriteToDataPipe> pending_write_; common::HandleWatcher handle_watcher_; + uint32 response_body_buffer_size_; bool auto_follow_redirects_; base::WeakPtrFactory<URLLoaderImpl> weak_ptr_factory_; diff --git a/mojo/services/public/interfaces/navigation/navigation.mojom b/mojo/services/public/interfaces/navigation/navigation.mojom index a08e361..5254bf0 100644 --- a/mojo/services/public/interfaces/navigation/navigation.mojom +++ b/mojo/services/public/interfaces/navigation/navigation.mojom @@ -26,8 +26,13 @@ struct NavigationDetails { struct ResponseDetails { // TODO(beng): consider providing access to URLRequest too. Currently it is // not possible to obtain from the URLLoader. + + // The URLLoader instance that generated the response. This must be kept + // alive until the response body has been completely consumed. + // TODO(darin): This should be |mojo.URLLoader loader|. See crbug/392693. + handle<message_pipe> loader_handle; + mojo.URLResponse response; - handle<data_pipe_consumer> response_body_stream; }; // Embedders that support navigation of implement this interface. diff --git a/mojo/services/public/interfaces/network/url_loader.mojom b/mojo/services/public/interfaces/network/url_loader.mojom index 22d5fdb..da340c4 100644 --- a/mojo/services/public/interfaces/network/url_loader.mojom +++ b/mojo/services/public/interfaces/network/url_loader.mojom @@ -16,15 +16,20 @@ struct URLRequest { // Additional HTTP request headers. string[] headers; - // The payload for the request body. For HTTP requests, the method must be - // set to "POST" or "PUT". - handle<data_pipe_consumer> body; + // The payload for the request body, represented as a concatenation of data + // streams. For HTTP requests, the method must be set to "POST" or "PUT". + handle<data_pipe_consumer>[] body; // The number of bytes to be read from |body|. A Content-Length header of // this value will be sent. Set to -1 if length is unknown, which will cause // |body| to be uploaded using a chunked encoding. int64 body_length = 0; + // The buffer size of the data pipe returned in URLResponse's |body| member. + // A value of 0 indicates that the default buffer size should be used. This + // value is just a suggestion. The URLLoader may choose to ignore this value. + uint32 response_body_buffer_size = 0; + // If set to true, then redirects will be automatically followed. Otherwise, // when a redirect is encounterd, FollowRedirect must be called to proceed. bool auto_follow_redirects = false; @@ -37,6 +42,13 @@ struct URLRequest { }; struct URLResponse { + // If the response resulted in a network level error, this field will be set. + NetworkError error; + + // The response body stream. Read from this data pipe to receive the bytes of + // response body. + handle<data_pipe_consumer> body; + // The final URL of the response, after redirects have been followed. string url; @@ -54,47 +66,41 @@ struct URLResponse { // The character set of the response body. string charset; + + // These fields are set to non-NULL if this response corresponds to a + // redirect. Call the |FollowRedirect| method on the URLLoader instance to + // follow this redirect. + string redirect_method; + string redirect_url; +}; + +struct URLLoaderStatus { + // If the loader has failed due to a network level error, this field will be + // set. + NetworkError error; + + // Set to true if the URLLoader is still working. Set to false once an error + // is encountered or the response body is completely copied to the response + // body stream. + bool is_loading; + + // TODO(darin): Add further details about the stages of loading (e.g., + // "resolving host") that happen prior to receiving bytes. }; -[Client=URLLoaderClient] interface URLLoader { - // Start loading the given |request|. When available, the response body will - // be copied to |response_body_stream|. - // - // The client's |OnReceivedResponse| method will run when response meta data - // becomes available, or if a redirect response is encountered and - // |auto_follow_redirects| is false, the client's |OnRecievedRedirect| method - // will called instead. - // - // NOTE: You may observe data being pushed to |response_body_stream| before - // you receive |OnReceivedResponse|. - Start(URLRequest request, handle<data_pipe_producer> response_body_stream); + // Loads the given |request|, asynchronously producing |response|. Consult + // |response| to determine if the request resulted in an error, was + // redirected, or has a response body to be consumed. + Start(URLRequest request) => (URLResponse response); // If the request passed to |Start| had |auto_follow_redirects| set to false, - // then upon receiving a redirect, |OnReceivedRedirect| will be called. To - // follow the indicated redirect, call the |FollowRedirect| method. - FollowRedirect(); -}; + // then upon receiving an URLResponse with a non-NULL |redirect_url| field, + // |FollowRedirect| may be called to load the URL indicated by the redirect. + FollowRedirect() => (URLResponse response); -interface URLLoaderClient { - // This method is called when a redirect is encountered, provided the - // request's |auto_follow_redirects| attribute was set to false. - OnReceivedRedirect(URLResponse response, string new_url, string new_method); - - // This method is called when response meta data becomes available. - OnReceivedResponse(URLResponse response); - - // This method is called when a network level error is encountered. This can - // happen before or after OnReceivedResponse, but cannot happen after - // OnReceivedEndOfResponseBody. - OnReceivedError(NetworkError error); - - // This method is called when the response body has been successfully - // downloaded and copied in its entirety to |response_body_stream|. - // - // NOTE: Because |response_body_stream| is limited in size, this event may be - // delayed until |response_body_stream| is consumed. - OnReceivedEndOfResponseBody(); + // Query status about the URLLoader. + QueryStatus() => (URLLoaderStatus status); }; } diff --git a/mojo/shell/dynamic_service_loader.cc b/mojo/shell/dynamic_service_loader.cc index 994e318..2b20243 100644 --- a/mojo/shell/dynamic_service_loader.cc +++ b/mojo/shell/dynamic_service_loader.cc @@ -80,19 +80,19 @@ class LocalLoader : public Loader { }; // For loading services via the network stack. -class NetworkLoader : public Loader, public URLLoaderClient { +class NetworkLoader : public Loader { public: explicit NetworkLoader(scoped_ptr<DynamicServiceRunner> runner, NetworkService* network_service) : Loader(runner.Pass()) { network_service->CreateURLLoader(Get(&url_loader_)); - url_loader_.set_client(this); } virtual void Start(const GURL& url, ScopedMessagePipeHandle service_handle, Context* context) OVERRIDE { service_handle_ = service_handle.Pass(); + context_ = context; URLRequestPtr request(URLRequest::New()); request->url = url.spec(); @@ -103,17 +103,9 @@ class NetworkLoader : public Loader, public URLLoaderClient { request->bypass_cache = true; } - DataPipe data_pipe; - url_loader_->Start(request.Pass(), data_pipe.producer_handle.Pass()); - - base::CreateTemporaryFile(&file_); - common::CopyToFile(data_pipe.consumer_handle.Pass(), - file_, - context->task_runners()->blocking_pool(), - base::Bind(&Loader::StartService, - base::Unretained(this), - file_, - base::Passed(&service_handle_))); + url_loader_->Start(request.Pass(), + base::Bind(&NetworkLoader::OnReceivedResponse, + base::Unretained(this))); } private: @@ -122,16 +114,24 @@ class NetworkLoader : public Loader, public URLLoaderClient { base::DeleteFile(file_, false); } - // URLLoaderClient methods: - virtual void OnReceivedRedirect(URLResponsePtr response, - const String& new_url, - const String& new_method) OVERRIDE { - // TODO(darin): Handle redirects properly! + void OnReceivedResponse(URLResponsePtr response) { + if (response->error) { + LOG(ERROR) << "Error (" << response->error->code << ": " + << response->error->description << ") while fetching " + << response->url; + } + + base::CreateTemporaryFile(&file_); + common::CopyToFile(response->body.Pass(), + file_, + context_->task_runners()->blocking_pool(), + base::Bind(&Loader::StartService, + base::Unretained(this), + file_, + base::Passed(&service_handle_))); } - virtual void OnReceivedResponse(URLResponsePtr response) OVERRIDE {} - virtual void OnReceivedError(NetworkErrorPtr error) OVERRIDE {} - virtual void OnReceivedEndOfResponseBody() OVERRIDE {} + Context* context_; NetworkServicePtr network_service_; URLLoaderPtr url_loader_; ScopedMessagePipeHandle service_handle_; diff --git a/mojo/shell/in_process_dynamic_service_runner.cc b/mojo/shell/in_process_dynamic_service_runner.cc index 6bcaa5c..0d80d40 100644 --- a/mojo/shell/in_process_dynamic_service_runner.cc +++ b/mojo/shell/in_process_dynamic_service_runner.cc @@ -74,9 +74,12 @@ void InProcessDynamicServiceRunner::Run() { break; } } else { + // In the component build, Mojo Apps link against mojo_system_impl. +#if !defined(COMPONENT_BUILD) // Strictly speaking this is not required, but it's very unusual to have // an app that doesn't require the basic system library. LOG(WARNING) << "MojoSetSystemThunks not found in app library"; +#endif } typedef MojoResult (*MojoMainFunction)(MojoHandle); |