http 0.8.3 → 0.8.4
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/.rubocop.yml +2 -2
- data/CHANGES.md +10 -0
- data/README.md +36 -39
- data/lib/http/cache/headers.rb +8 -8
- data/lib/http/chainable.rb +17 -4
- data/lib/http/client.rb +5 -4
- data/lib/http/connection.rb +35 -5
- data/lib/http/options.rb +4 -4
- data/lib/http/request.rb +27 -3
- data/lib/http/request/caching.rb +5 -5
- data/lib/http/request/writer.rb +7 -2
- data/lib/http/response/caching.rb +3 -3
- data/lib/http/version.rb +1 -1
- data/spec/lib/http/cache_spec.rb +6 -6
- data/spec/lib/http/client_spec.rb +13 -13
- data/spec/lib/http/headers_spec.rb +16 -16
- data/spec/lib/http/redirector_spec.rb +24 -24
- data/spec/lib/http/response_spec.rb +2 -2
- data/spec/lib/http_spec.rb +38 -4
- data/spec/support/http_handling_shared.rb +2 -2
- metadata +40 -4
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA1:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 9b829e0c5ca1c70ca3f55b33080088ab248c52fc
         | 
| 4 | 
            +
              data.tar.gz: 248df6f0b8df5a75bfa872d5f24a263568f63e5a
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: b4e37035a7a6b692d103a24e6f75a30509a5d2a92aa1b4c21a2c0a393886c648c5b28df3e36779aa274430243dbde29af69ea4eaff25c5ff4aecd3c880bc0068
         | 
| 7 | 
            +
              data.tar.gz: 76fae19bd0b8f31e9825a3514e21f83f006bc205c2e118ec4fec8ebd644900d3bbbf2f7119dc800ac4782b4ba9665be64a588083585d9bf12bae36e97188c69b
         | 
    
        data/.rubocop.yml
    CHANGED
    
    | @@ -3,7 +3,7 @@ Metrics/BlockNesting: | |
| 3 3 |  | 
| 4 4 | 
             
            Metrics/ClassLength:
         | 
| 5 5 | 
             
              CountComments: false
         | 
| 6 | 
            -
              Max:  | 
| 6 | 
            +
              Max: 120
         | 
| 7 7 |  | 
| 8 8 | 
             
            Metrics/PerceivedComplexity:
         | 
| 9 9 | 
             
              Max: 8
         | 
| @@ -37,7 +37,7 @@ Style/Documentation: | |
| 37 37 | 
             
              Enabled: false
         | 
| 38 38 |  | 
| 39 39 | 
             
            Style/DotPosition:
         | 
| 40 | 
            -
              EnforcedStyle:  | 
| 40 | 
            +
              EnforcedStyle: trailing
         | 
| 41 41 |  | 
| 42 42 | 
             
            Style/DoubleNegation:
         | 
| 43 43 | 
             
              Enabled: false
         | 
    
        data/CHANGES.md
    CHANGED
    
    | @@ -1,3 +1,13 @@ | |
| 1 | 
            +
            ## master (unreleased)
         | 
| 2 | 
            +
             | 
| 3 | 
            +
             | 
| 4 | 
            +
            ## 0.8.4 (2015-04-23)
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            * Deprecate `#default_headers` and `#default_headers=`. (@ixti)
         | 
| 7 | 
            +
            * Deprecate chainable methods with `with_` prefix. See #207. (@ixti)
         | 
| 8 | 
            +
            * Add support of HTTPS connections through proxy. See #186. (@Connorhd)
         | 
| 9 | 
            +
             | 
| 10 | 
            +
             | 
| 1 11 | 
             
            ## 0.8.3 (2015-04-07)
         | 
| 2 12 |  | 
| 3 13 | 
             
            * Fix request headline. See #206. (@ixti)
         | 
    
        data/README.md
    CHANGED
    
    | @@ -40,7 +40,7 @@ Installation | |
| 40 40 |  | 
| 41 41 | 
             
            Add this line to your application's Gemfile:
         | 
| 42 42 |  | 
| 43 | 
            -
                gem  | 
| 43 | 
            +
                gem "http"
         | 
| 44 44 |  | 
| 45 45 | 
             
            And then execute:
         | 
| 46 46 |  | 
| @@ -52,7 +52,7 @@ Or install it yourself as: | |
| 52 52 |  | 
| 53 53 | 
             
            Inside of your Ruby program do:
         | 
| 54 54 |  | 
| 55 | 
            -
                require  | 
| 55 | 
            +
                require "http"
         | 
| 56 56 |  | 
| 57 57 | 
             
            ...to pull it in as a dependency.
         | 
| 58 58 |  | 
| @@ -70,7 +70,7 @@ Here's some simple examples to get you started: | |
| 70 70 | 
             
            ### GET requests
         | 
| 71 71 |  | 
| 72 72 | 
             
            ```ruby
         | 
| 73 | 
            -
            >> HTTP.get( | 
| 73 | 
            +
            >> HTTP.get("https://github.com").to_s
         | 
| 74 74 | 
             
            => "<html><head><meta http-equiv=\"content-type\" content=..."
         | 
| 75 75 | 
             
            ```
         | 
| 76 76 |  | 
| @@ -78,7 +78,7 @@ That's all it takes! To obtain an `HTTP::Response` object instead of the respons | |
| 78 78 | 
             
            body, all we have to do is omit the #to_s on the end:
         | 
| 79 79 |  | 
| 80 80 | 
             
            ```ruby
         | 
| 81 | 
            -
            >> HTTP.get( | 
| 81 | 
            +
            >> HTTP.get("https://github.com")
         | 
| 82 82 | 
             
            => #<HTTP/1.0 200 OK @headers={"Content-Type"=>"text/html; charset=UTF-8", "Date"=>"Fri, ...>
         | 
| 83 83 | 
             
             => #<HTTP::Response/1.1 200 OK @headers={"Content-Type"=>"text/html; ...>
         | 
| 84 84 | 
             
            ```
         | 
| @@ -86,51 +86,51 @@ body, all we have to do is omit the #to_s on the end: | |
| 86 86 | 
             
            We can also obtain an `HTTP::Response::Body` object for this response:
         | 
| 87 87 |  | 
| 88 88 | 
             
            ```ruby
         | 
| 89 | 
            -
            >> HTTP.get( | 
| 89 | 
            +
            >> HTTP.get("https://github.com").body
         | 
| 90 90 | 
             
             => #<HTTP::Response::Body:814d7aac @streaming=false>
         | 
| 91 91 | 
             
            ```
         | 
| 92 92 |  | 
| 93 93 | 
             
            The response body can be streamed with `HTTP::Response::Body#readpartial`:
         | 
| 94 94 |  | 
| 95 95 | 
             
            ```ruby
         | 
| 96 | 
            -
            >> HTTP.get( | 
| 96 | 
            +
            >> HTTP.get("https://github.com").body.readpartial
         | 
| 97 97 | 
             
             => "<!doctype html><html "
         | 
| 98 98 | 
             
            ```
         | 
| 99 99 |  | 
| 100 100 | 
             
            In practice you'll want to bind the HTTP::Response::Body to a local variable (e.g.
         | 
| 101 | 
            -
            "body") and call readpartial on it repeatedly until it returns nil | 
| 101 | 
            +
            "body") and call readpartial on it repeatedly until it returns `nil`.
         | 
| 102 102 |  | 
| 103 103 | 
             
            ### POST requests
         | 
| 104 104 |  | 
| 105 105 | 
             
            Making POST requests is simple too. Want to POST a form?
         | 
| 106 106 |  | 
| 107 107 | 
             
            ```ruby
         | 
| 108 | 
            -
            HTTP.post( | 
| 108 | 
            +
            HTTP.post("http://example.com/resource", :form => {:foo => "42"})
         | 
| 109 109 | 
             
            ```
         | 
| 110 110 | 
             
            Making GET requests with query string parameters is as simple.
         | 
| 111 111 |  | 
| 112 112 | 
             
            ```ruby
         | 
| 113 | 
            -
            HTTP.get( | 
| 113 | 
            +
            HTTP.get("http://example.com/resource", :params => {:foo => "bar"})
         | 
| 114 114 | 
             
            ```
         | 
| 115 115 |  | 
| 116 116 | 
             
            Want to POST with a specific body, JSON for instance?
         | 
| 117 117 |  | 
| 118 118 | 
             
            ```ruby
         | 
| 119 | 
            -
            HTTP.post( | 
| 119 | 
            +
            HTTP.post("http://example.com/resource", :json => { :foo => "42" })
         | 
| 120 120 | 
             
            ```
         | 
| 121 121 |  | 
| 122 122 | 
             
            Or just a plain body?
         | 
| 123 123 |  | 
| 124 124 | 
             
            ```ruby
         | 
| 125 | 
            -
            HTTP.post( | 
| 125 | 
            +
            HTTP.post("http://example.com/resource", :body => "foo=42&bar=baz")
         | 
| 126 126 | 
             
            ```
         | 
| 127 127 |  | 
| 128 128 | 
             
            Posting a file?
         | 
| 129 129 |  | 
| 130 130 | 
             
            ``` ruby
         | 
| 131 | 
            -
            HTTP.post( | 
| 132 | 
            -
              :username =>  | 
| 133 | 
            -
              :avatar   => HTTP::FormData::File.new( | 
| 131 | 
            +
            HTTP.post("http://examplc.com/resource", :form => {
         | 
| 132 | 
            +
              :username => "ixti",
         | 
| 133 | 
            +
              :avatar   => HTTP::FormData::File.new("/home/ixit/avatar.png")
         | 
| 134 134 | 
             
            })
         | 
| 135 135 | 
             
            ```
         | 
| 136 136 |  | 
| @@ -142,15 +142,15 @@ Making request behind proxy is as simple as making them directly. Just specify | |
| 142 142 | 
             
            hostname (or IP address) of your proxy server and its port, and here you go:
         | 
| 143 143 |  | 
| 144 144 | 
             
            ```ruby
         | 
| 145 | 
            -
            HTTP.via( | 
| 146 | 
            -
              .get( | 
| 145 | 
            +
            HTTP.via("proxy-hostname.local", 8080)
         | 
| 146 | 
            +
              .get("http://example.com/resource")
         | 
| 147 147 | 
             
            ```
         | 
| 148 148 |  | 
| 149 149 | 
             
            Proxy needs authentication? No problem:
         | 
| 150 150 |  | 
| 151 151 | 
             
            ```ruby
         | 
| 152 | 
            -
            HTTP.via( | 
| 153 | 
            -
              .get( | 
| 152 | 
            +
            HTTP.via("proxy-hostname.local", 8080, "username", "password")
         | 
| 153 | 
            +
              .get("http://example.com/resource")
         | 
| 154 154 | 
             
            ```
         | 
| 155 155 |  | 
| 156 156 | 
             
            ### Adding Headers
         | 
| @@ -160,7 +160,7 @@ you want to get the latest commit of this library from GitHub in JSON format. | |
| 160 160 | 
             
            One way we could do this is by tacking a filename on the end of the URL:
         | 
| 161 161 |  | 
| 162 162 | 
             
            ```ruby
         | 
| 163 | 
            -
            HTTP.get( | 
| 163 | 
            +
            HTTP.get("https://github.com/httprb/http.rb/commit/HEAD.json")
         | 
| 164 164 | 
             
            ```
         | 
| 165 165 |  | 
| 166 166 | 
             
            The GitHub API happens to support this approach, but really this is a bit of a
         | 
| @@ -170,21 +170,18 @@ the full, raw power of HTTP, we can perform content negotiation the way HTTP | |
| 170 170 | 
             
            intends us to, by using the Accept header:
         | 
| 171 171 |  | 
| 172 172 | 
             
            ```ruby
         | 
| 173 | 
            -
            HTTP. | 
| 174 | 
            -
              get( | 
| 173 | 
            +
            HTTP.headers(:accept => "application/json")
         | 
| 174 | 
            +
              .get("https://github.com/httprb/http.rb/commit/HEAD")
         | 
| 175 175 | 
             
            ```
         | 
| 176 176 |  | 
| 177 177 | 
             
            This requests JSON from GitHub. GitHub is smart enough to understand our
         | 
| 178 | 
            -
            request and returns a response with Content-Type: application/json | 
| 178 | 
            +
            request and returns a response with `Content-Type: application/json`.
         | 
| 179 179 |  | 
| 180 | 
            -
            Shorter  | 
| 180 | 
            +
            Shorter alias exists for `HTTP.headers`:
         | 
| 181 181 |  | 
| 182 182 | 
             
            ```ruby
         | 
| 183 | 
            -
            HTTP | 
| 184 | 
            -
              get( | 
| 185 | 
            -
             | 
| 186 | 
            -
            HTTP[:accept => 'application/json'].
         | 
| 187 | 
            -
              get('https://github.com/httprb/http.rb/commit/HEAD')
         | 
| 183 | 
            +
            HTTP[:accept => "application/json"]
         | 
| 184 | 
            +
              .get("https://github.com/httprb/http.rb/commit/HEAD")
         | 
| 188 185 | 
             
            ```
         | 
| 189 186 |  | 
| 190 187 | 
             
            ### Authorization Header
         | 
