📄 httpresponse.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: HTTPResponse.java,v 1.14 2003/04/26 13:46:49 fnoe Exp $
*/
package cx.noe.jrevproxy;
import java.util.Hashtable;
import java.net.URL;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
import java.io.*;
/**
* HTTPResponse
*
* @author <a href="mailto:frederik@noe.cx"> Frederik Noe </a>
* @version <tt>$Revision: 1.14 $</tt>
*/
public class HTTPResponse extends HTTPBase{
/**
* Checks if the HTTP response has a chunked transfer encoding
*
* @param response the HTTP response
* @return true if the HTTP response is chunk encoded otherwise false
**/
public static boolean isChunkedTransfer(String response) {
String str = getValue(response,"Transfer-Encoding");
if(str == null)
return false;
if(str.compareToIgnoreCase("chunked") == 0)
return true;
return false;
}
/**
* Adds/modifies headers in the HTTP response
*
* @param response the HTTP response
* @param hostname the hostname of the machine where jRevProxy is running on
* @param vdir the virtual directory requested by the client
* @return the updated HTTP response containing the new/modified HTTP headers
*/
public static String updateHeaders(String response, String host, String virtdir) {
String tmp = response;
// check the HTTP returncode
int errorcode = getHTTPReturnCode(response);
switch(errorcode) {
case 200:
// add the 'Content-Location' header to the response
tmp = setValue(tmp,"Location","http://"+host+(virtdir.charAt(0)=='/'?virtdir:"/"+virtdir));
tmp = setValue(tmp,"Content-Location","http://"+host+(virtdir.charAt(0)=='/'?virtdir:"/"+virtdir));
break;
default: break;
}
return tmp;
}
/**
* Decode chunked transfer encoding
* Chunked transfer encoding follows this scheme:
* <chunk size><CRLF><Data chunk><CRLF>...<0 chunk size>
*
* @param response the HTTP response
* @return the decoded HTTP response
*/
public static String decodeTransferEncoding(String response) throws HTTPFormatException {
int start = -1, end = -1, chunk_size = 0, startHeader = -1, endHeader = -1;
StringBuffer buffer = new StringBuffer();
// let's search for the start of the Transfer-Encoding header
if((startHeader = response.toLowerCase().indexOf("Transfer-Encoding".toLowerCase())) == -1)
// it seems there is no header in the response, let's throw an exception
throw new HTTPFormatException("No Transfer-Encoding header found");
if((start = response.indexOf(CRLF+CRLF)) == -1)
// we do not find the data part, let's return the original response
throw new HTTPFormatException("No HTTP response body found");
start += 2*CRLF_LENGTH;
// we start looking for the first length indicator
if((end = response.indexOf(CRLF,start)) == -1)
// we do not seem to have a length indicator at all, let's return the original response
throw new HTTPFormatException("No start of transfer encoding length indicator found");
// let's search for the end of the Transfer-Encoding header
if(((endHeader = response.indexOf(CRLF,startHeader)) == -1) || endHeader > start)
throw new HTTPFormatException("No end of transfer encoding length indicator found");
// remove the Transfer-encoding header from the response
buffer.append(response.substring(0,startHeader));
buffer.append(response.substring(endHeader + CRLF_LENGTH,start));
//calculate the chunk size
chunk_size = Integer.parseInt(response.substring(start,end).trim(), 16);
while(chunk_size > 0) {
buffer.append(response.substring(end + CRLF_LENGTH,end + CRLF_LENGTH + chunk_size));
start = end + CRLF_LENGTH + chunk_size + CRLF_LENGTH;
if((end = response.indexOf(CRLF,start)) == -1)
// we do not seem to have a length indicator at all, let's return the original response
throw new HTTPFormatException("No transfer encoding length indicator found");
chunk_size = Integer.parseInt(response.substring(start,end).trim(), 16);
}
return buffer.toString();
}
/**
* Updates the hyperlinks and references in the internal request response
*
* @param response the HTTP response to be filtered
* @param hostname the hostname of the machine where jRevProxy is running on
* @param vdir the virtual directory requested by the client
* @param junction the internal URL
* @return the filtered HTTP response
**/
public static String filter(String response, String host, String virtdir, URL junction, boolean checkContentType) {
// check if we have a text response, if not give back the original
if(checkContentType)
if(getContentType(response)!= TEXT_HTML) {
return new String(response);
}
int patternFlags = Pattern.CASE_INSENSITIVE;
String filteredResponse = response;
String regex = "(<\\s*.+?\\s*(HREF|SRC|BACKGROUND|ACTION)\\s*=\\s*\"?\'?\\s*)(https?://"+junction.getHost()+")?(/?)(.+?\\s*.*?>)";
StringBuffer sb = new StringBuffer();
Pattern pattern = Pattern.compile(regex, patternFlags);
Matcher matcher = pattern.matcher(filteredResponse);
while (true) {
StringBuffer replacement = new StringBuffer();
if (!matcher.find())
break;
/// tmp
String firstgrp = matcher.group(1);
String secondgrp = matcher.group(2);
String fourthgrp = matcher.group(4);
//
String fifthgrp = matcher.group(5);
String thirdgrp = matcher.group(3);
if(thirdgrp != null && thirdgrp .length() != 0) {
replacement.append("$1https://");
replacement.append(host);
replacement.append(virtdir);
replacement.append("/$5");
}
else {
// check first if we are not screwing up URLs pointing to other sites
// if tmp contains references to http(s), then we should not modify the URL
if(fifthgrp.startsWith("http") || fifthgrp.startsWith("javascript:") || fourthgrp == null || fourthgrp.length() == 0)
continue;
replacement.append("$1");
replacement.append(virtdir);
replacement.append("/$5");
}
matcher.appendReplacement( sb, replacement.toString());
}
matcher.appendTail( sb );
filteredResponse = sb.toString();
// update the contentlength in case of checkedContentType
if(checkContentType)
filteredResponse = setContentLength(filteredResponse,calculateContentLength(filteredResponse));
return filteredResponse;
}
/**
* Retrieves the content-length value out of the HTTP response
*
* @param response the HTTP response
* @return the content length
*/
public static int getContentLength(String response) {
String str = getValue(response,"Content-Length");
if(str != null)
return Integer.parseInt(str);
return 0;
}
/**
* Retrieves the content type out of the HTTP response
* jRevProxy only parsee TEXT_HTML response
*
* @param response the HTTP response
* @return the content type
*/
public static int getContentType(String response) {
String str = getValue(response,"Content-Type");
if(str == null)
return NOT_AVAILABLE;
int i;
for(i=0; i<contentTypes.length;i++)
// let's find out if we find our predefined types in the content type header value
if(str.toLowerCase().indexOf(contentTypes[i]) != -1)
return i+1;
return NOT_AVAILABLE;
}
/**
* Calculate the length of both the content and the header
*
* @param response the HTTP Response string
* @return the total length of both header and body (in bytes)
*/
public static int getTotalResponseLength(String response) {
// calculate the length of both the content and the header
int start = 0, length = 0;
if((start = response.indexOf(CRLF + CRLF)) == -1)
return 0;
if((length = getContentLength(response)) > 0) {
length += start + 4;
return length;
}
return 0;
}
/**
* Check if the HTTP response body is not empty
*
* @param response the HTTP Response string
* @return true if there is no message body; false otherwise
*/
public static boolean isMsgBodyEmpty(String response) {
int start = -1;
if((start = response.indexOf(CRLF+CRLF)) == -1)
// we do not find the data part
return true;
if(start == response.length() - 1)
return true;
return false;
}
/**
* Calculates the total length of the body
*
* @param response the HTTP response
* @return the length (in bytes) of the body
*/
private static int calculateContentLength(String response) {
int start = 0, length = 0;
if((start = response.indexOf(CRLF + CRLF)) == -1)
return 0;
length = response.length() - start - 4;
return length;
}
/**
* Updates the content-length value in the HTTP response header
*
* @param response the HTTP response
* @param value the new content-length value
* @return the updated HTTP response
*/
private static String setContentLength(String response, int value) {
return setValue(response, "Content-Length", new Integer(value).toString());
}
/**
* Retrieves the HTTP response return code
* @param response the HTTP response
* @return the HTTP return code
*/
private static int getHTTPReturnCode(String response) {
int begin = 0, end = 0, returnval = 0;
if((begin = response.indexOf(" ")) == -1)
return -1;
if((end = response.indexOf(" ",begin+1)) == -1)
return -1;
try {
returnval = Integer.parseInt(response.substring(begin+1, end));
return returnval;
}
catch(Exception e)
{ return -1; }
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -