Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow multipart param request/file size limit customization #98

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
20 changes: 14 additions & 6 deletions ring-core/src/ring/middleware/multipart_params.clj
Expand Up @@ -34,9 +34,13 @@

(defn- file-item-seq
"Create a seq of FileItem instances from a request context."
[context]
[{:keys [max-file-size max-request-size]
:or {max-file-size -1, max-request-size -1}} context]
(file-item-iterator-seq
(.getItemIterator (FileUpload.) context)))
(.getItemIterator (doto (FileUpload.)
(.setFileSizeMax max-file-size)
(.setSizeMax max-request-size))
context)))

(defn- parse-file-item
"Parse a FileItemStream into a key-value pair. If the request is a file the
Expand All @@ -51,9 +55,9 @@

(defn- parse-multipart-params
"Parse a map of multipart parameters from the request."
[request encoding store]
[opts request encoding store]
(->> (request-context request encoding)
(file-item-seq)
(file-item-seq opts)
(map #(parse-file-item % store))
(reduce (fn [m [k v]] (assoc-conj m k v)) {})))

Expand All @@ -78,7 +82,7 @@
(:character-encoding request)
"UTF-8")
params (if (multipart-form? request)
(parse-multipart-params request encoding store)
(parse-multipart-params opts request encoding store)
{})]
(merge-with merge request
{:multipart-params params}
Expand All @@ -100,7 +104,11 @@
expect a map with :filename, content-type and :stream keys,
and its return value will be used as the value for the
parameter in the multipart parameter map. The default storage
function is the temp-file-store."
function is the temp-file-store.

:max-request-size - maximum allowed size of the request in bytes.

:max-file-size - maximum allowed size of a single uploaded file in bytes."
[handler & [opts]]
(fn [request]
(-> request
Expand Down
46 changes: 45 additions & 1 deletion ring-core/test/ring/middleware/test/multipart_params.clj
Expand Up @@ -77,5 +77,49 @@
(is (< (count (all-threads))
100))))

(defn- form-body-with-size [sz]
{:pre [(> sz 113)]}
(str "--XXXX\r\n"
"Content-Disposition: form-data;"
"name=\"upload\"; filename=\"test.txt\"\r\n"
"Content-Type: text/plain\r\n\r\n"
(apply str (repeat (- sz 113) "1")) "\r\n"
"--XXXX--"))

(defn- request-of [form-body]
{:content-type "multipart/form-data; boundary=XXXX"
:content-length (count form-body)
:body (string-input-stream form-body)})

(defn- root-cause [e]
(let [cause (.getCause e)]
(if (and cause (not (= java.io.IOException (type cause))))
(recur cause)
e)))

(deftest test-max-size-settings
(testing "Respects max request size in bytes"
(let [handler (wrap-multipart-params identity {:max-request-size 300, :store string-store})]

(let [response (handler (request-of (form-body-with-size 300)))]
(is (= (get-in response [:params "upload" :filename]) "test.txt")))

(is (thrown? org.apache.commons.fileupload.FileUploadBase$SizeLimitExceededException
(handler (request-of (form-body-with-size 500)))))))

(testing "Respects max file size in bytes"
(let [handler (wrap-multipart-params identity {:max-file-size 300, :store string-store})]

; Actual file size is less than 300
(let [response (handler (request-of (form-body-with-size 400)))]
(is (= (get-in response [:params "upload" :filename]) "test.txt")))

(try
(handler (request-of (form-body-with-size 500)))
(is false "Should fail with exception!")
(catch Exception e
(is (instance? org.apache.commons.fileupload.FileUploadBase$FileSizeLimitExceededException
(root-cause e))))))))

(deftest multipart-params-request-test
(is (fn? multipart-params-request)))
(is (fn? multipart-params-request)))