Lines 19-48
Link Here
|
19 |
package org.apache.jmeter.protocol.http.proxy; |
19 |
package org.apache.jmeter.protocol.http.proxy; |
20 |
|
20 |
|
21 |
import java.io.ByteArrayOutputStream; |
21 |
import java.io.ByteArrayOutputStream; |
22 |
import java.io.File; |
|
|
23 |
import java.io.IOException; |
22 |
import java.io.IOException; |
24 |
import java.io.InputStream; |
23 |
import java.io.InputStream; |
25 |
import java.io.UnsupportedEncodingException; |
|
|
26 |
import java.net.MalformedURLException; |
27 |
import java.net.URL; |
24 |
import java.net.URL; |
28 |
import java.util.HashMap; |
25 |
import java.util.HashMap; |
29 |
import java.util.HashSet; |
|
|
30 |
import java.util.Map; |
26 |
import java.util.Map; |
31 |
import java.util.Set; |
|
|
32 |
import java.util.StringTokenizer; |
27 |
import java.util.StringTokenizer; |
33 |
|
28 |
|
34 |
import org.apache.commons.io.FileUtils; |
|
|
35 |
import org.apache.commons.lang.CharUtils; |
29 |
import org.apache.commons.lang.CharUtils; |
36 |
import org.apache.jmeter.protocol.http.config.MultipartUrlConfig; |
30 |
import org.apache.jmeter.protocol.http.config.MultipartUrlConfig; |
37 |
import org.apache.jmeter.protocol.http.control.Header; |
31 |
import org.apache.jmeter.protocol.http.control.Header; |
38 |
import org.apache.jmeter.protocol.http.control.HeaderManager; |
32 |
import org.apache.jmeter.protocol.http.control.HeaderManager; |
39 |
import org.apache.jmeter.protocol.http.control.gui.HttpTestSampleGui; |
|
|
40 |
import org.apache.jmeter.protocol.http.gui.HeaderPanel; |
33 |
import org.apache.jmeter.protocol.http.gui.HeaderPanel; |
41 |
import org.apache.jmeter.protocol.http.sampler.HTTPSamplerBase; |
34 |
import org.apache.jmeter.protocol.http.sampler.HTTPSamplerBase; |
42 |
import org.apache.jmeter.protocol.http.sampler.HTTPSamplerFactory; |
|
|
43 |
import org.apache.jmeter.protocol.http.util.ConversionUtils; |
44 |
import org.apache.jmeter.protocol.http.util.HTTPConstants; |
35 |
import org.apache.jmeter.protocol.http.util.HTTPConstants; |
45 |
import org.apache.jmeter.protocol.http.util.HTTPFileArg; |
|
|
46 |
import org.apache.jmeter.testelement.TestElement; |
36 |
import org.apache.jmeter.testelement.TestElement; |
47 |
import org.apache.jmeter.util.JMeterUtils; |
37 |
import org.apache.jmeter.util.JMeterUtils; |
48 |
import org.apache.jorphan.logging.LoggingManager; |
38 |
import org.apache.jorphan.logging.LoggingManager; |
Lines 60-91
Link Here
|
60 |
private static final String HTTP = "http"; // $NON-NLS-1$ |
50 |
private static final String HTTP = "http"; // $NON-NLS-1$ |
61 |
private static final String HTTPS = "https"; // $NON-NLS-1$ |
51 |
private static final String HTTPS = "https"; // $NON-NLS-1$ |
62 |
private static final String PROXY_CONNECTION = "proxy-connection"; // $NON-NLS-1$ |
52 |
private static final String PROXY_CONNECTION = "proxy-connection"; // $NON-NLS-1$ |
63 |
private static final String CONTENT_TYPE = "content-type"; // $NON-NLS-1$ |
53 |
public static final String CONTENT_TYPE = "content-type"; // $NON-NLS-1$ |
64 |
private static final String CONTENT_LENGTH = "content-length"; // $NON-NLS-1$ |
54 |
public static final String CONTENT_LENGTH = "content-length"; // $NON-NLS-1$ |
65 |
|
|
|
66 |
/** Filetype to be used for the temporary binary files*/ |
67 |
private static final String binaryFileSuffix = |
68 |
JMeterUtils.getPropDefault("proxy.binary.filesuffix",// $NON-NLS-1$ |
69 |
".binary"); // $NON-NLS-1$ |
70 |
|
71 |
/** Which content-types will be treated as binary (exact match) */ |
72 |
private static final Set<String> binaryContentTypes = new HashSet<String>(); |
73 |
|
55 |
|
74 |
/** Where to store the temporary binary files */ |
|
|
75 |
private static final String binaryDirectory = |
76 |
JMeterUtils.getPropDefault("proxy.binary.directory",// $NON-NLS-1$ |
77 |
System.getProperty("user.dir")); // $NON-NLS-1$ proxy.binary.filetype=binary |
78 |
|
79 |
static { |
80 |
String binaries = JMeterUtils.getPropDefault("proxy.binary.types", // $NON-NLS-1$ |
81 |
"application/x-amf,application/x-java-serialized-object"); // $NON-NLS-1$ |
82 |
if (binaries.length() > 0){ |
83 |
StringTokenizer s = new StringTokenizer(binaries,"|, ");// $NON-NLS-1$ |
84 |
while (s.hasMoreTokens()){ |
85 |
binaryContentTypes.add(s.nextToken()); |
86 |
} |
87 |
} |
88 |
} |
89 |
|
56 |
|
90 |
/** |
57 |
/** |
91 |
* Http Request method, uppercased, e.g. GET or POST. |
58 |
* Http Request method, uppercased, e.g. GET or POST. |
Lines 114-127
Link Here
|
114 |
|
81 |
|
115 |
private HeaderManager headerManager; |
82 |
private HeaderManager headerManager; |
116 |
|
83 |
|
117 |
/* |
|
|
118 |
* Optionally number the requests |
119 |
*/ |
120 |
private static final boolean numberRequests = |
121 |
JMeterUtils.getPropDefault("proxy.number.requests", false); // $NON-NLS-1$ |
122 |
|
123 |
private static volatile int requestNumber = 0;// running number |
124 |
|
125 |
public HttpRequestHdr() { |
84 |
public HttpRequestHdr() { |
126 |
this.httpSamplerName = ""; // $NON-NLS-1$ |
85 |
this.httpSamplerName = ""; // $NON-NLS-1$ |
127 |
} |
86 |
} |
Lines 251-282
Link Here
|
251 |
return headerManager; |
210 |
return headerManager; |
252 |
} |
211 |
} |
253 |
|
212 |
|
254 |
public HTTPSamplerBase getSampler(Map<String, String> pageEncodings, Map<String, String> formEncodings) |
213 |
public String getContentType() { |
255 |
throws MalformedURLException, IOException { |
|
|
256 |
// Instantiate the sampler |
257 |
HTTPSamplerBase sampler = HTTPSamplerFactory.newInstance(httpSamplerName); |
258 |
// Damn! A whole new GUI just to instantiate a test element? |
259 |
// Isn't there a beter way? |
260 |
HttpTestSampleGui tempGui = new HttpTestSampleGui(); |
261 |
|
262 |
sampler.setProperty(TestElement.GUI_CLASS, tempGui.getClass().getName()); |
263 |
|
264 |
// Populate the sampler |
265 |
populateSampler(sampler, pageEncodings, formEncodings); |
266 |
|
267 |
tempGui.configure(sampler); |
268 |
tempGui.modifyTestElement(sampler); |
269 |
// Defaults |
270 |
sampler.setFollowRedirects(false); |
271 |
sampler.setUseKeepAlive(true); |
272 |
|
273 |
if (log.isDebugEnabled()) { |
274 |
log.debug("getSampler: sampler path = " + sampler.getPath()); |
275 |
} |
276 |
return sampler; |
277 |
} |
278 |
|
279 |
private String getContentType() { |
280 |
Header contentTypeHeader = headers.get(CONTENT_TYPE); |
214 |
Header contentTypeHeader = headers.get(CONTENT_TYPE); |
281 |
if (contentTypeHeader != null) { |
215 |
if (contentTypeHeader != null) { |
282 |
return contentTypeHeader.getValue(); |
216 |
return contentTypeHeader.getValue(); |
Lines 291-297
Link Here
|
291 |
return false; |
225 |
return false; |
292 |
} |
226 |
} |
293 |
|
227 |
|
294 |
private MultipartUrlConfig getMultipartConfig(String contentType) { |
228 |
public MultipartUrlConfig getMultipartConfig(String contentType) { |
295 |
if(isMultipart(contentType)) { |
229 |
if(isMultipart(contentType)) { |
296 |
// Get the boundary string for the multiparts from the content type |
230 |
// Get the boundary string for the multiparts from the content type |
297 |
String boundaryString = contentType.substring(contentType.toLowerCase(java.util.Locale.ENGLISH).indexOf("boundary=") + "boundary=".length()); |
231 |
String boundaryString = contentType.substring(contentType.toLowerCase(java.util.Locale.ENGLISH).indexOf("boundary=") + "boundary=".length()); |
Lines 300-471
Link Here
|
300 |
return null; |
234 |
return null; |
301 |
} |
235 |
} |
302 |
|
236 |
|
303 |
private void populateSampler( |
|
|
304 |
HTTPSamplerBase sampler, |
305 |
Map<String, String> pageEncodings, Map<String, String> formEncodings) |
306 |
throws MalformedURLException, UnsupportedEncodingException { |
307 |
sampler.setDomain(serverName()); |
308 |
if (log.isDebugEnabled()) { |
309 |
log.debug("Proxy: setting server: " + sampler.getDomain()); |
310 |
} |
311 |
sampler.setMethod(method); |
312 |
log.debug("Proxy: setting method: " + sampler.getMethod()); |
313 |
sampler.setPort(serverPort()); |
314 |
if (log.isDebugEnabled()) { |
315 |
log.debug("Proxy: setting port: " + sampler.getPort()); |
316 |
} |
317 |
if (url.indexOf("//") > -1) { |
318 |
String protocol = url.substring(0, url.indexOf(":")); |
319 |
if (log.isDebugEnabled()) { |
320 |
log.debug("Proxy: setting protocol to : " + protocol); |
321 |
} |
322 |
sampler.setProtocol(protocol); |
323 |
} else if (sampler.getPort() == HTTPConstants.DEFAULT_HTTPS_PORT) { |
324 |
sampler.setProtocol(HTTPS); |
325 |
if (log.isDebugEnabled()) { |
326 |
log.debug("Proxy: setting protocol to https"); |
327 |
} |
328 |
} else { |
329 |
if (log.isDebugEnabled()) { |
330 |
log.debug("Proxy setting default protocol to: http"); |
331 |
} |
332 |
sampler.setProtocol(HTTP); |
333 |
} |
334 |
|
335 |
URL pageUrl = null; |
336 |
if(sampler.isProtocolDefaultPort()) { |
337 |
pageUrl = new URL(sampler.getProtocol(), sampler.getDomain(), getPath()); |
338 |
} |
339 |
else { |
340 |
pageUrl = new URL(sampler.getProtocol(), sampler.getDomain(), sampler.getPort(), getPath()); |
341 |
} |
342 |
String urlWithoutQuery = getUrlWithoutQuery(pageUrl); |
343 |
|
344 |
|
345 |
// Check if the request itself tells us what the encoding is |
346 |
String contentEncoding = null; |
347 |
String requestContentEncoding = ConversionUtils.getEncodingFromContentType(getContentType()); |
348 |
if(requestContentEncoding != null) { |
349 |
contentEncoding = requestContentEncoding; |
350 |
} |
351 |
else { |
352 |
// Check if we know the encoding of the page |
353 |
if (pageEncodings != null) { |
354 |
synchronized (pageEncodings) { |
355 |
contentEncoding = pageEncodings.get(urlWithoutQuery); |
356 |
} |
357 |
} |
358 |
// Check if we know the encoding of the form |
359 |
if (formEncodings != null) { |
360 |
synchronized (formEncodings) { |
361 |
String formEncoding = formEncodings.get(urlWithoutQuery); |
362 |
// Form encoding has priority over page encoding |
363 |
if (formEncoding != null) { |
364 |
contentEncoding = formEncoding; |
365 |
} |
366 |
} |
367 |
} |
368 |
} |
369 |
|
370 |
// Get the post data using the content encoding of the request |
371 |
String postData = null; |
372 |
if (log.isDebugEnabled()) { |
373 |
if(contentEncoding != null) { |
374 |
log.debug("Using encoding " + contentEncoding + " for request body"); |
375 |
} |
376 |
else { |
377 |
log.debug("No encoding found, using JRE default encoding for request body"); |
378 |
} |
379 |
} |
380 |
if (contentEncoding != null) { |
381 |
postData = new String(rawPostData, contentEncoding); |
382 |
} else { |
383 |
// Use default encoding |
384 |
postData = new String(rawPostData); |
385 |
} |
386 |
|
387 |
if(contentEncoding != null) { |
388 |
sampler.setPath(getPath(), contentEncoding); |
389 |
} |
390 |
else { |
391 |
// Although the spec says UTF-8 should be used for encoding URL parameters, |
392 |
// most browser use ISO-8859-1 for default if encoding is not known. |
393 |
// We use null for contentEncoding, then the url parameters will be added |
394 |
// with the value in the URL, and the "encode?" flag set to false |
395 |
sampler.setPath(getPath(), null); |
396 |
} |
397 |
if (log.isDebugEnabled()) { |
398 |
log.debug("Proxy: setting path: " + sampler.getPath()); |
399 |
} |
400 |
if (!HTTPConstants.CONNECT.equals(getMethod()) && numberRequests) { |
401 |
requestNumber++; |
402 |
sampler.setName(requestNumber + " " + sampler.getPath()); |
403 |
} else { |
404 |
sampler.setName(sampler.getPath()); |
405 |
} |
406 |
|
407 |
// Set the content encoding |
408 |
if(contentEncoding != null) { |
409 |
sampler.setContentEncoding(contentEncoding); |
410 |
} |
411 |
|
412 |
// If it was a HTTP GET request, then all parameters in the URL |
413 |
// has been handled by the sampler.setPath above, so we just need |
414 |
// to do parse the rest of the request if it is not a GET request |
415 |
if((!HTTPConstants.CONNECT.equals(getMethod())) && (!HTTPConstants.GET.equals(method))) { |
416 |
// Check if it was a multipart http post request |
417 |
final String contentType = getContentType(); |
418 |
MultipartUrlConfig urlConfig = getMultipartConfig(contentType); |
419 |
if (urlConfig != null) { |
420 |
urlConfig.parseArguments(postData); |
421 |
// Tell the sampler to do a multipart post |
422 |
sampler.setDoMultipartPost(true); |
423 |
// Remove the header for content-type and content-length, since |
424 |
// those values will most likely be incorrect when the sampler |
425 |
// performs the multipart request, because the boundary string |
426 |
// will change |
427 |
getHeaderManager().removeHeaderNamed(CONTENT_TYPE); |
428 |
getHeaderManager().removeHeaderNamed(CONTENT_LENGTH); |
429 |
|
430 |
// Set the form data |
431 |
sampler.setArguments(urlConfig.getArguments()); |
432 |
// Set the file uploads |
433 |
sampler.setHTTPFiles(urlConfig.getHTTPFileArgs().asArray()); |
434 |
// used when postData is pure xml (eg. an xml-rpc call) or for PUT |
435 |
} else if (postData.trim().startsWith("<?") || "PUT".equals(sampler.getMethod())) { |
436 |
sampler.addNonEncodedArgument("", postData, ""); |
437 |
} else if (contentType == null || contentType.startsWith(HTTPConstants.APPLICATION_X_WWW_FORM_URLENCODED) ){ |
438 |
// It is the most common post request, with parameter name and values |
439 |
// We also assume this if no content type is present, to be most backwards compatible, |
440 |
// but maybe we should only parse arguments if the content type is as expected |
441 |
sampler.parseArguments(postData.trim(), contentEncoding); //standard name=value postData |
442 |
} else if (postData.length() > 0) { |
443 |
if (isBinaryContent(contentType)) { |
444 |
try { |
445 |
File tempDir = new File(binaryDirectory); |
446 |
File out = File.createTempFile(method, binaryFileSuffix, tempDir); |
447 |
FileUtils.writeByteArrayToFile(out,rawPostData); |
448 |
HTTPFileArg [] files = {new HTTPFileArg(out.getPath(),"",contentType)}; |
449 |
sampler.setHTTPFiles(files); |
450 |
} catch (IOException e) { |
451 |
log.warn("Could not create binary file: "+e); |
452 |
} |
453 |
} else { |
454 |
// Just put the whole postbody as the value of a parameter |
455 |
sampler.addNonEncodedArgument("", postData, ""); //used when postData is pure xml (ex. an xml-rpc call) |
456 |
} |
457 |
} |
458 |
} |
459 |
if (log.isDebugEnabled()) { |
460 |
log.debug("sampler path = " + sampler.getPath()); |
461 |
} |
462 |
} |
463 |
|
464 |
private boolean isBinaryContent(String contentType) { |
465 |
if (contentType == null) return false; |
466 |
return binaryContentTypes.contains(contentType); |
467 |
} |
468 |
|
469 |
// |
237 |
// |
470 |
// Parsing Methods |
238 |
// Parsing Methods |
471 |
// |
239 |
// |
Lines 475-481
Link Here
|
475 |
* |
243 |
* |
476 |
* @return server's internet name |
244 |
* @return server's internet name |
477 |
*/ |
245 |
*/ |
478 |
private String serverName() { |
246 |
public String serverName() { |
479 |
// chop to "server.name:x/thing" |
247 |
// chop to "server.name:x/thing" |
480 |
String str = url; |
248 |
String str = url; |
481 |
int i = str.indexOf("//"); // $NON-NLS-1$ |
249 |
int i = str.indexOf("//"); // $NON-NLS-1$ |
Lines 506-512
Link Here
|
506 |
* |
274 |
* |
507 |
* @return server's port (or UNSPECIFIED if not found) |
275 |
* @return server's port (or UNSPECIFIED if not found) |
508 |
*/ |
276 |
*/ |
509 |
private int serverPort() { |
277 |
public int serverPort() { |
510 |
String str = url; |
278 |
String str = url; |
511 |
// chop to "server.name:x/thing" |
279 |
// chop to "server.name:x/thing" |
512 |
int i = str.indexOf("//"); |
280 |
int i = str.indexOf("//"); |
Lines 531-537
Link Here
|
531 |
* |
299 |
* |
532 |
* @return the path |
300 |
* @return the path |
533 |
*/ |
301 |
*/ |
534 |
private String getPath() { |
302 |
public String getPath() { |
535 |
String str = url; |
303 |
String str = url; |
536 |
int i = str.indexOf("//"); |
304 |
int i = str.indexOf("//"); |
537 |
if (i > 0) { |
305 |
if (i > 0) { |
Lines 595-601
Link Here
|
595 |
// return strBuff.toString(); |
363 |
// return strBuff.toString(); |
596 |
// } |
364 |
// } |
597 |
|
365 |
|
598 |
private String getUrlWithoutQuery(URL _url) { |
366 |
public String getUrlWithoutQuery(URL _url) { |
599 |
String fullUrl = _url.toString(); |
367 |
String fullUrl = _url.toString(); |
600 |
String urlWithoutQuery = fullUrl; |
368 |
String urlWithoutQuery = fullUrl; |
601 |
String query = _url.getQuery(); |
369 |
String query = _url.getQuery(); |
Lines 605-608
Link Here
|
605 |
} |
373 |
} |
606 |
return urlWithoutQuery; |
374 |
return urlWithoutQuery; |
607 |
} |
375 |
} |
|
|
376 |
|
377 |
/** |
378 |
* @return the httpSamplerName |
379 |
*/ |
380 |
public String getHttpSamplerName() { |
381 |
return httpSamplerName; |
382 |
} |
383 |
|
384 |
public byte[] getRawPostData() { |
385 |
return rawPostData; |
386 |
} |
387 |
|
388 |
public String getProtocol(HTTPSamplerBase sampler) { |
389 |
if (url.indexOf("//") > -1) { |
390 |
String protocol = url.substring(0, url.indexOf(":")); |
391 |
if (log.isDebugEnabled()) { |
392 |
log.debug("Proxy: setting protocol to : " + protocol); |
393 |
} |
394 |
return protocol; |
395 |
} else if (sampler.getPort() == HTTPConstants.DEFAULT_HTTPS_PORT) { |
396 |
if (log.isDebugEnabled()) { |
397 |
log.debug("Proxy: setting protocol to https"); |
398 |
} |
399 |
return HTTPS; |
400 |
} else { |
401 |
if (log.isDebugEnabled()) { |
402 |
log.debug("Proxy setting default protocol to: http"); |
403 |
} |
404 |
return HTTP; |
405 |
} |
406 |
} |
608 |
} |
407 |
} |