   "Evaluates body with `ch-name` bound to the request's underlying
   asynchronous HTTP or WebSocket channel, and returns {:body AsyncChannel}
   as an implementation detail.
+
+  Note: for WebSocket requests, WebSocket handshake will be sent *after*
+  body is evaluated. I.e. body cannot call `send!`.
 
   ;; Asynchronous HTTP response (with optional streaming)
   (defn my-async-handler [request]

(def accept "DEPRECATED for `sec-websocket-accept" sec-websocket-accept)

(defn websocket-handshake-check
  "Returns sec-ws-accept iff received a valid WebSocket request."
  [^AsyncChannel ch ring-req]
  (when-let [sec-ws-key (get-in ring-req [:headers "sec-websocket-key"])]
    (when-let [sec-ws-accept (try (sec-websocket-accept sec-ws-key)
                                  (catch Exception _))]
      sec-ws-accept)))

(defn send-websocket-handshake!
  "Upgrade to WebSocket connection."
  [^AsyncChannel ch ^String sec-ws-accept]
  (.sendHandshake ch 
    {"Upgrade" "websocket" 
     "Connection" "Upgrade" 
     "Sec-WebSocket-Accept" sec-ws-accept}))

;; (defn websocket-req? [ring-req] (:websocket?    ring-req))
;; (defn async-channel  [ring-req] (:async-channel ring-req))


     (if (:websocket? ring-req#)
       (if-let [sec-ws-accept# (websocket-handshake-check ~ch-name ring-req#)]
         (do
           ~@body ; Eval body before handshake to allow hooks to be established, Ref. #318
           (send-checked-websocket-handshake! ~ch-name sec-ws-accept#)
           {:body ~ch-name})
         {:status 400 :body "Bad Sec-WebSocket-Key header"})
       (do ~@body {:body ~ch-name}))))
