thorero 0.9.4.4 → 0.9.4.5

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.
Files changed (298) hide show
  1. data/LICENSE +1 -1
  2. data/README +21 -0
  3. data/Rakefile +275 -108
  4. data/TODO +0 -0
  5. data/bin/merb +12 -0
  6. data/bin/merb-specs +5 -0
  7. data/docs/bootloading.dox +58 -0
  8. data/docs/documentation_standards +40 -0
  9. data/docs/merb-core-call-stack-diagram.mmap +0 -0
  10. data/docs/merb-core-call-stack-diagram.pdf +0 -0
  11. data/docs/merb-core-call-stack-diagram.png +0 -0
  12. data/docs/new_render_api +51 -0
  13. data/lib/merb-core.rb +603 -0
  14. data/lib/merb-core/autoload.rb +32 -0
  15. data/lib/merb-core/bootloader.rb +708 -0
  16. data/lib/merb-core/config.rb +303 -0
  17. data/lib/merb-core/constants.rb +43 -0
  18. data/lib/merb-core/controller/abstract_controller.rb +578 -0
  19. data/lib/merb-core/controller/exceptions.rb +302 -0
  20. data/lib/merb-core/controller/merb_controller.rb +256 -0
  21. data/lib/merb-core/controller/mime.rb +106 -0
  22. data/lib/merb-core/controller/mixins/authentication.rb +87 -0
  23. data/lib/merb-core/controller/mixins/controller.rb +290 -0
  24. data/lib/merb-core/controller/mixins/render.rb +481 -0
  25. data/lib/merb-core/controller/mixins/responder.rb +472 -0
  26. data/lib/merb-core/controller/template.rb +254 -0
  27. data/lib/merb-core/core_ext.rb +8 -0
  28. data/lib/merb-core/core_ext/kernel.rb +319 -0
  29. data/lib/merb-core/dispatch/cookies.rb +91 -0
  30. data/lib/merb-core/dispatch/dispatcher.rb +278 -0
  31. data/lib/merb-core/dispatch/exceptions.html.erb +303 -0
  32. data/lib/merb-core/dispatch/request.rb +603 -0
  33. data/lib/merb-core/dispatch/router.rb +179 -0
  34. data/lib/merb-core/dispatch/router/behavior.rb +867 -0
  35. data/lib/merb-core/dispatch/router/cached_proc.rb +52 -0
  36. data/lib/merb-core/dispatch/router/route.rb +321 -0
  37. data/lib/merb-core/dispatch/session.rb +78 -0
  38. data/lib/merb-core/dispatch/session/cookie.rb +168 -0
  39. data/lib/merb-core/dispatch/session/memcached.rb +184 -0
  40. data/lib/merb-core/dispatch/session/memory.rb +241 -0
  41. data/lib/merb-core/dispatch/worker.rb +28 -0
  42. data/lib/merb-core/gem_ext/erubis.rb +77 -0
  43. data/lib/{extlib → merb-core}/logger.rb +2 -2
  44. data/lib/merb-core/plugins.rb +59 -0
  45. data/lib/merb-core/rack.rb +21 -0
  46. data/lib/merb-core/rack/adapter.rb +44 -0
  47. data/lib/merb-core/rack/adapter/ebb.rb +25 -0
  48. data/lib/merb-core/rack/adapter/evented_mongrel.rb +26 -0
  49. data/lib/merb-core/rack/adapter/fcgi.rb +17 -0
  50. data/lib/merb-core/rack/adapter/irb.rb +118 -0
  51. data/lib/merb-core/rack/adapter/mongrel.rb +26 -0
  52. data/lib/merb-core/rack/adapter/runner.rb +28 -0
  53. data/lib/merb-core/rack/adapter/swiftiplied_mongrel.rb +26 -0
  54. data/lib/merb-core/rack/adapter/thin.rb +39 -0
  55. data/lib/merb-core/rack/adapter/thin_turbo.rb +24 -0
  56. data/lib/merb-core/rack/adapter/webrick.rb +36 -0
  57. data/lib/merb-core/rack/application.rb +18 -0
  58. data/lib/merb-core/rack/handler/mongrel.rb +97 -0
  59. data/lib/merb-core/rack/middleware.rb +26 -0
  60. data/lib/merb-core/rack/middleware/path_prefix.rb +31 -0
  61. data/lib/merb-core/rack/middleware/profiler.rb +19 -0
  62. data/lib/merb-core/rack/middleware/static.rb +45 -0
  63. data/lib/merb-core/server.rb +252 -0
  64. data/lib/merb-core/tasks/audit.rake +68 -0
  65. data/lib/merb-core/tasks/merb.rb +1 -0
  66. data/lib/merb-core/tasks/merb_rake_helper.rb +12 -0
  67. data/lib/merb-core/test.rb +11 -0
  68. data/lib/merb-core/test/helpers.rb +9 -0
  69. data/lib/merb-core/test/helpers/controller_helper.rb +8 -0
  70. data/lib/merb-core/test/helpers/multipart_request_helper.rb +175 -0
  71. data/lib/merb-core/test/helpers/request_helper.rb +344 -0
  72. data/lib/merb-core/test/helpers/route_helper.rb +33 -0
  73. data/lib/merb-core/test/helpers/view_helper.rb +121 -0
  74. data/lib/merb-core/test/matchers.rb +9 -0
  75. data/lib/merb-core/test/matchers/controller_matchers.rb +319 -0
  76. data/lib/merb-core/test/matchers/route_matchers.rb +136 -0
  77. data/lib/merb-core/test/matchers/view_matchers.rb +335 -0
  78. data/lib/merb-core/test/run_specs.rb +47 -0
  79. data/lib/merb-core/test/tasks/spectasks.rb +68 -0
  80. data/lib/merb-core/test/test_ext/hpricot.rb +32 -0
  81. data/lib/merb-core/test/test_ext/object.rb +14 -0
  82. data/lib/merb-core/test/test_ext/string.rb +14 -0
  83. data/lib/merb-core/vendor/facets.rb +2 -0
  84. data/lib/merb-core/vendor/facets/dictionary.rb +433 -0
  85. data/lib/merb-core/vendor/facets/inflect.rb +345 -0
  86. data/lib/merb-core/version.rb +11 -0
  87. data/spec/private/config/adapter_spec.rb +32 -0
  88. data/spec/private/config/config_spec.rb +202 -0
  89. data/spec/private/config/environment_spec.rb +13 -0
  90. data/spec/private/config/spec_helper.rb +1 -0
  91. data/spec/private/core_ext/kernel_spec.rb +169 -0
  92. data/spec/private/dispatch/bootloader_spec.rb +24 -0
  93. data/spec/private/dispatch/cookies_spec.rb +107 -0
  94. data/spec/private/dispatch/dispatch_spec.rb +35 -0
  95. data/spec/private/dispatch/fixture/app/controllers/application.rb +4 -0
  96. data/spec/private/dispatch/fixture/app/controllers/exceptions.rb +27 -0
  97. data/spec/private/dispatch/fixture/app/controllers/foo.rb +21 -0
  98. data/spec/private/dispatch/fixture/app/helpers/global_helpers.rb +8 -0
  99. data/spec/private/dispatch/fixture/app/views/exeptions/client_error.html.erb +37 -0
  100. data/spec/private/dispatch/fixture/app/views/exeptions/internal_server_error.html.erb +216 -0
  101. data/spec/private/dispatch/fixture/app/views/exeptions/not_acceptable.html.erb +38 -0
  102. data/spec/private/dispatch/fixture/app/views/exeptions/not_found.html.erb +40 -0
  103. data/spec/private/dispatch/fixture/app/views/foo/bar.html.erb +0 -0
  104. data/spec/private/dispatch/fixture/app/views/layout/application.html.erb +11 -0
  105. data/spec/private/dispatch/fixture/config/black_hole.rb +12 -0
  106. data/spec/private/dispatch/fixture/config/environments/development.rb +6 -0
  107. data/spec/private/dispatch/fixture/config/environments/production.rb +5 -0
  108. data/spec/private/dispatch/fixture/config/environments/test.rb +6 -0
  109. data/spec/private/dispatch/fixture/config/init.rb +45 -0
  110. data/spec/private/dispatch/fixture/config/rack.rb +11 -0
  111. data/spec/private/dispatch/fixture/config/router.rb +35 -0
  112. data/spec/private/dispatch/fixture/log/merb_test.log +1874 -0
  113. data/spec/private/dispatch/fixture/public/images/merb.jpg +0 -0
  114. data/spec/private/dispatch/fixture/public/merb.fcgi +4 -0
  115. data/spec/private/dispatch/fixture/public/stylesheets/master.css +119 -0
  116. data/spec/private/dispatch/route_params_spec.rb +24 -0
  117. data/spec/private/dispatch/session_mixin_spec.rb +47 -0
  118. data/spec/private/dispatch/spec_helper.rb +1 -0
  119. data/spec/private/plugins/plugin_spec.rb +166 -0
  120. data/spec/private/rack/application_spec.rb +49 -0
  121. data/spec/private/router/behavior_spec.rb +60 -0
  122. data/spec/private/router/fixture/log/merb_test.log +139 -0
  123. data/spec/private/router/route_spec.rb +414 -0
  124. data/spec/private/router/router_spec.rb +175 -0
  125. data/spec/private/vendor/facets/plural_spec.rb +564 -0
  126. data/spec/private/vendor/facets/singular_spec.rb +489 -0
  127. data/spec/public/DEFINITIONS +11 -0
  128. data/spec/public/abstract_controller/controllers/alt_views/layout/application.erb +1 -0
  129. data/spec/public/abstract_controller/controllers/alt_views/layout/merb/test/fixtures/abstract/render_string_controller_layout.erb +1 -0
  130. data/spec/public/abstract_controller/controllers/alt_views/layout/merb/test/fixtures/abstract/render_template_controller_layout.erb +1 -0
  131. data/spec/public/abstract_controller/controllers/alt_views/merb/test/fixtures/abstract/display_object_with_multiple_roots/index.erb +1 -0
  132. data/spec/public/abstract_controller/controllers/alt_views/merb/test/fixtures/abstract/display_object_with_multiple_roots/show.erb +1 -0
  133. data/spec/public/abstract_controller/controllers/alt_views/merb/test/fixtures/abstract/render_template_multiple_roots/index.erb +1 -0
  134. data/spec/public/abstract_controller/controllers/alt_views/partial/basic_partial_with_multiple_roots/_partial.erb +1 -0
  135. data/spec/public/abstract_controller/controllers/alt_views/render_template_multiple_roots_and_custom_location/index.erb +1 -0
  136. data/spec/public/abstract_controller/controllers/alt_views/render_template_multiple_roots_inherited/index.erb +1 -0
  137. data/spec/public/abstract_controller/controllers/cousins.rb +41 -0
  138. data/spec/public/abstract_controller/controllers/display.rb +54 -0
  139. data/spec/public/abstract_controller/controllers/filters.rb +193 -0
  140. data/spec/public/abstract_controller/controllers/helpers.rb +41 -0
  141. data/spec/public/abstract_controller/controllers/partial.rb +121 -0
  142. data/spec/public/abstract_controller/controllers/render.rb +113 -0
  143. data/spec/public/abstract_controller/controllers/views/helpers/capture/index.erb +1 -0
  144. data/spec/public/abstract_controller/controllers/views/helpers/capture_eq/index.erb +1 -0
  145. data/spec/public/abstract_controller/controllers/views/helpers/capture_with_args/index.erb +1 -0
  146. data/spec/public/abstract_controller/controllers/views/helpers/concat/index.erb +1 -0
  147. data/spec/public/abstract_controller/controllers/views/layout/alt.erb +1 -0
  148. data/spec/public/abstract_controller/controllers/views/layout/custom.erb +1 -0
  149. data/spec/public/abstract_controller/controllers/views/merb/test/fixtures/abstract/display_object/index.erb +1 -0
  150. data/spec/public/abstract_controller/controllers/views/merb/test/fixtures/abstract/display_object_with_action/new.erb +1 -0
  151. data/spec/public/abstract_controller/controllers/views/merb/test/fixtures/abstract/render_template/index.erb +1 -0
  152. data/spec/public/abstract_controller/controllers/views/merb/test/fixtures/abstract/render_template_app_layout/index.erb +0 -0
  153. data/spec/public/abstract_controller/controllers/views/merb/test/fixtures/abstract/render_template_custom_layout/index.erb +1 -0
  154. data/spec/public/abstract_controller/controllers/views/merb/test/fixtures/abstract/render_template_multiple_roots/index.erb +1 -0
  155. data/spec/public/abstract_controller/controllers/views/merb/test/fixtures/abstract/render_template_multiple_roots/show.erb +1 -0
  156. data/spec/public/abstract_controller/controllers/views/merb/test/fixtures/abstract/render_two_throw_contents/index.erb +1 -0
  157. data/spec/public/abstract_controller/controllers/views/partial/another_directory/_partial.erb +1 -0
  158. data/spec/public/abstract_controller/controllers/views/partial/basic_partial/_partial.erb +1 -0
  159. data/spec/public/abstract_controller/controllers/views/partial/basic_partial/index.erb +1 -0
  160. data/spec/public/abstract_controller/controllers/views/partial/basic_partial_with_multiple_roots/index.erb +1 -0
  161. data/spec/public/abstract_controller/controllers/views/partial/nested_partial/_first.erb +1 -0
  162. data/spec/public/abstract_controller/controllers/views/partial/nested_partial/_second.erb +1 -0
  163. data/spec/public/abstract_controller/controllers/views/partial/nested_partial/index.erb +1 -0
  164. data/spec/public/abstract_controller/controllers/views/partial/partial_in_another_directory/index.erb +1 -0
  165. data/spec/public/abstract_controller/controllers/views/partial/partial_with_both/_collection.erb +1 -0
  166. data/spec/public/abstract_controller/controllers/views/partial/partial_with_both/index.erb +1 -0
  167. data/spec/public/abstract_controller/controllers/views/partial/partial_with_collections/_collection.erb +1 -0
  168. data/spec/public/abstract_controller/controllers/views/partial/partial_with_collections/index.erb +1 -0
  169. data/spec/public/abstract_controller/controllers/views/partial/partial_with_collections_and_as/_collection.erb +1 -0
  170. data/spec/public/abstract_controller/controllers/views/partial/partial_with_collections_and_as/index.erb +1 -0
  171. data/spec/public/abstract_controller/controllers/views/partial/partial_with_collections_and_counter/_collection.erb +1 -0
  172. data/spec/public/abstract_controller/controllers/views/partial/partial_with_collections_and_counter/index.erb +1 -0
  173. data/spec/public/abstract_controller/controllers/views/partial/partial_with_locals/_variables.erb +1 -0
  174. data/spec/public/abstract_controller/controllers/views/partial/partial_with_locals/index.erb +1 -0
  175. data/spec/public/abstract_controller/controllers/views/partial/partial_with_with_and_locals/_both.erb +1 -0
  176. data/spec/public/abstract_controller/controllers/views/partial/partial_with_with_and_locals/index.erb +1 -0
  177. data/spec/public/abstract_controller/controllers/views/partial/with_absolute_partial/_partial.erb +1 -0
  178. data/spec/public/abstract_controller/controllers/views/partial/with_absolute_partial/index.erb +1 -0
  179. data/spec/public/abstract_controller/controllers/views/partial/with_as_partial/_with_partial.erb +1 -0
  180. data/spec/public/abstract_controller/controllers/views/partial/with_as_partial/index.erb +1 -0
  181. data/spec/public/abstract_controller/controllers/views/partial/with_nil_partial/_with_partial.erb +1 -0
  182. data/spec/public/abstract_controller/controllers/views/partial/with_nil_partial/index.erb +1 -0
  183. data/spec/public/abstract_controller/controllers/views/partial/with_partial/_with_partial.erb +1 -0
  184. data/spec/public/abstract_controller/controllers/views/partial/with_partial/index.erb +1 -0
  185. data/spec/public/abstract_controller/controllers/views/test_display/foo.html.erb +1 -0
  186. data/spec/public/abstract_controller/controllers/views/test_render/foo.html.erb +0 -0
  187. data/spec/public/abstract_controller/controllers/views/wonderful/index.erb +1 -0
  188. data/spec/public/abstract_controller/display_spec.rb +33 -0
  189. data/spec/public/abstract_controller/filter_spec.rb +106 -0
  190. data/spec/public/abstract_controller/helper_spec.rb +21 -0
  191. data/spec/public/abstract_controller/partial_spec.rb +61 -0
  192. data/spec/public/abstract_controller/render_spec.rb +90 -0
  193. data/spec/public/abstract_controller/spec_helper.rb +31 -0
  194. data/spec/public/boot_loader/boot_loader_spec.rb +33 -0
  195. data/spec/public/boot_loader/spec_helper.rb +1 -0
  196. data/spec/public/controller/authentication_spec.rb +103 -0
  197. data/spec/public/controller/base_spec.rb +36 -0
  198. data/spec/public/controller/controllers/authentication.rb +45 -0
  199. data/spec/public/controller/controllers/base.rb +36 -0
  200. data/spec/public/controller/controllers/display.rb +118 -0
  201. data/spec/public/controller/controllers/redirect.rb +30 -0
  202. data/spec/public/controller/controllers/responder.rb +93 -0
  203. data/spec/public/controller/controllers/url.rb +7 -0
  204. data/spec/public/controller/controllers/views/layout/custom.html.erb +1 -0
  205. data/spec/public/controller/controllers/views/layout/custom_arg.html.erb +1 -0
  206. data/spec/public/controller/controllers/views/layout/custom_arg.json.erb +1 -0
  207. data/spec/public/controller/controllers/views/merb/test/fixtures/controllers/class_and_local_provides/index.html.erb +1 -0
  208. data/spec/public/controller/controllers/views/merb/test/fixtures/controllers/class_and_local_provides/index.xml.erb +1 -0
  209. data/spec/public/controller/controllers/views/merb/test/fixtures/controllers/class_provides/index.html.erb +1 -0
  210. data/spec/public/controller/controllers/views/merb/test/fixtures/controllers/class_provides/index.xml.erb +1 -0
  211. data/spec/public/controller/controllers/views/merb/test/fixtures/controllers/display_with_template/index.html.erb +1 -0
  212. data/spec/public/controller/controllers/views/merb/test/fixtures/controllers/display_with_template/no_layout.html.erb +1 -0
  213. data/spec/public/controller/controllers/views/merb/test/fixtures/controllers/display_with_template_argument/index.html.erb +1 -0
  214. data/spec/public/controller/controllers/views/merb/test/fixtures/controllers/html_default/index.html.erb +1 -0
  215. data/spec/public/controller/controllers/views/merb/test/fixtures/controllers/layout/custom.html.erb +1 -0
  216. data/spec/public/controller/controllers/views/merb/test/fixtures/controllers/local_provides/index.html.erb +1 -0
  217. data/spec/public/controller/controllers/views/merb/test/fixtures/controllers/local_provides/index.xml.erb +1 -0
  218. data/spec/public/controller/controllers/views/merb/test/fixtures/controllers/multi_provides/index.html.erb +1 -0
  219. data/spec/public/controller/controllers/views/merb/test/fixtures/controllers/multi_provides/index.js.erb +1 -0
  220. data/spec/public/controller/display_spec.rb +84 -0
  221. data/spec/public/controller/redirect_spec.rb +27 -0
  222. data/spec/public/controller/responder_spec.rb +163 -0
  223. data/spec/public/controller/spec_helper.rb +11 -0
  224. data/spec/public/controller/url_spec.rb +180 -0
  225. data/spec/public/core/merb_core_spec.rb +45 -0
  226. data/spec/public/core_ext/class_spec.rb +91 -0
  227. data/spec/public/core_ext/fixtures/core_ext_dependency.rb +2 -0
  228. data/spec/public/core_ext/kernel_spec.rb +9 -0
  229. data/spec/public/core_ext/spec_helper.rb +1 -0
  230. data/spec/public/directory_structure/directory/app/controllers/application.rb +3 -0
  231. data/spec/public/directory_structure/directory/app/controllers/base.rb +13 -0
  232. data/spec/public/directory_structure/directory/app/controllers/custom.rb +19 -0
  233. data/spec/public/directory_structure/directory/app/views/base/template.html.erb +1 -0
  234. data/spec/public/directory_structure/directory/app/views/wonderful/template.erb +1 -0
  235. data/spec/public/directory_structure/directory/config/router.rb +3 -0
  236. data/spec/public/directory_structure/directory/log/merb_test.log +562 -0
  237. data/spec/public/directory_structure/directory_spec.rb +44 -0
  238. data/spec/public/logger/logger_spec.rb +181 -0
  239. data/spec/public/logger/spec_helper.rb +1 -0
  240. data/spec/public/reloading/directory/app/controllers/application.rb +3 -0
  241. data/spec/public/reloading/directory/app/controllers/reload.rb +6 -0
  242. data/spec/public/reloading/directory/config/init.rb +2 -0
  243. data/spec/public/reloading/directory/log/merb_test.log +138 -0
  244. data/spec/public/reloading/reload_spec.rb +103 -0
  245. data/spec/public/request/multipart_spec.rb +41 -0
  246. data/spec/public/request/request_spec.rb +228 -0
  247. data/spec/public/router/default_spec.rb +21 -0
  248. data/spec/public/router/deferred_spec.rb +22 -0
  249. data/spec/public/router/fixation_spec.rb +27 -0
  250. data/spec/public/router/fixture/log/merb_test.log +1556 -0
  251. data/spec/public/router/namespace_spec.rb +113 -0
  252. data/spec/public/router/nested_matches_spec.rb +97 -0
  253. data/spec/public/router/nested_resources_spec.rb +41 -0
  254. data/spec/public/router/resource_spec.rb +37 -0
  255. data/spec/public/router/resources_spec.rb +82 -0
  256. data/spec/public/router/spec_helper.rb +90 -0
  257. data/spec/public/router/special_spec.rb +61 -0
  258. data/spec/public/router/string_spec.rb +61 -0
  259. data/spec/public/template/template_spec.rb +104 -0
  260. data/spec/public/template/templates/error.html.erb +2 -0
  261. data/spec/public/template/templates/template.html.erb +1 -0
  262. data/spec/public/template/templates/template.html.myt +1 -0
  263. data/spec/public/test/controller_matchers_spec.rb +402 -0
  264. data/spec/public/test/controllers/controller_assertion_mock.rb +7 -0
  265. data/spec/public/test/controllers/dispatch_controller.rb +11 -0
  266. data/spec/public/test/controllers/spec_helper_controller.rb +38 -0
  267. data/spec/public/test/multipart_request_helper_spec.rb +159 -0
  268. data/spec/public/test/multipart_upload_text_file.txt +1 -0
  269. data/spec/public/test/request_helper_spec.rb +221 -0
  270. data/spec/public/test/route_helper_spec.rb +71 -0
  271. data/spec/public/test/route_matchers_spec.rb +162 -0
  272. data/spec/public/test/view_helper_spec.rb +96 -0
  273. data/spec/public/test/view_matchers_spec.rb +183 -0
  274. data/spec/spec_helper.rb +68 -0
  275. metadata +493 -41
  276. data/README.txt +0 -3
  277. data/lib/extlib.rb +0 -32
  278. data/lib/extlib/assertions.rb +0 -8
  279. data/lib/extlib/blank.rb +0 -42
  280. data/lib/extlib/class.rb +0 -175
  281. data/lib/extlib/hash.rb +0 -410
  282. data/lib/extlib/hook.rb +0 -366
  283. data/lib/extlib/inflection.rb +0 -141
  284. data/lib/extlib/lazy_array.rb +0 -106
  285. data/lib/extlib/mash.rb +0 -143
  286. data/lib/extlib/module.rb +0 -37
  287. data/lib/extlib/object.rb +0 -165
  288. data/lib/extlib/object_space.rb +0 -13
  289. data/lib/extlib/pathname.rb +0 -5
  290. data/lib/extlib/pooling.rb +0 -233
  291. data/lib/extlib/rubygems.rb +0 -38
  292. data/lib/extlib/simple_set.rb +0 -39
  293. data/lib/extlib/string.rb +0 -132
  294. data/lib/extlib/struct.rb +0 -8
  295. data/lib/extlib/tasks/release.rb +0 -9
  296. data/lib/extlib/time.rb +0 -12
  297. data/lib/extlib/version.rb +0 -3
  298. data/lib/extlib/virtual_file.rb +0 -10
