Lines 21-33
Link Here
|
21 |
import java.io.BufferedInputStream; |
21 |
import java.io.BufferedInputStream; |
22 |
import java.io.BufferedOutputStream; |
22 |
import java.io.BufferedOutputStream; |
23 |
import java.io.DataOutputStream; |
23 |
import java.io.DataOutputStream; |
|
|
24 |
import java.io.File; |
25 |
import java.io.FileInputStream; |
26 |
import java.io.FileNotFoundException; |
24 |
import java.io.IOException; |
27 |
import java.io.IOException; |
|
|
28 |
import java.io.InputStream; |
25 |
import java.io.OutputStream; |
29 |
import java.io.OutputStream; |
26 |
import java.net.Socket; |
30 |
import java.net.Socket; |
|
|
31 |
import java.net.URL; |
27 |
import java.net.UnknownHostException; |
32 |
import java.net.UnknownHostException; |
28 |
import java.net.URL; |
33 |
import java.security.KeyStore; |
|
|
34 |
import java.util.HashMap; |
29 |
import java.util.Map; |
35 |
import java.util.Map; |
30 |
|
36 |
|
|
|
37 |
import javax.net.ssl.KeyManagerFactory; |
38 |
import javax.net.ssl.SSLContext; |
39 |
import javax.net.ssl.SSLSocket; |
40 |
import javax.net.ssl.SSLSocketFactory; |
41 |
|
31 |
import org.apache.jmeter.protocol.http.control.HeaderManager; |
42 |
import org.apache.jmeter.protocol.http.control.HeaderManager; |
32 |
import org.apache.jmeter.protocol.http.parser.HTMLParseException; |
43 |
import org.apache.jmeter.protocol.http.parser.HTMLParseException; |
33 |
import org.apache.jmeter.protocol.http.sampler.HTTPSamplerBase; |
44 |
import org.apache.jmeter.protocol.http.sampler.HTTPSamplerBase; |
Lines 64-70
Link Here
|
64 |
private static final String PROXY_HEADERS_REMOVE_DEFAULT = "If-Modified-Since,If-None-Match,Host"; // $NON-NLS-1$ |
75 |
private static final String PROXY_HEADERS_REMOVE_DEFAULT = "If-Modified-Since,If-None-Match,Host"; // $NON-NLS-1$ |
65 |
|
76 |
|
66 |
private static final String PROXY_HEADERS_REMOVE_SEPARATOR = ","; // $NON-NLS-1$ |
77 |
private static final String PROXY_HEADERS_REMOVE_SEPARATOR = ","; // $NON-NLS-1$ |
|
|
78 |
|
79 |
// for ssl connection |
80 |
private static final String KEYSTORE_INSTANCE = "PKCS12"; // $NON-NLS-1$ |
81 |
|
82 |
private static final String KEYMANAGERFACTORY_INSTANCE = "SunX509"; // $NON-NLS-1$ |
83 |
|
84 |
private static final String SSLCONTEXT_INSTANCE = "SSLv3"; // $NON-NLS-1$ |
85 |
|
86 |
// Haspmap to save ssl connection between Jmeter proxy and browser |
87 |
private static HashMap hashHost = new HashMap(); |
88 |
|
89 |
// Proxy configuration SSL |
90 |
private static String CERT_DIRECTORY = JMeterUtils.getPropDefault("proxy.cert.directory", "./"); // $NON-NLS-1$ $NON-NLS-2$ |
91 |
|
92 |
private static String CERT_FILE = JMeterUtils.getPropDefault("proxy.cert.file", "server.p12"); // $NON-NLS-1$ $NON-NLS-2$ |
93 |
|
94 |
private static char[] KEYSTORE_PASSWORD = JMeterUtils.getPropDefault("proxy.cert.keystorepass", "password").toCharArray(); // $NON-NLS-1$ $NON-NLS-2$ |
95 |
|
96 |
private static char[] KEY_PASSWORD = JMeterUtils.getPropDefault("proxy.cert.keypassword","password").toCharArray(); // $NON-NLS-1$ $NON-NLS-2$ |
67 |
|
97 |
|
|
|
98 |
// Use with SSL connection |
99 |
private OutputStream outStreamClient = null; |
100 |
|
68 |
static { |
101 |
static { |
69 |
String removeList = JMeterUtils.getPropDefault(PROXY_HEADERS_REMOVE,PROXY_HEADERS_REMOVE_DEFAULT); |
102 |
String removeList = JMeterUtils.getPropDefault(PROXY_HEADERS_REMOVE,PROXY_HEADERS_REMOVE_DEFAULT); |
70 |
headersToRemove = JOrphanUtils.split(removeList,PROXY_HEADERS_REMOVE_SEPARATOR); |
103 |
headersToRemove = JOrphanUtils.split(removeList,PROXY_HEADERS_REMOVE_SEPARATOR); |
Lines 161-169
Link Here
|
161 |
SampleResult result = null; |
194 |
SampleResult result = null; |
162 |
HeaderManager headers = null; |
195 |
HeaderManager headers = null; |
163 |
|
196 |
|
164 |
try { |
197 |
try { |
|
|
198 |
// Now, parse only first line |
165 |
request.parse(new BufferedInputStream(clientSocket.getInputStream())); |
199 |
request.parse(new BufferedInputStream(clientSocket.getInputStream())); |
166 |
|
200 |
outStreamClient = clientSocket.getOutputStream(); |
|
|
201 |
|
202 |
if ((request.getMethod().startsWith(HTTPConstants.CONNECT)) && (outStreamClient != null)) { |
203 |
log.debug("Method CONNECT => SSL"); |
204 |
// write a OK reponse to browser, to engage SSL exchange |
205 |
outStreamClient.write(("HTTP/1.0 200 OK\r\n\r\n").getBytes()); // $NON-NLS-1$ |
206 |
outStreamClient.flush(); |
207 |
// With ssl request, url is host:port (without https:// or path) |
208 |
String[] param = request.getUrl().split(":"); // $NON-NLS-1$ |
209 |
if (param.length == 2) { |
210 |
log.debug("Start to negociate SSL connection, host: " + param[0]); |
211 |
clientSocket = startSSL(clientSocket, param[0]); |
212 |
} else { |
213 |
log.warn("In SSL request, unable to find host and port in CONNECT request"); |
214 |
} |
215 |
// Re-parse (now it's the http request over SSL) |
216 |
request.parse(new BufferedInputStream(clientSocket.getInputStream())); |
217 |
} |
218 |
|
167 |
// Populate the sampler. It is the same sampler as we sent into |
219 |
// Populate the sampler. It is the same sampler as we sent into |
168 |
// the constructor of the HttpRequestHdr instance above |
220 |
// the constructor of the HttpRequestHdr instance above |
169 |
request.getSampler(pageEncodings, formEncodings); |
221 |
request.getSampler(pageEncodings, formEncodings); |
Lines 225-230
Link Here
|
225 |
"To record https requests, see " + |
277 |
"To record https requests, see " + |
226 |
"<a href=\"http://jakarta.apache.org/jmeter/usermanual/component_reference.html#HTTP_Proxy_Server\">HTTP Proxy Server documentation</a>")); |
278 |
"<a href=\"http://jakarta.apache.org/jmeter/usermanual/component_reference.html#HTTP_Proxy_Server\">HTTP Proxy Server documentation</a>")); |
227 |
result = generateErrorResult(result, e); // Generate result (if nec.) and populate it |
279 |
result = generateErrorResult(result, e); // Generate result (if nec.) and populate it |
|
|
280 |
} catch (IOException ioe) { |
281 |
log.warn("IOE, certainly during response OK to CONNECT: anti-phishing method browser (request canceled by browser)." |
282 |
+ " Please accept fake JMeter SSL cert", ioe); |
228 |
} catch (Exception e) { |
283 |
} catch (Exception e) { |
229 |
log.error("Exception when processing sample", e); |
284 |
log.error("Exception when processing sample", e); |
230 |
writeErrorToClient(HttpReplyHdr.formTimeout()); |
285 |
writeErrorToClient(HttpReplyHdr.formTimeout()); |
Lines 253-259
Link Here
|
253 |
sampler.threadFinished(); // Needed for HTTPSampler2 |
308 |
sampler.threadFinished(); // Needed for HTTPSampler2 |
254 |
} |
309 |
} |
255 |
} |
310 |
} |
|
|
311 |
|
312 |
/** |
313 |
* SSL connection hashmap |
314 |
* @param host |
315 |
* @return a ssl socket factory |
316 |
*/ |
317 |
private SSLSocketFactory getSSLSocketFactory(String host) { |
318 |
synchronized (hashHost) { |
319 |
if (hashHost.containsKey(host)) { |
320 |
log.debug("Good, already in map, host=" + host); |
321 |
return (SSLSocketFactory) hashHost.get(host); |
322 |
} |
323 |
InputStream in = getCertificat(); |
324 |
if (in != null) { |
325 |
KeyStore ks = null; |
326 |
KeyManagerFactory kmf = null; |
327 |
SSLContext sslcontext = null; |
328 |
try { |
329 |
ks = KeyStore.getInstance(KEYSTORE_INSTANCE); |
330 |
ks.load(in, KEYSTORE_PASSWORD); |
331 |
kmf = KeyManagerFactory |
332 |
.getInstance(KEYMANAGERFACTORY_INSTANCE); |
333 |
kmf.init(ks, KEY_PASSWORD); |
334 |
sslcontext = SSLContext.getInstance(SSLCONTEXT_INSTANCE); |
335 |
sslcontext.init(kmf.getKeyManagers(), null, null); |
336 |
SSLSocketFactory sslFactory = sslcontext.getSocketFactory(); |
337 |
hashHost.put(host, sslFactory); |
338 |
log.info("KeyStore for SSL load OK and put host in map ("+host+")"); |
339 |
return sslFactory; |
340 |
} catch (Exception e) { |
341 |
log.error("Exception with keystore: " + e); |
342 |
} |
343 |
} else { |
344 |
throw new NullPointerException("Unable to read keystore"); |
345 |
} |
346 |
return null; |
347 |
} |
348 |
} |
256 |
|
349 |
|
|
|
350 |
/** |
351 |
* Negociate a SSL connection |
352 |
* @param sock socket in |
353 |
* @param host |
354 |
* @return a new client socket over ssl |
355 |
* @throws Exception if negociation failed |
356 |
*/ |
357 |
private Socket startSSL(Socket sock, String host) throws Exception { |
358 |
SSLSocketFactory sslFactory = getSSLSocketFactory(host); |
359 |
SSLSocket secureSocket; |
360 |
if (sslFactory != null) { |
361 |
try { |
362 |
secureSocket = (SSLSocket) sslFactory.createSocket(sock, sock |
363 |
.getInetAddress().getHostName(), sock.getPort(), true); |
364 |
secureSocket.setUseClientMode(false); |
365 |
log.debug("SSL transaction ok with cipher: " + secureSocket.getSession().getCipherSuite()); |
366 |
return secureSocket; |
367 |
} catch (Exception e) { |
368 |
log.error("Error in SSL socket negociation: ", e); |
369 |
throw e; |
370 |
} |
371 |
} else { |
372 |
log.warn("Unable to negociate SSL transaction, no keystore"); |
373 |
throw new Exception("Unable to negociate SSL transaction, no keystore"); |
374 |
} |
375 |
} |
376 |
|
377 |
/** |
378 |
* Load (fake) cert file |
379 |
* @return stream to key cert |
380 |
*/ |
381 |
private InputStream getCertificat() { |
382 |
File certFile = new File(CERT_DIRECTORY + CERT_FILE); |
383 |
InputStream in = null; |
384 |
if (certFile.exists() && certFile.canRead()) { |
385 |
try { |
386 |
log.info("Keystore file: "+CERT_DIRECTORY+CERT_FILE); |
387 |
in = new FileInputStream(certFile); |
388 |
} catch (FileNotFoundException e) { |
389 |
log.error("No server cert file found", e); |
390 |
} |
391 |
} else { |
392 |
throw new NullPointerException("No keystore found"); |
393 |
} |
394 |
return in; |
395 |
} |
396 |
|
257 |
private SampleResult generateErrorResult(SampleResult result, Exception e) { |
397 |
private SampleResult generateErrorResult(SampleResult result, Exception e) { |
258 |
if (result == null) { |
398 |
if (result == null) { |
259 |
result = new SampleResult(); |
399 |
result = new SampleResult(); |