-
Notifications
You must be signed in to change notification settings - Fork 99
Description
There are two issues preventing async handlers from working in any Servlet container, other than Jetty (e.g. Tomcat). Thankfully, one of them is super easy to fix, but the other I'm having trouble with and I would appreciate your help.
-
The
web.xmlemitted should contain aasync-supportedtag - especially when the[:ring :async?]option is true. This is very easily fixable by adding[:async-supported (:async? ring-options false)]], right before closing the:servlettag in themake-web-xmlfunction (here). If I manage to fix point 2 (see below), I can include this in the PR, otherwise it's such a trivial change that I don't really see the point of a PR just for that. -
The
compile-listenerfunction callsgenerate-handlerin order to resolve the actual user handler(here). As you can see if the[:ring :servlet-path-info?]option is true (or missing), the user-handler is wrapped in another function, which however takes a single argument, and therefore won't work with the three arguments passed to it (per the asyncring.util.servlet/make-service-method). If the[:ring :servlet-path-info?]option is explicitly set to false, then it works as expected (assuming of course that the actual handler allows for 3 args). Now, you might be tempted to think that this is also easily fixable, but trust me, it isn't...I tried adding a 3-arg arity to that function returned bygenerate-handler, and everything compiles/builds/deploys no problem, but then when I try to use it on a real project, I get compile-syntax errors like this:
:clojure.main/message
"Syntax error (ClassNotFoundException) compiling at (com/foo/gw/listener.clj:1:519).\nleiningen.ring.war\n",
:clojure.main/triage
{:clojure.error/phase :compile-syntax-check,
:clojure.error/line 1,
:clojure.error/column 519,
:clojure.error/source "listener.clj",
:clojure.error/path "com/foo/gw/listener.clj",
:clojure.error/class java.lang.ClassNotFoundException,
:clojure.error/cause "leiningen.ring.war"},
Here is the code in case you have doubts that the syntax is correct:
(defn- with-context-path-info [req context-path]
(assoc req
:context context-path
:path-info (-> (:uri req) (subs (count context-path)) not-empty (or "/"))))
(defn generate-handler [project handler-sym]
(if (get-in project [:ring :servlet-path-info?] true)
`(let [handler# ~(generate-resolve handler-sym)]
(fn
([request# respond# raise#]
(let [context# (.getContextPath
^javax.servlet.http.HttpServletRequest
(:servlet-request request#))]
(-> request#
(with-context-path-info context#)
(handler# respond# raise#))))
([request#]
(let [context# (.getContextPath
^javax.servlet.http.HttpServletRequest
(:servlet-request request#))]
(-> request#
(with-context-path-info context#)
(handler#))))))
(generate-resolve handler-sym)))I also tried generating two distinct functions based on the :async? option, but I got the exact same compile errors:
(if (get-in project [:ring :async?])
(fn [req respond raise] ...)
(fn [req] ...))If you can provide any form of insight as to why such a simple change (adding an arity) would cause compile-syntax errors, that would be fantastic. Many thanks in advance...