clean up double/triple encoding mess
This commit is contained in:
parent
6680d54868
commit
3b5001dbcc
18 changed files with 154 additions and 108 deletions
|
@ -1,6 +1,6 @@
|
||||||
group = org.xbib
|
group = org.xbib
|
||||||
name = netty-http
|
name = netty-http
|
||||||
version = 4.1.63.1
|
version = 4.1.63.2
|
||||||
|
|
||||||
gradle.wrapper.version = 6.6.1
|
gradle.wrapper.version = 6.6.1
|
||||||
netty.version = 4.1.63.Final
|
netty.version = 4.1.63.Final
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
|
|
||||||
def junitVersion = project.hasProperty('junit.version')?project.property('junit.version'):'5.6.2'
|
def junitVersion = project.hasProperty('junit.version')?project.property('junit.version'):'5.7.1'
|
||||||
def hamcrestVersion = project.hasProperty('hamcrest.version')?project.property('hamcrest.version'):'2.2'
|
def hamcrestVersion = project.hasProperty('hamcrest.version')?project.property('hamcrest.version'):'2.2'
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
@ -12,6 +12,7 @@ dependencies {
|
||||||
test {
|
test {
|
||||||
useJUnitPlatform()
|
useJUnitPlatform()
|
||||||
failFast = true
|
failFast = true
|
||||||
|
systemProperty 'java.util.logging.config.file', 'src/test/resources/logging.properties'
|
||||||
testLogging {
|
testLogging {
|
||||||
events 'STARTED', 'PASSED', 'FAILED', 'SKIPPED'
|
events 'STARTED', 'PASSED', 'FAILED', 'SKIPPED'
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,5 +2,9 @@ module org.xbib.netty.http.client.api {
|
||||||
exports org.xbib.netty.http.client.api;
|
exports org.xbib.netty.http.client.api;
|
||||||
requires org.xbib.netty.http.common;
|
requires org.xbib.netty.http.common;
|
||||||
requires org.xbib.net.url;
|
requires org.xbib.net.url;
|
||||||
|
requires io.netty.buffer;
|
||||||
|
requires io.netty.common;
|
||||||
requires io.netty.transport;
|
requires io.netty.transport;
|
||||||
|
requires io.netty.codec.http;
|
||||||
|
requires io.netty.codec.http2;
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,18 +14,14 @@ import io.netty.handler.codec.http.HttpVersion;
|
||||||
import io.netty.handler.codec.http.multipart.InterfaceHttpData;
|
import io.netty.handler.codec.http.multipart.InterfaceHttpData;
|
||||||
import io.netty.handler.codec.http2.HttpConversionUtil;
|
import io.netty.handler.codec.http2.HttpConversionUtil;
|
||||||
import io.netty.util.AsciiString;
|
import io.netty.util.AsciiString;
|
||||||
import org.xbib.net.PercentEncoder;
|
|
||||||
import org.xbib.net.PercentEncoders;
|
|
||||||
import org.xbib.net.URL;
|
import org.xbib.net.URL;
|
||||||
import org.xbib.netty.http.common.HttpAddress;
|
import org.xbib.netty.http.common.HttpAddress;
|
||||||
import org.xbib.netty.http.common.HttpParameters;
|
|
||||||
import org.xbib.netty.http.common.HttpResponse;
|
import org.xbib.netty.http.common.HttpResponse;
|
||||||
import org.xbib.netty.http.common.cookie.Cookie;
|
import org.xbib.netty.http.common.cookie.Cookie;
|
||||||
|
import org.xbib.netty.http.common.util.CaseInsensitiveParameters;
|
||||||
|
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
import java.nio.charset.MalformedInputException;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.nio.charset.UnmappableCharacterException;
|
|
||||||
import java.time.ZoneOffset;
|
import java.time.ZoneOffset;
|
||||||
import java.time.ZonedDateTime;
|
import java.time.ZonedDateTime;
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
|
@ -34,6 +30,7 @@ import java.util.Base64;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
@ -285,8 +282,6 @@ public final class Request {
|
||||||
|
|
||||||
private final Collection<Cookie> cookies;
|
private final Collection<Cookie> cookies;
|
||||||
|
|
||||||
private PercentEncoder encoder;
|
|
||||||
|
|
||||||
private HttpMethod httpMethod;
|
private HttpMethod httpMethod;
|
||||||
|
|
||||||
private HttpHeaders headers;
|
private HttpHeaders headers;
|
||||||
|
@ -303,13 +298,13 @@ public final class Request {
|
||||||
|
|
||||||
private CharSequence contentType;
|
private CharSequence contentType;
|
||||||
|
|
||||||
private HttpParameters uriParameters;
|
private final CaseInsensitiveParameters uriParameters;
|
||||||
|
|
||||||
private HttpParameters formParameters;
|
private final CaseInsensitiveParameters formParameters;
|
||||||
|
|
||||||
private ByteBuf content;
|
private ByteBuf content;
|
||||||
|
|
||||||
private List<InterfaceHttpData> bodyData;
|
private final List<InterfaceHttpData> bodyData;
|
||||||
|
|
||||||
private long timeoutInMillis;
|
private long timeoutInMillis;
|
||||||
|
|
||||||
|
@ -338,14 +333,9 @@ public final class Request {
|
||||||
this.removeHeaders = new ArrayList<>();
|
this.removeHeaders = new ArrayList<>();
|
||||||
this.cookies = new HashSet<>();
|
this.cookies = new HashSet<>();
|
||||||
this.bodyData = new ArrayList<>();
|
this.bodyData = new ArrayList<>();
|
||||||
charset(StandardCharsets.UTF_8);
|
this.contentType = DEFAULT_FORM_CONTENT_TYPE;
|
||||||
}
|
this.formParameters = new CaseInsensitiveParameters();
|
||||||
|
this.uriParameters = new CaseInsensitiveParameters();
|
||||||
public Builder charset(Charset charset) {
|
|
||||||
this.encoder = PercentEncoders.getQueryEncoder(charset);
|
|
||||||
this.formParameters = new HttpParameters(DEFAULT_FORM_CONTENT_TYPE);
|
|
||||||
this.uriParameters = new HttpParameters(DEFAULT_FORM_CONTENT_TYPE);
|
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Builder setMethod(HttpMethod httpMethod) {
|
public Builder setMethod(HttpMethod httpMethod) {
|
||||||
|
@ -433,7 +423,6 @@ public final class Request {
|
||||||
Objects.requireNonNull(contentType);
|
Objects.requireNonNull(contentType);
|
||||||
Objects.requireNonNull(charset);
|
Objects.requireNonNull(charset);
|
||||||
this.contentType = contentType;
|
this.contentType = contentType;
|
||||||
charset(charset);
|
|
||||||
addHeader(HttpHeaderNames.CONTENT_TYPE, contentType + "; charset=" + charset.name().toLowerCase());
|
addHeader(HttpHeaderNames.CONTENT_TYPE, contentType + "; charset=" + charset.name().toLowerCase());
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
@ -453,29 +442,28 @@ public final class Request {
|
||||||
} else {
|
} else {
|
||||||
collection = (Collection<Object>) value;
|
collection = (Collection<Object>) value;
|
||||||
}
|
}
|
||||||
String k = encode(contentType, name);
|
collection.forEach(v -> uriParameters.add(name, v.toString()));
|
||||||
collection.forEach(v -> uriParameters.addRaw(k, encode(contentType, v.toString())));
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Builder addRawParameter(String name, String value) {
|
public Builder addRawParameter(String name, String value) {
|
||||||
Objects.requireNonNull(name);
|
Objects.requireNonNull(name);
|
||||||
Objects.requireNonNull(value);
|
Objects.requireNonNull(value);
|
||||||
uriParameters.addRaw(name, value);
|
uriParameters.add(name, value);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Builder addFormParameter(String name, String value) {
|
public Builder addFormParameter(String name, String value) {
|
||||||
Objects.requireNonNull(name);
|
Objects.requireNonNull(name);
|
||||||
Objects.requireNonNull(value);
|
Objects.requireNonNull(value);
|
||||||
formParameters.addRaw(encode(contentType, name), encode(contentType, value));
|
formParameters.add(name, value);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Builder addRawFormParameter(String name, String value) {
|
public Builder addRawFormParameter(String name, String value) {
|
||||||
Objects.requireNonNull(name);
|
Objects.requireNonNull(name);
|
||||||
Objects.requireNonNull(value);
|
Objects.requireNonNull(value);
|
||||||
formParameters.addRaw(name, value);
|
formParameters.add(name, value);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -490,23 +478,6 @@ public final class Request {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String encode(CharSequence contentType, String value) {
|
|
||||||
if (value == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
String encodedValue = encoder.encode(value);
|
|
||||||
// https://www.w3.org/TR/html4/interact/forms.html#h-17.13.4
|
|
||||||
if (HttpHeaderValues.APPLICATION_X_WWW_FORM_URLENCODED.equals(contentType)) {
|
|
||||||
encodedValue = encodedValue.replace("%20", "+");
|
|
||||||
}
|
|
||||||
return encodedValue;
|
|
||||||
} catch (MalformedInputException | UnmappableCharacterException e) {
|
|
||||||
// should never be reached because encoder does not bail out on error
|
|
||||||
throw new IllegalArgumentException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Builder addCookie(Cookie cookie) {
|
public Builder addCookie(Cookie cookie) {
|
||||||
cookies.add(cookie);
|
cookies.add(cookie);
|
||||||
return this;
|
return this;
|
||||||
|
@ -610,7 +581,7 @@ public final class Request {
|
||||||
// add our URI parameters to the URL
|
// add our URI parameters to the URL
|
||||||
URL.Builder mutator = url.mutator();
|
URL.Builder mutator = url.mutator();
|
||||||
uriParameters.forEach(e -> mutator.queryParam(e.getKey(), e.getValue()));
|
uriParameters.forEach(e -> mutator.queryParam(e.getKey(), e.getValue()));
|
||||||
// calling build() performs percent encoding
|
// calling build() performs extra percent encoding!
|
||||||
url = mutator.build();
|
url = mutator.build();
|
||||||
String scheme = url.getScheme();
|
String scheme = url.getScheme();
|
||||||
if (httpVersion.majorVersion() == 2) {
|
if (httpVersion.majorVersion() == 2) {
|
||||||
|
@ -626,12 +597,7 @@ public final class Request {
|
||||||
validatedHeaders.set(HttpHeaderNames.ACCEPT_ENCODING, "gzip");
|
validatedHeaders.set(HttpHeaderNames.ACCEPT_ENCODING, "gzip");
|
||||||
}
|
}
|
||||||
if (!formParameters.isEmpty()) {
|
if (!formParameters.isEmpty()) {
|
||||||
try {
|
content(getAsQueryString(formParameters), contentType);
|
||||||
// form parameters are already percent encoded
|
|
||||||
content(formParameters.getAsQueryString(false), formParameters.getContentType());
|
|
||||||
} catch (MalformedInputException | UnmappableCharacterException e) {
|
|
||||||
throw new IllegalArgumentException();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
int length = content != null ? content.readableBytes() : 0;
|
int length = content != null ? content.readableBytes() : 0;
|
||||||
if (!validatedHeaders.contains(HttpHeaderNames.CONTENT_LENGTH) && !validatedHeaders.contains(HttpHeaderNames.TRANSFER_ENCODING)) {
|
if (!validatedHeaders.contains(HttpHeaderNames.CONTENT_LENGTH) && !validatedHeaders.contains(HttpHeaderNames.TRANSFER_ENCODING)) {
|
||||||
|
@ -674,5 +640,30 @@ public final class Request {
|
||||||
addHeader(HttpHeaderNames.CONTENT_LENGTH, (long) body.readableBytes());
|
addHeader(HttpHeaderNames.CONTENT_LENGTH, (long) body.readableBytes());
|
||||||
addHeader(HttpHeaderNames.CONTENT_TYPE, contentType);
|
addHeader(HttpHeaderNames.CONTENT_TYPE, contentType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String getAsQueryString(CaseInsensitiveParameters parameters) {
|
||||||
|
List<String> list = new ArrayList<>();
|
||||||
|
for (String key : parameters.names()) {
|
||||||
|
list.add(getAsQueryString(parameters, key));
|
||||||
|
}
|
||||||
|
return String.join("&", list);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getAsQueryString(CaseInsensitiveParameters parameters, String key) {
|
||||||
|
Collection<String> values = parameters.getAll(key);
|
||||||
|
if (values == null) {
|
||||||
|
return key + '=';
|
||||||
|
}
|
||||||
|
Iterator<String> it = values.iterator();
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
while (it.hasNext()) {
|
||||||
|
String v = it.next();
|
||||||
|
sb.append(key).append('=').append(v);
|
||||||
|
if (it.hasNext()) {
|
||||||
|
sb.append('&');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,13 +63,36 @@ class RequestBuilderTest {
|
||||||
assertEquals("http://xbib.org?param1=value1¶m2=value2", request.url().toString());
|
assertEquals("http://xbib.org?param1=value1¶m2=value2", request.url().toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testGetRequestWithPercent() {
|
||||||
|
Request request = Request.builder(HttpMethod.GET)
|
||||||
|
.url("http://xbib.org")
|
||||||
|
.addParameter("param1", "value1")
|
||||||
|
.addParameter("param2", "value%")
|
||||||
|
.build();
|
||||||
|
assertEquals("?param1=value1¶m2=value%25", request.relative());
|
||||||
|
assertEquals("http://xbib.org?param1=value1¶m2=value%25", request.url().toExternalForm());
|
||||||
|
assertEquals("http://xbib.org?param1=value1¶m2=value%", request.url().toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testGetRequestWithSpaces() {
|
||||||
|
Request request = Request.builder(HttpMethod.GET)
|
||||||
|
.url("http://xbib.org")
|
||||||
|
.addParameter(" param1 ", " value1 ")
|
||||||
|
.addParameter(" param2 ", " value2 ")
|
||||||
|
.build();
|
||||||
|
assertEquals("?%20param1%20=%20value1%20&%20param2%20=%20value2%20", request.relative());
|
||||||
|
assertEquals("http://xbib.org?%20param1%20=%20value1%20&%20param2%20=%20value2%20", request.url().toExternalForm());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testBasicPostRequest() {
|
void testBasicPostRequest() {
|
||||||
Request request = Request.builder(HttpMethod.POST)
|
Request request = Request.builder(HttpMethod.POST)
|
||||||
.url("http://xbib.org")
|
.url("http://xbib.org")
|
||||||
.addParameter("param1", "value1")
|
.addParameter("param1", "value1")
|
||||||
.addParameter("param2", "value2")
|
.addParameter("param2", "value2")
|
||||||
.content("a=b&c=d", "application/x-www-form-urldencoded")
|
.content("a=b&c=d", "application/x-www-form-urlencoded")
|
||||||
.build();
|
.build();
|
||||||
assertEquals("xbib.org", request.url().getHost());
|
assertEquals("xbib.org", request.url().getHost());
|
||||||
assertEquals("?param1=value1¶m2=value2", request.relative());
|
assertEquals("?param1=value1¶m2=value2", request.relative());
|
||||||
|
@ -77,6 +100,20 @@ class RequestBuilderTest {
|
||||||
assertEquals("a=b&c=d", request.content().toString(StandardCharsets.UTF_8));
|
assertEquals("a=b&c=d", request.content().toString(StandardCharsets.UTF_8));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testFormRequest() {
|
||||||
|
Request request = Request.builder(HttpMethod.POST)
|
||||||
|
.url("http://xbib.org")
|
||||||
|
.addParameter("param1", "value1")
|
||||||
|
.addParameter("param2", "value%")
|
||||||
|
.content("a=b&c=%", "application/x-www-form-urlencoded")
|
||||||
|
.build();
|
||||||
|
assertEquals("xbib.org", request.url().getHost());
|
||||||
|
assertEquals("?param1=value1¶m2=value%25", request.relative());
|
||||||
|
assertEquals("http://xbib.org?param1=value1¶m2=value%25", request.url().toExternalForm());
|
||||||
|
assertEquals("a=b&c=%", request.content().toString(StandardCharsets.UTF_8));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testRequest() {
|
void testRequest() {
|
||||||
Request request = Request.get()
|
Request request = Request.get()
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package org.xbib.netty.http.client.test.http1;
|
package org.xbib.netty.http.client.test.http1;
|
||||||
|
|
||||||
|
import io.netty.handler.codec.http.HttpHeaderValues;
|
||||||
import io.netty.handler.codec.http.HttpMethod;
|
import io.netty.handler.codec.http.HttpMethod;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
|
@ -9,6 +10,7 @@ import org.xbib.netty.http.client.test.NettyHttpTestExtension;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
@ -28,7 +30,33 @@ class Http1Test {
|
||||||
resp.getBodyAsString(StandardCharsets.UTF_8) +
|
resp.getBodyAsString(StandardCharsets.UTF_8) +
|
||||||
" status=" + resp.getStatus()))
|
" status=" + resp.getStatus()))
|
||||||
.build();
|
.build();
|
||||||
client.execute(request).get();
|
client.execute(request).get().close();
|
||||||
|
} finally {
|
||||||
|
client.shutdownGracefully();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testHttpGetRequest() throws Exception {
|
||||||
|
Client client = Client.builder()
|
||||||
|
.enableDebug()
|
||||||
|
.build();
|
||||||
|
try {
|
||||||
|
Map<String, Object> parameters = Map.of(
|
||||||
|
"version", "1.1",
|
||||||
|
"operation", "searchRetrieve",
|
||||||
|
"recordSchema", "MARC21plus-1-xml",
|
||||||
|
"query", "iss = 00280836"
|
||||||
|
);
|
||||||
|
Request request = Request.post()
|
||||||
|
.url("https://services.dnb.de/sru/zdb")
|
||||||
|
.setParameters(parameters)
|
||||||
|
.setResponseListener(resp -> logger.log(Level.INFO,
|
||||||
|
"got response: " + resp.getHeaders() +
|
||||||
|
resp.getBodyAsString(StandardCharsets.UTF_8) +
|
||||||
|
" status=" + resp.getStatus()))
|
||||||
|
.build();
|
||||||
|
client.execute(request).get().close();
|
||||||
} finally {
|
} finally {
|
||||||
client.shutdownGracefully();
|
client.shutdownGracefully();
|
||||||
}
|
}
|
||||||
|
@ -48,7 +76,7 @@ class Http1Test {
|
||||||
.setResponseListener(resp -> logger.log(Level.FINE, "got response: " +
|
.setResponseListener(resp -> logger.log(Level.FINE, "got response: " +
|
||||||
resp.getBodyAsString(StandardCharsets.UTF_8)))
|
resp.getBodyAsString(StandardCharsets.UTF_8)))
|
||||||
.build();
|
.build();
|
||||||
client.execute(request2).get();
|
client.execute(request2).get().close();
|
||||||
} finally {
|
} finally {
|
||||||
client.shutdownGracefully();
|
client.shutdownGracefully();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
/**
|
|
||||||
* Classes for testing Netty HTTP client.
|
|
||||||
*/
|
|
||||||
package org.xbib.netty.http.client.test;
|
|
8
netty-http-client/src/test/resources/logging.properties
Normal file
8
netty-http-client/src/test/resources/logging.properties
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
handlers=java.util.logging.FileHandler, java.util.logging.ConsoleHandler
|
||||||
|
.level=ALL
|
||||||
|
java.util.logging.SimpleFormatter.format=%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS.%1$tL %4$-7s [%3$s] %5$s %6$s%n
|
||||||
|
java.util.logging.ConsoleHandler.level=ALL
|
||||||
|
java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter
|
||||||
|
java.util.logging.FileHandler.level=ALL
|
||||||
|
java.util.logging.FileHandler.formatter=java.util.logging.SimpleFormatter
|
||||||
|
java.util.logging.FileHandler.pattern=build/test.log
|
|
@ -1,11 +1,9 @@
|
||||||
package org.xbib.netty.http.common;
|
package org.xbib.netty.http.common;
|
||||||
|
|
||||||
import io.netty.handler.codec.http.HttpHeaderValues;
|
import io.netty.handler.codec.http.HttpHeaderValues;
|
||||||
import org.xbib.net.PercentDecoder;
|
|
||||||
import org.xbib.net.PercentEncoder;
|
import org.xbib.net.PercentEncoder;
|
||||||
import org.xbib.net.PercentEncoders;
|
import org.xbib.net.PercentEncoders;
|
||||||
import org.xbib.netty.http.common.util.CaseInsensitiveParameters;
|
import org.xbib.netty.http.common.util.CaseInsensitiveParameters;
|
||||||
import org.xbib.netty.http.common.util.LimitedSet;
|
|
||||||
import java.nio.charset.CharacterCodingException;
|
import java.nio.charset.CharacterCodingException;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
import java.nio.charset.MalformedInputException;
|
import java.nio.charset.MalformedInputException;
|
||||||
|
@ -15,7 +13,6 @@ import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A limited multi-map of HTTP request parameters. Each key references a
|
* A limited multi-map of HTTP request parameters. Each key references a
|
||||||
|
@ -63,7 +60,6 @@ public class HttpParameters extends CaseInsensitiveParameters {
|
||||||
this.sizeLimit = sizeLimit;
|
this.sizeLimit = sizeLimit;
|
||||||
this.elementSizeLimit = elementSizeLimit;
|
this.elementSizeLimit = elementSizeLimit;
|
||||||
this.percentEncoder = PercentEncoders.getQueryEncoder(charset);
|
this.percentEncoder = PercentEncoders.getQueryEncoder(charset);
|
||||||
PercentDecoder percentDecoder = new PercentDecoder();
|
|
||||||
this.contentType = contentType;
|
this.contentType = contentType;
|
||||||
this.encoding = charset;
|
this.encoding = charset;
|
||||||
}
|
}
|
||||||
|
@ -132,30 +128,6 @@ public class HttpParameters extends CaseInsensitiveParameters {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addAll(String[] keyValuePairs, boolean percentEncode) {
|
|
||||||
for (int i = 0; i < keyValuePairs.length - 1; i += 2) {
|
|
||||||
add(keyValuePairs[i], keyValuePairs[i + 1], percentEncode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convenience method to merge a {@code Map<String, List<String>>}.
|
|
||||||
*
|
|
||||||
* @param m the map
|
|
||||||
*/
|
|
||||||
public void addMap(Map<String, List<String>> m) {
|
|
||||||
for (String key : m.keySet()) {
|
|
||||||
Collection<String> vals = getAll(key);
|
|
||||||
if (vals == null) {
|
|
||||||
vals = new LimitedSet<>(sizeLimit, elementSizeLimit);
|
|
||||||
for (String v : vals) {
|
|
||||||
super.add(key, v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
vals.addAll(m.get(key));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getAsQueryString(boolean percentEncode) throws MalformedInputException, UnmappableCharacterException {
|
public String getAsQueryString(boolean percentEncode) throws MalformedInputException, UnmappableCharacterException {
|
||||||
List<String> list = new ArrayList<>();
|
List<String> list = new ArrayList<>();
|
||||||
for (String key : super.names()) {
|
for (String key : super.names()) {
|
||||||
|
|
|
@ -414,7 +414,8 @@ class EndpointTest {
|
||||||
}
|
}
|
||||||
HttpServerDomain domain = HttpServerDomain.builder(httpAddress)
|
HttpServerDomain domain = HttpServerDomain.builder(httpAddress)
|
||||||
.addEndpointResolver(endpointResolverBuilder
|
.addEndpointResolver(endpointResolverBuilder
|
||||||
.setDispatcher((req, resp) -> resp.getBuilder().setStatus(HttpResponseStatus.OK).build().flush())
|
.setDispatcher((req, resp) -> resp.getBuilder()
|
||||||
|
.setStatus(HttpResponseStatus.OK.code()).build().flush())
|
||||||
.build())
|
.build())
|
||||||
.build();
|
.build();
|
||||||
Server server = Server.builder(domain)
|
Server server = Server.builder(domain)
|
||||||
|
@ -455,7 +456,8 @@ class EndpointTest {
|
||||||
for (int i = 0; i < max; i++) {
|
for (int i = 0; i < max; i++) {
|
||||||
domainBuilder.addEndpointResolver(endpointResolverBuilder.addEndpoint(HttpEndpoint.builder()
|
domainBuilder.addEndpointResolver(endpointResolverBuilder.addEndpoint(HttpEndpoint.builder()
|
||||||
.setPath("/" + i + "/**").build())
|
.setPath("/" + i + "/**").build())
|
||||||
.setDispatcher((req, resp) -> resp.getBuilder().setStatus(HttpResponseStatus.OK).build().flush())
|
.setDispatcher((req, resp) -> resp.getBuilder()
|
||||||
|
.setStatus(HttpResponseStatus.OK.code()).build().flush())
|
||||||
.build());
|
.build());
|
||||||
}
|
}
|
||||||
Server server = Server.builder(domainBuilder.build())
|
Server server = Server.builder(domainBuilder.build())
|
||||||
|
|
|
@ -34,7 +34,8 @@ class CleartextTest {
|
||||||
HttpAddress httpAddress = HttpAddress.http1("localhost", 8008);
|
HttpAddress httpAddress = HttpAddress.http1("localhost", 8008);
|
||||||
HttpServerDomain domain = HttpServerDomain.builder(httpAddress)
|
HttpServerDomain domain = HttpServerDomain.builder(httpAddress)
|
||||||
.singleEndpoint("/**", (request, response) ->
|
.singleEndpoint("/**", (request, response) ->
|
||||||
response.getBuilder().setStatus(HttpResponseStatus.OK).setContentType("text/plain").build()
|
response.getBuilder().setStatus(HttpResponseStatus.OK.code())
|
||||||
|
.setContentType("text/plain").build()
|
||||||
.write(request.getContent().toString(StandardCharsets.UTF_8)))
|
.write(request.getContent().toString(StandardCharsets.UTF_8)))
|
||||||
.build();
|
.build();
|
||||||
Server server = Server.builder(domain).build();
|
Server server = Server.builder(domain).build();
|
||||||
|
@ -68,7 +69,8 @@ class CleartextTest {
|
||||||
HttpAddress httpAddress = HttpAddress.http1("localhost", 8008);
|
HttpAddress httpAddress = HttpAddress.http1("localhost", 8008);
|
||||||
HttpServerDomain domain = HttpServerDomain.builder(httpAddress)
|
HttpServerDomain domain = HttpServerDomain.builder(httpAddress)
|
||||||
.singleEndpoint("/**", (request, response) ->
|
.singleEndpoint("/**", (request, response) ->
|
||||||
response.getBuilder().setStatus(HttpResponseStatus.OK).setContentType("text/plain").build()
|
response.getBuilder().setStatus(HttpResponseStatus.OK.code())
|
||||||
|
.setContentType("text/plain").build()
|
||||||
.write(request.getContent().toString(StandardCharsets.UTF_8)))
|
.write(request.getContent().toString(StandardCharsets.UTF_8)))
|
||||||
.build();
|
.build();
|
||||||
Server server = Server.builder(domain).build();
|
Server server = Server.builder(domain).build();
|
||||||
|
@ -113,7 +115,8 @@ class CleartextTest {
|
||||||
HttpAddress httpAddress = HttpAddress.http1("localhost", 8008);
|
HttpAddress httpAddress = HttpAddress.http1("localhost", 8008);
|
||||||
HttpServerDomain domain = HttpServerDomain.builder(httpAddress)
|
HttpServerDomain domain = HttpServerDomain.builder(httpAddress)
|
||||||
.singleEndpoint("/**", (request, response) ->
|
.singleEndpoint("/**", (request, response) ->
|
||||||
response.getBuilder().setStatus(HttpResponseStatus.OK).setContentType("text/plain").build()
|
response.getBuilder().setStatus(HttpResponseStatus.OK.code())
|
||||||
|
.setContentType("text/plain").build()
|
||||||
.write(request.getContent().toString(StandardCharsets.UTF_8)))
|
.write(request.getContent().toString(StandardCharsets.UTF_8)))
|
||||||
.build();
|
.build();
|
||||||
Server server = Server.builder(domain).build();
|
Server server = Server.builder(domain).build();
|
||||||
|
|
|
@ -35,7 +35,8 @@ class EncryptedTest {
|
||||||
Server server = Server.builder(HttpServerDomain.builder(httpAddress)
|
Server server = Server.builder(HttpServerDomain.builder(httpAddress)
|
||||||
.setSelfCert()
|
.setSelfCert()
|
||||||
.singleEndpoint("/", (request, response) ->
|
.singleEndpoint("/", (request, response) ->
|
||||||
response.getBuilder().setStatus(HttpResponseStatus.OK).setContentType("text/plain").build()
|
response.getBuilder().setStatus(HttpResponseStatus.OK.code())
|
||||||
|
.setContentType("text/plain").build()
|
||||||
.write(request.getContent().retain()))
|
.write(request.getContent().retain()))
|
||||||
.build())
|
.build())
|
||||||
.build();
|
.build();
|
||||||
|
@ -65,7 +66,8 @@ class EncryptedTest {
|
||||||
Server server = Server.builder(HttpServerDomain.builder(httpAddress)
|
Server server = Server.builder(HttpServerDomain.builder(httpAddress)
|
||||||
.setSelfCert()
|
.setSelfCert()
|
||||||
.singleEndpoint("/", (request, response) ->
|
.singleEndpoint("/", (request, response) ->
|
||||||
response.getBuilder().setStatus(HttpResponseStatus.OK).setContentType("text/plain").build()
|
response.getBuilder().setStatus(HttpResponseStatus.OK.code())
|
||||||
|
.setContentType("text/plain").build()
|
||||||
.write(request.getContent().toString(StandardCharsets.UTF_8)))
|
.write(request.getContent().toString(StandardCharsets.UTF_8)))
|
||||||
.build())
|
.build())
|
||||||
.build();
|
.build();
|
||||||
|
@ -108,7 +110,8 @@ class EncryptedTest {
|
||||||
Server server = Server.builder(HttpServerDomain.builder(httpAddress)
|
Server server = Server.builder(HttpServerDomain.builder(httpAddress)
|
||||||
.setSelfCert()
|
.setSelfCert()
|
||||||
.singleEndpoint("/", (request, response) ->
|
.singleEndpoint("/", (request, response) ->
|
||||||
response.getBuilder().setStatus(HttpResponseStatus.OK).setContentType("text/plain").build()
|
response.getBuilder().setStatus(HttpResponseStatus.OK.code())
|
||||||
|
.setContentType("text/plain").build()
|
||||||
.write(request.getContent().toString(StandardCharsets.UTF_8)))
|
.write(request.getContent().toString(StandardCharsets.UTF_8)))
|
||||||
.build())
|
.build())
|
||||||
.build();
|
.build();
|
||||||
|
|
|
@ -37,7 +37,8 @@ class FlushTest {
|
||||||
.singleEndpoint("/flush", "/**", (req, resp) -> {
|
.singleEndpoint("/flush", "/**", (req, resp) -> {
|
||||||
HttpParameters parameters = req.getParameters();
|
HttpParameters parameters = req.getParameters();
|
||||||
logger.log(Level.INFO, "got request " + parameters.toString() + ", sending 302 Found");
|
logger.log(Level.INFO, "got request " + parameters.toString() + ", sending 302 Found");
|
||||||
resp.getBuilder().setStatus(HttpResponseStatus.FOUND).build().flush();
|
resp.getBuilder().setStatus(HttpResponseStatus.FOUND.code())
|
||||||
|
.build().flush();
|
||||||
})
|
})
|
||||||
.build();
|
.build();
|
||||||
Server server = Server.builder(domain)
|
Server server = Server.builder(domain)
|
||||||
|
|
|
@ -38,7 +38,7 @@ class MimeUploadTest {
|
||||||
logger.log(Level.INFO, "got request, headers = " + req.getHeaders() +
|
logger.log(Level.INFO, "got request, headers = " + req.getHeaders() +
|
||||||
" params = " + parameters.toString() +
|
" params = " + parameters.toString() +
|
||||||
" body = " + req.getContent().toString(StandardCharsets.UTF_8));
|
" body = " + req.getContent().toString(StandardCharsets.UTF_8));
|
||||||
resp.getBuilder().setStatus(HttpResponseStatus.OK).build().flush();
|
resp.getBuilder().setStatus(HttpResponseStatus.OK.code()).build().flush();
|
||||||
}, "POST")
|
}, "POST")
|
||||||
.build();
|
.build();
|
||||||
Server server = Server.builder(domain)
|
Server server = Server.builder(domain)
|
||||||
|
|
|
@ -41,7 +41,7 @@ class PostTest {
|
||||||
if ("Jörg".equals(parameters.get("name"))) {
|
if ("Jörg".equals(parameters.get("name"))) {
|
||||||
success3.set(true);
|
success3.set(true);
|
||||||
}
|
}
|
||||||
resp.getBuilder().setStatus(HttpResponseStatus.OK).build().flush();
|
resp.getBuilder().setStatus(HttpResponseStatus.OK.code()).build().flush();
|
||||||
}, "POST")
|
}, "POST")
|
||||||
.build();
|
.build();
|
||||||
Server server = Server.builder(domain)
|
Server server = Server.builder(domain)
|
||||||
|
@ -91,7 +91,7 @@ class PostTest {
|
||||||
if ("Jörg".equals(parameters.get("name"))) {
|
if ("Jörg".equals(parameters.get("name"))) {
|
||||||
success3.set(true);
|
success3.set(true);
|
||||||
}
|
}
|
||||||
resp.getBuilder().setStatus(HttpResponseStatus.OK).build().flush();
|
resp.getBuilder().setStatus(HttpResponseStatus.OK.code()).build().flush();
|
||||||
}, "POST")
|
}, "POST")
|
||||||
.build();
|
.build();
|
||||||
Server server = Server.builder(domain)
|
Server server = Server.builder(domain)
|
||||||
|
@ -145,7 +145,7 @@ class PostTest {
|
||||||
if ("my value".equals(parameters.get("my param"))) {
|
if ("my value".equals(parameters.get("my param"))) {
|
||||||
success4.set(true);
|
success4.set(true);
|
||||||
}
|
}
|
||||||
resp.getBuilder().setStatus(HttpResponseStatus.OK).build().flush();
|
resp.getBuilder().setStatus(HttpResponseStatus.OK.code()).build().flush();
|
||||||
}, "POST")
|
}, "POST")
|
||||||
.build();
|
.build();
|
||||||
Server server = Server.builder(domain)
|
Server server = Server.builder(domain)
|
||||||
|
@ -202,7 +202,7 @@ class PostTest {
|
||||||
if ("my value".equals(parameters.get("my param"))) {
|
if ("my value".equals(parameters.get("my param"))) {
|
||||||
success4.set(true);
|
success4.set(true);
|
||||||
}
|
}
|
||||||
resp.getBuilder().setStatus(HttpResponseStatus.OK).build().flush();
|
resp.getBuilder().setStatus(HttpResponseStatus.OK.code()).build().flush();
|
||||||
}, "POST")
|
}, "POST")
|
||||||
.build();
|
.build();
|
||||||
Server server = Server.builder(domain)
|
Server server = Server.builder(domain)
|
||||||
|
@ -256,7 +256,7 @@ class PostTest {
|
||||||
if ("bÿc".equals(parameters.get("a"))) {
|
if ("bÿc".equals(parameters.get("a"))) {
|
||||||
success2.set(true);
|
success2.set(true);
|
||||||
}
|
}
|
||||||
resp.getBuilder().setStatus(HttpResponseStatus.OK).build().flush();
|
resp.getBuilder().setStatus(HttpResponseStatus.OK.code()).build().flush();
|
||||||
}, "POST")
|
}, "POST")
|
||||||
.build();
|
.build();
|
||||||
Server server = Server.builder(domain)
|
Server server = Server.builder(domain)
|
||||||
|
|
|
@ -36,7 +36,7 @@ class PutTest {
|
||||||
.singleEndpoint("/put", "/**", (req, resp) -> {
|
.singleEndpoint("/put", "/**", (req, resp) -> {
|
||||||
logger.log(Level.INFO, "got request " +
|
logger.log(Level.INFO, "got request " +
|
||||||
req.getContent().toString(StandardCharsets.UTF_8));
|
req.getContent().toString(StandardCharsets.UTF_8));
|
||||||
resp.getBuilder().setStatus(HttpResponseStatus.OK).build().flush();
|
resp.getBuilder().setStatus(HttpResponseStatus.OK.code()).build().flush();
|
||||||
success1.set(true);
|
success1.set(true);
|
||||||
}, "PUT")
|
}, "PUT")
|
||||||
.build();
|
.build();
|
||||||
|
@ -84,7 +84,7 @@ class PutTest {
|
||||||
.singleEndpoint("/put", "/**", (req, resp) -> {
|
.singleEndpoint("/put", "/**", (req, resp) -> {
|
||||||
logger.log(Level.INFO, "got request, length = " +
|
logger.log(Level.INFO, "got request, length = " +
|
||||||
req.getContent().readableBytes());
|
req.getContent().readableBytes());
|
||||||
resp.getBuilder().setStatus(HttpResponseStatus.OK).build().flush();
|
resp.getBuilder().setStatus(HttpResponseStatus.OK.code()).build().flush();
|
||||||
success1.set(true);
|
success1.set(true);
|
||||||
}, "PUT")
|
}, "PUT")
|
||||||
.build();
|
.build();
|
||||||
|
|
|
@ -31,7 +31,7 @@ class StreamTest {
|
||||||
assertEquals("my body parameter", content);
|
assertEquals("my body parameter", content);
|
||||||
ByteBufOutputStream outputStream = response.getOutputStream();
|
ByteBufOutputStream outputStream = response.getOutputStream();
|
||||||
outputStream.writeBytes("Hello World");
|
outputStream.writeBytes("Hello World");
|
||||||
response.getBuilder().setStatus(HttpResponseStatus.OK).setContentType("text/plain").build()
|
response.getBuilder().setStatus(HttpResponseStatus.OK.code()).setContentType("text/plain").build()
|
||||||
.write(outputStream);
|
.write(outputStream);
|
||||||
})
|
})
|
||||||
.build();
|
.build();
|
||||||
|
|
|
@ -32,7 +32,7 @@ class CleartextTest {
|
||||||
HttpAddress httpAddress = HttpAddress.http2("localhost", 8008);
|
HttpAddress httpAddress = HttpAddress.http2("localhost", 8008);
|
||||||
HttpServerDomain domain = HttpServerDomain.builder(httpAddress)
|
HttpServerDomain domain = HttpServerDomain.builder(httpAddress)
|
||||||
.singleEndpoint("/", (request, response) ->
|
.singleEndpoint("/", (request, response) ->
|
||||||
response.getBuilder().setStatus(HttpResponseStatus.OK).setContentType("text/plain").build()
|
response.getBuilder().setStatus(HttpResponseStatus.OK.code()).setContentType("text/plain").build()
|
||||||
.write(request.getContent().toString(StandardCharsets.UTF_8)))
|
.write(request.getContent().toString(StandardCharsets.UTF_8)))
|
||||||
.build();
|
.build();
|
||||||
Server server = Server.builder(domain)
|
Server server = Server.builder(domain)
|
||||||
|
@ -77,7 +77,7 @@ class CleartextTest {
|
||||||
HttpAddress httpAddress = HttpAddress.http2("localhost", 8008);
|
HttpAddress httpAddress = HttpAddress.http2("localhost", 8008);
|
||||||
HttpServerDomain domain = HttpServerDomain.builder(httpAddress)
|
HttpServerDomain domain = HttpServerDomain.builder(httpAddress)
|
||||||
.singleEndpoint("/", (request, response) ->
|
.singleEndpoint("/", (request, response) ->
|
||||||
response.getBuilder().setStatus(HttpResponseStatus.OK).setContentType("text/plain").build()
|
response.getBuilder().setStatus(HttpResponseStatus.OK.code()).setContentType("text/plain").build()
|
||||||
.write(request.getContent().toString(StandardCharsets.UTF_8)))
|
.write(request.getContent().toString(StandardCharsets.UTF_8)))
|
||||||
.build();
|
.build();
|
||||||
Server server = Server.builder(domain)
|
Server server = Server.builder(domain)
|
||||||
|
@ -128,7 +128,7 @@ class CleartextTest {
|
||||||
HttpAddress httpAddress = HttpAddress.http2("localhost", 8008);
|
HttpAddress httpAddress = HttpAddress.http2("localhost", 8008);
|
||||||
HttpServerDomain domain = HttpServerDomain.builder(httpAddress)
|
HttpServerDomain domain = HttpServerDomain.builder(httpAddress)
|
||||||
.singleEndpoint("/**", (request, response) ->
|
.singleEndpoint("/**", (request, response) ->
|
||||||
response.getBuilder().setStatus(HttpResponseStatus.OK).setContentType("text/plain").build()
|
response.getBuilder().setStatus(HttpResponseStatus.OK.code()).setContentType("text/plain").build()
|
||||||
.write(request.getContent().toString(StandardCharsets.UTF_8)))
|
.write(request.getContent().toString(StandardCharsets.UTF_8)))
|
||||||
.build();
|
.build();
|
||||||
Server server = Server.builder(domain).build();
|
Server server = Server.builder(domain).build();
|
||||||
|
@ -195,7 +195,7 @@ class CleartextTest {
|
||||||
AtomicInteger counter1 = new AtomicInteger();
|
AtomicInteger counter1 = new AtomicInteger();
|
||||||
HttpServerDomain domain1 = HttpServerDomain.builder(httpAddress1)
|
HttpServerDomain domain1 = HttpServerDomain.builder(httpAddress1)
|
||||||
.singleEndpoint("/", (request, response) -> {
|
.singleEndpoint("/", (request, response) -> {
|
||||||
response.getBuilder().setStatus(HttpResponseStatus.OK).setContentType("text/plain").build()
|
response.getBuilder().setStatus(HttpResponseStatus.OK.code()).setContentType("text/plain").build()
|
||||||
.write(request.getContent().toString(StandardCharsets.UTF_8));
|
.write(request.getContent().toString(StandardCharsets.UTF_8));
|
||||||
counter1.incrementAndGet();
|
counter1.incrementAndGet();
|
||||||
})
|
})
|
||||||
|
@ -207,7 +207,7 @@ class CleartextTest {
|
||||||
AtomicInteger counter2 = new AtomicInteger();
|
AtomicInteger counter2 = new AtomicInteger();
|
||||||
HttpServerDomain domain2 = HttpServerDomain.builder(httpAddress2)
|
HttpServerDomain domain2 = HttpServerDomain.builder(httpAddress2)
|
||||||
.singleEndpoint("/", (request, response) -> {
|
.singleEndpoint("/", (request, response) -> {
|
||||||
response.getBuilder().setStatus(HttpResponseStatus.OK).setContentType("text/plain").build()
|
response.getBuilder().setStatus(HttpResponseStatus.OK.code()).setContentType("text/plain").build()
|
||||||
.write(request.getContent().toString(StandardCharsets.UTF_8));
|
.write(request.getContent().toString(StandardCharsets.UTF_8));
|
||||||
counter2.incrementAndGet();
|
counter2.incrementAndGet();
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in a new issue