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-276
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 |
sampler.setProperty(TestElement.GUI_CLASS, HttpTestSampleGui.class.getName()); |
259 |
|
260 |
// Populate the sampler |
261 |
populateSampler(sampler, pageEncodings, formEncodings); |
262 |
|
263 |
// Defaults |
264 |
sampler.setFollowRedirects(false); |
265 |
sampler.setUseKeepAlive(true); |
266 |
|
267 |
if (log.isDebugEnabled()) { |
268 |
log.debug("getSampler: sampler path = " + sampler.getPath()); |
269 |
} |
270 |
return sampler; |
271 |
} |
272 |
|
273 |
private String getContentType() { |
274 |
Header contentTypeHeader = headers.get(CONTENT_TYPE); |
214 |
Header contentTypeHeader = headers.get(CONTENT_TYPE); |
275 |
if (contentTypeHeader != null) { |
215 |
if (contentTypeHeader != null) { |
276 |
return contentTypeHeader.getValue(); |
216 |
return contentTypeHeader.getValue(); |
Lines 285-291
Link Here
|
285 |
return false; |
225 |
return false; |
286 |
} |
226 |
} |
287 |
|
227 |
|
288 |
private MultipartUrlConfig getMultipartConfig(String contentType) { |
228 |
public MultipartUrlConfig getMultipartConfig(String contentType) { |
289 |
if(isMultipart(contentType)) { |
229 |
if(isMultipart(contentType)) { |
290 |
// Get the boundary string for the multiparts from the content type |
230 |
// Get the boundary string for the multiparts from the content type |
291 |
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 294-465
Link Here
|
294 |
return null; |
234 |
return null; |
295 |
} |
235 |
} |
296 |
|
236 |
|
297 |
private void populateSampler( |
|
|
298 |
HTTPSamplerBase sampler, |
299 |
Map<String, String> pageEncodings, Map<String, String> formEncodings) |
300 |
throws MalformedURLException, UnsupportedEncodingException { |
301 |
sampler.setDomain(serverName()); |
302 |
if (log.isDebugEnabled()) { |
303 |
log.debug("Proxy: setting server: " + sampler.getDomain()); |
304 |
} |
305 |
sampler.setMethod(method); |
306 |
log.debug("Proxy: setting method: " + sampler.getMethod()); |
307 |
sampler.setPort(serverPort()); |
308 |
if (log.isDebugEnabled()) { |
309 |
log.debug("Proxy: setting port: " + sampler.getPort()); |
310 |
} |
311 |
if (url.indexOf("//") > -1) { |
312 |
String protocol = url.substring(0, url.indexOf(":")); |
313 |
if (log.isDebugEnabled()) { |
314 |
log.debug("Proxy: setting protocol to : " + protocol); |
315 |
} |
316 |
sampler.setProtocol(protocol); |
317 |
} else if (sampler.getPort() == HTTPConstants.DEFAULT_HTTPS_PORT) { |
318 |
sampler.setProtocol(HTTPS); |
319 |
if (log.isDebugEnabled()) { |
320 |
log.debug("Proxy: setting protocol to https"); |
321 |
} |
322 |
} else { |
323 |
if (log.isDebugEnabled()) { |
324 |
log.debug("Proxy setting default protocol to: http"); |
325 |
} |
326 |
sampler.setProtocol(HTTP); |
327 |
} |
328 |
|
329 |
URL pageUrl = null; |
330 |
if(sampler.isProtocolDefaultPort()) { |
331 |
pageUrl = new URL(sampler.getProtocol(), sampler.getDomain(), getPath()); |
332 |
} |
333 |
else { |
334 |
pageUrl = new URL(sampler.getProtocol(), sampler.getDomain(), sampler.getPort(), getPath()); |
335 |
} |
336 |
String urlWithoutQuery = getUrlWithoutQuery(pageUrl); |
337 |
|
338 |
|
339 |
// Check if the request itself tells us what the encoding is |
340 |
String contentEncoding = null; |
341 |
String requestContentEncoding = ConversionUtils.getEncodingFromContentType(getContentType()); |
342 |
if(requestContentEncoding != null) { |
343 |
contentEncoding = requestContentEncoding; |
344 |
} |
345 |
else { |
346 |
// Check if we know the encoding of the page |
347 |
if (pageEncodings != null) { |
348 |
synchronized (pageEncodings) { |
349 |
contentEncoding = pageEncodings.get(urlWithoutQuery); |
350 |
} |
351 |
} |
352 |
// Check if we know the encoding of the form |
353 |
if (formEncodings != null) { |
354 |
synchronized (formEncodings) { |
355 |
String formEncoding = formEncodings.get(urlWithoutQuery); |
356 |
// Form encoding has priority over page encoding |
357 |
if (formEncoding != null) { |
358 |
contentEncoding = formEncoding; |
359 |
} |
360 |
} |
361 |
} |
362 |
} |
363 |
|
364 |
// Get the post data using the content encoding of the request |
365 |
String postData = null; |
366 |
if (log.isDebugEnabled()) { |
367 |
if(contentEncoding != null) { |
368 |
log.debug("Using encoding " + contentEncoding + " for request body"); |
369 |
} |
370 |
else { |
371 |
log.debug("No encoding found, using JRE default encoding for request body"); |
372 |
} |
373 |
} |
374 |
if (contentEncoding != null) { |
375 |
postData = new String(rawPostData, contentEncoding); |
376 |
} else { |
377 |
// Use default encoding |
378 |
postData = new String(rawPostData); |
379 |
} |
380 |
|
381 |
if(contentEncoding != null) { |
382 |
sampler.setPath(getPath(), contentEncoding); |
383 |
} |
384 |
else { |
385 |
// Although the spec says UTF-8 should be used for encoding URL parameters, |
386 |
// most browser use ISO-8859-1 for default if encoding is not known. |
387 |
// We use null for contentEncoding, then the url parameters will be added |
388 |
// with the value in the URL, and the "encode?" flag set to false |
389 |
sampler.setPath(getPath(), null); |
390 |
} |
391 |
if (log.isDebugEnabled()) { |
392 |
log.debug("Proxy: setting path: " + sampler.getPath()); |
393 |
} |
394 |
if (!HTTPConstants.CONNECT.equals(getMethod()) && numberRequests) { |
395 |
requestNumber++; |
396 |
sampler.setName(requestNumber + " " + sampler.getPath()); |
397 |
} else { |
398 |
sampler.setName(sampler.getPath()); |
399 |
} |
400 |
|
401 |
// Set the content encoding |
402 |
if(contentEncoding != null) { |
403 |
sampler.setContentEncoding(contentEncoding); |
404 |
} |
405 |
|
406 |
// If it was a HTTP GET request, then all parameters in the URL |
407 |
// has been handled by the sampler.setPath above, so we just need |
408 |
// to do parse the rest of the request if it is not a GET request |
409 |
if((!HTTPConstants.CONNECT.equals(getMethod())) && (!HTTPConstants.GET.equals(method))) { |
410 |
// Check if it was a multipart http post request |
411 |
final String contentType = getContentType(); |
412 |
MultipartUrlConfig urlConfig = getMultipartConfig(contentType); |
413 |
if (urlConfig != null) { |
414 |
urlConfig.parseArguments(postData); |
415 |
// Tell the sampler to do a multipart post |
416 |
sampler.setDoMultipartPost(true); |
417 |
// Remove the header for content-type and content-length, since |
418 |
// those values will most likely be incorrect when the sampler |
419 |
// performs the multipart request, because the boundary string |
420 |
// will change |
421 |
getHeaderManager().removeHeaderNamed(CONTENT_TYPE); |
422 |
getHeaderManager().removeHeaderNamed(CONTENT_LENGTH); |
423 |
|
424 |
// Set the form data |
425 |
sampler.setArguments(urlConfig.getArguments()); |
426 |
// Set the file uploads |
427 |
sampler.setHTTPFiles(urlConfig.getHTTPFileArgs().asArray()); |
428 |
// used when postData is pure xml (eg. an xml-rpc call) or for PUT |
429 |
} else if (postData.trim().startsWith("<?") || "PUT".equals(sampler.getMethod())) { |
430 |
sampler.addNonEncodedArgument("", postData, ""); |
431 |
} else if (contentType == null || contentType.startsWith(HTTPConstants.APPLICATION_X_WWW_FORM_URLENCODED) ){ |
432 |
// It is the most common post request, with parameter name and values |
433 |
// We also assume this if no content type is present, to be most backwards compatible, |
434 |
// but maybe we should only parse arguments if the content type is as expected |
435 |
sampler.parseArguments(postData.trim(), contentEncoding); //standard name=value postData |
436 |
} else if (postData.length() > 0) { |
437 |
if (isBinaryContent(contentType)) { |
438 |
try { |
439 |
File tempDir = new File(binaryDirectory); |
440 |
File out = File.createTempFile(method, binaryFileSuffix, tempDir); |
441 |
FileUtils.writeByteArrayToFile(out,rawPostData); |
442 |
HTTPFileArg [] files = {new HTTPFileArg(out.getPath(),"",contentType)}; |
443 |
sampler.setHTTPFiles(files); |
444 |
} catch (IOException e) { |
445 |
log.warn("Could not create binary file: "+e); |
446 |
} |
447 |
} else { |
448 |
// Just put the whole postbody as the value of a parameter |
449 |
sampler.addNonEncodedArgument("", postData, ""); //used when postData is pure xml (ex. an xml-rpc call) |
450 |
} |
451 |
} |
452 |
} |
453 |
if (log.isDebugEnabled()) { |
454 |
log.debug("sampler path = " + sampler.getPath()); |
455 |
} |
456 |
} |
457 |
|
458 |
private boolean isBinaryContent(String contentType) { |
459 |
if (contentType == null) return false; |
460 |
return binaryContentTypes.contains(contentType); |
461 |
} |
462 |
|
463 |
// |
237 |
// |
464 |
// Parsing Methods |
238 |
// Parsing Methods |
465 |
// |
239 |
// |
Lines 469-475
Link Here
|
469 |
* |
243 |
* |
470 |
* @return server's internet name |
244 |
* @return server's internet name |
471 |
*/ |
245 |
*/ |
472 |
private String serverName() { |
246 |
public String serverName() { |
473 |
// chop to "server.name:x/thing" |
247 |
// chop to "server.name:x/thing" |
474 |
String str = url; |
248 |
String str = url; |
475 |
int i = str.indexOf("//"); // $NON-NLS-1$ |
249 |
int i = str.indexOf("//"); // $NON-NLS-1$ |
Lines 500-506
Link Here
|
500 |
* |
274 |
* |
501 |
* @return server's port (or UNSPECIFIED if not found) |
275 |
* @return server's port (or UNSPECIFIED if not found) |
502 |
*/ |
276 |
*/ |
503 |
private int serverPort() { |
277 |
public int serverPort() { |
504 |
String str = url; |
278 |
String str = url; |
505 |
// chop to "server.name:x/thing" |
279 |
// chop to "server.name:x/thing" |
506 |
int i = str.indexOf("//"); |
280 |
int i = str.indexOf("//"); |
Lines 525-531
Link Here
|
525 |
* |
299 |
* |
526 |
* @return the path |
300 |
* @return the path |
527 |
*/ |
301 |
*/ |
528 |
private String getPath() { |
302 |
public String getPath() { |
529 |
String str = url; |
303 |
String str = url; |
530 |
int i = str.indexOf("//"); |
304 |
int i = str.indexOf("//"); |
531 |
if (i > 0) { |
305 |
if (i > 0) { |
Lines 589-595
Link Here
|
589 |
// return strBuff.toString(); |
363 |
// return strBuff.toString(); |
590 |
// } |
364 |
// } |
591 |
|
365 |
|
592 |
private String getUrlWithoutQuery(URL _url) { |
366 |
public String getUrlWithoutQuery(URL _url) { |
593 |
String fullUrl = _url.toString(); |
367 |
String fullUrl = _url.toString(); |
594 |
String urlWithoutQuery = fullUrl; |
368 |
String urlWithoutQuery = fullUrl; |
595 |
String query = _url.getQuery(); |
369 |
String query = _url.getQuery(); |
Lines 599-602
Link Here
|
599 |
} |
373 |
} |
600 |
return urlWithoutQuery; |
374 |
return urlWithoutQuery; |
601 |
} |
375 |
} |
|
|
376 |
|
377 |
/** |
378 |
* @return the httpSamplerName |
379 |
*/ |
380 |
public String getHttpSamplerName() { |
381 |
return httpSamplerName; |
382 |
} |
383 |
|
384 |
/** |
385 |
* @return byte[] Raw post data |
386 |
*/ |
387 |
public byte[] getRawPostData() { |
388 |
return rawPostData; |
389 |
} |
390 |
|
391 |
/** |
392 |
* @param sampler {@link HTTPSamplerBase} |
393 |
* @return String Protocol (http or https) |
394 |
*/ |
395 |
public String getProtocol(HTTPSamplerBase sampler) { |
396 |
if (url.indexOf("//") > -1) { |
397 |
String protocol = url.substring(0, url.indexOf(":")); |
398 |
if (log.isDebugEnabled()) { |
399 |
log.debug("Proxy: setting protocol to : " + protocol); |
400 |
} |
401 |
return protocol; |
402 |
} else if (sampler.getPort() == HTTPConstants.DEFAULT_HTTPS_PORT) { |
403 |
if (log.isDebugEnabled()) { |
404 |
log.debug("Proxy: setting protocol to https"); |
405 |
} |
406 |
return HTTPS; |
407 |
} else { |
408 |
if (log.isDebugEnabled()) { |
409 |
log.debug("Proxy setting default protocol to: http"); |
410 |
} |
411 |
return HTTP; |
412 |
} |
413 |
} |
602 |
} |
414 |
} |