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
Call relative and canonical path support #7839
Conversation
05d7d4b
to
7a6d134
Compare
7a6d134
to
9aee6c7
Compare
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 see you mentioned you looked at java.nio.file.Path
but it would be good to document what was missing that caused us to need a completely custom implementation here.
* // == "../url" | ||
* }}} | ||
*/ | ||
def relative()(implicit request: RequestHeader): String = this.relative(request.path) |
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 don't think we need the ()
here.
return relative(requestHeader.path()); | ||
} | ||
|
||
protected String relative(String startPath) { |
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.
Maybe this should be a public method public String relativeTo(String path)
.
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.
Also this seems like a lot of the logic here could be extracted into a utility method for use elsewhere. Something like PathUtils.relativize
.
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.
When changing this to a public method, it could be good to also improve documentation (with examples) for this method.
@@ -133,6 +139,111 @@ public String webSocketURL(boolean secure, String host) { | |||
return "ws" + (secure ? "s" : "") + "://" + host + this.url(); | |||
} | |||
|
|||
private static String CURDIR = "."; |
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.
Can we have the full names here? CURRENT_DIR
, SEPARATOR
, etc.
String trailingSep = url.endsWith(SEP) ? SEP : ""; | ||
|
||
return prefixSep + canonical.stream().collect(Collectors.joining(SEP)) + trailingSep + this.appendFragment(); | ||
} |
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.
If this implementation is robust (I haven't looked at it carefully enough to know), then we should extract it out somewhere and use it to solve #2337.
Thanks for the review. I'll follow up with another commit shortly. @gmethvin There are several reasons I chose to port Python's impl. instead of using the Java Class Library.
So while it's possible to use the JCL at the end of the day (with some massaging) I just feel that it's not the appropriate thing to do given that the options available are meant to be used with the filesystem and not URL's. However, if you or the rest of the team feel that you would prefer that I can update the PR accordingly. |
… relativeTo. Full names for dir constants. Dropped first params list from scala Call relative method.
/* | ||
* Copyright (C) 2009-2017 Lightbend Inc. <https://www.lightbend.com> | ||
*/ | ||
package play.libs; |
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.
Let's put this in play.core.utils
, since this is a utility mainly for internal use.
@gmethvin I updated it to the @marcospereira What documentation page and section would recommend updating? The main reference to |
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.
@seglo play.core.j
is a weird namespace to use, since that's typically used for Java adapters to the scala API. This looks like more of a generic utility to me.
/** | ||
* Utilities to work with URL paths. | ||
*/ | ||
public class Paths { |
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.
Maybe add a private default constructor here since this isn't meant to be instantiated.
@gmethvin Should I just create the |
@seglo Yes, you can do that, or if you prefer you can rewrite your code in scala (I don't have a strong opinion either way). |
@gmethvin OK. I should have just written it in Scala to begin with.. I had tunnel vision because |
I kept it as Java because I didn't have a compelling reason to rewrite it. I refactored the test coverage as suggested and made other misc. updates. |
LMK where you think the most appropriate place to document this feature would be and I'll add a commit.
|
@seglo I think the reverse routing section is the proper place to document it. Perhaps it would be good to add an example with a template showing both absolute and relative variants. |
I've added documentation to the Java and Scala guide's Routing sections. This was the last outstanding commit I had. |
@gmethvin I fixed some of the errors from the documentation test build, but I'm not really sure what's going on the remaining errors. Could you assist? |
@seglo There were a couple problems. First is that the main template doesn't exist (maybe you forgot to commit it?). The directories also didn't match the package names, and the way twirl templates work it will automatically infer the package name from the directory. See gmethvin@24b6713 |
Thanks a ton @gmethvin . I was getting mixed up between the doc package namespaces and the code sample namespaces. I doublechecked the rendered output and everything looks good. Your commit fixed the failing documentation tests. I think we're ready for a final review. Thanks for your patience. |
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.
lgtm
* Call relative and canonical path support * Move relative & canonical impl to Paths util type. Rename relative -> relativeTo. Full names for dir constants. Dropped first params list from scala Call relative method. * Move Paths to play.core.j namespace * Moved to play.core package * Re-factor tests * Relative routes documentation * Docs tests fixes * Fix package structure * Fix refs to code samples
Pull Request Checklist
Helpful things
Fixes
n/a
Purpose
Add a feature to
Call
to generate a relative route given aRequestHeader
. Usingrelative
routes makes it easier to develop standalone Play! apps that can be hosted behind proxy's or other HTTP gateways regardless of their prefix route. Several examples include:Background Context
Due to several issues[1] with
java.nio.file.Path.relativize(Path other)
I decided to roll my own implementation to create a canonical and relative path. I ported Python's posixpath implementation with a few minor additions to support routes that end without a trailing/
.The implementation is in Java and self-contained within the
play.mvc.Call
type. Two new public methods are available:String relative(Http.RequestHeader requestHeader)
String canonical()
The
relative
implementation is based onrelpath
(fromposixpath.py
) andcommonprefix
(fromgenericpath.py
) in the Python 2.7os.path
package. To canonicalize the URL first I ported thenormpath
implementation (fromposixpath.py
) also in theos.path
package.I also included a suite of tests to support variations of paths to relativize and canonicalize.
References
Feature proposal on the
play-framework-dev
list: https://groups.google.com/forum/#!topic/play-framework-dev/SCXWrbk1k-s[1] https://bugs.openjdk.java.net/browse/JDK-6925169, https://stackoverflow.com/a/37749932/895309