// This file is generated by TypeBuilder_cpp.template.

// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "content/browser/devtools/protocol/fetch.h"

#include "content/browser/devtools/protocol/protocol.h"

#include "third_party/inspector_protocol/crdtp/cbor.h"
#include "third_party/inspector_protocol/crdtp/find_by_first.h"
#include "third_party/inspector_protocol/crdtp/span.h"

namespace content {
namespace protocol {
namespace Fetch {

using crdtp::DeserializerState;
using crdtp::FallthroughCallback;
using crdtp::ProtocolTypeTraits;

// ------------- Enum values from types.

const char Metainfo::domainName[] = "Fetch";
const char Metainfo::commandPrefix[] = "Fetch.";
const char Metainfo::version[] = "1.3";



CRDTP_BEGIN_DESERIALIZER(RequestPattern)
    CRDTP_DESERIALIZE_FIELD_OPT("requestStage", m_requestStage),
    CRDTP_DESERIALIZE_FIELD_OPT("resourceType", m_resourceType),
    CRDTP_DESERIALIZE_FIELD_OPT("urlPattern", m_urlPattern),
CRDTP_END_DESERIALIZER()

CRDTP_BEGIN_SERIALIZER(RequestPattern)
    CRDTP_SERIALIZE_FIELD("urlPattern", m_urlPattern);
    CRDTP_SERIALIZE_FIELD("resourceType", m_resourceType);
    CRDTP_SERIALIZE_FIELD("requestStage", m_requestStage);
CRDTP_END_SERIALIZER();


CRDTP_BEGIN_DESERIALIZER(HeaderEntry)
    CRDTP_DESERIALIZE_FIELD("name", m_name),
    CRDTP_DESERIALIZE_FIELD("value", m_value),
CRDTP_END_DESERIALIZER()

CRDTP_BEGIN_SERIALIZER(HeaderEntry)
    CRDTP_SERIALIZE_FIELD("name", m_name);
    CRDTP_SERIALIZE_FIELD("value", m_value);
CRDTP_END_SERIALIZER();



const char* AuthChallenge::SourceEnum::Server = "Server";
const char* AuthChallenge::SourceEnum::Proxy = "Proxy";
CRDTP_BEGIN_DESERIALIZER(AuthChallenge)
    CRDTP_DESERIALIZE_FIELD("origin", m_origin),
    CRDTP_DESERIALIZE_FIELD("realm", m_realm),
    CRDTP_DESERIALIZE_FIELD("scheme", m_scheme),
    CRDTP_DESERIALIZE_FIELD_OPT("source", m_source),
CRDTP_END_DESERIALIZER()

CRDTP_BEGIN_SERIALIZER(AuthChallenge)
    CRDTP_SERIALIZE_FIELD("source", m_source);
    CRDTP_SERIALIZE_FIELD("origin", m_origin);
    CRDTP_SERIALIZE_FIELD("scheme", m_scheme);
    CRDTP_SERIALIZE_FIELD("realm", m_realm);
CRDTP_END_SERIALIZER();



const char* AuthChallengeResponse::ResponseEnum::Default = "Default";
const char* AuthChallengeResponse::ResponseEnum::CancelAuth = "CancelAuth";
const char* AuthChallengeResponse::ResponseEnum::ProvideCredentials = "ProvideCredentials";
CRDTP_BEGIN_DESERIALIZER(AuthChallengeResponse)
    CRDTP_DESERIALIZE_FIELD_OPT("password", m_password),
    CRDTP_DESERIALIZE_FIELD("response", m_response),
    CRDTP_DESERIALIZE_FIELD_OPT("username", m_username),
CRDTP_END_DESERIALIZER()

CRDTP_BEGIN_SERIALIZER(AuthChallengeResponse)
    CRDTP_SERIALIZE_FIELD("response", m_response);
    CRDTP_SERIALIZE_FIELD("username", m_username);
    CRDTP_SERIALIZE_FIELD("password", m_password);
CRDTP_END_SERIALIZER();


// ------------- Enum values from params.


// ------------- Frontend notifications.

void Frontend::RequestPaused(const String& requestId, std::unique_ptr<protocol::Network::Request> request, const String& frameId, const String& resourceType, std::optional<String> responseErrorReason, std::optional<int> responseStatusCode, std::optional<String> responseStatusText, std::unique_ptr<protocol::Array<protocol::Fetch::HeaderEntry>> responseHeaders, std::optional<String> networkId, std::optional<String> redirectedRequestId)
{
    if (!frontend_channel_)
        return;
    crdtp::ObjectSerializer serializer;
    serializer.AddField(crdtp::MakeSpan("requestId"), requestId);
    serializer.AddField(crdtp::MakeSpan("request"), request);
    serializer.AddField(crdtp::MakeSpan("frameId"), frameId);
    serializer.AddField(crdtp::MakeSpan("resourceType"), resourceType);
    serializer.AddField(crdtp::MakeSpan("responseErrorReason"), responseErrorReason);
    serializer.AddField(crdtp::MakeSpan("responseStatusCode"), responseStatusCode);
    serializer.AddField(crdtp::MakeSpan("responseStatusText"), responseStatusText);
    serializer.AddField(crdtp::MakeSpan("responseHeaders"), responseHeaders);
    serializer.AddField(crdtp::MakeSpan("networkId"), networkId);
    serializer.AddField(crdtp::MakeSpan("redirectedRequestId"), redirectedRequestId);
    frontend_channel_->SendProtocolNotification(crdtp::CreateNotification("Fetch.requestPaused", serializer.Finish()));
}

void Frontend::AuthRequired(const String& requestId, std::unique_ptr<protocol::Network::Request> request, const String& frameId, const String& resourceType, std::unique_ptr<protocol::Fetch::AuthChallenge> authChallenge)
{
    if (!frontend_channel_)
        return;
    crdtp::ObjectSerializer serializer;
    serializer.AddField(crdtp::MakeSpan("requestId"), requestId);
    serializer.AddField(crdtp::MakeSpan("request"), request);
    serializer.AddField(crdtp::MakeSpan("frameId"), frameId);
    serializer.AddField(crdtp::MakeSpan("resourceType"), resourceType);
    serializer.AddField(crdtp::MakeSpan("authChallenge"), authChallenge);
    frontend_channel_->SendProtocolNotification(crdtp::CreateNotification("Fetch.authRequired", serializer.Finish()));
}

void Frontend::flush()
{
    frontend_channel_->FlushProtocolNotifications();
}

void Frontend::sendRawNotification(std::unique_ptr<Serializable> notification)
{
    frontend_channel_->SendProtocolNotification(std::move(notification));
}

// --------------------- Dispatcher.

class DomainDispatcherImpl : public protocol::DomainDispatcher {
public:
    DomainDispatcherImpl(FrontendChannel* frontendChannel, Backend* backend)
        : DomainDispatcher(frontendChannel)
        , m_backend(backend) {}
    ~DomainDispatcherImpl() override { }

