Class: HTTPDisk::Cli

Inherits:
Object
  • Object
show all
Defined in:
lib/httpdisk/cli.rb

Overview

Command line httpdisk command.

Constant Summary collapse

UNITS =

for –expires

{
  s: 1,
  m: 60,
  h: 60 * 60,
  d: 24 * 60 * 60,
  w: 7 * 24 * 60 * 60,
  y: 365 * 7 * 24 * 60 * 60,
}.freeze
RETRY_OPTIONS =

we have a very liberal retry policy

{
  methods: %w[delete get head options patch post put trace],
  retry_statuses: (400..600).to_a,
  retry_if: ->(_env, _err) { true },
}.freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options) ⇒ Cli

Returns a new instance of Cli.



20
21
22
# File 'lib/httpdisk/cli.rb', line 20

def initialize(options)
  @options = options
end

Instance Attribute Details

#optionsObject (readonly)

Returns the value of attribute options.



8
9
10
# File 'lib/httpdisk/cli.rb', line 8

def options
  @options
end

Instance Method Details

#client_optionsObject

Options to HTTPDisk::Client



170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
# File 'lib/httpdisk/cli.rb', line 170

def client_options
  {}.tap do |client_options|
    client_options[:dir] = options[:dir]
    if options[:expires]
      seconds = parse_expires(options[:expires])
      if !seconds
        raise CliError, "invalid --expires #{options[:expires].inspect}"
      end

      client_options[:expires_in] = seconds
    end
    client_options[:force] = options[:force]
    client_options[:force_errors] = options[:force_errors]
  end
end

#create_faradayObject



56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# File 'lib/httpdisk/cli.rb', line 56

def create_faraday
  Faraday.new do
    # connection settings
    _1.proxy = proxy if options[:proxy]
    _1.options.timeout = options[:max_time] if options[:max_time]

    # cookie middleware
    _1.use :cookie_jar

    # BEFORE httpdisk so each redirect segment is cached
    _1.response :follow_redirects

    # httpdisk
    _1.use :httpdisk, client_options

    # AFTER httpdisk so transient failures are not cached
    if options[:retry]
      _1.request :retry, RETRY_OPTIONS.merge(max: options[:retry])
    end
  end
end

#output(response, f) ⇒ Object

Output response to f



96
97
98
99
100
101
102
103
# File 'lib/httpdisk/cli.rb', line 96

def output(response, f)
  if options[:include]
    f.puts "HTTPDISK #{response.status} #{response.reason_phrase}"
    response.headers.each { f.puts("#{_1}: #{_2}") }
    f.puts
  end
  f.write(response.body)
end

#parse_expires(s) ⇒ Object

Parse –expires flag



197
198
199
200
201
202
203
204
205
# File 'lib/httpdisk/cli.rb', line 197

def parse_expires(s)
  m = s.match(/^(\d+)([smhdwy])?$/)
  return if !m

  num, unit = m[1].to_i, (m[2] || 's').to_sym
  return if !UNITS.key?(unit)

  num * UNITS[unit]
end

#parse_proxy(proxy_flag) ⇒ Object

Parse –proxy flag



208
209
210
211
212
213
214
215
216
217
218
219
220
221
# File 'lib/httpdisk/cli.rb', line 208

def parse_proxy(proxy_flag)
  host, port = proxy_flag.split(':', 2)
  return if !host || host.empty?
  return if port&.empty?

  URI.parse('http://placeholder').tap do
    begin
      _1.host = host
      _1.port = port if port
    rescue URI::InvalidComponentError
      return
    end
  end.to_s
end

#proxyObject

Return validated –proxy flag if present

Raises:



187
188
189
190
191
192
193
194
# File 'lib/httpdisk/cli.rb', line 187

def proxy
  return if !options[:proxy]

  proxy = parse_proxy(options[:proxy])
  raise CliError, "--proxy should be host[:port], not #{options[:proxy].inspect}" if !proxy

  proxy
end

#request_bodyObject

Request body



143
144
145
# File 'lib/httpdisk/cli.rb', line 143

def request_body
  options[:data]
end

#request_headersObject

Request headers



148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
# File 'lib/httpdisk/cli.rb', line 148

def request_headers
  {}.tap do |headers|
    if options[:user_agent]
      headers['User-Agent'] = options[:user_agent]
    end

    options[:header].each do |header|
      key, value = header.split(': ', 2)
      if !key || !value || key.empty? || value.empty?
        raise CliError, "invalid --header #{header.inspect}"
      end

      headers[key] = value
    end
  end
end

#request_methodObject

HTTP method (get, post, etc.)



110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# File 'lib/httpdisk/cli.rb', line 110

def request_method
  method = if options[:request]
    options[:request]
  elsif options[:data]
    'post'
  end
  method ||= 'get'
  method = method.downcase.to_sym

  if !Faraday::Connection::METHODS.include?(method)
    raise CliError, "invalid --request #{method.inspect}"
  end

  method
end

#request_urlObject

Request url



127
128
129
130
131
132
133
134
135
136
137
138
139
140
# File 'lib/httpdisk/cli.rb', line 127

def request_url
  url = options[:url]
  # recover from missing http:
  if url !~ %r{^https?://}i
    if url =~ %r{^\w+://}
      raise CliError, 'only http/https supported'
    end

    url = "http://#{url}"
  end
  URI.parse(url)
rescue URI::InvalidURIError
  raise CliError, "invalid url #{url.inspect}"
end

#runObject

Make the request (or print status)



32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/httpdisk/cli.rb', line 32

def run
  # short circuit --status
  if options[:status]
    status
    return
  end

  # create Faraday client
  faraday = create_faraday

  # run request
  response = faraday.run_request(request_method, request_url, request_body, request_headers)
  if response.status >= 400
    raise CliError, "the requested URL returned error: #{response.status} #{response.reason_phrase}"
  end

  # output
  if options[:output]
    File.open(options[:output], 'w') { output(response, _1) }
  else
    output(response, $stdout)
  end
end

#statusObject

Support for –status



79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/httpdisk/cli.rb', line 79

def status
  # build env
  env = Faraday::Env.new.tap do
    _1.method = request_method
    _1.request_body = request_body
    _1.request_headers = request_headers
    _1.url = request_url
  end

  # now print status
  client = HTTPDisk::Client.new(nil, client_options)
  client.status(env).each do
    puts "#{_1}: #{_2.inspect}"
  end
end