sapoci-connect 0.1.14 → 0.5.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/CHANGELOG.md +7 -0
- data/LICENSE +1 -1
- data/README.md +62 -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 +55 -58
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: e091ad746f1c988fa9130ee59fa46db62371e40437f503f29d3ea7d5996a2715
|
4
|
+
data.tar.gz: 75c2fe60de24231d2c5a544649758aba98add78ef341b19c4a0f23bf851dd86a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 60d97f0f3a02c0a60524aeb1f2161095d07cd6fd1dd216ad181360ca4c03b04fb809a49a536047588ea5f388e7758155cadf9e9c41b3c7f44b230a17ade4b01a
|
7
|
+
data.tar.gz: 79208605ea5b145df2d19c24fdf5f8f8265603472f770de409c8051193d0e394ea8240db76d0bea396dca218ae58596dae6d1e81e5c8b432d16c3fa0e26041f8
|
data/CHANGELOG.md
CHANGED
data/LICENSE
CHANGED
data/README.md
CHANGED
@@ -1,7 +1,9 @@
|
|
1
1
|
# SAP OCI Connect
|
2
2
|
|
3
|
+
[![Test](https://github.com/meplato/sapoci-connect/actions/workflows/test.yml/badge.svg)](https://github.com/meplato/sapoci-connect/actions/workflows/test.yml)
|
4
|
+
|
3
5
|
We use this library to work with eprocurement punchout systems that
|
4
|
-
comply to the SAP OCI 4.0 specification.
|
6
|
+
comply to the SAP OCI 4.0 and 5.0 specification.
|
5
7
|
|
6
8
|
## Features
|
7
9
|
|
@@ -9,47 +11,78 @@ comply to the SAP OCI 4.0 specification.
|
|
9
11
|
|
10
12
|
It's as simple as this:
|
11
13
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
14
|
+
```ruby
|
15
|
+
conn = Faraday.new("http://onlineshop.com/path")
|
16
|
+
resp = SAPOCI::Connect.search(:get, conn, "toner", "http://return.to/me")
|
17
|
+
puts resp.status # => 200
|
18
|
+
puts resp.body # => <SAPOCI::Document>
|
19
|
+
puts resp.env[:raw_body] # => "<html>...</html>"
|
20
|
+
```
|
21
|
+
|
22
|
+
You can configure the Faraday connection in all detail. Just be sure to
|
23
|
+
include the SAPOCI middleware. Here's an example:
|
24
|
+
|
25
|
+
```ruby
|
26
|
+
conn = Faraday.new("http://onlineshop.com/path", params: {"token" => "123"}) do |builder|
|
27
|
+
builder.use SAPOCI::Connect::Middleware::FollowRedirects, {cookies: :all, limit: 5}
|
28
|
+
builder.use SAPOCI::Connect::Middleware::BackgroundSearch, {preserve_raw: true}
|
29
|
+
builder.adapter :net_http
|
30
|
+
end
|
31
|
+
```
|
32
|
+
|
33
|
+
Or, use symbols:
|
34
|
+
|
35
|
+
```ruby
|
36
|
+
conn = Faraday.new("http://onlineshop.com/path", params: {"token" => "123"}) do |builder|
|
37
|
+
builder.use :oci_follow_redirects, {cookies: :all, limit: 5}
|
38
|
+
builder.use :oci_background_search, {preserve_raw: true}
|
39
|
+
builder.adapter :net_http
|
40
|
+
end
|
41
|
+
```
|
42
|
+
|
43
|
+
The `SAPOCI::Connect::Middleware::FollowRedirects` expands on the existing
|
44
|
+
`FaradayMiddleware::FollowRedirects` middleware in that it forwards cookies
|
45
|
+
and returns some errors like e.g. when a redirect is blank or
|
46
|
+
the maximum number of redirects is reached.
|
47
|
+
|
48
|
+
The `SAPOCI::Connect::Middleware::BackgroundSearch` automatically parses the
|
49
|
+
response body (just like the JSON and XML parser middlewares do), and returns
|
50
|
+
an `SAPOCI::Document` to look into. Notice that `{preserve_raw: true}` needs
|
51
|
+
to be passed as well if you want the original HTTP response body in
|
52
|
+
`response.env[:raw_body]`.
|
53
|
+
|
54
|
+
Review [Faraday](https://github.com/lostisland/faraday) for details on
|
55
|
+
connection initiation. We require Faraday version 1.0.1 or later.
|
28
56
|
|
29
57
|
## Testing
|
30
58
|
|
31
59
|
Here's how to test locally:
|
32
60
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
61
|
+
```sh
|
62
|
+
bundle install
|
63
|
+
# Start a second console
|
64
|
+
rake start_test_server
|
65
|
+
# Back in first console
|
66
|
+
bundle exec rake test
|
67
|
+
```
|
38
68
|
|
39
|
-
To test
|
69
|
+
To test remote OCI punchout shops, use the `REMOTE` environment variable:
|
40
70
|
|
41
|
-
|
71
|
+
```sh
|
72
|
+
REMOTE="http://remote-site.com/Login.aspx?u=demo&p=secret" rake
|
73
|
+
```
|
42
74
|
|
43
75
|
## Credits
|
44
76
|
|
45
77
|
Standing on the shoulder of giants, where giants include:
|
46
78
|
|
47
|
-
* Rick Olson for
|
79
|
+
* Rick Olson and all contributors for
|
80
|
+
[faraday](https://github.com/lostisland/faraday),
|
48
81
|
* 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)
|
82
|
+
[faraday_middleware](https://github.com/lostisland/faraday_middleware)
|
53
83
|
|
54
84
|
... and many other contributors. Thanks, guys. You rock!
|
55
85
|
|
86
|
+
## License
|
87
|
+
|
88
|
+
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.1
|
4
|
+
version: 0.5.1
|
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: 2021-05-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: faraday
|
@@ -16,148 +16,146 @@ 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.4.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
|
-
- - "<"
|
31
|
-
- !ruby/object:Gem::Version
|
32
|
-
version: '0.9'
|
26
|
+
version: 1.4.1
|
33
27
|
- !ruby/object:Gem::Dependency
|
34
|
-
name:
|
28
|
+
name: faraday_middleware
|
35
29
|
requirement: !ruby/object:Gem::Requirement
|
36
30
|
requirements:
|
37
31
|
- - "~>"
|
38
32
|
- !ruby/object:Gem::Version
|
39
|
-
version:
|
40
|
-
- - "<"
|
41
|
-
- !ruby/object:Gem::Version
|
42
|
-
version: '2'
|
33
|
+
version: 1.0.0
|
43
34
|
type: :runtime
|
44
35
|
prerelease: false
|
45
36
|
version_requirements: !ruby/object:Gem::Requirement
|
46
37
|
requirements:
|
47
38
|
- - "~>"
|
48
39
|
- !ruby/object:Gem::Version
|
49
|
-
version:
|
50
|
-
- - "<"
|
51
|
-
- !ruby/object:Gem::Version
|
52
|
-
version: '2'
|
40
|
+
version: 1.0.0
|
53
41
|
- !ruby/object:Gem::Dependency
|
54
|
-
name:
|
42
|
+
name: rack
|
55
43
|
requirement: !ruby/object:Gem::Requirement
|
56
44
|
requirements:
|
57
45
|
- - "~>"
|
58
46
|
- !ruby/object:Gem::Version
|
59
|
-
version: '0
|
47
|
+
version: '2.0'
|
60
48
|
- - ">="
|
61
49
|
- !ruby/object:Gem::Version
|
62
|
-
version: 0.
|
50
|
+
version: 2.0.9
|
63
51
|
type: :runtime
|
64
52
|
prerelease: false
|
65
53
|
version_requirements: !ruby/object:Gem::Requirement
|
66
54
|
requirements:
|
67
55
|
- - "~>"
|
68
56
|
- !ruby/object:Gem::Version
|
69
|
-
version: '0
|
57
|
+
version: '2.0'
|
70
58
|
- - ">="
|
71
59
|
- !ruby/object:Gem::Version
|
72
|
-
version: 0.
|
60
|
+
version: 2.0.9
|
73
61
|
- !ruby/object:Gem::Dependency
|
74
|
-
name:
|
62
|
+
name: sapoci
|
75
63
|
requirement: !ruby/object:Gem::Requirement
|
76
64
|
requirements:
|
77
65
|
- - "~>"
|
78
66
|
- !ruby/object:Gem::Version
|
79
|
-
version:
|
80
|
-
- - "<"
|
81
|
-
- !ruby/object:Gem::Version
|
82
|
-
version: '1.6'
|
67
|
+
version: 0.5.2
|
83
68
|
type: :runtime
|
84
69
|
prerelease: false
|
85
70
|
version_requirements: !ruby/object:Gem::Requirement
|
86
71
|
requirements:
|
87
72
|
- - "~>"
|
88
73
|
- !ruby/object:Gem::Version
|
89
|
-
version:
|
90
|
-
|
74
|
+
version: 0.5.2
|
75
|
+
- !ruby/object:Gem::Dependency
|
76
|
+
name: webrick
|
77
|
+
requirement: !ruby/object:Gem::Requirement
|
78
|
+
requirements:
|
79
|
+
- - "~>"
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: 1.6.1
|
82
|
+
type: :runtime
|
83
|
+
prerelease: false
|
84
|
+
version_requirements: !ruby/object:Gem::Requirement
|
85
|
+
requirements:
|
86
|
+
- - "~>"
|
91
87
|
- !ruby/object:Gem::Version
|
92
|
-
version:
|
88
|
+
version: 1.6.1
|
93
89
|
- !ruby/object:Gem::Dependency
|
94
90
|
name: bundler
|
95
91
|
requirement: !ruby/object:Gem::Requirement
|
96
92
|
requirements:
|
97
93
|
- - "~>"
|
98
94
|
- !ruby/object:Gem::Version
|
99
|
-
version:
|
95
|
+
version: 2.2.17
|
100
96
|
type: :development
|
101
97
|
prerelease: false
|
102
98
|
version_requirements: !ruby/object:Gem::Requirement
|
103
99
|
requirements:
|
104
100
|
- - "~>"
|
105
101
|
- !ruby/object:Gem::Version
|
106
|
-
version:
|
102
|
+
version: 2.2.17
|
107
103
|
- !ruby/object:Gem::Dependency
|
108
104
|
name: rdoc
|
109
105
|
requirement: !ruby/object:Gem::Requirement
|
110
106
|
requirements:
|
111
107
|
- - "~>"
|
112
108
|
- !ruby/object:Gem::Version
|
113
|
-
version:
|
114
|
-
- - ">="
|
115
|
-
- !ruby/object:Gem::Version
|
116
|
-
version: 3.12.1
|
109
|
+
version: 6.3.1
|
117
110
|
type: :development
|
118
111
|
prerelease: false
|
119
112
|
version_requirements: !ruby/object:Gem::Requirement
|
120
113
|
requirements:
|
121
114
|
- - "~>"
|
122
115
|
- !ruby/object:Gem::Version
|
123
|
-
version:
|
124
|
-
- - ">="
|
125
|
-
- !ruby/object:Gem::Version
|
126
|
-
version: 3.12.1
|
116
|
+
version: 6.3.1
|
127
117
|
- !ruby/object:Gem::Dependency
|
128
118
|
name: rake
|
129
119
|
requirement: !ruby/object:Gem::Requirement
|
130
120
|
requirements:
|
131
121
|
- - "~>"
|
132
122
|
- !ruby/object:Gem::Version
|
133
|
-
version:
|
123
|
+
version: 13.0.3
|
134
124
|
type: :development
|
135
125
|
prerelease: false
|
136
126
|
version_requirements: !ruby/object:Gem::Requirement
|
137
127
|
requirements:
|
138
128
|
- - "~>"
|
139
129
|
- !ruby/object:Gem::Version
|
140
|
-
version:
|
130
|
+
version: 13.0.3
|
141
131
|
- !ruby/object:Gem::Dependency
|
142
132
|
name: sinatra
|
143
133
|
requirement: !ruby/object:Gem::Requirement
|
144
134
|
requirements:
|
145
135
|
- - "~>"
|
146
136
|
- !ruby/object:Gem::Version
|
147
|
-
version: '1
|
148
|
-
- - "<"
|
149
|
-
- !ruby/object:Gem::Version
|
150
|
-
version: '1.4'
|
137
|
+
version: '2.1'
|
151
138
|
type: :development
|
152
139
|
prerelease: false
|
153
140
|
version_requirements: !ruby/object:Gem::Requirement
|
154
141
|
requirements:
|
155
142
|
- - "~>"
|
156
143
|
- !ruby/object:Gem::Version
|
157
|
-
version: '1
|
158
|
-
|
144
|
+
version: '2.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.1'
|
152
|
+
type: :development
|
153
|
+
prerelease: false
|
154
|
+
version_requirements: !ruby/object:Gem::Requirement
|
155
|
+
requirements:
|
156
|
+
- - "~>"
|
159
157
|
- !ruby/object:Gem::Version
|
160
|
-
version: '1
|
158
|
+
version: '2.1'
|
161
159
|
description: HTTP client library for working with SAP OCI compliant servers.
|
162
160
|
email:
|
163
161
|
- oliver.eilhard@gmail.com
|
@@ -180,7 +178,7 @@ homepage: http://github.com/meplato/sapoci-connect
|
|
180
178
|
licenses:
|
181
179
|
- MIT
|
182
180
|
metadata: {}
|
183
|
-
post_install_message:
|
181
|
+
post_install_message:
|
184
182
|
rdoc_options:
|
185
183
|
- "--charset=UTF-8"
|
186
184
|
require_paths:
|
@@ -189,16 +187,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
189
187
|
requirements:
|
190
188
|
- - ">="
|
191
189
|
- !ruby/object:Gem::Version
|
192
|
-
version: '
|
190
|
+
version: '2.6'
|
193
191
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
194
192
|
requirements:
|
195
193
|
- - ">="
|
196
194
|
- !ruby/object:Gem::Version
|
197
|
-
version:
|
195
|
+
version: '0'
|
198
196
|
requirements: []
|
199
|
-
|
200
|
-
|
201
|
-
signing_key:
|
197
|
+
rubygems_version: 3.2.3
|
198
|
+
signing_key:
|
202
199
|
specification_version: 4
|
203
200
|
summary: The library builds on the sapoci gem and adds working with remotes, parsing
|
204
201
|
its results etc.
|