From: Martin Rubey
Subject: Re: [Axiom-developer] Axiom under Windows
Date: 
Message-ID: <9qvedw25un.fsf@aquin.mat.univie.ac.at>
Dear Bill,

(including comp.lang.lisp, I hope you don't mind.)

Dear lispers,

We are currently experimenting with a tiny lisp webserver to have axiom (a free
computer algebra system) process a request, whose result is a html file which
is then displayed in the browser.  We are using gcl (that's the lisp axiom
uses).  The lisp code is included at the end of the mail. (SPADCALL calls an
axiom function passed to socket)

All comments are most welcome.

"Bill Page" writes:

> I certainly am not "skilled in the art" either (Where are all the Lisp
> programmers when you need them? :-) but I think you can use read-line,
> e.g. ref:
> 
> http://www.lispworks.com/documentation/HyperSpec/Body/f_rd_lin.htm
> 
> Try replacing
> 
>   (subseq (string (read s nil 'eof)) 1))))
> 
> with
> 
>   (subseq (read-line s nil 'eof) 1)

Great! Only, why does this append

 HTTP/1.1

to the string read?

Thanks,

Martin

;; try it with
;; )lisp (load "hyper.lisp")
;; SOCKET(8080, getDocumentation$HyperDoc)$Lisp

(defvar *docfun*)

(defun socket (port docfun)
  (setq *docfun* docfun)
  (let ((s (si::socket port :server #'server)))
    (tagbody l
             (when (si::listen s)
               (let ((w (si::accept s)))
                 (server w)))
             (sleep 0.1)
             (go l))))

; server provides the stream which is sent by socket to localhost:port
; needs tidying, especially the checking whether fn changed.  
; Does it make sense to check this?
(defun server (s)

  (let* ((get (read s nil 'eof))

; fn contains the string after "localhost:port", i.e., it will commence with a
; "/", which subseq removes
         (fn (and (eq get 'get) 
;                 (subseq (string (read s nil 'eof)) 1))))
                  (subseq (read-line s nil 'eof) 1))))

; the following is just a debugging message
    (format t "Got ~S~%~%" fn)

; when the leading char is a question mark, we have to prepare documentation
    (when (string= (char fn 0) "?")
; *docfun* should return the name of an html file
; in case of an error, it will also return the name of an html file, which will
; contain the error message
      (setq fn (SPADCALL (subseq fn 1) *docfun*)))

; when the trailing four characters of the string are "html", we assume that we
; have an html file and tell our browser so.
; note that pictures or stylesheets do not like being introduced with this
; header.
    (when (string= (subseq fn (- (length fn) 4)) "html")
      (format s "HTTP/1.1 ~S~%" (if fn 200 403)))

; finally, we open the file, and display it
    (with-open-file  (q fn) (si::copy-stream q s))
    (close s)))

From: Kent M Pitman
Subject: Re: [Axiom-developer] Axiom under Windows
Date: 
Message-ID: <u7iqchll1.fsf@nhplace.com>
Martin Rubey <········@yahoo.de> writes:

> Great! Only, why does this append
> 
>  HTTP/1.1
> 
> to the string read?

I wasn't reading upstream but saw this query out of context, so maybe
I'm not seeing the context right, but at first glance it looks like
this could just as well be 1.0 or some other version.  But in any case,
you it might relate to the content of section 5.1 of the RFC for HTTP 1.0
 http://www.faqs.org/rfcs/rfc1945.html
or the same numbered section, 5.1, in the RFC for HTTP 1.1
 http://www.faqs.org/rfcs/rfc2616.html
From: Martin Rubey
Subject: Re: reading the request line from an http client, was: [Axiom-developer] Axiom under Windows
Date: 
Message-ID: <9q645v3lpk.fsf_-_@aquin.mat.univie.ac.at>
Dear Kent, Vassil,

(sorry for the obscure subject, I was being sloppy).

Kent M Pitman <······@nhplace.com> writes:

> Martin Rubey <········@yahoo.de> writes:
> 
> > Great! Only, why does this append
> > 
> >  HTTP/1.1
> > 
> > to the string read?
> 
> [...] But in any case, you it might relate to the content of section 5.1 of
> the RFC for HTTP 1.0 http://www.faqs.org/rfcs/rfc1945.html or the same
> numbered section, 5.1, in the RFC for HTTP 1.1
> http://www.faqs.org/rfcs/rfc2616.html

Vassil Nikolov <···············@pobox.com> writes:

>   Because it's there...
> 
>   The value returned by READ-LINE includes all characters on the line,
>   including the HTTP version token.  The latter is preceded by white space,
>   where READ would stop consuming input, so the value returned by READ won't
>   contain the HTTP version token.

Many thanks for the hints!

>   But I don't know what exactly problem you are trying to solve by looking
>   for a replacement for READ and considering READ-LINE for the purpose.

Well, READ turns everything into uppercase.  What I try to achieve is the
following: the request I get by (subseq (read-line s nil 'eof) 1)))) really
encodes an operation in axiom.  Since axiom is case-sensitive, I need to
preserve case, which I did up to now using vertical bars.  This works quite
well, apart from the fact that I noticed that spaces (which I used as
separator) are turned into %20 and the backquote "`" is turned into %60 on
firefox, but not on konqueror.  So, what I really need is a safe way to get
what is written in the browser into a string.  Of course, this also means to
find out which characters are preserved and which are translated into %xx
sequences.  At least, now I understand the %20.  It remains to find a character
which is guaranteed to be preserved by the protocol and which is forbidden to
be part of an operation specification in axiom...

Again, many thanks,

Martin
From: Vassil Nikolov
Subject: Re: reading the request line from an http client, was: [Axiom-developer] Axiom under Windows
Date: 
Message-ID: <kabqfnztsa.fsf@localhost.localdomain>
On 10 Jun 2007 16:53:11 +0200, Martin Rubey <········@yahoo.de> said:
| ...
| Well, READ turns everything into uppercase.

  Note---perhaps for the future---that one possibility is to use a
  customized readtable which preserves case (and ensures that
  constituent characters are indeed processed as such, etc. etc.).  In
  this specific case (processing a request line in an HTTP request)
  that may be overkill, of course.  More importantly, one usually
  leaves the job of extracting URIs and headers from an HTTP request,
  URL decoding, etc.  to some combination of a third-party web server
  and plug-ins and modules for it, and writes code on top of that, but
  I don't know, of course, whether you can actually make use of one in
  your project.

  Good luck,
  Vassil.


-- 
The truly good code is the obviously correct code.
From: Martin Rubey
Subject: Re: reading the request line from an http client, was: [Axiom-developer] Axiom under Windows
Date: 
Message-ID: <9qodjm99vu.fsf@aquin.mat.univie.ac.at>
Dear Vassil,

Vassil Nikolov <···············@pobox.com> writes:

> On 10 Jun 2007 16:53:11 +0200, Martin Rubey <········@yahoo.de> said:
> | ...
> | Well, READ turns everything into uppercase.
> 
>   Note---perhaps for the future---that one possibility is to use a
>   customized readtable which preserves case (and ensures that
>   constituent characters are indeed processed as such, etc. etc.).  In
>   this specific case (processing a request line in an HTTP request)
>   that may be overkill, of course.  

Yes, I did something extremely simple know, after I understood where the
problems came from.  I stayed with READ, since this does just the right thing
with respect to cutting of the http version thing.

  (let* ((get (read s nil 'eof))
         (fn (and (eq get 'get)
; fn contains the string after "localhost:port", i.e., it will commence with a
; "/", which subseq removes.  We also have to unencode the url: Certain
; characters (including the percent) will be encoded as %ab, where ab is the
; hex code of the character in latin 1.
; see http://www.blooberry.com/indexdot/html/topics/urlencoding.htm
                  (let* ((s1 (subseq (string (read s nil 'eof)) 1))
                         (n (length s1)) 
                         (s2 (make-string n)))
                    (do ((i 0 (incf i)) 
                         (j 0 (incf j))) 
                        ((= i n) (subseq s2 0 j)) 
                      (if (char= (char s1 i) #\%) 
                          (setf (char s2 j) 
                                (code-char (read-from-string 
                                            (concat "#x" 
                                                    (subseq s1 (incf i)
                                                            (1+ (incf i)))))))
                        (setf (char s2 j) (char s1 i))))))))

I guess that my code is not particularly beautiful, but I did not want to put
much more time into this detail right now.  (I guess I should get rid of the
nested let*, for example.

Many thanks for your hints,

Martin
From: Martin Rubey
Subject: Re: reading the request line from an http client, was: [Axiom-developer] Axiom under Windows
Date: 
Message-ID: <9qir9v26y4.fsf@aquin.mat.univie.ac.at>
I think that

http://www.blooberry.com/indexdot/html/topics/urlencoding.htm

contains all the information I needed.

Many many thanks again,

Martin
From: Vassil Nikolov
Subject: Re: [Axiom-developer] Axiom under Windows
Date: 
Message-ID: <ka4plg20cs.fsf@localhost.localdomain>
On 09 Jun 2007 23:08:48 +0200, Martin Rubey <········@yahoo.de> said:
| ...
|| Try replacing
|| 
|| (subseq (string (read s nil 'eof)) 1))))
|| 
|| with
|| 
|| (subseq (read-line s nil 'eof) 1)

| Great! Only, why does this append

|  HTTP/1.1

| to the string read?

  Because it's there...

  The value returned by READ-LINE includes all characters on the line,
  including the HTTP version token.  The latter is preceded by white
  space, where READ would stop consuming input, so the value returned
  by READ won't contain the HTTP version token.

  But I don't know what exactly problem you are trying to solve by
  looking for a replacement for READ and considering READ-LINE for the
  purpose.

  ---Vassil.


-- 
The truly good code is the obviously correct code.