• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2012 The Chromium Embedded Framework Authors.
2 // Portions copyright (c) 2012 The Chromium Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 
6 #include "libcef/browser/net/internal_scheme_handler.h"
7 
8 #include <string>
9 #include <utility>
10 
11 #include "libcef/common/app_manager.h"
12 
13 #include "base/notreached.h"
14 #include "base/strings/string_util.h"
15 #include "base/strings/utf_string_conversions.h"
16 #include "base/threading/thread_restrictions.h"
17 #include "net/base/mime_util.h"
18 #include "ui/base/resource/resource_bundle.h"
19 
20 namespace scheme {
21 
22 namespace {
23 
FilePathFromASCII(const std::string & str)24 base::FilePath FilePathFromASCII(const std::string& str) {
25 #if BUILDFLAG(IS_WIN)
26   return base::FilePath(base::ASCIIToWide(str));
27 #else
28   return base::FilePath(str);
29 #endif
30 }
31 
GetMimeType(const std::string & filename)32 std::string GetMimeType(const std::string& filename) {
33   // Requests should not block on the disk!  On POSIX this goes to disk.
34   // http://code.google.com/p/chromium/issues/detail?id=59849
35   base::ThreadRestrictions::ScopedAllowIO allow_io;
36 
37   std::string mime_type;
38   const base::FilePath& file_path = FilePathFromASCII(filename);
39   if (net::GetMimeTypeFromFile(file_path, &mime_type))
40     return mime_type;
41 
42   // Check for newer extensions used by internal resources but not yet
43   // recognized by the mime type detector.
44   const std::string& extension = CefString(file_path.FinalExtension());
45   if (extension == ".md")
46     return "text/markdown";
47   if (extension == ".woff2")
48     return "application/font-woff2";
49 
50   NOTREACHED() << "No known mime type for file: " << filename.c_str();
51   return "text/plain";
52 }
53 
54 class RedirectHandler : public CefResourceHandler {
55  public:
RedirectHandler(const GURL & url)56   explicit RedirectHandler(const GURL& url) : url_(url) {}
57 
58   RedirectHandler(const RedirectHandler&) = delete;
59   RedirectHandler& operator=(const RedirectHandler&) = delete;
60 
Open(CefRefPtr<CefRequest> request,bool & handle_request,CefRefPtr<CefCallback> callback)61   bool Open(CefRefPtr<CefRequest> request,
62             bool& handle_request,
63             CefRefPtr<CefCallback> callback) override {
64     // Continue immediately.
65     handle_request = true;
66     return true;
67   }
68 
GetResponseHeaders(CefRefPtr<CefResponse> response,int64 & response_length,CefString & redirectUrl)69   void GetResponseHeaders(CefRefPtr<CefResponse> response,
70                           int64& response_length,
71                           CefString& redirectUrl) override {
72     response_length = 0;
73     redirectUrl = url_.spec();
74   }
75 
Read(void * data_out,int bytes_to_read,int & bytes_read,CefRefPtr<CefResourceReadCallback> callback)76   bool Read(void* data_out,
77             int bytes_to_read,
78             int& bytes_read,
79             CefRefPtr<CefResourceReadCallback> callback) override {
80     NOTREACHED();
81     return false;
82   }
83 
Cancel()84   void Cancel() override {}
85 
86  private:
87   GURL url_;
88 
89   IMPLEMENT_REFCOUNTING(RedirectHandler);
90 };
91 
92 class InternalHandler : public CefResourceHandler {
93  public:
InternalHandler(const std::string & mime_type,CefRefPtr<CefStreamReader> reader,int size)94   InternalHandler(const std::string& mime_type,
95                   CefRefPtr<CefStreamReader> reader,
96                   int size)
97       : mime_type_(mime_type), reader_(reader), size_(size) {}
98 
99   InternalHandler(const InternalHandler&) = delete;
100   InternalHandler& operator=(const InternalHandler&) = delete;
101 
Open(CefRefPtr<CefRequest> request,bool & handle_request,CefRefPtr<CefCallback> callback)102   bool Open(CefRefPtr<CefRequest> request,
103             bool& handle_request,
104             CefRefPtr<CefCallback> callback) override {
105     // Continue immediately.
106     handle_request = true;
107     return true;
108   }
109 
GetResponseHeaders(CefRefPtr<CefResponse> response,int64 & response_length,CefString & redirectUrl)110   void GetResponseHeaders(CefRefPtr<CefResponse> response,
111                           int64& response_length,
112                           CefString& redirectUrl) override {
113     response_length = size_;
114 
115     response->SetMimeType(mime_type_);
116     response->SetStatus(200);
117   }
118 
Read(void * data_out,int bytes_to_read,int & bytes_read,CefRefPtr<CefResourceReadCallback> callback)119   bool Read(void* data_out,
120             int bytes_to_read,
121             int& bytes_read,
122             CefRefPtr<CefResourceReadCallback> callback) override {
123     // Read until the buffer is full or until Read() returns 0 to indicate no
124     // more data.
125     bytes_read = 0;
126     int read = 0;
127     do {
128       read = static_cast<int>(
129           reader_->Read(static_cast<char*>(data_out) + bytes_read, 1,
130                         bytes_to_read - bytes_read));
131       bytes_read += read;
132     } while (read != 0 && bytes_read < bytes_to_read);
133 
134     return (bytes_read > 0);
135   }
136 
Cancel()137   void Cancel() override {}
138 
139  private:
140   std::string mime_type_;
141   CefRefPtr<CefStreamReader> reader_;
142   int size_;
143 
144   IMPLEMENT_REFCOUNTING(InternalHandler);
145 };
146 
147 class InternalHandlerFactory : public CefSchemeHandlerFactory {
148  public:
InternalHandlerFactory(std::unique_ptr<InternalHandlerDelegate> delegate)149   explicit InternalHandlerFactory(
150       std::unique_ptr<InternalHandlerDelegate> delegate)
151       : delegate_(std::move(delegate)) {}
152 
153   InternalHandlerFactory(const InternalHandlerFactory&) = delete;
154   InternalHandlerFactory& operator=(const InternalHandlerFactory&) = delete;
155 
Create(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,const CefString & scheme_name,CefRefPtr<CefRequest> request)156   CefRefPtr<CefResourceHandler> Create(CefRefPtr<CefBrowser> browser,
157                                        CefRefPtr<CefFrame> frame,
158                                        const CefString& scheme_name,
159                                        CefRefPtr<CefRequest> request) override {
160     GURL url = GURL(request->GetURL().ToString());
161 
162     InternalHandlerDelegate::Action action;
163     if (delegate_->OnRequest(browser, request, &action)) {
164       if (!action.redirect_url.is_empty() && action.redirect_url.is_valid())
165         return new RedirectHandler(action.redirect_url);
166 
167       if (action.mime_type.empty())
168         action.mime_type = GetMimeType(url.path());
169 
170       if (!action.bytes && action.resource_id >= 0) {
171         std::string str =
172             ui::ResourceBundle::GetSharedInstance().LoadDataResourceString(
173                 action.resource_id);
174         if (str.empty()) {
175           NOTREACHED() << "Failed to load internal resource for id: "
176                        << action.resource_id << " URL: " << url.spec().c_str();
177           return nullptr;
178         }
179         action.bytes = base::RefCountedString::TakeString(&str);
180       }
181 
182       if (action.bytes) {
183         action.stream = CefStreamReader::CreateForData(
184             const_cast<unsigned char*>(action.bytes->data()),
185             action.bytes->size());
186         action.stream_size = action.bytes->size();
187       }
188 
189       if (action.stream.get()) {
190         return new InternalHandler(action.mime_type, action.stream,
191                                    action.stream_size);
192       }
193     }
194 
195     return nullptr;
196   }
197 
198  private:
199   std::unique_ptr<InternalHandlerDelegate> delegate_;
200 
201   IMPLEMENT_REFCOUNTING(InternalHandlerFactory);
202 };
203 
204 }  // namespace
205 
Action()206 InternalHandlerDelegate::Action::Action() : stream_size(-1), resource_id(-1) {}
207 
CreateInternalHandlerFactory(std::unique_ptr<InternalHandlerDelegate> delegate)208 CefRefPtr<CefSchemeHandlerFactory> CreateInternalHandlerFactory(
209     std::unique_ptr<InternalHandlerDelegate> delegate) {
210   DCHECK(delegate.get());
211   return new InternalHandlerFactory(std::move(delegate));
212 }
213 
214 }  // namespace scheme
215