make server HTTP request serializable in json

This commit is contained in:
Jörg Prante 2023-08-21 17:18:11 +02:00
parent 9c551e3c34
commit e3adbd4369
8 changed files with 144 additions and 11 deletions

View file

@ -1,5 +1,5 @@
group = org.xbib group = org.xbib
name = net-http name = net-http
version = 3.6.1 version = 3.6.2
org.gradle.warning.mode = ALL org.gradle.warning.mode = ALL

View file

@ -5,6 +5,7 @@ import io.netty.buffer.ByteBufUtil;
import io.netty.handler.codec.http.FullHttpRequest; import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.multipart.FileUpload; import io.netty.handler.codec.http.multipart.FileUpload;
import java.io.IOException; import java.io.IOException;
import java.util.Map;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import org.xbib.net.Parameter; import org.xbib.net.Parameter;
@ -33,6 +34,11 @@ public class HttpRequestBuilder extends BaseHttpRequestBuilder {
protected HttpRequestBuilder() { protected HttpRequestBuilder() {
} }
public HttpRequestBuilder parse(Map<String, Object> map) {
super.parse(map);
return this;
}
public HttpRequestBuilder setHttpRequest(io.netty.handler.codec.http.HttpRequest httpRequest) { public HttpRequestBuilder setHttpRequest(io.netty.handler.codec.http.HttpRequest httpRequest) {
if (httpRequest != null) { if (httpRequest != null) {
setVersion(HttpVersion.valueOf(httpRequest.protocolVersion().text())); setVersion(HttpVersion.valueOf(httpRequest.protocolVersion().text()));

View file

@ -52,9 +52,7 @@ public class NettyHttp2ServerTest {
.header(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN) .header(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN)
.charset(StandardCharsets.UTF_8) .charset(StandardCharsets.UTF_8)
.body("Hello, here is my response: " + .body("Hello, here is my response: " +
ctx.getRequest().getParameter() + " " + ctx.getRequest().asJson())
ctx.getRequest().getLocalAddress() + " " +
ctx.getRequest().getRemoteAddress())
.done(); .done();
}) })
.build()) .build())

View file

