blob: fc127b7b67bea734463cd2d5b0756b59beba58ae [file] [log] [blame]
/*
* Copyright (C) 2015 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
#include "MockContentFilter.h"
#if ENABLE(CONTENT_FILTERING)
#include "ContentFilter.h"
#include "ContentFilterUnblockHandler.h"
#include "Logging.h"
#include "ResourceRequest.h"
#include "ResourceResponse.h"
#include "SharedBuffer.h"
#include <mutex>
#include <wtf/text/CString.h>
namespace WebCore {
using Decision = MockContentFilterSettings::Decision;
using DecisionPoint = MockContentFilterSettings::DecisionPoint;
void MockContentFilter::ensureInstalled()
{
static std::once_flag onceFlag;
std::call_once(onceFlag, []{
ContentFilter::addType<MockContentFilter>();
});
}
static inline MockContentFilterSettings& settings()
{
return MockContentFilterSettings::singleton();
}
bool MockContentFilter::enabled()
{
bool enabled = settings().enabled();
LOG(ContentFiltering, "MockContentFilter is %s.\n", enabled ? "enabled" : "not enabled");
return enabled;
}
UniqueRef<MockContentFilter> MockContentFilter::create()
{
return makeUniqueRef<MockContentFilter>();
}
void MockContentFilter::willSendRequest(ResourceRequest& request, const ResourceResponse& redirectResponse)
{
if (!enabled()) {
m_state = State::Allowed;
return;
}
if (redirectResponse.isNull())
maybeDetermineStatus(DecisionPoint::AfterWillSendRequest);
else
maybeDetermineStatus(DecisionPoint::AfterRedirect);
if (m_state == State::Filtering)
return;
String modifiedRequestURLString { settings().modifiedRequestURL() };
if (modifiedRequestURLString.isEmpty())
return;
URL modifiedRequestURL { request.url(), modifiedRequestURLString };
if (!modifiedRequestURL.isValid()) {
LOG(ContentFiltering, "MockContentFilter failed to convert %s to a URL.\n", modifiedRequestURL.string().ascii().data());
return;
}
request.setURL(modifiedRequestURL);
}
void MockContentFilter::responseReceived(const ResourceResponse&)
{
maybeDetermineStatus(DecisionPoint::AfterResponse);
}
void MockContentFilter::addData(const uint8_t*, int)
{
maybeDetermineStatus(DecisionPoint::AfterAddData);
}
void MockContentFilter::finishedAddingData()
{
maybeDetermineStatus(DecisionPoint::AfterFinishedAddingData);
}
Ref<SharedBuffer> MockContentFilter::replacementData() const
{
ASSERT(didBlockData());
return SharedBuffer::create(m_replacementData.data(), m_replacementData.size());
}
ContentFilterUnblockHandler MockContentFilter::unblockHandler() const
{
ASSERT(didBlockData());
using DecisionHandlerFunction = ContentFilterUnblockHandler::DecisionHandlerFunction;
return ContentFilterUnblockHandler {
MockContentFilterSettings::unblockURLHost(), [](DecisionHandlerFunction decisionHandler) {
bool shouldAllow { settings().unblockRequestDecision() == Decision::Allow };
if (shouldAllow)
settings().setDecision(Decision::Allow);
LOG(ContentFiltering, "MockContentFilter %s the unblock request.\n", shouldAllow ? "allowed" : "did not allow");
decisionHandler(shouldAllow);
}
};
}
String MockContentFilter::unblockRequestDeniedScript() const
{
return "unblockRequestDenied()"_s;
}
void MockContentFilter::maybeDetermineStatus(DecisionPoint decisionPoint)
{
if (m_state != State::Filtering || decisionPoint != settings().decisionPoint())
return;
LOG(ContentFiltering, "MockContentFilter stopped buffering with state %u at decision point %u.\n", m_state, decisionPoint);
m_state = settings().decision() == Decision::Allow ? State::Allowed : State::Blocked;
if (m_state != State::Blocked)
return;
m_replacementData.clear();
const CString utf8BlockedString = settings().blockedString().utf8();
m_replacementData.append(utf8BlockedString.data(), utf8BlockedString.length());
}
} // namespace WebCore
#endif // ENABLE(CONTENT_FILTERING)