@@ -0,0 +1,603 @@
1
+ require 'tempfile'
2
+
3
+ module Merb
4
+
5
+ class Request
6
+ # def env def session def route_params
7
+ attr_accessor :env, :session, :route_params
8
+
9
+ # by setting these to false, auto-parsing is disabled; this way you can
10
+ # do your own parsing instead
11
+ cattr_accessor :parse_multipart_params, :parse_json_params,
12
+ :parse_xml_params
13
+ self.parse_multipart_params = true
14
+ self.parse_json_params = true
15
+ self.parse_xml_params = true
16
+
17
+ # Flash, and some older browsers can't use arbitrary
18
+ # request methods -- i.e., are limited to GET/POST.
19
+ # These user-agents can make POST requests in combination
20
+ # with these overrides to participate fully in REST
21
+ # Common examples are _method or fb_sig_request_method
22
+ # in the params, or an X-HTTP-Method-Override header
23
+ cattr_accessor :http_method_overrides
24
+ self.http_method_overrides = []
25
+
26
+ # Initial the request object.
27
+ #
28
+ # ==== Parameters
29
+ # http_request<~params:~[], ~body:IO>::
30
+ # An object like an HTTP Request.
31
+ def initialize(rack_env)
32
+ @env = rack_env
33
+ @body = rack_env['rack.input']
34
+ @route_params = {}
35
+ end
36
+
37
+ METHODS = %w{get post put delete head options}
38
+
39
+ # ==== Returns
40
+ # Symbol:: The name of the request method, e.g. :get.
41
+ #
42
+ # ==== Notes
43
+ # If the method is post, then the blocks specified in
44
+ # http_method_overrides will be checked for the masquerading method.
45
+ # The block will get the controller yielded to it. The first matching workaround wins.
46
+ # To disable this behavior, set http_method_overrides = []
47
+ def method
48
+ @method ||= begin
49
+ request_method = @env['REQUEST_METHOD'].downcase.to_sym
50
+ case request_method
51
+ when :get, :head, :put, :delete, :options
52
+ request_method
53
+ when :post
54
+ m = nil
55
+ self.class.http_method_overrides.each do |o|
56
+ m ||= o.call(self); break if m
57
+ end
58
+ m.downcase! if m
59
+ METHODS.include?(m) ? m.to_sym : :post
60
+ else
61
+ raise "Unknown REQUEST_METHOD: #{@env['REQUEST_METHOD']}"
62
+ end
63
+ end
64
+ end
65
+
66
+ # create predicate methods for querying the REQUEST_METHOD
67
+ # get? post? head? put? etc
68
+ METHODS.each do |m|
69
+ class_eval "def #{m}?() method == :#{m} end"
70
+ end
71
+
72
+ private
73
+
74
+ # ==== Returns
75
+ # Hash:: Parameters passed from the URL like ?blah=hello.
76
+ def query_params
77
+ @query_params ||= self.class.query_parse(query_string || '')
78
+ end
79
+
80
+ # Parameters passed in the body of the request. Ajax calls from
81
+ # prototype.js and other libraries pass content this way.
82
+ #
83
+ # ==== Returns
84
+ # Hash:: The parameters passed in the body.
85
+ def body_params
86
+ @body_params ||= begin
87
+ if content_type && content_type.match(Merb::Const::FORM_URL_ENCODED_REGEXP) # or content_type.nil?
88
+ self.class.query_parse(raw_post)
89
+ end
90
+ end
91
+ end
92
+
93
+ # ==== Returns
94
+ # Hash::
95
+ # The parameters gathered from the query string and the request body,
96
+ # with parameters in the body taking precedence.
97
+ def body_and_query_params
98
+ # ^-- FIXME a better name for this method
99
+ @body_and_query_params ||= begin
100
+ h = query_params
101
+ h.merge!(body_params) if body_params
102
+ h.to_mash
103
+ end
104
+ end
105
+
106
+ # ==== Raises
107
+ # ControllerExceptions::MultiPartParseError::
108
+ # Unable to parse the multipart form data.
109
+ #
110
+ # ==== Returns
111
+ # Hash:: The parsed multipart parameters.
112
+ def multipart_params
113
+ @multipart_params ||=
114
+ begin
115
+ # if the content-type is multipart
116
+ # parse the multipart. Otherwise return {}
117
+ if (Merb::Const::MULTIPART_REGEXP =~ content_type)
118
+ self.class.parse_multipart(@body, $1, content_length)
119
+ else
120
+ {}
121
+ end
122
+ rescue ControllerExceptions::MultiPartParseError => e
123
+ @multipart_params = {}
124
+ raise e
125
+ end
126
+ end
127
+
128
+ # ==== Returns
129
+ # Hash:: Parameters from body if this is a JSON request.
130
+ #
131
+ # ==== Notes
132
+ # If the JSON object parses as a Hash, it will be merged with the
133
+ # parameters hash. If it parses to anything else (such as an Array, or
134
+ # if it inflates to an Object) it will be accessible via the inflated_object
135
+ # parameter.
136
+ def json_params
137
+ @json_params ||= begin
138
+ if Merb::Const::JSON_MIME_TYPE_REGEXP.match(content_type)
139
+ jobj = JSON.parse(raw_post) rescue Mash.new
140
+ jobj.kind_of?(Hash) ? jobj : { :inflated_object => jobj }
141
+ end
142
+ end
143
+ end
144
+
145
+ # ==== Returns
146
+ # Hash:: Parameters from body if this is an XML request.
147
+ def xml_params
148
+ @xml_params ||= begin
149
+ if Merb::Const::XML_MIME_TYPE_REGEXP.match(content_type)
150
+ Hash.from_xml(raw_post) rescue Mash.new
151
+ end
152
+ end
153
+ end
154
+
155
+ public
156
+ # ==== Returns
157
+ # Hash:: All request parameters.
158
+ #
159
+ # ==== Notes
160
+ # The order of precedence for the params is XML, JSON, multipart, body and
161
+ # request string.
162
+ def params
163
+ @params ||= begin
164
+ h = body_and_query_params.merge(route_params)
165
+ h.merge!(multipart_params) if self.class.parse_multipart_params && multipart_params
166
+ h.merge!(json_params) if self.class.parse_json_params && json_params
167
+ h.merge!(xml_params) if self.class.parse_xml_params && xml_params
168
+ h
169
+ end
170
+ end
171
+
172
+ def message
173
+ return {} unless params[:_message]
174
+ begin
175
+ Marshal.load(Merb::Request.unescape(params[:_message]).unpack("m").first)
176
+ rescue ArgumentError
177
+ {}
178
+ end
179
+ end
180
+
181
+ # Resets the params to a nil value.
182
+ def reset_params!
183
+ @params = nil
184
+ end
185
+
186
+ # ==== Returns
187
+ # Hash:: The cookies for this request.
188
+ def cookies
189
+ @cookies ||= self.class.query_parse(@env[Merb::Const::HTTP_COOKIE], ';,')
190
+ end
191
+
192
+ # ==== Returns
193
+ # String:: The raw post.
194
+ def raw_post
195
+ @body.rewind if @body.respond_to?(:rewind)
196
+ @raw_post ||= @body.read
197
+ end
198
+
199
+ # ==== Returns
200
+ # Boolean:: If the request is an XML HTTP request.
201
+ def xml_http_request?
202
+ not /XMLHttpRequest/i.match(@env['HTTP_X_REQUESTED_WITH']).nil?
203
+ end
204
+ alias xhr? :xml_http_request?
205
+ alias ajax? :xml_http_request?
206
+
207
+ # ==== Returns
208
+ # String:: The remote IP address.
209
+ def remote_ip
210
+ return @env['HTTP_CLIENT_IP'] if @env.include?('HTTP_CLIENT_IP')
211
+
212
+ if @env.include?(Merb::Const::HTTP_X_FORWARDED_FOR) then
213
+ remote_ips = @env[Merb::Const::HTTP_X_FORWARDED_FOR].split(',').reject do |ip|
214
+ ip =~ /^unknown$|^(127|10|172\.16|192\.168)\./i
215
+ end
216
+
217
+ return remote_ips.first.strip unless remote_ips.empty?
218
+ end
219
+
220
+ return @env[Merb::Const::REMOTE_ADDR]
221
+ end
222
+
223
+ # ==== Returns
224
+ # String::
225
+ # The protocol, i.e. either "https://" or "http://" depending on the
226
+ # HTTPS header.
227
+ def protocol
228
+ ssl? ? 'https://' : 'http://'
229
+ end
230
+
231
+ # ==== Returns
232
+ # Boolean::: True if the request is an SSL request.
233
+ def ssl?
234
+ @env['HTTPS'] == 'on' || @env['HTTP_X_FORWARDED_PROTO'] == 'https'
235
+ end
236
+
237
+ # ==== Returns
238
+ # String:: The HTTP referer.
239
+ def referer
240
+ @env['HTTP_REFERER']
241
+ end
242
+
243
+ # ==== Returns
244
+ # String:: The full URI, including protocol and host
245
+ def full_uri
246
+ protocol + host + uri
247
+ end
248
+
249
+ # ==== Returns
250
+ # String:: The request URI.
251
+ def uri
252
+ @env['REQUEST_PATH'] || @env['REQUEST_URI']
253
+ end
254
+
255
+ # ==== Returns
256
+ # String:: The HTTP user agent.
257
+ def user_agent
258
+ @env['HTTP_USER_AGENT']
259
+ end
260
+
261
+ # ==== Returns
262
+ # String:: The server name.
263
+ def server_name
264
+ @env['SERVER_NAME']
265
+ end
266
+
267
+ # ==== Returns
268
+ # String:: The accepted encodings.
269
+ def accept_encoding
270
+ @env['HTTP_ACCEPT_ENCODING']
271
+ end
272
+
273
+ # ==== Returns
274
+ # String:: The script name.
275
+ def script_name
276
+ @env['SCRIPT_NAME']
277
+ end
278
+
279
+ # ==== Returns
280
+ # String:: HTTP cache control.
281
+ def cache_control
282
+ @env['HTTP_CACHE_CONTROL']
283
+ end
284
+
285
+ # ==== Returns
286
+ # String:: The accepted language.
287
+ def accept_language
288
+ @env['HTTP_ACCEPT_LANGUAGE']
289
+ end
290
+
291
+ # ==== Returns
292
+ # String:: The server software.
293
+ def server_software
294
+ @env['SERVER_SOFTWARE']
295
+ end
296
+
297
+ # ==== Returns
298
+ # String:: Value of HTTP_KEEP_ALIVE.
299
+ def keep_alive
300
+ @env['HTTP_KEEP_ALIVE']
301
+ end
302
+
303
+ # ==== Returns
304
+ # String:: The accepted character sets.
305
+ def accept_charset
306
+ @env['HTTP_ACCEPT_CHARSET']
307
+ end
308
+
309
+ # ==== Returns
310
+ # String:: The HTTP version
311
+ def version
312
+ @env['HTTP_VERSION']
313
+ end
314
+
315
+ # ==== Returns
316
+ # String:: The gateway.
317
+ def gateway
318
+ @env['GATEWAY_INTERFACE']
319
+ end
320
+
321
+ # ==== Returns
322
+ # String:: The accepted response types. Defaults to "*/*".
323
+ def accept
324
+ @env['HTTP_ACCEPT'].blank? ? "*/*" : @env['HTTP_ACCEPT']
325
+ end
326
+
327
+ # ==== Returns
328
+ # String:: The HTTP connection.
329
+ def connection
330
+ @env['HTTP_CONNECTION']
331
+ end
332
+
333
+ # ==== Returns
334
+ # String:: The query string.
335
+ def query_string
336
+ @env['QUERY_STRING']
337
+ end
338
+
339
+ # ==== Returns
340
+ # String:: The request content type.
341
+ def content_type
342
+ @env['CONTENT_TYPE']
343
+ end
344
+
345
+ # ==== Returns
346
+ # Fixnum:: The request content length.
347
+ def content_length
348
+ @content_length ||= @env[Merb::Const::CONTENT_LENGTH].to_i
349
+ end
350
+
351
+ # ==== Returns
352
+ # String::
353
+ # The URI without the query string. Strips trailing "/" and reduces
354
+ # duplicate "/" to a single "/".
355
+ def path
356
+ path = (uri.empty? ? '/' : uri.split('?').first).squeeze("/")
357
+ path = path[0..-2] if (path[-1] == ?/) && path.size > 1
358
+ path
359
+ end
360
+
361
+ # ==== Returns
362
+ # String:: The path info.
363
+ def path_info
364
+ @path_info ||= self.class.unescape(@env['PATH_INFO'])
365
+ end
366
+
367
+ # ==== Returns
368
+ # Fixnum:: The server port.
369
+ def port
370
+ @env['SERVER_PORT'].to_i
371
+ end
372
+
373
+ # ==== Returns
374
+ # String:: The full hostname including the port.
375
+ def host
376
+ @env['HTTP_X_FORWARDED_HOST'] || @env['HTTP_HOST']
377
+ end
378
+
379
+ # ==== Parameters
380
+ # tld_length<Fixnum>::
381
+ # Number of domains levels to inlclude in the top level domain. Defaults
382
+ # to 1.
383
+ #
384
+ # ==== Returns
385
+ # Array:: All the subdomain parts of the host.
386
+ def subdomains(tld_length = 1)
387
+ parts = host.split('.')
388
+ parts[0..-(tld_length+2)]
389
+ end
390
+
391
+ # ==== Parameters
392
+ # tld_length<Fixnum>::
393
+ # Number of domains levels to inlclude in the top level domain. Defaults
394
+ # to 1.
395
+ #
396
+ # ==== Returns
397
+ # String:: The full domain name without the port number.
398
+ def domain(tld_length = 1)
399
+ host.split('.').last(1 + tld_length).join('.').sub(/:\d+$/,'')
400
+ end
401
+
402
+ class << self
403
+
404
+ # ==== Parameters
405
+ # value<Array, Hash, Dictionary ~to_s>:: The value for the query string.
406
+ # prefix<~to_s>:: The prefix to add to the query string keys.
407
+ #
408
+ # ==== Returns
409
+ # String:: The query string.
410
+ #
411
+ # ==== Alternatives
412
+ # If the value is a string, the prefix will be used as the key.
413
+ #
414
+ # ==== Examples
415
+ # params_to_query_string(10, "page")
416
+ # # => "page=10"
417
+ # params_to_query_string({ :page => 10, :word => "ruby" })
418
+ # # => "page=10&word=ruby"
419
+ # params_to_query_string({ :page => 10, :word => "ruby" }, "search")
420
+ # # => "search[page]=10&search[word]=ruby"
421
+ # params_to_query_string([ "ice-cream", "cake" ], "shopping_list")
422
+ # # => "shopping_list[]=ice-cream&shopping_list[]=cake"
423
+ def params_to_query_string(value, prefix = nil)
424
+ case value
425
+ when Array
426
+ value.map { |v|
427
+ params_to_query_string(v, "#{prefix}[]")
428
+ } * "&"
429
+ when Hash, Dictionary
430
+ value.map { |k, v|
431
+ params_to_query_string(v, prefix ? "#{prefix}[#{Merb::Request.escape(k)}]" : Merb::Request.escape(k))
432
+ } * "&"
433
+ else
434
+ "#{prefix}=#{Merb::Request.escape(value)}"
435
+ end
436
+ end
437
+
438
+ # ==== Parameters
439
+ # s<String>:: String to URL escape.
440
+ #
441
+ # ==== returns
442
+ # String:: The escaped string.
443
+ def escape(s)
444
+ s.to_s.gsub(/([^ a-zA-Z0-9_.-]+)/n) {
445
+ '%'+$1.unpack('H2'*$1.size).join('%').upcase
446
+ }.tr(' ', '+')
447
+ end
448
+
449
+ # ==== Parameter
450
+ # s<String>:: String to URL unescape.
451
+ #
452
+ # ==== returns
453
+ # String:: The unescaped string.
454
+ def unescape(s)
455
+ s.tr('+', ' ').gsub(/((?:%[0-9a-fA-F]{2})+)/n){
456
+ [$1.delete('%')].pack('H*')
457
+ }
458
+ end
459
+
460
+ # ==== Parameters
461
+ # qs<String>:: The query string.
462
+ # d<String>:: The query string divider. Defaults to "&".
463
+ # preserve_order<Boolean>:: Preserve order of args. Defaults to false.
464
+ #
465
+ # ==== Returns
466
+ # Mash:: The parsed query string (Dictionary if preserve_order is set).
467
+ #
468
+ # ==== Examples
469
+ # query_parse("bar=nik&post[body]=heya")
470
+ # # => { :bar => "nik", :post => { :body => "heya" } }
471
+ def query_parse(qs, d = '&;', preserve_order = false)
472
+ qh = preserve_order ? Dictionary.new : {}
473
+ (qs||'').split(/[#{d}] */n).inject(qh) { |h,p|
474
+ key, value = unescape(p).split('=',2)
475
+ normalize_params(h, key, value)
476
+ }
477
+ preserve_order ? qh : qh.to_mash
478
+ end
479
+
480
+ NAME_REGEX = /Content-Disposition:.* name="?([^\";]*)"?/ni.freeze
481
+ CONTENT_TYPE_REGEX = /Content-Type: (.*)\r\n/ni.freeze
482
+ FILENAME_REGEX = /Content-Disposition:.* filename="?([^\";]*)"?/ni.freeze
483
+ CRLF = "\r\n".freeze
484
+ EOL = CRLF
485
+
486
+ # ==== Parameters
487
+ # request<IO>:: The raw request.
488
+ # boundary<String>:: The boundary string.
489
+ # content_length<Fixnum>:: The length of the content.
490
+ #
491
+ # ==== Raises
492
+ # ControllerExceptions::MultiPartParseError:: Failed to parse request.
493
+ #
494
+ # ==== Returns
495
+ # Hash:: The parsed request.
496
+ def parse_multipart(request, boundary, content_length)
497
+ boundary = "--#{boundary}"
498
+ paramhsh = {}
499
+ buf = ""
500
+ input = request
501
+ input.binmode if defined? input.binmode
502
+ boundary_size = boundary.size + EOL.size
503
+ bufsize = 16384
504
+ content_length -= boundary_size
505
+ status = input.read(boundary_size)
506
+ return {} if status == nil || status.empty?
507
+ raise ControllerExceptions::MultiPartParseError, "bad content body:\n'#{status}' should == '#{boundary + EOL}'" unless status == boundary + EOL
508
+ rx = /(?:#{EOL})?#{Regexp.quote(boundary,'n')}(#{EOL}|--)/
509
+ loop {
510
+ head = nil
511
+ body = ''
512
+ filename = content_type = name = nil
513
+ read_size = 0
514
+ until head && buf =~ rx
515
+ i = buf.index("\r\n\r\n")
516
+ if( i == nil && read_size == 0 && content_length == 0 )
517
+ content_length = -1
518
+ break
519
+ end
520
+ if !head && i
521
+ head = buf.slice!(0, i+2) # First \r\n
522
+ buf.slice!(0, 2) # Second \r\n
523
+ filename = head[FILENAME_REGEX, 1]
524
+ content_type = head[CONTENT_TYPE_REGEX, 1]
525
+ name = head[NAME_REGEX, 1]
526
+
527
+ if filename && !filename.empty?
528
+ body = Tempfile.new(:Merb)
529
+ body.binmode if defined? body.binmode
530
+ end
531
+ next
532
+ end
533
+
534
+ # Save the read body part.
535
+ if head && (boundary_size+4 < buf.size)
536
+ body << buf.slice!(0, buf.size - (boundary_size+4))
537
+ end
538
+
539
+ read_size = bufsize < content_length ? bufsize : content_length
540
+ if( read_size > 0 )
541
+ c = input.read(read_size)
542
+ raise ControllerExceptions::MultiPartParseError, "bad content body" if c.nil? || c.empty?
543
+ buf << c
544
+ content_length -= c.size
545
+ end
546
+ end
547
+
548
+ # Save the rest.
549
+ if i = buf.index(rx)
550
+ body << buf.slice!(0, i)
551
+ buf.slice!(0, boundary_size+2)
552
+
553
+ content_length = -1 if $1 == "--"
554
+ end
555
+
556
+ if filename && !filename.empty?
557
+ body.rewind
558
+ data = {
559
+ :filename => File.basename(filename),
560
+ :content_type => content_type,
561
+ :tempfile => body,
562
+ :size => File.size(body.path)
563
+ }
564
+ else
565
+ data = body
566
+ end
567
+ paramhsh = normalize_params(paramhsh,name,data)
568
+ break if buf.empty? || content_length == -1
569
+ }
570
+ paramhsh
571
+ end
572
+
573
+ # Converts a query string snippet to a hash and adds it to existing
574
+ # parameters.
575
+ #
576
+ # ==== Parameters
577
+ # parms<Hash>:: Parameters to add the normalized parameters to.
578
+ # name<String>:: The key of the parameter to normalize.
579
+ # val<String>:: The value of the parameter.
580
+ #
581
+ # ==== Returns
582
+ # Hash:: Normalized parameters
583
+ def normalize_params(parms, name, val=nil)
584
+ name =~ %r([\[\]]*([^\[\]]+)\]*)
585
+ key = $1 || ''
586
+ after = $' || ''
587
+
588
+ if after == ""
589
+ parms[key] = val
590
+ elsif after == "[]"
591
+ (parms[key] ||= []) << val
592
+ elsif after =~ %r(^\[\])
593
+ parms[key] ||= []
594
+ parms[key] << normalize_params({}, after, val)
595
+ else
596
+ parms[key] ||= {}
597
+ parms[key] = normalize_params(parms[key], after, val)
598
+ end
599
+ parms
600
+ end
601
+ end
602
+ end
603
+ end