
com.yahoo.application.container.handler.Response Maven / Gradle / Ivy
// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.application.container.handler;
import com.yahoo.api.annotations.Beta;
import com.yahoo.jdisc.http.HttpHeaders;
import com.yahoo.text.Utf8;
import java.nio.ByteBuffer;
import java.nio.charset.CharacterCodingException;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.UnsupportedCharsetException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* A response for use with {@link com.yahoo.application.container.JDisc#handleRequest(Request)}.
*
* @author Einar M R Rosenvinge
* @see Request
*/
@Beta
public class Response {
private final static Pattern charsetPattern = Pattern.compile("charset=([^\\s\\;]+)", Pattern.CASE_INSENSITIVE);
private final int status;
private final Headers headers = new Headers();
private final byte[] body;
/**
* Creates a Response with an empty body, and 200 (OK) response code.
*/
public Response() {
this(new byte[0]);
}
/**
* Creates a Response with a message body, and 200 (OK) response code.
*
* @param body the body of the response
*/
public Response(byte[] body) {
this(com.yahoo.jdisc.Response.Status.OK, body);
}
/**
* Creates a Response with a message body, and the given response code.
*
* @param status the status code of the response
* @param body the body of the response
* @since 5.1.28
*/
public Response(int status, byte[] body) {
this.status = status;
this.body = body;
}
/**
* Returns the status code of this response. This is an integer result code of the attempt to understand and
* satisfy the corresponding {@link com.yahoo.application.container.handler.Request}.
*
* @return The status code.
* @since 5.1.28
*/
public int getStatus() {
return status;
}
/**
* Returns the body of this Response.
*
* @return the body of this Response
*/
public byte[] getBody() {
return body;
}
/**
* Attempts to decode the buffer returned by {@link #getBody()} as a String in a best-effort manner. This is done
* using the Content-Type header - and defaults to UTF-8 encoding if the header is unparseable or not found.
* Note that this may very well throw a {@link CharacterCodingException}.
*
* @return a String with the decoded contents of the body buffer
* @throws CharacterCodingException if the body buffer was not well-formed
*/
public String getBodyAsString() throws CharacterCodingException {
CharsetDecoder decoder = charset().newDecoder();
return decoder.decode(ByteBuffer.wrap(body)).toString();
}
/**
* Returns a mutable multi-map of headers for this Response.
*
* @return a mutable multi-map of headers for this Response
*/
public Headers getHeaders() {
return headers;
}
@Override
public String toString() {
String bodyStr = (body == null || body.length == 0) ? "[empty]" : "[omitted]";
return "Response, headers: " + headers + ", body: " + bodyStr;
}
private Charset charset() {
return charset(headers.getFirst(HttpHeaders.Names.CONTENT_TYPE));
}
static Charset charset(String contentType) {
if (contentType != null) {
Matcher matcher = charsetPattern.matcher(contentType);
if (matcher.find()) {
try {
return Charset.forName(matcher.group(1));
} catch (UnsupportedCharsetException uce) {
return Utf8.getCharset();
}
}
}
return Utf8.getCharset();
}
}