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