2012-10-08 19:47:37 +02:00
|
|
|
// 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.
|
|
|
|
|
2015-11-26 03:53:12 +01:00
|
|
|
#include "libcef/browser/net/internal_scheme_handler.h"
|
2015-07-16 23:40:01 +02:00
|
|
|
|
2012-10-08 19:47:37 +02:00
|
|
|
#include <string>
|
2016-01-06 20:20:54 +01:00
|
|
|
#include <utility>
|
2015-07-16 23:40:01 +02:00
|
|
|
|
2020-06-28 23:05:36 +02:00
|
|
|
#include "libcef/common/app_manager.h"
|
2015-07-16 23:40:01 +02:00
|
|
|
|
2020-07-08 19:23:29 +02:00
|
|
|
#include "base/notreached.h"
|
2013-06-22 04:06:32 +02:00
|
|
|
#include "base/strings/string_util.h"
|
2015-07-16 23:40:01 +02:00
|
|
|
#include "base/strings/utf_string_conversions.h"
|
2015-08-06 20:47:42 +02:00
|
|
|
#include "base/threading/thread_restrictions.h"
|
2015-07-16 23:40:01 +02:00
|
|
|
#include "net/base/mime_util.h"
|
2012-10-08 19:47:37 +02:00
|
|
|
#include "ui/base/resource/resource_bundle.h"
|
|
|
|
|
|
|
|
namespace scheme {
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
2015-07-16 23:40:01 +02:00
|
|
|
base::FilePath FilePathFromASCII(const std::string& str) {
|
2022-01-24 18:58:02 +01:00
|
|
|
#if BUILDFLAG(IS_WIN)
|
2021-04-21 00:52:34 +02:00
|
|
|
return base::FilePath(base::ASCIIToWide(str));
|
2015-07-16 23:40:01 +02:00
|
|
|
#else
|
|
|
|
return base::FilePath(str);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2016-09-01 12:32:56 +02:00
|
|
|
std::string GetMimeType(const std::string& filename) {
|
2015-08-06 20:47:42 +02:00
|
|
|
// Requests should not block on the disk! On POSIX this goes to disk.
|
|
|
|
// http://code.google.com/p/chromium/issues/detail?id=59849
|
2022-11-15 18:50:53 +01:00
|
|
|
base::ScopedAllowBlockingForTesting allow_blocking;
|
2015-08-06 20:47:42 +02:00
|
|
|
|
2015-07-16 23:40:01 +02:00
|
|
|
std::string mime_type;
|
2015-10-09 17:23:12 +02:00
|
|
|
const base::FilePath& file_path = FilePathFromASCII(filename);
|
2023-01-02 23:59:03 +01:00
|
|
|
if (net::GetMimeTypeFromFile(file_path, &mime_type)) {
|
2015-07-16 23:40:01 +02:00
|
|
|
return mime_type;
|
2023-01-02 23:59:03 +01:00
|
|
|
}
|
2015-07-16 23:40:01 +02:00
|
|
|
|
2015-10-09 17:23:12 +02:00
|
|
|
// 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());
|
2023-01-02 23:59:03 +01:00
|
|
|
if (extension == ".md") {
|
2022-03-15 18:06:58 +01:00
|
|
|
return "text/markdown";
|
2023-01-02 23:59:03 +01:00
|
|
|
}
|
|
|
|
if (extension == ".woff2") {
|
2015-10-09 17:23:12 +02:00
|
|
|
return "application/font-woff2";
|
2023-01-02 23:59:03 +01:00
|
|
|
}
|
2015-10-09 17:23:12 +02:00
|
|
|
|
2012-10-08 19:47:37 +02:00
|
|
|
NOTREACHED() << "No known mime type for file: " << filename.c_str();
|
|
|
|
return "text/plain";
|
|
|
|
}
|
|
|
|
|
|
|
|
class RedirectHandler : public CefResourceHandler {
|
|
|
|
public:
|
2017-05-17 11:29:28 +02:00
|
|
|
explicit RedirectHandler(const GURL& url) : url_(url) {}
|
2012-10-08 19:47:37 +02:00
|
|
|
|
2021-12-06 21:40:25 +01:00
|
|
|
RedirectHandler(const RedirectHandler&) = delete;
|
|
|
|
RedirectHandler& operator=(const RedirectHandler&) = delete;
|
|
|
|
|
2019-12-31 13:24:10 +01:00
|
|
|
bool Open(CefRefPtr<CefRequest> request,
|
|
|
|
bool& handle_request,
|
|
|
|
CefRefPtr<CefCallback> callback) override {
|
|
|
|
// Continue immediately.
|
|
|
|
handle_request = true;
|
2012-10-08 19:47:37 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-11-12 20:25:15 +01:00
|
|
|
void GetResponseHeaders(CefRefPtr<CefResponse> response,
|
|
|
|
int64& response_length,
|
|
|
|
CefString& redirectUrl) override {
|
2012-10-08 19:47:37 +02:00
|
|
|
response_length = 0;
|
|
|
|
redirectUrl = url_.spec();
|
|
|
|
}
|
|
|
|
|
2019-12-31 13:24:10 +01:00
|
|
|
bool Read(void* data_out,
|
|
|
|
int bytes_to_read,
|
|
|
|
int& bytes_read,
|
|
|
|
CefRefPtr<CefResourceReadCallback> callback) override {
|
|
|
|
NOTREACHED();
|
2012-10-08 19:47:37 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-05-17 11:29:28 +02:00
|
|
|
void Cancel() override {}
|
2012-10-08 19:47:37 +02:00
|
|
|
|
|
|
|
private:
|
|
|
|
GURL url_;
|
|
|
|
|
|
|
|
IMPLEMENT_REFCOUNTING(RedirectHandler);
|
|
|
|
};
|
|
|
|
|
|
|
|
class InternalHandler : public CefResourceHandler {
|
|
|
|
public:
|
|
|
|
InternalHandler(const std::string& mime_type,
|
|
|
|
CefRefPtr<CefStreamReader> reader,
|
|
|
|
int size)
|
2017-05-17 11:29:28 +02:00
|
|
|
: mime_type_(mime_type), reader_(reader), size_(size) {}
|
2012-10-08 19:47:37 +02:00
|
|
|
|
2021-12-06 21:40:25 +01:00
|
|
|
InternalHandler(const InternalHandler&) = delete;
|
|
|
|
InternalHandler& operator=(const InternalHandler&) = delete;
|
|
|
|
|
2019-12-31 13:24:10 +01:00
|
|
|
bool Open(CefRefPtr<CefRequest> request,
|
|
|
|
bool& handle_request,
|
|
|
|
CefRefPtr<CefCallback> callback) override {
|
|
|
|
// Continue immediately.
|
|
|
|
handle_request = true;
|
2012-10-08 19:47:37 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-11-12 20:25:15 +01:00
|
|
|
void GetResponseHeaders(CefRefPtr<CefResponse> response,
|
|
|
|
int64& response_length,
|
|
|
|
CefString& redirectUrl) override {
|
2012-10-08 19:47:37 +02:00
|
|
|
response_length = size_;
|
|
|
|
|
|
|
|
response->SetMimeType(mime_type_);
|
|
|
|
response->SetStatus(200);
|
|
|
|
}
|
|
|
|
|
2019-12-31 13:24:10 +01:00
|
|
|
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);
|
|
|
|
|
2012-10-08 19:47:37 +02:00
|
|
|
return (bytes_read > 0);
|
|
|
|
}
|
|
|
|
|
2017-05-17 11:29:28 +02:00
|
|
|
void Cancel() override {}
|
2012-10-08 19:47:37 +02:00
|
|
|
|
|
|
|
private:
|
|
|
|
std::string mime_type_;
|
|
|
|
CefRefPtr<CefStreamReader> reader_;
|
|
|
|
int size_;
|
|
|
|
|
|
|
|
IMPLEMENT_REFCOUNTING(InternalHandler);
|
|
|
|
};
|
|
|
|
|
|
|
|
class InternalHandlerFactory : public CefSchemeHandlerFactory {
|
|
|
|
public:
|
|
|
|
explicit InternalHandlerFactory(
|
2016-04-27 22:38:52 +02:00
|
|
|
std::unique_ptr<InternalHandlerDelegate> delegate)
|
2017-05-17 11:29:28 +02:00
|
|
|
: delegate_(std::move(delegate)) {}
|
2012-10-08 19:47:37 +02:00
|
|
|
|
2021-12-06 21:40:25 +01:00
|
|
|
InternalHandlerFactory(const InternalHandlerFactory&) = delete;
|
|
|
|
InternalHandlerFactory& operator=(const InternalHandlerFactory&) = delete;
|
|
|
|
|
2017-05-17 11:29:28 +02:00
|
|
|
CefRefPtr<CefResourceHandler> Create(CefRefPtr<CefBrowser> browser,
|
|
|
|
CefRefPtr<CefFrame> frame,
|
|
|
|
const CefString& scheme_name,
|
|
|
|
CefRefPtr<CefRequest> request) override {
|
2012-10-08 19:47:37 +02:00
|
|
|
GURL url = GURL(request->GetURL().ToString());
|
|
|
|
|
|
|
|
InternalHandlerDelegate::Action action;
|
2015-03-02 21:25:14 +01:00
|
|
|
if (delegate_->OnRequest(browser, request, &action)) {
|
2023-01-02 23:59:03 +01:00
|
|
|
if (!action.redirect_url.is_empty() && action.redirect_url.is_valid()) {
|
2012-10-08 19:47:37 +02:00
|
|
|
return new RedirectHandler(action.redirect_url);
|
2023-01-02 23:59:03 +01:00
|
|
|
}
|
2012-10-08 19:47:37 +02:00
|
|
|
|
2023-01-02 23:59:03 +01:00
|
|
|
if (action.mime_type.empty()) {
|
2012-10-08 19:47:37 +02:00
|
|
|
action.mime_type = GetMimeType(url.path());
|
2023-01-02 23:59:03 +01:00
|
|
|
}
|
2012-10-08 19:47:37 +02:00
|
|
|
|
2020-02-10 18:10:17 +01:00
|
|
|
if (!action.bytes && action.resource_id >= 0) {
|
2020-07-02 20:45:16 +02:00
|
|
|
std::string str =
|
|
|
|
ui::ResourceBundle::GetSharedInstance().LoadDataResourceString(
|
2020-06-28 23:05:36 +02:00
|
|
|
action.resource_id);
|
2020-07-02 20:45:16 +02:00
|
|
|
if (str.empty()) {
|
2017-05-17 11:29:28 +02:00
|
|
|
NOTREACHED() << "Failed to load internal resource for id: "
|
|
|
|
<< action.resource_id << " URL: " << url.spec().c_str();
|
2020-01-15 14:36:24 +01:00
|
|
|
return nullptr;
|
2012-10-08 19:47:37 +02:00
|
|
|
}
|
2022-11-15 18:50:53 +01:00
|
|
|
action.bytes =
|
|
|
|
base::MakeRefCounted<base::RefCountedString>(std::move(str));
|
2012-10-08 19:47:37 +02:00
|
|
|
}
|
|
|
|
|
2020-02-10 18:10:17 +01:00
|
|
|
if (action.bytes) {
|
2017-07-06 22:39:37 +02:00
|
|
|
action.stream = CefStreamReader::CreateForData(
|
2020-02-10 18:10:17 +01:00
|
|
|
const_cast<unsigned char*>(action.bytes->data()),
|
|
|
|
action.bytes->size());
|
|
|
|
action.stream_size = action.bytes->size();
|
2017-07-06 22:39:37 +02:00
|
|
|
}
|
|
|
|
|
2012-10-08 19:47:37 +02:00
|
|
|
if (action.stream.get()) {
|
|
|
|
return new InternalHandler(action.mime_type, action.stream,
|
2017-05-17 11:29:28 +02:00
|
|
|
action.stream_size);
|
2012-10-08 19:47:37 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-15 14:36:24 +01:00
|
|
|
return nullptr;
|
2012-10-08 19:47:37 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
2016-04-27 22:38:52 +02:00
|
|
|
std::unique_ptr<InternalHandlerDelegate> delegate_;
|
2012-10-08 19:47:37 +02:00
|
|
|
|
|
|
|
IMPLEMENT_REFCOUNTING(InternalHandlerFactory);
|
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
|
2017-05-17 11:29:28 +02:00
|
|
|
InternalHandlerDelegate::Action::Action() : stream_size(-1), resource_id(-1) {}
|
2012-10-08 19:47:37 +02:00
|
|
|
|
|
|
|
CefRefPtr<CefSchemeHandlerFactory> CreateInternalHandlerFactory(
|
2016-04-27 22:38:52 +02:00
|
|
|
std::unique_ptr<InternalHandlerDelegate> delegate) {
|
2012-10-08 19:47:37 +02:00
|
|
|
DCHECK(delegate.get());
|
2016-01-06 20:20:54 +01:00
|
|
|
return new InternalHandlerFactory(std::move(delegate));
|
2012-10-08 19:47:37 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace scheme
|