/*
* Copyright 2016 LINE Corporation
*
* LINE Corporation licenses this file to you 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.
*/
package com.linecorp.armeria.common.http;
import io.netty.util.collection.IntObjectHashMap;
import io.netty.util.collection.IntObjectMap;
/**
* HTTP response code and its description.
*/
public final class HttpStatus implements Comparable<HttpStatus> {
private static final IntObjectMap<HttpStatus> map = new IntObjectHashMap<>(1000);
/**
* 100 Continue.
*/
public static final HttpStatus CONTINUE = newConstant(100, "Continue");
/**
* 101 Switching Protocols.
*/
public static final HttpStatus SWITCHING_PROTOCOLS = newConstant(101, "Switching Protocols");
/**
* 102 Processing (WebDAV, RFC2518).
*/
public static final HttpStatus PROCESSING = newConstant(102, "Processing");
/**
* 200 OK.
*/
public static final HttpStatus OK = newConstant(200, "OK");
/**
* 201 Created.
*/
public static final HttpStatus CREATED = newConstant(201, "Created");
/**
* 202 Accepted.
*/
public static final HttpStatus ACCEPTED = newConstant(202, "Accepted");
/**
* 203 Non-Authoritative Information (since HTTP/1.1).
*/
public static final HttpStatus NON_AUTHORITATIVE_INFORMATION =
newConstant(203, "Non-Authoritative Information");
/**
* 204 No Content.
*/
public static final HttpStatus NO_CONTENT = newConstant(204, "No Content");
/**
* 205 Reset Content.
*/
public static final HttpStatus RESET_CONTENT = newConstant(205, "Reset Content");
/**
* 206 Partial Content.
*/
public static final HttpStatus PARTIAL_CONTENT = newConstant(206, "Partial Content");
/**
* 207 Multi-Status (WebDAV, RFC2518).
*/
public static final HttpStatus MULTI_STATUS = newConstant(207, "Multi-Status");
/**
* 300 Multiple Choices.
*/
public static final HttpStatus MULTIPLE_CHOICES = newConstant(300, "Multiple Choices");
/**
* 301 Moved Permanently.
*/
public static final HttpStatus MOVED_PERMANENTLY = newConstant(301, "Moved Permanently");
/**
* 302 Found.
*/
public static final HttpStatus FOUND = newConstant(302, "Found");
/**
* 303 See Other (since HTTP/1.1).
*/
public static final HttpStatus SEE_OTHER = newConstant(303, "See Other");
/**
* 304 Not Modified.
*/
public static final HttpStatus NOT_MODIFIED = newConstant(304, "Not Modified");
/**
* 305 Use Proxy (since HTTP/1.1).
*/
public static final HttpStatus USE_PROXY = newConstant(305, "Use Proxy");
/**
* 307 Temporary Redirect (since HTTP/1.1).
*/
public static final HttpStatus TEMPORARY_REDIRECT = newConstant(307, "Temporary Redirect");
/**
* 400 Bad Request.
*/
public static final HttpStatus BAD_REQUEST = newConstant(400, "Bad Request");
/**
* 401 Unauthorized.
*/
public static final HttpStatus UNAUTHORIZED = newConstant(401, "Unauthorized");
/**
* 402 Payment Required.
*/
public static final HttpStatus PAYMENT_REQUIRED = newConstant(402, "Payment Required");
/**
* 403 Forbidden.
*/
public static final HttpStatus FORBIDDEN = newConstant(403, "Forbidden");
/**
* 404 Not Found.
*/
public static final HttpStatus NOT_FOUND = newConstant(404, "Not Found");
/**
* 405 Method Not Allowed.
*/
public static final HttpStatus METHOD_NOT_ALLOWED = newConstant(405, "Method Not Allowed");
/**
* 406 Not Acceptable.
*/
public static final HttpStatus NOT_ACCEPTABLE = newConstant(406, "Not Acceptable");
/**
* 407 Proxy Authentication Required.
*/
public static final HttpStatus PROXY_AUTHENTICATION_REQUIRED =
newConstant(407, "Proxy Authentication Required");
/**
* 408 Request Timeout.
*/
public static final HttpStatus REQUEST_TIMEOUT = newConstant(408, "Request Timeout");
/**
* 409 Conflict.
*/
public static final HttpStatus CONFLICT = newConstant(409, "Conflict");
/**
* 410 Gone.
*/
public static final HttpStatus GONE = newConstant(410, "Gone");
/**
* 411 Length Required.
*/
public static final HttpStatus LENGTH_REQUIRED = newConstant(411, "Length Required");
/**
* 412 Precondition Failed.
*/
public static final HttpStatus PRECONDITION_FAILED = newConstant(412, "Precondition Failed");
/**
* 413 Request Entity Too Large.
*/
public static final HttpStatus REQUEST_ENTITY_TOO_LARGE =
newConstant(413, "Request Entity Too Large");
/**
* 414 Request-URI Too Long.
*/
public static final HttpStatus REQUEST_URI_TOO_LONG = newConstant(414, "Request-URI Too Long");
/**
* 415 Unsupported Media Type.
*/
public static final HttpStatus UNSUPPORTED_MEDIA_TYPE = newConstant(415, "Unsupported Media Type");
/**
* 416 Requested Range Not Satisfiable.
*/
public static final HttpStatus REQUESTED_RANGE_NOT_SATISFIABLE =
newConstant(416, "Requested Range Not Satisfiable");
/**
* 417 Expectation Failed.
*/
public static final HttpStatus EXPECTATION_FAILED = newConstant(417, "Expectation Failed");
/**
* 421 Misdirected Request.
*
* @see <a href="https://tools.ietf.org/html/draft-ietf-httpbis-http2-15#section-9.1.2">421 Status Code</a>
*/
public static final HttpStatus MISDIRECTED_REQUEST = newConstant(421, "Misdirected Request");
/**
* 422 Unprocessable Entity (WebDAV, RFC4918).
*/
public static final HttpStatus UNPROCESSABLE_ENTITY = newConstant(422, "Unprocessable Entity");
/**
* 423 Locked (WebDAV, RFC4918).
*/
public static final HttpStatus LOCKED = newConstant(423, "Locked");
/**
* 424 Failed Dependency (WebDAV, RFC4918).
*/
public static final HttpStatus FAILED_DEPENDENCY = newConstant(424, "Failed Dependency");
/**
* 425 Unordered Collection (WebDAV, RFC3648).
*/
public static final HttpStatus UNORDERED_COLLECTION = newConstant(425, "Unordered Collection");
/**
* 426 Upgrade Required (RFC2817).
*/
public static final HttpStatus UPGRADE_REQUIRED = newConstant(426, "Upgrade Required");
/**
* 428 Precondition Required (RFC6585).
*/
public static final HttpStatus PRECONDITION_REQUIRED = newConstant(428, "Precondition Required");
/**
* 429 Too Many Requests (RFC6585).
*/
public static final HttpStatus TOO_MANY_REQUESTS = newConstant(429, "Too Many Requests");
/**
* 431 Request Header Fields Too Large (RFC6585).
*/
public static final HttpStatus REQUEST_HEADER_FIELDS_TOO_LARGE =
newConstant(431, "Request Header Fields Too Large");
/**
* 500 Internal Server Error.
*/
public static final HttpStatus INTERNAL_SERVER_ERROR = newConstant(500, "Internal Server Error");
/**
* 501 Not Implemented.
*/
public static final HttpStatus NOT_IMPLEMENTED = newConstant(501, "Not Implemented");
/**
* 502 Bad Gateway.
*/
public static final HttpStatus BAD_GATEWAY = newConstant(502, "Bad Gateway");
/**
* 503 Service Unavailable.
*/
public static final HttpStatus SERVICE_UNAVAILABLE = newConstant(503, "Service Unavailable");
/**
* 504 Gateway Timeout.
*/
public static final HttpStatus GATEWAY_TIMEOUT = newConstant(504, "Gateway Timeout");
/**
* 505 HTTP Version Not Supported.
*/
public static final HttpStatus HTTP_VERSION_NOT_SUPPORTED =
newConstant(505, "HTTP Version Not Supported");
/**
* 506 Variant Also Negotiates (RFC2295).
*/
public static final HttpStatus VARIANT_ALSO_NEGOTIATES = newConstant(506, "Variant Also Negotiates");
/**
* 507 Insufficient Storage (WebDAV, RFC4918).
*/
public static final HttpStatus INSUFFICIENT_STORAGE = newConstant(507, "Insufficient Storage");
/**
* 510 Not Extended (RFC2774).
*/
public static final HttpStatus NOT_EXTENDED = newConstant(510, "Not Extended");
/**
* 511 Network Authentication Required (RFC6585).
*/
public static final HttpStatus NETWORK_AUTHENTICATION_REQUIRED =
newConstant(511, "Network Authentication Required");
static {
for (int i = 0; i < 1000; i++) {
if (!map.containsKey(i)) {
map.put(i, new HttpStatus(i));
}
}
}
private static HttpStatus newConstant(int statusCode, String reasonPhrase) {
final HttpStatus status = new HttpStatus(statusCode, reasonPhrase);
map.put(statusCode, status);
return status;
}
/**
* Returns the {@link HttpStatus} represented by the specified code.
*/
public static HttpStatus valueOf(int code) {
final HttpStatus status = map.get(code);
return status != null ? status : new HttpStatus(code);
}
private final int code;
private final String codeAsText;
private final HttpStatusClass codeClass;
private final String reasonPhrase;
private final HttpData httpData;
private final String strVal;
/**
* Creates a new instance with the specified {@code code} and the auto-generated default reason phrase.
*/
private HttpStatus(int code) {
this(code, HttpStatusClass.valueOf(code).defaultReasonPhrase() + " (" + code + ')');
}
/**
* Creates a new instance with the specified {@code code} and its {@code reasonPhrase}.
*/
public HttpStatus(int code, String reasonPhrase) {
if (code < 0) {
throw new IllegalArgumentException(
"code: " + code + " (expected: 0+)");
}
if (reasonPhrase == null) {
throw new NullPointerException("reasonPhrase");
}
for (int i = 0; i < reasonPhrase.length(); i++) {
char c = reasonPhrase.charAt(i);
// Check prohibited characters.
switch (c) {
case '\n': case '\r':
throw new IllegalArgumentException(
"reasonPhrase contains one of the following prohibited characters: " +
"\\r\\n: " + reasonPhrase);
}
}
this.code = code;
codeAsText = Integer.toString(code);
codeClass = HttpStatusClass.valueOf(code);
this.reasonPhrase = reasonPhrase;
strVal = new StringBuilder(reasonPhrase.length() + 5).append(code)
.append(' ')
.append(reasonPhrase)
.toString();
httpData = HttpData.ofUtf8(strVal);
}
/**
* Returns the code of this {@link HttpStatus}.
*/
public int code() {
return code;
}
/**
* Returns the status code as {@link String}.
*/
public String codeAsText() {
return codeAsText;
}
/**
* Returns the reason phrase of this {@link HttpStatus}.
*/
public String reasonPhrase() {
return reasonPhrase;
}
/**
* Returns the class of this {@link HttpStatus}.
*/
public HttpStatusClass codeClass() {
return codeClass;
}
/**
* Returns the {@link HttpData} whose content is {@code "<code> <reasonPhrase>"} encoded in UTF-8.
* Do not modify the content of the returned {@link HttpData}; it will be reused.
*/
public HttpData toHttpData() {
return httpData;
}
@Override
public int hashCode() {
return code();
}
/**
* Returns whether the specified object is "equal to" this status.
*
* <p>Equality of {@link HttpStatus} only depends on {@link #code()}. The reason phrase is not considered
* for equality.
*/
@Override
public boolean equals(Object o) {
if (!(o instanceof HttpStatus)) {
return false;
}
return code() == ((HttpStatus) o).code();
}
/**
* Compares this status to the specified status.
*
* <p>Equality of {@link HttpStatus} only depends on {@link #code()}. The reason phrase is not considered
* for equality.
*/
@Override
public int compareTo(HttpStatus o) {
return code() - o.code();
}
@Override
public String toString() {
return strVal;
}
}