/* * Copyright 2003-2006 Rick Knowles <winstone-devel at lists sourceforge net> * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package winstone; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; import java.io.UnsupportedEncodingException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.Principal; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; import java.util.Hashtable; import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Random; import java.util.Set; import java.util.Stack; import java.util.StringTokenizer; import java.util.TimeZone; import javax.servlet.AsyncContext; import javax.servlet.DispatcherType; 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.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; /** * Implements the request interface required by the servlet spec. * * @author <a href="mailto:rick_knowles@hotmail.com">Rick Knowles</a> * @version $Id: WinstoneRequest.java,v 1.38 2007/10/28 16:29:02 rickknowles Exp * $ */ public class WinstoneRequest implements HttpServletRequest { protected static DateFormat headerDF = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US); protected static Random rnd = null; static { headerDF.setTimeZone(TimeZone.getTimeZone("GMT")); rnd = new Random(System.currentTimeMillis()); } // Request header constants static final String CONTENT_LENGTH_HEADER = "Content-Length"; static final String CONTENT_TYPE_HEADER = "Content-Type"; static final String AUTHORIZATION_HEADER = "Authorization"; static final String LOCALE_HEADER = "Accept-Language"; static final String HOST_HEADER = "Host"; static final String IN_COOKIE_HEADER1 = "Cookie"; static final String IN_COOKIE_HEADER2 = "Cookie2"; static final String METHOD_HEAD = "HEAD"; static final String METHOD_GET = "GET"; static final String METHOD_POST = "POST"; static final String POST_PARAMETERS = "application/x-www-form-urlencoded"; protected Map attributes; protected Map parameters; protected Stack attributesStack; protected Stack parametersStack; // protected Map forwardedParameters; protected String headers[]; protected Cookie cookies[]; protected String method; protected String scheme; protected String serverName; protected String requestURI; protected String servletPath; protected String pathInfo; protected String queryString; protected String protocol; protected int contentLength; protected String contentType; protected String encoding; protected int serverPort; protected String remoteIP; protected String remoteName; protected int remotePort; protected String localAddr; protected String localName; protected int localPort; protected Boolean parsedParameters; protected Map requestedSessionIds; protected Map currentSessionIds; protected String deadRequestedSessionId; protected List locales; protected String authorization; protected boolean isSecure; protected WinstoneInputStream inputData; protected BufferedReader inputReader; protected ServletConfiguration servletConfig; protected WebAppConfiguration webappConfig; protected HostGroup hostGroup; protected AuthenticationPrincipal authenticatedUser; protected ServletRequestAttributeListener requestAttributeListeners[]; protected ServletRequestListener requestListeners[]; private MessageDigest md5Digester; private final Set usedSessions; /** * InputStream factory method. */ public WinstoneRequest() throws IOException { this.attributes = new Hashtable(); this.parameters = new Hashtable(); this.locales = new ArrayList(); this.attributesStack = new Stack(); this.parametersStack = new Stack(); // this.forwardedParameters = new Hashtable(); this.requestedSessionIds = new Hashtable(); this.currentSessionIds = new Hashtable(); this.usedSessions = new HashSet(); this.contentLength = -1; this.isSecure = false; try { this.md5Digester = MessageDigest.getInstance("MD5"); } catch (NoSuchAlgorithmException err) { throw new WinstoneException("MD5 digester unavailable - what the ...?"); } } /** * Resets the request to be reused */ public void cleanUp() { this.requestListeners = null; this.requestAttributeListeners = null; this.attributes.clear(); this.parameters.clear(); this.attributesStack.clear(); this.parametersStack.clear(); // this.forwardedParameters.clear(); this.usedSessions.clear(); this.headers = null; this.cookies = null; this.method = null; this.scheme = null; this.serverName = null; this.requestURI = null; this.servletPath = null; this.pathInfo = null; this.queryString = null; this.protocol = null; this.contentLength = -1; this.contentType = null; this.encoding = null; this.inputData = null; this.inputReader = null; this.servletConfig = null; this.webappConfig = null; this.hostGroup = null; this.serverPort = -1; this.remoteIP = null; this.remoteName = null; this.remotePort = -1; this.localAddr = null; this.localName = null; this.localPort = -1; this.parsedParameters = null; this.requestedSessionIds.clear(); this.currentSessionIds.clear(); this.deadRequestedSessionId = null; this.locales.clear(); this.authorization = null; this.isSecure = false; this.authenticatedUser = null; } /** * Steps through the header array, searching for the first header matching */ private String extractFirstHeader(String name) { for (int n = 0; n < this.headers.length; n++) { if (this.headers[n].toUpperCase().startsWith(name.toUpperCase() + ':')) { return this.headers[n].substring(name.length() + 1).trim(); // 1 // for // colon } } return null; } private Collection extractHeaderNameList() { Collection headerNames = new HashSet(); for (int n = 0; n < this.headers.length; n++) { String name = this.headers[n]; int colonPos = name.indexOf(':'); headerNames.add(name.substring(0, colonPos)); } return headerNames; } public Map getAttributes() { return this.attributes; } public Map getParameters() { return this.parameters; } // // public Map getForwardedParameters() { // return this.forwardedParameters; // } public Stack getAttributesStack() { return this.attributesStack; } public Stack getParametersStack() { return this.parametersStack; } public Map getCurrentSessionIds() { return this.currentSessionIds; } public Map getRequestedSessionIds() { return this.requestedSessionIds; } public String getDeadRequestedSessionId() { return this.deadRequestedSessionId; } public HostGroup getHostGroup() { return this.hostGroup; } public WebAppConfiguration getWebAppConfig() { return this.webappConfig; } public ServletConfiguration getServletConfig() { return this.servletConfig; } public String getEncoding() { return this.encoding; } public Boolean getParsedParameters() { return this.parsedParameters; } public List getListLocales() { return this.locales; } public void setInputStream(WinstoneInputStream inputData) { this.inputData = inputData; } public void setHostGroup(HostGroup hostGroup) { this.hostGroup = hostGroup; } public void setWebAppConfig(WebAppConfiguration webappConfig) { this.webappConfig = webappConfig; } public void setServletConfig(ServletConfiguration servletConfig) { this.servletConfig = servletConfig; } public void setServerPort(int port) { this.serverPort = port; } public void setRemoteIP(String remoteIP) { this.remoteIP = remoteIP; } public void setRemoteName(String name) { this.remoteName = name; } public void setRemotePort(int port) { this.remotePort = port; } public void setLocalAddr(String ip) { this.localName = ip; } public void setLocalName(String name) { this.localName = name; } public void setLocalPort(int port) { this.localPort = port; } public void setMethod(String method) { this.method = method; } public void setIsSecure(boolean isSecure) { this.isSecure = isSecure; } public void setQueryString(String queryString) { this.queryString = queryString; } public void setServerName(String name) { this.serverName = name; } public void setRequestURI(String requestURI) { this.requestURI = requestURI; } public void setScheme(String scheme) { this.scheme = scheme; } public void setServletPath(String servletPath) { this.servletPath = servletPath; } public void setPathInfo(String pathInfo) { this.pathInfo = pathInfo; } public void setProtocol(String protocolString) { this.protocol = protocolString; } public void setRemoteUser(AuthenticationPrincipal user) { this.authenticatedUser = user; } public void setContentLength(int len) { this.contentLength = len; } public void setContentType(String type) { this.contentType = type; } public void setAuthorization(String auth) { this.authorization = auth; } public void setLocales(List locales) { this.locales = locales; } public void setCurrentSessionIds(Map currentSessionIds) { this.currentSessionIds = currentSessionIds; } public void setRequestedSessionIds(Map requestedSessionIds) { this.requestedSessionIds = requestedSessionIds; } public void setDeadRequestedSessionId(String deadRequestedSessionId) { this.deadRequestedSessionId = deadRequestedSessionId; } public void setEncoding(String encoding) { this.encoding = encoding; } public void setParsedParameters(Boolean parsed) { this.parsedParameters = parsed; } public void setRequestListeners(ServletRequestListener rl[]) { this.requestListeners = rl; } public void setRequestAttributeListeners(ServletRequestAttributeListener ral[]) { this.requestAttributeListeners = ral; } /** * Gets parameters from the url encoded parameter string */ public static void extractParameters(String urlEncodedParams, String encoding, Map outputParams, boolean overwrite) { Logger.log(Logger.DEBUG, Launcher.RESOURCES, "WinstoneRequest.ParsingParameters", new String[] { urlEncodedParams, encoding }); StringTokenizer st = new StringTokenizer(urlEncodedParams, "&", false); Set overwrittenParamNames = null; while (st.hasMoreTokens()) { String token = st.nextToken(); int equalPos = token.indexOf('='); try { String decodedNameDefault = decodeURLToken(equalPos == -1 ? token : token.substring(0, equalPos)); String decodedValueDefault = (equalPos == -1 ? "" : decodeURLToken(token.substring(equalPos + 1))); String decodedName = (encoding == null ? decodedNameDefault : new String(decodedNameDefault.getBytes("8859_1"), encoding)); String decodedValue = (encoding == null ? decodedValueDefault : new String(decodedValueDefault.getBytes("8859_1"), encoding)); Object already = null; if (overwrite) { if (overwrittenParamNames == null) { overwrittenParamNames = new HashSet(); } if (!overwrittenParamNames.contains(decodedName)) { overwrittenParamNames.add(decodedName); outputParams.remove(decodedName); } } already = outputParams.get(decodedName); if (already == null) { outputParams.put(decodedName, decodedValue); } else if (already instanceof String) { String pair[] = new String[2]; pair[0] = (String) already; pair[1] = decodedValue; outputParams.put(decodedName, pair); } else if (already instanceof String[]) { String alreadyArray[] = (String[]) already; String oneMore[] = new String[alreadyArray.length + 1]; System.arraycopy(alreadyArray, 0, oneMore, 0, alreadyArray.length); oneMore[oneMore.length - 1] = decodedValue; outputParams.put(decodedName, oneMore); } else { Logger.log(Logger.WARNING, Launcher.RESOURCES, "WinstoneRequest.UnknownParameterType", decodedName + " = " + decodedValue.getClass()); } } catch (UnsupportedEncodingException err) { Logger.log(Logger.ERROR, Launcher.RESOURCES, "WinstoneRequest.ErrorParameters", err); } } } /** * For decoding the URL encoding used on query strings */ public static String decodeURLToken(String in) { StringBuffer workspace = new StringBuffer(); for (int n = 0; n < in.length(); n++) { char thisChar = in.charAt(n); if (thisChar == '+') workspace.append(' '); else if (thisChar == '%') { String token = in.substring(Math.min(n + 1, in.length()), Math.min(n + 3, in.length())); try { int decoded = Integer.parseInt(token, 16); workspace.append((char) decoded); n += 2; } catch (RuntimeException err) { Logger.log(Logger.WARNING, Launcher.RESOURCES, "WinstoneRequest.InvalidURLTokenChar", token); workspace.append(thisChar); } } else workspace.append(thisChar); } return workspace.toString(); } public void discardRequestBody() { if (getContentLength() > 0) { try { Logger.log(Logger.DEBUG, Launcher.RESOURCES, "WinstoneResponse.ForceBodyParsing"); // If body not parsed if ((this.parsedParameters == null) || (this.parsedParameters.equals(Boolean.FALSE))) { // read full stream length try { InputStream in = getInputStream(); byte buffer[] = new byte[2048]; while (in.read(buffer) != -1) ; } catch (IllegalStateException err) { Reader in = getReader(); char buffer[] = new char[2048]; while (in.read(buffer) != -1) ; } } } catch (IOException err) { Logger.log(Logger.DEBUG, Launcher.RESOURCES, "WinstoneResponse.ErrorForceBodyParsing", err); } } } /** * This takes the parameters in the body of the request and puts them into * the parameters map. */ public void parseRequestParameters() { if ((parsedParameters != null) && !parsedParameters.booleanValue()) { Logger.log(Logger.WARNING, Launcher.RESOURCES, "WinstoneRequest.BothMethods"); this.parsedParameters = Boolean.TRUE; } else if (parsedParameters == null) { Map workingParameters = new HashMap(); try { // Parse query string from request if ((method.equals(METHOD_GET) || method.equals(METHOD_HEAD) || method.equals(METHOD_POST)) && (this.queryString != null)) { extractParameters(this.queryString, this.encoding, workingParameters, false); Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES, "WinstoneRequest.ParamLine", "" + workingParameters); } if (method.equals(METHOD_POST) && (contentType != null) && (contentType.equals(POST_PARAMETERS) || contentType.startsWith(POST_PARAMETERS + ";"))) { Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES, "WinstoneRequest.ParsingBodyParameters"); // Parse params byte paramBuffer[] = new byte[contentLength]; int readCount = this.inputData.read(paramBuffer); if (readCount != contentLength) Logger.log(Logger.WARNING, Launcher.RESOURCES, "WinstoneRequest.IncorrectContentLength", new String[] { contentLength + "", readCount + "" }); String paramLine = (this.encoding == null ? new String(paramBuffer) : new String(paramBuffer, this.encoding)); extractParameters(paramLine.trim(), this.encoding, workingParameters, false); Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES, "WinstoneRequest.ParamLine", "" + workingParameters); } this.parameters.putAll(workingParameters); this.parsedParameters = Boolean.TRUE; } catch (Throwable err) { Logger.log(Logger.ERROR, Launcher.RESOURCES, "WinstoneRequest.ErrorBodyParameters", err); this.parsedParameters = null; } } } /** * Go through the list of headers, and build the headers/cookies arrays for * the request object. */ public void parseHeaders(List headerList) { // Iterate through headers List outHeaderList = new ArrayList(); List cookieList = new ArrayList(); for (Iterator i = headerList.iterator(); i.hasNext();) { String header = (String) i.next(); int colonPos = header.indexOf(':'); String name = header.substring(0, colonPos); String value = header.substring(colonPos + 1).trim(); // Add it to out headers if it's not a cookie outHeaderList.add(header); // if (!name.equalsIgnoreCase(IN_COOKIE_HEADER1) // && !name.equalsIgnoreCase(IN_COOKIE_HEADER2)) if (name.equalsIgnoreCase(AUTHORIZATION_HEADER)) this.authorization = value; else if (name.equalsIgnoreCase(LOCALE_HEADER)) this.locales = parseLocales(value); else if (name.equalsIgnoreCase(CONTENT_LENGTH_HEADER)) this.contentLength = Integer.parseInt(value); else if (name.equalsIgnoreCase(HOST_HEADER)) { int nextColonPos = value.indexOf(':'); if ((nextColonPos == -1) || (nextColonPos == value.length() - 1)) { this.serverName = value; if (this.scheme != null) { if (this.scheme.equals("http")) { this.serverPort = 80; } else if (this.scheme.equals("https")) { this.serverPort = 443; } } } else { this.serverName = value.substring(0, nextColonPos); this.serverPort = Integer.parseInt(value.substring(nextColonPos + 1)); } } else if (name.equalsIgnoreCase(CONTENT_TYPE_HEADER)) { this.contentType = value; int semicolon = value.lastIndexOf(';'); if (semicolon != -1) { String encodingClause = value.substring(semicolon + 1).trim(); if (encodingClause.startsWith("charset=")) this.encoding = encodingClause.substring(8); } } else if (name.equalsIgnoreCase(IN_COOKIE_HEADER1) || name.equalsIgnoreCase(IN_COOKIE_HEADER2)) parseCookieLine(value, cookieList); } this.headers = (String[]) outHeaderList.toArray(new String[0]); if (cookieList.isEmpty()) { this.cookies = null; } else { this.cookies = (Cookie[]) cookieList.toArray(new Cookie[0]); } } private static String nextToken(StringTokenizer st) { if (st.hasMoreTokens()) { return st.nextToken(); } else { return null; } } private void parseCookieLine(String headerValue, List cookieList) { StringTokenizer st = new StringTokenizer(headerValue, ";", false); int version = 0; String cookieLine = nextToken(st); // check cookie version flag if ((cookieLine != null) && cookieLine.startsWith("$Version=")) { int equalPos = cookieLine.indexOf('='); try { version = Integer.parseInt(extractFromQuotes(cookieLine.substring(equalPos + 1).trim())); } catch (NumberFormatException err) { version = 0; } cookieLine = nextToken(st); } // process remainder - parameters while (cookieLine != null) { cookieLine = cookieLine.trim(); int equalPos = cookieLine.indexOf('='); if (equalPos == -1) { // next token cookieLine = nextToken(st); } else { String name = cookieLine.substring(0, equalPos); String value = extractFromQuotes(cookieLine.substring(equalPos + 1)); Cookie thisCookie = new Cookie(name, value); thisCookie.setVersion(version); thisCookie.setSecure(isSecure()); cookieList.add(thisCookie); // check for path / domain / port cookieLine = nextToken(st); while ((cookieLine != null) && cookieLine.trim().startsWith("$")) { cookieLine = cookieLine.trim(); equalPos = cookieLine.indexOf('='); String attrValue = equalPos == -1 ? "" : cookieLine.substring(equalPos + 1).trim(); if (cookieLine.startsWith("$Path")) { thisCookie.setPath(extractFromQuotes(attrValue)); } else if (cookieLine.startsWith("$Domain")) { thisCookie.setDomain(extractFromQuotes(attrValue)); } cookieLine = nextToken(st); } Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES, "WinstoneRequest.CookieFound", thisCookie.toString()); if (thisCookie.getName().equals(WinstoneSession.SESSION_COOKIE_NAME)) { // Find a context that manages this key HostConfiguration hostConfig = this.hostGroup.getHostByName(this.serverName); WebAppConfiguration ownerContext = hostConfig.getWebAppBySessionKey(thisCookie.getValue()); if (ownerContext != null) { this.requestedSessionIds.put(ownerContext.getContextPath(), thisCookie.getValue()); this.currentSessionIds.put(ownerContext.getContextPath(), thisCookie.getValue()); } // If not found, it was probably dead else { this.deadRequestedSessionId = thisCookie.getValue(); } // this.requestedSessionId = thisCookie.getValue(); // this.currentSessionId = thisCookie.getValue(); Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES, "WinstoneRequest.SessionCookieFound", new String[] { thisCookie.getValue(), ownerContext == null ? "" : "prefix:" + ownerContext.getContextPath() }); } } } } private static String extractFromQuotes(String input) { if ((input != null) && input.startsWith("\"") && input.endsWith("\"")) { return input.substring(1, input.length() - 1); } else { return input; } } private List parseLocales(String header) { // Strip out the whitespace StringBuffer lb = new StringBuffer(); for (int n = 0; n < header.length(); n++) { char c = header.charAt(n); if (!Character.isWhitespace(c)) lb.append(c); } // Tokenize by commas Map localeEntries = new HashMap(); StringTokenizer commaTK = new StringTokenizer(lb.toString(), ",", false); for (; commaTK.hasMoreTokens();) { String clause = commaTK.nextToken(); // Tokenize by semicolon Float quality = new Float(1); if (clause.indexOf(";q=") != -1) { int pos = clause.indexOf(";q="); try { quality = new Float(clause.substring(pos + 3)); } catch (NumberFormatException err) { quality = new Float(0); } clause = clause.substring(0, pos); } // Build the locale String language = ""; String country = ""; String variant = ""; int dpos = clause.indexOf('-'); if (dpos == -1) language = clause; else { language = clause.substring(0, dpos); String remainder = clause.substring(dpos + 1); int d2pos = remainder.indexOf('-'); if (d2pos == -1) country = remainder; else { country = remainder.substring(0, d2pos); variant = remainder.substring(d2pos + 1); } } Locale loc = new Locale(language, country, variant); // Put into list by quality List localeList = (List) localeEntries.get(quality); if (localeList == null) { localeList = new ArrayList(); localeEntries.put(quality, localeList); } localeList.add(loc); } // Extract and build the list Float orderKeys[] = (Float[]) localeEntries.keySet().toArray(new Float[0]); Arrays.sort(orderKeys); List outputLocaleList = new ArrayList(); for (int n = 0; n < orderKeys.length; n++) { // Skip backwards through the list of maps and add to the output // list int reversedIndex = (orderKeys.length - 1) - n; if ((orderKeys[reversedIndex].floatValue() <= 0) || (orderKeys[reversedIndex].floatValue() > 1)) continue; List localeList = (List) localeEntries.get(orderKeys[reversedIndex]); for (Iterator i = localeList.iterator(); i.hasNext();) outputLocaleList.add(i.next()); } return outputLocaleList; } public void addIncludeQueryParameters(String queryString) { Map lastParams = new Hashtable(); if (!this.parametersStack.isEmpty()) { lastParams.putAll((Map) this.parametersStack.peek()); } Map newQueryParams = new HashMap(); if (queryString != null) { extractParameters(queryString, this.encoding, newQueryParams, false); } lastParams.putAll(newQueryParams); this.parametersStack.push(lastParams); } public void addIncludeAttributes(String requestURI, String contextPath, String servletPath, String pathInfo, String queryString) { Map includeAttributes = new HashMap(); if (requestURI != null) { includeAttributes.put(RequestDispatcher.INCLUDE_REQUEST_URI, requestURI); } if (contextPath != null) { includeAttributes.put(RequestDispatcher.INCLUDE_CONTEXT_PATH, contextPath); } if (servletPath != null) { includeAttributes.put(RequestDispatcher.INCLUDE_SERVLET_PATH, servletPath); } if (pathInfo != null) { includeAttributes.put(RequestDispatcher.INCLUDE_PATH_INFO, pathInfo); } if (queryString != null) { includeAttributes.put(RequestDispatcher.INCLUDE_QUERY_STRING, queryString); } this.attributesStack.push(includeAttributes); } public void removeIncludeQueryString() { if (!this.parametersStack.isEmpty()) { this.parametersStack.pop(); } } public void clearIncludeStackForForward() { this.parametersStack.clear(); this.attributesStack.clear(); } public void setForwardQueryString(String forwardQueryString) { // this.forwardedParameters.clear(); // Parse query string from include / forward if (forwardQueryString != null) { String oldQueryString = this.queryString == null ? "" : this.queryString; boolean needJoiner = !forwardQueryString.equals("") && !oldQueryString.equals(""); this.queryString = forwardQueryString + (needJoiner ? "&" : "") + oldQueryString; if (this.parsedParameters != null) { Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES, "WinstoneRequest.ParsingParameters", new String[] { forwardQueryString, this.encoding }); extractParameters(forwardQueryString, this.encoding, this.parameters, true); Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES, "WinstoneRequest.ParamLine", "" + this.parameters); } } } public void removeIncludeAttributes() { if (!this.attributesStack.isEmpty()) { this.attributesStack.pop(); } } // Implementation methods for the servlet request stuff @Override public Object getAttribute(String name) { if (!this.attributesStack.isEmpty()) { Map includedAttributes = (Map) this.attributesStack.peek(); Object value = includedAttributes.get(name); if (value != null) { return value; } } return this.attributes.get(name); } @Override public Enumeration getAttributeNames() { Map attributes = new HashMap(this.attributes); if (!this.attributesStack.isEmpty()) { Map includedAttributes = (Map) this.attributesStack.peek(); attributes.putAll(includedAttributes); } return Collections.enumeration(attributes.keySet()); } @Override public void removeAttribute(String name) { Object value = attributes.get(name); if (value == null) return; // fire event if (this.requestAttributeListeners != null) { for (int n = 0; n < this.requestAttributeListeners.length; n++) { ClassLoader cl = Thread.currentThread().getContextClassLoader(); Thread.currentThread().setContextClassLoader(getWebAppConfig().getLoader()); this.requestAttributeListeners[n].attributeRemoved(new ServletRequestAttributeEvent(this.webappConfig, this, name, value)); Thread.currentThread().setContextClassLoader(cl); } } this.attributes.remove(name); } @Override public void setAttribute(String name, Object o) { if ((name != null) && (o != null)) { Object oldValue = attributes.get(name); attributes.put(name, o); // make sure it's set at the top level // fire event if (this.requestAttributeListeners != null) { if (oldValue == null) { for (int n = 0; n < this.requestAttributeListeners.length; n++) { ClassLoader cl = Thread.currentThread().getContextClassLoader(); Thread.currentThread().setContextClassLoader(getWebAppConfig().getLoader()); this.requestAttributeListeners[n].attributeAdded(new ServletRequestAttributeEvent(this.webappConfig, this, name, o)); Thread.currentThread().setContextClassLoader(cl); } } else { for (int n = 0; n < this.requestAttributeListeners.length; n++) { ClassLoader cl = Thread.currentThread().getContextClassLoader(); Thread.currentThread().setContextClassLoader(getWebAppConfig().getLoader()); this.requestAttributeListeners[n].attributeReplaced(new ServletRequestAttributeEvent(this.webappConfig, this, name, oldValue)); Thread.currentThread().setContextClassLoader(cl); } } } } else if (name != null) { removeAttribute(name); } } @Override public String getCharacterEncoding() { return this.encoding; } @Override public void setCharacterEncoding(String encoding) throws UnsupportedEncodingException { "blah".getBytes(encoding); // throws an exception if the encoding is // unsupported if (this.inputReader == null) { Logger.log(Logger.DEBUG, Launcher.RESOURCES, "WinstoneRequest.SetCharEncoding", new String[] { this.encoding, encoding }); this.encoding = encoding; } } @Override public int getContentLength() { return this.contentLength; } @Override public String getContentType() { return this.contentType; } @Override public Locale getLocale() { return this.locales.isEmpty() ? Locale.getDefault() : (Locale) this.locales.get(0); } @Override public Enumeration getLocales() { List sendLocales = this.locales; if (sendLocales.isEmpty()) sendLocales.add(Locale.getDefault()); return Collections.enumeration(sendLocales); } @Override public String getProtocol() { return this.protocol; } @Override public String getScheme() { return this.scheme; } @Override public boolean isSecure() { return this.isSecure; } @Override public BufferedReader getReader() throws IOException { if (this.inputReader != null) { return this.inputReader; } else { if (this.parsedParameters != null) { if (this.parsedParameters.equals(Boolean.TRUE)) { Logger.log(Logger.WARNING, Launcher.RESOURCES, "WinstoneRequest.BothMethodsReader"); } else { throw new IllegalStateException(Launcher.RESOURCES.getString("WinstoneRequest.CalledReaderAfterStream")); } } if (this.encoding != null) { this.inputReader = new BufferedReader(new InputStreamReader(this.inputData, this.encoding)); } else { this.inputReader = new BufferedReader(new InputStreamReader(this.inputData)); } this.parsedParameters = new Boolean(false); return this.inputReader; } } @Override public ServletInputStream getInputStream() throws IOException { if (this.inputReader != null) { throw new IllegalStateException(Launcher.RESOURCES.getString("WinstoneRequest.CalledStreamAfterReader")); } if (this.parsedParameters != null) { if (this.parsedParameters.equals(Boolean.TRUE)) { Logger.log(Logger.WARNING, Launcher.RESOURCES, "WinstoneRequest.BothMethods"); } } this.parsedParameters = new Boolean(false); return this.inputData; } @Override public String getParameter(String name) { parseRequestParameters(); Object param = null; if (!this.parametersStack.isEmpty()) { param = ((Map) this.parametersStack.peek()).get(name); } // if ((param == null) && this.forwardedParameters.get(name) != null) { // param = this.forwardedParameters.get(name); // } if (param == null) { param = this.parameters.get(name); } if (param == null) return null; else if (param instanceof String) return (String) param; else if (param instanceof String[]) return ((String[]) param)[0]; else return param.toString(); } @Override public Enumeration getParameterNames() { parseRequestParameters(); Set parameterKeys = new HashSet(this.parameters.keySet()); // parameterKeys.addAll(this.forwardedParameters.keySet()); if (!this.parametersStack.isEmpty()) { parameterKeys.addAll(((Map) this.parametersStack.peek()).keySet()); } return Collections.enumeration(parameterKeys); } @Override public String[] getParameterValues(String name) { parseRequestParameters(); Object param = null; if (!this.parametersStack.isEmpty()) { param = ((Map) this.parametersStack.peek()).get(name); } // if ((param == null) && this.forwardedParameters.get(name) != null) { // param = this.forwardedParameters.get(name); // } if (param == null) { param = this.parameters.get(name); } if (param == null) return null; else if (param instanceof String) { return new String[] { (String) param }; } else if (param instanceof String[]) return (String[]) param; else throw new WinstoneException(Launcher.RESOURCES.getString("WinstoneRequest.UnknownParameterType", name + " - " + param.getClass())); } @Override public Map getParameterMap() { Hashtable paramMap = new Hashtable(); for (Enumeration names = this.getParameterNames(); names.hasMoreElements();) { String name = (String) names.nextElement(); paramMap.put(name, getParameterValues(name)); } return paramMap; } @Override public String getServerName() { return this.serverName; } @Override public int getServerPort() { return this.serverPort; } @Override public String getRemoteAddr() { return this.remoteIP; } @Override public String getRemoteHost() { return this.remoteName; } @Override public int getRemotePort() { return this.remotePort; } @Override public String getLocalAddr() { return this.localAddr; } @Override public String getLocalName() { return this.localName; } @Override public int getLocalPort() { return this.localPort; } @Override public javax.servlet.RequestDispatcher getRequestDispatcher(String path) { if (path.startsWith("/")) return this.webappConfig.getRequestDispatcher(path); // Take the servlet path + pathInfo, and make an absolute path String fullPath = getServletPath() + (getPathInfo() == null ? "" : getPathInfo()); int lastSlash = fullPath.lastIndexOf('/'); String currentDir = (lastSlash == -1 ? "/" : fullPath.substring(0, lastSlash + 1)); return this.webappConfig.getRequestDispatcher(currentDir + path); } // Now the stuff for HttpServletRequest @Override public String getContextPath() { return this.webappConfig.getContextPath(); } @Override public Cookie[] getCookies() { return this.cookies; } @Override public long getDateHeader(String name) { String dateHeader = getHeader(name); if (dateHeader == null) { return -1; } else try { Date date = null; synchronized (headerDF) { date = headerDF.parse(dateHeader); } return date.getTime(); } catch (java.text.ParseException err) { throw new IllegalArgumentException(Launcher.RESOURCES.getString("WinstoneRequest.BadDate", dateHeader)); } } @Override public int getIntHeader(String name) { String header = getHeader(name); return header == null ? -1 : Integer.parseInt(header); } @Override public String getHeader(String name) { return extractFirstHeader(name); } @Override public Enumeration getHeaderNames() { return Collections.enumeration(extractHeaderNameList()); } @Override public Enumeration getHeaders(String name) { List headers = new ArrayList(); for (int n = 0; n < this.headers.length; n++) if (this.headers[n].toUpperCase().startsWith(name.toUpperCase() + ':')) headers.add(this.headers[n].substring(name.length() + 1).trim()); // 1 // for // colon return Collections.enumeration(headers); } @Override public String getMethod() { return this.method; } @Override public String getPathInfo() { return this.pathInfo; } @Override public String getPathTranslated() { return this.webappConfig.getRealPath(this.pathInfo); } @Override public String getQueryString() { return this.queryString; } @Override public String getRequestURI() { return this.requestURI; } @Override public String getServletPath() { return this.servletPath; } @Override public String getRequestedSessionId() { String actualSessionId = (String) this.requestedSessionIds.get(this.webappConfig.getContextPath()); if (actualSessionId != null) { return actualSessionId; } else { return this.deadRequestedSessionId; } } @Override public StringBuffer getRequestURL() { StringBuffer url = new StringBuffer(); url.append(getScheme()).append("://"); url.append(getServerName()); if (!((getServerPort() == 80) && getScheme().equals("http")) && !((getServerPort() == 443) && getScheme().equals("https"))) url.append(':').append(getServerPort()); url.append(getRequestURI()); // need encoded form, so can't use servlet // path + path info return url; } @Override public Principal getUserPrincipal() { return this.authenticatedUser; } @Override public boolean isUserInRole(String role) { if (this.authenticatedUser == null) return false; else if (this.servletConfig.getSecurityRoleRefs() == null) return this.authenticatedUser.isUserIsInRole(role); else { String replacedRole = (String) this.servletConfig.getSecurityRoleRefs().get(role); return this.authenticatedUser.isUserIsInRole(replacedRole == null ? role : replacedRole); } } @Override public String getAuthType() { return this.authenticatedUser == null ? null : this.authenticatedUser.getAuthType(); } @Override public String getRemoteUser() { return this.authenticatedUser == null ? null : this.authenticatedUser.getName(); } @Override public boolean isRequestedSessionIdFromCookie() { return (getRequestedSessionId() != null); } @Override public boolean isRequestedSessionIdFromURL() { return false; } @Override public boolean isRequestedSessionIdValid() { String requestedId = getRequestedSessionId(); if (requestedId == null) { return false; } WinstoneSession ws = this.webappConfig.getSessionById(requestedId, false); return (ws != null); // if (ws == null) { // return false; // } else { // return (validationCheck(ws, System.currentTimeMillis(), false) != // null); // } } @Override public HttpSession getSession() { return getSession(true); } @Override public HttpSession getSession(boolean create) { String cookieValue = (String) this.currentSessionIds.get(this.webappConfig.getContextPath()); // Handle the null case if (cookieValue == null) { if (!create) { return null; } else { cookieValue = makeNewSession().getId(); } } // Now get the session object WinstoneSession session = this.webappConfig.getSessionById(cookieValue, false); if (session != null) { // long nowDate = System.currentTimeMillis(); // session = validationCheck(session, nowDate, create); // if (session == null) { // this.currentSessionIds.remove(this.webappConfig.getContextPath()); // } } if (create && (session == null)) { session = makeNewSession(); } if (session != null) { this.usedSessions.add(session); session.addUsed(this); } return session; } /** * Make a new session, and return the id */ private WinstoneSession makeNewSession() { String cookieValue = "Winstone_" + this.remoteIP + "_" + this.serverPort + "_" + System.currentTimeMillis() + rnd.nextLong(); byte digestBytes[] = this.md5Digester.digest(cookieValue.getBytes()); // Write out in hex format char outArray[] = new char[32]; for (int n = 0; n < digestBytes.length; n++) { int hiNibble = (digestBytes[n] & 0xFF) >> 4; int loNibble = (digestBytes[n] & 0xF); outArray[2 * n] = (hiNibble > 9 ? (char) (hiNibble + 87) : (char) (hiNibble + 48)); outArray[2 * n + 1] = (loNibble > 9 ? (char) (loNibble + 87) : (char) (loNibble + 48)); } String newSessionId = new String(outArray); this.currentSessionIds.put(this.webappConfig.getContextPath(), newSessionId); return this.webappConfig.makeNewSession(newSessionId); } public void markSessionsAsRequestFinished(long lastAccessedTime, boolean saveSessions) { for (Iterator i = this.usedSessions.iterator(); i.hasNext();) { WinstoneSession session = (WinstoneSession) i.next(); session.setLastAccessedDate(lastAccessedTime); session.removeUsed(this); if (saveSessions) { session.saveToTemp(); } } this.usedSessions.clear(); } /** * @deprecated */ @Deprecated @Override public String getRealPath(String path) { return this.webappConfig.getRealPath(path); } /** * @deprecated */ @Deprecated @Override public boolean isRequestedSessionIdFromUrl() { return isRequestedSessionIdFromURL(); } @Override public AsyncContext getAsyncContext() { // TODO Auto-generated method stub return null; } @Override public DispatcherType getDispatcherType() { // TODO Auto-generated method stub return null; } @Override public ServletContext getServletContext() { // TODO Auto-generated method stub return null; } @Override public boolean isAsyncStarted() { // TODO Auto-generated method stub return false; } @Override public boolean isAsyncSupported() { // TODO Auto-generated method stub return false; } @Override public AsyncContext startAsync() throws IllegalStateException { // TODO Auto-generated method stub return null; } @Override public AsyncContext startAsync(ServletRequest arg0, ServletResponse arg1) throws IllegalStateException { // TODO Auto-generated method stub return null; } @Override public boolean authenticate(HttpServletResponse arg0) throws IOException, ServletException { // TODO Auto-generated method stub return false; } @Override public Part getPart(String arg0) throws IOException, ServletException { // TODO Auto-generated method stub return null; } @Override public Collection<Part> getParts() throws IOException, ServletException { // TODO Auto-generated method stub return null; } @Override public void login(String arg0, String arg1) throws ServletException { // TODO Auto-generated method stub } @Override public void logout() throws ServletException { // TODO Auto-generated method stub } }