Skip to content

Commit

Permalink
Merge pull request #2286 from chinmaygarde/master
Browse files Browse the repository at this point in the history
iOS: Drain and pass URLRequest body data to the platform implementation
  • Loading branch information
chinmaygarde committed Jan 25, 2016
2 parents 57ec439 + 0f0360e commit 4421177
Show file tree
Hide file tree
Showing 5 changed files with 115 additions and 14 deletions.
1 change: 1 addition & 0 deletions sky/services/ns_net/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ source_set("ns_net") {

deps = [
"//base:base",
"//mojo/data_pipe_utils",
"//mojo/public/cpp/application",
"//mojo/services/network/interfaces",
]
Expand Down
13 changes: 11 additions & 2 deletions sky/services/ns_net/network_service_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef SKY_SERVICES_NSNET_NETWORK_SERVICE_IMPL_H_
#define SKY_SERVICES_NSNET_NETWORK_SERVICE_IMPL_H_

#include "base/macros.h"
#include "mojo/public/cpp/application/interface_factory.h"
#include "mojo/public/cpp/bindings/strong_binding.h"
#include "mojo/services/network/interfaces/network_service.mojom.h"
Expand Down Expand Up @@ -31,11 +35,14 @@ class NetworkServiceImpl : public NetworkService {
HttpServerDelegatePtr delegate,
const CreateHttpServerCallback& callback) override;
void RegisterURLLoaderInterceptor(
URLLoaderInterceptorFactoryPtr factory) override;
void CreateHostResolver(InterfaceRequest<HostResolver> host_resolver) override;
URLLoaderInterceptorFactoryPtr factory) override;
void CreateHostResolver(
InterfaceRequest<HostResolver> host_resolver) override;

private:
StrongBinding<NetworkService> binding_;

DISALLOW_COPY_AND_ASSIGN(NetworkServiceImpl);
};

class NetworkServiceFactory : public InterfaceFactory<NetworkService> {
Expand All @@ -45,3 +52,5 @@ class NetworkServiceFactory : public InterfaceFactory<NetworkService> {
};

} // namespace mojo

