Browse Source

request for pdf resource from the webui

deepak1556 8 years ago
parent
commit
c982af991d

+ 13 - 30
atom/browser/atom_resource_dispatcher_host_delegate.cc

@@ -4,9 +4,7 @@
 
 #include "atom/browser/atom_resource_dispatcher_host_delegate.h"
 
-#include "atom/browser/atom_browser_context.h"
 #include "atom/browser/login_handler.h"
-#include "atom/browser/stream_manager.h"
 #include "atom/browser/web_contents_permission_helper.h"
 #include "atom/common/atom_constants.h"
 #include "atom/common/platform_util.h"
@@ -14,6 +12,7 @@
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "content/public/browser/browser_thread.h"
+#include "content/public/browser/stream_info.h"
 #include "net/base/escape.h"
 #include "net/ssl/client_cert_store.h"
 #include "net/url_request/url_request.h"
@@ -63,30 +62,20 @@ void HandleExternalProtocolInUI(
   permission_helper->RequestOpenExternalPermission(callback, has_user_gesture);
 }
 
-void OnPdfStreamCreated(
-    std::unique_ptr<content::StreamInfo> stream,
-    const std::string& stream_id,
-    const content::ResourceRequestInfo::WebContentsGetter& web_contents_getter,
-    int render_process_id,
-    int render_frame_id) {
+void OnPdfStreamCreated(const GURL& original_url,
+                        const content::ResourceRequestInfo::WebContentsGetter&
+                            web_contents_getter) {
   content::WebContents* web_contents = web_contents_getter.Run();
   if (!web_contents)
     return;
 
-  auto browser_context =
-      static_cast<AtomBrowserContext*>(web_contents->GetBrowserContext());
-  auto stream_manager = browser_context->stream_manager();
-  GURL original_url = stream->original_url;
-  stream_manager->AddStream(std::move(stream), stream_id, render_process_id,
-                            render_frame_id);
-  // The URL passes the stream ID to PDF webui that uses it to extract the
-  // stream from the StreamManager and also passes the URL that the PDF
-  // originates from, which is used whenever no stream is available from the
-  // content layer (this will happen when the webui page is reloaded).
-  // chrome://pdf-viewer/index.html?streamId=abcd&src=https://somepage/123.pdf
-  content::NavigationController::LoadURLParams params(GURL(base::StringPrintf(
-      "%sindex.html?%s=%s&%s=%s", kPdfViewerUIOrigin, kPdfViewerUIStreamId,
-      stream_id.c_str(), kPdfPluginSrc, original_url.spec().c_str())));
+  // The URL passes the original pdf resource url, that will be requested
+  // by the webui page.
+  // chrome://pdf-viewer/index.html?src=https://somepage/123.pdf
+  content::NavigationController::LoadURLParams params(
+      GURL(base::StringPrintf("%sindex.html?%s=%s", kPdfViewerUIOrigin,
+                              kPdfPluginSrc, original_url.spec().c_str())));
+  params.can_load_local_resources = true;
   web_contents->GetController().LoadURLWithParams(params);
 }
 
@@ -136,7 +125,6 @@ bool AtomResourceDispatcherHostDelegate::ShouldInterceptResourceAsStream(
     std::string* payload) {
   if (mime_type == "application/pdf") {
     *origin = GURL(kPdfViewerUIOrigin);
-    stream_info_[request] = base::GenerateGUID();
     return true;
   }
   return false;
@@ -145,17 +133,12 @@ bool AtomResourceDispatcherHostDelegate::ShouldInterceptResourceAsStream(
 void AtomResourceDispatcherHostDelegate::OnStreamCreated(
     net::URLRequest* request,
     std::unique_ptr<content::StreamInfo> stream) {
-  auto it = stream_info_.find(request);
-  if (it == stream_info_.end())
-    return;
   const content::ResourceRequestInfo* info =
       content::ResourceRequestInfo::ForRequest(request);
   content::BrowserThread::PostTask(
       BrowserThread::UI, FROM_HERE,
-      base::Bind(&OnPdfStreamCreated, base::Passed(&stream), it->second,
-                 info->GetWebContentsGetterForRequest(), info->GetChildID(),
-                 info->GetRenderFrameID()));
-  stream_info_.erase(it);
+      base::Bind(&OnPdfStreamCreated, stream->original_url,
+                 info->GetWebContentsGetterForRequest()));
 }
 
 }  // namespace atom

+ 0 - 4
atom/browser/atom_resource_dispatcher_host_delegate.h

@@ -5,7 +5,6 @@
 #ifndef ATOM_BROWSER_ATOM_RESOURCE_DISPATCHER_HOST_DELEGATE_H_
 #define ATOM_BROWSER_ATOM_RESOURCE_DISPATCHER_HOST_DELEGATE_H_
 
-#include <map>
 #include <string>
 
 #include "content/public/browser/resource_dispatcher_host_delegate.h"
@@ -34,9 +33,6 @@ class AtomResourceDispatcherHostDelegate
                        std::unique_ptr<content::StreamInfo> stream) override;
 
  private:
-  // Map between intercepted request and its generated stream id.
-  std::map<net::URLRequest*, std::string> stream_info_;
-
   DISALLOW_COPY_AND_ASSIGN(AtomResourceDispatcherHostDelegate);
 };
 

+ 2 - 4
atom/browser/atom_web_ui_controller_factory.cc

@@ -53,14 +53,12 @@ AtomWebUIControllerFactory::CreateWebUIControllerForURL(content::WebUI* web_ui,
     base::SplitStringIntoKeyValuePairs(url.query(), '=', '&', &toplevel_params);
     std::string stream_id, src;
     for (const auto& param : toplevel_params) {
-      if (param.first == kPdfViewerUIStreamId) {
-        stream_id = param.second;
-      } else if (param.first == kPdfPluginSrc) {
+      if (param.first == kPdfPluginSrc) {
         src = param.second;
       }
     }
     auto browser_context = web_ui->GetWebContents()->GetBrowserContext();
-    return new PdfViewerUI(browser_context, web_ui, stream_id, src);
+    return new PdfViewerUI(browser_context, web_ui, src);
   }
   return nullptr;
 }

+ 26 - 0
atom/browser/loader/layered_resource_handler.cc

@@ -0,0 +1,26 @@
+// Copyright (c) 2017 GitHub, Inc.
+// Use of this source code is governed by the MIT license that can be
+// found in the LICENSE file.
+
+#include "atom/browser/loader/layered_resource_handler.h"
+
+namespace atom {
+
+LayeredResourceHandler::LayeredResourceHandler(
+    net::URLRequest* request,
+    std::unique_ptr<content::ResourceHandler> next_handler,
+    Delegate* delegate)
+    : content::LayeredResourceHandler(request, std::move(next_handler)),
+      delegate_(delegate) {}
+
+LayeredResourceHandler::~LayeredResourceHandler() {}
+
+bool LayeredResourceHandler::OnResponseStarted(
+    content::ResourceResponse* response,
+    bool* defer) {
+  if (delegate_)
+    delegate_->OnResponseStarted(response);
+  return next_handler_->OnResponseStarted(response, defer);
+}
+
+}  // namespace atom

+ 40 - 0
atom/browser/loader/layered_resource_handler.h

@@ -0,0 +1,40 @@
+// Copyright (c) 2017 GitHub, Inc.
+// Use of this source code is governed by the MIT license that can be
+// found in the LICENSE file.
+
+#ifndef ATOM_BROWSER_LOADER_LAYERED_RESOURCE_HANDLER_H_
+#define ATOM_BROWSER_LOADER_LAYERED_RESOURCE_HANDLER_H_
+
+#include "content/browser/loader/layered_resource_handler.h"
+
+namespace atom {
+
+// Resource handler that notifies on various stages of a resource request.
+class LayeredResourceHandler : public content::LayeredResourceHandler {
+ public:
+  class Delegate {
+   public:
+    Delegate() {}
+    virtual ~Delegate() {}
+
+    virtual void OnResponseStarted(content::ResourceResponse* response) = 0;
+  };
+
+  LayeredResourceHandler(net::URLRequest* request,
+                         std::unique_ptr<content::ResourceHandler> next_handler,
+                         Delegate* delegate);
+  ~LayeredResourceHandler() override;
+
+  // content::LayeredResourceHandler:
+  bool OnResponseStarted(content::ResourceResponse* response,
+                         bool* defer) override;
+
+ private:
+  Delegate* delegate_;
+
+  DISALLOW_COPY_AND_ASSIGN(LayeredResourceHandler);
+};
+
+}  // namespace atom
+
+#endif  // ATOM_BROWSER_LOADER_LAYERED_RESOURCE_HANDLER_H_

+ 37 - 16
atom/browser/ui/webui/pdf_viewer_handler.cc

@@ -6,6 +6,7 @@
 
 #include "atom/common/atom_constants.h"
 #include "base/bind.h"
