NetworkCaptureEvent.cpp [plain text]
#include "config.h"
#include "NetworkCaptureEvent.h"
#if ENABLE(NETWORK_CAPTURE)
#include "NetworkCaptureLogging.h"
#include "json.hpp"
#include <WebCore/ResourceError.h>
#include <WebCore/ResourceRequest.h>
#include <WebCore/ResourceResponse.h>
#include <WebCore/URLParser.h>
#include <wtf/Assertions.h>
#include <wtf/Brigand.h>
#include <wtf/text/Base64.h>
namespace WebKit {
namespace NetworkCapture {
const char RequestSentEvent::typeName[] = "RequestSentEvent";
const char ResponseReceivedEvent::typeName[] = "ResponseReceivedEvent";
const char RedirectReceivedEvent::typeName[] = "RedirectReceivedEvent";
const char RedirectSentEvent::typeName[] = "RedirectSentEvent";
const char DataReceivedEvent::typeName[] = "DataReceivedEvent";
const char FinishedEvent::typeName[] = "FinishedEvent";
static Headers copyHeaders(const WebCore::HTTPHeaderMap& httpHeaders)
{
Headers headers;
for (const auto& header : httpHeaders)
headers.append(std::make_pair(header.key, header.value));
return headers;
}
Request::Request(String&& url, String&& referrer, int policy, String&& method, Headers&& headers)
: url(WTFMove(url))
, referrer(WTFMove(referrer))
, policy(WTFMove(policy))
, method(WTFMove(method))
, headers(WTFMove(headers))
{
}
Request::Request(const WebCore::ResourceRequest& request)
: url(request.url().string())
, referrer(request.httpReferrer())
, policy(static_cast<int>(request.cachePolicy()))
, method(request.httpMethod())
, headers(copyHeaders(request.httpHeaderFields()))
{
}
Request::operator WebCore::ResourceRequest() const
{
WebCore::URLParser parser(url);
WebCore::ResourceRequest request(parser.result(), referrer, static_cast<WebCore::ResourceRequestCachePolicy>(policy));
request.setHTTPMethod(method);
for (const auto& header : headers)
request.setHTTPHeaderField(header.first, header.second);
return request;
}
Response::Response(String&& url, String&& mimeType, long long expectedLength, String&& textEncodingName, String&& version, int status, String&& reason, Headers&& headers)
: url(WTFMove(url))
, mimeType(WTFMove(mimeType))
, expectedLength(WTFMove(expectedLength))
, textEncodingName(WTFMove(textEncodingName))
, status(WTFMove(status))
, reason(WTFMove(reason))
, headers(WTFMove(headers))
{
}
Response::Response(const WebCore::ResourceResponse& response)
: url(response.url().string())
, mimeType(response.mimeType())
, expectedLength(response.expectedContentLength())
, textEncodingName(response.textEncodingName())
, version(response.httpVersion())
, status(response.httpStatusCode())
, reason(response.httpStatusText())
, headers(copyHeaders(response.httpHeaderFields()))
{
}
Response::operator WebCore::ResourceResponse() const
{
WebCore::URLParser parser(url);
WebCore::ResourceResponse response(parser.result(), mimeType, expectedLength, textEncodingName);
response.setHTTPVersion(version);
response.setHTTPStatusCode(status);
response.setHTTPStatusText(reason);
for (const auto& header : headers)
response.setHTTPHeaderField(header.first, header.second);
return response;
}
Error::Error(String&& domain, String&& failingURL, String&& localizedDescription, int errorCode, int type)
: domain(WTFMove(domain))
, failingURL(WTFMove(failingURL))
, localizedDescription(WTFMove(localizedDescription))
, errorCode(WTFMove(errorCode))
, type(WTFMove(type))
{
}
Error::Error(const WebCore::ResourceError& error)
: domain(error.domain())
, failingURL(error.failingURL().string())
, localizedDescription(error.localizedDescription())
, errorCode(error.errorCode())
, type(static_cast<int>(error.type()))
{
}
Error::operator WebCore::ResourceError() const
{
WebCore::URLParser parser(failingURL);
WebCore::ResourceError error(domain, errorCode, parser.result(), localizedDescription, static_cast<WebCore::ResourceError::Type>(type));
return error;
}
using json = nlohmann::basic_json<>;
template<typename Type>
struct JSONCoder {
static json encode(Type val)
{
return json(val);
}
static Type decode(const json& jVal)
{
return jVal.get<Type>();
}
};
template<>
struct JSONCoder<const char*> {
static json encode(const char* val)
{
return json(val);
}
};
template<>
struct JSONCoder<String> {
static json encode(const String& val)
{
return json(static_cast<const char*>(val.utf8().data()));
}
static String decode(const json& jVal)
{
return String(jVal.get_ref<const std::string&>().c_str());
}
};
template<>
struct JSONCoder<CaptureTimeType> {
static json encode(const CaptureTimeType& time)
{
return JSONCoder<double>::encode(time.secondsSinceEpoch().seconds());
}
static CaptureTimeType decode(const json& jTime)
{
return CaptureTimeType::fromRawSeconds(JSONCoder<double>::decode(jTime));
}
};
template<>
struct JSONCoder<KeyValuePair> {
static json encode(const KeyValuePair& pair)
{
return json {
JSONCoder<String>::encode(pair.first),
JSONCoder<String>::encode(pair.second)
};
}
static KeyValuePair decode(const json& jPair)
{
return KeyValuePair {
JSONCoder<String>::decode(jPair[0]),
JSONCoder<String>::decode(jPair[1])
};
}
};
template<typename T>
struct JSONCoder<Vector<T>> {
static json encode(const Vector<T>& vector)
{
json jVector;
for (const auto& element : vector)
jVector.push_back(JSONCoder<T>::encode(element));
return jVector;
}
static Vector<T> decode(const json& jVector)
{
Vector<T> vector;
for (const auto& element : jVector)
vector.append(JSONCoder<T>::decode(element));
return vector;
}
};
template<>
struct JSONCoder<Request> {
static json encode(const Request& request)
{
return json {
{ "url", JSONCoder<String>::encode(request.url) },
{ "referrer", JSONCoder<String>::encode(request.referrer) },
{ "policy", JSONCoder<int>::encode(request.policy) },
{ "method", JSONCoder<String>::encode(request.method) },
{ "headers", JSONCoder<Headers>::encode(request.headers) }
};
}
static Request decode(const json& jRequest)
{
return Request {
JSONCoder<String>::decode(jRequest["url"]),
JSONCoder<String>::decode(jRequest["referrer"]),
JSONCoder<int>::decode(jRequest["policy"]),
JSONCoder<String>::decode(jRequest["method"]),
JSONCoder<Headers>::decode(jRequest["headers"])
};
}
};
template<>
struct JSONCoder<Response> {
static json encode(const Response& response)
{
return json {
{ "url", JSONCoder<String>::encode(response.url) },
{ "mimeType", JSONCoder<String>::encode(response.mimeType) },
{ "expectedLength", JSONCoder<long long>::encode(response.expectedLength) },
{ "textEncodingName", JSONCoder<String>::encode(response.textEncodingName) },
{ "version", JSONCoder<String>::encode(response.version) },
{ "status", JSONCoder<int>::encode(response.status) },
{ "reason", JSONCoder<String>::encode(response.reason) },
{ "headers", JSONCoder<Headers>::encode(response.headers) }
};
}
static Response decode(const json& jResponse)
{
return Response {
JSONCoder<String>::decode(jResponse["url"]),
JSONCoder<String>::decode(jResponse["mimeType"]),
JSONCoder<long long>::decode(jResponse["expectedLength"]),
JSONCoder<String>::decode(jResponse["textEncodingName"]),
JSONCoder<String>::decode(jResponse["version"]),
JSONCoder<int>::decode(jResponse["status"]),
JSONCoder<String>::decode(jResponse["reason"]),
JSONCoder<Headers>::decode(jResponse["headers"])
};
}
};
template<>
struct JSONCoder<Error> {
static json encode(const Error& error)
{
return json {
{ "domain", JSONCoder<String>::encode(error.domain) },
{ "failingURL", JSONCoder<String>::encode(error.failingURL) },
{ "localizedDescription", JSONCoder<String>::encode(error.localizedDescription) },
{ "errorCode", JSONCoder<int>::encode(error.errorCode) },
{ "type", JSONCoder<int>::encode(error.type) }
};
}
static Error decode(const json& jError)
{
return Error {
JSONCoder<String>::decode(jError["domain"]),
JSONCoder<String>::decode(jError["failingURL"]),
JSONCoder<String>::decode(jError["localizedDescription"]),
JSONCoder<int>::decode(jError["errorCode"]),
JSONCoder<int>::decode(jError["type"])
};
}
};
template<>
struct JSONCoder<WebCore::SharedBuffer> {
static json encode(const WebCore::SharedBuffer& data)
{
Vector<char> buffer;
base64Encode(data.data(), data.size(), buffer);
return json(&buffer[0], buffer.size());
}
static Ref<WebCore::SharedBuffer> decode(const json& jData)
{
Vector<char> data;
const auto& str = jData.get_ref<const std::string&>();
auto result = base64Decode(str.c_str(), str.size(), data);
ASSERT_UNUSED(result, result);
return WebCore::SharedBuffer::adoptVector(data);
}
};
template<>
struct JSONCoder<RequestSentEvent> {
static json encode(const RequestSentEvent& event)
{
return json {
{ "type", JSONCoder<const char*>::encode(event.typeName) },
{ "time", JSONCoder<CaptureTimeType>::encode(event.time) },
{ "request", JSONCoder<Request>::encode(event.request) }
};
}
static RequestSentEvent decode(const json& jEvent)
{
return RequestSentEvent {
JSONCoder<CaptureTimeType>::decode(jEvent["time"]),
JSONCoder<Request>::decode(jEvent["request"])
};
}
};
template<>
struct JSONCoder<ResponseReceivedEvent> {
static json encode(const ResponseReceivedEvent& event)
{
return json {
{ "type", JSONCoder<const char*>::encode(event.typeName) },
{ "time", JSONCoder<CaptureTimeType>::encode(event.time) },
{ "response", JSONCoder<Response>::encode(event.response) }
};
}
static ResponseReceivedEvent decode(const json& jEvent)
{
return ResponseReceivedEvent {
JSONCoder<CaptureTimeType>::decode(jEvent["time"]),
JSONCoder<Response>::decode(jEvent["response"])
};
}
};
template<>
struct JSONCoder<RedirectReceivedEvent> {
static json encode(const RedirectReceivedEvent& event)
{
return json {
{ "type", JSONCoder<const char*>::encode(event.typeName) },
{ "time", JSONCoder<CaptureTimeType>::encode(event.time) },
{ "request", JSONCoder<Request>::encode(event.request) },
{ "response", JSONCoder<Response>::encode(event.response) }
};
}
static RedirectReceivedEvent decode(const json& jEvent)
{
return RedirectReceivedEvent {
JSONCoder<CaptureTimeType>::decode(jEvent["time"]),
JSONCoder<Request>::decode(jEvent["request"]),
JSONCoder<Response>::decode(jEvent["response"])
};
}
};
template<>
struct JSONCoder<RedirectSentEvent> {
static json encode(const RedirectSentEvent& event)
{
return json {
{ "type", JSONCoder<const char*>::encode(event.typeName) },
{ "time", JSONCoder<CaptureTimeType>::encode(event.time) },
{ "request", JSONCoder<Request>::encode(event.request) },
};
}
static RedirectSentEvent decode(const json& jEvent)
{
return RedirectSentEvent {
JSONCoder<CaptureTimeType>::decode(jEvent["time"]),
JSONCoder<Request>::decode(jEvent["request"])
};
}
};
template<>
struct JSONCoder<DataReceivedEvent> {
static json encode(const DataReceivedEvent& event)
{
return json {
{ "type", JSONCoder<const char*>::encode(event.typeName) },
{ "time", JSONCoder<CaptureTimeType>::encode(event.time) },
{ "data", JSONCoder<WebCore::SharedBuffer>::encode(event.data.get()) }
};
}
static DataReceivedEvent decode(const json& jEvent)
{
return DataReceivedEvent {
JSONCoder<CaptureTimeType>::decode(jEvent["time"]),
JSONCoder<WebCore::SharedBuffer>::decode(jEvent["data"])
};
}
};
template<>
struct JSONCoder<FinishedEvent> {
static json encode(const FinishedEvent& event)
{
return json {
{ "type", JSONCoder<const char*>::encode(event.typeName) },
{ "time", JSONCoder<CaptureTimeType>::encode(event.time) },
{ "error", JSONCoder<Error>::encode(event.error) }
};
}
static FinishedEvent decode(const json& jEvent)
{
return FinishedEvent {
JSONCoder<CaptureTimeType>::decode(jEvent["time"]),
JSONCoder<Error>::decode(jEvent["error"])
};
}
};
std::string eventToString(const CaptureEvent& event)
{
json result;
WTF::visit([&result](const auto& event) {
using EventType = std::decay_t<decltype(event)>;
result = JSONCoder<EventType>::encode(event);
}, event);
return result.dump(4);
}
OptionalCaptureEvent stringToEvent(const char* jsonStr)
{
auto jValue = json::parse(jsonStr);
const auto& type = jValue["type"].get_ref<const std::string&>();
OptionalCaptureEvent result { std::nullopt };
brigand::for_each<CaptureEvent>([&](auto T) {
using Type = typename decltype(T)::type;
if (!result && type == Type::typeName)
result = OptionalCaptureEvent(JSONCoder<Type>::decode(jValue));
});
return result;
}
} }
#endif // ENABLE(NETWORK_CAPTURE)