#endif // SKY_SERVICES_NSNET_NETWORK_SERVICE_IMPL_H_
20 changes: 8 additions & 12 deletions sky/services/ns_net/network_service_impl.mm
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,11 @@
namespace mojo {

NetworkServiceImpl::NetworkServiceImpl(InterfaceRequest<NetworkService> request)
: binding_(this, request.Pass()) {
}
: binding_(this, request.Pass()) {}

NetworkServiceImpl::~NetworkServiceImpl() {
}
NetworkServiceImpl::~NetworkServiceImpl() {}

void NetworkServiceImpl::CreateURLLoader(
InterfaceRequest<URLLoader> loader) {
void NetworkServiceImpl::CreateURLLoader(InterfaceRequest<URLLoader> loader) {
new URLLoaderImpl(loader.Pass());
}

Expand All @@ -25,8 +22,7 @@
DCHECK(false);
}

void NetworkServiceImpl::CreateWebSocket(
InterfaceRequest<WebSocket> socket) {
void NetworkServiceImpl::CreateWebSocket(InterfaceRequest<WebSocket> socket) {
DCHECK(false);
}

Expand All @@ -46,8 +42,7 @@
DCHECK(false);
}

void NetworkServiceImpl::CreateUDPSocket(
InterfaceRequest<UDPSocket> socket) {
void NetworkServiceImpl::CreateUDPSocket(InterfaceRequest<UDPSocket> socket) {
DCHECK(false);
}

Expand All @@ -59,11 +54,12 @@
}

void NetworkServiceImpl::RegisterURLLoaderInterceptor(
URLLoaderInterceptorFactoryPtr factory) {
URLLoaderInterceptorFactoryPtr factory) {
DCHECK(false);
}

void NetworkServiceImpl::CreateHostResolver(InterfaceRequest<HostResolver> host_resolver) {
void NetworkServiceImpl::CreateHostResolver(
InterfaceRequest<HostResolver> host_resolver) {
DCHECK(false);
}

Expand Down
21 changes: 21 additions & 0 deletions sky/services/ns_net/url_loader_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,24 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef SKY_SERVICES_NSNET_URLLOADER_IMPL_H_
#define SKY_SERVICES_NSNET_URLLOADER_IMPL_H_

#include "base/macros.h"
#include "mojo/public/cpp/application/interface_factory.h"
#include "mojo/public/cpp/bindings/strong_binding.h"
#include "mojo/services/network/interfaces/url_loader.mojom.h"

#if __OBJC__
@class NSData;
#else // __OBJC__
class NSData;
#endif // __OBJC__

namespace mojo {

class AsyncNSDataDrainer;

class URLLoaderImpl : public URLLoader {
public:
explicit URLLoaderImpl(InterfaceRequest<URLLoader> request);
Expand All @@ -20,6 +32,15 @@ class URLLoaderImpl : public URLLoader {
private:
StrongBinding<URLLoader> binding_;
void* pending_connection_;
std::unique_ptr<AsyncNSDataDrainer> request_data_drainer_;

void StartNow(
URLRequestPtr request,
const StartCallback& callback, NSData* body_data);

DISALLOW_COPY_AND_ASSIGN(URLLoaderImpl);
};

} // namespace mojo

#endif // SKY_SERVICES_NSNET_URLLOADER_IMPL_H_
74 changes: 74 additions & 0 deletions sky/services/ns_net/url_loader_impl.mm
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@
// found in the LICENSE file.

#include "url_loader_impl.h"
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/logging.h"
#include "base/mac/scoped_nsautorelease_pool.h"
#include "mojo/data_pipe_utils/data_pipe_drainer.h"

#import <Foundation/Foundation.h>

Expand Down Expand Up @@ -95,6 +98,57 @@ - (void)dealloc {

namespace mojo {

class AsyncNSDataDrainer : common::DataPipeDrainer::Client {
public:
using CompletionCallback = base::Callback<void(NSData* /* transfer-none */)>;

AsyncNSDataDrainer()
: data_([[NSMutableData alloc] init]), draining_(false) {}

void StartWithCompletionCallback(ScopedDataPipeConsumerHandle source,
CompletionCallback callback) {
DCHECK(!draining_)
<< "A instance of an AsyncNSDataDrainer can only be used to drain once";
DCHECK(drainer_ == nullptr);

draining_ = true;
callback_ = callback;

// There is no "Start" method on a data pipe drainer. Instantiating
// an instance automatically starts the drain.
drainer_ = std::unique_ptr<common::DataPipeDrainer>(
new common::DataPipeDrainer(this, source.Pass()));
}

~AsyncNSDataDrainer() override { [data_ release]; }

private:
CompletionCallback callback_;
NSMutableData* data_;
std::unique_ptr<common::DataPipeDrainer> drainer_;
bool draining_;

void OnDataAvailable(const void* data, size_t num_bytes) override {
[data_ appendBytes:data length:num_bytes];
}

void OnDataComplete() override {
auto callback = callback_;
NSMutableData* data = data_;

[data retain];
// The owner of this NSData drainer may cause its collection in the callback
// If this is the first thing that happens in the callback, the final
// data_ reference may be released (in dtor) before the callback accesses
// that data further along in the same callback. So make sure we keep an
// extra reference for the duration of the callback.
callback.Run(data);
[data release];
}

DISALLOW_COPY_AND_ASSIGN(AsyncNSDataDrainer);
};

URLLoaderImpl::URLLoaderImpl(InterfaceRequest<URLLoader> request)
: binding_(this, request.Pass()), pending_connection_(nullptr) {}

Expand All @@ -104,12 +158,32 @@ - (void)dealloc {

void URLLoaderImpl::Start(URLRequestPtr request,
const StartCallback& callback) {
if (request->body.size() == 1) {
// If the body has request data, try to drain that
request_data_drainer_ =
std::unique_ptr<AsyncNSDataDrainer>(new AsyncNSDataDrainer());

request_data_drainer_->StartWithCompletionCallback(
request->body[0].Pass(), // handle
base::Bind(&URLLoaderImpl::StartNow, base::Unretained(this),
base::Passed(&request), callback));
} else {
StartNow(request.Pass(), callback, nullptr);
}
}

void URLLoaderImpl::StartNow(URLRequestPtr request,
const StartCallback& callback,
NSData* body_data) {
base::mac::ScopedNSAutoreleasePool pool;

request_data_drainer_.reset();

NSURL* url = [NSURL URLWithString:@(request->url.data())];
NSMutableURLRequest* req = [NSMutableURLRequest requestWithURL:url];

req.HTTPMethod = @(request->method.data());
req.HTTPBody = body_data; // by copy

for (const auto& header : request->headers) {
NSString* name = @(header->name.data());
Expand Down

0 comments on commit 4421177

Please sign in to comment.