From: Christopher C. Stacy
Subject: problem with portableaserve
Date: 
Message-ID: <uadqnswdk.fsf@grant.org>
I can't get the POST method forms to work.
I am using LWW 4.1.  Here's example:

============
 (load "/s/L/portableaserve-1.2.5a/load.lisp")

 (defpackage "TEST" (:use #:COMMON-LISP #:NET.HTML.GENERATOR #:NET.ASERVE))
 (in-package "TEST")


 (defun test (req ent)
   (with-http-response (req ent)
     (with-http-body (req ent)
       (html
         (:html
          (:head (:title "Test"))
          ((:body)
            (:h1 "Test")
             ((:form :name "testform" :action "/test" :method "POST")
               ((:font size "+2") "Foo: ")
                 ((:input :name "foo" :type "text")))))))))

 (compile 'test) 

  (start)
 =>#<WSERVER port 80 21281AD4>

 (net.aserve::debug-on :notrap)

 (publish :path "/test" :content-type "text/html" :function 'test)
 =>#<COMPUTED-ENTITY 214E7874>
============

This web page comes up, but submitting the form always blows up with:
 Error: #\f is not of type INTEGER.
 Call to (SETF SEQ::AREF-NO-CHECK)
 Call to (METHOD STREAM:STREAM-READ-SEQUENCE (COM.LJOSA.CHUNKED:CHUNKED-MIXIN T T T))
 Call to (HARLEQUIN-COMMON-LISP:SUBFUNCTION #:WT-3349 NET.ASERVE::READ-SEQUENCE-WITH-TIMEOUT)
 Call to MP::WITH-TIMEOUT-F
 Call to NET.ASERVE::READ-SEQUENCE-WITH-TIMEOUT
 Call to (METHOD GET-REQUEST-BODY (HTTP-REQUEST))
 Call to (HARLEQUIN-COMMON-LISP:SUBFUNCTION #:WT-485 TEST)
 Call to MP::WITH-TIMEOUT-F
 Call to TEST
 Call to (METHOD PROCESS-ENTITY (HTTP-REQUEST COMPUTED-ENTITY))
 Call to (METHOD HANDLE-REQUEST (HTTP-REQUEST))
 Call to NET.ASERVE::PROCESS-CONNECTION
 Call to NET.ASERVE::HTTP-WORKER-THREAD
 Call to (HARLEQUIN-COMMON-LISP:SUBFUNCTION 1 MP::INITIALIZE-PROCESS-STACK)

Is there a patch, or am I doing something wrong, or what?

Method "GET" forms work just fine and I successfully call
REQUEST-QUERY-VALUE with those.  (In the losing example above, 
it's blowing up without my even asking for that.)

From: Ram Krishnan
Subject: Re: problem with portableaserve
Date: 
Message-ID: <uit5bbnhq.fsf@mac.com>
······@grant.org (Christopher C. Stacy) writes:

> I can't get the POST method forms to work.
> I am using LWW 4.1.  Here's example:
>

For what its worth, I can't reproduce the problem on Lispworks LWW
4.2.  Btw, I made the following mod to your example:

(defun test (req ent)
  (with-http-response (req ent)
    (with-http-body (req ent)
      (let ((x (assoc "foo" (request-query req) :test #'equal)))
        (html
         (:html
          (:head (:title "Test"))
          ((:body)
           (:h1 "Test")
           ((:form :name "testform" :action "/test" :method "POST")
            ((:font size "+2") "Foo: ")
            ((:input :name "foo" :type "text")))
           (if x (html (:princ (cdr x)))))))))))

Best regards,

-ram
From: Christopher C. Stacy
Subject: Re: problem with portableaserve
Date: 
Message-ID: <uvg9bnwyl.fsf@grant.org>
>>>>> On Sat, 25 May 2002 22:20:08 GMT, Christopher C Stacy ("CStacy") writes:

 CStacy> I can't get the POST method forms to work.
 CStacy> I am using LWW 4.1.

 CStacy>  Error: #\f is not of type INTEGER.
 CStacy>  Call to (SETF SEQ::AREF-NO-CHECK)
 CStacy>  Call to (METHOD STREAM:STREAM-READ-SEQUENCE (COM.LJOSA.CHUNKED:CHUNKED-MIXIN T T T))
 CStacy>  Call to (HARLEQUIN-COMMON-LISP:SUBFUNCTION #:WT-3349 NET.ASERVE::READ-SEQUENCE-WITH-TIMEOUT)
 CStacy>  Call to MP::WITH-TIMEOUT-F
 CStacy>  Call to NET.ASERVE::READ-SEQUENCE-WITH-TIMEOUT
 CStacy>  Call to (METHOD GET-REQUEST-BODY (HTTP-REQUEST))

GET-REQUEST-BODY has a #-Allegro conditional that makes the sequence
be (UNSIGNED-BYTE 8) rather than a STRING.  This is passed to to the
READ-SEQUENCE-WITH-TIMEOUT stuff, and is followed by some unconditional
code that copies each element of the now-filled sequence into a new STRING;
it assumes that the sequence was character codes.

What's all this copying about?  Is this code conditionalized right, 
or is there some confusion about how the READ-SEQUENCE stuff is
supposed to work, or what?

I wonder why it appears to work in LWW 4.2.  Has anyone else seen this
problem under LWW 4.1, or am I the only one using it?
From: Rudi Schlatte
Subject: Re: problem with portableaserve
Date: 
Message-ID: <87vg9bckhz.fsf@ist.tu-graz.ac.at>
······@grant.org (Christopher C. Stacy) writes:

[snip backtrace]

> GET-REQUEST-BODY has a #-Allegro conditional that makes the sequence
> be (UNSIGNED-BYTE 8) rather than a STRING.  This is passed to to the
> READ-SEQUENCE-WITH-TIMEOUT stuff, and is followed by some unconditional
> code that copies each element of the now-filled sequence into a new STRING;
> it assumes that the sequence was character codes.
> 
> What's all this copying about?  Is this code conditionalized right, 
> or is there some confusion about how the READ-SEQUENCE stuff is
> supposed to work, or what?

ACL uses bivalent streams, so can call read-char and read-byte
interchangeably.  Generally, such uses are converted to read-byte in
PortableAServe; looks like you found a case that was missed.

> I wonder why it appears to work in LWW 4.2.  Has anyone else seen this
> problem under LWW 4.1, or am I the only one using it?

FWIW, I'm using AServe on cmucl and didn't run into the exact problem
you have, but it could be that you found the cause of some other
intermittent problems that I observed.

I'm currently porting the newest AllegroServe sources to PAServe; I'll
have a look into your problem as well.  Thanks for the detailed bug
report; this could be very helpful.

Regards,

Rudi
From: Christopher C. Stacy
Subject: Re: problem with portableaserve
Date: 
Message-ID: <uelfyvg62.fsf@grant.org>
>>>>> On 26 May 2002 11:43:20 +0200, Rudi Schlatte ("Rudi") writes:
 Rudi> I'm currently porting the newest AllegroServe sources to PAServe; I'll
 Rudi> have a look into your problem as well.  Thanks for the detailed bug
 Rudi> report; this could be very helpful.

Well, Thank You! 
From: Jochen Schmidt
Subject: Re: problem with portableaserve
Date: 
Message-ID: <acs6ng$ab3$1@rznews2.rrze.uni-erlangen.de>
Christopher C. Stacy wrote:

> I can't get the POST method forms to work.
> I am using LWW 4.1.  Here's example:
> 
> ============
>  (load "/s/L/portableaserve-1.2.5a/load.lisp")

Well - you seem to use version 1.2.5a which is a rather old one.
GET-REQUEST-BODY got completely rewritten from the one that came with 
original AServe in version 1.2.5b

This is the new G-R-B in PortableAServe

(defmethod get-request-body ((req http-request))
  "Return and cache the body of the http-request as string"
  (labels ((accept-char (char stream)
             (let ((c (read-char-no-hang stream nil nil)))
               (cond ((eql c char))
                     (c (unread-char c stream)))))
           
           (read-body-with-content-length (length stream)
             (prog1 (let ((ret (make-string length)))
                      (read-sequence-with-timeout 
                       ret length stream *read-request-body-timeout*))
                      
               ;; Chop CRLF for buggy browsers like Netscape
                      (and (accept-char #\return stream)
                           (accept-char #\linefeed stream))))
           
           (read-body-without-content-length (stream)
             (acl-mp:with-timeout (*read-request-body-timeout* nil)
               (if (equalp "keep-alive" (header-slot-value req :connection))
                   "" ; no body
                   (loop with result = (make-array 2048 
                                                              :element-type 
'character
                                                              :fill-pointer 
0)
                         for c = (read-char stream nil :eof)
                         do (vector-push-extend c result)
                         finally (return result))))))

    (or (request-request-body req)
        (setf (request-request-body req)
              (multiple-value-bind (length believe-it) 
                  (header-slot-value-integer req :content-length)
                (cond ((not (member (request-method req) '(:put :post))) "") ; no body
                      (believe-it (read-body-with-content-length length (request-socket 
req)))
                      (t (read-body-without-content-length (request-socket req)))))))))


This should fix your problems. But I think it is a good idea to fetch the 
newest version from CVS.  (actual version is 1.2.12c)

> 
>  (defpackage "TEST" (:use #:COMMON-LISP #:NET.HTML.GENERATOR
>  #:NET.ASERVE)) (in-package "TEST")
> 
> 
>  (defun test (req ent)
>    (with-http-response (req ent)
>      (with-http-body (req ent)
>        (html
>          (:html
>           (:head (:title "Test"))
>           ((:body)
>             (:h1 "Test")
>              ((:form :name "testform" :action "/test" :method "POST")
>                ((:font size "+2") "Foo: ")
>                  ((:input :name "foo" :type "text")))))))))
> 
>  (compile 'test)
> 
>   (start)
>  =>#<WSERVER port 80 21281AD4>
> 
>  (net.aserve::debug-on :notrap)
> 
>  (publish :path "/test" :content-type "text/html" :function 'test)
>  =>#<COMPUTED-ENTITY 214E7874>
> ============
> 
> This web page comes up, but submitting the form always blows up with:
>  Error: #\f is not of type INTEGER.
>  Call to (SETF SEQ::AREF-NO-CHECK)
>  Call to (METHOD STREAM:STREAM-READ-SEQUENCE
>  (COM.LJOSA.CHUNKED:CHUNKED-MIXIN T T T)) Call to
>  (HARLEQUIN-COMMON-LISP:SUBFUNCTION #:WT-3349
>  NET.ASERVE::READ-SEQUENCE-WITH-TIMEOUT) Call to MP::WITH-TIMEOUT-F Call
>  to NET.ASERVE::READ-SEQUENCE-WITH-TIMEOUT Call to (METHOD
>  GET-REQUEST-BODY (HTTP-REQUEST)) Call to
>  (HARLEQUIN-COMMON-LISP:SUBFUNCTION #:WT-485 TEST) Call to
>  MP::WITH-TIMEOUT-F Call to TEST
>  Call to (METHOD PROCESS-ENTITY (HTTP-REQUEST COMPUTED-ENTITY))
>  Call to (METHOD HANDLE-REQUEST (HTTP-REQUEST))
>  Call to NET.ASERVE::PROCESS-CONNECTION
>  Call to NET.ASERVE::HTTP-WORKER-THREAD
>  Call to (HARLEQUIN-COMMON-LISP:SUBFUNCTION 1
>  MP::INITIALIZE-PROCESS-STACK)
> 
> Is there a patch, or am I doing something wrong, or what?

Get the CVS release and try that please.

> Method "GET" forms work just fine and I successfully call
> REQUEST-QUERY-VALUE with those.  (In the losing example above,
> it's blowing up without my even asking for that.)

GET-REQUEST-BODY explicitely handles POST and PUT requests - the rewritten 
G-R-B (which is in use since 1.2.5b) should work.

I've also rewritten much MP and socket stuff in the more actual releases. 
The actual CVS version uses a new chunking module which makes better use of 
the internal buffering offered by the lisp-system (only supported with LW 
until now). The actual acl-socket layer for LW supports bivalent streams 
and has better integrated error handling (It tries to raise the same 
conditions like ACL).

--
http://www.dataheaven.de