1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
|
# frozen_string_literal: true
require 'rails_helper'
require 'securerandom'
describe Request do
subject { Request.new(:get, 'http://example.com') }
describe '#headers' do
it 'returns user agent' do
expect(subject.headers['User-Agent']).to be_present
end
it 'returns the date header' do
expect(subject.headers['Date']).to be_present
end
it 'returns the host header' do
expect(subject.headers['Host']).to be_present
end
it 'does not return virtual request-target header' do
expect(subject.headers['(request-target)']).to be_nil
end
end
describe '#on_behalf_of' do
it 'when used, adds signature header' do
subject.on_behalf_of(Fabricate(:account))
expect(subject.headers['Signature']).to be_present
end
end
describe '#add_headers' do
it 'adds headers to the request' do
subject.add_headers('Test' => 'Foo')
expect(subject.headers['Test']).to eq 'Foo'
end
end
describe '#perform' do
context 'with valid host' do
before { stub_request(:get, 'http://example.com') }
it 'executes a HTTP request' do
expect { |block| subject.perform(&block) }.to yield_control
expect(a_request(:get, 'http://example.com')).to have_been_made.once
end
it 'executes a HTTP request when the first address is private' do
resolver = double
allow(resolver).to receive(:getaddresses).with('example.com').and_return(%w(0.0.0.0 2001:4860:4860::8844))
allow(resolver).to receive(:timeouts=).and_return(nil)
allow(Resolv::DNS).to receive(:open).and_yield(resolver)
expect { |block| subject.perform(&block) }.to yield_control
expect(a_request(:get, 'http://example.com')).to have_been_made.once
end
it 'sets headers' do
expect { |block| subject.perform(&block) }.to yield_control
expect(a_request(:get, 'http://example.com').with(headers: subject.headers)).to have_been_made
end
it 'closes underlying connection' do
expect_any_instance_of(HTTP::Client).to receive(:close)
expect { |block| subject.perform(&block) }.to yield_control
end
it 'returns response which implements body_with_limit' do
subject.perform do |response|
expect(response).to respond_to :body_with_limit
end
end
end
context 'with private host' do
around do |example|
WebMock.disable!
example.run
WebMock.enable!
end
it 'raises Mastodon::ValidationError' do
resolver = double
allow(resolver).to receive(:getaddresses).with('example.com').and_return(%w(0.0.0.0 2001:db8::face))
allow(resolver).to receive(:timeouts=).and_return(nil)
allow(Resolv::DNS).to receive(:open).and_yield(resolver)
expect { subject.perform }.to raise_error Mastodon::ValidationError
end
end
end
describe "response's body_with_limit method" do
it 'rejects body more than 1 megabyte by default' do
stub_request(:any, 'http://example.com').to_return(body: SecureRandom.random_bytes(2.megabytes))
expect { subject.perform { |response| response.body_with_limit } }.to raise_error Mastodon::LengthValidationError
end
it 'accepts body less than 1 megabyte by default' do
stub_request(:any, 'http://example.com').to_return(body: SecureRandom.random_bytes(2.kilobytes))
expect { subject.perform { |response| response.body_with_limit } }.not_to raise_error
end
it 'rejects body by given size' do
stub_request(:any, 'http://example.com').to_return(body: SecureRandom.random_bytes(2.kilobytes))
expect { subject.perform { |response| response.body_with_limit(1.kilobyte) } }.to raise_error Mastodon::LengthValidationError
end
it 'rejects too large chunked body' do
stub_request(:any, 'http://example.com').to_return(body: SecureRandom.random_bytes(2.megabytes), headers: { 'Transfer-Encoding' => 'chunked' })
expect { subject.perform { |response| response.body_with_limit } }.to raise_error Mastodon::LengthValidationError
end
it 'rejects too large monolithic body' do
stub_request(:any, 'http://example.com').to_return(body: SecureRandom.random_bytes(2.megabytes), headers: { 'Content-Length' => 2.megabytes })
expect { subject.perform { |response| response.body_with_limit } }.to raise_error Mastodon::LengthValidationError
end
it 'truncates large monolithic body' do
stub_request(:any, 'http://example.com').to_return(body: SecureRandom.random_bytes(2.megabytes), headers: { 'Content-Length' => 2.megabytes })
expect(subject.perform { |response| response.truncated_body.bytesize }).to be < 2.megabytes
end
it 'uses binary encoding if Content-Type does not tell encoding' do
stub_request(:any, 'http://example.com').to_return(body: '', headers: { 'Content-Type' => 'text/html' })
expect(subject.perform { |response| response.body_with_limit.encoding }).to eq Encoding::BINARY
end
it 'uses binary encoding if Content-Type tells unknown encoding' do
stub_request(:any, 'http://example.com').to_return(body: '', headers: { 'Content-Type' => 'text/html; charset=unknown' })
expect(subject.perform { |response| response.body_with_limit.encoding }).to eq Encoding::BINARY
end
it 'uses encoding specified by Content-Type' do
stub_request(:any, 'http://example.com').to_return(body: '', headers: { 'Content-Type' => 'text/html; charset=UTF-8' })
expect(subject.perform { |response| response.body_with_limit.encoding }).to eq Encoding::UTF_8
end
end
end
|