glebtv-httpclient 3.0.2 → 3.1.0
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.
- checksums.yaml +4 -4
- data/README.md +173 -0
- data/lib/httpclient.rb +1 -1
- data/lib/httpclient/version.rb +1 -1
- data/test/test_httpclient.rb +3 -0
- metadata +34 -38
- data/README.rdoc +0 -108
- data/lib/http-access2.rb +0 -55
- data/lib/http-access2/cookie.rb +0 -1
- data/lib/http-access2/http.rb +0 -1
- data/test/test_http-access2.rb +0 -507
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2e0d58e8386526ded8469cb960b0467c25bb5f66
|
4
|
+
data.tar.gz: 3878a8b5e3846806535aba2c68c268a2edfdd74c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6caeace7cf8c7a9d288f7b84d7a03c08a1a24905f480e6d9881d610e3c98e6f508960107850ca37d15e8e1e4649784d5614a2f88bf1e1f696451f29d993ba2b6
|
7
|
+
data.tar.gz: 744bd70d9962218693a973d9042f6ddf7966078314043cdfad75b86801897a6c6d4ce9e7331b5ccb6b9ae922eb171642acca10a160012500c1004209c3fb0e78
|
data/README.md
ADDED
@@ -0,0 +1,173 @@
|
|
1
|
+
## About this fork
|
2
|
+
|
3
|
+
I just try to make it work properly (as a browser would) for my use cases.
|
4
|
+
|
5
|
+
[](https://travis-ci.org/glebtv/httpclient)
|
6
|
+
[](http://badge.fury.io/rb/glebtv-httpclient)
|
7
|
+
[](https://gemnasium.com/glebtv/httpclient)
|
8
|
+
|
9
|
+
If you don't like how something works, please send a PR or use original gem: https://github.com/nahi/httpclient
|
10
|
+
|
11
|
+
## Install
|
12
|
+
|
13
|
+
gem install glebtv-httpclient
|
14
|
+
|
15
|
+
or
|
16
|
+
|
17
|
+
gem 'httpclient'
|
18
|
+
|
19
|
+
|
20
|
+
## Usage example:
|
21
|
+
|
22
|
+
To serve as a starting point (cannot be used as-is, you will need to adjust settings, paths, etc)
|
23
|
+
|
24
|
+
```ruby
|
25
|
+
class Ht
|
26
|
+
attr_accessor :user_agent, :clnt, :cookie_jar, :referer
|
27
|
+
|
28
|
+
def initialize()
|
29
|
+
@user_agent = 'test_app'
|
30
|
+
|
31
|
+
@cookie_jar = ROOT_PATH + '/cookies.txt'
|
32
|
+
@referer = nil
|
33
|
+
@clnt = HTTPClient.new
|
34
|
+
|
35
|
+
@clnt.set_cookie_store(@cookie_jar)
|
36
|
+
# @clnt.socket_local.host = 'ip here'
|
37
|
+
@clnt.transparent_gzip_decompression = true
|
38
|
+
# @clnt.debug_dev = STDERR
|
39
|
+
end
|
40
|
+
|
41
|
+
def flush_cookies
|
42
|
+
@clnt.save_cookie_store
|
43
|
+
end
|
44
|
+
|
45
|
+
def urify(uri)
|
46
|
+
HTTPClient::Util.urify(uri)
|
47
|
+
end
|
48
|
+
|
49
|
+
def request(method, uri, params = nil)
|
50
|
+
if method.to_s == 'get'
|
51
|
+
query = params
|
52
|
+
body = nil
|
53
|
+
else
|
54
|
+
query = nil
|
55
|
+
body = URI.encode_www_form(params)
|
56
|
+
end
|
57
|
+
|
58
|
+
process(method, uri, query: query, body: body)
|
59
|
+
end
|
60
|
+
|
61
|
+
def process(method, uri, options)
|
62
|
+
retry_number = 0
|
63
|
+
while retry_number < 10
|
64
|
+
options = options.merge(header: headers, follow_redirect: false)
|
65
|
+
res = @clnt.request(method, uri.to_s, options)
|
66
|
+
if res.redirect?
|
67
|
+
if res.see_other? || res.found?
|
68
|
+
method = :get
|
69
|
+
options.delete(:body)
|
70
|
+
end
|
71
|
+
@referer = uri.to_s
|
72
|
+
uri = @clnt.default_redirect_uri_callback(urify(uri), res)
|
73
|
+
$logger.info "redirect to #{uri}"
|
74
|
+
retry_number += 1
|
75
|
+
else
|
76
|
+
@referer = uri.to_s
|
77
|
+
if res.ok?
|
78
|
+
return res
|
79
|
+
else
|
80
|
+
puts "BAD RESPONSE FOR #{uri}"
|
81
|
+
p options
|
82
|
+
puts "HEADER:"
|
83
|
+
puts res.header.dump
|
84
|
+
puts "CONTENT:"
|
85
|
+
puts res.content
|
86
|
+
raise HTTPClient::BadResponseError.new("unexpected response", res)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
raise 'redirect loop detected'
|
91
|
+
end
|
92
|
+
|
93
|
+
def headers
|
94
|
+
ret = {
|
95
|
+
'Accept' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
|
96
|
+
'Accept-Language' => 'ru,en;q=0.5',
|
97
|
+
'User-Agent' => @user_agent,
|
98
|
+
}
|
99
|
+
ret['Referer'] = @referer unless @referer.nil?
|
100
|
+
ret
|
101
|
+
end
|
102
|
+
end
|
103
|
+
```
|
104
|
+
|
105
|
+
|
106
|
+
## Original gem readme
|
107
|
+
|
108
|
+
httpclient - HTTP accessing library.
|
109
|
+
Copyright (C) 2000-2012 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
|
110
|
+
|
111
|
+
'httpclient' gives something like the functionality of libwww-perl (LWP) in
|
112
|
+
Ruby. 'httpclient' formerly known as 'http-access2'.
|
113
|
+
|
114
|
+
See HTTPClient for documentation.
|
115
|
+
|
116
|
+
|
117
|
+
## Features
|
118
|
+
|
119
|
+
* methods like GET/HEAD/POST/* via HTTP/1.1.
|
120
|
+
* HTTPS(SSL), Cookies, proxy, authentication(Digest, NTLM, Basic), etc.
|
121
|
+
* asynchronous HTTP request, streaming HTTP request.
|
122
|
+
* debug mode CLI.
|
123
|
+
|
124
|
+
* by contrast with net/http in standard distribution;
|
125
|
+
* Cookies support
|
126
|
+
* MT-safe
|
127
|
+
* streaming POST (POST with File/IO)
|
128
|
+
* Digest auth
|
129
|
+
* Negotiate/NTLM auth for WWW-Authenticate (requires net/ntlm module; rubyntlm gem)
|
130
|
+
* NTLM auth for Proxy-Authenticate (requires 'win32/sspi' module; rubysspi gem)
|
131
|
+
* extensible with filter interface
|
132
|
+
* you don't have to care HTTP/1.1 persistent connection
|
133
|
+
(httpclient cares instead of you)
|
134
|
+
|
135
|
+
* Not supported now
|
136
|
+
* Cache
|
137
|
+
* Rather advanced HTTP/1.1 usage such as Range, deflate, etc.
|
138
|
+
(of course you can set it in header by yourself)
|
139
|
+
|
140
|
+
## httpclient command
|
141
|
+
|
142
|
+
Usage:
|
143
|
+
|
144
|
+
Issues a GET request to the given URI and shows the wiredump and the parsed result:
|
145
|
+
|
146
|
+
% httpclient get https://www.google.co.jp/ q=ruby
|
147
|
+
|
148
|
+
Invokes irb shell with the binding that has a HTTPClient as 'self':
|
149
|
+
|
150
|
+
% httpclient
|
151
|
+
|
152
|
+
You can call HTTPClient instance methods like:
|
153
|
+
|
154
|
+
> get "https://www.google.co.jp/", :q => :ruby
|
155
|
+
|
156
|
+
## Author
|
157
|
+
|
158
|
+
Name:: Hiroshi Nakamura
|
159
|
+
E-mail:: nahi@ruby-lang.org
|
160
|
+
Project web site:: http://github.com/nahi/httpclient
|
161
|
+
|
162
|
+
|
163
|
+
## License
|
164
|
+
|
165
|
+
This program is copyrighted free software by NAKAMURA, Hiroshi. You can
|
166
|
+
redistribute it and/or modify it under the same terms of Ruby's license;
|
167
|
+
either the dual license version in 2003, or any later version.
|
168
|
+
|
169
|
+
httpclient/session.rb is based on http-access.rb in http-access/0.0.4. Some
|
170
|
+
part of it is copyrighted by Maebashi-san who made and published
|
171
|
+
http-access/0.0.4. http-access/0.0.4 did not include license notice but when
|
172
|
+
I asked Maebashi-san he agreed that I can redistribute it under the same terms
|
173
|
+
of Ruby. Many thanks to Maebashi-san.
|
data/lib/httpclient.rb
CHANGED
data/lib/httpclient/version.rb
CHANGED
data/test/test_httpclient.rb
CHANGED
@@ -607,7 +607,10 @@ EOS
|
|
607
607
|
|
608
608
|
# all browsers use GET for 302
|
609
609
|
post_body = StringIO.new("1234567890")
|
610
|
+
assert_equal('1234567890', @client.post_content(serverurl + 'servlet_413', post_body))
|
611
|
+
|
610
612
|
assert_equal('', @client.get_content(serverurl + 'servlet_redirect_413'))
|
613
|
+
post_body = StringIO.new("1234567890")
|
611
614
|
assert_equal('', @client.post_content(serverurl + 'servlet_redirect_413', post_body))
|
612
615
|
|
613
616
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: glebtv-httpclient
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.0
|
4
|
+
version: 3.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- glebtv
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-
|
11
|
+
date: 2013-11-17 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description:
|
14
14
|
email: glebtv@gmail.com
|
@@ -18,62 +18,58 @@ extensions: []
|
|
18
18
|
extra_rdoc_files: []
|
19
19
|
files:
|
20
20
|
- bin/httpclient
|
21
|
-
- lib/
|
22
|
-
- lib/
|
23
|
-
- lib/httpclient/ssl_config.rb
|
24
|
-
- lib/httpclient/cacert.p7s
|
21
|
+
- lib/httpclient.rb
|
22
|
+
- lib/glebtv-httpclient.rb
|
25
23
|
- lib/httpclient/connection.rb
|
26
|
-
- lib/httpclient/session.rb
|
27
24
|
- lib/httpclient/http.rb
|
28
|
-
- lib/httpclient/util.rb
|
29
25
|
- lib/httpclient/version.rb
|
30
|
-
- lib/httpclient/auth.rb
|
31
26
|
- lib/httpclient/include_client.rb
|
32
|
-
- lib/httpclient/
|
27
|
+
- lib/httpclient/auth.rb
|
33
28
|
- lib/httpclient/cookie.rb
|
34
|
-
- lib/httpclient.rb
|
35
|
-
- lib/
|
29
|
+
- lib/httpclient/util.rb
|
30
|
+
- lib/httpclient/timeout.rb
|
31
|
+
- lib/httpclient/ssl_config.rb
|
32
|
+
- lib/httpclient/session.rb
|
33
|
+
- lib/httpclient/cacert.p7s
|
36
34
|
- lib/hexdump.rb
|
37
|
-
- lib/
|
38
|
-
-
|
35
|
+
- lib/oauthclient.rb
|
36
|
+
- sample/ssl/webrick_httpsd.rb
|
37
|
+
- sample/ssl/0key.pem
|
38
|
+
- sample/ssl/htdocs/index.html
|
39
39
|
- sample/ssl/1000cert.pem
|
40
40
|
- sample/ssl/0cert.pem
|
41
|
-
- sample/ssl/htdocs/index.html
|
42
41
|
- sample/ssl/1000key.pem
|
43
|
-
- sample/ssl/0key.pem
|
44
42
|
- sample/ssl/ssl_client.rb
|
45
|
-
- sample/
|
46
|
-
- sample/
|
43
|
+
- sample/stream.rb
|
44
|
+
- sample/async.rb
|
47
45
|
- sample/howto.rb
|
48
46
|
- sample/auth.rb
|
47
|
+
- sample/cookie.rb
|
48
|
+
- sample/wcat.rb
|
49
|
+
- sample/oauth_buzz.rb
|
49
50
|
- sample/thread.rb
|
51
|
+
- sample/dav.rb
|
50
52
|
- sample/oauth_twitter.rb
|
51
|
-
- sample/stream.rb
|
52
|
-
- sample/async.rb
|
53
|
-
- sample/cookie.rb
|
54
53
|
- sample/oauth_friendfeed.rb
|
55
|
-
-
|
56
|
-
-
|
57
|
-
- test/htpasswd
|
58
|
-
- test/sslsvr.rb
|
59
|
-
- test/test_cookie.rb
|
54
|
+
- test/ca-chain.cert
|
55
|
+
- test/test_hexdump.rb
|
60
56
|
- test/htdigest
|
61
|
-
- test/test_ssl.rb
|
62
|
-
- test/subca.cert
|
63
|
-
- test/test_http-access2.rb
|
64
|
-
- test/test_httpclient.rb
|
65
57
|
- test/server.key
|
66
|
-
- test/
|
67
|
-
- test/helper.rb
|
68
|
-
- test/test_auth.rb
|
69
|
-
- test/test_include_client.rb
|
58
|
+
- test/test_cookie.rb
|
70
59
|
- test/client.cert
|
71
|
-
- test/
|
60
|
+
- test/htpasswd
|
72
61
|
- test/server.cert
|
62
|
+
- test/ca.cert
|
63
|
+
- test/helper.rb
|
64
|
+
- test/test_auth.rb
|
65
|
+
- test/sslsvr.rb
|
73
66
|
- test/client.key
|
67
|
+
- test/test_ssl.rb
|
68
|
+
- test/subca.cert
|
69
|
+
- test/test_include_client.rb
|
74
70
|
- test/runner.rb
|
75
|
-
- test/
|
76
|
-
- README.
|
71
|
+
- test/test_httpclient.rb
|
72
|
+
- README.md
|
77
73
|
homepage: http://github.com/glebtv/httpclient
|
78
74
|
licenses:
|
79
75
|
- ruby
|
@@ -94,7 +90,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
94
90
|
version: '0'
|
95
91
|
requirements: []
|
96
92
|
rubyforge_project:
|
97
|
-
rubygems_version: 2.
|
93
|
+
rubygems_version: 2.1.10
|
98
94
|
signing_key:
|
99
95
|
specification_version: 4
|
100
96
|
summary: Fork of httpclient with some fixes and patches I needed. Please use original
|
data/README.rdoc
DELETED
@@ -1,108 +0,0 @@
|
|
1
|
-
httpclient - HTTP accessing library.
|
2
|
-
Copyright (C) 2000-2012 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
|
3
|
-
|
4
|
-
'httpclient' gives something like the functionality of libwww-perl (LWP) in
|
5
|
-
Ruby. 'httpclient' formerly known as 'http-access2'.
|
6
|
-
|
7
|
-
See HTTPClient for documentation.
|
8
|
-
|
9
|
-
|
10
|
-
== Features
|
11
|
-
|
12
|
-
* methods like GET/HEAD/POST/* via HTTP/1.1.
|
13
|
-
* HTTPS(SSL), Cookies, proxy, authentication(Digest, NTLM, Basic), etc.
|
14
|
-
* asynchronous HTTP request, streaming HTTP request.
|
15
|
-
* debug mode CLI.
|
16
|
-
|
17
|
-
* by contrast with net/http in standard distribution;
|
18
|
-
* Cookies support
|
19
|
-
* MT-safe
|
20
|
-
* streaming POST (POST with File/IO)
|
21
|
-
* Digest auth
|
22
|
-
* Negotiate/NTLM auth for WWW-Authenticate (requires net/ntlm module; rubyntlm gem)
|
23
|
-
* NTLM auth for Proxy-Authenticate (requires 'win32/sspi' module; rubysspi gem)
|
24
|
-
* extensible with filter interface
|
25
|
-
* you don't have to care HTTP/1.1 persistent connection
|
26
|
-
(httpclient cares instead of you)
|
27
|
-
|
28
|
-
* Not supported now
|
29
|
-
* Cache
|
30
|
-
* Rather advanced HTTP/1.1 usage such as Range, deflate, etc.
|
31
|
-
(of course you can set it in header by yourself)
|
32
|
-
|
33
|
-
== httpclient command
|
34
|
-
|
35
|
-
Usage: 1) % httpclient get https://www.google.co.jp/ q=ruby
|
36
|
-
Usage: 2) % httpclient
|
37
|
-
|
38
|
-
For 1) it issues a GET request to the given URI and shows the wiredump and
|
39
|
-
the parsed result. For 2) it invokes irb shell with the binding that has a
|
40
|
-
HTTPClient as 'self'.
|
41
|
-
|
42
|
-
You can call HTTPClient instance methods like:
|
43
|
-
|
44
|
-
> get "https://www.google.co.jp/", :q => :ruby
|
45
|
-
|
46
|
-
== Author
|
47
|
-
|
48
|
-
Name:: Hiroshi Nakamura
|
49
|
-
E-mail:: nahi@ruby-lang.org
|
50
|
-
Project web site:: http://github.com/nahi/httpclient
|
51
|
-
|
52
|
-
|
53
|
-
== License
|
54
|
-
|
55
|
-
This program is copyrighted free software by NAKAMURA, Hiroshi. You can
|
56
|
-
redistribute it and/or modify it under the same terms of Ruby's license;
|
57
|
-
either the dual license version in 2003, or any later version.
|
58
|
-
|
59
|
-
httpclient/session.rb is based on http-access.rb in http-access/0.0.4. Some
|
60
|
-
part of it is copyrighted by Maebashi-san who made and published
|
61
|
-
http-access/0.0.4. http-access/0.0.4 did not include license notice but when
|
62
|
-
I asked Maebashi-san he agreed that I can redistribute it under the same terms
|
63
|
-
of Ruby. Many thanks to Maebashi-san.
|
64
|
-
|
65
|
-
|
66
|
-
== Install
|
67
|
-
|
68
|
-
=== Gem
|
69
|
-
|
70
|
-
You can install httpclient with rubygems.
|
71
|
-
|
72
|
-
% gem install httpclient
|
73
|
-
|
74
|
-
=== Package
|
75
|
-
|
76
|
-
You can install httpclient with the bundled installer script.
|
77
|
-
|
78
|
-
$ ruby install.rb
|
79
|
-
|
80
|
-
It will install lib/* to your site_ruby directory such as
|
81
|
-
/usr/local/lib/ruby/site_ruby/1.8/.
|
82
|
-
|
83
|
-
For uninstall, delete installed files from your site_ruby directory.
|
84
|
-
|
85
|
-
|
86
|
-
== Usage
|
87
|
-
|
88
|
-
See HTTPClient for documentation.
|
89
|
-
You can also check sample/howto.rb how to use APIs.
|
90
|
-
|
91
|
-
|
92
|
-
== Download
|
93
|
-
|
94
|
-
* Gem repository
|
95
|
-
* https://rubygems.org/gems/httpclient
|
96
|
-
|
97
|
-
* git: git://github.com/nahi/httpclient.git
|
98
|
-
|
99
|
-
== Bug report or Feature request
|
100
|
-
|
101
|
-
Please file a ticket at the project web site.
|
102
|
-
|
103
|
-
1. find a similar ticket from https://github.com/nahi/httpclient/issues
|
104
|
-
2. create a new ticket by clicking 'Create Issue' button.
|
105
|
-
3. you can use github features such as pull-request if you like.
|
106
|
-
|
107
|
-
Thanks in advance.
|
108
|
-
|
data/lib/http-access2.rb
DELETED
@@ -1,55 +0,0 @@
|
|
1
|
-
# HTTPAccess2 - HTTP accessing library.
|
2
|
-
# Copyright (C) 2000-2007 NAKAMURA, Hiroshi <nakahiro@sarion.co.jp>.
|
3
|
-
|
4
|
-
# This program is copyrighted free software by NAKAMURA, Hiroshi. You can
|
5
|
-
# redistribute it and/or modify it under the same terms of Ruby's license;
|
6
|
-
# either the dual license version in 2003, or any later version.
|
7
|
-
|
8
|
-
# http-access2.rb is based on http-access.rb in http-access/0.0.4. Some
|
9
|
-
# part of it is copyrighted by Maebashi-san who made and published
|
10
|
-
# http-access/0.0.4. http-access/0.0.4 did not include license notice but
|
11
|
-
# when I asked Maebashi-san he agreed that I can redistribute it under the
|
12
|
-
# same terms of Ruby. Many thanks to Maebashi-san.
|
13
|
-
|
14
|
-
|
15
|
-
require 'httpclient'
|
16
|
-
|
17
|
-
|
18
|
-
module HTTPAccess2
|
19
|
-
VERSION = ::HTTPClient::VERSION
|
20
|
-
RUBY_VERSION_STRING = ::HTTPClient::RUBY_VERSION_STRING
|
21
|
-
SSLEnabled = ::HTTPClient::SSLEnabled
|
22
|
-
SSPIEnabled = ::HTTPClient::SSPIEnabled
|
23
|
-
DEBUG_SSL = true
|
24
|
-
|
25
|
-
Util = ::HTTPClient::Util
|
26
|
-
|
27
|
-
class Client < ::HTTPClient
|
28
|
-
class RetryableResponse < StandardError
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
SSLConfig = ::HTTPClient::SSLConfig
|
33
|
-
BasicAuth = ::HTTPClient::BasicAuth
|
34
|
-
DigestAuth = ::HTTPClient::DigestAuth
|
35
|
-
NegotiateAuth = ::HTTPClient::NegotiateAuth
|
36
|
-
AuthFilterBase = ::HTTPClient::AuthFilterBase
|
37
|
-
WWWAuth = ::HTTPClient::WWWAuth
|
38
|
-
ProxyAuth = ::HTTPClient::ProxyAuth
|
39
|
-
Site = ::HTTPClient::Site
|
40
|
-
Connection = ::HTTPClient::Connection
|
41
|
-
SessionManager = ::HTTPClient::SessionManager
|
42
|
-
SSLSocketWrap = ::HTTPClient::SSLSocketWrap
|
43
|
-
DebugSocket = ::HTTPClient::DebugSocket
|
44
|
-
|
45
|
-
class Session < ::HTTPClient::Session
|
46
|
-
class Error < StandardError
|
47
|
-
end
|
48
|
-
class InvalidState < Error
|
49
|
-
end
|
50
|
-
class BadResponse < Error
|
51
|
-
end
|
52
|
-
class KeepAliveDisconnected < Error
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|
data/lib/http-access2/cookie.rb
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
require 'httpclient/cookie'
|
data/lib/http-access2/http.rb
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
require 'httpclient/http'
|
data/test/test_http-access2.rb
DELETED
@@ -1,507 +0,0 @@
|
|
1
|
-
require 'http-access2'
|
2
|
-
require File.expand_path('helper', File.dirname(__FILE__))
|
3
|
-
|
4
|
-
|
5
|
-
module HTTPAccess2
|
6
|
-
|
7
|
-
|
8
|
-
class TestClient < Test::Unit::TestCase
|
9
|
-
include Helper
|
10
|
-
include HTTPClient::Util
|
11
|
-
|
12
|
-
def setup
|
13
|
-
super
|
14
|
-
setup_server
|
15
|
-
setup_client
|
16
|
-
end
|
17
|
-
|
18
|
-
def teardown
|
19
|
-
super
|
20
|
-
end
|
21
|
-
|
22
|
-
def test_initialize
|
23
|
-
setup_proxyserver
|
24
|
-
escape_noproxy do
|
25
|
-
@proxyio.string = ""
|
26
|
-
@client = HTTPAccess2::Client.new(proxyurl)
|
27
|
-
assert_equal(urify(proxyurl), @client.proxy)
|
28
|
-
assert_equal(200, @client.head(serverurl).status)
|
29
|
-
assert(!@proxyio.string.empty?)
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
def test_agent_name
|
34
|
-
@client = HTTPAccess2::Client.new(nil, "agent_name_foo")
|
35
|
-
str = ""
|
36
|
-
@client.debug_dev = str
|
37
|
-
@client.get(serverurl)
|
38
|
-
lines = str.split(/(?:\r?\n)+/)
|
39
|
-
assert_equal("= Request", lines[0])
|
40
|
-
assert_match(/^User-Agent: agent_name_foo/, lines[4])
|
41
|
-
end
|
42
|
-
|
43
|
-
def test_from
|
44
|
-
@client = HTTPAccess2::Client.new(nil, nil, "from_bar")
|
45
|
-
str = ""
|
46
|
-
@client.debug_dev = str
|
47
|
-
@client.get(serverurl)
|
48
|
-
lines = str.split(/(?:\r?\n)+/)
|
49
|
-
assert_equal("= Request", lines[0])
|
50
|
-
assert_match(/^From: from_bar/, lines[5])
|
51
|
-
end
|
52
|
-
|
53
|
-
def test_debug_dev
|
54
|
-
str = ""
|
55
|
-
@client.debug_dev = str
|
56
|
-
assert(str.empty?)
|
57
|
-
@client.get(serverurl)
|
58
|
-
assert(!str.empty?)
|
59
|
-
end
|
60
|
-
|
61
|
-
def _test_protocol_version_http09
|
62
|
-
@client.protocol_version = 'HTTP/0.9'
|
63
|
-
str = ""
|
64
|
-
@client.debug_dev = str
|
65
|
-
@client.get(serverurl + 'hello')
|
66
|
-
lines = str.split(/(?:\r?\n)+/)
|
67
|
-
assert_equal("= Request", lines[0])
|
68
|
-
assert_equal("! CONNECTION ESTABLISHED", lines[2])
|
69
|
-
assert_equal("GET /hello HTTP/0.9", lines[3])
|
70
|
-
assert_equal("Connection: close", lines[5])
|
71
|
-
assert_equal("= Response", lines[6])
|
72
|
-
assert_match(/^hello/, lines[7])
|
73
|
-
end
|
74
|
-
|
75
|
-
def test_protocol_version_http10
|
76
|
-
@client.protocol_version = 'HTTP/1.0'
|
77
|
-
str = ""
|
78
|
-
@client.debug_dev = str
|
79
|
-
@client.get(serverurl + 'hello')
|
80
|
-
lines = str.split(/(?:\r?\n)+/)
|
81
|
-
assert_equal("= Request", lines[0])
|
82
|
-
assert_equal("! CONNECTION ESTABLISHED", lines[2])
|
83
|
-
assert_equal("GET /hello HTTP/1.0", lines[3])
|
84
|
-
assert_equal("Connection: close", lines[7])
|
85
|
-
assert_equal("= Response", lines[8])
|
86
|
-
end
|
87
|
-
|
88
|
-
def test_protocol_version_http11
|
89
|
-
str = ""
|
90
|
-
@client.debug_dev = str
|
91
|
-
@client.get(serverurl)
|
92
|
-
lines = str.split(/(?:\r?\n)+/)
|
93
|
-
assert_equal("= Request", lines[0])
|
94
|
-
assert_equal("! CONNECTION ESTABLISHED", lines[2])
|
95
|
-
assert_equal("GET / HTTP/1.1", lines[3])
|
96
|
-
assert_equal("Host: localhost:#{serverport}", lines[7])
|
97
|
-
@client.protocol_version = 'HTTP/1.1'
|
98
|
-
str = ""
|
99
|
-
@client.debug_dev = str
|
100
|
-
@client.get(serverurl)
|
101
|
-
lines = str.split(/(?:\r?\n)+/)
|
102
|
-
assert_equal("= Request", lines[0])
|
103
|
-
assert_equal("! CONNECTION ESTABLISHED", lines[2])
|
104
|
-
assert_equal("GET / HTTP/1.1", lines[3])
|
105
|
-
@client.protocol_version = 'HTTP/1.0'
|
106
|
-
str = ""
|
107
|
-
@client.debug_dev = str
|
108
|
-
@client.get(serverurl)
|
109
|
-
lines = str.split(/(?:\r?\n)+/)
|
110
|
-
assert_equal("= Request", lines[0])
|
111
|
-
assert_equal("! CONNECTION ESTABLISHED", lines[2])
|
112
|
-
assert_equal("GET / HTTP/1.0", lines[3])
|
113
|
-
end
|
114
|
-
|
115
|
-
def test_proxy
|
116
|
-
setup_proxyserver
|
117
|
-
escape_noproxy do
|
118
|
-
begin
|
119
|
-
@client.proxy = "http://"
|
120
|
-
rescue
|
121
|
-
assert_match(/InvalidURIError/, $!.class.to_s)
|
122
|
-
end
|
123
|
-
@client.proxy = ""
|
124
|
-
assert_nil(@client.proxy)
|
125
|
-
@client.proxy = "http://foo:1234"
|
126
|
-
assert_equal(urify("http://foo:1234"), @client.proxy)
|
127
|
-
uri = urify("http://bar:2345")
|
128
|
-
@client.proxy = uri
|
129
|
-
assert_equal(uri, @client.proxy)
|
130
|
-
#
|
131
|
-
@proxyio.string = ""
|
132
|
-
@client.proxy = nil
|
133
|
-
assert_equal(200, @client.head(serverurl).status)
|
134
|
-
assert(@proxyio.string.empty?)
|
135
|
-
#
|
136
|
-
@proxyio.string = ""
|
137
|
-
@client.proxy = proxyurl
|
138
|
-
assert_equal(200, @client.head(serverurl).status)
|
139
|
-
assert(!@proxyio.string.empty?)
|
140
|
-
end
|
141
|
-
end
|
142
|
-
|
143
|
-
def test_noproxy_for_localhost
|
144
|
-
@proxyio.string = ""
|
145
|
-
@client.proxy = proxyurl
|
146
|
-
assert_equal(200, @client.head(serverurl).status)
|
147
|
-
assert(@proxyio.string.empty?)
|
148
|
-
end
|
149
|
-
|
150
|
-
def test_no_proxy
|
151
|
-
setup_proxyserver
|
152
|
-
escape_noproxy do
|
153
|
-
# proxy is not set.
|
154
|
-
@client.no_proxy = 'localhost'
|
155
|
-
@proxyio.string = ""
|
156
|
-
@client.proxy = nil
|
157
|
-
assert_equal(200, @client.head(serverurl).status)
|
158
|
-
assert(/accept/ !~ @proxyio.string)
|
159
|
-
#
|
160
|
-
@proxyio.string = ""
|
161
|
-
@client.proxy = proxyurl
|
162
|
-
assert_equal(200, @client.head(serverurl).status)
|
163
|
-
assert(/accept/ !~ @proxyio.string)
|
164
|
-
#
|
165
|
-
@client.no_proxy = 'foobar'
|
166
|
-
@proxyio.string = ""
|
167
|
-
@client.proxy = proxyurl
|
168
|
-
assert_equal(200, @client.head(serverurl).status)
|
169
|
-
assert(/accept/ =~ @proxyio.string)
|
170
|
-
#
|
171
|
-
@client.no_proxy = 'foobar,localhost:baz'
|
172
|
-
@proxyio.string = ""
|
173
|
-
@client.proxy = proxyurl
|
174
|
-
assert_equal(200, @client.head(serverurl).status)
|
175
|
-
assert(/accept/ !~ @proxyio.string)
|
176
|
-
#
|
177
|
-
@client.no_proxy = 'foobar,localhost:443'
|
178
|
-
@proxyio.string = ""
|
179
|
-
@client.proxy = proxyurl
|
180
|
-
assert_equal(200, @client.head(serverurl).status)
|
181
|
-
assert(/accept/ =~ @proxyio.string)
|
182
|
-
#
|
183
|
-
@client.no_proxy = "foobar,localhost:443:localhost:#{serverport},baz"
|
184
|
-
@proxyio.string = ""
|
185
|
-
@client.proxy = proxyurl
|
186
|
-
assert_equal(200, @client.head(serverurl).status)
|
187
|
-
assert(/accept/ !~ @proxyio.string)
|
188
|
-
end
|
189
|
-
end
|
190
|
-
|
191
|
-
def test_get_content
|
192
|
-
assert_equal('hello', @client.get_content(serverurl + 'hello'))
|
193
|
-
assert_equal('hello', @client.get_content(serverurl + 'redirect1'))
|
194
|
-
assert_equal('hello', @client.get_content(serverurl + 'redirect2'))
|
195
|
-
assert_raises(HTTPClient::Session::BadResponse) do
|
196
|
-
@client.get_content(serverurl + 'notfound')
|
197
|
-
end
|
198
|
-
assert_raises(HTTPClient::Session::BadResponse) do
|
199
|
-
@client.get_content(serverurl + 'redirect_self')
|
200
|
-
end
|
201
|
-
called = false
|
202
|
-
@client.redirect_uri_callback = lambda { |uri, res|
|
203
|
-
newuri = res.header['location'][0]
|
204
|
-
called = true
|
205
|
-
newuri
|
206
|
-
}
|
207
|
-
assert_equal('hello', @client.get_content(serverurl + 'relative_redirect'))
|
208
|
-
assert(called)
|
209
|
-
end
|
210
|
-
|
211
|
-
def test_post_content
|
212
|
-
assert_equal('hello', @client.post_content(serverurl + 'hello'))
|
213
|
-
assert_equal('hello', @client.post_content(serverurl + 'redirect1'))
|
214
|
-
assert_equal('hello', @client.post_content(serverurl + 'redirect2'))
|
215
|
-
assert_raises(HTTPClient::Session::BadResponse) do
|
216
|
-
@client.post_content(serverurl + 'notfound')
|
217
|
-
end
|
218
|
-
assert_raises(HTTPClient::Session::BadResponse) do
|
219
|
-
@client.post_content(serverurl + 'redirect_self')
|
220
|
-
end
|
221
|
-
called = false
|
222
|
-
@client.redirect_uri_callback = lambda { |uri, res|
|
223
|
-
newuri = res.header['location'][0]
|
224
|
-
called = true
|
225
|
-
newuri
|
226
|
-
}
|
227
|
-
assert_equal('hello', @client.post_content(serverurl + 'relative_redirect'))
|
228
|
-
assert(called)
|
229
|
-
end
|
230
|
-
|
231
|
-
def test_head
|
232
|
-
assert_equal("head", @client.head(serverurl + 'servlet').header["x-head"][0])
|
233
|
-
param = {'1'=>'2', '3'=>'4'}
|
234
|
-
res = @client.head(serverurl + 'servlet', param)
|
235
|
-
assert_equal(param, params(res.header["x-query"][0]))
|
236
|
-
end
|
237
|
-
|
238
|
-
def test_get
|
239
|
-
assert_equal("get", @client.get(serverurl + 'servlet').content)
|
240
|
-
param = {'1'=>'2', '3'=>'4'}
|
241
|
-
res = @client.get(serverurl + 'servlet', param)
|
242
|
-
assert_equal(param, params(res.header["x-query"][0]))
|
243
|
-
end
|
244
|
-
|
245
|
-
def test_post
|
246
|
-
assert_equal("post", @client.post(serverurl + 'servlet').content)
|
247
|
-
param = {'1'=>'2', '3'=>'4'}
|
248
|
-
res = @client.get(serverurl + 'servlet', param)
|
249
|
-
assert_equal(param, params(res.header["x-query"][0]))
|
250
|
-
end
|
251
|
-
|
252
|
-
def test_put
|
253
|
-
assert_equal("put", @client.put(serverurl + 'servlet').content)
|
254
|
-
param = {'1'=>'2', '3'=>'4'}
|
255
|
-
res = @client.get(serverurl + 'servlet', param)
|
256
|
-
assert_equal(param, params(res.header["x-query"][0]))
|
257
|
-
end
|
258
|
-
|
259
|
-
def test_delete
|
260
|
-
assert_equal("delete", @client.delete(serverurl + 'servlet').content)
|
261
|
-
param = {'1'=>'2', '3'=>'4'}
|
262
|
-
res = @client.get(serverurl + 'servlet', param)
|
263
|
-
assert_equal(param, params(res.header["x-query"][0]))
|
264
|
-
end
|
265
|
-
|
266
|
-
def test_options
|
267
|
-
assert_equal("options", @client.options(serverurl + 'servlet').content)
|
268
|
-
param = {'1'=>'2', '3'=>'4'}
|
269
|
-
res = @client.get(serverurl + 'servlet', param)
|
270
|
-
assert_equal(param, params(res.header["x-query"][0]))
|
271
|
-
end
|
272
|
-
|
273
|
-
def test_trace
|
274
|
-
assert_equal("trace", @client.trace(serverurl + 'servlet').content)
|
275
|
-
param = {'1'=>'2', '3'=>'4'}
|
276
|
-
res = @client.get(serverurl + 'servlet', param)
|
277
|
-
assert_equal(param, params(res.header["x-query"][0]))
|
278
|
-
end
|
279
|
-
|
280
|
-
def test_get_query
|
281
|
-
assert_equal({'1'=>'2'}, check_query_get({1=>2}))
|
282
|
-
assert_equal({'a'=>'A', 'B'=>'b'}, check_query_get({"a"=>"A", "B"=>"b"}))
|
283
|
-
assert_equal({'&'=>'&'}, check_query_get({"&"=>"&"}))
|
284
|
-
assert_equal({'= '=>' =+'}, check_query_get({"= "=>" =+"}))
|
285
|
-
assert_equal(
|
286
|
-
['=', '&'].sort,
|
287
|
-
check_query_get([["=", "="], ["=", "&"]])['='].to_ary.sort
|
288
|
-
)
|
289
|
-
assert_equal({'123'=>'45'}, check_query_get('123=45'))
|
290
|
-
assert_equal({'12 3'=>'45', ' '=>' '}, check_query_get('12+3=45&+=+'))
|
291
|
-
assert_equal({}, check_query_get(''))
|
292
|
-
end
|
293
|
-
|
294
|
-
def test_post_body
|
295
|
-
assert_equal({'1'=>'2'}, check_query_post({1=>2}))
|
296
|
-
assert_equal({'a'=>'A', 'B'=>'b'}, check_query_post({"a"=>"A", "B"=>"b"}))
|
297
|
-
assert_equal({'&'=>'&'}, check_query_post({"&"=>"&"}))
|
298
|
-
assert_equal({'= '=>' =+'}, check_query_post({"= "=>" =+"}))
|
299
|
-
assert_equal(
|
300
|
-
['=', '&'].sort,
|
301
|
-
check_query_post([["=", "="], ["=", "&"]])['='].to_ary.sort
|
302
|
-
)
|
303
|
-
assert_equal({'123'=>'45'}, check_query_post('123=45'))
|
304
|
-
assert_equal({'12 3'=>'45', ' '=>' '}, check_query_post('12+3=45&+=+'))
|
305
|
-
assert_equal({}, check_query_post(''))
|
306
|
-
#
|
307
|
-
post_body = StringIO.new("foo=bar&foo=baz")
|
308
|
-
assert_equal(
|
309
|
-
["bar", "baz"],
|
310
|
-
check_query_post(post_body)["foo"].to_ary.sort
|
311
|
-
)
|
312
|
-
end
|
313
|
-
|
314
|
-
def test_extra_headers
|
315
|
-
str = ""
|
316
|
-
@client.debug_dev = str
|
317
|
-
@client.head(serverurl, nil, {"ABC" => "DEF"})
|
318
|
-
lines = str.split(/(?:\r?\n)+/)
|
319
|
-
assert_equal("= Request", lines[0])
|
320
|
-
assert_match("ABC: DEF", lines[4])
|
321
|
-
#
|
322
|
-
str = ""
|
323
|
-
@client.debug_dev = str
|
324
|
-
@client.get(serverurl, nil, [["ABC", "DEF"], ["ABC", "DEF"]])
|
325
|
-
lines = str.split(/(?:\r?\n)+/)
|
326
|
-
assert_equal("= Request", lines[0])
|
327
|
-
assert_match("ABC: DEF", lines[4])
|
328
|
-
assert_match("ABC: DEF", lines[5])
|
329
|
-
end
|
330
|
-
|
331
|
-
def test_timeout
|
332
|
-
assert_equal(60, @client.connect_timeout)
|
333
|
-
assert_equal(120, @client.send_timeout)
|
334
|
-
assert_equal(60, @client.receive_timeout)
|
335
|
-
end
|
336
|
-
|
337
|
-
def test_connect_timeout
|
338
|
-
# ToDo
|
339
|
-
end
|
340
|
-
|
341
|
-
def test_send_timeout
|
342
|
-
# ToDo
|
343
|
-
end
|
344
|
-
|
345
|
-
def test_receive_timeout
|
346
|
-
# this test takes 2 sec
|
347
|
-
assert_equal('hello', @client.get_content(serverurl + 'sleep?sec=2'))
|
348
|
-
@client.receive_timeout = 1
|
349
|
-
assert_equal('hello', @client.get_content(serverurl + 'sleep?sec=0'))
|
350
|
-
assert_raise(HTTPClient::ReceiveTimeoutError) do
|
351
|
-
@client.get_content(serverurl + 'sleep?sec=2')
|
352
|
-
end
|
353
|
-
@client.receive_timeout = 3
|
354
|
-
assert_equal('hello', @client.get_content(serverurl + 'sleep?sec=2'))
|
355
|
-
end
|
356
|
-
|
357
|
-
def test_cookies
|
358
|
-
cookiefile = File.join(File.dirname(File.expand_path(__FILE__)),
|
359
|
-
'test_cookies_file')
|
360
|
-
# from [ruby-talk:164079]
|
361
|
-
File.open(cookiefile, "wb") do |f|
|
362
|
-
f << "http://rubyforge.org//account/login.php session_ser LjEwMy45Ni40Ni0q%2A-fa0537de8cc31 1131676286 .rubyforge.org / 13\n"
|
363
|
-
end
|
364
|
-
cm = WebAgent::CookieManager::new(cookiefile)
|
365
|
-
cm.load_cookies
|
366
|
-
cookie = cm.cookies.first
|
367
|
-
url = cookie.url
|
368
|
-
assert(cookie.domain_match(url.host, cookie.domain))
|
369
|
-
end
|
370
|
-
|
371
|
-
private
|
372
|
-
|
373
|
-
def check_query_get(query)
|
374
|
-
WEBrick::HTTPUtils.parse_query(
|
375
|
-
@client.get(serverurl + 'servlet', query).header["x-query"][0]
|
376
|
-
)
|
377
|
-
end
|
378
|
-
|
379
|
-
def check_query_post(query)
|
380
|
-
WEBrick::HTTPUtils.parse_query(
|
381
|
-
@client.post(serverurl + 'servlet', query).header["x-query"][0]
|
382
|
-
)
|
383
|
-
end
|
384
|
-
|
385
|
-
def setup_server
|
386
|
-
@server = WEBrick::HTTPServer.new(
|
387
|
-
:BindAddress => "localhost",
|
388
|
-
:Logger => @logger,
|
389
|
-
:Port => 0,
|
390
|
-
:AccessLog => [],
|
391
|
-
:DocumentRoot => File.dirname(File.expand_path(__FILE__))
|
392
|
-
)
|
393
|
-
@serverport = @server.config[:Port]
|
394
|
-
[:hello, :sleep, :redirect1, :redirect2, :redirect3, :redirect_self, :relative_redirect].each do |sym|
|
395
|
-
@server.mount(
|
396
|
-
"/#{sym}",
|
397
|
-
WEBrick::HTTPServlet::ProcHandler.new(method("do_#{sym}").to_proc)
|
398
|
-
)
|
399
|
-
end
|
400
|
-
@server.mount('/servlet', TestServlet.new(@server))
|
401
|
-
@server_thread = start_server_thread(@server)
|
402
|
-
end
|
403
|
-
|
404
|
-
def escape_noproxy
|
405
|
-
backup = HTTPAccess2::Client::NO_PROXY_HOSTS.dup
|
406
|
-
HTTPAccess2::Client::NO_PROXY_HOSTS.clear
|
407
|
-
yield
|
408
|
-
ensure
|
409
|
-
HTTPAccess2::Client::NO_PROXY_HOSTS.replace(backup)
|
410
|
-
end
|
411
|
-
|
412
|
-
def do_hello(req, res)
|
413
|
-
res['content-type'] = 'text/html'
|
414
|
-
res.body = "hello"
|
415
|
-
end
|
416
|
-
|
417
|
-
def do_sleep(req, res)
|
418
|
-
sec = req.query['sec'].to_i
|
419
|
-
sleep sec
|
420
|
-
res['content-type'] = 'text/html'
|
421
|
-
res.body = "hello"
|
422
|
-
end
|
423
|
-
|
424
|
-
def do_redirect1(req, res)
|
425
|
-
res.set_redirect(WEBrick::HTTPStatus::MovedPermanently, serverurl + "hello")
|
426
|
-
end
|
427
|
-
|
428
|
-
def do_redirect2(req, res)
|
429
|
-
res.set_redirect(WEBrick::HTTPStatus::TemporaryRedirect, serverurl + "redirect3")
|
430
|
-
end
|
431
|
-
|
432
|
-
def do_redirect3(req, res)
|
433
|
-
res.set_redirect(WEBrick::HTTPStatus::Found, serverurl + "hello")
|
434
|
-
end
|
435
|
-
|
436
|
-
def do_redirect_self(req, res)
|
437
|
-
res.set_redirect(WEBrick::HTTPStatus::Found, serverurl + "redirect_self")
|
438
|
-
end
|
439
|
-
|
440
|
-
def do_relative_redirect(req, res)
|
441
|
-
res.set_redirect(WEBrick::HTTPStatus::Found, "hello")
|
442
|
-
end
|
443
|
-
|
444
|
-
class TestServlet < WEBrick::HTTPServlet::AbstractServlet
|
445
|
-
def get_instance(*arg)
|
446
|
-
self
|
447
|
-
end
|
448
|
-
|
449
|
-
def do_HEAD(req, res)
|
450
|
-
res["x-head"] = 'head' # use this for test purpose only.
|
451
|
-
res["x-query"] = query_response(req)
|
452
|
-
end
|
453
|
-
|
454
|
-
def do_GET(req, res)
|
455
|
-
res.body = 'get'
|
456
|
-
res["x-query"] = query_response(req)
|
457
|
-
end
|
458
|
-
|
459
|
-
def do_POST(req, res)
|
460
|
-
res.body = 'post'
|
461
|
-
res["x-query"] = body_response(req)
|
462
|
-
end
|
463
|
-
|
464
|
-
def do_PUT(req, res)
|
465
|
-
res.body = 'put'
|
466
|
-
end
|
467
|
-
|
468
|
-
def do_DELETE(req, res)
|
469
|
-
res.body = 'delete'
|
470
|
-
end
|
471
|
-
|
472
|
-
def do_OPTIONS(req, res)
|
473
|
-
# check RFC for legal response.
|
474
|
-
res.body = 'options'
|
475
|
-
end
|
476
|
-
|
477
|
-
def do_TRACE(req, res)
|
478
|
-
# client SHOULD reflect the message received back to the client as the
|
479
|
-
# entity-body of a 200 (OK) response. [RFC2616]
|
480
|
-
res.body = 'trace'
|
481
|
-
res["x-query"] = query_response(req)
|
482
|
-
end
|
483
|
-
|
484
|
-
private
|
485
|
-
|
486
|
-
def query_response(req)
|
487
|
-
query_escape(WEBrick::HTTPUtils.parse_query(req.query_string))
|
488
|
-
end
|
489
|
-
|
490
|
-
def body_response(req)
|
491
|
-
query_escape(WEBrick::HTTPUtils.parse_query(req.body))
|
492
|
-
end
|
493
|
-
|
494
|
-
def query_escape(query)
|
495
|
-
escaped = []
|
496
|
-
query.collect do |k, v|
|
497
|
-
v.to_ary.each do |ve|
|
498
|
-
escaped << CGI.escape(k) + '=' + CGI.escape(ve)
|
499
|
-
end
|
500
|
-
end
|
501
|
-
escaped.join('&')
|
502
|
-
end
|
503
|
-
end
|
504
|
-
end
|
505
|
-
|
506
|
-
|
507
|
-
end
|