8000 Reset Utf8ByteBufCharsetDecoder splitCharBuffer, close #1325 · chakra-coder/async-http-client@4a946b5 · GitHub
[go: up one dir, main page]

Skip to content 8000

Commit 4a946b5

Browse files
committed
Reset Utf8ByteBufCharsetDecoder splitCharBuffer, close AsyncHttpClient#1325
Motivation: Utf8ByteBufCharsetDecoder crashes with BufferOverflow when trying to decode a char whose byte length is larger than the one of the first split char that was decoded. This happens because we only reset position while we should be resetting capacity too. Modifications: User ByteBuffer reset instead os `position(0)`. Result: No more BufferOverflow
1 parent f4a4d15 commit 4a946b5

File tree

2 files changed

+40
-20
lines changed

2 files changed

+40
-20
lines changed

netty-utils/src/main/java/org/asynchttpclient/netty/util/Utf8ByteBufCharsetDecoder.java

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@
2424

2525
public class Utf8ByteBufCharsetDecoder {
2626

27+
private static final int INITIAL_CHAR_BUFFER_SIZE = 1024;
28+
private static final int UTF_8_MAX_BYTES_PER_CHAR = 4;
29+
2730
private static final ThreadLocal<Utf8ByteBufCharsetDecoder> POOL = new ThreadLocal<Utf8ByteBufCharsetDecoder>() {
2831
protected Utf8ByteBufCharsetDecoder initialValue() {
2932
return new Utf8ByteBufCharsetDecoder();
@@ -45,15 +48,8 @@ public static String decodeUtf8(ByteBuf... bufs) throws CharacterCodingException
4548
}
4649

4750
private final CharsetDecoder decoder = UTF_8.newDecoder();
48-
protected CharBuffer charBuffer = allocateCharBuffer(1024);
49-
private ByteBuffer splitCharBuffer;
50-
51-
protected void initSplitCharBuffer() {
52-
if (splitCharBuffer == null) {
53-
// UTF-8 chars are 4 bytes max
54-
splitCharBuffer = ByteBuffer.allocate(4);
55-
}
56-
}
51+
protected CharBuffer charBuffer = allocateCharBuffer(INITIAL_CHAR_BUFFER_SIZE);
52+
private ByteBuffer splitCharBuffer = ByteBuffer.allocate(UTF_8_MAX_BYTES_PER_CHAR);
5753

5854
protected CharBuffer allocateCharBuffer(int l) {
5955
return CharBuffer.allocate(l);
@@ -75,6 +71,7 @@ private void ensureCapacity(int l) {
7571
public void reset() {
7672
decoder.reset();
7773
charBuffer.clear();
74+
splitCharBuffer.clear();
7875
}
7976

8077
private static int charSize(byte firstByte) throws CharacterCodingException {
@@ -119,8 +116,6 @@ private void handleSplitCharBuffer(ByteBuffer nioBuffer, boolean endOfInput) thr
119116
if (res.isError()) {
120117
res.throwException();
121118
}
122-
123-
splitCharBuffer.position(0);
124119
}
125120
}
126121

@@ -135,7 +130,6 @@ protected void decodePartial(ByteBuffer nioBuffer, boolean endOfInput) throws Ch
135130
CoderResult res = decoder.decode(nioBuffer, charBuffer, endOfInput);
136131
if (res.isUnderflow()) {
137132
if (nioBuffer.remaining() > 0) {
138-
initSplitCharBuffer();
139133
splitCharBuffer.put(nioBuffer);
140134
}
141135
} else if (res.isError()) {

netty-utils/src/test/java/org/asynchttpclient/netty/util/ByteBufUtilsTest.java

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
*/
1414
package org.asynchttpclient.netty.util;
1515

16-
import static java.nio.charset.StandardCharsets.US_ASCII;
16+
import static java.nio.charset.StandardCharsets.*;
1717
import static org.testng.Assert.assertEquals;
1818
import io.netty.buffer.ByteBuf;
1919
import io.netty.buffer.Unpooled;
@@ -25,17 +25,43 @@ public class ByteBufUtilsTest {
2525
@Test
2626
public void testByteBuf2BytesHasBackingArray() {
2727
byte[] inputBytes = "testdata".getBytes(US_ASCII);
28-
ByteBuf inputBuf = Unpooled.wrappedBuffer(inputBytes);
29-
byte[] output = ByteBufUtils.byteBuf2Bytes(inputBuf);
30-
assertEquals(output, inputBytes);
28+
ByteBuf buf = Unpooled.wrappedBuffer(inputBytes);
29+
try {
30+
byte[] output = ByteBufUtils.byteBuf2Bytes(buf);
31+
assertEquals(output, inputBytes);
32+
} finally {
33+
buf.release();
34+
}
3135
}
3236

3337
@Test
3438
public void testByteBuf2BytesNoBackingArray() {
3539
byte[] inputBytes = "testdata".getBytes(US_ASCII);
36-
ByteBuf inputBuf = Unpooled.directBuffer();
37-
inputBuf.writeBytes(inputBytes);
38-
byte[] output = ByteBufUtils.byteBuf2Bytes(inputBuf);
39-
assertEquals(output, inputBytes);
40+
ByteBuf buf = Unpooled.directBuffer();
41+
try {
42+
buf.writeBytes(inputBytes);
43+
byte[] output = ByteBufUtils.byteBuf2Bytes(buf);
44+
assertEquals(output, inputBytes);
45+
} finally {
46+
buf.release();
47+
}
48+
}
49+
50+
@Test
51+
public void byteBufs2StringShouldBeAbleToDealWithCharsWithVariableBytesLength() throws Exception {
52+
String inputString = "°ä–";
53+
byte[] inputBytes = inputString.getBytes(UTF_8);
54+
55+
for (int i = 1; i < inputBytes.length - 1; i++) {
56+
ByteBuf buf1 = Unpooled.wrappedBuffer(inputBytes, 0, i);
57+
ByteBuf buf2 = Unpooled.wrappedBuffer(inputBytes, i, inputBytes.length - i);
58+
try {
59+
String s = ByteBufUtils.byteBuf2String(UTF_8, buf1, buf2);
60+
assertEquals(s, inputString);
61+
} finally {
62+
buf1.release();
63+
buf2.release();
64+
}
65+
}
4066
}
4167
}

0 commit comments

Comments
 (0)
0