📄 proxy.java
字号:
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.jmeter.protocol.http.proxy;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
import java.net.URL;
import java.util.Map;
import org.apache.jmeter.protocol.http.control.HeaderManager;
import org.apache.jmeter.protocol.http.parser.HTMLParseException;
import org.apache.jmeter.protocol.http.sampler.HTTPSamplerBase;
import org.apache.jmeter.protocol.http.sampler.HTTPSamplerFactory;
import org.apache.jmeter.protocol.http.util.HTTPConstants;
import org.apache.jmeter.samplers.SampleResult;
import org.apache.jmeter.testelement.TestElement;
import org.apache.jmeter.util.JMeterUtils;
import org.apache.jorphan.logging.LoggingManager;
import org.apache.jorphan.util.JOrphanUtils;
import org.apache.log.Logger;
/**
* Thread to handle one client request. Gets the request from the client and
* passes it on to the server, then sends the response back to the client.
* Information about the request and response is stored so it can be used in a
* JMeter test plan.
*
*/
public class Proxy extends Thread {
private static final Logger log = LoggingManager.getLoggerForClass();
private static final String NEW_LINE = "\n"; // $NON-NLS-1$
private static final String[] headersToRemove;
// Allow list of headers to be overridden
private static final String PROXY_HEADERS_REMOVE = "proxy.headers.remove"; // $NON-NLS-1$
private static final String PROXY_HEADERS_REMOVE_DEFAULT = "If-Modified-Since,If-None-Match"; // $NON-NLS-1$
private static final String PROXY_HEADERS_REMOVE_SEPARATOR = ","; // $NON-NLS-1$
static {
String removeList = JMeterUtils.getPropDefault(PROXY_HEADERS_REMOVE,PROXY_HEADERS_REMOVE_DEFAULT);
headersToRemove = JOrphanUtils.split(removeList,PROXY_HEADERS_REMOVE_SEPARATOR);
log.info("Proxy will remove the headers: "+removeList);
}
/** Socket to client. */
private Socket clientSocket = null;
/** Target to receive the generated sampler. */
private ProxyControl target;
/** Whether or not to capture the HTTP headers. */
private boolean captureHttpHeaders;
/** Whether to try to spoof as https **/
private boolean httpsSpoof;
private String httpsSpoofMatch; // if non-empty, then URLs must match in order to be spoofed
/** Reference to Deamon's Map of url string to page character encoding of that page */
private Map pageEncodings;
/** Reference to Deamon's Map of url string to character encoding for the form */
private Map formEncodings;
/**
* Default constructor - used by newInstance call in Daemon
*/
public Proxy() {
}
/**
* Create and configure a new Proxy object.
*
* @param clientSocket
* the socket connection to the client
* @param target
* the ProxyControl which will receive the generated sampler
*/
Proxy(Socket clientSocket, ProxyControl target) {
configure(clientSocket, target);
}
/**
* Configure the Proxy.
*
* @param clientSocket
* the socket connection to the client
* @param target
* the ProxyControl which will receive the generated sampler
*/
void configure(Socket _clientSocket, ProxyControl _target) {
configure(_clientSocket, _target, null, null);
}
/**
* Configure the Proxy.
*
* @param _clientSocket
* the socket connection to the client
* @param _target
* the ProxyControl which will receive the generated sampler
* @param _pageEncodings
* reference to the Map of Deamon, with mappings from page urls to encoding used
* @param formEncodingsEncodings
* reference to the Map of Deamon, with mappings from form action urls to encoding used
*/
void configure(Socket _clientSocket, ProxyControl _target, Map _pageEncodings, Map _formEncodings) {
this.target = _target;
this.clientSocket = _clientSocket;
this.captureHttpHeaders = _target.getCaptureHttpHeaders();
this.httpsSpoof = _target.getHttpsSpoof();
this.httpsSpoofMatch = _target.getHttpsSpoofMatch();
this.pageEncodings = _pageEncodings;
this.formEncodings = _formEncodings;
}
/**
* Main processing method for the Proxy object
*/
public void run() {
// Check which HTTPSampler class we should use
String httpSamplerName = HTTPSamplerFactory.DEFAULT_CLASSNAME;
if(target.getSamplerTypeName() == ProxyControl.SAMPLER_TYPE_HTTP_SAMPLER) {
httpSamplerName = HTTPSamplerFactory.HTTP_SAMPLER_JAVA;
}
else if(target.getSamplerTypeName() == ProxyControl.SAMPLER_TYPE_HTTP_SAMPLER2) {
httpSamplerName = HTTPSamplerFactory.HTTP_SAMPLER_APACHE;
}
// Instantiate the sampler
HTTPSamplerBase sampler = HTTPSamplerFactory.newInstance(httpSamplerName);
HttpRequestHdr request = new HttpRequestHdr(sampler);
SampleResult result = null;
HeaderManager headers = null;
try {
request.parse(new BufferedInputStream(clientSocket.getInputStream()));
// Populate the sampler. It is the same sampler as we sent into
// the constructor of the HttpRequestHdr instance above
request.getSampler(pageEncodings, formEncodings);
/*
* Create a Header Manager to ensure that the browsers headers are
* captured and sent to the server
*/
headers = request.getHeaderManager();
sampler.setHeaderManager(headers);
/*
* If we are trying to spoof https, change the protocol
*/
boolean forcedHTTP = false; // so we know when to revert
if (httpsSpoof) {
if (httpsSpoofMatch.length() > 0){
String url = request.getUrl();
if (url.matches(httpsSpoofMatch)){
sampler.setProtocol(HTTPConstants.PROTOCOL_HTTPS);
forcedHTTP = true;
}
} else {
sampler.setProtocol(HTTPConstants.PROTOCOL_HTTPS);
forcedHTTP = true;
}
}
sampler.threadStarted(); // Needed for HTTPSampler2
result = sampler.sample();
/*
* If we're dealing with text data, and if we're spoofing https,
* replace all occurences of "https://" with "http://" for the client.
* TODO - also check the match string to restrict the changes further?
*/
if (forcedHTTP && SampleResult.TEXT.equals(result.getDataType()))
{
final String enc = result.getDataEncodingWithDefault();
String noHttpsResult = new String(result.getResponseData(),enc);
final String HTTPS_HOST = // match https://host[:port]/ and drop default port if present
"https://([^:/]+)(:"+HTTPConstants.DEFAULT_HTTPS_PORT_STRING+")?"; // $NON-NLS-1$ $NON-NLS-2$
noHttpsResult = noHttpsResult.replaceAll(HTTPS_HOST, "http://$1"); // $NON-NLS-1$
result.setResponseData(noHttpsResult.getBytes(enc));
}
// Find the page encoding and possibly encodings for forms in the page
// in the response from the web server
String pageEncoding = addPageEncoding(result);
addFormEncodings(result, pageEncoding);
writeToClient(result, new BufferedOutputStream(clientSocket.getOutputStream()));
} catch (UnknownHostException uhe) {
log.warn("Server Not Found.", uhe);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -