summaryrefslogtreecommitdiffstats
path: root/src/main/java/com/btr/proxy/search/browser/ie/IEProxySearchStrategy.java
blob: 6641aff78490b02d84be30f198ea01b7ab902230 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
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
package com.btr.proxy.search.browser.ie;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.net.Proxy;
import java.net.ProxySelector;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

import com.btr.proxy.search.ProxySearchStrategy;
import com.btr.proxy.search.desktop.win.Win32IESettings;
import com.btr.proxy.search.desktop.win.Win32ProxyUtils;
import com.btr.proxy.selector.fixed.FixedProxySelector;
import com.btr.proxy.selector.misc.ProtocolDispatchSelector;
import com.btr.proxy.selector.pac.PacProxySelector;
import com.btr.proxy.selector.whitelist.ProxyBypassListSelector;
import com.btr.proxy.util.Logger;
import com.btr.proxy.util.Logger.LogLevel;
import com.btr.proxy.util.ProxyException;
import com.btr.proxy.util.ProxyUtil;
import com.btr.proxy.util.UriFilter;

/*****************************************************************************
 * Extracts the proxy settings for Microsoft Internet Explorer.
 * The settings are read by invoking native Windows API methods.  
 *
 * @author Bernd Rosstauscher (proxyvole@rosstauscher.de) Copyright 2009
 ****************************************************************************/

public class IEProxySearchStrategy implements ProxySearchStrategy {

	/*************************************************************************
	 * getProxySelector
	 * @see com.btr.proxy.search.ProxySearchStrategy#getProxySelector()
	 ************************************************************************/

	public ProxySelector getProxySelector() throws ProxyException {
		
		Logger.log(getClass(), LogLevel.TRACE, "Detecting IE proxy settings");
		
		Win32IESettings ieSettings = readSettings();
		
		ProxySelector result = createPacSelector(ieSettings);
		if (result == null) {
			result = createFixedProxySelector(ieSettings);
		}
		return result;
	}

	/*************************************************************************
	 * Loads the settings from the windows registry.
	 * @return WinIESettings containing all proxy settings.
	 ************************************************************************/
	
	public Win32IESettings readSettings() {
		Win32IESettings ieSettings = new Win32ProxyUtils().winHttpGetIEProxyConfigForCurrentUser();
		return ieSettings;
	}

	/*************************************************************************
	 * Parses the settings and creates an PAC ProxySelector for it.
	 * @param ieSettings the IE settings to use.
	 * @return a PacProxySelector the selector or null.
	 ************************************************************************/
	
	private PacProxySelector createPacSelector(Win32IESettings ieSettings) {
		String pacUrl = null;

		if (ieSettings.isAutoDetect()) {
			Logger.log(getClass(), LogLevel.TRACE, "Autodetecting script URL.");
			// This will take some time.
			pacUrl = new Win32ProxyUtils().winHttpDetectAutoProxyConfigUrl(
					Win32ProxyUtils.WINHTTP_AUTO_DETECT_TYPE_DHCP+
					Win32ProxyUtils.WINHTTP_AUTO_DETECT_TYPE_DNS_A);
		}
		if (pacUrl == null) {
			pacUrl = ieSettings.getAutoConfigUrl();
		}
		if (pacUrl != null && pacUrl.trim().length() > 0) {
			Logger.log(getClass(), LogLevel.TRACE, "IE uses script: "+pacUrl);
		     
			// Fix for issue 9
			// If the IE has a file URL and it only starts has 2 slashes, 
			// add a third so it can be properly converted to the URL class
		    if (pacUrl.startsWith("file://") && !pacUrl.startsWith("file:///")) {
		    	pacUrl = "file:///" + pacUrl.substring(7);
		    }
			return ProxyUtil.buildPacSelectorForUrl(pacUrl);
		}
		
		return null;
	}

	/*************************************************************************
	 * Parses the proxy settings into an ProxySelector.
	 * @param ieSettings the settings to use.
	 * @return a ProxySelector, null if no settings are set.
	 * @throws ProxyException on error.
	 ************************************************************************/
	
