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 }