Class: Vagrant::Downloaders::HTTP

Inherits:
Base
  • Object
show all
Defined in:
lib/vagrant/downloaders/http.rb

Overview

Downloads a file from an HTTP URL to a temporary file. This downloader reports its progress to stdout while downloading.

Class Method Summary (collapse)

Instance Method Summary (collapse)

Methods inherited from Base

#initialize

Constructor Details

This class inherits a constructor from Vagrant::Downloaders::Base

Class Method Details

+ (Boolean) match?(uri)

Returns:

  • (Boolean)


11
12
13
14
15
# File 'lib/vagrant/downloaders/http.rb', line 11

def self.match?(uri)
  # URI.parse barfs on '<drive letter>:\\files \on\ windows'
  extracted = URI.extract(uri, ['http', 'https']).first
  extracted && extracted.include?(uri)
end

Instance Method Details

- (Object) download!(source_url, destination_file)



17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/vagrant/downloaders/http.rb', line 17

def download!(source_url, destination_file)
  uri = URI.parse(source_url)
  proxy_uri = resolve_proxy(uri)

  http = Net::HTTP.new(uri.host, uri.port, proxy_uri.host, proxy_uri.port, proxy_uri.user, proxy_uri.password)
  http.read_timeout = nil # Disable the read timeout, just let it try to download

  if uri.scheme == "https"
    http.use_ssl = true
    http.verify_mode = OpenSSL::SSL::VERIFY_NONE
  end

  http.start do |h|
    @ui.info I18n.t("vagrant.downloaders.http.download", :url => source_url)

    headers = nil
    if uri.user && uri.password
      headers = {'Authorization' => 'Basic ' + Base64.encode64(uri.user + ':' + uri.password)}
    end

    h.request_get(uri.request_uri, headers) do |response|
      if response.is_a?(Net::HTTPRedirection)
        # Follow the HTTP redirect.
        # TODO: Error on some redirect limit
        download!(response["Location"], destination_file)
        return
      elsif !response.is_a?(Net::HTTPOK)
        raise Errors::DownloaderHTTPStatusError, :status => response.code
      end

      total = response.content_length
      progress = 0
      segment_count = 0

      response.read_body do |segment|
        # Report the progress out
        progress += segment.length
        segment_count += 1

        # Progress reporting is limited to every 25 segments just so
        # we're not constantly updating
        if segment_count % 25 == 0
          @ui.clear_line
          @ui.report_progress(progress, total)
          segment_count = 0
        end

        # Store the segment
        destination_file.write(segment)
      end

      # Clear the line one last time so that the progress meter disappears
      @ui.clear_line
    end
  end
rescue Errno::ECONNRESET
  raise Errors::DownloaderHTTPConnectReset
rescue Errno::ETIMEDOUT
  raise Errors::DownloaderHTTPConnectTimeout
rescue SocketError
  raise Errors::DownloaderHTTPSocketError
end