facets 1.3.3 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (589) hide show
  1. data/{doc/AUTHORS → AUTHORS} +12 -3
  2. data/README +35 -29
  3. data/WARNING +56 -0
  4. data/demo/annotation/demo_annotation.rb +22 -0
  5. data/demo/ansicolor/cdiff.rb +20 -0
  6. data/demo/ansicolor/example.rb +82 -0
  7. data/demo/io-reactor/chatserver.rb +347 -0
  8. data/demo/lisp/game.rb +47 -0
  9. data/lib/facet/all.rb +1 -0
  10. data/lib/facet/annattr.rb +1 -0
  11. data/lib/facet/class/to_proc.rb +1 -0
  12. data/lib/facet/cookie.rb +1 -0
  13. data/lib/facet/dir/self/descend.rb +1 -0
  14. data/lib/facet/enumerable/count.rb +1 -0
  15. data/lib/facet/hash/to_proc.rb +1 -0
  16. data/lib/facet/hashbuilder.rb +1 -0
  17. data/lib/facet/http.rb +1 -0
  18. data/lib/facet/httpaccess.rb +1 -0
  19. data/lib/facet/kernel/__get__.rb +1 -0
  20. data/lib/facet/kernel/__set__.rb +1 -0
  21. data/lib/facet/kernel/cache.rb +1 -0
  22. data/lib/facet/kernel/respond.rb +1 -0
  23. data/lib/facet/lazy.rb +1 -0
  24. data/lib/facet/module/class.rb +1 -0
  25. data/lib/facet/module/nodef.rb +1 -0
  26. data/lib/facet/opencascade.rb +1 -0
  27. data/lib/facet/pqueue.rb +1 -0
  28. data/lib/facet/taskable.rb +1 -0
  29. data/lib/facets.rb +98 -37
  30. data/lib/facets/core/all.rb +5 -0
  31. data/lib/facets/core/class/to_proc.rb +25 -0
  32. data/lib/facets/core/dir/self/ascend.rb +2 -1
  33. data/lib/facets/core/dir/self/descend.rb +11 -0
  34. data/lib/facets/core/enumerable/accumulate.rb +2 -2
  35. data/lib/facets/core/enumerable/count.rb +54 -0
  36. data/lib/facets/core/enumerable/cross.rb +3 -0
  37. data/lib/facets/core/enumerable/graph.rb +8 -4
  38. data/lib/facets/core/enumerable/self/cross.rb +11 -5
  39. data/lib/facets/core/hash/to_proc.rb +34 -0
  40. data/lib/facets/core/hash/traverse.rb +10 -5
  41. data/lib/facets/core/kernel/__class__.rb +1 -1
  42. data/lib/facets/core/kernel/__get__.rb +5 -0
  43. data/lib/facets/core/kernel/__set__.rb +2 -0
  44. data/lib/facets/core/kernel/assign_from.rb +1 -1
  45. data/lib/facets/core/kernel/assign_with.rb +11 -3
  46. data/lib/facets/core/kernel/bool.rb +1 -1
  47. data/lib/facets/core/kernel/cache.rb +31 -0
  48. data/lib/facets/core/kernel/demo.rb +4 -0
  49. data/lib/facets/core/kernel/get_by_id.rb +1 -0
  50. data/lib/facets/core/kernel/in.rb +1 -1
  51. data/lib/facets/core/kernel/instance_assign.rb +2 -3
  52. data/lib/facets/core/kernel/method.rb +25 -7
  53. data/lib/facets/core/kernel/methods.rb +1 -1
  54. data/lib/facets/core/kernel/new.rb +1 -1
  55. data/lib/facets/core/kernel/object_class.rb +1 -1
  56. data/lib/facets/core/kernel/object_hexid.rb +1 -1
  57. data/lib/facets/core/kernel/own.rb +1 -1
  58. data/lib/facets/core/kernel/require_all.rb +1 -0
  59. data/lib/facets/core/kernel/require_esc.rb +4 -2
  60. data/lib/facets/core/kernel/require_facet.rb +2 -0
  61. data/lib/facets/core/kernel/require_local.rb +1 -0
  62. data/lib/facets/core/kernel/respond.rb +14 -0
  63. data/lib/facets/core/kernel/send_as.rb +1 -1
  64. data/lib/facets/core/kernel/silence_warnings.rb +1 -1
  65. data/lib/facets/core/kernel/singleton.rb +3 -1
  66. data/lib/facets/core/matchdata/matchtree.rb +13 -3
  67. data/lib/facets/core/module/class.rb +3 -0
  68. data/lib/facets/core/module/integrate.rb +31 -4
  69. data/lib/facets/core/module/{undef.rb → nodef.rb} +8 -3
  70. data/lib/facets/core/module/revisal.rb +5 -5
  71. data/lib/facets/more/annattr.rb +147 -0
  72. data/lib/facets/more/annotation.rb +32 -136
  73. data/lib/facets/more/ansicode.rb +89 -100
  74. data/lib/facets/more/aspects.rb +28 -0
  75. data/lib/facets/more/association.rb +88 -47
  76. data/lib/facets/more/basicobject.rb +51 -33
  77. data/lib/facets/more/bbcode.rb +21 -34
  78. data/lib/facets/more/binaryreader.rb +62 -33
  79. data/lib/facets/more/bitmask.rb +24 -24
  80. data/lib/facets/more/blankslate.rb +4 -0
  81. data/lib/facets/more/builderobject.rb +16 -20
  82. data/lib/facets/more/bytes.rb +43 -24
  83. data/lib/facets/more/classinherit.rb +15 -31
  84. data/lib/facets/more/classmethods.rb +19 -29
  85. data/lib/facets/more/cloneable.rb +42 -30
  86. data/lib/facets/more/consoleapp.rb +42 -22
  87. data/lib/facets/more/cookie.rb +565 -0
  88. data/lib/facets/more/coroutine.rb +17 -21
  89. data/lib/facets/more/crypt.rb +33 -12
  90. data/lib/facets/more/dictionary.rb +27 -36
  91. data/lib/facets/more/downloader.rb +21 -17
  92. data/lib/facets/more/elementor.rb +22 -0
  93. data/lib/facets/more/enumerablepass.rb +19 -27
  94. data/lib/facets/more/expirable.rb +18 -28
  95. data/lib/facets/more/filelist.rb +33 -32
  96. data/lib/facets/more/floatstring.rb +31 -40
  97. data/lib/facets/more/functor.rb +15 -25
  98. data/lib/facets/more/hashbuilder.rb +76 -0
  99. data/lib/facets/more/heap.rb +29 -36
  100. data/lib/facets/more/htmlbuilder.rb +22 -24
  101. data/lib/facets/more/htmlhelper.rb +89 -0
  102. data/lib/facets/more/http.rb +570 -0
  103. data/lib/facets/more/httpaccess.rb +1608 -0
  104. data/lib/facets/more/inheritor.rb +29 -21
  105. data/lib/facets/more/interval.rb +21 -25
  106. data/lib/facets/more/ioredirect.rb +21 -25
  107. data/lib/facets/more/json.rb +27 -17
  108. data/lib/facets/more/lazy.rb +238 -0
  109. data/lib/facets/more/lisp.rb +24 -27
  110. data/lib/facets/more/lisp_format.rb +93 -85
  111. data/lib/facets/more/lrucache.rb +17 -27
  112. data/lib/facets/more/mathconstants.rb +22 -40
  113. data/lib/facets/more/methodprobe.rb +56 -61
  114. data/lib/facets/more/mock.rb +24 -17
  115. data/lib/facets/more/multipliers.rb +21 -17
  116. data/lib/facets/more/multiton.rb +18 -24
  117. data/lib/facets/more/nackclass.rb +17 -21
  118. data/lib/facets/more/nilcomparable.rb +28 -30
  119. data/lib/facets/more/nullclass.rb +16 -15
  120. data/lib/facets/more/one.rb +94 -58
  121. data/lib/facets/more/opencascade.rb +187 -0
  122. data/lib/facets/more/openobject.rb +89 -66
  123. data/lib/facets/more/orderedhash.rb +4 -0
  124. data/lib/facets/more/ormsupport.rb +18 -29
  125. data/lib/facets/more/overload.rb +39 -3
  126. data/lib/facets/more/paramix.rb +16 -24
  127. data/lib/facets/more/pathlist.rb +17 -23
  128. data/lib/facets/more/pool.rb +21 -29
  129. data/lib/facets/more/pqueue.rb +190 -0
  130. data/lib/facets/more/preinitialize.rb +17 -18
  131. data/lib/facets/more/progressbar.rb +19 -15
  132. data/lib/facets/more/promoteself.rb +17 -21
  133. data/lib/facets/more/quaternion.rb +379 -346
  134. data/lib/facets/more/recorder.rb +15 -20
  135. data/lib/facets/more/reference.rb +25 -22
  136. data/lib/facets/more/rexmlbuilder.rb +21 -6
  137. data/lib/facets/more/rtals.rb +27 -24
  138. data/lib/facets/more/semaphore.rb +15 -28
  139. data/lib/facets/more/snapshot.rb +45 -41
  140. data/lib/facets/more/stateparser.rb +25 -35
  141. data/lib/facets/more/statichash.rb +37 -29
  142. data/lib/facets/more/syncarray.rb +18 -26
  143. data/lib/facets/more/synchash.rb +17 -26
  144. data/lib/facets/more/system.rb +25 -17
  145. data/lib/facets/more/tagiterator.rb +15 -39
  146. data/lib/facets/more/taskable.rb +417 -0
  147. data/lib/facets/more/timer.rb +22 -26
  148. data/lib/facets/more/times.rb +23 -23
  149. data/lib/facets/more/tracepoint.rb +25 -24
  150. data/lib/facets/more/tuple.rb +25 -42
  151. data/lib/facets/more/typecast.rb +27 -29
  152. data/lib/facets/more/uninheritable.rb +15 -22
  153. data/lib/facets/more/units.rb +23 -29
  154. data/lib/facets/more/xmlbuilder.rb +20 -22
  155. data/lib/facets/more/xmlhelper.rb +18 -21
  156. data/lib/facets/more/xoxo.rb +23 -11
  157. data/lib/facets/more/yamlstruct.rb +25 -22
  158. data/test/lib/facets/core/array/test_at_rand.rb +1 -1
  159. data/test/lib/facets/core/array/test_delete_unless.rb +1 -1
  160. data/test/lib/facets/core/array/test_delete_values.rb +1 -1
  161. data/test/lib/facets/core/array/test_delete_values_at.rb +1 -1
  162. data/test/lib/facets/core/array/test_first.rb +1 -1
  163. data/test/lib/facets/core/array/test_head.rb +1 -1
  164. data/test/lib/facets/core/array/test_last_index.rb +1 -1
  165. data/test/lib/facets/core/array/test_merge.rb +1 -1
  166. data/test/lib/facets/core/array/test_mid.rb +1 -1
  167. data/test/lib/facets/core/array/test_middle.rb +1 -1
  168. data/test/lib/facets/core/array/test_op_fetch.rb +1 -1
  169. data/test/lib/facets/core/array/test_op_store.rb +1 -1
  170. data/test/lib/facets/core/array/test_pick.rb +1 -1
  171. data/test/lib/facets/core/array/test_pos.rb +1 -1
  172. data/test/lib/facets/core/array/test_pot.rb +1 -1
  173. data/test/lib/facets/core/array/test_pull.rb +1 -1
  174. data/test/lib/facets/core/array/test_rand_index.rb +1 -1
  175. data/test/lib/facets/core/array/test_rand_subset.rb +1 -1
  176. data/test/lib/facets/core/array/test_range.rb +1 -1
  177. data/test/lib/facets/core/array/test_rotate.rb +1 -1
  178. data/test/lib/facets/core/array/test_select.rb +1 -1
  179. data/test/lib/facets/core/array/test_shuffle.rb +1 -1
  180. data/test/lib/facets/core/array/test_thru.rb +1 -1
  181. data/test/lib/facets/core/array/test_to_b.rb +1 -1
  182. data/test/lib/facets/core/array/test_to_h.rb +1 -1
  183. data/test/lib/facets/core/array/test_to_hash.rb +1 -1
  184. data/test/lib/facets/core/binding/self/test_of_caller.rb +1 -1
  185. data/test/lib/facets/core/binding/test___LINE__.rb +1 -1
  186. data/test/lib/facets/core/binding/test_call_stack.rb +1 -1
  187. data/test/lib/facets/core/binding/test_called.rb +1 -1
  188. data/test/lib/facets/core/binding/test_caller.rb +1 -1
  189. data/test/lib/facets/core/binding/test_defined.rb +1 -1
  190. data/test/lib/facets/core/binding/test_eval.rb +1 -1
  191. data/test/lib/facets/core/binding/test_local_variables.rb +1 -1
  192. data/test/lib/facets/core/binding/test_method_name.rb +1 -1
  193. data/test/lib/facets/core/binding/test_op_fetch.rb +1 -1
  194. data/test/lib/facets/core/binding/test_op_store.rb +1 -1
  195. data/test/lib/facets/core/binding/test_self.rb +1 -1
  196. data/test/lib/facets/core/class/test_cattr.rb +1 -1
  197. data/test/lib/facets/core/class/test_descendents.rb +1 -1
  198. data/test/lib/facets/core/class/test_method_name.rb +1 -1
  199. data/test/lib/facets/core/class/test_remove_descendents.rb +1 -1
  200. data/test/lib/facets/core/class/test_unix_path.rb +1 -1
  201. data/test/lib/facets/core/comparable/test_at_least.rb +1 -1
  202. data/test/lib/facets/core/comparable/test_clip.rb +1 -1
  203. data/test/lib/facets/core/comparable/test_cmp.rb +1 -1
  204. data/test/lib/facets/core/continuation/self/test_create.rb +1 -1
  205. data/test/lib/facets/core/date/test_days_in_month.rb +1 -1
  206. data/test/lib/facets/core/date/test_days_of_month.rb +1 -1
  207. data/test/lib/facets/core/date/test_stamp.rb +1 -1
  208. data/test/lib/facets/core/date/test_to_date.rb +1 -1
  209. data/test/lib/facets/core/date/test_to_s.rb +1 -1
  210. data/test/lib/facets/core/date/test_to_time.rb +1 -1
  211. data/test/lib/facets/core/dir/self/test_ancestor.rb +1 -1
  212. data/test/lib/facets/core/dir/self/test_ascend.rb +1 -1
  213. data/test/lib/facets/core/enumerable/self/test_combinations.rb +1 -1
  214. data/test/lib/facets/core/enumerable/self/test_cross.rb +1 -1
  215. data/test/lib/facets/core/enumerable/test_collect_with_index.rb +1 -1
  216. data/test/lib/facets/core/enumerable/test_commonality.rb +1 -1
  217. data/test/lib/facets/core/enumerable/test_compact_collect.rb +1 -1
  218. data/test/lib/facets/core/enumerable/test_count.rb +38 -0
  219. data/test/lib/facets/core/enumerable/test_cross.rb +1 -1
  220. data/test/lib/facets/core/enumerable/test_each_combination.rb +1 -1
  221. data/test/lib/facets/core/enumerable/test_each_pair.rb +1 -1
  222. data/test/lib/facets/core/enumerable/test_each_slice.rb +1 -1
  223. data/test/lib/facets/core/enumerable/test_each_unique_pair.rb +1 -1
  224. data/test/lib/facets/core/enumerable/test_entropy.rb +1 -1
  225. data/test/lib/facets/core/enumerable/test_every.rb +1 -1
  226. data/test/lib/facets/core/enumerable/test_ew.rb +1 -1
  227. data/test/lib/facets/core/enumerable/test_filter_collect.rb +1 -1
  228. data/test/lib/facets/core/enumerable/test_find_collisions.rb +1 -1
  229. data/test/lib/facets/core/enumerable/test_frequency.rb +1 -1
  230. data/test/lib/facets/core/enumerable/test_graph.rb +1 -1
  231. data/test/lib/facets/core/enumerable/test_ideal_entropy.rb +1 -1
  232. data/test/lib/facets/core/enumerable/test_none.rb +1 -1
  233. data/test/lib/facets/core/enumerable/test_occur.rb +1 -1
  234. data/test/lib/facets/core/enumerable/test_one.rb +1 -1
  235. data/test/lib/facets/core/enumerable/test_op_pow.rb +1 -1
  236. data/test/lib/facets/core/enumerable/test_partition_by.rb +1 -1
  237. data/test/lib/facets/core/enumerable/test_permute.rb +1 -1
  238. data/test/lib/facets/core/enumerable/test_probability.rb +1 -1
  239. data/test/lib/facets/core/enumerable/test_to_h.rb +1 -1
  240. data/test/lib/facets/core/enumerable/test_uniq_by.rb +1 -1
  241. data/test/lib/facets/core/file/self/test_create.rb +1 -1
  242. data/test/lib/facets/core/file/self/test_open_as_string.rb +1 -1
  243. data/test/lib/facets/core/file/self/test_read_list.rb +1 -1
  244. data/test/lib/facets/core/file/self/test_sanitize.rb +1 -1
  245. data/test/lib/facets/core/file/self/test_split_all.rb +1 -1
  246. data/test/lib/facets/core/float/test_round_at.rb +1 -1
  247. data/test/lib/facets/core/float/test_round_to.rb +1 -1
  248. data/test/lib/facets/core/hash/self/test_zipnew.rb +1 -1
  249. data/test/lib/facets/core/hash/test_alias.rb +1 -1
  250. data/test/lib/facets/core/hash/test_assert_has_keys.rb +1 -1
  251. data/test/lib/facets/core/hash/test_assert_has_only_keys.rb +1 -1
  252. data/test/lib/facets/core/hash/test_at.rb +1 -1
  253. data/test/lib/facets/core/hash/test_collate.rb +1 -1
  254. data/test/lib/facets/core/hash/test_each.rb +1 -1
  255. data/test/lib/facets/core/hash/test_each_with_index.rb +1 -1
  256. data/test/lib/facets/core/hash/test_each_with_key.rb +1 -1
  257. data/test/lib/facets/core/hash/test_graph.rb +1 -1
  258. data/test/lib/facets/core/hash/test_has_keys.rb +1 -1
  259. data/test/lib/facets/core/hash/test_has_only_keys.rb +1 -1
  260. data/test/lib/facets/core/hash/test_inverse.rb +1 -1
  261. data/test/lib/facets/core/hash/test_keys_to_s.rb +1 -1
  262. data/test/lib/facets/core/hash/test_keys_to_sym.rb +1 -1
  263. data/test/lib/facets/core/hash/test_op_fetch.rb +1 -1
  264. data/test/lib/facets/core/hash/test_op_lshift.rb +1 -1
  265. data/test/lib/facets/core/hash/test_rand_key.rb +1 -1
  266. data/test/lib/facets/core/hash/test_rand_pair.rb +1 -1
  267. data/test/lib/facets/core/hash/test_rand_value.rb +1 -1
  268. data/test/lib/facets/core/hash/test_replace_each.rb +1 -1
  269. data/test/lib/facets/core/hash/test_shuffle.rb +1 -1
  270. data/test/lib/facets/core/hash/test_slice.rb +1 -1
  271. data/test/lib/facets/core/hash/test_swap.rb +1 -1
  272. data/test/lib/facets/core/hash/test_swapkey.rb +1 -1
  273. data/test/lib/facets/core/hash/test_to_h.rb +1 -1
  274. data/test/lib/facets/core/hash/test_to_ostruct.rb +1 -1
  275. data/test/lib/facets/core/hash/test_to_ostruct_recurse.rb +1 -1
  276. data/test/lib/facets/core/hash/test_traverse.rb +1 -1
  277. data/test/lib/facets/core/hash/test_update_each.rb +1 -1
  278. data/test/lib/facets/core/hash/test_update_keys.rb +1 -1
  279. data/test/lib/facets/core/hash/test_update_values.rb +1 -1
  280. data/test/lib/facets/core/hash/test_weave.rb +1 -1
  281. data/test/lib/facets/core/integer/test_factorial.rb +1 -1
  282. data/test/lib/facets/core/integer/test_multiple.rb +1 -1
  283. data/test/lib/facets/core/integer/test_ordinal.rb +1 -1
  284. data/test/lib/facets/core/integer/test_times_collect.rb +1 -1
  285. data/test/lib/facets/core/kernel/test___class__.rb +1 -1
  286. data/test/lib/facets/core/kernel/test_as.rb +1 -1
  287. data/test/lib/facets/core/kernel/test_assign_from.rb +1 -1
  288. data/test/lib/facets/core/kernel/test_assign_with.rb +1 -1
  289. data/test/lib/facets/core/kernel/test_bool.rb +1 -1
  290. data/test/lib/facets/core/kernel/test_bug.rb +1 -1
  291. data/test/lib/facets/core/kernel/test_call_stack.rb +1 -1
  292. data/test/lib/facets/core/kernel/test_called.rb +1 -1
  293. data/test/lib/facets/core/kernel/test_constant.rb +1 -1
  294. data/test/lib/facets/core/kernel/test_copy.rb +1 -1
  295. data/test/lib/facets/core/kernel/test_deep_copy.rb +1 -1
  296. data/test/lib/facets/core/kernel/test_demo.rb +1 -1
  297. data/test/lib/facets/core/kernel/test_fn.rb +1 -1
  298. data/test/lib/facets/core/kernel/test_generate_method_name.rb +1 -1
  299. data/test/lib/facets/core/kernel/test_get_by_id.rb +1 -1
  300. data/test/lib/facets/core/kernel/test_here.rb +1 -1
  301. data/test/lib/facets/core/kernel/test_in.rb +1 -1
  302. data/test/lib/facets/core/kernel/test_maybe.rb +1 -1
  303. data/test/lib/facets/core/kernel/test_metaclass.rb +1 -1
  304. data/test/lib/facets/core/kernel/test_method.rb +1 -1
  305. data/test/lib/facets/core/kernel/test_methodname.rb +1 -1
  306. data/test/lib/facets/core/kernel/test_methods.rb +1 -1
  307. data/test/lib/facets/core/kernel/test_new.rb +1 -1
  308. data/test/lib/facets/core/kernel/test_object_class.rb +1 -1
  309. data/test/lib/facets/core/kernel/test_object_hexid.rb +1 -1
  310. data/test/lib/facets/core/kernel/test_require_all.rb +1 -1
  311. data/test/lib/facets/core/kernel/test_require_esc.rb +1 -1
  312. data/test/lib/facets/core/kernel/test_require_facet.rb +1 -1
  313. data/test/lib/facets/core/kernel/test_resc.rb +1 -1
  314. data/test/lib/facets/core/kernel/test_returning.rb +1 -1
  315. data/test/lib/facets/core/kernel/test_send_as.rb +1 -1
  316. data/test/lib/facets/core/kernel/test_set_from.rb +1 -1
  317. data/test/lib/facets/core/kernel/test_set_with.rb +1 -1
  318. data/test/lib/facets/core/kernel/test_silently.rb +1 -1
  319. data/test/lib/facets/core/kernel/test_singleton.rb +1 -1
  320. data/test/lib/facets/core/kernel/test_superior.rb +1 -1
  321. data/test/lib/facets/core/kernel/test_supermethod.rb +1 -1
  322. data/test/lib/facets/core/kernel/test_this.rb +1 -1
  323. data/test/lib/facets/core/kernel/test_to_b.rb +1 -1
  324. data/test/lib/facets/core/kernel/test_to_bool.rb +1 -1
  325. data/test/lib/facets/core/kernel/test_uri.rb +1 -1
  326. data/test/lib/facets/core/kernel/test_val.rb +1 -1
  327. data/test/lib/facets/core/kernel/test_with_accessor.rb +1 -1
  328. data/test/lib/facets/core/matchdata/test_match.rb +1 -1
  329. data/test/lib/facets/core/matchdata/test_matchtree.rb +7 -2
  330. data/test/lib/facets/core/module/test_abstract.rb +1 -1
  331. data/test/lib/facets/core/module/test_alias_module_function.rb +1 -1
  332. data/test/lib/facets/core/module/test_ancestor.rb +1 -1
  333. data/test/lib/facets/core/module/test_basename.rb +1 -1
  334. data/test/lib/facets/core/module/test_by_name.rb +1 -1
  335. data/test/lib/facets/core/module/test_clone_using.rb +1 -1
  336. data/test/lib/facets/core/module/test_dirname.rb +1 -1
  337. data/test/lib/facets/core/module/test_equate_on.rb +1 -1
  338. data/test/lib/facets/core/module/test_generate_instance_method_name.rb +1 -1
  339. data/test/lib/facets/core/module/test_include_as.rb +1 -1
  340. data/test/lib/facets/core/module/test_inherit.rb +1 -1
  341. data/test/lib/facets/core/module/test_initializer.rb +1 -1
  342. data/test/lib/facets/core/module/test_instance_methods.rb +1 -1
  343. data/test/lib/facets/core/module/test_integrate.rb +1 -1
  344. data/test/lib/facets/core/module/test_memoize.rb +1 -1
  345. data/test/lib/facets/core/module/test_modspace.rb +1 -1
  346. data/test/lib/facets/core/module/test_namespace.rb +1 -1
  347. data/test/lib/facets/core/module/test_nesting.rb +1 -1
  348. data/test/lib/facets/core/module/{test_undef.rb → test_nodef.rb} +5 -5
  349. data/test/lib/facets/core/module/test_on_included.rb +1 -1
  350. data/test/lib/facets/core/module/test_redef.rb +1 -1
  351. data/test/lib/facets/core/module/test_redefine_method.rb +1 -1
  352. data/test/lib/facets/core/module/test_redirect.rb +1 -1
  353. data/test/lib/facets/core/module/test_redirect_method.rb +1 -1
  354. data/test/lib/facets/core/module/test_remove.rb +1 -1
  355. data/test/lib/facets/core/module/test_rename.rb +1 -1
  356. data/test/lib/facets/core/module/test_rename_method.rb +1 -1
  357. data/test/lib/facets/core/module/test_revisal.rb +1 -1
  358. data/test/lib/facets/core/module/test_shadow_method.rb +1 -1
  359. data/test/lib/facets/core/module/test_sort_on.rb +1 -1
  360. data/test/lib/facets/core/module/test_this.rb +1 -1
  361. data/test/lib/facets/core/module/test_wrap.rb +1 -1
  362. data/test/lib/facets/core/module/test_wrap_method.rb +1 -1
  363. data/test/lib/facets/core/nilclass/test_blank.rb +1 -1
  364. data/test/lib/facets/core/nilclass/test_empty.rb +1 -1
  365. data/test/lib/facets/core/nilclass/test_include.rb +1 -1
  366. data/test/lib/facets/core/nilclass/test_op_fetch.rb +1 -1
  367. data/test/lib/facets/core/nilclass/test_size.rb +1 -1
  368. data/test/lib/facets/core/nilclass/test_to_h.rb +1 -1
  369. data/test/lib/facets/core/numeric/test_approx.rb +1 -1
  370. data/test/lib/facets/core/numeric/test_ceil_multiple.rb +1 -1
  371. data/test/lib/facets/core/numeric/test_succ.rb +1 -1
  372. data/test/lib/facets/core/numeric/test_to_b.rb +1 -1
  373. data/test/lib/facets/core/ostruct/test___merge__.rb +1 -1
  374. data/test/lib/facets/core/ostruct/test___update__.rb +1 -1
  375. data/test/lib/facets/core/ostruct/test_op_fetch.rb +1 -1
  376. data/test/lib/facets/core/ostruct/test_op_store.rb +1 -1
  377. data/test/lib/facets/core/proc/test_compose.rb +1 -1
  378. data/test/lib/facets/core/proc/test_to_method.rb +1 -1
  379. data/test/lib/facets/core/range/test_to_r.rb +1 -1
  380. data/test/lib/facets/core/range/test_to_range.rb +1 -1
  381. data/test/lib/facets/core/range/test_umbrella.rb +1 -1
  382. data/test/lib/facets/core/range/test_within.rb +1 -1
  383. data/test/lib/facets/core/regexp/test_arity.rb +1 -1
  384. data/test/lib/facets/core/regexp/test_to_re.rb +1 -1
  385. data/test/lib/facets/core/regexp/test_to_regexp.rb +1 -1
  386. data/test/lib/facets/core/string/self/test_interpolate.rb +1 -1
  387. data/test/lib/facets/core/string/self/test_patterns.rb +1 -1
  388. data/test/lib/facets/core/string/self/test_rand_letter.rb +1 -1
  389. data/test/lib/facets/core/string/test_align_center.rb +1 -1
  390. data/test/lib/facets/core/string/test_at_rand.rb +1 -1
  391. data/test/lib/facets/core/string/test_basename.rb +1 -1
  392. data/test/lib/facets/core/string/test_blank.rb +1 -1
  393. data/test/lib/facets/core/string/test_bracket.rb +1 -1
  394. data/test/lib/facets/core/string/test_camelcase.rb +1 -1
  395. data/test/lib/facets/core/string/test_camelize.rb +1 -1
  396. data/test/lib/facets/core/string/test_capitalized.rb +1 -1
  397. data/test/lib/facets/core/string/test_chars.rb +1 -1
  398. data/test/lib/facets/core/string/test_cmp.rb +1 -1
  399. data/test/lib/facets/core/string/test_demodulize.rb +1 -1
  400. data/test/lib/facets/core/string/test_downcase.rb +1 -1
  401. data/test/lib/facets/core/string/test_dresner.rb +1 -1
  402. data/test/lib/facets/core/string/test_each_char.rb +1 -1
  403. data/test/lib/facets/core/string/test_each_word.rb +1 -1
  404. data/test/lib/facets/core/string/test_first.rb +1 -1
  405. data/test/lib/facets/core/string/test_fold.rb +1 -1
  406. data/test/lib/facets/core/string/test_frequency.rb +1 -1
  407. data/test/lib/facets/core/string/test_humanize.rb +1 -1
  408. data/test/lib/facets/core/string/test_indent.rb +1 -1
  409. data/test/lib/facets/core/string/test_index_all.rb +1 -1
  410. data/test/lib/facets/core/string/test_last.rb +1 -1
  411. data/test/lib/facets/core/string/test_line_wrap.rb +1 -1
  412. data/test/lib/facets/core/string/test_lines.rb +1 -1
  413. data/test/lib/facets/core/string/test_lowercase.rb +1 -1
  414. data/test/lib/facets/core/string/test_margin.rb +1 -1
  415. data/test/lib/facets/core/string/test_methodize.rb +1 -1
  416. data/test/lib/facets/core/string/test_modulize.rb +1 -1
  417. data/test/lib/facets/core/string/test_mscan.rb +1 -1
  418. data/test/lib/facets/core/string/test_natcmp.rb +1 -1
  419. data/test/lib/facets/core/string/test_nchar.rb +1 -1
  420. data/test/lib/facets/core/string/test_pathize.rb +1 -1
  421. data/test/lib/facets/core/string/test_pop.rb +1 -1
  422. data/test/lib/facets/core/string/test_pot.rb +1 -1
  423. data/test/lib/facets/core/string/test_probability.rb +1 -1
  424. data/test/lib/facets/core/string/test_push.rb +1 -1
  425. data/test/lib/facets/core/string/test_quote.rb +1 -1
  426. data/test/lib/facets/core/string/test_rand_byte.rb +1 -1
  427. data/test/lib/facets/core/string/test_rand_index.rb +1 -1
  428. data/test/lib/facets/core/string/test_range.rb +1 -1
  429. data/test/lib/facets/core/string/test_range_all.rb +1 -1
  430. data/test/lib/facets/core/string/test_range_of_line.rb +1 -1
  431. data/test/lib/facets/core/string/test_regesc.rb +1 -1
  432. data/test/lib/facets/core/string/test_shatter.rb +1 -1
  433. data/test/lib/facets/core/string/test_shift.rb +1 -1
  434. data/test/lib/facets/core/string/test_shuffle.rb +1 -1
  435. data/test/lib/facets/core/string/test_similarity.rb +1 -1
  436. data/test/lib/facets/core/string/test_singular.rb +1 -1
  437. data/test/lib/facets/core/string/test_soundex.rb +1 -1
  438. data/test/lib/facets/core/string/test_succ.rb +1 -1
  439. data/test/lib/facets/core/string/test_to_a.rb +1 -1
  440. data/test/lib/facets/core/string/test_to_b.rb +1 -1
  441. data/test/lib/facets/core/string/test_to_const.rb +1 -1
  442. data/test/lib/facets/core/string/test_to_date.rb +1 -1
  443. data/test/lib/facets/core/string/test_to_proc.rb +1 -1
  444. data/test/lib/facets/core/string/test_to_re.rb +1 -1
  445. data/test/lib/facets/core/string/test_to_time.rb +1 -1
  446. data/test/lib/facets/core/string/test_unix_crypt.rb +1 -1
  447. data/test/lib/facets/core/string/test_unpack.rb +1 -1
  448. data/test/lib/facets/core/string/test_unshift.rb +1 -1
  449. data/test/lib/facets/core/string/test_upcase.rb +1 -1
  450. data/test/lib/facets/core/string/test_whitespace.rb +1 -1
  451. data/test/lib/facets/core/string/test_word_filter.rb +1 -1
  452. data/test/lib/facets/core/string/test_word_wrap.rb +1 -1
  453. data/test/lib/facets/core/string/test_words.rb +1 -1
  454. data/test/lib/facets/core/symbol/test_camelcase.rb +1 -1
  455. data/test/lib/facets/core/symbol/test_camelize.rb +1 -1
  456. data/test/lib/facets/core/symbol/test_capitalize.rb +1 -1
  457. data/test/lib/facets/core/symbol/test_capitalized.rb +1 -1
  458. data/test/lib/facets/core/symbol/test_downcase.rb +1 -1
  459. data/test/lib/facets/core/symbol/test_not.rb +1 -1
  460. data/test/lib/facets/core/symbol/test_pad.rb +1 -1
  461. data/test/lib/facets/core/symbol/test_succ.rb +1 -1
  462. data/test/lib/facets/core/symbol/test_to_const.rb +1 -1
  463. data/test/lib/facets/core/symbol/test_to_proc.rb +1 -1
  464. data/test/lib/facets/core/symbol/test_to_str.rb +1 -1
  465. data/test/lib/facets/core/symbol/test_underscore.rb +1 -1
  466. data/test/lib/facets/core/symbol/test_upcase.rb +1 -1
  467. data/test/lib/facets/core/time/test_change.rb +1 -1
  468. data/test/lib/facets/core/time/test_elapse.rb +1 -1
  469. data/test/lib/facets/core/time/test_stamp.rb +1 -1
  470. data/test/lib/facets/core/time/test_to_date.rb +1 -1
  471. data/test/lib/facets/core/time/test_to_s.rb +1 -1
  472. data/test/lib/facets/core/time/test_to_time.rb +1 -1
  473. data/test/lib/facets/more/test_annattr.rb +39 -0
  474. data/test/lib/facets/more/test_annotatedattr.rb +39 -0
  475. data/test/lib/facets/more/test_annotation.rb +1 -22
  476. data/test/lib/facets/more/test_ansicode.rb +1 -1
  477. data/test/lib/facets/more/test_association.rb +6 -1
  478. data/test/lib/facets/more/test_basicobject.rb +1 -1
  479. data/test/lib/facets/more/test_bbcode.rb +1 -1
  480. data/test/lib/facets/more/test_binaryreader.rb +64 -0
  481. data/test/lib/facets/more/test_bitmask.rb +1 -1
  482. data/test/lib/facets/more/test_bytes.rb +1 -1
  483. data/test/lib/facets/more/test_classinherit.rb +1 -1
  484. data/test/lib/facets/more/test_classmethods.rb +1 -1
  485. data/test/lib/facets/more/test_coroutine.rb +1 -1
  486. data/test/lib/facets/more/test_crypt.rb +1 -1
  487. data/test/lib/facets/more/test_dictionary.rb +1 -1
  488. data/test/lib/facets/more/test_elementor.rb +1 -1
  489. data/test/lib/facets/more/test_enumerablepass.rb +1 -1
  490. data/test/lib/facets/more/test_floatstring.rb +1 -1
  491. data/test/lib/facets/more/test_functor.rb +1 -1
  492. data/test/lib/facets/more/test_htmlbuilder.rb +1 -1
  493. data/test/lib/facets/more/test_inheritor.rb +1 -1
  494. data/test/lib/facets/more/test_interval.rb +1 -1
  495. data/test/lib/facets/more/test_json.rb +1 -1
  496. data/test/lib/facets/more/test_lisp.rb +1 -1
  497. data/test/lib/facets/more/test_lisp_format.rb +1 -1
  498. data/test/lib/facets/more/test_lrucache.rb +1 -1
  499. data/test/lib/facets/more/test_mathconstants.rb +1 -1
  500. data/test/lib/facets/more/test_methodprobe.rb +1 -1
  501. data/test/lib/facets/more/test_multipliers.rb +1 -1
  502. data/test/lib/facets/more/test_multiton.rb +1 -1
  503. data/test/lib/facets/more/test_nackclass.rb +1 -1
  504. data/test/lib/facets/more/test_nilcomparable.rb +1 -1
  505. data/test/lib/facets/more/test_opencascade.rb +66 -0
  506. data/test/lib/facets/more/test_openobject.rb +14 -2
  507. data/test/lib/facets/more/test_overload.rb +1 -1
  508. data/test/lib/facets/more/test_paramix.rb +1 -1
  509. data/test/lib/facets/more/test_pqueue.rb +39 -0
  510. data/test/lib/facets/more/test_preinitialize.rb +1 -1
  511. data/test/lib/facets/more/test_promoteself.rb +1 -1
  512. data/test/lib/facets/more/test_recorder.rb +1 -1
  513. data/test/lib/facets/more/test_snapshot.rb +1 -1
  514. data/test/lib/facets/more/test_statichash.rb +11 -11
  515. data/test/lib/facets/more/test_syncarray.rb +1 -1
  516. data/test/lib/facets/more/test_synchash.rb +1 -1
  517. data/test/lib/facets/more/test_tagiterator.rb +1 -1
  518. data/test/lib/facets/more/test_taskable.rb +151 -0
  519. data/test/lib/facets/more/test_timer.rb +1 -1
  520. data/test/lib/facets/more/test_times.rb +1 -1
  521. data/test/lib/facets/more/test_tuple.rb +1 -1
  522. data/test/lib/facets/more/test_typecast.rb +1 -1
  523. data/test/lib/facets/more/test_uninheritable.rb +1 -1
  524. data/test/lib/facets/more/test_units.rb +1 -1
  525. data/test/lib/facets/more/test_xmlbuilder.rb +1 -1
  526. data/test/lib/facets/more/test_xmlhelper.rb +1 -1
  527. data/test/lib/facets/more/test_xoxo.rb +1 -1
  528. data/test/lib/facets/more/test_yamlstruct.rb +1 -1
  529. metadata +1243 -1247
  530. data/ProjectInfo +0 -89
  531. data/Rakefile +0 -181
  532. data/doc/CHANGELOG +0 -284
  533. data/doc/TODO +0 -73
  534. data/doc/noauto +0 -63
  535. data/lib/facet/array.rb +0 -1
  536. data/lib/facet/class.rb +0 -1
  537. data/lib/facet/comparable.rb +0 -1
  538. data/lib/facet/continuation.rb +0 -1
  539. data/lib/facet/date.rb +0 -1
  540. data/lib/facet/dir.rb +0 -1
  541. data/lib/facet/enumerable.rb +0 -1
  542. data/lib/facet/file.rb +0 -1
  543. data/lib/facet/fileutils.rb +0 -1
  544. data/lib/facet/float.rb +0 -1
  545. data/lib/facet/gem.rb +0 -1
  546. data/lib/facet/hash.rb +0 -1
  547. data/lib/facet/integer.rb +0 -1
  548. data/lib/facet/kernel.rb +0 -1
  549. data/lib/facet/logger.rb +0 -1
  550. data/lib/facet/matchdata.rb +0 -1
  551. data/lib/facet/module.rb +0 -1
  552. data/lib/facet/module/undef.rb +0 -1
  553. data/lib/facet/nilclass.rb +0 -1
  554. data/lib/facet/numeric.rb +0 -1
  555. data/lib/facet/pathname.rb +0 -1
  556. data/lib/facet/proc.rb +0 -1
  557. data/lib/facet/range.rb +0 -1
  558. data/lib/facet/regexp.rb +0 -1
  559. data/lib/facet/string.rb +0 -1
  560. data/lib/facet/symbol.rb +0 -1
  561. data/lib/facet/time.rb +0 -1
  562. data/lib/facet/unboundmethod.rb +0 -1
  563. data/lib/facets/core/array.rb +0 -35
  564. data/lib/facets/core/class.rb +0 -11
  565. data/lib/facets/core/comparable.rb +0 -5
  566. data/lib/facets/core/continuation.rb +0 -1
  567. data/lib/facets/core/date.rb +0 -6
  568. data/lib/facets/core/dir.rb +0 -4
  569. data/lib/facets/core/enumerable.rb +0 -42
  570. data/lib/facets/core/file.rb +0 -8
  571. data/lib/facets/core/fileutils.rb +0 -8
  572. data/lib/facets/core/float.rb +0 -4
  573. data/lib/facets/core/gem.rb +0 -4
  574. data/lib/facets/core/hash.rb +0 -40
  575. data/lib/facets/core/integer.rb +0 -9
  576. data/lib/facets/core/kernel.rb +0 -69
  577. data/lib/facets/core/logger.rb +0 -2
  578. data/lib/facets/core/matchdata.rb +0 -3
  579. data/lib/facets/core/module.rb +0 -43
  580. data/lib/facets/core/nilclass.rb +0 -9
  581. data/lib/facets/core/numeric.rb +0 -6
  582. data/lib/facets/core/pathname.rb +0 -2
  583. data/lib/facets/core/proc.rb +0 -3
  584. data/lib/facets/core/range.rb +0 -4
  585. data/lib/facets/core/regexp.rb +0 -3
  586. data/lib/facets/core/string.rb +0 -91
  587. data/lib/facets/core/symbol.rb +0 -13
  588. data/lib/facets/core/time.rb +0 -8
  589. data/lib/facets/core/unboundmethod.rb +0 -1
