Module: Puppet::Util::HttpProxy

Defined in:
lib/puppet/util/http_proxy.rb

Class Method Summary collapse

Class Method Details

.get_http_object(uri) ⇒ Net::HTTP::Proxy

Return a Net::HTTP::Proxy object.

This method optionally configures SSL correctly if the URI scheme is 'https', including setting up the root certificate store so remote server SSL certificates can be validated.


147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
# File 'lib/puppet/util/http_proxy.rb', line 147

def self.get_http_object(uri)
  proxy = proxy(uri)

  if uri.scheme == 'https'
    cert_store = OpenSSL::X509::Store.new
    cert_store.set_default_paths

    proxy.use_ssl = true
    proxy.verify_mode = OpenSSL::SSL::VERIFY_PEER
    proxy.cert_store = cert_store
  end

  if Puppet[:http_debug]
    proxy.set_debug_output($stderr)
  end

  proxy.open_timeout = Puppet[:http_connect_timeout]
  proxy.read_timeout = Puppet[:http_read_timeout]

  proxy
end

.http_proxy_envObject


18
19
20
21
22
23
24
25
26
27
# File 'lib/puppet/util/http_proxy.rb', line 18

def self.http_proxy_env
  # Returns a URI object if proxy is set, or nil
  proxy_env = ENV["http_proxy"] || ENV["HTTP_PROXY"]
  begin
    return URI.parse(proxy_env) if proxy_env
  rescue URI::InvalidURIError
    return nil
  end
  return nil
end

.http_proxy_hostObject


73
74
75
76
77
78
79
80
81
82
83
84
85
# File 'lib/puppet/util/http_proxy.rb', line 73

def self.http_proxy_host
  env = self.http_proxy_env

  if env and env.host
    return env.host
  end

  if Puppet.settings[:http_proxy_host] == 'none'
    return nil
  end

  return Puppet.settings[:http_proxy_host]
end

.http_proxy_passwordObject


111
112
113
114
115
116
117
118
119
120
121
122
123
# File 'lib/puppet/util/http_proxy.rb', line 111

def self.http_proxy_password
  env = self.http_proxy_env

  if env and env.password
    return env.password
  end

  if Puppet.settings[:http_proxy_user] == 'none' or Puppet.settings[:http_proxy_password] == 'none'
    return nil
  end

  return Puppet.settings[:http_proxy_password]
end

.http_proxy_portObject


87
88
89
90
91
92
93
94
95
# File 'lib/puppet/util/http_proxy.rb', line 87

def self.http_proxy_port
  env = self.http_proxy_env

  if env and env.port
    return env.port
  end

  return Puppet.settings[:http_proxy_port]
end

.http_proxy_userObject


97
98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/puppet/util/http_proxy.rb', line 97

def self.http_proxy_user
  env = self.http_proxy_env

  if env and env.user
    return env.user
  end

  if Puppet.settings[:http_proxy_user] == 'none'
    return nil
  end

  return Puppet.settings[:http_proxy_user]
end

.no_proxyObject


125
126
127
128
129
130
131
132
133
134
135
136
137
# File 'lib/puppet/util/http_proxy.rb', line 125

def self.no_proxy
  no_proxy_env = ENV["no_proxy"] || ENV["NO_PROXY"]

  if no_proxy_env
    return no_proxy_env
  end

  if Puppet.settings[:no_proxy] == 'none'
    return nil
  end

  return Puppet.settings[:no_proxy]
end

.no_proxy?(dest) ⇒ Boolean

The documentation around the format of the no_proxy variable seems inconsistent. Some suggests the use of the * as a way of matching any hosts under a domain, e.g.:

*.example.com

Other documentation suggests that just a leading '.' indicates a domain level exclusion, e.g.:

.example.com

We'll accommodate both here.


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
# File 'lib/puppet/util/http_proxy.rb', line 37

def self.no_proxy?(dest)
  no_proxy = self.no_proxy
  unless no_proxy
    return false
  end

  unless dest.is_a? URI
    begin
      dest = URI.parse(dest)
    rescue URI::InvalidURIError
      return false
    end
  end

  no_proxy.split(/\s*,\s*/).each do |d|
    host, port = d.split(':')
    host = Regexp.escape(host).gsub('\*', '.*')

    #If this no_proxy entry specifies a port, we want to match it against
    #the destination port.  Otherwise just match hosts.
    if port
      no_proxy_regex  = %r(#{host}:#{port}$)
      dest_string     = "#{dest.host}:#{dest.port}"
    else
      no_proxy_regex  = %r(#{host}$)
      dest_string     = "#{dest.host}"
    end

    if no_proxy_regex.match(dest_string)
      return true
    end
  end

  return false
end

.proxy(uri) ⇒ Object


6
7
8
9
10
11
12
13
14
15
16
# File 'lib/puppet/util/http_proxy.rb', line 6

def self.proxy(uri)
  if http_proxy_host && !no_proxy?(uri)
    Net::HTTP.new(uri.host, uri.port, self.http_proxy_host, self.http_proxy_port, self.http_proxy_user, self.http_proxy_password)
  else
    http = Net::HTTP.new(uri.host, uri.port, nil, nil, nil, nil)
    # Net::HTTP defaults the proxy port even though we said not to
    # use one. Set it to nil so caller is not surprised
    http.proxy_port = nil
    http
  end
end

.request_with_redirects(uri, method, redirect_limit = 10, &block) ⇒ Net::HTTPResponse

Retrieve a document through HTTP(s), following redirects if necessary. The returned response body may be compressed, and it is the caller's responsibility to decompress it based on the 'content-encoding' header.

Based on the the client implementation in the HTTP pool.

Raises:

  • (RedirectionLimitExceededException)

See Also:

  • Network::HTTP::Connection#request_with_redirects

181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
# File 'lib/puppet/util/http_proxy.rb', line 181

def self.request_with_redirects(uri, method, redirect_limit = 10, &block)
  current_uri = uri
  response = nil

  0.upto(redirect_limit) do |redirection|
    proxy = get_http_object(current_uri)

    headers = { 'Accept' => '*/*', 'User-Agent' => Puppet[:http_user_agent] }
    if Puppet.features.zlib?
      headers["Accept-Encoding"] = Puppet::HTTP::ACCEPT_ENCODING
    end

    response = proxy.send(:head, current_uri, headers)
    Puppet.debug("HTTP HEAD request to #{current_uri} returned #{response.code} #{response.message}")

    if [301, 302, 307].include?(response.code.to_i)
      # handle the redirection
      current_uri = URI.parse(response['location'])
      next
    end

    if method != :head
      if block_given?
        response = proxy.send("request_#{method}".to_sym, current_uri, headers, &block)
      else
        response = proxy.send(method, current_uri, headers)
      end

      Puppet.debug("HTTP #{method.to_s.upcase} request to #{current_uri} returned #{response.code} #{response.message}")
    end

    return response
  end

  raise RedirectionLimitExceededException, _("Too many HTTP redirections for %{uri}") % { uri: uri }
end