summaryrefslogtreecommitdiffstats
path: root/netwerk/protocol/http/Http3Stream.h
blob: 8463a3f86023a46f42fce62a2e28fdbe8908504f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef mozilla_net_Http3Stream_h
#define mozilla_net_Http3Stream_h

#include "nsAHttpTransaction.h"
#include "ARefBase.h"
#include "mozilla/WeakPtr.h"

namespace mozilla {
namespace net {

class Http3Session;

class Http3Stream final : public nsAHttpSegmentReader,
                          public nsAHttpSegmentWriter,
                          public SupportsWeakPtr,
                          public ARefBase {
 public:
  NS_DECL_NSAHTTPSEGMENTREADER
  NS_DECL_NSAHTTPSEGMENTWRITER
  // for RefPtr
  NS_INLINE_DECL_REFCOUNTING(Http3Stream, override)

  Http3Stream(nsAHttpTransaction* httpTransaction, Http3Session* session);

  bool HasStreamId() const { return mStreamId != UINT64_MAX; }
  uint64_t StreamId() const { return mStreamId; }

  nsresult TryActivating();

  // TODO priorities
  void TopLevelOuterContentWindowIdChanged(uint64_t windowId){};

  [[nodiscard]] nsresult ReadSegments(nsAHttpSegmentReader*);
  [[nodiscard]] nsresult WriteSegments(nsAHttpSegmentWriter*, uint32_t,
                                       uint32_t*);

  void SetQueued(bool aStatus) { mQueued = aStatus; }
  bool Queued() const { return mQueued; }

  bool Done() const { return mRecvState == RECV_DONE; }

  void Close(nsresult aResult);
  bool RecvdData() const { return mDataReceived; }

  nsAHttpTransaction* Transaction() { return mTransaction; }
  bool RecvdFin() const { return mFin; }
  bool RecvdReset() const { return mResetRecv; }
  void SetRecvdReset() { mResetRecv = true; }

  void StopSending();

  void SetResponseHeaders(nsTArray<uint8_t>& aResponseHeaders, bool fin);

  // Mirrors nsAHttpTransaction
  bool Do0RTT();
  nsresult Finish0RTT(bool aRestart);

 private:
  ~Http3Stream() = default;

  bool GetHeadersString(const char* buf, uint32_t avail, uint32_t* countUsed);
  nsresult StartRequest();
  void FindRequestContentLength();

  /**
   * SendStreamState:
   *  While sending request:
   *  - PREPARING_HEADERS:
   *      In this state we are collecting the headers and in some cases also
   *      waiting to be able to create a new stream.
   *      We need to read all headers into a buffer before calling
   *      Http3Session::TryActivating. Neqo may not have place for a new
   *      stream if it hits MAX_STREAMS limit. In that case the steam will be
   *      queued and dequeue when neqo can again create new stream
   *      (RequestsCreatable will be called).
   *      If transaction has data to send state changes to SENDING_BODY,
   *      otherwise the state transfers to READING_HEADERS.
   *  - SENDING_BODY:
   *      The stream will be in this state while the transaction is sending
   *      request body. Http3Session::SendRequestBody will be call to give
   *      the data to neqo.
   *      After SENDING_BODY, the state transfers to READING_HEADERS.
   *  - EARLY_RESPONSE:
   *      The server may send STOP_SENDING frame with error HTTP_NO_ERROR.
   *      That error means that the server is not interested in the request
   *      body. In this state the server will just ignore the request body.
   **/
  enum SendStreamState {
    PREPARING_HEADERS,
    WAITING_TO_ACTIVATE,
    SENDING_BODY,
    EARLY_RESPONSE,
    SEND_DONE
  } mSendState;

  /**
   * RecvStreamState:
   *  - BEFORE_HEADERS:
   *      The stream has not received headers yet.
   *  - READING_HEADERS:
   *      In this state Http3Session::ReadResponseHeaders will be called to read
   *      the response headers. All headers will be read at once into
   *      mFlatResponseHeaders. The stream will be in this state until all
   *      headers are given to the transaction.
   *      If the stream has been closed by the server after sending headers the
   *      stream will transit into RECEIVED_FIN state, otherwise it transits to
   *      READING_DATA state.
   *  - READING_DATA:
   *      In this state Http3Session::ReadResponseData will be called and the
   *      response body will be given to the transaction.
   *      This state may transfer to RECEIVED_FIN or DONE state.
   *  - DONE:
   *      The transaction is done.
   **/
  enum RecvStreamState {
    BEFORE_HEADERS,
    READING_HEADERS,
    READING_DATA,
    RECEIVED_FIN,
    RECV_DONE
  } mRecvState;

  uint64_t mStreamId;
  Http3Session* mSession;
  RefPtr<nsAHttpTransaction> mTransaction;
  nsCString mFlatHttpRequestHeaders;
  bool mQueued;
  bool mDataReceived;
  bool mResetRecv;
  nsTArray<uint8_t> mFlatResponseHeaders;
  uint32_t mRequestBodyLenRemaining;

  // The underlying socket transport object is needed to propogate some events
  RefPtr<nsISocketTransport> mSocketTransport;

  // For Progress Events
  uint64_t mTotalSent;
  uint64_t mTotalRead;

  bool mFin;

  bool mAttempting0RTT = false;

  uint32_t mSendingBlockedByFlowControlCount = 0;

  nsresult mSocketInCondition = NS_ERROR_NOT_INITIALIZED;
  nsresult mSocketOutCondition = NS_ERROR_NOT_INITIALIZED;
};

}  // namespace net
}  // namespace mozilla

#endif  // mozilla_net_Http3Stream_h