include ref in path as WW-5011 workaround#353
include ref in path as WW-5011 workaround#353yasserzamani merged 5 commits intoapache:struts-2-5-xfrom
Conversation
|
FYI I checked all references (usages) of |
|
Coverage decreased (-0.01%) to 47.014% when pulling fd91e75 on yasserzamani:WW-5011-2-5 into b23bfd4 on apache:struts-2-5-x. |
|
This will break backward-compatibility if someone extends |
e1661cf to
803feba
Compare
|
👍 I reset the PR to minimize backward-compatibility issues as much as possible :) |
|
Oh I realized ℹ️ Squash is recommended if accepted |
JCgH4164838Gh792C124B5
left a comment
There was a problem hiding this comment.
Hello @yasserzamani .
Thanks for advising me of this PR. 😄
After reviewing the changes I've commented in locations where some risks could be addressed.
For 2.5.x I'm still more comfortable with an opt-in/opt-out mechanism, even with a fallback-oriented logic like you've created in this PR.
Maybe this PR could consider using the new logic by default but allow an opt-out flag "struts.tiles.originalFileResourceHandling" (similar but opposite to the opt-in flag in PR#348) ?
That strategy would essentially eliminate backwards-compatibility risk for 2.5.x but still allow for the "new and improved" logic to be transparent by default.
Either way good work on the PR so far. 👍
Let me know what you think and let me know if my comments make sense or not.
| String path; | ||
| try { | ||
| //workarounds WW-5011 because includes ref in path | ||
| path = url.toURI().getPath(); |
There was a problem hiding this comment.
This might work, but I'm not sure whether a sub-context representation will always equate to a URL/URI anchor/fragment.
There was a problem hiding this comment.
I'm not sure if I could understand well but URI doesn't have getRef method while URL has which means URI has included ref (i.e. what is after "#") in path. My added unit tests verify this.
| // fallback solution | ||
| path = url.getPath(); | ||
|
|
||
| if (url.getRef() != null && !new File(path).exists()) { |
There was a problem hiding this comment.
Similar comment about sub-context representation and anchor/fragment "#".
A larger concern is there is now a File existence check happening here. That seems very risky as the URL can represent a non-file protocol resource.
There was a problem hiding this comment.
But getLastModified method already considers it should be a file.
There was a problem hiding this comment.
It seems getLastModified() considers the possibility that resource (path) is a file, but it doesn't assume it has to be a file.
If the path doesn't exist as a file (e.g. nonexistent file or non-file URL) then exists() will be false and getLastModified() just returns 0. (As a side note the base Tiles interface also allows for an IOException to be thrown if there's no modified date available ... but Struts has attempted to avoid that).
There was a problem hiding this comment.
fixed :) - learnt from tiles URLApplicationResource.
| /** | ||
| * workarounds WW-5011 | ||
| */ | ||
| private static String getExistedPath(URL url) throws MalformedURLException { |
There was a problem hiding this comment.
Maybe getExistedPath() would be clearer with a name like getExtractedPath() ?
There was a problem hiding this comment.
I named such because WW-5011 is because url.getPath doesn't exist always. What does Extracted refer?
There was a problem hiding this comment.
I thought "Extracted" was more general - just indicates the method attempts to extract the path from the URL (whether it actually exists or not).
Since the URL resource may not be a file, a File.exists() test cannot always determine if the path actually exists or not...
There was a problem hiding this comment.
fixed :) - learnt from tiles URLApplicationResource.
| @Override | ||
| public long getLastModified() throws IOException { | ||
| File file = new File(url.getPath()); | ||
| File file = new File(super.getLocalePath()); |
There was a problem hiding this comment.
I think this should call getExistedPath(url) (or its equivalent if it gets renamed).
The constructor used to call url.getPath() for its parameter, just like this method used to.
Since the constructor now calls getExistedPath(url), this method should probably call it too (for consistency).
There was a problem hiding this comment.
We already have passed it to super and we don't need compute it once again. My added unit tests show it seems work.
There was a problem hiding this comment.
The problem is super.getLocalePath() (from the Tiles code) doesn't guarantee return of the exact path string passed to super. Unfortunately the unit test can't easily check all possibilities, and changing the parameter passed risks breaking existing applications unexpectedly (in hard to predict ways).
If we want to avoid re-computing the path value, then maybe we should just add a new attribute to cache the URL path string in this PR and modify it like this:
final String urlPath;
// Code up to the constructor
public StrutsApplicationResource(URL url) throws MalformedURLException {
urlPath = getExistedPath(url);
super(urlPath);
this.url = url;
}
// Intervening code
@Override
public long getLastModified() throws IOException {
File file = new File(urlPath);
// Rest of codeThere was a problem hiding this comment.
fixed :) - learnt from tiles URLApplicationResource.
| try { | ||
| resources.add(new StrutsApplicationResource(entry.getValue())); | ||
| } catch (MalformedURLException e) { | ||
| LOG.warn("Cannot access [{}]", entry.getValue(), e); |
There was a problem hiding this comment.
Not sure if this is better as a debug level instead of warn ?
It's clearer with a warn, but users might not expect warnings in the logs (since it wouldn't happen before), so a debug might be "safer".
There was a problem hiding this comment.
We already have warn in current code a few lines above this newly added line :)
There was a problem hiding this comment.
True ... but that warn it isn't in a loop like this one (which was what "caught my eye") 😉
There was a problem hiding this comment.
👍 throw exception removed at all to honor lazy file existence check .
| } | ||
| } | ||
|
|
||
| if (!new File(path).exists()) { |
There was a problem hiding this comment.
(Oops ... comment accidentally dropped from my review, re-adding as a single comment)
The File existence checks are dangerous because the URL can be a non-file protocol resource.
For that reason it is recommended that the two File existence checks are either removed or the logic changed so that File existence checks are only performed after verifying the URL represents a file protocol resource. The check could be something like:
if ("file".equalsIgnoreCase(url.getProtocol())) {
// Perform file existence checks
}
// Return extracted path String (for non-File URLs or File URLs that pass existence checks).There was a problem hiding this comment.
👍 good idea, thanks!
|
|
||
| public StrutsApplicationResource(URL url) { | ||
| super(url.getPath()); | ||
| super(getFilePath(url)); |
There was a problem hiding this comment.
One last suggestion 😄 for the constructor (avoids calling getFilePath twice/regenerating the path string):
final String urlPath = getFilePath(url);
super(urlPath);
this.url = url;
this.file = new File(urlPath);|
Hello @yasserzamani . After your latest changes it LGTM 👍 Sorry to be a pain ... but I made one (last) minor suggestion above concerning the constructor, It's actually something you suggested earlier to avoid re-generating the path string twice, I'll go ahead and set feedback as approved whether you decide that additional change is worth it or not. Thanks for all of your work on this PR. 😄 p.s. It looks like this PR had the same Java 8 Travis CI failure that shows up intermittently too. |
|
No, it's fine :) thanks for your support! - actually this PR is very better now than mine :) I had tried to avoid re-computing the path but it says Travis build fixed by another commit 👍 |
|
Hello @lukaszlenart and @aleksandr-m. It looks like this PR is ready to go once one of you reviews the latest version and thinks it can be approved. Assuming it is approved/merged, then I can close my original PR for this issue. :) |
|
Looks good to me, LGTM 👍 |
include ref in path for StrutsApplicationResource as WW-5011 workaround (when real path or filename contains "#" character)