Skip to content

Fix #340 - Clarify extension handling #530

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

Open
wants to merge 8 commits into
base: master
Choose a base branch
from

Conversation

markt-asf
Copy link
Contributor

Keeping this in draft at this point as further changes are expected.

The specification document changes are mostly complete although I am expecting the wording to be improved based on review.

The API changes are intended as a starting point. I'll add some Javadoc once the API is more settled.

Feedback welcome. I'll leave it at least a couple of weeks before moving this to non-draft and merging.

@markt-asf
Copy link
Contributor Author

This has been open for almost a month. I was expecting more feedback. I'm moving this out of draft and currently intend to merge in the next week or so.

@markt-asf markt-asf marked this pull request as ready for review July 21, 2025 15:33
@joakime
Copy link
Contributor

joakime commented Jul 21, 2025

Sorry, I was out on break and missed this one.

@joakime
Copy link
Contributor

joakime commented Jul 21, 2025

I'll try to get feedback on this within the next 24 hours.


Extension[] extensions() default {};

@interface Extension {
Copy link
Contributor

Choose a reason for hiding this comment

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

I would consider moving this outside of ClientEndpoint so it could be used on the Server side as well, because there is ServerEndpointConfig.getExtensions but no equivalent on the ServerEndpoint annotation.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Moving this outside of ClientEndpoint would create a conflict with the Extension interface. Making the annotation available on the server side was also discussed in #340 and no use case was identified. Do you have a use case for this?

Copy link
Contributor

Choose a reason for hiding this comment

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

It is the use case of ServerEndpointConfig#getExtensions which does not make sense to me.

But it seems to me that either ServerEndpointConfig#getExtensions should be deprecated, or there should be an equivalent API on the @ServerEndpoint annotation.

But for example I would imagine something like this, which would allow you to negotiate a specific extension without setting a custom configurator.

@ServerEndpoint(value = "/", extensions = { @Extension(name = "permessage-deflate")})
public class MyServerEndpoint
{
    // ...
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think that would work for ServerEndpointConfig#getExtensions (matched with new @Extension support in @ServerEndpoint) if the intersection of those extensions and what the container supports was passed as installed to ServerEndpointConfig.Configurator.getNegotiatedExtensions. That would also need explicitly documenting in the spec.

That then begs the question what do we name @Extension. We can't use the obvious jakarta.websocket.Extension as that clashes with the existing interface. @ExtensionConfig?

Copy link
Contributor Author

@markt-asf markt-asf left a comment

Choose a reason for hiding this comment

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

Thanks for the review. I'll make the updates as per my comments shortly and we can continue to discuss the unresolved points.


Extension[] extensions() default {};

@interface Extension {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Moving this outside of ClientEndpoint would create a conflict with the Extension interface. Making the annotation available on the server side was also discussed in #340 and no use case was identified. Do you have a use case for this?


Extension[] extensions() default {};

@interface Extension {
Copy link
Contributor

Choose a reason for hiding this comment

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

It is the use case of ServerEndpointConfig#getExtensions which does not make sense to me.

But it seems to me that either ServerEndpointConfig#getExtensions should be deprecated, or there should be an equivalent API on the @ServerEndpoint annotation.

But for example I would imagine something like this, which would allow you to negotiate a specific extension without setting a custom configurator.

@ServerEndpoint(value = "/", extensions = { @Extension(name = "permessage-deflate")})
public class MyServerEndpoint
{
    // ...
}

@joakime
Copy link
Contributor

joakime commented Jul 25, 2025

How would we handle the common use case of rejecting or denying a specific extension from negotiating?

Can someone setup a server endpoint to reject permessage-deflate?

@ServerEndpoint(value = "/", reject-extensions = { @Extension(name = "permessage-deflate")})
public class MyServerEndpoint
{
    // ...
}

or

@ServerEndpoint(value = "/", extensions = { @Extension(name = "permessage-deflate", reject=true)})
public class MyServerEndpoint
{
    // ...
}

or

@ServerEndpoint(value = "/", extensions = { @Extension(name = "!permessage-deflate")})
public class MyServerEndpoint
{
    // ...
}

@markt-asf
Copy link
Contributor Author

How would we handle the common use case of rejecting or denying a specific extension from negotiating?

Can someone setup a server endpoint to reject permessage-deflate?

Do we need to? The mode for the client is that it declares the list of extensions it is prepared to support. Given the small number of extensions, that model should work for the server too. If we did adopt this feature, I'd lean towards the first option - although I'd use rejectExtensions for the annotation parameter name.

@joakime
Copy link
Contributor

joakime commented Jul 25, 2025

How would we handle the common use case of rejecting or denying a specific extension from negotiating?
Can someone setup a server endpoint to reject permessage-deflate?

Do we need to? The mode for the client is that it declares the list of extensions it is prepared to support. Given the small number of extensions, that model should work for the server too. If we did adopt this feature, I'd lean towards the first option - although I'd use rejectExtensions for the annotation parameter name.

Yes, it is a common use case.
Take for example the use case of a Web Browser connecting to a developed WebSocket Server Endpoint.
The Web Browser will have hard-coded list of extensions it advertises (list can change with a new version of the web browser).
The developer of the WebSocket Server Endpoint knows that one of the extensions is supported and available by the server, but they do not want to use that extension for whatever reason. (bugs in server, bugs in websocket client, network auditing tools, debugging reasons, network capture reasons, etc...)

@markt-asf
Copy link
Contributor Author

Sorry, not progressing this as fast as I would like. Other tasks keep getting in the way.
My current intention is to update this PR along the following lines:

  • Rename the Extension (and nested Parameter annotation) annotation to jakarta.websocket.ExtensionConfig
  • Use this annotation on ClientEndpoint and ServerEndpoint
  • Use a naming convention (TBD - see below) to allow denying an extension but only for the ServerEndpoint (the client always has to list all the extensions it would like to use)

While I like the use of ! as a prefix to indicate the extension should not be allowed, ! is a permitted character in an extension name. I know it is unlikely to be used but I'd rather not design in that potential risk given we can avoid it. We have a choice of "(),/:;<=>?@[\]{}. How about <?

@markt-asf
Copy link
Contributor Author

Updated PR for review. Once we have agreement, I'll likely refactor the commits to make the changes to main cleaner.

@joakime
Copy link
Contributor

joakime commented Aug 1, 2025

I'll have a chance to go over this better early next week.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants