twingly-http 0.1.0 → 0.4.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: c96f42ded2e94d947bd2a15cc7de75669e3f2dc06a17ff7d648eb3c0cf862c5e
4
- data.tar.gz: 5203e3833efe611708b1b185708735b2c6a027d20d8edd0e79c80dcca696d73a
3
+ metadata.gz: 573e3beb22fd03c1961fe5b6264b3a2b1ef9f0a5a89b95e0094e1693e76dff7f
4
+ data.tar.gz: 30a0dda321f1a3804492fd91e49907456cd3e45494f79ff571c054b648f7725c
5
5
  SHA512:
6
- metadata.gz: 6869f39208327e4b834f999e96a1a0d7253768022aca54f259c1f0cf57bf60331e4aabc966919ad0a7bef08e3091ff7090c9e576986f7d4f5336894ac47b250b
7
- data.tar.gz: 4cf992e7c60229b8fcbfd3ab62b0584e8531b229fd8a863d8ab1a47b248c5c2697eb225beecb6ec26377bce50009bf6ba295e1fee45622951be2809ffb5b4640
6
+ metadata.gz: 9d209c54bbd796f27d38796d6a5449cf961e7de9a351700098ba92f022502a34950dc7652c4c9d16f80d9ae7474fe65bd6d3a60976cf43db65f767d5fb97277e
7
+ data.tar.gz: 6e4db092c8893e0539b17af90233d9ac86f2bbb2f51a2ab3b29fbd7c671211861168e30b434b4abdbf209c332861292a71bee37cb47fe4a91f3623b14f67a21f
data/README.md CHANGED
@@ -1,7 +1,44 @@
1
1
  # Twingly::HTTP
2
2
 
