Use ByteBuf#writeShort/writeMedium instead of writeBytes
Motivation: 1. Some encoders used a `ByteBuf#writeBytes` to write short constant byte array (2-3 bytes). This can be replaced with more faster `ByteBuf#writeShort` or `ByteBuf#writeMedium` which do not access the memory. 2. Two chained calls of the `ByteBuf#setByte` with constants can be replaced with one `ByteBuf#setShort` to reduce index checks. 3. The signature of method `HttpHeadersEncoder#encoderHeader` has an unnecessary `throws`. Modifications: 1. Use `ByteBuf#writeShort` or `ByteBuf#writeMedium` instead of `ByteBuf#writeBytes` for the constants. 2. Use `ByteBuf#setShort` instead of chained call of the `ByteBuf#setByte` with constants. 3. Remove an unnecessary `throws` from `HttpHeadersEncoder#encoderHeader`. Result: A bit faster writes constants into buffers.
This commit is contained in:
parent
83db2b07b4
commit
df568c739e
@ -387,6 +387,30 @@ public final class ByteBufUtil {
|
||||
return Long.reverseBytes(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a big-endian 16-bit short integer to the buffer.
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public static ByteBuf writeShortBE(ByteBuf buf, int shortValue) {
|
||||
return buf.order() == ByteOrder.BIG_ENDIAN? buf.writeShort(shortValue) : buf.writeShortLE(shortValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a big-endian 16-bit short integer to the buffer.
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public static ByteBuf setShortBE(ByteBuf buf, int index, int shortValue) {
|
||||
return buf.order() == ByteOrder.BIG_ENDIAN? buf.setShort(index, shortValue) : buf.setShortLE(index, shortValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a big-endian 24-bit medium integer to the buffer.
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public static ByteBuf writeMediumBE(ByteBuf buf, int mediumValue) {
|
||||
return buf.order() == ByteOrder.BIG_ENDIAN? buf.writeMedium(mediumValue) : buf.writeMediumLE(mediumValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the given amount of bytes into a new {@link ByteBuf} that is allocated from the {@link ByteBufAllocator}.
|
||||
*/
|
||||
|
@ -19,6 +19,7 @@ import io.netty.util.AsciiString;
|
||||
import io.netty.util.CharsetUtil;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Arrays;
|
||||
import java.util.Random;
|
||||
@ -129,6 +130,66 @@ public class ByteBufUtilTest {
|
||||
-1));
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Test
|
||||
public void writeShortBE() {
|
||||
int expected = 0x1234;
|
||||
|
||||
ByteBuf buf = Unpooled.buffer(2).order(ByteOrder.BIG_ENDIAN);
|
||||
ByteBufUtil.writeShortBE(buf, expected);
|
||||
assertEquals(expected, buf.readShort());
|
||||
buf.resetReaderIndex();
|
||||
assertEquals(ByteBufUtil.swapShort((short) expected), buf.readShortLE());
|
||||
buf.release();
|
||||
|
||||
buf = Unpooled.buffer(2).order(ByteOrder.LITTLE_ENDIAN);
|
||||
ByteBufUtil.writeShortBE(buf, expected);
|
||||
assertEquals((short) expected, buf.readShortLE());
|
||||
buf.resetReaderIndex();
|
||||
assertEquals(ByteBufUtil.swapShort((short) expected), buf.readShort());
|
||||
buf.release();
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Test
|
||||
public void setShortBE() {
|
||||
int shortValue = 0x1234;
|
||||
|
||||
ByteBuf buf = Unpooled.wrappedBuffer(new byte[2]).order(ByteOrder.BIG_ENDIAN);
|
||||
ByteBufUtil.setShortBE(buf, 0, shortValue);
|
||||
assertEquals(shortValue, buf.readShort());
|
||||
buf.resetReaderIndex();
|
||||
assertEquals(ByteBufUtil.swapShort((short) shortValue), buf.readShortLE());
|
||||
buf.release();
|
||||
|
||||
buf = Unpooled.wrappedBuffer(new byte[2]).order(ByteOrder.LITTLE_ENDIAN);
|
||||
ByteBufUtil.setShortBE(buf, 0, shortValue);
|
||||
assertEquals((short) shortValue, buf.readShortLE());
|
||||
buf.resetReaderIndex();
|
||||
assertEquals(ByteBufUtil.swapShort((short) shortValue), buf.readShort());
|
||||
buf.release();
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Test
|
||||
public void writeMediumBE() {
|
||||
int mediumValue = 0x123456;
|
||||
|
||||
ByteBuf buf = Unpooled.buffer(4).order(ByteOrder.BIG_ENDIAN);
|
||||
ByteBufUtil.writeMediumBE(buf, mediumValue);
|
||||
assertEquals(mediumValue, buf.readMedium());
|
||||
buf.resetReaderIndex();
|
||||
assertEquals(ByteBufUtil.swapMedium(mediumValue), buf.readMediumLE());
|
||||
buf.release();
|
||||
|
||||
buf = Unpooled.buffer(4).order(ByteOrder.LITTLE_ENDIAN);
|
||||
ByteBufUtil.writeMediumBE(buf, mediumValue);
|
||||
assertEquals(mediumValue, buf.readMediumLE());
|
||||
buf.resetReaderIndex();
|
||||
assertEquals(ByteBufUtil.swapMedium(mediumValue), buf.readMedium());
|
||||
buf.release();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWriteUsAscii() {
|
||||
String usAscii = "NettyRocks";
|
||||
|
@ -21,12 +21,16 @@ import io.netty.buffer.ByteBufUtil;
|
||||
import io.netty.util.AsciiString;
|
||||
import io.netty.util.CharsetUtil;
|
||||
|
||||
import static io.netty.handler.codec.http.HttpConstants.*;
|
||||
import static io.netty.handler.codec.http.HttpObjectEncoder.CRLF_SHORT;
|
||||
|
||||
final class HttpHeadersEncoder {
|
||||
private static final int COLON_AND_SPACE_SHORT = (COLON << 8) | SP;
|
||||
|
||||
private HttpHeadersEncoder() {
|
||||
}
|
||||
|
||||
static void encoderHeader(CharSequence name, CharSequence value, ByteBuf buf) throws Exception {
|
||||
static void encoderHeader(CharSequence name, CharSequence value, ByteBuf buf) {
|
||||
final int nameLen = name.length();
|
||||
final int valueLen = value.length();
|
||||
final int entryLen = nameLen + valueLen + 4;
|
||||
@ -34,12 +38,12 @@ final class HttpHeadersEncoder {
|
||||
int offset = buf.writerIndex();
|
||||
writeAscii(buf, offset, name);
|
||||
offset += nameLen;
|
||||
buf.setByte(offset ++, ':');
|
||||
buf.setByte(offset ++, ' ');
|
||||
ByteBufUtil.setShortBE(buf, offset, COLON_AND_SPACE_SHORT);
|
||||
offset += 2;
|
||||
writeAscii(buf, offset, value);
|
||||
offset += valueLen;
|
||||
buf.setByte(offset ++, '\r');
|
||||
buf.setByte(offset ++, '\n');
|
||||
ByteBufUtil.setShortBE(buf, offset, CRLF_SHORT);
|
||||
offset += 2;
|
||||
buf.writerIndex(offset);
|
||||
}
|
||||
|
||||
|
@ -16,11 +16,11 @@
|
||||
package io.netty.handler.codec.http;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.ByteBufUtil;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.FileRegion;
|
||||
import io.netty.handler.codec.MessageToMessageEncoder;
|
||||
import io.netty.util.CharsetUtil;
|
||||
import io.netty.util.internal.PlatformDependent;
|
||||
import io.netty.util.internal.StringUtil;
|
||||
|
||||
import java.util.Iterator;
|
||||
@ -47,10 +47,10 @@ import static io.netty.handler.codec.http.HttpConstants.LF;
|
||||
* implement all abstract methods properly.
|
||||
*/
|
||||
public abstract class HttpObjectEncoder<H extends HttpMessage> extends MessageToMessageEncoder<Object> {
|
||||
static final byte[] CRLF = { CR, LF };
|
||||
private static final byte[] ZERO_CRLF = { '0', CR, LF };
|
||||
static final int CRLF_SHORT = (CR << 8) | LF;
|
||||
private static final int ZERO_CRLF_MEDIUM = ('0' << 16) | CRLF_SHORT;
|
||||
private static final byte[] ZERO_CRLF_CRLF = { '0', CR, LF, CR, LF };
|
||||
private static final ByteBuf CRLF_BUF = unreleasableBuffer(directBuffer(CRLF.length).writeBytes(CRLF));
|
||||
private static final ByteBuf CRLF_BUF = unreleasableBuffer(directBuffer(2).writeByte(CR).writeByte(LF));
|
||||
private static final ByteBuf ZERO_CRLF_CRLF_BUF = unreleasableBuffer(directBuffer(ZERO_CRLF_CRLF.length)
|
||||
.writeBytes(ZERO_CRLF_CRLF));
|
||||
|
||||
@ -77,7 +77,7 @@ public abstract class HttpObjectEncoder<H extends HttpMessage> extends MessageTo
|
||||
// Encode the message.
|
||||
encodeInitialLine(buf, m);
|
||||
encodeHeaders(m.headers(), buf);
|
||||
buf.writeBytes(CRLF);
|
||||
ByteBufUtil.writeShortBE(buf, CRLF_SHORT);
|
||||
state = isContentAlwaysEmpty(m) ? ST_CONTENT_ALWAYS_EMPTY :
|
||||
HttpUtil.isTransferEncodingChunked(m) ? ST_CONTENT_CHUNK : ST_CONTENT_NON_CHUNK;
|
||||
}
|
||||
@ -153,7 +153,7 @@ public abstract class HttpObjectEncoder<H extends HttpMessage> extends MessageTo
|
||||
/**
|
||||
* Encode the {@link HttpHeaders} into a {@link ByteBuf}.
|
||||
*/
|
||||
protected void encodeHeaders(HttpHeaders headers, ByteBuf buf) throws Exception {
|
||||
protected void encodeHeaders(HttpHeaders headers, ByteBuf buf) {
|
||||
Iterator<Entry<CharSequence, CharSequence>> iter = headers.iteratorCharSequence();
|
||||
while (iter.hasNext()) {
|
||||
Entry<CharSequence, CharSequence> header = iter.next();
|
||||
@ -166,7 +166,7 @@ public abstract class HttpObjectEncoder<H extends HttpMessage> extends MessageTo
|
||||
String lengthHex = Long.toHexString(contentLength);
|
||||
ByteBuf buf = ctx.alloc().buffer(lengthHex.length() + 2);
|
||||
buf.writeCharSequence(lengthHex, CharsetUtil.US_ASCII);
|
||||
buf.writeBytes(CRLF);
|
||||
ByteBufUtil.writeShortBE(buf, CRLF_SHORT);
|
||||
out.add(buf);
|
||||
out.add(encodeAndRetain(msg));
|
||||
out.add(CRLF_BUF.duplicate());
|
||||
@ -178,19 +178,14 @@ public abstract class HttpObjectEncoder<H extends HttpMessage> extends MessageTo
|
||||
out.add(ZERO_CRLF_CRLF_BUF.duplicate());
|
||||
} else {
|
||||
ByteBuf buf = ctx.alloc().buffer();
|
||||
buf.writeBytes(ZERO_CRLF);
|
||||
try {
|
||||
encodeHeaders(headers, buf);
|
||||
} catch (Exception ex) {
|
||||
buf.release();
|
||||
PlatformDependent.throwException(ex);
|
||||
}
|
||||
buf.writeBytes(CRLF);
|
||||
ByteBufUtil.writeMediumBE(buf, ZERO_CRLF_MEDIUM);
|
||||
encodeHeaders(headers, buf);
|
||||
ByteBufUtil.writeShortBE(buf, CRLF_SHORT);
|
||||
out.add(buf);
|
||||
}
|
||||
} else if (contentLength == 0) {
|
||||
// Need to produce some output otherwise an
|
||||
// IllegalstateException will be thrown
|
||||
// IllegalStateException will be thrown
|
||||
out.add(EMPTY_BUFFER);
|
||||
}
|
||||
}
|
||||
|
@ -28,6 +28,8 @@ import static io.netty.handler.codec.http.HttpConstants.SP;
|
||||
public class HttpRequestEncoder extends HttpObjectEncoder<HttpRequest> {
|
||||
private static final char SLASH = '/';
|
||||
private static final char QUESTION_MARK = '?';
|
||||
private static final int SLASH_AND_SPACE_SHORT = (SLASH << 8) | SP;
|
||||
private static final int SPACE_SLASH_AND_SPACE_MEDIUM = (SP << 16) | SLASH_AND_SPACE_SHORT;
|
||||
|
||||
@Override
|
||||
public boolean acceptOutboundMessage(Object msg) throws Exception {
|
||||
@ -37,37 +39,42 @@ public class HttpRequestEncoder extends HttpObjectEncoder<HttpRequest> {
|
||||
@Override
|
||||
protected void encodeInitialLine(ByteBuf buf, HttpRequest request) throws Exception {
|
||||
ByteBufUtil.copy(request.method().asciiName(), buf);
|
||||
buf.writeByte(SP);
|
||||
|
||||
// Add / as absolute path if no is present.
|
||||
// See http://tools.ietf.org/html/rfc2616#section-5.1.2
|
||||
String uri = request.uri();
|
||||
|
||||
if (uri.isEmpty()) {
|
||||
uri += SLASH;
|
||||
// Add " / " as absolute path if uri is not present.
|
||||
// See http://tools.ietf.org/html/rfc2616#section-5.1.2
|
||||
ByteBufUtil.writeMediumBE(buf, SPACE_SLASH_AND_SPACE_MEDIUM);
|
||||
} else {
|
||||
CharSequence uriCharSequence = uri;
|
||||
boolean needSlash = false;
|
||||
int start = uri.indexOf("://");
|
||||
if (start != -1 && uri.charAt(0) != SLASH) {
|
||||
int startIndex = start + 3;
|
||||
start += 3;
|
||||
// Correctly handle query params.
|
||||
// See https://github.com/netty/netty/issues/2732
|
||||
int index = uri.indexOf(QUESTION_MARK, startIndex);
|
||||
int index = uri.indexOf(QUESTION_MARK, start);
|
||||
if (index == -1) {
|
||||
if (uri.lastIndexOf(SLASH) <= startIndex) {
|
||||
uri += SLASH;
|
||||
if (uri.lastIndexOf(SLASH) <= start) {
|
||||
needSlash = true;
|
||||
}
|
||||
} else {
|
||||
if (uri.lastIndexOf(SLASH, index) <= startIndex) {
|
||||
uri = new StringBuilder(uri).insert(index, SLASH).toString();
|
||||
if (uri.lastIndexOf(SLASH, index) <= start) {
|
||||
uriCharSequence = new StringBuilder(uri).insert(index, SLASH);
|
||||
}
|
||||
}
|
||||
}
|
||||
buf.writeByte(SP).writeCharSequence(uriCharSequence, CharsetUtil.UTF_8);
|
||||
if (needSlash) {
|
||||
// write "/ " after uri
|
||||
ByteBufUtil.writeShortBE(buf, SLASH_AND_SPACE_SHORT);
|
||||
} else {
|
||||
buf.writeByte(SP);
|
||||
}
|
||||
}
|
||||
|
||||
buf.writeCharSequence(uri, CharsetUtil.UTF_8);
|
||||
|
||||
buf.writeByte(SP);
|
||||
request.protocolVersion().encode(buf);
|
||||
buf.writeBytes(CRLF);
|
||||
ByteBufUtil.writeShortBE(buf, CRLF_SHORT);
|
||||
}
|
||||
}
|
||||
|
@ -16,6 +16,7 @@
|
||||
package io.netty.handler.codec.http;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.ByteBufUtil;
|
||||
|
||||
import static io.netty.handler.codec.http.HttpConstants.*;
|
||||
|
||||
@ -35,6 +36,6 @@ public class HttpResponseEncoder extends HttpObjectEncoder<HttpResponse> {
|
||||
response.protocolVersion().encode(buf);
|
||||
buf.writeByte(SP);
|
||||
response.status().encode(buf);
|
||||
buf.writeBytes(CRLF);
|
||||
ByteBufUtil.writeShortBE(buf, CRLF_SHORT);
|
||||
}
|
||||
}
|
||||
|
@ -15,9 +15,6 @@
|
||||
*/
|
||||
package io.netty.handler.codec.rtsp;
|
||||
|
||||
import static io.netty.handler.codec.http.HttpConstants.CR;
|
||||
import static io.netty.handler.codec.http.HttpConstants.LF;
|
||||
import static io.netty.handler.codec.http.HttpConstants.SP;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.ByteBufUtil;
|
||||
import io.netty.handler.codec.UnsupportedMessageTypeException;
|
||||
@ -29,15 +26,14 @@ import io.netty.handler.codec.http.HttpResponse;
|
||||
import io.netty.util.CharsetUtil;
|
||||
import io.netty.util.internal.StringUtil;
|
||||
|
||||
import static io.netty.handler.codec.http.HttpConstants.*;
|
||||
|
||||
/**
|
||||
* Encodes an RTSP message represented in {@link HttpMessage} or an {@link HttpContent} into
|
||||
* a {@link ByteBuf}.
|
||||
*/
|
||||
public class RtspEncoder extends HttpObjectEncoder<HttpMessage> {
|
||||
/**
|
||||
* Constant for CRLF.
|
||||
*/
|
||||
private static final byte[] CRLF = {CR, LF};
|
||||
private static final int CRLF_SHORT = (CR << 8) | LF;
|
||||
|
||||
@Override
|
||||
public boolean acceptOutboundMessage(final Object msg)
|
||||
@ -55,7 +51,7 @@ public class RtspEncoder extends HttpObjectEncoder<HttpMessage> {
|
||||
buf.writeCharSequence(request.uri(), CharsetUtil.UTF_8);
|
||||
buf.writeByte(SP);
|
||||
buf.writeCharSequence(request.protocolVersion().toString(), CharsetUtil.US_ASCII);
|
||||
buf.writeBytes(CRLF);
|
||||
ByteBufUtil.writeShortBE(buf, CRLF_SHORT);
|
||||
} else if (message instanceof HttpResponse) {
|
||||
HttpResponse response = (HttpResponse) message;
|
||||
buf.writeCharSequence(response.protocolVersion().toString(), CharsetUtil.US_ASCII);
|
||||
@ -63,7 +59,7 @@ public class RtspEncoder extends HttpObjectEncoder<HttpMessage> {
|
||||
ByteBufUtil.copy(response.status().codeAsText(), buf);
|
||||
buf.writeByte(SP);
|
||||
buf.writeCharSequence(response.status().reasonPhrase(), CharsetUtil.US_ASCII);
|
||||
buf.writeBytes(CRLF);
|
||||
ByteBufUtil.writeShortBE(buf, CRLF_SHORT);
|
||||
} else {
|
||||
throw new UnsupportedMessageTypeException("Unsupported type "
|
||||
+ StringUtil.simpleClassName(message));
|
||||
|
@ -19,6 +19,8 @@ import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
@ -27,80 +29,97 @@ import static org.junit.Assert.*;
|
||||
*/
|
||||
public class HttpRequestEncoderTest {
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
private static ByteBuf[] getBuffers() {
|
||||
return new ByteBuf[]{
|
||||
Unpooled.buffer(128).order(ByteOrder.BIG_ENDIAN),
|
||||
Unpooled.buffer(128).order(ByteOrder.LITTLE_ENDIAN),
|
||||
Unpooled.wrappedBuffer(ByteBuffer.allocate(128).order(ByteOrder.BIG_ENDIAN)).resetWriterIndex(),
|
||||
Unpooled.wrappedBuffer(ByteBuffer.allocate(128).order(ByteOrder.LITTLE_ENDIAN)).resetWriterIndex()
|
||||
};
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUriWithoutPath() throws Exception {
|
||||
HttpRequestEncoder encoder = new HttpRequestEncoder();
|
||||
ByteBuf buffer = Unpooled.buffer(64);
|
||||
encoder.encodeInitialLine(buffer, new DefaultHttpRequest(HttpVersion.HTTP_1_1,
|
||||
HttpMethod.GET, "http://localhost"));
|
||||
String req = buffer.toString(Charset.forName("US-ASCII"));
|
||||
assertEquals("GET http://localhost/ HTTP/1.1\r\n", req);
|
||||
buffer.release();
|
||||
for (ByteBuf buffer : getBuffers()) {
|
||||
HttpRequestEncoder encoder = new HttpRequestEncoder();
|
||||
encoder.encodeInitialLine(buffer, new DefaultHttpRequest(HttpVersion.HTTP_1_1,
|
||||
HttpMethod.GET, "http://localhost"));
|
||||
String req = buffer.toString(Charset.forName("US-ASCII"));
|
||||
assertEquals("GET http://localhost/ HTTP/1.1\r\n", req);
|
||||
buffer.release();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUriWithoutPath2() throws Exception {
|
||||
HttpRequestEncoder encoder = new HttpRequestEncoder();
|
||||
ByteBuf buffer = Unpooled.buffer(64);
|
||||
encoder.encodeInitialLine(buffer, new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET,
|
||||
"http://localhost:9999?p1=v1"));
|
||||
String req = buffer.toString(Charset.forName("US-ASCII"));
|
||||
assertEquals("GET http://localhost:9999/?p1=v1 HTTP/1.1\r\n", req);
|
||||
buffer.release();
|
||||
for (ByteBuf buffer : getBuffers()) {
|
||||
HttpRequestEncoder encoder = new HttpRequestEncoder();
|
||||
encoder.encodeInitialLine(buffer, new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET,
|
||||
"http://localhost:9999?p1=v1"));
|
||||
String req = buffer.toString(Charset.forName("US-ASCII"));
|
||||
assertEquals("GET http://localhost:9999/?p1=v1 HTTP/1.1\r\n", req);
|
||||
buffer.release();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUriWithEmptyPath() throws Exception {
|
||||
HttpRequestEncoder encoder = new HttpRequestEncoder();
|
||||
ByteBuf buffer = Unpooled.buffer(64);
|
||||
encoder.encodeInitialLine(buffer, new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET,
|
||||
"http://localhost:9999/?p1=v1"));
|
||||
String req = buffer.toString(Charset.forName("US-ASCII"));
|
||||
assertEquals("GET http://localhost:9999/?p1=v1 HTTP/1.1\r\n", req);
|
||||
buffer.release();
|
||||
for (ByteBuf buffer : getBuffers()) {
|
||||
HttpRequestEncoder encoder = new HttpRequestEncoder();
|
||||
encoder.encodeInitialLine(buffer, new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET,
|
||||
"http://localhost:9999/?p1=v1"));
|
||||
String req = buffer.toString(Charset.forName("US-ASCII"));
|
||||
assertEquals("GET http://localhost:9999/?p1=v1 HTTP/1.1\r\n", req);
|
||||
buffer.release();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUriWithPath() throws Exception {
|
||||
HttpRequestEncoder encoder = new HttpRequestEncoder();
|
||||
ByteBuf buffer = Unpooled.buffer(64);
|
||||
encoder.encodeInitialLine(buffer, new DefaultHttpRequest(HttpVersion.HTTP_1_1,
|
||||
HttpMethod.GET, "http://localhost/"));
|
||||
String req = buffer.toString(Charset.forName("US-ASCII"));
|
||||
assertEquals("GET http://localhost/ HTTP/1.1\r\n", req);
|
||||
buffer.release();
|
||||
for (ByteBuf buffer : getBuffers()) {
|
||||
HttpRequestEncoder encoder = new HttpRequestEncoder();
|
||||
encoder.encodeInitialLine(buffer, new DefaultHttpRequest(HttpVersion.HTTP_1_1,
|
||||
HttpMethod.GET, "http://localhost/"));
|
||||
String req = buffer.toString(Charset.forName("US-ASCII"));
|
||||
assertEquals("GET http://localhost/ HTTP/1.1\r\n", req);
|
||||
buffer.release();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAbsPath() throws Exception {
|
||||
HttpRequestEncoder encoder = new HttpRequestEncoder();
|
||||
ByteBuf buffer = Unpooled.buffer(64);
|
||||
encoder.encodeInitialLine(buffer, new DefaultHttpRequest(HttpVersion.HTTP_1_1,
|
||||
HttpMethod.GET, "/"));
|
||||
String req = buffer.toString(Charset.forName("US-ASCII"));
|
||||
assertEquals("GET / HTTP/1.1\r\n", req);
|
||||
buffer.release();
|
||||
for (ByteBuf buffer : getBuffers()) {
|
||||
HttpRequestEncoder encoder = new HttpRequestEncoder();
|
||||
encoder.encodeInitialLine(buffer, new DefaultHttpRequest(HttpVersion.HTTP_1_1,
|
||||
HttpMethod.GET, "/"));
|
||||
String req = buffer.toString(Charset.forName("US-ASCII"));
|
||||
assertEquals("GET / HTTP/1.1\r\n", req);
|
||||
buffer.release();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmptyAbsPath() throws Exception {
|
||||
HttpRequestEncoder encoder = new HttpRequestEncoder();
|
||||
ByteBuf buffer = Unpooled.buffer(64);
|
||||
encoder.encodeInitialLine(buffer, new DefaultHttpRequest(HttpVersion.HTTP_1_1,
|
||||
HttpMethod.GET, ""));
|
||||
String req = buffer.toString(Charset.forName("US-ASCII"));
|
||||
assertEquals("GET / HTTP/1.1\r\n", req);
|
||||
buffer.release();
|
||||
for (ByteBuf buffer : getBuffers()) {
|
||||
HttpRequestEncoder encoder = new HttpRequestEncoder();
|
||||
encoder.encodeInitialLine(buffer, new DefaultHttpRequest(HttpVersion.HTTP_1_1,
|
||||
HttpMethod.GET, ""));
|
||||
String req = buffer.toString(Charset.forName("US-ASCII"));
|
||||
assertEquals("GET / HTTP/1.1\r\n", req);
|
||||
buffer.release();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQueryStringPath() throws Exception {
|
||||
HttpRequestEncoder encoder = new HttpRequestEncoder();
|
||||
ByteBuf buffer = Unpooled.buffer(64);
|
||||
encoder.encodeInitialLine(buffer, new DefaultHttpRequest(HttpVersion.HTTP_1_1,
|
||||
HttpMethod.GET, "/?url=http://example.com"));
|
||||
String req = buffer.toString(Charset.forName("US-ASCII"));
|
||||
assertEquals("GET /?url=http://example.com HTTP/1.1\r\n", req);
|
||||
buffer.release();
|
||||
for (ByteBuf buffer : getBuffers()) {
|
||||
HttpRequestEncoder encoder = new HttpRequestEncoder();
|
||||
encoder.encodeInitialLine(buffer, new DefaultHttpRequest(HttpVersion.HTTP_1_1,
|
||||
HttpMethod.GET, "/?url=http://example.com"));
|
||||
String req = buffer.toString(Charset.forName("US-ASCII"));
|
||||
assertEquals("GET /?url=http://example.com HTTP/1.1\r\n", req);
|
||||
buffer.release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -31,11 +31,10 @@ import java.util.RandomAccess;
|
||||
*/
|
||||
@UnstableApi
|
||||
public final class SmtpRequestEncoder extends MessageToMessageEncoder<Object> {
|
||||
private static final byte[] CRLF = {'\r', '\n'};
|
||||
private static final byte[] DOT_CRLF = {'.', '\r', '\n'};
|
||||
private static final int CRLF_SHORT = ('\r' << 8) | '\n';
|
||||
private static final byte SP = ' ';
|
||||
private static final ByteBuf DOT_CRLF_BUFFER = Unpooled.unreleasableBuffer(
|
||||
Unpooled.directBuffer(3).writeBytes(DOT_CRLF));
|
||||
Unpooled.directBuffer(3).writeByte('.').writeByte('\r').writeByte('\n'));
|
||||
|
||||
private boolean contentExpected;
|
||||
|
||||
@ -60,7 +59,7 @@ public final class SmtpRequestEncoder extends MessageToMessageEncoder<Object> {
|
||||
try {
|
||||
req.command().encode(buffer);
|
||||
writeParameters(req.parameters(), buffer);
|
||||
buffer.writeBytes(CRLF);
|
||||
ByteBufUtil.writeShortBE(buffer, CRLF_SHORT);
|
||||
out.add(buffer);
|
||||
release = false;
|
||||
if (req.command().isContentExpected()) {
|
||||
|
@ -27,7 +27,7 @@ import org.openjdk.jmh.annotations.Scope;
|
||||
import org.openjdk.jmh.annotations.State;
|
||||
import org.openjdk.jmh.annotations.Warmup;
|
||||
|
||||
import static io.netty.handler.codec.http.HttpConstants.SP;
|
||||
import static io.netty.handler.codec.http.HttpConstants.*;
|
||||
|
||||
@State(Scope.Benchmark)
|
||||
@Warmup(iterations = 10)
|
||||
@ -62,7 +62,8 @@ public class HttpRequestEncoderInsertBenchmark extends AbstractMicrobenchmark {
|
||||
}
|
||||
}
|
||||
|
||||
private class OldHttpRequestEncoder extends HttpObjectEncoder<HttpRequest> {
|
||||
private static class OldHttpRequestEncoder extends HttpObjectEncoder<HttpRequest> {
|
||||
private static final byte[] CRLF = {CR, LF};
|
||||
private static final char SLASH = '/';
|
||||
private static final char QUESTION_MARK = '?';
|
||||
|
||||
|
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright 2017 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you under the Apache License,
|
||||
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package io.netty.handler.codec.http;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.ByteBufUtil;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.microbench.util.AbstractMicrobenchmark;
|
||||
import org.openjdk.jmh.annotations.Benchmark;
|
||||
import org.openjdk.jmh.annotations.Measurement;
|
||||
import org.openjdk.jmh.annotations.OutputTimeUnit;
|
||||
import org.openjdk.jmh.annotations.Threads;
|
||||
import org.openjdk.jmh.annotations.Warmup;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static io.netty.handler.codec.http.HttpConstants.*;
|
||||
|
||||
@Threads(1)
|
||||
@Warmup(iterations = 3)
|
||||
@Measurement(iterations = 3)
|
||||
@OutputTimeUnit(TimeUnit.MICROSECONDS)
|
||||
public class WriteBytesVsShortOrMediumBenchmark extends AbstractMicrobenchmark {
|
||||
private static final int CRLF_SHORT = (CR << 8) + LF;
|
||||
private static final byte[] CRLF = { CR, LF };
|
||||
private static final int ZERO_CRLF_MEDIUM = ('0' << 16) + (CR << 8) + LF;
|
||||
private static final byte[] ZERO_CRLF = { '0', CR, LF };
|
||||
|
||||
private final ByteBuf buf = Unpooled.directBuffer(16);
|
||||
|
||||
@Benchmark
|
||||
public ByteBuf shortInt() {
|
||||
return ByteBufUtil.writeShortBE(buf, CRLF_SHORT).resetWriterIndex();
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public ByteBuf mediumInt() {
|
||||
return ByteBufUtil.writeMediumBE(buf, ZERO_CRLF_MEDIUM).resetWriterIndex();
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public ByteBuf byteArray2() {
|
||||
return buf.writeBytes(CRLF).resetWriterIndex();
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public ByteBuf byteArray3() {
|
||||
return buf.writeBytes(ZERO_CRLF).resetWriterIndex();
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public ByteBuf chainedBytes2() {
|
||||
return buf.writeByte(CR).writeByte(LF).resetWriterIndex();
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public ByteBuf chainedBytes3() {
|
||||
return buf.writeByte('0').writeByte(CR).writeByte(LF).resetWriterIndex();
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user