reap 5.0.0 → 5.10.10

Sign up to get free protection for your applications and to get access to all the features.
Files changed (236) hide show
  1. data/ANN +3 -0
  2. data/COPYING +11 -0
  3. data/ChangeLog +25 -0
  4. data/ProjectInfo +41 -66
  5. data/README +125 -0
  6. data/Rakefile +0 -10
  7. data/bin/reap +3 -4
  8. data/data/reap/scaffold/COPYING +11 -0
  9. data/data/reap/scaffold/{standard/ChangeLog → ChangeLog} +0 -0
  10. data/data/reap/scaffold/{standard/TODO → INSTALL} +0 -0
  11. data/data/reap/scaffold/{standard/ProjectInfo → ProjectInfo} +20 -20
  12. data/data/reap/scaffold/{subversion/trunk/ChangeLog → README} +0 -0
  13. data/data/reap/scaffold/Rakefile +146 -0
  14. data/data/reap/scaffold/{subversion/trunk/TODO → Todo} +0 -0
  15. data/{doc/note → data/reap/scaffold}/setup.rb +11 -18
  16. data/{doc/note/aRakefile → dev/Rakefile} +0 -0
  17. data/{doc/note → dev}/composite_task.rb +0 -0
  18. data/{doc/note → dev}/compositepublisher.rb +0 -0
  19. data/{doc/note → dev}/ftptools.rb +0 -0
  20. data/{doc/note → dev}/license-each.rb +0 -0
  21. data/{doc/note → dev}/publisher.rb +0 -0
  22. data/{doc/note → dev}/rubyforgepublisher.rb +0 -0
  23. data/{doc/note → dev}/sshpublisher.rb +0 -0
  24. data/{doc/note → dev}/suby-cvs.rb +0 -0
  25. data/{doc/note → dev}/template.rb +0 -0
  26. data/lib/reap/bin/reap.rb +67 -84
  27. data/{doc/note/interface/interface.rb → lib/reap/lint.rb} +0 -0
  28. data/lib/reap/projectinfo.rb +28 -206
  29. data/lib/reap/readymade.rb +21 -0
  30. data/lib/reap/task.rb +118 -184
  31. data/lib/reap/task/announce.rb +93 -181
  32. data/lib/reap/task/fileperm.rb +16 -46
  33. data/lib/reap/task/info.rb +7 -33
  34. data/lib/reap/task/install.rb +17 -52
  35. data/{task → lib/reap/task}/noop.rb +9 -4
  36. data/lib/reap/task/package.rb +102 -348
  37. data/lib/reap/task/publish.rb +29 -155
  38. data/lib/reap/task/rdoc.rb +40 -92
  39. data/lib/reap/task/scaffold.rb +98 -41
  40. data/lib/reap/task/test.rb +52 -147
  41. data/lib/reap/task/testext.rb +110 -0
  42. data/lib/reap/task/webpublish.rb +43 -0
  43. data/lib/reap/tasks.rb +13 -0
  44. data/lib/reap/test.rb +138 -0
  45. data/setup.rb +272 -287
  46. data/test/tc_reap.rb +1 -1
  47. data/web/ProjectInfo +57 -0
  48. data/web/images/appleboy.jpg +0 -0
  49. data/web/images/grape.jpg +0 -0
  50. data/web/index.html +124 -0
  51. data/web/rdoc/classes/Object.html +121 -0
  52. data/web/rdoc/classes/ProjectInfo.html +207 -0
  53. data/web/rdoc/classes/ProjectInfo.src/M000094.html +18 -0
  54. data/web/rdoc/classes/ProjectInfo.src/M000095.html +24 -0
  55. data/web/rdoc/classes/ProjectInfo.src/M000096.html +22 -0
  56. data/web/rdoc/classes/ProjectInfo.src/M000097.html +21 -0
  57. data/web/rdoc/classes/ProjectInfo.src/M000098.html +18 -0
  58. data/web/rdoc/classes/Reap.html +248 -0
  59. data/web/rdoc/classes/Reap.src/M000023.html +16 -0
  60. data/web/rdoc/classes/Reap.src/M000024.html +21 -0
  61. data/web/rdoc/classes/Reap.src/M000025.html +16 -0
  62. data/web/rdoc/classes/Reap.src/M000026.html +21 -0
  63. data/web/rdoc/classes/Reap/Announce.html +262 -0
  64. data/web/rdoc/classes/Reap/Announce.src/M000030.html +18 -0
  65. data/web/rdoc/classes/Reap/Announce.src/M000031.html +114 -0
  66. data/web/rdoc/classes/Reap/Announce.src/M000032.html +46 -0
  67. data/web/rdoc/classes/Reap/Info.html +176 -0
  68. data/web/rdoc/classes/Reap/Info.src/M000033.html +18 -0
  69. data/web/rdoc/classes/Reap/Info.src/M000034.html +17 -0
  70. data/web/rdoc/classes/Reap/Info.src/M000035.html +18 -0
  71. data/web/rdoc/classes/Reap/Install.html +193 -0
  72. data/web/rdoc/classes/Reap/Install.src/M000036.html +18 -0
  73. data/web/rdoc/classes/Reap/Install.src/M000037.html +20 -0
  74. data/web/rdoc/classes/Reap/Install.src/M000038.html +26 -0
  75. data/web/rdoc/classes/Reap/Noop.html +192 -0
  76. data/web/rdoc/classes/Reap/Noop.src/M000027.html +18 -0
  77. data/web/rdoc/classes/Reap/Noop.src/M000028.html +17 -0
  78. data/web/rdoc/classes/Reap/Noop.src/M000029.html +18 -0
  79. data/web/rdoc/classes/Reap/Package.html +310 -0
  80. data/web/rdoc/classes/Reap/Package.src/M000055.html +18 -0
  81. data/web/rdoc/classes/Reap/Package.src/M000056.html +68 -0
  82. data/web/rdoc/classes/Reap/Package.src/M000057.html +84 -0
  83. data/web/rdoc/classes/Reap/Package.src/M000058.html +61 -0
  84. data/web/rdoc/classes/Reap/Perm.html +236 -0
  85. data/web/rdoc/classes/Reap/Perm.src/M000078.html +18 -0
  86. data/web/rdoc/classes/Reap/Perm.src/M000079.html +21 -0
  87. data/web/rdoc/classes/Reap/Perm.src/M000080.html +42 -0
  88. data/web/rdoc/classes/Reap/Perm.src/M000081.html +26 -0
  89. data/web/rdoc/classes/Reap/Perm.src/M000082.html +18 -0
  90. data/web/rdoc/classes/Reap/Publish.html +213 -0
  91. data/web/rdoc/classes/Reap/Publish.src/M000070.html +18 -0
  92. data/web/rdoc/classes/Reap/Publish.src/M000071.html +22 -0
  93. data/web/rdoc/classes/Reap/Publish.src/M000072.html +37 -0
  94. data/web/rdoc/classes/Reap/RDoc.html +218 -0
  95. data/web/rdoc/classes/Reap/RDoc.src/M000059.html +18 -0
  96. data/web/rdoc/classes/Reap/RDoc.src/M000060.html +24 -0
  97. data/web/rdoc/classes/Reap/RDoc.src/M000061.html +70 -0
  98. data/web/rdoc/classes/Reap/Task.html +396 -0
  99. data/web/rdoc/classes/Reap/Task.src/M000039.html +18 -0
  100. data/web/rdoc/classes/Reap/Task.src/M000040.html +16 -0
  101. data/web/rdoc/classes/Reap/Task.src/M000041.html +16 -0
  102. data/web/rdoc/classes/Reap/Task.src/M000042.html +16 -0
  103. data/web/rdoc/classes/Reap/Task.src/M000043.html +16 -0
  104. data/web/rdoc/classes/Reap/Task.src/M000044.html +22 -0
  105. data/web/rdoc/classes/Reap/Task.src/M000045.html +16 -0
  106. data/web/rdoc/classes/Reap/Task.src/M000046.html +16 -0
  107. data/web/rdoc/classes/Reap/Task.src/M000047.html +16 -0
  108. data/web/rdoc/classes/Reap/Task.src/M000048.html +16 -0
  109. data/web/rdoc/classes/Reap/Task.src/M000049.html +16 -0
  110. data/web/rdoc/classes/Reap/Task.src/M000050.html +27 -0
  111. data/web/rdoc/classes/Reap/Task.src/M000051.html +19 -0
  112. data/web/rdoc/classes/Reap/Task.src/M000052.html +18 -0
  113. data/web/rdoc/classes/Reap/Task.src/M000053.html +18 -0
  114. data/web/rdoc/classes/Reap/Task.src/M000054.html +19 -0
  115. data/web/rdoc/classes/Reap/Test.html +253 -0
  116. data/web/rdoc/classes/Reap/Test.src/M000062.html +18 -0
  117. data/web/rdoc/classes/Reap/Test.src/M000063.html +26 -0
  118. data/web/rdoc/classes/Reap/Test.src/M000064.html +77 -0
  119. data/web/rdoc/classes/Reap/Test.src/M000065.html +27 -0
  120. data/web/rdoc/classes/Reap/Test.src/M000066.html +50 -0
  121. data/web/rdoc/classes/Reap/Test/TestResults.html +205 -0
  122. data/web/rdoc/classes/Reap/Test/TestResults.src/M000067.html +21 -0
  123. data/web/rdoc/classes/Reap/Test/TestResults.src/M000068.html +21 -0
  124. data/web/rdoc/classes/Reap/Test/TestResults.src/M000069.html +23 -0
  125. data/web/rdoc/classes/Reap/TestExt.html +234 -0
  126. data/web/rdoc/classes/Reap/TestExt.src/M000073.html +18 -0
  127. data/web/rdoc/classes/Reap/TestExt.src/M000074.html +20 -0
  128. data/web/rdoc/classes/Reap/TestExt.src/M000075.html +49 -0
  129. data/web/rdoc/classes/Reap/TestExt.src/M000076.html +34 -0
  130. data/web/rdoc/classes/Reap/TestExt.src/M000077.html +27 -0
  131. data/web/rdoc/classes/Reap/WebPublish.html +213 -0
  132. data/web/rdoc/classes/Reap/WebPublish.src/M000083.html +18 -0
  133. data/web/rdoc/classes/Reap/WebPublish.src/M000084.html +21 -0
  134. data/web/rdoc/classes/Reap/WebPublish.src/M000085.html +32 -0
  135. data/web/rdoc/classes/ReapCommand.html +425 -0
  136. data/web/rdoc/classes/ReapCommand.src/M000001.html +16 -0
  137. data/web/rdoc/classes/ReapCommand.src/M000003.html +16 -0
  138. data/web/rdoc/classes/ReapCommand.src/M000005.html +16 -0
  139. data/web/rdoc/classes/ReapCommand.src/M000007.html +16 -0
  140. data/web/rdoc/classes/ReapCommand.src/M000009.html +16 -0
  141. data/web/rdoc/classes/ReapCommand.src/M000011.html +16 -0
  142. data/web/rdoc/classes/ReapCommand.src/M000013.html +18 -0
  143. data/web/rdoc/classes/ReapCommand.src/M000014.html +19 -0
  144. data/web/rdoc/classes/ReapCommand.src/M000015.html +19 -0
  145. data/web/rdoc/classes/ReapCommand.src/M000016.html +24 -0
  146. data/web/rdoc/classes/ReapCommand.src/M000018.html +29 -0
  147. data/web/rdoc/classes/Scaffold.html +211 -0
  148. data/web/rdoc/classes/Scaffold.src/M000086.html +16 -0
  149. data/web/rdoc/classes/Scaffold.src/M000087.html +28 -0
  150. data/web/rdoc/classes/Scaffold.src/M000088.html +32 -0
  151. data/web/rdoc/classes/Scaffold.src/M000089.html +18 -0
  152. data/web/rdoc/classes/UnitTestKernel.html +176 -0
  153. data/web/rdoc/classes/UnitTestKernel.src/M000019.html +18 -0
  154. data/web/rdoc/classes/UnitTestKernel.src/M000020.html +18 -0
  155. data/web/rdoc/classes/UnitTestKernel.src/M000021.html +22 -0
  156. data/web/rdoc/classes/UnitTestKernel.src/M000022.html +22 -0
  157. data/web/rdoc/classes/UnitTesting.html +165 -0
  158. data/web/rdoc/classes/UnitTesting.src/M000090.html +34 -0
  159. data/web/rdoc/classes/UnitTesting.src/M000091.html +18 -0
  160. data/web/rdoc/classes/UnitTesting/Failure.html +156 -0
  161. data/web/rdoc/classes/UnitTesting/Failure.src/M000092.html +18 -0
  162. data/web/rdoc/classes/UnitTesting/Failure.src/M000093.html +21 -0
  163. data/web/rdoc/created.rid +1 -0
  164. data/web/rdoc/files/ANN.html +107 -0
  165. data/web/rdoc/files/COPYING.html +119 -0
  166. data/web/rdoc/files/ChangeLog.html +144 -0
  167. data/web/rdoc/files/ProjectInfo.html +190 -0
  168. data/web/rdoc/files/README.html +274 -0
  169. data/web/rdoc/files/Rakefile.html +101 -0
  170. data/web/rdoc/files/lib/reap/bin/reap_rb.html +129 -0
  171. data/web/rdoc/files/lib/reap/lint_rb.html +101 -0
  172. data/web/rdoc/files/lib/reap/projectinfo_rb.html +110 -0
  173. data/web/rdoc/files/lib/reap/readymade_rb.html +123 -0
  174. data/web/rdoc/files/lib/reap/task/announce_rb.html +114 -0
  175. data/web/rdoc/files/lib/reap/task/fileperm_rb.html +108 -0
  176. data/web/rdoc/files/lib/reap/task/info_rb.html +108 -0
  177. data/web/rdoc/files/lib/reap/task/install_rb.html +108 -0
  178. data/web/rdoc/files/lib/reap/task/noop_rb.html +108 -0
  179. data/web/rdoc/files/lib/reap/task/package_rb.html +109 -0
  180. data/web/rdoc/files/lib/reap/task/publish_rb.html +108 -0
  181. data/web/rdoc/files/lib/reap/task/rdoc_rb.html +108 -0
  182. data/web/rdoc/files/lib/reap/task/scaffold_rb.html +107 -0
  183. data/web/rdoc/files/lib/reap/task/test_rb.html +110 -0
  184. data/web/rdoc/files/lib/reap/task/testext_rb.html +109 -0
  185. data/web/rdoc/files/lib/reap/task/webpublish_rb.html +108 -0
  186. data/web/rdoc/files/lib/reap/task_rb.html +120 -0
  187. data/web/rdoc/files/lib/reap/tasks_rb.html +116 -0
  188. data/web/rdoc/files/lib/reap/test_rb.html +109 -0
  189. data/web/rdoc/fr_class_index.html +47 -0
  190. data/web/rdoc/fr_file_index.html +51 -0
  191. data/web/rdoc/fr_method_index.html +124 -0
  192. data/web/rdoc/index.html +24 -0
  193. data/web/rdoc/rdoc-style.css +208 -0
  194. metadata +257 -138
  195. data/bin/rubytest +0 -5
  196. data/data/reap/scaffold/standard/COPYING +0 -403
  197. data/data/reap/scaffold/standard/INSTALL +0 -14
  198. data/data/reap/scaffold/standard/README +0 -3
  199. data/data/reap/scaffold/standard/Rakefile +0 -10
  200. data/data/reap/scaffold/standard/setup.rb +0 -1568
  201. data/data/reap/scaffold/subversion/trunk/COPYING +0 -403
  202. data/data/reap/scaffold/subversion/trunk/INSTALL +0 -14
  203. data/data/reap/scaffold/subversion/trunk/ProjectInfo +0 -78
  204. data/data/reap/scaffold/subversion/trunk/README +0 -3
  205. data/data/reap/scaffold/subversion/trunk/Rakefile +0 -10
  206. data/data/reap/scaffold/subversion/trunk/setup.rb +0 -1568
  207. data/data/reap/setup.rb +0 -1568
  208. data/doc/COPYING +0 -403
  209. data/doc/ChangeLog +0 -18
  210. data/doc/LATEST +0 -29
  211. data/doc/README +0 -182
  212. data/doc/doap.xml +0 -27
  213. data/doc/note/ProjectInfo.rb +0 -88
  214. data/doc/note/Rakefile.0 +0 -118
  215. data/doc/note/Rakefile.htm +0 -69
  216. data/doc/note/application.rb +0 -124
  217. data/doc/note/interface/rubyforge.rb +0 -247
  218. data/doc/note/intro.txt +0 -42
  219. data/doc/note/package.rb +0 -629
  220. data/doc/note/package.rb.0 +0 -394
  221. data/doc/note/scaffold.rb +0 -123
  222. data/lib/reap/app.rb +0 -74
  223. data/lib/reap/bin/rubylint.rb +0 -1
  224. data/lib/reap/bin/rubytest.rb +0 -45
  225. data/lib/reap/rake.rb +0 -12
  226. data/lib/reap/rakeadapter.rb +0 -50
  227. data/lib/reap/reap.rb +0 -32
  228. data/lib/reap/task/custom.rb +0 -12
  229. data/lib/reap/task/doap.rb +0 -85
  230. data/lib/reap/task/extest.rb +0 -161
  231. data/lib/reap/task/manifest.rb +0 -70
  232. data/lib/reap/task/release.rb +0 -512
  233. data/lib/reap/task/template.rb +0 -46
  234. data/lib/reap/vendor/http-access2.rb +0 -1590
  235. data/lib/reap/vendor/http-access2/cookie.rb +0 -538
  236. data/lib/reap/vendor/http-access2/http.rb +0 -542
@@ -1,46 +0,0 @@
1
- require 'reap/task'
2
- require 'facet/gem/self/gempath'
3
-
4
- class Reap::Template < Reap::Task
5
-
6
- #task_name 'template'
7
-
8
- task_desc "Create a ProjectInfo template."
9
-
10
- task_help %{
11
-
12
- reap template
13
-
14
- Creates an empty PrjectInfo file in the current directory.
15
- It will not overwrite a PrjectInfo file if one is already
16
- present.
17
-
18
- }
19
-
20
- task_available { |app| ! app.projectfile? }
21
-
22
- # Copies the file from lib/data to the current dir.
23
-
24
- def run
25
- f = nil
26
- if ::ProjectInfo::INFO_FILES.any?{ |f| File.exists?(f) }
27
- puts "Project file '#{f}' already exists."
28
- return
29
- end
30
- filename = 'ProjectInfo'
31
- # if using gems
32
- if dir = Gem.gempath('reap')
33
- dir = File.join( dir, 'data', 'reap', 'scaffold', 'standard' )
34
- else
35
- dir = File.join( ::Config::CONFIG['datadir'], 'reap', 'scaffold', 'standard' )
36
- end
37
- f = File.join( dir, filename )
38
- raise "ProjectInfo template file #{f} is missing." unless File.file?( f )
39
- # copy
40
- FileUtils.install( f, '.' )
41
- tell "#{filename} created. You'll need to fill it out."
42
- return nil
43
- end
44
-
45
- end
46
-
@@ -1,1590 +0,0 @@
1
- # HTTPAccess2 - HTTP accessing library.
2
- # Copyright (C) 2000-2005 NAKAMURA, Hiroshi <nakahiro@sarion.co.jp>.
3
-
4
- # This program is copyrighted free software by NAKAMURA, Hiroshi. You can
5
- # redistribute it and/or modify it under the same terms of Ruby's license;
6
- # either the dual license version in 2003, or any later version.
7
-
8
- # http-access2.rb is based on http-access.rb in http-access/0.0.4. Some part
9
- # of code in http-access.rb was recycled in http-access2.rb. Those part is
10
- # copyrighted by Maehashi-san.
11
-
12
-
13
- # Ruby standard library
14
- require 'timeout'
15
- require 'uri'
16
- require 'socket'
17
- require 'thread'
18
-
19
- # Extra library
20
- #require 'http-access2/http'
21
- #require 'http-access2/cookie'
22
- require 'reap/vendor/http-access2/http'
23
- require 'reap/vendor/http-access2/cookie'
24
-
25
-
26
- module HTTPAccess2
27
- VERSION = '2.0.6'
28
- RUBY_VERSION_STRING = "ruby #{RUBY_VERSION} (#{RUBY_RELEASE_DATE}) [#{RUBY_PLATFORM}]"
29
- s = %w$Id: http-access2.rb 114 2005-09-13 03:20:38Z nahi $
30
- RCS_FILE, RCS_REVISION = s[1][/.*(?=,v$)/], s[2]
31
-
32
- SSLEnabled = begin
33
- require 'openssl'
34
- true
35
- rescue LoadError
36
- false
37
- end
38
-
39
- DEBUG_SSL = true
40
-
41
-
42
- # DESCRIPTION
43
- # HTTPAccess2::Client -- Client to retrieve web resources via HTTP.
44
- #
45
- # How to create your client.
46
- # 1. Create simple client.
47
- # clnt = HTTPAccess2::Client.new
48
- #
49
- # 2. Accessing resources through HTTP proxy.
50
- # clnt = HTTPAccess2::Client.new("http://myproxy:8080")
51
- #
52
- # 3. Set User-Agent and From in HTTP request header.(nil means "No proxy")
53
- # clnt = HTTPAccess2::Client.new(nil, "MyAgent", "nahi@keynauts.com")
54
- #
55
- # How to retrieve web resources.
56
- # 1. Get content of specified URL.
57
- # puts clnt.get_content("http://www.ruby-lang.org/en/")
58
- #
59
- # 2. Do HEAD request.
60
- # res = clnt.head(uri)
61
- #
62
- # 3. Do GET request with query.
63
- # res = clnt.get(uri)
64
- #
65
- # 4. Do POST request.
66
- # res = clnt.post(uri)
67
- # res = clnt.get|post|head(uri, proxy)
68
- #
69
- class Client
70
- attr_reader :agent_name
71
- attr_reader :from
72
- attr_reader :ssl_config
73
- attr_accessor :cookie_manager
74
- attr_reader :test_loopback_response
75
-
76
- class << self
77
- %w(get_content head get post put delete options trace).each do |name|
78
- eval <<-EOD
79
- def #{name}(*arg)
80
- new.#{name}(*arg)
81
- end
82
- EOD
83
- end
84
- end
85
-
86
- # SYNOPSIS
87
- # Client.new(proxy = nil, agent_name = nil, from = nil)
88
- #
89
- # ARGS
90
- # proxy A String of HTTP proxy URL. ex. "http://proxy:8080".
91
- # agent_name A String for "User-Agent" HTTP request header.
92
- # from A String for "From" HTTP request header.
93
- #
94
- # DESCRIPTION
95
- # Create an instance.
96
- # SSLConfig cannot be re-initialized. Create new client.
97
- #
98
- def initialize(proxy = nil, agent_name = nil, from = nil)
99
- @proxy = nil # assigned later.
100
- @no_proxy = nil
101
- @agent_name = agent_name
102
- @from = from
103
- @basic_auth = BasicAuth.new(self)
104
- @debug_dev = nil
105
- @ssl_config = SSLConfig.new(self)
106
- @redirect_uri_callback = method(:default_redirect_uri_callback)
107
- @test_loopback_response = []
108
- @session_manager = SessionManager.new
109
- @session_manager.agent_name = @agent_name
110
- @session_manager.from = @from
111
- @session_manager.ssl_config = @ssl_config
112
- @cookie_manager = WebAgent::CookieManager.new
113
- self.proxy = proxy
114
- end
115
-
116
- def debug_dev
117
- @debug_dev
118
- end
119
-
120
- def debug_dev=(dev)
121
- @debug_dev = dev
122
- reset_all
123
- @session_manager.debug_dev = dev
124
- end
125
-
126
- def protocol_version
127
- @session_manager.protocol_version
128
- end
129
-
130
- def protocol_version=(protocol_version)
131
- reset_all
132
- @session_manager.protocol_version = protocol_version
133
- end
134
-
135
- def connect_timeout
136
- @session_manager.connect_timeout
137
- end
138
-
139
- def connect_timeout=(connect_timeout)
140
- reset_all
141
- @session_manager.connect_timeout = connect_timeout
142
- end
143
-
144
- def send_timeout
145
- @session_manager.send_timeout
146
- end
147
-
148
- def send_timeout=(send_timeout)
149
- reset_all
150
- @session_manager.send_timeout = send_timeout
151
- end
152
-
153
- def receive_timeout
154
- @session_manager.receive_timeout
155
- end
156
-
157
- def receive_timeout=(receive_timeout)
158
- reset_all
159
- @session_manager.receive_timeout = receive_timeout
160
- end
161
-
162
- def proxy
163
- @proxy
164
- end
165
-
166
- def proxy=(proxy)
167
- if proxy.nil?
168
- @proxy = nil
169
- else
170
- if proxy.is_a?(URI)
171
- @proxy = proxy
172
- else
173
- @proxy = URI.parse(proxy)
174
- end
175
- if @proxy.scheme == nil or @proxy.scheme.downcase != 'http' or
176
- @proxy.host == nil or @proxy.port == nil
177
- raise ArgumentError.new("unsupported proxy `#{proxy}'")
178
- end
179
- end
180
- reset_all
181
- @proxy
182
- end
183
-
184
- def no_proxy
185
- @no_proxy
186
- end
187
-
188
- def no_proxy=(no_proxy)
189
- @no_proxy = no_proxy
190
- reset_all
191
- end
192
-
193
- # if your ruby is older than 2005-09-06, do not set socket_sync = false to
194
- # avoid an SSL socket blocking bug in openssl/buffering.rb.
195
- def socket_sync=(socket_sync)
196
- @session_manager.socket_sync = socket_sync
197
- end
198
-
199
- def set_basic_auth(uri, user_id, passwd)
200
- unless uri.is_a?(URI)
201
- uri = URI.parse(uri)
202
- end
203
- @basic_auth.set(uri, user_id, passwd)
204
- end
205
-
206
- def set_cookie_store(filename)
207
- if @cookie_manager.cookies_file
208
- raise RuntimeError.new("overriding cookie file location")
209
- end
210
- @cookie_manager.cookies_file = filename
211
- @cookie_manager.load_cookies if filename
212
- end
213
-
214
- def save_cookie_store
215
- @cookie_manager.save_cookies
216
- end
217
-
218
- def redirect_uri_callback=(redirect_uri_callback)
219
- @redirect_uri_callback = redirect_uri_callback
220
- end
221
-
222
- # SYNOPSIS
223
- # Client#get_content(uri, query = nil, extheader = {}, &block = nil)
224
- #
225
- # ARGS
226
- # uri an_URI or a_string of uri to connect.
227
- # query a_hash or an_array of query part. e.g. { "a" => "b" }.
228
- # Give an array to pass multiple value like
229
- # [["a" => "b"], ["a" => "c"]].
230
- # extheader
231
- # a_hash of extra headers like { "SOAPAction" => "urn:foo" }.
232
- # &block Give a block to get chunked message-body of response like
233
- # get_content(uri) { |chunked_body| ... }
234
- # Size of each chunk may not be the same.
235
- #
236
- # DESCRIPTION
237
- # Get a_sring of message-body of response.
238
- #
239
- def get_content(uri, query = nil, extheader = {}, &block)
240
- retry_connect(uri, query) do |uri, query|
241
- get(uri, query, extheader, &block)
242
- end
243
- end
244
-
245
- def post_content(uri, body = nil, extheader = {}, &block)
246
- retry_connect(uri, nil) do |uri, query|
247
- post(uri, body, extheader, &block)
248
- end
249
- end
250
-
251
- def default_redirect_uri_callback(res)
252
- uri = res.header['location'][0]
253
- puts "Redirect to: #{uri}" if $DEBUG
254
- uri
255
- end
256
-
257
- def head(uri, query = nil, extheader = {})
258
- request('HEAD', uri, query, nil, extheader)
259
- end
260
-
261
- def get(uri, query = nil, extheader = {}, &block)
262
- request('GET', uri, query, nil, extheader, &block)
263
- end
264
-
265
- def post(uri, body = nil, extheader = {}, &block)
266
- request('POST', uri, nil, body, extheader, &block)
267
- end
268
-
269
- def put(uri, body = nil, extheader = {}, &block)
270
- request('PUT', uri, nil, body, extheader, &block)
271
- end
272
-
273
- def delete(uri, extheader = {}, &block)
274
- request('DELETE', uri, nil, nil, extheader, &block)
275
- end
276
-
277
- def options(uri, extheader = {}, &block)
278
- request('OPTIONS', uri, nil, nil, extheader, &block)
279
- end
280
-
281
- def trace(uri, query = nil, body = nil, extheader = {}, &block)
282
- request('TRACE', uri, query, body, extheader, &block)
283
- end
284
-
285
- def request(method, uri, query = nil, body = nil, extheader = {}, &block)
286
- conn = Connection.new
287
- conn_request(conn, method, uri, query, body, extheader, &block)
288
- conn.pop
289
- end
290
-
291
- # Async interface.
292
-
293
- def head_async(uri, query = nil, extheader = {})
294
- request_async('HEAD', uri, query, nil, extheader)
295
- end
296
-
297
- def get_async(uri, query = nil, extheader = {})
298
- request_async('GET', uri, query, nil, extheader)
299
- end
300
-
301
- def post_async(uri, body = nil, extheader = {})
302
- request_async('POST', uri, nil, body, extheader)
303
- end
304
-
305
- def put_async(uri, body = nil, extheader = {})
306
- request_async('PUT', uri, nil, body, extheader)
307
- end
308
-
309
- def delete_async(uri, extheader = {})
310
- request_async('DELETE', uri, nil, nil, extheader)
311
- end
312
-
313
- def options_async(uri, extheader = {})
314
- request_async('OPTIONS', uri, nil, nil, extheader)
315
- end
316
-
317
- def trace_async(uri, query = nil, body = nil, extheader = {})
318
- request_async('TRACE', uri, query, body, extheader)
319
- end
320
-
321
- def request_async(method, uri, query = nil, body = nil, extheader = {})
322
- conn = Connection.new
323
- t = Thread.new(conn) { |tconn|
324
- conn_request(tconn, method, uri, query, body, extheader)
325
- }
326
- conn.async_thread = t
327
- conn
328
- end
329
-
330
- ##
331
- # Multiple call interface.
332
-
333
- # ???
334
-
335
- ##
336
- # Management interface.
337
-
338
- def reset(uri)
339
- @session_manager.reset(uri)
340
- end
341
-
342
- def reset_all
343
- @session_manager.reset_all
344
- end
345
-
346
- private
347
-
348
- def retry_connect(uri, query = nil)
349
- retry_number = 0
350
- while retry_number < 10
351
- res = yield(uri, query)
352
- if res.status == HTTP::Status::OK
353
- return res.content
354
- elsif HTTP::Status.redirect?(res.status)
355
- uri = @redirect_uri_callback.call(res)
356
- query = nil
357
- retry_number += 1
358
- else
359
- raise RuntimeError.new("Unexpected response: #{res.header.inspect}")
360
- end
361
- end
362
- raise RuntimeError.new("Retry count exceeded.")
363
- end
364
-
365
- def conn_request(conn, method, uri, query, body, extheader, &block)
366
- unless uri.is_a?(URI)
367
- uri = URI.parse(uri)
368
- end
369
- proxy = no_proxy?(uri) ? nil : @proxy
370
- begin
371
- req = create_request(method, uri, query, body, extheader, !proxy.nil?)
372
- do_get_block(req, proxy, conn, &block)
373
- rescue Session::KeepAliveDisconnected
374
- req = create_request(method, uri, query, body, extheader, !proxy.nil?)
375
- do_get_block(req, proxy, conn, &block)
376
- end
377
- end
378
-
379
- def create_request(method, uri, query, body, extheader, proxy)
380
- if extheader.is_a?(Hash)
381
- extheader = extheader.to_a
382
- end
383
- cred = @basic_auth.get(uri)
384
- if cred
385
- extheader << ['Authorization', "Basic " << cred]
386
- end
387
- if cookies = @cookie_manager.find(uri)
388
- extheader << ['Cookie', cookies]
389
- end
390
- boundary = nil
391
- content_type = extheader.find { |key, value|
392
- key.downcase == 'content-type'
393
- }
394
- if content_type && content_type[1] =~ /boundary=(.+)\z/
395
- boundary = $1
396
- end
397
- req = HTTP::Message.new_request(method, uri, query, body, proxy, boundary)
398
- extheader.each do |key, value|
399
- req.header.set(key, value)
400
- end
401
- if content_type.nil? and !body.nil?
402
- req.header.set('content-type', 'application/x-www-form-urlencoded')
403
- end
404
- req
405
- end
406
-
407
- NO_PROXY_HOSTS = ['localhost']
408
-
409
- def no_proxy?(uri)
410
- if !@proxy or NO_PROXY_HOSTS.include?(uri.host)
411
- return true
412
- end
413
- unless @no_proxy
414
- return false
415
- end
416
- @no_proxy.scan(/([^:,]+)(?::(\d+))?/) do |host, port|
417
- if /(\A|\.)#{Regexp.quote(host)}\z/i =~ uri.host &&
418
- (!port || uri.port == port.to_i)
419
- return true
420
- end
421
- end
422
- false
423
- end
424
-
425
- # !! CAUTION !!
426
- # Method 'do_get*' runs under MT conditon. Be careful to change.
427
- def do_get_block(req, proxy, conn, &block)
428
- if str = @test_loopback_response.shift
429
- dump_dummy_request_response(req.body.dump, str) if @debug_dev
430
- conn.push(HTTP::Message.new_response(str))
431
- return
432
- end
433
- content = ''
434
- res = HTTP::Message.new_response(content)
435
- @debug_dev << "= Request\n\n" if @debug_dev
436
- sess = @session_manager.query(req, proxy)
437
- @debug_dev << "\n\n= Response\n\n" if @debug_dev
438
- do_get_header(req, res, sess)
439
- conn.push(res)
440
- sess.get_data() do |str|
441
- block.call(str) if block
442
- content << str
443
- end
444
- @session_manager.keep(sess) unless sess.closed?
445
- end
446
-
447
- def do_get_stream(req, proxy, conn)
448
- if str = @test_loopback_response.shift
449
- dump_dummy_request_response(req.body.dump, str) if @debug_dev
450
- conn.push(HTTP::Message.new_response(str))
451
- return
452
- end
453
- piper, pipew = IO.pipe
454
- res = HTTP::Message.new_response(piper)
455
- @debug_dev << "= Request\n\n" if @debug_dev
456
- sess = @session_manager.query(req, proxy)
457
- @debug_dev << "\n\n= Response\n\n" if @debug_dev
458
- do_get_header(req, res, sess)
459
- conn.push(res)
460
- sess.get_data() do |str|
461
- pipew.syswrite(str)
462
- end
463
- pipew.close
464
- @session_manager.keep(sess) unless sess.closed?
465
- end
466
-
467
- def do_get_header(req, res, sess)
468
- res.version, res.status, res.reason = sess.get_status
469
- sess.get_header().each do |line|
470
- unless /^([^:]+)\s*:\s*(.*)$/ =~ line
471
- raise RuntimeError.new("Unparsable header: '#{line}'.") if $DEBUG
472
- end
473
- res.header.set($1, $2)
474
- end
475
- if res.header['set-cookie']
476
- res.header['set-cookie'].each do |cookie|
477
- @cookie_manager.parse(cookie, req.header.request_uri)
478
- end
479
- end
480
- end
481
-
482
- def dump_dummy_request_response(req, res)
483
- @debug_dev << "= Dummy Request\n\n"
484
- @debug_dev << req
485
- @debug_dev << "\n\n= Dummy Response\n\n"
486
- @debug_dev << res
487
- end
488
- end
489
-
490
-
491
- # HTTPAccess2::SSLConfig -- SSL configuration of a client.
492
- #
493
- class SSLConfig # :nodoc:
494
- attr_reader :client_cert
495
- attr_reader :client_key
496
- attr_reader :client_ca
497
-
498
- attr_reader :verify_mode
499
- attr_reader :verify_depth
500
- attr_reader :verify_callback
501
-
502
- attr_reader :timeout
503
- attr_reader :options
504
- attr_reader :ciphers
505
-
506
- attr_reader :cert_store # don't use if you don't know what it is.
507
-
508
- def initialize(client)
509
- return unless SSLEnabled
510
- @client = client
511
- @cert_store = OpenSSL::X509::Store.new
512
- @client_cert = @client_key = @client_ca = nil
513
- @verify_mode = OpenSSL::SSL::VERIFY_PEER |
514
- OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT
515
- @verify_depth = nil
516
- @verify_callback = nil
517
- @dest = nil
518
- @timeout = nil
519
- @options = defined?(OpenSSL::SSL::OP_ALL) ?
520
- OpenSSL::SSL::OP_ALL | OpenSSL::SSL::OP_NO_SSLv2 : nil
521
- @ciphers = "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH"
522
- end
523
-
524
- def set_client_cert_file(cert_file, key_file)
525
- @client_cert = OpenSSL::X509::Certificate.new(File.open(cert_file).read)
526
- @client_key = OpenSSL::PKey::RSA.new(File.open(key_file).read)
527
- change_notify
528
- end
529
-
530
- def set_trust_ca(trust_ca_file_or_hashed_dir)
531
- if FileTest.directory?(trust_ca_file_or_hashed_dir)
532
- @cert_store.add_path(trust_ca_file_or_hashed_dir)
533
- else
534
- @cert_store.add_file(trust_ca_file_or_hashed_dir)
535
- end
536
- change_notify
537
- end
538
-
539
- def set_crl(crl_file)
540
- crl = OpenSSL::X509::CRL.new(File.open(crl_file).read)
541
- @cert_store.add_crl(crl)
542
- @cert_store.flags = OpenSSL::X509::V_FLAG_CRL_CHECK | OpenSSL::X509::V_FLAG_CRL_CHECK_ALL
543
- change_notify
544
- end
545
-
546
- def client_cert=(client_cert)
547
- @client_cert = client_cert
548
- change_notify
549
- end
550
-
551
- def client_key=(client_key)
552
- @client_key = client_key
553
- change_notify
554
- end
555
-
556
- def client_ca=(client_ca)
557
- @client_ca = client_ca
558
- change_notify
559
- end
560
-
561
- def verify_mode=(verify_mode)
562
- @verify_mode = verify_mode
563
- change_notify
564
- end
565
-
566
- def verify_depth=(verify_depth)
567
- @verify_depth = verify_depth
568
- change_notify
569
- end
570
-
571
- def verify_callback=(verify_callback)
572
- @verify_callback = verify_callback
573
- change_notify
574
- end
575
-
576
- def timeout=(timeout)
577
- @timeout = timeout
578
- change_notify
579
- end
580
-
581
- def options=(options)
582
- @options = options
583
- change_notify
584
- end
585
-
586
- def ciphers=(ciphers)
587
- @ciphers = ciphers
588
- change_notify
589
- end
590
-
591
- # don't use if you don't know what it is.
592
- def cert_store=(cert_store)
593
- @cert_store = cert_store
594
- change_notify
595
- end
596
-
597
- # interfaces for SSLSocketWrap.
598
-
599
- def set_context(ctx)
600
- # Verification: Use Store#verify_callback instead of SSLContext#verify*?
601
- ctx.cert_store = @cert_store
602
- ctx.verify_mode = @verify_mode
603
- ctx.verify_depth = @verify_depth if @verify_depth
604
- ctx.verify_callback = @verify_callback || method(:default_verify_callback)
605
- # SSL config
606
- ctx.cert = @client_cert
607
- ctx.key = @client_key
608
- ctx.client_ca = @client_ca
609
- ctx.timeout = @timeout
610
- ctx.options = @options
611
- ctx.ciphers = @ciphers
612
- end
613
-
614
- # this definition must match with the one in ext/openssl/lib/openssl/ssl.rb
615
- def post_connection_check(peer_cert, hostname)
616
- check_common_name = true
617
- cert = peer_cert
618
- cert.extensions.each{|ext|
619
- next if ext.oid != "subjectAltName"
620
- ext.value.split(/,\s+/).each{|general_name|
621
- if /\ADNS:(.*)/ =~ general_name
622
- check_common_name = false
623
- reg = Regexp.escape($1).gsub(/\\\*/, "[^.]+")
624
- return true if /\A#{reg}\z/i =~ hostname
625
- elsif /\AIP Address:(.*)/ =~ general_name
626
- check_common_name = false
627
- return true if $1 == hostname
628
- end
629
- }
630
- }
631
- if check_common_name
632
- cert.subject.to_a.each{|oid, value|
633
- if oid == "CN" && value.casecmp(hostname) == 0
634
- return true
635
- end
636
- }
637
- end
638
- raise OpenSSL::SSL::SSLError, "hostname not match"
639
- end
640
-
641
- # Default callback for verification: only dumps error.
642
- def default_verify_callback(is_ok, ctx)
643
- if $DEBUG
644
- puts "#{ is_ok ? 'ok' : 'ng' }: #{ctx.current_cert.subject}"
645
- end
646
- if !is_ok
647
- depth = ctx.error_depth
648
- code = ctx.error
649
- msg = ctx.error_string
650
- STDERR.puts "at depth #{depth} - #{code}: #{msg}"
651
- end
652
- is_ok
653
- end
654
-
655
- # Sample callback method: CAUTION: does not check CRL/ARL.
656
- def sample_verify_callback(is_ok, ctx)
657
- unless is_ok
658
- depth = ctx.error_depth
659
- code = ctx.error
660
- msg = ctx.error_string
661
- STDERR.puts "at depth #{depth} - #{code}: #{msg}" if $DEBUG
662
- return false
663
- end
664
-
665
- cert = ctx.current_cert
666
- self_signed = false
667
- ca = false
668
- pathlen = nil
669
- server_auth = true
670
- self_signed = (cert.subject.cmp(cert.issuer) == 0)
671
-
672
- # Check extensions whatever its criticality is. (sample)
673
- cert.extensions.each do |ex|
674
- case ex.oid
675
- when 'basicConstraints'
676
- /CA:(TRUE|FALSE), pathlen:(\d+)/ =~ ex.value
677
- ca = ($1 == 'TRUE')
678
- pathlen = $2.to_i
679
- when 'keyUsage'
680
- usage = ex.value.split(/\s*,\s*/)
681
- ca = usage.include?('Certificate Sign')
682
- server_auth = usage.include?('Key Encipherment')
683
- when 'extendedKeyUsage'
684
- usage = ex.value.split(/\s*,\s*/)
685
- server_auth = usage.include?('Netscape Server Gated Crypto')
686
- when 'nsCertType'
687
- usage = ex.value.split(/\s*,\s*/)
688
- ca = usage.include?('SSL CA')
689
- server_auth = usage.include?('SSL Server')
690
- end
691
- end
692
-
693
- if self_signed
694
- STDERR.puts 'self signing CA' if $DEBUG
695
- return true
696
- elsif ca
697
- STDERR.puts 'middle level CA' if $DEBUG
698
- return true
699
- elsif server_auth
700
- STDERR.puts 'for server authentication' if $DEBUG
701
- return true
702
- end
703
-
704
- return false
705
- end
706
-
707
- private
708
-
709
- def change_notify
710
- @client.reset_all
711
- end
712
- end
713
-
714
-
715
- # HTTPAccess2::BasicAuth -- BasicAuth repository.
716
- #
717
- class BasicAuth # :nodoc:
718
- def initialize(client)
719
- @client = client
720
- @auth = {}
721
- end
722
-
723
- def set(uri, user_id, passwd)
724
- uri = uri.clone
725
- uri.path = uri.path.sub(/\/[^\/]*$/, '/')
726
- @auth[uri] = ["#{user_id}:#{passwd}"].pack('m').strip
727
- @client.reset_all
728
- end
729
-
730
- def get(uri)
731
- @auth.each do |realm_uri, cred|
732
- if ((realm_uri.host == uri.host) and
733
- (realm_uri.scheme == uri.scheme) and
734
- (realm_uri.port == uri.port) and
735
- uri.path.upcase.index(realm_uri.path.upcase) == 0)
736
- return cred
737
- end
738
- end
739
- nil
740
- end
741
- end
742
-
743
-
744
- # HTTPAccess2::Site -- manage a site(host and port)
745
- #
746
- class Site # :nodoc:
747
- attr_accessor :scheme
748
- attr_accessor :host
749
- attr_reader :port
750
-
751
- def initialize(uri = nil)
752
- if uri
753
- @scheme = uri.scheme
754
- @host = uri.host
755
- @port = uri.port.to_i
756
- else
757
- @scheme = 'tcp'
758
- @host = '0.0.0.0'
759
- @port = 0
760
- end
761
- end
762
-
763
- def addr
764
- "#{@scheme}://#{@host}:#{@port.to_s}"
765
- end
766
-
767
- def port=(port)
768
- @port = port.to_i
769
- end
770
-
771
- def ==(rhs)
772
- if rhs.is_a?(Site)
773
- ((@scheme == rhs.scheme) and (@host == rhs.host) and (@port == rhs.port))
774
- else
775
- false
776
- end
777
- end
778
-
779
- def to_s
780
- addr
781
- end
782
-
783
- def inspect
784
- sprintf("#<%s:0x%x %s>", self.class.name, __id__, addr)
785
- end
786
- end
787
-
788
-
789
- # HTTPAccess2::Connection -- magage a connection(one request and response to it).
790
- #
791
- class Connection # :nodoc:
792
- attr_accessor :async_thread
793
-
794
- def initialize(header_queue = [], body_queue = [])
795
- @headers = header_queue
796
- @body = body_queue
797
- @async_thread = nil
798
- @queue = Queue.new
799
- end
800
-
801
- def finished?
802
- if !@async_thread
803
- # Not in async mode.
804
- true
805
- elsif @async_thread.alive?
806
- # Working...
807
- false
808
- else
809
- # Async thread have been finished.
810
- @async_thread.join
811
- true
812
- end
813
- end
814
-
815
- def pop
816
- @queue.pop
817
- end
818
-
819
- def push(result)
820
- @queue.push(result)
821
- end
822
-
823
- def join
824
- unless @async_thread
825
- false
826
- else
827
- @async_thread.join
828
- end
829
- end
830
- end
831
-
832
-
833
- # HTTPAccess2::SessionManager -- manage several sessions.
834
- #
835
- class SessionManager # :nodoc:
836
- attr_accessor :agent_name # Name of this client.
837
- attr_accessor :from # Owner of this client.
838
-
839
- attr_accessor :protocol_version # Requested protocol version
840
- attr_accessor :chunk_size # Chunk size for chunked request
841
- attr_accessor :debug_dev # Device for dumping log for debugging
842
- attr_accessor :socket_sync # Boolean value for Socket#sync
843
-
844
- # These parameters are not used now...
845
- attr_accessor :connect_timeout
846
- attr_accessor :connect_retry # Maximum retry count. 0 for infinite.
847
- attr_accessor :send_timeout
848
- attr_accessor :receive_timeout
849
- attr_accessor :read_block_size
850
-
851
- attr_accessor :ssl_config
852
-
853
- def initialize
854
- @proxy = nil
855
-
856
- @agent_name = nil
857
- @from = nil
858
-
859
- @protocol_version = nil
860
- @debug_dev = nil
861
- @socket_sync = true
862
- @chunk_size = 4096
863
-
864
- @connect_timeout = 60
865
- @connect_retry = 1
866
- @send_timeout = 120
867
- @receive_timeout = 60 # For each read_block_size bytes
868
- @read_block_size = 8192
869
-
870
- @ssl_config = nil
871
-
872
- @sess_pool = []
873
- @sess_pool_mutex = Mutex.new
874
- end
875
-
876
- def proxy=(proxy)
877
- if proxy.nil?
878
- @proxy = nil
879
- else
880
- @proxy = Site.new(proxy)
881
- end
882
- end
883
-
884
- def query(req, proxy)
885
- req.body.chunk_size = @chunk_size
886
- dest_site = Site.new(req.header.request_uri)
887
- proxy_site = if proxy
888
- Site.new(proxy)
889
- else
890
- @proxy
891
- end
892
- sess = open(dest_site, proxy_site)
893
- begin
894
- sess.query(req)
895
- rescue
896
- sess.close
897
- raise
898
- end
899
- sess
900
- end
901
-
902
- def reset(uri)
903
- unless uri.is_a?(URI)
904
- uri = URI.parse(uri.to_s)
905
- end
906
- site = Site.new(uri)
907
- close(site)
908
- end
909
-
910
- def reset_all
911
- close_all
912
- end
913
-
914
- def keep(sess)
915
- add_cached_session(sess)
916
- end
917
-
918
- private
919
-
920
- def open(dest, proxy = nil)
921
- sess = nil
922
- if cached = get_cached_session(dest)
923
- sess = cached
924
- else
925
- sess = Session.new(dest, @agent_name, @from)
926
- sess.proxy = proxy
927
- sess.socket_sync = @socket_sync
928
- sess.requested_version = @protocol_version if @protocol_version
929
- sess.connect_timeout = @connect_timeout
930
- sess.connect_retry = @connect_retry
931
- sess.send_timeout = @send_timeout
932
- sess.receive_timeout = @receive_timeout
933
- sess.read_block_size = @read_block_size
934
- sess.ssl_config = @ssl_config
935
- sess.debug_dev = @debug_dev
936
- end
937
- sess
938
- end
939
-
940
- def close_all
941
- each_sess do |sess|
942
- sess.close
943
- end
944
- @sess_pool.clear
945
- end
946
-
947
- def close(dest)
948
- if cached = get_cached_session(dest)
949
- cached.close
950
- true
951
- else
952
- false
953
- end
954
- end
955
-
956
- def get_cached_session(dest)
957
- cached = nil
958
- @sess_pool_mutex.synchronize do
959
- new_pool = []
960
- @sess_pool.each do |s|
961
- if s.dest == dest
962
- cached = s
963
- else
964
- new_pool << s
965
- end
966
- end
967
- @sess_pool = new_pool
968
- end
969
- cached
970
- end
971
-
972
- def add_cached_session(sess)
973
- @sess_pool_mutex.synchronize do
974
- @sess_pool << sess
975
- end
976
- end
977
-
978
- def each_sess
979
- @sess_pool_mutex.synchronize do
980
- @sess_pool.each do |sess|
981
- yield(sess)
982
- end
983
- end
984
- end
985
- end
986
-
987
-
988
- # HTTPAccess2::SSLSocketWrap
989
- #
990
- class SSLSocketWrap
991
- def initialize(socket, context, debug_dev = nil)
992
- unless SSLEnabled
993
- raise RuntimeError.new(
994
- "Ruby/OpenSSL module is required for https access.")
995
- end
996
- @context = context
997
- @socket = socket
998
- @ssl_socket = create_ssl_socket(@socket)
999
- @debug_dev = debug_dev
1000
- end
1001
-
1002
- def ssl_connect
1003
- @ssl_socket.connect
1004
- end
1005
-
1006
- def post_connection_check(host)
1007
- verify_mode = @context.verify_mode || OpenSSL::SSL::VERIFY_NONE
1008
- if verify_mode == OpenSSL::SSL::VERIFY_NONE
1009
- return
1010
- elsif @ssl_socket.peer_cert.nil? and
1011
- check_mask(verify_mode, OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT)
1012
- raise OpenSSL::SSL::SSLError, "no peer cert"
1013
- end
1014
- hostname = host.host
1015
- if @ssl_socket.respond_to?(:post_connection_check)
1016
- @ssl_socket.post_connection_check(hostname)
1017
- end
1018
- @context.post_connection_check(@ssl_socket.peer_cert, hostname)
1019
- end
1020
-
1021
- def peer_cert
1022
- @ssl_socket.peer_cert
1023
- end
1024
-
1025
- def addr
1026
- @socket.addr
1027
- end
1028
-
1029
- def close
1030
- @ssl_socket.close
1031
- @socket.close
1032
- end
1033
-
1034
- def closed?
1035
- @socket.closed?
1036
- end
1037
-
1038
- def eof?
1039
- @ssl_socket.eof?
1040
- end
1041
-
1042
- def gets(*args)
1043
- str = @ssl_socket.gets(*args)
1044
- @debug_dev << str if @debug_dev
1045
- str
1046
- end
1047
-
1048
- def read(*args)
1049
- str = @ssl_socket.read(*args)
1050
- @debug_dev << str if @debug_dev
1051
- str
1052
- end
1053
-
1054
- def <<(str)
1055
- rv = @ssl_socket.write(str)
1056
- @debug_dev << str if @debug_dev
1057
- rv
1058
- end
1059
-
1060
- def flush
1061
- @ssl_socket.flush
1062
- end
1063
-
1064
- def sync
1065
- @ssl_socket.sync
1066
- end
1067
-
1068
- def sync=(sync)
1069
- @ssl_socket.sync = sync
1070
- end
1071
-
1072
- private
1073
-
1074
- def check_mask(value, mask)
1075
- value & mask == mask
1076
- end
1077
-
1078
- def create_ssl_socket(socket)
1079
- ssl_socket = nil
1080
- if OpenSSL::SSL.const_defined?("SSLContext")
1081
- ctx = OpenSSL::SSL::SSLContext.new
1082
- @context.set_context(ctx)
1083
- ssl_socket = OpenSSL::SSL::SSLSocket.new(socket, ctx)
1084
- else
1085
- ssl_socket = OpenSSL::SSL::SSLSocket.new(socket)
1086
- @context.set_context(ssl_socket)
1087
- end
1088
- ssl_socket
1089
- end
1090
- end
1091
-
1092
-
1093
- # HTTPAccess2::DebugSocket -- debugging support
1094
- #
1095
- class DebugSocket < TCPSocket
1096
- attr_accessor :debug_dev # Device for logging.
1097
-
1098
- class << self
1099
- def create_socket(host, port, debug_dev)
1100
- debug_dev << "! CONNECT TO #{host}:#{port}\n"
1101
- socket = new(host, port)
1102
- socket.debug_dev = debug_dev
1103
- socket.log_connect
1104
- socket
1105
- end
1106
-
1107
- private :new
1108
- end
1109
-
1110
- def initialize(*args)
1111
- super
1112
- @debug_dev = nil
1113
- end
1114
-
1115
- def log_connect
1116
- @debug_dev << '! CONNECTION ESTABLISHED' << "\n"
1117
- end
1118
-
1119
- def close
1120
- super
1121
- @debug_dev << '! CONNECTION CLOSED' << "\n"
1122
- end
1123
-
1124
- def gets(*args)
1125
- str = super
1126
- @debug_dev << str if str
1127
- str
1128
- end
1129
-
1130
- def read(*args)
1131
- str = super
1132
- @debug_dev << str if str
1133
- str
1134
- end
1135
-
1136
- def <<(str)
1137
- super
1138
- @debug_dev << str
1139
- end
1140
- end
1141
-
1142
-
1143
- # HTTPAccess2::Session -- manage http session with one site.
1144
- # One or more TCP sessions with the site may be created.
1145
- # Only 1 TCP session is live at the same time.
1146
- #
1147
- class Session # :nodoc:
1148
-
1149
- class Error < StandardError # :nodoc:
1150
- end
1151
-
1152
- class InvalidState < Error # :nodoc:
1153
- end
1154
-
1155
- class BadResponse < Error # :nodoc:
1156
- end
1157
-
1158
- class KeepAliveDisconnected < Error # :nodoc:
1159
- end
1160
-
1161
- attr_reader :dest # Destination site
1162
- attr_reader :src # Source site
1163
- attr_accessor :proxy # Proxy site
1164
- attr_accessor :socket_sync # Boolean value for Socket#sync
1165
-
1166
- attr_accessor :requested_version # Requested protocol version
1167
-
1168
- attr_accessor :debug_dev # Device for dumping log for debugging
1169
-
1170
- # These session parameters are not used now...
1171
- attr_accessor :connect_timeout
1172
- attr_accessor :connect_retry
1173
- attr_accessor :send_timeout
1174
- attr_accessor :receive_timeout
1175
- attr_accessor :read_block_size
1176
-
1177
- attr_accessor :ssl_config
1178
-
1179
- def initialize(dest, user_agent, from)
1180
- @dest = dest
1181
- @src = Site.new
1182
- @proxy = nil
1183
- @socket_sync = true
1184
- @requested_version = nil
1185
-
1186
- @debug_dev = nil
1187
-
1188
- @connect_timeout = nil
1189
- @connect_retry = 1
1190
- @send_timeout = nil
1191
- @receive_timeout = nil
1192
- @read_block_size = nil
1193
-
1194
- @ssl_config = nil
1195
-
1196
- @user_agent = user_agent
1197
- @from = from
1198
- @state = :INIT
1199
-
1200
- @requests = []
1201
-
1202
- @status = nil
1203
- @reason = nil
1204
- @headers = []
1205
-
1206
- @socket = nil
1207
- end
1208
-
1209
- # Send a request to the server
1210
- def query(req)
1211
- connect() if @state == :INIT
1212
- begin
1213
- timeout(@send_timeout) do
1214
- set_header(req)
1215
- req.dump(@socket)
1216
- # flush the IO stream as IO::sync mode is false
1217
- @socket.flush unless @socket_sync
1218
- end
1219
- rescue Errno::ECONNABORTED
1220
- close
1221
- raise KeepAliveDisconnected.new
1222
- rescue
1223
- if SSLEnabled and $!.is_a?(OpenSSL::SSL::SSLError)
1224
- raise KeepAliveDisconnected.new
1225
- elsif $!.is_a?(TimeoutError)
1226
- close
1227
- raise
1228
- else
1229
- raise
1230
- end
1231
- end
1232
-
1233
- @state = :META if @state == :WAIT
1234
- @next_connection = nil
1235
- @requests.push(req)
1236
- end
1237
-
1238
- def close
1239
- unless @socket.nil?
1240
- @socket.flush
1241
- @socket.close unless @socket.closed?
1242
- end
1243
- @state = :INIT
1244
- end
1245
-
1246
- def closed?
1247
- @state == :INIT
1248
- end
1249
-
1250
- def get_status
1251
- version = status = reason = nil
1252
- begin
1253
- if @state != :META
1254
- raise RuntimeError.new("get_status must be called at the beginning of a session.")
1255
- end
1256
- version, status, reason = read_header()
1257
- rescue
1258
- close
1259
- raise
1260
- end
1261
- return version, status, reason
1262
- end
1263
-
1264
- def get_header(&block)
1265
- begin
1266
- read_header() if @state == :META
1267
- rescue
1268
- close
1269
- raise
1270
- end
1271
- if block
1272
- @headers.each do |line|
1273
- block.call(line)
1274
- end
1275
- else
1276
- @headers
1277
- end
1278
- end
1279
-
1280
- def eof?
1281
- if @content_length == 0
1282
- true
1283
- elsif @readbuf.length > 0
1284
- false
1285
- else
1286
- @socket.closed? or @socket.eof?
1287
- end
1288
- end
1289
-
1290
- def get_data(&block)
1291
- begin
1292
- read_header() if @state == :META
1293
- return nil if @state != :DATA
1294
- unless @state == :DATA
1295
- raise InvalidState.new('state != DATA')
1296
- end
1297
- data = nil
1298
- if block
1299
- until eof?
1300
- begin
1301
- timeout(@receive_timeout) do
1302
- data = read_body()
1303
- end
1304
- rescue TimeoutError
1305
- raise
1306
- end
1307
- block.call(data) if data
1308
- end
1309
- data = nil # Calling with block returns nil.
1310
- else
1311
- begin
1312
- timeout(@receive_timeout) do
1313
- data = read_body()
1314
- end
1315
- rescue TimeoutError
1316
- raise
1317
- end
1318
- end
1319
- rescue
1320
- close
1321
- raise
1322
- end
1323
- if eof?
1324
- if @next_connection
1325
- @state = :WAIT
1326
- else
1327
- close
1328
- end
1329
- end
1330
- data
1331
- end
1332
-
1333
- private
1334
-
1335
- LibNames = "(#{RCS_FILE}/#{RCS_REVISION}, #{RUBY_VERSION_STRING})"
1336
-
1337
- def set_header(req)
1338
- req.version = @requested_version if @requested_version
1339
- if @user_agent
1340
- req.header.set('User-Agent', "#{@user_agent} #{LibNames}")
1341
- end
1342
- if @from
1343
- req.header.set('From', @from)
1344
- end
1345
- req.header.set('Date', Time.now)
1346
- end
1347
-
1348
- # Connect to the server
1349
- def connect
1350
- site = @proxy || @dest
1351
- begin
1352
- retry_number = 0
1353
- timeout(@connect_timeout) do
1354
- @socket = create_socket(site)
1355
- begin
1356
- @src.host = @socket.addr[3]
1357
- @src.port = @socket.addr[1]
1358
- rescue SocketError
1359
- # to avoid IPSocket#addr problem on Mac OS X 10.3 + ruby-1.8.1.
1360
- # cf. [ruby-talk:84909], [ruby-talk:95827]
1361
- end
1362
- if @dest.scheme == 'https'
1363
- @socket = create_ssl_socket(@socket)
1364
- connect_ssl_proxy(@socket) if @proxy
1365
- @socket.ssl_connect
1366
- @socket.post_connection_check(@dest)
1367
- end
1368
- # Use Ruby internal buffering instead of passing data immediatly
1369
- # to the underlying layer
1370
- # => we need to to call explicitely flush on the socket
1371
- @socket.sync = @socket_sync
1372
- end
1373
- rescue TimeoutError
1374
- if @connect_retry == 0
1375
- retry
1376
- else
1377
- retry_number += 1
1378
- retry if retry_number < @connect_retry
1379
- end
1380
- close
1381
- raise
1382
- end
1383
-
1384
- @state = :WAIT
1385
- @readbuf = ''
1386
- end
1387
-
1388
- def create_socket(site)
1389
- begin
1390
- if @debug_dev
1391
- DebugSocket.create_socket(site.host, site.port, @debug_dev)
1392
- else
1393
- TCPSocket.new(site.host, site.port)
1394
- end
1395
- rescue SystemCallError => e
1396
- e.message << " (#{site.host}, ##{site.port})"
1397
- raise
1398
- end
1399
- end
1400
-
1401
- # wrap socket with OpenSSL.
1402
- def create_ssl_socket(raw_socket)
1403
- SSLSocketWrap.new(raw_socket, @ssl_config, (DEBUG_SSL ? @debug_dev : nil))
1404
- end
1405
-
1406
- def connect_ssl_proxy(socket)
1407
- socket << sprintf("CONNECT %s:%s HTTP/1.1\r\n\r\n", @dest.host, @dest.port)
1408
- parse_header(socket)
1409
- unless @status == 200
1410
- raise BadResponse.new(
1411
- "connect to ssl proxy failed with status #{@status} #{@reason}")
1412
- end
1413
- end
1414
-
1415
- # Read status block.
1416
- def read_header
1417
- if @state == :DATA
1418
- get_data {}
1419
- check_state()
1420
- end
1421
- unless @state == :META
1422
- raise InvalidState, 'state != :META'
1423
- end
1424
- parse_header(@socket)
1425
- @content_length = nil
1426
- @chunked = false
1427
- @headers.each do |line|
1428
- case line
1429
- when /^Content-Length:\s+(\d+)/i
1430
- @content_length = $1.to_i
1431
- when /^Transfer-Encoding:\s+chunked/i
1432
- @chunked = true
1433
- @content_length = true # how?
1434
- @chunk_length = 0
1435
- when /^Connection:\s+([\-\w]+)/i, /^Proxy-Connection:\s+([\-\w]+)/i
1436
- case $1
1437
- when /^Keep-Alive$/i
1438
- @next_connection = true
1439
- when /^close$/i
1440
- @next_connection = false
1441
- end
1442
- else
1443
- # Nothing to parse.
1444
- end
1445
- end
1446
-
1447
- # Head of the request has been parsed.
1448
- @state = :DATA
1449
- req = @requests.shift
1450
-
1451
- if req.header.request_method == 'HEAD'
1452
- @content_length = 0
1453
- if @next_connection
1454
- @state = :WAIT
1455
- else
1456
- close
1457
- end
1458
- end
1459
- @next_connection = false unless @content_length
1460
- return [@version, @status, @reason]
1461
- end
1462
-
1463
- StatusParseRegexp = %r(\AHTTP/(\d+\.\d+)\s+(\d+)(?:\s+(.*))?\r?\n\z)
1464
- def parse_header(socket)
1465
- begin
1466
- timeout(@receive_timeout) do
1467
- begin
1468
- initial_line = socket.gets("\n")
1469
- if initial_line.nil?
1470
- raise KeepAliveDisconnected.new
1471
- end
1472
- if StatusParseRegexp =~ initial_line
1473
- @version, @status, @reason = $1, $2.to_i, $3
1474
- @next_connection = HTTP.keep_alive_enabled?(@version)
1475
- else
1476
- @version = '0.9'
1477
- @status = nil
1478
- @reason = nil
1479
- @next_connection = false
1480
- @readbuf = initial_line
1481
- break
1482
- end
1483
- @headers = []
1484
- while true
1485
- line = socket.gets("\n")
1486
- unless line
1487
- raise BadResponse.new('Unexpected EOF.')
1488
- end
1489
- line.sub!(/\r?\n\z/, '')
1490
- break if line.empty?
1491
- if line.sub!(/^\t/, '')
1492
- @headers[-1] << line
1493
- else
1494
- @headers.push(line)
1495
- end
1496
- end
1497
- end while (@version == '1.1' && @status == 100)
1498
- end
1499
- rescue TimeoutError
1500
- raise
1501
- end
1502
- end
1503
-
1504
- def read_body
1505
- if @chunked
1506
- return read_body_chunked()
1507
- elsif @content_length == 0
1508
- return nil
1509
- elsif @content_length
1510
- return read_body_length()
1511
- else
1512
- if @readbuf.length > 0
1513
- data = @readbuf
1514
- @readbuf = ''
1515
- return data
1516
- else
1517
- data = @socket.read(@read_block_size)
1518
- data = nil if data.empty? # Absorbing interface mismatch.
1519
- return data
1520
- end
1521
- end
1522
- end
1523
-
1524
- def read_body_length
1525
- maxbytes = @read_block_size
1526
- if @readbuf.length > 0
1527
- data = @readbuf[0, @content_length]
1528
- @readbuf[0, @content_length] = ''
1529
- @content_length -= data.length
1530
- return data
1531
- end
1532
- maxbytes = @content_length if maxbytes > @content_length
1533
- data = @socket.read(maxbytes)
1534
- if data
1535
- @content_length -= data.length
1536
- else
1537
- @content_length = 0
1538
- end
1539
- return data
1540
- end
1541
-
1542
- RS = "\r\n"
1543
- ChunkDelimiter = "0#{RS}"
1544
- ChunkTrailer = "0#{RS}#{RS}"
1545
- def read_body_chunked
1546
- if @chunk_length == 0
1547
- until (i = @readbuf.index(RS))
1548
- @readbuf << @socket.gets(RS)
1549
- end
1550
- i += 2
1551
- if @readbuf[0, i] == ChunkDelimiter
1552
- @content_length = 0
1553
- unless @readbuf[0, 5] == ChunkTrailer
1554
- @readbuf << @socket.gets(RS)
1555
- end
1556
- @readbuf[0, 5] = ''
1557
- return nil
1558
- end
1559
- @chunk_length = @readbuf[0, i].hex
1560
- @readbuf[0, i] = ''
1561
- end
1562
- while @readbuf.length < @chunk_length + 2
1563
- @readbuf << @socket.read(@chunk_length + 2 - @readbuf.length)
1564
- end
1565
- data = @readbuf[0, @chunk_length]
1566
- @readbuf[0, @chunk_length + 2] = ''
1567
- @chunk_length = 0
1568
- return data
1569
- end
1570
-
1571
- def check_state
1572
- if @state == :DATA
1573
- if eof?
1574
- if @next_connection
1575
- if @requests.empty?
1576
- @state = :WAIT
1577
- else
1578
- @state = :META
1579
- end
1580
- end
1581
- end
1582
- end
1583
- end
1584
- end
1585
-
1586
-
1587
- end
1588
-
1589
-
1590
- HTTPClient = HTTPAccess2::Client