diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/multipart/HttpPostRequestDecoder.java b/codec-http/src/main/java/io/netty/handler/codec/http/multipart/HttpPostRequestDecoder.java
index fb65bdfffc..af53bacf7f 100644
--- a/codec-http/src/main/java/io/netty/handler/codec/http/multipart/HttpPostRequestDecoder.java
+++ b/codec-http/src/main/java/io/netty/handler/codec/http/multipart/HttpPostRequestDecoder.java
@@ -33,7 +33,6 @@ import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.nio.charset.Charset;
import java.util.ArrayList;
-import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
@@ -42,8 +41,11 @@ import static io.netty.buffer.Unpooled.*;
/**
* This decoder will decode Body and can handle POST BODY.
+ *
+ * You MUST call {@link #destroy()} after completion to release all resources.
+ *
*/
-public class HttpPostRequestDecoder implements Iterator {
+public class HttpPostRequestDecoder {
/**
* Factory used to create InterfaceHttpData
*/
@@ -126,6 +128,8 @@ public class HttpPostRequestDecoder implements Iterator {
*/
private Attribute currentAttribute;
+ private boolean destroyed;
+
/**
*
* @param request
@@ -273,12 +277,19 @@ public class HttpPostRequestDecoder implements Iterator {
}
}
+ private void checkDestroyed() {
+ if (destroyed) {
+ throw new IllegalStateException(HttpPostRequestDecoder.class.getSimpleName() + " was destroyed already");
+ }
+ }
+
/**
* True if this request is a Multipart request
*
* @return True if this request is a Multipart request
*/
public boolean isMultipart() {
+ checkDestroyed();
return isMultipart;
}
@@ -293,6 +304,8 @@ public class HttpPostRequestDecoder implements Iterator {
* Need more chunks
*/
public List getBodyHttpDatas() throws NotEnoughDataDecoderException {
+ checkDestroyed();
+
if (!isLastChunk) {
throw new NotEnoughDataDecoderException();
}
@@ -311,6 +324,8 @@ public class HttpPostRequestDecoder implements Iterator {
* need more chunks
*/
public List getBodyHttpDatas(String name) throws NotEnoughDataDecoderException {
+ checkDestroyed();
+
if (!isLastChunk) {
throw new NotEnoughDataDecoderException();
}
@@ -330,6 +345,8 @@ public class HttpPostRequestDecoder implements Iterator {
* need more chunks
*/
public InterfaceHttpData getBodyHttpData(String name) throws NotEnoughDataDecoderException {
+ checkDestroyed();
+
if (!isLastChunk) {
throw new NotEnoughDataDecoderException();
}
@@ -350,6 +367,8 @@ public class HttpPostRequestDecoder implements Iterator {
* errors
*/
public HttpPostRequestDecoder offer(HttpContent content) throws ErrorDataDecoderException {
+ checkDestroyed();
+
// Maybe we should better not copy here for performance reasons but this will need
// more care by teh caller to release the content in a correct manner later
// So maybe something to optimize on a later stage
@@ -380,6 +399,8 @@ public class HttpPostRequestDecoder implements Iterator {
* No more data will be available
*/
public boolean hasNext() throws EndOfDataDecoderException {
+ checkDestroyed();
+
if (currentStatus == MultiPartStatus.EPILOGUE) {
// OK except if end of list
if (bodyListHttpDataRank >= bodyListHttpData.size()) {
@@ -394,11 +415,16 @@ public class HttpPostRequestDecoder implements Iterator {
* is called, there is no more available InterfaceHttpData. A subsequent
* call to offer(httpChunk) could enable more data.
*
+ * Be sure to call {@link InterfaceHttpData#release()} after you are done
+ * with processing to make sure to not leak any resources
+ *
* @return the next available InterfaceHttpData or null if none
* @throws EndOfDataDecoderException
* No more data will be available
*/
public InterfaceHttpData next() throws EndOfDataDecoderException {
+ checkDestroyed();
+
if (hasNext()) {
return bodyListHttpData.get(bodyListHttpDataRank++);
}
@@ -1172,10 +1198,31 @@ public class HttpPostRequestDecoder implements Iterator {
return null;
}
+ /**
+ * Destroy the {@link HttpPostRequestDecoder} and release all it resources. After this method
+ * was called it is not possible to operate on it anymore.
+ */
+ public void destroy() {
+ checkDestroyed();
+
+ cleanFiles();
+ if (undecodedChunk != null && undecodedChunk.refCnt() > 0) {
+ undecodedChunk.release();
+ undecodedChunk = null;
+ }
+
+ // release all data which was not yet pulled
+ for (int i = bodyListHttpDataRank; i < bodyListHttpData.size(); i++) {
+ bodyListHttpData.get(i).release();
+ }
+ }
+
/**
* Clean all HttpDatas (on Disk) for the current request.
*/
public void cleanFiles() {
+ checkDestroyed();
+
factory.cleanRequestHttpDatas(request);
}
@@ -1183,6 +1230,8 @@ public class HttpPostRequestDecoder implements Iterator {
* Remove the given FileUpload from the list of FileUploads to clean
*/
public void removeHttpDataFromClean(InterfaceHttpData data) {
+ checkDestroyed();
+
factory.removeHttpDataFromClean(request, data);
}
@@ -2043,11 +2092,6 @@ public class HttpPostRequestDecoder implements Iterator {
return array;
}
- @Override
- public void remove() {
- throw new UnsupportedOperationException();
- }
-
/**
* Exception when try reading data from request in chunked format, and not
* enough data are available (need more chunks)
diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/multipart/InterfaceHttpData.java b/codec-http/src/main/java/io/netty/handler/codec/http/multipart/InterfaceHttpData.java
index 12f1ab45ff..b0b9daf3ed 100644
--- a/codec-http/src/main/java/io/netty/handler/codec/http/multipart/InterfaceHttpData.java
+++ b/codec-http/src/main/java/io/netty/handler/codec/http/multipart/InterfaceHttpData.java
@@ -15,10 +15,12 @@
*/
package io.netty.handler.codec.http.multipart;
+import io.netty.util.ReferenceCounted;
+
/**
* Interface for all Objects that could be encoded/decoded using HttpPostRequestEncoder/Decoder
*/
-public interface InterfaceHttpData extends Comparable {
+public interface InterfaceHttpData extends Comparable, ReferenceCounted {
enum HttpDataType {
Attribute, FileUpload, InternalAttribute
}
diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/multipart/InternalAttribute.java b/codec-http/src/main/java/io/netty/handler/codec/http/multipart/InternalAttribute.java
index 2a83f1985f..2637ff57f4 100644
--- a/codec-http/src/main/java/io/netty/handler/codec/http/multipart/InternalAttribute.java
+++ b/codec-http/src/main/java/io/netty/handler/codec/http/multipart/InternalAttribute.java
@@ -17,6 +17,7 @@ package io.netty.handler.codec.http.multipart;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
+import io.netty.util.AbstractReferenceCounted;
import java.nio.charset.Charset;
import java.util.ArrayList;
@@ -26,7 +27,7 @@ import java.util.List;
* This Attribute is only for Encoder use to insert special command between object if needed
* (like Multipart Mixed mode)
*/
-final class InternalAttribute implements InterfaceHttpData {
+final class InternalAttribute extends AbstractReferenceCounted implements InterfaceHttpData {
private final List value = new ArrayList();
private final Charset charset;
private int size;
@@ -117,4 +118,9 @@ final class InternalAttribute implements InterfaceHttpData {
public String getName() {
return "InternalAttribute";
}
+
+ @Override
+ protected void deallocate() {
+ // Do nothing
+ }
}
diff --git a/example/src/main/java/io/netty/example/http/upload/HttpUploadServerHandler.java b/example/src/main/java/io/netty/example/http/upload/HttpUploadServerHandler.java
index eef02422bd..8d517edbc7 100644
--- a/example/src/main/java/io/netty/example/http/upload/HttpUploadServerHandler.java
+++ b/example/src/main/java/io/netty/example/http/upload/HttpUploadServerHandler.java
@@ -44,7 +44,6 @@ import io.netty.handler.codec.http.multipart.HttpPostRequestDecoder;
import io.netty.handler.codec.http.multipart.HttpPostRequestDecoder.EndOfDataDecoderException;
import io.netty.handler.codec.http.multipart.HttpPostRequestDecoder.ErrorDataDecoderException;
import io.netty.handler.codec.http.multipart.HttpPostRequestDecoder.IncompatibleDataDecoderException;
-import io.netty.handler.codec.http.multipart.HttpPostRequestDecoder.NotEnoughDataDecoderException;
import io.netty.handler.codec.http.multipart.InterfaceHttpData;
import io.netty.handler.codec.http.multipart.InterfaceHttpData.HttpDataType;
import io.netty.util.CharsetUtil;
@@ -192,7 +191,6 @@ public class HttpUploadServerHandler extends SimpleChannelInboundHandler datas;
- try {
- datas = decoder.getBodyHttpDatas();
- } catch (NotEnoughDataDecoderException e1) {
- // Should not be!
- e1.printStackTrace();
- responseContent.append(e1.getMessage());
- writeResponse(channel);
- channel.close();
- return;
- }
- for (InterfaceHttpData data : datas) {
- writeHttpData(data);
- }
- responseContent.append("\r\n\r\nEND OF CONTENT AT FINAL END\r\n");
- }
-
/**
* Example of reading request by chunk and getting values from chunk to chunk
*/