rest-core 3.6.0 → 4.0.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.
Files changed (74) hide show
  1. checksums.yaml +4 -4
  2. data/.gitmodules +3 -0
  3. data/.travis.yml +0 -1
  4. data/CHANGES.md +28 -0
  5. data/Gemfile +0 -2
  6. data/README.md +14 -95
  7. data/Rakefile +16 -3
  8. data/example/simple.rb +1 -0
  9. data/example/use-cases.rb +15 -3
  10. data/lib/rest-core.rb +38 -75
  11. data/lib/rest-core/client/universal.rb +3 -1
  12. data/lib/rest-core/client_oauth1.rb +64 -59
  13. data/lib/rest-core/event.rb +9 -11
  14. data/lib/rest-core/middleware/auth_basic.rb +21 -21
  15. data/lib/rest-core/middleware/bypass.rb +8 -8
  16. data/lib/rest-core/middleware/cache.rb +94 -90
  17. data/lib/rest-core/middleware/clash_response.rb +15 -14
  18. data/lib/rest-core/middleware/common_logger.rb +27 -26
  19. data/lib/rest-core/middleware/default_headers.rb +8 -8
  20. data/lib/rest-core/middleware/default_payload.rb +8 -8
  21. data/lib/rest-core/middleware/default_query.rb +8 -8
  22. data/lib/rest-core/middleware/default_site.rb +12 -12
  23. data/lib/rest-core/middleware/defaults.rb +38 -38
  24. data/lib/rest-core/middleware/error_detector.rb +10 -10
  25. data/lib/rest-core/middleware/error_detector_http.rb +6 -4
  26. data/lib/rest-core/middleware/error_handler.rb +14 -14
  27. data/lib/rest-core/middleware/follow_redirect.rb +28 -27
  28. data/lib/rest-core/middleware/json_request.rb +13 -11
  29. data/lib/rest-core/middleware/json_response.rb +29 -28
  30. data/lib/rest-core/middleware/oauth1_header.rb +84 -83
  31. data/lib/rest-core/middleware/oauth2_header.rb +27 -25
  32. data/lib/rest-core/middleware/oauth2_query.rb +15 -15
  33. data/lib/rest-core/middleware/query_response.rb +14 -14
  34. data/lib/rest-core/middleware/retry.rb +25 -23
  35. data/lib/rest-core/middleware/smash_response.rb +15 -14
  36. data/lib/rest-core/middleware/timeout.rb +18 -19
  37. data/lib/rest-core/test.rb +1 -18
  38. data/lib/rest-core/util/clash.rb +38 -37
  39. data/lib/rest-core/util/config.rb +40 -39
  40. data/lib/rest-core/util/dalli_extension.rb +11 -10
  41. data/lib/rest-core/util/hmac.rb +9 -8
  42. data/lib/rest-core/util/json.rb +55 -54
  43. data/lib/rest-core/util/parse_link.rb +13 -12
  44. data/lib/rest-core/util/parse_query.rb +24 -22
  45. data/lib/rest-core/version.rb +1 -1
  46. data/rest-core.gemspec +121 -158
  47. data/test/test_cache.rb +2 -0
  48. data/test/test_default_payload.rb +1 -1
  49. data/test/test_error_handler.rb +5 -4
  50. data/test/test_timeout.rb +9 -8
  51. data/test/test_universal.rb +8 -0
  52. metadata +9 -73
  53. data/lib/rest-core/builder.rb +0 -162
  54. data/lib/rest-core/client.rb +0 -277
  55. data/lib/rest-core/client/simple.rb +0 -2
  56. data/lib/rest-core/engine.rb +0 -36
  57. data/lib/rest-core/engine/dry.rb +0 -9
  58. data/lib/rest-core/engine/http-client.rb +0 -41
  59. data/lib/rest-core/error.rb +0 -5
  60. data/lib/rest-core/event_source.rb +0 -137
  61. data/lib/rest-core/middleware.rb +0 -151
  62. data/lib/rest-core/promise.rb +0 -249
  63. data/lib/rest-core/thread_pool.rb +0 -131
  64. data/lib/rest-core/timer.rb +0 -58
  65. data/lib/rest-core/util/payload.rb +0 -173
  66. data/test/test_builder.rb +0 -40
  67. data/test/test_client.rb +0 -177
  68. data/test/test_event_source.rb +0 -159
  69. data/test/test_future.rb +0 -16
  70. data/test/test_httpclient.rb +0 -118
  71. data/test/test_payload.rb +0 -204
  72. data/test/test_promise.rb +0 -146
  73. data/test/test_simple.rb +0 -38
  74. data/test/test_thread_pool.rb +0 -10
@@ -1,159 +0,0 @@
1
-
2
- require 'socket'
3
- require 'rest-core/test'
4
-
5
- describe RC::EventSource do
6
- after do
7
- Muack.verify
8
- WebMock.reset!
9
- end
10
-
11
- client = RC::Builder.client{use RC::Cache, {}, nil}.new
12
- server = lambda do |close=true|
13
- serv = TCPServer.new(0)
14
- port = serv.addr[1]
15
- path = "http://localhost:#{port}/"
16
- payload = <<-SSE
17
- event: put
18
- data: {}
19
-
20
- event: keep-alive
21
- data: null
22
- SSE
23
- m = [{'event' => 'put' , 'data' => '{}'},
24
- {'event' => 'keep-alive', 'data' => 'null'}]
25
-
26
- t = Thread.new do
27
- sock = serv.accept
28
- sock.readline("\r\n\r\n")
29
- sock.puts("HTTP/1.1 200 OK\r")
30
- sock.puts("Content-Type: text/event-stream\r")
31
- sock.puts
32
- sock.puts(payload)
33
- sock.close if close
34
- end
35
-
36
- [client.event_source(path, :a => 'b'), m, t]
37
- end
38
-
39
- would 'work regularly' do
40
- es, m, t = server.call
41
- flag = 0
42
-
43
- es.onopen do |sock|
44
- sock.should.kind_of? IO
45
- flag.should.eq 0
46
- flag += 1
47
- end.
48
- onmessage do |event, data, sock|
49
- {'event' => event, 'data' => data}.should.eq m.shift
50
- sock.should.kind_of? IO
51
- sock.should.not.closed?
52
- flag += 1
53
- end.
54
- onerror do |error, sock|
55
- error.should.kind_of? EOFError
56
- m.should.empty?
57
- sock.should.closed?
58
- flag.should.eq 3
59
- flag += 1
60
- end.start.wait
61
-
62
- flag.should.eq 4
63
- t.join
64
- end
65
-
66
- would 'close' do
67
- es, _, t = server.call(false)
68
- flag = 0
69
- es.onmessage do
70
- es.close
71
- flag += 1
72
- end.start.wait
73
-
74
- flag.should.eq 1
75
- t.join
76
- end
77
-
78
- would 'reconnect' do
79
- stub_select_for_stringio
80
- stub_request(:get, 'https://a?b=c').to_return(:body => <<-SSE)
81
- event: put
82
- data: 0
83
-
84
- event: put
85
- data: 1
86
- SSE
87
- stub_request(:get, 'https://a?c=d').to_return(:body => <<-SSE)
88
- event: put
89
- data: 2
90
-
91
- event: put
92
- data: 3
93
- SSE
94
- es = client.event_source('https://a', :b => 'c')
95
- m = ('0'..'3').to_a
96
- es.onmessage do |event, data|
97
- data.should.eq m.shift
98
-
99
- end.onerror do |error|
100
- error.should.kind_of? EOFError
101
- es.query = {:c => 'd'}
102
-
103
- end.onreconnect do |error, sock|
104
- error.should.kind_of? EOFError
105
- sock.should.respond_to? :read
106
- !m.empty? # not empty to reconnect
107
-
108
- end.start.wait
109
- m.should.empty?
110
- end
111
-
112
- would 'not cache' do
113
- stub_select_for_stringio
114
- stub_request(:get, 'https://a?b=c').to_return(:body => <<-SSE)
115
- event: put
116
- data: 0
117
-
118
- event: put
119
- data: 1
120
- SSE
121
- es = client.event_source('https://a', :b => 'c')
122
- m = %w[0 1 0 1]
123
- es.onmessage do |event, data|
124
- data.should.eq m.shift
125
-
126
- end.onerror do |error|
127
- error.should.kind_of? EOFError
128
-
129
- end.onreconnect do |error, sock|
130
- error.should.kind_of? EOFError
131
- sock.should.respond_to? :read
132
- !m.empty? # not empty to reconnect
133
-
134
- end.start.wait
135
- m.should.empty?
136
- end
137
-
138
- would 'not deadlock without ErrorHandler' do
139
- c = RC::Simple.new.event_source('http://localhost:1')
140
- c.onerror{ |e| e.should.kind_of?(Errno::ECONNREFUSED) }
141
- c.start.wait
142
- end
143
-
144
- would 'not deadlock with ErrorHandler' do
145
- c = RC::Universal.new(:log_method => false).
146
- event_source('http://localhost:1')
147
- c.onerror{ |e| e.should.kind_of?(Errno::ECONNREFUSED) }
148
- c.start.wait
149
- end
150
-
151
- would 'not deadlock if errors in onmessage' do
152
- err = nil
153
- es, _, _ = server.call
154
- es.onmessage do |event, data|
155
- raise err = "error"
156
- end.start.wait
157
- err.should.eq "error"
158
- end
159
- end
@@ -1,16 +0,0 @@
1
-
2
- require 'stringio'
3
- require 'rest-core/test'
4
-
5
- describe RC::Promise::Future do
6
- would 'fulfill the future' do
7
- promise = RC::Promise.new(RC::FAIL => [])
8
- promise.fulfill('body', 200, {'A' => 'B'}, StringIO.new)
9
-
10
- promise.future_body .should.eq 'body'
11
- promise.future_status .should.eq 200
12
- promise.future_headers .should.eq('A' => 'B')
13
- promise.future_socket .should.kind_of?(StringIO)
14
- promise.future_failures.should.eq []
15
- end
16
- end
@@ -1,118 +0,0 @@
1
-
2
- require 'rest-core/test'
3
-
4
- require 'openssl'
5
- require 'socket'
6
- require 'zlib'
7
-
8
- describe RC::HttpClient do
9
- describe 'POST Payload' do
10
- after do
11
- WebMock.reset!
12
- end
13
-
14
- client = RC::Builder.client
15
- path = 'http://example.com'
16
- ok = 'OK'
17
- c = client.new
18
-
19
- post = lambda do |payload, body|
20
- WebMock::API.stub_request(:post, path).
21
- with(:body => body).to_return(:body => ok)
22
- c.post(path, payload).should.eq ok
23
- end
24
-
25
- would 'post with string' do
26
- post['string', 'string']
27
- end
28
-
29
- would 'post with file' do
30
- File.open(__FILE__) do |f|
31
- b = f.read
32
- f.rewind
33
- post[f, b]
34
- end
35
- end
36
-
37
- would 'post with socket' do
38
- rd, wr = IO.pipe
39
- wr.write('socket')
40
- wr.close
41
- post[rd, 'socket']
42
- end
43
-
44
- would 'not kill the thread if error was coming from the task' do
45
- mock(HTTPClient).new{ raise 'boom' }.with_any_args
46
- c.request(RC::ASYNC => true).message.should.eq 'boom'
47
- Muack.verify
48
- end
49
-
50
- def accept body
51
- server = TCPServer.new(0)
52
- t = Thread.new do
53
- client = server.accept
54
- client.write(<<-HTTP)
55
- HTTP/1.0 200 OK\r
56
- Connection: close\r
57
- Content-Encoding: deflate\r
58
- \r
59
- #{body}\r
60
- HTTP
61
- client.close_write
62
- end
63
-
64
- yield("http://localhost:#{server.local_address.ip_port}")
65
-
66
- t.join
67
- end
68
-
69
- would 'accept deflate' do
70
- accept(Zlib::Deflate.deflate(ok)) do |site|
71
- c.post(site, 'body').should.eq ok
72
- end
73
- end
74
-
75
- config_engine = lambda do |engine|
76
- engine.transparent_gzip_decompression = false
77
- engine.ssl_config.verify_mode = OpenSSL::SSL::VERIFY_NONE
78
- end
79
-
80
- define_method(:define_default_config_engine) do |d|
81
- d.singleton_class.module_eval do
82
- define_method(:default_config_engine) do
83
- config_engine
84
- end
85
- end
86
- end
87
-
88
- would 'disable auto-deflate' do
89
- accept(ok) do |site|
90
- c.post(site, 'body', {}, :config_engine => config_engine).
91
- chomp.should.eq ok
92
- end
93
- end
94
-
95
- would 'disable auto-deflate with class default_config_engine' do
96
- accept(ok) do |site|
97
- d = RC::Builder.client
98
- define_default_config_engine(d)
99
- d.new.post(site, 'body').chomp.should.eq ok
100
- end
101
- end
102
-
103
- would 'disable auto-deflate with instance default_config_engine' do
104
- accept(ok) do |site|
105
- d = RC::Builder.client.new
106
- define_default_config_engine(d)
107
- d.post(site, 'body').chomp.should.eq ok
108
- end
109
- end
110
-
111
- would 'disable auto-deflate with setting config_engine' do
112
- accept(ok) do |site|
113
- d = RC::Builder.client.new(:config_engine => config_engine)
114
- d.post(site, 'body').chomp.should.eq ok
115
- end
116
- end
117
- end
118
- end
@@ -1,204 +0,0 @@
1
-
2
- require 'rest-core/test'
3
-
4
- describe RC::Payload do
5
- describe 'A regular Payload' do
6
- would 'use standard enctype as default content-type' do
7
- RC::Payload::UrlEncoded.new({}).headers['Content-Type'].
8
- should.eq 'application/x-www-form-urlencoded'
9
- end
10
-
11
- would 'form properly encoded params' do
12
- RC::Payload::UrlEncoded.new(:foo => 'bar').read.
13
- should.eq 'foo=bar'
14
- RC::Payload::UrlEncoded.new(:foo => 'bar', :baz => 'qux').read.
15
- should.eq 'baz=qux&foo=bar'
16
- end
17
-
18
- would 'escape parameters' do
19
- RC::Payload::UrlEncoded.new('foo ' => 'bar').read.
20
- should.eq 'foo%20=bar'
21
- end
22
-
23
- would 'properly handle arrays as repeated parameters' do
24
- RC::Payload::UrlEncoded.new(:foo => ['bar']).read.
25
- should.eq 'foo=bar'
26
- RC::Payload::UrlEncoded.new(:foo => ['bar', 'baz']).read.
27
- should.eq 'foo=bar&foo=baz'
28
- end
29
-
30
- would 'not close if stream already closed' do
31
- p = RC::Payload::UrlEncoded.new('foo ' => 'bar')
32
- p.close
33
- 2.times{ p.close.should.eq nil }
34
- end
35
- end
36
-
37
- describe 'A multipart Payload' do
38
- would 'use standard enctype as default content-type' do
39
- p = RC::Payload::Multipart.new({})
40
- stub(p).boundary{123}
41
- p.headers['Content-Type'].should.eq 'multipart/form-data; boundary=123'
42
- end
43
-
44
- would 'not error on close if stream already closed' do
45
- p = RC::Payload::Multipart.new(:file => File.open(__FILE__))
46
- p.close
47
- 2.times{ p.close.should.eq nil }
48
- end
49
-
50
- would 'form properly separated multipart data' do
51
- p = RC::Payload::Multipart.new(:bar => 'baz', :foo => 'bar')
52
- p.read.should.eq <<-EOS
53
- --#{p.boundary}\r
54
- Content-Disposition: form-data; name="bar"\r
55
- \r
56
- baz\r
57
- --#{p.boundary}\r
58
- Content-Disposition: form-data; name="foo"\r
59
- \r
60
- bar\r
61
- --#{p.boundary}--\r
62
- EOS
63
- end
64
-
65
- would 'form multiple files with the same name' do
66
- with_img do |f, n|
67
- with_img do |ff, nn|
68
- p = RC::Payload::Multipart.new(:foo => [f, ff])
69
- p.read.should.eq <<-EOS
70
- --#{p.boundary}\r
71
- Content-Disposition: form-data; name="foo"; filename="#{n}"\r
72
- Content-Type: image/jpeg\r
73
- \r
74
- #{'a'*10}\r
75
- --#{p.boundary}\r
76
- Content-Disposition: form-data; name="foo"; filename="#{nn}"\r
77
- Content-Type: image/jpeg\r
78
- \r
79
- #{'a'*10}\r
80
- --#{p.boundary}--\r
81
- EOS
82
- end
83
- end
84
- end
85
-
86
- would 'not escape parameters names' do
87
- p = RC::Payload::Multipart.new('bar ' => 'baz')
88
- p.read.should.eq <<-EOS
89
- --#{p.boundary}\r
90
- Content-Disposition: form-data; name="bar "\r
91
- \r
92
- baz\r
93
- --#{p.boundary}--\r
94
- EOS
95
- end
96
-
97
- would 'form properly separated multipart data' do
98
- with_img do |f, n|
99
- p = RC::Payload::Multipart.new(:foo => f)
100
- p.read.should.eq <<-EOS
101
- --#{p.boundary}\r
102
- Content-Disposition: form-data; name="foo"; filename="#{n}"\r
103
- Content-Type: image/jpeg\r
104
- \r
105
- #{File.read(f.path)}\r
106
- --#{p.boundary}--\r
107
- EOS
108
- end
109
- end
110
-
111
- would "ignore the name attribute when it's not set" do
112
- with_img do |f, n|
113
- p = RC::Payload::Multipart.new(nil => f)
114
- p.read.should.eq <<-EOS
115
- --#{p.boundary}\r
116
- Content-Disposition: form-data; filename="#{n}"\r
117
- Content-Type: image/jpeg\r
118
- \r
119
- #{File.read(f.path)}\r
120
- --#{p.boundary}--\r
121
- EOS
122
- end
123
- end
124
-
125
- would 'detect optional (original) content type and filename' do
126
- File.open(__FILE__) do |f|
127
- def f.content_type ; 'image/jpeg'; end
128
- def f.original_filename; 'foo.txt' ; end
129
- p = RC::Payload::Multipart.new(:foo => f)
130
- p.read.should.eq <<-EOS
131
- --#{p.boundary}\r
132
- Content-Disposition: form-data; name="foo"; filename="foo.txt"\r
133
- Content-Type: image/jpeg\r
134
- \r
135
- #{File.read(f.path)}\r
136
- --#{p.boundary}--\r
137
- EOS
138
- end
139
- end
140
- end
141
-
142
- describe 'streamed payloads' do
143
- would 'properly determine the size of file payloads' do
144
- File.open(__FILE__) do |f|
145
- p = RC::Payload.generate(f)
146
- p.size.should.eq f.stat.size
147
- end
148
- end
149
-
150
- would 'properly determine the size of other kinds of payloads' do
151
- s = StringIO.new('foo')
152
- p = RC::Payload.generate(s)
153
- p.size.should.eq 3
154
-
155
- begin
156
- f = Tempfile.new('rest-core')
157
- f.write('foo bar')
158
- f.rewind
159
-
160
- p = RC::Payload.generate(f)
161
- p.size.should.eq 7
162
- ensure
163
- f.close!
164
- end
165
- end
166
- end
167
-
168
- describe 'Payload generation' do
169
- would 'recognize standard urlencoded params' do
170
- RC::Payload.generate('foo' => 'bar').should.
171
- kind_of?(RC::Payload::UrlEncoded)
172
- end
173
-
174
- would 'recognize multipart params' do
175
- File.open(__FILE__) do |f|
176
- RC::Payload.generate('foo' => f).should.
177
- kind_of?(RC::Payload::Multipart)
178
- end
179
- end
180
-
181
- would 'return data if none of the above' do
182
- RC::Payload.generate('data').should.
183
- kind_of?(RC::Payload::StreamedString)
184
- end
185
-
186
- would 'recognize nested multipart payloads in arrays' do
187
- File.open(__FILE__) do |f|
188
- RC::Payload.generate('foo' => [f]).should.
189
- kind_of?(RC::Payload::Multipart)
190
- end
191
- end
192
-
193
- would 'recognize file payloads that can be streamed' do
194
- File.open(__FILE__) do |f|
195
- RC::Payload.generate(f).should.kind_of?(RC::Payload::Streamed)
196
- end
197
- end
198
-
199
- would 'recognize other payloads that can be streamed' do
200
- RC::Payload.generate(StringIO.new('foo')).should.
201
- kind_of?(RC::Payload::Streamed)
202
- end
203
- end
204
- end