HTTPClientConnection.java revision 88f16d892d54fd8c3e190cc1f6363638b11ae1a3
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at legal-notices/CDDLv1_0.txt.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information:
* Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*
*
* Portions Copyright 2013-2015 ForgeRock AS
*/
/**
* This class defines an HTTP client connection, which is a type of client
* connection that will be accepted by an instance of the HTTP connection
* handler.
*/
final class HTTPClientConnection extends ClientConnection implements
{
// TODO JNR Confirm with Matt that persistent searches are inapplicable to
// Rest2LDAP.
// TODO JNR Should I override getIdleTime()?
/**
* Class grouping together an {@link Operation} and its associated
* {@link LdapPromiseImpl} to ensure they are both atomically added
* and removed from the {@link HTTPClientConnection#operationsInProgress} Map.
*/
private static class OperationWithPromise
{
{
}
{
}
}
/** {@inheritDoc} */
private static final class SearchOperationWithPromise extends OperationWithPromise
{
final SearchResultHandler entryHandler;
{
this.entryHandler = entryHandler;
}
}
/** The tracer object for the debug logger. */
/**
* Official servlet property giving access to the SSF (Security Strength
* Factor) used to encrypt the current connection.
*/
private static final String SERVLET_SSF_CONSTANT =
"javax.servlet.request.key_size";
/**
* Indicates whether the Directory Server believes this connection to be valid
* and available for communication.
*/
private volatile boolean connectionValid = true;
/**
* Indicates whether this connection is about to be closed. This will be used
* to prevent accepting new requests while a disconnect is in progress.
*/
private boolean disconnectRequested;
/**
* Indicates whether the connection should keep statistics regarding the
* operations that it is performing.
*/
private final boolean keepStats;
/**
* The Map (messageID => {@link OperationWithPromise}) of all operations
* currently in progress on this connection.
*/
/**
* The number of operations performed on this connection. Used to compare with
* the resource limits of the network group.
*/
/**
* The lock used to provide threadsafe access to the map of operations in
* progress. This is used when we want to prevent puts on this map while we
* are removing all operations in progress.
*/
/** The connection ID assigned to this connection. */
private final long connectionID;
/** The reference to the connection handler that accepted this connection. */
private final HTTPConnectionHandler connectionHandler;
/** The statistics tracker associated with this client connection. */
private final HTTPStatistics statTracker;
private boolean useNanoTime;
/** Total execution time for this request. */
/** The protocol in use for this client connection. */
/** The query issued by the client. */
/** The user agent used by the client. */
/** The username that was used to authenticate. */
/**
* The HTTP status code returned to the client. Using 0 to say no status code
* was set since it is not .
*/
/** The client (remote) address. */
private final String clientAddress;
/** The client (remote) host name. */
private String clientHost;
/** The client (remote) port. */
private final int clientPort;
/** The remote (client) address. */
private final InetAddress remoteAddress;
/** The server (local) address. */
private final String serverAddress;
/** The server (local) host name. */
private String serverHost;
/** The server (local) port. */
private final int serverPort;
/** The local (server) address. */
private final InetAddress localAddress;
/** Whether this connection is secure. */
private final boolean isSecure;
/** Security-Strength Factor extracted from the request attribute. */
private final int securityStrengthFactor;
/**
* Constructs an instance of this class.
*
* @param connectionHandler
* the connection handler that accepted this connection
* @param request
* represents this client connection.
*/
{
this.connectionHandler = connectionHandler;
// memoize all the fields we need from the request before Grizzly decides to
// recycle it
this.securityStrengthFactor =
if (this.keepStats)
{
this.statTracker.updateConnect();
}
}
{
{
}
return request.getRequestURI();
}
/** {@inheritDoc} */
public String getAuthUser()
{
return this.authUser;
}
/** {@inheritDoc} */
public long getConnectionID()
{
return connectionID;
}
/** {@inheritDoc} */
{
return connectionHandler;
}
/** {@inheritDoc} */
public long getTotalProcessingTime()
{
return totalProcessingTime.get();
}
/** {@inheritDoc} */
public String getProtocol()
{
return protocol;
}
/** {@inheritDoc} */
public String getClientAddress()
{
return clientAddress;
}
/** {@inheritDoc} */
public String getClientHost()
{
return clientHost;
}
/** {@inheritDoc} */
public int getClientPort()
{
return clientPort;
}
/** {@inheritDoc} */
public String getServerAddress()
{
return serverAddress;
}
/** {@inheritDoc} */
public String getServerHost()
{
return serverHost;
}
/** {@inheritDoc} */
public int getServerPort()
{
return serverPort;
}
/** {@inheritDoc} */
public InetAddress getRemoteAddress()
{
return remoteAddress;
}
/** {@inheritDoc} */
public InetAddress getLocalAddress()
{
return localAddress;
}
/** {@inheritDoc} */
public boolean isSecure()
{
return isSecure;
}
/** {@inheritDoc} */
{
if (keepStats)
{
.getOperationType(), time);
}
{
try
{
if (keepStats)
{
}
}
catch (LdapException e)
{
}
}
}
{
if (useNanoTime)
{
return operation.getProcessingNanoTime();
}
return operation.getProcessingTime();
}
{
if (operation instanceof AddOperation)
{
return new AddResponseProtocolOp(resultCode);
}
else if (operation instanceof BindOperation)
{
return new BindResponseProtocolOp(resultCode);
}
else if (operation instanceof CompareOperation)
{
return new CompareResponseProtocolOp(resultCode);
}
else if (operation instanceof DeleteOperation)
{
return new DeleteResponseProtocolOp(resultCode);
}
else if (operation instanceof ExtendedOperation)
{
return new ExtendedResponseProtocolOp(resultCode);
}
else if (operation instanceof ModifyDNOperation)
{
return new ModifyDNResponseProtocolOp(resultCode);
}
else if (operation instanceof ModifyOperation)
{
return new ModifyResponseProtocolOp(resultCode);
}
else if (operation instanceof SearchOperation)
{
return new SearchResultDoneProtocolOp(resultCode);
}
}
/** {@inheritDoc} */
{
{
if (keepStats)
{
}
}
}
/** {@inheritDoc} */
{
{
if (keepStats)
{
}
}
return connectionValid;
}
/** {@inheritDoc} */
protected boolean sendIntermediateResponseMessage(
{
// if (keepStats)
// {
// this.statTracker.updateMessageWritten(new LDAPMessage(
// intermediateResponse.getOperation().getMessageID(),
// new IntermediateResponseProtocolOp(intermediateResponse.getOID())));
// }
throw new RuntimeException("Not implemented");
}
/** {@inheritDoc} */
{
}
/**
* {@inheritDoc}
*
* @param sendNotification
* not used with HTTP.
*/
{
// Set a flag indicating that the connection is being terminated so
// that no new requests will be accepted. Also cancel all operations
// in progress.
synchronized (opsInProgressLock)
{
// If we are already in the middle of a disconnect, then don't
// do anything.
if (disconnectRequested)
{
return;
}
disconnectRequested = true;
}
if (keepStats)
{
}
if (connectionID >= 0)
{
DirectoryServer.connectionClosed(this);
}
// Indicate that this connection is no longer valid.
connectionValid = false;
{
}
else
{
.getClosureMessage()));
}
this.connectionHandler.removeClientConnection(this);
}
/** {@inheritDoc} */
{
return this.method;
}
/** {@inheritDoc} */
{
return this.query;
}
/** {@inheritDoc} */
public int getStatusCode()
{
return this.statusCode.get();
}
/** {@inheritDoc} */
public String getUserAgent()
{
return this.userAgent;
}
/** {@inheritDoc} */
{
{
}
return results;
}
/** {@inheritDoc} */
{
{
}
return null;
}
/**
* Adds the passed in search operation to the in progress list along with the
* associated promise and the {@code SearchResultHandler}.
*
* @param operation
* the operation to add to the in progress list
* @param promise
* the promise associated to the operation
* @param searchResultHandler
* the search result handler associated to the promise result
* @throws DirectoryException
* If an error occurs
*/
{
if (searchResultHandler != null)
{
}
else
{
}
}
{
synchronized (opsInProgressLock)
{
// If we're already in the process of disconnecting the client, then reject the operation.
if (disconnectRequested)
{
}
}
}
/** {@inheritDoc} */
public boolean removeOperationInProgress(int messageID)
{
if (previousValue != null)
{
{
{
}
}
}
return previousValue != null;
}
/** {@inheritDoc} */
{
{
}
}
{
{
}
{
try
{
}
catch (IllegalArgumentException ignored)
{
// We cannot do much about it. Just log it.
}
}
return 0;
}
/** {@inheritDoc} */
{
synchronized (opsInProgressLock)
{
try
{
{
try
{
if (keepStats)
{
}
}
catch (Exception e)
{ // make sure all operations are cancelled, no matter what
logger.traceException(e);
}
}
}
catch (Exception e)
{ // TODO JNR should I keep this catch?
logger.traceException(e);
}
}
}
/** {@inheritDoc} */
int messageID)
{
synchronized (opsInProgressLock)
{
try
{
}
finally
{ // Ensure we always put back this operation
}
}
}
/** {@inheritDoc} */
public long getNumberOfOperations()
{
return this.operationsPerformed.get();
}
/** {@inheritDoc} */
public String getMonitorSummary()
{
{
}
}
{
try
{
}
catch (UnknownHostException e)
{
throw new RuntimeException("Should never happen", e);
}
}
/** {@inheritDoc} */
{
}
/**
* Returns the statTracker for this connection handler.
*
* @return the statTracker for this connection handler
*/
public HTTPStatistics getStatTracker()
{
return statTracker;
}
/** {@inheritDoc} */
public int getSSF()
{
return securityStrengthFactor;
}
/** {@inheritDoc} */
public boolean isConnectionValid()
{
return connectionValid;
}
/** {@inheritDoc} */
public boolean isInnerConnection()
{
return true;
}
/** {@inheritDoc} */
public void log(int statusCode)
{
{ // this request was not logged before
HTTPAccessLogger.logRequestInfo(this);
}
}
}