httpi 4.0.4 → 4.0.6
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/CHANGELOG.md +9 -0
- data/README.md +2 -2
- data/lib/httpi/adapter/base.rb +0 -3
- data/lib/httpi/adapter/curb.rb +15 -18
- data/lib/httpi/adapter/em_http.rb +7 -10
- data/lib/httpi/adapter/excon.rb +17 -20
- data/lib/httpi/adapter/http.rb +12 -14
- data/lib/httpi/adapter/httpclient.rb +5 -8
- data/lib/httpi/adapter/net_http.rb +30 -34
- data/lib/httpi/adapter/net_http_persistent.rb +3 -5
- data/lib/httpi/adapter/rack.rb +24 -16
- data/lib/httpi/adapter.rb +9 -12
- data/lib/httpi/auth/config.rb +0 -3
- data/lib/httpi/auth/ssl.rb +15 -18
- data/lib/httpi/cookie.rb +0 -3
- data/lib/httpi/cookie_store.rb +0 -3
- data/lib/httpi/dime.rb +13 -16
- data/lib/httpi/logger.rb +1 -3
- data/lib/httpi/query_builder.rb +5 -11
- data/lib/httpi/request.rb +11 -14
- data/lib/httpi/response.rb +2 -5
- data/lib/httpi/utils.rb +9 -11
- data/lib/httpi/version.rb +1 -1
- data/lib/httpi.rb +8 -11
- metadata +22 -11
data/lib/httpi/adapter.rb
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
module HTTPI
|
|
2
|
-
|
|
3
2
|
# = HTTPI::Adapter
|
|
4
3
|
#
|
|
5
4
|
# Manages the adapter classes. Currently supports:
|
|
@@ -9,21 +8,22 @@ module HTTPI
|
|
|
9
8
|
# * em_http
|
|
10
9
|
# * net/http
|
|
11
10
|
module Adapter
|
|
12
|
-
|
|
13
11
|
ADAPTERS = {}
|
|
14
12
|
ADAPTER_CLASS_MAP = {}
|
|
15
13
|
|
|
16
14
|
LOAD_ORDER = [:httpclient, :curb, :em_http, :excon, :http, :net_http, :net_http_persistent]
|
|
17
15
|
|
|
18
16
|
class << self
|
|
19
|
-
|
|
20
17
|
def register(name, adapter_class, deps)
|
|
21
|
-
ADAPTERS[name] = {
|
|
18
|
+
ADAPTERS[name] = {class: adapter_class, deps: deps}
|
|
22
19
|
ADAPTER_CLASS_MAP[adapter_class] = name
|
|
23
20
|
end
|
|
24
21
|
|
|
25
22
|
def use=(adapter)
|
|
26
|
-
|
|
23
|
+
if adapter.nil?
|
|
24
|
+
@adapter = nil
|
|
25
|
+
return
|
|
26
|
+
end
|
|
27
27
|
|
|
28
28
|
validate_adapter! adapter
|
|
29
29
|
load_adapter adapter
|
|
@@ -62,15 +62,12 @@ module HTTPI
|
|
|
62
62
|
|
|
63
63
|
def default_adapter
|
|
64
64
|
LOAD_ORDER.each do |adapter|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
next
|
|
70
|
-
end
|
|
65
|
+
load_adapter adapter
|
|
66
|
+
return adapter
|
|
67
|
+
rescue LoadError
|
|
68
|
+
next
|
|
71
69
|
end
|
|
72
70
|
end
|
|
73
|
-
|
|
74
71
|
end
|
|
75
72
|
end
|
|
76
73
|
end
|
data/lib/httpi/auth/config.rb
CHANGED
|
@@ -2,13 +2,11 @@ require "httpi/auth/ssl"
|
|
|
2
2
|
|
|
3
3
|
module HTTPI
|
|
4
4
|
module Auth
|
|
5
|
-
|
|
6
5
|
# = HTTPI::Auth::Config
|
|
7
6
|
#
|
|
8
7
|
# Manages HTTP and SSL auth configuration. Currently supports HTTP basic/digest,
|
|
9
8
|
# Negotiate/SPNEGO, and SSL client authentication.
|
|
10
9
|
class Config
|
|
11
|
-
|
|
12
10
|
# Supported authentication types.
|
|
13
11
|
TYPES = [:basic, :digest, :gssnegotiate, :ssl, :ntlm]
|
|
14
12
|
|
|
@@ -83,7 +81,6 @@ module HTTPI
|
|
|
83
81
|
|
|
84
82
|
# Accessor for the authentication type in use.
|
|
85
83
|
attr_accessor :type
|
|
86
|
-
|
|
87
84
|
end
|
|
88
85
|
end
|
|
89
86
|
end
|
data/lib/httpi/auth/ssl.rb
CHANGED
|
@@ -2,12 +2,10 @@ require "openssl"
|
|
|
2
2
|
|
|
3
3
|
module HTTPI
|
|
4
4
|
module Auth
|
|
5
|
-
|
|
6
5
|
# = HTTPI::Auth::SSL
|
|
7
6
|
#
|
|
8
7
|
# Provides SSL client authentication.
|
|
9
8
|
class SSL
|
|
10
|
-
|
|
11
9
|
VERIFY_MODES = [:none, :peer, :fail_if_no_peer_cert, :client_once]
|
|
12
10
|
CERT_TYPES = [:pem, :der]
|
|
13
11
|
|
|
@@ -21,7 +19,7 @@ module HTTPI
|
|
|
21
19
|
end.sort.reverse
|
|
22
20
|
|
|
23
21
|
# Returns OpenSSL::SSL::*_VERSION values for min_version and max_version
|
|
24
|
-
MIN_MAX_VERSIONS = OpenSSL::SSL.constants.select{|constant| constant
|
|
22
|
+
MIN_MAX_VERSIONS = OpenSSL::SSL.constants.select { |constant| constant =~ /_VERSION$/ }.map { |version| version.to_s.gsub(/_VERSION$/, "").to_sym }.reverse
|
|
25
23
|
|
|
26
24
|
# Returns whether SSL configuration is present.
|
|
27
25
|
def present?
|
|
@@ -74,8 +72,8 @@ module HTTPI
|
|
|
74
72
|
# Sets the cert type to validate SSL certificates PEM|DER.
|
|
75
73
|
def cert_type=(type)
|
|
76
74
|
unless CERT_TYPES.include? type
|
|
77
|
-
raise ArgumentError, "Invalid SSL cert type #{type.inspect}\n"
|
|
78
|
-
|
|
75
|
+
raise ArgumentError, "Invalid SSL cert type #{type.inspect}\n" \
|
|
76
|
+
"Please specify one of #{CERT_TYPES.inspect}"
|
|
79
77
|
end
|
|
80
78
|
|
|
81
79
|
@cert_type = type
|
|
@@ -89,8 +87,8 @@ module HTTPI
|
|
|
89
87
|
# Sets the SSL verify mode. Expects one of <tt>HTTPI::Auth::SSL::VERIFY_MODES</tt>.
|
|
90
88
|
def verify_mode=(mode)
|
|
91
89
|
unless VERIFY_MODES.include? mode
|
|
92
|
-
raise ArgumentError, "Invalid SSL verify mode #{mode.inspect}\n"
|
|
93
|
-
|
|
90
|
+
raise ArgumentError, "Invalid SSL verify mode #{mode.inspect}\n" \
|
|
91
|
+
"Please specify one of #{VERIFY_MODES.inspect}"
|
|
94
92
|
end
|
|
95
93
|
|
|
96
94
|
@verify_mode = mode
|
|
@@ -104,8 +102,8 @@ module HTTPI
|
|
|
104
102
|
# Sets the SSL version number. Expects one of <tt>HTTPI::Auth::SSL::SSL_VERSIONS</tt>.
|
|
105
103
|
def ssl_version=(version)
|
|
106
104
|
unless SSL_VERSIONS.include? version
|
|
107
|
-
raise ArgumentError, "Invalid SSL version #{version.inspect}\n"
|
|
108
|
-
|
|
105
|
+
raise ArgumentError, "Invalid SSL version #{version.inspect}\n" \
|
|
106
|
+
"Please specify one of #{SSL_VERSIONS.inspect}"
|
|
109
107
|
end
|
|
110
108
|
|
|
111
109
|
@ssl_version = version
|
|
@@ -119,8 +117,8 @@ module HTTPI
|
|
|
119
117
|
# Sets the SSL min_version number. Expects one of <tt>HTTPI::Auth::SSL::MIN_MAX_VERSIONS</tt>.
|
|
120
118
|
def min_version=(version)
|
|
121
119
|
unless MIN_MAX_VERSIONS.include? version
|
|
122
|
-
raise ArgumentError, "Invalid SSL min_version #{version.inspect}\n"
|
|
123
|
-
|
|
120
|
+
raise ArgumentError, "Invalid SSL min_version #{version.inspect}\n" \
|
|
121
|
+
"Please specify one of #{MIN_MAX_VERSIONS.inspect}"
|
|
124
122
|
end
|
|
125
123
|
|
|
126
124
|
@min_version = version
|
|
@@ -134,8 +132,8 @@ module HTTPI
|
|
|
134
132
|
# Sets the SSL min_version number. Expects one of <tt>HTTPI::Auth::SSL::MIN_MAX_VERSIONS</tt>.
|
|
135
133
|
def max_version=(version)
|
|
136
134
|
unless MIN_MAX_VERSIONS.include? version
|
|
137
|
-
raise ArgumentError, "Invalid SSL max_version #{version.inspect}\n"
|
|
138
|
-
|
|
135
|
+
raise ArgumentError, "Invalid SSL max_version #{version.inspect}\n" \
|
|
136
|
+
"Please specify one of #{MIN_MAX_VERSIONS.inspect}"
|
|
139
137
|
end
|
|
140
138
|
|
|
141
139
|
@max_version = version
|
|
@@ -168,13 +166,12 @@ module HTTPI
|
|
|
168
166
|
# Returns the SSL verify mode as a <tt>OpenSSL::SSL::VERIFY_*</tt> constant.
|
|
169
167
|
def openssl_verify_mode
|
|
170
168
|
case verify_mode
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
169
|
+
when :none then OpenSSL::SSL::VERIFY_NONE
|
|
170
|
+
when :peer then OpenSSL::SSL::VERIFY_PEER
|
|
171
|
+
when :fail_if_no_peer_cert then OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT
|
|
172
|
+
when :client_once then OpenSSL::SSL::VERIFY_CLIENT_ONCE
|
|
175
173
|
end
|
|
176
174
|
end
|
|
177
|
-
|
|
178
175
|
end
|
|
179
176
|
end
|
|
180
177
|
end
|
data/lib/httpi/cookie.rb
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
module HTTPI
|
|
2
|
-
|
|
3
2
|
# = HTTPI::Cookie
|
|
4
3
|
#
|
|
5
4
|
# Represents a single delicious cookie.
|
|
@@ -11,7 +10,6 @@ module HTTPI
|
|
|
11
10
|
# cookie.name # "token"
|
|
12
11
|
# cookie.name_and_value # "token=choc-choc-chip"
|
|
13
12
|
class Cookie
|
|
14
|
-
|
|
15
13
|
# Returns a list of cookies from a Hash of +headers+.
|
|
16
14
|
def self.list_from_headers(headers)
|
|
17
15
|
Array(headers["Set-Cookie"]).map { |cookie| new(cookie) }
|
|
@@ -30,6 +28,5 @@ module HTTPI
|
|
|
30
28
|
def name_and_value
|
|
31
29
|
@cookie.split(";").first
|
|
32
30
|
end
|
|
33
|
-
|
|
34
31
|
end
|
|
35
32
|
end
|
data/lib/httpi/cookie_store.rb
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
module HTTPI
|
|
2
|
-
|
|
3
2
|
# = HTTPI::CookieStore
|
|
4
3
|
#
|
|
5
4
|
# Stores a unique list of cookies for future requests.
|
|
@@ -13,7 +12,6 @@ module HTTPI
|
|
|
13
12
|
# # Fetch the names and values for the "Cookie" header
|
|
14
13
|
# cookie_store.fetch # => "token=choc-choc-chip"
|
|
15
14
|
class CookieStore
|
|
16
|
-
|
|
17
15
|
def initialize
|
|
18
16
|
@cookies = {}
|
|
19
17
|
end
|
|
@@ -29,6 +27,5 @@ module HTTPI
|
|
|
29
27
|
def fetch
|
|
30
28
|
@cookies.values.join(";") unless @cookies.empty?
|
|
31
29
|
end
|
|
32
|
-
|
|
33
30
|
end
|
|
34
31
|
end
|
data/lib/httpi/dime.rb
CHANGED
|
@@ -1,17 +1,15 @@
|
|
|
1
1
|
module HTTPI
|
|
2
|
-
|
|
3
2
|
DimeRecord = Struct.new(
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
"DimeRecord", :version, :first, :last, :chunked,
|
|
4
|
+
:type_format, :options, :id, :type, :data
|
|
6
5
|
)
|
|
7
6
|
|
|
8
7
|
class Dime < Array
|
|
9
|
-
|
|
10
8
|
BINARY = 1
|
|
11
9
|
XML = 2
|
|
12
10
|
|
|
13
11
|
def initialize(body)
|
|
14
|
-
bytes = body.unpack(
|
|
12
|
+
bytes = body.unpack("C*")
|
|
15
13
|
|
|
16
14
|
while bytes.length > 0
|
|
17
15
|
record = DimeRecord.new
|
|
@@ -29,34 +27,34 @@ module HTTPI
|
|
|
29
27
|
def configure_record(record, bytes)
|
|
30
28
|
byte = bytes.shift
|
|
31
29
|
|
|
32
|
-
record.version
|
|
33
|
-
record.first
|
|
34
|
-
record.last
|
|
35
|
-
record.chunked
|
|
30
|
+
record.version = (byte >> 3) & 31 # 5 bits DIME format version (always 1)
|
|
31
|
+
record.first = (byte >> 2) & 1 # 1 bit Set if this is the first part in the message
|
|
32
|
+
record.last = (byte >> 1) & 1 # 1 bit Set if this is the last part in the message
|
|
33
|
+
record.chunked = byte & 1 # 1 bit This file is broken into chunked parts
|
|
36
34
|
record.type_format = (bytes.shift >> 4) & 15 # 4 bits Type of file in the part (1 for binary data, 2 for XML)
|
|
37
|
-
|
|
35
|
+
# 4 bits Reserved (skipped in the above command)
|
|
38
36
|
end
|
|
39
37
|
|
|
40
38
|
# Fetch big-endian lengths.
|
|
41
39
|
def big_endian_lengths(bytes)
|
|
42
40
|
lengths = [] # we can't use a hash since the order will be screwed in Ruby 1.8
|
|
43
41
|
lengths << [:options, (bytes.shift << 8) | bytes.shift] # 2 bytes Length of the "options" field
|
|
44
|
-
lengths << [:id,
|
|
45
|
-
lengths << [:type,
|
|
46
|
-
lengths << [:data,
|
|
42
|
+
lengths << [:id, (bytes.shift << 8) | bytes.shift] # 2 bytes Length of the "ID" or "name" field
|
|
43
|
+
lengths << [:type, (bytes.shift << 8) | bytes.shift] # 2 bytes Length of the "type" field
|
|
44
|
+
lengths << [:data, (bytes.shift << 24) | (bytes.shift << 16) | (bytes.shift << 8) | bytes.shift] # 4 bytes Size of the included file
|
|
47
45
|
lengths
|
|
48
46
|
end
|
|
49
47
|
|
|
50
48
|
# Read in padded data.
|
|
51
49
|
def read_data(record, bytes, attribute_set)
|
|
52
50
|
attribute, length = attribute_set
|
|
53
|
-
content = bytes.slice!(0, length).pack(
|
|
51
|
+
content = bytes.slice!(0, length).pack("C*")
|
|
54
52
|
|
|
55
53
|
if attribute == :data && record.type_format == BINARY
|
|
56
54
|
content = StringIO.new(content)
|
|
57
55
|
end
|
|
58
56
|
|
|
59
|
-
record.send "#{attribute
|
|
57
|
+
record.send "#{attribute}=", content
|
|
60
58
|
bytes.slice!(0, 4 - (length & 3)) if (length & 3) != 0
|
|
61
59
|
end
|
|
62
60
|
|
|
@@ -67,6 +65,5 @@ module HTTPI
|
|
|
67
65
|
def binary_records
|
|
68
66
|
select { |r| r.type_format == BINARY }
|
|
69
67
|
end
|
|
70
|
-
|
|
71
68
|
end
|
|
72
69
|
end
|
data/lib/httpi/logger.rb
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
require "logger"
|
|
2
2
|
|
|
3
3
|
module HTTPI
|
|
4
|
-
|
|
5
4
|
class << self
|
|
6
|
-
|
|
7
5
|
# Sets whether to log HTTP requests.
|
|
8
6
|
attr_writer :log
|
|
9
7
|
|
|
@@ -47,7 +45,7 @@ module HTTPI
|
|
|
47
45
|
end
|
|
48
46
|
|
|
49
47
|
def request_ssl_info(request)
|
|
50
|
-
if request.auth
|
|
48
|
+
if request.auth&.ssl
|
|
51
49
|
"#{request.auth.ssl.ssl_version}/#{request.auth.ssl.verify_mode}"
|
|
52
50
|
end
|
|
53
51
|
end
|
data/lib/httpi/query_builder.rb
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
module HTTPI
|
|
2
2
|
module QueryBuilder
|
|
3
|
-
|
|
4
3
|
class Flat
|
|
5
|
-
|
|
6
4
|
# Returns a +query+ string given a +Hash+.
|
|
7
5
|
# Example:
|
|
8
6
|
#
|
|
@@ -11,11 +9,9 @@ module HTTPI
|
|
|
11
9
|
def self.build(query)
|
|
12
10
|
Rack::Utils.build_query(query)
|
|
13
11
|
end
|
|
14
|
-
|
|
15
12
|
end
|
|
16
13
|
|
|
17
14
|
class Nested
|
|
18
|
-
|
|
19
15
|
# Returns a +query+ string given a +Hash+.
|
|
20
16
|
# Example:
|
|
21
17
|
#
|
|
@@ -31,17 +27,15 @@ module HTTPI
|
|
|
31
27
|
# Changes Hash values into Strings
|
|
32
28
|
def self.stringify_hash_values(query)
|
|
33
29
|
query.each do |param, value|
|
|
34
|
-
if value.
|
|
35
|
-
|
|
36
|
-
elsif value.
|
|
37
|
-
|
|
30
|
+
query[param] = if value.is_a?(Hash)
|
|
31
|
+
stringify_hash_values(value)
|
|
32
|
+
elsif value.is_a?(Array)
|
|
33
|
+
value.map(&:to_s)
|
|
38
34
|
else
|
|
39
|
-
|
|
35
|
+
value.to_s
|
|
40
36
|
end
|
|
41
37
|
end
|
|
42
38
|
end
|
|
43
|
-
|
|
44
39
|
end
|
|
45
|
-
|
|
46
40
|
end
|
|
47
41
|
end
|
data/lib/httpi/request.rb
CHANGED
|
@@ -4,20 +4,18 @@ require "httpi/auth/config"
|
|
|
4
4
|
require "rack/utils"
|
|
5
5
|
|
|
6
6
|
module HTTPI
|
|
7
|
-
|
|
8
7
|
# = HTTPI::Request
|
|
9
8
|
#
|
|
10
9
|
# Represents an HTTP request and contains various methods for customizing that request.
|
|
11
10
|
class Request
|
|
12
|
-
|
|
13
11
|
# Available attribute writers.
|
|
14
12
|
ATTRIBUTES = [:url, :proxy, :headers, :body, :open_timeout, :read_timeout, :write_timeout, :follow_redirect, :redirect_limit, :query]
|
|
15
13
|
|
|
16
14
|
# Accepts a Hash of +args+ to mass assign attributes and authentication credentials.
|
|
17
15
|
def initialize(args = {})
|
|
18
|
-
if args.
|
|
16
|
+
if args.is_a? String
|
|
19
17
|
self.url = args
|
|
20
|
-
elsif args.
|
|
18
|
+
elsif args.is_a?(Hash) && !args.empty?
|
|
21
19
|
mass_assign args
|
|
22
20
|
end
|
|
23
21
|
end
|
|
@@ -25,7 +23,7 @@ module HTTPI
|
|
|
25
23
|
# Sets the +url+ to access. Raises an +ArgumentError+ unless the +url+ is valid.
|
|
26
24
|
def url=(url)
|
|
27
25
|
@url = normalize_url! url
|
|
28
|
-
auth.basic @url.user, @url.password ||
|
|
26
|
+
auth.basic @url.user, @url.password || "" if @url.user
|
|
29
27
|
end
|
|
30
28
|
|
|
31
29
|
# Returns the +url+ to access.
|
|
@@ -33,17 +31,17 @@ module HTTPI
|
|
|
33
31
|
|
|
34
32
|
# Sets the +query+ from +url+. Raises an +ArgumentError+ unless the +url+ is valid.
|
|
35
33
|
def query=(query)
|
|
36
|
-
raise ArgumentError, "Invalid URL: #{
|
|
37
|
-
if query.
|
|
34
|
+
raise ArgumentError, "Invalid URL: #{url}" unless url.respond_to?(:query)
|
|
35
|
+
if query.is_a?(Hash)
|
|
38
36
|
query = build_query_from_hash(query)
|
|
39
37
|
end
|
|
40
38
|
query = query.to_s unless query.is_a?(String)
|
|
41
|
-
|
|
39
|
+
url.query = query
|
|
42
40
|
end
|
|
43
41
|
|
|
44
42
|
# Returns the +query+ from +url+.
|
|
45
43
|
def query
|
|
46
|
-
|
|
44
|
+
url.query if url.respond_to?(:query)
|
|
47
45
|
end
|
|
48
46
|
|
|
49
47
|
# Sets the +proxy+ to use. Raises an +ArgumentError+ unless the +proxy+ is valid.
|
|
@@ -95,14 +93,14 @@ module HTTPI
|
|
|
95
93
|
|
|
96
94
|
# Sets a body request given a String or a Hash.
|
|
97
95
|
def body=(params)
|
|
98
|
-
@body = params.
|
|
96
|
+
@body = params.is_a?(Hash) ? build_query_from_hash(params) : params
|
|
99
97
|
end
|
|
100
98
|
|
|
101
99
|
# Sets the block to be called while processing the response. The block
|
|
102
100
|
# accepts a single parameter - the chunked response body.
|
|
103
101
|
def on_body(&block)
|
|
104
102
|
@on_body ||= nil
|
|
105
|
-
if block_given?
|
|
103
|
+
if block_given?
|
|
106
104
|
@on_body = block
|
|
107
105
|
end
|
|
108
106
|
@on_body
|
|
@@ -146,14 +144,13 @@ module HTTPI
|
|
|
146
144
|
|
|
147
145
|
# Expects a +url+, validates its validity and returns a +URI+ object.
|
|
148
146
|
def normalize_url!(url)
|
|
149
|
-
raise ArgumentError, "Invalid URL: #{url}" unless
|
|
150
|
-
url.
|
|
147
|
+
raise ArgumentError, "Invalid URL: #{url}" unless /^http|socks/.match?(url.to_s)
|
|
148
|
+
url.is_a?(URI) ? url : URI(url)
|
|
151
149
|
end
|
|
152
150
|
|
|
153
151
|
# Returns a +query+ string given a +Hash+
|
|
154
152
|
def build_query_from_hash(query)
|
|
155
153
|
HTTPI.query_builder.build(query)
|
|
156
154
|
end
|
|
157
|
-
|
|
158
155
|
end
|
|
159
156
|
end
|
data/lib/httpi/response.rb
CHANGED
|
@@ -6,12 +6,10 @@ require "httpi/dime"
|
|
|
6
6
|
require "httpi/cookie"
|
|
7
7
|
|
|
8
8
|
module HTTPI
|
|
9
|
-
|
|
10
9
|
# = HTTPI::Response
|
|
11
10
|
#
|
|
12
11
|
# Represents an HTTP response and contains various response details.
|
|
13
12
|
class Response
|
|
14
|
-
|
|
15
13
|
# Range of HTTP response codes considered to be successful.
|
|
16
14
|
SuccessfulResponseCodes = 200..299
|
|
17
15
|
# HTTP response codes considered to be a redirect.
|
|
@@ -79,12 +77,12 @@ module HTTPI
|
|
|
79
77
|
|
|
80
78
|
# Returns the gzip decoded response body.
|
|
81
79
|
def decoded_gzip_body
|
|
82
|
-
unless gzip = Zlib::GzipReader.new(StringIO.new(raw_body))
|
|
80
|
+
unless (gzip = Zlib::GzipReader.new(StringIO.new(raw_body)))
|
|
83
81
|
raise ArgumentError, "Unable to create Zlib::GzipReader"
|
|
84
82
|
end
|
|
85
83
|
gzip.read
|
|
86
84
|
ensure
|
|
87
|
-
gzip
|
|
85
|
+
gzip&.close
|
|
88
86
|
end
|
|
89
87
|
|
|
90
88
|
# Returns the DIME decoded response body.
|
|
@@ -93,6 +91,5 @@ module HTTPI
|
|
|
93
91
|
self.attachments = dime.binary_records
|
|
94
92
|
dime.xml_records.first.data
|
|
95
93
|
end
|
|
96
|
-
|
|
97
94
|
end
|
|
98
95
|
end
|
data/lib/httpi/utils.rb
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# mostly verbatim from: https://github.com/rack/rack/blob/main/lib/rack/headers.rb
|
|
2
|
-
# Because this is part of httpi's public API, its better not to load an external
|
|
3
|
-
# library for it.
|
|
2
|
+
# Because this is part of httpi's public API, its better not to load an external
|
|
3
|
+
# library for it.
|
|
4
4
|
module HTTPI
|
|
5
5
|
module Utils
|
|
6
6
|
# A case-insensitive Hash that preserves the original case of a
|
|
@@ -9,9 +9,9 @@ module HTTPI
|
|
|
9
9
|
class Headers < Hash
|
|
10
10
|
def self.[](headers)
|
|
11
11
|
if headers.is_a?(Headers) && !headers.frozen?
|
|
12
|
-
|
|
12
|
+
headers
|
|
13
13
|
else
|
|
14
|
-
|
|
14
|
+
new(headers)
|
|
15
15
|
end
|
|
16
16
|
end
|
|
17
17
|
|
|
@@ -46,20 +46,19 @@ module HTTPI
|
|
|
46
46
|
end
|
|
47
47
|
|
|
48
48
|
def [](k)
|
|
49
|
-
super
|
|
49
|
+
super || super(@names[k.downcase])
|
|
50
50
|
end
|
|
51
51
|
|
|
52
52
|
def []=(k, v)
|
|
53
53
|
canonical = k.downcase.freeze
|
|
54
54
|
delete k if @names[canonical] && @names[canonical] != k # .delete is expensive, don't invoke it unless necessary
|
|
55
55
|
@names[canonical] = k
|
|
56
|
-
super
|
|
56
|
+
super
|
|
57
57
|
end
|
|
58
58
|
|
|
59
59
|
def delete(k)
|
|
60
60
|
canonical = k.downcase
|
|
61
|
-
|
|
62
|
-
result
|
|
61
|
+
super(@names.delete(canonical))
|
|
63
62
|
end
|
|
64
63
|
|
|
65
64
|
def include?(k)
|
|
@@ -87,9 +86,8 @@ module HTTPI
|
|
|
87
86
|
end
|
|
88
87
|
|
|
89
88
|
protected
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
end
|
|
89
|
+
|
|
90
|
+
attr_reader :names
|
|
93
91
|
end
|
|
94
92
|
end
|
|
95
93
|
end
|
data/lib/httpi/version.rb
CHANGED
data/lib/httpi.rb
CHANGED
|
@@ -81,7 +81,6 @@ require "httpi/adapter/http"
|
|
|
81
81
|
# http.follow_redirect_count = 3 # HTTPClient example
|
|
82
82
|
# end
|
|
83
83
|
module HTTPI
|
|
84
|
-
|
|
85
84
|
REQUEST_METHODS = [:get, :post, :head, :put, :delete]
|
|
86
85
|
|
|
87
86
|
DEFAULT_LOG_LEVEL = :debug
|
|
@@ -102,7 +101,6 @@ module HTTPI
|
|
|
102
101
|
end
|
|
103
102
|
|
|
104
103
|
class << self
|
|
105
|
-
|
|
106
104
|
def query_builder
|
|
107
105
|
@query_builder ||= HTTPI::QueryBuilder::Flat
|
|
108
106
|
end
|
|
@@ -124,7 +122,7 @@ module HTTPI
|
|
|
124
122
|
|
|
125
123
|
# Executes an HTTP GET request.
|
|
126
124
|
def get(request, adapter = nil, &block)
|
|
127
|
-
request = Request.new(request) if request.
|
|
125
|
+
request = Request.new(request) if request.is_a? String
|
|
128
126
|
request(:get, request, adapter, &block)
|
|
129
127
|
end
|
|
130
128
|
|
|
@@ -136,7 +134,7 @@ module HTTPI
|
|
|
136
134
|
|
|
137
135
|
# Executes an HTTP HEAD request.
|
|
138
136
|
def head(request, adapter = nil, &block)
|
|
139
|
-
request = Request.new(request) if request.
|
|
137
|
+
request = Request.new(request) if request.is_a? String
|
|
140
138
|
request(:head, request, adapter, &block)
|
|
141
139
|
end
|
|
142
140
|
|
|
@@ -148,22 +146,22 @@ module HTTPI
|
|
|
148
146
|
|
|
149
147
|
# Executes an HTTP DELETE request.
|
|
150
148
|
def delete(request, adapter = nil, &block)
|
|
151
|
-
request = Request.new(request) if request.
|
|
149
|
+
request = Request.new(request) if request.is_a? String
|
|
152
150
|
request(:delete, request, adapter, &block)
|
|
153
151
|
end
|
|
154
152
|
|
|
155
153
|
# Executes an HTTP request for the given +method+.
|
|
156
154
|
def request(method, request, adapter = nil, redirects = 0)
|
|
157
155
|
adapter_class = load_adapter(adapter, request)
|
|
158
|
-
|
|
159
|
-
Adapter.client_setup_block
|
|
156
|
+
|
|
157
|
+
Adapter.client_setup_block&.call(adapter_class.client)
|
|
160
158
|
yield adapter_class.client if block_given?
|
|
161
159
|
log_request(method, request, Adapter.identify(adapter_class.class))
|
|
162
160
|
|
|
163
161
|
response = adapter_class.request(method)
|
|
164
162
|
|
|
165
163
|
if response && HTTPI::Response::RedirectResponseCodes.member?(response.code) && request.follow_redirect? && redirects < request.redirect_limit
|
|
166
|
-
request.url = URI.join(request.url, response.headers[
|
|
164
|
+
request.url = URI.join(request.url, response.headers["location"])
|
|
167
165
|
log("Following redirect: '#{request.url}'.")
|
|
168
166
|
return request(method, request, adapter, redirects + 1)
|
|
169
167
|
end
|
|
@@ -183,13 +181,12 @@ module HTTPI
|
|
|
183
181
|
private
|
|
184
182
|
|
|
185
183
|
def request_and_adapter_from(args)
|
|
186
|
-
return args if args[0].
|
|
187
|
-
[Request.new(:
|
|
184
|
+
return args if args[0].is_a? Request
|
|
185
|
+
[Request.new(url: args[0], body: args[1]), args[2]]
|
|
188
186
|
end
|
|
189
187
|
|
|
190
188
|
def load_adapter(adapter, request)
|
|
191
189
|
Adapter.load(adapter).new(request)
|
|
192
190
|
end
|
|
193
|
-
|
|
194
191
|
end
|
|
195
192
|
end
|