twingly-http 0.1.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 +7 -0
- data/LICENSE +20 -0
- data/README.md +23 -0
- data/lib/faraday/logfmt_logger.rb +8 -0
- data/lib/faraday/logfmt_logger/LICENSE.md +20 -0
- data/lib/faraday/logfmt_logger/middleware.rb +130 -0
- data/lib/faraday/url_size_limit.rb +8 -0
- data/lib/faraday/url_size_limit/middleware.rb +31 -0
- data/lib/twingly/heroku.rb +34 -0
- data/lib/twingly/http.rb +200 -0
- data/lib/twingly/string_utilities.rb +25 -0
- data/lib/twingly/version.rb +7 -0
- metadata +180 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: c96f42ded2e94d947bd2a15cc7de75669e3f2dc06a17ff7d648eb3c0cf862c5e
|
4
|
+
data.tar.gz: 5203e3833efe611708b1b185708735b2c6a027d20d8edd0e79c80dcca696d73a
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 6869f39208327e4b834f999e96a1a0d7253768022aca54f259c1f0cf57bf60331e4aabc966919ad0a7bef08e3091ff7090c9e576986f7d4f5336894ac47b250b
|
7
|
+
data.tar.gz: 4cf992e7c60229b8fcbfd3ab62b0584e8531b229fd8a863d8ab1a47b248c5c2697eb225beecb6ec26377bce50009bf6ba295e1fee45622951be2809ffb5b4640
|
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2019 Twingly AB
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
6
|
+
this software and associated documentation files (the "Software"), to deal in
|
7
|
+
the Software without restriction, including without limitation the rights to
|
8
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
9
|
+
the Software, and to permit persons to whom the Software is furnished to do so,
|
10
|
+
subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
17
|
+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
18
|
+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
19
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
20
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# Twingly::HTTP
|
2
|
+
|
3
|
+
Robust HTTP client
|
4
|
+
|
5
|
+
|
6
|
+
## Release workflow
|
7
|
+
|
8
|
+
* Bump the version in `lib/twingly/version.rb` in a commit, no need to push (the release task does that).
|
9
|
+
|
10
|
+
* Ensure you are signed in to RubyGems.org as [twingly][twingly-rubygems] with `gem signin`.
|
11
|
+
|
12
|
+
* Build and [publish](http://guides.rubygems.org/publishing/) the gem. This will create the proper tag in git, push the commit and tag and upload to RubyGems.
|
13
|
+
|
14
|
+
bundle exec rake release
|
15
|
+
|
16
|
+
* Update the changelog with [GitHub Changelog Generator](https://github.com/skywinder/github-changelog-generator/) (`gem install github_changelog_generator` if you don't have it, set `CHANGELOG_GITHUB_TOKEN` to a personal access token to avoid rate limiting by GitHub). This command will update `CHANGELOG.md`. You need to commit and push manually.
|
17
|
+
|
18
|
+
github_changelog_generator
|
19
|
+
|
20
|
+
[twingly-rubygems]: https://rubygems.org/profiles/twingly
|
21
|
+
[ruby-prof]: http://ruby-prof.rubyforge.org/
|
22
|
+
[memory_profiler]: https://github.com/SamSaffron/memory_profiler
|
23
|
+
[examples]: examples/url.rb
|
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009-2015 Rick Olson, Zack Hobson
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
@@ -0,0 +1,130 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "forwardable"
|
4
|
+
|
5
|
+
module Faraday
|
6
|
+
module LogfmtLogger
|
7
|
+
class Middleware < Response::Middleware
|
8
|
+
extend Forwardable
|
9
|
+
|
10
|
+
DEFAULT_OPTIONS = { headers: true, bodies: false }.freeze
|
11
|
+
|
12
|
+
def initialize(app, logger = nil, options = {})
|
13
|
+
super(app)
|
14
|
+
@logger = logger || begin
|
15
|
+
require "logger"
|
16
|
+
::Logger.new(STDOUT)
|
17
|
+
end
|
18
|
+
|
19
|
+
@filter = []
|
20
|
+
@options = DEFAULT_OPTIONS.merge(options)
|
21
|
+
yield self if block_given?
|
22
|
+
end
|
23
|
+
|
24
|
+
def_delegators :@logger, :debug, :info, :warn, :error, :fatal
|
25
|
+
|
26
|
+
def call(env)
|
27
|
+
info("request") do
|
28
|
+
log_entry = {
|
29
|
+
"source": "upstream-request",
|
30
|
+
"method": env.method.upcase,
|
31
|
+
"url": apply_filters(env.url.to_s),
|
32
|
+
"request_id": request_id,
|
33
|
+
}.merge(app_metadata)
|
34
|
+
|
35
|
+
Twingly::StringUtilities.logfmt(log_entry)
|
36
|
+
end
|
37
|
+
debug_log_request(env)
|
38
|
+
super
|
39
|
+
end
|
40
|
+
|
41
|
+
def on_complete(env)
|
42
|
+
info("response") do
|
43
|
+
log_entry = {
|
44
|
+
"source": "upstream-response",
|
45
|
+
"status": env.status,
|
46
|
+
"request_id": request_id,
|
47
|
+
}.merge(app_metadata)
|
48
|
+
|
49
|
+
Twingly::StringUtilities.logfmt(log_entry)
|
50
|
+
end
|
51
|
+
debug_log_response(env)
|
52
|
+
end
|
53
|
+
|
54
|
+
# Disable Rubocop here to keep the code look the same where it came from:
|
55
|
+
# https://github.com/lostisland/faraday/blob/v0.11.0/lib/faraday/response/logger.rb
|
56
|
+
|
57
|
+
# rubocop:disable all
|
58
|
+
def filter(filter_word, filter_replacement)
|
59
|
+
@filter.push([ filter_word, filter_replacement ])
|
60
|
+
end
|
61
|
+
# rubocop:enable all
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
def request_id
|
66
|
+
@options[:request_id]
|
67
|
+
end
|
68
|
+
|
69
|
+
def app_metadata
|
70
|
+
{
|
71
|
+
"release": Twingly::HTTP::Heroku.release_version,
|
72
|
+
}
|
73
|
+
end
|
74
|
+
|
75
|
+
# rubocop:disable all
|
76
|
+
def debug_log_request(env)
|
77
|
+
debug('request') { apply_filters( dump_headers env.request_headers ) } if log_headers?(:request)
|
78
|
+
debug('request') { apply_filters( dump_body(env[:body]) ) } if env[:body] && log_body?(:request)
|
79
|
+
end
|
80
|
+
|
81
|
+
def debug_log_response(env)
|
82
|
+
debug('response') { apply_filters( dump_headers env.response_headers ) } if log_headers?(:response)
|
83
|
+
debug('response') { apply_filters( dump_body env[:body] ) } if env[:body] && log_body?(:response)
|
84
|
+
end
|
85
|
+
|
86
|
+
def dump_headers(headers)
|
87
|
+
headers.map { |k, v| "#{k}: #{v.inspect}" }.join("\n")
|
88
|
+
end
|
89
|
+
|
90
|
+
def dump_body(body)
|
91
|
+
if body.respond_to?(:to_str)
|
92
|
+
body.to_str
|
93
|
+
else
|
94
|
+
pretty_inspect(body)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def pretty_inspect(body)
|
99
|
+
require 'pp' unless body.respond_to?(:pretty_inspect)
|
100
|
+
body.pretty_inspect
|
101
|
+
end
|
102
|
+
|
103
|
+
def log_headers?(type)
|
104
|
+
case @options[:headers]
|
105
|
+
when Hash then @options[:headers][type]
|
106
|
+
else @options[:headers]
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def log_body?(type)
|
111
|
+
case @options[:bodies]
|
112
|
+
when Hash then @options[:bodies][type]
|
113
|
+
else @options[:bodies]
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def apply_filters(output)
|
118
|
+
@filter.each do |pattern, replacement|
|
119
|
+
output = output.to_s.gsub(pattern, replacement)
|
120
|
+
end
|
121
|
+
output
|
122
|
+
end
|
123
|
+
# rubocop:enable all
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
Faraday::Response.register_middleware(
|
129
|
+
logfmt_logger: Faraday::LogfmtLogger::Middleware
|
130
|
+
)
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Faraday
|
4
|
+
module UrlSizeLimit
|
5
|
+
class LimitExceededError < StandardError; end
|
6
|
+
|
7
|
+
class Middleware < Faraday::Middleware
|
8
|
+
def initialize(app, max_size_bytes:)
|
9
|
+
super(app)
|
10
|
+
|
11
|
+
@max_size_bytes = max_size_bytes
|
12
|
+
end
|
13
|
+
|
14
|
+
def call(env)
|
15
|
+
url_bytesize = env.url.to_s.bytesize
|
16
|
+
|
17
|
+
if url_bytesize >= @max_size_bytes
|
18
|
+
raise LimitExceededError,
|
19
|
+
"Expected URL below #{@max_size_bytes} bytes, "\
|
20
|
+
"was #{url_bytesize} bytes"
|
21
|
+
end
|
22
|
+
|
23
|
+
@app.call(env)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
Faraday::Request.register_middleware(
|
30
|
+
url_size_limit: Faraday::UrlSizeLimit::Middleware
|
31
|
+
)
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Twingly
|
4
|
+
module HTTP
|
5
|
+
class Heroku
|
6
|
+
def self.app_name
|
7
|
+
ENV.fetch("HEROKU_APP_NAME") { "unknown_heroku_app_name" }
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.dyno_id
|
11
|
+
ENV.fetch("HEROKU_DYNO_ID") { "unknown_heroku_dyno_id" }
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.slug_commit
|
15
|
+
ENV.fetch("HEROKU_SLUG_COMMIT") { "unknown_heroku_slug_commit" }
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.release_version
|
19
|
+
ENV.fetch("HEROKU_RELEASE_VERSION") { "unknown_heroku_release_version" }
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.review_app?
|
23
|
+
parent_name = ENV.fetch("HEROKU_PARENT_APP_NAME") {}
|
24
|
+
|
25
|
+
return false unless parent_name
|
26
|
+
|
27
|
+
app_name = ENV.fetch("HEROKU_APP_NAME") { "" }
|
28
|
+
review_app_name_format = /\A#{parent_name}-pr-\d+\z/
|
29
|
+
|
30
|
+
review_app_name_format.match?(app_name)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
data/lib/twingly/http.rb
ADDED
@@ -0,0 +1,200 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "net/http"
|
4
|
+
require "faraday"
|
5
|
+
|
6
|
+
require_relative "../faraday/logfmt_logger"
|
7
|
+
require_relative "../faraday/url_size_limit"
|
8
|
+
require_relative "heroku"
|
9
|
+
require_relative "string_utilities"
|
10
|
+
|
11
|
+
module Twingly
|
12
|
+
module HTTP
|
13
|
+
class ConnectionError < StandardError; end
|
14
|
+
class UrlSizeLimitExceededError < StandardError; end
|
15
|
+
class Client # rubocop:disable Metrics/ClassLength
|
16
|
+
DEFAULT_RETRYABLE_EXCEPTIONS = [
|
17
|
+
Faraday::ConnectionFailed,
|
18
|
+
Faraday::SSLError,
|
19
|
+
Zlib::BufError,
|
20
|
+
Zlib::DataError,
|
21
|
+
].freeze
|
22
|
+
TIMEOUT_EXCEPTIONS = [
|
23
|
+
Faraday::TimeoutError,
|
24
|
+
Net::OpenTimeout,
|
25
|
+
].freeze
|
26
|
+
DEFAULT_HTTP_TIMEOUT = 20
|
27
|
+
DEFAULT_HTTP_OPEN_TIMEOUT = 10
|
28
|
+
DEFAULT_NUMBER_OF_RETRIES = 0
|
29
|
+
DEFAULT_RETRY_INTERVAL = 1
|
30
|
+
DEFAULT_MAX_URL_SIZE_BYTES = Float::INFINITY
|
31
|
+
|
32
|
+
attr_writer :http_timeout
|
33
|
+
attr_writer :http_open_timeout
|
34
|
+
attr_writer :number_of_retries
|
35
|
+
attr_writer :retry_interval
|
36
|
+
attr_writer :on_retry_callback
|
37
|
+
attr_writer :max_url_size_bytes
|
38
|
+
attr_writer :request_id
|
39
|
+
|
40
|
+
attr_accessor :retryable_exceptions
|
41
|
+
|
42
|
+
def initialize(logger:, base_user_agent:)
|
43
|
+
@logger = logger
|
44
|
+
@base_user_agent = base_user_agent
|
45
|
+
@request_id = nil
|
46
|
+
|
47
|
+
@http_timeout = DEFAULT_HTTP_TIMEOUT
|
48
|
+
@http_open_timeout = DEFAULT_HTTP_OPEN_TIMEOUT
|
49
|
+
|
50
|
+
@retryable_exceptions = DEFAULT_RETRYABLE_EXCEPTIONS
|
51
|
+
@number_of_retries = DEFAULT_NUMBER_OF_RETRIES
|
52
|
+
@retry_interval = DEFAULT_RETRY_INTERVAL
|
53
|
+
@on_retry_callback = nil
|
54
|
+
|
55
|
+
@max_url_size_bytes = DEFAULT_MAX_URL_SIZE_BYTES
|
56
|
+
end
|
57
|
+
|
58
|
+
def get(url, params: {})
|
59
|
+
http_response_for(:get, url: url, params: params)
|
60
|
+
end
|
61
|
+
|
62
|
+
def post(url, body:, headers: {})
|
63
|
+
http_response_for(:post, url: url, body: body, headers: headers)
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
|
68
|
+
# rubocop:disable Metrics/MethodLength
|
69
|
+
def http_response_for(method, *args)
|
70
|
+
response = case method
|
71
|
+
when :get
|
72
|
+
http_get_response(*args)
|
73
|
+
when :post
|
74
|
+
http_post_response(*args)
|
75
|
+
end
|
76
|
+
|
77
|
+
Response.new(headers: response.headers.to_h,
|
78
|
+
status: response.status,
|
79
|
+
body: response.body)
|
80
|
+
rescue *(@retryable_exceptions + TIMEOUT_EXCEPTIONS)
|
81
|
+
raise ConnectionError
|
82
|
+
rescue Faraday::UrlSizeLimit::LimitExceededError => error
|
83
|
+
raise UrlSizeLimitExceededError, error.message
|
84
|
+
end
|
85
|
+
# rubocop:enable all
|
86
|
+
|
87
|
+
def http_get_response(url:, params: {})
|
88
|
+
binary_url = url.dup.force_encoding(Encoding::BINARY)
|
89
|
+
http_client = create_http_client
|
90
|
+
|
91
|
+
headers = default_headers
|
92
|
+
|
93
|
+
http_client.get do |request|
|
94
|
+
request.url(binary_url)
|
95
|
+
request.params.merge!(params)
|
96
|
+
request.headers.merge!(headers)
|
97
|
+
request.options.timeout = @http_timeout
|
98
|
+
request.options.open_timeout = @http_open_timeout
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def http_post_response(url:, body:, headers:)
|
103
|
+
binary_url = url.dup.force_encoding(Encoding::BINARY)
|
104
|
+
http_client = create_http_client
|
105
|
+
|
106
|
+
headers = default_headers.merge(headers)
|
107
|
+
|
108
|
+
http_client.post do |request|
|
109
|
+
request.url(binary_url)
|
110
|
+
request.headers.merge!(headers)
|
111
|
+
request.body = body
|
112
|
+
request.options.timeout = @http_timeout
|
113
|
+
request.options.open_timeout = @http_open_timeout
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def create_http_client # rubocop:disable Metrics/MethodLength
|
118
|
+
Faraday.new do |faraday|
|
119
|
+
faraday.request :url_size_limit,
|
120
|
+
max_size_bytes: @max_url_size_bytes
|
121
|
+
faraday.request :retry,
|
122
|
+
max: @number_of_retries,
|
123
|
+
interval: @retry_interval,
|
124
|
+
exceptions: @retryable_exceptions,
|
125
|
+
methods: [], # empty [] forces Faraday to run retry_if
|
126
|
+
retry_if: retry_if
|
127
|
+
faraday.response :logfmt_logger, @logger.dup,
|
128
|
+
headers: true,
|
129
|
+
bodies: true,
|
130
|
+
request_id: @request_id
|
131
|
+
faraday.adapter Faraday.default_adapter
|
132
|
+
faraday.headers[:user_agent] = user_agent
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
def retry_if
|
137
|
+
lambda do |env, exception|
|
138
|
+
unwrapped_exception = unwrap_exception(exception)
|
139
|
+
|
140
|
+
# we do not retry on timeouts due to our request time budget
|
141
|
+
if timeout_error?(unwrapped_exception)
|
142
|
+
false
|
143
|
+
else
|
144
|
+
@on_retry_callback&.call(env, unwrapped_exception)
|
145
|
+
true
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
def unwrap_exception(exception)
|
151
|
+
if exception.respond_to?(:wrapped_exception)
|
152
|
+
exception.wrapped_exception
|
153
|
+
else
|
154
|
+
exception
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
def timeout_error?(error)
|
159
|
+
TIMEOUT_EXCEPTIONS.include?(error.class)
|
160
|
+
end
|
161
|
+
|
162
|
+
def user_agent
|
163
|
+
format(
|
164
|
+
"%<base>s (Release/%<release>s; Commit/%<commit>s)",
|
165
|
+
base: @base_user_agent,
|
166
|
+
release: Heroku.release_version,
|
167
|
+
commit: Heroku.slug_commit
|
168
|
+
)
|
169
|
+
end
|
170
|
+
|
171
|
+
def app_metadata
|
172
|
+
{
|
173
|
+
"dyno_id": Heroku.dyno_id,
|
174
|
+
"release": Heroku.release_version,
|
175
|
+
"git_head": Heroku.slug_commit,
|
176
|
+
}
|
177
|
+
end
|
178
|
+
|
179
|
+
def default_headers
|
180
|
+
{
|
181
|
+
"X-Request-Id": @request_id,
|
182
|
+
}.delete_if { |_name, value| value.to_s.strip.empty? }
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
class Response
|
187
|
+
attr_reader :headers
|
188
|
+
attr_reader :status
|
189
|
+
attr_reader :body
|
190
|
+
|
191
|
+
def initialize(headers: nil,
|
192
|
+
status: nil,
|
193
|
+
body: nil)
|
194
|
+
@headers = headers
|
195
|
+
@status = status
|
196
|
+
@body = body
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Twingly
|
4
|
+
module StringUtilities
|
5
|
+
module_function
|
6
|
+
|
7
|
+
def logfmt(hsh)
|
8
|
+
hsh.map { |key, value| "#{key}=#{value}" }.join(" ")
|
9
|
+
end
|
10
|
+
|
11
|
+
def strip_start_character(string, char:)
|
12
|
+
return unless string
|
13
|
+
|
14
|
+
if string[0] == char
|
15
|
+
string[1..-1]
|
16
|
+
else
|
17
|
+
string
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def split_key_pair(key_pair)
|
22
|
+
key_pair.to_s.split(":")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
metadata
ADDED
@@ -0,0 +1,180 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: twingly-http
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Twingly AB
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2019-11-07 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: faraday
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0.15'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0.15'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: climate_control
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0.1'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0.1'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '12'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '12'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rspec
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '3'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '3'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rubocop
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0.76'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0.76'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rubocop-rspec
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '1.36'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '1.36'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: toxiproxy
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '1.0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '1.0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: vcr
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - "~>"
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '5.0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - "~>"
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '5.0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: webmock
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - "~>"
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '3.7'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - "~>"
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '3.7'
|
139
|
+
description: Robust HTTP client tailored by Twingly
|
140
|
+
email:
|
141
|
+
- support@twingly.com
|
142
|
+
executables: []
|
143
|
+
extensions: []
|
144
|
+
extra_rdoc_files: []
|
145
|
+
files:
|
146
|
+
- LICENSE
|
147
|
+
- README.md
|
148
|
+
- lib/faraday/logfmt_logger.rb
|
149
|
+
- lib/faraday/logfmt_logger/LICENSE.md
|
150
|
+
- lib/faraday/logfmt_logger/middleware.rb
|
151
|
+
- lib/faraday/url_size_limit.rb
|
152
|
+
- lib/faraday/url_size_limit/middleware.rb
|
153
|
+
- lib/twingly/heroku.rb
|
154
|
+
- lib/twingly/http.rb
|
155
|
+
- lib/twingly/string_utilities.rb
|
156
|
+
- lib/twingly/version.rb
|
157
|
+
homepage: http://github.com/twingly/twingly-http
|
158
|
+
licenses:
|
159
|
+
- MIT
|
160
|
+
metadata: {}
|
161
|
+
post_install_message:
|
162
|
+
rdoc_options: []
|
163
|
+
require_paths:
|
164
|
+
- lib
|
165
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
166
|
+
requirements:
|
167
|
+
- - "~>"
|
168
|
+
- !ruby/object:Gem::Version
|
169
|
+
version: '2.5'
|
170
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
171
|
+
requirements:
|
172
|
+
- - ">="
|
173
|
+
- !ruby/object:Gem::Version
|
174
|
+
version: '0'
|
175
|
+
requirements: []
|
176
|
+
rubygems_version: 3.0.6
|
177
|
+
signing_key:
|
178
|
+
specification_version: 4
|
179
|
+
summary: Robust HTTP client
|
180
|
+
test_files: []
|