logstash-output-scalyr 0.1.10.beta → 0.1.11.beta

Sign up to get free protection for your applications and to get access to all the features.
Files changed (317) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +4 -0
  3. data/Gemfile +4 -0
  4. data/README.md +2 -2
  5. data/lib/logstash/outputs/scalyr.rb +94 -73
  6. data/lib/scalyr/common/client.rb +3 -1
  7. data/lib/scalyr/constants.rb +2 -0
  8. data/logstash-output-scalyr.gemspec +1 -1
  9. data/spec/logstash/outputs/scalyr_integration_spec.rb +119 -8
  10. data/spec/logstash/outputs/scalyr_spec.rb +9 -6
  11. data/vendor/bundle/jruby/2.5.0/cache/addressable-2.7.0.gem +0 -0
  12. data/vendor/bundle/jruby/2.5.0/cache/crack-0.4.5.gem +0 -0
  13. data/vendor/bundle/jruby/2.5.0/cache/hashdiff-1.0.1.gem +0 -0
  14. data/vendor/bundle/jruby/2.5.0/cache/public_suffix-4.0.6.gem +0 -0
  15. data/vendor/bundle/jruby/2.5.0/cache/rexml-3.2.5.gem +0 -0
  16. data/vendor/bundle/jruby/2.5.0/cache/webmock-3.13.0.gem +0 -0
  17. data/vendor/bundle/jruby/2.5.0/gems/addressable-2.7.0/CHANGELOG.md +235 -0
  18. data/vendor/bundle/jruby/2.5.0/gems/addressable-2.7.0/Gemfile +32 -0
  19. data/vendor/bundle/jruby/2.5.0/gems/addressable-2.7.0/LICENSE.txt +202 -0
  20. data/vendor/bundle/jruby/2.5.0/gems/addressable-2.7.0/README.md +121 -0
  21. data/vendor/bundle/jruby/2.5.0/gems/addressable-2.7.0/Rakefile +34 -0
  22. data/vendor/bundle/jruby/2.5.0/gems/addressable-2.7.0/data/unicode.data +0 -0
  23. data/vendor/bundle/jruby/2.5.0/gems/addressable-2.7.0/lib/addressable.rb +4 -0
  24. data/vendor/bundle/jruby/2.5.0/gems/addressable-2.7.0/lib/addressable/idna.rb +27 -0
  25. data/vendor/bundle/jruby/2.5.0/gems/addressable-2.7.0/lib/addressable/idna/native.rb +61 -0
  26. data/vendor/bundle/jruby/2.5.0/gems/addressable-2.7.0/lib/addressable/idna/pure.rb +676 -0
  27. data/vendor/bundle/jruby/2.5.0/gems/addressable-2.7.0/lib/addressable/template.rb +1045 -0
  28. data/vendor/bundle/jruby/2.5.0/gems/addressable-2.7.0/lib/addressable/uri.rb +2529 -0
  29. data/vendor/bundle/jruby/2.5.0/gems/addressable-2.7.0/lib/addressable/version.rb +32 -0
  30. data/vendor/bundle/jruby/2.5.0/gems/addressable-2.7.0/spec/addressable/idna_spec.rb +300 -0
  31. data/vendor/bundle/jruby/2.5.0/gems/addressable-2.7.0/spec/addressable/net_http_compat_spec.rb +30 -0
  32. data/vendor/bundle/jruby/2.5.0/gems/addressable-2.7.0/spec/addressable/rack_mount_compat_spec.rb +106 -0
  33. data/vendor/bundle/jruby/2.5.0/gems/addressable-2.7.0/spec/addressable/security_spec.rb +59 -0
  34. data/vendor/bundle/jruby/2.5.0/gems/addressable-2.7.0/spec/addressable/template_spec.rb +1451 -0
  35. data/vendor/bundle/jruby/2.5.0/gems/addressable-2.7.0/spec/addressable/uri_spec.rb +6603 -0
  36. data/vendor/bundle/jruby/2.5.0/gems/addressable-2.7.0/spec/spec_helper.rb +24 -0
  37. data/vendor/bundle/jruby/2.5.0/gems/addressable-2.7.0/tasks/clobber.rake +4 -0
  38. data/vendor/bundle/jruby/2.5.0/gems/addressable-2.7.0/tasks/gem.rake +93 -0
  39. data/vendor/bundle/jruby/2.5.0/gems/addressable-2.7.0/tasks/git.rake +47 -0
  40. data/vendor/bundle/jruby/2.5.0/gems/addressable-2.7.0/tasks/metrics.rake +24 -0
  41. data/vendor/bundle/jruby/2.5.0/gems/addressable-2.7.0/tasks/rspec.rake +23 -0
  42. data/vendor/bundle/jruby/2.5.0/gems/addressable-2.7.0/tasks/yard.rake +29 -0
  43. data/vendor/bundle/jruby/2.5.0/gems/crack-0.4.5/lib/crack.rb +7 -0
  44. data/vendor/bundle/jruby/2.5.0/gems/crack-0.4.5/lib/crack/json.rb +98 -0
  45. data/vendor/bundle/jruby/2.5.0/gems/crack-0.4.5/lib/crack/util.rb +17 -0
  46. data/vendor/bundle/jruby/2.5.0/gems/crack-0.4.5/lib/crack/version.rb +3 -0
  47. data/vendor/bundle/jruby/2.5.0/gems/crack-0.4.5/lib/crack/xml.rb +238 -0
  48. data/vendor/bundle/jruby/2.5.0/gems/hashdiff-1.0.1/Gemfile +8 -0
  49. data/vendor/bundle/jruby/2.5.0/gems/hashdiff-1.0.1/LICENSE +19 -0
  50. data/vendor/bundle/jruby/2.5.0/gems/hashdiff-1.0.1/README.md +276 -0
  51. data/vendor/bundle/jruby/2.5.0/gems/hashdiff-1.0.1/Rakefile +18 -0
  52. data/vendor/bundle/jruby/2.5.0/gems/hashdiff-1.0.1/changelog.md +100 -0
  53. data/vendor/bundle/jruby/2.5.0/gems/hashdiff-1.0.1/hashdiff.gemspec +39 -0
  54. data/vendor/bundle/jruby/2.5.0/gems/hashdiff-1.0.1/lib/hashdiff.rb +10 -0
  55. data/vendor/bundle/jruby/2.5.0/gems/hashdiff-1.0.1/lib/hashdiff/compare_hashes.rb +69 -0
  56. data/vendor/bundle/jruby/2.5.0/gems/hashdiff-1.0.1/lib/hashdiff/diff.rb +177 -0
  57. data/vendor/bundle/jruby/2.5.0/gems/hashdiff-1.0.1/lib/hashdiff/lcs.rb +66 -0
  58. data/vendor/bundle/jruby/2.5.0/gems/hashdiff-1.0.1/lib/hashdiff/lcs_compare_arrays.rb +32 -0
  59. data/vendor/bundle/jruby/2.5.0/gems/hashdiff-1.0.1/lib/hashdiff/linear_compare_array.rb +159 -0
  60. data/vendor/bundle/jruby/2.5.0/gems/hashdiff-1.0.1/lib/hashdiff/patch.rb +88 -0
  61. data/vendor/bundle/jruby/2.5.0/gems/hashdiff-1.0.1/lib/hashdiff/util.rb +155 -0
  62. data/vendor/bundle/jruby/2.5.0/gems/hashdiff-1.0.1/lib/hashdiff/version.rb +5 -0
  63. data/vendor/bundle/jruby/2.5.0/gems/hashdiff-1.0.1/spec/hashdiff/best_diff_spec.rb +75 -0
  64. data/vendor/bundle/jruby/2.5.0/gems/hashdiff-1.0.1/spec/hashdiff/diff_array_spec.rb +60 -0
  65. data/vendor/bundle/jruby/2.5.0/gems/hashdiff-1.0.1/spec/hashdiff/diff_spec.rb +360 -0
  66. data/vendor/bundle/jruby/2.5.0/gems/hashdiff-1.0.1/spec/hashdiff/lcs_spec.rb +76 -0
  67. data/vendor/bundle/jruby/2.5.0/gems/hashdiff-1.0.1/spec/hashdiff/linear_compare_array_spec.rb +50 -0
  68. data/vendor/bundle/jruby/2.5.0/gems/hashdiff-1.0.1/spec/hashdiff/patch_spec.rb +185 -0
  69. data/vendor/bundle/jruby/2.5.0/gems/hashdiff-1.0.1/spec/hashdiff/readme_spec.rb +15 -0
  70. data/vendor/bundle/jruby/2.5.0/gems/hashdiff-1.0.1/spec/hashdiff/util_spec.rb +116 -0
  71. data/vendor/bundle/jruby/2.5.0/gems/hashdiff-1.0.1/spec/spec_helper.rb +15 -0
  72. data/vendor/bundle/jruby/2.5.0/gems/public_suffix-4.0.6/2.0-Upgrade.md +52 -0
  73. data/vendor/bundle/jruby/2.5.0/gems/public_suffix-4.0.6/CHANGELOG.md +406 -0
  74. data/vendor/bundle/jruby/2.5.0/gems/public_suffix-4.0.6/Gemfile +15 -0
  75. data/vendor/bundle/jruby/2.5.0/gems/public_suffix-4.0.6/LICENSE.txt +22 -0
  76. data/vendor/bundle/jruby/2.5.0/gems/public_suffix-4.0.6/README.md +207 -0
  77. data/vendor/bundle/jruby/2.5.0/gems/public_suffix-4.0.6/Rakefile +51 -0
  78. data/vendor/bundle/jruby/2.5.0/gems/public_suffix-4.0.6/SECURITY.md +104 -0
  79. data/vendor/bundle/jruby/2.5.0/gems/public_suffix-4.0.6/bin/console +15 -0
  80. data/vendor/bundle/jruby/2.5.0/gems/public_suffix-4.0.6/codecov.yml +12 -0
  81. data/vendor/bundle/jruby/2.5.0/gems/public_suffix-4.0.6/data/list.txt +13380 -0
  82. data/vendor/bundle/jruby/2.5.0/gems/public_suffix-4.0.6/lib/public_suffix.rb +179 -0
  83. data/vendor/bundle/jruby/2.5.0/gems/public_suffix-4.0.6/lib/public_suffix/domain.rb +235 -0
  84. data/vendor/bundle/jruby/2.5.0/gems/public_suffix-4.0.6/lib/public_suffix/errors.rb +41 -0
  85. data/vendor/bundle/jruby/2.5.0/gems/public_suffix-4.0.6/lib/public_suffix/list.rb +247 -0
  86. data/vendor/bundle/jruby/2.5.0/gems/public_suffix-4.0.6/lib/public_suffix/rule.rb +350 -0
  87. data/vendor/bundle/jruby/2.5.0/gems/public_suffix-4.0.6/lib/public_suffix/version.rb +13 -0
  88. data/vendor/bundle/jruby/2.5.0/gems/public_suffix-4.0.6/public_suffix.gemspec +29 -0
  89. data/vendor/bundle/jruby/2.5.0/gems/public_suffix-4.0.6/test/acceptance_test.rb +131 -0
  90. data/vendor/bundle/jruby/2.5.0/gems/public_suffix-4.0.6/test/benchmarks/bm_find.rb +66 -0
  91. data/vendor/bundle/jruby/2.5.0/gems/public_suffix-4.0.6/test/benchmarks/bm_find_all.rb +102 -0
  92. data/vendor/bundle/jruby/2.5.0/gems/public_suffix-4.0.6/test/benchmarks/bm_names.rb +91 -0
  93. data/vendor/bundle/jruby/2.5.0/gems/public_suffix-4.0.6/test/benchmarks/bm_select.rb +26 -0
  94. data/vendor/bundle/jruby/2.5.0/gems/public_suffix-4.0.6/test/benchmarks/bm_select_incremental.rb +25 -0
  95. data/vendor/bundle/jruby/2.5.0/gems/public_suffix-4.0.6/test/benchmarks/bm_valid.rb +101 -0
  96. data/vendor/bundle/jruby/2.5.0/gems/public_suffix-4.0.6/test/profilers/domain_profiler.rb +12 -0
  97. data/vendor/bundle/jruby/2.5.0/gems/public_suffix-4.0.6/test/profilers/find_profiler.rb +12 -0
  98. data/vendor/bundle/jruby/2.5.0/gems/public_suffix-4.0.6/test/profilers/find_profiler_jp.rb +12 -0
  99. data/vendor/bundle/jruby/2.5.0/gems/public_suffix-4.0.6/test/profilers/initialization_profiler.rb +11 -0
  100. data/vendor/bundle/jruby/2.5.0/gems/public_suffix-4.0.6/test/profilers/list_profsize.rb +11 -0
  101. data/vendor/bundle/jruby/2.5.0/gems/public_suffix-4.0.6/test/profilers/object_binsize.rb +57 -0
  102. data/vendor/bundle/jruby/2.5.0/gems/public_suffix-4.0.6/test/psl_test.rb +52 -0
  103. data/vendor/bundle/jruby/2.5.0/gems/public_suffix-4.0.6/test/test_helper.rb +18 -0
  104. data/vendor/bundle/jruby/2.5.0/gems/public_suffix-4.0.6/test/tests.txt +98 -0
  105. data/vendor/bundle/jruby/2.5.0/gems/public_suffix-4.0.6/test/unit/domain_test.rb +106 -0
  106. data/vendor/bundle/jruby/2.5.0/gems/public_suffix-4.0.6/test/unit/errors_test.rb +25 -0
  107. data/vendor/bundle/jruby/2.5.0/gems/public_suffix-4.0.6/test/unit/list_test.rb +241 -0
  108. data/vendor/bundle/jruby/2.5.0/gems/public_suffix-4.0.6/test/unit/public_suffix_test.rb +188 -0
  109. data/vendor/bundle/jruby/2.5.0/gems/public_suffix-4.0.6/test/unit/rule_test.rb +222 -0
  110. data/vendor/bundle/jruby/2.5.0/gems/rexml-3.2.5/LICENSE.txt +22 -0
  111. data/vendor/bundle/jruby/2.5.0/gems/rexml-3.2.5/NEWS.md +178 -0
  112. data/vendor/bundle/jruby/2.5.0/gems/rexml-3.2.5/README.md +48 -0
  113. data/vendor/bundle/jruby/2.5.0/gems/rexml-3.2.5/doc/rexml/context.rdoc +143 -0
  114. data/vendor/bundle/jruby/2.5.0/gems/rexml-3.2.5/doc/rexml/tasks/rdoc/child.rdoc +87 -0
  115. data/vendor/bundle/jruby/2.5.0/gems/rexml-3.2.5/doc/rexml/tasks/rdoc/document.rdoc +276 -0
  116. data/vendor/bundle/jruby/2.5.0/gems/rexml-3.2.5/doc/rexml/tasks/rdoc/element.rdoc +602 -0
  117. data/vendor/bundle/jruby/2.5.0/gems/rexml-3.2.5/doc/rexml/tasks/rdoc/node.rdoc +97 -0
  118. data/vendor/bundle/jruby/2.5.0/gems/rexml-3.2.5/doc/rexml/tasks/rdoc/parent.rdoc +267 -0
  119. data/vendor/bundle/jruby/2.5.0/gems/rexml-3.2.5/doc/rexml/tasks/tocs/child_toc.rdoc +12 -0
  120. data/vendor/bundle/jruby/2.5.0/gems/rexml-3.2.5/doc/rexml/tasks/tocs/document_toc.rdoc +30 -0
  121. data/vendor/bundle/jruby/2.5.0/gems/rexml-3.2.5/doc/rexml/tasks/tocs/element_toc.rdoc +55 -0
  122. data/vendor/bundle/jruby/2.5.0/gems/rexml-3.2.5/doc/rexml/tasks/tocs/master_toc.rdoc +135 -0
  123. data/vendor/bundle/jruby/2.5.0/gems/rexml-3.2.5/doc/rexml/tasks/tocs/node_toc.rdoc +16 -0
  124. data/vendor/bundle/jruby/2.5.0/gems/rexml-3.2.5/doc/rexml/tasks/tocs/parent_toc.rdoc +25 -0
  125. data/vendor/bundle/jruby/2.5.0/gems/rexml-3.2.5/lib/rexml.rb +3 -0
  126. data/vendor/bundle/jruby/2.5.0/gems/rexml-3.2.5/lib/rexml/attlistdecl.rb +63 -0
  127. data/vendor/bundle/jruby/2.5.0/gems/rexml-3.2.5/lib/rexml/attribute.rb +205 -0
  128. data/vendor/bundle/jruby/2.5.0/gems/rexml-3.2.5/lib/rexml/cdata.rb +68 -0
  129. data/vendor/bundle/jruby/2.5.0/gems/rexml-3.2.5/lib/rexml/child.rb +97 -0
  130. data/vendor/bundle/jruby/2.5.0/gems/rexml-3.2.5/lib/rexml/comment.rb +80 -0
  131. data/vendor/bundle/jruby/2.5.0/gems/rexml-3.2.5/lib/rexml/doctype.rb +311 -0
  132. data/vendor/bundle/jruby/2.5.0/gems/rexml-3.2.5/lib/rexml/document.rb +451 -0
  133. data/vendor/bundle/jruby/2.5.0/gems/rexml-3.2.5/lib/rexml/dtd/attlistdecl.rb +11 -0
  134. data/vendor/bundle/jruby/2.5.0/gems/rexml-3.2.5/lib/rexml/dtd/dtd.rb +47 -0
  135. data/vendor/bundle/jruby/2.5.0/gems/rexml-3.2.5/lib/rexml/dtd/elementdecl.rb +18 -0
  136. data/vendor/bundle/jruby/2.5.0/gems/rexml-3.2.5/lib/rexml/dtd/entitydecl.rb +57 -0
  137. data/vendor/bundle/jruby/2.5.0/gems/rexml-3.2.5/lib/rexml/dtd/notationdecl.rb +40 -0
  138. data/vendor/bundle/jruby/2.5.0/gems/rexml-3.2.5/lib/rexml/element.rb +2599 -0
  139. data/vendor/bundle/jruby/2.5.0/gems/rexml-3.2.5/lib/rexml/encoding.rb +51 -0
  140. data/vendor/bundle/jruby/2.5.0/gems/rexml-3.2.5/lib/rexml/entity.rb +171 -0
  141. data/vendor/bundle/jruby/2.5.0/gems/rexml-3.2.5/lib/rexml/formatters/default.rb +116 -0
  142. data/vendor/bundle/jruby/2.5.0/gems/rexml-3.2.5/lib/rexml/formatters/pretty.rb +142 -0
  143. data/vendor/bundle/jruby/2.5.0/gems/rexml-3.2.5/lib/rexml/formatters/transitive.rb +58 -0
  144. data/vendor/bundle/jruby/2.5.0/gems/rexml-3.2.5/lib/rexml/functions.rb +447 -0
  145. data/vendor/bundle/jruby/2.5.0/gems/rexml-3.2.5/lib/rexml/instruction.rb +79 -0
  146. data/vendor/bundle/jruby/2.5.0/gems/rexml-3.2.5/lib/rexml/light/node.rb +188 -0
  147. data/vendor/bundle/jruby/2.5.0/gems/rexml-3.2.5/lib/rexml/namespace.rb +59 -0
  148. data/vendor/bundle/jruby/2.5.0/gems/rexml-3.2.5/lib/rexml/node.rb +76 -0
  149. data/vendor/bundle/jruby/2.5.0/gems/rexml-3.2.5/lib/rexml/output.rb +30 -0
  150. data/vendor/bundle/jruby/2.5.0/gems/rexml-3.2.5/lib/rexml/parent.rb +166 -0
  151. data/vendor/bundle/jruby/2.5.0/gems/rexml-3.2.5/lib/rexml/parseexception.rb +52 -0
  152. data/vendor/bundle/jruby/2.5.0/gems/rexml-3.2.5/lib/rexml/parsers/baseparser.rb +694 -0
  153. data/vendor/bundle/jruby/2.5.0/gems/rexml-3.2.5/lib/rexml/parsers/lightparser.rb +59 -0
  154. data/vendor/bundle/jruby/2.5.0/gems/rexml-3.2.5/lib/rexml/parsers/pullparser.rb +197 -0
  155. data/vendor/bundle/jruby/2.5.0/gems/rexml-3.2.5/lib/rexml/parsers/sax2parser.rb +273 -0
  156. data/vendor/bundle/jruby/2.5.0/gems/rexml-3.2.5/lib/rexml/parsers/streamparser.rb +61 -0
  157. data/vendor/bundle/jruby/2.5.0/gems/rexml-3.2.5/lib/rexml/parsers/treeparser.rb +101 -0
  158. data/vendor/bundle/jruby/2.5.0/gems/rexml-3.2.5/lib/rexml/parsers/ultralightparser.rb +57 -0
  159. data/vendor/bundle/jruby/2.5.0/gems/rexml-3.2.5/lib/rexml/parsers/xpathparser.rb +689 -0
  160. data/vendor/bundle/jruby/2.5.0/gems/rexml-3.2.5/lib/rexml/quickpath.rb +266 -0
  161. data/vendor/bundle/jruby/2.5.0/gems/rexml-3.2.5/lib/rexml/rexml.rb +37 -0
  162. data/vendor/bundle/jruby/2.5.0/gems/rexml-3.2.5/lib/rexml/sax2listener.rb +98 -0
  163. data/vendor/bundle/jruby/2.5.0/gems/rexml-3.2.5/lib/rexml/security.rb +28 -0
  164. data/vendor/bundle/jruby/2.5.0/gems/rexml-3.2.5/lib/rexml/source.rb +298 -0
  165. data/vendor/bundle/jruby/2.5.0/gems/rexml-3.2.5/lib/rexml/streamlistener.rb +93 -0
  166. data/vendor/bundle/jruby/2.5.0/gems/rexml-3.2.5/lib/rexml/text.rb +424 -0
  167. data/vendor/bundle/jruby/2.5.0/gems/rexml-3.2.5/lib/rexml/undefinednamespaceexception.rb +9 -0
  168. data/vendor/bundle/jruby/2.5.0/gems/rexml-3.2.5/lib/rexml/validation/relaxng.rb +539 -0
  169. data/vendor/bundle/jruby/2.5.0/gems/rexml-3.2.5/lib/rexml/validation/validation.rb +144 -0
  170. data/vendor/bundle/jruby/2.5.0/gems/rexml-3.2.5/lib/rexml/validation/validationexception.rb +10 -0
  171. data/vendor/bundle/jruby/2.5.0/gems/rexml-3.2.5/lib/rexml/xmldecl.rb +130 -0
  172. data/vendor/bundle/jruby/2.5.0/gems/rexml-3.2.5/lib/rexml/xmltokens.rb +85 -0
  173. data/vendor/bundle/jruby/2.5.0/gems/rexml-3.2.5/lib/rexml/xpath.rb +81 -0
  174. data/vendor/bundle/jruby/2.5.0/gems/rexml-3.2.5/lib/rexml/xpath_parser.rb +974 -0
  175. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/CHANGELOG.md +1894 -0
  176. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/Gemfile +9 -0
  177. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/LICENSE +20 -0
  178. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/README.md +1176 -0
  179. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/Rakefile +38 -0
  180. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/lib/webmock.rb +59 -0
  181. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/lib/webmock/api.rb +109 -0
  182. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/lib/webmock/assertion_failure.rb +11 -0
  183. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/lib/webmock/callback_registry.rb +35 -0
  184. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/lib/webmock/config.rb +18 -0
  185. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/lib/webmock/cucumber.rb +10 -0
  186. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/lib/webmock/deprecation.rb +9 -0
  187. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/lib/webmock/errors.rb +17 -0
  188. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/lib/webmock/http_lib_adapters/async_http_client_adapter.rb +216 -0
  189. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/lib/webmock/http_lib_adapters/curb_adapter.rb +351 -0
  190. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/lib/webmock/http_lib_adapters/em_http_request_adapter.rb +231 -0
  191. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/lib/webmock/http_lib_adapters/excon_adapter.rb +165 -0
  192. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/lib/webmock/http_lib_adapters/http_lib_adapter.rb +7 -0
  193. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/lib/webmock/http_lib_adapters/http_lib_adapter_registry.rb +19 -0
  194. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/lib/webmock/http_lib_adapters/http_rb/client.rb +17 -0
  195. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/lib/webmock/http_lib_adapters/http_rb/request.rb +16 -0
  196. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/lib/webmock/http_lib_adapters/http_rb/response.rb +64 -0
  197. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/lib/webmock/http_lib_adapters/http_rb/streamer.rb +29 -0
  198. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/lib/webmock/http_lib_adapters/http_rb/webmock.rb +68 -0
  199. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/lib/webmock/http_lib_adapters/http_rb_adapter.rb +37 -0
  200. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/lib/webmock/http_lib_adapters/httpclient_adapter.rb +259 -0
  201. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/lib/webmock/http_lib_adapters/manticore_adapter.rb +145 -0
  202. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/lib/webmock/http_lib_adapters/net_http.rb +385 -0
  203. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/lib/webmock/http_lib_adapters/net_http_response.rb +34 -0
  204. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/lib/webmock/http_lib_adapters/patron_adapter.rb +130 -0
  205. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/lib/webmock/http_lib_adapters/typhoeus_hydra_adapter.rb +174 -0
  206. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/lib/webmock/matchers/any_arg_matcher.rb +13 -0
  207. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/lib/webmock/matchers/hash_argument_matcher.rb +21 -0
  208. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/lib/webmock/matchers/hash_excluding_matcher.rb +15 -0
  209. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/lib/webmock/matchers/hash_including_matcher.rb +17 -0
  210. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/lib/webmock/minitest.rb +41 -0
  211. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/lib/webmock/rack_response.rb +69 -0
  212. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/lib/webmock/request_body_diff.rb +64 -0
  213. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/lib/webmock/request_execution_verifier.rb +77 -0
  214. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/lib/webmock/request_pattern.rb +405 -0
  215. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/lib/webmock/request_registry.rb +35 -0
  216. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/lib/webmock/request_signature.rb +54 -0
  217. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/lib/webmock/request_signature_snippet.rb +61 -0
  218. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/lib/webmock/request_stub.rb +100 -0
  219. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/lib/webmock/response.rb +159 -0
  220. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/lib/webmock/responses_sequence.rb +40 -0
  221. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/lib/webmock/rspec.rb +42 -0
  222. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/lib/webmock/rspec/matchers.rb +27 -0
  223. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/lib/webmock/rspec/matchers/request_pattern_matcher.rb +78 -0
  224. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/lib/webmock/rspec/matchers/webmock_matcher.rb +67 -0
  225. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/lib/webmock/stub_registry.rb +82 -0
  226. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/lib/webmock/stub_request_snippet.rb +38 -0
  227. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/lib/webmock/test_unit.rb +20 -0
  228. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/lib/webmock/util/hash_counter.rb +39 -0
  229. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/lib/webmock/util/hash_keys_stringifier.rb +25 -0
  230. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/lib/webmock/util/hash_validator.rb +17 -0
  231. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/lib/webmock/util/headers.rb +64 -0
  232. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/lib/webmock/util/json.rb +67 -0
  233. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/lib/webmock/util/query_mapper.rb +281 -0
  234. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/lib/webmock/util/uri.rb +111 -0
  235. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/lib/webmock/util/values_stringifier.rb +20 -0
  236. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/lib/webmock/util/version_checker.rb +111 -0
  237. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/lib/webmock/version.rb +3 -0
  238. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/lib/webmock/webmock.rb +163 -0
  239. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/minitest/test_helper.rb +34 -0
  240. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/minitest/test_webmock.rb +9 -0
  241. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/minitest/webmock_spec.rb +60 -0
  242. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/spec/acceptance/async_http_client/async_http_client_spec.rb +375 -0
  243. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/spec/acceptance/async_http_client/async_http_client_spec_helper.rb +73 -0
  244. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/spec/acceptance/curb/curb_spec.rb +499 -0
  245. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/spec/acceptance/curb/curb_spec_helper.rb +147 -0
  246. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/spec/acceptance/em_http_request/em_http_request_spec.rb +462 -0
  247. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/spec/acceptance/em_http_request/em_http_request_spec_helper.rb +77 -0
  248. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/spec/acceptance/excon/excon_spec.rb +77 -0
  249. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/spec/acceptance/excon/excon_spec_helper.rb +52 -0
  250. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/spec/acceptance/http_rb/http_rb_spec.rb +93 -0
  251. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/spec/acceptance/http_rb/http_rb_spec_helper.rb +54 -0
  252. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/spec/acceptance/httpclient/httpclient_spec.rb +217 -0
  253. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/spec/acceptance/httpclient/httpclient_spec_helper.rb +57 -0
  254. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/spec/acceptance/manticore/manticore_spec.rb +107 -0
  255. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/spec/acceptance/manticore/manticore_spec_helper.rb +35 -0
  256. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/spec/acceptance/net_http/net_http_shared.rb +153 -0
  257. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/spec/acceptance/net_http/net_http_spec.rb +369 -0
  258. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/spec/acceptance/net_http/net_http_spec_helper.rb +64 -0
  259. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/spec/acceptance/net_http/real_net_http_spec.rb +20 -0
  260. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/spec/acceptance/patron/patron_spec.rb +125 -0
  261. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/spec/acceptance/patron/patron_spec_helper.rb +54 -0
  262. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/spec/acceptance/shared/allowing_and_disabling_net_connect.rb +313 -0
  263. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/spec/acceptance/shared/callbacks.rb +148 -0
  264. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/spec/acceptance/shared/complex_cross_concern_behaviors.rb +36 -0
  265. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/spec/acceptance/shared/enabling_and_disabling_webmock.rb +95 -0
  266. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/spec/acceptance/shared/precedence_of_stubs.rb +15 -0
  267. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/spec/acceptance/shared/request_expectations.rb +930 -0
  268. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/spec/acceptance/shared/returning_declared_responses.rb +409 -0
  269. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/spec/acceptance/shared/stubbing_requests.rb +678 -0
  270. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/spec/acceptance/typhoeus/typhoeus_hydra_spec.rb +135 -0
  271. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/spec/acceptance/typhoeus/typhoeus_hydra_spec_helper.rb +60 -0
  272. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/spec/acceptance/webmock_shared.rb +41 -0
  273. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/spec/fixtures/test.txt +1 -0
  274. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/spec/quality_spec.rb +84 -0
  275. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/spec/spec_helper.rb +48 -0
  276. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/spec/support/example_curl_output.txt +22 -0
  277. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/spec/support/failures.rb +9 -0
  278. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/spec/support/my_rack_app.rb +53 -0
  279. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/spec/support/network_connection.rb +19 -0
  280. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/spec/support/webmock_server.rb +70 -0
  281. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/spec/unit/api_spec.rb +175 -0
  282. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/spec/unit/errors_spec.rb +129 -0
  283. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/spec/unit/http_lib_adapters/http_lib_adapter_registry_spec.rb +17 -0
  284. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/spec/unit/http_lib_adapters/http_lib_adapter_spec.rb +12 -0
  285. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/spec/unit/matchers/hash_excluding_matcher_spec.rb +61 -0
  286. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/spec/unit/matchers/hash_including_matcher_spec.rb +87 -0
  287. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/spec/unit/rack_response_spec.rb +112 -0
  288. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/spec/unit/request_body_diff_spec.rb +90 -0
  289. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/spec/unit/request_execution_verifier_spec.rb +208 -0
  290. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/spec/unit/request_pattern_spec.rb +736 -0
  291. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/spec/unit/request_registry_spec.rb +95 -0
  292. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/spec/unit/request_signature_snippet_spec.rb +89 -0
  293. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/spec/unit/request_signature_spec.rb +155 -0
  294. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/spec/unit/request_stub_spec.rb +199 -0
  295. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/spec/unit/response_spec.rb +286 -0
  296. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/spec/unit/stub_registry_spec.rb +103 -0
  297. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/spec/unit/stub_request_snippet_spec.rb +115 -0
  298. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/spec/unit/util/hash_counter_spec.rb +39 -0
  299. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/spec/unit/util/hash_keys_stringifier_spec.rb +27 -0
  300. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/spec/unit/util/headers_spec.rb +28 -0
  301. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/spec/unit/util/json_spec.rb +33 -0
  302. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/spec/unit/util/query_mapper_spec.rb +157 -0
  303. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/spec/unit/util/uri_spec.rb +371 -0
  304. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/spec/unit/util/version_checker_spec.rb +65 -0
  305. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/spec/unit/webmock_spec.rb +60 -0
  306. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/test/http_request.rb +24 -0
  307. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/test/shared_test.rb +108 -0
  308. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/test/test_helper.rb +23 -0
  309. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/test/test_webmock.rb +12 -0
  310. data/vendor/bundle/jruby/2.5.0/gems/webmock-3.13.0/webmock.gemspec +54 -0
  311. data/vendor/bundle/jruby/2.5.0/specifications/addressable-2.7.0.gemspec +39 -0
  312. data/vendor/bundle/jruby/2.5.0/specifications/crack-0.4.5.gemspec +32 -0
  313. data/vendor/bundle/jruby/2.5.0/specifications/hashdiff-1.0.1.gemspec +46 -0
  314. data/vendor/bundle/jruby/2.5.0/specifications/public_suffix-4.0.6.gemspec +24 -0
  315. data/vendor/bundle/jruby/2.5.0/specifications/rexml-3.2.5.gemspec +42 -0
  316. data/vendor/bundle/jruby/2.5.0/specifications/webmock-3.13.0.gemspec +85 -0
  317. metadata +309 -2
