AtlasOfLivingAustralia/downloads-plugin

IllegalArgumentException: URLDecoder: Illegal hex characters in escape (%) pattern

Closed this issue · 7 comments

The following error is happening on all of the hubs for a particular download (running biocache-hubs:2.0.5 with download-plugin:2.0.4) when visiting the following URLs:

https://biocache.ala.org.au/download/doi?doi=10.26197%2F5b5fe244b3013

https://avh.ala.org.au/download/doi?doi=10.26197%2F5b5fe244b3013

https://ozcam.ala.org.au/download/doi?doi=10.26197%2F5b5fe244b3013

2018-07-31 14:55:24.550 ERROR --- [o-8060-exec-237] StackTrace                               : Full Stack Trace:

java.lang.IllegalArgumentException: URLDecoder: Illegal hex characters in escape (%) pattern - For input string: " A"
	at java.net.URLDecoder.decode(URLDecoder.java:194)
	at java_net_URLDecoder$decode.call(Unknown Source)
	at gsp_downloads_plugin_downloaddoi_gsp$_run_closure2.doCall(gsp_downloads_plugin_downloaddoi_gsp.groovy:66)
	at sun.reflect.GeneratedMethodAccessor913.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:93)
	at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:325)
	at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:294)
	at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1022)
	at groovy.lang.Closure.call(Closure.java:414)
	at groovy.lang.Closure.call(Closure.java:408)
	at org.grails.taglib.TagBodyClosure.executeClosure(TagBodyClosure.java:200)
	at org.grails.taglib.TagBodyClosure.captureClosureOutput(TagBodyClosure.java:102)
	at org.grails.taglib.TagBodyClosure.call(TagBodyClosure.java:213)
	at org.grails.plugins.web.taglib.SitemeshTagLib.captureTagContent(SitemeshTagLib.groovy:48)
	at org.grails.plugins.web.taglib.SitemeshTagLib.captureTagContent(SitemeshTagLib.groovy)
	at org.grails.plugins.web.taglib.SitemeshTagLib$_closure3.doCall(SitemeshTagLib.groovy:156)
	at sun.reflect.GeneratedMethodAccessor352.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:93)
	at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:325)
	at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:294)
	at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1022)
	at groovy.lang.Closure.call(Closure.java:414)
	at org.grails.gsp.GroovyPage.invokeTagLibClosure(GroovyPage.java:417)
	at org.grails.gsp.GroovyPage.invokeTag(GroovyPage.java:335)
	at org.grails.gsp.GroovyPage$invokeTag$3.callCurrent(Unknown Source)
	at gsp_downloads_plugin_downloaddoi_gsp.run(gsp_downloads_plugin_downloaddoi_gsp.groovy:105)
	at org.grails.gsp.GroovyPageWritable.doWriteTo(GroovyPageWritable.java:162)
	at org.grails.gsp.GroovyPageWritable.writeTo(GroovyPageWritable.java:82)
	at org.grails.web.servlet.view.GroovyPageView.renderTemplate(GroovyPageView.java:76)
	at org.grails.web.servlet.view.AbstractGrailsView.renderWithinGrailsWebRequest(AbstractGrailsView.java:71)
	at org.grails.web.servlet.view.AbstractGrailsView.renderMergedOutputModel(AbstractGrailsView.java:55)
	at org.springframework.web.servlet.view.AbstractView.render(AbstractView.java:303)
	at org.grails.web.sitemesh.GrailsLayoutView.renderInnerView(GrailsLayoutView.java:150)
	at org.grails.web.sitemesh.GrailsLayoutView.obtainContent(GrailsLayoutView.java:128)
	at org.grails.web.sitemesh.GrailsLayoutView.renderTemplate(GrailsLayoutView.java:63)
	at org.grails.web.servlet.view.AbstractGrailsView.renderWithinGrailsWebRequest(AbstractGrailsView.java:71)
	at org.grails.web.servlet.view.AbstractGrailsView.renderMergedOutputModel(AbstractGrailsView.java:55)
	at org.springframework.web.servlet.view.AbstractView.render(AbstractView.java:303)
	at org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1286)
	at org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1041)
	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:984)
	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:901)
	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)
	at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:861)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:635)
	at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:742)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:230)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
	at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
	at org.springframework.boot.web.filter.ApplicationContextHeaderFilter.doFilterInternal(ApplicationContextHeaderFilter.java:55)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
	at org.springframework.boot.actuate.trace.WebRequestTraceFilter.doFilterInternal(WebRequestTraceFilter.java:105)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
	at org.grails.web.servlet.mvc.GrailsWebRequestFilter.doFilterInternal(GrailsWebRequestFilter.java:77)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
	at au.org.ala.cas.client.AlaHttpServletRequestWrapperFilter.doFilter(AlaHttpServletRequestWrapperFilter.java:81)
	at au.org.ala.cas.client.UriFilter.doFilter(UriFilter.java:188)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
	at org.jasig.cas.client.validation.AbstractTicketValidationFilter.doFilter(AbstractTicketValidationFilter.java:236)
	at au.org.ala.cas.client.UriFilter.doFilter(UriFilter.java:188)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
	at org.jasig.cas.client.authentication.AuthenticationFilter.doFilter(AuthenticationFilter.java:155)
	at au.org.ala.cas.client.UriFilter.doFilter(UriFilter.java:188)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
	at org.jasig.cas.client.session.SingleSignOutFilter.doFilter(SingleSignOutFilter.java:97)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
	at org.grails.web.filters.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:67)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
	at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:197)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
	at org.springframework.web.filter.CorsFilter.doFilterInternal(CorsFilter.java:96)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
	at org.springframework.boot.actuate.autoconfigure.MetricsFilter.doFilterInternal(MetricsFilter.java:106)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:478)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:80)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:341)
	at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:799)
	at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
	at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:861)
	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1455)
	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)

2018-07-31 14:55:24.551 ERROR --- [o-8060-exec-237] StackTrace                               : Full Stack Trace:

java.lang.IllegalArgumentException: URLDecoder: Illegal hex characters in escape (%) pattern - For input string: " A"
	at java.net.URLDecoder.decode(URLDecoder.java:194)
	at gsp_downloads_plugin_downloaddoi_gsp$_run_closure2.doCall(gsp_downloads_plugin_downloaddoi_gsp.groovy:66)
	at org.grails.taglib.TagBodyClosure.executeClosure(TagBodyClosure.java:200)
	at org.grails.taglib.TagBodyClosure.captureClosureOutput(TagBodyClosure.java:102)
	at org.grails.taglib.TagBodyClosure.call(TagBodyClosure.java:213)
	at org.grails.plugins.web.taglib.SitemeshTagLib.captureTagContent(SitemeshTagLib.groovy:48)
	at org.grails.plugins.web.taglib.SitemeshTagLib$_closure3.doCall(SitemeshTagLib.groovy:156)
	at org.grails.gsp.GroovyPage.invokeTagLibClosure(GroovyPage.java:417)
	at org.grails.gsp.GroovyPage.invokeTag(GroovyPage.java:335)
	at gsp_downloads_plugin_downloaddoi_gsp.run(gsp_downloads_plugin_downloaddoi_gsp.groovy:105)
	at org.grails.gsp.GroovyPageWritable.doWriteTo(GroovyPageWritable.java:162)
	at org.grails.gsp.GroovyPageWritable.writeTo(GroovyPageWritable.java:82)
	at org.grails.web.servlet.view.GroovyPageView.renderTemplate(GroovyPageView.java:76)
	at org.grails.web.servlet.view.AbstractGrailsView.renderWithinGrailsWebRequest(AbstractGrailsView.java:71)
	at org.grails.web.servlet.view.AbstractGrailsView.renderMergedOutputModel(AbstractGrailsView.java:55)
	at org.springframework.web.servlet.view.AbstractView.render(AbstractView.java:303)
	at org.grails.web.sitemesh.GrailsLayoutView.renderInnerView(GrailsLayoutView.java:150)
	at org.grails.web.sitemesh.GrailsLayoutView.obtainContent(GrailsLayoutView.java:128)
	at org.grails.web.sitemesh.GrailsLayoutView.renderTemplate(GrailsLayoutView.java:63)
	at org.grails.web.servlet.view.AbstractGrailsView.renderWithinGrailsWebRequest(AbstractGrailsView.java:71)
	at org.grails.web.servlet.view.AbstractGrailsView.renderMergedOutputModel(AbstractGrailsView.java:55)
	at org.springframework.web.servlet.view.AbstractView.render(AbstractView.java:303)
	at org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1286)
	at org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1041)
	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:984)
	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:901)
	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)
	at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:861)
	at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
	at org.springframework.boot.web.filter.ApplicationContextHeaderFilter.doFilterInternal(ApplicationContextHeaderFilter.java:55)
	at org.grails.web.servlet.mvc.GrailsWebRequestFilter.doFilterInternal(GrailsWebRequestFilter.java:77)
	at au.org.ala.cas.client.AlaHttpServletRequestWrapperFilter.doFilter(AlaHttpServletRequestWrapperFilter.java:81)
	at au.org.ala.cas.client.UriFilter.doFilter(UriFilter.java:188)
	at org.jasig.cas.client.validation.AbstractTicketValidationFilter.doFilter(AbstractTicketValidationFilter.java:236)
	at au.org.ala.cas.client.UriFilter.doFilter(UriFilter.java:188)
	at org.jasig.cas.client.authentication.AuthenticationFilter.doFilter(AuthenticationFilter.java:155)
	at au.org.ala.cas.client.UriFilter.doFilter(UriFilter.java:188)
	at org.jasig.cas.client.session.SingleSignOutFilter.doFilter(SingleSignOutFilter.java:97)
	at org.grails.web.filters.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:67)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at java.lang.Thread.run(Thread.java:748)

