cool.io 1.0.0 → 1.1.0
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.
- data/.gitignore +26 -0
- data/.rspec +3 -0
- data/.travis.yml +4 -0
- data/{CHANGES → CHANGES.md} +43 -79
- data/Gemfile +4 -0
- data/Gemfile.lock +32 -0
- data/{README.markdown → README.md} +0 -4
- data/Rakefile +31 -67
- data/cool.io.gemspec +25 -133
- data/ext/cool.io/extconf.rb +3 -0
- data/ext/cool.io/stat_watcher.c +99 -23
- data/ext/libev/Changes +24 -0
- data/ext/libev/ev.c +78 -32
- data/ext/libev/ev.h +11 -8
- data/ext/libev/ev_epoll.c +39 -7
- data/ext/libev/ev_kqueue.c +5 -5
- data/ext/libev/ev_poll.c +5 -5
- data/ext/libev/ev_port.c +26 -11
- data/ext/libev/ev_select.c +11 -8
- data/ext/libev/ev_vars.h +10 -4
- data/ext/libev/ev_win32.c +6 -6
- data/ext/libev/ev_wrap.h +10 -0
- data/lib/cool.io.rb +3 -3
- data/lib/cool.io/async_watcher.rb +1 -1
- data/lib/cool.io/dns_resolver.rb +14 -12
- data/lib/cool.io/dsl.rb +26 -26
- data/lib/cool.io/eventmachine.rb +18 -18
- data/lib/cool.io/http_client.rb +29 -22
- data/lib/cool.io/io.rb +18 -18
- data/lib/cool.io/iowatcher.rb +1 -1
- data/lib/cool.io/listener.rb +2 -2
- data/lib/cool.io/loop.rb +12 -12
- data/lib/cool.io/meta.rb +4 -4
- data/lib/cool.io/server.rb +3 -3
- data/lib/cool.io/socket.rb +36 -28
- data/lib/cool.io/timer_watcher.rb +1 -1
- data/lib/cool.io/version.rb +5 -0
- data/lib/coolio.rb +1 -1
- data/spec/stat_watcher_spec.rb +77 -0
- metadata +47 -56
- data/VERSION +0 -1
- data/lib/rev.rb +0 -4
- data/spec/possible_tests/schedules_other_threads.rb +0 -48
- data/spec/possible_tests/test_on_resolve_failed.rb +0 -9
- data/spec/possible_tests/test_resolves.rb +0 -27
- data/spec/possible_tests/test_write_during_resolve.rb +0 -27
- data/spec/possible_tests/works_straight.rb +0 -71
data/ext/libev/ev_wrap.h
CHANGED
@@ -40,6 +40,9 @@
|
|
40
40
|
#define pollidxmax ((loop)->pollidxmax)
|
41
41
|
#define epoll_events ((loop)->epoll_events)
|
42
42
|
#define epoll_eventmax ((loop)->epoll_eventmax)
|
43
|
+
#define epoll_eperms ((loop)->epoll_eperms)
|
44
|
+
#define epoll_epermcnt ((loop)->epoll_epermcnt)
|
45
|
+
#define epoll_epermmax ((loop)->epoll_epermmax)
|
43
46
|
#define kqueue_changes ((loop)->kqueue_changes)
|
44
47
|
#define kqueue_changemax ((loop)->kqueue_changemax)
|
45
48
|
#define kqueue_changecnt ((loop)->kqueue_changecnt)
|
@@ -82,9 +85,11 @@
|
|
82
85
|
#define fs_2625 ((loop)->fs_2625)
|
83
86
|
#define fs_hash ((loop)->fs_hash)
|
84
87
|
#define sig_pending ((loop)->sig_pending)
|
88
|
+
#define nosigmask ((loop)->nosigmask)
|
85
89
|
#define sigfd ((loop)->sigfd)
|
86
90
|
#define sigfd_w ((loop)->sigfd_w)
|
87
91
|
#define sigfd_set ((loop)->sigfd_set)
|
92
|
+
#define origflags ((loop)->origflags)
|
88
93
|
#define loop_count ((loop)->loop_count)
|
89
94
|
#define loop_depth ((loop)->loop_depth)
|
90
95
|
#define userdata ((loop)->userdata)
|
@@ -132,6 +137,9 @@
|
|
132
137
|
#undef pollidxmax
|
133
138
|
#undef epoll_events
|
134
139
|
#undef epoll_eventmax
|
140
|
+
#undef epoll_eperms
|
141
|
+
#undef epoll_epermcnt
|
142
|
+
#undef epoll_epermmax
|
135
143
|
#undef kqueue_changes
|
136
144
|
#undef kqueue_changemax
|
137
145
|
#undef kqueue_changecnt
|
@@ -174,9 +182,11 @@
|
|
174
182
|
#undef fs_2625
|
175
183
|
#undef fs_hash
|
176
184
|
#undef sig_pending
|
185
|
+
#undef nosigmask
|
177
186
|
#undef sigfd
|
178
187
|
#undef sigfd_w
|
179
188
|
#undef sigfd_set
|
189
|
+
#undef origflags
|
180
190
|
#undef loop_count
|
181
191
|
#undef loop_depth
|
182
192
|
#undef userdata
|
data/lib/cool.io.rb
CHANGED
@@ -1,12 +1,14 @@
|
|
1
1
|
#--
|
2
|
-
# Copyright (C)
|
2
|
+
# Copyright (C)2011 Tony Arcieri
|
3
3
|
# You can redistribute this under the terms of the Ruby license
|
4
4
|
# See file LICENSE for details
|
5
5
|
#++
|
6
6
|
|
7
7
|
require 'iobuffer'
|
8
8
|
|
9
|
+
require "cool.io/version"
|
9
10
|
require "cool.io_ext"
|
11
|
+
|
10
12
|
require "cool.io/loop"
|
11
13
|
require "cool.io/meta"
|
12
14
|
require "cool.io/io"
|
@@ -21,8 +23,6 @@ require "cool.io/http_client"
|
|
21
23
|
require "cool.io/dsl"
|
22
24
|
|
23
25
|
module Coolio
|
24
|
-
VERSION = File.read(File.expand_path('../../VERSION', __FILE__)).strip
|
25
|
-
def self.version; VERSION; end
|
26
26
|
def self.inspect; "Cool.io"; end
|
27
27
|
end
|
28
28
|
|
data/lib/cool.io/dns_resolver.rb
CHANGED
@@ -9,7 +9,7 @@
|
|
9
9
|
# as best I could with extremely limited knowledge of the DNS format. There's
|
10
10
|
# obviously a ton of stuff it doesn't support (like IPv6 and TCP).
|
11
11
|
#
|
12
|
-
# If you do know what you're doing with DNS, feel free to improve this!
|
12
|
+
# If you do know what you're doing with DNS, feel free to improve this!
|
13
13
|
# A good starting point my be this EventMachine Net::DNS-based asynchronous
|
14
14
|
# resolver:
|
15
15
|
#
|
@@ -44,10 +44,12 @@ module Coolio
|
|
44
44
|
# Query /etc/hosts (or the specified hostfile) for the given host
|
45
45
|
def self.hosts(host, hostfile = HOSTS)
|
46
46
|
hosts = {}
|
47
|
-
File.open(hostfile)
|
48
|
-
|
49
|
-
|
50
|
-
|
47
|
+
File.open(hostfile) do |f|
|
48
|
+
f.each_line do |host_entry|
|
49
|
+
entries = host_entry.gsub(/#.*$/, '').gsub(/\s+/, ' ').split(' ')
|
50
|
+
addr = entries.shift
|
51
|
+
entries.each { |e| hosts[e] ||= addr }
|
52
|
+
end
|
51
53
|
end
|
52
54
|
|
53
55
|
hosts[host]
|
@@ -65,10 +67,10 @@ module Coolio
|
|
65
67
|
|
66
68
|
@nameservers = nameservers
|
67
69
|
@question = request_question hostname
|
68
|
-
|
70
|
+
|
69
71
|
@socket = UDPSocket.new
|
70
72
|
@timer = Timeout.new(self)
|
71
|
-
|
73
|
+
|
72
74
|
super(@socket)
|
73
75
|
end
|
74
76
|
|
@@ -110,7 +112,7 @@ module Coolio
|
|
110
112
|
begin
|
111
113
|
@socket.send request_message, 0
|
112
114
|
rescue Errno::EHOSTUNREACH # TODO figure out why it has to be wrapper here, when the other wrapper should be wrapping this one!
|
113
|
-
end
|
115
|
+
end
|
114
116
|
end
|
115
117
|
|
116
118
|
# Called by the subclass when the DNS response is available
|
@@ -120,7 +122,7 @@ module Coolio
|
|
120
122
|
datagram = @socket.recvfrom_nonblock(DATAGRAM_SIZE).first
|
121
123
|
rescue Errno::ECONNREFUSED
|
122
124
|
end
|
123
|
-
|
125
|
+
|
124
126
|
address = response_address datagram rescue nil
|
125
127
|
address ? on_success(address) : on_failure
|
126
128
|
detach
|
@@ -128,7 +130,7 @@ module Coolio
|
|
128
130
|
|
129
131
|
def request_question(hostname)
|
130
132
|
raise ArgumentError, "hostname cannot be nil" if hostname.nil?
|
131
|
-
|
133
|
+
|
132
134
|
# Query name
|
133
135
|
message = hostname.split('.').map { |s| [s.size].pack('C') << s }.join + "\0"
|
134
136
|
|
@@ -149,7 +151,7 @@ module Coolio
|
|
149
151
|
qdcount = 1
|
150
152
|
|
151
153
|
# No answer, authority, or additional records
|
152
|
-
ancount = nscount = arcount = 0
|
154
|
+
ancount = nscount = arcount = 0
|
153
155
|
|
154
156
|
message << [qdcount, ancount, nscount, arcount].pack('nnnn')
|
155
157
|
message << @question
|
@@ -210,7 +212,7 @@ module Coolio
|
|
210
212
|
return @resolver.__send__(:send_request)
|
211
213
|
rescue Errno::EHOSTUNREACH # if the DNS is toast try again after the timeout occurs again
|
212
214
|
return nil
|
213
|
-
end
|
215
|
+
end
|
214
216
|
end
|
215
217
|
@resolver.__send__(:on_timeout)
|
216
218
|
@resolver.detach
|
data/lib/cool.io/dsl.rb
CHANGED
@@ -7,112 +7,112 @@
|
|
7
7
|
module Coolio
|
8
8
|
# A module we stash all the connections defined by the DSL under
|
9
9
|
module Connections; end
|
10
|
-
|
10
|
+
|
11
11
|
# A DSL for defining Cool.io connection types and servers
|
12
12
|
module DSL
|
13
13
|
# Define all methods on the metaclass
|
14
14
|
module_function
|
15
|
-
|
15
|
+
|
16
16
|
# Run the default Cool.io event loop
|
17
17
|
def run
|
18
18
|
Cool.io::Loop.default.run
|
19
19
|
end
|
20
|
-
|
20
|
+
|
21
21
|
# Connect to the given host and port using the given connection class
|
22
22
|
def connect(host, port, connection_name = nil, *initializer_args, &block)
|
23
23
|
if block_given?
|
24
24
|
initializer_args.unshift connection_name if connection_name
|
25
|
-
|
25
|
+
|
26
26
|
klass = Class.new Cool.io::TCPSocket
|
27
27
|
connection_builder = ConnectionBuilder.new klass
|
28
|
-
connection_builder.instance_eval
|
28
|
+
connection_builder.instance_eval(&block)
|
29
29
|
else
|
30
30
|
raise ArgumentError, "no connection name or block given" unless connection_name
|
31
31
|
klass = self[connection_name]
|
32
32
|
end
|
33
|
-
|
33
|
+
|
34
34
|
client = klass.connect host, port, *initializer_args
|
35
35
|
client.attach Cool.io::Loop.default
|
36
36
|
client
|
37
37
|
end
|
38
|
-
|
38
|
+
|
39
39
|
# Create a new Cool.io::TCPServer
|
40
40
|
def server(host, port, connection_name = nil, *initializer_args, &block)
|
41
41
|
if block_given?
|
42
42
|
initializer_args.unshift connection_name if connection_name
|
43
|
-
|
43
|
+
|
44
44
|
klass = Class.new Cool.io::TCPSocket
|
45
45
|
connection_builder = ConnectionBuilder.new klass
|
46
|
-
connection_builder.instance_eval
|
46
|
+
connection_builder.instance_eval(&block)
|
47
47
|
else
|
48
48
|
raise ArgumentError, "no connection name or block given" unless connection_name
|
49
49
|
klass = self[connection_name]
|
50
50
|
end
|
51
|
-
|
51
|
+
|
52
52
|
server = Cool.io::TCPServer.new host, port, klass, *initializer_args
|
53
53
|
server.attach Cool.io::Loop.default
|
54
54
|
server
|
55
55
|
end
|
56
|
-
|
56
|
+
|
57
57
|
# Create a new Cool.io::TCPSocket class
|
58
58
|
def connection(name, &block)
|
59
59
|
# Camelize class name
|
60
60
|
class_name = name.to_s.split('_').map { |s| s.capitalize }.join
|
61
|
-
|
61
|
+
|
62
62
|
connection = Class.new Cool.io::TCPSocket
|
63
63
|
connection_builder = ConnectionBuilder.new connection
|
64
|
-
connection_builder.instance_eval
|
65
|
-
|
64
|
+
connection_builder.instance_eval(&block)
|
65
|
+
|
66
66
|
Coolio::Connections.const_set class_name, connection
|
67
67
|
end
|
68
|
-
|
68
|
+
|
69
69
|
# Look up a connection class by its name
|
70
70
|
def [](connection_name)
|
71
71
|
class_name = connection_name.to_s.split('_').map { |s| s.capitalize }.join
|
72
|
-
|
72
|
+
|
73
73
|
begin
|
74
74
|
Coolio::Connections.const_get class_name
|
75
75
|
rescue NameError
|
76
76
|
raise NameError, "No connection type registered for #{connection_name.inspect}"
|
77
77
|
end
|
78
78
|
end
|
79
|
-
|
79
|
+
|
80
80
|
# Builder for Cool.io::TCPSocket classes
|
81
81
|
class ConnectionBuilder
|
82
82
|
def initialize(klass)
|
83
83
|
@klass = klass
|
84
84
|
end
|
85
|
-
|
85
|
+
|
86
86
|
# Declare an initialize function
|
87
87
|
def initializer(&action)
|
88
88
|
@klass.send :define_method, :initialize, &action
|
89
89
|
end
|
90
|
-
|
90
|
+
|
91
91
|
# Declare the on_connect callback
|
92
92
|
def on_connect(&action)
|
93
93
|
@klass.send :define_method, :on_connect, &action
|
94
94
|
end
|
95
|
-
|
95
|
+
|
96
96
|
# Declare a callback fired if we failed to connect
|
97
97
|
def on_connect_failed(&action)
|
98
98
|
@klass.send :define_method, :on_connect_failed, &action
|
99
99
|
end
|
100
|
-
|
100
|
+
|
101
101
|
# Declare a callback fired if DNS resolution failed
|
102
102
|
def on_resolve_failed(&action)
|
103
103
|
@klass.send :define_method, :on_resolve_failed, &action
|
104
104
|
end
|
105
|
-
|
105
|
+
|
106
106
|
# Declare the on_close callback
|
107
107
|
def on_close(&action)
|
108
108
|
@klass.send :define_method, :on_close, &action
|
109
109
|
end
|
110
|
-
|
110
|
+
|
111
111
|
# Declare the on_read callback
|
112
112
|
def on_read(&action)
|
113
113
|
@klass.send :define_method, :on_read, &action
|
114
114
|
end
|
115
|
-
|
115
|
+
|
116
116
|
# Declare the on_write_complete callback
|
117
117
|
def on_write_complete(&action)
|
118
118
|
@klass.send :define_method, :on_write_complete, &action
|
@@ -126,10 +126,10 @@ module Cool
|
|
126
126
|
module Coolness
|
127
127
|
def cool; Cool::IOThunk; end
|
128
128
|
end
|
129
|
-
|
129
|
+
|
130
130
|
module IOThunk
|
131
131
|
def self.io; Coolio::DSL; end
|
132
132
|
end
|
133
133
|
end
|
134
134
|
|
135
|
-
extend Cool::Coolness
|
135
|
+
extend Cool::Coolness
|
data/lib/cool.io/eventmachine.rb
CHANGED
@@ -43,8 +43,8 @@ module EventMachine
|
|
43
43
|
def add_timer(interval, proc = nil, &block)
|
44
44
|
block ||= proc
|
45
45
|
t = OneShotEMTimer.new(interval, false) # non repeating
|
46
|
-
t.setup(block)
|
47
|
-
|
46
|
+
t.setup(block)
|
47
|
+
|
48
48
|
# fire 'er off ltodo: do we keep track of these timers in memory?
|
49
49
|
t.attach(Coolio::Loop.default)
|
50
50
|
t
|
@@ -53,7 +53,7 @@ module EventMachine
|
|
53
53
|
def cancel_timer(t)
|
54
54
|
# guess there's a case where EM you can say 'cancel' but it's already fired?
|
55
55
|
# kind of odd but it happens
|
56
|
-
t.detach if t.attached?
|
56
|
+
t.detach if t.attached?
|
57
57
|
end
|
58
58
|
|
59
59
|
def set_comm_inactivity_timeout(*args); end # TODO
|
@@ -76,7 +76,7 @@ module EventMachine
|
|
76
76
|
wrapped_child.call_back_to_this(conn) # calls post_init for us
|
77
77
|
yield conn if block_given?
|
78
78
|
end
|
79
|
-
|
79
|
+
|
80
80
|
# Start a TCP server on the given address and port
|
81
81
|
def start_server(addr, port, handler = Connection, *args, &block)
|
82
82
|
# make sure we're a 'real' class here
|
@@ -85,11 +85,11 @@ module EventMachine
|
|
85
85
|
else
|
86
86
|
Class.new( Connection ) {handler and include handler}
|
87
87
|
end
|
88
|
-
|
89
|
-
server = Coolio::TCPServer.new(addr, port, CallsBackToEM, *args) do |wrapped_child|
|
88
|
+
|
89
|
+
server = Coolio::TCPServer.new(addr, port, CallsBackToEM, *args) do |wrapped_child|
|
90
90
|
conn = klass.new(wrapped_child)
|
91
91
|
conn.heres_your_socket(wrapped_child) # ideally NOT have this :)
|
92
|
-
wrapped_child.call_back_to_this(conn)
|
92
|
+
wrapped_child.call_back_to_this(conn)
|
93
93
|
block.call(conn) if block
|
94
94
|
end
|
95
95
|
|
@@ -126,9 +126,9 @@ module EventMachine
|
|
126
126
|
end
|
127
127
|
|
128
128
|
def on_connect
|
129
|
-
# @connection_timer.detach if @connection_timer
|
129
|
+
# @connection_timer.detach if @connection_timer
|
130
130
|
# won't need that anymore :) -- with server connecteds we don't have it, anyway
|
131
|
-
|
131
|
+
|
132
132
|
# TODO should server accepted's call this? They don't currently
|
133
133
|
# [and can't, since on_connect gets called basically in the initializer--needs some code love for that to happen :)
|
134
134
|
@call_back_to_this.connection_completed if @call_back_to_this
|
@@ -136,10 +136,10 @@ module EventMachine
|
|
136
136
|
|
137
137
|
def connection_has_timed_out
|
138
138
|
return if closed?
|
139
|
-
|
139
|
+
|
140
140
|
# wonder if this works when you're within a half-connected phase.
|
141
141
|
# I think it does. What about TCP state?
|
142
|
-
close unless closed?
|
142
|
+
close unless closed?
|
143
143
|
@call_back_to_this.unbind
|
144
144
|
end
|
145
145
|
|
@@ -188,18 +188,18 @@ module EventMachine
|
|
188
188
|
# initialize *args
|
189
189
|
#end
|
190
190
|
end
|
191
|
-
|
191
|
+
|
192
192
|
# we will need to call 'their functions' appropriately -- the commented out ones, here
|
193
|
-
#
|
193
|
+
#
|
194
194
|
# Callback fired when connection is created
|
195
195
|
def post_init
|
196
|
-
# I thought we were 'overriding' EM's existing methods, here.
|
196
|
+
# I thought we were 'overriding' EM's existing methods, here.
|
197
197
|
# Huh? Why do we have to define these then?
|
198
198
|
end
|
199
199
|
|
200
200
|
# Callback fired when connection is closed
|
201
201
|
def unbind; end
|
202
|
-
|
202
|
+
|
203
203
|
# Callback fired when data is received
|
204
204
|
# def receive_data(data); end
|
205
205
|
def heres_your_socket(instantiated_coolio_socket)
|
@@ -211,13 +211,13 @@ module EventMachine
|
|
211
211
|
def send_data(data)
|
212
212
|
@wrapped_coolio.write data
|
213
213
|
end
|
214
|
-
|
214
|
+
|
215
215
|
# Close the connection, optionally after writing
|
216
216
|
def close_connection(after_writing = false)
|
217
217
|
return close_connection_after_writing if after_writing
|
218
218
|
@wrapped_coolio.close
|
219
219
|
end
|
220
|
-
|
220
|
+
|
221
221
|
# Close the connection after all data has been written
|
222
222
|
def close_connection_after_writing
|
223
223
|
@wrapped_coolio.output_buffer_size.zero? ? @wrapped_coolio.close : @wrapped_coolio.should_close_after_writing
|
@@ -231,4 +231,4 @@ module EventMachine
|
|
231
231
|
end
|
232
232
|
|
233
233
|
# Shortcut constant
|
234
|
-
EM = EventMachine
|
234
|
+
EM = EventMachine
|
data/lib/cool.io/http_client.rb
CHANGED
@@ -29,12 +29,12 @@ module Coolio
|
|
29
29
|
def content_length
|
30
30
|
Integer(self[HttpClient::CONTENT_LENGTH]) rescue nil
|
31
31
|
end
|
32
|
-
|
32
|
+
|
33
33
|
# Is the transfer encoding chunked?
|
34
34
|
def chunked_encoding?
|
35
35
|
/chunked/i === self[HttpClient::TRANSFER_ENCODING]
|
36
36
|
end
|
37
|
-
|
37
|
+
end
|
38
38
|
|
39
39
|
class HttpChunkHeader < Hash
|
40
40
|
# When parsing chunked encodings this is set
|
@@ -56,14 +56,14 @@ module Coolio
|
|
56
56
|
def escape(s)
|
57
57
|
s.to_s.gsub(/([^ a-zA-Z0-9_.-]+)/n) {
|
58
58
|
'%'+$1.unpack('H2'*$1.size).join('%').upcase
|
59
|
-
}.tr(' ', '+')
|
59
|
+
}.tr(' ', '+')
|
60
60
|
end
|
61
61
|
|
62
62
|
# Unescapes a URI escaped string.
|
63
63
|
def unescape(s)
|
64
64
|
s.tr('+', ' ').gsub(/((?:%[0-9a-fA-F]{2})+)/n){
|
65
65
|
[$1.delete('%')].pack('H*')
|
66
|
-
}
|
66
|
+
}
|
67
67
|
end
|
68
68
|
|
69
69
|
# Map all header keys to a downcased string version
|
@@ -151,11 +151,11 @@ module Coolio
|
|
151
151
|
@chunk_header = HttpChunkHeader.new
|
152
152
|
end
|
153
153
|
|
154
|
-
# Send an HTTP request and consume the response.
|
154
|
+
# Send an HTTP request and consume the response.
|
155
155
|
# Supports the following options:
|
156
156
|
#
|
157
157
|
# head: {Key: Value}
|
158
|
-
# Specify an HTTP header, e.g. {'Connection': 'close'}
|
158
|
+
# Specify an HTTP header, e.g. {'Connection': 'close'}
|
159
159
|
#
|
160
160
|
# query: {Key: Value}
|
161
161
|
# Specify query string parameters (auto-escaped)
|
@@ -176,7 +176,7 @@ module Coolio
|
|
176
176
|
return unless @connected
|
177
177
|
send_request
|
178
178
|
end
|
179
|
-
|
179
|
+
|
180
180
|
# Enable the HttpClient if it has been disabled
|
181
181
|
def enable
|
182
182
|
super
|
@@ -195,7 +195,14 @@ module Coolio
|
|
195
195
|
|
196
196
|
# Called when the request has completed
|
197
197
|
def on_request_complete
|
198
|
-
close
|
198
|
+
@state == :finished ? close : @state = :finished
|
199
|
+
end
|
200
|
+
|
201
|
+
# called by close
|
202
|
+
def on_close
|
203
|
+
if @state != :finished and @state == :body
|
204
|
+
on_request_complete
|
205
|
+
end
|
199
206
|
end
|
200
207
|
|
201
208
|
# Called when an error occurs dispatching the request
|
@@ -211,7 +218,7 @@ module Coolio
|
|
211
218
|
#
|
212
219
|
# Coolio callbacks
|
213
220
|
#
|
214
|
-
|
221
|
+
|
215
222
|
def on_connect
|
216
223
|
@connected = true
|
217
224
|
send_request if @method and @path
|
@@ -260,8 +267,8 @@ module Coolio
|
|
260
267
|
|
261
268
|
def send_request_body
|
262
269
|
write @options[:body] if @options[:body]
|
263
|
-
end
|
264
|
-
|
270
|
+
end
|
271
|
+
|
265
272
|
#
|
266
273
|
# Response processing
|
267
274
|
#
|
@@ -289,21 +296,21 @@ module Coolio
|
|
289
296
|
|
290
297
|
def parse_header(header)
|
291
298
|
return false if @data.empty?
|
292
|
-
|
299
|
+
|
293
300
|
begin
|
294
301
|
@parser_nbytes = @parser.execute(header, @data.to_str, @parser_nbytes)
|
295
302
|
rescue Coolio::HttpClientParserError
|
296
303
|
on_error "invalid HTTP format, parsing fails"
|
297
304
|
@state = :invalid
|
298
305
|
end
|
299
|
-
|
306
|
+
|
300
307
|
return false unless @parser.finished?
|
301
308
|
|
302
309
|
# Clear parsed data from the buffer
|
303
310
|
@data.read(@parser_nbytes)
|
304
311
|
@parser.reset
|
305
312
|
@parser_nbytes = 0
|
306
|
-
|
313
|
+
|
307
314
|
true
|
308
315
|
end
|
309
316
|
|
@@ -324,7 +331,7 @@ module Coolio
|
|
324
331
|
@state = :body
|
325
332
|
@bytes_remaining = @response_header.content_length
|
326
333
|
end
|
327
|
-
|
334
|
+
|
328
335
|
true
|
329
336
|
end
|
330
337
|
|
@@ -334,7 +341,7 @@ module Coolio
|
|
334
341
|
@bytes_remaining = @chunk_header.chunk_size
|
335
342
|
@chunk_header = HttpChunkHeader.new
|
336
343
|
|
337
|
-
@state = @bytes_remaining > 0 ? :chunk_body : :response_footer
|
344
|
+
@state = @bytes_remaining > 0 ? :chunk_body : :response_footer
|
338
345
|
true
|
339
346
|
end
|
340
347
|
|
@@ -347,8 +354,8 @@ module Coolio
|
|
347
354
|
|
348
355
|
on_body_data @data.read(@bytes_remaining)
|
349
356
|
@bytes_remaining = 0
|
350
|
-
|
351
|
-
@state = :chunk_footer
|
357
|
+
|
358
|
+
@state = :chunk_footer
|
352
359
|
true
|
353
360
|
end
|
354
361
|
|
@@ -361,13 +368,13 @@ module Coolio
|
|
361
368
|
on_error "non-CRLF chunk footer"
|
362
369
|
@state = :invalid
|
363
370
|
end
|
364
|
-
|
371
|
+
|
365
372
|
true
|
366
373
|
end
|
367
374
|
|
368
375
|
def process_response_footer
|
369
376
|
return false if @data.size < 2
|
370
|
-
|
377
|
+
|
371
378
|
if @data.read(2) == CRLF
|
372
379
|
if @data.empty?
|
373
380
|
on_request_complete
|
@@ -380,7 +387,7 @@ module Coolio
|
|
380
387
|
on_error "non-CRLF response footer"
|
381
388
|
@state = :invalid
|
382
389
|
end
|
383
|
-
|
390
|
+
|
384
391
|
false
|
385
392
|
end
|
386
393
|
|
@@ -389,7 +396,7 @@ module Coolio
|
|
389
396
|
on_body_data @data.read
|
390
397
|
return false
|
391
398
|
end
|
392
|
-
|
399
|
+
|
393
400
|
if @bytes_remaining.zero?
|
394
401
|
on_request_complete
|
395
402
|
@state = :finished
|