Conversation
0143a03 to
01fb3c7
Compare
Merging this PR will not alter performance
Comparing Footnotes
|
01fb3c7 to
545a1ab
Compare
|
The generated output of |
3948217 to
6303fbd
Compare
| connect({ socket, cf }) { | ||
| const enc = new TextEncoder(); | ||
| strictEqual(typeof cf.clientIp, 'string'); | ||
| socket.writable.getWriter().write(enc.encode('hello')); |
There was a problem hiding this comment.
Should this be closing? e.g. await writer.close()?
There was a problem hiding this comment.
When I do something like the following the test freezes and times out – I guess that might point to a bug in the implementation?
let writer = socket.writable.getWriter();
await writer.write(enc.encode('hello'));
await writer.closed;
There was a problem hiding this comment.
await writer.closed does not trigger closing... if nothing triggers the actual closing (e.g. writer.close() or something) then I would fully expect await writer.closed to hang
There was a problem hiding this comment.
Calling writer.close() works, but if I await that (or do await writer.closed afterwards) this still hangs. I haven't worked with JS streams much before, but if I understand https://developer.mozilla.org/en-US/docs/Web/API/WritableStreamDefaultWriter/close correctly it's supposed to work?
There was a problem hiding this comment.
Supposed to, yes. That would suggest that the close promise is not being resolved, which would imply the connection isn't fully shutting down. @dom96 may have some ideas here since he wrote the socket impl initially.
26ab0db to
fe861bd
Compare
samples/tcp-ingress/worker.js
Outdated
|
|
||
| async connect(socket) { | ||
| // pipe the input stream to the output | ||
| socket.readable.pipeTo(socket.writable); |
There was a problem hiding this comment.
Needs to await the pipeTo or it may get canceled because it thinks the i/o is complete
| socket.readable.pipeTo(socket.writable); | |
| await socket.readable.pipeTo(socket.writable); |
jasnell
left a comment
There was a problem hiding this comment.
Follow-up review findings:
- [HIGH]
NeuterableIoStreammade globally refcounted — affects all existing users - [HIGH]
isDefaultFetchPortlogic semantically wrong for TCP ingress - [HIGH]
exceptionToPropagatehas external linkage; should bestaticor in anonymous namespace - [MEDIUM] Stack-allocated
HttpHeaderTablein connect handler; should reuse existing table - [MEDIUM]
TODO(now)needs resolution before merge - [MEDIUM]
KJ_LOG(WARNING)on every accepted TCP connection is noisy - [MEDIUM] Unused
rewritermember inTcpListener - [LOW] Misnamed variable in
writeOnsetInfotrace code - [LOW] Test decodes chunks twice
- [LOW] ConnectHandler parameter named
connectshadows member name
This review was generated with AI assistance and may contain inaccuracies.
| kj::Own<Service> service; | ||
| kj::HttpHeaderTable& headerTable; | ||
| kj::Own<HttpRewriter> rewriter; | ||
| kj::StringPtr addrStr; |
There was a problem hiding this comment.
[MEDIUM] rewriter is stored but never used. TCP connections don't need HTTP rewriting. Consider removing this member and the corresponding constructor parameter. This also means HttpRewriter doesn't need to be created for TCP sockets in listenOnSockets().
There was a problem hiding this comment.
Likely needs to be kept alive, even if not used?
3a01d49 to
b626b42
Compare
Implements the connect handler and tcp-ingress for a worker See the samples/tcp-ingress for an example Eliminate code duplication in server.c++ Require experimental flag for tcp ingress
b626b42 to
027d7d8
Compare
This PR implements support for defining a connect() handler, which is behind an experimental compat flag for now. This is largely based on James' previous PR for this (#1429), but includes changes to switch to the socket-based API, drop the deferred proxying code, add more tests, add proper tracing support etc. I don't have a strong background on how workerd/KJ streams work yet – there might be trivial issues in how streams are being used. You'll notice that this PR differs from the internal spec in that it still provides an event to the tail handler and there are several other issues – see the open questions below where I'm looking for input on how to best address this.
Open questions:
This still provides a ConnectEvent with a cfJson field to the JS connect handler: Based on the internal discussion, a cfJson field should not be needed, but the parameters set to be provided in server.c++ (clientIp, clientPid, clientUid) feel like they might be useful – should there be a different way to provide such metadata? Otherwise I'll change this to just provide a plain socket as the first parameter to the handler (as discussed on the internal spec)[Unchanged from previous PR] The headers provided by the incoming connect() call should be passed through instead of being discarded, right?We currently construct a neuterable stream in ServiceWorkerGlobalScope::connect() without really needing to do so – there should be a cleaner way to get an owned AsyncIoStream?I assume that HTTP response codes are not needed for TCP? This is relevant for the tail worker return event, which has an optional return code.Do we need to use HttpRewriter at all for TCP in server.c++? server.c++'sTcpListenerhas remnants of support for this left, but since it's not dealing with HTTP, rewriting might not be neededWindows tests are failing – perhaps related to EW-9330 Implement connect() handler #6059 (comment)?The following assumptions were made in implementing this:
I'm assuming that with the socket-based API, neuterable streams are not needed since deferred proxying does not need to be implemented.We may want TLS support in the future, but this is not included for now.