kitamomonga-mechanize 0.9.3.20090724215219

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (177) hide show
  1. data/CHANGELOG.rdoc +504 -0
  2. data/EXAMPLES.rdoc +171 -0
  3. data/FAQ.rdoc +11 -0
  4. data/GUIDE.rdoc +122 -0
  5. data/LICENSE.rdoc +340 -0
  6. data/Manifest.txt +176 -0
  7. data/README.rdoc +60 -0
  8. data/Rakefile +33 -0
  9. data/examples/flickr_upload.rb +23 -0
  10. data/examples/mech-dump.rb +7 -0
  11. data/examples/proxy_req.rb +9 -0
  12. data/examples/rubyforge.rb +21 -0
  13. data/examples/spider.rb +11 -0
  14. data/lib/mechanize.rb +666 -0
  15. data/lib/mechanize/chain.rb +34 -0
  16. data/lib/mechanize/chain/auth_headers.rb +78 -0
  17. data/lib/mechanize/chain/body_decoding_handler.rb +46 -0
  18. data/lib/mechanize/chain/connection_resolver.rb +76 -0
  19. data/lib/mechanize/chain/custom_headers.rb +21 -0
  20. data/lib/mechanize/chain/handler.rb +9 -0
  21. data/lib/mechanize/chain/header_resolver.rb +51 -0
  22. data/lib/mechanize/chain/parameter_resolver.rb +22 -0
  23. data/lib/mechanize/chain/post_connect_hook.rb +0 -0
  24. data/lib/mechanize/chain/post_page_hook.rb +18 -0
  25. data/lib/mechanize/chain/pre_connect_hook.rb +20 -0
  26. data/lib/mechanize/chain/request_resolver.rb +30 -0
  27. data/lib/mechanize/chain/response_body_parser.rb +38 -0
  28. data/lib/mechanize/chain/response_header_handler.rb +48 -0
  29. data/lib/mechanize/chain/response_reader.rb +39 -0
  30. data/lib/mechanize/chain/ssl_resolver.rb +40 -0
  31. data/lib/mechanize/chain/uri_resolver.rb +75 -0
  32. data/lib/mechanize/content_type_error.rb +14 -0
  33. data/lib/mechanize/cookie.rb +70 -0
  34. data/lib/mechanize/cookie_jar.rb +188 -0
  35. data/lib/mechanize/file.rb +71 -0
  36. data/lib/mechanize/file_response.rb +60 -0
  37. data/lib/mechanize/file_saver.rb +37 -0
  38. data/lib/mechanize/form.rb +364 -0
  39. data/lib/mechanize/form/button.rb +7 -0
  40. data/lib/mechanize/form/check_box.rb +11 -0
  41. data/lib/mechanize/form/field.rb +26 -0
  42. data/lib/mechanize/form/file_upload.rb +22 -0
  43. data/lib/mechanize/form/image_button.rb +21 -0
  44. data/lib/mechanize/form/multi_select_list.rb +67 -0
  45. data/lib/mechanize/form/option.rb +49 -0
  46. data/lib/mechanize/form/radio_button.rb +36 -0
  47. data/lib/mechanize/form/select_list.rb +43 -0
  48. data/lib/mechanize/headers.rb +11 -0
  49. data/lib/mechanize/history.rb +65 -0
  50. data/lib/mechanize/inspect.rb +88 -0
  51. data/lib/mechanize/monkey_patch.rb +35 -0
  52. data/lib/mechanize/page.rb +279 -0
  53. data/lib/mechanize/page/base.rb +8 -0
  54. data/lib/mechanize/page/encoding.rb +61 -0
  55. data/lib/mechanize/page/frame.rb +20 -0
  56. data/lib/mechanize/page/link.rb +53 -0
  57. data/lib/mechanize/page/meta.rb +50 -0
  58. data/lib/mechanize/pluggable_parsers.rb +101 -0
  59. data/lib/mechanize/redirect_limit_reached_error.rb +16 -0
  60. data/lib/mechanize/redirect_not_get_or_head_error.rb +18 -0
  61. data/lib/mechanize/response_code_error.rb +22 -0
  62. data/lib/mechanize/unsupported_scheme_error.rb +8 -0
  63. data/lib/mechanize/util.rb +73 -0
  64. data/test/chain/test_argument_validator.rb +14 -0
  65. data/test/chain/test_auth_headers.rb +25 -0
  66. data/test/chain/test_custom_headers.rb +18 -0
  67. data/test/chain/test_header_resolver.rb +28 -0
  68. data/test/chain/test_parameter_resolver.rb +35 -0
  69. data/test/chain/test_request_resolver.rb +29 -0
  70. data/test/chain/test_response_reader.rb +24 -0
  71. data/test/data/htpasswd +1 -0
  72. data/test/data/server.crt +16 -0
  73. data/test/data/server.csr +12 -0
  74. data/test/data/server.key +15 -0
  75. data/test/data/server.pem +15 -0
  76. data/test/helper.rb +129 -0
  77. data/test/htdocs/alt_text.html +10 -0
  78. data/test/htdocs/bad_form_test.html +9 -0
  79. data/test/htdocs/button.jpg +0 -0
  80. data/test/htdocs/empty_form.html +6 -0
  81. data/test/htdocs/file_upload.html +26 -0
  82. data/test/htdocs/find_link.html +41 -0
  83. data/test/htdocs/form_multi_select.html +16 -0
  84. data/test/htdocs/form_multival.html +37 -0
  85. data/test/htdocs/form_no_action.html +18 -0
  86. data/test/htdocs/form_no_input_name.html +16 -0
  87. data/test/htdocs/form_select.html +16 -0
  88. data/test/htdocs/form_select_all.html +16 -0
  89. data/test/htdocs/form_select_none.html +17 -0
  90. data/test/htdocs/form_select_noopts.html +10 -0
  91. data/test/htdocs/form_set_fields.html +14 -0
  92. data/test/htdocs/form_test.html +188 -0
  93. data/test/htdocs/frame_test.html +30 -0
  94. data/test/htdocs/google.html +13 -0
  95. data/test/htdocs/iframe_test.html +16 -0
  96. data/test/htdocs/index.html +6 -0
  97. data/test/htdocs/link with space.html +5 -0
  98. data/test/htdocs/meta_cookie.html +11 -0
  99. data/test/htdocs/no_title_test.html +6 -0
  100. data/test/htdocs/relative/tc_relative_links.html +21 -0
  101. data/test/htdocs/tc_bad_charset.html +9 -0
  102. data/test/htdocs/tc_bad_links.html +5 -0
  103. data/test/htdocs/tc_base_link.html +8 -0
  104. data/test/htdocs/tc_blank_form.html +11 -0
  105. data/test/htdocs/tc_charset.html +6 -0
  106. data/test/htdocs/tc_checkboxes.html +19 -0
  107. data/test/htdocs/tc_encoded_links.html +5 -0
  108. data/test/htdocs/tc_follow_meta.html +8 -0
  109. data/test/htdocs/tc_form_action.html +48 -0
  110. data/test/htdocs/tc_links.html +19 -0
  111. data/test/htdocs/tc_no_attributes.html +16 -0
  112. data/test/htdocs/tc_pretty_print.html +17 -0
  113. data/test/htdocs/tc_radiobuttons.html +17 -0
  114. data/test/htdocs/tc_referer.html +10 -0
  115. data/test/htdocs/tc_relative_links.html +19 -0
  116. data/test/htdocs/tc_textarea.html +23 -0
  117. data/test/htdocs/test_bad_encoding.html +52 -0
  118. data/test/htdocs/unusual______.html +5 -0
  119. data/test/servlets.rb +365 -0
  120. data/test/ssl_server.rb +48 -0
  121. data/test/test_authenticate.rb +71 -0
  122. data/test/test_bad_links.rb +25 -0
  123. data/test/test_blank_form.rb +16 -0
  124. data/test/test_checkboxes.rb +61 -0
  125. data/test/test_content_type.rb +13 -0
  126. data/test/test_cookie_class.rb +338 -0
  127. data/test/test_cookie_jar.rb +362 -0
  128. data/test/test_cookies.rb +123 -0
  129. data/test/test_encoded_links.rb +20 -0
  130. data/test/test_errors.rb +49 -0
  131. data/test/test_follow_meta.rb +108 -0
  132. data/test/test_form_action.rb +52 -0
  133. data/test/test_form_as_hash.rb +61 -0
  134. data/test/test_form_button.rb +38 -0
  135. data/test/test_form_no_inputname.rb +15 -0
  136. data/test/test_forms.rb +577 -0
  137. data/test/test_frames.rb +25 -0
  138. data/test/test_get_headers.rb +73 -0
  139. data/test/test_gzipping.rb +22 -0
  140. data/test/test_hash_api.rb +45 -0
  141. data/test/test_history.rb +142 -0
  142. data/test/test_history_added.rb +16 -0
  143. data/test/test_html_unscape_forms.rb +39 -0
  144. data/test/test_if_modified_since.rb +20 -0
  145. data/test/test_keep_alive.rb +31 -0
  146. data/test/test_links.rb +127 -0
  147. data/test/test_mech.rb +289 -0
  148. data/test/test_mechanize_file.rb +72 -0
  149. data/test/test_meta.rb +65 -0
  150. data/test/test_multi_select.rb +106 -0
  151. data/test/test_no_attributes.rb +13 -0
  152. data/test/test_option.rb +18 -0
  153. data/test/test_page.rb +127 -0
  154. data/test/test_page_encoding.rb +298 -0
  155. data/test/test_pluggable_parser.rb +145 -0
  156. data/test/test_post_form.rb +34 -0
  157. data/test/test_pretty_print.rb +22 -0
  158. data/test/test_radiobutton.rb +75 -0
  159. data/test/test_redirect_limit_reached.rb +39 -0
  160. data/test/test_redirect_verb_handling.rb +43 -0
  161. data/test/test_referer.rb +39 -0
  162. data/test/test_relative_links.rb +40 -0
  163. data/test/test_request.rb +13 -0
  164. data/test/test_response_code.rb +52 -0
  165. data/test/test_save_file.rb +103 -0
  166. data/test/test_scheme.rb +63 -0
  167. data/test/test_select.rb +106 -0
  168. data/test/test_select_all.rb +15 -0
  169. data/test/test_select_none.rb +15 -0
  170. data/test/test_select_noopts.rb +16 -0
  171. data/test/test_set_fields.rb +44 -0
  172. data/test/test_ssl_server.rb +20 -0
  173. data/test/test_subclass.rb +14 -0
  174. data/test/test_textarea.rb +45 -0
  175. data/test/test_upload.rb +109 -0
  176. data/test/test_verbs.rb +25 -0
  177. metadata +320 -0
