aspera-cli 4.18.0 → 4.18.1

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.
data/lib/aspera/rest.rb CHANGED
@@ -12,7 +12,7 @@ require 'json'
12
12
  require 'base64'
13
13
  require 'cgi'
14
14
 
15
- # add cancel method to http
15
+ # Cancel method for HTTP
16
16
  class Net::HTTP::Cancel < Net::HTTPRequest # rubocop:disable Style/ClassAndModuleChildren
17
17
  METHOD = 'CANCEL'
18
18
  REQUEST_HAS_BODY = false
@@ -24,12 +24,16 @@ module Aspera
24
24
  # rest call errors are raised as exception RestCallError
25
25
  # and error are analyzed in RestErrorAnalyzer
26
26
  class Rest
27
- # global settings also valid for any subclass
27
+ # Global settings also valid for any subclass
28
+ # @param user_agent [String] HTTP request header: 'User-Agent'
29
+ # @param download_partial_suffix [String] suffix for partial download
30
+ # @param session_cb [lambda] lambda called on new HTTP session. Takes the Net::HTTP as arg. Used to change parameters on creation.
31
+ # @param progress_bar [Object] progress bar object
28
32
  @@global = { # rubocop:disable Style/ClassVars
29
- user_agent: 'Ruby', # goes to HTTP request header: 'User-Agent'
30
- download_partial_suffix: '.http_partial', # suffix for partial download
31
- session_cb: nil, # a lambda which takes the Net::HTTP as arg, use this to change parameters
32
- progress_bar: nil # progress bar object
33
+ user_agent: 'RubyAsperaRest',
34
+ download_partial_suffix: '.http_partial',
35
+ session_cb: nil,
36
+ progress_bar: nil
33
37
  }
34
38
 
35
39
  # flag for array parameters prefixed with []
@@ -44,9 +48,10 @@ module Aspera
44
48
  JSON_DECODE = ['application/json', 'application/vnd.api+json', 'application/x-javascript'].freeze
45
49
 
46
50
  class << self
51
+ # @return [String] Basic auth token
47
52
  def basic_token(user, pass); return "Basic #{Base64.strict_encode64("#{user}:#{pass}")}"; end
48
53
 
49
- # used to build a parameter list prefixed with "[]"
54
+ # Build a parameter list prefixed with "[]"
50
55
  # @param values [Array] list of values
51
56
  def array_params(values)
52
57
  return [ARRAY_PARAMS].concat(values)
@@ -56,7 +61,7 @@ module Aspera
56
61
  return values.first.eql?(ARRAY_PARAMS)
57
62
  end
58
63
 
59
- # build URI from URL and parameters and check it is http or https, encode array [] parameters
64
+ # Build URI from URL and parameters and check it is http or https, encode array [] parameters
60
65
  def build_uri(url, query_hash=nil)
61
66
  uri = URI.parse(url)
62
67
  Aspera.assert(%w[http https].include?(uri.scheme)){"REST endpoint shall be http/s not #{uri.scheme}"}
@@ -82,8 +87,16 @@ module Aspera
82
87
  return uri
83
88
  end
84
89
 
90
+ # decode query string as hash
91
+ # Does not support arrays in query string, no standard, e.g. PHP's way is p[]=1&p[]=2
92
+ # @param query [String] query string
93
+ # @return [Hash] decoded query
85
94
  def decode_query(query)
86
- URI.decode_www_form(query).each_with_object({}){|v, h|h[v.first] = v.last }
95
+ URI.decode_www_form(query).each_with_object({}) do |pair, h|
96
+ key = pair.first
97
+ raise "Array not supported in query string: #{key}" if key.include?('[]') || h.key?(key)
98
+ h[key] = pair.last
99
+ end
87
100
  end
88
101
 
89
102
  # Start a HTTP/S session, also used for web sockets
@@ -141,6 +154,17 @@ module Aspera
141
154
  def user_agent
