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

Share Log Settings - Error downloading (some) log files #99

Closed
AFaust opened this issue Sep 17, 2017 · 5 comments · Fixed by #101
Closed

Share Log Settings - Error downloading (some) log files #99

AFaust opened this issue Sep 17, 2017 · 5 comments · Fixed by #101
Assignees
Labels
Milestone

Comments

@AFaust
Copy link
Contributor

AFaust commented Sep 17, 2017

Expected behavior

When opening the "Share Log Files" / "Repository Log Files" dialogs, all log files can be individually downloaded.

Actual behavior

When opening the "Share Log files" dialog, only some of the log files could be downloaded, and in some cases only once. For most log files, no action was apparent to the end user. The log file of Share showed exceptions like:

2017-09-17 16:22:24,785 ERROR [org.alfresco.web.site] [catalina-exec-10] org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.springframework.extensions.webscripts.WebScriptException: 08170008 Internal error
org.springframework.extensions.webscripts.WebScriptException: 08170008 Internal error
	at org.springframework.extensions.webscripts.AbstractRuntime.renderErrorResponse(AbstractRuntime.java:367)
	at org.springframework.extensions.webscripts.AbstractRuntime.executeScript(AbstractRuntime.java:246)
	at org.springframework.extensions.webscripts.servlet.mvc.WebScriptView.renderMergedOutputModel(WebScriptView.java:104)
	at org.springframework.web.servlet.view.AbstractView.render(AbstractView.java:264)
	at org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1216)
	at org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1001)
	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:945)
	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:867)
	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:951)
	at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:842)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
	at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:827)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
	at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
	at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:749)
	at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:487)
	at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:412)
	at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:339)
	at org.tuckey.web.filters.urlrewrite.NormalRewrittenUrl.doRewrite(NormalRewrittenUrl.java:213)
	at org.tuckey.web.filters.urlrewrite.RuleChain.handleRewrite(RuleChain.java:171)
	at org.tuckey.web.filters.urlrewrite.RuleChain.doRules(RuleChain.java:145)
	at org.tuckey.web.filters.urlrewrite.UrlRewriter.processRequest(UrlRewriter.java:92)
	at org.tuckey.web.filters.urlrewrite.UrlRewriteFilter.doFilter(UrlRewriteFilter.java:389)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
	at org.springframework.extensions.webscripts.servlet.SecurityHeadersFilter.doFilter(SecurityHeadersFilter.java:177)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
	at org.springframework.extensions.webscripts.servlet.CSRFFilter.doFilter(CSRFFilter.java:322)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
	at org.alfresco.web.site.servlet.SSOAuthenticationFilter.doFilter(SSOAuthenticationFilter.java:474)
	at org.alfresco.web.site.servlet.SSOAuthenticationFilter.doFilter(SSOAuthenticationFilter.java:443)
	at org.springframework.extensions.webscripts.servlet.BeanProxyFilter.doFilter(BeanProxyFilter.java:80)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:100)
	at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:953)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
	at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1041)
	at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:603)
	at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.doRun(AprEndpoint.java:2430)
	at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.run(AprEndpoint.java:2419)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
	at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.IllegalStateException: getOutputStream() has already been called for this response
	at org.apache.catalina.connector.Response.getWriter(Response.java:638)
	at org.apache.catalina.connector.ResponseFacade.getWriter(ResponseFacade.java:214)
	at javax.servlet.ServletResponseWrapper.getWriter(ServletResponseWrapper.java:105)
	at org.springframework.extensions.webscripts.servlet.WebScriptServletResponse.getWriter(WebScriptServletResponse.java:226)
	at org.springframework.extensions.webscripts.AbstractRuntime.renderErrorResponse(AbstractRuntime.java:362)
	... 54 more

Steps to reproduce the behavior

  • Start Alfresco Repository and Share
  • Browse to Share Admin Tools => Log4J Settings
  • Use "Share Log Files" button to access Share-tier log files

Additional details (analysis so far, log statements, references, etc.)

Tell us about your environment

Windows 10 64-bit, JDK 1.8.0_112, Alfresco Share 5.2.e, Alfresco Repository 5.2.f

@AFaust AFaust added the bug label Sep 17, 2017
@AFaust AFaust added this to the 1.0.0.0 milestone Sep 17, 2017
@AFaust AFaust self-assigned this Sep 17, 2017
@AFaust
Copy link
Contributor Author

AFaust commented Sep 17, 2017

The problem appears to be related to the Surf extension module processing on web scripts. Since the Repository-tier does not have this capability by default it might not be affected. Essentially, after the web script has already streamed the log file via the web script response output stream, the web script runtime container attempts to close the extensibility model. This entails getting a writer to the web script response, which fails because the output stream has already been accessed.

@AFaust
Copy link
Contributor Author

AFaust commented Sep 17, 2017

What "gems" one can find in the Surf source code. There is actually a way to suppress processing of the extensibility model, but it is neither exposed in a way that would allow it to be used for custom web scripts nor is it thread-safe. It is currently used in the FreeMarker "ProcessJsonModelDirective" when building "constants" for a Surf page (building the aggregated Dojo & AIkau JS / CSS dependencies and messages bootstrap). The following implementation is called in the LocalWebScriptRuntimeContainer:

    boolean extensibilitySuppressed = false;
    
    public void suppressExtensibility()
    {
        this.extensibilitySuppressed = true;
    }
    
    public void unsuppressExtensibility()
    {
        this.extensibilitySuppressed = false;
    }
    
    public boolean isExtensibilitySuppressed()
    {
        return this.extensibilitySuppressed;
    }

Should any web script request be processed while a page is being loaded in a different thread, this would prevent any extensions from working on that web script.

The core problem is that the LocalWebScriptRuntimeContainer will always process the extensibility model and access the writer, even if no extension was actually applied to the current request. This in effect prevents any AbstractWebScript to work that uses the output stream on the web script response to stream a response. Interestingly, I already identified and solved a similar issue with my Acosix Utility module that adds an extensible web script container on the Repository-tier, so this problem does not occur there even though my Repository has extensibility enabled much like Share has by default.

While we should file an issue with Alfresco for the conflict between extension module support and compatibility with generic AbstractWebScript implementations, a quick work-around would be possible by writing the response to the extensibility model instead of the web script response. The only problem is that this workaround only supports text-based content, and this issue could thus not be addressed for the ZIP-based download of multiple log files.

@AFaust
Copy link
Contributor Author

AFaust commented Sep 17, 2017

Even better - there already are the classes ExtensibilityHttpResponse / ExtensibilityServletOutputStream that are designed to facade the actual response and output stream, and transparently support writing to the extensibility model. Unfortunately though, those are only used for processing JSP-based web scripts and rendering the template header of a Surf template instance.

@AFaust
Copy link
Contributor Author

AFaust commented Sep 17, 2017

Reported as ALF-21949

@AFaust
Copy link
Contributor Author

AFaust commented Sep 17, 2017

It is yet unclear why downloading of log files works in 10-20 % of tests. Maybe the lack of thread-safety with extension handling has something to do with it.

AFaust added a commit to AFaust/ootbee-support-tools that referenced this issue Oct 29, 2017
- refactor file + streaming handling into shared utilities
- abstract differences between servlet / web script via facade interface
- adjust Aikau service to handle additional URL type
- update / correct some copyright notes
- add explicit Surf dependency as transitive dependency was missing
- move dependency management information into appropriate section
AFaust added a commit that referenced this issue Nov 19, 2017
- refactor file + streaming handling into shared utilities
- abstract differences between servlet / web script via facade interface
- adjust Aikau service to handle additional URL type
- update / correct some copyright notes
- add explicit Surf dependency as transitive dependency was missing
- move dependency management information into appropriate section
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
1 participant