ftw 0.0.1 → 0.0.4

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 (46) hide show
  1. data/README.md +7 -8
  2. data/lib/ftw.rb +4 -0
  3. data/lib/ftw/agent.rb +203 -20
  4. data/lib/ftw/connection.rb +117 -63
  5. data/lib/ftw/cookies.rb +87 -0
  6. data/lib/ftw/crlf.rb +1 -1
  7. data/lib/ftw/dns.rb +14 -5
  8. data/lib/ftw/http/headers.rb +15 -1
  9. data/lib/ftw/http/message.rb +9 -1
  10. data/lib/ftw/namespace.rb +1 -0
  11. data/lib/ftw/pool.rb +50 -0
  12. data/lib/ftw/poolable.rb +19 -0
  13. data/lib/ftw/request.rb +92 -28
  14. data/lib/ftw/response.rb +179 -0
  15. data/lib/ftw/version.rb +1 -1
  16. data/lib/ftw/websocket.rb +194 -0
  17. data/lib/ftw/websocket/parser.rb +183 -0
  18. data/test/all.rb +16 -0
  19. data/test/ftw/crlf.rb +12 -0
  20. data/test/ftw/http/dns.rb +6 -0
  21. data/test/{net/ftw → ftw}/http/headers.rb +5 -5
  22. data/test/testing.rb +0 -9
  23. metadata +13 -26
  24. data/lib/net-ftw.rb +0 -1
  25. data/lib/net/ftw.rb +0 -5
  26. data/lib/net/ftw/agent.rb +0 -10
  27. data/lib/net/ftw/connection.rb +0 -296
  28. data/lib/net/ftw/connection2.rb +0 -247
  29. data/lib/net/ftw/crlf.rb +0 -6
  30. data/lib/net/ftw/dns.rb +0 -57
  31. data/lib/net/ftw/http.rb +0 -2
  32. data/lib/net/ftw/http/client.rb +0 -116
  33. data/lib/net/ftw/http/client2.rb +0 -80
  34. data/lib/net/ftw/http/connection.rb +0 -42
  35. data/lib/net/ftw/http/headers.rb +0 -122
  36. data/lib/net/ftw/http/machine.rb +0 -38
  37. data/lib/net/ftw/http/message.rb +0 -91
  38. data/lib/net/ftw/http/request.rb +0 -80
  39. data/lib/net/ftw/http/response.rb +0 -80
  40. data/lib/net/ftw/http/server.rb +0 -5
  41. data/lib/net/ftw/machine.rb +0 -59
  42. data/lib/net/ftw/namespace.rb +0 -6
  43. data/lib/net/ftw/protocol/tls.rb +0 -12
  44. data/lib/net/ftw/websocket.rb +0 -139
  45. data/test/net/ftw/crlf.rb +0 -12
  46. data/test/net/ftw/http/dns.rb +0 -6
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ftw
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.4
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-02-08 00:00:00.000000000 Z
12
+ date: 2012-02-13 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description: Trying to build a solid and sane API for client and server web stuff.
15
15
  email:
@@ -19,39 +19,26 @@ extensions: []
19
19
  extra_rdoc_files: []
20
20
  files:
21
21
  - lib/ftw/agent.rb
22
+ - lib/ftw/pool.rb
23
+ - lib/ftw/cookies.rb
22
24
  - lib/ftw/http/headers.rb
23
25
  - lib/ftw/http/message.rb
26
+ - lib/ftw/websocket/parser.rb
24
27
  - lib/ftw/connection.rb
25
28
  - lib/ftw/request.rb
26
29
  - lib/ftw/namespace.rb
27
30
  - lib/ftw/dns.rb
31
+ - lib/ftw/response.rb
32
+ - lib/ftw/poolable.rb
33
+ - lib/ftw/websocket.rb
28
34
  - lib/ftw/crlf.rb
29
35
  - lib/ftw/version.rb
