Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve HTTP parsing long look-ahead #11486

Merged
merged 8 commits into from
Mar 5, 2024
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ public Result generateRequest(MetaData.Request info, ByteBuffer header, ByteBuff
int pos = BufferUtil.flipToFill(header);
try
{
// generate ResponseLine
// generate request line
generateRequestLine(info, header);

if (info.getHttpVersion() == HttpVersion.HTTP_0_9)
Expand Down Expand Up @@ -520,7 +520,7 @@ private void generateResponseLine(MetaData.Response response, ByteBuffer header)
String reason = response.getReason();
if (preprepared != null)
{
if (reason == null)
if (reason == null || preprepared._reason.equals(reason))
header.put(preprepared._responseLine);
else
{
Expand Down Expand Up @@ -779,11 +779,9 @@ private static void putContentLength(ByteBuffer header, long contentLength)
}
}

@Deprecated(forRemoval = true)
public static byte[] getReasonBuffer(int code)
{
PreparedResponse status = code < __preprepared.length ? __preprepared[code] : null;
if (status != null)
return status._reason;
return null;
}

Expand All @@ -807,9 +805,16 @@ public String toString()
// Build cache of response lines for status
private static class PreparedResponse
{
byte[] _reason;
byte[] _schemeCode;
byte[] _responseLine;
final String _reason;
final byte[] _schemeCode;
final byte[] _responseLine;

private PreparedResponse(String reason, byte[] schemeCode, byte[] responseLine)
{
_reason = reason;
_schemeCode = schemeCode;
_responseLine = responseLine;
}
}

private static final PreparedResponse[] __preprepared = new PreparedResponse[HttpStatus.MAX_CODE + 1];
Expand Down Expand Up @@ -838,10 +843,7 @@ private static class PreparedResponse
line[versionLength + 5 + reason.length()] = HttpTokens.CARRIAGE_RETURN;
line[versionLength + 6 + reason.length()] = HttpTokens.LINE_FEED;

__preprepared[i] = new PreparedResponse();
__preprepared[i]._schemeCode = Arrays.copyOfRange(line, 0, versionLength + 5);
__preprepared[i]._reason = Arrays.copyOfRange(line, versionLength + 5, line.length - 2);
__preprepared[i]._responseLine = line;
__preprepared[i] = new PreparedResponse(reason, Arrays.copyOfRange(line, 0, versionLength + 5), line);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -163,34 +163,34 @@ public String toString()
public static HttpMethod lookAheadGet(ByteBuffer buffer)
{
int len = buffer.remaining();
// Short cut for 3 char methods, mostly for GET optimisation
if (len > 3)
{
switch (buffer.getInt(buffer.position()))
{
case ACL_AS_INT:
return ACL;
case GET_AS_INT:
return GET;
case PRI_AS_INT:
return PRI;
case PUT_AS_INT:
return PUT;
case POST_AS_INT:
if (len > 4 && buffer.get(buffer.position() + 4) == ' ')
return POST;
break;
case HEAD_AS_INT:
if (len > 4 && buffer.get(buffer.position() + 4) == ' ')
return HEAD;
break;
default:
break;
}
}
// Shortcut for 3 or 4 char methods, mostly for GET optimisation
if (len > 4)
return lookAheadGet(buffer, buffer.getInt(buffer.position()));
return LOOK_AHEAD.getBest(buffer, 0, len);
}

/**
* Optimized lookup to find a method name and trailing space in a byte array.
*
* @param buffer buffer containing ISO-8859-1 characters, it is not modified, which must have at least 5 bytes remaining
* @param lookAhead The integer representation of the first 4 bytes of the buffer that has previously been fetched
* with the equivalent of {@code buffer.getInt(buffer.position())}
* @return An HttpMethod if a match or null if no easy match.
*/
static HttpMethod lookAheadGet(ByteBuffer buffer, int lookAhead)
{
return switch (lookAhead)
{
case ACL_AS_INT -> ACL;
case GET_AS_INT -> GET;
case PRI_AS_INT -> PRI;
case PUT_AS_INT -> PUT;
case POST_AS_INT -> (buffer.get(buffer.position() + 4) == ' ') ? POST : LOOK_AHEAD.getBest(buffer, 0, buffer.remaining());
case HEAD_AS_INT -> (buffer.get(buffer.position() + 4) == ' ') ? HEAD : LOOK_AHEAD.getBest(buffer, 0, buffer.remaining());
default -> LOOK_AHEAD.getBest(buffer, 0, buffer.remaining());
};
}

/**
* Converts the given String parameter to an HttpMethod.
* The string may differ from the Enum name as a '-' in the method
Expand Down
Loading
Loading