    using CallHandler = void (DomainDispatcherImpl::*)(crdtp::Dispatchable& dispatchable);

    bool Dispatch(crdtp::span<uint8_t> command_name, crdtp::Dispatchable& dispatchable) override;

    void disable(crdtp::Dispatchable& dispatchable);
    void enable(crdtp::Dispatchable& dispatchable);
    void failRequest(crdtp::Dispatchable& dispatchable);
    void fulfillRequest(crdtp::Dispatchable& dispatchable);
    void continueRequest(crdtp::Dispatchable& dispatchable);
    void continueWithAuth(crdtp::Dispatchable& dispatchable);
    void continueResponse(crdtp::Dispatchable& dispatchable);
    void getResponseBody(crdtp::Dispatchable& dispatchable);
    void takeResponseBodyAsStream(crdtp::Dispatchable& dispatchable);
 protected:
    Backend* m_backend;
};

namespace {
// This helper method with a static map of command methods (instance methods
// of DomainDispatcherImpl declared just above) by their name is used immediately below,
// in the DomainDispatcherImpl::Dispatch method.
DomainDispatcherImpl::CallHandler CommandByName(crdtp::span<uint8_t> command_name) {
  static auto* commands = [](){
    auto* commands = new std::vector<std::pair<crdtp::span<uint8_t>,
                              DomainDispatcherImpl::CallHandler>>{
    {
          crdtp::SpanFrom("continueRequest"),
          &DomainDispatcherImpl::continueRequest
    },
    {
          crdtp::SpanFrom("continueResponse"),
          &DomainDispatcherImpl::continueResponse
    },
    {
          crdtp::SpanFrom("continueWithAuth"),
          &DomainDispatcherImpl::continueWithAuth
    },
    {
          crdtp::SpanFrom("disable"),
          &DomainDispatcherImpl::disable
    },
    {
          crdtp::SpanFrom("enable"),
          &DomainDispatcherImpl::enable
    },
    {
          crdtp::SpanFrom("failRequest"),
          &DomainDispatcherImpl::failRequest
    },
    {
          crdtp::SpanFrom("fulfillRequest"),
          &DomainDispatcherImpl::fulfillRequest
    },
    {
          crdtp::SpanFrom("getResponseBody"),
          &DomainDispatcherImpl::getResponseBody
    },
    {
          crdtp::SpanFrom("takeResponseBodyAsStream"),
          &DomainDispatcherImpl::takeResponseBodyAsStream
    },
    };
    return commands;
  }();
  return crdtp::FindByFirst<DomainDispatcherImpl::CallHandler>(*commands, command_name, nullptr);
}
}  // namespace

bool DomainDispatcherImpl::Dispatch(crdtp::span<uint8_t> command_name, crdtp::Dispatchable& dispatchable) {
  CallHandler handler = CommandByName(command_name);
  if (!handler) return false;

  (this->*handler)(dispatchable);
  return true;
}


namespace {


}  // namespace

void DomainDispatcherImpl::disable(crdtp::Dispatchable& dispatchable)
{
    // Prepare input parameters.

    std::unique_ptr<DomainDispatcher::WeakPtr> weak = weakPtr();
    DispatchResponse response = m_backend->Disable();
    if (response.IsFallThrough()) {
        dispatchable.DispatchFallThrough(response.Message());
        return;
    }
    if (weak->get())
        weak->get()->sendResponse(dispatchable.CallId(), response);
    return;
}

class EnableCallbackImpl : public Backend::EnableCallback, public DomainDispatcher::Callback {
public:
    EnableCallbackImpl(std::unique_ptr<DomainDispatcher::WeakPtr> backendImpl, crdtp::Dispatchable& dispatchable)
        : DomainDispatcher::Callback(std::move(backendImpl), dispatchable, crdtp::SpanFrom("Fetch.enable")) { }

    void sendSuccess() override
    {
        crdtp::ObjectSerializer serializer;
        sendIfActive(serializer.Finish(), DispatchResponse::Success());
    }

    void fallThrough() override
    {
        fallThroughIfActive();
    }

    void sendFailure(const DispatchResponse& response) override
    {
        DCHECK(response.IsError());
        sendIfActive(nullptr, response);
    }
};

namespace {

struct enableParams : public crdtp::DeserializableProtocolObject<enableParams> {
    std::unique_ptr<protocol::Array<protocol::Fetch::RequestPattern>> patterns;
    std::optional<bool> handleAuthRequests;
    DECLARE_DESERIALIZATION_SUPPORT();
};

CRDTP_BEGIN_DESERIALIZER(enableParams)
    CRDTP_DESERIALIZE_FIELD_OPT("handleAuthRequests", handleAuthRequests),
    CRDTP_DESERIALIZE_FIELD_OPT("patterns", patterns),
CRDTP_END_DESERIALIZER()

}  // namespace

void DomainDispatcherImpl::enable(crdtp::Dispatchable& dispatchable)
{
    // Prepare input parameters.
    auto deserializer = crdtp::DeferredMessage::FromSpan(dispatchable.Params())->MakeDeserializer();
    enableParams params;
    if (!enableParams::Deserialize(&deserializer, &params)) {
      ReportInvalidParams(dispatchable, deserializer);
      return;
    }

    m_backend->Enable(std::move(params.patterns), std::move(params.handleAuthRequests), std::make_unique<EnableCallbackImpl>(weakPtr(), dispatchable));
}

class FailRequestCallbackImpl : public Backend::FailRequestCallback, public DomainDispatcher::Callback {
public:
    FailRequestCallbackImpl(std::unique_ptr<DomainDispatcher::WeakPtr> backendImpl, crdtp::Dispatchable& dispatchable)
        : DomainDispatcher::Callback(std::move(backendImpl), dispatchable, crdtp::SpanFrom("Fetch.failRequest")) { }