+#include "base/memory/ptr_util.h"
 #include "base/values.h"
 #include "content/public/browser/stream_handle.h"
 #include "content/public/browser/stream_info.h"
@@ -41,14 +42,35 @@ void CreateResponseHeadersDictionary(const net::HttpResponseHeaders* headers,
   }
 }
 
+void PopulateStreamInfo(base::DictionaryValue* stream_info,
+                        content::StreamInfo* stream,
+                        const std::string& original_url) {
+  std::unique_ptr<base::DictionaryValue> headers_dict(
+      new base::DictionaryValue);
+  auto stream_url = stream->handle->GetURL().spec();
+  CreateResponseHeadersDictionary(stream->response_headers.get(),
+                                  headers_dict.get());
+  stream_info->SetString("streamURL", stream_url);
+  stream_info->SetString("originalURL", original_url);
+  stream_info->Set("responseHeaders", std::move(headers_dict));
+}
+
 }  // namespace
 
-PdfViewerHandler::PdfViewerHandler(const content::StreamInfo* stream,
-                                   const std::string& src)
-    : stream_(stream), original_url_(src) {}
+PdfViewerHandler::PdfViewerHandler(const std::string& src)
+    : stream_(nullptr), original_url_(src), initialized_(false) {}
 
 PdfViewerHandler::~PdfViewerHandler() {}
 
+void PdfViewerHandler::SetPdfResourceStream(content::StreamInfo* stream) {
+  stream_ = stream;
+  if (initialized_) {
+    auto list = base::MakeUnique<base::ListValue>();
+    list->Set(0, std::move(initialize_callback_id_));
+    Initialize(list.get());
+  }
+}
+
 void PdfViewerHandler::RegisterMessages() {
   web_ui()->RegisterMessageCallback(
       "initialize",
@@ -79,24 +101,23 @@ void PdfViewerHandler::OnJavascriptDisallowed() {
 }
 
 void PdfViewerHandler::Initialize(const base::ListValue* args) {
-  AllowJavascript();
-
   CHECK_EQ(1U, args->GetSize());
   const base::Value* callback_id;
   CHECK(args->Get(0, &callback_id));
-  std::unique_ptr<base::DictionaryValue> stream_info(new base::DictionaryValue);
-  std::unique_ptr<base::DictionaryValue> headers_dict(
-      new base::DictionaryValue);
-  std::string stream_url = original_url_;
+
   if (stream_) {
-    stream_url = stream_->handle->GetURL().spec();
-    CreateResponseHeadersDictionary(stream_->response_headers.get(),
-                                    headers_dict.get());
+    initialized_ = false;
+
+    AllowJavascript();
+
+    std::unique_ptr<base::DictionaryValue> stream_info(
+        new base::DictionaryValue);
+    PopulateStreamInfo(stream_info.get(), stream_, original_url_);
+    ResolveJavascriptCallback(*callback_id, *stream_info);
+  } else {
+    initialize_callback_id_ = callback_id->CreateDeepCopy();
+    initialized_ = true;
   }
-  stream_info->SetString("streamURL", stream_url);
-  stream_info->SetString("originalURL", original_url_);
-  stream_info->Set("responseHeaders", std::move(headers_dict));
-  ResolveJavascriptCallback(*callback_id, *stream_info);
 }
 
 void PdfViewerHandler::GetDefaultZoom(const base::ListValue* args) {

+ 7 - 3
atom/browser/ui/webui/pdf_viewer_handler.h

@@ -23,10 +23,12 @@ namespace atom {
 
 class PdfViewerHandler : public content::WebUIMessageHandler {
  public:
-  PdfViewerHandler(const content::StreamInfo* stream,
-                   const std::string& original_url);
+  explicit PdfViewerHandler(const std::string& original_url);
   ~PdfViewerHandler() override;
 
+  void SetPdfResourceStream(content::StreamInfo* stream);
+
+ protected:
   // WebUIMessageHandler implementation.
   void RegisterMessages() override;
   void OnJavascriptAllowed() override;
@@ -43,8 +45,10 @@ class PdfViewerHandler : public content::WebUIMessageHandler {
   // Keeps track of events related to zooming.
   std::unique_ptr<content::HostZoomMap::Subscription>
       host_zoom_map_subscription_;
-  const content::StreamInfo* stream_;
+  std::unique_ptr<base::Value> initialize_callback_id_;
+  content::StreamInfo* stream_;
   std::string original_url_;
+  bool initialized_;
 
   DISALLOW_COPY_AND_ASSIGN(PdfViewerHandler);
 };

+ 111 - 6
atom/browser/ui/webui/pdf_viewer_ui.cc

@@ -11,14 +11,29 @@
 #include "atom/browser/ui/webui/pdf_viewer_handler.h"
 #include "atom/common/atom_constants.h"
 #include "components/pdf/common/pdf_messages.h"
+#include "content/browser/loader/resource_dispatcher_host_impl.h"
+#include "content/browser/loader/resource_request_info_impl.h"
+#include "content/browser/loader/stream_resource_handler.h"
+#include "content/browser/resource_context_impl.h"
+#include "content/browser/streams/stream.h"
+#include "content/browser/streams/stream_context.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/render_process_host.h"
 #include "content/public/browser/render_view_host.h"
+#include "content/public/browser/resource_context.h"
+#include "content/public/browser/stream_handle.h"
 #include "content/public/browser/url_data_source.h"
 #include "content/public/browser/web_contents.h"
-#include "content/public/common/bindings_policy.h"
 #include "grit/pdf_viewer_resources_map.h"
+#include "net/base/load_flags.h"
 #include "net/base/mime_util.h"
+#include "net/url_request/url_request.h"
+#include "net/url_request/url_request_context.h"
 #include "ui/base/resource/resource_bundle.h"
 
+using content::BrowserThread;
+
 namespace atom {
 
 namespace {
@@ -83,19 +98,68 @@ class BundledDataSource : public content::URLDataSource {
   DISALLOW_COPY_AND_ASSIGN(BundledDataSource);
 };
 
+void RequestPdfResource(
+    const GURL& url,
+    const GURL& origin,
+    int render_process_id,
+    int render_view_id,
+    int render_frame_id,
+    content::ResourceContext* resource_context,
+    base::Callback<void(std::unique_ptr<content::StreamInfo>)> callback,
+    atom::LayeredResourceHandler::Delegate* delegate) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+  const net::URLRequestContext* request_context =
+      resource_context->GetRequestContext();
+  std::unique_ptr<net::URLRequest> request(
+      request_context->CreateRequest(url, net::DEFAULT_PRIORITY, nullptr));
+  request->set_method("GET");
+
+  content::ResourceDispatcherHostImpl::Get()->InitializeURLRequest(
+      request.get(), content::Referrer(url, blink::WebReferrerPolicyDefault),
+      false,  // download.
+      render_process_id, render_view_id, render_frame_id, resource_context);
+
+  content::ResourceRequestInfoImpl* info =
+      content::ResourceRequestInfoImpl::ForRequest(request.get());
+  content::StreamContext* stream_context =
+      content::GetStreamContextForResourceContext(resource_context);
+
+  std::unique_ptr<content::ResourceHandler> handler(
+      new content::StreamResourceHandler(request.get(),
+                                         stream_context->registry(), origin));
+  info->set_is_stream(true);
+  std::unique_ptr<content::StreamInfo> stream_info(new content::StreamInfo);
+  stream_info->handle =
+      static_cast<content::StreamResourceHandler*>(handler.get())
+          ->stream()
+          ->CreateHandle();
+  stream_info->original_url = request->url();
+
+  // Helper to fill stream response details.
+  handler.reset(new atom::LayeredResourceHandler(request.get(),
+                                                 std::move(handler), delegate));
+
+  content::ResourceDispatcherHostImpl::Get()->BeginURLRequest(
+      std::move(request), std::move(handler),
+      false,  // download
+      false,  // content_initiated (download specific)
+      false,  // do_not_prompt_for_login (download specific)
+      resource_context);
+
+  callback.Run(std::move(stream_info));
+}
+
 }  // namespace
 
 PdfViewerUI::PdfViewerUI(content::BrowserContext* browser_context,
                          content::WebUI* web_ui,
-                         const std::string& stream_id,
                          const std::string& src)
     : content::WebUIController(web_ui),
       content::WebContentsObserver(web_ui->GetWebContents()),
       src_(src) {
-  auto context = static_cast<AtomBrowserContext*>(browser_context);
-  auto stream_manager = context->stream_manager();
-  stream_ = stream_manager->ReleaseStream(stream_id);
-  web_ui->AddMessageHandler(new PdfViewerHandler(stream_.get(), src));
+  pdf_handler_ = new PdfViewerHandler(src);
+  web_ui->AddMessageHandler(pdf_handler_);
   content::URLDataSource::Add(browser_context, new BundledDataSource);
 }
 
@@ -112,6 +176,47 @@ bool PdfViewerUI::OnMessageReceived(
   return handled;
 }
 
+void PdfViewerUI::OnPdfStreamResponseStarted(
+    scoped_refptr<net::HttpResponseHeaders> headers,
+    const std::string& mime_type) {
+  if (headers.get())
+    stream_->response_headers =
+        new net::HttpResponseHeaders(headers->raw_headers());
+  stream_->mime_type = mime_type;
+  pdf_handler_->SetPdfResourceStream(stream_.get());
+}
+
+void PdfViewerUI::OnResponseStarted(content::ResourceResponse* response) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+  auto resource_response_head = response->head;
+  BrowserThread::PostTask(
+      BrowserThread::UI, FROM_HERE,
+      base::Bind(&PdfViewerUI::OnPdfStreamResponseStarted,
+                 base::Unretained(this), resource_response_head.headers,
+                 resource_response_head.mime_type));
+}
+
+void PdfViewerUI::OnPdfStreamCreated(
+    std::unique_ptr<content::StreamInfo> stream) {
+  stream_ = std::move(stream);
+}
+
+void PdfViewerUI::RenderFrameCreated(content::RenderFrameHost* rfh) {
+  int render_process_id = rfh->GetProcess()->GetID();
+  int render_frame_id = rfh->GetRoutingID();
+  int render_view_id = rfh->GetRenderViewHost()->GetRoutingID();
+  auto resource_context =
+      web_contents()->GetBrowserContext()->GetResourceContext();
+  BrowserThread::PostTask(
+      BrowserThread::IO, FROM_HERE,
+      base::Bind(
+          &RequestPdfResource, GURL(src_), GURL(kPdfViewerUIOrigin),
+          render_process_id, render_view_id, render_frame_id, resource_context,
+          base::Bind(&PdfViewerUI::OnPdfStreamCreated, base::Unretained(this)),
+          this));
+}
+
 void PdfViewerUI::OnSaveURLAs(const GURL& url,
                               const content::Referrer& referrer) {
   web_contents()->SaveFrame(url, referrer);

+ 22 - 2
atom/browser/ui/webui/pdf_viewer_ui.h

@@ -7,6 +7,7 @@
 
 #include <string>
 
+#include "atom/browser/loader/layered_resource_handler.h"
 #include "base/macros.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "content/public/browser/web_ui_controller.h"
@@ -14,29 +15,48 @@
 
 namespace content {
 class BrowserContext;
+class ResourceContext;
 struct StreamInfo;
 }
 
+namespace net {
+class HttpResponseHeaders;
+}
+
 namespace atom {
 
+class PdfViewerHandler;
+
 class PdfViewerUI : public content::WebUIController,
-                    public content::WebContentsObserver {
+                    public content::WebContentsObserver,
+                    public LayeredResourceHandler::Delegate {
  public:
   PdfViewerUI(content::BrowserContext* browser_context,
               content::WebUI* web_ui,
-              const std::string& stream_id,
               const std::string& src);
   ~PdfViewerUI() override;
 
   // content::WebContentsObserver:
   bool OnMessageReceived(const IPC::Message& message,
                          content::RenderFrameHost* render_frame_host) override;
+  void RenderFrameCreated(content::RenderFrameHost* rfh) override;
+
+  // LayeredResourceHandler:
+  void OnResponseStarted(content::ResourceResponse* response) override;
 
  private:
+  void OnPdfStreamCreated(std::unique_ptr<content::StreamInfo> stream_info);
+  void OnPdfStreamResponseStarted(
+      scoped_refptr<net::HttpResponseHeaders> headers,
+      const std::string& mime_type);
   void OnSaveURLAs(const GURL& url, const content::Referrer& referrer);
 
   // Source URL from where the PDF originates.
   std::string src_;
+
+  PdfViewerHandler* pdf_handler_;
+
+  // Pdf Resource stream.
   std::unique_ptr<content::StreamInfo> stream_;
 
   DISALLOW_COPY_AND_ASSIGN(PdfViewerUI);

+ 2 - 0
filenames.gypi

@@ -213,6 +213,8 @@
       'atom/browser/javascript_environment.h',
       'atom/browser/lib/bluetooth_chooser.cc',
       'atom/browser/lib/bluetooth_chooser.h',
+      'atom/browser/loader/layered_resource_handler.cc',
+      'atom/browser/loader/layered_resource_handler.h',
       'atom/browser/login_handler.cc',
       'atom/browser/login_handler.h',
       'atom/browser/mac/atom_application.h',