📄 requesthandler.java
字号:
/*
* jRevProxy, an opensource Java reverse proxy server
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
*
* $Id: RequestHandler.java,v 2.14 2003/04/24 09:21:45 fnoe Exp $
*/
package cx.noe.jrevproxy;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.io.*;
import java.util.*;
import java.net.URL;
import cx.noe.jrevproxy.logging.ILog;
import cx.noe.jrevproxy.IHandlerInfo;
import cx.noe.jrevproxy.Ruleset;
import cx.noe.jrevproxy.Rule;
/**
* RequestHandler
*
* The RequestHandler handles the external request.
*
* @author <a href="mailto:frederik@noe.cx"> Frederik Noe </a>
* @version <tt>$Revision: 2.14 $</tt>
*/
public class RequestHandler implements RevProRunnable,ILog {
private PoolManager manager = null;
private ILog logger = null;
private Socket socket = null;
private Properties properties = null;
private int timeout = 5000;
private int soTimeout = 1000;
private Ruleset ruleset = null;
private int NRRETRIES = 10;
private ConnectionInfo connectioninfo = null;
/** Creates a new instance of RequestHandler
*
* @param manager the poolmanager instance
* @param properties the properties instance used to retrieve some key/value pairs
* @param connectioninfo the object instance that holds the connection and authentication info
*/
public RequestHandler(PoolManager manager, Properties properties, ConnectionInfo connectioninfo) {
this.manager = manager;
logger = manager.getLogger();
this.properties = properties;
this.connectioninfo = connectioninfo;
String strSOTimeout = null;
if((strSOTimeout = properties.getProperty("SOTIMEOUT")) != null)
try {
soTimeout = Integer.parseInt(strSOTimeout);
}
catch(Exception e) {}
String strTimeout = null;
if((strTimeout = properties.getProperty("TIMEOUT")) != null)
try {
timeout = Integer.parseInt(strTimeout);
}
catch(Exception e) {}
}
/**
* Thread execution code
*
* @param info information about the poolinstance that will run this method
*/
public void run(IHandlerInfo info) {
ILog oldLogger = logger;
logger = info.getLogger();
log(METHOD,"--run--");
OutputStream outEx = null;
InputStream inEx = null;
try {
SocketFactory factory = new SocketFactory(properties,logger);
log(DEBUG,"external socketfactory created");
// set a timeout to avoid infinite reads while no new bytes are arriving
socket.setSoTimeout(soTimeout);
log(DEBUG,"external socket timeout set: " + soTimeout);
// create the in/out streams for the external socket connection
outEx = socket.getOutputStream();
inEx = socket.getInputStream();
log(DEBUG,"external input- and outputstreams created");
ByteArrayOutputStream outStream = null;
int size = 0;
String inStr = null;
outStream = readRequest(inEx);
// convert to String so that we can start parsing the request
// check that we have a non-empty reques that is well formed (GET || POST)
if((size = outStream.size()) == 0 || !HTTPRequest.isHTTPRequest(inStr = outStream.toString())) {
if(size == 0) {
log(INFO,"no external request data available");
sendBadRequestResponse(outEx,"No data received");
}
else {
log(DEBUG,"external request: " + inStr);
log(INFO,"no valid external HTTP request received");
sendBadRequestResponse(outEx,"No valid HTTP request received");
}
// let's reset the logger back to the original
logger = oldLogger;
return;
}
// log the external request in case we are in debug mode
log(DEBUG,"external request: " + inStr);
// find out what virtual directory the request refers to
String vdir = null;
vdir = HTTPRequest.getVirtualDir(inStr);
log(DEBUG,"external virtual dir:" + vdir);
// find what rule applies out of the ruleset
Rule rule = ruleset.getApplicableRule(vdir);
if(rule == null) {
log(INFO,"Did not find an applicable rule for virtualdir " + vdir);
sendBadRequestResponse(outEx,"Exception");
// let's reset the logger back to the original
logger = oldLogger;
return;
}
// show in the logging what the rule is doing
log(INFO,"Found applicable rule " + rule.getName());
log(DEBUG,"Rule: " + vdir + " <-> " + rule.getJunction());
// check if client authentication is enabled and check if we have a user restriction
if(connectioninfo.getCertificate() != null) {
String subjectDN = connectioninfo.getCertificate().getSubjectDN().getName();
if(subjectDN != null)
if(!rule.isAuthorized(subjectDN)) {
sendNotAuthorizedResponse(outEx);
log(INFO,"User is NOT authorized to read the requested resource");
return;
}
else
log(INFO,"User is authorized to read the requested resource");
}
// modify the request so that it will seem that jRevProxy made the internal request instead of
// the external computer
String hostName = rule.getJunction().getHost();
int intPort = rule.getJunction().getPort();
inStr = HTTPRequest.setHostname(inStr, hostName);
inStr = HTTPRequest.trim(inStr);
String newVdir= rule.getJunction().getPath();
if (newVdir == null || newVdir == "")
newVdir = "/";
inStr = HTTPRequest.setVirtualDir(inStr,newVdir);
log(DEBUG,"jRevProxy modified request: " + inStr);
// send the internal request, receive the response and send it to the external host
Socket intSocket = null;
if(rule.getJunction().getProtocol().compareToIgnoreCase("HTTPS") == 0) {
intSocket = factory.getSSLClientSocket(hostName,intPort);
log(DEBUG,"internal SSLSocket created");
}
else {
intSocket = factory.getClientSocket(hostName,intPort);
log(DEBUG,"internal socket created");
}
intSocket.setSoTimeout(soTimeout);
log(DEBUG,"internal socket timeout set: " + soTimeout);
InputStream inIn = intSocket.getInputStream();
OutputStream outIn = intSocket.getOutputStream();
log(DEBUG,"internal input- and outputstreams created");
outStream = null;
int nrretries = 1;
// let's try a couple of times to send the request and receive a non-empty response back
do {
log(INFO, nrretries + " try to send and receive");
outIn.write(inStr.getBytes());
log(DEBUG,"internal request send");
outStream = readResponse(inIn);
log(DEBUG,"internal response received");
}
while((outStream.size() == 0 || HTTPResponse.isMsgBodyEmpty(outStream.toString())) && nrretries++ <NRRETRIES);
if(outStream.size() != 0) {
// check the contenttype
String outStr = outStream.toString();
log(DEBUG,"internal response: " + outStr);
if(HTTPResponse.getContentType(outStr) == HTTPResponse.TEXT_HTML) {
log(DEBUG,"Content is HTML");
// check if we have a chunked transfer encoding
if(HTTPResponse.isChunkedTransfer(outStr)) {
log(DEBUG,"Transfer-Encoding is chunked; let's decode it");
outStr = HTTPResponse.decodeTransferEncoding(outStr);
log(DEBUG,"decoded internal response: " + outStr);
}
log(DEBUG,"Let's update the response headers");
outStr = HTTPResponse.updateHeaders(outStr, socket.getLocalAddress().getHostName(), vdir);
log(DEBUG, "internal response with updated headers: " + outStr);
//
log(DEBUG,"Let's filter the response now");
outStr = HTTPResponse.filter(outStr, socket.getLocalAddress().getHostName(), vdir, rule.getJunction(), true);
log(DEBUG,"filtered internal response: " + outStr);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -