mechanize 0.6.4 → 0.6.5
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of mechanize might be problematic. Click here for more details.
- data/CHANGELOG.txt +15 -0
- data/Manifest.txt +84 -1
- data/README.txt +11 -1
- data/Rakefile +45 -49
- data/lib/mechanize.rb +72 -18
- data/lib/mechanize/errors.rb +5 -1
- data/lib/mechanize/form.rb +7 -0
- data/lib/mechanize/form_elements.rb +8 -4
- data/lib/mechanize/hpricot.rb +1 -0
- data/lib/mechanize/net-overrides/net/http.rb +1 -1
- data/lib/mechanize/net-overrides/net/https.rb +1 -0
- data/lib/mechanize/net-overrides/net/protocol.rb +1 -1
- data/lib/mechanize/page.rb +18 -23
- data/lib/mechanize/pluggable_parsers.rb +20 -2
- data/lib/mechanize/rexml.rb +1 -1
- data/test/htdocs/relative/tc_relative_links.html +1 -0
- data/test/ssl_server.rb +48 -0
- data/test/tc_cookie_class.rb +57 -8
- data/test/tc_cookie_jar.rb +27 -0
- data/test/tc_forms.rb +12 -0
- data/test/tc_html_unscape_forms.rb +46 -0
- data/test/tc_if_modified_since.rb +25 -0
- data/test/tc_mech.rb +33 -0
- data/test/tc_relative_links.rb +7 -0
- data/test/test_all.rb +2 -0
- data/test/test_includes.rb +1 -0
- data/test/test_servlets.rb +21 -0
- metadata +59 -46
- data/lib/mechanize/mech_version.rb +0 -5
data/CHANGELOG.txt
CHANGED
@@ -1,5 +1,20 @@
|
|
1
1
|
= Mechanize CHANGELOG
|
2
2
|
|
3
|
+
== 0.6.5
|
4
|
+
|
5
|
+
* Copying headers to a hash to prevent memory leaks
|
6
|
+
* Speeding up page parsing
|
7
|
+
* Aliased fields to elements
|
8
|
+
* Adding If-Modified-Since header
|
9
|
+
* Added delete_field! to form. Thanks to Sava Chankov
|
10
|
+
* Updated uri escaping to support high order characters. Thanks to Henrik Nyh.
|
11
|
+
* Better handling relative URIs. Thanks to Henrik Nyh
|
12
|
+
* Now handles pipes in URLs
|
13
|
+
http://rubyforge.org/tracker/?func=detail&aid=7140&group_id=1453&atid=5709
|
14
|
+
* Now escaping html entities in form fields.
|
15
|
+
http://rubyforge.org/tracker/?func=detail&aid=7563&group_id=1453&atid=5709
|
16
|
+
* Added MSIE 7.0 user agent string
|
17
|
+
|
3
18
|
== 0.6.4
|
4
19
|
|
5
20
|
* Adding the "redirect_ok" method to Mechanize to stop mechanize from
|
data/Manifest.txt
CHANGED
@@ -19,7 +19,6 @@ lib/mechanize/form_elements.rb
|
|
19
19
|
lib/mechanize/hpricot.rb
|
20
20
|
lib/mechanize/inspect.rb
|
21
21
|
lib/mechanize/list.rb
|
22
|
-
lib/mechanize/mech_version.rb
|
23
22
|
lib/mechanize/net-overrides/net/http.rb
|
24
23
|
lib/mechanize/net-overrides/net/https.rb
|
25
24
|
lib/mechanize/net-overrides/net/protocol.rb
|
@@ -29,3 +28,87 @@ lib/mechanize/parsers/rexml_page.rb
|
|
29
28
|
lib/mechanize/pluggable_parsers.rb
|
30
29
|
lib/mechanize/rexml.rb
|
31
30
|
setup.rb
|
31
|
+
test/data/htpasswd
|
32
|
+
test/data/server.crt
|
33
|
+
test/data/server.csr
|
34
|
+
test/data/server.key
|
35
|
+
test/data/server.pem
|
36
|
+
test/htdocs/alt_text.html
|
37
|
+
test/htdocs/bad_form_test.html
|
38
|
+
test/htdocs/button.jpg
|
39
|
+
test/htdocs/empty_form.html
|
40
|
+
test/htdocs/file_upload.html
|
41
|
+
test/htdocs/find_link.html
|
42
|
+
test/htdocs/form_multi_select.html
|
43
|
+
test/htdocs/form_multival.html
|
44
|
+
test/htdocs/form_no_action.html
|
45
|
+
test/htdocs/form_no_input_name.html
|
46
|
+
test/htdocs/form_select.html
|
47
|
+
test/htdocs/form_select_all.html
|
48
|
+
test/htdocs/form_select_none.html
|
49
|
+
test/htdocs/form_select_noopts.html
|
50
|
+
test/htdocs/form_set_fields.html
|
51
|
+
test/htdocs/form_test.html
|
52
|
+
test/htdocs/frame_test.html
|
53
|
+
test/htdocs/google.html
|
54
|
+
test/htdocs/iframe_test.html
|
55
|
+
test/htdocs/index.html
|
56
|
+
test/htdocs/link with space.html
|
57
|
+
test/htdocs/no_title_test.html
|
58
|
+
test/htdocs/relative/tc_relative_links.html
|
59
|
+
test/htdocs/tc_bad_links.html
|
60
|
+
test/htdocs/tc_checkboxes.html
|
61
|
+
test/htdocs/tc_encoded_links.html
|
62
|
+
test/htdocs/tc_form_action.html
|
63
|
+
test/htdocs/tc_links.html
|
64
|
+
test/htdocs/tc_no_attributes.html
|
65
|
+
test/htdocs/tc_pretty_print.html
|
66
|
+
test/htdocs/tc_radiobuttons.html
|
67
|
+
test/htdocs/tc_referer.html
|
68
|
+
test/htdocs/tc_relative_links.html
|
69
|
+
test/htdocs/tc_textarea.html
|
70
|
+
test/ssl_server.rb
|
71
|
+
test/tc_authenticate.rb
|
72
|
+
test/tc_bad_links.rb
|
73
|
+
test/tc_checkboxes.rb
|
74
|
+
test/tc_cookie_class.rb
|
75
|
+
test/tc_cookie_jar.rb
|
76
|
+
test/tc_cookies.rb
|
77
|
+
test/tc_encoded_links.rb
|
78
|
+
test/tc_errors.rb
|
79
|
+
test/tc_form_action.rb
|
80
|
+
test/tc_form_as_hash.rb
|
81
|
+
test/tc_form_button.rb
|
82
|
+
test/tc_form_no_inputname.rb
|
83
|
+
test/tc_forms.rb
|
84
|
+
test/tc_frames.rb
|
85
|
+
test/tc_gzipping.rb
|
86
|
+
test/tc_html_unscape_forms.rb
|
87
|
+
test/tc_if_modified_since.rb
|
88
|
+
test/tc_links.rb
|
89
|
+
test/tc_mech.rb
|
90
|
+
test/tc_multi_select.rb
|
91
|
+
test/tc_no_attributes.rb
|
92
|
+
test/tc_page.rb
|
93
|
+
test/tc_pluggable_parser.rb
|
94
|
+
test/tc_post_form.rb
|
95
|
+
test/tc_pretty_print.rb
|
96
|
+
test/tc_proxy.rb
|
97
|
+
test/tc_radiobutton.rb
|
98
|
+
test/tc_referer.rb
|
99
|
+
test/tc_relative_links.rb
|
100
|
+
test/tc_response_code.rb
|
101
|
+
test/tc_save_file.rb
|
102
|
+
test/tc_select.rb
|
103
|
+
test/tc_select_all.rb
|
104
|
+
test/tc_select_none.rb
|
105
|
+
test/tc_select_noopts.rb
|
106
|
+
test/tc_set_fields.rb
|
107
|
+
test/tc_ssl_server.rb
|
108
|
+
test/tc_subclass.rb
|
109
|
+
test/tc_textarea.rb
|
110
|
+
test/tc_upload.rb
|
111
|
+
test/tc_watches.rb
|
112
|
+
test/test_all.rb
|
113
|
+
test/test_includes.rb
|
114
|
+
test/test_servlets.rb
|
data/README.txt
CHANGED
@@ -29,12 +29,22 @@ Original Code:
|
|
29
29
|
Copyright (c) 2005 by Michael Neumann (mneumann@ntecs.de)
|
30
30
|
|
31
31
|
New Code:
|
32
|
-
Copyright (c)
|
32
|
+
Copyright (c) 2007 by Aaron Patterson (aaronp@rubyforge.org)
|
33
33
|
|
34
34
|
This library comes with a shameless plug for employing me
|
35
35
|
(Aaron[http://tenderlovemaking.com/]) programming
|
36
36
|
Ruby, my favorite language!
|
37
37
|
|
38
|
+
== Acknowledgments
|
39
|
+
|
40
|
+
This library was heavily influenced by its namesake in the perl world. A big
|
41
|
+
thanks goes to Andy Lester (andy@petdance.com), the author of the original
|
42
|
+
perl Mechanize which is available here[http://search.cpan.org/~petdance/WWW-Mechanize-1.20/]. Ruby Mechanize would not be around without you!
|
43
|
+
|
44
|
+
Thank you to Michael Neumann for starting the Ruby version. Thanks to everyone
|
45
|
+
who's helped out in various ways. Finally, thank you to the people using this
|
46
|
+
library!
|
47
|
+
|
38
48
|
== License
|
39
49
|
|
40
50
|
This library is distributed under the GPL. Please see the LICENSE[link://files/LICENSE_txt.html] file.
|
data/Rakefile
CHANGED
@@ -1,64 +1,60 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'hoe'
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
|
4
|
+
$LOAD_PATH.unshift File.join(File.dirname(__FILE__), "lib")
|
5
|
+
require 'mechanize'
|
6
|
+
|
7
|
+
class MechHoe < Hoe
|
8
|
+
def define_tasks
|
9
|
+
super
|
10
|
+
|
11
|
+
desc "Tag code"
|
12
|
+
task :tag do |p|
|
13
|
+
abort "Must supply VERSION=x.y.z" unless ENV['VERSION']
|
14
|
+
v = ENV['VERSION'].gsub(/\./, '_')
|
15
|
+
|
16
|
+
rf = RubyForge.new
|
17
|
+
user = rf.userconfig['username']
|
7
18
|
|
8
|
-
|
9
|
-
|
10
|
-
|
19
|
+
baseurl = "svn+ssh://#{user}@rubyforge.org//var/svn/#{name}"
|
20
|
+
sh "svn cp -m 'tagged REL-#{v}' . #{ baseurl }/tags/REL-#{ v }"
|
21
|
+
end
|
22
|
+
|
23
|
+
desc "Branch code"
|
24
|
+
Rake::Task.define_task("branch") do |p|
|
25
|
+
abort "Must supply VERSION=x.y.z" unless ENV['VERSION']
|
26
|
+
v = ENV['VERSION'].split(/\./)[0..1].join('_')
|
27
|
+
|
28
|
+
rf = RubyForge.new
|
29
|
+
user = rf.userconfig['username']
|
30
|
+
|
31
|
+
baseurl = "svn+ssh://#{user}@rubyforge.org/var/svn/#{name}"
|
32
|
+
sh "svn cp -m'branched #{v}' #{baseurl}/trunk #{baseurl}/branches/RB-#{v}"
|
33
|
+
end
|
34
|
+
|
35
|
+
desc "Update SSL Certificate"
|
36
|
+
Rake::Task.define_task('ssl_cert') do |p|
|
37
|
+
sh "openssl genrsa -des3 -out server.key 1024"
|
38
|
+
sh "openssl req -new -key server.key -out server.csr"
|
39
|
+
sh "cp server.key server.key.org"
|
40
|
+
sh "openssl rsa -in server.key.org -out server.key"
|
41
|
+
sh "openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt"
|
42
|
+
sh "cp server.key server.pem"
|
43
|
+
sh "mv server.key server.csr server.crt server.pem test/data/"
|
44
|
+
sh "rm server.key.org"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
11
48
|
|
12
|
-
|
13
|
-
p.rubyforge_name =
|
49
|
+
MechHoe.new('mechanize', WWW::Mechanize::VERSION) do |p|
|
50
|
+
p.rubyforge_name = 'mechanize'
|
14
51
|
p.author = 'Aaron Patterson'
|
15
52
|
p.email = 'aaronp@rubyforge.org'
|
16
53
|
p.summary = "Mechanize provides automated web-browsing"
|
17
54
|
p.description = p.paragraphs_of('README.txt', 3).join("\n\n")
|
18
55
|
p.url = p.paragraphs_of('README.txt', 1).first.strip
|
19
56
|
p.changes = p.paragraphs_of('CHANGELOG.txt', 0..2).join("\n\n")
|
20
|
-
files =
|
21
|
-
(p.test_globs + ['test/**/tc_*.rb',
|
22
|
-
"test/htdocs/**/*.{html,jpg}",
|
23
|
-
'test/data/server.*']).map { |x|
|
24
|
-
Dir.glob(x)
|
25
|
-
}.flatten + ['test/data/htpasswd']
|
26
57
|
p.extra_deps = ['hpricot']
|
27
|
-
p.spec_extras = { :test_files => files }
|
28
|
-
end
|
29
|
-
|
30
|
-
task :update_version do
|
31
|
-
announce "Updating Mechanize Version to #{PKG_VERSION}"
|
32
|
-
File.open("lib/mechanize/mech_version.rb", "w") do |f|
|
33
|
-
f.puts "module WWW"
|
34
|
-
f.puts " class Mechanize"
|
35
|
-
f.puts " Version = '#{PKG_VERSION}'"
|
36
|
-
f.puts " end"
|
37
|
-
f.puts "end"
|
38
|
-
end
|
39
|
-
sh 'svn commit -m"updating version" lib/mechanize/mech_version.rb'
|
40
58
|
end
|
41
59
|
|
42
|
-
desc "Tag code"
|
43
|
-
Rake::Task.define_task("tag") do |p|
|
44
|
-
baseurl = "svn+ssh://#{ENV['USER']}@rubyforge.org//var/svn/#{PKG_NAME}"
|
45
|
-
sh "svn cp -m 'tagged #{ PKG_VERSION }' . #{ baseurl }/tags/REL-#{ PKG_VERSION }"
|
46
|
-
end
|
47
|
-
|
48
|
-
desc "Branch code"
|
49
|
-
Rake::Task.define_task("branch") do |p|
|
50
|
-
baseurl = "svn+ssh://#{ENV['USER']}@rubyforge.org/var/svn/#{PKG_NAME}"
|
51
|
-
sh "svn cp -m 'branched #{ PKG_VERSION }' #{baseurl}/trunk #{ baseurl }/branches/RB-#{ PKG_VERSION }"
|
52
|
-
end
|
53
60
|
|
54
|
-
desc "Update SSL Certificate"
|
55
|
-
Rake::Task.define_task('ssl_cert') do |p|
|
56
|
-
sh "openssl genrsa -des3 -out server.key 1024"
|
57
|
-
sh "openssl req -new -key server.key -out server.csr"
|
58
|
-
sh "cp server.key server.key.org"
|
59
|
-
sh "openssl rsa -in server.key.org -out server.key"
|
60
|
-
sh "openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt"
|
61
|
-
sh "cp server.key server.pem"
|
62
|
-
sh "mv server.key server.csr server.crt server.pem test/data/"
|
63
|
-
sh "rm server.key.org"
|
64
|
-
end
|
data/lib/mechanize.rb
CHANGED
@@ -11,15 +11,24 @@
|
|
11
11
|
unless RUBY_VERSION > "1.8.2"
|
12
12
|
$LOAD_PATH.unshift File.join(File.dirname(__FILE__), "mechanize", "net-overrides")
|
13
13
|
end
|
14
|
+
|
14
15
|
require 'net/http'
|
15
16
|
require 'net/https'
|
16
17
|
|
18
|
+
# Monkey patch for ruby 1.8.4
|
19
|
+
unless RUBY_VERSION > "1.8.4"
|
20
|
+
module Net # :nodoc:
|
21
|
+
class HTTPResponse # :nodoc:
|
22
|
+
CODE_TO_OBJ['500'] = HTTPInternalServerError
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
17
27
|
require 'uri'
|
18
28
|
require 'webrick/httputils'
|
19
29
|
require 'zlib'
|
20
30
|
require 'stringio'
|
21
31
|
require 'mechanize/hpricot'
|
22
|
-
require 'mechanize/mech_version'
|
23
32
|
require 'mechanize/cookie'
|
24
33
|
require 'mechanize/errors'
|
25
34
|
require 'mechanize/pluggable_parsers'
|
@@ -50,15 +59,23 @@ module WWW
|
|
50
59
|
# search_results = agent.submit(search_form)
|
51
60
|
# puts search_results.body
|
52
61
|
class Mechanize
|
62
|
+
##
|
63
|
+
# The version of Mechanize you are using.
|
64
|
+
|
65
|
+
VERSION = '0.6.5'
|
66
|
+
|
67
|
+
##
|
68
|
+
# User Agent aliases
|
53
69
|
AGENT_ALIASES = {
|
54
70
|
'Windows IE 6' => 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)',
|
71
|
+
'Windows IE 7' => 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)',
|
55
72
|
'Windows Mozilla' => 'Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.4b) Gecko/20030516 Mozilla Firebird/0.6',
|
56
73
|
'Mac Safari' => 'Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/418 (KHTML, like Gecko) Safari/417.9.3',
|
57
74
|
'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',
|
58
75
|
'Mac Mozilla' => 'Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.4a) Gecko/20030401',
|
59
76
|
'Linux Mozilla' => 'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20030624',
|
60
77
|
'Linux Konqueror' => 'Mozilla/5.0 (compatible; Konqueror/3; Linux)',
|
61
|
-
'Mechanize' => "WWW-Mechanize/#{
|
78
|
+
'Mechanize' => "WWW-Mechanize/#{VERSION} (http://rubyforge.org/projects/mechanize/)"
|
62
79
|
}
|
63
80
|
|
64
81
|
attr_accessor :cookie_jar
|
@@ -219,9 +236,14 @@ class Mechanize
|
|
219
236
|
|
220
237
|
# Returns whether or not a url has been visited
|
221
238
|
def visited?(url)
|
239
|
+
! visited_page(url).nil?
|
240
|
+
end
|
241
|
+
|
242
|
+
# Returns a visited page for the url passed in, otherwise nil
|
243
|
+
def visited_page(url)
|
222
244
|
url = url.uri if url.respond_to? :uri
|
223
245
|
uri = to_absolute_uri(url).to_s
|
224
|
-
|
246
|
+
@history.reverse.find { |h| h.uri.to_s == uri }
|
225
247
|
end
|
226
248
|
|
227
249
|
# Runs given block, then resets the page history as it was before. self is
|
@@ -262,6 +284,11 @@ class Mechanize
|
|
262
284
|
# Add User-Agent header to request
|
263
285
|
request.add_field('User-Agent', @user_agent) if @user_agent
|
264
286
|
|
287
|
+
# Add If-Modified-Since if page is in history
|
288
|
+
if( (page = visited_page(uri)) && page.response['Last-Modified'] )
|
289
|
+
request.add_field('If-Modified-Since', page.response['Last-Modified'])
|
290
|
+
end
|
291
|
+
|
265
292
|
request.basic_auth(@user, @password) if @user || @password
|
266
293
|
request
|
267
294
|
end
|
@@ -269,14 +296,25 @@ class Mechanize
|
|
269
296
|
private
|
270
297
|
|
271
298
|
def to_absolute_uri(url, cur_page=current_page())
|
272
|
-
url
|
273
|
-
|
274
|
-
|
299
|
+
unless url.is_a? URI
|
300
|
+
url = url.to_s.strip
|
301
|
+
url = URI.parse(
|
302
|
+
Util.html_unescape(
|
303
|
+
url.split(/%[0-9A-Fa-f]{2}/).zip(
|
304
|
+
url.scan(/%[0-9A-Fa-f]{2}/)
|
305
|
+
).map { |x,y|
|
306
|
+
"#{URI.escape(x)}#{y}"
|
307
|
+
}.join('')
|
308
|
+
).gsub(/%23/, '#')
|
309
|
+
)
|
310
|
+
end
|
275
311
|
|
276
312
|
# construct an absolute uri
|
277
313
|
if url.relative?
|
278
314
|
raise 'no history. please specify an absolute URL' unless cur_page.uri
|
279
315
|
url = cur_page.uri + url
|
316
|
+
# Strip initial "/.." bits from the path
|
317
|
+
url.path.sub!(/^(\/\.\.)+(?=\/)/, '')
|
280
318
|
end
|
281
319
|
|
282
320
|
return url
|
@@ -403,21 +441,23 @@ class Mechanize
|
|
403
441
|
response,
|
404
442
|
response_body,
|
405
443
|
response.code
|
406
|
-
)
|
407
|
-
|
408
|
-
|
444
|
+
) { |parser|
|
445
|
+
parser.mech = self if parser.respond_to? :mech=
|
446
|
+
if parser.respond_to?(:watch_for_set=) && @watch_for_set
|
447
|
+
parser.watch_for_set = @watch_for_set
|
448
|
+
end
|
449
|
+
}
|
409
450
|
|
410
451
|
log.info("status: #{ page.code }") if log
|
411
452
|
|
412
|
-
if page.respond_to? :watch_for_set
|
413
|
-
page.watch_for_set = @watch_for_set
|
414
|
-
end
|
415
|
-
|
416
453
|
res_klass = Net::HTTPResponse::CODE_TO_OBJ[page.code.to_s]
|
417
454
|
|
418
455
|
return page if res_klass <= Net::HTTPSuccess
|
419
456
|
|
420
|
-
if res_klass
|
457
|
+
if res_klass == Net::HTTPNotModified
|
458
|
+
log.debug("Got cached page") if log
|
459
|
+
return visited_page(uri)
|
460
|
+
elsif res_klass <= Net::HTTPRedirection
|
421
461
|
return page unless follow_redirect?
|
422
462
|
log.info("follow redirect to: #{ response['Location'] }") if log
|
423
463
|
abs_uri = to_absolute_uri(response['Location'].to_s, page)
|
@@ -444,17 +484,31 @@ class Mechanize
|
|
444
484
|
|
445
485
|
def add_to_history(page)
|
446
486
|
@history.push(page)
|
447
|
-
if @max_history and @history.
|
448
|
-
|
449
|
-
|
487
|
+
if @max_history and @history.length > @max_history
|
488
|
+
while @history.length > @max_history
|
489
|
+
@history[0] = nil
|
490
|
+
@history.shift
|
491
|
+
end
|
450
492
|
end
|
451
493
|
end
|
452
494
|
|
495
|
+
# :stopdoc:
|
453
496
|
class Util
|
454
497
|
def self.html_unescape(s)
|
455
|
-
s
|
498
|
+
return s unless s
|
499
|
+
s.gsub(/&(\w+|#[0-9]+);/) { |match|
|
500
|
+
number = case match
|
501
|
+
when /&(\w+);/
|
502
|
+
Hpricot::NamedCharacters[$1]
|
503
|
+
when /&#([0-9]+);/
|
504
|
+
$1.to_i
|
505
|
+
end
|
506
|
+
|
507
|
+
number ? (number.chr rescue match) : match
|
508
|
+
}
|
456
509
|
end
|
457
510
|
end
|
511
|
+
# :startdoc:
|
458
512
|
end
|
459
513
|
|
460
514
|
end # module WWW
|
data/lib/mechanize/errors.rb
CHANGED
data/lib/mechanize/form.rb
CHANGED
@@ -26,6 +26,8 @@ module WWW
|
|
26
26
|
|
27
27
|
attr_reader :fields, :buttons, :file_uploads, :radiobuttons, :checkboxes
|
28
28
|
attr_reader :enctype
|
29
|
+
|
30
|
+
alias :elements :fields
|
29
31
|
|
30
32
|
def initialize(form_node, elements_node)
|
31
33
|
@form_node, @elements_node = form_node, elements_node
|
@@ -105,6 +107,11 @@ module WWW
|
|
105
107
|
end
|
106
108
|
end
|
107
109
|
|
110
|
+
# Removes all fields with name +field_name+.
|
111
|
+
def delete_field!(field_name)
|
112
|
+
@fields.delete_if{ |f| f.name == field_name}
|
113
|
+
end
|
114
|
+
|
108
115
|
private
|
109
116
|
def parse
|
110
117
|
@fields = WWW::Mechanize::List.new
|
@@ -10,7 +10,12 @@ module WWW
|
|
10
10
|
attr_accessor :name, :value
|
11
11
|
|
12
12
|
def initialize(name, value)
|
13
|
-
@name
|
13
|
+
@name = Util.html_unescape(name)
|
14
|
+
@value = if value.is_a? String
|
15
|
+
Util.html_unescape(value)
|
16
|
+
else
|
17
|
+
value
|
18
|
+
end
|
14
19
|
end
|
15
20
|
|
16
21
|
def query_value
|
@@ -24,7 +29,6 @@ module WWW
|
|
24
29
|
# of the file.
|
25
30
|
# See the example in EXAMPLES[link://files/EXAMPLES_txt.html]
|
26
31
|
class FileUpload < Field
|
27
|
-
attr_accessor :name # Field name
|
28
32
|
attr_accessor :file_name # File name
|
29
33
|
attr_accessor :mime_type # Mime Type (Optional)
|
30
34
|
|
@@ -32,7 +36,7 @@ module WWW
|
|
32
36
|
alias :file_data= :value=
|
33
37
|
|
34
38
|
def initialize(name, file_name)
|
35
|
-
@file_name = file_name
|
39
|
+
@file_name = Util.html_unescape(file_name)
|
36
40
|
@file_data = nil
|
37
41
|
super(name, @file_data)
|
38
42
|
end
|
@@ -215,7 +219,7 @@ module WWW
|
|
215
219
|
def initialize(node, select_list)
|
216
220
|
node.attributes ||= {}
|
217
221
|
@text = node.all_text
|
218
|
-
@value = node.attributes['value']
|
222
|
+
@value = Util.html_unescape(node.attributes['value'])
|
219
223
|
@selected = node.attributes.has_key?('selected') ? true : false
|
220
224
|
@select_list = select_list # The select list this option belongs to
|
221
225
|
end
|
data/lib/mechanize/hpricot.rb
CHANGED
data/lib/mechanize/page.rb
CHANGED
@@ -18,45 +18,40 @@ module WWW
|
|
18
18
|
class Page < File
|
19
19
|
extend Forwardable
|
20
20
|
|
21
|
-
attr_reader :
|
21
|
+
attr_reader :parser, :title, :watch_for_set
|
22
22
|
attr_reader :frames, :iframes, :links, :forms, :meta, :watches
|
23
23
|
attr_accessor :mech
|
24
24
|
|
25
|
+
alias :root :parser
|
26
|
+
|
25
27
|
def initialize(uri=nil, response=nil, body=nil, code=nil, mech=nil)
|
26
28
|
super(uri, response, body, code)
|
27
|
-
@watch_for_set
|
28
|
-
@mech
|
29
|
-
|
30
|
-
yield self if block_given?
|
29
|
+
@watch_for_set ||= {}
|
30
|
+
@mech ||= mech
|
31
31
|
|
32
32
|
raise Mechanize::ContentTypeError.new(response['content-type']) unless
|
33
33
|
content_type() =~ /^text\/html/
|
34
34
|
|
35
35
|
# construct parser and feed with HTML
|
36
36
|
if body && response
|
37
|
-
@
|
37
|
+
@parser ||= Hpricot.parse(body)
|
38
38
|
parse_html
|
39
39
|
end
|
40
40
|
end
|
41
41
|
|
42
|
-
# Get the response header
|
43
|
-
def header
|
44
|
-
@response
|
45
|
-
end
|
46
|
-
|
47
42
|
# Get the content type
|
48
43
|
def content_type
|
49
44
|
@response['content-type']
|
50
45
|
end
|
51
46
|
|
52
47
|
# Search through the page like HPricot
|
53
|
-
def_delegator :@
|
54
|
-
def_delegator :@
|
55
|
-
def_delegator :@
|
48
|
+
def_delegator :@parser, :search, :search
|
49
|
+
def_delegator :@parser, :/, :/
|
50
|
+
def_delegator :@parser, :at, :at
|
56
51
|
|
57
52
|
def watch_for_set=(obj)
|
58
53
|
@watch_for_set = obj
|
59
|
-
parse_html if @body
|
54
|
+
parse_html if @body && @watch_for_set
|
60
55
|
end
|
61
56
|
|
62
57
|
def form(name)
|
@@ -76,24 +71,24 @@ module WWW
|
|
76
71
|
@watches = {}
|
77
72
|
|
78
73
|
# Set the title
|
79
|
-
@title = if (@
|
80
|
-
(@
|
74
|
+
@title = if (@parser/'title').text.length > 0
|
75
|
+
(@parser/'title').text
|
81
76
|
end
|
82
77
|
|
83
78
|
# Find all the form tags
|
84
|
-
(@
|
79
|
+
(@parser/'form').each do |html_form|
|
85
80
|
form = Form.new(html_form, @mech, self)
|
86
81
|
form.action ||= @uri
|
87
82
|
@forms << form
|
88
83
|
end
|
89
84
|
|
90
85
|
# Find all the 'a' tags
|
91
|
-
(@
|
86
|
+
(@parser/'a').each do |node|
|
92
87
|
@links << Link.new(node, @mech, self)
|
93
88
|
end
|
94
89
|
|
95
90
|
# Find all 'meta' tags
|
96
|
-
(@
|
91
|
+
(@parser/'meta').each do |node|
|
97
92
|
next if node.attributes.nil?
|
98
93
|
next unless node.attributes.has_key? 'http-equiv'
|
99
94
|
next unless node.attributes.has_key? 'content'
|
@@ -108,19 +103,19 @@ module WWW
|
|
108
103
|
end
|
109
104
|
|
110
105
|
# Find all 'frame' tags
|
111
|
-
(@
|
106
|
+
(@parser/'frame').each do |node|
|
112
107
|
@frames << Frame.new(node, @mech, self)
|
113
108
|
end
|
114
109
|
|
115
110
|
# Find all 'iframe' tags
|
116
|
-
(@
|
111
|
+
(@parser/'iframe').each do |node|
|
117
112
|
@iframes << Frame.new(node, @mech, self)
|
118
113
|
end
|
119
114
|
|
120
115
|
# Find all watch tags
|
121
116
|
unless @watch_for_set.nil?
|
122
117
|
@watch_for_set.each do |key, klass|
|
123
|
-
(@
|
118
|
+
(@parser/key).each do |node|
|
124
119
|
@watches[key] ||= []
|
125
120
|
@watches[key] << (klass ? klass.new(node) : node)
|
126
121
|
end
|
@@ -18,11 +18,20 @@ module WWW
|
|
18
18
|
#
|
19
19
|
class File
|
20
20
|
attr_accessor :uri, :response, :body, :code
|
21
|
+
alias :header :response
|
21
22
|
|
22
23
|
alias :content :body
|
23
24
|
|
24
25
|
def initialize(uri=nil, response=nil, body=nil, code=nil)
|
25
|
-
@uri, @
|
26
|
+
@uri, @body, @code = uri, body, code
|
27
|
+
# Copy the headers in to a hash to prevent memory leaks
|
28
|
+
if response
|
29
|
+
@response = Headers.new
|
30
|
+
response.each { |k,v|
|
31
|
+
@response[k] = v
|
32
|
+
}
|
33
|
+
end
|
34
|
+
yield self if block_given?
|
26
35
|
end
|
27
36
|
|
28
37
|
# Use this method to save the content of this object to filename
|
@@ -50,7 +59,7 @@ module WWW
|
|
50
59
|
attr_reader :filename
|
51
60
|
|
52
61
|
def initialize(uri=nil, response=nil, body=nil, code=nil)
|
53
|
-
|
62
|
+
super(uri, response, body, code)
|
54
63
|
path = uri.path.empty? ? 'index.html' : uri.path.gsub(/^[\/]*/, '')
|
55
64
|
path += 'index.html' if path =~ /\/$/
|
56
65
|
|
@@ -154,5 +163,14 @@ module WWW
|
|
154
163
|
@parsers[content_type] = klass
|
155
164
|
end
|
156
165
|
end
|
166
|
+
|
167
|
+
class Headers < Hash
|
168
|
+
def [](key)
|
169
|
+
super(key.downcase)
|
170
|
+
end
|
171
|
+
def []=(key, value)
|
172
|
+
super(key.downcase, value)
|
173
|
+
end
|
174
|
+
end
|
157
175
|
end
|
158
176
|
end
|
data/lib/mechanize/rexml.rb
CHANGED
data/test/ssl_server.rb
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'webrick'
|
2
|
+
require 'webrick/https'
|
3
|
+
require 'servlets'
|
4
|
+
require 'logger'
|
5
|
+
|
6
|
+
base_dir = FileTest.exists?(Dir::pwd + '/test') ? Dir::pwd + '/test' : Dir::pwd
|
7
|
+
|
8
|
+
s = WEBrick::HTTPServer.new(
|
9
|
+
:Port => 2002,
|
10
|
+
:DocumentRoot => base_dir + "/htdocs",
|
11
|
+
:SSLEnable => true,
|
12
|
+
:SSLVerifyClient => OpenSSL::SSL::VERIFY_NONE,
|
13
|
+
:SSLCertificate => OpenSSL::X509::Certificate.new(
|
14
|
+
File.read("data/server.crt")
|
15
|
+
),
|
16
|
+
:SSLPrivateKey => OpenSSL::PKey::RSA.new(
|
17
|
+
File.read("data/server.pem")
|
18
|
+
),
|
19
|
+
:Logger => Logger.new(nil),
|
20
|
+
:AccessLog => Logger.new(nil)
|
21
|
+
)
|
22
|
+
s.mount("/one_cookie", OneCookieTest)
|
23
|
+
s.mount("/one_cookie_no_space", OneCookieNoSpacesTest)
|
24
|
+
s.mount("/many_cookies", ManyCookiesTest)
|
25
|
+
s.mount("/many_cookies_as_string", ManyCookiesAsStringTest)
|
26
|
+
s.mount("/send_cookies", SendCookiesTest)
|
27
|
+
s.mount("/form_post", FormTest)
|
28
|
+
s.mount("/form post", FormTest)
|
29
|
+
s.mount("/response_code", ResponseCodeTest)
|
30
|
+
s.mount("/file_upload", FileUploadTest)
|
31
|
+
s.mount("/bad_content_type", BadContentTypeTest)
|
32
|
+
s.mount("/content_type_test", ContentTypeTest)
|
33
|
+
|
34
|
+
htpasswd = WEBrick::HTTPAuth::Htpasswd.new(base_dir + '/data/htpasswd')
|
35
|
+
auth = WEBrick::HTTPAuth::BasicAuth.new(
|
36
|
+
:UserDB => htpasswd,
|
37
|
+
:Realm => 'mechanize',
|
38
|
+
:Logger => Logger.new(nil),
|
39
|
+
:AccessLog => Logger.new(nil)
|
40
|
+
)
|
41
|
+
s.mount_proc('/htpasswd_auth') { |req, res|
|
42
|
+
auth.authenticate(req, res)
|
43
|
+
res.body = "You are authenticated"
|
44
|
+
}
|
45
|
+
|
46
|
+
trap("INT") { s.stop }
|
47
|
+
|
48
|
+
s.start
|
data/test/tc_cookie_class.rb
CHANGED
@@ -23,6 +23,14 @@ module Enumerable
|
|
23
23
|
end
|
24
24
|
|
25
25
|
class CookieClassTest < Test::Unit::TestCase
|
26
|
+
def silently
|
27
|
+
warn_level = $VERBOSE
|
28
|
+
$VERBOSE = false
|
29
|
+
res = yield
|
30
|
+
$VERBOSE = warn_level
|
31
|
+
res
|
32
|
+
end
|
33
|
+
|
26
34
|
def test_parse_dates
|
27
35
|
url = URI.parse('http://localhost/')
|
28
36
|
|
@@ -47,9 +55,11 @@ class CookieClassTest < Test::Unit::TestCase
|
|
47
55
|
|
48
56
|
dates.each do |date|
|
49
57
|
cookie = "PREF=1; expires=#{date}"
|
50
|
-
|
51
|
-
|
52
|
-
|
58
|
+
silently do
|
59
|
+
WWW::Mechanize::Cookie.parse(url, cookie) { |cookie|
|
60
|
+
assert_equal(true, cookie.expires < yesterday)
|
61
|
+
}
|
62
|
+
end
|
53
63
|
end
|
54
64
|
end
|
55
65
|
|
@@ -76,11 +86,13 @@ class CookieClassTest < Test::Unit::TestCase
|
|
76
86
|
"20/06/95 21:07",
|
77
87
|
]
|
78
88
|
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
89
|
+
silently do
|
90
|
+
dates.each do |date|
|
91
|
+
cookie = "PREF=1; expires=#{date}"
|
92
|
+
WWW::Mechanize::Cookie.parse(url, cookie) { |cookie|
|
93
|
+
assert_equal(true, cookie.expires > (Time.now - 86400))
|
94
|
+
}
|
95
|
+
end
|
84
96
|
end
|
85
97
|
end
|
86
98
|
|
@@ -120,6 +132,43 @@ class CookieClassTest < Test::Unit::TestCase
|
|
120
132
|
end
|
121
133
|
end
|
122
134
|
|
135
|
+
def test_parse_valid_cookie_empty_value
|
136
|
+
url = URI.parse('http://rubyforge.org/')
|
137
|
+
cookie_params = {}
|
138
|
+
cookie_params['expires'] = 'expires=Sun, 27-Sep-2037 00:00:00 GMT'
|
139
|
+
cookie_params['path'] = 'path=/'
|
140
|
+
cookie_params['domain'] = 'domain=.rubyforge.org'
|
141
|
+
cookie_params['httponly'] = 'HttpOnly'
|
142
|
+
cookie_value = '12345%7D='
|
143
|
+
|
144
|
+
expires = Time.parse('Sun, 27-Sep-2037 00:00:00 GMT')
|
145
|
+
|
146
|
+
cookie_params.keys.combine.each do |c|
|
147
|
+
cookie_text = "#{cookie_value}; "
|
148
|
+
c.each_with_index do |key, idx|
|
149
|
+
if idx == (c.length - 1)
|
150
|
+
cookie_text << "#{cookie_params[key]}"
|
151
|
+
else
|
152
|
+
cookie_text << "#{cookie_params[key]}; "
|
153
|
+
end
|
154
|
+
end
|
155
|
+
cookie = nil
|
156
|
+
WWW::Mechanize::Cookie.parse(url, cookie_text) { |p_cookie| cookie = p_cookie }
|
157
|
+
assert_not_nil(cookie)
|
158
|
+
assert_equal('12345%7D=', cookie.to_s)
|
159
|
+
assert_equal('', cookie.value)
|
160
|
+
assert_equal('/', cookie.path)
|
161
|
+
assert_equal('rubyforge.org', cookie.domain)
|
162
|
+
|
163
|
+
# if expires was set, make sure we parsed it
|
164
|
+
if c.find { |k| k == 'expires' }
|
165
|
+
assert_equal(expires, cookie.expires)
|
166
|
+
else
|
167
|
+
assert_nil(cookie.expires)
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
123
172
|
# If no path was given, use the one from the URL
|
124
173
|
def test_cookie_using_url_path
|
125
174
|
url = URI.parse('http://rubyforge.org/login')
|
data/test/tc_cookie_jar.rb
CHANGED
@@ -43,6 +43,33 @@ class CookieJarTest < Test::Unit::TestCase
|
|
43
43
|
assert_equal(2, jar.cookies(url2).length)
|
44
44
|
end
|
45
45
|
|
46
|
+
def test_empty_value
|
47
|
+
values = { :name => 'Foo',
|
48
|
+
:value => '',
|
49
|
+
:path => '/',
|
50
|
+
:expires => Time.now + (10 * 86400),
|
51
|
+
:domain => 'rubyforge.org'
|
52
|
+
}
|
53
|
+
url = URI.parse('http://rubyforge.org/')
|
54
|
+
|
55
|
+
jar = WWW::Mechanize::CookieJar.new
|
56
|
+
assert_equal(0, jar.cookies(url).length)
|
57
|
+
|
58
|
+
# Add one cookie with an expiration date in the future
|
59
|
+
cookie = cookie_from_hash(values)
|
60
|
+
jar.add(url, cookie)
|
61
|
+
assert_equal(1, jar.cookies(url).length)
|
62
|
+
|
63
|
+
jar.add(url, cookie_from_hash( values.merge( :domain => 'RuByForge.Org',
|
64
|
+
:name => 'aaron'
|
65
|
+
) ) )
|
66
|
+
|
67
|
+
assert_equal(2, jar.cookies(url).length)
|
68
|
+
|
69
|
+
url2 = URI.parse('http://RuByFoRgE.oRg/')
|
70
|
+
assert_equal(2, jar.cookies(url2).length)
|
71
|
+
end
|
72
|
+
|
46
73
|
def test_add_future_cookies
|
47
74
|
values = { :name => 'Foo',
|
48
75
|
:value => 'Bar',
|
data/test/tc_forms.rb
CHANGED
@@ -500,6 +500,18 @@ class FormsMechTest < Test::Unit::TestCase
|
|
500
500
|
assert_not_nil(f)
|
501
501
|
assert_equal(number_of_fields + 1, form.fields.length)
|
502
502
|
end
|
503
|
+
|
504
|
+
def test_delete_field
|
505
|
+
page = @agent.get("http://localhost:#{PORT}/form_multival.html")
|
506
|
+
form = page.forms.name('post_form').first
|
507
|
+
|
508
|
+
assert_not_nil(form)
|
509
|
+
number_of_fields = form.fields.length
|
510
|
+
|
511
|
+
form.delete_field!('first')
|
512
|
+
assert_nil(form['first'])
|
513
|
+
assert_equal(number_of_fields - 2, form.fields.length)
|
514
|
+
end
|
503
515
|
|
504
516
|
def test_has_field
|
505
517
|
page = @agent.get("http://localhost:#{PORT}/form_multival.html")
|
@@ -0,0 +1,46 @@
|
|
1
|
+
$:.unshift File.join(File.dirname(__FILE__), "..", "lib")
|
2
|
+
|
3
|
+
require 'test/unit'
|
4
|
+
require 'rubygems'
|
5
|
+
require 'mechanize'
|
6
|
+
require 'test_includes'
|
7
|
+
|
8
|
+
class TestCheckBoxes < Test::Unit::TestCase
|
9
|
+
include TestMethods
|
10
|
+
|
11
|
+
def test_field
|
12
|
+
f = WWW::Mechanize::Field.new('a&b', 'a&b')
|
13
|
+
assert_equal('a&b', f.name)
|
14
|
+
assert_equal('a&b', f.value)
|
15
|
+
|
16
|
+
f = WWW::Mechanize::Field.new('a&b', 'a&b')
|
17
|
+
assert_equal('a&b', f.name)
|
18
|
+
assert_equal('a&b', f.value)
|
19
|
+
|
20
|
+
f = WWW::Mechanize::Field.new('a&b', 'a&b')
|
21
|
+
assert_equal('a&b', f.name)
|
22
|
+
assert_equal('a&b', f.value)
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_file_upload
|
26
|
+
f = WWW::Mechanize::FileUpload.new('a&b', 'a&b')
|
27
|
+
assert_equal('a&b', f.name)
|
28
|
+
assert_equal('a&b', f.file_name)
|
29
|
+
|
30
|
+
f = WWW::Mechanize::FileUpload.new('a&b', 'a&b')
|
31
|
+
assert_equal('a&b', f.name)
|
32
|
+
assert_equal('a&b', f.file_name)
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_image_button
|
36
|
+
f = WWW::Mechanize::ImageButton.new('a&b', 'a&b')
|
37
|
+
assert_equal('a&b', f.name)
|
38
|
+
assert_equal('a&b', f.value)
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_radio_button
|
42
|
+
f = WWW::Mechanize::RadioButton.new('a&b', 'a&b', nil, nil)
|
43
|
+
assert_equal('a&b', f.name)
|
44
|
+
assert_equal('a&b', f.value)
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
$:.unshift File.join(File.dirname(__FILE__), "..", "lib")
|
2
|
+
|
3
|
+
require 'test/unit'
|
4
|
+
require 'rubygems'
|
5
|
+
require 'mechanize'
|
6
|
+
require 'test_includes'
|
7
|
+
|
8
|
+
class TestIfModifiedSince < Test::Unit::TestCase
|
9
|
+
def setup
|
10
|
+
@agent = WWW::Mechanize.new
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_get_twice
|
14
|
+
assert_equal(0, @agent.history.length)
|
15
|
+
page = @agent.get('http://localhost/if_modified_since')
|
16
|
+
assert_match(/You did not send/, page.body)
|
17
|
+
|
18
|
+
assert_equal(1, @agent.history.length)
|
19
|
+
page2 = @agent.get('http://localhost/if_modified_since')
|
20
|
+
|
21
|
+
assert_equal(2, @agent.history.length)
|
22
|
+
assert_equal(page.object_id, page2.object_id)
|
23
|
+
assert_match(/You did not send/, page.body)
|
24
|
+
end
|
25
|
+
end
|
data/test/tc_mech.rb
CHANGED
@@ -13,6 +13,10 @@ class TestMechMethods < Test::Unit::TestCase
|
|
13
13
|
@agent = WWW::Mechanize.new
|
14
14
|
end
|
15
15
|
|
16
|
+
def test_weird_url
|
17
|
+
@agent.get('http://localhost/?action=bing&bang=boom=1|a=|b=|c=')
|
18
|
+
end
|
19
|
+
|
16
20
|
def test_history
|
17
21
|
0.upto(25) do |i|
|
18
22
|
assert_equal(i, @agent.history.size)
|
@@ -24,6 +28,8 @@ class TestMechMethods < Test::Unit::TestCase
|
|
24
28
|
@agent.history.last.uri.to_s)
|
25
29
|
assert_equal("http://localhost:#{PORT}/",
|
26
30
|
@agent.history[-2].uri.to_s)
|
31
|
+
assert_equal("http://localhost:#{PORT}/",
|
32
|
+
@agent.history[-2].uri.to_s)
|
27
33
|
|
28
34
|
assert_equal(true, @agent.visited?("http://localhost:#{PORT}/"))
|
29
35
|
assert_equal(true, @agent.visited?("/form_test.html"))
|
@@ -32,6 +38,16 @@ class TestMechMethods < Test::Unit::TestCase
|
|
32
38
|
|
33
39
|
end
|
34
40
|
|
41
|
+
def test_visited
|
42
|
+
@agent.get("http://localhost/content_type_test?ct=application/pdf")
|
43
|
+
assert_equal(true,
|
44
|
+
@agent.visited?("http://localhost/content_type_test?ct=application/pdf"))
|
45
|
+
assert_equal(false,
|
46
|
+
@agent.visited?("http://localhost/content_type_test"))
|
47
|
+
assert_equal(false,
|
48
|
+
@agent.visited?("http://localhost/content_type_test?ct=text/html"))
|
49
|
+
end
|
50
|
+
|
35
51
|
def test_max_history
|
36
52
|
@agent.max_history = 10
|
37
53
|
0.upto(10) do |i|
|
@@ -45,6 +61,23 @@ class TestMechMethods < Test::Unit::TestCase
|
|
45
61
|
end
|
46
62
|
end
|
47
63
|
|
64
|
+
def test_max_history_order
|
65
|
+
@agent.max_history = 2
|
66
|
+
assert_equal(0, @agent.history.length)
|
67
|
+
|
68
|
+
@agent.get('http://localhost/form_test.html')
|
69
|
+
assert_equal(1, @agent.history.length)
|
70
|
+
|
71
|
+
@agent.get('http://localhost/empty_form.html')
|
72
|
+
assert_equal(2, @agent.history.length)
|
73
|
+
|
74
|
+
@agent.get('http://localhost/tc_checkboxes.html')
|
75
|
+
assert_equal(2, @agent.history.length)
|
76
|
+
assert_equal('http://localhost/empty_form.html', @agent.history[0].uri.to_s)
|
77
|
+
assert_equal('http://localhost/tc_checkboxes.html',
|
78
|
+
@agent.history[1].uri.to_s)
|
79
|
+
end
|
80
|
+
|
48
81
|
def test_back_button
|
49
82
|
0.upto(5) do |i|
|
50
83
|
assert_equal(i, @agent.history.size)
|
data/test/tc_relative_links.rb
CHANGED
@@ -18,6 +18,13 @@ class TestRelativeLinks < Test::Unit::TestCase
|
|
18
18
|
assert_equal('http://localhost/tc_relative_links.html', @agent.current_page.uri.to_s)
|
19
19
|
end
|
20
20
|
|
21
|
+
def test_too_many_dots
|
22
|
+
@page = @agent.get("http://localhost/relative/tc_relative_links.html")
|
23
|
+
page = @page.links.text('too many dots').click
|
24
|
+
assert_not_nil(page)
|
25
|
+
assert_equal('http://localhost/tc_relative_links.html', page.uri.to_s)
|
26
|
+
end
|
27
|
+
|
21
28
|
def test_go_forward
|
22
29
|
@page = @agent.get("http://localhost/tc_relative_links.html")
|
23
30
|
@page = @page.links.first.click
|
data/test/test_all.rb
CHANGED
data/test/test_includes.rb
CHANGED
data/test/test_servlets.rb
CHANGED
@@ -16,6 +16,27 @@ class RefererServlet < WEBrick::HTTPServlet::AbstractServlet
|
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
19
|
+
class ModifiedSinceServlet < WEBrick::HTTPServlet::AbstractServlet
|
20
|
+
def do_GET(req, res)
|
21
|
+
s_time = 'Fri, 04 May 2001 00:00:38 GMT'
|
22
|
+
|
23
|
+
my_time = Time.parse(s_time)
|
24
|
+
|
25
|
+
if req['If-Modified-Since']
|
26
|
+
your_time = Time.parse(req['If-Modified-Since'])
|
27
|
+
if my_time > your_time
|
28
|
+
res.body = 'This page was updated since you requested'
|
29
|
+
else
|
30
|
+
res.status = 304
|
31
|
+
end
|
32
|
+
else
|
33
|
+
res.body = 'You did not send an If-Modified-Since header'
|
34
|
+
end
|
35
|
+
|
36
|
+
res['Last-Modified'] = s_time
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
19
40
|
class GzipServlet < WEBrick::HTTPServlet::AbstractServlet
|
20
41
|
def do_GET(req, res)
|
21
42
|
if req['Accept-Encoding'] =~ /gzip/
|
metadata
CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.0
|
|
3
3
|
specification_version: 1
|
4
4
|
name: mechanize
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.6.
|
7
|
-
date:
|
6
|
+
version: 0.6.5
|
7
|
+
date: 2007-02-26 00:00:00 -08:00
|
8
8
|
summary: Mechanize provides automated web-browsing
|
9
9
|
require_paths:
|
10
10
|
- lib
|
@@ -54,7 +54,6 @@ files:
|
|
54
54
|
- lib/mechanize/hpricot.rb
|
55
55
|
- lib/mechanize/inspect.rb
|
56
56
|
- lib/mechanize/list.rb
|
57
|
-
- lib/mechanize/mech_version.rb
|
58
57
|
- lib/mechanize/net-overrides/net/http.rb
|
59
58
|
- lib/mechanize/net-overrides/net/https.rb
|
60
59
|
- lib/mechanize/net-overrides/net/protocol.rb
|
@@ -64,10 +63,46 @@ files:
|
|
64
63
|
- lib/mechanize/pluggable_parsers.rb
|
65
64
|
- lib/mechanize/rexml.rb
|
66
65
|
- setup.rb
|
67
|
-
|
68
|
-
- test/
|
69
|
-
- test/
|
70
|
-
- test/
|
66
|
+
- test/data/htpasswd
|
67
|
+
- test/data/server.crt
|
68
|
+
- test/data/server.csr
|
69
|
+
- test/data/server.key
|
70
|
+
- test/data/server.pem
|
71
|
+
- test/htdocs/alt_text.html
|
72
|
+
- test/htdocs/bad_form_test.html
|
73
|
+
- test/htdocs/button.jpg
|
74
|
+
- test/htdocs/empty_form.html
|
75
|
+
- test/htdocs/file_upload.html
|
76
|
+
- test/htdocs/find_link.html
|
77
|
+
- test/htdocs/form_multi_select.html
|
78
|
+
- test/htdocs/form_multival.html
|
79
|
+
- test/htdocs/form_no_action.html
|
80
|
+
- test/htdocs/form_no_input_name.html
|
81
|
+
- test/htdocs/form_select.html
|
82
|
+
- test/htdocs/form_select_all.html
|
83
|
+
- test/htdocs/form_select_none.html
|
84
|
+
- test/htdocs/form_select_noopts.html
|
85
|
+
- test/htdocs/form_set_fields.html
|
86
|
+
- test/htdocs/form_test.html
|
87
|
+
- test/htdocs/frame_test.html
|
88
|
+
- test/htdocs/google.html
|
89
|
+
- test/htdocs/iframe_test.html
|
90
|
+
- test/htdocs/index.html
|
91
|
+
- test/htdocs/link with space.html
|
92
|
+
- test/htdocs/no_title_test.html
|
93
|
+
- test/htdocs/relative/tc_relative_links.html
|
94
|
+
- test/htdocs/tc_bad_links.html
|
95
|
+
- test/htdocs/tc_checkboxes.html
|
96
|
+
- test/htdocs/tc_encoded_links.html
|
97
|
+
- test/htdocs/tc_form_action.html
|
98
|
+
- test/htdocs/tc_links.html
|
99
|
+
- test/htdocs/tc_no_attributes.html
|
100
|
+
- test/htdocs/tc_pretty_print.html
|
101
|
+
- test/htdocs/tc_radiobuttons.html
|
102
|
+
- test/htdocs/tc_referer.html
|
103
|
+
- test/htdocs/tc_relative_links.html
|
104
|
+
- test/htdocs/tc_textarea.html
|
105
|
+
- test/ssl_server.rb
|
71
106
|
- test/tc_authenticate.rb
|
72
107
|
- test/tc_bad_links.rb
|
73
108
|
- test/tc_checkboxes.rb
|
@@ -83,6 +118,8 @@ test_files:
|
|
83
118
|
- test/tc_forms.rb
|
84
119
|
- test/tc_frames.rb
|
85
120
|
- test/tc_gzipping.rb
|
121
|
+
- test/tc_html_unscape_forms.rb
|
122
|
+
- test/tc_if_modified_since.rb
|
86
123
|
- test/tc_links.rb
|
87
124
|
- test/tc_mech.rb
|
88
125
|
- test/tc_multi_select.rb
|
@@ -107,45 +144,11 @@ test_files:
|
|
107
144
|
- test/tc_textarea.rb
|
108
145
|
- test/tc_upload.rb
|
109
146
|
- test/tc_watches.rb
|
110
|
-
- test/
|
111
|
-
- test/
|
112
|
-
- test/
|
113
|
-
|
114
|
-
- test/
|
115
|
-
- test/htdocs/form_multi_select.html
|
116
|
-
- test/htdocs/form_multival.html
|
117
|
-
- test/htdocs/form_no_action.html
|
118
|
-
- test/htdocs/form_no_input_name.html
|
119
|
-
- test/htdocs/form_select.html
|
120
|
-
- test/htdocs/form_select_all.html
|
121
|
-
- test/htdocs/form_select_none.html
|
122
|
-
- test/htdocs/form_select_noopts.html
|
123
|
-
- test/htdocs/form_set_fields.html
|
124
|
-
- test/htdocs/form_test.html
|
125
|
-
- test/htdocs/frame_test.html
|
126
|
-
- test/htdocs/google.html
|
127
|
-
- test/htdocs/iframe_test.html
|
128
|
-
- test/htdocs/index.html
|
129
|
-
- test/htdocs/link with space.html
|
130
|
-
- test/htdocs/no_title_test.html
|
131
|
-
- test/htdocs/tc_bad_links.html
|
132
|
-
- test/htdocs/tc_checkboxes.html
|
133
|
-
- test/htdocs/tc_encoded_links.html
|
134
|
-
- test/htdocs/tc_form_action.html
|
135
|
-
- test/htdocs/tc_links.html
|
136
|
-
- test/htdocs/tc_no_attributes.html
|
137
|
-
- test/htdocs/tc_pretty_print.html
|
138
|
-
- test/htdocs/tc_radiobuttons.html
|
139
|
-
- test/htdocs/tc_referer.html
|
140
|
-
- test/htdocs/tc_relative_links.html
|
141
|
-
- test/htdocs/tc_textarea.html
|
142
|
-
- test/htdocs/relative/tc_relative_links.html
|
143
|
-
- test/htdocs/button.jpg
|
144
|
-
- test/data/server.crt
|
145
|
-
- test/data/server.csr
|
146
|
-
- test/data/server.key
|
147
|
-
- test/data/server.pem
|
148
|
-
- test/data/htpasswd
|
147
|
+
- test/test_all.rb
|
148
|
+
- test/test_includes.rb
|
149
|
+
- test/test_servlets.rb
|
150
|
+
test_files:
|
151
|
+
- test/test_all.rb
|
149
152
|
rdoc_options: []
|
150
153
|
extra_rdoc_files: []
|
151
154
|
executables: []
|
@@ -161,4 +164,14 @@ dependencies:
|
|
161
164
|
- ">"
|
162
165
|
- !ruby/object:Gem::Version
|
163
166
|
version: 0.0.0
|
167
|
+
version:
|
168
|
+
- !ruby/object:Gem::Dependency
|
169
|
+
name: hoe
|
170
|
+
version_requirement:
|
171
|
+
version_requirements: !ruby/object:Gem::Version::Requirement
|
172
|
+
requirements:
|
173
|
+
-
|
174
|
+
- ">="
|
175
|
+
- !ruby/object:Gem::Version
|
176
|
+
version: 1.2.0
|
164
177
|
version:
|