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

Sign up to get free protection for your applications and to get access to all the features.
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