All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.pdd.pop.ext.glassfish.grizzly.http.HttpRequestPacket Maven / Gradle / Ivy

/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 2010-2015 Oracle and/or its affiliates. All rights reserved.
 *
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, the "License").  You
 * may not use this file except in compliance with the License.  You can
 * obtain a copy of the License at
 * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
 * or packager/legal/LICENSE.txt.  See the License for the specific
 * language governing permissions and limitations under the License.
 *
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at packager/legal/LICENSE.txt.
 *
 * GPL Classpath Exception:
 * Oracle designates this particular file as subject to the "Classpath"
 * exception as provided by Oracle in the GPL Version 2 section of the License
 * file that accompanied this code.
 *
 * Modifications:
 * If applicable, add the following below the License Header, with the fields
 * enclosed by brackets [] replaced by your own identifying information:
 * "Portions Copyright [year] [name of copyright owner]"
 *
 * Contributor(s):
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don't indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 */

package com.pdd.pop.ext.glassfish.grizzly.http;

import com.pdd.pop.ext.glassfish.grizzly.Connection;
import com.pdd.pop.ext.glassfish.grizzly.http.util.DataChunk;
import com.pdd.pop.ext.glassfish.grizzly.http.util.Header;
import com.pdd.pop.ext.glassfish.grizzly.http.util.HttpCodecUtils;
import com.pdd.pop.ext.glassfish.grizzly.http.util.MimeHeaders;
import com.pdd.pop.ext.glassfish.grizzly.http.util.RequestURIRef;

import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import com.pdd.pop.ext.glassfish.grizzly.attributes.AttributeBuilder;
import com.pdd.pop.ext.glassfish.grizzly.attributes.AttributeHolder;
import com.pdd.pop.ext.glassfish.grizzly.attributes.DefaultAttributeBuilder;

/**
 * The {@link HttpHeader} object, which represents HTTP request message.
 *
 * @see HttpHeader
 * @see HttpResponsePacket
 * 
 * @author Alexey Stashok
 */
public abstract class HttpRequestPacket extends HttpHeader {
    /**
     * Prefix for all service/read-only attributes, that once added could not
     * be removed. The attributes with this prefix will not be listed in the
     * {@link #getAttributeNames()} result.
     * The prefix was introduced with the intention to avoid collisions with
     * normal user attributes and fail fast when we compare read-only and
     * normal user attributes.
     */
    public static final String READ_ONLY_ATTR_PREFIX = "@RoA.";
    
    private static final AttributeBuilder ATTR_BUILDER =
            new DefaultAttributeBuilder();

    // ----------------------------------------------------- Instance Variables

    private Connection connection;

    private HttpResponsePacket response;

    private int serverPort = -1;
    protected int remotePort = -1;
    protected int localPort = -1;

    private final RequestURIRef requestURIRef = new RequestURIRef();

    private String localHost;

    private final DataChunk methodC = DataChunk.newInstance();
    protected Method parsedMethod;

    private final DataChunk queryC = DataChunk.newInstance();
    protected final DataChunk remoteAddressC = DataChunk.newInstance();
    protected final DataChunk remoteHostC = DataChunk.newInstance();
    protected final DataChunk localNameC = DataChunk.newInstance();
    protected final DataChunk localAddressC = DataChunk.newInstance();
    private final DataChunk serverNameC = DataChunk.newInstance();

    /**
     * Authentication type.
     */
    private final DataChunk authTypeC = DataChunk.newInstance();
    private final DataChunk remoteUserC = DataChunk.newInstance();

    private boolean requiresAcknowledgement;

    protected DataChunk unparsedHostC;
    private boolean hostHeaderParsed;

    /**
     * Internal notes associated with this request by Catalina components
     * and event listeners.
     */
    private final transient AttributeHolder notesHolder =
            ATTR_BUILDER.createUnsafeAttributeHolder();

    /**
     * The attributes associated with this Request, keyed by attribute name.
     */
    protected final Map attributes = new HashMap();

    /**
     * Returns {@link HttpRequestPacket} builder.
     *
     * @return {@link Builder}.
     */
    public static Builder builder() {
        return new Builder();
    }
    
    // ----------------------------------------------------------- Constructors


    protected HttpRequestPacket() {
        setMethod(Method.GET);
    }


    // ---------------------------------------------------------- Public Methods


    public void setConnection(Connection connection) {
        this.connection = connection;
    }

    public Connection getConnection() {
        return connection;
    }

    public HttpResponsePacket getResponse() {
        return response;
    }

    // -------------------- Request data --------------------


    /**
     * Get the HTTP request method as {@link DataChunk}
     * (avoiding creation of a String object). The result format is "GET|POST...".
     *
     * @return the HTTP request method as {@link DataChunk}
     * (avoiding creation of a String object). The result format is "GET|POST...".
     */
    public DataChunk getMethodDC() {
        // potentially the value might be changed, so we need to parse it again
        parsedMethod = null;
        return methodC;
    }

    /**
     * Get the HTTP request method.
     *
     * @return the HTTP request method.
     */
    public Method getMethod() {
        if (parsedMethod != null) {
            return parsedMethod;
        }

        parsedMethod = Method.valueOf(methodC);

        return parsedMethod;
    }

    /**
     * Set the HTTP request method.
     * @param method the HTTP request method. Format is "GET|POST...".
     */
    public void setMethod(final String method) {
        this.methodC.setString(method);
        parsedMethod = null;
    }

    /**
     * Set the HTTP request method.
     * @param method the HTTP request method. Format is "GET|POST...".
     */
    public void setMethod(final Method method) {
        this.methodC.setString(method.getMethodString());
        parsedMethod = method;
    }

    /**
     * Returns the request URL of the HTTP request as {@link RequestURIRef}
     * (avoiding creation of a String object).
     * 
     * @return the request URL of the HTTP request as {@link RequestURIRef}
     * (avoiding creation of a String object).
     */
    public RequestURIRef getRequestURIRef() {
        return requestURIRef;
    }

    /**
     * Returns the request URL.
     *
     * @return the request URL.
     */
    public String getRequestURI() {
        return requestURIRef.getURI();
    }

    /**
     * Set the request URL.
     *
     * @param requestURI the request URL.
     */
    public void setRequestURI(String requestURI) {
        this.requestURIRef.setURI(requestURI);
    }

    /**
     * Returns the query string that is contained in the request URL after the
     * path. This method returns null if the URL does not have a query string.
     * The result is represented as {@link DataChunk} (avoiding creation of a
     * String object).
     * 
     * @return the query string that is contained in the request URL after the
     * path. This method returns null if the URL does not have a query string.
     * The result is represented as {@link DataChunk} (avoiding creation of a
     * String object).
     */
    public DataChunk getQueryStringDC() {
        return queryC;
    }

    /**
     * Returns the query string that is contained in the request URL after the
     * path. This method returns null if the URL does not have a query string.
     *
     * @return the query string that is contained in the request URL after the
     * path. This method returns null if the URL does not have a query string.
     */
    public String getQueryString() {
        return ((queryC.isNull()) ? null : queryC.toString());
    }

    /**
     * Set the query portion of the request URI.
     *
     * @param query the query String
     */
    public void setQueryString(String query) {
        queryC.setString(query);
    }

    
    /**
     * Return the buffer holding the server name, if
     * any. Use isNull() to check if there is no value
     * set.
     * This is the "virtual host", derived from the
     * Host: header.
     * 
     * @return the buffer holding the server name
     */
    protected DataChunk serverNameRaw() {
        return serverNameC;
    }
    
    /**
     * Return the buffer holding the server name, if
     * any. Use isNull() to check if there is no value
     * set.
     * This is the "virtual host", derived from the
     * Host: header.
     * @return the buffer holding the server name, if
     * any
     */
    public DataChunk serverName() {
        parseHostHeader();
        return serverNameC;
    }




    /**
     * @return Returns the integer value of the Internet Protocol (IP) port as
     *  specified in the Host request header.
     */
    public int getServerPort() {
        parseHostHeader();
        return serverPort;
    }

    /**
     * Sets the Internet Protocol (IP) port specified in the
     *  Host request header.
     *
     * @param serverPort the port as specified in the Host
     *  request header
     */
    public void setServerPort(int serverPort) {
        this.serverPort = serverPort;
    }

