sapoci-connect 0.1.13 → 0.5.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 +5 -5
- data/CHANGELOG.md +7 -0
- data/LICENSE +1 -1
- data/README.md +60 -29
- data/bin/sapoci-search +12 -13
- data/lib/sapoci/connect.rb +28 -17
- data/lib/sapoci/connect/middleware/background_search.rb +27 -7
- data/lib/sapoci/connect/middleware/follow_redirects.rb +108 -55
- metadata +63 -54
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 73d5cc2a601abaeac5f0c1714fc3d90c3d9aeed867fb27b5db55b7ad419253b6
|
4
|
+
data.tar.gz: 29681db3952f41460c3bc23c515b21df82662739ae6059961f59a86e09c4a081
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 448e88f525d88480eee90519947541ab7ff84933bc0b951681a8a5635f42510a19fb969de266420043c6b952c0f810738fa731441c9a75da8c0fb2a503867b6c
|
7
|
+
data.tar.gz: 84ce2cbc421695b64a9ddf457f673e8581bbe72933d81e959e989ecd88726e822728c7b00e0e3e85ed2c40f1d68db1072e2f3ad05dd3fa10ba9090ba762e1f2d
|
data/CHANGELOG.md
CHANGED
data/LICENSE
CHANGED
data/README.md
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# SAP OCI Connect
|
2
2
|
|
3
3
|
We use this library to work with eprocurement punchout systems that
|
4
|
-
comply to the SAP OCI 4.0 specification.
|
4
|
+
comply to the SAP OCI 4.0 and 5.0 specification.
|
5
5
|
|
6
6
|
## Features
|
7
7
|
|
@@ -9,47 +9,78 @@ comply to the SAP OCI 4.0 specification.
|
|
9
9
|
|
10
10
|
It's as simple as this:
|
11
11
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
12
|
+
```ruby
|
13
|
+
conn = Faraday.new("http://onlineshop.com/path")
|
14
|
+
resp = SAPOCI::Connect.search(:get, conn, "toner", "http://return.to/me")
|
15
|
+
puts resp.status # => 200
|
16
|
+
puts resp.body # => <SAPOCI::Document>
|
17
|
+
puts resp.env[:raw_body] # => "<html>...</html>"
|
18
|
+
```
|
19
|
+
|
20
|
+
You can configure the Faraday connection in all detail. Just be sure to
|
21
|
+
include the SAPOCI middleware. Here's an example:
|
22
|
+
|
23
|
+
```ruby
|
24
|
+
conn = Faraday.new("http://onlineshop.com/path", params: {"token" => "123"}) do |builder|
|
25
|
+
builder.use SAPOCI::Connect::Middleware::FollowRedirects, {cookies: :all, limit: 5}
|
26
|
+
builder.use SAPOCI::Connect::Middleware::BackgroundSearch, {preserve_raw: true}
|
27
|
+
builder.adapter :net_http
|
28
|
+
end
|
29
|
+
```
|
30
|
+
|
31
|
+
Or, use symbols:
|
32
|
+
|
33
|
+
```ruby
|
34
|
+
conn = Faraday.new("http://onlineshop.com/path", params: {"token" => "123"}) do |builder|
|
35
|
+
builder.use :oci_follow_redirects, {cookies: :all, limit: 5}
|
36
|
+
builder.use :oci_background_search, {preserve_raw: true}
|
37
|
+
builder.adapter :net_http
|
38
|
+
end
|
39
|
+
```
|
40
|
+
|
41
|
+
The `SAPOCI::Connect::Middleware::FollowRedirects` expands on the existing
|
42
|
+
`FaradayMiddleware::FollowRedirects` middleware in that it forwards cookies
|
43
|
+
and returns some errors like e.g. when a redirect is blank or
|
44
|
+
the maximum number of redirects is reached.
|
45
|
+
|
46
|
+
The `SAPOCI::Connect::Middleware::BackgroundSearch` automatically parses the
|
47
|
+
response body (just like the JSON and XML parser middlewares do), and returns
|
48
|
+
an `SAPOCI::Document` to look into. Notice that `{preserve_raw: true}` needs
|
49
|
+
to be passed as well if you want the original HTTP response body in
|
50
|
+
`response.env[:raw_body]`.
|
51
|
+
|
52
|
+
Review [Faraday](https://github.com/lostisland/faraday) for details on
|
53
|
+
connection initiation. We require Faraday version 1.0.1 or later.
|
28
54
|
|
29
55
|
## Testing
|
30
56
|
|
31
57
|
Here's how to test locally:
|
32
58
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
59
|
+
```sh
|
60
|
+
$ bundle install
|
61
|
+
$ # Start a second console
|
62
|
+
$ rake start_test_server
|
63
|
+
$ # Back in first console
|
64
|
+
$ bundle exec rake test
|
65
|
+
```
|
38
66
|
|
39
|
-
To test
|
67
|
+
To test remote OCI punchout shops, use the `REMOTE` environment variable:
|
40
68
|
|
41
|
-
|
69
|
+
```sh
|
70
|
+
$ REMOTE="http://remote-site.com/Login.aspx?u=demo&p=secret" rake
|
71
|
+
```
|
42
72
|
|
43
73
|
## Credits
|
44
74
|
|
45
75
|
Standing on the shoulder of giants, where giants include:
|
46
76
|
|
47
|
-
* Rick Olson for
|
77
|
+
* Rick Olson and all contributors for
|
78
|
+
[faraday](https://github.com/lostisland/faraday),
|
48
79
|
* Erik Michaels-Ober, Wynn Netherland, et al. for
|
49
|
-
[faraday_middleware](https://github.com/
|
50
|
-
* Ilya Grigorik for [em-synchrony](https://github.com/igrigorik/em-synchrony),
|
51
|
-
[em-http-request](https://github.com/igrigorik/em-http-request) and stuff,
|
52
|
-
* David Balatero and Paul Dix for [typhoeus](https://github.com/dbalatero/typhoeus)
|
80
|
+
[faraday_middleware](https://github.com/lostisland/faraday_middleware)
|
53
81
|
|
54
82
|
... and many other contributors. Thanks, guys. You rock!
|
55
83
|
|
84
|
+
## License
|
85
|
+
|
86
|
+
MIT. See [LICENSE](https://github.com/meplato/sapoci-connect/blob/master/LICENSE).
|
data/bin/sapoci-search
CHANGED
@@ -55,22 +55,22 @@ begin
|
|
55
55
|
uri.query = nil
|
56
56
|
|
57
57
|
# Setup
|
58
|
-
conn = Faraday.new(uri.to_s, :
|
59
|
-
builder.
|
60
|
-
builder.
|
61
|
-
builder.
|
62
|
-
builder.adapter
|
58
|
+
conn = Faraday.new(uri.to_s, ssl: {verify: true}) do |builder|
|
59
|
+
builder.use :oci_follow_redirects, {cookies: :all, limit: 10}
|
60
|
+
builder.use :oci_background_search, {preserve_raw: true}
|
61
|
+
builder.response :logger if options.debug
|
62
|
+
builder.adapter Faraday.default_adapter
|
63
63
|
end
|
64
64
|
|
65
65
|
# Respect proxy settings
|
66
66
|
options.proxy_uri ||= ENV['SAPOCI_PROXY_URI']
|
67
|
-
conn.proxy({:
|
67
|
+
conn.proxy({uri: options.proxy_uri}) if options.proxy_uri
|
68
68
|
|
69
69
|
# Execute
|
70
70
|
method = options.http_post ? :post : :get
|
71
|
-
resp = SAPOCI::Connect.search(method, conn, keywords, "http://
|
71
|
+
resp = SAPOCI::Connect.search(method, conn, keywords, "http://validator.meplato.com/oci/punchouts/checkout", params)
|
72
72
|
if resp.status == 200
|
73
|
-
doc = resp.
|
73
|
+
doc = resp.body
|
74
74
|
$stdout.puts "%3s %-15s %-30s %s" % ["Idx", "Vendormat", "Description", "Price per unit"]
|
75
75
|
$stdout.puts "".ljust(98, '-')
|
76
76
|
doc.items.each do |item|
|
@@ -78,23 +78,22 @@ begin
|
|
78
78
|
$stdout.puts " %s" % [item.longtext]
|
79
79
|
end
|
80
80
|
$stdout.puts "===> #{doc.items.size} items"
|
81
|
-
$stdout.puts resp.
|
81
|
+
$stdout.puts resp.env[:raw_body].to_s if options.debug
|
82
82
|
exit 0
|
83
83
|
elsif resp.status == 404
|
84
84
|
$stdout.puts "Not found (HTTP status #{resp.status})"
|
85
|
-
$stdout.puts resp.
|
85
|
+
$stdout.puts resp.env[:raw_body].to_s if options.debug
|
86
86
|
exit 1
|
87
87
|
elsif resp.status == 500
|
88
88
|
$stdout.puts "Server crashed (HTTP status #{resp.status})"
|
89
|
-
$stdout.puts resp.
|
89
|
+
$stdout.puts resp.env[:raw_body].to_s if options.debug
|
90
90
|
exit 1
|
91
91
|
else
|
92
92
|
$stdout.puts "Error: HTTP status code=#{resp.status}"
|
93
|
-
$stdout.puts resp.
|
93
|
+
$stdout.puts resp.env[:raw_body].to_s if options.debug
|
94
94
|
exit 1
|
95
95
|
end
|
96
96
|
|
97
|
-
|
98
97
|
rescue => e
|
99
98
|
$stderr.print "#{e.class}: " unless e.class == RuntimeError
|
100
99
|
$stderr.puts e.message
|
data/lib/sapoci/connect.rb
CHANGED
@@ -1,34 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'faraday'
|
4
|
+
require 'faraday_middleware'
|
2
5
|
require 'sapoci'
|
3
6
|
require 'sapoci/connect/middleware/follow_redirects'
|
4
7
|
require 'sapoci/connect/middleware/background_search'
|
5
8
|
|
6
9
|
module SAPOCI
|
7
10
|
module Connect
|
8
|
-
|
9
|
-
# Register Faraday middleware
|
10
|
-
if Faraday.respond_to?(:register_middleware)
|
11
|
-
Faraday.register_middleware :response,
|
12
|
-
:follow_redirects => lambda { SAPOCI::Connect::Middleware::FollowRedirects },
|
13
|
-
:background_search => lambda { SAPOCI::Connect::Middleware::BackgroundSearch }
|
14
|
-
end
|
15
|
-
|
16
11
|
# Perform an OCI background search.
|
17
12
|
#
|
18
13
|
# If you need to follow redirects and pass cookies along, you should
|
19
14
|
# initialize and use Faraday with this pattern:
|
20
15
|
#
|
21
|
-
# conn = Faraday.new("http://shop.com/path", :
|
22
|
-
# builder.response :follow_redirects, :cookies => :all, :limit => 5, :standards_compliant => true
|
23
|
-
# builder.response :background_search
|
24
|
-
# builder.adapter Faraday.default_adapter
|
25
|
-
# end
|
16
|
+
# conn = Faraday.new("http://shop.com/path", params: {"optional" => "value"})
|
26
17
|
# conn.options[:timeout] = 3
|
27
18
|
# conn.options[:open_timeout] = 5
|
19
|
+
#
|
28
20
|
# resp = SAPOCI::Connect.search(:get, conn, "toner", "http://return.to/me")
|
29
|
-
# puts resp.status
|
30
|
-
# puts resp.body
|
21
|
+
# puts resp.status # => 200
|
22
|
+
# puts resp.body # => <SAPOCI::Document>
|
23
|
+
# puts resp.env[:raw_body] # => "<html>...</html>"
|
31
24
|
#
|
25
|
+
# Notice you can configure the Faraday connection:
|
26
|
+
#
|
27
|
+
# conn = Faraday.new("http://shop.com/path", params: {"optional" => "value"}) do |builder|
|
28
|
+
# builder.use SAPOCI::Connect::Middleware::FollowRedirects, {cookies: :all, limit: 5}
|
29
|
+
# builder.use SAPOCI::Connect::Middleware::BackgroundSearch, {preserve_raw: true}
|
30
|
+
# builder.adapter Faraday.default_adapter
|
31
|
+
# end
|
32
|
+
#
|
33
|
+
# ... or with symbols:
|
34
|
+
#
|
35
|
+
# conn = Faraday.new("http://shop.com/path", params: {"optional" => "value"}) do |builder|
|
36
|
+
# builder.use :oci_follow_redirects, {cookies: :all, limit: 5}
|
37
|
+
# builder.use :oci_background_search, {preserve_raw: true}
|
38
|
+
# builder.adapter Faraday.default_adapter
|
39
|
+
# end
|
32
40
|
def self.search(method, connection, keywords, hook_url, extra_params = nil)
|
33
41
|
params = {
|
34
42
|
"FUNCTION" => "BACKGROUND_SEARCH",
|
@@ -37,8 +45,11 @@ module SAPOCI
|
|
37
45
|
}
|
38
46
|
params.update(extra_params) if extra_params
|
39
47
|
|
48
|
+
unless connection.builder.handlers.include?(SAPOCI::Connect::Middleware::FollowRedirects)
|
49
|
+
connection.use SAPOCI::Connect::Middleware::FollowRedirects, {cookies: :all, limit: 5}
|
50
|
+
end
|
40
51
|
unless connection.builder.handlers.include?(SAPOCI::Connect::Middleware::BackgroundSearch)
|
41
|
-
connection.
|
52
|
+
connection.use SAPOCI::Connect::Middleware::BackgroundSearch, {preserve_raw: true}
|
42
53
|
end
|
43
54
|
|
44
55
|
case method.to_sym
|
@@ -48,7 +59,7 @@ module SAPOCI
|
|
48
59
|
end
|
49
60
|
when :post
|
50
61
|
connection.post do |req|
|
51
|
-
req.body = Faraday::Utils.build_nested_query
|
62
|
+
req.body = Faraday::Utils.build_nested_query(params)
|
52
63
|
end
|
53
64
|
else
|
54
65
|
raise "SAPOCI::Connect.search only allows :get or :post requests"
|
@@ -1,15 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'faraday_middleware/response_middleware'
|
4
|
+
|
1
5
|
module SAPOCI
|
2
6
|
module Connect
|
3
7
|
module Middleware
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
8
|
+
# BackgroundSearch is a Faraday response middleware that parses
|
9
|
+
# the response body into a SAPOCI::Document.
|
10
|
+
#
|
11
|
+
# If you want Faraday to preserve the original HTTP response body,
|
12
|
+
# pass `preserve_raw: true` to the parser.
|
13
|
+
#
|
14
|
+
# Example:
|
15
|
+
#
|
16
|
+
# conn = Faraday.new("http://onlineshop.com/path", params: {"token" => "123"}) do |builder|
|
17
|
+
# builder.use SAPOCI::Connect::Middleware::FollowRedirects, {cookies: :all, limit: 5}
|
18
|
+
# builder.use SAPOCI::Connect::Middleware::BackgroundSearch, {preserve_raw: true}
|
19
|
+
# builder.adapter :net_http
|
20
|
+
# end
|
21
|
+
class BackgroundSearch < FaradayMiddleware::ResponseMiddleware
|
22
|
+
dependency 'sapoci'
|
23
|
+
|
24
|
+
define_parser do |body, parser_options|
|
25
|
+
::SAPOCI::Document.from_html(body) unless body.empty?
|
11
26
|
end
|
12
27
|
end
|
28
|
+
|
29
|
+
# Register known middlewares under symbol
|
30
|
+
if Faraday::Middleware.respond_to?(:register_middleware)
|
31
|
+
Faraday::Middleware.register_middleware oci_background_search: -> { SAPOCI::Connect::Middleware::BackgroundSearch }
|
32
|
+
end
|
13
33
|
end
|
14
34
|
end
|
15
35
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'faraday'
|
2
4
|
require 'set'
|
3
5
|
require 'webrick'
|
@@ -6,7 +8,7 @@ module SAPOCI
|
|
6
8
|
module Connect
|
7
9
|
module Middleware
|
8
10
|
# Public: Exception thrown when the maximum amount of requests is exceeded.
|
9
|
-
class RedirectLimitReached < Faraday::
|
11
|
+
class RedirectLimitReached < Faraday::ClientError
|
10
12
|
attr_reader :response
|
11
13
|
|
12
14
|
def initialize(response)
|
@@ -14,9 +16,9 @@ module SAPOCI
|
|
14
16
|
@response = response
|
15
17
|
end
|
16
18
|
end
|
17
|
-
|
19
|
+
|
18
20
|
# Public: Exception thrown when client returns an empty location header
|
19
|
-
class RedirectWithoutLocation < Faraday::
|
21
|
+
class RedirectWithoutLocation < Faraday::ClientError
|
20
22
|
attr_reader :response
|
21
23
|
|
22
24
|
def initialize(response)
|
@@ -24,54 +26,62 @@ module SAPOCI
|
|
24
26
|
@response = response
|
25
27
|
end
|
26
28
|
end
|
27
|
-
|
28
|
-
# Public: Follow HTTP 301, 302, 303, and
|
29
|
-
# PUT, and DELETE requests.
|
29
|
+
|
30
|
+
# Public: Follow HTTP 301, 302, 303, 307, and 308 redirects.
|
30
31
|
#
|
31
|
-
#
|
32
|
-
#
|
33
|
-
#
|
34
|
-
#
|
32
|
+
# For HTTP 301, 302, and 303, the original GET, POST, PUT, DELETE, or PATCH
|
33
|
+
# request gets converted into a GET. With `standards_compliant: true`,
|
34
|
+
# however, the HTTP method after 301/302 remains unchanged. This allows you
|
35
|
+
# to opt into HTTP/1.1 compliance and act unlike the major web browsers.
|
35
36
|
#
|
36
|
-
#
|
37
|
-
#
|
38
|
-
# compliance enabled, a 302 will instead act in accordance with the HTTP
|
39
|
-
# specification, which will replay the original request to the received
|
40
|
-
# Location, just as with a 307.
|
37
|
+
# This middleware currently only works with synchronous requests; i.e. it
|
38
|
+
# doesn't support parallelism.
|
41
39
|
#
|
42
|
-
#
|
43
|
-
# including original HTTP request method (GET, POST, PUT, DELETE, PATCH),
|
44
|
-
# original headers, and original body.
|
40
|
+
# Example:
|
45
41
|
#
|
46
|
-
#
|
47
|
-
#
|
42
|
+
# Faraday.new(url: url) do |faraday|
|
43
|
+
# faraday.use SAPOCI::Connect::Middleware::FollowRedirects
|
44
|
+
# faraday.adapter Faraday.default_adapter
|
45
|
+
# end
|
48
46
|
class FollowRedirects < Faraday::Middleware
|
49
47
|
# HTTP methods for which 30x redirects can be followed
|
50
|
-
ALLOWED_METHODS = Set.new [
|
48
|
+
ALLOWED_METHODS = Set.new %i[head options get post put patch delete]
|
51
49
|
# HTTP redirect status codes that this middleware implements
|
52
|
-
REDIRECT_CODES = Set.new [301, 302, 303, 307]
|
50
|
+
REDIRECT_CODES = Set.new [301, 302, 303, 307, 308]
|
53
51
|
# Keys in env hash which will get cleared between requests
|
54
|
-
ENV_TO_CLEAR = Set.new [
|
52
|
+
ENV_TO_CLEAR = Set.new %i[status response response_headers]
|
55
53
|
|
56
54
|
# Default value for max redirects followed
|
57
55
|
FOLLOW_LIMIT = 3
|
58
56
|
|
57
|
+
# Regex that matches characters that need to be escaped in URLs, sans
|
58
|
+
# the "%" character which we assume already represents an escaped sequence.
|
59
|
+
URI_UNSAFE = %r{[^\-_.!~*'()a-zA-Z\d;/?:@&=+$,\[\]%]}.freeze
|
60
|
+
|
61
|
+
AUTH_HEADER = 'Authorization'
|
62
|
+
|
59
63
|
# Public: Initialize the middleware.
|
60
64
|
#
|
61
65
|
# options - An options Hash (default: {}):
|
62
|
-
#
|
63
|
-
#
|
64
|
-
#
|
65
|
-
#
|
66
|
+
# :limit - A Numeric redirect limit (default: 3)
|
67
|
+
# :standards_compliant - A Boolean indicating whether to respect
|
68
|
+
# the HTTP spec when following 301/302
|
69
|
+
# (default: false)
|
70
|
+
# :callback - A callable used on redirects
|
71
|
+
# with the old and new envs
|
72
|
+
# :cookies - An Array of Strings (e.g.
|
73
|
+
# ['cookie1', 'cookie2']) to choose
|
74
|
+
# cookies to be kept, or :all to keep
|
75
|
+
# all cookies (default: []).
|
76
|
+
# :clear_authorization_header - A Boolean indicating whether the request
|
77
|
+
# Authorization header should be cleared on
|
78
|
+
# redirects (default: true)
|
66
79
|
def initialize(app, options = {})
|
67
80
|
super(app)
|
68
81
|
@options = options
|
69
82
|
|
70
|
-
@
|
71
|
-
@
|
72
|
-
|
73
|
-
@replay_request_codes = Set.new [307]
|
74
|
-
@replay_request_codes << 302 if standards_compliant?
|
83
|
+
@convert_to_get = Set.new [303]
|
84
|
+
@convert_to_get << 301 << 302 unless standards_compliant?
|
75
85
|
end
|
76
86
|
|
77
87
|
def call(env)
|
@@ -80,72 +90,115 @@ module SAPOCI
|
|
80
90
|
|
81
91
|
private
|
82
92
|
|
83
|
-
def
|
84
|
-
|
93
|
+
def convert_to_get?(response)
|
94
|
+
!%i[head options].include?(response.env[:method]) &&
|
95
|
+
@convert_to_get.include?(response.status)
|
85
96
|
end
|
86
97
|
|
87
98
|
def perform_with_redirection(env, follows)
|
88
99
|
request_body = env[:body]
|
89
100
|
response = @app.call(env)
|
90
101
|
|
91
|
-
response.on_complete do |
|
92
|
-
if follow_redirect?(
|
93
|
-
raise RedirectLimitReached, response if follows.zero?
|
94
|
-
|
95
|
-
|
102
|
+
response.on_complete do |response_env|
|
103
|
+
if follow_redirect?(response_env, response)
|
104
|
+
raise SAPOCI::Connect::Middleware::RedirectLimitReached, response if follows.zero?
|
105
|
+
|
106
|
+
new_request_env = update_env(response_env.dup, request_body, response)
|
107
|
+
callback&.call(response_env, new_request_env)
|
108
|
+
response = perform_with_redirection(new_request_env, follows - 1)
|
96
109
|
end
|
97
110
|
end
|
98
111
|
response
|
99
112
|
end
|
100
113
|
|
101
114
|
def update_env(env, request_body, response)
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
115
|
+
redirect_from_url = env[:url].to_s
|
116
|
+
redirect_to_url = safe_escape(response['location'] || '')
|
117
|
+
raise RedirectWithoutLocation, response if redirect_to_url.blank?
|
118
|
+
env[:url] += redirect_to_url
|
119
|
+
|
106
120
|
if @options[:cookies] && cookie_string = collect_cookies(env)
|
107
121
|
env[:request_headers]['Cookie'] = cookie_string
|
108
122
|
end
|
109
123
|
|
110
|
-
|
124
|
+
ENV_TO_CLEAR.each { |key| env.delete key }
|
125
|
+
|
126
|
+
if convert_to_get?(response)
|
111
127
|
env[:method] = :get
|
112
128
|
env[:body] = nil
|
113
129
|
else
|
114
130
|
env[:body] = request_body
|
115
131
|
end
|
116
132
|
|
117
|
-
|
133
|
+
clear_authorization_header(env, redirect_from_url, redirect_to_url)
|
118
134
|
|
119
135
|
env
|
120
136
|
end
|
121
137
|
|
122
138
|
def follow_redirect?(env, response)
|
123
|
-
ALLOWED_METHODS.include?
|
124
|
-
REDIRECT_CODES.include?
|
139
|
+
ALLOWED_METHODS.include?(env[:method]) &&
|
140
|
+
REDIRECT_CODES.include?(response.status)
|
125
141
|
end
|
126
142
|
|
127
143
|
def follow_limit
|
128
144
|
@options.fetch(:limit, FOLLOW_LIMIT)
|
129
145
|
end
|
130
146
|
|
147
|
+
def standards_compliant?
|
148
|
+
@options.fetch(:standards_compliant, false)
|
149
|
+
end
|
150
|
+
|
151
|
+
def callback
|
152
|
+
@options[:callback]
|
153
|
+
end
|
154
|
+
|
155
|
+
# Internal: escapes unsafe characters from an URL which might be a path
|
156
|
+
# component only or a fully qualified URI so that it can be joined onto an
|
157
|
+
# URI:HTTP using the `+` operator. Doesn't escape "%" characters so to not
|
158
|
+
# risk double-escaping.
|
159
|
+
def safe_escape(uri)
|
160
|
+
uri = uri.split('#')[0] # we want to remove the fragment if present
|
161
|
+
uri.to_s.gsub(URI_UNSAFE) do |match|
|
162
|
+
'%' + match.unpack('H2' * match.bytesize).join('%').upcase
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
def clear_authorization_header(env, from_url, to_url)
|
167
|
+
return env if redirect_to_same_host?(from_url, to_url)
|
168
|
+
return env unless @options.fetch(:clear_authorization_header, true)
|
169
|
+
|
170
|
+
env[:request_headers].delete(AUTH_HEADER)
|
171
|
+
end
|
172
|
+
|
173
|
+
def redirect_to_same_host?(from_url, to_url)
|
174
|
+
return true if to_url.start_with?('/')
|
175
|
+
|
176
|
+
from_uri = URI.parse(from_url)
|
177
|
+
to_uri = URI.parse(to_url)
|
178
|
+
|
179
|
+
[from_uri.scheme, from_uri.host, from_uri.port] ==
|
180
|
+
[to_uri.scheme, to_uri.host, to_uri.port]
|
181
|
+
end
|
182
|
+
|
131
183
|
def collect_cookies(env)
|
132
184
|
if response_cookies = env[:response_headers]['Set-Cookie']
|
133
185
|
@cookies = WEBrick::Cookie.parse_set_cookies(response_cookies)
|
134
186
|
@cookies.inject([]) do |result, cookie|
|
135
|
-
#
|
136
|
-
|
137
|
-
|
138
|
-
|
187
|
+
# only send back name and value
|
188
|
+
if @options[:cookies] == :all || (@options[:cookies].include?(cookie.name.to_sym) || @options[:cookies].include?(cookie.name.to_s))
|
189
|
+
result << cookie.name + "=" + cookie.value
|
190
|
+
end
|
191
|
+
end.to_a.uniq.join(";")
|
139
192
|
else
|
140
193
|
nil
|
141
194
|
end
|
142
195
|
end
|
196
|
+
end
|
143
197
|
|
144
|
-
|
145
|
-
|
146
|
-
|
198
|
+
# Register known middlewares under symbol
|
199
|
+
if Faraday::Middleware.respond_to?(:register_middleware)
|
200
|
+
Faraday::Middleware.register_middleware oci_follow_redirects: -> { SAPOCI::Connect::Middleware::FollowRedirects }
|
147
201
|
end
|
148
202
|
end
|
149
203
|
end
|
150
204
|
end
|
151
|
-
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sapoci-connect
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Oliver Eilhard
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-07-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: faraday
|
@@ -16,142 +16,152 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
20
|
-
- - "<"
|
21
|
-
- !ruby/object:Gem::Version
|
22
|
-
version: '0.9'
|
19
|
+
version: 1.0.1
|
23
20
|
type: :runtime
|
24
21
|
prerelease: false
|
25
22
|
version_requirements: !ruby/object:Gem::Requirement
|
26
23
|
requirements:
|
27
24
|
- - "~>"
|
28
25
|
- !ruby/object:Gem::Version
|
29
|
-
version:
|
30
|
-
|
26
|
+
version: 1.0.1
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: faraday_middleware
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 1.0.0
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
31
39
|
- !ruby/object:Gem::Version
|
32
|
-
version:
|
40
|
+
version: 1.0.0
|
33
41
|
- !ruby/object:Gem::Dependency
|
34
42
|
name: rack
|
35
43
|
requirement: !ruby/object:Gem::Requirement
|
36
44
|
requirements:
|
37
45
|
- - "~>"
|
38
46
|
- !ruby/object:Gem::Version
|
39
|
-
version:
|
40
|
-
- - "<"
|
41
|
-
- !ruby/object:Gem::Version
|
42
|
-
version: '2'
|
47
|
+
version: 2.2.3
|
43
48
|
type: :runtime
|
44
49
|
prerelease: false
|
45
50
|
version_requirements: !ruby/object:Gem::Requirement
|
46
51
|
requirements:
|
47
52
|
- - "~>"
|
48
53
|
- !ruby/object:Gem::Version
|
49
|
-
version:
|
50
|
-
- - "<"
|
51
|
-
- !ruby/object:Gem::Version
|
52
|
-
version: '2'
|
54
|
+
version: 2.2.3
|
53
55
|
- !ruby/object:Gem::Dependency
|
54
56
|
name: sapoci
|
55
57
|
requirement: !ruby/object:Gem::Requirement
|
56
58
|
requirements:
|
57
59
|
- - "~>"
|
58
60
|
- !ruby/object:Gem::Version
|
59
|
-
version:
|
60
|
-
- - ">="
|
61
|
-
- !ruby/object:Gem::Version
|
62
|
-
version: 0.1.9
|
61
|
+
version: 0.5.0
|
63
62
|
type: :runtime
|
64
63
|
prerelease: false
|
65
64
|
version_requirements: !ruby/object:Gem::Requirement
|
66
65
|
requirements:
|
67
66
|
- - "~>"
|
68
67
|
- !ruby/object:Gem::Version
|
69
|
-
version:
|
70
|
-
- - ">="
|
71
|
-
- !ruby/object:Gem::Version
|
72
|
-
version: 0.1.9
|
68
|
+
version: 0.5.0
|
73
69
|
- !ruby/object:Gem::Dependency
|
74
|
-
name:
|
70
|
+
name: webrick
|
75
71
|
requirement: !ruby/object:Gem::Requirement
|
76
72
|
requirements:
|
77
73
|
- - "~>"
|
78
74
|
- !ruby/object:Gem::Version
|
79
|
-
version:
|
80
|
-
- - "<"
|
81
|
-
- !ruby/object:Gem::Version
|
82
|
-
version: '1.6'
|
75
|
+
version: 1.6.0
|
83
76
|
type: :runtime
|
84
77
|
prerelease: false
|
85
78
|
version_requirements: !ruby/object:Gem::Requirement
|
86
79
|
requirements:
|
87
80
|
- - "~>"
|
88
81
|
- !ruby/object:Gem::Version
|
89
|
-
version:
|
90
|
-
- - "<"
|
91
|
-
- !ruby/object:Gem::Version
|
92
|
-
version: '1.6'
|
82
|
+
version: 1.6.0
|
93
83
|
- !ruby/object:Gem::Dependency
|
94
84
|
name: bundler
|
95
85
|
requirement: !ruby/object:Gem::Requirement
|
96
86
|
requirements:
|
97
87
|
- - "~>"
|
98
88
|
- !ruby/object:Gem::Version
|
99
|
-
version:
|
89
|
+
version: 2.1.4
|
100
90
|
type: :development
|
101
91
|
prerelease: false
|
102
92
|
version_requirements: !ruby/object:Gem::Requirement
|
103
93
|
requirements:
|
104
94
|
- - "~>"
|
105
95
|
- !ruby/object:Gem::Version
|
106
|
-
version:
|
96
|
+
version: 2.1.4
|
107
97
|
- !ruby/object:Gem::Dependency
|
108
98
|
name: rdoc
|
109
99
|
requirement: !ruby/object:Gem::Requirement
|
110
100
|
requirements:
|
111
101
|
- - "~>"
|
112
102
|
- !ruby/object:Gem::Version
|
113
|
-
version:
|
103
|
+
version: 6.2.1
|
114
104
|
type: :development
|
115
105
|
prerelease: false
|
116
106
|
version_requirements: !ruby/object:Gem::Requirement
|
117
107
|
requirements:
|
118
108
|
- - "~>"
|
119
109
|
- !ruby/object:Gem::Version
|
120
|
-
version:
|
110
|
+
version: 6.2.1
|
121
111
|
- !ruby/object:Gem::Dependency
|
122
112
|
name: rake
|
123
113
|
requirement: !ruby/object:Gem::Requirement
|
124
114
|
requirements:
|
125
115
|
- - "~>"
|
126
116
|
- !ruby/object:Gem::Version
|
127
|
-
version:
|
117
|
+
version: 13.0.1
|
128
118
|
type: :development
|
129
119
|
prerelease: false
|
130
120
|
version_requirements: !ruby/object:Gem::Requirement
|
131
121
|
requirements:
|
132
122
|
- - "~>"
|
133
123
|
- !ruby/object:Gem::Version
|
134
|
-
version:
|
124
|
+
version: 13.0.1
|
135
125
|
- !ruby/object:Gem::Dependency
|
136
126
|
name: sinatra
|
137
127
|
requirement: !ruby/object:Gem::Requirement
|
138
128
|
requirements:
|
139
129
|
- - "~>"
|
140
130
|
- !ruby/object:Gem::Version
|
141
|
-
version: '
|
142
|
-
- - "
|
131
|
+
version: '2.0'
|
132
|
+
- - ">="
|
143
133
|
- !ruby/object:Gem::Version
|
144
|
-
version:
|
134
|
+
version: 2.0.8.1
|
145
135
|
type: :development
|
146
136
|
prerelease: false
|
147
137
|
version_requirements: !ruby/object:Gem::Requirement
|
148
138
|
requirements:
|
149
139
|
- - "~>"
|
150
140
|
- !ruby/object:Gem::Version
|
151
|
-
version: '
|
152
|
-
- - "
|
141
|
+
version: '2.0'
|
142
|
+
- - ">="
|
143
|
+
- !ruby/object:Gem::Version
|
144
|
+
version: 2.0.8.1
|
145
|
+
- !ruby/object:Gem::Dependency
|
146
|
+
name: sinatra-contrib
|
147
|
+
requirement: !ruby/object:Gem::Requirement
|
148
|
+
requirements:
|
149
|
+
- - "~>"
|
150
|
+
- !ruby/object:Gem::Version
|
151
|
+
version: '2.0'
|
152
|
+
- - ">="
|
153
153
|
- !ruby/object:Gem::Version
|
154
|
-
version:
|
154
|
+
version: 2.0.8.1
|
155
|
+
type: :development
|
156
|
+
prerelease: false
|
157
|
+
version_requirements: !ruby/object:Gem::Requirement
|
158
|
+
requirements:
|
159
|
+
- - "~>"
|
160
|
+
- !ruby/object:Gem::Version
|
161
|
+
version: '2.0'
|
162
|
+
- - ">="
|
163
|
+
- !ruby/object:Gem::Version
|
164
|
+
version: 2.0.8.1
|
155
165
|
description: HTTP client library for working with SAP OCI compliant servers.
|
156
166
|
email:
|
157
167
|
- oliver.eilhard@gmail.com
|
@@ -174,25 +184,24 @@ homepage: http://github.com/meplato/sapoci-connect
|
|
174
184
|
licenses:
|
175
185
|
- MIT
|
176
186
|
metadata: {}
|
177
|
-
post_install_message:
|
187
|
+
post_install_message:
|
178
188
|
rdoc_options:
|
179
189
|
- "--charset=UTF-8"
|
180
190
|
require_paths:
|
181
191
|
- lib
|
182
192
|
required_ruby_version: !ruby/object:Gem::Requirement
|
183
193
|
requirements:
|
184
|
-
- - "
|
194
|
+
- - "~>"
|
185
195
|
- !ruby/object:Gem::Version
|
186
|
-
version: '
|
196
|
+
version: '2.4'
|
187
197
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
188
198
|
requirements:
|
189
199
|
- - ">="
|
190
200
|
- !ruby/object:Gem::Version
|
191
|
-
version:
|
201
|
+
version: '0'
|
192
202
|
requirements: []
|
193
|
-
|
194
|
-
|
195
|
-
signing_key:
|
203
|
+
rubygems_version: 3.0.3
|
204
|
+
signing_key:
|
196
205
|
specification_version: 4
|
197
206
|
summary: The library builds on the sapoci gem and adds working with remotes, parsing
|
198
207
|
its results etc.
|