@fails-components/webtransport-transport-http3-quiche 1.0.0-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CMakeLists.txt +978 -0
- package/LICENSE +39 -0
- package/LICENSE.chromium +27 -0
- package/LICENSE.envoy +207 -0
- package/build.js +315 -0
- package/lib/clientsocket.js +80 -0
- package/lib/index.js +47 -0
- package/lib/serversocket.js +80 -0
- package/lib/socket.js +118 -0
- package/lib/types.ts +15 -0
- package/lib/utils.js +12 -0
- package/package.json +68 -0
- package/platform/icufix/fakedata.cpp +8 -0
- package/platform/quiche/quic/core/io/socket_win.inc +3 -0
- package/platform/quiche_platform_impl/quiche_bug_tracker_impl.h +7 -0
- package/platform/quiche_platform_impl/quiche_client_stats_impl.h +7 -0
- package/platform/quiche_platform_impl/quiche_command_line_flags_impl.h +7 -0
- package/platform/quiche_platform_impl/quiche_containers_impl.h +7 -0
- package/platform/quiche_platform_impl/quiche_event_loop_impl.h +7 -0
- package/platform/quiche_platform_impl/quiche_export_impl.h +6 -0
- package/platform/quiche_platform_impl/quiche_flag_utils_impl.h +11 -0
- package/platform/quiche_platform_impl/quiche_flags_impl.h +8 -0
- package/platform/quiche_platform_impl/quiche_googleurl_impl.h +8 -0
- package/platform/quiche_platform_impl/quiche_iovec_impl.h +10 -0
- package/platform/quiche_platform_impl/quiche_logging_impl.h +21 -0
- package/platform/quiche_platform_impl/quiche_mem_slice_impl.h +2 -0
- package/platform/quiche_platform_impl/quiche_mutex_impl.h +8 -0
- package/platform/quiche_platform_impl/quiche_prefetch_impl.h +11 -0
- package/platform/quiche_platform_impl/quiche_reference_counted_impl.h +16 -0
- package/platform/quiche_platform_impl/quiche_server_stats_impl.h +7 -0
- package/platform/quiche_platform_impl/quiche_stack_trace_impl.h +12 -0
- package/platform/quiche_platform_impl/quiche_stream_buffer_allocator_impl.h +8 -0
- package/platform/quiche_platform_impl/quiche_testvalue_impl.h +1 -0
- package/platform/quiche_platform_impl/quiche_thread_local_impl.h +6 -0
- package/platform/quiche_platform_impl/quiche_time_utils_impl.h +13 -0
- package/platform/quiche_platform_impl/quiche_udp_socket_platform_impl.h +39 -0
- package/readme.md +20 -0
- package/src/http3backendresponse.cc +36 -0
- package/src/http3backendresponse.h +109 -0
- package/src/http3client.cc +1402 -0
- package/src/http3client.h +531 -0
- package/src/http3clientsession.cc +65 -0
- package/src/http3clientsession.h +58 -0
- package/src/http3clientstream.cc +52 -0
- package/src/http3clientstream.h +42 -0
- package/src/http3dispatcher.cc +62 -0
- package/src/http3dispatcher.h +57 -0
- package/src/http3server.cc +529 -0
- package/src/http3server.h +149 -0
- package/src/http3serverbackend.cc +104 -0
- package/src/http3serverbackend.h +96 -0
- package/src/http3serversession.cc +123 -0
- package/src/http3serversession.h +95 -0
- package/src/http3serverstream.cc +463 -0
- package/src/http3serverstream.h +114 -0
- package/src/http3sessioncache.cc +85 -0
- package/src/http3sessioncache.h +59 -0
- package/src/http3wtsessionvisitor.cc +312 -0
- package/src/http3wtsessionvisitor.h +257 -0
- package/src/http3wtstreamvisitor.cc +286 -0
- package/src/http3wtstreamvisitor.h +323 -0
- package/src/librarymain.cc +86 -0
- package/src/librarymain.h +42 -0
- package/src/napialarmfactory.cc +51 -0
- package/src/napialarmfactory.h +165 -0
- package/src/socketjswriter.cc +46 -0
- package/src/socketjswriter.h +100 -0
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
// Copyright (c) 2022 Marten Richter or other contributers (see commit). All rights reserved.
|
|
2
|
+
// Use of this source code is governed by a BSD-style license that can be
|
|
3
|
+
// found in the LICENSE file.
|
|
4
|
+
|
|
5
|
+
#include "src/http3wtstreamvisitor.h"
|
|
6
|
+
#include "src/http3server.h"
|
|
7
|
+
|
|
8
|
+
namespace quic
|
|
9
|
+
{
|
|
10
|
+
void Http3WTStreamJS::init(Http3WTStream *wtstream)
|
|
11
|
+
{
|
|
12
|
+
wtstream_ = std::unique_ptr<Http3WTStream>(wtstream);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
Http3WTStream::Visitor::~Visitor()
|
|
16
|
+
{
|
|
17
|
+
// printf("stream ~Visitor %d %x %x\n", getpid(), this, stream_);
|
|
18
|
+
while (stream_->chunks_.size() > 0)
|
|
19
|
+
{
|
|
20
|
+
auto cur = stream_->chunks_.front();
|
|
21
|
+
|
|
22
|
+
// now we have to inform the server TODO
|
|
23
|
+
stream_->getJS()->processStreamWrite(cur.bufferhandle, false);
|
|
24
|
+
|
|
25
|
+
stream_->chunks_.pop_front();
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (!stream_->stop_sending_received_)
|
|
29
|
+
{
|
|
30
|
+
stream_->getJS()->processStreamRecvSignal(0, NetworkTask::stopSending);
|
|
31
|
+
}
|
|
32
|
+
if (!stream_->stream_was_reset_)
|
|
33
|
+
{
|
|
34
|
+
stream_->getJS()->processStreamRecvSignal(0, NetworkTask::resetStream);
|
|
35
|
+
}
|
|
36
|
+
Http3WTStreamJS *strobj = stream_->getJS();
|
|
37
|
+
if (strobj)
|
|
38
|
+
{
|
|
39
|
+
stream_->stream_ = nullptr;
|
|
40
|
+
strobj->Unref();
|
|
41
|
+
}
|
|
42
|
+
else
|
|
43
|
+
{
|
|
44
|
+
stream_->stream_ = nullptr;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
void Http3WTStream::Visitor::OnWriteSideInDataRecvdState() // called if everything is written to the client and it is closed
|
|
49
|
+
{
|
|
50
|
+
if (stream_->send_fin_)
|
|
51
|
+
stream_->getJS()->processStreamNetworkFinish(NetworkTask::streamFinal);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
void Http3WTStream::Visitor::OnResetStreamReceived(WebTransportStreamError error)
|
|
55
|
+
{
|
|
56
|
+
// should this be removed
|
|
57
|
+
/*
|
|
58
|
+
|
|
59
|
+
// Send FIN in response to a stream reset. We want to test that we can
|
|
60
|
+
// operate one side of the stream cleanly while the other is reset, thus
|
|
61
|
+
// replying with a FIN rather than a RESET_STREAM is more appropriate here.
|
|
62
|
+
stream_->send_fin_ = true;
|
|
63
|
+
OnCanWrite();*/
|
|
64
|
+
stream_->stream_was_reset_ = true;
|
|
65
|
+
lasterror = error;
|
|
66
|
+
stream_->getJS()->processStreamRecvSignal(error, NetworkTask::resetStream); // may be move below
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
void Http3WTStream::Visitor::OnStopSendingReceived(WebTransportStreamError error)
|
|
70
|
+
{
|
|
71
|
+
stream_->stop_sending_received_ = true;
|
|
72
|
+
stream_->getJS()->processStreamRecvSignal(error, NetworkTask::stopSending); // may be move below
|
|
73
|
+
// we should also finallize the stream, so send a fin
|
|
74
|
+
stream_->send_fin_ = true;
|
|
75
|
+
OnCanWrite();
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
void Http3WTStream::cancelWrite(Napi::ObjectReference *handle)
|
|
79
|
+
{
|
|
80
|
+
getJS()->processStreamWrite(handle, false);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
void Http3WTStream::doCanRead()
|
|
84
|
+
{
|
|
85
|
+
// if (pause_reading_) return ; // back pressure folks!
|
|
86
|
+
|
|
87
|
+
if (pause_reading_ && !drain_reads_)
|
|
88
|
+
{
|
|
89
|
+
can_read_pending_ = true;
|
|
90
|
+
return; // back pressure folks!
|
|
91
|
+
}
|
|
92
|
+
size_t readable = stream_->ReadableBytes();
|
|
93
|
+
bool read = false;
|
|
94
|
+
while (readable > 0)
|
|
95
|
+
{
|
|
96
|
+
Http3WTStreamJS::StreamReadBuffer rbuf(js_);
|
|
97
|
+
rbuf.getBuffer(readable);
|
|
98
|
+
|
|
99
|
+
size_t remainSize = rbuf.bufferSize();
|
|
100
|
+
uint32_t writepos = 0;
|
|
101
|
+
|
|
102
|
+
while (readable > 0 && remainSize > 0) {
|
|
103
|
+
size_t len = remainSize;
|
|
104
|
+
WebTransportStream::ReadResult result =
|
|
105
|
+
stream_->Read(absl::Span<char>(((char *)rbuf.bufferData()) + writepos, len));
|
|
106
|
+
QUIC_DVLOG(1) << "Attempted reading on WebTransport stream "
|
|
107
|
+
<< ", bytes read: " << result.bytes_read;
|
|
108
|
+
writepos += result.bytes_read;
|
|
109
|
+
remainSize -= result.bytes_read;
|
|
110
|
+
readable = stream_->ReadableBytes();
|
|
111
|
+
if (result.fin) rbuf.setFin();
|
|
112
|
+
}
|
|
113
|
+
rbuf.commitBuffer(writepos, readable == 0);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
void Http3WTStream::doCanWrite()
|
|
118
|
+
{
|
|
119
|
+
/* if (/* stop_sending_received_ || * pause_reading_)
|
|
120
|
+
{
|
|
121
|
+
return;
|
|
122
|
+
} */
|
|
123
|
+
if (fin_was_sent_)
|
|
124
|
+
return;
|
|
125
|
+
|
|
126
|
+
while (chunks_.size() > 0)
|
|
127
|
+
{
|
|
128
|
+
auto cur = chunks_.front();
|
|
129
|
+
bool success = stream_->Write(absl::string_view(cur.buffer, cur.len));
|
|
130
|
+
QUIC_DVLOG(1) << "Attempted writing on WebTransport bidirectional stream "
|
|
131
|
+
<< ", success: " << (success ? "yes" : "no");
|
|
132
|
+
if (!success)
|
|
133
|
+
{
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
// now we have to inform the server TODO
|
|
137
|
+
getJS()->processStreamWrite(cur.bufferhandle, true);
|
|
138
|
+
|
|
139
|
+
chunks_.pop_front();
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
if (send_fin_)
|
|
143
|
+
{
|
|
144
|
+
bool success = stream_->SendFin();
|
|
145
|
+
if (success)
|
|
146
|
+
fin_was_sent_ = true;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
void Http3WTStream::stopSendingInt(unsigned int reason)
|
|
151
|
+
{
|
|
152
|
+
if (stream_)
|
|
153
|
+
{
|
|
154
|
+
stream_->SendStopSending(reason);
|
|
155
|
+
getJS()->processStreamNetworkFinish(NetworkTask::stopSending);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
void Http3WTStream::resetStreamInt(unsigned int reason)
|
|
160
|
+
{
|
|
161
|
+
if (stream_)
|
|
162
|
+
{
|
|
163
|
+
stream_->ResetWithUserCode(reason);
|
|
164
|
+
getJS()->processStreamNetworkFinish(NetworkTask::resetStream);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
void Http3WTStreamJS::processStreamNetworkFinish(NetworkTask task)
|
|
169
|
+
{
|
|
170
|
+
Napi::HandleScope scope(Env());
|
|
171
|
+
|
|
172
|
+
Napi::Object objVal = Value().Get("jsobj").As<Napi::Object>();
|
|
173
|
+
|
|
174
|
+
std::string nettaskstr;
|
|
175
|
+
switch (task)
|
|
176
|
+
{
|
|
177
|
+
case NetworkTask::resetStream:
|
|
178
|
+
{
|
|
179
|
+
nettaskstr = "resetStream";
|
|
180
|
+
}
|
|
181
|
+
break;
|
|
182
|
+
case NetworkTask::stopSending:
|
|
183
|
+
{
|
|
184
|
+
nettaskstr = "stopSending";
|
|
185
|
+
}
|
|
186
|
+
break;
|
|
187
|
+
case NetworkTask::streamFinal:
|
|
188
|
+
{
|
|
189
|
+
nettaskstr = "streamFinal";
|
|
190
|
+
}
|
|
191
|
+
break;
|
|
192
|
+
default:
|
|
193
|
+
return;
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
Napi::Object retObj = Napi::Object::New(Env());
|
|
197
|
+
retObj.Set("nettask", nettaskstr);
|
|
198
|
+
|
|
199
|
+
objVal.Get("onStreamNetworkFinish").As<Napi::Function>().Call(objVal, {retObj});
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
void Http3WTStreamJS::processStreamRecvSignal(WebTransportStreamError error_code, NetworkTask task)
|
|
203
|
+
{
|
|
204
|
+
Napi::HandleScope scope(Env());
|
|
205
|
+
|
|
206
|
+
Napi::Object objVal = Value().Get("jsobj").As<Napi::Object>();
|
|
207
|
+
|
|
208
|
+
std::string nettaskstr;
|
|
209
|
+
switch (task)
|
|
210
|
+
{
|
|
211
|
+
case NetworkTask::resetStream:
|
|
212
|
+
{
|
|
213
|
+
nettaskstr = "resetStream";
|
|
214
|
+
}
|
|
215
|
+
break;
|
|
216
|
+
case NetworkTask::stopSending:
|
|
217
|
+
{
|
|
218
|
+
nettaskstr = "stopSending";
|
|
219
|
+
}
|
|
220
|
+
break;
|
|
221
|
+
case NetworkTask::streamFinal:
|
|
222
|
+
{
|
|
223
|
+
nettaskstr = "streamFinal";
|
|
224
|
+
}
|
|
225
|
+
break;
|
|
226
|
+
default:
|
|
227
|
+
return;
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
Napi::Object retObj = Napi::Object::New(Env());
|
|
231
|
+
retObj.Set("purpose", "StreamRecvSignal");
|
|
232
|
+
retObj.Set("code", error_code);
|
|
233
|
+
retObj.Set("nettask", nettaskstr);
|
|
234
|
+
|
|
235
|
+
objVal.Get("onStreamRecvSignal").As<Napi::Function>().Call(objVal, {retObj});
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
void Http3WTStreamJS::processStreamWrite(Napi::ObjectReference *bufferhandle, bool success)
|
|
239
|
+
{
|
|
240
|
+
Napi::HandleScope scope(Env());
|
|
241
|
+
|
|
242
|
+
Napi::Object objVal = Value().Get("jsobj").As<Napi::Object>();
|
|
243
|
+
bufferhandle->Unref(); // release the outgoing buffer
|
|
244
|
+
delete bufferhandle; // free the handle object
|
|
245
|
+
|
|
246
|
+
Napi::Object retObj = Napi::Object::New(Env());
|
|
247
|
+
retObj.Set("success", success);
|
|
248
|
+
|
|
249
|
+
objVal.Get("onStreamWrite").As<Napi::Function>().Call(objVal, {retObj});
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
void Http3WTStreamJS::StreamReadBuffer::getBuffer(size_t reqsize) {
|
|
253
|
+
Napi::HandleScope scope(jsobj_->Env());
|
|
254
|
+
Napi::Object objVal = jsobj_->Value().Get("jsobj").As<Napi::Object>();
|
|
255
|
+
|
|
256
|
+
Napi::Object argObj = Napi::Object::New(jsobj_->Env());
|
|
257
|
+
argObj.Set("byteSize", reqsize);
|
|
258
|
+
|
|
259
|
+
Napi::Value bufferVal = objVal.Get("getReadBuffer").As<Napi::Function>().Call(objVal, {argObj});
|
|
260
|
+
bufferObj = Napi::Persistent(bufferVal.As<Napi::Object>());
|
|
261
|
+
Napi::Object locBuf = bufferVal.As<Napi::Object>();
|
|
262
|
+
fin = locBuf.Get("fin").As<Napi::Boolean>();
|
|
263
|
+
if (locBuf.Has("buffer")) {
|
|
264
|
+
Napi::Uint8Array buffer = locBuf.Get("buffer").As<Napi::Uint8Array>();
|
|
265
|
+
buffer_ = buffer.Data();
|
|
266
|
+
buffersize_ =buffer.ByteLength();
|
|
267
|
+
}
|
|
268
|
+
// buffer
|
|
269
|
+
// byob
|
|
270
|
+
// readBytes
|
|
271
|
+
// fin
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
void Http3WTStreamJS::StreamReadBuffer::commitBuffer(uint32_t readbytes, bool drained) {
|
|
275
|
+
Napi::HandleScope scope(jsobj_->Env());
|
|
276
|
+
Napi::Object objVal = jsobj_->Value().Get("jsobj").As<Napi::Object>();
|
|
277
|
+
|
|
278
|
+
bufferObj.Set("fin", fin);
|
|
279
|
+
bufferObj.Set("readBytes", Napi::Value::From(jsobj_->Env(),readbytes));
|
|
280
|
+
bufferObj.Set("drained", drained);
|
|
281
|
+
Napi::Value bufferVal = objVal.Get("commitReadBuffer").As<Napi::Function>().Call(objVal, {bufferObj.Value()});
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
}
|
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
// modifications
|
|
2
|
+
// Copyright (c) 2022 Marten Richter or other contributers (see commit). All rights reserved.
|
|
3
|
+
// Use of this source code is governed by a BSD-style license that can be
|
|
4
|
+
// found in the LICENSE file.
|
|
5
|
+
|
|
6
|
+
// original copyright used only portions, see LICENSE.chromium
|
|
7
|
+
// Copyright (c) 2021 The Chromium Authors. All rights reserved.
|
|
8
|
+
// Use of this source code is governed by a BSD-style license that can be
|
|
9
|
+
// found in the LICENSE file.
|
|
10
|
+
|
|
11
|
+
#ifndef HTTP3_WT_STREAM_VISITOR_H_
|
|
12
|
+
#define HTTP3_WT_STREAM_VISITOR_H_
|
|
13
|
+
|
|
14
|
+
#include <napi.h>
|
|
15
|
+
|
|
16
|
+
#include <string>
|
|
17
|
+
|
|
18
|
+
#include "src/librarymain.h"
|
|
19
|
+
#include "quiche/common/simple_buffer_allocator.h"
|
|
20
|
+
#include "quiche/quic/core/web_transport_interface.h"
|
|
21
|
+
#include "quiche/quic/platform/api/quic_logging.h"
|
|
22
|
+
#include "quiche/common/quiche_circular_deque.h"
|
|
23
|
+
|
|
24
|
+
namespace quic
|
|
25
|
+
{
|
|
26
|
+
class Http3EventLoop;
|
|
27
|
+
|
|
28
|
+
class Http3WTStreamJS;
|
|
29
|
+
|
|
30
|
+
class Http3WTStream
|
|
31
|
+
{
|
|
32
|
+
friend Http3WTStreamJS;
|
|
33
|
+
|
|
34
|
+
public:
|
|
35
|
+
Http3WTStream(WebTransportStream *stream) : stream_(stream),
|
|
36
|
+
js_(nullptr)
|
|
37
|
+
{
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
~Http3WTStream(){/*printf("stream destruct %x\n", this);*/};
|
|
41
|
+
|
|
42
|
+
class Visitor : public WebTransportStreamVisitor
|
|
43
|
+
{
|
|
44
|
+
public:
|
|
45
|
+
Visitor(Http3WTStream *stream) : stream_(stream), lasterror(0) {}
|
|
46
|
+
|
|
47
|
+
~Visitor();
|
|
48
|
+
|
|
49
|
+
void OnCanRead() override
|
|
50
|
+
{
|
|
51
|
+
stream_->doCanRead();
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
void OnCanWrite() override
|
|
55
|
+
{
|
|
56
|
+
stream_->doCanWrite();
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
void OnResetStreamReceived(WebTransportStreamError error) override;
|
|
60
|
+
|
|
61
|
+
void OnStopSendingReceived(WebTransportStreamError /*error*/) override;
|
|
62
|
+
|
|
63
|
+
void OnWriteSideInDataRecvdState() override;
|
|
64
|
+
|
|
65
|
+
protected:
|
|
66
|
+
Http3WTStream *stream_;
|
|
67
|
+
WebTransportStreamError lasterror;
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
void doCanRead();
|
|
71
|
+
|
|
72
|
+
void doCanWrite();
|
|
73
|
+
|
|
74
|
+
void doStopReading()
|
|
75
|
+
{
|
|
76
|
+
pause_reading_ = true;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
void doDrainReads()
|
|
80
|
+
{
|
|
81
|
+
pause_reading_ = false;
|
|
82
|
+
drain_reads_ = true;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
void tryWrite()
|
|
86
|
+
{
|
|
87
|
+
if (stream_ && stream_->CanWrite())
|
|
88
|
+
{
|
|
89
|
+
doCanWrite();
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
void tryRead()
|
|
94
|
+
{
|
|
95
|
+
pause_reading_ = false;
|
|
96
|
+
if (stream_ && ((stream_->ReadableBytes() > 0) || can_read_pending_))
|
|
97
|
+
{
|
|
98
|
+
can_read_pending_ = false;
|
|
99
|
+
doCanRead();
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
Http3WTStreamJS *getJS()
|
|
104
|
+
{
|
|
105
|
+
return js_;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
void setJS(Http3WTStreamJS *js)
|
|
109
|
+
{
|
|
110
|
+
js_ = js;
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
bool gone()
|
|
114
|
+
{
|
|
115
|
+
return !stream_;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
protected:
|
|
119
|
+
// internal functions called by js object
|
|
120
|
+
|
|
121
|
+
void streamFinalInt()
|
|
122
|
+
{
|
|
123
|
+
send_fin_ = true;
|
|
124
|
+
tryWrite();
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
void stopSendingInt(unsigned int reason);
|
|
128
|
+
void resetStreamInt(unsigned int reason);
|
|
129
|
+
|
|
130
|
+
WebTransportStream *stream() { return stream_; }
|
|
131
|
+
|
|
132
|
+
struct WChunks
|
|
133
|
+
{
|
|
134
|
+
char *buffer;
|
|
135
|
+
size_t len;
|
|
136
|
+
Napi::ObjectReference *bufferhandle;
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
void writeChunkInt(char *buffer, size_t len, Napi::ObjectReference *bufferhandle)
|
|
140
|
+
{
|
|
141
|
+
if (fin_was_sent_ || send_fin_)
|
|
142
|
+
{
|
|
143
|
+
cancelWrite(bufferhandle);
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
if (!stream_)
|
|
147
|
+
{
|
|
148
|
+
cancelWrite(bufferhandle);
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
WChunks cur;
|
|
152
|
+
cur.buffer = buffer;
|
|
153
|
+
cur.len = len;
|
|
154
|
+
cur.bufferhandle = bufferhandle;
|
|
155
|
+
chunks_.push_back(cur);
|
|
156
|
+
tryWrite();
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
void cancelWrite(Napi::ObjectReference *handle);
|
|
160
|
+
|
|
161
|
+
private:
|
|
162
|
+
Http3WTStreamJS *js_;
|
|
163
|
+
|
|
164
|
+
WebTransportStream *stream_;
|
|
165
|
+
bool send_fin_ = false;
|
|
166
|
+
bool fin_was_sent_ = false;
|
|
167
|
+
bool stop_sending_received_ = false;
|
|
168
|
+
bool pause_reading_ = false;
|
|
169
|
+
bool drain_reads_ = false;
|
|
170
|
+
bool can_read_pending_ = false;
|
|
171
|
+
bool stream_was_reset_ = false;
|
|
172
|
+
std::deque<WChunks> chunks_;
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
class Http3WTStreamJS : public Napi::ObjectWrap<Http3WTStreamJS>
|
|
176
|
+
{
|
|
177
|
+
friend Http3WTStream;
|
|
178
|
+
friend Http3WTStream::Visitor;
|
|
179
|
+
|
|
180
|
+
public:
|
|
181
|
+
class StreamReadBuffer
|
|
182
|
+
{
|
|
183
|
+
public:
|
|
184
|
+
StreamReadBuffer(Http3WTStreamJS *jsobj) : fin(false), jsobj_(jsobj),
|
|
185
|
+
buffer_(nullptr), buffersize_(0)
|
|
186
|
+
{
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
void getBuffer(size_t reqsize);
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
unsigned char * bufferData() { return buffer_;};
|
|
194
|
+
size_t bufferSize() { return buffersize_;};
|
|
195
|
+
|
|
196
|
+
bool hasBuffer() {return buffer_ != nullptr;}
|
|
197
|
+
|
|
198
|
+
void commitBuffer(uint32_t readbytes, bool drained);
|
|
199
|
+
|
|
200
|
+
void setFin() { fin = true;}
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
protected:
|
|
204
|
+
Napi::ObjectReference bufferObj;
|
|
205
|
+
unsigned char *buffer_;
|
|
206
|
+
size_t buffersize_;
|
|
207
|
+
// buffer?: Uint8Array
|
|
208
|
+
// byob?
|
|
209
|
+
bool fin;
|
|
210
|
+
Http3WTStreamJS *jsobj_; // unowned
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
public:
|
|
214
|
+
|
|
215
|
+
Http3WTStreamJS(const Napi::CallbackInfo &info) : Napi::ObjectWrap<Http3WTStreamJS>(info)
|
|
216
|
+
{
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
void init(Http3WTStream *wtstream);
|
|
220
|
+
|
|
221
|
+
// nan stuff
|
|
222
|
+
|
|
223
|
+
void startReading(const Napi::CallbackInfo &info)
|
|
224
|
+
{
|
|
225
|
+
wtstream_->tryRead();
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
void stopReading(const Napi::CallbackInfo &info)
|
|
229
|
+
{
|
|
230
|
+
wtstream_->doStopReading();
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
void drainReads(const Napi::CallbackInfo &info)
|
|
234
|
+
{
|
|
235
|
+
wtstream_->doDrainReads();
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
void writeChunk(const Napi::CallbackInfo &info)
|
|
239
|
+
{
|
|
240
|
+
// ok we have to get the buffer
|
|
241
|
+
|
|
242
|
+
const Napi::Object bufferlocal = info[0].ToObject();
|
|
243
|
+
Napi::ObjectReference *bufferhandle = new Napi::ObjectReference();
|
|
244
|
+
*bufferhandle = Napi::Persistent(bufferlocal);
|
|
245
|
+
|
|
246
|
+
char *buffer = bufferlocal.As<Napi::Buffer<char>>().Data();
|
|
247
|
+
size_t len = bufferlocal.As<Napi::Buffer<char>>().Length();
|
|
248
|
+
|
|
249
|
+
wtstream_->writeChunkInt(buffer, len, bufferhandle);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
void streamFinal(const Napi::CallbackInfo &info)
|
|
253
|
+
{
|
|
254
|
+
wtstream_->streamFinalInt();
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
void stopSending(const Napi::CallbackInfo &info)
|
|
258
|
+
{
|
|
259
|
+
unsigned int reason = 0;
|
|
260
|
+
|
|
261
|
+
if (!info[0].IsUndefined())
|
|
262
|
+
{
|
|
263
|
+
Napi::Number reasonl = info[0].ToNumber();
|
|
264
|
+
reason = reasonl.Int32Value();
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
wtstream_->stopSendingInt(reason);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
void resetStream(const Napi::CallbackInfo &info)
|
|
271
|
+
{
|
|
272
|
+
int code = 0;
|
|
273
|
+
unsigned int reason = 0;
|
|
274
|
+
|
|
275
|
+
if (!info[0].IsUndefined())
|
|
276
|
+
{
|
|
277
|
+
Napi::Number reasonl = info[0].ToNumber();
|
|
278
|
+
reason = reasonl.Int32Value();
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
wtstream_->resetStreamInt(reason);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
static void InitExports(Napi::Env env, Napi::Object exports, Http3Constructors *constr)
|
|
285
|
+
{
|
|
286
|
+
Napi::Function tplwtsv =
|
|
287
|
+
DefineClass(env, "Http3WTStreamVisitor",
|
|
288
|
+
{InstanceMethod<&Http3WTStreamJS::writeChunk>("writeChunk",
|
|
289
|
+
static_cast<napi_property_attributes>(napi_writable | napi_configurable)),
|
|
290
|
+
InstanceMethod<&Http3WTStreamJS::resetStream>("resetStream",
|
|
291
|
+
static_cast<napi_property_attributes>(napi_writable | napi_configurable)),
|
|
292
|
+
InstanceMethod<&Http3WTStreamJS::stopSending>("stopSending", static_cast<napi_property_attributes>(napi_writable | napi_configurable)),
|
|
293
|
+
InstanceMethod<&Http3WTStreamJS::streamFinal>("streamFinal", static_cast<napi_property_attributes>(napi_writable | napi_configurable)),
|
|
294
|
+
InstanceMethod<&Http3WTStreamJS::startReading>("startReading",
|
|
295
|
+
static_cast<napi_property_attributes>(napi_writable | napi_configurable)),
|
|
296
|
+
InstanceMethod<&Http3WTStreamJS::startReading>("drainReads",
|
|
297
|
+
static_cast<napi_property_attributes>(napi_writable | napi_configurable)),
|
|
298
|
+
InstanceMethod<&Http3WTStreamJS::stopReading>("stopReading",
|
|
299
|
+
static_cast<napi_property_attributes>(napi_writable | napi_configurable))});
|
|
300
|
+
constr->stream = Napi::Persistent(tplwtsv);
|
|
301
|
+
exports.Set("Http3WTStreamVisitor", tplwtsv);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
void setObj(Http3WTStream *wtstream)
|
|
305
|
+
{
|
|
306
|
+
wtstream_ = std::unique_ptr<Http3WTStream>(wtstream);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
Http3WTStream *getObj()
|
|
310
|
+
{
|
|
311
|
+
return wtstream_.get();
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
protected:
|
|
315
|
+
std::unique_ptr<Http3WTStream> wtstream_;
|
|
316
|
+
|
|
317
|
+
void processStreamWrite(Napi::ObjectReference *bufferhandle, bool success);
|
|
318
|
+
void processStreamNetworkFinish(NetworkTask task);
|
|
319
|
+
void processStreamRecvSignal(WebTransportStreamError error_code, NetworkTask task);
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
#endif
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
// Copyright (c) 2022 Marten Richter or other contributers (see commit). All rights reserved.
|
|
2
|
+
// Use of this source code is governed by a BSD-style license that can be
|
|
3
|
+
// found in the LICENSE file.
|
|
4
|
+
|
|
5
|
+
// portions taken from libquiche, original copyright, see LICENSE.chromium
|
|
6
|
+
// Copyright (c) The Chromium Authors. All rights reserved.
|
|
7
|
+
// Use of this source code is governed by a BSD-style license that can be
|
|
8
|
+
// found in the LICENSE file.
|
|
9
|
+
|
|
10
|
+
#include "src/librarymain.h"
|
|
11
|
+
#include "src/http3server.h"
|
|
12
|
+
#include "src/http3client.h"
|
|
13
|
+
#include "src/http3dispatcher.h"
|
|
14
|
+
#include "src/http3wtsessionvisitor.h"
|
|
15
|
+
#include "src/napialarmfactory.h"
|
|
16
|
+
#include "quiche/common/platform/api/quiche_command_line_flags.h"
|
|
17
|
+
|
|
18
|
+
#include "absl/log/initialize.h"
|
|
19
|
+
#include "absl/strings/string_view.h"
|
|
20
|
+
|
|
21
|
+
using namespace Napi;
|
|
22
|
+
|
|
23
|
+
namespace quic
|
|
24
|
+
{
|
|
25
|
+
bool hasSetLogging = false;
|
|
26
|
+
|
|
27
|
+
void quicheInit(const Napi::CallbackInfo &info)
|
|
28
|
+
{
|
|
29
|
+
std::vector<std::string> quiche_cmd_line;
|
|
30
|
+
quiche_cmd_line.push_back(std::string("webtransport.node"));
|
|
31
|
+
if (!info[0].IsUndefined() /*|| info[1].IsFunction()*/)
|
|
32
|
+
{
|
|
33
|
+
Napi::Object lobj = info[0].ToObject();
|
|
34
|
+
if (lobj.IsEmpty())
|
|
35
|
+
{
|
|
36
|
+
Napi::Error::New(info.Env(), "No callback obj for Http3Transport").ThrowAsJavaScriptException();
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
quiche_cmd_line.push_back(std::string("-v"));
|
|
41
|
+
if (lobj.Has("quicheLogVerbose") && lobj.Get("quicheLogVerbose").IsFunction())
|
|
42
|
+
{
|
|
43
|
+
Napi::Value verboseValue = (lobj).Get("quicheLogVerbose");
|
|
44
|
+
quiche_cmd_line.push_back(verboseValue.ToString().Utf8Value());
|
|
45
|
+
}
|
|
46
|
+
else
|
|
47
|
+
{
|
|
48
|
+
quiche_cmd_line.push_back(std::string("-1"));
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
else
|
|
52
|
+
{
|
|
53
|
+
Napi::Error::New(info.Env(), "Callback not passed to Webtransport library internals").ThrowAsJavaScriptException();
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
std::vector<const char *> quiche_cmd_line_char;
|
|
57
|
+
for (auto cur = quiche_cmd_line.begin(); cur != quiche_cmd_line.end(); cur++)
|
|
58
|
+
{
|
|
59
|
+
quiche_cmd_line_char.push_back((*cur).c_str());
|
|
60
|
+
}
|
|
61
|
+
if (!hasSetLogging)
|
|
62
|
+
{
|
|
63
|
+
quiche::QuicheParseCommandLineFlags("No use instruction.", quiche_cmd_line.size(), &(*quiche_cmd_line_char.begin()));
|
|
64
|
+
hasSetLogging = true;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
Napi::Object Init(Napi::Env env, Napi::Object exports)
|
|
69
|
+
{
|
|
70
|
+
Http3Constructors *constr = new Http3Constructors();
|
|
71
|
+
|
|
72
|
+
Http3ServerJS::InitExports(env, exports);
|
|
73
|
+
Http3ClientJS::InitExports(env, exports);
|
|
74
|
+
Http3WTSessionJS::InitExports(env, exports, constr);
|
|
75
|
+
Http3WTStreamJS::InitExports(env, exports, constr);
|
|
76
|
+
NapiAlarmJS::InitExports(env, exports, constr);
|
|
77
|
+
Napi::Function qinitna = Function::New<quicheInit>(env);
|
|
78
|
+
constr->quicheInit = Napi::Persistent(qinitna);
|
|
79
|
+
exports.Set("quicheInit", qinitna);
|
|
80
|
+
|
|
81
|
+
env.SetInstanceData<Http3Constructors>(constr);
|
|
82
|
+
return exports;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
NODE_API_MODULE(webtransport, Init)
|
|
86
|
+
}
|