    /**
     * @return the {@link DataChunk} representing the Internet Protocol (IP)
     *  address of the client or last proxy that sent the request.
     */
    public DataChunk remoteAddr() {
        if (remoteAddressC.isNull()) {
            remoteAddressC
                  .setString(((InetSocketAddress) connection.getPeerAddress())
                        .getAddress().getHostAddress());
        }
        return remoteAddressC;

    }


    /**
      * @return the Internet Protocol (IP) address of the client or last proxy
     *   that sent the request.
     */
    public String getRemoteAddress() {
        return remoteAddr().toString();
    }


    /**
     * @return a {@link DataChunk} representing the fully qualified
     *  name of the client or the last proxy that sent the request. If the
     *  engine cannot or chooses not to resolve the host name (to improve
     *  performance), this method returns the the IP address.
     */
    public DataChunk remoteHost() {
         if ((remoteHostC.isNull())) {
            String remoteHost = null;
            InetAddress inetAddr = ((InetSocketAddress) connection
                  .getPeerAddress()).getAddress();
            if (inetAddr != null) {
                remoteHost = inetAddr.getHostName();
            }

            if (remoteHost == null) {
                if (!remoteAddressC.isNull()) {
                    remoteHost = remoteAddressC.toString();
                } else { // all we can do is punt
                    remoteHostC.recycle();
                }
            }
            remoteHostC.setString(remoteHost);
        }
        return remoteHostC;
    }


    /**
     * @return a String representing the fully qualified name of
     *  the client or the last proxy that sent the request. If the engine cannot
     *  or chooses not to resolve the hostname (to improve performance), this
     *  method returns the the IP address.
     */
    public String getRemoteHost() {

        return remoteHost().toString();
        
    }


    /**
     * Allows consumers of this request to be notified if the user-agent
     * requires acknowledgment of an expectation (i.e., the Expect header).
     *
     * @param requiresAcknowledgement true if expectation
     *  processing is required.
     */
    protected void requiresAcknowledgement(boolean requiresAcknowledgement) {
        this.requiresAcknowledgement = requiresAcknowledgement;
    }


    /**
     * @return true if this request requires acknowledgement.
     */
    public boolean requiresAcknowledgement() {
        return requiresAcknowledgement;
    }


    /**
     * @return a {@link DataChunk} representing the host name of the
     *  Internet Protocol (IP) interface on which the request was received.
     */
    public DataChunk localName() {

        if (localNameC.isNull()) {
            InetAddress inetAddr = ((InetSocketAddress) connection
                  .getLocalAddress()).getAddress();
            localNameC.setString(inetAddr.getHostName());
        }
        return localNameC;
        
    }


    /**
     * @return a String representing the host name of the 
     *  Internet Protocol (IP) interface on which the request was received.
     */
    public String getLocalName() {

        return localName().toString();

    }


    /**
     * @return a {@link DataChunk} representing the Internet Protocol (IP)
     *  address of the interface on which the request was received.
     */
    public DataChunk localAddr() {
        if (localAddressC.isNull()) {
            InetAddress inetAddr = ((InetSocketAddress) connection
                  .getLocalAddress()).getAddress();
            localAddressC.setString(inetAddr.getHostAddress());
        }
        return localAddressC;
    }


    /**
     * @return a String representing the Internet Protocol (IP)
     *  address of the interface on which the request was received.
     */
    public String getLocalAddress() {

        return localAddr().toString();

    }


    /**
     * @return the Internet Protocol (IP) source port of the client or last
     *  proxy that sent the request.
     */
    public int getRemotePort() {
        if (remotePort == -1) {
            remotePort = ((InetSocketAddress) connection.getPeerAddress()).getPort();
        }
        return remotePort;
    }


    /**
     * Sets the Internet Protocol (IP) source port of the client or last
     * proxy that sent the request.
     *
     * @param port the source port of the client
     */
    public void setRemotePort(int port) {
        this.remotePort = port;
    }


    /**
     * @return the Internet Protocol (IP) port number of the interface on which
     *  the request was received.
     */
    public int getLocalPort() {
        if (localPort == -1) {
            localPort = ((InetSocketAddress) connection.getLocalAddress()).getPort();
        }
        return localPort;
    }


    /**
     * Sets the Internet Protocol (IP) port number of the interface on which
     * the request was received.
     *
     * @param port the port on which the request was received
     */
    public void setLocalPort(int port) {
        this.localPort = port;
    }


    /**
     * @return the host name of the server servicing this request.
     */
    public String getLocalHost() {
        return localHost;
    }


    /**
     * Set the host name of the server servicing this request.
     * @param host the host name of the server servicing this request.
     */
    public void setLocalHost(String host) {
        this.localHost = host;
    }

    /**
     * @return the authentication type used for this Request.
     */
     public DataChunk authType() {
         return authTypeC;
     }

    /**
     * @return the name of the remote user that has been authenticated
     * for this Request.
     */
     public DataChunk remoteUser() {
         return remoteUserC;
     }

     /**
     * Create a named {@link Note} associated with this Request.
     *
     * @param  the {@link Note} type.
     * @param name the {@link Note} name.
     * @return the {@link Note}.
     */
    @SuppressWarnings({"unchecked"})
    public static  Note createNote(final String name) {
        return new Note(ATTR_BUILDER.createAttribute(name));
    }

    /**
     * Return the {@link Note} value associated with this Request,
     * or null if no such binding exists.
     * Use {@link #createNote(java.lang.String)} to create a new {@link Note}.
     *
     * @param  the {@link Note} type.
     * @param note {@link Note} value to be returned
     * @return the {@link Note} value associated with this Request,
     * or null if no such binding exists
     */
    public  E getNote(final Note note) {
        return note.attribute.get(notesHolder);
    }


    /**
     * Return a {@link Set} containing the String names of all note bindings
     * that exist for this request.
     * Use {@link #createNote(java.lang.String)} to create a new {@link Note}.
     *
     * @return a {@link Set} containing the String names of all note bindings
     * that exist for this request.
     */
    public Set getNoteNames() {
        return notesHolder.getAttributeNames();
    }


    /**
     * Remove the {@link Note} value associated with this request.
     * Use {@link #createNote(java.lang.String)} to create a new {@link Note}.
     *
     * @param  the {@link Note} type.
     * @param note {@link Note} value to be removed
     * @return the old value associated with the {@link Node}, that was removed
     */
    public  E removeNote(final Note note) {
        return note.attribute.remove(notesHolder);
    }


    /**
     * Bind the {@link Note} value to this Request,
     * replacing any existing binding for this name.
     * Use {@link #createNote(java.lang.String)} to create a new {@link Note}.
     *
     * @param  the {@link Note} type.
     * @param note {@link Note} to which the object should be bound
     * @param value the {@link Note} value be bound to the specified {@link Note}.
     */
    public  void setNote(final Note note, final E value) {
        note.attribute.set(notesHolder, value);
    }

    /**
     * @return the specified request attribute if it exists; otherwise, return
     * null.
     *
     * @param name Name of the request attribute to return
     */
    public Object getAttribute(final String name) {
        return attributes.get(name);
    }


    /**
     * @return read-only {@link Set} of the names of all request attributes,
     * or an empty {@link Set} if there are none.
     */
    public Set getAttributeNames() {
        final Set attrNames = new HashSet(attributes.size());
        for (String name : attributes.keySet()) {
            if (name == null || !name.startsWith(READ_ONLY_ATTR_PREFIX)) {
                attrNames.add(name);
            }
        }
        
        return Collections.unmodifiableSet(attrNames);
    }

    /**
     * Set the specified request attribute to the specified value.
     *
     * @param name Name of the request attribute to set
     * @param value The associated value
     */
    public void setAttribute(final String name, final Object value) {
        final Object oldValue = attributes.put(name, value);
        // make sure we don't overwrite read-only attribute
        if (oldValue != null &&
                name != null && name.startsWith(READ_ONLY_ATTR_PREFIX)) {
            // restore the original value for read-only attribute
            attributes.put(name, oldValue);
        }
    }

    /**
     * Remove the specified request attribute if it exists.
     *
     * @param name Name of the request attribute to remove
     */
    public void removeAttribute(final String name) {
        if (name == null || !name.startsWith(READ_ONLY_ATTR_PREFIX)) {
            attributes.remove(name);
        }
    }

