// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.jdisc; import com.yahoo.jdisc.handler.ContentChannel; import com.yahoo.jdisc.handler.RequestHandler; import com.yahoo.jdisc.handler.ResponseDispatch; import com.yahoo.jdisc.handler.ResponseHandler; import java.util.HashMap; import java.util.Map; /** *

This class represents the single response (which may have any content model that a {@link RequestHandler} chooses * to implement) of some single request. Contrary to the {@link Request} class, this has no active reference to the * parent {@link Container} (this is tracked internally by counting the number of requests vs the number of responses * seen). The {@link ResponseHandler} of a Response is implicit in the invocation of {@link * RequestHandler#handleRequest(Request, ResponseHandler)}.

* *

The usage pattern of the Response is similar to that of the Request in that the {@link ResponseHandler} returns a * {@link ContentChannel} into which to write the Response content.

* * @author Simon Thoresen Hult * @see Request * @see ResponseHandler */ public class Response { /** * This interface acts as a namespace for the built-in status codes of the jDISC core. These are identical to the * common HTTP status codes (see RFC2616). */ public interface Status { /** *

1xx: Informational - Request received, continuing process.

*/ int CONTINUE = 100; int SWITCHING_PROTOCOLS = 101; int PROCESSING = 102; /** *

2xx: Success - The action was successfully received, understood, and accepted.

*/ int OK = 200; int CREATED = 201; int ACCEPTED = 202; int NON_AUTHORITATIVE_INFORMATION = 203; int NO_CONTENT = 204; int RESET_CONTENT = 205; int PARTIAL_CONTENT = 206; int MULTI_STATUS = 207; /** *

3xx: Redirection - Further action must be taken in order to complete the request.

*/ int MULTIPLE_CHOICES = 300; int MOVED_PERMANENTLY = 301; int FOUND = 302; int SEE_OTHER = 303; int NOT_MODIFIED = 304; int USE_PROXY = 305; int TEMPORARY_REDIRECT = 307; /** *

4xx: Client Error - The request contains bad syntax or cannot be fulfilled.

*/ int BAD_REQUEST = 400; int UNAUTHORIZED = 401; int PAYMENT_REQUIRED = 402; int FORBIDDEN = 403; int NOT_FOUND = 404; int METHOD_NOT_ALLOWED = 405; int NOT_ACCEPTABLE = 406; int PROXY_AUTHENTICATION_REQUIRED = 407; int REQUEST_TIMEOUT = 408; int CONFLICT = 409; int GONE = 410; int LENGTH_REQUIRED = 411; int PRECONDITION_FAILED = 412; int REQUEST_TOO_LONG = 413; int REQUEST_URI_TOO_LONG = 414; int UNSUPPORTED_MEDIA_TYPE = 415; int REQUESTED_RANGE_NOT_SATISFIABLE = 416; int EXPECTATION_FAILED = 417; int INSUFFICIENT_SPACE_ON_RESOURCE = 419; int METHOD_FAILURE = 420; int UNPROCESSABLE_ENTITY = 422; int LOCKED = 423; int FAILED_DEPENDENCY = 424; int TOO_MANY_REQUESTS = 429; /** 5xx: Server Error - The server failed to fulfill an apparently valid request. */ int INTERNAL_SERVER_ERROR = 500; int NOT_IMPLEMENTED = 501; int BAD_GATEWAY = 502; int SERVICE_UNAVAILABLE = 503; int GATEWAY_TIMEOUT = 504; int VERSION_NOT_SUPPORTED = 505; int INSUFFICIENT_STORAGE = 507; } private final Map context = new HashMap<>(); private final HeaderFields headers = new HeaderFields(); private Throwable error; private int status; private Request.RequestType requestType; /** * Creates a new instance of this class. * * @param status The status code to assign to this. */ public Response(int status) { this(status, null); } /** * Creates a new instance of this class. * * @param status The status code to assign to this. * @param error The error to assign to this. */ public Response(int status, Throwable error) { this.status = status; this.error = error; } /** *

Returns the named application context objects. This data is not intended for network transport, rather they * are intended for passing shared data between components of an Application.

* *

Modifying the context map is a thread-unsafe operation -- any changes made after calling {@link * ResponseHandler#handleResponse(Response)} might never become visible to other threads, and might throw * ConcurrentModificationExceptions in other threads.

* * @return The context map. */ public Map context() { return context; } /** *

Returns the set of header fields of this Request. These are the meta-data of the Request, and are not applied * to any internal {@link Container} logic. Modifying headers is a thread-unsafe operation -- any changes made after * calling {@link ResponseHandler#handleResponse(Response)} might never become visible to other threads, and might * throw ConcurrentModificationExceptions in other threads.

* * @return The header fields. */ public HeaderFields headers() { return headers; } /** *

Returns the status code of this response. This is an integer result code of the attempt to understand and * satisfy the corresponding {@link Request}. It is encouraged, although not enforced, to use the built-in {@link * Status} codes whenever possible.

* * @return The status code. * @see #setStatus(int) */ public int getStatus() { return status; } /** *

Sets the status code of this response. This is an integer result code of the attempt to understand and * satisfy the corresponding {@link Request}. It is encouraged, although not enforced, to use the built-in {@link * Status} codes whenever possible.

* *

Because access to this field is not guarded by any lock, any changes made after calling {@link * ResponseHandler#handleResponse(Response)} might never become visible to other threads.

* * @param status The status code to set. * @return This, to allow chaining. * @see #getStatus() */ public Response setStatus(int status) { this.status = status; return this; } /** *

Returns the error of this response, or null if none has been set. This is typically non-null if the status * indicates an unsuccessful response.

* * @return The error. * @see #getError() */ public Throwable getError() { return error; } /** *

Sets the error of this response. It is encouraged, although not enforced, to use this field to attach * additional information to an unsuccessful response.

* *

Because access to this field is not guarded by any lock, any changes made after calling {@link * ResponseHandler#handleResponse(Response)} might never become visible to other threads.

* * @param error The error to set. * @return This, to allow chaining. * @see #getError() */ public Response setError(Throwable error) { this.error = error; return this; } /** Sets the type classification of this request for metric collection purposes */ public void setRequestType(Request.RequestType requestType) { this.requestType = requestType; } /** Returns the type classification of this request for metric collection purposes, or null if not set */ public Request.RequestType getRequestType() { return requestType; } /** * This is a convenience method for creating a Response with status {@link Status#GATEWAY_TIMEOUT} and passing * that to the given {@link ResponseHandler#handleResponse(Response)}. For trivial implementations of {@link * RequestHandler#handleTimeout(Request, ResponseHandler)}, simply call this method. * * @param handler The handler to pass the timeout {@link Response} to. */ public static void dispatchTimeout(ResponseHandler handler) { ResponseDispatch.newInstance(Status.GATEWAY_TIMEOUT).dispatch(handler); } }