com.sun.grizzly.tcp.http11.GrizzlyRequest Maven / Gradle / Ivy
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 1997-2008 Sun Microsystems, Inc. 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.html
* or glassfish/bootstrap/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 glassfish/bootstrap/legal/LICENSE.txt.
* Sun designates this particular file as subject to the "Classpath" exception
* as provided by Sun in the GPL Version 2 section of the License file that
* accompanied this code. If applicable, add the following below the License
* Header, with the fields enclosed by brackets [] replaced by your own
* identifying information: "Portions Copyrighted [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.
*
*
* This file incorporates work covered by the following copyright and
* permission notice:
*
* Copyright 2004 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.grizzly.tcp.http11;
import com.sun.grizzly.tcp.ActionCode;
import com.sun.grizzly.tcp.Request;
import com.sun.grizzly.util.buf.B2CConverter;
import com.sun.grizzly.util.buf.ByteChunk;
import com.sun.grizzly.util.buf.CharChunk;
import com.sun.grizzly.util.buf.MessageBytes;
import com.sun.grizzly.util.http.Cookie;
import com.sun.grizzly.util.http.Cookies;
import com.sun.grizzly.util.http.Enumerator;
import com.sun.grizzly.util.http.FastHttpDateFormat;
import com.sun.grizzly.util.http.Globals;
import com.sun.grizzly.util.http.ParameterMap;
import com.sun.grizzly.util.http.Parameters;
import com.sun.grizzly.util.http.ServerCookie;
import com.sun.grizzly.util.http.StringParser;
import com.sun.grizzly.util.res.StringManager;
import javax.security.auth.Subject;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.InetAddress;
import java.net.Socket;
import java.net.URLDecoder;
import java.security.AccessController;
import java.security.Principal;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Locale;
import java.util.Map;
import java.util.Random;
import java.util.TimeZone;
import java.util.TreeMap;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
/**
* Wrapper object for the Coyote request.
*
* @author Remy Maucherat
* @author Craig R. McClanahan
* @version $Revision: 1.2 $ $Date: 2007/03/14 02:15:42 $
*/
public class GrizzlyRequest{
// ----------------------------------------------------------- Constructors
public GrizzlyRequest() {
// START OF SJSAS 6231069
formats = (SimpleDateFormat[]) staticDateFormats.get();
formats[0].setTimeZone(TimeZone.getTimeZone("GMT"));
formats[1].setTimeZone(TimeZone.getTimeZone("GMT"));
formats[2].setTimeZone(TimeZone.getTimeZone("GMT"));
// END OF SJSAS 6231069
}
// ------------------------------------------------------------- Properties
/**
* The match string for identifying a session ID parameter.
*/
private static final String match =
";" + Globals.SESSION_PARAMETER_NAME + "=";
/**
* The match string for identifying a session ID parameter.
*/
private static final char[] SESSION_ID = match.toCharArray();
private GrizzlySession session;
// -------------------------------------------------------------------- //
/**
* Not Good. We need a better mechanism.
* TODO: Move Session Management out of here
*/
private static Map sessions = new
HashMap();
/**
* Scheduled Thread that clean the cache every XX seconds.
*/
private static ScheduledThreadPoolExecutor sessionExpirer
= new ScheduledThreadPoolExecutor(1, new ThreadFactory(){
public Thread newThread(Runnable r) {
return new SchedulerThread(r,"Grizzly");
}
});
/**
* Simple daemon thread.
*/
private static class SchedulerThread extends Thread{
public SchedulerThread(Runnable r, String name){
super(r, name);
setDaemon(true);
}
}
/**
* That code is far from optimal and needs to be rewrite appropriately.
*/
static{
sessionExpirer.scheduleAtFixedRate(new Runnable(){
public void run(){
long currentTime = System.currentTimeMillis();
Iterator> iterator = sessions.entrySet().iterator();
Map.Entry entry;
while (iterator.hasNext()){
entry = iterator.next();
if (entry.getValue().getSessionTimeout() == -1) continue;
if (currentTime - entry.getValue().getTimestamp() >
entry.getValue().getSessionTimeout()){
entry.getValue().setIsValid(false);
iterator.remove();
}
}
}
},5,5, TimeUnit.SECONDS);
}
// --------------------------------------------------------------------- //
/**
* Grizzly request.
*/
protected Request request;
/**
* Set the Coyote request.
*
* @param request The Grizzly request
*/
public void setRequest(Request request) {
this.request = request;
inputBuffer.setRequest(request);
}
/**
* Get the Coyote request.
*/
public Request getRequest() {
return (this.request);
}
// ----------------------------------------------------- Instance Variables
/**
* The string manager for this package.
*/
protected static StringManager sm =
StringManager.getManager(Constants.Package);
/**
* The set of cookies associated with this Request.
*/
protected Cookie[] cookies = null;
// START OF SJSAS 6231069
/*
protected SimpleDateFormat formats[] = {
new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US),
new SimpleDateFormat("EEEEEE, dd-MMM-yy HH:mm:ss zzz", Locale.US),
new SimpleDateFormat("EEE MMMM d HH:mm:ss yyyy", Locale.US)
}*/
/**
* The set of SimpleDateFormat formats to use in getDateHeader().
*/
private static ThreadLocal staticDateFormats = new ThreadLocal() {
@Override
protected Object initialValue() {
SimpleDateFormat[] f = new SimpleDateFormat[3];
f[0] = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz",
Locale.US);
f[1] = new SimpleDateFormat("EEEEEE, dd-MMM-yy HH:mm:ss zzz",
Locale.US);
f[2] = new SimpleDateFormat("EEE MMMM d HH:mm:ss yyyy", Locale.US);
return f;
}
};
protected SimpleDateFormat formats[];
// END OF SJSAS 6231069
/**
* The default Locale if none are specified.
*/
protected static Locale defaultLocale = Locale.getDefault();
/**
* The attributes associated with this Request, keyed by attribute name.
*/
protected HashMap attributes = new HashMap();
/**
* List of read only attributes for this Request.
*/
private HashMap readOnlyAttributes = new HashMap();
/**
* The preferred Locales assocaited with this Request.
*/
protected ArrayList locales = new ArrayList();
/**
* Internal notes associated with this request by Catalina components
* and event listeners.
*/
private transient HashMap notes = new HashMap();
/**
* Authentication type.
*/
protected String authType = null;
/**
* The current dispatcher type.
*/
protected Object dispatcherType = null;
/**
* The associated input buffer.
*/
protected GrizzlyInputBuffer inputBuffer = new GrizzlyInputBuffer();
/**
* GrizzlyInputStream.
*/
protected GrizzlyInputStream inputStream =
new GrizzlyInputStream(inputBuffer);
/**
* Reader.
*/
protected GrizzlyReader reader = new GrizzlyReader(inputBuffer);
/**
* Using stream flag.
*/
protected boolean usingInputStream = false;
/**
* Using writer flag.
*/
protected boolean usingReader = false;
/**
* User principal.
*/
protected Principal userPrincipal = null;
/**
* GrizzlySession parsed flag.
*/
protected boolean sessionParsed = false;
/**
* Request parameters parsed flag.
*/
protected boolean requestParametersParsed = false;
/**
* Cookies parsed flag.
*/
protected boolean cookiesParsed = false;
/**
* Secure flag.
*/
protected boolean secure = false;
/**
* The Subject associated with the current AccessControllerContext
*/
protected Subject subject = null;
/**
* Post data buffer.
*/
protected static int CACHED_POST_LEN = 8192;
protected byte[] postData = null;
/**
* Hash map used in the getParametersMap method.
*/
protected ParameterMap parameterMap = new ParameterMap();
/**
* The current request dispatcher path.
*/
protected Object requestDispatcherPath = null;
/**
* Was the requested session ID received in a cookie?
*/
protected boolean requestedSessionCookie = false;
/**
* The requested session ID (if any) for this request.
*/
protected String requestedSessionId = null;
/**
* Was the requested session ID received in a URL?
*/
protected boolean requestedSessionURL = false;
/**
* The socket through which this Request was received.
*/
protected Socket socket = null;
/**
* Parse locales.
*/
protected boolean localesParsed = false;
/**
* The string parser we will use for parsing request lines.
*/
private StringParser parser = new StringParser();
/**
* Local port
*/
protected int localPort = -1;
/**
* Remote address.
*/
protected String remoteAddr = null;
/**
* Remote host.
*/
protected String remoteHost = null;
/**
* Remote port
*/
protected int remotePort = -1;
/**
* Local address
*/
protected String localName = null;
/**
* Local address
*/
protected String localAddr = null;
// START S1AS 4703023
/**
* The current application dispatch depth.
*/
private int dispatchDepth = 0;
/**
* The maximum allowed application dispatch depth.
*/
private static int maxDispatchDepth = Constants.DEFAULT_MAX_DISPATCH_DEPTH;
// END S1AS 4703023
// START SJSAS 6346226
private String jrouteId;
// END SJSAS 6346226
/**
* The response with which this request is associated.
*/
protected GrizzlyResponse response = null;
/**
* Return the Response with which this Request is associated.
*/
public GrizzlyResponse getResponse() {
return response;
}
/**
* Set the Response with which this Request is associated.
*
* @param response The new associated response
*/
public void setResponse(GrizzlyResponse response) {
this.response = response;
}
// --------------------------------------------------------- Public Methods
/**
* Release all object references, and initialize instance variables, in
* preparation for reuse of this object.
*/
public void recycle() {
dispatcherType = null;
requestDispatcherPath = null;
authType = null;
inputBuffer.recycle();
usingInputStream = false;
usingReader = false;
userPrincipal = null;
subject = null;
sessionParsed = false;
requestParametersParsed = false;
cookiesParsed = false;
locales.clear();
localesParsed = false;
secure = false;
remoteAddr = null;
remoteHost = null;
remotePort = -1;
localPort = -1;
localAddr = null;
localName = null;
attributes.clear();
cookies = null;
requestedSessionId = null;
session = null;
dispatchDepth = 0; // S1AS 4703023
parameterMap.setLocked(false);
parameterMap.clear();
if (System.getSecurityManager() != null) {
if (inputStream != null) {
inputStream.clear();
inputStream = null;
}
if (reader != null) {
reader.clear();
reader = null;
}
}
}
// -------------------------------------------------------- Request Methods
/**
* Return the authorization credentials sent with this request.
*/
public String getAuthorization() {
return (request.getHeader(Constants.AUTHORIZATION_HEADER));
}
/**
* Set the authorization credentials sent with this request.
*
* @param authorization The new authorization credentials
*/
public void setAuthorization(String authorization) {
// Not used
}
/**
* Return the Socket (if any) through which this Request was received.
* This should only be used to access underlying state
* information about this Socket, such as the SSLSession associated with
* an SSLSocket.
*/
public Socket getSocket() {
return (socket);
}
/**
* Set the Socket (if any) through which this Request was received.
*
* @param socket The socket through which this request was received
*/
public void setSocket(Socket socket) {
this.socket = socket;
remoteHost = null;
remoteAddr = null;
remotePort = -1;
localPort = -1;
localAddr = null;
localName = null;
}
/**
* Return the input stream associated with this Request.
*/
public InputStream getStream() {
if (inputStream == null) {
inputStream = new GrizzlyInputStream(inputBuffer);
}
return inputStream;
}
/**
* Set the input stream associated with this Request.
*
* @param stream The new input stream
*/
public void setStream(InputStream stream) {
// Ignore
}
/**
* URI byte to char converter (not recycled).
*/
protected B2CConverter URIConverter = null;
/**
* Return the URI converter.
*/
public B2CConverter getURIConverter() {
return URIConverter;
}
/**
* Set the URI converter.
*
* @param URIConverter the new URI connverter
*/
public void setURIConverter(B2CConverter URIConverter) {
this.URIConverter = URIConverter;
}
// ------------------------------------------------- Request Public Methods
/**
* Create and return a GrizzlyInputStream to read the content
* associated with this Request.
*
* @exception IOException if an input/output error occurs
*/
public GrizzlyInputStream createInputStream()
throws IOException {
if (inputStream == null) {
inputStream = new GrizzlyInputStream(inputBuffer);
}
return inputStream;
}
/**
* Perform whatever actions are required to flush and close the input
* stream or reader, in a single operation.
*
* @exception IOException if an input/output error occurs
*/
public void finishRequest() throws IOException {
// The reader and input stream don't need to be closed
}
/**
* Return the object bound with the specified name to the internal notes
* for this request, or null
if no such binding exists.
*
* @param name Name of the note to be returned
*/
public Object getNote(String name) {
return (notes.get(name));
}
/**
* Return an Iterator containing the String names of all notes bindings
* that exist for this request.
*/
public Iterator getNoteNames() {
return (notes.keySet().iterator());
}
/**
* Remove any object bound to the specified name in the internal notes
* for this request.
*
* @param name Name of the note to be removed
*/
public void removeNote(String name) {
notes.remove(name);
}
/**
* Bind an object to a specified name in the internal notes associated
* with this request, replacing any existing binding for this name.
*
* @param name Name to which the object should be bound
* @param value Object to be bound to the specified name
*/
public void setNote(String name, Object value) {
notes.put(name, value);
}
/**
* Set the content length associated with this Request.
*
* @param length The new content length
*/
public void setContentLength(int length) {
// Not used
}
/**
* Set the content type (and optionally the character encoding)
* associated with this Request. For example,
* text/html; charset=ISO-8859-4
.
*
* @param type The new content type
*/
public void setContentType(String type) {
// Not used
}
/**
* Set the protocol name and version associated with this Request.
*
* @param protocol Protocol name and version
*/
public void setProtocol(String protocol) {
// Not used
}
/**
* Set the IP address of the remote client associated with this Request.
*
* @param remoteAddr The remote IP address
*/
public void setRemoteAddr(String remoteAddr) {
// Not used
}
/**
* Set the fully qualified name of the remote client associated with this
* Request.
*
* @param remoteHost The remote host name
*/
public void setRemoteHost(String remoteHost) {
// Not used
}
/**
* Set the name of the scheme associated with this request. Typical values
* are http
, https
, and ftp
.
*
* @param scheme The scheme
*/
public void setScheme(String scheme) {
// Not used
}
/**
* Set the value to be returned by isSecure()
* for this Request.
*
* @param secure The new isSecure value
*/
public void setSecure(boolean secure) {
this.secure = secure;
}
/**
* Set the name of the server (virtual host) to process this request.
*
* @param name The server name
*/
public void setServerName(String name) {
request.serverName().setString(name);
}
/**
* Set the port number of the server to process this request.
*
* @param port The server port
*/
public void setServerPort(int port) {
request.setServerPort(port);
}
// ------------------------------------------------- ServletRequest Methods
/**
* Return the specified request attribute if it exists; otherwise, return
* null
.
*
* @param name Name of the request attribute to return
*/
public Object getAttribute(String name) {
Object attr=attributes.get(name);
if(attr!=null)
return(attr);
attr = request.getAttribute(name);
if(attr != null)
return attr;
// XXX Should move to Globals
if(Constants.SSL_CERTIFICATE_ATTR.equals(name)) {
request.action(ActionCode.ACTION_REQ_SSL_CERTIFICATE, null);
attr = getAttribute(Globals.CERTIFICATES_ATTR);
if(attr != null)
attributes.put(name, attr);
} else if( isSSLAttribute(name) ) {
request.action(ActionCode.ACTION_REQ_SSL_ATTRIBUTE,
request);
attr = request.getAttribute(Globals.CERTIFICATES_ATTR);
if( attr != null) {
attributes.put(Globals.CERTIFICATES_ATTR, attr);
}
attr = request.getAttribute(Globals.CIPHER_SUITE_ATTR);
if(attr != null) {
attributes.put(Globals.CIPHER_SUITE_ATTR, attr);
}
attr = request.getAttribute(Globals.KEY_SIZE_ATTR);
if(attr != null) {
attributes.put(Globals.KEY_SIZE_ATTR, attr);
}
attr = attributes.get(name);
}
return attr;
}
/**
* Test if a given name is one of the special Servlet-spec SSL attributes.
*/
static boolean isSSLAttribute(String name) {
return Globals.CERTIFICATES_ATTR.equals(name) ||
Globals.CIPHER_SUITE_ATTR.equals(name) ||
Globals.KEY_SIZE_ATTR.equals(name);
}
/**
* Return the names of all request attributes for this Request, or an
* empty Enumeration
if there are none.
*/
public Enumeration getAttributeNames() {
return new Enumerator(attributes.keySet(), true);
}
/**
* Return the character encoding for this Request.
*/
public String getCharacterEncoding() {
return (request.getCharacterEncoding());
}
/**
* Return the content length for this Request.
*/
public int getContentLength() {
return (request.getContentLength());
}
/**
* Return the content type for this Request.
*/
public String getContentType() {
return (request.getContentType());
}
/**
* Return the servlet input stream for this Request. The default
* implementation returns a servlet input stream created by
* createInputStream()
.
*
* @exception IllegalStateException if getReader()
has
* already been called for this request
* @exception IOException if an input/output error occurs
*/
public GrizzlyInputStream getInputStream() throws IOException {
if (usingReader)
throw new IllegalStateException
(sm.getString("request.getInputStream.ise"));
usingInputStream = true;
if (inputStream == null) {
inputStream = new GrizzlyInputStream(inputBuffer);
}
return inputStream;
}
/**
* Return the preferred Locale that the client will accept content in,
* based on the value for the first Accept-Language
header
* that was encountered. If the request did not specify a preferred
* language, the server's default Locale is returned.
*/
public Locale getLocale() {
if (!localesParsed)
parseLocales();
if (locales.size() > 0) {
return ((Locale) locales.get(0));
} else {
return (defaultLocale);
}
}
/**
* Return the set of preferred Locales that the client will accept
* content in, based on the values for any Accept-Language
* headers that were encountered. If the request did not specify a
* preferred language, the server's default Locale is returned.
*/
public Enumeration getLocales() {
if (!localesParsed)
parseLocales();
if (locales.size() > 0)
return (new Enumerator(locales));
ArrayList results = new ArrayList();
results.add(defaultLocale);
return (new Enumerator(results));
}
/**
* Return the value of the specified request parameter, if any; otherwise,
* return null
. If there is more than one value defined,
* return only the first one.
*
* @param name Name of the desired request parameter
*/
public String getParameter(String name) {
if (!requestParametersParsed)
parseRequestParameters();
return request.getParameters().getParameter(name);
}
/**
* Returns a {@link Map} of the parameters of this request.
* Request parameters are extra information sent with the request.
* For HTTP servlets, parameters are contained in the query string
* or posted form data.
*
* @return A {@link Map} containing parameter names as keys
* and parameter values as map values.
*/
public Map getParameterMap() {
if (parameterMap.isLocked())
return parameterMap;
Enumeration e = getParameterNames();
while (e.hasMoreElements()) {
String name = e.nextElement().toString();
String[] values = getParameterValues(name);
parameterMap.put(name, values);
}
parameterMap.setLocked(true);
return parameterMap;
}
/**
* Return the names of all defined request parameters for this request.
*/
public Enumeration getParameterNames() {
if (!requestParametersParsed)
parseRequestParameters();
return request.getParameters().getParameterNames();
}
/**
* Return the defined values for the specified request parameter, if any;
* otherwise, return null
.
*
* @param name Name of the desired request parameter
*/
public String[] getParameterValues(String name) {
if (!requestParametersParsed)
parseRequestParameters();
return request.getParameters().getParameterValues(name);
}
/**
* Return the protocol and version used to make this Request.
*/
public String getProtocol() {
return request.protocol().toString();
}
/**
* Read the Reader wrapping the input stream for this Request. The
* default implementation wraps a BufferedReader
around the
* servlet input stream returned by createInputStream()
.
*
* @exception IllegalStateException if getInputStream()
* has already been called for this request
* @exception IOException if an input/output error occurs
*/
public BufferedReader getReader() throws IOException {
if (usingInputStream)
throw new IllegalStateException
(sm.getString("request.getReader.ise"));
usingReader = true;
inputBuffer.checkConverter();
if (reader == null) {
reader = new GrizzlyReader(inputBuffer);
}
return reader;
}
/**
* Return the remote IP address making this Request.
*/
public String getRemoteAddr() {
if (remoteAddr == null) {
if (socket != null) {
InetAddress inet = socket.getInetAddress();
remoteAddr = inet.getHostAddress();
} else {
request.action
(ActionCode.ACTION_REQ_HOST_ADDR_ATTRIBUTE, request);
remoteAddr = request.remoteAddr().toString();
}
}
return remoteAddr;
}
/**
* Return the remote host name making this Request.
*/
public String getRemoteHost() {
if (remoteHost == null) {
if (socket != null) {
InetAddress inet = socket.getInetAddress();
remoteHost = inet.getHostName();
} else {
request.action
(ActionCode.ACTION_REQ_HOST_ATTRIBUTE, request);
remoteHost = request.remoteHost().toString();
}
}
return remoteHost;
}
/**
* Returns the Internet Protocol (IP) source port of the client
* or last proxy that sent the request.
*/
public int getRemotePort(){
if (remotePort == -1) {
if (socket != null) {
remotePort = socket.getPort();
} else {
request.action
(ActionCode.ACTION_REQ_REMOTEPORT_ATTRIBUTE, request);
remotePort = request.getRemotePort();
}
}
return remotePort;
}
/**
* Returns the host name of the Internet Protocol (IP) interface on
* which the request was received.
*/
public String getLocalName(){
if (localName == null) {
if (socket != null) {
InetAddress inet = socket.getLocalAddress();
localName = inet.getHostName();
} else {
request.action
(ActionCode.ACTION_REQ_LOCAL_NAME_ATTRIBUTE, request);
localName = request.localName().toString();
}
}
return localName;
}
/**
* Returns the Internet Protocol (IP) address of the interface on
* which the request was received.
*/
public String getLocalAddr(){
if (localAddr == null) {
if (socket != null) {
InetAddress inet = socket.getLocalAddress();
localAddr = inet.getHostAddress();
} else {
request.action
(ActionCode.ACTION_REQ_LOCAL_ADDR_ATTRIBUTE, request);
localAddr = request.localAddr().toString();
}
}
return localAddr;
}
/**
* Returns the Internet Protocol (IP) port number of the interface
* on which the request was received.
*/
public int getLocalPort(){
if (localPort == -1){
if (socket != null) {
localPort = socket.getLocalPort();
} else {
request.action
(ActionCode.ACTION_REQ_LOCALPORT_ATTRIBUTE, request);
localPort = request.getLocalPort();
}
}
return localPort;
}
/**
* Return the scheme used to make this Request.
*/
public String getScheme() {
String scheme = (request.scheme().toString());
if (scheme == null){
scheme = "http";
}
return scheme;
}
/**
* Return the server name responding to this Request.
*/
public String getServerName() {
return (request.serverName().toString());
}
/**
* Return the server port responding to this Request.
*/
public int getServerPort() {
return (request.getServerPort());
}
/**
* Was this request received on a secure connection?
*/
public boolean isSecure() {
return (secure);
}
/**
* Return true if the session identifier included in this
* request identifies a valid session.
*/
public boolean isRequestedSessionIdValid() {
if (requestedSessionId == null)
return (false);
if (session != null
&& requestedSessionId.equals(session.getIdInternal())) {
return session.isValid();
}
GrizzlySession localSession = sessions.put(requestedSessionId,session);
if ((localSession != null) && localSession.isValid())
return (true);
else
return (false);
}
/**
* Return true if the session identifier included in this
* request came from a cookie.
*/
public boolean isRequestedSessionIdFromCookie() {
if (requestedSessionId != null)
return (requestedSessionCookie);
else
return (false);
}
/**
* Return true if the session identifier included in this
* request came from the request URI.
*/
public boolean isRequestedSessionIdFromURL() {
if (requestedSessionId != null)
return (requestedSessionURL);
else
return (false);
}
/**
* Remove the specified request attribute if it exists.
*
* @param name Name of the request attribute to remove
*/
public void removeAttribute(String name) {
Object value = null;
boolean found = false;
// Remove the specified attribute
// Check for read only attribute
// requests are per thread so synchronization unnecessary
if (readOnlyAttributes.containsKey(name)) {
return;
}
found = attributes.containsKey(name);
if (found) {
value = attributes.get(name);
attributes.remove(name);
}
}
/**
* 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(String name, Object value) {
// Name cannot be null
if (name == null)
throw new IllegalArgumentException
(sm.getString("request.setAttribute.namenull"));
// Null value is the same as removeAttribute()
if (value == null) {
removeAttribute(name);
return;
}
if (name.equals(Globals.DISPATCHER_TYPE_ATTR)) {
dispatcherType = value;
return;
} else if (name.equals(Globals.DISPATCHER_REQUEST_PATH_ATTR)) {
requestDispatcherPath = value;
return;
}
Object oldValue = null;
boolean replaced = false;
// Add or replace the specified attribute
// Check for read only attribute
// requests are per thread so synchronization unnecessary
if (readOnlyAttributes.containsKey(name)) {
return;
}
oldValue = attributes.put(name, value);
if (oldValue != null) {
replaced = true;
}
// START SJSAS 6231069
// Pass special attributes to the ngrizzly layer
if (name.startsWith("grizzly.")) {
request.setAttribute(name, value);
}
// END SJSAS 6231069
}
/**
* Overrides the name of the character encoding used in the body of this
* request.
*
* This method must be called prior to reading request parameters or
* reading input using getReader()
. Otherwise, it has no
* effect.
*
* @param enc String
containing the name of
* the character encoding.
* @throws java.io.UnsupportedEncodingException if this
* ServletRequest is still in a state where a
* character encoding may be set, but the specified
* encoding is invalid
*
* @since Servlet 2.3
*/
public void setCharacterEncoding(String enc)
throws UnsupportedEncodingException {
// START SJSAS 4936855
if (requestParametersParsed || usingReader) {
return;
}
// END SJSAS 4936855
// Ensure that the specified encoding is valid
byte buffer[] = new byte[1];
buffer[0] = (byte) 'a';
// START S1AS 6179607: Workaround for 6181598. Workaround should be
// removed once the underlying issue in J2SE has been fixed.
/*
* String dummy = new String(buffer, enc);
*/
// END S1AS 6179607
// START S1AS 6179607
final byte[] finalBuffer = buffer;
final String finalEnc = enc;
String dummy = null;
if (System.getSecurityManager() != null) {
try {
dummy = (String) AccessController.doPrivileged(
new PrivilegedExceptionAction() {
public Object run() throws UnsupportedEncodingException {
return new String(finalBuffer, finalEnc);
}
});
} catch (PrivilegedActionException pae) {
throw (UnsupportedEncodingException) pae.getCause();
}
} else {
dummy = new String(buffer, enc);
}
// END S1AS 6179607
// Save the validated encoding
request.setCharacterEncoding(enc);
}
// START S1AS 4703023
/**
* Static setter method for the maximum dispatch depth
*/
public static void setMaxDispatchDepth(int depth) {
maxDispatchDepth = depth;
}
public static int getMaxDispatchDepth(){
return maxDispatchDepth;
}
/**
* Increment the depth of application dispatch
*/
public int incrementDispatchDepth() {
return ++dispatchDepth;
}
/**
* Decrement the depth of application dispatch
*/
public int decrementDispatchDepth() {
return --dispatchDepth;
}
/**
* Check if the application dispatching has reached the maximum
*/
public boolean isMaxDispatchDepthReached() {
return dispatchDepth > maxDispatchDepth;
}
// END S1AS 4703023
// ---------------------------------------------------- HttpRequest Methods
/**
* Add a Cookie to the set of Cookies associated with this Request.
*
* @param cookie The new cookie
*/
public void addCookie(Cookie cookie) {
// For compatibility only
if (!cookiesParsed)
parseCookies();
int size = 0;
if (cookie != null) {
size = cookies.length;
}
Cookie[] newCookies = new Cookie[size + 1];
System.arraycopy(cookies, 0, newCookies, 0, size);
newCookies[size] = cookie;
cookies = newCookies;
}
/**
* Add a Header to the set of Headers associated with this Request.
*
* @param name The new header name
* @param value The new header value
*/
public void addHeader(String name, String value) {
// Not used
}
/**
* Add a Locale to the set of preferred Locales for this Request. The
* first added Locale will be the first one returned by getLocales().
*
* @param locale The new preferred Locale
*/
public void addLocale(Locale locale) {
locales.add(locale);
}
/**
* Add a parameter name and corresponding set of values to this Request.
* (This is used when restoring the original request on a form based
* login).
*
* @param name Name of this request parameter
* @param values Corresponding values for this request parameter
*/
public void addParameter(String name, String values[]) {
request.getParameters().addParameterValues(name, values);
}
/**
* Clear the collection of Cookies associated with this Request.
*/
public void clearCookies() {
cookiesParsed = true;
cookies = null;
}
/**
* Clear the collection of Headers associated with this Request.
*/
public void clearHeaders() {
// Not used
}
/**
* Clear the collection of Locales associated with this Request.
*/
public void clearLocales() {
locales.clear();
}
/**
* Clear the collection of parameters associated with this Request.
*/
public void clearParameters() {
// Not used
}
/**
* Set the authentication type used for this request, if any; otherwise
* set the type to null
. Typical values are "BASIC",
* "DIGEST", or "SSL".
*
* @param type The authentication type used
*/
public void setAuthType(String type) {
this.authType = type;
}
/**
* Set the HTTP request method used for this Request.
*
* @param method The request method
*/
public void setMethod(String method) {
// Not used
}
/**
* Set the query string for this Request. This will normally be called
* by the HTTP Connector, when it parses the request headers.
*
* @param query The query string
*/
public void setQueryString(String query) {
// Not used
}
/**
* Set the unparsed request URI for this Request. This will normally be
* called by the HTTP Connector, when it parses the request headers.
*
* @param uri The request URI
*/
public void setRequestURI(String uri) {
// Not used
}
/**
* Set the decoded request URI.
*
* @param uri The decoded request URI
*/
public void setDecodedRequestURI(String uri) {
// Not used
}
/**
* Get the decoded request URI.
*
* @return the URL decoded request URI
*/
public String getDecodedRequestURI() {
return (request.decodedURI().toString());
}
/**
* Get the decoded request URI.
*
* @return the URL decoded request URI
*/
public MessageBytes getDecodedRequestURIMB() {
return (request.decodedURI());
}
/**
* Set the Principal who has been authenticated for this Request. This
* value is also used to calculate the value to be returned by the
* getRemoteUser()
method.
*
* @param principal The user Principal
*/
public void setUserPrincipal(Principal principal) {
this.userPrincipal = principal;
}
// --------------------------------------------- HttpServletRequest Methods
/**
* Return the authentication type used for this Request.
*/
public String getAuthType() {
return (authType);
}
/**
* Return the set of Cookies received with this Request.
*/
public Cookie[] getCookies() {
if (!cookiesParsed)
parseCookies();
return cookies;
}
/**
* Set the set of cookies recieved with this Request.
*/
public void setCookies(Cookie[] cookies) {
this.cookies = cookies;
}
/**
* Return the value of the specified date header, if any; otherwise
* return -1.
*
* @param name Name of the requested date header
*
* @exception IllegalArgumentException if the specified header value
* cannot be converted to a date
*/
public long getDateHeader(String name) {
String value = getHeader(name);
if (value == null)
return (-1L);
// Attempt to convert the date header in a variety of formats
long result = FastHttpDateFormat.parseDate(value, formats);
if (result != (-1L)) {
return result;
}
throw new IllegalArgumentException(value);
}
/**
* Return the first value of the specified header, if any; otherwise,
* return null
*
* @param name Name of the requested header
*/
public String getHeader(String name) {
return request.getHeader(name);
}
/**
* Return all of the values of the specified header, if any; otherwise,
* return an empty enumeration.
*
* @param name Name of the requested header
*/
public Enumeration getHeaders(String name) {
return request.getMimeHeaders().values(name);
}
/**
* Return the names of all headers received with this request.
*/
public Enumeration getHeaderNames() {
return request.getMimeHeaders().names();
}
/**
* Return the value of the specified header as an integer, or -1 if there
* is no such header for this request.
*
* @param name Name of the requested header
*
* @exception IllegalArgumentException if the specified header value
* cannot be converted to an integer
*/
public int getIntHeader(String name) {
String value = getHeader(name);
if (value == null) {
return (-1);
} else {
return (Integer.parseInt(value));
}
}
/**
* Return the HTTP request method used in this Request.
*/
public String getMethod() {
return request.method().toString();
}
/**
* Return the query string associated with this request.
*/
public String getQueryString() {
String queryString = request.queryString().toString();
if (queryString == null || queryString.equals("")) {
return (null);
} else {
return queryString;
}
}
/**
* Return the name of the remote user that has been authenticated
* for this Request.
*/
public String getRemoteUser() {
if (userPrincipal != null) {
return (userPrincipal.getName());
} else {
return (null);
}
}
/**
* Return the session identifier included in this request, if any.
*/
public String getRequestedSessionId() {
return (requestedSessionId);
}
/**
* Return the request URI for this request.
*/
public String getRequestURI() {
return request.requestURI().toString();
}
/**
* Reconstructs the URL the client used to make the request.
* The returned URL contains a protocol, server name, port
* number, and server path, but it does not include query
* string parameters.
*
* Because this method returns a StringBuffer
,
* not a String
, you can modify the URL easily,
* for example, to append query parameters.
*
* This method is useful for creating redirect messages and
* for reporting errors.
*
* @return A StringBuffer
object containing the
* reconstructed URL
*/
public StringBuffer getRequestURL() {
StringBuilder url = new StringBuilder();
String scheme = getScheme();
int port = getServerPort();
if (port < 0)
port = 80; // Work around java.net.URL bug
url.append(scheme);
url.append("://");
url.append(getServerName());
if ((scheme.equals("http") && (port != 80))
|| (scheme.equals("https") && (port != 443))) {
url.append(':');
url.append(port);
}
url.append(getRequestURI());
return (new StringBuffer(url));
}
/**
* Return the principal that has been authenticated for this Request.
*/
public Principal getUserPrincipal() {
return (userPrincipal);
}
protected String unescape(String s) {
if (s == null) {
return null;
}
if (s.indexOf('\\') == -1) {
return s;
}
StringBuilder buf = new StringBuilder();
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (c != '\\') {
buf.append(c);
} else {
if (++i >= s.length()) {
//invalid escape, hence invalid cookie
throw new IllegalArgumentException();
}
c = s.charAt(i);
buf.append(c);
}
}
return buf.toString();
}
/**
* Parse cookies.
*/
protected void parseCookies() {
cookiesParsed = true;
Cookies serverCookies = request.getCookies();
int count = serverCookies.getCookieCount();
if (count <= 0)
return;
cookies = new Cookie[count];
int idx = 0;
for (int i = 0; i < count; i++) {
ServerCookie scookie = serverCookies.getCookie(i);
try {
// we must unescape the '\\' escape character
Cookie cookie = new Cookie(scookie.getName().toString(), null);
int version = scookie.getVersion();
cookie.setVersion(version);
cookie.setValue(unescape(scookie.getValue().toString()));
cookie.setPath(unescape(scookie.getPath().toString()));
String domain = scookie.getDomain().toString();
if (domain != null) {
cookie.setDomain(unescape(domain));//avoid NPE
}
String comment = scookie.getComment().toString();
cookie.setComment((version == 1) ? unescape(comment) : null);
cookies[idx++] = cookie;
} catch(IllegalArgumentException e) {
; // Ignore bad cookie.
}
}
if( idx < count ) {
Cookie [] ncookies = new Cookie[idx];
System.arraycopy(cookies, 0, ncookies, 0, idx);
cookies = ncookies;
}
}
/**
* Parse request parameters.
*/
protected void parseRequestParameters() {
/* SJSAS 4936855
requestParametersParsed = true;
*/
Parameters parameters = request.getParameters();
// getCharacterEncoding() may have been overridden to search for
// hidden form field containing request encoding
String enc = getCharacterEncoding();
// START SJSAS 4936855
// Delay updating requestParametersParsed to TRUE until
// after getCharacterEncoding() has been called, because
// getCharacterEncoding() may cause setCharacterEncoding() to be
// called, and the latter will ignore the specified encoding if
// requestParametersParsed is TRUE
requestParametersParsed = true;
// END SJSAS 4936855
if (enc != null) {
parameters.setEncoding(enc);
parameters.setQueryStringEncoding(enc);
} else {
parameters.setEncoding
(com.sun.grizzly.tcp.Constants.DEFAULT_CHARACTER_ENCODING);
parameters.setQueryStringEncoding
(com.sun.grizzly.tcp.Constants.DEFAULT_CHARACTER_ENCODING);
}
parameters.handleQueryParameters();
if (usingInputStream || usingReader)
return;
if (!getMethod().equalsIgnoreCase("POST"))
return;
String contentType = getContentType();
if (contentType == null)
contentType = "";
int semicolon = contentType.indexOf(';');
if (semicolon >= 0) {
contentType = contentType.substring(0, semicolon).trim();
} else {
contentType = contentType.trim();
}
if (!("application/x-www-form-urlencoded".equals(contentType)))
return;
int len = getContentLength();
if (len > 0) {
try {
byte[] formData = getPostBody();
if (formData != null) {
parameters.processParameters(formData, 0, len);
}
} catch (Throwable t) {
; // Ignore
}
}
}
// START SJSAS 6346738
/**
* Gets the POST body of this request.
*
* @return The POST body of this request
*/
protected byte[] getPostBody() throws IOException {
int len = getContentLength();
byte[] formData = null;
if (len < CACHED_POST_LEN) {
if (postData == null)
postData = new byte[CACHED_POST_LEN];
formData = postData;
} else {
formData = new byte[len];
}
int actualLen = readPostBody(formData, len);
if (actualLen == len) {
return formData;
}
return null;
}
// END SJSAS 6346738
/**
* Read post body in an array.
*/
protected int readPostBody(byte body[], int len)
throws IOException {
int offset = 0;
do {
int inputLen = getStream().read(body, offset, len - offset);
if (inputLen <= 0) {
return offset;
}
offset += inputLen;
} while ((len - offset) > 0);
return len;
}
/**
* Parse request locales.
*/
protected void parseLocales() {
localesParsed = true;
Enumeration values = getHeaders("accept-language");
while (values.hasMoreElements()) {
String value = values.nextElement().toString();
parseLocalesHeader(value);
}
}
/**
* Parse accept-language header value.
*/
protected void parseLocalesHeader(String value) {
// 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 locales = new TreeMap();
// 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);
}
value = sb.toString();
}
// Process each comma-delimited language specification
parser.setString(value); // ASSERT: parser is available to us
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 {
quality = Double.parseDouble(entry.substring(semi + 3));
} 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 = "";
}
}
// 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 values = (ArrayList) locales.get(key);
if (values == null) {
values = new ArrayList();
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 (Object o : locales.keySet()) {
Double key = (Double) o;
ArrayList list = (ArrayList) locales.get(key);
for (Object aList : list) {
Locale locale = (Locale) aList;
addLocale(locale);
}
}
}
/**
* Parses the value of the JROUTE cookie, if present.
*/
void parseJrouteCookie() {
Cookies serverCookies = request.getCookies();
int count = serverCookies.getCookieCount();
if (count <= 0) {
return;
}
for (int i=0; iJROUTE
cookie or appended to the
* session identifier encoded in the URI (if cookies have been disabled).
*
* @return The jroute id of this request, or null if this request does not
* carry any jroute id
*/
public String getJrouteId() {
return jrouteId;
}
// ------------------------------------------------------ GrizzlySession support --/
/**
* Return the session associated with this Request, creating one
* if necessary.
*/
public GrizzlySession getSession() {
return doGetSession(true);
}
/**
* Return the session associated with this Request, creating one
* if necessary and requested.
*
* @param create Create a new session if one does not exist
*/
public GrizzlySession getSession(boolean create) {
return doGetSession(create);
}
protected GrizzlySession doGetSession(boolean create) {
// Return the current session if it exists and is valid
if ((session != null) && !session.isValid()) {
session = null;
}
if (session != null)
return (session);
if (requestedSessionId != null) {
session = sessions.get(requestedSessionId);
if ((session != null) && !session.isValid())
session = null;
if (session != null) {
return (session);
}
}
// Create a new session if requested and the response is not committed
if (!create)
return (null);
if (requestedSessionId != null) {
session = new GrizzlySession(requestedSessionId);
} else {
Random r = new Random();
requestedSessionId = String.valueOf(Math.abs(r.nextLong()));
session = new GrizzlySession(requestedSessionId);
}
sessions.put(requestedSessionId,session);
// Creating a new session cookie based on the newly created session
if (session != null) {
Cookie cookie = new Cookie(Globals.SESSION_COOKIE_NAME,
session.getIdInternal());
configureSessionCookie(cookie);
response.addCookie(cookie);
}
if (session != null) {
return (session);
} else {
return (null);
}
}
/**
* Configures the given JSESSIONID cookie.
*
* @param cookie The JSESSIONID cookie to be configured
*/
protected void configureSessionCookie(Cookie cookie) {
cookie.setMaxAge(-1);
String contextPath = null;
cookie.setPath("/");
if (isSecure()) {
cookie.setSecure(true);
}
}
protected Cookie makeCookie(ServerCookie scookie) {
return makeCookie(scookie, false);
}
protected Cookie makeCookie(ServerCookie scookie, boolean decode) {
String name = scookie.getName().toString();
String value = scookie.getValue().toString();
if (decode) {
try {
name = URLDecoder.decode(name, "UTF-8");
value = URLDecoder.decode(value, "UTF-8");
} catch (UnsupportedEncodingException e) {
name = URLDecoder.decode(name);
value = URLDecoder.decode(value);
}
}
return new Cookie(name, value);
}
/**
* Parse session id in URL.
*/
protected void parseSessionId() {
ByteChunk uriBC = request.requestURI().getByteChunk();
int semicolon = uriBC.indexOf(match, 0, match.length(), 0);
if (semicolon > 0) {
// Parse session ID, and extract it from the decoded request URI
int start = uriBC.getStart();
int end = uriBC.getEnd();
int sessionIdStart = start + semicolon + match.length();
int semicolon2 = uriBC.indexOf(';', sessionIdStart);
String sessionId = null;
if (semicolon2 >= 0) {
sessionId = new String(uriBC.getBuffer(), sessionIdStart,
semicolon2 - semicolon - match.length());
} else {
sessionId = new String(uriBC.getBuffer(), sessionIdStart,
end - sessionIdStart);
}
int jrouteIndex = sessionId.lastIndexOf(':');
if (jrouteIndex > 0) {
setRequestedSessionId(sessionId.substring(0, jrouteIndex));
if (jrouteIndex < (sessionId.length()-1)) {
setJrouteId(sessionId.substring(jrouteIndex+1));
}
} else {
setRequestedSessionId(sessionId);
}
setRequestedSessionURL(true);
if (!request.requestURI().getByteChunk().isNull()) {
parseSessionIdFromRequestURI();
}
} else {
setRequestedSessionId(null);
setRequestedSessionURL(false);
}
}
/**
* Extracts the session ID from the request URI.
*/
protected void parseSessionIdFromRequestURI() {
int start, end, sessionIdStart, semicolon, semicolon2;
MessageBytes requestURI = request.requestURI();
ByteChunk uriBC = requestURI.getByteChunk();
start = uriBC.getStart();
end = uriBC.getEnd();
semicolon = uriBC.indexOf(match, 0, match.length(), 0);
if (semicolon > 0) {
sessionIdStart = start + semicolon;
semicolon2 = uriBC.indexOf
(';', semicolon + match.length());
byte[] buf = uriBC.getBuffer();
if (semicolon2 >= 0) {
System.arraycopy(buf, start + semicolon2, buf, sessionIdStart, end - start - semicolon2);
requestURI.setBytes(buf, start, semicolon
+ (end - start - semicolon2));
} else {
requestURI.setBytes(buf, start, semicolon);
}
}
}
/**
* Set a flag indicating whether or not the requested session ID for this
* request came in through a cookie. This is normally called by the
* HTTP Connector, when it parses the request headers.
*
* @param flag The new flag
*/
public void setRequestedSessionCookie(boolean flag) {
this.requestedSessionCookie = flag;
}
/**
* Set the requested session ID for this request. This is normally called
* by the HTTP Connector, when it parses the request headers.
*
* @param id The new session id
*/
public void setRequestedSessionId(String id) {
this.requestedSessionId = id;
}
/**
* Set a flag indicating whether or not the requested session ID for this
* request came in through a URL. This is normally called by the
* HTTP Connector, when it parses the request headers.
*
* @param flag The new flag
*/
public void setRequestedSessionURL(boolean flag) {
this.requestedSessionURL = flag;
}
}