class Vanagon::Component::Source::Http

Constants

CHECKSUM_TYPES

Allowed checksum algorithms to use when validating files

Attributes

sum[RW]

Accessors :url, :file, :extension, :workdir, :cleanup are inherited from Local

sum_type[RW]

Accessors :url, :file, :extension, :workdir, :cleanup are inherited from Local

Public Class Methods

new(url, sum:, workdir:, sum_type:, **options) click to toggle source

Constructor for the Http source type

@param url [String] url of the http source to fetch @param sum [String] sum to verify the download against or URL to fetch

sum from

@param workdir [String] working directory to download into @param sum_type [String] type of sum we are verifying @raise [RuntimeError] an exception is raised is sum is nil

# File lib/vanagon/component/source/http.rb, line 51
def initialize(url, sum:, workdir:, sum_type:, **options)
  unless sum
    fail "sum is required to validate the http source"
  end
  unless sum_type
    fail "sum_type is required to validate the http source"
  end
  unless CHECKSUM_TYPES.include? sum_type
    fail %(checksum type "#{sum_type}" is invalid; please use #{CHECKSUM_TYPES.join(', ')})
  end

  @url = url
  @sum = sum
  @workdir = workdir
  @sum_type = sum_type

  if Vanagon::Component::Source::Http.valid_url?(@sum)
    sum_file = download(@sum)
    File.open(File.join(@workdir, sum_file)) do |file|
      # the sha1 files generated during archive creation  are formatted
      # "<sha1sum> <filename>". This will also work for sources that
      # only contain the checksum.
      remote_sum = file.read.split.first
      unless remote_sum
        fail "Downloaded checksum file seems to be empty, make sure you have the correct URL"
      end
      @sum = remote_sum
    end
  end
end
valid_url?(target_url) click to toggle source
# File lib/vanagon/component/source/http.rb, line 20
def valid_url?(target_url)
  uri = URI.parse(target_url.to_s)
  return false unless ['http', 'https'].include? uri.scheme

  Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http|
    response = http.request(Net::HTTP::Head.new(uri))
    case response
    when Net::HTTPRedirection
      # By parsing the location header, we get either an absolute
      # URI or a URI with a relative `path`. Adding it to `uri`
      # should correctly update the relative `path` or overwrite
      # the entire URI if it's absolute.
      location = URI.parse(response.header['location'])
      valid_url?(uri + location)
    when Net::HTTPSuccess
      true
    else
      false
    end
  end
end

Public Instance Methods

download(target_url, target_file = nil, headers = { "Accept-Encoding" => "identity" }) click to toggle source

Downloads the file from @url into the @workdir @param target_url [String, URI, Addressable::URI] url of an http source to retrieve with GET @raise [RuntimeError, Vanagon::Error] an exception is raised if the URI scheme cannot be handled

# File lib/vanagon/component/source/http.rb, line 106
def download(target_url, target_file = nil, headers = { "Accept-Encoding" => "identity" }) # rubocop:disable Metrics/AbcSize
  uri = URI.parse(target_url.to_s)
  target_file ||= File.basename(uri.path)

  # Add X-RPROXY-PASS to request header if the environment variable exists
  headers['X-RPROXY-PASS'] = ENV['X-RPROXY-PASS'] if ENV['X-RPROXY-PASS']

  VanagonLogger.info "Downloading file '#{target_file}' from url '#{target_url}'"

  Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http|
    http.request(Net::HTTP::Get.new(uri, headers)) do |response|
      case response
      when Net::HTTPRedirection
        # By parsing the location header, we get either an absolute
        # URI or a URI with a relative `path`. Adding it to `uri`
        # should correctly update the relative `path` or overwrite
        # the entire URI if it's absolute.
        location = URI.parse(response.header['location'])
        download(uri + location, target_file)
      when Net::HTTPSuccess
        File.open(File.join(@workdir, target_file), 'w') do |io|
          response.read_body { |chunk| io.write(chunk) }
        end
      else
        fail "Error: #{response.code.to_s}. Unable to get source from #{target_url}"
      end
    end
  end

  target_file
rescue Errno::ETIMEDOUT, Timeout::Error, Errno::EINVAL,
  Errno::EACCES, Errno::ECONNRESET, EOFError, Net::HTTPBadResponse,
  Net::HTTPHeaderSyntaxError, Net::ProtocolError => e
  raise Vanagon::Error.wrap(e, "Problem downloading #{target_file} from '#{@url}'. Please verify you have the correct uri specified.")
end
fetch() click to toggle source

Download the source from the url specified. Sets the full path to the file as @file and the @extension for the file as a side effect.

# File lib/vanagon/component/source/http.rb, line 84
def fetch
  @file = download(@url)
end
file() click to toggle source
# File lib/vanagon/component/source/http.rb, line 88
def file
  @file ||= fetch
end
verify() click to toggle source

Verify the downloaded file matches the provided sum

@raise [RuntimeError] an exception is raised if the sum does not match the sum of the file

# File lib/vanagon/component/source/http.rb, line 95
def verify
  VanagonLogger.info "Verifying file: #{file} against sum: '#{sum}'"
  actual = get_sum(File.join(workdir, file), sum_type)
  return true if sum == actual

  fail "Unable to verify '#{File.join(workdir, file)}': #{sum_type} mismatch (expected '#{sum}', got '#{actual}')"
end