jiuyiUniapp/service/node_modules/react-native/ReactCommon/jsinspector-modern/NetworkIOAgent.h

267 lines
8.3 KiB
C
Raw Normal View History

2025-02-13 09:59:20 +08:00
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include "CdpJson.h"
#include "InspectorInterfaces.h"
#include "ScopedExecutor.h"
#include <folly/dynamic.h>
#include <mutex>
#include <sstream>
#include <string>
#include <unordered_map>
#include <utility>
#include <variant>
namespace facebook::react::jsinspector_modern {
using StreamID = const std::string;
using Headers = std::map<std::string, std::string>;
using IOReadError = const std::string;
namespace {
class Stream; // Defined in NetworkIOAgent.cpp
using StreamsMap = std::unordered_map<std::string, std::shared_ptr<Stream>>;
} // namespace
struct LoadNetworkResourceRequest {
std::string url;
};
struct ReadStreamParams {
StreamID handle;
std::optional<unsigned long> size;
std::optional<unsigned long> offset;
};
struct NetworkResource {
bool success{};
std::optional<std::string> stream;
std::optional<int> httpStatusCode;
std::optional<std::string> netErrorName;
std::optional<Headers> headers;
folly::dynamic toDynamic() const {
auto dynamicResource = folly::dynamic::object("success", success);
if (success) { // stream IFF successful
assert(stream);
dynamicResource("stream", *stream);
}
if (netErrorName) { // Only if unsuccessful
assert(!success);
dynamicResource("netErrorName", *netErrorName);
}
if (httpStatusCode) { // Guaranteed if successful
dynamicResource("httpStatusCode", *httpStatusCode);
} else {
assert(!success);
}
if (headers) { // Guaranteed if successful
auto dynamicHeaders = folly::dynamic::object();
for (const auto& pair : *headers) {
dynamicHeaders(pair.first, pair.second);
}
dynamicResource("headers", std::move(dynamicHeaders));
} else {
assert(!success);
}
return dynamicResource;
}
};
struct IOReadResult {
std::string data;
bool eof;
bool base64Encoded;
folly::dynamic toDynamic() const {
auto obj = folly::dynamic::object("data", data);
obj("eof", eof);
obj("base64Encoded", base64Encoded);
return obj;
}
};
/**
* Passed to `loadNetworkResource`, provides callbacks for processing incoming
* data and other events.
*/
class NetworkRequestListener {
public:
NetworkRequestListener() = default;
NetworkRequestListener(const NetworkRequestListener&) = delete;
NetworkRequestListener& operator=(const NetworkRequestListener&) = delete;
NetworkRequestListener(NetworkRequestListener&&) noexcept = default;
NetworkRequestListener& operator=(NetworkRequestListener&&) noexcept =
default;
virtual ~NetworkRequestListener() = default;
/**
* To be called by the delegate on receipt of response headers, including
* on "unsuccessful" status codes.
*
* \param httpStatusCode The HTTP status code received.
* \param headers Response headers as an unordered_map.
*/
virtual void onHeaders(int httpStatusCode, const Headers& headers) = 0;
/**
* To be called by the delegate on receipt of data chunks.
* \param data The data received.
*/
virtual void onData(std::string_view data) = 0;
/**
* To be called by the delegate on any error with the request, either before
* headers are received or for a subsequent interrupion.
*
* \param message A short, human-readable message, which may be forwarded to
* the CDP client either in the `loadNetworkResource` response (if headers
* were not yet received), or as a CDP error in response to a subsequent
* `IO.read`.
*/
virtual void onError(const std::string& message) = 0;
/**
* To be called by the delegate on successful completion of the request.
* Delegates must call *either* onCompletion() or onError() exactly once.
*/
virtual void onCompletion() = 0;
/**
* Optionally (preferably) used to give NetworkIOAgent
a way to cancel an
* in-progress download.
*
* \param cancelFunction A function that can be called to cancel a download,
* may be called before or after the download is complete.
*/
virtual void setCancelFunction(std::function<void()> cancelFunction) = 0;
};
/**
* Implemented by the HostTargetDelegate per-platform to perform network
* requests.
*/
class LoadNetworkResourceDelegate {
public:
LoadNetworkResourceDelegate() = default;
LoadNetworkResourceDelegate(const LoadNetworkResourceDelegate&) = delete;
LoadNetworkResourceDelegate& operator=(const LoadNetworkResourceDelegate&) =
delete;
LoadNetworkResourceDelegate(LoadNetworkResourceDelegate&&) noexcept = delete;
LoadNetworkResourceDelegate& operator=(
LoadNetworkResourceDelegate&&) noexcept = delete;
virtual ~LoadNetworkResourceDelegate() = default;
/**
* Called by NetworkIOAgent on handling a
* `Network.loadNetworkResource` CDP request. Platform implementations should
* override this to perform a network request of the given URL, and use
* listener's callbacks (via the executor) on receipt of headers, data chunks,
* and errors.
*
* \param params A LoadNetworkResourceRequest, including the url.
* \param executor A listener-scoped executor used by the delegate to execute
* listener callbacks on headers, data chunks, and errors. Implementations
* *should* call listener->setCancelFunction() to provide a lambda that can be
* called to abort any in-flight network operation that is no longer needed.
*/
virtual void loadNetworkResource(
[[maybe_unused]] const LoadNetworkResourceRequest& params,
[[maybe_unused]] ScopedExecutor<NetworkRequestListener> executor) = 0;
};
/**
* Provides an agent for handling CDP's Network.loadNetworkResource, IO.read and
* IO.close.
*
* Owns state of all in-progress and completed HTTP requests - ensure
* IO.close is used to free resources once consumed.
*
* Public methods must be called the same thread as the given executor.
*/
class NetworkIOAgent {
public:
/**
* \param frontendChannel A channel used to send responses to the
* frontend.
* \param executor An executor used for any callbacks provided, and for
* processing incoming data or other events from network operations.
*/
NetworkIOAgent(FrontendChannel frontendChannel, VoidExecutor executor)
: frontendChannel_(frontendChannel),
executor_(executor),
streams_(std::make_shared<StreamsMap>()) {}
/**
* Handle a CDP request. The response will be sent over the provided
* \c FrontendChannel synchronously or asynchronously.
* \param req The parsed request.
*/
bool handleRequest(
const cdp::PreparsedRequest& req,
LoadNetworkResourceDelegate& delegate);
private:
/**
* A channel used to send responses and events to the frontend.
*/
FrontendChannel frontendChannel_;
/**
* An executor used to create NetworkRequestListener-scoped executors for the
* delegate.
*/
VoidExecutor executor_;
/**
* Map of stream objects, which contain data received, accept read requests
* and listen for delegate events. Delegates have a scoped executor for Stream
* instances, but Streams will not live beyond the destruction of this
* NetworkIOAgent instance + executor scope.
*
* This is a shared_ptr so that we may capture a weak_ptr in our
* Stream::create callback without creating a cycle.
*/
std::shared_ptr<StreamsMap> streams_;
/**
* Stream IDs are strings of an incrementing integer, unique within each
* NewtworkIOAgent instance. This stores the next one to use.
*/
unsigned long nextStreamId_{0};
/**
* Begin loading an HTTP resource, delegating platform-specific
* implementation, responding to the frontend on headers received or on error.
* Does not catch exceptions thrown by the delegate (such as
* NotImplementedException).
*/
void handleLoadNetworkResource(
const cdp::PreparsedRequest& req,
LoadNetworkResourceDelegate& delegate);
/**
* Handle an IO.read CDP request. Emit a chunk of data from the stream, once
* enough has been downloaded, or report an error.
*/
void handleIoRead(const cdp::PreparsedRequest& req);
/**
* Handle an IO.close CDP request. Safely aborts any in-flight request.
* Reports CDP ok if the stream is found, or a CDP error if not.
*/
void handleIoClose(const cdp::PreparsedRequest& req);
};
} // namespace facebook::react::jsinspector_modern