plezi 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +22 -0
- data/CHANGELOG.md +450 -0
- data/Gemfile +4 -0
- data/KNOWN_ISSUES.md +13 -0
- data/LICENSE.txt +22 -0
- data/README.md +341 -0
- data/Rakefile +2 -0
- data/TODO.md +19 -0
- data/bin/plezi +301 -0
- data/lib/plezi.rb +125 -0
- data/lib/plezi/base/cache.rb +77 -0
- data/lib/plezi/base/connections.rb +33 -0
- data/lib/plezi/base/dsl.rb +177 -0
- data/lib/plezi/base/engine.rb +85 -0
- data/lib/plezi/base/events.rb +84 -0
- data/lib/plezi/base/io_reactor.rb +41 -0
- data/lib/plezi/base/logging.rb +62 -0
- data/lib/plezi/base/rack_app.rb +89 -0
- data/lib/plezi/base/services.rb +57 -0
- data/lib/plezi/base/timers.rb +71 -0
- data/lib/plezi/handlers/controller_magic.rb +383 -0
- data/lib/plezi/handlers/http_echo.rb +27 -0
- data/lib/plezi/handlers/http_host.rb +215 -0
- data/lib/plezi/handlers/http_router.rb +69 -0
- data/lib/plezi/handlers/magic_helpers.rb +43 -0
- data/lib/plezi/handlers/route.rb +272 -0
- data/lib/plezi/handlers/stubs.rb +143 -0
- data/lib/plezi/server/README.md +33 -0
- data/lib/plezi/server/helpers/http.rb +169 -0
- data/lib/plezi/server/helpers/mime_types.rb +999 -0
- data/lib/plezi/server/protocols/http_protocol.rb +318 -0
- data/lib/plezi/server/protocols/http_request.rb +133 -0
- data/lib/plezi/server/protocols/http_response.rb +294 -0
- data/lib/plezi/server/protocols/websocket.rb +208 -0
- data/lib/plezi/server/protocols/ws_response.rb +92 -0
- data/lib/plezi/server/services/basic_service.rb +224 -0
- data/lib/plezi/server/services/no_service.rb +196 -0
- data/lib/plezi/server/services/ssl_service.rb +193 -0
- data/lib/plezi/version.rb +3 -0
- data/plezi.gemspec +26 -0
- data/resources/404.erb +68 -0
- data/resources/404.haml +64 -0
- data/resources/404.html +67 -0
- data/resources/404.slim +63 -0
- data/resources/500.erb +68 -0
- data/resources/500.haml +63 -0
- data/resources/500.html +67 -0
- data/resources/500.slim +63 -0
- data/resources/Gemfile +85 -0
- data/resources/anorexic_gray.png +0 -0
- data/resources/anorexic_websockets.html +47 -0
- data/resources/code.rb +8 -0
- data/resources/config.ru +39 -0
- data/resources/controller.rb +139 -0
- data/resources/db_ac_config.rb +58 -0
- data/resources/db_dm_config.rb +51 -0
- data/resources/db_sequel_config.rb +42 -0
- data/resources/en.yml +204 -0
- data/resources/environment.rb +41 -0
- data/resources/haml_config.rb +6 -0
- data/resources/i18n_config.rb +14 -0
- data/resources/rakefile.rb +22 -0
- data/resources/redis_config.rb +35 -0
- data/resources/routes.rb +26 -0
- data/resources/welcome_page.html +72 -0
- data/websocket chatroom.md +639 -0
- metadata +141 -0
@@ -0,0 +1,92 @@
|
|
1
|
+
module Plezi
|
2
|
+
|
3
|
+
# this class handles WebSocket response.
|
4
|
+
#
|
5
|
+
# the WSResponse supports only one method - the send method.
|
6
|
+
#
|
7
|
+
# use: `response << data` to send data. data should be a String object.
|
8
|
+
#
|
9
|
+
# the data wil be sent as text if the string is encoded as a UTF-8 string (default encoding).
|
10
|
+
# otherwise, the data will be sent as a binary stream.
|
11
|
+
#
|
12
|
+
# todo: extentions support, support frames longer then 125 bytes.
|
13
|
+
class WSResponse
|
14
|
+
|
15
|
+
#the service through which the response will be sent.
|
16
|
+
attr_reader :service
|
17
|
+
#the request.
|
18
|
+
attr_accessor :request
|
19
|
+
|
20
|
+
def initialize request
|
21
|
+
@request, @service = request,request.service
|
22
|
+
end
|
23
|
+
|
24
|
+
# pushes data to the body of the response. this is the preffered way to add data to the response.
|
25
|
+
def << str
|
26
|
+
service.send_nonblock self.class.frame_data(str.dup)
|
27
|
+
self
|
28
|
+
end
|
29
|
+
|
30
|
+
# sends the response object. headers will be frozen (they can only be sent at the head of the response).
|
31
|
+
#
|
32
|
+
# the response will remain open for more data to be sent through (using `response << data` and `response.send`).
|
33
|
+
def send str
|
34
|
+
service.send_nonblock self.class.frame_data(str.dup)
|
35
|
+
end
|
36
|
+
|
37
|
+
# makes sure any data held in the buffer is actually sent.
|
38
|
+
def flush
|
39
|
+
service.flush
|
40
|
+
end
|
41
|
+
|
42
|
+
# sends any pending data and closes the connection.
|
43
|
+
def close
|
44
|
+
service.send_nonblock self.class.frame_data('', 8)
|
45
|
+
service.disconnect
|
46
|
+
end
|
47
|
+
|
48
|
+
# Dangerzone! ()alters the string, use `send` instead: formats the data as one or more WebSocket frames.
|
49
|
+
def self.frame_data data, op_code = nil, fin = true
|
50
|
+
# set up variables
|
51
|
+
frame = ''.force_encoding('binary')
|
52
|
+
op_code ||= data.encoding.name == 'UTF-8' ? 1 : 2
|
53
|
+
data.force_encoding('binary')
|
54
|
+
|
55
|
+
# fragment big data chuncks into smaller frames
|
56
|
+
[frame << frame_data(data.slice!(0..1048576), op_code, false), op_code = 0] while data.length > 1048576
|
57
|
+
|
58
|
+
# apply extenetions to the frame
|
59
|
+
ext = 0
|
60
|
+
# ext |= call each service.protocol.extenetions with data #changes data and returns flags to be set
|
61
|
+
# service.protocol.extenetions.each { |ex| ext |= WSProtocol::SUPPORTED_EXTENTIONS[ex[0]][2].call data, ex[1..-1]}
|
62
|
+
|
63
|
+
# set
|
64
|
+
frame << ( (fin ? 0b10000000 : 0) | (op_code & 0b00001111) | ext).chr
|
65
|
+
|
66
|
+
if data.length < 125
|
67
|
+
frame << data.length.chr
|
68
|
+
elsif data.length.bit_length < 16
|
69
|
+
frame << 126.chr
|
70
|
+
frame << [data.length].pack('S>')
|
71
|
+
else
|
72
|
+
frame << 127.chr
|
73
|
+
frame << [data.length].pack('Q>')
|
74
|
+
end
|
75
|
+
frame << data
|
76
|
+
frame
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
|
82
|
+
######
|
83
|
+
## example requests
|
84
|
+
|
85
|
+
# GET / HTTP/1.1
|
86
|
+
# Host: localhost:2000
|
87
|
+
# Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
|
88
|
+
# Cookie: user_token=2INa32_vDgx8Aa1qe43oILELpSdIe9xwmT8GTWjkS-w
|
89
|
+
# User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10) AppleWebKit/600.1.25 (KHTML, like Gecko) Version/8.0 Safari/600.1.25
|
90
|
+
# Accept-Language: en-us
|
91
|
+
# Accept-Encoding: gzip, deflate
|
92
|
+
# Connection: keep-alive
|
@@ -0,0 +1,224 @@
|
|
1
|
+
module Plezi
|
2
|
+
|
3
|
+
# this class is a basic TCP socket service.
|
4
|
+
#
|
5
|
+
# a protocol should be assigned, or the service will fall back to an echo service.
|
6
|
+
#
|
7
|
+
# a protocol should answer to: on_connect(service), on_message(service, data), on_disconnect(service) and on_exception(service, exception)
|
8
|
+
#
|
9
|
+
# the on_message method should return any data that wasn't used (to be sent again as part of the next `on_message` call, once more data is received).
|
10
|
+
#
|
11
|
+
# if the protocol is a class, these methods should be instance methods.
|
12
|
+
# a protocol class should support the initialize(service, parameters={}) method as well.
|
13
|
+
#
|
14
|
+
# to-do: fix logging
|
15
|
+
class BasicService
|
16
|
+
|
17
|
+
# create a listener (io) - will create a TCPServer socket
|
18
|
+
#
|
19
|
+
# listeners are 'server sockets' that answer to `accept` by creating a new connection socket (io).
|
20
|
+
def self.create_service port, parameters
|
21
|
+
TCPServer.new(port)
|
22
|
+
end
|
23
|
+
|
24
|
+
# instance methods
|
25
|
+
|
26
|
+
attr_reader :socket, :locker, :closed, :parameters, :out_que, :active_time
|
27
|
+
attr_accessor :protocol, :handler, :timeout
|
28
|
+
|
29
|
+
# creates a new connection wrapper object for the new socket that was recieved from the `accept_nonblock` method call.
|
30
|
+
def initialize socket, parameters = {}
|
31
|
+
@handler = parameters[:handler]
|
32
|
+
@socket = socket
|
33
|
+
# socket.setsockopt Socket::SOL_SOCKET, Socket::SO_RCVTIMEO, "\n\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" #== [10 sec 0 usec].pack '1_2'
|
34
|
+
@out_que = []
|
35
|
+
@locker = Mutex.new
|
36
|
+
@parameters = parameters
|
37
|
+
@protocol = parameters[:protocol]
|
38
|
+
@protocol = protocol.new self, parameters if protocol.is_a?(Class)
|
39
|
+
@protocol.on_connect self if @protocol && @protocol.methods.include?(:on_connect)
|
40
|
+
touch
|
41
|
+
@timeout ||= 5
|
42
|
+
# Plezi.callback self, :on_message
|
43
|
+
end
|
44
|
+
|
45
|
+
# # sets a connection timeout
|
46
|
+
# def set_timeout timeout = 8
|
47
|
+
# @timeout = timeout
|
48
|
+
# end
|
49
|
+
|
50
|
+
# checks if a connection timed out
|
51
|
+
def timedout?
|
52
|
+
Time.now - @active_time > @timeout
|
53
|
+
end
|
54
|
+
|
55
|
+
# resets the timer for the connection timeout
|
56
|
+
def touch
|
57
|
+
@active_time = Time.now
|
58
|
+
end
|
59
|
+
|
60
|
+
# returns an IO-like object used for reading/writing (unlike the original IO object, this can be an SSL layer or any other wrapper object).
|
61
|
+
def io
|
62
|
+
touch
|
63
|
+
@socket
|
64
|
+
end
|
65
|
+
|
66
|
+
# sends data immidiately - forcing the data to be sent, flushing any pending messages in the que
|
67
|
+
def send data = nil
|
68
|
+
return if @out_que.empty? && data.nil?
|
69
|
+
locker.synchronize do
|
70
|
+
unless @out_que.empty?
|
71
|
+
@out_que.each { |d| _send d rescue disconnect }
|
72
|
+
@out_que.clear
|
73
|
+
end
|
74
|
+
(_send data rescue disconnect) if data
|
75
|
+
touch
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
# sends data immidiately, interrupting any pending que and ignoring thread safety.
|
80
|
+
def send_unsafe_interrupt data = nil
|
81
|
+
touch
|
82
|
+
_send data rescue disconnect
|
83
|
+
end
|
84
|
+
|
85
|
+
# sends data without waiting - data might be sent in a different order then intended.
|
86
|
+
def send_nonblock data
|
87
|
+
touch
|
88
|
+
locker.synchronize {@out_que << data}
|
89
|
+
Plezi.callback(self, :send)
|
90
|
+
end
|
91
|
+
|
92
|
+
# adds data to the out buffer - but doesn't send the data until a send event is called.
|
93
|
+
def << data
|
94
|
+
touch
|
95
|
+
locker.synchronize {@out_que << data}
|
96
|
+
end
|
97
|
+
|
98
|
+
# makes sure any data in the que is send and calls `flush` on the socket, to make sure the buffer is sent.
|
99
|
+
def flush
|
100
|
+
begin
|
101
|
+
send
|
102
|
+
socket.flush
|
103
|
+
rescue Exception => e
|
104
|
+
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
# event based interface for messages.
|
109
|
+
|
110
|
+
# notice: since it is all async evet base - multipart messages might be garbled up...?
|
111
|
+
# todo: protect from garbeling.
|
112
|
+
def on_message
|
113
|
+
# return false if locker.locked?
|
114
|
+
return false if locker.locked?
|
115
|
+
begin
|
116
|
+
|
117
|
+
locker.synchronize do
|
118
|
+
return disconnect if _disconnected?
|
119
|
+
protocol.on_message(self)
|
120
|
+
end
|
121
|
+
|
122
|
+
rescue Exception => e
|
123
|
+
return disconnect
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
# called once a socket is disconnected or needs to be disconnected.
|
128
|
+
def on_disconnect
|
129
|
+
Plezi.callback Plezi, :remove_connection, self
|
130
|
+
locker.synchronize do
|
131
|
+
@out_que.each { |d| _send d rescue true}
|
132
|
+
@out_que.clear
|
133
|
+
end
|
134
|
+
Plezi.callback protocol, :on_disconnect, self if protocol
|
135
|
+
close
|
136
|
+
end
|
137
|
+
|
138
|
+
# status markers
|
139
|
+
|
140
|
+
# closes the connection
|
141
|
+
def close
|
142
|
+
locker.synchronize do
|
143
|
+
_close rescue true
|
144
|
+
end
|
145
|
+
end
|
146
|
+
# returns true if the service is disconnected
|
147
|
+
def disconnected?
|
148
|
+
_disconnected?
|
149
|
+
end
|
150
|
+
# disconects the service.
|
151
|
+
def disconnect
|
152
|
+
Plezi.callback self, :on_disconnect
|
153
|
+
end
|
154
|
+
# returns true if the socket has content to be read.
|
155
|
+
def has_incoming_data?
|
156
|
+
(socket.stat.size > 0) rescue false
|
157
|
+
end
|
158
|
+
|
159
|
+
|
160
|
+
# identification markers
|
161
|
+
|
162
|
+
#returns the service type - set to normal
|
163
|
+
def service_type
|
164
|
+
'normal'
|
165
|
+
end
|
166
|
+
#returns true if the service is encrypted using the OpenSSL library.
|
167
|
+
def ssl?
|
168
|
+
false
|
169
|
+
end
|
170
|
+
|
171
|
+
#################
|
172
|
+
# overide the followind methods for any child class.
|
173
|
+
|
174
|
+
# this is a public method and it should be used by child classes to implement each
|
175
|
+
# read(_nonblock) action. accepts one argument ::size for an optional buffer size to be read.
|
176
|
+
def read size = 1048576
|
177
|
+
data = @socket.recv_nonblock( size )
|
178
|
+
touch unless data.nil? || data.empty?
|
179
|
+
return data
|
180
|
+
rescue Exception => e
|
181
|
+
return ''
|
182
|
+
end
|
183
|
+
|
184
|
+
protected
|
185
|
+
|
186
|
+
# this is a protected method, it should be used by child classes to implement each
|
187
|
+
# send action.
|
188
|
+
def _send data
|
189
|
+
# data.force_encoding "binary" rescue false
|
190
|
+
len = data.bytesize
|
191
|
+
act = @socket.send data, 0
|
192
|
+
while len > act
|
193
|
+
act += @socket.send data.byteslice(act..-1) , 0
|
194
|
+
touch
|
195
|
+
end
|
196
|
+
end
|
197
|
+
# this is a protected method, it should be used by child classes to implement each
|
198
|
+
# close action. doesn't accept any arguments.
|
199
|
+
def _close
|
200
|
+
socket.flush rescue true
|
201
|
+
socket.close
|
202
|
+
end
|
203
|
+
# this is a protected method, it should be used by child classes to tell if the socket
|
204
|
+
# was closed (returns true/false).
|
205
|
+
def _disconnected?
|
206
|
+
socket.closed? rescue true # || socket.stat.mode == 0140222 rescue true # if mode is read only, it's the same as closed.
|
207
|
+
end
|
208
|
+
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
|
213
|
+
######
|
214
|
+
## example requests
|
215
|
+
|
216
|
+
# GET /parsed_request HTTP/1.1
|
217
|
+
# Host: localhost:2000
|
218
|
+
# Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
|
219
|
+
# Cookie: user_token=2INa32_vDgx8Aa1qe43oILELpSdIe9xwmT8GTWjkS-w
|
220
|
+
# User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10) AppleWebKit/600.1.25 (KHTML, like Gecko) Version/8.0 Safari/600.1.25
|
221
|
+
# Accept-Language: en-us
|
222
|
+
# Accept-Encoding: gzip, deflate
|
223
|
+
# Connection: keep-alive
|
224
|
+
# X-Forwarded-For: 127.0.0.3
|
@@ -0,0 +1,196 @@
|
|
1
|
+
module Plezi
|
2
|
+
|
3
|
+
# this class is a basic TCP socket service.
|
4
|
+
#
|
5
|
+
# a protocol should be assigned, or the service will fall back to an echo service.
|
6
|
+
#
|
7
|
+
# a protocol should answer to: on_connect(service), on_message(service, data), on_disconnect(service) and on_exception(service, exception)
|
8
|
+
#
|
9
|
+
# the on_message method should return any data that wasn't used (to be sent again as part of the next `on_message` call, once more data is received).
|
10
|
+
#
|
11
|
+
# if the protocol is a class, these methods should be instance methods.
|
12
|
+
# a protocol class should support the initialize(service, parameters={}) method as well.
|
13
|
+
#
|
14
|
+
# to-do: fix logging
|
15
|
+
class NoService
|
16
|
+
|
17
|
+
# create a listener (io) - will create a TCPServer socket
|
18
|
+
#
|
19
|
+
# listeners are 'server sockets' that answer to `accept` by creating a new connection socket (io).
|
20
|
+
def self.create_service port, parameters
|
21
|
+
self
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.accept
|
25
|
+
false
|
26
|
+
end
|
27
|
+
|
28
|
+
# instance methods
|
29
|
+
|
30
|
+
attr_reader :socket, :locker, :closed, :parameters, :out_que, :active_time
|
31
|
+
attr_accessor :protocol, :handler, :timeout
|
32
|
+
|
33
|
+
# creates a new connection wrapper object for the new socket that was recieved from the `accept_nonblock` method call.
|
34
|
+
def initialize socket, parameters = {}
|
35
|
+
@handler = parameters[:handler]
|
36
|
+
@socket = nil
|
37
|
+
# socket.setsockopt Socket::SOL_SOCKET, Socket::SO_RCVTIMEO, "\n\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" #== [10 sec 0 usec].pack '1_2'
|
38
|
+
@out_que = []
|
39
|
+
@locker = Mutex.new
|
40
|
+
@parameters = parameters
|
41
|
+
@protocol = parameters[:protocol]
|
42
|
+
@protocol = protocol.new self, parameters if protocol.is_a?(Class)
|
43
|
+
@protocol.on_connect self if @protocol && @protocol.methods.include?(:on_connect)
|
44
|
+
touch
|
45
|
+
@timeout ||= 5
|
46
|
+
# Plezi.callback self, :on_message
|
47
|
+
end
|
48
|
+
|
49
|
+
# # sets a connection timeout
|
50
|
+
# def set_timeout timeout = 8
|
51
|
+
# @timeout = timeout
|
52
|
+
# end
|
53
|
+
|
54
|
+
# checks if a connection timed out
|
55
|
+
def timedout?
|
56
|
+
Time.now - @active_time > @timeout
|
57
|
+
end
|
58
|
+
|
59
|
+
# resets the timer for the connection timeout
|
60
|
+
def touch
|
61
|
+
@active_time = Time.now
|
62
|
+
end
|
63
|
+
|
64
|
+
# returns an IO-like object used for reading/writing (unlike the original IO object, this can be an SSL layer or any other wrapper object).
|
65
|
+
def io
|
66
|
+
touch
|
67
|
+
@socket
|
68
|
+
end
|
69
|
+
|
70
|
+
# sends data immidiately - forcing the data to be sent, flushing any pending messages in the que
|
71
|
+
def send data = nil
|
72
|
+
touch
|
73
|
+
end
|
74
|
+
|
75
|
+
# sends data immidiately, interrupting any pending que and ignoring thread safety.
|
76
|
+
def send_unsafe_interrupt data = nil
|
77
|
+
touch
|
78
|
+
_send data rescue disconnect
|
79
|
+
end
|
80
|
+
|
81
|
+
# sends data without waiting - data might be sent in a different order then intended.
|
82
|
+
def send_nonblock data
|
83
|
+
touch
|
84
|
+
locker.synchronize {@out_que << data}
|
85
|
+
Plezi.callback(self, :send)
|
86
|
+
end
|
87
|
+
|
88
|
+
# adds data to the out buffer - but doesn't send the data until a send event is called.
|
89
|
+
def << data
|
90
|
+
touch
|
91
|
+
locker.synchronize {@out_que << data}
|
92
|
+
end
|
93
|
+
|
94
|
+
# makes sure any data in the que is send and calls `flush` on the socket, to make sure the buffer is sent.
|
95
|
+
def flush
|
96
|
+
end
|
97
|
+
|
98
|
+
# event based interface for messages.
|
99
|
+
|
100
|
+
# notice: since it is all async evet base - multipart messages might be garbled up...?
|
101
|
+
# todo: protect from garbeling.
|
102
|
+
def on_message
|
103
|
+
# return false if locker.locked?
|
104
|
+
return false if locker.locked?
|
105
|
+
return disconnect if (_disconnected? rescue true)
|
106
|
+
locker.synchronize do
|
107
|
+
begin
|
108
|
+
touch
|
109
|
+
if protocol
|
110
|
+
protocol.on_message self
|
111
|
+
end
|
112
|
+
rescue Exception => e
|
113
|
+
Plezi.error e
|
114
|
+
return disconnect
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
# called once a socket is disconnected or needs to be disconnected.
|
120
|
+
def on_disconnect
|
121
|
+
Plezi.callback Plezi, :remove_connection, self
|
122
|
+
|
123
|
+
close
|
124
|
+
end
|
125
|
+
|
126
|
+
# status markers
|
127
|
+
|
128
|
+
# closes the connection
|
129
|
+
def close
|
130
|
+
end
|
131
|
+
# returns true if the service is disconnected
|
132
|
+
def disconnected?
|
133
|
+
false
|
134
|
+
end
|
135
|
+
# disconects the service.
|
136
|
+
def disconnect
|
137
|
+
on_disconnect
|
138
|
+
end
|
139
|
+
# returns true if the socket has content to be read.
|
140
|
+
def has_incoming_data?
|
141
|
+
false
|
142
|
+
end
|
143
|
+
|
144
|
+
|
145
|
+
# identification markers
|
146
|
+
|
147
|
+
#returns the service type - set to normal
|
148
|
+
def service_type
|
149
|
+
'no-service'
|
150
|
+
end
|
151
|
+
#returns true if the service is encrypted using the OpenSSL library.
|
152
|
+
def ssl?
|
153
|
+
false
|
154
|
+
end
|
155
|
+
|
156
|
+
#################
|
157
|
+
# overide the followind methods for any child class.
|
158
|
+
|
159
|
+
# this is a public method and it should be used by child classes to implement each
|
160
|
+
# read(_nonblock) action. accepts one argument ::size for an optional buffer size to be read.
|
161
|
+
def read size = 1048576
|
162
|
+
''
|
163
|
+
end
|
164
|
+
|
165
|
+
protected
|
166
|
+
|
167
|
+
# this is a protected method, it should be used by child classes to implement each
|
168
|
+
# send action.
|
169
|
+
def _send data
|
170
|
+
''
|
171
|
+
end
|
172
|
+
# this is a protected method, it should be used by child classes to implement each
|
173
|
+
# close action. doesn't accept any arguments.
|
174
|
+
def _close
|
175
|
+
end
|
176
|
+
# this is a protected method, it should be used by child classes to tell if the socket
|
177
|
+
# was closed (returns true/false).
|
178
|
+
def _disconnected?
|
179
|
+
false # if mode is read only, it's the same as closed.
|
180
|
+
end
|
181
|
+
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
|
186
|
+
######
|
187
|
+
## example requests
|
188
|
+
|
189
|
+
# GET / HTTP/1.1
|
190
|
+
# Host: localhost:2000
|
191
|
+
# Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
|
192
|
+
# Cookie: user_token=2INa32_vDgx8Aa1qe43oILELpSdIe9xwmT8GTWjkS-w
|
193
|
+
# User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10) AppleWebKit/600.1.25 (KHTML, like Gecko) Version/8.0 Safari/600.1.25
|
194
|
+
# Accept-Language: en-us
|
195
|
+
# Accept-Encoding: gzip, deflate
|
196
|
+
# Connection: keep-alive
|