Jens-G opened a new pull request, #3781:
URL: https://github.com/apache/thrift/pull/3781

   > **Stacked on #3780 (THRIFT-6177).** Only the second commit belongs to this 
ticket. Merge #3780 first and this rebases to a single commit.
   
   `TWebSocketServer::readFrame` reads a frame's payload with a single call to 
the transport underneath and treats anything short of the whole payload as end 
of stream:
   
   ```cpp
   read = transport_->read(buffer, length);
   readBuffer_.wroteBytes(read);
   if (read < length) {
     return false;
   }
   ```
   
   `TSocket::read` performs one `recv()` and returns whatever that produced, 
and the transport factory hands `TWebSocketServer` the accepted `TSocket` 
itself, so the payload arrives in as many pieces as the network chose. 
Returning `false` makes `readAll_virt` return 0, which the caller reads as a 
closed connection.
   
   So no frame whose payload does not arrive in one read can be received at 
all. Demonstrated with a `TServerSocket`, a `TWebSocketServer` over the 
accepted socket, and a client writing a well-formed 4000-byte frame as 2000 + 
2000 bytes with a pause between them:
   
   ```
   client: payload 4000 bytes, sent as 2000 + 2000 with 300 ms between
   server: readAll returned 0 of 4000
   ```
   
   and with this change, over the same socket:
   
   ```
   server: readAll returned 4000 of 4000
   server: payload intact: yes
   ```
   
   In practice this is any frame past the path MTU, so the transport could not 
carry a Thrift message beyond roughly 1.4 kB over an ordinary Ethernet path.
   
   ### The fix
   
   Read the payload with `readAll()`, which is how 
`TFramedTransport::readFrame` reads its own frames, and keep the existing 
signal for a peer that leaves in the middle of one: `readAll` raises 
`END_OF_FILE`, which is caught and turned back into the same `return false` the 
caller sees today. Nothing else about the contract changes.
   
   ### Why it is stacked
   
   `readAll()` waits for the number of bytes the frame declared. That is only 
safe once that number is bounded, which is what #3780 does — without it, a 
header declaring `0xFFFFFFFF` would make the server wait for 4 GB rather than 
return. With it, the wait is bounded by `TConfiguration::maxFrameSize` and by 
the socket's own receive timeout, the same two limits that bound 
`TFramedTransport`.
   
   ### Tests
   
   Two more cases in `lib/cpp/test/TWebSocketServerTest.cpp`:
   
   - a frame delivered as 8 + 1000 + the rest arrives whole — fails before the 
change with `0 != 4000`;
   - a frame whose payload stops after 500 bytes is still reported as end of 
stream rather than handed over half-read — passes either way, and is there so 
that waiting for the rest of a frame cannot quietly become handing a half-read 
one to the protocol.
   
   Full `bin/UnitTests`: 108 of 109. The one failure, 
`TServerSocketTest/test_bind_to_address`, is a pre-existing environment failure 
on this host and is present on `master`.
   
   🤖 Generated with [Claude Code](https://claude.com/claude-code)
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to