webmachine 1.2.2 → 1.3.0
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 +7 -0
- data/.gitignore +4 -0
- data/CHANGELOG.md +4 -0
- data/Gemfile +13 -11
- data/README.md +85 -89
- data/Rakefile +0 -1
- data/documentation/adapters.md +39 -0
- data/documentation/authentication-and-authorization.md +37 -0
- data/documentation/configurator.md +19 -0
- data/documentation/error-handling.md +86 -0
- data/documentation/examples.md +215 -0
- data/documentation/how-it-works.md +76 -0
- data/documentation/routes.md +97 -0
- data/documentation/validation.md +159 -0
- data/documentation/versioning-apis.md +74 -0
- data/documentation/visual-debugger.md +38 -0
- data/examples/application.rb +2 -2
- data/examples/debugger.rb +1 -1
- data/lib/webmachine.rb +3 -1
- data/lib/webmachine/adapter.rb +7 -13
- data/lib/webmachine/adapters.rb +1 -2
- data/lib/webmachine/adapters/httpkit.rb +74 -0
- data/lib/webmachine/adapters/lazy_request_body.rb +1 -2
- data/lib/webmachine/adapters/rack.rb +37 -21
- data/lib/webmachine/adapters/reel.rb +21 -23
- data/lib/webmachine/adapters/webrick.rb +16 -16
- data/lib/webmachine/application.rb +2 -2
- data/lib/webmachine/chunked_body.rb +3 -4
- data/lib/webmachine/constants.rb +75 -0
- data/lib/webmachine/decision/conneg.rb +12 -10
- data/lib/webmachine/decision/flow.rb +31 -21
- data/lib/webmachine/decision/fsm.rb +10 -18
- data/lib/webmachine/decision/helpers.rb +9 -37
- data/lib/webmachine/dispatcher.rb +13 -10
- data/lib/webmachine/dispatcher/route.rb +18 -8
- data/lib/webmachine/errors.rb +7 -1
- data/lib/webmachine/header_negotiation.rb +25 -0
- data/lib/webmachine/headers.rb +7 -2
- data/lib/webmachine/locale/en.yml +7 -5
- data/lib/webmachine/media_type.rb +10 -8
- data/lib/webmachine/request.rb +44 -15
- data/lib/webmachine/resource.rb +1 -1
- data/lib/webmachine/resource/callbacks.rb +6 -4
- data/lib/webmachine/spec/IO_response.body +1 -0
- data/lib/webmachine/spec/adapter_lint.rb +70 -36
- data/lib/webmachine/spec/test_resource.rb +10 -4
- data/lib/webmachine/streaming/fiber_encoder.rb +1 -5
- data/lib/webmachine/streaming/io_encoder.rb +6 -0
- data/lib/webmachine/trace.rb +1 -0
- data/lib/webmachine/trace/fsm.rb +20 -10
- data/lib/webmachine/trace/resource_proxy.rb +2 -0
- data/lib/webmachine/translation.rb +2 -1
- data/lib/webmachine/version.rb +3 -3
- data/memory_test.rb +37 -0
- data/spec/spec_helper.rb +9 -9
- data/spec/webmachine/adapter_spec.rb +14 -15
- data/spec/webmachine/adapters/httpkit_spec.rb +10 -0
- data/spec/webmachine/adapters/rack_spec.rb +6 -6
- data/spec/webmachine/adapters/reel_spec.rb +15 -11
- data/spec/webmachine/adapters/webrick_spec.rb +2 -2
- data/spec/webmachine/application_spec.rb +18 -17
- data/spec/webmachine/chunked_body_spec.rb +3 -3
- data/spec/webmachine/configuration_spec.rb +5 -5
- data/spec/webmachine/cookie_spec.rb +13 -13
- data/spec/webmachine/decision/conneg_spec.rb +48 -42
- data/spec/webmachine/decision/falsey_spec.rb +4 -4
- data/spec/webmachine/decision/flow_spec.rb +194 -144
- data/spec/webmachine/decision/fsm_spec.rb +17 -17
- data/spec/webmachine/decision/helpers_spec.rb +20 -20
- data/spec/webmachine/dispatcher/route_spec.rb +73 -27
- data/spec/webmachine/dispatcher_spec.rb +34 -24
- data/spec/webmachine/errors_spec.rb +1 -1
- data/spec/webmachine/etags_spec.rb +19 -19
- data/spec/webmachine/events_spec.rb +6 -6
- data/spec/webmachine/headers_spec.rb +14 -14
- data/spec/webmachine/media_type_spec.rb +36 -36
- data/spec/webmachine/request_spec.rb +33 -33
- data/spec/webmachine/resource/authentication_spec.rb +6 -6
- data/spec/webmachine/response_spec.rb +12 -12
- data/spec/webmachine/trace/fsm_spec.rb +8 -8
- data/spec/webmachine/trace/resource_proxy_spec.rb +9 -9
- data/spec/webmachine/trace/trace_store_spec.rb +5 -5
- data/spec/webmachine/trace_spec.rb +3 -3
- data/webmachine.gemspec +2 -6
- metadata +48 -206
- data/lib/webmachine/adapters/hatetepe.rb +0 -108
- data/lib/webmachine/adapters/mongrel.rb +0 -127
- data/lib/webmachine/dispatcher/not_found_resource.rb +0 -5
- data/lib/webmachine/fiber18.rb +0 -88
- data/spec/webmachine/adapters/hatetepe_spec.rb +0 -60
- data/spec/webmachine/adapters/mongrel_spec.rb +0 -16
@@ -1,39 +1,38 @@
|
|
1
1
|
require "spec_helper"
|
2
2
|
|
3
3
|
describe Webmachine::Adapter do
|
4
|
-
let(:
|
5
|
-
let(:dispatcher) { Webmachine::Dispatcher.new }
|
4
|
+
let(:application) { Webmachine::Application.new }
|
6
5
|
let(:adapter) do
|
7
|
-
|
6
|
+
server = TCPServer.new('0.0.0.0', 0)
|
7
|
+
application.configuration.port = server.addr[1]
|
8
|
+
server.close
|
9
|
+
|
10
|
+
described_class.new(application)
|
8
11
|
end
|
9
12
|
|
10
13
|
describe "#initialize" do
|
11
|
-
it "stores the provided
|
12
|
-
adapter.
|
13
|
-
end
|
14
|
-
|
15
|
-
it "stores the provided dispatcher" do
|
16
|
-
adapter.dispatcher.should eql dispatcher
|
14
|
+
it "stores the provided application" do
|
15
|
+
expect(adapter.application).to eq(application)
|
17
16
|
end
|
18
17
|
end
|
19
18
|
|
20
19
|
describe ".run" do
|
21
20
|
it "creates a new adapter and runs it" do
|
22
|
-
adapter =
|
21
|
+
adapter = double(described_class)
|
23
22
|
|
24
|
-
described_class.
|
25
|
-
with(
|
23
|
+
expect(described_class).to receive(:new).
|
24
|
+
with(application).
|
26
25
|
and_return(adapter)
|
27
26
|
|
28
|
-
adapter.
|
27
|
+
expect(adapter).to receive(:run)
|
29
28
|
|
30
|
-
described_class.run(
|
29
|
+
described_class.run(application)
|
31
30
|
end
|
32
31
|
end
|
33
32
|
|
34
33
|
describe "#run" do
|
35
34
|
it "raises a NotImplementedError" do
|
36
|
-
|
35
|
+
expect { adapter.run }.to raise_exception(NotImplementedError)
|
37
36
|
end
|
38
37
|
end
|
39
38
|
|
@@ -7,30 +7,30 @@ describe Webmachine::Adapters::Rack do
|
|
7
7
|
it_should_behave_like :adapter_lint do
|
8
8
|
it "should set Server header" do
|
9
9
|
response = client.request(Net::HTTP::Get.new("/test"))
|
10
|
-
response["Server"].
|
11
|
-
response["Server"].
|
10
|
+
expect(response["Server"]).to match(/Webmachine/)
|
11
|
+
expect(response["Server"]).to match(/Rack/)
|
12
12
|
end
|
13
13
|
end
|
14
14
|
end
|
15
15
|
|
16
16
|
describe Webmachine::Adapters::Rack::RackResponse do
|
17
17
|
context "on Rack < 1.5 release" do
|
18
|
-
before { Rack.
|
18
|
+
before { allow(Rack).to receive_messages(:release => "1.4") }
|
19
19
|
|
20
20
|
it "should add Content-Type header on not acceptable response" do
|
21
21
|
rack_response = described_class.new(double(:body), 406, {})
|
22
22
|
rack_status, rack_headers, rack_body = rack_response.finish
|
23
|
-
rack_headers.
|
23
|
+
expect(rack_headers).to have_key("Content-Type")
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
27
27
|
context "on Rack >= 1.5 release" do
|
28
|
-
before { Rack.
|
28
|
+
before { allow(Rack).to receive_messages(:release => "1.5") }
|
29
29
|
|
30
30
|
it "should not add Content-Type header on not acceptable response" do
|
31
31
|
rack_response = described_class.new(double(:body), 406, {})
|
32
32
|
rack_status, rack_headers, rack_body = rack_response.finish
|
33
|
-
rack_headers.
|
33
|
+
expect(rack_headers).not_to have_key("Content-Type")
|
34
34
|
end
|
35
35
|
end
|
36
36
|
end
|
@@ -1,15 +1,19 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
require 'webmachine/spec/adapter_lint'
|
3
3
|
describe Webmachine::Adapters::Reel do
|
4
|
-
|
5
|
-
|
6
|
-
let(:configuration) { Webmachine::Configuration.default }
|
7
|
-
let(:dispatcher) { Webmachine::Dispatcher.new }
|
8
|
-
let(:adapter) do
|
9
|
-
described_class.new(configuration, dispatcher)
|
4
|
+
context 'lint' do
|
5
|
+
it_should_behave_like :adapter_lint
|
10
6
|
end
|
11
7
|
|
12
8
|
context 'websockets' do
|
9
|
+
let(:application) { Webmachine::Application.new }
|
10
|
+
let(:adapter) do
|
11
|
+
server = TCPServer.new('0.0.0.0', 0)
|
12
|
+
application.configuration.port = server.addr[1]
|
13
|
+
server.close
|
14
|
+
described_class.new(application)
|
15
|
+
end
|
16
|
+
|
13
17
|
let(:example_host) { "www.example.com" }
|
14
18
|
let(:example_path) { "/example"}
|
15
19
|
let(:example_url) { "ws://#{example_host}#{example_path}" }
|
@@ -28,8 +32,8 @@ describe Webmachine::Adapters::Reel do
|
|
28
32
|
let(:server_message) { "Hi client!" }
|
29
33
|
|
30
34
|
it 'supports websockets' do
|
31
|
-
configuration.adapter_options[:websocket_handler] = proc do |socket|
|
32
|
-
socket.read.
|
35
|
+
application.configuration.adapter_options[:websocket_handler] = proc do |socket|
|
36
|
+
expect(socket.read).to eq client_message
|
33
37
|
socket << server_message
|
34
38
|
end
|
35
39
|
|
@@ -44,7 +48,7 @@ describe Webmachine::Adapters::Reel do
|
|
44
48
|
parser = WebSocket::Parser.new
|
45
49
|
parser.append client.readpartial(4096) until message = parser.next_message
|
46
50
|
|
47
|
-
message.
|
51
|
+
expect(message).to eq server_message
|
48
52
|
end
|
49
53
|
end
|
50
54
|
end
|
@@ -54,7 +58,7 @@ describe Webmachine::Adapters::Reel do
|
|
54
58
|
begin
|
55
59
|
timeout(5) do
|
56
60
|
begin
|
57
|
-
sock = TCPSocket.new(adptr.configuration.ip, adptr.configuration.port)
|
61
|
+
sock = TCPSocket.new(adptr.application.configuration.ip, adptr.application.configuration.port)
|
58
62
|
begin
|
59
63
|
yield(sock)
|
60
64
|
ensure
|
@@ -66,7 +70,7 @@ describe Webmachine::Adapters::Reel do
|
|
66
70
|
end
|
67
71
|
end
|
68
72
|
ensure
|
69
|
-
|
73
|
+
thread.kill if thread
|
70
74
|
end
|
71
75
|
end
|
72
76
|
end
|
@@ -5,8 +5,8 @@ describe Webmachine::Adapters::WEBrick do
|
|
5
5
|
it_should_behave_like :adapter_lint do
|
6
6
|
it "should set Server header" do
|
7
7
|
response = client.request(Net::HTTP::Get.new("/test"))
|
8
|
-
response["Server"].
|
9
|
-
response["Server"].
|
8
|
+
expect(response["Server"]).to match(/Webmachine/)
|
9
|
+
expect(response["Server"]).to match(/WEBrick/)
|
10
10
|
end
|
11
11
|
end
|
12
12
|
end
|
@@ -5,69 +5,70 @@ describe Webmachine::Application do
|
|
5
5
|
let(:test_resource) { Class.new(Webmachine::Resource) }
|
6
6
|
|
7
7
|
it "accepts a Configuration when initialized" do
|
8
|
-
config = Webmachine::Configuration.new('1.1.1.1', 9999, :
|
9
|
-
described_class.new(config).configuration.
|
8
|
+
config = Webmachine::Configuration.new('1.1.1.1', 9999, :Reel, {})
|
9
|
+
expect(described_class.new(config).configuration).to be(config)
|
10
10
|
end
|
11
11
|
|
12
12
|
it "is yielded into a block provided during initialization" do
|
13
13
|
yielded_app = nil
|
14
|
-
described_class.new do |app|
|
15
|
-
app.
|
14
|
+
returned_app = described_class.new do |app|
|
15
|
+
expect(app).to be_kind_of(Webmachine::Application)
|
16
16
|
yielded_app = app
|
17
|
-
end
|
17
|
+
end
|
18
|
+
expect(returned_app).to be(yielded_app)
|
18
19
|
end
|
19
20
|
|
20
21
|
it "is initialized with the default Configration if none is given" do
|
21
|
-
application.configuration.
|
22
|
+
expect(application.configuration).to eq(Webmachine::Configuration.default)
|
22
23
|
end
|
23
24
|
|
24
25
|
it "returns the receiver from the configure call so you can chain it" do
|
25
|
-
application.configure { |c| }.
|
26
|
+
expect(application.configure { |c| }).to equal(application)
|
26
27
|
end
|
27
28
|
|
28
29
|
it "is configurable" do
|
29
30
|
application.configure do |config|
|
30
|
-
config.
|
31
|
+
expect(config).to be_kind_of(Webmachine::Configuration)
|
31
32
|
end
|
32
33
|
end
|
33
34
|
|
34
35
|
it "is initialized with an empty Dispatcher" do
|
35
|
-
application.dispatcher.routes.
|
36
|
+
expect(application.dispatcher.routes).to be_empty
|
36
37
|
end
|
37
38
|
|
38
39
|
it "can have routes added" do
|
39
40
|
route = nil
|
40
41
|
resource = test_resource # overcome instance_eval :/
|
41
42
|
|
42
|
-
application.routes.
|
43
|
+
expect(application.routes).to be_empty
|
43
44
|
|
44
45
|
application.routes do
|
45
|
-
route = add [
|
46
|
+
route = add [:*], resource
|
46
47
|
end
|
47
48
|
|
48
|
-
route.
|
49
|
-
application.routes.
|
49
|
+
expect(route).to be_kind_of(Webmachine::Dispatcher::Route)
|
50
|
+
expect(application.routes).to eq([route])
|
50
51
|
end
|
51
52
|
|
52
53
|
describe "#adapter" do
|
53
54
|
let(:adapter_class) { application.adapter_class }
|
54
55
|
|
55
56
|
it "returns an instance of it's adapter class" do
|
56
|
-
application.adapter.
|
57
|
+
expect(application.adapter).to be_an_instance_of(adapter_class)
|
57
58
|
end
|
58
59
|
|
59
60
|
it "is memoized" do
|
60
|
-
application.adapter.
|
61
|
+
expect(application.adapter).to eql application.adapter
|
61
62
|
end
|
62
63
|
end
|
63
64
|
|
64
65
|
it "can be run" do
|
65
|
-
application.adapter.
|
66
|
+
expect(application.adapter).to receive(:run)
|
66
67
|
application.run
|
67
68
|
end
|
68
69
|
|
69
70
|
it "can be queried about its configured adapter" do
|
70
71
|
expected = Webmachine::Adapters.const_get(application.configuration.adapter)
|
71
|
-
application.adapter_class.
|
72
|
+
expect(application.adapter_class).to equal(expected)
|
72
73
|
end
|
73
74
|
end
|
@@ -7,7 +7,7 @@ describe Webmachine::ChunkedBody do
|
|
7
7
|
Webmachine::ChunkedBody.new(['foo', 'bar', '', 'j', 'webmachine']).each do |chunk|
|
8
8
|
body << chunk
|
9
9
|
end
|
10
|
-
body.
|
10
|
+
expect(body).to eq("3\r\nfoo\r\n3\r\nbar\r\n1\r\nj\r\na\r\nwebmachine\r\n0\r\n\r\n")
|
11
11
|
end
|
12
12
|
|
13
13
|
context "with an empty body" do
|
@@ -16,14 +16,14 @@ describe Webmachine::ChunkedBody do
|
|
16
16
|
Webmachine::ChunkedBody.new([]).each do |chunk|
|
17
17
|
body << chunk
|
18
18
|
end
|
19
|
-
body.
|
19
|
+
expect(body).to eq("0\r\n\r\n")
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
23
23
|
describe "#each" do
|
24
24
|
context "without a block given" do
|
25
25
|
it "returns an Enumerator" do
|
26
|
-
Webmachine::ChunkedBody.new([]).each.
|
26
|
+
expect(Webmachine::ChunkedBody.new([]).each).to respond_to(:next)
|
27
27
|
end
|
28
28
|
end
|
29
29
|
end
|
@@ -4,13 +4,13 @@ describe Webmachine::Configuration do
|
|
4
4
|
before { Webmachine.configuration = nil }
|
5
5
|
|
6
6
|
%w{ip port adapter adapter_options}.each do |field|
|
7
|
-
it {
|
8
|
-
it {
|
7
|
+
it { is_expected.to respond_to(field) }
|
8
|
+
it { is_expected.to respond_to("#{field}=") }
|
9
9
|
end
|
10
10
|
|
11
11
|
it "should yield configuration to the block" do
|
12
12
|
Webmachine.configure do |config|
|
13
|
-
config.
|
13
|
+
expect(config).to be_kind_of(described_class)
|
14
14
|
end
|
15
15
|
end
|
16
16
|
|
@@ -18,10 +18,10 @@ describe Webmachine::Configuration do
|
|
18
18
|
Webmachine.configure do |config|
|
19
19
|
@config = config
|
20
20
|
end
|
21
|
-
@config.
|
21
|
+
expect(@config).to eq Webmachine.configuration
|
22
22
|
end
|
23
23
|
|
24
24
|
it "should return the module from the configure call so you can chain it" do
|
25
|
-
Webmachine.configure {|c|}.
|
25
|
+
expect(Webmachine.configure {|c|}).to eq Webmachine
|
26
26
|
end
|
27
27
|
end
|
@@ -53,14 +53,14 @@ describe Webmachine::Cookie do
|
|
53
53
|
|
54
54
|
it "should include the attributes in its string version" do
|
55
55
|
str = subject.to_s
|
56
|
-
str.
|
57
|
-
str.
|
58
|
-
str.
|
59
|
-
str.
|
60
|
-
str.
|
61
|
-
str.
|
62
|
-
str.
|
63
|
-
str.
|
56
|
+
expect(str).to include "Secure"
|
57
|
+
expect(str).to include "HttpOnly"
|
58
|
+
expect(str).to include "Comment=comment+with+spaces"
|
59
|
+
expect(str).to include "Domain=www.server.com"
|
60
|
+
expect(str).to include "Path=/"
|
61
|
+
expect(str).to include "Version=1"
|
62
|
+
expect(str).to include "Max-Age=60"
|
63
|
+
expect(str).to include "Expires=Sun, 14-Mar-2010 03:14:00 GMT"
|
64
64
|
end
|
65
65
|
end
|
66
66
|
end
|
@@ -70,30 +70,30 @@ describe Webmachine::Cookie do
|
|
70
70
|
|
71
71
|
subject { Webmachine::Cookie.parse(str) }
|
72
72
|
|
73
|
-
it("should have the cookie") { subject.
|
73
|
+
it("should have the cookie") { expect(subject).to eq({ "cookie" => "monster" }) }
|
74
74
|
|
75
75
|
describe "parsing multiple cookie parameters" do
|
76
76
|
let(:str) { "cookie=monster; monster=mash" }
|
77
77
|
|
78
|
-
it("should have both cookies") { subject.
|
78
|
+
it("should have both cookies") { expect(subject).to eq({ "cookie" => "monster", "monster" => "mash" }) }
|
79
79
|
end
|
80
80
|
|
81
81
|
describe "parsing an encoded cookie" do
|
82
82
|
let(:str) { "cookie=yum+yum" }
|
83
83
|
|
84
|
-
it("should decode the cookie") { subject.
|
84
|
+
it("should decode the cookie") { expect(subject).to eq({ "cookie" => "yum yum" }) }
|
85
85
|
end
|
86
86
|
|
87
87
|
describe "parsing nil" do
|
88
88
|
let(:str) { nil }
|
89
89
|
|
90
|
-
it("should return empty hash") { subject.
|
90
|
+
it("should return empty hash") { expect(subject).to eq({}) }
|
91
91
|
end
|
92
92
|
|
93
93
|
describe "parsing duplicate cookies" do
|
94
94
|
let(:str) { "cookie=monster; cookie=yum+yum" }
|
95
95
|
|
96
|
-
it("should return the first instance of the cookie") { subject.
|
96
|
+
it("should return the first instance of the cookie") { expect(subject).to eq({ "cookie" => "monster" }) }
|
97
97
|
end
|
98
98
|
end
|
99
99
|
end
|
@@ -9,35 +9,35 @@ describe Webmachine::Decision::Conneg do
|
|
9
9
|
|
10
10
|
context "choosing a media type" do
|
11
11
|
it "should not choose a type when none are provided" do
|
12
|
-
subject.choose_media_type([], "*/*").
|
12
|
+
expect(subject.choose_media_type([], "*/*")).to be_nil
|
13
13
|
end
|
14
14
|
|
15
15
|
it "should not choose a type when none are acceptable" do
|
16
|
-
subject.choose_media_type(["text/html"], "application/json").
|
16
|
+
expect(subject.choose_media_type(["text/html"], "application/json")).to be_nil
|
17
17
|
end
|
18
18
|
|
19
19
|
it "should choose the first acceptable type" do
|
20
|
-
subject.choose_media_type(["text/html", "application/xml"],
|
21
|
-
"application/xml, text/html, */*").
|
20
|
+
expect(subject.choose_media_type(["text/html", "application/xml"],
|
21
|
+
"application/xml, text/html, */*")).to eq("application/xml")
|
22
22
|
end
|
23
23
|
|
24
24
|
it "should choose the type that matches closest when matching subparams" do
|
25
|
-
subject.choose_media_type(["text/html",
|
25
|
+
expect(subject.choose_media_type(["text/html",
|
26
26
|
["text/html", {"charset" => "iso8859-1"}]],
|
27
|
-
"text/html;charset=iso8859-1, application/xml").
|
28
|
-
|
27
|
+
"text/html;charset=iso8859-1, application/xml")).
|
28
|
+
to eq("text/html;charset=iso8859-1")
|
29
29
|
end
|
30
30
|
|
31
31
|
it "should choose a type more specific than requested when an exact match is not present" do
|
32
|
-
subject.choose_media_type(["application/json;v=3;foo=bar", "application/json;v=2"],
|
33
|
-
"text/html, application/json").
|
34
|
-
|
32
|
+
expect(subject.choose_media_type(["application/json;v=3;foo=bar", "application/json;v=2"],
|
33
|
+
"text/html, application/json")).
|
34
|
+
to eq("application/json;v=3;foo=bar")
|
35
35
|
end
|
36
36
|
|
37
37
|
|
38
38
|
it "should choose the preferred type over less-preferred types" do
|
39
|
-
subject.choose_media_type(["text/html", "application/xml"],
|
40
|
-
"application/xml;q=0.7, text/html, */*").
|
39
|
+
expect(subject.choose_media_type(["text/html", "application/xml"],
|
40
|
+
"application/xml;q=0.7, text/html, */*")).to eq("text/html")
|
41
41
|
|
42
42
|
end
|
43
43
|
|
@@ -47,114 +47,120 @@ describe Webmachine::Decision::Conneg do
|
|
47
47
|
"bah;")
|
48
48
|
}.to raise_error(Webmachine::MalformedRequest)
|
49
49
|
end
|
50
|
+
|
51
|
+
it "should choose a type when more than one accept header is present" do
|
52
|
+
expect(subject.choose_media_type(["text/html"],
|
53
|
+
["text/html", "text/plain"])).to eq("text/html")
|
54
|
+
|
55
|
+
end
|
50
56
|
end
|
51
57
|
|
52
58
|
context "choosing an encoding" do
|
53
59
|
it "should not set the encoding when none are provided" do
|
54
60
|
subject.choose_encoding({}, "identity, gzip")
|
55
|
-
subject.metadata['Content-Encoding'].
|
56
|
-
subject.response.headers['Content-Encoding'].
|
61
|
+
expect(subject.metadata['Content-Encoding']).to be_nil
|
62
|
+
expect(subject.response.headers['Content-Encoding']).to be_nil
|
57
63
|
end
|
58
64
|
|
59
65
|
it "should not set the Content-Encoding header when it is identity" do
|
60
66
|
subject.choose_encoding({"gzip"=> :encode_gzip, "identity" => :encode_identity}, "identity")
|
61
|
-
subject.metadata['Content-Encoding'].
|
62
|
-
response.headers['Content-Encoding'].
|
67
|
+
expect(subject.metadata['Content-Encoding']).to eq('identity')
|
68
|
+
expect(response.headers['Content-Encoding']).to be_nil
|
63
69
|
end
|
64
70
|
|
65
71
|
it "should choose the first acceptable encoding" do
|
66
72
|
subject.choose_encoding({"gzip" => :encode_gzip}, "identity, gzip")
|
67
|
-
subject.metadata['Content-Encoding'].
|
68
|
-
response.headers['Content-Encoding'].
|
73
|
+
expect(subject.metadata['Content-Encoding']).to eq('gzip')
|
74
|
+
expect(response.headers['Content-Encoding']).to eq('gzip')
|
69
75
|
end
|
70
76
|
|
71
77
|
it "should choose the first acceptable encoding" \
|
72
78
|
", even when no white space after comma" do
|
73
79
|
subject.choose_encoding({"gzip" => :encode_gzip}, "identity,gzip")
|
74
|
-
subject.metadata['Content-Encoding'].
|
75
|
-
response.headers['Content-Encoding'].
|
80
|
+
expect(subject.metadata['Content-Encoding']).to eq('gzip')
|
81
|
+
expect(response.headers['Content-Encoding']).to eq('gzip')
|
76
82
|
end
|
77
83
|
|
78
84
|
it "should choose the preferred encoding over less-preferred encodings" do
|
79
85
|
subject.choose_encoding({"gzip" => :encode_gzip, "identity" => :encode_identity}, "gzip, identity;q=0.7")
|
80
|
-
subject.metadata['Content-Encoding'].
|
81
|
-
response.headers['Content-Encoding'].
|
86
|
+
expect(subject.metadata['Content-Encoding']).to eq('gzip')
|
87
|
+
expect(response.headers['Content-Encoding']).to eq('gzip')
|
82
88
|
end
|
83
89
|
|
84
90
|
it "should not set the encoding if none are acceptable" do
|
85
91
|
subject.choose_encoding({"gzip" => :encode_gzip}, "identity")
|
86
|
-
subject.metadata['Content-Encoding'].
|
87
|
-
response.headers['Content-Encoding'].
|
92
|
+
expect(subject.metadata['Content-Encoding']).to be_nil
|
93
|
+
expect(response.headers['Content-Encoding']).to be_nil
|
88
94
|
end
|
89
95
|
end
|
90
96
|
|
91
97
|
context "choosing a charset" do
|
92
98
|
it "should not set the charset when none are provided" do
|
93
99
|
subject.choose_charset([], "ISO-8859-1")
|
94
|
-
subject.metadata['Charset'].
|
100
|
+
expect(subject.metadata['Charset']).to be_nil
|
95
101
|
end
|
96
102
|
|
97
103
|
it "should choose the first acceptable charset" do
|
98
104
|
subject.choose_charset([["UTF-8", :to_utf8],["US-ASCII", :to_ascii]], "US-ASCII, UTF-8")
|
99
|
-
subject.metadata['Charset'].
|
105
|
+
expect(subject.metadata['Charset']).to eq("US-ASCII")
|
100
106
|
end
|
101
107
|
|
102
108
|
it "should choose the preferred charset over less-preferred charsets" do
|
103
109
|
subject.choose_charset([["UTF-8", :to_utf8],["US-ASCII", :to_ascii]], "US-ASCII;q=0.7, UTF-8")
|
104
|
-
subject.metadata['Charset'].
|
110
|
+
expect(subject.metadata['Charset']).to eq("UTF-8")
|
105
111
|
end
|
106
112
|
|
107
113
|
it "should not set the charset if none are acceptable" do
|
108
114
|
subject.choose_charset([["UTF-8", :to_utf8],["US-ASCII", :to_ascii]], "ISO-8859-1")
|
109
|
-
subject.metadata['Charset'].
|
115
|
+
expect(subject.metadata['Charset']).to be_nil
|
110
116
|
end
|
111
117
|
|
112
118
|
it "should choose a charset case-insensitively" do
|
113
119
|
subject.choose_charset([["UtF-8", :to_utf8],["US-ASCII", :to_ascii]], "iso-8859-1, utf-8")
|
114
|
-
subject.metadata['Charset'].
|
120
|
+
expect(subject.metadata['Charset']).to eq("utf-8")
|
115
121
|
end
|
116
122
|
end
|
117
123
|
|
118
124
|
context "choosing a language" do
|
119
125
|
it "should not set the language when none are provided" do
|
120
126
|
subject.choose_language([], "en")
|
121
|
-
subject.metadata['Language'].
|
127
|
+
expect(subject.metadata['Language']).to be_nil
|
122
128
|
end
|
123
129
|
|
124
130
|
it "should choose the first acceptable language" do
|
125
131
|
subject.choose_language(['en', 'en-US', 'es'], "en-US, es")
|
126
|
-
subject.metadata['Language'].
|
127
|
-
response.headers['Content-Language'].
|
132
|
+
expect(subject.metadata['Language']).to eq("en-US")
|
133
|
+
expect(response.headers['Content-Language']).to eq("en-US")
|
128
134
|
end
|
129
135
|
|
130
136
|
it "should choose the preferred language over less-preferred languages" do
|
131
137
|
subject.choose_language(['en', 'en-US', 'es'], "en-US;q=0.6, es")
|
132
|
-
subject.metadata['Language'].
|
133
|
-
response.headers['Content-Language'].
|
138
|
+
expect(subject.metadata['Language']).to eq("es")
|
139
|
+
expect(response.headers['Content-Language']).to eq("es")
|
134
140
|
end
|
135
141
|
|
136
142
|
it "should select the first language if all are acceptable" do
|
137
143
|
subject.choose_language(['en', 'fr', 'es'], "*")
|
138
|
-
subject.metadata['Language'].
|
139
|
-
response.headers['Content-Language'].
|
144
|
+
expect(subject.metadata['Language']).to eq("en")
|
145
|
+
expect(response.headers['Content-Language']).to eq("en")
|
140
146
|
end
|
141
147
|
|
142
148
|
it "should select the closest acceptable language when an exact match is not available" do
|
143
149
|
subject.choose_language(['en-US', 'es'], "en, fr")
|
144
|
-
subject.metadata['Language'].
|
145
|
-
response.headers['Content-Language'].
|
150
|
+
expect(subject.metadata['Language']).to eq('en-US')
|
151
|
+
expect(response.headers['Content-Language']).to eq('en-US')
|
146
152
|
end
|
147
153
|
|
148
154
|
it "should not set the language if none are acceptable" do
|
149
155
|
subject.choose_language(['en'], 'es')
|
150
|
-
subject.metadata['Language'].
|
151
|
-
response.headers.
|
156
|
+
expect(subject.metadata['Language']).to be_nil
|
157
|
+
expect(response.headers).not_to include('Content-Language')
|
152
158
|
end
|
153
159
|
|
154
160
|
it "should choose a language case-insensitively" do
|
155
161
|
subject.choose_language(['en-US', 'ZH'], 'zh-ch, EN')
|
156
|
-
subject.metadata['Language'].
|
157
|
-
response.headers['Content-Language'].
|
162
|
+
expect(subject.metadata['Language']).to eq('en-US')
|
163
|
+
expect(response.headers['Content-Language']).to eq('en-US')
|
158
164
|
end
|
159
165
|
end
|
160
166
|
end
|