sensu-em 2.0.0-java

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (177) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +21 -0
  3. data/.travis.yml +12 -0
  4. data/.yardopts +7 -0
  5. data/CHANGELOG.md +33 -0
  6. data/GNU +281 -0
  7. data/Gemfile +2 -0
  8. data/LICENSE +60 -0
  9. data/README.md +109 -0
  10. data/Rakefile +20 -0
  11. data/docs/DocumentationGuidesIndex.md +27 -0
  12. data/docs/GettingStarted.md +521 -0
  13. data/docs/old/ChangeLog +211 -0
  14. data/docs/old/DEFERRABLES +246 -0
  15. data/docs/old/EPOLL +141 -0
  16. data/docs/old/INSTALL +13 -0
  17. data/docs/old/KEYBOARD +42 -0
  18. data/docs/old/LEGAL +25 -0
  19. data/docs/old/LIGHTWEIGHT_CONCURRENCY +130 -0
  20. data/docs/old/PURE_RUBY +75 -0
  21. data/docs/old/RELEASE_NOTES +94 -0
  22. data/docs/old/SMTP +4 -0
  23. data/docs/old/SPAWNED_PROCESSES +148 -0
  24. data/docs/old/TODO +8 -0
  25. data/eventmachine.gemspec +38 -0
  26. data/examples/guides/getting_started/01_eventmachine_echo_server.rb +18 -0
  27. data/examples/guides/getting_started/02_eventmachine_echo_server_that_recognizes_exit_command.rb +22 -0
  28. data/examples/guides/getting_started/03_simple_chat_server.rb +149 -0
  29. data/examples/guides/getting_started/04_simple_chat_server_step_one.rb +27 -0
  30. data/examples/guides/getting_started/05_simple_chat_server_step_two.rb +43 -0
  31. data/examples/guides/getting_started/06_simple_chat_server_step_three.rb +98 -0
  32. data/examples/guides/getting_started/07_simple_chat_server_step_four.rb +121 -0
  33. data/examples/guides/getting_started/08_simple_chat_server_step_five.rb +141 -0
  34. data/examples/old/ex_channel.rb +43 -0
  35. data/examples/old/ex_queue.rb +2 -0
  36. data/examples/old/ex_tick_loop_array.rb +15 -0
  37. data/examples/old/ex_tick_loop_counter.rb +32 -0
  38. data/examples/old/helper.rb +2 -0
  39. data/ext/binder.cpp +124 -0
  40. data/ext/binder.h +46 -0
  41. data/ext/cmain.cpp +887 -0
  42. data/ext/ed.cpp +1988 -0
  43. data/ext/ed.h +422 -0
  44. data/ext/em.cpp +2352 -0
  45. data/ext/em.h +253 -0
  46. data/ext/eventmachine.h +128 -0
  47. data/ext/extconf.rb +179 -0
  48. data/ext/fastfilereader/extconf.rb +103 -0
  49. data/ext/fastfilereader/mapper.cpp +214 -0
  50. data/ext/fastfilereader/mapper.h +59 -0
  51. data/ext/fastfilereader/rubymain.cpp +127 -0
  52. data/ext/kb.cpp +79 -0
  53. data/ext/page.cpp +107 -0
  54. data/ext/page.h +51 -0
  55. data/ext/pipe.cpp +347 -0
  56. data/ext/project.h +161 -0
  57. data/ext/rubymain.cpp +1318 -0
  58. data/ext/ssl.cpp +468 -0
  59. data/ext/ssl.h +94 -0
  60. data/java/.classpath +6 -0
  61. data/java/.gitignore +1 -0
  62. data/java/.project +17 -0
  63. data/java/src/com/rubyeventmachine/DatagramPacket.java +13 -0
  64. data/java/src/com/rubyeventmachine/EmReactor.java +529 -0
  65. data/java/src/com/rubyeventmachine/EmReactorException.java +40 -0
  66. data/java/src/com/rubyeventmachine/EventCallback.java +7 -0
  67. data/java/src/com/rubyeventmachine/EventCode.java +26 -0
  68. data/java/src/com/rubyeventmachine/EventableChannel.java +130 -0
  69. data/java/src/com/rubyeventmachine/EventableDatagramChannel.java +180 -0
  70. data/java/src/com/rubyeventmachine/EventableSocketChannel.java +405 -0
  71. data/java/src/com/rubyeventmachine/SslBox.java +310 -0
  72. data/lib/em/buftok.rb +110 -0
  73. data/lib/em/callback.rb +58 -0
  74. data/lib/em/channel.rb +64 -0
  75. data/lib/em/completion.rb +304 -0
  76. data/lib/em/connection.rb +712 -0
  77. data/lib/em/deferrable/pool.rb +2 -0
  78. data/lib/em/deferrable.rb +210 -0
  79. data/lib/em/file_watch.rb +73 -0
  80. data/lib/em/future.rb +61 -0
  81. data/lib/em/iterator.rb +231 -0
  82. data/lib/em/messages.rb +66 -0
  83. data/lib/em/pool.rb +151 -0
  84. data/lib/em/process_watch.rb +45 -0
  85. data/lib/em/processes.rb +123 -0
  86. data/lib/em/protocols/header_and_content.rb +138 -0
  87. data/lib/em/protocols/httpclient.rb +279 -0
  88. data/lib/em/protocols/httpclient2.rb +600 -0
  89. data/lib/em/protocols/line_and_text.rb +125 -0
  90. data/lib/em/protocols/line_protocol.rb +29 -0
  91. data/lib/em/protocols/linetext2.rb +161 -0
  92. data/lib/em/protocols/memcache.rb +331 -0
  93. data/lib/em/protocols/object_protocol.rb +46 -0
  94. data/lib/em/protocols/postgres3.rb +246 -0
  95. data/lib/em/protocols/saslauth.rb +175 -0
  96. data/lib/em/protocols/smtpclient.rb +365 -0
  97. data/lib/em/protocols/smtpserver.rb +643 -0
  98. data/lib/em/protocols/socks4.rb +66 -0
  99. data/lib/em/protocols/stomp.rb +205 -0
  100. data/lib/em/protocols/tcptest.rb +54 -0
  101. data/lib/em/protocols.rb +37 -0
  102. data/lib/em/pure_ruby.rb +1017 -0
  103. data/lib/em/queue.rb +71 -0
  104. data/lib/em/resolver.rb +209 -0
  105. data/lib/em/spawnable.rb +84 -0
  106. data/lib/em/streamer.rb +118 -0
  107. data/lib/em/threaded_resource.rb +90 -0
  108. data/lib/em/tick_loop.rb +85 -0
  109. data/lib/em/timers.rb +61 -0
  110. data/lib/em/version.rb +3 -0
  111. data/lib/eventmachine.rb +1553 -0
  112. data/lib/jeventmachine.rb +321 -0
  113. data/lib/rubyeventmachine.jar +0 -0
  114. data/rakelib/cpp.rake_example +77 -0
  115. data/rakelib/package.rake +98 -0
  116. data/rakelib/test.rake +8 -0
  117. data/tests/client.crt +31 -0
  118. data/tests/client.key +51 -0
  119. data/tests/em_test_helper.rb +64 -0
  120. data/tests/server.crt +36 -0
  121. data/tests/server.key +51 -0
  122. data/tests/test_attach.rb +150 -0
  123. data/tests/test_basic.rb +294 -0
  124. data/tests/test_channel.rb +62 -0
  125. data/tests/test_completion.rb +177 -0
  126. data/tests/test_connection_count.rb +53 -0
  127. data/tests/test_defer.rb +18 -0
  128. data/tests/test_deferrable.rb +35 -0
  129. data/tests/test_epoll.rb +145 -0
  130. data/tests/test_error_handler.rb +38 -0
  131. data/tests/test_exc.rb +28 -0
  132. data/tests/test_file_watch.rb +65 -0
  133. data/tests/test_futures.rb +170 -0
  134. data/tests/test_get_sock_opt.rb +37 -0
  135. data/tests/test_handler_check.rb +35 -0
  136. data/tests/test_hc.rb +155 -0
  137. data/tests/test_httpclient.rb +190 -0
  138. data/tests/test_httpclient2.rb +133 -0
  139. data/tests/test_idle_connection.rb +25 -0
  140. data/tests/test_inactivity_timeout.rb +54 -0
  141. data/tests/test_iterator.rb +97 -0
  142. data/tests/test_kb.rb +34 -0
  143. data/tests/test_line_protocol.rb +33 -0
  144. data/tests/test_ltp.rb +138 -0
  145. data/tests/test_ltp2.rb +288 -0
  146. data/tests/test_next_tick.rb +104 -0
  147. data/tests/test_object_protocol.rb +36 -0
  148. data/tests/test_pause.rb +102 -0
  149. data/tests/test_pending_connect_timeout.rb +52 -0
  150. data/tests/test_pool.rb +194 -0
  151. data/tests/test_process_watch.rb +48 -0
  152. data/tests/test_processes.rb +128 -0
  153. data/tests/test_proxy_connection.rb +180 -0
  154. data/tests/test_pure.rb +88 -0
  155. data/tests/test_queue.rb +50 -0
  156. data/tests/test_resolver.rb +55 -0
  157. data/tests/test_running.rb +14 -0
  158. data/tests/test_sasl.rb +47 -0
  159. data/tests/test_send_file.rb +217 -0
  160. data/tests/test_servers.rb +33 -0
  161. data/tests/test_set_sock_opt.rb +37 -0
  162. data/tests/test_shutdown_hooks.rb +23 -0
  163. data/tests/test_smtpclient.rb +55 -0
  164. data/tests/test_smtpserver.rb +57 -0
  165. data/tests/test_spawn.rb +293 -0
  166. data/tests/test_ssl_args.rb +78 -0
  167. data/tests/test_ssl_echo_data.rb +60 -0
  168. data/tests/test_ssl_methods.rb +56 -0
  169. data/tests/test_ssl_verify.rb +82 -0
  170. data/tests/test_stomp.rb +37 -0
  171. data/tests/test_system.rb +42 -0
  172. data/tests/test_threaded_resource.rb +53 -0
  173. data/tests/test_tick_loop.rb +59 -0
  174. data/tests/test_timers.rb +123 -0
  175. data/tests/test_ud.rb +8 -0
  176. data/tests/test_unbind_reason.rb +48 -0
  177. metadata +297 -0