3
- Robust HTTP client
3
+ [![GitHub Build Status](https://github.com/twingly/twingly-http/workflows/CI/badge.svg?branch=master)](https://github.com/twingly/twingly-http/actions)
4
4
 
5
+ Robust HTTP client, tailored by Twingly.
6
+
7
+ ## Getting Started
8
+
9
+ Install the gem:
10
+
11
+ gem install twingly-http
12
+
13
+ Example "one-liner" usage:
14
+
15
+ ```
16
+ ruby -rlogger -rtwingly/http -e '\
17
+ logger = Logger.new(STDOUT); logger.level = :INFO; \
18
+ puts Twingly::HTTP::Client.new(logger: logger, \
19
+ base_user_agent: "").get("http://example.org").status'
20
+ ```
21
+
22
+ Example `irb` usage:
23
+
24
+ ```
25
+ irb -rlogger -rtwingly/http
26
+ ```
27
+ ```ruby
28
+ logger = Logger.new(STDOUT); logger.level = :INFO
29
+ client = Twingly::HTTP::Client.new(logger: logger, base_user_agent: "")
30
+ client.get("http://example.org").status
31
+ ```
32
+
33
+ ## Tests
34
+
35
+ The tests require [Toxiproxy](https://github.com/Shopify/toxiproxy)
36
+
37
+ docker-compose up
38
+
39
+ Run tests with
40
+
41
+ bundle exec rake
5
42
 
6
43
  ## Release workflow
7
44
 
@@ -18,6 +55,3 @@ Robust HTTP client
18
55
  github_changelog_generator
19
56
 
20
57
  [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
data/lib/twingly/http.rb CHANGED
@@ -1,7 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "logger"
3
4
  require "net/http"
4
5
  require "faraday"
6
+ require "faraday_middleware"
5
7
 
6
8
  require_relative "../faraday/logfmt_logger"
7
9
  require_relative "../faraday/url_size_limit"
@@ -12,6 +14,7 @@ module Twingly
12
14
  module HTTP
13
15
  class ConnectionError < StandardError; end
14
16
  class UrlSizeLimitExceededError < StandardError; end
17
+ class RedirectLimitReachedError < StandardError; end
15
18
  class Client # rubocop:disable Metrics/ClassLength
16
19
  DEFAULT_RETRYABLE_EXCEPTIONS = [
17
20
  Faraday::ConnectionFailed,
@@ -28,6 +31,7 @@ module Twingly
28
31
  DEFAULT_NUMBER_OF_RETRIES = 0
29
32
  DEFAULT_RETRY_INTERVAL = 1
30
33
  DEFAULT_MAX_URL_SIZE_BYTES = Float::INFINITY
34
+ DEFAULT_FOLLOW_REDIRECTS_LIMIT = 3
31
35
 
32
36
  attr_writer :http_timeout
33
37
  attr_writer :http_open_timeout
@@ -36,43 +40,60 @@ module Twingly
36
40
  attr_writer :on_retry_callback
37
41
  attr_writer :max_url_size_bytes
38
42
  attr_writer :request_id
43
+ attr_writer :follow_redirects
39
44
 
45
+ attr_accessor :follow_redirects_limit
46
+ attr_accessor :logger
40
47
  attr_accessor :retryable_exceptions
41
48
 
42
- def initialize(logger:, base_user_agent:)
43
- @logger = logger
49
+ def initialize(base_user_agent:, logger: default_logger)
44
50
  @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
51
+ @logger = logger
54
52
 
55
- @max_url_size_bytes = DEFAULT_MAX_URL_SIZE_BYTES
53
+ initialize_defaults
56
54
  end
57
55
 
58
- def get(url, params: {})
59
- http_response_for(:get, url: url, params: params)
56
+ def get(url, params: {}, headers: {})
57
+ http_response_for(:get, url: url, params: params, headers: headers)
60
58
  end
61
59
 
62
60
  def post(url, body:, headers: {})
63
61
  http_response_for(:post, url: url, body: body, headers: headers)
64
62
  end
65
63
 
64
+ def put(url, body:, headers: {})
65
+ http_response_for(:put, url: url, body: body, headers: headers)
66
+ end
67
+
68
+ def patch(url, body:, headers: {})
69
+ http_response_for(:patch, url: url, body: body, headers: headers)
70
+ end
71
+
72
+ def delete(url, params: {}, headers: {})
73
+ http_response_for(:delete, url: url, params: params, headers: headers)
74
+ end
75
+
66
76
  private
67
77
 
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
78
+ def default_logger
79
+ Logger.new(File::NULL)
80
+ end
81
+
82
+ def initialize_defaults
83
+ @request_id = nil
84
+ @http_timeout = DEFAULT_HTTP_TIMEOUT
85
+ @http_open_timeout = DEFAULT_HTTP_OPEN_TIMEOUT
86
+ @retryable_exceptions = DEFAULT_RETRYABLE_EXCEPTIONS
87
+ @number_of_retries = DEFAULT_NUMBER_OF_RETRIES
88
+ @retry_interval = DEFAULT_RETRY_INTERVAL
89
+ @on_retry_callback = nil
90
+ @follow_redirects = false
91
+ @follow_redirects_limit = DEFAULT_FOLLOW_REDIRECTS_LIMIT
92
+ @max_url_size_bytes = DEFAULT_MAX_URL_SIZE_BYTES
93
+ end
94
+
95
+ def http_response_for(method, **args)
96
+ response = send("http_#{method}_response", **args)
76
97
 
77
98
  Response.new(headers: response.headers.to_h,
78
99
  status: response.status,
@@ -81,14 +102,15 @@ module Twingly
81
102
  raise ConnectionError
82
103
  rescue Faraday::UrlSizeLimit::LimitExceededError => error
83
104
  raise UrlSizeLimitExceededError, error.message
105
+ rescue FaradayMiddleware::RedirectLimitReached => error
106
+ raise RedirectLimitReachedError, error.message
84
107
  end
85
- # rubocop:enable all
86
108
 
87
- def http_get_response(url:, params: {})
109
+ def http_get_response(url:, params:, headers:)
88
110
  binary_url = url.dup.force_encoding(Encoding::BINARY)
89
111
  http_client = create_http_client
90
112
 
91
- headers = default_headers
113
+ headers = default_headers.merge(headers)
92
114
 
93
115
  http_client.get do |request|
94
116
  request.url(binary_url)
@@ -114,6 +136,51 @@ module Twingly
114
136
  end
115
137
  end
116
138
 
139
+ def http_put_response(url:, body:, headers:)
140
+ binary_url = url.dup.force_encoding(Encoding::BINARY)
141
+ http_client = create_http_client
142
+
143
+ headers = default_headers.merge(headers)
144
+
145
+ http_client.put do |request|
146
+ request.url(binary_url)
147
+ request.headers.merge!(headers)
148
+ request.body = body
149
+ request.options.timeout = @http_timeout
150
+ request.options.open_timeout = @http_open_timeout
151
+ end
152
+ end
153
+
154
+ def http_patch_response(url:, body:, headers:)
155
+ binary_url = url.dup.force_encoding(Encoding::BINARY)
156
+ http_client = create_http_client
157
+
158
+ headers = default_headers.merge(headers)
159
+
160
+ http_client.patch do |request|
161
+ request.url(binary_url)
162
+ request.headers.merge!(headers)
163
+ request.body = body
164
+ request.options.timeout = @http_timeout
165
+ request.options.open_timeout = @http_open_timeout
166
+ end
167
+ end
168
+
169
+ def http_delete_response(url:, params:, headers:)
170
+ binary_url = url.dup.force_encoding(Encoding::BINARY)
171
+ http_client = create_http_client
172
+
173
+ headers = default_headers.merge(headers)
174
+
175
+ http_client.delete do |request|
176
+ request.url(binary_url)
177
+ request.params.merge!(params)
178
+ request.headers.merge!(headers)
179
+ request.options.timeout = @http_timeout
180
+ request.options.open_timeout = @http_open_timeout
181
+ end
182
+ end
183
+
117
184
  def create_http_client # rubocop:disable Metrics/MethodLength
118
185
  Faraday.new do |faraday|
119
186
  faraday.request :url_size_limit,
@@ -128,6 +195,10 @@ module Twingly
128
195
  headers: true,
129
196
  bodies: true,
130
197
  request_id: @request_id
198
+ if @follow_redirects
199
+ faraday.use FaradayMiddleware::FollowRedirects,
200
+ limit: @follow_redirects_limit
201
+ end
131
202
  faraday.adapter Faraday.default_adapter
132
203
  faraday.headers[:user_agent] = user_agent
133
204
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Twingly
4
4
  module HTTP
5
- VERSION = "0.1.0"
5
+ VERSION = "0.4.0"
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: twingly-http
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Twingly AB
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-11-07 00:00:00.000000000 Z
11
+ date: 2021-11-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -16,14 +16,34 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '0.15'
19
+ version: '1'
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 1.0.1
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: '1'
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 1.0.1
33
+ - !ruby/object:Gem::Dependency
34
+ name: faraday_middleware
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: 1.0.0
20
40
  type: :runtime
21
41
  prerelease: false
22
42
  version_requirements: !ruby/object:Gem::Requirement
23
43
  requirements:
24
44
  - - "~>"
25
45
  - !ruby/object:Gem::Version
26
- version: '0.15'
46
+ version: 1.0.0
27
47
  - !ruby/object:Gem::Dependency
28
48
  name: climate_control
29
49
  requirement: !ruby/object:Gem::Requirement
@@ -72,14 +92,14 @@ dependencies:
72
92
  requirements:
73
93
  - - "~>"
74
94
  - !ruby/object:Gem::Version
75
- version: '0.76'
95
+ version: 0.77.0
76
96
  type: :development
77
97
  prerelease: false
78
98
  version_requirements: !ruby/object:Gem::Requirement
79
99
  requirements:
80
100
  - - "~>"
81
101
  - !ruby/object:Gem::Version
82
- version: '0.76'
102
+ version: 0.77.0
83
103
  - !ruby/object:Gem::Dependency
84
104
  name: rubocop-rspec
85
105
  requirement: !ruby/object:Gem::Requirement
@@ -158,13 +178,13 @@ homepage: http://github.com/twingly/twingly-http
158
178
  licenses:
159
179
  - MIT
160
180
  metadata: {}
161
- post_install_message:
181
+ post_install_message:
162
182
  rdoc_options: []
163
183
  require_paths:
164
184
  - lib
165
185
  required_ruby_version: !ruby/object:Gem::Requirement
166
186
  requirements:
167
- - - "~>"
187
+ - - ">="
168
188
  - !ruby/object:Gem::Version
169
189
  version: '2.5'
170
190
  required_rubygems_version: !ruby/object:Gem::Requirement
@@ -173,8 +193,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
173
193
  - !ruby/object:Gem::Version
174
194
  version: '0'
175
195
  requirements: []
176
- rubygems_version: 3.0.6
177
- signing_key:
196
+ rubygems_version: 3.1.6
197
+ signing_key:
178
198
  specification_version: 4
179
199
  summary: Robust HTTP client
180
200
  test_files: []