diff --git a/services/ns_net/BUILD.gn b/services/ns_net/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..ab7a5eb82197f1189b8854d4299642dd5cfd51d5 --- /dev/null +++ b/services/ns_net/BUILD.gn @@ -0,0 +1,19 @@ +# Copyright 2015 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. + +source_set("ns_net") { + sources = [ + "network_service_impl.h", + "network_service_impl.mm", + "url_loader_impl.h", + "url_loader_impl.mm", + ] + + deps = [ + "//base:base", + "//mojo/common", + "//mojo/public/cpp/application", + "//mojo/services/network/public/interfaces", + ] +} diff --git a/services/ns_net/network_service_impl.h b/services/ns_net/network_service_impl.h new file mode 100644 index 0000000000000000000000000000000000000000..2e01168fb6473f90b2c52a449207b17df101c08f --- /dev/null +++ b/services/ns_net/network_service_impl.h @@ -0,0 +1,46 @@ +// Copyright 2015 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. + +#include "mojo/public/cpp/application/interface_factory.h" +#include "mojo/public/cpp/bindings/strong_binding.h" +#include "mojo/services/network/public/interfaces/network_service.mojom.h" + +namespace mojo { + +class NetworkServiceImpl : public NetworkService { + public: + explicit NetworkServiceImpl(InterfaceRequest request) + : binding_(this, request.Pass()) {} + + void CreateURLLoader(InterfaceRequest loader) override; + void GetCookieStore(InterfaceRequest cookie_store) override; + void CreateWebSocket(InterfaceRequest socket) override; + void CreateTCPBoundSocket( + NetAddressPtr local_address, + InterfaceRequest bound_socket, + const CreateTCPBoundSocketCallback& callback) override; + void CreateTCPConnectedSocket( + NetAddressPtr remote_address, + ScopedDataPipeConsumerHandle send_stream, + ScopedDataPipeProducerHandle receive_stream, + InterfaceRequest client_socket, + const CreateTCPConnectedSocketCallback& callback) override; + void CreateUDPSocket(InterfaceRequest socket) override; + void CreateHttpServer(NetAddressPtr local_address, + HttpServerDelegatePtr delegate, + const CreateHttpServerCallback& callback) override; + void RegisterURLLoaderInterceptor( + URLLoaderInterceptorFactoryPtr factory) override; + + private: + StrongBinding binding_; +}; + +class NetworkServiceFactory : public InterfaceFactory { + public: + void Create(ApplicationConnection* connection, + InterfaceRequest request) override; +}; + +} // namespace mojo diff --git a/services/ns_net/network_service_impl.mm b/services/ns_net/network_service_impl.mm new file mode 100644 index 0000000000000000000000000000000000000000..903b345dff78ff3b83fb588242b12dadbd6a1056 --- /dev/null +++ b/services/ns_net/network_service_impl.mm @@ -0,0 +1,65 @@ +// Copyright 2015 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. + +#include "network_service_impl.h" +#include "url_loader_impl.h" +#include "base/logging.h" +#include + +namespace mojo { + +void NetworkServiceImpl::CreateURLLoader( + InterfaceRequest loader) { + new URLLoaderImpl(loader.Pass()); +} + +void NetworkServiceImpl::GetCookieStore( + InterfaceRequest cookie_store) { + DCHECK(false); +} + +void NetworkServiceImpl::CreateWebSocket( + InterfaceRequest socket) { + DCHECK(false); +} + +void NetworkServiceImpl::CreateTCPBoundSocket( + NetAddressPtr local_address, + InterfaceRequest bound_socket, + const CreateTCPBoundSocketCallback& callback) { + DCHECK(false); +} + +void NetworkServiceImpl::CreateTCPConnectedSocket( + NetAddressPtr remote_address, + ScopedDataPipeConsumerHandle send_stream, + ScopedDataPipeProducerHandle receive_stream, + InterfaceRequest client_socket, + const CreateTCPConnectedSocketCallback& callback) { + DCHECK(false); +} + +void NetworkServiceImpl::CreateUDPSocket( + InterfaceRequest socket) { + DCHECK(false); +} + +void NetworkServiceImpl::CreateHttpServer( + NetAddressPtr local_address, + HttpServerDelegatePtr delegate, + const CreateHttpServerCallback& callback) { + DCHECK(false); +} + +void NetworkServiceImpl::RegisterURLLoaderInterceptor( + URLLoaderInterceptorFactoryPtr factory) { + DCHECK(false); +} + +void NetworkServiceFactory::Create(ApplicationConnection* connection, + InterfaceRequest request) { + new NetworkServiceImpl(request.Pass()); +} + +} // namespace mojo diff --git a/services/ns_net/url_loader_impl.h b/services/ns_net/url_loader_impl.h new file mode 100644 index 0000000000000000000000000000000000000000..473166f25302676c845b5faed690d45c5590ef2b --- /dev/null +++ b/services/ns_net/url_loader_impl.h @@ -0,0 +1,26 @@ +// Copyright 2015 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. + +#include "mojo/public/cpp/application/interface_factory.h" +#include "mojo/public/cpp/bindings/strong_binding.h" +#include "mojo/services/network/public/interfaces/url_loader.mojom.h" + +namespace mojo { + +class URLLoaderImpl : public URLLoader { + public: + explicit URLLoaderImpl(InterfaceRequest request); + ~URLLoaderImpl(); + + void Start(URLRequestPtr request, const StartCallback& callback) override; + void FollowRedirect(const FollowRedirectCallback& callback) override; + void QueryStatus(const QueryStatusCallback& callback) override; + + private: + StrongBinding binding_; + void* connection_delegate_; + void* pending_connection_; +}; + +} // namespace mojo diff --git a/services/ns_net/url_loader_impl.mm b/services/ns_net/url_loader_impl.mm new file mode 100644 index 0000000000000000000000000000000000000000..702b9e09ecf4bc84e610312bdb35583ddf31651a --- /dev/null +++ b/services/ns_net/url_loader_impl.mm @@ -0,0 +1,158 @@ +// Copyright 2015 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. + +#include "url_loader_impl.h" +#include "base/logging.h" +#include "base/mac/scoped_nsautorelease_pool.h" + +#import + +@interface URLLoaderConnectionDelegate : NSObject + +@property(nonatomic) mojo::URLLoaderImpl::StartCallback startCallback; + +@end + +@implementation URLLoaderConnectionDelegate { + mojo::URLResponsePtr _response; + mojo::ScopedDataPipeProducerHandle _producer; +} + +@synthesize startCallback = _startCallback; + +- (void)connection:(NSURLConnection*)connection + didReceiveResponse:(NSHTTPURLResponse*)response { + _response = mojo::URLResponse::New(); + _response->status_code = response.statusCode; + _response->url = + mojo::String(connection.originalRequest.URL.absoluteString.UTF8String); + mojo::DataPipe pipe; + _response->body = pipe.consumer_handle.Pass(); + _producer = pipe.producer_handle.Pass(); + [self.class updateDelegate:self asPending:YES]; +} + +- (void)connection:(NSURLConnection*)connection didReceiveData:(NSData*)data { + if (!_startCallback.is_null()) { + DCHECK(_response); + _startCallback.Run(_response.Pass()); + _startCallback.reset(); + _response.reset(); + } + uint32_t length = data.length; + MojoResult result = WriteDataRaw(_producer.get(), data.bytes, &length, + MOJO_WRITE_DATA_FLAG_ALL_OR_NONE); + // FIXME(csg): Handle buffers in case of failures + DCHECK(result == MOJO_RESULT_OK); + DCHECK(length == data.length); +} + +- (void)connectionDidFinishLoading:(NSURLConnection*)connection { + DCHECK(_response.is_null()); + DCHECK(_startCallback.is_null()); + _producer.reset(); + [self.class updateDelegate:self asPending:NO]; +} + +- (void)connection:(NSURLConnection*)connection + didFailWithError:(NSError*)error { + if (!_startCallback.is_null()) { + if (_response.is_null()) { + _response = mojo::URLResponse::New(); + _response->url = mojo::String( + connection.originalRequest.URL.absoluteString.UTF8String); + } + + _response->error = mojo::NetworkError::New(); + _response->error->description = + mojo::String(error.localizedDescription.UTF8String); + + _startCallback.Run(_response.Pass()); + _startCallback.reset(); + } + + _response.reset(); + _producer.reset(); + [self.class updateDelegate:self asPending:NO]; +} + +// Since the only reference to the producer end of a data pipe is held by the +// delegate, which itself has no strong reference, we put the in-flight requests +// in a collection that references these delegates while they are active. ++ (void)updateDelegate:(URLLoaderConnectionDelegate*)delegate + asPending:(BOOL)pending { + static NSMutableSet* pendingConnections = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + pendingConnections = [[NSMutableSet alloc] init]; + }); + if (pending) { + [pendingConnections addObject:delegate]; + } else { + [pendingConnections removeObject:delegate]; + } +} + +- (void)dealloc { + DCHECK(_response.is_null()); + DCHECK(_startCallback.is_null()); + _producer.reset(); + [super dealloc]; +} + +@end + +namespace mojo { + +URLLoaderImpl::URLLoaderImpl(InterfaceRequest request) + : binding_(this, request.Pass()), + connection_delegate_(nullptr), + pending_connection_(nullptr) { + connection_delegate_ = [[URLLoaderConnectionDelegate alloc] init]; +} + +URLLoaderImpl::~URLLoaderImpl() { + [(id)connection_delegate_ release]; + + [(id)pending_connection_ cancel]; + [(id)pending_connection_ release]; +} + +void URLLoaderImpl::Start(URLRequestPtr request, + const StartCallback& callback) { + base::mac::ScopedNSAutoreleasePool pool; + + NSURL* url = [NSURL URLWithString:@(request->url.data())]; + NSMutableURLRequest* req = [NSMutableURLRequest requestWithURL:url]; + + req.HTTPMethod = @(request->method.data()); + + if (request->bypass_cache) { + req.cachePolicy = NSURLRequestReloadIgnoringLocalCacheData; + } + + URLLoaderConnectionDelegate* delegate = + (URLLoaderConnectionDelegate*)connection_delegate_; + + NSURLConnection* connection = + [NSURLConnection connectionWithRequest:req delegate:delegate]; + + delegate.startCallback = callback; + + [connection start]; + + pending_connection_ = [connection retain]; +} + +void URLLoaderImpl::FollowRedirect(const FollowRedirectCallback& callback) { + base::mac::ScopedNSAutoreleasePool pool; + DCHECK(false); +} + +void URLLoaderImpl::QueryStatus(const QueryStatusCallback& callback) { + base::mac::ScopedNSAutoreleasePool pool; + DCHECK(false); +} + +} // namespace mojo