header.ss
#lang scheme/base
;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; NET.plt
;;
;; abstraction of common network behaviors and services
;;
;; Bonzai Lab, LLC.  All rights reserved.
;;
;; Licensed under LGPL.
;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; header.ss
;; basic function for generating and parsing RFC822 headers.
;; yc 8/18/2009 - first version
(require mzlib/trace
         scheme/contract
         "line.ss"
         )

;; a header is simply a pair of strings...
(define (header? h)
  (and (pair? h)
       (string? (car h))
       (string? (cdr h))))

;; header->string: does not generate terminator
(define (header->string h) 
  (format "~a: ~a" (car h) (cdr h)))

;; string->header
;; convert a string into a header?
(define (string->header line)
  (define (helper match)
    (if match
        (cons (cadr match) (caddr match))
        #f))
  (helper (regexp-match #px"^([^:]+)\\s*:\\s*(.+)$" line)))

;; reading header.
;; RFC822 headers are actually non-trivial for parsing purposes. 
;; first it requires the handling of "folded line", which means that any line
;; that does not end directly in
(define (read-headers in) 
  (define (return lines)
    (map string->header lines))
  (define (helper lines) 
    (let ((l (read-folded-line in))) 
      (if (string=? l "") ;; we are done...
          (return lines)
          (helper (cons l lines)))))
  (helper '()))
          
;; provide
(provide/contract 
 (header? (-> any/c boolean?))
 (header->string (-> header? string?))
 (string->header (-> string? (or/c #f (cons/c string? string?))))
 (read-headers (-> input-port? (listof header?)))
 )