glebtv-httpclient 3.0.2 → 3.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
[![Build Status](https://travis-ci.org/glebtv/httpclient.png?branch=master)](https://travis-ci.org/glebtv/httpclient)
|
6
|
+
[![Gem Version](https://badge.fury.io/rb/glebtv-httpclient.png)](http://badge.fury.io/rb/glebtv-httpclient)
|
7
|
+
[![Dependency Status](https://gemnasium.com/glebtv/httpclient.png)](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
|