js_asker.h 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. // Copyright (c) 2015 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_NET_JS_ASKER_H_
  5. #define ATOM_BROWSER_NET_JS_ASKER_H_
  6. #include "atom/common/native_mate_converters/net_converter.h"
  7. #include "base/callback.h"
  8. #include "base/memory/ref_counted.h"
  9. #include "base/memory/weak_ptr.h"
  10. #include "base/values.h"
  11. #include "content/public/browser/browser_thread.h"
  12. #include "net/base/net_errors.h"
  13. #include "net/http/http_response_headers.h"
  14. #include "net/http/http_status_code.h"
  15. #include "net/url_request/url_request_context_getter.h"
  16. #include "net/url_request/url_request_job.h"
  17. #include "v8/include/v8.h"
  18. namespace atom {
  19. using JavaScriptHandler =
  20. base::Callback<void(const base::DictionaryValue&, v8::Local<v8::Value>)>;
  21. namespace internal {
  22. using BeforeStartCallback =
  23. base::Callback<void(v8::Isolate*, v8::Local<v8::Value>)>;
  24. using ResponseCallback =
  25. base::Callback<void(bool, std::unique_ptr<base::Value> options)>;
  26. // Ask handler for options in UI thread.
  27. void AskForOptions(v8::Isolate* isolate,
  28. const JavaScriptHandler& handler,
  29. std::unique_ptr<base::DictionaryValue> request_details,
  30. const BeforeStartCallback& before_start,
  31. const ResponseCallback& callback);
  32. // Test whether the |options| means an error.
  33. bool IsErrorOptions(base::Value* value, int* error);
  34. } // namespace internal
  35. template<typename RequestJob>
  36. class JsAsker : public RequestJob {
  37. public:
  38. JsAsker(net::URLRequest* request, net::NetworkDelegate* network_delegate)
  39. : RequestJob(request, network_delegate), weak_factory_(this) {}
  40. // Called by |CustomProtocolHandler| to store handler related information.
  41. void SetHandlerInfo(
  42. v8::Isolate* isolate,
  43. net::URLRequestContextGetter* request_context_getter,
  44. const JavaScriptHandler& handler) {
  45. isolate_ = isolate;
  46. request_context_getter_ = request_context_getter;
  47. handler_ = handler;
  48. }
  49. // Subclass should do initailze work here.
  50. virtual void BeforeStartInUI(v8::Isolate*, v8::Local<v8::Value>) {}
  51. virtual void StartAsync(std::unique_ptr<base::Value> options) = 0;
  52. net::URLRequestContextGetter* request_context_getter() const {
  53. return request_context_getter_;
  54. }
  55. private:
  56. // RequestJob:
  57. void Start() override {
  58. std::unique_ptr<base::DictionaryValue> request_details(
  59. new base::DictionaryValue);
  60. request_start_time_ = base::TimeTicks::Now();
  61. FillRequestDetails(request_details.get(), RequestJob::request());
  62. content::BrowserThread::PostTask(
  63. content::BrowserThread::UI, FROM_HERE,
  64. base::Bind(&internal::AskForOptions,
  65. isolate_,
  66. handler_,
  67. base::Passed(&request_details),
  68. base::Bind(&JsAsker::BeforeStartInUI,
  69. weak_factory_.GetWeakPtr()),
  70. base::Bind(&JsAsker::OnResponse,
  71. weak_factory_.GetWeakPtr())));
  72. }
  73. int GetResponseCode() const override { return net::HTTP_OK; }
  74. // NOTE: We have to implement this method or risk a crash in blink for
  75. // redirects!
  76. void GetLoadTimingInfo(net::LoadTimingInfo* load_timing_info) const override {
  77. load_timing_info->send_start = request_start_time_;
  78. load_timing_info->send_end = request_start_time_;
  79. load_timing_info->request_start = request_start_time_;
  80. load_timing_info->receive_headers_end = response_start_time_;
  81. }
  82. void GetResponseInfo(net::HttpResponseInfo* info) override {
  83. info->headers = new net::HttpResponseHeaders("");
  84. }
  85. // Called when the JS handler has sent the response, we need to decide whether
  86. // to start, or fail the job.
  87. void OnResponse(bool success, std::unique_ptr<base::Value> value) {
  88. response_start_time_ = base::TimeTicks::Now();
  89. int error = net::ERR_NOT_IMPLEMENTED;
  90. if (success && value && !internal::IsErrorOptions(value.get(), &error)) {
  91. StartAsync(std::move(value));
  92. } else {
  93. RequestJob::NotifyStartError(
  94. net::URLRequestStatus(net::URLRequestStatus::FAILED, error));
  95. }
  96. }
  97. v8::Isolate* isolate_;
  98. net::URLRequestContextGetter* request_context_getter_;
  99. JavaScriptHandler handler_;
  100. base::TimeTicks request_start_time_;
  101. base::TimeTicks response_start_time_;
  102. base::WeakPtrFactory<JsAsker> weak_factory_;
  103. DISALLOW_COPY_AND_ASSIGN(JsAsker);
  104. };
  105. } // namespace atom
  106. #endif // ATOM_BROWSER_NET_JS_ASKER_H_