Add support for response filtering (issue #515).

- Add a new CefRequestHandler::GetResourceResponseFilter method and
  CefResponseFilter class.
This commit is contained in:
Marshall Greenblatt
2015-12-04 21:58:56 -05:00
parent 864db71f6b
commit f207a555a3
40 changed files with 1765 additions and 6 deletions

View File

@ -8,17 +8,23 @@
#include "include/cef_urlrequest.h"
#include "libcef/browser/browser_host_impl.h"
#include "libcef/browser/net/response_filter_wrapper.h"
#include "libcef/browser/net/url_request_user_data.h"
#include "libcef/browser/thread_util.h"
#include "libcef/common/request_impl.h"
#include "libcef/common/response_impl.h"
#include "net/base/net_errors.h"
#include "net/filter/filter.h"
#include "net/http/http_util.h"
#include "net/url_request/url_request.h"
namespace {
// Buffer size allocated when filtering data.
// Should match the value in net/filter/filter.cc.
const int kFilterBufSize = 32 * 1024;
class CefBeforeResourceLoadCallbackImpl : public CefRequestCallback {
public:
typedef net::CompletionCallback CallbackType;
@ -380,3 +386,55 @@ bool CefNetworkDelegate::OnCanAccessFile(const net::URLRequest& request,
const base::FilePath& path) const {
return true;
}
net::Filter* CefNetworkDelegate::SetupFilter(net::URLRequest* request,
net::Filter* filter_list) {
CefRefPtr<CefResponseFilter> cef_filter;
CefRefPtr<CefBrowserHostImpl> browser =
CefBrowserHostImpl::GetBrowserForRequest(request);
if (browser.get()) {
CefRefPtr<CefClient> client = browser->GetClient();
if (client.get()) {
CefRefPtr<CefRequestHandler> handler = client->GetRequestHandler();
if (handler.get()) {
CefRefPtr<CefFrame> frame = browser->GetFrameForRequest(request);
CefRefPtr<CefRequestImpl> cefRequest = new CefRequestImpl();
cefRequest->Set(request);
cefRequest->SetReadOnly(true);
CefRefPtr<CefResponseImpl> cefResponse = new CefResponseImpl();
cefResponse->Set(request);
cefResponse->SetReadOnly(true);
cef_filter = handler->GetResourceResponseFilter(browser.get(), frame,
cefRequest.get(),
cefResponse.get());
}
}
}
if (cef_filter.get() && cef_filter->InitFilter()) {
scoped_ptr<CefResponseFilterWrapper> wrapper(
new CefResponseFilterWrapper(cef_filter, filter_list != nullptr));
wrapper->InitBuffer(kFilterBufSize);
if (filter_list) {
// Install the wrapper at the end of the filter list.
net::Filter* last_filter = filter_list;
do {
if (!last_filter->next_filter_.get()) {
last_filter->next_filter_ = wrapper.Pass();
break;
}
last_filter = last_filter->next_filter_.get();
} while (last_filter);
} else {
// Only the wrapper exists.
filter_list = wrapper.release();
}
}
return filter_list;
}

View File

@ -28,6 +28,8 @@ class CefNetworkDelegate : public net::NetworkDelegateImpl {
void OnCompleted(net::URLRequest* request, bool started) override;
bool OnCanAccessFile(const net::URLRequest& request,
const base::FilePath& path) const override;
net::Filter* SetupFilter(net::URLRequest* request,
net::Filter* filter_list) override;
DISALLOW_COPY_AND_ASSIGN(CefNetworkDelegate);
};

View File

@ -577,7 +577,8 @@ void CefResourceRequestJob::FetchResponseCookies(
}
void CefResourceRequestJob::DoneWithRequest() {
DCHECK(!done_);
if (done_)
return;
done_ = true;
if (request_)

View File

@ -0,0 +1,71 @@
// Copyright 2014 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/response_filter_wrapper.h"
#include "base/logging.h"
// FilterType is used for logging purposes only.
CefResponseFilterWrapper::CefResponseFilterWrapper(
CefRefPtr<CefResponseFilter> cef_filter,
bool has_other_filters)
: Filter(Filter::FILTER_TYPE_UNSUPPORTED),
cef_filter_(cef_filter),
has_other_filters_(has_other_filters) {
DCHECK(cef_filter_.get());
}
CefResponseFilterWrapper::~CefResponseFilterWrapper() {
}
net::Filter::FilterStatus CefResponseFilterWrapper::ReadFilteredData(
char* dest_buffer,
int* dest_len) {
if (!dest_buffer || !dest_len || *dest_len <= 0)
return net::Filter::FILTER_ERROR;
size_t data_in_size = static_cast<size_t>(stream_data_len_);
size_t data_in_read = 0;
size_t data_out_size = static_cast<size_t>(*dest_len);
size_t data_out_write = 0;
cef_response_filter_status_t cef_status = cef_filter_->Filter(
next_stream_data_, data_in_size, data_in_read,
dest_buffer, data_out_size, data_out_write);
// Return early if there's an error.
if (cef_status == RESPONSE_FILTER_ERROR)
return net::Filter::FILTER_ERROR;
// Normalize the out values.
if (data_in_read > data_in_size) {
LOG(ERROR) <<
"potential buffer overflow; data_in_read exceeds data_in_size";
data_in_read = data_in_size;
}
if (data_out_write > data_out_size) {
LOG(ERROR) <<
"potential buffer overflow; data_out_write exceeds data_out_size";
data_out_write = data_out_size;
}
// Output the number of bytes written.
*dest_len = static_cast<int>(data_out_write);
if (data_in_size - data_in_read > 0U) {
// There are bytes left so adjust the stream pointer and return FILTER_OK.
next_stream_data_ += data_in_read;
stream_data_len_ -= static_cast<int>(data_in_read);
return Filter::FILTER_OK;
}
// No bytes left. Might need more data or might be done.
// If |has_other_filters_| is true then we must return FILTER_NEED_MORE_DATA
// or additional data will not be sent.
next_stream_data_ = nullptr;
stream_data_len_ = 0;
if (cef_status == RESPONSE_FILTER_NEED_MORE_DATA || has_other_filters_)
return Filter::FILTER_NEED_MORE_DATA;
return Filter::FILTER_DONE;
}

View File

@ -0,0 +1,41 @@
// Copyright 2015 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.
#ifndef CEF_LIBCEF_BROWSER_NET_RESPONSE_FILTER_WRAPPER_H_
#define CEF_LIBCEF_BROWSER_NET_RESPONSE_FILTER_WRAPPER_H_
#include "include/cef_response_filter.h"
#include "base/basictypes.h"
#include "net/filter/filter.h"
class CefResponseFilterWrapper : public net::Filter {
public:
CefResponseFilterWrapper(CefRefPtr<CefResponseFilter> cef_filter,
bool has_other_filters);
~CefResponseFilterWrapper() override;
// Decodes the pre-filter data and writes the output into the dest_buffer
// passed in.
// The function returns FilterStatus. See filter.h for its description.
//
// Upon entry, *dest_len is the total size (in number of chars) of the
// destination buffer. Upon exit, *dest_len is the actual number of chars
// written into the destination buffer.
//
// This function will fail if there is no pre-filter data in the
// stream_buffer_. On the other hand, *dest_len can be 0 upon successful
// return. For example, the internal filter may process some pre-filter data
// but not produce output yet.
FilterStatus ReadFilteredData(char* dest_buffer, int* dest_len) override;
private:
CefRefPtr<CefResponseFilter> cef_filter_;
const bool has_other_filters_;
DISALLOW_COPY_AND_ASSIGN(CefResponseFilterWrapper);
};
#endif // CEF_LIBCEF_BROWSER_NET_RESPONSE_FILTER_WRAPPER_H_