ruby-requests 0.0.1.a1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,11 @@
1
+ auth_param basic program /usr/lib/squid3/basic_ncsa_auth /etc/squid3/passwords
2
+ auth_param basic realm proxy
3
+ acl authenticated proxy_auth REQUIRED
4
+ http_access allow authenticated
5
+
6
+ http_port 3128
7
+
8
+ cache_dir ufs /var/spool/squid3 100 16 256
9
+ coredump_dir /var/spool/squid3
10
+
11
+ access_log stdio:/var/log/squid3/access.log squid
@@ -0,0 +1,326 @@
1
+
2
+ require 'rspec'
3
+ require 'base64'
4
+ require 'openssl'
5
+ require_relative '../spec_helper'
6
+
7
+
8
+ RSpec.describe Requests do
9
+ reset_log
10
+ display_verbose_log
11
+
12
+ shared_examples "bad SSL certificates" do |method|
13
+ it "raises exception on self-signed cert" do
14
+ url = BADSSL_URLS['self-signed']
15
+ expect {
16
+ Requests.send(method, url)
17
+ }.to raise_error(OpenSSL::SSL::SSLError)
18
+ end
19
+
20
+ it "doesn't raise exception when verify: false" do
21
+ url = BADSSL_URLS['self-signed']
22
+ expect {
23
+ Requests.send(method, url, verify: false)
24
+ }.not_to raise_error
25
+ end
26
+ end
27
+
28
+ shared_examples "redirects" do |method, protocol, httpbin|
29
+ it "#{protocol} follows redirect with allow_redirects: true" do
30
+ skip "Not implemented yet"
31
+ url = httpbin + '/redirect-to'
32
+ payload = {'url' => 'http://example.com'}
33
+ resp = Requests.send(method, url, params: payload,
34
+ allow_redirects: true)
35
+ expect(resp.status_code).to eq(200)
36
+ expect(resp.url).to eq('http://example.com')
37
+ end
38
+
39
+ it "#{protocol} doesn't follow redirect with allow_redirects: false" do
40
+ url = httpbin + '/redirect-to'
41
+ payload = {'url' => 'http://example.com'}
42
+ resp = Requests.send(method, url, params: payload,
43
+ allow_redirects: false)
44
+ expect(resp.status_code).to eq(302)
45
+ full_url = url + '?' + URI.encode_www_form(payload)
46
+ expect(resp.url).to eq(full_url)
47
+ end
48
+ end
49
+
50
+ shared_examples "all methods" do |method, protocol, httpbin|
51
+ it "#{protocol} sets url attribute on the response" do
52
+ url = httpbin + '/anything'
53
+ resp = Requests.send(method, url)
54
+ expect(resp.url).to eq(url)
55
+ end
56
+
57
+ it "uses timeout" do
58
+ url = httpbin + '/anything'
59
+ expect {
60
+ Requests.send(method, url, timeout: [0.00001, 2])
61
+ }.to raise_error(Requests::ConnectionTimeout)
62
+ end
63
+ end
64
+
65
+ shared_examples "methods with response body" do |method, protocol, httpbin|
66
+ let(:url) { httpbin + '/anything' }
67
+
68
+ it "#{protocol} makes request" do
69
+ resp = Requests.send(method, url)
70
+ received_headers = Requests::Utils::InsensitiveDict
71
+ .new(resp.json['headers'])
72
+ expect(resp.json['args']).to eq({})
73
+ user_agent = received_headers['User-Agent']
74
+ expect(user_agent).to eq(Requests::Utils.default_user_agent)
75
+ end
76
+
77
+ it "#{protocol} sends query string params" do
78
+ payload = {
79
+ 'example_key' => 'example_value',
80
+ 'other_key' => 'other_value',
81
+ 'another_key' => ['this', 'is', 'an', 'array'],
82
+ }
83
+ resp = Requests.send(method, url, params: payload)
84
+ expect(resp.json['args']).to eq(payload)
85
+ end
86
+
87
+ it "#{protocol} sends headers" do
88
+ headers = {
89
+ 'Header-Name' => 'header value',
90
+ 'Other-Header' => 'other value',
91
+ 'lowercase-header' => 'should still match',
92
+ 'User-Agent' => 'Mozilla whatever',
93
+ }
94
+ resp = Requests.send(method, url, headers: headers)
95
+ sent_headers = Requests::Utils::InsensitiveDict
96
+ .new(resp.json['headers'])
97
+ headers.each do |k, v|
98
+ expect(sent_headers[k]).to eq(v)
99
+ end
100
+ end
101
+
102
+ it "#{protocol} sends cookies" do
103
+ cookies = {
104
+ 'chocolate' => 'chip',
105
+ 'oatmeal' => 'raisin hell',
106
+ }
107
+ resp = Requests.send(method, url, cookies: cookies)
108
+ sent_cookies = resp.json['headers']['Cookie']
109
+ expect(sent_cookies).to include('chocolate=chip')
110
+ expect(sent_cookies).to include('oatmeal="raisin hell"')
111
+ end
112
+ end
113
+
114
+ shared_examples "GET method" do |protocol, httpbin|
115
+ it "#{protocol} sends basic auth" do
116
+ url = httpbin + '/basic-auth/testuser/testpassword'
117
+ resp = Requests.get(url, auth: ['testuser', 'testpassword'])
118
+ expect(resp.status_code).to eq(200)
119
+ end
120
+
121
+ it "uses timeout" do
122
+ url = httpbin + '/delay/60'
123
+ expect {
124
+ Requests.get(url, timeout: 2)
125
+ }.to raise_error(Requests::TimeoutError)
126
+ end
127
+
128
+ it "#{protocol} decodes gzip" do
129
+ url = httpbin + '/gzip'
130
+ resp = Requests.get(url, headers: {'Test-Header' => 'value'})
131
+ expect(resp.json['headers']['Test-Header']).to eq('value')
132
+ end
133
+
134
+ it "#{protocol} decodes deflate" do
135
+ url = httpbin + '/deflate'
136
+ resp = Requests.get(url, headers: {'Test-Header' => 'value'})
137
+ expect(resp.json['headers']['Test-Header']).to eq('value')
138
+ end
139
+
140
+ it "#{protocol} sets response cookies from Set-Cookie header" do
141
+ url = httpbin + '/cookies/set'
142
+ set_cookies = {
143
+ 'macadamia' => 'nut',
144
+ 'peanut' => 'butter',
145
+ }
146
+ resp = Requests.get(url, params: set_cookies,
147
+ allow_redirects: false)
148
+ expect(resp.cookies_hash).to eq(set_cookies)
149
+ end
150
+
151
+ it "#{protocol} handles unicode" do
152
+ url = httpbin + '/encoding/utf8'
153
+ unicode_str = "Зарегистрируйтесь сейчас на"
154
+ r = Requests.get(url)
155
+ expect(r.text).to include(unicode_str)
156
+ end
157
+ end
158
+
159
+ shared_examples "methods with request body" do |method, protocol, httpbin|
160
+ let(:url) { httpbin + '/anything' }
161
+
162
+ it "#{protocol} sends json object as body" do
163
+ json_payload = {
164
+ 'some' => 'thing',
165
+ 'that' => ['can', 'be', 'encoded'],
166
+ 'as' => {'json' => true},
167
+ }
168
+ resp = Requests.send(method, url, json: json_payload)
169
+ expect(resp.json['json']).to eq(json_payload)
170
+ end
171
+
172
+ it "#{protocol} sends json array as body" do
173
+ json_payload = ['some', 'list', 'of', 7, {'items' => [1, 42]}]
174
+ resp = Requests.send(method, url, json: json_payload)
175
+ expect(resp.json['json']).to eq(json_payload)
176
+ end
177
+
178
+ it "#{protocol} sends data string as body" do
179
+ data = "Some sample data\nthat isn't JSON\n"
180
+ resp = Requests.send(method, url, data: data)
181
+ expect(resp.json['data']).to eq(data)
182
+ end
183
+
184
+ it "#{protocol} sends data hash as form-urlencoded" do
185
+ data = {
186
+ "key a" => "value a",
187
+ "key b" => "value b",
188
+ }
189
+ resp = Requests.send(method, url, data: data)
190
+ expect(resp.json['form']).to eq(data)
191
+ end
192
+
193
+ it "#{protocol} sends data array as form-urlencoded" do
194
+ data = [["key a", "value a"],
195
+ ["key b", "value b"]]
196
+ expected = {
197
+ "key a" => "value a",
198
+ "key b" => "value b",
199
+ }
200
+ resp = Requests.send(method, url, data: data)
201
+ expect(resp.json['form']).to eq(expected)
202
+ end
203
+
204
+ it "#{protocol} sends files" do
205
+ end
206
+
207
+ it "#{protocol} sends basic auth" do
208
+ url = httpbin + '/basic-auth/testuser/testpassword'
209
+ resp = Requests.send(method, url, auth: ['testuser',
210
+ 'testpassword'])
211
+
212
+ # Can't check response status code here because httpbin.org
213
+ # only allows GET requests on /basic-auth:
214
+ auth_token = Base64.strict_encode64('testuser:testpassword')
215
+ encoded_auth = "Basic #{auth_token}"
216
+ auth_header = resp.request.headers['Authorization']
217
+ expect(auth_header).to eq(encoded_auth)
218
+ end
219
+ end
220
+
221
+ shared_examples "HEAD method" do |protocol, httpbin|
222
+ let(:url) { httpbin + '/anything' }
223
+
224
+ it "#{protocol} makes request" do
225
+ resp = Requests.head(url)
226
+ expect(resp.status_code).to eq(200)
227
+ end
228
+
229
+ it "#{protocol} body is empty" do
230
+ resp = Requests.head(url)
231
+ expect(resp.text).to eq('')
232
+ end
233
+ end
234
+
235
+ shared_examples "OPTIONS method" do |protocol, httpbin|
236
+ let(:all_methods) {
237
+ ['PUT', 'POST', 'OPTIONS', 'DELETE',
238
+ 'HEAD', 'GET', 'TRACE', 'PATCH']
239
+ }
240
+
241
+ it "#{protocol} gets allow header in response /anything" do
242
+ url = httpbin + "/anything"
243
+ resp = Requests.options(url)
244
+ allowed = resp.headers['allow'].split(', ')
245
+ diff = (allowed - all_methods) + (all_methods - allowed)
246
+ expect(diff).to eq([])
247
+ end
248
+
249
+ it "#{protocol} gets allow header in response /delete" do
250
+ url = httpbin + "/delete"
251
+ resp = Requests.options(url)
252
+ allowed = resp.headers['allow'].split(', ')
253
+ methods = ['OPTIONS', 'DELETE']
254
+ diff = (allowed - methods) + (methods - allowed)
255
+ expect(diff).to eq([])
256
+ end
257
+ end
258
+
259
+ describe "GET" do
260
+ HTTPBIN_URLS.each do |protocol, httpbin|
261
+ include_examples("all methods", "get", protocol, httpbin)
262
+ include_examples("redirects", "get", protocol, httpbin)
263
+ include_examples("methods with response body", "get", protocol,
264
+ httpbin)
265
+ include_examples("GET method", protocol, httpbin)
266
+ end
267
+ include_examples("bad SSL certificates", 'get')
268
+ end
269
+
270
+ describe "POST" do
271
+ HTTPBIN_URLS.each do |protocol, httpbin|
272
+ include_examples("all methods", "post", protocol, httpbin)
273
+ include_examples("redirects", "post", protocol, httpbin)
274
+ include_examples("methods with response body", "post", protocol,
275
+ httpbin)
276
+ include_examples("methods with request body", "post", protocol,
277
+ httpbin)
278
+ end
279
+ include_examples("bad SSL certificates", 'post')
280
+ end
281
+
282
+ describe "PUT" do
283
+ HTTPBIN_URLS.each do |protocol, httpbin|
284
+ include_examples("all methods", "put", protocol, httpbin)
285
+ include_examples("redirects", "put", protocol, httpbin)
286
+ include_examples("methods with response body", "put", protocol,
287
+ httpbin)
288
+ include_examples("methods with request body", "put", protocol,
289
+ httpbin)
290
+ end
291
+ end
292
+
293
+ describe "PATCH" do
294
+ HTTPBIN_URLS.each do |protocol, httpbin|
295
+ include_examples("all methods", "patch", protocol, httpbin)
296
+ include_examples("redirects", "patch", protocol, httpbin)
297
+ include_examples("methods with response body", "patch", protocol,
298
+ httpbin)
299
+ include_examples("methods with request body", "patch", protocol,
300
+ httpbin)
301
+ end
302
+ end
303
+
304
+ describe "HEAD" do
305
+ HTTPBIN_URLS.each do |protocol, httpbin|
306
+ include_examples("all methods", "head", protocol, httpbin)
307
+ include_examples("redirects", "head", protocol, httpbin)
308
+ include_examples("HEAD method", protocol, httpbin)
309
+ end
310
+ end
311
+
312
+ describe "DELETE" do
313
+ HTTPBIN_URLS.each do |protocol, httpbin|
314
+ include_examples("all methods", "delete", protocol, httpbin)
315
+ include_examples("redirects", "delete", protocol, httpbin)
316
+ # include_examples("DELETE method", protocol, httpbin)
317
+ end
318
+ end
319
+
320
+ describe "OPTIONS" do
321
+ HTTPBIN_URLS.each do |protocol, httpbin|
322
+ include_examples("all methods", "options", protocol, httpbin)
323
+ include_examples("OPTIONS method", protocol, httpbin)
324
+ end
325
+ end
326
+ end
@@ -0,0 +1,111 @@
1
+ require 'rspec'
2
+ require_relative '../spec_helper'
3
+
4
+
5
+ RSpec.describe Requests::Session do
6
+ let(:httpbin) {
7
+ HTTPBIN_URLS['HTTPS']
8
+ }
9
+
10
+ let(:anything_url) {
11
+ httpbin + '/anything'
12
+ }
13
+
14
+ before(:each) do
15
+ @session = Requests::Session.new
16
+ end
17
+
18
+ describe "headers" do
19
+ before(:each) do
20
+ @session_hdrs = {
21
+ 'Test-Header' => 'test value',
22
+ 'Other-Header' => 'other value',
23
+ }
24
+ @session.headers = @session_hdrs
25
+ end
26
+
27
+ it "sends session headers with each request" do
28
+ r = @session.get(anything_url)
29
+ expect(r.json['headers']['Test-Header']).to(
30
+ eq(@session_hdrs['Test-Header'])
31
+ )
32
+ expect(r.json['headers']['Other-Header']).to(
33
+ eq(@session_hdrs['Other-Header'])
34
+ )
35
+ end
36
+
37
+ it "request headers take precedence over session headers" do
38
+ req_hdrs = {'Test-Header' => 'request-specific'}
39
+ r = @session.get(anything_url, headers: req_hdrs)
40
+ expect(r.json['headers']['Test-Header']).to(
41
+ eq(req_hdrs['Test-Header'])
42
+ )
43
+ expect(r.json['headers']['Other-Header']).to(
44
+ eq(@session_hdrs['Other-Header'])
45
+ )
46
+ end
47
+
48
+ it "session headers can be updated" do
49
+ @session.headers['New-Header'] = 'new value'
50
+ r = @session.put(anything_url)
51
+ expect(r.json['headers']['New-Header']).to eq('new value')
52
+ end
53
+ end
54
+
55
+ describe "cookies" do
56
+ let(:cookie_url) { httpbin + '/cookies' }
57
+
58
+ before(:each) do
59
+ @cookies = Requests::CookieJar.new
60
+ @cookies.add(
61
+ Requests::Cookie.new('chocolate', 'chip', domain: 'httpbin.org',
62
+ for_domain: true, path: '/')
63
+ )
64
+ @cookies.add(
65
+ Requests::Cookie.new('or', 'eo', domain: 'httpbin.org',
66
+ for_domain: true, path: '/')
67
+ )
68
+ @session.cookies = @cookies
69
+ end
70
+
71
+ it "sends session cookies with each request" do
72
+ r = @session.get(cookie_url)
73
+ expect(r.json['cookies']).to(
74
+ eq({'chocolate' => 'chip', 'or' => 'eo'})
75
+ )
76
+ end
77
+
78
+ it "request cookies take precedence over session cookies" do
79
+ r = @session.get(cookie_url, cookies: {'or' => 'something else'})
80
+ expect(r.json['cookies']).to(
81
+ eq({'chocolate' => 'chip',
82
+ 'or' => 'something else'})
83
+ )
84
+ end
85
+
86
+ it "only sends cookies belonging to request uri" do
87
+ # this will set some cookies for github.com:
88
+ r = @session.get("https://github.com")
89
+ github_cookies = r.cookies.to_hash
90
+
91
+ r = @session.get(cookie_url)
92
+ github_cookies.each_key do |key|
93
+ expect(r.json['cookies']).not_to include(key)
94
+ end
95
+ end
96
+
97
+ it "persists cookies set by requests" do
98
+ req_cookies = {'new-cookie' => 'new value',
99
+ 'other-cookie' => 'other value'}
100
+ @session.get(cookie_url + '/set', params: req_cookies)
101
+ r = @session.get(cookie_url)
102
+ expect(r.json['cookies']).to(
103
+ eq({'chocolate' => 'chip',
104
+ 'or' => 'eo'}.merge(req_cookies))
105
+ )
106
+ end
107
+ end
108
+
109
+ # TODO: Write tests for proxies in a Session after figuring out
110
+ # a good automated way to test proxies
111
+ end
@@ -0,0 +1,44 @@
1
+ require 'simplecov'
2
+
3
+ SimpleCov.start { add_filter 'spec/' } unless ENV['COVERAGE'] == 'false'
4
+
5
+ require_relative '../lib/requests'
6
+
7
+ REQUESTS_VERBOSE = (ENV['REQUESTS_VERBOSE'] == 'true')
8
+ ENV['REQUESTS_HTTP_DEBUG'] = 'true' if REQUESTS_VERBOSE
9
+
10
+ HTTPBIN_URLS = {
11
+ 'HTTP' => 'http://httpbin.org',
12
+ 'HTTPS' => 'https://httpbin.org',
13
+ }
14
+
15
+ BADSSL_URLS = {
16
+ 'self-signed' => 'https://self-signed.badssl.com/',
17
+ }
18
+
19
+ $log = StringIO.new
20
+ $logger = Requests::Logger.new($log, level: 'debug', enabled: true)
21
+ Requests.logger = $logger
22
+
23
+
24
+ def reset_log
25
+ before(:each) do
26
+ $log.seek(0)
27
+ end
28
+ end
29
+
30
+ def display_verbose_log
31
+ after(:each) do
32
+ if REQUESTS_VERBOSE
33
+ $log.seek(0)
34
+ puts "\nCAPTURED LOG:"
35
+ puts "=" * 16
36
+ puts $log.read
37
+ puts "=" * 16 + "\n"
38
+ end
39
+ end
40
+ end
41
+
42
+ def running_in_docker
43
+ ENV['RUNNING_IN_DOCKER'] == 'true'
44
+ end