data/Manifest.txt ADDED
@@ -0,0 +1,176 @@
1
+ CHANGELOG.rdoc
2
+ EXAMPLES.rdoc
3
+ FAQ.rdoc
4
+ GUIDE.rdoc
5
+ LICENSE.rdoc
6
+ Manifest.txt
7
+ README.rdoc
8
+ Rakefile
9
+ examples/flickr_upload.rb
10
+ examples/mech-dump.rb
11
+ examples/proxy_req.rb
12
+ examples/rubyforge.rb
13
+ examples/spider.rb
14
+ lib/mechanize.rb
15
+ lib/mechanize/chain.rb
16
+ lib/mechanize/chain/auth_headers.rb
17
+ lib/mechanize/chain/body_decoding_handler.rb
18
+ lib/mechanize/chain/connection_resolver.rb
19
+ lib/mechanize/chain/custom_headers.rb
20
+ lib/mechanize/chain/handler.rb
21
+ lib/mechanize/chain/header_resolver.rb
22
+ lib/mechanize/chain/parameter_resolver.rb
23
+ lib/mechanize/chain/post_connect_hook.rb
24
+ lib/mechanize/chain/post_page_hook.rb
25
+ lib/mechanize/chain/pre_connect_hook.rb
26
+ lib/mechanize/chain/request_resolver.rb
27
+ lib/mechanize/chain/response_body_parser.rb
28
+ lib/mechanize/chain/response_header_handler.rb
29
+ lib/mechanize/chain/response_reader.rb
30
+ lib/mechanize/chain/ssl_resolver.rb
31
+ lib/mechanize/chain/uri_resolver.rb
32
+ lib/mechanize/content_type_error.rb
33
+ lib/mechanize/cookie.rb
34
+ lib/mechanize/cookie_jar.rb
35
+ lib/mechanize/file.rb
36
+ lib/mechanize/file_response.rb
37
+ lib/mechanize/file_saver.rb
38
+ lib/mechanize/form.rb
39
+ lib/mechanize/form/button.rb
40
+ lib/mechanize/form/check_box.rb
41
+ lib/mechanize/form/field.rb
42
+ lib/mechanize/form/file_upload.rb
43
+ lib/mechanize/form/image_button.rb
44
+ lib/mechanize/form/multi_select_list.rb
45
+ lib/mechanize/form/option.rb
46
+ lib/mechanize/form/radio_button.rb
47
+ lib/mechanize/form/select_list.rb
48
+ lib/mechanize/headers.rb
49
+ lib/mechanize/history.rb
50
+ lib/mechanize/inspect.rb
51
+ lib/mechanize/monkey_patch.rb
52
+ lib/mechanize/page.rb
53
+ lib/mechanize/page/base.rb
54
+ lib/mechanize/page/encoding.rb
55
+ lib/mechanize/page/frame.rb
56
+ lib/mechanize/page/link.rb
57
+ lib/mechanize/page/meta.rb
58
+ lib/mechanize/pluggable_parsers.rb
59
+ lib/mechanize/redirect_limit_reached_error.rb
60
+ lib/mechanize/redirect_not_get_or_head_error.rb
61
+ lib/mechanize/response_code_error.rb
62
+ lib/mechanize/unsupported_scheme_error.rb
63
+ lib/mechanize/util.rb
64
+ test/chain/test_argument_validator.rb
65
+ test/chain/test_auth_headers.rb
66
+ test/chain/test_custom_headers.rb
67
+ test/chain/test_header_resolver.rb
68
+ test/chain/test_parameter_resolver.rb
69
+ test/chain/test_request_resolver.rb
70
+ test/chain/test_response_reader.rb
71
+ test/data/htpasswd
72
+ test/data/server.crt
73
+ test/data/server.csr
74
+ test/data/server.key
75
+ test/data/server.pem
76
+ test/helper.rb
77
+ test/htdocs/alt_text.html
78
+ test/htdocs/bad_form_test.html
79
+ test/htdocs/button.jpg
80
+ test/htdocs/empty_form.html
81
+ test/htdocs/file_upload.html
82
+ test/htdocs/find_link.html
83
+ test/htdocs/form_multi_select.html
84
+ test/htdocs/form_multival.html
85
+ test/htdocs/form_no_action.html
86
+ test/htdocs/form_no_input_name.html
87
+ test/htdocs/form_select.html
88
+ test/htdocs/form_select_all.html
89
+ test/htdocs/form_select_none.html
90
+ test/htdocs/form_select_noopts.html
91
+ test/htdocs/form_set_fields.html
92
+ test/htdocs/form_test.html
93
+ test/htdocs/frame_test.html
94
+ test/htdocs/google.html
95
+ test/htdocs/iframe_test.html
96
+ test/htdocs/index.html
97
+ test/htdocs/link with space.html
98
+ test/htdocs/meta_cookie.html
99
+ test/htdocs/no_title_test.html
100
+ test/htdocs/relative/tc_relative_links.html
101
+ test/htdocs/tc_bad_charset.html
102
+ test/htdocs/tc_bad_links.html
103
+ test/htdocs/tc_base_link.html
104
+ test/htdocs/tc_blank_form.html
105
+ test/htdocs/tc_charset.html
106
+ test/htdocs/tc_checkboxes.html
107
+ test/htdocs/tc_encoded_links.html
108
+ test/htdocs/tc_follow_meta.html
109
+ test/htdocs/tc_form_action.html
110
+ test/htdocs/tc_links.html
111
+ test/htdocs/tc_no_attributes.html
112
+ test/htdocs/tc_pretty_print.html
113
+ test/htdocs/tc_radiobuttons.html
114
+ test/htdocs/tc_referer.html
115
+ test/htdocs/tc_relative_links.html
116
+ test/htdocs/tc_textarea.html
117
+ test/htdocs/test_bad_encoding.html
118
+ test/htdocs/unusual______.html
119
+ test/servlets.rb
120
+ test/ssl_server.rb
121
+ test/test_authenticate.rb
122
+ test/test_bad_links.rb
123
+ test/test_blank_form.rb
124
+ test/test_checkboxes.rb
125
+ test/test_content_type.rb
126
+ test/test_cookie_class.rb
127
+ test/test_cookie_jar.rb
128
+ test/test_cookies.rb
129
+ test/test_encoded_links.rb
130
+ test/test_errors.rb
131
+ test/test_follow_meta.rb
132
+ test/test_form_action.rb
133
+ test/test_form_as_hash.rb
134
+ test/test_form_button.rb
135
+ test/test_form_no_inputname.rb
136
+ test/test_forms.rb
137
+ test/test_frames.rb
138
+ test/test_get_headers.rb
139
+ test/test_gzipping.rb
140
+ test/test_hash_api.rb
141
+ test/test_history.rb
142
+ test/test_history_added.rb
143
+ test/test_html_unscape_forms.rb
144
+ test/test_if_modified_since.rb
145
+ test/test_keep_alive.rb
146
+ test/test_links.rb
147
+ test/test_mech.rb
148
+ test/test_mechanize_file.rb
149
+ test/test_meta.rb
150
+ test/test_multi_select.rb
151
+ test/test_no_attributes.rb
152
+ test/test_option.rb
153
+ test/test_page.rb
154
+ test/test_page_encoding.rb
155
+ test/test_pluggable_parser.rb
156
+ test/test_post_form.rb
157
+ test/test_pretty_print.rb
158
+ test/test_radiobutton.rb
159
+ test/test_redirect_limit_reached.rb
160
+ test/test_redirect_verb_handling.rb
161
+ test/test_referer.rb
162
+ test/test_relative_links.rb
163
+ test/test_request.rb
164
+ test/test_response_code.rb
165
+ test/test_save_file.rb
166
+ test/test_scheme.rb
167
+ test/test_select.rb
168
+ test/test_select_all.rb
169
+ test/test_select_none.rb
170
+ test/test_select_noopts.rb
171
+ test/test_set_fields.rb
172
+ test/test_ssl_server.rb
173
+ test/test_subclass.rb
174
+ test/test_textarea.rb
175
+ test/test_upload.rb
176
+ test/test_verbs.rb
data/README.rdoc ADDED
@@ -0,0 +1,60 @@
1
+ = WWW::Mechanize
2
+
3
+ * http://mechanize.rubyforge.org/
4
+ * http://github.com/tenderlove/mechanize/tree/master
5
+
6
+ == DESCRIPTION
7
+
8
+ The Mechanize library is used for automating interaction with websites.
9
+ Mechanize automatically stores and sends cookies, follows redirects,
10
+ can follow links, and submit forms. Form fields can be populated and
11
+ submitted. Mechanize also keeps track of the sites that you have visited as
12
+ a history.
13
+
14
+ == Dependencies
15
+
16
+ * ruby 1.8.6
17
+ * nokogiri[http://nokogiri.rubyforge.org]
18
+
19
+ == SUPPORT:
20
+
21
+ The mechanize mailing list is available here:
22
+
23
+ * http://rubyforge.org/mailman/listinfo/mechanize-users
24
+
25
+ The bug tracker is available here:
26
+
27
+ * http://rubyforge.org/tracker/?atid=5709&group_id=1453
28
+
29
+ == Examples
30
+
31
+ If you are just starting, check out the GUIDE.
32
+ Also, check out the EXAMPLES file.
33
+
34
+ == Authors
35
+
36
+ Copyright (c) 2005 by Michael Neumann (mneumann@ntecs.de)
37
+
38
+ Copyright (c) 2006-2009:
39
+
40
+ * {Aaron Patterson}[http://tenderlovemaking.com] (aaronp@rubyforge.org)
41
+ * {Mike Dalessio}[http://mike.daless.io] (mike@csa.net)
42
+
43
+ This library comes with a shameless plug for employing me
44
+ (Aaron[http://tenderlovemaking.com/]) programming
45
+ Ruby, my favorite language!
46
+
47
+ == Acknowledgments
48
+
49
+ This library was heavily influenced by its namesake in the perl world. A big
50
+ thanks goes to Andy Lester (andy@petdance.com), the author of the original
51
+ perl Mechanize which is available here[http://search.cpan.org/~petdance/WWW-Mechanize-1.20/]. Ruby Mechanize would not be around without you!
52
+
53
+ Thank you to Michael Neumann for starting the Ruby version. Thanks to everyone
54
+ who's helped out in various ways. Finally, thank you to the people using this
55
+ library!
56
+
57
+ == License
58
+
59
+ This library is distributed under the GPL. Please see the LICENSE file.
60
+
data/Rakefile ADDED
@@ -0,0 +1,33 @@
1
+ require 'rubygems'
2
+ require 'hoe'
3
+
4
+ Hoe.spec 'mechanize' do
5
+ developer 'Aaron Patterson', 'aaronp@rubyforge.org'
6
+ developer 'Mike Dalessio', 'mike.dalessio@gmail.com'
7
+
8
+ self.readme_file = 'README.rdoc'
9
+ self.history_file = 'CHANGELOG.rdoc'
10
+ self.extra_rdoc_files << Dir['*.rdoc']
11
+ self.extra_deps << ['nokogiri', '>= 1.2.1']
12
+ end
13
+
14
+ desc "Update SSL Certificate"
15
+ task('ssl_cert') do |p|
16
+ sh "openssl genrsa -des3 -out server.key 1024"
17
+ sh "openssl req -new -key server.key -out server.csr"
18
+ sh "cp server.key server.key.org"
19
+ sh "openssl rsa -in server.key.org -out server.key"
20
+ sh "openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt"
21
+ sh "cp server.key server.pem"
22
+ sh "mv server.key server.csr server.crt server.pem test/data/"
23
+ sh "rm server.key.org"
24
+ end
25
+
26
+ desc 'Generate a gem spec'
27
+ task "gem:spec" do
28
+ File.open("mechanize.gemspec", 'w') do |f|
29
+ now = Time.now.strftime("%Y%m%d%H%M%S")
30
+ f.write `rake debug_gem`.sub(/(s.version = ".*)(")/) { "#{$1}.#{now}#{$2}" }
31
+ end
32
+ end
33
+
@@ -0,0 +1,23 @@
1
+ $:.unshift File.join(File.dirname(__FILE__), "..", "lib")
2
+
3
+ require 'rubygems'
4
+ require 'mechanize'
5
+
6
+ agent = WWW::Mechanize.new
7
+
8
+ # Get the flickr sign in page
9
+ page = agent.get('http://flickr.com/signin/flickr/')
10
+
11
+ # Fill out the login form
12
+ form = page.forms.name('flickrloginform').first
13
+ form.email = ARGV[0]
14
+ form.password = ARGV[1]
15
+ page = agent.submit(form)
16
+
17
+ # Go to the upload page
18
+ page = agent.click page.links.text('Upload')
19
+
20
+ # Fill out the form
21
+ form = page.forms.action('/photos_upload_process.gne').first
22
+ form.file_uploads.name('file1').first.file_name = ARGV[2]
23
+ agent.submit(form)
@@ -0,0 +1,7 @@
1
+ $:.unshift File.join(File.dirname(__FILE__), "..", "lib")
2
+
3
+ require 'rubygems'
4
+ require 'mechanize'
5
+
6
+ agent = WWW::Mechanize.new
7
+ puts agent.get(ARGV[0]).inspect
@@ -0,0 +1,9 @@
1
+ $:.unshift File.join(File.dirname(__FILE__), "..", "lib")
2
+
3
+ require 'rubygems'
4
+ require 'mechanize'
5
+
6
+ agent = WWW::Mechanize.new
7
+ agent.set_proxy('localhost', '8000')
8
+ page = agent.get(ARGV[0])
9
+ puts page.body
@@ -0,0 +1,21 @@
1
+ $:.unshift File.join(File.dirname(__FILE__), "..", "lib")
2
+
3
+ # This example logs a user in to rubyforge and prints out the body of the
4
+ # page after logging the user in.
5
+ require 'rubygems'
6
+ require 'mechanize'
7
+
8
+ # Create a new mechanize object
9
+ agent = WWW::Mechanize.new { |a| a.log = Logger.new(STDERR) }
10
+
11
+ # Load the rubyforge website
12
+ page = agent.get('http://rubyforge.org/')
13
+ page = agent.click page.links.text(/Log In/) # Click the login link
14
+ form = page.forms[1] # Select the first form
15
+ form.form_loginname = ARGV[0]
16
+ form.form_pw = ARGV[1]
17
+
18
+ # Submit the form
19
+ page = agent.submit(form, form.buttons.first)
20
+
21
+ puts page.body # Print out the body
@@ -0,0 +1,11 @@
1
+ $:.unshift File.join(File.dirname(__FILE__), "..", "lib")
2
+
3
+ require 'rubygems'
4
+ require 'mechanize'
5
+
6
+ agent = WWW::Mechanize.new
7
+ stack = agent.get(ARGV[0]).links
8
+ while l = stack.pop
9
+ next unless l.uri.host == agent.history.first.uri.host
10
+ stack.push(*(agent.click(l).links)) unless agent.visited? l.href
11
+ end
data/lib/mechanize.rb ADDED
@@ -0,0 +1,666 @@
1
+ require 'net/http'
2
+ require 'net/https'
3
+ require 'uri'
4
+ require 'webrick/httputils'
5
+ require 'zlib'
6
+ require 'stringio'
7
+ require 'digest/md5'
8
+ require 'fileutils'
9
+ require 'nokogiri'
10
+ require 'forwardable'
11
+ require 'iconv'
12
+ require 'nkf'
13
+
14
+ require 'mechanize/util'
15
+ require 'mechanize/content_type_error'
16
+ require 'mechanize/response_code_error'
17
+ require 'mechanize/unsupported_scheme_error'
18
+ require 'mechanize/redirect_limit_reached_error'
19
+ require 'mechanize/redirect_not_get_or_head_error'
20
+ require 'mechanize/cookie'
21
+ require 'mechanize/cookie_jar'
22
+ require 'mechanize/history'
23
+ require 'mechanize/form'
24
+ require 'mechanize/pluggable_parsers'
25
+ require 'mechanize/file_response'
26
+ require 'mechanize/inspect'
27
+ require 'mechanize/chain'
28
+ require 'mechanize/monkey_patch'
29
+
30
+ # = Synopsis
31
+ # The Mechanize library is used for automating interaction with a website. It
32
+ # can follow links, and submit forms. Form fields can be populated and
33
+ # submitted. A history of URL's is maintained and can be queried.
34
+ #
35
+ # == Example
36
+ # require 'rubygems'
37
+ # require 'mechanize'
38
+ # require 'logger'
39
+ #
40
+ # agent = WWW::Mechanize.new { |a| a.log = Logger.new("mech.log") }
41
+ # agent.user_agent_alias = 'Mac Safari'
42
+ # page = agent.get("http://www.google.com/")
43
+ # search_form = page.form_with(:name => "f")
44
+ # search_form.field_with(:name => "q").value = "Hello"
45
+ # search_results = agent.submit(search_form)
46
+ # puts search_results.body
47
+ class Mechanize
48
+ ##
49
+ # The version of Mechanize you are using.
50
+ VERSION = '0.9.3'
51
+
52
+ ##
53
+ # User Agent aliases
54
+ AGENT_ALIASES = {
55
+ 'Windows IE 6' => 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)',
56
+ 'Windows IE 7' => 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)',
57
+ 'Windows Mozilla' => 'Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.4b) Gecko/20030516 Mozilla Firebird/0.6',
58
+ 'Mac Safari' => 'Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/418 (KHTML, like Gecko) Safari/417.9.3',
59
+ 'Mac FireFox' => 'Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8.0.3) Gecko/20060426 Firefox/1.5.0.3',
60
+ 'Mac Mozilla' => 'Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.4a) Gecko/20030401',
61
+ 'Linux Mozilla' => 'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20030624',
62
+ 'Linux Konqueror' => 'Mozilla/5.0 (compatible; Konqueror/3; Linux)',
63
+ 'iPhone' => 'Mozilla/5.0 (iPhone; U; CPU like Mac OS X; en) AppleWebKit/420+ (KHTML, like Gecko) Version/3.0 Mobile/1C28 Safari/419.3',
64
+ 'Mechanize' => "WWW-Mechanize/#{VERSION} (http://rubyforge.org/projects/mechanize/)"
65
+ }
66
+
67
+ attr_accessor :cookie_jar
68
+ attr_accessor :open_timeout, :read_timeout
69
+ attr_accessor :user_agent
70
+ attr_accessor :watch_for_set
71
+ attr_accessor :ca_file
72
+ attr_accessor :key
73
+ attr_accessor :cert
74
+ attr_accessor :pass
75
+ attr_accessor :redirect_ok
76
+ attr_accessor :keep_alive_time
77
+ attr_accessor :keep_alive
78
+ attr_accessor :conditional_requests
79
+ attr_accessor :follow_meta_refresh
80
+ attr_accessor :verify_callback
81
+ attr_accessor :history_added
82
+ attr_accessor :scheme_handlers
83
+ attr_accessor :redirection_limit
84
+
85
+ # A hash of custom request headers
86
+ attr_accessor :request_headers
87
+
88
+ # The HTML parser to be used when parsing documents
89
+ attr_accessor :html_parser
90
+
91
+ # use Content-Disposition header or not
92
+ attr_accessor :use_content_disposition
93
+
94
+ attr_reader :history
95
+ attr_reader :pluggable_parser
96
+ attr_reader :post_page_hook
97
+
98
+ alias :follow_redirect? :redirect_ok
99
+
100
+ @html_parser = Nokogiri::HTML
101
+ class << self; attr_accessor :html_parser, :log end
102
+
103
+ def initialize(params = {})
104
+ # attr_accessors
105
+ @cookie_jar = CookieJar.new
106
+ @log = nil
107
+ @open_timeout = nil
108
+ @read_timeout = nil
109
+ @user_agent = AGENT_ALIASES['Mechanize']
110
+ @watch_for_set = nil
111
+ @history_added = nil
112
+ @ca_file = nil # OpenSSL server certificate file
113
+
114
+ # callback for OpenSSL errors while verifying the server certificate
115
+ # chain, can be used for debugging or to ignore errors by always
116
+ # returning _true_
117
+ @verify_callback = nil
118
+ @cert = nil # OpenSSL Certificate
119
+ @key = nil # OpenSSL Private Key
120
+ @pass = nil # OpenSSL Password
121
+ @redirect_ok = true # Should we follow redirects?
122
+
123
+ # attr_readers
124
+ @history = Mechanize::History.new
125
+ @pluggable_parser = PluggableParser.new
126
+
127
+ # Auth variables
128
+ @user = nil # Auth User
129
+ @password = nil # Auth Password
130
+ @digest = nil # DigestAuth Digest
131
+ @auth_hash = {} # Keep track of urls for sending auth
132
+ @request_headers= {} # A hash of request headers to be used
133
+
134
+ # Proxy settings
135
+ @proxy_addr = nil
136
+ @proxy_pass = nil
137
+ @proxy_port = nil
138
+ @proxy_user = nil
139
+
140
+ @conditional_requests = true
141
+
142
+ @follow_meta_refresh = false
143
+ @redirection_limit = 20
144
+
145
+ # Connection Cache & Keep alive
146
+ @connection_cache = {}
147
+ @keep_alive_time = 300
148
+ @keep_alive = true
149
+
150
+ @use_content_disposition = false
151
+
152
+ @scheme_handlers = Hash.new { |h,k|
153
+ h[k] = lambda { |link, page|
154
+ raise UnsupportedSchemeError.new(k)
155
+ }
156
+ }
157
+ @scheme_handlers['http'] = lambda { |link, page| link }
158
+ @scheme_handlers['https'] = @scheme_handlers['http']
159
+ @scheme_handlers['relative'] = @scheme_handlers['http']
160
+ @scheme_handlers['file'] = @scheme_handlers['http']
161
+
162
+ @pre_connect_hook = Chain::PreConnectHook.new
163
+ @post_connect_hook = Chain::PostConnectHook.new
164
+
165
+ @post_page_hook = Chain::PostPageHook.new
166
+
167
+ @html_parser = self.class.html_parser
168
+
169
+ set_init_param(params)
170
+
171
+ yield self if block_given?
172
+ end
173
+
174
+ def max_history=(length); @history.max_size = length end
175
+ def max_history; @history.max_size end
176
+ def log=(l); self.class.log = l end
177
+ def log; self.class.log end
178
+
179
+ def pre_connect_hooks
180
+ @pre_connect_hook.hooks
181
+ end
182
+
183
+ def post_connect_hooks
184
+ @post_connect_hook.hooks
185
+ end
186
+
187
+ def post_page_hooks
188
+ @post_page_hook.hooks
189
+ end
190
+
191
+ # Sets the proxy address, port, user, and password
192
+ # +addr+ should be a host, with no "http://"
193
+ def set_proxy(addr, port, user = nil, pass = nil)
194
+ @proxy_addr, @proxy_port, @proxy_user, @proxy_pass = addr, port, user, pass
195
+ end
196
+
197
+ # Set the user agent for the Mechanize object.
198
+ # See AGENT_ALIASES
199
+ def user_agent_alias=(al)
200
+ self.user_agent = AGENT_ALIASES[al] || raise("unknown agent alias")
201
+ end
202
+
203
+ # Returns a list of cookies stored in the cookie jar.
204
+ def cookies
205
+ @cookie_jar.to_a
206
+ end
207
+
208
+ # Sets the user and password to be used for authentication.
209
+ def auth(user, password)
210
+ @user = user
211
+ @password = password
212
+ end
213
+ alias :basic_auth :auth
214
+
215
+ # Fetches the URL passed in and returns a page.
216
+ def get(options, parameters = [], referer = nil)
217
+ unless options.is_a? Hash
218
+ url = options
219
+ unless parameters.respond_to?(:each) # FIXME: Remove this in 0.8.0
220
+ referer = parameters
221
+ parameters = []
222
+ end
223
+ else
224
+ raise ArgumentError.new("url must be specified") unless url = options[:url]
225
+ parameters = options[:params] || []
226
+ referer = options[:referer]
227
+ headers = options[:headers]
228
+ end
229
+
230
+ unless referer
231
+ if url.to_s =~ /^http/
232
+ referer = Page.new(nil, {'content-type'=>'text/html'})
233
+ else
234
+ referer = current_page || Page.new(nil, {'content-type'=>'text/html'})
235
+ end
236
+ end
237
+
238
+ # FIXME: Huge hack so that using a URI as a referer works. I need to
239
+ # refactor everything to pass around URIs but still support
240
+ # Mechanize::Page#base
241
+ unless referer.is_a?(Mechanize::File)
242
+ referer = referer.is_a?(String) ?
243
+ Page.new(URI.parse(referer), {'content-type' => 'text/html'}) :
244
+ Page.new(referer, {'content-type' => 'text/html'})
245
+ end
246
+
247
+ # fetch the page
248
+ page = fetch_page( :uri => url,
249
+ :referer => referer,
250
+ :headers => headers || {},
251
+ :params => parameters
252
+ )
253
+ add_to_history(page)
254
+ yield page if block_given?
255
+ page
256
+ end
257
+
258
+ ####
259
+ # PUT to +url+ with +entity+, and setting +options+:
260
+ #
261
+ # put('http://tenderlovemaking.com/', 'new content', :headers => {'Content-Type' => 'text/plain'})
262
+ #
263
+ def put(url, entity, options = {})
264
+ request_with_entity(:put, url, entity, options)
265
+ end
266
+
267
+ ####
268
+ # DELETE to +url+ with +query_params+, and setting +options+:
269
+ #
270
+ # delete('http://tenderlovemaking.com/', {'q' => 'foo'}, :headers => {})
271
+ #
272
+ def delete(url, query_params = {}, options = {})
273
+ page = head(url, query_params, options.merge({:verb => :delete}))
274
+ add_to_history(page)
275
+ page
276
+ end
277
+
278
+ ####
279
+ # HEAD to +url+ with +query_params+, and setting +options+:
280
+ #
281
+ # head('http://tenderlovemaking.com/', {'q' => 'foo'}, :headers => {})
282
+ #
283
+ def head(url, query_params = {}, options = {})
284
+ options = {
285
+ :uri => url,
286
+ :headers => {},
287
+ :params => query_params,
288
+ :verb => :head
289
+ }.merge(options)
290
+ # fetch the page
291
+ page = fetch_page(options)
292
+ yield page if block_given?
293
+ page
294
+ end
295
+
296
+ # Fetch a file and return the contents of the file.
297
+ def get_file(url)
298
+ get(url).body
299
+ end
300
+
301
+ # Clicks the Mechanize::Link object passed in and returns the
302
+ # page fetched.
303
+ def click(link)
304
+ referer = link.page rescue referer = nil
305
+ href = link.respond_to?(:href) ? link.href :
306
+ (link['href'] || link['src'])
307
+ get(:url => href, :referer => (referer || current_page()))
308
+ end
309
+
310
+ # Equivalent to the browser back button. Returns the most recent page
311
+ # visited.
312
+ def back
313
+ @history.pop
314
+ end
315
+
316
+ # Posts to the given URL with the request entity. The request
317
+ # entity is specified by either a string, or a list of key-value
318
+ # pairs represented by a hash or an array of arrays.
319
+ #
320
+ # Examples:
321
+ # agent.post('http://example.com/', "foo" => "bar")
322
+ #
323
+ # agent.post('http://example.com/', [ ["foo", "bar"] ])
324
+ #
325
+ # agent.post('http://example.com/', "<message>hello</message>", 'Content-Type' => 'application/xml')
326
+ def post(url, query={}, headers={})
327
+ if query.is_a?(String)
328
+ return request_with_entity(:post, url, query, :headers => headers)
329
+ end
330
+ node = {}
331
+ # Create a fake form
332
+ class << node
333
+ def search(*args); []; end
334
+ end
335
+ node['method'] = 'POST'
336
+ node['enctype'] = 'application/x-www-form-urlencoded'
337
+
338
+ form = Form.new(node)
339
+ query.each { |k,v|
340
+ if v.is_a?(IO)
341
+ form.enctype = 'multipart/form-data'
342
+ ul = Form::FileUpload.new(k.to_s,::File.basename(v.path))
343
+ ul.file_data = v.read
344
+ form.file_uploads << ul
345
+ else
346
+ form.fields << Form::Field.new(k.to_s,v)
347
+ end
348
+ }
349
+ post_form(url, form, headers)
350
+ end
351
+
352
+ # Submit a form with an optional button.
353
+ # Without a button:
354
+ # page = agent.get('http://example.com')
355
+ # agent.submit(page.forms.first)
356
+ # With a button
357
+ # agent.submit(page.forms.first, page.forms.first.buttons.first)
358
+ def submit(form, button=nil, headers={})
359
+ form.add_button_to_query(button) if button
360
+ case form.method.upcase
361
+ when 'POST'
362
+ post_form(form.action, form, headers)
363
+ when 'GET'
364
+ get( :url => form.action.gsub(/\?[^\?]*$/, ''),
365
+ :params => form.build_query,
366
+ :headers => headers,
367
+ :referer => form.page
368
+ )
369
+ else
370
+ raise "unsupported method: #{form.method.upcase}"
371
+ end
372
+ end
373
+
374
+ def request_with_entity(verb, url, entity, options={})
375
+ cur_page = current_page || Page.new( nil, {'content-type'=>'text/html'})
376
+
377
+ options = {
378
+ :uri => url,
379
+ :referer => cur_page,
380
+ :headers => {},
381
+ }.update(options)
382
+
383
+ headers = {
384
+ 'Content-Type' => 'application/octet-stream',
385
+ 'Content-Length' => entity.size.to_s,
386
+ }.update(options[:headers])
387
+
388
+ options.update({
389
+ :verb => verb,
390
+ :params => [entity],
391
+ :headers => headers,
392
+ })
393
+
394
+ page = fetch_page(options)
395
+ add_to_history(page)
396
+ page
397
+ end
398
+
399
+ # Returns the current page loaded by Mechanize
400
+ def current_page
401
+ @history.last
402
+ end
403
+
404
+ # Returns whether or not a url has been visited
405
+ def visited?(url)
406
+ ! visited_page(url).nil?
407
+ end
408
+
409
+ # Returns a visited page for the url passed in, otherwise nil
410
+ # agent.visited_page(-1) is agent.history[-1]
411
+ def visited_page(url)
412
+ if url.kind_of?(Integer)
413
+ history[url]
414
+ else
415
+ url = url.href if url.respond_to?(:href)
416
+ @history.visited_page(resolve(url))
417
+ end
418
+ end
419
+
420
+ # Runs given block, then resets the page history as it was before. self is
421
+ # given as a parameter to the block. Returns the value of the block.
422
+ def transact
423
+ history_backup = @history.dup
424
+ begin
425
+ yield self
426
+ ensure
427
+ @history = history_backup
428
+ end
429
+ end
430
+
431
+ alias :page :current_page
432
+
433
+ private
434
+
435
+ def set_init_param(params)
436
+ mech_methods = self.public_methods
437
+ config_pairs = Hash.new # Set configs only when no error occuers
438
+ if RUBY_VERSION >= '1.9.0'
439
+ params.each_pair do |k, value|
440
+ if (key = (k.to_s + '=').to_sym) && mech_methods.include?(key) then
441
+ config_pairs[key] = value
442
+ elsif (key = k.to_sym) && mech_methods.include?(key) then
443
+ config_pairs[key] = value
444
+ else raise "Invalid configure key: #{k}"
445
+ end
446
+ end
447
+ else
448
+ params.each_pair do |k, value|
449
+ if (key = k.to_s + '=') && mech_methods.include?(key) then
450
+ config_pairs[key] = value
451
+ elsif (key = k.to_s) && mech_methods.include?(key) then
452
+ config_pairs[key] = value
453
+ else raise "Invalid configure key: #{k}"
454
+ end
455
+ end
456
+ end
457
+
458
+ config_pairs.each_pair do |key, value|
459
+ self.__send__(key, *value)
460
+ end
461
+ end
462
+
463
+ def resolve(url, referer = current_page())
464
+ hash = { :uri => url, :referer => referer }
465
+ chain = Chain.new([
466
+ Chain::URIResolver.new(@scheme_handlers)
467
+ ]).handle(hash)
468
+ hash[:uri].to_s
469
+ end
470
+
471
+ def post_form(url, form, headers = {})
472
+ cur_page = form.page || current_page ||
473
+ Page.new( nil, {'content-type'=>'text/html'})
474
+
475
+ request_data = form.request_data
476
+
477
+ log.debug("query: #{ request_data.inspect }") if log
478
+
479
+ # fetch the page
480
+ page = fetch_page( :uri => url,
481
+ :referer => cur_page,
482
+ :verb => :post,
483
+ :params => [request_data],
484
+ :headers => {
485
+ 'Content-Type' => form.enctype,
486
+ 'Content-Length' => request_data.size.to_s,
487
+ }.merge(headers))
488
+ add_to_history(page)
489
+ page
490
+ end
491
+
492
+ # uri is an absolute URI
493
+ def fetch_page(params)
494
+ options = {
495
+ :request => nil,
496
+ :response => nil,
497
+ :connection => nil,
498
+ :referer => current_page(),
499
+ :uri => nil,
500
+ :verb => :get,
501
+ :agent => self,
502
+ :redirects => 0,
503
+ :params => [],
504
+ :headers => {},
505
+ }.merge(params)
506
+
507
+ before_connect = Chain.new([
508
+ Chain::URIResolver.new(@scheme_handlers),
509
+ Chain::ParameterResolver.new,
510
+ Chain::RequestResolver.new,
511
+ Chain::ConnectionResolver.new(
512
+ @connection_cache,
513
+ @keep_alive,
514
+ @proxy_addr,
515
+ @proxy_port,
516
+ @proxy_user,
517
+ @proxy_pass
518
+ ),
519
+ Chain::SSLResolver.new(@ca_file, @verify_callback, @cert, @key, @pass),
520
+ Chain::AuthHeaders.new(@auth_hash, @user, @password, @digest),
521
+ Chain::HeaderResolver.new(
522
+ @keep_alive,
523
+ @keep_alive_time,
524
+ @cookie_jar,
525
+ @user_agent,
526
+ @request_headers
527
+ ),
528
+ Chain::CustomHeaders.new,
529
+ @pre_connect_hook,
530
+ ])
531
+ before_connect.handle(options)
532
+
533
+ uri = options[:uri]
534
+ request = options[:request]
535
+ cur_page = options[:referer]
536
+ request_data = options[:params]
537
+ redirects = options[:redirects]
538
+ http_obj = options[:connection]
539
+
540
+ # Add If-Modified-Since if page is in history
541
+ if( (page = visited_page(uri)) && page.response['Last-Modified'] )
542
+ request['If-Modified-Since'] = page.response['Last-Modified']
543
+ end if(@conditional_requests)
544
+
545
+ # Specify timeouts if given
546
+ http_obj.open_timeout = @open_timeout if @open_timeout
547
+ http_obj.read_timeout = @read_timeout if @read_timeout
548
+ http_obj.start unless http_obj.started?
549
+
550
+ # Log specified headers for the request
551
+ log.info("#{ request.class }: #{ request.path }") if log
552
+ request.each_header do |k, v|
553
+ log.debug("request-header: #{ k } => #{ v }")
554
+ end if log
555
+
556
+ # Send the request
557
+ attempts = 0
558
+ begin
559
+ response = http_obj.request(request, *request_data) { |r|
560
+ connection_chain = Chain.new([
561
+ Chain::ResponseReader.new(r),
562
+ Chain::BodyDecodingHandler.new,
563
+ ])
564
+ connection_chain.handle(options)
565
+ }
566
+ rescue EOFError, Errno::ECONNRESET, Errno::EPIPE => x
567
+ log.error("Rescuing EOF error") if log
568
+ http_obj.finish
569
+ raise x if attempts >= 2
570
+ request.body = nil
571
+ http_obj.start
572
+ attempts += 1
573
+ retry
574
+ end
575
+
576
+ after_connect = Chain.new([
577
+ @post_connect_hook,
578
+ Chain::ResponseBodyParser.new(@pluggable_parser, @watch_for_set),
579
+ Chain::ResponseHeaderHandler.new(@cookie_jar, @connection_cache),
580
+ ])
581
+ after_connect.handle(options)
582
+
583
+ res_klass = options[:res_klass]
584
+ response_body = options[:response_body]
585
+ page = options[:page]
586
+
587
+ log.info("status: #{ page.code }") if log
588
+
589
+ if follow_meta_refresh
590
+ redirect_uri = nil
591
+ referer = page
592
+ if (page.respond_to?(:meta) && (redirect = page.meta.first))
593
+ redirect_uri = redirect.uri.to_s
594
+ sleep redirect.node['delay'].to_f
595
+ referer = Page.new(nil, {'content-type'=>'text/html'})
596
+ elsif refresh = response['refresh']
597
+ delay, redirect_uri = Page::Meta.parse(refresh, uri)
598
+ raise StandardError, "Invalid refresh http header" unless delay
599
+ if redirects + 1 > redirection_limit
600
+ raise RedirectLimitReachedError.new(page, redirects)
601
+ end
602
+ sleep delay.to_f
603
+ end
604
+ if redirect_uri
605
+ @history.push(page, page.uri)
606
+ return fetch_page(
607
+ :uri => redirect_uri,
608
+ :referer => referer,
609
+ :params => [],
610
+ :verb => :get,
611
+ :redirects => redirects + 1
612
+ )
613
+ end
614
+ end
615
+
616
+ return page if res_klass <= Net::HTTPSuccess
617
+
618
+ if res_klass == Net::HTTPNotModified
619
+ log.debug("Got cached page") if log
620
+ return visited_page(uri) || page
621
+ elsif res_klass <= Net::HTTPRedirection
622
+ return page unless follow_redirect?
623
+ log.info("follow redirect to: #{ response['Location'] }") if log
624
+ from_uri = page.uri
625
+ raise RedirectLimitReachedError.new(page, redirects) if redirects + 1 > redirection_limit
626
+ redirect_verb = options[:verb] == :head ? :head : :get
627
+ page = fetch_page( :uri => response['Location'].to_s,
628
+ :referer => page,
629
+ :params => [],
630
+ :verb => redirect_verb,
631
+ :redirects => redirects + 1
632
+ )
633
+ @history.push(page, from_uri)
634
+ return page
635
+ elsif res_klass <= Net::HTTPUnauthorized
636
+ raise ResponseCodeError.new(page) unless @user || @password
637
+ raise ResponseCodeError.new(page) if @auth_hash.has_key?(uri.host)
638
+ if response['www-authenticate'] =~ /Digest/i
639
+ @auth_hash[uri.host] = :digest
640
+ if response['server'] =~ /Microsoft-IIS/
641
+ @auth_hash[uri.host] = :iis_digest
642
+ end
643
+ @digest = response['www-authenticate']
644
+ else
645
+ @auth_hash[uri.host] = :basic
646
+ end
647
+ return fetch_page( :uri => uri,
648
+ :referer => cur_page,
649
+ :verb => request.method.downcase.to_sym,
650
+ :params => request_data,
651
+ :headers => options[:headers]
652
+ )
653
+ end
654
+
655
+ raise ResponseCodeError.new(page), "Unhandled response", caller
656
+ end
657
+
658
+ def add_to_history(page)
659
+ @history.push(page, resolve(page.uri))
660
+ history_added.call(page) if history_added
661
+ end
662
+ end
663
+
664
+ module WWW; end
665
+ WWW::Mechanize = ::Mechanize
666
+