4 * Copyright (c) 2011 project bchan
6 * This software is provided 'as-is', without any express or implied
7 * warranty. In no event will the authors be held liable for any damages
8 * arising from the use of this software.
10 * Permission is granted to anyone to use this software for any purpose,
11 * including commercial applications, and to alter it and redistribute it
12 * freely, subject to the following restrictions:
14 * 1. The origin of this software must not be misrepresented; you must not
15 * claim that you wrote the original software. If you use this software
16 * in a product, an acknowledgment in the product documentation would be
17 * appreciated but is not required.
19 * 2. Altered source versions must be plainly marked as such, and must not be
20 * misrepresented as being the original software.
22 * 3. This notice may not be removed or altered from any source
28 #include "httpdateparser.h"
38 #include <btron/btron.h>
39 #include <bsys/queue.h>
41 #ifdef BCHAN_CONFIG_DEBUG
42 # define DP(arg) printf arg
43 # define DP_ER(msg, err) printf("%s (%d/%x)\n", msg, err>>16, err)
46 # define DP_ER(msg, err) /**/
53 typedef struct ascstr_t_ ascstr_t;
55 EXPORT W ascstr_appendstr(ascstr_t *astr, UB *apd, W apd_len)
59 str = realloc(astr->str, astr->len + apd_len + 1);
65 memcpy(astr->str + astr->len, apd, apd_len);
67 astr->str[astr->len] = '\0';
72 EXPORT W ascstr_cmp(ascstr_t *s1, ascstr_t *s2)
76 len = s1->len > s2->len ? s2->len : s1->len;
77 for (i = 0; i < len; i++) {
78 if (s1->str[i] > s2->str[i]) {
80 } else if (s1->str[i] < s2->str[i]) {
85 /* check terminate char: '\0' */
86 if (s1->str[i] > s2->str[i]) {
88 } else if (s1->str[i] < s2->str[i]) {
91 return 0; /* same length */
100 EXPORT Bool ascstr_suffixcmp(ascstr_t *astr, ascstr_t *suffix)
102 if (astr->len < suffix->len) {
105 if (strncmp(astr->str + astr->len - suffix->len, suffix->str, suffix->len) != 0) {
118 EXPORT Bool ascstr_prefixcmp(ascstr_t *astr, ascstr_t *prefix)
120 if (astr->len < prefix->len) {
123 if (strncmp(astr->str, prefix->str, prefix->len) != 0) {
130 EXPORT W ascstr_initialize(ascstr_t *astr)
132 astr->str = malloc(sizeof(UB));
133 if (astr->str == NULL) {
141 EXPORT VOID ascstr_finalize(ascstr_t *astr)
146 struct httpcookie_t_ {
148 /* requested host and path */
149 ascstr_t origin_host;
150 ascstr_t origin_path;
151 /* Set-Cookie value */
152 ascstr_t attr; /* NAME string */
153 ascstr_t name; /* VALUE string */
162 typedef struct httpcookie_t_ httpcookie_t;
164 LOCAL ascstr_t* httpcookie_getvaliddomain(httpcookie_t *cookie)
166 if (cookie->domain.len != 0) {
167 return &cookie->domain;
169 return &cookie->origin_host;
172 LOCAL ascstr_t* httpcookie_getvalidpath(httpcookie_t *cookie)
174 if (cookie->path.len != 0) {
175 return &cookie->path;
177 return &cookie->origin_path;
180 LOCAL Bool httpcookie_isvalueset(httpcookie_t *cookie)
182 if (cookie->attr.len == 0) {
185 if (cookie->name.len == 0) {
191 /* check replace condition. */
192 LOCAL Bool httpcookie_issamekey(httpcookie_t *cookie1, httpcookie_t *cookie2)
197 cmp = ascstr_cmp(&cookie1->attr, &cookie2->attr);
201 as1 = httpcookie_getvaliddomain(cookie1);
202 as2 = httpcookie_getvaliddomain(cookie2);
203 cmp = ascstr_cmp(as1, as2);
210 LOCAL httpcookie_t* httpcookie_nextnode(httpcookie_t *cookie)
212 return (httpcookie_t*)cookie->que.next;
215 LOCAL VOID httpcookie_setexpires(httpcookie_t *cookie, STIME expires)
217 cookie->persistent = True;
218 cookie->expires = expires;
221 LOCAL VOID httpcookie_QueRemove(httpcookie_t *cookie)
223 QueRemove(&cookie->que);
224 QueInit(&cookie->que);
227 LOCAL VOID httpcookie_QueInsert(httpcookie_t *entry, httpcookie_t *que)
229 QueInsert(&entry->que, &que->que);
232 LOCAL W httpcookie_initialize(httpcookie_t *cookie, UB *host, W host_len, UB *path, W path_len)
236 QueInit(&cookie->que);
237 err = ascstr_initialize(&cookie->origin_host);
239 goto error_originhost;
241 err = ascstr_appendstr(&cookie->origin_host, host, host_len);
243 goto error_originhost_append;
245 err = ascstr_initialize(&cookie->origin_path);
247 goto error_originpath;
249 err = ascstr_appendstr(&cookie->origin_path, path, path_len);
251 goto error_originpath_append;
253 err = ascstr_initialize(&cookie->attr);
257 err = ascstr_initialize(&cookie->name);
261 err = ascstr_initialize(&cookie->comment);
265 err = ascstr_initialize(&cookie->domain);
269 err = ascstr_initialize(&cookie->path);
273 err = ascstr_initialize(&cookie->version);
278 cookie->persistent = False;
279 cookie->secure = False;
284 ascstr_finalize(&cookie->version);
286 ascstr_finalize(&cookie->path);
288 ascstr_finalize(&cookie->domain);
290 ascstr_finalize(&cookie->comment);
292 ascstr_finalize(&cookie->name);
294 ascstr_finalize(&cookie->attr);
296 error_originpath_append:
297 ascstr_finalize(&cookie->origin_path);
299 error_originhost_append:
300 ascstr_finalize(&cookie->origin_host);
305 LOCAL VOID httpcookie_finalize(httpcookie_t *cookie)
307 ascstr_finalize(&cookie->version);
308 ascstr_finalize(&cookie->path);
309 ascstr_finalize(&cookie->domain);
310 ascstr_finalize(&cookie->comment);
311 ascstr_finalize(&cookie->name);
312 ascstr_finalize(&cookie->attr);
313 ascstr_finalize(&cookie->origin_path);
314 ascstr_finalize(&cookie->origin_host);
315 QueRemove(&cookie->que);
318 LOCAL httpcookie_t* httpcookie_new(UB *host, W host_len, UB *path, W path_len)
320 httpcookie_t *cookie;
323 cookie = malloc(sizeof(httpcookie_t));
324 if (cookie == NULL) {
327 err = httpcookie_initialize(cookie, host, host_len, path, path_len);
335 LOCAL VOID httpcookie_delete(httpcookie_t *cookie)
337 httpcookie_finalize(cookie);
348 LOCAL httpcookie_t* cookiedb_sentinelnode(cookiedb_t *db)
350 return (httpcookie_t*)&db->sentinel;
353 struct cookiedb_writeiterator_t_ {
359 httpcookie_t *current;
361 typedef struct cookiedb_writeiterator_t_ cookiedb_writeiterator_t;
363 LOCAL W count_priod(ascstr_t *str)
368 for (i = 0; i < str->len; i++) {
369 if (str->str[i] == '.') {
377 LOCAL Bool check_specified_TLD(ascstr_t *domain)
379 if (strncmp(domain->str + domain->len - 4, ".net", 4) == 0) {
382 if (strncmp(domain->str + domain->len - 4, ".com", 4) == 0) {
385 if (strncmp(domain->str + domain->len - 4, ".edu", 4) == 0) {
388 if (strncmp(domain->str + domain->len - 4, ".org", 4) == 0) {
391 if (strncmp(domain->str + domain->len - 4, ".gov", 4) == 0) {
394 if (strncmp(domain->str + domain->len - 4, ".mil", 4) == 0) {
397 if (strncmp(domain->str + domain->len - 4, ".int", 4) == 0) {
400 /* TODO: other TLDs. */
404 LOCAL Bool cookiedb_writeiterator_checksendcondition_domaincheck(cookiedb_writeiterator_t *iter, httpcookie_t *cookie)
408 if (cookie->domain.len != 0) {
409 if (cookie->domain.len == (iter->host.len + 1)) {
411 * domain = .xxx.yyy.zzz
412 * origin = xxx.yyy.zzz
414 if (strncmp(cookie->domain.str + 1, iter->host.str, iter->host.len) != 0) {
418 ok = ascstr_suffixcmp(&iter->host, &cookie->domain);
423 /* count period number is not need for counting in insertion to queue. */
425 ok = ascstr_suffixcmp(&iter->host, &cookie->origin_host);
434 LOCAL Bool cookiedb_writeitereator_pathcheck(cookiedb_writeiterator_t *iter, httpcookie_t *cookie)
437 if (cookie->path.len != 0) {
438 ok = ascstr_prefixcmp(&iter->path, &cookie->path);
440 ok = ascstr_prefixcmp(&iter->path, &cookie->origin_path);
445 LOCAL Bool cookiedb_writeiterator_checksendcondition(cookiedb_writeiterator_t *iter, httpcookie_t *cookie)
449 if (cookie->secure == True) {
450 if (iter->secure != True) {
454 if (cookie->persistent == True) {
455 if (cookie->expires < iter->time) {
459 ok = cookiedb_writeiterator_checksendcondition_domaincheck(iter, cookie);
463 ok = cookiedb_writeitereator_pathcheck(iter, cookie);
471 LOCAL Bool cookiedb_writeiterator_next(cookiedb_writeiterator_t *iter, httpcookie_t **cookie)
476 senti = cookiedb_sentinelnode(iter->origin);
478 if (iter->current == senti) {
481 send = cookiedb_writeiterator_checksendcondition(iter, iter->current);
485 iter->current = httpcookie_nextnode(iter->current);
487 if (iter->current != senti) {
488 *cookie = iter->current;
489 iter->current = httpcookie_nextnode(iter->current);
496 LOCAL W cookiedb_writeiterator_initialize(cookiedb_writeiterator_t *iter, cookiedb_t *db, UB *host, W host_len, UB *path, W path_len, Bool secure, STIME time)
501 err = ascstr_initialize(&iter->host);
505 err = ascstr_appendstr(&iter->host, host, host_len);
507 ascstr_finalize(&iter->host);
510 err = ascstr_initialize(&iter->path);
512 ascstr_finalize(&iter->host);
515 err = ascstr_appendstr(&iter->path, path, path_len);
517 ascstr_finalize(&iter->path);
518 ascstr_finalize(&iter->host);
523 iter->secure = secure;
525 senti = cookiedb_sentinelnode(db);
526 iter->current = httpcookie_nextnode(senti);
531 LOCAL VOID cookiedb_writeiterator_finalize(cookiedb_writeiterator_t *iter)
533 ascstr_finalize(&iter->path);
534 ascstr_finalize(&iter->host);
537 struct cookiedb_writeheadercontext_t_ {
538 cookiedb_writeiterator_t iter;
540 COOKIEDB_WRITEITERATORCONTEXT_STATE_START,
541 COOKIEDB_WRITEITERATORCONTEXT_STATE_NAME,
542 COOKIEDB_WRITEITERATORCONTEXT_STATE_EQUAL,
543 COOKIEDB_WRITEITERATORCONTEXT_STATE_VALUE,
544 COOKIEDB_WRITEITERATORCONTEXT_STATE_COLON,
545 COOKIEDB_WRITEITERATORCONTEXT_STATE_CRLF,
546 COOKIEDB_WRITEITERATORCONTEXT_STATE_END,
548 httpcookie_t *current;
551 LOCAL UB cookiedb_writeheader_context_headername[] = "Cookie: ";
552 LOCAL UB cookiedb_writeheader_context_equal[] = "=";
553 LOCAL UB cookiedb_writeheader_context_colon[] = "; ";
554 LOCAL UB cookiedb_writeheader_context_crlf[] = "\r\n";
556 EXPORT Bool cookiedb_writeheadercontext_makeheader(cookiedb_writeheadercontext_t *context, UB **str, W *len)
560 switch (context->state) {
561 case COOKIEDB_WRITEITERATORCONTEXT_STATE_START:
562 cont = cookiedb_writeiterator_next(&context->iter, &context->current);
566 *str = cookiedb_writeheader_context_headername;
568 context->state = COOKIEDB_WRITEITERATORCONTEXT_STATE_NAME;
570 case COOKIEDB_WRITEITERATORCONTEXT_STATE_NAME:
571 *str = context->current->attr.str;
572 *len = context->current->attr.len;
573 context->state = COOKIEDB_WRITEITERATORCONTEXT_STATE_EQUAL;
575 case COOKIEDB_WRITEITERATORCONTEXT_STATE_EQUAL:
576 *str = cookiedb_writeheader_context_equal;
578 context->state = COOKIEDB_WRITEITERATORCONTEXT_STATE_VALUE;
580 case COOKIEDB_WRITEITERATORCONTEXT_STATE_VALUE:
581 *str = context->current->name.str;
582 *len = context->current->name.len;
583 context->state = COOKIEDB_WRITEITERATORCONTEXT_STATE_COLON;
585 case COOKIEDB_WRITEITERATORCONTEXT_STATE_COLON:
586 *str = cookiedb_writeheader_context_colon;
587 cont = cookiedb_writeiterator_next(&context->iter, &context->current);
590 context->state = COOKIEDB_WRITEITERATORCONTEXT_STATE_CRLF;
593 context->state = COOKIEDB_WRITEITERATORCONTEXT_STATE_NAME;
596 case COOKIEDB_WRITEITERATORCONTEXT_STATE_CRLF:
597 *str = cookiedb_writeheader_context_crlf;
599 context->state = COOKIEDB_WRITEITERATORCONTEXT_STATE_END;
601 case COOKIEDB_WRITEITERATORCONTEXT_STATE_END:
608 LOCAL cookiedb_writeheadercontext_t* cookiedb_writeheadercontext_new(cookiedb_t *db, UB *host, W host_len, UB *path, W path_len, Bool secure, STIME time)
610 cookiedb_writeheadercontext_t *context;
613 context = (cookiedb_writeheadercontext_t*)malloc(sizeof(cookiedb_writeheadercontext_t));
614 if (context == NULL) {
617 err = cookiedb_writeiterator_initialize(&context->iter, db, host, host_len, path, path_len, secure, time);
622 context->state = COOKIEDB_WRITEITERATORCONTEXT_STATE_START;
627 LOCAL VOID cookiedb_writeheadercontext_delete(cookiedb_writeheadercontext_t *context)
629 cookiedb_writeiterator_finalize(&context->iter);
633 EXPORT cookiedb_writeheadercontext_t* cookiedb_startheaderwrite(cookiedb_t *db, UB *host, W host_len, UB *path, W path_len, Bool secure, STIME time)
635 cookiedb_writeheadercontext_t *context;
637 context = cookiedb_writeheadercontext_new(db, host, host_len, path, path_len, secure, time);
638 if (context == NULL) {
645 EXPORT VOID cookiedb_endheaderwrite(cookiedb_t *db, cookiedb_writeheadercontext_t *context)
647 cookiedb_writeheadercontext_delete(context);
650 struct cookiedb_readheadercontext_t_ {
656 COOKIEDB_READHEADERCONTEXT_STATE_START,
657 COOKIEDB_READHEADERCONTEXT_STATE_NAMEATTR,
658 COOKIEDB_READHEADERCONTEXT_STATE_OTHERVAL,
660 httpcookie_t *reading;
663 LOCAL VOID cookiedb_readheadercontext_insertcookie(cookiedb_readheadercontext_t *context, httpcookie_t *cookie)
665 QueInsert(&cookie->que, &context->sentinel);
668 EXPORT W cookiedb_readheadercontext_appendchar_attr(cookiedb_readheadercontext_t *context, UB ch)
670 if (context->state != COOKIEDB_READHEADERCONTEXT_STATE_NAMEATTR) {
671 context->state = COOKIEDB_READHEADERCONTEXT_STATE_NAMEATTR;
672 if (context->reading != NULL) {
673 cookiedb_readheadercontext_insertcookie(context, context->reading);
675 context->reading = httpcookie_new(context->host.str, context->host.len, context->path.str, context->path.len);
676 if (context->reading == NULL) {
677 return -1; /* TODO: error value */
680 return ascstr_appendstr(&context->reading->attr, &ch, 1);
683 LOCAL W cookiedb_readheadercontext_appdatechar_common(cookiedb_readheadercontext_t *context, ascstr_t *target, UB ch)
685 if (context->state == COOKIEDB_READHEADERCONTEXT_STATE_START) {
688 context->state = COOKIEDB_READHEADERCONTEXT_STATE_OTHERVAL;
689 return ascstr_appendstr(target, &ch, 1);
692 EXPORT W cookiedb_readheadercontext_appendchar_name(cookiedb_readheadercontext_t *context, UB ch)
694 return cookiedb_readheadercontext_appdatechar_common(context, &context->reading->name, ch);
697 EXPORT W cookiedb_readheadercontext_appendchar_comment(cookiedb_readheadercontext_t *context, UB ch)
699 return cookiedb_readheadercontext_appdatechar_common(context, &context->reading->comment, ch);
702 EXPORT W cookiedb_readheadercontext_appendchar_domain(cookiedb_readheadercontext_t *context, UB ch)
704 return cookiedb_readheadercontext_appdatechar_common(context, &context->reading->domain, ch);
707 EXPORT W cookiedb_readheadercontext_appendchar_path(cookiedb_readheadercontext_t *context, UB ch)
709 return cookiedb_readheadercontext_appdatechar_common(context, &context->reading->path, ch);
712 EXPORT W cookiedb_readheadercontext_appendchar_version(cookiedb_readheadercontext_t *context, UB ch)
714 return cookiedb_readheadercontext_appdatechar_common(context, &context->reading->version, ch);
717 EXPORT W cookiedb_readheadercontext_setsecure(cookiedb_readheadercontext_t *context)
719 if (context->state == COOKIEDB_READHEADERCONTEXT_STATE_START) {
722 context->state = COOKIEDB_READHEADERCONTEXT_STATE_OTHERVAL;
724 context->reading->secure = True;
729 EXPORT W cookiedb_readheadercontext_setexpires(cookiedb_readheadercontext_t *context, STIME expires)
731 if (context->state == COOKIEDB_READHEADERCONTEXT_STATE_START) {
734 context->state = COOKIEDB_READHEADERCONTEXT_STATE_OTHERVAL;
736 httpcookie_setexpires(context->reading, expires);
741 EXPORT W cookiedb_readheadercontext_setmaxage(cookiedb_readheadercontext_t *context, W seconds)
747 httpcookie_setexpires(context->reading, context->current + seconds);
752 LOCAL httpcookie_t* cookiedb_readheadercontext_prevcookie(cookiedb_readheadercontext_t *context)
755 empty = isQueEmpty(&context->sentinel);
759 return (httpcookie_t*)context->sentinel.prev;
762 LOCAL cookiedb_readheadercontext_t* cookiedb_readheadercontext_new(UB *host, W host_len, UB *path, W path_len, STIME time)
764 cookiedb_readheadercontext_t *context;
767 context = (cookiedb_readheadercontext_t*)malloc(sizeof(cookiedb_readheadercontext_t));
768 if (context == NULL) {
771 err = ascstr_initialize(&context->host);
776 err = ascstr_appendstr(&context->host, host, host_len);
778 ascstr_finalize(&context->host);
782 err = ascstr_initialize(&context->path);
784 ascstr_finalize(&context->host);
788 err = ascstr_appendstr(&context->path, path, path_len);
790 ascstr_finalize(&context->path);
791 ascstr_finalize(&context->host);
795 context->reading = NULL;
796 QueInit(&context->sentinel);
797 context->state = COOKIEDB_READHEADERCONTEXT_STATE_START;
798 context->current = time;
803 LOCAL VOID cookiedb_readheadercontext_delete(cookiedb_readheadercontext_t *context)
805 httpcookie_t *cookie;
808 cookie = cookiedb_readheadercontext_prevcookie(context);
809 if (cookie == NULL) {
812 httpcookie_delete(cookie);
814 if (context->reading != NULL) {
815 httpcookie_delete(context->reading);
818 ascstr_finalize(&context->path);
819 ascstr_finalize(&context->host);
823 EXPORT cookiedb_readheadercontext_t* cookiedb_startheaderread(cookiedb_t *db, UB *host, W host_len, UB *path, W path_len, STIME time)
825 cookiedb_readheadercontext_t *context;
827 context = cookiedb_readheadercontext_new(host, host_len, path, path_len, time);
828 if (context == NULL) {
835 LOCAL VOID cookiedb_insertcookie(cookiedb_t *db, httpcookie_t *cookie)
837 httpcookie_t *senti, *node;
838 ascstr_t *as_a, *as_n;
842 senti = cookiedb_sentinelnode(db);
843 node = httpcookie_nextnode(senti);
846 httpcookie_QueInsert(cookie, senti);
849 as_n = httpcookie_getvalidpath(node);
850 as_a = httpcookie_getvalidpath(cookie);
851 cmp = ascstr_cmp(as_n, as_a);
853 samekey = httpcookie_issamekey(node, cookie);
854 if (samekey == True) {
855 httpcookie_QueInsert(cookie, node);
856 httpcookie_delete(node);
859 } else if (cmp < 0) {
860 httpcookie_QueInsert(cookie, node);
863 node = httpcookie_nextnode(node);
867 LOCAL Bool cookiedb_checkinsertioncondition(cookiedb_t *db, httpcookie_t *cookie, STIME current)
873 if (cookie->domain.len != 0) {
874 if (cookie->domain.str[0] != '.') { /* is not error and add period? */
877 /* same as cookiedb_writeiterator_checksendcondition */
878 count = count_priod(&cookie->domain);
879 ok = check_specified_TLD(&cookie->domain);
889 /* domain and request host check */
890 if (cookie->domain.len == (cookie->origin_host.len + 1)) {
892 * domain = .xxx.yyy.zzz
893 * origin = xxx.yyy.zzz
895 if (strncmp(cookie->domain.str + 1, cookie->origin_host.str, cookie->origin_host.len) != 0) {
899 ok = ascstr_suffixcmp(&cookie->origin_host, &cookie->domain);
907 if (cookie->expires == 0) {
910 if (cookie->expires >= current) {
917 LOCAL VOID cookiedb_insertwithcheck(cookiedb_t *db, httpcookie_t *cookie, STIME current)
920 save = cookiedb_checkinsertioncondition(db, cookie, current);
922 cookiedb_insertcookie(db, cookie);
924 httpcookie_delete(cookie);
928 EXPORT VOID cookiedb_endheaderread(cookiedb_t *db, cookiedb_readheadercontext_t *context)
930 httpcookie_t *cookie;
934 cookie = cookiedb_readheadercontext_prevcookie(context);
935 if (cookie == NULL) {
938 httpcookie_QueRemove(cookie);
939 cookiedb_insertwithcheck(db, cookie, context->current);
941 if (context->reading != NULL) {
942 ok = httpcookie_isvalueset(context->reading);
944 httpcookie_QueRemove(context->reading);
945 cookiedb_insertwithcheck(db, context->reading, context->current);
947 httpcookie_delete(context->reading);
949 context->reading = NULL;
952 cookiedb_readheadercontext_delete(context);
955 EXPORT VOID cookiedb_clearallcookie(cookiedb_t *db)
957 httpcookie_t *cookie;
962 empty = isQueEmpty(&db->sentinel);
966 cookie = (httpcookie_t*)db->sentinel.prev;
967 httpcookie_delete(cookie);
971 fd = opn_fil(db->lnk, F_UPDATE, NULL);
975 err = fnd_rec(fd, F_TOPEND, 1 << db->rectype, db->subtype, NULL);
980 err = loc_rec(fd, F_LOCK);
986 err = loc_rec(fd, F_UNLOCK);
990 LOCAL W cookiedb_append_astr_recode(W fd, ascstr_t *astr)
992 return wri_rec(fd, -1, astr->str, astr->len, NULL, NULL, 0);
996 LOCAL UB dec[] = "0123456789";
997 LOCAL W UW_to_str(UW n, UB *str)
999 W i = 0,digit,draw = 0;
1001 digit = n / 1000000000 % 10;
1002 if ((digit != 0)||(draw != 0)) {
1003 str[i++] = dec[digit];
1006 digit = n / 100000000 % 10;
1007 if ((digit != 0)||(draw != 0)) {
1008 str[i++] = dec[digit];
1011 digit = n / 10000000 % 10;
1012 if ((digit != 0)||(draw != 0)) {
1013 str[i++] = dec[digit];
1016 digit = n / 1000000 % 10;
1017 if ((digit != 0)||(draw != 0)) {
1018 str[i++] = dec[digit];
1021 digit = n / 100000 % 10;
1022 if ((digit != 0)||(draw != 0)) {
1023 str[i++] = dec[digit];
1026 digit = n / 10000 % 10;
1027 if ((digit != 0)||(draw != 0)) {
1028 str[i++] = dec[digit];
1031 digit = n / 1000 % 10;
1032 if ((digit != 0)||(draw != 0)) {
1033 str[i++] = dec[digit];
1036 digit = n / 100 % 10;
1037 if ((digit != 0)||(draw != 0)) {
1038 str[i++] = dec[digit];
1041 digit = n / 10 % 10;
1042 if ((digit != 0)||(draw != 0)) {
1043 str[i++] = dec[digit];
1047 str[i++] = dec[digit];
1052 LOCAL W cookiedb_append_STIME_recode(W fd, STIME time)
1057 len = UW_to_str(time, str);
1058 return wri_rec(fd, -1, str, len, NULL, NULL, 0);
1061 LOCAL W cookiedb_writecookietorecord(httpcookie_t *cookie, W fd)
1065 UB secure[6] = "secure";
1067 ascstr_t a_paren = {paren, 2};
1068 ascstr_t a_secure = {secure, 6};
1069 ascstr_t a_nl = {nl, 1};
1071 err = cookiedb_append_astr_recode(fd, &cookie->origin_host);
1075 err = cookiedb_append_astr_recode(fd, &a_paren);
1079 err = cookiedb_append_astr_recode(fd, &cookie->origin_path);
1083 err = cookiedb_append_astr_recode(fd, &a_paren);
1087 err = cookiedb_append_astr_recode(fd, &cookie->attr);
1091 err = cookiedb_append_astr_recode(fd, &a_paren);
1095 err = cookiedb_append_astr_recode(fd, &cookie->name);
1099 err = cookiedb_append_astr_recode(fd, &a_paren);
1103 err = cookiedb_append_astr_recode(fd, &cookie->comment);
1107 err = cookiedb_append_astr_recode(fd, &a_paren);
1111 err = cookiedb_append_astr_recode(fd, &cookie->domain);
1115 err = cookiedb_append_astr_recode(fd, &a_paren);
1119 err = cookiedb_append_STIME_recode(fd, cookie->expires);
1123 err = cookiedb_append_astr_recode(fd, &a_paren);
1127 err = cookiedb_append_astr_recode(fd, &cookie->path);
1131 err = cookiedb_append_astr_recode(fd, &a_paren);
1135 err = cookiedb_append_astr_recode(fd, &cookie->version);
1139 err = cookiedb_append_astr_recode(fd, &a_paren);
1143 if (cookie->secure == True) {
1144 err = cookiedb_append_astr_recode(fd, &a_secure);
1149 err = cookiedb_append_astr_recode(fd, &a_paren);
1153 err = cookiedb_append_astr_recode(fd, &a_nl);
1161 LOCAL W cookiedb_writecookiestorecord(cookiedb_t *db, W fd)
1163 httpcookie_t *senti, *node;
1166 senti = cookiedb_sentinelnode(db);
1167 node = httpcookie_nextnode(senti);
1168 for (; node != senti; node = httpcookie_nextnode(node)) {
1169 if (node->persistent == False) {
1172 err = cookiedb_writecookietorecord(node, fd);
1180 EXPORT W cookiedb_writefile(cookiedb_t *db)
1184 fd = opn_fil(db->lnk, F_UPDATE, NULL);
1188 err = fnd_rec(fd, F_TOPEND, 1 << db->rectype, db->subtype, NULL);
1189 if (err == ER_REC) {
1190 err = ins_rec(fd, NULL, 0, db->rectype, db->subtype, 0);
1194 err = see_rec(fd, -1, 0, NULL);
1198 } else if (err < 0) {
1202 err = loc_rec(fd, F_LOCK);
1208 err = cookiedb_writecookiestorecord(db, fd);
1210 DP_ER("cookiedb_writecookiestorecord error\n", err);
1213 err = loc_rec(fd, F_UNLOCK);
1218 struct cookiedb_readfilecontext_t_ {
1220 COOKIEDB_READFILECONTEXT_STATE_ORIGIN_HOST,
1221 COOKIEDB_READFILECONTEXT_STATE_ORIGIN_PATH,
1222 COOKIEDB_READFILECONTEXT_STATE_ATTR,
1223 COOKIEDB_READFILECONTEXT_STATE_NAME,
1224 COOKIEDB_READFILECONTEXT_STATE_COMMENT,
1225 COOKIEDB_READFILECONTEXT_STATE_DOMAIN,
1226 COOKIEDB_READFILECONTEXT_STATE_EXPIRES,
1227 COOKIEDB_READFILECONTEXT_STATE_EXPIRES_ERROR,
1228 COOKIEDB_READFILECONTEXT_STATE_PATH,
1229 COOKIEDB_READFILECONTEXT_STATE_VERSION,
1230 COOKIEDB_READFILECONTEXT_STATE_SECURE,
1231 COOKIEDB_READFILECONTEXT_STATE_OTHER,
1236 tokenchecker_t securecheck;
1238 typedef struct cookiedb_readfilecontext_t_ cookiedb_readfilecontext_t;
1240 LOCAL Bool cookiedb_readfilecontext_cookiecheck(httpcookie_t *cookie)
1242 if (cookie->origin_host.len == 0) {
1245 if (cookie->origin_path.len == 0) {
1248 if (cookie->attr.len == 0) {
1251 if (cookie->name.len == 0) {
1254 if (cookie->persistent == False) {
1260 LOCAL W cookiedb_readfilecontext_inputcommand(cookiedb_readfilecontext_t *ctx, psvlexer_result_t *cmd)
1266 if (cmd->type == PSVLEXER_RESULT_FIELDEND) {
1267 ok = cookiedb_readfilecontext_cookiecheck(ctx->buf);
1269 httpcookie_delete(ctx->buf);
1271 cookiedb_insertcookie(ctx->db, ctx->buf);
1273 ctx->buf = httpcookie_new(NULL, 0, NULL, 0);
1274 if (ctx->buf == NULL) {
1275 return -1; /* TODO */
1277 ctx->state = COOKIEDB_READFILECONTEXT_STATE_ORIGIN_HOST;
1280 switch (ctx->state) {
1281 case COOKIEDB_READFILECONTEXT_STATE_ORIGIN_HOST:
1282 if (cmd->type == PSVLEXER_RESULT_SEPARATION) {
1283 ctx->state = COOKIEDB_READFILECONTEXT_STATE_ORIGIN_PATH;
1284 } else if (cmd->type == PSVLEXER_RESULT_VALUE) {
1285 err = ascstr_appendstr(&ctx->buf->origin_host, cmd->str, cmd->len);
1291 case COOKIEDB_READFILECONTEXT_STATE_ORIGIN_PATH:
1292 if (cmd->type == PSVLEXER_RESULT_SEPARATION) {
1293 ctx->state = COOKIEDB_READFILECONTEXT_STATE_ATTR;
1294 } else if (cmd->type == PSVLEXER_RESULT_VALUE) {
1295 err = ascstr_appendstr(&ctx->buf->origin_path, cmd->str, cmd->len);
1301 case COOKIEDB_READFILECONTEXT_STATE_ATTR:
1302 if (cmd->type == PSVLEXER_RESULT_SEPARATION) {
1303 ctx->state = COOKIEDB_READFILECONTEXT_STATE_NAME;
1304 } else if (cmd->type == PSVLEXER_RESULT_VALUE) {
1305 err = ascstr_appendstr(&ctx->buf->attr, cmd->str, cmd->len);
1311 case COOKIEDB_READFILECONTEXT_STATE_NAME:
1312 if (cmd->type == PSVLEXER_RESULT_SEPARATION) {
1313 ctx->state = COOKIEDB_READFILECONTEXT_STATE_COMMENT;
1314 } else if (cmd->type == PSVLEXER_RESULT_VALUE) {
1315 err = ascstr_appendstr(&ctx->buf->name, cmd->str, cmd->len);
1321 case COOKIEDB_READFILECONTEXT_STATE_COMMENT:
1322 if (cmd->type == PSVLEXER_RESULT_SEPARATION) {
1323 ctx->state = COOKIEDB_READFILECONTEXT_STATE_DOMAIN;
1324 } else if (cmd->type == PSVLEXER_RESULT_VALUE) {
1325 err = ascstr_appendstr(&ctx->buf->comment, cmd->str, cmd->len);
1331 case COOKIEDB_READFILECONTEXT_STATE_DOMAIN:
1332 if (cmd->type == PSVLEXER_RESULT_SEPARATION) {
1333 ctx->state = COOKIEDB_READFILECONTEXT_STATE_EXPIRES;
1335 } else if (cmd->type == PSVLEXER_RESULT_VALUE) {
1336 err = ascstr_appendstr(&ctx->buf->domain, cmd->str, cmd->len);
1342 case COOKIEDB_READFILECONTEXT_STATE_EXPIRES:
1343 if (cmd->type == PSVLEXER_RESULT_SEPARATION) {
1344 ctx->state = COOKIEDB_READFILECONTEXT_STATE_PATH;
1345 httpcookie_setexpires(ctx->buf, ctx->time);
1346 } else if (cmd->type == PSVLEXER_RESULT_VALUE) {
1347 for (i = 0; i < cmd->len; i++) {
1350 ctx->time = ctx->time * 10 + c - '0';
1352 ctx->state = COOKIEDB_READFILECONTEXT_STATE_EXPIRES_ERROR;
1358 case COOKIEDB_READFILECONTEXT_STATE_EXPIRES_ERROR:
1359 if (cmd->type == PSVLEXER_RESULT_SEPARATION) {
1360 ctx->state = COOKIEDB_READFILECONTEXT_STATE_PATH;
1363 case COOKIEDB_READFILECONTEXT_STATE_PATH:
1364 if (cmd->type == PSVLEXER_RESULT_SEPARATION) {
1365 ctx->state = COOKIEDB_READFILECONTEXT_STATE_VERSION;
1366 } else if (cmd->type == PSVLEXER_RESULT_VALUE) {
1367 err = ascstr_appendstr(&ctx->buf->path, cmd->str, cmd->len);
1373 case COOKIEDB_READFILECONTEXT_STATE_VERSION:
1374 if (cmd->type == PSVLEXER_RESULT_SEPARATION) {
1375 ctx->state = COOKIEDB_READFILECONTEXT_STATE_SECURE;
1376 tokenchecker_clear(&ctx->securecheck);
1377 } else if (cmd->type == PSVLEXER_RESULT_VALUE) {
1378 err = ascstr_appendstr(&ctx->buf->version, cmd->str, cmd->len);
1384 case COOKIEDB_READFILECONTEXT_STATE_SECURE:
1385 if (cmd->type == PSVLEXER_RESULT_SEPARATION) {
1386 ctx->state = COOKIEDB_READFILECONTEXT_STATE_OTHER;
1387 ret = tokenchecker_endinput(&ctx->securecheck, &val);
1388 if (ret == TOKENCHECKER_DETERMINE) {
1389 ctx->buf->secure = True;
1391 } else if (cmd->type == PSVLEXER_RESULT_VALUE) {
1392 for (i = 0; i < cmd->len; i++) {
1393 tokenchecker_inputchar(&ctx->securecheck, cmd->str[i], &val);
1397 case COOKIEDB_READFILECONTEXT_STATE_OTHER:
1404 LOCAL tokenchecker_valuetuple_t nList_secure[] = {
1407 LOCAL B eToken_secure[] = "<";
1409 LOCAL W cookiedb_readfilecontext_initialize(cookiedb_readfilecontext_t *ctx, cookiedb_t *db)
1411 ctx->buf = httpcookie_new(NULL, 0, NULL, 0);
1412 if (ctx->buf == NULL) {
1413 return -1; /* TODO */
1416 ctx->state = COOKIEDB_READFILECONTEXT_STATE_ORIGIN_HOST;
1417 tokenchecker_initialize(&ctx->securecheck, nList_secure, 1, eToken_secure);
1421 LOCAL VOID cookiedb_readfilecontext_finalize(cookiedb_readfilecontext_t *ctx)
1423 tokenchecker_finalize(&ctx->securecheck);
1424 if (ctx->buf != NULL) {
1425 httpcookie_delete(ctx->buf);
1429 LOCAL W cookiedb_readcookiesfrommemory(cookiedb_t *db, UB *data, W len)
1432 psvlexer_result_t *result;
1433 cookiedb_readfilecontext_t context;
1434 W i,j,err,result_len;
1436 err = psvlexer_initialize(&lexer);
1440 err = cookiedb_readfilecontext_initialize(&context, db);
1442 psvlexer_finalize(&lexer);
1445 for (i = 0; i < len; i++) {
1446 psvlexer_inputchar(&lexer, data + i, 1, &result, &result_len);
1448 for (j = 0; j < result_len; j++) {
1449 err = cookiedb_readfilecontext_inputcommand(&context, result + j);
1458 cookiedb_readfilecontext_finalize(&context);
1459 psvlexer_finalize(&lexer);
1464 LOCAL W cookiedb_readcookiesfromrecord(cookiedb_t *db, W fd)
1469 err = rea_rec(fd, 0, NULL, 0, &r_len, NULL);
1473 r_data = malloc(r_len);
1474 if (r_data == NULL) {
1477 err = rea_rec(fd, 0, r_data, r_len, NULL, NULL);
1486 printf("r_len = %d\n", r_len);
1487 for (i = 0; i < r_len; i++) {
1488 printf("%c", r_data[i]);
1493 err = cookiedb_readcookiesfrommemory(db, r_data, r_len);
1500 LOCAL VOID cookiedb_clearpersistentcookie(cookiedb_t *db)
1502 httpcookie_t *senti, *node, *node2;
1504 senti = cookiedb_sentinelnode(db);
1505 node = httpcookie_nextnode(senti);
1506 for (; node != senti;) {
1507 if (node->persistent == True) {
1508 node2 = httpcookie_nextnode(node);
1509 httpcookie_delete(node);
1512 node = httpcookie_nextnode(node);
1517 EXPORT W cookiedb_readfile(cookiedb_t *db)
1521 fd = opn_fil(db->lnk, F_UPDATE, NULL);
1525 err = fnd_rec(fd, F_TOPEND, 1 << db->rectype, db->subtype, NULL);
1526 if (err == ER_REC) {
1527 cookiedb_clearpersistentcookie(db);
1530 } else if (err < 0) {
1534 err = loc_rec(fd, F_LOCK);
1539 cookiedb_clearpersistentcookie(db);
1540 err = cookiedb_readcookiesfromrecord(db, fd);
1544 err = loc_rec(fd, F_UNLOCK);
1549 LOCAL W cookiedb_initialize(cookiedb_t *db, LINK *db_lnk, W rectype, UH subtype)
1551 QueInit(&db->sentinel);
1553 db->rectype = rectype;
1554 db->subtype = subtype;
1558 LOCAL VOID cookiedb_finalize(cookiedb_t *db)
1560 httpcookie_t *cookie;
1564 empty = isQueEmpty(&db->sentinel);
1565 if (empty == True) {
1568 cookie = (httpcookie_t*)db->sentinel.prev;
1569 httpcookie_delete(cookie);
1573 EXPORT cookiedb_t* cookiedb_new(LINK *db_lnk, W rectype, UH subtype)
1578 db = malloc(sizeof(cookiedb_t));
1582 err = cookiedb_initialize(db, db_lnk, rectype, subtype);
1591 EXPORT VOID cookiedb_delete(cookiedb_t *db)
1593 cookiedb_finalize(db);