electron/atom/browser/api/atom_api_protocol.h

198 lines
7 KiB
C
Raw Normal View History

// Copyright (c) 2013 GitHub, Inc.
2014-04-25 09:49:37 +00:00
// Use of this source code is governed by the MIT license that can be
2013-08-24 07:26:10 +00:00
// found in the LICENSE file.
#ifndef ATOM_BROWSER_API_ATOM_API_PROTOCOL_H_
#define ATOM_BROWSER_API_ATOM_API_PROTOCOL_H_
2013-08-24 08:38:19 +00:00
#include <map>
#include <memory>
2016-08-26 22:30:02 +00:00
#include <string>
#include <utility>
#include <vector>
2013-08-24 08:38:19 +00:00
#include "atom/browser/api/trackable_object.h"
#include "atom/browser/atom_browser_context.h"
#include "atom/browser/net/atom_url_request_job_factory.h"
#include "atom/common/promise_util.h"
2014-04-21 08:33:32 +00:00
#include "base/callback.h"
#include "base/memory/weak_ptr.h"
#include "base/task/post_task.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
2015-08-12 13:32:52 +00:00
#include "native_mate/arguments.h"
#include "native_mate/dictionary.h"
2014-04-21 08:33:32 +00:00
#include "native_mate/handle.h"
#include "net/url_request/url_request_context.h"
2014-04-21 08:33:32 +00:00
namespace base {
class DictionaryValue;
}
2013-08-24 07:26:10 +00:00
namespace atom {
namespace api {
std::vector<std::string> GetStandardSchemes();
void RegisterSchemesAsPrivileged(v8::Local<v8::Value> val,
mate::Arguments* args);
class Protocol : public mate::TrackableObject<Protocol> {
2013-08-24 07:26:10 +00:00
public:
using Handler =
base::Callback<void(const base::DictionaryValue&, v8::Local<v8::Value>)>;
using CompletionCallback = base::Callback<void(v8::Local<v8::Value>)>;
2015-07-09 09:18:45 +00:00
2018-04-18 01:44:10 +00:00
static mate::Handle<Protocol> Create(v8::Isolate* isolate,
AtomBrowserContext* browser_context);
2014-04-21 08:33:32 +00:00
2016-04-25 01:17:54 +00:00
static void BuildPrototype(v8::Isolate* isolate,
v8::Local<v8::FunctionTemplate> prototype);
2014-04-21 08:33:32 +00:00
2016-04-25 01:17:54 +00:00
protected:
2016-05-08 11:14:14 +00:00
Protocol(v8::Isolate* isolate, AtomBrowserContext* browser_context);
~Protocol() override;
2013-08-24 07:26:10 +00:00
private:
// Possible errors.
enum ProtocolError {
2018-04-18 01:44:10 +00:00
PROTOCOL_OK, // no error
PROTOCOL_FAIL, // operation failed, should never occur
PROTOCOL_REGISTERED,
PROTOCOL_NOT_REGISTERED,
PROTOCOL_INTERCEPTED,
PROTOCOL_NOT_INTERCEPTED,
};
2014-04-21 08:33:32 +00:00
// The protocol handler that will create a protocol handler for certain
// request job.
2018-04-18 01:44:10 +00:00
template <typename RequestJob>
class CustomProtocolHandler
: public net::URLRequestJobFactory::ProtocolHandler {
public:
2018-04-18 01:44:10 +00:00
CustomProtocolHandler(v8::Isolate* isolate,
net::URLRequestContextGetter* request_context,
const Handler& handler)
: isolate_(isolate),
request_context_(request_context),
handler_(handler) {}
~CustomProtocolHandler() override {}
net::URLRequestJob* MaybeCreateJob(
net::URLRequest* request,
net::NetworkDelegate* network_delegate) const override {
RequestJob* request_job = new RequestJob(request, network_delegate);
request_job->SetHandlerInfo(isolate_, request_context_, handler_);
return request_job;
}
private:
v8::Isolate* isolate_;
net::URLRequestContextGetter* request_context_;
Protocol::Handler handler_;
DISALLOW_COPY_AND_ASSIGN(CustomProtocolHandler);
};
2015-07-05 17:53:07 +00:00
// Register the protocol with certain request job.
2018-04-18 01:44:10 +00:00
template <typename RequestJob>
2015-08-13 11:26:18 +00:00
void RegisterProtocol(const std::string& scheme,
const Handler& handler,
2015-08-13 11:26:18 +00:00
mate::Arguments* args) {
CompletionCallback callback;
args->GetNext(&callback);
auto* getter = static_cast<URLRequestContextGetter*>(
browser_context_->GetRequestContext());
base::PostTaskWithTraitsAndReplyWithResult(
FROM_HERE, {content::BrowserThread::IO},
base::BindOnce(&Protocol::RegisterProtocolInIO<RequestJob>,
base::RetainedRef(getter), isolate(), scheme, handler),
base::BindOnce(&Protocol::OnIOCompleted, GetWeakPtr(), callback));
}
2018-04-18 01:44:10 +00:00
template <typename RequestJob>
2016-06-15 12:11:42 +00:00
static ProtocolError RegisterProtocolInIO(
scoped_refptr<URLRequestContextGetter> request_context_getter,
2016-06-15 12:11:42 +00:00
v8::Isolate* isolate,
const std::string& scheme,
const Handler& handler) {
auto* job_factory = request_context_getter->job_factory();
2016-06-15 12:11:42 +00:00
if (job_factory->IsHandledProtocol(scheme))
return PROTOCOL_REGISTERED;
auto protocol_handler = std::make_unique<CustomProtocolHandler<RequestJob>>(
isolate, request_context_getter.get(), handler);
2016-06-15 12:11:42 +00:00
if (job_factory->SetProtocolHandler(scheme, std::move(protocol_handler)))
return PROTOCOL_OK;
else
return PROTOCOL_FAIL;
}
2015-08-13 11:33:53 +00:00
// Unregister the protocol handler that handles |scheme|.
2015-08-13 11:26:18 +00:00
void UnregisterProtocol(const std::string& scheme, mate::Arguments* args);
2016-06-15 12:11:42 +00:00
static ProtocolError UnregisterProtocolInIO(
scoped_refptr<URLRequestContextGetter> request_context_getter,
2016-06-15 12:11:42 +00:00
const std::string& scheme);
2015-08-12 13:32:52 +00:00
2015-08-13 11:33:53 +00:00
// Whether the protocol has handler registered.
v8::Local<v8::Promise> IsProtocolHandled(const std::string& scheme);
2015-08-13 11:33:53 +00:00
2015-08-13 12:10:05 +00:00
// Replace the protocol handler with a new one.
2018-04-18 01:44:10 +00:00
template <typename RequestJob>
2015-08-13 12:10:05 +00:00
void InterceptProtocol(const std::string& scheme,
const Handler& handler,
mate::Arguments* args) {
CompletionCallback callback;
args->GetNext(&callback);
auto* getter = static_cast<URLRequestContextGetter*>(
browser_context_->GetRequestContext());
base::PostTaskWithTraitsAndReplyWithResult(
FROM_HERE, {content::BrowserThread::IO},
base::BindOnce(&Protocol::InterceptProtocolInIO<RequestJob>,
base::RetainedRef(getter), isolate(), scheme, handler),
base::BindOnce(&Protocol::OnIOCompleted, GetWeakPtr(), callback));
2015-08-13 12:10:05 +00:00
}
2018-04-18 01:44:10 +00:00
template <typename RequestJob>
2016-06-15 12:11:42 +00:00
static ProtocolError InterceptProtocolInIO(
scoped_refptr<URLRequestContextGetter> request_context_getter,
2016-06-15 12:11:42 +00:00
v8::Isolate* isolate,
const std::string& scheme,
const Handler& handler) {
auto* job_factory = request_context_getter->job_factory();
2016-06-15 12:11:42 +00:00
if (!job_factory->IsHandledProtocol(scheme))
2015-08-13 12:10:05 +00:00
return PROTOCOL_NOT_REGISTERED;
// It is possible a protocol is handled but can not be intercepted.
if (!job_factory->HasProtocolHandler(scheme))
return PROTOCOL_FAIL;
auto protocol_handler = std::make_unique<CustomProtocolHandler<RequestJob>>(
isolate, request_context_getter.get(), handler);
2016-06-15 12:11:42 +00:00
if (!job_factory->InterceptProtocol(scheme, std::move(protocol_handler)))
return PROTOCOL_INTERCEPTED;
2015-08-13 12:10:05 +00:00
return PROTOCOL_OK;
}
2015-08-13 12:19:02 +00:00
// Restore the |scheme| to its original protocol handler.
void UninterceptProtocol(const std::string& scheme, mate::Arguments* args);
2016-06-15 12:11:42 +00:00
static ProtocolError UninterceptProtocolInIO(
scoped_refptr<URLRequestContextGetter> request_context_getter,
2016-06-15 12:11:42 +00:00
const std::string& scheme);
2015-08-13 12:19:02 +00:00
// Convert error code to JS exception and call the callback.
void OnIOCompleted(const CompletionCallback& callback, ProtocolError error);
// Convert error code to string.
std::string ErrorCodeToString(ProtocolError error);
2013-08-30 02:15:15 +00:00
2018-04-18 01:44:10 +00:00
base::WeakPtr<Protocol> GetWeakPtr() { return weak_factory_.GetWeakPtr(); }
2015-08-13 12:10:05 +00:00
scoped_refptr<AtomBrowserContext> browser_context_;
base::WeakPtrFactory<Protocol> weak_factory_;
2013-08-30 02:15:15 +00:00
2014-04-21 08:33:32 +00:00
DISALLOW_COPY_AND_ASSIGN(Protocol);
2013-08-24 07:26:10 +00:00
};
} // namespace api
} // namespace atom
#endif // ATOM_BROWSER_API_ATOM_API_PROTOCOL_H_