| // Copyright (c) 2012 The Chromium Embedded Framework Authors. |
| // Portions copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "libcef/browser/net/internal_scheme_handler.h" |
| |
| #include <string> |
| #include <utility> |
| |
| #include "libcef/common/content_client.h" |
| |
| #include "base/strings/string_util.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "base/threading/thread_restrictions.h" |
| #include "net/base/mime_util.h" |
| #include "ui/base/resource/resource_bundle.h" |
| |
| namespace scheme { |
| |
| namespace { |
| |
| base::FilePath FilePathFromASCII(const std::string& str) { |
| #if defined(OS_WIN) |
| return base::FilePath(base::ASCIIToUTF16(str)); |
| #else |
| return base::FilePath(str); |
| #endif |
| } |
| |
| std::string GetMimeType(const std::string& filename) { |
| // Requests should not block on the disk! On POSIX this goes to disk. |
| // http://code.google.com/p/chromium/issues/detail?id=59849 |
| base::ThreadRestrictions::ScopedAllowIO allow_io; |
| |
| std::string mime_type; |
| const base::FilePath& file_path = FilePathFromASCII(filename); |
| if (net::GetMimeTypeFromFile(file_path, &mime_type)) |
| return mime_type; |
| |
| // Check for newer extensions used by internal resources but not yet |
| // recognized by the mime type detector. |
| const std::string& extension = CefString(file_path.FinalExtension()); |
| if (extension == ".woff2") |
| return "application/font-woff2"; |
| |
| NOTREACHED() << "No known mime type for file: " << filename.c_str(); |
| return "text/plain"; |
| } |
| |
| class RedirectHandler : public CefResourceHandler { |
| public: |
| explicit RedirectHandler(const GURL& url) : url_(url) {} |
| |
| bool Open(CefRefPtr<CefRequest> request, |
| bool& handle_request, |
| CefRefPtr<CefCallback> callback) override { |
| // Continue immediately. |
| handle_request = true; |
| return true; |
| } |
| |
| void GetResponseHeaders(CefRefPtr<CefResponse> response, |
| int64& response_length, |
| CefString& redirectUrl) override { |
| response_length = 0; |
| redirectUrl = url_.spec(); |
| } |
| |
| bool Read(void* data_out, |
| int bytes_to_read, |
| int& bytes_read, |
| CefRefPtr<CefResourceReadCallback> callback) override { |
| NOTREACHED(); |
| return false; |
| } |
| |
| void Cancel() override {} |
| |
| private: |
| GURL url_; |
| |
| IMPLEMENT_REFCOUNTING(RedirectHandler); |
| DISALLOW_COPY_AND_ASSIGN(RedirectHandler); |
| }; |
| |
| class InternalHandler : public CefResourceHandler { |
| public: |
| InternalHandler(const std::string& mime_type, |
| CefRefPtr<CefStreamReader> reader, |
| int size) |
| : mime_type_(mime_type), reader_(reader), size_(size) {} |
| |
| bool Open(CefRefPtr<CefRequest> request, |
| bool& handle_request, |
| CefRefPtr<CefCallback> callback) override { |
| // Continue immediately. |
| handle_request = true; |
| return true; |
| } |
| |
| void GetResponseHeaders(CefRefPtr<CefResponse> response, |
| int64& response_length, |
| CefString& redirectUrl) override { |
| response_length = size_; |
| |
| response->SetMimeType(mime_type_); |
| response->SetStatus(200); |
| } |
| |
| bool Read(void* data_out, |
| int bytes_to_read, |
| int& bytes_read, |
| CefRefPtr<CefResourceReadCallback> callback) override { |
| // Read until the buffer is full or until Read() returns 0 to indicate no |
| // more data. |
| bytes_read = 0; |
| int read = 0; |
| do { |
| read = static_cast<int>( |
| reader_->Read(static_cast<char*>(data_out) + bytes_read, 1, |
| bytes_to_read - bytes_read)); |
| bytes_read += read; |
| } while (read != 0 && bytes_read < bytes_to_read); |
| |
| return (bytes_read > 0); |
| } |
| |
| void Cancel() override {} |
| |
| private: |
| std::string mime_type_; |
| CefRefPtr<CefStreamReader> reader_; |
| int size_; |
| |
| IMPLEMENT_REFCOUNTING(InternalHandler); |
| DISALLOW_COPY_AND_ASSIGN(InternalHandler); |
| }; |
| |
| class InternalHandlerFactory : public CefSchemeHandlerFactory { |
| public: |
| explicit InternalHandlerFactory( |
| std::unique_ptr<InternalHandlerDelegate> delegate) |
| : delegate_(std::move(delegate)) {} |
| |
| CefRefPtr<CefResourceHandler> Create(CefRefPtr<CefBrowser> browser, |
| CefRefPtr<CefFrame> frame, |
| const CefString& scheme_name, |
| CefRefPtr<CefRequest> request) override { |
| GURL url = GURL(request->GetURL().ToString()); |
| |
| InternalHandlerDelegate::Action action; |
| if (delegate_->OnRequest(browser, request, &action)) { |
| if (!action.redirect_url.is_empty() && action.redirect_url.is_valid()) |
| return new RedirectHandler(action.redirect_url); |
| |
| if (action.mime_type.empty()) |
| action.mime_type = GetMimeType(url.path()); |
| |
| if (!action.bytes && action.resource_id >= 0) { |
| std::string str = |
| ui::ResourceBundle::GetSharedInstance().LoadDataResourceString( |
| action.resource_id); |
| if (str.empty()) { |
| NOTREACHED() << "Failed to load internal resource for id: " |
| << action.resource_id << " URL: " << url.spec().c_str(); |
| return nullptr; |
| } |
| action.bytes = base::RefCountedString::TakeString(&str); |
| } |
| |
| if (action.bytes) { |
| action.stream = CefStreamReader::CreateForData( |
| const_cast<unsigned char*>(action.bytes->data()), |
| action.bytes->size()); |
| action.stream_size = action.bytes->size(); |
| } |
| |
| if (action.stream.get()) { |
| return new InternalHandler(action.mime_type, action.stream, |
| action.stream_size); |
| } |
| } |
| |
| return nullptr; |
| } |
| |
| private: |
| std::unique_ptr<InternalHandlerDelegate> delegate_; |
| |
| IMPLEMENT_REFCOUNTING(InternalHandlerFactory); |
| DISALLOW_COPY_AND_ASSIGN(InternalHandlerFactory); |
| }; |
| |
| } // namespace |
| |
| InternalHandlerDelegate::Action::Action() : stream_size(-1), resource_id(-1) {} |
| |
| CefRefPtr<CefSchemeHandlerFactory> CreateInternalHandlerFactory( |
| std::unique_ptr<InternalHandlerDelegate> delegate) { |
| DCHECK(delegate.get()); |
| return new InternalHandlerFactory(std::move(delegate)); |
| } |
| |
| } // namespace scheme |