httpx 0.11.1 → 0.13.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.
- checksums.yaml +4 -4
 - data/README.md +2 -2
 - data/doc/release_notes/0_11_1.md +5 -1
 - data/doc/release_notes/0_11_2.md +5 -0
 - data/doc/release_notes/0_11_3.md +5 -0
 - data/doc/release_notes/0_12_0.md +55 -0
 - data/doc/release_notes/0_13_0.md +58 -0
 - data/doc/release_notes/0_13_1.md +5 -0
 - data/lib/httpx.rb +2 -1
 - data/lib/httpx/adapters/faraday.rb +4 -6
 - data/lib/httpx/altsvc.rb +1 -0
 - data/lib/httpx/chainable.rb +2 -2
 - data/lib/httpx/connection.rb +80 -28
 - data/lib/httpx/connection/http1.rb +19 -6
 - data/lib/httpx/connection/http2.rb +32 -25
 - data/lib/httpx/io.rb +16 -3
 - data/lib/httpx/io/ssl.rb +35 -24
 - data/lib/httpx/io/tcp.rb +50 -28
 - data/lib/httpx/io/tls.rb +218 -0
 - data/lib/httpx/io/tls/box.rb +365 -0
 - data/lib/httpx/io/tls/context.rb +199 -0
 - data/lib/httpx/io/tls/ffi.rb +390 -0
 - data/lib/httpx/io/unix.rb +27 -12
 - data/lib/httpx/options.rb +11 -23
 - data/lib/httpx/parser/http1.rb +4 -4
 - data/lib/httpx/plugins/aws_sdk_authentication.rb +81 -0
 - data/lib/httpx/plugins/aws_sigv4.rb +218 -0
 - data/lib/httpx/plugins/compression.rb +20 -8
 - data/lib/httpx/plugins/compression/brotli.rb +8 -6
 - data/lib/httpx/plugins/compression/deflate.rb +4 -7
 - data/lib/httpx/plugins/compression/gzip.rb +2 -2
 - data/lib/httpx/plugins/cookies/set_cookie_parser.rb +1 -1
 - data/lib/httpx/plugins/digest_authentication.rb +1 -1
 - data/lib/httpx/plugins/follow_redirects.rb +1 -1
 - data/lib/httpx/plugins/h2c.rb +43 -58
 - data/lib/httpx/plugins/internal_telemetry.rb +93 -0
 - data/lib/httpx/plugins/multipart.rb +2 -0
 - data/lib/httpx/plugins/multipart/encoder.rb +4 -9
 - data/lib/httpx/plugins/proxy.rb +1 -1
 - data/lib/httpx/plugins/proxy/http.rb +1 -1
 - data/lib/httpx/plugins/proxy/socks4.rb +8 -0
 - data/lib/httpx/plugins/proxy/socks5.rb +8 -0
 - data/lib/httpx/plugins/push_promise.rb +3 -2
 - data/lib/httpx/plugins/retries.rb +2 -2
 - data/lib/httpx/plugins/stream.rb +6 -6
 - data/lib/httpx/plugins/upgrade.rb +83 -0
 - data/lib/httpx/plugins/upgrade/h2.rb +54 -0
 - data/lib/httpx/pool.rb +14 -6
 - data/lib/httpx/registry.rb +1 -7
 - data/lib/httpx/request.rb +11 -1
 - data/lib/httpx/resolver/https.rb +3 -11
 - data/lib/httpx/response.rb +14 -7
 - data/lib/httpx/selector.rb +5 -0
 - data/lib/httpx/session.rb +25 -2
 - data/lib/httpx/transcoder/body.rb +3 -5
 - data/lib/httpx/version.rb +1 -1
 - data/sig/chainable.rbs +2 -1
 - data/sig/connection/http1.rbs +3 -2
 - data/sig/connection/http2.rbs +5 -3
 - data/sig/options.rbs +7 -20
 - data/sig/plugins/aws_sdk_authentication.rbs +17 -0
 - data/sig/plugins/aws_sigv4.rbs +64 -0
 - data/sig/plugins/compression.rbs +5 -3
 - data/sig/plugins/compression/brotli.rbs +1 -1
 - data/sig/plugins/compression/deflate.rbs +1 -1
 - data/sig/plugins/compression/gzip.rbs +1 -1
 - data/sig/plugins/cookies.rbs +0 -1
 - data/sig/plugins/digest_authentication.rbs +0 -1
 - data/sig/plugins/expect.rbs +0 -2
 - data/sig/plugins/follow_redirects.rbs +0 -2
 - data/sig/plugins/h2c.rbs +5 -10
 - data/sig/plugins/persistent.rbs +0 -1
 - data/sig/plugins/proxy.rbs +0 -1
 - data/sig/plugins/push_promise.rbs +1 -1
 - data/sig/plugins/retries.rbs +0 -4
 - data/sig/plugins/upgrade.rbs +23 -0
 - data/sig/response.rbs +3 -1
 - metadata +24 -2
 
    
        checksums.yaml
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            ---
         
     | 
| 
       2 
2 
     | 
    
         
             
            SHA256:
         
     | 
| 
       3 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       4 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: e3859c516c1cdddc64f8105fafd5425da26074582b1590cc87f65401a909e0e2
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: 209b5c1fba921d69f9aa2167ccb0f4b6b45a1a28667364eefef8026104004f53
         
     | 
| 
       5 
5 
     | 
    
         
             
            SHA512:
         
     | 
