rest-core 3.6.0 → 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
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