-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Migrate some URIUtil methods to HttpScheme for proper normalization #11390
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
Conversation
joakime
commented
Feb 8, 2024
•
edited
Loading
edited
- Deprecate URIUtil methods that are not normalizing URI strings properly from component parts.
- Add relevant HttpScheme methods to perform proper normalization of URI components.
- Migrate all existing code to use new HttpScheme methods.
* the returned String might not include a port, and will not include the ending {@code /} character. | ||
* @see #appendNormalizedUri(StringBuilder, String, String, int) | ||
*/ | ||
public static String normalizeUri(String scheme, String server, int port) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I prefer normalizeURI()
with URI
all capital.
* the returned String might not include a port. | ||
* @see #appendNormalizedUri(StringBuilder, String, String, int) | ||
*/ | ||
public static String normalizeUri(String scheme, String server, int port, String path, String query) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ditto re URI.
I would also add fragment
as this method may be used on the client too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, but I hope the client isn't sending the fragment on the HTTP protocol, as that's not spec compliant.
* @param server the server hostname, may not be blank or null. | ||
* @param port the port | ||
*/ | ||
public static void appendNormalizedUri(StringBuilder url, String scheme, String server, int port) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ditto re fragment
.
I would rename it to concatNormalizeURI()
.
{ | ||
url.append(path); | ||
if (StringUtil.isNotBlank(query)) | ||
{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Drop braces.
@@ -357,7 +358,7 @@ static String toRedirectURI(Request request, String location) | |||
{ | |||
// make the location an absolute URI | |||
StringBuilder url = new StringBuilder(128); | |||
URIUtil.appendSchemeHostPort(url, uri.getScheme(), Request.getServerName(request), Request.getServerPort(request)); | |||
HttpScheme.appendNormalizedUri(url, uri.getScheme(), Request.getServerName(request), Request.getServerPort(request)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can use the method that also takes the path and query, since you are adding the location in the next line.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nope, as location
already has the query considered, it is not a pure path.
@@ -217,7 +217,8 @@ protected String filterServerResponseHeader(HttpServletRequest request, Response | |||
URI locationURI = URI.create(headerValue).normalize(); | |||
if (locationURI.isAbsolute() && isBackendLocation(locationURI)) | |||
{ | |||
StringBuilder newURI = URIUtil.newURIBuilder(request.getScheme(), request.getServerName(), request.getServerPort()); | |||
StringBuilder newURI = new StringBuilder(); | |||
HttpScheme.appendNormalizedUri(newURI, request.getScheme(), request.getServerName(), request.getServerPort()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The code below this line adds path, query and fragment, so you can just use the new method with more parameters.
response.setContentLength(0); | ||
baseRequest.getResponse().sendRedirect(_redirectCode, url, true); | ||
baseRequest.getResponse().sendRedirect(_redirectCode, url.toString(), true); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
url
is already a String
, no need to call toString()
?
@@ -293,7 +294,7 @@ private void attemptLogoutRedirect(ServletRequest request) | |||
if (_logoutRedirectPath != null) | |||
{ | |||
StringBuilder sb = new StringBuilder(128); | |||
URIUtil.appendSchemeHostPort(sb, request.getScheme(), request.getServerName(), request.getServerPort()); | |||
HttpScheme.appendNormalizedUri(sb, request.getScheme(), request.getServerName(), request.getServerPort()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use the method with more arguments.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not appropriate to use longer version here, as the next two lines build up a path.
request.getServerPort(), | ||
locationURI.getRawPath(), | ||
locationURI.getRawQuery()); | ||
String component = locationURI.getRawFragment(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add the fragment
as parameter to the method with many parameters.
response.setContentLength(0); | ||
response.sendRedirect(url, true); | ||
response.sendRedirect(url.toString(), true); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
url
already a String?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm very cautious about changes like this.... they often have unintended consequences.
Can we bump this to 12.0.8, merge it immediately after 12.0.7 and give it a full month of testing?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Merge of 11.0.x to 12.0.x of PR #11389
That should have been done in it's own PR, as it is not controversial.
Deprecate URIUtil methods that are not normalizing URI strings properly from component parts.
Can you explain what is incorrect about the current normalization?
Add relevant HttpScheme methods to perform proper normalization of URI components.
HttpScheme is the wrong location for these normalization methods. Keep them in URIUtil.
Migrate all existing code to use new HttpScheme methods.
You need to motivate why we are doing this. There are behaviour changes, API changes and class/location changes all in one PR, so it is hard to pick apart why/what/how
* @param query the optional query (any encoding is assumed to be performed already) | ||
* @param fragment the optional fragment (any encoding is assumed to be performed already) | ||
*/ | ||
public static void concatNormalizedURI(StringBuilder url, String scheme, String server, int port, String path, String query, String fragment) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Most of these new methods, and this one specifically, are not HttpScheme
methods, but rather URIUtil
. This class should only have schemes and their metadata, not arbitrary URI util methods.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We would wind up duplicating HttpScheme in jetty-util then.
This change to move the URI behaviors that need scheme knowledge to HttpScheme was specifically requested by @sbordet
…iutil-append-scheme-host-port
Done, this is not relevant to this PR.
Note: The specific changes in this PR was requested by @sbordet URIUtil version only works for a subset of schemes. We've had reports that we generate URL/URI in various places that are triggering various auditing / security layers when it encounters things that are viewed as "suspicious" (a loosely defined term meaning "we do things that don't follow the specs" and is an indication of nefarious actors).
The building of the normalized URI needs scheme knowledge to do a critical piece properly (the port).
Consistency, we don't normalize scheme / port combinations properly across the codebase. At this point, this PR is the completion of the task set to me from @sbordet |
@joakime thanks for the explanations. I think we should do as you suggest and effectively "move" So either we can create an The methods in URIUtil can then be corrected to do the normalization correctly (and new APIs added if the old ones are not good) and we could then see some explicit changes in URIUtilTest that make it clear how we have changed normalization. That way we don't end up with unused wrong normalization methods that might accidentally get used again in future, plus new normalization methods with different behaviours. @sbordet thoughts? |
@gregw the scheme and the port are related and Producing a proper URI string by concatenation requires scheme/port knowledge, so the concatenation logic must be close to I don't see why are you proposing to move everything to I can live with deprecating |
@sbordet if we add URI normalization methods to oej.http, then we end up with two sets of URI normalization: in We already have Adding |
Thing is jetty-util is also too far down the dependency tree for all of this. Knowing this truth about our current codebase in HEAD, why not just use HttpURI instead? See Draft PR #11415 as an alternate solution. |
@joakime However, it still does leave URIUtil with substandard normalization. We could make everything use What does "too far down" mean? I understand that currently We can then fix the normalization that exists in |
Closing in favor of #11415 that uses a mix of HttpURI and new URIUtil methods |