    void sendSuccess() override
    {
        crdtp::ObjectSerializer serializer;
        sendIfActive(serializer.Finish(), DispatchResponse::Success());
    }

    void fallThrough() override
    {
        fallThroughIfActive();
    }

    void sendFailure(const DispatchResponse& response) override
    {
        DCHECK(response.IsError());
        sendIfActive(nullptr, response);
    }
};

namespace {

struct failRequestParams : public crdtp::DeserializableProtocolObject<failRequestParams> {
    String requestId;
    String errorReason;
    DECLARE_DESERIALIZATION_SUPPORT();
};

CRDTP_BEGIN_DESERIALIZER(failRequestParams)
    CRDTP_DESERIALIZE_FIELD("errorReason", errorReason),
    CRDTP_DESERIALIZE_FIELD("requestId", requestId),
CRDTP_END_DESERIALIZER()

}  // namespace

void DomainDispatcherImpl::failRequest(crdtp::Dispatchable& dispatchable)
{
    // Prepare input parameters.
    auto deserializer = crdtp::DeferredMessage::FromSpan(dispatchable.Params())->MakeDeserializer();
    failRequestParams params;
    if (!failRequestParams::Deserialize(&deserializer, &params)) {
      ReportInvalidParams(dispatchable, deserializer);
      return;
    }

    m_backend->FailRequest(params.requestId, params.errorReason, std::make_unique<FailRequestCallbackImpl>(weakPtr(), dispatchable));
}

class FulfillRequestCallbackImpl : public Backend::FulfillRequestCallback, public DomainDispatcher::Callback {
public:
    FulfillRequestCallbackImpl(std::unique_ptr<DomainDispatcher::WeakPtr> backendImpl, crdtp::Dispatchable& dispatchable)
        : DomainDispatcher::Callback(std::move(backendImpl), dispatchable, crdtp::SpanFrom("Fetch.fulfillRequest")) { }

    void sendSuccess() override
    {
        crdtp::ObjectSerializer serializer;
        sendIfActive(serializer.Finish(), DispatchResponse::Success());
    }

    void fallThrough() override
    {
        fallThroughIfActive();
    }

    void sendFailure(const DispatchResponse& response) override
    {
        DCHECK(response.IsError());
        sendIfActive(nullptr, response);
    }
};

namespace {

struct fulfillRequestParams : public crdtp::DeserializableProtocolObject<fulfillRequestParams> {
    String requestId;
    int responseCode;
    std::unique_ptr<protocol::Array<protocol::Fetch::HeaderEntry>> responseHeaders;
    std::optional<Binary> binaryResponseHeaders;
    std::optional<Binary> body;
    std::optional<String> responsePhrase;
    DECLARE_DESERIALIZATION_SUPPORT();
};

CRDTP_BEGIN_DESERIALIZER(fulfillRequestParams)
    CRDTP_DESERIALIZE_FIELD_OPT("binaryResponseHeaders", binaryResponseHeaders),
    CRDTP_DESERIALIZE_FIELD_OPT("body", body),
    CRDTP_DESERIALIZE_FIELD("requestId", requestId),
    CRDTP_DESERIALIZE_FIELD("responseCode", responseCode),
    CRDTP_DESERIALIZE_FIELD_OPT("responseHeaders", responseHeaders),
    CRDTP_DESERIALIZE_FIELD_OPT("responsePhrase", responsePhrase),
CRDTP_END_DESERIALIZER()

}  // namespace

void DomainDispatcherImpl::fulfillRequest(crdtp::Dispatchable& dispatchable)
{
    // Prepare input parameters.
    auto deserializer = crdtp::DeferredMessage::FromSpan(dispatchable.Params())->MakeDeserializer();
    fulfillRequestParams params;
    if (!fulfillRequestParams::Deserialize(&deserializer, &params)) {
      ReportInvalidParams(dispatchable, deserializer);
      return;
    }

    m_backend->FulfillRequest(params.requestId, params.responseCode, std::move(params.responseHeaders), std::move(params.binaryResponseHeaders), std::move(params.body), std::move(params.responsePhrase), std::make_unique<FulfillRequestCallbackImpl>(weakPtr(), dispatchable));
}

class ContinueRequestCallbackImpl : public Backend::ContinueRequestCallback, public DomainDispatcher::Callback {
public:
    ContinueRequestCallbackImpl(std::unique_ptr<DomainDispatcher::WeakPtr> backendImpl, crdtp::Dispatchable& dispatchable)
        : DomainDispatcher::Callback(std::move(backendImpl), dispatchable, crdtp::SpanFrom("Fetch.continueRequest")) { }

    void sendSuccess() override
    {
        crdtp::ObjectSerializer serializer;
        sendIfActive(serializer.Finish(), DispatchResponse::Success());
    }

    void fallThrough() override
    {
        fallThroughIfActive();
    }

    void sendFailure(const DispatchResponse& response) override
    {
        DCHECK(response.IsError());
        sendIfActive(nullptr, response);
    }
};

namespace {

struct continueRequestParams : public crdtp::DeserializableProtocolObject<continueRequestParams> {
    String requestId;
    std::optional<String> url;
    std::optional<String> method;
    std::optional<Binary> postData;
    std::unique_ptr<protocol::Array<protocol::Fetch::HeaderEntry>> headers;
    std::optional<bool> interceptResponse;
    DECLARE_DESERIALIZATION_SUPPORT();
};

CRDTP_BEGIN_DESERIALIZER(continueRequestParams)
    CRDTP_DESERIALIZE_FIELD_OPT("headers", headers),
    CRDTP_DESERIALIZE_FIELD_OPT("interceptResponse", interceptResponse),
    CRDTP_DESERIALIZE_FIELD_OPT("method", method),
    CRDTP_DESERIALIZE_FIELD_OPT("postData", postData),
    CRDTP_DESERIALIZE_FIELD("requestId", requestId),
    CRDTP_DESERIALIZE_FIELD_OPT("url", url),
CRDTP_END_DESERIALIZER()

}  // namespace

void DomainDispatcherImpl::continueRequest(crdtp::Dispatchable& dispatchable)
{
    // Prepare input parameters.
    auto deserializer = crdtp::DeferredMessage::FromSpan(dispatchable.Params())->MakeDeserializer();
    continueRequestParams params;
    if (!continueRequestParams::Deserialize(&deserializer, &params)) {
      ReportInvalidParams(dispatchable, deserializer);
      return;
    }

    m_backend->ContinueRequest(params.requestId, std::move(params.url), std::move(params.method), std::move(params.postData), std::move(params.headers), std::move(params.interceptResponse), std::make_unique<ContinueRequestCallbackImpl>(weakPtr(), dispatchable));
}

class ContinueWithAuthCallbackImpl : public Backend::ContinueWithAuthCallback, public DomainDispatcher::Callback {
public:
    ContinueWithAuthCallbackImpl(std::unique_ptr<DomainDispatcher::WeakPtr> backendImpl, crdtp::Dispatchable& dispatchable)
        : DomainDispatcher::Callback(std::move(backendImpl), dispatchable, crdtp::SpanFrom("Fetch.continueWithAuth")) { }

    void sendSuccess() override
    {
        crdtp::ObjectSerializer serializer;
        sendIfActive(serializer.Finish(), DispatchResponse::Success());
    }

    void fallThrough() override
    {
        fallThroughIfActive();
    }

