merb-core 0.9.8 → 0.9.9
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.
- data/CONTRIBUTORS +33 -0
- data/README +7 -3
- data/Rakefile +3 -3
- data/lib/merb-core.rb +165 -94
- data/lib/merb-core/bootloader.rb +469 -100
- data/lib/merb-core/config.rb +79 -3
- data/lib/merb-core/constants.rb +24 -2
- data/lib/merb-core/controller/abstract_controller.rb +172 -67
- data/lib/merb-core/controller/exceptions.rb +50 -6
- data/lib/merb-core/controller/merb_controller.rb +215 -108
- data/lib/merb-core/controller/mime.rb +36 -12
- data/lib/merb-core/controller/mixins/authentication.rb +52 -7
- data/lib/merb-core/controller/mixins/conditional_get.rb +14 -0
- data/lib/merb-core/controller/mixins/controller.rb +90 -58
- data/lib/merb-core/controller/mixins/render.rb +34 -10
- data/lib/merb-core/controller/mixins/responder.rb +40 -16
- data/lib/merb-core/controller/template.rb +37 -16
- data/lib/merb-core/core_ext/hash.rb +9 -0
- data/lib/merb-core/core_ext/kernel.rb +92 -41
- data/lib/merb-core/dispatch/dispatcher.rb +29 -45
- data/lib/merb-core/dispatch/request.rb +186 -82
- data/lib/merb-core/dispatch/router.rb +141 -53
- data/lib/merb-core/dispatch/router/behavior.rb +296 -139
- data/lib/merb-core/dispatch/router/resources.rb +51 -19
- data/lib/merb-core/dispatch/router/route.rb +76 -23
- data/lib/merb-core/dispatch/session.rb +80 -36
- data/lib/merb-core/dispatch/session/container.rb +31 -15
- data/lib/merb-core/dispatch/session/cookie.rb +51 -22
- data/lib/merb-core/dispatch/session/memcached.rb +10 -6
- data/lib/merb-core/dispatch/session/memory.rb +17 -5
- data/lib/merb-core/dispatch/session/store_container.rb +21 -9
- data/lib/merb-core/dispatch/worker.rb +16 -2
- data/lib/merb-core/gem_ext/erubis.rb +4 -0
- data/lib/merb-core/plugins.rb +13 -0
- data/lib/merb-core/rack.rb +1 -0
- data/lib/merb-core/rack/adapter.rb +1 -0
- data/lib/merb-core/rack/adapter/abstract.rb +95 -17
- data/lib/merb-core/rack/adapter/irb.rb +50 -5
- data/lib/merb-core/rack/application.rb +27 -5
- data/lib/merb-core/rack/handler/mongrel.rb +6 -6
- data/lib/merb-core/rack/helpers.rb +33 -0
- data/lib/merb-core/rack/middleware/conditional_get.rb +1 -1
- data/lib/merb-core/rack/middleware/path_prefix.rb +3 -3
- data/lib/merb-core/rack/middleware/static.rb +11 -7
- data/lib/merb-core/server.rb +134 -69
- data/lib/merb-core/tasks/gem_management.rb +153 -80
- data/lib/merb-core/tasks/merb_rake_helper.rb +12 -4
- data/lib/merb-core/tasks/stats.rake +1 -1
- data/lib/merb-core/test/helpers/mock_request_helper.rb +29 -22
- data/lib/merb-core/test/helpers/request_helper.rb +1 -1
- data/lib/merb-core/test/helpers/route_helper.rb +50 -4
- data/lib/merb-core/test/matchers/request_matchers.rb +2 -36
- data/lib/merb-core/test/matchers/view_matchers.rb +32 -22
- data/lib/merb-core/test/run_specs.rb +6 -5
- data/lib/merb-core/test/test_ext/rspec.rb +6 -19
- data/lib/merb-core/version.rb +1 -1
- metadata +5 -4
@@ -25,16 +25,26 @@ module Merb
|
|
25
25
|
self.http_method_overrides = []
|
26
26
|
|
27
27
|
# Initialize the request object.
|
28
|
-
#
|
28
|
+
#
|
29
29
|
# ==== Parameters
|
30
30
|
# http_request<~params:~[], ~body:IO>::
|
31
31
|
# An object like an HTTP Request.
|
32
|
+
#
|
33
|
+
# @api private
|
32
34
|
def initialize(rack_env)
|
33
35
|
@env = rack_env
|
34
36
|
@body = rack_env['rack.input']
|
35
37
|
@route_params = {}
|
36
38
|
end
|
37
39
|
|
40
|
+
# Returns the controller object for initialization and dispatching the
|
41
|
+
# request.
|
42
|
+
#
|
43
|
+
# ==== Returns
|
44
|
+
# Class:: The controller class matching the routed request,
|
45
|
+
# e.g. Posts.
|
46
|
+
#
|
47
|
+
# @api private
|
38
48
|
def controller
|
39
49
|
unless params[:controller]
|
40
50
|
raise ControllerExceptions::NotFound,
|
@@ -58,13 +68,15 @@ module Merb
|
|
58
68
|
METHODS = %w{get post put delete head options}
|
59
69
|
|
60
70
|
# ==== Returns
|
61
|
-
#
|
71
|
+
# Symbol:: The name of the request method, e.g. :get.
|
62
72
|
#
|
63
73
|
# ==== Notes
|
64
74
|
# If the method is post, then the blocks specified in
|
65
75
|
# http_method_overrides will be checked for the masquerading method.
|
66
76
|
# The block will get the controller yielded to it. The first matching workaround wins.
|
67
77
|
# To disable this behavior, set http_method_overrides = []
|
78
|
+
#
|
79
|
+
# @api public
|
68
80
|
def method
|
69
81
|
@method ||= begin
|
70
82
|
request_method = @env['REQUEST_METHOD'].downcase.to_sym
|
@@ -89,86 +101,83 @@ module Merb
|
|
89
101
|
METHODS.each do |m|
|
90
102
|
class_eval "def #{m}?() method == :#{m} end"
|
91
103
|
end
|
92
|
-
|
104
|
+
|
105
|
+
# ==== Notes
|
93
106
|
# Find route using requested URI and merges route
|
94
107
|
# parameters (:action, :controller and named segments)
|
95
108
|
# into request params hash.
|
109
|
+
#
|
110
|
+
# @api private
|
96
111
|
def find_route!
|
97
112
|
@route, @route_params = Merb::Router.route_for(self)
|
98
|
-
params.merge! @route_params
|
113
|
+
params.merge! @route_params if @route_params.is_a?(Hash)
|
99
114
|
end
|
100
115
|
|
116
|
+
# ==== Notes
|
101
117
|
# Processes the return value of a deferred router block
|
102
118
|
# and returns the current route params for the current
|
103
119
|
# request evaluation
|
104
|
-
#
|
105
|
-
# @private
|
120
|
+
#
|
121
|
+
# @api private
|
106
122
|
def _process_block_return(retval)
|
107
123
|
# If the return value is an array, then it is a redirect
|
108
124
|
# so we must set the request as a redirect and extract
|
109
125
|
# the redirect params and return it as a hash so that the
|
110
126
|
# dispatcher can handle it
|
111
|
-
if retval.is_a?(Array)
|
112
|
-
redirects!
|
113
|
-
return { :url => retval[0], :status => retval[1] }
|
114
|
-
end
|
127
|
+
matched! if retval.is_a?(Array)
|
115
128
|
retval
|
116
129
|
end
|
117
130
|
|
118
|
-
# Sets the request as a redirect. This method is only really
|
119
|
-
# used in the router to tell the request object how to handle
|
120
|
-
# the route params. This will also set the request as matched.
|
121
|
-
# ---
|
122
|
-
# @private
|
123
|
-
def redirects!
|
124
|
-
@matched = true
|
125
|
-
@redirects = true
|
126
|
-
end
|
127
|
-
|
128
131
|
# Sets the request as matched. This will abort evaluating any
|
129
132
|
# further deferred procs.
|
130
|
-
#
|
131
|
-
# @private
|
133
|
+
#
|
134
|
+
# @api private
|
132
135
|
def matched!
|
133
136
|
@matched = true
|
134
137
|
end
|
135
138
|
|
136
139
|
# Checks whether or not the request has been matched to a route.
|
137
|
-
#
|
138
|
-
# @private
|
140
|
+
#
|
141
|
+
# @api private
|
139
142
|
def matched?
|
140
143
|
@matched
|
141
144
|
end
|
142
|
-
|
143
|
-
# Redirect status of route matched this request.
|
144
|
-
#
|
145
|
-
# ==== Returns
|
146
|
-
# Integer::
|
147
|
-
# The URL to redirect to if the route redirects
|
148
|
-
def redirect_status
|
149
|
-
@route_params[:status] if redirects?
|
150
|
-
end
|
151
|
-
|
152
|
-
# Returns redirect url of route matched this request.
|
153
|
-
#
|
145
|
+
|
154
146
|
# ==== Returns
|
155
|
-
#
|
156
|
-
|
157
|
-
|
147
|
+
# (Array, Hash):: the route params for the matched route.
|
148
|
+
#
|
149
|
+
# ==== Notes
|
150
|
+
# If the response is an Array then it is considered a direct Rack response
|
151
|
+
# to be sent back as a response. Otherwise, the route_params is a Hash with
|
152
|
+
# routing data (controller, action, et al).
|
153
|
+
#
|
154
|
+
# @api private
|
155
|
+
def rack_response
|
156
|
+
@route_params
|
158
157
|
end
|
159
|
-
|
160
|
-
#
|
161
|
-
#
|
158
|
+
|
159
|
+
# If @route_params is an Array, then it will be the rack response.
|
160
|
+
# In this case, the request is considered handled.
|
161
|
+
#
|
162
162
|
# ==== Returns
|
163
|
-
#
|
164
|
-
|
165
|
-
|
163
|
+
# Boolean:: true if @route_params is an Array, false otherwise.
|
164
|
+
#
|
165
|
+
# @api private
|
166
|
+
def handled?
|
167
|
+
@route_params.is_a?(Array)
|
166
168
|
end
|
167
169
|
|
170
|
+
# == Params
|
171
|
+
#
|
172
|
+
# Handles processing params from raw data and merging them together to get
|
173
|
+
# the final request params.
|
174
|
+
|
168
175
|
private
|
169
176
|
|
170
177
|
# ==== Returns
|
171
178
|
# Hash:: Parameters passed from the URL like ?blah=hello.
|
179
|
+
#
|
180
|
+
# @api private
|
172
181
|
def query_params
|
173
182
|
@query_params ||= self.class.query_parse(query_string || '')
|
174
183
|
end
|
@@ -178,6 +187,8 @@ module Merb
|
|
178
187
|
#
|
179
188
|
# ==== Returns
|
180
189
|
# Hash:: The parameters passed in the body.
|
190
|
+
#
|
191
|
+
# @api private
|
181
192
|
def body_params
|
182
193
|
@body_params ||= begin
|
183
194
|
if content_type && content_type.match(Merb::Const::FORM_URL_ENCODED_REGEXP) # or content_type.nil?
|
@@ -185,11 +196,13 @@ module Merb
|
|
185
196
|
end
|
186
197
|
end
|
187
198
|
end
|
188
|
-
|
199
|
+
|
189
200
|
# ==== Returns
|
190
201
|
# Mash::
|
191
202
|
# The parameters gathered from the query string and the request body,
|
192
203
|
# with parameters in the body taking precedence.
|
204
|
+
#
|
205
|
+
# @api private
|
193
206
|
def body_and_query_params
|
194
207
|
# ^-- FIXME a better name for this method
|
195
208
|
@body_and_query_params ||= begin
|
@@ -198,13 +211,15 @@ module Merb
|
|
198
211
|
h.to_mash
|
199
212
|
end
|
200
213
|
end
|
201
|
-
|
214
|
+
|
202
215
|
# ==== Raises
|
203
216
|
# ControllerExceptions::MultiPartParseError::
|
204
217
|
# Unable to parse the multipart form data.
|
205
218
|
#
|
206
219
|
# ==== Returns
|
207
220
|
# Hash:: The parsed multipart parameters.
|
221
|
+
#
|
222
|
+
# @api private
|
208
223
|
def multipart_params
|
209
224
|
@multipart_params ||=
|
210
225
|
begin
|
@@ -220,7 +235,7 @@ module Merb
|
|
220
235
|
raise e
|
221
236
|
end
|
222
237
|
end
|
223
|
-
|
238
|
+
|
224
239
|
# ==== Returns
|
225
240
|
# Hash:: Parameters from body if this is a JSON request.
|
226
241
|
#
|
@@ -229,6 +244,8 @@ module Merb
|
|
229
244
|
# parameters hash. If it parses to anything else (such as an Array, or
|
230
245
|
# if it inflates to an Object) it will be accessible via the inflated_object
|
231
246
|
# parameter.
|
247
|
+
#
|
248
|
+
# @api private
|
232
249
|
def json_params
|
233
250
|
@json_params ||= begin
|
234
251
|
if Merb::Const::JSON_MIME_TYPE_REGEXP.match(content_type)
|
@@ -237,9 +254,11 @@ module Merb
|
|
237
254
|
end
|
238
255
|
end
|
239
256
|
end
|
240
|
-
|
257
|
+
|
241
258
|
# ==== Returns
|
242
259
|
# Hash:: Parameters from body if this is an XML request.
|
260
|
+
#
|
261
|
+
# @api private
|
243
262
|
def xml_params
|
244
263
|
@xml_params ||= begin
|
245
264
|
if Merb::Const::XML_MIME_TYPE_REGEXP.match(content_type)
|
@@ -256,6 +275,8 @@ module Merb
|
|
256
275
|
# ==== Notes
|
257
276
|
# The order of precedence for the params is XML, JSON, multipart, body and
|
258
277
|
# request string.
|
278
|
+
#
|
279
|
+
# @api public
|
259
280
|
def params
|
260
281
|
@params ||= begin
|
261
282
|
h = body_and_query_params.merge(route_params)
|
@@ -266,6 +287,10 @@ module Merb
|
|
266
287
|
end
|
267
288
|
end
|
268
289
|
|
290
|
+
# ==== Returns
|
291
|
+
# String:: Returns the redirect message Base64 unencoded.
|
292
|
+
#
|
293
|
+
# @api public
|
269
294
|
def message
|
270
295
|
return {} unless params[:_message]
|
271
296
|
begin
|
@@ -274,14 +299,19 @@ module Merb
|
|
274
299
|
{}
|
275
300
|
end
|
276
301
|
end
|
277
|
-
|
302
|
+
|
303
|
+
# ==== Notes
|
278
304
|
# Resets the params to a nil value.
|
305
|
+
#
|
306
|
+
# @api private
|
279
307
|
def reset_params!
|
280
308
|
@params = nil
|
281
309
|
end
|
282
310
|
|
283
311
|
# ==== Returns
|
284
312
|
# String:: The raw post.
|
313
|
+
#
|
314
|
+
# @api private
|
285
315
|
def raw_post
|
286
316
|
@body.rewind if @body.respond_to?(:rewind)
|
287
317
|
@raw_post ||= @body.read
|
@@ -289,6 +319,8 @@ module Merb
|
|
289
319
|
|
290
320
|
# ==== Returns
|
291
321
|
# Boolean:: If the request is an XML HTTP request.
|
322
|
+
#
|
323
|
+
# @api public
|
292
324
|
def xml_http_request?
|
293
325
|
not /XMLHttpRequest/i.match(@env['HTTP_X_REQUESTED_WITH']).nil?
|
294
326
|
end
|
@@ -297,17 +329,19 @@ module Merb
|
|
297
329
|
|
298
330
|
# ==== Returns
|
299
331
|
# String:: The remote IP address.
|
332
|
+
#
|
333
|
+
# @api public
|
300
334
|
def remote_ip
|
301
335
|
return @env['HTTP_CLIENT_IP'] if @env.include?('HTTP_CLIENT_IP')
|
302
|
-
|
336
|
+
|
303
337
|
if @env.include?(Merb::Const::HTTP_X_FORWARDED_FOR) then
|
304
338
|
remote_ips = @env[Merb::Const::HTTP_X_FORWARDED_FOR].split(',').reject do |ip|
|
305
339
|
ip =~ /^unknown$|^(127|10|172\.16|192\.168)\./i
|
306
340
|
end
|
307
|
-
|
341
|
+
|
308
342
|
return remote_ips.first.strip unless remote_ips.empty?
|
309
343
|
end
|
310
|
-
|
344
|
+
|
311
345
|
return @env[Merb::Const::REMOTE_ADDR]
|
312
346
|
end
|
313
347
|
|
@@ -315,126 +349,168 @@ module Merb
|
|
315
349
|
# String::
|
316
350
|
# The protocol, i.e. either "https" or "http" depending on the
|
317
351
|
# HTTPS header.
|
352
|
+
#
|
353
|
+
# @api public
|
318
354
|
def protocol
|
319
355
|
ssl? ? 'https' : 'http'
|
320
356
|
end
|
321
357
|
|
322
358
|
# ==== Returns
|
323
359
|
# Boolean::: True if the request is an SSL request.
|
360
|
+
#
|
361
|
+
# @api public
|
324
362
|
def ssl?
|
325
363
|
@env['HTTPS'] == 'on' || @env['HTTP_X_FORWARDED_PROTO'] == 'https'
|
326
364
|
end
|
327
365
|
|
328
366
|
# ==== Returns
|
329
367
|
# String:: The HTTP referer.
|
368
|
+
#
|
369
|
+
# @api public
|
330
370
|
def referer
|
331
371
|
@env['HTTP_REFERER']
|
332
372
|
end
|
333
373
|
|
334
374
|
# ==== Returns
|
335
375
|
# String:: The full URI, including protocol and host
|
376
|
+
#
|
377
|
+
# @api public
|
336
378
|
def full_uri
|
337
379
|
protocol + "://" + host + uri
|
338
380
|
end
|
339
381
|
|
340
382
|
# ==== Returns
|
341
383
|
# String:: The request URI.
|
384
|
+
#
|
385
|
+
# @api public
|
342
386
|
def uri
|
343
387
|
@env['REQUEST_PATH'] || @env['REQUEST_URI'] || path_info
|
344
388
|
end
|
345
|
-
|
389
|
+
|
346
390
|
# ==== Returns
|
347
391
|
# String:: The HTTP user agent.
|
392
|
+
#
|
393
|
+
# @api public
|
348
394
|
def user_agent
|
349
395
|
@env['HTTP_USER_AGENT']
|
350
396
|
end
|
351
|
-
|
397
|
+
|
352
398
|
# ==== Returns
|
353
399
|
# String:: The server name.
|
400
|
+
#
|
401
|
+
# @api public
|
354
402
|
def server_name
|
355
403
|
@env['SERVER_NAME']
|
356
404
|
end
|
357
|
-
|
405
|
+
|
358
406
|
# ==== Returns
|
359
407
|
# String:: The accepted encodings.
|
408
|
+
#
|
409
|
+
# @api private
|
360
410
|
def accept_encoding
|
361
411
|
@env['HTTP_ACCEPT_ENCODING']
|
362
412
|
end
|
363
|
-
|
413
|
+
|
364
414
|
# ==== Returns
|
365
415
|
# String:: The script name.
|
416
|
+
#
|
417
|
+
# @api public
|
366
418
|
def script_name
|
367
419
|
@env['SCRIPT_NAME']
|
368
420
|
end
|
369
|
-
|
421
|
+
|
370
422
|
# ==== Returns
|
371
423
|
# String:: HTTP cache control.
|
424
|
+
#
|
425
|
+
# @api public
|
372
426
|
def cache_control
|
373
427
|
@env['HTTP_CACHE_CONTROL']
|
374
428
|
end
|
375
|
-
|
429
|
+
|
376
430
|
# ==== Returns
|
377
431
|
# String:: The accepted language.
|
432
|
+
#
|
433
|
+
# @api public
|
378
434
|
def accept_language
|
379
435
|
@env['HTTP_ACCEPT_LANGUAGE']
|
380
436
|
end
|
381
|
-
|
437
|
+
|
382
438
|
# ==== Returns
|
383
439
|
# String:: The server software.
|
440
|
+
#
|
441
|
+
# @api public
|
384
442
|
def server_software
|
385
443
|
@env['SERVER_SOFTWARE']
|
386
444
|
end
|
387
|
-
|
445
|
+
|
388
446
|
# ==== Returns
|
389
447
|
# String:: Value of HTTP_KEEP_ALIVE.
|
448
|
+
#
|
449
|
+
# @api public
|
390
450
|
def keep_alive
|
391
451
|
@env['HTTP_KEEP_ALIVE']
|
392
452
|
end
|
393
|
-
|
453
|
+
|
394
454
|
# ==== Returns
|
395
455
|
# String:: The accepted character sets.
|
456
|
+
#
|
457
|
+
# @api public
|
396
458
|
def accept_charset
|
397
459
|
@env['HTTP_ACCEPT_CHARSET']
|
398
460
|
end
|
399
|
-
|
461
|
+
|
400
462
|
# ==== Returns
|
401
463
|
# String:: The HTTP version
|
464
|
+
#
|
465
|
+
# @api private
|
402
466
|
def version
|
403
467
|
@env['HTTP_VERSION']
|
404
468
|
end
|
405
|
-
|
469
|
+
|
406
470
|
# ==== Returns
|
407
471
|
# String:: The gateway.
|
472
|
+
#
|
473
|
+
# @api public
|
408
474
|
def gateway
|
409
475
|
@env['GATEWAY_INTERFACE']
|
410
476
|
end
|
411
|
-
|
477
|
+
|
412
478
|
# ==== Returns
|
413
479
|
# String:: The accepted response types. Defaults to "*/*".
|
480
|
+
#
|
481
|
+
# @api private
|
414
482
|
def accept
|
415
483
|
@env['HTTP_ACCEPT'].blank? ? "*/*" : @env['HTTP_ACCEPT']
|
416
484
|
end
|
417
|
-
|
485
|
+
|
418
486
|
# ==== Returns
|
419
487
|
# String:: The HTTP connection.
|
488
|
+
#
|
489
|
+
# @api private
|
420
490
|
def connection
|
421
491
|
@env['HTTP_CONNECTION']
|
422
492
|
end
|
423
|
-
|
493
|
+
|
424
494
|
# ==== Returns
|
425
495
|
# String:: The query string.
|
496
|
+
#
|
497
|
+
# @api private
|
426
498
|
def query_string
|
427
499
|
@env['QUERY_STRING']
|
428
500
|
end
|
429
|
-
|
501
|
+
|
430
502
|
# ==== Returns
|
431
503
|
# String:: The request content type.
|
504
|
+
#
|
505
|
+
# @api private
|
432
506
|
def content_type
|
433
507
|
@env['CONTENT_TYPE']
|
434
508
|
end
|
435
|
-
|
509
|
+
|
436
510
|
# ==== Returns
|
437
511
|
# Fixnum:: The request content length.
|
512
|
+
#
|
513
|
+
# @api public
|
438
514
|
def content_length
|
439
515
|
@content_length ||= @env[Merb::Const::CONTENT_LENGTH].to_i
|
440
516
|
end
|
@@ -443,6 +519,8 @@ module Merb
|
|
443
519
|
# String::
|
444
520
|
# The URI without the query string. Strips trailing "/" and reduces
|
445
521
|
# duplicate "/" to a single "/".
|
522
|
+
#
|
523
|
+
# @api public
|
446
524
|
def path
|
447
525
|
path = (uri.empty? ? '/' : uri.split('?').first).squeeze("/")
|
448
526
|
path = path[0..-2] if (path[-1] == ?/) && path.size > 1
|
@@ -451,18 +529,24 @@ module Merb
|
|
451
529
|
|
452
530
|
# ==== Returns
|
453
531
|
# String:: The path info.
|
532
|
+
#
|
533
|
+
# @api public
|
454
534
|
def path_info
|
455
535
|
@path_info ||= self.class.unescape(@env['PATH_INFO'])
|
456
536
|
end
|
457
537
|
|
458
538
|
# ==== Returns
|
459
539
|
# Fixnum:: The server port.
|
540
|
+
#
|
541
|
+
# @api public
|
460
542
|
def port
|
461
543
|
@env['SERVER_PORT'].to_i
|
462
544
|
end
|
463
545
|
|
464
546
|
# ==== Returns
|
465
547
|
# String:: The full hostname including the port.
|
548
|
+
#
|
549
|
+
# @api public
|
466
550
|
def host
|
467
551
|
@env['HTTP_X_FORWARDED_HOST'] || @env['HTTP_HOST']
|
468
552
|
end
|
@@ -474,6 +558,8 @@ module Merb
|
|
474
558
|
#
|
475
559
|
# ==== Returns
|
476
560
|
# Array:: All the subdomain parts of the host.
|
561
|
+
#
|
562
|
+
# @api public
|
477
563
|
def subdomains(tld_length = 1)
|
478
564
|
parts = host.split('.')
|
479
565
|
parts[0..-(tld_length+2)]
|
@@ -486,18 +572,24 @@ module Merb
|
|
486
572
|
#
|
487
573
|
# ==== Returns
|
488
574
|
# String:: The full domain name without the port number.
|
575
|
+
#
|
576
|
+
# @api public
|
489
577
|
def domain(tld_length = 1)
|
490
578
|
host.split('.').last(1 + tld_length).join('.').sub(/:\d+$/,'')
|
491
579
|
end
|
492
|
-
|
580
|
+
|
493
581
|
# ==== Returns
|
494
582
|
# Value of If-None-Match request header.
|
583
|
+
#
|
584
|
+
# @api private
|
495
585
|
def if_none_match
|
496
586
|
@env[Merb::Const::HTTP_IF_NONE_MATCH]
|
497
587
|
end
|
498
|
-
|
588
|
+
|
499
589
|
# ==== Returns
|
500
590
|
# Value of If-Modified-Since request header.
|
591
|
+
#
|
592
|
+
# @api private
|
501
593
|
def if_modified_since
|
502
594
|
if time = @env[Merb::Const::HTTP_IF_MODIFIED_SINCE]
|
503
595
|
Time.rfc2822(time)
|
@@ -525,6 +617,8 @@ module Merb
|
|
525
617
|
# # => "search[page]=10&search[word]=ruby"
|
526
618
|
# params_to_query_string([ "ice-cream", "cake" ], "shopping_list")
|
527
619
|
# # => "shopping_list[]=ice-cream&shopping_list[]=cake"
|
620
|
+
#
|
621
|
+
# @api private
|
528
622
|
def params_to_query_string(value, prefix = nil)
|
529
623
|
case value
|
530
624
|
when Array
|
@@ -545,17 +639,21 @@ module Merb
|
|
545
639
|
#
|
546
640
|
# ==== returns
|
547
641
|
# String:: The escaped string.
|
642
|
+
#
|
643
|
+
# @api private
|
548
644
|
def escape(s)
|
549
645
|
s.to_s.gsub(/([^ a-zA-Z0-9_.-]+)/n) {
|
550
646
|
'%'+$1.unpack('H2'*$1.size).join('%').upcase
|
551
647
|
}.tr(' ', '+')
|
552
648
|
end
|
553
|
-
|
649
|
+
|
554
650
|
# ==== Parameter
|
555
651
|
# s<String>:: String to URL unescape.
|
556
652
|
#
|
557
653
|
# ==== returns
|
558
654
|
# String:: The unescaped string.
|
655
|
+
#
|
656
|
+
# @api private
|
559
657
|
def unescape(s)
|
560
658
|
s.tr('+', ' ').gsub(/((?:%[0-9a-fA-F]{2})+)/n){
|
561
659
|
[$1.delete('%')].pack('H*')
|
@@ -573,6 +671,8 @@ module Merb
|
|
573
671
|
# ==== Examples
|
574
672
|
# query_parse("bar=nik&post[body]=heya")
|
575
673
|
# # => { :bar => "nik", :post => { :body => "heya" } }
|
674
|
+
#
|
675
|
+
# @api private
|
576
676
|
def query_parse(query_string, delimiter = '&;', preserve_order = false)
|
577
677
|
query = preserve_order ? Dictionary.new : {}
|
578
678
|
for pair in (query_string || '').split(/[#{delimiter}] */n)
|
@@ -586,13 +686,13 @@ module Merb
|
|
586
686
|
end
|
587
687
|
preserve_order ? query : query.to_mash
|
588
688
|
end
|
589
|
-
|
689
|
+
|
590
690
|
NAME_REGEX = /Content-Disposition:.* name="?([^\";]*)"?/ni.freeze
|
591
691
|
CONTENT_TYPE_REGEX = /Content-Type: (.*)\r\n/ni.freeze
|
592
692
|
FILENAME_REGEX = /Content-Disposition:.* filename="?([^\";]*)"?/ni.freeze
|
593
693
|
CRLF = "\r\n".freeze
|
594
694
|
EOL = CRLF
|
595
|
-
|
695
|
+
|
596
696
|
# ==== Parameters
|
597
697
|
# request<IO>:: The raw request.
|
598
698
|
# boundary<String>:: The boundary string.
|
@@ -603,6 +703,8 @@ module Merb
|
|
603
703
|
#
|
604
704
|
# ==== Returns
|
605
705
|
# Hash:: The parsed request.
|
706
|
+
#
|
707
|
+
# @api private
|
606
708
|
def parse_multipart(request, boundary, content_length)
|
607
709
|
boundary = "--#{boundary}"
|
608
710
|
paramhsh = {}
|
@@ -633,19 +735,19 @@ module Merb
|
|
633
735
|
filename = head[FILENAME_REGEX, 1]
|
634
736
|
content_type = head[CONTENT_TYPE_REGEX, 1]
|
635
737
|
name = head[NAME_REGEX, 1]
|
636
|
-
|
738
|
+
|
637
739
|
if filename && !filename.empty?
|
638
740
|
body = Tempfile.new(:Merb)
|
639
741
|
body.binmode if defined? body.binmode
|
640
742
|
end
|
641
743
|
next
|
642
744
|
end
|
643
|
-
|
745
|
+
|
644
746
|
# Save the read body part.
|
645
747
|
if head && (boundary_size+4 < buf.size)
|
646
748
|
body << buf.slice!(0, buf.size - (boundary_size+4))
|
647
749
|
end
|
648
|
-
|
750
|
+
|
649
751
|
read_size = bufsize < content_length ? bufsize : content_length
|
650
752
|
if( read_size > 0 )
|
651
753
|
c = input.read(read_size)
|
@@ -654,15 +756,15 @@ module Merb
|
|
654
756
|
content_length -= c.size
|
655
757
|
end
|
656
758
|
end
|
657
|
-
|
759
|
+
|
658
760
|
# Save the rest.
|
659
761
|
if i = buf.index(rx)
|
660
762
|
body << buf.slice!(0, i)
|
661
763
|
buf.slice!(0, boundary_size+2)
|
662
|
-
|
764
|
+
|
663
765
|
content_length = -1 if $1 == "--"
|
664
766
|
end
|
665
|
-
|
767
|
+
|
666
768
|
if filename && !filename.empty?
|
667
769
|
body.rewind
|
668
770
|
data = {
|
@@ -679,7 +781,7 @@ module Merb
|
|
679
781
|
}
|
680
782
|
paramhsh
|
681
783
|
end
|
682
|
-
|
784
|
+
|
683
785
|
# Converts a query string snippet to a hash and adds it to existing
|
684
786
|
# parameters.
|
685
787
|
#
|
@@ -690,6 +792,8 @@ module Merb
|
|
690
792
|
#
|
691
793
|
# ==== Returns
|
692
794
|
# Hash:: Normalized parameters
|
795
|
+
#
|
796
|
+
# @api private
|
693
797
|
def normalize_params(parms, name, val=nil)
|
694
798
|
name =~ %r([\[\]]*([^\[\]]+)\]*)
|
695
799
|
key = $1 || ''
|
@@ -715,4 +819,4 @@ module Merb
|
|
715
819
|
end
|
716
820
|
end
|
717
821
|
end
|
718
|
-
end
|
822
|
+
end
|