123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167 |
- (import
- (except (rnrs base) let-values)
- (only (guile) lambda* λ error when display sleep)
- ;; Guile modules
- ;; alist->hash-table
- (prefix (ice-9 hash-table) ice9-hash-table:)
- ;; Guile exception handling
- (ice-9 exceptions)
- (ice-9 session)
- ;; for bytevector operations
- (ice-9 binary-ports)
- ;; SRFIs
- ;; hash tables
- (prefix (srfi srfi-69) srfi-69:)
- ;; receive form
- (prefix (srfi srfi-8) srfi-8:)
- ;; let-values
- (prefix (srfi srfi-11) srfi-11:)
- ;; list utils
- (prefix (srfi srfi-1) srfi-1:)
- ;; web server, concurrent
- (fibers web server)
- ;; standard web library
- (web request)
- (web response)
- (web uri)
- (sxml simple)
- ;; custom modules
- ;; model
- (model handler-config)
- ;; handlers
- (handlers index)
- (handlers schedule)
- (handlers resources)
- (handlers about)
- (handlers static-asset)
- (handlers debug)
- (handlers not-found-404)
- (middleware middleware)
- (lib utils response-utils)
- (lib utils request-utils)
- (lib utils list-utils)
- ;; (path-handling)
- (lib web-location-handling)
- (file-reader)
- (lib mime-types)
- (prefix (logging) log:)
- (templates helpers)
- (prefix (fslib) fslib:))
- ;;;
- ;;; SERVER
- ;;;
- ;; Here we define the routes and other server specific
- ;; stuff.
- ;; A routes-config is a hash that contains associations
- ;; between route parts and handlers.
- (define routes-config
- (srfi-69:alist->hash-table
- (list (cons '() (make-handler-config index-handler))
- (cons '("home") (make-handler-config index-handler))
- (cons '("schedule") (make-handler-config schedule-handler))
- (cons '("resources") (make-handler-config resources-handler))
- (cons '("about") (make-handler-config about-handler))
- (cons '("debug") (make-handler-config debug-handler))
- (cons '("static")
- (make-handler-config static-asset-handler
- #:handles-children #t)))))
- (define make-routes-dispatcher
- (lambda* (routes-config #:key (default-handler debug-handler))
- "make-routes-dispatcher returns a procedure, which, for
- each request, looks up the appropriate handler inside the
- given routes-config. As a fallback, a default-handler is
- given. In this case it is the debug-handler, which will
- render all headers."
- ;; NOTE: make-routes-dispatcher itself is not
- ;; responsible for answering to requests. The Guile web
- ;; server leaves the implementation details completely
- ;; to us and thus offers maximum flexibility in this
- ;; matter. We made the decision ourselves, that we want
- ;; to look at the request URI parts, to determin the
- ;; appropriate handler.
- (λ (request body)
- ;; Here we can have sequential actions. The first action in this example
- ;; is a logging middleware. We could make a middleware return a result,
- ;; which is then handed to the next middleware which might in turn
- ;; manipulate the result of the first one or create a new result or
- ;; whatever else we want to implement.
- (logging-middleware request body)
- (define req-path-components (request-path-components request))
- (log:debug "request path components:" req-path-components)
- ;; Try to find the request path in the routes. If it is not in the routes,
- ;; try to find each prefix of the request path in the routes. If a prefix
- ;; is in the routes, check, whether the handler of that route is
- ;; configured to match all requests starting with that request path
- ;; prefix.
- (let ([handler-conf
- (srfi-69:hash-table-ref routes-config
- req-path-components
- (λ () #f))])
- (cond
- [handler-conf
- ;; The request path has been found in the routes. Let the request be
- ;; handled by the corresponding handler.
- (log:debug "handler found for" req-path-components)
- ((handler-config-handler handler-conf) request body)]
- [else
- ;; Try to find request path prefixes in the routes. Reverse the prefixes
- ;; list, to check for longest prefixes first.
- (let ([req-path-prefixes (list-prefixes-long-to-short req-path-components)])
- (let ([prefix-request-path-handler
- (srfi-1:fold (λ (req-path-prefix acc)
- ;; Try to get a handler config for the request path
- ;; prefix.
- (let ([maybe-handler-conf
- (srfi-69:hash-table-ref routes-config
- req-path-prefix
- (λ () #f))])
- ;; If already a handler has been found, use
- ;; that one. This ensures to use the handler
- ;; for the longest matched prefix.
- (or acc
- ;; To actually match the request path, the
- ;; handler config must specify, that the handler
- ;; matches children of the route it is set for.
- (and (handler-config? maybe-handler-conf)
- (handler-config-handles-children? maybe-handler-conf)
- (handler-config-handler maybe-handler-conf)))))
- #f
- req-path-prefixes)])
- (cond
- [prefix-request-path-handler
- (log:debug "prefix handler found for" req-path-components)
- (prefix-request-path-handler request body)]
- ;; If even a handler for a prefix of the request path could not be
- ;; found, answer with a 404 response.
- [else
- (log:debug "no handler found for" req-path-components)
- (not-found-404-handler request body)])))])))))
- (define main
- (λ ()
- (log:debug "Starting the web server ...")
- ;; Start the server. The run-server procedure expects to
- ;; be given a procedure, which will dispatch requests to
- ;; whatever is responsible for handling the
- ;; requests. Theoretically one could implement all
- ;; inside this dispatcher, but that would be less clean.
- (run-server
- (make-routes-dispatcher routes-config #:default-handler debug-handler))
- (log:debug "Stopped web server.")))
- (main)
|