[racket] Servlet static file paths, I just don't get it

From: Jay McCarthy (jay.mccarthy at gmail.com)
Date: Mon Sep 30 21:14:02 EDT 2013

On Sun, Sep 29, 2013 at 1:50 PM, Erich Rast <erich at snafu.de> wrote:
> Thanks a lot! That's what I was suspecting already.
>
> But I still wonder how to do achieve what I want. how do I make
> "http://my-server.com/lottery" respond to my lottery servlet, but every
> other request to respond with respond-unknown *and also* show an
> image file within respond-unknown? Is there no way to load a static
> file (e.g. by relative path) within such a "catch all" handler?

The Racket Web server is not a monolithic blob that insists things
happen one way. It's really a library for building Web servers.

The default dispatcher sequence of serve/servlet puts the filesystem
handler after the servlet handler. You could just switch them on your
machine, then real files would have precedence over the servlet. You
would do this by decomposing serve/servlet into a call to
serve/launch/wait, dispatch/servlet, and make from
dispatchers/dispatch-files.

Alternatively, if you have small number of files then you could add
some clauses to dispatch-rules like

[("funny-fish.png") fail-to-fs]

where fail-to-fs is

(define (fail-to-fs req) (next-dispatcher))

Alternatively, you could embed the code that serves files

[("funny-fish.png") serve-fish]

(define (serve-fish req)
 (file-response 200 #"OK" "funny-fish.png"))

OR

[("funny-fish.png") serve-fish]

(define (serve-fish req)
 (response 200 #"OK" 0 #"image/png" empty (lambda (op)
(with-input-from-file "funny-fish.png" (lambda () (copy-ports
(current-input-port) op)))))

There are a lot of options.

Jay

> I'm using a dispatcher because I want to later add lots of experimental
> servlets, all of which should have easy urls (my-server/lottery,
> my-server/test, etc.). Everything else should be handled by
> respond-unknown. Do I have to use a static web page instead of
> respond-unknown?
>
> Best,
>
> Erich
>
> On Sat, 28 Sep 2013 21:57:21 -0600
> Jay McCarthy <jay.mccarthy at gmail.com> wrote:
>
>> Hi Erich,
>>
>> You have programmed your servlet to respond to all requests, including
>> requests to URLs like "http://your-server.com/images/Sloth.png". If
>> you go to that URL, you'll see that it shows you the result of
>> respond-unknown.
>>
>> On Sat, Sep 28, 2013 at 4:05 PM, Erich Rast <erich at snafu.de> wrote:
>> > This is driving me nuts, I just cannot find the place where my
>> > servlet gets static files from. I run the following "server.scm" in
>> > a directory in which there is also "htdocs/images/Sloth.png" but no
>> > matter what combination of img src file paths and extra-file-paths
>> > I try, respond-unknown does not want to display the Sloth.png when
>> > I click run:
>> >
>> > #lang racket
>> > (require web-server/web-server
>> >          web-server/dispatch
>> >           web-server/servlet-env
>> >           web-server/servlet)
>> > (require "lottery/darkstar-lottery.scm")
>> >
>> > (define (respond-unknown req)
>> >   (response/xexpr '(html
>> >      (head (title "The 3-Toed Sloth"))
>> >      (body
>> >       (img ([src "images/Sloth.png"]))
>> >       (h1 "Under construction")))))
>> >
>> > (define-values (dispatch input-url)
>> >   (dispatch-rules
>> >    (("lottery") lottery-app)
>> >    (else respond-unknown)))
>>
>> You did it right here when you said that if you go to anything other
>> than "/lottery" then you should run 'respond-unknown'
>>
>> If you look at section 5.1 of the documentation (the first section on
>> dispatch-rules) that has this paragraph:
>>
>> "When you use web-server/dispatch with serve/servlet, you almost
>> always want to use the #:servlet-regexp argument with the value "" to
>> capture all top-level requests. However, make sure you don’t include
>> an else in your rules if you are also serving static files, or else
>> the filesystem server will never see the requests."
>>
>> The problem mentioned is exactly what you did.
>>
>> Jay
>>
>> >
>> > (serve/servlet dispatch ; answers requests
>> >                #:servlet-path "" ; is the default URL
>> >                #:extra-files-paths (list (build-path
>> >                (current-directory) "htdocs"))
>> >                #:port 8080 ; is the port
>> >                #:servlet-regexp #rx"")
>> >
>> > How do I make the servlet serve the file "htdocs/images/Sloth.png"
>> > relative to the servlet source directory and how do I address it in
>> > the "img" tag? I tried absolute paths, too, but no luck.
>> >
>> > Best,
>> >
>> > Erich
>> >
>> > P.S. For completeness, the content of
>> > lottery/darkstar-lottery.scm:
>> >
>> > #lang racket
>> > (require web-server/servlet
>> >          web-server/servlet-env)
>> > (provide lottery-app)
>> >
>> > (define (draw n total)
>> >   (sort
>> >    (take
>> >     (shuffle (for/list ((i (in-range total)))
>> >                (add1 i)))
>> >     n)
>> >    <))
>> >
>> > (define (stringify numbers)
>> >   (string-append
>> >    (apply string-append
>> >           (for/list ([n (in-list (reverse (cdr (reverse
>> > numbers))))]) (format "~a, " n)))
>> >    (format "~a" (car (reverse numbers)))))
>> >
>> > (define (euromillions)
>> >   (define (draw-5-of-50)
>> >     (draw 5 50))
>> >   (define (draw-2-of-11)
>> >     (draw 2 11))
>> >   (format "The next lottery result is ~a with additional numbers
>> > ~a." (stringify (draw-5-of-50))
>> >           (stringify (draw-2-of-11))))
>> >
>> > (define (lottery-app req)
>> >   (response/xexpr
>> >    `(html (head (title "Euromillions"))
>> >           (body (p ,(euromillions))))))
>> >
>> > ;(serve/servlet lottery-app
>> > ;               #:servlet-path "/lottery"
>> > ;               #:port 8080
>> > ;               #:command-line #t)
>> > ____________________
>> >   Racket Users list:
>> >   http://lists.racket-lang.org/users
>>
>>
>>
>



-- 
Jay McCarthy <jay at cs.byu.edu>
Assistant Professor / Brigham Young University
http://faculty.cs.byu.edu/~jay

"The glory of God is Intelligence" - D&C 93


Posted on the users mailing list.