lhc 12.0.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.
Files changed (195) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +37 -0
  3. data/.rubocop.localch.yml +325 -0
  4. data/.rubocop.yml +61 -0
  5. data/.ruby-version +1 -0
  6. data/Gemfile +13 -0
  7. data/Gemfile.activesupport4 +4 -0
  8. data/Gemfile.activesupport5 +4 -0
  9. data/Gemfile.activesupport6 +4 -0
  10. data/LICENSE +674 -0
  11. data/README.md +984 -0
  12. data/Rakefile +25 -0
  13. data/cider-ci.yml +6 -0
  14. data/cider-ci/bin/bundle +51 -0
  15. data/cider-ci/bin/ruby_install +8 -0
  16. data/cider-ci/bin/ruby_version +25 -0
  17. data/cider-ci/jobs/rspec-activesupport-4.yml +28 -0
  18. data/cider-ci/jobs/rspec-activesupport-5.yml +27 -0
  19. data/cider-ci/jobs/rspec-activesupport-6.yml +28 -0
  20. data/cider-ci/jobs/rubocop.yml +18 -0
  21. data/cider-ci/task_components/bundle.yml +22 -0
  22. data/cider-ci/task_components/rspec.yml +36 -0
  23. data/cider-ci/task_components/rubocop.yml +29 -0
  24. data/cider-ci/task_components/ruby.yml +15 -0
  25. data/friday.yml +3 -0
  26. data/lhc.gemspec +39 -0
  27. data/lib/core_ext/hash/deep_transform_values.rb +48 -0
  28. data/lib/lhc.rb +136 -0
  29. data/lib/lhc/concerns/lhc/basic_methods_concern.rb +42 -0
  30. data/lib/lhc/concerns/lhc/configuration_concern.rb +20 -0
  31. data/lib/lhc/concerns/lhc/fix_invalid_encoding_concern.rb +42 -0
  32. data/lib/lhc/concerns/lhc/formats_concern.rb +25 -0
  33. data/lib/lhc/concerns/lhc/request/user_agent_concern.rb +25 -0
  34. data/lib/lhc/config.rb +47 -0
  35. data/lib/lhc/endpoint.rb +119 -0
  36. data/lib/lhc/error.rb +80 -0
  37. data/lib/lhc/errors/client_error.rb +73 -0
  38. data/lib/lhc/errors/parser_error.rb +4 -0
  39. data/lib/lhc/errors/server_error.rb +28 -0
  40. data/lib/lhc/errors/timeout.rb +4 -0
  41. data/lib/lhc/errors/unknown_error.rb +4 -0
  42. data/lib/lhc/format.rb +18 -0
  43. data/lib/lhc/formats.rb +8 -0
  44. data/lib/lhc/formats/form.rb +45 -0
  45. data/lib/lhc/formats/json.rb +55 -0
  46. data/lib/lhc/formats/multipart.rb +45 -0
  47. data/lib/lhc/formats/plain.rb +42 -0
  48. data/lib/lhc/interceptor.rb +32 -0
  49. data/lib/lhc/interceptors.rb +26 -0
  50. data/lib/lhc/interceptors/auth.rb +98 -0
  51. data/lib/lhc/interceptors/caching.rb +127 -0
  52. data/lib/lhc/interceptors/default_timeout.rb +16 -0
  53. data/lib/lhc/interceptors/logging.rb +37 -0
  54. data/lib/lhc/interceptors/monitoring.rb +63 -0
  55. data/lib/lhc/interceptors/prometheus.rb +51 -0
  56. data/lib/lhc/interceptors/retry.rb +41 -0
  57. data/lib/lhc/interceptors/rollbar.rb +36 -0
  58. data/lib/lhc/interceptors/throttle.rb +81 -0
  59. data/lib/lhc/interceptors/zipkin.rb +110 -0
  60. data/lib/lhc/railtie.rb +10 -0
  61. data/lib/lhc/request.rb +157 -0
  62. data/lib/lhc/response.rb +60 -0
  63. data/lib/lhc/response/data.rb +28 -0
  64. data/lib/lhc/response/data/base.rb +22 -0
  65. data/lib/lhc/response/data/collection.rb +16 -0
  66. data/lib/lhc/response/data/item.rb +29 -0
  67. data/lib/lhc/rspec.rb +12 -0
  68. data/lib/lhc/test/cache_helper.rb +3 -0
  69. data/lib/lhc/version.rb +5 -0
  70. data/script/ci/build.sh +19 -0
  71. data/spec/basic_methods/delete_spec.rb +34 -0
  72. data/spec/basic_methods/get_spec.rb +49 -0
  73. data/spec/basic_methods/post_spec.rb +42 -0
  74. data/spec/basic_methods/put_spec.rb +48 -0
  75. data/spec/basic_methods/request_spec.rb +19 -0
  76. data/spec/basic_methods/request_without_rails_spec.rb +29 -0
  77. data/spec/config/endpoints_spec.rb +63 -0
  78. data/spec/config/placeholders_spec.rb +32 -0
  79. data/spec/core_ext/hash/deep_transform_values_spec.rb +24 -0
  80. data/spec/dummy/README.rdoc +28 -0
  81. data/spec/dummy/Rakefile +8 -0
  82. data/spec/dummy/app/assets/config/manifest.js +3 -0
  83. data/spec/dummy/app/assets/images/.keep +0 -0
  84. data/spec/dummy/app/assets/javascripts/application.js +13 -0
  85. data/spec/dummy/app/assets/stylesheets/application.css +15 -0
  86. data/spec/dummy/app/controllers/application_controller.rb +7 -0
  87. data/spec/dummy/app/controllers/concerns/.keep +0 -0
  88. data/spec/dummy/app/helpers/application_helper.rb +4 -0
  89. data/spec/dummy/app/mailers/.keep +0 -0
  90. data/spec/dummy/app/models/.keep +0 -0
  91. data/spec/dummy/app/models/concerns/.keep +0 -0
  92. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  93. data/spec/dummy/bin/bundle +5 -0
  94. data/spec/dummy/bin/rails +6 -0
  95. data/spec/dummy/bin/rake +6 -0
  96. data/spec/dummy/config.ru +6 -0
  97. data/spec/dummy/config/application.rb +16 -0
  98. data/spec/dummy/config/boot.rb +7 -0
  99. data/spec/dummy/config/environment.rb +7 -0
  100. data/spec/dummy/config/environments/development.rb +36 -0
  101. data/spec/dummy/config/environments/production.rb +77 -0
  102. data/spec/dummy/config/environments/test.rb +41 -0
  103. data/spec/dummy/config/initializers/assets.rb +10 -0
  104. data/spec/dummy/config/initializers/backtrace_silencers.rb +9 -0
  105. data/spec/dummy/config/initializers/cookies_serializer.rb +5 -0
  106. data/spec/dummy/config/initializers/filter_parameter_logging.rb +6 -0
  107. data/spec/dummy/config/initializers/inflections.rb +18 -0
  108. data/spec/dummy/config/initializers/mime_types.rb +6 -0
  109. data/spec/dummy/config/initializers/session_store.rb +5 -0
  110. data/spec/dummy/config/initializers/wrap_parameters.rb +11 -0
  111. data/spec/dummy/config/locales/en.yml +23 -0
  112. data/spec/dummy/config/routes.rb +58 -0
  113. data/spec/dummy/config/secrets.yml +22 -0
  114. data/spec/dummy/lib/assets/.keep +0 -0
  115. data/spec/dummy/log/.keep +0 -0
  116. data/spec/dummy/public/404.html +67 -0
  117. data/spec/dummy/public/422.html +67 -0
  118. data/spec/dummy/public/500.html +66 -0
  119. data/spec/dummy/public/favicon.ico +0 -0
  120. data/spec/endpoint/compile_spec.rb +35 -0
  121. data/spec/endpoint/match_spec.rb +41 -0
  122. data/spec/endpoint/placeholders_spec.rb +30 -0
  123. data/spec/endpoint/remove_interpolated_params_spec.rb +17 -0
  124. data/spec/endpoint/values_as_params_spec.rb +31 -0
  125. data/spec/error/dup_spec.rb +12 -0
  126. data/spec/error/find_spec.rb +57 -0
  127. data/spec/error/response_spec.rb +17 -0
  128. data/spec/error/timeout_spec.rb +14 -0
  129. data/spec/error/to_s_spec.rb +80 -0
  130. data/spec/formats/form_spec.rb +27 -0
  131. data/spec/formats/json_spec.rb +66 -0
  132. data/spec/formats/multipart_spec.rb +26 -0
  133. data/spec/formats/plain_spec.rb +29 -0
  134. data/spec/interceptors/after_request_spec.rb +20 -0
  135. data/spec/interceptors/after_response_spec.rb +39 -0
  136. data/spec/interceptors/auth/basic_auth_spec.rb +17 -0
  137. data/spec/interceptors/auth/bearer_spec.rb +19 -0
  138. data/spec/interceptors/auth/reauthentication_configuration_spec.rb +61 -0
  139. data/spec/interceptors/auth/reauthentication_spec.rb +44 -0
  140. data/spec/interceptors/before_request_spec.rb +21 -0
  141. data/spec/interceptors/before_response_spec.rb +20 -0
  142. data/spec/interceptors/caching/hydra_spec.rb +26 -0
  143. data/spec/interceptors/caching/main_spec.rb +73 -0
  144. data/spec/interceptors/caching/methods_spec.rb +42 -0
  145. data/spec/interceptors/caching/options_spec.rb +89 -0
  146. data/spec/interceptors/caching/parameters_spec.rb +24 -0
  147. data/spec/interceptors/caching/response_status_spec.rb +29 -0
  148. data/spec/interceptors/caching/to_cache_spec.rb +16 -0
  149. data/spec/interceptors/default_interceptors_spec.rb +15 -0
  150. data/spec/interceptors/default_timeout/main_spec.rb +34 -0
  151. data/spec/interceptors/define_spec.rb +29 -0
  152. data/spec/interceptors/dup_spec.rb +19 -0
  153. data/spec/interceptors/logging/main_spec.rb +37 -0
  154. data/spec/interceptors/monitoring/main_spec.rb +97 -0
  155. data/spec/interceptors/prometheus_spec.rb +54 -0
  156. data/spec/interceptors/response_competition_spec.rb +41 -0
  157. data/spec/interceptors/retry/main_spec.rb +73 -0
  158. data/spec/interceptors/return_response_spec.rb +38 -0
  159. data/spec/interceptors/rollbar/invalid_encoding_spec.rb +43 -0
  160. data/spec/interceptors/rollbar/main_spec.rb +57 -0
  161. data/spec/interceptors/throttle/main_spec.rb +106 -0
  162. data/spec/interceptors/throttle/reset_track_spec.rb +53 -0
  163. data/spec/interceptors/zipkin/distributed_tracing_spec.rb +135 -0
  164. data/spec/rails_helper.rb +6 -0
  165. data/spec/request/body_spec.rb +39 -0
  166. data/spec/request/encoding_spec.rb +37 -0
  167. data/spec/request/error_handling_spec.rb +88 -0
  168. data/spec/request/headers_spec.rb +12 -0
  169. data/spec/request/ignore_errors_spec.rb +73 -0
  170. data/spec/request/option_dup_spec.rb +13 -0
  171. data/spec/request/parallel_requests_spec.rb +59 -0
  172. data/spec/request/params_encoding_spec.rb +26 -0
  173. data/spec/request/request_without_rails_spec.rb +15 -0
  174. data/spec/request/url_patterns_spec.rb +54 -0
  175. data/spec/request/user_agent_spec.rb +26 -0
  176. data/spec/request/user_agent_without_rails_spec.rb +27 -0
  177. data/spec/response/body_spec.rb +16 -0
  178. data/spec/response/code_spec.rb +16 -0
  179. data/spec/response/data_accessor_spec.rb +29 -0
  180. data/spec/response/data_spec.rb +61 -0
  181. data/spec/response/effective_url_spec.rb +16 -0
  182. data/spec/response/headers_spec.rb +18 -0
  183. data/spec/response/options_spec.rb +18 -0
  184. data/spec/response/success_spec.rb +13 -0
  185. data/spec/response/time_spec.rb +21 -0
  186. data/spec/spec_helper.rb +8 -0
  187. data/spec/support/fixtures/json/feedback.json +11 -0
  188. data/spec/support/fixtures/json/feedbacks.json +164 -0
  189. data/spec/support/fixtures/json/localina_content_ad.json +23 -0
  190. data/spec/support/load_json.rb +5 -0
  191. data/spec/support/reset_config.rb +7 -0
  192. data/spec/support/zipkin_mock.rb +113 -0
  193. data/spec/timeouts/no_signal_spec.rb +13 -0
  194. data/spec/timeouts/timings_spec.rb +55 -0
  195. metadata +534 -0
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_support'
4
+
5
+ module LHC
6
+ module BasicMethodsConcern
7
+ extend ActiveSupport::Concern
8
+
9
+ module ClassMethods
10
+ def request(options)
11
+ if options.is_a? Array
12
+ parallel_requests(options)
13
+ else
14
+ LHC::Request.new(options).response
15
+ end
16
+ end
17
+
18
+ [:get, :post, :put, :delete].each do |http_method|
19
+ define_method(http_method) do |url, options = {}|
20
+ request(options.merge(
21
+ url: url,
22
+ method: http_method
23
+ ))
24
+ end
25
+ end
26
+
27
+ private
28
+
29
+ def parallel_requests(options)
30
+ hydra = Typhoeus::Hydra.new # do not use memoization !
31
+ requests = []
32
+ options.each do |option|
33
+ request = LHC::Request.new(option, false)
34
+ requests << request
35
+ hydra.queue request.raw unless request.response.present?
36
+ end
37
+ hydra.run
38
+ requests.map(&:response)
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_support'
4
+
5
+ module LHC
6
+ module ConfigurationConcern
7
+ extend ActiveSupport::Concern
8
+
9
+ module ClassMethods
10
+ def config
11
+ LHC::Config.instance
12
+ end
13
+
14
+ def configure
15
+ LHC::Config.instance.reset
16
+ yield config
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_support'
4
+
5
+ module LHC
6
+ module FixInvalidEncodingConcern
7
+ extend ActiveSupport::Concern
8
+
9
+ module ClassMethods
10
+ # fix strings that contain non-UTF8 encoding in a forceful way
11
+ # should none of the fix-attempts be successful,
12
+ # an empty string is returned instead
13
+ def fix_invalid_encoding(string)
14
+ return string unless string.is_a?(String)
15
+ result = string.dup
16
+
17
+ # we assume it's ISO-8859-1 first
18
+ if !result.valid_encoding? || !utf8?(result)
19
+ result.encode!('UTF-8', 'ISO-8859-1', invalid: :replace, undef: :replace, replace: '')
20
+ end
21
+
22
+ # if it's still an issue, try with BINARY
23
+ if !result.valid_encoding? || !utf8?(result)
24
+ result.encode!('UTF-8', 'BINARY', invalid: :replace, undef: :replace, replace: '')
25
+ end
26
+
27
+ # if its STILL an issue, return an empty string :(
28
+ if !result.valid_encoding? || !utf8?(result)
29
+ result = ""
30
+ end
31
+
32
+ result
33
+ end
34
+
35
+ private
36
+
37
+ def utf8?(string)
38
+ string.encoding == Encoding::UTF_8
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LHC
4
+ module FormatsConcern
5
+ extend ActiveSupport::Concern
6
+
7
+ module ClassMethods
8
+ def form
9
+ LHC::Formats::Form
10
+ end
11
+
12
+ def json
13
+ LHC::Formats::JSON
14
+ end
15
+
16
+ def multipart
17
+ LHC::Formats::Multipart
18
+ end
19
+
20
+ def plain
21
+ LHC::Formats::Plain
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_support'
4
+ require 'lhc/version'
5
+
6
+ module LHC
7
+ class Request
8
+ module UserAgentConcern
9
+ extend ActiveSupport::Concern
10
+
11
+ included do
12
+ Typhoeus::Config.user_agent = begin
13
+ version = LHC::VERSION
14
+ application = nil
15
+ if defined?(Rails)
16
+ app_class = Rails.application.class
17
+ application = (ActiveSupport.gem_version >= Gem::Version.new('6.0.0')) ? app_class.module_parent_name : app_class.parent_name
18
+ end
19
+
20
+ "LHC (#{[version, application].compact.join('; ')}) [https://github.com/local-ch/lhc]"
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'singleton'
4
+
5
+ class LHC::Config
6
+ include Singleton
7
+
8
+ def initialize
9
+ @endpoints = {}
10
+ @placeholders = {}
11
+ end
12
+
13
+ def endpoint(name, url, options = {})
14
+ name = name.to_sym
15
+ raise 'Endpoint already exists for that name' if @endpoints[name]
16
+ @endpoints[name] = LHC::Endpoint.new(url, options)
17
+ end
18
+
19
+ def endpoints
20
+ @endpoints.dup
21
+ end
22
+
23
+ def placeholder(name, value)
24
+ name = name.to_sym
25
+ raise 'Placeholder already exists for that name' if @placeholders[name]
26
+ @placeholders[name] = value
27
+ end
28
+
29
+ def placeholders
30
+ @placeholders.dup
31
+ end
32
+
33
+ def interceptors
34
+ (@interceptors || []).dup
35
+ end
36
+
37
+ def interceptors=(interceptors)
38
+ raise 'Default interceptors already set and can only be set once' if @interceptors
39
+ @interceptors = interceptors
40
+ end
41
+
42
+ def reset
43
+ @endpoints = {}
44
+ @placeholders = {}
45
+ @interceptors = nil
46
+ end
47
+ end
@@ -0,0 +1,119 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'addressable/template'
4
+
5
+ # An endpoint is an url that leads to a backend resource.
6
+ # The url can also be an url-template (https://tools.ietf.org/html/rfc6570).
7
+ class LHC::Endpoint
8
+ attr_accessor :url
9
+ attr_writer :options
10
+
11
+ def initialize(url, options = nil)
12
+ self.url = url
13
+ self.options = options
14
+ end
15
+
16
+ def uri
17
+ @uri ||= Addressable::Template.new(url)
18
+ end
19
+
20
+ def compile(params)
21
+ context = LHC.config.placeholders.deep_dup
22
+ context.merge!(params) if params.is_a?(Hash)
23
+ expanded = uri.partial_expand(context)
24
+
25
+ if expanded.variables.empty?
26
+ expanded.pattern
27
+ else
28
+ raise("Compilation incomplete. Unable to find value for #{expanded.variables.join(', ')}.")
29
+ end
30
+ end
31
+
32
+ # Endpoint options are immutable
33
+ def options
34
+ @options.deep_dup
35
+ end
36
+
37
+ # Removes keys from provided params hash
38
+ # when they are used for interpolation.
39
+ def remove_interpolated_params!(params)
40
+ params ||= {}
41
+ removed = params.slice(*placeholders)
42
+ params.except!(*placeholders)
43
+
44
+ removed
45
+ end
46
+
47
+ # Returns all placeholders found in the url-template.
48
+ # They are alphabetically sorted.
49
+ def placeholders
50
+ uri.variables.sort.map(&:to_sym)
51
+ end
52
+
53
+ # Compares a concrete url with a template
54
+ # Returns true if concrete url is covered by the template
55
+ # Example: {+datastore}/contracts/{id} == http://local.ch/contracts/1
56
+ def match?(url)
57
+ return true if url == uri.pattern
58
+ match_data = match_data(url)
59
+ return false if match_data.nil?
60
+
61
+ first = match_data.values.first
62
+ last = match_data.values.last
63
+ url_format = File.extname(url)
64
+
65
+ # eliminate false positives in form:
66
+ # http://host/feedbacks matches {+service}/{entry_id}/feedbacks (service: http:/, entry_id: host)
67
+ first&.match(%{https?:/$}).nil? &&
68
+ # eliminates false positives in form:
69
+ # http://host/entries/123.json matches {+service}/entries/{id} (service: http://host, id: 123.json)
70
+ (url_format.blank? || !last&.ends_with?(url_format))
71
+ end
72
+
73
+ # Extracts the values from url and
74
+ # creates params according to template
75
+ def values_as_params(url)
76
+ match_data = match_data(url)
77
+ return if match_data.nil?
78
+ Hash[match_data.variables.map(&:to_sym).zip(match_data.values)]
79
+ end
80
+
81
+ # Checks if the name has a match in the current context
82
+ def find_value(name, mapping)
83
+ context = LHC.config.placeholders.deep_dup
84
+ context.merge!(mapping)
85
+
86
+ context[name]
87
+ end
88
+
89
+ # Compares a concrete url with a template
90
+ # Returns true if concrete url is covered by the template
91
+ # Example: {+datastore}/contracts/{id} == http://local.ch/contracts/1
92
+ def self.match?(url, template)
93
+ new(template).match?(url)
94
+ end
95
+
96
+ # Returns all placeholders found in the url-template.
97
+ # They are alphabetically sorted.
98
+ def self.placeholders(template)
99
+ new(template).placeholders
100
+ end
101
+
102
+ # Extracts the values from url and
103
+ # creates params according to template
104
+ def self.values_as_params(template, url)
105
+ raise("#{url} does not match the template: #{template}") if !match?(url, template)
106
+ new(template).values_as_params(url)
107
+ end
108
+
109
+ private
110
+
111
+ def match_data(url)
112
+ parsed = URI.parse(url)
113
+ parsed.query = parsed.fragment = nil
114
+
115
+ uri.match(parsed)
116
+ rescue URI::InvalidURIError
117
+ nil
118
+ end
119
+ end
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ class LHC::Error < StandardError
4
+ include LHC::FixInvalidEncodingConcern
5
+
6
+ attr_accessor :response, :_message
7
+
8
+ def self.map
9
+ {
10
+ 400 => LHC::BadRequest,
11
+ 401 => LHC::Unauthorized,
12
+ 402 => LHC::PaymentRequired,
13
+ 403 => LHC::Forbidden,
14
+ 404 => LHC::NotFound,
15
+ 405 => LHC::MethodNotAllowed,
16
+ 406 => LHC::NotAcceptable,
17
+ 407 => LHC::ProxyAuthenticationRequired,
18
+ 408 => LHC::RequestTimeout,
19
+ 409 => LHC::Conflict,
20
+ 410 => LHC::Gone,
21
+ 411 => LHC::LengthRequired,
22
+ 412 => LHC::PreconditionFailed,
23
+ 413 => LHC::RequestEntityTooLarge,
24
+ 414 => LHC::RequestUriToLong,
25
+ 415 => LHC::UnsupportedMediaType,
26
+ 416 => LHC::RequestedRangeNotSatisfiable,
27
+ 417 => LHC::ExpectationFailed,
28
+ 422 => LHC::UnprocessableEntity,
29
+ 423 => LHC::Locked,
30
+ 424 => LHC::FailedDependency,
31
+ 426 => LHC::UpgradeRequired,
32
+
33
+ 500 => LHC::InternalServerError,
34
+ 501 => LHC::NotImplemented,
35
+ 502 => LHC::BadGateway,
36
+ 503 => LHC::ServiceUnavailable,
37
+ 504 => LHC::GatewayTimeout,
38
+ 505 => LHC::HttpVersionNotSupported,
39
+ 507 => LHC::InsufficientStorage,
40
+ 510 => LHC::NotExtended
41
+ }
42
+ end
43
+
44
+ def self.find(response)
45
+ return LHC::Timeout if response.timeout?
46
+ status_code = response.code.to_s[0..2].to_i
47
+ error = map[status_code]
48
+ error ||= LHC::UnknownError
49
+ error
50
+ end
51
+
52
+ def self.dup
53
+ self
54
+ end
55
+
56
+ def initialize(message, response)
57
+ super(message)
58
+ self._message = message
59
+ self.response = response
60
+ end
61
+
62
+ def self.to_a
63
+ [self]
64
+ end
65
+
66
+ def to_s
67
+ return response if response.is_a?(String)
68
+ request = response.request
69
+ debug = []
70
+ debug << [request.method, request.url].map { |str| self.class.fix_invalid_encoding(str) }.join(' ')
71
+ debug << "Options: #{request.options}"
72
+ debug << "Headers: #{request.headers}"
73
+ debug << "Response Code: #{response.code} (#{response.options[:return_code]})"
74
+ debug << "Response Options: #{response.options}"
75
+ debug << response.body
76
+ debug << _message
77
+
78
+ debug.map { |str| self.class.fix_invalid_encoding(str) }.join("\n")
79
+ end
80
+ end
@@ -0,0 +1,73 @@
1
+ # frozen_string_literal: true
2
+
3
+ class LHC::ClientError < LHC::Error
4
+ end
5
+
6
+ class LHC::BadRequest < LHC::ClientError
7
+ end
8
+
9
+ class LHC::Unauthorized < LHC::ClientError
10
+ end
11
+
12
+ class LHC::PaymentRequired < LHC::ClientError
13
+ end
14
+
15
+ class LHC::Forbidden < LHC::ClientError
16
+ end
17
+
18
+ class LHC::Forbidden < LHC::ClientError
19
+ end
20
+
21
+ class LHC::NotFound < LHC::ClientError
22
+ end
23
+
24
+ class LHC::MethodNotAllowed < LHC::ClientError
25
+ end
26
+
27
+ class LHC::NotAcceptable < LHC::ClientError
28
+ end
29
+
30
+ class LHC::ProxyAuthenticationRequired < LHC::ClientError
31
+ end
32
+
33
+ class LHC::RequestTimeout < LHC::ClientError
34
+ end
35
+
36
+ class LHC::Conflict < LHC::ClientError
37
+ end
38
+
39
+ class LHC::Gone < LHC::ClientError
40
+ end
41
+
42
+ class LHC::LengthRequired < LHC::ClientError
43
+ end
44
+
45
+ class LHC::PreconditionFailed < LHC::ClientError
46
+ end
47
+
48
+ class LHC::RequestEntityTooLarge < LHC::ClientError
49
+ end
50
+
51
+ class LHC::RequestUriToLong < LHC::ClientError
52
+ end
53
+
54
+ class LHC::UnsupportedMediaType < LHC::ClientError
55
+ end
56
+
57
+ class LHC::RequestedRangeNotSatisfiable < LHC::ClientError
58
+ end
59
+
60
+ class LHC::ExpectationFailed < LHC::ClientError
61
+ end
62
+
63
+ class LHC::UnprocessableEntity < LHC::ClientError
64
+ end
65
+
66
+ class LHC::Locked < LHC::ClientError
67
+ end
68
+
69
+ class LHC::FailedDependency < LHC::ClientError
70
+ end
71
+
72
+ class LHC::UpgradeRequired < LHC::ClientError
73
+ end