[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[elpa] 46/119: more documentation and examples
From: |
Eric Schulte |
Subject: |
[elpa] 46/119: more documentation and examples |
Date: |
Mon, 10 Mar 2014 16:57:19 +0000 |
eschulte pushed a commit to branch master
in repository elpa.
commit 1293830a2582cbc9be9bcf8703c37dc35136eed1
Author: Eric Schulte <address@hidden>
Date: Wed Dec 25 17:08:09 2013 -0700
more documentation and examples
---
NOTES | 2 +-
README | 3 +-
doc/emacs-web-server.texi | 105 +++++++++++++++++++++++++++++++---------
emacs-web-server-test.el | 14 +++++
emacs-web-server.el | 8 +--
examples/0-hello-world.el | 7 ++-
examples/1-hello-world-utf8.el | 33 +++++++------
examples/2-hello-world-html.el | 9 ++--
examples/3-file-server.el | 16 ++++--
examples/4-url-param-echo.el | 23 +++++----
examples/5-post-echo.el | 24 +++++----
11 files changed, 163 insertions(+), 81 deletions(-)
diff --git a/NOTES b/NOTES
index 26e018a..78030da 100644
--- a/NOTES
+++ b/NOTES
@@ -2,7 +2,7 @@
* Notes
* Tasks [7/9]
-** TODO Documentation [0/4]
+** STARTED Documentation [0/4]
- [ ] introduction
- [ ] handlers
- [ ] request headers
diff --git a/README b/README
index 6f7ccd7..78d4d6a 100644
--- a/README
+++ b/README
@@ -12,4 +12,5 @@ STATUS
EXAMPLES
See the examples/ directory in this repository. The Emacs Web
- Server is also used to run https://github.com/eschulte/el-sprunge.
+ Server is also used to run https://github.com/eschulte/el-sprunge
+ and https://github.com/eschulte/org-ehtml/tree/emacs-web-server.
diff --git a/doc/emacs-web-server.texi b/doc/emacs-web-server.texi
index e5ac1c9..30d79cf 100644
--- a/doc/emacs-web-server.texi
+++ b/doc/emacs-web-server.texi
@@ -41,7 +41,7 @@ A copy of the license is included in the section entitled
@end ifnottex
@menu
-* Introduction:: Getting to know the Emacs Web Server
+* Introduction:: Overview of the Emacs Web Server
* Handlers:: Handlers respond to HTTP requests
* Request:: Getting information on HTTP requests
* Usage Examples:: Examples demonstrating usage
@@ -65,30 +65,32 @@ Appendices
@chapter Introduction
@cindex introduction
-The Emacs Web Server is a Web server implemented in Emacs Lisp using
-Emacs network communication primitives. HTTP requests are matched to
-handlers (@pxref{Handlers}) which are implemented as Emacs Lisp
-functions. Handler functions receive a request object
-(@pxref{Request}) which holds information about the request and the
-HTTP connection process. Handlers write their responses directly to
-the connection process.
+The Emacs Web Server is a Web server implemented entirely in Emacs
+Lisp. HTTP requests are matched to handlers (@pxref{Handlers}) which
+are Emacs Lisp functions. Handlers receive as their only argument a
+request object (@pxref{Request}) which holds information about the
+request and the process holding HTTP network connection. Handlers
+write their responses directly to the network process.
A number of examples (@pxref{Usage Examples}) demonstrate usage of the
-Emacs Web Server. Finally, the functions defining the interface are
+Emacs Web Server. All public functions of the Emacs Web Server are
listed (@pxref{Function Index}).
@node Handlers, Request, Handlers, Top
@chapter Handlers
@cindex handlers
-The Emacs Web Server is started with the @code{ews-start} function
-which takes a ``handlers'' association list which is composed of pairs
-of matchers and handler functions.
+The function @code{ews-start} takes takes two arguments
address@hidden and @code{port}. It starts a server listening on
address@hidden responding to requests with @code{handlers}, an
+association list composed of pairs of matchers and handler functions.
address@hidden may be either a simple regular expression or a
-function. A simple matcher consists of an HTTP header and a regular
-expression. When the regular expression matches the content of that
-header the simple matcher succeeds and the associated handler is
address@hidden Matchers
+
+Matchers may be a regular expression or a function. Regular
+expression matchers consists of an HTTP header and a regular
+expression. When the regular expression matches the content of the
+given header the matcher succeeds and the associated handler is
called. For example the following matches any @code{GET} request
whose path starts with the substring ``foo''.
@@ -96,9 +98,9 @@ whose path starts with the substring ``foo''.
(:GET . "^foo")
@end example
-A complex matcher is a function which takes the request object
+A function matcher is a function which takes the request object
(@pxref{Request}) and succeeds when the function returns a non-nil
-value. For example the following matcher matches every request
+value. For example the following matcher matches every request,
@example
(lambda (_) t)
@@ -108,17 +110,34 @@ and the following matches only requests in which the
supplied
``number'' parameter is odd.
@example
-(lambda (request) (oddp (cdr (assoc "number" request))))
+(lambda (request)
+ (oddp (string-to-number (cdr (assoc "number" request)))))
@end example
address@hidden Handler
+
+Each handler is a function which takes a request object
+(@pxref{Request}) as its only argument. The function may respond to
+the request by writing to the network process held in the
address@hidden field of the request object. For example, the
address@hidden function may be used to write string data
+to a request as in the following.
+
address@hidden
+ (process-send-string (process request) "hello world")
address@hidden example
+
+When the handler function exits the connection is terminated unless
+the handler function returns the keyword @code{:keep-alive}.
+
@node Request, Usage Examples, Handlers, Top
@chapter Request
@cindex request
-Information on requests is stored in a @code{request} object. The
+Each HTTP requests is represented using a @code{request} object. The
request object is used to decide which handler to call, and is passed
-to the called handler. This object holds information on the request
-including the request process, all HTTP headers, and parameters.
+as an argument to the called handler. The request object holds the
+network process, all HTTP headers, and any parameters.
The text of the request is parsed into an alist. HTML Headers are
keyed using uppercase keywords (e.g., @code{:GET}), and user supplied
@@ -140,27 +159,67 @@ These examples demonstrate usage.
@node Hello World, Hello World UTF8, Usage Examples, Usage Examples
@section Hello World
+
+The simplest possible ``hello world'' example. The handler consists
+of a single (matcher . handler) pair. The function matcher matches
address@hidden incoming HTTP request. The handler responds by setting
+the content type to @code{text/plain}, and then sending the string
+``hello world''. When the handler exits the network connection of the
+request is closed.
+
@verbatiminclude ../examples/0-hello-world.el
@node Hello World UTF8, Hello World HTML, Hello World, Usage Examples
@section Hello World UTF8
+
+This example only differs from the previous in that the
+``Content-type'' indicates UTF8 encoded data, and the hello world sent
+is selected at random from a list of different languages.
+
@verbatiminclude ../examples/1-hello-world-utf8.el
@node Hello World HTML, File Server, Hello World UTF8, Usage Examples
@section Hello World HTML
@verbatiminclude ../examples/2-hello-world-html.el
+This variation of the ``hello world'' example sends a @code{text/html}
+response instead of a simple @code{text/plain} response.
+
@node File Server, URL Parameter Echo, Hello World HTML, Usage Examples
@section File Server
+
+The following example implements a file server which will serve files
+from the @code{docroot} document root set to the current working
+directory in this example. Three helper functions are used;
address@hidden is used to check if the requested path is
+within the document root, if so the file is served and
address@hidden is used to appropriately set the mime-type of the
+response based on the extension of the file, if not then
address@hidden is used to send a default ``File Not Found''
+response.
+
@verbatiminclude ../examples/3-file-server.el
@node URL Parameter Echo, POST Echo, File Server, Usage Examples
@section URL Parameter Echo
+
+This example demonstrates access of URL-encoded parameters in a
address@hidden request. For example the following URL
address@hidden://localhost:9005/example?foo=bar&baz=qux} will render as an
+the following HTML table.
+
address@hidden @columnfractions .5 .5
address@hidden foo @tab bar
address@hidden baz @tab qux
address@hidden multitable
+
@verbatiminclude ../examples/4-url-param-echo.el
@node POST Echo, Function Index, URL Parameter Echo, Usage Examples
@section POST Echo
-POST parameters are used for example when HTML forms are submitted.
+
+The following example echos back the content of the ``message'' field
+in a @code{POST} request.
@verbatiminclude ../examples/5-post-echo.el
diff --git a/emacs-web-server-test.el b/emacs-web-server-test.el
index 62dad3e..aa80442 100644
--- a/emacs-web-server-test.el
+++ b/emacs-web-server-test.el
@@ -165,4 +165,18 @@
org=-+one%0A-+two%0A-+three%0A-+four%0A%0A&beg=646&end=667&path=%2Fcomplex.org")
"))))
(ews-stop server))))
+(ert-deftest ews/simple-post ()
+ "Test a simple POST server."
+ (ews-test-with
+ '(((:POST . ".*") .
+ (lambda (request)
+ (with-slots (process headers) request
+ (let ((message (cdr (assoc "message" headers))))
+ (ews-response-header process 200
+ '("Content-type" . "text/plain"))
+ (process-send-string process
+ (format "you said %S\n" message)))))))
+ (should (string= (ews-test-curl-to-string "" nil '(("message" . "foo")))
+ "you said \"foo\"\n"))))
+
(provide 'emacs-web-server-test)
diff --git a/emacs-web-server.el b/emacs-web-server.el
index a97e56e..29838f9 100644
--- a/emacs-web-server.el
+++ b/emacs-web-server.el
@@ -24,6 +24,7 @@
(defclass ews-request ()
((process :initarg :process :accessor process :initform nil)
(pending :initarg :pending :accessor pending :initform "")
+ (context :initarg :context :accessor context :initform nil)
(boundary :initarg :boundary :accessor boundary :initform nil)
(headers :initarg :headers :accessor headers :initform (list nil))))
@@ -162,15 +163,12 @@ function.
(defun ews-parse-request (request string)
"Parse request STRING from REQUEST with process PROC.
Return non-nil only when parsing is complete."
- (with-slots (process pending boundary headers) request
+ (with-slots (process pending context boundary headers) request
(setq pending (concat pending string))
(let ((delimiter (concat "\r\n" (if boundary (concat "--" boundary) "")))
;; Track progress through string, always work with the
;; section of string between LAST-INDEX and INDEX.
- (last-index 0) index
- ;; Current context, either a particular content-type for
- ;; custom parsing or nil for no special parsing.
- context)
+ (last-index 0) index)
(catch 'finished-parsing-headers
;; parse headers and append to request
(while (setq index (string-match delimiter pending last-index))
diff --git a/examples/0-hello-world.el b/examples/0-hello-world.el
index 76ae4f3..91e819a 100644
--- a/examples/0-hello-world.el
+++ b/examples/0-hello-world.el
@@ -1,7 +1,8 @@
;;; hello-world.el --- simple hello world server using Emacs Web Server
(ews-start
'(((lambda (_) t) .
- (lambda (proc request)
- (ews-response-header proc 200 '("Content-type" . "text/plain"))
- (process-send-string proc "hello world"))))
+ (lambda (request)
+ (with-slots (process headers) request
+ (ews-response-header process 200 '("Content-type" . "text/plain"))
+ (process-send-string process "hello world")))))
9000)
diff --git a/examples/1-hello-world-utf8.el b/examples/1-hello-world-utf8.el
index d7804b2..0e00362 100644
--- a/examples/1-hello-world-utf8.el
+++ b/examples/1-hello-world-utf8.el
@@ -1,20 +1,21 @@
;;; hello-world-utf8.el --- utf8 hello world server using Emacs Web Server
(ews-start
'(((lambda (_) t) .
- (lambda (proc request)
- (let ((hellos '("こんにちは"
- "안녕하세요"
- "góðan dag"
- "Grüßgott"
- "hyvää päivää"
- "yá'át'ééh"
- "Γεια σας"
- "Вiтаю"
- "გამარჯობა"
- "नमस्ते"
- "你好")))
- (ews-response-header proc 200
- '("Content-type" . "text/plain; charset=utf-8"))
- (process-send-string proc
- (concat (nth (random (length hellos)) hellos) " world"))))))
+ (lambda (request)
+ (with-slots (process headers) request
+ (let ((hellos '("こんにちは"
+ "안녕하세요"
+ "góðan dag"
+ "Grüßgott"
+ "hyvää päivää"
+ "yá'át'ééh"
+ "Γεια σας"
+ "Вiтаю"
+ "გამარჯობა"
+ "नमस्ते"
+ "你好")))
+ (ews-response-header process 200
+ '("Content-type" . "text/plain; charset=utf-8"))
+ (process-send-string process
+ (concat (nth (random (length hellos)) hellos) " world")))))))
9001)
diff --git a/examples/2-hello-world-html.el b/examples/2-hello-world-html.el
index 49d4420..5f2587a 100644
--- a/examples/2-hello-world-html.el
+++ b/examples/2-hello-world-html.el
@@ -1,9 +1,10 @@
;;; hello-world-html.el --- html hello world server using Emacs Web Server
(ews-start
'(((lambda (_) t) .
- (lambda (proc request)
- (ews-response-header proc 200 '("Content-type" . "text/html"))
- (process-send-string proc "<html>
+ (lambda (request)
+ (with-slots (process headers) request
+ (ews-response-header process 200 '("Content-type" . "text/html"))
+ (process-send-string process "<html>
<head>
<title>Hello World</title>
</head>
@@ -11,5 +12,5 @@
<b>hello world</b>
</body>
</html>
-"))))
+")))))
9002)
diff --git a/examples/3-file-server.el b/examples/3-file-server.el
index ba32c65..ba7cfb1 100644
--- a/examples/3-file-server.el
+++ b/examples/3-file-server.el
@@ -1,7 +1,11 @@
;;; file-server.el --- serve any files using Emacs Web Server
-;; This example uses absolute paths and will try to serve files from
-;; the root of the file-system, so don't run it on a public server.
-(ews-start
- '(((:GET . ".*") .
- (lambda (proc request) (ews-send-file proc (cdr (assoc :GET request))))))
- 9004)
+(lexical-let ((docroot default-directory))
+ (ews-start
+ (list (cons (cons :GET ".*")
+ (lambda (request)
+ (with-slots (process headers) request
+ (let ((path (substring (cdr (assoc :GET headers)) 1)))
+ (if (ews-subdirectoryp docroot path)
+ (ews-send-file process (expand-file-name path
docroot))
+ (ews-send-404 process)))))))
+ 9004))
diff --git a/examples/4-url-param-echo.el b/examples/4-url-param-echo.el
index 48a5284..2277b4d 100644
--- a/examples/4-url-param-echo.el
+++ b/examples/4-url-param-echo.el
@@ -1,15 +1,16 @@
;;; url-param-echo.el --- echo back url-paramed message using Emacs Web Server
(ews-start
'(((:GET . ".*") .
- (lambda (proc request)
- (ews-response-header proc 200 '("Content-type" . "text/html"))
- (process-send-string proc
- (concat "URL Parameters:</br><table><tr>"
- (mapconcat (lambda (pair)
- (format "<th>%s</th><td>%s</td>"
- (car pair) (cdr pair)))
- (cl-remove-if-not (lambda (el) (stringp (car el)))
- request)
- "</tr><tr>")
- "</tr></table>")))))
+ (lambda (request)
+ (with-slots (process headers) request
+ (ews-response-header process 200 '("Content-type" . "text/html"))
+ (process-send-string process
+ (concat "URL Parameters:</br><table><tr>"
+ (mapconcat (lambda (pair)
+ (format "<th>%s</th><td>%s</td>"
+ (car pair) (cdr pair)))
+ (cl-remove-if-not (lambda (el) (stringp (car el)))
+ headers)
+ "</tr><tr>")
+ "</tr></table>"))))))
9005)
diff --git a/examples/5-post-echo.el b/examples/5-post-echo.el
index b4d81d4..b7cd78d 100644
--- a/examples/5-post-echo.el
+++ b/examples/5-post-echo.el
@@ -1,16 +1,18 @@
;;; post-echo.el --- echo back posted message using Emacs Web Server
(ews-start
'(((:POST . ".*") .
- (lambda (proc request)
- (let ((message (cdr (assoc "message" request))))
- (ews-response-header proc 200 '("Content-type" . "text/plain"))
- (process-send-string proc
- (if message
- (format "you said %S\n" message)
- "This is a POST request, but it has no \"message\".\n")))))
+ (lambda (request)
+ (with-slots (process headers) request
+ (let ((message (cdr (assoc "message" headers))))
+ (ews-response-header process 200 '("Content-type" . "text/plain"))
+ (process-send-string process
+ (if message
+ (format "you said %S\n" message)
+ "This is a POST request, but it has no \"message\".\n"))))))
((:GET . ".*") .
- (lambda (proc request)
- (ews-response-header proc 200 '("Content-type" . "text/plain"))
- (process-send-string proc
- "This is a GET request not a POST request.\n"))))
+ (lambda (request)
+ (with-slots (process) request
+ (ews-response-header process 200 '("Content-type" . "text/plain"))
+ (process-send-string process
+ "This is a GET request not a POST request.\n")))))
9003)
- [elpa] 39/119: removed extra comments from examples, (continued)
- [elpa] 39/119: removed extra comments from examples, Eric Schulte, 2014/03/10
- [elpa] 40/119: moving around examples, Eric Schulte, 2014/03/10
- [elpa] 42/119: Makefile integration, Eric Schulte, 2014/03/10
- [elpa] 44/119: note, Eric Schulte, 2014/03/10
- [elpa] 43/119: more, Eric Schulte, 2014/03/10
- [elpa] 41/119: including examples in documentation, Eric Schulte, 2014/03/10
- [elpa] 47/119: even more documentation and examples, Eric Schulte, 2014/03/10
- [elpa] 48/119: update README, Eric Schulte, 2014/03/10
- [elpa] 49/119: small updates to README and NOTES, Eric Schulte, 2014/03/10
- [elpa] 50/119: MAYBE incremental handler calls, Eric Schulte, 2014/03/10
- [elpa] 46/119: more documentation and examples,
Eric Schulte <=
- [elpa] 51/119: renaming files, Eric Schulte, 2014/03/10
- [elpa] 53/119: added commentary, Eric Schulte, 2014/03/10
- [elpa] 55/119: update link in README, Eric Schulte, 2014/03/10
- [elpa] 54/119: doc tweaks, Eric Schulte, 2014/03/10
- [elpa] 45/119: new request object, Eric Schulte, 2014/03/10
- [elpa] 56/119: fix ports in examples, Eric Schulte, 2014/03/10
- [elpa] 58/119: note: shouldn't use BASIC authentication w/o HTTPS, Eric Schulte, 2014/03/10
- [elpa] 59/119: notes about security & authentication options, Eric Schulte, 2014/03/10
- [elpa] 57/119: BASIC HTTP authentication, Eric Schulte, 2014/03/10
- [elpa] 61/119: fix deprecated file name in file example, Eric Schulte, 2014/03/10