Search code examples
clojurering

InputStream to Clojure Ring map


I see that when a web browser connects to a HTTP server the following lines are sent:

GET / HTTP/1.1
Content-Length: 13

Hello, world!

I want to write a program that takes an InputStream, reads these lines and returns a Ring request map according to the ring specification.

Could you please suggest a Clojure library for this purpose? I took a quick look at web server source codes with ring support (for example http-kit) but with no success so far.


Solution

  • This surely can be achieved with http-kit library. But there are 2 problems:

    1. The class org.httpkit.server.ClojureRing is private. You have to access its method via reflection.
    2. :remote-addr value is read from InetSocketAddress object assigned to request, or you need to to have X-Forwarded-For header in your request string.

    Here is working demo:

    (let [request "POST / HTTP/1.1\nContent-Length: 13\nX-Forwarded-For: 127.0.0.1\n\nHello, world!"
          bytes (java.nio.ByteBuffer/wrap (.getBytes request))
          decoder (org.httpkit.server.HttpDecoder. 
                    8388608 4096 ProxyProtocolOption/DISABLED)
          method (.getMethod org.httpkit.server.ClojureRing 
                             "buildRequestMap"
                             (into-array [org.httpkit.server.HttpRequest]))]
      (.setAccessible method true)
      (.invoke method nil (object-array [(.decode decoder bytes)]))) 
    
    =>
    {:remote-addr "127.0.0.1",
     :headers {"content-length" "13", "x-forwarded-for" "127.0.0.1"},
     :async-channel nil,
     :server-port 80,
     :content-length 13,
     :websocket? false,
     :content-type nil,
     :character-encoding "utf8",
     :uri "/",
     :server-name nil,
     :query-string nil,
     :body #object[org.httpkit.BytesInputStream 0x4f078b2 "BytesInputStream[len=13]"],
     :scheme :http,
     :request-method :post}