This patch implements Intercept Request EWK APIs.
Reference:
1. https://review.tizen.org/gerrit/273043/
2. https://review.tizen.org/gerrit/273467/
3. https://review.tizen.org/gerrit/279298/
Change-Id: I9bee738d055289644ec3f78c1fc633bca7ed500f
Signed-off-by: Ayush Kumar <ayush.k123@samsung.com>
return bytes_read;
}
+#if BUILDFLAG(IS_EFL)
+int64_t ChunkedUploadDataStream::GetSizeSync() const {
+ // See comment in ::DumpUploadData
+ LOG(ERROR) << "Trying to get size of unsupported ChunkedUploadDataStream";
+ return -1;
+}
+
+bool ChunkedUploadDataStream::DumpUploadData(std::string& data) const {
+ // DumpUploadData was added to support ewk_intercept_request_body_get API,
+ // which can be used to extract body of intercepted request. Chunked upload
+ // data stream has specific usage outside of chromium EFL port - see
+ // SetChunkedUpload in google_one_shot_remote_engine.cc and
+ // google_streaming_remote_engine.cc.
+ // We couldn't support it in a meaningful way, unless all_data_appended_ is
+ // true when we reach ewk intercept request callback in
+ // URLRequestInterceptorEFL::MaybeInterceptRequest. Otherwise we would get
+ // partial data, or no data at all.
+ LOG(ERROR) << "Trying to dump data from unsupported ChunkedUploadDataStream";
+ return false;
+}
+#endif
+
} // namespace net
// Writers.
void AppendData(const char* data, int data_len, bool is_done);
+#if BUILDFLAG(IS_EFL)
+ int64_t GetSizeSync() const override;
+ bool DumpUploadData(std::string& data) const override;
+#endif
+
private:
// UploadDataStream implementation.
int InitInternal(const NetLogWithSource& net_log) override;
}
}
+#if BUILDFLAG(IS_EFL)
+int64_t ElementsUploadDataStream::GetSizeSync() const {
+ int64_t total_size = 0;
+ for (size_t i = 0; i < element_readers_.size(); ++i) {
+ int64_t element_size = element_readers_[i]->GetSizeSync();
+ if (element_size < 0)
+ return -1;
+ total_size += element_size;
+ }
+ return total_size;
+}
+
+bool ElementsUploadDataStream::DumpUploadData(std::string& data) const {
+ int64_t total_size = GetSizeSync();
+ if (total_size < 0)
+ return false;
+
+ data.clear();
+ data.reserve(total_size);
+ for (size_t i = 0; i < element_readers_.size(); ++i) {
+ std::string reader_data;
+ if (element_readers_[i]->DumpReaderData(reader_data)) {
+ data += reader_data;
+ } else {
+ // If read fails, we pad result with null bytes to match behavior of
+ // ::ReadElements
+ // TODO(g.ludwikowsk): should we also do this if read doesn't fail, but
+ // we get too little data? Also we already return false if GetSizeSync
+ // fails.
+ LOG(ERROR) << "Read failed, padding result with zero";
+ data += std::string(total_size - data.size(), '\0');
+ break;
+ }
+ }
+ return true;
+}
+#endif
+
} // namespace net
std::unique_ptr<UploadElementReader> reader,
int64_t identifier);
+#if BUILDFLAG(IS_EFL)
+ int64_t GetSizeSync() const override;
+ bool DumpUploadData(std::string& data) const override;
+#endif
+
private:
// UploadDataStream implementation.
bool IsInMemory() const override;
return std::make_unique<UploadOwnedBytesElementReader>(&data);
}
+#if BUILDFLAG(IS_EFL)
+int64_t UploadBytesElementReader::GetSizeSync() const {
+ if (!bytes())
+ return -1;
+ return length();
+}
+
+bool UploadBytesElementReader::DumpReaderData(std::string& data) const {
+ if (!bytes())
+ return false;
+
+ data = std::string(bytes(), bytes() + length());
+ return true;
+}
+#endif
+
} // namespace net
int buf_length,
CompletionOnceCallback callback) override;
+#if BUILDFLAG(IS_EFL)
+ int64_t GetSizeSync() const override;
+ bool DumpReaderData(std::string& data) const override;
+#endif
+
private:
const char* const bytes_;
const uint64_t length_;
return true;
}
+#if BUILDFLAG(IS_EFL)
+int64_t UploadDataStream::GetSizeSync() const {
+ LOG(ERROR) << "Trying to get size of unsupported UploadDataStream";
+ return -1;
+}
+
+bool UploadDataStream::DumpUploadData(std::string& data) const {
+ LOG(ERROR) << "Trying to dump data from unsupported UploadDataStream";
+ return false;
+}
+#endif
+
} // namespace net
// Even if this is false but there is a QUIC/H2 stream, the upload is allowed.
virtual bool AllowHTTP1() const;
+#if BUILDFLAG(IS_EFL)
+ virtual int64_t GetSizeSync() const;
+ virtual bool DumpUploadData(std::string& data) const;
+#endif
+
protected:
// Must be called by subclasses when InitInternal and ReadInternal complete
// asynchronously.
#include "net/base/upload_element_reader.h"
+#if BUILDFLAG(IS_EFL)
+#include "base/logging.h"
+#endif
+
namespace net {
const UploadBytesElementReader* UploadElementReader::AsBytesReader() const {
return false;
}
+#if BUILDFLAG(IS_EFL)
+int64_t UploadElementReader::GetSizeSync() const {
+ LOG(ERROR) << "Trying to get size of unsupported UploadElementReader";
+ return -1;
+}
+
+bool UploadElementReader::DumpReaderData(std::string& data) const {
+ LOG(ERROR) << "Trying to dump data from unsupported UploadElementReader";
+ return false;
+}
+#endif
+
} // namespace net
virtual int Read(IOBuffer* buf,
int buf_length,
CompletionOnceCallback callback) = 0;
+
+#if BUILDFLAG(IS_EFL)
+ virtual int64_t GetSizeSync() const;
+ virtual bool DumpReaderData(std::string& data) const;
+#endif
};
} // namespace net
overriding_content_length = 0;
}
+#if BUILDFLAG(IS_EFL)
+int64_t UploadFileElementReader::GetSizeSync() const {
+ int64_t file_size;
+ if (GetFileSize(path_, &file_size))
+ return file_size;
+ return -1;
+}
+
+bool UploadFileElementReader::DumpReaderData(std::string& data) const {
+ return base::ReadFileToString(path_, &data);
+}
+#endif
+
} // namespace net
int buf_length,
CompletionOnceCallback callback) override;
+#if BUILDFLAG(IS_EFL)
+ int64_t GetSizeSync() const override;
+ bool DumpReaderData(std::string& data) const override;
+#endif
+
private:
enum class State {
// No async operation is pending.
"browser/browsing_data_remover_efl.h",
"browser/download_manager_delegate_efl.cc",
"browser/download_manager_delegate_efl.h",
+ "browser/intercept_request_params.h",
"browser/javascript_dialog_manager_efl.cc",
"browser/javascript_dialog_manager_efl.h",
"browser/javascript_modal_dialog_efl.cc",
"browser/mime_override_manager_efl.h",
"browser/navigation_policy_handler_efl.cc",
"browser/navigation_policy_handler_efl.h",
+ "browser/network_service/proxying_url_loader_efl.cc",
+ "browser/network_service/proxying_url_loader_efl.h",
+ "browser/network_service/proxying_url_loader_factory_efl.cc",
+ "browser/network_service/proxying_url_loader_factory_efl.h",
"browser/policy_response_delegate_efl.cc",
"browser/policy_response_delegate_efl.h",
"browser/quota_permission_context_efl.cc",
"text_encoding_map_efl.h",
"url_request_context_getter_efl.cc",
"url_request_context_getter_efl.h",
+ "url_request_interceptor_efl.cc",
+ "url_request_interceptor_efl.h",
+ "url_request_job_efl.cc",
+ "url_request_job_efl.h",
"usermedia_permission_popup.cc",
"usermedia_permission_popup.h",
"web_contents_delegate_efl.cc",
"private/ewk_history_private.h",
"private/ewk_hit_test_private.cc",
"private/ewk_hit_test_private.h",
+ "private/ewk_intercept_request_private.cc",
+ "private/ewk_intercept_request_private.h",
"private/ewk_main_private.cc",
"private/ewk_main_private.h",
"private/ewk_manifest_private.cc",
--- /dev/null
+// Copyright 2022 Samsung Electronics. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef INTERCEPT_REQUEST_PARAMS_H_
+#define INTERCEPT_REQUEST_PARAMS_H_
+
+#include <string>
+
+#include "net/base/upload_data_stream.h"
+#include "net/http/http_request_headers.h"
+#include "url/gurl.h"
+
+struct InterceptRequestParams {
+ InterceptRequestParams() = default;
+ InterceptRequestParams(const InterceptRequestParams& params) = default;
+ ~InterceptRequestParams() = default;
+
+ GURL url;
+ std::string method = "GET";
+ net::HttpRequestHeaders headers;
+ net::UploadDataStream* upload = nullptr;
+};
+
+#endif // INTERCEPT_REQUEST_PARAMS_H_
--- /dev/null
+// Copyright 2022 Samsung Electronics. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "browser/network_service/proxying_url_loader_efl.h"
+
+#include "base/threading/sequenced_task_runner_handle.h"
+#include "content/public/browser/browser_thread.h"
+#include "mojo/public/cpp/system/simple_watcher.h"
+#include "net/base/io_buffer.h"
+#include "net/http/http_util.h"
+#include "services/network/public/cpp/features.h"
+#include "services/network/public/mojom/url_response_head.mojom.h"
+
+// static
+void ProxyingURLLoaderEfl::Create(
+ std::unique_ptr<_Ewk_Intercept_Request> intercept_request,
+ mojo::PendingReceiver<::network::mojom::URLLoader> loader,
+ mojo::PendingRemote<network::mojom::URLLoaderClient> client) {
+ auto* proxying_url_loader_efl = new ProxyingURLLoaderEfl(
+ std::move(intercept_request), std::move(loader), std::move(client));
+}
+
+ProxyingURLLoaderEfl::ProxyingURLLoaderEfl(
+ std::unique_ptr<_Ewk_Intercept_Request> intercept_request,
+ mojo::PendingReceiver<::network::mojom::URLLoader> loader,
+ mojo::PendingRemote<network::mojom::URLLoaderClient> client)
+ : intercept_request_(std::move(intercept_request)),
+ binding_(this),
+ weak_ptr_factory_(this) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+ intercept_request_->set_delegate(this);
+
+ binding_.Bind(std::move(loader));
+ binding_.set_disconnect_handler(
+ base::BindOnce(&ProxyingURLLoaderEfl::OnConnectionError,
+ weak_ptr_factory_.GetWeakPtr()));
+ client_.Bind(std::move(client));
+}
+
+void ProxyingURLLoaderEfl::ResponseDecided() {
+ mojo::ScopedDataPipeProducerHandle pipe_producer_handle;
+ mojo::ScopedDataPipeConsumerHandle pipe_consumer_handle;
+ MojoResult pipe_result = mojo::CreateDataPipe(
+ network::features::GetDataPipeDefaultAllocationSize(),
+ pipe_producer_handle, pipe_consumer_handle);
+ if (pipe_result != MOJO_RESULT_OK) {
+ Finish(net::ERR_FAILED);
+ return;
+ }
+
+ network::mojom::URLResponseHeadPtr response_head =
+ network::mojom::URLResponseHead::New();
+
+ response_head->request_start = base::TimeTicks::Now();
+ response_head->response_start = response_head->request_start;
+
+ std::string headers = intercept_request_->response_headers_take();
+ response_head->headers = base::MakeRefCounted<net::HttpResponseHeaders>(
+ net::HttpUtil::AssembleRawHeaders(headers));
+ response_head->headers->GetMimeType(&response_head->mime_type);
+
+ response_head->charset = "utf-8";
+
+ client_->OnReceiveResponse(std::move(response_head),
+ std::move(pipe_consumer_handle), absl::nullopt);
+
+ producer_handle_ = std::move(pipe_producer_handle);
+
+ producer_handle_watcher_ = std::make_unique<mojo::SimpleWatcher>(
+ FROM_HERE, mojo::SimpleWatcher::ArmingPolicy::MANUAL,
+ base::SequencedTaskRunnerHandle::Get());
+ producer_handle_watcher_->Watch(
+ producer_handle_.get(), MOJO_HANDLE_SIGNAL_WRITABLE,
+ MOJO_WATCH_CONDITION_SATISFIED,
+ base::BindRepeating(&ProxyingURLLoaderEfl::OnHandleReady,
+ weak_ptr_factory_.GetWeakPtr()));
+
+ if (!intercept_request_->is_chunked_write())
+ ReadRawData();
+}
+
+void ProxyingURLLoaderEfl::PutChunk(const char* data, size_t length) {
+ AddRawDataIntoBuffer(data, length);
+}
+
+void ProxyingURLLoaderEfl::ChunkedReadDone() {
+ read_complete_ = true;
+ // All data has already been sent, so call Finish() here.
+ if (buffers_.empty())
+ Finish(net::OK);
+}
+
+void ProxyingURLLoaderEfl::ReadRawData() {
+ std::unique_ptr<char[]> response_body =
+ intercept_request_->response_body_take();
+ // All raw data has been read.
+ read_complete_ = true;
+ AddRawDataIntoBuffer(response_body.get(),
+ intercept_request_->response_body_length_get());
+}
+
+void ProxyingURLLoaderEfl::AddRawDataIntoBuffer(const char* data,
+ size_t length) {
+ scoped_refptr<net::IOBuffer> buffer =
+ base::MakeRefCounted<net::IOBuffer>(length);
+ memcpy(buffer->data(), data, length);
+ buffers_.push(
+ base::MakeRefCounted<net::DrainableIOBuffer>(std::move(buffer), length));
+
+ SendRawData();
+}
+
+void ProxyingURLLoaderEfl::SendRawData() {
+ while (true) {
+ if (buffers_.empty()) {
+ if (read_complete_)
+ Finish(net::OK);
+ return;
+ }
+
+ net::DrainableIOBuffer* buffer = buffers_.front().get();
+ auto write_size = static_cast<uint32_t>(buffer->BytesRemaining());
+ DCHECK_GT(write_size, 0);
+
+ MojoResult result = producer_handle_->WriteData(buffer->data(), &write_size,
+ MOJO_WRITE_DATA_FLAG_NONE);
+ if (result == MOJO_RESULT_SHOULD_WAIT) {
+ producer_handle_watcher_->ArmOrNotify();
+ return;
+ }
+
+ if (result != MOJO_RESULT_OK) {
+ Finish(net::ERR_FAILED);
+ return;
+ }
+
+ buffer->DidConsume(write_size);
+ if (!buffer->BytesRemaining())
+ buffers_.pop();
+ }
+}
+
+void ProxyingURLLoaderEfl::OnHandleReady(
+ MojoResult result,
+ const mojo::HandleSignalsState& state) {
+ if (result != MOJO_RESULT_OK) {
+ Finish(net::ERR_FAILED);
+ return;
+ }
+
+ SendRawData();
+}
+
+void ProxyingURLLoaderEfl::Finish(int error) {
+ client_->OnComplete(network::URLLoaderCompletionStatus(error));
+ producer_handle_watcher_.reset();
+ producer_handle_.reset();
+ client_.reset();
+ weak_ptr_factory_.InvalidateWeakPtrs();
+ MaybeDeleteSelf();
+}
+
+void ProxyingURLLoaderEfl::OnConnectionError() {
+ binding_.reset();
+ client_.reset();
+ MaybeDeleteSelf();
+}
+
+void ProxyingURLLoaderEfl::MaybeDeleteSelf() {
+ if (!binding_.is_bound() && !client_.is_bound())
+ delete this;
+}
--- /dev/null
+// Copyright 2022 Samsung Electronics. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef PROXYING_URL_LOADER_EFL_H_
+#define PROXYING_URL_LOADER_EFL_H_
+
+#include "base/containers/queue.h"
+#include "base/memory/weak_ptr.h"
+#include "mojo/public/cpp/bindings/receiver.h"
+#include "mojo/public/cpp/bindings/remote.h"
+#include "mojo/public/cpp/system/data_pipe.h"
+#include "private/ewk_intercept_request_private.h"
+#include "services/network/public/mojom/url_loader.mojom.h"
+
+namespace mojo {
+class SimpleWatcher;
+}
+
+namespace net {
+class DrainableIOBuffer;
+}
+
+class ProxyingURLLoaderEfl : public network::mojom::URLLoader,
+ public _Ewk_Intercept_Request::Delegate {
+ public:
+ static void Create(
+ std::unique_ptr<_Ewk_Intercept_Request> intercept_request,
+ mojo::PendingReceiver<::network::mojom::URLLoader> loader,
+ mojo::PendingRemote<network::mojom::URLLoaderClient> client);
+
+ ~ProxyingURLLoaderEfl() override = default;
+
+ private:
+ // network::mojom::URLLoader:
+ void FollowRedirect(
+ const std::vector<std::string>& removed_headers,
+ const net::HttpRequestHeaders& modified_headers,
+ const net::HttpRequestHeaders& modified_cors_exempt_headers,
+ const absl::optional<GURL>& new_url) override {}
+ void SetPriority(net::RequestPriority priority,
+ int32_t intra_priority_value) override {}
+ void PauseReadingBodyFromNet() override {}
+ void ResumeReadingBodyFromNet() override {}
+
+ // _Ewk_Intercept_Request::Delegate:
+ void ResponseDecided() override;
+ void PutChunk(const char* data, size_t length) override;
+ void ChunkedReadDone() override;
+
+ ProxyingURLLoaderEfl(
+ std::unique_ptr<_Ewk_Intercept_Request> intercept_request,
+ mojo::PendingReceiver<::network::mojom::URLLoader> loader,
+ mojo::PendingRemote<network::mojom::URLLoaderClient> client);
+
+ ProxyingURLLoaderEfl(const ProxyingURLLoaderEfl&) = delete;
+ ProxyingURLLoaderEfl& operator=(const ProxyingURLLoaderEfl&) = delete;
+
+ void ReadRawData();
+ void AddRawDataIntoBuffer(const char* data, size_t length);
+ void SendRawData();
+ void OnHandleReady(MojoResult result, const mojo::HandleSignalsState& state);
+ void Finish(int error);
+ void OnConnectionError();
+ void MaybeDeleteSelf();
+
+ std::unique_ptr<_Ewk_Intercept_Request> intercept_request_;
+
+ mojo::Receiver<network::mojom::URLLoader> binding_;
+ mojo::Remote<network::mojom::URLLoaderClient> client_;
+ mojo::ScopedDataPipeProducerHandle producer_handle_;
+ std::unique_ptr<mojo::SimpleWatcher> producer_handle_watcher_;
+
+ base::queue<scoped_refptr<net::DrainableIOBuffer>> buffers_;
+ bool read_complete_ = false;
+
+ base::WeakPtrFactory<ProxyingURLLoaderEfl> weak_ptr_factory_;
+};
+
+#endif // URL_LOADER_EFL_H_
--- /dev/null
+// Copyright 2022 Samsung Electronics. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "browser/network_service/proxying_url_loader_factory_efl.h"
+
+#include "base/task/thread_pool.h"
+#include "browser/intercept_request_params.h"
+#include "browser/network_service/proxying_url_loader_efl.h"
+#include "content/public/browser/browser_thread.h"
+#include "net/base/elements_upload_data_stream.h"
+#include "net/base/upload_bytes_element_reader.h"
+#include "net/base/upload_file_element_reader.h"
+#include "private/ewk_intercept_request_private.h"
+#include "services/network/public/cpp/resource_request.h"
+
+using network::ResourceRequestBody;
+
+namespace {
+
+// A subclass of net::UploadBytesElementReader which owns
+// ResourceRequestBody.
+class BytesElementReader : public net::UploadBytesElementReader {
+ public:
+ BytesElementReader(ResourceRequestBody* resource_request_body,
+ const network::DataElementBytes& element)
+ : net::UploadBytesElementReader(element.AsStringPiece().data(),
+ element.AsStringPiece().size()),
+ resource_request_body_(resource_request_body) {}
+
+ ~BytesElementReader() override {}
+
+ BytesElementReader(const BytesElementReader&) = delete;
+ BytesElementReader& operator=(const BytesElementReader&) = delete;
+
+ private:
+ scoped_refptr<ResourceRequestBody> resource_request_body_;
+};
+
+// A subclass of net::UploadFileElementReader which owns
+// ResourceRequestBody.
+// This class is necessary to ensure the BlobData and any attached shareable
+// files survive until upload completion.
+class FileElementReader : public net::UploadFileElementReader {
+ public:
+ FileElementReader(ResourceRequestBody* resource_request_body,
+ base::TaskRunner* task_runner,
+ const network::DataElementFile& element)
+ : net::UploadFileElementReader(task_runner,
+ element.path(),
+ element.offset(),
+ element.length(),
+ element.expected_modification_time()),
+ resource_request_body_(resource_request_body) {}
+
+ ~FileElementReader() override {}
+
+ FileElementReader(const FileElementReader&) = delete;
+ FileElementReader& operator=(const FileElementReader&) = delete;
+
+ private:
+ scoped_refptr<ResourceRequestBody> resource_request_body_;
+};
+
+} // namespace
+
+// static
+void ProxyingURLLoaderFactoryEfl::CreateProxy(
+ content::BrowserContextEfl::ResourceContextEfl* resource_context,
+ mojo::PendingReceiver<network::mojom::URLLoaderFactory> loader_receiver,
+ mojo::PendingRemote<network::mojom::URLLoaderFactory>
+ target_factory_remote) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+ new ProxyingURLLoaderFactoryEfl(resource_context, std::move(loader_receiver),
+ std::move(target_factory_remote));
+}
+
+ProxyingURLLoaderFactoryEfl::ProxyingURLLoaderFactoryEfl(
+ content::BrowserContextEfl::ResourceContextEfl* resource_context,
+ mojo::PendingReceiver<network::mojom::URLLoaderFactory> loader_receiver,
+ mojo::PendingRemote<network::mojom::URLLoaderFactory> target_factory_remote)
+ : resource_context_(resource_context), weak_ptr_factory_(this) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+ if (target_factory_remote) {
+ target_factory_.Bind(std::move(target_factory_remote));
+ target_factory_.set_disconnect_handler(
+ base::BindOnce(&ProxyingURLLoaderFactoryEfl::OnTargetFactoryError,
+ base::Unretained(this)));
+ }
+
+ proxy_receivers_.Add(this, std::move(loader_receiver));
+ proxy_receivers_.set_disconnect_handler(
+ base::BindRepeating(&ProxyingURLLoaderFactoryEfl::OnProxyBindingError,
+ base::Unretained(this)));
+}
+
+ProxyingURLLoaderFactoryEfl::~ProxyingURLLoaderFactoryEfl() {}
+
+std::unique_ptr<net::UploadDataStream>
+ProxyingURLLoaderFactoryEfl::BuildUploadDataStream(
+ network::ResourceRequestBody* body,
+ base::SingleThreadTaskRunner* file_task_runner) {
+ std::vector<std::unique_ptr<net::UploadElementReader>> element_readers;
+ for (const auto& element : *body->elements()) {
+ switch (element.type()) {
+ case network::mojom::DataElementDataView::Tag::kBytes:
+ element_readers.push_back(std::make_unique<BytesElementReader>(
+ body, element.As<network::DataElementBytes>()));
+ break;
+ case network::mojom::DataElementDataView::Tag::kFile:
+ element_readers.push_back(std::make_unique<FileElementReader>(
+ body, file_task_runner, element.As<network::DataElementFile>()));
+ break;
+ default:
+ NOTREACHED();
+ break;
+ }
+ }
+
+ return std::make_unique<net::ElementsUploadDataStream>(
+ std::move(element_readers), body->identifier());
+}
+
+void ProxyingURLLoaderFactoryEfl::CreateLoaderAndStart(
+ mojo::PendingReceiver<::network::mojom::URLLoader> loader,
+ int32_t request_id,
+ uint32_t options,
+ const network::ResourceRequest& request,
+ mojo::PendingRemote<network::mojom::URLLoaderClient> client,
+ const net::MutableNetworkTrafficAnnotationTag& traffic_annotation) {
+ InterceptRequestParams params;
+ params.url = request.url;
+ params.method = request.method;
+ params.headers = request.headers;
+
+ std::unique_ptr<net::UploadDataStream> upload_data_stream;
+ if (request.request_body.get()) {
+ upload_data_stream = BuildUploadDataStream(
+ request.request_body.get(),
+ base::ThreadPool::CreateSingleThreadTaskRunner(
+ {base::MayBlock(), base::TaskPriority::USER_VISIBLE})
+ .get());
+ params.upload = upload_data_stream.get();
+ }
+
+ auto intercept_request = std::make_unique<_Ewk_Intercept_Request>(params);
+ resource_context_->RunInterceptRequestCallback(intercept_request.get());
+ intercept_request->callback_ended();
+ if (intercept_request->is_ignored()) {
+ target_factory_->CreateLoaderAndStart(std::move(loader), request_id,
+ options, request, std::move(client),
+ traffic_annotation);
+ return;
+ }
+
+ ProxyingURLLoaderEfl::Create(std::move(intercept_request), std::move(loader),
+ std::move(client));
+}
+
+void ProxyingURLLoaderFactoryEfl::Clone(
+ mojo::PendingReceiver<network::mojom::URLLoaderFactory> loader_receiver) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+ proxy_receivers_.Add(this, std::move(loader_receiver));
+}
+
+void ProxyingURLLoaderFactoryEfl::OnTargetFactoryError() {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+ delete this;
+}
+
+void ProxyingURLLoaderFactoryEfl::OnProxyBindingError() {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+ if (proxy_receivers_.empty())
+ delete this;
+}
--- /dev/null
+// Copyright 2022 Samsung Electronics. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef PROXYING_URL_LOADER_FACTORY_EFL_H_
+#define PROXYING_URL_LOADER_FACTORY_EFL_H_
+
+#include "base/memory/weak_ptr.h"
+#include "browser_context_efl.h"
+#include "mojo/public/cpp/bindings/receiver_set.h"
+#include "mojo/public/cpp/bindings/remote.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
+#include "services/network/public/mojom/url_loader_factory.mojom.h"
+
+namespace content {
+class ResourceContext;
+}
+
+class ProxyingURLLoaderFactoryEfl : public network::mojom::URLLoaderFactory {
+ public:
+ static void CreateProxy(
+ content::BrowserContextEfl::ResourceContextEfl* resource_context,
+ mojo::PendingReceiver<network::mojom::URLLoaderFactory> loader_receiver,
+ mojo::PendingRemote<network::mojom::URLLoaderFactory>
+ target_factory_remote);
+
+ ~ProxyingURLLoaderFactoryEfl() override;
+
+ private:
+ // network::mojom::URLLoaderFactory
+ void CreateLoaderAndStart(
+ mojo::PendingReceiver<::network::mojom::URLLoader> loader,
+ int32_t request_id,
+ uint32_t options,
+ const network::ResourceRequest& request,
+ mojo::PendingRemote<network::mojom::URLLoaderClient> client,
+ const net::MutableNetworkTrafficAnnotationTag& traffic_annotation)
+ override;
+ void Clone(mojo::PendingReceiver<network::mojom::URLLoaderFactory>
+ loader_receiver) override;
+
+ ProxyingURLLoaderFactoryEfl(
+ content::BrowserContextEfl::ResourceContextEfl* resource_context,
+ mojo::PendingReceiver<network::mojom::URLLoaderFactory> loader_receiver,
+ mojo::PendingRemote<network::mojom::URLLoaderFactory>
+ target_factory_remote);
+
+ ProxyingURLLoaderFactoryEfl(const ProxyingURLLoaderFactoryEfl&) = delete;
+ ProxyingURLLoaderFactoryEfl& operator=(const ProxyingURLLoaderFactoryEfl&) =
+ delete;
+
+ void OnTargetFactoryError();
+ void OnProxyBindingError();
+ std::unique_ptr<net::UploadDataStream> BuildUploadDataStream(
+ network::ResourceRequestBody* body,
+ base::SingleThreadTaskRunner* file_task_runner);
+
+ content::BrowserContextEfl::ResourceContextEfl* resource_context_;
+
+ mojo::ReceiverSet<network::mojom::URLLoaderFactory> proxy_receivers_;
+ mojo::Remote<network::mojom::URLLoaderFactory> target_factory_;
+
+ base::WeakPtrFactory<ProxyingURLLoaderFactoryEfl> weak_ptr_factory_;
+};
+
+#endif // PROXYING_URL_LOADER_FACTORY_EFL_H_
BrowserContextEfl::ResourceContextEfl::ResourceContextEfl(
scoped_refptr<CookieManager> cookie_manager)
- : cookie_manager_(cookie_manager) {}
+ : cookie_manager_(cookie_manager),
+ intercept_request_callback_{nullptr, nullptr, nullptr} {}
BrowserContextEfl::~BrowserContextEfl() {
NotifyWillBeDestroyed();
return http_custom_headers_;
}
+void BrowserContextEfl::ResourceContextEfl::SetInterceptRequestCallback(
+ Ewk_Context* ewk_context,
+ Ewk_Context_Intercept_Request_Callback callback,
+ void* user_data) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ base::AutoLock locker(intercept_request_callback_lock_);
+ intercept_request_callback_ = {ewk_context, callback, user_data};
+}
+
+bool BrowserContextEfl::ResourceContextEfl::HasInterceptRequestCallback()
+ const {
+ base::AutoLock locker(intercept_request_callback_lock_);
+ return !!intercept_request_callback_.callback;
+}
+
+void BrowserContextEfl::ResourceContextEfl::RunInterceptRequestCallback(
+ _Ewk_Intercept_Request* intercept_request) const {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ base::AutoLock locker(intercept_request_callback_lock_);
+ if (intercept_request_callback_.callback)
+ intercept_request_callback_.Run(intercept_request);
+}
+
scoped_refptr<CookieManager>
BrowserContextEfl::ResourceContextEfl::GetCookieManager() const {
return cookie_manager_;
scoped_refptr<CookieManager> GetCookieManager() const;
+ void SetInterceptRequestCallback(
+ Ewk_Context* ewk_context,
+ Ewk_Context_Intercept_Request_Callback callback,
+ void* user_data);
+ bool HasInterceptRequestCallback() const;
+ void RunInterceptRequestCallback(
+ _Ewk_Intercept_Request* intercept_request) const;
+
private:
+ struct InterceptRequestCallbackWithData {
+ Ewk_Context* context;
+ Ewk_Context_Intercept_Request_Callback callback;
+ void* user_data;
+
+ void Run(_Ewk_Intercept_Request* intercept_request) const {
+ callback(context, intercept_request, user_data);
+ }
+ };
+
scoped_refptr<CookieManager> cookie_manager_;
HTTPCustomHeadersEflMap http_custom_headers_;
mutable base::Lock http_custom_headers_lock_;
+
+ InterceptRequestCallbackWithData intercept_request_callback_;
+ mutable base::Lock intercept_request_callback_lock_;
};
BrowserContextEfl(EWebContext*, bool incognito = false);
#include "base/callback.h"
#include "base/strings/string_number_conversions.h"
#include "browser/editor_client_observer.h"
+#include "browser/network_service/proxying_url_loader_factory_efl.h"
#include "browser/notification/notification_controller_efl.h"
#include "browser/quota_permission_context_efl.h"
#include "browser/render_message_filter_efl.h"
return nullptr;
}
+bool ContentBrowserClientEfl::WillCreateURLLoaderFactory(
+ content::BrowserContext* browser_context,
+ content::RenderFrameHost* frame,
+ int render_process_id,
+ URLLoaderFactoryType type,
+ const url::Origin& request_initiator,
+ absl::optional<int64_t> navigation_id,
+ ukm::SourceIdObj ukm_source_id,
+ mojo::PendingReceiver<network::mojom::URLLoaderFactory>* factory_receiver,
+ mojo::PendingRemote<network::mojom::TrustedURLLoaderHeaderClient>*
+ header_client,
+ bool* bypass_redirect_checks,
+ bool* disable_secure_dns,
+ network::mojom::URLLoaderFactoryOverridePtr* factory_override) {
+ auto* resource_context_efl =
+ static_cast<content::BrowserContextEfl*>(browser_context)
+ ->GetResourceContextEfl();
+ if (!resource_context_efl->HasInterceptRequestCallback())
+ return false;
+
+ auto proxied_receiver = std::move(*factory_receiver);
+ mojo::PendingRemote<network::mojom::URLLoaderFactory> target_factory_remote;
+ *factory_receiver = target_factory_remote.InitWithNewPipeAndPassReceiver();
+ GetIOThreadTaskRunner({})->PostTask(
+ FROM_HERE,
+ base::BindOnce(&ProxyingURLLoaderFactoryEfl::CreateProxy,
+ resource_context_efl, std::move(proxied_receiver),
+ std::move(target_factory_remote)));
+ return true;
+}
+
} // namespace content
void RemoveAcceptLangsChangedCallback(AcceptLangsChangedCallback callback);
private:
+ bool WillCreateURLLoaderFactory(
+ BrowserContext* browser_context,
+ RenderFrameHost* frame,
+ int render_process_id,
+ URLLoaderFactoryType type,
+ const url::Origin& request_initiator,
+ absl::optional<int64_t> navigation_id,
+ ukm::SourceIdObj ukm_source_id,
+ mojo::PendingReceiver<network::mojom::URLLoaderFactory>* factory_receiver,
+ mojo::PendingRemote<network::mojom::TrustedURLLoaderHeaderClient>*
+ header_client,
+ bool* bypass_redirect_checks,
+ bool* disable_secure_dns,
+ network::mojom::URLLoaderFactoryOverridePtr* factory_override) override;
+
scoped_refptr<network::SharedURLLoaderFactory>
GetSystemSharedURLLoaderFactory() override;
bool EWebContext::GetExtensibleAPI(const std::string& api_name) {
return TizenExtensibleHost::GetInstance()->GetExtensibleAPI(api_name);
}
+
+void EWebContext::SetInterceptRequestCallback(
+ Ewk_Context* ewk_context,
+ Ewk_Context_Intercept_Request_Callback callback,
+ void* user_data) {
+ BrowserContextEfl::ResourceContextEfl* resource_context_efl =
+ browser_context_->GetResourceContextEfl();
+ if (!resource_context_efl) {
+ LOG(ERROR) << "Unable to get ResourceContextEfl.";
+ return;
+ }
+ resource_context_efl->SetInterceptRequestCallback(ewk_context, callback,
+ user_data);
+}
bool SetExtensibleAPI(const std::string& api_name, bool enable);
bool GetExtensibleAPI(const std::string& api_name);
+ void SetInterceptRequestCallback(
+ Ewk_Context* ewk_context,
+ Ewk_Context_Intercept_Request_Callback callback,
+ void* user_data);
+
private:
EWebContext(bool incognito);
EWebContext(const std::string& injectedBundlePath);
NetworkDelegateEfl::NetworkDelegateEfl(
base::WeakPtr<CookieManager> cookie_manager)
- : cookie_manager_(cookie_manager) {}
+ : intercept_request_callback_with_data_{nullptr, nullptr, nullptr},
+ cookie_manager_(cookie_manager) {}
#if !defined(EWK_BRINGUP) // FIXME: m85 bringup
NetworkDelegate::AuthRequiredResponse NetworkDelegateEfl::OnAuthRequired(
const base::FilePath& absolute_path) const {
return true;
}
+void NetworkDelegateEfl::SetInterceptRequestCallback(
+ Ewk_Context* ewk_context,
+ Ewk_Context_Intercept_Request_Callback callback,
+ void* user_data) {
+ intercept_request_callback_with_data_ = {ewk_context, callback, user_data};
+}
+
+bool NetworkDelegateEfl::HasInterceptRequestCallback() const {
+ return !!intercept_request_callback_with_data_.callback;
+}
+
+void NetworkDelegateEfl::RunInterceptRequestCallback(
+ _Ewk_Intercept_Request* intercept_request) const {
+ if (intercept_request && intercept_request_callback_with_data_.callback)
+ intercept_request_callback_with_data_.Run(intercept_request);
+}
}; // namespace net
#define _NETWORK_DELEGATE_EFL_H_
#include "base/compiler_specific.h"
-#include "net/base/network_delegate_impl.h"
#include "cookie_manager.h"
+#include "net/base/network_delegate_impl.h"
+#include "public/ewk_context.h"
namespace net {
public:
NetworkDelegateEfl(base::WeakPtr<CookieManager> cookie_manager);
+ NetworkDelegateEfl(const NetworkDelegateEfl&) = delete;
+ NetworkDelegateEfl& operator=(const NetworkDelegateEfl&) = delete;
+
+ void SetInterceptRequestCallback(
+ Ewk_Context* ewk_context,
+ Ewk_Context_Intercept_Request_Callback callback,
+ void* user_data);
+ bool HasInterceptRequestCallback() const;
+ void RunInterceptRequestCallback(
+ _Ewk_Intercept_Request* intercept_request) const;
+
private:
// NetworkDelegate implementation.
#if !defined(EWK_BRINGUP) // FIXME: m85 bringup
const base::FilePath& original_path,
const base::FilePath& absolute_path) const;
+ struct InterceptRequestCallbackWithData {
+ Ewk_Context* context;
+ Ewk_Context_Intercept_Request_Callback callback;
+ void* user_data;
+
+ void Run(_Ewk_Intercept_Request* intercept_request) const {
+ callback(context, intercept_request, user_data);
+ }
+ };
+
+ InterceptRequestCallbackWithData intercept_request_callback_with_data_;
+
base::WeakPtr<CookieManager> cookie_manager_;
};
impl->SetNotificationCallbacks(
this, show_callback, cancel_callback, user_data);
}
+
+void Ewk_Context::SetContextInterceptRequestCallback(
+ Ewk_Context_Intercept_Request_Callback callback,
+ void* user_data) {
+ impl->SetInterceptRequestCallback(this, callback, user_data);
+}
Ewk_Context_Notification_Cancel_Callback cancel_callback,
void* user_data);
+ void SetContextInterceptRequestCallback(
+ Ewk_Context_Intercept_Request_Callback callback,
+ void* user_data);
+
private:
EWebContext* impl;
--- /dev/null
+// Copyright 2016 Samsung Electronics. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ewk_intercept_request_private.h"
+
+#include <cstring>
+
+#include "base/bind.h"
+#include "base/strings/string_number_conversions.h"
+#include "browser/intercept_request_params.h"
+#include "content/public/browser/browser_task_traits.h"
+#include "content/public/browser/browser_thread.h"
+#include "net/base/upload_data_stream.h"
+#include "net/http/http_request_headers.h"
+#include "net/http/http_status_code.h"
+
+using content::BrowserThread;
+
+namespace {
+void _headers_entry_free_cb(void* data) {
+ free(data);
+}
+} // namespace
+
+_Ewk_Intercept_Request::_Ewk_Intercept_Request(
+ const InterceptRequestParams& params)
+ // API user might want to receive even invalid urls
+ : delegate_(nullptr),
+ request_scheme_(params.url.scheme()),
+ request_url_(params.url.possibly_invalid_spec()),
+ request_http_method_(params.method),
+ request_upload_(params.upload),
+ request_body_length_(-1),
+ response_body_length_(0),
+ response_status_code_(-1),
+ ignored_(false),
+ chunked_write_(false) {
+ request_headers_ = eina_hash_string_small_new(_headers_entry_free_cb);
+ net::HttpRequestHeaders::Iterator current_header(params.headers);
+ while (current_header.GetNext()) {
+ if (!eina_hash_add(request_headers_, current_header.name().c_str(),
+ strdup(current_header.value().c_str()))) {
+ LOG(ERROR) << "Failed to add header to Eina_Hash";
+ }
+ }
+}
+
+_Ewk_Intercept_Request::~_Ewk_Intercept_Request() {
+ eina_hash_free(request_headers_);
+}
+
+Eina_Bool _Ewk_Intercept_Request::response_status_set(
+ int status_code,
+ const char* custom_status_text) {
+ response_status_code_ = status_code;
+ if (custom_status_text) {
+ response_status_text_ = custom_status_text;
+ } else {
+ response_status_text_ =
+ net::GetHttpReasonPhrase(net::HttpStatusCode(status_code));
+ }
+ return EINA_TRUE;
+}
+
+Eina_Bool _Ewk_Intercept_Request::response_header_add(const char* field_name,
+ const char* field_value) {
+ response_headers_map_.push_back(
+ std::pair<std::string, std::string>(field_name, field_value));
+ return EINA_TRUE;
+}
+
+Eina_Bool _Ewk_Intercept_Request::response_header_map_add(
+ const Eina_Hash* headers) {
+ Eina_Iterator* it = eina_hash_iterator_tuple_new(headers);
+ if (!it)
+ return EINA_FALSE;
+ void* data;
+ while (eina_iterator_next(it, &data)) {
+ Eina_Hash_Tuple* tuple = static_cast<Eina_Hash_Tuple*>(data);
+ std::string field_name = static_cast<const char*>(tuple->key);
+ std::string field_value = static_cast<const char*>(tuple->data);
+ response_headers_map_.push_back(std::pair<std::string, std::string>(
+ std::move(field_name), std::move(field_value)));
+ }
+ eina_iterator_free(it);
+ return EINA_TRUE;
+}
+
+void _Ewk_Intercept_Request::headers_generate() {
+ response_headers_.append("HTTP/1.1 ");
+ response_headers_.append(base::NumberToString(response_status_code_));
+ response_headers_.append(" ");
+ response_headers_.append(response_status_text_);
+ response_headers_.append("\r\n");
+ for (const auto& header : response_headers_map_) {
+ response_headers_.append(header.first);
+ response_headers_.append(": ");
+ response_headers_.append(header.second);
+ response_headers_.append("\r\n");
+ }
+ response_headers_.append("\r\n");
+}
+
+Eina_Bool _Ewk_Intercept_Request::response_body_set(const void* data,
+ size_t length) {
+ headers_generate();
+ set_data(data, length);
+ post_response_decided();
+ return EINA_TRUE;
+}
+
+Eina_Bool _Ewk_Intercept_Request::response_set(const char* headers,
+ const void* data,
+ size_t length) {
+ response_headers_ = headers;
+ set_data(data, length);
+ post_response_decided();
+ return EINA_TRUE;
+}
+
+void _Ewk_Intercept_Request::set_data(const void* data, size_t length) {
+ response_body_.reset(new char[length]);
+ memcpy(response_body_.get(), data, length);
+ response_body_length_ = length;
+}
+
+Eina_Bool _Ewk_Intercept_Request::request_ignore() {
+ ignored_ = true;
+ return EINA_TRUE;
+}
+
+Eina_Bool _Ewk_Intercept_Request::response_write_chunk(const void* data,
+ size_t length) {
+ // On first chunked write generate headers and signal job.
+ if (!chunked_write_) {
+ chunked_write_ = true;
+ headers_generate();
+ post_response_decided();
+ }
+
+ // Zero length data means end of response body. Also there is possibility of
+ // early finish if engine doesn't want response to the request anymore.
+ if (length == 0 || chunked_write_early_exit_.IsSet()) {
+ post_chunked_read_done();
+ return EINA_FALSE;
+ }
+
+ char* data_copy = new char[length];
+ memcpy(data_copy, data, length);
+ post_put_chunk(data_copy, length);
+ return EINA_TRUE;
+}
+
+void _Ewk_Intercept_Request::response_decided() {
+ if (delegate_)
+ delegate_->ResponseDecided();
+}
+
+void _Ewk_Intercept_Request::post_response_decided() {
+ content::GetIOThreadTaskRunner({})->PostTask(
+ FROM_HERE, base::BindRepeating(&_Ewk_Intercept_Request::response_decided,
+ base::Unretained(this)));
+}
+
+void _Ewk_Intercept_Request::put_chunk(const char* data, size_t length) {
+ if (delegate_)
+ delegate_->PutChunk(data, length);
+}
+
+void _Ewk_Intercept_Request::post_put_chunk(const char* data, size_t length) {
+ content::GetIOThreadTaskRunner({})->PostTask(
+ FROM_HERE, base::BindRepeating(&_Ewk_Intercept_Request::put_chunk,
+ base::Unretained(this), data, length));
+}
+
+void _Ewk_Intercept_Request::chunked_read_done() {
+ if (delegate_)
+ delegate_->ChunkedReadDone();
+}
+
+void _Ewk_Intercept_Request::post_chunked_read_done() {
+ content::GetIOThreadTaskRunner({})->PostTask(
+ FROM_HERE, base::BindRepeating(&_Ewk_Intercept_Request::chunked_read_done,
+ base::Unretained(this)));
+}
+
+const char* _Ewk_Intercept_Request::request_body_get() const {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ if (!request_body_.empty())
+ return request_body_.data();
+
+ if (!request_upload_) {
+ LOG(ERROR) << "Trying to get request body outside of "
+ "Ewk_Context_Intercept_Request_Callback";
+ return nullptr;
+ }
+
+ std::string http_body;
+ if (!request_upload_->DumpUploadData(http_body))
+ return nullptr;
+
+ request_body_ = http_body;
+ return request_body_.data();
+}
+
+int64_t _Ewk_Intercept_Request::request_body_length_get() const {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ if (request_body_length_ >= 0)
+ return request_body_length_;
+
+ if (!request_upload_) {
+ LOG(ERROR) << "Trying to get request body length outside of "
+ "Ewk_Context_Intercept_Request_Callback";
+ return -1;
+ }
+
+ request_body_length_ = request_upload_->GetSizeSync();
+ return request_body_length_;
+}
--- /dev/null
+// Copyright 2016 Samsung Electronics. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef EWK_EFL_INTEGRATION_PRIVATE_EWK_INTERCEPT_REQUEST_PRIVATE_H_
+#define EWK_EFL_INTEGRATION_PRIVATE_EWK_INTERCEPT_REQUEST_PRIVATE_H_
+
+#include <cstddef>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <Eina.h>
+
+#include "base/synchronization/atomic_flag.h"
+
+namespace net {
+class UploadDataStream;
+}
+
+struct InterceptRequestParams;
+
+struct _Ewk_Intercept_Request {
+ public:
+ class Delegate {
+ public:
+ virtual void ResponseDecided() = 0;
+
+ virtual void PutChunk(const char* data, size_t length) = 0;
+
+ virtual void ChunkedReadDone() = 0;
+
+ protected:
+ virtual ~Delegate() {}
+ };
+
+ explicit _Ewk_Intercept_Request(const InterceptRequestParams& params);
+ ~_Ewk_Intercept_Request();
+
+ // functions so user can use EWK API to get info about intercepted request
+ // to make a decision
+ const char* request_scheme_get() const { return request_scheme_.c_str(); }
+ const char* request_url_get() const { return request_url_.c_str(); }
+ const char* request_http_method_get() const {
+ return request_http_method_.c_str();
+ }
+ const Eina_Hash* request_headers_get() const { return request_headers_; }
+ const char* request_body_get() const;
+ int64_t request_body_length_get() const;
+
+ // functions so user can use EWK API to write response for intercepted
+ // request
+ Eina_Bool response_set(const char* headers, const void* data, size_t length);
+ Eina_Bool request_ignore();
+ Eina_Bool response_status_set(int status_code,
+ const char* custom_status_text);
+ Eina_Bool response_header_add(const char* field_name,
+ const char* field_value);
+ Eina_Bool response_header_map_add(const Eina_Hash* headers);
+ Eina_Bool response_body_set(const void* data, size_t length);
+ Eina_Bool response_write_chunk(const void* data, size_t length);
+
+ // functions so URLRequestJobEFL can get info about headers and body of
+ // custom response
+ std::string&& response_headers_take() { return std::move(response_headers_); }
+ std::unique_ptr<char[]> response_body_take() {
+ return std::move(response_body_);
+ }
+ size_t response_body_length_get() const { return response_body_length_; }
+ bool is_ignored() const { return ignored_; }
+ bool is_chunked_write() const { return chunked_write_; }
+ void request_early_exit() { chunked_write_early_exit_.Set(); }
+ void set_delegate(Delegate* delegate) { delegate_ = delegate; }
+ void callback_ended() { request_upload_ = nullptr; }
+
+ private:
+ void set_data(const void* data, size_t length);
+ void headers_generate();
+ void response_decided();
+ void post_response_decided();
+ void put_chunk(const char* data, size_t length);
+ void post_put_chunk(const char* data, size_t length);
+ void chunked_read_done();
+ void post_chunked_read_done();
+
+ Delegate* delegate_;
+
+ std::string request_scheme_;
+ std::string request_url_;
+ std::string request_http_method_;
+ Eina_Hash* request_headers_;
+
+ // request_upload_ is valid only during the callback. It is saved to allow
+ // retrieving request body. We don't save request's body every time in
+ // constructor (like other data), because data uploaded in request body may
+ // have excessive size.
+ net::UploadDataStream* request_upload_;
+
+ // mutable because request_body_ is lazily loaded in its const getter
+ mutable std::string request_body_;
+ // mutable because request_body_size_ is lazily loaded in its const getter
+ mutable int64_t request_body_length_;
+
+ std::string response_headers_;
+ std::unique_ptr<char[]> response_body_;
+ size_t response_body_length_;
+ int response_status_code_;
+ std::string response_status_text_;
+ std::vector<std::pair<std::string, std::string>> response_headers_map_;
+
+ bool ignored_;
+ bool chunked_write_;
+ base::AtomicFlag chunked_write_early_exit_;
+};
+
+#endif // EWK_EFL_INTEGRATION_PRIVATE_EWK_INTERCEPT_REQUEST_PRIVATE_H_
return EINA_TRUE;
}
+void ewk_context_intercept_request_callback_set(
+ Ewk_Context* context,
+ Ewk_Context_Intercept_Request_Callback callback,
+ void* user_data) {
+ EINA_SAFETY_ON_NULL_RETURN(context);
+ context->SetContextInterceptRequestCallback(callback, user_data);
+}
+
void ewk_context_compression_proxy_enabled_set(Ewk_Context* context, Eina_Bool enabled)
{
LOG_EWK_API_MOCKUP();
#include "ewk_intercept_request_internal.h"
+#include "private/ewk_intercept_request_private.h"
#include "private/ewk_private.h"
+const char* ewk_intercept_request_url_get(
+ Ewk_Intercept_Request* intercept_request) {
+ EINA_SAFETY_ON_NULL_RETURN_VAL(intercept_request, NULL);
+ return intercept_request->request_url_get();
+}
+
+const char* ewk_intercept_request_http_method_get(
+ Ewk_Intercept_Request* intercept_request) {
+ EINA_SAFETY_ON_NULL_RETURN_VAL(intercept_request, NULL);
+ return intercept_request->request_http_method_get();
+}
+
+const Eina_Hash* ewk_intercept_request_headers_get(
+ Ewk_Intercept_Request* intercept_request) {
+ EINA_SAFETY_ON_NULL_RETURN_VAL(intercept_request, NULL);
+ return intercept_request->request_headers_get();
+}
-Eina_Bool ewk_intercept_request_ignore(Ewk_Intercept_Request* interceptRequest)
-{
- LOG_EWK_API_MOCKUP();
- return true;
+Eina_Bool ewk_intercept_request_ignore(
+ Ewk_Intercept_Request* intercept_request) {
+ EINA_SAFETY_ON_NULL_RETURN_VAL(intercept_request, EINA_FALSE);
+ return intercept_request->request_ignore();
}
-const char* ewk_intercept_request_url_get(Ewk_Intercept_Request* interceptRequest)
-{
- LOG_EWK_API_MOCKUP();
- return NULL;
+Eina_Bool ewk_intercept_request_response_set(
+ Ewk_Intercept_Request* intercept_request,
+ const char* headers,
+ const char* body,
+ size_t length) {
+ EINA_SAFETY_ON_NULL_RETURN_VAL(intercept_request, EINA_FALSE);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(headers, EINA_FALSE);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(body, EINA_FALSE);
+ return intercept_request->response_set(headers, body, length);
}
-const char* ewk_intercept_request_http_method_get(Ewk_Intercept_Request* interceptRequest)
-{
- LOG_EWK_API_MOCKUP();
- return NULL;
+Eina_Bool ewk_intercept_request_response_status_set(
+ Ewk_Intercept_Request* intercept_request,
+ int status_code,
+ const char* custom_status_text) {
+ EINA_SAFETY_ON_NULL_RETURN_VAL(intercept_request, EINA_FALSE);
+ return intercept_request->response_status_set(status_code,
+ custom_status_text);
}
-const Eina_Hash* ewk_intercept_request_headers_get(Ewk_Intercept_Request* interceptRequest)
-{
- LOG_EWK_API_MOCKUP();
- return NULL;
+Eina_Bool ewk_intercept_request_response_header_add(
+ Ewk_Intercept_Request* intercept_request,
+ const char* field_name,
+ const char* field_value) {
+ EINA_SAFETY_ON_NULL_RETURN_VAL(intercept_request, EINA_FALSE);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(field_name, EINA_FALSE);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(field_value, EINA_FALSE);
+ return intercept_request->response_header_add(field_name, field_value);
}
-Eina_Bool ewk_intercept_request_response_set(Ewk_Intercept_Request* interceptRequest, const char* headers, const char* body, int length)
-{
- LOG_EWK_API_MOCKUP();
- return false;
+Eina_Bool ewk_intercept_request_response_header_map_add(
+ Ewk_Intercept_Request* intercept_request,
+ const Eina_Hash* headers) {
+ EINA_SAFETY_ON_NULL_RETURN_VAL(intercept_request, EINA_FALSE);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(headers, EINA_FALSE);
+ return intercept_request->response_header_map_add(headers);
}
-const char* ewk_intercept_request_scheme_get(Ewk_Intercept_Request* intercept_request)
-{
- LOG_EWK_API_MOCKUP();
- return NULL;
+Eina_Bool ewk_intercept_request_response_body_set(
+ Ewk_Intercept_Request* intercept_request,
+ const char* body,
+ size_t length) {
+ EINA_SAFETY_ON_NULL_RETURN_VAL(intercept_request, EINA_FALSE);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(body, EINA_FALSE);
+ return intercept_request->response_body_set(body, length);
}
-const char* ewk_intercept_request_body_get(Ewk_Intercept_Request* intercept_request)
-{
- LOG_EWK_API_MOCKUP();
- return NULL;
+Eina_Bool ewk_intercept_request_response_write_chunk(
+ Ewk_Intercept_Request* intercept_request,
+ const char* chunk,
+ size_t length) {
+ EINA_SAFETY_ON_NULL_RETURN_VAL(intercept_request, EINA_FALSE);
+ // (chunk == NULL && length == 0) means to end of data, handled inside
+ // |response_write_chunk|.
+ if (chunk != NULL || length != 0) {
+ EINA_SAFETY_ON_NULL_RETURN_VAL(chunk, EINA_FALSE);
+ EINA_SAFETY_ON_TRUE_RETURN_VAL(length == 0, EINA_FALSE);
+ }
+ return intercept_request->response_write_chunk(chunk, length);
}
-int64_t ewk_intercept_request_body_length_get(Ewk_Intercept_Request* intercept_request)
-{
- LOG_EWK_API_MOCKUP();
- return -1;
+
+const char* ewk_intercept_request_scheme_get(
+ Ewk_Intercept_Request* intercept_request) {
+ EINA_SAFETY_ON_NULL_RETURN_VAL(intercept_request, NULL);
+ return intercept_request->request_scheme_get();
+}
+
+const char* ewk_intercept_request_body_get(
+ Ewk_Intercept_Request* intercept_request) {
+ EINA_SAFETY_ON_NULL_RETURN_VAL(intercept_request, NULL);
+ return intercept_request->request_body_get();
+}
+
+int64_t ewk_intercept_request_body_length_get(
+ Ewk_Intercept_Request* intercept_request) {
+ EINA_SAFETY_ON_NULL_RETURN_VAL(intercept_request, -1);
+ return intercept_request->request_body_length_get();
}
#include "net/url_request/url_request_job_factory.h"
#include "network_delegate_efl.h"
#include "services/network/public/cpp/network_switches.h"
+#include "url_request_interceptor_efl.h"
#include "wrt/wrt_file_protocol_handler.h"
using net::SQLitePersistentCookieStore;
base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN})
.get())));
DCHECK(set_protocol);
+#endif
// Set up interceptors in the reverse order.
std::unique_ptr<net::URLRequestJobFactory> top_job_factory =
std::move(job_factory);
- for (URLRequestInterceptorScopedVector::reverse_iterator i =
- request_interceptors_.rbegin();
- i != request_interceptors_.rend(); ++i) {
- top_job_factory.reset(new net::URLRequestInterceptingJobFactory(
- std::move(top_job_factory), std::move(*i)));
- }
+ request_interceptors_.push_back(
+ base::WrapUnique(new URLRequestInterceptorEFL()));
+
request_interceptors_.clear();
-#endif
- storage_->set_job_factory(std::move(job_factory));
+ storage_->set_job_factory(std::move(top_job_factory));
#else
net::URLRequestContextBuilder builder;
url_request_context_ = builder.Build();
#endif
}
+void URLRequestContextGetterEfl::SetInterceptRequestCallback(
+ Ewk_Context* ewk_context,
+ Ewk_Context_Intercept_Request_Callback callback,
+ void* user_data) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+
+ if (network_delegate_.get()) {
+ (static_cast<net::NetworkDelegateEfl*>(network_delegate_.get()))
+ ->SetInterceptRequestCallback(ewk_context, callback, user_data);
+ }
+}
+
}; // namespace content
#include "net/http/http_network_session.h"
#include "net/proxy_resolution/proxy_config_service.h"
#include "net/url_request/url_request_context_getter.h"
+#include "net/url_request/url_request_interceptor.h"
+#include "public/ewk_context.h"
#include "public/ewk_cookie_manager_internal.h"
namespace net {
void NotifyContextShuttingDown();
+ void SetInterceptRequestCallback(
+ Ewk_Context* ewk_context,
+ Ewk_Context_Intercept_Request_Callback callback,
+ void* user_data);
+
protected:
virtual ~URLRequestContextGetterEfl();
std::unique_ptr<net::NetworkDelegate> network_delegate_;
std::unique_ptr<net::CertVerifier> cert_verifier_;
std::unique_ptr<net::URLRequestContext> url_request_context_;
+ std::vector<std::unique_ptr<net::URLRequestInterceptor>>
+ request_interceptors_;
base::WeakPtrFactory<URLRequestContextGetterEfl> weak_ptr_factory_;
};
--- /dev/null
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2016 Samsung Electronics. 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_request_interceptor_efl.h"
+
+#include "base/supports_user_data.h"
+#include "browser/intercept_request_params.h"
+#include "content/public/browser/browser_thread.h"
+#include "net/http/http_request_headers.h"
+#include "net/url_request/url_request_job.h"
+#include "network_delegate_efl.h"
+#include "private/ewk_intercept_request_private.h"
+#include "url/gurl.h"
+#include "url_request_job_efl.h"
+
+class WebContents;
+
+namespace content {
+
+namespace {
+
+const void* const kRequestAlreadyHasJobDataKey = &kRequestAlreadyHasJobDataKey;
+
+} // namespace
+
+URLRequestInterceptorEFL::URLRequestInterceptorEFL() {}
+
+URLRequestInterceptorEFL::~URLRequestInterceptorEFL() {}
+
+std::unique_ptr<net::URLRequestJob>
+URLRequestInterceptorEFL::MaybeInterceptRequest(
+ net::URLRequest* request) const {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ // MaybeInterceptRequest can be called multiple times for the same request.
+ if (request->GetUserData(kRequestAlreadyHasJobDataKey))
+ return nullptr;
+
+ auto network_delegate_efl =
+ static_cast<net::NetworkDelegateEfl*>(request->network_delegate());
+
+ if (!network_delegate_efl->HasInterceptRequestCallback())
+ return nullptr;
+
+ InterceptRequestParams params;
+ params.url = request->url();
+ // Code for getting request headers ported from android webview impl, see
+ // android_webview/native/aw_contents_io_thread_client_impl.cc.
+ // Headers for http requests we get here will not be the same as headers
+ // which would be sent if request have been executed normally.
+ //
+ // Getting the same http headers would require creating URLRequestHttpJob,
+ // which fills http headers. See HttpNetworkTransaction::BuildRequestHeaders
+ // in net/http/http_network_transaction.cc.
+ params.method = request->method();
+ params.headers = request->extra_request_headers();
+ params.upload =
+ const_cast<net::UploadDataStream*>(request->get_upload_for_testing());
+
+ auto intercept_request = new _Ewk_Intercept_Request(params);
+ network_delegate_efl->RunInterceptRequestCallback(intercept_request);
+ intercept_request->callback_ended();
+ if (intercept_request->is_ignored()) {
+ delete intercept_request;
+ return nullptr;
+ }
+
+ GURL referrer(request->referrer());
+ if (referrer.is_valid() &&
+ (!request->is_pending() || request->is_redirecting())) {
+ request->SetExtraRequestHeaderByName(net::HttpRequestHeaders::kReferer,
+ referrer.spec(), true);
+ }
+ request->SetUserData(kRequestAlreadyHasJobDataKey,
+ std::unique_ptr<base::SupportsUserData::Data>(
+ new base::SupportsUserData::Data()));
+
+ return base::WrapUnique(new URLRequestJobEFL(request, intercept_request));
+}
+
+} // namespace content
--- /dev/null
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Copyright 2016 Samsung Electronics. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef EWK_EFL_INTEGRATION_URL_REQUEST_INTERCEPTOR_EFL_H_
+#define EWK_EFL_INTEGRATION_URL_REQUEST_INTERCEPTOR_EFL_H_
+
+#include "net/url_request/url_request_interceptor.h"
+#include "public/ewk_context.h"
+
+namespace net {
+class URLRequest;
+class URLRequestJob;
+class NetworkDelegate;
+} // namespace net
+
+struct _Ewk_Intercept_Request;
+
+namespace content {
+
+class URLRequestInterceptorEFL : public net::URLRequestInterceptor {
+ public:
+ URLRequestInterceptorEFL();
+ ~URLRequestInterceptorEFL() override;
+
+ URLRequestInterceptorEFL(const URLRequestInterceptorEFL&) = delete;
+ URLRequestInterceptorEFL& operator=(const URLRequestInterceptorEFL&) = delete;
+
+ std::unique_ptr<net::URLRequestJob> MaybeInterceptRequest(
+ net::URLRequest* request) const override;
+};
+
+} // namespace content
+
+#endif // EWK_EFL_INTEGRATION_URL_REQUEST_INTERCEPTOR_EFL_H_
--- /dev/null
+// Copyright 2012 The Chromium Authors. All rights reserved.
+// Copyright 2016 Samsung Electronics. 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_request_job_efl.h"
+
+#include <algorithm>
+#include <cstring>
+
+#include "base/callback.h"
+#include "base/strings/string_util.h"
+#include "content/public/browser/browser_thread.h"
+#include "net/base/io_buffer.h"
+#include "net/base/net_errors.h"
+#include "net/http/http_response_headers.h"
+
+using content::BrowserThread;
+
+URLRequestJobEFL::URLRequestJobEFL(net::URLRequest* request,
+ _Ewk_Intercept_Request* intercept_request)
+ : URLRequestJob(request),
+ intercept_request_(intercept_request),
+ response_info_(),
+ bytes_read_(0),
+ response_body_length_(0),
+ killed_(false),
+ waiting_done_(false),
+ communication_done_(false),
+ started_(false),
+ available_data_(0),
+ buf_(nullptr),
+ buf_size_(0) {
+ intercept_request_->set_delegate(this);
+}
+
+URLRequestJobEFL::~URLRequestJobEFL() {}
+
+URLRequestJobEFL::Chunk::Chunk(const char* data, size_t length)
+ : data_(data), data_pos_(data), length_(length) {}
+
+URLRequestJobEFL::Chunk::~Chunk() {}
+
+void URLRequestJobEFL::HeadersComplete() {
+ // Converts \r\n separated headers to \0 separated as expected by
+ // net::HttpResponseHeaders. We can't really expect \0 separated headers from
+ // EWK C API.
+ base::ReplaceSubstringsAfterOffset(&response_headers_, 0, "\r\n",
+ std::string("\0", 1));
+ response_info_.headers = new net::HttpResponseHeaders(response_headers_);
+
+ NotifyHeadersComplete();
+}
+
+void URLRequestJobEFL::TakeResponseData() {
+ response_headers_ = intercept_request_->response_headers_take();
+ if (!intercept_request_->is_chunked_write()) {
+ response_body_ = intercept_request_->response_body_take();
+ response_body_length_ = intercept_request_->response_body_length_get();
+ }
+}
+
+void URLRequestJobEFL::Start() {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ started_ = true;
+
+ // User have already sent all data or started chunked writing.
+ if (waiting_done_)
+ HeadersComplete();
+}
+
+int URLRequestJobEFL::ReadRawData(net::IOBuffer* buf, int buf_size) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ // It is safe to call is_chunked_write here on IO thread, despite it being
+ // set in UI/user thread. Due to URLRequestJob contract we won't enter
+ // ReadRawData until we call NotifyHeadersComplete, which is called in
+ // response to ResponseDecided task posted on IO thread by
+ // Ewk_Intercept_Request. is_chunked_write internal state is always decided
+ // before ResponseDecided is posted. The same reasoning applies to call to
+ // is_chunked_write in ResponseDecided task.
+ if (intercept_request_->is_chunked_write()) {
+ // If user signaled end of writing before all data was read by engine
+ // we couldn't call ::NotifyDone() in ::ChunkedReadDone(), so we can signal
+ // end of data here by setting |bytes_read| to 0 and returning true.
+ if (communication_done_ && !available_data_)
+ return 0;
+
+ if (available_data_) {
+ // If user wrote some chunks of data before ::ReadRawData() we can read
+ // it already here.
+ return static_cast<int>(ReadChunkedData(buf, buf_size));
+ } else {
+ // If there is no chunk of data we save |buf| and wait for a write.
+ buf_ = buf;
+ buf_size_ = buf_size;
+ return net::ERR_IO_PENDING;
+ }
+ } else {
+ return static_cast<int>(ReadData(buf, buf_size));
+ }
+}
+
+void URLRequestJobEFL::Kill() {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ if (killed_)
+ return;
+ killed_ = true;
+ buf_ = nullptr;
+ buf_size_ = -1;
+ intercept_request_->request_early_exit();
+ URLRequestJob::Kill();
+}
+
+void URLRequestJobEFL::ResponseDecided() {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ waiting_done_ = true;
+ TakeResponseData();
+ if (started_ && !killed_) {
+ // No point in notifing if job is dead.
+ HeadersComplete();
+ }
+}
+
+void URLRequestJobEFL::PutChunk(const char* data, size_t length) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ if (killed_) {
+ // No point doing any work if job is already killed, but events are still
+ // scheduled.
+ delete data;
+ return;
+ }
+ chunks_.emplace(data, length);
+ available_data_ += length;
+ if (buf_) {
+ // A buffer is ready, we can write now.
+ int result = static_cast<int>(ReadChunkedData(buf_, buf_size_));
+ buf_ = nullptr;
+ buf_size_ = -1;
+ ReadRawDataComplete(result);
+ }
+}
+
+void URLRequestJobEFL::ChunkedReadDone() {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ communication_done_ = true;
+ // If user spammed engine with data, and called ::ChunkedReadDone() before
+ // all chunks have been read, then we might not be done yet. End of reading
+ // will be signaled from ::ReadRawData().
+ if (chunks_.empty() && !killed_)
+ ReadRawDataComplete(0);
+}
+
+size_t URLRequestJobEFL::ReadChunkedData(net::IOBuffer* buf, int buf_size) {
+ size_t to_read = std::min(static_cast<size_t>(buf_size), available_data_);
+ available_data_ -= to_read;
+ char* buf_ptr = buf->data();
+ while (!chunks_.empty()) {
+ if (chunks_.front().Available() > to_read) {
+ memcpy(buf_ptr, chunks_.front().Data(), to_read);
+ buf_ptr += to_read;
+ chunks_.front().Advance(to_read);
+ to_read = 0;
+ break;
+ } else {
+ memcpy(buf_ptr, chunks_.front().Data(), chunks_.front().Available());
+ buf_ptr += chunks_.front().Available();
+ to_read -= chunks_.front().Available();
+ chunks_.front().Advance(chunks_.front().Available());
+ chunks_.pop();
+ if (!to_read)
+ break;
+ }
+ }
+ return buf_ptr - buf->data();
+}
+
+size_t URLRequestJobEFL::ReadData(net::IOBuffer* buf, int buf_size) {
+ size_t to_read = std::min(static_cast<size_t>(buf_size),
+ response_body_length_ - bytes_read_);
+ if (to_read) {
+ memcpy(buf->data(), response_body_.get() + bytes_read_, to_read);
+ bytes_read_ += to_read;
+ }
+
+ return to_read;
+}
+
+bool URLRequestJobEFL::GetMimeType(std::string* mime_type) const {
+ return response_info_.headers->GetMimeType(mime_type);
+}
+
+bool URLRequestJobEFL::GetCharset(std::string* charset) {
+ *charset = std::string("utf8");
+ return true;
+}
+
+int URLRequestJobEFL::GetResponseCode() const {
+ return response_info_.headers->response_code();
+}
+
+void URLRequestJobEFL::GetResponseInfo(net::HttpResponseInfo* info) {
+ *info = response_info_;
+}
--- /dev/null
+// Copyright 2012 The Chromium Authors. All rights reserved.
+// Copyright 2016 Samsung Electronics. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef EWK_EFL_INTEGRATION_URL_REQUEST_JOB_EFL_H_
+#define EWK_EFL_INTEGRATION_URL_REQUEST_JOB_EFL_H_
+
+#include <cstddef>
+#include <queue>
+#include <string>
+
+#include "net/http/http_response_info.h"
+#include "net/url_request/url_request_job.h"
+
+#include "private/ewk_intercept_request_private.h"
+
+namespace net {
+class URLRequest;
+class IOBuffer;
+} // namespace net
+
+class URLRequestJobEFL : public net::URLRequestJob,
+ public _Ewk_Intercept_Request::Delegate {
+ public:
+ URLRequestJobEFL(net::URLRequest* request,
+ _Ewk_Intercept_Request* intercept_request);
+ ~URLRequestJobEFL() override;
+
+ URLRequestJobEFL(const URLRequestJobEFL&) = delete;
+ URLRequestJobEFL& operator=(const URLRequestJobEFL&) = delete;
+
+ // URLRequestJob:
+ void Start() override;
+ void Kill() override;
+ int ReadRawData(net::IOBuffer* buf, int buf_size) override;
+ bool GetMimeType(std::string* mime_type) const override;
+ bool GetCharset(std::string* charset) override;
+ int GetResponseCode() const override;
+ void GetResponseInfo(net::HttpResponseInfo* info) override;
+
+ _Ewk_Intercept_Request* GetInterceptRequestHandle() const {
+ return intercept_request_.get();
+ }
+
+ private:
+ // _Ewk_Intercept_Request::Delegate:
+ void ResponseDecided() override;
+ void PutChunk(const char* data, size_t length) override;
+ void ChunkedReadDone() override;
+
+ class Chunk {
+ public:
+ Chunk(const char* data, size_t length);
+ ~Chunk();
+
+ size_t Available() { return length_ - (data_pos_ - data_.get()); }
+ const char* Data() { return data_pos_; }
+ void Advance(size_t count) { data_pos_ += count; }
+
+ private:
+ std::unique_ptr<const char[]> data_;
+ const char* data_pos_;
+ size_t length_;
+ };
+
+ void HeadersComplete();
+ void TakeResponseData();
+ size_t ReadData(net::IOBuffer* buf, int buf_size);
+ size_t ReadChunkedData(net::IOBuffer* buf, int buf_size);
+
+ std::unique_ptr<_Ewk_Intercept_Request> intercept_request_;
+ net::HttpResponseInfo response_info_;
+
+ size_t bytes_read_;
+ size_t response_body_length_;
+ bool killed_;
+ bool waiting_done_;
+ bool communication_done_;
+ bool started_;
+
+ std::string response_headers_;
+ std::unique_ptr<char[]> response_body_;
+
+ size_t available_data_;
+ std::queue<Chunk> chunks_;
+ // |buf_| lifetime is managed by outer scope, it is alive as long as job uses
+ // it - until ::ReadRawData returns (with value true), or until
+ // ::NotifyReadComplete call in async case.
+ net::IOBuffer* buf_;
+ int buf_size_;
+};
+
+#endif // EWK_EFL_INTEGRATION_URL_REQUEST_JOB_EFL_H_
void WebContentsDelegateEfl::NavigationStateChanged(
WebContents* source, InvalidateTypes changed_flags) {
+ // We always notfiy clients about title invalidation, even if its text
+ // didn't actually change. This is to maintain EWK API consistency.
+ if (changed_flags & INVALIDATE_TYPE_TITLE) {
+ web_view_->SmartCallback<EWebViewCallbacks::TitleChange>().call(
+ base::UTF16ToUTF8(source->GetTitle()).c_str());
+ }
+
// We only notify clients if visible url actually changed, because on some
// pages we would get notifications with flag INVALIDATE_TYPE_URL even when
// visible url did not change.