📄 proxiedresponseprocessor.java
字号:
/*
* SSL-Explorer
*
* Copyright (C) 2003-2006 3SP LTD. All Rights Reserved
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package com.sslexplorer.replacementproxy;
import java.io.InputStream;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Enumeration;
import java.util.List;
import java.util.StringTokenizer;
import java.util.zip.GZIPInputStream;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.maverick.http.HttpResponse;
import com.sslexplorer.boot.CaseInsensitiveMap;
import com.sslexplorer.boot.HttpConstants;
import com.sslexplorer.boot.Util;
import com.sslexplorer.core.CookieItem;
import com.sslexplorer.core.CookieMap;
/**
* @author Brett Smith <brett@3sp.com>
*/
public class ProxiedResponseProcessor {
final static Log log = LogFactory.getLog(ProxiedResponseProcessor.class);
private ProxiedRequestDispatcher requestDispatcher;
private int maxAge;
private ContentCache cache;
private SimpleDateFormat sdf;
private RequestProcessor requestProcessor;
// private boolean keepAlive;
private Date expiryDate;
private CookieMap cookieMap;
private String contentType;
private int contentLength;
private List headers;
private boolean cacheable;
private InputStream serverIn;
private String charset;
static CaseInsensitiveMap ignoreHeaders = new CaseInsensitiveMap();
static {
ignoreHeaders.put(HttpConstants.HDR_PROXY_CONNECTION, Boolean.TRUE);
ignoreHeaders.put(HttpConstants.HDR_ACCEPT_ENCODING, Boolean.TRUE);
ignoreHeaders.put(HttpConstants.HDR_TRANSFER_ENCODING, Boolean.TRUE);
ignoreHeaders.put(HttpConstants.HDR_TE, Boolean.TRUE);
ignoreHeaders.put(HttpConstants.HDR_TRAILER, Boolean.TRUE);
ignoreHeaders.put(HttpConstants.HDR_PROXY_AUTHORIZATION, Boolean.TRUE);
ignoreHeaders.put(HttpConstants.HDR_PROXY_AUTHENTICATE, Boolean.TRUE);
ignoreHeaders.put(HttpConstants.HDR_UPGRADE, Boolean.TRUE);
ignoreHeaders.put(HttpConstants.HDR_CONTENT_ENCODING, Boolean.TRUE);
}
/**
*
*/
public ProxiedResponseProcessor(RequestProcessor requestProcessor, ProxiedRequestDispatcher requestDispatcher, int maxAge, ContentCache cache, CookieMap cookieMap) {
this.requestDispatcher = requestDispatcher;
this.requestProcessor = requestProcessor;
this.maxAge = maxAge;
this.cache = cache;
this.cookieMap = cookieMap;
// keepAlive = requestDispatcher.isKeepAlive();
sdf = new SimpleDateFormat("EEEE, dd-MMM-yy HH:mm:ss zzz");
}
public ProxiedRequestDispatcher getRequestDispatcher() {
return requestDispatcher;
}
public void processResponse() throws Exception {
HttpResponse serverResponse = requestDispatcher.getServerResponse();
headers = new ArrayList();
// Determine if the response can be cached, and if so, for how long
expiryDate = maxAge == 0 ? null : new Date(System.currentTimeMillis() + maxAge);
cacheable = false;
if (cache != null && HttpConstants.METHOD_GET.equals(requestProcessor.getRequestMethod()) && requestDispatcher.getResponseCode() == HttpConstants.RESP_200_OK) {
cacheable = true;
// HTTP 1.0
String cacheControl = serverResponse.getHeaderField(HttpConstants.HDR_PRAGMA);
if (cacheControl != null && cacheControl.equalsIgnoreCase("no-cache")) {
if (log.isDebugEnabled())
log.debug("Not caching as server explicitly requested not to.");
cacheable = false;
} else {
String expires = serverResponse.getHeaderField(HttpConstants.HDR_EXPIRES);
if (expires != null) {
try {
expiryDate = sdf.parse(expires);
} catch (Exception e2) {
}
}
}
// HTTP 1.1
if (cacheable) {
cacheControl = serverResponse.getHeaderField(HttpConstants.HDR_CACHE_CONTROL);
if (cacheControl != null) {
StringTokenizer tok = new StringTokenizer(cacheControl, ";");
while (tok.hasMoreTokens()) {
String t = tok.nextToken().trim();
String tl = t.toLowerCase();
if (t.startsWith("no-cache") || t.startsWith("no-store")) {
cacheable = false;
if (log.isDebugEnabled())
log.debug("Not caching as server explicitly requested not to.");
} else if (tl.startsWith("max-age")) {
try {
expiryDate.setTime(expiryDate.getTime() - (Integer.parseInt(Util.valueOfNameValuePair(tl))));
} catch (Exception e2) {
}
}
}
}
}
}
String contentEncoding = serverResponse.getHeaderField(HttpConstants.HDR_CONTENT_ENCODING);
serverIn = serverResponse.getInputStream();
if ("gzip".equals(contentEncoding)) {
serverIn = new GZIPInputStream(serverIn);
} else if ("identity".equals(contentEncoding) || contentEncoding == null) {
// Plain
} else {
throw new Exception("Invalid content encoding " + serverResponse.getHeaderField(HttpConstants.HDR_CONTENT_ENCODING));
}
/**
* Filter out unsupported authentication methods because they dont
* work through the reverse proxy - the best way to enable these
* will be to allow credentials to be set on the reverse proxy
* web forward.
*/
String[] challenges = serverResponse.getHeaderFields("www-authenticate");
if(challenges!=null) {
serverResponse.removeFields("www-authenticate");
for (int i = 0; i < challenges.length; i++) {
if (challenges[i].toLowerCase().startsWith("basic")
|| challenges[i].toLowerCase().startsWith("digest")) {
serverResponse.setHeaderField("www-authenticate", challenges[i]);
}
}
}
//response.setStatus(serverResponse.getStatus());
//response.setReason(serverResponse.getReason());
serverResponse.removeFields("Server");
serverResponse.removeFields("Date");
for (Enumeration e = serverResponse.getHeaderFieldNames();
e.hasMoreElements(); ) {
String hdr = (String) e.nextElement();
if (log.isDebugEnabled())
log.debug("Received header " + hdr);
String[] val = serverResponse.getHeaderFields(hdr);
for (int i = 0; i < val.length; i++) {
if (hdr.equalsIgnoreCase("Content-Type")) {
StringTokenizer tok = new StringTokenizer(val[i], ";");
while (tok.hasMoreTokens()) {
String t = tok.nextToken().trim();
String tl = t.toLowerCase();
if (tl.startsWith("charset=")) {
charset = Util.valueOfNameValuePair(t);
}
else {
contentType = Util.valueOfNameValuePair(t);
}
}
contentType = val[i];
if (log.isDebugEnabled())
log.debug("Received content type " + contentType + " (charset = " + charset + ")");
} else if (hdr.equalsIgnoreCase("Content-Length")) {
try {
contentLength = Integer.parseInt(val[i]);
} catch (Exception ex) {
}
if (log.isDebugEnabled())
log.debug("Received content length " + contentLength);
} else {
if (hdr.equalsIgnoreCase("Location")) {
URL actual = new URL(requestProcessor.getContext(), val[i]);
cache.clear(actual.toExternalForm());
String newVal = "/replacementProxyEngine?sslex_ticket=" + requestProcessor.getUniqueTicket() + "&sslex_url=" + Util.urlEncode(actual.toExternalForm());
if (log.isDebugEnabled())
log.debug("Found location of header " + val + " changing to " + newVal + " ( removed "
+ actual.toExternalForm() + " from cache");
val[i] = newVal;
} else if (hdr.equalsIgnoreCase("Set-Cookie")) {
StringTokenizer t = new StringTokenizer(val[i], ";");
String cookieName = null;
String cookieValue = null;
Date cookieExpiry = null;
try {
while (t.hasMoreTokens()) {
String name = Util.trimBoth(t.nextToken());
int idx = name.indexOf('=');
if(idx > -1) {
String value = name.substring(idx + 1);
name = name.substring(0, idx);
if (name.equalsIgnoreCase("path")) {
} else if (name.equalsIgnoreCase("expires")) {
cookieExpiry = sdf.parse(value);
} else if (name.equalsIgnoreCase("domain")) {
} else {
if (cookieName != null) {
throw new Exception("Unexpected element in Set-Cookie: " + name + "=" + value);
}
cookieName = name;
cookieValue = value;
}
} else {
cookieName = name;
cookieValue = "";
}
}
} catch (Exception ex) {
log.warn("Invalid cookie.", ex);
}
// Create the fake cookie name and place it in the
// cookie map
if (cookieName != null) {
String fakeCookieName = Math.abs((requestDispatcher.getConnectionURL().getProtocol() + ":" + requestDispatcher.getConnectionURL().getHost())
.hashCode())
+ "_" + cookieName;
CookieItem cookieItem = new CookieItem(cookieName, fakeCookieName);
cookieMap.put(cookieItem);
val[i] = fakeCookieName + "=" + (cookieValue == null ? "" : Util.urlEncode(cookieValue))
+ (cookieExpiry != null ? (";expires=" + sdf.format(cookieExpiry)) : "");
}
}
if (log.isDebugEnabled())
log.debug("Adding header " + hdr + " = " + val[i]);
headers.add(new Header(hdr, val[i]));
}
}
}
}
public List getHeaders() {
return headers;
}
/**
* @return
*/
public String getContentType() {
return contentType;
}
public String getCharset() {
return charset;
}
public int getContentLength() {
return contentLength;
}
/**
* @return
*/
public boolean isCacheable() {
return cacheable;
}
public InputStream getProxiedInputStream() {
return serverIn;
}
/**
* @return
*/
public Date getCacheExpiryDate() {
return expiryDate;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -