Skip to content

Conversation

@joakime
Copy link
Contributor

@joakime joakime commented Nov 25, 2025

Cleanup all code paths that perform a ComplianceViolation check to do the following ...

  • Always report the violation, if detected.
  • Report if the violation was allowed (or not)
  • Use the HttpChannelState.getCompliaceViolationListener() in all cases (this gets the benefit of a single ComplianceViolation.Listener to use, along with all of the initialize(), onRequestBegin(), and onRequestEnd() techniques.
  • Deprecate the HttpConfiguration notify methods
  • Deprecate the ComplianceViolation.notify() static methods.

Closes #12806

@joakime joakime self-assigned this Nov 25, 2025
@joakime joakime added the Bug For general bugs on Jetty side label Nov 25, 2025
@joakime joakime added the Sponsored This issue affects a user with a commercial support agreement label Nov 25, 2025
@joakime joakime moved this to 👀 In review in Jetty 12.1.5 Nov 25, 2025
@joakime joakime removed this from Jetty 12.1.5 Nov 27, 2025
@joakime joakime moved this to 👀 In review in Jetty 12.1.6 Nov 27, 2025
@joakime joakime marked this pull request as ready for review December 2, 2025 13:01
@joakime joakime requested a review from gregw December 2, 2025 13:01
Copy link
Contributor

@gregw gregw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking better, but still work to do.


if (_violations != null && !_violations.isEmpty())
{
CookieCompliance cookieCompliance = _parser.getCookieCompliance();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This variable is not used

if (_violations != null && !_violations.isEmpty())
{
CookieCompliance cookieCompliance = _parser.getCookieCompliance();
_violations.forEach(complianceViolationListener::onComplianceViolation);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we assertNotNull on the cVL? or skip this line if it is null?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The expectation is that there will always be a cVL, even if its just ComplianceViolation.Listener.NOOP.
I added a requireNonNull to the start of the method anyway.

parseField(field);
}

CookieCompliance getCookieCompliance();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

javadoc

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Easier to just get rid of this method, it's no longer being used anyway.

*/
void initialize();

boolean complianceAllows(ComplianceViolation violation, String detail);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

never called?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed


boolean complianceAllows(ComplianceViolation violation, String detail);

<T extends Throwable> void complianceAssert(ComplianceViolation violation, String detail, Function<String, T> error) throws T;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

javadoc

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, would this not be better as a method on HttpConfiguration? When would a channel ever have a different impl?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Each channel has a (potentially) unique set of cVL due cVL.initialize() requirement.
The HttpConfiguration approach is the wrong place for most use cases with cVL.
It only really fits (and barely at that) for pre-channel violations like from HttpParser (but even that isn't really a concern anymore with the channel based approach).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

javadoc added

Comment on lines 203 to 222
{
ComplianceViolation.Mode mode;

if (violation instanceof UriCompliance.Violation)
mode = getHttpConfiguration().getUriCompliance();
else if (violation instanceof HttpCompliance.Violation)
mode = getHttpConfiguration().getHttpCompliance();
else if (violation instanceof MultiPartCompliance.Violation)
mode = getHttpConfiguration().getMultiPartCompliance();
else if (violation instanceof CookieCompliance.Violation)
mode = getHttpConfiguration().getRequestCookieCompliance();
else
throw new UnsupportedOperationException("Unsupported ComplianceViolation type: " + violation.getClass().getName());

boolean allowed = mode.allows(violation);

// Always report violation to listeners
_complianceViolationListener.onComplianceViolation(new ComplianceViolation.Event(mode, violation, detail, allowed));

return allowed;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method is substantially the same as the one above. Factor out the mode selection maybe to HttpConfiguration itself

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed

if (qualityCSV == null)
{
HttpConfiguration httpConfiguration = request.getConnectionMetaData().getHttpConfiguration();
HttpChannel httpChannel = HttpChannel.from(request);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it is more natural to report violations to the HttpConfiguration rather than the HttpChannel

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But that's the wrong place and doesn't take into account the cVL.initialize() / cVL.onRequestBegin() / cVL.onRequestEnd() requirements.
The HttpChannel is also the place where these events fire.
The individual violations (cVL.onComplianceViolation()) occur between these.

*/
public void notifyViolation(ComplianceViolation violation, String details)
{
ComplianceViolation.Mode mode;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The mode selection code is duplicated again. Perhaps we should just have the following methods on HttpConfiguration:

    public ComplianceViolation.Mode getComplianceViolationModeFor(ComplianceViolation violation)
    {
        if (violation instanceof UriCompliance.Violation)
            return getUriCompliance();
        else if (violation instanceof HttpCompliance.Violation)
            return getHttpCompliance();
        else if (violation instanceof MultiPartCompliance.Violation)
            return getMultiPartCompliance();
        else if (violation instanceof CookieCompliance.Violation)
            return getRequestCookieCompliance();
        else
            throw new UnsupportedOperationException("Unsupported ComplianceViolation type: " + violation.getClass().getName());
    }

    public <T extends Throwable> void assertAllowed(ComplianceViolation violation, String detail, Function<String, T> error) throws T
    {
        ComplianceViolation.Mode mode = getComplianceViolationModeFor(violation);
        boolean allowed = mode.allows(violation);

        List<ComplianceViolation.Listener> listeners = getComplianceViolationListeners();
        ComplianceViolation.Event event = new ComplianceViolation.Event(mode, violation, detail, allowed);
        Throwable throwable = null;
        for (ComplianceViolation.Listener listener : listeners)
        {
            try
            {
                listener.onComplianceViolation(event);
            }
            catch (Throwable t)
            {
                throwable = ExceptionUtil.combine(throwable, t);
            }
        }
        ExceptionUtil.ifExceptionThrowUnchecked(throwable);

        if (!allowed)
            throw error.apply(violation.getDescription());
    }

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed, no longer being used.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Bug For general bugs on Jetty side Sponsored This issue affects a user with a commercial support agreement

Projects

Status: 👀 In review

Development

Successfully merging this pull request may close these issues.

How to migrate from legacy compliance mode

3 participants