@@ -0,0 +1,600 @@
1
+ #--
2
+ #
3
+ # Author:: Francis Cianfrocca (gmail: blackhedd)
4
+ # Homepage:: http://rubyeventmachine.com
5
+ # Date:: 16 July 2006
6
+ #
7
+ # See EventMachine and EventMachine::Connection for documentation and
8
+ # usage examples.
9
+ #
10
+ #----------------------------------------------------------------------------
11
+ #
12
+ # Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
13
+ # Gmail: blackhedd
14
+ #
15
+ # This program is free software; you can redistribute it and/or modify
16
+ # it under the terms of either: 1) the GNU General Public License
17
+ # as published by the Free Software Foundation; either version 2 of the
18
+ # License, or (at your option) any later version; or 2) Ruby's License.
19
+ #
20
+ # See the file COPYING for complete licensing information.
21
+ #
22
+ #---------------------------------------------------------------------------
23
+ #
24
+ #
25
+
26
+ module EventMachine
27
+ module Protocols
28
+
29
+ # <b>Note:</b> This class is deprecated and will be removed. Please use EM-HTTP-Request instead.
30
+ #
31
+ # === Usage
32
+ #
33
+ # EM.run{
34
+ # conn = EM::Protocols::HttpClient2.connect 'google.com', 80
35
+ #
36
+ # req = conn.get('/')
37
+ # req.callback{ |response|
38
+ # p(response.status)
39
+ # p(response.headers)
40
+ # p(response.content)
41
+ # }
42
+ # }
43
+ class HttpClient2 < Connection
44
+ include LineText2
45
+
46
+ def initialize
47
+ warn "HttpClient2 is deprecated and will be removed. EM-Http-Request should be used instead."
48
+
49
+ @authorization = nil
50
+ @closed = nil
51
+ @requests = nil
52
+ end
53
+
54
+ # @private
55
+ class Request
56
+ include Deferrable
57
+
58
+ attr_reader :version
59
+ attr_reader :status
60
+ attr_reader :header_lines
61
+ attr_reader :headers
62
+ attr_reader :content
63
+ attr_reader :internal_error
64
+
65
+ def initialize conn, args
66
+ @conn = conn
67
+ @args = args
68
+ @header_lines = []
69
+ @headers = {}
70
+ @blanks = 0
71
+ @chunk_trailer = nil
72
+ @chunking = nil
73
+ end
74
+
75
+ def send_request
76
+ az = @args[:authorization] and az = "Authorization: #{az}\r\n"
77
+
78
+ r = [
79
+ "#{@args[:verb]} #{@args[:uri]} HTTP/#{@args[:version] || "1.1"}\r\n",
80
+ "Host: #{@args[:host_header] || "_"}\r\n",
81
+ az || "",
82
+ "\r\n"
83
+ ]
84
+ @conn.send_data r.join
85
+ end
86
+
87
+
88
+ #--
89
+ #
90
+ def receive_line ln
91
+ if @chunk_trailer
92
+ receive_chunk_trailer(ln)
93
+ elsif @chunking
94
+ receive_chunk_header(ln)
95
+ else
96
+ receive_header_line(ln)
97
+ end
98
+ end
99
+
100
+ #--
101
+ #
102
+ def receive_chunk_trailer ln
103
+ if ln.length == 0
104
+ @conn.pop_request
105
+ succeed(self)
106
+ else
107
+ p "Received chunk trailer line"
108
+ end
109
+ end
110
+
111
+ #--
112
+ # Allow up to ten blank lines before we get a real response line.
113
+ # Allow no more than 100 lines in the header.
114
+ #
115
+ def receive_header_line ln
116
+ if ln.length == 0
117
+ if @header_lines.length > 0
118
+ process_header
119
+ else
120
+ @blanks += 1
121
+ if @blanks > 10
122
+ @conn.close_connection
123
+ end
124
+ end
125
+ else
126
+ @header_lines << ln
127
+ if @header_lines.length > 100
128
+ @internal_error = :bad_header
129
+ @conn.close_connection
130
+ end
131
+ end
132
+ end
133
+
134
+ #--
135
+ # Cf RFC 2616 pgh 3.6.1 for the format of HTTP chunks.
136
+ #
137
+ def receive_chunk_header ln
138
+ if ln.length > 0
139
+ chunksize = ln.to_i(16)
140
+ if chunksize > 0
141
+ @conn.set_text_mode(ln.to_i(16))
142
+ else
143
+ @content = @content ? @content.join : ''
144
+ @chunk_trailer = true
145
+ end
146
+ else
147
+ # We correctly come here after each chunk gets read.
148
+ # p "Got A BLANK chunk line"
149
+ end
150
+
151
+ end
152
+
153
+
154
+ #--
155
+ # We get a single chunk. Append it to the incoming content and switch back to line mode.
156
+ #
157
+ def receive_chunked_text text
158
+ # p "RECEIVED #{text.length} CHUNK"
159
+ (@content ||= []) << text
160
+ end
161
+
162
+
163
+ #--
164
+ # TODO, inefficient how we're handling this. Part of it is done so as to
165
+ # make sure we don't have problems in detecting chunked-encoding, content-length,
166
+ # etc.
167
+ #
168
+ HttpResponseRE = /\AHTTP\/(1.[01]) ([\d]{3})/i
169
+ ClenRE = /\AContent-length:\s*(\d+)/i
170
+ ChunkedRE = /\ATransfer-encoding:\s*chunked/i
171
+ ColonRE = /\:\s*/
172
+
173
+ def process_header
174
+ unless @header_lines.first =~ HttpResponseRE
175
+ @conn.close_connection
176
+ @internal_error = :bad_request
177
+ end
178
+ @version = $1.dup
179
+ @status = $2.dup.to_i
180
+
181
+ clen = nil
182
+ chunks = nil
183
+ @header_lines.each_with_index do |e,ix|
184
+ if ix > 0
185
+ hdr,val = e.split(ColonRE,2)
186
+ (@headers[hdr.downcase] ||= []) << val
187
+ end
188
+
189
+ if clen == nil and e =~ ClenRE
190
+ clen = $1.dup.to_i
191
+ end
192
+ if e =~ ChunkedRE
193
+ chunks = true
194
+ end
195
+ end
196
+
197
+ if clen
198
+ # If the content length is zero we should not call set_text_mode,
199
+ # because a value of zero will make it wait forever, hanging the
200
+ # connection. Just return success instead, with empty content.
201
+ if clen == 0 then
202
+ @content = ""
203
+ @conn.pop_request
204
+ succeed(self)
205
+ else
206
+ @conn.set_text_mode clen
207
+ end
208
+ elsif chunks
209
+ @chunking = true
210
+ else
211
+ # Chunked transfer, multipart, or end-of-connection.
212
+ # For end-of-connection, we need to go the unbind
213
+ # method and suppress its desire to fail us.
214
+ p "NO CLEN"
215
+ p @args[:uri]
216
+ p @header_lines
217
+ @internal_error = :unsupported_clen
218
+ @conn.close_connection
219
+ end
220
+ end
221
+ private :process_header
222
+
223
+
224
+ def receive_text text
225
+ @chunking ? receive_chunked_text(text) : receive_sized_text(text)
226
+ end
227
+
228
+ #--
229
+ # At the present time, we only handle contents that have a length
230
+ # specified by the content-length header.
231
+ #
232
+ def receive_sized_text text
233
+ @content = text
234
+ @conn.pop_request
235
+ succeed(self)
236
+ end
237
+ end
238
+
239
+ # Make a connection to a remote HTTP server.
240
+ # Can take either a pair of arguments (which will be interpreted as
241
+ # a hostname/ip-address and a port), or a hash.
242
+ # If the arguments are a hash, then supported values include:
243
+ # :host => a hostname or ip-address
244
+ # :port => a port number
245
+ # :ssl => true to enable ssl
246
+ def self.connect *args
247
+ if args.length == 2
248
+ args = {:host=>args[0], :port=>args[1]}
249
+ else
250
+ args = args.first
251
+ end
252
+
253
+ h,prt,ssl = args[:host], Integer(args[:port]), (args[:tls] || args[:ssl])
254
+ conn = EM.connect( h, prt, self )
255
+ conn.start_tls if ssl
256
+ conn.set_default_host_header( h, prt, ssl )
257
+ conn
258
+ end
259
+
260
+ # Get a url
261
+ #
262
+ # req = conn.get(:uri => '/')
263
+ # req.callback{|response| puts response.content }
264
+ #
265
+ def get args
266
+ if args.is_a?(String)
267
+ args = {:uri=>args}
268
+ end
269
+ args[:verb] = "GET"
270
+ request args
271
+ end
272
+
273
+ # Post to a url
274
+ #
275
+ # req = conn.post('/data')
276
+ # req.callback{|response| puts response.content }
277
+ #--
278
+ # XXX there's no way to supply a POST body.. wtf?
279
+ def post args
280
+ if args.is_a?(String)
281
+ args = {:uri=>args}
282
+ end
283
+ args[:verb] = "POST"
284
+ request args
285
+ end
286
+
287
+
288
+ #--
289
+ # Compute and remember a string to be used as the host header in HTTP requests
290
+ # unless the user overrides it with an argument to #request.
291
+ #
292
+ # @private
293
+ def set_default_host_header host, port, ssl
294
+ if (ssl and port != 443) or (!ssl and port != 80)
295
+ @host_header = "#{host}:#{port}"
296
+ else
297
+ @host_header = host
298
+ end
299
+ end
300
+
301
+
302
+ # @private
303
+ def post_init
304
+ super
305
+ @connected = EM::DefaultDeferrable.new
306
+ end
307
+
308
+ # @private
309
+ def connection_completed
310
+ super
311
+ @connected.succeed
312
+ end
313
+
314
+ #--
315
+ # All pending requests, if any, must fail.
316
+ # We might come here without ever passing through connection_completed
317
+ # in case we can't connect to the server. We'll also get here when the
318
+ # connection closes (either because the server closes it, or we close it
319
+ # due to detecting an internal error or security violation).
320
+ # In either case, run down all pending requests, if any, and signal failure
321
+ # on them.
322
+ #
323
+ # Set and remember a flag (@closed) so we can immediately fail any
324
+ # subsequent requests.
325
+ #
326
+ # @private
327
+ def unbind
328
+ super
329
+ @closed = true
330
+ (@requests || []).each {|r| r.fail}
331
+ end
332
+
333
+ # @private
334
+ def request args
335
+ args[:host_header] = @host_header unless args.has_key?(:host_header)
336
+ args[:authorization] = @authorization unless args.has_key?(:authorization)
337
+ r = Request.new self, args
338
+ if @closed
339
+ r.fail
340
+ else
341
+ (@requests ||= []).unshift r
342
+ @connected.callback {r.send_request}
343
+ end
344
+ r
345
+ end
346
+
347
+ # @private
348
+ def receive_line ln
349
+ if req = @requests.last
350
+ req.receive_line ln
351
+ else
352
+ p "??????????"
353
+ p ln
354
+ end
355
+ end
356
+
357
+ # @private
358
+ def receive_binary_data text
359
+ @requests.last.receive_text text
360
+ end
361
+
362
+ #--
363
+ # Called by a Request object when it completes.
364
+ #
365
+ # @private
366
+ def pop_request
367
+ @requests.pop
368
+ end
369
+ end
370
+
371
+
372
+ =begin
373
+ class HttpClient2x < Connection
374
+ include LineText2
375
+
376
+ # TODO: Make this behave appropriate in case a #connect fails.
377
+ # Currently, this produces no errors.
378
+
379
+ # Make a connection to a remote HTTP server.
380
+ # Can take either a pair of arguments (which will be interpreted as
381
+ # a hostname/ip-address and a port), or a hash.
382
+ # If the arguments are a hash, then supported values include:
383
+ # :host => a hostname or ip-address;
384
+ # :port => a port number
385
+ #--
386
+ # TODO, support optional encryption arguments like :ssl
387
+ def self.connect *args
388
+ if args.length == 2
389
+ args = {:host=>args[0], :port=>args[1]}
390
+ else
391
+ args = args.first
392
+ end
393
+
394
+ h,prt = args[:host],Integer(args[:port])
395
+ EM.connect( h, prt, self, h, prt )
396
+ end
397
+
398
+
399
+ #--
400
+ # Sugars a connection that makes a single request and then
401
+ # closes the connection. Matches the behavior and the arguments
402
+ # of the original implementation of class HttpClient.
403
+ #
404
+ # Intended primarily for back compatibility, but the idiom
405
+ # is probably useful so it's not deprecated.
406
+ # We return a Deferrable, as did the original implementation.
407
+ #
408
+ # Because we're improving the way we deal with errors and exceptions
409
+ # (specifically, HTTP response codes other than 2xx will trigger the
410
+ # errback rather than the callback), this may break some existing code.
411
+ #
412
+ def self.request args
413
+ c = connect args
414
+ end
415
+
416
+ #--
417
+ # Requests can be pipelined. When we get a request, add it to the
418
+ # front of a queue as an array. The last element of the @requests
419
+ # array is always the oldest request received. Each element of the
420
+ # @requests array is a two-element array consisting of a hash with
421
+ # the original caller's arguments, and an initially-empty Ostruct
422
+ # containing the data we retrieve from the server's response.
423
+ # Maintain the instance variable @current_response, which is the response
424
+ # of the oldest pending request. That's just to make other code a little
425
+ # easier. If the variable doesn't exist when we come here, we're
426
+ # obviously the first request being made on the connection.
427
+ #
428
+ # The reason for keeping this method private (and requiring use of the
429
+ # convenience methods #get, #post, #head, etc) is to avoid the small
430
+ # performance penalty of canonicalizing the verb.
431
+ #
432
+ def request args
433
+ d = EventMachine::DefaultDeferrable.new
434
+
435
+ if @closed
436
+ d.fail
437
+ return d
438
+ end
439
+
440
+ o = OpenStruct.new
441
+ o.deferrable = d
442
+ (@requests ||= []).unshift [args, o]
443
+ @current_response ||= @requests.last.last
444
+ @connected.callback {
445
+ az = args[:authorization] and az = "Authorization: #{az}\r\n"
446
+
447
+ r = [
448
+ "#{args[:verb]} #{args[:uri]} HTTP/#{args[:version] || "1.1"}\r\n",
449
+ "Host: #{args[:host_header] || @host_header}\r\n",
450
+ az || "",
451
+ "\r\n"
452
+ ]
453
+ p r
454
+ send_data r.join
455
+ }
456
+ o.deferrable
457
+ end
458
+ private :request
459
+
460
+ def get args
461
+ if args.is_a?(String)
462
+ args = {:uri=>args}
463
+ end
464
+ args[:verb] = "GET"
465
+ request args
466
+ end
467
+
468
+ def initialize host, port
469
+ super
470
+ @host_header = "#{host}:#{port}"
471
+ end
472
+ def post_init
473
+ super
474
+ @connected = EM::DefaultDeferrable.new
475
+ end
476
+
477
+
478
+ def connection_completed
479
+ super
480
+ @connected.succeed
481
+ end
482
+
483
+ #--
484
+ # Make sure to throw away any leftover incoming data if we've
485
+ # been closed due to recognizing an error.
486
+ #
487
+ # Generate an internal error if we get an unreasonable number of
488
+ # header lines. It could be malicious.
489
+ #
490
+ def receive_line ln
491
+ p ln
492
+ return if @closed
493
+
494
+ if ln.length > 0
495
+ (@current_response.headers ||= []).push ln
496
+ abort_connection if @current_response.headers.length > 100
497
+ else
498
+ process_received_headers
499
+ end
500
+ end
501
+
502
+ #--
503
+ # We come here when we've seen all the headers for a particular request.
504
+ # What we do next depends on the response line (which should be the
505
+ # first line in the header set), and whether there is content to read.
506
+ # We may transition into a text-reading state to read content, or
507
+ # we may abort the connection, or we may go right back into parsing
508
+ # responses for the next response in the chain.
509
+ #
510
+ # We make an ASSUMPTION that the first line is an HTTP response.
511
+ # Anything else produces an error that aborts the connection.
512
+ # This may not be enough, because it may be that responses to pipelined
513
+ # requests will come with a blank-line delimiter.
514
+ #
515
+ # Any non-2xx response will be treated as a fatal error, and abort the
516
+ # connection. We will set up the status and other response parameters.
517
+ # TODO: we will want to properly support 1xx responses, which some versions
518
+ # of IIS copiously generate.
519
+ # TODO: We need to give the option of not aborting the connection with certain
520
+ # non-200 responses, in order to work with NTLM and other authentication
521
+ # schemes that work at the level of individual connections.
522
+ #
523
+ # Some error responses will get sugarings. For example, we'll return the
524
+ # Location header in the response in case of a 301/302 response.
525
+ #
526
+ # Possible dispositions here:
527
+ # 1) No content to read (either content-length is zero or it's a HEAD request);
528
+ # 2) Switch to text mode to read a specific number of bytes;
529
+ # 3) Read a chunked or multipart response;
530
+ # 4) Read till the server closes the connection.
531
+ #
532
+ # Our reponse to the client can be either to wait till all the content
533
+ # has been read and then to signal caller's deferrable, or else to signal
534
+ # it when we finish the processing the headers and then expect the caller
535
+ # to have given us a block to call as the content comes in. And of course
536
+ # the latter gets stickier with chunks and multiparts.
537
+ #
538
+ HttpResponseRE = /\AHTTP\/(1.[01]) ([\d]{3})/i
539
+ ClenRE = /\AContent-length:\s*(\d+)/i
540
+ def process_received_headers
541
+ abort_connection unless @current_response.headers.first =~ HttpResponseRE
542
+ @current_response.version = $1.dup
543
+ st = $2.dup
544
+ @current_response.status = st.to_i
545
+ abort_connection unless st[0,1] == "2"
546
+
547
+ clen = nil
548
+ @current_response.headers.each do |e|
549
+ if clen == nil and e =~ ClenRE
550
+ clen = $1.dup.to_i
551
+ end
552
+ end
553
+
554
+ if clen
555
+ set_text_mode clen
556
+ end
557
+ end
558
+ private :process_received_headers
559
+
560
+
561
+ def receive_binary_data text
562
+ @current_response.content = text
563
+ @current_response.deferrable.succeed @current_response
564
+ @requests.pop
565
+ @current_response = (@requests.last || []).last
566
+ set_line_mode
567
+ end
568
+
569
+
570
+
571
+ # We've received either a server error or an internal error.
572
+ # Close the connection and abort any pending requests.
573
+ #--
574
+ # When should we call close_connection? It will cause #unbind
575
+ # to be fired. Should the user expect to see #unbind before
576
+ # we call #receive_http_error, or the other way around?
577
+ #
578
+ # Set instance variable @closed. That's used to inhibit further
579
+ # processing of any inbound data after an error has been recognized.
580
+ #
581
+ # We shouldn't have to worry about any leftover outbound data,
582
+ # because we call close_connection (not close_connection_after_writing).
583
+ # That ensures that any pipelined requests received after an error
584
+ # DO NOT get streamed out to the server on this connection.
585
+ # Very important. TODO, write a unit-test to establish that behavior.
586
+ #
587
+ def abort_connection
588
+ close_connection
589
+ @closed = true
590
+ @current_response.deferrable.fail( @current_response )
591
+ end
592
+
593
+
594
+ #------------------------
595
+ # Below here are user-overridable methods.
596
+
597
+ end
598
+ =end
599
+ end
600
+ end