1
0
Fork 0

cache returns 304 as appropriate; more pages set etags

* tekuti/cache.scm (update-cache): Expand cache size back to 20.
  (cached-response-and-body, make-entry): Entries are now procedures
  that return the cached pair. They also have some more smarts regarding
  etags, last-modified, and conditional requests.

* tekuti/page-helpers.scm (respond): Add etag arg. Set a date.

* tekuti/page.scm: Set etags on a number of pages.
This commit is contained in:
Andy Wingo 2010-12-06 13:00:53 +01:00
parent 15f024a12d
commit 839d2e27eb
3 changed files with 81 additions and 22 deletions

View file

@ -30,13 +30,19 @@
#:use-module (tekuti util) #:use-module (tekuti util)
#:use-module (web request) #:use-module (web request)
#:use-module (web response) #:use-module (web response)
#:use-module (srfi srfi-19)
#:export (make-empty-cache #:export (make-empty-cache
cached-response-and-body cached-response-and-body
update-cache)) update-cache))
(define (cacheable-request? request) (define (cacheable-request? request)
(and (memq (request-method request) '(GET HEAD)) (and (memq (request-method request) '(GET HEAD))
(not (request-authorization request)))) (not (request-authorization request))
;; We don't cache these conditional requests; just
;; if-modified-since and if-none-match.
(not (request-if-match request))
(not (request-if-range request))
(not (request-if-unmodified-since request))))
(define (cacheable-response? response) (define (cacheable-response? response)
(and (not (memq 'no-cache (response-pragma response))) (and (not (memq 'no-cache (response-pragma response)))
@ -47,31 +53,75 @@
(define (make-empty-cache) (define (make-empty-cache)
'()) '())
(define (make-entry matcher response body) (define-syntax build-headers
(cons matcher (cons response body))) (syntax-rules ()
(define (entry-matcher entry) ((_ k v-exp rest ...)
(car entry)) (let ((v v-exp))
(define (entry-response-body-pair entry) (let ((tail (build-headers rest ...)))
(cdr entry)) (if v
(acons 'k v tail)
tail))))
((_ tail)
tail)))
(define (make-entry request response body)
(let ((uri (request-uri request))
(method (request-method request)))
(case (response-code response)
((304)
(lambda (request)
(and (equal? (request-uri request) uri)
(eq? (request-method request) method)
(let ((last-modified (response-last-modified response))
(since (request-if-modified-since request)))
(if (and last-modified since)
(<= (date->time-utc last-modified) (date->time-utc since))
#t))
(let ((etag (response-etag response))
(match (request-if-none-match request)))
(if (and etag match)
(and (list? match) (member etag match))
#t))
(cons response body))))
((200)
(lambda (request)
(and (equal? (request-uri request) uri)
(eq? (request-method request) method)
(or (let ((last-modified (response-last-modified response))
(since (request-if-modified-since request))
(etag (response-etag response))
(match (request-if-none-match request)))
(and (or since match)
(or (not since)
(and last-modified
(<= (date->time-utc last-modified)
(date->time-utc since))))
(or (not match)
(and etag (list? match) (member etag match)))
(cons (build-response
#:code 304
#:headers (build-headers
etag etag
last-modified last-modified
date (current-date)
'()))
#f)))
(cons response body)))))
(else
(lambda (request)
(and (equal? (request-uri request) uri)
(eq? (request-method request) method)
(cons response body)))))))
(define (cached-response-and-body cache request) (define (cached-response-and-body cache request)
(and cache (and cache
(cacheable-request? request) (cacheable-request? request)
(or-map (lambda (entry) (or-map (lambda (entry) (entry request))
(and ((entry-matcher entry) request)
(entry-response-body-pair entry)))
cache))) cache)))
(define (make-matcher request response)
(let ((uri (request-uri request))
(method (request-method request)))
(lambda (request)
(and (equal? (request-uri request) uri)
(eq? (request-method request) method)))))
(define (update-cache cache request response body) (define (update-cache cache request response body)
(if (and (cacheable-request? request) (if (and (cacheable-request? request)
(cacheable-response? response)) (cacheable-response? response))
(cons (make-entry (make-matcher request response) response body) (cons (make-entry request response body)
(take-max (or cache '()) 9)) (take-max (or cache '()) 19))
(or cache '()))) (or cache '())))

View file

@ -80,6 +80,7 @@
(status (if redirect 302 200)) (status (if redirect 302 200))
(title *title*) (title *title*)
last-modified last-modified
etag
(doctype xhtml-doctype) (doctype xhtml-doctype)
(content-type-params '(("charset" . "utf-8"))) (content-type-params '(("charset" . "utf-8")))
(content-type "text/html") (content-type "text/html")
@ -91,6 +92,8 @@
location (and=> redirect ensure-public-uri) location (and=> redirect ensure-public-uri)
last-modified last-modified last-modified last-modified
content-type (cons content-type content-type-params) content-type (cons content-type content-type-params)
date (current-date)
etag (if (string? etag) (cons etag #t) etag)
extra-headers)) extra-headers))
(lambda (port) (lambda (port)
(if sxml (if sxml

View file

@ -171,7 +171,8 @@
(respond `(,(main-sidebar request index) (respond `(,(main-sidebar request index)
,@(map (lambda (post) ,@(map (lambda (post)
(show-post post #f)) (show-post post #f))
(published-posts index 10))))) (published-posts index 10)))
#:etag (assq-ref index 'master)))
(define (page-show-post request body index year month day post) (define (page-show-post request body index year month day post)
(cond (cond
@ -180,7 +181,8 @@
=> (lambda (post) => (lambda (post)
(respond `(,(post-sidebar post index) (respond `(,(post-sidebar post index)
,(show-post post #t)) ,(show-post post #t))
#:title (string-append (post-title post) " -- " *title*)))) #:title (string-append (post-title post) " -- " *title*)
#:etag (assq-ref index 'master))))
(else (else
(page-not-found request body index)))) (page-not-found request body index))))
@ -233,7 +235,8 @@
(cond (cond
((or (null? posts) (too-early? (car posts))) ((or (null? posts) (too-early? (car posts)))
(respond (reverse out) (respond (reverse out)
#:title (string-append "archives -- " *title*))) #:title (string-append "archives -- " *title*)
#:etag (assq-ref index 'master)))
((new-header (car posts)) ((new-header (car posts))
=> (lambda (sxml) => (lambda (sxml)
(lp (cdr posts) (make-date-header (car posts)) (lp (cdr posts) (make-date-header (car posts))
@ -256,6 +259,7 @@
(respond `((div (@ (id "tag-cloud")) (respond `((div (@ (id "tag-cloud"))
(h2 "all tags") (h2 "all tags")
,@(tag-cloud (top-tags index 200)))) ,@(tag-cloud (top-tags index 200))))
#:etag (assq-ref index 'master)
#:title (string-append "all tags -- " *title*))) #:title (string-append "all tags -- " *title*)))
(define (page-show-tag request body index tag) (define (page-show-tag request body index tag)
@ -268,6 +272,7 @@
,@(map (lambda (post) `(p ,(post-link post))) ,@(map (lambda (post) `(p ,(post-link post)))
posts) posts)
,(related-tag-cloud tag index)) ,(related-tag-cloud tag index))
#:etag (assq-ref index 'master)
#:title (string-append "posts tagged \"" tag "\"")) #:title (string-append "posts tagged \"" tag "\""))
(respond `((h2 "Unknown tag " ,tag) (respond `((h2 "Unknown tag " ,tag)
(p "No posts were found tagged as \"" ,tag "\".")) (p "No posts were found tagged as \"" ,tag "\"."))
@ -305,6 +310,7 @@
#:last-modified (and=> last-modified timestamp->date) #:last-modified (and=> last-modified timestamp->date)
#:doctype #f #:doctype #f
#:content-type "application/atom+xml" #:content-type "application/atom+xml"
#:etag (assq-ref index 'master)
#:sxml (append (atom-header last-modified) #:sxml (append (atom-header last-modified)
(map (map
(lambda (post) (lambda (post)