How to send an input stream as a response in ring? - clojure

I have the following code, in which I want to send an InputStream of a file in the function fetch-items, which handles the route /fetch-items.
(defn id->image [image-id]
(let [image (.getInputStream (gfs/find-by-id fs image-id))] image))
(defn item-resp [item]
(assoc item :_id (str (:_id item))
:images (into [] (map id->image (:image-ids item))))
)
(defn fetch-items [req]
(res/response
(map item-resp (find fs "items" {}))))
Here's my request in the client side, using cljs-ajax:
(ajax-request
{:uri "http://localhost:5000/fetch-items"
:method :get
:handler #(prn (into [] %))
:format (json-request-format)
:response-format (raw-response-format)
}
)
But the response I get on the client is this:
[:failure :parse] [:response nil] [:status-text "No reader function for tag object. Format should have been EDN"]
:original-text "{:_id \"5e63f5c591585c30985793cd\", :images [#object[com.mongodb.gridfs.GridFSDBFile$GridFSInputStream 0x22556652 \"com.mongodb.gridfs.GridFSDBFile$GridFSInputStream#22556652\"]]}{:_id \"5e63f5d891585c30985793d0\", :images [#object[com.mongodb.gridfs.GridFSDBFile$GridFSInputStream 0x266ae6c0 \"com.mongodb.gridfs.GridFSDBFile$GridFSInputStream#266ae6c0\"]]}{:_id \"5e63f5e891585c30985793d3\", ...
Why would the response say that the format should have been edn? How do I extract this file/image out in the client side?
--- EDIT ----
Doing the following:
(IOUtils/toString image "utf-8")
returns a string of size 1594 bytes, which is much smaller than the expected image size.
I think this is because it's converting the file object to base64 and not the actual chunk of data associated with it.
How do I make it convert the actual GridFS chunk to base64 string and not the file object?

It seems that you are building a response and directly putting an reference to an InputStream object into the response, without encoding the contents of the stream into an array of bytes and serializing the contents on the response.
You'll need to find a way to read the contents of the stream and encode it in the response (maybe send them encoded as base 64?)
On the other end, the client seems to be expecting an EDN response, and when it found the string #object, it complained that it didn't have a way to read an object with such a tag.
Here's a simple example of how to read an EDN string with a tagged literal, you can extend it so you decode the image in the client (note I'm using Java in the decoder, you'll need a different implementation on JS):
(defn b64decode [s]
(->> s .getBytes (.decode (java.util.Base64/getDecoder)) String.))
(def message "{:hello :world :msg #base64str \"SGV5LCBpdCB3b3JrcyE=\"}")
;; Now we can read the EDN string above adding our handler for #base64str
(clojure.edn/read-string {:readers {'base64str b64decode}} message)
;; => {:hello :world, :msg "Hey, it works!"}

Related

How to correctly sign GDAX request in Clojure

I have been struggling with signing requests for private GDAX endpoints for a while. Everything I have tried results in a 400 response with a message of "invalid signature." I have read their documentation on the matter several times, which can be found here. My current code is below. I'm using clj-http for making requests. I'm using their /time endpoint response for the timestamp, and I'm using pandect for the sha256 HMAC generation. I've tried converting the secret-decoded to a string using String. before passing it to sha256-hmac. I've also examined the request using clj-http's debug flag. It looks to me that I am following their directions precisely, but something must be wrong. I've done a lot of online searching before posting here. Any help would be greatly appreciated.
(defn get-time
[]
(-> (str (:api-base-url config) "/time")
(http/get {:as :json})
:body))
(defn- create-signature
([timestamp method path]
(create-signature timestamp method path ""))
([timestamp method path body]
(let [secret-decoded (b64/decode (.getBytes (:api-secret config)))
prehash-string (str timestamp (clojure.string/upper-case method) path body)
hmac (sha256-hmac prehash-string secret-decoded)]
(-> hmac
.getBytes
b64/encode
String.))))
(defn- send-signed-request
[method path & [opts]]
(let [url (str (:api-base-url config) path)
timestamp (long (:epoch (get-time)))
signature (create-signature timestamp method path (:body opts))]
(http/request
(merge {:method method
:url url
:as :json
:headers {"CB-ACCESS-KEY" (:api-key config)
"CB-ACCESS-SIGN" signature
"CB-ACCESS-TIMESTAMP" timestamp
"CB-ACCESS-PASSPHRASE" (:api-passphrase config)
"Content-Type" "application/json"}
:debug true}
opts))))
(defn get-accounts []
(send-signed-request "GET" "/accounts"))
(send-signed-request "GET" "/accounts")))
I've figured out the issue. Just in case anyone happens to have this very specific problem, I'm posting the solution. My error was that I was using the sha256-hmac function from pandect, which returns a string hmac, then I was converting that to a byte array, base64 encoding it, and converting it back to a string. Somewhere in those conversions, or perhaps in the pandect function's conversion, the value is altered in an erroneous way.
What works is using the sha256-hmac* function (note the asterisk) from pandect, which returns a raw byte array hmac, then base64 encoding that result directly, and converting it to a string. Below is the corrected, working code snippet, with which I was able to make a request to a private GDAX endpoint.
(defn create-signature
([timestamp method path]
(create-signature timestamp method path ""))
([timestamp method path body]
(let [secret-decoded (b64/decode (.getBytes (:api-secret config)))
prehash-string (str timestamp (clojure.string/upper-case method) path body)
hmac (sha256-hmac* prehash-string secret-decoded)]
(-> hmac
b64/encode
String.))))

Using piped-input-stream from ring.utils.io to serve files

I need to create on the fly excel file on request and serve it to user via response, using clojure.ring.
I use docjure to create an excel file and write it to the output stream
(see this function: https://github.com/mjul/docjure/blob/master/src/dk/ative/docjure/spreadsheet.clj#L86), and I get the output stream from using piped-input-stream (see https://github.com/ring-clojure/ring/blob/1.5.0/ring-core/src/ring/util/io.clj#L11).
The relevant part of code:
(defn excel-response
[params]
(-> (response (piped-input-stream (fn [out-stream]
(create-excel-into-stream out-stream
params))))
(assoc :headers {"Content-Type"
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"})))
Using this function, I always get an empty .xlsx file for some reasons.
It seems like piped-input-stream closes before I can serve it as the body of my response.
How do I use it properly, so I can write to output stream, pass it to input stream and then serve as the body of response?
Your excel-response function looks correct to me, I've written something very similar before. What does your create-excel-into-stream function look like?
This has worked for me in the past.
(ns my.data.handler
(:require [clojure.data.csv :as csv]
[clojure.java.io :as io]))
(defn create-excel-into-stream
[out-stream params]
(let [excel-data (get-excel-data params)]
(with-open [writer (io/writer out-stream)]
(csv/write-csv writer excel-data))))

Why does the order of Ring middleware need to be reversed?

I'm writing some middleware for Ring and I'm really confused as to why I have to reverse the order of the middleware.
I've found this blog post but it doesn't explain why I have to reverse it.
Here's a quick excerpt from the blog post:
(def app
(wrap-keyword-params (wrap-params my-handler)))
The response would be:
{; Trimmed for brevity
:params {"my_param" "54"}}
Note that the wrap keyword params didn't get called on it because the params hash didn't exist yet. But when you reverse the order of the middleware like so:
(def app
(wrap-params (wrap-keyword-params my-handler)))
{; Trimmed for brevity
:params {:my_param "54"}}
It works.
Could somebody please explain why you have to reverse the order of the middleware?
It helps to visualize what middleware actually is.
(defn middleware [handler]
(fn [request]
;; ...
;; Do something to the request before sending it down the chain.
;; ...
(let [response (handler request)]
;; ...
;; Do something to the response that's coming back up the chain.
;; ...
response)))
That right there was pretty much the a-ha moment for me.
What's confusing at first glance is that middleware isn't applied to the request, which is what you're thinking of.
Recall that a Ring app is just a function that takes a request and returns a response (which means it's a handler):
((fn [request] {:status 200, ...}) request) ;=> response
Let's zoom out a little bit. We get another handler:
((GET "/" [] "Hello") request) ;=> response
Let's zoom out a little more. We find the my-routes handler:
(my-routes request) ;=> response
Well, what if you wanted to do something before sending the request to the my-routes handler? You can wrap it with another handler.
((fn [req] (println "Request came in!") (my-routes req)) request) ;=> response
That's a little hard to read, so let's break out for clarity. We can define a function that returns that handler. Middleware are functions that take a handler and wrap it another handler. It doesn't return a response. It returns a handler that can return a response.
(defn println-middleware [wrapped-func]
(fn [req]
(println "Request came in!")
(wrapped-func req)))
((println-middleware my-route) request) ;=> response
And if we need to do something before even println-middleware gets the request, then we can wrap it again:
((outer-middleware (println-middleware my-routes)) request) ;=> response
The key is that my-routes, just like your my-handler, is the only named function that actually takes the request as an argument.
One final demonstration:
(handler3 (handler2 (handler1 request))) ;=> response
((middleware1 (middleware2 (middleware3 handler1))) request) ;=> response
I write so much because I can sympathize. But scroll back up to my first middleware example and hopefully it makes more sense.
The ring middleware is a series of functions which when stacked up return a handler function.
The section of the article that answers your question:
In case of Ring wrappers, typically we have “before” decorators that
perform some preparations before calling the “real” business function.
Since they are higher order functions and not direct function calls,
they are applied in reversed order. If one depends on the other, the
dependent one needs to be on the “inside”.
Here is a contrived example:
(let [post-wrap (fn [handler]
(fn [request]
(str (handler request) ", post-wrapped")))
pre-wrap (fn [handler]
(fn [request]
(handler (str request ", pre-wrapped"))))
around (fn [handler]
(fn [request]
(str (handler (str request ", pre-around")) ", post-around")))
handler (-> (pre-wrap identity)
post-wrap
around)]
(println (handler "(this was the input)")))
This prints and returns:
(this was the input), pre-around, pre-wrapped, post-wrapped, post-around
nil
As you may know the ring app is actually just a function that receives a request map and returns a response map.
In the first case the order in which the functions are applied is this:
request -> [wrap-keyword-params -> wrap-params -> my-handler] -> response
wrap-keyword-params looks for the key :params in the request but it's not there since wrap-params is the one who adds that key based on the "urlencoded parameters from the query string and form body".
When you invert the order of those two:
request -> [wrap-params -> wrap-keyword-params -> my-handler] -> response
You get the desired result since once the request gets to wrap-keyword-params, wrap-params has already added the corresponding keys.
The answer by danneu is nice, but it only really "clicked" for me after I visualized it in code to see how the chaining of middleware really looks like without the "->" threading macro magic (here's a link if you're not familiar with it). This is what I ended up with:
Let's say you have a request handler that looks like this:
(def amazing-handler
(-> #'some-amazing-fn
some-mware
another-mware
one-more-mware))
^^ The above handler, written without using a threading macro, would look like this (and I'm extending the indentation on purpose, so it is visually easier to understand which request belongs to which handler):
(def amazing-handler
(one-more-mware
(another-mware
((some-mware #'some-amazing-fn) request-from-another-mware)
request-from-one-more-mware)
original-request))
^^ The above is a style of code that requires us to read it from inside out (which sometimes is hard to follow), the threading macros (-> and ->>) allow us to read code in a natural left-to-right way, but it requires understanding on our part of how exactly it allows us to compose code in this "natural" way behind the scene.
Here's a more complete example:
;; For reference: this is how the end result of the entire "threading" looks like:
;; (((#'some-amazing-fn req-from-up-passed-down) req-from-up-passed-down) original-request)
(defn some-amazing-fn [req] ;; this "req" is the one that will get passed to this function from "some-mware"
(println "this is the final destination of the req", req)
(ring.util.http-response/ok {:body "some funny response"}))
(defn one-more-mware [some-argument] ;; the "some-argument" in this case is (another-mware (some-mware #'some-amazing-fn))
(fn [req] ;; the "req" here is the original request generated by the ring adaptors and passed to this chain of middleware
(println "|--> from fn inside one-more-mware")
(some-argument req))) ;; here we provide the another-mware with the request that it will then pass down the chain of middleware, you can imagine that chain, at this point in time, to look like this:
;; ((another-mware (some-mware #'some-amazing-fn)) req)
(defn another-mware [dunno-something] ;; the "dunno-something" in this case is (some-mware #'some-amazing-fn)
(fn [req] ;; the "req" here is passed from one-more-mware function
(println "|--> from fn inside another-mware")
(dunno-something req))) ;; here we are passing the "req" down the line to the (some-mware #'some-amazing-fn), so the entire thing behind the scenes, at this point in time, looks like this:
;; ((some-mware #'some-amazing-fn) req)
(defn some-mware [some-handler] ;; the "some-handler" arg here refers to #'some-amazing-fn
(fn [req] ;; the "req" here is passed to this function from another-mware function
(println "|--> from fn inside some-mware")
(some-handler req))) ;; here is where we are passing a "req" argument to the #'some-amazing-fn, so behind the scenes it could be thought of as looking like this:
;; (#'some-amazing-fn req)
(def amazing-handler
(-> #'some-amazing-fn
some-mware
another-mware
one-more-mware))
;; |--> from fn inside one-more-mware
;; |--> from fn inside another-mware
;; |--> from fn inside some-mware
;; |--> this is the final destination of the req {.. .. ..}

Strange boolean behavior in Clojure with checkbox in form-data

I'm using an AngularJS resource to basically $.ajax() some form data.
Post.put({user:$scope.getLoggedInUser(), action:"new"},{body:$scope.postBody, "public":$scope.postPublic}, function(post) {
On the form is a checkbox named "public."
I am using this function to merge the form data with the params from the URL:
(defn get-params [request]
(merge (:params request) (parse-string (slurp (request :body)) true)))
when I println from my route's handler like so I get a nice true when the checkbox is checked:
(println (:public (get-params request)))
However, when I pass the parameter (i.e. not the println) to another function in my controller that talks to the database, I do another println at the beginning of that function and get nil instead.
I've tried passing it as
(read-string x)
(boolean (Boolean/valueOf x))
(Boolean/valueOf x)
to no avail.
One thing that might be causing it (but I don't know why) is that I'm wrapping the request through authentication like this:
(auth? request #(create x y z))
where the (create) function creates a record in the database.
I can't get it to be true no matter what I've tried.
EDIT: more complete code
CONTROLLER
(defn auth? [request callback-true & [callback-false]]
(println (callback-true))
(let [login-response (auth/login request)]
(if (and (not (string? login-response))
login-response)
(callback-true)
(if callback-false
(callback-false)
(json-response (str "{\"auth\":" login-response "}"), 401)))))
(defn create [user logged-in-user body public?]
(if (= logged-in-user user)
(json-response (post-view/single-post (post/create user body public?)))
(json-response "{\"auth\":\"can't create post under different logged in user\"}" 401)))
(defroutes routes
....
(PUT "/api/:user/new" request
(println request)
(auth? request
#(create (:user (request :params))
(:user (request :session))
(:body (get-params request))
(:public (get-params request)))))
....
)
MODEL
(defn create [username body public?]
(println public?)
(when-not (and
(str/blank? body)
(str/blank? username))
(let [user-id (:id (get-id-from-username username))
new-post-id
(:id
(sql/with-connection db
(sql/insert-values :post
[:usr_id :body :public] [user-id body (Boolean/valueOf public?)])))]
(by-id new-post-id))))
Don't call get-params twice. (request :body) returns a stream, which can't be read twice.

Get body of HTTP response in Clojure

I'm trying to get the body of a HTTP response with Clojure, with a handler. However the http-agent function hangs without returning.
This will print the response, and then hang without returning:
(use '[clojure.contrib.http.agent])
(def text (result (http-agent "http://jsonip.com"
:method "GET")))
(println text)
This will print "Handling...", then hang indefinitely:
(use '[clojure.contrib.http.agent])
(defn do-stuff
"handler"
[response]
(do
(println "Handling...")
(slurp (string response))))
(def text (result (http-agent "http://jsonip.com"
:method "GET"
:handler do-stuff)))
(println (str "text! " text))
How can I get the http-agent method to stop hanging? In the second case I've listed above, how can I get the handler to return the response body?
Thanks for your help,
Kevin
In the second piece of code you have not printed out what is slurped. Should be like this -
(println (slurp (string response)))