sapoci-connect 0.4.1 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1dcb0c9390414437dd0cff6decde1d7678d53feadc6261fba7a32818a8398be3
4
- data.tar.gz: 1db9b712ef050897b2d007305cabbb5463b97501dbff2db69e091fdfa368d947
3
+ metadata.gz: 73d5cc2a601abaeac5f0c1714fc3d90c3d9aeed867fb27b5db55b7ad419253b6
4
+ data.tar.gz: 29681db3952f41460c3bc23c515b21df82662739ae6059961f59a86e09c4a081
5
5
  SHA512:
6
- metadata.gz: 2a2101cc2afebeac2d42a533b2df0436b22381c05dfcbc7ac007e02d6bce2276165dbd4a877c15e90a0f21ee8e193004f8bf05847f311879838e15d02707e1fd
7
- data.tar.gz: 25e0d9317d33f560ed0cf73b91197afef8434f23a3e39defcbd3e2a88142e6df61de0241d5e8e7b1e42af0011c4d715857a004b8c2f3d35045d8ae4a506096d5
6
+ metadata.gz: 448e88f525d88480eee90519947541ab7ff84933bc0b951681a8a5635f42510a19fb969de266420043c6b952c0f810738fa731441c9a75da8c0fb2a503867b6c
7
+ data.tar.gz: 84ce2cbc421695b64a9ddf457f673e8581bbe72933d81e959e989ecd88726e822728c7b00e0e3e85ed2c40f1d68db1072e2f3ad05dd3fa10ba9090ba762e1f2d
@@ -1,3 +1,10 @@
1
+ *2020-07-28 (0.5.0)*
2
+
3
+ * Require latest versions of all dependencies, including
4
+ Faraday 1.0.1 or later.
5
+ * Require Ruby 2.4 or later.
6
+
7
+
1
8
  *2014-03-14 (0.1.13)*
2
9
 
3
10
  * Fix versioning issues
data/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2007-2012 Oliver Eilhard
1
+ Copyright (c) 2007-2020 Oliver Eilhard
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
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
- conn = Faraday.new("http://onlineshop.com/path", :params => {"token" => "123"}) do |builder|
13
- builder.response :follow_redirects, :cookies => :all, :limit => 5
14
- builder.response :background_search
15
- builder.adapter :net_http
16
- end
17
-
18
- conn.options[:timeout] = 5
19
- conn.options[:open_timeout] = 10
20
-
21
- resp = SAPOCI::Connect.search(:get, conn, "toner", "http://return.to/me")
22
- puts resp.status # => 200
23
- puts resp.body # => <SAPOCI::Document>
24
- puts resp.env[:raw_body] # => "<html>...</html>"
25
-
26
- Review [Faraday](https://github.com/technoweenie/faraday) for details on
27
- connection initiation. We require Faraday version 0.8.0 or later.
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
- $ bundle update
34
- $ # Start a second console
35
- $ ruby test/live_server.rb
36
- $ # Back in first console
37
- $ bundle exec rake test
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 external servers, use the REMOTE environment variable:
67
+ To test remote OCI punchout shops, use the `REMOTE` environment variable:
40
68
 
41
- $ REMOTE="http://remote-site.com/Login.aspx?u=demo&p=secret" rake
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 [faraday](https://github.com/technoweenie/faraday),
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/pengwynn/faraday_middleware),
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).
@@ -55,22 +55,22 @@ begin
55
55
  uri.query = nil
56
56
 
57
57
  # Setup
58
- conn = Faraday.new(uri.to_s, :ssl => {:verify => true}) do |builder|
59
- builder.response :follow_redirects, :cookies => :all, :limit => 10
60
- builder.response :background_search
61
- builder.use Faraday::Response::Logger if options.debug
62
- builder.adapter Faraday.default_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({:uri => options.proxy_uri}) if options.proxy_uri
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://return.to/me", params)
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.env[:sapoci]
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.body.to_s if options.debug
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.body.to_s if options.debug
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.body.to_s if options.debug
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.body.to_s if options.debug
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
@@ -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", :params => {"optional" => "value"}) do |builder|
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 # => 200
30
- # puts resp.body # => <SAPOCI::Document>
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.response :background_search
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 params
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
- class BackgroundSearch < Faraday::Response::Middleware
5
- def on_complete(env)
6
- case env[:status]
7
- when 200
8
- env[:sapoci] = SAPOCI::Document.from_html(env[:body])
9
- else
10
- end
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::Error::ClientError
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::Error::ClientError
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 307 redirects for GET, PATCH, POST,
29
- # PUT, and DELETE requests.
29
+
30
+ # Public: Follow HTTP 301, 302, 303, 307, and 308 redirects.
30
31
  #
31
- # This middleware does not follow the HTTP specification for HTTP 302, by
32
- # default, in that it follows the improper implementation used by most major
33
- # web browsers which forces the redirected request to become a GET request
34
- # regardless of the original request method.
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
- # For HTTP 301, 302, and 303, the original request is transformed into a
37
- # GET request to the response Location, by default. However, with standards
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
- # For HTTP 307, the original request is replayed to the response Location,
43
- # including original HTTP request method (GET, POST, PUT, DELETE, PATCH),
44
- # original headers, and original body.
40
+ # Example:
45
41
  #
46
- # This middleware currently only works with synchronous requests; in other
47
- # words, it doesn't support parallelism.
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 [:get, :post, :put, :patch, :delete]
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 [:status, :response, :response_headers]
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
- # limit - A Numeric redirect limit (default: 3)
63
- # standards_compliant - A Boolean indicating whether to respect
64
- # the HTTP spec when following 302
65
- # (default: false)
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
- @options[:cookies] = :all
71
- @cookies = []
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 transform_into_get?(response)
84
- !@replay_request_codes.include? response.status
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 |env|
92
- if follow_redirect?(env, response)
93
- raise RedirectLimitReached, response if follows.zero?
94
- env = update_env(env, request_body, response)
95
- response = perform_with_redirection(env, follows - 1)
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
- location = response['location']
103
- raise RedirectWithoutLocation, response if location.to_s.size == 0
104
- env[:url] += location
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
- if transform_into_get?(response)
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
- ENV_TO_CLEAR.each {|key| env.delete key }
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? env[:method] and
124
- REDIRECT_CODES.include? response.status
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
- # TODO only send back cookies where path is nil or
136
- # path matches according to env[:url]
137
- result << cookie.name + "=" + cookie.value
138
- end.uniq.join(";")
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
- def standards_compliant?
145
- @options.fetch(:standards_compliant, false)
146
- end
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.1
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: 2020-03-02 00:00:00.000000000 Z
11
+ date: 2020-07-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -16,96 +16,112 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '0.8'
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: '0.8'
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: '0.9'
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: '2.2'
40
- - - ">="
41
- - !ruby/object:Gem::Version
42
- version: 2.2.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: '2.2'
50
- - - ">="
51
- - !ruby/object:Gem::Version
52
- version: 2.2.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: 0.4.3
61
+ version: 0.5.0
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 0.5.0
69
+ - !ruby/object:Gem::Dependency
70
+ name: webrick
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 1.6.0
60
76
  type: :runtime
61
77
  prerelease: false
62
78
  version_requirements: !ruby/object:Gem::Requirement
63
79
  requirements:
64
80
  - - "~>"
65
81
  - !ruby/object:Gem::Version
66
- version: 0.4.3
82
+ version: 1.6.0
67
83
  - !ruby/object:Gem::Dependency
68
84
  name: bundler
69
85
  requirement: !ruby/object:Gem::Requirement
70
86
  requirements:
71
87
  - - "~>"
72
88
  - !ruby/object:Gem::Version
73
- version: 1.17.3
89
+ version: 2.1.4
74
90
  type: :development
75
91
  prerelease: false
76
92
  version_requirements: !ruby/object:Gem::Requirement
77
93
  requirements:
78
94
  - - "~>"
79
95
  - !ruby/object:Gem::Version
80
- version: 1.17.3
96
+ version: 2.1.4
81
97
  - !ruby/object:Gem::Dependency
82
98
  name: rdoc
83
99
  requirement: !ruby/object:Gem::Requirement
84
100
  requirements:
85
101
  - - "~>"
86
102
  - !ruby/object:Gem::Version
87
- version: 3.12.1
103
+ version: 6.2.1
88
104
  type: :development
89
105
  prerelease: false
90
106
  version_requirements: !ruby/object:Gem::Requirement
91
107
  requirements:
92
108
  - - "~>"
93
109
  - !ruby/object:Gem::Version
94
- version: 3.12.1
110
+ version: 6.2.1
95
111
  - !ruby/object:Gem::Dependency
96
112
  name: rake
97
113
  requirement: !ruby/object:Gem::Requirement
98
114
  requirements:
99
115
  - - "~>"
100
116
  - !ruby/object:Gem::Version
101
- version: 12.3.3
117
+ version: 13.0.1
102
118
  type: :development
103
119
  prerelease: false
104
120
  version_requirements: !ruby/object:Gem::Requirement
105
121
  requirements:
106
122
  - - "~>"
107
123
  - !ruby/object:Gem::Version
108
- version: 12.3.3
124
+ version: 13.0.1
109
125
  - !ruby/object:Gem::Dependency
110
126
  name: sinatra
111
127
  requirement: !ruby/object:Gem::Requirement
@@ -126,6 +142,26 @@ dependencies:
126
142
  - - ">="
127
143
  - !ruby/object:Gem::Version
128
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
+ - !ruby/object:Gem::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
129
165
  description: HTTP client library for working with SAP OCI compliant servers.
130
166
  email:
131
167
  - oliver.eilhard@gmail.com
@@ -148,24 +184,24 @@ homepage: http://github.com/meplato/sapoci-connect
148
184
  licenses:
149
185
  - MIT
150
186
  metadata: {}
151
- post_install_message:
187
+ post_install_message:
152
188
  rdoc_options:
153
189
  - "--charset=UTF-8"
154
190
  require_paths:
155
191
  - lib
156
192
  required_ruby_version: !ruby/object:Gem::Requirement
157
193
  requirements:
158
- - - ">="
194
+ - - "~>"
159
195
  - !ruby/object:Gem::Version
160
- version: '0'
196
+ version: '2.4'
161
197
  required_rubygems_version: !ruby/object:Gem::Requirement
162
198
  requirements:
163
199
  - - ">="
164
200
  - !ruby/object:Gem::Version
165
- version: 1.3.6
201
+ version: '0'
166
202
  requirements: []
167
203
  rubygems_version: 3.0.3
168
- signing_key:
204
+ signing_key:
169
205
  specification_version: 4
170
206
  summary: The library builds on the sapoci gem and adds working with remotes, parsing
171
207
  its results etc.