1. 18 Apr, 2018 4 commits
    • Kenton Varda's avatar
      Further improve http-test to avoid initializing async I/O at all in most tests. · 2c57e5cb
      Kenton Varda authored
      Yay for fake timers in tests.
      2c57e5cb
    • Kenton Varda's avatar
      Use new userspace pipes in http-test. · 1e542ad1
      Kenton Varda authored
      This speeds up the test somewhat, but more importantly, it tests the pipe implementation across a variety of usage patterns.
      
      This actually uncovered a bug in the HTTP implementation: An HttpClient could inadvertently issue overlapping reads in cases where multiple concurrent (pipelined) requests are made.
      1e542ad1
    • Kenton Varda's avatar
      Implement in-process byte stream pipes. · 7117175d
      Kenton Varda authored
      This lets you construct an AsyncInputStream / AsyncOutputStream pair that operates entirely within userspace, rather than pushing through a kernel-level pipe. This is far more efficient, avoiding system calls and reducing copies.
      
      The pipe does not buffer at all. Instead, it waits for both a read() and a write() call to be active at the same time, and then it fulfills one with the other.
      
      This implementation also optimizes pumps. Imagine the situation: you create a pipe; you call pumpTo() on the write end to pump it to some other; then you write to the write end of the pipe. In this case, the write will *directly* call the target stream to which the pipe is being pumped. Hence, adding daisy-chained pipes on top of a final output stream does not incur additional copies of the data. Similarly, tryPumpFrom() is optimized on the read end.
      7117175d
    • Kenton Varda's avatar
      Implement 'Canceler' for managing side-band promise cancelation. · 0df23c4f
      Kenton Varda authored
      This is necessary when someone other than the promise owner might need to destroy the state a promise is operating on. It comes up when implementing pumpTo() for userland pipes -- cancelling the pump needs to cancel any writes currently passing through the pipe.
      0df23c4f
  2. 09 Apr, 2018 2 commits
    • Kenton Varda's avatar
      Merge pull request #659 from capnproto/head-content-length · 394643ba
      Kenton Varda authored
      Allow app to send arbitrary Content-Length/Transfer-Encoding in HEAD responses.
      394643ba
    • Kenton Varda's avatar
      Allow app to send arbitrary Content-Length/Transfer-Encoding in HEAD responses. · be9b18c5
      Kenton Varda authored
      Previously, the app could control Content-Length by passing `expectedBodySize`. This is great for enabling code that "just works" by handling GET and HEAD requests identically.
      
      However, in somewhat more-complicated situations -- especilaly in proxies -- you end up having to write special-case hacks for HEAD requests to deal with the fact that the body is actually empty, but has a non-zero "expected" size.
      
      We can make life easier for proxies by allowing the application to directly set the Content-Length and Transfer-Encoding headers in the case of HEAD responses, much like we allow applications to set WebSocket-related headers on non-WebSocket requests/responses.
      
      This change actually fixes a bug in Cloudflare Workers where Content-Length is not passed through correctly for HEAD responses. No changes are needed on the Workers side (except adding a test).
      be9b18c5
  3. 03 Apr, 2018 2 commits
  4. 02 Apr, 2018 6 commits
  5. 29 Mar, 2018 1 commit
    • Harris Hancock's avatar
      Implement URL fragment, path, and userinfo component encode functions · 084f5526
      Harris Hancock authored
      According to the WHATWG URL spec, each different component of a URL gets its very own percent encode set, which we've been doing wrong this whole time.
      
      In terms of reserved characters, the fragment set is a subset of the path set, which is a subset of the userinfo set, which is a subset of RFC 2396's reserved set.
      084f5526
  6. 23 Mar, 2018 1 commit
  7. 22 Mar, 2018 3 commits
  8. 19 Mar, 2018 3 commits
  9. 15 Mar, 2018 3 commits
  10. 13 Mar, 2018 5 commits
  11. 26 Feb, 2018 1 commit
  12. 25 Feb, 2018 1 commit
  13. 23 Feb, 2018 2 commits
    • Kenton Varda's avatar
      Extend HttpServer to inform the caller when a connection ends cleanly on drain(). · 098004cd
      Kenton Varda authored
      This allows an application which calls drain() to potentially pass off HTTP connections to a new HttpServer afterwards. Without this, the application has no way to know if the connections are in an indeterminant state.
      
      This change also makes it OK for an application to fail to read the whole request body. Previously, if an app returned a response without reading the whole request, an exception would eventually be thrown, but potentially not until the client had initiated a new request on the same connection. The client would then get a spurious 500 error.
      098004cd
    • Kenton Varda's avatar
      18f7ff52
  14. 17 Feb, 2018 1 commit
  15. 16 Feb, 2018 4 commits
  16. 13 Feb, 2018 1 commit
    • Kenton Varda's avatar
      Redesign server-side WebSocket handling. · 632888d6
      Kenton Varda authored
      Previously HttpService had two virtual methods: request() and openWebSocket(). Since it's legitimate to respond to a WebSocket request with a normal HTTP response, openWebSocket() actually had a default implementation that fell back to request().
      
      In the new design, there is only request(). The HttpService detects a WebSocket request by checking the headers. A convenience method, HttpHeaders::isWebSocket(), is provided for this purpose.
      
      The new approach makes life much easier for services composed of many layers. For example, you might write an HttpService implementation which performs some URL or header rewrite and then calls on to another HttpService. Previously, every such wrapper would have to separately handle regular requests and WebSockets, usually with near-identical code. Of course, you could factor out the common code, but in practice this often turned out pretty clunky. Worse, developers would often just omit the openWebSocket() implementation since implementing only request() seems to work fine -- until you need a WebSocket, and everything is broken. With the new approach, you have to go somewhat out of your way to write a wrapper layer that breaks WebSockets.
      
      I did not apply the same logic to HttpClient because:
      
      1. It's not as easy: HttpClient's methods return results rather than calling a callback on completion, so unifying the methods would have forced request()'s signature to change. Lots of code would need to be updated, and would likely become uglier, as request() would now have to return a `webSocketOrBody` variant type even when the caller isn't asking for a WebSocket.
      2. People don't implement custom HttpClients nearly as often as they implement custom HttpServices.
      632888d6