    /**
     * Returns true if this request is a HEAD
     *  request, otherwise returns false.
     *
     * @return true if this request is a HEAD
     *  request, otherwise returns false.
     */
    public boolean isHeadRequest() {
        return (Method.HEAD.equals(getMethod()));
    }

    // -------------------- Recycling --------------------

    /**
     * {@inheritDoc}
     */
    @Override
    protected void reset() {
        requestURIRef.recycle();
        queryC.recycle();

        methodC.recycle();
        parsedMethod = null;

        hostHeaderParsed = false;
        unparsedHostC = null;
        
        remoteAddressC.recycle();
        remoteHostC.recycle();
        localAddressC.recycle();
        localNameC.recycle();
        serverNameC.recycle();

        authTypeC.recycle();
        remoteUserC.recycle();
        
        attributes.clear();

        requiresAcknowledgement = false;

        remotePort = -1;
        localPort = -1;
        serverPort = -1;

        connection = null;
        localHost = null;
        response = null;

        super.reset();
    }
    
    /**
     * {@inheritDoc}
     */
    @Override
    public final boolean isRequest() {
        return true;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public String toString() {
        final StringBuilder sb = new StringBuilder(256);
        sb.append("HttpRequestPacket (\n   method=").append(getMethod())
                .append("\n   url=").append(getRequestURI())
                .append("\n   query=").append(getQueryString())
                .append("\n   protocol=").append(getProtocol().getProtocolString())
                .append("\n   content-length=").append(getContentLength())
                .append("\n   headers=[");
        final MimeHeaders headersLocal = getHeaders();
        for (final String name : headersLocal.names()) {
            sb.append("\n      ").append(name).append('=')
                    .append(headersLocal.getHeader(name));
        }
        sb.append("]\n)");

        return sb.toString();
    }


    // ------------------------------------------------------- Protected Methods


    protected void setResponse(HttpResponsePacket response) {
        this.response = response;
    }


    // --------------------------------------------------------- Private Methods


    private void parseHostHeader() {
        if (!hostHeaderParsed) {
            doParseHostHeader();
            hostHeaderParsed = true;
        }
    }

    protected void doParseHostHeader() {
        HttpCodecUtils.parseHost(unparsedHostC, serverNameC, this);
    }
    
    // ---------------------------------------------------------- Nested Classes


    /**
     * HttpRequestPacket message builder.
     */
    public static class Builder extends HttpHeader.Builder {

        protected Method method;
        protected String methodString;
        protected String uri;
        protected String queryString;
        protected String host;

        /**
         * Set the HTTP request method.
         * @param method the HTTP request method..
         */
        public Builder method(final Method method) {
            this.method = method;
            methodString = null;
            return this;
        }

        /**
         * Set the HTTP request method.
         * @param method the HTTP request method. Format is "GET|POST...".
         */
        public Builder method(final String method) {
            this.methodString = method;
            this.method = null;
            return this;
        }

        /**
         * Set the request URI.
         *
         * @param uri the request URI.
         */
        public Builder uri(final String uri) {
            this.uri = uri;
            return this;
        }

        /**
         * Set the value for the Host header.
         * @param host the value for the Host header.
         *
         * @return this.
         */
        public Builder host(final String host) {
            this.host = host;
            return this;
        }

        /**
         * Set the query portion of the request URI.
         *
         * @param queryString the query String
         *
         * @return the current Builder
         */
        public Builder query(final String queryString) {
            this.queryString = queryString;
            return this;
        }

        /**
         * Build the HttpRequestPacket message.
         *
         * @return HttpRequestPacket
         */
        public final HttpRequestPacket build() {
            HttpRequestPacket packet = (HttpRequestPacket) super.build();
            if (method != null) {
                packet.setMethod(method);
            }
            if (methodString != null) {
                packet.setMethod(methodString);
            }
            if (uri != null) {
                packet.setRequestURI(uri);
            }
            if (queryString != null) {
                packet.setQueryString(queryString);
            }
            if (host != null) {
                packet.addHeader(Header.Host, host);
            }
            return packet;
        }

        public void reset() {
            super.reset();
            method = null;
            uri = null;
            queryString = null;
        }

        @Override
        protected HttpHeader create() {
            return HttpRequestPacketImpl.create();
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy