rev 0.1.1 → 0.1.2

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 (207) hide show
  1. data/README +45 -9
  2. data/doc/rdoc/classes/Rev.html +368 -0
  3. data/doc/rdoc/classes/Rev.src/M000001.html +28 -0
  4. data/doc/rdoc/classes/Rev.src/M000002.html +35 -0
  5. data/doc/rdoc/classes/Rev.src/M000003.html +24 -0
  6. data/doc/rdoc/classes/Rev.src/M000004.html +28 -0
  7. data/doc/rdoc/classes/Rev.src/M000005.html +27 -0
  8. data/doc/rdoc/classes/Rev.src/M000006.html +33 -0
  9. data/doc/rdoc/classes/Rev.src/M000007.html +43 -0
  10. data/doc/rdoc/classes/Rev.src/M000008.html +16 -0
  11. data/doc/rdoc/classes/Rev/Buffer.html +354 -0
  12. data/doc/rdoc/classes/Rev/Buffer.src/M000019.html +17 -0
  13. data/doc/rdoc/classes/Rev/Buffer.src/M000020.html +29 -0
  14. data/doc/rdoc/classes/Rev/Buffer.src/M000021.html +27 -0
  15. data/doc/rdoc/classes/Rev/Buffer.src/M000022.html +27 -0
  16. data/doc/rdoc/classes/Rev/Buffer.src/M000023.html +31 -0
  17. data/doc/rdoc/classes/Rev/Buffer.src/M000024.html +31 -0
  18. data/doc/rdoc/classes/Rev/Buffer.src/M000025.html +30 -0
  19. data/doc/rdoc/classes/Rev/Buffer.src/M000026.html +50 -0
  20. data/doc/rdoc/classes/Rev/Buffer.src/M000027.html +22 -0
  21. data/doc/rdoc/classes/Rev/Buffer.src/M000028.html +24 -0
  22. data/doc/rdoc/classes/Rev/Buffer.src/M000029.html +24 -0
  23. data/doc/rdoc/classes/Rev/BufferedIO.html +397 -0
  24. data/doc/rdoc/classes/Rev/BufferedIO.src/M000095.html +23 -0
  25. data/doc/rdoc/classes/Rev/BufferedIO.src/M000096.html +16 -0
  26. data/doc/rdoc/classes/Rev/BufferedIO.src/M000097.html +16 -0
  27. data/doc/rdoc/classes/Rev/BufferedIO.src/M000098.html +16 -0
  28. data/doc/rdoc/classes/Rev/BufferedIO.src/M000099.html +18 -0
  29. data/doc/rdoc/classes/Rev/BufferedIO.src/M000100.html +18 -0
  30. data/doc/rdoc/classes/Rev/BufferedIO.src/M000101.html +23 -0
  31. data/doc/rdoc/classes/Rev/BufferedIO.src/M000102.html +18 -0
  32. data/doc/rdoc/classes/Rev/BufferedIO.src/M000103.html +20 -0
  33. data/doc/rdoc/classes/Rev/BufferedIO.src/M000104.html +24 -0
  34. data/doc/rdoc/classes/Rev/BufferedIO.src/M000105.html +23 -0
  35. data/doc/rdoc/classes/Rev/BufferedIO.src/M000106.html +22 -0
  36. data/doc/rdoc/classes/Rev/BufferedIO.src/M000107.html +29 -0
  37. data/doc/rdoc/classes/Rev/BufferedIO/Writer.html +154 -0
  38. data/doc/rdoc/classes/Rev/BufferedIO/Writer.src/M000108.html +19 -0
  39. data/doc/rdoc/classes/Rev/BufferedIO/Writer.src/M000109.html +18 -0
  40. data/doc/rdoc/classes/Rev/DNSResolver.html +401 -0
  41. data/doc/rdoc/classes/Rev/DNSResolver.src/M000124.html +25 -0
  42. data/doc/rdoc/classes/Rev/DNSResolver.src/M000125.html +29 -0
  43. data/doc/rdoc/classes/Rev/DNSResolver.src/M000126.html +20 -0
  44. data/doc/rdoc/classes/Rev/DNSResolver.src/M000127.html +19 -0
  45. data/doc/rdoc/classes/Rev/DNSResolver.src/M000128.html +16 -0
  46. data/doc/rdoc/classes/Rev/DNSResolver.src/M000129.html +16 -0
  47. data/doc/rdoc/classes/Rev/DNSResolver.src/M000131.html +19 -0
  48. data/doc/rdoc/classes/Rev/DNSResolver.src/M000132.html +21 -0
  49. data/doc/rdoc/classes/Rev/DNSResolver.src/M000133.html +27 -0
  50. data/doc/rdoc/classes/Rev/DNSResolver.src/M000134.html +28 -0
  51. data/doc/rdoc/classes/Rev/DNSResolver.src/M000135.html +55 -0
  52. data/doc/rdoc/classes/Rev/DNSResolver/Timeout.html +154 -0
  53. data/doc/rdoc/classes/Rev/DNSResolver/Timeout.src/M000136.html +20 -0
  54. data/doc/rdoc/classes/Rev/DNSResolver/Timeout.src/M000137.html +22 -0
  55. data/doc/rdoc/classes/Rev/HttpChunkHeader.html +156 -0
  56. data/doc/rdoc/classes/Rev/HttpChunkHeader.src/M000031.html +19 -0
  57. data/doc/rdoc/classes/Rev/HttpClient.html +460 -0
  58. data/doc/rdoc/classes/Rev/HttpClient.src/M000042.html +18 -0
  59. data/doc/rdoc/classes/Rev/HttpClient.src/M000043.html +27 -0
  60. data/doc/rdoc/classes/Rev/HttpClient.src/M000044.html +24 -0
  61. data/doc/rdoc/classes/Rev/HttpClient.src/M000045.html +19 -0
  62. data/doc/rdoc/classes/Rev/HttpClient.src/M000046.html +17 -0
  63. data/doc/rdoc/classes/Rev/HttpClient.src/M000047.html +19 -0
  64. data/doc/rdoc/classes/Rev/HttpClient.src/M000048.html +18 -0
  65. data/doc/rdoc/classes/Rev/HttpClient.src/M000049.html +18 -0
  66. data/doc/rdoc/classes/Rev/HttpClient.src/M000050.html +19 -0
  67. data/doc/rdoc/classes/Rev/HttpClient.src/M000051.html +19 -0
  68. data/doc/rdoc/classes/Rev/HttpClient.src/M000052.html +19 -0
  69. data/doc/rdoc/classes/Rev/HttpClient.src/M000053.html +41 -0
  70. data/doc/rdoc/classes/Rev/HttpClient.src/M000054.html +18 -0
  71. data/doc/rdoc/classes/Rev/HttpClient.src/M000055.html +34 -0
  72. data/doc/rdoc/classes/Rev/HttpEncoding.html +310 -0
  73. data/doc/rdoc/classes/Rev/HttpEncoding.src/M000009.html +20 -0
  74. data/doc/rdoc/classes/Rev/HttpEncoding.src/M000010.html +20 -0
  75. data/doc/rdoc/classes/Rev/HttpEncoding.src/M000011.html +18 -0
  76. data/doc/rdoc/classes/Rev/HttpEncoding.src/M000012.html +18 -0
  77. data/doc/rdoc/classes/Rev/HttpEncoding.src/M000013.html +18 -0
  78. data/doc/rdoc/classes/Rev/HttpEncoding.src/M000014.html +19 -0
  79. data/doc/rdoc/classes/Rev/HttpEncoding.src/M000015.html +18 -0
  80. data/doc/rdoc/classes/Rev/HttpEncoding.src/M000016.html +18 -0
  81. data/doc/rdoc/classes/Rev/HttpEncoding.src/M000017.html +22 -0
  82. data/doc/rdoc/classes/Rev/HttpEncoding.src/M000018.html +18 -0
  83. data/doc/rdoc/classes/Rev/HttpResponseHeader.html +219 -0
  84. data/doc/rdoc/classes/Rev/HttpResponseHeader.src/M000032.html +18 -0
  85. data/doc/rdoc/classes/Rev/HttpResponseHeader.src/M000033.html +18 -0
  86. data/doc/rdoc/classes/Rev/HttpResponseHeader.src/M000034.html +18 -0
  87. data/doc/rdoc/classes/Rev/IOWatcher.html +285 -0
  88. data/doc/rdoc/classes/Rev/IOWatcher.src/M000079.html +17 -0
  89. data/doc/rdoc/classes/Rev/IOWatcher.src/M000080.html +27 -0
  90. data/doc/rdoc/classes/Rev/IOWatcher.src/M000081.html +26 -0
  91. data/doc/rdoc/classes/Rev/IOWatcher.src/M000082.html +27 -0
  92. data/doc/rdoc/classes/Rev/IOWatcher.src/M000083.html +27 -0
  93. data/doc/rdoc/classes/Rev/IOWatcher.src/M000084.html +24 -0
  94. data/doc/rdoc/classes/Rev/IOWatcher.src/M000085.html +25 -0
  95. data/doc/rdoc/classes/Rev/Listener.html +207 -0
  96. data/doc/rdoc/classes/Rev/Listener.src/M000065.html +19 -0
  97. data/doc/rdoc/classes/Rev/Listener.src/M000066.html +19 -0
  98. data/doc/rdoc/classes/Rev/Listener.src/M000067.html +16 -0
  99. data/doc/rdoc/classes/Rev/Listener.src/M000068.html +18 -0
  100. data/doc/rdoc/classes/Rev/Loop.html +395 -0
  101. data/doc/rdoc/classes/Rev/Loop.src/M000070.html +25 -0
  102. data/doc/rdoc/classes/Rev/Loop.src/M000071.html +45 -0
  103. data/doc/rdoc/classes/Rev/Loop.src/M000072.html +18 -0
  104. data/doc/rdoc/classes/Rev/Loop.src/M000073.html +23 -0
  105. data/doc/rdoc/classes/Rev/Loop.src/M000074.html +19 -0
  106. data/doc/rdoc/classes/Rev/Loop.src/M000075.html +17 -0
  107. data/doc/rdoc/classes/Rev/Loop.src/M000076.html +27 -0
  108. data/doc/rdoc/classes/Rev/Loop.src/M000077.html +32 -0
  109. data/doc/rdoc/classes/Rev/Loop.src/M000078.html +32 -0
  110. data/doc/rdoc/classes/Rev/Server.html +164 -0
  111. data/doc/rdoc/classes/Rev/Server.src/M000121.html +32 -0
  112. data/doc/rdoc/classes/Rev/Server.src/M000122.html +20 -0
  113. data/doc/rdoc/classes/Rev/Socket.html +213 -0
  114. data/doc/rdoc/classes/Rev/Socket.src/M000035.html +21 -0
  115. data/doc/rdoc/classes/Rev/Socket.src/M000036.html +25 -0
  116. data/doc/rdoc/classes/Rev/Socket.src/M000037.html +16 -0
  117. data/doc/rdoc/classes/Rev/Socket.src/M000038.html +16 -0
  118. data/doc/rdoc/classes/Rev/Socket/Connector.html +154 -0
  119. data/doc/rdoc/classes/Rev/Socket/Connector.src/M000040.html +19 -0
  120. data/doc/rdoc/classes/Rev/Socket/Connector.src/M000041.html +28 -0
  121. data/doc/rdoc/classes/Rev/TCPListener.html +161 -0
  122. data/doc/rdoc/classes/Rev/TCPListener.src/M000069.html +23 -0
  123. data/doc/rdoc/classes/Rev/TCPServer.html +147 -0
  124. data/doc/rdoc/classes/Rev/TCPServer.src/M000123.html +20 -0
  125. data/doc/rdoc/classes/Rev/TCPSocket.html +233 -0
  126. data/doc/rdoc/classes/Rev/TCPSocket.src/M000056.html +20 -0
  127. data/doc/rdoc/classes/Rev/TCPSocket.src/M000057.html +34 -0
  128. data/doc/rdoc/classes/Rev/TCPSocket.src/M000058.html +24 -0
  129. data/doc/rdoc/classes/Rev/TCPSocket.src/M000059.html +18 -0
  130. data/doc/rdoc/classes/Rev/TCPSocket/TCPConnectResolver.html +171 -0
  131. data/doc/rdoc/classes/Rev/TCPSocket/TCPConnectResolver.src/M000060.html +19 -0
  132. data/doc/rdoc/classes/Rev/TCPSocket/TCPConnectResolver.src/M000061.html +27 -0
  133. data/doc/rdoc/classes/Rev/TCPSocket/TCPConnectResolver.src/M000062.html +23 -0
  134. data/doc/rdoc/classes/Rev/TCPSocket/TCPConnectSocket.html +154 -0
  135. data/doc/rdoc/classes/Rev/TCPSocket/TCPConnectSocket.src/M000063.html +25 -0
  136. data/doc/rdoc/classes/Rev/TCPSocket/TCPConnectSocket.src/M000064.html +23 -0
  137. data/doc/rdoc/classes/Rev/TimerWatcher.html +288 -0
  138. data/doc/rdoc/classes/Rev/TimerWatcher.src/M000086.html +17 -0
  139. data/doc/rdoc/classes/Rev/TimerWatcher.src/M000087.html +27 -0
  140. data/doc/rdoc/classes/Rev/TimerWatcher.src/M000088.html +26 -0
  141. data/doc/rdoc/classes/Rev/TimerWatcher.src/M000089.html +27 -0
  142. data/doc/rdoc/classes/Rev/TimerWatcher.src/M000090.html +27 -0
  143. data/doc/rdoc/classes/Rev/TimerWatcher.src/M000091.html +42 -0
  144. data/doc/rdoc/classes/Rev/TimerWatcher.src/M000092.html +24 -0
  145. data/doc/rdoc/classes/Rev/UNIXListener.html +147 -0
  146. data/doc/rdoc/classes/Rev/UNIXListener.src/M000120.html +18 -0
  147. data/doc/rdoc/classes/Rev/UNIXServer.html +147 -0
  148. data/doc/rdoc/classes/Rev/UNIXServer.src/M000030.html +18 -0
  149. data/doc/rdoc/classes/Rev/UNIXSocket.html +175 -0
  150. data/doc/rdoc/classes/Rev/UNIXSocket.src/M000093.html +18 -0
  151. data/doc/rdoc/classes/Rev/UNIXSocket.src/M000094.html +21 -0
  152. data/doc/rdoc/classes/Rev/Watcher.html +349 -0
  153. data/doc/rdoc/classes/Rev/Watcher.src/M000110.html +20 -0
  154. data/doc/rdoc/classes/Rev/Watcher.src/M000111.html +20 -0
  155. data/doc/rdoc/classes/Rev/Watcher.src/M000112.html +17 -0
  156. data/doc/rdoc/classes/Rev/Watcher.src/M000113.html +48 -0
  157. data/doc/rdoc/classes/Rev/Watcher.src/M000114.html +62 -0
  158. data/doc/rdoc/classes/Rev/Watcher.src/M000115.html +34 -0
  159. data/doc/rdoc/classes/Rev/Watcher.src/M000116.html +34 -0
  160. data/doc/rdoc/classes/Rev/Watcher.src/M000117.html +27 -0
  161. data/doc/rdoc/classes/Rev/Watcher.src/M000118.html +24 -0
  162. data/doc/rdoc/classes/Rev/Watcher.src/M000119.html +27 -0
  163. data/doc/rdoc/created.rid +1 -0
  164. data/doc/rdoc/files/LICENSE.html +165 -0
  165. data/doc/rdoc/files/README.html +297 -0
  166. data/doc/rdoc/files/ext/rev/rev_buffer_c.html +101 -0
  167. data/doc/rdoc/files/ext/rev/rev_ext_c.html +101 -0
  168. data/doc/rdoc/files/ext/rev/rev_io_watcher_c.html +101 -0
  169. data/doc/rdoc/files/ext/rev/rev_loop_c.html +101 -0
  170. data/doc/rdoc/files/ext/rev/rev_timer_watcher_c.html +101 -0
  171. data/doc/rdoc/files/ext/rev/rev_watcher_c.html +101 -0
  172. data/doc/rdoc/files/lib/rev/buffered_io_rb.html +101 -0
  173. data/doc/rdoc/files/lib/rev/dns_resolver_rb.html +101 -0
  174. data/doc/rdoc/files/lib/rev/http_client_rb.html +101 -0
  175. data/doc/rdoc/files/lib/rev/io_watcher_rb.html +101 -0
  176. data/doc/rdoc/files/lib/rev/listener_rb.html +108 -0
  177. data/doc/rdoc/files/lib/rev/loop_rb.html +101 -0
  178. data/doc/rdoc/files/lib/rev/server_rb.html +101 -0
  179. data/doc/rdoc/files/lib/rev/socket_rb.html +109 -0
  180. data/doc/rdoc/files/lib/rev/timer_watcher_rb.html +101 -0
  181. data/doc/rdoc/files/lib/rev/watcher_rb.html +101 -0
  182. data/doc/rdoc/files/lib/rev_rb.html +101 -0
  183. data/doc/rdoc/fr_class_index.html +52 -0
  184. data/doc/rdoc/fr_file_index.html +45 -0
  185. data/doc/rdoc/fr_method_index.html +163 -0
  186. data/doc/rdoc/index.html +24 -0
  187. data/doc/rdoc/rdoc-style.css +208 -0
  188. data/ext/rev/extconf.rb +1 -1
  189. data/ext/rev/rev.h +0 -1
  190. data/ext/rev/rev_buffer.c +606 -0
  191. data/ext/rev/rev_ext.c +1 -0
  192. data/ext/rev/rev_io_watcher.c +53 -19
  193. data/ext/rev/rev_loop.c +12 -35
  194. data/ext/rev/rev_timer_watcher.c +45 -3
  195. data/ext/rev/rev_watcher.c +13 -1
  196. data/lib/http11_client.bundle +0 -0
  197. data/lib/rev.rb +1 -1
  198. data/lib/rev/buffered_io.rb +25 -22
  199. data/lib/rev/dns_resolver.rb +31 -14
  200. data/lib/rev/http_client.rb +88 -91
  201. data/lib/rev/listener.rb +22 -5
  202. data/lib/rev/loop.rb +13 -0
  203. data/lib/rev/server.rb +10 -3
  204. data/lib/rev/socket.rb +30 -9
  205. data/lib/rev/watcher.rb +4 -2
  206. data/lib/rev_ext.bundle +0 -0
  207. metadata +230 -2
