com.eucalyptus.objectstorage.pipeline.ObjectStorageRESTExceptionHandler.java Source code

Java tutorial

Introduction

Here is the source code for com.eucalyptus.objectstorage.pipeline.ObjectStorageRESTExceptionHandler.java

Source

/*************************************************************************
 * Copyright 2009-2013 Eucalyptus Systems, Inc.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see http://www.gnu.org/licenses/.
 *
 * Please contact Eucalyptus Systems, Inc., 6755 Hollister Ave., Goleta
 * CA 93117, USA or visit http://www.eucalyptus.com/licenses/ if you need
 * additional information or have any questions.
 ************************************************************************/

package com.eucalyptus.objectstorage.pipeline;

import java.nio.charset.Charset;

import org.apache.log4j.Logger;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelFuture;
import org.jboss.netty.channel.ChannelFutureListener;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.Channels;
import org.jboss.netty.channel.ExceptionEvent;
import org.jboss.netty.channel.SimpleChannelUpstreamHandler;
import org.jboss.netty.handler.codec.http.HttpHeaders;
import org.jboss.netty.handler.codec.http.HttpResponseStatus;
import org.jboss.netty.handler.codec.http.HttpVersion;

import com.eucalyptus.context.Context;
import com.eucalyptus.context.Contexts;
import com.eucalyptus.http.MappingHttpRequest;
import com.eucalyptus.http.MappingHttpResponse;
import com.eucalyptus.objectstorage.exceptions.ObjectStorageException;
import com.eucalyptus.objectstorage.exceptions.s3.InvalidAccessKeyIdException;
import com.eucalyptus.objectstorage.exceptions.s3.SignatureDoesNotMatchException;
import com.eucalyptus.objectstorage.msgs.ObjectStorageErrorMessageType;
import com.eucalyptus.ws.WebServicesException;
import com.google.common.base.Strings;
import com.google.common.util.concurrent.Runnables;

public class ObjectStorageRESTExceptionHandler extends SimpleChannelUpstreamHandler {
    private static final Logger LOG = Logger.getLogger(ObjectStorageRESTExceptionHandler.class);
    private static final String CODE_UNKNOWN = "UNKNOWN";

    private static final Charset UTF_8 = Charset.forName("UTF-8");

    @Override
    public void exceptionCaught(final ChannelHandlerContext ctx, final ExceptionEvent e) throws Exception {
        final Channel ch = e.getChannel();
        Throwable cause = e.getCause();
        if (cause.getCause() != null) {
            // wrapped exception
            cause = cause.getCause();
        }

        // Get the request ID from the context and clear the context. If you cant log an exception and move on
        String requestId = null;
        HttpVersion httpVersion = HttpVersion.HTTP_1_0;
        Runnable cleanup = Runnables.doNothing();
        try {
            if (ch != null) {
                Context context = Contexts.lookup(ch);
                requestId = context.getCorrelationId();
                MappingHttpRequest request = context.getHttpRequest();
                httpVersion = request != null ? request.getProtocolVersion() : httpVersion;
                cleanup = () -> Contexts.clear(context);
            }
        } catch (Exception ex) {
            LOG.trace("Error getting request ID or clearing context", ex);
        }

        // Populate the error response fields
        final HttpResponseStatus status;
        final String code;
        final String resource;

        if (cause instanceof ObjectStorageException) {
            ObjectStorageException walrusEx = (ObjectStorageException) cause;
            status = walrusEx.getStatus();
            code = walrusEx.getCode();
            resource = walrusEx.getResource();
        } else if (cause instanceof WebServicesException) {
            WebServicesException webEx = (WebServicesException) cause;
            status = webEx.getStatus();
            code = CODE_UNKNOWN;
            resource = null;
        } else {
            status = HttpResponseStatus.INTERNAL_SERVER_ERROR;
            code = CODE_UNKNOWN;
            resource = null;
        }

        final ObjectStorageErrorMessageType errorResponse = new ObjectStorageErrorMessageType();
        errorResponse.setResource(Strings.nullToEmpty(resource));
        errorResponse.setMessage(Strings.nullToEmpty(cause.getMessage()));
        errorResponse.setCode(Strings.nullToEmpty(code));
        errorResponse.setRequestId(Strings.nullToEmpty(requestId));
        errorResponse.setStatus(status);

        if (cause instanceof InvalidAccessKeyIdException) {
            errorResponse.setAccessKeyId(((InvalidAccessKeyIdException) cause).getAccessKeyId());
            errorResponse.setResource(null);
        }

        if (cause instanceof SignatureDoesNotMatchException) {
            SignatureDoesNotMatchException ex = (SignatureDoesNotMatchException) cause;
            errorResponse.setAccessKeyId(ex.getAccessKeyId());
            errorResponse.setResource(null);
            errorResponse.setStringToSign(Strings.nullToEmpty(ex.getStringToSign()));
            errorResponse.setSignatureProvided(Strings.nullToEmpty(ex.getSignatureProvided()));
            if (ex.getStringToSign() != null)
                errorResponse.setStringToSignBytes(stringToByteString(ex.getStringToSign()));
            errorResponse.setCanonicalRequest(Strings.nullToEmpty(ex.getCanonicalRequest()));
            if (ex.getCanonicalRequest() != null)
                errorResponse.setCanonicalRequestBytes(stringToByteString(ex.getCanonicalRequest()));
        }

        if (ctx.getChannel().isConnected()) {
            final MappingHttpResponse response = new MappingHttpResponse(httpVersion);
            response.setStatus(status);
            response.setMessage(errorResponse);
            response.setCorrelationId(requestId);
            errorResponse.setCorrelationId(requestId);
            final ChannelFuture writeFuture = Channels.future(ctx.getChannel());
            writeFuture.addListener(ChannelFutureListener.CLOSE);
            response.setHeader(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.CLOSE);
            Channels.write(ctx, writeFuture, response);
            cleanup.run();
        } else {
            ctx.sendDownstream(e);
        }
    }

    private static String stringToByteString(String in) {
        StringBuilder sb = new StringBuilder();
        byte[] b = in.getBytes(UTF_8);
        for (int i = 0; i < b.length; i++)
            sb.append(b[i]).append(" ");
        sb.deleteCharAt(sb.length() - 1);
        return sb.toString();
    }
}