// 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 #include #include "libcef/common/app_manager.h" #include "base/notreached.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 BUILDFLAG(IS_WIN) return base::FilePath(base::ASCIIToWide(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::ScopedAllowBlockingForTesting allow_blocking; 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 == ".md") { return "text/markdown"; } if (extension == ".woff2") { return "application/font-woff2"; } DCHECK(false) << "No known mime type for file: " << filename.c_str(); return "text/plain"; } class RedirectHandler : public CefResourceHandler { public: explicit RedirectHandler(const GURL& url) : url_(url) {} RedirectHandler(const RedirectHandler&) = delete; RedirectHandler& operator=(const RedirectHandler&) = delete; bool Open(CefRefPtr request, bool& handle_request, CefRefPtr callback) override { // Continue immediately. handle_request = true; return true; } void GetResponseHeaders(CefRefPtr 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 callback) override { DCHECK(false); return false; } void Cancel() override {} private: GURL url_; IMPLEMENT_REFCOUNTING(RedirectHandler); }; class InternalHandler : public CefResourceHandler { public: InternalHandler(const std::string& mime_type, CefRefPtr reader, int size) : mime_type_(mime_type), reader_(reader), size_(size) {} InternalHandler(const InternalHandler&) = delete; InternalHandler& operator=(const InternalHandler&) = delete; bool Open(CefRefPtr request, bool& handle_request, CefRefPtr callback) override { // Continue immediately. handle_request = true; return true; } void GetResponseHeaders(CefRefPtr 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 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( reader_->Read(static_cast(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 reader_; int size_; IMPLEMENT_REFCOUNTING(InternalHandler); }; class InternalHandlerFactory : public CefSchemeHandlerFactory { public: explicit InternalHandlerFactory( std::unique_ptr delegate) : delegate_(std::move(delegate)) {} InternalHandlerFactory(const InternalHandlerFactory&) = delete; InternalHandlerFactory& operator=(const InternalHandlerFactory&) = delete; CefRefPtr Create(CefRefPtr browser, CefRefPtr frame, const CefString& scheme_name, CefRefPtr 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()) { DCHECK(false) << "Failed to load internal resource for id: " << action.resource_id << " URL: " << url.spec().c_str(); return nullptr; } action.bytes = base::MakeRefCounted(std::move(str)); } if (action.bytes) { action.stream = CefStreamReader::CreateForData( const_cast(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 delegate_; IMPLEMENT_REFCOUNTING(InternalHandlerFactory); }; } // namespace InternalHandlerDelegate::Action::Action() : stream_size(-1), resource_id(-1) {} CefRefPtr CreateInternalHandlerFactory( std::unique_ptr delegate) { DCHECK(delegate.get()); return new InternalHandlerFactory(std::move(delegate)); } } // namespace scheme