http2 0.0.28 → 0.0.33
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 +5 -5
- data/README.md +150 -28
- data/Rakefile +20 -31
- data/lib/http2.rb +105 -70
- data/lib/http2/base_request.rb +22 -0
- data/{include → lib/http2}/connection.rb +56 -28
- data/lib/http2/cookie.rb +22 -0
- data/lib/http2/errors.rb +18 -0
- data/lib/http2/get_request.rb +33 -0
- data/{include → lib/http2}/post_data_generator.rb +7 -6
- data/{include → lib/http2}/post_multipart_request.rb +20 -20
- data/{include → lib/http2}/post_request.rb +17 -22
- data/lib/http2/response.rb +109 -0
- data/{include → lib/http2}/response_reader.rb +75 -42
- data/{include → lib/http2}/url_builder.rb +6 -6
- data/lib/http2/utils.rb +52 -0
- data/spec/helpers.rb +27 -0
- data/spec/http2/cookies_spec.rb +18 -0
- data/spec/http2/get_request_spec.rb +11 -0
- data/spec/http2/post_data_generator_spec.rb +2 -1
- data/spec/http2/post_multipart_request_spec.rb +11 -0
- data/spec/http2/post_request_spec.rb +11 -0
- data/spec/http2/response_reader_spec.rb +12 -0
- data/spec/http2/response_spec.rb +73 -0
- data/spec/http2/url_builder_spec.rb +1 -1
- data/spec/http2_spec.rb +107 -89
- data/spec/spec_helper.rb +8 -8
- data/spec/spec_root/content_type_test.rhtml +4 -0
- data/spec/spec_root/cookie_test.rhtml +8 -0
- data/spec/spec_root/json_test.rhtml +9 -0
- data/spec/spec_root/multipart_test.rhtml +28 -0
- data/spec/spec_root/redirect_test.rhtml +3 -0
- data/spec/spec_root/unauthorized.rhtml +3 -0
- data/spec/spec_root/unsupported_media_type.rhtml +3 -0
- metadata +118 -36
- data/.document +0 -5
- data/.rspec +0 -1
- data/Gemfile +0 -14
- data/Gemfile.lock +0 -77
- data/VERSION +0 -1
- data/http2.gemspec +0 -77
- data/include/errors.rb +0 -11
- data/include/get_request.rb +0 -34
- data/include/response.rb +0 -73
- data/include/utils.rb +0 -40
- data/shippable.yml +0 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 856e9e6edf6d355dc73912489a6263a6a213abbaa1ec87f6fa4b5547f727f336
|
4
|
+
data.tar.gz: f4062dda7f2970331ab68a9e38095fe7bc729f61a27305e7eaea4ddb9a2d28fe
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8ca5c943ae78a977a5253487670755830ea8225b417f79238cbaff5cf6d4f3adabe1e572b6480325c19e6cb317f35e10d2ef491de79df9d15cc7f6f8014f2b13
|
7
|
+
data.tar.gz: aead6eadd6b8569bab500e3ebf64bea0188ebf06739c83ba78d1f1fcd70b3b3ac0a6ad2516610bdefd2751bc63acb53c352fbbc1e3e310931d41ab0b6bf72f18
|
data/README.md
CHANGED
@@ -1,41 +1,143 @@
|
|
1
|
+
[](https://codeclimate.com/github/kaspernj/http2)
|
2
|
+
[](https://www.peakflow.io/en/projects/http2/build-groups)
|
4
|
+
|
1
5
|
# http2
|
2
6
|
|
3
|
-
|
4
|
-
[](https://codeclimate.com/github/kaspernj/http2)
|
5
|
-
[](https://codeclimate.com/github/kaspernj/http2)
|
7
|
+
A HTTP-framework for Ruby supporting keep-alive, compression, JSON-posting, detailed inspection of responses and much more.
|
6
8
|
|
7
|
-
|
9
|
+
# Usage
|
8
10
|
|
9
11
|
```ruby
|
10
12
|
require "rubygems"
|
11
13
|
require "http2"
|
12
14
|
|
13
|
-
Http2.new(:
|
14
|
-
#
|
15
|
-
res = http.get("path/to/something")
|
16
|
-
puts res.body
|
17
|
-
puts "All response-headers: #{res.headers}"
|
18
|
-
puts "Specific header: #{res.header("HeaderName")}"
|
19
|
-
|
20
|
-
#Post-request.
|
21
|
-
res = http.post(:url => "path/to/something", :post => {
|
22
|
-
"some_post_val" => "some_value"
|
23
|
-
})
|
24
|
-
|
25
|
-
res.content_type #=> "text/html"
|
26
|
-
|
27
|
-
#Post-multipart (upload).
|
28
|
-
res = http.post_multipart(:url => "path/to/something", :post => {
|
29
|
-
"test_file1" => {
|
30
|
-
:fpath => fpath,
|
31
|
-
:filename => "specfile"
|
32
|
-
}
|
33
|
-
})
|
34
|
-
|
35
|
-
puts "Cookies until now: #{http.cookies}"
|
15
|
+
Http2.new(host: "www.google.dk") do |http|
|
16
|
+
# Do requests here.
|
36
17
|
end
|
37
18
|
```
|
38
19
|
|
20
|
+
Or without using a block for ensuring closing of connection:
|
21
|
+
```ruby
|
22
|
+
http = Http2.new(...)
|
23
|
+
|
24
|
+
# Do requests here.
|
25
|
+
|
26
|
+
http.destroy # Closes the connection and frees up any variables used
|
27
|
+
```
|
28
|
+
|
29
|
+
Or through a proxy:
|
30
|
+
```ruby
|
31
|
+
Http2.new(host: "www.google.com", proxy: {host: "myproxy.com", port: 80, user: "myname", passwd: "mypassword"})
|
32
|
+
```
|
33
|
+
|
34
|
+
You can also use SSL:
|
35
|
+
```ruby
|
36
|
+
Http2.new(host: "myhost.com", ssl: true, ssl_skip_verify: true)
|
37
|
+
```
|
38
|
+
|
39
|
+
You can make it follow redirects like this:
|
40
|
+
```ruby
|
41
|
+
Http2.new(host: "myhost.com", follow_redirects: true)
|
42
|
+
```
|
43
|
+
|
44
|
+
## Get requests
|
45
|
+
```ruby
|
46
|
+
res = http.get("path/to/something")
|
47
|
+
```
|
48
|
+
|
49
|
+
Or as a hash:
|
50
|
+
```ruby
|
51
|
+
res = http.get(url: "path/to/something")
|
52
|
+
```
|
53
|
+
|
54
|
+
## Post requests
|
55
|
+
```ruby
|
56
|
+
res = http.post(url: "path/to/something", post: {
|
57
|
+
"some_post_val" => "some_value"
|
58
|
+
})
|
59
|
+
```
|
60
|
+
|
61
|
+
### Extra headers
|
62
|
+
```ruby
|
63
|
+
res = http.post(
|
64
|
+
url: "path",
|
65
|
+
headers: {"Auth": "123"},
|
66
|
+
post: {data: "test"}
|
67
|
+
)
|
68
|
+
```
|
69
|
+
|
70
|
+
### Post JSON as content
|
71
|
+
```ruby
|
72
|
+
res = http.post(url: "path/to/something", json: {some_argument: true})
|
73
|
+
```
|
74
|
+
|
75
|
+
### Reading JSON from request
|
76
|
+
```ruby
|
77
|
+
res = http.post(url: "something", json: {some_argument: true})
|
78
|
+
res.json? #=> true (if content-type is application/json)
|
79
|
+
res.json #=> {"value" => "something"}
|
80
|
+
```
|
81
|
+
|
82
|
+
## Delete requests
|
83
|
+
```ruby
|
84
|
+
res = http.delete(url: "path/to/something")
|
85
|
+
```
|
86
|
+
|
87
|
+
## File upload
|
88
|
+
```ruby
|
89
|
+
res = http.post_multipart(url: "path/to/something", post: {
|
90
|
+
"test_file1" => {
|
91
|
+
fpath: fpath,
|
92
|
+
filename: "specfile"
|
93
|
+
}
|
94
|
+
})
|
95
|
+
```
|
96
|
+
|
97
|
+
## Reading cookies
|
98
|
+
```ruby
|
99
|
+
puts "Cookies until now: #{http.cookies}"
|
100
|
+
```
|
101
|
+
|
102
|
+
## Building URL's
|
103
|
+
```ruby
|
104
|
+
ub = ::Http2::UrlBuilder.new
|
105
|
+
ub.host = "www.google.com"
|
106
|
+
ub.port = 80
|
107
|
+
ub.path = "script.php"
|
108
|
+
ub.params["some_param"] = 2
|
109
|
+
|
110
|
+
ub.build #=> "http://www.google.com/..."
|
111
|
+
ub.build_params #=> "some_param=2&some_other_param=..."
|
112
|
+
ub.build_path_and_params #=> "script.php?some_param=2"
|
113
|
+
ub.params? #=> true
|
114
|
+
ub.host #=> "www.google.com"
|
115
|
+
ub.port #=> 80
|
116
|
+
ub.path #=> "script.php"
|
117
|
+
```
|
118
|
+
|
119
|
+
## Inspecting responses
|
120
|
+
|
121
|
+
```ruby
|
122
|
+
resp = http.get("path/to/something")
|
123
|
+
resp.content_type #=> "text/html"
|
124
|
+
resp.content_length #=> 136
|
125
|
+
resp.header("content-length") #=> "136"
|
126
|
+
resp.headers #=> {"content-type" => ["text/html"], "content-length" => ["136"]}
|
127
|
+
resp.code #=> "200"
|
128
|
+
resp.charset #=> "utf-8"
|
129
|
+
resp.http_version #=> "1.1"
|
130
|
+
resp.body #=> "<html><body>..."
|
131
|
+
resp.requested_url #=> "http://example.com/maybe/redirected/path/to/something"
|
132
|
+
```
|
133
|
+
|
134
|
+
## Get parameters later.
|
135
|
+
|
136
|
+
```ruby
|
137
|
+
http.host #=> example.com
|
138
|
+
http.port #=> 80
|
139
|
+
```
|
140
|
+
|
39
141
|
|
40
142
|
## Reconnect
|
41
143
|
|
@@ -45,6 +147,27 @@ Handy when doing retries.
|
|
45
147
|
http.reconnect
|
46
148
|
```
|
47
149
|
|
150
|
+
|
151
|
+
## Basic HTTP authentication for all requests
|
152
|
+
|
153
|
+
```ruby
|
154
|
+
http = Http2.new(
|
155
|
+
host: "www.somehost.com",
|
156
|
+
basic_auth: {
|
157
|
+
user: "username",
|
158
|
+
passwd: "password"
|
159
|
+
}
|
160
|
+
)
|
161
|
+
```
|
162
|
+
|
163
|
+
## Inspect the headers that were sent
|
164
|
+
|
165
|
+
```ruby
|
166
|
+
response = http.get("some_page")
|
167
|
+
request = response.request
|
168
|
+
request.headers_string #=> "GET /some_page\n..."
|
169
|
+
```
|
170
|
+
|
48
171
|
## Contributing to http2
|
49
172
|
|
50
173
|
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet.
|
@@ -59,4 +182,3 @@ http.reconnect
|
|
59
182
|
|
60
183
|
Copyright (c) 2012 Kasper Johansen. See LICENSE.txt for
|
61
184
|
further details.
|
62
|
-
|
data/Rakefile
CHANGED
@@ -1,49 +1,38 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require 'rubygems'
|
4
|
-
require 'bundler'
|
1
|
+
require "rubygems"
|
2
|
+
require "bundler"
|
5
3
|
begin
|
6
4
|
Bundler.setup(:default, :development)
|
7
5
|
rescue Bundler::BundlerError => e
|
8
|
-
|
9
|
-
|
6
|
+
warn e.message
|
7
|
+
warn "Run `bundle install` to install missing gems"
|
10
8
|
exit e.status_code
|
11
9
|
end
|
12
|
-
require
|
13
|
-
|
14
|
-
require 'jeweler'
|
15
|
-
Jeweler::Tasks.new do |gem|
|
16
|
-
# gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
|
17
|
-
gem.name = "http2"
|
18
|
-
gem.homepage = "http://github.com/kaspernj/http2"
|
19
|
-
gem.license = "MIT"
|
20
|
-
gem.summary = %Q{A lightweight framework for doing http-connections in Ruby. Supports cookies, keep-alive, compressing and much more.}
|
21
|
-
gem.description = %Q{A lightweight framework for doing http-connections in Ruby. Supports cookies, keep-alive, compressing and much more.}
|
22
|
-
gem.email = "k@spernj.org"
|
23
|
-
gem.authors = ["Kasper Johansen"]
|
24
|
-
# dependencies defined in Gemfile
|
25
|
-
end
|
26
|
-
Jeweler::RubygemsDotOrgTasks.new
|
10
|
+
require "rake"
|
27
11
|
|
28
|
-
require
|
29
|
-
require
|
12
|
+
require "rspec/core"
|
13
|
+
require "rspec/core/rake_task"
|
30
14
|
RSpec::Core::RakeTask.new(:spec) do |spec|
|
31
|
-
spec.pattern = FileList[
|
15
|
+
spec.pattern = FileList["spec/**/*_spec.rb"]
|
32
16
|
end
|
33
17
|
|
34
18
|
RSpec::Core::RakeTask.new(:rcov) do |spec|
|
35
|
-
spec.pattern =
|
19
|
+
spec.pattern = "spec/**/*_spec.rb"
|
36
20
|
spec.rcov = true
|
37
21
|
end
|
38
22
|
|
39
|
-
task :
|
23
|
+
task default: :spec
|
40
24
|
|
41
|
-
require
|
25
|
+
require "rdoc/task"
|
42
26
|
Rake::RDocTask.new do |rdoc|
|
43
|
-
version = File.exist?(
|
27
|
+
version = File.exist?("VERSION") ? File.read("VERSION") : ""
|
44
28
|
|
45
|
-
rdoc.rdoc_dir =
|
29
|
+
rdoc.rdoc_dir = "rdoc"
|
46
30
|
rdoc.title = "http2 #{version}"
|
47
|
-
rdoc.rdoc_files.include(
|
48
|
-
rdoc.rdoc_files.include(
|
31
|
+
rdoc.rdoc_files.include("README*")
|
32
|
+
rdoc.rdoc_files.include("lib/**/*.rb")
|
49
33
|
end
|
34
|
+
|
35
|
+
Bundler::GemHelper.install_tasks
|
36
|
+
|
37
|
+
require "best_practice_project"
|
38
|
+
BestPracticeProject.load_tasks
|
data/lib/http2.rb
CHANGED
@@ -3,9 +3,10 @@ require "uri"
|
|
3
3
|
require "monitor" unless ::Kernel.const_defined?(:Monitor)
|
4
4
|
require "string-cases"
|
5
5
|
|
6
|
-
#This class tries to emulate a browser in Ruby without any visual stuff.
|
6
|
+
# This class tries to emulate a browser in Ruby without any visual stuff.
|
7
|
+
# Remember cookies, keep sessions alive, reset connections according to keep-alive rules and more.
|
7
8
|
#===Examples
|
8
|
-
# Http2.new(:
|
9
|
+
# Http2.new(host: "www.somedomain.com", port: 80, ssl: false, debug: false) do |http|
|
9
10
|
# res = http.get("index.rhtml?show=some_page")
|
10
11
|
# html = res.body
|
11
12
|
# print html
|
@@ -15,52 +16,64 @@ require "string-cases"
|
|
15
16
|
# print "#{res.headers}"
|
16
17
|
# end
|
17
18
|
class Http2
|
18
|
-
#Autoloader for subclasses.
|
19
|
+
# Autoloader for subclasses.
|
19
20
|
def self.const_missing(name)
|
20
|
-
|
21
|
-
return Http2.const_get(name)
|
22
|
-
end
|
21
|
+
file_path = "#{File.dirname(__FILE__)}/http2/#{::StringCases.camel_to_snake(name)}.rb"
|
23
22
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
resp = http.get("/api.php?longurl=#{url}")
|
28
|
-
return resp.body
|
23
|
+
if File.exist?(file_path)
|
24
|
+
require file_path
|
25
|
+
return Http2.const_get(name) if Http2.const_defined?(name)
|
29
26
|
end
|
27
|
+
|
28
|
+
super
|
30
29
|
end
|
31
30
|
|
32
31
|
attr_reader :autostate, :connection, :cookies, :args, :debug, :mutex, :resp, :raise_errors, :nl
|
33
32
|
attr_accessor :keepalive_max, :keepalive_timeout
|
34
33
|
|
35
|
-
VALID_ARGUMENTS_INITIALIZE = [
|
34
|
+
VALID_ARGUMENTS_INITIALIZE = [
|
35
|
+
:host, :port, :skip_port_in_host_header, :ssl, :ssl_skip_verify, :nl, :user_agent, :raise_errors,
|
36
|
+
:follow_redirects, :debug, :encoding_gzip, :autostate, :basic_auth, :extra_headers, :proxy
|
37
|
+
].freeze
|
36
38
|
def initialize(args = {})
|
37
39
|
@args = parse_init_args(args)
|
38
40
|
set_default_values
|
39
41
|
@cookies = {}
|
40
42
|
@mutex = Monitor.new
|
41
|
-
|
42
43
|
@connection = ::Http2::Connection.new(self)
|
43
44
|
|
44
45
|
if block_given?
|
45
46
|
begin
|
46
47
|
yield(self)
|
47
48
|
ensure
|
48
|
-
|
49
|
+
destroy
|
49
50
|
end
|
50
51
|
end
|
51
52
|
end
|
52
53
|
|
54
|
+
def host
|
55
|
+
@args.fetch(:host)
|
56
|
+
end
|
57
|
+
|
58
|
+
def port
|
59
|
+
@args.fetch(:port)
|
60
|
+
end
|
61
|
+
|
62
|
+
def ssl?
|
63
|
+
@args[:ssl] ? true : false
|
64
|
+
end
|
65
|
+
|
53
66
|
def reconnect
|
54
67
|
@connection.reconnect
|
55
68
|
end
|
56
69
|
|
57
70
|
def new_url
|
58
71
|
builder = Http2::UrlBuilder.new
|
59
|
-
builder.host =
|
60
|
-
builder.port =
|
72
|
+
builder.host = host
|
73
|
+
builder.port = port
|
61
74
|
builder.protocol = @args[:protocol]
|
62
75
|
|
63
|
-
|
76
|
+
builder
|
64
77
|
end
|
65
78
|
|
66
79
|
# Closes current connection if any, changes the arguments on the object and reconnects keeping all cookies and other stuff intact.
|
@@ -70,7 +83,7 @@ class Http2
|
|
70
83
|
@connection = ::Http2::Connection.new(self)
|
71
84
|
end
|
72
85
|
|
73
|
-
#Destroys the object unsetting all variables and closing all sockets.
|
86
|
+
# Destroys the object unsetting all variables and closing all sockets.
|
74
87
|
#===Examples
|
75
88
|
# http.destroy
|
76
89
|
def destroy
|
@@ -86,26 +99,22 @@ class Http2
|
|
86
99
|
@connection = nil
|
87
100
|
end
|
88
101
|
|
89
|
-
#Forces various stuff into arguments-hash like URL from original arguments and enables single-string-shortcuts and more.
|
102
|
+
# Forces various stuff into arguments-hash like URL from original arguments and enables single-string-shortcuts and more.
|
90
103
|
def parse_args(*args)
|
91
104
|
if args.length == 1 && args.first.is_a?(String)
|
92
|
-
args = {:
|
93
|
-
elsif args.length
|
94
|
-
raise "Couldnt parse arguments."
|
95
|
-
elsif args.is_a?(Array) && args.length == 1
|
105
|
+
args = {url: args.first}
|
106
|
+
elsif args.length == 1
|
96
107
|
args = args.first
|
97
108
|
else
|
98
|
-
raise "Invalid arguments: '#{args.class.name}'
|
109
|
+
raise "Invalid arguments: '#{args.class.name}'"
|
99
110
|
end
|
100
111
|
|
101
|
-
if args[:url].to_s.split("\n").length != 1
|
102
|
-
raise "Invalid URL: '#{args[:url]}'."
|
103
|
-
end
|
112
|
+
raise "Invalid URL: '#{args[:url]}'" if args[:url] != "" && args[:url].to_s.split("\n").length != 1
|
104
113
|
|
105
|
-
|
114
|
+
args
|
106
115
|
end
|
107
116
|
|
108
|
-
#Returns a result-object based on the arguments.
|
117
|
+
# Returns a result-object based on the arguments.
|
109
118
|
#===Examples
|
110
119
|
# res = http.get("somepage.html")
|
111
120
|
# print res.body #=> <String>-object containing the HTML gotten.
|
@@ -116,13 +125,13 @@ class Http2
|
|
116
125
|
# Proxies the request to another method but forces the method to be "DELETE".
|
117
126
|
def delete(args)
|
118
127
|
if args[:json]
|
119
|
-
|
128
|
+
post(args.merge(method: :delete))
|
120
129
|
else
|
121
|
-
|
130
|
+
get(args.merge(method: :delete))
|
122
131
|
end
|
123
132
|
end
|
124
133
|
|
125
|
-
#Returns the default headers for a request.
|
134
|
+
# Returns the default headers for a request.
|
126
135
|
#===Examples
|
127
136
|
# headers_hash = http.default_headers
|
128
137
|
# print "#{headers_hash}"
|
@@ -131,97 +140,120 @@ class Http2
|
|
131
140
|
|
132
141
|
headers = {
|
133
142
|
"Connection" => "Keep-Alive",
|
134
|
-
"User-Agent" => @uagent
|
143
|
+
"User-Agent" => @uagent,
|
144
|
+
"Host" => host_header
|
135
145
|
}
|
136
146
|
|
137
|
-
#Possible to give custom host-argument.
|
138
|
-
host = args[:host] || @args[:host]
|
139
|
-
port = args[:port] || @args[:port]
|
140
|
-
|
141
|
-
headers["Host"] = host
|
142
|
-
headers["Host"] << ":#{port}" if port && ![80, 443].include?(port.to_i) && !@args[:skip_port_in_host_header]
|
143
147
|
headers["Accept-Encoding"] = "gzip" if @args[:encoding_gzip]
|
144
148
|
|
145
149
|
if @args[:basic_auth]
|
146
150
|
require "base64" unless ::Kernel.const_defined?(:Base64)
|
147
|
-
headers["Authorization"] = "Basic #{Base64.
|
151
|
+
headers["Authorization"] = "Basic #{Base64.strict_encode64("#{@args[:basic_auth][:user]}:#{@args[:basic_auth][:passwd]}").strip}"
|
152
|
+
end
|
153
|
+
|
154
|
+
if @args[:proxy] && @args[:proxy][:user] && @args[:proxy][:passwd] && !@connection.proxy_connect?
|
155
|
+
require "base64" unless ::Kernel.const_defined?(:Base64)
|
156
|
+
puts "Http2: Adding proxy auth header to request" if @debug
|
157
|
+
headers["Proxy-Authorization"] = "Basic #{Base64.strict_encode64("#{@args[:proxy][:user]}:#{@args[:proxy][:passwd]}").strip}"
|
148
158
|
end
|
149
159
|
|
150
160
|
headers.merge!(@args[:extra_headers]) if @args[:extra_headers]
|
151
161
|
headers.merge!(args[:headers]) if args[:headers]
|
152
|
-
|
162
|
+
|
163
|
+
headers
|
153
164
|
end
|
154
165
|
|
155
|
-
#Posts to a certain page.
|
166
|
+
# Posts to a certain page.
|
156
167
|
#===Examples
|
157
168
|
# res = http.post("login.php", {"username" => "John Doe", "password" => 123)
|
158
169
|
def post(args)
|
159
170
|
::Http2::PostRequest.new(self, args).execute
|
160
171
|
end
|
161
172
|
|
162
|
-
#Posts to a certain page using the multipart-method.
|
173
|
+
# Posts to a certain page using the multipart-method.
|
163
174
|
#===Examples
|
164
175
|
# res = http.post_multipart("upload.php", {"normal_value" => 123, "file" => Tempfile.new(?)})
|
165
176
|
def post_multipart(*args)
|
166
177
|
::Http2::PostMultipartRequest.new(self, *args).execute
|
167
178
|
end
|
168
179
|
|
169
|
-
#Returns a header-string which normally would be used for a request in the given state.
|
170
|
-
def header_str(headers_hash
|
171
|
-
headers_hash["Cookie"] = cookie_header_string
|
180
|
+
# Returns a header-string which normally would be used for a request in the given state.
|
181
|
+
def header_str(headers_hash)
|
182
|
+
headers_hash["Cookie"] = cookie_header_string unless cookie_header_string.empty?
|
172
183
|
|
173
184
|
headers_str = ""
|
174
185
|
headers_hash.each do |key, val|
|
175
186
|
headers_str << "#{key}: #{val}#{@nl}"
|
176
187
|
end
|
177
188
|
|
178
|
-
|
189
|
+
headers_str
|
179
190
|
end
|
180
191
|
|
181
192
|
def cookie_header_string
|
182
193
|
cstr = ""
|
183
194
|
|
184
195
|
first = true
|
185
|
-
@cookies.each do |
|
196
|
+
@cookies.each do |_cookie_name, cookie|
|
186
197
|
cstr << "; " unless first
|
187
198
|
first = false if first
|
199
|
+
ensure_single_lines([cookie.name, cookie.value])
|
200
|
+
cstr << "#{Http2::Utils.urlenc(cookie.name)}=#{Http2::Utils.urlenc(cookie.value)}"
|
201
|
+
end
|
188
202
|
|
189
|
-
|
190
|
-
|
191
|
-
value = cookie_data["value"]
|
192
|
-
else
|
193
|
-
name = cookie_name
|
194
|
-
value = cookie_data
|
195
|
-
end
|
203
|
+
cstr
|
204
|
+
end
|
196
205
|
|
197
|
-
|
198
|
-
|
199
|
-
|
206
|
+
def cookie(name)
|
207
|
+
name = name.to_s
|
208
|
+
return @cookies.fetch(name) if @cookies.key?(name)
|
200
209
|
|
201
|
-
|
210
|
+
raise "No cookie by that name: '#{name}' in '#{@cookies.keys.join(", ")}'"
|
211
|
+
end
|
212
|
+
|
213
|
+
def ensure_single_lines(*strings)
|
214
|
+
strings.each do |string|
|
215
|
+
raise "More than one line: #{string}." unless string.to_s.lines.to_a.length == 1
|
216
|
+
end
|
202
217
|
end
|
203
218
|
|
204
219
|
def on_content_call(args, str)
|
205
220
|
args[:on_content].call(str) if args.key?(:on_content)
|
206
221
|
end
|
207
222
|
|
208
|
-
#Reads the response after posting headers and data.
|
223
|
+
# Reads the response after posting headers and data.
|
209
224
|
#===Examples
|
210
225
|
# res = http.read_response
|
211
|
-
def read_response(args = {})
|
212
|
-
::Http2::ResponseReader.new(http2: self, sock: @sock, args: args).response
|
226
|
+
def read_response(request, args = {})
|
227
|
+
::Http2::ResponseReader.new(http2: self, sock: @sock, args: args, request: request).response
|
228
|
+
end
|
229
|
+
|
230
|
+
def to_s
|
231
|
+
"<Http2 host: #{host}:#{port}>"
|
232
|
+
end
|
233
|
+
|
234
|
+
def inspect
|
235
|
+
to_s
|
213
236
|
end
|
214
237
|
|
215
238
|
private
|
216
239
|
|
217
|
-
|
240
|
+
def host_header
|
241
|
+
# Possible to give custom host-argument.
|
242
|
+
host = args[:host] || self.host
|
243
|
+
port = args[:port] || self.port
|
244
|
+
|
245
|
+
host_header_string = host.dup # Copy host string to avoid changing the original string if port has been given!
|
246
|
+
host_header_string << ":#{port}" if port && ![80, 443].include?(port.to_i) && !@args[:skip_port_in_host_header]
|
247
|
+
host_header_string
|
248
|
+
end
|
249
|
+
|
250
|
+
# Registers the states from a result.
|
218
251
|
def autostate_register(res)
|
219
252
|
puts "Http2: Running autostate-register on result." if @debug
|
220
253
|
@autostate_values.clear
|
221
254
|
|
222
255
|
res.body.to_s.scan(/<input type="hidden" name="__(EVENTTARGET|EVENTARGUMENT|VIEWSTATE|LASTFOCUS)" id="(.*?)" value="(.*?)" \/>/) do |match|
|
223
256
|
name = "__#{match[0]}"
|
224
|
-
id = match[1]
|
225
257
|
value = match[2]
|
226
258
|
|
227
259
|
puts "Http2: Registered autostate-value with name '#{name}' and value '#{value}'." if @debug
|
@@ -231,21 +263,24 @@ private
|
|
231
263
|
raise "No states could be found." if @autostate_values.empty?
|
232
264
|
end
|
233
265
|
|
234
|
-
#Sets the states on the given post-hash.
|
266
|
+
# Sets the states on the given post-hash.
|
235
267
|
def autostate_set_on_post_hash(phash)
|
236
268
|
phash.merge!(@autostate_values)
|
237
269
|
end
|
238
270
|
|
239
271
|
def parse_init_args(args)
|
240
|
-
args = {:
|
272
|
+
args = {host: args} if args.is_a?(String)
|
241
273
|
raise "Arguments wasnt a hash." unless args.is_a?(Hash)
|
242
274
|
|
243
|
-
args.
|
275
|
+
args.each_key do |key|
|
244
276
|
raise "Invalid key: '#{key}'." unless VALID_ARGUMENTS_INITIALIZE.include?(key)
|
245
277
|
end
|
246
278
|
|
279
|
+
args[:proxy][:connect] = true if args[:proxy] && !args[:proxy].key?(:connect) && args[:ssl]
|
280
|
+
|
247
281
|
raise "No host was given." unless args[:host]
|
248
|
-
|
282
|
+
|
283
|
+
args
|
249
284
|
end
|
250
285
|
|
251
286
|
def set_default_values
|
@@ -253,7 +288,7 @@ private
|
|
253
288
|
@autostate_values = {} if autostate
|
254
289
|
@nl = @args[:nl] || "\r\n"
|
255
290
|
|
256
|
-
|
291
|
+
unless @args[:port]
|
257
292
|
if @args[:ssl]
|
258
293
|
@args[:port] = 443
|
259
294
|
else
|
@@ -273,4 +308,4 @@ private
|
|
273
308
|
@raise_errors = false
|
274
309
|
end
|
275
310
|
end
|
276
|
-
end
|
311
|
+
end
|