1 /*******************************************************************************
2 
3     HTTP Cookie Generator
4 
5     Reference:      RFC 2109
6 
7                     @see http://www.w3.org/Protocols/rfc2109/rfc2109.txt
8                     @see http://www.servlets.com/rfcs/rfc2109.html
9 
10     Copyright:
11         Copyright (c) 2009-2016 dunnhumby Germany GmbH.
12         All rights reserved.
13 
14     License:
15         Boost Software License Version 1.0. See LICENSE_BOOST.txt for details.
16         Alternatively, this file may be distributed under the terms of the Tango
17         3-Clause BSD License (see LICENSE_BSD.txt for details).
18 
19  ******************************************************************************/
20 
21 module ocean.net.http.cookie.HttpCookieGenerator;
22 
23 
24 import ocean.meta.types.Qualifiers;
25 
26 import ocean.core.Verify;
27 
28 import ocean.net.util.ParamSet;
29 
30 import ocean.net.http.consts.CookieAttributeNames;
31 
32 import ocean.net.http.time.HttpTimeFormatter;
33 
34 import core.stdc.time: time_t;
35 
36 /******************************************************************************/
37 
38 class HttpCookieGenerator : ParamSet
39 {
40     /**************************************************************************
41 
42         Cookie ID
43 
44      **************************************************************************/
45 
46     public istring id;
47 
48     /**************************************************************************
49 
50         Cookie domain and path
51 
52      **************************************************************************/
53 
54     public cstring domain, path;
55 
56     /**************************************************************************
57 
58         Expiration time manager
59 
60      **************************************************************************/
61 
62     private static class ExpirationTime
63     {
64         /**********************************************************************
65 
66             Expiration time if set.
67 
68          **********************************************************************/
69 
70         private time_t t;
71 
72         /**********************************************************************
73 
74             true if the expiration time is currently defined or false otherwise.
75 
76          **********************************************************************/
77 
78         private bool is_set_ = false;
79 
80         /**********************************************************************
81 
82             Sets the expiration time.
83 
84             Params:
85                 t = expiration time
86 
87             Returns:
88                 t
89 
90             In:
91                 t must be at least 0.
92 
93          **********************************************************************/
94 
95         public time_t opAssign ( time_t t )
96         {
97             verify(t >= 0, "negative time value");
98             this.is_set_ = true;
99             return this.t = t;
100         }
101 
102         /**********************************************************************
103 
104             Marks the expiration time as "not set".
105 
106          **********************************************************************/
107 
108         public void clear ( )
109         {
110             this.is_set_ = false;
111         }
112 
113         /**********************************************************************
114 
115             Returns:
116                 true if the expiration time is currently defined or false
117                 otherwise.
118 
119          **********************************************************************/
120 
121         public bool is_set ( )
122         {
123             return this.is_set_;
124         }
125 
126         /**********************************************************************
127 
128             Obtains the expiration time.
129 
130             Params:
131                 t = destination variable, will be set to the expiration time if
132                     and only if an expiration time is currently defined.
133 
134             Returns:
135                 true if an expiration time is currently defined and t has been
136                 set to it or false otherwise.
137 
138          **********************************************************************/
139 
140         public bool get ( ref time_t t )
141         {
142             if (this.is_set_)
143             {
144                 t = this.t;
145             }
146 
147             return this.is_set_;
148         }
149     }
150 
151     /**************************************************************************
152 
153         Expiration time manager with string formatter
154 
155      **************************************************************************/
156 
157     private static class FormatExpirationTime : ExpirationTime
158     {
159         /**********************************************************************
160 
161             String formatter
162 
163          **********************************************************************/
164 
165         private HttpTimeFormatter formatter;
166 
167         /**********************************************************************
168 
169             Returns:
170                 current expiration time as HTTP time string or null if currently
171                 no expiration time is defined.
172 
173          **********************************************************************/
174 
175         public mstring format ( )
176         {
177             return super.is_set_? this.formatter.format(super.t) : null;
178         }
179     }
180 
181     /**************************************************************************
182 
183         Expiration time manager instance
184 
185      **************************************************************************/
186 
187     public  ExpirationTime       expiration_time;
188 
189     /**************************************************************************
190 
191         Expiration time manager/formatter instance
192 
193      **************************************************************************/
194 
195     private FormatExpirationTime fmt_expiration_time;
196 
197     /**************************************************************************
198 
199         Constructor
200 
201         Params:
202             id              = cookie ID
203             attribute_names = cookie attribute names
204 
205         Note:
206             This constructor takes a reference to id and use it internally,
207             hence 'id' must remain valid for the lifetime of this object.
208 
209      **************************************************************************/
210 
211     this ( istring id, istring[] attribute_names ... )
212     {
213         super.addKeys(this.id = id);
214 
215         super.addKeys(attribute_names);
216 
217         super.rehash();
218 
219         this.expiration_time = this.fmt_expiration_time = new FormatExpirationTime;
220     }
221 
222     /**************************************************************************
223 
224         Sets the cookie value.
225 
226         Params:
227             val = cookie value string
228 
229         Returns:
230             cookie value
231 
232      **************************************************************************/
233 
234     cstring value ( cstring val )
235     {
236         return super[this.id] = val;
237     }
238 
239     /**************************************************************************
240 
241         Returns:
242             the current cookie value
243 
244      **************************************************************************/
245 
246     cstring value ( )
247     {
248         return super[this.id];
249     }
250 
251     /**************************************************************************
252 
253         Renders the HTTP response Cookie header line field value.
254 
255         Params:
256             appendContent = callback delegate that will be invoked repeatedly
257             to concatenate the Cookie header line field value.
258 
259      **************************************************************************/
260 
261     void render ( scope void delegate ( cstring str ) appendContent )
262     {
263         uint i = 0;
264 
265         void append ( cstring key, cstring val )
266         {
267             if (val)
268             {
269                 if (i++)
270                 {
271                     appendContent("; ");
272                 }
273 
274                 appendContent(key);
275                 appendContent("=");
276                 appendContent(val);
277             }
278         }
279 
280         foreach (key, val; super)
281         {
282             append(key, val);
283         }
284 
285         append(CookieAttributeNames.Names.Domain,  this.domain);
286         append(CookieAttributeNames.Names.Path,    this.path);
287         append(CookieAttributeNames.Names.Expires, this.fmt_expiration_time.format());
288     }
289 
290     /**************************************************************************
291 
292         Clears the expiration time.
293 
294      **************************************************************************/
295 
296     public override void reset ( )
297     {
298         super.reset();
299 
300         this.expiration_time.clear();
301     }
302 }