| @@ -193,23 +190,23 @@ With [HTTP Basic Authentication](http://tools.ietf.org/html/rfc2617) using | |
| 193 190 | 
             
            a username and password:
         | 
| 194 191 |  | 
| 195 192 | 
             
            ```ruby
         | 
| 196 | 
            -
            HTTP.basic_auth(:user =>  | 
| 193 | 
            +
            HTTP.basic_auth(:user => "user", :pass => "pass")
         | 
| 197 194 | 
             
            # <HTTP::Headers {"Authorization"=>"Basic dXNlcjpwYXNz"}>
         | 
| 198 195 | 
             
            ```
         | 
| 199 196 |  | 
| 200 197 | 
             
            Or with plain as-is value:
         | 
| 201 198 |  | 
| 202 199 | 
             
            ```ruby
         | 
| 203 | 
            -
            HTTP.auth( | 
| 200 | 
            +
            HTTP.auth("Bearer VGhlIEhUVFAgR2VtLCBST0NLUw")
         | 
| 204 201 | 
             
            # <HTTP::Headers {"Authorization"=>"Bearer VGhlIEhUVFAgR2VtLCBST0NLUw"}>
         | 
| 205 202 | 
             
            ```
         | 
| 206 203 |  | 
| 207 204 | 
             
            And Chain all together!
         | 
| 208 205 |  | 
| 209 206 | 
             
            ```ruby
         | 
| 210 | 
            -
            HTTP.basic_auth(:user =>  | 
| 211 | 
            -
              . | 
| 212 | 
            -
              .get( | 
| 207 | 
            +
            HTTP.basic_auth(:user => "user", :pass => "pass")
         | 
| 208 | 
            +
              .headers("Cookie" => "9wq3w")
         | 
| 209 | 
            +
              .get("https://example.com")
         | 
| 213 210 | 
             
            ```
         | 
| 214 211 |  | 
| 215 212 | 
             
            ### Content Negotiation
         | 
| @@ -219,7 +216,7 @@ right? But usually it's not, and so we end up adding ".json" onto the ends of | |
| 219 216 | 
             
            our URLs because the existing mechanisms make it too hard. It should be easy:
         | 
| 220 217 |  | 
| 221 218 | 
             
            ```ruby
         | 
| 222 | 
            -
            HTTP.accept(:json).get( | 
| 219 | 
            +
            HTTP.accept(:json).get("https://github.com/httprb/http.rb/commit/HEAD")
         | 
| 223 220 | 
             
            ```
         | 
| 224 221 |  | 
| 225 222 | 
             
            This adds the appropriate Accept header for retrieving a JSON response for the
         | 
| @@ -232,8 +229,8 @@ Celluloid::IO actor. Here's a parallel HTTP fetcher combining http.rb with | |
| 232 229 | 
             
            Celluloid::IO:
         | 
| 233 230 |  | 
| 234 231 | 
             
            ```ruby
         | 
| 235 | 
            -
            require  | 
| 236 | 
            -
            require  | 
| 232 | 
            +
            require "celluloid/io"
         | 
| 233 | 
            +
            require "http"
         | 
| 237 234 |  | 
| 238 235 | 
             
            class HttpFetcher
         | 
| 239 236 | 
             
              include Celluloid::IO
         | 
| @@ -256,10 +253,10 @@ http.rb provides caching of HTTP request (per | |
| 256 253 | 
             
            so.
         | 
| 257 254 |  | 
| 258 255 | 
             
            ```ruby
         | 
| 259 | 
            -
            require  | 
| 256 | 
            +
            require "http"
         | 
| 260 257 |  | 
| 261 | 
            -
            http = HTTP. | 
| 262 | 
            -
             | 
| 258 | 
            +
            http = HTTP.cache(:metastore   => "file:/var/cache/my-app-http/meta",
         | 
| 259 | 
            +
                              :entitystore => "file:/var/cache/my-app-http/entity")
         | 
| 263 260 |  | 
| 264 261 | 
             
            http.get("http://example.com/")   # makes request
         | 
| 265 262 | 
             
            http.get("http://example.com/")   # skips making request and returns
         | 
    
        data/lib/http/cache/headers.rb
    CHANGED
    
    | @@ -69,9 +69,9 @@ module HTTP | |
| 69 69 | 
             
                  # ---
         | 
| 70 70 | 
             
                  # Some servers send a "Expire: -1" header which must be treated as expired
         | 
| 71 71 | 
             
                  def seconds_til_expires
         | 
| 72 | 
            -
                    get("Expires")
         | 
| 73 | 
            -
                       | 
| 74 | 
            -
                       | 
| 72 | 
            +
                    get("Expires").
         | 
| 73 | 
            +
                      map { |e| http_date_to_ttl(e) }.
         | 
| 74 | 
            +
                      max
         | 
| 75 75 | 
             
                  end
         | 
| 76 76 |  | 
| 77 77 | 
             
                  def http_date_to_ttl(t_str)
         | 
| @@ -89,11 +89,11 @@ module HTTP | |
| 89 89 |  | 
| 90 90 | 
             
                  # @return [Numeric] the value of the max-age component of cache control
         | 
| 91 91 | 
             
                  def explicit_max_age
         | 
| 92 | 
            -
                    get("Cache-Control")
         | 
| 93 | 
            -
                       | 
| 94 | 
            -
                      . | 
| 95 | 
            -
                       | 
| 96 | 
            -
                       | 
| 92 | 
            +
                    get("Cache-Control").
         | 
| 93 | 
            +
                      map { |v| (/max-age=(\d+)/i).match(v) }.
         | 
| 94 | 
            +
                      compact.
         | 
| 95 | 
            +
                      map { |m| m[1].to_i }.
         | 
| 96 | 
            +
                      max
         | 
| 97 97 | 
             
                  end
         | 
| 98 98 | 
             
                end
         | 
| 99 99 | 
             
              end
         | 
    
        data/lib/http/chainable.rb
    CHANGED
    
    | @@ -140,20 +140,31 @@ module HTTP | |
| 140 140 | 
             
                  branch default_options.with_follow opts
         | 
| 141 141 | 
             
                end
         | 
| 142 142 |  | 
| 143 | 
            -
                # @deprecated
         | 
| 143 | 
            +
                # @deprecated will be removed in 1.0.0
         | 
| 144 144 | 
             
                # @see #follow
         | 
| 145 145 | 
             
                alias_method :with_follow, :follow
         | 
| 146 146 |  | 
| 147 | 
            -
                def  | 
| 147 | 
            +
                def cache(cache)
         | 
| 148 148 | 
             
                  branch default_options.with_cache(cache)
         | 
| 149 149 | 
             
                end
         | 
| 150 150 |  | 
| 151 | 
            +
                # @deprecated will be removed in 1.0.0
         | 
| 152 | 
            +
                # @see #cache
         | 
| 153 | 
            +
                alias_method :with_cache, :cache
         | 
| 154 | 
            +
             | 
| 151 155 | 
             
                # Make a request with the given headers
         | 
| 152 156 | 
             
                # @param headers
         | 
| 153 | 
            -
                def  | 
| 157 | 
            +
                def headers(headers)
         | 
| 154 158 | 
             
                  branch default_options.with_headers(headers)
         | 
| 155 159 | 
             
                end
         | 
| 156 | 
            -
             | 
| 160 | 
            +
             | 
| 161 | 
            +
                # @deprecated will be removed in 1.0.0
         | 
| 162 | 
            +
                # @see #headers
         | 
| 163 | 
            +
                alias_method :with, :headers
         | 
| 164 | 
            +
             | 
| 165 | 
            +
                # @deprecated will be removed in 1.0.0
         | 
| 166 | 
            +
                # @see #headers
         | 
| 167 | 
            +
                alias_method :with_headers, :headers
         | 
| 157 168 |  | 
| 158 169 | 
             
                # Accept the given MIME type(s)
         | 
| 159 170 | 
             
                # @param type
         | 
| @@ -195,12 +206,14 @@ module HTTP | |
| 195 206 | 
             
                  @default_options = HTTP::Options.new(opts)
         | 
| 196 207 | 
             
                end
         | 
| 197 208 |  | 
| 209 | 
            +
                # @deprecated Will be removed in 1.0.0; Use `#default_options#headers`
         | 
| 198 210 | 
             
                # Get headers of HTTP options
         | 
| 199 211 | 
             
                def default_headers
         | 
| 200 212 | 
             
                  default_options.headers
         | 
| 201 213 | 
             
                end
         | 
| 202 214 |  | 
| 203 215 | 
             
                # Set headers of HTTP options
         | 
| 216 | 
            +
                # @deprecated Will be removed in 1.0.0; Use `#headers`
         | 
| 204 217 | 
             
                # @param headers
         | 
| 205 218 | 
             
                def default_headers=(headers)
         | 
| 206 219 | 
             
                  @default_options = default_options.dup do |opts|
         | 
    
        data/lib/http/client.rb
    CHANGED
    
    | @@ -21,8 +21,6 @@ module HTTP | |
| 21 21 |  | 
| 22 22 | 
             
                HTTP_OR_HTTPS_RE   = %r{^https?://}i
         | 
| 23 23 |  | 
| 24 | 
            -
                attr_reader :default_options
         | 
| 25 | 
            -
             | 
| 26 24 | 
             
                def initialize(default_options = {})
         | 
| 27 25 | 
             
                  @default_options = HTTP::Options.new(default_options)
         | 
| 28 26 | 
             
                  @connection = nil
         | 
| @@ -72,8 +70,11 @@ module HTTP | |
| 72 70 | 
             
                  @state = :dirty
         | 
| 73 71 |  | 
| 74 72 | 
             
                  @connection ||= HTTP::Connection.new(req, options)
         | 
| 75 | 
            -
             | 
| 76 | 
            -
                  @connection. | 
| 73 | 
            +
             | 
| 74 | 
            +
                  unless @connection.failed_proxy_connect?
         | 
| 75 | 
            +
                    @connection.send_request(req)
         | 
| 76 | 
            +
                    @connection.read_headers!
         | 
| 77 | 
            +
                  end
         | 
| 77 78 |  | 
| 78 79 | 
             
                  res = Response.new(
         | 
| 79 80 | 
             
                    @connection.status_code,
         | 
    
        data/lib/http/connection.rb
    CHANGED
    
    | @@ -6,6 +6,7 @@ module HTTP | |
| 6 6 | 
             
              # A connection to the HTTP server
         | 
| 7 7 | 
             
              class Connection
         | 
| 8 8 | 
             
                extend Forwardable
         | 
| 9 | 
            +
             | 
| 9 10 | 
             
                # Attempt to read this much data
         | 
| 10 11 | 
             
                BUFFER_SIZE = 16_384
         | 
| 11 12 |  | 
| @@ -18,16 +19,18 @@ module HTTP | |
| 18 19 | 
             
                # @param [HTTP::Request] req
         | 
| 19 20 | 
             
                # @param [HTTP::Options] options
         | 
| 20 21 | 
             
                def initialize(req, options)
         | 
| 21 | 
            -
                  @persistent | 
| 22 | 
            -
                  @keep_alive_timeout | 
| 23 | 
            -
                  @pending_request | 
| 24 | 
            -
                  @pending_response | 
| 22 | 
            +
                  @persistent           = options.persistent?
         | 
| 23 | 
            +
                  @keep_alive_timeout   = options[:keep_alive_timeout].to_f
         | 
| 24 | 
            +
                  @pending_request      = false
         | 
| 25 | 
            +
                  @pending_response     = false
         | 
| 26 | 
            +
                  @failed_proxy_connect = false
         | 
| 25 27 |  | 
| 26 28 | 
             
                  @parser = Response::Parser.new
         | 
| 27 29 |  | 
| 28 30 | 
             
                  @socket = options[:timeout_class].new(options[:timeout_options])
         | 
| 29 31 | 
             
                  @socket.connect(options[:socket_class], req.socket_host, req.socket_port)
         | 
| 30 32 |  | 
| 33 | 
            +
                  send_proxy_connect_request(req)
         | 
| 31 34 | 
             
                  start_tls(req, options)
         | 
| 32 35 | 
             
                  reset_timer
         | 
| 33 36 | 
             
                end
         | 
| @@ -41,6 +44,11 @@ module HTTP | |
| 41 44 | 
             
                # @see (HTTP::Response::Parser#headers)
         | 
| 42 45 | 
             
                def_delegator :@parser, :headers
         | 
| 43 46 |  | 
| 47 | 
            +
                # @return [Boolean] whenever proxy connect failed
         | 
| 48 | 
            +
                def failed_proxy_connect?
         | 
| 49 | 
            +
                  @failed_proxy_connect
         | 
| 50 | 
            +
                end
         | 
| 51 | 
            +
             | 
| 44 52 | 
             
                # Send a request to the server
         | 
| 45 53 | 
             
                #
         | 
| 46 54 | 
             
                # @param [Request] Request to send to the server
         | 
| @@ -129,7 +137,7 @@ module HTTP | |
| 129 137 | 
             
                # @param (see #initialize)
         | 
| 130 138 | 
             
                # @return [void]
         | 
| 131 139 | 
             
                def start_tls(req, options)
         | 
| 132 | 
            -
                  return unless req.uri.https? && ! | 
| 140 | 
            +
                  return unless req.uri.https? && !failed_proxy_connect?
         | 
| 133 141 |  | 
| 134 142 | 
             
                  ssl_context = options[:ssl_context]
         | 
| 135 143 |  | 
| @@ -141,6 +149,28 @@ module HTTP | |
| 141 149 | 
             
                  @socket.start_tls(req.uri.host, options[:ssl_socket_class], ssl_context)
         | 
| 142 150 | 
             
                end
         | 
| 143 151 |  | 
| 152 | 
            +
                # Open tunnel through proxy
         | 
| 153 | 
            +
                def send_proxy_connect_request(req)
         | 
| 154 | 
            +
                  return unless req.uri.https? && req.using_proxy?
         | 
| 155 | 
            +
             | 
| 156 | 
            +
                  @pending_request = true
         | 
| 157 | 
            +
             | 
| 158 | 
            +
                  req.connect_using_proxy @socket
         | 
| 159 | 
            +
             | 
| 160 | 
            +
                  @pending_request = false
         | 
| 161 | 
            +
                  @pending_response = true
         | 
| 162 | 
            +
             | 
| 163 | 
            +
                  read_headers!
         | 
| 164 | 
            +
             | 
| 165 | 
            +
                  if @parser.status_code == 200
         | 
| 166 | 
            +
                    @parser.reset
         | 
| 167 | 
            +
                    @pending_response = false
         | 
| 168 | 
            +
                    return
         | 
| 169 | 
            +
                  end
         | 
| 170 | 
            +
             | 
| 171 | 
            +
                  @failed_proxy_connect = true
         | 
| 172 | 
            +
                end
         | 
| 173 | 
            +
             | 
| 144 174 | 
             
                # Resets expiration of persistent connection.
         | 
| 145 175 | 
             
                # @return [void]
         | 
| 146 176 | 
             
                def reset_timer
         | 
    
        data/lib/http/options.rb
    CHANGED
    
    | @@ -30,7 +30,7 @@ module HTTP | |
| 30 30 |  | 
| 31 31 | 
             
                  def def_option(name, &interpreter)
         | 
| 32 32 | 
             
                    defined_options << name.to_sym
         | 
| 33 | 
            -
                    interpreter ||=  | 
| 33 | 
            +
                    interpreter ||= lambda { |v| v }
         | 
| 34 34 |  | 
| 35 35 | 
             
                    attr_accessor name
         | 
| 36 36 | 
             
                    protected :"#{name}="
         | 
| @@ -118,9 +118,9 @@ module HTTP | |
| 118 118 | 
             
                end
         | 
| 119 119 |  | 
| 120 120 | 
             
                def to_hash
         | 
| 121 | 
            -
                  hash_pairs = self.class
         | 
| 122 | 
            -
                               . | 
| 123 | 
            -
                                | 
| 121 | 
            +
                  hash_pairs = self.class.
         | 
| 122 | 
            +
                               defined_options.
         | 
| 123 | 
            +
                               flat_map { |opt_name| [opt_name, self[opt_name]] }
         | 
| 124 124 | 
             
                  Hash[*hash_pairs]
         | 
| 125 125 | 
             
                end
         | 
| 126 126 |  | 
    
        data/lib/http/request.rb
    CHANGED
    
    | @@ -90,7 +90,7 @@ module HTTP | |
| 90 90 |  | 
| 91 91 | 
             
                # Stream the request to a socket
         | 
| 92 92 | 
             
                def stream(socket)
         | 
| 93 | 
            -
                  include_proxy_authorization_header if using_authenticated_proxy?
         | 
| 93 | 
            +
                  include_proxy_authorization_header if using_authenticated_proxy? && !@uri.https?
         | 
| 94 94 | 
             
                  Request::Writer.new(socket, body, headers, request_header).stream
         | 
| 95 95 | 
             
                end
         | 
| 96 96 |  | 
| @@ -106,8 +106,17 @@ module HTTP | |
| 106 106 |  | 
| 107 107 | 
             
                # Compute and add the Proxy-Authorization header
         | 
| 108 108 | 
             
                def include_proxy_authorization_header
         | 
| 109 | 
            -
                   | 
| 110 | 
            -
             | 
| 109 | 
            +
                  headers["Proxy-Authorization"] = proxy_authorization_header
         | 
| 110 | 
            +
                end
         | 
| 111 | 
            +
             | 
| 112 | 
            +
                def proxy_authorization_header
         | 
| 113 | 
            +
                  digest = Base64.strict_encode64("#{proxy[:proxy_username]}:#{proxy[:proxy_password]}")
         | 
| 114 | 
            +
                  "Basic #{digest}"
         | 
| 115 | 
            +
                end
         | 
| 116 | 
            +
             | 
| 117 | 
            +
                # Setup tunnel through proxy for SSL request
         | 
| 118 | 
            +
                def connect_using_proxy(socket)
         | 
| 119 | 
            +
                  Request::Writer.new(socket, nil, proxy_connect_headers, proxy_connect_header).connect_through_proxy
         | 
| 111 120 | 
             
                end
         | 
| 112 121 |  | 
| 113 122 | 
             
                # Compute HTTP request header for direct or proxy request
         | 
| @@ -116,6 +125,21 @@ module HTTP | |
| 116 125 | 
             
                  "#{verb.to_s.upcase} #{request_uri} HTTP/#{version}"
         | 
| 117 126 | 
             
                end
         | 
| 118 127 |  | 
| 128 | 
            +
                # Compute HTTP request header SSL proxy connection
         | 
| 129 | 
            +
                def proxy_connect_header
         | 
| 130 | 
            +
                  "CONNECT #{@uri.host}:#{@uri.port} HTTP/#{version}"
         | 
| 131 | 
            +
                end
         | 
| 132 | 
            +
             | 
| 133 | 
            +
                # Headers to send with proxy connect request
         | 
| 134 | 
            +
                def proxy_connect_headers
         | 
| 135 | 
            +
                  connect_headers = HTTP::Headers.coerce(
         | 
| 136 | 
            +
                    "Host" => headers["Host"],
         | 
| 137 | 
            +
                    "User-Agent" => headers["User-Agent"]
         | 
| 138 | 
            +
                  )
         | 
| 139 | 
            +
                  connect_headers["Proxy-Authorization"] = proxy_authorization_header if using_authenticated_proxy?
         | 
| 140 | 
            +
                  connect_headers
         | 
| 141 | 
            +
                end
         | 
| 142 | 
            +
             | 
| 119 143 | 
             
                # Host for tcp socket
         | 
| 120 144 | 
             
                def socket_host
         | 
| 121 145 | 
             
                  using_proxy? ? proxy[:proxy_address] : host
         | 
    
        data/lib/http/request/caching.rb
    CHANGED
    
    | @@ -70,7 +70,7 @@ module HTTP | |
| 70 70 | 
             
                  end
         | 
| 71 71 |  | 
| 72 72 | 
             
                  def env
         | 
| 73 | 
            -
                    {"rack-cache.cache_key" =>  | 
| 73 | 
            +
                    {"rack-cache.cache_key" => lambda { |r| r.uri.to_s }}
         | 
| 74 74 | 
             
                  end
         | 
| 75 75 |  | 
| 76 76 | 
             
                  private
         | 
| @@ -80,11 +80,11 @@ module HTTP | |
| 80 80 | 
             
                  def conditional_headers_for(cached_response)
         | 
| 81 81 | 
             
                    headers = HTTP::Headers.new
         | 
| 82 82 |  | 
| 83 | 
            -
                    cached_response.headers.get("Etag")
         | 
| 84 | 
            -
                       | 
| 83 | 
            +
                    cached_response.headers.get("Etag").
         | 
| 84 | 
            +
                      each { |etag| headers.add("If-None-Match", etag) }
         | 
| 85 85 |  | 
| 86 | 
            -
                    cached_response.headers.get("Last-Modified")
         | 
| 87 | 
            -
                       | 
| 86 | 
            +
                    cached_response.headers.get("Last-Modified").
         | 
| 87 | 
            +
                      each { |last_mod| headers.add("If-Modified-Since", last_mod) }
         | 
| 88 88 |  | 
| 89 89 | 
             
                    headers.add("Cache-Control", "max-age=0") if cache_headers.forces_revalidation?
         | 
| 90 90 |  | 
    
        data/lib/http/request/writer.rb
    CHANGED
    
    | @@ -29,6 +29,12 @@ module HTTP | |
| 29 29 | 
             
                    send_request_body
         | 
| 30 30 | 
             
                  end
         | 
| 31 31 |  | 
| 32 | 
            +
                  # Send headers needed to connect through proxy
         | 
| 33 | 
            +
                  def connect_through_proxy
         | 
| 34 | 
            +
                    add_headers
         | 
| 35 | 
            +
                    @socket << join_headers
         | 
| 36 | 
            +
                  end
         | 
| 37 | 
            +
             | 
| 32 38 | 
             
                  # Adds the headers to the header array for the given request body we are working
         | 
| 33 39 | 
             
                  # with
         | 
| 34 40 | 
             
                  def add_body_type_headers
         | 
| @@ -50,9 +56,8 @@ module HTTP | |
| 50 56 | 
             
                  def send_request_header
         | 
| 51 57 | 
             
                    add_headers
         | 
| 52 58 | 
             
                    add_body_type_headers
         | 
| 53 | 
            -
                    header = join_headers
         | 
| 54 59 |  | 
| 55 | 
            -
                    @socket <<  | 
| 60 | 
            +
                    @socket << join_headers
         | 
| 56 61 | 
             
                  end
         | 
| 57 62 |  | 
| 58 63 | 
             
                  def send_request_body
         | 
| @@ -123,9 +123,9 @@ module HTTP | |
| 123 123 |  | 
| 124 124 | 
             
                  # @return [Time] the time at which the server generated this response.
         | 
| 125 125 | 
             
                  def server_response_time
         | 
| 126 | 
            -
                    headers.get("Date")
         | 
| 127 | 
            -
                       | 
| 128 | 
            -
                       | 
| 126 | 
            +
                    headers.get("Date").
         | 
| 127 | 
            +
                      map(&method(:to_time_or_epoch)).
         | 
| 128 | 
            +
                      max || begin
         | 
| 129 129 | 
             
                                # set it if it is not already set
         | 
| 130 130 | 
             
                                headers["Date"] = received_at.httpdate
         | 
| 131 131 | 
             
                                received_at
         | 
    
        data/lib/http/version.rb
    CHANGED
    
    
    
        data/spec/lib/http/cache_spec.rb
    CHANGED
    
    | @@ -6,8 +6,8 @@ RSpec.describe HTTP::Cache do | |
| 6 6 | 
             
                subject { described_class }
         | 
| 7 7 |  | 
| 8 8 | 
             
                it "allows metastore and entitystore" do
         | 
| 9 | 
            -
                  expect(subject.new(:metastore => "heap:/", :entitystore => "heap:/"))
         | 
| 10 | 
            -
                     | 
| 9 | 
            +
                  expect(subject.new(:metastore => "heap:/", :entitystore => "heap:/")).
         | 
| 10 | 
            +
                    to be_kind_of HTTP::Cache
         | 
| 11 11 | 
             
                end
         | 
| 12 12 | 
             
              end
         | 
| 13 13 |  | 
| @@ -151,10 +151,10 @@ RSpec.describe HTTP::Cache do | |
| 151 151 |  | 
| 152 152 | 
             
                it "makes request with conditional request headers" do
         | 
| 153 153 | 
             
                  subject.perform(request, opts) do |actual_request, _|
         | 
| 154 | 
            -
                    expect(actual_request.headers["If-None-Match"])
         | 
| 155 | 
            -
                       | 
| 156 | 
            -
                    expect(actual_request.headers["If-Modified-Since"])
         | 
| 157 | 
            -
                       | 
| 154 | 
            +
                    expect(actual_request.headers["If-None-Match"]).
         | 
| 155 | 
            +
                      to eq cached_response.headers["Etag"]
         | 
| 156 | 
            +
                    expect(actual_request.headers["If-Modified-Since"]).
         | 
| 157 | 
            +
                      to eq cached_response.headers["Last-Modified"]
         | 
| 158 158 |  | 
| 159 159 | 
             
                    origin_response
         | 
| 160 160 | 
             
                  end
         | 
| @@ -60,8 +60,8 @@ RSpec.describe HTTP::Client do | |
| 60 60 | 
             
                    "http://example.com/" => redirect_response("/")
         | 
| 61 61 | 
             
                  )
         | 
| 62 62 |  | 
| 63 | 
            -
                  expect { client.get("http://example.com/") }
         | 
| 64 | 
            -
                     | 
| 63 | 
            +
                  expect { client.get("http://example.com/") }.
         | 
| 64 | 
            +
                    to raise_error(HTTP::Redirector::EndlessRedirectError)
         | 
| 65 65 | 
             
                end
         | 
| 66 66 |  | 
| 67 67 | 
             
                it "fails if max amount of hops reached" do
         | 
| @@ -75,8 +75,8 @@ RSpec.describe HTTP::Client do | |
| 75 75 | 
             
                    "http://example.com/6" => simple_response("OK")
         | 
| 76 76 | 
             
                  )
         | 
| 77 77 |  | 
| 78 | 
            -
                  expect { client.get("http://example.com/") }
         | 
| 79 | 
            -
                     | 
| 78 | 
            +
                  expect { client.get("http://example.com/") }.
         | 
| 79 | 
            +
                    to raise_error(HTTP::Redirector::TooManyRedirectsError)
         | 
| 80 80 | 
             
                end
         | 
| 81 81 |  | 
| 82 82 | 
             
                context "with non-ASCII URLs" do
         | 
| @@ -103,17 +103,17 @@ RSpec.describe HTTP::Client do | |
| 103 103 | 
             
                it "returns cached responses if they exist" do
         | 
| 104 104 | 
             
                  cached_response = simple_response("cached").caching
         | 
| 105 105 | 
             
                  StubbedClient.new(:cache =>
         | 
| 106 | 
            -
                                    HTTP::Cache.new(:metastore => "heap:/", :entitystore => "heap:/"))
         | 
| 107 | 
            -
                     | 
| 108 | 
            -
                     | 
| 106 | 
            +
                                    HTTP::Cache.new(:metastore => "heap:/", :entitystore => "heap:/")).
         | 
| 107 | 
            +
                    stub("http://example.com/#{sn}" => cached_response).
         | 
| 108 | 
            +
                    get("http://example.com/#{sn}")
         | 
| 109 109 |  | 
| 110 110 | 
             
                  # cache is now warm
         | 
| 111 111 |  | 
| 112 | 
            -
                  client = StubbedClient.new(:cache => HTTP::Cache.new(:metastore => "heap:/", :entitystore => "heap:/"))
         | 
| 113 | 
            -
                            | 
| 112 | 
            +
                  client = StubbedClient.new(:cache => HTTP::Cache.new(:metastore => "heap:/", :entitystore => "heap:/")).
         | 
| 113 | 
            +
                           stub("http://example.com/#{sn}" => simple_response("OK"))
         | 
| 114 114 |  | 
| 115 | 
            -
                  expect(client.get("http://example.com/#{sn}").body.to_s)
         | 
| 116 | 
            -
                     | 
| 115 | 
            +
                  expect(client.get("http://example.com/#{sn}").body.to_s).
         | 
| 116 | 
            +
                    to eq cached_response.body.to_s
         | 
| 117 117 | 
             
                end
         | 
| 118 118 | 
             
              end
         | 
| 119 119 |  | 
| @@ -226,8 +226,8 @@ RSpec.describe HTTP::Client do | |
| 226 226 | 
             
                end
         | 
| 227 227 |  | 
| 228 228 | 
             
                it "fails with OpenSSL::SSL::SSLError if host mismatch" do
         | 
| 229 | 
            -
                  expect { client.get(dummy_ssl.endpoint.gsub("127.0.0.1", "localhost")) }
         | 
| 230 | 
            -
                     | 
| 229 | 
            +
                  expect { client.get(dummy_ssl.endpoint.gsub("127.0.0.1", "localhost")) }.
         | 
| 230 | 
            +
                    to raise_error(OpenSSL::SSL::SSLError, /does not match/)
         | 
| 231 231 | 
             
                end
         | 
| 232 232 |  | 
| 233 233 | 
             
                context "with SSL options instead of a context" do
         | 
| @@ -29,13 +29,13 @@ RSpec.describe HTTP::Headers do | |
| 29 29 | 
             
                end
         | 
| 30 30 |  | 
| 31 31 | 
             
                it "fails with empty header name" do
         | 
| 32 | 
            -
                  expect { headers.set "", "foo bar" }
         | 
| 33 | 
            -
                     | 
| 32 | 
            +
                  expect { headers.set "", "foo bar" }.
         | 
| 33 | 
            +
                    to raise_error HTTP::InvalidHeaderNameError
         | 
| 34 34 | 
             
                end
         | 
| 35 35 |  | 
| 36 36 | 
             
                it "fails with invalid header name" do
         | 
| 37 | 
            -
                  expect { headers.set "foo bar", "baz" }
         | 
| 38 | 
            -
                     | 
| 37 | 
            +
                  expect { headers.set "foo bar", "baz" }.
         | 
| 38 | 
            +
                    to raise_error HTTP::InvalidHeaderNameError
         | 
| 39 39 | 
             
                end
         | 
| 40 40 | 
             
              end
         | 
| 41 41 |  | 
| @@ -77,13 +77,13 @@ RSpec.describe HTTP::Headers do | |
| 77 77 | 
             
                end
         | 
| 78 78 |  | 
| 79 79 | 
             
                it "fails with empty header name" do
         | 
| 80 | 
            -
                  expect { headers.delete "" }
         | 
| 81 | 
            -
                     | 
| 80 | 
            +
                  expect { headers.delete "" }.
         | 
| 81 | 
            +
                    to raise_error HTTP::InvalidHeaderNameError
         | 
| 82 82 | 
             
                end
         | 
| 83 83 |  | 
| 84 84 | 
             
                it "fails with invalid header name" do
         | 
| 85 | 
            -
                  expect { headers.delete "foo bar" }
         | 
| 86 | 
            -
                     | 
| 85 | 
            +
                  expect { headers.delete "foo bar" }.
         | 
| 86 | 
            +
                    to raise_error HTTP::InvalidHeaderNameError
         | 
| 87 87 | 
             
                end
         | 
| 88 88 | 
             
              end
         | 
| 89 89 |  | 
| @@ -111,13 +111,13 @@ RSpec.describe HTTP::Headers do | |
| 111 111 | 
             
                end
         | 
| 112 112 |  | 
| 113 113 | 
             
                it "fails with empty header name" do
         | 
| 114 | 
            -
                  expect { headers.add "", "foobar" }
         | 
| 115 | 
            -
                     | 
| 114 | 
            +
                  expect { headers.add "", "foobar" }.
         | 
| 115 | 
            +
                    to raise_error HTTP::InvalidHeaderNameError
         | 
| 116 116 | 
             
                end
         | 
| 117 117 |  | 
| 118 118 | 
             
                it "fails with invalid header name" do
         | 
| 119 | 
            -
                  expect { headers.add "foo bar", "baz" }
         | 
| 120 | 
            -
                     | 
| 119 | 
            +
                  expect { headers.add "foo bar", "baz" }.
         | 
| 120 | 
            +
                    to raise_error HTTP::InvalidHeaderNameError
         | 
| 121 121 | 
             
                end
         | 
| 122 122 | 
             
              end
         | 
| 123 123 |  | 
| @@ -139,13 +139,13 @@ RSpec.describe HTTP::Headers do | |
| 139 139 | 
             
                end
         | 
| 140 140 |  | 
| 141 141 | 
             
                it "fails with empty header name" do
         | 
| 142 | 
            -
                  expect { headers.get "" }
         | 
| 143 | 
            -
                     | 
| 142 | 
            +
                  expect { headers.get "" }.
         | 
| 143 | 
            +
                    to raise_error HTTP::InvalidHeaderNameError
         | 
| 144 144 | 
             
                end
         | 
| 145 145 |  | 
| 146 146 | 
             
                it "fails with invalid header name" do
         | 
| 147 | 
            -
                  expect { headers.get "foo bar" }
         | 
| 148 | 
            -
                     | 
| 147 | 
            +
                  expect { headers.get "foo bar" }.
         | 
| 148 | 
            +
                    to raise_error HTTP::InvalidHeaderNameError
         | 
| 149 149 | 
             
                end
         | 
| 150 150 | 
             
              end
         | 
| 151 151 |  | 
| @@ -33,24 +33,24 @@ RSpec.describe HTTP::Redirector do | |
| 33 33 | 
             
                  req = HTTP::Request.new :head, "http://example.com"
         | 
| 34 34 | 
             
                  res = proc { |prev_req| redirect_response(301, "#{prev_req.uri}/1") }
         | 
| 35 35 |  | 
| 36 | 
            -
                  expect { redirector.perform(req, res.call(req), &res) }
         | 
| 37 | 
            -
                     | 
| 36 | 
            +
                  expect { redirector.perform(req, res.call(req), &res) }.
         | 
| 37 | 
            +
                    to raise_error HTTP::Redirector::TooManyRedirectsError
         | 
| 38 38 | 
             
                end
         | 
| 39 39 |  | 
| 40 40 | 
             
                it "fails with EndlessRedirectError if endless loop detected" do
         | 
| 41 41 | 
             
                  req = HTTP::Request.new :head, "http://example.com"
         | 
| 42 42 | 
             
                  res = redirect_response(301, req.uri)
         | 
| 43 43 |  | 
| 44 | 
            -
                  expect { redirector.perform(req, res) { res } }
         | 
| 45 | 
            -
                     | 
| 44 | 
            +
                  expect { redirector.perform(req, res) { res } }.
         | 
| 45 | 
            +
                    to raise_error HTTP::Redirector::EndlessRedirectError
         | 
| 46 46 | 
             
                end
         | 
| 47 47 |  | 
| 48 48 | 
             
                it "fails with StateError if there were no Location header" do
         | 
| 49 49 | 
             
                  req = HTTP::Request.new :head, "http://example.com"
         | 
| 50 50 | 
             
                  res = simple_response(301)
         | 
| 51 51 |  | 
| 52 | 
            -
                  expect { |b| redirector.perform(req, res, &b) }
         | 
| 53 | 
            -
                     | 
| 52 | 
            +
                  expect { |b| redirector.perform(req, res, &b) }.
         | 
| 53 | 
            +
                    to raise_error HTTP::StateError
         | 
| 54 54 | 
             
                end
         | 
| 55 55 |  | 
| 56 56 | 
             
                it "returns first non-redirect response" do
         | 
| @@ -86,24 +86,24 @@ RSpec.describe HTTP::Redirector do | |
| 86 86 | 
             
                      req = HTTP::Request.new :put, "http://example.com"
         | 
| 87 87 | 
             
                      res = redirect_response 300, "http://example.com/1"
         | 
| 88 88 |  | 
| 89 | 
            -
                      expect { redirector.perform(req, res) { simple_response 200 } }
         | 
| 90 | 
            -
                         | 
| 89 | 
            +
                      expect { redirector.perform(req, res) { simple_response 200 } }.
         | 
| 90 | 
            +
                        to raise_error HTTP::StateError
         | 
| 91 91 | 
             
                    end
         | 
| 92 92 |  | 
| 93 93 | 
             
                    it "raises StateError if original request was POST" do
         | 
| 94 94 | 
             
                      req = HTTP::Request.new :post, "http://example.com"
         | 
| 95 95 | 
             
                      res = redirect_response 300, "http://example.com/1"
         | 
| 96 96 |  | 
| 97 | 
            -
                      expect { redirector.perform(req, res) { simple_response 200 } }
         | 
| 98 | 
            -
                         | 
| 97 | 
            +
                      expect { redirector.perform(req, res) { simple_response 200 } }.
         | 
| 98 | 
            +
                        to raise_error HTTP::StateError
         | 
| 99 99 | 
             
                    end
         | 
| 100 100 |  | 
| 101 101 | 
             
                    it "raises StateError if original request was DELETE" do
         | 
| 102 102 | 
             
                      req = HTTP::Request.new :delete, "http://example.com"
         | 
| 103 103 | 
             
                      res = redirect_response 300, "http://example.com/1"
         | 
| 104 104 |  | 
| 105 | 
            -
                      expect { redirector.perform(req, res) { simple_response 200 } }
         | 
| 106 | 
            -
                         | 
| 105 | 
            +
                      expect { redirector.perform(req, res) { simple_response 200 } }.
         | 
| 106 | 
            +
                        to raise_error HTTP::StateError
         | 
| 107 107 | 
             
                    end
         | 
| 108 108 | 
             
                  end
         | 
| 109 109 |  | 
| @@ -170,24 +170,24 @@ RSpec.describe HTTP::Redirector do | |
| 170 170 | 
             
                      req = HTTP::Request.new :put, "http://example.com"
         | 
| 171 171 | 
             
                      res = redirect_response 301, "http://example.com/1"
         | 
| 172 172 |  | 
| 173 | 
            -
                      expect { redirector.perform(req, res) { simple_response 200 } }
         | 
| 174 | 
            -
                         | 
| 173 | 
            +
                      expect { redirector.perform(req, res) { simple_response 200 } }.
         | 
| 174 | 
            +
                        to raise_error HTTP::StateError
         | 
| 175 175 | 
             
                    end
         | 
| 176 176 |  | 
| 177 177 | 
             
                    it "raises StateError if original request was POST" do
         | 
| 178 178 | 
             
                      req = HTTP::Request.new :post, "http://example.com"
         | 
| 179 179 | 
             
                      res = redirect_response 301, "http://example.com/1"
         | 
| 180 180 |  | 
| 181 | 
            -
                      expect { redirector.perform(req, res) { simple_response 200 } }
         | 
| 182 | 
            -
                         | 
| 181 | 
            +
                      expect { redirector.perform(req, res) { simple_response 200 } }.
         | 
| 182 | 
            +
                        to raise_error HTTP::StateError
         | 
| 183 183 | 
             
                    end
         | 
| 184 184 |  | 
| 185 185 | 
             
                    it "raises StateError if original request was DELETE" do
         | 
| 186 186 | 
             
                      req = HTTP::Request.new :delete, "http://example.com"
         | 
| 187 187 | 
             
                      res = redirect_response 301, "http://example.com/1"
         | 
| 188 188 |  | 
| 189 | 
            -
                      expect { redirector.perform(req, res) { simple_response 200 } }
         | 
| 190 | 
            -
                         | 
| 189 | 
            +
                      expect { redirector.perform(req, res) { simple_response 200 } }.
         | 
| 190 | 
            +
                        to raise_error HTTP::StateError
         | 
| 191 191 | 
             
                    end
         | 
| 192 192 | 
             
                  end
         | 
| 193 193 |  | 
| @@ -254,24 +254,24 @@ RSpec.describe HTTP::Redirector do | |
| 254 254 | 
             
                      req = HTTP::Request.new :put, "http://example.com"
         | 
| 255 255 | 
             
                      res = redirect_response 302, "http://example.com/1"
         | 
| 256 256 |  | 
| 257 | 
            -
                      expect { redirector.perform(req, res) { simple_response 200 } }
         | 
| 258 | 
            -
                         | 
| 257 | 
            +
                      expect { redirector.perform(req, res) { simple_response 200 } }.
         | 
| 258 | 
            +
                        to raise_error HTTP::StateError
         | 
| 259 259 | 
             
                    end
         | 
| 260 260 |  | 
| 261 261 | 
             
                    it "raises StateError if original request was POST" do
         | 
| 262 262 | 
             
                      req = HTTP::Request.new :post, "http://example.com"
         | 
| 263 263 | 
             
                      res = redirect_response 302, "http://example.com/1"
         | 
| 264 264 |  | 
| 265 | 
            -
                      expect { redirector.perform(req, res) { simple_response 200 } }
         | 
| 266 | 
            -
                         | 
| 265 | 
            +
                      expect { redirector.perform(req, res) { simple_response 200 } }.
         | 
| 266 | 
            +
                        to raise_error HTTP::StateError
         | 
| 267 267 | 
             
                    end
         | 
| 268 268 |  | 
| 269 269 | 
             
                    it "raises StateError if original request was DELETE" do
         | 
| 270 270 | 
             
                      req = HTTP::Request.new :delete, "http://example.com"
         | 
| 271 271 | 
             
                      res = redirect_response 302, "http://example.com/1"
         | 
| 272 272 |  | 
| 273 | 
            -
                      expect { redirector.perform(req, res) { simple_response 200 } }
         | 
| 274 | 
            -
                         | 
| 273 | 
            +
                      expect { redirector.perform(req, res) { simple_response 200 } }.
         | 
| 274 | 
            +
                        to raise_error HTTP::StateError
         | 
| 275 275 | 
             
                    end
         | 
| 276 276 | 
             
                  end
         | 
| 277 277 |  | 
| @@ -105,8 +105,8 @@ RSpec.describe HTTP::Response do | |
| 105 105 | 
             
                  body      = double :to_s => "foobar"
         | 
| 106 106 | 
             
                  response  = HTTP::Response.new(200, "1.1", headers, body)
         | 
| 107 107 |  | 
| 108 | 
            -
                  expect(response.inspect)
         | 
| 109 | 
            -
                     | 
| 108 | 
            +
                  expect(response.inspect).
         | 
| 109 | 
            +
                    to eq '#<HTTP::Response/1.1 200 OK {"Content-Type"=>"text/plain"}>'
         | 
| 110 110 | 
             
                end
         | 
| 111 111 | 
             
              end
         | 
| 112 112 |  | 
    
        data/spec/lib/http_spec.rb
    CHANGED
    
    | @@ -5,6 +5,11 @@ require "support/proxy_server" | |
| 5 5 |  | 
| 6 6 | 
             
            RSpec.describe HTTP do
         | 
| 7 7 | 
             
              run_server(:dummy) { DummyServer.new }
         | 
| 8 | 
            +
              run_server(:dummy_ssl) { DummyServer.new(:ssl => true) }
         | 
| 9 | 
            +
             | 
| 10 | 
            +
              let(:ssl_client) do
         | 
| 11 | 
            +
                HTTP::Client.new :ssl_context => SSLHelper.client_context
         | 
| 12 | 
            +
              end
         | 
| 8 13 |  | 
| 9 14 | 
             
              context "getting resources" do
         | 
| 10 15 | 
             
                it "is easy" do
         | 
| @@ -63,6 +68,18 @@ RSpec.describe HTTP do | |
| 63 68 | 
             
                    response = HTTP.via(proxy.addr, proxy.port, "username", "password").get dummy.endpoint
         | 
| 64 69 | 
             
                    expect(response.to_s).to match(/<!doctype html>/)
         | 
| 65 70 | 
             
                  end
         | 
| 71 | 
            +
             | 
| 72 | 
            +
                  context "ssl" do
         | 
| 73 | 
            +
                    it "responds with the endpoint's body" do
         | 
| 74 | 
            +
                      response = ssl_client.via(proxy.addr, proxy.port).get dummy_ssl.endpoint
         | 
| 75 | 
            +
                      expect(response.to_s).to match(/<!doctype html>/)
         | 
| 76 | 
            +
                    end
         | 
| 77 | 
            +
             | 
| 78 | 
            +
                    it "ignores credentials" do
         | 
| 79 | 
            +
                      response = ssl_client.via(proxy.addr, proxy.port, "username", "password").get dummy_ssl.endpoint
         | 
| 80 | 
            +
                      expect(response.to_s).to match(/<!doctype html>/)
         | 
| 81 | 
            +
                    end
         | 
| 82 | 
            +
                  end
         | 
| 66 83 | 
             
                end
         | 
| 67 84 |  | 
| 68 85 | 
             
                context "proxy with authentication" do
         | 
| @@ -87,6 +104,23 @@ RSpec.describe HTTP do | |
| 87 104 | 
             
                    response = HTTP.via(proxy.addr, proxy.port).get dummy.endpoint
         | 
| 88 105 | 
             
                    expect(response.status).to eq(407)
         | 
| 89 106 | 
             
                  end
         | 
| 107 | 
            +
             | 
| 108 | 
            +
                  context "ssl" do
         | 
| 109 | 
            +
                    it "responds with the endpoint's body" do
         | 
| 110 | 
            +
                      response = ssl_client.via(proxy.addr, proxy.port, "username", "password").get dummy_ssl.endpoint
         | 
| 111 | 
            +
                      expect(response.to_s).to match(/<!doctype html>/)
         | 
| 112 | 
            +
                    end
         | 
| 113 | 
            +
             | 
| 114 | 
            +
                    it "responds with 407 when wrong credentials given" do
         | 
| 115 | 
            +
                      response = ssl_client.via(proxy.addr, proxy.port, "user", "pass").get dummy_ssl.endpoint
         | 
| 116 | 
            +
                      expect(response.status).to eq(407)
         | 
| 117 | 
            +
                    end
         | 
| 118 | 
            +
             | 
| 119 | 
            +
                    it "responds with 407 if no credentials given" do
         | 
| 120 | 
            +
                      response = ssl_client.via(proxy.addr, proxy.port).get dummy_ssl.endpoint
         | 
| 121 | 
            +
                      expect(response.status).to eq(407)
         | 
| 122 | 
            +
                    end
         | 
| 123 | 
            +
                  end
         | 
| 90 124 | 
             
                end
         | 
| 91 125 | 
             
              end
         | 
| 92 126 |  | 
| @@ -151,15 +185,15 @@ RSpec.describe HTTP do | |
| 151 185 |  | 
| 152 186 | 
             
                it "sets Authorization header with proper BasicAuth value" do
         | 
| 153 187 | 
             
                  client = HTTP.basic_auth :user => "foo", :pass => "bar"
         | 
| 154 | 
            -
                  expect(client.default_headers[:authorization])
         | 
| 155 | 
            -
                     | 
| 188 | 
            +
                  expect(client.default_headers[:authorization]).
         | 
| 189 | 
            +
                    to match(%r{^Basic [A-Za-z0-9+/]+=*$})
         | 
| 156 190 | 
             
                end
         | 
| 157 191 | 
             
              end
         | 
| 158 192 |  | 
| 159 | 
            -
              describe ". | 
| 193 | 
            +
              describe ".cache" do
         | 
| 160 194 | 
             
                it "sets cache option" do
         | 
| 161 195 | 
             
                  cache = double(:cache, :perform => nil)
         | 
| 162 | 
            -
                  client = HTTP. | 
| 196 | 
            +
                  client = HTTP.cache cache
         | 
| 163 197 | 
             
                  expect(client.default_options[:cache]).to eq cache
         | 
| 164 198 | 
             
                end
         | 
| 165 199 | 
             
              end
         | 
| @@ -82,8 +82,8 @@ RSpec.shared_context "HTTP handling" do | |
| 82 82 | 
             
                  end
         | 
| 83 83 |  | 
| 84 84 | 
             
                  it "errors if reading takes too long" do
         | 
| 85 | 
            -
                    expect { client.get("#{server.endpoint}/sleep").body.to_s }
         | 
| 86 | 
            -
                       | 
| 85 | 
            +
                    expect { client.get("#{server.endpoint}/sleep").body.to_s }.
         | 
| 86 | 
            +
                      to raise_error(HTTP::TimeoutError, /Timed out/)
         | 
| 87 87 | 
             
                  end
         | 
| 88 88 | 
             
                end
         | 
| 89 89 | 
             
              end
         | 
    
        metadata
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: http
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 0.8. | 
| 4 | 
            +
              version: 0.8.4
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Tony Arcieri
         | 
| @@ -10,7 +10,7 @@ authors: | |
| 10 10 | 
             
            autorequire: 
         | 
| 11 11 | 
             
            bindir: bin
         | 
| 12 12 | 
             
            cert_chain: []
         | 
| 13 | 
            -
            date: 2015-04- | 
| 13 | 
            +
            date: 2015-04-23 00:00:00.000000000 Z
         | 
| 14 14 | 
             
            dependencies:
         | 
| 15 15 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 16 16 | 
             
              name: http_parser.rb
         | 
| @@ -180,9 +180,45 @@ required_rubygems_version: !ruby/object:Gem::Requirement | |
| 180 180 | 
             
                  version: '0'
         | 
| 181 181 | 
             
            requirements: []
         | 
| 182 182 | 
             
            rubyforge_project: 
         | 
| 183 | 
            -
            rubygems_version: 2. | 
| 183 | 
            +
            rubygems_version: 2.4.5
         | 
| 184 184 | 
             
            signing_key: 
         | 
| 185 185 | 
             
            specification_version: 4
         | 
| 186 186 | 
             
            summary: HTTP should be easy
         | 
| 187 | 
            -
            test_files: | 
| 187 | 
            +
            test_files:
         | 
| 188 | 
            +
            - spec/lib/http/cache/headers_spec.rb
         | 
| 189 | 
            +
            - spec/lib/http/cache_spec.rb
         | 
| 190 | 
            +
            - spec/lib/http/client_spec.rb
         | 
| 191 | 
            +
            - spec/lib/http/content_type_spec.rb
         | 
| 192 | 
            +
            - spec/lib/http/headers/mixin_spec.rb
         | 
| 193 | 
            +
            - spec/lib/http/headers_spec.rb
         | 
| 194 | 
            +
            - spec/lib/http/options/body_spec.rb
         | 
| 195 | 
            +
            - spec/lib/http/options/form_spec.rb
         | 
| 196 | 
            +
            - spec/lib/http/options/headers_spec.rb
         | 
| 197 | 
            +
            - spec/lib/http/options/json_spec.rb
         | 
| 198 | 
            +
            - spec/lib/http/options/merge_spec.rb
         | 
| 199 | 
            +
            - spec/lib/http/options/new_spec.rb
         | 
| 200 | 
            +
            - spec/lib/http/options/proxy_spec.rb
         | 
| 201 | 
            +
            - spec/lib/http/options_spec.rb
         | 
| 202 | 
            +
            - spec/lib/http/redirector_spec.rb
         | 
| 203 | 
            +
            - spec/lib/http/request/caching_spec.rb
         | 
| 204 | 
            +
            - spec/lib/http/request/writer_spec.rb
         | 
| 205 | 
            +
            - spec/lib/http/request_spec.rb
         | 
| 206 | 
            +
            - spec/lib/http/response/body_spec.rb
         | 
| 207 | 
            +
            - spec/lib/http/response/caching_spec.rb
         | 
| 208 | 
            +
            - spec/lib/http/response/io_body_spec.rb
         | 
| 209 | 
            +
            - spec/lib/http/response/status_spec.rb
         | 
| 210 | 
            +
            - spec/lib/http/response/string_body_spec.rb
         | 
| 211 | 
            +
            - spec/lib/http/response_spec.rb
         | 
| 212 | 
            +
            - spec/lib/http_spec.rb
         | 
| 213 | 
            +
            - spec/spec_helper.rb
         | 
| 214 | 
            +
            - spec/support/black_hole.rb
         | 
| 215 | 
            +
            - spec/support/capture_warning.rb
         | 
| 216 | 
            +
            - spec/support/connection_reuse_shared.rb
         | 
| 217 | 
            +
            - spec/support/dummy_server.rb
         | 
| 218 | 
            +
            - spec/support/dummy_server/servlet.rb
         | 
| 219 | 
            +
            - spec/support/http_handling_shared.rb
         | 
| 220 | 
            +
            - spec/support/proxy_server.rb
         | 
| 221 | 
            +
            - spec/support/servers/config.rb
         | 
| 222 | 
            +
            - spec/support/servers/runner.rb
         | 
| 223 | 
            +
            - spec/support/ssl_helper.rb
         | 
| 188 224 | 
             
            has_rdoc: 
         |