package org.mockserver.codec;
import com.google.common.base.Charsets;
import com.google.common.net.MediaType;
import io.netty.buffer.Unpooled;
import io.netty.handler.codec.http.*;
import io.netty.util.CharsetUtil;
import org.hamcrest.core.Is;
import org.junit.Before;
import org.junit.Test;
import org.mockserver.mappers.ContentTypeMapper;
import org.mockserver.model.*;
import org.mockserver.model.Cookie;
import org.mockserver.model.HttpRequest;
import java.util.ArrayList;
import java.util.List;
import static io.netty.handler.codec.http.HttpHeaderNames.CONTENT_TYPE;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.core.Is.is;
import static org.mockserver.model.BinaryBody.binary;
import static org.mockserver.model.Cookie.cookie;
import static org.mockserver.model.Header.header;
import static org.mockserver.model.NottableString.string;
import static org.mockserver.model.Parameter.param;
import static org.mockserver.model.StringBody.exact;
/**
* @author jamesdbloom
*/
public class MockServerRequestDecoderTest {
private MockServerRequestDecoder mockServerRequestDecoder;
private List<Object> output;
private FullHttpRequest fullHttpRequest;
@Before
public void setupFixture() {
mockServerRequestDecoder = new MockServerRequestDecoder(false);
output = new ArrayList<Object>();
}
@Test
public void shouldDecodeMethod() {
// given
fullHttpRequest = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.OPTIONS, "/uri");
// when
mockServerRequestDecoder.decode(null, fullHttpRequest, output);
// then
NottableString method = ((HttpRequest) output.get(0)).getMethod();
assertThat(method, is(string("OPTIONS")));
}
@Test
public void shouldDecodeQueryParameters() {
// given
String uri = "/uri?" +
"queryStringParameterNameOne=queryStringParameterValueOne_One&" +
"queryStringParameterNameOne=queryStringParameterValueOne_Two&" +
"queryStringParameterNameTwo=queryStringParameterValueTwo_One";
fullHttpRequest = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, uri);
// when
mockServerRequestDecoder.decode(null, fullHttpRequest, output);
// then
List<Parameter> queryStringParameters = ((HttpRequest) output.get(0)).getQueryStringParameters();
assertThat(queryStringParameters, containsInAnyOrder(
param("queryStringParameterNameOne", "queryStringParameterValueOne_One", "queryStringParameterValueOne_Two"),
param("queryStringParameterNameTwo", "queryStringParameterValueTwo_One")
));
}
@Test
public void shouldDecodePath() {
// given
fullHttpRequest = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, "/uri");
// when
mockServerRequestDecoder.decode(null, fullHttpRequest, output);
// then
HttpRequest httpRequest = ((HttpRequest) output.get(0));
assertThat(httpRequest.getPath(), is(string("/uri")));
}
@Test
public void shouldDecodeHeaders() {
// given
fullHttpRequest = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, "/uri");
fullHttpRequest.headers().add("headerName1", "headerValue1_1");
fullHttpRequest.headers().add("headerName1", "headerValue1_2");
fullHttpRequest.headers().add("headerName2", "headerValue2");
// when
mockServerRequestDecoder.decode(null, fullHttpRequest, output);
// then
List<Header> headers = ((HttpRequest) output.get(0)).getHeaders();
assertThat(headers, containsInAnyOrder(
header("headerName1", "headerValue1_1", "headerValue1_2"),
header("headerName2", "headerValue2")
));
}
@Test
public void shouldDecodeIsKeepAlive() {
// given
fullHttpRequest = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, "/uri");
fullHttpRequest.headers().add("Connection", "keep-alive");
// when
mockServerRequestDecoder.decode(null, fullHttpRequest, output);
// then
HttpRequest httpRequest = (HttpRequest) output.get(0);
assertThat(httpRequest.isKeepAlive(), is(true));
}
@Test
public void shouldDecodeIsNotKeepAlive() {
// given
fullHttpRequest = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, "/uri");
fullHttpRequest.headers().add("Connection", "close");
// when
mockServerRequestDecoder.decode(null, fullHttpRequest, output);
// then
HttpRequest httpRequest = (HttpRequest) output.get(0);
assertThat(httpRequest.isKeepAlive(), is(false));
}
@Test
public void shouldDecodeCookies() {
// given
fullHttpRequest = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, "/uri");
fullHttpRequest.headers().add("Cookie", "cookieName1=cookieValue1 ; cookieName2=cookieValue2; ");
fullHttpRequest.headers().add("Cookie", "cookieName3 =cookieValue3 ;");
// when
mockServerRequestDecoder.decode(null, fullHttpRequest, output);
// then
List<Cookie> cookies = ((HttpRequest) output.get(0)).getCookies();
assertThat(cookies, containsInAnyOrder(
cookie("cookieName1", "cookieValue1 "),
cookie("cookieName2", "cookieValue2"),
cookie("cookieName3", "cookieValue3 ")
));
}
@Test
public void shouldDecodeCookiesWithEmbeddedEquals() {
// given
fullHttpRequest = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, "/uri");
fullHttpRequest.headers().add("Cookie", "cookieName1=cookie=Value1 ; cookieName2=cookie==Value2; ");
// when
mockServerRequestDecoder.decode(null, fullHttpRequest, output);
// then
List<Cookie> cookies = ((HttpRequest) output.get(0)).getCookies();
assertThat(cookies, containsInAnyOrder(
cookie("cookieName1", "cookie=Value1 "),
cookie("cookieName2", "cookie==Value2")
));
}
/*
* Test is significant because popular Java REST library Jersey adds $Version=1 to all cookies
* in line with RFC2965's recommendation (even though RFC2965 is now marked "Obsolete" by
* RFC6265, this is still common and not hard to handle).
*/
@Test
public void shouldDecodeCookiesWithRFC2965StyleAttributes() {
// given
fullHttpRequest = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, "/uri");
fullHttpRequest.headers().add("Cookie", "$Version=1; Customer=WILE_E_COYOTE; $Path=/acme");
// when
mockServerRequestDecoder.decode(null, fullHttpRequest, output);
// then
List<Cookie> cookies = ((HttpRequest) output.get(0)).getCookies();
assertThat(cookies, containsInAnyOrder(
cookie("Customer", "WILE_E_COYOTE")
));
}
@Test
public void shouldDecodeBodyWithContentTypeAndNoCharset() {
// given
fullHttpRequest = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, "/uri", Unpooled.wrappedBuffer("A normal string with ASCII characters".getBytes(ContentTypeMapper.DEFAULT_HTTP_CHARACTER_SET)));
fullHttpRequest.headers().add(CONTENT_TYPE, MediaType.create("text", "plain").toString());
// when
mockServerRequestDecoder.decode(null, fullHttpRequest, output);
// then
Body body = ((HttpRequest) output.get(0)).getBody();
assertThat(body, Is.<Body>is(exact("A normal string with ASCII characters", CharsetUtil.UTF_8)));
}
@Test
public void shouldDecodeBodyWithNoContentType() {
// given
fullHttpRequest = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, "/uri", Unpooled.wrappedBuffer("A normal string with ASCII characters".getBytes(ContentTypeMapper.DEFAULT_HTTP_CHARACTER_SET)));
// when
mockServerRequestDecoder.decode(null, fullHttpRequest, output);
// then
Body body = ((HttpRequest) output.get(0)).getBody();
assertThat(body, Is.<Body>is(exact("A normal string with ASCII characters")));
}
@Test
public void shouldTransmitUnencodableCharacters() {
// given
fullHttpRequest = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, "/uri", Unpooled.wrappedBuffer("Euro sign: \u20AC".getBytes(ContentTypeMapper.DEFAULT_HTTP_CHARACTER_SET)));
fullHttpRequest.headers().add(CONTENT_TYPE, MediaType.create("text", "plain").toString());
// when
mockServerRequestDecoder.decode(null, fullHttpRequest, output);
// then
Body body = ((HttpRequest) output.get(0)).getBody();
assertThat(body.getRawBytes(), is("Euro sign: \u20AC".getBytes(ContentTypeMapper.DEFAULT_HTTP_CHARACTER_SET)));
assertThat((String)body.getValue(), is(new String("Euro sign: \u20AC".getBytes(ContentTypeMapper.DEFAULT_HTTP_CHARACTER_SET), ContentTypeMapper.DEFAULT_HTTP_CHARACTER_SET)));
}
@Test
public void shouldUseDefaultCharsetIfCharsetNotSupported() {
// given
fullHttpRequest = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, "/uri", Unpooled.wrappedBuffer("A normal string with ASCII characters".getBytes(ContentTypeMapper.DEFAULT_HTTP_CHARACTER_SET)));
fullHttpRequest.headers().add(CONTENT_TYPE, "plain/text; charset=invalid-charset");
// when
mockServerRequestDecoder.decode(null, fullHttpRequest, output);
// then
Body body = ((HttpRequest) output.get(0)).getBody();
assertThat(body, Is.<Body>is(exact("A normal string with ASCII characters")));
}
@Test
public void shouldDecodeBodyWithUTF8ContentType() {
// given
fullHttpRequest = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, "/uri", Unpooled.wrappedBuffer("avro işarəsi: \u20AC".getBytes(Charsets.UTF_8)));
fullHttpRequest.headers().add(CONTENT_TYPE, MediaType.PLAIN_TEXT_UTF_8.toString());
// when
mockServerRequestDecoder.decode(null, fullHttpRequest, output);
// then
Body body = ((HttpRequest) output.get(0)).getBody();
assertThat(body, Is.<Body>is(exact("avro işarəsi: \u20AC", Charsets.UTF_8)));
}
@Test
public void shouldDecodeBodyWithUTF16ContentType() {
// given
fullHttpRequest = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, "/uri", Unpooled.wrappedBuffer("我说中国话".getBytes(Charsets.UTF_16)));
fullHttpRequest.headers().add(CONTENT_TYPE, MediaType.create("text", "plain").withCharset(Charsets.UTF_16).toString());
// when
mockServerRequestDecoder.decode(null, fullHttpRequest, output);
// then
Body body = ((HttpRequest) output.get(0)).getBody();
assertThat(body, Is.<Body>is(exact("我说中国话", Charsets.UTF_16)));
}
@Test
public void shouldDecodeBinaryBody() {
// given
fullHttpRequest = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, "/uri", Unpooled.wrappedBuffer("some_random_bytes".getBytes()));
fullHttpRequest.headers().add(CONTENT_TYPE, MediaType.JPEG);
// when
mockServerRequestDecoder.decode(null, fullHttpRequest, output);
// then
Body body = ((HttpRequest) output.get(0)).getBody();
assertThat(body, Is.<Body>is(binary("some_random_bytes".getBytes())));
}
}