30
- - lib/net/ftw/protocol/tls.rb
31
- - lib/net/ftw/connection2.rb
32
- - lib/net/ftw/agent.rb
33
- - lib/net/ftw/machine.rb
34
- - lib/net/ftw/http/headers.rb
35
- - lib/net/ftw/http/machine.rb
36
- - lib/net/ftw/http/server.rb
37
- - lib/net/ftw/http/client2.rb
38
- - lib/net/ftw/http/message.rb
39
- - lib/net/ftw/http/connection.rb
40
- - lib/net/ftw/http/request.rb
41
- - lib/net/ftw/http/response.rb
42
- - lib/net/ftw/http/client.rb
43
- - lib/net/ftw/connection.rb
44
- - lib/net/ftw/namespace.rb
45
- - lib/net/ftw/dns.rb
46
- - lib/net/ftw/websocket.rb
47
- - lib/net/ftw/http.rb
48
- - lib/net/ftw/crlf.rb
49
- - lib/net/ftw.rb
50
- - lib/net-ftw.rb
36
+ - lib/ftw.rb
37
+ - test/ftw/http/headers.rb
38
+ - test/ftw/http/dns.rb
39
+ - test/ftw/crlf.rb
51
40
  - test/testing.rb
52
- - test/net/ftw/http/headers.rb
53
- - test/net/ftw/http/dns.rb
54
- - test/net/ftw/crlf.rb
41
+ - test/all.rb
55
42
  - README.md
56
43
  homepage: http://github.com/jordansissel/ruby-ftw
57
44
  licenses:
