       (downstream :body (ChannelBuffers/wrappedBuffer GzipUtils/header)))
 
     ;; send the chunks
-    (send-chunks deflater downstream compressed-byte-buffer)
+    (send-chunks deflater downstream buf)
 
     ;; send the trailer if needed
     (when (nil? chunk)

  (let [buf-len (alength buf)]
    (loop []
      (let [compressed-bytes (.deflate deflater buf 0 buf-len)]
        (if-not (= 0 compressed-bytes)
          (let [channel-buffer (ChannelBuffers/copiedBuffer buf 0 compressed-bytes)]
            (downstream :body channel-buffer)
            (recur)))))))

(defn- gzip-and-send
  [state crc deflater downstream compressed-byte-buffer chunk]
  (let [buffer-length (alength compressed-byte-buffer)
        sent-header (:sent-header @state)]
    ;; update the crc and set the input
    (if (nil? chunk)

(defn encoder
  ([app] (encoder app default-opts))
  ([app opts]
     (defmiddleware
       [state downstream upstream]
       app

       :upstream
       (defstream
         (request [[{accept-encoding-header "accept-encoding"} _ :as req]]
           ;; save off whether we accept gzip for this request and
           ;; pass upstream
           (let [accept-encoding-header (or accept-encoding-header "")
                 accept-encodings (into #{} (string/split #"\s*,\s*" (string/trim accept-encoding-header)))
                 accept-gzip? (contains? accept-encodings "gzip")]
             (swap! state #(assoc % :accept-gzip? accept-gzip?))
             (upstream :request req)))

         ;; must pass all other events through, like pause/resume/abort
         (else [evt val]
           (upstream evt val)))

       :downstream
       (defstream
         (response [[status {content-type-header "content-type" :as hdrs} body :as resp]]
           ;; send the resposne with appropriate headers
           (let [content-type-header (content-type hdrs)
                 gzip-content-type? (contains? (:gzip-content-types opts) content-type-header)]
             (if-not (and gzip-content-type? (:accept-gzip? @state))
               (downstream :response resp)
               (let [hdrs (assoc hdrs "content-encoding" "gzip")]
                 (if (= :chunked body)
                   ;; chunked body, yank the content length header,
                   ;; add the transfer encoding header, and set the
                   ;; state so that chunks will gzip and allocate a
                   ;; deflater, crc, and buffer for the exchange
                   (let [hdrs (-> hdrs (assoc "transfer-encoding" "chunked") (dissoc "content-length"))]
                     (swap! state #(assoc %
                                     :gzip? true
                                     :deflater (Deflater. Deflater/DEFAULT_COMPRESSION true)
                                     :crc (CRC32.)
                                     :buf (byte-array 4092)))
                     (downstream :response [status hdrs body]))

                   ;; not chunked, gzip the whole thing and send it down
                   (let [gzipped-body (gzip-entire-body body)
                         hdrs (assoc hdrs "content-length" (.readableBytes gzipped-body))]
                     (downstream :response [status hdrs gzipped-body])))))))

         (body [chunk]
           (if-not (:gzip? @state)
             ;; not gziping, send chunk as is
             (downstream :body chunk)

             ;; gzip and send appropriate chunks
             (let [deflater (:deflater @state)
                   crc (:crc @state)
                   buf (:buf @state)]
               (gzip-and-send-chunk state downstream chunk deflater crc buf))))

         ;; must pass all other events through, like pause/resume/abort
         (else [evt val]
           (downstream evt val))))))