@@ -146,7 +146,7 @@ module Rev
146
146
  @parser_nbytes = 0
147
147
 
148
148
  @state = :response_header
149
- @data = ''
149
+ @data = Rev::Buffer.new
150
150
 
151
151
  @response_header = HttpResponseHeader.new
152
152
  @chunk_header = HttpChunkHeader.new
@@ -224,9 +224,8 @@ module Rev
224
224
  end
225
225
 
226
226
  def on_read(data)
227
- until @state == :finished or @state == :invalid or data.empty?
228
- @state, data = dispatch_data(@state, data)
229
- end
227
+ @data << data
228
+ dispatch
230
229
  end
231
230
 
232
231
  #
@@ -273,147 +272,145 @@ module Rev
273
272
  # Response processing
274
273
  #
275
274
 
276
- def dispatch_data(state, data)
277
- case state
278
- when :response_header
279
- parse_response_header(data)
280
- when :chunk_header
281
- parse_chunk_header(data)
282
- when :chunk_body
283
- process_chunk_body(data)
284
- when :chunk_footer
285
- process_chunk_footer(data)
286
- when :response_footer
287
- process_response_footer(data)
288
- when :body
289
- process_body(data)
290
- else raise RuntimeError, "invalid state: #{@state}"
275
+ def dispatch
276
+ while case @state
277
+ when :response_header
278
+ parse_response_header
279
+ when :chunk_header
280
+ parse_chunk_header
281
+ when :chunk_body
282
+ process_chunk_body
283
+ when :chunk_footer
284
+ process_chunk_footer
285
+ when :response_footer
286
+ process_response_footer
287
+ when :body
288
+ process_body
289
+ when :finished, :invalid
290
+ break
291
+ else raise RuntimeError, "invalid state: #{@state}"
292
+ end
291
293
  end
