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

Issue #10084 - Directory results from getResourcePaths(String) should include trailing slash #10085

Merged

Conversation

joakime
Copy link
Contributor

@joakime joakime commented Jul 7, 2023

  • Adding support for trailing slashes on getResourcePaths(String) results.
  • Backporting tests from ee10 to ee9
  • Fixing bug in getRealPath(String) as well

@joakime joakime added Bug For general bugs on Jetty side Jetty 12 labels Jul 7, 2023
@joakime joakime requested a review from gregw July 7, 2023 22:33
@joakime joakime self-assigned this Jul 7, 2023
@joakime joakime added this to the 12.0.x milestone Jul 7, 2023
@joakime joakime linked an issue Jul 7, 2023 that may be closed by this pull request
}

@Test
@Disabled("There is extra decoding of the nested-reserved paths that is getting in the way")
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This can be fixed with @lorban backporting his work in PR #9974 back to ee9 tree.

Copy link
Contributor

Choose a reason for hiding this comment

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

That would also require backporting the fix to 10/11.

gregw
gregw previously requested changes Jul 8, 2023
Comment on lines +819 to +822
String entry = path + item.getFileName();
if (item.isDirectory())
entry = entry + '/';
set.add(entry);
Copy link
Contributor

Choose a reason for hiding this comment

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

Is it possible to resolve this within the resource classes? Previously the resource classes would have the trailing '/' on directories so it would be everywhere. Doing it just here as a post process risks not covering all usages.

Copy link
Contributor Author

@joakime joakime Jul 8, 2023

Choose a reason for hiding this comment

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

The Resource object returns a List<Resource> so I think perhaps the place would be Resource.getFileName() ?

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes getFileName, toString and anything else that returns the path as a string. Ideally even the URI should have the trailing slash. But
I don't think Path retains it.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Turns out fixing getFileName() breaks a lot of test cases.
See latest Jenkins build on this PR.
I'll noodle through them on monday.

Copy link
Contributor

Choose a reason for hiding this comment

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

Would be good to check if any of these texts existed in jetty 11 and see if they were changed to not expect the trailing slash

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 Jetty 11 Resource.getName() does not return the trailing slash on directories.