	private ProxySelector createFixedProxySelector(Win32IESettings ieSettings) throws ProxyException {
		String proxyString = ieSettings.getProxy();
		String bypassList = ieSettings.getProxyBypass();
		if (proxyString == null) {
			return null;
		}
		Logger.log(getClass(), LogLevel.TRACE, 
				"IE uses manual settings: {0} with bypass list: {1}", proxyString, bypassList);
		
		Properties p = parseProxyList(proxyString);
		
		ProtocolDispatchSelector ps = new ProtocolDispatchSelector();
		addSelectorForProtocol(p, "http", ps);
		addSelectorForProtocol(p, "https", ps);
		addSelectorForProtocol(p, "ftp", ps);
		addSelectorForProtocol(p, "gopher", ps);
		addSelectorForProtocol(p, "socks", ps);
		addFallbackSelector(p, ps);

		ProxySelector result = setByPassListOnSelector(bypassList, ps);
		return result;
	}

	/*************************************************************************
	 * @param bypassList
	 * @param ps
	 * @return 
	 ************************************************************************/
	
	private ProxySelector setByPassListOnSelector(String bypassList,
			ProtocolDispatchSelector ps) {
		if (bypassList != null && bypassList.trim().length() > 0) {
			ProxyBypassListSelector result; 
			if ("<local>".equals(bypassList.trim())) {
				result = buildLocalBypassSelector(ps);
			} else {
				bypassList = bypassList.replace(';', ',');
				result = new ProxyBypassListSelector(bypassList, ps);
			}
			return result;
		}
		return ps;
	}

	/*************************************************************************
	 * @param ps
	 * @return
	 ************************************************************************/
	
	private ProxyBypassListSelector buildLocalBypassSelector(
			ProtocolDispatchSelector ps) {
		List<UriFilter> localBypassFilter = new ArrayList<UriFilter>();
		localBypassFilter.add(new IELocalByPassFilter());
		return new ProxyBypassListSelector(localBypassFilter, ps);
	}

	/*************************************************************************
	 * Installs a fallback selector that is used whenever no protocol specific
	 * selector is defined.
	 * @param settings to take the proxy settings from.
	 * @param ps to install the created selector on.
	 ************************************************************************/
	
	private void addFallbackSelector(Properties settings, ProtocolDispatchSelector ps) {
		String proxy = settings.getProperty("default");
		if (proxy != null) {
			ps.setFallbackSelector(ProxyUtil.parseProxySettings(proxy));
		}
	}

	/*************************************************************************
	 * Creates a selector for a given protocol. The proxy will be taken
	 * from the settings and installed on the dispatch selector.
	 * @param settings to take the proxy settings from.
	 * @param protocol to create a selector for.
	 * @param ps to install the created selector on.
	 ************************************************************************/
	
	private void addSelectorForProtocol(Properties settings, String protocol, ProtocolDispatchSelector ps) {
		String proxy = settings.getProperty(protocol);
		if (proxy != null) {
			Proxy.Type fb = protocol.startsWith("socks") ? Proxy.Type.SOCKS : Proxy.Type.HTTP;
			ProxySelector protocolSelector = ProxyUtil.parseProxySettings(proxy, fb, 0);
			ps.setSelector(protocol, protocolSelector);
		}
	}

	/*************************************************************************
	 * Parses the proxy list and splits it by protocol.
	 * @param proxyString the proxy list string
	 * @return Properties with separated settings.
	 * @throws ProxyException on parse error.
	 ************************************************************************/
	
	private Properties parseProxyList(String proxyString) throws ProxyException {
		Properties p = new Properties();
		if (proxyString.indexOf('=') == -1) {
			p.setProperty("default", proxyString);
		} else {
			try {
				proxyString = proxyString.replace(';', '\n');
				p.load(new ByteArrayInputStream(proxyString.getBytes("ISO-8859-1")));
			} catch (IOException e) {
				Logger.log(getClass(), LogLevel.ERROR, 
						"Error reading IE settings as properties: {0}", e);
	
				throw new ProxyException(e);
			}
		}
		return p;
	}

}