@@ -1 +0,0 @@
1
- require "net/ftw"
@@ -1,5 +0,0 @@
1
- require "net/ftw/http/client"
2
- require "net/ftw/connection"
3
- require "net/ftw/dns"
4
- require "net/ftw/websocket"
5
- #require "net/ftw/spdy"
@@ -1,10 +0,0 @@
1
- require "net/ftw/namespace"
2
-
3
- # Goal: Provide a nice way to sanely access web crap.
4
- # * websockets
5
- # * http
6
- # * spdy
7
- # * https
8
- class Net::FTW::UserAgent
9
-
10
- end
@@ -1,296 +0,0 @@
1
- require "cabin" # rubygem "cabin"
2
- require "net/ftw/dns"
3
- require "net/ftw/namespace"
4
- require "socket"
5
- require "timeout" # ruby stdlib, just for the Timeout exception.
6
- require "backport-bij" # for Array#rotate, IO::WaitWritable, etc, in ruby < 1.9
7
-
8
- # TODO(sissel): What's the API look like here?
9
- # EventMachine::Connection has these:
10
- # * events: post_init (and connection_completed), receive_data, unbind
11
- # * methods: send_data, close
12
- # Socket has
13
- # * no events
14
- # * methods: connect, read, write, close
15
- #
16
- # Actual events:
17
- # * connected
18
- # * disconnected(reason)
19
- # * timeout, connection reset, connection refused, write error, read
20
- # error, etc
21
- # * data received
22
- #
23
- # Methods
24
- # * send data
25
- # * reconnect
26
- # * get socket
27
- # * disconnect
28
- #
29
-
30
- # A network connection. This is TCP.
31
- #
32
- # Example:
33
- #
34
- # conn = Net::FTW::Connection.new("www.google.com:80")
35
- # conn.on(CONNECTED) do |address|
36
- # puts "Connected to #{address} (#{conn.peer})"
37
- # conn.write("GET / HTTP/1.0\r\n\r\n")
38
- # end
39
- # conn.on(DATA) do |data|
40
- # puts data
41
- # end
42
- # conn.run
43
- #
44
- # You can use IO::select on this objects of this type.
45
- class Net::FTW::Connection
46
-
47
- # Events
48
- CONNECTED = :connected
49
- DISCONNECTED = :disconnected
50
- READER_CLOSED = :reader_closed
51
- DATA = :data
52
-
53
- # Disconnection reasons
54
- TIMEOUT = :timeout
55
- REFUSED = :refused
56
- LOST = :lost
57
- INTENTIONAL = :intentional
58
-
59
- # A new network connection.
60
- # The 'destination' argument can be an array of strings or a single string.
61
- # String format is expected to be "host:port"
62
- #
63
- # Example:
64
- #
65
- # conn = Net::FTW::Connection.new(["1.2.3.4:80", "1.2.3.5:80"])
66
- #
67
- # If you specify multiple destinations, they are used in a round-robin
68
- # decision made during reconnection.
69
- public
70
- def initialize(destinations)
71
- if destinations.is_a?(String)
72
- @destinations = [destinations]
73
- else
74
- @destinations = destinations
75
- end
76
-
77
- # Handlers are key => array of callbacks
78
- @handlers = Hash.new { |h,k| h[k] = [] }
79
-
80
- on(CONNECTED) { |address| connected(address) }
81
- on(DISCONNECTED) { |reason, error| disconnected(reason, error) }
82
-
83
- @connect_timeout = 2
84
-
85
- # Use a fixed-size string that we set to BINARY encoding.
86
- # Not all byte sequences are UTF-8 friendly :0
87
- @read_size = 16384
88
- @read_buffer = " " * @read_size
89
-
90
- # Tell Ruby 1.9 that this string is a binary string, not utf-8 or somesuch.
91
- if @read_buffer.respond_to?(:force_encoding)
92
- @read_buffer.force_encoding("BINARY")
93
- end
94
-
95
- # TODO(sissel): Validate @destinations
96
- end # def initialize
97
-
98
- # Register an event callback
99
- # Valid events:
100
- #
101
- # * Net::FTW::Connection::CONNECTED - 1 argument, the host:port string connected to.
102
- # * Net::FTW::Connection::DISCONNECTED - 2 arguments, the reason and the
103
- # exception (if any)
104
- # * Net::FTW::Connection::DATA - 1 argument to block, the data read
105
- #
106
- # Disconnection reasons:
107
- # * :timeout
108
- # * :refused
109
- # * :closed
110
- # * :lost
111
- public
112
- def on(event, &block)
113
- @handlers[event] << block
114
- end # def on
115
-
116
- # Trigger an event with arguments.
117
- # All callbacks for the event will be invoked in the order they were
118
- # registered. See the 'on' method for registering callbacks.
119
- public
120
- def trigger(event, *args)
121
- @handlers[event].each do |block|
122
- block.call(*args)
123
- end
124
- end # def trigger
125
-
126
- public
127
- def connect(timeout=nil)
128
- # TODO(sissel): Raise if we're already connected?
129
- close if connected?
130
- host, port = @destinations.first.split(":")
131
- @destinations = @destinations.rotate # round-robin
132
-
133
- # Do dns resolution on the host. If there are multiple
134
- # addresses resolved, return one at random.
135
- @remote_address = Net::FTW::DNS.singleton.resolve_random(host)
136
-
137
- family = @remote_address.include?(":") ? Socket::AF_INET6 : Socket::AF_INET
138
- @socket = Socket.new(family, Socket::SOCK_STREAM, 0)
139
- sockaddr = Socket.pack_sockaddr_in(port, @remote_address)
140
- # TODO(sissel): Support local address binding
141
-
142
- # Connect with timeout
143
- begin
144
- @socket.connect_nonblock(sockaddr)
145
- rescue IO::WaitWritable
146
- # Ruby actually raises Errno::EINPROGRESS, but for some reason
147
- # the documentation says to use this IO::WaitWritable thing...
148
- # I don't get it, but whatever :(
149
- if writable?(timeout)
150
- begin
151
- @socket.connect_nonblock(sockaddr) # check connection failure
152
- rescue Errno::EISCONN # Ignore, we're already connected.
153
- rescue Errno::ECONNREFUSED => e
154
- # Fire 'disconnected' event with reason :refused
155
- trigger(DISCONNECTED, :refused, e)
156
- end
157
- else
158
- # Connection timeout
159
- # Fire 'disconnected' event with reason :timeout
160
- trigger(DISCONNECTED, :connect_timeout, nil)
161
- end
162
- end
163
-
164
- # We're now connected.
165
- trigger(CONNECTED, "#{host}:#{port}")
166
- end # def connect
167
-
168
- # Is this Connection connected?
169
- public
170
- def connected?
171
- return @connected
172
- end # def connected?
173
-
174
- # Write data to this connection.
175
- # This method blocks until the write succeeds unless a timeout is given.
176
- #
177
- # Returns the number of bytes written (See IO#syswrite)
178
- public
179
- def write(data, timeout=nil)
180
- #connect if !connected?
181
- if writable?(timeout)
182
- return @socket.syswrite(data)
183
- else
184
- raise Timeout::Error.new
185
- end
186
- end # def write
187
-
188
- # Read data from this connection
189
- # This method blocks until the read succeeds unless a timeout is given.
190
- #
191
- # This method is not guaranteed to read exactly 'length' bytes. See
192
- # IO#sysread
193
- public
194
- def read(length, timeout=nil)
195
- if readable?(timeout)
196
- begin
197
- @socket.sysread(length, @read_buffer)
198
- return @read_buffer
199
- rescue EOFError
200
- trigger(READER_CLOSED)
201
- end
202
- else
203
- raise Timeout::Error.new
204
- end
205
- end # def read
206
-
207
- # End this connection
208
- public
209
- def disconnect(reason=INTENTIONAL)
210
- begin
211
- #@reader_closed = true
212
- @socket.close_read
213
- rescue IOError => e
214
- # Ignore
215
- end
216
-
217
- begin
218
- @socket.close_write
219
- rescue IOError => e
220
- # Ignore
221
- end
222
-
223
- trigger(DISCONNECTED, reason)
224
- end # def disconnect
225
-
226
- # Is this connection writable? Returns true if it is writable within
227
- # the timeout period. False otherwise.
228
- #
229
- # The time out is in seconds. Fractional seconds are OK.
230
- public
231
- def writable?(timeout)
232
- ready = IO.select(nil, [@socket], nil, timeout)
233
- return !ready.nil?
234
- end # def writable?
235
-
236
- # Is this connection readable? Returns true if it is readable within
237
- # the timeout period. False otherwise.
238
- #
239
- # The time out is in seconds. Fractional seconds are OK.
240
- public
241
- def readable?(timeout)
242
- #return false if @reader_closed
243
- ready = IO.select([@socket], nil, nil, timeout)
244
- return !ready.nil?
245
- end # def readable?
246
-
247
- protected
248
- def connected(address)
249
- @remote_address = nil
250
- @connected = true
251
- end # def connected
252
-
253
- protected
254
- def disconnected(reason, error)
255
- @remote_address = nil
256
- @connected = false
257
- end # def disconnected
258
-
259
- # The host:port
260
- public
261
- def peer
262
- return @remote_address
263
- end # def peer
264
-
265
- # Run this Connection.
266
- # This is generally meant for Threaded or synchronous operation.
267
- # For EventMachine, see TODO(sissel): Implement EventMachine support.
268
- public
269
- def run
270
- connect(@connect_timeout) if not connected?
271
- while connected?
272
- read_and_trigger
273
- end
274
- end # def run
275
-
276
- # Read data and trigger data callbacks.
277
- #
278
- # This is mainly useful if you are implementing your own run loops
279
- # and IO::select shenanigans.
280
- public
281
- def read_and_trigger
282
- data = read(@read_size)
283
- if data.length == 0
284
- disconnect(EOFError)
285
- else
286
- trigger(DATA, data)
287
- end
288
- end # def read_and_trigger
289
-
290
- # Support 'to_io' so you can use IO::select on this object.
291
- public
292
- def to_io
293
- return @socket
294
- end
295
- end # class Net::FTW::Connection
296
-
@@ -1,247 +0,0 @@
1
- require "cabin" # rubygem "cabin"
2
- require "net/ftw/dns"
3
- require "net/ftw/namespace"
4
- require "socket"
5
- require "timeout" # ruby stdlib, just for the Timeout exception.
6
- require "backport-bij" # for Array#rotate, IO::WaitWritable, etc, in ruby < 1.9
7
-
8
- # A network connection. This is TCP.
9
- #
10
- # Example:
11
- #
12
- # conn = Net::FTW::Connection.new("www.google.com:80")
13
- # conn.on(CONNECTED) do |address|
14
- # puts "Connected to #{address} (#{conn.peer})"
15
- # conn.write("GET / HTTP/1.0\r\n\r\n")
16
- # end
17
- # conn.on(DATA) do |data|
18
- # puts data
19
- # end
20
- # conn.run
21
- #
22
- # You can use IO::select on this objects of this type.
23
- class Net::FTW::Connection2
24
-
25
- # Events
26
- CONNECTED = :connected
27
- DISCONNECTED = :disconnected
28
- READER_CLOSED = :reader_closed
29
- DATA = :data
30
-
31
- # Disconnection reasons
32
- TIMEOUT = :timeout
33
- REFUSED = :refused
34
- LOST = :lost
35
- INTENTIONAL = :intentional
36
-
37
- # A new network connection.
38
- # The 'destination' argument can be an array of strings or a single string.
39
- # String format is expected to be "host:port"
40
- #
41
- # Example:
42
- #
43
- # conn = Net::FTW::Connection.new(["1.2.3.4:80", "1.2.3.5:80"])
44
- #
45
- # If you specify multiple destinations, they are used in a round-robin
46
- # decision made during reconnection.
47
- public
48
- def initialize(destinations)
49
- if destinations.is_a?(String)
50
- @destinations = [destinations]
51
- else
52
- @destinations = destinations
53
- end
54
-
55
- # Handlers are key => array of callbacks
56
- @handlers = Hash.new { |h,k| h[k] = [] }
57
-
58
- @connect_timeout = 2
59
-
60
- # Use a fixed-size string that we set to BINARY encoding.
61
- # Not all byte sequences are UTF-8 friendly :0
62
- @read_size = 16384
63
- @read_buffer = " " * @read_size
64
-
65
- # Tell Ruby 1.9 that this string is a binary string, not utf-8 or somesuch.
66
- if @read_buffer.respond_to?(:force_encoding)
67
- @read_buffer.force_encoding("BINARY")
68
- end
69
-
70
- # TODO(sissel): Validate @destinations
71
- end # def initialize
72
-
73
- public
74
- def connect(timeout=nil)
75
- # TODO(sissel): Raise if we're already connected?
76
- close if connected?
77
- host, port = @destinations.first.split(":")
78
- @destinations = @destinations.rotate # round-robin
79
-
80
- # Do dns resolution on the host. If there are multiple
81
- # addresses resolved, return one at random.
82
- @remote_address = Net::FTW::DNS.singleton.resolve_random(host)
83
-
84
- family = @remote_address.include?(":") ? Socket::AF_INET6 : Socket::AF_INET
85
- @socket = Socket.new(family, Socket::SOCK_STREAM, 0)
86
- sockaddr = Socket.pack_sockaddr_in(port, @remote_address)
87
- # TODO(sissel): Support local address binding
88
-
89
- # Connect with timeout
90
- begin
91
- @socket.connect_nonblock(sockaddr)
92
- rescue IO::WaitWritable
93
- # Ruby actually raises Errno::EINPROGRESS, but for some reason
94
- # the documentation says to use this IO::WaitWritable thing...
95
- # I don't get it, but whatever :(
96
- if writable?(timeout)
97
- begin
98
- @socket.connect_nonblock(sockaddr) # check connection failure
99
- rescue Errno::EISCONN # Ignore, we're already connected.
100
- rescue Errno::ECONNREFUSED => e
101
- # Fire 'disconnected' event with reason :refused
102
- trigger(DISCONNECTED, :refused, e)
103
- end
104
- else
105
- # Connection timeout
106
- # Fire 'disconnected' event with reason :timeout
107
- trigger(DISCONNECTED, :connect_timeout, nil)
108
- end
109
- end
110
-
111
- # We're now connected.
112
- trigger(CONNECTED, "#{host}:#{port}")
113
- end # def connect
114
-
115
- # Is this Connection connected?
116
- public
117
- def connected?
118
- return @connected
119
- end # def connected?
120
-
121
- # Write data to this connection.
122
- # This method blocks until the write succeeds unless a timeout is given.
123
- #
124
- # Returns the number of bytes written (See IO#syswrite)
125
- public
126
- def write(data, timeout=nil)
127
- #connect if !connected?
128
- if writable?(timeout)
129
- return @socket.syswrite(data)
130
- else
131
- raise Timeout::Error.new
132
- end
133
- end # def write
134
-
135
- # Read data from this connection
136
- # This method blocks until the read succeeds unless a timeout is given.
137
- #
138
- # This method is not guaranteed to read exactly 'length' bytes. See
139
- # IO#sysread
140
- public
141
- def read(length, timeout=nil)
142
- if readable?(timeout)
143
- begin
144
- @socket.sysread(length, @read_buffer)
145
- return @read_buffer
146
- rescue EOFError
147
- trigger(READER_CLOSED)
148
- end
149
- else
150
- raise Timeout::Error.new
151
- end
152
- end # def read
153
-
154
- # End this connection
155
- public
156
- def disconnect(reason=INTENTIONAL)
157
- begin
158
- #@reader_closed = true
159
- @socket.close_read
160
- rescue IOError => e
161
- # Ignore
162
- end
163
-
164
- begin
165
- @socket.close_write
166
- rescue IOError => e
167
- # Ignore
168
- end
169
-
170
- trigger(DISCONNECTED, reason)
171
- end # def disconnect
172
-
173
- # Is this connection writable? Returns true if it is writable within
174
- # the timeout period. False otherwise.
175
- #
176
- # The time out is in seconds. Fractional seconds are OK.
177
- public
178
- def writable?(timeout)
179
- ready = IO.select(nil, [@socket], nil, timeout)
180
- return !ready.nil?
181
- end # def writable?
182
-
183
- # Is this connection readable? Returns true if it is readable within
184
- # the timeout period. False otherwise.
185
- #
186
- # The time out is in seconds. Fractional seconds are OK.
187
- public
188
- def readable?(timeout)
189
- #return false if @reader_closed
190
- ready = IO.select([@socket], nil, nil, timeout)
191
- return !ready.nil?
192
- end # def readable?
193
-
194
- protected
195
- def connected(address)
196
- @remote_address = nil
197
- @connected = true
198
- end # def connected
199
-
200
- protected
201
- def disconnected(reason, error)
202
- @remote_address = nil
203
- @connected = false
204
- end # def disconnected
205
-
206
- # The host:port
207
- public
208
- def peer
209
- return @remote_address
210
- end # def peer
211
-
212
- # Run this Connection.
213
- # This is generally meant for Threaded or synchronous operation.
214
- # For EventMachine, see TODO(sissel): Implement EventMachine support.
215
- public
216
- def run
217
- connect(@connect_timeout) if not connected?
218
- while connected?
219
- read_and_trigger
220
- end
221
- end # def run
222
-
223
- # Read data and trigger data callbacks.
224
- #
225
- # This is mainly useful if you are implementing your own run loops
226
- # and IO::select shenanigans.
227
- public
228
- def read_and_trigger
229
- data = read(@read_size)
230
- if data.length == 0
231
- disconnect(EOFError)
232
- else
233
- trigger(DATA, data)
234
- end
235
- end # def read_and_trigger
236
-
237
- # Support 'to_io' so you can use IO::select on this object.
238
- public
239
- def to_io
240
- return @socket
241
- end
242
-
243
- def trigger(*args)
244
- p :trigger => args
245
- end
246
- end # class Net::FTW::Connection
247
-