changelog shortlog graph tags branches changeset files revisions annotate raw help

Mercurial > core / lisp/lib/net/proto/http.lisp

changeset 381: 386d51cf61ca
parent: de40bd522c84
child: 849bbe48e32d
author: Richard Westhaver <ellis@rwest.io>
date: Tue, 28 May 2024 23:12:31 -0400
permissions: -rw-r--r--
description: add ffi/readline, net updates
1 ;;; lib/net/proto/http.lisp --- HTTP Support
2 
3 ;; based on https://github.com/fukamachi/fast-http
4 
5 ;; see also: https://github.com/orthecreedence/http-parse
6 
7 ;;; Commentary:
8 
9 ;; Fukamachi has implemented the current state-of-the-art HTTP libraries
10 ;; (fast-http, dexador, etc). For the time being we'll be using these with
11 ;; minimal changes. At some point in the future it would be ideal to
12 ;; re-implement this in a sans-io style.
13 
14 ;;; Code:
15 (in-package :net/proto/http)
16 
17 ;;; utils
18 (defmacro casev (keyform &body clauses)
19  (once-only (keyform)
20  (flet ((get-val (val)
21  (cond
22  ((eq val 'otherwise) val)
23  ((symbolp val) (symbol-value val))
24  ((constantp val) val)
25  (T (error "CASEV can be used only with variables or constants")))))
26  `(case ,keyform
27  ,@(loop for (val . clause) in clauses
28  if (eq val 'otherwise)
29  collect `(otherwise ,@clause)
30  else if (listp val)
31  collect `((,@(mapcar #'get-val val)) ,@clause)
32  else
33  collect `(,(get-val val) ,@clause))))))
34 
35 (defmacro casev= (keyform &body clauses)
36  (once-only (keyform)
37  (flet ((get-val (val)
38  (cond
39  ((eq val 'otherwise) val)
40  ((symbolp val) (symbol-value val))
41  ((constantp val) val)
42  (T (error "CASEV can be used only with variables or constants")))))
43  `(cond
44  ,@(loop for (val . clause) in clauses
45  if (eq val 'otherwise)
46  collect `(T ,@clause)
47  else if (listp val)
48  collect `((or ,@(mapcar (lambda (val)
49  `(= ,keyform ,(get-val val)))
50  val))
51  ,@clause)
52  else
53  collect `((= ,keyform ,(get-val val)) ,@clause))))))
54 
55 (defmacro case-byte (byte &body cases)
56  `(casev= ,byte
57  ,@(loop for (val . form) in cases
58  if (eq val 'otherwise)
59  collect `(,val ,@form)
60  else if (listp val)
61  collect `(,(mapcar #'char-code val) ,@form)
62  else
63  collect `(,(char-code val) ,@form))))
64 
65 (defmacro tagcase (keyform &body blocks)
66  (let ((end (gensym "END")))
67  `(tagbody
68  (case ,keyform
69  ,@(loop for (tag . body) in blocks
70  if (eq tag 'otherwise)
71  collect `(otherwise ,@body (go ,end))
72  else
73  collect `(,tag (go ,(if (listp tag) (car tag) tag)))))
74  (go ,end)
75  ,@(loop for (tag . body) in blocks
76  if (listp tag)
77  append tag
78  else
79  collect tag
80  collect `(progn ,@body
81  (go ,end)))
82  ,end)))
83 
84 (defmacro tagcasev (keyform &body blocks)
85  (let ((end (gensym "END")))
86  `(tagbody
87  (casev ,keyform
88  ,@(loop for (tag . body) in blocks
89  if (eq tag 'otherwise)
90  collect `(otherwise ,@body (go ,end))
91  else
92  collect `(,tag (go ,(if (listp tag) (car tag) tag)))))
93  (go ,end)
94  ,@(loop for (tag . body) in blocks
95  if (listp tag)
96  append tag
97  else if (not (eq tag 'otherwise))
98  collect tag
99  collect `(progn ,@body
100  (go ,end)))
101  ,end)))
102 
103 (defmacro tagcasev= (keyform &body blocks)
104  (let ((end (gensym "END")))
105  `(tagbody
106  (casev= ,keyform
107  ,@(loop for (tag . body) in blocks
108  if (eq tag 'otherwise)
109  collect `(otherwise ,@body (go ,end))
110  else
111  collect `(,tag (go ,(if (listp tag) (car tag) tag)))))
112  (go ,end)
113  ,@(loop for (tag . body) in blocks
114  if (listp tag)
115  append tag
116  else if (not (eq tag 'otherwise))
117  collect tag
118  collect `(progn ,@body
119  (go ,end)))
120  ,end)))
121 
122 (defun make-collector ()
123  (let ((none '#:none))
124  (declare (dynamic-extent none))
125  (with-collectors (buffer)
126  (return-from make-collector
127  (lambda (&optional (data none))
128  (unless (eq data none)
129  (buffer data))
130  buffer)))))
131 
132 (declaim (inline %whitespacep))
133 (defun %whitespacep (char)
134  (declare (type character char)
135  (optimize (speed 3) (safety 0)))
136  (or (char= char #\Space)
137  (char= char #\Tab)))
138 
139 (declaim (inline position-not-whitespace))
140 (defun position-not-whitespace (string &key from-end)
141  (declare (type simple-string string)
142  (optimize (speed 3) (safety 0)))
143  (let* ((len (length string))
144  (start (if from-end (1- len) 0))
145  (end (if from-end 0 (1- len)))
146  (step-fn (if from-end #'1- #'1+)))
147  (declare (type integer len start end))
148  (do ((i start (funcall step-fn i)))
149  ((= i end) i)
150  (declare (type integer i))
151  (unless (%whitespacep (aref string i))
152  (return-from position-not-whitespace i)))))
153 
154 (declaim (inline number-string-p))
155 (defun number-string-p (string)
156  (declare (type simple-string string)
157  (optimize (speed 3) (safety 2)))
158  ;; empty string
159  (when (zerop (length string))
160  (return-from number-string-p nil))
161  (let ((end (position-not-whitespace string :from-end t))
162  (dot-read-p nil))
163  ;; spaces string
164  ;; (when (null end)
165  ;; (return-from number-string-p))
166  (locally (declare (type integer end)
167  (optimize (safety 0)))
168  (incf end)
169  (do ((i (the integer (or (position-not-whitespace string) 0)) (1+ i)))
170  ((= i end) T)
171  (declare (type integer i))
172  (let ((char (aref string i)))
173  (declare (type character char))
174  (cond
175  ((alpha-char-p char)
176  (return-from number-string-p nil))
177  ((digit-char-p char))
178  ((char= char #\.)
179  (when dot-read-p
180  (return-from number-string-p nil))
181  (setq dot-read-p t))
182  (T (return-from number-string-p nil))))))))
183 
184 ;;; http
185 (defun make-http-parser (http &key first-line-callback header-callback body-callback finish-callback (head-request nil))
186  (declare (type http http))
187  (let (callbacks
188 
189  (parse-fn (etypecase http
190  (http-request #'parse-request)
191  (http-response #'parse-response)))
192 
193  (headers nil)
194 
195  (header-value-buffer nil)
196  parsing-header-field
197  data-buffer
198 
199  header-complete-p
200  completedp)
201  (flet ((collect-prev-header-value ()
202  (when header-value-buffer
203  (let ((header-value
204  (locally (declare (optimize (speed 3) (safety 0)))
205  (coerce-to-string
206  (the (or octet-concatenated-xsubseqs octet-xsubseq) header-value-buffer)))))
207 
208  (if (string= parsing-header-field "set-cookie")
209  (push header-value (gethash "set-cookie" headers))
210  (multiple-value-bind (previous-value existp)
211  (gethash (the simple-string parsing-header-field) headers)
212  (setf (gethash (the simple-string parsing-header-field) headers)
213  (if existp
214  (if (simple-string-p previous-value)
215  (concatenate 'string (the simple-string previous-value) ", " header-value)
216  (format nil "~A, ~A" previous-value header-value))
217  header-value))))))))
218  (setq callbacks
219  (make-callbacks
220  :message-begin (lambda (http)
221  (declare (ignore http))
222  (setq headers (make-hash-table :test 'equal)
223  header-complete-p nil
224  completedp nil))
225  :url (lambda (http data start end)
226  (declare (type octet-vector data)
227  (type pointer start end))
228  (setf (http-resource http)
229  (ascii-octets-to-string data :start start :end end)))
230  :status (lambda (http data start end)
231  (declare (type octet-vector data)
232  (type pointer start end))
233  (setf (http-status-text http)
234  (ascii-octets-to-string data :start start :end end)))
235  :first-line (and first-line-callback
236  (lambda (http)
237  (declare (ignore http))
238  (funcall (the function first-line-callback))))
239  :header-field (lambda (http data start end)
240  (declare (ignore http)
241  (type octet-vector data)
242  (type pointer start end))
243  (collect-prev-header-value)
244  (setq header-value-buffer (make-concatenated-xsubseqs))
245  (setq parsing-header-field
246  (ascii-octets-to-lower-string data :start start :end end)))
247  :header-value (lambda (http data start end)
248  (declare (ignore http)
249  (type octet-vector data)
250  (type pointer start end))
251  (xnconcf header-value-buffer
252  (xsubseq (subseq (the octet-vector data) start end) 0)))
253  :headers-complete (lambda (http)
254  (collect-prev-header-value)
255  (setq header-value-buffer nil)
256  (when (gethash "set-cookie" headers)
257  (setf (gethash "set-cookie" headers)
258  (nreverse (gethash "set-cookie" headers))))
259  (setf (http-headers http) headers)
260  (when header-callback
261  (funcall (the function header-callback) headers))
262  (when (and (not (http-chunked-p http))
263  (not (numberp (http-content-length http))))
264  (setq completedp t))
265  (setq header-complete-p t))
266  :body (and body-callback
267  (lambda (http data start end)
268  (declare (ignore http)
269  (type octet-vector data)
270  (type pointer start end))
271  (funcall (the function body-callback)
272  data start end)))
273  :message-complete (lambda (http)
274  (declare (ignore http))
275  (collect-prev-header-value)
276  (when finish-callback
277  (funcall (the function finish-callback)))
278  (setq completedp t)))))
279 
280  (lambda (data &key (start 0) end)
281  (declare (optimize (speed 3) (safety 2)))
282  (cond
283  ((eql data :eof)
284  (setq completedp t)
285  (when finish-callback
286  (funcall (the function finish-callback))))
287  (T
288  (locally (declare (type octet-vector data)
289  (type pointer start))
290  (check-type end (or null pointer))
291  (when data-buffer
292  (setq data
293  (coerce 'list
294  (xnconc (xsubseq data-buffer 0)
295  (xsubseq (the octet-vector data) start (or end (length data))))))
296  (setq data-buffer nil
297  start 0
298  end nil))
299  (setf (http-mark http) start)
300  (handler-case
301  (funcall parse-fn http callbacks (the octet-vector data) :start start :end end :head-request head-request)
302  (eof ()
303  (setq data-buffer
304  (subseq data (http-mark http) (or end (length data)))))))))
305  (values http header-complete-p completedp))))
306 
307 (defun find-boundary (content-type)
308  (declare (type string content-type))
309  (let ((parsing-boundary nil))
310  (parse-header-value-parameters content-type
311  :header-value-callback
312  (lambda (data start end)
313  (unless (string= data "multipart/form-data"
314  :start1 start :end1 end)
315  (return-from find-boundary nil)))
316  :header-parameter-key-callback
317  (lambda (data start end)
318  (when (string= data "boundary"
319  :start1 start :end1 end)
320  (setq parsing-boundary t)))
321  :header-parameter-value-callback
322  (lambda (data start end)
323  (when parsing-boundary
324  (return-from find-boundary (subseq data start end)))))))
325 
326 ;;; byte-vector
327 (defconstant +cr+ (char-code #\Return))
328 (defconstant +lf+ (char-code #\Linefeed))
329 (defconstant +space+ (char-code #\Space))
330 (defconstant +tab+ (char-code #\Tab))
331 (defconstant +page+ (char-code #\Page))
332 (defconstant +dash+ #.(char-code #\-))
333 
334 (define-constant +crlf+
335  (make-array 2 :element-type '(unsigned-byte 8)
336  :initial-contents (list +cr+ +lf+))
337  :test 'equalp)
338 
339 (deftype octet-vector (&optional (len '*))
340  `(simple-array (unsigned-byte 8) (,len)))
341 
342 (declaim (inline digit-byte-char-p
343  digit-byte-char-to-integer
344  alpha-byte-char-p
345  alpha-byte-char-to-lower-char
346  alphanumeric-byte-char-p
347  mark-byte-char-p))
348 
349 (defun digit-byte-char-p (byte)
350  (declare (type (unsigned-byte 8) byte)
351  (optimize (speed 3) (safety 0)))
352  (<= #.(char-code #\0) byte #.(char-code #\9)))
353 
354 (declaim (ftype (function ((unsigned-byte 8)) fixnum) digit-byte-char-to-integer))
355 (defun digit-byte-char-to-integer (byte)
356  (declare (type (unsigned-byte 8) byte)
357  (optimize (speed 3) (safety 0)))
358  (the fixnum (- byte #.(char-code #\0))))
359 
360 (defun alpha-byte-char-p (byte)
361  (declare (type (unsigned-byte 8) byte)
362  (optimize (speed 3) (safety 0)))
363  (or (<= #.(char-code #\A) byte #.(char-code #\Z))
364  (<= #.(char-code #\a) byte #.(char-code #\z))))
365 
366 (defun alpha-byte-char-to-lower-char (byte)
367  (declare (type (unsigned-byte 8) byte)
368  (optimize (speed 3) (safety 0)))
369  (the character
370  (cond
371  ((<= #.(char-code #\A) byte #.(char-code #\Z))
372  (code-char (+ byte #x20)))
373  (T #+nil(<= #.(char-code #\a) byte #.(char-code #\z))
374  (code-char byte)))))
375 
376 (defun alphanumeric-byte-char-p (byte)
377  (declare (type (unsigned-byte 8) byte))
378  (or (alpha-byte-char-p byte)
379  (digit-byte-char-p byte)))
380 
381 (defun mark-byte-char-p (byte)
382  (declare (type (unsigned-byte 8) byte)
383  (optimize (speed 3) (safety 0)))
384  (or (= byte #.(char-code #\-))
385  (= byte #.(char-code #\_))
386  (= byte #.(char-code #\.))
387  (= byte #.(char-code #\!))
388  (= byte #.(char-code #\~))
389  (= byte #.(char-code #\*))
390  (= byte #.(char-code #\'))
391  (= byte #.(char-code #\())
392  (= byte #.(char-code #\)))))
393 
394 (declaim (ftype (function ((unsigned-byte 8)) (unsigned-byte 8)) byte-to-ascii-lower)
395  (inline byte-to-ascii-lower))
396 (defun byte-to-ascii-lower (x)
397  (declare (type (unsigned-byte 8) x)
398  (optimize (speed 3) (safety 0)))
399  (if (<= #.(char-code #\A) x #.(char-code #\Z))
400  (- x #.(- (char-code #\A) (char-code #\a)))
401  x))
402 
403 (declaim (inline ascii-octets-to-string))
404 (defun ascii-octets-to-string (octets &key (start 0) (end (length octets)))
405  (declare (type octet-vector octets)
406  (type (unsigned-byte 64) start end)
407  (optimize (speed 3) (safety 0)))
408  (let* ((len (the (unsigned-byte 64) (- end start)))
409  (string (make-string len :element-type 'character)))
410  (declare (type (unsigned-byte 64) len)
411  (type simple-string string))
412  (do ((i 0 (1+ i))
413  (j start (1+ j)))
414  ((= j end) string)
415  (setf (aref string i)
416  (code-char (aref octets j))))))
417 
418 (declaim (inline ascii-octets-to-lower-string))
419 (defun ascii-octets-to-lower-string (octets &key (start 0) (end (length octets)))
420  (declare (type octet-vector octets)
421  (type (unsigned-byte 64) start end)
422  (optimize (speed 3) (safety 0)))
423  (let* ((len (the (unsigned-byte 64) (- end start)))
424  (string (make-string len :element-type 'character)))
425  (declare (type (unsigned-byte 64) len)
426  (type simple-string string))
427  (do ((i 0 (1+ i))
428  (j start (1+ j)))
429  ((= j end) string)
430  (setf (aref string i)
431  (code-char (byte-to-ascii-lower (aref octets j)))))))
432 
433 (defun append-byte-vectors (vec1 vec2)
434  (declare (type octet-vector vec1 vec2)
435  (optimize (speed 3) (safety 0)))
436  (let* ((vec1-len (length vec1))
437  (vec2-len (length vec2))
438  (result (make-array (+ vec1-len vec2-len)
439  :element-type '(unsigned-byte 8))))
440  (declare (type octet-vector result))
441  (replace result vec1 :start1 0)
442  (replace result vec2 :start1 vec1-len)
443  result))
444 
445 ;;; multipart-parser
446 (defstruct (ll-multipart-parser (:constructor make-ll-multipart-parser
447  (&key boundary
448  &aux (header-parser
449  (let ((parser (make-http)))
450  (setf (http-state parser) +state-headers+)
451  parser)))))
452  (state 0 :type fixnum)
453  (header-parser)
454  boundary
455  body-mark
456  body-buffer
457  boundary-mark
458  boundary-buffer)
459 
460 #.`(eval-when (:compile-toplevel :load-toplevel :execute)
461  ,@(loop for i from 0
462  for state in '(parsing-delimiter-dash-start
463  parsing-delimiter-dash
464  parsing-delimiter
465  parsing-delimiter-end
466  parsing-delimiter-almost-done
467  parsing-delimiter-done
468  header-field-start
469  body-start
470  looking-for-delimiter
471  maybe-delimiter-start
472  maybe-delimiter-first-dash
473  maybe-delimiter-second-dash
474  body-almost-done
475  body-done)
476  collect `(defconstant ,(format-symbol t "+~A+" state) ,i)))
477 
478 (defun http-multipart-parse (parser callbacks data &key (start 0) end)
479  (declare (type octet-vector data))
480  (let* ((end (or end (length data)))
481  (boundary (map '(simple-array (unsigned-byte 8) (*)) #'char-code (ll-multipart-parser-boundary parser)))
482  (boundary-length (length boundary))
483  (header-parser (ll-multipart-parser-header-parser parser)))
484  (declare (type octet-vector boundary))
485  (when (= start end)
486  (return-from http-multipart-parse start))
487 
488  (macrolet ((with-body-cb (callback &body body)
489  `(handler-case (when-let ((,callback (callbacks-body callbacks)))
490  ,@body)
491  (error (e)
492  (error 'cb-body :error e))))
493  (call-body-cb (&optional (end '(ll-multipart-parser-boundary-mark parser)))
494  (let ((g-end (gensym "END")))
495  `(with-body-cb callback
496  (when (ll-multipart-parser-body-buffer parser)
497  (funcall callback parser
498  (ll-multipart-parser-body-buffer parser)
499  0 (length (ll-multipart-parser-body-buffer parser)))
500  (setf (ll-multipart-parser-body-buffer parser) nil))
501  (when-let ((,g-end ,end))
502  (funcall callback parser data
503  (ll-multipart-parser-body-mark parser)
504  ,g-end)))))
505  (flush-boundary-buffer ()
506  `(with-body-cb callback
507  (when (ll-multipart-parser-boundary-buffer parser)
508  (funcall callback parser
509  (ll-multipart-parser-boundary-buffer parser)
510  0 (length (ll-multipart-parser-boundary-buffer parser)))
511  (setf (ll-multipart-parser-boundary-buffer parser) nil)))))
512  (let* ((p start)
513  (byte (aref data p)))
514  #+http-debug
515  (log:debug (code-char byte))
516  (tagbody
517  (macrolet ((go-state (tag &optional (advance 1))
518  `(progn
519  ,(case advance
520  (0 ())
521  (1 '(incf p))
522  (otherwise `(incf p ,advance)))
523  (setf (ll-multipart-parser-state parser) ,tag)
524  #+http-debug
525  (log:debug ,(princ-to-string tag))
526  ,@(and (not (eql advance 0))
527  `((when (= p end)
528  (go exit-loop))
529  (setq byte (aref data p))
530  #+http-debug
531  (log:debug (code-char byte))))
532  (go ,tag))))
533  (tagcasev (ll-multipart-parser-state parser)
534  (+parsing-delimiter-dash-start+
535  (unless (= byte +dash+)
536  (go-state +header-field-start+ 0))
537  (go-state +parsing-delimiter-dash+))
538 
539  (+parsing-delimiter-dash+
540  (unless (= byte +dash+)
541  (error 'invalid-multipart-body))
542  (go-state +parsing-delimiter+))
543 
544  (+parsing-delimiter+
545  (let ((end2 (+ p boundary-length)))
546  (cond
547  ((ll-multipart-parser-boundary-buffer parser)
548  (when (< (+ end (length (ll-multipart-parser-boundary-buffer parser)) -3) end2)
549  (setf (ll-multipart-parser-boundary-buffer parser)
550  (concatenate 'octet-vector
551  (ll-multipart-parser-boundary-buffer parser)
552  data))
553  (go exit-loop))
554  (let ((data2 (make-array boundary-length :element-type '(unsigned-byte 8)))
555  (boundary-buffer-length (length (ll-multipart-parser-boundary-buffer parser))))
556  (replace data2 (ll-multipart-parser-boundary-buffer parser)
557  :start2 2)
558  (replace data2 data
559  :start1 (- boundary-buffer-length 2))
560  (unless (search boundary data2)
561  ;; Still in the body
562  (when (ll-multipart-parser-body-mark parser)
563  (call-body-cb nil)
564  (flush-boundary-buffer)
565  (go-state +looking-for-delimiter+))
566  (error 'invalid-boundary))
567  (go-state +parsing-delimiter-end+ (- boundary-length boundary-buffer-length -2))))
568  ((< (1- end) end2)
569  ;; EOF
570  (setf (ll-multipart-parser-boundary-buffer parser)
571  (if (ll-multipart-parser-boundary-buffer parser)
572  (concatenate 'octet-vector
573  (ll-multipart-parser-boundary-buffer parser)
574  (subseq data (max 0 (- p 2))))
575  (subseq data (max 0 (- p 2)))))
576  (go exit-loop))
577  (T
578  (unless (search boundary data :start2 p :end2 end2)
579  ;; Still in the body
580  (when (ll-multipart-parser-body-mark parser)
581  (go-state +looking-for-delimiter+))
582  (error 'invalid-boundary))
583  (go-state +parsing-delimiter-end+ boundary-length)))))
584 
585  (+parsing-delimiter-end+
586  (casev byte
587  (+cr+ (go-state +parsing-delimiter-almost-done+))
588  (+lf+ (go-state +parsing-delimiter-almost-done+ 0))
589  (+dash+ (go-state +body-almost-done+))
590  (otherwise
591  ;; Still in the body
592  (when (ll-multipart-parser-body-mark parser)
593  (call-body-cb nil)
594  (flush-boundary-buffer)
595  (go-state +looking-for-delimiter+))
596  (error 'invalid-boundary))))
597 
598  (+parsing-delimiter-almost-done+
599  (unless (= byte +lf+)
600  (error 'invalid-boundary))
601  (when (ll-multipart-parser-body-mark parser)
602  ;; got a part
603  (when (ll-multipart-parser-boundary-mark parser)
604  (call-body-cb))
605  (when-let ((callback (callbacks-message-complete callbacks)))
606  (handler-case (funcall callback parser)
607  (error (e)
608  (error 'cb-message-complete :error e)))))
609  (go-state +parsing-delimiter-done+))
610 
611  (+parsing-delimiter-done+
612  (when-let ((callback (callbacks-message-begin callbacks)))
613  (handler-case (funcall callback parser)
614  (error (e)
615  (error 'cb-message-begin :error e))))
616  (setf (ll-multipart-parser-body-mark parser) p)
617  (go-state +header-field-start+ 0))
618 
619  (+header-field-start+
620  (let ((next (parse-headers header-parser callbacks data p end)))
621  (setq p (1- next)) ;; XXX
622  ;; parsing headers done
623  (when (= (http-state header-parser) +state-body+)
624  (when-let ((callback (callbacks-headers-complete callbacks)))
625  (handler-case (funcall callback parser)
626  (error (e)
627  (error 'cb-headers-complete :error e))))
628  (setf (http-state header-parser) +state-headers+))
629  (go-state +body-start+ 0)))
630 
631  (+body-start+
632  (setf (ll-multipart-parser-body-mark parser) (1+ p))
633  (go-state +looking-for-delimiter+))
634 
635  (+looking-for-delimiter+
636  (setf (ll-multipart-parser-boundary-mark parser) nil)
637  (casev byte
638  (+cr+ (setf (ll-multipart-parser-boundary-mark parser) p)
639  (go-state +maybe-delimiter-start+))
640  (otherwise (go-state +looking-for-delimiter+))))
641 
642  (+maybe-delimiter-start+
643  (unless (= byte +lf+)
644  (go-state +looking-for-delimiter+ 0))
645  (go-state +maybe-delimiter-first-dash+))
646 
647  (+maybe-delimiter-first-dash+
648  (if (= byte +dash+)
649  (go-state +maybe-delimiter-second-dash+)
650  (if (= byte +cr+)
651  (progn
652  (setf (ll-multipart-parser-boundary-mark parser) p)
653  (go-state +maybe-delimiter-start+))
654  (go-state +looking-for-delimiter+))))
655 
656  (+maybe-delimiter-second-dash+
657  (if (= byte +dash+)
658  (go-state +parsing-delimiter+)
659  (go-state +looking-for-delimiter+)))
660 
661  (+body-almost-done+
662  (casev byte
663  (+dash+ (go-state +body-done+ 0))
664  (otherwise (error 'invalid-multipart-body))))
665 
666  (+body-done+
667  (when (ll-multipart-parser-body-mark parser)
668  ;; got a part
669  (setf (ll-multipart-parser-body-buffer parser) nil)
670  (call-body-cb)
671  (when-let ((callback (callbacks-message-complete callbacks)))
672  (handler-case (funcall callback parser)
673  (error (e)
674  (error 'cb-message-complete :error e))))
675  (setf (ll-multipart-parser-body-mark parser) nil))
676  (go exit-loop))))
677  exit-loop)
678  (when (ll-multipart-parser-body-mark parser)
679  (when (<= +looking-for-delimiter+
680  (ll-multipart-parser-state parser)
681  +maybe-delimiter-second-dash+)
682  (call-body-cb (or (ll-multipart-parser-boundary-mark parser) p)))
683  ;; buffer the last part
684  (when (ll-multipart-parser-boundary-mark parser)
685  (setf (ll-multipart-parser-body-buffer parser)
686  (if (ll-multipart-parser-body-buffer parser)
687  (concatenate 'octet-vector
688  (ll-multipart-parser-body-buffer parser)
689  (subseq data (ll-multipart-parser-boundary-mark parser)))
690  (subseq data (ll-multipart-parser-boundary-mark parser)))))
691 
692  (setf (ll-multipart-parser-body-mark parser) 0
693  (ll-multipart-parser-boundary-mark parser) nil))
694  p))))
695 
696 (defun make-multipart-parser (content-type callback)
697  (check-type content-type string)
698  (let ((boundary (find-boundary content-type)))
699  (unless boundary
700  (return-from make-multipart-parser nil))
701 
702  (let ((parser (make-ll-multipart-parser :boundary boundary))
703  (headers (make-hash-table :test 'equal))
704  parsing-content-disposition
705  parsing-header-field
706  field-meta
707  header-value-buffer
708  (body-buffer (make-smart-buffer))
709  callbacks)
710  (flet ((collect-prev-header-value ()
711  (when header-value-buffer
712  (let ((header-value
713  (babel:octets-to-string
714  header-value-buffer)))
715  (when parsing-content-disposition
716  (setq field-meta
717  (let (parsing-key
718  (field-meta (make-hash-table :test 'equal)))
719  (parse-header-value-parameters header-value
720  :header-parameter-key-callback
721  (lambda (data start end)
722  (setq parsing-key
723  (string-downcase (subseq data start end))))
724  :header-parameter-value-callback
725  (lambda (data start end)
726  (setf (gethash parsing-key field-meta)
727  (subseq data start end))))
728  field-meta)))
729  (setf (gethash parsing-header-field headers)
730  header-value)))))
731  (setq callbacks
732  (make-callbacks
733  :header-field (lambda (parser data start end)
734  (declare (ignore parser))
735  (collect-prev-header-value)
736  (setq header-value-buffer (make-concatenated-xsubseqs))
737 
738  (let ((header-name
739  (ascii-octets-to-lower-string data :start start :end end)))
740  (setq parsing-content-disposition
741  (string= header-name "content-disposition"))
742  (setq parsing-header-field header-name)))
743  :header-value (lambda (parser data start end)
744  (declare (ignore parser))
745  (xnconcf header-value-buffer
746  (subseq (subseq data start end) 0)))
747  :headers-complete (lambda (parser)
748  (declare (ignore parser))
749  (collect-prev-header-value))
750  :message-complete (lambda (parser)
751  (declare (ignore parser))
752  (funcall callback
753  (gethash "name" field-meta)
754  headers
755  field-meta
756  body-buffer)
757  (setq headers (make-hash-table :test 'equal)
758  body-buffer (vector)
759  header-value-buffer nil))
760  :body (lambda (parser data start end)
761  (declare (ignore parser))
762  (write-sequence data body-buffer start end)))))
763  (lambda (data)
764  (http-multipart-parse parser callbacks data)
765  (= (ll-multipart-parser-state parser) +body-done+)))))
766 
767 ;;; http
768 ;;
769 ;; Types
770 
771 (deftype status-code () '(integer 0 10000))
772 
773 ;;
774 ;; States
775 
776 (defconstant +state-first-line+ 0)
777 (defconstant +state-headers+ 1)
778 (defconstant +state-chunk-size+ 2)
779 (defconstant +state-body+ 3)
780 (defconstant +state-chunk-body-end-crlf+ 4)
781 (defconstant +state-trailing-headers+ 5)
782 
783 (defstruct (http (:conc-name :http-))
784  (method nil :type symbol)
785  (major-version 0 :type fixnum)
786  (minor-version 9 :type fixnum)
787  (status 0 :type status-code)
788  (content-length nil :type (or null integer))
789  (chunked-p nil :type boolean)
790  (upgrade-p nil :type boolean)
791 
792  headers
793 
794  ;; private
795  (header-read 0 :type fixnum)
796  (mark -1 :type fixnum)
797  (state +state-first-line+ :type fixnum))
798 
799 (defun http-version (http)
800  (float
801  (+ (http-major-version http)
802  (/ (http-minor-version http) 10))))
803 
804 (defstruct (http-request (:include http)
805  (:conc-name :http-))
806  resource)
807 
808 (defstruct (http-response (:include http)
809  (:conc-name :http-))
810  status-text)
811 
812 ;;; Errors
813 (define-condition http-error (protocol-error)
814  (description)
815  (:report
816  (lambda (condition stream)
817  (format stream "~A: ~A" (type-of condition) (slot-value condition 'description)))))
818 
819 
820 ;;
821 ;; Callback-related errors
822 
823 (define-condition callback-error (http-error)
824  ((error :initarg :error
825  :initform nil))
826  (:report (lambda (condition stream)
827  (with-slots (description error) condition
828  (format stream "Callback Error: ~A~:[~;~:*~% ~A~]"
829  description
830  error)))))
831 
832 (define-condition cb-message-begin (callback-error)
833  ((description :initform "the message-begin callback failed")))
834 (define-condition cb-url (callback-error)
835  ((description :initform "the url callback failed")))
836 (define-condition cb-first-line (callback-error)
837  ((description :initform "the first line callback failed")))
838 (define-condition cb-header-field (callback-error)
839  ((description :initform "the header-field callback failed")))
840 (define-condition cb-header-value (callback-error)
841  ((description :initform "the header-value callback failed")))
842 (define-condition cb-headers-complete (callback-error)
843  ((description :initform "the headers-complete callback failed")))
844 (define-condition cb-body (callback-error)
845  ((description :initform "the body callback failed")))
846 (define-condition cb-message-complete (callback-error)
847  ((description :initform "the message-complete callback failed")))
848 (define-condition cb-status (callback-error)
849  ((description :initform "the status callback failed")))
850 
851 ;;
852 ;; Parsing-related errors
853 
854 (define-condition parsing-error (http-error) ())
855 
856 (define-condition invalid-eof-state (parsing-error)
857  ((description :initform "stream ended at an unexpected time")))
858 (define-condition header-overflow (parsing-error)
859  ((description :initform "too many header bytes seen; overflow detected")))
860 (define-condition closed-connection (parsing-error)
861  ((description :initform "data received after completed connection: close message")))
862 (define-condition invalid-version (parsing-error)
863  ((description :initform "invalid HTTP version")))
864 (define-condition invalid-status (parsing-error)
865  ((description :initform "invalid HTTP status code")
866  (status-code :initarg :status-code
867  :initform nil))
868  (:report (lambda (condition stream)
869  (with-slots (description status-code) condition
870  (format stream "~A: ~A~:[~;~:* (Code=~A)~]"
871  (type-of condition)
872  description
873  status-code)))))
874 (define-condition invalid-method (parsing-error)
875  ((description :initform "invalid HTTP method")))
876 (define-condition invalid-url (parsing-error)
877  ((description :initform "invalid URL")))
878 (define-condition invalid-host (parsing-error)
879  ((description :initform "invalid host")))
880 (define-condition invalid-port (parsing-error)
881  ((description :initform "invalid port")))
882 (define-condition invalid-path (parsing-error)
883  ((description :initform "invalid path")))
884 (define-condition invalid-query-string (parsing-error)
885  ((description :initform "invalid query string")))
886 (define-condition invalid-fragment (parsing-error)
887  ((description :initform "invalid fragment")))
888 (define-condition lf-expected (parsing-error)
889  ((description :initform "LF character expected")))
890 (define-condition invalid-header-token (parsing-error)
891  ((description :initform "invalid character in header")))
892 (define-condition invalid-content-length (parsing-error)
893  ((description :initform "invalid character in content-length header")))
894 (define-condition invalid-chunk-size (parsing-error)
895  ((description :initform "invalid character in chunk size header")))
896 (define-condition invalid-constant (parsing-error)
897  ((description :initform "invalid constant string")))
898 
899 (define-condition invalid-internal-state (parsing-error)
900  ((description :initform "encountered unexpected internal state")
901  (code :initarg :code))
902  (:report
903  (lambda (condition stream)
904  (format stream "~A: ~A (Code=~A)"
905  (type-of condition)
906  (slot-value condition 'description)
907  (slot-value condition 'code)))))
908 (define-condition strict-error (parsing-error)
909  ((description :initform "strict mode assertion failed")
910  (form :initarg :form))
911  (:report
912  (lambda (condition stream)
913  (format stream "~A: ~A~% ~A"
914  (type-of condition)
915  (slot-value condition 'description)
916  (slot-value condition 'form)))))
917 (define-condition paused-error (parsing-error)
918  ((description :initform "parser is paused")))
919 (define-condition unknown-error (parsing-error)
920  ((description :initform "an unknown error occured")))
921 
922 
923 ;;
924 ;; Multipart parsing
925 
926 (define-condition multipart-parsing-error (http-error) ())
927 
928 (define-condition invalid-multipart-body (multipart-parsing-error)
929  ((description :initform "invalid multipart body")))
930 (define-condition invalid-boundary (multipart-parsing-error)
931  ((description :initform "invalid boundary")))
932 
933 
934 ;;
935 ;; Header value parsing
936 
937 (define-condition header-value-parsing-error (multipart-parsing-error) ())
938 
939 (define-condition invalid-header-value (header-value-parsing-error)
940  ((description :initform "invalid header value")))
941 (define-condition invalid-parameter-key (header-value-parsing-error)
942  ((description :initform "invalid parameter key")))
943 (define-condition invalid-parameter-value (header-value-parsing-error)
944  ((description :initform "invalid parameter value")))
945 
946 ;;; parser
947 ;;
948 ;; Variables
949 
950 (declaim (type fixnum +max-header-line+))
951 (defconstant +max-header-line+ 1024
952  "Maximum number of header lines allowed.
953 
954 This restriction is for protecting users' application
955 against denial-of-service attacks where the attacker feeds
956 us a never-ending header that the application keeps buffering.")
957 
958 
959 ;;
960 ;; Types
961 
962 (deftype pointer () 'integer)
963 
964 
965 ;;
966 ;; Callbacks
967 
968 (defstruct callbacks
969  (message-begin nil :type (or null function)) ;; 1 arg
970  (url nil :type (or null function))
971  (first-line nil :type (or null function))
972  (status nil :type (or null function))
973  (header-field nil :type (or null function))
974  (header-value nil :type (or null function))
975  (headers-complete nil :type (or null function)) ;; 1 arg
976  (body nil :type (or null function))
977  (message-complete nil :type (or null function)))
978 
979 (defmacro callback-data (name http callbacks data start end)
980  (with-gensyms (callback e)
981  `(when-let ((,callback (,(format-symbol t "~A-~A" :callbacks name) ,callbacks)))
982  (handler-bind ((error
983  (lambda (,e)
984  (unless (typep ,e 'http-error)
985  (error ',(format-symbol t "~A-~A" :cb name)
986  :error ,e)
987  (abort ,e)))))
988  (funcall ,callback ,http ,data ,start ,end)))))
989 
990 (defmacro callback-notify (name http callbacks)
991  (with-gensyms (callback e)
992  `(when-let ((,callback (,(format-symbol t "~A-~A" :callbacks name) ,callbacks)))
993  (handler-bind ((error
994  (lambda (,e)
995  (unless (typep ,e 'http-error)
996  (error ',(format-symbol t "~A-~A" :cb name)
997  :error ,e)
998  (abort ,e)))))
999  (funcall ,callback ,http)))))
1000 
1001 
1002 ;;
1003 ;; Parser utilities
1004 
1005 (define-condition eof () ())
1006 
1007 (define-condition expect-failed (parsing-error)
1008  ((description :initform "expect failed")))
1009 
1010 
1011 ;;
1012 ;; Tokens
1013 
1014 (declaim (type (simple-array character (128)) +tokens+))
1015 (define-constant +tokens+
1016  (make-array 128
1017  :element-type 'character
1018  :initial-contents
1019  '( #\Nul #\Nul #\Nul #\Nul #\Nul #\Nul #\Nul #\Nul
1020  #\Nul #\Nul #\Nul #\Nul #\Nul #\Nul #\Nul #\Nul
1021  #\Nul #\Nul #\Nul #\Nul #\Nul #\Nul #\Nul #\Nul
1022  #\Nul #\Nul #\Nul #\Nul #\Nul #\Nul #\Nul #\Nul
1023  #\Nul #\! #\Nul #\# #\$ #\% #\& #\'
1024  #\Nul #\Nul #\* #\+ #\Nul #\- #\. #\Nul
1025  #\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7
1026  #\8 #\9 #\Nul #\Nul #\Nul #\Nul #\Nul #\Nul
1027  #\Nul #\a #\b #\c #\d #\e #\f #\g
1028  #\h #\i #\j #\k #\l #\m #\n #\o
1029  #\p #\q #\r #\s #\t #\u #\v #\w
1030  #\x #\y #\z #\Nul #\Nul #\Nul #\^ #\_
1031  #\` #\a #\b #\c #\d #\e #\f #\g
1032  #\h #\i #\j #\k #\l #\m #\n #\o
1033  #\p #\q #\r #\s #\t #\u #\v #\w
1034  #\x #\y #\z #\Nul #\| #\Nul #\~ #\Nul ))
1035  :test 'equalp)
1036 
1037 (declaim (type (simple-array fixnum (128)) +unhex+))
1038 (define-constant +unhex+
1039  (make-array 128 :element-type 'fixnum :initial-contents
1040  '(-1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
1041  -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
1042  -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
1043  0 1 2 3 4 5 6 7 8 9 -1 -1 -1 -1 -1 -1
1044  -1 10 11 12 13 14 15 -1 -1 -1 -1 -1 -1 -1 -1 -1
1045  -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
1046  -1 10 11 12 13 14 15 -1 -1 -1 -1 -1 -1 -1 -1 -1
1047  -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1))
1048  :test 'equalp)
1049 
1050 (defun unhex-byte (byte)
1051  (aref +unhex+ byte))
1052 
1053 ;;
1054 ;; Main
1055 
1056 (defun parse-method (data start end)
1057  (declare (type octet-vector data)
1058  (type pointer start end))
1059  (with-octets-parsing (data :start start :end end)
1060  (return-from parse-method
1061  (values
1062  (prog1
1063  (match-case
1064  ("CONNECT" :CONNECT)
1065  ("COPY" :COPY)
1066  ("CHECKOUT" :CHECKOUT)
1067  ("DELETE" :DELETE)
1068  ("GET" :GET)
1069  ("HEAD" :HEAD)
1070  ("LOCK" :LOCK)
1071  ("MKCOL" :MKCOL)
1072  ("MKCALENDAR" :MKCALENDAR)
1073  ("MKACTIVITY" :MKACTIVITY)
1074  ("MOVE" :MOVE)
1075  ("MERGE" :MERGE)
1076  ("M-SEARCH" :M-SEARCH)
1077  ("NOTIFY" :NOTIFY)
1078  ("OPTIONS" :OPTIONS)
1079  ("POST" :POST)
1080  ("PROPFIND" :PROPFIND)
1081  ("PROPPATCH" :PROPPATCH)
1082  ("PUT" :PUT)
1083  ("PURGE" :PURGE)
1084  ("PATCH" :PATCH)
1085  ("REPORT" :REPORT)
1086  ("SEARCH" :SEARCH)
1087  ("SUBSCRIBE" :SUBSCRIBE)
1088  ("TRACE" :TRACE)
1089  ("UNLOCK" :UNLOCK)
1090  ("UNSUBSCRIBE" :UNSUBSCRIBE)
1091  (otherwise (error 'invalid-method)))
1092  (unless (= (current) +space+)
1093  (error 'invalid-method)))
1094  (pos))))
1095  (error 'eof))
1096 
1097 (defun parse-url (data start end)
1098  (declare (type octet-vector data)
1099  (type pointer start end))
1100  (flet ((url-char-byte-p (byte)
1101  (or (<= (char-code #\!) byte (char-code #\~))
1102  (<= 128 byte))))
1103  (with-octets-parsing (data :start start :end end)
1104  (skip-while url-char-byte-p)
1105  (return-from parse-url (pos)))
1106  (error 'eof)))
1107 
1108 (defun parse-http-version (data start end)
1109  (declare (type octet-vector data)
1110  (type pointer start end))
1111  (let (major minor)
1112  (with-octets-parsing (data :start start :end end)
1113  (or (match? "HTTP/")
1114  (return-from parse-http-version (values nil nil (pos))))
1115  (if (digit-byte-char-p (current))
1116  (setq major (digit-byte-char-to-integer (current)))
1117  (return-from parse-http-version (values nil nil (pos))))
1118  (advance)
1119  (or (skip? #\.) (return-from parse-http-version (values nil nil (pos))))
1120  (if (digit-byte-char-p (current))
1121  (setq minor (digit-byte-char-to-integer (current)))
1122  (return-from parse-http-version (values nil nil (pos))))
1123  (advance)
1124  (return-from parse-http-version
1125  (values major minor (pos))))
1126  (error 'eof)))
1127 
1128 (defun parse-status-code (http callbacks data start end)
1129  (declare (type octet-vector data)
1130  (type pointer start end))
1131  (or (with-octets-parsing (data :start start :end end)
1132  (if (digit-byte-char-p (current))
1133  (setf (http-status http) (digit-byte-char-to-integer (current)))
1134  (error 'invalid-status))
1135  (loop
1136  (advance)
1137  (cond
1138  ((digit-byte-char-p (current))
1139  (setf (http-status http)
1140  (+ (the fixnum (* 10 (http-status http)))
1141  (digit-byte-char-to-integer (current))))
1142  (when (< 999 (http-status http))
1143  (error 'invalid-status :status-code (http-status http))))
1144  ((= (current) +space+)
1145  ;; Reading the status text
1146  (advance)
1147  (let ((status-text-start (pos)))
1148  (skip* (not #\Return))
1149  (advance)
1150  (skip #\Newline)
1151  (callback-data :status http callbacks data status-text-start (- (pos) 1)))
1152  (return))
1153  ((= (current) +cr+)
1154  ;; No status text
1155  (advance)
1156  (skip #\Newline)
1157  (return))
1158  (T (error 'invalid-status))))
1159  (pos))
1160  (error 'eof)))
1161 
1162 (defun parse-header-field-and-value (http callbacks data start end)
1163  (declare (type octet-vector data)
1164  (type pointer start end))
1165  (or
1166  (with-octets-parsing (data :start start :end end)
1167  (let ((field-start (pos))
1168  field-end)
1169  (macrolet ((skip-until-value-start-and (&body body)
1170  `(progn
1171  ;; skip #\: and leading spaces
1172  (skip #\:)
1173  (skip* #\Space #\Tab)
1174  (cond
1175  ((= (current) +cr+)
1176  ;; continue to the next line
1177  (advance)
1178  (skip #\Newline)
1179  (cond
1180  ((or (= (current) +space+)
1181  (= (current) +tab+))
1182  (skip* #\Space #\Tab)
1183  (if (= (current) +cr+)
1184  ;; empty body
1185  (progn
1186  (advance)
1187  (skip #\Newline)
1188  (callback-data :header-field http callbacks data field-start field-end)
1189  (callback-data :header-value http callbacks data (pos) (pos)))
1190  (progn ,@body)))
1191  ;; empty body
1192  (t
1193  (callback-data :header-field http callbacks data field-start field-end)
1194  (callback-data :header-value http callbacks data (pos) (pos)))))
1195  (t ,@body))))
1196  (handle-otherwise ()
1197  `(progn
1198  ;; skip until field end
1199  (do ((char (aref +tokens+ (current))
1200  (aref +tokens+ (current))))
1201  ((= (current) (char-code #\:)))
1202  (declare (type character char))
1203  (when (char= char #\Nul)
1204  (error 'invalid-header-token))
1205  (advance))
1206 
1207  (setq field-end (pos))
1208  (skip-until-value-start-and
1209  (advance-to*
1210  (parse-header-value http callbacks data (pos) end field-start field-end)))))
1211  (expect-field-end (&body body)
1212  `(if (= (current) #.(char-code #\:))
1213  (progn
1214  (setq field-end (pos))
1215  ,@body)
1216  (handle-otherwise))))
1217  (match-i-case
1218  ("content-length"
1219  (expect-field-end
1220  (skip-until-value-start-and
1221  (multiple-value-bind (value-start value-end next content-length)
1222  (parse-header-value-content-length data (pos) end)
1223  (declare (type pointer next))
1224  (setf (http-content-length http) content-length)
1225  (advance-to* next)
1226  (callback-data :header-field http callbacks data field-start field-end)
1227  (callback-data :header-value http callbacks data value-start value-end)))))
1228  ("transfer-encoding"
1229  (expect-field-end
1230  (skip-until-value-start-and
1231  (multiple-value-bind (value-start value-end next chunkedp)
1232  (parse-header-value-transfer-encoding data (pos) end)
1233  (declare (type pointer next))
1234  (setf (http-chunked-p http) chunkedp)
1235  (advance-to* next)
1236  (callback-data :header-field http callbacks data field-start field-end)
1237  (callback-data :header-value http callbacks data value-start value-end)))))
1238  ("upgrade"
1239  (expect-field-end
1240  (skip-until-value-start-and
1241  (setf (http-upgrade-p http) T)
1242  (let ((value-start (pos)))
1243  (skip* (not #\Return))
1244  (advance)
1245  (skip #\Newline)
1246  (callback-data :header-field http callbacks data field-start field-end)
1247  (callback-data :header-value http callbacks data value-start (- (pos) 2))))))
1248  (otherwise (handle-otherwise)))))
1249  (pos))
1250  (error 'eof)))
1251 
1252 (defun parse-header-value (http callbacks data start end &optional field-start field-end)
1253  (or (with-octets-parsing (data :start start :end end)
1254  (skip* (not #\Return))
1255  (advance)
1256  (skip #\Newline)
1257  (when field-start
1258  (callback-data :header-field http callbacks data field-start field-end))
1259  (callback-data :header-value http callbacks data start (- (pos) 2))
1260  (pos))
1261  (error 'eof)))
1262 
1263 (defun parse-header-value-transfer-encoding (data start end)
1264  (declare (type octet-vector data)
1265  (type pointer start end))
1266  (with-octets-parsing (data :start start :end end)
1267  (match-i-case
1268  ("chunked"
1269  (if (= (current) +cr+)
1270  (progn
1271  (advance)
1272  (skip #\Newline)
1273  (return-from parse-header-value-transfer-encoding
1274  (values start (- (pos) 2) (pos) t)))
1275  (progn
1276  (skip+ (not #\Return))
1277  (advance)
1278  (skip #\Newline)
1279  (return-from parse-header-value-transfer-encoding
1280  (values start (- (pos) 2) (pos) nil)))))
1281  (otherwise
1282  (skip* (not #\Return))
1283  (advance)
1284  (skip #\Newline)
1285  (return-from parse-header-value-transfer-encoding
1286  (values start (- (pos) 2) (pos) nil)))))
1287  (error 'eof))
1288 
1289 (defun parse-header-value-content-length (data start end)
1290  (declare (type octet-vector data)
1291  (type pointer start end))
1292  (let ((content-length 0))
1293  (declare (type integer content-length))
1294  (with-octets-parsing (data :start start :end end)
1295  (if (digit-byte-char-p (current))
1296  (setq content-length (digit-byte-char-to-integer (current)))
1297  (error 'invalid-content-length))
1298  (loop
1299  (advance)
1300  (cond
1301  ((digit-byte-char-p (current))
1302  (setq content-length
1303  (+ (* 10 content-length)
1304  (digit-byte-char-to-integer (current)))))
1305  ((= (current) +cr+)
1306  (advance)
1307  (skip #\Newline)
1308  (return-from parse-header-value-content-length
1309  (values start (- (pos) 2) (pos) content-length)))
1310  ((= (current) +space+)
1311  ;; Discard spaces
1312  )
1313  (t (error 'invalid-content-length)))))
1314  (error 'eof)))
1315 
1316 (defun parse-header-line (http callbacks data start end)
1317  (declare (type octet-vector data)
1318  (type pointer start end))
1319  (when (<= end start)
1320  (error 'eof))
1321  (let ((current (aref data start)))
1322  (declare (type (unsigned-byte 8) current))
1323  (cond
1324  ((or (= current +tab+)
1325  (= current +space+))
1326  (parse-header-value http callbacks data start end))
1327  ((/= current +cr+)
1328  (parse-header-field-and-value http callbacks data start end))
1329  (t
1330  (incf start)
1331  (when (= start end)
1332  (error 'eof))
1333  (setq current (aref data start))
1334  (unless (= current +lf+)
1335  (error 'expect-failed))
1336  (values (1+ start) t)))))
1337 
1338 (defun parse-headers (http callbacks data start end)
1339  (declare (type http http)
1340  (type octet-vector data)
1341  (type pointer start end))
1342  (or (with-octets-parsing (data :start start :end end)
1343  ;; empty headers
1344  (when (= (current) +cr+)
1345  (advance)
1346  (if (= (current) +lf+)
1347  (return-from parse-headers (1+ (pos)))
1348  (error 'expect-failed)))
1349 
1350  (advance-to* (parse-header-field-and-value http callbacks data start end))
1351 
1352  (setf (http-mark http) (pos))
1353  (loop
1354  (when (= +max-header-line+ (the fixnum (incf (http-header-read http))))
1355  (error 'header-overflow))
1356  (multiple-value-bind (next endp)
1357  (parse-header-line http callbacks data (pos) end)
1358  (advance-to* next)
1359  (when endp
1360  (return)))
1361  (setf (http-mark http) (pos)))
1362  (setf (http-mark http) (pos))
1363  (setf (http-state http) +state-body+)
1364 
1365  (pos))
1366  (error 'eof)))
1367 
1368 (defun read-body-data (http callbacks data start end)
1369  (declare (type http http)
1370  (type octet-vector data)
1371  (type pointer start end))
1372  (let ((readable-count (the pointer (- end start))))
1373  (declare (dynamic-extent readable-count)
1374  (type pointer readable-count))
1375  (if (<= (http-content-length http) readable-count)
1376  (let ((body-end (+ start (http-content-length http))))
1377  (declare (dynamic-extent body-end))
1378  (setf (http-content-length http) 0)
1379  (callback-data :body http callbacks data start body-end)
1380  (setf (http-mark http) body-end)
1381  (values body-end t))
1382  ;; still needs to read
1383  (progn
1384  (decf (http-content-length http) readable-count)
1385  (callback-data :body http callbacks data start end)
1386  (setf (http-mark http) end)
1387  (values end nil)))))
1388 
1389 (defun http-message-needs-eof-p (http)
1390  (let ((status-code (http-status http)))
1391  (declare (type status-code status-code))
1392  (when (= status-code 0) ;; probably request
1393  (return-from http-message-needs-eof-p nil))
1394 
1395  (when (or (< 99 status-code 200) ;; 1xx e.g. Continue
1396  (= status-code 204) ;; No Content
1397  (= status-code 304)) ;; Not Modified
1398  (return-from http-message-needs-eof-p nil))
1399 
1400  (when (or (http-chunked-p http)
1401  (http-content-length http))
1402  (return-from http-message-needs-eof-p nil))
1403  T))
1404 
1405 (defun parse-http-body (http callbacks data start end requestp)
1406  (declare (type http http)
1407  (type octet-vector data)
1408  (type pointer start end))
1409  (macrolet ((message-complete ()
1410  `(progn
1411  (callback-notify :message-complete http callbacks)
1412  (setf (http-state http) +state-first-line+))))
1413  (case (http-content-length http)
1414  (0
1415  ;; Content-Length header given but zero: Content-Length: 0\r\n
1416  (message-complete)
1417  start)
1418  ('nil
1419  (if (or requestp
1420  (not (http-message-needs-eof-p http)))
1421  ;; Assume content-length 0 - read the next
1422  (progn
1423  (message-complete)
1424  ;; By returning "start", we'll continue
1425  ;; to parse the next request in case if
1426  ;; HTTP pipelining is used. Probably
1427  ;; we need some way to enable (or disable)
1428  ;; HTTP pipelining support.
1429  start)
1430  ;; read until EOF
1431  (progn
1432  (callback-data :body http callbacks data start end)
1433  (setf (http-mark http) end)
1434  (message-complete)
1435  end)))
1436  (otherwise
1437  ;; Content-Length header given and non-zero
1438  (multiple-value-bind (next completedp)
1439  (read-body-data http callbacks data start end)
1440  (when completedp
1441  (message-complete))
1442  next)))))
1443 
1444 (defun parse-chunked-body (http callbacks data start end)
1445  (declare (type http http)
1446  (type octet-vector data)
1447  (type pointer start end))
1448 
1449  (when (= start end)
1450  (return-from parse-chunked-body start))
1451 
1452  (or (with-octets-parsing (data :start start :end end)
1453  (tagbody
1454  (cond
1455  ((= (http-state http) +state-chunk-size+)
1456  (go chunk-size))
1457  ((= (http-state http) +state-body+)
1458  (go body))
1459  ((= (http-state http) +state-chunk-body-end-crlf+)
1460  (go body-end-crlf))
1461  ((= (http-state http) +state-trailing-headers+)
1462  (go trailing-headers))
1463  (T (error 'invalid-internal-state :code (http-state http))))
1464 
1465  chunk-size
1466  (let ((unhex-val (unhex-byte (current))))
1467  (declare (type fixnum unhex-val)
1468  (dynamic-extent unhex-val))
1469  (when (= unhex-val -1)
1470  (error 'invalid-chunk-size))
1471  (setf (http-content-length http) unhex-val)
1472 
1473  (loop
1474  (advance)
1475  (if (= (current) +cr+)
1476  (progn
1477  (advance)
1478  (tagbody
1479  (skip #\Newline)
1480  :eof
1481  (return)))
1482  (progn
1483  (setq unhex-val (unhex-byte (current)))
1484  (cond
1485  ((= unhex-val -1)
1486  (cond
1487  ((or (= (current) (char-code #\;))
1488  (= (current) (char-code #\Space)))
1489  (skip* (not #\Return))
1490  (advance)
1491  (tagbody
1492  (skip #\Newline)
1493  :eof
1494  (return)))
1495  (t (error 'invalid-chunk-size))))
1496  (t (setf (http-content-length http)
1497  (+ (* 16 (http-content-length http)) unhex-val)))))))
1498  (setf (http-state http) +state-body+)
1499  (if (eofp)
1500  (return-from parse-chunked-body (pos))
1501  (setf (http-mark http) (pos))))
1502 
1503  body
1504  (cond
1505  ((zerop (http-content-length http))
1506  ;; trailing headers
1507  (setf (http-state http) +state-trailing-headers+)
1508  (go trailing-headers))
1509  (T
1510  (multiple-value-bind (next completedp)
1511  (read-body-data http callbacks data (pos) end)
1512  (declare (type pointer next))
1513  (unless completedp
1514  (return-from parse-chunked-body (pos)))
1515  (setf (http-state http) +state-chunk-body-end-crlf+)
1516  (advance-to next))))
1517 
1518  body-end-crlf
1519  (skip #\Return)
1520  (tagbody
1521  (skip #\Newline)
1522  :eof
1523  (setf (http-state http) +state-chunk-size+)
1524  (when (eofp)
1525  (return-from parse-chunked-body (pos))))
1526  (setf (http-mark http) (pos))
1527  (go chunk-size)
1528 
1529  trailing-headers
1530  (return-from parse-chunked-body
1531  (prog1 (parse-headers http callbacks data (pos) end)
1532  (callback-notify :message-complete http callbacks)))))
1533  (error 'eof)))
1534 
1535 (defun parse-request (http callbacks data &key (start 0) end (head-request nil))
1536  (declare (type http http)
1537  (type octet-vector data)
1538  (ignorable head-request))
1539  (let ((end (or end (length data))))
1540  (declare (type pointer start end))
1541  (handler-bind ((match-failed
1542  (lambda (c)
1543  (declare (ignore c))
1544  (error 'expect-failed))))
1545  (with-octets-parsing (data :start start :end end)
1546  (setf (http-mark http) start)
1547 
1548  (tagbody
1549  (let ((state (http-state http)))
1550  (declare (type fixnum state))
1551  (cond
1552  ((= +state-first-line+ state)
1553  (go first-line))
1554  ((= +state-headers+ state)
1555  (go headers))
1556  ((<= +state-chunk-size+ state +state-trailing-headers+)
1557  (go body))
1558  (T (error 'invalid-internal-state :code state))))
1559 
1560  first-line
1561  ;; skip first empty line (some clients add CRLF after POST content)
1562  (when (= (current) +cr+)
1563  (advance)
1564  (tagbody
1565  (skip #\Newline)
1566  :eof
1567  (when (eofp)
1568  (return-from parse-request (pos)))))
1569 
1570  (setf (http-mark http) (pos))
1571  (callback-notify :message-begin http callbacks)
1572 
1573  (multiple-value-bind (method next)
1574  (parse-method data (pos) end)
1575  (declare (type pointer next))
1576  (setf (http-method http) method)
1577  (advance-to* next))
1578  (skip* #\Space)
1579  (let ((url-start-mark (pos))
1580  (url-end-mark (parse-url data (pos) end)))
1581  (declare (type pointer url-start-mark url-end-mark))
1582  (tagbody retry-url-parse
1583  (advance-to* url-end-mark)
1584 
1585  (skip* #\Space)
1586 
1587  (cond
1588  ;; No HTTP version
1589  ((= (current) +cr+)
1590  (callback-data :url http callbacks data url-start-mark url-end-mark)
1591  (advance)
1592  (skip #\Newline))
1593  (t (multiple-value-bind (major minor next)
1594  (parse-http-version data (pos) end)
1595  (declare (type pointer next))
1596  (unless major
1597  ;; Invalid HTTP version.
1598  ;; Assuming it's also a part of URI.
1599  (let ((new-url-end-mark (parse-url data next end)))
1600  (when (= url-end-mark new-url-end-mark)
1601  (error 'invalid-version))
1602  (setq url-end-mark new-url-end-mark)
1603  (go retry-url-parse)))
1604  (callback-data :url http callbacks data url-start-mark url-end-mark)
1605  (setf (http-major-version http) major
1606  (http-minor-version http) minor)
1607  (advance-to* next))
1608  (skip #\Return)
1609  (skip #\Newline)))))
1610 
1611  (setf (http-mark http) (pos))
1612  (setf (http-state http) +state-headers+)
1613  (callback-notify :first-line http callbacks)
1614 
1615  headers
1616  (advance-to* (parse-headers http callbacks data (pos) end))
1617 
1618  (callback-notify :headers-complete http callbacks)
1619  (setf (http-header-read http) 0)
1620 
1621  ;; Exit, the rest of the connect is in a different protocol.
1622  (when (http-upgrade-p http)
1623  (setf (http-state http) +state-first-line+)
1624  (callback-notify :message-complete http callbacks)
1625  (return-from parse-request (pos)))
1626 
1627  (setf (http-state http)
1628  (if (http-chunked-p http)
1629  +state-chunk-size+
1630  +state-body+))
1631 
1632  body
1633  (if (http-chunked-p http)
1634  (advance-to* (parse-chunked-body http callbacks data (pos) end))
1635  (progn
1636  (and (advance-to* (parse-http-body http callbacks data (pos) end t))
1637  (go first-line))))
1638  (return-from parse-request (pos)))))
1639  (error 'eof)))
1640 
1641 (defun parse-response (http callbacks data &key (start 0) end (head-request nil))
1642  (declare (type http http)
1643  (type octet-vector data))
1644  (let ((end (or end
1645  (length data))))
1646  (declare (type pointer start end))
1647  (handler-bind ((match-failed
1648  (lambda (c)
1649  (declare (ignore c))
1650  (error 'expect-failed))))
1651  (with-octets-parsing (data :start start :end end)
1652  (setf (http-mark http) start)
1653 
1654  (tagbody
1655  (let ((state (http-state http)))
1656  (declare (type fixnum state))
1657  (cond
1658  ((= +state-first-line+ state)
1659  (go first-line))
1660  ((= +state-headers+ state)
1661  (go headers))
1662  ((<= +state-chunk-size+ state +state-trailing-headers+)
1663  (go body))
1664  (T (error 'invalid-internal-state :code state))))
1665 
1666  first-line
1667  (setf (http-mark http) (pos))
1668  (callback-notify :message-begin http callbacks)
1669 
1670  (multiple-value-bind (major minor next)
1671  (parse-http-version data (pos) end)
1672  (declare (type pointer next))
1673  (setf (http-major-version http) major
1674  (http-minor-version http) minor)
1675  (advance-to* next))
1676 
1677  (cond
1678  ((= (current) +space+)
1679  (advance)
1680  (advance-to (parse-status-code http callbacks data (pos) end)))
1681  ((= (current) +cr+)
1682  (skip #\Newline))
1683  (T (error 'invalid-version)))
1684 
1685  (setf (http-mark http) (pos))
1686  (setf (http-state http) +state-headers+)
1687  (callback-notify :first-line http callbacks)
1688 
1689  headers
1690  (advance-to* (parse-headers http callbacks data (pos) end))
1691 
1692  (callback-notify :headers-complete http callbacks)
1693  (setf (http-header-read http) 0)
1694  (setf (http-state http)
1695  (if (http-chunked-p http)
1696  +state-chunk-size+
1697  +state-body+))
1698 
1699  (when head-request
1700  (callback-notify :message-complete http callbacks)
1701  (setf (http-state http) +state-first-line+)
1702  (return-from parse-response (pos)))
1703 
1704  body
1705  (if (http-chunked-p http)
1706  (advance-to* (parse-chunked-body http callbacks data (pos) end))
1707  (progn
1708  (advance-to* (parse-http-body http callbacks data (pos) end nil))
1709  (unless (eofp)
1710  (go first-line))))
1711  (return-from parse-response (pos)))))
1712  (error 'eof)))
1713 
1714 (defun parse-header-value-parameters (data &key
1715  header-value-callback
1716  header-parameter-key-callback
1717  header-parameter-value-callback)
1718  (declare (type simple-string data)
1719  (optimize (speed 3) (safety 2)))
1720 
1721  (let* ((header-name-mark 0)
1722  parameter-key-mark
1723  parameter-value-mark
1724  parsing-quoted-string-p
1725  (p 0)
1726  (end (length data))
1727  (char (aref data p)))
1728  (declare (type character char))
1729 
1730  (when (= end 0)
1731  (return-from parse-header-value-parameters 0))
1732 
1733  (macrolet ((go-state (state &optional (advance 1))
1734  `(locally (declare (optimize (speed 3) (safety 0)))
1735  (incf p ,advance)
1736  (when (= p end)
1737  (go eof))
1738  (setq char (aref data p))
1739  (go ,state))))
1740  (flet ((tokenp (char)
1741  (declare (optimize (speed 3) (safety 0)))
1742  (let ((byte (char-code char)))
1743  (and (< byte 128)
1744  (not (char= (the character (aref +tokens+ byte)) #\Nul))))))
1745  (tagbody
1746  parsing-header-value-start
1747  (case char
1748  ((#\Space #\Tab)
1749  (go-state parsing-header-value))
1750  (otherwise
1751  (unless (tokenp char)
1752  (error 'invalid-header-value))
1753  (setq header-name-mark p)
1754  (go-state parsing-header-value 0)))
1755 
1756  parsing-header-value
1757  (case char
1758  (#\;
1759  (when header-value-callback
1760  (funcall (the function header-value-callback)
1761  data header-name-mark p))
1762  (setq header-name-mark nil)
1763  (go-state looking-for-parameter-key))
1764  (otherwise (go-state parsing-header-value)))
1765 
1766  looking-for-parameter-key
1767  (case char
1768  ((#\Space #\Tab #\; #\Newline #\Return)
1769  (go-state looking-for-parameter-key))
1770  (otherwise
1771  (unless (tokenp char)
1772  (error 'invalid-parameter-key))
1773  (setq parameter-key-mark p)
1774  (go-state parsing-parameter-key)))
1775 
1776  parsing-parameter-key
1777  (case char
1778  (#\=
1779  (assert parameter-key-mark)
1780  (when header-parameter-key-callback
1781  (funcall (the function header-parameter-key-callback)
1782  data parameter-key-mark p))
1783  (setq parameter-key-mark nil)
1784  (go-state parsing-parameter-value-start))
1785  (otherwise
1786  (unless (tokenp char)
1787  (error 'invalid-parameter-key))
1788  (go-state parsing-parameter-key)))
1789 
1790  parsing-parameter-value-start
1791  (case char
1792  (#\"
1793  ;; quoted-string
1794  (setq parameter-value-mark (1+ p))
1795  (setq parsing-quoted-string-p t)
1796  (go-state parsing-parameter-quoted-value))
1797  ((#.+space+ #.+tab+)
1798  (go-state parsing-parameter-value-start))
1799  (otherwise
1800  (setq parameter-value-mark p)
1801  (go-state parsing-parameter-value 0)))
1802 
1803  parsing-parameter-quoted-value
1804  (if (char= char #\")
1805  (progn
1806  (assert parameter-value-mark)
1807  (setq parsing-quoted-string-p nil)
1808  (when header-parameter-value-callback
1809  (funcall (the function header-parameter-value-callback)
1810  data parameter-value-mark p))
1811  (setq parameter-value-mark nil)
1812  (go-state looking-for-parameter-key))
1813  (go-state parsing-parameter-quoted-value))
1814 
1815  parsing-parameter-value
1816  (case char
1817  (#\;
1818  (assert parameter-value-mark)
1819  (when header-parameter-value-callback
1820  (funcall (the function header-parameter-value-callback)
1821  data parameter-value-mark p))
1822  (setq parameter-value-mark nil)
1823  (go-state looking-for-parameter-key))
1824  (otherwise
1825  (go-state parsing-parameter-value)))
1826 
1827  eof
1828  (when header-name-mark
1829  (when header-value-callback
1830  (funcall (the function header-value-callback)
1831  data header-name-mark p)))
1832  (when parameter-key-mark
1833  (error 'invalid-eof-state))
1834  (when parameter-value-mark
1835  (when parsing-quoted-string-p
1836  (error 'invalid-eof-state))
1837  (when header-parameter-value-callback
1838  (funcall (the function header-parameter-value-callback)
1839  data parameter-value-mark p))))))
1840  p))