292
294
  end
293
295
 
294
- def parse_header(header, data)
295
- @data << data
296
- @parser_nbytes = @parser.execute(header, @data, @parser_nbytes)
297
- return unless @parser.finished?
296
+ def parse_header(header)
297
+ return false if @data.empty?
298
+
299
+ @parser_nbytes = @parser.execute(header, @data.to_str, @parser_nbytes)
300
+ return false unless @parser.finished?
298
301
 
299
- remainder = @data.slice(@parser_nbytes, @data.size)
300
- @data = ''
302
+ # Clear parsed data from the buffer
303
+ @data.read(@parser_nbytes)
301
304
  @parser.reset
302
305
  @parser_nbytes = 0
303
-
304
- remainder
306
+
307
+ true
305
308
  end
306
309
 
307
- def parse_response_header(data)
308
- data = parse_header(@response_header, data)
309
- return :response_header, '' if data.nil?
310
+ def parse_response_header
311
+ return false unless parse_header(@response_header)
310
312
 
311
313
  unless @response_header.http_status and @response_header.http_reason
312
314
  on_error "no HTTP response"
313
- return :invalid
315
+ @state = :invalid
316
+ return false
314
317
  end
315
318
 
316
319
  on_response_header(@response_header)
317
320
 
318
321
  if @response_header.chunked_encoding?
319
- return :chunk_header, data
322
+ @state = :chunk_header
320
323
  else
324
+ @state = :body
321
325
  @bytes_remaining = @response_header.content_length
322
- return :body, data
323
326
  end
327
+
328
+ true
324
329
  end
325
330
 
326
- def parse_chunk_header(data)
327
- data = parse_header(@chunk_header, data)
328
- return :chunk_header, '' if data.nil?
331
+ def parse_chunk_header
332
+ return false unless parse_header(@chunk_header)
329
333
 
330
334
  @bytes_remaining = @chunk_header.chunk_size
331
335
  @chunk_header = HttpChunkHeader.new
332
336
 
333
- if @bytes_remaining > 0
334
- return :chunk_body, data
335
- else
336
- @bytes_remaining = 2
337
- return :response_footer, data
338
- end
337
+ @state = @bytes_remaining > 0 ? :chunk_body : :response_footer
338
+ true
339
339
  end
340
340
 
341
- def process_chunk_body(data)
342
- if data.size < @bytes_remaining
343
- @bytes_remaining -= data.size
344
- on_body_data data
345
- return :chunk_body, ''
341
+ def process_chunk_body
342
+ if @data.size < @bytes_remaining
343
+ @bytes_remaining -= @data.size
344
+ on_body_data @data.read
345
+ return false
346
346
  end
