1 /*
2 **  Licensed to the Apache Software Foundation (ASF) under one or more
3 ** contributor license agreements.  See the NOTICE file distributed with
4 ** this work for additional information regarding copyright ownership.
5 ** The ASF licenses this file to You under the Apache License, Version 2.0
6 ** (the "License"); you may not use this file except in compliance with
7 ** the License.  You may obtain a copy of the License at
8 **
9 **      http://www.apache.org/licenses/LICENSE-2.0
10 **
11 **  Unless required by applicable law or agreed to in writing, software
12 **  distributed under the License is distributed on an "AS IS" BASIS,
13 **  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 **  See the License for the specific language governing permissions and
15 **  limitations under the License.
16 */
17 
18 #ifndef APREQ_COOKIE_H
19 #define APREQ_COOKIE_H
20 
21 #include "apreq.h"
22 #include "apr_time.h"
23 
24 #ifdef  __cplusplus
25 extern "C" {
26 #endif
27 
28 /**
29  * @file apreq_cookie.h
30  * @brief Cookies and Jars.
31  * @ingroup libapreq2
32  *
33  * apreq_cookie.h describes a common server-side API for request (incoming)
34  * and response (outgoing) cookies.  It aims towards compliance with the
35  * standard cookie specifications listed below.
36  *
37  * @see http://wp.netscape.com/newsref/std/cookie_spec.html
38  * @see http://www.ietf.org/rfc/rfc2109.txt
39  * @see http://www.ietf.org/rfc/rfc2964.txt
40  * @see http://www.ietf.org/rfc/rfc2965.txt
41  *
42  */
43 
44 /** This macro is deprecated.
45  *
46  * Maximum length of a single Set-Cookie(2) header.
47  */
48 #define APREQ_COOKIE_MAX_LENGTH            4096
49 
50 /** @brief Cookie type, supporting both Netscape and RFC cookie specifications.
51  */
52 
53 typedef struct apreq_cookie_t {
54 
55     char           *path;        /**< Restricts url path */
56     char           *domain;      /**< Restricts server domain */
57     char           *port;        /**< Restricts server port */
58     char           *comment;     /**< RFC cookies may send a comment */
59     char           *commentURL;  /**< RFC cookies may place an URL here */
60     apr_time_t      max_age;     /**< total duration of cookie: -1 == session */
61     unsigned        flags;       /**< charsets, taint marks, app-specific bits */
62     const apreq_value_t   v;     /**< "raw" cookie value */
63 
64 } apreq_cookie_t;
65 
66 
67 /** Upgrades a jar's table values to apreq_cookie_t structs. */
68 static APR_INLINE
apreq_value_to_cookie(const char * val)69 apreq_cookie_t *apreq_value_to_cookie(const char *val)
70 {
71     union { const char *in; char *out; } deconst;
72 
73     deconst.in = val;
74     return apreq_attr_to_type(apreq_cookie_t, v,
75            apreq_attr_to_type(apreq_value_t, data, deconst.out));
76 }
77 
78 /**@return 1 if this is an RFC cookie, 0 if its a Netscape cookie. */
79 static APR_INLINE
apreq_cookie_version(const apreq_cookie_t * c)80 unsigned apreq_cookie_version(const apreq_cookie_t *c) {
81     return APREQ_FLAGS_GET(c->flags, APREQ_COOKIE_VERSION);
82 }
83 
84 /** Sets the cookie's protocol version. */
85 static APR_INLINE
apreq_cookie_version_set(apreq_cookie_t * c,unsigned v)86 void apreq_cookie_version_set(apreq_cookie_t *c, unsigned v) {
87     APREQ_FLAGS_SET(c->flags, APREQ_COOKIE_VERSION, v);
88 }
89 
90 /** @return 1 if the secure flag is set, 0 otherwise. */
91 static APR_INLINE
apreq_cookie_is_secure(const apreq_cookie_t * c)92 unsigned apreq_cookie_is_secure(const apreq_cookie_t *c) {
93     return APREQ_FLAGS_GET(c->flags, APREQ_COOKIE_SECURE);
94 }
95 
96 /** Sets the cookie's secure flag, meaning it only
97  *  comes back over an SSL-encrypted connction.
98  */
99 static APR_INLINE
apreq_cookie_secure_on(apreq_cookie_t * c)100 void apreq_cookie_secure_on(apreq_cookie_t *c) {
101     APREQ_FLAGS_ON(c->flags, APREQ_COOKIE_SECURE);
102 }
103 
104 /** Turns off the cookie's secure flag. */
105 static APR_INLINE
apreq_cookie_secure_off(apreq_cookie_t * c)106 void apreq_cookie_secure_off(apreq_cookie_t *c) {
107     APREQ_FLAGS_OFF(c->flags, APREQ_COOKIE_SECURE);
108 }
109 
110 /** @return 1 if the HttpOnly flag is set, 0 otherwise. */
111 static APR_INLINE
apreq_cookie_is_httponly(const apreq_cookie_t * c)112 unsigned apreq_cookie_is_httponly(const apreq_cookie_t *c) {
113     return APREQ_FLAGS_GET(c->flags, APREQ_COOKIE_HTTPONLY);
114 }
115 
116 /** Sets the cookie's HttpOnly flag, meaning it is not
117  *  accessible through client-side script in supported
118  *  browsers.
119  */
120 static APR_INLINE
apreq_cookie_httponly_on(apreq_cookie_t * c)121 void apreq_cookie_httponly_on(apreq_cookie_t *c) {
122     APREQ_FLAGS_ON(c->flags, APREQ_COOKIE_HTTPONLY);
123 }
124 
125 /** Turns off the cookie's HttpOnly flag. */
126 static APR_INLINE
apreq_cookie_httponly_off(apreq_cookie_t * c)127 void apreq_cookie_httponly_off(apreq_cookie_t *c) {
128     APREQ_FLAGS_OFF(c->flags, APREQ_COOKIE_HTTPONLY);
129 }
130 
131 
132 /** @return 1 if the taint flag is set, 0 otherwise. */
133 static APR_INLINE
apreq_cookie_is_tainted(const apreq_cookie_t * c)134 unsigned apreq_cookie_is_tainted(const apreq_cookie_t *c) {
135     return APREQ_FLAGS_GET(c->flags, APREQ_TAINTED);
136 }
137 
138 /** Sets the cookie's tainted flag. */
139 static APR_INLINE
apreq_cookie_tainted_on(apreq_cookie_t * c)140 void apreq_cookie_tainted_on(apreq_cookie_t *c) {
141     APREQ_FLAGS_ON(c->flags, APREQ_TAINTED);
142 }
143 
144 /** Turns off the cookie's tainted flag. */
145 static APR_INLINE
apreq_cookie_tainted_off(apreq_cookie_t * c)146 void apreq_cookie_tainted_off(apreq_cookie_t *c) {
147     APREQ_FLAGS_OFF(c->flags, APREQ_TAINTED);
148 }
149 
150 /**
151  * Parse a cookie header and store the cookies in an apr_table_t.
152  *
153  * @param pool pool which allocates the cookies
154  * @param jar table where parsed cookies are stored
155  * @param header the header value
156  *
157  * @return APR_SUCCESS.
158  * @return ::APREQ_ERROR_BADSEQ if an unparseable character sequence appears.
159  * @return ::APREQ_ERROR_MISMATCH if an rfc-cookie attribute appears in a
160  *         netscape cookie header.
161  * @return ::APR_ENOTIMPL if an unrecognized rfc-cookie attribute appears.
162  * @return ::APREQ_ERROR_NOTOKEN if a required token was not present.
163  * @return ::APREQ_ERROR_BADCHAR if an unexpected token was present.
164  */
165 APREQ_DECLARE(apr_status_t) apreq_parse_cookie_header(apr_pool_t *pool,
166                                                       apr_table_t *jar,
167                                                       const char *header);
168 
169 /**
170  * Returns a new cookie, made from the argument list.
171  *
172  * @param pool  Pool which allocates the cookie.
173  * @param name  The cookie's name.
174  * @param nlen  Length of name.
175  * @param value The cookie's value.
176  * @param vlen  Length of value.
177  *
178  * @return the new cookie
179  */
180 APREQ_DECLARE(apreq_cookie_t *) apreq_cookie_make(apr_pool_t *pool,
181                                                   const char *name,
182                                                   const apr_size_t nlen,
183                                                   const char *value,
184                                                   const apr_size_t vlen);
185 
186 /**
187  * Returns a string that represents the cookie as it would appear
188  * in a valid "Set-Cookie*" header.
189  *
190  * @param c cookie.
191  * @param p pool which allocates the returned string.
192  *
193  * @return header string.
194  */
195 APREQ_DECLARE(char*) apreq_cookie_as_string(const apreq_cookie_t *c,
196                                             apr_pool_t *p);
197 
198 
199 /**
200  * Same functionality as apreq_cookie_as_string.  Stores the string
201  * representation in buf, using up to len bytes in buf as storage.
202  * The return value has the same semantics as that of apr_snprintf,
203  * including the special behavior for a "len = 0" argument.
204  *
205  * @param c   cookie.
206  * @param buf storage location for the result.
207  * @param len size of buf's storage area.
208  *
209  * @return size of resulting header string.
210  */
211 APREQ_DECLARE(int) apreq_cookie_serialize(const apreq_cookie_t *c,
212                                           char *buf, apr_size_t len);
213 
214 /**
215  * Set the Cookie's expiration date.
216  *
217  * @param c The cookie.
218  * @param time_str If NULL, the Cookie's expiration date is unset,
219  * making it a session cookie.  This means no "expires" or "max-age"
220  * attribute will appear in the cookie's serialized form. If time_str
221  * is not NULL, the expiration date will be reset to the offset (from now)
222  * represented by time_str.  The time_str should be in a format that
223  * apreq_atoi64t() can understand, namely /[+-]?\\d+\\s*[YMDhms]/.
224  *
225  * @remarks Now time_str may also be a fixed date; see apr_date_parse_rfc()
226  * for admissible formats.
227  */
228 APREQ_DECLARE(void) apreq_cookie_expires(apreq_cookie_t *c,
229                                          const char *time_str);
230 
231 #ifdef __cplusplus
232  }
233 #endif
234 
235 #endif /*APREQ_COOKIE_H*/
236 
237 
238