| Index: content/browser/loader/loader_test_service_impl.cc
 | 
| diff --git a/content/browser/loader/loader_test_service_impl.cc b/content/browser/loader/loader_test_service_impl.cc
 | 
| new file mode 100644
 | 
| index 0000000000000000000000000000000000000000..deb41e4d24a7630e79421e82b6874962ee34a94a
 | 
| --- /dev/null
 | 
| +++ b/content/browser/loader/loader_test_service_impl.cc
 | 
| @@ -0,0 +1,110 @@
 | 
| +// 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 "content/browser/loader/loader_test_service_impl.h"
 | 
| +
 | 
| +#include "base/bind.h"
 | 
| +#include "base/memory/scoped_ptr.h"
 | 
| +#include "content/browser/loader/loader_test_service_context.h"
 | 
| +#include "mojo/message_pump/handle_watcher.h"
 | 
| +
 | 
| +namespace content {
 | 
| +
 | 
| +class LoaderTestServiceImpl::Job {
 | 
| + public:
 | 
| +  Job(int id,
 | 
| +      mojo::ScopedDataPipeConsumerHandle reader,
 | 
| +      LoaderTestServiceImpl* service,
 | 
| +      const TransmitCallback& callback)
 | 
| +      : id_(id),
 | 
| +        reader_(std::move(reader)),
 | 
| +        read_size_(0),
 | 
| +        service_(service),
 | 
| +        callback_(callback) {}
 | 
| +
 | 
| +  void Start() { StartWatching(); }
 | 
| +
 | 
| +  void StartWatching() {
 | 
| +    handle_watcher_.Start(reader_.get(), MOJO_HANDLE_SIGNAL_READABLE,
 | 
| +                          MOJO_DEADLINE_INDEFINITE,
 | 
| +                          base::Bind(&Job::OnReadable, base::Unretained(this)));
 | 
| +  }
 | 
| +
 | 
| +  void OnReadable(MojoResult) {
 | 
| +    // fprintf(stderr, "%s\n", __PRETTY_FUNCTION__);
 | 
| +    while (true) {
 | 
| +      const void* buffer = nullptr;
 | 
| +      uint32_t available;
 | 
| +      MojoResult result = mojo::BeginReadDataRaw(
 | 
| +          reader_.get(), &buffer, &available, MOJO_WRITE_DATA_FLAG_NONE);
 | 
| +      // fprintf(stderr, "result = %d\n", static_cast<int>(result));
 | 
| +      // for (size_t i = 0; i < available; ++i) {
 | 
| +      // fprintf(stderr, "buffer[%zu] = %02x\n", i, ((const char*)buffer)[i]);
 | 
| +      // }
 | 
| +      if (result == MOJO_RESULT_OK) {
 | 
| +        mojo::EndReadDataRaw(reader_.get(), available);
 | 
| +        read_size_ += available;
 | 
| +        // fprintf(stderr, "read %zu\n", static_cast<size_t>(available));
 | 
| +      } else if (result == MOJO_RESULT_SHOULD_WAIT) {
 | 
| +        StartWatching();
 | 
| +        break;
 | 
| +      } else if (result == MOJO_RESULT_FAILED_PRECONDITION) {
 | 
| +        fprintf(stderr, "done: read %zu bytes\n", read_size_);
 | 
| +        callback_.Run();
 | 
| +        service_->DeleteJob(id_);
 | 
| +        // |this| is deleted here.
 | 
| +        return;
 | 
| +      } else {
 | 
| +        service_->DeleteJob(id_);
 | 
| +        // |this| is deleted here.
 | 
| +        return;
 | 
| +      }
 | 
| +    }
 | 
| +  }
 | 
| +
 | 
| + private:
 | 
| +  int id_;
 | 
| +  mojo::ScopedDataPipeConsumerHandle reader_;
 | 
| +  mojo::common::HandleWatcher handle_watcher_;
 | 
| +  size_t read_size_;
 | 
| +  LoaderTestServiceImpl* service_;
 | 
| +  TransmitCallback callback_;
 | 
| +};
 | 
| +
 | 
| +LoaderTestServiceImpl::LoaderTestServiceImpl(
 | 
| +    mojo::InterfaceRequest<LoaderTestService> request,
 | 
| +    LoaderTestServiceContext* context)
 | 
| +    : binding_(this, std::move(request)), context_(context), job_id_(0) {
 | 
| +  fprintf(stderr, "%s\n", __PRETTY_FUNCTION__);
 | 
| +  binding_.set_connection_error_handler(base::Bind(
 | 
| +      &LoaderTestServiceImpl::OnConnectionError, base::Unretained(this)));
 | 
| +}
 | 
| +
 | 
| +LoaderTestServiceImpl::~LoaderTestServiceImpl() = default;
 | 
| +
 | 
| +void LoaderTestServiceImpl::OnConnectionError() {
 | 
| +  fprintf(stderr, "%s\n", __PRETTY_FUNCTION__);
 | 
| +  context_->ServiceHadConnectionError(this);
 | 
| +  // |this| is deleted here.
 | 
| +}
 | 
| +
 | 
| +void LoaderTestServiceImpl::Transmit(mojo::ScopedDataPipeConsumerHandle pipe,
 | 
| +                                     const TransmitCallback& callback) {
 | 
| +  fprintf(stderr, "%s\n", __PRETTY_FUNCTION__);
 | 
| +  int id = ++job_id_;
 | 
| +  auto i = jobs_.insert(std::make_pair(
 | 
| +      id, scoped_ptr<Job>(new Job(id, std::move(pipe), this, callback))));
 | 
| +  i.first->second->Start();
 | 
| +}
 | 
| +
 | 
| +void LoaderTestServiceImpl::Hash(mojo::ScopedDataPipeConsumerHandle pipe,
 | 
| +                                 const HashCallback& callback) {
 | 
| +  callback.Run("hello");
 | 
| +}
 | 
| +
 | 
| +void LoaderTestServiceImpl::DeleteJob(int id) {
 | 
| +  jobs_.erase(id);
 | 
| +}
 | 
| +
 | 
| +}  // namespace content
 | 
| 
 |