[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Gcl-devel] Re: Simple web server in GCL
From: |
Camm Maguire |
Subject: |
[Gcl-devel] Re: Simple web server in GCL |
Date: |
17 Jun 2005 09:39:23 -0400 |
User-agent: |
Gnus/5.09 (Gnus v5.9.0) Emacs/21.2 |
Greetings, and please excuse my delayed reply!
1) I can certainly make araneida work on GCL if we need it, but I'm
missing the rationale, and of course time is always tight. Isn't a
full blown webserver overkill? Do we need any functionality not in
the simple little code we've been playing with? I thought we were
at the point to write html producing functions to feed through this
mechanism.
2) I think this
> > )lisp (progn
> > ; we need a new output stream backed by a string
> > (setq tmpout (make-string-output-stream))
> > ; we hold on to the regular algebra output stream
> > (setq save |$algebraOutputStream|)
> > ; we capture the regular output into our string stream
> > (setq |$algebraOutputStream| tmpout)
> > ; we generate output
> > (|parseAndInterpret| "(x+1)^9")
> > ; we get the results from the algebra output stream
> > (setq result (get-output-stream-string |$algebraOutputStream|))
> > ; we restore the regular algebra output stream
> > (setq |$algebraOutputStream| save)
> > ; and return the result
> > result)
> >
can be simplified to
)lisp (with-output-to-string (s) (let ((|$algebraOutputStream| s))
(|parseAndInterpret| "(x+1)^9")))
Or even
(defun axiom-string-eval (c)
(with-output-to-string (s)
(let ((|$algebraOutputStream| s))
(|parseAndInterpret| c))))
)lisp (axiom-string-eval "(x+1)^9")
But since you'd be calling this from the server running in lisp, you
don't need the )lisp escape, no?
I take it |$algebraOutputStream| is a declared special.
Take care,
"Page, Bill" <address@hidden> writes:
> Kai,
>
> On Wednesday, June 15, 2005 12:51 PM you wrote:
>
> > ...
> > Bill Page wrote:
> >> ...
> >> Right now I know that on the newest version of GCL
> >> (Version_2_6_7pre) it is possible to run a simple
> >> web server in the same image that runs Axiom on both
> >> Linux and Windows.
> >
> > I did not know about that. Which web server is that?
>
> It consists of just a pair few lines of lisp code written by
> Camm. See emails attached below. Also some related some of my
> notes about web browser page design and details on capturing
> Axiom output from Tim.
>
> > I do not think that establishing a socket connection is a great
> > deal on Windows. I have never done it myself admittedly, but
> > other Lisp projects do it and it seems to be simple. Besides we
> > have to listen to a socket anyway with Araneida. If there is
> > trouble to get sockets working on Windows we are screwed anyway.
>
> I am attaching the email thread between between Camm and me
> from the axiom-developer email list about the "simple web
> server" lisp code that works in both Windows and Linux. It might
> be a bit "thin" to follow, but I think you should probably be able
> to find the relevant parts. Just ask if not. If/when you do
> get access to a running GCL, you should give this a try.
>
> Regards,
> Bill Page.
>
> ------------------
>
> -----Original Message-----
> From: Camm Maguire [mailto:address@hidden
> Sent: Thursday, April 28, 2005 2:52 PM
> To: Bill Page (E-mail)
> Cc: address@hidden; address@hidden
> Subject: Re: [Gcl-devel] Simple web server code for GCL for Windows
>
>
> Greetings! Here's a quick way to get started:
>
> ============================================================================
> =
>
> Starting program: /fix/t1/camm/debian/gcl/gcl-2.6.6/unixport/saved_gcl .
> GCL (GNU Common Lisp) 2.6.6 CLtL1 Apr 28 2005 17:10:11
> Source License: LGPL(gcl,gmp), GPL(unexec,bfd)
> Binary License: GPL due to GPL'ed components: (READLINE BFD UNEXEC)
> Modifications of this banner must retain notice of a compatible license
> Dedicated to the memory of W. Schelter
>
> Use (help) to get some basic information on how to use GCL.
>
> >(defun foo (s)
> (let* ((get (read s nil 'eof))
> (fn (and (eq get 'get) (string-downcase (read s nil 'eof))))
> (fn (when (probe-file fn) fn)))
> (format s "HTTP/1.1 ~S~%~%" (if fn 404 500))
> (when fn
> (if (pathname-name (pathname fn))
> (with-open-file (q fn) (si::copy-stream q s))
> (dolist (l (directory fn)) (format s "~a~%" (namestring l)))))
> (close s)))
>
> >(defun bar (p fn)
> (let ((s (si::socket p :server fn)))
> (tagbody l
> (when (si::listen s)
> (let ((w (si::accept s)))
> (foo w)))
> (sleep 3)
> (go l))))
>
> >(bar 8080 #'foo)
> ============================================================================
> =
>
> Then point your browser to localhost:8080. You should be able to get
> directory listings and files. There is obviously no protocol nor
> error implementation here, but that should be straightforward for the
> web gurus.
>
> This will accept multiple simultaneous connections and process them
> one at a time. The delay mechanism can obviously be adjusted. Each
> connection is stateless -- a multiplexing solution for persistent
> connections can be implemented in like manner. Also, all connections
> are in the same process. It is trivial to fork() in linux for each
> connection, but don't know how this would be done on Windows.
> Speaking of which, does MS have select? There are other hooks for
> allowing work in the image while connections are handled in the
> background, e.g. SIGIO, but don't know the portable nor most desirable
> way of doing this.
>
> Anything can be done here that one wishes -- my question is, what is
> the advantage vis a vis an external server like apache? Presumably,
> axiom could spit out results directly instead of being called in a
> cgi, which is of some value. Anyway, more discussion on where and why
> this should go if anywhere would be great!
>
> Take care,
>
>
> "Page, Bill" <address@hidden> writes:
>
> > GCL Gurus,
> >
> > Does anyone know of a simple web server program in lisp that
> > works (or should work) under GCL on both linux and Windows?
> > I am correct to assume that with socket support working properly
> > this should be quite easy (say 20 or 30 lines of code)?
> >
> > If an example code exists that works on linux, I would like to
> > try it under Windows. If there are problems I would be glad to
> > help try debugging it.
> >
> > Regards,
> > Bill Page.
> >
>
>
> -----Original Message-----
> From: Camm Maguire [mailto:address@hidden
> Sent: Wednesday, May 04, 2005 1:41 PM
> To: Bill Page (E-mail)
> Cc: 'Mike Thomas'; address@hidden; Paul F. Dietz
> Subject: Re: [Axiom-developer] RE: [Gcl-devel] Re: axiom porting
>
> Here is a little modification to the server example:
>
> (defun foo (s)
> (let* ((get (read s nil 'eof))
> (fn (and (eq get 'get) (string-downcase (read s nil 'eof))))
> (dn (if (eql (aref fn (1- (length fn))) #\/) fn
> (si::string-concatenate fn "/")))
> (dir (directory dn))
> (file (unless dir (when (probe-file fn) fn))))
> (format s "HTTP/1.1 ~S~%" (if fn 404 500))
> (format s "Content-type: text/html~%~%")
> (format t "get ~a fn ~a dn ~a~%" get fn dn)
> (cond (file (with-open-file (q file) (si::copy-stream q s)))
> (dir (dolist (l dir)
> (let ((n (namestring l)))
> (format s "<a href=\"~a\">~a</a> <a href=\"~a/\"> /...
> </a><br>~%" n n n)))))
> (close s)))
>
> ============================================================================
> =
>
> These are just toys of course, just meant to illustrate my limited
> understanding of how one can distinguish files from directories in
> *standard* lisp. We can add anything non-standard we might need, of
> course.
>
>
> -----Original Message-----
> From: Page, Bill [mailto:address@hidden
> Sent: Tuesday, May 03, 2005 4:21 PM
> To: 'Camm Maguire'
> Cc: 'Mike Thomas'; address@hidden; Bill Page (E-mail);
> address@hidden
> Subject: [Gcl-devel] RE: [Axiom-developer] Simple web server code for
> GCLfor Windows
>
>
> Camm,
>
> You are right. The simple GCL web server program that you
> wrote is working on both linux and Windows. Great!
>
> On Tuesday, May 03, 2005 9:56 AM Camm Maguire wrote:
>
> >...
> > What this will send to the gcl function 'foo' is 'get /dir'
> > #'foo must find a file or directory by that name to produce
> > output, which I'm guessing does not exist on your system.
> > You can add a diagnostic like:
>
> (defun foo (s)
> (let* ((get (read s nil 'eof))
> (fn (and (eq get 'get) (string-downcase (read s nil 'eof))))
> (fn (when (probe-file fn) fn)))
> (format s "HTTP/1.1 ~S~%" (if fn 404 500))
> (format s "Content-type: text/html~%~%")
> (format t "get ~a fn ~a~%" get fn)
> (when fn
> (if (pathname-name (pathname fn))
> (with-open-file (q fn) (si::copy-stream q s))
> (dolist (l (directory fn)) (format s "~a~%" (namestring l)))))
> (close s))
> )
>
> > You can also do 'telnet localhost 8085' and type 'get /dir'
> > to see the output, which I think is likely '404' in my pseudo
> > html error code example.
>
> Thanks. This works exactly as you claim. For example on my system
>
> http://localhost:8085/msys/1.0/home/bpage/
>
> produces a list of files and
>
> http://localhost:8085/msys/1.0/home/bpage/repository.html
>
> displays the web page in a browser (See Content-type above).
>
> Just to play a little (although I know almost knowing about
> lisp :) I also changed the file list to HTML format like this:
>
> (format s "<a href=\"~a\">~a</a> <a href=\"~a/\"> /... </a><br>~%"
> (namestring l) (namestring l) (namestring l)))
>
> It would be nicer to make the result and the content type depend
> on whether something was a directory or on the type of the file
> etc instead of the syntax of the name, but I could not easily
> discover how to do that in GCL. Specifically how can I tell a
> directory from a file? Can anyone suggest a suitable "Getting
> started in GCL" tutorial?
>
> Anyway, it seems clear that we could use this approach to develop
> a portable HyperTex browser for Axiom if we decide to go that
> root.
>
> Regards,
> Bill Page.
>
>
> -----Original Message-----
> From: Camm Maguire [mailto:address@hidden
> Sent: Thursday, May 05, 2005 10:19 AM
> To: Bill Page
> Cc: 'Mike Thomas'; address@hidden; Paul F. Dietz
> Subject: Re: [Axiom-developer] RE: [Gcl-devel] Re: axiom porting
>
>
>
> >
> >===========================================================================
> ==
> > >
> > >Here is a little modification to the server example:
> > >
> > > (defun foo (s) (let* ((get (read s nil 'eof)) (fn (and (eq
> > > get 'get) (string-downcase (read s nil 'eof))))
> > > (dn (if (eql (aref fn (1- (length fn))) #\/) fn
> (si::string-concatenate fn "/")))
> > > (dir (directory dn))
> > > (file (unless dir (when (probe-file fn) fn))))
>
> This last line should likely read
>
> (file (or (probe-file fn) dir))
>
> just to ensure that probe-file takes precedence.
>
> > > (format s "HTTP/1.1 ~S~%" (if fn 404 500))
> > > (format s "Content-type: text/html~%~%")
> > > (format t "get ~a fn ~a dn ~a~%" get fn dn)
> > > (cond (file (with-open-file (q file) (si::copy-stream q s)))
> > > (dir (dolist (l dir)
> > > (let ((n (namestring l)))
> > > (format s "<a href=\"~a\">~a</a> <a href=\"~a/\"> /...
> </a><br>~%" n n n)))))
> > > (close s)))
> > >
> >
> >===========================================================================
> ==
> > >
> > >These are just toys of course, just meant to illustrate my limited
> > >understanding of how one can distinguish files from directories in
> > >*standard* lisp. We can add anything non-standard we might need, of
> > > course.
> > I like it. As I said, it works for me with the non-ansi gcl
> Version_2_6_7pre
> > on Windows XP/sp2. No aborts this time.
> >
> > And I am learning a little lisp too :) Thanks.
>
> Great!
>
> Take care,
>
>
> -----Original Message-----
> From: Bill Page [mailto:address@hidden
> Sent: Thursday, May 05, 2005 1:44 PM
> To: Camm Maguire
> Cc: Mike Thomas; address@hidden
> Subject: Re: [Axiom-developer] RE: [Gcl-devel] Re: axiom porting
>
>
> Camm Maguire wrote:
>
> >>Using IE, the problem seems to intermittant. It works for a while
> >>with some urls and not others.
> >>
> >>
> >
> >Does this mean that there are some errors that are 100% reproducible?
> >If so, start with those.
> >
> >
> Yes.
>
> >IE appears to be closing the socket before your write completes. The
> >odd thing is that you report that it is intermittent. There are two
> >possibiities that come to mind -- either ie insists on a complete set
> >of html headers from the server, or there is a timeout issue.
> >
> Ok, problem solved (I think). It turned out not to be so exotic an issue.
> I modified the web server program as follows:
>
> - (format s "HTTP/1.1 ~S~%" (if fn 404 500))
> + (format s "HTTP/1.1 ~S~%" (if fn 200 404 ))
>
> If I understand HTTP correctly "404" in the header means "file not found".
> "200" means "ok". "500" means server error. So we were both saying
> "file not found" but then delivering the file anyway. If that's the case
> then it is surprizing that FireFox worked and not surprizing that IE closes
> the socket connection before we can send the file.
>
> With this change both FireFox and IE now seem to work reliable
> and identically for me.
>
> Anyway, I will take a closer look at the HTTP standard to make sure
> that our headers are correct and complete.
>
> Regards,
> Bill Page.
>
>
> -----Original Message-----
> From: Camm Maguire [mailto:address@hidden
> Sent: Thursday, May 05, 2005 2:36 PM
> To: Bill Page
> Cc: Mike Thomas; address@hidden
> Subject: Re: [Axiom-developer] RE: [Gcl-devel] Re: axiom porting
>
>
> Greetings!
>
> Bill Page <address@hidden> writes:
>
> > Camm Maguire wrote:
> >
> > >>Using IE, the problem seems to intermittant. It works for a while
> > >>with some urls and not others.
> > >>
> > >
> > >Does this mean that there are some errors that are 100% reproducible?
> > >If so, start with those.
> > >
> > Yes.
> >
> > >IE appears to be closing the socket before your write completes. The
> > >odd thing is that you report that it is intermittent. There are two
> > >possibiities that come to mind -- either ie insists on a complete set
> > >of html headers from the server, or there is a timeout issue.
> > >
> > Ok, problem solved (I think). It turned out not to be so exotic an issue.
> > I modified the web server program as follows:
> >
> > - (format s "HTTP/1.1 ~S~%" (if fn 404 500))
> > + (format s "HTTP/1.1 ~S~%" (if fn 200 404 ))
> >
>
> Thanks! This is just what we need -- an html guy!
>
> BTW, misspoke earlier re: suggested edit to #"foo. What I meant was:
>
> (defun foo (s)
> (let* ((get (read s nil 'eof))
> (fn (and (eq get 'get) (string-downcase (read s nil 'eof))))
> (file (probe-file fn)))
>
> (format s "HTTP/1.1 ~S~%" (if fn 200 404))
> (format s "Content-type: text/html~%~%")
>
> (if file
> (with-open-file (q file) (si::copy-stream q s))
> (let ((dir (directory (if (eql (aref fn (1- (length fn))) #\/) fn
> (si::string-concatenate fn "/")))))
> (dolist (l dir)
> (let ((n (namestring l)))
> (format s "<a href=\"~a\">~a</a> <a href=\"~a/\"> /...
> </a><br>~%" n n n)))))
> (close s)))
>
> which should function the same as what you have but express the
> precedence better. This counts on probe-file returning nil for
> directories.
>
> Take care,
>
> > If I understand HTTP correctly "404" in the header means "file not found".
> > "200" means "ok". "500" means server error. So we were both saying
> > "file not found" but then delivering the file anyway. If that's the case
> > then it is surprizing that FireFox worked and not surprizing that IE
> closes
> > the socket connection before we can send the file.
> >
> > With this change both FireFox and IE now seem to work reliable
> > and identically for me.
> >
> > Anyway, I will take a closer look at the HTTP standard to make sure
> > that our headers are correct and complete.
> >
> > Regards,
> > Bill Page.
> >
>
>
>
> -----Original Message-----
> From: Bill Page [mailto:address@hidden
> Sent: Friday, May 20, 2005 11:20 AM
> To: address@hidden
> Cc: address@hidden
> Subject: [Axiom-developer] Axiom interface via HTTP
>
>
> On May 20, 2005 8:28 AM Tim Daly wrote:
>
> > Off hand I'm not sure how to do string input but I'm
> > sure it is possible. I'll have to read some code and let
> > you know. Why can't you just feed the string to stdin?
>
> What I am talking about is using the socket code that Camm
> wrote as an HTTP interface to Axiom. The idea is that the
> input loop of AXIOMsys operates a dedicated special purpose
> web server and the user connects to Axiom using a standard
> browser. There is only one AXIOMsys process running as a
> server that talks directly to the browser. It might be
> invoked by starting AXIOMsys and giving a command like:
>
> )set httpmode
>
> In addition to the HTTP port, as part of the HTTP protocol
> with HTML <form ... method="put"> stdin is involved in
> receiving the contents of the web form. This new "httpmode"
> code in AXIOMsys would parse this input from the web browser,
> format it as an Axiom command and process it as if it was
> normal keyboard input. (This is where I need help to
> understand how to call the Axiom input evaluation from
> within lisp and return the result of the calculation back
> to the httpmode list function. Which in turn gets formatted
> as HTTP and sent back to the browser. All of this is done
> entirely within AXIOMsys without any auxillary processes.
>
> One simple web page layout that might work would have two
> parts like this:
>
> -------------------------------------------------------
> | Axiom commands ... |
> | ______________________________________________ |
> | | ) -> integrate(sin x, x) |^| |
> | | ) -> D(%, x) | | |
> | |______________________________________________|v| |
> | [execute] |
> |=====================================================|
> | Axiom output ... |
> | |
> | (1) -cos(x) |
> | Type: Union(Expression Integer ... ) |
> | |
> | (2) sin (x) |
> | Type: Expression Integer |
> | |
> -------------------------------------------------------
>
> The first part is an HTML form with a text input field and
> a button labelled [Execute]. The second part contains the
> output generated by AXIOIMsys.
>
> More complicated page layouts are possible but limitations
> in the way HTTP/HTML works does constrain the design to
> essentially "simplex" (one-way at a time) kind of
> interactions.
>
> > Check out FAQ 19 to figure out how to get the output in
> > a single line.
>
> Thanks but I am not sure if this is relevant.
>
> > Oh, yeah, and remember to use AXIOMsys rather than axiom
> > as the command.
>
> Yes. Graphics is another issue. I would like to be able
> to have Axiom graphics generate VRML (OpenInventor) output
> for display in the browser.
>
> Regards,
> Bill Page.
>
>
> -----Original Message-----
> From: Bill Page [mailto:address@hidden
> Sent: Friday, May 20, 2005 10:39 PM
> To: address@hidden
> Cc: address@hidden
> Subject: [Axiom-developer] RE: lisp talk
>
>
> On May 20, 2005 6:14 PM Tim Daly wrote:
>
> > There is an embedded command server within AXIOMsys.
> > Look at:
> >
> http://daly.axiom-developer.org/TimothyDaly_files/lisptalk/pages/lisp35.html
> >
>
> Thanks, Tim. I believe that
>
> parseAndInterpret stringBuf
>
> is what I was looking for.
>
> Now, this is boot language code, right? So in lisp I have
> to tack on the | | onto the function name and then I can
> call it like this:
>
> (1) -> )lisp (|parseAndInterpret| "integrate(sin x,x)")
>
> (1) - cos(x)
> Type: Union(Expression Integer,...)
>
> Value = ((|Union| (|Expression| (|Integer|)) (|List| (|Expression|
> (|Integer|)))
> ) WRAPPED 0 (1 #<vector 10ccde54> (1 0 . -1)) 0 . 1)
>
> (2) ->
>
> and sure enough! Axiom parses and interprets the string.
> Great.
>
> I presume that there is no reason why this would not work
> when called directly from a lisp function, right? In my
> scheme this string would be passed to Axiom by the http
> webserver code.
>
> But the result appears as stdout and the value returned
> seems to contain the type information. (What is this WRAPPED
> stuff?)
>
> > Also, there is some way to do input because the axiom browser
> > already feeds expressions to AXIOMsys thru a socket.
>
> Yes, input seems to be no problem.
>
> > The string output function mentioned in FAQ 19 is a linear
> > form of the output. However Axiom's native output machinery
> > is called CHARYBDIS which was a research project from the
> > 60s with the goal of printing mathematics on typewriters.
> > Axiom still uses that code.
>
> What I really would like is to see the result also returned
> in the value. I would like to see the output in the form
> of say, a list of strings. So the returned value in the
> example above would be something like this
>
> Value = (("- cos(x)" "Type: Union(Expression Integer,...)")
> ((|Union| (|Expression| (|Integer|)) (|List| (|Expression|
> (|Integer|)))
> ) WRAPPED 0 (1 #<vector 10ccde54> (1 0 . -1)) 0 . 1)
> )
>
> In other words I guess I need the ouput of CHARYBDIS in the
> form of a list of strings instead of in the output stream
> (and later the LaTeX output and the openmath output). Can
> you think of anywhere in Axiom where something like this is
> already done?
>
> Regards,
> Bill Page.
>
>
> -----Original Message-----
> From: Camm Maguire [mailto:address@hidden
> Sent: Monday, May 23, 2005 2:35 PM
> To: address@hidden
> Cc: address@hidden; address@hidden
> Subject: [Gcl-devel] Re: capturing output strings
>
>
> Greetings!
>
> This is an ANSI issue -- traditionally, GCL has used element-type
> 'string-char for strings, but this type was dropped by the ansi
> committee. We'll clear it up soon hopefully, but for now you can just
> replace 'base-char with 'string-char and it will work.
>
> Take care,
>
> address@hidden writes:
>
> > this seems to fail:
> >
> > axiom
> >
> > -> )lisp (setq result (make-array '(0) :element-type 'base-char
> :fill-pointer 0 :adjustable t))
> >
> > Value = #<vector 0894bde4>
> >
> > -> )lisp (with-output-to-string (|$algebraOutputStream| result)
> (|parseAndInterpret| "(x+1)^9"))
> >
> > >> System error:
> > #<vector 0894bde4> is not a string with a fill-pointer
> >
> > This appears to be a bug as result certainly has a fill pointer.
> >
> >
> > This is an attempt to capture the output sent to the
> > stream |$algebraOutputStream| in some more elegant form
> > (instead of this kludge):
> >
> > )lisp (progn
> > ; we need a new output stream backed by a string
> > (setq tmpout (make-string-output-stream))
> > ; we hold on to the regular algebra output stream
> > (setq save |$algebraOutputStream|)
> > ; we capture the regular output into our string stream
> > (setq |$algebraOutputStream| tmpout)
> > ; we generate output
> > (|parseAndInterpret| "(x+1)^9")
> > ; we get the results from the algebra output stream
> > (setq result (get-output-stream-string |$algebraOutputStream|))
> > ; we restore the regular algebra output stream
> > (setq |$algebraOutputStream| save)
> > ; and return the result
> > result)
> >
> > t
> >
>
>
>
--
Camm Maguire address@hidden
==========================================================================
"The earth is but one country, and mankind its citizens." -- Baha'u'llah
- [Gcl-devel] Re: Simple web server in GCL,
Camm Maguire <=