]> git.netwichtig.de Git - user/henk/code/ruby/rbot.git/blob - lib/rbot/httputil.rb
{{{httputil.rb}}} now handles redirects: a step towards #105, can be used also in...
[user/henk/code/ruby/rbot.git] / lib / rbot / httputil.rb
1 module Irc
2 module Utils
3
4 require 'resolv'
5 require 'net/http'
6 require 'net/https'
7 Net::HTTP.version_1_2
8
9 # class for making http requests easier (mainly for plugins to use)
10 # this class can check the bot proxy configuration to determine if a proxy
11 # needs to be used, which includes support for per-url proxy configuration.
12 class HttpUtil
13     BotConfig.register BotConfigBooleanValue.new('http.use_proxy',
14       :default => false, :desc => "should a proxy be used for HTTP requests?")
15     BotConfig.register BotConfigStringValue.new('http.proxy_uri', :default => false,
16       :desc => "Proxy server to use for HTTP requests (URI, e.g http://proxy.host:port)")
17     BotConfig.register BotConfigStringValue.new('http.proxy_user',
18       :default => nil,
19       :desc => "User for authenticating with the http proxy (if required)")
20     BotConfig.register BotConfigStringValue.new('http.proxy_pass',
21       :default => nil,
22       :desc => "Password for authenticating with the http proxy (if required)")
23     BotConfig.register BotConfigArrayValue.new('http.proxy_include',
24       :default => [],
25       :desc => "List of regexps to check against a URI's hostname/ip to see if we should use the proxy to access this URI. All URIs are proxied by default if the proxy is set, so this is only required to re-include URIs that might have been excluded by the exclude list. e.g. exclude /.*\.foo\.com/, include bar\.foo\.com")
26     BotConfig.register BotConfigArrayValue.new('http.proxy_exclude',
27       :default => [],
28       :desc => "List of regexps to check against a URI's hostname/ip to see if we should use avoid the proxy to access this URI and access it directly")
29     BotConfig.register BotConfigIntegerValue.new('http.max_redir',
30       :default => 5,
31       :desc => "Maximum number of redirections to be used when getting a document")
32
33   def initialize(bot)
34     @bot = bot
35     @headers = {
36       'User-Agent' => "rbot http util #{$version} (http://linuxbrit.co.uk/rbot/)",
37     }
38   end
39
40   # if http_proxy_include or http_proxy_exclude are set, then examine the
41   # uri to see if this is a proxied uri
42   # the in/excludes are a list of regexps, and each regexp is checked against
43   # the server name, and its IP addresses
44   def proxy_required(uri)
45     use_proxy = true
46     if @bot.config["http.proxy_exclude"].empty? && @bot.config["http.proxy_include"].empty?
47       return use_proxy
48     end
49
50     list = [uri.host]
51     begin
52       list.concat Resolv.getaddresses(uri.host)
53     rescue StandardError => err
54       warning "couldn't resolve host uri.host"
55     end
56
57     unless @bot.config["http.proxy_exclude"].empty?
58       re = @bot.config["http.proxy_exclude"].collect{|r| Regexp.new(r)}
59       re.each do |r|
60         list.each do |item|
61           if r.match(item)
62             use_proxy = false
63             break
64           end
65         end
66       end
67     end
68     unless @bot.config["http.proxy_include"].empty?
69       re = @bot.config["http.proxy_include"].collect{|r| Regexp.new(r)}
70       re.each do |r|
71         list.each do |item|
72           if r.match(item)
73             use_proxy = true
74             break
75           end
76         end
77       end
78     end
79     debug "using proxy for uri #{uri}?: #{use_proxy}"
80     return use_proxy
81   end
82
83   # uri:: Uri to create a proxy for
84   #
85   # return a net/http Proxy object, which is configured correctly for
86   # proxying based on the bot's proxy configuration.
87   # This will include per-url proxy configuration based on the bot config
88   # +http_proxy_include/exclude+ options.
89   def get_proxy(uri)
90     proxy = nil
91     proxy_host = nil
92     proxy_port = nil
93     proxy_user = nil
94     proxy_pass = nil
95
96     if @bot.config["http.use_proxy"]
97       if (ENV['http_proxy'])
98         proxy = URI.parse ENV['http_proxy'] rescue nil
99       end
100       if (@bot.config["http.proxy_uri"])
101         proxy = URI.parse @bot.config["http.proxy_uri"] rescue nil
102       end
103       if proxy
104         debug "proxy is set to #{proxy.host} port #{proxy.port}"
105         if proxy_required(uri)
106           proxy_host = proxy.host
107           proxy_port = proxy.port
108           proxy_user = @bot.config["http.proxy_user"]
109           proxy_pass = @bot.config["http.proxy_pass"]
110         end
111       end
112     end
113
114     h = Net::HTTP.new(uri.host, uri.port, proxy_host, proxy_port, proxy_user, proxy_port)
115     h.use_ssl = true if uri.scheme == "https"
116     return h
117   end
118
119   # uri::         uri to query (Uri object)
120   # readtimeout:: timeout for reading the response
121   # opentimeout:: timeout for opening the connection
122   #
123   # simple get request, returns response body if the status code is 200 and
124   # the request doesn't timeout.
125   def get(uri, readtimeout=10, opentimeout=5, redirs=0)
126     proxy = get_proxy(uri)
127     proxy.open_timeout = opentimeout
128     proxy.read_timeout = readtimeout
129
130     begin
131       proxy.start() {|http|
132         resp = http.get(uri.request_uri(), @headers)
133         case resp.code
134         when "200"
135           return resp.body
136         when "302"
137           debug "Redirecting #{uri} to #{resp['location']}"
138           if redirs < @bot.config["http.max_redir"]
139             return get( URI.parse(resp['location']), readtimeout, opentimeout, redirs+1 )
140           else
141             warning "Max redirection reached, not going to #{resp['location']}"
142             return nil
143           end
144         else
145           debug "HttpUtil.get return code #{resp.code} #{resp.body}"
146         end
147         return nil
148       }
149     rescue StandardError, Timeout::Error => e
150       error "HttpUtil.get exception: #{e.inspect}, while trying to get #{uri}"
151     end
152     return nil
153   end
154 end
155 end
156 end