[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[elpa] 35/119: cleaned up header/param parsing
From: |
Eric Schulte |
Subject: |
[elpa] 35/119: cleaned up header/param parsing |
Date: |
Mon, 10 Mar 2014 16:57:12 +0000 |
eschulte pushed a commit to branch master
in repository elpa.
commit 1249a4eb6e745f40624b616854441340137589a9
Author: Eric Schulte <address@hidden>
Date: Sat Dec 21 23:20:05 2013 -0700
cleaned up header/param parsing
---
emacs-web-server-test.el | 11 ++--
emacs-web-server.el | 108 +++++++++++++++++++++++-------------------
examples/5-url-param-echo.el | 3 +-
3 files changed, 67 insertions(+), 55 deletions(-)
diff --git a/emacs-web-server-test.el b/emacs-web-server-test.el
index ad56ffb..21d7d5e 100644
--- a/emacs-web-server-test.el
+++ b/emacs-web-server-test.el
@@ -86,7 +86,7 @@ Connection: keep-alive
"))
(unwind-protect
(progn
- (ews-do-filter (process server) client header-string)
+ (ews-parse-request (process server) client header-string)
(let ((headers (cdr (headers client))))
(should (string= (cdr (assoc :ACCEPT-ENCODING headers))
"gzip, deflate"))
@@ -118,7 +118,7 @@ Content-Disposition: form-data; name=\"name\"
"))
(unwind-protect
(progn
- (ews-do-filter (process server) client header-string)
+ (ews-parse-request (process server) client header-string)
(let ((headers (cdr (headers client))))
(should (string= (cdr (assoc "name" headers))
"\"schulte\""))
@@ -149,10 +149,11 @@ Cache-Control: no-cache
org=-+one%0A-+two%0A-+three%0A-+four%0A%0A&beg=646&end=667&path=%2Fcomplex.org"))
(unwind-protect
(progn
- (ews-do-filter (process server) client header-string)
+ (ews-parse-request (process server) client header-string)
(let ((headers (cdr (headers client))))
- (should (string= (cdr (assoc "path" headers)) "complex.org"))
- (should (string= (cdr (assoc "beg" headers)) "64"))
+ (message "headers:%S" headers)
+ (should (string= (cdr (assoc "path" headers)) "/complex.org"))
+ (should (string= (cdr (assoc "beg" headers)) "646"))
(should (string= (cdr (assoc "end" headers)) "667"))
(should (string= (cdr (assoc "org" headers))
"- one
diff --git a/emacs-web-server.el b/emacs-web-server.el
index 509e9c7..bd16f49 100644
--- a/emacs-web-server.el
+++ b/emacs-web-server.el
@@ -109,6 +109,11 @@ function.
(format "^\\(%s\\) \\([^[:space:]]+\\) \\([^[:space:]]+\\)$"
(mapconcat #'symbol-name ews-http-common-methods "\\|")))
+(defun ews-parse-query-string (string)
+ "Thin wrapper around `url-parse-query-string'."
+ (mapcar (lambda (pair) (cons (first pair) (second pair)))
+ (url-parse-query-string string nil 'allow-newlines)))
+
(defun ews-parse (proc string)
(cl-flet ((to-keyword (s) (intern (concat ":" (upcase (match-string 1 s))))))
(cond
@@ -117,8 +122,8 @@ function.
(url (match-string 2 string)))
(if (string-match "?" url)
(cons (cons method (substring url 0 (match-beginning 0)))
- (url-parse-query-string (url-unhex-string
- (substring url (match-end 0))) ))
+ (ews-parse-query-string
+ (url-unhex-string (substring url (match-end 0)))))
(list (cons method url)))))
((string-match "^\\([^[:space:]]+\\): \\(.*\\)$" string)
(list (cons (to-keyword string) (match-string 2 string))))
@@ -145,64 +150,71 @@ function.
(push (cons proc (make-instance 'ews-client)) clients))
(let ((c (cdr (assoc proc clients))))
(when (not (eq (catch 'close-connection
- (if (ews-do-filter proc c string)
+ (if (ews-parse-request proc c string)
(ews-call-handler proc (cdr (headers c)) handler)
:keep-open))
:keep-open))
(setq clients (assq-delete-all proc clients))
(delete-process proc)))))
-;; TODO: content-type should switch from escaping on double \r\n, to
-;; parsing multipart data on double \r\n
-(defun ews-do-filter (proc client string)
- "Return non-nil when finished and the client may be deleted."
+(defun ews-parse-request (proc client string)
+ "Parse request STRING from CLIENT with process PROC.
+Return non-nil only when parsing is complete and CLIENT may be
+deleted."
(with-slots (leftover boundary headers) client
(let ((pending (concat leftover string))
- (delimiter (if boundary
- (regexp-quote (concat "\r\n--" boundary))
- "\r\n"))
- (last-index 0) index tmp-index)
+ (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)
(catch 'finished-parsing-headers
;; parse headers and append to client
(while (setq index (string-match delimiter pending last-index))
(let ((tmp (+ index (length delimiter))))
- (cond
- ;; Double \r\n outside of post data means we are done
- ;; w/headers and should call the handler.
- ((and (not boundary) (= last-index index))
- (throw 'finished-parsing-headers t))
- ;; Parse a URL
- ((eq boundary :application/x-www-form-urlencoded)
- (mapc (lambda (pair) (setcdr (last headers) (list pair)))
- (url-parse-query-string
- (ews-trim (substring pending last-index))))
- (throw 'finished-parsing-headers t))
- ;; Build up multipart data.
- (boundary
- (setcdr (last headers)
- (list (ews-parse-multipart/form
- (ews-trim
- (substring pending last-index index)))))
- ;; a boundary suffixed by "--" indicates the end of the headers
- (when (and (> (length pending) (+ tmp 2))
- (string= (substring pending tmp (+ tmp 2)) "--"))
- (throw 'finished-parsing-headers t)))
- ;; Standard header parsing.
- (:otherwise
- (let ((this (ews-parse proc (substring pending last-index
index))))
- (if (and (caar this) (eql (caar this) :CONTENT-TYPE))
- (cl-destructuring-bind (type &rest data)
- (mail-header-parse-content-type (cdar this))
- (cond
- ((string= type "multipart/form-data")
- (when (assoc 'boundary data)
- (setq boundary (cdr (assoc 'boundary data)))
- (setq delimiter (concat "\r\n--" boundary))))
- ((string= type "application/x-www-form-urlencoded")
- (setq boundary (intern (concat ":" (downcase type)))))
- (:otherwise
- (ews-error proc "TODO: handle content type: %S"
type))))
- (setcdr (last headers) this)))))
+ (if (= last-index index) ; double \r\n ends current run of headers
+ (case context
+ ;; Parse URL data.
+ ;; http://www.w3.org/TR/html4/interact/forms.html#h-17.13.4
+ (application/x-www-form-urlencoded
+ (mapc (lambda (pair) (setcdr (last headers) (list pair)))
+ (ews-parse-query-string
+ (replace-regexp-in-string
+ "\\+" " "
+ (ews-trim (substring pending last-index)))))
+ (throw 'finished-parsing-headers t))
+ ;; Set custom delimiter for multipart form data.
+ (multipart/form-data
+ (setq delimiter (concat "\r\n--" boundary)))
+ ;; No special context so we're done.
+ (:otherwise (throw 'finished-parsing-headers t)))
+ (if (eql context 'multipart/form-data)
+ (progn
+ (setcdr (last headers)
+ (list (ews-parse-multipart/form
+ (ews-trim
+ (substring pending last-index index)))))
+ ;; Boundary suffixed by "--" indicates end of the headers.
+ (when (and (> (length pending) (+ tmp 2))
+ (string= (substring pending tmp (+ tmp 2))
"--"))
+ (throw 'finished-parsing-headers t)))
+ ;; Standard header parsing.
+ (let ((header
+ (ews-parse proc (substring pending last-index index))))
+ ;; Content-Type indicates that the next double \r\n
+ ;; will be followed by a special type of content which
+ ;; will require special parsing. Thus we will note
+ ;; the type in the CONTEXT variable for parsing
+ ;; dispatch above.
+ (if (and (caar header) (eql (caar header) :CONTENT-TYPE))
+ (cl-destructuring-bind (type &rest data)
+ (mail-header-parse-content-type (cdar header))
+ (setq boundary (cdr (assoc 'boundary data)))
+ (setq context (intern (downcase type))))
+ ;; All other headers are collected directly.
+ (setcdr (last headers) header)))))
(setq last-index tmp)))
(setq leftover (ews-trim (substring pending last-index)))
nil))))
diff --git a/examples/5-url-param-echo.el b/examples/5-url-param-echo.el
index 00c2e17..c0dfa1d 100644
--- a/examples/5-url-param-echo.el
+++ b/examples/5-url-param-echo.el
@@ -17,8 +17,7 @@
(concat "URL Parameters:</br><table><tr>"
(mapconcat (lambda (pair)
(format "<th>%s</th><td>%s</td>"
- (car pair)
- (mapconcat #'identity (cdr pair) " ")))
+ (car pair) (cdr pair)))
(cl-remove-if-not (lambda (el) (stringp (car el)))
request)
"</tr><tr>")
- [elpa] 26/119: thread proc through some functions, (continued)
- [elpa] 26/119: thread proc through some functions, Eric Schulte, 2014/03/10
- [elpa] 28/119: testing a hello-world server, Eric Schulte, 2014/03/10
- [elpa] 27/119: run test processes asynch, Eric Schulte, 2014/03/10
- [elpa] 29/119: update examples, Eric Schulte, 2014/03/10
- [elpa] 31/119: match more HTTP methods, Eric Schulte, 2014/03/10
- [elpa] 30/119: fleshed out some more tests, Eric Schulte, 2014/03/10
- [elpa] 32/119: url-encoded parameters, Eric Schulte, 2014/03/10
- [elpa] 34/119: found a confounding POST example, Eric Schulte, 2014/03/10
- [elpa] 33/119: ews-subdirectoryp convenience function, Eric Schulte, 2014/03/10
- [elpa] 36/119: bug fix, Eric Schulte, 2014/03/10
- [elpa] 35/119: cleaned up header/param parsing,
Eric Schulte <=
- [elpa] 37/119: fixed tests, running and passing, Eric Schulte, 2014/03/10
- [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