webmachine 1.6.0 → 2.0.0.beta
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -0
- data/README.md +2 -5
- data/documentation/adapters.md +2 -11
- data/examples/debugger.rb +5 -3
- data/examples/logging.rb +2 -2
- data/examples/webrick.rb +2 -2
- data/lib/webmachine/adapter.rb +0 -3
- data/lib/webmachine/adapters/lazy_request_body.rb +1 -1
- data/lib/webmachine/adapters/rack.rb +38 -34
- data/lib/webmachine/adapters/rack_mapped.rb +1 -2
- data/lib/webmachine/adapters/webrick.rb +11 -12
- data/lib/webmachine/adapters.rb +0 -2
- data/lib/webmachine/application.rb +2 -2
- data/lib/webmachine/chunked_body.rb +1 -1
- data/lib/webmachine/configuration.rb +1 -1
- data/lib/webmachine/constants.rb +12 -12
- data/lib/webmachine/cookie.rb +20 -18
- data/lib/webmachine/decision/conneg.rb +24 -24
- data/lib/webmachine/decision/falsey.rb +0 -1
- data/lib/webmachine/decision/flow.rb +19 -20
- data/lib/webmachine/decision/fsm.rb +4 -4
- data/lib/webmachine/decision/helpers.rb +21 -21
- data/lib/webmachine/dispatcher/route.rb +28 -28
- data/lib/webmachine/dispatcher.rb +3 -2
- data/lib/webmachine/errors.rb +7 -8
- data/lib/webmachine/etags.rb +2 -1
- data/lib/webmachine/header_negotiation.rb +5 -6
- data/lib/webmachine/headers.rb +5 -5
- data/lib/webmachine/media_type.rb +5 -5
- data/lib/webmachine/quoted_string.rb +3 -3
- data/lib/webmachine/request.rb +7 -10
- data/lib/webmachine/rescueable_exception.rb +3 -3
- data/lib/webmachine/resource/authentication.rb +3 -4
- data/lib/webmachine/resource/callbacks.rb +3 -3
- data/lib/webmachine/resource/encodings.rb +3 -9
- data/lib/webmachine/resource.rb +1 -1
- data/lib/webmachine/response.rb +7 -9
- data/lib/webmachine/spec/adapter_lint.rb +67 -69
- data/lib/webmachine/spec/test_resource.rb +22 -22
- data/lib/webmachine/streaming/encoder.rb +3 -2
- data/lib/webmachine/streaming/io_encoder.rb +4 -3
- data/lib/webmachine/trace/fsm.rb +25 -18
- data/lib/webmachine/trace/resource_proxy.rb +10 -9
- data/lib/webmachine/trace/static/http-headers-status-v3.png +0 -0
- data/lib/webmachine/trace/trace_resource.rb +22 -24
- data/lib/webmachine/trace.rb +7 -6
- data/lib/webmachine/translation.rb +3 -3
- data/lib/webmachine/version.rb +1 -1
- metadata +52 -86
- data/.gitignore +0 -31
- data/Gemfile +0 -46
- data/Guardfile +0 -11
- data/RELEASING.md +0 -21
- data/Rakefile +0 -44
- data/lib/webmachine/adapters/httpkit.rb +0 -74
- data/lib/webmachine/adapters/reel.rb +0 -113
- data/memory_test.rb +0 -37
- data/spec/spec_helper.rb +0 -56
- data/spec/webmachine/adapter_spec.rb +0 -39
- data/spec/webmachine/adapters/httpkit_spec.rb +0 -10
- data/spec/webmachine/adapters/rack_mapped_spec.rb +0 -71
- data/spec/webmachine/adapters/rack_spec.rb +0 -62
- data/spec/webmachine/adapters/reel_spec.rb +0 -76
- data/spec/webmachine/adapters/webrick_spec.rb +0 -12
- data/spec/webmachine/application_spec.rb +0 -74
- data/spec/webmachine/chunked_body_spec.rb +0 -30
- data/spec/webmachine/configuration_spec.rb +0 -27
- data/spec/webmachine/cookie_spec.rb +0 -99
- data/spec/webmachine/decision/conneg_spec.rb +0 -166
- data/spec/webmachine/decision/falsey_spec.rb +0 -8
- data/spec/webmachine/decision/flow_spec.rb +0 -1148
- data/spec/webmachine/decision/fsm_spec.rb +0 -163
- data/spec/webmachine/decision/helpers_spec.rb +0 -216
- data/spec/webmachine/dispatcher/rfc3986_percent_decode_spec.rb +0 -22
- data/spec/webmachine/dispatcher/route_spec.rb +0 -248
- data/spec/webmachine/dispatcher_spec.rb +0 -104
- data/spec/webmachine/errors_spec.rb +0 -13
- data/spec/webmachine/etags_spec.rb +0 -75
- data/spec/webmachine/events_spec.rb +0 -58
- data/spec/webmachine/headers_spec.rb +0 -99
- data/spec/webmachine/media_type_spec.rb +0 -85
- data/spec/webmachine/request_spec.rb +0 -273
- data/spec/webmachine/rescueable_exception_spec.rb +0 -15
- data/spec/webmachine/resource/authentication_spec.rb +0 -68
- data/spec/webmachine/response_spec.rb +0 -51
- data/spec/webmachine/trace/fsm_spec.rb +0 -37
- data/spec/webmachine/trace/resource_proxy_spec.rb +0 -34
- data/spec/webmachine/trace/trace_store_spec.rb +0 -29
- data/spec/webmachine/trace_spec.rb +0 -17
- data/webmachine.gemspec +0 -25
@@ -23,11 +23,11 @@ module Webmachine
|
|
23
23
|
obj
|
24
24
|
when MEDIA_TYPE_REGEX
|
25
25
|
type, raw_params = $1, $2
|
26
|
-
params =
|
26
|
+
params = raw_params.scan(PARAMS_REGEX).map { |m| [m[0], m[2].to_s] }.to_h
|
27
27
|
new(type, params)
|
28
28
|
else
|
29
29
|
unless Array === obj && String === obj[0] && Hash === obj[1]
|
30
|
-
raise ArgumentError, t('invalid_media_type', :
|
30
|
+
raise ArgumentError, t('invalid_media_type', type: obj.inspect)
|
31
31
|
end
|
32
32
|
type = parse(obj[0])
|
33
33
|
type.params.merge!(obj[1])
|
@@ -43,7 +43,7 @@ module Webmachine
|
|
43
43
|
|
44
44
|
# @param [String] type the main media type, e.g. application/json
|
45
45
|
# @param [Hash] params the media type parameters
|
46
|
-
def initialize(type, params={})
|
46
|
+
def initialize(type, params = {})
|
47
47
|
@type, @params = type, params
|
48
48
|
end
|
49
49
|
|
@@ -88,13 +88,13 @@ module Webmachine
|
|
88
88
|
# @param [Hash] params the requested params
|
89
89
|
# @return [true,false] whether it is an acceptable match
|
90
90
|
def params_match?(other)
|
91
|
-
other.all? {|k,v| params[k] == v }
|
91
|
+
other.all? { |k, v| params[k] == v }
|
92
92
|
end
|
93
93
|
|
94
94
|
# Reconstitutes the type into a String
|
95
95
|
# @return [String] the type as a String
|
96
96
|
def to_s
|
97
|
-
[type, *params.map {|k,v| "#{k}=#{v}" }].join(
|
97
|
+
[type, *params.map { |k, v| "#{k}=#{v}" }].join(';')
|
98
98
|
end
|
99
99
|
|
100
100
|
# @return [String] The major type, e.g. "application", "text", "image"
|
@@ -19,10 +19,10 @@ module Webmachine
|
|
19
19
|
|
20
20
|
# Ensures that quotes exist around a quoted-string
|
21
21
|
def quote(str)
|
22
|
-
if str
|
22
|
+
if QS_ANCHORED.match?(str)
|
23
23
|
str
|
24
24
|
else
|
25
|
-
%
|
25
|
+
%("#{escape_quotes str}")
|
26
26
|
end
|
27
27
|
end
|
28
28
|
|
@@ -33,7 +33,7 @@ module Webmachine
|
|
33
33
|
|
34
34
|
# Unescapes quotes within a quoted string
|
35
35
|
def unescape_quotes(str)
|
36
|
-
str.
|
36
|
+
str.delete('\\')
|
37
37
|
end
|
38
38
|
end
|
39
39
|
end
|
data/lib/webmachine/request.rb
CHANGED
@@ -21,7 +21,7 @@ module Webmachine
|
|
21
21
|
# @param [Headers] headers the HTTP request headers
|
22
22
|
# @param [String,#to_s,#each,nil] body the entity included in the
|
23
23
|
# request, if present
|
24
|
-
def initialize(method, uri, headers, body, routing_tokens=nil, base_uri=nil)
|
24
|
+
def initialize(method, uri, headers, body, routing_tokens = nil, base_uri = nil)
|
25
25
|
@method, @headers, @body = method, headers, body
|
26
26
|
@uri = build_uri(uri, headers)
|
27
27
|
@routing_tokens = routing_tokens || @uri.path.match(ROUTING_PATH_MATCH)[1].split(SLASH)
|
@@ -37,12 +37,12 @@ module Webmachine
|
|
37
37
|
# lowercased-underscored version of the header name, e.g.
|
38
38
|
# `if_unmodified_since`.
|
39
39
|
def method_missing(m, *args, &block)
|
40
|
-
if m
|
40
|
+
if HTTP_HEADERS_MATCH.match?(m)
|
41
41
|
# Access headers more easily as underscored methods.
|
42
42
|
header_name = m.to_s.tr(UNDERSCORE, DASH)
|
43
43
|
if (header_value = @headers[header_name])
|
44
44
|
# Make future lookups faster.
|
45
|
-
self.class.class_eval <<-RUBY, __FILE__, __LINE__
|
45
|
+
self.class.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
46
46
|
def #{m}
|
47
47
|
@headers["#{header_name}"]
|
48
48
|
end
|
@@ -66,8 +66,8 @@ module Webmachine
|
|
66
66
|
def query
|
67
67
|
unless @query
|
68
68
|
@query = {}
|
69
|
-
(uri.query || '').split(
|
70
|
-
key, value = kv.split(
|
69
|
+
(uri.query || '').split('&').each do |kv|
|
70
|
+
key, value = kv.split('=')
|
71
71
|
if key && value
|
72
72
|
key, value = CGI.unescape(key), CGI.unescape(value)
|
73
73
|
@query[key] = value
|
@@ -82,9 +82,7 @@ module Webmachine
|
|
82
82
|
# @return [Hash]
|
83
83
|
# {} if no Cookies header set
|
84
84
|
def cookies
|
85
|
-
|
86
|
-
@cookies = Webmachine::Cookie.parse(headers['Cookie'])
|
87
|
-
end
|
85
|
+
@cookies ||= Webmachine::Cookie.parse(headers['Cookie'])
|
88
86
|
@cookies
|
89
87
|
end
|
90
88
|
|
@@ -93,7 +91,7 @@ module Webmachine
|
|
93
91
|
# @return [Boolean]
|
94
92
|
# true if this request was made via HTTPS
|
95
93
|
def https?
|
96
|
-
uri.scheme ==
|
94
|
+
uri.scheme == 'https'
|
97
95
|
end
|
98
96
|
|
99
97
|
# Is this a GET request?
|
@@ -191,6 +189,5 @@ module Webmachine
|
|
191
189
|
|
192
190
|
parse_host(uri, headers.fetch(HOST))
|
193
191
|
end
|
194
|
-
|
195
192
|
end # class Request
|
196
193
|
end # module Webmachine
|
@@ -2,7 +2,7 @@ module Webmachine::RescuableException
|
|
2
2
|
require_relative 'errors'
|
3
3
|
require 'set'
|
4
4
|
|
5
|
-
UNRESCUABLE_DEFAULTS =
|
5
|
+
UNRESCUABLE_DEFAULTS = [
|
6
6
|
Webmachine::MalformedRequest,
|
7
7
|
NoMemoryError, SystemExit, SignalException
|
8
8
|
].freeze
|
@@ -45,7 +45,7 @@ module Webmachine::RescuableException
|
|
45
45
|
# @param (see #remove)
|
46
46
|
#
|
47
47
|
def self.add(*exceptions)
|
48
|
-
exceptions.each{|e| UNRESCUABLE.delete(e)}
|
48
|
+
exceptions.each { |e| UNRESCUABLE.delete(e) }
|
49
49
|
end
|
50
50
|
|
51
51
|
#
|
@@ -57,6 +57,6 @@ module Webmachine::RescuableException
|
|
57
57
|
# A subclass of Exception.
|
58
58
|
#
|
59
59
|
def self.remove(*exceptions)
|
60
|
-
exceptions.each{|e| UNRESCUABLE.add(e)}
|
60
|
+
exceptions.each { |e| UNRESCUABLE.add(e) }
|
61
61
|
end
|
62
62
|
end
|
@@ -23,14 +23,13 @@ module Webmachine
|
|
23
23
|
# @yieldparam [String] user the passed username
|
24
24
|
# @yieldparam [String] password the passed password
|
25
25
|
# @yieldreturn [true,false] whether the username/password is correct
|
26
|
-
def basic_auth(header, realm=
|
27
|
-
if header =~ BASIC_HEADER && (
|
26
|
+
def basic_auth(header, realm = 'Webmachine')
|
27
|
+
if header =~ BASIC_HEADER && yield(*$1.unpack1('m*').split(/:/, 2))
|
28
28
|
true
|
29
29
|
else
|
30
|
-
%
|
30
|
+
%(Basic realm="#{realm}")
|
31
31
|
end
|
32
32
|
end
|
33
|
-
|
34
33
|
end # module Authentication
|
35
34
|
end # class Resource
|
36
35
|
end # module Webmachine
|
@@ -265,7 +265,7 @@ module Webmachine
|
|
265
265
|
# @api callback
|
266
266
|
# @see Encodings
|
267
267
|
def encodings_provided
|
268
|
-
{IDENTITY => :encode_identity
|
268
|
+
{IDENTITY => :encode_identity}
|
269
269
|
end
|
270
270
|
|
271
271
|
# If this method is implemented, it should return a list of
|
@@ -360,7 +360,8 @@ module Webmachine
|
|
360
360
|
# constructed and sent. The return value is ignored, so any effect
|
361
361
|
# of this method must be by modifying the response.
|
362
362
|
# @api callback
|
363
|
-
def finish_request
|
363
|
+
def finish_request
|
364
|
+
end
|
364
365
|
|
365
366
|
#
|
366
367
|
# This method is called when an error is raised within a subclass of
|
@@ -389,7 +390,6 @@ module Webmachine
|
|
389
390
|
def validate_content_checksum
|
390
391
|
nil
|
391
392
|
end
|
392
|
-
|
393
393
|
end # module Callbacks
|
394
394
|
end # class Resource
|
395
395
|
end # module Webmachine
|
@@ -15,23 +15,17 @@ module Webmachine
|
|
15
15
|
# The 'deflate' encoding, which uses libz's DEFLATE compression.
|
16
16
|
def encode_deflate(data)
|
17
17
|
# The deflate options were borrowed from Rack and Mongrel1.
|
18
|
-
Zlib::Deflate.deflate(data,
|
19
|
-
# drop the zlib header which causes both Safari and IE to choke
|
20
|
-
-Zlib::MAX_WBITS,
|
21
|
-
Zlib::DEF_MEM_LEVEL,
|
22
|
-
Zlib::DEFAULT_STRATEGY
|
23
|
-
])
|
18
|
+
Zlib::Deflate.deflate(data, Zlib::DEFAULT_COMPRESSION, -Zlib::MAX_WBITS, Zlib::DEF_MEM_LEVEL, Zlib::DEFAULT_STRATEGY)
|
24
19
|
end
|
25
20
|
|
26
21
|
# The 'gzip' encoding, which uses GNU Zip (via libz).
|
27
22
|
# @note Because of the header/checksum requirements, gzip cannot
|
28
23
|
# be used on streamed responses.
|
29
24
|
def encode_gzip(data)
|
30
|
-
|
31
|
-
Zlib::GzipWriter.wrap(StringIO.new(out)){|gz| gz << data }
|
25
|
+
''.tap do |out|
|
26
|
+
Zlib::GzipWriter.wrap(StringIO.new(out)) { |gz| gz << data }
|
32
27
|
end
|
33
28
|
end
|
34
|
-
|
35
29
|
end # module Encodings
|
36
30
|
end # class Resource
|
37
31
|
end # module Webmachine
|
data/lib/webmachine/resource.rb
CHANGED
@@ -59,11 +59,11 @@ module Webmachine
|
|
59
59
|
end
|
60
60
|
|
61
61
|
private
|
62
|
+
|
62
63
|
# When no specific charsets are provided, this acts as an identity
|
63
64
|
# on the response body. Probably deserves some refactoring.
|
64
65
|
def charset_nop(x)
|
65
66
|
x
|
66
67
|
end
|
67
|
-
|
68
68
|
end # class Resource
|
69
69
|
end # module Webmachine
|
data/lib/webmachine/response.rb
CHANGED
@@ -35,7 +35,7 @@ module Webmachine
|
|
35
35
|
# of the target resource, or manually set the Location header
|
36
36
|
# using {#headers}.
|
37
37
|
# @param [String, URI] location the target of the redirection
|
38
|
-
def do_redirect(location=nil)
|
38
|
+
def do_redirect(location = nil)
|
39
39
|
headers['Location'] = location.to_s if location
|
40
40
|
self.redirect = true
|
41
41
|
end
|
@@ -54,8 +54,8 @@ module Webmachine
|
|
54
54
|
end
|
55
55
|
end
|
56
56
|
|
57
|
-
|
58
|
-
|
57
|
+
alias_method :is_redirect?, :redirect
|
58
|
+
alias_method :redirect_to, :do_redirect
|
59
59
|
|
60
60
|
# A {Hash} that can flatten array values into single values with a separator
|
61
61
|
class HeaderHash < ::Hash
|
@@ -63,17 +63,15 @@ module Webmachine
|
|
63
63
|
# @param [String] The separator used to join Array values
|
64
64
|
# @return [HeaderHash] A new {HeaderHash} with Array values flattened
|
65
65
|
def flattened(separator = ',')
|
66
|
-
|
66
|
+
collect { |k, v|
|
67
67
|
case v
|
68
68
|
when Array
|
69
|
-
[k,v.join(separator)]
|
69
|
+
[k, v.join(separator)]
|
70
70
|
else
|
71
|
-
[k,v]
|
71
|
+
[k, v]
|
72
72
|
end
|
73
|
-
}
|
74
|
-
|
73
|
+
}.to_h
|
75
74
|
end
|
76
75
|
end
|
77
|
-
|
78
76
|
end # class Response
|
79
77
|
end # module Webmachine
|
@@ -1,7 +1,7 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require 'webmachine/spec/test_resource'
|
2
|
+
require 'net/http'
|
3
3
|
|
4
|
-
ADDRESS =
|
4
|
+
ADDRESS = '127.0.0.1'
|
5
5
|
|
6
6
|
shared_examples_for :adapter_lint do
|
7
7
|
attr_reader :client
|
@@ -12,7 +12,7 @@ shared_examples_for :adapter_lint do
|
|
12
12
|
temp_server = TCPServer.new(ADDRESS, 0)
|
13
13
|
port = temp_server.addr[1]
|
14
14
|
temp_server.close # only frees Ruby resource, socket is in TIME_WAIT at OS level
|
15
|
-
|
15
|
+
# so we can't have our adapter use it too quickly
|
16
16
|
|
17
17
|
sleep(0.1) # 'Wait' for temp_server to *really* close, not just TIME_WAIT
|
18
18
|
port
|
@@ -20,10 +20,10 @@ shared_examples_for :adapter_lint do
|
|
20
20
|
|
21
21
|
def create_test_application(port)
|
22
22
|
Webmachine::Application.new.tap do |application|
|
23
|
-
application.dispatcher.add_route [
|
23
|
+
application.dispatcher.add_route ['test'], Test::Resource
|
24
24
|
|
25
25
|
application.configure do |c|
|
26
|
-
c.ip
|
26
|
+
c.ip = ADDRESS
|
27
27
|
c.port = port
|
28
28
|
end
|
29
29
|
end
|
@@ -37,12 +37,10 @@ shared_examples_for :adapter_lint do
|
|
37
37
|
|
38
38
|
def wait_until_server_responds_to(client)
|
39
39
|
Timeout.timeout(5, TestApplicationNotResponsive) do
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
retry
|
45
|
-
end
|
40
|
+
client.start
|
41
|
+
rescue Errno::ECONNREFUSED
|
42
|
+
sleep(0.01)
|
43
|
+
retry
|
46
44
|
end
|
47
45
|
end
|
48
46
|
|
@@ -62,9 +60,9 @@ shared_examples_for :adapter_lint do
|
|
62
60
|
@server_thread.kill
|
63
61
|
end
|
64
62
|
|
65
|
-
it
|
66
|
-
request = Net::HTTP::Get.new(
|
67
|
-
request[
|
63
|
+
it 'provides the request URI' do
|
64
|
+
request = Net::HTTP::Get.new('/test')
|
65
|
+
request['Accept'] = 'test/response.request_uri'
|
68
66
|
response = client.request(request)
|
69
67
|
expect(response.body).to eq("http://#{ADDRESS}:#{@port}/test")
|
70
68
|
end
|
@@ -80,92 +78,92 @@ shared_examples_for :adapter_lint do
|
|
80
78
|
# end
|
81
79
|
# end
|
82
80
|
|
83
|
-
it
|
84
|
-
request = Net::HTTP::Put.new(
|
85
|
-
request.body =
|
86
|
-
request[
|
81
|
+
it 'provides a string-like request body' do
|
82
|
+
request = Net::HTTP::Put.new('/test')
|
83
|
+
request.body = 'Hello, World!'
|
84
|
+
request['Content-Type'] = 'test/request.stringbody'
|
87
85
|
response = client.request(request)
|
88
|
-
expect(response[
|
89
|
-
expect(response.body).to eq(
|
86
|
+
expect(response['Content-Length']).to eq('21')
|
87
|
+
expect(response.body).to eq('String: Hello, World!')
|
90
88
|
end
|
91
89
|
|
92
|
-
it
|
93
|
-
request = Net::HTTP::Put.new(
|
94
|
-
request.body =
|
95
|
-
request[
|
90
|
+
it 'provides an enumerable request body' do
|
91
|
+
request = Net::HTTP::Put.new('/test')
|
92
|
+
request.body = 'Hello, World!'
|
93
|
+
request['Content-Type'] = 'test/request.enumbody'
|
96
94
|
response = client.request(request)
|
97
|
-
expect(response[
|
98
|
-
expect(response.body).to eq(
|
95
|
+
expect(response['Content-Length']).to eq('19')
|
96
|
+
expect(response.body).to eq('Enum: Hello, World!')
|
99
97
|
end
|
100
98
|
|
101
|
-
it
|
102
|
-
request = Net::HTTP::Get.new(
|
99
|
+
it 'handles missing pages' do
|
100
|
+
request = Net::HTTP::Get.new('/missing')
|
103
101
|
response = client.request(request)
|
104
|
-
expect(response.code).to eq(
|
105
|
-
expect(response[
|
102
|
+
expect(response.code).to eq('404')
|
103
|
+
expect(response['Content-Type']).to eq('text/html')
|
106
104
|
end
|
107
105
|
|
108
|
-
it
|
109
|
-
request = Net::HTTP::Post.new(
|
110
|
-
request.body =
|
106
|
+
it 'handles empty response bodies' do
|
107
|
+
request = Net::HTTP::Post.new('/test')
|
108
|
+
request.body = ''
|
111
109
|
response = client.request(request)
|
112
|
-
expect(response.code).to eq(
|
113
|
-
expect([
|
110
|
+
expect(response.code).to eq('204')
|
111
|
+
expect(['0', nil]).to include(response['Content-Length'])
|
114
112
|
expect(response.body).to be_nil
|
115
113
|
end
|
116
114
|
|
117
|
-
it
|
118
|
-
request = Net::HTTP::Get.new(
|
119
|
-
request[
|
115
|
+
it 'handles string response bodies' do
|
116
|
+
request = Net::HTTP::Get.new('/test')
|
117
|
+
request['Accept'] = 'test/response.stringbody'
|
120
118
|
response = client.request(request)
|
121
|
-
expect(response[
|
122
|
-
expect(response.body).to eq(
|
119
|
+
expect(response['Content-Length']).to eq('20')
|
120
|
+
expect(response.body).to eq('String response body')
|
123
121
|
end
|
124
122
|
|
125
|
-
it
|
126
|
-
request = Net::HTTP::Get.new(
|
127
|
-
request[
|
123
|
+
it 'handles enumerable response bodies' do
|
124
|
+
request = Net::HTTP::Get.new('/test')
|
125
|
+
request['Accept'] = 'test/response.enumbody'
|
128
126
|
response = client.request(request)
|
129
|
-
expect(response[
|
130
|
-
expect(response.body).to eq(
|
127
|
+
expect(response['Transfer-Encoding']).to eq('chunked')
|
128
|
+
expect(response.body).to eq('Enumerable response body')
|
131
129
|
end
|
132
130
|
|
133
|
-
it
|
134
|
-
request = Net::HTTP::Get.new(
|
135
|
-
request[
|
131
|
+
it 'handles proc response bodies' do
|
132
|
+
request = Net::HTTP::Get.new('/test')
|
133
|
+
request['Accept'] = 'test/response.procbody'
|
136
134
|
response = client.request(request)
|
137
|
-
expect(response[
|
138
|
-
expect(response.body).to eq(
|
135
|
+
expect(response['Transfer-Encoding']).to eq('chunked')
|
136
|
+
expect(response.body).to eq('Proc response body')
|
139
137
|
end
|
140
138
|
|
141
|
-
it
|
142
|
-
request = Net::HTTP::Get.new(
|
143
|
-
request[
|
139
|
+
it 'handles fiber response bodies' do
|
140
|
+
request = Net::HTTP::Get.new('/test')
|
141
|
+
request['Accept'] = 'test/response.fiberbody'
|
144
142
|
response = client.request(request)
|
145
|
-
expect(response[
|
146
|
-
expect(response.body).to eq(
|
143
|
+
expect(response['Transfer-Encoding']).to eq('chunked')
|
144
|
+
expect(response.body).to eq('Fiber response body')
|
147
145
|
end
|
148
146
|
|
149
|
-
it
|
150
|
-
request = Net::HTTP::Get.new(
|
151
|
-
request[
|
147
|
+
it 'handles io response bodies' do
|
148
|
+
request = Net::HTTP::Get.new('/test')
|
149
|
+
request['Accept'] = 'test/response.iobody'
|
152
150
|
response = client.request(request)
|
153
|
-
expect(response[
|
151
|
+
expect(response['Content-Length']).to eq('17')
|
154
152
|
expect(response.body).to eq("IO response body\n")
|
155
153
|
end
|
156
154
|
|
157
|
-
it
|
158
|
-
request = Net::HTTP::Get.new(
|
159
|
-
request[
|
160
|
-
request[
|
155
|
+
it 'handles request cookies' do
|
156
|
+
request = Net::HTTP::Get.new('/test')
|
157
|
+
request['Accept'] = 'test/response.cookies'
|
158
|
+
request['Cookie'] = 'echo=echocookie'
|
161
159
|
response = client.request(request)
|
162
|
-
expect(response.body).to eq(
|
160
|
+
expect(response.body).to eq('echocookie')
|
163
161
|
end
|
164
162
|
|
165
|
-
it
|
166
|
-
request = Net::HTTP::Get.new(
|
167
|
-
request[
|
163
|
+
it 'handles response cookies' do
|
164
|
+
request = Net::HTTP::Get.new('/test')
|
165
|
+
request['Accept'] = 'test/response.cookies'
|
168
166
|
response = client.request(request)
|
169
|
-
expect(response[
|
167
|
+
expect(response['Set-Cookie']).to eq('cookie=monster, rodeo=clown')
|
170
168
|
end
|
171
169
|
end
|
@@ -1,35 +1,35 @@
|
|
1
1
|
module Test
|
2
2
|
class Resource < Webmachine::Resource
|
3
3
|
def allowed_methods
|
4
|
-
[
|
4
|
+
['GET', 'PUT', 'POST']
|
5
5
|
end
|
6
6
|
|
7
7
|
def content_types_accepted
|
8
8
|
[
|
9
|
-
[
|
10
|
-
[
|
9
|
+
['test/request.stringbody', :from_string],
|
10
|
+
['test/request.enumbody', :from_enum]
|
11
11
|
]
|
12
12
|
end
|
13
13
|
|
14
14
|
def content_types_provided
|
15
15
|
[
|
16
|
-
[
|
17
|
-
[
|
18
|
-
[
|
19
|
-
[
|
20
|
-
[
|
21
|
-
[
|
22
|
-
[
|
23
|
-
[
|
16
|
+
['test/response.stringbody', :to_string],
|
17
|
+
['test/response.enumbody', :to_enum],
|
18
|
+
['test/response.procbody', :to_proc],
|
19
|
+
['test/response.fiberbody', :to_fiber],
|
20
|
+
['test/response.iobody', :to_io_body],
|
21
|
+
['test/response.cookies', :to_cookies],
|
22
|
+
['test/response.request_uri', :to_request_uri],
|
23
|
+
['test/response.rack_env', :to_rack_env]
|
24
24
|
]
|
25
25
|
end
|
26
26
|
|
27
27
|
def from_string
|
28
|
-
response.body = "String: #{request.body
|
28
|
+
response.body = "String: #{request.body}"
|
29
29
|
end
|
30
30
|
|
31
31
|
def from_enum
|
32
|
-
response.body =
|
32
|
+
response.body = 'Enum: '
|
33
33
|
request.body.each do |part|
|
34
34
|
response.body += part
|
35
35
|
end
|
@@ -41,22 +41,22 @@ module Test
|
|
41
41
|
end
|
42
42
|
|
43
43
|
def to_string
|
44
|
-
|
44
|
+
'String response body'
|
45
45
|
end
|
46
46
|
|
47
47
|
def to_enum
|
48
|
-
[
|
48
|
+
['Enumerable ', 'response ', 'body']
|
49
49
|
end
|
50
50
|
|
51
51
|
def to_proc
|
52
|
-
|
52
|
+
proc { 'Proc response body' }
|
53
53
|
end
|
54
54
|
|
55
55
|
def to_fiber
|
56
56
|
Fiber.new do
|
57
|
-
Fiber.yield
|
58
|
-
Fiber.yield
|
59
|
-
|
57
|
+
Fiber.yield 'Fiber '
|
58
|
+
Fiber.yield 'response '
|
59
|
+
'body'
|
60
60
|
end
|
61
61
|
end
|
62
62
|
|
@@ -65,12 +65,12 @@ module Test
|
|
65
65
|
end
|
66
66
|
|
67
67
|
def to_cookies
|
68
|
-
response.set_cookie(
|
69
|
-
response.set_cookie(
|
68
|
+
response.set_cookie('cookie', 'monster')
|
69
|
+
response.set_cookie('rodeo', 'clown')
|
70
70
|
# FIXME: Mongrel/WEBrick fail if this method returns nil
|
71
71
|
# Might be a net/http issue. Is this a bug?
|
72
72
|
# @see Flow#o18, Helpers#encode_body_if_set
|
73
|
-
request.cookies[
|
73
|
+
request.cookies['echo'] || ''
|
74
74
|
end
|
75
75
|
|
76
76
|
def to_request_uri
|
@@ -12,12 +12,13 @@ module Webmachine
|
|
12
12
|
end
|
13
13
|
|
14
14
|
protected
|
15
|
+
|
15
16
|
# @return [true, false] whether the stream will be modified by
|
16
17
|
# the encoder and/or charsetter. Only returns true if using the
|
17
18
|
# built-in "encode_identity" and "charset_nop" methods.
|
18
19
|
def is_unencoded?
|
19
|
-
encoder.to_s ==
|
20
|
-
charsetter.to_s ==
|
20
|
+
encoder.to_s == 'encode_identity' &&
|
21
|
+
charsetter.to_s == 'charset_nop'
|
21
22
|
end
|
22
23
|
end # class Encoder
|
23
24
|
end # module Streaming
|
@@ -13,7 +13,7 @@ module Webmachine
|
|
13
13
|
# @yield [chunk]
|
14
14
|
# @yieldparam [String] chunk a chunk of the response, encoded
|
15
15
|
def each
|
16
|
-
while chunk = body.read(CHUNK_SIZE)
|
16
|
+
while (chunk = body.read(CHUNK_SIZE)) && (chunk != '')
|
17
17
|
yield resource.send(encoder, resource.send(charsetter, chunk))
|
18
18
|
end
|
19
19
|
end
|
@@ -26,7 +26,7 @@ module Webmachine
|
|
26
26
|
if can_copy_stream?
|
27
27
|
IO.copy_stream(body, outstream)
|
28
28
|
else
|
29
|
-
each {|chunk| outstream << chunk }
|
29
|
+
each { |chunk| outstream << chunk }
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
@@ -60,9 +60,10 @@ module Webmachine
|
|
60
60
|
size == 0
|
61
61
|
end
|
62
62
|
|
63
|
-
|
63
|
+
alias_method :bytesize, :size
|
64
64
|
|
65
65
|
private
|
66
|
+
|
66
67
|
def can_copy_stream?
|
67
68
|
IO.respond_to?(:copy_stream) && is_unencoded? && !is_string_io?
|
68
69
|
end
|