001    /**
002     * Licensed to the Apache Software Foundation (ASF) under one
003     * or more contributor license agreements.  See the NOTICE file
004     * distributed with this work for additional information
005     * regarding copyright ownership.  The ASF licenses this file
006     * to you under the Apache License, Version 2.0 (the
007     * "License"); you may not use this file except in compliance
008     * with the License.  You may obtain a copy of the License at
009     *
010     *     http://www.apache.org/licenses/LICENSE-2.0
011     *
012     * Unless required by applicable law or agreed to in writing, software
013     * distributed under the License is distributed on an "AS IS" BASIS,
014     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015     * See the License for the specific language governing permissions and
016     * limitations under the License.
017     */
018    
019    package org.apache.hadoop.fs.http.server;
020    
021    import com.sun.jersey.api.container.ContainerException;
022    import org.apache.hadoop.classification.InterfaceAudience;
023    import org.apache.hadoop.lib.service.FileSystemAccessException;
024    import org.apache.hadoop.lib.wsrs.ExceptionProvider;
025    import org.slf4j.Logger;
026    import org.slf4j.LoggerFactory;
027    import org.slf4j.MDC;
028    
029    import javax.ws.rs.core.Response;
030    import javax.ws.rs.ext.Provider;
031    import java.io.FileNotFoundException;
032    import java.io.IOException;
033    
034    /**
035     * JAX-RS <code>ExceptionMapper</code> implementation that maps HttpFSServer's
036     * exceptions to HTTP status codes.
037     */
038    @Provider
039    @InterfaceAudience.Private
040    public class HttpFSExceptionProvider extends ExceptionProvider {
041      private static Logger AUDIT_LOG = LoggerFactory.getLogger("httpfsaudit");
042      private static Logger LOG = LoggerFactory.getLogger(HttpFSExceptionProvider.class);
043    
044      /**
045       * Maps different exceptions thrown by HttpFSServer to HTTP status codes.
046       * <p/>
047       * <ul>
048       * <li>SecurityException : HTTP UNAUTHORIZED</li>
049       * <li>FileNotFoundException : HTTP NOT_FOUND</li>
050       * <li>IOException : INTERNAL_HTTP SERVER_ERROR</li>
051       * <li>UnsupporteOperationException : HTTP BAD_REQUEST</li>
052       * <li>all other exceptions : HTTP INTERNAL_SERVER_ERROR </li>
053       * </ul>
054       *
055       * @param throwable exception thrown.
056       *
057       * @return mapped HTTP status code
058       */
059      @Override
060      public Response toResponse(Throwable throwable) {
061        Response.Status status;
062        if (throwable instanceof FileSystemAccessException) {
063          throwable = throwable.getCause();
064        }
065        if (throwable instanceof ContainerException) {
066          throwable = throwable.getCause();
067        }
068        if (throwable instanceof SecurityException) {
069          status = Response.Status.UNAUTHORIZED;
070        } else if (throwable instanceof FileNotFoundException) {
071          status = Response.Status.NOT_FOUND;
072        } else if (throwable instanceof IOException) {
073          status = Response.Status.INTERNAL_SERVER_ERROR;
074        } else if (throwable instanceof UnsupportedOperationException) {
075          status = Response.Status.BAD_REQUEST;
076        } else if (throwable instanceof IllegalArgumentException) {
077          status = Response.Status.BAD_REQUEST;
078        } else {
079          status = Response.Status.INTERNAL_SERVER_ERROR;
080        }
081        return createResponse(status, throwable);
082      }
083    
084      /**
085       * Logs the HTTP status code and exception in HttpFSServer's log.
086       *
087       * @param status HTTP status code.
088       * @param throwable exception thrown.
089       */
090      @Override
091      protected void log(Response.Status status, Throwable throwable) {
092        String method = MDC.get("method");
093        String path = MDC.get("path");
094        String message = getOneLineMessage(throwable);
095        AUDIT_LOG.warn("FAILED [{}:{}] response [{}] {}", new Object[]{method, path, status, message});
096        LOG.warn("[{}:{}] response [{}] {}", new Object[]{method, path, status, message}, throwable);
097      }
098    
099    }