((section 2 "Outdated egg!" (p "This is an egg for CHICKEN 4, the unsupported old release.  You're almost certainly looking for " (int-link "/eggref/5/mongrel2" "the CHICKEN 5 version of this egg") ", if it exists.") (p "If it does not exist, there may be equivalent functionality provided by another egg; have a look at the " (link "https://wiki.call-cc.org/chicken-projects/egg-index-5.html" "egg index") ". Otherwise, please consider porting this egg to the current version of CHICKEN.") (tags "egg")) (section 2 "mongrel2" (toc) (section 3 "Description" (p "This egg provides an API for writing " (link "http://mongrel2.org/" "Mongrel2") " handlers. Mongrel2 strives to be an application, language, and network architecture agnostic web server. The server itself is written in C and is required to actually put handlers created with this egg to use. Mongrel2 communicates with its handlers via " (int-link "zmq" "ZeroMQ") ".") (p "The API comes in two flavors: " (tt "mongrel2-lolevel") " which is modeled after the Python example handler code of the distribution (see " (tt "examples/python") " in the Mongrel2 tarball) and " (tt "mongrel2") " which is built on top of that and modeled after " (int-link "spiffy") "'s API.")) (section 3 "Author" (p (int-link "/users/moritz-heidkamp" "Moritz Heidkamp"))) (section 3 "Caveat" (p "This API is very experimental and may change significantly in the near future.")) (section 3 "Documentation" (p "The following assumes that you are familiar with " (link "http://www.zeromq.org/" "ZeroMQ") " as well as Mongrel2's architecture. If you aren't yet, go read the " (link "http://zguide.zeromq.org/chapter:all" "ZeroMQ guide") " and/or the " (link "http://mongrel2.org/static/mongrel2-manual.html" "Mongrel2 Manual") ".") (section 4 "mongrel2-lolevel" (def (sig (procedure "(connect-handler id response-endpoint request-endpoint #!optional request-id)" (id connect-handler))) (p "Creates and connects two " (int-link "zmq") " sockets for communicating with a Mongrel2 server. The " (tt "id") " is used as the PUB socket's identity and " (tt "request-endpoint") " is a zmq endpoint string for that socket to connect to. Correspondingly, " (tt "request-endpoint") " is the zmq endpoint string for the PULL socket to connect to. Optionally, an identity for that socket can be given as " (tt "request-id") ". The return value is an opaque connection record which is further referred to as a " (i "connection") ".")) (def (sig (procedure "(receive-request connection)" (id receive-request))) (p "Receives a request from " (tt "connection") ". This will block the current thread until a request is available. Requests are returned in the form of a record which can be inspected with several procedures also available in this module.")) (def (sig (procedure "(request-disconnect? request)" (id request-disconnect?))) (p "Checks whether the given " (tt "request") " signifies a disconnect event.")) (def (sig (procedure "(request-sender request)" (id request-sender))) (p "Returns the given " (tt "request") "'s sender UUID as a string.")) (def (sig (procedure "(request-path request)" (id request-path))) (p "Returns the given " (tt "request") "'s URI path as a string.")) (def (sig (procedure "(request-headers request)" (id request-headers))) (p "Returns the given " (tt "request") "'s headers as an alist with the keys being symbols.")) (def (sig (procedure "(request-header name request)" (id request-header))) (p "Return the value of " (tt "request") "'s header " (tt "name") " which must be a symbol. If there no header of that name is found, " (tt "#f") " is returned.")) (def (sig (procedure "(request-method request)" (id request-method))) (p "Returns the given " (tt "request") "'s method as a symbol, e.g. " (tt "JSON") " or " (tt "GET") ".")) (def (sig (procedure "(request-body request)" (id request-body))) (p "Returns the given " (tt "request") "'s body as a string.")) (def (sig (procedure "(request-data request)" (id request-data))) (p "Returns the given " (tt "request") "'s body in a structured format. This depends on the request's method. Currently it will only handle requests of the type " (tt "JSON") " and return the body's contents parsed by the " (tt "json") " egg.")) (def (sig (procedure "(request-id request)" (id request-id))) (p "Returns the given " (tt "request") "'s listener id as a string.")) (def (sig (procedure "(request-type)" (id request-type))) (p "Returns the given " (tt "request") "'s type as a symbol. This is either " (tt "json") ", " (tt "xml") " or " (tt "http") ".")) (def (sig (procedure "(request-uri)" (id request-uri))) (p "Returns the given " (tt "request") "'s URI as a " (int-link "uri-common") " record.")) (def (sig (procedure "(send-response request response)" (id send-response))) (p "Sends a " (tt "response") " string for the given " (tt "request") ".")) (def (sig (procedure "(send-http-response request #!key code reason body headers response)" (id send-http-response))) (p "Sends an HTTP response for the given " (tt "request") ". The arguments are exactly the same as those of " (int-link "spiffy") "'s " (tt "send-response") " with the addition of the keyword argument " (tt "response") " which can be used to pass in an " (int-link "intarweb") " response record to be used as a basis (default is an empty response record)."))) (section 4 "mongrel2" (def (sig (parameter "(handler-response-id [id])" (id handler-response-id))) (p "The response socket's identity string.")) (def (sig (parameter "(handler-response-endpoint [endpoint])" (id handler-response-endpoint))) (p "The response socket's endpoint string.")) (def (sig (parameter "(handler-request-id [id])" (id handler-request-id))) (p "The request socket's identity string.")) (def (sig (parameter "(handler-request-endpoint [endpoint])" (id handler-request-endpoint))) (p "The request socket's endpoint string.")) (def (sig (parameter "(current-request [request])" (id current-request))) (p "The current Mongrel2 request record (see the " (tt "mongrel2-lolevel") " module for available accessors).")) (def (sig (parameter "(current-http-request [http-request])" (id current-http-request))) (p "If the " (tt "current-request") "'s " (tt "request-type") " is " (tt "http") ", this parameter holds a corresponding " (int-link "intarweb") " request record. Otherwise it will be " (tt "#f") ".")) (def (sig (parameter "(current-http-response [http-response])" (id current-http-response))) (p "If the " (tt "current-request") "'s " (tt "request-type") " is " (tt "http") ", this parameter holds an " (int-link "intarweb") " response record which can be used to build up a response. Otherwise it will be " (tt "#f") ".")) (def (sig (procedure "(handler-start [handler])" (id handler-start))) (p "Starts the handler mainloop. " (tt "handler") " is a thunk which is called for each incoming request with the above paramters set accordingly. It is expected to send a response to " (tt "current-request") ". See " (tt "send-response") " and " (tt "send-http-response") " on how to do that.")) (def (sig (procedure "(send-response body)" (id send-response))) (p "Sends the string " (tt "body") " as the response for " (tt "current-request") ".")) (def (sig (procedure "(send-http-response #!key code reason body headers)" (id send-http-response))) (p "Sends a HTTP response for " (tt "current-request") ". This procedure works exactly like " (int-link "spiffy") "'s " (tt "send-response") ".")))) (section 3 "Examples" (section 4 "mongrel2-lolevel" (highlight scheme "(use mongrel2-lolevel)\n\n(define conn (connect-handler \"6cafb469-3b40-40c1-a50a-ede619ce3d16\"\n                              \"tcp://127.0.0.1:1234\"\n                              \"tcp://127.0.0.1:1235\"\n                              \"55752929-b6c0-4015-9e9e-17c765c90a12\"))\n\n(let loop ()\n  \n  (print \"WAITING FOR REQUEST\")\n\n  (let ((req (receive-request conn)))\n\n    (if (request-disconnect? req)\n        (print \"DISCONNECT\")\n        (send-http-response req \n                            body: (format \"\\nSENDER: ~A\\nIDENT: ~A\\nPATH: ~A\\nHEADERS: ~S\\nBODY: ~A\"\n                                          (request-sender req)\n                                          (request-id req)\n                                          (request-path req)\n                                          (request-headers req) \n                                          (request-body req))\n                            headers: '((content-type text/plain)))))\n  \n  (loop))")) (section 4 "mongrel2" (highlight scheme "(use mongrel2 uri-common (prefix intarweb http-))\n                              \n(handler-response-id \"6cafb469-3b40-40c1-a50a-ede619ce3d16\")\n(handler-response-endpoint \"tcp://127.0.0.1:1234\")\n(handler-request-id \"55752929-b6c0-4015-9e9e-17c765c90a12\")\n(handler-request-endpoint \"tcp://127.0.0.1:1235\")\n\n(handler-start (lambda ()\n                 (let ((uri (uri->string (http-request-uri (current-http-request)))))\n                   (send-http-response body: (format \"thank you for requesting ~A\" uri)))))\n")))))