# -*- org -*- * TODO tests * TODO cookies =(set-cookie! key value #!key comment domain max-age path secure version)=; cookie-values are folded into the client parameters (soon to be simply parameters?). * DONE segregation of server and client parameters CLOSED: [2011-06-02 Thu 21:46] - CLOSING NOTE [2011-06-02 Thu 21:46] \\ Damn: we had this elegant environment mechanism for server parameters; might well return to that! with promiscuous and selective accessors, viz.: =query-{any,all}=, =query-server-{any,all}=, =query-client-{any,all}=. =server= is the server-supplied things like =HTTP_USER=, =HTTP_PASSWD=, etc.; =client=: post, get and cookies parameters. Should cookies have their own =query-cookie-{any,all}=? Maybe; but cookies are falsifiable just like get and post parameters, aren't they? Oh, weird: =$Paths= are associated with individual key-value pairs. Oh, well. No, let's fold cookies into =client= for now; until we find a use-case for segregation. We already have a mechanism for this, by the way: =call-with-environment-variables=; oh, shit: should we keep this? * DONE redirect abstractions, etc.? CLOSED: [2011-06-02 Thu 21:21] * DONE shit: ~call-with-content-type-&c.~ is really a special case of ~call-with-status-&c.~ CLOSED: [2011-04-26 Tue 18:50] - CLOSING NOTE [2011-04-26 Tue 18:50] \\ it's a pain in the ass to have to think about content type for certain "content-less" status like 301; but it allows for a consistent api. - CLOSING NOTE [2011-04-26 Tue 18:37] \\ that's fine; users calling ~call-with-status-&c.~ with arguments will have to think about the content-type, though. why is this necessary? where the status is namely 200 (and which happens to be ~(default-status)~). i can't think of a clean way right now to distinguish between both default parameters: status code and content-type. ~(display-status-&c. [content-type [status [rest]]])~? that forces us to use, say, ~text~ as the content-type when we want to do a ~301~; but maybe that's not such a bad thing, is it? weird, though, that ~content-type~ is the primary argument for a ~display-status~ function; should we fold this into ~display-content-type-&c.~? i don't want to have to think about ~200~ when i want, say, a content-type of ~xhtml~, do i? you do with ~mod_python~ and co., interestingly enough. i don't really want to have to think about content-type when i'm doing a status header; nor status when i'm just dishing out content. maybe i should keep them separate, after all, even though there's some multiplication of entities there. maybe we can rewrite ~display-content-type-&c.~ to be a specialization of ~display-status~; which happens to pass an argument to the ~200~ status-displayer? hmm. that gives you the option of ~(display-status-&c. 200 'text)~; even though that's not exactly analogous to ~(display-status-&c. 301 )~. these divergent behaviours and parameter-expectations are going to have to be documented. maybe you should have to think about the content type when doing a redirect; maybe i'm masking too many details from the user. that would certainly simplify the api. * DONE what about redirect, etc.? CLOSED: [2011-04-26 Tue 17:42] - CLOSING NOTE [2011-04-26 Tue 17:42] \\ display-status-&c. should we have some 301 abstractions: maybe a ~(display-status-&c. code . rest)~? ~rest~ would be optional arguments becoming e.g. a ~Location: <(car rest)>~ header. #+BEGIN_SRC scheme :tangle test-display-status.scm :shebang #!/usr/bin/env chicken-scheme (use alist-lib test) (include "call-with-query.scm") (import call-with-query) (define default-status (make-parameter 200)) (define display-status (case-lambda (() (display-status (default-status))) ((status) (display-header "Status" status)))) (define statuses `((301 . ,(lambda (location) (display-header "Location" location))))) (define display-status-&c. (case-lambda (() (display-status-&c. (default-status))) ((status . rest) (display-status status) (apply (alist-ref/default statuses status void) rest) (display-content-type-&c. 'text)))) (test "Default 200 status" "Status: 200\r\nContent-type: text/plain\r\n\r\n" (with-output-to-string (lambda () (display-status-&c.)))) (test "301 redirect" "Status: 301\r\nLocation: http://example.com\r\nContent-type: text/plain\r\n\r\n" (with-output-to-string (lambda () (display-status-&c. 301 "http://example.com")))) #+END_SRC * DONE should ~query~ be a procedure which responds to keys? CLOSED: [2011-04-26 Tue 16:50] - CLOSING NOTE [2011-04-26 Tue 16:50] \\ decided on the convenience functions ~query-any~ and ~query-all~. this ~(alist-ref/default query key #f)~ thing is so prevalent as to be irritating; what about multiple keys, though? ~(query key)~ would have to return an element, in that case, or an improper list; wouldn't it? better in that sense to let people deal with the alist? fuck it. #+BEGIN_SRC scheme :tangle test-query-proc.scm :shebang #!/usr/bin/env chicken-scheme (use alist-lib debug) (let ((query '((cancel . "Cancel") (doctor . 1) (doctor . 13))) (key 'cancel)) (debug (alist-ref query key) (fold (lambda (elt acc) (cons (cdr elt) acc)) '() (filter (lambda (pair) (equal? (car pair) key)) query)))) #+END_SRC yeah, it's a pain in the ass: either we have to special-case the single case; or return a list each time, which leads to an irritating ~car~. i guess a couple convenience functions aren't out of the question: ~(query-any key) -> {value, #f}~ (or should we do the whole error vs. ~query-any/default~ thing? when would we want to error?), ~(query-all key) -> {values, nil}~; they're basically just wrappers around ~alist-ref~. speaking of which: how should ~alist-lib~ deal with multiple values? ~srfi-69~ gets to punt because of the one key -> value contract; is this something that should be handled "up-stream"? no, let's stick with ~memv~-like semantics. #+BEGIN_SRC scheme :tangle test-query-any-query-all.scm :shebang #!/usr/bin/env chicken-scheme (use alist-lib debug test) (define (query-any query key) (alist-ref/default query key #f)) (define (query-all query key) (fold (lambda (elt acc) (cons (cdr elt) acc)) '() (filter (lambda (pair) (equal? (car pair) key)) query))) (let ((query '((cancel . "Cancel") (doctor . 1) (doctor . 13))) (key 'cancel)) (test "Multiple values, choose any" 1 (query-any query 'doctor)) (test "Multiple values, choose all" '(13 1) (query-all query 'doctor)) (test "No values, choose any" #f (query-any query 'harro)) (test "No values, choose all" '() (query-all query 'harro))) #+END_SRC * DONE test module CLOSED: [2011-04-25 Mon 20:36] #+BEGIN_SRC scheme :tangle test-call-with-query-module.scm :shebang #!/usr/bin/env chicken-scheme (use debug) (include "call-with-query.scm") (import call-with-query) (call-with-dynamic-fastcgi-query (lambda (query) (display-content-type 'html) (display-eol) (display-xml-prolog) (display-doctype) (display "harrooeutnh"))) #+END_SRC * DONE ~display-default-headers~ CLOSED: [2011-04-26 Tue 03:09] - CLOSING NOTE [2011-04-26 Tue 03:09] \\ ~display-content-type-&c.~ something to abstract this? #+BEGIN_SRC scheme (define (display-default-headers) (display-content-type) (display-eol) (display-xml-prolog) (display-doctype)) #+END_SRC let's think about this, but indeed do something; the composite of content-type, eol, optional prolog and doc type is not exactly "headers". ~(display-content-type+eol+prolog+doctype [prolog [doctype]])~; what about text, cvs, etc.? ~(display-content-type-&c. [{text,html,xhtml,csv,...}])~ * DONE ~call-with-...~ vs. ~with-...~ CLOSED: [2011-04-25 Mon 20:02] - CLOSING NOTE [2011-04-25 Mon 20:03] \\ decided to go with `call-with-...' despite the environmental modifications. is ~call-with-...~ appropriate when the procedures takes an argument; ~with-...~ when there is a niladic thunk? [[http://wiki.call-cc.org/man/4/Unit%20ports#string-port-extensions][chicken's string-ports]] seems to imply so; what about r5rs? #+BEGIN_EXAMPLE 20:47 < klutometis> what's the convention for `call-with-...' vs. `with-...'? 20:48 < klutometis> i notice that r5rs uses `with-...' when the thunk is niladic (tautology); and `call-with-...' when the procedure is n-ary, where n >= 1. 20:48 < cky> klutometis: call-with-* passes the object to your function. with-* sets a certain parameter to that object. 20:49 < klutometis> exemplorum gratia: `with-output-to-file' (niladic), `call-with-values' (n-ary). 20:51 < klutometis> cky: it seems a little arbitrary, though, doesn't it? you're still "calling" a thunk with zero arguments; i don't see how one is necessarily `call-with-...' and the other merely `with-...'. 20:51 < cky> The call-with is not referring to the procedure. It's referring to how the object is to be stashed. 20:52 < cky> call-with-* means object to be passed as arg; with-* means object to be stored in parameter. 20:54 < klutometis> cky: i'm currently writing a dynamic-wind abstraction, bizarrely, which does both; i take it the `call-with-...' convention wins out over `call-...'. 20:54 < klutometis> sorry, `with-...'. 20:54 < cky> Um. If it affects external state (and I consider parameters to be external state), use with-*. 20:55 < cky> call-with-* has an expectation that no external state be modified, and everything is contained within the procedure you passed. 20:55 < klutometis> yeah; but it passes in arguments, too. this is probably a pathological corner case. 20:55 < cky> Yeah. :-/ #+END_EXAMPLE * DONE ~call-with-dynamic-fastcgi-query~ CLOSED: [2011-04-25 Mon 20:03] - CLOSING NOTE [2011-04-25 Mon 20:03] \\ reasonable first pass (punting on current-error-port) as noted in another project, we had roughly something like this in mind: #+BEGIN_QUOTE with something reasonable that binds ~in~, ~out~, ~err~ to the standard ports with string ports; binds ~env~ to the environment; automatically extracts the query-string (if available); automatically extracts the post-data (if available); has some notion of content-type, status, xml-prolog, and doc-type. this shit we have now is ridiculous. maybe it can even combine get and post variables into "query": ~(call-with-dynamic-fcgi (lambda (query) ...)~? let query be '() when we don't have anything? #+END_QUOTE #+BEGIN_SRC scheme :tangle test-call-with-fastcgi.scm :shebang #!/usr/bin/env chicken-scheme (use fastcgi call-with-environment-variables ports srfi-39 uri-common debug alist-lib) (define (call-with-dynamic-fastcgi-query quaerendum) (fcgi-dynamic-server-accept-loop (lambda (in out err env) (let ((query (append (form-urldecode (fcgi-get-post-data in env)) (form-urldecode (let ((query (env "QUERY_STRING"))) (and (not (string-null? query)) query)))))) (parameterize ((current-output-port (make-output-port (lambda (scribendum) (out scribendum)) void)) ;; Redirecting current-error-port is actually a pain: it ;; obscures Apache logs. #; (current-error-port (make-output-port (lambda (errandum) (err errandum)) void))) (call-with-environment-variables (env) (lambda () (quaerendum query)))))))) (define (display-eol) (display "\r\n")) (define (display-header header value) (format #t "~a: ~a" header value) (display-eol)) (define content-types '((text . "text/plain") (html . "text/html"))) (define default-content-type (make-parameter 'text)) (define display-content-type (case-lambda (() (display-content-type (default-content-type))) ((content-type) (display-header "Content-type" (if (string? content-type) content-type (alist-ref/default content-types content-type (default-content-type))))))) (call-with-dynamic-fastcgi-query (lambda (query) (display-content-type 'html) (display-eol) (display "harro"))) #+END_SRC #+BEGIN_SRC fundamental :tangle .htaccess Order deny,allow Allow from all Options Indexes ExecCGI SetHandler fastcgi-script #+END_SRC