Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
df07f72
Revert "Add http request validators feature flag (#472)"
attilakreiner Sep 28, 2023
f3e2245
WIP
attilakreiner Sep 28, 2023
7691312
fix
attilakreiner Oct 10, 2023
1f811c4
WIP
attilakreiner Oct 11, 2023
502db7f
WIP integation tests
attilakreiner Oct 13, 2023
330119d
WIP integration tests
attilakreiner Oct 16, 2023
2963d52
WIP h2 tests
attilakreiner Oct 18, 2023
4d9a19b
WIP h2 tests - content
attilakreiner Oct 19, 2023
dce5c70
WIP http/1.1 ITs - content
attilakreiner Oct 20, 2023
5e11f6f
fix
attilakreiner Oct 20, 2023
16af5e3
fix
attilakreiner Oct 21, 2023
4452d5b
WIP
attilakreiner Oct 25, 2023
eb9842b
fix method names
attilakreiner Oct 26, 2023
09e3087
WIP fix
attilakreiner Oct 26, 2023
e6ea82c
cleanup
attilakreiner Oct 26, 2023
dfcc7fa
fix h2 invalid test so all requests use the same connection
attilakreiner Oct 26, 2023
9a7f3c3
fix review items 1
attilakreiner Oct 27, 2023
215e72c
fix review items 2
attilakreiner Oct 27, 2023
cb5ffd8
fix review items 3
attilakreiner Oct 27, 2023
e95c006
Add server side for the invalid test h2
attilakreiner Oct 27, 2023
1296060
Fix invalid content in http/1.1 validation
attilakreiner Nov 2, 2023
769643b
Fix duplicate response header issue
attilakreiner Nov 2, 2023
a86eef4
fix NPE
attilakreiner Nov 3, 2023
345ded8
Revert "Fix duplicate response header issue"
attilakreiner Nov 3, 2023
9ffb3b1
send reset frame
attilakreiner Nov 3, 2023
7ee5980
fix
attilakreiner Nov 3, 2023
f57273f
fix 1
attilakreiner Nov 6, 2023
ad0c98f
fix 2
attilakreiner Nov 6, 2023
b5eded0
fix 3
attilakreiner Nov 6, 2023
ba32eb1
fix
attilakreiner Nov 7, 2023
3b4af62
fix 1
attilakreiner Nov 8, 2023
f3f0ee2
fix 2
attilakreiner Nov 8, 2023
5f6f544
fix 3
attilakreiner Nov 8, 2023
60d2ed5
fix 4
attilakreiner Nov 8, 2023
1cb75af
fix 5
attilakreiner Nov 8, 2023
0b5b33e
fix 6
attilakreiner Nov 8, 2023
d0ce297
fix 7
attilakreiner Nov 8, 2023
69812f7
fix 8
attilakreiner Nov 8, 2023
187e877
fix 9
attilakreiner Nov 8, 2023
cccd57f
fix 10
attilakreiner Nov 8, 2023
1b5a811
refactor HttpRequestType
attilakreiner Nov 8, 2023
3a5c307
refactor HttpRequestType 2
attilakreiner Nov 8, 2023
d748cca
WIP TreeMap
attilakreiner Nov 8, 2023
fc290e7
Add unit tests for urlDecodedComparator
attilakreiner Nov 8, 2023
dce06c6
fix 1
attilakreiner Nov 9, 2023
662fd09
fix 2
attilakreiner Nov 9, 2023
decd91d
fix 3
attilakreiner Nov 9, 2023
d41768f
PercentEncodableStringComparator 1
attilakreiner Nov 9, 2023
99718e1
PercentEncodableStringComparator 2
attilakreiner Nov 9, 2023
115da84
fix 4
attilakreiner Nov 9, 2023
be01927
WIP fix bug
attilakreiner Nov 10, 2023
b553ebe
fix 1
attilakreiner Nov 10, 2023
5cc0499
fix 2
attilakreiner Nov 10, 2023
0acab22
fix 1
attilakreiner Nov 11, 2023
12728d4
fix 2
attilakreiner Nov 13, 2023
d5e567c
fix 3
attilakreiner Nov 13, 2023
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
Prev Previous commit
Next Next commit
WIP
  • Loading branch information
attilakreiner committed Nov 13, 2023
commit 4452d5bbcd93b8df6eb6e9fb67930258318733ca
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.agrona.DirectBuffer;

import io.aklivity.zilla.runtime.binding.http.config.HttpAccessControlConfig;
import io.aklivity.zilla.runtime.binding.http.config.HttpCredentialsConfig;
import io.aklivity.zilla.runtime.binding.http.config.HttpOptionsConfig;
Expand Down Expand Up @@ -328,24 +330,22 @@ private Map<String, String8FW> parseQueryParams(
return queryParams;
}

public boolean validate(
public boolean validateHeader(
HttpRequestType request,
HttpBeginExFW beginEx)
{
boolean isValid = true;
if (request != null)
{
boolean isValidHeader = validateHeaders(request, beginEx);
boolean isValidHeader = validateHeaderValues(request, beginEx);
boolean isValidPathParams = validatePathParams(request);
boolean isValidQueryParams = validateQueryParams(request);
// TODO: Ati - validate content (probably somewhere else)
//boolean isValidContent = validateContent(requestType, beginEx);
isValid = isValidHeader && isValidPathParams && isValidQueryParams; // && isValidContent;
isValid = isValidHeader && isValidPathParams && isValidQueryParams;
}
return isValid;
}

private boolean validateHeaders(
private boolean validateHeaderValues(
HttpRequestType request,
HttpBeginExFW beginEx)
{
Expand Down Expand Up @@ -411,16 +411,19 @@ private boolean validateQueryParams(
return isValid;
}

private boolean validateContent(
HttpRequestType request)
public boolean validateContent(
HttpRequestType request,
DirectBuffer buffer,
int index,
int length)
{
AtomicBoolean isValidContent = new AtomicBoolean(true);
boolean isValid = true;
if (request != null && request.content != null)
{
Validator validator = request.content;
// TODO: Ati
isValid = validator.read(buffer, index, length);
}
return isValidContent.get();
return isValid;
}

private static Function<Function<String, String>, String> orElseIfNull(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -406,6 +406,7 @@ public final class HttpServerFactory implements HttpStreamFactory
private final Array32FW<HttpHeaderFW> headers400;
private final Array32FW<HttpHeaderFW> headers403;
private final Array32FW<HttpHeaderFW> headers404;
private final DirectBuffer response400;
private final DirectBuffer response403;
private final DirectBuffer response404;

Expand Down Expand Up @@ -582,6 +583,7 @@ public HttpServerFactory(
this.headers400 = initHeadersEmpty(config, STATUS_400);
this.headers403 = initHeaders(config, STATUS_403);
this.headers404 = initHeadersEmpty(config, STATUS_404);
this.response400 = initResponse(config, 400, "Bad Request");
this.response403 = initResponse(config, 403, "Forbidden");
this.response404 = initResponse(config, 404, "Not Found");
}
Expand Down Expand Up @@ -1059,8 +1061,7 @@ else if (!isCorsRequestAllowed(server.binding, headers))
}

HttpRouteConfig route = binding.resolve(exchangeAuth, headers::get);
server.request = binding.resolveRequest(headers::get);
if (route != null && binding.validate(server.request, beginEx))
if (route != null)
{
if (binding.options != null && binding.options.overrides != null)
{
Expand All @@ -1075,7 +1076,9 @@ else if (!isCorsRequestAllowed(server.binding, headers))
HttpPolicyConfig policy = binding.access().effectivePolicy(headers);
final String origin = policy == CROSS_ORIGIN ? headers.get(HEADER_NAME_ORIGIN) : null;

server.onDecodeHeaders(server.routedId, route.id, traceId, exchangeAuth, policy, origin, beginEx);
server.request = binding.resolveRequest(headers::get);
error = server.onDecodeHeaders(server.routedId, route.id, traceId, exchangeAuth, policy, origin,
beginEx);
}
else
{
Expand Down Expand Up @@ -2215,7 +2218,7 @@ private void onDecodeCorsPreflight(
assert exchange == null;
}

private void onDecodeHeaders(
private DirectBuffer onDecodeHeaders(
long originId,
long routedId,
long traceId,
Expand All @@ -2224,14 +2227,24 @@ private void onDecodeHeaders(
String origin,
HttpBeginExFW beginEx)
{
final HttpExchange exchange = new HttpExchange(originId, routedId, authorization, traceId, policy, origin);
exchange.doRequestBegin(traceId, beginEx);
exchange.doResponseWindow(traceId);
boolean isValid = binding.validateHeader(request, beginEx);
DirectBuffer error = null;
if (isValid)
{
final HttpExchange exchange = new HttpExchange(originId, routedId, authorization, traceId, policy, origin);
exchange.doRequestBegin(traceId, beginEx);
exchange.doResponseWindow(traceId);

final HttpHeaderFW connection = beginEx.headers().matchFirst(h -> HEADER_CONNECTION.equals(h.name()));
exchange.responseClosing = connection != null && connectionClose.reset(connection.value().asString()).matches();
final HttpHeaderFW connection = beginEx.headers().matchFirst(h -> HEADER_CONNECTION.equals(h.name()));
exchange.responseClosing = connection != null && connectionClose.reset(connection.value().asString()).matches();

this.exchange = exchange;
this.exchange = exchange;
}
else
{
error = response400;
}
return error;
}

private void onDecodeHeadersOnly(
Expand All @@ -2254,7 +2267,18 @@ private int onDecodeBody(
int limit,
Flyweight extension)
{
return exchange.doRequestData(traceId, budgetId, buffer, offset, limit, extension);
boolean isValid = binding.validateContent(request, buffer, 0, limit - offset);
int result = 0;
if (isValid)
{
result = exchange.doRequestData(traceId, budgetId, buffer, offset, limit, extension);
}
else
{
doEncodeHeaders(exchange, traceId, authorization, budgetId, headers400);
exchange.doRequestAbort(traceId, EMPTY_OCTETS);
}
return result;
}

private void onDecodeTrailers(
Expand Down Expand Up @@ -3729,7 +3753,6 @@ private final class Http2Server
private int decodedStreamId;
private byte decodedFlags;
private int decodableDataBytes;
private HttpRequestType request;

private Http2Server(
HttpBindingConfig binding,
Expand Down Expand Up @@ -4844,10 +4867,6 @@ else if (!isCorsRequestAllowed(binding, headers))
HttpPolicyConfig policy = binding.access().effectivePolicy(headers);
final String origin = policy == CROSS_ORIGIN ? headers.get(HEADER_NAME_ORIGIN) : null;

final Http2Exchange exchange =
new Http2Exchange(originId, routedId, NO_REQUEST_ID, streamId, exchangeAuth,
traceId, policy, origin, contentLength);

if (binding.options != null && binding.options.overrides != null)
{
binding.options.overrides.forEach((k, v) -> headers.put(k.asString(), v.asString()));
Expand All @@ -4858,8 +4877,12 @@ else if (!isCorsRequestAllowed(binding, headers))
.headers(hs -> headers.forEach((n, v) -> hs.item(h -> h.name(n).value(v))))
.build();

this.request = binding.resolveRequest(headers::get);
boolean isValid = binding.validate(request, beginEx);
HttpRequestType request = binding.resolveRequest(headers::get);

final Http2Exchange exchange = new Http2Exchange(originId, routedId, NO_REQUEST_ID, streamId,
exchangeAuth, traceId, policy, origin, contentLength, request);

boolean isValid = binding.validateHeader(request, beginEx);
if (isValid)
{
exchange.doRequestBegin(traceId, beginEx);
Expand All @@ -4870,7 +4893,7 @@ else if (!isCorsRequestAllowed(binding, headers))
}
else
{
doEncodeHeaders(traceId, authorization, streamId, headers404, true);
doEncodeHeaders(traceId, authorization, streamId, headers400, true);
}
}
}
Expand Down Expand Up @@ -5076,6 +5099,12 @@ private int onDecodeData(

if (payloadLength > 0)
{
boolean isValid = binding.validateContent(exchange.request, payload, 0, payloadLength);
if (!isValid)
{
doEncodeHeaders(traceId, authorization, streamId, headers400, true);
exchange.doRequestAbort(traceId, EMPTY_OCTETS);
}
payloadRemaining.set(payloadLength);
exchange.doRequestData(traceId, payload, payloadRemaining);
progress += payloadLength - payloadRemaining.value;
Expand Down Expand Up @@ -5225,7 +5254,7 @@ private void doEncodePromise(
doEncodePushPromise(traceId, authorization, pushId, promiseId, promise);

final Http2Exchange exchange = new Http2Exchange(originId, routedId, requestId, promiseId,
exchangeAuth, traceId, policy, origin, contentLength);
exchangeAuth, traceId, policy, origin, contentLength, null);

final HttpBeginExFW beginEx = beginExRW.wrap(extBuffer, 0, extBuffer.capacity())
.typeId(httpTypeId)
Expand Down Expand Up @@ -5541,6 +5570,8 @@ private final class Http2Exchange
private long responseAck;
private int responseMax;

private final HttpRequestType request;

private Http2Exchange(
long originId,
long routedId,
Expand All @@ -5550,7 +5581,8 @@ private Http2Exchange(
long traceId,
HttpPolicyConfig policy,
String origin,
long requestContentLength)
long requestContentLength,
HttpRequestType request)
{
this.originId = originId;
this.routedId = routedId;
Expand All @@ -5562,6 +5594,7 @@ private Http2Exchange(
this.requestId = requestId == NO_REQUEST_ID ? supplyInitialId.applyAsLong(routedId) : requestId;
this.responseId = supplyReplyId.applyAsLong(this.requestId);
this.expiringId = expireIfNecessary(guard, sessionId, originId, routedId, replyId, traceId, streamId);
this.request = request;
}

private int initialWindow()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ write "POST /valid/1234567890123/123 HTTP/1.1" "\r\n"
write "Host: localhost:8080" "\r\n"
write "\r\n"

read "HTTP/1.1 404 Not Found\r\n"
read "HTTP/1.1 400 Bad Request\r\n"
read "Connection: close\r\n"
read "\r\n"
read closed
Expand All @@ -39,7 +39,7 @@ write "POST /valid/1234567890123/1234567890123?page=123 HTTP/1.1" "\r\n"
write "Host: localhost:8080" "\r\n"
write "\r\n"

read "HTTP/1.1 404 Not Found\r\n"
read "HTTP/1.1 400 Bad Request\r\n"
read "Connection: close\r\n"
read "\r\n"
read closed
Expand All @@ -55,7 +55,7 @@ write "Host: localhost:8080" "\r\n"
write "Code: 123" "\r\n"
write "\r\n"

read "HTTP/1.1 404 Not Found\r\n"
read "HTTP/1.1 400 Bad Request\r\n"
read "Connection: close\r\n"
read "\r\n"
read closed
Expand All @@ -74,7 +74,7 @@ write "Content-Type: text/plain" "\r\n"
write "\r\n"
write "123"

read "HTTP/1.1 404 Not Found\r\n"
read "HTTP/1.1 400 Bad Request\r\n"
read "Connection: close\r\n"
read "\r\n"
read closed
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ read "POST /valid/1234567890123/123 HTTP/1.1" "\r\n"
read "Host: localhost:8080" "\r\n"
read "\r\n"

write "HTTP/1.1 404 Not Found\r\n"
write "HTTP/1.1 400 Bad Request\r\n"
write "Connection: close\r\n"
write "\r\n"
write close
Expand All @@ -40,7 +40,7 @@ read "POST /valid/1234567890123/1234567890123?page=123 HTTP/1.1" "\r\n"
read "Host: localhost:8080" "\r\n"
read "\r\n"

write "HTTP/1.1 404 Not Found\r\n"
write "HTTP/1.1 400 Bad Request\r\n"
write "Connection: close\r\n"
write "\r\n"
write close
Expand All @@ -54,7 +54,7 @@ read "Host: localhost:8080" "\r\n"
read "Code: 123" "\r\n"
read "\r\n"

write "HTTP/1.1 404 Not Found\r\n"
write "HTTP/1.1 400 Bad Request\r\n"
write "Connection: close\r\n"
write "\r\n"
write close
Expand All @@ -71,7 +71,7 @@ read "Content-Type: text/plain" "\r\n"
read "\r\n"
read "123"

write "HTTP/1.1 404 Not Found\r\n"
write "HTTP/1.1 400 Bad Request\r\n"
write "Connection: close\r\n"
write "\r\n"
write close
Loading