emacs-elpa-diffs
[Top][All Lists]
Advanced

[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)



reply via email to

[Prev in Thread] Current Thread [Next in Thread]