⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 httpresponse.java

📁 轻量级Http代理服务器
💻 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 + -