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

io.helidon.common.http.Http Maven / Gradle / Ivy

There is a newer version: 4.0.0-M1
Show newest version
/*
 * Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved.
 *
 * 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.
 */

package io.helidon.common.http;

import java.time.LocalDate;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.format.DateTimeParseException;
import java.time.format.SignStyle;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;

import io.helidon.common.CollectionsHelper;

import static java.time.temporal.ChronoField.DAY_OF_MONTH;
import static java.time.temporal.ChronoField.DAY_OF_WEEK;
import static java.time.temporal.ChronoField.HOUR_OF_DAY;
import static java.time.temporal.ChronoField.MINUTE_OF_HOUR;
import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
import static java.time.temporal.ChronoField.OFFSET_SECONDS;
import static java.time.temporal.ChronoField.SECOND_OF_MINUTE;
import static java.time.temporal.ChronoField.YEAR;

/**
 * HTTP protocol related constants and utilities.
 * 

* Utility class */ public final class Http { private Http() { } /** * Commonly used status codes defined by HTTP, see * HTTP/1.1 documentation * for the complete list. Additional status codes can be added by applications * by creating an implementation of {@link ResponseStatus}. *

* Copied from JAX-RS. */ public enum Status implements ResponseStatus { /** * 200 OK, see HTTP/1.1 documentation. */ OK_200(200, "OK"), /** * 201 Created, see HTTP/1.1 documentation. */ CREATED_201(201, "Created"), /** * 202 Accepted, see HTTP/1.1 documentation * . */ ACCEPTED_202(202, "Accepted"), /** * 204 No Content, see * HTTP/1.1 documentation. */ NO_CONTENT_204(204, "No Content"), /** * 205 Reset Content, see * HTTP/1.1 documentation. * * @since 2.0 */ RESET_CONTENT_205(205, "Reset Content"), /** * 206 Reset Content, see * HTTP/1.1 documentation. * * @since 2.0 */ PARTIAL_CONTENT_206(206, "Partial Content"), /** * 301 Moved Permanently, see * HTTP/1.1 documentation. */ MOVED_PERMANENTLY_301(301, "Moved Permanently"), /** * 302 Found, see HTTP/1.1 documentation. * * @since 2.0 */ FOUND_302(302, "Found"), /** * 303 See Other, see * HTTP/1.1 documentation. */ SEE_OTHER_303(303, "See Other"), /** * 304 Not Modified, see * HTTP/1.1 documentation. */ NOT_MODIFIED_304(304, "Not Modified"), /** * 305 Use Proxy, see * HTTP/1.1 documentation. * * @since 2.0 */ USE_PROXY_305(305, "Use Proxy"), /** * 307 Temporary Redirect, see * HTTP/1.1 documentation. */ TEMPORARY_REDIRECT_307(307, "Temporary Redirect"), /** * 400 Bad Request, see * HTTP/1.1 documentation. */ BAD_REQUEST_400(400, "Bad Request"), /** * 401 Unauthorized, see * HTTP/1.1 documentation. */ UNAUTHORIZED_401(401, "Unauthorized"), /** * 402 Payment Required, see * HTTP/1.1 documentation. * * @since 2.0 */ PAYMENT_REQUIRED_402(402, "Payment Required"), /** * 403 Forbidden, see * HTTP/1.1 documentation. */ FORBIDDEN_403(403, "Forbidden"), /** * 404 Not Found, see * HTTP/1.1 documentation. */ NOT_FOUND_404(404, "Not Found"), /** * 405 Method Not Allowed, see * HTTP/1.1 documentation. * * @since 2.0 */ METHOD_NOT_ALLOWED_405(405, "Method Not Allowed"), /** * 406 Not Acceptable, see * HTTP/1.1 documentation. */ NOT_ACCEPTABLE_406(406, "Not Acceptable"), /** * 407 Proxy Authentication Required, see * HTTP/1.1 documentation. * * @since 2.0 */ PROXY_AUTHENTICATION_REQUIRED_407(407, "Proxy Authentication Required"), /** * 408 Request Timeout, see * HTTP/1.1 documentation. * * @since 2.0 */ REQUEST_TIMEOUT_408(408, "Request Timeout"), /** * 409 Conflict, see * HTTP/1.1 documentation. */ CONFLICT_409(409, "Conflict"), /** * 410 Gone, see HTTP/1.1 documentation. */ GONE_410(410, "Gone"), /** * 411 Length Required, see * HTTP/1.1 documentation. * * @since 2.0 */ LENGTH_REQUIRED_411(411, "Length Required"), /** * 412 Precondition Failed, see * HTTP/1.1 documentation. */ PRECONDITION_FAILED_412(412, "Precondition Failed"), /** * 413 Request Entity Too Large, see * HTTP/1.1 documentation. * * @since 2.0 */ REQUEST_ENTITY_TOO_LARGE_413(413, "Request Entity Too Large"), /** * 414 Request-URI Too Long, see * HTTP/1.1 documentation. * * @since 2.0 */ REQUEST_URI_TOO_LONG_414(414, "Request-URI Too Long"), /** * 415 Unsupported Media Type, see * HTTP/1.1 documentation. */ UNSUPPORTED_MEDIA_TYPE_415(415, "Unsupported Media Type"), /** * 416 Requested Range Not Satisfiable, see * HTTP/1.1 documentation. * * @since 2.0 */ REQUESTED_RANGE_NOT_SATISFIABLE_416(416, "Requested Range Not Satisfiable"), /** * 417 Expectation Failed, see * HTTP/1.1 documentation. * * @since 2.0 */ EXPECTATION_FAILED_417(417, "Expectation Failed"), /** * 418 I'm a teapot, see * Hyper Text Coffee Pot Control Protocol (HTCPCP/1.0). */ I_AM_A_TEAPOT(418, "I'm a teapot"), /** * 500 Internal Server Error, see * HTTP/1.1 documentation. */ INTERNAL_SERVER_ERROR_500(500, "Internal Server Error"), /** * 501 Not Implemented, see * HTTP/1.1 documentation. * * @since 2.0 */ NOT_IMPLEMENTED_501(501, "Not Implemented"), /** * 502 Bad Gateway, see * HTTP/1.1 documentation. * * @since 2.0 */ BAD_GATEWAY_502(502, "Bad Gateway"), /** * 503 Service Unavailable, see * HTTP/1.1 documentation. */ SERVICE_UNAVAILABLE_503(503, "Service Unavailable"), /** * 504 Gateway Timeout, see * HTTP/1.1 documentation. * * @since 2.0 */ GATEWAY_TIMEOUT_504(504, "Gateway Timeout"), /** * 505 HTTP Version Not Supported, see * HTTP/1.1 documentation. * * @since 2.0 */ HTTP_VERSION_NOT_SUPPORTED(505, "HTTP Version Not Supported"); private final int code; private final String reason; private final Family family; Status(int statusCode, String reasonPhrase) { this.code = statusCode; this.reason = reasonPhrase; this.family = Family.of(statusCode); } /** * Convert a numerical status code into the corresponding {@code Status} enum value. *

* As opposed to {@link ResponseStatus#create(int)}, this method returns {@link Optional#empty() no value} * for an unknown status code not represented by a value in this enumeration of standard HTTP response status codes. * * @param statusCode the numerical status code. * @return optionally the matching Status if a matching {@code Status} value is defined. */ public static Optional find(int statusCode) { for (Status s : Status.values()) { if (s.code == statusCode) { return Optional.of(s); } } return Optional.empty(); } /** * Get the class of status code. * * @return the class of status code. */ @Override public Family family() { return family; } /** * Get the associated status code. * * @return the status code. */ @Override public int code() { return code; } /** * Get the reason phrase. * * @return the reason phrase. */ @Override public String reasonPhrase() { return reason; } /** * Get the response status as string. * * @return the response status string in the form of a partial HTTP response status line, * i.e. {@code "Status-Code SP Reason-Phrase"}. */ @Override public String toString() { return code + " " + reason; } } /** * Enumeration of all standard HTTP {@link RequestMethod methods}. * It is extensible enumeration pattern. * * @see RequestMethod */ public enum Method implements RequestMethod { /** * The OPTIONS method represents a request for information about the communication options available * on the request/response chain identified by the Request-URI. This method allows the client to determine the options * and/or requirements associated with a resource, or the capabilities of a server, without implying a resource action * or initiating a resource retrieval. */ OPTIONS, /** * The GET method means retrieve whatever information (in the form of an entity) is identified by the Request-URI. * If the Request-URI refers to a data-producing tryProcess, it is the produced data which shall be returned as the entity * in the response and not the source text of the tryProcess, unless that text happens to be the output of the tryProcess. */ GET, /** * The HEAD method is identical to {@link #GET} except that the server MUST NOT return a message-body in the response. * The metainformation contained in the HTTP headers in response to a HEAD request SHOULD be identical to the information * sent in response to a GET request. This method can be used for obtaining metainformation about the entity implied * by the request without transferring the entity-body itself. This method is often used for testing hypertext links * for validity, accessibility, and recent modification. */ HEAD, /** * The POST method is used to request that the origin server acceptedTypes the entity enclosed in the request * as a new subordinate of the resource identified by the Request-URI in the Request-Line. * The actual function performed by the POST method is determined by the server and is usually dependent on the * Request-URI. The posted entity is subordinate to that URI in the same way that a file is subordinate to a directory * containing it, a news article is subordinate to a newsgroup to which it is posted, or a record is subordinate * to a database. */ POST, /** * The PUT method requests that the enclosed entity be stored under the supplied Request-URI. If the Request-URI refers * to an already existing resource, the enclosed entity SHOULD be considered as a modified version of the one residing * on the origin server. If the Request-URI does not point to an existing resource, and that URI is capable of being * defined as a new resource by the requesting user agent, the origin server can create the resource with that URI. * If a new resource is created, the origin server MUST inform the user agent via the 201 (Created) response. * If an existing resource is modified, either the 200 (OK) or 204 (No Content) response codes SHOULD be sent to indicate * successful completion of the request. If the resource could not be created or modified with the Request-URI, * an appropriate error response SHOULD be given that reflects the nature of the problem. The recipient of the entity * MUST NOT ignore any Content-* (e.g. Content-Range) headers that it does not understand or implement and MUST return * a 501 (Not Implemented) response in such cases. */ PUT, /** * The DELETE method requests that the origin server delete the resource identified by the Request-URI. * This method MAY be overridden by human intervention (or other means) on the origin server. The client cannot * be guaranteed that the operation has been carried out, even if the status code returned from the origin server * indicates that the action has been completed successfully. However, the server SHOULD NOT indicate success unless, * at the time the response is given, it intends to delete the resource or move it to an inaccessible location. */ DELETE, /** * The TRACE method is used to invoke a remote, application-layer loop- back of the request message. * The final recipient of the request SHOULD reflect the message received back to the client as the entity-body * of a 200 (OK) response. The final recipient is either the origin server or the first proxy or gateway to receive * a Max-Forwards value of zero (0) in the request (see section 14.31). A TRACE request MUST NOT include an entity. */ TRACE } /** * Enumeration of supported HTTP protocol versions. */ public enum Version { /** * HTTP version {@code HTTP/1.0}. */ V1_0("HTTP/1.0"), /** * HTTP version {@code HTTP/1.1}. */ V1_1("HTTP/1.1"), /** * HTTP version {@code HTTP/2.0}. */ V2_0("HTTP/2.0"); private final String value; Version(String value) { this.value = value; } /** * Returns HTTP version for provided parameter. * * @param version HTTP version. * @return Version instance. * @throws NullPointerException if parameter {@code version} is null. * @throws IllegalArgumentException if it is not provided version. */ public static Version create(String version) { Objects.requireNonNull(version, "Version value is null!"); for (Version v : Version.values()) { if (version.equals(v.value)) { return v; } } throw new IllegalArgumentException("Unknown HTTP version: " + version + "!"); } /** * Returns {@code String} representation of this {@link Version}. * * @return a string representation. */ public String value() { return value; } } /** * Interface representing an HTTP request method, all standard methods are in {@link Method} enumeration. * * @see Method */ @FunctionalInterface public interface RequestMethod { /** * Create new HTTP request method instance from the provided name. *

* In case the method name is recognized as one of the {@link Method standard HTTP methods}, the respective enumeration * value is returned. * * @param name the method name. Must not be {@code null} or empty and must be a legal HTTP method name string. * @return HTTP request method instance representing an HTTP method with the provided name. * @throws IllegalArgumentException In case of illegal method name or in case the name is empty or {@code null}. */ static RequestMethod create(String name) { if (name != null && !name.isEmpty()) { for (int i = 0; i < name.length(); i++) { char ch = name.charAt(i); if (Character.isISOControl(ch)) { throw new IllegalArgumentException("HTTP method name parameter must not contain ISO control characters!"); } else if (Character.isWhitespace(ch)) { throw new IllegalArgumentException("HTTP method name parameter must not contain whitespace!"); } } } else { throw new IllegalArgumentException("HTTP method name must not be null or empty!"); } final String upperCaseName = name.toUpperCase(); for (Method method : Method.values()) { if (method.name().equals(upperCaseName)) { return method; } } return new RequestMethod() { @Override public String name() { return upperCaseName; } @Override public boolean equals(Object other) { return (other instanceof RequestMethod) && name().equals(((RequestMethod) other).name()); } @Override public int hashCode() { return upperCaseName.hashCode(); } }; } /** * Get method name. * * @return a method name. */ String name(); } /** * Base interface for status codes used in HTTP responses. *

* Copied from JAX-RS. */ @SuppressWarnings("unused") public interface ResponseStatus { /** * Convert a numerical status code into the corresponding ResponseStatus. *

* As opposed to {@link Status#find(int)}, this method is guaranteed to always return an instance. * For an unknown {@link Status} it creates an ad-hoc {@link ResponseStatus}. * * @param statusCode the numerical status code * @return the matching ResponseStatus; either a {@link Status} or an ad-hoc {@link ResponseStatus} */ static ResponseStatus create(int statusCode) { return create(statusCode, null); } /** * Convert a numerical status code into the corresponding ResponseStatus. *

* It either returns an existing {@link Status} if possible. For an unknown {@link Status} it creates * an ad-hoc {@link ResponseStatus} or whenever a custom reason phrase is provided. * * @param statusCode the numerical status code; if known, a {@link Status is returned} * @param reasonPhrase the reason phrase; if {@code null} or a known reason phrase, a * {@link Status} is returned; otherwise, a new instance is returned * @return the matching ResponseStatus; either a {@link Status} or an ad-hoc {@link ResponseStatus} */ static ResponseStatus create(int statusCode, String reasonPhrase) { return Status.find(statusCode) // keep status that has the same reason phrase or if the supplied phrase is null .filter(status -> (null == reasonPhrase) || status.reasonPhrase().equalsIgnoreCase(reasonPhrase)) // the next statement returns an instance of ResponseStatus, previous of Status - cast // to make the mapping work without .map(ResponseStatus.class::cast) // only create the new ResponseStatus if we did not find an existing Status .orElseGet(() -> new ResponseStatus() { // not using a method, as it would be implicitly public (this being an interface) @Override public int code() { return statusCode; } @Override public Family family() { return Family.of(statusCode); } @Override public String reasonPhrase() { return reasonPhrase; } @Override public int hashCode() { return Integer.hashCode(statusCode); } @Override public boolean equals(Object other) { if (other instanceof ResponseStatus) { ResponseStatus os = (ResponseStatus) other; return (code() == os.code()) && (family() == os.family()) && (reasonPhraseEquals(os)); } return false; } private boolean reasonPhraseEquals(ResponseStatus other) { if (null == reasonPhrase) { return null == other.reasonPhrase(); } return reasonPhrase.equalsIgnoreCase(other.reasonPhrase()); } @Override public String toString() { return "ResponseStatus{code=" + code() + ", reason" + reasonPhrase() + "}"; } }); } /** * Get the associated integer value representing the status code. * * @return the integer value representing the status code. */ int code(); /** * Get the class of status code. * * @return the class of status code. */ Family family(); /** * Get the reason phrase. * * @return the reason phrase. */ String reasonPhrase(); /** * An enumeration representing the class of status code. Family is used * here since class is overloaded in Java. *

* Copied from JAX-RS. */ enum Family { /** * {@code 1xx} HTTP status codes. */ INFORMATIONAL, /** * {@code 2xx} HTTP status codes. */ SUCCESSFUL, /** * {@code 3xx} HTTP status codes. */ REDIRECTION, /** * {@code 4xx} HTTP status codes. */ CLIENT_ERROR, /** * {@code 5xx} HTTP status codes. */ SERVER_ERROR, /** * Other, unrecognized HTTP status codes. */ OTHER; /** * Get the family for the response status code. * * @param statusCode response status code to get the family for. * @return family of the response status code. */ public static Family of(int statusCode) { switch (statusCode / 100) { case 1: return Family.INFORMATIONAL; case 2: return Family.SUCCESSFUL; case 3: return Family.REDIRECTION; case 4: return Family.CLIENT_ERROR; case 5: return Family.SERVER_ERROR; default: return Family.OTHER; } } } } /** * Utility class with a list of names of standard HTTP headers and related tooling methods. */ @SuppressWarnings({"WeakerAccess", "unused"}) public static final class Header { /** * The {@value} header name. * Content-Types that are acceptedTypes for the response. */ public static final String ACCEPT = "Accept"; /** * The {@value} header name. * Character sets that are acceptedTypes. */ public static final String ACCEPT_CHARSET = "Accept-Charset"; /** * The {@value} header name. * List of acceptedTypes encodings. */ public static final String ACCEPT_ENCODING = "Accept-Encoding"; /** * The {@value} header name. * List of acceptedTypes human languages for response. */ public static final String ACCEPT_LANGUAGE = "Accept-Language"; /** * The {@value} header name. * Acceptable version in time. */ public static final String ACCEPT_DATETIME = "Accept-Datetime"; /** * The {@value} header name. * Authentication credentials for HTTP authentication. */ public static final String AUTHORIZATION = "Authorization"; /** * The {@value} header name. * An HTTP cookie previously sent by the server with {@value SET_COOKIE}. */ public static final String COOKIE = "Cookie"; /** * The {@value} header name. * Indicates that particular server behaviors are required by the client. */ public static final String EXPECT = "Expect"; /** * The {@value} header name. * Disclose original information of a client connecting to a web server through an HTTP proxy. */ public static final String FORWARDED = "Forwarded"; /** * The {@value} header name. * The email address of the user making the request. */ public static final String FROM = "From"; /** * The {@value} header name. * The domain name of the server (for virtual hosting), and the TCP port number on which the server is listening. * The port number may be omitted if the port is the standard port for the service requested. */ public static final String HOST = "Host"; /** * The {@value} header name. * Only perform the action if the client supplied entity matches the same entity on the server. This is mainly * for methods like PUT to only update a resource if it has not been modified since the user last updated it. */ public static final String IF_MATCH = "If-Match"; /** * The {@value} header name. * Allows a 304 Not Modified to be returned if content is unchanged. */ public static final String IF_MODIFIED_SINCE = "If-Modified-Since"; /** * The {@value} header name. * Allows a 304 Not Modified to be returned if content is unchanged, based on {@link #ETAG}. */ public static final String IF_NONE_MATCH = "If-None-Match"; /** * The {@value} header name. * If the entity is unchanged, send me the part(s) that I am missing; otherwise, send me the entire new entity. */ public static final String IF_RANGE = "If-Range"; /** * The {@value} header name. * Only send the response if the entity has not been modified since a specific time. */ public static final String IF_UNMODIFIED_SINCE = "If-Unmodified-Since"; /** * The {@value} header name. * Limit the number of times the message can be forwarded through proxies or gateways. */ public static final String MAX_FORWARDS = "Max-Forwards"; /** * The {@value} header name. * Initiates a request for cross-origin resource sharing (asks server for an {@code 'Access-Control-Allow-Origin'} * response field). */ public static final String ORIGIN = "Origin"; /** * The {@value} header name. * Request only part of an entity. Bytes are numbered from 0. */ public static final String RANGE = "Range"; /** * The {@value} header name. * This is the address of the previous web page from which a link to the currently requested page was followed. * (The word referrer has been misspelled in the RFC as well as in most implementations to the point that it has * become standard usage and is considered correct terminology.) */ public static final String REFERER = "Referer"; /** * The {@value} header name. * The transfer encodings the user agent is willing to acceptedTypes: the same values as for the response header field * {@code Transfer-Encoding} can be used, plus the trailers value (related to the chunked transfer method) * to notify the server it expects to receive additional fields in the trailer after the last, zero-sized, chunk. */ public static final String TE = "TE"; /** * The {@value} header name. * The user agent string of the user agent. */ public static final String USER_AGENT = "User-Agent"; /** * The {@value} header name. * Informs the server of proxies through which the request was sent. */ public static final String VIA = "Via"; /** * The {@value} header name. * Specifies which patch document formats this server supports. */ public static final String ACCEPT_PATCH = "Accept-Patch"; /** * The {@value} header name. * What partial content range types this server supports via byte serving. */ public static final String ACCEPT_RANGES = "Accept-Ranges"; /** * The {@value} header name. * The age the object has been in a proxy cache in seconds. */ public static final String AGE = "Age"; /** * The {@value} header name. * Valid actions for a specified resource. To be used for a 405 Method not allowed. */ public static final String ALLOW = "Allow"; /** * The {@value} header name. * A server uses Alt-Svc header (meaning Alternative Services) to indicate that its resources can also be * accessed at a different network location (host or port) or using a different protocol. */ public static final String ALT_SVC = "Alt-Svc"; /** * The {@value} header name. * Tells all caching mechanisms from server to client whether they may cache this object. It is measured in seconds. */ public static final String CACHE_CONTROL = "Cache-Control"; /** * The {@value} header name. * Control options for the current connection and list of hop-by-hop response fields. */ public static final String CONNECTION = "Connection"; /** * The {@value} header name. * An opportunity to raise a File Download dialogue box for a known MIME type with binary format or suggest * a filename for dynamic content. Quotes are necessary with special characters. */ public static final String CONTENT_DISPOSITION = "Content-Disposition"; /** * The {@value} header name. * The type of encoding used on the data. */ public static final String CONTENT_ENCODING = "Content-Encoding"; /** * The {@value} header name. * The natural language or languages of the intended audience for the enclosed content. */ public static final String CONTENT_LANGUAGE = "Content-Language"; /** * The {@value} header name. * The length of the response body in octets. */ public static final String CONTENT_LENGTH = "Content-Length"; /** * The {@value} header name. * An alternate location for the returned data. */ public static final String CONTENT_LOCATION = "aa"; /** * The {@value} header name. * Where in a full body message this partial message belongs. */ public static final String CONTENT_RANGE = "Content-Range"; /** * The {@value} header name. * The MIME type of this content. */ public static final String CONTENT_TYPE = "Content-Type"; /** * The {@value} header name. * The date and time that the message was sent (in HTTP-date format as defined by RFC 7231). */ public static final String DATE = "Date"; /** * The {@value} header name. * An identifier for a specific version of a resource, often a message digest. */ public static final String ETAG = "ETag"; /** * The {@value} header name. * Gives the date/time after which the response is considered stale (in HTTP-date format as defined by RFC 7231) */ public static final String EXPIRES = "Expires"; /** * The {@value} header name. * The last modified date for the requested object (in HTTP-date format as defined by RFC 7231) */ public static final String LAST_MODIFIED = "Last-Modified"; /** * The {@value} header name. * Used to express a typed relationship with another resource, where the relation type is defined by RFC 5988. */ public static final String LINK = "Link"; /** * The {@value} header name. * Used in redirection, or whenRequest a new resource has been created. */ public static final String LOCATION = "Location"; /** * The {@value} header name. * Implementation-specific fields that may have various effects anywhere along the request-response chain. */ public static final String PRAGMA = "Pragma"; /** * The {@value} header name. * HTTP Public Key Pinning, announces hash of website's authentic TLS certificate. */ public static final String PUBLIC_KEY_PINS = "Public-Key-Pins"; /** * The {@value} header name. * If an entity is temporarily unavailable, this instructs the client to try again later. Value could be a specified * period of time (in seconds) or an HTTP-date. */ public static final String RETRY_AFTER = "Retry-After"; /** * The {@value} header name. * A name for the server. */ public static final String SERVER = "Server"; /** * The {@value} header name. * An HTTP cookie set directive. */ public static final String SET_COOKIE = "Set-Cookie"; /** * The {@value} header name. * A HSTS Policy informing the HTTP client how long to cache the HTTPS only policy and whether this applies to subdomains. */ public static final String STRICT_TRANSPORT_SECURITY = "Strict-Transport-Security"; /** * The {@value} header name. * The Trailer general field value indicates that the given set of header fields is present in the trailer of * a message encoded with chunked transfer coding. */ public static final String TRAILER = "Trailer"; /** * The {@value} header name. * The form of encoding used to safely transfer the entity to the user. Currently defined methods are: * {@code chunked, compress, deflate, gzip, identity}. */ public static final String TRANSFER_ENCODING = "Transfer-Encoding"; /** * The {@value} header name. * Tracking Status Value, value suggested to be sent in response to a DNT(do-not-track). */ public static final String TSV = "TSV"; /** * The {@value} header name. * Ask to upgrade to another protocol. */ public static final String UPGRADE = "Upgrade"; /** * The {@value} header name. * Tells downstream proxies how to match future request headers to decide whether the cached response can be used rather * than requesting a fresh one from the origin server. */ public static final String VARY = "Vary"; /** * The {@value} header name. * A general warning about possible problems with the entity body. */ public static final String WARNING = "Warning"; /** * The {@value} header name. * Indicates the authentication scheme that should be used to access the requested entity. */ public static final String WWW_AUTHENTICATE = "WWW-Authenticate"; private Header() { } } /** * Support for HTTP date formats based on RFC2616. */ public static final class DateTime { /** * The RFC850 date-time formatter, such as {@code 'Sunday, 06-Nov-94 08:49:37 GMT'}. *

* This is obsolete standard (obsoleted by RFC1036). Headers MUST NOT be generated in this format. * However it should be used as a fallback for parsing to achieve compatibility with older HTTP standards. *

* Since the format accepts 2 digits year representation formatter works well for dates between * {@code (now - 50 Years)} and {@code (now + 49 Years)}. */ public static final DateTimeFormatter RFC_850_DATE_TIME; /** * The RFC1123 date-time formatter, such as {@code 'Tue, 3 Jun 2008 11:05:30 GMT'}. *

* This is standard for RFC2616 and all created headers MUST be in this format! However implementation must * accept headers also in RFC850 and ANSI C {@code asctime()} format. *

* This is just copy of convenient copy of {@link DateTimeFormatter#RFC_1123_DATE_TIME}. */ public static final DateTimeFormatter RFC_1123_DATE_TIME = DateTimeFormatter.RFC_1123_DATE_TIME; /** * The ANSI C's {@code asctime()} format, such as {@code 'Sun Nov 6 08:49:37 1994'}. *

* Headers MUST NOT be generated in this format. * However it should be used as a fallback for parsing to achieve compatibility with older HTTP standards. */ public static final DateTimeFormatter ASCTIME_DATE_TIME; /** * Manual list ensures that no localisation can affect standard parsing/generating. */ private static final Map MONTH_NAME_3D; static { Map map = new HashMap<>(); map.put(1L, "Jan"); map.put(2L, "Feb"); map.put(3L, "Mar"); map.put(4L, "Apr"); map.put(5L, "May"); map.put(6L, "Jun"); map.put(7L, "Jul"); map.put(8L, "Aug"); map.put(9L, "Sep"); map.put(10L, "Oct"); map.put(11L, "Nov"); map.put(12L, "Dec"); MONTH_NAME_3D = Collections.unmodifiableMap(map); // manually code maps to ensure correct data always used // (locale data can be changed by application code) Map dayOfWeekFull = CollectionsHelper.mapOf(1L, "Monday", 2L, "Tuesday", 3L, "Wednesday", 4L, "Thursday", 5L, "Friday", 6L, "Saturday", 7L, "Sunday"); RFC_850_DATE_TIME = new DateTimeFormatterBuilder() .parseCaseInsensitive() .parseLenient() .optionalStart() .appendText(DAY_OF_WEEK, dayOfWeekFull) .appendLiteral(", ") .optionalEnd() .appendValue(DAY_OF_MONTH, 2, 2, SignStyle.NOT_NEGATIVE) .appendLiteral('-') .appendText(MONTH_OF_YEAR, MONTH_NAME_3D) .appendLiteral('-') .appendValueReduced(YEAR, 2, 2, LocalDate.now().minusYears(50).getYear()) .appendLiteral(' ') .appendValue(HOUR_OF_DAY, 2) .appendLiteral(':') .appendValue(MINUTE_OF_HOUR, 2) .optionalStart() .appendLiteral(':') .appendValue(SECOND_OF_MINUTE, 2) .optionalEnd() .appendLiteral(' ') .appendOffset("+HHMM", "GMT") .toFormatter(); // manually code maps to ensure correct data always used // (locale data can be changed by application code) Map dayOfWeek3d = CollectionsHelper.mapOf(1L, "Mon", 2L, "Tue", 3L, "Wed", 4L, "Thu", 5L, "Fri", 6L, "Sat", 7L, "Sun"); ASCTIME_DATE_TIME = new DateTimeFormatterBuilder() .parseCaseInsensitive() .parseLenient() .optionalStart() .appendText(DAY_OF_WEEK, dayOfWeek3d) .appendLiteral(' ') .appendText(MONTH_OF_YEAR, MONTH_NAME_3D) .appendLiteral(' ') .padNext(2) .appendValue(DAY_OF_MONTH, 1, 2, SignStyle.NOT_NEGATIVE) .appendLiteral(' ') .appendValue(HOUR_OF_DAY, 2) .appendLiteral(':') .appendValue(MINUTE_OF_HOUR, 2) .appendLiteral(':') .appendValue(SECOND_OF_MINUTE, 2) .appendLiteral(' ') .appendValue(YEAR, 4) .parseDefaulting(OFFSET_SECONDS, 0) .toFormatter(); } private DateTime() { } /** * Parse provided text to {@link ZonedDateTime} using any possible date / time format specified * by RFC2616 Hypertext Transfer Protocol. *

* Formats are specified by {@link #RFC_1123_DATE_TIME}, {@link #RFC_850_DATE_TIME} and {@link #ASCTIME_DATE_TIME}. * * @param text a text to parse. * @return parsed date time. * @throws DateTimeParseException if not in any of supported formats. */ public static ZonedDateTime parse(String text) { try { return ZonedDateTime.parse(text, RFC_1123_DATE_TIME); } catch (DateTimeParseException pe) { try { return ZonedDateTime.parse(text, RFC_850_DATE_TIME); } catch (DateTimeParseException pe2) { return ZonedDateTime.parse(text, ASCTIME_DATE_TIME); } } } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy