unofficial mirror of guile-user@gnu.org 
 help / color / mirror / Atom feed
* Serving files with guile web server
@ 2011-03-16 23:33 romel
  2011-03-17 14:55 ` romel
  0 siblings, 1 reply; 10+ messages in thread
From: romel @ 2011-03-16 23:33 UTC (permalink / raw)
  To: guile-user

Hi,

I will like to serve plain text files and images with run-server from (web
server) module.

After reading the documentation I think in something similar to:

-----------------
(define (serve-file request body)
  (let* ((path (request-path-components request))
	 (file-path (public-file-path path)))
    (if (and file-path (file-exists? file-path))
	(values '((content-type . (text/plain)))
		(open-input-file file-path))
	(not-found request))))

(define (file-server)
  (run-server serve-file))
-----------------

But I got:

-----------------
ERROR: In procedure scm-error:
ERROR: unexpected body type

Entering a new prompt.  Type `,bt' for a backtrace or `,q' to continue.
scheme@(guile-user) [1]> ,bt

In module/web/server.scm:
   291:29  1 (#<procedure 22d9480 at module/web/server.scm:283:3 ()>)
In unknown file:
           0 (scm-error misc-error #f "~A" ("unexpected body type") #f)
-----------------

Anybody knows how to serve text and image files from guile web server?

Thanks,
Romel Sandoval






^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: Serving files with guile web server
  2011-03-16 23:33 Serving files with guile web server romel
@ 2011-03-17 14:55 ` romel
  2011-03-19  2:20   ` Neil Jerram
  0 siblings, 1 reply; 10+ messages in thread
From: romel @ 2011-03-17 14:55 UTC (permalink / raw)
  To: romel; +Cc: guile-user

I gave a second read to the manual and found:

"The handler should return two values: the response, as a <response>
record from (web response), and the response body as a string, bytevector,
or #f if not present."

If this is correct then I guess I should check the file type first and
then read the file to either create a string or a bytevector from it.

Any recommendation will be highly appreciated.

Thanks,
Romel Sandoval

> Hi,
>
> I will like to serve plain text files and images with run-server from (web
> server) module.
>
> After reading the documentation I think in something similar to:
>
> -----------------
> (define (serve-file request body)
>   (let* ((path (request-path-components request))
> 	 (file-path (public-file-path path)))
>     (if (and file-path (file-exists? file-path))
> 	(values '((content-type . (text/plain)))
> 		(open-input-file file-path))
> 	(not-found request))))
>
> (define (file-server)
>   (run-server serve-file))
> -----------------
>
> But I got:
>
> -----------------
> ERROR: In procedure scm-error:
> ERROR: unexpected body type
>
> Entering a new prompt.  Type `,bt' for a backtrace or `,q' to continue.
> scheme@(guile-user) [1]> ,bt
>
> In module/web/server.scm:
>    291:29  1 (#<procedure 22d9480 at module/web/server.scm:283:3 ()>)
> In unknown file:
>            0 (scm-error misc-error #f "~A" ("unexpected body type") #f)
> -----------------
>
> Anybody knows how to serve text and image files from guile web server?
>
> Thanks,
> Romel Sandoval
>
>
>
>
>






^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: Serving files with guile web server
  2011-03-17 14:55 ` romel
@ 2011-03-19  2:20   ` Neil Jerram
  2011-03-19 16:47     ` romel
  2011-03-22  8:51     ` Thien-Thi Nguyen
  0 siblings, 2 replies; 10+ messages in thread
From: Neil Jerram @ 2011-03-19  2:20 UTC (permalink / raw)
  To: romel; +Cc: guile-user

romel@lavabit.com writes:

> I gave a second read to the manual and found:
>
> "The handler should return two values: the response, as a <response>
> record from (web response), and the response body as a string, bytevector,
> or #f if not present."
>
> If this is correct then I guess I should check the file type first and
> then read the file to either create a string or a bytevector from it.
>
> Any recommendation will be highly appreciated.

Well, I suppose I'd recommend considering not using the Guile server to
serve static files.  Using Guile makes more sense when you want to
generate dynamic content, because then you're really using the
capabilities of the language.

In my web server experiments so far I've used Apache, modlisp and Guile
together, and this combination seems to work well.  Then Apache can
handle all the static content (I guess using the efficient sendfile)
without bothering modlisp or Guile, but dynamic stuff can be routed via
modlisp to Guile.

Regards,
      Neil



^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: Serving files with guile web server
  2011-03-19  2:20   ` Neil Jerram
@ 2011-03-19 16:47     ` romel
  2011-03-19 18:17       ` Neil Jerram
  2011-03-31 14:44       ` Andy Wingo
  2011-03-22  8:51     ` Thien-Thi Nguyen
  1 sibling, 2 replies; 10+ messages in thread
From: romel @ 2011-03-19 16:47 UTC (permalink / raw)
  To: Neil Jerram; +Cc: guile-user

Please see comments below.

Neil Jerram writes:
> romel@lavabit.com writes:
>
>> I gave a second read to the manual and found:
>>
>> "The handler should return two values: the response, as a <response>
>> record from (web response), and the response body as a string,
>> bytevector,
>> or #f if not present."

This is true but I found that when it comes about text is better to use a
lambda that receive a port and then write text to that port.

>>
>> If this is correct then I guess I should check the file type first and
>> then read the file to either create a string or a bytevector from it.

Is important to check the file type, if you need to serve an image you
must use the correct mime-type and a bytevertor.

>>
>> Any recommendation will be highly appreciated.
>
> Well, I suppose I'd recommend considering not using the Guile server to
> serve static files.  Using Guile makes more sense when you want to
> generate dynamic content, because then you're really using the
> capabilities of the language.
>
> In my web server experiments so far I've used Apache, modlisp and Guile
> together, and this combination seems to work well.  Then Apache can
> handle all the static content (I guess using the efficient sendfile)
> without bothering modlisp or Guile, but dynamic stuff can be routed via
> modlisp to Guile.
>

I think that's a good idea but while I was trying to setup my Apache I
found it complex compared to setting up something for python or java using
a web framework (maybe because of the lack of tutorials, examples,
frameworks, etc.), so I think that it would be great to have a standalone
server so you can instant hack something, or even for production, I think
it could be scalable using clusters.

So far I have been able to serve text files and images, it should work
with any mime-type now, but I have not test it yet.

Here is the piece of code that handles files for the curious:

	(let ((file-path (public-file-path path)))
	  (if (file-exists? file-path)
	      (let* ((mime-type (mime-type-ref file-path))
		     (mime-type-symbol (mime-type-symbol mime-type)))
		(if (text-mime-type? mime-type)
		    (values
		     `((content-type . (,mime-type-symbol)))
		     (lambda (out-port)
		       (call-with-input-file file-path
			 (lambda (in-port)
			   (display (read-delimited "" in-port)
                                                    out-port)))))
		    (values
		     `((content-type . (,mime-type-symbol)))
		     (call-with-input-file file-path
			 (lambda (in-port)
			   (get-bytevector-all in-port))))))
	      (not-found request)))

I hope it's readable :-)

Guile web module it's great!

Thanks,
Romel Sandoval






^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: Serving files with guile web server
  2011-03-19 16:47     ` romel
@ 2011-03-19 18:17       ` Neil Jerram
  2011-03-19 22:23         ` romel
  2011-03-31 14:44       ` Andy Wingo
  1 sibling, 1 reply; 10+ messages in thread
From: Neil Jerram @ 2011-03-19 18:17 UTC (permalink / raw)
  To: romel; +Cc: guile-user

romel@lavabit.com writes:

> So far I have been able to serve text files and images, it should work
> with any mime-type now, but I have not test it yet.
>
> Here is the piece of code that handles files for the curious:
>
> 	(let ((file-path (public-file-path path)))
> 	  (if (file-exists? file-path)
> 	      (let* ((mime-type (mime-type-ref file-path))
> 		     (mime-type-symbol (mime-type-symbol mime-type)))
> 		(if (text-mime-type? mime-type)
> 		    (values
> 		     `((content-type . (,mime-type-symbol)))
> 		     (lambda (out-port)
> 		       (call-with-input-file file-path
> 			 (lambda (in-port)
> 			   (display (read-delimited "" in-port)
>                                                     out-port)))))
> 		    (values
> 		     `((content-type . (,mime-type-symbol)))
> 		     (call-with-input-file file-path
> 			 (lambda (in-port)
> 			   (get-bytevector-all in-port))))))
> 	      (not-found request)))
>
> I hope it's readable :-)

Certainly, it looks good.  Where does mime-type-ref come from, though?

Perhaps that could be wrapped up as `static-file-response' (or a better
name if you can think of one) and added to (web server).

Regards,
     Neil



^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: Serving files with guile web server
  2011-03-19 18:17       ` Neil Jerram
@ 2011-03-19 22:23         ` romel
  0 siblings, 0 replies; 10+ messages in thread
From: romel @ 2011-03-19 22:23 UTC (permalink / raw)
  To: Neil Jerram; +Cc: guile-user

Neil Jerram writes:
> Certainly, it looks good.  Where does mime-type-ref come from, though?
>

Thanks, mime-type-ref comes from (glider mime-types) it's a little module
I wrote specifically for this purpose, see code below

(define-module (glider mime-types)
  :export (mime-type-ref text-mime-type? mime-type-symbol))

(define *mime-types* (make-hash-table 31))
(hash-set! *mime-types* "css" '("text" . "css"))
(hash-set! *mime-types* "txt" '("text" . "plain"))
(hash-set! *mime-types* "png" '("image" . "png"))
(hash-set! *mime-types* "jpg" '("image" . "jpeg"))
(hash-set! *mime-types* "jpeg" '("image" . "jpeg"))
(hash-set! *mime-types* "gif" '("image" . "gif"))

(define (mime-type-ref file-name)
  (let* ((dot-position (string-rindex file-name #\.))
	 (extension (and dot-position
			 (string-copy file-name (+ dot-position 1))))
	 (mime-type (and dot-position
			 (hash-ref *mime-types* extension))))
    (if mime-type mime-type '("application" . "octet-stream"))))

(define (mime-type-symbol mime-type)
  (string->symbol (string-append (car mime-type) "/" (cdr mime-type))))

(define (text-mime-type? mime-type)
  (if (equal? (car mime-type) "text") #t #f))

> Perhaps that could be wrapped up as `static-file-response' (or a better
> name if you can think of one) and added to (web server).

It would be great to have static file serving available from (web server),
I think that static-file-response is a good name.

Thanks,
Romel Sandoval






^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: Serving files with guile web server
  2011-03-19  2:20   ` Neil Jerram
  2011-03-19 16:47     ` romel
@ 2011-03-22  8:51     ` Thien-Thi Nguyen
  2011-03-31 14:23       ` Andy Wingo
  1 sibling, 1 reply; 10+ messages in thread
From: Thien-Thi Nguyen @ 2011-03-22  8:51 UTC (permalink / raw)
  To: Neil Jerram; +Cc: guile-user

() Neil Jerram <neil@ossau.uklinux.net>
() Sat, 19 Mar 2011 02:20:47 +0000

   Well, I suppose I'd recommend considering not using
   the Guile server to serve static files.

If efficiency is a concern, another approach is to wrap
sendfile(2) or something like it.

 http://www.gnuvola.org/software/ttn-do/ttn-do.html.gz#index-sendfile-140

This is what "ttn-do sizzweb", "ttn-do serve-debiso" and the
serveez packages do, although for the latter the wrapping is
admittedly very thin (C only) at present.  That may change...

 http://www.gnuvola.org/software/ttn-do/ttn-do.html.gz#sizzweb
 http://www.gnuvola.org/software/ttn-do/ttn-do.html.gz#serve-debiso
 http://git.savannah.gnu.org/cgit/serveez.git?h=next
 https://github.com/spk121/serveez-mg/

Probably a good exercise for Guile 2 FFI.  If sendfile (or ilk) is
too Linux- (or ilk) specific, a nice fallback would be to wrap the
POSIX scatter/gather support, i.e., writev(2)/readv(2).

 http://www.gnuvola.org/software/ttn-do/ttn-do.html.gz#index-iovec-142
 http://www.gnuvola.org/software/ttn-do/ttn-do.html.gz#index-writev-144
 http://www.gnuvola.org/software/ttn-do/ttn-do.html.gz#index-readv-143

This is what (ttn-do zzz x-protocol) uses, albeit sub-optimally for now.

 http://www.gnuvola.org/software/ttn-do/ttn-do.html.gz#zzz-x_002dprotocol



^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: Serving files with guile web server
  2011-03-22  8:51     ` Thien-Thi Nguyen
@ 2011-03-31 14:23       ` Andy Wingo
  2011-03-31 15:09         ` Andy Wingo
  0 siblings, 1 reply; 10+ messages in thread
From: Andy Wingo @ 2011-03-31 14:23 UTC (permalink / raw)
  To: Thien-Thi Nguyen; +Cc: guile-user, Neil Jerram

On Tue 22 Mar 2011 09:51, Thien-Thi Nguyen <ttn@gnuvola.org> writes:

> If efficiency is a concern, another approach is to wrap
> sendfile(2) or something like it.

IMHO we should bind sendfile(2) in Guile itself.

Andy
-- 
http://wingolog.org/



^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: Serving files with guile web server
  2011-03-19 16:47     ` romel
  2011-03-19 18:17       ` Neil Jerram
@ 2011-03-31 14:44       ` Andy Wingo
  1 sibling, 0 replies; 10+ messages in thread
From: Andy Wingo @ 2011-03-31 14:44 UTC (permalink / raw)
  To: romel; +Cc: guile-user, Neil Jerram

On Sat 19 Mar 2011 17:47, romel@lavabit.com writes:

>> romel@lavabit.com writes:
>>
>>> I gave a second read to the manual and found:
>>>
>>> "The handler should return two values: the response, as a <response>
>>> record from (web response), and the response body as a string,
>>> bytevector,
>>> or #f if not present."
>
> This is true but I found that when it comes about text is better to use a
> lambda that receive a port and then write text to that port.

I have added info about returning procedures as response bodies to the
doc.  Thanks.

It would be good for sanitize-response to support ports as well, I
think.

> I think that it would be great to have a standalone server so you can
> instant hack something, or even for production, I think it could be
> scalable using clusters.

I think more standalone capabilities is a good thing.  It's nice to be
able to throw up a server for testing.  For production though you really
need to not do blocking reads or writes.

> Guile web module it's great!

Thanks!  Have fun and let us know how it goes :)

Andy
-- 
http://wingolog.org/



^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: Serving files with guile web server
  2011-03-31 14:23       ` Andy Wingo
@ 2011-03-31 15:09         ` Andy Wingo
  0 siblings, 0 replies; 10+ messages in thread
From: Andy Wingo @ 2011-03-31 15:09 UTC (permalink / raw)
  To: Thien-Thi Nguyen; +Cc: guile-user, Neil Jerram

On Thu 31 Mar 2011 16:23, Andy Wingo <wingo@pobox.com> writes:

> On Tue 22 Mar 2011 09:51, Thien-Thi Nguyen <ttn@gnuvola.org> writes:
>
>> If efficiency is a concern, another approach is to wrap
>> sendfile(2) or something like it.
>
> IMHO we should bind sendfile(2) in Guile itself.

Well, I guess I take that back:

  http://thread.gmane.org/gmane.comp.lib.gnulib.bugs/25012

But we'll still be here whenever gnulib figures out what it is they want
to name it :)

Andy
-- 
http://wingolog.org/



^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2011-03-31 15:09 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-03-16 23:33 Serving files with guile web server romel
2011-03-17 14:55 ` romel
2011-03-19  2:20   ` Neil Jerram
2011-03-19 16:47     ` romel
2011-03-19 18:17       ` Neil Jerram
2011-03-19 22:23         ` romel
2011-03-31 14:44       ` Andy Wingo
2011-03-22  8:51     ` Thien-Thi Nguyen
2011-03-31 14:23       ` Andy Wingo
2011-03-31 15:09         ` Andy Wingo

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).