@ -1,6 +1,9 @@
package org.xbib.net.http.netty.test; package org.xbib.net.http.netty.test;
import io.netty.bootstrap.Bootstrap; import io.netty.bootstrap.Bootstrap;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Level; import java.util.logging.Level;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@ -9,7 +12,9 @@ import org.xbib.net.URL;
import org.xbib.net.http.HttpAddress; import org.xbib.net.http.HttpAddress;
import org.xbib.net.http.HttpHeaderNames; import org.xbib.net.http.HttpHeaderNames;
import org.xbib.net.http.HttpHeaderValues; import org.xbib.net.http.HttpHeaderValues;
import org.xbib.net.http.HttpMethod;
import org.xbib.net.http.HttpResponseStatus; import org.xbib.net.http.HttpResponseStatus;
import org.xbib.net.http.client.HttpRequestBuilder;
import org.xbib.net.http.client.netty.HttpRequest; import org.xbib.net.http.client.netty.HttpRequest;
import org.xbib.net.http.client.netty.NettyHttpClient; import org.xbib.net.http.client.netty.NettyHttpClient;
import org.xbib.net.http.client.netty.NettyHttpClientConfig; import org.xbib.net.http.client.netty.NettyHttpClientConfig;
@ -22,6 +27,7 @@ import org.xbib.net.http.server.route.HttpRouter;
import org.xbib.net.http.server.service.BaseHttpService; import org.xbib.net.http.server.service.BaseHttpService;
import org.xbib.net.http.server.netty.NettyHttpServer; import org.xbib.net.http.server.netty.NettyHttpServer;
import org.xbib.net.http.server.netty.NettyHttpServerConfig; import org.xbib.net.http.server.netty.NettyHttpServerConfig;
import org.xbib.net.util.JsonUtil;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.logging.Logger; import java.util.logging.Logger;
@ -50,11 +56,7 @@ public class NettyHttpServerTest {
ctx.status(HttpResponseStatus.OK) ctx.status(HttpResponseStatus.OK)
.header(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN) .header(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN)
.charset(StandardCharsets.UTF_8) .charset(StandardCharsets.UTF_8)
.body("domain" + .body(ctx.getRequest().asJson())
" parameter = " + ctx.getRequest().getParameter().toString() +
" local address = " + ctx.getRequest().getLocalAddress() +
" remote address = " + ctx.getRequest().getRemoteAddress() +
" attributes = " + ctx.getAttributes())
.done(); .done();
}) })
.build()) .build())
@ -81,10 +83,19 @@ public class NettyHttpServerTest {
HttpRequest request = HttpRequest.get() HttpRequest request = HttpRequest.get()
.setURL(url) .setURL(url)
.setResponseListener(resp -> { .setResponseListener(resp -> {
String body = resp.getBodyAsChars(StandardCharsets.UTF_8).toString();
logger.log(Level.INFO, "got response:" + logger.log(Level.INFO, "got response:" +
" status = " + resp.getStatus() + " status = " + resp.getStatus() +
" header = " + resp.getHeaders() + " header = " + resp.getHeaders() +
" body = " + resp.getBodyAsChars(StandardCharsets.UTF_8)); " body = " + body);
try {
Map<String, Object> map = JsonUtil.toMap(body);
org.xbib.net.http.server.netty.HttpRequest httpRequest = org.xbib.net.http.server.netty.HttpRequest.builder()
.parse(map).build();
logger.log(Level.INFO, "parsed http request = " + httpRequest.asJson());
} catch (IOException e) {
throw new RuntimeException(e);
}
received.set(true); received.set(true);
}) })
.build(); .build();

View file

@ -1,9 +1,19 @@
package org.xbib.net.http.server; package org.xbib.net.http.server;
import java.io.IOException;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.xbib.datastructures.common.Pair;
import org.xbib.datastructures.json.tiny.JsonBuilder;
import org.xbib.net.Attributes; import org.xbib.net.Attributes;
import org.xbib.net.Parameter; import org.xbib.net.Parameter;
import org.xbib.net.ParameterException;
import org.xbib.net.URL; import org.xbib.net.URL;
import org.xbib.net.http.HttpHeaders; import org.xbib.net.http.HttpHeaders;
import org.xbib.net.http.HttpMethod; import org.xbib.net.http.HttpMethod;
@ -101,4 +111,59 @@ public abstract class BaseHttpRequest implements HttpRequest {
public Attributes getAttributes() { public Attributes getAttributes() {
return attributes; return attributes;
} }
@Override
public String asJson() {
JsonBuilder jsonBuilder = JsonBuilder.builder();
try {
jsonBuilder.beginMap();
Map<String, Object> local = Map.of("host", builder.localAddress.getHostString(), "port", builder.localAddress.getPort());
jsonBuilder.buildKey("local").buildMap(local);
Map<String, Object> remote = Map.of("host", builder.remoteAddress.getHostString(), "port", builder.remoteAddress.getPort());
jsonBuilder.buildKey("remote").buildMap(remote);
jsonBuilder.buildKey("baseurl").buildValue(builder.baseURL.toString());
jsonBuilder.buildKey("version").buildValue(builder.getVersion().toString());
jsonBuilder.buildKey("method").buildValue(builder.getMethod().toString());
Map<String, Object> headerMap = builder.getHeaders().entries().stream()
.collect(Collectors.toMap(Pair::getKey, Pair::getValue, (x, y) -> y, LinkedHashMap::new));
jsonBuilder.buildKey("header").buildMap(headerMap);
jsonBuilder.buildKey("requesturi").buildValue(builder.getRequestURI());
jsonBuilder.buildKey("requestpath").buildValue(builder.getRequestPath());
Parameter queryParameter = builder.parameter.get(Parameter.Domain.QUERY);
Map<String, Object> queryParameterMap = queryParameter != null ?
queryParameter.asMultiMap().asMap().entrySet().stream()
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (x, y) -> y, LinkedHashMap::new)) : Map.of();
Parameter pathParameter = builder.parameter.get(Parameter.Domain.PATH);
Map<String, Object> pathParameterMap = pathParameter != null ?
pathParameter.asMultiMap().asMap().entrySet().stream()
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (x, y) -> y, LinkedHashMap::new)) : Map.of();
Parameter formParameter = builder.parameter.get(Parameter.Domain.FORM);
Map<String, Object> formParameterMap = formParameter != null ?
formParameter.asMultiMap().asMap().entrySet().stream()
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (x, y) -> y, LinkedHashMap::new)) : Map.of();
Parameter cookieParameter = builder.parameter.get(Parameter.Domain.COOKIE);
Map<String, Object> cookieParameterMap = cookieParameter != null ?
cookieParameter.asMultiMap().asMap().entrySet().stream()
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (x, y) -> y, LinkedHashMap::new)) : Map.of();
Parameter headerParameter = builder.parameter.get(Parameter.Domain.HEADER);
Map<String, Object> headerParameterMap = headerParameter != null ?
headerParameter.asMultiMap().asMap().entrySet().stream()
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (x, y) -> y, LinkedHashMap::new)) : Map.of();
jsonBuilder.buildKey("parameter").buildMap(Map.of("query", queryParameterMap,
"path", pathParameterMap,
"form", formParameterMap,
"cookie", cookieParameterMap,
"header", headerParameterMap));
jsonBuilder.buildKey("sequenceid").buildValue(builder.sequenceId);
jsonBuilder.buildKey("streamid").buildValue(builder.streamId);
jsonBuilder.buildKey("requestid").buildValue(builder.requestId);
// body may be large
//jsonBuilder.buildKey("encoding").buildValue("ISO-8859-1");
//jsonBuilder.buildKey("body").buildValue(StandardCharsets.ISO_8859_1.decode(builder.getBody()).toString());
jsonBuilder.endMap();
} catch (IOException | ParameterException e) {
// ignore
}
return jsonBuilder.build();
}
} }

View file

@ -1,13 +1,20 @@
package org.xbib.net.http.server; package org.xbib.net.http.server;
import java.net.InetAddress;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.CharBuffer; import java.nio.CharBuffer;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects; import java.util.Objects;
import org.xbib.datastructures.common.Maps;
import org.xbib.net.Parameter; import org.xbib.net.Parameter;
import org.xbib.net.ParameterBuilder;
import org.xbib.net.URL; import org.xbib.net.URL;
import org.xbib.net.URLBuilder; import org.xbib.net.URLBuilder;
import org.xbib.net.http.HttpAddress; import org.xbib.net.http.HttpAddress;
@ -59,6 +66,50 @@ public abstract class BaseHttpRequestBuilder implements HttpRequestBuilder {
this.messages = new ArrayList<>(); this.messages = new ArrayList<>();
} }
@SuppressWarnings("unchecked")
public BaseHttpRequestBuilder parse(Map<String, Object> map) {
Map<String, Object> localMap = (Map<String, Object>) map.get("local");
String localHost = Maps.getString(localMap, "host");
int localPort = Maps.getInteger(localMap, "port", -1);
setLocalAddress(new InetSocketAddress(localHost, localPort));
Map<String, Object> remoteMap = (Map<String, Object>) map.get("remote");
String remoteHost = Maps.getString(remoteMap, "host");
int remotePort = Maps.getInteger(remoteMap, "port", -1);
setRemoteAddress(new InetSocketAddress(remoteHost, remotePort));
setBaseURL(URL.from(Maps.getString(map, "baseurl")));
setVersion(HttpVersion.valueOf(Maps.getString(map, "version")));
setMethod(HttpMethod.valueOf(Maps.getString(map, "method")));
HttpHeaders httpHeaders = new HttpHeaders();
Map<String, Object> headerMap = (Map<String, Object>) map.get("header");
if (headerMap != null) {
headerMap.forEach((k, v) -> {
if (v instanceof Iterable<?> ) {
httpHeaders.add(k, (Iterable<?>) v);
} else {
httpHeaders.add(k, v.toString());
}
});
}
setHeaders(httpHeaders);
setRequestURI(Maps.getString(map, "requesturi"));
setRequestPath(Maps.getString(map, "requestpath"));
ParameterBuilder parameterBuilder = Parameter.builder().domain(Parameter.Domain.QUERY);
Map<String, Object> parameterMap = (Map<String, Object>) map.get("parameter");
Arrays.asList(Parameter.Domain.QUERY, Parameter.Domain.PATH, Parameter.Domain.FORM, Parameter.Domain.COOKIE, Parameter.Domain.HEADER).forEach(d -> {
Map<String, Object> m = (Map<String, Object>) parameterMap.get(d.name().toLowerCase(Locale.ROOT));
if (m != null) {
ParameterBuilder p = Parameter.builder().domain(d);
m.forEach(p::add);
parameterBuilder.add(p.build());
}
});
setParameter(parameterBuilder.build());
setSequenceId(Maps.getInteger(map, "sequenceid", 0));
setStreamId(Maps.getInteger(map, "streamid", -1));
setRequestId(Maps.getLong(map, "requestid", -1L));
return this;
}
@Override @Override
public BaseHttpRequestBuilder setContext(HttpRouterContext httpRouterContext) { public BaseHttpRequestBuilder setContext(HttpRouterContext httpRouterContext) {
if (done) { if (done) {

View file

@ -43,4 +43,6 @@ public interface HttpRequest extends Request {
List<Message> getMessages(); List<Message> getMessages();
Attributes getAttributes(); Attributes getAttributes();
String asJson();
} }

View file

@ -6,7 +6,7 @@ dependencyResolutionManagement {
version('groovy', '4.0.13') version('groovy', '4.0.13')
version('netty', '4.1.96.Final') version('netty', '4.1.96.Final')
version('netty-tcnative', '2.0.61.Final') version('netty-tcnative', '2.0.61.Final')
version('datastructures', '2.3.0') version('datastructures', '2.3.1')
version('config', '5.0.3') version('config', '5.0.3')
version('net', '3.3.3') version('net', '3.3.3')
library('junit-jupiter-api', 'org.junit.jupiter', 'junit-jupiter-api').versionRef('junit') library('junit-jupiter-api', 'org.junit.jupiter', 'junit-jupiter-api').versionRef('junit')