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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: f484b4c9d147af9c98201434179751e799b3636b
4
- data.tar.gz: f789227e3f8c3a8a52d711333a8a58278eaadd9d
2
+ SHA256:
3
+ metadata.gz: 73d5cc2a601abaeac5f0c1714fc3d90c3d9aeed867fb27b5db55b7ad419253b6
4
+ data.tar.gz: 29681db3952f41460c3bc23c515b21df82662739ae6059961f59a86e09c4a081
5
5
  SHA512:
6
- metadata.gz: 6d0557026c4b687975a6ecef28afdd92b2352c89da6c8f0605833b901d0462bbcb4febb19e89633695d2b3df3105f4208369908565897234972322a89ea81bea
7
- data.tar.gz: 079fe2e1745fb51294f38c4c4c02f0ae919db68d7b6977aa7f5f10fc0712ad4fb8a431f751c60cf5a89feb4bf18b8a64a39abd675fc5fdd91175e0269c2924ca
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
- $ rake
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.1.13
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: 2014-03-14 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,142 +16,152 @@ 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: '1.2'
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: '1.2'
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: '0.1'
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: '0.1'
70
- - - ">="
71
- - !ruby/object:Gem::Version
72
- version: 0.1.9
68
+ version: 0.5.0
73
69
  - !ruby/object:Gem::Dependency
74
- name: nokogiri
70
+ name: webrick
75
71
  requirement: !ruby/object:Gem::Requirement
76
72
  requirements:
77
73
  - - "~>"
78
74
  - !ruby/object:Gem::Version
79
- version: '1.5'
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: '1.5'
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: '1.2'
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: '1.2'
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: '2.5'
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: '2.5'
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: '10.1'
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: '10.1'
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: '1.3'
142
- - - "<"
131
+ version: '2.0'
132
+ - - ">="
143
133
  - !ruby/object:Gem::Version
144
- version: '1.4'
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: '1.3'
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: '1.4'
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: '0'
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: 1.3.6
201
+ version: '0'
192
202
  requirements: []
193
- rubyforge_project:
194
- rubygems_version: 2.2.0
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.