Re: How to simple exit in CGI?
Pascal Bourguignon <[email protected]> Tue, 28 Mar 2017 23:51:06 +0200
| Newsgroups | gmane.lisp.clisp.general |
|---|---|
| Message-ID | <[email protected]> |
> On 28 Mar 2017, at 22:24, Jean Louis <[email protected]> wrote: > > On Tue, Mar 28, 2017 at 09:43:57PM +0200, Pascal Bourguignon wrote: >> There is some confusion between the type of delivery you want, and >> in the case of CGI, some technical difficulty in writing a file able >> to do both. > > I am just trying to understand, if there is no *standard-input* > coming, why the program is not going one step forward, to for example, > spit the headers our. > >> When you write a file starting with “#!” it’s to be considered as a >> script by the unix system, that is, a file that will be processed >> (interpreted) by the command given after “#!”. > > Thank you for explanation, I am aware of it. Yet I am trying to run it > as a memory image, for the speed it is giving. > >> If you save the above file in test.cgi and chmod +x it, it won’t >> work, because alexandria won’t be loaded by the script. > > Right now, it works, as it is saved as memory image which itself has > Alexandria inside. I am using this small program to detect the change > when test.lisp is saved, so that it generates test.cgi which I can > then try to wget or browse. In emacs, you can just type M-x compile RET when you save your source. (Assuming you wrote the Makefile as I advised). > (defparameter file (car *args*)) The expression in the defparameter form is evaluated when the source file (or the fas file) is loaded. It is NOT evaluated when the lisp image is loaded! Also, you’ve been told to use *stars* around the name of special variables defined with defvar or defparameter. You really need to do it! > (defun check-the (file) > (let ((file (format nil "~a.lisp" file))) > (file-stat-mtime (file-stat file)))) > > (defparameter check (check-the file)) > > (defun do-compile (file) ;; (setf file "order") > (cd "/home/data1/protected/public_html/") > (let* ((original (format nil "~a.lisp" file)) > (executable (format nil "~a.cgi" file)) > (command (format nil "lisp -i ~a -x \"(saveinitmem \\\"~a\\\" :executable t :init-function 'main :quiet t :norc t)\"" original executable))) > (unless (equalp check (check-the file)) > (print command) > (shell command) > (set-file-stat executable :mode #O0755) > (setf check (check-the file)))) > (sleep .3)) Here, you’re not using clisp, but CMU CL (lisp). (Each character is important, with computers). > > (loop (do-compile file)) > > I can use it without Alexandria, I guess this is equivalent > below. Yet, I just need to find out how to recognize that there is no > *standard-input* coming, as it is more or less "hanging" if there is > no POST or GET parameter. When you reach end-of-file. In general, the end of file “condition” can be dealt with in two different ways. Usually, I/O functions have optional parameters to let you choose how it will deal when it detects the end of a file. Usually, the default way is to signal an END-OF-FILE error. The alternate way is to return a “guard” value (by default NIL), instead of the read object. > > (setf custom:*ansi* t) > > (defun POST-collect () > (let (lines (loop for line = (read-line *standard-input* nil nil) > while line > collect)) > (format "~{~a~}" lines))) CL-USER> (defun POST-collect () (let (lines (loop for line = (read-line *standard-input* nil nil) while line collect)) (format "~{~a~}" lines))) POST-COLLECT CL-USER> (with-input-from-string (*standard-intput* "") (post-collect)) *** - LET: illegal variable specification (LOOP FOR LINE = (READ-LINE *STANDARD-INPUT* NIL NIL) WHILE LINE COLLECT) Perhaps you should read a tutorial about lisp programming before trying to implement your CGI script. I would advise: http://clisp.hg.sourceforge.net/hgweb/clisp/clisp/raw-file/tip/doc/LISP-tutorial.txt http://www.franz.com/resources/educational_resources/cooper.book.pdf (but for Allegro CL, you should ignore the parts that are implementation specific). http://www.cliki.net/Online%20Tutorial > (defun headers nil And you still use NIL instead of () for parameters. > (format t "Content-type: text/plain~2%")) > > (defun main () > (let ((url "http://localhost") > (query (or (getenv "QUERY_STRING") > (POST-collect)))) > ;; (format t "Status: 302 Found~%Location: ~a~%~%" url) > (headers) > (princ "Hello there") > ;; (finish-output) I would advise you to keep calls to finish-output (and always use it when doing interactive I/O). > (exit 0))) > ;; (main) > >> You could use a macro such as without-output or >> redirecting-stdout-to-stderr to prevent quicklisp messages: > > Well thank you for that, I will keep it for later usage. > > I was thinking that :verbose nil and :silent t within (ql:quickload "" > would suppress the messages. And in some scripts it does it so. > > So it is possible to say: > > (ql:quickload "alexandria" :verbose nil :silent t) > without the output. It seems to work. Notice however that it doesn’t catch *terminal-io* (it couldn’t do so conformingly, but neither without-output could). > >> By the way, you should normally use the nickname ALEXANDRIA, instead >> of the specific versioned package name ALEXANDRIA.0.DEV, unless you >> are using an internal API that you can expect to be specific to the >> version 0 (development) of ALEXANDRIA. > > That I did not know, for one reason, when I type alexandria on CLISP > REPL, it completes to alexandria.0.dev: and I was thinking that is > so. Now I see that I can use alexandria: only, thank you. > >> Now, if you don’t plan to use scripts for your CGI, but an executable image, I would advise you to structure your project with: >> >> - a normal lisp source file, >> - a lisp source file defining a package, >> - an ASDF system definition file, to load your program with asdf or quicklisp, >> - a lisp “script” to load and generate the executable image, and >> - a Makefile to build it. >> See attached files. >> >> CL-USER> (ls) >> ./Makefile >> ./generate-executable.lisp >> ./jean-cgi.asd >> ./jean-cgi.lisp >> ./packages.lisp >> ; No value >> CL-USER> (ql:quickload "jean-cgi") >> To load "jean-cgi": >> Load 1 ASDF system: >> jean-cgi >> ; Loading "jean-cgi" >> >> ("jean-cgi") >> CL-USER> >> >> The advantage of being able to load your program in an interactive >> lisp image, is that you will be able to run and test it at the REPL, >> with the help of the interactive debugger, etc. For example, this >> should work: >> >> CL-USER> (with-input-from-string (*standard-intput* "") >> (jean-cgi:main)) > > Thank you, I am keeping that for later. Right now I have put > everything in one Lisp image, one order.lisp file, including the GnuPG > key, so that GnuPg directory is recreated on server automatically, and > that all inquiries are encrypted on the way back to me. Your code is wrong. My code is correct: I proved it to you by showing you how it worked correctly in two different ways. Now you can keep it for later, but then I will resume helping you only later. > Everything is working well so far, only that I cannot solve the > problem when the CGI is called directly, it is waiting too long. > > If I make the same thing in Perl: > > #!/usr/bin/perl > exit; > > there is no waiting time. And I came from Perl world. > > and if I make the same in CLISP: > > (defun main () > (exit)) > > and save as memory image, the wget is not exiting. Basically CLISP is > not exiting. You’re lying. > >> My own utility library cesarum, doesn’t have this problem: >> >> CL-USER> (with-input-from-string (*standard-intput* "") >> (contents-from-stream *standard-intput* :min-size 16384)) >> "" >> >> you might prefer using it rather than alexandria (but beware, I >> license my software under the AGPL3 license). > > That is best license currently for free software. I would use AGPL > myself, there is no incompatibility. > > OK I have all your repository on my computer. > > There is slight problem, there, if I come to directory, common-lisp, > and type make, thee command "lc" is missing. I don't have any > distribution, yet I tried looking on Debian server distribution, could > not find the package lc. > > I have tried ./compile.sh and make, yet, too many troubles. > Don’t use them, they’re outdated. The point of cloning it in ~/quicklisp/local-projects is to be able to load it with quicklisp. I gave you the exact expression to use! > ;;;; Compiling with clisp Common Lisp > clisp: /package/prog/clisp-clisp/lib/clisp-2.49+/full/lisp.run: No > such file or directory -- I don't know why. > >> cesarum currently can be found at: >> https://gitlab.com/com-informatimago/com-informatimago >> <https://gitlab.com/com-informatimago/com-informatimago> ; clone it >> in ~/quicklisp/local-projects and use (ql:quickload >> :com.informatimago.common-lisp.cesarum) to load it. > > I have it already. I cannot load it, don't know where to start. If you didn’t install it in ~/quicklisp/local-projects, then it will be harder. > > I do need cesarum, if you said it worked. Yes. That said, I left alexandria in your code that I modified to make it work. The limitation of alexandria shows only on string-stream, not on file-stream or (I assume) socket-stream. > >> And to help, I write a Makefile that will invoke the various CL >> implementations with the precise options to load >> generate-executable.lisp correctly (it changes from one >> implementation to another). >> >> >> >> [pjb@despina :0.0]$ make >> clisp -q -ansi -norc -x '(load "generate-executable.lisp")' -x '(quit)' >> ;; Loading file generate-executable.lisp ... >> ;; Loading file /Users/pjb/quicklisp/setup.lisp ... >> ;; Loading file /Users/pjb/quicklisp/ASDF.lisp ... >> ;; Loaded file /Users/pjb/quicklisp/ASDF.lisp >> ;; Loaded file /Users/pjb/quicklisp/setup.lisp >> To load "jean-cgi": >> Load 1 ASDF system: >> jean-cgi >> ; Loading "jean-cgi" >> >> >> Bytes permanently allocated: 172,224 >> Bytes currently in use: 6,034,936 >> Bytes available until next GC: 1,507,604 >> ;; Loaded file generate-executable.lisp >> T >> >> ~/Sites/cgi >> [pjb@despina :0.0]$ > > OK I see that is similar to my idea. I run the program in background, > which watches that file is saved. Yet, with or without Alexandria, > simple (exit) is not exiting in CGI, like Perl does. > >> So you can see how clisp is invoked to load generate-executable.lisp. >> generate-executable.lisp loads quicklisp, and then use it to compile >> and load jean-cgi. Finally it saves the executable image. >> >> In more complex programs, generate-executable.lisp would first >> delete the compiled fas files found in ~/.cache/common-lisp/*/… to >> ensure that all the fas file loaded by quicklisp are freshly >> compiled (notably with the *features* set that can be configured in >> generate-executable.lisp). > > OK thank you, I see, that is what I will implement. > >> Finally, we’ve obtained a CGI executable that we can test in the shell: >> >> [pjb@despina :0.0]$ ./jean.cgi </dev/null >> Status: 302 Found >> Location: http://localhost > > That is what I need, yet now I need to know how to implement it. > Look into the file I attached, instead of keeping them for later!!! -- __Pascal J. Bourguignon__ ------------------------------------------------------------------------------ Check out the vibrant tech community on one of the world's most engaging tech sites, Slashdot.org! http://sdm.link/slashdot _______________________________________________ clisp-list mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/clisp-list