diff --git a/collects/web-server/prototype-web-server/private/mod-map.ss b/collects/web-server/prototype-web-server/private/mod-map.ss new file mode 100644 index 0000000000..39a3fffea2 --- /dev/null +++ b/collects/web-server/prototype-web-server/private/mod-map.ss @@ -0,0 +1,58 @@ +(module mod-map mzscheme + (require (lib "list.ss") + (lib "plt-match.ss")) + (provide compress-serial + decompress-serial) + + ; XXX even though we allow all values to be serialized, we only protect against source modification of the servlet program. + + ;; compress-mod-map : (listof (cons mod-spec symbol)) -> (listof (cons (or mod-spec number) symbol)) + (define (compress-mod-map mm) + (compress-mod-map/seen empty mm)) + + (define (lookup-seen ms seen) + (match seen + [(list) + (values #f (list ms))] + [(list-rest ms+ seen+) + (if (equal? ms ms+) + (values 0 (list* ms+ seen+)) + (let-values ([(i seen++) (lookup-seen ms seen+)]) + (values (if i (add1 i) #f) (list* ms+ seen++))))])) + + (define (compress-mod-map/seen seen mm) + (match mm + [(list) + (list)] + [(list-rest (list-rest mod-spec sym) mm) + (define-values (i seen+) (lookup-seen mod-spec seen)) + (if i + (list* (cons i sym) (compress-mod-map/seen seen+ mm)) + (list* (cons mod-spec sym) (compress-mod-map/seen seen+ mm)))])) + + ;; decompress-mod-map : (listof (cons (or mod-spec number) symbol)) -> (listof (cons mod-spec symbol)) + (define (decompress-mod-map cmm) + (decompress-mod-map/seen empty cmm)) + + (define (decompress-mod-map/seen seen cmm) + (match cmm + [(list) + (list)] + [(list-rest (list-rest mod-spec-or-n sym) cmm) + (if (number? mod-spec-or-n) + (list* (cons (list-ref seen mod-spec-or-n) sym) + (decompress-mod-map/seen seen cmm)) + (list* (cons mod-spec-or-n sym) + (decompress-mod-map/seen (append seen (list mod-spec-or-n)) cmm)))])) + + ; compress-serial : serial -> serial (with compressed mod-map) + (define compress-serial + (match-lambda + [(list e0 mm e2 e3 e4 e5) + (list e0 (compress-mod-map mm) e2 e3 e4 e5)])) + + ; decompress-serial : serial (with compressed mod-map) -> serial + (define decompress-serial + (match-lambda + [(list e0 cmm e2 e3 e4 e5) + (list e0 (decompress-mod-map cmm) e2 e3 e4 e5)]))) \ No newline at end of file diff --git a/collects/web-server/prototype-web-server/private/stuff-url.ss b/collects/web-server/prototype-web-server/private/stuff-url.ss index 306d8490ba..9007f6f8d1 100644 --- a/collects/web-server/prototype-web-server/private/stuff-url.ss +++ b/collects/web-server/prototype-web-server/private/stuff-url.ss @@ -1,204 +1,15 @@ (module stuff-url mzscheme (require (lib "url.ss" "net") - (lib "list.ss") - (lib "plt-match.ss") - "utils.ss") - - ; XXX even though we allow all values to be serialized, we only protect against source modification of the servlet program. + "utils.ss" + "mod-map.ss") ; XXX url: first try continuation, then turn into hash ; XXX different ways to hash, different ways to store (maybe cookie?) - - ;; **************************************** - ;; URL LAYOUT - - ;; The mod-map will be encoded in the URL path. The graph, fixups and serial will be - ;; encoded in the query. - - ;; The first path element following the servlet file-name will be the labeling code. - - ;; The remaining path elements will encode the mod-map, now represented as a list of - ;; numbers. - - ;; The query will contain bindings for at least one and as many as three keys: - - ;; g -- the graph - ;; f -- the fixups - ;; v -- the main serial value. - - ;; If the graph and fixups are trivial, then they will be omitted from the query. - + (provide stuff-url extend-url-query - unstuff-url - find-binding) - - ;; compress-mod-map : (listof (cons mod-spec symbol)) -> (listof (cons (or mod-spec number) symbol)) - (define (compress-mod-map mm) - (compress-mod-map/seen empty mm)) - - (define (lookup-seen ms seen) - (match seen - [(list) - (values #f (list ms))] - [(list-rest ms+ seen+) - (if (equal? ms ms+) - (values 0 (list* ms+ seen+)) - (let-values ([(i seen++) (lookup-seen ms seen+)]) - (values (if i (add1 i) #f) (list* ms+ seen++))))])) - - (define (compress-mod-map/seen seen mm) - (match mm - [(list) - (list)] - [(list-rest (list-rest mod-spec sym) mm) - (define-values (i seen+) (lookup-seen mod-spec seen)) - (if i - (list* (cons i sym) (compress-mod-map/seen seen+ mm)) - (list* (cons mod-spec sym) (compress-mod-map/seen seen+ mm)))])) - - ;; decompress-mod-map : (listof (cons (or mod-spec number) symbol)) -> (listof (cons mod-spec symbol)) - (define (decompress-mod-map cmm) - (decompress-mod-map/seen empty cmm)) - - (define (decompress-mod-map/seen seen cmm) - (match cmm - [(list) - (list)] - [(list-rest (list-rest mod-spec-or-n sym) cmm) - (if (number? mod-spec-or-n) - (list* (cons (list-ref seen mod-spec-or-n) sym) - (decompress-mod-map/seen seen cmm)) - (list* (cons mod-spec-or-n sym) - (decompress-mod-map/seen (append seen (list mod-spec-or-n)) cmm)))])) - - ; compress-serial : serial -> serial (with compressed mod-map) - (define compress-serial - (match-lambda - [(list e0 mm e2 e3 e4 e5) - (list e0 (compress-mod-map mm) e2 e3 e4 e5)])) - - ; decompress-serial : serial (with compressed mod-map) -> serial - (define decompress-serial - (match-lambda - [(list e0 cmm e2 e3 e4 e5) - (list e0 (decompress-mod-map cmm) e2 e3 e4 e5)])) - - ;; url-parts: module-path serial -> string (listof (union number 'k)) s-expr s-expr s-expr - ;; compute the parts for the url: - ;; labeling code - ;; simplified mod-map encoding - ;; graph - ;; fixups - ;; main serial - (define (url-parts mod-path sv) - (let* ([mod-map (cadr sv)] - [lab-code (get-labeling-code mod-path mod-map)] - [simple-map (simplify-module-map mod-path lab-code mod-map)]) - (values lab-code simple-map - (list-ref sv 3) - (list-ref sv 4) - (list-ref sv 5)))) - - ;; recover-serial: module-path (listof (union number 'k)) s-expr s-expr s-expr -> serial - ;; recover the serializable value from parts - (define (recover-serial mod-path label-code simple-map graph fixups main-serial) - (list (length simple-map) - (reconstruct-mod-map mod-path label-code simple-map) - (length graph) - graph fixups main-serial)) - - ;; reconstruct-mod-map: module-path string (listof (union number 'k)) -> module-map - ;; reconstruct the module map from the simple map - (define (reconstruct-mod-map mod-path label-code simple-map) - (map - (lambda (n-or-k) - (if (symbol? n-or-k) - `((lib "abort-resume.ss" "web-server" "prototype-web-server" "private") . ,n-or-k) - (cons - mod-path - (string->symbol - (format "web-deserialize-info:~a~a" - label-code - n-or-k))))) - simple-map)) - - ;; get-labeling-code: module-path module-map -> string - ;; pull the labeling code out of the module map - (define (get-labeling-code pth mod-map) - (let loop ([mod-map mod-map]) - (cond - [(null? mod-map) - (error "couldn't find labeling code")] - [(and (same-module? pth (caar mod-map)) - (match-labeling-code (cdar mod-map))) - => (lambda (lcode) lcode)] - [else (loop (cdr mod-map))]))) - - (define WEB-DESERIALIZE-INFO-REGEXP (regexp "web-deserialize-info:([a-zA-Z]*)(.*)")) - ;; match-labeling-code: symbol -> string - ;; pull the labeling code out of the symbol - (define (match-labeling-code sym) - (let ([match? (regexp-match WEB-DESERIALIZE-INFO-REGEXP (symbol->string sym))]) - (and match? (cadr match?)))) - - ;; match-label: symbol -> number - ;; pull the closure number out of the symbol - (define (match-label sym) - (let ([match? (regexp-match WEB-DESERIALIZE-INFO-REGEXP (symbol->string sym))]) - (and match? (string->number (caddr match?))))) - - ;; simplify-module-map: module-path string module-map -> (listof (union number symbol)) - ;; convert the module-map into a simple list - (define (simplify-module-map pth labeling-code mod-map) - (let loop ([mm mod-map]) - (cond - [(null? mm) '()] - [(and (same-module? pth (caar mm)) - (match-label (cdar mm))) - => (lambda (lab) (cons lab (loop (cdr mm))))] - [(same-module? '(lib "abort-resume.ss" "web-server" "prototype-web-server" "private") (caar mm)) - (cons (cdar mm) (loop (cdr mm)))] - [else - (error "cannot construct abreviated module map" mod-map)]))) - - ;; same-module?: module-path module-path -> boolean - ;; do the module paths specify the same module? - (define (same-module? path-str mod-path) - (eqv? ((current-module-name-resolver) path-str #f #f) - ((current-module-name-resolver) mod-path #f #f))) - - ;; stuff-url: serial url path -> url - ;; encode in the url - #;(define (stuff-url svl uri pth) - (let-values ([(l-code simple-mod-map graph fixups sv) - (url-parts pth svl)]) - (let ([new-query - `(,(cons 'c l-code) - ,@(if (null? graph) '() - (list (cons 'g (format "~s" graph)))) - ,@(if (null? fixups) '() - (list (cons 'f (format "~s" fixups)))) - ,(cons 'v (format "~s" sv)))]) - (let ([result-uri - (make-url - (url-scheme uri) - (url-user uri) - (url-host uri) - (url-port uri) - #t - (append (url-path uri) - (map - (lambda (n-or-sym) (make-path/param (format "~a" n-or-sym) empty)) - simple-mod-map)) - new-query - (url-fragment uri))]) - (begin0 - result-uri - (when (> (string-length (url->string result-uri)) - 1024) - (error "the url is too big: " (url->string result-uri)))))))) + unstuff-url) ; XXX Abstract this (require (lib "md5.ss")) @@ -215,23 +26,15 @@ (build-path (find-system-path 'home-dir) ".urls" (format "~a" hash)) (lambda () (read)))) + ;; stuff-url: serial url path -> url + ;; encode in the url (define (stuff-url svl uri pth) - #;(printf "stuff: ~s~n" svl) - (let ([result-uri - (make-url - (url-scheme uri) - (url-user uri) - (url-host uri) - (url-port uri) - #t - (url-path uri) - (list (cons 'c (md5-store (write/string (compress-serial svl))))) - (url-fragment uri))]) - (begin0 - result-uri - (when (> (string-length (url->string result-uri)) - 1024) - (error "the url is too big: " (url->string result-uri)))))) + (define result-uri + (extend-url-query uri 'c (md5-store (write/string (compress-serial svl))))) + (when (> (string-length (url->string result-uri)) + 1024) + (error "the url is too big: " (url->string result-uri))) + result-uri) (define (extend-url-query uri key val) (make-url @@ -244,32 +47,8 @@ (list* (cons key val) (url-query uri)) (url-fragment uri))) - + ;; unstuff-url: url url path -> serial ;; decode from the url and reconstruct the serial - #;(define (unstuff-url req-url ses-url mod-path) - (let ([suff (split-url-path ses-url req-url)] - [qry (url-query req-url)]) - (recover-serial - mod-path - (find-binding 'c qry) - (map - (lambda (elt) - (define nelt (string->number elt)) - (if (not nelt) (string->symbol elt) - nelt)) - suff) - (or (find-binding 'g qry) '()) - (or (find-binding 'f qry) '()) - (find-binding 'v qry)))) (define (unstuff-url req-url ses-url mod-path) - (decompress-serial (read/string (md5-lookup (find-binding 'c (url-query req-url)))))) - - ;; find-binding: symbol (list (cons symbol string)) -> (union string #f) - ;; find the binding in the query or return false - (define (find-binding key qry) - (cond - [(null? qry) #f] - [(eqv? key (caar qry)) - (read (open-input-string (cdar qry)))] - [else (find-binding key (cdr qry))]))) \ No newline at end of file + (decompress-serial (read/string (md5-lookup (find-binding 'c (url-query req-url))))))) \ No newline at end of file diff --git a/collects/web-server/prototype-web-server/private/utils.ss b/collects/web-server/prototype-web-server/private/utils.ss index a57c5cbbca..5f7a112837 100644 --- a/collects/web-server/prototype-web-server/private/utils.ss +++ b/collects/web-server/prototype-web-server/private/utils.ss @@ -6,12 +6,22 @@ (lib "serialize.ss")) (provide/contract + [find-binding (symbol? (listof (cons/c symbol? string?)) . -> . (or/c serializable? false/c))] [read/string (string? . -> . serializable?)] [write/string (serializable? . -> . string?)] - [url->servlet-path (url? . -> . (listof string?))] + [url->servlet-path ((path? url?) . ->* . ((or/c path? false/c) (or/c (listof string?) false/c) (or/c (listof string?) false/c)))] [make-session-url (url? (listof string?) . -> . url?)] [split-url-path (url? url? . -> . (or/c (listof string?) false/c))]) + ;; find-binding: symbol (list (cons symbol string)) -> (union string #f) + ;; find the binding in the query or return false + (define (find-binding key qry) + (cond + [(null? qry) #f] + [(eqv? key (caar qry)) + (read/string (cdar qry))] + [else (find-binding key (cdr qry))])) + (define (read/string str) (read (open-input-string str))) (define (write/string v) @@ -109,7 +119,7 @@ rest-of-path)] [else (loop new-base (list* next-path-segment servlet-path) - rest-of-path)]))]))) + rest-of-path)]))]))) ;; split-url-path: url url -> (union (listof string) #f) ;; the first url's path is a prefix of the path of the second diff --git a/collects/web-server/prototype-web-server/private/web.ss b/collects/web-server/prototype-web-server/private/web.ss index 219000e9e1..a013739839 100644 --- a/collects/web-server/prototype-web-server/private/web.ss +++ b/collects/web-server/prototype-web-server/private/web.ss @@ -6,7 +6,8 @@ (rename "abort-resume.ss" send/suspend0 send/suspend) (all-except "abort-resume.ss" send/suspend) "session.ss" - "stuff-url.ss") + "stuff-url.ss" + "utils.ss") (provide ;; Server Interface diff --git a/collects/web-server/prototype-web-server/tests/stuff-url-tests.ss b/collects/web-server/prototype-web-server/tests/stuff-url-tests.ss index 4abb13cc1f..f2a2d28c46 100644 --- a/collects/web-server/prototype-web-server/tests/stuff-url-tests.ss +++ b/collects/web-server/prototype-web-server/tests/stuff-url-tests.ss @@ -1,5 +1,6 @@ (module stuff-url-tests mzscheme (require (lib "stuff-url.ss" "web-server" "prototype-web-server" "private") + (lib "mod-map.ss" "web-server" "prototype-web-server" "private") (planet "test.ss" ("schematics" "schemeunit.plt" 2)) (planet "util.ss" ("schematics" "schemeunit.plt" 2)) (lib "url.ss" "net") @@ -8,20 +9,14 @@ (lib "etc.ss") "util.ss") - (require/expose (lib "stuff-url.ss" "web-server" "prototype-web-server" "private") - (same-module? url-parts recover-serial)) - (provide stuff-url-suite) - (define uri0 (string->url "www.google.com")) + (define uri0 (string->url "www.google.com")) - (define (simplify-unsimplify svl pth) - (let-values ([(l-code simple-mod-map graph fixups sv) - (url-parts pth svl)]) - (recover-serial - pth - l-code - simple-mod-map graph fixups sv))) + (define (simplify-unsimplify v) + (decompress-serial + (compress-serial + v))) (define (stuff-unstuff svl uri mod-path) (let ([result-uri (stuff-url svl uri mod-path)]) @@ -37,40 +32,20 @@ (define stuff-url-suite (test-suite - "Tests for stuff-url.ss" - - (test-case - "Test same-module?" - - (check-true - (same-module? `(file ,(path->string (build-absolute-path (find-collects-dir) "web-server" "prototype-web-server" "private" "abort-resume.ss"))) - '(lib "abort-resume.ss" "web-server" "prototype-web-server" "private"))) - - (check-true - (same-module? `(file ,(path->string (build-absolute-path (this-expression-source-directory) "../private/abort-resume.ss"))) - '(lib "abort-resume.ss" "web-server" "prototype-web-server" "private"))) - - (check-true - (same-module? - '(lib "abort-resume.ss" "web-server" "prototype-web-server" "private") - '(lib "./abort-resume.ss" "web-server" "prototype-web-server" "private")))) + "Tests for stuff-url.ss" (test-case "compose url-parts and recover-serial (1)" (let-values ([(ev) (make-eval/mod-path m00)]) - (let* ([k0 (simplify-unsimplify (ev '(serialize (dispatch-start start 'foo))) - m00)] - [k1 (simplify-unsimplify (ev `(serialize (dispatch ,the-dispatch (list (deserialize ',k0) 1)))) - m00)] - [k2 (simplify-unsimplify (ev `(serialize (dispatch ,the-dispatch (list (deserialize ',k1) 2)))) - m00)]) + (let* ([k0 (simplify-unsimplify (ev '(serialize (dispatch-start start 'foo))))] + [k1 (simplify-unsimplify (ev `(serialize (dispatch ,the-dispatch (list (deserialize ',k0) 1)))))] + [k2 (simplify-unsimplify (ev `(serialize (dispatch ,the-dispatch (list (deserialize ',k1) 2)))))]) (check-true (= 6 (ev `(dispatch ,the-dispatch (list (deserialize ',k2) 3)))))))) (test-case "compose url-parts and recover-serial (2)" (let-values ([(ev) (make-eval/mod-path m01)]) - (let* ([k0 (simplify-unsimplify (ev '(serialize (dispatch-start start 'foo))) - m01)]) + (let* ([k0 (simplify-unsimplify (ev '(serialize (dispatch-start start 'foo))))]) (check-true (= 7 (ev `(dispatch ,the-dispatch (list (deserialize ',k0) 7)))))))) (test-case