PNG  IHDR!@ PLTE>O`jqv 7'tEXtPage
cookie.scm - metalympiada
git clone git://metalympiada.org/
Log | Files | README | LICENSE

cookie.scm (3693B)


   1 ;;; guile-webutils -- Web application utilities for Guile
   2 ;;; Copyright © 2016  Christopher Allan Webber <cwebber@dustycloud.org>
   3 (define-module (cookie)
   4   #:export (set-cookie delete-cookie))
   5 (use-modules (srfi srfi-1)
   6              (srfi srfi-19)
   7              (srfi srfi-26)
   8              (ice-9 control)
   9              (ice-9 match)
  10              (web http))
  11 
  12 (define cookie-val-char-set
  13   (char-set-difference (char-set-delete char-set:ascii #\, #\;)
  14                        char-set:iso-control))
  15 
  16 (define cookie-name-char-set
  17   (char-set-delete cookie-val-char-set #\=))
  18 
  19 (define (parse-cookie cookie-text)
  20   (let ((parts (string-split cookie-text #\;)))
  21     (define (split-cookie-pair cookie-pair)
  22       (let* ((trimmed (string-trim cookie-pair))
  23              (delim (string-index trimmed #\=))
  24              (attrib (if delim
  25                          (substring trimmed 0 delim)
  26                          trimmed))
  27              (val (if delim
  28                       (substring trimmed (+ delim 1))
  29                       #t)))
  30         (cons attrib val)))
  31     (map split-cookie-pair parts)))
  32 
  33 (define (date->http-date-string date)
  34   (call-with-output-string (cut (@@ (web http) write-date) date <>)))
  35 
  36 (define (write-cookie cookie-alist port)
  37   (let ((cookie-str
  38          (string-join 
  39           (map (match-lambda
  40                  ((name . (? string? val))
  41                   (string-append name "=" val))
  42                  ((name . (? date? val))
  43                   (string-append name "=" (date->http-date-string val)))
  44                  ((name . #t)
  45                   name))
  46                cookie-alist)
  47           "; ")))
  48     (display cookie-str port)))
  49 
  50 (define (valid-cookie-name? str)
  51   (and (string? str)
  52        (string-every cookie-name-char-set str)))
  53 
  54 (define (valid-cookie-val? str)
  55   (or (eq? str #t)
  56       (and (string? str)
  57            (string-every cookie-val-char-set str))
  58       (date? str)))
  59 
  60 (define (validate-cookie cookie-alist)
  61   (match cookie-alist
  62     ((((? valid-cookie-name? name) . (or #t (? valid-cookie-val? _))) ...)
  63      #t)
  64     (_ #f)))
  65 
  66 (declare-header! "Cookie"
  67                  parse-cookie validate-cookie write-cookie)
  68 
  69 (define (parse-set-cookie str)
  70   (match (parse-cookie str)
  71     (((name . val) attrs ...)
  72      (list name val attrs))))
  73 
  74 (define (validate-set-cookie obj)
  75   (match obj
  76     ((name val (attrs ...))
  77      (validate-cookie
  78       (cons (cons name val)
  79             attrs)))
  80     (_ #f)))
  81 
  82 (define (write-set-cookie obj port)
  83   (match obj
  84     ((name val (attrs ...))
  85      (write-cookie
  86       (cons (cons name val)
  87             attrs)
  88       port))))
  89 
  90 (declare-header! "Set-Cookie"
  91                  parse-set-cookie validate-set-cookie write-set-cookie
  92                  #:multiple? #t)
  93 
  94 (define* (set-cookie name #:optional (val "")
  95                      #:key expires max-age domain
  96                      path secure http-only
  97                      (extensions '())) 
  98   (define (maybe-append name val)
  99     (lambda (prev)
 100       (if val
 101           (cons (cons name val)
 102                 prev)
 103           prev)))
 104   (define basic-prop-alist
 105     ((compose
 106       (maybe-append "Expires" expires)
 107       (maybe-append "Max-Age" max-age)
 108       (maybe-append "Domain" domain)
 109       (maybe-append "Path" path)
 110       (maybe-append "Secure" secure)
 111       (maybe-append "HttpOnly" http-only))
 112      '()))
 113   (define prop-alist
 114     (append basic-prop-alist
 115             extensions))
 116   (cons 'set-cookie (list name val prop-alist)))
 117 
 118 (define %the-epoch
 119   (time-monotonic->date (make-time 'time-monotonic 0 0) 0))
 120 
 121 (define (delete-cookie name)
 122   (set-cookie name
 123               #:expires %the-epoch
 124               #:path "/"
 125               #:secure #t
 126               #:http-only #t))
@JmIDATx[]lu3Ryi i~N }(- pFH9Tܞ33G.%v!H{wscr/pA|A+x]YQ -dn…ܠE(v.^/bE\ ݻ|] !\ @CERI -pU8TpS7&xzp~bT OΝJv T(` W%S/9 f68vɅsg!|N+" F> .8w*!}>'x7sl V24{9YR7wp7`.rC ;gahE}tJYV'9̝ 4,pn-L<^4L-&qɫݼ 3[Q g6ftHN g΄밥qqsp;Ё9쀅grRCҬlTVՇ@$ }m|fm=zE,Jwa38BP8_%9XL +9 `d"MUڲb2>??/q<2L#Cr3 ,V}m&i܆%if☳OJyΌ, aڭIܜ:=) ) Lϐ*TG!@Dp.X_?0aP*d<W'Y R*gu=-ygmt` ,z5ՑX/LJF'@}b M$ Y޵`M|R) ` 0t!=#+-s nyDJPZECev]<%|]KU擺:85NPZ&f!^3(hDH?AGZ[ot : $sgх*Flg6M TZRmY%TMeИJ\>kiחb+W$*G9^ ^D*;>onY)׍D@C.ٰt4̞xi9pb-wߘa)$HIwru# 8 nuiⱷ͠3T.ouN~TܳFVoySwel 9(A="9ù:#/Vh4UNe(kI]g#¥iO5Wzl6>1% pY>EUNüׯ@ڋ"&kfn b%lvLU 鵶(|n# %# O3$kXEӍӝp{ZQ+yh)JBeR  d&jcx %e.pF\Mj{O@-"o-6Ă+7#teR6o@!c.?{ħFE|=(>5Ó}F8mp2S"Xlˋ /W[g5so*&u2d+"(Q D}Q,c{;(Sxw}JY/ D㎸.7v?3ꄓsq_Z^ojΛ{ïmxz0Z345b3*u,|u+7oz^pCէړW`QhC;kk4*wNώ"z_Sl&4'YQ]= 6UI|6" [ `J56lhĈ x0*0+$g8%dZ鹁OIЙ[=7ږ̓RJ 95ѿ~:)gX, tBFGj׊LgOD&PIV$qy8!V? `jJH E6>iO W AV beR7hԷ]`0g\jEͲf|8ʌ>!C'a&_j5otR71J Rõ} h`Q}#9>F 9h3Q OH 9{x+J @Us1aI-;Y á X !ZA#J@{:+-|[C0A22߅_ f !\bgpC% TgYg_#1g^.aNpxP%+NK706,.VA+jh"Tu9wJk֣b5b *Y"cnPpo_QGE"% U4]rR9P;H%.$C4K< qW.j07eIPBUZ⚩ްX[dzR;b2*ftR$[)鰂a-ˆI>).x24 YO^+\? /؊ROfd>?2tR}陭lO 9GJܺ^ gk{H6H/l]!Xa1$. WB؆,?Sc+*`d?u N;Ú?؊ZbaAA\[NһGaypK[tUHvGdbd@Vm?^Ȅz/Lr\ )1&[ w00E?Ro1)> 2jjrрɬAinC.y7&+q$u0>1L! u 5XMDҠ#3us SuqdHPrPjG5^I~{ %㒽I*!eE;hj\;~+ n2 ]h|Y+pb#Ed$8%|r61zHU6 p[KRd۳!jyW?B7Ċ]p~{WV q>1p*@I&F3?OeȆeSWWՅ@j;(c:SmAXSC;}*혊 mu" 4uL۟ – @\TZv]mb%ZO }4̂Bh_c -o8~ܤ J_U87!Dj@B ކW%^Bpk_dUqr7^n/apiqB: KDEQ rq㡑}wO?IU6QAP_va-LY#_/u&{:HeߊuakN~'0ؒ^ӷn0G\ՋΓ:[ (}L|9f}5\'߃ؠ6\Icon :ZIHh߰$X$Lҩ8t$dec9dO0l`֓ap՛{a1_v'*x8,ދe6qz J:A1jGbt¿C؀|B}TcUh ZR7 @kH  }+UdĴc0Z8ˎ c}fQ^Ǔ^]_%Zd`C,~Cb&KI DdN u@{u2Y;[N{uvcvdXlW[]{D \9 `@]ƫδ,r91N ]W'ͷ#NWc Ѡg ;B1>^/m+z?$ ^ZGݧwYguXbR=S2ћ oȦt~k7~.]b&}<ʞyP3h0Gf[R+XTCHtЊ(Ǵ7:&:ݲ2k2I)@6jب{Lײr,nn\-#AB(%FfeP 77Ԫ?XHR[܌,5Q.<HoJHz;ng47s T PA{@"@'Mp;PR/'vb;f"W\yØp֑_(Yp&w4\1ӱks"b5(9@XzE }e?*JE+;uKRllP]=*v^ιB;cfSЄ9?F;x P#hYҼ6H3U:XЏ0As[7Hβ57i3? cx4EV\RҲyrDCI/zF#ܞ@~biX[!eiTL na|OSԸ֧TZqF kKQi ~aY*`aT`D$K[E+O7 <\I2:XrMm/uvM/) QvE"+ nP#!^SP*l)$J^ٓlcSȉ2q7 ~ y7iY$:#!X.%Kw3#vB#nИK˪5X2P78 D