347
347
 
348
- on_body_data data.slice!(0, @bytes_remaining)
349
- @bytes_remaining = 2
350
- return :chunk_footer, data
348
+ on_body_data @data.read(@bytes_remaining)
349
+ @bytes_remaining = 0
350
+
351
+ @state = :chunk_footer
352
+ true
351
353
  end
352
354
 
353
- def process_crlf(data)
354
- @data << data.slice!(0, @bytes_remaining)
355
- @bytes_remaining = 2 - @data.size
356
- return unless @bytes_remaining == 0
355
+ def process_chunk_footer
356
+ return false if @data.size < 2
357
357
 
358
- matches_crlf = (@data == CRLF)
359
- @data = ''
360
-
361
- return matches_crlf, data
362
- end
363
-
364
- def process_chunk_footer(data)
365
- result, data = process_crlf(data)
366
- return :chunk_footer, '' if result.nil?
367
-
368
- if result
369
- return :chunk_header, data
358
+ if @data.read(2) == CRLF
359
+ @state = :chunk_header
370
360
  else
371
361
  on_error "non-CRLF chunk footer"
372
- return :invalid
362
+ @state = :invalid
373
363
  end
374
- end
375
-
376
- def process_response_footer(data)
377
- result, data = process_crlf(data)
378
- return :response_footer, '' if result.nil?
379
- if result
380
- unless data.empty?
364
+
365
+ true
366
+ end
367
+
368
+ def process_response_footer
369
+ return false if @data.size < 2
370
+
371
+ if @data.read(2) == CRLF
372
+ if @data.empty?
373
+ on_request_complete
374
+ @state = :finished
375
+ else
381
376
  on_error "garbage at end of chunked response"