| 
       6 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       7 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: 3862b4879291aa944b92c50d232abc6413a170f2bcd501d6f33a1ca55a99a1411dd0d4f2b6a50b92a8b1465fa42b654ef658c15a91154205bfd60bcdc983c5a5
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: 6b2f721cc2bb8e0fe7267517dcd146fe50f448676bcec64e9744d5f358232d8d9c364acd6717e0df3a72bfcb1d154a7e4b74252324cf9a248f1fe062242eb4fe
         
     | 
    
        data/README.md
    CHANGED
    
    | 
         @@ -113,7 +113,7 @@ The test suite runs against [httpbin proxied over nghttp2](https://nghttp2.org/h 
     | 
|
| 
       113 
113 
     | 
    
         | 
| 
       114 
114 
     | 
    
         
             
            ## Supported Rubies
         
     | 
| 
       115 
115 
     | 
    
         | 
| 
       116 
     | 
    
         
            -
            All Rubies greater or equal to 2.1, and always latest JRuby.
         
     | 
| 
      
 116 
     | 
    
         
            +
            All Rubies greater or equal to 2.1, and always latest JRuby and Truffleruby.
         
     | 
| 
       117 
117 
     | 
    
         | 
| 
       118 
118 
     | 
    
         
             
            **Note**: This gem is tested against all latest patch versions, i.e. if you're using 2.2.0 and you experience some issue, please test it against 2.2.10 (latest patch version of 2.2) before creating an issue.
         
     | 
| 
       119 
119 
     | 
    
         | 
| 
         @@ -133,7 +133,7 @@ All Rubies greater or equal to 2.1, and always latest JRuby. 
     | 
|
| 
       133 
133 
     | 
    
         | 
| 
       134 
134 
     | 
    
         
             
            If your requirement is to run requests over HTTP/2 and TLS, make sure you run a version of the gem which compiles OpenSSL 1.0.2 (Ruby 2.3 and higher are guaranteed to).
         
     | 
| 
       135 
135 
     | 
    
         | 
| 
       136 
     | 
    
         
            -
             
     | 
| 
      
 136 
     | 
    
         
            +
            In order to use HTTP/2 under JRuby, [check this link](https://gitlab.com/honeyryderchuck/httpx/-/wikis/JRuby-Truffleruby-Other-Rubies) to know what to do.
         
     | 
| 
       137 
137 
     | 
    
         | 
| 
       138 
138 
     | 
    
         
             
            ### Known bugs
         
     | 
| 
       139 
139 
     | 
    
         | 
    
        data/doc/release_notes/0_11_1.md
    CHANGED
    
    
| 
         @@ -0,0 +1,5 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # 0.11.3
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            ## Bugfixes
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            `EOFError` was being thrown when HTTP/1.1 non-chunked responses which don't contain a "content-length" header. The RFC mandates that the socket should be consumed until the server closes it, so a patch was implemented, to return the available response in such cases.
         
     | 
| 
         @@ -0,0 +1,55 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # 0.12.0
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            ## Features
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            ### AWS Sigv4 Authentication Plugin
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            A new plugin, `:aws_sigv4`, is now shipped with `httpx`. It implements the [AWS Signature Version 4 request signing process](https://docs.aws.amazon.com/general/latest/gr/signature-version-4.html), a well documented way of authenticating requests to AWS services, which has since been adopted by other cloud providers, such as Google Cloud Storage.
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
            See how to use it here: https://gitlab.com/honeyryderchuck/httpx/-/wikis/AWS-Sigv4#sessionaws_sigv4_authentication
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
            For convenience, there's a derivative plugin, `:aws_sdk_authentication`, which builds on top of `:aws_sigv4`, and integrates with the `aws-sdk-core` gem, maintained by AWS, to resolve the authentication credentials (p.ex. if you support ephemeral access keys).
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
            See how to use it here: https://gitlab.com/honeyryderchuck/httpx/-/wikis/AWS-Sigv4#sessionaws_sdk_authentication
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
            Other FAQ: https://gitlab.com/honeyryderchuck/httpx/-/wikis/AWS-Sigv4#faqs
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
            ### HTTP/2 support for JRuby
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
            `jruby-openssl` doesn't support ALPN protocol negotiation, nor are there plans to implement, which limited the seamless HTTP/2 usage in `httpx`. A new connection adapter was therefore added specifically for JRuby, where ssl/tls connections will be handled using ffi-based openssl bindings, provided you bundle `ffi-compiler` and `concurrent-ruby`, and install a TLS/1.2-compatible `openssl` package.
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
            See how to use it here: https://gitlab.com/honeyryderchuck/httpx/-/wikis/JRuby-Truffleruby-Other-Rubies#http2
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
            ## Improvements
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
            ### truffleruby support
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
            `httpx` supports and tests against `truffleruby` (known to run tests since v20.3, passing all tests since v21).
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
            ### Performance
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
            Several optimizations were introduced:
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
            * Reduction in read/write system calls;
         
     | 
| 
      
 35 
     | 
    
         
            +
            * more usage of `String#byteslice` in parsing (instead of string mutation);
         
     | 
| 
      
 36 
     | 
    
         
            +
            * Avoid selection on connections with no outstanding requests;
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
            They all contributed to a massive performance improvement, itself reflected in test runs, which need half the time they used to to complete.
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
            ### APIs
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
            * `HTTPX::ErrorResponse#to_s` now uses the exception full message, instead of just the backtrace.
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
            ## Bugfixes
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
            * HTTP/2 stream protocol errors do not cause the process to hang (instead, error responnses are yielded);
         
     | 
| 
      
 47 
     | 
    
         
            +
            * Fixed body stream bugs on retries when error causing retry would happen mid-transfer;
         
     | 
| 
      
 48 
     | 
    
         
            +
            * Fixed `:multipart` plugin body rewind on retries to start the transfer from the beginning;
         
     | 
| 
      
 49 
     | 
    
         
            +
            * Fixed auto-load of  `:proxy` plugin when `HTTPS_PROXY` or `HTTP_PROXY` is set;
         
     | 
| 
      
 50 
     | 
    
         
            +
            * Errno::EPIPE errors mid transfer now cause `httpx` to read from the server and get the appropriate HTTP error response;
         
     | 
| 
      
 51 
     | 
    
         
            +
            * Make sure that all requests have an error responnse if the error happens early;
         
     | 
| 
      
 52 
     | 
    
         
            +
            * Fixed TCP handshake Errno::INPROGRESS handling inside TLS connnections, which was causing the process to hang in a high handshake contention scenario;
         
     | 
| 
      
 53 
     | 
    
         
            +
            * Do not call the event loop if there's nothing to listen on (the DoH resolver was being listened on even if there was nothing to be request);
         
     | 
| 
      
 54 
     | 
    
         
            +
            * Fixed double event registry for DoH resolvers;
         
     | 
| 
      
 55 
     | 
    
         
            +
            * 
         
     | 
| 
         @@ -0,0 +1,58 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # 0.13.0
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            ## Features
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            ### Upgrade plugin
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            A new plugin, `:upgrade`, is now available. This plugin allows one to "hook" on HTTP/1.1's protocol upgrade mechanism (see: https://developer.mozilla.org/en-US/docs/Web/HTTP/Protocol_upgrade_mechanism), which is the mechanism that browsers use to initiate websockets (there is an example of how to use `httpx` to start a websocket client connection [in the tests](https://gitlab.com/honeyryderchuck/httpx/-/blob/master/test/support/requests/plugins/upgrade.rb))
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
            You can read more about the `:upgrade` plugin in the [wiki](https://honeyryderchuck.gitlab.io/httpx/wiki/Connection-Upgrade).
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
            It's the basis of two plugins:
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
            #### `:h2c`
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
            This plugin was been rewritten on top of the `:upgrade` plugin, and handles upgrading a plaintext (non-"https") HTTP/1.1 connection, into an HTTP/2 connection.
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
            https://honeyryderchuck.gitlab.io/httpx/wiki/Connection-Upgrade#h2c
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
            #### `:upgrade/h2`
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
            This plugin handles when a server responds to a request with an `Upgrade: h2` header, does the following requests to the same origin via HTTP/2 prior knowledge (bypassing the necessity for ALPN negotiation, which is the whole point of the feature).
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
            https://honeyryderchuck.gitlab.io/httpx/wiki/Connection-Upgrade#h2
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
            ### `:addresses` option
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
            The `:addresses` option is now available. You can use it to pass a list of IPs to connect to:
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 30 
     | 
    
         
            +
            # will not resolve example.com, and instead connect to one of the IPs passed.
         
     | 
| 
      
 31 
     | 
    
         
            +
            HTTPX.get("http://example.com", addresses: %w[172.5.3.1 172.5.3.2]))
         
     | 
| 
      
 32 
     | 
    
         
            +
            ```
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
            You should also use it to connect to HTTP servers bound to a UNIX socket, in which case you'll have to provide a path:
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 37 
     | 
    
         
            +
            HTTPX.get("http://example.com", addresses: %w[/path/to/usocket]))
         
     | 
| 
      
 38 
     | 
    
         
            +
            ```
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
            The `:transport_options` are therefore deprecated, and will be moved in a major version.
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
            ## Improvements
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
            Some internal improvements that allow certainn plugins not to "leak" globally, such as the `:compression` plugin, which used to enable compression for all the `httpx` sessions from the same process. It doesn't anymore.
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
            Using exceptionless nonblocking connect calls in the supported rubies.
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
            Removed unneeded APIs around the Options object (`with_` methods, or the defined options list).
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
            ## Bugfixes
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
            HTTP/1.1 persistent connections were closing after each request after the max requests was reached. It's fixed, and the new connection will also be persistent.
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
            When passing open IO objects for origins (the `:io` option), `httpx` was still trying to resolve the origin's domain. This not only didn't make sense, it broke if the domain is unresolvable. It has been fixed.
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
            Fixed usage of `:io` option when passed an "authority/io" hash.
         
     | 
| 
      
 57 
     | 
    
         
            +
             
     | 
| 
      
 58 
     | 
    
         
            +
            Fixing some issues around trying to connnect to the next available IPAddress when the previous one was unreachable or ETIMEDOUT.
         
     | 
    
        data/lib/httpx.rb
    CHANGED
    
    | 
         @@ -19,7 +19,6 @@ require "httpx/headers" 
     | 
|
| 
       19 
19 
     | 
    
         
             
            require "httpx/request"
         
     | 
| 
       20 
20 
     | 
    
         
             
            require "httpx/response"
         
     | 
| 
       21 
21 
     | 
    
         
             
            require "httpx/chainable"
         
     | 
| 
       22 
     | 
    
         
            -
            require "httpx/session"
         
     | 
| 
       23 
22 
     | 
    
         | 
| 
       24 
23 
     | 
    
         
             
            # Top-Level Namespace
         
     | 
| 
       25 
24 
     | 
    
         
             
            #
         
     | 
| 
         @@ -59,3 +58,5 @@ module HTTPX 
     | 
|
| 
       59 
58 
     | 
    
         | 
| 
       60 
59 
     | 
    
         
             
              extend Chainable
         
     | 
| 
       61 
60 
     | 
    
         
             
            end
         
     | 
| 
      
 61 
     | 
    
         
            +
             
     | 
| 
      
 62 
     | 
    
         
            +
            require "httpx/session"
         
     | 
| 
         @@ -123,11 +123,9 @@ module Faraday 
     | 
|
| 
       123 
123 
     | 
    
         
             
                      end
         
     | 
| 
       124 
124 
     | 
    
         | 
| 
       125 
125 
     | 
    
         
             
                      def method_missing(meth, *args, &blk)
         
     | 
| 
       126 
     | 
    
         
            -
                         
     | 
| 
       127 
     | 
    
         
            -
             
     | 
| 
       128 
     | 
    
         
            -
                         
     | 
| 
       129 
     | 
    
         
            -
                          super
         
     | 
| 
       130 
     | 
    
         
            -
                        end
         
     | 
| 
      
 126 
     | 
    
         
            +
                        return super unless @env && @env.respond_to?(meth)
         
     | 
| 
      
 127 
     | 
    
         
            +
             
     | 
| 
      
 128 
     | 
    
         
            +
                        @env.__send__(meth, *args, &blk)
         
     | 
| 
       131 
129 
     | 
    
         
             
                      end
         
     | 
| 
       132 
130 
     | 
    
         
             
                    end
         
     | 
| 
       133 
131 
     | 
    
         | 
| 
         @@ -197,7 +195,7 @@ module Faraday 
     | 
|
| 
       197 
195 
     | 
    
         
             
                      response_headers.merge!(response.headers)
         
     | 
| 
       198 
196 
     | 
    
         
             
                    end
         
     | 
| 
       199 
197 
     | 
    
         
             
                    @app.call(env)
         
     | 
| 
       200 
     | 
    
         
            -
                  rescue  
     | 
| 
      
 198 
     | 
    
         
            +
                  rescue ::HTTPX::TLSError => e
         
     | 
| 
       201 
199 
     | 
    
         
             
                    raise SSL_ERROR, e
         
     | 
| 
       202 
200 
     | 
    
         
             
                  rescue Errno::ECONNABORTED,
         
     | 
| 
       203 
201 
     | 
    
         
             
                         Errno::ECONNREFUSED,
         
     | 
    
        data/lib/httpx/altsvc.rb
    CHANGED
    
    
    
        data/lib/httpx/chainable.rb
    CHANGED
    
    | 
         @@ -17,12 +17,12 @@ module HTTPX 
     | 
|
| 
       17 
17 
     | 
    
         
             
                # :nocov:
         
     | 
| 
       18 
18 
     | 
    
         
             
                def timeout(**args)
         
     | 
| 
       19 
19 
     | 
    
         
             
                  warn ":#{__method__} is deprecated, use :with_timeout instead"
         
     | 
| 
       20 
     | 
    
         
            -
                   
     | 
| 
      
 20 
     | 
    
         
            +
                  with(timeout: args)
         
     | 
| 
       21 
21 
     | 
    
         
             
                end
         
     | 
| 
       22 
22 
     | 
    
         | 
| 
       23 
23 
     | 
    
         
             
                def headers(headers)
         
     | 
| 
       24 
24 
     | 
    
         
             
                  warn ":#{__method__} is deprecated, use :with_headers instead"
         
     | 
| 
       25 
     | 
    
         
            -
                   
     | 
| 
      
 25 
     | 
    
         
            +
                  with(headers: headers)
         
     | 
| 
       26 
26 
     | 
    
         
             
                end
         
     | 
| 
       27 
27 
     | 
    
         
             
                # :nocov:
         
     | 
| 
       28 
28 
     | 
    
         | 
    
        data/lib/httpx/connection.rb
    CHANGED
    
    | 
         @@ -71,6 +71,8 @@ module HTTPX 
     | 
|
| 
       71 
71 
     | 
    
         
             
                  @inflight = 0
         
     | 
| 
       72 
72 
     | 
    
         
             
                  @keep_alive_timeout = options.timeout.keep_alive_timeout
         
     | 
| 
       73 
73 
     | 
    
         
             
                  @keep_alive_timer = nil
         
     | 
| 
      
 74 
     | 
    
         
            +
             
     | 
| 
      
 75 
     | 
    
         
            +
                  self.addresses = options.addresses if options.addresses
         
     | 
| 
       74 
76 
     | 
    
         
             
                end
         
     | 
| 
       75 
77 
     | 
    
         | 
| 
       76 
78 
     | 
    
         
             
                # this is a semi-private method, to be used by the resolver
         
     | 
| 
         @@ -105,6 +107,8 @@ module HTTPX 
     | 
|
| 
       105 
107 
     | 
    
         | 
| 
       106 
108 
     | 
    
         
             
                  return false if exhausted?
         
     | 
| 
       107 
109 
     | 
    
         | 
| 
      
 110 
     | 
    
         
            +
                  return false unless connection.addresses
         
     | 
| 
      
 111 
     | 
    
         
            +
             
     | 
| 
       108 
112 
     | 
    
         
             
                  !(@io.addresses & connection.addresses).empty? && @options == connection.options
         
     | 
| 
       109 
113 
     | 
    
         
             
                end
         
     | 
| 
       110 
114 
     | 
    
         | 
| 
         @@ -170,7 +174,7 @@ module HTTPX 
     | 
|
| 
       170 
174 
     | 
    
         
             
                  end
         
     | 
| 
       171 
175 
     | 
    
         | 
| 
       172 
176 
     | 
    
         
             
                  # if the write buffer is full, we drain it
         
     | 
| 
       173 
     | 
    
         
            -
                  return :w  
     | 
| 
      
 177 
     | 
    
         
            +
                  return :w unless @write_buffer.empty?
         
     | 
| 
       174 
178 
     | 
    
         | 
| 
       175 
179 
     | 
    
         
             
                  return @parser.interests if @parser
         
     | 
| 
       176 
180 
     | 
    
         | 
| 
         @@ -251,11 +255,18 @@ module HTTPX 
     | 
|
| 
       251 
255 
     | 
    
         | 
| 
       252 
256 
     | 
    
         
             
                def consume
         
     | 
| 
       253 
257 
     | 
    
         
             
                  catch(:called) do
         
     | 
| 
      
 258 
     | 
    
         
            +
                    epiped = false
         
     | 
| 
       254 
259 
     | 
    
         
             
                    loop do
         
     | 
| 
       255 
260 
     | 
    
         
             
                      parser.consume
         
     | 
| 
       256 
261 
     | 
    
         | 
| 
       257 
     | 
    
         
            -
                      # we exit if there's no more  
     | 
| 
       258 
     | 
    
         
            -
                       
     | 
| 
      
 262 
     | 
    
         
            +
                      # we exit if there's no more requests to process
         
     | 
| 
      
 263 
     | 
    
         
            +
                      #
         
     | 
| 
      
 264 
     | 
    
         
            +
                      # this condition takes into account:
         
     | 
| 
      
 265 
     | 
    
         
            +
                      #
         
     | 
| 
      
 266 
     | 
    
         
            +
                      # * the number of inflight requests
         
     | 
| 
      
 267 
     | 
    
         
            +
                      # * the number of pending requests
         
     | 
| 
      
 268 
     | 
    
         
            +
                      # * whether the write buffer has bytes (i.e. for close handshake)
         
     | 
| 
      
 269 
     | 
    
         
            +
                      if @pending.size.zero? && @inflight.zero? && @write_buffer.empty?
         
     | 
| 
       259 
270 
     | 
    
         
             
                        log(level: 3) { "NO MORE REQUESTS..." }
         
     | 
| 
       260 
271 
     | 
    
         
             
                        return
         
     | 
| 
       261 
272 
     | 
    
         
             
                      end
         
     | 
| 
         @@ -265,9 +276,17 @@ module HTTPX 
     | 
|
| 
       265 
276 
     | 
    
         
             
                      read_drained = false
         
     | 
| 
       266 
277 
     | 
    
         
             
                      write_drained = nil
         
     | 
| 
       267 
278 
     | 
    
         | 
| 
       268 
     | 
    
         
            -
                      # 
     | 
| 
      
 279 
     | 
    
         
            +
                      #
         
     | 
| 
      
 280 
     | 
    
         
            +
                      # tight read loop.
         
     | 
| 
      
 281 
     | 
    
         
            +
                      #
         
     | 
| 
      
 282 
     | 
    
         
            +
                      # read as much of the socket as possible.
         
     | 
| 
      
 283 
     | 
    
         
            +
                      #
         
     | 
| 
      
 284 
     | 
    
         
            +
                      # this tight loop reads all the data it can from the socket and pipes it to
         
     | 
| 
      
 285 
     | 
    
         
            +
                      # its parser.
         
     | 
| 
      
 286 
     | 
    
         
            +
                      #
         
     | 
| 
       269 
287 
     | 
    
         
             
                      loop do
         
     | 
| 
       270 
288 
     | 
    
         
             
                        siz = @io.read(@window_size, @read_buffer)
         
     | 
| 
      
 289 
     | 
    
         
            +
                        log(level: 3, color: :cyan) { "IO READ: #{siz} bytes..." }
         
     | 
| 
       271 
290 
     | 
    
         
             
                        unless siz
         
     | 
| 
       272 
291 
     | 
    
         
             
                          ex = EOFError.new("descriptor closed")
         
     | 
| 
       273 
292 
     | 
    
         
             
                          ex.set_backtrace(caller)
         
     | 
| 
         @@ -275,27 +294,53 @@ module HTTPX 
     | 
|
| 
       275 
294 
     | 
    
         
             
                          return
         
     | 
| 
       276 
295 
     | 
    
         
             
                        end
         
     | 
| 
       277 
296 
     | 
    
         | 
| 
      
 297 
     | 
    
         
            +
                        # socket has been drained. mark and exit the read loop.
         
     | 
| 
       278 
298 
     | 
    
         
             
                        if siz.zero?
         
     | 
| 
       279 
299 
     | 
    
         
             
                          read_drained = @read_buffer.empty?
         
     | 
| 
      
 300 
     | 
    
         
            +
                          epiped = false
         
     | 
| 
       280 
301 
     | 
    
         
             
                          break
         
     | 
| 
       281 
302 
     | 
    
         
             
                        end
         
     | 
| 
       282 
303 
     | 
    
         | 
| 
       283 
304 
     | 
    
         
             
                        parser << @read_buffer.to_s
         
     | 
| 
       284 
305 
     | 
    
         | 
| 
      
 306 
     | 
    
         
            +
                        # continue reading if possible.
         
     | 
| 
      
 307 
     | 
    
         
            +
                        break if interests == :w && !epiped
         
     | 
| 
      
 308 
     | 
    
         
            +
             
     | 
| 
      
 309 
     | 
    
         
            +
                        # exit the read loop if connection is preparing to be closed
         
     | 
| 
       285 
310 
     | 
    
         
             
                        break if @state == :closing || @state == :closed
         
     | 
| 
       286 
311 
     | 
    
         | 
| 
       287 
     | 
    
         
            -
                        #  
     | 
| 
       288 
     | 
    
         
            -
             
     | 
| 
      
 312 
     | 
    
         
            +
                        # exit #consume altogether if all outstanding requests have been dealt with
         
     | 
| 
      
 313 
     | 
    
         
            +
                        return if @pending.size.zero? && @inflight.zero?
         
     | 
| 
      
 314 
     | 
    
         
            +
                      end unless (interests == :w || @state == :closing) && !epiped
         
     | 
| 
       289 
315 
     | 
    
         | 
| 
       290 
     | 
    
         
            -
                      # 
     | 
| 
      
 316 
     | 
    
         
            +
                      #
         
     | 
| 
      
 317 
     | 
    
         
            +
                      # tight write loop.
         
     | 
| 
      
 318 
     | 
    
         
            +
                      #
         
     | 
| 
      
 319 
     | 
    
         
            +
                      # flush as many bytes as the sockets allow.
         
     | 
| 
      
 320 
     | 
    
         
            +
                      #
         
     | 
| 
       291 
321 
     | 
    
         
             
                      loop do
         
     | 
| 
      
 322 
     | 
    
         
            +
                        # buffer has been drainned, mark and exit the write loop.
         
     | 
| 
       292 
323 
     | 
    
         
             
                        if @write_buffer.empty?
         
     | 
| 
       293 
324 
     | 
    
         
             
                          # we only mark as drained on the first loop
         
     | 
| 
       294 
325 
     | 
    
         
             
                          write_drained = write_drained.nil? && @inflight.positive?
         
     | 
| 
      
 326 
     | 
    
         
            +
             
     | 
| 
       295 
327 
     | 
    
         
             
                          break
         
     | 
| 
       296 
328 
     | 
    
         
             
                        end
         
     | 
| 
       297 
329 
     | 
    
         | 
| 
       298 
     | 
    
         
            -
                         
     | 
| 
      
 330 
     | 
    
         
            +
                        begin
         
     | 
| 
      
 331 
     | 
    
         
            +
                          siz = @io.write(@write_buffer)
         
     | 
| 
      
 332 
     | 
    
         
            +
                        rescue Errno::EPIPE
         
     | 
| 
      
 333 
     | 
    
         
            +
                          # this can happen if we still have bytes in the buffer to send to the server, but
         
     | 
| 
      
 334 
     | 
    
         
            +
                          # the server wants to respond immediately with some message, or an error. An example is
         
     | 
| 
      
 335 
     | 
    
         
            +
                          # when one's uploading a big file to an unintended endpoint, and the server stops the
         
     | 
| 
      
 336 
     | 
    
         
            +
                          # consumption, and responds immediately with an authorization of even method not allowed error.
         
     | 
| 
      
 337 
     | 
    
         
            +
                          # at this point, we have to let the connection switch to read-mode.
         
     | 
| 
      
 338 
     | 
    
         
            +
                          log(level: 2) { "pipe broken, could not flush buffer..." }
         
     | 
| 
      
 339 
     | 
    
         
            +
                          epiped = true
         
     | 
| 
      
 340 
     | 
    
         
            +
                          read_drained = false
         
     | 
| 
      
 341 
     | 
    
         
            +
                          break
         
     | 
| 
      
 342 
     | 
    
         
            +
                        end
         
     | 
| 
      
 343 
     | 
    
         
            +
                        log(level: 3, color: :cyan) { "IO WRITE: #{siz} bytes..." }
         
     | 
| 
       299 
344 
     | 
    
         
             
                        unless siz
         
     | 
| 
       300 
345 
     | 
    
         
             
                          ex = EOFError.new("descriptor closed")
         
     | 
| 
       301 
346 
     | 
    
         
             
                          ex.set_backtrace(caller)
         
     | 
| 
         @@ -303,21 +348,28 @@ module HTTPX 
     | 
|
| 
       303 
348 
     | 
    
         
             
                          return
         
     | 
| 
       304 
349 
     | 
    
         
             
                        end
         
     | 
| 
       305 
350 
     | 
    
         | 
| 
      
 351 
     | 
    
         
            +
                        # socket closed for writing. mark and exit the write loop.
         
     | 
| 
       306 
352 
     | 
    
         
             
                        if siz.zero?
         
     | 
| 
       307 
353 
     | 
    
         
             
                          write_drained = !@write_buffer.empty?
         
     | 
| 
       308 
354 
     | 
    
         
             
                          break
         
     | 
| 
       309 
355 
     | 
    
         
             
                        end
         
     | 
| 
       310 
356 
     | 
    
         | 
| 
       311 
     | 
    
         
            -
                         
     | 
| 
      
 357 
     | 
    
         
            +
                        # exit write loop if marked to consume from peer, or is closing.
         
     | 
| 
      
 358 
     | 
    
         
            +
                        break if interests == :r || @state == :closing || @state == :closed
         
     | 
| 
       312 
359 
     | 
    
         | 
| 
       313 
360 
     | 
    
         
             
                        write_drained = false
         
     | 
| 
       314 
     | 
    
         
            -
                      end
         
     | 
| 
      
 361 
     | 
    
         
            +
                      end unless interests == :r
         
     | 
| 
       315 
362 
     | 
    
         | 
| 
       316 
363 
     | 
    
         
             
                      # return if socket is drained
         
     | 
| 
       317 
     | 
    
         
            -
                       
     | 
| 
       318 
     | 
    
         
            -
             
     | 
| 
       319 
     | 
    
         
            -
             
     | 
| 
       320 
     | 
    
         
            -
                       
     | 
| 
      
 364 
     | 
    
         
            +
                      next unless (interests != :r || read_drained) &&
         
     | 
| 
      
 365 
     | 
    
         
            +
                                  (interests != :w || write_drained)
         
     | 
| 
      
 366 
     | 
    
         
            +
             
     | 
| 
      
 367 
     | 
    
         
            +
                      # gotta go back to the event loop. It happens when:
         
     | 
| 
      
 368 
     | 
    
         
            +
                      #
         
     | 
| 
      
 369 
     | 
    
         
            +
                      # * the socket is drained of bytes or it's not the interest of the conn to read;
         
     | 
| 
      
 370 
     | 
    
         
            +
                      # * theres nothing more to write, or it's not in the interest of the conn to write;
         
     | 
| 
      
 371 
     | 
    
         
            +
                      log(level: 3) { "(#{interests}): WAITING FOR EVENTS..." }
         
     | 
| 
      
 372 
     | 
    
         
            +
                      return
         
     | 
| 
       321 
373 
     | 
    
         
             
                    end
         
     | 
| 
       322 
374 
     | 
    
         
             
                  end
         
     | 
| 
       323 
375 
     | 
    
         
             
                end
         
     | 
| 
         @@ -424,33 +476,33 @@ module HTTPX 
     | 
|
| 
       424 
476 
     | 
    
         
             
                      remove_instance_variable(:@total_timeout)
         
     | 
| 
       425 
477 
     | 
    
         
             
                    end
         
     | 
| 
       426 
478 
     | 
    
         | 
| 
       427 
     | 
    
         
            -
                     
     | 
| 
       428 
     | 
    
         
            -
                    @read_buffer.clear
         
     | 
| 
       429 
     | 
    
         
            -
                    if @keep_alive_timer
         
     | 
| 
       430 
     | 
    
         
            -
                      @keep_alive_timer.cancel
         
     | 
| 
       431 
     | 
    
         
            -
                      remove_instance_variable(:@keep_alive_timer)
         
     | 
| 
       432 
     | 
    
         
            -
                    end
         
     | 
| 
       433 
     | 
    
         
            -
             
     | 
| 
       434 
     | 
    
         
            -
                    remove_instance_variable(:@timeout) if defined?(@timeout)
         
     | 
| 
      
 479 
     | 
    
         
            +
                    purge_after_closed
         
     | 
| 
       435 
480 
     | 
    
         
             
                  when :already_open
         
     | 
| 
       436 
481 
     | 
    
         
             
                    nextstate = :open
         
     | 
| 
       437 
482 
     | 
    
         
             
                    send_pending
         
     | 
| 
       438 
483 
     | 
    
         
             
                  end
         
     | 
| 
       439 
484 
     | 
    
         
             
                  @state = nextstate
         
     | 
| 
       440 
     | 
    
         
            -
                rescue Errno::EHOSTUNREACH
         
     | 
| 
       441 
     | 
    
         
            -
                  # at this point, all addresses from the IO object have failed
         
     | 
| 
       442 
     | 
    
         
            -
                  reset
         
     | 
| 
       443 
     | 
    
         
            -
                  emit(:unreachable)
         
     | 
| 
       444 
     | 
    
         
            -
                  throw(:jump_tick)
         
     | 
| 
       445 
485 
     | 
    
         
             
                rescue Errno::ECONNREFUSED,
         
     | 
| 
       446 
486 
     | 
    
         
             
                       Errno::EADDRNOTAVAIL,
         
     | 
| 
       447 
     | 
    
         
            -
                        
     | 
| 
      
 487 
     | 
    
         
            +
                       Errno::EHOSTUNREACH,
         
     | 
| 
      
 488 
     | 
    
         
            +
                       TLSError => e
         
     | 
| 
       448 
489 
     | 
    
         
             
                  # connect errors, exit gracefully
         
     | 
| 
       449 
490 
     | 
    
         
             
                  handle_error(e)
         
     | 
| 
       450 
491 
     | 
    
         
             
                  @state = :closed
         
     | 
| 
       451 
492 
     | 
    
         
             
                  emit(:close)
         
     | 
| 
       452 
493 
     | 
    
         
             
                end
         
     | 
| 
       453 
494 
     | 
    
         | 
| 
      
 495 
     | 
    
         
            +
                def purge_after_closed
         
     | 
| 
      
 496 
     | 
    
         
            +
                  @io.close if @io
         
     | 
| 
      
 497 
     | 
    
         
            +
                  @read_buffer.clear
         
     | 
| 
      
 498 
     | 
    
         
            +
                  if @keep_alive_timer
         
     | 
| 
      
 499 
     | 
    
         
            +
                    @keep_alive_timer.cancel
         
     | 
| 
      
 500 
     | 
    
         
            +
                    remove_instance_variable(:@keep_alive_timer)
         
     | 
| 
      
 501 
     | 
    
         
            +
                  end
         
     | 
| 
      
 502 
     | 
    
         
            +
             
     | 
| 
      
 503 
     | 
    
         
            +
                  remove_instance_variable(:@timeout) if defined?(@timeout)
         
     | 
| 
      
 504 
     | 
    
         
            +
                end
         
     | 
| 
      
 505 
     | 
    
         
            +
             
     | 
| 
       454 
506 
     | 
    
         
             
                def handle_response
         
     | 
| 
       455 
507 
     | 
    
         
             
                  @inflight -= 1
         
     | 
| 
       456 
508 
     | 
    
         
             
                  return unless @inflight.zero?
         
     | 
| 
         @@ -10,7 +10,7 @@ module HTTPX 
     | 
|
| 
       10 
10 
     | 
    
         
             
                MAX_REQUESTS = 100
         
     | 
| 
       11 
11 
     | 
    
         
             
                CRLF = "\r\n"
         
     | 
| 
       12 
12 
     | 
    
         | 
| 
       13 
     | 
    
         
            -
                attr_reader :pending
         
     | 
| 
      
 13 
     | 
    
         
            +
                attr_reader :pending, :requests
         
     | 
| 
       14 
14 
     | 
    
         | 
| 
       15 
15 
     | 
    
         
             
                def initialize(buffer, options)
         
     | 
| 
       16 
16 
     | 
    
         
             
                  @options = Options.new(options)
         
     | 
| 
         @@ -74,9 +74,10 @@ module HTTPX 
     | 
|
| 
       74 
74 
     | 
    
         
             
                end
         
     | 
| 
       75 
75 
     | 
    
         | 
| 
       76 
76 
     | 
    
         
             
                def consume
         
     | 
| 
       77 
     | 
    
         
            -
                  requests_limit = [@ 
     | 
| 
      
 77 
     | 
    
         
            +
                  requests_limit = [@max_requests, @requests.size].min
         
     | 
| 
      
 78 
     | 
    
         
            +
                  concurrent_requests_limit = [@max_concurrent_requests, requests_limit].min
         
     | 
| 
       78 
79 
     | 
    
         
             
                  @requests.each_with_index do |request, idx|
         
     | 
| 
       79 
     | 
    
         
            -
                    break if idx >=  
     | 
| 
      
 80 
     | 
    
         
            +
                    break if idx >= concurrent_requests_limit
         
     | 
| 
       80 
81 
     | 
    
         
             
                    next if request.state == :done
         
     | 
| 
       81 
82 
     | 
    
         | 
| 
       82 
83 
     | 
    
         
             
                    request.headers["connection"] ||= request.options.persistent || idx < requests_limit - 1 ? "keep-alive" : "close"
         
     | 
| 
         @@ -115,7 +116,7 @@ module HTTPX 
     | 
|
| 
       115 
116 
     | 
    
         
             
                  response = @request.response
         
     | 
| 
       116 
117 
     | 
    
         
             
                  log(level: 2) { "trailer headers received" }
         
     | 
| 
       117 
118 
     | 
    
         | 
| 
       118 
     | 
    
         
            -
                  log(color: :yellow) { h.each.map { |f, v| "-> HEADER: #{f}: #{v}" }.join("\n") }
         
     | 
| 
      
 119 
     | 
    
         
            +
                  log(color: :yellow) { h.each.map { |f, v| "-> HEADER: #{f}: #{v.join(", ")}" }.join("\n") }
         
     | 
| 
       119 
120 
     | 
    
         
             
                  response.merge_headers(h)
         
     | 
| 
       120 
121 
     | 
    
         
             
                end
         
     | 
| 
       121 
122 
     | 
    
         | 
| 
         @@ -161,6 +162,16 @@ module HTTPX 
     | 
|
| 
       161 
162 
     | 
    
         
             
                end
         
     | 
| 
       162 
163 
     | 
    
         | 
| 
       163 
164 
     | 
    
         
             
                def handle_error(ex)
         
     | 
| 
      
 165 
     | 
    
         
            +
                  if (ex.is_a?(EOFError) || ex.is_a?(TimeoutError)) && @request && @request.response &&
         
     | 
| 
      
 166 
     | 
    
         
            +
                     !@request.response.headers.key?("content-length") &&
         
     | 
| 
      
 167 
     | 
    
         
            +
                     !@request.response.headers.key?("transfer-encoding")
         
     | 
| 
      
 168 
     | 
    
         
            +
                    # if the response does not contain a content-length header, the server closing the
         
     | 
| 
      
 169 
     | 
    
         
            +
                    # connnection is the indicator of response consumed.
         
     | 
| 
      
 170 
     | 
    
         
            +
                    # https://greenbytes.de/tech/webdav/rfc2616.html#rfc.section.4.4
         
     | 
| 
      
 171 
     | 
    
         
            +
                    catch(:called) { on_complete }
         
     | 
| 
      
 172 
     | 
    
         
            +
                    return
         
     | 
| 
      
 173 
     | 
    
         
            +
                  end
         
     | 
| 
      
 174 
     | 
    
         
            +
             
     | 
| 
       164 
175 
     | 
    
         
             
                  if @pipelining
         
     | 
| 
       165 
176 
     | 
    
         
             
                    disable
         
     | 
| 
       166 
177 
     | 
    
         
             
                  else
         
     | 
| 
         @@ -224,6 +235,8 @@ module HTTPX 
     | 
|
| 
       224 
235 
     | 
    
         | 
| 
       225 
236 
     | 
    
         
             
                def disable_pipelining
         
     | 
| 
       226 
237 
     | 
    
         
             
                  return if @requests.empty?
         
     | 
| 
      
 238 
     | 
    
         
            +
                  # do not disable pipelining if already set to 1 request at a time
         
     | 
| 
      
 239 
     | 
    
         
            +
                  return if @max_concurrent_requests == 1
         
     | 
| 
       227 
240 
     | 
    
         | 
| 
       228 
241 
     | 
    
         
             
                  @requests.each do |r|
         
     | 
| 
       229 
242 
     | 
    
         
             
                    r.transition(:idle)
         
     | 
| 
         @@ -240,7 +253,7 @@ module HTTPX 
     | 
|
| 
       240 
253 
     | 
    
         
             
                  @pipelining = false
         
     | 
| 
       241 
254 
     | 
    
         
             
                end
         
     | 
| 
       242 
255 
     | 
    
         | 
| 
       243 
     | 
    
         
            -
                def  
     | 
| 
      
 256 
     | 
    
         
            +
                def set_protocol_headers(request)
         
     | 
| 
       244 
257 
     | 
    
         
             
                  request.headers["host"] ||= request.authority
         
     | 
| 
       245 
258 
     | 
    
         
             
                  request.headers["connection"] ||= request.options.persistent ? "keep-alive" : "close"
         
     | 
| 
       246 
259 
     | 
    
         
             
                  if !request.headers.key?("content-length") &&
         
     | 
| 
         @@ -254,7 +267,6 @@ module HTTPX 
     | 
|
| 
       254 
267 
     | 
    
         
             
                end
         
     | 
| 
       255 
268 
     | 
    
         | 
| 
       256 
269 
     | 
    
         
             
                def handle(request)
         
     | 
| 
       257 
     | 
    
         
            -
                  set_request_headers(request)
         
     | 
| 
       258 
270 
     | 
    
         
             
                  catch(:buffer_full) do
         
     | 
| 
       259 
271 
     | 
    
         
             
                    request.transition(:headers)
         
     | 
| 
       260 
272 
     | 
    
         
             
                    join_headers(request) if request.state == :headers
         
     | 
| 
         @@ -270,6 +282,7 @@ module HTTPX 
     | 
|
| 
       270 
282 
     | 
    
         
             
                  log(color: :yellow) { "<- HEADLINE: #{buffer.chomp.inspect}" }
         
     | 
| 
       271 
283 
     | 
    
         
             
                  @buffer << buffer
         
     | 
| 
       272 
284 
     | 
    
         
             
                  buffer.clear
         
     | 
| 
      
 285 
     | 
    
         
            +
                  set_protocol_headers(request)
         
     | 
| 
       273 
286 
     | 
    
         
             
                  request.headers.each do |field, value|
         
     | 
| 
       274 
287 
     | 
    
         
             
                    buffer << "#{capitalized(field)}: #{value}" << CRLF
         
     | 
| 
       275 
288 
     | 
    
         
             
                    log(color: :yellow) { "<- HEADER: #{buffer.chomp}" }
         
     |