Shammer's Philosophy

My private adversaria

rewrite http-read-line of http://d.hatena.ne.jp/shammer/20160320/p1

In the article Lisp HTTP Client handling chunked responses - Shammerism, I wrote a HTTP client which can handle chunked response. In this article, the function whose name is http-read-line uses do loop, but I would like to rewrite as recursive. Here is a re-write version.

(define-condition invalid-http-line-error (error)
  ((text :initarg :text :reader get-error-message))
  (:report (lambda (condition stream)
             (format stream "~S.~%" (get-error-message condition)))))

(defun read-http-line-as-bytes ()
  (let ((c (read-byte *client-stream* nil 'eof)))
    (cond ((equal c 'eof)
           (error (make-condition 'invalid-http-line-error
                                  :text "Client closed socket during read-http-line")))
          ((equal c 13)
           (let ((next (read-byte *client-stream* nil 'eof)))
             (if (equal next 10)
                 (list 13 10)
                 (error (make-condition 'invalid-http-line-error
                                        :text "Invalid http line, http line should be finished with 13 10")))))
          (t
           (append (list c) (flatten (list (read-http-line-as-bytes))))))))

(defun read-http-line-as-string ()
  (labels ((close-socket-after-message-output (message)
             (format t "~A~%" message)
             (close *client-stream*)))
    (handler-case
        (let ((byte-list (read-http-line-as-bytes)))
          (if (equal byte-list (list 13 10))
              ""
              (decode-string-from-octets
               (coerce (subseq byte-list 0 (- (length byte-list) 2)) ;; Remove (13 10) before convert to string
                       '(simple-array (unsigned-byte 8)))
               :external-format :utf-8)))
      (invalid-http-line-error (ihle)
        (close-socket-after-message-output
         (format nil "Invalid HTTP line received with ~A, close this connection.~%" (get-error-message ihle)))))))

I used adjustable array whose element type is unsigned-byte 8 with the following function, but I found the way how to do the same thins as this function with only lisp standard libraries.

(defun make-byte-array ()
  (make-array 0 :fill-pointer 0 :adjustable t :element-type '(unsigned-byte 8)))

Using coerce with following options can do the same thing.

? (coerce list '(simple-array (unsigned-byte 8)))

There are a lot of things to learn about lisp. I keep learning Lisp to be able to use Lisp as well as Java. I wrote a lot of code, but there are a lot of wasted code, I guess. I have to brush up my Lisp code.