r5483: *** empty log message ***
[wol.git] / uri.lisp
1 ;;;; -*- Mode: Lisp; Syntax: ANSI-Common-Lisp; Base: 10; Package: wol  -*-
2 ;;;; *************************************************************************
3 ;;;; FILE IDENTIFICATION
4 ;;;;
5 ;;;; Name:          uri.lisp
6 ;;;; Purpose:       URI functions for wol
7 ;;;; Programmer:    Kevin M. Rosenberg
8 ;;;; Date Started:  July 2003
9 ;;;;
10 ;;;; $Id: uri.lisp,v 1.8 2003/08/10 05:16:52 kevin Exp $
11 ;;;;
12 ;;;; This file and Wol are Copyright (c) 2003 by Kevin M. Rosenberg
13 ;;;; *************************************************************************
14
15 (in-package #:wol)
16
17 (defun req-recode-uri-sans-session-id (req)
18   (let ((ppath (puri:uri-parsed-path (request-uri req))))
19     (when (is-raw-session-id (second ppath))
20       (let ((new-path (list* (car ppath) (cddr ppath))))
21         (setf (uri-parsed-path (request-uri req)) new-path)
22         (setf (uri-parsed-path (request-raw-uri req)) new-path))
23       (setf (request-decoded-uri-path req)
24         (uridecode-string (uri-path (request-raw-uri req))))
25       (raw-session-id->session-id (second ppath)))))
26
27 (defun request-cookies (req)
28   (aif (aserve-request req)
29        (net.aserve:get-cookie-values it)
30        (loop for h in (request-headers req)
31            when (eq :cookie (car h))
32            collect (cdr h))))
33
34 (defun header-lines-matching (key headers)
35   (loop for hdr in headers
36       when (eq key (car hdr))
37       collect (cdr hdr)))
38
39 (defun set-cookies-in-headers (headers)
40   (header-lines-matching :set-cookie headers))
41
42 (defun cookies-in-headers (headers)
43   (header-lines-matching :cookie headers))
44
45 (defun cookie-session-key (ent cookies)
46   "Return the session key from the alist of cookies"
47   (let ((name (project-name (entity-project ent))))
48     (cdr (assoc name cookies :test #'string-equal))))
49
50 (defun compute-uris (req ent)
51   "Compute URI's of a request"
52   (let ((url-session-id (req-recode-uri-sans-session-id req)))
53     (compute-session req ent url-session-id)
54     
55     (multiple-value-bind (page plists query) 
56         (decode-url (puri:uri-path (request-raw-uri req)))
57       (when page
58         (setf (request-page req) (base-page-name page ent)))
59       (when plists
60         (setf (request-plist req) (car plists))
61         (setf (request-next-plists req) (cdr plists))
62         (when (null page)
63           (awhen (getf (request-plist req) :page)
64                  (setf (request-page req) it))))
65       (setf (request-uri-query req) query))))
66
67
68 ;;; URI Functions
69
70 (defun base-page-name (page ent)
71   "Return the base page name for a html url"
72   (let ((len-prefix (length (project-prefix (entity-project ent)))))
73     (assert (>= (length page) len-prefix))
74     (string-strip-ending (subseq page len-prefix)
75                          '(".html" ".lsp"))))
76
77 (defun split-plist-url (url)
78   (string-delimited-string-to-list url +plist-header+))
79
80 (defun decode-url (url)
81   "Decode raw url. Returns (values `<pagename>.html' list-of-plists query)"
82   (let* ((plists '())
83          (qsplit (delimited-string-to-list url #\?))
84          (query (cadr qsplit))
85          (split (split-plist-url (car qsplit)))
86          (page-name 
87           (when (and (plusp (length (car split)))
88                      (not (string= +full-asp-header+ (car split)))
89                      (not (string-starts-with +full-asp-header+ (car split))))
90             (car split))))
91     (dolist (elem (cdr split))
92       (push (url-string-to-plist elem) plists))
93     (values page-name (nreverse plists) query)))
94
95
96
97 (defun make-wol-url (page req ent &optional plist)
98   (let ((session (websession-from-req req))
99         (url-plist (append (list :page page) plist))
100         (prefix (project-prefix (entity-project ent))))
101     (concatenate 'string
102       prefix
103       (if (and session
104                  (websession-key session)
105                  (not (eq :cookies (websession-method session))))
106           (format nil "~~~A~~/" (websession-key session))
107         "")
108       (if (null plist)
109         (concatenate 'string page ".html")
110         (concatenate 'string
111           +asp-header+
112           (concatenate 'string +plist-header+ 
113                        (plist-to-url-string url-plist)))))))
114
115
116 ;; Property lists
117
118 (defun plist-to-url-string (plist &key (base64 t))
119   (let ((str (plist-to-compressed-string plist)))
120     (if base64
121         (string-to-base64-string str :uri t)
122         (uriencode-string str))))
123
124 (defun url-string-to-plist (str &key (base64 t))
125   (let ((decode (if base64
126                     (base64-string-to-string str :uri t)
127                     (uridecode-string str))))
128     (when decode
129       (ignore-errors (compressed-string-to-plist decode)))))
130
131 (defun plist-to-compressed-string (plist)
132   "Decode an encoded plist"
133     (assert (evenp (length plist)))
134     (do* ((output '())
135           (list plist (cddr list)))
136          ((null list)
137           (prin1-to-string (nreverse output)))
138       (push (compress-elem (car list)) output)
139       (push (cadr list) output)))
140
141 (defun compress-elem (elem)
142   "Encode a plist elem"
143   (case elem
144     (:page :p)
145     (:posted :t)
146     (:object-id :o)
147     (:session-id :s)
148     (:lang :l)
149     (:logged :g)
150     (:caller :c)
151     (:db :d)
152     
153     ;; For lookup-func1
154     (:func :f)
155     (:format :r)
156     (:key :k)
157     (:labels :a)
158     (:subobjects :b)
159     (:english-only :e)
160    
161     (:xml :x)
162     (:next-page :n)
163     
164     (otherwise elem)))
165
166 (defun compressed-string-to-plist (encoded-str)
167   (let ((encoded (ignore-errors (read-from-string encoded-str)))
168         (output '()))
169     (unless encoded
170       (cmsg "invalid encoded string")
171       #+ignore
172       (gen-invalid-encoded-str encoded-str)
173       nil)
174     (assert (evenp (length encoded)))
175     (do* ((elist encoded (cddr elist)))
176          ((null elist) (nreverse output))
177       (push (decompress-elem (car elist)) output)
178       (push (cadr elist) output))))
179
180 (defun decompress-elem (elem)
181   (case elem
182     (:N :next-page)
183     (:T :posted)
184     (:O :object-id)
185     (:S :session-id)
186     (:L :lang)
187     (:G :logged)
188     (:C :caller)
189     (:D :db)
190     
191     ;; For posting to lookup-func1
192     (:F :func)
193     (:K :key)
194     (:B :subobjects)
195     (:A :labels)
196     (:E :english-only)
197     (:R :format)
198     
199     (:X :xml)
200     (:P :page)
201
202     (otherwise elem)))
203           
204