cache GET-BINDINGS-RESULTS' results of POST requests with weak-pointers
This commit is contained in:
		
							parent
							
								
									588dc93ddf
								
							
						
					
					
						commit
						ddae6cfb3c
					
				|  | @ -33,22 +33,60 @@ | ||||||
| ;;; Return the form data as an alist of decoded strings. | ;;; Return the form data as an alist of decoded strings. | ||||||
| ;;; So a query string like "button=on&reply=Oh,%20yes" becomes alist | ;;; So a query string like "button=on&reply=Oh,%20yes" becomes alist | ||||||
| ;;;     (("button" . "on") ("reply" . "Oh, yes")) | ;;;     (("button" . "on") ("reply" . "Oh, yes")) | ||||||
| ;;; This only works for GET and POST methods. | ;;; This works only for GET and POST methods. | ||||||
| 
 | 
 | ||||||
| (define form-query parse-html-form-query) | (define form-query parse-html-form-query) | ||||||
|  | 
 | ||||||
|  | ;; Bindings of POST requests can be read only once, since they are | ||||||
|  | ;; read from an input port. So we have to cache them, for the case of | ||||||
|  | ;; a later GET-BINDINGS call on the same POST request. The request are | ||||||
|  | ;; referenced by a weak pointer. | ||||||
|  | (define *POST-bindings-cache* '()) | ||||||
|  | (define *cache-lock* (make-lock)) | ||||||
|  | 
 | ||||||
| (define (get-bindings request) | (define (get-bindings request) | ||||||
|   (let ((request-method (request:method request))) |   (let ((request-method (request:method request))) | ||||||
|     (cond |     (cond | ||||||
|      ((string=? request-method "GET") |      ((string=? request-method "GET") | ||||||
|       (form-query (http-url:search (request:url request)))) |       (form-query (http-url:search (request:url request)))) | ||||||
|      ((string=? request-method "POST") |      ((string=? request-method "POST") | ||||||
|       (let* ((content-length (get-content-length (request:headers request))) |       (or (cached-bindings request) | ||||||
| 	     (input-port (socket:inport (request:socket request))) | 	  (let* ((content-length (get-content-length (request:headers request))) | ||||||
| 	     (form-data (read-string content-length input-port))) | 		 (input-port (socket:inport (request:socket request))) | ||||||
| 	(form-query form-data))) | 		 (form-data (read-string content-length input-port))) | ||||||
|  | 	    (let ((form-bindings (form-query form-data))) | ||||||
|  | 	      (obtain-lock *cache-lock*) | ||||||
|  | 	      (set! *POST-bindings-cache* (cons (cons (make-weak-pointer request) | ||||||
|  | 						      form-bindings) | ||||||
|  | 						*POST-bindings-cache*)) | ||||||
|  | 	      (release-lock *cache-lock*) | ||||||
|  | 	      form-bindings)))) | ||||||
|      (else |      (else | ||||||
|       (error "unsupported request type"))))) |       (error "unsupported request type"))))) | ||||||
| 
 | 
 | ||||||
|  | ;; Looking up, if we have cached this request. While going through the | ||||||
|  | ;; list, we remove entries to request objects, that are no longer | ||||||
|  | ;; valid. Expecting a call for an uncached request every now and then, | ||||||
|  | ;; it is guaranteed, that the list is cleaned up every now and then. | ||||||
|  | (define (cached-bindings request) | ||||||
|  |   (obtain-lock *cache-lock*) | ||||||
|  |   (let ((result  | ||||||
|  | 	 (let loop ((cache *POST-bindings-cache*)) | ||||||
|  | 	   (if (null? cache) | ||||||
|  | 	       #f			; no such request cached | ||||||
|  | 	       (let* ((head (car cache)) | ||||||
|  | 		      (req (weak-pointer-ref (car head)))) | ||||||
|  | 		 (if req | ||||||
|  | 		     (if (eq? req request) | ||||||
|  | 			 (cdar cache)	; request is cached | ||||||
|  | 			 (loop (cdr cache))) ; request isn't cached | ||||||
|  | 		     (begin | ||||||
|  | 		       ;; request object is gone ==> remove it from list | ||||||
|  | 		       (set! cache (cdr cache)) | ||||||
|  | 		       (loop cache)))))))) | ||||||
|  |     (release-lock *cache-lock*) | ||||||
|  |     result)) | ||||||
|  |     | ||||||
| ;; Will be needed when we handle POST requests. | ;; Will be needed when we handle POST requests. | ||||||
| (define (get-content-length headers) | (define (get-content-length headers) | ||||||
|   (cond ((get-header headers 'content-length) => |   (cond ((get-header headers 'content-length) => | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	 interp
						interp