root/trunk/thirdparty/chunga/streams.lisp

Revision 3186, 7.1 kB (checked in by edi, 8 months ago)

Import current Chunga dev version from laptop

Previous history at http://trac.common-lisp.net/tbnl/browser/branches/chunga

Line 
1 ;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: CHUNGA; Base: 10 -*-
2 ;;; $Header: /usr/local/cvsrep/chunga/streams.lisp,v 1.10 2008/05/24 03:06:22 edi Exp $
3
4 ;;; Copyright (c) 2006-2008, Dr. Edmund Weitz.  All rights reserved.
5
6 ;;; Redistribution and use in source and binary forms, with or without
7 ;;; modification, are permitted provided that the following conditions
8 ;;; are met:
9
10 ;;;   * Redistributions of source code must retain the above copyright
11 ;;;     notice, this list of conditions and the following disclaimer.
12
13 ;;;   * Redistributions in binary form must reproduce the above
14 ;;;     copyright notice, this list of conditions and the following
15 ;;;     disclaimer in the documentation and/or other materials
16 ;;;     provided with the distribution.
17
18 ;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED
19 ;;; OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 ;;; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 ;;; ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
22 ;;; DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 ;;; DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
24 ;;; GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 ;;; INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
26 ;;; WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27 ;;; NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 ;;; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30 (in-package :chunga)
31
32 (defclass chunked-stream (trivial-gray-stream-mixin)
33   ((real-stream :initarg :real-stream
34                 :reader chunked-stream-stream
35                 :documentation "The actual stream that's used for
36 input and/or output."))
37   (:documentation "Every chunked stream returned by
38 MAKE-CHUNKED-STREAM is of this type which is a subtype of
39 STREAM."))
40
41 (defclass chunked-input-stream (chunked-stream fundamental-binary-input-stream)
42   ((input-chunking-p :initform nil
43                      :reader chunked-stream-input-chunking-p
44                      :documentation "Whether input chunking is currently enabled.")
45    (input-buffer :initform nil
46                  :documentation "A vector containing the binary
47 data from the most recent chunk that was read.")
48    (input-index :initform 0
49                 :accessor chunked-stream-input-index
50                 :documentation "The current position within INPUT-BUFFER.")
51    (input-limit :initform 0
52                 :accessor chunked-stream-input-limit
53                 :documentation "Only the content in INPUT-BUFFER
54 up to INPUT-LIMIT belongs to the current chunk.")
55    (chunk-extensions :initform nil
56                      :reader chunked-input-stream-extensions
57                      :documentation "An alist of attribute/value
58 pairs corresponding to the optional `chunk extensions' which
59 might be encountered when reading from a chunked stream.")
60    (chunk-trailers :initform nil
61                    :reader chunked-input-stream-trailers
62                    :documentation "An alist of attribute/value
63 pairs corresponding to the optional `trailer' HTTP headers which
64 might be encountered at the end of a chunked stream.")
65    (expecting-crlf-p :initform nil
66                      :accessor expecting-crlf-p
67                      :documentation "Whether we expect to see
68 CRLF before we can read the next chunk-size header part from the
69 stream.  \(This will actually be the CRLF from the end of the
70 last chunk-data part.)"))
71   (:documentation "A chunked stream is of this type if its
72 underlying stream is an input stream. This is a subtype of
73 CHUNKED-STREAM."))
74
75 (defclass chunked-output-stream (chunked-stream fundamental-binary-output-stream)
76   ((output-chunking-p :initform nil
77                       :reader chunked-stream-output-chunking-p
78                       :documentation "Whether output chunking is
79 currently enabled.")
80    (output-buffer :initform (make-array +output-buffer-size+ :element-type '(unsigned-byte 8))
81                   :accessor output-buffer
82                   :documentation "A vector used to temporary
83 store data which will output in one chunk.")
84    (output-index :initform 0
85                  :accessor output-index
86                  :documentation "The current end of OUTPUT-BUFFER."))
87   (:documentation "A chunked stream is of this type if its
88 underlying stream is an output stream. This is a subtype of
89 CHUNKED-STREAM."))
90
91 (defclass chunked-io-stream (chunked-input-stream chunked-output-stream)
92   ()
93   (:documentation "A chunked stream is of this type if it is both
94 a CHUNKED-INPUT-STREAM as well as a CHUNKED-OUTPUT-STREAM."))
95
96 (defmethod stream-element-type ((stream chunked-stream))
97   "Chunked streams are always binary streams.  Wrap them with
98 flexi streams if you need a character stream."
99   '(unsigned-byte 8))
100
101 (defmethod open-stream-p ((stream chunked-stream))
102   "A chunked stream is open if its underlying stream is open."
103   (open-stream-p (chunked-stream-stream stream)))
104
105 (defmethod close ((stream chunked-stream) &key abort)
106   "If a chunked stream is closed, we close the underlying stream as well."
107   (with-slots (real-stream)
108       stream
109     (cond ((open-stream-p real-stream)
110            (close real-stream :abort abort))
111           (t nil))))
112
113 (define-condition input-chunking-unexpected-end-of-file (stream-error)
114   ()
115   (:documentation "A condition of this type is signaled if we
116 reach an unexpected EOF on a chunked stream with input chunking
117 enabled.  This is a subtype of STREAM-ERROR, so
118 STREAM-ERROR-STREAM can be used to access the offending
119 stream."))
120
121 (define-condition input-chunking-body-corrupted (stream-error)
122   ((last-char :initarg :last-char
123               :documentation "The \(unexpected) character which was read.")
124    (expected-chars :initarg :expected-chars
125                    :documentation "The characters which were
126 expected.  A list of characters or one single character."))
127   (:report (lambda (condition stream)
128              (with-slots (last-char expected-chars)
129                  condition
130                (format stream "Chunked stream ~S seems to be corrupted.
131 Read character ~S, but expected ~:[a member of ~S~;~S~]."
132                        (stream-error-stream condition)
133                        last-char (atom expected-chars) expected-chars))))
134   (:documentation "A condition of this type is signaled if an
135 unexpected character \(octet) is read while reading from a
136 chunked stream with input chunking enabled. This is a subtype of
137 STREAM-ERROR, so STREAM-ERROR-STREAM can be used to access the
138 offending stream."))
139
140 (defun make-chunked-stream (stream)
141   "Creates and returns a chunked stream \(a stream of type
142 CHUNKED-STREAM) which wraps STREAM.  STREAM must be an open
143 binary stream."
144   (unless (and (streamp stream)
145                (open-stream-p stream))
146     (error "~S should have been an open stream." stream))
147   (make-instance ;; actual type depends on STREAM
148                  (cond ((and (input-stream-p stream)
149                              (output-stream-p stream))
150                         'chunked-io-stream)
151                        ((input-stream-p stream)
152                         'chunked-input-stream)
153                        ((output-stream-p stream)
154                         'chunked-output-stream))
155                  :real-stream stream))
Note: See TracBrowser for help on using the browser.