blob: 924fce162f7d6844e701e25ef8a9288798cdfc22 [file] [log] [blame]
// Copyright 2020 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 THIRD_PARTY_BLINK_RENDERER_MODULES_WEBTRANSPORT_INCOMING_STREAM_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBTRANSPORT_INCOMING_STREAM_H_
#include <stdint.h>
#include "base/callback.h"
#include "base/logging.h"
#include "base/optional.h"
#include "base/types/strong_alias.h"
#include "mojo/public/cpp/system/data_pipe.h"
#include "mojo/public/cpp/system/simple_watcher.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
#include "third_party/blink/renderer/bindings/core/v8/script_value.h"
#include "third_party/blink/renderer/modules/modules_export.h"
#include "third_party/blink/renderer/platform/heap/thread_state.h"
#include "third_party/blink/renderer/platform/heap/visitor.h"
namespace blink {
class ScriptState;
class StreamAbortInfo;
class ReadableStream;
class ReadableStreamDefaultControllerWithScriptScope;
// Implementation of the IncomingStream mixin from the standard:
// https://wicg.github.io/web-transport/#incoming-stream. ReceiveStream and
// BidirectionalStream delegate to this to implement the functionality.
class MODULES_EXPORT IncomingStream final
: public GarbageCollected<IncomingStream> {
USING_PRE_FINALIZER(IncomingStream, Dispose);
public:
enum class State {
kOpen,
kAborted,
kClosed,
};
IncomingStream(ScriptState*,
base::OnceClosure on_abort,
mojo::ScopedDataPipeConsumerHandle);
~IncomingStream();
// Init() must be called before the stream is used.
void Init();
// Methods from the IncomingStream IDL:
// https://wicg.github.io/web-transport/#incoming-stream
ReadableStream* Readable() const {
DVLOG(1) << "IncomingStream::readable() called";
return readable_;
}
ScriptPromise ReadingAborted() const { return reading_aborted_; }
void AbortReading(StreamAbortInfo*);
// Called from QuicTransport via a WebTransportStream class. May execute
// JavaScript.
void OnIncomingStreamClosed(bool fin_received);
// Called via QuicTransport via a WebTransportStream class. Expects a
// JavaScript scope to have been entered.
void Reset();
// Called from QuicTransport rather than using
// ExecutionContextLifecycleObserver to ensure correct destruction order.
// Does not execute JavaScript.
void ContextDestroyed();
State GetState() const { return state_; }
void Trace(Visitor*) const;
private:
class UnderlyingSource;
using IsLocalAbort = base::StrongAlias<class IsLocalAbortTag, bool>;
// Called when |data_pipe_| becomes readable or errored.
void OnHandleReady(MojoResult, const mojo::HandleSignalsState&);
// Called when |data_pipe_| is closed.
void OnPeerClosed(MojoResult, const mojo::HandleSignalsState&);
// Rejects any unfinished read() calls and resets |data_pipe_|.
void HandlePipeClosed();
// Handles a remote close appropriately for the value of |fin_received_|.
void ProcessClose();
// Reads all the data currently in the pipe and enqueues it. If no data is
// currently available, triggers the |read_watcher_| and enqueues when data
// becomes available.
void ReadFromPipeAndEnqueue();
// Copies a sequence of bytes into an ArrayBuffer and enqueues it.
void EnqueueBytes(const void* source, uint32_t byte_length);
// Creates a DOMException indicating that the stream has been aborted.
// If IsLocalAbort it true it will indicate a locally-initiated abort,
// otherwise it will indicate a server--initiated abort.
ScriptValue CreateAbortException(IsLocalAbort);
// Closes |readable_|, resolves |reading_aborted_| and resets |data_pipe_|.
void CloseAbortAndReset();
// Errors |readable_|, resolves |reading_aborted_| and resets |data_pipe_|.
// |exception| will be set as the error on |readable_|.
void ErrorStreamAbortAndReset(ScriptValue exception);
// Resolves the |reading_aborted_| promise and resets the |data_pipe_|.
void AbortAndReset();
// Resets |data_pipe_| and clears the watchers.
// If the pipe is open it will be closed as a side-effect.
void ResetPipe();
// Prepares the object for destruction.
void Dispose();
const Member<ScriptState> script_state_;
base::OnceClosure on_abort_;
mojo::ScopedDataPipeConsumerHandle data_pipe_;
// Only armed when we need to read something.
mojo::SimpleWatcher read_watcher_;
// Always armed to detect close.
mojo::SimpleWatcher close_watcher_;
Member<ReadableStream> readable_;
Member<ReadableStreamDefaultControllerWithScriptScope> controller_;
// Promise returned by the |readingAborted| attribute.
ScriptPromise reading_aborted_;
Member<ScriptPromiseResolver> reading_aborted_resolver_;
State state_ = State::kOpen;
// This is set when OnIncomingStreamClosed() is called.
base::Optional<bool> fin_received_;
// True when |data_pipe_| has been detected to be closed. The close is not
// processed until |fin_received_| is also set.
bool is_pipe_closed_ = false;
// Indicates if we are currently performing a two-phase read from the pipe and
// so can't start another read.
bool in_two_phase_read_ = false;
// Indicates if we need to perform another read after the current one
// completes.
bool read_pending_ = false;
};
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_WEBTRANSPORT_INCOMING_STREAM_H_