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.
Files changed (57) hide show
  1. data/CONTRIBUTORS +33 -0
  2. data/README +7 -3
  3. data/Rakefile +3 -3
  4. data/lib/merb-core.rb +165 -94
  5. data/lib/merb-core/bootloader.rb +469 -100
  6. data/lib/merb-core/config.rb +79 -3
  7. data/lib/merb-core/constants.rb +24 -2
  8. data/lib/merb-core/controller/abstract_controller.rb +172 -67
  9. data/lib/merb-core/controller/exceptions.rb +50 -6
  10. data/lib/merb-core/controller/merb_controller.rb +215 -108
  11. data/lib/merb-core/controller/mime.rb +36 -12
  12. data/lib/merb-core/controller/mixins/authentication.rb +52 -7
  13. data/lib/merb-core/controller/mixins/conditional_get.rb +14 -0
  14. data/lib/merb-core/controller/mixins/controller.rb +90 -58
  15. data/lib/merb-core/controller/mixins/render.rb +34 -10
  16. data/lib/merb-core/controller/mixins/responder.rb +40 -16
  17. data/lib/merb-core/controller/template.rb +37 -16
  18. data/lib/merb-core/core_ext/hash.rb +9 -0
  19. data/lib/merb-core/core_ext/kernel.rb +92 -41
  20. data/lib/merb-core/dispatch/dispatcher.rb +29 -45
  21. data/lib/merb-core/dispatch/request.rb +186 -82
  22. data/lib/merb-core/dispatch/router.rb +141 -53
  23. data/lib/merb-core/dispatch/router/behavior.rb +296 -139
  24. data/lib/merb-core/dispatch/router/resources.rb +51 -19
  25. data/lib/merb-core/dispatch/router/route.rb +76 -23
  26. data/lib/merb-core/dispatch/session.rb +80 -36
  27. data/lib/merb-core/dispatch/session/container.rb +31 -15
  28. data/lib/merb-core/dispatch/session/cookie.rb +51 -22
  29. data/lib/merb-core/dispatch/session/memcached.rb +10 -6
  30. data/lib/merb-core/dispatch/session/memory.rb +17 -5
  31. data/lib/merb-core/dispatch/session/store_container.rb +21 -9
  32. data/lib/merb-core/dispatch/worker.rb +16 -2
  33. data/lib/merb-core/gem_ext/erubis.rb +4 -0
  34. data/lib/merb-core/plugins.rb +13 -0
  35. data/lib/merb-core/rack.rb +1 -0
  36. data/lib/merb-core/rack/adapter.rb +1 -0
  37. data/lib/merb-core/rack/adapter/abstract.rb +95 -17
  38. data/lib/merb-core/rack/adapter/irb.rb +50 -5
  39. data/lib/merb-core/rack/application.rb +27 -5
  40. data/lib/merb-core/rack/handler/mongrel.rb +6 -6
  41. data/lib/merb-core/rack/helpers.rb +33 -0
  42. data/lib/merb-core/rack/middleware/conditional_get.rb +1 -1
  43. data/lib/merb-core/rack/middleware/path_prefix.rb +3 -3
  44. data/lib/merb-core/rack/middleware/static.rb +11 -7
  45. data/lib/merb-core/server.rb +134 -69
  46. data/lib/merb-core/tasks/gem_management.rb +153 -80
  47. data/lib/merb-core/tasks/merb_rake_helper.rb +12 -4
  48. data/lib/merb-core/tasks/stats.rake +1 -1
  49. data/lib/merb-core/test/helpers/mock_request_helper.rb +29 -22
  50. data/lib/merb-core/test/helpers/request_helper.rb +1 -1
  51. data/lib/merb-core/test/helpers/route_helper.rb +50 -4
  52. data/lib/merb-core/test/matchers/request_matchers.rb +2 -36
  53. data/lib/merb-core/test/matchers/view_matchers.rb +32 -22
  54. data/lib/merb-core/test/run_specs.rb +6 -5
  55. data/lib/merb-core/test/test_ext/rspec.rb +6 -19
  56. data/lib/merb-core/version.rb +1 -1
  57. 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
- # <Symbol>:: The name of the request method, e.g. :get.
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
- # <String>:: redirect url of route matched this request
156
- def redirect_url
157
- @route_params[:url] if redirects?
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
- # Returns true if matched route does immediate redirection.
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
- # <Boolean>:: if matched route does immediate redirection.
164
- def redirects?
165
- @redirects
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