-
-
Save tjweir/203608 to your computer and use it in GitHub Desktop.
This file contains hidden or 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
| (ns alandipert.minihttpd | |
| (:use [clojure.contrib.duck-streams :only (reader writer read-lines spit to-byte-array)] | |
| [clojure.contrib.str-utils :only (re-split str-join)]) | |
| (:import (java.net ServerSocket Socket InetAddress URLDecoder) | |
| (java.io File))) | |
| (def codes {200 "HTTP/1.0 200 OK" | |
| 404 "HTTP/1.0 404 Not Found"}) | |
| (def mimes {"css" "Content-type: text/css" | |
| "html" "Content-type: text/html" | |
| "jpg" "Content-type: image/jpeg" | |
| "png" "Content-type: image/png" | |
| "gif" "Content-type: image/gif" | |
| "clj" "Content-type: text/plain" | |
| "txt" "Content-type: text/plain"}) | |
| (def error {404 "The file was not found." | |
| 500 "There was a server error."}) | |
| (def doc-root "/Users/alan/Sites") | |
| (defn build-headers [& headers] | |
| "Build a header string and end it with two spaces" | |
| (str (str-join "\r\n" headers) "\r\n\r\n")) | |
| (defn get-ext [abspath] | |
| "Try to get a file's extension for use mapping to a MIME type" | |
| (last (re-split #"\." abspath))) | |
| (defn send-resource [sock file] | |
| "Open the socket's output stream and send headers and content" | |
| (with-open [os (.getOutputStream sock)] | |
| (let [path (.getAbsolutePath file) | |
| headers (build-headers (codes 200) (mimes (get-ext path) "txt"))] | |
| (.write os (to-byte-array headers) 0 (count headers)) | |
| (.write os (to-byte-array file) 0 (.length file))))) | |
| (defn send-error [sock code msg] | |
| "Open the socket's output stream and send header and error message" | |
| (with-open [wrt (writer (.getOutputStream sock))] | |
| (spit wrt (str (build-headers (codes code) (mimes "txt")) msg)))) | |
| (defn handle-request [sock] | |
| "Send the file if it exists, or a 404" | |
| (with-open [rdr (reader (.getInputStream sock))] | |
| (let [uri (second (re-split #"\s+" (first (line-seq rdr)))) | |
| file (File. (str doc-root (URLDecoder/decode uri)))] | |
| (if (.exists file) | |
| (send-resource sock file) | |
| (send-error sock 404 "File not found"))))) | |
| (defmulti http-listen class) | |
| (defmethod http-listen ServerSocket [socket] | |
| "Bind to a socket and keep listening" | |
| (let [client-socket (.accept socket)] | |
| (handle-request client-socket)) | |
| (recur socket)) | |
| (defmethod http-listen Integer [port] | |
| "Takes a port number to listen on; defers to the listen loop function" | |
| (http-listen (ServerSocket. port))) | |
| (http-listen 8081) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment