Removing a SeekAheadNoBackArrayException to avoid exception handling
Motivation: A `SeekAheadNoBackArrayException` used as check for `ByteBuf#hasArray`. The catch of exceptions carries a large overhead on stack trace filling, and this should be avoided. Modifications: - Remove the class `SeekAheadNoBackArrayException` and replace its usage with `if` statements. - Use methods from `ObjectUtils` for better readability. - Make private methods static where it make sense. - Remove unused private methods. Result: Less of exception handling logic, better performance.
This commit is contained in:
parent
e06cb82c4c
commit
b03b0f22d1
@ -62,10 +62,6 @@ final class HttpPostBodyUtil {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
TransferEncodingMechanism() {
|
||||
value = name();
|
||||
}
|
||||
|
||||
public String value() {
|
||||
return value;
|
||||
}
|
||||
@ -79,13 +75,6 @@ final class HttpPostBodyUtil {
|
||||
private HttpPostBodyUtil() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Exception when NO Backend Array is found
|
||||
*/
|
||||
static class SeekAheadNoBackArrayException extends Exception {
|
||||
private static final long serialVersionUID = -630418804938699495L;
|
||||
}
|
||||
|
||||
/**
|
||||
* This class intends to decrease the CPU in seeking ahead some bytes in
|
||||
* HttpPostRequestDecoder
|
||||
@ -98,9 +87,12 @@ final class HttpPostBodyUtil {
|
||||
int limit;
|
||||
ByteBuf buffer;
|
||||
|
||||
SeekAheadOptimize(ByteBuf buffer) throws SeekAheadNoBackArrayException {
|
||||
/**
|
||||
* @param buffer buffer with a backing byte array
|
||||
*/
|
||||
SeekAheadOptimize(ByteBuf buffer) {
|
||||
if (!buffer.hasArray()) {
|
||||
throw new SeekAheadNoBackArrayException();
|
||||
throw new IllegalArgumentException("buffer hasn't backing byte array");
|
||||
}
|
||||
this.buffer = buffer;
|
||||
bytes = buffer.array();
|
||||
@ -128,14 +120,6 @@ final class HttpPostBodyUtil {
|
||||
int getReadPosition(int index) {
|
||||
return index - origPos + readerIndex;
|
||||
}
|
||||
|
||||
void clear() {
|
||||
buffer = null;
|
||||
bytes = null;
|
||||
limit = 0;
|
||||
pos = 0;
|
||||
readerIndex = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -152,20 +136,6 @@ final class HttpPostBodyUtil {
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the first whitespace
|
||||
* @return the rank of the first whitespace
|
||||
*/
|
||||
static int findWhitespace(String sb, int offset) {
|
||||
int result;
|
||||
for (result = offset; result < sb.length(); result ++) {
|
||||
if (Character.isWhitespace(sb.charAt(result))) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the end of String
|
||||
* @return the rank of the end of string
|
||||
|
@ -22,7 +22,6 @@ import io.netty.handler.codec.http.HttpHeaderNames;
|
||||
import io.netty.handler.codec.http.HttpHeaderValues;
|
||||
import io.netty.handler.codec.http.HttpRequest;
|
||||
import io.netty.handler.codec.http.LastHttpContent;
|
||||
import io.netty.handler.codec.http.multipart.HttpPostBodyUtil.SeekAheadNoBackArrayException;
|
||||
import io.netty.handler.codec.http.multipart.HttpPostBodyUtil.SeekAheadOptimize;
|
||||
import io.netty.handler.codec.http.multipart.HttpPostBodyUtil.TransferEncodingMechanism;
|
||||
import io.netty.handler.codec.http.multipart.HttpPostRequestDecoder.EndOfDataDecoderException;
|
||||
@ -42,6 +41,7 @@ import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import static io.netty.buffer.Unpooled.*;
|
||||
import static io.netty.util.internal.ObjectUtil.*;
|
||||
|
||||
/**
|
||||
* This decoder will decode Body and can handle POST BODY.
|
||||
@ -172,18 +172,9 @@ public class HttpPostMultipartRequestDecoder implements InterfaceHttpPostRequest
|
||||
* errors
|
||||
*/
|
||||
public HttpPostMultipartRequestDecoder(HttpDataFactory factory, HttpRequest request, Charset charset) {
|
||||
if (factory == null) {
|
||||
throw new NullPointerException("factory");
|
||||
}
|
||||
if (request == null) {
|
||||
throw new NullPointerException("request");
|
||||
}
|
||||
if (charset == null) {
|
||||
throw new NullPointerException("charset");
|
||||
}
|
||||
this.request = request;
|
||||
this.charset = charset;
|
||||
this.factory = factory;
|
||||
this.request = checkNotNull(request, "request");
|
||||
this.charset = checkNotNull(charset, "charset");
|
||||
this.factory = checkNotNull(factory, "factory");
|
||||
// Fill default values
|
||||
|
||||
setMultipart(this.request.headers().get(HttpHeaderNames.CONTENT_TYPE));
|
||||
@ -238,10 +229,7 @@ public class HttpPostMultipartRequestDecoder implements InterfaceHttpPostRequest
|
||||
*/
|
||||
@Override
|
||||
public void setDiscardThreshold(int discardThreshold) {
|
||||
if (discardThreshold < 0) {
|
||||
throw new IllegalArgumentException("discardThreshold must be >= 0");
|
||||
}
|
||||
this.discardThreshold = discardThreshold;
|
||||
this.discardThreshold = checkPositiveOrZero(discardThreshold, "discardThreshold");
|
||||
}
|
||||
|
||||
/**
|
||||
@ -547,7 +535,7 @@ public class HttpPostMultipartRequestDecoder implements InterfaceHttpPostRequest
|
||||
}
|
||||
// load data
|
||||
try {
|
||||
loadFieldMultipart(multipartDataBoundary);
|
||||
loadFieldMultipart(undecodedChunk, multipartDataBoundary, currentAttribute);
|
||||
} catch (NotEnoughDataDecoderException ignored) {
|
||||
return null;
|
||||
}
|
||||
@ -589,19 +577,16 @@ public class HttpPostMultipartRequestDecoder implements InterfaceHttpPostRequest
|
||||
*
|
||||
* @throws NotEnoughDataDecoderException
|
||||
*/
|
||||
void skipControlCharacters() {
|
||||
SeekAheadOptimize sao;
|
||||
try {
|
||||
sao = new SeekAheadOptimize(undecodedChunk);
|
||||
} catch (SeekAheadNoBackArrayException ignored) {
|
||||
private static void skipControlCharacters(ByteBuf undecodedChunk) {
|
||||
if (!undecodedChunk.hasArray()) {
|
||||
try {
|
||||
skipControlCharactersStandard();
|
||||
skipControlCharactersStandard(undecodedChunk);
|
||||
} catch (IndexOutOfBoundsException e1) {
|
||||
throw new NotEnoughDataDecoderException(e1);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
SeekAheadOptimize sao = new SeekAheadOptimize(undecodedChunk);
|
||||
while (sao.pos < sao.limit) {
|
||||
char c = (char) (sao.bytes[sao.pos++] & 0xFF);
|
||||
if (!Character.isISOControl(c) && !Character.isWhitespace(c)) {
|
||||
@ -612,7 +597,7 @@ public class HttpPostMultipartRequestDecoder implements InterfaceHttpPostRequest
|
||||
throw new NotEnoughDataDecoderException("Access out of bounds");
|
||||
}
|
||||
|
||||
void skipControlCharactersStandard() {
|
||||
private static void skipControlCharactersStandard(ByteBuf undecodedChunk) {
|
||||
for (;;) {
|
||||
char c = (char) undecodedChunk.readUnsignedByte();
|
||||
if (!Character.isISOControl(c) && !Character.isWhitespace(c)) {
|
||||
@ -639,7 +624,7 @@ public class HttpPostMultipartRequestDecoder implements InterfaceHttpPostRequest
|
||||
// --AaB03x or --AaB03x--
|
||||
int readerIndex = undecodedChunk.readerIndex();
|
||||
try {
|
||||
skipControlCharacters();
|
||||
skipControlCharacters(undecodedChunk);
|
||||
} catch (NotEnoughDataDecoderException ignored) {
|
||||
undecodedChunk.readerIndex(readerIndex);
|
||||
return null;
|
||||
@ -647,7 +632,7 @@ public class HttpPostMultipartRequestDecoder implements InterfaceHttpPostRequest
|
||||
skipOneLine();
|
||||
String newline;
|
||||
try {
|
||||
newline = readDelimiter(delimiter);
|
||||
newline = readDelimiter(undecodedChunk, delimiter);
|
||||
} catch (NotEnoughDataDecoderException ignored) {
|
||||
undecodedChunk.readerIndex(readerIndex);
|
||||
return null;
|
||||
@ -686,8 +671,8 @@ public class HttpPostMultipartRequestDecoder implements InterfaceHttpPostRequest
|
||||
while (!skipOneLine()) {
|
||||
String newline;
|
||||
try {
|
||||
skipControlCharacters();
|
||||
newline = readLine();
|
||||
skipControlCharacters(undecodedChunk);
|
||||
newline = readLine(undecodedChunk, charset);
|
||||
} catch (NotEnoughDataDecoderException ignored) {
|
||||
undecodedChunk.readerIndex(readerIndex);
|
||||
return null;
|
||||
@ -899,7 +884,7 @@ public class HttpPostMultipartRequestDecoder implements InterfaceHttpPostRequest
|
||||
}
|
||||
// load data as much as possible
|
||||
try {
|
||||
readFileUploadByteMultipart(delimiter);
|
||||
readFileUploadByteMultipart(undecodedChunk, delimiter, currentFileUpload);
|
||||
} catch (NotEnoughDataDecoderException e) {
|
||||
// do not change the buffer position
|
||||
// since some can be already saved into FileUpload
|
||||
@ -986,7 +971,7 @@ public class HttpPostMultipartRequestDecoder implements InterfaceHttpPostRequest
|
||||
* Need more chunks and reset the {@code readerIndex} to the previous
|
||||
* value
|
||||
*/
|
||||
private String readLineStandard() {
|
||||
private static String readLineStandard(ByteBuf undecodedChunk, Charset charset) {
|
||||
int readerIndex = undecodedChunk.readerIndex();
|
||||
try {
|
||||
ByteBuf line = buffer(64);
|
||||
@ -1026,13 +1011,11 @@ public class HttpPostMultipartRequestDecoder implements InterfaceHttpPostRequest
|
||||
* Need more chunks and reset the {@code readerIndex} to the previous
|
||||
* value
|
||||
*/
|
||||
private String readLine() {
|
||||
SeekAheadOptimize sao;
|
||||
try {
|
||||
sao = new SeekAheadOptimize(undecodedChunk);
|
||||
} catch (SeekAheadNoBackArrayException ignored) {
|
||||
return readLineStandard();
|
||||
private static String readLine(ByteBuf undecodedChunk, Charset charset) {
|
||||
if (!undecodedChunk.hasArray()) {
|
||||
return readLineStandard(undecodedChunk, charset);
|
||||
}
|
||||
SeekAheadOptimize sao = new SeekAheadOptimize(undecodedChunk);
|
||||
int readerIndex = undecodedChunk.readerIndex();
|
||||
try {
|
||||
ByteBuf line = buffer(64);
|
||||
@ -1083,7 +1066,7 @@ public class HttpPostMultipartRequestDecoder implements InterfaceHttpPostRequest
|
||||
* Need more chunks and reset the {@code readerIndex} to the previous
|
||||
* value
|
||||
*/
|
||||
private String readDelimiterStandard(String delimiter) {
|
||||
private static String readDelimiterStandard(ByteBuf undecodedChunk, String delimiter) {
|
||||
int readerIndex = undecodedChunk.readerIndex();
|
||||
try {
|
||||
StringBuilder sb = new StringBuilder(64);
|
||||
@ -1177,13 +1160,11 @@ public class HttpPostMultipartRequestDecoder implements InterfaceHttpPostRequest
|
||||
* Need more chunks and reset the readerInder to the previous
|
||||
* value
|
||||
*/
|
||||
private String readDelimiter(String delimiter) {
|
||||
SeekAheadOptimize sao;
|
||||
try {
|
||||
sao = new SeekAheadOptimize(undecodedChunk);
|
||||
} catch (SeekAheadNoBackArrayException ignored) {
|
||||
return readDelimiterStandard(delimiter);
|
||||
private static String readDelimiter(ByteBuf undecodedChunk, String delimiter) {
|
||||
if (!undecodedChunk.hasArray()) {
|
||||
return readDelimiterStandard(undecodedChunk, delimiter);
|
||||
}
|
||||
SeekAheadOptimize sao = new SeekAheadOptimize(undecodedChunk);
|
||||
int readerIndex = undecodedChunk.readerIndex();
|
||||
int delimiterPos = 0;
|
||||
int len = delimiter.length();
|
||||
@ -1299,7 +1280,8 @@ public class HttpPostMultipartRequestDecoder implements InterfaceHttpPostRequest
|
||||
* @throws ErrorDataDecoderException
|
||||
* write IO error occurs with the FileUpload
|
||||
*/
|
||||
private void readFileUploadByteMultipartStandard(String delimiter) {
|
||||
private static void readFileUploadByteMultipartStandard(ByteBuf undecodedChunk, String delimiter,
|
||||
FileUpload currentFileUpload) {
|
||||
int readerIndex = undecodedChunk.readerIndex();
|
||||
// found the decoder limit
|
||||
boolean newLine = true;
|
||||
@ -1405,14 +1387,13 @@ public class HttpPostMultipartRequestDecoder implements InterfaceHttpPostRequest
|
||||
* @throws ErrorDataDecoderException
|
||||
* write IO error occurs with the FileUpload
|
||||
*/
|
||||
private void readFileUploadByteMultipart(String delimiter) {
|
||||
SeekAheadOptimize sao;
|
||||
try {
|
||||
sao = new SeekAheadOptimize(undecodedChunk);
|
||||
} catch (SeekAheadNoBackArrayException ignored) {
|
||||
readFileUploadByteMultipartStandard(delimiter);
|
||||
private static void readFileUploadByteMultipart(ByteBuf undecodedChunk, String delimiter,
|
||||
FileUpload currentFileUpload) {
|
||||
if (!undecodedChunk.hasArray()) {
|
||||
readFileUploadByteMultipartStandard(undecodedChunk, delimiter, currentFileUpload);
|
||||
return;
|
||||
}
|
||||
SeekAheadOptimize sao = new SeekAheadOptimize(undecodedChunk);
|
||||
int readerIndex = undecodedChunk.readerIndex();
|
||||
// found the decoder limit
|
||||
boolean newLine = true;
|
||||
@ -1518,7 +1499,8 @@ public class HttpPostMultipartRequestDecoder implements InterfaceHttpPostRequest
|
||||
* Need more chunks
|
||||
* @throws ErrorDataDecoderException
|
||||
*/
|
||||
private void loadFieldMultipartStandard(String delimiter) {
|
||||
private static void loadFieldMultipartStandard(ByteBuf undecodedChunk, String delimiter,
|
||||
Attribute currentAttribute) {
|
||||
int readerIndex = undecodedChunk.readerIndex();
|
||||
try {
|
||||
// found the decoder limit
|
||||
@ -1624,14 +1606,12 @@ public class HttpPostMultipartRequestDecoder implements InterfaceHttpPostRequest
|
||||
* Need more chunks
|
||||
* @throws ErrorDataDecoderException
|
||||
*/
|
||||
private void loadFieldMultipart(String delimiter) {
|
||||
SeekAheadOptimize sao;
|
||||
try {
|
||||
sao = new SeekAheadOptimize(undecodedChunk);
|
||||
} catch (SeekAheadNoBackArrayException ignored) {
|
||||
loadFieldMultipartStandard(delimiter);
|
||||
private static void loadFieldMultipart(ByteBuf undecodedChunk, String delimiter, Attribute currentAttribute) {
|
||||
if (!undecodedChunk.hasArray()) {
|
||||
loadFieldMultipartStandard(undecodedChunk, delimiter, currentAttribute);
|
||||
return;
|
||||
}
|
||||
SeekAheadOptimize sao = new SeekAheadOptimize(undecodedChunk);
|
||||
int readerIndex = undecodedChunk.readerIndex();
|
||||
try {
|
||||
// found the decoder limit
|
||||
|
@ -21,7 +21,6 @@ import io.netty.handler.codec.http.HttpContent;
|
||||
import io.netty.handler.codec.http.HttpRequest;
|
||||
import io.netty.handler.codec.http.LastHttpContent;
|
||||
import io.netty.handler.codec.http.QueryStringDecoder;
|
||||
import io.netty.handler.codec.http.multipart.HttpPostBodyUtil.SeekAheadNoBackArrayException;
|
||||
import io.netty.handler.codec.http.multipart.HttpPostBodyUtil.SeekAheadOptimize;
|
||||
import io.netty.handler.codec.http.multipart.HttpPostRequestDecoder.EndOfDataDecoderException;
|
||||
import io.netty.handler.codec.http.multipart.HttpPostRequestDecoder.ErrorDataDecoderException;
|
||||
@ -36,6 +35,7 @@ import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import static io.netty.buffer.Unpooled.*;
|
||||
import static io.netty.util.internal.ObjectUtil.*;
|
||||
|
||||
/**
|
||||
* This decoder will decode Body and can handle POST BODY.
|
||||
@ -145,18 +145,9 @@ public class HttpPostStandardRequestDecoder implements InterfaceHttpPostRequestD
|
||||
* errors
|
||||
*/
|
||||
public HttpPostStandardRequestDecoder(HttpDataFactory factory, HttpRequest request, Charset charset) {
|
||||
if (factory == null) {
|
||||
throw new NullPointerException("factory");
|
||||
}
|
||||
if (request == null) {
|
||||
throw new NullPointerException("request");
|
||||
}
|
||||
if (charset == null) {
|
||||
throw new NullPointerException("charset");
|
||||
}
|
||||
this.request = request;
|
||||
this.charset = charset;
|
||||
this.factory = factory;
|
||||
this.request = checkNotNull(request, "request");
|
||||
this.charset = checkNotNull(charset, "charset");
|
||||
this.factory = checkNotNull(factory, "factory");
|
||||
if (request instanceof HttpContent) {
|
||||
// Offer automatically if the given request is als type of HttpContent
|
||||
// See #1089
|
||||
@ -192,10 +183,7 @@ public class HttpPostStandardRequestDecoder implements InterfaceHttpPostRequestD
|
||||
*/
|
||||
@Override
|
||||
public void setDiscardThreshold(int discardThreshold) {
|
||||
if (discardThreshold < 0) {
|
||||
throw new IllegalArgumentException("discardThreshold must be >= 0");
|
||||
}
|
||||
this.discardThreshold = discardThreshold;
|
||||
this.discardThreshold = checkPositiveOrZero(discardThreshold, "discardThreshold");
|
||||
}
|
||||
|
||||
/**
|
||||
@ -513,13 +501,11 @@ public class HttpPostStandardRequestDecoder implements InterfaceHttpPostRequestD
|
||||
* errors
|
||||
*/
|
||||
private void parseBodyAttributes() {
|
||||
SeekAheadOptimize sao;
|
||||
try {
|
||||
sao = new SeekAheadOptimize(undecodedChunk);
|
||||
} catch (SeekAheadNoBackArrayException ignored) {
|
||||
if (!undecodedChunk.hasArray()) {
|
||||
parseBodyAttributesStandard();
|
||||
return;
|
||||
}
|
||||
SeekAheadOptimize sao = new SeekAheadOptimize(undecodedChunk);
|
||||
int firstpos = undecodedChunk.readerIndex();
|
||||
int currentpos = firstpos;
|
||||
int equalpos;
|
||||
@ -661,42 +647,6 @@ public class HttpPostStandardRequestDecoder implements InterfaceHttpPostRequestD
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Skip control Characters
|
||||
*/
|
||||
void skipControlCharacters() {
|
||||
SeekAheadOptimize sao;
|
||||
try {
|
||||
sao = new SeekAheadOptimize(undecodedChunk);
|
||||
} catch (SeekAheadNoBackArrayException ignored) {
|
||||
try {
|
||||
skipControlCharactersStandard();
|
||||
} catch (IndexOutOfBoundsException e) {
|
||||
throw new NotEnoughDataDecoderException(e);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
while (sao.pos < sao.limit) {
|
||||
char c = (char) (sao.bytes[sao.pos++] & 0xFF);
|
||||
if (!Character.isISOControl(c) && !Character.isWhitespace(c)) {
|
||||
sao.setReadPosition(1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
throw new NotEnoughDataDecoderException("Access out of bounds");
|
||||
}
|
||||
|
||||
void skipControlCharactersStandard() {
|
||||
for (;;) {
|
||||
char c = (char) undecodedChunk.readUnsignedByte();
|
||||
if (!Character.isISOControl(c) && !Character.isWhitespace(c)) {
|
||||
undecodedChunk.readerIndex(undecodedChunk.readerIndex() - 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy the {@link HttpPostStandardRequestDecoder} and release all it resources. After this method
|
||||
* was called it is not possible to operate on it anymore.
|
||||
|
Loading…
Reference in New Issue
Block a user