2018-07-31 14:55:24.551 ERROR --- [o-8060-exec-237] .a.c.c.C.[.[.[.[grailsDispatcherServlet] : Servlet.service() for servlet [grailsDispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.grails.gsp.GroovyPagesException: Error processing GroovyPageView: URLDecoder: Illegal hex characters in escape (%) pattern - For input string: " A"] with root cause

java.lang.IllegalArgumentException: URLDecoder: Illegal hex characters in escape (%) pattern - For input string: " A"
	at java.net.URLDecoder.decode(URLDecoder.java:194)
	at gsp_downloads_plugin_downloaddoi_gsp$_run_closure2.doCall(gsp_downloads_plugin_downloaddoi_gsp.groovy:66)
	at org.grails.taglib.TagBodyClosure.executeClosure(TagBodyClosure.java:200)
	at org.grails.taglib.TagBodyClosure.captureClosureOutput(TagBodyClosure.java:102)
	at org.grails.taglib.TagBodyClosure.call(TagBodyClosure.java:213)
	at org.grails.plugins.web.taglib.SitemeshTagLib.captureTagContent(SitemeshTagLib.groovy:48)
	at org.grails.plugins.web.taglib.SitemeshTagLib$_closure3.doCall(SitemeshTagLib.groovy:156)
	at org.grails.gsp.GroovyPage.invokeTagLibClosure(GroovyPage.java:417)
	at org.grails.gsp.GroovyPage.invokeTag(GroovyPage.java:335)
	at gsp_downloads_plugin_downloaddoi_gsp.run(gsp_downloads_plugin_downloaddoi_gsp.groovy:105)
	at org.grails.gsp.GroovyPageWritable.doWriteTo(GroovyPageWritable.java:162)
	at org.grails.gsp.GroovyPageWritable.writeTo(GroovyPageWritable.java:82)
	at org.grails.web.servlet.view.GroovyPageView.renderTemplate(GroovyPageView.java:76)
	at org.grails.web.servlet.view.AbstractGrailsView.renderWithinGrailsWebRequest(AbstractGrailsView.java:71)
	at org.grails.web.servlet.view.AbstractGrailsView.renderMergedOutputModel(AbstractGrailsView.java:55)
	at org.springframework.web.servlet.view.AbstractView.render(AbstractView.java:303)
	at org.grails.web.sitemesh.GrailsLayoutView.renderInnerView(GrailsLayoutView.java:150)
	at org.grails.web.sitemesh.GrailsLayoutView.obtainContent(GrailsLayoutView.java:128)
	at org.grails.web.sitemesh.GrailsLayoutView.renderTemplate(GrailsLayoutView.java:63)
	at org.grails.web.servlet.view.AbstractGrailsView.renderWithinGrailsWebRequest(AbstractGrailsView.java:71)
	at org.grails.web.servlet.view.AbstractGrailsView.renderMergedOutputModel(AbstractGrailsView.java:55)
	at org.springframework.web.servlet.view.AbstractView.render(AbstractView.java:303)
	at org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1286)
	at org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1041)
	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:984)
	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:901)
	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)
	at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:861)
	at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
	at org.springframework.boot.web.filter.ApplicationContextHeaderFilter.doFilterInternal(ApplicationContextHeaderFilter.java:55)
	at org.grails.web.servlet.mvc.GrailsWebRequestFilter.doFilterInternal(GrailsWebRequestFilter.java:77)
	at au.org.ala.cas.client.AlaHttpServletRequestWrapperFilter.doFilter(AlaHttpServletRequestWrapperFilter.java:81)
	at au.org.ala.cas.client.UriFilter.doFilter(UriFilter.java:188)
	at org.jasig.cas.client.validation.AbstractTicketValidationFilter.doFilter(AbstractTicketValidationFilter.java:236)
	at au.org.ala.cas.client.UriFilter.doFilter(UriFilter.java:188)
	at org.jasig.cas.client.authentication.AuthenticationFilter.doFilter(AuthenticationFilter.java:155)
	at au.org.ala.cas.client.UriFilter.doFilter(UriFilter.java:188)
	at org.jasig.cas.client.session.SingleSignOutFilter.doFilter(SingleSignOutFilter.java:97)
	at org.grails.web.filters.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:67)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at java.lang.Thread.run(Thread.java:748)

