org.glassfish.grizzly.http.server.Response Maven / Gradle / Ivy
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 2008-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.
*
*
* 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 org.glassfish.grizzly.http.server;
import java.io.IOException;
import java.io.OutputStream;
import java.io.Writer;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.LinkedList;
import java.util.Locale;
import java.util.TimeZone;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.glassfish.grizzly.CloseListener;
import org.glassfish.grizzly.CloseType;
import org.glassfish.grizzly.Closeable;
import org.glassfish.grizzly.CompletionHandler;
import org.glassfish.grizzly.GenericCloseListener;
import org.glassfish.grizzly.Grizzly;
import org.glassfish.grizzly.filterchain.FilterChainContext;
import org.glassfish.grizzly.http.Cookie;
import org.glassfish.grizzly.http.Cookies;
import org.glassfish.grizzly.http.HttpContext;
import org.glassfish.grizzly.http.HttpResponsePacket;
import org.glassfish.grizzly.http.io.InputBuffer;
import org.glassfish.grizzly.http.io.NIOOutputStream;
import org.glassfish.grizzly.http.io.NIOWriter;
import org.glassfish.grizzly.http.io.OutputBuffer;
import org.glassfish.grizzly.http.server.io.ServerOutputBuffer;
import org.glassfish.grizzly.http.server.util.Globals;
import org.glassfish.grizzly.http.server.util.HtmlHelper;
import org.glassfish.grizzly.http.util.CharChunk;
import static org.glassfish.grizzly.http.util.Constants.*;
import org.glassfish.grizzly.http.util.ContentType;
import org.glassfish.grizzly.http.util.CookieSerializerUtils;
import org.glassfish.grizzly.http.util.FastHttpDateFormat;
import org.glassfish.grizzly.http.util.Header;
import org.glassfish.grizzly.http.util.HeaderValue;
import org.glassfish.grizzly.http.util.HttpRequestURIDecoder;
import org.glassfish.grizzly.http.util.HttpStatus;
import org.glassfish.grizzly.http.util.MimeHeaders;
import org.glassfish.grizzly.http.util.UEncoder;
import org.glassfish.grizzly.localization.LogMessages;
import org.glassfish.grizzly.utils.DelayedExecutor;
import org.glassfish.grizzly.utils.DelayedExecutor.DelayQueue;
/**
* Wrapper object for the Coyote response.
*
* @author Remy Maucherat
* @author Craig R. McClanahan
* @version $Revision: 1.2 $ $Date: 2006/11/02 20:01:44 $
*/
public class Response {
enum SuspendState {
NONE, SUSPENDED, RESUMING, RESUMED, CANCELLING, CANCELLED
}
private static final Logger LOGGER = Grizzly.logger(Response.class);
static DelayQueue createDelayQueue(
final DelayedExecutor delayedExecutor) {
return delayedExecutor.createDelayQueue(new DelayQueueWorker(),
new DelayQueueResolver());
}
// ----------------------------------------------------------- Constructors
protected Response() {
urlEncoder.addSafeCharacter('/');
}
// ----------------------------------------------------- Instance Variables
private boolean cacheEnabled = false;
/**
* Default locale as mandated by the spec.
*/
private static final Locale DEFAULT_LOCALE = Locale.getDefault();
private static final String HTTP_RESPONSE_DATE_HEADER =
"EEE, dd MMM yyyy HH:mm:ss zzz";
/**
* The date format we will use for creating date headers.
*/
protected SimpleDateFormat format = null;
/**
* Descriptive information about this Response implementation.
*/
protected static final String info =
"org.glassfish.grizzly.http.server.Response/2.0";
// ------------------------------------------------------------- Properties
/**
* The request with which this response is associated.
*/
protected Request request = null;
/**
* Coyote response.
*/
protected HttpResponsePacket response;
/**
* Grizzly {@link org.glassfish.grizzly.filterchain.FilterChain} context,
* related to this HTTP request/response
*/
protected FilterChainContext ctx;
/**
* Grizzly {@link HttpContext} associated with the current Request/Response
* processing.
*/
protected HttpContext httpContext;
/**
* The associated output buffer.
*/
protected final ServerOutputBuffer outputBuffer = new ServerOutputBuffer();
/**
* The associated output stream.
*/
private final NIOOutputStreamImpl outputStream = new NIOOutputStreamImpl();
/**
* The associated writer.
*/
private final NIOWriterImpl writer = new NIOWriterImpl();
/**
* The application commit flag.
*/
protected boolean appCommitted = false;
/**
* The error flag.
*/
protected boolean error = false;
/**
* Using output stream flag.
*/
protected boolean usingOutputStream = false;
/**
* Using writer flag.
*/
protected boolean usingWriter = false;
/**
* URL encoder.
*/
protected final UEncoder urlEncoder = new UEncoder();
/**
* Recyclable buffer to hold the redirect URL.
*/
protected final CharChunk redirectURLCC = new CharChunk();
protected DelayedExecutor.DelayQueue delayQueue;
SuspendState suspendState = SuspendState.NONE;
private final SuspendedContextImpl suspendedContext = new SuspendedContextImpl();
private SuspendStatus suspendStatus;
private boolean sendFileEnabled;
private ErrorPageGenerator errorPageGenerator;
// --------------------------------------------------------- Public Methods
public void initialize(final Request request,
final HttpResponsePacket response,
final FilterChainContext ctx,
final DelayedExecutor.DelayQueue delayQueue,
final HttpServerFilter serverFilter) {
this.request = request;
this.response = response;
sendFileEnabled = ((serverFilter != null)
&& serverFilter.getConfiguration().isSendFileEnabled());
outputBuffer.initialize(this, ctx);
this.ctx = ctx;
this.httpContext = HttpContext.get(ctx);
this.delayQueue = delayQueue;
}
SuspendStatus initSuspendStatus() {
suspendStatus = SuspendStatus.create();
return suspendStatus;
}
/**
* Return the Request with which this Response is associated.
*/
public Request getRequest() {
return request;
}
/**
* Get the {@link HttpResponsePacket}.
*/
public HttpResponsePacket getResponse() {
return response;
}
/**
* Release all object references, and initialize instance variables, in
* preparation for reuse of this object.
*/
protected void recycle() {
delayQueue = null;
outputBuffer.recycle();
outputStream.recycle();
writer.recycle();
usingOutputStream = false;
usingWriter = false;
appCommitted = false;
error = false;
errorPageGenerator = null;
request = null;
response.recycle();
sendFileEnabled = false;
response = null;
ctx = null;
suspendState = SuspendState.NONE;
cacheEnabled = false;
}
// ------------------------------------------------------- Response Methods
/**
* Encode the session identifier associated with this response
* into the specified URL, if necessary.
*
* @param url URL to be encoded
*/
public String encodeURL(String url) {
String absolute = toAbsolute(url, false);
if (isEncodeable(absolute)) {
// W3c spec clearly said
if (url.equalsIgnoreCase("")){
url = absolute;
}
return toEncoded(url,request.getSession().getIdInternal());
} else {
return (url);
}
}
/**
* Encode the session identifier associated with this response
* into the specified redirect URL, if necessary.
*
* @param url URL to be encoded
*/
public String encodeRedirectURL(String url) {
if (isEncodeable(toAbsolute(url, false))) {
return toEncoded(url, request.getSession().getIdInternal());
} else {
return url;
}
}
/**
* Return true if the specified URL should be encoded with
* a session identifier. This will be true if all of the following
* conditions are met:
*
* - The request we are responding to asked for a valid session
*
- The requested session ID was not received via a cookie
*
- The specified URL points back to somewhere within the web
* application that is responding to this request
*
*
* @param location Absolute URL to be validated
*/
protected boolean isEncodeable(final String location) {
if (location == null)
return (false);
// Is this an intra-document reference?
if (location.startsWith("#"))
return (false);
final Session session = request.getSession(false);
if (session == null)
return (false);
if (request.isRequestedSessionIdFromCookie())
return (false);
return doIsEncodeable(request, session, location);
}
private static boolean doIsEncodeable(Request request, Session session,
String location){
// Is this a valid absolute URL?
URL url;
try {
url = new URL(location);
} catch (MalformedURLException e) {
return (false);
}
// Does this URL match down to (and including) the context path?
if (!request.getScheme().equalsIgnoreCase(url.getProtocol()))
return (false);
if (!request.getServerName().equalsIgnoreCase(url.getHost()))
return (false);
int serverPort = request.getServerPort();
if (serverPort == -1) {
if ("https".equals(request.getScheme()))
serverPort = 443;
else
serverPort = 80;
}
int urlPort = url.getPort();
if (urlPort == -1) {
if ("https".equals(url.getProtocol()))
urlPort = 443;
else
urlPort = 80;
}
if (serverPort != urlPort)
return (false);
String contextPath = "/";
String file = url.getFile();
if ((file == null) || !file.startsWith(contextPath)) {
return (false);
}
if (file.contains(";jsessionid=" + session.getIdInternal())) {
return (false);
}
// This URL belongs to our web application, so it is encodeable
return (true);
}
/**
* Return descriptive information about this Response implementation and
* the corresponding version number, in the format
* <description>/<version>
.
*/
public String getInfo() {
return info;
}
/**
* Set the error flag.
*/
public void setError() {
error = true;
}
/**
* Error flag accessor.
*/
public boolean isError() {
return error;
}
/**
* @return the {@link ErrorPageGenerator} to be used by
* {@link #sendError(int)} or {@link #sendError(int, java.lang.String)}.
*/
public ErrorPageGenerator getErrorPageGenerator() {
return errorPageGenerator;
}
/**
* Sets the {@link ErrorPageGenerator} to be used by
* {@link #sendError(int)} or {@link #sendError(int, java.lang.String)}.
*
* @param errorPageGenerator
*/
public void setErrorPageGenerator(ErrorPageGenerator errorPageGenerator) {
this.errorPageGenerator = errorPageGenerator;
}
// BEGIN S1AS 4878272
/**
* Sets detail error message.
*
* @param message detail error message
*/
public void setDetailMessage(String message) {
checkResponse();
response.setReasonPhrase(message);
}
/**
* Gets detail error message.
*
* @return the detail error message
*/
public String getDetailMessage() {
checkResponse();
return response.getReasonPhrase();
}
// END S1AS 4878272
/**
* Perform whatever actions are required to flush and close the output
* stream or writer, in a single operation.
*/
public void finish() {
// Writing leftover bytes
try {
outputBuffer.endRequest();
} catch (IOException e) {
if (LOGGER.isLoggable(Level.FINEST)) {
LOGGER.log(Level.FINEST,
LogMessages.WARNING_GRIZZLY_HTTP_SERVER_RESPONSE_FINISH_ERROR(), e);
}
} catch (Throwable t) {
if (LOGGER.isLoggable(Level.WARNING)) {
LOGGER.log(Level.WARNING,
LogMessages.WARNING_GRIZZLY_HTTP_SERVER_RESPONSE_FINISH_ERROR(), t);
}
}
}
/**
* Return the content length that was set or calculated for this Response.
*/
public int getContentLength() {
checkResponse();
return (int) response.getContentLength();
}
/**
* Return the content length that was set or calculated for this Response.
*/
public long getContentLengthLong() {
checkResponse();
return response.getContentLength();
}
/**
* Return the content type that was set or calculated for this response,
* or null
if no content type was set.
*/
public String getContentType() {
checkResponse();
return response.getContentType();
}
// ------------------------------------------------ ServletResponse Methods
/**
* Return the actual buffer size used for this Response.
*/
public int getBufferSize() {
return outputBuffer.getBufferSize();
}
/**
* Return the character encoding used for this Response.
*/
public String getCharacterEncoding() {
checkResponse();
final String characterEncoding = response.getCharacterEncoding();
if (characterEncoding == null) {
return DEFAULT_HTTP_CHARACTER_ENCODING;
}
return characterEncoding;
}
/*
* Overrides the name of the character encoding used in the body
* of the request. This method must be called prior to reading
* request parameters or reading input using getReader().
*
* @param charset String containing the name of the chararacter encoding.
*/
public void setCharacterEncoding(String charset) {
checkResponse();
if (isCommitted())
return;
// Ignore any call made after the getWriter has been invoked
// The default should be used
if (usingWriter)
return;
response.setCharacterEncoding(charset);
}
/**
* Create and return a ServletOutputStream to write the content
* associated with this Response.
*/
public NIOOutputStream createOutputStream() {
outputStream.setOutputBuffer(outputBuffer);
return outputStream;
}
/**
*
* Return the {@link NIOOutputStream} associated with this {@link Response}.
* This {@link NIOOutputStream} will write content in a non-blocking manner.
*
*
* @throws IllegalStateException if {@link #getWriter()} or {@link #getNIOWriter()}
* were already invoked.
*/
public NIOOutputStream getNIOOutputStream() {
if (usingWriter)
throw new IllegalStateException("Illegal attempt to call getOutputStream() after getWriter() has already been called.");
usingOutputStream = true;
outputStream.setOutputBuffer(outputBuffer);
return outputStream;
}
/**
*
* Return the {@link OutputStream} associated with this {@link Response}.
*
*
* By default the returned {@link NIOOutputStream} will work as blocking
* {@link java.io.OutputStream}, but it will be possible to call {@link NIOOutputStream#canWrite()} or
* {@link NIOOutputStream#notifyCanWrite(org.glassfish.grizzly.WriteHandler)} to
* avoid blocking.
*
* @return the {@link NIOOutputStream} associated with this {@link Response}.
*
* @throws IllegalStateException if {@link #getWriter()} or {@link #getNIOWriter()}
* were already invoked.
*
* @since 2.1.2
*/
public OutputStream getOutputStream() {
return getNIOOutputStream();
}
/**
* Return the Locale assigned to this response.
*/
public Locale getLocale() {
checkResponse();
Locale locale = response.getLocale();
if (locale == null) {
locale = DEFAULT_LOCALE;
response.setLocale(locale);
}
return locale;
}
/**
*
* Return the {@link NIOWriter} associated with this {@link Response}.
*
*
* By default the returned {@link NIOWriter} will work as blocking
* {@link java.io.Writer}, but it will be possible to call {@link NIOWriter#canWrite()} or
* {@link NIOWriter#notifyCanWrite(org.glassfish.grizzly.WriteHandler)} to
* avoid blocking.
*
* @throws IllegalStateException if {@link #getOutputStream()} or
* {@link #getNIOOutputStream()} were already invoked.
*/
public Writer getWriter() {
return getNIOWriter();
}
/**
*
* Return the {@link NIOWriter} associated with this {@link Response}.
* The {@link NIOWriter} will write content in a non-blocking manner.
*
*
* @return the {@link NIOWriter} associated with this {@link Response}.
*
* @throws IllegalStateException if {@link #getOutputStream()} or
* {@link #getNIOOutputStream()} were already invoked.
*
* @since 2.1.2
*/
public NIOWriter getNIOWriter() {
if (usingOutputStream)
throw new IllegalStateException("Illegal attempt to call getWriter() after getOutputStream() has already been called.");
/*
* If the response's character encoding has not been specified as
* described in getCharacterEncoding
(i.e., the method
* just returns the default value ISO-8859-1
),
* getWriter
updates it to ISO-8859-1
* (with the effect that a subsequent call to getContentType() will
* include a charset=ISO-8859-1 component which will also be
* reflected in the Content-Type response header, thereby satisfying
* the Servlet spec requirement that containers must communicate the
* character encoding used for the servlet response's writer to the
* client).
*/
setCharacterEncoding(getCharacterEncoding());
usingWriter = true;
outputBuffer.prepareCharacterEncoder();
writer.setOutputBuffer(outputBuffer);
return writer;
}
/**
* Has the output of this response already been committed?
*/
public boolean isCommitted() {
checkResponse();
return response.isCommitted();
}
/**
* Flush the current buffered content to the network.
* @throws IOException
*/
public void flush() throws IOException {
outputBuffer.flush();
}
/**
* @return the {@link OutputBuffer} associated with this
* Response
.
*/
public OutputBuffer getOutputBuffer() {
return outputBuffer;
}
/**
* Clears any data that exists in the buffer as well as the status code
* and headers.
*
* @exception IllegalStateException if this response has already
* been committed
*/
public void reset() {
checkResponse();
if (isCommitted()) {
throw new IllegalStateException();
}
response.getHeaders().clear();
response.setContentLanguage(null);
if (response.getContentLength() > 0) {
response.setContentLengthLong(-1L);
}
response.setCharacterEncoding(null);
response.setStatus(null);
response.setContentType((String) null);
response.setLocale(null);
outputBuffer.reset();
usingWriter = false;
usingOutputStream = false;
}
/**
* Reset the data buffer but not any status or header information.
*
* @exception IllegalStateException if the response has already
* been committed
*/
public void resetBuffer() {
resetBuffer(false);
}
/**
* Reset the data buffer and the using Writer/Stream flags but not any
* status or header information.
*
* @param resetWriterStreamFlags true
if the internal
* usingWriter
, usingOutputStream
,
* isCharacterEncodingSet
flags should also be reset
*
* @exception IllegalStateException if the response has already
* been committed
*/
public void resetBuffer(final boolean resetWriterStreamFlags) {
if (isCommitted())
throw new IllegalStateException("Cannot reset buffer after response has been committed.");
outputBuffer.reset();
if (resetWriterStreamFlags) {
usingOutputStream = false;
usingWriter = false;
}
}
/**
* Set the buffer size to be used for this Response.
*
* @param size The new buffer size
*
* @exception IllegalStateException if this method is called after
* output has been committed for this response
*/
public void setBufferSize(final int size) {
if (isCommitted()) {
throw new IllegalStateException("Unable to change buffer size as the response has been committed");
}
outputBuffer.setBufferSize(size);
}
/**
* Set the content length (in bytes) for this Response.
*
* If the length
argument is negative - then {@link org.glassfish.grizzly.http.HttpPacket}
* content-length value will be reset to -1 and
* Content-Length header (if present) will be removed.
*
* @param length The new content length
*/
public void setContentLengthLong(final long length) {
checkResponse();
if (isCommitted())
return;
if (usingWriter)
return;
response.setContentLengthLong(length);
}
/**
* Set the content length (in bytes) for this Response.
*
* If the length
argument is negative - then {@link org.glassfish.grizzly.http.HttpPacket}
* content-length value will be reset to -1 and
* Content-Length header (if present) will be removed.
*
* @param length The new content length
*/
public void setContentLength(final int length) {
setContentLengthLong(length);
}
/**
* Set the content type for this Response.
*
* @param type The new content type
*/
public void setContentType(String type) {
checkResponse();
if (isCommitted())
return;
// Ignore charset if getWriter() has already been called
if (usingWriter) {
if (type != null) {
int index = type.indexOf(";");
if (index != -1) {
type = type.substring(0, index);
}
}
}
response.setContentType(type);
}
/**
* Set the content type for this Response.
*
* @param type The new content type
*/
public void setContentType(final ContentType type) {
checkResponse();
if (isCommitted())
return;
if (type == null) {
response.setContentType((String) null);
return;
}
if (!usingWriter) {
response.setContentType(type);
} else {
// Ignore charset if getWriter() has already been called
response.setContentType(type.getMimeType());
}
}
/**
* Set the Locale that is appropriate for this response, including
* setting the appropriate character encoding.
*
* @param locale The new locale
*/
public void setLocale(final Locale locale) {
checkResponse();
if (isCommitted())
return;
response.setLocale(locale);
}
// --------------------------------------------------- HttpResponsePacket Methods
/**
* Return an array of all cookies set for this response, or
* a zero-length array if no cookies have been set.
*/
public Cookie[] getCookies() {
final Cookies cookies = new Cookies();
cookies.setHeaders(response.getHeaders(), false);
return cookies.get();
}
/**
* Return the value for the specified header, or null
if this
* header has not been set. If more than one value was added for this
* name, only the first is returned; use getHeaderValues() to retrieve all
* of them.
*
* @param name Header name to look up
*/
public String getHeader(String name) {
checkResponse();
return response.getHeader(name);
}
/**
* Return an array of all the header names set for this response, or
* a zero-length array if no headers have been set.
*/
public String[] getHeaderNames() {
checkResponse();
MimeHeaders headers = response.getHeaders();
int n = headers.size();
String[] result = new String[n];
for (int i = 0; i < n; i++) {
result[i] = headers.getName(i).toString();
}
return result;
}
/**
* Return an array of all the header values associated with the
* specified header name, or an zero-length array if there are no such
* header values.
*
* @param name Header name to look up
*/
public String[] getHeaderValues(final String name) {
checkResponse();
final Collection result = new LinkedList();
for (final String headerValue : response.getHeaders().values(name)) {
result.add(headerValue);
}
return result.toArray(new String[result.size()]);
}
/**
* Return the error message that was set with sendError()
* for this Response.
*/
public String getMessage() {
checkResponse();
return response.getReasonPhrase();
}
/**
* Return the HTTP status code associated with this Response.
*/
public int getStatus() {
checkResponse();
return response.getStatus();
}
/**
* Reset this response, and specify the values for the HTTP status code
* and corresponding message.
*
* @exception IllegalStateException if this response has already been
* committed
*/
public void reset(final int status, final String message) {
reset();
setStatus(status, message);
}
// -------------------------------------------- HttpServletResponse Methods
/**
* Add the specified Cookie to those that will be included with
* this Response.
*
* @param cookie Cookie to be added
*/
@SuppressWarnings({"unchecked"})
public void addCookie(final Cookie cookie) {
if (isCommitted())
return;
final StringBuilder sb = new StringBuilder();
//web application code can receive a IllegalArgumentException
//from the appendCookieValue invokation
if (System.getSecurityManager() != null) {
AccessController.doPrivileged(new PrivilegedAction() {
@Override
public Object run() {
CookieSerializerUtils.serializeServerCookie(sb, cookie);
return null;
}
});
} else {
CookieSerializerUtils.serializeServerCookie(sb, cookie);
}
// if we reached here, no exception, cookie is valid
// the header name is Set-Cookie for both "old" and v.1 ( RFC2109 )
// RFC2965 is not supported by browsers and the Servlet spec
// asks for 2109.
addHeader(Header.SetCookie, sb.toString());
}
/**
* Special method for adding a session cookie as we should be overriding
* any previous
* @param cookie
*/
protected void addSessionCookieInternal(final Cookie cookie) {
if (isCommitted())
return;
String name = cookie.getName();
final String headername = Header.SetCookie.toString();
final String startsWith = name + "=";
final StringBuilder sb = new StringBuilder();
//web application code can receive a IllegalArgumentException
//from the appendCookieValue invokation
if (System.getSecurityManager() != null) {
AccessController.doPrivileged(new PrivilegedAction