fix HTTP file upload cleanup on client and server

This commit is contained in:
Jörg Prante 2023-04-08 12:05:19 +02:00
parent 3749b9ba3a
commit dab29dbf9f
4 changed files with 25 additions and 29 deletions

View file

@ -2,9 +2,11 @@ package org.xbib.net.http.client.netty;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.pool.ChannelPoolHandler;
import io.netty.handler.codec.http.multipart.HttpDataFactory;
import io.netty.util.concurrent.Future;
import java.io.Closeable;
import java.io.IOException;
@ -84,6 +86,14 @@ public class NettyHttpClient implements HttpClient<HttpRequest, HttpResponse>, C
return new ChannelInitializer<>() {
@Override
protected void initChannel(Channel channel) throws Exception {
channel.closeFuture().addListener((ChannelFuture future) -> {
Channel ch = future.channel();
HttpDataFactory httpDataFactory = ch.attr(NettyHttpClientConfig.ATTRIBUTE_HTTP_DATAFACTORY).get();
if (httpDataFactory != null) {
logger.log(Level.FINEST, "cleaning http data factory");
httpDataFactory.cleanAllHttpData();
}
});
interaction.setSettingsPromise(channel.newPromise());
lookupChannelInitializer(httpAddress)
.init(channel, httpAddress, getClient(), builder.nettyCustomizer, interaction);

View file

@ -2,11 +2,13 @@ package org.xbib.net.http.client.netty;
import io.netty.buffer.ByteBufAllocator;
import io.netty.channel.WriteBufferWaterMark;
import io.netty.handler.codec.http.multipart.HttpDataFactory;
import io.netty.handler.codec.http2.Http2Settings;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.proxy.HttpProxyHandler;
import io.netty.handler.proxy.Socks4ProxyHandler;
import io.netty.handler.proxy.Socks5ProxyHandler;
import io.netty.util.AttributeKey;
import java.util.ArrayList;
import java.util.List;
import org.xbib.net.SocketConfig;
@ -16,6 +18,8 @@ import org.xbib.net.http.client.BackOff;
public class NettyHttpClientConfig {
public static final AttributeKey<HttpDataFactory> ATTRIBUTE_HTTP_DATAFACTORY = AttributeKey.valueOf("http_datafactory");
/**
* If frame logging /traffic logging is enabled or not.
*/

View file

@ -1,12 +1,9 @@
package org.xbib.net.http.client.netty.http1;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.handler.codec.http.DefaultFullHttpRequest;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpChunkedInput;
import io.netty.handler.codec.http.HttpHeaderNames;
import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.codec.http.HttpVersion;
@ -34,6 +31,7 @@ import org.xbib.net.http.HttpAddress;
import org.xbib.net.http.HttpHeaders;
import org.xbib.net.http.HttpResponseStatus;
import org.xbib.net.http.client.Part;
import org.xbib.net.http.client.netty.NettyHttpClientConfig;
import org.xbib.net.http.cookie.Cookie;
import org.xbib.net.http.client.cookie.CookieDecoder;
import org.xbib.net.http.client.cookie.CookieEncoder;
@ -131,25 +129,16 @@ public class Http1Interaction extends BaseInteraction {
}
io.netty.handler.codec.http.HttpRequest httpRequest = httpPostRequestEncoder.finalizeRequest();
channel.write(httpRequest);
} else {
channel.write(fullHttpRequest);
}
channel.write(fullHttpRequest);
if (httpPostRequestEncoder != null && httpPostRequestEncoder.isChunked()) {
logger.log(Level.FINEST, "finish chunked HTTP POST encoder");
channel.write(httpPostRequestEncoder);
} else {
logger.log(Level.FINEST, "HTTP POST encoder not chunked");
}
channel.flush();
} catch (HttpPostRequestEncoder.ErrorDataEncoderException e) {
throw new IOException(e);
} finally {
if (httpPostRequestEncoder != null) {
logger.log(Level.FINEST, "cleaning files of HTTP POST encoder");
//httpPostRequestEncoder.cleanFiles();
}
logger.log(Level.FINEST, "clean all http data");
//httpDataFactory.cleanAllHttpData();
channel.attr(NettyHttpClientConfig.ATTRIBUTE_HTTP_DATAFACTORY).set(httpDataFactory);
}
return this;
}

View file

@ -39,37 +39,29 @@ public class HttpFileUploadHandler extends SimpleChannelInboundHandler<HttpObjec
@Override
protected void channelRead0(ChannelHandlerContext ctx, HttpObject httpObject) {
logger.log(Level.FINEST, "checking file upload");
HttpRequest httpRequest = null;
HttpPostRequestDecoder httpDecoder = null;
if (httpObject instanceof HttpRequest) {
httpRequest = (HttpRequest) httpObject;
// peek into request if we have a POST request
if (httpRequest.method() == HttpMethod.POST) {
logger.log(Level.FINEST, "checking HTTP POST: success");
HttpDataFactory factory = new DefaultHttpDataFactory(nettyHttpServer.getNettyHttpServerConfig().getFileUploadDiskThreshold());
httpDecoder = new HttpPostRequestDecoder(factory, httpRequest);
}
}
if (httpDecoder != null) {
if (httpObject instanceof HttpContent chunk) {
logger.log(Level.FINEST, "got chunk");
httpDecoder.offer(chunk);
try {
while (httpDecoder.hasNext()) {
InterfaceHttpData data = httpDecoder.next();
logger.log(Level.FINEST, "got data");
if (data != null) {
try {
if (data.getHttpDataType() == InterfaceHttpData.HttpDataType.FileUpload) {
logger.log(Level.FINEST, "got file upload");
FileUpload fileUpload = (FileUpload) data;
requestReceived(ctx, httpRequest, fileUpload);
} else {
logger.log(Level.FINEST, "got HTTP data type = " + data.getHttpDataType());
}
} finally {
data.release();
if (data.getHttpDataType() == InterfaceHttpData.HttpDataType.FileUpload) {
logger.log(Level.FINEST, "got file upload");
FileUpload fileUpload = (FileUpload) data;
requestReceived(ctx, httpRequest, fileUpload);
} else {
logger.log(Level.FINEST, "got HTTP data type = " + data.getHttpDataType());
}
}
}
@ -77,7 +69,8 @@ public class HttpFileUploadHandler extends SimpleChannelInboundHandler<HttpObjec
logger.log(Level.FINEST, "end of data decoder exception");
}
if (chunk instanceof LastHttpContent) {
//httpDecoder.destroy();
logger.log(Level.FINEST, "destroying HTTP decode");
httpDecoder.destroy();
}
} else {
logger.log(Level.FINEST, "not a HttpContent: " );