Re: Uploading a file to web server using Lisp



On Feb 5, 12:04 pm, nalle...@xxxxxxxxx wrote:
On Feb 5, 10:19 am, "Trastabuga" <lisper...@xxxxxxxxx> wrote:

Could anyone point me the direction how I can implement uploading
files from a web browser to a web server using lisp? Any libraries? Is
CGI the only way to accomplish it? There are lots of materials on how
to do it using PHP but I could nothing for Lisp.

Here's an exmple on how to do it with portableaserve http://www.cliki.net/Portableaserve(from examples.cl included in the
tarball)

http://paste.lisp.org/display/36419

hth

Nick

;; these two urls show how to transfer a user-selected file from
;; the client browser to the server.
;;
;; We use two urls (/getfile to put up the form and /getfile-post to
;; handle the post action of the form). We could have done it all
;; with one url but since there's a lot of code it helps in the
;; presentation to separate the two.
;;
(publish :path "/getfile-old"
:content-type "text/html; charset=utf-8"
:function #'(lambda (req ent) (getfile-function
req ent "/getfile-got-old")))

(publish :path "/getfile"
:content-type "text/html; charset=utf-8"
:function #'(lambda (req ent) (getfile-function
req ent "/getfile-got")))

(defun getfile-function (req ent posturl)
(with-http-response (req ent)
(with-http-body (req ent)
(html (:head "get file")
(:body
((:form :enctype "multipart/form-data"
:method "post"
:action posturl)
"Let me know what file to grab"
:br
((:input :type "file"
:name "thefile"
:value "*.txt"))
:br
((:input :type "text" :name "textthing"))
"Enter some text"
:br
((:input :type "checkbox" :name "checkone"))
"check box one"
:br
((:input :type "checkbox" :name "checktwo"))
"check box two"
:br
((:input :type "submit"))))))))


this would probubly also help

http://paste.lisp.org/display/36419#1

Nick

;;
;; this demonstrates the use of the low level multipart access
functions.
;; In this code we parse the result of get-multipart-header ourselves
;; and we use get-multipart-sequence.
;; In the example that follows (associate with path "/getfile-got")
;; we show now to use the higher level functions to retrive multipart
;; data
(publish :path "/getfile-got-old"
:content-type "text/html; charset=utf-8"
:function
#'(lambda (req ent)

(with-http-response (req ent)
(let ((h nil)
(files-written)
(text-strings)
)
(loop
; get headers for the next item
(if* (null (setq h (get-multipart-header req)))
then ; no more items
(return))
; we can get the filename from the header if
; it was an <input type="file"> item. If there is
; no filename, we just create one.
(pprint h)
(pprint (multiple-value-list (parse-multipart-
header h)))
(let ((cd (assoc :content-disposition h :test
#'eq))
(filename)
(sep))
(if* (and cd (consp (cadr cd)))
then (setq filename (cdr (assoc "filename"
(cddr (cadr
cd))
:test
#'equalp)))
(if* filename
then ;; locate the part of the
filename
;; after the last directory
separator.
;; the common lisp pathname
functions are
;; no help since the filename
syntax
;; may be foreign to the OS on
which
;; the server is running.
(setq sep
(max (or (position #\/ filename
:from-end t)
-1)
(or (position #\\ filename
:from-end t)
-1)))
(setq filename
(subseq filename (1+ sep)
(length filename)))))
(if* (and filename (not (equal filename "")))
then (push filename files-written)
(with-open-file (pp
filename :direction :output
:if-exists :supersede
:element-type '(unsigned-
byte 8))
(format t "writing file ~s~%" filename)
(let ((buffer (make-array 4096
:element-
type
'(unsigned-
byte 8))))

(loop (let ((count (get-multipart-
sequence
req
buffer)))
(if* (null count) then
(return))
(write-sequence buffer
pp :end count)))))
elseif (null filename)
then ; no filename, just grab as a text
; string
(let ((buffer (make-string 1024)))
(loop
(let ((count (get-multipart-sequence
req buffer
:external-format :utf8-
base)))
(if* count
then (push (subseq buffer 0
count)
text-strings)
else (return))))))))



;; now send back a response for the browser

(with-http-body (req ent
:external-format :utf8-base)
(html (:html (:head (:title "form example"))
(:body "-- processed the form, files
written --"
(dolist (file (nreverse files-
written))
(html :br "file: "
(:b (:prin1-safe
file))))
:br
"-- Non-file items Returned: --
" :br
(dolist (ts (reverse text-
strings))
(html (:princ-safe
ts) :br))))))))))


;;
;; this retrieves data from a multipart form using the high level
;; functions. You can compare this code to that above to see which
;; method you prefer
;;
(publish :path "/getfile-got"
:content-type "text/html; charset=utf-8"
:function
#'(lambda (req ent)
(with-http-response (req ent)
(let ((files-written)
(text-strings)
(overlimit)
)
(loop
(multiple-value-bind (kind name filename content-
type)
(parse-multipart-header
(get-multipart-header req))

(case kind
(:eof (return)) ; no more to read
(:data
(push (cons name (get-all-multipart-data req))
text-strings))
(:file
(let ((contents (get-all-multipart-data
req
:type :binary
:limit 1000000 ; abitrary
limit
)))
; find the tail of the filename, can't use
; lisp pathname code since the filename
syntax
; may not correspond to this lisp's native
os
(let ((sep (max (or (position #\/ filename
:from-end t)
-1)
(or (position #\\ filename
:from-end t)
-1))))
(if* sep
then (setq filename
(subseq filename (1+ sep)))))
(if* (eq contents :limit)
then ; tried to give us too much
(setq overlimit t)
elseif (equal filename "") ; no file given
thenret ; ignore
else
(with-open-file (p filename
:direction :output
:if-
exists :supersede
:element-type
'(unsigned-byte 8))
(format
t "writing file ~s, content-type
~s~%"
filename content-type)
(push filename files-written)
(write-sequence contents p)))))
(t ; all else ignore but read to next header
(get-all-multipart-data req :limit 1000)))))




;; now send back a response for the browser

(with-http-body (req ent
:external-format :utf8-base)
(html (:html (:head (:title "form example"))
(:body "-- processed the form, files
written --"
(dolist (file (nreverse files-
written))
(html :br "file: "
(:b (:prin1-safe
file))))
(if* overlimit
then (html :br
"File given was
over our "
"limit in the
size we "
"will accept"))
:br
"-- Non-file items Returned: --
" :br
(dolist (ts (reverse text-
strings))
(html
"item name: " (:princ-safe
(car ts))
", item value: "
(:princ-safe (cdr ts))
:br))))))))))

.



Relevant Pages

  • Re: Convince me not to use eval
    ... The macro takes a directory name and a filename (it's meant to be ... manipulate symbols/identifiers in Lisp is much greater than in other ... TK) and then take this new variable and load the actual filename onto ... Look ma, no EVALs. ...
    (comp.lang.lisp)
  • Re: IIS replacing blanks
    ... Can you give the exact filename you are trying to access via the browser? ... And are you trying to retrieve it from a web server via HTTP or what ... HTTP URLs cannot have spaces in it, so it is translated to %20 by the client ...
    (microsoft.public.inetserver.iis)
  • Re: download counter?
    ... create table counter (filename varchar(100), ... Better then redirecting is to read file in php script, send to browser and write to sql table after a file is complete send. ... This avoid a situation when user cancel download. ...
    (comp.lang.php)
  • Creating a pseudo filename for downloading? help!
    ... filename rather than the actual filename on the server ... Tells the browser to expect a download ... Tells the browser the format of the data ...
    (comp.lang.php)
  • Creating a pseudo filename for downloading? help!
    ... When the user clicks on the URL that we send him I need the PHP ... filename rather than the actual filename on the server ... Tells the browser the format of the data ...
    (comp.lang.php)