cool.io 1.2.3-x86-mingw32 → 1.4.1-x86-mingw32

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 (52) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +3 -0
  3. data/.travis.yml +3 -3
  4. data/CHANGES.md +35 -0
  5. data/README.md +1 -3
  6. data/Rakefile +11 -13
  7. data/cool.io.gemspec +3 -2
  8. data/examples/callbacked_echo_server.rb +24 -0
  9. data/ext/cool.io/extconf.rb +8 -24
  10. data/ext/cool.io/loop.c +1 -1
  11. data/ext/iobuffer/iobuffer.c +2 -0
  12. data/ext/libev/Changes +123 -4
  13. data/ext/libev/LICENSE +2 -1
  14. data/ext/libev/README +8 -8
  15. data/ext/libev/ev.c +313 -144
  16. data/ext/libev/ev.h +18 -10
  17. data/ext/libev/ev_epoll.c +4 -1
  18. data/ext/libev/ev_kqueue.c +1 -1
  19. data/ext/libev/ev_select.c +3 -4
  20. data/ext/libev/ev_vars.h +3 -2
  21. data/ext/libev/ev_win32.c +1 -1
  22. data/ext/libev/win_select.patch +115 -0
  23. data/lib/cool.io.rb +6 -4
  24. data/lib/cool.io/dns_resolver.rb +4 -10
  25. data/lib/cool.io/dsl.rb +6 -2
  26. data/lib/cool.io/io.rb +36 -16
  27. data/lib/cool.io/loop.rb +3 -11
  28. data/lib/cool.io/meta.rb +2 -2
  29. data/lib/cool.io/version.rb +4 -2
  30. data/spec/async_watcher_spec.rb +5 -5
  31. data/spec/dns_spec.rb +11 -7
  32. data/spec/iobuffer_spec.rb +147 -0
  33. data/spec/spec_helper.rb +2 -2
  34. data/spec/stat_watcher_spec.rb +3 -3
  35. data/spec/tcp_server_spec.rb +98 -5
  36. data/spec/tcp_socket_spec.rb +185 -0
  37. data/spec/timer_watcher_spec.rb +23 -19
  38. data/spec/udp_socket_spec.rb +58 -0
  39. data/spec/unix_listener_spec.rb +7 -7
  40. data/spec/unix_server_spec.rb +7 -7
  41. metadata +83 -103
  42. data/examples/httpclient.rb +0 -38
  43. data/ext/http11_client/.gitignore +0 -5
  44. data/ext/http11_client/LICENSE +0 -31
  45. data/ext/http11_client/ext_help.h +0 -14
  46. data/ext/http11_client/extconf.rb +0 -6
  47. data/ext/http11_client/http11_client.c +0 -300
  48. data/ext/http11_client/http11_parser.c +0 -403
  49. data/ext/http11_client/http11_parser.h +0 -48
  50. data/ext/http11_client/http11_parser.rl +0 -173
  51. data/lib/cool.io/eventmachine.rb +0 -234
  52. data/lib/cool.io/http_client.rb +0 -427
@@ -1,427 +0,0 @@
1
- #--
2
- # Copyright (C)2007-10 Tony Arcieri
3
- # Includes portions originally Copyright (C)2005 Zed Shaw
4
- # You can redistribute this under the terms of the Ruby license
5
- # See file LICENSE for details
6
- #++
7
-
8
- require "cool.io/custom_require"
9
- cool_require 'http11_client'
10
-
11
- module Coolio
12
- # A simple hash is returned for each request made by HttpClient with
13
- # the headers that were given by the server for that request.
14
- class HttpResponseHeader < Hash
15
- # The reason returned in the http response ("OK","File not found",etc.)
16
- attr_accessor :http_reason
17
-
18
- # The HTTP version returned.
19
- attr_accessor :http_version
20
-
21
- # The status code (as a string!)
22
- attr_accessor :http_status
23
-
24
- # HTTP response status as an integer
25
- def status
26
- Integer(http_status) rescue nil
27
- end
28
-
29
- # Length of content as an integer, or nil if chunked/unspecified
30
- def content_length
31
- Integer(self[HttpClient::CONTENT_LENGTH]) rescue nil
32
- end
33
-
34
- # Is the transfer encoding chunked?
35
- def chunked_encoding?
36
- /chunked/i === self[HttpClient::TRANSFER_ENCODING]
37
- end
38
- end
39
-
40
- class HttpChunkHeader < Hash
41
- # When parsing chunked encodings this is set
42
- attr_accessor :http_chunk_size
43
-
44
- # Size of the chunk as an integer
45
- def chunk_size
46
- return @chunk_size unless @chunk_size.nil?
47
- @chunk_size = @http_chunk_size ? @http_chunk_size.to_i(base=16) : 0
48
- end
49
- end
50
-
51
- # Methods for building HTTP requests
52
- module HttpEncoding
53
- HTTP_REQUEST_HEADER="%s %s HTTP/1.1\r\n"
54
- FIELD_ENCODING = "%s: %s\r\n"
55
-
56
- # Escapes a URI.
57
- def escape(s)
58
- s.to_s.gsub(/([^ a-zA-Z0-9_.-]+)/n) {
59
- '%'+$1.unpack('H2'*$1.size).join('%').upcase
60
- }.tr(' ', '+')
61
- end
62
-
63
- # Unescapes a URI escaped string.
64
- def unescape(s)
65
- s.tr('+', ' ').gsub(/((?:%[0-9a-fA-F]{2})+)/n){
66
- [$1.delete('%')].pack('H*')
67
- }
68
- end
69
-
70
- # Map all header keys to a downcased string version
71
- def munge_header_keys(head)
72
- head.inject({}) { |h, (k, v)| h[k.to_s.downcase] = v; h }
73
- end
74
-
75
- # HTTP is kind of retarded that you have to specify
76
- # a Host header, but if you include port 80 then further
77
- # redirects will tack on the :80 which is annoying.
78
- def encode_host
79
- remote_host + (remote_port.to_i != 80 ? ":#{remote_port}" : "")
80
- end
81
-
82
- def encode_request(method, path, query)
83
- HTTP_REQUEST_HEADER % [method.to_s.upcase, encode_query(path, query)]
84
- end
85
-
86
- def encode_query(path, query)
87
- return path unless query
88
- path + "?" + query.map { |k, v| encode_param(k, v) }.join('&')
89
- end
90
-
91
- # URL encodes a single k=v parameter.
92
- def encode_param(k, v)
93
- escape(k) + "=" + escape(v)
94
- end
95
-
96
- # Encode a field in an HTTP header
97
- def encode_field(k, v)
98
- FIELD_ENCODING % [k, v]
99
- end
100
-
101
- def encode_headers(head)
102
- head.inject('') do |result, (key, value)|
103
- # Munge keys from foo-bar-baz to Foo-Bar-Baz
104
- key = key.split('-').map { |k| k.capitalize }.join('-')
105
- result << encode_field(key, value)
106
- end
107
- end
108
-
109
- def encode_cookies(cookies)
110
- cookies.inject('') { |result, (k, v)| result << encode_field('Cookie', encode_param(k, v)) }
111
- end
112
- end
113
-
114
- # HTTP client class implemented as a subclass of Coolio::TCPSocket. Encodes
115
- # requests and allows streaming consumption of the response. Response is
116
- # parsed with a Ragel-generated whitelist parser which supports chunked
117
- # HTTP encoding.
118
- #
119
- # == Example
120
- #
121
- # loop = Coolio::Loop.default
122
- # client = Coolio::HttpClient.connect("www.google.com").attach(loop)
123
- # client.request('GET', '/search', query: {q: 'foobar'})
124
- # loop.run
125
- #
126
- class HttpClient < TCPSocket
127
- include HttpEncoding
128
-
129
- ALLOWED_METHODS=[:put, :get, :post, :delete, :head]
130
- TRANSFER_ENCODING="TRANSFER_ENCODING"
131
- CONTENT_LENGTH="CONTENT_LENGTH"
132
- SET_COOKIE="SET_COOKIE"
133
- LOCATION="LOCATION"
134
- HOST="HOST"
135
- CRLF="\r\n"
136
-
137
- # Connect to the given server, with port 80 as the default
138
- def self.connect(addr, port = 80, *args)
139
- super
140
- end
141
-
142
- def initialize(socket)
143
- super
144
-
145
- @parser = HttpClientParser.new
146
- @parser_nbytes = 0
147
-
148
- @state = :response_header
149
- @data = ::IO::Buffer.new
150
-
151
- @response_header = HttpResponseHeader.new
152
- @chunk_header = HttpChunkHeader.new
153
- end
154
-
155
- # Send an HTTP request and consume the response.
156
- # Supports the following options:
157
- #
158
- # head: {Key: Value}
159
- # Specify an HTTP header, e.g. {'Connection': 'close'}
160
- #
161
- # query: {Key: Value}
162
- # Specify query string parameters (auto-escaped)
163
- #
164
- # cookies: {Key: Value}
165
- # Specify hash of cookies (auto-escaped)
166
- #
167
- # body: String
168
- # Specify the request body (you must encode it for now)
169
- #
170
- def request(method, path, options = {})
171
- raise ArgumentError, "invalid request path" unless /^\// === path
172
- raise RuntimeError, "request already sent" if @requested
173
-
174
- @method, @path, @options = method, path, options
175
- @requested = true
176
-
177
- return unless @connected
178
- send_request
179
- end
180
-
181
- # Enable the HttpClient if it has been disabled
182
- def enable
183
- super
184
- dispatch unless @data.empty?
185
- end
186
-
187
- # Called when response header has been received
188
- def on_response_header(response_header)
189
- end
190
-
191
- # Called when part of the body has been read
192
- def on_body_data(data)
193
- STDOUT.write data
194
- STDOUT.flush
195
- end
196
-
197
- # Called when the request has completed
198
- def on_request_complete
199
- @state == :finished ? close : @state = :finished
200
- end
201
-
202
- # called by close
203
- def on_close
204
- if @state != :finished and @state == :body
205
- on_request_complete
206
- end
207
- end
208
-
209
- # Called when an error occurs dispatching the request
210
- def on_error(reason)
211
- close
212
- raise RuntimeError, reason
213
- end
214
-
215
- #########
216
- protected
217
- #########
218
-
219
- #
220
- # Coolio callbacks
221
- #
222
-
223
- def on_connect
224
- @connected = true
225
- send_request if @method and @path
226
- end
227
-
228
- def on_read(data)
229
- @data << data
230
- dispatch
231
- end
232
-
233
- #
234
- # Request sending
235
- #
236
-
237
- def send_request
238
- send_request_header
239
- send_request_body
240
- end
241
-
242
- def send_request_header
243
- query = @options[:query]
244
- head = @options[:head] ? munge_header_keys(@options[:head]) : {}
245
- cookies = @options[:cookies]
246
- body = @options[:body]
247
-
248
- # Set the Host header if it hasn't been specified already
249
- head['host'] ||= encode_host
250
-
251
- # Set the Content-Length if it hasn't been specified already and a body was given
252
- head['content-length'] ||= body ? body.length : 0
253
-
254
- # Set the User-Agent if it hasn't been specified
255
- head['user-agent'] ||= "Coolio #{Coolio::VERSION}"
256
-
257
- # Default to Connection: close
258
- head['connection'] ||= 'close'
259
-
260
- # Build the request
261
- request_header = encode_request(@method, @path, query)
262
- request_header << encode_headers(head)
263
- request_header << encode_cookies(cookies) if cookies
264
- request_header << CRLF
265
-
266
- write request_header
267
- end
268
-
269
- def send_request_body
270
- write @options[:body] if @options[:body]
271
- end
272
-
273
- #
274
- # Response processing
275
- #
276
-
277
- def dispatch
278
- while enabled? and case @state
279
- when :response_header
280
- parse_response_header
281
- when :chunk_header
282
- parse_chunk_header
283
- when :chunk_body
284
- process_chunk_body
285
- when :chunk_footer
286
- process_chunk_footer
287
- when :response_footer
288
- process_response_footer
289
- when :body
290
- process_body
291
- when :finished, :invalid
292
- break
293
- else raise RuntimeError, "invalid state: #{@state}"
294
- end
295
- end
296
- end
297
-
298
- def parse_header(header)
299
- return false if @data.empty?
300
-
301
- begin
302
- @parser_nbytes = @parser.execute(header, @data.to_str, @parser_nbytes)
303
- rescue Coolio::HttpClientParserError
304
- on_error "invalid HTTP format, parsing fails"
305
- @state = :invalid
306
- end
307
-
308
- return false unless @parser.finished?
309
-
310
- # Clear parsed data from the buffer
311
- @data.read(@parser_nbytes)
312
- @parser.reset
313
- @parser_nbytes = 0
314
-
315
- true
316
- end
317
-
318
- def parse_response_header
319
- return false unless parse_header(@response_header)
320
-
321
- unless @response_header.http_status and @response_header.http_reason
322
- on_error "no HTTP response"
323
- @state = :invalid
324
- return false
325
- end
326
-
327
- on_response_header(@response_header)
328
-
329
- if @response_header.chunked_encoding?
330
- @state = :chunk_header
331
- else
332
- @state = :body
333
- @bytes_remaining = @response_header.content_length
334
- end
335
-
336
- true
337
- end
338
-
339
- def parse_chunk_header
340
- return false unless parse_header(@chunk_header)
341
-
342
- @bytes_remaining = @chunk_header.chunk_size
343
- @chunk_header = HttpChunkHeader.new
344
-
345
- @state = @bytes_remaining > 0 ? :chunk_body : :response_footer
346
- true
347
- end
348
-
349
- def process_chunk_body
350
- if @data.size < @bytes_remaining
351
- @bytes_remaining -= @data.size
352
- on_body_data @data.read
353
- return false
354
- end
355
-
356
- on_body_data @data.read(@bytes_remaining)
357
- @bytes_remaining = 0
358
-
359
- @state = :chunk_footer
360
- true
361
- end
362
-
363
- def process_chunk_footer
364
- return false if @data.size < 2
365
-
366
- if @data.read(2) == CRLF
367
- @state = :chunk_header
368
- else
369
- on_error "non-CRLF chunk footer"
370
- @state = :invalid
371
- end
372
-
373
- true
374
- end
375
-
376
- def process_response_footer
377
- return false if @data.size < 2
378
-
379
- if @data.read(2) == CRLF
380
- if @data.empty?
381
- on_request_complete
382
- @state = :finished
383
- else
384
- on_error "garbage at end of chunked response"
385
- @state = :invalid
386
- end
387
- else
388
- on_error "non-CRLF response footer"
389
- @state = :invalid
390
- end
391
-
392
- false
393
- end
394
-
395
- def process_body
396
- if @bytes_remaining.nil?
397
- on_body_data @data.read
398
- return false
399
- end
400
-
401
- if @bytes_remaining.zero?
402
- on_request_complete
403
- @state = :finished
404
- return false
405
- end
406
-
407
- if @data.size < @bytes_remaining
408
- @bytes_remaining -= @data.size
409
- on_body_data @data.read
410
- return false
411
- end
412
-
413
- on_body_data @data.read(@bytes_remaining)
414
- @bytes_remaining = 0
415
-
416
- if @data.empty?
417
- on_request_complete
418
- @state = :finished
419
- else
420
- on_error "garbage at end of body"
421
- @state = :invalid
422
- end
423
-
424
- false
425
- end
426
- end
427
- end