facets 1.3.3 → 1.4.0

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