org.mockserver.model.HttpResponse Maven / Gradle / Ivy
package org.mockserver.model;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.google.common.collect.Multimap;
import io.netty.handler.codec.http.cookie.ClientCookieDecoder;
import java.nio.charset.Charset;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import static io.netty.handler.codec.http.HttpHeaderNames.CONTENT_TYPE;
import static io.netty.handler.codec.http.HttpHeaderNames.SET_COOKIE;
import static org.mockserver.model.Header.header;
import static org.mockserver.model.HttpStatusCode.NOT_FOUND_404;
import static org.mockserver.model.HttpStatusCode.OK_200;
import static org.mockserver.model.NottableString.string;
/**
* @author jamesdbloom
*/
@SuppressWarnings("rawtypes")
public class HttpResponse extends Action implements HttpMessage {
private int hashCode;
private Integer statusCode;
private String reasonPhrase;
private BodyWithContentType body;
private Headers headers;
private Cookies cookies;
private ConnectionOptions connectionOptions;
/**
* Static builder to create a response.
*/
public static HttpResponse response() {
return new HttpResponse();
}
/**
* Static builder to create a response with a 200 status code and the string response body.
*
* @param body a string
*/
public static HttpResponse response(String body) {
return new HttpResponse().withStatusCode(OK_200.code()).withReasonPhrase(OK_200.reasonPhrase()).withBody(body);
}
/**
* Static builder to create a not found response.
*/
public static HttpResponse notFoundResponse() {
return new HttpResponse().withStatusCode(NOT_FOUND_404.code()).withReasonPhrase(NOT_FOUND_404.reasonPhrase());
}
/**
* The status code to return, such as 200, 404, the status code specified
* here will result in the default status message for this status code for
* example for 200 the status message "OK" is used
*
* @param statusCode an integer such as 200 or 404
*/
public HttpResponse withStatusCode(Integer statusCode) {
this.statusCode = statusCode;
this.hashCode = 0;
return this;
}
public Integer getStatusCode() {
return statusCode;
}
/**
* The reason phrase to return, if no reason code is returned this will
* be defaulted to the standard reason phrase for the statusCode,
* i.e. for a statusCode of 200 the standard reason phrase is "OK"
*
* @param reasonPhrase an string such as "Not Found" or "OK"
*/
public HttpResponse withReasonPhrase(String reasonPhrase) {
this.reasonPhrase = reasonPhrase;
this.hashCode = 0;
return this;
}
public String getReasonPhrase() {
return reasonPhrase;
}
/**
* Set response body to return as a string response body. The character set will be determined by the Content-Type header
* on the response. To force the character set, use {@link #withBody(String, Charset)}.
*
* @param body a string
*/
public HttpResponse withBody(String body) {
if (body != null) {
this.body = new StringBody(body);
this.hashCode = 0;
}
return this;
}
/**
* Set response body to return a string response body with the specified encoding. Note: The character set of the
* response will be forced to the specified charset, even if the Content-Type header specifies otherwise.
*
* @param body a string
* @param charset character set the string will be encoded in
*/
public HttpResponse withBody(String body, Charset charset) {
if (body != null) {
this.body = new StringBody(body, charset);
this.hashCode = 0;
}
return this;
}
/**
* Set response body to return a string response body with the specified encoding. Note: The character set of the
* response will be forced to the specified charset, even if the Content-Type header specifies otherwise.
*
* @param body a string
* @param contentType media type, if charset is included this will be used for encoding string
*/
public HttpResponse withBody(String body, MediaType contentType) {
if (body != null) {
this.body = new StringBody(body, contentType);
this.hashCode = 0;
}
return this;
}
/**
* Set response body to return as binary such as a pdf or image
*
* @param body a byte array
*/
public HttpResponse withBody(byte[] body) {
this.body = new BinaryBody(body);
this.hashCode = 0;
return this;
}
/**
* Set the body to return for example:
*
* string body:
* - exact(" a simple string body");
*
* or
*
* - new StringBody(" a simple string body")
*
* binary body:
* - binary(IOUtils.readFully(getClass().getClassLoader().getResourceAsStream("example.pdf"), 1024));
*
* or
*
* - new BinaryBody(IOUtils.readFully(getClass().getClassLoader().getResourceAsStream("example.pdf"), 1024));
*
* @param body an instance of one of the Body subclasses including StringBody or BinaryBody
*/
public HttpResponse withBody(BodyWithContentType body) {
this.body = body;
this.hashCode = 0;
return this;
}
public BodyWithContentType getBody() {
return body;
}
@JsonIgnore
public byte[] getBodyAsRawBytes() {
return this.body != null ? this.body.getRawBytes() : new byte[0];
}
@JsonIgnore
public String getBodyAsString() {
if (body != null) {
return body.toString();
} else {
return null;
}
}
public Headers getHeaders() {
return this.headers;
}
private Headers getOrCreateHeaders() {
if (this.headers == null) {
this.headers = new Headers();
this.hashCode = 0;
}
return this.headers;
}
public HttpResponse withHeaders(Headers headers) {
if (headers == null || headers.isEmpty()) {
this.headers = null;
} else {
this.headers = headers;
}
this.hashCode = 0;
return this;
}
/**
* The headers to return as a list of Header objects
*
* @param headers a list of Header objects
*/
public HttpResponse withHeaders(List headers) {
getOrCreateHeaders().withEntries(headers);
this.hashCode = 0;
return this;
}
/**
* The headers to return as a varargs of Header objects
*
* @param headers varargs of Header objects
*/
public HttpResponse withHeaders(Header... headers) {
getOrCreateHeaders().withEntries(headers);
this.hashCode = 0;
return this;
}
/**
* Add a header to return as a Header object, if a header with
* the same name already exists this will NOT be modified but
* two headers will exist
*
* @param header a Header object
*/
public HttpResponse withHeader(Header header) {
getOrCreateHeaders().withEntry(header);
this.hashCode = 0;
return this;
}
/**
* Add a header to return as a Header object, if a header with
* the same name already exists this will NOT be modified but
* two headers will exist
*
* @param name the header name
* @param values the header values
*/
public HttpResponse withHeader(String name, String... values) {
if (values.length == 0) {
values = new String[]{".*"};
}
getOrCreateHeaders().withEntry(name, values);
this.hashCode = 0;
return this;
}
/**
* Add a header to return as a Header object, if a header with
* the same name already exists this will NOT be modified but
* two headers will exist
*
* @param name the header name as a NottableString
* @param values the header values which can be a varags of NottableStrings
*/
public HttpResponse withHeader(NottableString name, NottableString... values) {
if (values.length == 0) {
values = new NottableString[]{string(".*")};
}
getOrCreateHeaders().withEntry(header(name, values));
this.hashCode = 0;
return this;
}
public HttpResponse withContentType(MediaType mediaType) {
getOrCreateHeaders().withEntry(header(CONTENT_TYPE.toString(), mediaType.toString()));
this.hashCode = 0;
return this;
}
/**
* Update header to return as a Header object, if a header with
* the same name already exists it will be modified
*
* @param header a Header object
*/
public HttpResponse replaceHeader(Header header) {
getOrCreateHeaders().replaceEntry(header);
this.hashCode = 0;
return this;
}
/**
* Update header to return as a Header object, if a header with
* the same name already exists it will be modified
*
* @param name the header name
* @param values the header values
*/
public HttpResponse replaceHeader(String name, String... values) {
if (values.length == 0) {
values = new String[]{".*"};
}
getOrCreateHeaders().replaceEntry(name, values);
this.hashCode = 0;
return this;
}
public List getHeaderList() {
if (this.headers != null) {
return this.headers.getEntries();
} else {
return Collections.emptyList();
}
}
public Multimap getHeaderMultimap() {
if (this.headers != null) {
return this.headers.getMultimap();
} else {
return null;
}
}
public List getHeader(String name) {
if (this.headers != null) {
return this.headers.getValues(name);
} else {
return Collections.emptyList();
}
}
public String getFirstHeader(String name) {
if (this.headers != null) {
return this.headers.getFirstValue(name);
} else {
return "";
}
}
/**
* Returns true if a header with the specified name has been added
*
* @param name the header name
* @return true if a header has been added with that name otherwise false
*/
public boolean containsHeader(String name) {
if (this.headers != null) {
return this.headers.containsEntry(name);
} else {
return false;
}
}
public HttpResponse removeHeader(String name) {
if (this.headers != null) {
headers.remove(name);
this.hashCode = 0;
}
return this;
}
public HttpResponse removeHeader(NottableString name) {
if (this.headers != null) {
headers.remove(name);
this.hashCode = 0;
}
return this;
}
/**
* Returns true if a header with the specified name has been added
*
* @param name the header name
* @param value the header value
* @return true if a header has been added with that name otherwise false
*/
public boolean containsHeader(String name, String value) {
if (this.headers != null) {
return this.headers.containsEntry(name, value);
} else {
return false;
}
}
public Cookies getCookies() {
return this.cookies;
}
private Cookies getOrCreateCookies() {
if (this.cookies == null) {
this.cookies = new Cookies();
this.hashCode = 0;
}
return this.cookies;
}
public HttpResponse withCookies(Cookies cookies) {
if (cookies == null || cookies.isEmpty()) {
this.cookies = null;
} else {
this.cookies = cookies;
}
this.hashCode = 0;
return this;
}
/**
* The cookies to return as Set-Cookie headers as a list of Cookie objects
*
* @param cookies a list of Cookie objects
*/
public HttpResponse withCookies(List cookies) {
getOrCreateCookies().withEntries(cookies);
this.hashCode = 0;
return this;
}
/**
* The cookies to return as Set-Cookie headers as a varargs of Cookie objects
*
* @param cookies a varargs of Cookie objects
*/
public HttpResponse withCookies(Cookie... cookies) {
getOrCreateCookies().withEntries(cookies);
this.hashCode = 0;
return this;
}
/**
* Add cookie to return as Set-Cookie header
*
* @param cookie a Cookie object
*/
public HttpResponse withCookie(Cookie cookie) {
getOrCreateCookies().withEntry(cookie);
this.hashCode = 0;
return this;
}
/**
* Add cookie to return as Set-Cookie header
*
* @param name the cookies name
* @param value the cookies value
*/
public HttpResponse withCookie(String name, String value) {
getOrCreateCookies().withEntry(name, value);
this.hashCode = 0;
return this;
}
/**
* Adds one cookie to match on or to not match on using the NottableString, each NottableString can either be a positive matching value,
* such as string("match"), or a value to not match on, such as not("do not match"), the string values passed to the NottableString
* can be a plain string or a regex (for more details of the supported regex syntax see
* http://docs.oracle.com/javase/8/docs/api/java/util/regex/Pattern.html)
*
* @param name the cookies name
* @param value the cookies value
*/
public HttpResponse withCookie(NottableString name, NottableString value) {
getOrCreateCookies().withEntry(name, value);
this.hashCode = 0;
return this;
}
public List getCookieList() {
if (this.cookies != null) {
return this.cookies.getEntries();
} else {
return Collections.emptyList();
}
}
public Map getCookieMap() {
if (this.cookies != null) {
return this.cookies.getMap();
} else {
return null;
}
}
public boolean cookieHeadeDoesNotAlreadyExists(Cookie cookieValue) {
List setCookieHeaders = getHeader(SET_COOKIE.toString());
for (String setCookieHeader : setCookieHeaders) {
String existingCookieName = ClientCookieDecoder.LAX.decode(setCookieHeader).name();
String existingCookieValue = ClientCookieDecoder.LAX.decode(setCookieHeader).value();
if (existingCookieName.equalsIgnoreCase(cookieValue.getName().getValue()) && existingCookieValue.equalsIgnoreCase(cookieValue.getValue().getValue())) {
return false;
}
}
return true;
}
public boolean cookieHeadeDoesNotAlreadyExists(String name, String value) {
List setCookieHeaders = getHeader(SET_COOKIE.toString());
for (String setCookieHeader : setCookieHeaders) {
String existingCookieName = ClientCookieDecoder.LAX.decode(setCookieHeader).name();
String existingCookieValue = ClientCookieDecoder.LAX.decode(setCookieHeader).value();
if (existingCookieName.equalsIgnoreCase(name) && existingCookieValue.equalsIgnoreCase(value)) {
return false;
}
}
return true;
}
/**
* The connection options for override the default connection behaviour, this allows full control of headers such
* as "Connection" or "Content-Length" or controlling whether the socket is closed after the response has been sent
*
* @param connectionOptions the connection options for override the default connection behaviour
*/
public HttpResponse withConnectionOptions(ConnectionOptions connectionOptions) {
this.connectionOptions = connectionOptions;
this.hashCode = 0;
return this;
}
public ConnectionOptions getConnectionOptions() {
return connectionOptions;
}
@Override
@JsonIgnore
public Type getType() {
return Type.RESPONSE;
}
public HttpResponse shallowClone() {
return response()
.withStatusCode(statusCode)
.withReasonPhrase(reasonPhrase)
.withBody(body)
.withHeaders(headers)
.withCookies(cookies)
.withDelay(getDelay())
.withConnectionOptions(connectionOptions);
}
@SuppressWarnings("MethodDoesntCallSuperMethod")
public HttpResponse clone() {
return response()
.withStatusCode(statusCode)
.withReasonPhrase(reasonPhrase)
.withBody(body)
.withHeaders(headers != null ? headers.clone() : null)
.withCookies(cookies != null ? cookies.clone() : null)
.withDelay(getDelay())
.withConnectionOptions(connectionOptions);
}
public HttpResponse update(HttpResponse responseOverride, HttpResponseModifier responseModifier) {
if (responseOverride != null) {
if (responseOverride.getStatusCode() != null) {
withStatusCode(responseOverride.getStatusCode());
}
if (responseOverride.getReasonPhrase() != null) {
withReasonPhrase(responseOverride.getReasonPhrase());
}
for (Header header : responseOverride.getHeaderList()) {
getOrCreateHeaders().replaceEntry(header);
}
for (Cookie cookie : responseOverride.getCookieList()) {
withCookie(cookie);
}
if (responseOverride.getBody() != null) {
withBody(responseOverride.getBody());
}
if (responseOverride.getConnectionOptions() != null) {
withConnectionOptions(responseOverride.getConnectionOptions());
}
this.hashCode = 0;
}
if (responseModifier != null) {
if (responseModifier.getHeaders() != null) {
withHeaders(responseModifier.getHeaders().update(getHeaders()));
}
if (responseModifier.getCookies() != null) {
withCookies(responseModifier.getCookies().update(getCookies()));
}
}
return this;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
if (hashCode() != o.hashCode()) {
return false;
}
if (!super.equals(o)) {
return false;
}
HttpResponse that = (HttpResponse) o;
return Objects.equals(statusCode, that.statusCode) &&
Objects.equals(reasonPhrase, that.reasonPhrase) &&
Objects.equals(body, that.body) &&
Objects.equals(headers, that.headers) &&
Objects.equals(cookies, that.cookies) &&
Objects.equals(connectionOptions, that.connectionOptions);
}
@Override
public int hashCode() {
if (hashCode == 0) {
hashCode = Objects.hash(super.hashCode(), statusCode, reasonPhrase, body, headers, cookies, connectionOptions);
}
return hashCode;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy