simple-http 0.1.5 → 0.2.2
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 +5 -5
- data/lib/simple/http.rb +78 -128
- data/lib/simple/http/body_builder.rb +71 -0
- data/lib/simple/http/caching.rb +46 -0
- data/lib/simple/http/driver/default.rb +81 -0
- data/lib/simple/http/errors.rb +19 -11
- data/lib/simple/http/headers.rb +34 -0
- data/lib/simple/http/request.rb +12 -0
- data/lib/simple/http/response.rb +63 -0
- data/lib/simple/http/version.rb +22 -1
- data/test/assertions_test.rb +2 -2
- data/test/basic_auth_test.rb +8 -8
- data/test/echo_test.rb +67 -0
- data/test/fixtures/httpd/basic-auth.rb +7 -0
- data/test/fixtures/httpd/echo.rb +54 -0
- data/test/fixtures/httpd/root.rb +20 -0
- data/test/redirection_test.rb +12 -4
- data/test/simple_https_test.rb +14 -0
- data/test/test_helper.rb +39 -3
- metadata +14 -8
- data/lib/simple/http/assertions.rb +0 -16
- data/lib/simple/http/expires_in.rb +0 -34
- data/lib/simple/http/result.rb +0 -41
- data/test/simple_http_test.rb +0 -17
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: c92784b07cf1f548d0c40078b19609308a45788bbc550a42305c1bf26c6e32a0
|
4
|
+
data.tar.gz: e9c7ad66790380696674c6a6566581e87eef1735b2f7dd6656918908600df04c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: eb4bbedf1338cc0c657e3e1c7ac38d3e243656d5128c25d2f8252eaa8bd5a228e50bc17cf967eac469a5f15db873899dcee187962effe812a15ff05dca007bf0
|
7
|
+
data.tar.gz: ce18010f695ae2be693552cfc41ed001490d47490ecd1be6fc22fa6d6847cc19506c007e3741ef1a8522590529f090247479d8e802aa5e30389d78f229d44898
|
data/lib/simple/http.rb
CHANGED
@@ -10,197 +10,147 @@ module Simple; end
|
|
10
10
|
class Simple::HTTP; end
|
11
11
|
|
12
12
|
require_relative "http/version"
|
13
|
-
require_relative "http/
|
14
|
-
require_relative "http/expires_in"
|
13
|
+
require_relative "http/caching"
|
15
14
|
require_relative "http/errors"
|
15
|
+
require_relative "http/headers"
|
16
|
+
require_relative "http/request"
|
17
|
+
require_relative "http/response"
|
18
|
+
|
19
|
+
require "openssl"
|
16
20
|
|
17
21
|
#
|
18
|
-
# A very simple, Net::HTTP-based HTTP client.
|
22
|
+
# A very simple, Net::HTTP-based HTTP client.
|
19
23
|
#
|
20
24
|
# Has some support for transferring JSON data: all data in PUT and POST
|
21
25
|
# requests are jsonized, and all data in responses are parsed as JSON if
|
22
26
|
# the Content-Type header is set to "application/json".
|
23
27
|
class Simple::HTTP
|
24
|
-
|
25
28
|
#
|
26
29
|
# The logger instance.
|
27
|
-
|
30
|
+
attr_accessor :logger
|
28
31
|
|
29
32
|
#
|
30
|
-
# The base URL
|
31
|
-
# https: are done relative to this base URL.
|
32
|
-
|
33
|
-
|
33
|
+
# The base URL when set, all requests that do not start with http: or
|
34
|
+
# https: are done relative to this base URL.
|
35
|
+
attr_accessor :base_url
|
36
|
+
|
34
37
|
#
|
35
|
-
# When set (default), redirections are followed. Note: When
|
38
|
+
# When set (default), redirections are followed. Note: When
|
36
39
|
# follows_redirections is not set, a HTTP redirection would raise an
|
37
40
|
# error - which is probably only useful when testing an interface.
|
38
|
-
|
41
|
+
attr_accessor :follows_redirections
|
39
42
|
|
40
43
|
#
|
41
44
|
# When set, appends this to all request URLs
|
42
|
-
|
45
|
+
attr_accessor :default_params
|
43
46
|
|
44
47
|
#
|
45
48
|
# When set, sets Authorization headers to all requests. Must be an
|
46
49
|
# array [ username, password ].
|
47
|
-
|
50
|
+
attr_accessor :basic_auth
|
48
51
|
|
49
52
|
def initialize
|
50
53
|
self.follows_redirections = true
|
51
|
-
self.logger = Logger.new(STDERR)
|
52
|
-
self.logger.level = Logger::WARN
|
54
|
+
self.logger = Logger.new(STDERR, level: :warn)
|
53
55
|
end
|
54
56
|
|
55
|
-
def
|
56
|
-
|
57
|
-
|
58
|
-
def delete(url, headers = {}); http :DELETE, url, nil, headers; end
|
57
|
+
def head(url, headers = {})
|
58
|
+
request :HEAD, url, nil, headers
|
59
|
+
end
|
59
60
|
|
60
|
-
|
61
|
-
|
61
|
+
def get(url, headers = {})
|
62
|
+
request :GET, url, nil, headers
|
63
|
+
end
|
62
64
|
|
63
|
-
|
64
|
-
|
65
|
-
|
65
|
+
def post(url, body = nil, headers = {})
|
66
|
+
request :POST, url, body, headers
|
67
|
+
end
|
66
68
|
|
67
|
-
|
68
|
-
|
69
|
-
# on response headers. Override as needed.
|
70
|
-
def expires_in(response)
|
71
|
-
response.expires_in
|
69
|
+
def put(url, body = nil, headers = {})
|
70
|
+
request :PUT, url, body, headers
|
72
71
|
end
|
73
72
|
|
74
|
-
|
73
|
+
def delete(url, headers = {})
|
74
|
+
request :DELETE, url, nil, headers
|
75
|
+
end
|
76
|
+
|
77
|
+
#
|
78
|
+
# -- Caching ----------------------------------------------------------------
|
79
|
+
|
80
|
+
# When set, and a response is cacheable (as it returns a valid expires_in
|
81
|
+
# value), the cache object is used to cache responses.
|
82
|
+
attr_accessor :cache
|
75
83
|
|
76
84
|
# -- HTTP request -----------------------------------------------------------
|
77
85
|
|
78
|
-
def
|
86
|
+
def request(verb, url, body, headers)
|
79
87
|
#
|
80
88
|
# normalize url; i.e. prepend base_url if the url itself is incomplete.
|
81
89
|
unless url =~ /^(http|https):/
|
82
|
-
url = File.join(base_url, url)
|
90
|
+
url = File.join(base_url, url)
|
83
91
|
end
|
84
|
-
|
92
|
+
|
93
|
+
uri = URI.parse(url)
|
94
|
+
unless uri.is_a?(URI::HTTP)
|
95
|
+
raise ArgumentError, "Invalid URL: #{url}"
|
96
|
+
end
|
97
|
+
|
85
98
|
# append default_params, if set
|
86
99
|
if default_params
|
87
100
|
url.concat(url.include?("?") ? "&" : "?")
|
88
101
|
url.concat default_params
|
89
102
|
end
|
90
103
|
|
91
|
-
|
92
|
-
|
104
|
+
request = Request.new(verb: verb, url: url, body: body, headers: headers)
|
105
|
+
|
106
|
+
execute_request(request)
|
93
107
|
end
|
94
108
|
|
95
|
-
|
96
|
-
# do a HTTP request, return its response or, when not successful,
|
97
|
-
# raise an error.
|
98
|
-
def http_(method, url, body, headers, max_redirections = 10)
|
99
|
-
if method == :GET && cache && result = cache.read(url)
|
100
|
-
logger.debug "#{method} #{url}: using cached result"
|
101
|
-
return result
|
102
|
-
end
|
109
|
+
private
|
103
110
|
|
104
|
-
|
105
|
-
|
106
|
-
raise ArgumentError, "Invalid URL: #{url}"
|
107
|
-
end
|
111
|
+
def execute_request(request, max_redirections: 10)
|
112
|
+
response = execute_request_w_caching(request)
|
108
113
|
|
109
|
-
|
110
|
-
|
111
|
-
http.use_ssl = true
|
112
|
-
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
113
|
-
end
|
114
|
+
return response unless response.status >= 300 && response.status <= 399
|
115
|
+
return response unless follows_redirections
|
114
116
|
|
115
|
-
|
116
|
-
# build request
|
117
|
-
request = build_request method, uri, body, headers
|
117
|
+
raise ::Simple::HTTP::TooManyRedirections, response if max_redirections <= 0
|
118
118
|
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
response = http.request(request)
|
123
|
-
logger.info "#{method} #{url}: #{response.body.bytesize} byte, #{"%.3f secs" % (Time.now - started_at)}"
|
119
|
+
request = ::Simple::HTTP::Request.new(verb: :GET, url: response.headers["Location"], headers: {})
|
120
|
+
execute_request(request, max_redirections: max_redirections - 1)
|
121
|
+
end
|
124
122
|
|
125
|
-
|
126
|
-
|
127
|
-
# attribute set, but sometimes not. We make sure that the uri is set
|
128
|
-
# everytime.
|
129
|
-
response.uri = uri
|
123
|
+
def execute_request_w_caching(request)
|
124
|
+
is_cacheable = request.verb == :GET && cache
|
130
125
|
|
131
|
-
|
132
|
-
|
133
|
-
if response.is_a?(Net::HTTPSuccess)
|
134
|
-
result = response.result
|
135
|
-
if cache && method == :GET && expires_in = self.expires_in(response)
|
136
|
-
if response.expires_in == expires_in
|
137
|
-
logger.debug "#{method} #{url}: store in cache, w/expiration of #{expires_in}"
|
138
|
-
else
|
139
|
-
logger.debug "#{method} #{url}: store in cache, w/custom expiration of #{expires_in} (instead #{response.expires_in.inspect})"
|
140
|
-
end
|
141
|
-
cache.write(url, result, expires_in: expires_in)
|
142
|
-
end
|
143
|
-
|
144
|
-
return result
|
126
|
+
if is_cacheable && (cached = Caching.fetch(request))
|
127
|
+
return cached
|
145
128
|
end
|
146
129
|
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
end
|
153
|
-
|
154
|
-
target_url = response["Location"]
|
155
|
-
unless target_url =~ /^(http|https):\/\//
|
156
|
-
base_url = "#{uri.scheme}://#{uri.host}"
|
157
|
-
File.join base_url, target_url
|
158
|
-
end
|
159
|
-
|
160
|
-
return http_(:GET, target_url, nil, {}, max_redirections - 1)
|
130
|
+
response = execute_request_w_logging(request)
|
131
|
+
|
132
|
+
expires_in = Caching.determine_expires_in(response)
|
133
|
+
if is_cacheable && expires_in
|
134
|
+
Caching.store(request, response, expires_in: expires_in)
|
161
135
|
end
|
162
136
|
|
163
|
-
|
164
|
-
# raise an error in any other case.
|
165
|
-
raise Error.new(method, request, response)
|
137
|
+
response
|
166
138
|
end
|
167
139
|
|
168
|
-
|
140
|
+
def execute_request_w_logging(request)
|
141
|
+
started_at = Time.now
|
169
142
|
|
170
|
-
|
171
|
-
:GET => Net::HTTP::Get,
|
172
|
-
:POST => Net::HTTP::Post,
|
173
|
-
:PUT => Net::HTTP::Put,
|
174
|
-
:DELETE => Net::HTTP::Delete
|
175
|
-
}.freeze #:nodoc:
|
143
|
+
response = driver.execute_request(request, client: self)
|
176
144
|
|
177
|
-
|
178
|
-
|
179
|
-
def build_request(method, uri, body, headers)
|
180
|
-
klass = REQUEST_CLASSES.fetch(method)
|
181
|
-
request = klass.new(uri.request_uri)
|
182
|
-
|
183
|
-
if uri.user
|
184
|
-
request.basic_auth(uri.user, uri.password)
|
185
|
-
elsif basic_auth
|
186
|
-
request.basic_auth(*basic_auth)
|
145
|
+
logger.info do
|
146
|
+
"#{request}: #{response}, #{"%.3f secs" % (Time.now - started_at)}"
|
187
147
|
end
|
188
148
|
|
189
|
-
|
190
|
-
|
191
|
-
# # TODO: set headers
|
192
|
-
# # set_request_headers request, headers
|
193
|
-
# end
|
194
|
-
|
195
|
-
# set request body
|
196
|
-
if request.request_body_permitted? && body
|
197
|
-
request.content_type = "application/json"
|
198
|
-
if body.is_a?(Hash) || body.is_a?(Array)
|
199
|
-
body = JSON.generate(body)
|
200
|
-
end
|
201
|
-
request.body = body
|
202
|
-
end
|
149
|
+
response
|
150
|
+
end
|
203
151
|
|
204
|
-
|
152
|
+
def driver
|
153
|
+
require "simple/http/driver/default"
|
154
|
+
::Simple::HTTP::Driver::Default
|
205
155
|
end
|
206
156
|
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# This module originally was taken from rack/media_type.rb and modified:
|
2
|
+
# we don't want to have a rack (which is a server toolset) dependency
|
3
|
+
# in simple-http, which is a client after all.
|
4
|
+
|
5
|
+
# parses content_type to return media_type and charset, and can reencode bodies.
|
6
|
+
class Simple::HTTP::BodyBuilder
|
7
|
+
SPLIT_PATTERN = %r{\s*[;,]\s*}
|
8
|
+
|
9
|
+
def initialize(content_type)
|
10
|
+
@media_type = content_type.split(SPLIT_PATTERN, 2).first.downcase if content_type
|
11
|
+
@charset = fetch_content_type_param(content_type, "charset", default: nil)
|
12
|
+
end
|
13
|
+
|
14
|
+
# The media type (type/subtype) portion of the CONTENT_TYPE header
|
15
|
+
# without any media type parameters. e.g., when CONTENT_TYPE is
|
16
|
+
# "text/plain;charset=utf-8", the media-type is "text/plain".
|
17
|
+
#
|
18
|
+
# For more information on the use of media types in HTTP, see:
|
19
|
+
# http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.7
|
20
|
+
attr_reader :media_type
|
21
|
+
|
22
|
+
# The charset as embedded on the Content-Type header
|
23
|
+
attr_reader :charset
|
24
|
+
|
25
|
+
# returns the body
|
26
|
+
#
|
27
|
+
# This method reencodes the text body into UTF-8. Non-text bodies should be
|
28
|
+
# encoded as ASCII-8BIT (a.k.a. "BINARY")
|
29
|
+
def reencode(body)
|
30
|
+
body&.encode(best_encoding)
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
BINARY = ::Encoding.find "ASCII-8BIT"
|
36
|
+
UTF8 = ::Encoding.find "UTF-8"
|
37
|
+
|
38
|
+
# returns the encoding we want for the body.
|
39
|
+
#
|
40
|
+
# This method makes sure to reencode text bodies into UTF-8, and non-text
|
41
|
+
# bodies as ASCII-8BIT (a.k.a. "BINARY")
|
42
|
+
def best_encoding
|
43
|
+
case media_type
|
44
|
+
when /^application\/json/, /^application\/xml/, /^text\// then UTF8
|
45
|
+
else BINARY
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# The media type parameters provided in CONTENT_TYPE as a Hash, or
|
50
|
+
# an empty Hash if no CONTENT_TYPE or media-type parameters were
|
51
|
+
# provided. e.g., when the CONTENT_TYPE is "text/plain;charset=utf-8",
|
52
|
+
# this method responds with the following Hash:
|
53
|
+
# { 'charset' => 'utf-8' }
|
54
|
+
def fetch_content_type_param(content_type, parameter_name, default:)
|
55
|
+
return default if content_type.nil?
|
56
|
+
|
57
|
+
parameter_name = parameter_name.downcase
|
58
|
+
|
59
|
+
content_type.split(SPLIT_PATTERN)[1..-1]
|
60
|
+
.each do |s|
|
61
|
+
k, v = s.split("=", 2)
|
62
|
+
return strip_doublequotes(v) if k.downcase == parameter_name
|
63
|
+
end
|
64
|
+
|
65
|
+
default
|
66
|
+
end
|
67
|
+
|
68
|
+
def strip_doublequotes(str)
|
69
|
+
str[0] == '"' && str[-1] == '"' ? str[1..-2] : str
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# This file is part of the simple-http ruby gem.
|
2
|
+
#
|
3
|
+
# Copyright (c) 2011 - 2015 @radiospiel
|
4
|
+
# Distributed under the terms of the modified BSD license, see LICENSE.BSD
|
5
|
+
|
6
|
+
module Simple::HTTP::Caching
|
7
|
+
extend self
|
8
|
+
|
9
|
+
#
|
10
|
+
# returns expiration information, in seconds from now.
|
11
|
+
def determine_expires_in(response)
|
12
|
+
return nil unless cacheable_status?(response.status)
|
13
|
+
|
14
|
+
expires_in = parse_cache_control response
|
15
|
+
expires_in ||= parse_expires response
|
16
|
+
|
17
|
+
return expires_in if expires_in && expires_in > 0
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def cacheable_status?(status)
|
23
|
+
(status >= 200 && status <= 299) || (status >= 400 && status <= 499)
|
24
|
+
end
|
25
|
+
|
26
|
+
# Returns the expiration setting from the "Cache-Control"'s max-age entry
|
27
|
+
def parse_cache_control(response)
|
28
|
+
cache_control = response.headers["Cache-Control"]
|
29
|
+
return unless cache_control
|
30
|
+
|
31
|
+
cache_control.split(/,\s+/).each do |part|
|
32
|
+
next unless part =~ /max-age=(\d+)/
|
33
|
+
|
34
|
+
return Integer($1)
|
35
|
+
end
|
36
|
+
nil
|
37
|
+
end
|
38
|
+
|
39
|
+
# Returns the expiration setting from the "Expires" header
|
40
|
+
def parse_expires(response)
|
41
|
+
expires = response.headers["Expires"]
|
42
|
+
return unless expires
|
43
|
+
|
44
|
+
Time.parse(expires) - Time.now
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
2
|
+
|
3
|
+
module Simple::HTTP::Driver
|
4
|
+
end
|
5
|
+
|
6
|
+
module Simple::HTTP::Driver::Default
|
7
|
+
extend self
|
8
|
+
|
9
|
+
#
|
10
|
+
# do a HTTP request, return its response or, when not successful,
|
11
|
+
# raise an error.
|
12
|
+
def execute_request(request, client:)
|
13
|
+
verb, url, body, headers =
|
14
|
+
request.verb, request.url, request.body, request.headers
|
15
|
+
|
16
|
+
uri = URI.parse(url)
|
17
|
+
|
18
|
+
# build Net::HTTP request
|
19
|
+
request = build_request verb, uri, body, headers, client: client
|
20
|
+
|
21
|
+
# execute request
|
22
|
+
net_http = load_net_http(uri.scheme, uri.host, uri.port)
|
23
|
+
resp = net_http.request(request)
|
24
|
+
|
25
|
+
::Simple::HTTP::Response.new request: request,
|
26
|
+
status: Integer(resp.code),
|
27
|
+
message: resp.message,
|
28
|
+
headers: Simple::HTTP::Headers.new(resp),
|
29
|
+
body: resp.body
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
# rubocop:disable Style/HashSyntax, Layout/AlignHash
|
35
|
+
REQUEST_CLASSES = {
|
36
|
+
:HEAD => Net::HTTP::Head,
|
37
|
+
:GET => Net::HTTP::Get,
|
38
|
+
:POST => Net::HTTP::Post,
|
39
|
+
:PUT => Net::HTTP::Put,
|
40
|
+
:DELETE => Net::HTTP::Delete
|
41
|
+
}.freeze #:nodoc:
|
42
|
+
|
43
|
+
#
|
44
|
+
# build a HTTP request object.
|
45
|
+
def build_request(method, uri, body, _headers, client:)
|
46
|
+
klass = REQUEST_CLASSES.fetch(method)
|
47
|
+
request = klass.new(uri.request_uri)
|
48
|
+
|
49
|
+
if uri.user
|
50
|
+
request.basic_auth(uri.user, uri.password)
|
51
|
+
elsif client.basic_auth
|
52
|
+
request.basic_auth(*client.basic_auth)
|
53
|
+
end
|
54
|
+
|
55
|
+
# set request headers
|
56
|
+
# unless headers && !headers.empty?
|
57
|
+
# # TODO: set headers
|
58
|
+
# # set_request_headers request, headers
|
59
|
+
# end
|
60
|
+
|
61
|
+
# set request body
|
62
|
+
if request.request_body_permitted? && body
|
63
|
+
request.content_type = "application/json"
|
64
|
+
if body.is_a?(Hash) || body.is_a?(Array)
|
65
|
+
body = JSON.generate(body)
|
66
|
+
end
|
67
|
+
request.body = body
|
68
|
+
end
|
69
|
+
|
70
|
+
request
|
71
|
+
end
|
72
|
+
|
73
|
+
def load_net_http(scheme, host, port)
|
74
|
+
net_http = Net::HTTP.new(host, port)
|
75
|
+
if scheme == "https"
|
76
|
+
net_http.use_ssl = true
|
77
|
+
net_http.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
78
|
+
end
|
79
|
+
net_http
|
80
|
+
end
|
81
|
+
end
|
data/lib/simple/http/errors.rb
CHANGED
@@ -7,27 +7,35 @@ module Simple; end
|
|
7
7
|
class Simple::HTTP; end
|
8
8
|
|
9
9
|
class Simple::HTTP::Error < RuntimeError
|
10
|
-
|
10
|
+
attr_reader :response
|
11
11
|
|
12
|
-
def initialize(
|
13
|
-
@
|
12
|
+
def initialize(response)
|
13
|
+
@response = response
|
14
14
|
end
|
15
15
|
|
16
|
-
def
|
17
|
-
response.
|
16
|
+
def status
|
17
|
+
response.status
|
18
|
+
end
|
19
|
+
|
20
|
+
def request
|
21
|
+
@response.request
|
22
|
+
end
|
23
|
+
|
24
|
+
def verb
|
25
|
+
request.class::METHOD
|
18
26
|
end
|
19
27
|
|
20
28
|
def message
|
21
|
-
|
22
|
-
if response.is_a?(Net::HTTPRedirection)
|
23
|
-
message += " To #{response["Location"]}"
|
24
|
-
end
|
25
|
-
message
|
29
|
+
"#{verb} #{request.uri} ##{status} #{response.message}"
|
26
30
|
end
|
27
31
|
end
|
28
32
|
|
29
33
|
class Simple::HTTP::TooManyRedirections < Simple::HTTP::Error
|
34
|
+
def location
|
35
|
+
response["Location"]
|
36
|
+
end
|
37
|
+
|
30
38
|
def message
|
31
|
-
"
|
39
|
+
"#{super}: too many redirections (latest to #{location})"
|
32
40
|
end
|
33
41
|
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
class Simple::HTTP::Headers < Hash
|
2
|
+
def initialize(headers)
|
3
|
+
case headers
|
4
|
+
when Net::HTTPHeader
|
5
|
+
headers.each_name.map do |name|
|
6
|
+
values = headers.get_fields(name)
|
7
|
+
self[name] = values.length == 1 ? values.first : values
|
8
|
+
end
|
9
|
+
else
|
10
|
+
headers.each do |name, value|
|
11
|
+
self[name] = value
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def [](key)
|
17
|
+
super key.downcase
|
18
|
+
end
|
19
|
+
|
20
|
+
def value(key)
|
21
|
+
values(key)&.first
|
22
|
+
end
|
23
|
+
|
24
|
+
def values(key)
|
25
|
+
v = self[key]
|
26
|
+
Array(v) if v
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def []=(key, value)
|
32
|
+
super key.downcase, value
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
class Simple::HTTP::Request
|
2
|
+
attr_reader :verb, :url, :body, :headers
|
3
|
+
|
4
|
+
def initialize(verb:, url:, body: nil, headers:)
|
5
|
+
@verb, @url, @body, @headers = verb, url, body, headers
|
6
|
+
end
|
7
|
+
|
8
|
+
def to_s
|
9
|
+
scrubbed_url = url.gsub(/\/\/(.*):(.*)@/) { |_| "//#{$1}:xxxxxx@" }
|
10
|
+
"#{verb} #{scrubbed_url}"
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require_relative "./body_builder"
|
2
|
+
|
3
|
+
class Simple::HTTP::Response
|
4
|
+
BodyBuilder = Simple::HTTP::BodyBuilder
|
5
|
+
|
6
|
+
attr_reader :request
|
7
|
+
attr_reader :status
|
8
|
+
attr_reader :message
|
9
|
+
attr_reader :headers
|
10
|
+
attr_reader :original_body
|
11
|
+
|
12
|
+
def initialize(request:, body:, headers:, status:, message:)
|
13
|
+
@request, @headers = request, headers
|
14
|
+
@status, @message = status, message
|
15
|
+
@original_body = body
|
16
|
+
|
17
|
+
# adjust encoding on original_body
|
18
|
+
@body_builder = BodyBuilder.new(headers["Content-Type"])
|
19
|
+
|
20
|
+
if @original_body && (charset = @body_builder.charset)
|
21
|
+
@original_body.force_encoding(charset)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# e.g "text/plain"
|
26
|
+
def media_type
|
27
|
+
@body_builder.media_type
|
28
|
+
end
|
29
|
+
|
30
|
+
# returns the body
|
31
|
+
#
|
32
|
+
# This method reencodes the text body into UTF-8. Non-text bodies should be
|
33
|
+
# encoded as ASCII-8BIT (a.k.a. "BINARY")
|
34
|
+
def body
|
35
|
+
@body ||= @body_builder.reencode(@original_body)
|
36
|
+
end
|
37
|
+
|
38
|
+
def bytes
|
39
|
+
@original_body&.byte_size || 0
|
40
|
+
end
|
41
|
+
|
42
|
+
def to_s
|
43
|
+
"#{status} #{message.gsub(/\s+$/, "")} (#{bytes} byte)"
|
44
|
+
end
|
45
|
+
|
46
|
+
# evaluate and potentially parses response body.
|
47
|
+
# raises an Simple::Http::Error if the result code is not a 2xx
|
48
|
+
def content!
|
49
|
+
raise Error, self unless status >= 200 && status <= 299
|
50
|
+
|
51
|
+
content
|
52
|
+
end
|
53
|
+
|
54
|
+
# evaluate and potentially parse response
|
55
|
+
def content
|
56
|
+
case media_type
|
57
|
+
when "application/json"
|
58
|
+
JSON.parse(body) unless body.empty?
|
59
|
+
else
|
60
|
+
body
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
data/lib/simple/http/version.rb
CHANGED
@@ -5,5 +5,26 @@
|
|
5
5
|
|
6
6
|
module Simple; end
|
7
7
|
class Simple::HTTP
|
8
|
-
|
8
|
+
|
9
|
+
module GemHelper
|
10
|
+
extend self
|
11
|
+
|
12
|
+
def version(name)
|
13
|
+
spec = Gem.loaded_specs[name]
|
14
|
+
version = spec ? spec.version.to_s : "0.0.0"
|
15
|
+
# version += "+unreleased" if !spec || unreleased?(spec)
|
16
|
+
version
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def unreleased?(spec)
|
22
|
+
return false unless defined?(Bundler::Source::Gemspec)
|
23
|
+
return true if spec.source.is_a?(::Bundler::Source::Gemspec)
|
24
|
+
return true if spec.source.is_a?(::Bundler::Source::Path)
|
25
|
+
false
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
VERSION = GemHelper.version "simple-http"
|
9
30
|
end
|
data/test/assertions_test.rb
CHANGED
@@ -7,14 +7,14 @@ require_relative 'test_helper'
|
|
7
7
|
class SimpleHttpTest < Simple::HTTP::TestCase
|
8
8
|
def test_assert_http_error
|
9
9
|
assert_http_error(456) do
|
10
|
-
http.get "
|
10
|
+
http.get "/status/456"
|
11
11
|
end
|
12
12
|
end
|
13
13
|
|
14
14
|
def test_assert_http_redirects_to
|
15
15
|
http.follows_redirections = false
|
16
16
|
assert_http_redirects_to "http://eu.httpbin.org" do
|
17
|
-
http.get "
|
17
|
+
http.get "/redirect-to?url=http://eu.httpbin.org"
|
18
18
|
end
|
19
19
|
end
|
20
20
|
end
|
data/test/basic_auth_test.rb
CHANGED
@@ -6,35 +6,35 @@ require_relative 'test_helper'
|
|
6
6
|
|
7
7
|
class SimpleHttpTest < Simple::HTTP::TestCase
|
8
8
|
def test_basic_auth
|
9
|
-
http.basic_auth = [ "
|
10
|
-
http.get "
|
9
|
+
http.basic_auth = [ "admin", "secret" ]
|
10
|
+
http.get "/basic-auth/user/passwd"
|
11
11
|
end
|
12
12
|
|
13
13
|
def test_basic_auth_invalid
|
14
14
|
http.basic_auth = [ "wronguser", "passwd" ]
|
15
15
|
assert_http_error 401 do
|
16
|
-
http.get "
|
16
|
+
http.get "/basic-auth/user/passwd"
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
20
20
|
def test_basic_auth_missing
|
21
21
|
http.basic_auth = [ "wronguser", "passwd" ]
|
22
22
|
assert_http_error 401 do
|
23
|
-
http.get "
|
23
|
+
http.get "/basic-auth/user/passwd"
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
27
27
|
def test_url_auth
|
28
|
-
http.get "http://
|
28
|
+
http.get "http://admin:secret@#{HOST}:#{PORT}/basic-auth/user/passwd"
|
29
29
|
end
|
30
30
|
|
31
31
|
def test_url_auth_overrides_basic_auth
|
32
32
|
http.basic_auth = [ "wronguser", "passwd" ]
|
33
|
-
http.get "http://
|
33
|
+
http.get "http://admin:secret@#{HOST}:#{PORT}/basic-auth/user/passwd"
|
34
34
|
|
35
|
-
http.basic_auth = [ "
|
35
|
+
http.basic_auth = [ "admin", "secret" ]
|
36
36
|
assert_http_error 401 do
|
37
|
-
http.get "http://
|
37
|
+
http.get "http://wrongadmin:secret@#{HOST}:#{PORT}/basic-auth/user/passwd"
|
38
38
|
end
|
39
39
|
end
|
40
40
|
end
|
data/test/echo_test.rb
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
# Author:: radiospiel (mailto:eno@radiospiel.org)
|
2
|
+
# Copyright:: Copyright (c) 2011-2015 radiospiel
|
3
|
+
# License:: Distributes under the terms of the Modified BSD License, see LICENSE.BSD for details.
|
4
|
+
|
5
|
+
require_relative 'test_helper'
|
6
|
+
|
7
|
+
class EchoTest < Simple::HTTP::TestCase
|
8
|
+
def test_get
|
9
|
+
response = http.get "/echo?a=1&b=2"
|
10
|
+
expected = <<~MSG
|
11
|
+
GET
|
12
|
+
a: 1
|
13
|
+
b: 2
|
14
|
+
MSG
|
15
|
+
|
16
|
+
assert_equal(expected, response.content)
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_head
|
20
|
+
response = http.head "/echo?a=1&b=2"
|
21
|
+
assert_equal(nil, response.content)
|
22
|
+
assert_equal(200, response.status)
|
23
|
+
end
|
24
|
+
|
25
|
+
def body_example
|
26
|
+
{
|
27
|
+
foo: "bar"
|
28
|
+
}
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_post
|
32
|
+
response = http.post "/echo?a=1&b=2", body_example
|
33
|
+
expected = <<~MSG
|
34
|
+
POST
|
35
|
+
a: 1
|
36
|
+
b: 2
|
37
|
+
CONTENT_TYPE: application/json
|
38
|
+
{"foo":"bar"}
|
39
|
+
MSG
|
40
|
+
|
41
|
+
assert_equal(expected, response.content)
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_put
|
45
|
+
response = http.put "/echo?a=1&b=2", body_example
|
46
|
+
expected = <<~MSG
|
47
|
+
PUT
|
48
|
+
a: 1
|
49
|
+
b: 2
|
50
|
+
CONTENT_TYPE: application/json
|
51
|
+
{"foo":"bar"}
|
52
|
+
MSG
|
53
|
+
|
54
|
+
assert_equal(expected, response.content)
|
55
|
+
end
|
56
|
+
|
57
|
+
def test_delete
|
58
|
+
response = http.delete "/echo?a=1&b=2"
|
59
|
+
expected = <<~MSG
|
60
|
+
DELETE
|
61
|
+
a: 1
|
62
|
+
b: 2
|
63
|
+
MSG
|
64
|
+
|
65
|
+
assert_equal(expected, response.content)
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
helpers do
|
2
|
+
def debug_params
|
3
|
+
params.map { |k, v| "#{k}: #{v}" }.sort.join("\n")
|
4
|
+
end
|
5
|
+
|
6
|
+
def interesting_header(name)
|
7
|
+
return true if name == "CONTENT_TYPE"
|
8
|
+
return true if name =~ /X_/
|
9
|
+
false
|
10
|
+
end
|
11
|
+
|
12
|
+
def debug_headers
|
13
|
+
headers = request.each_header.select { |header, _| interesting_header(header) }
|
14
|
+
return if headers.empty?
|
15
|
+
headers.map { |k, v| "#{k}: #{v}" }.sort.join("\n")
|
16
|
+
end
|
17
|
+
|
18
|
+
def debug_body
|
19
|
+
verb = request.request_method
|
20
|
+
return unless verb == "POST" || verb == "PUT"
|
21
|
+
|
22
|
+
request.body.rewind
|
23
|
+
request.body.read
|
24
|
+
end
|
25
|
+
|
26
|
+
def debug
|
27
|
+
[
|
28
|
+
request.request_method,
|
29
|
+
debug_params,
|
30
|
+
debug_headers,
|
31
|
+
debug_body
|
32
|
+
].compact.map { |s| "#{s}\n" }.join("")
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
get "/" do
|
37
|
+
debug
|
38
|
+
end
|
39
|
+
|
40
|
+
head "/" do
|
41
|
+
debug
|
42
|
+
end
|
43
|
+
|
44
|
+
post "/" do
|
45
|
+
debug
|
46
|
+
end
|
47
|
+
|
48
|
+
put "/" do
|
49
|
+
debug
|
50
|
+
end
|
51
|
+
|
52
|
+
delete "/" do
|
53
|
+
debug
|
54
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
get "/" do
|
2
|
+
end
|
3
|
+
|
4
|
+
get "/status/:status" do
|
5
|
+
status params[:status]
|
6
|
+
"No content"
|
7
|
+
end
|
8
|
+
|
9
|
+
get "/redirect-to" do
|
10
|
+
redirect params[:url]
|
11
|
+
end
|
12
|
+
|
13
|
+
get "/redirect-to-self" do
|
14
|
+
redirect "/redirect-to-self"
|
15
|
+
end
|
16
|
+
|
17
|
+
get "/redirection-target" do
|
18
|
+
content_type :html
|
19
|
+
"I am the redirection target"
|
20
|
+
end
|
data/test/redirection_test.rb
CHANGED
@@ -5,14 +5,22 @@
|
|
5
5
|
require_relative 'test_helper'
|
6
6
|
|
7
7
|
class RedirectionTest < Simple::HTTP::TestCase
|
8
|
+
def test_limits_redirections
|
9
|
+
assert_raise(Simple::HTTP::TooManyRedirections) {
|
10
|
+
http.get "/redirect-to-self"
|
11
|
+
}
|
12
|
+
end
|
13
|
+
|
8
14
|
def test_follows_redirections
|
9
|
-
|
10
|
-
assert_match(/
|
15
|
+
response = http.get "/redirect-to?url=http://#{HOST}:#{PORT}/redirection-target"
|
16
|
+
assert_match(/I am the redirection target/, response.content)
|
11
17
|
end
|
12
18
|
|
13
|
-
|
19
|
+
# We have a hard time to convince the test application to redirect
|
20
|
+
# to an invalid location.. we therefore skip this test.
|
21
|
+
def skipped_test_raises_error_on_invalid_redirect_location
|
14
22
|
assert_raise(ArgumentError) {
|
15
|
-
http.get "
|
23
|
+
http.get "/redirect-to?url=foo"
|
16
24
|
}
|
17
25
|
end
|
18
26
|
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# Author:: radiospiel (mailto:eno@radiospiel.org)
|
2
|
+
# Copyright:: Copyright (c) 2011-2015 radiospiel
|
3
|
+
# License:: Distributes under the terms of the Modified BSD License, see LICENSE.BSD for details.
|
4
|
+
|
5
|
+
ENV['SSL_CERT_FILE'] = '/usr/local/etc/openssl/certs/cert.pem'
|
6
|
+
|
7
|
+
require_relative 'test_helper'
|
8
|
+
|
9
|
+
class SimpleHttpsTest < Simple::HTTP::TestCase
|
10
|
+
def skipped_test_https
|
11
|
+
response = http.get "https://google.com"
|
12
|
+
assert_match(/doctype/, response)
|
13
|
+
end
|
14
|
+
end
|
data/test/test_helper.rb
CHANGED
@@ -1,22 +1,58 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'bundler/setup'
|
3
3
|
|
4
|
-
#
|
4
|
+
# -- setup a test server serving ./test/fixtures/httpd ------------------------
|
5
|
+
#
|
6
|
+
# This server uses simple-httpd to serve some static and dynamic test content.
|
7
|
+
# Note: for purity reasons this should be reimplemented via a rack middleware.
|
8
|
+
#
|
9
|
+
$: << "../rspec-httpd/lib"
|
10
|
+
require "rspec/httpd/server"
|
11
|
+
|
5
12
|
require 'test/unit'
|
6
13
|
|
14
|
+
# require 'simplecov'
|
15
|
+
#
|
7
16
|
# SimpleCov.start do
|
8
17
|
# add_filter "test/*.rb"
|
9
18
|
# end
|
10
19
|
|
11
20
|
require 'simple/http'
|
12
|
-
require 'simple/http/assertions'
|
13
21
|
|
14
22
|
class Simple::HTTP::TestCase < Test::Unit::TestCase
|
15
|
-
|
23
|
+
HOST = "0.0.0.0"
|
24
|
+
PORT = 12345
|
16
25
|
|
17
26
|
attr :http
|
18
27
|
|
28
|
+
# start a test server. Note that this starts the server only once, and
|
29
|
+
# automatically cleans up the server when this process finishes.
|
30
|
+
def start_server!
|
31
|
+
httpd_root = "#{__dir__}/fixtures/httpd"
|
32
|
+
|
33
|
+
# The command to start the server must reset the BUNDLE_GEMFILE environment
|
34
|
+
# setting.
|
35
|
+
command = "cd ../simple-httpd/ && BUNDLE_GEMFILE= PORT=12345 bin/simple-httpd #{httpd_root} -q"
|
36
|
+
command = "#{command} 2> log/simple-httpd.log"
|
37
|
+
|
38
|
+
::RSpec::Httpd::Server.start! port: PORT, command: command
|
39
|
+
end
|
40
|
+
|
19
41
|
def setup
|
42
|
+
start_server!
|
43
|
+
|
20
44
|
@http = Simple::HTTP.new
|
45
|
+
@http.base_url = "http://#{HOST}:#{PORT}"
|
46
|
+
end
|
47
|
+
|
48
|
+
def assert_http_error(expected_status, &block)
|
49
|
+
response = yield
|
50
|
+
assert_equal(expected_status, response.status)
|
51
|
+
end
|
52
|
+
|
53
|
+
def assert_http_redirects_to(expected_location, &block)
|
54
|
+
response = yield
|
55
|
+
assert_includes([301, 302], response.status)
|
56
|
+
assert_equal(expected_location, response.headers["Location"])
|
21
57
|
end
|
22
58
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: simple-http
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- radiospiel
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2019-11-16 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: Simple code for simple HTTP requests
|
14
14
|
email: eno@radiospiel.org
|
@@ -18,15 +18,22 @@ extra_rdoc_files: []
|
|
18
18
|
files:
|
19
19
|
- README.md
|
20
20
|
- lib/simple/http.rb
|
21
|
-
- lib/simple/http/
|
21
|
+
- lib/simple/http/body_builder.rb
|
22
|
+
- lib/simple/http/caching.rb
|
23
|
+
- lib/simple/http/driver/default.rb
|
22
24
|
- lib/simple/http/errors.rb
|
23
|
-
- lib/simple/http/
|
24
|
-
- lib/simple/http/
|
25
|
+
- lib/simple/http/headers.rb
|
26
|
+
- lib/simple/http/request.rb
|
27
|
+
- lib/simple/http/response.rb
|
25
28
|
- lib/simple/http/version.rb
|
26
29
|
- test/assertions_test.rb
|
27
30
|
- test/basic_auth_test.rb
|
31
|
+
- test/echo_test.rb
|
32
|
+
- test/fixtures/httpd/basic-auth.rb
|
33
|
+
- test/fixtures/httpd/echo.rb
|
34
|
+
- test/fixtures/httpd/root.rb
|
28
35
|
- test/redirection_test.rb
|
29
|
-
- test/
|
36
|
+
- test/simple_https_test.rb
|
30
37
|
- test/test_helper.rb
|
31
38
|
homepage: http://github.com/radiospiel/simple-http
|
32
39
|
licenses: []
|
@@ -46,8 +53,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
46
53
|
- !ruby/object:Gem::Version
|
47
54
|
version: '0'
|
48
55
|
requirements: []
|
49
|
-
|
50
|
-
rubygems_version: 2.5.1
|
56
|
+
rubygems_version: 3.0.4
|
51
57
|
signing_key:
|
52
58
|
specification_version: 4
|
53
59
|
summary: Simple code for simple HTTP requests
|
@@ -1,16 +0,0 @@
|
|
1
|
-
# Author:: radiospiel (mailto:eno@radiospiel.org)
|
2
|
-
# Copyright:: Copyright (c) 2011-2015 radiospiel
|
3
|
-
# License:: Distributes under the terms of the Modified BSD License, see LICENSE.BSD for details.
|
4
|
-
|
5
|
-
module Simple::HTTP::Assertions
|
6
|
-
def assert_http_error(expected_status, &block)
|
7
|
-
http_error = assert_raises(Simple::HTTP::Error, &block)
|
8
|
-
assert_equal(expected_status, http_error.code)
|
9
|
-
end
|
10
|
-
|
11
|
-
def assert_http_redirects_to(expected_location, &block)
|
12
|
-
http_error = assert_raises(Simple::HTTP::Error, &block)
|
13
|
-
assert_includes([301, 302], http_error.code)
|
14
|
-
assert_equal(expected_location, http_error.response["Location"])
|
15
|
-
end
|
16
|
-
end
|
@@ -1,34 +0,0 @@
|
|
1
|
-
# This file is part of the simple-http ruby gem.
|
2
|
-
#
|
3
|
-
# Copyright (c) 2011 - 2015 @radiospiel
|
4
|
-
# Distributed under the terms of the modified BSD license, see LICENSE.BSD
|
5
|
-
|
6
|
-
require "net/http"
|
7
|
-
|
8
|
-
class Net::HTTPResponse
|
9
|
-
private
|
10
|
-
|
11
|
-
#
|
12
|
-
# The "max-age" value, in seconds, from the Cache-Control header.
|
13
|
-
def max_age
|
14
|
-
return unless cache_control = header["Cache-Control"]
|
15
|
-
cache_control.split(/, /).each do |part|
|
16
|
-
next unless part =~ /max-age=(\d+)/
|
17
|
-
return Integer($1)
|
18
|
-
end
|
19
|
-
nil
|
20
|
-
end
|
21
|
-
|
22
|
-
public
|
23
|
-
|
24
|
-
#
|
25
|
-
# returns expiration information, in seconds from now.
|
26
|
-
def expires_in
|
27
|
-
expires_in = max_age
|
28
|
-
if !expires_in && expires = header["Expires"]
|
29
|
-
expires_in = Time.parse(expires) - Time.now
|
30
|
-
end
|
31
|
-
|
32
|
-
return expires_in if expires_in && expires_in > 0
|
33
|
-
end
|
34
|
-
end
|
data/lib/simple/http/result.rb
DELETED
@@ -1,41 +0,0 @@
|
|
1
|
-
# This file is part of the simple-http ruby gem.
|
2
|
-
#
|
3
|
-
# Copyright (c) 2011 - 2015 @radiospiel
|
4
|
-
# Distributed under the terms of the modified BSD license, see LICENSE.BSD
|
5
|
-
|
6
|
-
require "net/http"
|
7
|
-
|
8
|
-
class Net::HTTPResponse
|
9
|
-
#
|
10
|
-
# evaluate and potentially parse response
|
11
|
-
def result
|
12
|
-
case response.content_type
|
13
|
-
when "application/json"
|
14
|
-
JSON.parse(body) unless body.empty?
|
15
|
-
else
|
16
|
-
body_string
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
private
|
21
|
-
|
22
|
-
#
|
23
|
-
# returns a body. The resulting string is encoded in ASCII-8BIT, if the
|
24
|
-
# content type is binary, and encoded in UTF8 otherwise.
|
25
|
-
def body_string
|
26
|
-
default_encoding = content_is_binary? ? "ASCII-8BIT" : "UTF-8"
|
27
|
-
|
28
|
-
body = self.body
|
29
|
-
if charset = type_params["charset"]
|
30
|
-
body = body.force_encoding(charset)
|
31
|
-
end
|
32
|
-
body.encode(default_encoding)
|
33
|
-
end
|
34
|
-
|
35
|
-
def content_is_binary?
|
36
|
-
case content_type
|
37
|
-
when /^image/ then true
|
38
|
-
else false
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
data/test/simple_http_test.rb
DELETED
@@ -1,17 +0,0 @@
|
|
1
|
-
# Author:: radiospiel (mailto:eno@radiospiel.org)
|
2
|
-
# Copyright:: Copyright (c) 2011-2015 radiospiel
|
3
|
-
# License:: Distributes under the terms of the Modified BSD License, see LICENSE.BSD for details.
|
4
|
-
|
5
|
-
require_relative 'test_helper'
|
6
|
-
|
7
|
-
class SimpleHttpTest < Simple::HTTP::TestCase
|
8
|
-
def test_http_google
|
9
|
-
google = http.get "http://google.com"
|
10
|
-
assert_match(/doctype/, google)
|
11
|
-
end
|
12
|
-
|
13
|
-
def test_https_google
|
14
|
-
google = http.get "https://google.com"
|
15
|
-
assert_match(/doctype/, google)
|
16
|
-
end
|
17
|
-
end
|