-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Create .gitignore , Delete .nrepl-port Update README.md Update README.md
- Loading branch information
0 parents
commit aa5a13d
Showing
5 changed files
with
168 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
# Auto detect text files and perform LF normalization | ||
* text=auto |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
.idea | ||
.nrepl-port | ||
*.iml |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
# Microhttp Ring Adapter | ||
|
||
## What | ||
Adapter for using [microhttp](https://github.com/ebarlas/microhttp) | ||
as a ring server. | ||
|
||
Doesn't support the required `:remote-addr` key properly because microhttp | ||
does not support recovering that information. This isn't the biggest loss as | ||
that information isn't reliable in modern cloud environments anyways, but | ||
worth noting. | ||
|
||
This was done as a proof of concept, but the code is simple enough that | ||
I am confident it is as production ready as microhttp. | ||
|
||
## deps.edn | ||
|
||
```clojure | ||
io.github.bowbahdoe/microhttp-ring-adapter {:git/tag "v0.0.1"} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
{:paths ["src"] | ||
:deps {ring/ring-core {:mvn/version "1.9.5"} | ||
org.microhttp/microhttp {:mvn/version "0.7"}}} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,141 @@ | ||
(ns dev.mccue.microhttp-ring-adapter | ||
(:require [clojure.string :as string] | ||
[ring.core.protocols :as ring-protocols]) | ||
(:import (org.microhttp Request Handler Response Header EventLoop Options DebugLogger) | ||
(java.io ByteArrayInputStream ByteArrayOutputStream))) | ||
|
||
(set! *warn-on-reflection* true) | ||
|
||
(defn- ->req | ||
[{:keys [host port]} ^Request microhttp-request] | ||
(let [[uri query-string] (string/split (.uri microhttp-request) | ||
#"\?")] | ||
{:server-port port | ||
:server-name host | ||
:remote-addr "" ; TODO: microhttp doesn't have a way to recover this | ||
:uri uri | ||
:query-string query-string | ||
:scheme :http | ||
:request-method (keyword (string/lower-case (.method microhttp-request))) | ||
:headers (reduce (fn [acc ^Header header] | ||
(assoc acc | ||
(string/lower-case (.name header)) | ||
(.value header))) | ||
{} | ||
(.headers microhttp-request)) | ||
:body (ByteArrayInputStream. (or (.body microhttp-request) | ||
(byte-array 0)))})) | ||
|
||
(def ^{:private true} status->reason | ||
{100 "Continue" | ||
101 "Switching Protocols" | ||
200 "OK" | ||
201 "Created" | ||
202 "Accepted" | ||
203 "Non-Authoritative Information" | ||
204 "No Content" | ||
205 "Reset Content" | ||
206 "Partial Content" | ||
300 "Multiple Choices" | ||
301 "Moved Permanently" | ||
302 "Found" | ||
303 "See Other" | ||
304 "Not Modified" | ||
305 "Use Proxy" | ||
307 "Temporary Redirect" | ||
400 "Bad Request" | ||
401 "Unauthorized" | ||
402 "Payment Required" | ||
403 "Forbidden" | ||
404 "Not Found" | ||
405 "Method Not Allowed" | ||
406 "Not Acceptable" | ||
407 "Proxy Authentication Required" | ||
408 "Request Time-out" | ||
409 "Conflict" | ||
410 "Gone" | ||
411 "Length Required" | ||
412 "Precondition Failed" | ||
413 "Request Entity Too Large" | ||
414 "Request-URI Too Large" | ||
415 "Unsupported Media Type" | ||
416 "Requested range not satisfiable" | ||
417 "Expectation Failed" | ||
500 "Internal Server Error" | ||
501 "Not Implemented" | ||
502 "Bad Gateway" | ||
503 "Service Unavailable" | ||
504 "Gateway Time-out" | ||
505 "HTTP Version not supported"}) | ||
|
||
(defn- <-res | ||
[ring-response] | ||
(let [out (ByteArrayOutputStream.)] | ||
(ring-protocols/write-body-to-stream (:body ring-response) | ||
ring-response | ||
out) | ||
(Response. (:status ring-response) | ||
(or (status->reason (:status ring-response)) "IDK") | ||
(reduce (fn [header-list [k v]] | ||
(conj header-list (Header. k v))) | ||
[] | ||
(:headers ring-response)) | ||
(.toByteArray out)))) | ||
|
||
(defn- ring-handler->Handler | ||
[{:keys [host port]} ring-handler] | ||
(reify Handler | ||
(handle [_ microhttp-request callback] | ||
(let [ring-request (->req {:host host | ||
:port port} microhttp-request) | ||
microhttp-response (<-res (ring-handler ring-request))] | ||
(.accept callback microhttp-response))))) | ||
|
||
(defn create-microhttp-event-loop | ||
([handler] | ||
(create-microhttp-event-loop handler {})) | ||
([handler options] | ||
(let [microhttp-options (cond-> (Options.) | ||
(some? (options :host)) | ||
(.withHost (:host options)) | ||
|
||
(some? (options :port)) | ||
(.withPort (:port options)) | ||
|
||
(some? (options :reuse-addr)) | ||
(.withReuseAddr (:reuse-addr options)) | ||
|
||
(some? (options :reuse-port)) | ||
(.withReusePort (:reuse-port options)) | ||
|
||
(some? (options :resolution)) | ||
(.withResolution (:resolution options)) | ||
|
||
(some? (options :request-timeout)) | ||
(.withRequestTimeout (:request-timeout options)) | ||
|
||
(some? (options :read-buffer-size)) | ||
(.withReadBufferSize (:read-buffer-size options)) | ||
|
||
(some? (options :accept-length)) | ||
(.withAcceptLength (:accept-length options)) | ||
|
||
(some? (options :max-request-size)) | ||
(.withMaxRequestSize (:max-request-size options))) | ||
microhttp-logger (or (:logger options) (DebugLogger.))] | ||
(EventLoop. microhttp-options | ||
microhttp-logger | ||
(ring-handler->Handler | ||
{:host (.host microhttp-options) | ||
:port (.port microhttp-options)} | ||
handler))))) | ||
|
||
(comment | ||
(defn handler [req] | ||
{:status 200 | ||
:headers {"Content-Type" "text/html"} | ||
:body (str "<pre>" | ||
(with-out-str | ||
(clojure.pprint/pprint req)) | ||
"</pre>")}) | ||
(def event-loop (create-microhttp-event-loop #'handler {:port 1242}))) |