382
- return :invalid
377
+ @state = :invalid
383
378
  end
384
-
385
- on_request_complete
386
- return :finished
387
379
  else
388
380
  on_error "non-CRLF response footer"
389
- return :invalid
381
+ @state = :invalid
390
382
  end
383
+
384
+ false
391
385
  end
392
386
 
393
- def process_body(data)
387
+ def process_body
394
388
  # FIXME the proper thing to do here is probably to keep reading until
395
389
  # the socket closes, then assume that's the end of the body, provided
396
390
  # the server has specified Connection: close
397
391
  if @bytes_remaining.nil?
398
392
  on_error "no content length specified"
399
- return :invalid
393
+ @state = :invalid
400
394
  end
401
395
 
402
- if data.size < @bytes_remaining
403
- @bytes_remaining -= data.size
404
- on_body_data data
405
- return :body, ''
396
+ if @data.size < @bytes_remaining
397
+ @bytes_remaining -= @data.size
398
+ on_body_data @data.read
399
+ return false
406
400
  end
407
401
 
408
- on_body_data data.slice!(0, @bytes_remaining)
402
+ on_body_data @data.read(@bytes_remaining)
403
+ @bytes_remaining = 0
409
404
 
410
- unless data.empty?
405
+ if @data.empty?
406
+ on_request_complete
407
+ @state = :finished
408
+ else
411
409
  on_error "garbage at end of body"