142
155
  return @@global[:user_agent]
143
156
  end
157
+
158
+ def parse_header(header)
159
+ type, *params = header.split(/;\s*/)
160
+ parameters = params.map do |param|
161
+ one = param.split(/=\s*/)
162
+ one[0] = one[0].to_sym
163
+ one[1] = one[1].gsub(/\A"|"\z/, '')
164
+ one
165
+ end.to_h
166
+ { type: type.downcase, parameters: parameters }
167
+ end
144
168
  end
145
169
 
146
170
  private
@@ -185,8 +209,12 @@ module Aspera
185
209
  headers: nil
186
210
  )
187
211
  Aspera.assert_type(base_url, String)
188
- # base url with max one trailing slashes (note: string may be frozen)
189
- @base_url = base_url.gsub(%r{//+$}, '/')
212
+ # base url with no trailing slashes (note: string may be frozen)
213
+ @base_url = base_url.gsub(%r{/+$}, '')
214
+ # remove trailing port if it is 443 and scheme is https
215
+ @base_url = @base_url.gsub(/:443$/, '') if @base_url.start_with?('https://')
216
+ @base_url = @base_url.gsub(/:80$/, '') if @base_url.start_with?('http://')
217
+ Log.log.debug{"Rest.new(#{@base_url})"}
190
218
  # default is no auth
191
219
  @auth_params = auth.nil? ? {type: :none} : auth
192
220
  Aspera.assert_type(@auth_params, Hash)
@@ -265,7 +293,7 @@ module Aspera
265
293
  begin
266
294
  # TODO: shall we percent encode subpath (spaces) test with access key delete with space in id
267
295
  # URI.escape()
268
- separator = !['', '/'].include?(subpath) || @base_url.end_with?('/') ? '/' : ''
296
+ separator = ['', '/'].include?(subpath) ? '' : '/'
269
297
  uri = self.class.build_uri("#{@base_url}#{separator}#{subpath}", query)
270
298
  Log.log.debug{"URI=#{uri}"}
271
299
  begin
@@ -305,7 +333,7 @@ module Aspera
305
333
  # make http request (pipelined)
306
334
  http_session.request(req) do |response|
307
335
  result[:http] = response
308
- result_mime = (result[:http]['Content-Type'] || 'text/plain').split(';').first.downcase
336
+ result_mime = self.class.parse_header(result[:http]['Content-Type'] || 'text/plain')[:type]
309
337
  # JSON data needs to be parsed, in case it contains an error code
310
338
  if !save_to_file.nil? &&
311
339
  result[:http].code.to_s.start_with?('2') &&
@@ -315,8 +343,11 @@ module Aspera
315
343
  Log.log.debug('before write file')
316
344
  target_file = save_to_file
317
345
  # override user's path to path in header
318
- if !response['Content-Disposition'].nil? && (m = response['Content-Disposition'].match(/filename="([^"]+)"/))
319
- target_file = File.join(File.dirname(target_file), m[1])
346
+ if !response['Content-Disposition'].nil?
347
+ disposition = self.class.parse_header(response['Content-Disposition'])
348
+ if disposition[:parameters].key?(:filename)
349
+ target_file = File.join(File.dirname(target_file), disposition[:parameters][:filename])
350
+ end
320
351
  end
321
352
  # download with temp filename
322
353
  target_file_tmp = "#{target_file}#{@@global[:download_partial_suffix]}"
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: aspera-cli
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.18.0
4
+ version: 4.18.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Laurent Martin
@@ -37,7 +37,7 @@ cert_chain:
37
37
  eTf9kxhVM40wGQOECVNA8UsEEZHD48eF+csUYZtAJOF5oxTI8UyV9T/o6CgO0c9/
38
38
  Gzz+Qm5ULOUcPiJLjSpaiTrkiIVYiDGnqNSr6R1Hb1c=
39
39
  -----END CERTIFICATE-----
40
- date: 2024-07-10 00:00:00.000000000 Z
40
+ date: 2024-08-21 00:00:00.000000000 Z
41
41
  dependencies:
42
42
  - !ruby/object:Gem::Dependency
43
43
  name: blankslate
@@ -390,6 +390,7 @@ files:
390
390
  - README.md
391
391
  - bin/ascli
392
392
  - bin/asession
393
+ - examples/build_package.sh
393
394
  - examples/dascli
394
395
  - examples/proxy.pac
395
396
  - examples/rubyc
@@ -435,6 +436,7 @@ files:
435
436
  - lib/aspera/cli/plugins/preview.rb
436
437
  - lib/aspera/cli/plugins/server.rb
437
438
  - lib/aspera/cli/plugins/shares.rb
439
+ - lib/aspera/cli/special_values.rb
438
440
  - lib/aspera/cli/sync_actions.rb
439
441
  - lib/aspera/cli/transfer_agent.rb
440
442
  - lib/aspera/cli/transfer_progress.rb
@@ -468,7 +470,6 @@ files:
468
470
  - lib/aspera/oauth/jwt.rb
469
471
  - lib/aspera/oauth/url_json.rb
470
472
  - lib/aspera/oauth/web.rb
471
- - lib/aspera/open_application.rb
472
473
  - lib/aspera/persistency_action_once.rb
473
474
  - lib/aspera/persistency_folder.rb
474
475
  - lib/aspera/preview/file_types.rb
metadata.gz.sig CHANGED
Binary file
@@ -1,69 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'aspera/log'
4
- require 'aspera/environment'
5
- require 'rbconfig'
6
- require 'singleton'
7
-
8
- module Aspera
9
- # Allows a user to open a Url
10
- # if method is "text", then URL is displayed on terminal
11
- # if method is "graphical", then the URL will be opened with the default browser.
12
- class OpenApplication
13
- include Singleton
14
- USER_INTERFACES = %i[text graphical].freeze
15
- class << self
16
- def default_gui_mode
17
- # assume not remotely connected on macos and windows
18
- return :graphical if [Environment::OS_WINDOWS, Environment::OS_X].include?(Environment.os)
19
- # unix family
20
- return :graphical if ENV.key?('DISPLAY') && !ENV['DISPLAY'].empty?
21
- return :text
22
- end
23
-
24
- # command must be non blocking
25
- def uri_graphical(uri)
26
- case Environment.os
27
- when Environment::OS_X then return system('open', uri.to_s)
28
- when Environment::OS_WINDOWS then return system('start', 'explorer', %Q{"#{uri}"})
29
- when Environment::OS_LINUX then return system('xdg-open', uri.to_s)
30
- else
31
- raise "no graphical open method for #{Environment.os}"
32
- end
33
- end
34
-
35
- def editor(file_path)
36
- if ENV.key?('EDITOR')
37
- system(ENV['EDITOR'], file_path.to_s)
38
- elsif Environment.os.eql?(Environment::OS_WINDOWS)
39
- system('notepad.exe', %Q{"#{file_path}"})
40
- else
41
- uri_graphical(file_path.to_s)
42
- end
43
- end
44
- end
45
-
46
- attr_accessor :url_method
47
-
48
- def initialize
49
- @url_method = self.class.default_gui_mode
50
- end
51
-
52
- # this is non blocking
53
- def uri(the_url)
54
- case @url_method
55
- when :graphical
56
- self.class.uri_graphical(the_url)
57
- when :text
58
- case the_url.to_s
59
- when /^http/
60
- puts "USER ACTION: please enter this url in a browser:\n#{the_url.to_s.red}\n"
61
- else
62
- puts "USER ACTION: open this:\n#{the_url.to_s.red}\n"
63
- end
64
- else
65
- raise StandardError, "unsupported url open method: #{@url_method}"
66
- end
67
- end
68
- end
69
- end