org.ireland.jnetty.http.HttpServletRequestImpl.java Source code

Java tutorial

Introduction

Here is the source code for org.ireland.jnetty.http.HttpServletRequestImpl.java

Source

//
//  ========================================================================
//  Copyright (c) 1995-2013 Mort Bay Consulting Pty. Ltd.
//  ------------------------------------------------------------------------
//  All rights reserved. This program and the accompanying materials
//  are made available under the terms of the Eclipse Public License v1.0
//  and Apache License v2.0 which accompanies this distribution.
//
//      The Eclipse Public License is available at
//      http://www.eclipse.org/legal/epl-v10.html
//
//      The Apache License v2.0 is available at
//      http://www.opensource.org/licenses/apache2.0.php
//
//  You may elect to redistribute this code under either of these licenses.
//  ========================================================================
//

package org.ireland.jnetty.http;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.Enumeration;
import java.util.EventListener;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeMap;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.nio.charset.Charset;
import java.nio.charset.UnsupportedCharsetException;

import java.security.Principal;

import javax.servlet.AsyncContext;
import javax.servlet.AsyncListener;
import javax.servlet.DispatcherType;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletRequest;
import javax.servlet.ServletRequestAttributeEvent;
import javax.servlet.ServletRequestAttributeListener;
import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
import javax.servlet.ServletResponse;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.servlet.http.Part;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.http.CookieDecoder;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpContent;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpVersion;
import io.netty.handler.codec.http.QueryStringDecoder;

import org.eclipse.jetty.util.MultiMap;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.URIUtil;
import org.eclipse.jetty.util.UrlEncoded;

import org.ireland.jnetty.dispatch.HttpInvocation;
import org.ireland.jnetty.http.io.ByteBufServletInputStream;
import org.ireland.jnetty.server.session.HttpSessionImpl;
import org.ireland.jnetty.server.session.SessionManager;
import org.ireland.jnetty.util.StringParser;
import org.ireland.jnetty.util.http.ContentTypeUtil;
import org.ireland.jnetty.webapp.WebApp;

/* ------------------------------------------------------------ */
/**
 * Jetty HttpServletRequestImpl.
 * <p>
 * Implements {@link javax.servlet.http.HttpServletRequest} from the <code>javax.servlet.http</code> package.
 * </p>
 * <p>
 * request object to be as lightweight as possible and not actually implement any significant behavior. For example
 * <ul>
 * 
 * <li>The {@link HttpServletRequestImpl#getContextPath()} method will return null, until the request has been passed to
 * a {@link ContextHandler} which matches the {@link HttpServletRequestImpl#getPathInfo()} with a context path and calls
 * {@link HttpServletRequestImpl#setContextPath(String)} as a result.</li>
 * 
 * <li>the HTTP session methods will all return null sessions until such time as a request has been passed to a
 * {@link org.eclipse.jetty.server.session.SessionHandler} which checks for session cookies and enables the ability to
 * create new sessions.</li>
 * 
 * <li>The {@link HttpServletRequestImpl#getServletPath()} method will return null until the request has been passed to
 * a <code>org.eclipse.jetty.servlet.ServletHandler</code> and the pathInfo matched against the servlet URL patterns and
 * {@link HttpServletRequestImpl#setServletPath(String)} called as a result.</li>
 * </ul>
 * 
 * A request instance is created for each connection accepted by the server and recycled for each HTTP request received
 * via that connection. An effort is made to avoid reparsing headers and cookies that are likely to be the same for
 * requests from the same connection.
 * 
 * <p>
 * The form content that a request can process is limited to protect from Denial of Service attacks. The size in bytes
 * is limited by {@link ContextHandler#getMaxFormContentSize()} or if there is no context then the
 * "org.eclipse.jetty.server.Request.maxFormContentSize" {@link Server} attribute. The number of parameters keys is
 * limited by {@link ContextHandler#getMaxFormKeys()} or if there is no context then the
 * "org.eclipse.jetty.server.Request.maxFormKeys" {@link Server} attribute.
 * 
 * 
 */
public class HttpServletRequestImpl implements HttpServletRequest {

    /**
     * Logger available to subclasses.
     */
    protected static final Log LOG = LogFactory.getLog(HttpServletRequestImpl.class);

    /**
     * The default Locale if none are specified.
     */
    protected static final Locale defaultLocale = Locale.getDefault();

    private static final Collection<Locale> __defaultLocale = Collections.singleton(Locale.getDefault());

    // Util

    /**
     * The string parser we will use for parsing request lines.
     */
    private StringParser parser;
    //

    private final ServletContext servletContext;

    //the HttpInvocation of this Request()
    private HttpInvocation _invocation;

    // Netty
    private final SocketChannel socketChannel;

    private final ChannelHandlerContext ctx;

    private final FullHttpResponse response;

    private final HttpServletResponseImpl _httpResponse;

    // request
    private final FullHttpRequest request;

    // request-header
    private final HttpHeaders headers;

    // request-body
    private final HttpContent body;

    // the content of HttpServletRequestImpl Body,as byte array. normaly,please use HttpContent body
    private byte[] bodyContent;

    // Netty<<

    /**
     * ServletInputStream.
     */
    protected ServletInputStream inputStream;

    /**
     * @see javax.servlet.ServletRequest#getInputStream() Using body as a stream flag.
     *      InputStream,??Reader
     */
    protected boolean usingInputStream = false;

    /**
     * @see javax.servlet.ServletRequest#getReader() Using body as reader flag.
     *      Reader,??InputStream
     */
    protected boolean usingReader = false;

    private List<ServletRequestAttributeListener> _requestAttributeListeners;

    private boolean _secure;
    private boolean _asyncSupported = true;
    private boolean _newContext;
    private boolean _cookiesExtracted = false;
    private boolean _handled = false;
    private boolean _paramsExtracted;

    /**
     * The attributes associated with this HttpServletRequestImpl, keyed by attribute name.
     */
    protected Map<String, Object> _attributes;

    private String _contentType;
    private String _characterEncoding;

    /**
     * Cookies parsed flag.
     */
    protected boolean cookiesParsed = false;

    // rawUri = contextPath + servletPath + pathInfo +?+ queryString

    // : /myweb
    private String _contextPath = "";

    // : /myservlet
    private String _servletPath;

    // : /page.do  null
    private String _pathInfo = null;

    // : name=jack&pwd=123
    private String _queryString;

    /**
     * Request QueryString Extracted flag.
     */
    private boolean _queryStringExtracted;

    private DispatcherType _dispatcherType;

    private HttpMethod _httpMethod;

    // Parameters from query string and form HttpServletRequestImpl Body(application/x-www-form-urlencoded [POST |PUT])
    private Map<String, List<String>> _parameters;

    private int _port;
    private HttpVersion _httpVersion = HttpVersion.HTTP_1_1;
    private String _queryEncoding;

    private BufferedReader _reader;

    private String _readerEncoding;

    private InetSocketAddress _remote;

    private String _requestedSessionId;

    private String _requestURI;

    private String _scheme = "http";

    private String _serverName;

    private HttpSessionImpl _session;
    private SessionManager _sessionManager;

    //true: has try to Extracte the sessionid
    private boolean _sessionIdExtracted;

    private boolean _isSessionIdFromCookie;

    private long _timeStamp;
    private long _dispatchTime;

    /**
     * The set of cookies associated with this HttpServletRequestImpl.
     */
    protected Cookie[] cookies = null;

    /**
     * The preferred Locales associated with this HttpServletRequestImpl.
     */
    protected List<Locale> _locales;

    /**
     * Parse _locales.
     */
    protected boolean localesParsed = false;

