Skip to content

Commit

Permalink
Ensure that a canonical path is always used for the docBase of a Cont…
Browse files Browse the repository at this point in the history
…ext to ensure consistent behaviour.

git-svn-id: https://svn.apache.org/repos/asf/tomcat/tc8.5.x/trunk@1842703 13f79535-47bb-0310-9956-ffa450edef68
  • Loading branch information
markt-asf committed Oct 3, 2018
1 parent 7801929 commit fd2abbb
Show file tree
Hide file tree
Showing 2 changed files with 5 additions and 1 deletion.
2 changes: 1 addition & 1 deletion java/org/apache/catalina/startup/ContextConfig.java
Expand Up @@ -579,7 +579,7 @@ protected void fixDocBase() throws IOException {

File file = new File(docBase);
if (!file.isAbsolute()) {
docBase = (new File(appBase, docBase)).getPath();
docBase = (new File(appBase, docBase)).getCanonicalPath();

This comment has been minimized.

Copy link
@gjaekel

gjaekel Mar 10, 2019

Dear Mark,

please revert this change: While formerly working, this will break the startup of an application WAR, if it is

  1. deployed by using an symbolic link and
  2. the destination name of the link will not end with '.war'

for instance foo.war -> /some/path/to/bar.war.version-tag.

Guido

This comment has been minimized.

Copy link
@michael-o

michael-o Mar 10, 2019

Member

@gjaekel is there any compelling reason not to name your WARs: {artifactId}-{version}.war?

@markt-asf What was the motivation for this change? Which consistency do we win here?

This comment has been minimized.

Copy link
@gjaekel

gjaekel Mar 10, 2019

@michael-o:
Dear Michael,
thank you for discussion and moderation!

tltr: yes, because our scheme in the deployment backend is used in this way since more than 10 years. And it's not forbidden in any way: Tomcat don't have to care about the name of the destination of a symlink of a WAR.

Long version: All the WARs in every document base at every virtual host on my Tomcat farm already are named foo.war, other are named sub#path#bar.war to form an "Application" from different parts. In addition, there are instances like instance_a.war and foo_mandator_a.war, foo_mandator_b.war that are symlinks to local linked "templates" named ./foo._war (to exclude this to be taken into account for deploy), that are itself also a link. And the concrete instance of the unique artifact will detect the mandator to act for by it's own deployment name. I think it's also not very common that somebody uses the feature of root context definition.

All WARs are linked into a "webapp repository" on a shared r/o directory tree.This is organized in path and names by projects, internal artifact names, it's versions, and deployment aims (different set of Tomcats on a couple of stages).

I describe this just for explanation, and I'm sorry, but IMHO it have to be complete out of Tomcat's scope to where a symlink will point and what is the concrete name of the destination - that's in the domain of the underlying operating system. As all the years, Tomcat just have to care about the local view, the name of a file or directory, regardless if it's a plain file, a hard or soft symlink or whatever the operating system is able to offer to the JVM if it request to "list the directory" of the docbase.

That's my "con" against the change. I'm curious to get the "pro" for the change, i.e. anything that is broken without and works with.

And I'm sure: If there is some, we'll find a resolution to get both intentions in line.

Guido

This comment has been minimized.

Copy link
@michael-o

michael-o Mar 10, 2019

Member

Wow, I'll need some time to mentally process this. But what I at least would expect from our code is that if the canonical path is not the given path and the canonical target isn't \.war$ an error shall be logged because symlinks are opaque to the application.

This comment has been minimized.

Copy link
@gjaekel

gjaekel Mar 10, 2019

Yes, "Wow" fits: A little change, but a big effect.

Please notice: All aspects of the "Context setup" are still taken from the name of the link itself. But org.apache.catalina.webresources.StandardRoot.createMainResourceSet() -- in fact org.apache.catalina.startup.ContextConfig() -- fails about the fact that the link destination don't end with .war. And that's is of no matter at all.

I already started a thread on the user mailing list. For easy reference, i'll add the decription and the "tweaked" error message here again:

  • If I a deployment is a file named 'foo.war', all works well as before and expected.
  • If it an symbolic link named 'foo.war' pointing to '[/]bar.war', also all works as before and expected (i.e. the root context name is 'foo')
  • But now and in contrast to before: if the link destination don't have the extension '.war', the deployment process will fail.

From this, after establishing the link

foo.war -> some/path/to/destination/bar.any_non-war-extension

for deployment, with the newer Tomcat version I get the error

	20190308-092433.557 ERROR [catalina-exec-38] [] [[/manager]] FAIL - Application at context path [/foo] could not be started
	org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Catalina].StandardHost[localhost].StandardContext[/foo]]
	        at org.apache.catalina.util.LifecycleBase.start(Unknown Source)
	        at org.apache.catalina.manager.ManagerServlet.start(Unknown Source)
	        at org.apache.catalina.manager.HTMLManagerServlet.start(Unknown Source)
	        at org.apache.catalina.manager.HTMLManagerServlet.doPost(Unknown Source)
	        at javax.servlet.http.HttpServlet.service(Unknown Source)
	        at javax.servlet.http.HttpServlet.service(Unknown Source)
	        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(Unknown Source)
	        at org.apache.catalina.core.ApplicationFilterChain.doFilter(Unknown Source)
	        at org.apache.catalina.filters.CsrfPreventionFilter.doFilter(Unknown Source)
	        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(Unknown Source)
	        at org.apache.catalina.core.ApplicationFilterChain.doFilter(Unknown Source)
	        at org.apache.tomcat.websocket.server.WsFilter.doFilter(Unknown Source)
	        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(Unknown Source)
	        at org.apache.catalina.core.ApplicationFilterChain.doFilter(Unknown Source)
	        at org.apache.catalina.filters.SetCharacterEncodingFilter.doFilter(Unknown Source)
	        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(Unknown Source)
	        at org.apache.catalina.core.ApplicationFilterChain.doFilter(Unknown Source)
	        at org.apache.catalina.core.StandardWrapperValve.invoke(Unknown Source)
	        at org.apache.catalina.core.StandardContextValve.invoke(Unknown Source)
	        at org.apache.catalina.authenticator.AuthenticatorBase.invoke(Unknown Source)
	        at org.apache.catalina.core.StandardHostValve.invoke(Unknown Source)
	        at org.apache.catalina.valves.ErrorReportValve.invoke(Unknown Source)
	        at org.apache.catalina.valves.RequestFilterValve.process(Unknown Source)
	        at org.apache.catalina.valves.RemoteAddrValve.invoke(Unknown Source)
	        at org.apache.catalina.valves.AbstractAccessLogValve.invoke(Unknown Source)
	        at org.apache.catalina.core.StandardEngineValve.invoke(Unknown Source)
	        at org.apache.catalina.connector.CoyoteAdapter.service(Unknown Source)
	        at org.apache.coyote.http11.Http11Processor.service(Unknown Source)
	        at org.apache.coyote.AbstractProcessorLight.process(Unknown Source)
	        at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(Unknown Source)
	        at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(Unknown Source)
	        at org.apache.tomcat.util.net.SocketProcessorBase.run(Unknown Source)
	        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
	        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	        at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(Unknown Source)
	        at java.lang.Thread.run(Thread.java:748)
	Caused by: org.apache.catalina.LifecycleException: Failed to start component [org.apache.catalina.webresources.StandardRoot@23279aae]
	        at org.apache.catalina.util.LifecycleBase.start(Unknown Source)
	        at org.apache.catalina.core.StandardContext.resourcesStart(Unknown Source)
	        at org.apache.catalina.core.StandardContext.startInternal(Unknown Source)
	        ... 36 more
	Caused by: java.lang.IllegalArgumentException: The main resource set specified [/some/full/path/to/destination/bar.any_non-war_extension] is not valid
	        at org.apache.catalina.webresources.StandardRoot.createMainResourceSet(Unknown Source)
	        at org.apache.catalina.webresources.StandardRoot.startInternal(Unknown Source)
	        ... 39 more

At this state, the Context is listed as '/foo' in the Tomcat Manager (with running=false) and if I start it here, the Message is equivalent:

FAIL - Application at context path [/foo] could not be started
FAIL - Encountered exception [org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Catalina].StandardHost[localhost].StandardContext[/foo]]]

} else {
docBase = file.getCanonicalPath();
}
Expand Down
4 changes: 4 additions & 0 deletions webapps/docs/changelog.xml
Expand Up @@ -73,6 +73,10 @@
<code>web.xml.default</code> that can be used to customize <code>conf/context.xml</code>
and <code>conf/web.xml</code> on a per host basis. (fschumacher)
</fix>
<fix>
Ensure that a canonical path is always used for the docBase of a Context
to ensure consistent behaviour. (markt)
</fix>
</changelog>
</subsection>
<subsection name="Coyote">
Expand Down

0 comments on commit fd2abbb

Please sign in to comment.