mechanize 2.4 → 2.5
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.
Potentially problematic release.
This version of mechanize might be problematic. Click here for more details.
- data.tar.gz.sig +0 -0
- data/CHANGELOG.rdoc +30 -4
- data/EXAMPLES.rdoc +2 -2
- data/GUIDE.rdoc +13 -13
- data/Manifest.txt +30 -0
- data/README.rdoc +19 -2
- data/lib/mechanize.rb +30 -7
- data/lib/mechanize/chunked_termination_error.rb +7 -0
- data/lib/mechanize/form.rb +7 -5
- data/lib/mechanize/form/radio_button.rb +14 -0
- data/lib/mechanize/http/agent.rb +54 -24
- data/lib/mechanize/http/auth_store.rb +6 -0
- data/lib/mechanize/http/content_disposition_parser.rb +1 -1
- data/lib/mechanize/monkey_patch.rb +3 -2
- data/lib/mechanize/page.rb +0 -2
- data/lib/mechanize/parser.rb +2 -2
- data/lib/mechanize/test_case.rb +70 -435
- data/lib/mechanize/test_case/.document +1 -0
- data/lib/mechanize/test_case/bad_chunking_servlet.rb +14 -0
- data/lib/mechanize/test_case/basic_auth_servlet.rb +24 -0
- data/lib/mechanize/test_case/content_type_servlet.rb +8 -0
- data/lib/mechanize/test_case/digest_auth_servlet.rb +33 -0
- data/lib/mechanize/test_case/file_upload_servlet.rb +20 -0
- data/lib/mechanize/test_case/form_servlet.rb +55 -0
- data/lib/mechanize/test_case/gzip_servlet.rb +32 -0
- data/lib/mechanize/test_case/header_servlet.rb +14 -0
- data/lib/mechanize/test_case/http_refresh_servlet.rb +9 -0
- data/lib/mechanize/test_case/infinite_redirect_servlet.rb +10 -0
- data/lib/mechanize/test_case/infinite_refresh_servlet.rb +10 -0
- data/lib/mechanize/test_case/many_cookies_as_string_servlet.rb +37 -0
- data/lib/mechanize/test_case/many_cookies_servlet.rb +33 -0
- data/lib/mechanize/test_case/modified_since_servlet.rb +21 -0
- data/lib/mechanize/test_case/ntlm_servlet.rb +30 -0
- data/lib/mechanize/test_case/one_cookie_no_spaces_servlet.rb +11 -0
- data/lib/mechanize/test_case/one_cookie_servlet.rb +11 -0
- data/lib/mechanize/test_case/quoted_value_cookie_servlet.rb +11 -0
- data/lib/mechanize/test_case/redirect_servlet.rb +13 -0
- data/lib/mechanize/test_case/referer_servlet.rb +12 -0
- data/lib/mechanize/test_case/refresh_with_empty_url.rb +15 -0
- data/lib/mechanize/test_case/refresh_without_url.rb +14 -0
- data/lib/mechanize/test_case/response_code_servlet.rb +15 -0
- data/lib/mechanize/test_case/send_cookies_servlet.rb +19 -0
- data/lib/mechanize/test_case/server.rb +36 -0
- data/lib/mechanize/test_case/servlets.rb +55 -0
- data/lib/mechanize/test_case/verb_servlet.rb +11 -0
- data/test/test_mechanize.rb +12 -12
- data/test/test_mechanize_file.rb +11 -0
- data/test/test_mechanize_file_response.rb +23 -0
- data/test/test_mechanize_form.rb +34 -0
- data/test/test_mechanize_form_radio_button.rb +19 -2
- data/test/test_mechanize_http_agent.rb +104 -26
- data/test/test_mechanize_http_auth_store.rb +23 -0
- data/test/test_mechanize_http_content_disposition_parser.rb +6 -0
- data/test/test_mechanize_page.rb +3 -5
- data/test/test_mechanize_page_link.rb +0 -32
- metadata +39 -8
- metadata.gz.sig +2 -2
@@ -38,6 +38,8 @@ class Mechanize::HTTP::AuthStore
|
|
38
38
|
# 2617. If +domain+ is given it is only used for NTLM authentication.
|
39
39
|
|
40
40
|
def add_auth uri, user, pass, realm = nil, domain = nil
|
41
|
+
uri = URI uri unless URI === uri
|
42
|
+
|
41
43
|
raise ArgumentError,
|
42
44
|
'NTLM domain given with realm which NTLM does not use' if
|
43
45
|
realm and domain
|
@@ -88,6 +90,8 @@ only to a particular server you specify.
|
|
88
90
|
# Retrieves credentials for +realm+ on the server at +uri+.
|
89
91
|
|
90
92
|
def credentials_for uri, realm
|
93
|
+
uri = URI uri unless URI === uri
|
94
|
+
|
91
95
|
uri += '/'
|
92
96
|
|
93
97
|
realms = @auth_accounts[uri]
|
@@ -100,6 +104,8 @@ only to a particular server you specify.
|
|
100
104
|
# set all credentials for the server at +uri+ are removed.
|
101
105
|
|
102
106
|
def remove_auth uri, realm = nil
|
107
|
+
uri = URI uri unless URI === uri
|
108
|
+
|
103
109
|
uri += '/'
|
104
110
|
|
105
111
|
if realm then
|
data/lib/mechanize/page.rb
CHANGED
@@ -26,8 +26,6 @@ class Mechanize::Page < Mechanize::File
|
|
26
26
|
|
27
27
|
def initialize(uri=nil, response=nil, body=nil, code=nil, mech=nil)
|
28
28
|
response ||= DEFAULT_RESPONSE
|
29
|
-
raise Mechanize::ContentTypeError, response['content-type'] unless
|
30
|
-
response['content-type'] =~ %r{\A(?:text/html|application/xhtml\+xml)(?:$|\s*[\s;,])}i
|
31
29
|
|
32
30
|
@meta_content_type = nil
|
33
31
|
@encoding = nil
|
data/lib/mechanize/parser.rb
CHANGED
@@ -157,12 +157,12 @@ module Mechanize::Parser
|
|
157
157
|
# Finds a free filename based on +filename+, but is not race-free
|
158
158
|
|
159
159
|
def find_free_name filename
|
160
|
-
|
160
|
+
base_filename = filename ||= @filename
|
161
161
|
|
162
162
|
number = 1
|
163
163
|
|
164
164
|
while File.exist? filename do
|
165
|
-
filename = "#{
|
165
|
+
filename = "#{base_filename}.#{number}"
|
166
166
|
number += 1
|
167
167
|
end
|
168
168
|
|
data/lib/mechanize/test_case.rb
CHANGED
@@ -14,11 +14,29 @@ end
|
|
14
14
|
|
15
15
|
require 'minitest/autorun'
|
16
16
|
|
17
|
+
##
|
18
|
+
# A generic test case for testing mechanize. Using a subclass of
|
19
|
+
# Mechanize::TestCase for your tests will create an isolated mechanize
|
20
|
+
# instance that won't pollute your filesystem or other tests.
|
21
|
+
#
|
22
|
+
# Once Mechanize::TestCase is loaded no HTTP requests will be made outside
|
23
|
+
# mechanize itself. All requests are handled via WEBrick servlets.
|
24
|
+
#
|
25
|
+
# Mechanize uses WEBrick servlets to test some functionality. You can run
|
26
|
+
# other HTTP clients against the servlets using:
|
27
|
+
#
|
28
|
+
# ruby -rmechanize/test_case/server -e0
|
29
|
+
#
|
30
|
+
# Which will launch a test server at http://localhost:8000
|
31
|
+
|
17
32
|
class Mechanize::TestCase < MiniTest::Unit::TestCase
|
18
33
|
|
19
34
|
TEST_DIR = File.expand_path '../../../test', __FILE__
|
20
35
|
REQUESTS = []
|
21
36
|
|
37
|
+
##
|
38
|
+
# Creates a clean mechanize instance +@mech+ for use in tests.
|
39
|
+
|
22
40
|
def setup
|
23
41
|
super
|
24
42
|
|
@@ -28,6 +46,10 @@ class Mechanize::TestCase < MiniTest::Unit::TestCase
|
|
28
46
|
@ssl_certificate = nil
|
29
47
|
end
|
30
48
|
|
49
|
+
##
|
50
|
+
# Creates a fake page with URI http://fake.example and an empty, submittable
|
51
|
+
# form.
|
52
|
+
|
31
53
|
def fake_page agent = @mech
|
32
54
|
uri = URI 'http://fake.example/'
|
33
55
|
html = <<-END
|
@@ -41,15 +63,24 @@ class Mechanize::TestCase < MiniTest::Unit::TestCase
|
|
41
63
|
Mechanize::Page.new uri, nil, html, 200, agent
|
42
64
|
end
|
43
65
|
|
66
|
+
##
|
67
|
+
# Is the Encoding constant defined?
|
68
|
+
|
44
69
|
def have_encoding?
|
45
70
|
Object.const_defined? :Encoding
|
46
71
|
end
|
47
72
|
|
73
|
+
##
|
74
|
+
# Creates a Mechanize::Page with the given +body+
|
75
|
+
|
48
76
|
def html_page body
|
49
77
|
uri = URI 'http://example/'
|
50
78
|
Mechanize::Page.new uri, nil, body, 200, @mech
|
51
79
|
end
|
52
80
|
|
81
|
+
##
|
82
|
+
# Runs the block inside a temporary directory
|
83
|
+
|
53
84
|
def in_tmpdir
|
54
85
|
Dir.mktmpdir do |dir|
|
55
86
|
Dir.chdir dir do
|
@@ -58,6 +89,9 @@ class Mechanize::TestCase < MiniTest::Unit::TestCase
|
|
58
89
|
end
|
59
90
|
end
|
60
91
|
|
92
|
+
##
|
93
|
+
# Creates a Nokogiri Node +element+ with the given +attributes+
|
94
|
+
|
61
95
|
def node element, attributes = {}
|
62
96
|
doc = Nokogiri::HTML::Document.new
|
63
97
|
|
@@ -70,6 +104,10 @@ class Mechanize::TestCase < MiniTest::Unit::TestCase
|
|
70
104
|
node
|
71
105
|
end
|
72
106
|
|
107
|
+
##
|
108
|
+
# Creates a Mechanize::Page for the given +uri+ with the given
|
109
|
+
# +content_type+, response +body+ and HTTP status +code+
|
110
|
+
|
73
111
|
def page uri, content_type = 'text/html', body = '', code = 200
|
74
112
|
uri = URI uri unless URI::Generic === uri
|
75
113
|
|
@@ -77,10 +115,16 @@ class Mechanize::TestCase < MiniTest::Unit::TestCase
|
|
77
115
|
@mech)
|
78
116
|
end
|
79
117
|
|
118
|
+
##
|
119
|
+
# Requests made during this tests
|
120
|
+
|
80
121
|
def requests
|
81
122
|
REQUESTS
|
82
123
|
end
|
83
124
|
|
125
|
+
##
|
126
|
+
# An SSL private key. This key is the same across all test runs
|
127
|
+
|
84
128
|
def ssl_private_key
|
85
129
|
@ssl_private_key ||= OpenSSL::PKey::RSA.new <<-KEY
|
86
130
|
-----BEGIN RSA PRIVATE KEY-----
|
@@ -92,6 +136,9 @@ p80joKOug2UUgqOLD2GUSO//AiEA9ssY6AFxjHWuwo/+/rkLmkfO2s1Lz3OeUEWq
|
|
92
136
|
KEY
|
93
137
|
end
|
94
138
|
|
139
|
+
##
|
140
|
+
# An X509 certificate. This certificate is the same across all test runs
|
141
|
+
|
95
142
|
def ssl_certificate
|
96
143
|
@ssl_certificate ||= OpenSSL::X509::Certificate.new <<-CERT
|
97
144
|
-----BEGIN CERTIFICATE-----
|
@@ -106,6 +153,9 @@ UQIBATANBgkqhkiG9w0BAQUFAANBAAAB////////////////////////////////
|
|
106
153
|
CERT
|
107
154
|
end
|
108
155
|
|
156
|
+
##
|
157
|
+
# Creates a Tempfile with +content+ that is immediately unlinked
|
158
|
+
|
109
159
|
def tempfile content
|
110
160
|
body_io = Tempfile.new @__name__
|
111
161
|
body_io.unlink
|
@@ -118,445 +168,18 @@ UQIBATANBgkqhkiG9w0BAQUFAANBAAAB////////////////////////////////
|
|
118
168
|
|
119
169
|
end
|
120
170
|
|
121
|
-
|
122
|
-
def do_GET(req,res)
|
123
|
-
htpd = nil
|
124
|
-
Tempfile.open 'dot.htpasswd' do |io|
|
125
|
-
htpd = WEBrick::HTTPAuth::Htpasswd.new(io.path)
|
126
|
-
htpd.set_passwd('Blah', 'user', 'pass')
|
127
|
-
end
|
128
|
-
|
129
|
-
authenticator = WEBrick::HTTPAuth::BasicAuth.new({
|
130
|
-
:UserDB => htpd,
|
131
|
-
:Realm => 'Blah',
|
132
|
-
:Logger => Logger.new(nil)
|
133
|
-
})
|
134
|
-
|
135
|
-
begin
|
136
|
-
authenticator.authenticate(req,res)
|
137
|
-
res.body = 'You are authenticated'
|
138
|
-
rescue WEBrick::HTTPStatus::Unauthorized
|
139
|
-
res.status = 401
|
140
|
-
end
|
141
|
-
end
|
142
|
-
alias :do_POST :do_GET
|
143
|
-
end
|
144
|
-
|
145
|
-
class ContentTypeServlet < WEBrick::HTTPServlet::AbstractServlet
|
146
|
-
def do_GET(req, res)
|
147
|
-
ct = req.query['ct'] || "text/html; charset=utf-8"
|
148
|
-
res['Content-Type'] = ct
|
149
|
-
res.body = "Hello World"
|
150
|
-
end
|
151
|
-
end
|
152
|
-
|
153
|
-
class DigestAuthServlet < WEBrick::HTTPServlet::AbstractServlet
|
154
|
-
htpd = nil
|
171
|
+
require 'mechanize/test_case/servlets'
|
155
172
|
|
156
|
-
|
157
|
-
htpd = WEBrick::HTTPAuth::Htdigest.new(io.path)
|
158
|
-
htpd.set_passwd('Blah', 'user', 'pass')
|
159
|
-
end
|
160
|
-
|
161
|
-
@@authenticator = WEBrick::HTTPAuth::DigestAuth.new({
|
162
|
-
:UserDB => htpd,
|
163
|
-
:Realm => 'Blah',
|
164
|
-
:Algorithm => 'MD5',
|
165
|
-
:Logger => Logger.new(nil)
|
166
|
-
})
|
167
|
-
|
168
|
-
def do_GET(req,res)
|
169
|
-
def req.request_time; Time.now; end
|
170
|
-
def req.request_uri; '/digest_auth'; end
|
171
|
-
def req.request_method; "GET"; end
|
172
|
-
|
173
|
-
begin
|
174
|
-
@@authenticator.authenticate(req,res)
|
175
|
-
res.body = 'You are authenticated'
|
176
|
-
rescue WEBrick::HTTPStatus::Unauthorized
|
177
|
-
res.status = 401
|
178
|
-
end
|
179
|
-
FileUtils.rm('digest.htpasswd') if File.exists?('digest.htpasswd')
|
180
|
-
end
|
181
|
-
alias :do_POST :do_GET
|
173
|
+
module Net # :nodoc:
|
182
174
|
end
|
183
175
|
|
184
|
-
class
|
185
|
-
def do_POST(req, res)
|
186
|
-
res.body = req.body
|
187
|
-
end
|
188
|
-
end
|
189
|
-
|
190
|
-
class FormServlet < WEBrick::HTTPServlet::AbstractServlet
|
191
|
-
def do_GET(req, res)
|
192
|
-
res.body = "<HTML><body>"
|
193
|
-
req.query.each_key { |k|
|
194
|
-
req.query[k].each_data { |data|
|
195
|
-
res.body << "<a href=\"#\">#{WEBrick::HTTPUtils.unescape(k)}:#{WEBrick::HTTPUtils.unescape(data)}</a><br />"
|
196
|
-
}
|
197
|
-
}
|
198
|
-
res.body << "<div id=\"query\">#{res.query}</div></body></HTML>"
|
199
|
-
res['Content-Type'] = "text/html"
|
200
|
-
end
|
201
|
-
|
202
|
-
def do_POST(req, res)
|
203
|
-
res.body = "<HTML><body>"
|
204
|
-
|
205
|
-
req.query.each_key { |k|
|
206
|
-
req.query[k].each_data { |data|
|
207
|
-
res.body << "<a href=\"#\">#{k}:#{data}</a><br />"
|
208
|
-
}
|
209
|
-
}
|
210
|
-
|
211
|
-
res.body << "<div id=\"query\">#{req.body}</div></body></HTML>"
|
212
|
-
res['Content-Type'] = "text/html"
|
213
|
-
end
|
214
|
-
end
|
215
|
-
|
216
|
-
class GzipServlet < WEBrick::HTTPServlet::AbstractServlet
|
217
|
-
def do_GET(req, res)
|
218
|
-
if req['Accept-Encoding'] =~ /gzip/
|
219
|
-
if name = req.query['file'] then
|
220
|
-
open("#{Mechanize::TestCase::TEST_DIR}/htdocs/#{name}", 'r') do |io|
|
221
|
-
string = ""
|
222
|
-
zipped = StringIO.new string, 'w'
|
223
|
-
Zlib::GzipWriter.wrap zipped do |gz|
|
224
|
-
gz.write io.read
|
225
|
-
end
|
226
|
-
res.body = string
|
227
|
-
end
|
228
|
-
else
|
229
|
-
res.body = ''
|
230
|
-
end
|
231
|
-
res['Content-Encoding'] = req['X-ResponseContentEncoding'] || 'gzip'
|
232
|
-
res['Content-Type'] = "text/html"
|
233
|
-
else
|
234
|
-
res.code = 400
|
235
|
-
res.body = 'no gzip'
|
236
|
-
end
|
237
|
-
end
|
238
|
-
end
|
239
|
-
|
240
|
-
class HeaderServlet < WEBrick::HTTPServlet::AbstractServlet
|
241
|
-
def do_GET(req, res)
|
242
|
-
res['Content-Type'] = "text/html"
|
243
|
-
|
244
|
-
req.query.each do |x,y|
|
245
|
-
res[x] = y
|
246
|
-
end
|
247
|
-
|
248
|
-
body = ''
|
249
|
-
req.each_header do |k,v|
|
250
|
-
body << "#{k}|#{v}\n"
|
251
|
-
end
|
252
|
-
res.body = body
|
253
|
-
end
|
254
|
-
end
|
255
|
-
|
256
|
-
class HttpRefreshServlet < WEBrick::HTTPServlet::AbstractServlet
|
257
|
-
def do_GET(req, res)
|
258
|
-
res['Content-Type'] = req.query['ct'] || "text/html"
|
259
|
-
refresh_time = req.query['refresh_time'] || 0
|
260
|
-
refresh_url = req.query['refresh_url'] || '/index.html'
|
261
|
-
res['Refresh'] = " #{refresh_time};url=#{refresh_url}\r\n";
|
262
|
-
end
|
263
|
-
end
|
264
|
-
|
265
|
-
class InfiniteRedirectServlet < WEBrick::HTTPServlet::AbstractServlet
|
266
|
-
def do_GET(req, res)
|
267
|
-
res['Content-Type'] = req.query['ct'] || "text/html"
|
268
|
-
res.status = req.query['code'] ? req.query['code'].to_i : '302'
|
269
|
-
number = req.query['q'] ? req.query['q'].to_i : 0
|
270
|
-
res['Location'] = "/infinite_redirect?q=#{number + 1}"
|
271
|
-
end
|
272
|
-
alias :do_POST :do_GET
|
273
|
-
end
|
274
|
-
|
275
|
-
class InfiniteRefreshServlet < WEBrick::HTTPServlet::AbstractServlet
|
276
|
-
def do_GET(req, res)
|
277
|
-
res['Content-Type'] = req.query['ct'] || "text/html"
|
278
|
-
res.status = req.query['code'] ? req.query['code'].to_i : '302'
|
279
|
-
number = req.query['q'] ? req.query['q'].to_i : 0
|
280
|
-
res['Refresh'] = " 0;url=http://localhost/infinite_refresh?q=#{number + 1}\r\n";
|
281
|
-
end
|
282
|
-
end
|
283
|
-
|
284
|
-
class ManyCookiesAsStringServlet < WEBrick::HTTPServlet::AbstractServlet
|
285
|
-
def do_GET(req, res)
|
286
|
-
cookies = []
|
287
|
-
name_cookie = WEBrick::Cookie.new("name", "Aaron")
|
288
|
-
name_cookie.path = "/"
|
289
|
-
name_cookie.expires = Time.now + 86400
|
290
|
-
name_cookie.domain = 'localhost'
|
291
|
-
cookies << name_cookie
|
292
|
-
cookies << name_cookie
|
293
|
-
cookies << name_cookie
|
294
|
-
cookies << "#{name_cookie}; HttpOnly"
|
295
|
-
|
296
|
-
expired_cookie = WEBrick::Cookie.new("expired", "doh")
|
297
|
-
expired_cookie.path = "/"
|
298
|
-
expired_cookie.expires = Time.now - 86400
|
299
|
-
cookies << expired_cookie
|
300
|
-
|
301
|
-
different_path_cookie = WEBrick::Cookie.new("a_path", "some_path")
|
302
|
-
different_path_cookie.path = "/some_path"
|
303
|
-
different_path_cookie.expires = Time.now + 86400
|
304
|
-
cookies << different_path_cookie
|
305
|
-
|
306
|
-
no_path_cookie = WEBrick::Cookie.new("no_path", "no_path")
|
307
|
-
no_path_cookie.expires = Time.now + 86400
|
308
|
-
cookies << no_path_cookie
|
309
|
-
|
310
|
-
no_exp_path_cookie = WEBrick::Cookie.new("no_expires", "nope")
|
311
|
-
no_exp_path_cookie.path = "/"
|
312
|
-
cookies << no_exp_path_cookie
|
313
|
-
|
314
|
-
res['Set-Cookie'] = cookies.join(', ')
|
315
|
-
|
316
|
-
res['Content-Type'] = "text/html"
|
317
|
-
res.body = "<html><body>hello</body></html>"
|
318
|
-
end
|
319
|
-
end
|
320
|
-
|
321
|
-
class ManyCookiesServlet < WEBrick::HTTPServlet::AbstractServlet
|
322
|
-
def do_GET(req, res)
|
323
|
-
name_cookie = WEBrick::Cookie.new("name", "Aaron")
|
324
|
-
name_cookie.path = "/"
|
325
|
-
name_cookie.expires = Time.now + 86400
|
326
|
-
res.cookies << name_cookie
|
327
|
-
res.cookies << name_cookie
|
328
|
-
res.cookies << name_cookie
|
329
|
-
res.cookies << name_cookie
|
330
|
-
|
331
|
-
expired_cookie = WEBrick::Cookie.new("expired", "doh")
|
332
|
-
expired_cookie.path = "/"
|
333
|
-
expired_cookie.expires = Time.now - 86400
|
334
|
-
res.cookies << expired_cookie
|
335
|
-
|
336
|
-
different_path_cookie = WEBrick::Cookie.new("a_path", "some_path")
|
337
|
-
different_path_cookie.path = "/some_path"
|
338
|
-
different_path_cookie.expires = Time.now + 86400
|
339
|
-
res.cookies << different_path_cookie
|
340
|
-
|
341
|
-
no_path_cookie = WEBrick::Cookie.new("no_path", "no_path")
|
342
|
-
no_path_cookie.expires = Time.now + 86400
|
343
|
-
res.cookies << no_path_cookie
|
344
|
-
|
345
|
-
no_exp_path_cookie = WEBrick::Cookie.new("no_expires", "nope")
|
346
|
-
no_exp_path_cookie.path = "/"
|
347
|
-
res.cookies << no_exp_path_cookie
|
348
|
-
|
349
|
-
res['Content-Type'] = "text/html"
|
350
|
-
res.body = "<html><body>hello</body></html>"
|
351
|
-
end
|
352
|
-
end
|
353
|
-
|
354
|
-
class ModifiedSinceServlet < WEBrick::HTTPServlet::AbstractServlet
|
355
|
-
def do_GET(req, res)
|
356
|
-
s_time = 'Fri, 04 May 2001 00:00:38 GMT'
|
357
|
-
|
358
|
-
my_time = Time.parse(s_time)
|
359
|
-
|
360
|
-
if req['If-Modified-Since']
|
361
|
-
your_time = Time.parse(req['If-Modified-Since'])
|
362
|
-
if my_time > your_time
|
363
|
-
res.body = 'This page was updated since you requested'
|
364
|
-
else
|
365
|
-
res.status = 304
|
366
|
-
end
|
367
|
-
else
|
368
|
-
res.body = 'You did not send an If-Modified-Since header'
|
369
|
-
end
|
370
|
-
|
371
|
-
res['Last-Modified'] = s_time
|
372
|
-
end
|
373
|
-
end
|
374
|
-
|
375
|
-
class NTLMServlet < WEBrick::HTTPServlet::AbstractServlet
|
376
|
-
|
377
|
-
def do_GET(req, res)
|
378
|
-
if req['Authorization'] =~ /^NTLM (.*)/ then
|
379
|
-
authorization = $1.unpack('m*').first
|
380
|
-
|
381
|
-
if authorization =~ /^NTLMSSP\000\001/ then
|
382
|
-
type_2 = 'TlRMTVNTUAACAAAADAAMADAAAAABAoEAASNFZ4mr' \
|
383
|
-
'ze8AAAAAAAAAAGIAYgA8AAAARABPAE0AQQBJAE4A' \
|
384
|
-
'AgAMAEQATwBNAEEASQBOAAEADABTAEUAUgBWAEUA' \
|
385
|
-
'UgAEABQAZABvAG0AYQBpAG4ALgBjAG8AbQADACIA' \
|
386
|
-
'cwBlAHIAdgBlAHIALgBkAG8AbQBhAGkAbgAuAGMA' \
|
387
|
-
'bwBtAAAAAAA='
|
388
|
-
|
389
|
-
res['WWW-Authenticate'] = "NTLM #{type_2}"
|
390
|
-
res.status = 401
|
391
|
-
elsif authorization =~ /^NTLMSSP\000\003/ then
|
392
|
-
res.body = 'ok'
|
393
|
-
else
|
394
|
-
res['WWW-Authenticate'] = 'NTLM'
|
395
|
-
res.status = 401
|
396
|
-
end
|
397
|
-
else
|
398
|
-
res['WWW-Authenticate'] = 'NTLM'
|
399
|
-
res.status = 401
|
400
|
-
end
|
401
|
-
end
|
402
|
-
|
403
|
-
end
|
404
|
-
|
405
|
-
class OneCookieNoSpacesServlet < WEBrick::HTTPServlet::AbstractServlet
|
406
|
-
def do_GET(req, res)
|
407
|
-
cookie = WEBrick::Cookie.new("foo", "bar")
|
408
|
-
cookie.path = "/"
|
409
|
-
cookie.expires = Time.now + 86400
|
410
|
-
res.cookies << cookie.to_s.gsub(/; /, ';')
|
411
|
-
res['Content-Type'] = "text/html"
|
412
|
-
res.body = "<html><body>hello</body></html>"
|
413
|
-
end
|
414
|
-
end
|
415
|
-
|
416
|
-
class OneCookieServlet < WEBrick::HTTPServlet::AbstractServlet
|
417
|
-
def do_GET(req, res)
|
418
|
-
cookie = WEBrick::Cookie.new("foo", "bar")
|
419
|
-
cookie.path = "/"
|
420
|
-
cookie.expires = Time.now + 86400
|
421
|
-
res.cookies << cookie
|
422
|
-
res['Content-Type'] = "text/html"
|
423
|
-
res.body = "<html><body>hello</body></html>"
|
424
|
-
end
|
425
|
-
end
|
426
|
-
|
427
|
-
class QuotedValueCookieServlet < WEBrick::HTTPServlet::AbstractServlet
|
428
|
-
def do_GET(req, res)
|
429
|
-
cookie = WEBrick::Cookie.new("quoted", "\"value\"")
|
430
|
-
cookie.path = "/"
|
431
|
-
cookie.expires = Time.now + 86400
|
432
|
-
res.cookies << cookie
|
433
|
-
res['Content-Type'] = "text/html"
|
434
|
-
res.body = "<html><body>hello</body></html>"
|
435
|
-
end
|
436
|
-
end
|
437
|
-
|
438
|
-
class RedirectServlet < WEBrick::HTTPServlet::AbstractServlet
|
439
|
-
def do_GET(req, res)
|
440
|
-
res['Content-Type'] = req.query['ct'] || "text/html"
|
441
|
-
res.status = req.query['code'] ? req.query['code'].to_i : '302'
|
442
|
-
res['Location'] = "/verb"
|
443
|
-
end
|
444
|
-
|
445
|
-
alias :do_POST :do_GET
|
446
|
-
alias :do_HEAD :do_GET
|
447
|
-
alias :do_PUT :do_GET
|
448
|
-
alias :do_DELETE :do_GET
|
449
|
-
end
|
450
|
-
|
451
|
-
class RefererServlet < WEBrick::HTTPServlet::AbstractServlet
|
452
|
-
def do_GET(req, res)
|
453
|
-
res['Content-Type'] = "text/html"
|
454
|
-
res.body = req['Referer'] || ''
|
455
|
-
end
|
456
|
-
|
457
|
-
def do_POST(req, res)
|
458
|
-
res['Content-Type'] = "text/html"
|
459
|
-
res.body = req['Referer'] || ''
|
460
|
-
end
|
461
|
-
end
|
462
|
-
|
463
|
-
class RefreshWithoutUrl < WEBrick::HTTPServlet::AbstractServlet
|
464
|
-
@@count = 0
|
465
|
-
def do_GET(req, res)
|
466
|
-
res['Content-Type'] = "text/html"
|
467
|
-
@@count += 1
|
468
|
-
if @@count > 1
|
469
|
-
res['Refresh'] = "0; url=http://localhost/index.html";
|
470
|
-
else
|
471
|
-
res['Refresh'] = "0";
|
472
|
-
end
|
473
|
-
end
|
474
|
-
end
|
475
|
-
|
476
|
-
class RefreshWithEmptyUrl < WEBrick::HTTPServlet::AbstractServlet
|
477
|
-
@@count = 0
|
478
|
-
def do_GET(req, res)
|
479
|
-
res['Content-Type'] = "text/html"
|
480
|
-
@@count += 1
|
481
|
-
if @@count > 1
|
482
|
-
res['Refresh'] = "0; url=http://localhost/index.html";
|
483
|
-
else
|
484
|
-
res['Refresh'] = "0; url=";
|
485
|
-
end
|
486
|
-
end
|
487
|
-
end
|
488
|
-
|
489
|
-
class ResponseCodeServlet < WEBrick::HTTPServlet::AbstractServlet
|
490
|
-
def do_GET(req, res)
|
491
|
-
res['Content-Type'] = req.query['ct'] || "text/html"
|
492
|
-
if req.query['code']
|
493
|
-
code = req.query['code'].to_i
|
494
|
-
case code
|
495
|
-
when 300, 301, 302, 303, 304, 305, 307
|
496
|
-
res['Location'] = "/index.html"
|
497
|
-
end
|
498
|
-
res.status = code
|
499
|
-
else
|
500
|
-
end
|
501
|
-
end
|
502
|
-
end
|
503
|
-
|
504
|
-
class SendCookiesServlet < WEBrick::HTTPServlet::AbstractServlet
|
505
|
-
def do_GET(req, res)
|
506
|
-
res['Content-Type'] = "text/html"
|
507
|
-
res.body = "<html><body>"
|
508
|
-
req.cookies.each { |c|
|
509
|
-
res.body << "<a href=\"#\">#{c.name}:#{c.value}</a>"
|
510
|
-
}
|
511
|
-
res.body << "</body></html>"
|
512
|
-
end
|
513
|
-
end
|
514
|
-
|
515
|
-
class VerbServlet < WEBrick::HTTPServlet::AbstractServlet
|
516
|
-
%w(HEAD GET POST PUT DELETE).each do |verb|
|
517
|
-
eval(<<-eomethod)
|
518
|
-
def do_#{verb}(req, res)
|
519
|
-
res.header['X-Request-Method'] = #{verb.dump}
|
520
|
-
end
|
521
|
-
eomethod
|
522
|
-
end
|
523
|
-
end
|
524
|
-
|
525
|
-
class Net::HTTP
|
176
|
+
class Net::HTTP # :nodoc:
|
526
177
|
alias :old_do_start :do_start
|
527
178
|
|
528
179
|
def do_start
|
529
180
|
@started = true
|
530
181
|
end
|
531
182
|
|
532
|
-
SERVLETS = {
|
533
|
-
'/gzip' => GzipServlet,
|
534
|
-
'/form_post' => FormServlet,
|
535
|
-
'/basic_auth' => BasicAuthServlet,
|
536
|
-
'/form post' => FormServlet,
|
537
|
-
'/response_code' => ResponseCodeServlet,
|
538
|
-
'/http_refresh' => HttpRefreshServlet,
|
539
|
-
'/content_type_test' => ContentTypeServlet,
|
540
|
-
'/referer' => RefererServlet,
|
541
|
-
'/file_upload' => FileUploadServlet,
|
542
|
-
'/one_cookie' => OneCookieServlet,
|
543
|
-
'/one_cookie_no_space' => OneCookieNoSpacesServlet,
|
544
|
-
'/many_cookies' => ManyCookiesServlet,
|
545
|
-
'/many_cookies_as_string' => ManyCookiesAsStringServlet,
|
546
|
-
'/ntlm' => NTLMServlet,
|
547
|
-
'/send_cookies' => SendCookiesServlet,
|
548
|
-
'/quoted_value_cookie' => QuotedValueCookieServlet,
|
549
|
-
'/if_modified_since' => ModifiedSinceServlet,
|
550
|
-
'/http_headers' => HeaderServlet,
|
551
|
-
'/infinite_redirect' => InfiniteRedirectServlet,
|
552
|
-
'/infinite_refresh' => InfiniteRefreshServlet,
|
553
|
-
'/redirect' => RedirectServlet,
|
554
|
-
'/refresh_without_url' => RefreshWithoutUrl,
|
555
|
-
'/refresh_with_empty_url' => RefreshWithEmptyUrl,
|
556
|
-
'/digest_auth' => DigestAuthServlet,
|
557
|
-
'/verb' => VerbServlet,
|
558
|
-
}
|
559
|
-
|
560
183
|
PAGE_CACHE = {}
|
561
184
|
|
562
185
|
alias :old_request :request
|
@@ -585,7 +208,7 @@ class Net::HTTP
|
|
585
208
|
|
586
209
|
Mechanize::TestCase::REQUESTS << req
|
587
210
|
|
588
|
-
if servlet_klass =
|
211
|
+
if servlet_klass = MECHANIZE_TEST_CASE_SERVLETS[path]
|
589
212
|
servlet = servlet_klass.new({})
|
590
213
|
servlet.send "do_#{req.method}", req, res
|
591
214
|
else
|
@@ -625,8 +248,12 @@ class Net::HTTP
|
|
625
248
|
|
626
249
|
io = StringIO.new(res.body)
|
627
250
|
response.instance_variable_set :@socket, io
|
628
|
-
def io.read clen, dest, _
|
629
|
-
dest
|
251
|
+
def io.read clen, dest = nil, _ = nil
|
252
|
+
if dest then
|
253
|
+
dest << super(clen)
|
254
|
+
else
|
255
|
+
super clen
|
256
|
+
end
|
630
257
|
end
|
631
258
|
|
632
259
|
body_exist = req.response_body_permitted? &&
|
@@ -640,11 +267,19 @@ class Net::HTTP
|
|
640
267
|
end
|
641
268
|
end
|
642
269
|
|
643
|
-
class Net::HTTPRequest
|
270
|
+
class Net::HTTPRequest # :nodoc:
|
644
271
|
attr_accessor :query, :body, :cookies, :user
|
272
|
+
|
273
|
+
def host
|
274
|
+
'example'
|
275
|
+
end
|
276
|
+
|
277
|
+
def port
|
278
|
+
80
|
279
|
+
end
|
645
280
|
end
|
646
281
|
|
647
|
-
class Response
|
282
|
+
class Response # :nodoc:
|
648
283
|
include Net::HTTPHeader
|
649
284
|
|
650
285
|
attr_reader :code
|