All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.officefloor.server.http.HttpException Maven / Gradle / Ivy

The newest version!
/*-
 * #%L
 * HTTP Server
 * %%
 * Copyright (C) 2005 - 2020 Daniel Sagenschneider
 * %%
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * #L%
 */

package net.officefloor.server.http;

import java.io.PrintWriter;
import java.io.StringWriter;

import net.officefloor.server.stream.StreamBuffer;
import net.officefloor.server.stream.StreamBufferPool;

/**
 * 

* HTTP {@link Exception}. *

* This is a {@link RuntimeException} as typically this is handled directly by * the {@link HttpServerImplementation} to send a {@link HttpResponse}. It is * typically not for application logic to handle. * * @author Daniel Sagenschneider */ public class HttpException extends RuntimeException { /** * Serial version UID. */ private static final long serialVersionUID = 1L; /** * {@link HttpHeader} space. */ private static byte[] SPACE = " ".getBytes(ServerHttpConnection.HTTP_CHARSET); /** * {@link HttpHeader} end of line encoded bytes. */ private static byte[] HEADER_EOLN = "\r\n".getBytes(ServerHttpConnection.HTTP_CHARSET); /** * {@link HttpHeader} name/value separation. */ private static byte[] COLON_SPACE = ": ".getBytes(ServerHttpConnection.HTTP_CHARSET); /** * Content-Length {@link HttpHeaderName}. */ private static HttpHeaderName CONTENT_LENGTH = new HttpHeaderName("Content-Length"); /** * No {@link WritableHttpHeader} instances value. */ private static final WritableHttpHeader[] NO_HEADERS = new WritableHttpHeader[0]; /** * {@link HttpStatus}. */ private final HttpStatus status; /** * Possible {@link WritableHttpHeader} instances for the {@link HttpResponse}. */ private final WritableHttpHeader[] headers; /** * {@link HttpResponse} entity content. */ private final String entity; /** * Instantiate. * * @param status {@link HttpStatus}. */ public HttpException(HttpStatus status) { super(status.getStatusMessage()); this.status = status; this.headers = NO_HEADERS; this.entity = null; } /** * Instantiate. * * @param status {@link HttpStatus}. * @param cause {@link Throwable} cause. */ public HttpException(HttpStatus status, Throwable cause) { super(cause); this.status = status; this.headers = NO_HEADERS; this.entity = null; } /** * Convenience constructor for providing error message. * * @param statusCode Status code. * @param errorMessage Error message. */ public HttpException(int statusCode, String errorMessage) { this(HttpStatus.getHttpStatus(statusCode), errorMessage); } /** * Convenience constructor for providing error message. * * @param status {@link HttpStatus}. * @param errorMessage Error message. */ public HttpException(HttpStatus status, String errorMessage) { super(new ErrorMessageException(errorMessage)); this.status = status; this.headers = NO_HEADERS; this.entity = null; } /** * Instantiate. * * @param status {@link HttpStatus}. * @param headers {@link HttpHeader} instances. May be null. * @param entity Entity for the {@link HttpResponse}. May be null. */ public HttpException(HttpStatus status, WritableHttpHeader[] headers, String entity) { super(status.getStatusMessage()); this.status = status; this.headers = (headers == null ? NO_HEADERS : headers); this.entity = entity; } /** * Enable wrapping {@link Throwable} in a {@link HttpException} for * {@link HttpStatus#INTERNAL_SERVER_ERROR}. * * @param cause {@link Throwable} cause. */ public HttpException(Throwable cause) { this(HttpStatus.INTERNAL_SERVER_ERROR, cause); } /** * Obtains the {@link HttpStatus} for the {@link HttpResponse}. * * @return {@link HttpStatus} for the {@link HttpResponse}. */ public HttpStatus getHttpStatus() { return this.status; } /** * Obtains the {@link HttpHeader} instances. * * @return {@link HttpHeader} instances. */ public HttpHeader[] getHttpHeaders() { return this.headers; } /** * Obtains the entity for the {@link HttpResponse}. * * @return Entity for the {@link HttpResponse}. */ public String getEntity() { return this.entity; } /** * Writes the HTTP response for this {@link HttpException}. * * @param Buffer type. * @param version {@link HttpVersion}. * @param isIncludeStackTrace Whether to include the stack trace. * @param head Head {@link StreamBuffer} of the linked list of * {@link StreamBuffer} instances. * @param bufferPool {@link StreamBufferPool}. */ public void writeHttpResponse(HttpVersion version, boolean isIncludeStackTrace, StreamBuffer head, StreamBufferPool bufferPool) { // Write the status line version.write(head, bufferPool); StreamBuffer.write(SPACE, head, bufferPool); this.status.write(head, bufferPool); StreamBuffer.write(HEADER_EOLN, head, bufferPool); // Write the headers for (int i = 0; i < this.headers.length; i++) { this.headers[i].write(head, bufferPool); } // Determine if include the stack trace if (!isIncludeStackTrace) { // Complete request without entity StreamBuffer.write(HEADER_EOLN, head, bufferPool); return; } // Generate the stack trace StringWriter stackTrace = new StringWriter(); PrintWriter writer = new PrintWriter(stackTrace); this.printStackTrace(writer); writer.flush(); byte[] stackTraceBytes = stackTrace.toString().getBytes(ServerHttpConnection.DEFAULT_HTTP_ENTITY_CHARSET); // Write header for the content length CONTENT_LENGTH.write(head, bufferPool); StreamBuffer.write(COLON_SPACE, head, bufferPool); StreamBuffer.write(stackTraceBytes.length, head, bufferPool); StreamBuffer.write(HEADER_EOLN, head, bufferPool); // Write end of headers StreamBuffer.write(HEADER_EOLN, head, bufferPool); // Write the stack trace StreamBuffer.write(stackTraceBytes, head, bufferPool); } /** * Allow error message. */ private static class ErrorMessageException extends Exception { private static final long serialVersionUID = 1L; /** * Instantiate with error message. * * @param message Error message. */ private ErrorMessageException(String message) { super(message); } } /* * ==================== Exception ===================== */ @Override public String getMessage() { Throwable cause = this.getCause(); if ((cause != null) && (cause instanceof ErrorMessageException)) { // Use just the error message return cause.getMessage(); } else { // Provide full message return super.getMessage(); } } }