// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.container.jdisc; import com.yahoo.container.logging.AccessLogEntry; import com.yahoo.jdisc.HeaderFields; import com.yahoo.jdisc.Request; import com.yahoo.jdisc.Response; import com.yahoo.processing.execution.Execution.Trace.LogValue; import java.io.IOException; import java.io.OutputStream; import java.util.Collections; /** * An HTTP response as an opaque payload with headers and content type. * * @author hmusum * @author Steinar Knutsen */ public abstract class HttpResponse { /** Default response content type; text/plain. */ public static final String DEFAULT_MIME_TYPE = "text/plain"; /** Default encoding/character set of a HTTP response; UTF-8. */ public static final String DEFAULT_CHARACTER_ENCODING = "UTF-8"; private final Response parentResponse; /** * Creates a new HTTP response * * @param status the HTTP status code to return with this response (may be changed later) * @see Response */ public HttpResponse(int status) { parentResponse = com.yahoo.jdisc.http.HttpResponse.newInstance(status); } /** Marshals this response to the network layer. The caller is responsible for flushing and closing outputStream. */ public abstract void render(OutputStream outputStream) throws IOException; /** The amount of content bytes this response may have in-flight (if positive) before response rendering blocks. */ public long maxPendingBytes() { return -1; } /** * Returns the numeric HTTP status code, e.g. 200, 404 and so on. * * @return the numeric HTTP status code */ public int getStatus() { return parentResponse.getStatus(); } /** * Sets the numeric HTTP status code this will return. */ public void setStatus(int status) { parentResponse.setStatus(status); } /** * The response headers. * * @return a mutable, thread-unsafe view of the response headers */ public HeaderFields headers() { return parentResponse.headers(); } /** * The underlying JDisc response. * * @return the actual response which will be used by the JDisc layer */ public com.yahoo.jdisc.Response getJdiscResponse() { return parentResponse; } /** * The MIME type of the response contents or null. If null is returned, no * content type header is added to the HTTP response. * * @return by default {@link HttpResponse#DEFAULT_MIME_TYPE} */ public String getContentType() { return DEFAULT_MIME_TYPE; } /** * The name of the encoding for the response contents, if applicable. Return * null if character set is not applicable to the response in question (e.g. * binary formats). If null is returned, not "charset" element is added to * the content type header. * * @return by default {@link HttpResponse#DEFAULT_CHARACTER_ENCODING} */ public String getCharacterEncoding() { return DEFAULT_CHARACTER_ENCODING; } // ======================================== // Purely optional stuff from this point on // ======================================== /** * Override this method to add information from the response to the access log. * * Remember to also invoke super if you override it. * * @param accessLogEntry the access log entry to add information to. */ public void populateAccessLogEntry(final AccessLogEntry accessLogEntry) { for (LogValue logValue : getLogValues()) { accessLogEntry.addKeyValue(logValue.getKey(), logValue.getValue()); } } /** * Complete creation of this response. * This is called by the container once just before writing the response header back to the caller, * so this is the last moment at which status and headers can be determined. * This default implementation does nothing. */ public void complete() { } public Iterable getLogValues() { return Collections::emptyIterator; } /** Sets the type classification of this request for metric collection purposes */ public void setRequestType(Request.RequestType requestType) { parentResponse.setRequestType(requestType); } /** * Returns the type classification of this request for metric collection purposes, or null if not set. * When not set, the request type will be "read" for GET requests and "write" for other request methods. */ public Request.RequestType getRequestType() { return parentResponse.getRequestType(); } }