{"size": 12038, "ext": "scrbl", "max_stars_repo_path": "web-server-doc/web-server/scribblings/servlet-env.scrbl", "max_stars_repo_name": "jessealama/web-server", "max_stars_repo_stars_event_min_datetime": "2015-01-21T08:11:58.000Z", "max_stars_repo_stars_event_max_datetime": "2022-03-20T08:28:39.000Z", "max_issues_repo_path": "web-server-doc/web-server/scribblings/servlet-env.scrbl", "max_issues_repo_name": "jessealama/web-server", "max_issues_repo_issues_event_min_datetime": "2015-01-14T08:06:37.000Z", "max_issues_repo_issues_event_max_datetime": "2022-02-12T14:38:40.000Z", "max_forks_repo_path": "web-server-doc/web-server/scribblings/servlet-env.scrbl", "max_forks_repo_name": "jessealama/web-server", "max_forks_repo_forks_event_min_datetime": "2015-03-05T15:07:36.000Z", "max_forks_repo_forks_event_max_datetime": "2021-07-30T18:59:25.000Z"}
{"max_stars_count": 82, "max_issues_count": 105, "max_forks_count": 37, "avg_line_length": 47.9601593625, "max_line_length": 252, "alphanum_fraction": 0.6279282273}
#lang scribble/doc
@(require "web-server.rkt")

@title[#:tag "servlet-env"]{Simple Single Servlet Servers}
@(require (for-label web-server/servlet-env
                     web-server/http
                     web-server/managers/lru
                     web-server/managers/manager
                     web-server/lang/lang-api
                     web-server/private/util
                     web-server/dispatchers/dispatch
                     web-server/configuration/configuration-table
                     web-server/configuration/responders
                     web-server/dispatchers/dispatch-log
                     net/url
                     racket/serialize
                     web-server/stuffers
                     web-server/servlet/servlet-structs
                     web-server/servlet-dispatch
                     web-server/safety-limits
                     racket/list))

@defmodule[web-server/servlet-env]

The @web-server provides a way to quickly configure and start a servlet with more customizability than @racketmodname[web-server/insta] provides. This is provided by the @racketmodname[web-server/servlet-env] module.

@section{Examples}

Here is a simple example of its use:
@racketmod[
racket
(require web-server/servlet
         web-server/servlet-env)

(define (start req)
  (response/xexpr
   `(html (head (title "Hello world!"))
          (body (p "Hey out there!")))))

(serve/servlet start)
]

Unlike the @racketmodname[web-server/insta] language, @racket[start] is not a special identifier, so we could just as well have written the example as:
@racketmod[
racket
(require web-server/servlet
         web-server/servlet-env)

(define (my-app req)
  (response/xexpr
   `(html (head (title "Hello world!"))
          (body (p "Hey out there!")))))

(serve/servlet my-app)
]

Let's look at some of the customizations @racket[serve/servlet] allows.

Suppose you'd like to change the port to something else, change the last line to:
@racketblock[
(serve/servlet my-app 
               #:port 8080)
]

Suppose you want to accept connections from external machines:
@racketblock[
(serve/servlet my-app 
               #:listen-ip #f)
]

By default the URL for your servlet is @filepath{http://localhost:8000/servlets/standalone.rkt}, 
suppose you wanted it to be @filepath{http://localhost:8000/hello.rkt}:
@racketblock[
(serve/servlet my-app
               #:servlet-path "/hello.rkt")
]

Suppose you wanted it to capture top-level requests:
@racketblock[
(serve/servlet my-app
               #:servlet-regexp #rx"")
]
Or, perhaps just some nice top-level name:
@racketblock[
(serve/servlet my-app
               #:servlet-path "/main")
]

Suppose you wanted to use a style-sheet (@filepath{style.css}) found on your Desktop (@filepath{/Users/jay/Desktop/}):
@racketblock[
(serve/servlet my-app
               #:extra-files-paths 
               (list
                (build-path "/Users/jay/Desktop")))
]
These files are served @emph{in addition} to those from the @racket[#:server-root-path] @filepath{htdocs} directory.
You may pass any number of extra paths.

If you want to use @racket[serve/servlet] in a start up script for a Web application,
and don't want a browser opened or the DrRacket banner printed, then you can write:
@racketblock[
(serve/servlet my-app
               #:command-line? #t)
]

@subsection{Stateless Servlets}

Suppose you would like to start a server for a stateless Web servlet @filepath{servlet.rkt} that provides @racketid[start]:
@racketmod[
 racket
 (require "servlet.rkt"
          web-server/servlet-env)

 (serve/servlet start #:stateless? #t)
]

You can also put the call to @racket[serve/servlet] in the @racketmodname[web-server] module directly:
@racketmod[
 web-server
 (require web-server/servlet-env)
 
 (define (start req)
   (start
    (send/suspend
     (lambda (k-url)
       (response/xexpr
        `(html (body (a ([href ,k-url]) "Hello world!"))))))))
 
 (serve/servlet start #:stateless? #t)
]
Like always, you don't even need to save the file.

@section{Full API}

@defproc[(serve/servlet [start (request? . -> . can-be-response?)]
                        [#:command-line? command-line? boolean? #f]
                        [#:connection-close? connection-close? boolean? #f]
                        [#:launch-browser? launch-browser? boolean? (not command-line?)]
                        [#:quit? quit? boolean? (not command-line?)]
                        [#:banner? banner? boolean? (not command-line?)]
                        [#:listen-ip listen-ip (or/c #f string?) "127.0.0.1"]
                        [#:port port listen-port-number? 8000]
                        [#:max-waiting max-waiting exact-nonnegative-integer? 511]
                        [#:safety-limits safety-limits safety-limits?
                         (make-safety-limits #:max-waiting max-waiting)]
                        [#:servlet-path servlet-path string?
                                        "/servlets/standalone.rkt"]
                        [#:servlet-regexp servlet-regexp regexp?
                                          (regexp 
                                           (format "^~a$" (regexp-quote servlet-path)))]
                        [#:stateless? stateless? boolean? #f]
                        [#:stuffer stuffer (stuffer/c serializable? bytes?) default-stuffer]
                        [#:manager manager manager? (make-threshold-LRU-manager #f (* 128 1024 1024))]
                        [#:servlet-namespace servlet-namespace (listof module-path?) empty]
                        [#:server-root-path server-root-path path-string? (collection-path "web-server" "default-web-root")]
                        [#:extra-files-paths extra-files-paths (listof path-string?) (list (build-path server-root-path "htdocs"))]
                        [#:servlets-root servlets-root path-string? (build-path server-root-path "htdocs")]
                        [#:servlet-current-directory servlet-current-directory path-string? servlets-root]
                        [#:file-not-found-responder file-not-found-responder
                                                    (request? . -> . can-be-response?)
                                                    (gen-file-not-found-responder 
                                                     (build-path
                                                      server-root-path
                                                      "conf"
                                                      "not-found.html"))]
                        [#:servlet-loading-responder
                         responders-servlet-loading
                         (url? any/c . -> . can-be-response?)
                         servlet-loading-responder]
                        [#:servlet-responder
                         responders-servlet
                         (url? any/c . -> . can-be-response?)
                         servlet-error-responder]
                        [#:mime-types-path mime-types-path path-string?
                                           ....]
                        [#:ssl? ssl? boolean? #f]
                        [#:ssl-cert ssl-cert (or/c #f path-string?) (and ssl? (build-path server-root-path "server-cert.pem"))]
                        [#:ssl-key ssl-key (or/c #f path-string?) (and ssl? (build-path server-root-path "private-key.pem"))]

                        [#:log-file log-file (or/c #f path-string? output-port?) #f]
                        [#:log-format log-format (or/c log-format/c format-req/c) 'apache-default])
                       any]{
 This sets up and starts a fairly default server instance.
      
 @racket[start] is loaded as a servlet and responds to requests that match @racket[servlet-regexp]. The current directory
 of servlet execution is @racket[servlet-current-directory].

 If @racket[launch-browser?] is true, then a web browser is opened to @filepath{http://localhost:<port><servlet-path>}. @racket[servlet-path] has no other purpose, if @racket[servlet-regexp] is provided.
 
 If @racket[quit?] is true, then the URL @filepath["/quit"] ends the server.
  
 If @racket[stateless?] is true, then the servlet is run as a stateless @racketmod[web-server] module and @racket[stuffer] is used
 as the @tech{stuffer}.

@racket[serve/servlet] is simpler interface over
@racket[serve/launch/wait], @racket[dispatch/servlet], and a few of
the standard @secref["dispatchers" #:doc
'(lib "web-server/scribblings/web-server-internal.scrbl")]. Some
options, like @racket[port] and @racket[safety-limits] are transparently
passed to @racket[serve/launch/wait]. Some advanced customization
requires using these underlying pieces of the
@racketmodname[web-server] directly. However, many simpler
customizations do not, which the rest of this section describes.
 
 The server listens on @racket[listen-ip] and port @racket[port]. If @racket[listen-ip] is @racket[#f], then the server accepts 
 connections to all of the listening machine's addresses. Otherwise, the server accepts connections only at the interface(s) associated with the given string.
 For example, providing @racket["127.0.0.1"] (the default) as @racket[listen-ip] creates a server that accepts only connections to @racket["127.0.0.1"] (the loopback interface) from the local machine.
 
 If @racket[ssl-cert] and @racket[ssl-key] are not false, then the server runs in HTTPS mode with @racket[ssl-cert]
 and @racket[ssl-key] as the certificates and private keys.
 
 The servlet is loaded with @racket[manager]
 as its continuation manager. (The default manager limits the amount of memory to 64 MB and
 deals with memory pressure as discussed in the @racket[make-threshold-LRU-manager] documentation.)
 
 The server files are rooted at @racket[server-root-path] (which is
the @filepath{default-web-root} directory in the
@racketmodname[web-server] collection by default.)  File paths, in
addition to the @filepath["htdocs"] directory under
@racket[server-root-path] may be provided with
@racket[extra-files-paths]. These paths are checked first, in the
order they appear in the list.
 
 Other servlets are served from @racket[servlets-root]. 
 The modules specified by @racket[servlet-namespace] are shared between servlets found in @racket[servlets-root] and the current namespace (and therefore
 the @racket[start] procedure.)
 
 If a file cannot be found, @racket[file-not-found-responder] is used to generate an error response. If a servlet fails to load, @racket[responders-servlet-loading] is used. If a servlet errors during its operation, @racket[responders-servlet] is used.

 If @racket[banner?] is true, then an informative banner is printed. You may want to use this when
 running from the command line, in which case the @racket[command-line?] option controls similar options.
 
 MIME types are looked up at @racket[mime-types-path]. By default the @filepath{mime.types} file in the
 @racket[server-root-path] is used, but if that file does not exist, then the file that ships with the
 Web Server is used instead. Of course, if a path is given, then it overrides this behavior.

 If @racket[log-file] is given, then it used to log requests using @racket[log-format] as the format. Allowable formats
 are those allowed by @racket[log-format->format]. If @racket[log-format] is a function, it is used directly to render the log entry.
 If @racket[log-file] is a filepath, the given file is opened and written in a different thread. If @racket[log-file] is an @racket[output-port?], 
 logs are written directly to the port.
 
 If @racket[connection-close?] is @racket[#t], then every connection is closed after one
 request. Otherwise, the client decides based on what HTTP version it uses.

 @history[#:changed "1.6"
          @elem{Added the @racket[safety-limits] argument as with @racket[serve/launch/wait]:
            see @elemref["safety-limits-porting"]{compatability note}.}
          #:changed "1.3"
          @elem{Added support for providing @racket[log-file] as an output port.}]
}
