|
5 | 5 | ;; using this software in any fashion, you are agreeing to be bound by the |
6 | 6 | ;; terms of this license. You must not remove this notice, or any other, from |
7 | 7 | ;; this software. |
| 8 | +;; Modified by Adam Blinkinsop <blinks@acm.org> in August 2009. |
8 | 9 |
|
9 | 10 | (ns compojure.http.multipart |
10 | 11 | "Add multipart form handling to Compojure. Relies on the Apache Commons |
11 | 12 | FileUpload library." |
12 | 13 | (:use clojure.contrib.def) |
13 | 14 | (:use compojure.map-utils) |
14 | | - (:import org.apache.commons.fileupload.FileUpload) |
15 | | - (:import org.apache.commons.fileupload.RequestContext) |
16 | | - (:import org.apache.commons.fileupload.disk.DiskFileItemFactory) |
17 | | - (:import org.apache.commons.fileupload.disk.DiskFileItem)) |
| 15 | + (:import [org.apache.commons.fileupload.servlet ServletFileUpload])) |
18 | 16 |
|
19 | | -(defn multipart-form? |
20 | | - "Does a request have a multipart form?" |
| 17 | +(defn multipart? |
| 18 | + "Does this request contain multipart content?" |
21 | 19 | [request] |
22 | | - (if-let [content-type (:content-type request)] |
23 | | - (.startsWith content-type "multipart/form-data"))) |
| 20 | + (ServletFileUpload/isMultipartContent request)) |
24 | 21 |
|
25 | | -(defvar- file-upload |
26 | | - (FileUpload. |
27 | | - (doto (DiskFileItemFactory.) |
28 | | - (.setSizeThreshold -1) |
29 | | - (.setFileCleaningTracker nil))) |
30 | | - "Uploader class to save multipart form values to temporary files.") |
| 22 | +(defvar- upload (ServletFileUpload.)) |
31 | 23 |
|
32 | | -(defn- request-context |
33 | | - "Create a RequestContext object from a request map." |
34 | | - [request] |
35 | | - (proxy [RequestContext] [] |
36 | | - (getContentType [] (:content-type request)) |
37 | | - (getContentLength [] (:content-length request)) |
38 | | - (getCharacterEncoding [] (:character-encoding request)) |
39 | | - (getInputStream [] (:body request)))) |
40 | | - |
41 | | -(defn- file-map |
42 | | - "Create a file map from a DiskFileItem." |
43 | | - [#^DiskFileItem item] |
44 | | - {:disk-file-item item |
45 | | - :filename (.getName item) |
46 | | - :size (.getSize item) |
47 | | - :content-type (.getContentType item) |
48 | | - :tempfile (.getStoreLocation item)}) |
49 | | - |
50 | | -(defn parse-multipart-params |
51 | | - "Parse a map of multipart parameters from the request." |
52 | | - [request] |
53 | | - (reduce |
54 | | - (fn [param-map, #^DiskFileItem item] |
55 | | - (assoc-vec param-map |
56 | | - (keyword (.getFieldName item)) |
57 | | - (if (.isFormField item) |
58 | | - (if (zero? (.getSize item)) |
59 | | - "" |
60 | | - (.getString item)) |
61 | | - (file-map item)))) |
62 | | - {} |
63 | | - (.parseRequest |
64 | | - file-upload |
65 | | - (request-context request)))) |
| 24 | +(defn field-seq |
| 25 | + "Map field names to values, which will either be a simple string or map. |
66 | 26 |
|
67 | | -(defn get-multipart-params |
68 | | - "Retrieve multipart params from the request." |
| 27 | + Multipart values will be maps with content-type, name (original filename), |
| 28 | + and stream (an open input stream object)." |
69 | 29 | [request] |
70 | | - (if (multipart-form? request) |
71 | | - (parse-multipart-params request) |
72 | | - {})) |
| 30 | + (map (fn [i] {(keyword (.getFieldName i)) |
| 31 | + (if (.isFormField i) |
| 32 | + (.getParameter request (.getFieldName i)) |
| 33 | + {:content-type (.getContentType i) |
| 34 | + :name (.getName i) |
| 35 | + :stream (.openStream i)})}) |
| 36 | + (.getItemIterator upload request))) |
73 | 37 |
|
74 | 38 | (defn with-multipart |
75 | | - "Decorate a Ring handler with multipart parameters." |
76 | 39 | [handler] |
77 | 40 | (fn [request] |
78 | | - (let [params (get-multipart-params request) |
79 | | - request (-> request |
80 | | - (assoc :multipart-params params) |
81 | | - (assoc :params (merge (request :params) params)))] |
| 41 | + (let [req (merge request {:params (merge (field-seq request))})] |
82 | 42 | (handler request)))) |
0 commit comments