Change the type of HTTP string properties to AsciiString

Related: #3132

Motivation:

Changing the type of the string properties of HttpVersion and
HttpResponseStatus to AsciiString will give us the performance advantage
when encoding it into the wire.

Modifications:

- Change the type of the following properties to AsciiString:
  - HttpVersion.protocolName()
  - HttpVersion.text()
  - HttpResponseStatus.reasonPhrase()
- Inline their respective encode() methods because they are used only in
  the encoders.
- Fix the test failures incurred by the changes above

Result:

Getting close to the machine
This commit is contained in:
Trustin Lee 2014-12-06 18:42:58 +09:00
parent 377ef31bb1
commit 97bf8a6d61
7 changed files with 55 additions and 79 deletions

View File

@ -39,7 +39,6 @@ public class HttpRequestEncoder extends HttpObjectEncoder<HttpRequest> {
protected void encodeInitialLine(ByteBuf buf, HttpRequest request) throws Exception { protected void encodeInitialLine(ByteBuf buf, HttpRequest request) throws Exception {
AsciiString method = request.method().name(); AsciiString method = request.method().name();
buf.writeBytes(method.array(), method.arrayOffset(), method.length()); buf.writeBytes(method.array(), method.arrayOffset(), method.length());
buf.writeByte(SP); buf.writeByte(SP);
// Add / as absolute path if no is present. // Add / as absolute path if no is present.
@ -73,9 +72,10 @@ public class HttpRequestEncoder extends HttpObjectEncoder<HttpRequest> {
} }
buf.writeBytes(uri.getBytes(CharsetUtil.UTF_8)); buf.writeBytes(uri.getBytes(CharsetUtil.UTF_8));
buf.writeByte(SP); buf.writeByte(SP);
request.protocolVersion().encode(buf);
AsciiString version = request.protocolVersion().text();
buf.writeBytes(version.array(), version.arrayOffset(), version.length());
buf.writeBytes(CRLF); buf.writeBytes(CRLF);
} }
} }

View File

@ -16,6 +16,7 @@
package io.netty.handler.codec.http; package io.netty.handler.codec.http;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import io.netty.handler.codec.AsciiString;
import static io.netty.handler.codec.http.HttpConstants.*; import static io.netty.handler.codec.http.HttpConstants.*;
@ -33,9 +34,16 @@ public class HttpResponseEncoder extends HttpObjectEncoder<HttpResponse> {
@Override @Override
protected void encodeInitialLine(ByteBuf buf, HttpResponse response) throws Exception { protected void encodeInitialLine(ByteBuf buf, HttpResponse response) throws Exception {
response.protocolVersion().encode(buf); AsciiString version = response.protocolVersion().text();
buf.writeBytes(version.array(), version.arrayOffset(), version.length());
buf.writeByte(SP); buf.writeByte(SP);
response.status().encode(buf);
AsciiString code = response.status().codeAsText();
buf.writeBytes(code.array(), code.arrayOffset(), code.length());
buf.writeByte(SP);
AsciiString reasonPhrase = response.status().reasonPhrase();
buf.writeBytes(reasonPhrase.array(), reasonPhrase.arrayOffset(), reasonPhrase.length());
buf.writeBytes(CRLF); buf.writeBytes(CRLF);
} }
} }

View File

@ -15,11 +15,7 @@
*/ */
package io.netty.handler.codec.http; package io.netty.handler.codec.http;
import io.netty.buffer.ByteBuf;
import io.netty.handler.codec.AsciiString; import io.netty.handler.codec.AsciiString;
import io.netty.util.CharsetUtil;
import static io.netty.handler.codec.http.HttpConstants.*;
/** /**
* The response code and its description of HTTP or its derived protocols, such as * The response code and its description of HTTP or its derived protocols, such as
@ -472,8 +468,7 @@ public class HttpResponseStatus implements Comparable<HttpResponseStatus> {
private final AsciiString codeAsText; private final AsciiString codeAsText;
private HttpStatusClass codeClass; private HttpStatusClass codeClass;
private final String reasonPhrase; private final AsciiString reasonPhrase;
private final byte[] bytes;
/** /**
* Creates a new instance with the specified {@code code} and the auto-generated default reason phrase. * Creates a new instance with the specified {@code code} and the auto-generated default reason phrase.
@ -512,12 +507,7 @@ public class HttpResponseStatus implements Comparable<HttpResponseStatus> {
this.code = code; this.code = code;
codeAsText = new AsciiString(Integer.toString(code)); codeAsText = new AsciiString(Integer.toString(code));
this.reasonPhrase = reasonPhrase; this.reasonPhrase = new AsciiString(reasonPhrase);
if (bytes) {
this.bytes = (code + " " + reasonPhrase).getBytes(CharsetUtil.US_ASCII);
} else {
this.bytes = null;
}
} }
/** /**
@ -537,7 +527,7 @@ public class HttpResponseStatus implements Comparable<HttpResponseStatus> {
/** /**
* Returns the reason phrase of this {@link HttpResponseStatus}. * Returns the reason phrase of this {@link HttpResponseStatus}.
*/ */
public String reasonPhrase() { public AsciiString reasonPhrase() {
return reasonPhrase; return reasonPhrase;
} }
@ -545,11 +535,11 @@ public class HttpResponseStatus implements Comparable<HttpResponseStatus> {
* Returns the class of this {@link HttpResponseStatus} * Returns the class of this {@link HttpResponseStatus}
*/ */
public HttpStatusClass codeClass() { public HttpStatusClass codeClass() {
HttpStatusClass type = this.codeClass; HttpStatusClass codeClass = this.codeClass;
if (type == null) { if (codeClass == null) {
this.codeClass = type = HttpStatusClass.valueOf(code); this.codeClass = codeClass = HttpStatusClass.valueOf(code);
} }
return type; return codeClass;
} }
@Override @Override
@ -587,14 +577,4 @@ public class HttpResponseStatus implements Comparable<HttpResponseStatus> {
.append(reasonPhrase) .append(reasonPhrase)
.toString(); .toString();
} }
void encode(ByteBuf buf) {
if (bytes == null) {
HttpHeaderUtil.encodeAscii0(String.valueOf(code()), buf);
buf.writeByte(SP);
HttpHeaderUtil.encodeAscii0(String.valueOf(reasonPhrase()), buf);
} else {
buf.writeBytes(bytes);
}
}
} }

View File

@ -15,8 +15,7 @@
*/ */
package io.netty.handler.codec.http; package io.netty.handler.codec.http;
import io.netty.buffer.ByteBuf; import io.netty.handler.codec.AsciiString;
import io.netty.util.CharsetUtil;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@ -37,12 +36,12 @@ public class HttpVersion implements Comparable<HttpVersion> {
/** /**
* HTTP/1.0 * HTTP/1.0
*/ */
public static final HttpVersion HTTP_1_0 = new HttpVersion("HTTP", 1, 0, false, true); public static final HttpVersion HTTP_1_0 = new HttpVersion("HTTP", 1, 0, false);
/** /**
* HTTP/1.1 * HTTP/1.1
*/ */
public static final HttpVersion HTTP_1_1 = new HttpVersion("HTTP", 1, 1, true, true); public static final HttpVersion HTTP_1_1 = new HttpVersion("HTTP", 1, 1, true);
/** /**
* Returns an existing or new {@link HttpVersion} instance which matches to * Returns an existing or new {@link HttpVersion} instance which matches to
@ -88,12 +87,12 @@ public class HttpVersion implements Comparable<HttpVersion> {
return null; return null;
} }
private final String protocolName; private final AsciiString protocolName;
private final int majorVersion; private final int majorVersion;
private final int minorVersion; private final int minorVersion;
private final String text; private final AsciiString text;
private final String textAsString;
private final boolean keepAliveDefault; private final boolean keepAliveDefault;
private final byte[] bytes;
/** /**
* Creates a new HTTP version with the specified version string. You will * Creates a new HTTP version with the specified version string. You will
@ -121,12 +120,12 @@ public class HttpVersion implements Comparable<HttpVersion> {
throw new IllegalArgumentException("invalid version format: " + text); throw new IllegalArgumentException("invalid version format: " + text);
} }
protocolName = m.group(1); protocolName = new AsciiString(m.group(1));
majorVersion = Integer.parseInt(m.group(2)); majorVersion = Integer.parseInt(m.group(2));
minorVersion = Integer.parseInt(m.group(3)); minorVersion = Integer.parseInt(m.group(3));
this.text = protocolName + '/' + majorVersion + '.' + minorVersion; textAsString = protocolName + "/" + majorVersion + '.' + minorVersion;
this.text = new AsciiString(textAsString);
this.keepAliveDefault = keepAliveDefault; this.keepAliveDefault = keepAliveDefault;
bytes = null;
} }
/** /**
@ -140,15 +139,7 @@ public class HttpVersion implements Comparable<HttpVersion> {
* {@code true} if and only if the connection is kept alive unless * {@code true} if and only if the connection is kept alive unless
* the {@code "Connection"} header is set to {@code "close"} explicitly. * the {@code "Connection"} header is set to {@code "close"} explicitly.
*/ */
public HttpVersion( public HttpVersion(String protocolName, int majorVersion, int minorVersion, boolean keepAliveDefault) {
String protocolName, int majorVersion, int minorVersion,
boolean keepAliveDefault) {
this(protocolName, majorVersion, minorVersion, keepAliveDefault, false);
}
private HttpVersion(
String protocolName, int majorVersion, int minorVersion,
boolean keepAliveDefault, boolean bytes) {
if (protocolName == null) { if (protocolName == null) {
throw new NullPointerException("protocolName"); throw new NullPointerException("protocolName");
} }
@ -172,23 +163,18 @@ public class HttpVersion implements Comparable<HttpVersion> {
throw new IllegalArgumentException("negative minorVersion"); throw new IllegalArgumentException("negative minorVersion");
} }
this.protocolName = protocolName; this.protocolName = new AsciiString(protocolName);
this.majorVersion = majorVersion; this.majorVersion = majorVersion;
this.minorVersion = minorVersion; this.minorVersion = minorVersion;
text = protocolName + '/' + majorVersion + '.' + minorVersion; textAsString = protocolName + '/' + majorVersion + '.' + minorVersion;
text = new AsciiString(textAsString);
this.keepAliveDefault = keepAliveDefault; this.keepAliveDefault = keepAliveDefault;
if (bytes) {
this.bytes = text.getBytes(CharsetUtil.US_ASCII);
} else {
this.bytes = null;
}
} }
/** /**
* Returns the name of the protocol such as {@code "HTTP"} in {@code "HTTP/1.0"}. * Returns the name of the protocol such as {@code "HTTP"} in {@code "HTTP/1.0"}.
*/ */
public String protocolName() { public AsciiString protocolName() {
return protocolName; return protocolName;
} }
@ -209,7 +195,7 @@ public class HttpVersion implements Comparable<HttpVersion> {
/** /**
* Returns the full protocol version text such as {@code "HTTP/1.0"}. * Returns the full protocol version text such as {@code "HTTP/1.0"}.
*/ */
public String text() { public AsciiString text() {
return text; return text;
} }
@ -226,7 +212,7 @@ public class HttpVersion implements Comparable<HttpVersion> {
*/ */
@Override @Override
public String toString() { public String toString() {
return text(); return textAsString;
} }
@Override @Override
@ -261,12 +247,4 @@ public class HttpVersion implements Comparable<HttpVersion> {
return minorVersion() - o.minorVersion(); return minorVersion() - o.minorVersion();
} }
void encode(ByteBuf buf) {
if (bytes == null) {
HttpHeaderUtil.encodeAscii0(text, buf);
} else {
buf.writeBytes(bytes);
}
}
} }

View File

@ -16,6 +16,7 @@
package io.netty.handler.codec.rtsp; package io.netty.handler.codec.rtsp;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import io.netty.handler.codec.AsciiString;
import io.netty.handler.codec.http.FullHttpRequest; import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.HttpRequest; import io.netty.handler.codec.http.HttpRequest;
import io.netty.util.CharsetUtil; import io.netty.util.CharsetUtil;
@ -37,11 +38,15 @@ public class RtspRequestEncoder extends RtspObjectEncoder<HttpRequest> {
@Override @Override
protected void encodeInitialLine(ByteBuf buf, HttpRequest request) throws Exception { protected void encodeInitialLine(ByteBuf buf, HttpRequest request) throws Exception {
buf.writeBytes(request.method().toString().getBytes(CharsetUtil.US_ASCII)); AsciiString method = request.method().name();
buf.writeBytes(method.array(), method.arrayOffset(), method.length());
buf.writeByte(SP); buf.writeByte(SP);
buf.writeBytes(request.uri().getBytes(CharsetUtil.UTF_8)); buf.writeBytes(request.uri().getBytes(CharsetUtil.UTF_8));
buf.writeByte(SP); buf.writeByte(SP);
buf.writeBytes(request.protocolVersion().toString().getBytes(CharsetUtil.US_ASCII));
AsciiString version = request.protocolVersion().text();
buf.writeBytes(version.array(), version.arrayOffset(), version.length());
buf.writeBytes(CRLF); buf.writeBytes(CRLF);
} }
} }

View File

@ -16,9 +16,9 @@
package io.netty.handler.codec.rtsp; package io.netty.handler.codec.rtsp;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import io.netty.handler.codec.AsciiString;
import io.netty.handler.codec.http.FullHttpResponse; import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpResponse; import io.netty.handler.codec.http.HttpResponse;
import io.netty.util.CharsetUtil;
import static io.netty.handler.codec.http.HttpConstants.*; import static io.netty.handler.codec.http.HttpConstants.*;
@ -36,11 +36,16 @@ public class RtspResponseEncoder extends RtspObjectEncoder<HttpResponse> {
@Override @Override
protected void encodeInitialLine(ByteBuf buf, HttpResponse response) throws Exception { protected void encodeInitialLine(ByteBuf buf, HttpResponse response) throws Exception {
buf.writeBytes(response.protocolVersion().toString().getBytes(CharsetUtil.US_ASCII)); AsciiString version = response.protocolVersion().text();
buf.writeBytes(version.array(), version.arrayOffset(), version.length());
buf.writeByte(SP); buf.writeByte(SP);
buf.writeBytes(String.valueOf(response.status().code()).getBytes(CharsetUtil.US_ASCII));
AsciiString code = response.status().codeAsText();
buf.writeBytes(code.array(), code.arrayOffset(), code.length());
buf.writeByte(SP); buf.writeByte(SP);
buf.writeBytes(response.status().reasonPhrase().getBytes(CharsetUtil.US_ASCII));
AsciiString reasonPhrase = response.status().reasonPhrase();
buf.writeBytes(reasonPhrase.array(), reasonPhrase.arrayOffset(), reasonPhrase.length());
buf.writeBytes(CRLF); buf.writeBytes(CRLF);
} }
} }

View File

@ -52,7 +52,7 @@ public class HttpInvalidMessageTest {
DecoderResult dr = req.decoderResult(); DecoderResult dr = req.decoderResult();
assertFalse(dr.isSuccess()); assertFalse(dr.isSuccess());
assertTrue(dr.isFailure()); assertTrue(dr.isFailure());
assertEquals("Good Value", req.headers().get("Good_Name")); assertTrue("Good Value".contentEquals(req.headers().get("Good_Name")));
assertEquals("/maybe-something", req.uri()); assertEquals("/maybe-something", req.uri());
ensureInboundTrafficDiscarded(ch); ensureInboundTrafficDiscarded(ch);
} }
@ -79,8 +79,8 @@ public class HttpInvalidMessageTest {
DecoderResult dr = res.decoderResult(); DecoderResult dr = res.decoderResult();
assertFalse(dr.isSuccess()); assertFalse(dr.isSuccess());
assertTrue(dr.isFailure()); assertTrue(dr.isFailure());
assertEquals("Maybe OK", res.status().reasonPhrase()); assertTrue("Maybe OK".contentEquals(res.status().reasonPhrase()));
assertEquals("Good Value", res.headers().get("Good_Name")); assertTrue("Good Value".contentEquals(res.headers().get("Good_Name")));
ensureInboundTrafficDiscarded(ch); ensureInboundTrafficDiscarded(ch);
} }