Describe the bug
Affects old and new UI. Discovered in 2020.2 alpha, was able to replicate in 2020.1.6. When making selections in a Canvas selection session, if you spam click Save with at least one selection set, it will trigger an error.
In the legacy search New UI, start a selection session and add an attachment or resource summary. Then spam click (double click sometimes works but otherwise just quickly click repeatedly) “Save” and a full page error will display.
500: Internal Server Error - Already rendered!
In the old UI, this happens with a different error message.
Troublingly, once this has happened it seems that any further selection sessions will have the same issue when hitting Save, preventing selections.
This is specific to Canvas integration - it occurs within CanvasConnectorService when attempting to get a response.getMessage. There is also a missing language string in the area- com.tle.core.connectors.canvas.error.prelim which used to read:
An error occurred in Canvas\:
To Reproduce
Steps to reproduce the behavior:
Go to a selection session from Canvas.
Make some selections.
Very quickly, repeatedly click the Save button.
See full page error.
Re open selection session.
Make some selections.
Click Save once.
Note that the same issue arises as before.
Expected behavior
We should handle this better, perhaps debouncing the Save call such that it doesn't cause issues. If #2600 were to be fixed, it would make this much harder to occur as it would close the selection session after the first save click.
The expected behaviour would be to handle spam clicking without error.
Screenshots
Here are two clips of this happening in the old and new UI. Note - this does not have to be a cloud search selection, that's simply what I was testing at the time that I found this bug. You can make this happen with any selection.
Stacktrace
java.lang.RuntimeException: ???com.tle.core.connectors.canvas.error.prelim??? (400) Bad Request --- <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>400 Bad Request</title>
</head><body>
<p>Your browser sent a request that this server could not understand.<br />
Size of a request header field exceeds server limit.</p>
<hr>
<address>Apache Server at canvas.instructure.com Port 80</address>
</body></html>
at com.tle.core.connectors.canvas.service.CanvasConnectorService.getCanvasResponse(CanvasConnectorService.java:803)
at com.tle.core.connectors.canvas.service.CanvasConnectorService.getCanvasResponse(CanvasConnectorService.java:760)
at com.tle.core.connectors.canvas.service.CanvasConnectorService.getCanvasJSONResponse(CanvasConnectorService.java:749)
at com.tle.core.connectors.canvas.service.CanvasConnectorService.getCanvasCourse(CanvasConnectorService.java:650)
at com.tle.core.connectors.canvas.service.CanvasConnectorService.getCourseCode(CanvasConnectorService.java:140)
at com.tle.core.connectors.service.ConnectorRepositoryServiceImpl.addItemToCourse(ConnectorRepositoryServiceImpl.java:191)
at com.tle.core.security.impl.MethodSecurityInteceptor.invoke(MethodSecurityInteceptor.java:79)
at com.tle.core.security.impl.MethodSecurityInteceptor.invoke(MethodSecurityInteceptor.java:79)
at com.tle.integration.lti.canvasextension.CanvasIntegration.select(CanvasIntegration.java:418)
at com.tle.integration.lti.canvasextension.CanvasIntegration.select(CanvasIntegration.java:79)
at com.tle.web.integration.IntegrationImpl.select(IntegrationImpl.java:63)
at com.tle.web.integration.IntegrationSection.executeSelectionsMade(IntegrationSection.java:57)
at com.tle.web.selection.TreeLookupSelectionCallback.executeSelectionsMade(TreeLookupSelectionCallback.java:37)
at com.tle.web.selection.SelectionServiceImpl.returnFromSession(SelectionServiceImpl.java:146)
at com.tle.web.selection.section.CourseListSection.save(CourseListSection.java:510)
at sun.reflect.GeneratedMethodAccessor411.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.tle.web.sections.events.js.MethodInvocationEventGenerator$1.fireDirect(MethodInvocationEventGenerator.java:94)
at com.tle.web.sections.events.AbstractDirectEvent.fire(AbstractDirectEvent.java:86)
at com.tle.web.sections.generic.DefaultSectionInfo.processEvent(DefaultSectionInfo.java:420)
at com.tle.web.sections.generic.DefaultSectionInfo.processEvent(DefaultSectionInfo.java:394)
at com.tle.web.sections.generic.DefaultSectionInfo.processQueue(DefaultSectionInfo.java:388)
at com.tle.web.sections.registry.AbstractSectionsController.execute(AbstractSectionsController.java:44)
at com.tle.web.api.LegacyContentApi.$anonfun$submit$1(LegacyContentApi.scala:450)
at com.tle.web.api.LegacyContentApi.withTreePath(LegacyContentApi.scala:318)
at com.tle.web.api.LegacyContentApi.submit(LegacyContentApi.scala:447)
at sun.reflect.GeneratedMethodAccessor182.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:138)
at org.jboss.resteasy.core.ResourceMethodInvoker.internalInvokeOnTarget(ResourceMethodInvoker.java:543)
at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTargetAfterFilter(ResourceMethodInvoker.java:432)
at org.jboss.resteasy.core.ResourceMethodInvoker.lambda$invokeOnTarget$0(ResourceMethodInvoker.java:393)
at org.jboss.resteasy.core.interception.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:358)
at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTarget(ResourceMethodInvoker.java:395)
at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:364)
at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:337)
at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:440)
at org.jboss.resteasy.core.SynchronousDispatcher.lambda$invoke$4(SynchronousDispatcher.java:229)
at org.jboss.resteasy.core.SynchronousDispatcher.lambda$preprocess$0(SynchronousDispatcher.java:135)
at org.jboss.resteasy.core.interception.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:358)
at org.jboss.resteasy.core.SynchronousDispatcher.preprocess(SynchronousDispatcher.java:138)
at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:215)
at org.jboss.resteasy.plugins.server.servlet.ServletContainerDispatcher.service(ServletContainerDispatcher.java:245)
at org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.service(HttpServletDispatcher.java:61)
at org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.service(HttpServletDispatcher.java:56)
at com.tle.web.remoting.resteasy.RestEasyServlet.service(RestEasyServlet.java:140)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:733)
at com.tle.web.dispatcher.ServletDispatcher.dispatch(ServletDispatcher.java:95)
at com.tle.web.dispatcher.RequestDispatchFilter.doFilter(RequestDispatchFilter.java:91)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:542)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:143)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:374)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:880)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1601)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
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(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:748)
11:51:06,230 ERROR [RestEasyExceptionMapper] REST API error
com.tle.web.sections.SectionsRuntimeException: Already rendered!
at com.tle.web.sections.generic.DefaultSectionInfo.setRendered(DefaultSectionInfo.java:100)
at com.tle.web.api.LegacyContentApi.$anonfun$submit$5(LegacyContentApi.scala:456)
at scala.Option.getOrElse(Option.scala:189)
at com.tle.web.api.LegacyContentApi.$anonfun$submit$1(LegacyContentApi.scala:455)
at com.tle.web.api.LegacyContentApi.withTreePath(LegacyContentApi.scala:318)
at com.tle.web.api.LegacyContentApi.submit(LegacyContentApi.scala:447)
at sun.reflect.GeneratedMethodAccessor182.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:138)
at org.jboss.resteasy.core.ResourceMethodInvoker.internalInvokeOnTarget(ResourceMethodInvoker.java:543)
at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTargetAfterFilter(ResourceMethodInvoker.java:432)
at org.jboss.resteasy.core.ResourceMethodInvoker.lambda$invokeOnTarget$0(ResourceMethodInvoker.java:393)
at org.jboss.resteasy.core.interception.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:358)
at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTarget(ResourceMethodInvoker.java:395)
at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:364)
at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:337)
at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:440)
at org.jboss.resteasy.core.SynchronousDispatcher.lambda$invoke$4(SynchronousDispatcher.java:229)
at org.jboss.resteasy.core.SynchronousDispatcher.lambda$preprocess$0(SynchronousDispatcher.java:135)
at org.jboss.resteasy.core.interception.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:358)
at org.jboss.resteasy.core.SynchronousDispatcher.preprocess(SynchronousDispatcher.java:138)
at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:215)
at org.jboss.resteasy.plugins.server.servlet.ServletContainerDispatcher.service(ServletContainerDispatcher.java:245)
at org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.service(HttpServletDispatcher.java:61)
at org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.service(HttpServletDispatcher.java:56)
at com.tle.web.remoting.resteasy.RestEasyServlet.service(RestEasyServlet.java:140)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:733)
at com.tle.web.dispatcher.ServletDispatcher.dispatch(ServletDispatcher.java:95)
at com.tle.web.dispatcher.RequestDispatchFilter.doFilter(RequestDispatchFilter.java:91)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:542)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:143)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:374)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:880)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1601)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
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(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:748)
Platform:
OpenEquella Version: Tested 2020.1.6, 2020.2 alpha. Probably quite a bit older.
Describe the bug Affects old and new UI. Discovered in 2020.2 alpha, was able to replicate in 2020.1.6. When making selections in a Canvas selection session, if you spam click Save with at least one selection set, it will trigger an error.
In the legacy search New UI, start a selection session and add an attachment or resource summary. Then spam click (double click sometimes works but otherwise just quickly click repeatedly) “Save” and a full page error will display.
500: Internal Server Error - Already rendered!
In the old UI, this happens with a different error message.
Troublingly, once this has happened it seems that any further selection sessions will have the same issue when hitting Save, preventing selections.
This is specific to Canvas integration - it occurs within CanvasConnectorService when attempting to get a response.getMessage. There is also a missing language string in the area-
com.tle.core.connectors.canvas.error.prelim
which used to read:An error occurred in Canvas\:
To Reproduce Steps to reproduce the behavior:
Expected behavior We should handle this better, perhaps debouncing the Save call such that it doesn't cause issues. If #2600 were to be fixed, it would make this much harder to occur as it would close the selection session after the first save click. The expected behaviour would be to handle spam clicking without error.
Screenshots Here are two clips of this happening in the old and new UI. Note - this does not have to be a cloud search selection, that's simply what I was testing at the time that I found this bug. You can make this happen with any selection.
Stacktrace
Platform: