#lang racket ;; to store the input data (struct request [segment-id stdin data params] #:mutable #:transparent) (define (create-empty-request) (request #f (open-output-bytes) (open-output-bytes) (open-output-bytes))) (define (decode-segment request in out) ;; don't care if read-bytes return eof (define header (read-bytes 8 in)) (define segment-type (bytes-ref header 1)) (define segment-id (+ (arithmetic-shift (bytes-ref header 2) 8) (bytes-ref header 3))) ;; don't care if read-bytes return eof (define data-length (+ (arithmetic-shift (bytes-ref header 4) 8) (bytes-ref header 5))) (define data (read-bytes data-length in)) ;; consume the padding bytes (void (read-bytes (bytes-ref header 6) in)) ;; (printf "segment type: ~a\n" segment-type) ;; (printf "id: ~a\n" segment-id) ;; (printf "data length: ~a\n" data-length) ;; (printf "~a\n" data) ;; segment-id = 0 is a special case where the web server and the fastcgi ;; process exchange information like n° of maximum connection so... we don't ;; care. (when (= 0 segment-id) (raise "unimplemented")) ;; (printf "~a\n" request) (case segment-type ;; fcgi beginrequest ((1) (set-request-segment-id! request segment-id)) ;; fcgi params ((4) (display data (request-params request))) ;; fcgi stdin ((5) (if (= 0 data-length) ; Not sure if it's the rigth way but use that to ; know if the webserver input is over. (respond request out) (display data (request-stdin request)))) ;; fcgi data ((8) (display data (request-data request))) ;; fcgi get values ;; fcgi abort request ((2 9) (raise "unimplemented")) (else (raise "undocumented type")))) (define (end-of-request id) (bytes ;; header 1 3 (arithmetic-shift id -8) (bitwise-bit-field id 0 8) 0 8 0 0 ;; the data ; what the status should be? 0 0 0 0 0 0 0 0 )) (define (build-header type id data-length padding-length) (bytes 1 type (arithmetic-shift id -8) (modulo id 256) (arithmetic-shift data-length -8) (modulo data-length 256) padding-length 0)) (define (fcgi-end-request id out) (write-bytes (build-header 3 id 8 0) out) (write-bytes (bytes 0 0 0 0 0 0 0 0) out) (close-output-port out)) (define (write-fcgi-stdout id data out [close #f]) (define data-length (bytes-length data)) (define padding-length (if (= 0 (modulo data-length 8)) 0 (- 8 (modulo data-length 8)))) (write-bytes (build-header 6 id data-length padding-length) out) (write-bytes data out) (when (not (= 0 padding-length)) (write-bytes (make-bytes padding-length) out)) (when close (write-bytes (build-header 6 id 0 0) out))) (define (respond request out) ;; get the data from request (define params (decode-params (open-input-bytes (let ([port (request-params request)]) (close-output-port port) (get-output-bytes port))))) (define data (open-output-bytes)) (write-bytes #"Content-type: text/html\r\n\r\n
" data) (write-bytes #"" data) (write-bytes (car param) data) (write-bytes #" | " data) (write-bytes (cdr param) data) (write-bytes #" |