merb-core 0.9.8 → 0.9.9
Sign up to get free protection for your applications and to get access to all the features.
- 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
|