The DOI resolves properly using the standard DOI resolution:

https://doi.org/10.26197/5b5fe244b3013

redirects to the expected target successfully:

https://doi.ala.org.au/doi/8fe13819-b878-48ec-a3c0-28e3ece73215

However, we can't expect users to know how create those URLs themselves.

Changing the %2F to / does not seem to help:

https://biocache.ala.org.au/download/doi?doi=10.26197/5b5fe244b3013

This relates to ticket 21267 on the helpdesk

If we are going to decode the URL on doi.gsp, it should have been percent encoded by our code previously, otherwise it is also vulnerable to other issues.

@nickdos going back through my memories the reason of having a DOI landing page in downloads plugin is because it formats fields specifically for downloads as opposed to showing a more generic view as the DOI Service does.

DOI service treats all metadata as opaque hence it is not trying to parse invalid urls.

Apart from fixing the url issues definitely one thing we need to do is to end up with one DOI landing page to avoid any ambiguity.

Are you happy for me to move the DOI display code in downloads plugin to doi service so we centralize all doi code. The caveat is that DOI service will know about download specific concerns. I need to implement something there to display a specific view for DOIs coming from biocache and use the generic view for anything else.

@javier-molina @nickdos The doi.ala.org.au code doesn't conceptually need to be completely ambivalent about the source of the DOI.

All of the DOI's that will be sent there will be from ALA applications, and there are relatively few of them. Implementing some specific templates for each application shouldn't be an ongoing maintenance issue if they are designed and implemented as cleanly as possible.

Before porting any code across from downloads-plugin to doi-service the URL encoding issues described in this issue and #29 must be fixed. We can't have users losing access to their downloads on doi.ala.org.au because their particular download had a character in its URL that we have not been handling correctly.

@javier-molina the current DOI landing page is on doi.ala.org.au, I originally thought it was going to be the downloads page on biocache (which is your recollection I think). This would've been set when the DOI was minted.

Maybe the current situation was an accident as opposed to by design. If so, we could simply change the code to set the DOI resolving URL to be the biocache one. And then we could keep the downloads specific formatting in the downloads-plugin, which seems a bit neater to me. I also like this as its simple and consistent for the user (one interface) and closely follows the GBIF way of doing it.

What do you all think?

I would prefer to leave the DOI landing page at doi.ala.org.au, and redirect from there in the future if we find that users are making comments about that and they would prefer application specific landing pages.

In my view, giving it a centralised DNS name inside of the ALA implies that it is easier in the future to support, given we are making a commitment to users to support the DOI for the foreseeable future. There are ways of changing the resolved URIs using ANDS/DataCite APIs, so we can change them if necessary, but it is simpler to leave it as it is with doi.ala.org.au at this point since we are already struggling to maintain the ALA infrastructure and avoiding an extra task would be ideal.

It must not be switched right now as the DOI landing page in downloads-plugin is broken, (and insecure), and avoiding it by sending users to https://doi.org and from there directly to https://doi.ala.org.au/ is the main reason we were able to switch to using biocache-hubs-2/biocache-service-2 today.

The new page on doi.ala.org.au is showing correctly for me now and doesn't appear to generate any errors in the log files