@@ -0,0 +1,2529 @@
1
+ # frozen_string_literal: true
2
+
3
+ # encoding:utf-8
4
+ #--
5
+ # Copyright (C) Bob Aman
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+ #++
19
+
20
+
21
+ require "addressable/version"
22
+ require "addressable/idna"
23
+ require "public_suffix"
24
+
25
+ ##
26
+ # Addressable is a library for processing links and URIs.
27
+ module Addressable
28
+ ##
29
+ # This is an implementation of a URI parser based on
30
+ # <a href="http://www.ietf.org/rfc/rfc3986.txt">RFC 3986</a>,
31
+ # <a href="http://www.ietf.org/rfc/rfc3987.txt">RFC 3987</a>.
32
+ class URI
33
+ ##
34
+ # Raised if something other than a uri is supplied.
35
+ class InvalidURIError < StandardError
36
+ end
37
+
38
+ ##
39
+ # Container for the character classes specified in
40
+ # <a href="http://www.ietf.org/rfc/rfc3986.txt">RFC 3986</a>.
41
+ module CharacterClasses
42
+ ALPHA = "a-zA-Z"
43
+ DIGIT = "0-9"
44
+ GEN_DELIMS = "\\:\\/\\?\\#\\[\\]\\@"
45
+ SUB_DELIMS = "\\!\\$\\&\\'\\(\\)\\*\\+\\,\\;\\="
46
+ RESERVED = GEN_DELIMS + SUB_DELIMS
47
+ UNRESERVED = ALPHA + DIGIT + "\\-\\.\\_\\~"
48
+ PCHAR = UNRESERVED + SUB_DELIMS + "\\:\\@"
49
+ SCHEME = ALPHA + DIGIT + "\\-\\+\\."
50
+ HOST = UNRESERVED + SUB_DELIMS + "\\[\\:\\]"
51
+ AUTHORITY = PCHAR
52
+ PATH = PCHAR + "\\/"
53
+ QUERY = PCHAR + "\\/\\?"
54
+ FRAGMENT = PCHAR + "\\/\\?"
55
+ end
56
+
57
+ SLASH = '/'
58
+ EMPTY_STR = ''
59
+
60
+ URIREGEX = /^(([^:\/?#]+):)?(\/\/([^\/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?$/
61
+
62
+ PORT_MAPPING = {
63
+ "http" => 80,
64
+ "https" => 443,
65
+ "ftp" => 21,
66
+ "tftp" => 69,
67
+ "sftp" => 22,
68
+ "ssh" => 22,
69
+ "svn+ssh" => 22,
70
+ "telnet" => 23,
71
+ "nntp" => 119,
72
+ "gopher" => 70,
73
+ "wais" => 210,
74
+ "ldap" => 389,
75
+ "prospero" => 1525
76
+ }
77
+
78
+ ##
79
+ # Returns a URI object based on the parsed string.
80
+ #
81
+ # @param [String, Addressable::URI, #to_str] uri
82
+ # The URI string to parse.
83
+ # No parsing is performed if the object is already an
84
+ # <code>Addressable::URI</code>.
85
+ #
86
+ # @return [Addressable::URI] The parsed URI.
87
+ def self.parse(uri)
88
+ # If we were given nil, return nil.
89
+ return nil unless uri
90
+ # If a URI object is passed, just return itself.
91
+ return uri.dup if uri.kind_of?(self)
92
+
93
+ # If a URI object of the Ruby standard library variety is passed,
94
+ # convert it to a string, then parse the string.
95
+ # We do the check this way because we don't want to accidentally
96
+ # cause a missing constant exception to be thrown.
97
+ if uri.class.name =~ /^URI\b/
98
+ uri = uri.to_s
99
+ end
100
+
101
+ # Otherwise, convert to a String
102
+ begin
103
+ uri = uri.to_str
104
+ rescue TypeError, NoMethodError
105
+ raise TypeError, "Can't convert #{uri.class} into String."
106
+ end if not uri.is_a? String
107
+
108
+ # This Regexp supplied as an example in RFC 3986, and it works great.
109
+ scan = uri.scan(URIREGEX)
110
+ fragments = scan[0]
111
+ scheme = fragments[1]
112
+ authority = fragments[3]
113
+ path = fragments[4]
114
+ query = fragments[6]
115
+ fragment = fragments[8]
116
+ user = nil
117
+ password = nil
118
+ host = nil
119
+ port = nil
120
+ if authority != nil
121
+ # The Regexp above doesn't split apart the authority.
122
+ userinfo = authority[/^([^\[\]]*)@/, 1]
123
+ if userinfo != nil
124
+ user = userinfo.strip[/^([^:]*):?/, 1]
125
+ password = userinfo.strip[/:(.*)$/, 1]
126
+ end
127
+ host = authority.sub(
128
+ /^([^\[\]]*)@/, EMPTY_STR
129
+ ).sub(
130
+ /:([^:@\[\]]*?)$/, EMPTY_STR
131
+ )
132
+ port = authority[/:([^:@\[\]]*?)$/, 1]
133
+ end
134
+ if port == EMPTY_STR
135
+ port = nil
136
+ end
137
+
138
+ return new(
139
+ :scheme => scheme,
140
+ :user => user,
141
+ :password => password,
142
+ :host => host,
143
+ :port => port,
144
+ :path => path,
145
+ :query => query,
146
+ :fragment => fragment
147
+ )
148
+ end
149
+
150
+ ##
151
+ # Converts an input to a URI. The input does not have to be a valid
152
+ # URI — the method will use heuristics to guess what URI was intended.
153
+ # This is not standards-compliant, merely user-friendly.
154
+ #
155
+ # @param [String, Addressable::URI, #to_str] uri
156
+ # The URI string to parse.
157
+ # No parsing is performed if the object is already an
158
+ # <code>Addressable::URI</code>.
159
+ # @param [Hash] hints
160
+ # A <code>Hash</code> of hints to the heuristic parser.
161
+ # Defaults to <code>{:scheme => "http"}</code>.
162
+ #
163
+ # @return [Addressable::URI] The parsed URI.
164
+ def self.heuristic_parse(uri, hints={})
165
+ # If we were given nil, return nil.
166
+ return nil unless uri
167
+ # If a URI object is passed, just return itself.
168
+ return uri.dup if uri.kind_of?(self)
169
+
170
+ # If a URI object of the Ruby standard library variety is passed,
171
+ # convert it to a string, then parse the string.
172
+ # We do the check this way because we don't want to accidentally
173
+ # cause a missing constant exception to be thrown.
174
+ if uri.class.name =~ /^URI\b/
175
+ uri = uri.to_s
176
+ end
177
+
178
+ if !uri.respond_to?(:to_str)
179
+ raise TypeError, "Can't convert #{uri.class} into String."
180
+ end
181
+ # Otherwise, convert to a String
182
+ uri = uri.to_str.dup.strip
183
+ hints = {
184
+ :scheme => "http"
185
+ }.merge(hints)
186
+ case uri
187
+ when /^http:\//i
188
+ uri.sub!(/^http:\/+/i, "http://")
189
+ when /^https:\//i
190
+ uri.sub!(/^https:\/+/i, "https://")
191
+ when /^feed:\/+http:\//i
192
+ uri.sub!(/^feed:\/+http:\/+/i, "feed:http://")
193
+ when /^feed:\//i
194
+ uri.sub!(/^feed:\/+/i, "feed://")
195
+ when %r[^file:/{4}]i
196
+ uri.sub!(%r[^file:/+]i, "file:////")
197
+ when %r[^file://localhost/]i
198
+ uri.sub!(%r[^file://localhost/+]i, "file:///")
199
+ when %r[^file:/+]i
200
+ uri.sub!(%r[^file:/+]i, "file:///")
201
+ when /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/
202
+ uri.sub!(/^/, hints[:scheme] + "://")
203
+ when /\A\d+\..*:\d+\z/
204
+ uri = "#{hints[:scheme]}://#{uri}"
205
+ end
206
+ match = uri.match(URIREGEX)
207
+ fragments = match.captures
208
+ authority = fragments[3]
209
+ if authority && authority.length > 0
210
+ new_authority = authority.tr("\\", "/").gsub(" ", "%20")
211
+ # NOTE: We want offset 4, not 3!
212
+ offset = match.offset(4)
213
+ uri = uri.dup
214
+ uri[offset[0]...offset[1]] = new_authority
215
+ end
216
+ parsed = self.parse(uri)
217
+ if parsed.scheme =~ /^[^\/?#\.]+\.[^\/?#]+$/
218
+ parsed = self.parse(hints[:scheme] + "://" + uri)
219
+ end
220
+ if parsed.path.include?(".")
221
+ if parsed.path[/\b@\b/]
222
+ parsed.scheme = "mailto" unless parsed.scheme
223
+ elsif new_host = parsed.path[/^([^\/]+\.[^\/]*)/, 1]
224
+ parsed.defer_validation do
225
+ new_path = parsed.path.sub(
226
+ Regexp.new("^" + Regexp.escape(new_host)), EMPTY_STR)
227
+ parsed.host = new_host
228
+ parsed.path = new_path
229
+ parsed.scheme = hints[:scheme] unless parsed.scheme
230
+ end
231
+ end
232
+ end
233
+ return parsed
234
+ end
235
+
236
+ ##
237
+ # Converts a path to a file scheme URI. If the path supplied is
238
+ # relative, it will be returned as a relative URI. If the path supplied
239
+ # is actually a non-file URI, it will parse the URI as if it had been
240
+ # parsed with <code>Addressable::URI.parse</code>. Handles all of the
241
+ # various Microsoft-specific formats for specifying paths.
242
+ #
243
+ # @param [String, Addressable::URI, #to_str] path
244
+ # Typically a <code>String</code> path to a file or directory, but
245
+ # will return a sensible return value if an absolute URI is supplied
246
+ # instead.
247
+ #
248
+ # @return [Addressable::URI]
249
+ # The parsed file scheme URI or the original URI if some other URI
250
+ # scheme was provided.
251
+ #
252
+ # @example
253
+ # base = Addressable::URI.convert_path("/absolute/path/")
254
+ # uri = Addressable::URI.convert_path("relative/path")
255
+ # (base + uri).to_s
256
+ # #=> "file:///absolute/path/relative/path"
257
+ #
258
+ # Addressable::URI.convert_path(
259
+ # "c:\\windows\\My Documents 100%20\\foo.txt"
260
+ # ).to_s
261
+ # #=> "file:///c:/windows/My%20Documents%20100%20/foo.txt"
262
+ #
263
+ # Addressable::URI.convert_path("http://example.com/").to_s
264
+ # #=> "http://example.com/"
265
+ def self.convert_path(path)
266
+ # If we were given nil, return nil.
267
+ return nil unless path
268
+ # If a URI object is passed, just return itself.
269
+ return path if path.kind_of?(self)
270
+ if !path.respond_to?(:to_str)
271
+ raise TypeError, "Can't convert #{path.class} into String."
272
+ end
273
+ # Otherwise, convert to a String
274
+ path = path.to_str.strip
275
+
276
+ path.sub!(/^file:\/?\/?/, EMPTY_STR) if path =~ /^file:\/?\/?/
277
+ path = SLASH + path if path =~ /^([a-zA-Z])[\|:]/
278
+ uri = self.parse(path)
279
+
280
+ if uri.scheme == nil
281
+ # Adjust windows-style uris
282
+ uri.path.sub!(/^\/?([a-zA-Z])[\|:][\\\/]/) do
283
+ "/#{$1.downcase}:/"
284
+ end
285
+ uri.path.tr!("\\", SLASH)
286
+ if File.exist?(uri.path) &&
287
+ File.stat(uri.path).directory?
288
+ uri.path.chomp!(SLASH)
289
+ uri.path = uri.path + '/'
290
+ end
291
+
292
+ # If the path is absolute, set the scheme and host.
293
+ if uri.path.start_with?(SLASH)
294
+ uri.scheme = "file"
295
+ uri.host = EMPTY_STR
296
+ end
297
+ uri.normalize!
298
+ end
299
+
300
+ return uri
301
+ end
302
+
303
+ ##
304
+ # Joins several URIs together.
305
+ #
306
+ # @param [String, Addressable::URI, #to_str] *uris
307
+ # The URIs to join.
308
+ #
309
+ # @return [Addressable::URI] The joined URI.
310
+ #
311
+ # @example
312
+ # base = "http://example.com/"
313
+ # uri = Addressable::URI.parse("relative/path")
314
+ # Addressable::URI.join(base, uri)
315
+ # #=> #<Addressable::URI:0xcab390 URI:http://example.com/relative/path>
316
+ def self.join(*uris)
317
+ uri_objects = uris.collect do |uri|
318
+ if !uri.respond_to?(:to_str)
319
+ raise TypeError, "Can't convert #{uri.class} into String."
320
+ end
321
+ uri.kind_of?(self) ? uri : self.parse(uri.to_str)
322
+ end
323
+ result = uri_objects.shift.dup
324
+ for uri in uri_objects
325
+ result.join!(uri)
326
+ end
327
+ return result
328
+ end
329
+
330
+ ##
331
+ # Tables used to optimize encoding operations in `self.encode_component`
332
+ # and `self.normalize_component`
333
+ SEQUENCE_ENCODING_TABLE = Hash.new do |hash, sequence|
334
+ hash[sequence] = sequence.unpack("C*").map do |c|
335
+ format("%02x", c)
336
+ end.join
337
+ end
338
+
339
+ SEQUENCE_UPCASED_PERCENT_ENCODING_TABLE = Hash.new do |hash, sequence|
340
+ hash[sequence] = sequence.unpack("C*").map do |c|
341
+ format("%%%02X", c)
342
+ end.join
343
+ end
344
+
345
+ ##
346
+ # Percent encodes a URI component.
347
+ #
348
+ # @param [String, #to_str] component The URI component to encode.
349
+ #
350
+ # @param [String, Regexp] character_class
351
+ # The characters which are not percent encoded. If a <code>String</code>
352
+ # is passed, the <code>String</code> must be formatted as a regular
353
+ # expression character class. (Do not include the surrounding square
354
+ # brackets.) For example, <code>"b-zB-Z0-9"</code> would cause
355
+ # everything but the letters 'b' through 'z' and the numbers '0' through
356
+ # '9' to be percent encoded. If a <code>Regexp</code> is passed, the
357
+ # value <code>/[^b-zB-Z0-9]/</code> would have the same effect. A set of
358
+ # useful <code>String</code> values may be found in the
359
+ # <code>Addressable::URI::CharacterClasses</code> module. The default
360
+ # value is the reserved plus unreserved character classes specified in
361
+ # <a href="http://www.ietf.org/rfc/rfc3986.txt">RFC 3986</a>.
362
+ #
363
+ # @param [Regexp] upcase_encoded
364
+ # A string of characters that may already be percent encoded, and whose
365
+ # encodings should be upcased. This allows normalization of percent
366
+ # encodings for characters not included in the
367
+ # <code>character_class</code>.
368
+ #
369
+ # @return [String] The encoded component.
370
+ #
371
+ # @example
372
+ # Addressable::URI.encode_component("simple/example", "b-zB-Z0-9")
373
+ # => "simple%2Fex%61mple"
374
+ # Addressable::URI.encode_component("simple/example", /[^b-zB-Z0-9]/)
375
+ # => "simple%2Fex%61mple"
376
+ # Addressable::URI.encode_component(
377
+ # "simple/example", Addressable::URI::CharacterClasses::UNRESERVED
378
+ # )
379
+ # => "simple%2Fexample"
380
+ def self.encode_component(component, character_class=
381
+ CharacterClasses::RESERVED + CharacterClasses::UNRESERVED,
382
+ upcase_encoded='')
383
+ return nil if component.nil?
384
+
385
+ begin
386
+ if component.kind_of?(Symbol) ||
387
+ component.kind_of?(Numeric) ||
388
+ component.kind_of?(TrueClass) ||
389
+ component.kind_of?(FalseClass)
390
+ component = component.to_s
391
+ else
392
+ component = component.to_str
393
+ end
394
+ rescue TypeError, NoMethodError
395
+ raise TypeError, "Can't convert #{component.class} into String."
396
+ end if !component.is_a? String
397
+
398
+ if ![String, Regexp].include?(character_class.class)
399
+ raise TypeError,
400
+ "Expected String or Regexp, got #{character_class.inspect}"
401
+ end
402
+ if character_class.kind_of?(String)
403
+ character_class = /[^#{character_class}]/
404
+ end
405
+ # We can't perform regexps on invalid UTF sequences, but
406
+ # here we need to, so switch to ASCII.
407
+ component = component.dup
408
+ component.force_encoding(Encoding::ASCII_8BIT)
409
+ # Avoiding gsub! because there are edge cases with frozen strings
410
+ component = component.gsub(character_class) do |sequence|
411
+ SEQUENCE_UPCASED_PERCENT_ENCODING_TABLE[sequence]
412
+ end
413
+ if upcase_encoded.length > 0
414
+ upcase_encoded_chars = upcase_encoded.chars.map do |char|
415
+ SEQUENCE_ENCODING_TABLE[char]
416
+ end
417
+ component = component.gsub(/%(#{upcase_encoded_chars.join('|')})/,
418
+ &:upcase)
419
+ end
420
+ return component
421
+ end
422
+
423
+ class << self
424
+ alias_method :encode_component, :encode_component
425
+ end
426
+
427
+ ##
428
+ # Unencodes any percent encoded characters within a URI component.
429
+ # This method may be used for unencoding either components or full URIs,
430
+ # however, it is recommended to use the <code>unencode_component</code>
431
+ # alias when unencoding components.
432
+ #
433
+ # @param [String, Addressable::URI, #to_str] uri
434
+ # The URI or component to unencode.
435
+ #
436
+ # @param [Class] return_type
437
+ # The type of object to return.
438
+ # This value may only be set to <code>String</code> or
439
+ # <code>Addressable::URI</code>. All other values are invalid. Defaults
440
+ # to <code>String</code>.
441
+ #
442
+ # @param [String] leave_encoded
443
+ # A string of characters to leave encoded. If a percent encoded character
444
+ # in this list is encountered then it will remain percent encoded.
445
+ #
446
+ # @return [String, Addressable::URI]
447
+ # The unencoded component or URI.
448
+ # The return type is determined by the <code>return_type</code>
449
+ # parameter.
450
+ def self.unencode(uri, return_type=String, leave_encoded='')
451
+ return nil if uri.nil?
452
+
453
+ begin
454
+ uri = uri.to_str
455
+ rescue NoMethodError, TypeError
456
+ raise TypeError, "Can't convert #{uri.class} into String."
457
+ end if !uri.is_a? String
458
+ if ![String, ::Addressable::URI].include?(return_type)
459
+ raise TypeError,
460
+ "Expected Class (String or Addressable::URI), " +
461
+ "got #{return_type.inspect}"
462
+ end
463
+ uri = uri.dup
464
+ # Seriously, only use UTF-8. I'm really not kidding!
465
+ uri.force_encoding("utf-8")
466
+ leave_encoded = leave_encoded.dup.force_encoding("utf-8")
467
+ result = uri.gsub(/%[0-9a-f]{2}/iu) do |sequence|
468
+ c = sequence[1..3].to_i(16).chr
469
+ c.force_encoding("utf-8")
470
+ leave_encoded.include?(c) ? sequence : c
471
+ end
472
+ result.force_encoding("utf-8")
473
+ if return_type == String
474
+ return result
475
+ elsif return_type == ::Addressable::URI
476
+ return ::Addressable::URI.parse(result)
477
+ end
478
+ end
479
+
480
+ class << self
481
+ alias_method :unescape, :unencode
482
+ alias_method :unencode_component, :unencode
483
+ alias_method :unescape_component, :unencode
484
+ end
485
+
486
+
487
+ ##
488
+ # Normalizes the encoding of a URI component.
489
+ #
490
+ # @param [String, #to_str] component The URI component to encode.
491
+ #
492
+ # @param [String, Regexp] character_class
493
+ # The characters which are not percent encoded. If a <code>String</code>
494
+ # is passed, the <code>String</code> must be formatted as a regular
495
+ # expression character class. (Do not include the surrounding square
496
+ # brackets.) For example, <code>"b-zB-Z0-9"</code> would cause
497
+ # everything but the letters 'b' through 'z' and the numbers '0'
498
+ # through '9' to be percent encoded. If a <code>Regexp</code> is passed,
499
+ # the value <code>/[^b-zB-Z0-9]/</code> would have the same effect. A
500
+ # set of useful <code>String</code> values may be found in the
501
+ # <code>Addressable::URI::CharacterClasses</code> module. The default
502
+ # value is the reserved plus unreserved character classes specified in
503
+ # <a href="http://www.ietf.org/rfc/rfc3986.txt">RFC 3986</a>.
504
+ #
505
+ # @param [String] leave_encoded
506
+ # When <code>character_class</code> is a <code>String</code> then
507
+ # <code>leave_encoded</code> is a string of characters that should remain
508
+ # percent encoded while normalizing the component; if they appear percent
509
+ # encoded in the original component, then they will be upcased ("%2f"
510
+ # normalized to "%2F") but otherwise left alone.
511
+ #
512
+ # @return [String] The normalized component.
513
+ #
514
+ # @example
515
+ # Addressable::URI.normalize_component("simpl%65/%65xampl%65", "b-zB-Z")
516
+ # => "simple%2Fex%61mple"
517
+ # Addressable::URI.normalize_component(
518
+ # "simpl%65/%65xampl%65", /[^b-zB-Z]/
519
+ # )
520
+ # => "simple%2Fex%61mple"
521
+ # Addressable::URI.normalize_component(
522
+ # "simpl%65/%65xampl%65",
523
+ # Addressable::URI::CharacterClasses::UNRESERVED
524
+ # )
525
+ # => "simple%2Fexample"
526
+ # Addressable::URI.normalize_component(
527
+ # "one%20two%2fthree%26four",
528
+ # "0-9a-zA-Z &/",
529
+ # "/"
530
+ # )
531
+ # => "one two%2Fthree&four"
532
+ def self.normalize_component(component, character_class=
533
+ CharacterClasses::RESERVED + CharacterClasses::UNRESERVED,
534
+ leave_encoded='')
535
+ return nil if component.nil?
536
+
537
+ begin
538
+ component = component.to_str
539
+ rescue NoMethodError, TypeError
540
+ raise TypeError, "Can't convert #{component.class} into String."
541
+ end if !component.is_a? String
542
+
543
+ if ![String, Regexp].include?(character_class.class)
544
+ raise TypeError,
545
+ "Expected String or Regexp, got #{character_class.inspect}"
546
+ end
547
+ if character_class.kind_of?(String)
548
+ leave_re = if leave_encoded.length > 0
549
+ character_class = "#{character_class}%" unless character_class.include?('%')
550
+
551
+ "|%(?!#{leave_encoded.chars.map do |char|
552
+ seq = SEQUENCE_ENCODING_TABLE[char]
553
+ [seq.upcase, seq.downcase]
554
+ end.flatten.join('|')})"
555
+ end
556
+
557
+ character_class = /[^#{character_class}]#{leave_re}/
558
+ end
559
+ # We can't perform regexps on invalid UTF sequences, but
560
+ # here we need to, so switch to ASCII.
561
+ component = component.dup
562
+ component.force_encoding(Encoding::ASCII_8BIT)
563
+ unencoded = self.unencode_component(component, String, leave_encoded)
564
+ begin
565
+ encoded = self.encode_component(
566
+ Addressable::IDNA.unicode_normalize_kc(unencoded),
567
+ character_class,
568
+ leave_encoded
569
+ )
570
+ rescue ArgumentError
571
+ encoded = self.encode_component(unencoded)
572
+ end
573
+ encoded.force_encoding(Encoding::UTF_8)
574
+ return encoded
575
+ end
576
+
577
+ ##
578
+ # Percent encodes any special characters in the URI.
579
+ #
580
+ # @param [String, Addressable::URI, #to_str] uri
581
+ # The URI to encode.
582
+ #
583
+ # @param [Class] return_type
584
+ # The type of object to return.
585
+ # This value may only be set to <code>String</code> or
586
+ # <code>Addressable::URI</code>. All other values are invalid. Defaults
587
+ # to <code>String</code>.
588
+ #
589
+ # @return [String, Addressable::URI]
590
+ # The encoded URI.
591
+ # The return type is determined by the <code>return_type</code>
592
+ # parameter.
593
+ def self.encode(uri, return_type=String)
594
+ return nil if uri.nil?
595
+
596
+ begin
597
+ uri = uri.to_str
598
+ rescue NoMethodError, TypeError
599
+ raise TypeError, "Can't convert #{uri.class} into String."
600
+ end if !uri.is_a? String
601
+
602
+ if ![String, ::Addressable::URI].include?(return_type)
603
+ raise TypeError,
604
+ "Expected Class (String or Addressable::URI), " +
605
+ "got #{return_type.inspect}"
606
+ end
607
+ uri_object = uri.kind_of?(self) ? uri : self.parse(uri)
608
+ encoded_uri = Addressable::URI.new(
609
+ :scheme => self.encode_component(uri_object.scheme,
610
+ Addressable::URI::CharacterClasses::SCHEME),
611
+ :authority => self.encode_component(uri_object.authority,
612
+ Addressable::URI::CharacterClasses::AUTHORITY),
613
+ :path => self.encode_component(uri_object.path,
614
+ Addressable::URI::CharacterClasses::PATH),
615
+ :query => self.encode_component(uri_object.query,
616
+ Addressable::URI::CharacterClasses::QUERY),
617
+ :fragment => self.encode_component(uri_object.fragment,
618
+ Addressable::URI::CharacterClasses::FRAGMENT)
619
+ )
620
+ if return_type == String
621
+ return encoded_uri.to_s
622
+ elsif return_type == ::Addressable::URI
623
+ return encoded_uri
624
+ end
625
+ end
626
+
627
+ class << self
628
+ alias_method :escape, :encode
629
+ end
630
+
631
+ ##
632
+ # Normalizes the encoding of a URI. Characters within a hostname are
633
+ # not percent encoded to allow for internationalized domain names.
634
+ #
635
+ # @param [String, Addressable::URI, #to_str] uri
636
+ # The URI to encode.
637
+ #
638
+ # @param [Class] return_type
639
+ # The type of object to return.
640
+ # This value may only be set to <code>String</code> or
641
+ # <code>Addressable::URI</code>. All other values are invalid. Defaults
642
+ # to <code>String</code>.
643
+ #
644
+ # @return [String, Addressable::URI]
645
+ # The encoded URI.
646
+ # The return type is determined by the <code>return_type</code>
647
+ # parameter.
648
+ def self.normalized_encode(uri, return_type=String)
649
+ begin
650
+ uri = uri.to_str
651
+ rescue NoMethodError, TypeError
652
+ raise TypeError, "Can't convert #{uri.class} into String."
653
+ end if !uri.is_a? String
654
+
655
+ if ![String, ::Addressable::URI].include?(return_type)
656
+ raise TypeError,
657
+ "Expected Class (String or Addressable::URI), " +
658
+ "got #{return_type.inspect}"
659
+ end
660
+ uri_object = uri.kind_of?(self) ? uri : self.parse(uri)
661
+ components = {
662
+ :scheme => self.unencode_component(uri_object.scheme),
663
+ :user => self.unencode_component(uri_object.user),
664
+ :password => self.unencode_component(uri_object.password),
665
+ :host => self.unencode_component(uri_object.host),
666
+ :port => (uri_object.port.nil? ? nil : uri_object.port.to_s),
667
+ :path => self.unencode_component(uri_object.path),
668
+ :query => self.unencode_component(uri_object.query),
669
+ :fragment => self.unencode_component(uri_object.fragment)
670
+ }
671
+ components.each do |key, value|
672
+ if value != nil
673
+ begin
674
+ components[key] =
675
+ Addressable::IDNA.unicode_normalize_kc(value.to_str)
676
+ rescue ArgumentError
677
+ # Likely a malformed UTF-8 character, skip unicode normalization
678
+ components[key] = value.to_str
679
+ end
680
+ end
681
+ end
682
+ encoded_uri = Addressable::URI.new(
683
+ :scheme => self.encode_component(components[:scheme],
684
+ Addressable::URI::CharacterClasses::SCHEME),
685
+ :user => self.encode_component(components[:user],
686
+ Addressable::URI::CharacterClasses::UNRESERVED),
687
+ :password => self.encode_component(components[:password],
688
+ Addressable::URI::CharacterClasses::UNRESERVED),
689
+ :host => components[:host],
690
+ :port => components[:port],
691
+ :path => self.encode_component(components[:path],
692
+ Addressable::URI::CharacterClasses::PATH),
693
+ :query => self.encode_component(components[:query],
694
+ Addressable::URI::CharacterClasses::QUERY),
695
+ :fragment => self.encode_component(components[:fragment],
696
+ Addressable::URI::CharacterClasses::FRAGMENT)
697
+ )
698
+ if return_type == String
699
+ return encoded_uri.to_s
700
+ elsif return_type == ::Addressable::URI
701
+ return encoded_uri
702
+ end
703
+ end
704
+
705
+ ##
706
+ # Encodes a set of key/value pairs according to the rules for the
707
+ # <code>application/x-www-form-urlencoded</code> MIME type.
708
+ #
709
+ # @param [#to_hash, #to_ary] form_values
710
+ # The form values to encode.
711
+ #
712
+ # @param [TrueClass, FalseClass] sort
713
+ # Sort the key/value pairs prior to encoding.
714
+ # Defaults to <code>false</code>.
715
+ #
716
+ # @return [String]
717
+ # The encoded value.
718
+ def self.form_encode(form_values, sort=false)
719
+ if form_values.respond_to?(:to_hash)
720
+ form_values = form_values.to_hash.to_a
721
+ elsif form_values.respond_to?(:to_ary)
722
+ form_values = form_values.to_ary
723
+ else
724
+ raise TypeError, "Can't convert #{form_values.class} into Array."
725
+ end
726
+
727
+ form_values = form_values.inject([]) do |accu, (key, value)|
728
+ if value.kind_of?(Array)
729
+ value.each do |v|
730
+ accu << [key.to_s, v.to_s]
731
+ end
732
+ else
733
+ accu << [key.to_s, value.to_s]
734
+ end
735
+ accu
736
+ end
737
+
738
+ if sort
739
+ # Useful for OAuth and optimizing caching systems
740
+ form_values = form_values.sort
741
+ end
742
+ escaped_form_values = form_values.map do |(key, value)|
743
+ # Line breaks are CRLF pairs
744
+ [
745
+ self.encode_component(
746
+ key.gsub(/(\r\n|\n|\r)/, "\r\n"),
747
+ CharacterClasses::UNRESERVED
748
+ ).gsub("%20", "+"),
749
+ self.encode_component(
750
+ value.gsub(/(\r\n|\n|\r)/, "\r\n"),
751
+ CharacterClasses::UNRESERVED
752
+ ).gsub("%20", "+")
753
+ ]
754
+ end
755
+ return escaped_form_values.map do |(key, value)|
756
+ "#{key}=#{value}"
757
+ end.join("&")
758
+ end
759
+
760
+ ##
761
+ # Decodes a <code>String</code> according to the rules for the
762
+ # <code>application/x-www-form-urlencoded</code> MIME type.
763
+ #
764
+ # @param [String, #to_str] encoded_value
765
+ # The form values to decode.
766
+ #
767
+ # @return [Array]
768
+ # The decoded values.
769
+ # This is not a <code>Hash</code> because of the possibility for
770
+ # duplicate keys.
771
+ def self.form_unencode(encoded_value)
772
+ if !encoded_value.respond_to?(:to_str)
773
+ raise TypeError, "Can't convert #{encoded_value.class} into String."
774
+ end
775
+ encoded_value = encoded_value.to_str
776
+ split_values = encoded_value.split("&").map do |pair|
777
+ pair.split("=", 2)
778
+ end
779
+ return split_values.map do |(key, value)|
780
+ [
781
+ key ? self.unencode_component(
782
+ key.gsub("+", "%20")).gsub(/(\r\n|\n|\r)/, "\n") : nil,
783
+ value ? (self.unencode_component(
784
+ value.gsub("+", "%20")).gsub(/(\r\n|\n|\r)/, "\n")) : nil
785
+ ]
786
+ end
787
+ end
788
+
789
+ ##
790
+ # Creates a new uri object from component parts.
791
+ #
792
+ # @option [String, #to_str] scheme The scheme component.
793
+ # @option [String, #to_str] user The user component.
794
+ # @option [String, #to_str] password The password component.
795
+ # @option [String, #to_str] userinfo
796
+ # The userinfo component. If this is supplied, the user and password
797
+ # components must be omitted.
798
+ # @option [String, #to_str] host The host component.
799
+ # @option [String, #to_str] port The port component.
800
+ # @option [String, #to_str] authority
801
+ # The authority component. If this is supplied, the user, password,
802
+ # userinfo, host, and port components must be omitted.
803
+ # @option [String, #to_str] path The path component.
804
+ # @option [String, #to_str] query The query component.
805
+ # @option [String, #to_str] fragment The fragment component.
806
+ #
807
+ # @return [Addressable::URI] The constructed URI object.
808
+ def initialize(options={})
809
+ if options.has_key?(:authority)
810
+ if (options.keys & [:userinfo, :user, :password, :host, :port]).any?
811
+ raise ArgumentError,
812
+ "Cannot specify both an authority and any of the components " +
813
+ "within the authority."
814
+ end
815
+ end
816
+ if options.has_key?(:userinfo)
817
+ if (options.keys & [:user, :password]).any?
818
+ raise ArgumentError,
819
+ "Cannot specify both a userinfo and either the user or password."
820
+ end
821
+ end
822
+
823
+ self.defer_validation do
824
+ # Bunch of crazy logic required because of the composite components
825
+ # like userinfo and authority.
826
+ self.scheme = options[:scheme] if options[:scheme]
827
+ self.user = options[:user] if options[:user]
828
+ self.password = options[:password] if options[:password]
829
+ self.userinfo = options[:userinfo] if options[:userinfo]
830
+ self.host = options[:host] if options[:host]
831
+ self.port = options[:port] if options[:port]
832
+ self.authority = options[:authority] if options[:authority]
833
+ self.path = options[:path] if options[:path]
834
+ self.query = options[:query] if options[:query]
835
+ self.query_values = options[:query_values] if options[:query_values]
836
+ self.fragment = options[:fragment] if options[:fragment]
837
+ end
838
+ self.to_s
839
+ end
840
+
841
+ ##
842
+ # Freeze URI, initializing instance variables.
843
+ #
844
+ # @return [Addressable::URI] The frozen URI object.
845
+ def freeze
846
+ self.normalized_scheme
847
+ self.normalized_user
848
+ self.normalized_password
849
+ self.normalized_userinfo
850
+ self.normalized_host
851
+ self.normalized_port
852
+ self.normalized_authority
853
+ self.normalized_site
854
+ self.normalized_path
855
+ self.normalized_query
856
+ self.normalized_fragment
857
+ self.hash
858
+ super
859
+ end
860
+
861
+ ##
862
+ # The scheme component for this URI.
863
+ #
864
+ # @return [String] The scheme component.
865
+ def scheme
866
+ return defined?(@scheme) ? @scheme : nil
867
+ end
868
+
869
+ ##
870
+ # The scheme component for this URI, normalized.
871
+ #
872
+ # @return [String] The scheme component, normalized.
873
+ def normalized_scheme
874
+ return nil unless self.scheme
875
+ @normalized_scheme ||= begin
876
+ if self.scheme =~ /^\s*ssh\+svn\s*$/i
877
+ "svn+ssh".dup
878
+ else
879
+ Addressable::URI.normalize_component(
880
+ self.scheme.strip.downcase,
881
+ Addressable::URI::CharacterClasses::SCHEME
882
+ )
883
+ end
884
+ end
885
+ # All normalized values should be UTF-8
886
+ @normalized_scheme.force_encoding(Encoding::UTF_8) if @normalized_scheme
887
+ @normalized_scheme
888
+ end
889
+
890
+ ##
891
+ # Sets the scheme component for this URI.
892
+ #
893
+ # @param [String, #to_str] new_scheme The new scheme component.
894
+ def scheme=(new_scheme)
895
+ if new_scheme && !new_scheme.respond_to?(:to_str)
896
+ raise TypeError, "Can't convert #{new_scheme.class} into String."
897
+ elsif new_scheme
898
+ new_scheme = new_scheme.to_str
899
+ end
900
+ if new_scheme && new_scheme !~ /\A[a-z][a-z0-9\.\+\-]*\z/i
901
+ raise InvalidURIError, "Invalid scheme format: #{new_scheme}"
902
+ end
903
+ @scheme = new_scheme
904
+ @scheme = nil if @scheme.to_s.strip.empty?
905
+
906
+ # Reset dependent values
907
+ remove_instance_variable(:@normalized_scheme) if defined?(@normalized_scheme)
908
+ remove_composite_values
909
+
910
+ # Ensure we haven't created an invalid URI
911
+ validate()
912
+ end
913
+
914
+ ##
915
+ # The user component for this URI.
916
+ #
917
+ # @return [String] The user component.
918
+ def user
919
+ return defined?(@user) ? @user : nil
920
+ end
921
+
922
+ ##
923
+ # The user component for this URI, normalized.
924
+ #
925
+ # @return [String] The user component, normalized.
926
+ def normalized_user
927
+ return nil unless self.user
928
+ return @normalized_user if defined?(@normalized_user)
929
+ @normalized_user ||= begin
930
+ if normalized_scheme =~ /https?/ && self.user.strip.empty? &&
931
+ (!self.password || self.password.strip.empty?)
932
+ nil
933
+ else
934
+ Addressable::URI.normalize_component(
935
+ self.user.strip,
936
+ Addressable::URI::CharacterClasses::UNRESERVED
937
+ )
938
+ end
939
+ end
940
+ # All normalized values should be UTF-8
941
+ @normalized_user.force_encoding(Encoding::UTF_8) if @normalized_user
942
+ @normalized_user
943
+ end
944
+
945
+ ##
946
+ # Sets the user component for this URI.
947
+ #
948
+ # @param [String, #to_str] new_user The new user component.
949
+ def user=(new_user)
950
+ if new_user && !new_user.respond_to?(:to_str)
951
+ raise TypeError, "Can't convert #{new_user.class} into String."
952
+ end
953
+ @user = new_user ? new_user.to_str : nil
954
+
955
+ # You can't have a nil user with a non-nil password
956
+ if password != nil
957
+ @user = EMPTY_STR if @user.nil?
958
+ end
959
+
960
+ # Reset dependent values
961
+ remove_instance_variable(:@userinfo) if defined?(@userinfo)
962
+ remove_instance_variable(:@normalized_userinfo) if defined?(@normalized_userinfo)
963
+ remove_instance_variable(:@authority) if defined?(@authority)
964
+ remove_instance_variable(:@normalized_user) if defined?(@normalized_user)
965
+ remove_composite_values
966
+
967
+ # Ensure we haven't created an invalid URI
968
+ validate()
969
+ end
970
+
971
+ ##
972
+ # The password component for this URI.
973
+ #
974
+ # @return [String] The password component.
975
+ def password
976
+ return defined?(@password) ? @password : nil
977
+ end
978
+
979
+ ##
980
+ # The password component for this URI, normalized.
981
+ #
982
+ # @return [String] The password component, normalized.
983
+ def normalized_password
984
+ return nil unless self.password
985
+ return @normalized_password if defined?(@normalized_password)
986
+ @normalized_password ||= begin
987
+ if self.normalized_scheme =~ /https?/ && self.password.strip.empty? &&
988
+ (!self.user || self.user.strip.empty?)
989
+ nil
990
+ else
991
+ Addressable::URI.normalize_component(
992
+ self.password.strip,
993
+ Addressable::URI::CharacterClasses::UNRESERVED
994
+ )
995
+ end
996
+ end
997
+ # All normalized values should be UTF-8
998
+ if @normalized_password
999
+ @normalized_password.force_encoding(Encoding::UTF_8)
1000
+ end
1001
+ @normalized_password
1002
+ end
1003
+
1004
+ ##
1005
+ # Sets the password component for this URI.
1006
+ #
1007
+ # @param [String, #to_str] new_password The new password component.
1008
+ def password=(new_password)
1009
+ if new_password && !new_password.respond_to?(:to_str)
1010
+ raise TypeError, "Can't convert #{new_password.class} into String."
1011
+ end
1012
+ @password = new_password ? new_password.to_str : nil
1013
+
1014
+ # You can't have a nil user with a non-nil password
1015
+ @password ||= nil
1016
+ @user ||= nil
1017
+ if @password != nil
1018
+ @user = EMPTY_STR if @user.nil?
1019
+ end
1020
+
1021
+ # Reset dependent values
1022
+ remove_instance_variable(:@userinfo) if defined?(@userinfo)
1023
+ remove_instance_variable(:@normalized_userinfo) if defined?(@normalized_userinfo)
1024
+ remove_instance_variable(:@authority) if defined?(@authority)
1025
+ remove_instance_variable(:@normalized_password) if defined?(@normalized_password)
1026
+ remove_composite_values
1027
+
1028
+ # Ensure we haven't created an invalid URI
1029
+ validate()
1030
+ end
1031
+
1032
+ ##
1033
+ # The userinfo component for this URI.
1034
+ # Combines the user and password components.
1035
+ #
1036
+ # @return [String] The userinfo component.
1037
+ def userinfo
1038
+ current_user = self.user
1039
+ current_password = self.password
1040
+ (current_user || current_password) && @userinfo ||= begin
1041
+ if current_user && current_password
1042
+ "#{current_user}:#{current_password}"
1043
+ elsif current_user && !current_password
1044
+ "#{current_user}"
1045
+ end
1046
+ end
1047
+ end
1048
+
1049
+ ##
1050
+ # The userinfo component for this URI, normalized.
1051
+ #
1052
+ # @return [String] The userinfo component, normalized.
1053
+ def normalized_userinfo
1054
+ return nil unless self.userinfo
1055
+ return @normalized_userinfo if defined?(@normalized_userinfo)
1056
+ @normalized_userinfo ||= begin
1057
+ current_user = self.normalized_user
1058
+ current_password = self.normalized_password
1059
+ if !current_user && !current_password
1060
+ nil
1061
+ elsif current_user && current_password
1062
+ "#{current_user}:#{current_password}".dup
1063
+ elsif current_user && !current_password
1064
+ "#{current_user}".dup
1065
+ end
1066
+ end
1067
+ # All normalized values should be UTF-8
1068
+ if @normalized_userinfo
1069
+ @normalized_userinfo.force_encoding(Encoding::UTF_8)
1070
+ end
1071
+ @normalized_userinfo
1072
+ end
1073
+
1074
+ ##
1075
+ # Sets the userinfo component for this URI.
1076
+ #
1077
+ # @param [String, #to_str] new_userinfo The new userinfo component.
1078
+ def userinfo=(new_userinfo)
1079
+ if new_userinfo && !new_userinfo.respond_to?(:to_str)
1080
+ raise TypeError, "Can't convert #{new_userinfo.class} into String."
1081
+ end
1082
+ new_user, new_password = if new_userinfo
1083
+ [
1084
+ new_userinfo.to_str.strip[/^(.*):/, 1],
1085
+ new_userinfo.to_str.strip[/:(.*)$/, 1]
1086
+ ]
1087
+ else
1088
+ [nil, nil]
1089
+ end
1090
+
1091
+ # Password assigned first to ensure validity in case of nil
1092
+ self.password = new_password
1093
+ self.user = new_user
1094
+
1095
+ # Reset dependent values
1096
+ remove_instance_variable(:@authority) if defined?(@authority)
1097
+ remove_composite_values
1098
+
1099
+ # Ensure we haven't created an invalid URI
1100
+ validate()
1101
+ end
1102
+
1103
+ ##
1104
+ # The host component for this URI.
1105
+ #
1106
+ # @return [String] The host component.
1107
+ def host
1108
+ return defined?(@host) ? @host : nil
1109
+ end
1110
+
1111
+ ##
1112
+ # The host component for this URI, normalized.
1113
+ #
1114
+ # @return [String] The host component, normalized.
1115
+ def normalized_host
1116
+ return nil unless self.host
1117
+ @normalized_host ||= begin
1118
+ if !self.host.strip.empty?
1119
+ result = ::Addressable::IDNA.to_ascii(
1120
+ URI.unencode_component(self.host.strip.downcase)
1121
+ )
1122
+ if result =~ /[^\.]\.$/
1123
+ # Single trailing dots are unnecessary.
1124
+ result = result[0...-1]
1125
+ end
1126
+ result = Addressable::URI.normalize_component(
1127
+ result,
1128
+ CharacterClasses::HOST)
1129
+ result
1130
+ else
1131
+ EMPTY_STR.dup
1132
+ end
1133
+ end
1134
+ # All normalized values should be UTF-8
1135
+ @normalized_host.force_encoding(Encoding::UTF_8) if @normalized_host
1136
+ @normalized_host
1137
+ end
1138
+
1139
+ ##
1140
+ # Sets the host component for this URI.
1141
+ #
1142
+ # @param [String, #to_str] new_host The new host component.
1143
+ def host=(new_host)
1144
+ if new_host && !new_host.respond_to?(:to_str)
1145
+ raise TypeError, "Can't convert #{new_host.class} into String."
1146
+ end
1147
+ @host = new_host ? new_host.to_str : nil
1148
+
1149
+ # Reset dependent values
1150
+ remove_instance_variable(:@authority) if defined?(@authority)
1151
+ remove_instance_variable(:@normalized_host) if defined?(@normalized_host)
1152
+ remove_composite_values
1153
+
1154
+ # Ensure we haven't created an invalid URI
1155
+ validate()
1156
+ end
1157
+
1158
+ ##
1159
+ # This method is same as URI::Generic#host except
1160
+ # brackets for IPv6 (and 'IPvFuture') addresses are removed.
1161
+ #
1162
+ # @see Addressable::URI#host
1163
+ #
1164
+ # @return [String] The hostname for this URI.
1165
+ def hostname
1166
+ v = self.host
1167
+ /\A\[(.*)\]\z/ =~ v ? $1 : v
1168
+ end
1169
+
1170
+ ##
1171
+ # This method is same as URI::Generic#host= except
1172
+ # the argument can be a bare IPv6 address (or 'IPvFuture').
1173
+ #
1174
+ # @see Addressable::URI#host=
1175
+ #
1176
+ # @param [String, #to_str] new_hostname The new hostname for this URI.
1177
+ def hostname=(new_hostname)
1178
+ if new_hostname &&
1179
+ (new_hostname.respond_to?(:ipv4?) || new_hostname.respond_to?(:ipv6?))
1180
+ new_hostname = new_hostname.to_s
1181
+ elsif new_hostname && !new_hostname.respond_to?(:to_str)
1182
+ raise TypeError, "Can't convert #{new_hostname.class} into String."
1183
+ end
1184
+ v = new_hostname ? new_hostname.to_str : nil
1185
+ v = "[#{v}]" if /\A\[.*\]\z/ !~ v && /:/ =~ v
1186
+ self.host = v
1187
+ end
1188
+
1189
+ ##
1190
+ # Returns the top-level domain for this host.
1191
+ #
1192
+ # @example
1193
+ # Addressable::URI.parse("http://www.example.co.uk").tld # => "co.uk"
1194
+ def tld
1195
+ PublicSuffix.parse(self.host, ignore_private: true).tld
1196
+ end
1197
+
1198
+ ##
1199
+ # Sets the top-level domain for this URI.
1200
+ #
1201
+ # @param [String, #to_str] new_tld The new top-level domain.
1202
+ def tld=(new_tld)
1203
+ replaced_tld = host.sub(/#{tld}\z/, new_tld)
1204
+ self.host = PublicSuffix::Domain.new(replaced_tld).to_s
1205
+ end
1206
+
1207
+ ##
1208
+ # Returns the public suffix domain for this host.
1209
+ #
1210
+ # @example
1211
+ # Addressable::URI.parse("http://www.example.co.uk").domain # => "example.co.uk"
1212
+ def domain
1213
+ PublicSuffix.domain(self.host, ignore_private: true)
1214
+ end
1215
+
1216
+ ##
1217
+ # The authority component for this URI.
1218
+ # Combines the user, password, host, and port components.
1219
+ #
1220
+ # @return [String] The authority component.
1221
+ def authority
1222
+ self.host && @authority ||= begin
1223
+ authority = String.new
1224
+ if self.userinfo != nil
1225
+ authority << "#{self.userinfo}@"
1226
+ end
1227
+ authority << self.host
1228
+ if self.port != nil
1229
+ authority << ":#{self.port}"
1230
+ end
1231
+ authority
1232
+ end
1233
+ end
1234
+
1235
+ ##
1236
+ # The authority component for this URI, normalized.
1237
+ #
1238
+ # @return [String] The authority component, normalized.
1239
+ def normalized_authority
1240
+ return nil unless self.authority
1241
+ @normalized_authority ||= begin
1242
+ authority = String.new
1243
+ if self.normalized_userinfo != nil
1244
+ authority << "#{self.normalized_userinfo}@"
1245
+ end
1246
+ authority << self.normalized_host
1247
+ if self.normalized_port != nil
1248
+ authority << ":#{self.normalized_port}"
1249
+ end
1250
+ authority
1251
+ end
1252
+ # All normalized values should be UTF-8
1253
+ if @normalized_authority
1254
+ @normalized_authority.force_encoding(Encoding::UTF_8)
1255
+ end
1256
+ @normalized_authority
1257
+ end
1258
+
1259
+ ##
1260
+ # Sets the authority component for this URI.
1261
+ #
1262
+ # @param [String, #to_str] new_authority The new authority component.
1263
+ def authority=(new_authority)
1264
+ if new_authority
1265
+ if !new_authority.respond_to?(:to_str)
1266
+ raise TypeError, "Can't convert #{new_authority.class} into String."
1267
+ end
1268
+ new_authority = new_authority.to_str
1269
+ new_userinfo = new_authority[/^([^\[\]]*)@/, 1]
1270
+ if new_userinfo
1271
+ new_user = new_userinfo.strip[/^([^:]*):?/, 1]
1272
+ new_password = new_userinfo.strip[/:(.*)$/, 1]
1273
+ end
1274
+ new_host = new_authority.sub(
1275
+ /^([^\[\]]*)@/, EMPTY_STR
1276
+ ).sub(
1277
+ /:([^:@\[\]]*?)$/, EMPTY_STR
1278
+ )
1279
+ new_port =
1280
+ new_authority[/:([^:@\[\]]*?)$/, 1]
1281
+ end
1282
+
1283
+ # Password assigned first to ensure validity in case of nil
1284
+ self.password = defined?(new_password) ? new_password : nil
1285
+ self.user = defined?(new_user) ? new_user : nil
1286
+ self.host = defined?(new_host) ? new_host : nil
1287
+ self.port = defined?(new_port) ? new_port : nil
1288
+
1289
+ # Reset dependent values
1290
+ remove_instance_variable(:@userinfo) if defined?(@userinfo)
1291
+ remove_instance_variable(:@normalized_userinfo) if defined?(@normalized_userinfo)
1292
+ remove_composite_values
1293
+
1294
+ # Ensure we haven't created an invalid URI
1295
+ validate()
1296
+ end
1297
+
1298
+ ##
1299
+ # The origin for this URI, serialized to ASCII, as per
1300
+ # RFC 6454, section 6.2.
1301
+ #
1302
+ # @return [String] The serialized origin.
1303
+ def origin
1304
+ if self.scheme && self.authority
1305
+ if self.normalized_port
1306
+ "#{self.normalized_scheme}://#{self.normalized_host}" +
1307
+ ":#{self.normalized_port}"
1308
+ else
1309
+ "#{self.normalized_scheme}://#{self.normalized_host}"
1310
+ end
1311
+ else
1312
+ "null"
1313
+ end
1314
+ end
1315
+
1316
+ ##
1317
+ # Sets the origin for this URI, serialized to ASCII, as per
1318
+ # RFC 6454, section 6.2. This assignment will reset the `userinfo`
1319
+ # component.
1320
+ #
1321
+ # @param [String, #to_str] new_origin The new origin component.
1322
+ def origin=(new_origin)
1323
+ if new_origin
1324
+ if !new_origin.respond_to?(:to_str)
1325
+ raise TypeError, "Can't convert #{new_origin.class} into String."
1326
+ end
1327
+ new_origin = new_origin.to_str
1328
+ new_scheme = new_origin[/^([^:\/?#]+):\/\//, 1]
1329
+ unless new_scheme
1330
+ raise InvalidURIError, 'An origin cannot omit the scheme.'
1331
+ end
1332
+ new_host = new_origin[/:\/\/([^\/?#:]+)/, 1]
1333
+ unless new_host
1334
+ raise InvalidURIError, 'An origin cannot omit the host.'
1335
+ end
1336
+ new_port = new_origin[/:([^:@\[\]\/]*?)$/, 1]
1337
+ end
1338
+
1339
+ self.scheme = defined?(new_scheme) ? new_scheme : nil
1340
+ self.host = defined?(new_host) ? new_host : nil
1341
+ self.port = defined?(new_port) ? new_port : nil
1342
+ self.userinfo = nil
1343
+
1344
+ # Reset dependent values
1345
+ remove_instance_variable(:@userinfo) if defined?(@userinfo)
1346
+ remove_instance_variable(:@normalized_userinfo) if defined?(@normalized_userinfo)
1347
+ remove_instance_variable(:@authority) if defined?(@authority)
1348
+ remove_instance_variable(:@normalized_authority) if defined?(@normalized_authority)
1349
+ remove_composite_values
1350
+
1351
+ # Ensure we haven't created an invalid URI
1352
+ validate()
1353
+ end
1354
+
1355
+ # Returns an array of known ip-based schemes. These schemes typically
1356
+ # use a similar URI form:
1357
+ # <code>//<user>:<password>@<host>:<port>/<url-path></code>
1358
+ def self.ip_based_schemes
1359
+ return self.port_mapping.keys
1360
+ end
1361
+
1362
+ # Returns a hash of common IP-based schemes and their default port
1363
+ # numbers. Adding new schemes to this hash, as necessary, will allow
1364
+ # for better URI normalization.
1365
+ def self.port_mapping
1366
+ PORT_MAPPING
1367
+ end
1368
+
1369
+ ##
1370
+ # The port component for this URI.
1371
+ # This is the port number actually given in the URI. This does not
1372
+ # infer port numbers from default values.
1373
+ #
1374
+ # @return [Integer] The port component.
1375
+ def port
1376
+ return defined?(@port) ? @port : nil
1377
+ end
1378
+
1379
+ ##
1380
+ # The port component for this URI, normalized.
1381
+ #
1382
+ # @return [Integer] The port component, normalized.
1383
+ def normalized_port
1384
+ return nil unless self.port
1385
+ return @normalized_port if defined?(@normalized_port)
1386
+ @normalized_port ||= begin
1387
+ if URI.port_mapping[self.normalized_scheme] == self.port
1388
+ nil
1389
+ else
1390
+ self.port
1391
+ end
1392
+ end
1393
+ end
1394
+
1395
+ ##
1396
+ # Sets the port component for this URI.
1397
+ #
1398
+ # @param [String, Integer, #to_s] new_port The new port component.
1399
+ def port=(new_port)
1400
+ if new_port != nil && new_port.respond_to?(:to_str)
1401
+ new_port = Addressable::URI.unencode_component(new_port.to_str)
1402
+ end
1403
+
1404
+ if new_port.respond_to?(:valid_encoding?) && !new_port.valid_encoding?
1405
+ raise InvalidURIError, "Invalid encoding in port"
1406
+ end
1407
+
1408
+ if new_port != nil && !(new_port.to_s =~ /^\d+$/)
1409
+ raise InvalidURIError,
1410
+ "Invalid port number: #{new_port.inspect}"
1411
+ end
1412
+
1413
+ @port = new_port.to_s.to_i
1414
+ @port = nil if @port == 0
1415
+
1416
+ # Reset dependent values
1417
+ remove_instance_variable(:@authority) if defined?(@authority)
1418
+ remove_instance_variable(:@normalized_port) if defined?(@normalized_port)
1419
+ remove_composite_values
1420
+
1421
+ # Ensure we haven't created an invalid URI
1422
+ validate()
1423
+ end
1424
+
1425
+ ##
1426
+ # The inferred port component for this URI.
1427
+ # This method will normalize to the default port for the URI's scheme if
1428
+ # the port isn't explicitly specified in the URI.
1429
+ #
1430
+ # @return [Integer] The inferred port component.
1431
+ def inferred_port
1432
+ if self.port.to_i == 0
1433
+ self.default_port
1434
+ else
1435
+ self.port.to_i
1436
+ end
1437
+ end
1438
+
1439
+ ##
1440
+ # The default port for this URI's scheme.
1441
+ # This method will always returns the default port for the URI's scheme
1442
+ # regardless of the presence of an explicit port in the URI.
1443
+ #
1444
+ # @return [Integer] The default port.
1445
+ def default_port
1446
+ URI.port_mapping[self.scheme.strip.downcase] if self.scheme
1447
+ end
1448
+
1449
+ ##
1450
+ # The combination of components that represent a site.
1451
+ # Combines the scheme, user, password, host, and port components.
1452
+ # Primarily useful for HTTP and HTTPS.
1453
+ #
1454
+ # For example, <code>"http://example.com/path?query"</code> would have a
1455
+ # <code>site</code> value of <code>"http://example.com"</code>.
1456
+ #
1457
+ # @return [String] The components that identify a site.
1458
+ def site
1459
+ (self.scheme || self.authority) && @site ||= begin
1460
+ site_string = "".dup
1461
+ site_string << "#{self.scheme}:" if self.scheme != nil
1462
+ site_string << "//#{self.authority}" if self.authority != nil
1463
+ site_string
1464
+ end
1465
+ end
1466
+
1467
+ ##
1468
+ # The normalized combination of components that represent a site.
1469
+ # Combines the scheme, user, password, host, and port components.
1470
+ # Primarily useful for HTTP and HTTPS.
1471
+ #
1472
+ # For example, <code>"http://example.com/path?query"</code> would have a
1473
+ # <code>site</code> value of <code>"http://example.com"</code>.
1474
+ #
1475
+ # @return [String] The normalized components that identify a site.
1476
+ def normalized_site
1477
+ return nil unless self.site
1478
+ @normalized_site ||= begin
1479
+ site_string = "".dup
1480
+ if self.normalized_scheme != nil
1481
+ site_string << "#{self.normalized_scheme}:"
1482
+ end
1483
+ if self.normalized_authority != nil
1484
+ site_string << "//#{self.normalized_authority}"
1485
+ end
1486
+ site_string
1487
+ end
1488
+ # All normalized values should be UTF-8
1489
+ @normalized_site.force_encoding(Encoding::UTF_8) if @normalized_site
1490
+ @normalized_site
1491
+ end
1492
+
1493
+ ##
1494
+ # Sets the site value for this URI.
1495
+ #
1496
+ # @param [String, #to_str] new_site The new site value.
1497
+ def site=(new_site)
1498
+ if new_site
1499
+ if !new_site.respond_to?(:to_str)
1500
+ raise TypeError, "Can't convert #{new_site.class} into String."
1501
+ end
1502
+ new_site = new_site.to_str
1503
+ # These two regular expressions derived from the primary parsing
1504
+ # expression
1505
+ self.scheme = new_site[/^(?:([^:\/?#]+):)?(?:\/\/(?:[^\/?#]*))?$/, 1]
1506
+ self.authority = new_site[
1507
+ /^(?:(?:[^:\/?#]+):)?(?:\/\/([^\/?#]*))?$/, 1
1508
+ ]
1509
+ else
1510
+ self.scheme = nil
1511
+ self.authority = nil
1512
+ end
1513
+ end
1514
+
1515
+ ##
1516
+ # The path component for this URI.
1517
+ #
1518
+ # @return [String] The path component.
1519
+ def path
1520
+ return defined?(@path) ? @path : EMPTY_STR
1521
+ end
1522
+
1523
+ NORMPATH = /^(?!\/)[^\/:]*:.*$/
1524
+ ##
1525
+ # The path component for this URI, normalized.
1526
+ #
1527
+ # @return [String] The path component, normalized.
1528
+ def normalized_path
1529
+ @normalized_path ||= begin
1530
+ path = self.path.to_s
1531
+ if self.scheme == nil && path =~ NORMPATH
1532
+ # Relative paths with colons in the first segment are ambiguous.
1533
+ path = path.sub(":", "%2F")
1534
+ end
1535
+ # String#split(delimeter, -1) uses the more strict splitting behavior
1536
+ # found by default in Python.
1537
+ result = path.strip.split(SLASH, -1).map do |segment|
1538
+ Addressable::URI.normalize_component(
1539
+ segment,
1540
+ Addressable::URI::CharacterClasses::PCHAR
1541
+ )
1542
+ end.join(SLASH)
1543
+
1544
+ result = URI.normalize_path(result)
1545
+ if result.empty? &&
1546
+ ["http", "https", "ftp", "tftp"].include?(self.normalized_scheme)
1547
+ result = SLASH.dup
1548
+ end
1549
+ result
1550
+ end
1551
+ # All normalized values should be UTF-8
1552
+ @normalized_path.force_encoding(Encoding::UTF_8) if @normalized_path
1553
+ @normalized_path
1554
+ end
1555
+
1556
+ ##
1557
+ # Sets the path component for this URI.
1558
+ #
1559
+ # @param [String, #to_str] new_path The new path component.
1560
+ def path=(new_path)
1561
+ if new_path && !new_path.respond_to?(:to_str)
1562
+ raise TypeError, "Can't convert #{new_path.class} into String."
1563
+ end
1564
+ @path = (new_path || EMPTY_STR).to_str
1565
+ if !@path.empty? && @path[0..0] != SLASH && host != nil
1566
+ @path = "/#{@path}"
1567
+ end
1568
+
1569
+ # Reset dependent values
1570
+ remove_instance_variable(:@normalized_path) if defined?(@normalized_path)
1571
+ remove_composite_values
1572
+
1573
+ # Ensure we haven't created an invalid URI
1574
+ validate()
1575
+ end
1576
+
1577
+ ##
1578
+ # The basename, if any, of the file in the path component.
1579
+ #
1580
+ # @return [String] The path's basename.
1581
+ def basename
1582
+ # Path cannot be nil
1583
+ return File.basename(self.path).sub(/;[^\/]*$/, EMPTY_STR)
1584
+ end
1585
+
1586
+ ##
1587
+ # The extname, if any, of the file in the path component.
1588
+ # Empty string if there is no extension.
1589
+ #
1590
+ # @return [String] The path's extname.
1591
+ def extname
1592
+ return nil unless self.path
1593
+ return File.extname(self.basename)
1594
+ end
1595
+
1596
+ ##
1597
+ # The query component for this URI.
1598
+ #
1599
+ # @return [String] The query component.
1600
+ def query
1601
+ return defined?(@query) ? @query : nil
1602
+ end
1603
+
1604
+ ##
1605
+ # The query component for this URI, normalized.
1606
+ #
1607
+ # @return [String] The query component, normalized.
1608
+ def normalized_query(*flags)
1609
+ return nil unless self.query
1610
+ return @normalized_query if defined?(@normalized_query)
1611
+ @normalized_query ||= begin
1612
+ modified_query_class = Addressable::URI::CharacterClasses::QUERY.dup
1613
+ # Make sure possible key-value pair delimiters are escaped.
1614
+ modified_query_class.sub!("\\&", "").sub!("\\;", "")
1615
+ pairs = (self.query || "").split("&", -1)
1616
+ pairs.delete_if(&:empty?) if flags.include?(:compacted)
1617
+ pairs.sort! if flags.include?(:sorted)
1618
+ component = pairs.map do |pair|
1619
+ Addressable::URI.normalize_component(pair, modified_query_class, "+")
1620
+ end.join("&")
1621
+ component == "" ? nil : component
1622
+ end
1623
+ # All normalized values should be UTF-8
1624
+ @normalized_query.force_encoding(Encoding::UTF_8) if @normalized_query
1625
+ @normalized_query
1626
+ end
1627
+
1628
+ ##
1629
+ # Sets the query component for this URI.
1630
+ #
1631
+ # @param [String, #to_str] new_query The new query component.
1632
+ def query=(new_query)
1633
+ if new_query && !new_query.respond_to?(:to_str)
1634
+ raise TypeError, "Can't convert #{new_query.class} into String."
1635
+ end
1636
+ @query = new_query ? new_query.to_str : nil
1637
+
1638
+ # Reset dependent values
1639
+ remove_instance_variable(:@normalized_query) if defined?(@normalized_query)
1640
+ remove_composite_values
1641
+ end
1642
+
1643
+ ##
1644
+ # Converts the query component to a Hash value.
1645
+ #
1646
+ # @param [Class] return_type The return type desired. Value must be either
1647
+ # `Hash` or `Array`.
1648
+ #
1649
+ # @return [Hash, Array, nil] The query string parsed as a Hash or Array
1650
+ # or nil if the query string is blank.
1651
+ #
1652
+ # @example
1653
+ # Addressable::URI.parse("?one=1&two=2&three=3").query_values
1654
+ # #=> {"one" => "1", "two" => "2", "three" => "3"}
1655
+ # Addressable::URI.parse("?one=two&one=three").query_values(Array)
1656
+ # #=> [["one", "two"], ["one", "three"]]
1657
+ # Addressable::URI.parse("?one=two&one=three").query_values(Hash)
1658
+ # #=> {"one" => "three"}
1659
+ # Addressable::URI.parse("?").query_values
1660
+ # #=> {}
1661
+ # Addressable::URI.parse("").query_values
1662
+ # #=> nil
1663
+ def query_values(return_type=Hash)
1664
+ empty_accumulator = Array == return_type ? [] : {}
1665
+ if return_type != Hash && return_type != Array
1666
+ raise ArgumentError, "Invalid return type. Must be Hash or Array."
1667
+ end
1668
+ return nil if self.query == nil
1669
+ split_query = self.query.split("&").map do |pair|
1670
+ pair.split("=", 2) if pair && !pair.empty?
1671
+ end.compact
1672
+ return split_query.inject(empty_accumulator.dup) do |accu, pair|
1673
+ # I'd rather use key/value identifiers instead of array lookups,
1674
+ # but in this case I really want to maintain the exact pair structure,
1675
+ # so it's best to make all changes in-place.
1676
+ pair[0] = URI.unencode_component(pair[0])
1677
+ if pair[1].respond_to?(:to_str)
1678
+ # I loathe the fact that I have to do this. Stupid HTML 4.01.
1679
+ # Treating '+' as a space was just an unbelievably bad idea.
1680
+ # There was nothing wrong with '%20'!
1681
+ # If it ain't broke, don't fix it!
1682
+ pair[1] = URI.unencode_component(pair[1].to_str.tr("+", " "))
1683
+ end
1684
+ if return_type == Hash
1685
+ accu[pair[0]] = pair[1]
1686
+ else
1687
+ accu << pair
1688
+ end
1689
+ accu
1690
+ end
1691
+ end
1692
+
1693
+ ##
1694
+ # Sets the query component for this URI from a Hash object.
1695
+ # An empty Hash or Array will result in an empty query string.
1696
+ #
1697
+ # @param [Hash, #to_hash, Array] new_query_values The new query values.
1698
+ #
1699
+ # @example
1700
+ # uri.query_values = {:a => "a", :b => ["c", "d", "e"]}
1701
+ # uri.query
1702
+ # # => "a=a&b=c&b=d&b=e"
1703
+ # uri.query_values = [['a', 'a'], ['b', 'c'], ['b', 'd'], ['b', 'e']]
1704
+ # uri.query
1705
+ # # => "a=a&b=c&b=d&b=e"
1706
+ # uri.query_values = [['a', 'a'], ['b', ['c', 'd', 'e']]]
1707
+ # uri.query
1708
+ # # => "a=a&b=c&b=d&b=e"
1709
+ # uri.query_values = [['flag'], ['key', 'value']]
1710
+ # uri.query
1711
+ # # => "flag&key=value"
1712
+ def query_values=(new_query_values)
1713
+ if new_query_values == nil
1714
+ self.query = nil
1715
+ return nil
1716
+ end
1717
+
1718
+ if !new_query_values.is_a?(Array)
1719
+ if !new_query_values.respond_to?(:to_hash)
1720
+ raise TypeError,
1721
+ "Can't convert #{new_query_values.class} into Hash."
1722
+ end
1723
+ new_query_values = new_query_values.to_hash
1724
+ new_query_values = new_query_values.map do |key, value|
1725
+ key = key.to_s if key.kind_of?(Symbol)
1726
+ [key, value]
1727
+ end
1728
+ # Useful default for OAuth and caching.
1729
+ # Only to be used for non-Array inputs. Arrays should preserve order.
1730
+ new_query_values.sort!
1731
+ end
1732
+
1733
+ # new_query_values have form [['key1', 'value1'], ['key2', 'value2']]
1734
+ buffer = "".dup
1735
+ new_query_values.each do |key, value|
1736
+ encoded_key = URI.encode_component(
1737
+ key, CharacterClasses::UNRESERVED
1738
+ )
1739
+ if value == nil
1740
+ buffer << "#{encoded_key}&"
1741
+ elsif value.kind_of?(Array)
1742
+ value.each do |sub_value|
1743
+ encoded_value = URI.encode_component(
1744
+ sub_value, CharacterClasses::UNRESERVED
1745
+ )
1746
+ buffer << "#{encoded_key}=#{encoded_value}&"
1747
+ end
1748
+ else
1749
+ encoded_value = URI.encode_component(
1750
+ value, CharacterClasses::UNRESERVED
1751
+ )
1752
+ buffer << "#{encoded_key}=#{encoded_value}&"
1753
+ end
1754
+ end
1755
+ self.query = buffer.chop
1756
+ end
1757
+
1758
+ ##
1759
+ # The HTTP request URI for this URI. This is the path and the
1760
+ # query string.
1761
+ #
1762
+ # @return [String] The request URI required for an HTTP request.
1763
+ def request_uri
1764
+ return nil if self.absolute? && self.scheme !~ /^https?$/i
1765
+ return (
1766
+ (!self.path.empty? ? self.path : SLASH) +
1767
+ (self.query ? "?#{self.query}" : EMPTY_STR)
1768
+ )
1769
+ end
1770
+
1771
+ ##
1772
+ # Sets the HTTP request URI for this URI.
1773
+ #
1774
+ # @param [String, #to_str] new_request_uri The new HTTP request URI.
1775
+ def request_uri=(new_request_uri)
1776
+ if !new_request_uri.respond_to?(:to_str)
1777
+ raise TypeError, "Can't convert #{new_request_uri.class} into String."
1778
+ end
1779
+ if self.absolute? && self.scheme !~ /^https?$/i
1780
+ raise InvalidURIError,
1781
+ "Cannot set an HTTP request URI for a non-HTTP URI."
1782
+ end
1783
+ new_request_uri = new_request_uri.to_str
1784
+ path_component = new_request_uri[/^([^\?]*)\??(?:.*)$/, 1]
1785
+ query_component = new_request_uri[/^(?:[^\?]*)\?(.*)$/, 1]
1786
+ path_component = path_component.to_s
1787
+ path_component = (!path_component.empty? ? path_component : SLASH)
1788
+ self.path = path_component
1789
+ self.query = query_component
1790
+
1791
+ # Reset dependent values
1792
+ remove_composite_values
1793
+ end
1794
+
1795
+ ##
1796
+ # The fragment component for this URI.
1797
+ #
1798
+ # @return [String] The fragment component.
1799
+ def fragment
1800
+ return defined?(@fragment) ? @fragment : nil
1801
+ end
1802
+
1803
+ ##
1804
+ # The fragment component for this URI, normalized.
1805
+ #
1806
+ # @return [String] The fragment component, normalized.
1807
+ def normalized_fragment
1808
+ return nil unless self.fragment
1809
+ return @normalized_fragment if defined?(@normalized_fragment)
1810
+ @normalized_fragment ||= begin
1811
+ component = Addressable::URI.normalize_component(
1812
+ self.fragment,
1813
+ Addressable::URI::CharacterClasses::FRAGMENT
1814
+ )
1815
+ component == "" ? nil : component
1816
+ end
1817
+ # All normalized values should be UTF-8
1818
+ if @normalized_fragment
1819
+ @normalized_fragment.force_encoding(Encoding::UTF_8)
1820
+ end
1821
+ @normalized_fragment
1822
+ end
1823
+
1824
+ ##
1825
+ # Sets the fragment component for this URI.
1826
+ #
1827
+ # @param [String, #to_str] new_fragment The new fragment component.
1828
+ def fragment=(new_fragment)
1829
+ if new_fragment && !new_fragment.respond_to?(:to_str)
1830
+ raise TypeError, "Can't convert #{new_fragment.class} into String."
1831
+ end
1832
+ @fragment = new_fragment ? new_fragment.to_str : nil
1833
+
1834
+ # Reset dependent values
1835
+ remove_instance_variable(:@normalized_fragment) if defined?(@normalized_fragment)
1836
+ remove_composite_values
1837
+
1838
+ # Ensure we haven't created an invalid URI
1839
+ validate()
1840
+ end
1841
+
1842
+ ##
1843
+ # Determines if the scheme indicates an IP-based protocol.
1844
+ #
1845
+ # @return [TrueClass, FalseClass]
1846
+ # <code>true</code> if the scheme indicates an IP-based protocol.
1847
+ # <code>false</code> otherwise.
1848
+ def ip_based?
1849
+ if self.scheme
1850
+ return URI.ip_based_schemes.include?(
1851
+ self.scheme.strip.downcase)
1852
+ end
1853
+ return false
1854
+ end
1855
+
1856
+ ##
1857
+ # Determines if the URI is relative.
1858
+ #
1859
+ # @return [TrueClass, FalseClass]
1860
+ # <code>true</code> if the URI is relative. <code>false</code>
1861
+ # otherwise.
1862
+ def relative?
1863
+ return self.scheme.nil?
1864
+ end
1865
+
1866
+ ##
1867
+ # Determines if the URI is absolute.
1868
+ #
1869
+ # @return [TrueClass, FalseClass]
1870
+ # <code>true</code> if the URI is absolute. <code>false</code>
1871
+ # otherwise.
1872
+ def absolute?
1873
+ return !relative?
1874
+ end
1875
+
1876
+ ##
1877
+ # Joins two URIs together.
1878
+ #
1879
+ # @param [String, Addressable::URI, #to_str] The URI to join with.
1880
+ #
1881
+ # @return [Addressable::URI] The joined URI.
1882
+ def join(uri)
1883
+ if !uri.respond_to?(:to_str)
1884
+ raise TypeError, "Can't convert #{uri.class} into String."
1885
+ end
1886
+ if !uri.kind_of?(URI)
1887
+ # Otherwise, convert to a String, then parse.
1888
+ uri = URI.parse(uri.to_str)
1889
+ end
1890
+ if uri.to_s.empty?
1891
+ return self.dup
1892
+ end
1893
+
1894
+ joined_scheme = nil
1895
+ joined_user = nil
1896
+ joined_password = nil
1897
+ joined_host = nil
1898
+ joined_port = nil
1899
+ joined_path = nil
1900
+ joined_query = nil
1901
+ joined_fragment = nil
1902
+
1903
+ # Section 5.2.2 of RFC 3986
1904
+ if uri.scheme != nil
1905
+ joined_scheme = uri.scheme
1906
+ joined_user = uri.user
1907
+ joined_password = uri.password
1908
+ joined_host = uri.host
1909
+ joined_port = uri.port
1910
+ joined_path = URI.normalize_path(uri.path)
1911
+ joined_query = uri.query
1912
+ else
1913
+ if uri.authority != nil
1914
+ joined_user = uri.user
1915
+ joined_password = uri.password
1916
+ joined_host = uri.host
1917
+ joined_port = uri.port
1918
+ joined_path = URI.normalize_path(uri.path)
1919
+ joined_query = uri.query
1920
+ else
1921
+ if uri.path == nil || uri.path.empty?
1922
+ joined_path = self.path
1923
+ if uri.query != nil
1924
+ joined_query = uri.query
1925
+ else
1926
+ joined_query = self.query
1927
+ end
1928
+ else
1929
+ if uri.path[0..0] == SLASH
1930
+ joined_path = URI.normalize_path(uri.path)
1931
+ else
1932
+ base_path = self.path.dup
1933
+ base_path = EMPTY_STR if base_path == nil
1934
+ base_path = URI.normalize_path(base_path)
1935
+
1936
+ # Section 5.2.3 of RFC 3986
1937
+ #
1938
+ # Removes the right-most path segment from the base path.
1939
+ if base_path.include?(SLASH)
1940
+ base_path.sub!(/\/[^\/]+$/, SLASH)
1941
+ else
1942
+ base_path = EMPTY_STR
1943
+ end
1944
+
1945
+ # If the base path is empty and an authority segment has been
1946
+ # defined, use a base path of SLASH
1947
+ if base_path.empty? && self.authority != nil
1948
+ base_path = SLASH
1949
+ end
1950
+
1951
+ joined_path = URI.normalize_path(base_path + uri.path)
1952
+ end
1953
+ joined_query = uri.query
1954
+ end
1955
+ joined_user = self.user
1956
+ joined_password = self.password
1957
+ joined_host = self.host
1958
+ joined_port = self.port
1959
+ end
1960
+ joined_scheme = self.scheme
1961
+ end
1962
+ joined_fragment = uri.fragment
1963
+
1964
+ return self.class.new(
1965
+ :scheme => joined_scheme,
1966
+ :user => joined_user,
1967
+ :password => joined_password,
1968
+ :host => joined_host,
1969
+ :port => joined_port,
1970
+ :path => joined_path,
1971
+ :query => joined_query,
1972
+ :fragment => joined_fragment
1973
+ )
1974
+ end
1975
+ alias_method :+, :join
1976
+
1977
+ ##
1978
+ # Destructive form of <code>join</code>.
1979
+ #
1980
+ # @param [String, Addressable::URI, #to_str] The URI to join with.
1981
+ #
1982
+ # @return [Addressable::URI] The joined URI.
1983
+ #
1984
+ # @see Addressable::URI#join
1985
+ def join!(uri)
1986
+ replace_self(self.join(uri))
1987
+ end
1988
+
1989
+ ##
1990
+ # Merges a URI with a <code>Hash</code> of components.
1991
+ # This method has different behavior from <code>join</code>. Any
1992
+ # components present in the <code>hash</code> parameter will override the
1993
+ # original components. The path component is not treated specially.
1994
+ #
1995
+ # @param [Hash, Addressable::URI, #to_hash] The components to merge with.
1996
+ #
1997
+ # @return [Addressable::URI] The merged URI.
1998
+ #
1999
+ # @see Hash#merge
2000
+ def merge(hash)
2001
+ if !hash.respond_to?(:to_hash)
2002
+ raise TypeError, "Can't convert #{hash.class} into Hash."
2003
+ end
2004
+ hash = hash.to_hash
2005
+
2006
+ if hash.has_key?(:authority)
2007
+ if (hash.keys & [:userinfo, :user, :password, :host, :port]).any?
2008
+ raise ArgumentError,
2009
+ "Cannot specify both an authority and any of the components " +
2010
+ "within the authority."
2011
+ end
2012
+ end
2013
+ if hash.has_key?(:userinfo)
2014
+ if (hash.keys & [:user, :password]).any?
2015
+ raise ArgumentError,
2016
+ "Cannot specify both a userinfo and either the user or password."
2017
+ end
2018
+ end
2019
+
2020
+ uri = self.class.new
2021
+ uri.defer_validation do
2022
+ # Bunch of crazy logic required because of the composite components
2023
+ # like userinfo and authority.
2024
+ uri.scheme =
2025
+ hash.has_key?(:scheme) ? hash[:scheme] : self.scheme
2026
+ if hash.has_key?(:authority)
2027
+ uri.authority =
2028
+ hash.has_key?(:authority) ? hash[:authority] : self.authority
2029
+ end
2030
+ if hash.has_key?(:userinfo)
2031
+ uri.userinfo =
2032
+ hash.has_key?(:userinfo) ? hash[:userinfo] : self.userinfo
2033
+ end
2034
+ if !hash.has_key?(:userinfo) && !hash.has_key?(:authority)
2035
+ uri.user =
2036
+ hash.has_key?(:user) ? hash[:user] : self.user
2037
+ uri.password =
2038
+ hash.has_key?(:password) ? hash[:password] : self.password
2039
+ end
2040
+ if !hash.has_key?(:authority)
2041
+ uri.host =
2042
+ hash.has_key?(:host) ? hash[:host] : self.host
2043
+ uri.port =
2044
+ hash.has_key?(:port) ? hash[:port] : self.port
2045
+ end
2046
+ uri.path =
2047
+ hash.has_key?(:path) ? hash[:path] : self.path
2048
+ uri.query =
2049
+ hash.has_key?(:query) ? hash[:query] : self.query
2050
+ uri.fragment =
2051
+ hash.has_key?(:fragment) ? hash[:fragment] : self.fragment
2052
+ end
2053
+
2054
+ return uri
2055
+ end
2056
+
2057
+ ##
2058
+ # Destructive form of <code>merge</code>.
2059
+ #
2060
+ # @param [Hash, Addressable::URI, #to_hash] The components to merge with.
2061
+ #
2062
+ # @return [Addressable::URI] The merged URI.
2063
+ #
2064
+ # @see Addressable::URI#merge
2065
+ def merge!(uri)
2066
+ replace_self(self.merge(uri))
2067
+ end
2068
+
2069
+ ##
2070
+ # Returns the shortest normalized relative form of this URI that uses the
2071
+ # supplied URI as a base for resolution. Returns an absolute URI if
2072
+ # necessary. This is effectively the opposite of <code>route_to</code>.
2073
+ #
2074
+ # @param [String, Addressable::URI, #to_str] uri The URI to route from.
2075
+ #
2076
+ # @return [Addressable::URI]
2077
+ # The normalized relative URI that is equivalent to the original URI.
2078
+ def route_from(uri)
2079
+ uri = URI.parse(uri).normalize
2080
+ normalized_self = self.normalize
2081
+ if normalized_self.relative?
2082
+ raise ArgumentError, "Expected absolute URI, got: #{self.to_s}"
2083
+ end
2084
+ if uri.relative?
2085
+ raise ArgumentError, "Expected absolute URI, got: #{uri.to_s}"
2086
+ end
2087
+ if normalized_self == uri
2088
+ return Addressable::URI.parse("##{normalized_self.fragment}")
2089
+ end
2090
+ components = normalized_self.to_hash
2091
+ if normalized_self.scheme == uri.scheme
2092
+ components[:scheme] = nil
2093
+ if normalized_self.authority == uri.authority
2094
+ components[:user] = nil
2095
+ components[:password] = nil
2096
+ components[:host] = nil
2097
+ components[:port] = nil
2098
+ if normalized_self.path == uri.path
2099
+ components[:path] = nil
2100
+ if normalized_self.query == uri.query
2101
+ components[:query] = nil
2102
+ end
2103
+ else
2104
+ if uri.path != SLASH and components[:path]
2105
+ self_splitted_path = split_path(components[:path])
2106
+ uri_splitted_path = split_path(uri.path)
2107
+ self_dir = self_splitted_path.shift
2108
+ uri_dir = uri_splitted_path.shift
2109
+ while !self_splitted_path.empty? && !uri_splitted_path.empty? and self_dir == uri_dir
2110
+ self_dir = self_splitted_path.shift
2111
+ uri_dir = uri_splitted_path.shift
2112
+ end
2113
+ components[:path] = (uri_splitted_path.fill('..') + [self_dir] + self_splitted_path).join(SLASH)
2114
+ end
2115
+ end
2116
+ end
2117
+ end
2118
+ # Avoid network-path references.
2119
+ if components[:host] != nil
2120
+ components[:scheme] = normalized_self.scheme
2121
+ end
2122
+ return Addressable::URI.new(
2123
+ :scheme => components[:scheme],
2124
+ :user => components[:user],
2125
+ :password => components[:password],
2126
+ :host => components[:host],
2127
+ :port => components[:port],
2128
+ :path => components[:path],
2129
+ :query => components[:query],
2130
+ :fragment => components[:fragment]
2131
+ )
2132
+ end
2133
+
2134
+ ##
2135
+ # Returns the shortest normalized relative form of the supplied URI that
2136
+ # uses this URI as a base for resolution. Returns an absolute URI if
2137
+ # necessary. This is effectively the opposite of <code>route_from</code>.
2138
+ #
2139
+ # @param [String, Addressable::URI, #to_str] uri The URI to route to.
2140
+ #
2141
+ # @return [Addressable::URI]
2142
+ # The normalized relative URI that is equivalent to the supplied URI.
2143
+ def route_to(uri)
2144
+ return URI.parse(uri).route_from(self)
2145
+ end
2146
+
2147
+ ##
2148
+ # Returns a normalized URI object.
2149
+ #
2150
+ # NOTE: This method does not attempt to fully conform to specifications.
2151
+ # It exists largely to correct other people's failures to read the
2152
+ # specifications, and also to deal with caching issues since several
2153
+ # different URIs may represent the same resource and should not be
2154
+ # cached multiple times.
2155
+ #
2156
+ # @return [Addressable::URI] The normalized URI.
2157
+ def normalize
2158
+ # This is a special exception for the frequently misused feed
2159
+ # URI scheme.
2160
+ if normalized_scheme == "feed"
2161
+ if self.to_s =~ /^feed:\/*http:\/*/
2162
+ return URI.parse(
2163
+ self.to_s[/^feed:\/*(http:\/*.*)/, 1]
2164
+ ).normalize
2165
+ end
2166
+ end
2167
+
2168
+ return self.class.new(
2169
+ :scheme => normalized_scheme,
2170
+ :authority => normalized_authority,
2171
+ :path => normalized_path,
2172
+ :query => normalized_query,
2173
+ :fragment => normalized_fragment
2174
+ )
2175
+ end
2176
+
2177
+ ##
2178
+ # Destructively normalizes this URI object.
2179
+ #
2180
+ # @return [Addressable::URI] The normalized URI.
2181
+ #
2182
+ # @see Addressable::URI#normalize
2183
+ def normalize!
2184
+ replace_self(self.normalize)
2185
+ end
2186
+
2187
+ ##
2188
+ # Creates a URI suitable for display to users. If semantic attacks are
2189
+ # likely, the application should try to detect these and warn the user.
2190
+ # See <a href="http://www.ietf.org/rfc/rfc3986.txt">RFC 3986</a>,
2191
+ # section 7.6 for more information.
2192
+ #
2193
+ # @return [Addressable::URI] A URI suitable for display purposes.
2194
+ def display_uri
2195
+ display_uri = self.normalize
2196
+ display_uri.host = ::Addressable::IDNA.to_unicode(display_uri.host)
2197
+ return display_uri
2198
+ end
2199
+
2200
+ ##
2201
+ # Returns <code>true</code> if the URI objects are equal. This method
2202
+ # normalizes both URIs before doing the comparison, and allows comparison
2203
+ # against <code>Strings</code>.
2204
+ #
2205
+ # @param [Object] uri The URI to compare.
2206
+ #
2207
+ # @return [TrueClass, FalseClass]
2208
+ # <code>true</code> if the URIs are equivalent, <code>false</code>
2209
+ # otherwise.
2210
+ def ===(uri)
2211
+ if uri.respond_to?(:normalize)
2212
+ uri_string = uri.normalize.to_s
2213
+ else
2214
+ begin
2215
+ uri_string = ::Addressable::URI.parse(uri).normalize.to_s
2216
+ rescue InvalidURIError, TypeError
2217
+ return false
2218
+ end
2219
+ end
2220
+ return self.normalize.to_s == uri_string
2221
+ end
2222
+
2223
+ ##
2224
+ # Returns <code>true</code> if the URI objects are equal. This method
2225
+ # normalizes both URIs before doing the comparison.
2226
+ #
2227
+ # @param [Object] uri The URI to compare.
2228
+ #
2229
+ # @return [TrueClass, FalseClass]
2230
+ # <code>true</code> if the URIs are equivalent, <code>false</code>
2231
+ # otherwise.
2232
+ def ==(uri)
2233
+ return false unless uri.kind_of?(URI)
2234
+ return self.normalize.to_s == uri.normalize.to_s
2235
+ end
2236
+
2237
+ ##
2238
+ # Returns <code>true</code> if the URI objects are equal. This method
2239
+ # does NOT normalize either URI before doing the comparison.
2240
+ #
2241
+ # @param [Object] uri The URI to compare.
2242
+ #
2243
+ # @return [TrueClass, FalseClass]
2244
+ # <code>true</code> if the URIs are equivalent, <code>false</code>
2245
+ # otherwise.
2246
+ def eql?(uri)
2247
+ return false unless uri.kind_of?(URI)
2248
+ return self.to_s == uri.to_s
2249
+ end
2250
+
2251
+ ##
2252
+ # A hash value that will make a URI equivalent to its normalized
2253
+ # form.
2254
+ #
2255
+ # @return [Integer] A hash of the URI.
2256
+ def hash
2257
+ @hash ||= self.to_s.hash * -1
2258
+ end
2259
+
2260
+ ##
2261
+ # Clones the URI object.
2262
+ #
2263
+ # @return [Addressable::URI] The cloned URI.
2264
+ def dup
2265
+ duplicated_uri = self.class.new(
2266
+ :scheme => self.scheme ? self.scheme.dup : nil,
2267
+ :user => self.user ? self.user.dup : nil,
2268
+ :password => self.password ? self.password.dup : nil,
2269
+ :host => self.host ? self.host.dup : nil,
2270
+ :port => self.port,
2271
+ :path => self.path ? self.path.dup : nil,
2272
+ :query => self.query ? self.query.dup : nil,
2273
+ :fragment => self.fragment ? self.fragment.dup : nil
2274
+ )
2275
+ return duplicated_uri
2276
+ end
2277
+
2278
+ ##
2279
+ # Omits components from a URI.
2280
+ #
2281
+ # @param [Symbol] *components The components to be omitted.
2282
+ #
2283
+ # @return [Addressable::URI] The URI with components omitted.
2284
+ #
2285
+ # @example
2286
+ # uri = Addressable::URI.parse("http://example.com/path?query")
2287
+ # #=> #<Addressable::URI:0xcc5e7a URI:http://example.com/path?query>
2288
+ # uri.omit(:scheme, :authority)
2289
+ # #=> #<Addressable::URI:0xcc4d86 URI:/path?query>
2290
+ def omit(*components)
2291
+ invalid_components = components - [
2292
+ :scheme, :user, :password, :userinfo, :host, :port, :authority,
2293
+ :path, :query, :fragment
2294
+ ]
2295
+ unless invalid_components.empty?
2296
+ raise ArgumentError,
2297
+ "Invalid component names: #{invalid_components.inspect}."
2298
+ end
2299
+ duplicated_uri = self.dup
2300
+ duplicated_uri.defer_validation do
2301
+ components.each do |component|
2302
+ duplicated_uri.send((component.to_s + "=").to_sym, nil)
2303
+ end
2304
+ duplicated_uri.user = duplicated_uri.normalized_user
2305
+ end
2306
+ duplicated_uri
2307
+ end
2308
+
2309
+ ##
2310
+ # Destructive form of omit.
2311
+ #
2312
+ # @param [Symbol] *components The components to be omitted.
2313
+ #
2314
+ # @return [Addressable::URI] The URI with components omitted.
2315
+ #
2316
+ # @see Addressable::URI#omit
2317
+ def omit!(*components)
2318
+ replace_self(self.omit(*components))
2319
+ end
2320
+
2321
+ ##
2322
+ # Determines if the URI is an empty string.
2323
+ #
2324
+ # @return [TrueClass, FalseClass]
2325
+ # Returns <code>true</code> if empty, <code>false</code> otherwise.
2326
+ def empty?
2327
+ return self.to_s.empty?
2328
+ end
2329
+
2330
+ ##
2331
+ # Converts the URI to a <code>String</code>.
2332
+ #
2333
+ # @return [String] The URI's <code>String</code> representation.
2334
+ def to_s
2335
+ if self.scheme == nil && self.path != nil && !self.path.empty? &&
2336
+ self.path =~ NORMPATH
2337
+ raise InvalidURIError,
2338
+ "Cannot assemble URI string with ambiguous path: '#{self.path}'"
2339
+ end
2340
+ @uri_string ||= begin
2341
+ uri_string = String.new
2342
+ uri_string << "#{self.scheme}:" if self.scheme != nil
2343
+ uri_string << "//#{self.authority}" if self.authority != nil
2344
+ uri_string << self.path.to_s
2345
+ uri_string << "?#{self.query}" if self.query != nil
2346
+ uri_string << "##{self.fragment}" if self.fragment != nil
2347
+ uri_string.force_encoding(Encoding::UTF_8)
2348
+ uri_string
2349
+ end
2350
+ end
2351
+
2352
+ ##
2353
+ # URI's are glorified <code>Strings</code>. Allow implicit conversion.
2354
+ alias_method :to_str, :to_s
2355
+
2356
+ ##
2357
+ # Returns a Hash of the URI components.
2358
+ #
2359
+ # @return [Hash] The URI as a <code>Hash</code> of components.
2360
+ def to_hash
2361
+ return {
2362
+ :scheme => self.scheme,
2363
+ :user => self.user,
2364
+ :password => self.password,
2365
+ :host => self.host,
2366
+ :port => self.port,
2367
+ :path => self.path,
2368
+ :query => self.query,
2369
+ :fragment => self.fragment
2370
+ }
2371
+ end
2372
+
2373
+ ##
2374
+ # Returns a <code>String</code> representation of the URI object's state.
2375
+ #
2376
+ # @return [String] The URI object's state, as a <code>String</code>.
2377
+ def inspect
2378
+ sprintf("#<%s:%#0x URI:%s>", URI.to_s, self.object_id, self.to_s)
2379
+ end
2380
+
2381
+ ##
2382
+ # This method allows you to make several changes to a URI simultaneously,
2383
+ # which separately would cause validation errors, but in conjunction,
2384
+ # are valid. The URI will be revalidated as soon as the entire block has
2385
+ # been executed.
2386
+ #
2387
+ # @param [Proc] block
2388
+ # A set of operations to perform on a given URI.
2389
+ def defer_validation
2390
+ raise LocalJumpError, "No block given." unless block_given?
2391
+ @validation_deferred = true
2392
+ yield
2393
+ @validation_deferred = false
2394
+ validate
2395
+ return nil
2396
+ end
2397
+
2398
+ protected
2399
+ SELF_REF = '.'
2400
+ PARENT = '..'
2401
+
2402
+ RULE_2A = /\/\.\/|\/\.$/
2403
+ RULE_2B_2C = /\/([^\/]*)\/\.\.\/|\/([^\/]*)\/\.\.$/
2404
+ RULE_2D = /^\.\.?\/?/
2405
+ RULE_PREFIXED_PARENT = /^\/\.\.?\/|^(\/\.\.?)+\/?$/
2406
+
2407
+ ##
2408
+ # Resolves paths to their simplest form.
2409
+ #
2410
+ # @param [String] path The path to normalize.
2411
+ #
2412
+ # @return [String] The normalized path.
2413
+ def self.normalize_path(path)
2414
+ # Section 5.2.4 of RFC 3986
2415
+
2416
+ return nil if path.nil?
2417
+ normalized_path = path.dup
2418
+ begin
2419
+ mod = nil
2420
+ mod ||= normalized_path.gsub!(RULE_2A, SLASH)
2421
+
2422
+ pair = normalized_path.match(RULE_2B_2C)
2423
+ parent, current = pair[1], pair[2] if pair
2424
+ if pair && ((parent != SELF_REF && parent != PARENT) ||
2425
+ (current != SELF_REF && current != PARENT))
2426
+ mod ||= normalized_path.gsub!(
2427
+ Regexp.new(
2428
+ "/#{Regexp.escape(parent.to_s)}/\\.\\./|" +
2429
+ "(/#{Regexp.escape(current.to_s)}/\\.\\.$)"
2430
+ ), SLASH
2431
+ )
2432
+ end
2433
+
2434
+ mod ||= normalized_path.gsub!(RULE_2D, EMPTY_STR)
2435
+ # Non-standard, removes prefixed dotted segments from path.
2436
+ mod ||= normalized_path.gsub!(RULE_PREFIXED_PARENT, SLASH)
2437
+ end until mod.nil?
2438
+
2439
+ return normalized_path
2440
+ end
2441
+
2442
+ ##
2443
+ # Ensures that the URI is valid.
2444
+ def validate
2445
+ return if !!@validation_deferred
2446
+ if self.scheme != nil && self.ip_based? &&
2447
+ (self.host == nil || self.host.empty?) &&
2448
+ (self.path == nil || self.path.empty?)
2449
+ raise InvalidURIError,
2450
+ "Absolute URI missing hierarchical segment: '#{self.to_s}'"
2451
+ end
2452
+ if self.host == nil
2453
+ if self.port != nil ||
2454
+ self.user != nil ||
2455
+ self.password != nil
2456
+ raise InvalidURIError, "Hostname not supplied: '#{self.to_s}'"
2457
+ end
2458
+ end
2459
+ if self.path != nil && !self.path.empty? && self.path[0..0] != SLASH &&
2460
+ self.authority != nil
2461
+ raise InvalidURIError,
2462
+ "Cannot have a relative path with an authority set: '#{self.to_s}'"
2463
+ end
2464
+ if self.path != nil && !self.path.empty? &&
2465
+ self.path[0..1] == SLASH + SLASH && self.authority == nil
2466
+ raise InvalidURIError,
2467
+ "Cannot have a path with two leading slashes " +
2468
+ "without an authority set: '#{self.to_s}'"
2469
+ end
2470
+ unreserved = CharacterClasses::UNRESERVED
2471
+ sub_delims = CharacterClasses::SUB_DELIMS
2472
+ if !self.host.nil? && (self.host =~ /[<>{}\/\\\?\#\@"[[:space:]]]/ ||
2473
+ (self.host[/^\[(.*)\]$/, 1] != nil && self.host[/^\[(.*)\]$/, 1] !~
2474
+ Regexp.new("^[#{unreserved}#{sub_delims}:]*$")))
2475
+ raise InvalidURIError, "Invalid character in host: '#{self.host.to_s}'"
2476
+ end
2477
+ return nil
2478
+ end
2479
+
2480
+ ##
2481
+ # Replaces the internal state of self with the specified URI's state.
2482
+ # Used in destructive operations to avoid massive code repetition.
2483
+ #
2484
+ # @param [Addressable::URI] uri The URI to replace <code>self</code> with.
2485
+ #
2486
+ # @return [Addressable::URI] <code>self</code>.
2487
+ def replace_self(uri)
2488
+ # Reset dependent values
2489
+ instance_variables.each do |var|
2490
+ if instance_variable_defined?(var) && var != :@validation_deferred
2491
+ remove_instance_variable(var)
2492
+ end
2493
+ end
2494
+
2495
+ @scheme = uri.scheme
2496
+ @user = uri.user
2497
+ @password = uri.password
2498
+ @host = uri.host
2499
+ @port = uri.port
2500
+ @path = uri.path
2501
+ @query = uri.query
2502
+ @fragment = uri.fragment
2503
+ return self
2504
+ end
2505
+
2506
+ ##
2507
+ # Splits path string with "/" (slash).
2508
+ # It is considered that there is empty string after last slash when
2509
+ # path ends with slash.
2510
+ #
2511
+ # @param [String] path The path to split.
2512
+ #
2513
+ # @return [Array<String>] An array of parts of path.
2514
+ def split_path(path)
2515
+ splitted = path.split(SLASH)
2516
+ splitted << EMPTY_STR if path.end_with? SLASH
2517
+ splitted
2518
+ end
2519
+
2520
+ ##
2521
+ # Resets composite values for the entire URI
2522
+ #
2523
+ # @api private
2524
+ def remove_composite_values
2525
+ remove_instance_variable(:@uri_string) if defined?(@uri_string)
2526
+ remove_instance_variable(:@hash) if defined?(@hash)
2527
+ end
2528
+ end
2529
+ end