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,318 @@
|
|
1
|
+
module Plezi
|
2
|
+
|
3
|
+
# this module is the protocol (controller) for the HTTP server.
|
4
|
+
#
|
5
|
+
#
|
6
|
+
# to do: implemet logging, support body types: multipart (non-ASCII form data / uploaded files), json & xml
|
7
|
+
class HTTPProtocol
|
8
|
+
|
9
|
+
HTTP_METHODS = %w{GET HEAD POST PUT DELETE TRACE OPTIONS}
|
10
|
+
|
11
|
+
attr_accessor :service
|
12
|
+
|
13
|
+
def initialize service, params
|
14
|
+
@service = service
|
15
|
+
@parser_stage = 0
|
16
|
+
@parser_data = {}
|
17
|
+
@parser_body = ''
|
18
|
+
@parser_chunk = ''
|
19
|
+
@parser_length = 0
|
20
|
+
@locker = Mutex.new
|
21
|
+
@@rack_dictionary ||= {"HOST".freeze => :host_name, 'REQUEST_METHOD'.freeze => :method,
|
22
|
+
'PATH_INFO'.freeze => :path, 'QUERY_STRING'.freeze => :query,
|
23
|
+
'SERVER_NAME'.freeze => :host_name, 'SERVER_PORT'.freeze => :port,
|
24
|
+
'rack.url_scheme'.freeze => :requested_protocol}
|
25
|
+
end
|
26
|
+
|
27
|
+
# called when connection is initialized.
|
28
|
+
def on_connect service
|
29
|
+
end
|
30
|
+
|
31
|
+
# called when data is recieved.
|
32
|
+
#
|
33
|
+
# this method is called within a lock on the service (Mutex) - craeful from double locking.
|
34
|
+
#
|
35
|
+
# typically returns an Array with any data not yet processed (to be returned to the in-que)... but here it always processes (or discards) the data.
|
36
|
+
def on_message(service)
|
37
|
+
# parse the request
|
38
|
+
@locker.synchronize { parse_message }
|
39
|
+
if (@parser_stage == 1) && @parser_data[:version] >= 1.1
|
40
|
+
# send 100 continue message????? doesn't work! both Crome and Safari go crazy if this is sent after the request was sent (but before all the packets were recieved... msgs over 1 Mb).
|
41
|
+
# Plezi.push_event Proc.new { Plezi.info "sending continue signal."; service.send_nonblock "100 Continue\r\n\r\n" }
|
42
|
+
# service.send_unsafe_interrupt "100 Continue\r\n\r\n" # causes double lock on service
|
43
|
+
end
|
44
|
+
true
|
45
|
+
end
|
46
|
+
|
47
|
+
# # called when a disconnect is fired
|
48
|
+
# # (socket was disconnected / service should be disconnected / shutdown / socket error)
|
49
|
+
def on_disconnect service
|
50
|
+
end
|
51
|
+
|
52
|
+
# called when an exception was raised
|
53
|
+
# (socket was disconnected / service should be disconnected / shutdown / socket error)
|
54
|
+
def on_exception service, e
|
55
|
+
Plezi.error e
|
56
|
+
end
|
57
|
+
|
58
|
+
|
59
|
+
# Protocol specific helper methods.
|
60
|
+
|
61
|
+
# parses incoming data
|
62
|
+
def parse_message data = nil
|
63
|
+
data ||= service.read.to_s.lines.to_a
|
64
|
+
# require 'pry'; binding.pry
|
65
|
+
if @parser_stage == 0
|
66
|
+
return false unless parse_method data
|
67
|
+
end
|
68
|
+
if @parser_stage == 1
|
69
|
+
return false unless parse_head data
|
70
|
+
end
|
71
|
+
if @parser_stage == 2
|
72
|
+
return false unless parse_body data
|
73
|
+
end
|
74
|
+
true
|
75
|
+
end
|
76
|
+
|
77
|
+
# parses the method request (the first line in the HTTP request).
|
78
|
+
def parse_method data
|
79
|
+
return false unless data[0] && data[0].match(/^#{HTTP_METHODS.join('|')}/)
|
80
|
+
@parser_data[:time_recieved] = Time.now
|
81
|
+
@parser_data[:params] = {}
|
82
|
+
@parser_data[:cookies] = Cookies.new
|
83
|
+
@parser_data[:method] = ''
|
84
|
+
@parser_data[:query] = ''
|
85
|
+
@parser_data[:original_path] = ''
|
86
|
+
@parser_data[:path] = ''
|
87
|
+
if defined? Rack
|
88
|
+
@parser_data['rack.version'] = Rack::VERSION
|
89
|
+
@parser_data['rack.multithread'] = true
|
90
|
+
@parser_data['rack.multiprocess'] = false
|
91
|
+
@parser_data['rack.hijack?'] = false
|
92
|
+
@parser_data['rack.logger'] = Plezi.logger
|
93
|
+
end
|
94
|
+
@parser_data[:method], @parser_data[:query], @parser_data[:version] = data.shift.split(/[\s]+/)
|
95
|
+
@parser_data[:version] = (@parser_data[:version] || 'HTTP/1.1').match(/[0-9\.]+/).to_s.to_f
|
96
|
+
data.shift while data[0].to_s.match /^[\r\n]+/
|
97
|
+
@parser_stage = 1
|
98
|
+
end
|
99
|
+
|
100
|
+
#parses the head on a request (headers and values).
|
101
|
+
def parse_head data
|
102
|
+
until data[0].nil? || data[0].match(/^[\r\n]+$/)
|
103
|
+
m = data.shift.match(/^([^:]*):[\s]*([^\r\n]*)/)
|
104
|
+
# move cookies to cookie-jar, all else goes to headers
|
105
|
+
case m[1].downcase
|
106
|
+
when 'cookie'
|
107
|
+
HTTP.extract_data m[2].split(/[;,][\s]?/), @parser_data[:cookies], :uri
|
108
|
+
end
|
109
|
+
@parser_data[ HTTP.make_utf8!(m[1]).downcase ] ? (@parser_data[ HTTP.make_utf8!(m[1]).downcase ] << ", #{HTTP.make_utf8! m[2]}"): (@parser_data[ HTTP.make_utf8!(m[1]).downcase ] = HTTP.make_utf8! m[2])
|
110
|
+
end
|
111
|
+
return false unless data[0]
|
112
|
+
data.shift while data[0] && data[0].match(/^[\r\n]+$/)
|
113
|
+
if @parser_data["transfer-coding"] || (@parser_data["content-length"] && @parser_data["content-length"].to_i != 0) || @parser_data["content-type"]
|
114
|
+
@parser_stage = 2
|
115
|
+
else
|
116
|
+
# create request object and hand over to handler
|
117
|
+
complete_request
|
118
|
+
return parse_message data unless data.empty?
|
119
|
+
end
|
120
|
+
true
|
121
|
+
end
|
122
|
+
|
123
|
+
#parses the body of a request.
|
124
|
+
def parse_body data
|
125
|
+
# check for body is needed, if exists and if complete
|
126
|
+
if @parser_data["transfer-coding"] == "chunked"
|
127
|
+
until data.empty? || data[0].to_s.match(/0(\r)?\n/)
|
128
|
+
if @parser_length == 0
|
129
|
+
@parser_length = data.to_s.shift.match(/^[a-z0-9A-Z]+/).to_i(16)
|
130
|
+
@parser_chunk.clear
|
131
|
+
end
|
132
|
+
unless @parser_length == 0
|
133
|
+
@parser_chunk << data.shift while ( (@parser_length >= @parser_chunk.bytesize) && data[0])
|
134
|
+
end
|
135
|
+
if @parser_length <= @parser_chunk.bytesize
|
136
|
+
@parser_body << @parser_chunk.byteslice(0, @parser_body.bytesize)
|
137
|
+
@parser_length = 0
|
138
|
+
@parser_chunk.clear
|
139
|
+
end
|
140
|
+
end
|
141
|
+
return false unless data[0].to_s.match(/0(\r)?\n/)
|
142
|
+
true until data.empty? || data.shift.match(/^[\r\n]+$/)
|
143
|
+
data.shift while data[0].to_s.match /^[\r\n]+$/
|
144
|
+
elsif @parser_data["content-length"].to_i
|
145
|
+
@parser_length = @parser_data["content-length"].to_i if @parser_length == 0
|
146
|
+
@parser_chunk << data.shift while @parser_length > @parser_chunk.bytesize && data[0]
|
147
|
+
return false if @parser_length > @parser_chunk.bytesize
|
148
|
+
@parser_body = @parser_chunk.byteslice(0, @parser_length)
|
149
|
+
@parser_chunk.clear
|
150
|
+
else
|
151
|
+
Plezi.warn 'bad body request - trying to read'
|
152
|
+
@parser_body << data.shift while data[0] && !data[0].match(/^[\r\n]+$/)
|
153
|
+
end
|
154
|
+
# parse body (POST parameters)
|
155
|
+
read_body
|
156
|
+
|
157
|
+
# complete request
|
158
|
+
complete_request
|
159
|
+
|
160
|
+
#read next request unless data is finished
|
161
|
+
return parse_message data unless data.empty?
|
162
|
+
true
|
163
|
+
end
|
164
|
+
|
165
|
+
# completes the parsing of the request and sends the request to the handler.
|
166
|
+
def complete_request
|
167
|
+
#finalize params and query properties
|
168
|
+
m = @parser_data[:query].match /(([a-z0-9A-Z]+):\/\/)?(([^\/\:]+))?(:([0-9]+))?([^\?\#]*)(\?([^\#]*))?/
|
169
|
+
@parser_data[:requested_protocol] = m[1] || (service.ssl? ? 'https' : 'http')
|
170
|
+
@parser_data[:host_name] = m[4] || (@parser_data['host'] ? @parser_data['host'].match(/^[^:]*/).to_s : nil)
|
171
|
+
@parser_data[:port] = m[6] || (@parser_data['host'] ? @parser_data['host'].match(/:([0-9]*)/).to_a[1] : nil)
|
172
|
+
@parser_data[:original_path] = HTTP.decode(m[7], :uri) || '/'
|
173
|
+
@parser_data['host'] ||= "#{@parser_data[:host_name]}:#{@parser_data[:port]}"
|
174
|
+
# parse query for params - m[9] is the data part of the query
|
175
|
+
if m[9]
|
176
|
+
HTTP.extract_data m[9].split(/[&;]/), @parser_data[:params]
|
177
|
+
end
|
178
|
+
|
179
|
+
HTTP.make_utf8! @parser_data[:original_path]
|
180
|
+
@parser_data[:path] = @parser_data[:original_path].chomp('/')
|
181
|
+
@parser_data[:original_path].freeze
|
182
|
+
|
183
|
+
HTTP.make_utf8! @parser_data[:host_name] if @parser_data[:host_name]
|
184
|
+
HTTP.make_utf8! @parser_data[:query]
|
185
|
+
|
186
|
+
@parser_data[:client_ip] = @parser_data['x-forwarded-for'].to_s.split(/,[\s]?/)[0] || (service.socket.remote_address.ip_address) rescue 'unknown IP'
|
187
|
+
|
188
|
+
@@rack_dictionary.each {|k,v| @parser_data[k] = @parser_data[v]}
|
189
|
+
|
190
|
+
#create request
|
191
|
+
request = HTTPRequest.new service
|
192
|
+
request.update @parser_data
|
193
|
+
|
194
|
+
#clear current state
|
195
|
+
@parser_data.clear
|
196
|
+
@parser_body.clear
|
197
|
+
@parser_chunk.clear
|
198
|
+
@parser_length = 0
|
199
|
+
@parser_stage = 0
|
200
|
+
|
201
|
+
#check for server-responses
|
202
|
+
case request.request_method
|
203
|
+
when "TRACE"
|
204
|
+
return true
|
205
|
+
when "OPTIONS"
|
206
|
+
Plezi.push_event Proc.new do
|
207
|
+
response = HTTPResponse.new request
|
208
|
+
response[:Allow] = "GET,HEAD,POST,PUT,DELETE,OPTIONS"
|
209
|
+
response["access-control-allow-origin"] = "*"
|
210
|
+
response['content-length'] = 0
|
211
|
+
response.finish
|
212
|
+
end
|
213
|
+
return true
|
214
|
+
end
|
215
|
+
|
216
|
+
#pass it to the handler or decler error.
|
217
|
+
if service && service.handler
|
218
|
+
Plezi.callback service.handler, :on_request, request
|
219
|
+
else
|
220
|
+
Plezi.error "No Handler for this HTTP service."
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
# read the body's data and parse any incoming data.
|
225
|
+
def read_body
|
226
|
+
# parse content
|
227
|
+
case @parser_data["content-type"].to_s
|
228
|
+
when /x-www-form-urlencoded/
|
229
|
+
HTTP.extract_data @parser_body.split(/[&;]/), @parser_data[:params], :uri
|
230
|
+
when /multipart\/form-data/
|
231
|
+
read_multipart @parser_data, @parser_body
|
232
|
+
when /text\/xml/
|
233
|
+
# to-do support xml? support json?
|
234
|
+
@parser_data[:body] = @parser_body.dup
|
235
|
+
when /application\/json/
|
236
|
+
@parser_data[:body] = @parser_body.dup
|
237
|
+
JSON.parse(HTTP.make_utf8! @parser_data[:body]).each {|k, v| HTTP.add_param_to_hash k, v, @parser_data[:params]}
|
238
|
+
else
|
239
|
+
@parser_data[:body] = @parser_body.dup
|
240
|
+
Plezi.error "POST body type (#{@parser_data["content-type"]}) cannot be parsed. raw body is kept in the request's data as request[:body]: #{@parser_body}"
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
# parse a mime/multipart body or part.
|
245
|
+
def read_multipart headers, part, name_prefix = ''
|
246
|
+
if headers["content-type"].to_s.match /multipart/
|
247
|
+
boundry = headers["content-type"].match(/boundary=([^\s]+)/)[1]
|
248
|
+
if headers["content-disposition"].to_s.match /name=/
|
249
|
+
if name_prefix.empty?
|
250
|
+
name_prefix << HTTP.decode(headers["content-disposition"].to_s.match(/name="([^"]*)"/)[1])
|
251
|
+
else
|
252
|
+
name_prefix << "[#{HTTP.decode(headers["content-disposition"].to_s.match(/name="([^"]*)"/)[1])}]"
|
253
|
+
end
|
254
|
+
end
|
255
|
+
part.split(/([\r]?\n)?--#{boundry}(--)?[\r]?\n/).each do |p|
|
256
|
+
unless p.strip.empty? || p=='--'
|
257
|
+
# read headers
|
258
|
+
h = {}
|
259
|
+
p = p.lines
|
260
|
+
while p[0].match(/^[^:]+:[^\r\n]+/)
|
261
|
+
m = p.shift.match(/^([^:]+):[\s]?([^\r\n]+)/)
|
262
|
+
h[m[1].downcase] = m[2]
|
263
|
+
end
|
264
|
+
if p[0].strip.empty?
|
265
|
+
p.shift
|
266
|
+
else
|
267
|
+
Plezi.error 'Expected empty line after last header - empty line missing.'
|
268
|
+
end
|
269
|
+
# send headers and body to be read
|
270
|
+
read_multipart h, p.join, name_prefix
|
271
|
+
end
|
272
|
+
end
|
273
|
+
return
|
274
|
+
end
|
275
|
+
|
276
|
+
# require a part body to exist (data exists) for parsing
|
277
|
+
return true if part.to_s.empty?
|
278
|
+
|
279
|
+
# convert part to `charset` if charset is defined?
|
280
|
+
|
281
|
+
if !headers["content-disposition"]
|
282
|
+
Plezi.error "Wrong multipart format with headers: #{headers} and body: #{part}"
|
283
|
+
return
|
284
|
+
end
|
285
|
+
|
286
|
+
cd = {}
|
287
|
+
|
288
|
+
HTTP.extract_data headers["content-disposition"].match(/[^;];([^\r\n]*)/)[1].split(/[;,][\s]?/), cd, :uri
|
289
|
+
|
290
|
+
name = name_prefix.dup
|
291
|
+
|
292
|
+
if name_prefix.empty?
|
293
|
+
name << HTTP.decode(cd[:name][1..-2])
|
294
|
+
else
|
295
|
+
name << "[#{HTTP.decode(cd[:name][1..-2])}]"
|
296
|
+
end
|
297
|
+
if headers["content-type"]
|
298
|
+
HTTP.add_param_to_hash "#{name}[data]", part, @parser_data[:params]
|
299
|
+
HTTP.add_param_to_hash "#{name}[type]", HTTP.make_utf8!(headers["content-type"]), @parser_data[:params]
|
300
|
+
cd.each {|k,v| HTTP.add_param_to_hash "#{name}[#{k.to_s}]", HTTP.make_utf8!(v[1..-2]), @parser_data[:params] unless k == :name}
|
301
|
+
else
|
302
|
+
HTTP.add_param_to_hash name, HTTP.decode(part, :utf8), @parser_data[:params]
|
303
|
+
end
|
304
|
+
true
|
305
|
+
end
|
306
|
+
end
|
307
|
+
end
|
308
|
+
|
309
|
+
## Heroku/extra headers info
|
310
|
+
|
311
|
+
# All headers are considered to be case-insensitive, as per HTTP Specification.
|
312
|
+
# X-Forwarded-For: the originating IP address of the client connecting to the Heroku router
|
313
|
+
# X-Forwarded-Proto: the originating protocol of the HTTP request (example: https)
|
314
|
+
# X-Forwarded-Port: the originating port of the HTTP request (example: 443)
|
315
|
+
# X-Request-Start: unix timestamp (milliseconds) when the request was received by the router
|
316
|
+
# X-Request-Id: the Heroku HTTP Request ID
|
317
|
+
# Via: a code name for the Heroku router
|
318
|
+
|
@@ -0,0 +1,133 @@
|
|
1
|
+
module Plezi
|
2
|
+
|
3
|
+
# class is the base for the HTTP server.
|
4
|
+
#
|
5
|
+
# the class is initialized with a TCP/IP connection socket and starts
|
6
|
+
# an event driven cycle using the `EventStack.push` and `EventStack.reverse_async`.
|
7
|
+
#
|
8
|
+
# to-do: fox logging.
|
9
|
+
class HTTPRequest < Hash
|
10
|
+
|
11
|
+
def initialize service
|
12
|
+
super()
|
13
|
+
self[:plezi_service] = service
|
14
|
+
end
|
15
|
+
|
16
|
+
public
|
17
|
+
|
18
|
+
# the request's headers
|
19
|
+
def headers
|
20
|
+
self.select {|k,v| k.is_a? String }
|
21
|
+
end
|
22
|
+
# the request's method (GET, POST... etc').
|
23
|
+
def request_method
|
24
|
+
self[:method]
|
25
|
+
end
|
26
|
+
# set request's method (GET, POST... etc').
|
27
|
+
def request_method= value
|
28
|
+
self[:method] = value
|
29
|
+
end
|
30
|
+
# the parameters sent by the client.
|
31
|
+
def params
|
32
|
+
self[:params]
|
33
|
+
end
|
34
|
+
# the cookies sent by the client.
|
35
|
+
def cookies
|
36
|
+
self[:cookies]
|
37
|
+
end
|
38
|
+
|
39
|
+
# the query string
|
40
|
+
def query
|
41
|
+
self[:query]
|
42
|
+
end
|
43
|
+
|
44
|
+
# the original (frozen) path (resource requested).
|
45
|
+
def original_path
|
46
|
+
self[:original_path]
|
47
|
+
end
|
48
|
+
|
49
|
+
# the requested path (rewritable).
|
50
|
+
def path
|
51
|
+
self[:path]
|
52
|
+
end
|
53
|
+
def path=(new_path)
|
54
|
+
self[:path] = new_path
|
55
|
+
end
|
56
|
+
|
57
|
+
# the base url ([http/https]://host[:port])
|
58
|
+
def base_url switch_protocol = nil
|
59
|
+
"#{switch_protocol || self[:requested_protocol]}://#{self[:host_name]}#{self[:port]? ":#{self[:port]}" : ''}"
|
60
|
+
end
|
61
|
+
|
62
|
+
# the service (socket wrapper) that answered this request
|
63
|
+
def service
|
64
|
+
self[:plezi_service]
|
65
|
+
end
|
66
|
+
# the protocol managing this request
|
67
|
+
def protocol
|
68
|
+
self[:requested_protocol]
|
69
|
+
end
|
70
|
+
# the handler dealing with this request
|
71
|
+
def handler
|
72
|
+
self[:plezi_service].handler
|
73
|
+
end
|
74
|
+
|
75
|
+
# method recognition
|
76
|
+
|
77
|
+
# returns true of the method == GET
|
78
|
+
def get?
|
79
|
+
self[:method] == 'GET'
|
80
|
+
end
|
81
|
+
# returns true of the method == HEAD
|
82
|
+
def head?
|
83
|
+
self[:method] == 'HEAD'
|
84
|
+
end
|
85
|
+
# returns true of the method == POST
|
86
|
+
def post?
|
87
|
+
self[:method] == 'POST'
|
88
|
+
end
|
89
|
+
# returns true of the method == PUT
|
90
|
+
def put?
|
91
|
+
self[:method] == 'PUT'
|
92
|
+
end
|
93
|
+
# returns true of the method == DELETE
|
94
|
+
def delete?
|
95
|
+
self[:method] == 'DELETE'
|
96
|
+
end
|
97
|
+
# returns true of the method == TRACE
|
98
|
+
def trace?
|
99
|
+
self[:method] == 'TRACE'
|
100
|
+
end
|
101
|
+
# returns true of the method == OPTIONS
|
102
|
+
def options?
|
103
|
+
self[:method] == 'OPTIONS'
|
104
|
+
end
|
105
|
+
# returns true of the method == CONNECT
|
106
|
+
def connect?
|
107
|
+
self[:method] == 'CONNECT'
|
108
|
+
end
|
109
|
+
# returns true of the method == PATCH
|
110
|
+
def patch?
|
111
|
+
self[:method] == 'PATCH'
|
112
|
+
end
|
113
|
+
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
|
118
|
+
######
|
119
|
+
## example requests
|
120
|
+
|
121
|
+
# GET / HTTP/1.1
|
122
|
+
# Host: localhost:2000
|
123
|
+
# Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
|
124
|
+
# Cookie: user_token=2INa32_vDgx8Aa1qe43oILELpSdIe9xwmT8GTWjkS-w
|
125
|
+
# 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
|
126
|
+
# Accept-Language: en-us
|
127
|
+
# Accept-Encoding: gzip, deflate
|
128
|
+
# Connection: keep-alive
|
129
|
+
#
|
130
|
+
# => "GET / HTTP/1.1\n\rHost: localhost:2000\n\rAccept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\n\rCookie: user_token=2INa32_vDgx8Aa1qe43oILELpSdIe9xwmT8GTWjkS-w\n\rUser-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\n\rAccept-Language: en-us\n\rAccept-Encoding: gzip, deflate\n\rConnection: keep-alive\n\r\n\r"
|
131
|
+
# => "GET /people/are/friendly HTTP/1.1\n\rHost: localhost:2000\n\rAccept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\n\rCookie: user_token=2INa32_vDgx8Aa1qe43oILELpSdIe9xwmT8GTWjkS-w\n\rUser-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\n\rAccept-Language: en-us\n\rAccept-Encoding: gzip, deflate\n\rConnection: keep-alive\n\r\n\r"
|
132
|
+
# => "GET /girls?sexy=true HTTP/1.1\n\rHost: localhost:2000\n\rAccept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\n\rCookie: user_token=2INa32_vDgx8Aa1qe43oILELpSdIe9xwmT8GTWjkS-w\n\rUser-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\n\rAccept-Language: en-us\n\rAccept-Encoding: gzip, deflate\n\rConnection: keep-alive\n\r\n\r"
|
133
|
+
# chunked => "17d; ignored data=boaz\r\nGET / HTTP/1.1\r\nHost: localhost:3000\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\nCookie: user_token=2INa32_vDgx8Aa1qe43oILELpSdIe9xwmT8GTWjkS-w\r\nUser-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\r\nAccept-Language: en-us\r\nAccept-Encoding: gzip, deflate\r\nConnection: keep-alive\r\nc\r\n\r\nparsed as:\r\n\r\n4f4\r\n{:raw=>\"GET / HTTP/1.1\\r\\nHost: localhost:3000\\r\\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\\r\\nCookie: user_token=2INa32_vDgx8Aa1qe43oILELpSdIe9xwmT8GTWjkS-w\\r\\nUser-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\\r\\nAccept-Language: en-us\\r\\nAccept-Encoding: gzip, deflate\\r\\nConnection: keep-alive\\r\\n\\r\\n\", :plezi_service=>#<Plezi::BasicService:0x007ff4daab5ac8 @handler=Plezi::HTTPEcho, @socket=#<TCPSocket:fd 9>, @in_que=\"\", @out_que=[], @locker=#<Mutex:0x007ff4daab5a28>, @parameters={:protocol=>Plezi::HTTPProtocol, :handler=>Plezi::HTTPEcho}, @protocol=Plezi::HTTPProtocol>, :params=>{}, :cookies=>{:user_token=>\"2INa32_vDgx8Aa1qe43oILELpSdIe9xwmT8GTWjkS-w\"}, :method=>\"GET\", :query=>\"/\", :original_path=>\"/\", :path=>\"/\", :version=>\"HTTP/1.1\", \"host\"=>\"localhost:3000\", \"accept\"=>\"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\", \"cookie\"=>\"user_token=2INa32_vDgx8Aa1qe43oILELpSdIe9xwmT8GTWjkS-w\", \"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\", \"accept-language\"=>\"en-us\", \"accept-encoding\"=>\"gzip, deflate\", \"connection\"=>\"keep-alive\"}\r\n0\r\n\r\n"
|