7 #include "http_header.h"
16 /* plugin config for all request/connections */
21 buffer
*cookie_domain
;
22 unsigned int cookie_max_age
;
28 plugin_config
**config_storage
;
33 /* init the plugin data */
34 INIT_FUNC(mod_usertrack_init
) {
37 p
= calloc(1, sizeof(*p
));
42 /* detroy the plugin data */
43 FREE_FUNC(mod_usertrack_free
) {
48 if (!p
) return HANDLER_GO_ON
;
50 if (p
->config_storage
) {
52 for (i
= 0; i
< srv
->config_context
->used
; i
++) {
53 plugin_config
*s
= p
->config_storage
[i
];
55 if (NULL
== s
) continue;
57 buffer_free(s
->cookie_name
);
58 buffer_free(s
->cookie_attrs
);
59 buffer_free(s
->cookie_domain
);
63 free(p
->config_storage
);
71 /* handle plugin config and check values */
73 SETDEFAULTS_FUNC(mod_usertrack_set_defaults
) {
77 config_values_t cv
[] = {
78 { "usertrack.cookie-name", NULL
, T_CONFIG_STRING
, T_CONFIG_SCOPE_CONNECTION
}, /* 0 */
79 { "usertrack.cookie-max-age", NULL
, T_CONFIG_INT
, T_CONFIG_SCOPE_CONNECTION
}, /* 1 */
80 { "usertrack.cookie-domain", NULL
, T_CONFIG_STRING
, T_CONFIG_SCOPE_CONNECTION
}, /* 2 */
81 { "usertrack.cookie-attrs", NULL
, T_CONFIG_STRING
, T_CONFIG_SCOPE_CONNECTION
}, /* 3 */
83 { NULL
, NULL
, T_CONFIG_UNSET
, T_CONFIG_SCOPE_UNSET
}
86 if (!p
) return HANDLER_ERROR
;
88 p
->config_storage
= calloc(srv
->config_context
->used
, sizeof(plugin_config
*));
90 for (i
= 0; i
< srv
->config_context
->used
; i
++) {
91 data_config
const* config
= (data_config
const*)srv
->config_context
->data
[i
];
94 s
= calloc(1, sizeof(plugin_config
));
95 s
->cookie_name
= buffer_init();
96 s
->cookie_attrs
= buffer_init();
97 s
->cookie_domain
= buffer_init();
98 s
->cookie_max_age
= 0;
100 cv
[0].destination
= s
->cookie_name
;
101 cv
[1].destination
= &(s
->cookie_max_age
);
102 cv
[2].destination
= s
->cookie_domain
;
103 cv
[3].destination
= s
->cookie_attrs
;
105 p
->config_storage
[i
] = s
;
107 if (0 != config_insert_values_global(srv
, config
->value
, cv
, i
== 0 ? T_CONFIG_SCOPE_SERVER
: T_CONFIG_SCOPE_CONNECTION
)) {
108 return HANDLER_ERROR
;
111 if (buffer_string_is_empty(s
->cookie_name
)) {
112 buffer_copy_string_len(s
->cookie_name
, CONST_STR_LEN("TRACKID"));
114 size_t j
, len
= buffer_string_length(s
->cookie_name
);
115 for (j
= 0; j
< len
; j
++) {
116 char c
= s
->cookie_name
->ptr
[j
] | 32;
117 if (c
< 'a' || c
> 'z') {
118 log_error_write(srv
, __FILE__
, __LINE__
, "sb",
119 "invalid character in usertrack.cookie-name:",
122 return HANDLER_ERROR
;
127 if (!buffer_string_is_empty(s
->cookie_domain
)) {
128 size_t j
, len
= buffer_string_length(s
->cookie_domain
);
129 for (j
= 0; j
< len
; j
++) {
130 char c
= s
->cookie_domain
->ptr
[j
];
131 if (c
<= 32 || c
>= 127 || c
== '"' || c
== '\\') {
132 log_error_write(srv
, __FILE__
, __LINE__
, "sb",
133 "invalid character in usertrack.cookie-domain:",
136 return HANDLER_ERROR
;
142 return HANDLER_GO_ON
;
147 static int mod_usertrack_patch_connection(server
*srv
, connection
*con
, plugin_data
*p
) {
149 plugin_config
*s
= p
->config_storage
[0];
153 PATCH(cookie_domain
);
154 PATCH(cookie_max_age
);
156 /* skip the first, the global context */
157 for (i
= 1; i
< srv
->config_context
->used
; i
++) {
158 data_config
*dc
= (data_config
*)srv
->config_context
->data
[i
];
159 s
= p
->config_storage
[i
];
161 /* condition didn't match */
162 if (!config_check_cond(srv
, con
, dc
)) continue;
165 for (j
= 0; j
< dc
->value
->used
; j
++) {
166 data_unset
*du
= dc
->value
->data
[j
];
168 if (buffer_is_equal_string(du
->key
, CONST_STR_LEN("usertrack.cookie-name"))) {
170 } else if (buffer_is_equal_string(du
->key
, CONST_STR_LEN("usertrack.cookie-attrs"))) {
172 } else if (buffer_is_equal_string(du
->key
, CONST_STR_LEN("usertrack.cookie-max-age"))) {
173 PATCH(cookie_max_age
);
174 } else if (buffer_is_equal_string(du
->key
, CONST_STR_LEN("usertrack.cookie-domain"))) {
175 PATCH(cookie_domain
);
184 URIHANDLER_FUNC(mod_usertrack_uri_handler
) {
185 plugin_data
*p
= p_d
;
190 char hh
[LI_ITOSTRING_LENGTH
];
192 if (buffer_is_empty(con
->uri
.path
)) return HANDLER_GO_ON
;
194 mod_usertrack_patch_connection(srv
, con
, p
);
196 if (NULL
!= (b
= http_header_request_get(con
, HTTP_HEADER_COOKIE
, CONST_STR_LEN("Cookie")))) {
198 /* we have a cookie, does it contain a valid name ? */
202 * check for cookiename + (WS | '=')
206 if (NULL
!= (g
= strstr(b
->ptr
, p
->conf
.cookie_name
->ptr
))) {
210 for (nc
= g
+ buffer_string_length(p
->conf
.cookie_name
); *nc
== ' ' || *nc
== '\t'; nc
++);
213 /* ok, found the key of our own cookie */
215 if (strlen(nc
) > 32) {
217 return HANDLER_GO_ON
;
224 cookie
= srv
->tmp_buf
;
225 buffer_copy_buffer(cookie
, p
->conf
.cookie_name
);
226 buffer_append_string_len(cookie
, CONST_STR_LEN("="));
229 /* taken from mod_auth.c */
231 /* generate shared-secret */
232 li_MD5_Init(&Md5Ctx
);
233 li_MD5_Update(&Md5Ctx
, CONST_BUF_LEN(con
->uri
.path
));
234 li_MD5_Update(&Md5Ctx
, CONST_STR_LEN("+"));
236 li_itostrn(hh
, sizeof(hh
), srv
->cur_ts
);
237 li_MD5_Update(&Md5Ctx
, (unsigned char *)hh
, strlen(hh
));
238 li_itostrn(hh
, sizeof(hh
), li_rand_pseudo());
239 li_MD5_Update(&Md5Ctx
, (unsigned char *)hh
, strlen(hh
));
241 li_MD5_Final(h
, &Md5Ctx
);
243 buffer_append_string_encoded_hex_lc(cookie
, (char *)h
, 16);
245 /* usertrack.cookie-attrs, if set, replaces all other attrs */
246 if (!buffer_string_is_empty(p
->conf
.cookie_attrs
)) {
247 buffer_append_string_buffer(cookie
, p
->conf
.cookie_attrs
);
248 http_header_response_insert(con
, HTTP_HEADER_SET_COOKIE
, CONST_STR_LEN("Set-Cookie"), CONST_BUF_LEN(cookie
));
249 return HANDLER_GO_ON
;
252 buffer_append_string_len(cookie
, CONST_STR_LEN("; Path=/"));
253 buffer_append_string_len(cookie
, CONST_STR_LEN("; Version=1"));
255 if (!buffer_string_is_empty(p
->conf
.cookie_domain
)) {
256 buffer_append_string_len(cookie
, CONST_STR_LEN("; Domain="));
257 buffer_append_string_encoded(cookie
, CONST_BUF_LEN(p
->conf
.cookie_domain
), ENCODING_REL_URI
);
260 if (p
->conf
.cookie_max_age
) {
261 buffer_append_string_len(cookie
, CONST_STR_LEN("; max-age="));
262 buffer_append_int(cookie
, p
->conf
.cookie_max_age
);
265 http_header_response_insert(con
, HTTP_HEADER_SET_COOKIE
, CONST_STR_LEN("Set-Cookie"), CONST_BUF_LEN(cookie
));
267 return HANDLER_GO_ON
;
270 /* this function is called at dlopen() time and inits the callbacks */
272 int mod_usertrack_plugin_init(plugin
*p
);
273 int mod_usertrack_plugin_init(plugin
*p
) {
274 p
->version
= LIGHTTPD_VERSION_ID
;
275 p
->name
= buffer_init_string("usertrack");
277 p
->init
= mod_usertrack_init
;
278 p
->handle_uri_clean
= mod_usertrack_uri_handler
;
279 p
->set_defaults
= mod_usertrack_set_defaults
;
280 p
->cleanup
= mod_usertrack_free
;