    void sendFailure(const DispatchResponse& response) override
    {
        DCHECK(response.IsError());
        sendIfActive(nullptr, response);
    }
};

namespace {

struct continueWithAuthParams : public crdtp::DeserializableProtocolObject<continueWithAuthParams> {
    String requestId;
    std::unique_ptr<protocol::Fetch::AuthChallengeResponse> authChallengeResponse;
    DECLARE_DESERIALIZATION_SUPPORT();
};

CRDTP_BEGIN_DESERIALIZER(continueWithAuthParams)
    CRDTP_DESERIALIZE_FIELD("authChallengeResponse", authChallengeResponse),
    CRDTP_DESERIALIZE_FIELD("requestId", requestId),
CRDTP_END_DESERIALIZER()

}  // namespace

void DomainDispatcherImpl::continueWithAuth(crdtp::Dispatchable& dispatchable)
{
    // Prepare input parameters.
    auto deserializer = crdtp::DeferredMessage::FromSpan(dispatchable.Params())->MakeDeserializer();
    continueWithAuthParams params;
    if (!continueWithAuthParams::Deserialize(&deserializer, &params)) {
      ReportInvalidParams(dispatchable, deserializer);
      return;
    }

    m_backend->ContinueWithAuth(params.requestId, std::move(params.authChallengeResponse), std::make_unique<ContinueWithAuthCallbackImpl>(weakPtr(), dispatchable));
}

class ContinueResponseCallbackImpl : public Backend::ContinueResponseCallback, public DomainDispatcher::Callback {
public:
    ContinueResponseCallbackImpl(std::unique_ptr<DomainDispatcher::WeakPtr> backendImpl, crdtp::Dispatchable& dispatchable)
        : DomainDispatcher::Callback(std::move(backendImpl), dispatchable, crdtp::SpanFrom("Fetch.continueResponse")) { }

    void sendSuccess() override
    {
        crdtp::ObjectSerializer serializer;
        sendIfActive(serializer.Finish(), DispatchResponse::Success());
    }

    void fallThrough() override
    {
        fallThroughIfActive();
    }

    void sendFailure(const DispatchResponse& response) override
    {
        DCHECK(response.IsError());
        sendIfActive(nullptr, response);
    }
};

namespace {

struct continueResponseParams : public crdtp::DeserializableProtocolObject<continueResponseParams> {
    String requestId;
    std::optional<int> responseCode;
    std::optional<String> responsePhrase;
    std::unique_ptr<protocol::Array<protocol::Fetch::HeaderEntry>> responseHeaders;
    std::optional<Binary> binaryResponseHeaders;
    DECLARE_DESERIALIZATION_SUPPORT();
};

CRDTP_BEGIN_DESERIALIZER(continueResponseParams)
    CRDTP_DESERIALIZE_FIELD_OPT("binaryResponseHeaders", binaryResponseHeaders),
    CRDTP_DESERIALIZE_FIELD("requestId", requestId),
    CRDTP_DESERIALIZE_FIELD_OPT("responseCode", responseCode),
    CRDTP_DESERIALIZE_FIELD_OPT("responseHeaders", responseHeaders),
    CRDTP_DESERIALIZE_FIELD_OPT("responsePhrase", responsePhrase),
CRDTP_END_DESERIALIZER()

}  // namespace

void DomainDispatcherImpl::continueResponse(crdtp::Dispatchable& dispatchable)
{
    // Prepare input parameters.
    auto deserializer = crdtp::DeferredMessage::FromSpan(dispatchable.Params())->MakeDeserializer();
    continueResponseParams params;
    if (!continueResponseParams::Deserialize(&deserializer, &params)) {
      ReportInvalidParams(dispatchable, deserializer);
      return;
    }

    m_backend->ContinueResponse(params.requestId, std::move(params.responseCode), std::move(params.responsePhrase), std::move(params.responseHeaders), std::move(params.binaryResponseHeaders), std::make_unique<ContinueResponseCallbackImpl>(weakPtr(), dispatchable));
}

class GetResponseBodyCallbackImpl : public Backend::GetResponseBodyCallback, public DomainDispatcher::Callback {
public:
    GetResponseBodyCallbackImpl(std::unique_ptr<DomainDispatcher::WeakPtr> backendImpl, crdtp::Dispatchable& dispatchable)
        : DomainDispatcher::Callback(std::move(backendImpl), dispatchable, crdtp::SpanFrom("Fetch.getResponseBody")) { }

    void sendSuccess(const String& body, bool base64Encoded) override
    {
        crdtp::ObjectSerializer serializer;
        serializer.AddField(crdtp::MakeSpan("body"), body);
        serializer.AddField(crdtp::MakeSpan("base64Encoded"), base64Encoded);
        sendIfActive(serializer.Finish(), DispatchResponse::Success());
    }