    /* ------------------------------------------------------------ */
    public HttpServletRequestImpl(WebApp webApp, ServletContext servletContext, SocketChannel socketChannel,
            ChannelHandlerContext ctx, FullHttpResponse response, FullHttpRequest request,
            HttpServletResponseImpl httpResponse) {
        this.servletContext = servletContext;

        this._sessionManager = webApp.getSessionManager();

        this.socketChannel = socketChannel;
        this.ctx = ctx;
        this.response = response;
        this.request = request;

        _httpResponse = httpResponse;

        this.headers = request.headers();
        this.body = request;

    }

    /* ------------------------------------------------------------ */
    public void addEventListener(final EventListener listener) {
        if (listener instanceof ServletRequestAttributeListener) {
            if (_requestAttributeListeners == null)
                _requestAttributeListeners = new ArrayList<ServletRequestAttributeListener>();

            _requestAttributeListeners.add((ServletRequestAttributeListener) listener);
        }

        if (listener instanceof AsyncListener)
            throw new IllegalArgumentException(listener.getClass().toString());
    }

    /* ------------------------------------------------------------ */
    /**
     * Extract Parameters from query string and form HttpServletRequestImpl Body(application/x-www-form-urlencoded [POST
     * | PUT])
     */
    public void extractParameters() {

        if (_paramsExtracted)
            return;

        _paramsExtracted = true;

        if (_parameters == null)
            _parameters = new HashMap<String, List<String>>();

        // Handle query string

        if (_queryEncoding == null) {
            QueryStringDecoder queryStringDecoder = new QueryStringDecoder(request.getUri());

            _parameters.putAll(queryStringDecoder.parameters());

        } else {
            try {
                QueryStringDecoder queryStringDecoder = new QueryStringDecoder(request.getUri(),
                        Charset.forName(_queryEncoding));

                _parameters.putAll(queryStringDecoder.parameters());

            } catch (UnsupportedCharsetException e) {
                if (LOG.isDebugEnabled())
                    LOG.warn(e);
                else
                    LOG.warn(e.toString());
            }
        }

        // handle form _content (application/x-www-form-urlencoded)
        String encoding = getCharacterEncoding();
        String content_type = getContentType();

        if (content_type != null && content_type.length() > 0) {
            content_type = ContentTypeUtil.getContentTypeWithoutCharset(content_type);

            // application/x-www-form-urlencoded( POST or PUT )
            if (HttpHeaders.Values.APPLICATION_X_WWW_FORM_URLENCODED.equals(content_type)
                    && (HttpMethod.POST.name().equals(getMethod()) || HttpMethod.PUT.name().equals(getMethod()))) {
                int content_length = getContentLength();
                if (content_length > 0) {
                    try {
                        Charset bodyCharset = Charset.forName(encoding);
                        String bodyContent = new String(getRowBodyContent(), bodyCharset);

                        // Add form params to query params
                        QueryStringDecoder queryStringDecoder = new QueryStringDecoder(bodyContent, bodyCharset,
                                false);

                        if (_parameters == null)
                            _parameters = queryStringDecoder.parameters();
                        else//merge
                        {
                            Map<String, List<String>> map = queryStringDecoder.parameters();

                            for (Entry<String, List<String>> e : map.entrySet()) {
                                if (!_parameters.containsKey(e.getKey())) {
                                    _parameters.put(e.getKey(), e.getValue());
                                } else// parameter with the same name exist,merge
                                {
                                    List<String> value = _parameters.get(e.getKey());

                                    if (value == null)
                                        _parameters.put(e.getKey(), e.getValue());
                                    else {
                                        value.addAll(e.getValue()); // merge
                                        _parameters.put(e.getKey(), value);
                                    }
                                }
                            }
                        }
                    } catch (Exception e) {
                        if (LOG.isDebugEnabled())
                            e.printStackTrace();
                        else
                            LOG.warn(e.toString());
                    }
                }
            }
        }
    }

    /**
     * 
     * @return the content of HttpServletRequestImpl Body,as byte array. this method will not change the read / write
     *         index of body
     */
    private byte[] getRowBodyContent() {
        // get [0,writerIndex) of body.date();
        if (bodyContent == null) {
            int content_length = body.content().writerIndex(); // [0,writerIndex)

            int old_readerIndex = body.content().readerIndex();// resver the old_readrIndex

            byte[] data = new byte[content_length];

            body.content().readerIndex(0);

            body.content().readBytes(data, 0, content_length);

            body.content().readerIndex(old_readerIndex); // recover the readerIndex

            bodyContent = data;
        }

        return bodyContent;
    }

    /* ------------------------------------------------------------ */
    @Override
    public AsyncContext getAsyncContext() {
        /*
         * HttpChannelState continuation = getHttpChannelState(); if (continuation.isInitial() &&
         * !continuation.isAsync()) throw new IllegalStateException(continuation.getStatusString()); return
         * continuation;
         */
        // throw new UnsupportedOperationException();
        return null;
    }

    /* ------------------------------------------------------------ */
    /*
     * @see javax.servlet.ServletRequest#getAttribute(java.lang.String)
     */
    @Override
    // OK
    public Object getAttribute(String name) {
        return (_attributes == null) ? null : _attributes.get(name);
    }

    /* ------------------------------------------------------------ */
    /*
     * @see javax.servlet.ServletRequest#getAttributeNames()
     */
    @Override
    // OK
    public Enumeration<String> getAttributeNames() {
        // Take a copy to prevent ConncurrentModificationExceptions if used to
        // remove attributes
        Set<String> names = new HashSet<String>();
        names.addAll(_attributes.keySet());
        return Collections.enumeration(names);
    }

    /* ------------------------------------------------------------ */
    /*
      */
    public Map<String, Object> getAttributes() {
        if (_attributes == null)
            _attributes = new HashMap();
        return _attributes;
    }

    /* ------------------------------------------------------------ */
    /*
     * @see javax.servlet.http.HttpServletRequest#getAuthType()
     */
    @Override
    public String getAuthType() {
        return null;
    }

    /* ------------------------------------------------------------ */
    /*
     * @see javax.servlet.ServletRequest#getCharacterEncoding()
     */
    @Override
    // OK
    public String getCharacterEncoding() {
        if (_characterEncoding == null) {
            _characterEncoding = ContentTypeUtil.getCharsetFromContentType(getContentType());
        }

        return _characterEncoding;
    }

    /* ------------------------------------------------------------ */
    /**
     * @return Returns the connection.
     */
    public SocketChannel getHttpChannel() {
        return socketChannel;
    }

    /* ------------------------------------------------------------ */
    /*
     * @see javax.servlet.ServletRequest#getContentLength()
     */
    @Override
    // OK
    public int getContentLength() {
        long length = HttpHeaders.getContentLength(request, -1);

        return (int) ((length <= Integer.MAX_VALUE) ? length : -1);
    }

    /* ------------------------------------------------------------ */
    /*
     * @see javax.servlet.ServletRequest#getContentType()
     * 
     * example: "text/css;charset=UTF-8"
     */
    @Override
    // OK
    public String getContentType() {
        if (_contentType == null)
            _contentType = getHeader(HttpHeaders.Names.CONTENT_TYPE);

        return _contentType;
    }

    /* ------------------------------------------------------------ */
    /*
     * @see javax.servlet.http.HttpServletRequest#getContextPath()
     */
    @Override
    public String getContextPath() {
        if (servletContext == null)
            return "";

        return servletContext.getContextPath();
    }

    /* ------------------------------------------------------------ */
    /*
     * @see javax.servlet.http.HttpServletRequest#getCookies()
     */
    @Override
    // OK
    public Cookie[] getCookies() {
        if (!_cookiesExtracted)
            extracteCookie();

        return cookies;
    }

    /**
     * Extracte cookies.
     */
    protected void extracteCookie() {
        _cookiesExtracted = true;

        // Decode the cookie.
        String cookieString = headers.get(HttpHeaders.Names.COOKIE);
        if (cookieString != null) {
            Set<io.netty.handler.codec.http.Cookie> _cookies = CookieDecoder.decode(cookieString);

            this.cookies = new Cookie[_cookies.size()];

            int i = 0;

            // Convent netty's Cookie to Servlet's Cookie
            for (io.netty.handler.codec.http.Cookie c : _cookies) {
                Cookie cookie = new Cookie(c.getName(), c.getValue());

                cookie.setComment(c.getComment());

                if (c.getDomain() != null)
                    cookie.setDomain(c.getDomain());

                cookie.setHttpOnly(c.isHttpOnly());
                cookie.setMaxAge((int) c.getMaxAge());
                cookie.setPath(c.getPath());
                cookie.setSecure(c.isSecure());
                cookie.setVersion(c.getVersion());

                this.cookies[i] = cookie;
                i++;
            }
        }
    }

    /* ------------------------------------------------------------ */
    /*
     * @see javax.servlet.http.HttpServletRequest#getDateHeader(java.lang.String)
     */
    @Override
    // OK
    public long getDateHeader(String name) {
        Date date = HttpHeaders.getDateHeader(request, name, null);

        return (date == null) ? -1 : date.getTime();
    }

    /* ------------------------------------------------------------ */
    @Override
    // OK
    public DispatcherType getDispatcherType() {
        return _dispatcherType;
    }

    /* ------------------------------------------------------------ */
    /*
     * @see javax.servlet.http.HttpServletRequest#getHeader(java.lang.String)
     */
    @Override
    // ok
    public String getHeader(String name) {
        return headers.get(name);
    }

    /* ------------------------------------------------------------ */
    /*
     * @see javax.servlet.http.HttpServletRequest#getHeaderNames()
     */
    @Override
    // OK
    public Enumeration<String> getHeaderNames() {
        return Collections.enumeration(headers.names());
    }

    /* ------------------------------------------------------------ */
    /*
     * @see javax.servlet.http.HttpServletRequest#getHeaders(java.lang.String)
     */
    @Override
    // OK
    public Enumeration<String> getHeaders(String name) {
        List<String> e = headers.getAll(name);
        if (e == null)
            return Collections.enumeration(Collections.<String>emptyList());

        return Collections.enumeration(e);
    }

    /* ------------------------------------------------------------ */
    /*
     * @see javax.servlet.ServletRequest#getInputStream()
     */
    @Override
    // OK
    public ServletInputStream getInputStream() throws IOException {
        if (usingReader) {
            throw new IllegalStateException("Already using Reader");
        }

        usingInputStream = true;
        if (inputStream == null) {
            inputStream = new ByteBufServletInputStream(body.content());
        }
        return inputStream;
    }

    /* ------------------------------------------------------------ */
    /*
     * @see javax.servlet.http.HttpServletRequest#getIntHeader(java.lang.String)
     */
    @Override
    // OK
    public int getIntHeader(String name) {
        return HttpHeaders.getIntHeader(request, name, -1);
    }

    /* ------------------------------------------------------------ */
    /*
     * @see javax.servlet.ServletRequest#getLocale()
     */
    @Override
    public Locale getLocale() {

        if (!localesParsed) {
            parseLocales();
        }

        if (_locales.size() > 0) {
            return _locales.get(0);
        }

        return defaultLocale;
    }

    /* ------------------------------------------------------------ */
    /*
     * @see javax.servlet.ServletRequest#getLocales()
     */
    @Override
    public Enumeration<Locale> getLocales() {

        if (!localesParsed) {
            parseLocales();
        }

        if (_locales.size() > 0) {
            return Collections.enumeration(_locales);
        }
        List<Locale> results = new LinkedList<Locale>();
        results.add(defaultLocale);
        return Collections.enumeration(results);

    }

    /**
     * Parse request _locales.
     */
    protected void parseLocales() {

        localesParsed = true;

        Enumeration<String> values = getHeaders(HttpHeaders.Names.ACCEPT_LANGUAGE);

        while (values.hasMoreElements()) {
            String value = values.nextElement();
            parseLocalesHeader(value);
        }

    }

    /**
     * Parse accept-language header value.
     */
    protected void parseLocalesHeader(String value) {
        if (parser == null)
            parser = new StringParser();

        // Store the accumulated languages that have been requested in
        // a local collection, sorted by the quality value (so we can
        // add Locales in descending order). The values will be ArrayLists
        // containing the corresponding Locales to be added
        TreeMap<Double, ArrayList<Locale>> locales = new TreeMap<Double, ArrayList<Locale>>();

        // Preprocess the value to remove all whitespace
        int white = value.indexOf(' ');
        if (white < 0) {
            white = value.indexOf('\t');
        }
        if (white >= 0) {
            StringBuilder sb = new StringBuilder();
            int len = value.length();
            for (int i = 0; i < len; i++) {
                char ch = value.charAt(i);
                if ((ch != ' ') && (ch != '\t')) {
                    sb.append(ch);
                }
            }
            parser.setString(sb.toString());
        } else {
            parser.setString(value);
        }

        // Process each comma-delimited language specification
        int length = parser.getLength();
        while (true) {

            // Extract the next comma-delimited entry
            int start = parser.getIndex();
            if (start >= length) {
                break;
            }
            int end = parser.findChar(',');
            String entry = parser.extract(start, end).trim();
            parser.advance(); // For the following entry

            // Extract the quality factor for this entry
            double quality = 1.0;
            int semi = entry.indexOf(";q=");
            if (semi >= 0) {
                try {
                    String strQuality = entry.substring(semi + 3);
                    if (strQuality.length() <= 5) {
                        quality = Double.parseDouble(strQuality);
                    } else {
                        quality = 0.0;
                    }
                } catch (NumberFormatException e) {
                    quality = 0.0;
                }
                entry = entry.substring(0, semi);
            }

            // Skip entries we are not going to keep track of
            if (quality < 0.00005) {
                continue; // Zero (or effectively zero) quality factors
            }
            if ("*".equals(entry)) {
                continue; // FIXME - "*" entries are not handled
            }

            // Extract the language and country for this entry
            String language = null;
            String country = null;
            String variant = null;
            int dash = entry.indexOf('-');
            if (dash < 0) {
                language = entry;
                country = "";
                variant = "";
            } else {
                language = entry.substring(0, dash);
                country = entry.substring(dash + 1);
                int vDash = country.indexOf('-');
                if (vDash > 0) {
                    String cTemp = country.substring(0, vDash);
                    variant = country.substring(vDash + 1);
                    country = cTemp;
                } else {
                    variant = "";
                }
            }
            if (!isAlpha(language) || !isAlpha(country) || !isAlpha(variant)) {
                continue;
            }

            // Add a new Locale to the list of Locales for this quality level
            Locale locale = new Locale(language, country, variant);
            Double key = new Double(-quality); // Reverse the order
            ArrayList<Locale> values = locales.get(key);
            if (values == null) {
                values = new ArrayList<Locale>();
                locales.put(key, values);
            }
            values.add(locale);

        }

        // Process the quality values in highest->lowest order (due to
        // negating the Double value when creating the key)
        for (ArrayList<Locale> list : locales.values()) {
            for (Locale locale : list) {
                addLocale(locale);
            }
        }

    }

    protected static final boolean isAlpha(String value) {
        for (int i = 0; i < value.length(); i++) {
            char c = value.charAt(i);
            if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))) {
                return false;
            }
        }
        return true;
    }

    /**
     * Add a Locale to the set of preferred Locales for this HttpServletRequestImpl. The first added Locale will be the
     * first one returned by getLocales().
     * 
     * @param locale
     *            The new preferred Locale
     */
    public void addLocale(Locale locale) {
        if (_locales == null)
            _locales = new LinkedList<Locale>();
        _locales.add(locale);
    }

    /* ------------------------------------------------------------ */
    /*
     * @see javax.servlet.ServletRequest#getLocalAddr()
     */
    @Override
    // OK
    public String getLocalAddr() {
        InetSocketAddress local = socketChannel.localAddress();
        if (local == null)
            return "";
        InetAddress address = local.getAddress();
        if (address == null)
            return local.getHostString();
        return address.getHostAddress();
    }

    /* ------------------------------------------------------------ */
    /*
     * @see javax.servlet.ServletRequest#getLocalName()
     */
    @Override
    // ok
    public String getLocalName() {
        InetSocketAddress local = socketChannel.localAddress();
        return local.getHostString();
    }

    /* ------------------------------------------------------------ */
    /*
     * @see javax.servlet.ServletRequest#getLocalPort()
     */
    @Override
    // OK
    public int getLocalPort() {
        InetSocketAddress local = socketChannel.localAddress();
        return local.getPort();
    }

    /* ------------------------------------------------------------ */
    /*
     * @see javax.servlet.http.HttpServletRequest#getMethod()
     */
    @Override
    // OK
    public String getMethod() {
        return request.getMethod().toString();
    }

    /* ------------------------------------------------------------ */
    /*
     * @see javax.servlet.ServletRequest#getParameter(java.lang.String)
     */
    @Override
    // OK
    public String getParameter(String name) {
        if (!_paramsExtracted)
            extractParameters();
        List<String> list = _parameters.get(name);

        if (list == null || list.isEmpty())
            return null;

        return list.get(0);
    }

    /* ------------------------------------------------------------ */
    /*
     * @see javax.servlet.ServletRequest#getParameterMap()
     */
    @Override
    // OK
    public Map<String, String[]> getParameterMap() {
        if (!_paramsExtracted)
            extractParameters();

        HashMap<String, String[]> map = new HashMap<String, String[]>(_parameters.size() * 3 / 2);

        for (Map.Entry<String, List<String>> entry : _parameters.entrySet()) {
            String[] a = null;
            if (entry.getValue() != null) {
                a = new String[entry.getValue().size()];
                a = entry.getValue().toArray(a);
            }
            map.put(entry.getKey(), a);
        }

        return Collections.unmodifiableMap(map);
    }

    /* ------------------------------------------------------------ */
    /*
     * @see javax.servlet.ServletRequest#getParameterNames()
     */
    @Override
    // OK
    public Enumeration<String> getParameterNames() {
        if (!_paramsExtracted)
            extractParameters();
        return Collections.enumeration(_parameters.keySet());
    }

    /* ------------------------------------------------------------ */
    /**
     * @return Returns the parameters.
     */
    /*
     * public MultiMap<String> getParameters() { return _parameters; }
     */

    /* ------------------------------------------------------------ */
    /*
     * @see javax.servlet.ServletRequest#getParameterValues(java.lang.String)
     */
    @Override
    // ok
    public String[] getParameterValues(String name) {
        if (!_paramsExtracted)
            extractParameters();
        List<String> vals = _parameters.get(name);
        if (vals == null)
            return null;
        return vals.toArray(new String[vals.size()]);
    }

    /* ------------------------------------------------------------ */
    /*
     * @see javax.servlet.http.HttpServletRequest#getPathInfo()
     */
    @Override
    public String getPathInfo() {
        if (_invocation != null)
            return _invocation.getFilterChainInvocation().getPathInfo();
        else
            return null;
    }

    /* ------------------------------------------------------------ */
    /*
     * @see javax.servlet.http.HttpServletRequest#getPathTranslated()
     */
    @Override
    public String getPathTranslated() {
        if (_pathInfo == null || servletContext == null)
            return null;
        return servletContext.getRealPath(_pathInfo);
    }

    /* ------------------------------------------------------------ */
    /*
     * @see javax.servlet.ServletRequest#getProtocol()
     */
    @Override
    // OK
    public String getProtocol() {
        return _httpVersion.toString();
    }

    /* ------------------------------------------------------------ */
    /*
     * @see javax.servlet.ServletRequest#getProtocol()
     */
    public HttpVersion getHttpVersion() {
        return _httpVersion;
    }

    /* ------------------------------------------------------------ */
    public String getQueryEncoding() {
        return _queryEncoding;
    }

    /* ------------------------------------------------------------ */
    /*
     * @see javax.servlet.http.HttpServletRequest#getQueryString()
     */
    @Override
    public String getQueryString() {
        if (_invocation != null)
            return _invocation.getQueryString();
        else
            return null;
    }

    /**
     * uri??RequestURI?QueryString
     * 
     * @return
     */
    boolean parseRequestURIAndQueryString() {
        if (_queryString == null || _requestURI == null) {
            if (_queryEncoding == null) {
                String uri = request.getUri();

                int p = uri.indexOf('?');

                if (p != -1)
                    _queryString = uri.substring(p + 1);

                // ?requestURI
                if (p == -1)
                    _requestURI = uri;
                else
                    _requestURI = uri.substring(0, p);
            } else {
                // TODO: what about other queryEncoding?
            }
        }

        _queryStringExtracted = true;

        return true;
    }

    /* ------------------------------------------------------------ */
    /*
     * @see javax.servlet.ServletRequest#getReader()
     */
    @Override
    // ok
    public BufferedReader getReader() throws IOException {
        if (usingInputStream) {
            throw new IllegalStateException("using InputStream already");
        }

        usingReader = true;

        String encoding = getCharacterEncoding();

        if (encoding == null)
            encoding = "ISO-8859-1";

        if (_reader == null || !encoding.equalsIgnoreCase(_readerEncoding)) {
            final ServletInputStream in = getInputStream();
            _readerEncoding = encoding;
            _reader = new BufferedReader(new InputStreamReader(in, encoding)) {
                @Override
                public void close() throws IOException {
                    in.close();
                }
            };
        }

        return _reader;
    }

    /* ------------------------------------------------------------ */
    /*
     * @see javax.servlet.ServletRequest#getRealPath(java.lang.String)
     */
    @Deprecated
    @Override
    public String getRealPath(String path) {
        if (servletContext == null)
            return null;
        return servletContext.getRealPath(path);
    }

    /* ------------------------------------------------------------ */
    /*
     * @see javax.servlet.ServletRequest#getRemoteAddr()
     */
    @Override
    // OK
    public String getRemoteAddr() {
        InetSocketAddress remote = _remote;
        if (remote == null)
            remote = socketChannel.remoteAddress();

        if (remote == null)
            return "";

        InetAddress address = remote.getAddress();
        if (address == null)
            return remote.getHostString();

        return address.getHostAddress();
    }

    /* ------------------------------------------------------------ */
    /*
     * @see javax.servlet.ServletRequest#getRemoteHost()
     */
    @Override
    // OK
    public String getRemoteHost() {
        InetSocketAddress remote = _remote;
        if (remote == null)
            remote = socketChannel.remoteAddress();
        return remote == null ? "" : remote.getHostString();
    }

    /* ------------------------------------------------------------ */
    /*
     * @see javax.servlet.ServletRequest#getRemotePort()
     */
    @Override
    // OK
    public int getRemotePort() {
        InetSocketAddress remote = _remote;

        if (remote == null)
            remote = socketChannel.remoteAddress();

        return remote == null ? 0 : remote.getPort();
    }

    /* ------------------------------------------------------------ */
    /*
     * @see javax.servlet.http.HttpServletRequest#getRemoteUser()
     */
    @Override
    // ok
    public String getRemoteUser() {
        Principal p = getUserPrincipal();
        if (p == null)
            return null;
        return p.getName();
    }

    /* ------------------------------------------------------------ */
    /*
     * @see javax.servlet.ServletRequest#getRequestDispatcher(java.lang.String)
     */
    @Override
    public RequestDispatcher getRequestDispatcher(String path) {
        if (path == null || servletContext == null)
            return null;

        // handle relative path
        if (!path.startsWith("/")) {
            String relTo = URIUtil.addPaths(_servletPath, _pathInfo);
            int slash = relTo.lastIndexOf("/");
            if (slash > 1)
                relTo = relTo.substring(0, slash + 1);
            else
                relTo = "/";
            path = URIUtil.addPaths(relTo, path);
        }

        return servletContext.getRequestDispatcher(path);
    }

    /* ------------------------------------------------------------ */
    /*
     * @see javax.servlet.http.HttpServletRequest#getRequestedSessionId()
     */
    @Override
    public String getRequestedSessionId() {
        return _requestedSessionId;
    }

    /* ------------------------------------------------------------ */
    /*
     * @see javax.servlet.http.HttpServletRequest#getRequestURI()
     */
    @Override
    public String getRequestURI() {
        if (_invocation != null)
            return _invocation.getFilterChainInvocation().getRequestURI();
        else
            return "";
    }

    /* ------------------------------------------------------------ */
    /*
     * @see javax.servlet.http.HttpServletRequest#getRequestURL()
     */
    @Override
    public StringBuffer getRequestURL() {
        final StringBuffer url = new StringBuffer(48);
        String scheme = getScheme();
        int port = getServerPort();

        url.append(scheme);
        url.append("://");
        url.append(getServerName());
        if (_port > 0 && ((scheme.equalsIgnoreCase(URIUtil.HTTP) && port != 80)
                || (scheme.equalsIgnoreCase(URIUtil.HTTPS) && port != 443))) {
            url.append(':');
            url.append(_port);
        }

        url.append(getRequestURI());
        return url;
    }

    /* ------------------------------------------------------------ */
    /**
     * Reconstructs the URL the client used to make the request. The returned URL contains a protocol, server name, port
     * number, and, but it does not include a path.
     * <p>
     * Because this method returns a <code>StringBuffer</code>, not a string, you can modify the URL easily, for
     * example, to append path and query parameters.
     * 
     * This method is useful for creating redirect messages and for reporting errors.
     * 
     * @return "scheme://host:port"
     */
    public StringBuilder getRootURL() {
        StringBuilder url = new StringBuilder(48);
        String scheme = getScheme();
        int port = getServerPort();

        url.append(scheme);
        url.append("://");
        url.append(getServerName());

        if (port > 0 && ((scheme.equalsIgnoreCase("http") && port != 80)
                || (scheme.equalsIgnoreCase("https") && port != 443))) {
            url.append(':');
            url.append(port);
        }
        return url;
    }

    /* ------------------------------------------------------------ */
    /*
     * @see javax.servlet.ServletRequest#getScheme()
     */
    @Override
    public String getScheme() {
        return _scheme;
    }

    /* ------------------------------------------------------------ */
    /*
     * @see javax.servlet.ServletRequest#getServerName()
     */
    @Override
    // OK
    public String getServerName() {
        if (_serverName == null) {
            parseServerNameAndServerPort();
        }

        return _serverName;
    }

    /**
     * 1:Return host from header field "Host"
     * 
     * OR:2:Return host from connection
     * 
     * 3:Return the local host
     */
    private void parseServerNameAndServerPort() {
        // Return host from header field
        String hostPort = getHeader(HttpHeaders.Names.HOST);
        if (hostPort != null) {
            loop: for (int i = hostPort.length(); i-- > 0;) {
                char ch = (char) (0xff & hostPort.charAt(i));
                switch (ch) {
                case ']':
                    break loop;

                case ':':
                    _serverName = hostPort.substring(0, i);
                    try {
                        _port = Integer.parseInt(hostPort.substring(i + 1));
                    } catch (NumberFormatException e) {
                        LOG.warn(e);
                    }
                    return;
                }
            }

            if (_serverName == null || _port < 0) {
                _serverName = hostPort;
                _port = 0;
            }

            return;
        }

        // Return host from connection
        if (socketChannel != null) {
            _serverName = getLocalName();
            _port = getLocalPort();
            if (_serverName != null && !"0.0.0.0".equals(_serverName))
                return;
        }

        // Return the local host
        try {
            _serverName = InetAddress.getLocalHost().getHostAddress();
        } catch (java.net.UnknownHostException e) {
            LOG.debug(e);
        }
    }

    /* ------------------------------------------------------------ */
    /*
     * @see javax.servlet.ServletRequest#getServerPort()
     */
    @Override
    public int getServerPort() {
        if (_port <= 0) {
            if (_serverName == null)
                parseServerNameAndServerPort();

            if (_port <= 0) {
                InetSocketAddress local = socketChannel.localAddress();
                _port = local == null ? 0 : local.getPort();
            }
        }

        if (_port <= 0) {
            if (getScheme().equalsIgnoreCase("https"))
                return 443;
            return 80;
        }
        return _port;
    }

    /* ------------------------------------------------------------ */
    @Override
    // ok
    public ServletContext getServletContext() {
        return servletContext;
    }

    /* ------------------------------------------------------------ */
    /*
      */
    /*
     * public String getServletName() { if (_scope != null) return _scope.getName(); return null; }
     */
    /* ------------------------------------------------------------ */
    /*
     * @see javax.servlet.http.HttpServletRequest#getServletPath()
     */
    @Override
    public String getServletPath() {
        if (_invocation != null)
            return _invocation.getFilterChainInvocation().getServletPath();
        else
            return "";
    }

    /* ------------------------------------------------------------ */

    /**
     * cookieURL???SessionId
     * @return
     */
    protected String extracteSessionId() {
        String sessionId = findSessionIdFromCookie();

        _sessionIdExtracted = true;
        return sessionId;
    }

    /**
     * Returns the session id in the HTTP request cookies. Because the webApp might use the cookie to change the page
     * contents, the caching sets vary: JSESSIONID.
     */
    protected String findSessionIdFromCookie() {
        Cookie cookie = getCookie("JSESSIONID");

        if (cookie != null) {
            _isSessionIdFromCookie = true;
            return cookie.getValue();
        } else
            return null;
    }

    /**
     * ??cookie
     * Returns the named cookie from the browser
     */
    public Cookie getCookie(String name) {
        Cookie[] cookies = getCookies();

        if (cookies == null)
            return null;

        for (Cookie cookie : cookies) {
            if (cookie.getName().equals(name)) {
                return cookie;
            }
        }

        return null;
    }

    /* ------------------------------------------------------------ */
    /*
     * @see javax.servlet.http.HttpServletRequest#getSession()
     */
    @Override
    public HttpSession getSession() {
        return getSession(true);
    }

    /* ------------------------------------------------------------ */
    /*
     * @see javax.servlet.http.HttpServletRequest#getSession(boolean)
     */
    @Override
    public HttpSession getSession(boolean create) {
        if (_session != null) {
            if (_sessionManager.isValid(_session))
                return _session;
            else
            // Session
            {
                _session.invalidate();
                _session = null;
            }
        }

        //COOKIEURLSESSIONID,try to extract sessionId from cookie OR URL
        if (!_sessionIdExtracted) {
            String sessionId = extracteSessionId();

            if (sessionId != null) {
                HttpSessionImpl session = _sessionManager.getSession(sessionId);

                if (session != null && _sessionManager.isValid(session)) {
                    _session = session;
                    return _session;
                }
            }
        }

        if (!create)
            return null;

        // Session
        if (_sessionManager == null)
            throw new IllegalStateException("No SessionManager");

        _session = _sessionManager.createNewSession(this);

        Cookie cookie = _sessionManager.getSessionCookie(_session, getContextPath(), isSecure());

        if (cookie != null) {
            _httpResponse.addCookie(cookie);
        }

        return _session;

    }

    /* ------------------------------------------------------------ */
    /**
     * @return Returns the sessionManager.
     */
    public SessionManager getSessionManager() {
        return _sessionManager;
    }

    /* ------------------------------------------------------------ */
    /**
     * Get HttpServletRequestImpl TimeStamp
     * 
     * @return The time that the request was received.
     */
    public long getTimeStamp() {
        return _timeStamp;
    }

    /* ------------------------------------------------------------ */
    /*
     * @see javax.servlet.http.HttpServletRequest#getUserPrincipal()
     */
    @Override
    public Principal getUserPrincipal() {
        /*
         * if (_authentication instanceof Authentication.Deferred)
         * setAuthentication(((Authentication.Deferred)_authentication).authenticate(this));
         * 
         * if (_authentication instanceof Authentication.User) { UserIdentity user =
         * ((Authentication.User)_authentication).getUserIdentity(); return user.getUserPrincipal(); }
         * 
         * return null;
         */
        return null;
    }

    /* ------------------------------------------------------------ */
    /**
     * Get timestamp of the request dispatch
     * 
     * @return timestamp
     */
    public long getDispatchTime() {
        return _dispatchTime;
    }

    /* ------------------------------------------------------------ */
    public boolean isHandled() {
        return _handled;
    }

    @Override
    public boolean isAsyncStarted() {
        //TODO:NOT support now
        return false;
    }

    /* ------------------------------------------------------------ */
    @Override
    public boolean isAsyncSupported() {
        return _asyncSupported;
    }

    /* ------------------------------------------------------------ */
    /*
     * @see javax.servlet.http.HttpServletRequest#isRequestedSessionIdFromCookie()
     */
    @Override
    public boolean isRequestedSessionIdFromCookie() {
        return _requestedSessionId != null && _isSessionIdFromCookie;
    }

    /* ------------------------------------------------------------ */
    /*
     * @see javax.servlet.http.HttpServletRequest#isRequestedSessionIdFromUrl()
     */
    @Override
    public boolean isRequestedSessionIdFromUrl() {
        return _requestedSessionId != null && !_isSessionIdFromCookie;
    }

    /* ------------------------------------------------------------ */
    /*
     * @see javax.servlet.http.HttpServletRequest#isRequestedSessionIdFromURL()
     */
    @Override
    public boolean isRequestedSessionIdFromURL() {
        return _requestedSessionId != null && !_isSessionIdFromCookie;
    }

    /* ------------------------------------------------------------ */
    /*
     * @see javax.servlet.http.HttpServletRequest#isRequestedSessionIdValid()
     */
    @Override
    public boolean isRequestedSessionIdValid() {
        if (_requestedSessionId == null)
            return false;

        HttpSession session = getSession(false);
        return (session != null);
    }

    /* ------------------------------------------------------------ */
    /*
     * @see javax.servlet.ServletRequest#isSecure()
     */
    @Override
    public boolean isSecure() {
        return _secure;
    }

    /* ------------------------------------------------------------ */
    public void setSecure(boolean secure) {
        _secure = secure;
    }

    /* ------------------------------------------------------------ */
    /*
     * @see javax.servlet.http.HttpServletRequest#isUserInRole(java.lang.String)
     */
    @Override
    public boolean isUserInRole(String role) {
        /*
         * if (_authentication instanceof Authentication.Deferred)
         * setAuthentication(((Authentication.Deferred)_authentication).authenticate(this));
         * 
         * if (_authentication instanceof Authentication.User) return
         * ((Authentication.User)_authentication).isUserInRole(_scope,role); return false;
         */
        //TODO: 
        return false;
    }

    /* ------------------------------------------------------------ */
    protected void recycle() {
        _asyncSupported = true;
        _handled = false;
        if (servletContext != null)
            throw new IllegalStateException("HttpServletRequestImpl in context!");
        if (_attributes != null)
            _attributes.clear();
        _characterEncoding = null;
        _contextPath = null;

        _cookiesExtracted = false;
        _serverName = null;
        _pathInfo = null;
        _port = 0;
        _httpVersion = HttpVersion.HTTP_1_1;
        _queryEncoding = null;
        _queryString = null;
        _requestedSessionId = null;
        _isSessionIdFromCookie = false;
        _session = null;
        _sessionManager = null;
        _requestURI = null;
        // _scope = null;
        _scheme = URIUtil.HTTP;
        _servletPath = null;
        _timeStamp = 0;
        // _uri = null;
        if (_parameters != null)
            _parameters.clear();
        _parameters = null;
        _paramsExtracted = false;

        _remote = null;
        headers.clear();
    }

    /* ------------------------------------------------------------ */
    /*
     * @see javax.servlet.ServletRequest#removeAttribute(java.lang.String)
     */
    @Override
    // OK
    public void removeAttribute(String name) {
        if (_attributes == null)
            return;

        //
        boolean found = _attributes.containsKey(name);
        if (found) {
            Object value = _attributes.get(name);
            _attributes.remove(name);

            // Notify interested application event listeners
            notifyAttributeRemoved(name, value);
        }
    }

    /* ------------------------------------------------------------ */
    public void removeEventListener(final EventListener listener) {
        if (_requestAttributeListeners != null)
            _requestAttributeListeners.remove(listener);
    }

    /* ------------------------------------------------------------ */
    public void setAsyncSupported(boolean supported) {
        _asyncSupported = supported;
    }

    /* ------------------------------------------------------------ */
    /*
     * Set a request attribute. if the attribute name is "org.eclipse.jetty.server.server.Request.queryEncoding" then
     * the value is also passed in a call to {@link #setQueryEncoding}. <p> if the attribute name is
     * "org.eclipse.jetty.server.server.ResponseBuffer", then the response buffer is flushed with @{link
     * #flushResponseBuffer} <p> if the attribute name is "org.eclipse.jetty.io.EndPoint.maxIdleTime", then the value is
     * passed to the associated {@link EndPoint#setIdleTimeout}.
     * 
     * @see javax.servlet.ServletRequest#setAttribute(java.lang.String, java.lang.Object)
     */
    @Override
    // OK
    public void setAttribute(String name, Object value) {
        // Name cannot be null
        if (name == null) {
            throw new IllegalArgumentException("Name cannot be null");
        }

        // Null value is the same as removeAttribute()
        if (value == null) {
            removeAttribute(name);
            return;
        }

        if (_attributes == null)
            _attributes = new HashMap<String, Object>();

        Object oldValue = _attributes.put(name, value);

        // Notify interested ServletRequestAttributeListeners
        if (oldValue == null)
            notifyAttributeAdded(name, value);
        else
            notifyAttributeReplaced(name, oldValue);
    }

    /* ------------------------------------------------------------ */

    /**
     * Notify interested ServletRequestAttributeListeners that attribute has been assigned a value.
     * 
     * ?
     * 
     */
    private void notifyAttributeAdded(String name, Object value) {
        if (_requestAttributeListeners != null && !_requestAttributeListeners.isEmpty()) {
            final ServletRequestAttributeEvent event = new ServletRequestAttributeEvent(servletContext, this, name,
                    value);

            for (ServletRequestAttributeListener listener : _requestAttributeListeners) {
                listener.attributeAdded(event);
            }
        }
    }

    /**
     * Notify interested ServletRequestAttributeListeners that attribute has been Replaced.
     * 
     * ??
     */
    private void notifyAttributeReplaced(String name, Object oldValue) {
        if (_requestAttributeListeners != null && !_requestAttributeListeners.isEmpty()) {
            final ServletRequestAttributeEvent event = new ServletRequestAttributeEvent(servletContext, this, name,
                    oldValue);

            for (ServletRequestAttributeListener listener : _requestAttributeListeners) {
                listener.attributeReplaced(event);
            }
        }
    }

    /* ------------------------------------------------------------ */
    /**
     * Notify interested listeners that attribute has been removed. ?
     */
    private void notifyAttributeRemoved(String name, Object value) {
        if (_requestAttributeListeners != null && !_requestAttributeListeners.isEmpty()) {
            final ServletRequestAttributeEvent event = new ServletRequestAttributeEvent(servletContext, this, name,
                    value);

            for (ServletRequestAttributeListener listener : _requestAttributeListeners) {
                listener.attributeRemoved(event);
            }
        }
    }

    /* ------------------------------------------------------------ */
    /*
      */
    public void setAttributes(Map<String, Object> attributes) {
        _attributes = attributes;
    }

    /* ------------------------------------------------------------ */

    /* ------------------------------------------------------------ */
    /*
     * @see javax.servlet.ServletRequest#setCharacterEncoding(java.lang.String)
     */
    @Override
    // OK
    public void setCharacterEncoding(String encoding) throws UnsupportedEncodingException {
        if (usingReader) {
            return;
        }

        _characterEncoding = encoding;

        // check encoding is supported
        if (!"UTF-8".equalsIgnoreCase(encoding))
            Charset.forName(encoding);
    }

    /* ------------------------------------------------------------ */
    /*
     * @see javax.servlet.ServletRequest#setCharacterEncoding(java.lang.String)
     */
    public void setCharacterEncodingUnchecked(String encoding) {
        _characterEncoding = encoding;
    }

    /* ------------------------------------------------------------ */
    /*
     * @see javax.servlet.ServletRequest#getContentType()
     */
    public void setContentType(String contentType) {
        headers.set(HttpHeaders.Names.CONTENT_TYPE, contentType);

    }

    /* ------------------------------------------------------------ */
    /**
     * Set request context
     * 
     * @param context
     *            context object
     */
    /*
     * public void setContext(DefalutServletContext context) { _newContext = servletContext != context; servletContext =
     * context; }
     */

    /* ------------------------------------------------------------ */
    /**
     * @return True if this is the first call of {@link #takeNewContext()} since the last
     *         {@link #setContext(org.eclipse.jetty.server.handler.ContextHandler.Context)} call.
     */
    public boolean takeNewContext() {
        boolean nc = _newContext;
        _newContext = false;
        return nc;
    }

    /* ------------------------------------------------------------ */
    /**
     * Sets the "context path" for this request
     * 
     * @see HttpServletRequest#getContextPath()
     */
    public void setContextPath(String contextPath) {
        _contextPath = contextPath;
    }

    /* ------------------------------------------------------------ */
    /**
     * @param cookies
     *            The cookies to set.
     */
    public void setCookies(Cookie[] cookies) {
        this.cookies = cookies;
    }

    /* ------------------------------------------------------------ */
    public void setDispatcherType(DispatcherType type) {
        _dispatcherType = type;
    }

    /* ------------------------------------------------------------ */
    public void setHandled(boolean h) {
        _handled = h;
    }

    /* ------------------------------------------------------------ */
    /**
     * @param method
     *            The method to set.
     */
    public void setMethod(HttpMethod httpMethod) {
        _httpMethod = httpMethod;
    }

    /* ------------------------------------------------------------ */
    public boolean isHead() {
        return HttpMethod.HEAD == _httpMethod;
    }

    /* ------------------------------------------------------------ */
    /**
     * @param parameters
     *            The parameters to set.
     */
    public void setParameters(Map<String, List<String>> parameters) {
        _parameters = (parameters == null) ? _parameters : parameters;
        if (_paramsExtracted && _parameters == null)
            throw new IllegalStateException();
    }

    /* ------------------------------------------------------------ */
    /**
     * @param pathInfo
     *            The pathInfo to set.
     */
    public void setPathInfo(String pathInfo) {
        _pathInfo = pathInfo;
    }

    /* ------------------------------------------------------------ */
    /**
     * @param version
     *            The protocol to set.
     */
    public void setHttpVersion(HttpVersion version) {
        _httpVersion = version;
    }

    /* ------------------------------------------------------------ */
    /**
     * Set the character encoding used for the query string. This call will effect the return of getQueryString and
     * getParamaters. It must be called before any geParameter methods.
     * 
     * The request attribute "org.eclipse.jetty.server.server.Request.queryEncoding" may be set as an alternate method
     * of calling setQueryEncoding.
     * 
     * @param queryEncoding
     */
    public void setQueryEncoding(String queryEncoding) {
        _queryEncoding = queryEncoding;
        _queryString = null;
    }

    /* ------------------------------------------------------------ */
    /**
     * @param queryString
     *            The queryString to set.
     */
    public void setQueryString(String queryString) {
        _queryString = queryString;
        _queryEncoding = null; // assume utf-8
    }

    /* ------------------------------------------------------------ */
    /**
     * @param addr
     *            The address to set.
     */
    public void setRemoteAddr(InetSocketAddress addr) {
        _remote = addr;
    }

    /* ------------------------------------------------------------ */
    /**
     * @param requestedSessionId
     *            The requestedSessionId to set.
     */
    public void setRequestedSessionId(String requestedSessionId) {
        _requestedSessionId = requestedSessionId;
    }

    /* ------------------------------------------------------------ */
    /**
     * @param requestedSessionIdCookie
     *            The requestedSessionIdCookie to set.
     */
    public void setRequestedSessionIdFromCookie(boolean requestedSessionIdCookie) {
        _isSessionIdFromCookie = requestedSessionIdCookie;
    }

    /* ------------------------------------------------------------ */
    /**
     * @param requestURI
     *            The requestURI to set.
     */
    public void setRequestURI(String requestURI) {
        _requestURI = requestURI;
    }

    /* ------------------------------------------------------------ */
    /**
     * @param scheme
     *            The scheme to set.
     */
    public void setScheme(String scheme) {
        _scheme = scheme;
    }

    /* ------------------------------------------------------------ */
    /**
     * @param host
     *            The host to set.
     */
    public void setServerName(String host) {
        _serverName = host;
    }

    /* ------------------------------------------------------------ */
    /**
     * @param port
     *            The port to set.
     */
    public void setServerPort(int port) {
        _port = port;
    }

    /* ------------------------------------------------------------ */
    /**
     * @param servletPath
     *            The servletPath to set.
     */
    public void setServletPath(String servletPath) {
        _servletPath = servletPath;
    }

    /* ------------------------------------------------------------ */
    /**
     * @param session
     *            The session to set.
     */
    public void setSession(HttpSessionImpl session) {
        _session = session;
    }

    /* ------------------------------------------------------------ */
    /**
     * @param sessionManager
     *            The sessionManager to set.
     */
    public void setSessionManager(SessionManager sessionManager) {
        _sessionManager = sessionManager;
    }

    /* ------------------------------------------------------------ */
    public void setTimeStamp(long ts) {
        _timeStamp = ts;
    }

    /* ------------------------------------------------------------ */
    /**
     * Set timetstamp of request dispatch
     * 
     * @param value
     *            timestamp
     */
    public void setDispatchTime(long value) {
        _dispatchTime = value;
    }

    /* ------------------------------------------------------------ */
    @Override
    public AsyncContext startAsync() throws IllegalStateException {
        /*
         * if (!_asyncSupported) throw new IllegalStateException("!asyncSupported"); HttpChannelState state =
         * getHttpChannelState(); state.startAsync(); return state;
         */
        throw new UnsupportedOperationException();
    }

    /* ------------------------------------------------------------ */
    @Override
    public AsyncContext startAsync(ServletRequest servletRequest, ServletResponse servletResponse)
            throws IllegalStateException {
        /*
         * if (!_asyncSupported) throw new IllegalStateException("!asyncSupported"); HttpChannelState state =
         * getHttpChannelState(); state.startAsync(servletContext, servletRequest, servletResponse); return state;
         */
        throw new UnsupportedOperationException();
    }

    /* ------------------------------------------------------------ */
    @Override
    public String toString() {
        return (_handled ? "[" : "(") + getMethod() + " " + request.getUri() + (_handled ? "]@" : ")@") + hashCode()
                + " " + super.toString();
    }

    /* ------------------------------------------------------------ */
    @Override
    public boolean authenticate(HttpServletResponse response) throws IOException, ServletException {
        throw new UnsupportedOperationException();
    }

    /* ------------------------------------------------------------ */
    @Override
    public Part getPart(String name) throws IOException, ServletException {
        /*
         * if (getContentType() == null || !getContentType().startsWith("multipart/form-data")) throw new
         * ServletException("Content-Type != multipart/form-data");
         * 
         * if (_multiPartInputStream == null) { MultipartConfigElement config =
         * (MultipartConfigElement)getAttribute(__MULTIPART_CONFIG_ELEMENT);
         * 
         * if (config == null) throw new IllegalStateException("No multipart config for servlet");
         * 
         * _multiPartInputStream = new MultiPartInputStreamParser(getInputStream(), getContentType(),config,
         * (servletContext != null?(File)servletContext.getAttribute("javax.servlet.context.tempdir"):null));
         * setAttribute(__MULTIPART_INPUT_STREAM, _multiPartInputStream); setAttribute(__MULTIPART_CONTEXT,
         * servletContext); Collection<Part> parts = _multiPartInputStream.getParts(); //causes parsing for (Part
         * p:parts) { MultiPartInputStreamParser.MultiPart mp = (MultiPartInputStreamParser.MultiPart)p; if
         * (mp.getContentDispositionFilename() == null && mp.getFile() == null) { //Servlet Spec 3.0 pg 23, parts
         * without filenames must be put into init params String charset = null; if (mp.getContentType() != null)
         * charset = MimeTypes.getCharsetFromContentType(mp.getContentType());
         * 
         * String content=new String(mp.getBytes(),charset==null?StringUtil.__UTF8:charset); getParameter(""); //cause
         * params to be evaluated getParameters().add(mp.getName(), content); } } } return
         * _multiPartInputStream.getPart(name);
         */
        throw new UnsupportedOperationException();
    }

    /* ------------------------------------------------------------ */
    @Override
    public Collection<Part> getParts() throws IOException, ServletException {
        /*
         * if (getContentType() == null || !getContentType().startsWith("multipart/form-data")) throw new
         * ServletException("Content-Type != multipart/form-data");
         * 
         * if (_multiPartInputStream == null) { MultipartConfigElement config =
         * (MultipartConfigElement)getAttribute(__MULTIPART_CONFIG_ELEMENT);
         * 
         * if (config == null) throw new IllegalStateException("No multipart config for servlet");
         * 
         * _multiPartInputStream = new MultiPartInputStreamParser(getInputStream(), getContentType(), config,
         * (servletContext != null?(File)servletContext.getAttribute("javax.servlet.context.tempdir"):null));
         * 
         * setAttribute(__MULTIPART_INPUT_STREAM, _multiPartInputStream); setAttribute(__MULTIPART_CONTEXT,
         * servletContext); Collection<Part> parts = _multiPartInputStream.getParts(); //causes parsing for (Part
         * p:parts) { MultiPartInputStreamParser.MultiPart mp = (MultiPartInputStreamParser.MultiPart)p; if
         * (mp.getContentDispositionFilename() == null && mp.getFile() == null) { //Servlet Spec 3.0 pg 23, parts
         * without filenames must be put into init params String charset = null; if (mp.getContentType() != null)
         * charset = MimeTypes.getCharsetFromContentType(mp.getContentType());
         * 
         * String content=new String(mp.getBytes(),charset==null?StringUtil.__UTF8:charset); getParameter(""); //cause
         * params to be evaluated getParameters().add(mp.getName(), content); } } } return
         * _multiPartInputStream.getParts();
         */
        throw new UnsupportedOperationException();
    }

    /* ------------------------------------------------------------ */
    @Override
    public void login(String username, String password) throws ServletException {
        throw new UnsupportedOperationException();
    }

    /* ------------------------------------------------------------ */
    @Override
    public void logout() throws ServletException {
        throw new UnsupportedOperationException();
    }

    /* ------------------------------------------------------------ */
    /**
     * Merge in a new query string. The query string is merged with the existing parameters and
     * {@link #setParameters(MultiMap)} and {@link #setQueryString(String)} are called with the result. The merge is
     * according to the rules of the servlet dispatch forward method.
     * 
     * @param query
     *            The query string to merge into the request.
     */
    /*
     * public void mergeQueryString(String query) { // extract parameters from dispatch query MultiMap<String>
     * parameters = new MultiMap<>(); UrlEncoded.decodeTo(query,parameters, StringUtil.__UTF8_CHARSET,-1); //have to
     * assume UTF-8 because we can't know otherwise
     * 
     * boolean merge_old_query = false;
     * 
     * // Have we evaluated parameters if (!_paramsExtracted) extractParameters();
     * 
     * // Are there any existing parameters? if (_parameters != null && _parameters.size() > 0) { // Merge parameters;
     * new parameters of the same name take precedence. merge_old_query = parameters.addAllValues(_parameters); }
     * 
     * if (_queryString != null && _queryString.length() > 0) { if (merge_old_query) { StringBuilder
     * overridden_query_string = new StringBuilder(); MultiMap<String> overridden_old_query = new MultiMap<>();
     * UrlEncoded.decodeTo(_queryString,overridden_old_query,getQueryEncoding(),-1);//decode using any queryencoding set
     * for the request
     * 
     * 
     * MultiMap<String> overridden_new_query = new MultiMap<>();
     * UrlEncoded.decodeTo(query,overridden_new_query,StringUtil.__UTF8_CHARSET,-1); //have to assume utf8 as we cannot
     * know otherwise
     * 
     * for(String name: overridden_old_query.keySet()) { if (!overridden_new_query.containsKey(name)) { List<String>
     * values = overridden_old_query.get(name); for(String v: values) {
     * overridden_query_string.append("&").append(name).append("=").append(v); } } }
     * 
     * query = query + overridden_query_string; } else { query = query + "&" + _queryString; } }
     * 
     * setParameters(parameters); setQueryString(query); }
     */

    public FullHttpRequest getFullHttpRequest() {
        return request;
    }

    public Map<String, List<String>> getParameters() {
        return _parameters;
    }

    /* ------------------------------------------------------------ */
    /**
     * Merge in a new query string. The query string is merged with the existing parameters and
     * {@link #setParameters(MultiMap)} and {@link #setQueryString(String)} are called with the result. The merge is
     * according to the rules of the servlet dispatch forward method.
     * 
     * @param query
     *            The query string to merge into the request.
     */
    public void mergeQueryString(String query) {
        /*
         * // extract parameters from dispatch query MultiMap<String> parameters = new MultiMap<>();
         * UrlEncoded.decodeTo(query,parameters, StringUtil.__UTF8_CHARSET,-1); //have to assume UTF-8 because we can't
         * know otherwise
         * 
         * boolean merge_old_query = false;
         * 
         * // Have we evaluated parameters if (!_paramsExtracted) extractParameters();
         * 
         * // Are there any existing parameters? if (_parameters != null && _parameters.size() > 0) { // Merge
         * parameters; new parameters of the same name take precedence. merge_old_query =
         * parameters.addAllValues(_parameters); }
         * 
         * if (_queryString != null && _queryString.length() > 0) { if (merge_old_query) { StringBuilder
         * overridden_query_string = new StringBuilder(); MultiMap<String> overridden_old_query = new MultiMap<>();
         * UrlEncoded.decodeTo(_queryString,overridden_old_query,getQueryEncoding(),-1);//decode using any queryencoding
         * set for the request
         * 
         * 
         * MultiMap<String> overridden_new_query = new MultiMap<>();
         * UrlEncoded.decodeTo(query,overridden_new_query,StringUtil.__UTF8_CHARSET,-1); //have to assume utf8 as we
         * cannot know otherwise
         * 
         * for(String name: overridden_old_query.keySet()) { if (!overridden_new_query.containsKey(name)) { List<String>
         * values = overridden_old_query.get(name); for(String v: values) {
         * overridden_query_string.append("&").append(name).append("=").append(v); } } }
         * 
         * query = query + overridden_query_string; } else { query = query + "&" + _queryString; } }
         * 
         * setParameters(parameters); setQueryString(query);
         */
    }

    public HttpInvocation getInvocation() {
        return _invocation;
    }

    public void setInvocation(HttpInvocation invocation) {
        this._invocation = invocation;
    }
}