2 +--------------------------------------------------------------------+
4 +--------------------------------------------------------------------+
5 | Redistribution and use in source and binary forms, with or without |
6 | modification, are permitted provided that the conditions mentioned |
7 | in the accompanying LICENSE file are met. |
8 +--------------------------------------------------------------------+
9 | Copyright (c) 2004-2007, Michael Wallner <mike@php.net> |
10 +--------------------------------------------------------------------+
16 #include "php_http_api.h"
17 #include "php_http_date_api.h"
18 #include "php_http_cookie_api.h"
20 #include "ext/standard/url.h"
22 /* {{{ PHP_MINIT_FUNCTION(http_cookie) */
23 PHP_MINIT_FUNCTION(http_cookie
)
25 HTTP_LONG_CONSTANT("HTTP_COOKIE_PARSE_RAW", HTTP_COOKIE_PARSE_RAW
);
26 HTTP_LONG_CONSTANT("HTTP_COOKIE_SECURE", HTTP_COOKIE_SECURE
);
27 HTTP_LONG_CONSTANT("HTTP_COOKIE_HTTPONLY", HTTP_COOKIE_HTTPONLY
);
33 /* {{{ http_cookie_list *http_cookie_list_init(http_cookie_list *) */
34 PHP_HTTP_API http_cookie_list
*_http_cookie_list_init(http_cookie_list
*list ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC TSRMLS_DC
)
37 list
= emalloc_rel(sizeof(http_cookie_list
));
40 zend_hash_init(&list
->cookies
, 0, NULL
, ZVAL_PTR_DTOR
, 0);
41 zend_hash_init(&list
->extras
, 0, NULL
, ZVAL_PTR_DTOR
, 0);
52 /* {{{ void http_cookie_list_dtor(http_cookie_list *) */
53 PHP_HTTP_API
void _http_cookie_list_dtor(http_cookie_list
*list TSRMLS_DC
)
56 zend_hash_destroy(&list
->cookies
);
57 zend_hash_destroy(&list
->extras
);
59 STR_SET(list
->path
, NULL
);
60 STR_SET(list
->domain
, NULL
);
65 /* {{{ void http_cookie_list_free(http_cookie_list **) */
66 PHP_HTTP_API
void _http_cookie_list_free(http_cookie_list
**list TSRMLS_DC
)
69 http_cookie_list_dtor(*list
);
76 /* {{{ const char *http_cookie_list_get_cookie(http_cookie_list *, const char*, size_t) */
77 PHP_HTTP_API
const char *_http_cookie_list_get_cookie(http_cookie_list
*list
, const char *name
, size_t name_len TSRMLS_DC
)
80 if ((SUCCESS
!= zend_hash_find(&list
->cookies
, HTTP_ZAPI_CONST_CAST(char *) name
, name_len
+ 1, (void *) &cookie
)) || (Z_TYPE_PP(cookie
) != IS_STRING
)) {
83 return Z_STRVAL_PP(cookie
);
87 /* {{{ const char *http_cookie_list_get_extra(http_cookie_list *, const char *, size_t) */
88 PHP_HTTP_API
const char *_http_cookie_list_get_extra(http_cookie_list
*list
, const char *name
, size_t name_len TSRMLS_DC
)
91 if ((SUCCESS
!= zend_hash_find(&list
->extras
, HTTP_ZAPI_CONST_CAST(char *) name
, name_len
+ 1, (void *) &extra
)) || (Z_TYPE_PP(extra
) != IS_STRING
)) {
94 return Z_STRVAL_PP(extra
);
98 /* {{{ void http_cookie_list_add_cookie(http_cookie_list *, const char *, size_t, const char *, size_t) */
99 PHP_HTTP_API
void _http_cookie_list_add_cookie(http_cookie_list
*list
, const char *name
, size_t name_len
, const char *value
, size_t value_len TSRMLS_DC
)
102 char *key
= estrndup(name
, name_len
);
103 MAKE_STD_ZVAL(cookie_value
);
104 ZVAL_STRINGL(cookie_value
, estrndup(value
, value_len
), value_len
, 0);
105 zend_hash_update(&list
->cookies
, key
, name_len
+ 1, (void *) &cookie_value
, sizeof(zval
*), NULL
);
110 /* {{{ void http_cookie_list_add_extr(http_cookie_list *, const char *, size_t, const char *, size_t) */
111 PHP_HTTP_API
void _http_cookie_list_add_extra(http_cookie_list
*list
, const char *name
, size_t name_len
, const char *value
, size_t value_len TSRMLS_DC
)
114 char *key
= estrndup(name
, name_len
);
115 MAKE_STD_ZVAL(cookie_value
);
116 ZVAL_STRINGL(cookie_value
, estrndup(value
, value_len
), value_len
, 0);
117 zend_hash_update(&list
->extras
, key
, name_len
+ 1, (void *) &cookie_value
, sizeof(zval
*), NULL
);
122 typedef struct _http_parse_param_cb_arg_t
{
123 http_cookie_list
*list
;
125 char **allowed_extras
;
126 } http_parse_param_cb_arg
;
128 /* {{{ static void http_parse_cookie_callback */
129 static void http_parse_cookie_callback(void *ptr
, const char *key
, int keylen
, const char *val
, int vallen TSRMLS_DC
)
131 http_parse_param_cb_arg
*arg
= (http_parse_param_cb_arg
*) ptr
;
133 #define _KEY_IS(s) (keylen == lenof(s) && !strncasecmp(key, (s), keylen))
135 STR_SET(arg
->list
->path
, estrndup(val
, vallen
));
136 } else if _KEY_IS("domain") {
137 STR_SET(arg
->list
->domain
, estrndup(val
, vallen
));
138 } else if _KEY_IS("expires") {
139 char *date
= estrndup(val
, vallen
);
140 arg
->list
->expires
= http_parse_date(date
);
142 } else if _KEY_IS("secure") {
143 arg
->list
->flags
|= HTTP_COOKIE_SECURE
;
144 } else if _KEY_IS("httpOnly") {
145 arg
->list
->flags
|= HTTP_COOKIE_HTTPONLY
;
147 /* check for extra */
148 if (arg
->allowed_extras
) {
149 char **ae
= arg
->allowed_extras
;
152 if ((size_t) keylen
== strlen(*ae
) && !strncasecmp(key
, *ae
, keylen
)) {
153 if (arg
->flags
& HTTP_COOKIE_PARSE_RAW
) {
154 http_cookie_list_add_extra(arg
->list
, key
, keylen
, val
, vallen
);
156 char *dec
= estrndup(val
, vallen
);
157 int declen
= php_url_decode(dec
, vallen
);
159 http_cookie_list_add_extra(arg
->list
, key
, keylen
, dec
, declen
);
167 if (arg
->flags
& HTTP_COOKIE_PARSE_RAW
) {
168 http_cookie_list_add_cookie(arg
->list
, key
, keylen
, val
, vallen
);
170 char *dec
= estrndup(val
, vallen
);
171 int declen
= php_url_decode(dec
, vallen
);
173 http_cookie_list_add_cookie(arg
->list
, key
, keylen
, dec
, declen
);
180 /* {{{ http_cookie_list *http_parse_cookie(char *, long) */
181 PHP_HTTP_API http_cookie_list
*_http_parse_cookie_ex(http_cookie_list
*list
, const char *string
, long flags
, char **allowed_extras TSRMLS_DC
)
183 int free_list
= !list
;
184 http_parse_param_cb_arg arg
;
186 list
= http_cookie_list_init(list
);
190 arg
.allowed_extras
= allowed_extras
;
192 if (SUCCESS
!= http_parse_params_ex(string
, HTTP_PARAMS_RAISE_ERROR
, http_parse_cookie_callback
, &arg
)) {
194 http_cookie_list_free(&list
);
196 http_cookie_list_dtor(list
);
205 /* {{{ void http_cookie_list_tostruct(http_cookie_list *, zval *) */
206 PHP_HTTP_API
void _http_cookie_list_tostruct(http_cookie_list
*list
, zval
*strct TSRMLS_DC
)
208 zval array
, *cookies
, *extras
;
210 INIT_ZARR(array
, HASH_OF(strct
));
212 MAKE_STD_ZVAL(cookies
);
214 zend_hash_copy(Z_ARRVAL_P(cookies
), &list
->cookies
, (copy_ctor_func_t
) zval_add_ref
, NULL
, sizeof(zval
*));
215 add_assoc_zval(&array
, "cookies", cookies
);
217 MAKE_STD_ZVAL(extras
);
219 zend_hash_copy(Z_ARRVAL_P(extras
), &list
->extras
, (copy_ctor_func_t
) zval_add_ref
, NULL
, sizeof(zval
*));
220 add_assoc_zval(&array
, "extras", extras
);
222 add_assoc_long(&array
, "flags", list
->flags
);
223 add_assoc_long(&array
, "expires", (long) list
->expires
);
224 add_assoc_string(&array
, "path", STR_PTR(list
->path
), 1);
225 add_assoc_string(&array
, "domain", STR_PTR(list
->domain
), 1);
229 /* {{{ http_cookie_list *http_cookie_list_fromstruct(http_cookie_list *, zval *strct) */
230 PHP_HTTP_API http_cookie_list
*_http_cookie_list_fromstruct(http_cookie_list
*list
, zval
*strct TSRMLS_DC
)
233 HashTable
*ht
= HASH_OF(strct
);
235 list
= http_cookie_list_init(list
);
237 if (SUCCESS
== zend_hash_find(ht
, "cookies", sizeof("cookies"), (void *) &tmp
) && Z_TYPE_PP(tmp
) == IS_ARRAY
) {
238 zend_hash_copy(&list
->cookies
, Z_ARRVAL_PP(tmp
), (copy_ctor_func_t
) zval_add_ref
, NULL
, sizeof(zval
*));
240 if (SUCCESS
== zend_hash_find(ht
, "extras", sizeof("extras"), (void *) &tmp
) && Z_TYPE_PP(tmp
) == IS_ARRAY
) {
241 zend_hash_copy(&list
->extras
, Z_ARRVAL_PP(tmp
), (copy_ctor_func_t
) zval_add_ref
, NULL
, sizeof(zval
*));
243 if (SUCCESS
== zend_hash_find(ht
, "flags", sizeof("flags"), (void *) &tmp
)) {
244 switch (Z_TYPE_PP(tmp
)) {
246 list
->flags
= Z_LVAL_PP(tmp
);
249 list
->flags
= (long) Z_DVAL_PP(tmp
);
252 cpy
= http_zsep(IS_LONG
, *tmp
);
253 list
->flags
= Z_LVAL_P(cpy
);
260 if (SUCCESS
== zend_hash_find(ht
, "expires", sizeof("expires"), (void *) &tmp
)) {
261 switch (Z_TYPE_PP(tmp
)) {
263 list
->expires
= Z_LVAL_PP(tmp
);
266 list
->expires
= (long) Z_DVAL_PP(tmp
);
269 cpy
= http_zsep(IS_LONG
, *tmp
);
271 list
->expires
= Z_LVAL_P(cpy
);
273 time_t expires
= http_parse_date(Z_STRVAL_PP(tmp
));
275 list
->expires
= expires
;
284 if (SUCCESS
== zend_hash_find(ht
, "path", sizeof("path"), (void *) &tmp
) && Z_TYPE_PP(tmp
) == IS_STRING
) {
285 list
->path
= estrndup(Z_STRVAL_PP(tmp
), Z_STRLEN_PP(tmp
));
287 if (SUCCESS
== zend_hash_find(ht
, "domain", sizeof("domain"), (void *) &tmp
) && Z_TYPE_PP(tmp
) == IS_STRING
) {
288 list
->domain
= estrndup(Z_STRVAL_PP(tmp
), Z_STRLEN_PP(tmp
));
295 /* {{{ inline append_encoded */
296 static inline void append_encoded(phpstr
*buf
, const char *key
, size_t key_len
, const char *val
, size_t val_len
)
301 enc_str
[0] = php_url_encode(key
, key_len
, &enc_len
[0]);
302 enc_str
[1] = php_url_encode(val
, val_len
, &enc_len
[1]);
304 phpstr_append(buf
, enc_str
[0], enc_len
[0]);
305 phpstr_appends(buf
, "=");
306 phpstr_append(buf
, enc_str
[1], enc_len
[1]);
307 phpstr_appends(buf
, "; ");
314 /* {{{ void http_cookie_list_tostring(http_cookie_list *, char **, size_t *) */
315 PHP_HTTP_API
void _http_cookie_list_tostring(http_cookie_list
*list
, char **str
, size_t *len TSRMLS_DC
)
319 HashKey key
= initHashKey(0);
324 FOREACH_HASH_KEYVAL(pos
, &list
->cookies
, key
, val
) {
325 if (key
.type
== HASH_KEY_IS_STRING
&& key
.len
) {
326 append_encoded(&buf
, key
.str
, key
.len
-1, Z_STRVAL_PP(val
), Z_STRLEN_PP(val
));
330 if (list
->domain
&& *list
->domain
) {
331 phpstr_appendf(&buf
, "domain=%s; ", list
->domain
);
333 if (list
->path
&& *list
->path
) {
334 phpstr_appendf(&buf
, "path=%s; ", list
->path
);
337 char *date
= http_date(list
->expires
);
338 phpstr_appendf(&buf
, "expires=%s; ", date
);
342 FOREACH_HASH_KEYVAL(pos
, &list
->extras
, key
, val
) {
343 if (key
.type
== HASH_KEY_IS_STRING
&& key
.len
) {
344 append_encoded(&buf
, key
.str
, key
.len
-1, Z_STRVAL_PP(val
), Z_STRLEN_PP(val
));
348 if (list
->flags
& HTTP_COOKIE_SECURE
) {
349 phpstr_appends(&buf
, "secure; ");
351 if (list
->flags
& HTTP_COOKIE_HTTPONLY
) {
352 phpstr_appends(&buf
, "httpOnly; ");
356 *str
= PHPSTR_VAL(&buf
);
357 *len
= PHPSTR_LEN(&buf
);
366 * vim600: noet sw=4 ts=4 fdm=marker
367 * vim<600: noet sw=4 ts=4