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

📄 abstracthttplogichandler.java

📁 mina是以Java实现的一个开源的网络程序框架
💻 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.mina.proxy.handlers.http;import java.io.UnsupportedEncodingException;import java.util.HashMap;import java.util.List;import java.util.Map;import org.apache.mina.core.buffer.IoBuffer;import org.apache.mina.core.filterchain.IoFilter.NextFilter;import org.apache.mina.core.future.ConnectFuture;import org.apache.mina.core.future.IoFutureListener;import org.apache.mina.core.session.IoSession;import org.apache.mina.core.session.IoSessionInitializer;import org.apache.mina.proxy.AbstractProxyLogicHandler;import org.apache.mina.proxy.ProxyAuthException;import org.apache.mina.proxy.ProxyConnector;import org.apache.mina.proxy.session.ProxyIoSession;import org.apache.mina.proxy.utils.IoBufferDecoder;import org.apache.mina.proxy.utils.StringUtilities;import org.slf4j.Logger;import org.slf4j.LoggerFactory;/** * AbstractHttpLogicHandler.java - Base class for HTTP proxy {@link AbstractProxyLogicHandler} implementations.  * Provides HTTP request encoding/response decoding functionality. *  * @author The Apache MINA Project (dev@mina.apache.org) * @version $Rev: 685703 $, $Date: 2008-08-14 00:14:47 +0200 (Thu, 14 Aug 2008) $ * @since MINA 2.0.0-M3 */public abstract class AbstractHttpLogicHandler extends        AbstractProxyLogicHandler {    private final static Logger logger = LoggerFactory            .getLogger(AbstractHttpLogicHandler.class);    private final static String DECODER = AbstractHttpLogicHandler.class            .getName()            + ".Decoder";    private final static byte[] HTTP_DELIMITER = new byte[] { '\r', '\n', '\r',            '\n' };    private final static byte[] CRLF_DELIMITER = new byte[] { '\r', '\n' };    // Parsing vars    /**     * Temporary buffer to accumulate the HTTP response from the proxy.     */    private IoBuffer responseData = null;    /**     * The parsed http proxy response     */    private HttpProxyResponse parsedResponse = null;    /**     * The content length of the proxy response.     */    private int contentLength = -1;    // HTTP/1.1 vars    /**     * A flag that indicates that this is a HTTP/1.1 response with chunked data.and that some chunks are missing.        */    private boolean hasChunkedData;    /**     * A flag that indicates that some chunks of data are missing to complete the HTTP/1.1 response.        */    private boolean waitingChunkedData;    /**     * A flag that indicates that chunked data has been read and that we're now reading the footers.        */    private boolean waitingFooters;    /**     * Contains the position of the entity body start in the <code>responseData</code> {@link IoBuffer}.     */    private int entityBodyStartPosition;    /**     * Contains the limit of the entity body start in the <code>responseData</code> {@link IoBuffer}.     */    private int entityBodyLimitPosition;    /**     * Creates a new {@link AbstractHttpLogicHandler}.     *      * @param proxyIoSession	 {@link ProxyIoSession} in use.     * @param request the requested url to negotiate with the proxy.     */    public AbstractHttpLogicHandler(final ProxyIoSession proxyIoSession) {        super(proxyIoSession);    }    /**     * Handle incoming data during the handshake process. Should consume only the     * handshake data from the buffer, leaving any extra data in place.     */    public synchronized void messageReceived(final NextFilter nextFilter,            final IoBuffer buf) throws ProxyAuthException {        logger.debug(" messageReceived()");        IoBufferDecoder decoder = (IoBufferDecoder) getSession().getAttribute(                DECODER);        if (decoder == null) {            decoder = new IoBufferDecoder(HTTP_DELIMITER);            getSession().setAttribute(DECODER, decoder);        }        try {            if (parsedResponse == null) {                responseData = decoder.decodeFully(buf);                if (responseData == null) {                    return;                }                // Handle the response								                String responseHeader = responseData                        .getString(getProxyIoSession().getCharset()                                .newDecoder());                entityBodyStartPosition = responseData.position();                logger.debug("  response header received:\n{}", responseHeader                        .replace("\r", "\\r").replace("\n", "\\n\n"));                // Parse the response                parsedResponse = decodeResponse(responseHeader);                // Is handshake complete ?                if (parsedResponse.getStatusCode() == 200                        || (parsedResponse.getStatusCode() >= 300 && parsedResponse                                .getStatusCode() <= 307)) {                    buf.position(0);                    setHandshakeComplete();                    return;                }                String contentLengthHeader = StringUtilities                        .getSingleValuedHeader(parsedResponse.getHeaders(),                                "Content-Length");                if (contentLengthHeader == null) {                    contentLength = 0;                } else {                    contentLength = Integer                            .parseInt(contentLengthHeader.trim());                    decoder.setContentLength(contentLength, true);                }            }            if (!hasChunkedData) {                if (contentLength > 0) {                    IoBuffer tmp = decoder.decodeFully(buf);                    if (tmp == null) {                        return;                    }                    responseData.setAutoExpand(true);                    responseData.put(tmp);                    contentLength = 0;                }                if ("chunked".equalsIgnoreCase(StringUtilities                        .getSingleValuedHeader(parsedResponse.getHeaders(),                                "Transfer-Encoding"))) {                    // Handle Transfer-Encoding: Chunked                    logger.debug("Retrieving additional http response chunks");                    hasChunkedData = true;                    waitingChunkedData = true;                }            }            if (hasChunkedData) {                // Read chunks                while (waitingChunkedData) {                    if (contentLength == 0) {                        decoder.setDelimiter(CRLF_DELIMITER, false);                        IoBuffer tmp = decoder.decodeFully(buf);                        if (tmp == null) {                            return;                        }                        String chunkSize = tmp.getString(getProxyIoSession()                                .getCharset().newDecoder());                        int pos = chunkSize.indexOf(';');                        if (pos >= 0) {                            chunkSize = chunkSize.substring(0, pos);                        } else {                            chunkSize = chunkSize.substring(0, chunkSize                                    .length() - 2);                        }                        contentLength = Integer.decode("0x" + chunkSize);                        if (contentLength > 0) {                            contentLength += 2; // also read chunk's trailing CRLF                            decoder.setContentLength(contentLength, true);                        }                    }                    if (contentLength == 0) {                        waitingChunkedData = false;                        waitingFooters = true;                        entityBodyLimitPosition = responseData.position();                        break;                    }                    IoBuffer tmp = decoder.decodeFully(buf);                    if (tmp == null) {                        return;                    }                    contentLength = 0;                    responseData.put(tmp);                    buf.position(buf.position());                }                // Read footers                while (waitingFooters) {                    decoder.setDelimiter(CRLF_DELIMITER, false);                    IoBuffer tmp = decoder.decodeFully(buf);                    if (tmp == null) {                        return;                    }                    if (tmp.remaining() == 2) {                        waitingFooters = false;                        break;                    }                    // add footer to headers					                    String footer = tmp.getString(getProxyIoSession()                            .getCharset().newDecoder());                    String[] f = footer.split(":\\s?", 2);                    StringUtilities.addValueToHeader(parsedResponse                            .getHeaders(), f[0], f[1], false);                    responseData.put(tmp);                    responseData.put(CRLF_DELIMITER);                }            }            responseData.flip();            logger.debug("  end of response received:\n{}",                    responseData.getString(getProxyIoSession().getCharset()                            .newDecoder()));            // Retrieve entity body content            responseData.position(entityBodyStartPosition);            responseData.limit(entityBodyLimitPosition);            parsedResponse.setBody(responseData.getString(getProxyIoSession()                    .getCharset().newDecoder()));            // Free the response buffer            responseData.free();            responseData = null;            handleResponse(parsedResponse);            parsedResponse = null;            hasChunkedData = false;            contentLength = -1;            decoder.setDelimiter(HTTP_DELIMITER, true);            if (!isHandshakeComplete()) {                doHandshake(nextFilter);            }        } catch (Exception ex) {            if (ex instanceof ProxyAuthException) {                throw ((ProxyAuthException) ex);            } else {                throw new ProxyAuthException("Handshake failed", ex);            }        }    }    /**     * Handle a HTTP response from the proxy server.     *      * @param response The response.     */    public abstract void handleResponse(final HttpProxyResponse response)            throws ProxyAuthException;    /**     * Calls{@link #writeRequest0(NextFilter, HttpProxyRequest)} to write the request.      * If needed a reconnection to the proxy is done previously.     */    public void writeRequest(final NextFilter nextFilter,            final HttpProxyRequest request) throws ProxyAuthException {        ProxyIoSession proxyIoSession = getProxyIoSession();        if (proxyIoSession.isReconnectionNeeded()) {            reconnect(nextFilter, request);        } else {            writeRequest0(nextFilter, request);        }    }    /**     * Encode a HTTP request and send it to the proxy server.     */    private void writeRequest0(final NextFilter nextFilter,            final HttpProxyRequest request) {        try {            String data = request.toHttpString();            IoBuffer buf = IoBuffer.wrap(data.getBytes(getProxyIoSession()                    .getCharsetName()));            logger.debug("   write:\n{}", data.replace("\r", "\\r").replace(                    "\n", "\\n\n"));            writeData(nextFilter, buf);        } catch (UnsupportedEncodingException ex) {            closeSession("Unable to send HTTP request: ", ex);        }    }    /**     * Method to reconnect to proxy when it decides not to maintain the connection during handshake.     * @throws ProxyAuthException      */    private void reconnect(final NextFilter nextFilter,            final HttpProxyRequest request) throws ProxyAuthException {        logger.debug("Reconnecting to proxy ...");        final ProxyIoSession proxyIoSession = getProxyIoSession();        final ProxyConnector connector = proxyIoSession.getConnector();        connector.connect(new IoSessionInitializer<ConnectFuture>() {            public void initializeSession(final IoSession session,                    ConnectFuture future) {                logger.debug("Initializing new session: " + session);                session.setAttribute(ProxyIoSession.PROXY_SESSION,                        proxyIoSession);                proxyIoSession.setSession(session);                logger.debug("  setting proxyIoSession: " + proxyIoSession);                future.addListener(new IoFutureListener<ConnectFuture>() {                    public void operationComplete(ConnectFuture future) {                        proxyIoSession.setReconnectionNeeded(false);                        writeRequest0(nextFilter, request);                    }                });            }        });    }    /**     * Parse a HTTP response from the proxy server.     *      * @param response The response string.     */    protected HttpProxyResponse decodeResponse(final String response)            throws Exception {        logger.debug("  parseResponse()");        // Break response into lines        String[] responseLines = response.split(HttpProxyConstants.CRLF);        // Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF        // BUG FIX : Trimed to prevent failures with some proxies that add extra space chars        // like "Microsoft-IIS/5.0" ...        String[] statusLine = responseLines[0].trim().split(" ", 2);        if (statusLine.length < 2) {            throw new Exception("Invalid response status line (" + statusLine                    + "). Response: " + response);        }        // Status code is 3 digits        if (statusLine[1].matches("^\\d\\d\\d")) {            throw new Exception("Invalid response code (" + statusLine[1]                    + "). Response: " + response);        }        Map<String, List<String>> headers = new HashMap<String, List<String>>();        for (int i = 1; i < responseLines.length; i++) {            String[] args = responseLines[i].split(":\\s?", 2);            StringUtilities.addValueToHeader(headers, args[0], args[1], false);        }        return new HttpProxyResponse(statusLine[0], statusLine[1], headers);    }}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -