Nilorea Library
C utilities for networking, threading, graphics
Loading...
Searching...
No Matches
ex_cookies.c
Go to the documentation of this file.
1/*
2 * Nilorea Library
3 * Copyright (C) 2005-2026 Castagnier Mickael
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * 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
14 * implied. See the License for the specific language governing
15 * permissions and limitations under the License.
16 *
17 * SPDX-License-Identifier: Apache-2.0
18 */
19
27#include "nilorea/n_common.h"
28#include "nilorea/n_cookies.h"
29#include "nilorea/n_log.h"
30#include "nilorea/n_str.h"
31
32#include <stdio.h>
33#include <string.h>
34
35static int failures = 0;
36
37/* Parse the -V LOG_LEVEL verbosity argument. */
38void process_args(int argc, char** argv) {
39 int opt = 0;
40 while ((opt = getopt(argc, argv, "hvV:")) != EOF) {
41 switch (opt) {
42 case 'V':
43 if (!strncmp("LOG_NULL", optarg, 8))
45 else if (!strncmp("LOG_NOTICE", optarg, 10))
47 else if (!strncmp("LOG_INFO", optarg, 8))
49 else if (!strncmp("LOG_ERR", optarg, 7))
51 else if (!strncmp("LOG_DEBUG", optarg, 9))
53 else {
54 fprintf(stderr, "Unknown log level %s\n", optarg);
55 exit(1);
56 }
57 break;
58 case 'v':
59 fprintf(stderr, "ex_cookies\n");
60 exit(1);
61 case 'h':
62 default:
63 fprintf(stderr, "usage: %s [-V LOG_LEVEL]\n", argv[0]);
64 break;
65 }
66 }
67}
68
69/* Does the built header contain the substring (NULL header counts as no)? */
70static int hdr_has(N_STR* h, const char* needle) {
71 return h && h->data && strstr(h->data, needle) != NULL;
72}
73
74int main(int argc, char** argv) {
75 N_COOKIE_JAR* jar;
76 N_STR* h;
78 process_args(argc, argv);
79
80 jar = n_cookiejar_new();
81 if (!jar) {
82 n_log(LOG_ERR, "jar alloc failed");
83 return 1;
84 }
85
86 n_cookiejar_add_from_header(jar, "sid=abc; Path=/; Domain=example.com", "example.com");
87 n_cookiejar_add_from_header(jar, "token=xyz; Secure", "example.com");
88 n_cookiejar_add_from_header(jar, "sub=1; Domain=.example.com", "example.com");
89 n_cookiejar_add_from_header(jar, "adm=1; Path=/admin", "example.com");
90 n_cookiejar_add_from_header(jar, "old=1; Max-Age=-100", "example.com"); /* already expired */
91 if (n_cookiejar_count(jar) != 5) {
92 n_log(LOG_ERR, "expected 5 cookies, got %zu", n_cookiejar_count(jar));
93 failures++;
94 }
95
96 /* http request to / : sid + sub, not the Secure token, not the /admin cookie,
97 not the expired one */
98 h = n_cookiejar_build_header(jar, "example.com", "/", 0);
99 if (!hdr_has(h, "sid=abc") || hdr_has(h, "token=xyz") || hdr_has(h, "adm=1") || hdr_has(h, "old=1")) {
100 n_log(LOG_ERR, "http / header wrong: '%s'", h && h->data ? h->data : "(null)");
101 failures++;
102 }
103 free_nstr(&h);
104
105 /* https request: the Secure cookie is now included */
106 h = n_cookiejar_build_header(jar, "example.com", "/", 1);
107 if (!hdr_has(h, "token=xyz") || !hdr_has(h, "sid=abc")) {
108 n_log(LOG_ERR, "https header missing secure cookie: '%s'", h && h->data ? h->data : "(null)");
109 failures++;
110 }
111 free_nstr(&h);
112
113 /* the .example.com cookie matches a subdomain */
114 h = n_cookiejar_build_header(jar, "www.example.com", "/", 0);
115 if (!hdr_has(h, "sub=1")) {
116 n_log(LOG_ERR, "subdomain match failed: '%s'", h && h->data ? h->data : "(null)");
117 failures++;
118 }
119 free_nstr(&h);
120
121 /* the /admin cookie is sent only under /admin */
122 h = n_cookiejar_build_header(jar, "example.com", "/admin/panel", 0);
123 if (!hdr_has(h, "adm=1")) {
124 n_log(LOG_ERR, "path match failed: '%s'", h && h->data ? h->data : "(null)");
125 failures++;
126 }
127 free_nstr(&h);
128
129 /* an unrelated domain matches nothing */
130 h = n_cookiejar_build_header(jar, "other.test", "/", 0);
131 if (h != NULL) {
132 n_log(LOG_ERR, "unrelated domain should yield no header");
133 failures++;
134 free_nstr(&h);
135 }
136
137 /* re-Set sid: value replaced, count unchanged */
138 n_cookiejar_add_from_header(jar, "sid=NEW; Domain=example.com", "example.com");
139 if (n_cookiejar_count(jar) != 5) {
140 n_log(LOG_ERR, "replace changed count: %zu", n_cookiejar_count(jar));
141 failures++;
142 }
143 h = n_cookiejar_build_header(jar, "example.com", "/", 0);
144 if (!hdr_has(h, "sid=NEW")) {
145 n_log(LOG_ERR, "sid not replaced: '%s'", h && h->data ? h->data : "(null)");
146 failures++;
147 }
148 free_nstr(&h);
149
151 if (n_cookiejar_count(jar) != 0) {
152 n_log(LOG_ERR, "clear left %zu cookies", n_cookiejar_count(jar));
153 failures++;
154 }
155
156 n_cookiejar_free(&jar);
157 if (jar) {
158 n_log(LOG_ERR, "free did not NULL the jar");
159 failures++;
160 }
161
162 if (failures) {
163 n_log(LOG_ERR, "ex_cookies: %d failure(s)", failures);
164 return 1;
165 }
166 n_log(LOG_NOTICE, "ex_cookies: all checks passed");
167 return 0;
168}
static int failures
int main(void)
void process_args(int argc, char **argv)
Definition ex_common.c:48
static int hdr_has(N_STR *h, const char *needle)
Definition ex_cookies.c:70
#define n_log(__LEVEL__,...)
Logging function wrapper to get line and func.
Definition n_log.h:89
#define LOG_DEBUG
debug-level messages
Definition n_log.h:84
#define LOG_ERR
error conditions
Definition n_log.h:76
void set_log_level(const int log_level)
Set the global log level value ( static int LOG_LEVEL )
Definition n_log.c:121
#define LOG_NOTICE
normal but significant condition
Definition n_log.h:80
#define LOG_NULL
no log output
Definition n_log.h:46
#define LOG_INFO
informational
Definition n_log.h:82
void n_cookiejar_free(N_COOKIE_JAR **jar)
free a cookie jar and all its cookies, then NULL the pointer
Definition n_cookies.c:63
void n_cookiejar_add_from_header(N_COOKIE_JAR *jar, const char *set_cookie_value, const char *request_domain)
parse one Set-Cookie value (without the "Set-Cookie:" name) and store it; request_domain/path supply ...
Definition n_cookies.c:97
N_STR * n_cookiejar_build_header(N_COOKIE_JAR *jar, const char *domain, const char *path, int is_secure)
build a "name=value; name2=value2" Cookie header value for a request (domain/path/secure/expiry match...
Definition n_cookies.c:181
N_COOKIE_JAR * n_cookiejar_new(void)
create an empty cookie jar; free with n_cookiejar_free.
Definition n_cookies.c:49
void n_cookiejar_clear(N_COOKIE_JAR *jar)
drop every stored cookie
Definition n_cookies.c:229
size_t n_cookiejar_count(N_COOKIE_JAR *jar)
number of cookies currently stored
Definition n_cookies.c:219
a thread-safe cookie jar
Definition n_cookies.h:56
char * data
the string
Definition n_str.h:63
#define free_nstr(__ptr)
free a N_STR structure and set the pointer to NULL
Definition n_str.h:203
A box including a string and his lenght.
Definition n_str.h:61
Common headers and low-level functions & define.
Domain-aware HTTP cookie jar: Set-Cookie parsing and Cookie header building.
Generic log system.
N_STR and string function declaration.