;;;; CLASH --- The Common Lisp Adaptable Simple HTTP server ;;;; This is copyrighted software. See documentation for terms. ;;;; ;;;; resource.cl --- Definition of a served resource ;;;; ;;;; Checkout Tag: $Name$ ;;;; $Id$ (in-package :CLASH) ;;;; %File Description: ;;;; ;;;; A resource is that which is accessed by a client through a server ;;;; via an URL ;) ;;;; (defclass resource () ()) (defgeneric resource-allowed-methods (resource)) (defgeneric access-resource (resource request) (:argument-precedence-order request resource)) (defgeneric access-resource-using-method (resource request method) (:argument-precedence-order method request resource)) (defmethod access-resource ((resource resource) request) (let ((method (request-method request)) (allowed-methods (resource-allowed-methods resource))) (if (member method allowed-methods) (access-resource-using-method resource request method) (error 'clash-error :code +HTTP-Code-Method-Not-Allowed+ :entity-initargs (list :allow allowed-methods))))) (defclass static-resource (resource) ((entity :initarg :entity :accessor static-resource-entity) (allowed-methods :allocation :class :initform '(:GET :HEAD) :reader resource-allowed-methods))) (defmethod access-resource-using-method ((resource static-resource) request (method (eql :GET))) (create-response request +HTTP-Code-OK+ :entity (static-resource-entity resource))) (defmethod access-resource-using-method ((resource static-resource) request (method (eql :HEAD))) (create-response request +HTTP-Code-OK+ :entity (static-resource-entity resource))) (defclass dynamic-resource (resource) ((allowed-methods :initarg :allowed-methods :initform '(:GET :HEAD) :reader resource-allowed-methods) (generator :initarg :generator :reader dynamic-resource-generator))) (defmethod access-resource-using-method ((resource dynamic-resource) request method) (funcall (dynamic-resource-generator resource) resource request method)) (defclass dynamic-form-resource (dynamic-resource) ((processor :initarg :processor :reader dynamic-form-resource-processor)) (:default-initargs :allowed-methods '(:GET :HEAD :POST))) (defmethod access-resource-using-method ((resource dynamic-form-resource) request (method (eql :POST))) (funcall (dynamic-form-resource-processor resource) resource request method)) (defun parse-form-data (request) (let* ((entity (request-entity request)) (data (entity-body entity))) (parse-query-part data 0 (length data)))) (defmacro with-form-data (vars request &body body) (loop with data-sym = (gensym) for var in vars collect `(,var (cdr (assoc (symbol-name ',var) ,data-sym :test #'string-equal))) into bindings finally (return `(let ((,data-sym (parse-form-data ,request))) (let ,bindings ,@body)))))