qingstor-sdk 2.2.2 → 2.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/README.md +83 -7
- data/lib/qingstor/sdk/general/config.rb +109 -12
- data/lib/qingstor/sdk/general/contract.rb +6 -3
- data/lib/qingstor/sdk/general/logger.rb +1 -1
- data/lib/qingstor/sdk/request/preprocessor.rb +62 -0
- data/lib/qingstor/sdk/request/request.rb +17 -4
- data/lib/qingstor/sdk/request/signer.rb +28 -11
- data/lib/qingstor/sdk/service/bucket.rb +889 -73
- data/lib/qingstor/sdk/service/object.rb +300 -44
- data/lib/qingstor/sdk/service/qingstor.rb +14 -7
- data/lib/qingstor/sdk/version.rb +1 -1
- metadata +47 -29
- data/lib/qingstor/sdk/general/default/config.yaml +0 -15
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: b4067ee8cebe68b7a6ff943ce45aab389887fec3eb3725311eb8fd0bbf44fa50
|
4
|
+
data.tar.gz: 97d3720cb4c6ac65b45fa66a1ac8b117300f96489894c19381972ed945b59c79
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2d09dc5817005d1645473bddb4f5a354a4fef382dcf34775dee845cbffe1188d28d8684df73daf7440d58a83d6aa3e26d1c1e2199dacedf294f40fae915f25ec
|
7
|
+
data.tar.gz: a0a940c7419f8acc356977c9d336a7c982b67282624baa0e0b44e0f8b31a37cf3dd4b6e4d3f5b19ca84c6bf11a7d14c0169a522fc44d3390d297d29598be675b
|
data/README.md
CHANGED
@@ -1,11 +1,10 @@
|
|
1
1
|
# QingStor::SDK
|
2
2
|
|
3
|
-
|
4
|
-
[![Build Status](https://travis-ci.org/yunify/qingstor-sdk-ruby.svg?branch=master)](https://travis-ci.org/yunify/qingstor-sdk-ruby)
|
3
|
+
[![Build Status](https://github.com/qingstor/qingstor-sdk-ruby/workflows/Unit%20Test/badge.svg?branch=master)](https://github.com/qingstor/qingstor-sdk-ruby/actions?query=workflow%3A%22Unit+Test%22)
|
5
4
|
[![Gem Version](https://badge.fury.io/rb/qingstor-sdk.svg)](http://badge.fury.io/rb/qingstor-sdk)
|
6
5
|
[![API Reference](http://img.shields.io/badge/api-reference-green.svg)](https://docs.qingcloud.com/qingstor/)
|
7
6
|
[![License](http://img.shields.io/badge/license-apache%20v2-blue.svg)](https://github.com/yunify/qingstor-sdk-ruby/blob/master/LICENSE)
|
8
|
-
|
7
|
+
[![Join the chat](https://img.shields.io/badge/chat-online-blue?style=flat&logo=zulip)](https://qingstor.zulipchat.com/join/odapi42t7xhqc7v4gb2wfgjx/)
|
9
8
|
|
10
9
|
The official QingStor SDK for Ruby programming language.
|
11
10
|
|
@@ -15,7 +14,9 @@ This Gem uses Ruby's _keyword arguments_ feature, thus Ruby v2.1.5 or higher is
|
|
15
14
|
required. See [this article](https://robots.thoughtbot.com/ruby-2-keyword-arguments)
|
16
15
|
for more details about _keyword arguments_.
|
17
16
|
|
18
|
-
_Notice:_
|
17
|
+
_Notice:_ As of sdk v2.4, we no longer support Ruby 2.4 and earlier versions since Ruby 2.4 has been marked as EOL.
|
18
|
+
If you are still using Ruby 2.4 and earlier, you may not be able to use some new features of our sdk,
|
19
|
+
so please upgrade your version of Ruby as soon as possible.
|
19
20
|
|
20
21
|
### Install from RubyGems
|
21
22
|
|
@@ -123,6 +124,11 @@ server (in case of QingStor is deployed in private environment, thus has
|
|
123
124
|
different endpoint with public QingStor) either in the config file, or in
|
124
125
|
the program dynamically.
|
125
126
|
|
127
|
+
**Notice:** config will not be checked available when `new`, `load` and `update`,
|
128
|
+
which will be done right before initializing `service` or `bucket`.
|
129
|
+
If you need to check config, you should call `config.check` whenever you want.
|
130
|
+
If `check` failed, a `ConfigurationError` will be raised.
|
131
|
+
|
126
132
|
___Code Example:___
|
127
133
|
|
128
134
|
``` ruby
|
@@ -132,6 +138,7 @@ require 'qingstor/sdk'
|
|
132
138
|
config = QingStor::SDK::Config.new.load_default_config
|
133
139
|
|
134
140
|
# Create with default value
|
141
|
+
# priority from high to low: param > env > user config > default config
|
135
142
|
config = QingStor::SDK::Config.new({
|
136
143
|
host: 'qingstor.dev',
|
137
144
|
log_level: 'debug',
|
@@ -145,6 +152,13 @@ config = QingStor::SDK::Config.init ENV['ENV_ACCESS_KEY_ID'],
|
|
145
152
|
config = QingStor::SDK::Config.new
|
146
153
|
config = config.load_config_from_file '~/qingstor/config.yaml'
|
147
154
|
|
155
|
+
# Load configuration from env variable:
|
156
|
+
# QINGSTOR_ACCESS_KEY_ID for access_key_id
|
157
|
+
# QINGSTOR_SECRET_ACCESS_KEY for secret_access_key
|
158
|
+
# QINGSTOR_ENABLE_VIRTUAL_HOST_STYLE for enable_virtual_host_style
|
159
|
+
# QINGSTOR_ENDPOINT for endpoint
|
160
|
+
config = QingStor::SDK::Config.new.load_env_config
|
161
|
+
|
148
162
|
# Change API server
|
149
163
|
config.update({host: 'test.qingstor.com'})
|
150
164
|
```
|
@@ -160,26 +174,84 @@ secret_access_key: 'SECRET_ACCESS_KEY'
|
|
160
174
|
host: 'qingstor.com'
|
161
175
|
port: 443
|
162
176
|
protocol: 'https'
|
177
|
+
# or set endpoint directly
|
178
|
+
# endpoint: https://qingstor.com:443
|
179
|
+
|
163
180
|
connection_retries: 3
|
164
181
|
|
182
|
+
# Additional User-Agent
|
183
|
+
additional_user_agent: ""
|
184
|
+
|
165
185
|
# Valid log levels are "debug", "info", "warn", "error", and "fatal".
|
166
|
-
log_level:
|
186
|
+
log_level: warn
|
187
|
+
|
188
|
+
# SDK will use virtual host style for all API calls if enabled
|
189
|
+
enable_virtual_host_style: false
|
167
190
|
```
|
168
191
|
|
169
192
|
## Change Log
|
170
193
|
All notable changes to QingStor SDK for Ruby will be documented here.
|
171
194
|
|
195
|
+
### [v2.5.0] - 2021-02-09
|
196
|
+
|
197
|
+
### Added
|
198
|
+
|
199
|
+
- config: Add env variable support (#52)
|
200
|
+
- signer: Add support for anonymous API call (#53)
|
201
|
+
- config: Add support for endpoint (#55)
|
202
|
+
- config: Add support for enable_vhost_style (#56)
|
203
|
+
|
204
|
+
### Changed
|
205
|
+
|
206
|
+
- Request: Modify Metadata in header to apply rfc 02 (#49)
|
207
|
+
- config: Refactor config check (#54)
|
208
|
+
|
209
|
+
### [v2.4.0] - 2021-01-05
|
210
|
+
|
211
|
+
### Added
|
212
|
+
|
213
|
+
- Support to set x-qs-metadata-directive header (#29)
|
214
|
+
- Add support for bucket replication (#45)
|
215
|
+
|
216
|
+
### Changed
|
217
|
+
|
218
|
+
- ci: Transfer ci into github action (#30)
|
219
|
+
|
220
|
+
### Fixed
|
221
|
+
|
222
|
+
- Fix metadata added into signature when empty (#44)
|
223
|
+
|
224
|
+
### [v2.3.0] - 2020-05-11
|
225
|
+
|
226
|
+
### Added
|
227
|
+
|
228
|
+
- Add support for lifecycle and notification.
|
229
|
+
- Add support for bucket logging, bucket cname and append object. (#24)
|
230
|
+
|
231
|
+
### Fixed
|
232
|
+
|
233
|
+
- Modify content-type check for application/json. (#21)
|
234
|
+
- Fix sub-resources not be recognized when generate signature. (#25)
|
235
|
+
- Fix meta data not work as intended. (#26)
|
236
|
+
- Reverse fix of empty map in template, should not compact empty hash when sign. (#28)
|
237
|
+
|
238
|
+
### [v2.2.3] - 2017-03-28
|
239
|
+
|
240
|
+
### Fixed
|
241
|
+
|
242
|
+
- Fix status code of DELETE CORS API.
|
243
|
+
|
172
244
|
### [v2.2.2] - 2017-03-10
|
173
245
|
|
174
246
|
### Fixed
|
175
247
|
|
176
|
-
- Resource is not mandatory in bucket policy statement
|
248
|
+
- Resource is not mandatory in bucket policy statement.
|
177
249
|
|
178
250
|
### [v2.2.1] - 2017-03-10
|
179
251
|
|
180
252
|
#### Added
|
181
253
|
|
182
|
-
- Allow user to append additional info to User-Agent
|
254
|
+
- Allow user to append additional info to User-Agent.
|
183
255
|
|
184
256
|
### [v2.2.0] - 2017-02-28
|
185
257
|
|
@@ -240,6 +312,10 @@ All notable changes to QingStor SDK for Ruby will be documented here.
|
|
240
312
|
The Apache License (Version 2.0, January 2004).
|
241
313
|
|
242
314
|
[compatible]: https://github.com/yunify/qingstor-sdk-ruby/tree/compatible
|
315
|
+
[v2.5.0]: https://github.com/yunify/qingstor-sdk-ruby/compare/v2.4.0...v2.5.0
|
316
|
+
[v2.4.0]: https://github.com/yunify/qingstor-sdk-ruby/compare/v2.3.0...v2.4.0
|
317
|
+
[v2.3.0]: https://github.com/yunify/qingstor-sdk-ruby/compare/v2.2.3...v2.3.0
|
318
|
+
[v2.2.3]: https://github.com/yunify/qingstor-sdk-ruby/compare/v2.2.2...v2.2.3
|
243
319
|
[v2.2.2]: https://github.com/yunify/qingstor-sdk-ruby/compare/v2.2.1...v2.2.2
|
244
320
|
[v2.2.1]: https://github.com/yunify/qingstor-sdk-ruby/compare/v2.2.0...v2.2.1
|
245
321
|
[v2.2.0]: https://github.com/yunify/qingstor-sdk-ruby/compare/v2.1.1...v2.2.0
|
@@ -15,10 +15,13 @@
|
|
15
15
|
# +-------------------------------------------------------------------------
|
16
16
|
|
17
17
|
require 'fileutils'
|
18
|
+
require 'ipaddr'
|
19
|
+
require 'uri'
|
18
20
|
require 'yaml'
|
19
21
|
|
20
22
|
require 'active_support/core_ext/hash/keys'
|
21
23
|
require 'active_support/core_ext/hash/deep_merge'
|
24
|
+
require 'active_support/core_ext/object/blank'
|
22
25
|
require 'net/http/persistent'
|
23
26
|
|
24
27
|
module QingStor
|
@@ -26,33 +29,83 @@ module QingStor
|
|
26
29
|
class Config < Hash
|
27
30
|
attr_accessor :connection
|
28
31
|
|
32
|
+
DEFAULT_AS_HASH = {
|
33
|
+
host: 'qingstor.com'.freeze,
|
34
|
+
port: 443,
|
35
|
+
protocol: 'https'.freeze,
|
36
|
+
connection_retries: 3,
|
37
|
+
log_level: 'warn'.freeze,
|
38
|
+
enable_virtual_host_style: false
|
39
|
+
}
|
40
|
+
|
29
41
|
def self.init(access_key_id, secret_access_key)
|
30
42
|
initial_config = {
|
31
43
|
access_key_id: access_key_id,
|
32
|
-
secret_access_key: secret_access_key
|
44
|
+
secret_access_key: secret_access_key
|
33
45
|
}
|
34
46
|
Config.new(initial_config)
|
35
47
|
end
|
36
48
|
|
37
49
|
def initialize(initial_config = {})
|
38
50
|
self.connection = Net::HTTP::Persistent.new
|
51
|
+
# load default config as basic
|
39
52
|
load_default_config
|
53
|
+
# load from config, env path superior to ~/.qingstor/config.yaml
|
54
|
+
load_user_config_path_exist
|
55
|
+
# load envs, cover corresponding config if env exists
|
56
|
+
load_env_config
|
57
|
+
# cover by user's param
|
40
58
|
update initial_config
|
41
59
|
end
|
42
60
|
|
43
61
|
def update(another_config = {})
|
44
62
|
deep_merge! another_config.deep_symbolize_keys!
|
63
|
+
parse_boolean(:enable_virtual_host_style)
|
45
64
|
Logger.set_level self[:log_level]
|
46
65
|
self
|
47
66
|
end
|
48
67
|
|
49
68
|
def check
|
50
|
-
[:access_key_id
|
51
|
-
|
52
|
-
|
69
|
+
if self[:access_key_id].blank? && self[:secret_access_key].present? ||
|
70
|
+
self[:access_key_id].present? && self[:secret_access_key].blank?
|
71
|
+
raise ConfigurationError, 'ak and sk should be both both empty or not empty'
|
72
|
+
end
|
73
|
+
|
74
|
+
if self[:access_key_id].blank? && self[:secret_access_key].blank?
|
75
|
+
Logger.warn 'Both ak and sk not configured, will call api as anonymous user'
|
76
|
+
end
|
77
|
+
|
78
|
+
# check endpoint and host/port/protocol
|
79
|
+
if self[:endpoint].blank?
|
80
|
+
# host/port/protocol must set if endpoint not set
|
81
|
+
%i[host port protocol].each do |x|
|
82
|
+
if self[x].blank?
|
83
|
+
raise ConfigurationError, "#{x.to_sym} not specified"
|
84
|
+
end
|
85
|
+
end
|
86
|
+
else
|
87
|
+
# if endpoint set, host/port/protocol ignore, and warn
|
88
|
+
%i[host port protocol].each do |x|
|
89
|
+
if self[x].present? && !Config.is_default?(x, self[x])
|
90
|
+
Logger.warn "Endpoint configured, #{x.to_sym} will be ignored"
|
91
|
+
end
|
53
92
|
end
|
54
93
|
end
|
55
|
-
|
94
|
+
|
95
|
+
# add ip check for vhost enabled
|
96
|
+
if self[:enable_virtual_host_style]
|
97
|
+
if self[:endpoint].present?
|
98
|
+
uri = Preprocessor.parse_endpoint self[:endpoint]
|
99
|
+
ip = uri.host
|
100
|
+
else
|
101
|
+
ip = self[:host]
|
102
|
+
end
|
103
|
+
if is_valid_ip? ip
|
104
|
+
raise ConfigurationError, 'ip host not allowed if vhost enabled'
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
if self[:additional_user_agent].present?
|
56
109
|
self[:additional_user_agent].each_byte do |x|
|
57
110
|
# Allow space(32) to ~(126) in ASCII Table, exclude "(34).
|
58
111
|
if x < 32 || x > 126 || x == 32 || x == 34
|
@@ -64,12 +117,36 @@ module QingStor
|
|
64
117
|
end
|
65
118
|
|
66
119
|
def load_default_config
|
67
|
-
|
120
|
+
update DEFAULT_AS_HASH
|
68
121
|
end
|
69
122
|
|
70
123
|
def load_user_config
|
71
|
-
|
72
|
-
|
124
|
+
if !ENV[Contract::ENV_CONFIG_PATH].nil?
|
125
|
+
load_config_from_file ENV[Contract::ENV_CONFIG_PATH]
|
126
|
+
else
|
127
|
+
load_config_from_file Contract::USER_CONFIG_FILEPATH
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
def load_env_config
|
132
|
+
another_config = {}
|
133
|
+
unless ENV[Contract::ENV_ACCESS_KEY_ID].nil?
|
134
|
+
another_config[:access_key_id] =
|
135
|
+
ENV[Contract::ENV_ACCESS_KEY_ID]
|
136
|
+
end
|
137
|
+
unless ENV[Contract::ENV_SECRET_ACCESS_KEY].nil?
|
138
|
+
another_config[:secret_access_key] =
|
139
|
+
ENV[Contract::ENV_SECRET_ACCESS_KEY]
|
140
|
+
end
|
141
|
+
unless ENV[Contract::ENV_ENABLE_VIRTUAL_HOST_STYLE].nil?
|
142
|
+
another_config[:enable_virtual_host_style] =
|
143
|
+
ENV[Contract::ENV_ENABLE_VIRTUAL_HOST_STYLE]
|
144
|
+
end
|
145
|
+
unless ENV[Contract::ENV_ENDPOINT].nil?
|
146
|
+
another_config[:endpoint] =
|
147
|
+
ENV[Contract::ENV_ENDPOINT]
|
148
|
+
end
|
149
|
+
update another_config
|
73
150
|
end
|
74
151
|
|
75
152
|
def load_config_from_file(path)
|
@@ -79,10 +156,30 @@ module QingStor
|
|
79
156
|
|
80
157
|
private
|
81
158
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
159
|
+
# load user config if path exist, and skip check
|
160
|
+
def load_user_config_path_exist
|
161
|
+
# if env path configured, update from env; otherwise, if ~/.qingstor/config.yaml exists, update from this
|
162
|
+
if !ENV[Contract::ENV_CONFIG_PATH].nil? && File.exist?(ENV[Contract::ENV_CONFIG_PATH])
|
163
|
+
load_config_from_file ENV[Contract::ENV_CONFIG_PATH]
|
164
|
+
elsif File.exist? Contract::USER_CONFIG_FILEPATH
|
165
|
+
load_config_from_file Contract::USER_CONFIG_FILEPATH
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
def parse_boolean(key)
|
170
|
+
self[key.to_sym] = self[key.to_sym].to_s.downcase == 'true'
|
171
|
+
end
|
172
|
+
|
173
|
+
def is_valid_ip?(ip)
|
174
|
+
IPAddr.new ip
|
175
|
+
true
|
176
|
+
rescue
|
177
|
+
false
|
178
|
+
end
|
179
|
+
|
180
|
+
# @return boolean
|
181
|
+
def self.is_default?(key, value)
|
182
|
+
DEFAULT_AS_HASH[key.to_sym].present? && DEFAULT_AS_HASH[key.to_sym] == value
|
86
183
|
end
|
87
184
|
end
|
88
185
|
end
|
@@ -23,9 +23,12 @@ module QingStor
|
|
23
23
|
|
24
24
|
# GEM_DIRECTORY = Gem::Specification.find_by_name('qingcloud-sdk').gem_dir
|
25
25
|
# DEFAULT_SUPPORT_DIRECTORY = GEM_DIRECTORY + '/lib/qingcloud/sdk/commons/default'
|
26
|
-
|
27
|
-
|
28
|
-
|
26
|
+
|
27
|
+
ENV_ACCESS_KEY_ID = 'QINGSTOR_ACCESS_KEY_ID'.freeze
|
28
|
+
ENV_SECRET_ACCESS_KEY = 'QINGSTOR_SECRET_ACCESS_KEY'.freeze
|
29
|
+
ENV_CONFIG_PATH = 'QINGSTOR_CONFIG_PATH'.freeze
|
30
|
+
ENV_ENABLE_VIRTUAL_HOST_STYLE = 'QINGSTOR_ENABLE_VIRTUAL_HOST_STYLE'.freeze
|
31
|
+
ENV_ENDPOINT = 'QINGSTOR_ENDPOINT'.freeze
|
29
32
|
end
|
30
33
|
end
|
31
34
|
end
|
@@ -23,7 +23,7 @@ module QingStor
|
|
23
23
|
@@level = :warn
|
24
24
|
|
25
25
|
def self.set_level(level)
|
26
|
-
index = %w
|
26
|
+
index = %w[debug info warn error fatal].find_index level.to_s
|
27
27
|
@@logger.level = index.nil? ? 0 : index
|
28
28
|
@@level = level.to_sym
|
29
29
|
end
|
@@ -17,8 +17,10 @@
|
|
17
17
|
require 'cgi'
|
18
18
|
require 'base64'
|
19
19
|
require 'digest'
|
20
|
+
require 'uri'
|
20
21
|
|
21
22
|
require 'active_support/core_ext/hash/keys'
|
23
|
+
require 'active_support/core_ext/object/blank'
|
22
24
|
require 'mimemagic'
|
23
25
|
|
24
26
|
module QingStor
|
@@ -41,6 +43,15 @@ module QingStor
|
|
41
43
|
def self.request_endpoint(input)
|
42
44
|
config = input[:config]
|
43
45
|
zone = input[:properties] ? input[:properties][:zone] : nil
|
46
|
+
# handle endpoint directly if it exists
|
47
|
+
if config[:endpoint].present?
|
48
|
+
uri = parse_endpoint(config[:endpoint].to_s)
|
49
|
+
if zone
|
50
|
+
uri.host = "#{zone}.#{uri.host}"
|
51
|
+
end
|
52
|
+
return uri.to_s
|
53
|
+
end
|
54
|
+
|
44
55
|
if zone
|
45
56
|
"#{config[:protocol]}://#{zone}.#{config[:host]}:#{config[:port]}"
|
46
57
|
else
|
@@ -49,6 +60,16 @@ module QingStor
|
|
49
60
|
end
|
50
61
|
|
51
62
|
def self.request_uri(input)
|
63
|
+
config = input[:config]
|
64
|
+
# if enable vhost, and uri property contains bucket-name
|
65
|
+
if config[:enable_virtual_host_style] && input[:properties].present? && input[:properties][:"bucket-name"]
|
66
|
+
uri = parse_endpoint input[:request_endpoint]
|
67
|
+
# modify host, add bucket before
|
68
|
+
uri.host = "#{input[:properties][:"bucket-name"]}.#{uri.host}"
|
69
|
+
input[:request_endpoint] = uri.to_s
|
70
|
+
# handle request_uri, remove prefix (bucket-name)
|
71
|
+
input[:request_uri].delete_prefix! URI_BUCKET_PREFIX if input[:request_uri].start_with? URI_BUCKET_PREFIX
|
72
|
+
end
|
52
73
|
unless input[:properties].nil?
|
53
74
|
input[:properties].each do |k, v|
|
54
75
|
input[:request_uri].gsub! "<#{k}>", (escape v.to_s)
|
@@ -102,6 +123,21 @@ module QingStor
|
|
102
123
|
input[:request_headers][:'Content-MD5'] = Base64.encode64(Digest::MD5.digest(input[:request_body])).strip
|
103
124
|
end
|
104
125
|
|
126
|
+
# X-QS-MetaData used to handle meta data
|
127
|
+
unless input[:request_headers][:'X-QS-MetaData'].nil?
|
128
|
+
if input[:request_headers][:'X-QS-MetaData'].is_a?(Hash) && !input[:request_headers][:'X-QS-MetaData'].empty?
|
129
|
+
prefix = 'x-qs-meta-'
|
130
|
+
input[:request_headers][:'X-QS-MetaData'].each do |k, v|
|
131
|
+
k = k.to_s
|
132
|
+
# add prefix for meta data in header
|
133
|
+
k = prefix + k
|
134
|
+
input[:request_headers][:"#{k}"] = v
|
135
|
+
end
|
136
|
+
end
|
137
|
+
# remove X-QS-MetaData from request header
|
138
|
+
input[:request_headers].delete :'X-QS-MetaData'
|
139
|
+
end
|
140
|
+
|
105
141
|
input[:request_headers].map do |k, v|
|
106
142
|
input[:request_headers][k] = escape v.to_s unless v.to_s.ascii_only?
|
107
143
|
end
|
@@ -139,6 +175,32 @@ module QingStor
|
|
139
175
|
origin.gsub! '+', '%20'
|
140
176
|
origin
|
141
177
|
end
|
178
|
+
|
179
|
+
# try to parse endpoint:
|
180
|
+
# if endpoint invalid, means ip host without scheme, like: 192.168.0.1:3000
|
181
|
+
# if endpoint parsed, and no scheme find, means host without scheme, like: qingstor.dev
|
182
|
+
# both above will add default schema at the start, and parse again
|
183
|
+
def self.parse_endpoint(endpoint)
|
184
|
+
if endpoint.blank?
|
185
|
+
raise 'endpoint should not be empty when parse'
|
186
|
+
end
|
187
|
+
|
188
|
+
begin
|
189
|
+
uri = URI.parse endpoint
|
190
|
+
unless uri.scheme.nil?
|
191
|
+
return uri
|
192
|
+
end
|
193
|
+
rescue URI::InvalidURIError
|
194
|
+
# Ignored and continue, add scheme prefix then
|
195
|
+
end
|
196
|
+
|
197
|
+
endpoint = "http://#{endpoint}" # add default scheme for endpoint
|
198
|
+
URI.parse endpoint
|
199
|
+
end
|
200
|
+
|
201
|
+
private
|
202
|
+
|
203
|
+
URI_BUCKET_PREFIX = '/<bucket-name>'.freeze
|
142
204
|
end
|
143
205
|
end
|
144
206
|
end
|