File: | d/cookies.c |
Warning: | line 669, column 9 Duplicate code detected |
Note: | line 851, column 9 Similar code here |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* |
2 | * The contents of this file are subject to the Mozilla Public License |
3 | * Version 1.1 (the "License"); you may not use this file except in |
4 | * compliance with the License. You may obtain a copy of the License at |
5 | * http://mozilla.org/. |
6 | * |
7 | * Software distributed under the License is distributed on an "AS IS" |
8 | * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See |
9 | * the License for the specific language governing rights and limitations |
10 | * under the License. |
11 | * |
12 | * The Original Code is AOLserver Code and related documentation |
13 | * distributed by AOL. |
14 | * |
15 | * The Initial Developer of the Original Code is America Online, |
16 | * Inc. Portions created by AOL are Copyright (C) 1999 America Online, |
17 | * Inc. All Rights Reserved. |
18 | * |
19 | * Alternatively, the contents of this file may be used under the terms |
20 | * of the GNU General Public License (the "GPL"), in which case the |
21 | * provisions of GPL are applicable instead of those above. If you wish |
22 | * to allow use of your version of this file only under the terms of the |
23 | * GPL and not to allow others to use your version of this file under the |
24 | * License, indicate your decision by deleting the provisions above and |
25 | * replace them with the notice and other provisions required by the GPL. |
26 | * If you do not delete the provisions above, a recipient may use your |
27 | * version of this file under either the License or the GPL. |
28 | */ |
29 | |
30 | /* |
31 | * cookies.c -- |
32 | * |
33 | * Routines to manipulate HTTP cookie headers. |
34 | * |
35 | */ |
36 | |
37 | #include "nsd.h" |
38 | |
39 | /* |
40 | * Local functions defined in this file. |
41 | */ |
42 | |
43 | static int GetFirstNamedCookie(Ns_DStringTcl_DString *dest, const Ns_Set *hdrs, |
44 | const char *setName, const char *name) |
45 | NS_GNUC_NONNULL(2)__attribute__((__nonnull__(2))) NS_GNUC_NONNULL(3)__attribute__((__nonnull__(3))) NS_GNUC_NONNULL(4)__attribute__((__nonnull__(4))); |
46 | |
47 | static int GetAllNamedCookies(Ns_DStringTcl_DString *dest, const Ns_Set *hdrs, |
48 | const char *setName, const char *name) |
49 | NS_GNUC_NONNULL(1)__attribute__((__nonnull__(1))) NS_GNUC_NONNULL(2)__attribute__((__nonnull__(2))) NS_GNUC_NONNULL(3)__attribute__((__nonnull__(3))) NS_GNUC_NONNULL(4)__attribute__((__nonnull__(4))); |
50 | |
51 | static bool_Bool DeleteNamedCookies(Ns_Set *hdrs, const char *setName, |
52 | const char *name) |
53 | NS_GNUC_NONNULL(1)__attribute__((__nonnull__(1))) NS_GNUC_NONNULL(2)__attribute__((__nonnull__(2))) NS_GNUC_NONNULL(3)__attribute__((__nonnull__(3))); |
54 | |
55 | |
56 | typedef char* (CookieParser)(Ns_DStringTcl_DString *dest, char *chars, const char *name, |
57 | size_t nameLen, char **nextPtr) |
58 | NS_GNUC_NONNULL(2)__attribute__((__nonnull__(2))) NS_GNUC_NONNULL(3)__attribute__((__nonnull__(3))); |
59 | |
60 | static CookieParser GetFromCookieHeader; |
61 | static CookieParser GetFromSetCookieHeader; |
62 | |
63 | static char *CopyCookieValue(Tcl_DString *dest, char *valueStart) |
64 | NS_GNUC_NONNULL(1)__attribute__((__nonnull__(1))) NS_GNUC_NONNULL(2)__attribute__((__nonnull__(2))); |
65 | |
66 | static Ns_ObjvTable samesiteValues[] = { |
67 | {"strict", UCHAR('s')((unsigned char)('s'))}, |
68 | {"lax", UCHAR('l')((unsigned char)('l'))}, |
69 | {"none", UCHAR('n')((unsigned char)('n'))}, |
70 | {NULL((void*)0), 0u} |
71 | }; |
72 | |
73 | |
74 | |
75 | /* |
76 | *---------------------------------------------------------------------- |
77 | * |
78 | * CopyCookieValue -- |
79 | * |
80 | * Copy the CookieValue into the provided Tcl_DString |
81 | * |
82 | * Results: |
83 | * None |
84 | * |
85 | * Side effects: |
86 | * Append to provided Tcl_DString |
87 | * |
88 | *---------------------------------------------------------------------- |
89 | */ |
90 | |
91 | static char * |
92 | CopyCookieValue(Tcl_DString *dest, char *valueStart) |
93 | { |
94 | char save, *q; |
95 | |
96 | NS_NONNULL_ASSERT(dest != NULL)((void) (0)); |
97 | NS_NONNULL_ASSERT(valueStart != NULL)((void) (0)); |
98 | |
99 | if (*valueStart == '"') { |
100 | /* |
101 | * Advance past optional quote. |
102 | */ |
103 | ++valueStart; |
104 | } |
105 | q = valueStart; |
106 | while (*q != '"' && *q != ';' && *q != '\0') { |
107 | ++q; |
108 | } |
109 | save = *q; |
110 | *q = '\0'; |
111 | Ns_CookieDecode(dest, valueStart, NULL((void*)0)); |
112 | *q = save; |
113 | |
114 | /* |
115 | * Advance past delimiter. |
116 | */ |
117 | while (*q == '"' || *q == ';') { |
118 | q++; |
119 | } |
120 | |
121 | return q; |
122 | } |
123 | |
124 | |
125 | /* |
126 | *---------------------------------------------------------------------- |
127 | * |
128 | * GetFromCookieHeader -- |
129 | * |
130 | * Get a cookie from the cookie header. The cookie header field has a |
131 | * content of the form: |
132 | * |
133 | * cookie1="value1"; cookie2="value2"; style=null; ... |
134 | * |
135 | * so we have to iterate over the cookie/value pairs separated with |
136 | * semicolons. |
137 | * |
138 | * Results: |
139 | * On success a non-null value pointing the begin of the found |
140 | * cookie such we can iterate to search for more cookies with the same |
141 | * name |
142 | * |
143 | * Side effects: |
144 | * When Tcl_DString dest is provided, the value of the cookie is |
145 | * appended to the DString. |
146 | * |
147 | *---------------------------------------------------------------------- |
148 | */ |
149 | |
150 | static char * |
151 | GetFromCookieHeader(Ns_DStringTcl_DString *dest, char *chars, const char *name, |
152 | size_t nameLen, char **nextPtr) |
153 | { |
154 | char *cookieStart = NULL((void*)0), *toParse = chars; |
155 | |
156 | NS_NONNULL_ASSERT(chars != NULL)((void) (0)); |
157 | NS_NONNULL_ASSERT(name != NULL)((void) (0)); |
158 | |
159 | for ( ; likely(*toParse != '\0')(__builtin_expect((*toParse != '\0'), 1)); ) { |
160 | /* |
161 | * Skip optional white space. |
162 | */ |
163 | for (; (CHARTYPE(space, *toParse)(((*__ctype_b_loc ())[(int) (((int)((unsigned char)(*toParse) )))] & (unsigned short int) _ISspace)) != 0); toParse++) { |
164 | } |
165 | if (*toParse == '\0') { |
166 | break; |
167 | } |
168 | |
169 | if (strncmp(toParse, name, nameLen) == 0) { |
170 | char *q = toParse + nameLen; |
171 | |
172 | /* |
173 | * Name starts correctly |
174 | */ |
175 | if (likely(*q == '=')(__builtin_expect((*q == '='), 1))) { |
176 | /* |
177 | * Full match, we found the cookie |
178 | */ |
179 | cookieStart = toParse; |
180 | q++; /* advance past equals sign */ |
181 | if (dest != NULL((void*)0)) { |
182 | q = CopyCookieValue(dest, q); |
183 | } |
184 | toParse = q; |
185 | break; |
186 | } |
187 | } |
188 | /* |
189 | * Look for the next semicolon |
190 | */ |
191 | for (; (*toParse != '\0') && (*toParse != ';'); toParse++) { |
192 | ; |
193 | } |
194 | if (*toParse == ';') { |
195 | /* |
196 | * We found a semicolon and skip it; |
197 | */ |
198 | toParse++; |
199 | } |
200 | } |
201 | |
202 | if (nextPtr != NULL((void*)0)) { |
203 | *nextPtr = toParse; |
204 | } |
205 | |
206 | return cookieStart; |
207 | } |
208 | |
209 | |
210 | /* |
211 | *---------------------------------------------------------------------- |
212 | * |
213 | * GetFromSetCookieHeader -- |
214 | * |
215 | * Get a cookie from the set-cookie header. The set-cookie header field |
216 | * has a content of the form: |
217 | * |
218 | * cookie1="new-value"; Expires=Fri, 01-Jan-2035 01:00:00 GMT; Path=/; HttpOnly |
219 | * |
220 | * In order to get the cookie-value, the entry has to start with a |
221 | * name/value pair. |
222 | * |
223 | * Results: |
224 | * On success a non-null value pointing the begin of the found |
225 | * cookie |
226 | * |
227 | * Side effects: |
228 | * When Tcl_DString dest is provided, the value of the cookie is |
229 | * appended to the DString. |
230 | * |
231 | *---------------------------------------------------------------------- |
232 | */ |
233 | |
234 | static char * |
235 | GetFromSetCookieHeader(Ns_DStringTcl_DString *dest, char *chars, const char *name, |
236 | size_t nameLen, char **nextPtr) { |
237 | char *cookieStart = NULL((void*)0), *toParse = chars; |
238 | |
239 | NS_NONNULL_ASSERT(chars != NULL)((void) (0)); |
240 | NS_NONNULL_ASSERT(name != NULL)((void) (0)); |
241 | |
242 | /* |
243 | * Skip white space (should not be needed). |
244 | */ |
245 | for (; (CHARTYPE(space, *toParse)(((*__ctype_b_loc ())[(int) (((int)((unsigned char)(*toParse) )))] & (unsigned short int) _ISspace)) != 0); toParse++) { |
246 | ; |
247 | } |
248 | if (strncmp(toParse, name, nameLen) == 0) { |
249 | char *q = toParse + nameLen; |
250 | |
251 | /* |
252 | * Name starts correctly |
253 | */ |
254 | |
255 | if (*q == '=') { |
256 | /* |
257 | * Full match, we found the cookie |
258 | */ |
259 | cookieStart = toParse; |
260 | q++; /* advance past equals sign */ |
261 | if (dest != NULL((void*)0)) { |
262 | q = CopyCookieValue(dest, q); |
263 | } |
264 | toParse = q; |
265 | } |
266 | } |
267 | if (nextPtr != NULL((void*)0)) { |
268 | *nextPtr = toParse; |
269 | } |
270 | |
271 | return cookieStart; |
272 | } |
273 | |
274 | |
275 | /* |
276 | *---------------------------------------------------------------------- |
277 | * |
278 | * GetFirstNamedCookie -- |
279 | * |
280 | * Search for a cookie with the given name in the given set and |
281 | * return the first hit. |
282 | * |
283 | * Results: |
284 | * index value on success, or -1 |
285 | * |
286 | * Side effects: |
287 | * when NsString dest is provided, the value of the cookie is |
288 | * appended to the DString. |
289 | * |
290 | *---------------------------------------------------------------------- |
291 | */ |
292 | |
293 | static int |
294 | GetFirstNamedCookie(Ns_DStringTcl_DString *dest, const Ns_Set *hdrs, const char *setName, |
295 | const char *name) |
296 | { |
297 | int idx = -1; |
298 | size_t nameLen, i; |
299 | CookieParser *cookieParser; |
300 | |
301 | NS_NONNULL_ASSERT(hdrs != NULL)((void) (0)); |
302 | NS_NONNULL_ASSERT(setName != NULL)((void) (0)); |
303 | NS_NONNULL_ASSERT(name != NULL)((void) (0)); |
304 | |
305 | nameLen = strlen(name); |
306 | |
307 | cookieParser = (*setName == 'c') |
308 | ? GetFromCookieHeader |
309 | : GetFromSetCookieHeader; |
310 | |
311 | for (i = 0u; i < hdrs->size; ++i) { |
312 | if (strcasecmp(hdrs->fields[i].name, setName) == 0) { |
313 | /* |
314 | * We have the right header. |
315 | */ |
316 | if ((*cookieParser)(dest, hdrs->fields[i].value, name, |
317 | nameLen, NULL((void*)0)) != NULL((void*)0)) { |
318 | /* |
319 | * We found the result. |
320 | */ |
321 | idx = (int) i; |
322 | break; |
323 | } |
324 | } |
325 | } |
326 | |
327 | return idx; |
328 | } |
329 | |
330 | /* |
331 | *---------------------------------------------------------------------- |
332 | * |
333 | * GetAllNamedCookies -- |
334 | * |
335 | * Search for a cookie with the given name in the given set and |
336 | * return all hits. |
337 | * |
338 | * Results: |
339 | * Number of cookies with the given name |
340 | * |
341 | * Side effects: |
342 | * Update the first argument with a list of cookie values |
343 | * |
344 | *---------------------------------------------------------------------- |
345 | */ |
346 | static int |
347 | GetAllNamedCookies(Ns_DStringTcl_DString *dest, const Ns_Set *hdrs, const char *setName, |
348 | const char *name) |
349 | { |
350 | int count = 0; |
351 | size_t nameLen, i; |
352 | CookieParser *cookieParser; |
353 | |
354 | NS_NONNULL_ASSERT(dest != NULL)((void) (0)); |
355 | NS_NONNULL_ASSERT(hdrs != NULL)((void) (0)); |
356 | NS_NONNULL_ASSERT(setName != NULL)((void) (0)); |
357 | NS_NONNULL_ASSERT(name != NULL)((void) (0)); |
358 | |
359 | nameLen = strlen(name); |
360 | cookieParser = (*setName == 'c') |
361 | ? GetFromCookieHeader |
362 | : GetFromSetCookieHeader; |
363 | |
364 | for (i = 0u; i < hdrs->size; i++) { |
365 | if (strcasecmp(hdrs->fields[i].name, setName) == 0) { |
366 | char *toParse; |
367 | |
368 | /* |
369 | * We have the right header, parse the string; |
370 | */ |
371 | for (toParse = hdrs->fields[i].value; *toParse != '\0'; ) { |
372 | Ns_DStringTcl_DString cookie; |
373 | |
374 | Ns_DStringInitTcl_DStringInit(&cookie); |
375 | if ((*cookieParser)(&cookie, toParse, name, nameLen, |
376 | &toParse) != NULL((void*)0)) { |
377 | /* |
378 | * We found the named cookie; |
379 | */ |
380 | count ++; |
381 | Tcl_DStringAppendElement(dest, cookie.string); |
382 | } |
383 | Ns_DStringFreeTcl_DStringFree(&cookie); |
384 | } |
385 | break; |
386 | } |
387 | } |
388 | |
389 | return count; |
390 | } |
391 | |
392 | |
393 | /* |
394 | *---------------------------------------------------------------------- |
395 | * |
396 | * DeleteNamedCookies -- |
397 | * |
398 | * Delete all cookies with the specified name form the given set. |
399 | * |
400 | * Results: |
401 | * Boolean value. |
402 | * |
403 | * Side effects: |
404 | * Delete nsset entry. |
405 | * |
406 | *---------------------------------------------------------------------- |
407 | */ |
408 | |
409 | static bool_Bool |
410 | DeleteNamedCookies(Ns_Set *hdrs, const char *setName, const char *name) |
411 | { |
412 | bool_Bool success = NS_FALSE0; |
413 | |
414 | NS_NONNULL_ASSERT(hdrs != NULL)((void) (0)); |
415 | NS_NONNULL_ASSERT(setName != NULL)((void) (0)); |
416 | NS_NONNULL_ASSERT(name != NULL)((void) (0)); |
417 | |
418 | for (;;) { |
419 | int idx = GetFirstNamedCookie(NULL((void*)0), hdrs, setName, name); |
420 | if (idx != -1) { |
421 | Ns_SetDelete(hdrs, idx); |
422 | success = NS_TRUE1; |
423 | } else { |
424 | break; |
425 | } |
426 | } |
427 | return success; |
428 | } |
429 | |
430 | |
431 | /* |
432 | *---------------------------------------------------------------------- |
433 | * |
434 | * Ns_ConnSetCookie, Ns_ConnSetCookieEx, Ns_ConnSetSecureCookie -- |
435 | * |
436 | * Set a cookie for the given connection. |
437 | * |
438 | * Results: |
439 | * None. |
440 | * |
441 | * Side effects: |
442 | * Existing cookie with same name, path, domain will be dropped |
443 | * by client. |
444 | * |
445 | *---------------------------------------------------------------------- |
446 | */ |
447 | |
448 | void |
449 | Ns_ConnSetCookieEx(const Ns_Conn *conn, const char *name, const char *value, |
450 | time_t maxage, const char *domain, const char *path, |
451 | unsigned int flags) |
452 | { |
453 | Ns_DStringTcl_DString cookie; |
454 | |
455 | NS_NONNULL_ASSERT(conn != NULL)((void) (0)); |
456 | NS_NONNULL_ASSERT(name != NULL)((void) (0)); |
457 | |
458 | if ((flags & NS_COOKIE_REPLACE0x08u) != 0u) { |
459 | (void)DeleteNamedCookies(Ns_ConnOutputHeaders(conn), "set-cookie", |
460 | name); |
461 | } |
462 | |
463 | Ns_DStringInitTcl_DStringInit(&cookie); |
464 | Ns_DStringVarAppend(&cookie, name, "=\"", (char *)0L); |
465 | if (value != NULL((void*)0)) { |
466 | Ns_CookieEncode(&cookie, value, NULL((void*)0)); |
467 | } |
468 | Ns_DStringAppend(&cookie, "\"")Tcl_DStringAppend((&cookie), ("\""), -1); |
469 | if ((flags & NS_COOKIE_EXPIRENOW0x10u) != 0u) { |
470 | Ns_DStringAppend(&cookie, "; Expires=Fri, 01-Jan-1980 01:00:00 GMT")Tcl_DStringAppend((&cookie), ("; Expires=Fri, 01-Jan-1980 01:00:00 GMT" ), -1); |
471 | } else if (maxage == TIME_T_MAX9223372036854775807L) { |
472 | Ns_DStringAppend(&cookie, "; Expires=Fri, 01-Jan-2035 01:00:00 GMT")Tcl_DStringAppend((&cookie), ("; Expires=Fri, 01-Jan-2035 01:00:00 GMT" ), -1); |
473 | } else if (maxage > 0) { |
474 | Ns_DStringPrintf(&cookie, "; Max-Age=%" PRId64"l" "d", (int64_t)maxage); |
475 | } else { |
476 | /* |
477 | * maxage == 0, don't specify any expiry |
478 | */ |
479 | } |
480 | /* ignore empty domain, since IE rejects it */ |
481 | if (domain != NULL((void*)0) && *domain != '\0') { |
482 | Ns_DStringVarAppend(&cookie, "; Domain=", domain, (char *)0L); |
483 | } |
484 | if (path != NULL((void*)0)) { |
485 | Ns_DStringVarAppend(&cookie, "; Path=", path, (char *)0L); |
486 | } |
487 | if ((flags & NS_COOKIE_SECURE0x01u) != 0u) { |
488 | Ns_DStringAppend(&cookie, "; Secure")Tcl_DStringAppend((&cookie), ("; Secure"), -1); |
489 | } |
490 | if ((flags & NS_COOKIE_DISCARD0x04u) != 0u) { |
491 | Ns_DStringAppend(&cookie, "; Discard")Tcl_DStringAppend((&cookie), ("; Discard"), -1); |
492 | } |
493 | if ((flags & NS_COOKIE_SCRIPTABLE0x02u) == 0u) { |
494 | Ns_DStringAppend(&cookie, "; HttpOnly")Tcl_DStringAppend((&cookie), ("; HttpOnly"), -1); |
495 | } |
496 | |
497 | if ((flags & NS_COOKIE_SAMESITE_STRICT0x20u) != 0u) { |
498 | Ns_DStringAppend(&cookie, "; SameSite=Strict")Tcl_DStringAppend((&cookie), ("; SameSite=Strict"), -1); |
499 | } else if ((flags & NS_COOKIE_SAMESITE_LAX0x40u) != 0u) { |
500 | Ns_DStringAppend(&cookie, "; SameSite=Lax")Tcl_DStringAppend((&cookie), ("; SameSite=Lax"), -1); |
501 | } else if ((flags & NS_COOKIE_SAMESITE_NONE0x80u) != 0u) { |
502 | Ns_DStringAppend(&cookie, "; SameSite=None")Tcl_DStringAppend((&cookie), ("; SameSite=None"), -1); |
503 | } |
504 | |
505 | |
506 | Ns_ConnSetHeaders(conn, "Set-Cookie", cookie.string); |
507 | Ns_DStringFreeTcl_DStringFree(&cookie); |
508 | } |
509 | |
510 | void |
511 | Ns_ConnSetCookie(const Ns_Conn *conn, const char *name, const char *value, |
512 | time_t maxage) |
513 | { |
514 | NS_NONNULL_ASSERT(conn != NULL)((void) (0)); |
515 | NS_NONNULL_ASSERT(name != NULL)((void) (0)); |
516 | |
517 | Ns_ConnSetCookieEx(conn, name, value, maxage, NULL((void*)0), NULL((void*)0), 0u); |
518 | } |
519 | |
520 | void |
521 | Ns_ConnSetSecureCookie(const Ns_Conn *conn, const char *name, const char *value, |
522 | time_t maxage) |
523 | { |
524 | NS_NONNULL_ASSERT(conn != NULL)((void) (0)); |
525 | NS_NONNULL_ASSERT(name != NULL)((void) (0)); |
526 | |
527 | Ns_ConnSetCookieEx(conn, name, value, maxage, NULL((void*)0), NULL((void*)0), NS_COOKIE_SECURE0x01u); |
528 | } |
529 | |
530 | |
531 | /* |
532 | *---------------------------------------------------------------------- |
533 | * |
534 | * Ns_ConnDeleteCookie, Ns_ConnDeleteSecureCookie -- |
535 | * |
536 | * Expire immediately the cookie with matching name, domain and path. |
537 | * |
538 | * Results: |
539 | * None. |
540 | * |
541 | * Side effects: |
542 | * None. |
543 | * |
544 | *---------------------------------------------------------------------- |
545 | */ |
546 | |
547 | void |
548 | Ns_ConnDeleteCookie(const Ns_Conn *conn, const char *name, const char *domain, |
549 | const char *path) |
550 | { |
551 | NS_NONNULL_ASSERT(conn != NULL)((void) (0)); |
552 | NS_NONNULL_ASSERT(name != NULL)((void) (0)); |
553 | |
554 | Ns_ConnSetCookieEx(conn, name, NULL((void*)0), (time_t)0, domain, path, |
555 | NS_COOKIE_EXPIRENOW0x10u); |
556 | } |
557 | |
558 | void |
559 | Ns_ConnDeleteSecureCookie(const Ns_Conn *conn, const char *name, |
560 | const char *domain, const char *path) |
561 | { |
562 | NS_NONNULL_ASSERT(conn != NULL)((void) (0)); |
563 | NS_NONNULL_ASSERT(name != NULL)((void) (0)); |
564 | |
565 | Ns_ConnSetCookieEx(conn, name, NULL((void*)0), (time_t)0, domain, path, |
566 | NS_COOKIE_EXPIRENOW0x10u|NS_COOKIE_SECURE0x01u); |
567 | } |
568 | |
569 | |
570 | /* |
571 | *---------------------------------------------------------------------- |
572 | * |
573 | * Ns_ConnGetCookie -- |
574 | * |
575 | * Get first matching cookie for the given connection. |
576 | * |
577 | * Results: |
578 | * dest->string or NULL on error. |
579 | * |
580 | * Side effects: |
581 | * Cookie value is CookieDecoded before placement in dest. |
582 | * |
583 | *---------------------------------------------------------------------- |
584 | */ |
585 | |
586 | const char * |
587 | Ns_ConnGetCookie(Ns_DStringTcl_DString *dest, const Ns_Conn *conn, const char *name) |
588 | { |
589 | int idx; |
590 | |
591 | NS_NONNULL_ASSERT(dest != NULL)((void) (0)); |
592 | NS_NONNULL_ASSERT(conn != NULL)((void) (0)); |
593 | NS_NONNULL_ASSERT(name != NULL)((void) (0)); |
594 | |
595 | idx = GetFirstNamedCookie(dest, Ns_ConnHeaders(conn), "cookie", name); |
596 | |
597 | return idx != -1 ? Ns_DStringValue(dest)((dest)->string) : NULL((void*)0); |
598 | } |
599 | |
600 | |
601 | |
602 | /* |
603 | *---------------------------------------------------------------------- |
604 | * |
605 | * NsTclSetCookieObjCmd -- |
606 | * |
607 | * Implements "ns_setcookie". |
608 | * |
609 | * Results: |
610 | * Tcl result. |
611 | * |
612 | * Side effects: |
613 | * None. |
614 | * |
615 | *---------------------------------------------------------------------- |
616 | */ |
617 | |
618 | int |
619 | NsTclSetCookieObjCmd(ClientData UNUSED(clientData)UNUSED_clientData __attribute__((__unused__)), Tcl_Interp *interp, |
620 | int objc, Tcl_Obj *const* objv) |
621 | { |
622 | Ns_Conn *conn; |
623 | char *name, *data, *domain = NULL((void*)0), *path = NULL((void*)0); |
624 | int secure = 0, scriptable = 0, discard = 0, replace = 0, result; |
625 | int samesite = INTCHAR('l')((int)((unsigned char)(('l')))); |
626 | Ns_Time *expiresPtr = NULL((void*)0); |
627 | Ns_ObjvSpec opts[] = { |
628 | {"-discard", Ns_ObjvBool, &discard, NULL((void*)0)}, |
629 | {"-domain", Ns_ObjvString, &domain, NULL((void*)0)}, |
630 | {"-expires", Ns_ObjvTime, &expiresPtr, NULL((void*)0)}, |
631 | {"-path", Ns_ObjvString, &path, NULL((void*)0)}, |
632 | {"-replace", Ns_ObjvBool, &replace, NULL((void*)0)}, |
633 | {"-samesite", Ns_ObjvIndex, &samesite, samesiteValues}, |
634 | {"-scriptable", Ns_ObjvBool, &scriptable, NULL((void*)0)}, |
635 | {"-secure", Ns_ObjvBool, &secure, NULL((void*)0)}, |
636 | {"--", Ns_ObjvBreak, NULL((void*)0), NULL((void*)0)}, |
637 | {NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0)} |
638 | }; |
639 | Ns_ObjvSpec args[] = { |
640 | {"name", Ns_ObjvString, &name, NULL((void*)0)}, |
641 | {"data", Ns_ObjvString, &data, NULL((void*)0)}, |
642 | {NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0)} |
643 | }; |
644 | |
645 | if (Ns_ParseObjv(opts, args, interp, 1, objc, objv) != NS_OK |
646 | || NsConnRequire(interp, NS_CONN_REQUIRE_CONFIGURED0x0004u, &conn) != NS_OK) { |
647 | result = TCL_ERROR1; |
648 | |
649 | } else { |
650 | unsigned int flags = 0u; |
651 | time_t maxage; |
652 | |
653 | if (secure != 0) { |
654 | flags |= NS_COOKIE_SECURE0x01u; |
655 | } |
656 | if (scriptable != 0) { |
657 | flags |= NS_COOKIE_SCRIPTABLE0x02u; |
658 | } |
659 | if (discard != 0) { |
660 | flags |= NS_COOKIE_DISCARD0x04u; |
661 | } |
662 | if (replace != 0) { |
663 | flags |= NS_COOKIE_REPLACE0x08u; |
664 | } |
665 | /* |
666 | * If "-samesite none" flag was provided, and secure was not set, fall |
667 | * back to "-samesite lax" and complain. |
668 | */ |
669 | if (samesite == INTCHAR('n')((int)((unsigned char)(('n')))) && secure == 0) { |
Duplicate code detected | |
670 | Ns_Log(Warning, "cookie '%s': trying to set '-samesite none' " |
671 | "without the '-secure' flag. Fall back to -samesite lax", name); |
672 | samesite = INTCHAR('l')((int)((unsigned char)(('l')))); |
673 | } |
674 | if (samesite == INTCHAR('s')((int)((unsigned char)(('s'))))) { |
675 | flags |= NS_COOKIE_SAMESITE_STRICT0x20u; |
676 | } else if (samesite == INTCHAR('l')((int)((unsigned char)(('l'))))) { |
677 | flags |= NS_COOKIE_SAMESITE_LAX0x40u; |
678 | } else if (samesite == INTCHAR('n')((int)((unsigned char)(('n'))))) { |
679 | flags |= NS_COOKIE_SAMESITE_NONE0x80u; |
680 | } |
681 | |
682 | /* |
683 | * Accept expiry time as relative or absolute and adjust to the relative |
684 | * time Ns_ConnSetCookieEx expects, taking account of the special value |
685 | * -1 which is short hand for infinite. |
686 | */ |
687 | |
688 | if (expiresPtr != NULL((void*)0)) { |
689 | /* |
690 | * The start time is close enough to "now" |
691 | */ |
692 | const Ns_Time *nowPtr = Ns_ConnStartTime(conn); |
693 | if (expiresPtr->sec < 0) { |
694 | maxage = TIME_T_MAX9223372036854775807L; |
695 | } else if (expiresPtr->sec > nowPtr->sec) { |
696 | maxage = (time_t)expiresPtr->sec - (time_t)nowPtr->sec; |
697 | } else { |
698 | maxage = expiresPtr->sec; |
699 | } |
700 | } else { |
701 | maxage = 0; |
702 | } |
703 | |
704 | Ns_ConnSetCookieEx(conn, name, data, maxage, domain, path, flags); |
705 | result = TCL_OK0; |
706 | } |
707 | |
708 | return result; |
709 | } |
710 | |
711 | |
712 | /* |
713 | *---------------------------------------------------------------------- |
714 | * |
715 | * NsTclGetCookieObjCmd -- |
716 | * |
717 | * Implements "ns_getcookie". The given default will be |
718 | * returned if no matching cookie exists. |
719 | * |
720 | * Results: |
721 | * Tcl result. |
722 | * |
723 | * Side effects: |
724 | * None. |
725 | * |
726 | *---------------------------------------------------------------------- |
727 | */ |
728 | |
729 | int |
730 | NsTclGetCookieObjCmd(ClientData UNUSED(clientData)UNUSED_clientData __attribute__((__unused__)), Tcl_Interp *interp, |
731 | int objc, Tcl_Obj *const* objv) |
732 | { |
733 | Ns_Conn *conn; |
734 | char *nameString; |
735 | Tcl_Obj *defaultObj = NULL((void*)0); |
736 | int status = TCL_OK0; |
737 | int withSetCookies = (int)NS_FALSE0, withAll = (int)NS_FALSE0; |
738 | |
739 | Ns_ObjvSpec opts[] = { |
740 | {"-all", Ns_ObjvBool, &withAll, NULL((void*)0)}, |
741 | {"-include_set_cookies", Ns_ObjvBool, &withSetCookies, NULL((void*)0)}, |
742 | {"--", Ns_ObjvBreak, NULL((void*)0), NULL((void*)0)}, |
743 | {NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0)} |
744 | }; |
745 | Ns_ObjvSpec args[] = { |
746 | {"name", Ns_ObjvString, &nameString, NULL((void*)0)}, |
747 | {"?default", Ns_ObjvObj, &defaultObj, NULL((void*)0)}, |
748 | {NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0)} |
749 | }; |
750 | |
751 | if (Ns_ParseObjv(opts, args, interp, 1, objc, objv) != NS_OK |
752 | || NsConnRequire(interp, NS_CONN_REQUIRE_CONFIGURED0x0004u, &conn) != NS_OK) { |
753 | status = TCL_ERROR1; |
754 | |
755 | } else if (withSetCookies == (int)NS_TRUE1 && withAll == (int)NS_TRUE1) { |
756 | Ns_TclPrintfResult(interp, "%s", "invalid combination of flags -include_set_cookies and -all"); |
757 | status = TCL_ERROR1; |
758 | |
759 | } else { |
760 | Ns_DStringTcl_DString ds; |
761 | int idx = -1; |
762 | |
763 | Ns_DStringInitTcl_DStringInit(&ds); |
764 | |
765 | if (withAll == (int)NS_TRUE1) { |
766 | idx = GetAllNamedCookies(&ds, Ns_ConnHeaders(conn), |
767 | "cookie", nameString); |
768 | |
769 | } else { |
770 | if (withSetCookies == (int)NS_TRUE1) { |
771 | idx = GetFirstNamedCookie(&ds, Ns_ConnOutputHeaders(conn), |
772 | "set-cookie", nameString); |
773 | } |
774 | if (idx == -1) { |
775 | idx = GetFirstNamedCookie(&ds, Ns_ConnHeaders(conn), |
776 | "cookie", nameString); |
777 | } |
778 | } |
779 | |
780 | if (idx != -1) { |
781 | Tcl_DStringResult(interp, &ds); |
782 | } else if (defaultObj != NULL((void*)0)) { |
783 | Tcl_SetObjResult(interp, defaultObj); |
784 | } else { |
785 | Tcl_SetObjResult(interp, Tcl_NewStringObj("no such cookie", -1)); |
786 | status = TCL_ERROR1; |
787 | } |
788 | Ns_DStringFreeTcl_DStringFree(&ds); |
789 | } |
790 | |
791 | return status; |
792 | } |
793 | |
794 | |
795 | /* |
796 | *---------------------------------------------------------------------- |
797 | * |
798 | * NsTclDeleteCookieObjCmd -- |
799 | * |
800 | * Implements "ns_deletecookie". |
801 | * |
802 | * Results: |
803 | * Tcl result. |
804 | * |
805 | * Side effects: |
806 | * See Ns_ConnDeleteCookie(). |
807 | * |
808 | *---------------------------------------------------------------------- |
809 | */ |
810 | |
811 | int |
812 | NsTclDeleteCookieObjCmd(ClientData UNUSED(clientData)UNUSED_clientData __attribute__((__unused__)), Tcl_Interp *interp, |
813 | int objc, Tcl_Obj *const* objv) |
814 | { |
815 | Ns_Conn *conn; |
816 | char *name, *domain = NULL((void*)0), *path = NULL((void*)0); |
817 | int secure = 0, replace = 0, result; |
818 | int samesite = INTCHAR('l')((int)((unsigned char)(('l')))); |
819 | Ns_ObjvSpec opts[] = { |
820 | {"-domain", Ns_ObjvString, &domain, NULL((void*)0)}, |
821 | {"-path", Ns_ObjvString, &path, NULL((void*)0)}, |
822 | {"-replace", Ns_ObjvBool, &replace, NULL((void*)0)}, |
823 | {"-samesite",Ns_ObjvIndex, &samesite, samesiteValues}, |
824 | {"-secure", Ns_ObjvBool, &secure, NULL((void*)0)}, |
825 | {"--", Ns_ObjvBreak, NULL((void*)0), NULL((void*)0)}, |
826 | {NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0)} |
827 | }; |
828 | Ns_ObjvSpec args[] = { |
829 | {"name", Ns_ObjvString, &name, NULL((void*)0)}, |
830 | {NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0)} |
831 | }; |
832 | |
833 | if (Ns_ParseObjv(opts, args, interp, 1, objc, objv) != NS_OK |
834 | || NsConnRequire(interp, NS_CONN_REQUIRE_CONFIGURED0x0004u, &conn) != NS_OK) { |
835 | result = TCL_ERROR1; |
836 | |
837 | } else { |
838 | unsigned int flags = 0u; |
839 | |
840 | if (replace != 0) { |
841 | flags |= NS_COOKIE_REPLACE0x08u; |
842 | } |
843 | if (secure != 0) { |
844 | flags |= NS_COOKIE_SECURE0x01u; |
845 | } |
846 | |
847 | /* |
848 | * If "-samesite none" flag was provided, and secure was not set, fall |
849 | * back to "-samesite lax" and complain. |
850 | */ |
851 | if (samesite == INTCHAR('n')((int)((unsigned char)(('n')))) && secure == 0) { |
Similar code here | |
852 | Ns_Log(Warning, "cookie '%s': trying to set '-samesite none' " |
853 | "without the '-secure' flag. Fall back to -samesite lax", name); |
854 | samesite = INTCHAR('l')((int)((unsigned char)(('l')))); |
855 | } |
856 | |
857 | if (samesite == INTCHAR('s')((int)((unsigned char)(('s'))))) { |
858 | flags |= NS_COOKIE_SAMESITE_STRICT0x20u; |
859 | } else if (samesite == INTCHAR('l')((int)((unsigned char)(('l'))))) { |
860 | flags |= NS_COOKIE_SAMESITE_LAX0x40u; |
861 | } else if (samesite == INTCHAR('n')((int)((unsigned char)(('n'))))) { |
862 | flags |= NS_COOKIE_SAMESITE_NONE0x80u; |
863 | } |
864 | |
865 | Ns_ConnSetCookieEx(conn, name, NULL((void*)0), (time_t)0, domain, path, |
866 | NS_COOKIE_EXPIRENOW0x10u|flags); |
867 | result = TCL_OK0; |
868 | } |
869 | |
870 | return result; |
871 | } |
872 | |
873 | /* |
874 | * Local Variables: |
875 | * mode: c |
876 | * c-basic-offset: 4 |
877 | * fill-column: 78 |
878 | * indent-tabs-mode: nil |
879 | * End: |
880 | */ |