text:
hunchentoot-1.2.35/ 0000755 0000041 0000041 00000000000 12656661410 014177 5 ustar www-data www-data hunchentoot-1.2.35/set-timeouts.lisp 0000644 0000041 0000041 00000007062 12656661410 017537 0 ustar www-data www-data ;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: CL-USER; Base: 10 -*-
;;; Copyright (c) 2004-2010, Dr. Edmund Weitz. All rights reserved.
;;; Redistribution and use in source and binary forms, with or without
;;; modification, are permitted provided that the following conditions
;;; are met:
;;; * Redistributions of source code must retain the above copyright
;;; notice, this list of conditions and the following disclaimer.
;;; * Redistributions in binary form must reproduce the above
;;; copyright notice, this list of conditions and the following
;;; disclaimer in the documentation and/or other materials
;;; provided with the distribution.
(in-package :hunchentoot)
(defun set-timeouts (usocket read-timeout write-timeout)
"Sets up timeouts on the given USOCKET object. READ-TIMEOUT is the
read timeout period, WRITE-TIMEOUT is the write timeout, specified in
\(fractional) seconds. The timeouts can either be implemented using
the low-level socket options SO_RCVTIMEO and SO_SNDTIMEO or some
other, implementation specific mechanism. On platforms that do not
support separate read and write timeouts, both must be equal or an
error will be signaled. READ-TIMEOUT and WRITE-TIMEOUT may be NIL,
which means that the corresponding socket timeout value will not be
(declare (ignorable usocket read-timeout write-timeout))
;; add other Lisps here if necessary
#+(or :sbcl :cmu :abcl)
(unless (eql read-timeout write-timeout)
(parameter-error "Read and write timeouts for socket must be equal."))
(when read-timeout
(socket:socket-options (usocket:socket usocket) :SO-RCVTIMEO read-timeout))
(when write-timeout
(socket:socket-options (usocket:socket usocket) :SO-SNDTIMEO write-timeout))
(when read-timeout
(setf (sb-bsd-sockets:sockopt-receive-timeout (usocket:socket usocket))
(when write-timeout
(setf (sb-bsd-sockets:sockopt-send-timeout (usocket:socket usocket))
(when read-timeout
(setf (ccl:stream-input-timeout (usocket:socket usocket))
(when write-timeout
(setf (ccl:stream-output-timeout (usocket:socket usocket))
(when read-timeout
(setf (sb-impl::fd-stream-timeout (usocket:socket-stream usocket))
(coerce read-timeout 'single-float)))
(setf (lisp::fd-stream-timeout (usocket:socket-stream usocket))
(coerce read-timeout 'integer))
(when read-timeout
(java:jcall (java:jmethod "java.net.Socket" "setSoTimeout" "int")
(usocket:socket usocket)
(* 1000 read-timeout)))
(when write-timeout
(warn "Unimplemented."))
#-(or :clisp :allegro :openmcl :sbcl :lispworks :cmu :ecl :abcl)
(not-implemented 'set-timeouts))
hunchentoot-1.2.35/cookie.lisp 0000644 0000041 0000041 00000012263 12656661410 016345 0 ustar www-data www-data ;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: HUNCHENTOOT; Base: 10 -*-
;;; Copyright (c) 2004-2010, Dr. Edmund Weitz. All rights reserved.
;;; Redistribution and use in source and binary forms, with or without
;;; modification, are permitted provided that the following conditions
;;; are met:
;;; * Redistributions of source code must retain the above copyright
;;; notice, this list of conditions and the following disclaimer.
;;; * Redistributions in binary form must reproduce the above
;;; copyright notice, this list of conditions and the following
;;; disclaimer in the documentation and/or other materials
;;; provided with the distribution.
(in-package :hunchentoot)
(defclass cookie ()
((name :initarg :name
:reader cookie-name
:type string
:documentation "The name of the cookie - a string.")
(value :initarg :value
:accessor cookie-value
:initform ""
:documentation "The value of the cookie. Will be URL-encoded
when sent to the browser.")
(expires :initarg :expires
:initform nil
:accessor cookie-expires
:documentation "The time \(a universal time) when the
cookie expires \(or NIL).")
(max-age :initarg :max-age
:initform nil
:accessor cookie-max-age
:documentation "The time delta \(in seconds) after which the
cookie expires \(or NIL).")
(path :initarg :path
:initform nil
:accessor cookie-path
:documentation "The path this cookie is valid for \(or NIL).")
(domain :initarg :domain
:initform nil
:accessor cookie-domain
:documentation "The domain this cookie is valid for \(or NIL).")
(secure :initarg :secure
:initform nil
:accessor cookie-secure
:documentation "A generalized boolean denoting whether this
cookie is a secure cookie.")
(http-only :initarg :http-only
:initform nil
:accessor cookie-http-only
:documentation "A generalized boolean denoting whether
this cookie is a `HttpOnly' cookie.
This is a Microsoft extension that has been implemented in Firefox as
well. See
.html, that file is sent to the client after variable
substitution. Variables are referenced by ${
~A~@[~%~%Backtrace:~%~%~A~]" (escape-for-html (princ-to-string error)) (when *show-lisp-backtraces-p* (escape-for-html (princ-to-string backtrace)))) (cooked-message "An error has occurred"))) (t (when (<= 400 http-status-code) (cooked-message "An error has occurred")))))) (defmethod acceptor-status-message ((acceptor t) http-status-code &rest args &key &allow-other-keys) (apply 'make-cooked-message http-status-code args)) (defmethod acceptor-status-message :around ((acceptor acceptor) http-status-code &rest args &key &allow-other-keys) (handler-case (call-next-method) (error (e) (log-message* :error "error ~A during error processing, sending cooked message to client" e) (apply 'make-cooked-message http-status-code args)))) (defun string-as-keyword (string) "Intern STRING as keyword using the reader so that case conversion is done with the reader defaults." (let ((*package* (find-package :keyword))) (read-from-string string))) (defmethod acceptor-status-message ((acceptor acceptor) http-status-code &rest properties &key &allow-other-keys) "Default function to generate error message sent to the client." (labels ((substitute-request-context-variables (string) (let ((properties (append `(:script-name ,(script-name*) :lisp-implementation-type ,(lisp-implementation-type) :lisp-implementation-version ,(lisp-implementation-version) :hunchentoot-version ,*hunchentoot-version*) properties))) (unless *show-lisp-backtraces-p* (setf (getf properties :backtrace) nil)) (cl-ppcre:regex-replace-all "(?i)\\$\\{([a-z0-9-_]+)\\}" string (lambda (target-string start end match-start match-end reg-starts reg-ends) (declare (ignore start end match-start match-end)) (let ((variable-name (string-as-keyword (subseq target-string (aref reg-starts 0) (aref reg-ends 0))))) (escape-for-html (princ-to-string (getf properties variable-name variable-name)))))))) (file-contents (file) (let ((buf (make-string (file-length file)))) (read-sequence buf file) buf)) (error-contents-from-template () (let ((error-file-template-pathname (and (acceptor-error-template-directory acceptor) (probe-file (make-pathname :name (princ-to-string http-status-code) :type "html" :defaults (acceptor-error-template-directory acceptor)))))) (when error-file-template-pathname (with-open-file (file error-file-template-pathname :if-does-not-exist nil :element-type 'character) (when file (setf (content-type*) "text/html") (substitute-request-context-variables (file-contents file)))))))) (or (unless (< 300 http-status-code) (call-next-method)) ; don't ever try template for positive return codes (when *show-lisp-errors-p* (error-contents-from-template)) ; try template (call-next-method)))) ; fall back to cooked message (defgeneric acceptor-remove-session (acceptor session) (:documentation "This function is called whenever a session in ACCEPTOR is being destroyed because of a session timout or an explicit REMOVE-SESSION call.")) (defmethod acceptor-remove-session ((acceptor acceptor) (session t)) "Default implementation for the session removal hook function. This function is called whenever a session is destroyed." nil) (defgeneric acceptor-server-name (acceptor) (:documentation "Returns a string which can be used for 'Server' headers.") (:method ((acceptor acceptor)) (format nil "Hunchentoot ~A" *hunchentoot-version*))) hunchentoot-1.2.35/conditions.lisp 0000644 0000041 0000041 00000012754 12656661410 017252 0 ustar www-data www-data ;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: HUNCHENTOOT; Base: 10 -*- ;;; Copyright (c) 2008-2009, Dr. Edmund Weitz. All rights reserved. ;;; Redistribution and use in source and binary forms, with or without ;;; modification, are permitted provided that the following conditions ;;; are met: ;;; * Redistributions of source code must retain the above copyright ;;; notice, this list of conditions and the following disclaimer. ;;; * Redistributions in binary form must reproduce the above ;;; copyright notice, this list of conditions and the following ;;; disclaimer in the documentation and/or other materials ;;; provided with the distribution. ;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED ;;; OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ;;; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ;;; ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ;;; DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ;;; DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE ;;; GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ;;; INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, ;;; WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING ;;; NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ;;; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. (in-package :hunchentoot) (define-condition hunchentoot-condition (condition) () (:documentation "Superclass for all conditions related to Hunchentoot.")) (define-condition hunchentoot-error (hunchentoot-condition error) () (:documentation "Superclass for all errors related to Hunchentoot.")) (define-condition hunchentoot-simple-error (hunchentoot-error simple-condition) () (:documentation "Like HUNCHENTOOT-ERROR but with formatting capabilities.")) (defun hunchentoot-error (format-control &rest format-arguments) "Signals an error of type HUNCHENTOOT-SIMPLE-ERROR with the provided format control and arguments." (error 'hunchentoot-simple-error :format-control format-control :format-arguments format-arguments)) (define-condition hunchentoot-warning (hunchentoot-condition warning) () (:documentation "Superclass for all warnings related to Hunchentoot.")) (define-condition hunchentoot-simple-warning (hunchentoot-warning simple-condition) () (:documentation "Like HUNCHENTOOT-WARNING but with formatting capabilities.")) (defun hunchentoot-warn (format-control &rest format-arguments) "Signals a warning of type HUNCHENTOOT-SIMPLE-WARNING with the provided format control and arguments." (warn 'hunchentoot-simple-warning :format-control format-control :format-arguments format-arguments)) (define-condition parameter-error (hunchentoot-simple-error) () (:documentation "Signalled if a function was called with incosistent or illegal parameters.")) (defun parameter-error (format-control &rest format-arguments) "Signals an error of type PARAMETER-ERROR with the provided format control and arguments." (error 'parameter-error :format-control format-control :format-arguments format-arguments)) (define-condition operation-not-implemented (hunchentoot-error) ((operation :initarg :operation :reader hunchentoot-operation-not-implemented-operation :documentation "The name of the unimplemented operation.")) (:report (lambda (condition stream) (format stream "The operation ~A is not yet implemented for the implementation ~A. Consider sending a patch..." (hunchentoot-operation-not-implemented-operation condition) (lisp-implementation-type)))) (:documentation "This warning is signalled when an operation \(like SETUID for example) is not implemented for a specific Lisp.")) (defun not-implemented (name) "Used to signal an error if an operation named NAME is not implemented." (error 'operation-not-implemented :operation name)) (define-condition bad-request (hunchentoot-error) ()) ;;; (defgeneric maybe-invoke-debugger (condition) (:documentation "This generic function is called whenever a condition CONDITION is signaled in Hunchentoot. You might want to specialize it on specific condition classes for debugging purposes.") (:method (condition) "The default method invokes the debugger with CONDITION if *CATCH-ERRORS-P* is NIL." (unless *catch-errors-p* (invoke-debugger condition)))) (defmacro with-debugger (&body body) "Executes BODY and invokes the debugger if an error is signaled and *CATCH-ERRORS-P* is NIL." `(handler-bind ((bad-request (lambda (c) (declare (ignore c)) (setf (return-code *reply*) +http-bad-request+) (abort-request-handler))) (error #'maybe-invoke-debugger)) ,@body)) (defmacro ignore-errors* (&body body) "Like IGNORE-ERRORS, but observes *CATCH-ERRORS-P*." `(ignore-errors (with-debugger ,@body))) (defmacro handler-case* (expression &rest clauses) "Like HANDLER-CASE, but observes *CATCH-ERRORS-P*." `(handler-case (with-debugger ,expression) ,@clauses)) (defun get-backtrace () "Returns a string with a backtrace of what the Lisp system thinks is the \"current\" error." (handler-case (with-output-to-string (s) (trivial-backtrace:print-backtrace-to-stream s)) (error (condition) (format nil "Could not generate backtrace: ~A." condition)))) hunchentoot-1.2.35/packages.lisp 0000644 0000041 0000041 00000023554 12656661410 016657 0 ustar www-data www-data ;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: CL-USER; Base: 10 -*- ;;; Copyright (c) 2004-2010, Dr. Edmund Weitz. All rights reserved. ;;; Redistribution and use in source and binary forms, with or without ;;; modification, are permitted provided that the following conditions ;;; are met: ;;; * Redistributions of source code must retain the above copyright ;;; notice, this list of conditions and the following disclaimer. ;;; * Redistributions in binary form must reproduce the above ;;; copyright notice, this list of conditions and the following ;;; disclaimer in the documentation and/or other materials ;;; provided with the distribution. ;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED ;;; OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ;;; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ;;; ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ;;; DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ;;; DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE ;;; GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ;;; INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, ;;; WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING ;;; NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ;;; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. (in-package :cl-user) (defpackage #:hunchentoot (:nicknames #:tbnl) (:use :cl :cl-ppcre :chunga :flexi-streams :url-rewrite) (:shadow #:defconstant #:url-encode) #+:lispworks (:import-from :lw #:with-unique-names #:when-let) (:export #:*acceptor* #:*catch-errors-p* #+:lispworks #:*cleanup-function* #+:lispworks #:*cleanup-interval* #:*content-types-for-url-rewrite* #:*default-connection-timeout* #:*default-content-type* #:*dispatch-table* #:*file-upload-hook* #:*handle-http-errors-p* #:*header-stream* #:*http-error-handler* #:*hunchentoot-default-external-format* #:*hunchentoot-version* #:*lisp-errors-log-level* #:*lisp-warnings-log-level* #:*log-lisp-backtraces-p* #:*log-lisp-errors-p* #:*log-lisp-warnings-p* #:*methods-for-post-parameters* #:*reply* #:*request* #:*rewrite-for-session-urls* #:*session* #:*session-gc-frequency* #:*session-max-time* #:*session-secret* #:*show-lisp-backtraces-p* #:*show-lisp-errors-p* #:*tmp-directory* #:*use-remote-addr-for-sessions* #:*use-user-agent-for-sessions* #:+http-accepted+ #:+http-authorization-required+ #:+http-bad-gateway+ #:+http-bad-request+ #:+http-conflict+ #:+http-continue+ #:+http-created+ #:+http-expectation-failed+ #:+http-failed-dependency+ #:+http-forbidden+ #:+http-gateway-time-out+ #:+http-gone+ #:+http-internal-server-error+ #:+http-length-required+ #:+http-method-not-allowed+ #:+http-moved-permanently+ #:+http-moved-temporarily+ #:+http-multi-status+ #:+http-multiple-choices+ #:+http-network-authentication-required+ #:+http-no-content+ #:+http-non-authoritative-information+ #:+http-not-acceptable+ #:+http-not-found+ #:+http-not-implemented+ #:+http-not-modified+ #:+http-ok+ #:+http-partial-content+ #:+http-payment-required+ #:+http-precondition-failed+ #:+http-precondition-required+ #:+http-proxy-authentication-required+ #:+http-request-entity-too-large+ #:+http-request-header-fields-too-large+ #:+http-request-time-out+ #:+http-request-uri-too-large+ #:+http-requested-range-not-satisfiable+ #:+http-reset-content+ #:+http-see-other+ #:+http-service-unavailable+ #:+http-switching-protocols+ #:+http-temporary-redirect+ #:+http-too-many-requests+ #:+http-unsupported-media-type+ #:+http-use-proxy+ #:+http-version-not-supported+ #:abort-request-handler #:accept-connections #:acceptor #:acceptor-access-log-destination #:acceptor-address #:acceptor-listen-backlog #:acceptor-dispatch-request #:acceptor-error-template-directory #:acceptor-input-chunking-p #:acceptor-log-access #:acceptor-log-message #:acceptor-message-log-destination #:acceptor-name #:acceptor-output-chunking-p #:acceptor-persistent-connections-p #:acceptor-port #:acceptor-read-timeout #:acceptor-remove-session #:acceptor-reply-class #:acceptor-request-class #:acceptor-ssl-p #-:hunchentoot-no-ssl #:acceptor-ssl-certificate-file #-:hunchentoot-no-ssl #:acceptor-ssl-privatekey-file #-:hunchentoot-no-ssl #:acceptor-ssl-privatekey-password #:acceptor-status-message #:acceptor-write-timeout #:acceptor-document-root #:acceptor-error-template-directory #:authorization #:aux-request-value #:client-as-string #:content-length #:content-length* #:content-type #:content-type* #:cookie-domain #:cookie-expires #:cookie-http-only #:cookie-in #:cookie-max-age #:cookie-name #:cookie-out #:cookie-path #:cookie-secure #:cookie-value #:cookies-in #:cookies-in* #:cookies-out #:cookies-out* #:create-folder-dispatcher-and-handler #:create-prefix-dispatcher #:create-regex-dispatcher #:create-request-handler-thread #:create-static-file-dispatcher-and-handler #:decrement-taskmaster-thread-count #:default-document-directory #:define-easy-handler #:delete-aux-request-value #:delete-session-value #:dispatch-easy-handlers #:easy-acceptor #-:hunchentoot-no-ssl #:easy-ssl-acceptor #:escape-for-html #:execute-acceptor #:get-parameter #:get-parameters #:get-parameters* #:handle-incoming-connection #:handle-if-modified-since #:handle-request #:handle-static-file #:header-in #:header-in* #:header-out #:headers-in #:headers-in* #:headers-out #:headers-out* #:host #:http-token-p #:hunchentoot-condition #:hunchentoot-error #:hunchentoot-warning #:increment-taskmaster-thread-count #:initialize-connection-stream #:log-message* #:maybe-invoke-debugger #:mime-type #:multi-threaded-taskmaster #:next-session-id #:no-cache #:one-thread-per-connection-taskmaster #:parameter #:parameter-error #:post-parameter #:post-parameters #:post-parameters* #:process-connection #:process-request #:query-string #:query-string* #:raw-post-data #:real-remote-addr #:reason-phrase #:recompute-request-parameters #:redirect #:referer #:regenerate-session-cookie-value #:remote-addr #:remote-addr* #:remote-port #:remote-port* #:local-addr #:local-addr* #:local-port #:local-port* #:remove-session #:reply #:reply-external-format #:reply-external-format* #:request #:request-acceptor #:request-method #:request-method* #:request-pathname #:request-uri #:request-uri* #:require-authorization #:reset-connection-stream #:reset-sessions #:reset-session-secret #:return-code #:return-code* #:rfc-1123-date #:script-name #:script-name* #:send-headers #:server-protocol #:server-protocol* #:session #:session-cookie-name #:session-cookie-value #:session-created #:session-db #:session-db-lock #:session-gc #:session-id #:session-max-time #:session-remote-addr #:session-start #:session-too-old-p #:session-user-agent #:session-value #:session-verify #:set-cookie #:set-cookie* #:shutdown #:single-threaded-taskmaster #-:hunchentoot-no-ssl #:ssl-acceptor #:ssl-p #:start #:start-listening #:start-session #:start-thread #:started-p #:stop #:taskmaster #:taskmaster-acceptor #:taskmaster-max-accept-count #:taskmaster-max-thread-count #:taskmaster-thread-count #:too-many-taskmaster-requests #:url-decode #:url-encode #:user-agent #:within-request-p #:detach-socket #:bad-request)) hunchentoot-1.2.35/session.lisp 0000644 0000041 0000041 00000041116 12656661410 016556 0 ustar www-data www-data ;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: HUNCHENTOOT; Base: 10 -*- ;;; Copyright (c) 2004-2010, Dr. Edmund Weitz. All rights reserved. ;;; Redistribution and use in source and binary forms, with or without ;;; modification, are permitted provided that the following conditions ;;; are met: ;;; * Redistributions of source code must retain the above copyright ;;; notice, this list of conditions and the following disclaimer. ;;; * Redistributions in binary form must reproduce the above ;;; copyright notice, this list of conditions and the following ;;; disclaimer in the documentation and/or other materials ;;; provided with the distribution. ;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED ;;; OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ;;; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ;;; ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ;;; DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ;;; DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE ;;; GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ;;; INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, ;;; WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING ;;; NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ;;; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. (in-package :hunchentoot) (defgeneric session-db-lock (acceptor &key whole-db-p) (:documentation "A function which returns a lock that will be used to prevent concurrent access to sessions. The first argument will be the acceptor that handles the current request, the second argument is true if the whole \(current) session database is modified. If it is NIL, only one existing session in the database is modified. This function can return NIL which means that sessions or session databases will be modified without a lock held \(for example for single-threaded environments). The default is to always return a global lock \(ignoring the ACCEPTOR argument) for Lisps that support threads and NIL otherwise.")) (defmethod session-db-lock ((acceptor t) &key (whole-db-p t)) (declare (ignore whole-db-p)) *global-session-db-lock*) (defmacro with-session-lock-held ((lock) &body body) "This is like WITH-LOCK-HELD except that it will accept NIL as a \"lock\" and just execute BODY in this case." (with-unique-names (thunk) (with-rebinding (lock) `(flet ((,thunk () ,@body)) (cond (,lock (with-lock-held (,lock) (,thunk))) (t (,thunk))))))) (defgeneric session-db (acceptor) (:documentation "Returns the current session database which is an alist where each car is a session's ID and the cdr is the corresponding SESSION object itself. The default is to use a global list for all acceptors.")) (defmethod session-db ((acceptor t)) *session-db*) (defgeneric (setf session-db) (new-value acceptor) (:documentation "Modifies the current session database. See SESSION-DB.")) (defmethod (setf session-db) (new-value (acceptor t)) (setq *session-db* new-value)) (defgeneric next-session-id (acceptor) (:documentation "Returns the next sequential session ID, an integer, which should be unique per session. The default method uses a simple global counter and isn't guarded by a lock. For a high-performance production environment you might consider using a more robust implementation.")) (let ((session-id-counter 0)) (defmethod next-session-id ((acceptor t)) (incf session-id-counter))) (defclass session () ((session-id :initform (next-session-id (request-acceptor *request*)) :reader session-id :type integer :documentation "The unique ID \(an INTEGER) of the session.") (session-string :reader session-string :documentation "The session string encodes enough data to safely retrieve this session. It is sent to the browser as a cookie value or as a GET parameter.") (user-agent :initform (user-agent *request*) :reader session-user-agent :documentation "The incoming 'User-Agent' header that was sent when this session was created.") (remote-addr :initform (real-remote-addr *request*) :reader session-remote-addr :documentation "The remote IP address of the client when this session was started as returned by REAL-REMOTE-ADDR.") (session-start :initform (get-universal-time) :reader session-start :documentation "The time this session was started.") (last-click :initform (get-universal-time) :reader session-last-click :documentation "The last time this session was used.") (session-data :initarg :session-data :initform nil :reader session-data :documentation "Data associated with this session - see SESSION-VALUE.") (max-time :initarg :max-time :initform *session-max-time* :accessor session-max-time :type fixnum :documentation "The time \(in seconds) after which this session expires if it's not used.")) (:documentation "SESSION objects are automatically maintained by Hunchentoot. They should not be created explicitly with MAKE-INSTANCE but implicitly with START-SESSION and they should be treated as opaque objects. You can ignore Hunchentoot's SESSION objects altogether and implement your own sessions if you provide corresponding methods for SESSION-COOKIE-VALUE and SESSION-VERIFY.")) (defun encode-session-string (id user-agent remote-addr start) "Creates a uniquely encoded session string based on the values ID, USER-AGENT, REMOTE-ADDR, and START" (unless (boundp '*session-secret*) (hunchentoot-warn "Session secret is unbound. Using Lisp's RANDOM function to initialize it.") (reset-session-secret)) ;; *SESSION-SECRET* is used twice due to known theoretical ;; vulnerabilities of MD5 encoding (md5-hex (concatenate 'string *session-secret* (md5-hex (format nil "~A~A~@[~A~]~@[~A~]~A" *session-secret* id (and *use-user-agent-for-sessions* user-agent) (and *use-remote-addr-for-sessions* remote-addr) start))))) (defun stringify-session (session) "Creates a string representing the SESSION object SESSION. See ENCODE-SESSION-STRING." (encode-session-string (session-id session) (session-user-agent session) (session-remote-addr session) (session-start session))) (defmethod initialize-instance :after ((session session) &rest init-args) "Set SESSION-STRING slot after the session has been initialized." (declare (ignore init-args)) (setf (slot-value session 'session-string) (stringify-session session))) (defun session-gc () "Removes sessions from the current session database which are too old - see SESSION-TOO-OLD-P." (with-session-lock-held ((session-db-lock *acceptor*)) (setf (session-db *acceptor*) (loop for id-session-pair in (session-db *acceptor*) for (nil . session) = id-session-pair when (session-too-old-p session) do (acceptor-remove-session *acceptor* session) else collect id-session-pair))) (values)) (defun session-value (symbol &optional (session *session*)) "Returns the value associated with SYMBOL from the session object SESSION \(the default is the current session) if it exists." (when session (let ((found (assoc symbol (session-data session) :test #'eq))) (values (cdr found) found)))) (defsetf session-value (symbol &optional session) (new-value) "Sets the value associated with SYMBOL from the session object SESSION. If there is already a value associated with SYMBOL it will be replaced. Will automatically start a session if none was supplied and there's no session for the current request." (with-rebinding (symbol) (with-unique-names (place %session) `(let ((,%session (or ,session (start-session)))) (with-session-lock-held ((session-db-lock *acceptor* :whole-db-p nil)) (let* ((,place (assoc ,symbol (session-data ,%session) :test #'eq))) (cond (,place (setf (cdr ,place) ,new-value)) (t (push (cons ,symbol ,new-value) (slot-value ,%session 'session-data)) ,new-value)))))))) (defun delete-session-value (symbol &optional (session *session*)) "Removes the value associated with SYMBOL from SESSION if there is one." (when session (setf (slot-value session 'session-data) (delete symbol (session-data session) :key #'car :test #'eq))) (values)) (defgeneric session-cookie-value (session) (:documentation "Returns a string which can be used to safely restore the session SESSION if as session has already been established. This is used as the value stored in the session cookie or in the corresponding GET parameter and verified by SESSION-VERIFY. A default method is provided and there's no reason to change it unless you want to use your own session objects.")) (defmethod session-cookie-value ((session session)) (and session (format nil "~D:~A" (session-id session) (session-string session)))) (defgeneric session-cookie-name (acceptor) (:documentation "Returns the name \(a string) of the cookie \(or the GET parameter) which is used to store a session on the client side. The default is to use the string \"hunchentoot-session\", but you can specialize this function if you want another name.")) (defmethod session-cookie-name ((acceptor t)) "hunchentoot-session") (defgeneric session-created (acceptor new-session) (:documentation "This function is called whenever a new session has been created. There's a default method which might trigger a session GC based on the value of *SESSION-GC-FREQUENCY*. The return value is ignored.")) (let ((global-session-usage-counter 0)) (defmethod session-created ((acceptor t) (session t)) "Counts session usage globally and triggers session GC if necessary." (when (and *session-gc-frequency* (zerop (mod (incf global-session-usage-counter) *session-gc-frequency*))) (session-gc)))) (defun start-session () "Returns the current SESSION object. If there is no current session, creates one and updates the corresponding data structures. In this case the function will also send a session cookie to the browser." (let ((session (session *request*))) (when session (return-from start-session session)) (setf session (make-instance 'session) (session *request*) session) (with-session-lock-held ((session-db-lock *acceptor*)) (setf (session-db *acceptor*) (acons (session-id session) session (session-db *acceptor*)))) (set-cookie (session-cookie-name *acceptor*) :value (session-cookie-value session) :path "/" :http-only t) (session-created *acceptor* session) (setq *session* session))) (defun remove-session (session) "Completely removes the SESSION object SESSION from Hunchentoot's internal session database." (set-cookie (session-cookie-name *acceptor*) :value "deleted" :path "/" :expires 0) (with-session-lock-held ((session-db-lock *acceptor*)) (acceptor-remove-session *acceptor* session) (setf (session-db *acceptor*) (delete (session-id session) (session-db *acceptor*) :key #'car :test #'=))) (values)) (defun session-too-old-p (session) "Returns true if the SESSION object SESSION has not been active in the last \(SESSION-MAX-TIME SESSION) seconds." (< (+ (session-last-click session) (session-max-time session)) (get-universal-time))) (defun get-stored-session (id) "Returns the SESSION object corresponding to the number ID if the session has not expired. Will remove the session if it has expired but will not create a new one." (let ((session (cdr (assoc id (session-db *acceptor*) :test #'=)))) (when (and session (session-too-old-p session)) (when *reply* (log-message* :info "Session with ID ~A too old" id)) (remove-session session) (setq session nil)) session)) (defun regenerate-session-cookie-value (session) "Regenerates the cookie value. This should be used when a user logs in according to the application to prevent against session fixation attacks. The cookie value being dependent on ID, USER-AGENT, REMOTE-ADDR, START, and *SESSION-SECRET*, the only value we can change is START to regenerate a new value. Since we're generating a new cookie, it makes sense to have the session being restarted, in time. That said, because of this fact, calling this function twice in the same second will regenerate twice the same value." (setf (slot-value session 'session-start) (get-universal-time) (slot-value session 'session-string) (stringify-session session)) (set-cookie (session-cookie-name *acceptor*) :value (session-cookie-value session) :path "/" :http-only t)) (defgeneric session-verify (request) (:documentation "Tries to get a session identifier from the cookies \(or alternatively from the GET parameters) sent by the client (see SESSION-COOKIE-NAME and SESSION-COOKIE-VALUE). This identifier is then checked for validity against the REQUEST object REQUEST. On success the corresponding session object \(if not too old) is returned \(and updated). Otherwise NIL is returned. A default method is provided and you only need to write your own one if you want to maintain your own sessions.")) (defmethod session-verify ((request request)) (let ((session-identifier (or (when-let (session-cookie (cookie-in (session-cookie-name *acceptor*) request)) (url-decode session-cookie)) (get-parameter (session-cookie-name *acceptor*) request)))) (when (and (stringp session-identifier) (scan "^\\d+:.+" session-identifier)) (destructuring-bind (id-string session-string) (split ":" session-identifier :limit 2) (let* ((id (parse-integer id-string)) (session (get-stored-session id)) (user-agent (user-agent request)) (remote-addr (remote-addr request))) (cond ((and session (string= session-string (session-string session)) (string= session-string (encode-session-string id user-agent (real-remote-addr request) (session-start session)))) ;; the session key presented by the client is valid (setf (slot-value session 'last-click) (get-universal-time)) session) (session ;; the session ID pointed to an existing session, but the ;; session string did not match the expected session string (log-message* :warning "Fake session identifier '~A' (User-Agent: '~A', IP: '~A')" session-identifier user-agent remote-addr) ;; remove the session to make sure that it can't be used ;; again; the original legitimate user will be required to ;; log in again (remove-session session) nil) (t ;; no session was found under the ID given, presumably ;; because it has expired. (log-message* :info "No session for session identifier '~A' (User-Agent: '~A', IP: '~A')" session-identifier user-agent remote-addr) nil))))))) (defun reset-session-secret () "Sets *SESSION-SECRET* to a new random value. All old sessions will cease to be valid." (setq *session-secret* (create-random-string 10 36))) (defun reset-sessions (&optional (acceptor *acceptor*)) "Removes ALL stored sessions of ACCEPTOR." (with-session-lock-held ((session-db-lock acceptor)) (loop for (nil . session) in (session-db acceptor) do (acceptor-remove-session acceptor session)) (setq *session-db* nil)) (values)) hunchentoot-1.2.35/doc/ 0000755 0000041 0000041 00000000000 12656661410 014744 5 ustar www-data www-data hunchentoot-1.2.35/doc/hunchentoot.gif 0000644 0000041 0000041 00000000752 12656661410 017775 0 ustar www-data www-data GIF89a] - � ���������!�$Created with The GIMP by Uwe von Loh !� , ] - ������/���ڋ�� ��p]����� ǀ�J���������F���DΒRi3�8��ӊ6'iY�.�W4�UĘ�_��ţ.�-��r6�c��6Xh���3�w�x����X��(xf�yɕ��)���4��IH�%��8�z [+S갸i�ۖ��6|��J�,\'�L[K�,��=�JZ����;��w`F��6.Hέi}͎�;_el�� ���o�s��cvMt�Q�=���ѕ��(��r�1]�O$��X�d����!�xQe�������w`���dʜ�vƬ8(�C?w��4z�"%�D�� �^M������kAsZ+v5�R"K�j-� 6N�cL�B�45gӤ��=���[ �ڈ�[�����s��.ir\�r4 ; hunchentoot-1.2.35/doc/Makefile 0000644 0000041 0000041 00000000247 12656661410 016407 0 ustar www-data www-data all: xsltproc --stringparam library-version `perl -ne 'print "$$1\n" if (/:version "(.*)"/)' ../hunchentoot.asd` clixdoc.xsl index.xml > ../www/hunchentoot-doc.html hunchentoot-1.2.35/doc/clixdoc.xsl 0000644 0000041 0000041 00000041135 12656661410 017125 0 ustar www-data www-data
(setf (
(setf (
Hunchentoot is a web server written in Common Lisp and at the same time a toolkit for building dynamic websites. As a stand-alone web server, Hunchentoot is capable of HTTP/1.1 chunking (both directions), persistent connections (keep-alive), and SSL.
Hunchentoot provides facilities like automatic session handling (with and without cookies), logging, customizable error handling, and easy access to GET and POST parameters sent by the client. It does not include functionality to programmatically generate HTML output. For this task you can use any library you like, e.g. (shameless self-plug) CL-WHO or HTML-TEMPLATE.
Hunchentoot talks with its front-end or with the client over TCP/IP sockets and optionally uses multiprocessing to handle several requests at the same time. Therefore, it cannot be implemented completely in portable Common Lisp. It currently works with LispWorks and all Lisps which are supported by the compatibility layers usocket and Bordeaux Threads.
Hunchentoot comes with a BSD-style license so you can basically do with it whatever you want.
Hunchentoot is (or was) for example used by QuickHoney, City Farming, Heike Stephan.
Download shortcut: http://weitz.de/files/hunchentoot.tar.gz.
:HUNCHENTOOT-NO-SSL to
*FEATURES* before you compile it.
Hunchentoot will only work with Lisps where the character codes of all Latin-1 characters coincide with their Unicode code points (which is the case for all current implementations I know).
Hunchentoot itself together with this documentation can be
downloaded from
The current version is
The preferred method to compile and load Hunchentoot is via ASDF. If you want to avoid downloading and installing all the dependencies manually, give Zach Beane's excellent Quicklisp system a try.
Hunchentoot and its dependencies can also be installed with clbuild. There's also a port for Gentoo Linux thanks to Matthew Kennedy.
The current development version of Hunchentoot can be found at https://github.com/edicl/hunchentoot. If you want to send patches, please fork the github repository and send pull requests.
ProxyPass /hunchentoot http://127.0.0.1:3000/hunchentoot ProxyPassReverse /hunchentoot http://127.0.0.1:3000/hunchentootThis will tunnel all requests where the URI path begins with
"/hunchentoot" to a (Hunchentoot) server listening on
port�3000 on the same machine.
Of course, there are several other (more lightweight) web proxies that you could use instead of Apache.
The development version of Hunchentoot can be found on github. Please use the github issue tracking system to submit bug reports. Patches are welcome, please use GitHub pull requests. If you want to make a change, please read this first.
(hunchentoot:start (make-instance 'hunchentoot:easy-acceptor :port 4242))That's it. Now you should be able to enter the address "
http://127.0.0.1:4242/" in
your browser and see something, albeit nothing very interesting
for now.
By default, Hunchentoot serves the files from the
www/ directory in its source tree. In the
distribution, that directory contains a HTML version of the
documentation as well as the error templates. The location of
the document root directory can be specified when creating a new
ACCEPTOR instance by the way of the
ACCEPTOR-DOCUMENT-ROOT. Likewise, the
location of the error template directory can be specified by the
ACCEPTOR-ERROR-TEMPLATE-DIRECTORY. Both
ACCEPTOR-DOCUMENT-ROOT and
ACCEPTOR-ERROR-TEMPLATE-DIRECTORY can be
specified using a logical pathname, which will be translated
once when the ACCEPTOR is instantiated.
The EASY-ACCEPTOR class implements a framework for developing web applications. Handlers are defined using the DEFINE-EASY-HANDLER macro. Request dispatching is performed according to the list of dispatch functions in *DISPATCH-TABLE*. Each of the functions on that list is called to determine whether it wants to handle the request, provided as single argument. If a dispatcher function wants to handle the request, it returns another function to actually create the desired page.
DEFINE-EASY-HANDLER is accompanied by a set of dispatcher creation functions that can be used to create dispatchers for standard tasks. These are documented in the subchapter on easy handlers
Now be a bit more adventurous, try this
(hunchentoot:define-easy-handler (say-yo :uri "/yo") (name) (setf (hunchentoot:content-type*) "text/plain") (format nil "Hey~@[ ~A~]!" name))and see what happens at "
http://127.0.0.1:4242/yo" or
http://127.0.0.1:4242/yo?name=Dude" .
Hunchentoot comes with a little example website which you can use to see if it works and which should also demonstrate a couple of the things you can do with Hunchentoot. To start the example website, enter the following code into your listener:
(asdf:oos 'asdf:load-op :hunchentoot-test)Now go to "
http://127.0.0.1:4242/hunchentoot/test" and play a bit.
Adam Petersen has written a book called "Lisp for the Web" which explains how Hunchentoot and some other libraries can be used to build web sites.
Here is some software which extends Hunchentoot or is based on it:
:port initarg if you don't want to listen
on the default http port 80. There are other initargs most
of which you probably won't need very often. They are
explained in detail in the docstrings of the slot
definitions for this class.
Unless you are in a Lisp without MP capabilities, you can have several active instances of ACCEPTOR (listening on different ports) at the same time.
:SSL-CERTIFICATE-FILE and
:SSL-PRIVATEKEY-FILE, for
pathname designators denoting the certificate file and the key file in
PEM format. On LispWorks, you can have both in one file in which case
the second initarg is optional. You can also use the
:SSL-PRIVATEKEY-PASSWORD initarg to provide a password
(as a string) for the key file (or
NIL, the default, for
no password).
The default port for SSL-ACCEPTOR instances is 443 instead of 80
NIL and
subclasses of ACCEPTOR must specialize this method to signal that
they're using secure connections - see the SSL-ACCEPTOR class.
If you just want to use the standard acceptors that come with Hunchentoot, you don't need to know anything about the functions listed in this section.
Handlers may call to the DETACH-SOCKET generic function to indicate that no further requests should be handled on the connection by Hunchentoot, and that responsibility for the socket is assumed by third-party software. This can be used by specialized handlers that wish to hand over connection polling or processing to functions outside of Hunchentoot, i.e. for connection multiplexing or implementing specialized client protocols. Hunchentoot will finish processing the request and the PROCESS-CONNECTION function will return without closing the connection. At that point, the acceptor may interact with the socket in whatever fashion required.
(asdf:load-system "hunchentoot") (asdf:load-system "drakma") ;;; Subclass ACCEPTOR (defclass vhost (tbnl:acceptor) ;; slots ((dispatch-table :initform '() :accessor dispatch-table :documentation "List of dispatch functions")) ;; options (:default-initargs ; default-initargs must be used :address "127.0.0.1")) ; because ACCEPTOR uses it ;;; Specialise ACCEPTOR-DISPATCH-REQUEST for VHOSTs (defmethod tbnl:acceptor-dispatch-request ((vhost vhost) request) ;; try REQUEST on each dispatcher in turn (mapc (lambda (dispatcher) (let ((handler (funcall dispatcher request))) (when handler ; Handler found. FUNCALL it and return result (return-from tbnl:acceptor-dispatch-request (funcall handler))))) (dispatch-table vhost)) (call-next-method)) ;;; ====================================================================== ;;; Now all we need to do is test it ;;; Instantiate VHOSTs (defvar vhost1 (make-instance 'vhost :port 50001)) (defvar vhost2 (make-instance 'vhost :port 50002)) ;;; Populate each dispatch table (push (tbnl:create-prefix-dispatcher "/foo" 'foo1) (dispatch-table vhost1)) (push (tbnl:create-prefix-dispatcher "/foo" 'foo2) (dispatch-table vhost2)) ;;; Define handlers (defun foo1 () "Hello") (defun foo2 () "Goodbye") ;;; Start VHOSTs (tbnl:start vhost1) (tbnl:start vhost2) ;;; Make some requests (drakma:http-request "http://127.0.0.1:50001/foo") ;;; =| ;;; 127.0.0.1 - [2012-06-08 14:30:39] "GET /foo HTTP/1.1" 200 5 "-" "Drakma/1.2.6 (SBCL 1.0.56; Linux; 2.6.32-5-686; http://weitz.de/drakma/)" ;;; => ;;; "Hello" ;;; 200 ;;; ((:CONTENT-LENGTH . "5") (:DATE . "Fri, 08 Jun 2012 14:30:39 GMT") ;;; (:SERVER . "Hunchentoot 1.2.3") (:CONNECTION . "Close") ;;; (:CONTENT-TYPE . "text/html; charset=utf-8")) ;;; #<PURI:URI http://127.0.0.1:50001/foo> ;;; #<FLEXI-STREAMS:FLEXI-IO-STREAM {CA90059}> ;;; T ;;; "OK" (drakma:http-request "http://127.0.0.1:50002/foo") ;;; =| ;;; 127.0.0.1 - [2012-06-08 14:30:47] "GET /foo HTTP/1.1" 200 7 "-" "Drakma/1.2.6 (SBCL 1.0.56; Linux; 2.6.32-5-686; http://weitz.de/drakma/)" ;;; => ;;; "Goodbye" ;;; 200 ;;; ((:CONTENT-LENGTH . "7") (:DATE . "Fri, 08 Jun 2012 14:30:47 GMT") ;;; (:SERVER . "Hunchentoot 1.2.3") (:CONNECTION . "Close") ;;; (:CONTENT-TYPE . "text/html; charset=utf-8")) ;;; #<PURI:URI http://127.0.0.1:50002/foo> ;;; #<FLEXI-STREAMS:FLEXI-IO-STREAM {CAE8059}> ;;; T ;;; "OK"How to make each VHOST write to separate access log streams (or files) is left as an exercise to the reader.
You can control the resources consumed by a threaded taskmaster via
two initargs.
:max-thread-count lets you set the maximum
number of request threads that can be processes simultaneously. If
this is
nil, the is no thread limit imposed.
:max-accept-count lets you set the maximum number of requests
that can be outstanding (i.e. being processed or queued for processing).
:max-thread-count is supplied and
NIL, then a +HTTP-SERVICE-UNAVAILABLE+
error will be generated if there are more than the max-thread-count
threads processing requests. If both
:max-accept-count are supplied, then max-thread-count
must be less than max-accept-count; if more than max-thread-count
requests are being processed, then requests up to max-accept-count
will be queued until a thread becomes available. If more than
max-accept-count requests are outstanding, then a +HTTP-SERVICE-UNAVAILABLE+
error will be generated.
In a load-balanced environment with multiple Hunchentoot servers, it's
reasonable to provide
:max-thread-count but leave
:max-accept-count null. This will immediately result
in +HTTP-SERVICE-UNAVAILABLE+ when one server is
out of resources, so the load balancer can try to find another server.
In an environment with a single Hunchentoot server, it's reasonable
to provide both
:max-thread-count and a somewhat larger value
:max-accept-count. This will cause a server that's almost
out of resources to wait a bit; if the server is completely out of resources,
then the reply will be +HTTP-SERVICE-UNAVAILABLE+.
The default for these values is 100 and 120, respectively.
If you want to implement your own taskmasters, you should subclass TASKMASTER or one of its subclasses, SINGLE-THREADED-TASKMASTER or ONE-THREAD-PER-CONNECTION-TASKMASTER, and specialize the generic functions in this section.
This is the default taskmaster implementation for multi-threaded Lisp implementations.
This is the simplest possible taskmaster implementation in that its
methods do nothing but calling their acceptor "sister"
methods - EXECUTE-ACCEPTOR calls ACCEPT-CONNECTIONS,
HANDLE-INCOMING-CONNECTION calls PROCESS-CONNECTION.
Instead, you should instantiate its subclass
ONE-THREAD-PER-CONNECTION-TASKMASTER described above.
is intended to be inherited from by extensions to Hunchentoot,
such as quux-hunchentoot's
though at the moment, doing so only inherits one slot and one method,
on EXECUTE-ACCEPTOR,
to have it start a new thread for the acceptor,
then saved in said slot.
(defmethod create-request-handler-thread ((taskmaster monitor-taskmaster) socket) (bt:make-thread (lambda () (with-monitor-error-handlers (unwind-protect (with-monitor-variable-bindings (process-connection (taskmaster-acceptor taskmaster) socket)) (decrement-taskmaster-request-count taskmaster))))))
The ACCEPTOR class defines a ACCEPTOR-DISPATCH-REQUEST generic function which is used to actually dispatch the request. This function is called by the default method of HANDLE-REQUEST. Each ACCEPTOR-DISPATCH-REQUEST method looks at the request object and depending on its contents decides to either handle the request or call the next method.
In order to dispatch a request, Hunchentoot calls the ACCEPTOR-DISPATCH-REQUEST generic functions. The method for ACCEPTOR tries to serve a static file relative to it's ACCEPTOR-DOCUMENT-ROOT. Application specific acceptor subclasses will typically perform URL parsing and dispatching according to the policy that is required.
The default method of HANDLE-REQUEST sets up standard logging and error handling before it calls the acceptor's request dispatcher.
Request handlers do their work by modifying the reply object if necessary and by eventually returning the response body in the form of a string or a binary sequence. As an alternative, they can also call SEND-HEADERS and write directly to a stream.
The EASY-ACCEPTOR class defines a method
for ACCEPTOR-DISPATCH-REQUEST that walks
through the list *DISPATCH-TABLE* which
consists of dispatch functions. Each of these
functions accepts the request object as its only argument and
either returns a request handler to handle the request or
NIL which means that the next dispatcher in the
list will be tried. If all dispatch functions return
NIL, the next
ACCEPTOR-DISPATCH-REQUEST will be called.
All functions and variables in this section are related to the easy request dispatch mechanism and are meaningless if you're using your own request dispatcher.
NIL, it will be used as a the content type for
all files in the folder. Otherwise (which is the default)
the content type of each file will be
determined as usual.
DEFUN and optionally registers it with a
URI so that it will be found
by DISPATCH-EASY-HANDLERS.
(name &key uri acceptor-names default-parameter-type default-request-type).
(var &key real-name parameter-type init-form request-type).The resulting handler will be a Lisp function with the name
object returns a true value.
T which means that the handler will be
returned by DISPATCH-EASY-HANDLERS
in every acceptor.
Whether the GET or POST parameter (or both) will be taken into
consideration, depends on
NIL. In the last case, the value of
:BOTH) will be used.
The value of
If the corresponding GET or POST parameter wasn't provided by
the client,
NIL. If
and the parameter string consists solely of decimal
'CHARACTER and the parameter string is of
length one,
T (unless it is
NIL by the
first rule above, of course).
Those were the rules for simple parameter types, but
HASH-TABLE. The second value of the list must
always be a simple parameter type as in the last paragraph -
we'll call it the inner type below.
In the case of
'LIST, all GET/POST parameters
In the case of
'ARRAY, all GET/POST parameters
which have a name like the result of
(format nil "~A[~A]" real-name n)where
NIL. Note
VAR will always be bound to an array, which
may be empty, so it will never be
NIL, even if no
appropriate GET/POST parameters are found.
The full form of a
'HASH-TABLE parameter type is
(hash-table inner-type key-type test-function)but
'EQUAL, respectively. For this parameter type,
all GET/POST parameters which have a name like the result of
(format nil "~A{~A}" real-name key)(where
even if no appropriate GET/POST parameters are found.
To make matters even more complicated, the three compound
parameter types also have an abbreviated form - just one of
the symbols
HASH-TABLE. In this case, the inner type will
default to
'STRING) will be used
If the result of the computations above would be
NIL, then
Handlers built with this macro are constructed in such a way
that the resulting Lisp function is useful even outside of
Hunchentoot. Specifically, all the parameter computations
above will only happen if *REQUEST* is
bound, i.e. if we're within a Hunchentoot request.
The example code that comes with Hunchentoot contains an example which demonstrates some of the features of DEFINE-EASY-HANDLER.
If you need more fine-grained control over the behaviour of request
objects, you can subclass REQUEST and initialize
slot of the ACCEPTOR class accordingly. The
acceptor will generate request objects of the class named by this
slot of the ACCEPTOR class.
X-Forwarded-For' incoming http header as the
second value in the form of a list of IP addresses and the first
element of this list as the first value if this header exists.
Otherwise returns the value of REMOTE-ADDR as the only value.
if there is none. If both a GET and a POST parameter with
the same name exist the GET parameter is returned. Search
is case-sensitive. See also
GET-PARAMETER and
NIL if there ain't no GET parameter
with this name). Note that only the first value will be
returned if the client provided more than one GET parameter
with the name
NIL if there ain't
no POST parameter with this name). If, however, the browser
sent a file through
form, the value of this function is a three-element list
(path file-name content-type)where
POST parameters will only be computed if the content type of
the request body was
application/x-www-form-urlencoded. Although
this function is called
POST-PARAMETER, you can
instruct Hunchentoot to compute these parameters for other
request methods by
setting *METHODS-FOR-POST-PARAMETERS*.
See also POST-PARAMETERS and *TMP-DIRECTORY*.
See also POST-PARAMETER.
NIL if there is none.
NIL if there is no such header.
NIL, it should be a unary
function which will be called with a pathname for each file
which is uploaded to Hunchentoot. The
pathname denotes the temporary file to which the uploaded
file is written. The hook is called directly before the
file is created. At this point,
*REQUEST* is already bound to the
current REQUEST object, but obviously
you can't access the post parameters yet.
multipart/form-data in which
NIL is returned). By default, the result is
a string if the type of the
media type
"text", and a vector of octets otherwise. In
the case of a string, the external format to be used to decode
the content will be determined from the
parameter sent by the client (or
otherwise *HUNCHENTOOT-DEFAULT-EXTERNAL-FORMAT*
will be used).
You can also provide an external format explicitly (through
If, however, you provide a true value
0. If the client provided
Content-Length header, the stream will also
have a
corresponding bound,
so no matter whether the client used chunked encoding or
not, you can always read until EOF.
If the content type of the request
application/x-www-form-urlencoded, the
content has been read by Hunchentoot already and you can't
read from the stream anymore.
You can call RAW-POST-DATA more than once
per request, but you can't mix calls which have different
values for
Note that this function is slightly misnamed because a client can send content even if the request method is not POST.
The return value of this function is ignored.
Like PROCESS-CONNECTION, this is another function the behaviour of which you should only modify if you really, really know what you're doing.
The default method calls the acceptor's request dispatcher, but you can of course implement a different behaviour. The default method also sets up standard error handling for the handler.
Might be a good place to bind or rebind special variables which can then be accessed by your handlers.
If you need more fine-grained control over the behaviour of reply
objects, you can subclass REPLY and initialize
slot of the ACCEPTOR class accordingly. The
acceptor will generate reply objects of the class named by this
You should not mess with the slots of these objects directly, but you
can subclass REPLY in order to implement your own behaviour. See the
:reply-class initarg
of the ACCEPTOR class.
of HEADER-OUT changes the current value
of the header named
Note that the header 'Set-Cookie' cannot be queried by
HEADER-OUT and must not be set by
SETF of HEADER-OUT. See
also HEADERS-OUT*,
COOKIES-OUT*, and
If your handlers return the full body as a string or as an array of octets, you should not call this function. If a handler calls SEND-HEADERS , its return value is ignored.
Hunchentoot makes some reasonable effort to prevent eavesdroppers from hijacking sessions (see below), but this should not be considered really secure. Don't store sensitive data in sessions and rely solely on the session mechanism as a safeguard against malicious users who want to get at this data!
For each request there's one SESSION object which is accessible to the handler via the special variable *SESSION*. This object holds all the information available about the session and can be accessed with the functions described in this chapter. Note that the internal structure of SESSION objects should be considered opaque and may change in future releases of Hunchentoot.
Sessions are automatically verified for validity and age when the REQUEST object is instantiated, i.e. if *SESSION* is not NIL then this session is valid (as far as Hunchentoot is concerned) and not too old. Old sessions are automatically removed.
Hunchentoot also provides a SESSION-REGENERATE-COOKIE-VALUE function that creates a new cookie value. This helps to prevent against session fixation attacks, and should be used when a user logs in according to the application.
MAKE-INSTANCE but implicitly
with START-SESSION and they should be treated as
opaque objects.
You can ignore Hunchentoot's SESSION objects and implement your own sessions if you provide corresponding methods for SESSION-COOKIE-VALUE and SESSION-VERIFY.
NIL. The default
value for
SETF of SESSION-VALUE is called
NIL then a
session is automatically instantiated
with START-SESSION.
This might for example be an issue if the client uses a proxy server which doesn't send correct 'X-Forwarded-For' headers.
NIL. See SESSION-CREATED.
(session-max-time�session) seconds.
One way is to mostly leave the session mechanism intact but to tweak it a bit:
The other way to customize Hunchentoot's sessions is to completely replace them. This is actually pretty easy: Create your own class to store state (which doesn't have to and probably shouldn't inherit from SESSION) and implement methods for SESSION-VERIFY and SESSION-COOKIE-VALUE - that's it. Hunchentoot will continue to use cookies and/or to rewrite URLs to keep track of session state and it will store "the current session" (whatever that is in your implementation) in *SESSION*. Everything else (like persisting sessions, GC, getting and setting values) you'll have to take care of yourself and the other session functions (like START-SESSION or SESSION-VALUE) won't work anymore. (Almost) total freedom, but a lot of responsibility as well... :)
"hunchentoot-session", but you can
specialize this function if you want another name.
The return value is ignored.
NIL, only one existing session in the database is
This function can return
NIL which means that sessions or
session databases will be modified without a lock held (for example
for single-threaded environments). The default is to always return a
global lock (ignoring the
NIL otherwise.
NIL is returned.
A default method is provided and you only need to write your own one if you want to maintain your own sessions.
A default method is provided and there's no reason to change it unless you want to use your own session objects.
(defclass cookie () ((name :initarg :name :reader cookie-name :type string :documentation "The name of the cookie - a string.") (value :initarg :value :accessor cookie-value :initform "" :documentation "The value of the cookie. Will be URL-encoded when sent to the browser.") (expires :initarg :expires :initform nil :accessor cookie-expires :documentation "The time (a universal time) when the cookie expires (or NIL).") (max-age :initarg :max-age :initform nil :accessor cookie-max-age :documentation "The time delta (in seconds) after which the cookie expires (or NIL).") (path :initarg :path :initform nil :accessor cookie-path :documentation "The path this cookie is valid for (or NIL).") (domain :initarg :domain :initform nil :accessor cookie-domain :documentation "The domain this cookie is valid for (or NIL).") (secure :initarg :secure :initform nil :accessor cookie-secure :documentation "A generalized boolean denoting whether this is a secure cookie.") (http-only :initarg :http-only :initform nil :accessor cookie-http-only :documentation "A generalized boolean denoting whether this is a HttpOnly cookie.")))The reader COOKIE-NAME and the accessors COOKIE-VALUE, COOKIE-EXPIRES, COOKIE-MAX-AGE, COOKIE-PATH, COOKIE-DOMAIN, COOKIE-SECURE, and COOKIE-HTTP-ONLY are all exported from the
HUNCHENTOOT package. For now, the class name itself is not exported.
COOKIE object from the parameters
provided to this function and adds it to the outgoing cookies
of the
REPLY object
COOKIE object
REPLY object
ACCESS-LOG-DESTINATION and
MESSAGE-LOG-DESTINATION slots in the
ACCEPTOR to
NIL. The two
slots can be initialized by providing the
:ACCESS-LOG-DESTINATION and :MESSAGE-LOG-DESTINATION
initialization arguments when creating the acceptor or set by
setting the slots through its
ACCEPTOR-MESSAGE-LOG-DESTINATION and
ACCEPTOR-ACCESS-LOG-DESTINATION accessors.
When the path for the message or accept log is set to a variable holding an output stream, hunchentoots writes corresponding log entries to that stream. By default, Hunchentoot logs to *STANDARD-ERROR*.
Access logging is done in a format similar to what the Apache web server can write so that logfile analysis using standard tools is possible. Errors during request processing are logged to a separate file.
The standard logging mechanism is deliberately simple and slow. The log files are opened for each log entry and closed again after writing, and access to them is protected by a global lock. Derived acceptor classes can implement methods for the ACCEPTOR-LOG-MESSAGE and ACCEPTOR-LOG-ACCESS generic functions in order to log differently (e.g. to a central logging server or in a different file format.
Errors happening within a handler which are not caught by the handler itself are handled by Hunchentoot by logging them to the established ACCEPTOR-MESSAGE-LOG-DESTINATION.
NIL if there is no message
logger or whatever the message logger returns.
This is the function which Hunchentoot itself uses to log errors it catches during request processing.
:ERROR (the default),
(the default), or
This section describes how Hunchentoot deals with exceptional situations. See also the secion about logging.
When an error occurs while processing a request, Hunchentoot's default behavior is to catch the error, log it and optionally display it to the client in the HTML response. This behavior can be customized through the values of a number of special variables, which are documented below.
(the default is
T), then errors which happen while a
request is handled aren't caught as usual, but
instead your
Lisp's debugger
is invoked.
This variable should obviously always be set to a true value
in a production environment.
See MAYBE-INVOKE-DEBUGGER
if you want to fine-tune this behaviour.
is signaled in Hunchentoot. You might want to specialize it on
specific condition classes for debugging purposes. The default
method invokes
the debugger with
Note that for this function to be useful you should usually send 'Last-Modified' headers back to the client. See the code of CREATE-STATIC-FILE-DISPATCHER-AND-HANDLER for an example.
NIL the
function tries to determine the correct content type from
the file's suffix or falls back
"application/octet-stream" as a last resort.
Note that this function calls SEND-HEADERS internally, so after you've called it, the headers are sent and the return value of your handler is ignored.
:HTTP or
:HTTPS, and
the URL to redirect to will be constructed
:HTTPS, the client will be redirected to a
https URL, if it's
:HTTP it'll be sent to a
http URL. If both
NIL for return codes Hunchentoot
doesn't know.
NIL, it should be bound to a stream to
which incoming and outgoing headers will be written for debugging
NIL. The initial value is
the name of a function which invokes a garbage collection on 32-bit
versions of LispWorks.
This variable is only available on LispWorks.
NIL or a positive integer. The system calls
whenever *CLEANUP-INTERVAL* new worker threads
(counted globally across all acceptors) have been created unless the
value is
NIL. The initial value is 100.
This variable is only available on LispWorks.
To run the confidence test, start the example web server. Then, in your Lisp listener, type
(hunchentoot-test:test-hunchentoot "http://localhost:4242")You will see some diagnostic output and a summary line that reports whether any tests have failed. (You can also use the example certificate and key files in the test directory and start and test an https server instead.)
The script expects the Hunchentoot example test server to be
running at the given
NIL to
make that happen. Alternatively, you may want to have Hunchentoot
display detailed error information in the error response page.
You can set the *SHOW-LISP-ERRORS-P* to a
true value to make that happen. If you don't want to see Lisp
backtraces in these error pages, you can
set *SHOW-LISP-BACKTRACES-P*
It turned out that Jeff Caldwell had worked on something similar so he emailed me and proposed to join our efforts. As I had no immediate plans to release my code (which was poorly organized, undocumented, and mostly CMUCL-specific), I gave it to Jeff and he worked towards a release. He added docstrings, refactored, added some stuff, and based it on KMRCL to make it portable across several Lisp implementations.
Unfortunately, Jeff is at least as busy as I am so he didn't find the time to finish a full release. But in spring�2004 I needed a documented version of the code for a client of mine who thought it would be good if the toolkit were publicly available under an open source license. So I took Jeff's code, refactored again (to sync with the changes I had done in the meantime), and added documentation. This resulted in TBNL�0.1.0 (which initially required mod_lisp as its front-end).
In March�2005, Bob Hutchinson sent patches which enabled TBNL to use other front-ends than mod_lisp. This made me aware that TBNL was already almost a full web server, so eventually I wrote Hunchentoot which was a full web server, implemented as a wrapper around TBNL. Hunchentoot�0.1.0 was released at the end of 2005 and was originally LispWorks-only.
Hunchentoot�0.4.0, released in October�2006, was the first release which also worked with other Common Lisp implementations. It is a major rewrite and also incorporates most of TBNL and replaces it completely.
Hunchentoot�1.0.0, released in February 2009, is again a major rewrite and should be considered work in progress. It moved to using the usocket and Bordeaux Threads libraries for non-LispWorks Lisps, thereby removing most of the platform dependent code. Threading behaviour was made controllable through the introduction of taskmasters. mod_lisp support and several other things were removed in this release to simplify the code base (and partly due to the lack of interest). Several architectural changes (lots of them not backwards-compatible) were made to ease customization of Hunchentoot's behaviour. A significant part of the 1.0.0 redesign was done by Hans H�bner.
package in alphabetical order linked to their corresponding
documentation entries:
Hunchentoot originally used code from ACL-COMPAT, specifically the chunking code from Jochen Schmidt. (This has been replaced by Chunga.) When I ported Hunchentoot to other Lisps than LispWorks, I stole code from ACL-COMPAT, KMRCL, and trivial-sockets for implementation-dependent stuff like sockets and MP. (This has been replaced by Bordeaux Threads and usocket.)
Parts of this documentation were prepared with DOCUMENTATION-TEMPLATE, no animals were harmed.


text:
Albany Area Hospital
Albany Area Hospital was recognized by Centers for Medicare & Medicaid Services (CMS) as one of modern hospitals which are scientifically measured and assessed to have high-quality health care services for promoting health and improving the quality of life. Albany Area Hospital is located at 300 Third Avenue Albany, MN 56307 and can be contacted via phone number (320) 845-2121.
Contact Info
- Monday - Friday: 8:00 AM - 5:00 PM
- Saturday - Sunday: Closed
Patient Experiences
Center for Medicare & Medicaid Services (CMS) regularly gathers feedback information from patients (and their family or friends) about their experiences with a certain hospital. In this survey, the patients shares their feelings about services they received, and whether they would recommend the hospital to someone else. This information is also very helpful to the hospital, telling where to focus such improvement efforts for better health care and services.
This hospital data was updated by using the dataset publicized on Aug 10th, 2016 by the Centers for Medicare and Medicaid Services (CMS). If you found out anything that is incorrect and want to change it, please follow this Update Data guide.
Related Providers
Nearby Hospitals
Fairview Southdale Hospital
6401 France Avenue South
Mille Lacs Health System
200 North Elm Street
St Francis Medical Center
2400 St Francis Drive
Essentia Health St Marys - Detroit Lakes
1027 Washington Ave
St Francis Regional Medical Center
1455 St Francis Avenue
Newly Added Hospitals
Essentia Health St Mary's Medical Center
407 East Third Street
Douglas County Hospital
111 17th Avenue East
University Medical Center-mesabi / Mesaba Clinics
750 East 34th St
Mayo Clinic Health System - Albert Lea
404 West Fountain Street
Winona Health Services
855 Mankato Avenue

subset: commoncrawl


text:
Tuesday, June 03, 2014
Vintage Photos: You Win Some You Lose Some
Well it's a fickle one the world of online auctions and you have those who live by the bid will die by the bid! ...or something like that. Two photos tonight, both of which I love. The top one arrived today and I think it is a thoroughly disarming candid portrait. Very happy to have won it. The photo below on the other hand I don't own. I love it for two reasons. First for the extremely handsome young man in the background and then just for its casualness and sense of fun which belies the fact that, although on first glance it looks like something from the 40s, if you click and enlarge and look at the calendar in the background you will see it is barely out of the Victorian period. I was so busy looking at the image and thinking how wonderful it was whilst I waited for the auction to come to its close that suddenly the page was changing in front of my eyes and someone else waltzed off with it for much less than I would have been prepared to pay! Grrrr...
2 comments:
USA I'd say. Probably students. University of Philadelphia. 24th Nov 1904.
It's a nice photo indeed. Would it not be an idea to offer the buyer the purchase plus a little extra for it?
- 2:12 pm
- Alexis said...
The first one is lovely : the boy seems delighted to be pictured - I wonder by whom...
- 12:28 pm
Subscribe to: Post Comments (Atom)


text:
John Weller
First Mentioned
Full Name
John Weller
Also Known As
Principal Weller
California, USA
School Principal
Her secretary, Rose, asks Claire via phone if she can hold for him and she says yes, though she can't talk because she has to park her car and she is in the loading and unloading zone. John tells her that Mr. Waters caught Alex letting Haley copy her homework and that he is about to have a little talk with them, so they'll be out a few minutes late. Claire apologizes to John saying that she is a better mother than this, and John tells her that she has said that already.


text:
- Trending Now: More Trending:
- implode ballistic transgender beleaguer scaramouch
Definition of dewindtite
: a mineral Pb3(UO2)5(PO4)4(OH)4.10H2O consisting of a hydrous basic phosphate of lead and uranium
There's more!
Love words? You must — there are over 200,000 words in our free online dictionary, but you are looking for one that's only in the Merriam-Webster Unabridged Dictionary.
Start your free trial today and get unlimited access to America's largest dictionary, with:
- More than 250,000 words that aren't in our free dictionary
- Expanded definitions, etymologies, and usage notes
- Advanced search features
- Ad free!
Origin and Etymology of dewindtite
French, from Jean Dewindt, 20th century Belgian geologist + French -ite
Seen and Heard
What made you want to look up dewindtite? Please tell us where you read or heard it (including the quote, if possible).


text:
Welcome to the ineedhits Search Engine Marketing blog, where we share the latest search engine and online marketing news, releases, industry trends and great DIY tips and advice.
Is it a sign of the times? Assumptions this early might be hasty, but the alarm bells are surely ringing down at the Googleplex. Amazon's A9 search and Alexa, both highly recognized and trafficked online services, have dumped Google for their search results.
To add salt to the wounds, Google has been replaced by its arch nemesis Microsoft, aka Windows Live Search. This surely has Bill Gates smiling while Serge and Larry rue the loss.
Speculation in the industry suggests this could be the first Google dumping of many, as the search giant has made its intentions clear that pure search is no longer its only goal. With the unveiling of Google Base and other extensions to the empire, Google is starting to stretch its relationship with many of the websites that have served its results for years.
As Google vies to gain market share across the online shopping vertical and other portal directions, it will continue to lose some of its trusty alliances, as these organizations are not prepared to have Google competing against them. Let's face it, why would Amazon want to serve competing ads for books across its websites.
The interesting side to this story is that MSN has recently launched a new online shopping service to compliment the existing MSN shopping portal, so this new union could be short lived. Perhaps Amazon is just testing options before deciding on a complete transition away from Google results.
At the end of the day, the real winner in these turbulent internet times will be the search engines dedicated purely to search, as they present no significant risk to the sites hosting their results. This could be the renaissance of the smaller engines such as Ask.com as one blog suggested. Only time will tell, but stay tuned as speculation of more Google dumpings are sure to ensue.
7 day Google inclusion money back guaranteed – Only $19.95
Agreed in another blog: http://www.encodemedia.co.uk/scgi-bin/blosxom.cgi/2006/03/30#gooooodbye
By Anonymous - May 2, 2006
What will this do to the predictions of Google over $1000 in 2007?
By Anonymous - May 2, 2006
Hi !
I am Piter Kokoniz. Just want to tell, that your posts are really interesting
And want to ask you: will you continue to post in this blog in future?
Sorry for my bad english:)
Thank you!
By PiterKokoniz - April 7, 2009
Keep up to date with the latest from our blogs.
Yahoo's Brilliant Babel Fish Makeover
Yahoo! has revived AltaVista's Babel Fish, the translation service that's been around since the dawn of search engines (or so ...


text:
Spadea 70755; 1975; Women's Dress or Chemise -- This Spadea Boutique chemise is styled for both Misses and Women's Sizes. The body of the dress is gently gathered to a yoke. The sleeves are gathered into cuffs just above the elbow.
Links to reviews/blog posts Edit
Sources/Vendors Edit
Gallery Edit
[insert your photos of this pattern made up]
Wishlist Edit
[insert your username, and make sure your preferences allow for people to contact you via e-mail. Do not list your email address here!]


text:
Have Ford Questions? Ask a Mechanic for Answers ASAP
Hello and thank you for using Just Answer I'm Paul and I will help you with your Question
this is a common issue with a loose ground g103
it is under the air cleaner assembly
stand by
I am attaching more info
click here for the testing information
let me know what you find and if you need more help
let me know if you need more help
check all the grounds
I am attaching the wiring diagram for the dome light circuit
did you check the data circuits as mentioned in the test report I attached?
check battery cable connections
I am attaching the computer data digram make sure you have good continuity on the data circuits between the modules
click here to view the data circuits


text:
Apple's car project is still something of a mystery, and that's leading to all kinds of speculation. John Martellaro and Bryan Chaffin join Jeff Gamet to look at reports that Apple wanted to buy a high end car maker, plus they have some thoughts on Apple's paper bag patent.
TMO Daily Observations 2016-09-22: The State of Apple Car, Apple's Bag Patent
- The state of Apple's car project
- Turns Out Apple CAN Patent Its Way Out of a Paper Bag
- Jeff's Getting Started with Podcasting class at Boulder Digital Arts. Use discount code JGametPod16 for 15% off.
- TMO Daily Observations Twitter feed


text:
Faculty of Health
Pelvic Assessment for Continence Training (PACT)
PACT Authentic Learning Program
Pelvic Assessment for Continence Training (PACT): A Practice Development and Accreditation Program for Continence Practitioners
The PACT program is a practice development and accreditation program designed to develop confidence and competence in performing both female and male pelvic examination for continence assessment, endorsed by the Royal Collage of Nursing Australia.
Next course dates to be confirmed.
Attendance attracts 10 RCNA Continuing Nurse Education (CNE) points as part of RCNA's Life Long Learning Program (3LP)
The program utilises a range of teaching and learning methods delivered by healthcare professionals, Professor Turner, O&G consultant Dr Nathan, senior nursing and physiotherapist continence practitioners and Clinical Teaching Associates (CTAs).
The core learning experiences are authentic role-play scenarios with experienced Clinical Teaching Associates trained to teach and accredit sensitive pelvic floor examinations. The focus of learning is on putting theoretical knowledge into practice in a safe learning environment.
The overall aims of the program are to:
- Introduce participants to a standardised approach to assessing the pelvic floor.
- Provide a theoretical outline to develop the participants' understanding of the anatomy and physiology related to pelvic floor assessment.
- Provide a unique and authentic learning opportunity to develop the participants' skills and competencies in pelvic examination assessment relevant to continence status.
- Develop the participants' understanding of the impact of related surgical and medical conditions upon continence/incontinence and pelvic assessment.
- Develop the participants' communication and consultation skills.
- Support participants in achieving continence pelvic floor assessment accreditation.
Some comments from previous participants:
"Extremely valuable learning exercise. It has improved my confidence to perform DVE/DRE."
"I am more competent and confident in the examination of the pelvic floor."
"This was all facilitated by the wonderful CTAs!"
Course registration and payment
You can register your interest in participating in the course on the PACT Registration page.
Payment for the course can be made at the PACT Online Payment site. Complete the first page with your personal details and then proceed to make the payment. Please do not make a payment until you have received confirmation of your course registration.
Contact for further information:Mr Neil Sefton
Head, Human Simulation
Education and Training
Hobart Clinical School
University of Tasmania
Ph: +61 3 6226 4897
Visit the Continence Foundation of Australia website for more information about bowel and bladder health.
In partnership with the Tasmanian Department of Health and Human Services, the Continence Foundation of Australia, and the Royal College of Nursing Australia.


text:
In which Shiva Nata saves my life again.
And not even metaphorically.
Which is the usual way.
Three times.
Just in the past week.
The first time I was crossing the street. At the crosswalk. With the green light. Three lanes.
As I'm crossing, I can't see the third lane until I'm there, but oh look here's who is zooming down and through the third lane at top speed: some lady who seems in retrospect to believe that "right on red" means you don't have to stop at the red or even slow down, apparently.
Shiva Nata has given me quick instincts and even quicker reflexes.
I felt my body pulling me back before even knowing what was happening, she missed me by inches.
We were one hundred percent bound to cross orbits, except for tingle-knowing which feels like luck but is not luck.
She had speed but I had speediness. I could feel the tug-pull of belly communicating with spine and earth that happens when I try to keep my balance during an impossibly fast level 3.
My body knew what to do before I did, it's been training for this for years while we've been rewriting all the internal patterns. And then I was somehow still standing and she was gone.
The second time.
In the shower. Slipped and skidded on a slippery surface in a moment of not paying attention.
It was that moment of knowing the fall was coming.
And then the same thing as before.
Balance was magically there, righting me. Righting myself. Partly core, partly internal remembering, partly body being there for me with steadiness and a determined love.
It was a moment of shiva nata. I could feel it.
And then.
The third time was crossing the street again. This time someone on the phone, seriously people, stop doing that, driving around a corner and not looking.
My body executed a little hop-skip-jump with more grace than I felt internally, and it took me out of the path of destruction.
Path. Of. Destruction.
So the symbolic concept/essence/whatever of Shiva is, of course, destruction. Paths and paths of it!
But not the kind of destruction that people think it is.
It's more like this:
A pure, clean, clear, compassionate, loving slicing away of everything that is no longer valid, relevant or true.
An undoing of the structures that are rigid distortions of truth, so that new organic forms can emerge. A rewriting of the patterns that aren't working so that the new patterns can take shape.
It is this undoing and unraveling that has put me in this deeper relationship with my body, trusting my instinctive pushes and pulls. A new connection with the home of my body that is changing everything.
Destruction is taking me home. But not through ruining things. Through connecting up portals, opening the right doors, showing me possibility.
And it's saving my life. Over and over again.
This is awesome. Both in the sense of "wow that is neato-rad!" and in the sense of sweet loving grace-filled nondenominational REVERENT AWE. Yes.
Alligatoroos! The commenting blanket fort.
Things that are welcome today:
Joy-filled exclamations of delight for these beautiful things.
Stories of ways that Shiva Nata or shivanautical side effects have helped you in unexpected ways.
Warm heart-sighs.
That is all for now. May we all receive the deconstructing of whatever needs to be deconstructed, in the sweetest and safest ways possible.


text:
Dhulikhel is located at the Eastern rim of Kathmandu Valley, south of the Himalayas at 1550m above sea level.
It has a special place in the history of Nepal, as for many centuries it has been an important trading centre on the ancient commercial route linking Nepal to Tibet. Even now, a bird's eye view from the resorts at Dhulikhel to the landscapes; highway to Tibet and horizons far to the Tibetan borders, clearly exhibits Dhulikhel as the gateway of Tibet.
Dhulikhel offers a spectacular view of the green mountains and further into the snow capped Himalayas. The panorama offers a majestic undisturbed view of the Himalayan ranges stretching from Mount Annapurna to Mount Karolung in the Far East. More than twenty Himalayan peaks including Mt. Annapurna, Mt. Ganesh Himal, Mt. Langtang, Mt. Phuribichyachu, Mt. Gaurishanker, Mt. Lhotse and many others can be seen in their full glory from the different vantage points in Dhulikhel.
Dhulikhel is also famous for its assembly of fine old Newari houses, often occupied by 20 or more members of the local extended families. Their most valuable assets are the beautifully carved windows and doors, fine examples of traditional Newari craftsmanship. As one wanders down the traffic free narrow streets, one passes through a medieval city inhabited for at least five centuries and may have a feeling that he is in the garden of cultural theme park.
Read more about Dhulikhel


text:
"Is this compatible with Panasonic VIERA 42"
If you plan to walk mount a television, Overstock has a great variety to suit many applications. I compared with the mounts at electronics stores, and this was a great value, probably half the price. It's a very good quality mount....
Arrowmounts Ultra-Slim Tilting Wall Mount for 23" - 42" LED/LCD TVs AM-SLT2342B
ITEM#: 14325997The Arrowmounts Ultra-Slim Design Series Tilting Wall Mount for 23" to 42" LED or LCD TVs is great for achieving that sleek, ultra-slim look for your flat screen TV. This mount has a low profile design where it sits only 2.5 cm from the wall. It has a weight capacity of 75 lbs and supports flat-panel TV sizes ranging between 23" to 42". This mount Allows for up to 10 degrees of tilt for optimal viewing. It's lift-and-hook design makes it super-easy to install your TV on the mount, especially when using the integrated leveling mechanism. This mount is compatible with most mounting hole patterns including the VESA standard.
- Model: AM-SLT2342B
- Ultra-slim design
- Supported Flat-Panel TV Sizes: 23" - 42"
- Max Load: 34 kg / 75 lbs
- Low profile-installs only 2.5 cm (1") from wall
- Solid heavy-gauge steel construction
- Quick release locking system makes installation fast and easy
- Allows up to +/-10 degrees of tilt for optimal viewing
- Compatible with most hole patterns including VESA standard
- Includes installation guide and hardware kit
- Max Mounting Pattern: 400 mm x 400 mm
- Dimensions: 18" x 18" x 1"
- Weight: 4 lbs
|Low Profile, Tilt
|Cabinet, Stand or Bracket Type
|Wall Mount
|See Details
|5 year Limited Manufacturer
|Model Number
|Country of Origin
Similar Items
Sonax M-415-MPM Tilting Flat Panel White Wall Mount for 32" - 55" TVs
Today: $34.99
Sonax E-5055-MP Tilting Flat Panel Wall Mount for 32" - 55" TVs
Today: $29.99
Sonax E-5155-MP Tilting Flat Panel Wall Mount for 32" - 65" TVs
Today: $36.99
Arrowmounts 10 to 23-inch Tilt/ Swivel Flat Screen TV Ceiling Mount
Today: $25.99
CorLiving T-101-MTM Tilting Flat Panel Wall Mount for 26" - 47" TVs
Today: $36.99
CorLiving T-102-MTM Tilting Flat Panel Wall Mount for 32" - 55" TVs
Today: $44.99
Customer Reviews
Most Helpful
Perfect & Easy Ultra-Slim Tilting Wall Mount
First off, for the money and efficiency of ease of order to delivery, there is no better place than Overstock.com for TV wall mounts. This is my fourth or fifth wall mount that I have ordered, and EVERY one was simple to install, easy to use and well worth the money. That being said, I have installed several of these, and really didn't need directions. These are very high level and simple, and leave a few important things out that if this was you first attempt, you would need to know. First off, this mount fits the very hard to find VESA 200x400 mount on the 39" LCD TV's. I ordered 2 previous and they didn't fit, so my kids have wall mounts now for their rooms. There are locking washers, screws and washers for only 3 sizes of mount screws. You have to mount the vertical bars to the TV first and use the included side handled screwdriver to tighten the top screw after you pull the slide/tilt out into extended position. I used a small washer, locking washer and the screws(in that order) included with no issues. Once these are attached to TV, and the metal bracket mounted to wall, it was so easy to pull the cord that disengages the locking mount and gently push the bottom side of TV till it locks. The actual wall mounting bracket can be placed virtually anywhere. I used the included 1/2 wall screws and drilled center of bracket to a support stud, took 5 minutes to mount. It even includes its own level block. Previous reviews disputed the tool-less tilting, and I can see where they think that. When you attach the vertical beams to TV, just loosen the top screws that are to the inside(not facing out once TV is on wall) just a little bit. This will allow the tilt to be made w/out removing TV from wall easier. Honestly, unless you are putting this TV up high on the wall, the tilt is really not required. Hope this helps.Read More
Most Recent
Great value
If you plan to walk mount a television, Overstock has a great variety to suit many applications. I compared with the mounts at electronics stores, and this was a great value, probably half the price. It's a very good quality mount.Read More
Good quality, great price
This product is sturdy and easy to use.Read More
Product is as decribed, no problemsRead More
TV bracket
Solid construction. Easy install. Tilt feature works great.Read More
Does the job at a great price
Save $$$ over the electronic retailers, mounts easy, all the hardware needed was included, great value for the moneyRead More
Questions & Answers
I would suggest measuring your TV to make sure before ordering: Supported Flat-Panel TV Sizes: 23" - 42" Max Mounting Pattern: 400 mm x 400 mm
Shopping Tips & Inspiration
Top 10 Christmas Gift Ideas for the Techie
Whether you're shopping for your dad, husband, son, brother, or boyfriend, finding the perfect gift for the techie guy in your life just got easier. We've put together the top gifts for the person in your life that is always in the know when it comes to the latest and greatest tech gadgets.
Best Bluetooth Speakers for Christmas
From rugged and waterproof outdoor speakers to wireless speaker sets for quality indoor surround sound, Bluetooth speakers are a must-have for the music lovers, partygoers, and outdoor enthusiasts on your list. Check out these top trends to get started on your Christmas 2016 shopping.
Stocking Stuffer Ideas
In the hurry and flurry of Christmas Day, don't overlook the gifts found in Christmas stockings. Stocking stuffers are usually smaller and less expensive than what you put under the tree, but they're a thoughtful and ideal way to celebrate the personality or interests of those on your list. Peruse our options and you'll be ready to grant the holiday wishes of the special people in your life.
How to Find Electronics Deals on Cyber Monday
You can count on a lot of great Cyber Monday deals, and some of the best sales will include discounted electronics. To get a jumpstart on your online shopping, you can do your homework beforehand. Whether you're looking to expand your own tech collection or shopping for the gadget geek on your list, these are the hottest electronics deals to look for on Cyber Monday.
Valentine's Day Gifts for Him
Forget the flowers and chocolate, and treat the man in your life to an extra special gift this Valentine's Day. Finding the perfect gift is sometimes difficult, but remember that you can't go wrong with a thoughtful, personal, and romantic present during this holiday devoted to all things love. If you're looking to give your significant other a truly memorable Valentine's Day gift, here are a few suggestions.
Unique Electronic Gift Ideas
Electronics are popular to give as gifts, but how do you find unique ideas for someone who seems to have everything? Our shopping guide is here to help.
Top 5 Electronic Gifts for Your Husband or Boyfriend
Top 5 Electronic Gifts for Your Husband or Boyfriend from Overstock.com. The electronics store has gift options to match any guy's interests.
Recycling Electronics by State
Recycling Electronics by State from Overstock.com. A state-by-state guide to recycling electronics and e-waste.
Top 5 Electronic Gifts for Seniors
Top 5 Electronic Gifts for Seniors from Overstock.com. Among the enormous selection of electronics available, plenty of devices can be enjoyed or even put to practical use by seniors.
Electronics Recycling Guide
Electronics Recycling Guide from Overstock.com. Reduce, reuse, and recycle your electronics with the help of these tips.
Shipping & Returns
Contact Information
Shipping Information:
Our standard shipping method is ground shipping. We also offer expedited shipping for most items. Your final
shipping cost and estimated delivery timeframe will be available at checkout.
Standard shipping details
Expedited shipping details
Standard Return Policy for Electronics:
The items must arrive at our warehouse within 30 days of purchase. You must return items in their original condition to qualify for a full refund. We will issue a partial refund of up to 70 percent if returned items have been opened, used, or returned late. More Details
For your protection, all orders are screened for security purposes. If your order is selected for review, our Loss Prevention Team may contact you by phone or email. There may be a two business day delay to process your order.
** Most Oversize orders are delivered within 1-4 weeks. Some orders may take 6 weeks to be delivered.


text:
Torquay Weekender - Torquay
Belgrave Road Torquay TQ2 5HZ GB
Torquay Weekender on
Event Information
Torquay Weekender 14th year
3 rooms Northern Room, Modern Room and Pumping Hearts Room open decks during the day.
Dinner Bed and Breakfast included, all Rooms with private Bathroom and Tea and Coffee making equipment.
Use of all the Hotel facilities, Swimming Pool, Sauna and Steam Room. Spa treatments and Massage available
Dj's Including: Ginger Taylor, Ted Massey, Pete French, Nige Brown, Snowy, Mick Bennett, John Barker, Kenny Lee,
John Farrell, Steve Russell, Francis T, Andy Vass and Steve Towers other Guests to be confirmed.
Venue Details
Event AddressBelgrave Road, Torquay, England, TQ2 5HZ, United Kingdom
Contact the venuePlease check with the venue/promoter to confirm details before travelling
Venue Map
Venue Street View
Event Reviews and Comments
Welcome to the Torquay Weekender Event Review Section
There are no reviews to display.
Welcome to the Torquay Weekender Comments sectiom
This event is now over. Look up now to read the latest reviews of this soul event
There are no comments to display.
Join or log in now!
Comments are members only
Create an account
Sign up to Soul Source now.. Free & easy!
Register a new account
Sign in
Already have an account? Sign in here.
Sign In Now


text:
Don't panic. If one of your Apple devices goes missing, iCloud can help you figure out where it is. Just sign in at iCloud.com or use the Find My iPhone app to see your missing iPhone, iPad, iPod touch, or Mac on a map. And with the Lost Mode feature you don't just see where your device is, you can track where it's been. That way you can decide on your best course of action. You can immediately lock your device and send it a message with a contact number. Then whoever finds it can call you from the Lock screen without accessing the rest of the information on your device. - Apple
Ah, yes. "Find my iPhone" is, in theory, a great idea and, in practice, it works great helping locate your errant idevices. The problem is, even if you know where your idevice is, will you actually be able to get it back?
Yesterday, I talked to a friend of my wife's (I will call her friend "Sue") who told me the following story: On a recent Thursday, here in Ventura, some 60-odd miles from Los Angeles' San Fernando Valley, someone entered Sue's home through an unlocked sliding door and made off with the most expensive and portable thing in sight: Her husband's brand new MacBook Pro.
When the couple realized what had happened they logged into Apple iCloud's and went to "Find My iPhone" (which can be used with all iOS and OS X devices) and set the laptop to "Lost Mode." Then they waited.
Finally, on Saturday, roughly 48 hours later, the MacBook was switched on and, voila! There, on the "Find my iPhone" map was the location of the device! This turned out to be what was, until a couple of years ago, a sober living facility in Van Nuys, a neighborhood in the San Fernando Valley.
They immediately called Van Nuys Police Department and … the cops weren't interested. The couple were told that if the police went and knocked on the door and no one answered then that would be it, there would be nothing more the police could do. Even if the door was answered, the occupants would only have to deny they had the laptop and, again, it would be over and done with. In other words, it wasn't worth even trying.
Sue and her husband realized they only had one choice, click on the "Erase MacBook" option to wipe it clean. Sue said that this was "mentally useful; you can realize it's gone and you can move on."
This is the disappointing reality of using "Find My iPhone" with stolen property because even when you know with a high degree of certainty where a valuable piece of stolen equipment is, it's usually not enough cause for the police to get involved because technical certainty isn't legal certainty. I just spoke with the watch commander of Ventura PD who told me that what action is taken, if any, depends on local departmental policy, manpower availability, and requires verifiable accuracy of location.
Sue and her husband considered claiming the loss on their homeowners insurance but they figured it wouldn't be worth it because it would increase their premium so, to them, the loss of the MacBook has been consigned to the past.
The takeaway? If you think the "Find My iPhone" will help you if your property is stolen then, yes, it might but it's a long shot. Apple's service is great for mislaid devices but in the case of theft, unless you have, shall we say, "enforcement" of your own, it's going to be easier just to hit "Erase."


text:
Blitz User Gallery
Toihlsa by OJay
Toihlsa is an action oriented 3rd person RPG settled in the Gothic Universe.
Working quite a long time on this now, and we're still in early alpha stage, but coming along nicely.
Visit our website for more details!
|1+ years ago
|No. of ratings:
|Average rating:
|4.43 / 5
|Blitz Social Club