plezi 0.7.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.
- 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
|