URLEncode fail.

25 views
Skip to first unread message

LauJensen

unread,
Aug 19, 2009, 5:58:42 PM8/19/09
to Compojure
Gentlemen,

I have a website thats driven using Compojure. To this site I wanted
to add a backdoor to upload some images to the webserver (dont ask
why). Per Stuart Sierras advice I picked up his http.agent from
Clojure-contrib, hoping that it could simple POST the image file like
so:

user> (http-agent "http://localhost:8888/backdoor/" :method
"POST" :body (File. "/tmp/mypicture.jpg"))

From the client side, this works fine. The server fails to receive
though. I think because it sees the entire body as URL and tries to
decode it. How do I get around this and pass the file to my upload
function?

(def *max_size* (* 30 1024 1024)) ; 30 Megabytes

(defn upload-file
[request base-path]
(if (ServletFileUpload/isMultipartContent request)
(let [uploader (ServletFileUpload. (DiskFileItemFactory.))
items (.parseRequest uploader request)]
(doseq [item items]
(if (and (not (.isFormField item))
(> *max_size* (.getSize item)))
(try
(let [file (File. (str base-path (.getName item)))]
(log Priority/INFO (str "Receiving " (.getName item)
" (" (.getSize item) "b)")
(.write item file)))
(catch Exception e (println "\nGot exception: " e)))
(log Priority/DEBUG "File upload rejected: Maximum size
exceeded"))))))

I never get that far, this fires soon as the request is made:

2009-08-19 23:44:34.001::WARN: /backdoor/
java.lang.IllegalArgumentException: URLDecoder: Incomplete trailing
escape (%) pattern
at java.net.URLDecoder.decode(URLDecoder.java:187)
at compojure.encodings$urldecode__333.invoke(encodings.clj:25)
at compojure.http.request$parse_params__455$fn__457.invoke
(request.clj:28)
at clojure.core$reduce__3319$fn__3322.invoke(core.clj:539)
at clojure.core$reduce__3319.invoke(core.clj:537)
at compojure.http.request$parse_params__455.invoke(request.clj:31)
at compojure.http.request$parse_form_params__479.invoke(request.clj:
62)
at compojure.http.request$assoc_func__486.invoke(request.clj:76)
at compojure.http.request$assoc_params__490.invoke(request.clj:82)
at compojure.http.request$with_params__493$fn__495.invoke(request.clj:
91)
at compojure.http.request$with_cookies__506$fn__508.invoke
(request.clj:108)
at compojure.http.servlet$request_handler__828.invoke(servlet.clj:
109)
at bestinclass$eval__1639$fn__1641.invoke(boot.clj:24)
at clojure.proxy.javax.servlet.http.HttpServlet.service(Unknown
Source)
at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:
502)
at org.mortbay.jetty.servlet.ServletHandler.handle
(ServletHandler.java:380)
at org.mortbay.jetty.servlet.SessionHandler.handle
(SessionHandler.java:181)
at org.mortbay.jetty.handler.ContextHandler.handle
(ContextHandler.java:765)
at org.mortbay.jetty.handler.HandlerWrapper.handle
(HandlerWrapper.java:152)
at org.mortbay.jetty.Server.handle(Server.java:324)
at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:
535)
at org.mortbay.jetty.HttpConnection$RequestHandler.content
(HttpConnection.java:880)
at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:747)
at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:218)
at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:404)
at org.mortbay.jetty.bio.SocketConnector$Connection.run
(SocketConnector.java:228)
at org.mortbay.thread.QueuedThreadPool$PoolThread.run
(QueuedThreadPool.java:520)


Stuart Sierra

unread,
Aug 20, 2009, 1:25:46 PM8/20/09
to Compojure
I suggested on IRC that Compojure is trying to parse the HTTP request
body as "application/x-www-form-urlencoded" even though there is no
"Content-Type" header in the request.

-SS

Lau

unread,
Aug 20, 2009, 1:52:28 PM8/20/09
to Compojure
And since I couldnt figure out how to make Compojure accept the pure
File object, I tried POSTing like this instead:

(defn post-image
[f]
(let [filePost (PostMethod. "http://localhost:8888/backdoor/")
parts (into-array [(FilePart. (.getName f) f)])
client (HttpClient.)]
(.. filePost (getParams) (setBooleanParameter
HttpMethodParams/USE_EXPECT_CONTINUE
true))
(.setRequestEntity filePost (MultipartRequestEntity. parts
(.getParams filePost)))
(.. client (getHttpConnectionManager) (getParams)
(setConnectionTimeout 5000))
(.executeMethod client filePost)))

Which works perfectly if you feed it a File object for its argument.

James Reeves

unread,
Aug 20, 2009, 8:25:33 PM8/20/09
to Compojure
On Aug 20, 1:25 pm, Stuart Sierra <the.stuart.sie...@gmail.com> wrote:
> I suggested on IRC that Compojure is trying to parse the HTTP request
> body as "application/x-www-form-urlencoded" even though there is no
> "Content-Type" header in the request.

Actually, I think it's a bug in the HttpURLConnection class that
http.agent uses:

http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6369510

- James

Stuart Sierra

unread,
Aug 21, 2009, 5:34:41 PM8/21/09
to Compojure
On Aug 20, 8:25 pm, James Reeves <weavejes...@googlemail.com> wrote:
> Actually, I think it's a bug in the HttpURLConnection class that
> http.agent uses:
>
> http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6369510

Aha! Thanks, James. Apparently this happens even if you explicitly
set a different Content-Type header. Sheesh.

The bug report seems to indicate that this was fixed in Java 6 and in
Java 5.0 update 10.

-SS

James Reeves

unread,
Aug 21, 2009, 9:12:24 PM8/21/09
to Compojure
On Aug 20, 1:52 pm, Lau <lau.jen...@bestinclass.dk> wrote:
> And since I couldnt figure out how to make Compojure accept the pure
> File object

You could use the routes* function, which doesn't try to parse
urlencoded forms, even if the content type is set to "application/x-
www-form-urlencoded".

(def my-bare-routes
(routes*
(GET "/" ...)
...))

- James
Reply all
Reply to author
Forward
0 new messages