scout 5.7.1 → 5.7.2.pre
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.markdown +5 -0
- data/lib/scout/command/run.rb +1 -1
- data/lib/scout/server.rb +2 -1
- data/lib/scout/streamer.rb +3 -2
- data/lib/scout/streamer_daemon.rb +4 -4
- data/lib/scout/version.rb +1 -1
- data/test/scout_test.rb +7 -8
- data/vendor/httpclient/README.txt +759 -0
- data/vendor/httpclient/bin/httpclient +65 -0
- data/vendor/httpclient/lib/hexdump.rb +50 -0
- data/vendor/httpclient/lib/http-access2.rb +55 -0
- data/vendor/httpclient/lib/http-access2/cookie.rb +1 -0
- data/vendor/httpclient/lib/http-access2/http.rb +1 -0
- data/vendor/httpclient/lib/httpclient.rb +1156 -0
- data/vendor/httpclient/lib/httpclient/auth.rb +899 -0
- data/vendor/httpclient/lib/httpclient/cacert.p7s +1912 -0
- data/vendor/httpclient/lib/httpclient/connection.rb +88 -0
- data/vendor/httpclient/lib/httpclient/cookie.rb +438 -0
- data/vendor/httpclient/lib/httpclient/http.rb +1046 -0
- data/vendor/httpclient/lib/httpclient/include_client.rb +83 -0
- data/vendor/httpclient/lib/httpclient/session.rb +1025 -0
- data/vendor/httpclient/lib/httpclient/ssl_config.rb +403 -0
- data/vendor/httpclient/lib/httpclient/timeout.rb +140 -0
- data/vendor/httpclient/lib/httpclient/util.rb +178 -0
- data/vendor/httpclient/lib/httpclient/version.rb +3 -0
- data/vendor/httpclient/lib/oauthclient.rb +110 -0
- data/vendor/httpclient/sample/async.rb +8 -0
- data/vendor/httpclient/sample/auth.rb +11 -0
- data/vendor/httpclient/sample/cookie.rb +18 -0
- data/vendor/httpclient/sample/dav.rb +103 -0
- data/vendor/httpclient/sample/howto.rb +49 -0
- data/vendor/httpclient/sample/oauth_buzz.rb +57 -0
- data/vendor/httpclient/sample/oauth_friendfeed.rb +59 -0
- data/vendor/httpclient/sample/oauth_salesforce_10.rb +63 -0
- data/vendor/httpclient/sample/oauth_twitter.rb +61 -0
- data/vendor/httpclient/sample/ssl/0cert.pem +22 -0
- data/vendor/httpclient/sample/ssl/0key.pem +30 -0
- data/vendor/httpclient/sample/ssl/1000cert.pem +19 -0
- data/vendor/httpclient/sample/ssl/1000key.pem +18 -0
- data/vendor/httpclient/sample/ssl/htdocs/index.html +10 -0
- data/vendor/httpclient/sample/ssl/ssl_client.rb +22 -0
- data/vendor/httpclient/sample/ssl/webrick_httpsd.rb +29 -0
- data/vendor/httpclient/sample/stream.rb +21 -0
- data/vendor/httpclient/sample/thread.rb +27 -0
- data/vendor/httpclient/sample/wcat.rb +21 -0
- data/vendor/httpclient/test/ca-chain.cert +44 -0
- data/vendor/httpclient/test/ca.cert +23 -0
- data/vendor/httpclient/test/client.cert +19 -0
- data/vendor/httpclient/test/client.key +15 -0
- data/vendor/httpclient/test/helper.rb +129 -0
- data/vendor/httpclient/test/htdigest +1 -0
- data/vendor/httpclient/test/htpasswd +2 -0
- data/vendor/httpclient/test/runner.rb +2 -0
- data/vendor/httpclient/test/server.cert +19 -0
- data/vendor/httpclient/test/server.key +15 -0
- data/vendor/httpclient/test/sslsvr.rb +65 -0
- data/vendor/httpclient/test/subca.cert +21 -0
- data/vendor/httpclient/test/test_auth.rb +321 -0
- data/vendor/httpclient/test/test_cookie.rb +391 -0
- data/vendor/httpclient/test/test_hexdump.rb +14 -0
- data/vendor/httpclient/test/test_http-access2.rb +507 -0
- data/vendor/httpclient/test/test_httpclient.rb +1783 -0
- data/vendor/httpclient/test/test_include_client.rb +52 -0
- data/vendor/httpclient/test/test_ssl.rb +235 -0
- data/vendor/multi_json/.document +5 -0
- data/vendor/multi_json/.rspec +3 -0
- data/vendor/multi_json/.travis.yml +11 -0
- data/vendor/multi_json/.yardopts +6 -0
- data/vendor/multi_json/CHANGELOG.md +169 -0
- data/vendor/multi_json/CONTRIBUTING.md +46 -0
- data/vendor/multi_json/Gemfile +31 -0
- data/vendor/multi_json/LICENSE.md +20 -0
- data/vendor/multi_json/README.md +109 -0
- data/vendor/multi_json/Rakefile +12 -0
- data/vendor/multi_json/lib/multi_json.rb +157 -0
- data/vendor/multi_json/lib/multi_json/adapter.rb +48 -0
- data/vendor/multi_json/lib/multi_json/adapters/gson.rb +19 -0
- data/vendor/multi_json/lib/multi_json/adapters/jr_jackson.rb +19 -0
- data/vendor/multi_json/lib/multi_json/adapters/json_common.rb +25 -0
- data/vendor/multi_json/lib/multi_json/adapters/json_gem.rb +11 -0
- data/vendor/multi_json/lib/multi_json/adapters/json_pure.rb +11 -0
- data/vendor/multi_json/lib/multi_json/adapters/nsjsonserialization.rb +34 -0
- data/vendor/multi_json/lib/multi_json/adapters/oj.rb +24 -0
- data/vendor/multi_json/lib/multi_json/adapters/ok_json.rb +22 -0
- data/vendor/multi_json/lib/multi_json/adapters/yajl.rb +19 -0
- data/vendor/multi_json/lib/multi_json/convertible_hash_keys.rb +43 -0
- data/vendor/multi_json/lib/multi_json/load_error.rb +11 -0
- data/vendor/multi_json/lib/multi_json/options.rb +48 -0
- data/vendor/multi_json/lib/multi_json/vendor/okjson.rb +606 -0
- data/vendor/multi_json/lib/multi_json/version.rb +20 -0
- data/vendor/multi_json/multi_json.gemspec +22 -0
- data/vendor/multi_json/spec/adapter_shared_example.rb +235 -0
- data/vendor/multi_json/spec/has_options.rb +119 -0
- data/vendor/multi_json/spec/helper.rb +35 -0
- data/vendor/multi_json/spec/json_common_shared_example.rb +30 -0
- data/vendor/multi_json/spec/multi_json_spec.rb +226 -0
- data/vendor/{signature → pusher}/.document +0 -0
- data/vendor/{json_pure/diagrams/.keep → pusher/.gemtest} +0 -0
- data/vendor/pusher/.gitignore +23 -0
- data/vendor/pusher/.travis.yml +15 -0
- data/vendor/pusher/Gemfile +2 -0
- data/vendor/{pusher-gem → pusher}/LICENSE +1 -1
- data/vendor/pusher/README.md +186 -0
- data/vendor/{pusher-gem → pusher}/Rakefile +0 -0
- data/vendor/{pusher-gem → pusher}/examples/async_message.rb +0 -0
- data/vendor/pusher/lib/pusher.rb +60 -0
- data/vendor/{pusher-gem → pusher}/lib/pusher/channel.rb +47 -54
- data/vendor/pusher/lib/pusher/client.rb +306 -0
- data/vendor/pusher/lib/pusher/request.rb +107 -0
- data/vendor/pusher/lib/pusher/resource.rb +36 -0
- data/vendor/pusher/lib/pusher/webhook.rb +110 -0
- data/vendor/{pusher-gem → pusher}/pusher.gemspec +6 -5
- data/vendor/pusher/spec/channel_spec.rb +127 -0
- data/vendor/pusher/spec/client_spec.rb +464 -0
- data/vendor/{pusher-gem → pusher}/spec/spec_helper.rb +12 -0
- data/vendor/pusher/spec/web_hook_spec.rb +117 -0
- data/vendor/signature/.travis.yml +15 -0
- data/vendor/signature/Gemfile +1 -1
- data/vendor/signature/README.md +38 -28
- data/vendor/signature/lib/signature.rb +97 -15
- data/vendor/signature/lib/signature/query_encoder.rb +47 -0
- data/vendor/signature/lib/signature/version.rb +1 -1
- data/vendor/signature/signature.gemspec +3 -2
- data/vendor/signature/spec/signature_spec.rb +164 -55
- data/vendor/signature/spec/spec_helper.rb +2 -3
- metadata +120 -145
- data/vendor/json_pure/.gitignore +0 -12
- data/vendor/json_pure/.travis.yml +0 -20
- data/vendor/json_pure/CHANGES +0 -282
- data/vendor/json_pure/COPYING +0 -58
- data/vendor/json_pure/COPYING-json-jruby +0 -57
- data/vendor/json_pure/GPL +0 -340
- data/vendor/json_pure/Gemfile +0 -11
- data/vendor/json_pure/README-json-jruby.markdown +0 -33
- data/vendor/json_pure/README.rdoc +0 -358
- data/vendor/json_pure/Rakefile +0 -412
- data/vendor/json_pure/TODO +0 -1
- data/vendor/json_pure/VERSION +0 -1
- data/vendor/json_pure/data/example.json +0 -1
- data/vendor/json_pure/data/index.html +0 -38
- data/vendor/json_pure/data/prototype.js +0 -4184
- data/vendor/json_pure/ext/json/ext/fbuffer/fbuffer.h +0 -181
- data/vendor/json_pure/ext/json/ext/generator/depend +0 -1
- data/vendor/json_pure/ext/json/ext/generator/extconf.rb +0 -14
- data/vendor/json_pure/ext/json/ext/generator/generator.c +0 -1435
- data/vendor/json_pure/ext/json/ext/generator/generator.h +0 -148
- data/vendor/json_pure/ext/json/ext/parser/depend +0 -1
- data/vendor/json_pure/ext/json/ext/parser/extconf.rb +0 -13
- data/vendor/json_pure/ext/json/ext/parser/parser.c +0 -2204
- data/vendor/json_pure/ext/json/ext/parser/parser.h +0 -77
- data/vendor/json_pure/ext/json/ext/parser/parser.rl +0 -927
- data/vendor/json_pure/install.rb +0 -23
- data/vendor/json_pure/java/src/json/ext/ByteListTranscoder.java +0 -167
- data/vendor/json_pure/java/src/json/ext/Generator.java +0 -444
- data/vendor/json_pure/java/src/json/ext/GeneratorMethods.java +0 -232
- data/vendor/json_pure/java/src/json/ext/GeneratorService.java +0 -43
- data/vendor/json_pure/java/src/json/ext/GeneratorState.java +0 -543
- data/vendor/json_pure/java/src/json/ext/OptionsReader.java +0 -114
- data/vendor/json_pure/java/src/json/ext/Parser.java +0 -2644
- data/vendor/json_pure/java/src/json/ext/Parser.rl +0 -968
- data/vendor/json_pure/java/src/json/ext/ParserService.java +0 -35
- data/vendor/json_pure/java/src/json/ext/RuntimeInfo.java +0 -121
- data/vendor/json_pure/java/src/json/ext/StringDecoder.java +0 -167
- data/vendor/json_pure/java/src/json/ext/StringEncoder.java +0 -106
- data/vendor/json_pure/java/src/json/ext/Utils.java +0 -89
- data/vendor/json_pure/json-java.gemspec +0 -23
- data/vendor/json_pure/json.gemspec +0 -37
- data/vendor/json_pure/json_pure.gemspec +0 -39
- data/vendor/json_pure/lib/json.rb +0 -62
- data/vendor/json_pure/lib/json/add/bigdecimal.rb +0 -28
- data/vendor/json_pure/lib/json/add/complex.rb +0 -22
- data/vendor/json_pure/lib/json/add/core.rb +0 -11
- data/vendor/json_pure/lib/json/add/date.rb +0 -34
- data/vendor/json_pure/lib/json/add/date_time.rb +0 -50
- data/vendor/json_pure/lib/json/add/exception.rb +0 -31
- data/vendor/json_pure/lib/json/add/ostruct.rb +0 -31
- data/vendor/json_pure/lib/json/add/range.rb +0 -29
- data/vendor/json_pure/lib/json/add/rational.rb +0 -22
- data/vendor/json_pure/lib/json/add/regexp.rb +0 -30
- data/vendor/json_pure/lib/json/add/struct.rb +0 -30
- data/vendor/json_pure/lib/json/add/symbol.rb +0 -25
- data/vendor/json_pure/lib/json/add/time.rb +0 -38
- data/vendor/json_pure/lib/json/common.rb +0 -487
- data/vendor/json_pure/lib/json/ext.rb +0 -21
- data/vendor/json_pure/lib/json/ext/.keep +0 -0
- data/vendor/json_pure/lib/json/generic_object.rb +0 -70
- data/vendor/json_pure/lib/json/pure.rb +0 -21
- data/vendor/json_pure/lib/json/pure/generator.rb +0 -522
- data/vendor/json_pure/lib/json/pure/parser.rb +0 -359
- data/vendor/json_pure/lib/json/version.rb +0 -8
- data/vendor/json_pure/tests/fixtures/fail1.json +0 -1
- data/vendor/json_pure/tests/fixtures/fail10.json +0 -1
- data/vendor/json_pure/tests/fixtures/fail11.json +0 -1
- data/vendor/json_pure/tests/fixtures/fail12.json +0 -1
- data/vendor/json_pure/tests/fixtures/fail13.json +0 -1
- data/vendor/json_pure/tests/fixtures/fail14.json +0 -1
- data/vendor/json_pure/tests/fixtures/fail18.json +0 -1
- data/vendor/json_pure/tests/fixtures/fail19.json +0 -1
- data/vendor/json_pure/tests/fixtures/fail2.json +0 -1
- data/vendor/json_pure/tests/fixtures/fail20.json +0 -1
- data/vendor/json_pure/tests/fixtures/fail21.json +0 -1
- data/vendor/json_pure/tests/fixtures/fail22.json +0 -1
- data/vendor/json_pure/tests/fixtures/fail23.json +0 -1
- data/vendor/json_pure/tests/fixtures/fail24.json +0 -1
- data/vendor/json_pure/tests/fixtures/fail25.json +0 -1
- data/vendor/json_pure/tests/fixtures/fail27.json +0 -2
- data/vendor/json_pure/tests/fixtures/fail28.json +0 -2
- data/vendor/json_pure/tests/fixtures/fail3.json +0 -1
- data/vendor/json_pure/tests/fixtures/fail4.json +0 -1
- data/vendor/json_pure/tests/fixtures/fail5.json +0 -1
- data/vendor/json_pure/tests/fixtures/fail6.json +0 -1
- data/vendor/json_pure/tests/fixtures/fail7.json +0 -1
- data/vendor/json_pure/tests/fixtures/fail8.json +0 -1
- data/vendor/json_pure/tests/fixtures/fail9.json +0 -1
- data/vendor/json_pure/tests/fixtures/pass1.json +0 -56
- data/vendor/json_pure/tests/fixtures/pass15.json +0 -1
- data/vendor/json_pure/tests/fixtures/pass16.json +0 -1
- data/vendor/json_pure/tests/fixtures/pass17.json +0 -1
- data/vendor/json_pure/tests/fixtures/pass2.json +0 -1
- data/vendor/json_pure/tests/fixtures/pass26.json +0 -1
- data/vendor/json_pure/tests/fixtures/pass3.json +0 -6
- data/vendor/json_pure/tests/setup_variant.rb +0 -11
- data/vendor/json_pure/tests/test_json.rb +0 -545
- data/vendor/json_pure/tests/test_json_addition.rb +0 -196
- data/vendor/json_pure/tests/test_json_encoding.rb +0 -65
- data/vendor/json_pure/tests/test_json_fixtures.rb +0 -35
- data/vendor/json_pure/tests/test_json_generate.rb +0 -322
- data/vendor/json_pure/tests/test_json_generic_object.rb +0 -75
- data/vendor/json_pure/tests/test_json_string_matching.rb +0 -39
- data/vendor/json_pure/tests/test_json_unicode.rb +0 -72
- data/vendor/json_pure/tools/fuzz.rb +0 -139
- data/vendor/json_pure/tools/server.rb +0 -62
- data/vendor/pusher-gem/Gemfile +0 -2
- data/vendor/pusher-gem/README.md +0 -80
- data/vendor/pusher-gem/lib/pusher.rb +0 -107
- data/vendor/pusher-gem/lib/pusher/request.rb +0 -107
- data/vendor/pusher-gem/spec/channel_spec.rb +0 -274
- data/vendor/pusher-gem/spec/pusher_spec.rb +0 -87
- data/vendor/ruby-hmac/History.txt +0 -15
- data/vendor/ruby-hmac/Manifest.txt +0 -11
- data/vendor/ruby-hmac/README.md +0 -41
- data/vendor/ruby-hmac/Rakefile +0 -23
- data/vendor/ruby-hmac/lib/hmac-md5.rb +0 -11
- data/vendor/ruby-hmac/lib/hmac-rmd160.rb +0 -11
- data/vendor/ruby-hmac/lib/hmac-sha1.rb +0 -11
- data/vendor/ruby-hmac/lib/hmac-sha2.rb +0 -25
- data/vendor/ruby-hmac/lib/hmac.rb +0 -118
- data/vendor/ruby-hmac/lib/ruby_hmac.rb +0 -2
- data/vendor/ruby-hmac/ruby-hmac.gemspec +0 -33
- data/vendor/ruby-hmac/test/test_hmac.rb +0 -89
- data/vendor/signature/VERSION +0 -1
@@ -0,0 +1,107 @@
|
|
1
|
+
require 'signature'
|
2
|
+
require 'digest/md5'
|
3
|
+
require 'multi_json'
|
4
|
+
|
5
|
+
module Pusher
|
6
|
+
class Request
|
7
|
+
attr_reader :body, :params
|
8
|
+
|
9
|
+
def initialize(client, verb, uri, params, body = nil)
|
10
|
+
@client, @verb, @uri = client, verb, uri
|
11
|
+
@head = {}
|
12
|
+
|
13
|
+
@body = body
|
14
|
+
if body
|
15
|
+
params[:body_md5] = Digest::MD5.hexdigest(body)
|
16
|
+
@head['Content-Type'] = 'application/json'
|
17
|
+
end
|
18
|
+
|
19
|
+
request = Signature::Request.new(verb.to_s.upcase, uri.path, params)
|
20
|
+
request.sign(client.authentication_token)
|
21
|
+
@params = request.signed_params
|
22
|
+
end
|
23
|
+
|
24
|
+
def send_sync
|
25
|
+
http = @client.sync_http_client
|
26
|
+
|
27
|
+
begin
|
28
|
+
response = http.request(@verb, @uri, @params, @body, @head)
|
29
|
+
rescue HTTPClient::BadResponseError, HTTPClient::TimeoutError,
|
30
|
+
SocketError, Errno::ECONNREFUSED => e
|
31
|
+
error = Pusher::HTTPError.new("#{e.message} (#{e.class})")
|
32
|
+
error.original_error = e
|
33
|
+
raise error
|
34
|
+
end
|
35
|
+
|
36
|
+
body = response.body ? response.body.chomp : nil
|
37
|
+
|
38
|
+
return handle_response(response.code.to_i, body)
|
39
|
+
end
|
40
|
+
|
41
|
+
def send_async
|
42
|
+
if defined?(EventMachine) && EventMachine.reactor_running?
|
43
|
+
http_client = @client.em_http_client(@uri)
|
44
|
+
df = EM::DefaultDeferrable.new
|
45
|
+
|
46
|
+
http = case @verb
|
47
|
+
when :post
|
48
|
+
http_client.post({
|
49
|
+
:query => @params, :body => @body, :head => @head
|
50
|
+
})
|
51
|
+
when :get
|
52
|
+
http_client.get({
|
53
|
+
:query => @params, :head => @head
|
54
|
+
})
|
55
|
+
else
|
56
|
+
raise "Unsuported verb"
|
57
|
+
end
|
58
|
+
http.callback {
|
59
|
+
begin
|
60
|
+
df.succeed(handle_response(http.response_header.status, http.response.chomp))
|
61
|
+
rescue => e
|
62
|
+
df.fail(e)
|
63
|
+
end
|
64
|
+
}
|
65
|
+
http.errback { |e|
|
66
|
+
message = "Network error connecting to pusher (#{http.error})"
|
67
|
+
Pusher.logger.debug(message)
|
68
|
+
df.fail(Error.new(message))
|
69
|
+
}
|
70
|
+
|
71
|
+
return df
|
72
|
+
else
|
73
|
+
http = @client.sync_http_client
|
74
|
+
|
75
|
+
return http.request_async(@verb, @uri, @params, @body, @head)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
private
|
80
|
+
|
81
|
+
def handle_response(status_code, body)
|
82
|
+
case status_code
|
83
|
+
when 200
|
84
|
+
return symbolize_first_level(MultiJson.decode(body))
|
85
|
+
when 202
|
86
|
+
return true
|
87
|
+
when 400
|
88
|
+
raise Error, "Bad request: #{body}"
|
89
|
+
when 401
|
90
|
+
raise AuthenticationError, body
|
91
|
+
when 404
|
92
|
+
raise Error, "404 Not found (#{@uri.path})"
|
93
|
+
when 407
|
94
|
+
raise Error, "Proxy Authentication Required"
|
95
|
+
else
|
96
|
+
raise Error, "Unknown error (status code #{status_code}): #{body}"
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def symbolize_first_level(hash)
|
101
|
+
hash.inject({}) do |result, (key, value)|
|
102
|
+
result[key.to_sym] = value
|
103
|
+
result
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Pusher
|
2
|
+
class Resource
|
3
|
+
def initialize(client, path)
|
4
|
+
@client = client
|
5
|
+
@path = path
|
6
|
+
end
|
7
|
+
|
8
|
+
def get(params)
|
9
|
+
create_request(:get, params).send_sync
|
10
|
+
end
|
11
|
+
|
12
|
+
def get_async(params)
|
13
|
+
create_request(:get, params).send_async
|
14
|
+
end
|
15
|
+
|
16
|
+
def post(params)
|
17
|
+
body = MultiJson.encode(params)
|
18
|
+
create_request(:post, {}, body).send_sync
|
19
|
+
end
|
20
|
+
|
21
|
+
def post_async(params)
|
22
|
+
body = MultiJson.encode(params)
|
23
|
+
create_request(:post, {}, body).send_async
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def create_request(verb, params, body = nil)
|
29
|
+
Request.new(@client, verb, url, params, body)
|
30
|
+
end
|
31
|
+
|
32
|
+
def url
|
33
|
+
@_url ||= @client.url(@path)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
require 'multi_json'
|
2
|
+
require 'openssl'
|
3
|
+
|
4
|
+
module Pusher
|
5
|
+
# Used to parse and authenticate WebHooks
|
6
|
+
#
|
7
|
+
# @example Sinatra
|
8
|
+
# post '/webhooks' do
|
9
|
+
# webhook = Pusher::WebHook.new(request)
|
10
|
+
# if webhook.valid?
|
11
|
+
# webhook.events.each do |event|
|
12
|
+
# case event["name"]
|
13
|
+
# when 'channel_occupied'
|
14
|
+
# puts "Channel occupied: #{event["channel"]}"
|
15
|
+
# when 'channel_vacated'
|
16
|
+
# puts "Channel vacated: #{event["channel"]}"
|
17
|
+
# end
|
18
|
+
# end
|
19
|
+
# else
|
20
|
+
# status 401
|
21
|
+
# end
|
22
|
+
# return
|
23
|
+
# end
|
24
|
+
#
|
25
|
+
class WebHook
|
26
|
+
attr_reader :key, :signature
|
27
|
+
|
28
|
+
# Provide either a Rack::Request or a Hash containing :key, :signature,
|
29
|
+
# :body, and :content_type (optional)
|
30
|
+
#
|
31
|
+
def initialize(request, client = Pusher)
|
32
|
+
@client = client
|
33
|
+
# Should work without Rack
|
34
|
+
if defined?(Rack::Request) && request.kind_of?(Rack::Request)
|
35
|
+
@key = request.env['HTTP_X_PUSHER_KEY']
|
36
|
+
@signature = request.env["HTTP_X_PUSHER_SIGNATURE"]
|
37
|
+
@content_type = request.content_type
|
38
|
+
|
39
|
+
request.body.rewind
|
40
|
+
@body = request.body.read
|
41
|
+
request.body.rewind
|
42
|
+
else
|
43
|
+
@key, @signature, @body = request.values_at(:key, :signature, :body)
|
44
|
+
@content_type = request[:content_type] || 'application/json'
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# Returns whether the WebHook is valid by checking that the signature
|
49
|
+
# matches the configured key & secret. In the case that the webhook is
|
50
|
+
# invalid, the reason is logged
|
51
|
+
#
|
52
|
+
# @param extra_tokens [Hash] If you have extra tokens for your Pusher app, you can specify them so that they're used to attempt validation.
|
53
|
+
#
|
54
|
+
def valid?(extra_tokens = nil)
|
55
|
+
extra_tokens = [extra_tokens] if extra_tokens.kind_of?(Hash)
|
56
|
+
if @key == @client.key
|
57
|
+
return check_signature(@client.secret)
|
58
|
+
elsif extra_tokens
|
59
|
+
extra_tokens.each do |token|
|
60
|
+
return check_signature(token[:secret]) if @key == token[:key]
|
61
|
+
end
|
62
|
+
end
|
63
|
+
Pusher.logger.warn "Received webhook with unknown key: #{key}"
|
64
|
+
return false
|
65
|
+
end
|
66
|
+
|
67
|
+
# Array of events (as Hashes) contained inside the webhook
|
68
|
+
#
|
69
|
+
def events
|
70
|
+
data["events"]
|
71
|
+
end
|
72
|
+
|
73
|
+
# The time at which the WebHook was initially triggered by Pusher, i.e.
|
74
|
+
# when the event occurred
|
75
|
+
#
|
76
|
+
# @return [Time]
|
77
|
+
#
|
78
|
+
def time
|
79
|
+
Time.at(data["time_ms"].to_f/1000)
|
80
|
+
end
|
81
|
+
|
82
|
+
# Access the parsed WebHook body
|
83
|
+
#
|
84
|
+
def data
|
85
|
+
@data ||= begin
|
86
|
+
case @content_type
|
87
|
+
when 'application/json'
|
88
|
+
MultiJson.decode(@body)
|
89
|
+
else
|
90
|
+
raise "Unknown Content-Type (#{@content_type})"
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
private
|
96
|
+
|
97
|
+
# Checks signature against secret and returns boolean
|
98
|
+
#
|
99
|
+
def check_signature(secret)
|
100
|
+
digest = OpenSSL::Digest::SHA256.new
|
101
|
+
expected = OpenSSL::HMAC.hexdigest(digest, secret, @body)
|
102
|
+
if @signature == expected
|
103
|
+
return true
|
104
|
+
else
|
105
|
+
Pusher.logger.warn "Received WebHook with invalid signature: got #{@signature}, expected #{expected}"
|
106
|
+
return false
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
@@ -3,7 +3,7 @@ $:.push File.expand_path("../lib", __FILE__)
|
|
3
3
|
|
4
4
|
Gem::Specification.new do |s|
|
5
5
|
s.name = "pusher"
|
6
|
-
s.version = "0.
|
6
|
+
s.version = "0.12.0"
|
7
7
|
s.platform = Gem::Platform::RUBY
|
8
8
|
s.authors = ["Pusher"]
|
9
9
|
s.email = ["support@pusher.com"]
|
@@ -12,14 +12,15 @@ Gem::Specification.new do |s|
|
|
12
12
|
s.description = %q{Wrapper for pusher.com REST api}
|
13
13
|
|
14
14
|
s.add_dependency "multi_json", "~> 1.0"
|
15
|
-
s.add_dependency
|
16
|
-
s.add_dependency "
|
17
|
-
s.add_dependency
|
15
|
+
s.add_dependency 'signature', "~> 0.1.6"
|
16
|
+
s.add_dependency "httpclient", "~> 2.3.0"
|
17
|
+
s.add_dependency "jruby-openssl" if defined?(JRUBY_VERSION)
|
18
18
|
|
19
19
|
s.add_development_dependency "rspec", "~> 2.0"
|
20
20
|
s.add_development_dependency "webmock"
|
21
|
-
s.add_development_dependency "em-http-request", "~> 1.
|
21
|
+
s.add_development_dependency "em-http-request", "~> 1.1.0"
|
22
22
|
s.add_development_dependency "rake"
|
23
|
+
s.add_development_dependency "rack"
|
23
24
|
|
24
25
|
s.files = `git ls-files`.split("\n")
|
25
26
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
@@ -0,0 +1,127 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Pusher::Channel do
|
4
|
+
before do
|
5
|
+
@client = Pusher::Client.new({
|
6
|
+
:app_id => '20',
|
7
|
+
:key => '12345678900000001',
|
8
|
+
:secret => '12345678900000001',
|
9
|
+
:host => 'api.pusherapp.com',
|
10
|
+
:port => 80,
|
11
|
+
})
|
12
|
+
@channel = @client['test_channel']
|
13
|
+
end
|
14
|
+
|
15
|
+
let(:pusher_url_regexp) { %r{/apps/20/events} }
|
16
|
+
|
17
|
+
def stub_post(status, body = nil)
|
18
|
+
options = {:status => status}
|
19
|
+
options.merge!({:body => body}) if body
|
20
|
+
|
21
|
+
stub_request(:post, pusher_url_regexp).to_return(options)
|
22
|
+
end
|
23
|
+
|
24
|
+
def stub_post_to_raise(e)
|
25
|
+
stub_request(:post, pusher_url_regexp).to_raise(e)
|
26
|
+
end
|
27
|
+
|
28
|
+
describe '#trigger!' do
|
29
|
+
it "should use @client.trigger internally" do
|
30
|
+
@client.should_receive(:trigger)
|
31
|
+
@channel.trigger('new_event', 'Some data')
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe '#trigger' do
|
36
|
+
it "should log failure if error raised in http call" do
|
37
|
+
stub_post_to_raise(HTTPClient::BadResponseError)
|
38
|
+
|
39
|
+
Pusher.logger.should_receive(:error).with("Exception from WebMock (HTTPClient::BadResponseError) (Pusher::HTTPError)")
|
40
|
+
Pusher.logger.should_receive(:debug) #backtrace
|
41
|
+
channel = Pusher::Channel.new(@client.url, 'test_channel', @client)
|
42
|
+
channel.trigger('new_event', 'Some data')
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should log failure if Pusher returns an error response" do
|
46
|
+
stub_post 401, "some signature info"
|
47
|
+
Pusher.logger.should_receive(:error).with("some signature info (Pusher::AuthenticationError)")
|
48
|
+
Pusher.logger.should_receive(:debug) #backtrace
|
49
|
+
channel = Pusher::Channel.new(@client.url, 'test_channel', @client)
|
50
|
+
channel.trigger('new_event', 'Some data')
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
describe "#trigger_async" do
|
55
|
+
it "should use @client.trigger_async internally" do
|
56
|
+
@client.should_receive(:trigger_async)
|
57
|
+
@channel.trigger_async('new_event', 'Some data')
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
describe '#info' do
|
62
|
+
it "should call the Client#channel_info" do
|
63
|
+
@client.should_receive(:get).with("/channels/mychannel", anything)
|
64
|
+
@channel = @client['mychannel']
|
65
|
+
@channel.info
|
66
|
+
end
|
67
|
+
|
68
|
+
it "should assemble the requested attribes into the info option" do
|
69
|
+
@client.should_receive(:get).with(anything, {
|
70
|
+
:info => "user_count,connection_count"
|
71
|
+
})
|
72
|
+
@channel = @client['presence-foo']
|
73
|
+
@channel.info(%w{user_count connection_count})
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
describe "#authentication_string" do
|
78
|
+
def authentication_string(*data)
|
79
|
+
lambda { @channel.authentication_string(*data) }
|
80
|
+
end
|
81
|
+
|
82
|
+
it "should return an authentication string given a socket id" do
|
83
|
+
auth = @channel.authentication_string('socketid')
|
84
|
+
|
85
|
+
auth.should == '12345678900000001:827076f551e22451357939e4c7bb1200de29f921d5bf80b40d71668f9cd61c40'
|
86
|
+
end
|
87
|
+
|
88
|
+
it "should raise error if authentication is invalid" do
|
89
|
+
[nil, ''].each do |invalid|
|
90
|
+
authentication_string(invalid).should raise_error Pusher::Error
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
describe 'with extra string argument' do
|
95
|
+
it 'should be a string or nil' do
|
96
|
+
authentication_string('socketid', 123).should raise_error Pusher::Error
|
97
|
+
authentication_string('socketid', {}).should raise_error Pusher::Error
|
98
|
+
|
99
|
+
authentication_string('socketid', 'boom').should_not raise_error
|
100
|
+
authentication_string('socketid', nil).should_not raise_error
|
101
|
+
end
|
102
|
+
|
103
|
+
it "should return an authentication string given a socket id and custom args" do
|
104
|
+
auth = @channel.authentication_string('socketid', 'foobar')
|
105
|
+
|
106
|
+
auth.should == "12345678900000001:#{hmac(@client.secret, "socketid:test_channel:foobar")}"
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
describe '#authenticate' do
|
112
|
+
before :each do
|
113
|
+
@custom_data = {:uid => 123, :info => {:name => 'Foo'}}
|
114
|
+
end
|
115
|
+
|
116
|
+
it 'should return a hash with signature including custom data and data as json string' do
|
117
|
+
MultiJson.stub(:encode).with(@custom_data).and_return 'a json string'
|
118
|
+
|
119
|
+
response = @channel.authenticate('socketid', @custom_data)
|
120
|
+
|
121
|
+
response.should == {
|
122
|
+
:auth => "12345678900000001:#{hmac(@client.secret, "socketid:test_channel:a json string")}",
|
123
|
+
:channel_data => 'a json string'
|
124
|
+
}
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
@@ -0,0 +1,464 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
require 'em-http'
|
4
|
+
|
5
|
+
describe Pusher do
|
6
|
+
describe 'using multiple Client objects' do
|
7
|
+
before :each do
|
8
|
+
@client1 = Pusher::Client.new
|
9
|
+
@client2 = Pusher::Client.new
|
10
|
+
|
11
|
+
@client1.scheme = 'ws'
|
12
|
+
@client2.scheme = 'wss'
|
13
|
+
@client1.host = 'one'
|
14
|
+
@client2.host = 'two'
|
15
|
+
@client1.port = 81
|
16
|
+
@client2.port = 82
|
17
|
+
@client1.app_id = '1111'
|
18
|
+
@client2.app_id = '2222'
|
19
|
+
@client1.key = 'AAAA'
|
20
|
+
@client2.key = 'BBBB'
|
21
|
+
@client1.secret = 'aaaaaaaa'
|
22
|
+
@client2.secret = 'bbbbbbbb'
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should send scheme messages to different objects" do
|
26
|
+
@client1.scheme.should_not == @client2.scheme
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should send host messages to different objects" do
|
30
|
+
@client1.host.should_not == @client2.host
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should send port messages to different objects" do
|
34
|
+
@client1.port.should_not == @client2.port
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should send app_id messages to different objects" do
|
38
|
+
@client1.app_id.should_not == @client2.app_id
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should send app_id messages to different objects" do
|
42
|
+
@client1.key.should_not == @client2.key
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should send app_id messages to different objects" do
|
46
|
+
@client1.secret.should_not == @client2.secret
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should send app_id messages to different objects" do
|
50
|
+
@client1.authentication_token.key.should_not == @client2.authentication_token.key
|
51
|
+
@client1.authentication_token.secret.should_not == @client2.authentication_token.secret
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should send url messages to different objects" do
|
55
|
+
@client1.url.to_s.should_not == @client2.url.to_s
|
56
|
+
@client1.url = 'ws://one/apps/111'
|
57
|
+
@client2.url = 'wss://two/apps/222'
|
58
|
+
@client1.scheme.should_not == @client2.scheme
|
59
|
+
@client1.host.should_not == @client2.host
|
60
|
+
@client1.app_id.should_not == @client2.app_id
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should send encrypted messages to different objects" do
|
64
|
+
@client1.encrypted = false
|
65
|
+
@client2.encrypted = true
|
66
|
+
@client1.scheme.should_not == @client2.scheme
|
67
|
+
@client1.port.should_not == @client2.port
|
68
|
+
end
|
69
|
+
|
70
|
+
it "should send [] messages to different objects" do
|
71
|
+
@client1['test'].should_not == @client2['test']
|
72
|
+
end
|
73
|
+
|
74
|
+
it "should send http_proxy messages to different objects" do
|
75
|
+
@client1.http_proxy = 'http://oneuser:onepassword@onehost:8080'
|
76
|
+
@client2.http_proxy = 'http://twouser:twopassword@twohost:8880'
|
77
|
+
@client1.http_proxy.should_not == @client2.http_proxy
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
# The behaviour should be the same when using the Client object, or the
|
82
|
+
# 'global' client delegated through the Pusher class
|
83
|
+
[lambda { Pusher }, lambda { Pusher::Client.new }].each do |client_gen|
|
84
|
+
before :each do
|
85
|
+
@client = client_gen.call
|
86
|
+
end
|
87
|
+
|
88
|
+
describe 'default configuration' do
|
89
|
+
it 'should be preconfigured for api host' do
|
90
|
+
@client.host.should == 'api.pusherapp.com'
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'should be preconfigured for port 80' do
|
94
|
+
@client.port.should == 80
|
95
|
+
end
|
96
|
+
|
97
|
+
it 'should use standard logger if no other logger if defined' do
|
98
|
+
Pusher.logger.debug('foo')
|
99
|
+
Pusher.logger.should be_kind_of(Logger)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
describe 'logging configuration' do
|
104
|
+
it "can be configured to use any logger" do
|
105
|
+
logger = double("ALogger")
|
106
|
+
logger.should_receive(:debug).with('foo')
|
107
|
+
Pusher.logger = logger
|
108
|
+
Pusher.logger.debug('foo')
|
109
|
+
Pusher.logger = nil
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
describe "configuration using url" do
|
114
|
+
it "should be possible to configure everything by setting the url" do
|
115
|
+
@client.url = "test://somekey:somesecret@api.staging.pusherapp.com:8080/apps/87"
|
116
|
+
|
117
|
+
@client.scheme.should == 'test'
|
118
|
+
@client.host.should == 'api.staging.pusherapp.com'
|
119
|
+
@client.port.should == 8080
|
120
|
+
@client.key.should == 'somekey'
|
121
|
+
@client.secret.should == 'somesecret'
|
122
|
+
@client.app_id.should == '87'
|
123
|
+
end
|
124
|
+
|
125
|
+
it "should override scheme and port when setting encrypted=true after url" do
|
126
|
+
@client.url = "http://somekey:somesecret@api.staging.pusherapp.com:8080/apps/87"
|
127
|
+
@client.encrypted = true
|
128
|
+
|
129
|
+
@client.scheme.should == 'https'
|
130
|
+
@client.port.should == 443
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
describe 'configuring a http proxy' do
|
135
|
+
it "should be possible to configure everything by setting the http_proxy" do
|
136
|
+
@client.http_proxy = 'http://someuser:somepassword@proxy.host.com:8080'
|
137
|
+
|
138
|
+
@client.proxy.should == {:scheme => 'http', :host => 'proxy.host.com', :port => 8080, :user => 'someuser', :password => 'somepassword'}
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
describe 'when configured' do
|
143
|
+
before :each do
|
144
|
+
@client.app_id = '20'
|
145
|
+
@client.key = '12345678900000001'
|
146
|
+
@client.secret = '12345678900000001'
|
147
|
+
end
|
148
|
+
|
149
|
+
describe '#[]' do
|
150
|
+
before do
|
151
|
+
@channel = @client['test_channel']
|
152
|
+
end
|
153
|
+
|
154
|
+
it 'should return a channel' do
|
155
|
+
@channel.should be_kind_of(Pusher::Channel)
|
156
|
+
end
|
157
|
+
|
158
|
+
%w{app_id key secret}.each do |config|
|
159
|
+
it "should raise exception if #{config} not configured" do
|
160
|
+
@client.send("#{config}=", nil)
|
161
|
+
lambda {
|
162
|
+
@client['test_channel']
|
163
|
+
}.should raise_error(Pusher::ConfigurationError)
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
describe '#channels' do
|
169
|
+
it "should call the correct URL and symbolise response correctly" do
|
170
|
+
api_path = %r{/apps/20/channels}
|
171
|
+
stub_request(:get, api_path).to_return({
|
172
|
+
:status => 200,
|
173
|
+
:body => MultiJson.encode('channels' => {
|
174
|
+
"channel1" => {},
|
175
|
+
"channel2" => {}
|
176
|
+
})
|
177
|
+
})
|
178
|
+
@client.channels.should == {
|
179
|
+
:channels => {
|
180
|
+
"channel1" => {},
|
181
|
+
"channel2" => {}
|
182
|
+
}
|
183
|
+
}
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
describe '#channel_info' do
|
188
|
+
it "should call correct URL and symbolise response" do
|
189
|
+
api_path = %r{/apps/20/channels/mychannel}
|
190
|
+
stub_request(:get, api_path).to_return({
|
191
|
+
:status => 200,
|
192
|
+
:body => MultiJson.encode({
|
193
|
+
'occupied' => false,
|
194
|
+
})
|
195
|
+
})
|
196
|
+
@client.channel_info('mychannel').should == {
|
197
|
+
:occupied => false,
|
198
|
+
}
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
describe '#trigger' do
|
203
|
+
before :each do
|
204
|
+
@api_path = %r{/apps/20/events}
|
205
|
+
stub_request(:post, @api_path).to_return({
|
206
|
+
:status => 200,
|
207
|
+
:body => MultiJson.encode({})
|
208
|
+
})
|
209
|
+
end
|
210
|
+
|
211
|
+
it "should call correct URL" do
|
212
|
+
@client.trigger(['mychannel'], 'event', {'some' => 'data'}).
|
213
|
+
should == {}
|
214
|
+
end
|
215
|
+
|
216
|
+
it "should pass any parameters in the body of the request" do
|
217
|
+
@client.trigger(['mychannel', 'c2'], 'event', {'some' => 'data'}, {
|
218
|
+
:socket_id => "1234"
|
219
|
+
})
|
220
|
+
WebMock.should have_requested(:post, @api_path).with { |req|
|
221
|
+
parsed = MultiJson.decode(req.body)
|
222
|
+
parsed["name"].should == 'event'
|
223
|
+
parsed["channels"].should == ["mychannel", "c2"]
|
224
|
+
parsed["socket_id"].should == '1234'
|
225
|
+
}
|
226
|
+
end
|
227
|
+
|
228
|
+
it "should convert non string data to JSON before posting" do
|
229
|
+
@client.trigger(['mychannel'], 'event', {'some' => 'data'})
|
230
|
+
WebMock.should have_requested(:post, @api_path).with { |req|
|
231
|
+
MultiJson.decode(req.body)["data"].should == '{"some":"data"}'
|
232
|
+
}
|
233
|
+
end
|
234
|
+
|
235
|
+
it "should accept a single channel as well as an array" do
|
236
|
+
@client.trigger('mychannel', 'event', {'some' => 'data'})
|
237
|
+
WebMock.should have_requested(:post, @api_path).with { |req|
|
238
|
+
MultiJson.decode(req.body)["channels"].should == ['mychannel']
|
239
|
+
}
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
describe '#trigger_async' do
|
244
|
+
before :each do
|
245
|
+
@api_path = %r{/apps/20/events}
|
246
|
+
stub_request(:post, @api_path).to_return({
|
247
|
+
:status => 200,
|
248
|
+
:body => MultiJson.encode({})
|
249
|
+
})
|
250
|
+
end
|
251
|
+
|
252
|
+
it "should call correct URL" do
|
253
|
+
EM.run {
|
254
|
+
@client.trigger_async('mychannel', 'event', {'some' => 'data'}).callback { |r|
|
255
|
+
r.should == {}
|
256
|
+
EM.stop
|
257
|
+
}
|
258
|
+
}
|
259
|
+
end
|
260
|
+
|
261
|
+
it "should pass any parameters in the body of the request" do
|
262
|
+
EM.run {
|
263
|
+
@client.trigger_async('mychannel', 'event', {'some' => 'data'}, {
|
264
|
+
:socket_id => "1234"
|
265
|
+
}).callback {
|
266
|
+
WebMock.should have_requested(:post, @api_path).with { |req|
|
267
|
+
MultiJson.decode(req.body)["socket_id"].should == '1234'
|
268
|
+
}
|
269
|
+
EM.stop
|
270
|
+
}
|
271
|
+
}
|
272
|
+
end
|
273
|
+
|
274
|
+
it "should convert non string data to JSON before posting" do
|
275
|
+
EM.run {
|
276
|
+
@client.trigger_async('mychannel', 'event', {'some' => 'data'}).callback {
|
277
|
+
WebMock.should have_requested(:post, @api_path).with { |req|
|
278
|
+
MultiJson.decode(req.body)["data"].should == '{"some":"data"}'
|
279
|
+
}
|
280
|
+
EM.stop
|
281
|
+
}
|
282
|
+
}
|
283
|
+
end
|
284
|
+
end
|
285
|
+
|
286
|
+
[:get, :post].each do |verb|
|
287
|
+
describe "##{verb}" do
|
288
|
+
before :each do
|
289
|
+
@url_regexp = %r{api.pusherapp.com}
|
290
|
+
stub_request(verb, @url_regexp).
|
291
|
+
to_return(:status => 200, :body => "{}")
|
292
|
+
end
|
293
|
+
|
294
|
+
let(:call_api) { @client.send(verb, '/path') }
|
295
|
+
|
296
|
+
it "should use http by default" do
|
297
|
+
call_api
|
298
|
+
WebMock.should have_requested(verb, %r{http://api.pusherapp.com/apps/20/path})
|
299
|
+
end
|
300
|
+
|
301
|
+
it "should use https if configured" do
|
302
|
+
@client.encrypted = true
|
303
|
+
call_api
|
304
|
+
WebMock.should have_requested(verb, %r{https://api.pusherapp.com})
|
305
|
+
end
|
306
|
+
|
307
|
+
it "should format the respose hash with symbols at first level" do
|
308
|
+
stub_request(verb, @url_regexp).to_return({
|
309
|
+
:status => 200,
|
310
|
+
:body => MultiJson.encode({'something' => {'a' => 'hash'}})
|
311
|
+
})
|
312
|
+
call_api.should == {
|
313
|
+
:something => {'a' => 'hash'}
|
314
|
+
}
|
315
|
+
end
|
316
|
+
|
317
|
+
it "should catch all http exceptions and raise a Pusher::HTTPError wrapping the original error" do
|
318
|
+
stub_request(verb, @url_regexp).to_raise(HTTPClient::TimeoutError)
|
319
|
+
|
320
|
+
error = nil
|
321
|
+
begin
|
322
|
+
call_api
|
323
|
+
rescue => e
|
324
|
+
error = e
|
325
|
+
end
|
326
|
+
|
327
|
+
error.class.should == Pusher::HTTPError
|
328
|
+
error.should be_kind_of(Pusher::Error)
|
329
|
+
error.message.should == 'Exception from WebMock (HTTPClient::TimeoutError)'
|
330
|
+
error.original_error.class.should == HTTPClient::TimeoutError
|
331
|
+
end
|
332
|
+
|
333
|
+
it "should raise Pusher::Error if call returns 400" do
|
334
|
+
stub_request(verb, @url_regexp).to_return({:status => 400})
|
335
|
+
lambda { call_api }.should raise_error(Pusher::Error)
|
336
|
+
end
|
337
|
+
|
338
|
+
it "should raise AuthenticationError if pusher returns 401" do
|
339
|
+
stub_request(verb, @url_regexp).to_return({:status => 401})
|
340
|
+
lambda { call_api }.should raise_error(Pusher::AuthenticationError)
|
341
|
+
end
|
342
|
+
|
343
|
+
it "should raise Pusher::Error if pusher returns 404" do
|
344
|
+
stub_request(verb, @url_regexp).to_return({:status => 404})
|
345
|
+
lambda { call_api }.should raise_error(Pusher::Error, '404 Not found (/apps/20/path)')
|
346
|
+
end
|
347
|
+
|
348
|
+
it "should raise Pusher::Error if pusher returns 407" do
|
349
|
+
stub_request(verb, @url_regexp).to_return({:status => 407})
|
350
|
+
lambda { call_api }.should raise_error(Pusher::Error, 'Proxy Authentication Required')
|
351
|
+
end
|
352
|
+
|
353
|
+
it "should raise Pusher::Error if pusher returns 500" do
|
354
|
+
stub_request(verb, @url_regexp).to_return({:status => 500, :body => "some error"})
|
355
|
+
lambda { call_api }.should raise_error(Pusher::Error, 'Unknown error (status code 500): some error')
|
356
|
+
end
|
357
|
+
end
|
358
|
+
end
|
359
|
+
|
360
|
+
describe "async calling without eventmachine" do
|
361
|
+
[[:get, :get_async], [:post, :post_async]].each do |verb, method|
|
362
|
+
describe "##{method}" do
|
363
|
+
before :each do
|
364
|
+
@url_regexp = %r{api.pusherapp.com}
|
365
|
+
stub_request(verb, @url_regexp).
|
366
|
+
to_return(:status => 200, :body => "{}")
|
367
|
+
end
|
368
|
+
|
369
|
+
let(:call_api) {
|
370
|
+
@client.send(method, '/path').tap { |c|
|
371
|
+
# Allow the async thread (inside httpclient) to run
|
372
|
+
while !c.finished?
|
373
|
+
sleep 0.01
|
374
|
+
end
|
375
|
+
}
|
376
|
+
}
|
377
|
+
|
378
|
+
it "should use http by default" do
|
379
|
+
call_api
|
380
|
+
WebMock.should have_requested(verb, %r{http://api.pusherapp.com/apps/20/path})
|
381
|
+
end
|
382
|
+
|
383
|
+
it "should use https if configured" do
|
384
|
+
@client.encrypted = true
|
385
|
+
call_api
|
386
|
+
WebMock.should have_requested(verb, %r{https://api.pusherapp.com})
|
387
|
+
end
|
388
|
+
|
389
|
+
# Note that the raw httpclient connection object is returned and
|
390
|
+
# the response isn't handled (by handle_response) in the normal way.
|
391
|
+
it "should return a httpclient connection object" do
|
392
|
+
connection = call_api
|
393
|
+
connection.finished?.should be_true
|
394
|
+
response = connection.pop
|
395
|
+
response.status.should == 200
|
396
|
+
response.body.read.should == "{}"
|
397
|
+
end
|
398
|
+
end
|
399
|
+
end
|
400
|
+
end
|
401
|
+
|
402
|
+
describe "async calling with eventmachine" do
|
403
|
+
[[:get, :get_async], [:post, :post_async]].each do |verb, method|
|
404
|
+
describe "##{method}" do
|
405
|
+
before :each do
|
406
|
+
@url_regexp = %r{api.pusherapp.com}
|
407
|
+
stub_request(verb, @url_regexp).
|
408
|
+
to_return(:status => 200, :body => "{}")
|
409
|
+
end
|
410
|
+
|
411
|
+
let(:call_api) { @client.send(method, '/path') }
|
412
|
+
|
413
|
+
it "should use http by default" do
|
414
|
+
EM.run {
|
415
|
+
call_api.callback {
|
416
|
+
WebMock.should have_requested(verb, %r{http://api.pusherapp.com/apps/20/path})
|
417
|
+
EM.stop
|
418
|
+
}
|
419
|
+
}
|
420
|
+
end
|
421
|
+
|
422
|
+
it "should use https if configured" do
|
423
|
+
EM.run {
|
424
|
+
@client.encrypted = true
|
425
|
+
call_api.callback {
|
426
|
+
WebMock.should have_requested(verb, %r{https://api.pusherapp.com})
|
427
|
+
EM.stop
|
428
|
+
}
|
429
|
+
}
|
430
|
+
end
|
431
|
+
|
432
|
+
it "should format the respose hash with symbols at first level" do
|
433
|
+
EM.run {
|
434
|
+
stub_request(verb, @url_regexp).to_return({
|
435
|
+
:status => 200,
|
436
|
+
:body => MultiJson.encode({'something' => {'a' => 'hash'}})
|
437
|
+
})
|
438
|
+
call_api.callback { |response|
|
439
|
+
response.should == {
|
440
|
+
:something => {'a' => 'hash'}
|
441
|
+
}
|
442
|
+
EM.stop
|
443
|
+
}
|
444
|
+
}
|
445
|
+
end
|
446
|
+
|
447
|
+
it "should errback with Pusher::Error on unsuccessful response" do
|
448
|
+
EM.run {
|
449
|
+
stub_request(verb, @url_regexp).to_return({:status => 400})
|
450
|
+
|
451
|
+
call_api.errback { |e|
|
452
|
+
e.class.should == Pusher::Error
|
453
|
+
EM.stop
|
454
|
+
}.callback {
|
455
|
+
fail
|
456
|
+
}
|
457
|
+
}
|
458
|
+
end
|
459
|
+
end
|
460
|
+
end
|
461
|
+
end
|
462
|
+
end
|
463
|
+
end
|
464
|
+
end
|