package org.dcache.webdav.federation;
import io.milton.http.AbstractWrappingResponseHandler;
import io.milton.http.Request;
import io.milton.http.Response;
import io.milton.http.webdav.WebDavResponseHandler;
import io.milton.resource.Resource;
/**
* This class implements support for the "Global Access Service" feature that
* allows seamless access to a global federation of storage. This is achieved
* by the storage system responding to certain local failures by redirecting
* the client to the next replica from a supplied stack of replicas. This
* process is described here:
*
* https://svnweb.cern.ch/trac/lcgdm/wiki/Dpm/WebDAV/Extensions
*
* The client supplies a carefully crafted URL with additional metadata encoded
* as a query string. The format for this query string is described in the
* ReplicaInfo class. If dCache would return a NOT_FOUND or FORBIDDEN
* response, this is replaced by a MOVED_TEMPORARILY response with the next
* replica in the stack as the location. A list of the failures that the
* client has already experienced are propagated as part of the next request.
* <p>
* Normally, the final replica in the stack of supplied replicas is the
* catalogue itself. This is to allow the catalogue to update its internal
* cache with the failed responses and suggest additional replicas to the
* client, if any.
* <p>
* Because of this, we do not anticipate receiving a federated request that
* fails with no next replica to redirect; this scenario is not described in the
* above wiki page. Under these circumstances, dCache will allow the FORBIDDEN
* or NOT_FOUND error response to propagate back to the client.
* <p>
* If the client supplies no query string, or the query string is malformed then
* dCache will treat the request as a normal request and all errors will be
* propagated back to the client.
*/
public class FederationResponseHandler extends AbstractWrappingResponseHandler
{
public FederationResponseHandler(WebDavResponseHandler wrapped)
{
super(wrapped);
}
@Override
public void respondNotFound(Response response, Request request)
{
ReplicaInfo info = ReplicaInfo.forRequest(request);
if (info.hasNext()) {
super.respondRedirect(response, request, info.buildLocationWhenNotFound());
} else {
super.respondNotFound(response, request);
}
}
@Override
public void respondForbidden(Resource resource, Response response, Request request)
{
ReplicaInfo info = ReplicaInfo.forRequest(request);
if (info.hasNext()) {
super.respondRedirect(response, request, info.buildLocationWhenForbidden());
} else {
super.respondForbidden(resource, response, request);
}
}
}