412
- return :invalid
410
+ @state = :invalid
413
411
  end
414
412
 
415
- on_request_complete
416
- return :finished
413
+ false
417
414
  end
418
415
  end
419
- end
416
+ end
data/lib/rev/listener.rb CHANGED
@@ -8,11 +8,20 @@ require 'socket'
8
8
  require File.dirname(__FILE__) + '/../rev'
9
9
 
10
10
  module Rev
11
+ # Listeners wait for incoming connections. When a listener receives a
12
+ # connection it fires the on_connection event with the newly accepted
13
+ # socket as a parameter.
11
14
  class Listener < IOWatcher
12
15
  def initialize(listen_socket)
13
16
  @listen_socket = listen_socket
14
17
  super(@listen_socket)
15
18
  end
19
+
20
+ # Close the listener
21
+ def close
22
+ detach if attached?
23
+ @listen_socket.close
24
+ end
16
25
 
17
26
  # Called whenever the server receives a new connection
18
27
  def on_connection(socket); end
@@ -29,12 +38,20 @@ module Rev
29
38
  end
30
39
 
31
40
  class TCPListener < Listener
32
- # Create a new Rev::TCPListener
41
+ DEFAULT_BACKLOG = 1024
42
+
43
+ # Create a new Rev::TCPListener on the specified address and port.
44
+ # Accepts the following options:
33
45
  #
34
- # Accepts the same arguments as TCPServer.new
35
- def initialize(*args)
36
- listen_socket = ::TCPServer.new(*args)
37
- listen_socket.instance_eval { listen(1024) } # Change listen backlog to 1024
46
+ # :backlog - Max size of the pending connection queue (default 1024)
47
+ # :reverse_lookup - Retain BasicSocket's reverse DNS functionality (default false)
48
+ #
49
+ def initialize(addr, port, options = {})
50
+ BasicSocket.do_not_reverse_lookup = true unless options[:reverse_lookup]
51
+ options[:backlog] ||= DEFAULT_BACKLOG
52
+
53
+ listen_socket = ::TCPServer.new(addr, port)
54
+ listen_socket.instance_eval { listen(options[:backlog]) }
38
55
  super(listen_socket)
39
56
  end
40
57
  end
data/lib/rev/loop.rb CHANGED
@@ -8,7 +8,20 @@ require File.dirname(__FILE__) + '/../rev'
8
8
 
9
9
  module Rev
10
10
  class Loop
11
+ @@default_loop = {}
11
12
  attr_reader :watchers
13
+
14
+ # Retrieve the default event loop for the current thread
15
+ def self.default
16
+ # Well awesome, variables stashed in Thread.current[]
17
+ # are only accessible in the context of the Fiber where
18
+ # they were stored. Soo... we need to make our own
19
+ # thread-local store if we want Fiber compatibility
20
+ #
21
+ # I think this should be sufficient... but it may need
22
+ # a mutex or something, got me.
23
+ @@default_loop[Thread.current] ||= Loop.new
24
+ end
12
25
 
13
26
  # Create a new Rev::Loop
14
27
  #
data/lib/rev/server.rb CHANGED
@@ -8,10 +8,13 @@ require File.dirname(__FILE__) + '/../rev'
8
8
 
9
9
  module Rev
10
10
  class Server < Listener
11
+ # Servers listen for incoming connections and create new connection objects
12
+ # whenever incoming connections are received. The default class for new
13
+ # connections is a Socket, but any subclass of IOWatcher is acceptable.
11
14
  def initialize(listen_socket, klass = Socket, *args, &block)
12
15
  # Ensure the provided class responds to attach
13
- unless (klass.instance_method(:attach) rescue nil)
14
- raise ArgumentError, "provided class must respond to 'attach'"
16
+ unless klass.allocate.is_a? IOWatcher
17
+ raise ArgumentError, "provided class must descend from IOWatcher"
15
18
  end
16
19
 
17
20
  # Verify the arity of the provided arguments
@@ -37,6 +40,8 @@ module Rev
37
40
  end
38
41
  end
39
42
 
43
+ # TCP server class. Listens on the specified host and port and creates
44
+ # new connection objects of the given class.
40
45
  class TCPServer < Server
41
46
  def initialize(host, port, klass = TCPSocket, *args, &block)
42
47
  listen_socket = ::TCPServer.new(host, port)
