http2 0.0.28 → 0.0.33
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
[![Code Climate](https://codeclimate.com/github/kaspernj/http2.png)](https://codeclimate.com/github/kaspernj/http2)
|
2
|
+
[![Build Status](https://www.peakflow.io/en/projects/http2/branch-statuses/master.svg
|
3
|
+
)](https://www.peakflow.io/en/projects/http2/build-groups)
|
4
|
+
|
1
5
|
# http2
|
2
6
|
|
3
|
-
|
4
|
-
[![Code Climate](https://codeclimate.com/github/kaspernj/http2.png)](https://codeclimate.com/github/kaspernj/http2)
|
5
|
-
[![Code Climate](https://codeclimate.com/github/kaspernj/http2/coverage.png)](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
|