ruby-requests 0.0.1.a1

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.
@@ -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