    void fallThrough() override
    {
        fallThroughIfActive();
    }

    void sendFailure(const DispatchResponse& response) override
    {
        DCHECK(response.IsError());
        sendIfActive(nullptr, response);
    }
};

namespace {

struct getResponseBodyParams : public crdtp::DeserializableProtocolObject<getResponseBodyParams> {
    String requestId;
    DECLARE_DESERIALIZATION_SUPPORT();
};

CRDTP_BEGIN_DESERIALIZER(getResponseBodyParams)
    CRDTP_DESERIALIZE_FIELD("requestId", requestId),
CRDTP_END_DESERIALIZER()

}  // namespace

void DomainDispatcherImpl::getResponseBody(crdtp::Dispatchable& dispatchable)
{
    // Prepare input parameters.
    auto deserializer = crdtp::DeferredMessage::FromSpan(dispatchable.Params())->MakeDeserializer();
    getResponseBodyParams params;
    if (!getResponseBodyParams::Deserialize(&deserializer, &params)) {
      ReportInvalidParams(dispatchable, deserializer);
      return;
    }

    m_backend->GetResponseBody(params.requestId, std::make_unique<GetResponseBodyCallbackImpl>(weakPtr(), dispatchable));
}

class TakeResponseBodyAsStreamCallbackImpl : public Backend::TakeResponseBodyAsStreamCallback, public DomainDispatcher::Callback {
public:
    TakeResponseBodyAsStreamCallbackImpl(std::unique_ptr<DomainDispatcher::WeakPtr> backendImpl, crdtp::Dispatchable& dispatchable)
        : DomainDispatcher::Callback(std::move(backendImpl), dispatchable, crdtp::SpanFrom("Fetch.takeResponseBodyAsStream")) { }

    void sendSuccess(const String& stream) override
    {
        crdtp::ObjectSerializer serializer;
        serializer.AddField(crdtp::MakeSpan("stream"), stream);
        sendIfActive(serializer.Finish(), DispatchResponse::Success());
    }

    void fallThrough() override
    {
        fallThroughIfActive();
    }

    void sendFailure(const DispatchResponse& response) override
    {
        DCHECK(response.IsError());
        sendIfActive(nullptr, response);
    }
};

namespace {

struct takeResponseBodyAsStreamParams : public crdtp::DeserializableProtocolObject<takeResponseBodyAsStreamParams> {
    String requestId;
    DECLARE_DESERIALIZATION_SUPPORT();
};

CRDTP_BEGIN_DESERIALIZER(takeResponseBodyAsStreamParams)
    CRDTP_DESERIALIZE_FIELD("requestId", requestId),
CRDTP_END_DESERIALIZER()

}  // namespace

void DomainDispatcherImpl::takeResponseBodyAsStream(crdtp::Dispatchable& dispatchable)
{
    // Prepare input parameters.
    auto deserializer = crdtp::DeferredMessage::FromSpan(dispatchable.Params())->MakeDeserializer();
    takeResponseBodyAsStreamParams params;
    if (!takeResponseBodyAsStreamParams::Deserialize(&deserializer, &params)) {
      ReportInvalidParams(dispatchable, deserializer);
      return;
    }

    m_backend->TakeResponseBodyAsStream(params.requestId, std::make_unique<TakeResponseBodyAsStreamCallbackImpl>(weakPtr(), dispatchable));
}

namespace {
// This helper method (with a static map of redirects) is used from Dispatcher::wire
// immediately below.
const std::vector<std::pair<crdtp::span<uint8_t>, crdtp::span<uint8_t>>>& SortedRedirects() {
  static auto* redirects = [](){
    auto* redirects = new std::vector<std::pair<crdtp::span<uint8_t>, crdtp::span<uint8_t>>>{
    };
    return redirects;
  }();
  return *redirects;
}
}  // namespace

// static
void Dispatcher::wire(UberDispatcher* uber, Backend* backend)
{
    auto dispatcher = std::make_unique<DomainDispatcherImpl>(uber->channel(), backend);
    uber->WireBackend(crdtp::SpanFrom("Fetch"), SortedRedirects(), std::move(dispatcher));
}

} // Fetch
} // namespace content
} // namespace protocol