@@ -45,9 +50,11 @@ module Rev
45
50
  end
46
51
  end
47
52
 
53
+ # UNIX server class. Listens on the specified UNIX domain socket and
54
+ # creates new connection objects of the given class.
48
55
  class UNIXServer < Server
49
56
  def initialize(path, klass = UNIXSocket, *args, &block)
50
57
  super(::UNIXServer.new(*args), klass, *args, &block)
51
58
  end
52
59
  end
53
- end
60
+ end
data/lib/rev/socket.rb CHANGED
@@ -9,7 +9,7 @@ require 'resolv'
9
9
  require File.dirname(__FILE__) + '/../rev'
10
10
 
11
11
  module Rev
12
- class Socket < BufferedIO
12
+ class Socket < BufferedIO
13
13
  def self.connect(socket, *args)
14
14
  new(socket, *args).instance_eval {
15
15
  @connector = Connector.new(self, socket)
@@ -38,6 +38,10 @@ module Rev
38
38
  def on_connect_failed; end
39
39
  event_callback :on_connect_failed
40
40
 
41
+ # Called if a hostname failed to resolve when connecting
42
+ # Defaults to being aliased to on_connect_failed
43
+ alias_method :on_resolve_failed, :on_connect_failed
44
+
41
45
  #########
42
46
  protected
43
47
  #########
@@ -76,6 +80,17 @@ module Rev
76
80
  attr_reader :remote_host, :remote_addr, :remote_port, :address_family
77
81
  watcher_delegate :@resolver
78
82
 
83
+ # Similar to .new, but used in cases where the resulting object is in a
84
+ # "half-open" state. This is primarily used for when asynchronous
85
+ # DNS resolution is taking place. We don't actually have a handle to
86
+ # the socket we want to use to create the watcher yet, since we don't
87
+ # know the IP address to connect to.
88
+ def self.precreate(*args, &block)
89
+ obj = allocate
90
+ obj.__send__(:preinitialize, *args, &block)
91
+ obj
92
+ end
93
+
79
94
  # Perform a non-blocking connect to the given host and port
80
95
  def self.connect(addr, port, *args)
81
96
  family = nil
@@ -94,13 +109,17 @@ module Rev
94
109
  return connect(host, port, *args)
95
110
  end
96
111
 
97
- return allocate.instance_eval {
98
- @remote_host, @remote_addr, @remote_port = addr, addr, port
99
- @resolver = TCPConnectResolver.new(self, addr, port, *args)
100
- self
101
- }
112
+ precreate(addr, port, *args)
102
113
  end
103
114
 
115
+ # Called by precreate during asyncronous DNS resolution
116
+ def preinitialize(addr, port, *args)
117
+ @remote_host, @remote_addr, @remote_port = addr, addr, port
118
+ @resolver = TCPConnectResolver.new(self, addr, port, *args)
119
+ end
120
+
121
+ private :preinitialize
122
+
104
123
  def initialize(socket)
105
124
  unless socket.is_a?(::TCPSocket) or socket.is_a?(TCPConnectSocket)
106
125
  raise TypeError, "socket must be a TCPSocket"
@@ -111,6 +130,10 @@ module Rev
111
130
  @address_family, @remote_port, @remote_host, @remote_addr = socket.peeraddr
112
131
  end
113
132
 
133
+ def peeraddr
134
+ [@address_family, @remote_port, @remote_host, @remote_addr]
135
+ end
136
+
114
137
  #########
115
138
  protected
116
139
  #########
@@ -157,15 +180,13 @@ module Rev
157
180
  end
158
181
 
159
182
  def on_failure
160
- @sock.on_connect_failed
183
+ @sock.__send__(:on_resolve_failed)
161
184
  @sock.instance_eval {
162
185
  @resolver = nil
163
186
  @failed = true
164
187
  }
165
188
  return
166
189
  end
167
-
168
- alias_method :on_timeout, :on_failure
169
190
  end
170
191
  end
171
192
 
data/lib/rev/watcher.rb CHANGED
@@ -39,8 +39,10 @@ module Rev
39
39
  @#{method}_callback = block
40
40
  return
41
41
  end
42
-
43
- @#{method}_callback.(*([self] + args)) if @#{method}_callback
42
+
43
+ if @#{method}_callback
44
+ instance_exec(*args, &@#{method}_callback)
45
+ end
44
46
  end
45
47
  EOD
46
48
  end