           word #(keyword (.group % 1))
           path nil)))))
  
-(defn match-route
+(defn- match-route
   "Match a path against a parsed route. Returns a map of keywords and their
   matching path values."
   [route path]

            "Content-Type" (context-mimetype context (str update)))
       (pipe-stream in out))))
 
(defn redirect-to
  "A shortcut for a '302 Moved' HTTP redirect."
  [location]
  [302 {"Location" location}])
 
(defn page-not-found
  "A shortcut to create a '404 Not Found' HTTP response."
  ([] (page-not-found "public/404.html"))
  ([filename] [404 (file filename)]))
 
;;;; Resource ;;;;
 
(defstruct http-resource
  :method
  :route
  :function)
 
(defn get-session
  "Returns a ref to a hash-map that acts as a HTTP session that can be updated
  within a Clojure STM transaction."
  [#^HttpServletRequest request]
  (let [session (.getSession request)]
    (or (.getAttribute session "clj-session")
        (let [clj-session (ref {})]
          (.setAttribute session "clj-session" clj-session)
          clj-session))))
 
(defmacro resource-fn
  "Macro that wraps the body of a resource up in a standalone function."
  [& body]
  `(fn ~'[route context request]
     (let ~'[method (.getMethod request)
             full-path (.getPathInfo request)
             param #(.getParameter request (compojure.str-utils/str* %))
             header #(.getHeader request (compojure.str-utils/str* %))
             mimetype #(compojure.http/context-mimetype (str %))
             session (compojure.http/get-session request)]
       (do ~@body))))
 
(defn serve-file
  "Serve up a static file from a directory. A 404 is returned if the file
  does not exist."
  ([path]
    (serve-file "public" path))
  ([root path]
    (let [static-file (file root path)]
      (if (.isFile static-file)
        static-file
        :next))))
 
(defn find-method
  "Returns either the value of the '_method' HTTP parameter, or the method
  of the HTTP request."
  [#^HttpServletRequest request]
  (or (.getParameter request "_method")
      (.getMethod request)))
 
(defn apply-http-resource
  "Finds and evaluates the resource that matches the HttpServletRequest. If the
  resource returns :next, the next matching resource is evaluated."
  [resources context request response]
  (let [method (find-method request)
        path (.getPathInfo request)
        method= #(or (nil? %) (= method %))
 
        route? (fn [resource]
                    (if (method= (resource :method))
                      (match-route (resource :route) path)))
 
        response? (fn [resource]
                    (if-let route-params (route? resource)
                      (let [func (resource :function)
                            resp (func route-params
                                       context
                                       request)]
                        (if (not= :next resp)
                          (or resp [])))))]
    (update-response response context
      (some response? resources))))
            
(defmacro GET "Creates a GET resource."
  [route & body]
  `(struct http-resource "GET" (compile-route ~route) (resource-fn ~@body)))
 
(defmacro PUT "Creates a PUT resource."
  [route & body]
  `(struct http-resource "PUT" (compile-route ~route) (resource-fn ~@body)))
 
(defmacro POST "Creates a POST resource."
  [route & body]
  `(struct http-resource "POST" (compile-route ~route) (resource-fn ~@body)))
 
(defmacro DELETE "Creates a DELETE resource."
  [route & body]
  `(struct http-resource "DELETE" (compile-route ~route) (resource-fn ~@body)))
 
(defmacro HEAD "Creates a HEAD resource."
  [route & body]
  `(struct http-resource "HEAD" (compile-route ~route) (resource-fn ~@body)))
 
(defmacro ANY "Creates a resource that responds to any HTTP method."
  [route & body]
  `(struct http-resource nil (compile-route ~route) (resource-fn ~@body)))
 
;;;; Servlet ;;;;
 
(defn servlet
  "Create a servlet from a sequence of resources."
  [& resources]
  (proxy [HttpServlet] []
    (service [request response]
      (.setCharacterEncoding response "UTF-8")
      (apply-http-resource resources
                           (.getServletContext this)
                           request
                           response))))
 
(defmacro defservlet
  "Shortcut for (def name (servlet resources))"
  [name doc & resources]
  (if (string? doc)
    `(def
       ~(with-meta name (assoc (meta name) :doc doc))
        (servlet ~@resources))
    `(def ~name (servlet ~doc ~@resources))))

;; HTTP handler library for Compojure
(ns compojure.http
  (:use (compojure control
                   file-utils
                   parser
                   str-utils))
  (:import (java.io File
                    FileInputStream)
           (javax.servlet ServletContext)
           (javax.servlet.http HttpServlet
                               HttpServletRequest
                               HttpServletResponse)))
;;;; Mimetypes ;;;;
 
(defn context-mimetype