However, the Jetty 11 Resource.list() returns a String array, and that array has the trailing slash.
The Resource.list() method in Jetty 11 is used ...

  • ContextHandler.getResourcePaths(String) which returns a Set<String> on the Servlet API
  • Resource.getListHTML - used to iterate a directory, and build a new set of Resources, that eventually are presented (in HTML)
  • MetaInfConfiguration - iterates over WEB-INF/lib/*.jar files, and builds a new set of Resources that eventually wind up in the WebAppClassLoader
  • WebAppClassLoader - used in addJars(Resource) to iterate a directory and build a new set of Resources that are added to the WebAppClassLoader
  • Runner.Classpath.addJars(Resource) - same a WebAppClassLoader.addJars(Resource)

Turns out that in Jetty 12 we skip the String array step (eg: the Resource -> String array -> List of Resource -> iterate/process flow).
In Jetty 11, we don't rely on the results of Resource.getName() for anything critical, it seems to be used only for things like debugging, exception messages, keys in the annotation parser, etc.

@joakime joakime requested a review from lorban July 8, 2023 09:55
@joakime joakime marked this pull request as draft July 8, 2023 13:04
@joakime joakime requested a review from gregw July 8, 2023 13:04
}

@Test
@Disabled("There is extra decoding of the nested-reserved paths that is getting in the way")
Copy link
Contributor

Choose a reason for hiding this comment

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

That would also require backporting the fix to 10/11.

joakime added 3 commits July 10, 2023 09:17
…iling slash on dirs

+ Bring Resource.getFileName in
  alignment with other JVM methods
  of the same name.
  eg: Path.getFileName
@joakime joakime marked this pull request as ready for review July 10, 2023 17:42
@joakime joakime requested a review from lorban July 11, 2023 12:29
@joakime joakime dismissed gregw’s stale review July 11, 2023 13:58

Stale review

@joakime joakime merged commit c8fd1a1 into jetty-12.0.x Jul 11, 2023
@joakime joakime deleted the fix/12.0.x/getresourcepaths-dirs-with-trailing-slash branch July 11, 2023 16:39
@gregw
Copy link
Contributor

gregw commented Jul 12, 2023

@joakime whoa! you're dismissing my reviews now and merging anyway?!?!?!
I still believe this is the wrong approach of just fixing listing. It looks like the dropping of the trailing "/" for directories was made when you switched from FileResource to PathResource.
Fixing it like this just feels like playing what-a-mole with resource bugs.

gregw added a commit that referenced this pull request Jul 12, 2023
@gregw
Copy link
Contributor

gregw commented Jul 12, 2023

@joakime I have pushed an extra test in c435bfd that checks that for a getResource(String) the result includes a trailing slash for a directory. This test passes, because it turns out that we already have the code in PathResource to ensure there is a trailing slash on the URI.

So I'm less concerned about this PR now... other than dismissing negative review and that it feels wrong that we already have a Resource that internally has the trailing '/' and that returns that in the URI, but that here we are using getFilename() that doesn't return the trailing slash, so we have to re-add it. Looks like make work to me and a chance to get something wrong. Surely we can ask a resource for it's segment relative to another and not have to do the work again externally?

@joakime
Copy link
Contributor Author

joakime commented Jul 12, 2023

See #10085 (comment)

The behavior in Jetty 9/10/11 for this ...

  • Trailing slash was present only in ServletContext.getResourcePaths(String) usages
  • Resource.list() was the place a trailing slash was done.
  • Resource.list() returned a String[]
  • Resource.list() was only used as-is for ServletContext.getResourcePaths(String) (all other uses of Resource.list() took the values and created another collection of Resource objects, which meant the trailing slash wasn't meaningful)
  • The Resource.getName() method did not return a trailing slash for JarFile, File, and Path implementations.
  • URLResource.getName() returned the trailing slash, but only if it was present on the input (it didn't add it)
  • URLResource behavior with getName() was not applied to JarFile implementation.

@joakime
Copy link
Contributor Author

joakime commented Jul 12, 2023

@joakime I have pushed an extra test in c435bfd that checks that for a getResource(String) the result includes a trailing slash for a directory. This test passes, because it turns out that we already have the code in PathResource to ensure there is a trailing slash on the URI.

The getResource(String) returns a value in URL path terms, right? (not filesystem path terms).

The getRealPath(String) likely has the same requirements for trailing slash, but the returned value is in native file system path terms.

Examples:
We have a webapp (exploded directory) on windows, in path C:\jetty\webapps\context\.

  • getRealPath("/WEB-INF/web.xml") should return C:\jetty\webapps\context\WEB-INF\web.xml
  • getRealPath("/css/") should return C:\jetty\webapps\context\css\

Right?

@gregw
Copy link
Contributor

gregw commented Jul 12, 2023

Correct, getResource(String) returns a URL. This is correctly including a trailing slash for directories because our resource implementations correctly contain an internal URI that includes the trailing slash for directories.

It seams wrong/fragile that in order to implement getResourcePaths(String) that there is not some API in resource that can give reasonable access to this trailing slash. Instead this PR used a filename method, which probably rightly doesn't include the trailing slash and then has to recreate the trailing slash repeating existing logic.

It is not explicit what space that the return set of getResourcePaths(String) is in, but given that it doesn't have "real" in it's method name and the examples all include '/', then I think it is safe to assume it is a set of partial URI path segments, decoded (like most other servlet APIs). It should be possible to extract that from the URI in the resource.

But, this got merged without approval, so I guess it is done. But let's remember this when doing any future resource work and look to see if we can avoid duplicating this logic.

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
Projects
None yet
Development

Successfully merging this pull request may close these issues.

ServletApiContext.getResourcePaths() doesn't respect the spec
3 participants