diamond-mechanize 2.1 → 2.2
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.
- 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
|
-
|