diamond-mechanize 2.1 → 2.2
Sign up to get free protection for your applications and to get access to all the features.
- metadata +222 -167
- data/Rakefile +0 -49
- data/lib/mechanize/content_type_error.rb +0 -13
- data/lib/mechanize/cookie.rb +0 -232
- data/lib/mechanize/cookie_jar.rb +0 -194
- data/lib/mechanize/download.rb +0 -59
- data/lib/mechanize/element_matcher.rb +0 -36
- data/lib/mechanize/file.rb +0 -65
- data/lib/mechanize/file_connection.rb +0 -17
- data/lib/mechanize/file_request.rb +0 -26
- data/lib/mechanize/file_response.rb +0 -74
- data/lib/mechanize/file_saver.rb +0 -39
- data/lib/mechanize/form/button.rb +0 -6
- data/lib/mechanize/form/check_box.rb +0 -12
- data/lib/mechanize/form/field.rb +0 -54
- data/lib/mechanize/form/file_upload.rb +0 -21
- data/lib/mechanize/form/hidden.rb +0 -3
- data/lib/mechanize/form/image_button.rb +0 -19
- data/lib/mechanize/form/keygen.rb +0 -34
- data/lib/mechanize/form/multi_select_list.rb +0 -94
- data/lib/mechanize/form/option.rb +0 -50
- data/lib/mechanize/form/radio_button.rb +0 -55
- data/lib/mechanize/form/reset.rb +0 -3
- data/lib/mechanize/form/select_list.rb +0 -44
- data/lib/mechanize/form/submit.rb +0 -3
- data/lib/mechanize/form/text.rb +0 -3
- data/lib/mechanize/form/textarea.rb +0 -3
- data/lib/mechanize/form.rb +0 -543
- data/lib/mechanize/headers.rb +0 -23
- data/lib/mechanize/history.rb +0 -82
- data/lib/mechanize/http/agent.rb +0 -1004
- data/lib/mechanize/http/auth_challenge.rb +0 -59
- data/lib/mechanize/http/auth_realm.rb +0 -31
- data/lib/mechanize/http/content_disposition_parser.rb +0 -188
- data/lib/mechanize/http/www_authenticate_parser.rb +0 -155
- data/lib/mechanize/http.rb +0 -8
- data/lib/mechanize/monkey_patch.rb +0 -16
- data/lib/mechanize/page/base.rb +0 -7
- data/lib/mechanize/page/frame.rb +0 -27
- data/lib/mechanize/page/image.rb +0 -30
- data/lib/mechanize/page/label.rb +0 -20
- data/lib/mechanize/page/link.rb +0 -98
- data/lib/mechanize/page/meta_refresh.rb +0 -68
- data/lib/mechanize/page.rb +0 -440
- data/lib/mechanize/parser.rb +0 -173
- data/lib/mechanize/pluggable_parsers.rb +0 -144
- data/lib/mechanize/redirect_limit_reached_error.rb +0 -19
- data/lib/mechanize/redirect_not_get_or_head_error.rb +0 -21
- data/lib/mechanize/response_code_error.rb +0 -21
- data/lib/mechanize/response_read_error.rb +0 -27
- data/lib/mechanize/robots_disallowed_error.rb +0 -28
- data/lib/mechanize/test_case.rb +0 -663
- data/lib/mechanize/unauthorized_error.rb +0 -3
- data/lib/mechanize/unsupported_scheme_error.rb +0 -6
- data/lib/mechanize/util.rb +0 -101
- data/lib/mechanize.rb +0 -1079
- data/test/data/htpasswd +0 -1
- data/test/data/server.crt +0 -16
- data/test/data/server.csr +0 -12
- data/test/data/server.key +0 -15
- data/test/data/server.pem +0 -15
- data/test/htdocs/alt_text.html +0 -10
- data/test/htdocs/bad_form_test.html +0 -9
- data/test/htdocs/button.jpg +0 -0
- data/test/htdocs/canonical_uri.html +0 -9
- data/test/htdocs/dir with spaces/foo.html +0 -1
- data/test/htdocs/empty_form.html +0 -6
- data/test/htdocs/file_upload.html +0 -26
- data/test/htdocs/find_link.html +0 -41
- data/test/htdocs/form_multi_select.html +0 -16
- data/test/htdocs/form_multival.html +0 -37
- data/test/htdocs/form_no_action.html +0 -18
- data/test/htdocs/form_no_input_name.html +0 -16
- data/test/htdocs/form_order_test.html +0 -11
- data/test/htdocs/form_select.html +0 -16
- data/test/htdocs/form_set_fields.html +0 -14
- data/test/htdocs/form_test.html +0 -188
- data/test/htdocs/frame_referer_test.html +0 -10
- data/test/htdocs/frame_test.html +0 -30
- data/test/htdocs/google.html +0 -13
- data/test/htdocs/index.html +0 -6
- data/test/htdocs/link with space.html +0 -5
- data/test/htdocs/meta_cookie.html +0 -11
- data/test/htdocs/no_title_test.html +0 -6
- data/test/htdocs/noindex.html +0 -9
- data/test/htdocs/rails_3_encoding_hack_form_test.html +0 -27
- data/test/htdocs/relative/tc_relative_links.html +0 -21
- data/test/htdocs/robots.html +0 -8
- data/test/htdocs/robots.txt +0 -2
- data/test/htdocs/tc_bad_charset.html +0 -9
- data/test/htdocs/tc_bad_links.html +0 -5
- data/test/htdocs/tc_base_link.html +0 -8
- data/test/htdocs/tc_blank_form.html +0 -11
- data/test/htdocs/tc_charset.html +0 -6
- data/test/htdocs/tc_checkboxes.html +0 -19
- data/test/htdocs/tc_encoded_links.html +0 -5
- data/test/htdocs/tc_field_precedence.html +0 -11
- data/test/htdocs/tc_follow_meta.html +0 -8
- data/test/htdocs/tc_form_action.html +0 -48
- data/test/htdocs/tc_links.html +0 -19
- data/test/htdocs/tc_meta_in_body.html +0 -9
- data/test/htdocs/tc_pretty_print.html +0 -17
- data/test/htdocs/tc_referer.html +0 -16
- data/test/htdocs/tc_relative_links.html +0 -19
- data/test/htdocs/tc_textarea.html +0 -23
- data/test/htdocs/test_click.html +0 -11
- data/test/htdocs/unusual______.html +0 -5
- data/test/test_mechanize.rb +0 -1164
- data/test/test_mechanize_cookie.rb +0 -451
- data/test/test_mechanize_cookie_jar.rb +0 -483
- data/test/test_mechanize_download.rb +0 -43
- data/test/test_mechanize_file.rb +0 -61
- data/test/test_mechanize_file_connection.rb +0 -21
- data/test/test_mechanize_file_request.rb +0 -19
- data/test/test_mechanize_file_saver.rb +0 -21
- data/test/test_mechanize_form.rb +0 -875
- data/test/test_mechanize_form_check_box.rb +0 -38
- data/test/test_mechanize_form_encoding.rb +0 -114
- data/test/test_mechanize_form_field.rb +0 -63
- data/test/test_mechanize_form_file_upload.rb +0 -20
- data/test/test_mechanize_form_image_button.rb +0 -12
- data/test/test_mechanize_form_keygen.rb +0 -32
- data/test/test_mechanize_form_multi_select_list.rb +0 -84
- data/test/test_mechanize_form_option.rb +0 -55
- data/test/test_mechanize_form_radio_button.rb +0 -78
- data/test/test_mechanize_form_select_list.rb +0 -76
- data/test/test_mechanize_form_textarea.rb +0 -52
- data/test/test_mechanize_headers.rb +0 -35
- data/test/test_mechanize_history.rb +0 -103
- data/test/test_mechanize_http_agent.rb +0 -1225
- data/test/test_mechanize_http_auth_challenge.rb +0 -39
- data/test/test_mechanize_http_auth_realm.rb +0 -49
- data/test/test_mechanize_http_content_disposition_parser.rb +0 -118
- data/test/test_mechanize_http_www_authenticate_parser.rb +0 -146
- data/test/test_mechanize_link.rb +0 -80
- data/test/test_mechanize_page.rb +0 -118
- data/test/test_mechanize_page_encoding.rb +0 -182
- data/test/test_mechanize_page_frame.rb +0 -16
- data/test/test_mechanize_page_link.rb +0 -390
- data/test/test_mechanize_page_meta_refresh.rb +0 -127
- data/test/test_mechanize_parser.rb +0 -289
- data/test/test_mechanize_pluggable_parser.rb +0 -52
- data/test/test_mechanize_redirect_limit_reached_error.rb +0 -24
- data/test/test_mechanize_redirect_not_get_or_head_error.rb +0 -14
- data/test/test_mechanize_subclass.rb +0 -22
- data/test/test_mechanize_util.rb +0 -103
- data/test/test_multi_select.rb +0 -119
data/lib/mechanize/parser.rb
DELETED
@@ -1,173 +0,0 @@
|
|
1
|
-
##
|
2
|
-
# The parser module provides standard methods for accessing the headers and
|
3
|
-
# content of a response that are shared across pluggable parsers.
|
4
|
-
|
5
|
-
module Mechanize::Parser
|
6
|
-
|
7
|
-
extend Forwardable
|
8
|
-
|
9
|
-
special_filenames = Regexp.union %w[
|
10
|
-
AUX
|
11
|
-
COM1
|
12
|
-
COM2
|
13
|
-
COM3
|
14
|
-
COM4
|
15
|
-
COM5
|
16
|
-
COM6
|
17
|
-
COM7
|
18
|
-
COM8
|
19
|
-
COM9
|
20
|
-
CON
|
21
|
-
LPT1
|
22
|
-
LPT2
|
23
|
-
LPT3
|
24
|
-
LPT4
|
25
|
-
LPT5
|
26
|
-
LPT6
|
27
|
-
LPT7
|
28
|
-
LPT8
|
29
|
-
LPT9
|
30
|
-
NUL
|
31
|
-
PRN
|
32
|
-
]
|
33
|
-
|
34
|
-
##
|
35
|
-
# Special filenames that must be escaped
|
36
|
-
|
37
|
-
SPECIAL_FILENAMES = /\A#{special_filenames}/i
|
38
|
-
|
39
|
-
##
|
40
|
-
# The URI this file was retrieved from
|
41
|
-
|
42
|
-
attr_accessor :uri
|
43
|
-
|
44
|
-
##
|
45
|
-
# The Mechanize::Headers for this file
|
46
|
-
|
47
|
-
attr_accessor :response
|
48
|
-
|
49
|
-
alias header response
|
50
|
-
|
51
|
-
##
|
52
|
-
# The HTTP response code
|
53
|
-
|
54
|
-
attr_accessor :code
|
55
|
-
|
56
|
-
##
|
57
|
-
# :method: [](header)
|
58
|
-
#
|
59
|
-
# Access HTTP +header+ by name
|
60
|
-
|
61
|
-
def_delegator :header, :[], :[]
|
62
|
-
|
63
|
-
##
|
64
|
-
# :method: []=(header, value)
|
65
|
-
#
|
66
|
-
# Set HTTP +header+ to +value+
|
67
|
-
|
68
|
-
def_delegator :header, :[]=, :[]=
|
69
|
-
|
70
|
-
##
|
71
|
-
# :method: key?(header)
|
72
|
-
#
|
73
|
-
# Is the named +header+ present?
|
74
|
-
|
75
|
-
def_delegator :header, :key?, :key?
|
76
|
-
|
77
|
-
##
|
78
|
-
# :method: each
|
79
|
-
#
|
80
|
-
# Enumerate HTTP headers
|
81
|
-
|
82
|
-
def_delegator :header, :each, :each
|
83
|
-
|
84
|
-
##
|
85
|
-
# :method: each
|
86
|
-
#
|
87
|
-
# Enumerate HTTP headers in capitalized (canonical) form
|
88
|
-
|
89
|
-
def_delegator :header, :canonical_each, :canonical_each
|
90
|
-
|
91
|
-
##
|
92
|
-
# Extracts the filename from a Content-Disposition header in the #response
|
93
|
-
# or from the URI. If +full_path+ is true the filename will include the
|
94
|
-
# host name and path to the resource, otherwise a filename in the current
|
95
|
-
# directory is given.
|
96
|
-
|
97
|
-
def extract_filename full_path = @full_path
|
98
|
-
handled = false
|
99
|
-
|
100
|
-
if @uri then
|
101
|
-
uri = @uri
|
102
|
-
uri += 'index.html' if uri.path.end_with? '/'
|
103
|
-
|
104
|
-
path = uri.path.split(/\//)
|
105
|
-
filename = path.pop || 'index.html'
|
106
|
-
else
|
107
|
-
path = []
|
108
|
-
filename = 'index.html'
|
109
|
-
end
|
110
|
-
|
111
|
-
# Set the filename
|
112
|
-
if disposition = @response['content-disposition'] then
|
113
|
-
content_disposition =
|
114
|
-
Mechanize::HTTP::ContentDispositionParser.parse disposition
|
115
|
-
|
116
|
-
if content_disposition then
|
117
|
-
filename = content_disposition.filename
|
118
|
-
filename = filename.split(/[\\\/]/).last
|
119
|
-
handled = true
|
120
|
-
end
|
121
|
-
end
|
122
|
-
|
123
|
-
if not handled and @uri then
|
124
|
-
filename << '.html' unless filename =~ /\./
|
125
|
-
filename << "?#{@uri.query}" if @uri.query
|
126
|
-
end
|
127
|
-
|
128
|
-
if SPECIAL_FILENAMES =~ filename then
|
129
|
-
filename = "_#{filename}"
|
130
|
-
end
|
131
|
-
|
132
|
-
filename = filename.tr "\x00-\x20<>:\"/\\|?*", '_'
|
133
|
-
|
134
|
-
@filename = if full_path then
|
135
|
-
File.join @uri.host, path, filename
|
136
|
-
else
|
137
|
-
filename
|
138
|
-
end
|
139
|
-
end
|
140
|
-
|
141
|
-
##
|
142
|
-
# Creates a Mechanize::Header from the Net::HTTPResponse +response+.
|
143
|
-
#
|
144
|
-
# This allows the Net::HTTPResponse to be garbage collected sooner.
|
145
|
-
|
146
|
-
def fill_header response
|
147
|
-
@response = Mechanize::Headers.new
|
148
|
-
|
149
|
-
response.each { |k,v|
|
150
|
-
@response[k] = v
|
151
|
-
} if response
|
152
|
-
|
153
|
-
@response
|
154
|
-
end
|
155
|
-
|
156
|
-
##
|
157
|
-
# Finds a free filename based on +filename+, but is not race-free
|
158
|
-
|
159
|
-
def find_free_name filename
|
160
|
-
filename = @filename unless filename
|
161
|
-
|
162
|
-
number = 1
|
163
|
-
|
164
|
-
while File.exist? filename do
|
165
|
-
filename = "#{@filename}.#{number}"
|
166
|
-
number += 1
|
167
|
-
end
|
168
|
-
|
169
|
-
filename
|
170
|
-
end
|
171
|
-
|
172
|
-
end
|
173
|
-
|
@@ -1,144 +0,0 @@
|
|
1
|
-
require 'mechanize/file'
|
2
|
-
require 'mechanize/file_saver'
|
3
|
-
require 'mechanize/page'
|
4
|
-
|
5
|
-
##
|
6
|
-
# This class is used to register and maintain pluggable parsers for Mechanize
|
7
|
-
# to use.
|
8
|
-
#
|
9
|
-
# Mechanize allows different parsers for different content types. Mechanize
|
10
|
-
# uses PluggableParser to determine which parser to use for any content type.
|
11
|
-
# To use your own pluggable parser or to change the default pluggable parsers,
|
12
|
-
# register them with this class.
|
13
|
-
#
|
14
|
-
# The default parser for unregistered content types is Mechanize::File.
|
15
|
-
#
|
16
|
-
# The module Mechanize::Parser provides basic functionality for any content
|
17
|
-
# type, so you may use it in custom parsers you write. For small files you
|
18
|
-
# wish to perform in-memory operations on, you should subclass
|
19
|
-
# Mechanize::File. For large files you should subclass Mechanize::Download as
|
20
|
-
# the content is only loaded into memory in small chunks.
|
21
|
-
#
|
22
|
-
# == Example
|
23
|
-
#
|
24
|
-
# To create your own parser, just create a class that takes four parameters in
|
25
|
-
# the constructor. Here is an example of registering a pluggable parser that
|
26
|
-
# handles CSV files:
|
27
|
-
#
|
28
|
-
# require 'csv'
|
29
|
-
#
|
30
|
-
# class CSVParser < Mechanize::File
|
31
|
-
# attr_reader :csv
|
32
|
-
#
|
33
|
-
# def initialize uri = nil, response = nil, body = nil, code = nil
|
34
|
-
# super uri, response, body, code
|
35
|
-
# @csv = CSV.parse body
|
36
|
-
# end
|
37
|
-
# end
|
38
|
-
#
|
39
|
-
# agent = Mechanize.new
|
40
|
-
# agent.pluggable_parser.csv = CSVParser
|
41
|
-
# agent.get('http://example.com/test.csv') # => CSVParser
|
42
|
-
#
|
43
|
-
# Now any response with a content type of 'text/csv' will initialize a
|
44
|
-
# CSVParser and return that object to the caller.
|
45
|
-
#
|
46
|
-
# To register a pluggable parser for a content type that pluggable parser does
|
47
|
-
# not know about, use the hash syntax:
|
48
|
-
#
|
49
|
-
# agent.pluggable_parser['text/something'] = SomeClass
|
50
|
-
#
|
51
|
-
# To set the default parser, use #default:
|
52
|
-
#
|
53
|
-
# agent.pluggable_parser.default = Mechanize::Download
|
54
|
-
#
|
55
|
-
# Now all unknown content types will be saved to disk and not loaded into
|
56
|
-
# memory.
|
57
|
-
|
58
|
-
class Mechanize::PluggableParser
|
59
|
-
|
60
|
-
CONTENT_TYPES = {
|
61
|
-
:html => 'text/html',
|
62
|
-
:wap => 'application/vnd.wap.xhtml+xml',
|
63
|
-
:xhtml => 'application/xhtml+xml',
|
64
|
-
:pdf => 'application/pdf',
|
65
|
-
:csv => 'text/csv',
|
66
|
-
:xml => 'text/xml',
|
67
|
-
}
|
68
|
-
|
69
|
-
attr_accessor :default
|
70
|
-
|
71
|
-
def initialize
|
72
|
-
@parsers = {
|
73
|
-
CONTENT_TYPES[:html] => Mechanize::Page,
|
74
|
-
CONTENT_TYPES[:xhtml] => Mechanize::Page,
|
75
|
-
CONTENT_TYPES[:wap] => Mechanize::Page,
|
76
|
-
}
|
77
|
-
|
78
|
-
@default = Mechanize::File
|
79
|
-
end
|
80
|
-
|
81
|
-
##
|
82
|
-
# Returns the parser registered for the given +content_type+
|
83
|
-
|
84
|
-
def parser(content_type)
|
85
|
-
content_type.nil? ? default : @parsers[content_type] || default
|
86
|
-
end
|
87
|
-
|
88
|
-
def register_parser(content_type, klass) # :nodoc:
|
89
|
-
@parsers[content_type] = klass
|
90
|
-
end
|
91
|
-
|
92
|
-
##
|
93
|
-
# Registers +klass+ as the parser for text/html and application/xhtml+xml
|
94
|
-
# content
|
95
|
-
|
96
|
-
def html=(klass)
|
97
|
-
register_parser(CONTENT_TYPES[:html], klass)
|
98
|
-
register_parser(CONTENT_TYPES[:xhtml], klass)
|
99
|
-
end
|
100
|
-
|
101
|
-
##
|
102
|
-
# Registers +klass+ as the parser for application/xhtml+xml content
|
103
|
-
|
104
|
-
def xhtml=(klass)
|
105
|
-
register_parser(CONTENT_TYPES[:xhtml], klass)
|
106
|
-
end
|
107
|
-
|
108
|
-
##
|
109
|
-
# Registers +klass+ as the parser for application/pdf content
|
110
|
-
|
111
|
-
def pdf=(klass)
|
112
|
-
register_parser(CONTENT_TYPES[:pdf], klass)
|
113
|
-
end
|
114
|
-
|
115
|
-
##
|
116
|
-
# Registers +klass+ as the parser for text/csv content
|
117
|
-
|
118
|
-
def csv=(klass)
|
119
|
-
register_parser(CONTENT_TYPES[:csv], klass)
|
120
|
-
end
|
121
|
-
|
122
|
-
##
|
123
|
-
# Registers +klass+ as the parser for text/xml content
|
124
|
-
|
125
|
-
def xml=(klass)
|
126
|
-
register_parser(CONTENT_TYPES[:xml], klass)
|
127
|
-
end
|
128
|
-
|
129
|
-
##
|
130
|
-
# Retrieves the parser for +content_type+ content
|
131
|
-
|
132
|
-
def [](content_type)
|
133
|
-
@parsers[content_type]
|
134
|
-
end
|
135
|
-
|
136
|
-
##
|
137
|
-
# Sets the parser for +content_type+ content to +klass+
|
138
|
-
|
139
|
-
def []=(content_type, klass)
|
140
|
-
@parsers[content_type] = klass
|
141
|
-
end
|
142
|
-
|
143
|
-
end
|
144
|
-
|
@@ -1,19 +0,0 @@
|
|
1
|
-
##
|
2
|
-
# Raised when too many redirects are sent
|
3
|
-
|
4
|
-
class Mechanize::RedirectLimitReachedError < Mechanize::Error
|
5
|
-
|
6
|
-
attr_reader :page
|
7
|
-
attr_reader :redirects
|
8
|
-
attr_reader :response_code
|
9
|
-
|
10
|
-
def initialize page, redirects
|
11
|
-
@page = page
|
12
|
-
@redirects = redirects
|
13
|
-
@response_code = page.code
|
14
|
-
|
15
|
-
super "Redirect limit of #{redirects} reached"
|
16
|
-
end
|
17
|
-
|
18
|
-
end
|
19
|
-
|
@@ -1,21 +0,0 @@
|
|
1
|
-
##
|
2
|
-
# Raised when a POST, PUT, or DELETE request results in a redirect
|
3
|
-
# see RFC 2616 10.3.2, 10.3.3 http://www.ietf.org/rfc/rfc2616.txt
|
4
|
-
|
5
|
-
class Mechanize::RedirectNotGetOrHeadError < Mechanize::Error
|
6
|
-
attr_reader :page, :response_code, :verb, :uri
|
7
|
-
def initialize(page, verb)
|
8
|
-
@page = page
|
9
|
-
@verb = verb
|
10
|
-
@uri = page.uri
|
11
|
-
@response_code = page.code
|
12
|
-
end
|
13
|
-
|
14
|
-
def to_s
|
15
|
-
method = @verb.to_s.upcase
|
16
|
-
"#{@response_code} redirect received after a #{method} request"
|
17
|
-
end
|
18
|
-
|
19
|
-
alias :inspect :to_s
|
20
|
-
end
|
21
|
-
|
@@ -1,21 +0,0 @@
|
|
1
|
-
# This error is raised when Mechanize encounters a response code it does not
|
2
|
-
# know how to handle. Currently, this exception will be thrown if Mechanize
|
3
|
-
# encounters response codes other than 200, 301, or 302. Any other response
|
4
|
-
# code is up to the user to handle.
|
5
|
-
|
6
|
-
class Mechanize::ResponseCodeError < Mechanize::Error
|
7
|
-
attr_reader :response_code
|
8
|
-
attr_reader :page
|
9
|
-
|
10
|
-
def initialize(page)
|
11
|
-
@page = page
|
12
|
-
@response_code = page.code.to_s
|
13
|
-
end
|
14
|
-
|
15
|
-
def to_s
|
16
|
-
"#{@response_code} => #{Net::HTTPResponse::CODE_TO_OBJ[@response_code]}"
|
17
|
-
end
|
18
|
-
|
19
|
-
alias inspect to_s
|
20
|
-
end
|
21
|
-
|
@@ -1,27 +0,0 @@
|
|
1
|
-
##
|
2
|
-
# Raised when Mechanize encounters an error while reading the response body
|
3
|
-
# from the server. Contains the response headers and the response body up to
|
4
|
-
# the error along with the initial error.
|
5
|
-
|
6
|
-
class Mechanize::ResponseReadError < Mechanize::Error
|
7
|
-
|
8
|
-
attr_reader :body_io
|
9
|
-
attr_reader :error
|
10
|
-
attr_reader :response
|
11
|
-
|
12
|
-
##
|
13
|
-
# Creates a new ResponseReadError with the +error+ raised, the +response+
|
14
|
-
# and the +body_io+ for content read so far.
|
15
|
-
|
16
|
-
def initialize error, response, body_io
|
17
|
-
@error = error
|
18
|
-
@response = response
|
19
|
-
@body_io = body_io
|
20
|
-
end
|
21
|
-
|
22
|
-
def message # :nodoc:
|
23
|
-
"#{@error.message} (#{self.class})"
|
24
|
-
end
|
25
|
-
|
26
|
-
end
|
27
|
-
|
@@ -1,28 +0,0 @@
|
|
1
|
-
# Exception that is raised when an access to a resource is disallowed by
|
2
|
-
# robots.txt or by HTML document itself.
|
3
|
-
|
4
|
-
class Mechanize::RobotsDisallowedError < Mechanize::Error
|
5
|
-
def initialize(url)
|
6
|
-
if url.is_a?(URI)
|
7
|
-
@url = url.to_s
|
8
|
-
@uri = url
|
9
|
-
else
|
10
|
-
@url = url.to_s
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
# Returns the URL (string) of the resource that caused this error.
|
15
|
-
attr_reader :url
|
16
|
-
|
17
|
-
# Returns the URL (URI object) of the resource that caused this
|
18
|
-
# error. URI::InvalidURIError may be raised if the URL happens to
|
19
|
-
# be invalid or not understood by the URI library.
|
20
|
-
def uri
|
21
|
-
@uri ||= URI.parse(url)
|
22
|
-
end
|
23
|
-
|
24
|
-
def to_s
|
25
|
-
"Robots access is disallowed for URL: #{url}"
|
26
|
-
end
|
27
|
-
alias :inspect :to_s
|
28
|
-
end
|
data/lib/mechanize/test_case.rb
DELETED
@@ -1,663 +0,0 @@
|
|
1
|
-
require 'mechanize'
|
2
|
-
require 'logger'
|
3
|
-
require 'tempfile'
|
4
|
-
require 'tmpdir'
|
5
|
-
require 'webrick'
|
6
|
-
require 'zlib'
|
7
|
-
|
8
|
-
require 'rubygems'
|
9
|
-
|
10
|
-
begin
|
11
|
-
gem 'minitest'
|
12
|
-
rescue Gem::LoadError
|
13
|
-
end
|
14
|
-
|
15
|
-
require 'minitest/autorun'
|
16
|
-
|
17
|
-
class Mechanize::TestCase < MiniTest::Unit::TestCase
|
18
|
-
|
19
|
-
TEST_DIR = File.expand_path '../../../test', __FILE__
|
20
|
-
REQUESTS = []
|
21
|
-
|
22
|
-
def setup
|
23
|
-
super
|
24
|
-
|
25
|
-
REQUESTS.clear
|
26
|
-
@mech = Mechanize.new
|
27
|
-
@ssl_private_key = nil
|
28
|
-
@ssl_certificate = nil
|
29
|
-
end
|
30
|
-
|
31
|
-
def fake_page agent = @mech
|
32
|
-
uri = URI 'http://fake.example/'
|
33
|
-
html = <<-END
|
34
|
-
<html>
|
35
|
-
<body>
|
36
|
-
<form><input type="submit" value="submit" /></form>
|
37
|
-
</body>
|
38
|
-
</html>
|
39
|
-
END
|
40
|
-
|
41
|
-
response = { 'content-type' => 'text/html' }
|
42
|
-
|
43
|
-
Mechanize::Page.new uri, response, html, 200, agent
|
44
|
-
end
|
45
|
-
|
46
|
-
def have_encoding?
|
47
|
-
Object.const_defined? :Encoding
|
48
|
-
end
|
49
|
-
|
50
|
-
def html_page body
|
51
|
-
uri = URI 'http://example/'
|
52
|
-
Mechanize::Page.new uri, { 'content-type' => 'text/html' }, body, 200, @mech
|
53
|
-
end
|
54
|
-
|
55
|
-
def in_tmpdir
|
56
|
-
Dir.mktmpdir do |dir|
|
57
|
-
Dir.chdir dir do
|
58
|
-
yield
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
def node element, attributes = {}
|
64
|
-
doc = Nokogiri::HTML::Document.new
|
65
|
-
|
66
|
-
node = Nokogiri::XML::Node.new element, doc
|
67
|
-
|
68
|
-
attributes.each do |name, value|
|
69
|
-
node[name] = value
|
70
|
-
end
|
71
|
-
|
72
|
-
node
|
73
|
-
end
|
74
|
-
|
75
|
-
def page uri, content_type = 'text/html', body = '', code = 200
|
76
|
-
uri = URI uri unless URI::Generic === uri
|
77
|
-
|
78
|
-
Mechanize::Page.new(uri, { 'content-type' => content_type }, body, code,
|
79
|
-
@mech)
|
80
|
-
end
|
81
|
-
|
82
|
-
def requests
|
83
|
-
REQUESTS
|
84
|
-
end
|
85
|
-
|
86
|
-
def ssl_private_key
|
87
|
-
@ssl_private_key ||= OpenSSL::PKey::RSA.new <<-KEY
|
88
|
-
-----BEGIN RSA PRIVATE KEY-----
|
89
|
-
MIG7AgEAAkEA8pmEfmP0Ibir91x6pbts4JmmsVZd3xvD5p347EFvBCbhBW1nv1Gs
|
90
|
-
bCBEFlSiT1q2qvxGb5IlbrfdhdgyqdTXUQIBAQIBAQIhAPumXslvf6YasXa1hni3
|
91
|
-
p80joKOug2UUgqOLD2GUSO//AiEA9ssY6AFxjHWuwo/+/rkLmkfO2s1Lz3OeUEWq
|
92
|
-
6DiHOK8CAQECAQECIQDt8bc4vS6wh9VXApNSKIpVygtxSFe/IwLeX26n77j6Qg==
|
93
|
-
-----END RSA PRIVATE KEY-----
|
94
|
-
KEY
|
95
|
-
end
|
96
|
-
|
97
|
-
def ssl_certificate
|
98
|
-
@ssl_certificate ||= OpenSSL::X509::Certificate.new <<-CERT
|
99
|
-
-----BEGIN CERTIFICATE-----
|
100
|
-
MIIBQjCB7aADAgECAgEAMA0GCSqGSIb3DQEBBQUAMCoxDzANBgNVBAMMBm5vYm9k
|
101
|
-
eTEXMBUGCgmSJomT8ixkARkWB2V4YW1wbGUwIBcNMTExMTAzMjEwODU5WhgPOTk5
|
102
|
-
OTEyMzExMjU5NTlaMCoxDzANBgNVBAMMBm5vYm9keTEXMBUGCgmSJomT8ixkARkW
|
103
|
-
B2V4YW1wbGUwWjANBgkqhkiG9w0BAQEFAANJADBGAkEA8pmEfmP0Ibir91x6pbts
|
104
|
-
4JmmsVZd3xvD5p347EFvBCbhBW1nv1GsbCBEFlSiT1q2qvxGb5IlbrfdhdgyqdTX
|
105
|
-
UQIBATANBgkqhkiG9w0BAQUFAANBAAAB////////////////////////////////
|
106
|
-
//8AMCEwCQYFKw4DAhoFAAQUePiv+QrJxyjtEJNnH5pB9OTWIqA=
|
107
|
-
-----END CERTIFICATE-----
|
108
|
-
CERT
|
109
|
-
end
|
110
|
-
|
111
|
-
end
|
112
|
-
|
113
|
-
class BasicAuthServlet < WEBrick::HTTPServlet::AbstractServlet
|
114
|
-
def do_GET(req,res)
|
115
|
-
htpd = WEBrick::HTTPAuth::Htpasswd.new('dot.htpasswd')
|
116
|
-
htpd.set_passwd('Blah', 'user', 'pass')
|
117
|
-
authenticator = WEBrick::HTTPAuth::BasicAuth.new({
|
118
|
-
:UserDB => htpd,
|
119
|
-
:Realm => 'Blah',
|
120
|
-
:Logger => Logger.new(nil)
|
121
|
-
}
|
122
|
-
)
|
123
|
-
begin
|
124
|
-
authenticator.authenticate(req,res)
|
125
|
-
res.body = 'You are authenticated'
|
126
|
-
rescue WEBrick::HTTPStatus::Unauthorized
|
127
|
-
res.status = 401
|
128
|
-
end
|
129
|
-
FileUtils.rm('dot.htpasswd')
|
130
|
-
end
|
131
|
-
alias :do_POST :do_GET
|
132
|
-
end
|
133
|
-
|
134
|
-
class ContentTypeServlet < WEBrick::HTTPServlet::AbstractServlet
|
135
|
-
def do_GET(req, res)
|
136
|
-
ct = req.query['ct'] || "text/html; charset=utf-8"
|
137
|
-
res['Content-Type'] = ct
|
138
|
-
res.body = "Hello World"
|
139
|
-
end
|
140
|
-
end
|
141
|
-
|
142
|
-
class DigestAuthServlet < WEBrick::HTTPServlet::AbstractServlet
|
143
|
-
htpd = WEBrick::HTTPAuth::Htdigest.new('digest.htpasswd')
|
144
|
-
htpd.set_passwd('Blah', 'user', 'pass')
|
145
|
-
@@authenticator = WEBrick::HTTPAuth::DigestAuth.new({
|
146
|
-
:UserDB => htpd,
|
147
|
-
:Realm => 'Blah',
|
148
|
-
:Algorithm => 'MD5',
|
149
|
-
:Logger => Logger.new(nil)
|
150
|
-
}
|
151
|
-
)
|
152
|
-
def do_GET(req,res)
|
153
|
-
def req.request_time; Time.now; end
|
154
|
-
def req.request_uri; '/digest_auth'; end
|
155
|
-
def req.request_method; "GET"; end
|
156
|
-
|
157
|
-
begin
|
158
|
-
@@authenticator.authenticate(req,res)
|
159
|
-
res.body = 'You are authenticated'
|
160
|
-
rescue WEBrick::HTTPStatus::Unauthorized
|
161
|
-
res.status = 401
|
162
|
-
end
|
163
|
-
FileUtils.rm('digest.htpasswd') if File.exists?('digest.htpasswd')
|
164
|
-
end
|
165
|
-
alias :do_POST :do_GET
|
166
|
-
end
|
167
|
-
|
168
|
-
class FileUploadServlet < WEBrick::HTTPServlet::AbstractServlet
|
169
|
-
def do_POST(req, res)
|
170
|
-
res.body = req.body
|
171
|
-
end
|
172
|
-
end
|
173
|
-
|
174
|
-
class FormServlet < WEBrick::HTTPServlet::AbstractServlet
|
175
|
-
def do_GET(req, res)
|
176
|
-
res.body = "<HTML><body>"
|
177
|
-
req.query.each_key { |k|
|
178
|
-
req.query[k].each_data { |data|
|
179
|
-
res.body << "<a href=\"#\">#{WEBrick::HTTPUtils.unescape(k)}:#{WEBrick::HTTPUtils.unescape(data)}</a><br />"
|
180
|
-
}
|
181
|
-
}
|
182
|
-
res.body << "<div id=\"query\">#{res.query}</div></body></HTML>"
|
183
|
-
res['Content-Type'] = "text/html"
|
184
|
-
end
|
185
|
-
|
186
|
-
def do_POST(req, res)
|
187
|
-
res.body = "<HTML><body>"
|
188
|
-
|
189
|
-
req.query.each_key { |k|
|
190
|
-
req.query[k].each_data { |data|
|
191
|
-
res.body << "<a href=\"#\">#{k}:#{data}</a><br />"
|
192
|
-
}
|
193
|
-
}
|
194
|
-
|
195
|
-
res.body << "<div id=\"query\">#{req.body}</div></body></HTML>"
|
196
|
-
res['Content-Type'] = "text/html"
|
197
|
-
end
|
198
|
-
end
|
199
|
-
|
200
|
-
class GzipServlet < WEBrick::HTTPServlet::AbstractServlet
|
201
|
-
def do_GET(req, res)
|
202
|
-
if req['Accept-Encoding'] =~ /gzip/
|
203
|
-
if name = req.query['file'] then
|
204
|
-
open("#{Mechanize::TestCase::TEST_DIR}/htdocs/#{name}", 'r') do |io|
|
205
|
-
string = ""
|
206
|
-
zipped = StringIO.new string, 'w'
|
207
|
-
Zlib::GzipWriter.wrap zipped do |gz|
|
208
|
-
gz.write io.read
|
209
|
-
end
|
210
|
-
res.body = string
|
211
|
-
end
|
212
|
-
else
|
213
|
-
res.body = ''
|
214
|
-
end
|
215
|
-
res['Content-Encoding'] = req['X-ResponseContentEncoding'] || 'gzip'
|
216
|
-
res['Content-Type'] = "text/html"
|
217
|
-
else
|
218
|
-
res.code = 400
|
219
|
-
res.body = 'no gzip'
|
220
|
-
end
|
221
|
-
end
|
222
|
-
end
|
223
|
-
|
224
|
-
class HeaderServlet < WEBrick::HTTPServlet::AbstractServlet
|
225
|
-
def do_GET(req, res)
|
226
|
-
res['Content-Type'] = "text/html"
|
227
|
-
|
228
|
-
req.query.each do |x,y|
|
229
|
-
res[x] = y
|
230
|
-
end
|
231
|
-
|
232
|
-
body = ''
|
233
|
-
req.each_header do |k,v|
|
234
|
-
body << "#{k}|#{v}\n"
|
235
|
-
end
|
236
|
-
res.body = body
|
237
|
-
end
|
238
|
-
end
|
239
|
-
|
240
|
-
class HttpRefreshServlet < WEBrick::HTTPServlet::AbstractServlet
|
241
|
-
def do_GET(req, res)
|
242
|
-
res['Content-Type'] = req.query['ct'] || "text/html"
|
243
|
-
refresh_time = req.query['refresh_time'] || 0
|
244
|
-
refresh_url = req.query['refresh_url'] || '/index.html'
|
245
|
-
res['Refresh'] = " #{refresh_time};url=#{refresh_url}\r\n";
|
246
|
-
end
|
247
|
-
end
|
248
|
-
|
249
|
-
class InfiniteRedirectServlet < WEBrick::HTTPServlet::AbstractServlet
|
250
|
-
def do_GET(req, res)
|
251
|
-
res['Content-Type'] = req.query['ct'] || "text/html"
|
252
|
-
res.status = req.query['code'] ? req.query['code'].to_i : '302'
|
253
|
-
number = req.query['q'] ? req.query['q'].to_i : 0
|
254
|
-
res['Location'] = "/infinite_redirect?q=#{number + 1}"
|
255
|
-
end
|
256
|
-
alias :do_POST :do_GET
|
257
|
-
end
|
258
|
-
|
259
|
-
class InfiniteRefreshServlet < WEBrick::HTTPServlet::AbstractServlet
|
260
|
-
def do_GET(req, res)
|
261
|
-
res['Content-Type'] = req.query['ct'] || "text/html"
|
262
|
-
res.status = req.query['code'] ? req.query['code'].to_i : '302'
|
263
|
-
number = req.query['q'] ? req.query['q'].to_i : 0
|
264
|
-
res['Refresh'] = " 0;url=http://localhost/infinite_refresh?q=#{number + 1}\r\n";
|
265
|
-
end
|
266
|
-
end
|
267
|
-
|
268
|
-
class ManyCookiesAsStringServlet < WEBrick::HTTPServlet::AbstractServlet
|
269
|
-
def do_GET(req, res)
|
270
|
-
cookies = []
|
271
|
-
name_cookie = WEBrick::Cookie.new("name", "Aaron")
|
272
|
-
name_cookie.path = "/"
|
273
|
-
name_cookie.expires = Time.now + 86400
|
274
|
-
name_cookie.domain = 'localhost'
|
275
|
-
cookies << name_cookie
|
276
|
-
cookies << name_cookie
|
277
|
-
cookies << name_cookie
|
278
|
-
cookies << "#{name_cookie}; HttpOnly"
|
279
|
-
|
280
|
-
expired_cookie = WEBrick::Cookie.new("expired", "doh")
|
281
|
-
expired_cookie.path = "/"
|
282
|
-
expired_cookie.expires = Time.now - 86400
|
283
|
-
cookies << expired_cookie
|
284
|
-
|
285
|
-
different_path_cookie = WEBrick::Cookie.new("a_path", "some_path")
|
286
|
-
different_path_cookie.path = "/some_path"
|
287
|
-
different_path_cookie.expires = Time.now + 86400
|
288
|
-
cookies << different_path_cookie
|
289
|
-
|
290
|
-
no_path_cookie = WEBrick::Cookie.new("no_path", "no_path")
|
291
|
-
no_path_cookie.expires = Time.now + 86400
|
292
|
-
cookies << no_path_cookie
|
293
|
-
|
294
|
-
no_exp_path_cookie = WEBrick::Cookie.new("no_expires", "nope")
|
295
|
-
no_exp_path_cookie.path = "/"
|
296
|
-
cookies << no_exp_path_cookie
|
297
|
-
|
298
|
-
res['Set-Cookie'] = cookies.join(', ')
|
299
|
-
|
300
|
-
res['Content-Type'] = "text/html"
|
301
|
-
res.body = "<html><body>hello</body></html>"
|
302
|
-
end
|
303
|
-
end
|
304
|
-
|
305
|
-
class ManyCookiesServlet < WEBrick::HTTPServlet::AbstractServlet
|
306
|
-
def do_GET(req, res)
|
307
|
-
name_cookie = WEBrick::Cookie.new("name", "Aaron")
|
308
|
-
name_cookie.path = "/"
|
309
|
-
name_cookie.expires = Time.now + 86400
|
310
|
-
res.cookies << name_cookie
|
311
|
-
res.cookies << name_cookie
|
312
|
-
res.cookies << name_cookie
|
313
|
-
res.cookies << name_cookie
|
314
|
-
|
315
|
-
expired_cookie = WEBrick::Cookie.new("expired", "doh")
|
316
|
-
expired_cookie.path = "/"
|
317
|
-
expired_cookie.expires = Time.now - 86400
|
318
|
-
res.cookies << expired_cookie
|
319
|
-
|
320
|
-
different_path_cookie = WEBrick::Cookie.new("a_path", "some_path")
|
321
|
-
different_path_cookie.path = "/some_path"
|
322
|
-
different_path_cookie.expires = Time.now + 86400
|
323
|
-
res.cookies << different_path_cookie
|
324
|
-
|
325
|
-
no_path_cookie = WEBrick::Cookie.new("no_path", "no_path")
|
326
|
-
no_path_cookie.expires = Time.now + 86400
|
327
|
-
res.cookies << no_path_cookie
|
328
|
-
|
329
|
-
no_exp_path_cookie = WEBrick::Cookie.new("no_expires", "nope")
|
330
|
-
no_exp_path_cookie.path = "/"
|
331
|
-
res.cookies << no_exp_path_cookie
|
332
|
-
|
333
|
-
res['Content-Type'] = "text/html"
|
334
|
-
res.body = "<html><body>hello</body></html>"
|
335
|
-
end
|
336
|
-
end
|
337
|
-
|
338
|
-
class ModifiedSinceServlet < WEBrick::HTTPServlet::AbstractServlet
|
339
|
-
def do_GET(req, res)
|
340
|
-
s_time = 'Fri, 04 May 2001 00:00:38 GMT'
|
341
|
-
|
342
|
-
my_time = Time.parse(s_time)
|
343
|
-
|
344
|
-
if req['If-Modified-Since']
|
345
|
-
your_time = Time.parse(req['If-Modified-Since'])
|
346
|
-
if my_time > your_time
|
347
|
-
res.body = 'This page was updated since you requested'
|
348
|
-
else
|
349
|
-
res.status = 304
|
350
|
-
end
|
351
|
-
else
|
352
|
-
res.body = 'You did not send an If-Modified-Since header'
|
353
|
-
end
|
354
|
-
|
355
|
-
res['Last-Modified'] = s_time
|
356
|
-
end
|
357
|
-
end
|
358
|
-
|
359
|
-
class NTLMServlet < WEBrick::HTTPServlet::AbstractServlet
|
360
|
-
|
361
|
-
def do_GET(req, res)
|
362
|
-
if req['Authorization'] =~ /^NTLM (.*)/ then
|
363
|
-
authorization = $1.unpack('m*').first
|
364
|
-
|
365
|
-
if authorization =~ /^NTLMSSP\000\001/ then
|
366
|
-
type_2 = 'TlRMTVNTUAACAAAADAAMADAAAAABAoEAASNFZ4mr' \
|
367
|
-
'ze8AAAAAAAAAAGIAYgA8AAAARABPAE0AQQBJAE4A' \
|
368
|
-
'AgAMAEQATwBNAEEASQBOAAEADABTAEUAUgBWAEUA' \
|
369
|
-
'UgAEABQAZABvAG0AYQBpAG4ALgBjAG8AbQADACIA' \
|
370
|
-
'cwBlAHIAdgBlAHIALgBkAG8AbQBhAGkAbgAuAGMA' \
|
371
|
-
'bwBtAAAAAAA='
|
372
|
-
|
373
|
-
res['WWW-Authenticate'] = "NTLM #{type_2}"
|
374
|
-
res.status = 401
|
375
|
-
elsif authorization =~ /^NTLMSSP\000\003/ then
|
376
|
-
res.body = 'ok'
|
377
|
-
else
|
378
|
-
res['WWW-Authenticate'] = 'NTLM'
|
379
|
-
res.status = 401
|
380
|
-
end
|
381
|
-
else
|
382
|
-
res['WWW-Authenticate'] = 'NTLM'
|
383
|
-
res.status = 401
|
384
|
-
end
|
385
|
-
end
|
386
|
-
|
387
|
-
end
|
388
|
-
|
389
|
-
class OneCookieNoSpacesServlet < WEBrick::HTTPServlet::AbstractServlet
|
390
|
-
def do_GET(req, res)
|
391
|
-
cookie = WEBrick::Cookie.new("foo", "bar")
|
392
|
-
cookie.path = "/"
|
393
|
-
cookie.expires = Time.now + 86400
|
394
|
-
res.cookies << cookie.to_s.gsub(/; /, ';')
|
395
|
-
res['Content-Type'] = "text/html"
|
396
|
-
res.body = "<html><body>hello</body></html>"
|
397
|
-
end
|
398
|
-
end
|
399
|
-
|
400
|
-
class OneCookieServlet < WEBrick::HTTPServlet::AbstractServlet
|
401
|
-
def do_GET(req, res)
|
402
|
-
cookie = WEBrick::Cookie.new("foo", "bar")
|
403
|
-
cookie.path = "/"
|
404
|
-
cookie.expires = Time.now + 86400
|
405
|
-
res.cookies << cookie
|
406
|
-
res['Content-Type'] = "text/html"
|
407
|
-
res.body = "<html><body>hello</body></html>"
|
408
|
-
end
|
409
|
-
end
|
410
|
-
|
411
|
-
class QuotedValueCookieServlet < WEBrick::HTTPServlet::AbstractServlet
|
412
|
-
def do_GET(req, res)
|
413
|
-
cookie = WEBrick::Cookie.new("quoted", "\"value\"")
|
414
|
-
cookie.path = "/"
|
415
|
-
cookie.expires = Time.now + 86400
|
416
|
-
res.cookies << cookie
|
417
|
-
res['Content-Type'] = "text/html"
|
418
|
-
res.body = "<html><body>hello</body></html>"
|
419
|
-
end
|
420
|
-
end
|
421
|
-
|
422
|
-
class RedirectServlet < WEBrick::HTTPServlet::AbstractServlet
|
423
|
-
def do_GET(req, res)
|
424
|
-
res['Content-Type'] = req.query['ct'] || "text/html"
|
425
|
-
res.status = req.query['code'] ? req.query['code'].to_i : '302'
|
426
|
-
res['Location'] = "/verb"
|
427
|
-
end
|
428
|
-
|
429
|
-
alias :do_POST :do_GET
|
430
|
-
alias :do_HEAD :do_GET
|
431
|
-
alias :do_PUT :do_GET
|
432
|
-
alias :do_DELETE :do_GET
|
433
|
-
end
|
434
|
-
|
435
|
-
class RefererServlet < WEBrick::HTTPServlet::AbstractServlet
|
436
|
-
def do_GET(req, res)
|
437
|
-
res['Content-Type'] = "text/html"
|
438
|
-
res.body = req['Referer'] || ''
|
439
|
-
end
|
440
|
-
|
441
|
-
def do_POST(req, res)
|
442
|
-
res['Content-Type'] = "text/html"
|
443
|
-
res.body = req['Referer'] || ''
|
444
|
-
end
|
445
|
-
end
|
446
|
-
|
447
|
-
class RefreshWithoutUrl < WEBrick::HTTPServlet::AbstractServlet
|
448
|
-
@@count = 0
|
449
|
-
def do_GET(req, res)
|
450
|
-
res['Content-Type'] = "text/html"
|
451
|
-
@@count += 1
|
452
|
-
if @@count > 1
|
453
|
-
res['Refresh'] = "0; url=http://localhost/index.html";
|
454
|
-
else
|
455
|
-
res['Refresh'] = "0";
|
456
|
-
end
|
457
|
-
end
|
458
|
-
end
|
459
|
-
|
460
|
-
class RefreshWithEmptyUrl < WEBrick::HTTPServlet::AbstractServlet
|
461
|
-
@@count = 0
|
462
|
-
def do_GET(req, res)
|
463
|
-
res['Content-Type'] = "text/html"
|
464
|
-
@@count += 1
|
465
|
-
if @@count > 1
|
466
|
-
res['Refresh'] = "0; url=http://localhost/index.html";
|
467
|
-
else
|
468
|
-
res['Refresh'] = "0; url=";
|
469
|
-
end
|
470
|
-
end
|
471
|
-
end
|
472
|
-
|
473
|
-
class ResponseCodeServlet < WEBrick::HTTPServlet::AbstractServlet
|
474
|
-
def do_GET(req, res)
|
475
|
-
res['Content-Type'] = req.query['ct'] || "text/html"
|
476
|
-
if req.query['code']
|
477
|
-
code = req.query['code'].to_i
|
478
|
-
case code
|
479
|
-
when 300, 301, 302, 303, 304, 305, 307
|
480
|
-
res['Location'] = "/index.html"
|
481
|
-
end
|
482
|
-
res.status = code
|
483
|
-
else
|
484
|
-
end
|
485
|
-
end
|
486
|
-
end
|
487
|
-
|
488
|
-
class SendCookiesServlet < WEBrick::HTTPServlet::AbstractServlet
|
489
|
-
def do_GET(req, res)
|
490
|
-
res['Content-Type'] = "text/html"
|
491
|
-
res.body = "<html><body>"
|
492
|
-
req.cookies.each { |c|
|
493
|
-
res.body << "<a href=\"#\">#{c.name}:#{c.value}</a>"
|
494
|
-
}
|
495
|
-
res.body << "</body></html>"
|
496
|
-
end
|
497
|
-
end
|
498
|
-
|
499
|
-
class VerbServlet < WEBrick::HTTPServlet::AbstractServlet
|
500
|
-
%w(HEAD GET POST PUT DELETE).each do |verb|
|
501
|
-
eval(<<-eomethod)
|
502
|
-
def do_#{verb}(req, res)
|
503
|
-
res.header['X-Request-Method'] = #{verb.dump}
|
504
|
-
end
|
505
|
-
eomethod
|
506
|
-
end
|
507
|
-
end
|
508
|
-
|
509
|
-
class Net::HTTP
|
510
|
-
alias :old_do_start :do_start
|
511
|
-
|
512
|
-
def do_start
|
513
|
-
@started = true
|
514
|
-
end
|
515
|
-
|
516
|
-
SERVLETS = {
|
517
|
-
'/gzip' => GzipServlet,
|
518
|
-
'/form_post' => FormServlet,
|
519
|
-
'/basic_auth' => BasicAuthServlet,
|
520
|
-
'/form post' => FormServlet,
|
521
|
-
'/response_code' => ResponseCodeServlet,
|
522
|
-
'/http_refresh' => HttpRefreshServlet,
|
523
|
-
'/content_type_test' => ContentTypeServlet,
|
524
|
-
'/referer' => RefererServlet,
|
525
|
-
'/file_upload' => FileUploadServlet,
|
526
|
-
'/one_cookie' => OneCookieServlet,
|
527
|
-
'/one_cookie_no_space' => OneCookieNoSpacesServlet,
|
528
|
-
'/many_cookies' => ManyCookiesServlet,
|
529
|
-
'/many_cookies_as_string' => ManyCookiesAsStringServlet,
|
530
|
-
'/ntlm' => NTLMServlet,
|
531
|
-
'/send_cookies' => SendCookiesServlet,
|
532
|
-
'/quoted_value_cookie' => QuotedValueCookieServlet,
|
533
|
-
'/if_modified_since' => ModifiedSinceServlet,
|
534
|
-
'/http_headers' => HeaderServlet,
|
535
|
-
'/infinite_redirect' => InfiniteRedirectServlet,
|
536
|
-
'/infinite_refresh' => InfiniteRefreshServlet,
|
537
|
-
'/redirect' => RedirectServlet,
|
538
|
-
'/refresh_without_url' => RefreshWithoutUrl,
|
539
|
-
'/refresh_with_empty_url' => RefreshWithEmptyUrl,
|
540
|
-
'/digest_auth' => DigestAuthServlet,
|
541
|
-
'/verb' => VerbServlet,
|
542
|
-
}
|
543
|
-
|
544
|
-
PAGE_CACHE = {}
|
545
|
-
|
546
|
-
alias :old_request :request
|
547
|
-
|
548
|
-
def request(req, *data, &block)
|
549
|
-
url = URI.parse(req.path)
|
550
|
-
path = WEBrick::HTTPUtils.unescape(url.path)
|
551
|
-
|
552
|
-
path = '/index.html' if path == '/'
|
553
|
-
|
554
|
-
res = ::Response.new
|
555
|
-
res.query_params = url.query
|
556
|
-
|
557
|
-
req.query = if 'POST' != req.method && url.query then
|
558
|
-
WEBrick::HTTPUtils.parse_query url.query
|
559
|
-
elsif req['content-type'] =~ /www-form-urlencoded/ then
|
560
|
-
WEBrick::HTTPUtils.parse_query req.body
|
561
|
-
elsif req['content-type'] =~ /boundary=(.+)/ then
|
562
|
-
boundary = WEBrick::HTTPUtils.dequote $1
|
563
|
-
WEBrick::HTTPUtils.parse_form_data req.body, boundary
|
564
|
-
else
|
565
|
-
{}
|
566
|
-
end
|
567
|
-
|
568
|
-
req.cookies = WEBrick::Cookie.parse(req['Cookie'])
|
569
|
-
|
570
|
-
Mechanize::TestCase::REQUESTS << req
|
571
|
-
|
572
|
-
if servlet_klass = SERVLETS[path]
|
573
|
-
servlet = servlet_klass.new({})
|
574
|
-
servlet.send "do_#{req.method}", req, res
|
575
|
-
else
|
576
|
-
filename = "htdocs#{path.gsub(/[^\/\\.\w\s]/, '_')}"
|
577
|
-
unless PAGE_CACHE[filename]
|
578
|
-
open("#{Mechanize::TestCase::TEST_DIR}/#{filename}", 'rb') { |io|
|
579
|
-
PAGE_CACHE[filename] = io.read
|
580
|
-
}
|
581
|
-
end
|
582
|
-
|
583
|
-
res.body = PAGE_CACHE[filename]
|
584
|
-
case filename
|
585
|
-
when /\.txt$/
|
586
|
-
res['Content-Type'] = 'text/plain'
|
587
|
-
when /\.jpg$/
|
588
|
-
res['Content-Type'] = 'image/jpeg'
|
589
|
-
end
|
590
|
-
end
|
591
|
-
|
592
|
-
res['Content-Type'] ||= 'text/html'
|
593
|
-
res.code ||= "200"
|
594
|
-
|
595
|
-
response_klass = Net::HTTPResponse::CODE_TO_OBJ[res.code.to_s]
|
596
|
-
response = response_klass.new res.http_version, res.code, res.message
|
597
|
-
|
598
|
-
res.header.each do |k,v|
|
599
|
-
v = v.first if v.length == 1
|
600
|
-
response[k] = v
|
601
|
-
end
|
602
|
-
|
603
|
-
res.cookies.each do |cookie|
|
604
|
-
response.add_field 'Set-Cookie', cookie.to_s
|
605
|
-
end
|
606
|
-
|
607
|
-
response['Content-Type'] ||= 'text/html'
|
608
|
-
response['Content-Length'] = res['Content-Length'] || res.body.length.to_s
|
609
|
-
|
610
|
-
io = StringIO.new(res.body)
|
611
|
-
response.instance_variable_set :@socket, io
|
612
|
-
def io.read clen, dest, _
|
613
|
-
dest << string[0, clen]
|
614
|
-
end
|
615
|
-
|
616
|
-
body_exist = req.response_body_permitted? &&
|
617
|
-
response_klass.body_permitted?
|
618
|
-
|
619
|
-
response.instance_variable_set :@body_exist, body_exist
|
620
|
-
|
621
|
-
yield response if block_given?
|
622
|
-
|
623
|
-
response
|
624
|
-
end
|
625
|
-
end
|
626
|
-
|
627
|
-
class Net::HTTPRequest
|
628
|
-
attr_accessor :query, :body, :cookies, :user
|
629
|
-
end
|
630
|
-
|
631
|
-
class Response
|
632
|
-
include Net::HTTPHeader
|
633
|
-
|
634
|
-
attr_reader :code
|
635
|
-
attr_accessor :body, :query, :cookies
|
636
|
-
attr_accessor :query_params, :http_version
|
637
|
-
attr_accessor :header
|
638
|
-
|
639
|
-
def code=(c)
|
640
|
-
@code = c.to_s
|
641
|
-
end
|
642
|
-
|
643
|
-
alias :status :code
|
644
|
-
alias :status= :code=
|
645
|
-
|
646
|
-
def initialize
|
647
|
-
@header = {}
|
648
|
-
@body = ''
|
649
|
-
@code = nil
|
650
|
-
@query = nil
|
651
|
-
@cookies = []
|
652
|
-
@http_version = '1.1'
|
653
|
-
end
|
654
|
-
|
655
|
-
def read_body
|
656
|
-
yield body
|
657
|
-
end
|
658
|
-
|
659
|
-
def message
|
660
|
-
''
|
661
|
-
end
|
662
|
-
end
|
663
|
-
|