simple-http 0.1.5 → 0.2.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|