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.
Files changed (251) hide show
  1. data/CHANGELOG.markdown +5 -0
  2. data/lib/scout/command/run.rb +1 -1
  3. data/lib/scout/server.rb +2 -1
  4. data/lib/scout/streamer.rb +3 -2
  5. data/lib/scout/streamer_daemon.rb +4 -4
  6. data/lib/scout/version.rb +1 -1
  7. data/test/scout_test.rb +7 -8
  8. data/vendor/httpclient/README.txt +759 -0
  9. data/vendor/httpclient/bin/httpclient +65 -0
  10. data/vendor/httpclient/lib/hexdump.rb +50 -0
  11. data/vendor/httpclient/lib/http-access2.rb +55 -0
  12. data/vendor/httpclient/lib/http-access2/cookie.rb +1 -0
  13. data/vendor/httpclient/lib/http-access2/http.rb +1 -0
  14. data/vendor/httpclient/lib/httpclient.rb +1156 -0
  15. data/vendor/httpclient/lib/httpclient/auth.rb +899 -0
  16. data/vendor/httpclient/lib/httpclient/cacert.p7s +1912 -0
  17. data/vendor/httpclient/lib/httpclient/connection.rb +88 -0
  18. data/vendor/httpclient/lib/httpclient/cookie.rb +438 -0
  19. data/vendor/httpclient/lib/httpclient/http.rb +1046 -0
  20. data/vendor/httpclient/lib/httpclient/include_client.rb +83 -0
  21. data/vendor/httpclient/lib/httpclient/session.rb +1025 -0
  22. data/vendor/httpclient/lib/httpclient/ssl_config.rb +403 -0
  23. data/vendor/httpclient/lib/httpclient/timeout.rb +140 -0
  24. data/vendor/httpclient/lib/httpclient/util.rb +178 -0
  25. data/vendor/httpclient/lib/httpclient/version.rb +3 -0
  26. data/vendor/httpclient/lib/oauthclient.rb +110 -0
  27. data/vendor/httpclient/sample/async.rb +8 -0
  28. data/vendor/httpclient/sample/auth.rb +11 -0
  29. data/vendor/httpclient/sample/cookie.rb +18 -0
  30. data/vendor/httpclient/sample/dav.rb +103 -0
  31. data/vendor/httpclient/sample/howto.rb +49 -0
  32. data/vendor/httpclient/sample/oauth_buzz.rb +57 -0
  33. data/vendor/httpclient/sample/oauth_friendfeed.rb +59 -0
  34. data/vendor/httpclient/sample/oauth_salesforce_10.rb +63 -0
  35. data/vendor/httpclient/sample/oauth_twitter.rb +61 -0
  36. data/vendor/httpclient/sample/ssl/0cert.pem +22 -0
  37. data/vendor/httpclient/sample/ssl/0key.pem +30 -0
  38. data/vendor/httpclient/sample/ssl/1000cert.pem +19 -0
  39. data/vendor/httpclient/sample/ssl/1000key.pem +18 -0
  40. data/vendor/httpclient/sample/ssl/htdocs/index.html +10 -0
  41. data/vendor/httpclient/sample/ssl/ssl_client.rb +22 -0
  42. data/vendor/httpclient/sample/ssl/webrick_httpsd.rb +29 -0
  43. data/vendor/httpclient/sample/stream.rb +21 -0
  44. data/vendor/httpclient/sample/thread.rb +27 -0
  45. data/vendor/httpclient/sample/wcat.rb +21 -0
  46. data/vendor/httpclient/test/ca-chain.cert +44 -0
  47. data/vendor/httpclient/test/ca.cert +23 -0
  48. data/vendor/httpclient/test/client.cert +19 -0
  49. data/vendor/httpclient/test/client.key +15 -0
  50. data/vendor/httpclient/test/helper.rb +129 -0
  51. data/vendor/httpclient/test/htdigest +1 -0
  52. data/vendor/httpclient/test/htpasswd +2 -0
  53. data/vendor/httpclient/test/runner.rb +2 -0
  54. data/vendor/httpclient/test/server.cert +19 -0
  55. data/vendor/httpclient/test/server.key +15 -0
  56. data/vendor/httpclient/test/sslsvr.rb +65 -0
  57. data/vendor/httpclient/test/subca.cert +21 -0
  58. data/vendor/httpclient/test/test_auth.rb +321 -0
  59. data/vendor/httpclient/test/test_cookie.rb +391 -0
  60. data/vendor/httpclient/test/test_hexdump.rb +14 -0
  61. data/vendor/httpclient/test/test_http-access2.rb +507 -0
  62. data/vendor/httpclient/test/test_httpclient.rb +1783 -0
  63. data/vendor/httpclient/test/test_include_client.rb +52 -0
  64. data/vendor/httpclient/test/test_ssl.rb +235 -0
  65. data/vendor/multi_json/.document +5 -0
  66. data/vendor/multi_json/.rspec +3 -0
  67. data/vendor/multi_json/.travis.yml +11 -0
  68. data/vendor/multi_json/.yardopts +6 -0
  69. data/vendor/multi_json/CHANGELOG.md +169 -0
  70. data/vendor/multi_json/CONTRIBUTING.md +46 -0
  71. data/vendor/multi_json/Gemfile +31 -0
  72. data/vendor/multi_json/LICENSE.md +20 -0
  73. data/vendor/multi_json/README.md +109 -0
  74. data/vendor/multi_json/Rakefile +12 -0
  75. data/vendor/multi_json/lib/multi_json.rb +157 -0
  76. data/vendor/multi_json/lib/multi_json/adapter.rb +48 -0
  77. data/vendor/multi_json/lib/multi_json/adapters/gson.rb +19 -0
  78. data/vendor/multi_json/lib/multi_json/adapters/jr_jackson.rb +19 -0
  79. data/vendor/multi_json/lib/multi_json/adapters/json_common.rb +25 -0
  80. data/vendor/multi_json/lib/multi_json/adapters/json_gem.rb +11 -0
  81. data/vendor/multi_json/lib/multi_json/adapters/json_pure.rb +11 -0
  82. data/vendor/multi_json/lib/multi_json/adapters/nsjsonserialization.rb +34 -0
  83. data/vendor/multi_json/lib/multi_json/adapters/oj.rb +24 -0
  84. data/vendor/multi_json/lib/multi_json/adapters/ok_json.rb +22 -0
  85. data/vendor/multi_json/lib/multi_json/adapters/yajl.rb +19 -0
  86. data/vendor/multi_json/lib/multi_json/convertible_hash_keys.rb +43 -0
  87. data/vendor/multi_json/lib/multi_json/load_error.rb +11 -0
  88. data/vendor/multi_json/lib/multi_json/options.rb +48 -0
  89. data/vendor/multi_json/lib/multi_json/vendor/okjson.rb +606 -0
  90. data/vendor/multi_json/lib/multi_json/version.rb +20 -0
  91. data/vendor/multi_json/multi_json.gemspec +22 -0
  92. data/vendor/multi_json/spec/adapter_shared_example.rb +235 -0
  93. data/vendor/multi_json/spec/has_options.rb +119 -0
  94. data/vendor/multi_json/spec/helper.rb +35 -0
  95. data/vendor/multi_json/spec/json_common_shared_example.rb +30 -0
  96. data/vendor/multi_json/spec/multi_json_spec.rb +226 -0
  97. data/vendor/{signature → pusher}/.document +0 -0
  98. data/vendor/{json_pure/diagrams/.keep → pusher/.gemtest} +0 -0
  99. data/vendor/pusher/.gitignore +23 -0
  100. data/vendor/pusher/.travis.yml +15 -0
  101. data/vendor/pusher/Gemfile +2 -0
  102. data/vendor/{pusher-gem → pusher}/LICENSE +1 -1
  103. data/vendor/pusher/README.md +186 -0
  104. data/vendor/{pusher-gem → pusher}/Rakefile +0 -0
  105. data/vendor/{pusher-gem → pusher}/examples/async_message.rb +0 -0
  106. data/vendor/pusher/lib/pusher.rb +60 -0
  107. data/vendor/{pusher-gem → pusher}/lib/pusher/channel.rb +47 -54
  108. data/vendor/pusher/lib/pusher/client.rb +306 -0
  109. data/vendor/pusher/lib/pusher/request.rb +107 -0
  110. data/vendor/pusher/lib/pusher/resource.rb +36 -0
  111. data/vendor/pusher/lib/pusher/webhook.rb +110 -0
  112. data/vendor/{pusher-gem → pusher}/pusher.gemspec +6 -5
  113. data/vendor/pusher/spec/channel_spec.rb +127 -0
  114. data/vendor/pusher/spec/client_spec.rb +464 -0
  115. data/vendor/{pusher-gem → pusher}/spec/spec_helper.rb +12 -0
  116. data/vendor/pusher/spec/web_hook_spec.rb +117 -0
  117. data/vendor/signature/.travis.yml +15 -0
  118. data/vendor/signature/Gemfile +1 -1
  119. data/vendor/signature/README.md +38 -28
  120. data/vendor/signature/lib/signature.rb +97 -15
  121. data/vendor/signature/lib/signature/query_encoder.rb +47 -0
  122. data/vendor/signature/lib/signature/version.rb +1 -1
  123. data/vendor/signature/signature.gemspec +3 -2
  124. data/vendor/signature/spec/signature_spec.rb +164 -55
  125. data/vendor/signature/spec/spec_helper.rb +2 -3
  126. metadata +120 -145
  127. data/vendor/json_pure/.gitignore +0 -12
  128. data/vendor/json_pure/.travis.yml +0 -20
  129. data/vendor/json_pure/CHANGES +0 -282
  130. data/vendor/json_pure/COPYING +0 -58
  131. data/vendor/json_pure/COPYING-json-jruby +0 -57
  132. data/vendor/json_pure/GPL +0 -340
  133. data/vendor/json_pure/Gemfile +0 -11
  134. data/vendor/json_pure/README-json-jruby.markdown +0 -33
  135. data/vendor/json_pure/README.rdoc +0 -358
  136. data/vendor/json_pure/Rakefile +0 -412
  137. data/vendor/json_pure/TODO +0 -1
  138. data/vendor/json_pure/VERSION +0 -1
  139. data/vendor/json_pure/data/example.json +0 -1
  140. data/vendor/json_pure/data/index.html +0 -38
  141. data/vendor/json_pure/data/prototype.js +0 -4184
  142. data/vendor/json_pure/ext/json/ext/fbuffer/fbuffer.h +0 -181
  143. data/vendor/json_pure/ext/json/ext/generator/depend +0 -1
  144. data/vendor/json_pure/ext/json/ext/generator/extconf.rb +0 -14
  145. data/vendor/json_pure/ext/json/ext/generator/generator.c +0 -1435
  146. data/vendor/json_pure/ext/json/ext/generator/generator.h +0 -148
  147. data/vendor/json_pure/ext/json/ext/parser/depend +0 -1
  148. data/vendor/json_pure/ext/json/ext/parser/extconf.rb +0 -13
  149. data/vendor/json_pure/ext/json/ext/parser/parser.c +0 -2204
  150. data/vendor/json_pure/ext/json/ext/parser/parser.h +0 -77
  151. data/vendor/json_pure/ext/json/ext/parser/parser.rl +0 -927
  152. data/vendor/json_pure/install.rb +0 -23
  153. data/vendor/json_pure/java/src/json/ext/ByteListTranscoder.java +0 -167
  154. data/vendor/json_pure/java/src/json/ext/Generator.java +0 -444
  155. data/vendor/json_pure/java/src/json/ext/GeneratorMethods.java +0 -232
  156. data/vendor/json_pure/java/src/json/ext/GeneratorService.java +0 -43
  157. data/vendor/json_pure/java/src/json/ext/GeneratorState.java +0 -543
  158. data/vendor/json_pure/java/src/json/ext/OptionsReader.java +0 -114
  159. data/vendor/json_pure/java/src/json/ext/Parser.java +0 -2644
  160. data/vendor/json_pure/java/src/json/ext/Parser.rl +0 -968
  161. data/vendor/json_pure/java/src/json/ext/ParserService.java +0 -35
  162. data/vendor/json_pure/java/src/json/ext/RuntimeInfo.java +0 -121
  163. data/vendor/json_pure/java/src/json/ext/StringDecoder.java +0 -167
  164. data/vendor/json_pure/java/src/json/ext/StringEncoder.java +0 -106
  165. data/vendor/json_pure/java/src/json/ext/Utils.java +0 -89
  166. data/vendor/json_pure/json-java.gemspec +0 -23
  167. data/vendor/json_pure/json.gemspec +0 -37
  168. data/vendor/json_pure/json_pure.gemspec +0 -39
  169. data/vendor/json_pure/lib/json.rb +0 -62
  170. data/vendor/json_pure/lib/json/add/bigdecimal.rb +0 -28
  171. data/vendor/json_pure/lib/json/add/complex.rb +0 -22
  172. data/vendor/json_pure/lib/json/add/core.rb +0 -11
  173. data/vendor/json_pure/lib/json/add/date.rb +0 -34
  174. data/vendor/json_pure/lib/json/add/date_time.rb +0 -50
  175. data/vendor/json_pure/lib/json/add/exception.rb +0 -31
  176. data/vendor/json_pure/lib/json/add/ostruct.rb +0 -31
  177. data/vendor/json_pure/lib/json/add/range.rb +0 -29
  178. data/vendor/json_pure/lib/json/add/rational.rb +0 -22
  179. data/vendor/json_pure/lib/json/add/regexp.rb +0 -30
  180. data/vendor/json_pure/lib/json/add/struct.rb +0 -30
  181. data/vendor/json_pure/lib/json/add/symbol.rb +0 -25
  182. data/vendor/json_pure/lib/json/add/time.rb +0 -38
  183. data/vendor/json_pure/lib/json/common.rb +0 -487
  184. data/vendor/json_pure/lib/json/ext.rb +0 -21
  185. data/vendor/json_pure/lib/json/ext/.keep +0 -0
  186. data/vendor/json_pure/lib/json/generic_object.rb +0 -70
  187. data/vendor/json_pure/lib/json/pure.rb +0 -21
  188. data/vendor/json_pure/lib/json/pure/generator.rb +0 -522
  189. data/vendor/json_pure/lib/json/pure/parser.rb +0 -359
  190. data/vendor/json_pure/lib/json/version.rb +0 -8
  191. data/vendor/json_pure/tests/fixtures/fail1.json +0 -1
  192. data/vendor/json_pure/tests/fixtures/fail10.json +0 -1
  193. data/vendor/json_pure/tests/fixtures/fail11.json +0 -1
  194. data/vendor/json_pure/tests/fixtures/fail12.json +0 -1
  195. data/vendor/json_pure/tests/fixtures/fail13.json +0 -1
  196. data/vendor/json_pure/tests/fixtures/fail14.json +0 -1
  197. data/vendor/json_pure/tests/fixtures/fail18.json +0 -1
  198. data/vendor/json_pure/tests/fixtures/fail19.json +0 -1
  199. data/vendor/json_pure/tests/fixtures/fail2.json +0 -1
  200. data/vendor/json_pure/tests/fixtures/fail20.json +0 -1
  201. data/vendor/json_pure/tests/fixtures/fail21.json +0 -1
  202. data/vendor/json_pure/tests/fixtures/fail22.json +0 -1
  203. data/vendor/json_pure/tests/fixtures/fail23.json +0 -1
  204. data/vendor/json_pure/tests/fixtures/fail24.json +0 -1
  205. data/vendor/json_pure/tests/fixtures/fail25.json +0 -1
  206. data/vendor/json_pure/tests/fixtures/fail27.json +0 -2
  207. data/vendor/json_pure/tests/fixtures/fail28.json +0 -2
  208. data/vendor/json_pure/tests/fixtures/fail3.json +0 -1
  209. data/vendor/json_pure/tests/fixtures/fail4.json +0 -1
  210. data/vendor/json_pure/tests/fixtures/fail5.json +0 -1
  211. data/vendor/json_pure/tests/fixtures/fail6.json +0 -1
  212. data/vendor/json_pure/tests/fixtures/fail7.json +0 -1
  213. data/vendor/json_pure/tests/fixtures/fail8.json +0 -1
  214. data/vendor/json_pure/tests/fixtures/fail9.json +0 -1
  215. data/vendor/json_pure/tests/fixtures/pass1.json +0 -56
  216. data/vendor/json_pure/tests/fixtures/pass15.json +0 -1
  217. data/vendor/json_pure/tests/fixtures/pass16.json +0 -1
  218. data/vendor/json_pure/tests/fixtures/pass17.json +0 -1
  219. data/vendor/json_pure/tests/fixtures/pass2.json +0 -1
  220. data/vendor/json_pure/tests/fixtures/pass26.json +0 -1
  221. data/vendor/json_pure/tests/fixtures/pass3.json +0 -6
  222. data/vendor/json_pure/tests/setup_variant.rb +0 -11
  223. data/vendor/json_pure/tests/test_json.rb +0 -545
  224. data/vendor/json_pure/tests/test_json_addition.rb +0 -196
  225. data/vendor/json_pure/tests/test_json_encoding.rb +0 -65
  226. data/vendor/json_pure/tests/test_json_fixtures.rb +0 -35
  227. data/vendor/json_pure/tests/test_json_generate.rb +0 -322
  228. data/vendor/json_pure/tests/test_json_generic_object.rb +0 -75
  229. data/vendor/json_pure/tests/test_json_string_matching.rb +0 -39
  230. data/vendor/json_pure/tests/test_json_unicode.rb +0 -72
  231. data/vendor/json_pure/tools/fuzz.rb +0 -139
  232. data/vendor/json_pure/tools/server.rb +0 -62
  233. data/vendor/pusher-gem/Gemfile +0 -2
  234. data/vendor/pusher-gem/README.md +0 -80
  235. data/vendor/pusher-gem/lib/pusher.rb +0 -107
  236. data/vendor/pusher-gem/lib/pusher/request.rb +0 -107
  237. data/vendor/pusher-gem/spec/channel_spec.rb +0 -274
  238. data/vendor/pusher-gem/spec/pusher_spec.rb +0 -87
  239. data/vendor/ruby-hmac/History.txt +0 -15
  240. data/vendor/ruby-hmac/Manifest.txt +0 -11
  241. data/vendor/ruby-hmac/README.md +0 -41
  242. data/vendor/ruby-hmac/Rakefile +0 -23
  243. data/vendor/ruby-hmac/lib/hmac-md5.rb +0 -11
  244. data/vendor/ruby-hmac/lib/hmac-rmd160.rb +0 -11
  245. data/vendor/ruby-hmac/lib/hmac-sha1.rb +0 -11
  246. data/vendor/ruby-hmac/lib/hmac-sha2.rb +0 -25
  247. data/vendor/ruby-hmac/lib/hmac.rb +0 -118
  248. data/vendor/ruby-hmac/lib/ruby_hmac.rb +0 -2
  249. data/vendor/ruby-hmac/ruby-hmac.gemspec +0 -33
  250. data/vendor/ruby-hmac/test/test_hmac.rb +0 -89
  251. data/vendor/signature/VERSION +0 -1
@@ -0,0 +1,83 @@
1
+ # It is useful to re-use a HTTPClient instance for multiple requests, to
2
+ # re-use HTTP 1.1 persistent connections.
3
+ #
4
+ # To do that, you sometimes want to store an HTTPClient instance in a global/
5
+ # class variable location, so it can be accessed and re-used.
6
+ #
7
+ # This mix-in makes it easy to create class-level access to one or more
8
+ # HTTPClient instances. The HTTPClient instances are lazily initialized
9
+ # on first use (to, for instance, avoid interfering with WebMock/VCR),
10
+ # and are initialized in a thread-safe manner. Note that a
11
+ # HTTPClient, once initialized, is safe for use in multiple threads.
12
+ #
13
+ # Note that you `extend` HTTPClient::IncludeClient, not `include.
14
+ #
15
+ # require 'httpclient/include_client'
16
+ # class Widget
17
+ # extend HTTPClient::IncludeClient
18
+ #
19
+ # include_http_client
20
+ # # and/or, specify more stuff
21
+ # include_http_client('http://myproxy:8080', :method_name => :my_client) do |client|
22
+ # # any init you want
23
+ # client.set_cookie_store nil
24
+ # client.
25
+ # end
26
+ # end
27
+ #
28
+ # That creates two HTTPClient instances available at the class level.
29
+ # The first will be available from Widget.http_client (default method
30
+ # name for `include_http_client`), with default initialization.
31
+ #
32
+ # The second will be available at Widget.my_client, with the init arguments
33
+ # provided, further initialized by the block provided.
34
+ #
35
+ # In addition to a class-level method, for convenience instance-level methods
36
+ # are also provided. Widget.http_client is identical to Widget.new.http_client
37
+ #
38
+ #
39
+ class HTTPClient
40
+ module IncludeClient
41
+
42
+
43
+ def include_http_client(*args, &block)
44
+ # We're going to dynamically define a class
45
+ # to hold our state, namespaced, as well as possibly dynamic
46
+ # name of cover method.
47
+ method_name = (args.last.delete(:method_name) if args.last.kind_of? Hash) || :http_client
48
+ args.pop if args.last == {} # if last arg was named methods now empty, remove it.
49
+
50
+ # By the amazingness of closures, we can create these things
51
+ # in local vars here and use em in our method, we don't even
52
+ # need iVars for state.
53
+ client_instance = nil
54
+ client_mutex = Mutex.new
55
+ client_args = args
56
+ client_block = block
57
+
58
+ # to define a _class method_ on the specific class that's currently
59
+ # `self`, we have to use this bit of metaprogramming, sorry.
60
+ (class << self; self ; end).instance_eval do
61
+ define_method(method_name) do
62
+ # implementation copied from ruby stdlib singleton
63
+ # to create this global obj thread-safely.
64
+ return client_instance if client_instance
65
+ client_mutex.synchronize do
66
+ return client_instance if client_instance
67
+ # init HTTPClient with specified args/block
68
+ client_instance = HTTPClient.new(*client_args)
69
+ client_block.call(client_instance) if client_block
70
+ end
71
+ return client_instance
72
+ end
73
+ end
74
+
75
+ # And for convenience, an _instance method_ on the class that just
76
+ # delegates to the class method.
77
+ define_method(method_name) do
78
+ self.class.send(method_name)
79
+ end
80
+
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,1025 @@
1
+ # HTTPClient - HTTP client library.
2
+ # Copyright (C) 2000-2009 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
3
+ #
4
+ # This program is copyrighted free software by NAKAMURA, Hiroshi. You can
5
+ # redistribute it and/or modify it under the same terms of Ruby's license;
6
+ # either the dual license version in 2003, or any later version.
7
+ #
8
+ # httpclient/session.rb is based on http-access.rb in http-access/0.0.4. Some
9
+ # part of it is copyrighted by Maebashi-san who made and published
10
+ # http-access/0.0.4. http-access/0.0.4 did not include license notice but when
11
+ # I asked Maebashi-san he agreed that I can redistribute it under the same terms
12
+ # of Ruby. Many thanks to Maebashi-san.
13
+
14
+
15
+ require 'socket'
16
+ require 'thread'
17
+ require 'stringio'
18
+ require 'zlib'
19
+
20
+ require 'httpclient/timeout'
21
+ require 'httpclient/ssl_config'
22
+ require 'httpclient/http'
23
+
24
+
25
+ class HTTPClient
26
+
27
+
28
+ # Represents a Site: protocol scheme, host String and port Number.
29
+ class Site
30
+ # Protocol scheme.
31
+ attr_accessor :scheme
32
+ # Host String.
33
+ attr_accessor :host
34
+ alias hostname host
35
+ # Port number.
36
+ attr_accessor :port
37
+
38
+ # Creates a new Site based on the given URI.
39
+ def initialize(uri = nil)
40
+ if uri
41
+ @scheme = uri.scheme
42
+ @host = uri.hostname
43
+ @port = uri.port.to_i
44
+ else
45
+ @scheme = 'tcp'
46
+ @host = '0.0.0.0'
47
+ @port = 0
48
+ end
49
+ end
50
+
51
+ # Returns address String.
52
+ def addr
53
+ "#{@scheme}://#{@host}:#{@port.to_s}"
54
+ end
55
+
56
+ # Returns true is scheme, host and port are '=='
57
+ def ==(rhs)
58
+ (@scheme == rhs.scheme) and (@host == rhs.host) and (@port == rhs.port)
59
+ end
60
+
61
+ # Same as ==.
62
+ def eql?(rhs)
63
+ self == rhs
64
+ end
65
+
66
+ def hash # :nodoc:
67
+ [@scheme, @host, @port].hash
68
+ end
69
+
70
+ def to_s # :nodoc:
71
+ addr
72
+ end
73
+
74
+ # Returns true if scheme, host and port of the given URI matches with this.
75
+ def match(uri)
76
+ (@scheme == uri.scheme) and (@host == uri.host) and (@port == uri.port.to_i)
77
+ end
78
+
79
+ def inspect # :nodoc:
80
+ sprintf("#<%s:0x%x %s>", self.class.name, __id__, addr)
81
+ end
82
+
83
+ EMPTY = Site.new.freeze
84
+ end
85
+
86
+
87
+ # Manages sessions for a HTTPClient instance.
88
+ class SessionManager
89
+ # Name of this client. Used for 'User-Agent' header in HTTP request.
90
+ attr_accessor :agent_name
91
+ # Owner of this client. Used for 'From' header in HTTP request.
92
+ attr_accessor :from
93
+
94
+ # Requested protocol version
95
+ attr_accessor :protocol_version
96
+ # Chunk size for chunked request
97
+ attr_accessor :chunk_size
98
+ # Device for dumping log for debugging
99
+ attr_accessor :debug_dev
100
+ # Boolean value for Socket#sync
101
+ attr_accessor :socket_sync
102
+
103
+ attr_accessor :connect_timeout
104
+ # Maximum retry count. 0 for infinite.
105
+ attr_accessor :connect_retry
106
+ attr_accessor :send_timeout
107
+ attr_accessor :receive_timeout
108
+ attr_accessor :keep_alive_timeout
109
+ attr_accessor :read_block_size
110
+ attr_accessor :protocol_retry_count
111
+
112
+ # Local address to bind local side of the socket to
113
+ attr_accessor :socket_local
114
+
115
+ attr_accessor :ssl_config
116
+
117
+ attr_reader :test_loopback_http_response
118
+
119
+ attr_accessor :transparent_gzip_decompression
120
+
121
+ def initialize(client)
122
+ @client = client
123
+ @proxy = client.proxy
124
+
125
+ @agent_name = nil
126
+ @from = nil
127
+
128
+ @protocol_version = nil
129
+ @debug_dev = client.debug_dev
130
+ @socket_sync = true
131
+ @chunk_size = ::HTTP::Message::Body::DEFAULT_CHUNK_SIZE
132
+
133
+ @connect_timeout = 60
134
+ @connect_retry = 1
135
+ @send_timeout = 120
136
+ @receive_timeout = 60 # For each read_block_size bytes
137
+ @keep_alive_timeout = 15 # '15' is from Apache 2 default
138
+ @read_block_size = 1024 * 16 # follows net/http change in 1.8.7
139
+ @protocol_retry_count = 5
140
+
141
+ @ssl_config = nil
142
+ @test_loopback_http_response = []
143
+
144
+ @transparent_gzip_decompression = false
145
+ @socket_local = Site.new
146
+
147
+ @sess_pool = {}
148
+ @sess_pool_mutex = Mutex.new
149
+ @sess_pool_last_checked = Time.now
150
+ end
151
+
152
+ def proxy=(proxy)
153
+ if proxy.nil?
154
+ @proxy = nil
155
+ else
156
+ @proxy = Site.new(proxy)
157
+ end
158
+ end
159
+
160
+ def query(req, via_proxy)
161
+ req.http_body.chunk_size = @chunk_size
162
+ sess = open(req.header.request_uri, via_proxy)
163
+ begin
164
+ sess.query(req)
165
+ rescue
166
+ sess.close
167
+ raise
168
+ end
169
+ sess
170
+ end
171
+
172
+ def reset(uri)
173
+ site = Site.new(uri)
174
+ close(site)
175
+ end
176
+
177
+ def reset_all
178
+ close_all
179
+ end
180
+
181
+ # assert: sess.last_used must not be nil
182
+ def keep(sess)
183
+ add_cached_session(sess)
184
+ end
185
+
186
+ def invalidate(site)
187
+ @sess_pool_mutex.synchronize do
188
+ if pool = @sess_pool[site]
189
+ pool.each do |sess|
190
+ sess.invalidate
191
+ end
192
+ end
193
+ end
194
+ end
195
+
196
+ private
197
+
198
+ def open(uri, via_proxy = false)
199
+ site = Site.new(uri)
200
+ sess = nil
201
+ if cached = get_cached_session(site)
202
+ sess = cached
203
+ else
204
+ sess = Session.new(@client, site, @agent_name, @from)
205
+ sess.proxy = via_proxy ? @proxy : nil
206
+ sess.socket_sync = @socket_sync
207
+ sess.requested_version = @protocol_version if @protocol_version
208
+ sess.connect_timeout = @connect_timeout
209
+ sess.connect_retry = @connect_retry
210
+ sess.send_timeout = @send_timeout
211
+ sess.receive_timeout = @receive_timeout
212
+ sess.read_block_size = @read_block_size
213
+ sess.protocol_retry_count = @protocol_retry_count
214
+ sess.ssl_config = @ssl_config
215
+ sess.debug_dev = @debug_dev
216
+ sess.socket_local = @socket_local
217
+ sess.test_loopback_http_response = @test_loopback_http_response
218
+ sess.transparent_gzip_decompression = @transparent_gzip_decompression
219
+ end
220
+ sess
221
+ end
222
+
223
+ def close_all
224
+ @sess_pool_mutex.synchronize do
225
+ @sess_pool.each do |site, pool|
226
+ pool.each do |sess|
227
+ sess.close
228
+ end
229
+ end
230
+ end
231
+ @sess_pool.clear
232
+ end
233
+
234
+ # This method might not work as you expected...
235
+ def close(dest)
236
+ if cached = get_cached_session(Site.new(dest))
237
+ cached.close
238
+ true
239
+ else
240
+ false
241
+ end
242
+ end
243
+
244
+ def get_cached_session(site)
245
+ @sess_pool_mutex.synchronize do
246
+ now = Time.now
247
+ if now > @sess_pool_last_checked + @keep_alive_timeout
248
+ scrub_cached_session(now)
249
+ @sess_pool_last_checked = now
250
+ end
251
+ if pool = @sess_pool[site]
252
+ pool.each_with_index do |sess, idx|
253
+ if valid_session?(sess, now)
254
+ return pool.slice!(idx)
255
+ end
256
+ end
257
+ end
258
+ end
259
+ nil
260
+ end
261
+
262
+ def scrub_cached_session(now)
263
+ @sess_pool.each do |site, pool|
264
+ pool.replace(pool.select { |sess|
265
+ if valid_session?(sess, now)
266
+ true
267
+ else
268
+ sess.close # close & remove from the pool
269
+ false
270
+ end
271
+ })
272
+ end
273
+ end
274
+
275
+ def valid_session?(sess, now)
276
+ !sess.invalidated? and (now <= sess.last_used + @keep_alive_timeout)
277
+ end
278
+
279
+ def add_cached_session(sess)
280
+ @sess_pool_mutex.synchronize do
281
+ (@sess_pool[sess.dest] ||= []).unshift(sess)
282
+ end
283
+ end
284
+ end
285
+
286
+
287
+ # Wraps up OpenSSL::SSL::SSLSocket and offers debugging features.
288
+ class SSLSocketWrap
289
+ def initialize(socket, context, debug_dev = nil)
290
+ unless SSLEnabled
291
+ raise ConfigurationError.new('Ruby/OpenSSL module is required')
292
+ end
293
+ @context = context
294
+ @socket = socket
295
+ @ssl_socket = create_openssl_socket(@socket)
296
+ @debug_dev = debug_dev
297
+ end
298
+
299
+ def ssl_connect(hostname = nil)
300
+ if hostname && @ssl_socket.respond_to?(:hostname=)
301
+ @ssl_socket.hostname = hostname
302
+ end
303
+ @ssl_socket.connect
304
+ end
305
+
306
+ def post_connection_check(host)
307
+ verify_mode = @context.verify_mode || OpenSSL::SSL::VERIFY_NONE
308
+ if verify_mode == OpenSSL::SSL::VERIFY_NONE
309
+ return
310
+ elsif @ssl_socket.peer_cert.nil? and
311
+ check_mask(verify_mode, OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT)
312
+ raise OpenSSL::SSL::SSLError.new('no peer cert')
313
+ end
314
+ hostname = host.host
315
+ if @ssl_socket.respond_to?(:post_connection_check) and RUBY_VERSION > "1.8.4"
316
+ @ssl_socket.post_connection_check(hostname)
317
+ else
318
+ @context.post_connection_check(@ssl_socket.peer_cert, hostname)
319
+ end
320
+ end
321
+
322
+ def ssl_version
323
+ @ssl_socket.ssl_version if @ssl_socket.respond_to?(:ssl_version)
324
+ end
325
+
326
+ def ssl_cipher
327
+ @ssl_socket.cipher
328
+ end
329
+
330
+ def ssl_state
331
+ @ssl_socket.state
332
+ end
333
+
334
+ def peer_cert
335
+ @ssl_socket.peer_cert
336
+ end
337
+
338
+ def close
339
+ @ssl_socket.close
340
+ @socket.close
341
+ end
342
+
343
+ def closed?
344
+ @socket.closed?
345
+ end
346
+
347
+ def eof?
348
+ @ssl_socket.eof?
349
+ end
350
+
351
+ def gets(*args)
352
+ str = @ssl_socket.gets(*args)
353
+ debug(str)
354
+ str
355
+ end
356
+
357
+ def read(*args)
358
+ str = @ssl_socket.read(*args)
359
+ debug(str)
360
+ str
361
+ end
362
+
363
+ def readpartial(*args)
364
+ str = @ssl_socket.readpartial(*args)
365
+ debug(str)
366
+ str
367
+ end
368
+
369
+ def <<(str)
370
+ rv = @ssl_socket.write(str)
371
+ debug(str)
372
+ rv
373
+ end
374
+
375
+ def flush
376
+ @ssl_socket.flush
377
+ end
378
+
379
+ def sync
380
+ @ssl_socket.sync
381
+ end
382
+
383
+ def sync=(sync)
384
+ @ssl_socket.sync = sync
385
+ end
386
+
387
+ private
388
+
389
+ def check_mask(value, mask)
390
+ value & mask == mask
391
+ end
392
+
393
+ def create_openssl_socket(socket)
394
+ ssl_socket = nil
395
+ if OpenSSL::SSL.const_defined?("SSLContext")
396
+ ctx = OpenSSL::SSL::SSLContext.new
397
+ @context.set_context(ctx)
398
+ ssl_socket = OpenSSL::SSL::SSLSocket.new(socket, ctx)
399
+ else
400
+ ssl_socket = OpenSSL::SSL::SSLSocket.new(socket)
401
+ @context.set_context(ssl_socket)
402
+ end
403
+ ssl_socket
404
+ end
405
+
406
+ def debug(str)
407
+ @debug_dev << str if @debug_dev && str
408
+ end
409
+ end
410
+
411
+
412
+ # Wraps up a Socket for method interception.
413
+ module SocketWrap
414
+ def initialize(socket, *args)
415
+ super(*args)
416
+ @socket = socket
417
+ end
418
+
419
+ def close
420
+ @socket.close
421
+ end
422
+
423
+ def closed?
424
+ @socket.closed?
425
+ end
426
+
427
+ def eof?
428
+ @socket.eof?
429
+ end
430
+
431
+ def gets(*args)
432
+ @socket.gets(*args)
433
+ end
434
+
435
+ def read(*args)
436
+ @socket.read(*args)
437
+ end
438
+
439
+ def readpartial(*args)
440
+ # StringIO doesn't support :readpartial
441
+ if @socket.respond_to?(:readpartial)
442
+ @socket.readpartial(*args)
443
+ else
444
+ @socket.read(*args)
445
+ end
446
+ end
447
+
448
+ def <<(str)
449
+ @socket << str
450
+ end
451
+
452
+ def flush
453
+ @socket.flush
454
+ end
455
+
456
+ def sync
457
+ @socket.sync
458
+ end
459
+
460
+ def sync=(sync)
461
+ @socket.sync = sync
462
+ end
463
+ end
464
+
465
+
466
+ # Module for intercepting Socket methods and dumps in/out to given debugging
467
+ # device. debug_dev must respond to <<.
468
+ module DebugSocket
469
+ extend SocketWrap
470
+
471
+ def debug_dev=(debug_dev)
472
+ @debug_dev = debug_dev
473
+ end
474
+
475
+ def close
476
+ super
477
+ debug("! CONNECTION CLOSED\n")
478
+ end
479
+
480
+ def gets(*args)
481
+ str = super
482
+ debug(str)
483
+ str
484
+ end
485
+
486
+ def read(*args)
487
+ str = super
488
+ debug(str)
489
+ str
490
+ end
491
+
492
+ def readpartial(*args)
493
+ str = super
494
+ debug(str)
495
+ str
496
+ end
497
+
498
+ def <<(str)
499
+ super
500
+ debug(str)
501
+ end
502
+
503
+ private
504
+
505
+ def debug(str)
506
+ if str && @debug_dev
507
+ if str.index("\0")
508
+ require 'hexdump'
509
+ str.force_encoding('BINARY') if str.respond_to?(:force_encoding)
510
+ @debug_dev << HexDump.encode(str).join("\n")
511
+ else
512
+ @debug_dev << str
513
+ end
514
+ end
515
+ end
516
+ end
517
+
518
+
519
+ # Dummy Socket for emulating loopback test.
520
+ class LoopBackSocket
521
+ include SocketWrap
522
+
523
+ def initialize(host, port, response)
524
+ super(response.is_a?(StringIO) ? response : StringIO.new(response))
525
+ @host = host
526
+ @port = port
527
+ end
528
+
529
+ def <<(str)
530
+ # ignored
531
+ end
532
+ end
533
+
534
+
535
+ # Manages a HTTP session with a Site.
536
+ class Session
537
+ include HTTPClient::Timeout
538
+ include Util
539
+
540
+ # Destination site
541
+ attr_reader :dest
542
+ # Proxy site
543
+ attr_accessor :proxy
544
+ # Boolean value for Socket#sync
545
+ attr_accessor :socket_sync
546
+ # Requested protocol version
547
+ attr_accessor :requested_version
548
+ # Device for dumping log for debugging
549
+ attr_accessor :debug_dev
550
+
551
+ attr_accessor :connect_timeout
552
+ attr_accessor :connect_retry
553
+ attr_accessor :send_timeout
554
+ attr_accessor :receive_timeout
555
+ attr_accessor :read_block_size
556
+ attr_accessor :protocol_retry_count
557
+
558
+ attr_accessor :socket_local
559
+
560
+ attr_accessor :ssl_config
561
+ attr_reader :ssl_peer_cert
562
+ attr_accessor :test_loopback_http_response
563
+
564
+ attr_accessor :transparent_gzip_decompression
565
+ attr_reader :last_used
566
+
567
+ def initialize(client, dest, agent_name, from)
568
+ @client = client
569
+ @dest = dest
570
+ @invalidated = false
571
+ @proxy = nil
572
+ @socket_sync = true
573
+ @requested_version = nil
574
+
575
+ @debug_dev = nil
576
+
577
+ @connect_timeout = nil
578
+ @connect_retry = 1
579
+ @send_timeout = nil
580
+ @receive_timeout = nil
581
+ @read_block_size = nil
582
+ @protocol_retry_count = 5
583
+
584
+ @ssl_config = nil
585
+ @ssl_peer_cert = nil
586
+
587
+ @test_loopback_http_response = nil
588
+ @socket_local = Site::EMPTY
589
+
590
+ @agent_name = agent_name
591
+ @from = from
592
+ @state = :INIT
593
+
594
+ @requests = []
595
+
596
+ @status = nil
597
+ @reason = nil
598
+ @headers = []
599
+
600
+ @socket = nil
601
+ @readbuf = nil
602
+
603
+ @transparent_gzip_decompression = false
604
+ @last_used = nil
605
+ end
606
+
607
+ # Send a request to the server
608
+ def query(req)
609
+ connect if @state == :INIT
610
+ # Use absolute URI (not absolute path) iif via proxy AND not HTTPS.
611
+ req.header.request_absolute_uri = !@proxy.nil? and !https?(@dest)
612
+ begin
613
+ timeout(@send_timeout, SendTimeoutError) do
614
+ set_header(req)
615
+ req.dump(@socket)
616
+ # flush the IO stream as IO::sync mode is false
617
+ @socket.flush unless @socket_sync
618
+ end
619
+ rescue Errno::ECONNABORTED, Errno::ECONNRESET, Errno::EPIPE, IOError
620
+ # JRuby can raise IOError instead of ECONNRESET for now
621
+ close
622
+ raise KeepAliveDisconnected.new(self)
623
+ rescue HTTPClient::TimeoutError
624
+ close
625
+ raise
626
+ rescue
627
+ close
628
+ if SSLEnabled and $!.is_a?(OpenSSL::SSL::SSLError)
629
+ raise KeepAliveDisconnected.new(self)
630
+ else
631
+ raise
632
+ end
633
+ end
634
+
635
+ @state = :META if @state == :WAIT
636
+ @next_connection = nil
637
+ @requests.push(req)
638
+ @last_used = Time.now
639
+ end
640
+
641
+ def close
642
+ if !@socket.nil? and !@socket.closed?
643
+ # @socket.flush may block when it the socket is already closed by
644
+ # foreign host and the client runs under MT-condition.
645
+ @socket.close
646
+ end
647
+ @state = :INIT
648
+ end
649
+
650
+ def closed?
651
+ @state == :INIT
652
+ end
653
+
654
+ def invalidate
655
+ @invalidated = true
656
+ end
657
+
658
+ def invalidated?
659
+ @invalidated
660
+ end
661
+
662
+ def get_header
663
+ begin
664
+ if @state != :META
665
+ raise RuntimeError.new("get_status must be called at the beginning of a session")
666
+ end
667
+ read_header
668
+ rescue
669
+ close
670
+ raise
671
+ end
672
+ [@version, @status, @reason, @headers]
673
+ end
674
+
675
+ def eof?
676
+ if !@content_length.nil?
677
+ @content_length == 0
678
+ else
679
+ @socket.closed? or @socket.eof?
680
+ end
681
+ end
682
+
683
+ def get_body(&block)
684
+ begin
685
+ read_header if @state == :META
686
+ return nil if @state != :DATA
687
+ if @gzipped and @transparent_gzip_decompression
688
+ # zlib itself has a functionality to decompress gzip stream.
689
+ # - zlib 1.2.5 Manual
690
+ # http://www.zlib.net/manual.html#Advanced
691
+ # > windowBits can also be greater than 15 for optional gzip decoding. Add 32 to
692
+ # > windowBits to enable zlib and gzip decoding with automatic header detection,
693
+ # > or add 16 to decode only the gzip format
694
+ inflate_stream = Zlib::Inflate.new(Zlib::MAX_WBITS + 32)
695
+ original_block = block
696
+ block = Proc.new { |buf|
697
+ original_block.call(inflate_stream.inflate(buf))
698
+ }
699
+ end
700
+ if @chunked
701
+ read_body_chunked(&block)
702
+ elsif @content_length
703
+ read_body_length(&block)
704
+ else
705
+ read_body_rest(&block)
706
+ end
707
+ rescue
708
+ close
709
+ raise
710
+ end
711
+ if eof?
712
+ if @next_connection
713
+ @state = :WAIT
714
+ else
715
+ close
716
+ end
717
+ end
718
+ nil
719
+ end
720
+
721
+ private
722
+
723
+ def set_header(req)
724
+ if @requested_version
725
+ if /^(?:HTTP\/|)(\d+.\d+)$/ =~ @requested_version
726
+ req.http_version = $1
727
+ end
728
+ end
729
+ if @agent_name && req.header.get('User-Agent').empty?
730
+ req.header.set('User-Agent', "#{@agent_name} #{LIB_NAME}")
731
+ end
732
+ if @from && req.header.get('From').empty?
733
+ req.header.set('From', @from)
734
+ end
735
+ if req.header.get('Accept').empty?
736
+ req.header.set('Accept', '*/*')
737
+ end
738
+ if @transparent_gzip_decompression
739
+ req.header.set('Accept-Encoding', 'gzip,deflate')
740
+ end
741
+ if req.header.get('Date').empty?
742
+ req.header.set_date_header
743
+ end
744
+ end
745
+
746
+ # Connect to the server
747
+ def connect
748
+ site = @proxy || @dest
749
+ retry_number = 0
750
+ begin
751
+ timeout(@connect_timeout, ConnectTimeoutError) do
752
+ @socket = create_socket(site)
753
+ if https?(@dest)
754
+ if @socket.is_a?(LoopBackSocket)
755
+ connect_ssl_proxy(@socket, urify(@dest.to_s)) if @proxy
756
+ else
757
+ @socket = create_ssl_socket(@socket)
758
+ connect_ssl_proxy(@socket, urify(@dest.to_s)) if @proxy
759
+ begin
760
+ @socket.ssl_connect(@dest.host)
761
+ ensure
762
+ if $DEBUG
763
+ warn("Protocol version: #{@socket.ssl_version}")
764
+ warn("Cipher: #{@socket.ssl_cipher.inspect}")
765
+ warn("State: #{@socket.ssl_state}")
766
+ end
767
+ end
768
+ @socket.post_connection_check(@dest)
769
+ @ssl_peer_cert = @socket.peer_cert
770
+ end
771
+ end
772
+ # Use Ruby internal buffering instead of passing data immediately
773
+ # to the underlying layer
774
+ # => we need to to call explicitly flush on the socket
775
+ @socket.sync = @socket_sync
776
+ end
777
+ rescue RetryableResponse
778
+ retry_number += 1
779
+ if retry_number < @protocol_retry_count
780
+ retry
781
+ end
782
+ raise BadResponseError.new("connect to the server failed with status #{@status} #{@reason}")
783
+ rescue TimeoutError
784
+ if @connect_retry == 0
785
+ retry
786
+ else
787
+ retry_number += 1
788
+ retry if retry_number < @connect_retry
789
+ end
790
+ close
791
+ raise
792
+ end
793
+ @state = :WAIT
794
+ end
795
+
796
+ def create_socket(site)
797
+ socket = nil
798
+ begin
799
+ @debug_dev << "! CONNECT TO #{site.host}:#{site.port}\n" if @debug_dev
800
+ if str = @test_loopback_http_response.shift
801
+ socket = LoopBackSocket.new(site.host, site.port, str)
802
+ elsif @socket_local == Site::EMPTY
803
+ socket = TCPSocket.new(site.host, site.port)
804
+ else
805
+ socket = TCPSocket.new(site.host, site.port, @socket_local.host, @socket_local.port)
806
+ end
807
+ if @debug_dev
808
+ @debug_dev << "! CONNECTION ESTABLISHED\n"
809
+ socket.extend(DebugSocket)
810
+ socket.debug_dev = @debug_dev
811
+ end
812
+ rescue SystemCallError => e
813
+ e.message << " (#{site})"
814
+ raise
815
+ rescue SocketError => e
816
+ e.message << " (#{site})"
817
+ raise
818
+ end
819
+ socket
820
+ end
821
+
822
+ # wrap socket with OpenSSL.
823
+ def create_ssl_socket(raw_socket)
824
+ SSLSocketWrap.new(raw_socket, @ssl_config, @debug_dev)
825
+ end
826
+
827
+ def connect_ssl_proxy(socket, uri)
828
+ req = HTTP::Message.new_connect_request(uri)
829
+ @client.request_filter.each do |filter|
830
+ filter.filter_request(req)
831
+ end
832
+ set_header(req)
833
+ req.dump(@socket)
834
+ @socket.flush unless @socket_sync
835
+ res = HTTP::Message.new_response('')
836
+ parse_header
837
+ res.http_version, res.status, res.reason = @version, @status, @reason
838
+ @headers.each do |key, value|
839
+ res.header.set(key.to_s, value)
840
+ end
841
+ commands = @client.request_filter.collect { |filter|
842
+ filter.filter_response(req, res)
843
+ }
844
+ if commands.find { |command| command == :retry }
845
+ raise RetryableResponse.new
846
+ end
847
+ unless @status == 200
848
+ raise BadResponseError.new("connect to ssl proxy failed with status #{@status} #{@reason}", res)
849
+ end
850
+ end
851
+
852
+ # Read status block.
853
+ def read_header
854
+ @content_length = nil
855
+ @chunked = false
856
+ @gzipped = false
857
+ @chunk_length = 0
858
+ parse_header
859
+ # Header of the request has been parsed.
860
+ @state = :DATA
861
+ req = @requests.shift
862
+ if req.header.request_method == 'HEAD' or no_message_body?(@status)
863
+ @content_length = 0
864
+ if @next_connection
865
+ @state = :WAIT
866
+ else
867
+ close
868
+ end
869
+ end
870
+ @next_connection = false if !@content_length and !@chunked
871
+ end
872
+
873
+ StatusParseRegexp = %r(\AHTTP/(\d+\.\d+)\s+(\d\d\d)\s*([^\r\n]+)?\r?\n\z)
874
+ def parse_header
875
+ timeout(@receive_timeout, ReceiveTimeoutError) do
876
+ initial_line = nil
877
+ begin
878
+ begin
879
+ initial_line = @socket.gets("\n")
880
+ if initial_line.nil?
881
+ close
882
+ raise KeepAliveDisconnected.new(self)
883
+ end
884
+ rescue Errno::ECONNABORTED, Errno::ECONNRESET, Errno::EPIPE, IOError
885
+ # JRuby can raise IOError instead of ECONNRESET for now
886
+ close
887
+ raise KeepAliveDisconnected.new(self)
888
+ end
889
+ if StatusParseRegexp !~ initial_line
890
+ @version = '0.9'
891
+ @status = nil
892
+ @reason = nil
893
+ @next_connection = false
894
+ @content_length = nil
895
+ @readbuf = initial_line
896
+ break
897
+ end
898
+ @version, @status, @reason = $1, $2.to_i, $3
899
+ @next_connection = HTTP::Message.keep_alive_enabled?(@version)
900
+ @headers = []
901
+ while true
902
+ line = @socket.gets("\n")
903
+ unless line
904
+ raise BadResponseError.new('unexpected EOF')
905
+ end
906
+ line.chomp!
907
+ break if line.empty?
908
+ if line[0] == ?\ or line[0] == ?\t
909
+ last = @headers.last[1]
910
+ last << ' ' unless last.empty?
911
+ last << line.strip
912
+ else
913
+ key, value = line.strip.split(/\s*:\s*/, 2)
914
+ parse_keepalive_header(key, value)
915
+ @headers << [key, value]
916
+ end
917
+ end
918
+ end while (@version == '1.1' && @status == 100)
919
+ end
920
+ end
921
+
922
+ def no_message_body?(status)
923
+ !status.nil? && # HTTP/0.9
924
+ ((status >= 100 && status < 200) || status == 204 || status == 304)
925
+ end
926
+
927
+ def parse_keepalive_header(key, value)
928
+ key = key.downcase
929
+ if key == 'content-length'
930
+ @content_length = value.to_i
931
+ elsif key == 'content-encoding' and ( value.downcase == 'gzip' or
932
+ value.downcase == 'x-gzip' or value.downcase == 'deflate' )
933
+ @gzipped = true
934
+ elsif key == 'transfer-encoding' and value.downcase == 'chunked'
935
+ @chunked = true
936
+ @chunk_length = 0
937
+ @content_length = nil
938
+ elsif key == 'connection' or key == 'proxy-connection'
939
+ if value.downcase == 'keep-alive'
940
+ @next_connection = true
941
+ else
942
+ @next_connection = false
943
+ end
944
+ end
945
+ end
946
+
947
+ def read_body_length(&block)
948
+ return nil if @content_length == 0
949
+ while true
950
+ buf = empty_bin_str
951
+ maxbytes = @read_block_size
952
+ maxbytes = @content_length if maxbytes > @content_length
953
+ timeout(@receive_timeout, ReceiveTimeoutError) do
954
+ begin
955
+ @socket.readpartial(maxbytes, buf)
956
+ rescue EOFError
957
+ close
958
+ buf = nil
959
+ end
960
+ end
961
+ if buf && buf.bytesize > 0
962
+ @content_length -= buf.bytesize
963
+ yield buf
964
+ else
965
+ @content_length = 0
966
+ end
967
+ return if @content_length == 0
968
+ end
969
+ end
970
+
971
+ RS = "\r\n"
972
+ def read_body_chunked(&block)
973
+ buf = empty_bin_str
974
+ while true
975
+ len = @socket.gets(RS)
976
+ if len.nil? # EOF
977
+ close
978
+ return
979
+ end
980
+ @chunk_length = len.hex
981
+ if @chunk_length == 0
982
+ @content_length = 0
983
+ @socket.gets(RS)
984
+ return
985
+ end
986
+ timeout(@receive_timeout, ReceiveTimeoutError) do
987
+ @socket.read(@chunk_length + 2, buf)
988
+ end
989
+ unless buf.empty?
990
+ yield buf.slice(0, @chunk_length)
991
+ end
992
+ end
993
+ end
994
+
995
+ def read_body_rest
996
+ if @readbuf and @readbuf.bytesize > 0
997
+ yield @readbuf
998
+ @readbuf = nil
999
+ end
1000
+ while true
1001
+ buf = empty_bin_str
1002
+ timeout(@receive_timeout, ReceiveTimeoutError) do
1003
+ begin
1004
+ @socket.readpartial(@read_block_size, buf)
1005
+ rescue EOFError
1006
+ buf = nil
1007
+ end
1008
+ end
1009
+ if buf && buf.bytesize > 0
1010
+ yield buf
1011
+ else
1012
+ return
1013
+ end
1014
+ end
1015
+ end
1016
+
1017
+ def empty_bin_str
1018
+ str = ''
1019
+ str.force_encoding('BINARY') if str.respond_to?(:force_encoding)
1020
+ str
1021
+ end
1022
+ end
1023
+
1024
+
1025
+ end