atom_api_protocol.h 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. // Copyright (c) 2013 GitHub, Inc.
  2. // Use of this source code is governed by the MIT license that can be
  3. // found in the LICENSE file.
  4. #ifndef ATOM_BROWSER_API_ATOM_API_PROTOCOL_H_
  5. #define ATOM_BROWSER_API_ATOM_API_PROTOCOL_H_
  6. #include <map>
  7. #include <string>
  8. #include <vector>
  9. #include "atom/browser/api/trackable_object.h"
  10. #include "atom/browser/atom_browser_context.h"
  11. #include "atom/browser/net/atom_url_request_job_factory.h"
  12. #include "base/callback.h"
  13. #include "base/memory/weak_ptr.h"
  14. #include "content/public/browser/browser_thread.h"
  15. #include "native_mate/arguments.h"
  16. #include "native_mate/dictionary.h"
  17. #include "native_mate/handle.h"
  18. #include "net/url_request/url_request_context.h"
  19. namespace base {
  20. class DictionaryValue;
  21. }
  22. namespace atom {
  23. namespace api {
  24. std::vector<std::string> GetStandardSchemes();
  25. void RegisterStandardSchemes(const std::vector<std::string>& schemes,
  26. mate::Arguments* args);
  27. class Protocol : public mate::TrackableObject<Protocol> {
  28. public:
  29. using Handler =
  30. base::Callback<void(const base::DictionaryValue&, v8::Local<v8::Value>)>;
  31. using CompletionCallback = base::Callback<void(v8::Local<v8::Value>)>;
  32. using BooleanCallback = base::Callback<void(bool)>;
  33. static mate::Handle<Protocol> Create(v8::Isolate* isolate,
  34. AtomBrowserContext* browser_context);
  35. static void BuildPrototype(v8::Isolate* isolate,
  36. v8::Local<v8::FunctionTemplate> prototype);
  37. protected:
  38. Protocol(v8::Isolate* isolate, AtomBrowserContext* browser_context);
  39. ~Protocol() override;
  40. private:
  41. // Possible errors.
  42. enum ProtocolError {
  43. PROTOCOL_OK, // no error
  44. PROTOCOL_FAIL, // operation failed, should never occur
  45. PROTOCOL_REGISTERED,
  46. PROTOCOL_NOT_REGISTERED,
  47. PROTOCOL_INTERCEPTED,
  48. PROTOCOL_NOT_INTERCEPTED,
  49. };
  50. // The protocol handler that will create a protocol handler for certain
  51. // request job.
  52. template <typename RequestJob>
  53. class CustomProtocolHandler
  54. : public net::URLRequestJobFactory::ProtocolHandler {
  55. public:
  56. CustomProtocolHandler(v8::Isolate* isolate,
  57. net::URLRequestContextGetter* request_context,
  58. const Handler& handler)
  59. : isolate_(isolate),
  60. request_context_(request_context),
  61. handler_(handler) {}
  62. ~CustomProtocolHandler() override {}
  63. net::URLRequestJob* MaybeCreateJob(
  64. net::URLRequest* request,
  65. net::NetworkDelegate* network_delegate) const override {
  66. RequestJob* request_job = new RequestJob(request, network_delegate);
  67. request_job->SetHandlerInfo(isolate_, request_context_.get(), handler_);
  68. return request_job;
  69. }
  70. private:
  71. v8::Isolate* isolate_;
  72. scoped_refptr<net::URLRequestContextGetter> request_context_;
  73. Protocol::Handler handler_;
  74. DISALLOW_COPY_AND_ASSIGN(CustomProtocolHandler);
  75. };
  76. // Register schemes that can handle service worker.
  77. void RegisterServiceWorkerSchemes(const std::vector<std::string>& schemes);
  78. // Register the protocol with certain request job.
  79. template <typename RequestJob>
  80. void RegisterProtocol(const std::string& scheme,
  81. const Handler& handler,
  82. mate::Arguments* args) {
  83. CompletionCallback callback;
  84. args->GetNext(&callback);
  85. auto* getter = browser_context_->GetRequestContext();
  86. content::BrowserThread::PostTaskAndReplyWithResult(
  87. content::BrowserThread::IO, FROM_HERE,
  88. base::BindOnce(&Protocol::RegisterProtocolInIO<RequestJob>,
  89. base::RetainedRef(getter), isolate(), scheme, handler),
  90. base::BindOnce(&Protocol::OnIOCompleted, GetWeakPtr(), callback));
  91. }
  92. template <typename RequestJob>
  93. static ProtocolError RegisterProtocolInIO(
  94. scoped_refptr<brightray::URLRequestContextGetter> request_context_getter,
  95. v8::Isolate* isolate,
  96. const std::string& scheme,
  97. const Handler& handler) {
  98. auto* job_factory = static_cast<AtomURLRequestJobFactory*>(
  99. request_context_getter->job_factory());
  100. if (job_factory->IsHandledProtocol(scheme))
  101. return PROTOCOL_REGISTERED;
  102. std::unique_ptr<CustomProtocolHandler<RequestJob>> protocol_handler(
  103. new CustomProtocolHandler<RequestJob>(
  104. isolate, request_context_getter.get(), handler));
  105. if (job_factory->SetProtocolHandler(scheme, std::move(protocol_handler)))
  106. return PROTOCOL_OK;
  107. else
  108. return PROTOCOL_FAIL;
  109. }
  110. // Unregister the protocol handler that handles |scheme|.
  111. void UnregisterProtocol(const std::string& scheme, mate::Arguments* args);
  112. static ProtocolError UnregisterProtocolInIO(
  113. scoped_refptr<brightray::URLRequestContextGetter> request_context_getter,
  114. const std::string& scheme);
  115. // Whether the protocol has handler registered.
  116. void IsProtocolHandled(const std::string& scheme,
  117. const BooleanCallback& callback);
  118. static bool IsProtocolHandledInIO(
  119. scoped_refptr<brightray::URLRequestContextGetter> request_context_getter,
  120. const std::string& scheme);
  121. // Replace the protocol handler with a new one.
  122. template <typename RequestJob>
  123. void InterceptProtocol(const std::string& scheme,
  124. const Handler& handler,
  125. mate::Arguments* args) {
  126. CompletionCallback callback;
  127. args->GetNext(&callback);
  128. auto* getter = browser_context_->GetRequestContext();
  129. content::BrowserThread::PostTaskAndReplyWithResult(
  130. content::BrowserThread::IO, FROM_HERE,
  131. base::BindOnce(&Protocol::InterceptProtocolInIO<RequestJob>,
  132. base::RetainedRef(getter), isolate(), scheme, handler),
  133. base::BindOnce(&Protocol::OnIOCompleted, GetWeakPtr(), callback));
  134. }
  135. template <typename RequestJob>
  136. static ProtocolError InterceptProtocolInIO(
  137. scoped_refptr<brightray::URLRequestContextGetter> request_context_getter,
  138. v8::Isolate* isolate,
  139. const std::string& scheme,
  140. const Handler& handler) {
  141. auto* job_factory = static_cast<AtomURLRequestJobFactory*>(
  142. request_context_getter->job_factory());
  143. if (!job_factory->IsHandledProtocol(scheme))
  144. return PROTOCOL_NOT_REGISTERED;
  145. // It is possible a protocol is handled but can not be intercepted.
  146. if (!job_factory->HasProtocolHandler(scheme))
  147. return PROTOCOL_FAIL;
  148. std::unique_ptr<CustomProtocolHandler<RequestJob>> protocol_handler(
  149. new CustomProtocolHandler<RequestJob>(
  150. isolate, request_context_getter.get(), handler));
  151. if (!job_factory->InterceptProtocol(scheme, std::move(protocol_handler)))
  152. return PROTOCOL_INTERCEPTED;
  153. return PROTOCOL_OK;
  154. }
  155. // Restore the |scheme| to its original protocol handler.
  156. void UninterceptProtocol(const std::string& scheme, mate::Arguments* args);
  157. static ProtocolError UninterceptProtocolInIO(
  158. scoped_refptr<brightray::URLRequestContextGetter> request_context_getter,
  159. const std::string& scheme);
  160. // Convert error code to JS exception and call the callback.
  161. void OnIOCompleted(const CompletionCallback& callback, ProtocolError error);
  162. // Convert error code to string.
  163. std::string ErrorCodeToString(ProtocolError error);
  164. base::WeakPtr<Protocol> GetWeakPtr() { return weak_factory_.GetWeakPtr(); }
  165. scoped_refptr<AtomBrowserContext> browser_context_;
  166. base::WeakPtrFactory<Protocol> weak_factory_;
  167. DISALLOW_COPY_AND_ASSIGN(Protocol);
  168. };
  169. } // namespace api
  170. } // namespace atom
  171. #endif // ATOM_BROWSER_API_ATOM_API_PROTOCOL_H_