@@ -0,0 +1,1608 @@
1
+ # = httpaccess.rb
2
+ #
3
+ # == Copyright (C) 2000 NAKAMURA, Hiroshi
4
+ #
5
+ # Ruby License
6
+ #
7
+ # This module is free software. You may use, modify, and/or redistribute this
8
+ # software under the same terms as Ruby.
9
+ #
10
+ # This program is distributed in the hope that it will be useful, but WITHOUT
11
+ # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12
+ # FOR A PARTICULAR PURPOSE.
13
+ #
14
+ # == Author(s)
15
+ #
16
+ # * Hiroshi Nakamura <nakahiro@sarion.co.jp>
17
+ # * Maehashi
18
+ #
19
+ # == Developer Notes
20
+ #
21
+ # NOTE httpaccess.rb is based on http-access2.rb which is based on
22
+ # http-access/0.0.4. Some part of code in http-access.rb was recycled
23
+ # in http-access2.rb. Those parts are copyrighted by Maehashi-san.
24
+
25
+ # Author:: Hiroshi Nakamura and Maehashi
26
+ # Copyright:: Copyright (c) 2000 Hiroshi Nakamura and Maehashi
27
+ # License:: Ruby License
28
+
29
+ # Ruby standard library
30
+ require 'timeout'
31
+ require 'uri'
32
+ require 'socket'
33
+ require 'thread'
34
+
35
+ # Extra library
36
+ require 'facets/more/http'
37
+ require 'facets/more/cookie'
38
+
39
+ # = HTTP Accessing Library
40
+ #
41
+ # Provides an easy to use HTTP interface. Easily retrive web pages
42
+ # programmtically submit forms.
43
+
44
+ module HTTPAccess
45
+
46
+ VERSION = '2.0.6'
47
+ RUBY_VERSION_STRING = "ruby #{RUBY_VERSION} (#{RUBY_RELEASE_DATE}) [#{RUBY_PLATFORM}]"
48
+ s = %w$Id: http-access2.rb 114 2005-09-13 03:20:38Z nahi $
49
+ RCS_FILE, RCS_REVISION = s[1][/.*(?=,v$)/], s[2]
50
+
51
+ SSLEnabled = begin
52
+ require 'openssl'
53
+ true
54
+ rescue LoadError
55
+ false
56
+ end
57
+
58
+ DEBUG_SSL = true
59
+
60
+ # DESCRIPTION
61
+ # HTTPAccess::Client -- Client to retrieve web resources via HTTP.
62
+ #
63
+ # How to create your client.
64
+ # 1. Create simple client.
65
+ # clnt = HTTPAccess::Client.new
66
+ #
67
+ # 2. Accessing resources through HTTP proxy.
68
+ # clnt = HTTPAccess::Client.new("http://myproxy:8080")
69
+ #
70
+ # 3. Set User-Agent and From in HTTP request header.(nil means "No proxy")
71
+ # clnt = HTTPAccess::Client.new(nil, "MyAgent", "nahi@keynauts.com")
72
+ #
73
+ # How to retrieve web resources.
74
+ # 1. Get content of specified URL.
75
+ # puts clnt.get_content("http://www.ruby-lang.org/en/")
76
+ #
77
+ # 2. Do HEAD request.
78
+ # res = clnt.head(uri)
79
+ #
80
+ # 3. Do GET request with query.
81
+ # res = clnt.get(uri)
82
+ #
83
+ # 4. Do POST request.
84
+ # res = clnt.post(uri)
85
+ # res = clnt.get|post|head(uri, proxy)
86
+ #
87
+ class Client
88
+ attr_reader :agent_name
89
+ attr_reader :from
90
+ attr_reader :ssl_config
91
+ attr_accessor :cookie_manager
92
+ attr_reader :test_loopback_response
93
+
94
+ class << self
95
+ %w(get_content head get post put delete options trace).each do |name|
96
+ eval <<-EOD
97
+ def #{name}(*arg)
98
+ new.#{name}(*arg)
99
+ end
100
+ EOD
101
+ end
102
+ end
103
+
104
+ # SYNOPSIS
105
+ # Client.new(proxy = nil, agent_name = nil, from = nil)
106
+ #
107
+ # ARGS
108
+ # proxy A String of HTTP proxy URL. ex. "http://proxy:8080".
109
+ # agent_name A String for "User-Agent" HTTP request header.
110
+ # from A String for "From" HTTP request header.
111
+ #
112
+ # DESCRIPTION
113
+ # Create an instance.
114
+ # SSLConfig cannot be re-initialized. Create new client.
115
+ #
116
+ def initialize(proxy = nil, agent_name = nil, from = nil)
117
+ @proxy = nil # assigned later.
118
+ @no_proxy = nil
119
+ @agent_name = agent_name
120
+ @from = from
121
+ @basic_auth = BasicAuth.new(self)
122
+ @debug_dev = nil
123
+ @ssl_config = SSLConfig.new(self)
124
+ @redirect_uri_callback = method(:default_redirect_uri_callback)
125
+ @test_loopback_response = []
126
+ @session_manager = SessionManager.new
127
+ @session_manager.agent_name = @agent_name
128
+ @session_manager.from = @from
129
+ @session_manager.ssl_config = @ssl_config
130
+ @cookie_manager = WebAgent::CookieManager.new
131
+ self.proxy = proxy
132
+ end
133
+
134
+ def debug_dev
135
+ @debug_dev
136
+ end
137
+
138
+ def debug_dev=(dev)
139
+ @debug_dev = dev
140
+ reset_all
141
+ @session_manager.debug_dev = dev
142
+ end
143
+
144
+ def protocol_version
145
+ @session_manager.protocol_version
146
+ end
147
+
148
+ def protocol_version=(protocol_version)
149
+ reset_all
150
+ @session_manager.protocol_version = protocol_version
151
+ end
152
+
153
+ def connect_timeout
154
+ @session_manager.connect_timeout
155
+ end
156
+
157
+ def connect_timeout=(connect_timeout)
158
+ reset_all
159
+ @session_manager.connect_timeout = connect_timeout
160
+ end
161
+
162
+ def send_timeout
163
+ @session_manager.send_timeout
164
+ end
165
+
166
+ def send_timeout=(send_timeout)
167
+ reset_all
168
+ @session_manager.send_timeout = send_timeout
169
+ end
170
+
171
+ def receive_timeout
172
+ @session_manager.receive_timeout
173
+ end
174
+
175
+ def receive_timeout=(receive_timeout)
176
+ reset_all
177
+ @session_manager.receive_timeout = receive_timeout
178
+ end
179
+
180
+ def proxy
181
+ @proxy
182
+ end
183
+
184
+ def proxy=(proxy)
185
+ if proxy.nil?
186
+ @proxy = nil
187
+ else
188
+ if proxy.is_a?(URI)
189
+ @proxy = proxy
190
+ else
191
+ @proxy = URI.parse(proxy)
192
+ end
193
+ if @proxy.scheme == nil or @proxy.scheme.downcase != 'http' or
194
+ @proxy.host == nil or @proxy.port == nil
195
+ raise ArgumentError.new("unsupported proxy `#{proxy}'")
196
+ end
197
+ end
198
+ reset_all
199
+ @proxy
200
+ end
201
+
202
+ def no_proxy
203
+ @no_proxy
204
+ end
205
+
206
+ def no_proxy=(no_proxy)
207
+ @no_proxy = no_proxy
208
+ reset_all
209
+ end
210
+
211
+ # if your ruby is older than 2005-09-06, do not set socket_sync = false to
212
+ # avoid an SSL socket blocking bug in openssl/buffering.rb.
213
+ def socket_sync=(socket_sync)
214
+ @session_manager.socket_sync = socket_sync
215
+ end
216
+
217
+ def set_basic_auth(uri, user_id, passwd)
218
+ unless uri.is_a?(URI)
219
+ uri = URI.parse(uri)
220
+ end
221
+ @basic_auth.set(uri, user_id, passwd)
222
+ end
223
+
224
+ def set_cookie_store(filename)
225
+ if @cookie_manager.cookies_file
226
+ raise RuntimeError.new("overriding cookie file location")
227
+ end
228
+ @cookie_manager.cookies_file = filename
229
+ @cookie_manager.load_cookies if filename
230
+ end
231
+
232
+ def save_cookie_store
233
+ @cookie_manager.save_cookies
234
+ end
235
+
236
+ def redirect_uri_callback=(redirect_uri_callback)
237
+ @redirect_uri_callback = redirect_uri_callback
238
+ end
239
+
240
+ # SYNOPSIS
241
+ # Client#get_content(uri, query = nil, extheader = {}, &block = nil)
242
+ #
243
+ # ARGS
244
+ # uri an_URI or a_string of uri to connect.
245
+ # query a_hash or an_array of query part. e.g. { "a" => "b" }.
246
+ # Give an array to pass multiple value like
247
+ # [["a" => "b"], ["a" => "c"]].
248
+ # extheader
249
+ # a_hash of extra headers like { "SOAPAction" => "urn:foo" }.
250
+ # &block Give a block to get chunked message-body of response like
251
+ # get_content(uri) { |chunked_body| ... }
252
+ # Size of each chunk may not be the same.
253
+ #
254
+ # DESCRIPTION
255
+ # Get a_sring of message-body of response.
256
+ #
257
+ def get_content(uri, query = nil, extheader = {}, &block)
258
+ retry_connect(uri, query) do |uri, query|
259
+ get(uri, query, extheader, &block)
260
+ end
261
+ end
262
+
263
+ def post_content(uri, body = nil, extheader = {}, &block)
264
+ retry_connect(uri, nil) do |uri, query|
265
+ post(uri, body, extheader, &block)
266
+ end
267
+ end
268
+
269
+ def default_redirect_uri_callback(res)
270
+ uri = res.header['location'][0]
271
+ puts "Redirect to: #{uri}" if $DEBUG
272
+ uri
273
+ end
274
+
275
+ def head(uri, query = nil, extheader = {})
276
+ request('HEAD', uri, query, nil, extheader)
277
+ end
278
+
279
+ def get(uri, query = nil, extheader = {}, &block)
280
+ request('GET', uri, query, nil, extheader, &block)
281
+ end
282
+
283
+ def post(uri, body = nil, extheader = {}, &block)
284
+ request('POST', uri, nil, body, extheader, &block)
285
+ end
286
+
287
+ def put(uri, body = nil, extheader = {}, &block)
288
+ request('PUT', uri, nil, body, extheader, &block)
289
+ end
290
+
291
+ def delete(uri, extheader = {}, &block)
292
+ request('DELETE', uri, nil, nil, extheader, &block)
293
+ end
294
+
295
+ def options(uri, extheader = {}, &block)
296
+ request('OPTIONS', uri, nil, nil, extheader, &block)
297
+ end
298
+
299
+ def trace(uri, query = nil, body = nil, extheader = {}, &block)
300
+ request('TRACE', uri, query, body, extheader, &block)
301
+ end
302
+
303
+ def request(method, uri, query = nil, body = nil, extheader = {}, &block)
304
+ conn = Connection.new
305
+ conn_request(conn, method, uri, query, body, extheader, &block)
306
+ conn.pop
307
+ end
308
+
309
+ # Async interface.
310
+
311
+ def head_async(uri, query = nil, extheader = {})
312
+ request_async('HEAD', uri, query, nil, extheader)
313
+ end
314
+
315
+ def get_async(uri, query = nil, extheader = {})
316
+ request_async('GET', uri, query, nil, extheader)
317
+ end
318
+
319
+ def post_async(uri, body = nil, extheader = {})
320
+ request_async('POST', uri, nil, body, extheader)
321
+ end
322
+
323
+ def put_async(uri, body = nil, extheader = {})
324
+ request_async('PUT', uri, nil, body, extheader)
325
+ end
326
+
327
+ def delete_async(uri, extheader = {})
328
+ request_async('DELETE', uri, nil, nil, extheader)
329
+ end
330
+
331
+ def options_async(uri, extheader = {})
332
+ request_async('OPTIONS', uri, nil, nil, extheader)
333
+ end
334
+
335
+ def trace_async(uri, query = nil, body = nil, extheader = {})
336
+ request_async('TRACE', uri, query, body, extheader)
337
+ end
338
+
339
+ def request_async(method, uri, query = nil, body = nil, extheader = {})
340
+ conn = Connection.new
341
+ t = Thread.new(conn) { |tconn|
342
+ conn_request(tconn, method, uri, query, body, extheader)
343
+ }
344
+ conn.async_thread = t
345
+ conn
346
+ end
347
+
348
+ ##
349
+ # Multiple call interface.
350
+
351
+ # ???
352
+
353
+ ##
354
+ # Management interface.
355
+
356
+ def reset(uri)
357
+ @session_manager.reset(uri)
358
+ end
359
+
360
+ def reset_all
361
+ @session_manager.reset_all
362
+ end
363
+
364
+ private
365
+
366
+ def retry_connect(uri, query = nil)
367
+ retry_number = 0
368
+ while retry_number < 10
369
+ res = yield(uri, query)
370
+ if res.status == HTTP::Status::OK
371
+ return res.content
372
+ elsif HTTP::Status.redirect?(res.status)
373
+ uri = @redirect_uri_callback.call(res)
374
+ query = nil
375
+ retry_number += 1
376
+ else
377
+ raise RuntimeError.new("Unexpected response: #{res.header.inspect}")
378
+ end
379
+ end
380
+ raise RuntimeError.new("Retry count exceeded.")
381
+ end
382
+
383
+ def conn_request(conn, method, uri, query, body, extheader, &block)
384
+ unless uri.is_a?(URI)
385
+ uri = URI.parse(uri)
386
+ end
387
+ proxy = no_proxy?(uri) ? nil : @proxy
388
+ begin
389
+ req = create_request(method, uri, query, body, extheader, !proxy.nil?)
390
+ do_get_block(req, proxy, conn, &block)
391
+ rescue Session::KeepAliveDisconnected
392
+ req = create_request(method, uri, query, body, extheader, !proxy.nil?)
393
+ do_get_block(req, proxy, conn, &block)
394
+ end
395
+ end
396
+
397
+ def create_request(method, uri, query, body, extheader, proxy)
398
+ if extheader.is_a?(Hash)
399
+ extheader = extheader.to_a
400
+ end
401
+ cred = @basic_auth.get(uri)
402
+ if cred
403
+ extheader << ['Authorization', "Basic " << cred]
404
+ end
405
+ if cookies = @cookie_manager.find(uri)
406
+ extheader << ['Cookie', cookies]
407
+ end
408
+ boundary = nil
409
+ content_type = extheader.find { |key, value|
410
+ key.downcase == 'content-type'
411
+ }
412
+ if content_type && content_type[1] =~ /boundary=(.+)\z/
413
+ boundary = $1
414
+ end
415
+ req = HTTP::Message.new_request(method, uri, query, body, proxy, boundary)
416
+ extheader.each do |key, value|
417
+ req.header.set(key, value)
418
+ end
419
+ if content_type.nil? and !body.nil?
420
+ req.header.set('content-type', 'application/x-www-form-urlencoded')
421
+ end
422
+ req
423
+ end
424
+
425
+ NO_PROXY_HOSTS = ['localhost']
426
+
427
+ def no_proxy?(uri)
428
+ if !@proxy or NO_PROXY_HOSTS.include?(uri.host)
429
+ return true
430
+ end
431
+ unless @no_proxy
432
+ return false
433
+ end
434
+ @no_proxy.scan(/([^:,]+)(?::(\d+))?/) do |host, port|
435
+ if /(\A|\.)#{Regexp.quote(host)}\z/i =~ uri.host &&
436
+ (!port || uri.port == port.to_i)
437
+ return true
438
+ end
439
+ end
440
+ false
441
+ end
442
+
443
+ # !! CAUTION !!
444
+ # Method 'do_get*' runs under MT conditon. Be careful to change.
445
+ def do_get_block(req, proxy, conn, &block)
446
+ if str = @test_loopback_response.shift
447
+ dump_dummy_request_response(req.body.dump, str) if @debug_dev
448
+ conn.push(HTTP::Message.new_response(str))
449
+ return
450
+ end
451
+ content = ''
452
+ res = HTTP::Message.new_response(content)
453
+ @debug_dev << "= Request\n\n" if @debug_dev
454
+ sess = @session_manager.query(req, proxy)
455
+ @debug_dev << "\n\n= Response\n\n" if @debug_dev
456
+ do_get_header(req, res, sess)
457
+ conn.push(res)
458
+ sess.get_data() do |str|
459
+ block.call(str) if block
460
+ content << str
461
+ end
462
+ @session_manager.keep(sess) unless sess.closed?
463
+ end
464
+
465
+ def do_get_stream(req, proxy, conn)
466
+ if str = @test_loopback_response.shift
467
+ dump_dummy_request_response(req.body.dump, str) if @debug_dev
468
+ conn.push(HTTP::Message.new_response(str))
469
+ return
470
+ end
471
+ piper, pipew = IO.pipe
472
+ res = HTTP::Message.new_response(piper)
473
+ @debug_dev << "= Request\n\n" if @debug_dev
474
+ sess = @session_manager.query(req, proxy)
475
+ @debug_dev << "\n\n= Response\n\n" if @debug_dev
476
+ do_get_header(req, res, sess)
477
+ conn.push(res)
478
+ sess.get_data() do |str|
479
+ pipew.syswrite(str)
480
+ end
481
+ pipew.close
482
+ @session_manager.keep(sess) unless sess.closed?
483
+ end
484
+
485
+ def do_get_header(req, res, sess)
486
+ res.version, res.status, res.reason = sess.get_status
487
+ sess.get_header().each do |line|
488
+ unless /^([^:]+)\s*:\s*(.*)$/ =~ line
489
+ raise RuntimeError.new("Unparsable header: '#{line}'.") if $DEBUG
490
+ end
491
+ res.header.set($1, $2)
492
+ end
493
+ if res.header['set-cookie']
494
+ res.header['set-cookie'].each do |cookie|
495
+ @cookie_manager.parse(cookie, req.header.request_uri)
496
+ end
497
+ end
498
+ end
499
+
500
+ def dump_dummy_request_response(req, res)
501
+ @debug_dev << "= Dummy Request\n\n"
502
+ @debug_dev << req
503
+ @debug_dev << "\n\n= Dummy Response\n\n"
504
+ @debug_dev << res
505
+ end
506
+ end
507
+
508
+
509
+ # HTTPAccess::SSLConfig -- SSL configuration of a client.
510
+ #
511
+ class SSLConfig # :nodoc:
512
+ attr_reader :client_cert
513
+ attr_reader :client_key
514
+ attr_reader :client_ca
515
+
516
+ attr_reader :verify_mode
517
+ attr_reader :verify_depth
518
+ attr_reader :verify_callback
519
+
520
+ attr_reader :timeout
521
+ attr_reader :options
522
+ attr_reader :ciphers
523
+
524
+ attr_reader :cert_store # don't use if you don't know what it is.
525
+
526
+ def initialize(client)
527
+ return unless SSLEnabled
528
+ @client = client
529
+ @cert_store = OpenSSL::X509::Store.new
530
+ @client_cert = @client_key = @client_ca = nil
531
+ @verify_mode = OpenSSL::SSL::VERIFY_PEER |
532
+ OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT
533
+ @verify_depth = nil
534
+ @verify_callback = nil
535
+ @dest = nil
536
+ @timeout = nil
537
+ @options = defined?(OpenSSL::SSL::OP_ALL) ?
538
+ OpenSSL::SSL::OP_ALL | OpenSSL::SSL::OP_NO_SSLv2 : nil
539
+ @ciphers = "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH"
540
+ end
541
+
542
+ def set_client_cert_file(cert_file, key_file)
543
+ @client_cert = OpenSSL::X509::Certificate.new(File.open(cert_file).read)
544
+ @client_key = OpenSSL::PKey::RSA.new(File.open(key_file).read)
545
+ change_notify
546
+ end
547
+
548
+ def set_trust_ca(trust_ca_file_or_hashed_dir)
549
+ if FileTest.directory?(trust_ca_file_or_hashed_dir)
550
+ @cert_store.add_path(trust_ca_file_or_hashed_dir)
551
+ else
552
+ @cert_store.add_file(trust_ca_file_or_hashed_dir)
553
+ end
554
+ change_notify
555
+ end
556
+
557
+ def set_crl(crl_file)
558
+ crl = OpenSSL::X509::CRL.new(File.open(crl_file).read)
559
+ @cert_store.add_crl(crl)
560
+ @cert_store.flags = OpenSSL::X509::V_FLAG_CRL_CHECK | OpenSSL::X509::V_FLAG_CRL_CHECK_ALL
561
+ change_notify
562
+ end
563
+
564
+ def client_cert=(client_cert)
565
+ @client_cert = client_cert
566
+ change_notify
567
+ end
568
+
569
+ def client_key=(client_key)
570
+ @client_key = client_key
571
+ change_notify
572
+ end
573
+
574
+ def client_ca=(client_ca)
575
+ @client_ca = client_ca
576
+ change_notify
577
+ end
578
+
579
+ def verify_mode=(verify_mode)
580
+ @verify_mode = verify_mode
581
+ change_notify
582
+ end
583
+
584
+ def verify_depth=(verify_depth)
585
+ @verify_depth = verify_depth
586
+ change_notify
587
+ end
588
+
589
+ def verify_callback=(verify_callback)
590
+ @verify_callback = verify_callback
591
+ change_notify
592
+ end
593
+
594
+ def timeout=(timeout)
595
+ @timeout = timeout
596
+ change_notify
597
+ end
598
+
599
+ def options=(options)
600
+ @options = options
601
+ change_notify
602
+ end
603
+
604
+ def ciphers=(ciphers)
605
+ @ciphers = ciphers
606
+ change_notify
607
+ end
608
+
609
+ # don't use if you don't know what it is.
610
+ def cert_store=(cert_store)
611
+ @cert_store = cert_store
612
+ change_notify
613
+ end
614
+
615
+ # interfaces for SSLSocketWrap.
616
+
617
+ def set_context(ctx)
618
+ # Verification: Use Store#verify_callback instead of SSLContext#verify*?
619
+ ctx.cert_store = @cert_store
620
+ ctx.verify_mode = @verify_mode
621
+ ctx.verify_depth = @verify_depth if @verify_depth
622
+ ctx.verify_callback = @verify_callback || method(:default_verify_callback)
623
+ # SSL config
624
+ ctx.cert = @client_cert
625
+ ctx.key = @client_key
626
+ ctx.client_ca = @client_ca
627
+ ctx.timeout = @timeout
628
+ ctx.options = @options
629
+ ctx.ciphers = @ciphers
630
+ end
631
+
632
+ # this definition must match with the one in ext/openssl/lib/openssl/ssl.rb
633
+ def post_connection_check(peer_cert, hostname)
634
+ check_common_name = true
635
+ cert = peer_cert
636
+ cert.extensions.each{|ext|
637
+ next if ext.oid != "subjectAltName"
638
+ ext.value.split(/,\s+/).each{|general_name|
639
+ if /\ADNS:(.*)/ =~ general_name
640
+ check_common_name = false
641
+ reg = Regexp.escape($1).gsub(/\\\*/, "[^.]+")
642
+ return true if /\A#{reg}\z/i =~ hostname
643
+ elsif /\AIP Address:(.*)/ =~ general_name
644
+ check_common_name = false
645
+ return true if $1 == hostname
646
+ end
647
+ }
648
+ }
649
+ if check_common_name
650
+ cert.subject.to_a.each{|oid, value|
651
+ if oid == "CN" && value.casecmp(hostname) == 0
652
+ return true
653
+ end
654
+ }
655
+ end
656
+ raise OpenSSL::SSL::SSLError, "hostname not match"
657
+ end
658
+
659
+ # Default callback for verification: only dumps error.
660
+ def default_verify_callback(is_ok, ctx)
661
+ if $DEBUG
662
+ puts "#{ is_ok ? 'ok' : 'ng' }: #{ctx.current_cert.subject}"
663
+ end
664
+ if !is_ok
665
+ depth = ctx.error_depth
666
+ code = ctx.error
667
+ msg = ctx.error_string
668
+ STDERR.puts "at depth #{depth} - #{code}: #{msg}"
669
+ end
670
+ is_ok
671
+ end
672
+
673
+ # Sample callback method: CAUTION: does not check CRL/ARL.
674
+ def sample_verify_callback(is_ok, ctx)
675
+ unless is_ok
676
+ depth = ctx.error_depth
677
+ code = ctx.error
678
+ msg = ctx.error_string
679
+ STDERR.puts "at depth #{depth} - #{code}: #{msg}" if $DEBUG
680
+ return false
681
+ end
682
+
683
+ cert = ctx.current_cert
684
+ self_signed = false
685
+ ca = false
686
+ pathlen = nil
687
+ server_auth = true
688
+ self_signed = (cert.subject.cmp(cert.issuer) == 0)
689
+
690
+ # Check extensions whatever its criticality is. (sample)
691
+ cert.extensions.each do |ex|
692
+ case ex.oid
693
+ when 'basicConstraints'
694
+ /CA:(TRUE|FALSE), pathlen:(\d+)/ =~ ex.value
695
+ ca = ($1 == 'TRUE')
696
+ pathlen = $2.to_i
697
+ when 'keyUsage'
698
+ usage = ex.value.split(/\s*,\s*/)
699
+ ca = usage.include?('Certificate Sign')
700
+ server_auth = usage.include?('Key Encipherment')
701
+ when 'extendedKeyUsage'
702
+ usage = ex.value.split(/\s*,\s*/)
703
+ server_auth = usage.include?('Netscape Server Gated Crypto')
704
+ when 'nsCertType'
705
+ usage = ex.value.split(/\s*,\s*/)
706
+ ca = usage.include?('SSL CA')
707
+ server_auth = usage.include?('SSL Server')
708
+ end
709
+ end
710
+
711
+ if self_signed
712
+ STDERR.puts 'self signing CA' if $DEBUG
713
+ return true
714
+ elsif ca
715
+ STDERR.puts 'middle level CA' if $DEBUG
716
+ return true
717
+ elsif server_auth
718
+ STDERR.puts 'for server authentication' if $DEBUG
719
+ return true
720
+ end
721
+
722
+ return false
723
+ end
724
+
725
+ private
726
+
727
+ def change_notify
728
+ @client.reset_all
729
+ end
730
+ end
731
+
732
+
733
+ # HTTPAccess::BasicAuth -- BasicAuth repository.
734
+ #
735
+ class BasicAuth # :nodoc:
736
+ def initialize(client)
737
+ @client = client
738
+ @auth = {}
739
+ end
740
+
741
+ def set(uri, user_id, passwd)
742
+ uri = uri.clone
743
+ uri.path = uri.path.sub(/\/[^\/]*$/, '/')
744
+ @auth[uri] = ["#{user_id}:#{passwd}"].pack('m').strip
745
+ @client.reset_all
746
+ end
747
+
748
+ def get(uri)
749
+ @auth.each do |realm_uri, cred|
750
+ if ((realm_uri.host == uri.host) and
751
+ (realm_uri.scheme == uri.scheme) and
752
+ (realm_uri.port == uri.port) and
753
+ uri.path.upcase.index(realm_uri.path.upcase) == 0)
754
+ return cred
755
+ end
756
+ end
757
+ nil
758
+ end
759
+ end
760
+
761
+
762
+ # HTTPAccess::Site -- manage a site(host and port)
763
+ #
764
+ class Site # :nodoc:
765
+ attr_accessor :scheme
766
+ attr_accessor :host
767
+ attr_reader :port
768
+
769
+ def initialize(uri = nil)
770
+ if uri
771
+ @scheme = uri.scheme
772
+ @host = uri.host
773
+ @port = uri.port.to_i
774
+ else
775
+ @scheme = 'tcp'
776
+ @host = '0.0.0.0'
777
+ @port = 0
778
+ end
779
+ end
780
+
781
+ def addr
782
+ "#{@scheme}://#{@host}:#{@port.to_s}"
783
+ end
784
+
785
+ def port=(port)
786
+ @port = port.to_i
787
+ end
788
+
789
+ def ==(rhs)
790
+ if rhs.is_a?(Site)
791
+ ((@scheme == rhs.scheme) and (@host == rhs.host) and (@port == rhs.port))
792
+ else
793
+ false
794
+ end
795
+ end
796
+
797
+ def to_s
798
+ addr
799
+ end
800
+
801
+ def inspect
802
+ sprintf("#<%s:0x%x %s>", self.class.name, __id__, addr)
803
+ end
804
+ end
805
+
806
+
807
+ # HTTPAccess::Connection -- magage a connection(one request and response to it).
808
+ #
809
+ class Connection # :nodoc:
810
+ attr_accessor :async_thread
811
+
812
+ def initialize(header_queue = [], body_queue = [])
813
+ @headers = header_queue
814
+ @body = body_queue
815
+ @async_thread = nil
816
+ @queue = Queue.new
817
+ end
818
+
819
+ def finished?
820
+ if !@async_thread
821
+ # Not in async mode.
822
+ true
823
+ elsif @async_thread.alive?
824
+ # Working...
825
+ false
826
+ else
827
+ # Async thread have been finished.
828
+ @async_thread.join
829
+ true
830
+ end
831
+ end
832
+
833
+ def pop
834
+ @queue.pop
835
+ end
836
+
837
+ def push(result)
838
+ @queue.push(result)
839
+ end
840
+
841
+ def join
842
+ unless @async_thread
843
+ false
844
+ else
845
+ @async_thread.join
846
+ end
847
+ end
848
+ end
849
+
850
+
851
+ # HTTPAccess::SessionManager -- manage several sessions.
852
+ #
853
+ class SessionManager # :nodoc:
854
+ attr_accessor :agent_name # Name of this client.
855
+ attr_accessor :from # Owner of this client.
856
+
857
+ attr_accessor :protocol_version # Requested protocol version
858
+ attr_accessor :chunk_size # Chunk size for chunked request
859
+ attr_accessor :debug_dev # Device for dumping log for debugging
860
+ attr_accessor :socket_sync # Boolean value for Socket#sync
861
+
862
+ # These parameters are not used now...
863
+ attr_accessor :connect_timeout
864
+ attr_accessor :connect_retry # Maximum retry count. 0 for infinite.
865
+ attr_accessor :send_timeout
866
+ attr_accessor :receive_timeout
867
+ attr_accessor :read_block_size
868
+
869
+ attr_accessor :ssl_config
870
+
871
+ def initialize
872
+ @proxy = nil
873
+
874
+ @agent_name = nil
875
+ @from = nil
876
+
877
+ @protocol_version = nil
878
+ @debug_dev = nil
879
+ @socket_sync = true
880
+ @chunk_size = 4096
881
+
882
+ @connect_timeout = 60
883
+ @connect_retry = 1
884
+ @send_timeout = 120
885
+ @receive_timeout = 60 # For each read_block_size bytes
886
+ @read_block_size = 8192
887
+
888
+ @ssl_config = nil
889
+
890
+ @sess_pool = []
891
+ @sess_pool_mutex = Mutex.new
892
+ end
893
+
894
+ def proxy=(proxy)
895
+ if proxy.nil?
896
+ @proxy = nil
897
+ else
898
+ @proxy = Site.new(proxy)
899
+ end
900
+ end
901
+
902
+ def query(req, proxy)
903
+ req.body.chunk_size = @chunk_size
904
+ dest_site = Site.new(req.header.request_uri)
905
+ proxy_site = if proxy
906
+ Site.new(proxy)
907
+ else
908
+ @proxy
909
+ end
910
+ sess = open(dest_site, proxy_site)
911
+ begin
912
+ sess.query(req)
913
+ rescue
914
+ sess.close
915
+ raise
916
+ end
917
+ sess
918
+ end
919
+
920
+ def reset(uri)
921
+ unless uri.is_a?(URI)
922
+ uri = URI.parse(uri.to_s)
923
+ end
924
+ site = Site.new(uri)
925
+ close(site)
926
+ end
927
+
928
+ def reset_all
929
+ close_all
930
+ end
931
+
932
+ def keep(sess)
933
+ add_cached_session(sess)
934
+ end
935
+
936
+ private
937
+
938
+ def open(dest, proxy = nil)
939
+ sess = nil
940
+ if cached = get_cached_session(dest)
941
+ sess = cached
942
+ else
943
+ sess = Session.new(dest, @agent_name, @from)
944
+ sess.proxy = proxy
945
+ sess.socket_sync = @socket_sync
946
+ sess.requested_version = @protocol_version if @protocol_version
947
+ sess.connect_timeout = @connect_timeout
948
+ sess.connect_retry = @connect_retry
949
+ sess.send_timeout = @send_timeout
950
+ sess.receive_timeout = @receive_timeout
951
+ sess.read_block_size = @read_block_size
952
+ sess.ssl_config = @ssl_config
953
+ sess.debug_dev = @debug_dev
954
+ end
955
+ sess
956
+ end
957
+
958
+ def close_all
959
+ each_sess do |sess|
960
+ sess.close
961
+ end
962
+ @sess_pool.clear
963
+ end
964
+
965
+ def close(dest)
966
+ if cached = get_cached_session(dest)
967
+ cached.close
968
+ true
969
+ else
970
+ false
971
+ end
972
+ end
973
+
974
+ def get_cached_session(dest)
975
+ cached = nil
976
+ @sess_pool_mutex.synchronize do
977
+ new_pool = []
978
+ @sess_pool.each do |s|
979
+ if s.dest == dest
980
+ cached = s
981
+ else
982
+ new_pool << s
983
+ end
984
+ end
985
+ @sess_pool = new_pool
986
+ end
987
+ cached
988
+ end
989
+
990
+ def add_cached_session(sess)
991
+ @sess_pool_mutex.synchronize do
992
+ @sess_pool << sess
993
+ end
994
+ end
995
+
996
+ def each_sess
997
+ @sess_pool_mutex.synchronize do
998
+ @sess_pool.each do |sess|
999
+ yield(sess)
1000
+ end
1001
+ end
1002
+ end
1003
+ end
1004
+
1005
+
1006
+ # HTTPAccess::SSLSocketWrap
1007
+ #
1008
+ class SSLSocketWrap
1009
+ def initialize(socket, context, debug_dev = nil)
1010
+ unless SSLEnabled
1011
+ raise RuntimeError.new(
1012
+ "Ruby/OpenSSL module is required for https access.")
1013
+ end
1014
+ @context = context
1015
+ @socket = socket
1016
+ @ssl_socket = create_ssl_socket(@socket)
1017
+ @debug_dev = debug_dev
1018
+ end
1019
+
1020
+ def ssl_connect
1021
+ @ssl_socket.connect
1022
+ end
1023
+
1024
+ def post_connection_check(host)
1025
+ verify_mode = @context.verify_mode || OpenSSL::SSL::VERIFY_NONE
1026
+ if verify_mode == OpenSSL::SSL::VERIFY_NONE
1027
+ return
1028
+ elsif @ssl_socket.peer_cert.nil? and
1029
+ check_mask(verify_mode, OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT)
1030
+ raise OpenSSL::SSL::SSLError, "no peer cert"
1031
+ end
1032
+ hostname = host.host
1033
+ if @ssl_socket.respond_to?(:post_connection_check)
1034
+ @ssl_socket.post_connection_check(hostname)
1035
+ end
1036
+ @context.post_connection_check(@ssl_socket.peer_cert, hostname)
1037
+ end
1038
+
1039
+ def peer_cert
1040
+ @ssl_socket.peer_cert
1041
+ end
1042
+
1043
+ def addr
1044
+ @socket.addr
1045
+ end
1046
+
1047
+ def close
1048
+ @ssl_socket.close
1049
+ @socket.close
1050
+ end
1051
+
1052
+ def closed?
1053
+ @socket.closed?
1054
+ end
1055
+
1056
+ def eof?
1057
+ @ssl_socket.eof?
1058
+ end
1059
+
1060
+ def gets(*args)
1061
+ str = @ssl_socket.gets(*args)
1062
+ @debug_dev << str if @debug_dev
1063
+ str
1064
+ end
1065
+
1066
+ def read(*args)
1067
+ str = @ssl_socket.read(*args)
1068
+ @debug_dev << str if @debug_dev
1069
+ str
1070
+ end
1071
+
1072
+ def <<(str)
1073
+ rv = @ssl_socket.write(str)
1074
+ @debug_dev << str if @debug_dev
1075
+ rv
1076
+ end
1077
+
1078
+ def flush
1079
+ @ssl_socket.flush
1080
+ end
1081
+
1082
+ def sync
1083
+ @ssl_socket.sync
1084
+ end
1085
+
1086
+ def sync=(sync)
1087
+ @ssl_socket.sync = sync
1088
+ end
1089
+
1090
+ private
1091
+
1092
+ def check_mask(value, mask)
1093
+ value & mask == mask
1094
+ end
1095
+
1096
+ def create_ssl_socket(socket)
1097
+ ssl_socket = nil
1098
+ if OpenSSL::SSL.const_defined?("SSLContext")
1099
+ ctx = OpenSSL::SSL::SSLContext.new
1100
+ @context.set_context(ctx)
1101
+ ssl_socket = OpenSSL::SSL::SSLSocket.new(socket, ctx)
1102
+ else
1103
+ ssl_socket = OpenSSL::SSL::SSLSocket.new(socket)
1104
+ @context.set_context(ssl_socket)
1105
+ end
1106
+ ssl_socket
1107
+ end
1108
+ end
1109
+
1110
+
1111
+ # HTTPAccess::DebugSocket -- debugging support
1112
+ #
1113
+ class DebugSocket < TCPSocket
1114
+ attr_accessor :debug_dev # Device for logging.
1115
+
1116
+ class << self
1117
+ def create_socket(host, port, debug_dev)
1118
+ debug_dev << "! CONNECT TO #{host}:#{port}\n"
1119
+ socket = new(host, port)
1120
+ socket.debug_dev = debug_dev
1121
+ socket.log_connect
1122
+ socket
1123
+ end
1124
+
1125
+ private :new
1126
+ end
1127
+
1128
+ def initialize(*args)
1129
+ super
1130
+ @debug_dev = nil
1131
+ end
1132
+
1133
+ def log_connect
1134
+ @debug_dev << '! CONNECTION ESTABLISHED' << "\n"
1135
+ end
1136
+
1137
+ def close
1138
+ super
1139
+ @debug_dev << '! CONNECTION CLOSED' << "\n"
1140
+ end
1141
+
1142
+ def gets(*args)
1143
+ str = super
1144
+ @debug_dev << str if str
1145
+ str
1146
+ end
1147
+
1148
+ def read(*args)
1149
+ str = super
1150
+ @debug_dev << str if str
1151
+ str
1152
+ end
1153
+
1154
+ def <<(str)
1155
+ super
1156
+ @debug_dev << str
1157
+ end
1158
+ end
1159
+
1160
+
1161
+ # HTTPAccess::Session -- manage http session with one site.
1162
+ # One or more TCP sessions with the site may be created.
1163
+ # Only 1 TCP session is live at the same time.
1164
+ #
1165
+ class Session # :nodoc:
1166
+
1167
+ class Error < StandardError # :nodoc:
1168
+ end
1169
+
1170
+ class InvalidState < Error # :nodoc:
1171
+ end
1172
+
1173
+ class BadResponse < Error # :nodoc:
1174
+ end
1175
+
1176
+ class KeepAliveDisconnected < Error # :nodoc:
1177
+ end
1178
+
1179
+ attr_reader :dest # Destination site
1180
+ attr_reader :src # Source site
1181
+ attr_accessor :proxy # Proxy site
1182
+ attr_accessor :socket_sync # Boolean value for Socket#sync
1183
+
1184
+ attr_accessor :requested_version # Requested protocol version
1185
+
1186
+ attr_accessor :debug_dev # Device for dumping log for debugging
1187
+
1188
+ # These session parameters are not used now...
1189
+ attr_accessor :connect_timeout
1190
+ attr_accessor :connect_retry
1191
+ attr_accessor :send_timeout
1192
+ attr_accessor :receive_timeout
1193
+ attr_accessor :read_block_size
1194
+
1195
+ attr_accessor :ssl_config
1196
+
1197
+ def initialize(dest, user_agent, from)
1198
+ @dest = dest
1199
+ @src = Site.new
1200
+ @proxy = nil
1201
+ @socket_sync = true
1202
+ @requested_version = nil
1203
+
1204
+ @debug_dev = nil
1205
+
1206
+ @connect_timeout = nil
1207
+ @connect_retry = 1
1208
+ @send_timeout = nil
1209
+ @receive_timeout = nil
1210
+ @read_block_size = nil
1211
+
1212
+ @ssl_config = nil
1213
+
1214
+ @user_agent = user_agent
1215
+ @from = from
1216
+ @state = :INIT
1217
+
1218
+ @requests = []
1219
+
1220
+ @status = nil
1221
+ @reason = nil
1222
+ @headers = []
1223
+
1224
+ @socket = nil
1225
+ end
1226
+
1227
+ # Send a request to the server
1228
+ def query(req)
1229
+ connect() if @state == :INIT
1230
+ begin
1231
+ timeout(@send_timeout) do
1232
+ set_header(req)
1233
+ req.dump(@socket)
1234
+ # flush the IO stream as IO::sync mode is false
1235
+ @socket.flush unless @socket_sync
1236
+ end
1237
+ rescue Errno::ECONNABORTED
1238
+ close
1239
+ raise KeepAliveDisconnected.new
1240
+ rescue
1241
+ if SSLEnabled and $!.is_a?(OpenSSL::SSL::SSLError)
1242
+ raise KeepAliveDisconnected.new
1243
+ elsif $!.is_a?(TimeoutError)
1244
+ close
1245
+ raise
1246
+ else
1247
+ raise
1248
+ end
1249
+ end
1250
+
1251
+ @state = :META if @state == :WAIT
1252
+ @next_connection = nil
1253
+ @requests.push(req)
1254
+ end
1255
+
1256
+ def close
1257
+ unless @socket.nil?
1258
+ @socket.flush
1259
+ @socket.close unless @socket.closed?
1260
+ end
1261
+ @state = :INIT
1262
+ end
1263
+
1264
+ def closed?
1265
+ @state == :INIT
1266
+ end
1267
+
1268
+ def get_status
1269
+ version = status = reason = nil
1270
+ begin
1271
+ if @state != :META
1272
+ raise RuntimeError.new("get_status must be called at the beginning of a session.")
1273
+ end
1274
+ version, status, reason = read_header()
1275
+ rescue
1276
+ close
1277
+ raise
1278
+ end
1279
+ return version, status, reason
1280
+ end
1281
+
1282
+ def get_header(&block)
1283
+ begin
1284
+ read_header() if @state == :META
1285
+ rescue
1286
+ close
1287
+ raise
1288
+ end
1289
+ if block
1290
+ @headers.each do |line|
1291
+ block.call(line)
1292
+ end
1293
+ else
1294
+ @headers
1295
+ end
1296
+ end
1297
+
1298
+ def eof?
1299
+ if @content_length == 0
1300
+ true
1301
+ elsif @readbuf.length > 0
1302
+ false
1303
+ else
1304
+ @socket.closed? or @socket.eof?
1305
+ end
1306
+ end
1307
+
1308
+ def get_data(&block)
1309
+ begin
1310
+ read_header() if @state == :META
1311
+ return nil if @state != :DATA
1312
+ unless @state == :DATA
1313
+ raise InvalidState.new('state != DATA')
1314
+ end
1315
+ data = nil
1316
+ if block
1317
+ until eof?
1318
+ begin
1319
+ timeout(@receive_timeout) do
1320
+ data = read_body()
1321
+ end
1322
+ rescue TimeoutError
1323
+ raise
1324
+ end
1325
+ block.call(data) if data
1326
+ end
1327
+ data = nil # Calling with block returns nil.
1328
+ else
1329
+ begin
1330
+ timeout(@receive_timeout) do
1331
+ data = read_body()
1332
+ end
1333
+ rescue TimeoutError
1334
+ raise
1335
+ end
1336
+ end
1337
+ rescue
1338
+ close
1339
+ raise
1340
+ end
1341
+ if eof?
1342
+ if @next_connection
1343
+ @state = :WAIT
1344
+ else
1345
+ close
1346
+ end
1347
+ end
1348
+ data
1349
+ end
1350
+
1351
+ private
1352
+
1353
+ LibNames = "(#{RCS_FILE}/#{RCS_REVISION}, #{RUBY_VERSION_STRING})"
1354
+
1355
+ def set_header(req)
1356
+ req.version = @requested_version if @requested_version
1357
+ if @user_agent
1358
+ req.header.set('User-Agent', "#{@user_agent} #{LibNames}")
1359
+ end
1360
+ if @from
1361
+ req.header.set('From', @from)
1362
+ end
1363
+ req.header.set('Date', Time.now)
1364
+ end
1365
+
1366
+ # Connect to the server
1367
+ def connect
1368
+ site = @proxy || @dest
1369
+ begin
1370
+ retry_number = 0
1371
+ timeout(@connect_timeout) do
1372
+ @socket = create_socket(site)
1373
+ begin
1374
+ @src.host = @socket.addr[3]
1375
+ @src.port = @socket.addr[1]
1376
+ rescue SocketError
1377
+ # to avoid IPSocket#addr problem on Mac OS X 10.3 + ruby-1.8.1.
1378
+ # cf. [ruby-talk:84909], [ruby-talk:95827]
1379
+ end
1380
+ if @dest.scheme == 'https'
1381
+ @socket = create_ssl_socket(@socket)
1382
+ connect_ssl_proxy(@socket) if @proxy
1383
+ @socket.ssl_connect
1384
+ @socket.post_connection_check(@dest)
1385
+ end
1386
+ # Use Ruby internal buffering instead of passing data immediatly
1387
+ # to the underlying layer
1388
+ # => we need to to call explicitely flush on the socket
1389
+ @socket.sync = @socket_sync
1390
+ end
1391
+ rescue TimeoutError
1392
+ if @connect_retry == 0
1393
+ retry
1394
+ else
1395
+ retry_number += 1
1396
+ retry if retry_number < @connect_retry
1397
+ end
1398
+ close
1399
+ raise
1400
+ end
1401
+
1402
+ @state = :WAIT
1403
+ @readbuf = ''
1404
+ end
1405
+
1406
+ def create_socket(site)
1407
+ begin
1408
+ if @debug_dev
1409
+ DebugSocket.create_socket(site.host, site.port, @debug_dev)
1410
+ else
1411
+ TCPSocket.new(site.host, site.port)
1412
+ end
1413
+ rescue SystemCallError => e
1414
+ e.message << " (#{site.host}, ##{site.port})"
1415
+ raise
1416
+ end
1417
+ end
1418
+
1419
+ # wrap socket with OpenSSL.
1420
+ def create_ssl_socket(raw_socket)
1421
+ SSLSocketWrap.new(raw_socket, @ssl_config, (DEBUG_SSL ? @debug_dev : nil))
1422
+ end
1423
+
1424
+ def connect_ssl_proxy(socket)
1425
+ socket << sprintf("CONNECT %s:%s HTTP/1.1\r\n\r\n", @dest.host, @dest.port)
1426
+ parse_header(socket)
1427
+ unless @status == 200
1428
+ raise BadResponse.new(
1429
+ "connect to ssl proxy failed with status #{@status} #{@reason}")
1430
+ end
1431
+ end
1432
+
1433
+ # Read status block.
1434
+ def read_header
1435
+ if @state == :DATA
1436
+ get_data {}
1437
+ check_state()
1438
+ end
1439
+ unless @state == :META
1440
+ raise InvalidState, 'state != :META'
1441
+ end
1442
+ parse_header(@socket)
1443
+ @content_length = nil
1444
+ @chunked = false
1445
+ @headers.each do |line|
1446
+ case line
1447
+ when /^Content-Length:\s+(\d+)/i
1448
+ @content_length = $1.to_i
1449
+ when /^Transfer-Encoding:\s+chunked/i
1450
+ @chunked = true
1451
+ @content_length = true # how?
1452
+ @chunk_length = 0
1453
+ when /^Connection:\s+([\-\w]+)/i, /^Proxy-Connection:\s+([\-\w]+)/i
1454
+ case $1
1455
+ when /^Keep-Alive$/i
1456
+ @next_connection = true
1457
+ when /^close$/i
1458
+ @next_connection = false
1459
+ end
1460
+ else
1461
+ # Nothing to parse.
1462
+ end
1463
+ end
1464
+
1465
+ # Head of the request has been parsed.
1466
+ @state = :DATA
1467
+ req = @requests.shift
1468
+
1469
+ if req.header.request_method == 'HEAD'
1470
+ @content_length = 0
1471
+ if @next_connection
1472
+ @state = :WAIT
1473
+ else
1474
+ close
1475
+ end
1476
+ end
1477
+ @next_connection = false unless @content_length
1478
+ return [@version, @status, @reason]
1479
+ end
1480
+
1481
+ StatusParseRegexp = %r(\AHTTP/(\d+\.\d+)\s+(\d+)(?:\s+(.*))?\r?\n\z)
1482
+ def parse_header(socket)
1483
+ begin
1484
+ timeout(@receive_timeout) do
1485
+ begin
1486
+ initial_line = socket.gets("\n")
1487
+ if initial_line.nil?
1488
+ raise KeepAliveDisconnected.new
1489
+ end
1490
+ if StatusParseRegexp =~ initial_line
1491
+ @version, @status, @reason = $1, $2.to_i, $3
1492
+ @next_connection = HTTP.keep_alive_enabled?(@version)
1493
+ else
1494
+ @version = '0.9'
1495
+ @status = nil
1496
+ @reason = nil
1497
+ @next_connection = false
1498
+ @readbuf = initial_line
1499
+ break
1500
+ end
1501
+ @headers = []
1502
+ while true
1503
+ line = socket.gets("\n")
1504
+ unless line
1505
+ raise BadResponse.new('Unexpected EOF.')
1506
+ end
1507
+ line.sub!(/\r?\n\z/, '')
1508
+ break if line.empty?
1509
+ if line.sub!(/^\t/, '')
1510
+ @headers[-1] << line
1511
+ else
1512
+ @headers.push(line)
1513
+ end
1514
+ end
1515
+ end while (@version == '1.1' && @status == 100)
1516
+ end
1517
+ rescue TimeoutError
1518
+ raise
1519
+ end
1520
+ end
1521
+
1522
+ def read_body
1523
+ if @chunked
1524
+ return read_body_chunked()
1525
+ elsif @content_length == 0
1526
+ return nil
1527
+ elsif @content_length
1528
+ return read_body_length()
1529
+ else
1530
+ if @readbuf.length > 0
1531
+ data = @readbuf
1532
+ @readbuf = ''
1533
+ return data
1534
+ else
1535
+ data = @socket.read(@read_block_size)
1536
+ data = nil if data.empty? # Absorbing interface mismatch.
1537
+ return data
1538
+ end
1539
+ end
1540
+ end
1541
+
1542
+ def read_body_length
1543
+ maxbytes = @read_block_size
1544
+ if @readbuf.length > 0
1545
+ data = @readbuf[0, @content_length]
1546
+ @readbuf[0, @content_length] = ''
1547
+ @content_length -= data.length
1548
+ return data
1549
+ end
1550
+ maxbytes = @content_length if maxbytes > @content_length
1551
+ data = @socket.read(maxbytes)
1552
+ if data
1553
+ @content_length -= data.length
1554
+ else
1555
+ @content_length = 0
1556
+ end
1557
+ return data
1558
+ end
1559
+
1560
+ RS = "\r\n"
1561
+ ChunkDelimiter = "0#{RS}"
1562
+ ChunkTrailer = "0#{RS}#{RS}"
1563
+ def read_body_chunked
1564
+ if @chunk_length == 0
1565
+ until (i = @readbuf.index(RS))
1566
+ @readbuf << @socket.gets(RS)
1567
+ end
1568
+ i += 2
1569
+ if @readbuf[0, i] == ChunkDelimiter
1570
+ @content_length = 0
1571
+ unless @readbuf[0, 5] == ChunkTrailer
1572
+ @readbuf << @socket.gets(RS)
1573
+ end
1574
+ @readbuf[0, 5] = ''
1575
+ return nil
1576
+ end
1577
+ @chunk_length = @readbuf[0, i].hex
1578
+ @readbuf[0, i] = ''
1579
+ end
1580
+ while @readbuf.length < @chunk_length + 2
1581
+ @readbuf << @socket.read(@chunk_length + 2 - @readbuf.length)
1582
+ end
1583
+ data = @readbuf[0, @chunk_length]
1584
+ @readbuf[0, @chunk_length + 2] = ''
1585
+ @chunk_length = 0
1586
+ return data
1587
+ end
1588
+
1589
+ def check_state
1590
+ if @state == :DATA
1591
+ if eof?
1592
+ if @next_connection
1593
+ if @requests.empty?
1594
+ @state = :WAIT
1595
+ else
1596
+ @state = :META
1597
+ end
1598
+ end
1599
+ end
1600
+ end
1601
+ end
1602
+ end
1603
+
1604
+
1605
+ end
1606
+
1607
+
1608
+ HTTPClient = HTTPAccess::Client