OSDN Git Service

a27a3b452aad707d299e41618aca5ae416bfed87
[bbk/bchan.git] / src / cookiedb.c
1 /*
2  * cookiedb.c
3  *
4  * Copyright (c) 2011 project bchan
5  *
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.
9  *
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:
13  *
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.
18  *
19  * 2. Altered source versions must be plainly marked as such, and must not be
20  *    misrepresented as being the original software.
21  *
22  * 3. This notice may not be removed or altered from any source
23  *    distribution.
24  *
25  */
26
27 #include    "cookiedb.h"
28 #include    "httpdateparser.h"
29 #include    "psvlexer.h"
30 #include    "parselib.h"
31
32 #include        <basic.h>
33 #include        <bstdio.h>
34 #include        <bstdlib.h>
35 #include        <bstring.h>
36 #include        <bctype.h>
37 #include        <errcode.h>
38 #include        <btron/btron.h>
39 #include        <bsys/queue.h>
40
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)
44 #else
45 # define DP(arg) /**/
46 # define DP_ER(msg, err) /**/
47 #endif
48
49 struct ascstr_t_ {
50         UB *str;
51         W len;
52 };
53 typedef struct ascstr_t_ ascstr_t;
54
55 EXPORT W ascstr_appendstr(ascstr_t *astr, UB *apd, W apd_len)
56 {
57         UB *str;
58
59         str = realloc(astr->str, astr->len + apd_len + 1);
60         if (str == NULL) {
61                 return -1;
62         }
63         astr->str = str;
64
65         memcpy(astr->str + astr->len, apd, apd_len);
66         astr->len += apd_len;
67         astr->str[astr->len] = '\0';
68
69         return 0;
70 }
71
72 EXPORT W ascstr_cmp(ascstr_t *s1, ascstr_t *s2)
73 {
74         W i,len;
75
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]) {
79                         return 1;
80                 } else if (s1->str[i] < s2->str[i]) {
81                         return -1;
82                 }
83         }
84
85         /* check terminate char: '\0' */
86         if (s1->str[i] > s2->str[i]) {
87                 return 1;
88         } else if (s1->str[i] < s2->str[i]) {
89                 return -1;
90         }
91         return 0; /* same length */
92 }
93
94 /*
95  * match example
96  *  astr:    XXXXYYYYZZZZ
97  *  suffix:       YYYZZZZ
98  *
99  */
100 EXPORT Bool ascstr_suffixcmp(ascstr_t *astr, ascstr_t *suffix)
101 {
102         if (astr->len < suffix->len) {
103                 return False;
104         }
105         if (strncmp(astr->str + astr->len - suffix->len, suffix->str, suffix->len) != 0) {
106                 return False;
107         }
108
109         return True;
110 }
111
112 /*
113  * match example
114  *  astr:    XXXXYYYYZZZZ
115  *  prefix:  XXXXYY
116  *
117  */
118 EXPORT Bool ascstr_prefixcmp(ascstr_t *astr, ascstr_t *prefix)
119 {
120         if (astr->len < prefix->len) {
121                 return False;
122         }
123         if (strncmp(astr->str, prefix->str, prefix->len) != 0) {
124                 return False;
125         }
126
127         return True;
128 }
129
130 EXPORT W ascstr_initialize(ascstr_t *astr)
131 {
132         astr->str = malloc(sizeof(UB));
133         if (astr->str == NULL) {
134                 return -1;
135         }
136         astr->str[0] = '\0';
137         astr->len = 0;
138         return 0;
139 }
140
141 EXPORT VOID ascstr_finalize(ascstr_t *astr)
142 {
143         free(astr->str);
144 }
145
146 struct httpcookie_t_ {
147         QUEUE que;
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 */
154         ascstr_t comment;
155         ascstr_t domain;
156         Bool persistent;
157         STIME expires;
158         ascstr_t path;
159         ascstr_t version;
160         Bool secure;
161 };
162 typedef struct httpcookie_t_ httpcookie_t;
163
164 LOCAL ascstr_t* httpcookie_getvaliddomain(httpcookie_t *cookie)
165 {
166         if (cookie->domain.len != 0) {
167                 return &cookie->domain;
168         }
169         return &cookie->origin_host;
170 }
171
172 LOCAL ascstr_t* httpcookie_getvalidpath(httpcookie_t *cookie)
173 {
174         if (cookie->path.len != 0) {
175                 return &cookie->path;
176         }
177         return &cookie->origin_path;
178 }
179
180 LOCAL Bool httpcookie_isvalueset(httpcookie_t *cookie)
181 {
182         if (cookie->attr.len == 0) {
183                 return False;
184         }
185         if (cookie->name.len == 0) {
186                 return False;
187         }
188         return True;
189 }
190
191 /* check replace condition. */
192 LOCAL Bool httpcookie_issamekey(httpcookie_t *cookie1, httpcookie_t *cookie2)
193 {
194         W cmp;
195         ascstr_t *as1, *as2;
196
197         cmp = ascstr_cmp(&cookie1->attr, &cookie2->attr);
198         if (cmp != 0) {
199                 return False;
200         }
201         as1 = httpcookie_getvaliddomain(cookie1);
202         as2 = httpcookie_getvaliddomain(cookie2);
203         cmp = ascstr_cmp(as1, as2);
204         if (cmp != 0) {
205                 return False;
206         }
207         return True;
208 }
209
210 LOCAL httpcookie_t* httpcookie_nextnode(httpcookie_t *cookie)
211 {
212         return (httpcookie_t*)cookie->que.next;
213 }
214
215 LOCAL VOID httpcookie_setexpires(httpcookie_t *cookie, STIME expires)
216 {
217         cookie->persistent = True;
218         cookie->expires = expires;
219 }
220
221 LOCAL VOID httpcookie_QueRemove(httpcookie_t *cookie)
222 {
223         QueRemove(&cookie->que);
224         QueInit(&cookie->que);
225 }
226
227 LOCAL VOID httpcookie_QueInsert(httpcookie_t *entry, httpcookie_t *que)
228 {
229         QueInsert(&entry->que, &que->que);
230 }
231
232 LOCAL W httpcookie_initialize(httpcookie_t *cookie, UB *host, W host_len, UB *path, W path_len)
233 {
234         W err;
235
236         QueInit(&cookie->que);
237         err = ascstr_initialize(&cookie->origin_host);
238         if (err < 0) {
239                 goto error_originhost;
240         }
241         err = ascstr_appendstr(&cookie->origin_host, host, host_len);
242         if (err < 0) {
243                 goto error_originhost_append;
244         }
245         err = ascstr_initialize(&cookie->origin_path);
246         if (err < 0) {
247                 goto error_originpath;
248         }
249         err = ascstr_appendstr(&cookie->origin_path, path, path_len);
250         if (err < 0) {
251                 goto error_originpath_append;
252         }
253         err = ascstr_initialize(&cookie->attr);
254         if (err < 0) {
255                 goto error_attr;
256         }
257         err = ascstr_initialize(&cookie->name);
258         if (err < 0) {
259                 goto error_name;
260         }
261         err = ascstr_initialize(&cookie->comment);
262         if (err < 0) {
263                 goto error_comment;
264         }
265         err = ascstr_initialize(&cookie->domain);
266         if (err < 0) {
267                 goto error_domain;
268         }
269         err = ascstr_initialize(&cookie->path);
270         if (err < 0) {
271                 goto error_path;
272         }
273         err = ascstr_initialize(&cookie->version);
274         if (err < 0) {
275                 goto error_version;
276         }
277
278         cookie->persistent = False;
279         cookie->secure = False;
280         cookie->expires = 0;
281
282         return 0;
283
284         ascstr_finalize(&cookie->version);
285 error_version:
286         ascstr_finalize(&cookie->path);
287 error_path:
288         ascstr_finalize(&cookie->domain);
289 error_domain:
290         ascstr_finalize(&cookie->comment);
291 error_comment:
292         ascstr_finalize(&cookie->name);
293 error_name:
294         ascstr_finalize(&cookie->attr);
295 error_attr:
296 error_originpath_append:
297         ascstr_finalize(&cookie->origin_path);
298 error_originpath:
299 error_originhost_append:
300         ascstr_finalize(&cookie->origin_host);
301 error_originhost:
302         return err;
303 }
304
305 LOCAL VOID httpcookie_finalize(httpcookie_t *cookie)
306 {
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);
316 }
317
318 LOCAL httpcookie_t* httpcookie_new(UB *host, W host_len, UB *path, W path_len)
319 {
320         httpcookie_t *cookie;
321         W err;
322
323         cookie = malloc(sizeof(httpcookie_t));
324         if (cookie == NULL) {
325                 return NULL;
326         }
327         err = httpcookie_initialize(cookie, host, host_len, path, path_len);
328         if (err < 0) {
329                 free(cookie);
330                 return NULL;
331         }
332         return cookie;
333 }
334
335 LOCAL VOID httpcookie_delete(httpcookie_t *cookie)
336 {
337         httpcookie_finalize(cookie);
338         free(cookie);
339 }
340
341 struct cookiedb_t_ {
342         QUEUE sentinel;
343         LINK *lnk;
344         W rectype;
345         UH subtype;
346 };
347
348 LOCAL httpcookie_t* cookiedb_sentinelnode(cookiedb_t *db)
349 {
350         return (httpcookie_t*)&db->sentinel;
351 }
352
353 struct cookiedb_writeiterator_t_ {
354         cookiedb_t *origin;
355         ascstr_t host;
356         ascstr_t path;
357         Bool secure;
358         STIME time;
359         httpcookie_t *current;
360 };
361 typedef struct cookiedb_writeiterator_t_ cookiedb_writeiterator_t;
362
363 LOCAL W count_priod(ascstr_t *str)
364 {
365         W i,count;
366
367         count = 0;
368         for (i = 0; i < str->len; i++) {
369                 if (str->str[i] == '.') {
370                         count++;
371                 }
372         }
373
374         return count;
375 }
376
377 LOCAL Bool check_specified_TLD(ascstr_t *domain)
378 {
379         if (strncmp(domain->str + domain->len - 4, ".net", 4) == 0) {
380                 return True;
381         }
382         if (strncmp(domain->str + domain->len - 4, ".com", 4) == 0) {
383                 return True;
384         }
385         if (strncmp(domain->str + domain->len - 4, ".edu", 4) == 0) {
386                 return True;
387         }
388         if (strncmp(domain->str + domain->len - 4, ".org", 4) == 0) {
389                 return True;
390         }
391         if (strncmp(domain->str + domain->len - 4, ".gov", 4) == 0) {
392                 return True;
393         }
394         if (strncmp(domain->str + domain->len - 4, ".mil", 4) == 0) {
395                 return True;
396         }
397         if (strncmp(domain->str + domain->len - 4, ".int", 4) == 0) {
398                 return True;
399         }
400         /* TODO: other TLDs. */
401         return False;
402 }
403
404 LOCAL Bool cookiedb_writeiterator_checksendcondition_domaincheck(cookiedb_writeiterator_t *iter, httpcookie_t *cookie)
405 {
406         Bool ok;
407
408         if (cookie->domain.len != 0) {
409                 if (cookie->domain.len == (iter->host.len + 1)) {
410                         /* for
411                          *  domain = .xxx.yyy.zzz
412                          *  origin =  xxx.yyy.zzz
413                          */
414                         if (strncmp(cookie->domain.str + 1, iter->host.str, iter->host.len) != 0) {
415                                 return False;
416                         }
417                 } else {
418                         ok = ascstr_suffixcmp(&iter->host, &cookie->domain);
419                         if (ok == False) {
420                                 return False;
421                         }
422                 }
423                 /* count period number is not need for counting in insertion to queue. */
424         } else {
425                 ok = ascstr_suffixcmp(&iter->host, &cookie->origin_host);
426                 if (ok == False) {
427                         return False;
428                 }
429         }
430
431         return True;
432 }
433
434 LOCAL Bool cookiedb_writeitereator_pathcheck(cookiedb_writeiterator_t *iter, httpcookie_t *cookie)
435 {
436         Bool ok;
437         if (cookie->path.len != 0) {
438                 ok = ascstr_prefixcmp(&iter->path, &cookie->path);
439         } else {
440                 ok = ascstr_prefixcmp(&iter->path, &cookie->origin_path);
441         }
442         return True;
443 }
444
445 LOCAL Bool cookiedb_writeiterator_checksendcondition(cookiedb_writeiterator_t *iter, httpcookie_t *cookie)
446 {
447         Bool ok;
448
449         if (cookie->secure == True) {
450                 if (iter->secure != True) {
451                         return False;
452                 }
453         }
454         if (cookie->persistent == True) {
455                 if (cookie->expires < iter->time) {
456                         return False;
457                 }
458         }
459         ok = cookiedb_writeiterator_checksendcondition_domaincheck(iter, cookie);
460         if (ok == False) {
461                 return False;
462         }
463         ok = cookiedb_writeitereator_pathcheck(iter, cookie);
464         if (ok == False) {
465                 return False;
466         }
467
468         return True;
469 }
470
471 LOCAL Bool cookiedb_writeiterator_next(cookiedb_writeiterator_t *iter, httpcookie_t **cookie)
472 {
473         httpcookie_t *senti;
474         Bool send;
475
476         senti = cookiedb_sentinelnode(iter->origin);
477         for (;;) {
478                 if (iter->current == senti) {
479                         break;
480                 }
481                 send = cookiedb_writeiterator_checksendcondition(iter, iter->current);
482                 if (send == True) {
483                         break;
484                 }
485                 iter->current = httpcookie_nextnode(iter->current);
486         }
487         if (iter->current != senti) {
488                 *cookie = iter->current;
489                 iter->current = httpcookie_nextnode(iter->current);
490                 return True;
491         }
492
493         return False;
494 }
495
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)
497 {
498         W err;
499         httpcookie_t *senti;
500
501         err = ascstr_initialize(&iter->host);
502         if (err < 0) {
503                 return err;
504         }
505         err = ascstr_appendstr(&iter->host, host, host_len);
506         if (err < 0) {
507                 ascstr_finalize(&iter->host);
508                 return err;
509         }
510         err = ascstr_initialize(&iter->path);
511         if (err < 0) {
512                 ascstr_finalize(&iter->host);
513                 return err;
514         }
515         err = ascstr_appendstr(&iter->path, path, path_len);
516         if (err < 0) {
517                 ascstr_finalize(&iter->path);
518                 ascstr_finalize(&iter->host);
519                 return err;
520         }
521
522         iter->origin = db;
523         iter->secure = secure;
524         iter->time = time;
525         senti = cookiedb_sentinelnode(db);
526         iter->current = httpcookie_nextnode(senti);
527
528         return 0;
529 }
530
531 LOCAL VOID cookiedb_writeiterator_finalize(cookiedb_writeiterator_t *iter)
532 {
533         ascstr_finalize(&iter->path);
534         ascstr_finalize(&iter->host);
535 }
536
537 struct cookiedb_writeheadercontext_t_ {
538         cookiedb_writeiterator_t iter;
539         enum {
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,
547         } state;
548         httpcookie_t *current;
549 };
550
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";
555
556 EXPORT Bool cookiedb_writeheadercontext_makeheader(cookiedb_writeheadercontext_t *context, UB **str, W *len)
557 {
558         Bool cont;
559
560         switch (context->state) {
561         case COOKIEDB_WRITEITERATORCONTEXT_STATE_START:
562                 cont = cookiedb_writeiterator_next(&context->iter, &context->current);
563                 if (cont == False) {
564                         return False;
565                 }
566                 *str = cookiedb_writeheader_context_headername;
567                 *len = 8;
568                 context->state = COOKIEDB_WRITEITERATORCONTEXT_STATE_NAME;
569                 return True;
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;
574                 return True;
575         case COOKIEDB_WRITEITERATORCONTEXT_STATE_EQUAL:
576                 *str = cookiedb_writeheader_context_equal;
577                 *len = 1;
578                 context->state = COOKIEDB_WRITEITERATORCONTEXT_STATE_VALUE;
579                 return True;
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;
584                 return True;
585         case COOKIEDB_WRITEITERATORCONTEXT_STATE_COLON:
586                 *str = cookiedb_writeheader_context_colon;
587                 cont = cookiedb_writeiterator_next(&context->iter, &context->current);
588                 if (cont == False) {
589                         *len = 1;
590                         context->state = COOKIEDB_WRITEITERATORCONTEXT_STATE_CRLF;
591                 } else {
592                         *len = 2;
593                         context->state = COOKIEDB_WRITEITERATORCONTEXT_STATE_NAME;
594                 }
595                 return True;
596         case COOKIEDB_WRITEITERATORCONTEXT_STATE_CRLF:
597                 *str = cookiedb_writeheader_context_crlf;
598                 *len = 2;
599                 context->state = COOKIEDB_WRITEITERATORCONTEXT_STATE_END;
600                 return True;
601         case COOKIEDB_WRITEITERATORCONTEXT_STATE_END:
602                 return False;
603         }
604
605         return False;
606 }
607
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)
609 {
610         cookiedb_writeheadercontext_t *context;
611         W err;
612
613         context = (cookiedb_writeheadercontext_t*)malloc(sizeof(cookiedb_writeheadercontext_t));
614         if (context == NULL) {
615                 return NULL;
616         }
617         err = cookiedb_writeiterator_initialize(&context->iter, db, host, host_len, path, path_len, secure, time);
618         if (err < 0) {
619                 free(context);
620                 return NULL;
621         }
622         context->state = COOKIEDB_WRITEITERATORCONTEXT_STATE_START;
623
624         return context;
625 }
626
627 LOCAL VOID cookiedb_writeheadercontext_delete(cookiedb_writeheadercontext_t *context)
628 {
629         cookiedb_writeiterator_finalize(&context->iter);
630         free(context);
631 }
632
633 EXPORT cookiedb_writeheadercontext_t* cookiedb_startheaderwrite(cookiedb_t *db, UB *host, W host_len, UB *path, W path_len, Bool secure, STIME time)
634 {
635         cookiedb_writeheadercontext_t *context;
636
637         context = cookiedb_writeheadercontext_new(db, host, host_len, path, path_len, secure, time);
638         if (context == NULL) {
639                 return NULL;
640         }
641
642         return context;
643 }
644
645 EXPORT VOID cookiedb_endheaderwrite(cookiedb_t *db, cookiedb_writeheadercontext_t *context)
646 {
647         cookiedb_writeheadercontext_delete(context);
648 }
649
650 struct cookiedb_readheadercontext_t_ {
651         ascstr_t host;
652         ascstr_t path;
653         STIME current;
654         QUEUE sentinel;
655         enum {
656                 COOKIEDB_READHEADERCONTEXT_STATE_START,
657                 COOKIEDB_READHEADERCONTEXT_STATE_NAMEATTR,
658                 COOKIEDB_READHEADERCONTEXT_STATE_OTHERVAL,
659         } state;
660         httpcookie_t *reading;
661 };
662
663 LOCAL VOID cookiedb_readheadercontext_insertcookie(cookiedb_readheadercontext_t *context, httpcookie_t *cookie)
664 {
665         QueInsert(&cookie->que, &context->sentinel);
666 }
667
668 EXPORT W cookiedb_readheadercontext_appendchar_attr(cookiedb_readheadercontext_t *context, UB ch)
669 {
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);
674                 }
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 */
678                 }
679         }
680         return ascstr_appendstr(&context->reading->attr, &ch, 1);
681 }
682
683 LOCAL W cookiedb_readheadercontext_appdatechar_common(cookiedb_readheadercontext_t *context, ascstr_t *target, UB ch)
684 {
685         if (context->state == COOKIEDB_READHEADERCONTEXT_STATE_START) {
686                 return 0;
687         }
688         context->state = COOKIEDB_READHEADERCONTEXT_STATE_OTHERVAL;
689         return ascstr_appendstr(target, &ch, 1);
690 }
691
692 EXPORT W cookiedb_readheadercontext_appendchar_name(cookiedb_readheadercontext_t *context, UB ch)
693 {
694         return cookiedb_readheadercontext_appdatechar_common(context, &context->reading->name, ch);
695 }
696
697 EXPORT W cookiedb_readheadercontext_appendchar_comment(cookiedb_readheadercontext_t *context, UB ch)
698 {
699         return cookiedb_readheadercontext_appdatechar_common(context, &context->reading->comment, ch);
700 }
701
702 EXPORT W cookiedb_readheadercontext_appendchar_domain(cookiedb_readheadercontext_t *context, UB ch)
703 {
704         return cookiedb_readheadercontext_appdatechar_common(context, &context->reading->domain, ch);
705 }
706
707 EXPORT W cookiedb_readheadercontext_appendchar_path(cookiedb_readheadercontext_t *context, UB ch)
708 {
709         return cookiedb_readheadercontext_appdatechar_common(context, &context->reading->path, ch);
710 }
711
712 EXPORT W cookiedb_readheadercontext_appendchar_version(cookiedb_readheadercontext_t *context, UB ch)
713 {
714         return cookiedb_readheadercontext_appdatechar_common(context, &context->reading->version, ch);
715 }
716
717 EXPORT W cookiedb_readheadercontext_setsecure(cookiedb_readheadercontext_t *context)
718 {
719         if (context->state == COOKIEDB_READHEADERCONTEXT_STATE_START) {
720                 return 0;
721         }
722         context->state = COOKIEDB_READHEADERCONTEXT_STATE_OTHERVAL;
723
724         context->reading->secure = True;
725
726         return 0;
727 }
728
729 EXPORT W cookiedb_readheadercontext_setexpires(cookiedb_readheadercontext_t *context, STIME expires)
730 {
731         if (context->state == COOKIEDB_READHEADERCONTEXT_STATE_START) {
732                 return 0;
733         }
734         context->state = COOKIEDB_READHEADERCONTEXT_STATE_OTHERVAL;
735
736         httpcookie_setexpires(context->reading, expires);
737
738         return 0;
739 }
740
741 EXPORT W cookiedb_readheadercontext_setmaxage(cookiedb_readheadercontext_t *context, W seconds)
742 {
743         if (seconds <= 0) {
744                 return 0;
745         }
746
747         httpcookie_setexpires(context->reading, context->current + seconds);
748
749         return 0;
750 }
751
752 LOCAL httpcookie_t* cookiedb_readheadercontext_prevcookie(cookiedb_readheadercontext_t *context)
753 {
754         Bool empty;
755         empty = isQueEmpty(&context->sentinel);
756         if (empty == True) {
757                 return NULL;
758         }
759         return (httpcookie_t*)context->sentinel.prev;
760 }
761
762 LOCAL cookiedb_readheadercontext_t* cookiedb_readheadercontext_new(UB *host, W host_len, UB *path, W path_len, STIME time)
763 {
764         cookiedb_readheadercontext_t *context;
765         W err;
766
767         context = (cookiedb_readheadercontext_t*)malloc(sizeof(cookiedb_readheadercontext_t));
768         if (context == NULL) {
769                 return NULL;
770         }
771         err = ascstr_initialize(&context->host);
772         if (err < 0) {
773                 free(context);
774                 return NULL;
775         }
776         err = ascstr_appendstr(&context->host, host, host_len);
777         if (err < 0) {
778                 ascstr_finalize(&context->host);
779                 free(context);
780                 return NULL;
781         }
782         err = ascstr_initialize(&context->path);
783         if (err < 0) {
784                 ascstr_finalize(&context->host);
785                 free(context);
786                 return NULL;
787         }
788         err = ascstr_appendstr(&context->path, path, path_len);
789         if (err < 0) {
790                 ascstr_finalize(&context->path);
791                 ascstr_finalize(&context->host);
792                 free(context);
793                 return NULL;
794         }
795         context->reading = NULL;
796         QueInit(&context->sentinel);
797         context->state = COOKIEDB_READHEADERCONTEXT_STATE_START;
798         context->current = time;
799
800         return context;
801 }
802
803 LOCAL VOID cookiedb_readheadercontext_delete(cookiedb_readheadercontext_t *context)
804 {
805         httpcookie_t *cookie;
806
807         for (;;) {
808                 cookie = cookiedb_readheadercontext_prevcookie(context);
809                 if (cookie == NULL) {
810                         break;
811                 }
812                 httpcookie_delete(cookie);
813         }
814         if (context->reading != NULL) {
815                 httpcookie_delete(context->reading);
816         }
817
818         ascstr_finalize(&context->path);
819         ascstr_finalize(&context->host);
820         free(context);
821 }
822
823 EXPORT cookiedb_readheadercontext_t* cookiedb_startheaderread(cookiedb_t *db, UB *host, W host_len, UB *path, W path_len, STIME time)
824 {
825         cookiedb_readheadercontext_t *context;
826
827         context = cookiedb_readheadercontext_new(host, host_len, path, path_len, time);
828         if (context == NULL) {
829                 return NULL;
830         }
831
832         return context;
833 }
834
835 LOCAL VOID cookiedb_insertcookie(cookiedb_t *db, httpcookie_t *cookie)
836 {
837         httpcookie_t *senti, *node;
838         ascstr_t *as_a, *as_n;
839         W cmp;
840         Bool samekey;
841
842         senti = cookiedb_sentinelnode(db);
843         node = httpcookie_nextnode(senti);
844         for (;;) {
845                 if (node == senti) {
846                         httpcookie_QueInsert(cookie, senti);
847                         break;
848                 }
849                 as_n = httpcookie_getvalidpath(node);
850                 as_a = httpcookie_getvalidpath(cookie);
851                 cmp = ascstr_cmp(as_n, as_a);
852                 if (cmp == 0) {
853                         samekey = httpcookie_issamekey(node, cookie);
854                         if (samekey == True) {
855                                 httpcookie_QueInsert(cookie, node);
856                                 httpcookie_delete(node);
857                                 break;
858                         }
859                 } else if (cmp < 0) {
860                         httpcookie_QueInsert(cookie, node);
861                         break;
862                 }
863                 node = httpcookie_nextnode(node);
864         }
865 }
866
867 LOCAL Bool cookiedb_checkinsertioncondition(cookiedb_t *db, httpcookie_t *cookie, STIME current)
868 {
869         W count;
870         Bool ok;
871
872         /* domain check */
873         if (cookie->domain.len != 0) {
874                 if (cookie->domain.str[0] != '.') { /* is not error and add period? */
875                         return False;
876                 }
877                 /* same as cookiedb_writeiterator_checksendcondition */
878                 count = count_priod(&cookie->domain);
879                 ok = check_specified_TLD(&cookie->domain);
880                 if (ok == True) {
881                         if (count < 2) {
882                                 return False;
883                         }
884                 } else {
885                         if (count < 3) {
886                                 return False;
887                         }
888                 }
889                 /* domain and request host check */
890                 if (cookie->domain.len == (cookie->origin_host.len + 1)) {
891                         /* for
892                          *  domain = .xxx.yyy.zzz
893                          *  origin =  xxx.yyy.zzz
894                          */
895                         if (strncmp(cookie->domain.str + 1, cookie->origin_host.str, cookie->origin_host.len) != 0) {
896                                 return False;
897                         }
898                 } else {
899                         ok = ascstr_suffixcmp(&cookie->origin_host, &cookie->domain);
900                         if (ok == False) {
901                                 return False;
902                         }
903                 }
904         }
905
906         /* expire check */
907         if (cookie->expires == 0) {
908                 return True;
909         }
910         if (cookie->expires >= current) {
911                 return True;
912         }
913
914         return False;
915 }
916
917 LOCAL VOID cookiedb_insertwithcheck(cookiedb_t *db, httpcookie_t *cookie, STIME current)
918 {
919         Bool save;
920         save = cookiedb_checkinsertioncondition(db, cookie, current);
921         if (save == True) {
922                 cookiedb_insertcookie(db, cookie);
923         } else {
924                 httpcookie_delete(cookie);
925         }
926 }
927
928 EXPORT VOID cookiedb_endheaderread(cookiedb_t *db, cookiedb_readheadercontext_t *context)
929 {
930         httpcookie_t *cookie;
931         Bool ok;
932
933         for (;;) {
934                 cookie = cookiedb_readheadercontext_prevcookie(context);
935                 if (cookie == NULL) {
936                         break;
937                 }
938                 httpcookie_QueRemove(cookie);
939                 cookiedb_insertwithcheck(db, cookie, context->current);
940         }
941         if (context->reading != NULL) {
942                 ok = httpcookie_isvalueset(context->reading);
943                 if (ok == True) {
944                         httpcookie_QueRemove(context->reading);
945                         cookiedb_insertwithcheck(db, context->reading, context->current);
946                 } else {
947                         httpcookie_delete(context->reading);
948                 }
949                 context->reading = NULL;
950         }
951
952         cookiedb_readheadercontext_delete(context);
953 }
954
955 EXPORT VOID cookiedb_clearallcookie(cookiedb_t *db)
956 {
957         httpcookie_t *cookie;
958         Bool empty;
959         W fd, err = 0;
960
961         for (;;) {
962                 empty = isQueEmpty(&db->sentinel);
963                 if (empty == True) {
964                         break;
965                 }
966                 cookie = (httpcookie_t*)db->sentinel.prev;
967                 httpcookie_delete(cookie);
968         }
969
970         /* clear file */
971         fd = opn_fil(db->lnk, F_UPDATE, NULL);
972         if (fd < 0) {
973                 return;
974         }
975         err = fnd_rec(fd, F_TOPEND, 1 << db->rectype, db->subtype, NULL);
976         if (err < 0) {
977                 cls_fil(fd);
978                 return;
979         }
980         err = loc_rec(fd, F_LOCK);
981         if (err < 0) {
982                 cls_fil(fd);
983                 return;
984         }
985         trc_rec(fd, 0);
986         err = loc_rec(fd, F_UNLOCK);
987         cls_fil(fd);
988 }
989
990 LOCAL W cookiedb_append_astr_recode(W fd, ascstr_t *astr)
991 {
992         return wri_rec(fd, -1, astr->str, astr->len, NULL, NULL, 0);
993 }
994
995 /* tmp */
996 LOCAL UB dec[] = "0123456789";
997 LOCAL W UW_to_str(UW n, UB *str)
998 {
999         W i = 0,digit,draw = 0;
1000
1001         digit = n / 1000000000 % 10;
1002         if ((digit != 0)||(draw != 0)) {
1003                 str[i++] = dec[digit];
1004                 draw = 1;
1005         }
1006         digit = n / 100000000 % 10;
1007         if ((digit != 0)||(draw != 0)) {
1008                 str[i++] = dec[digit];
1009                 draw = 1;
1010         }
1011         digit = n / 10000000 % 10;
1012         if ((digit != 0)||(draw != 0)) {
1013                 str[i++] = dec[digit];
1014                 draw = 1;
1015         }
1016         digit = n / 1000000 % 10;
1017         if ((digit != 0)||(draw != 0)) {
1018                 str[i++] = dec[digit];
1019                 draw = 1;
1020         }
1021         digit = n / 100000 % 10;
1022         if ((digit != 0)||(draw != 0)) {
1023                 str[i++] = dec[digit];
1024                 draw = 1;
1025         }
1026         digit = n / 10000 % 10;
1027         if ((digit != 0)||(draw != 0)) {
1028                 str[i++] = dec[digit];
1029                 draw = 1;
1030         }
1031         digit = n / 1000 % 10;
1032         if ((digit != 0)||(draw != 0)) {
1033                 str[i++] = dec[digit];
1034                 draw = 1;
1035         }
1036         digit = n / 100 % 10;
1037         if ((digit != 0)||(draw != 0)) {
1038                 str[i++] = dec[digit];
1039                 draw = 1;
1040         }
1041         digit = n / 10 % 10;
1042         if ((digit != 0)||(draw != 0)) {
1043                 str[i++] = dec[digit];
1044                 draw = 1;
1045         }
1046         digit = n % 10;
1047         str[i++] = dec[digit];
1048
1049         return i;
1050 }
1051
1052 LOCAL W cookiedb_append_STIME_recode(W fd, STIME time)
1053 {
1054         UB str[10];
1055         W len;
1056
1057         len = UW_to_str(time, str);
1058         return wri_rec(fd, -1, str, len, NULL, NULL, 0);
1059 }
1060
1061 LOCAL W cookiedb_writecookietorecord(httpcookie_t *cookie, W fd)
1062 {
1063         W err;
1064         UB paren[2] = "<>";
1065         UB secure[6] = "secure";
1066         UB nl[1] = "\n";
1067         ascstr_t a_paren = {paren, 2};
1068         ascstr_t a_secure = {secure, 6};
1069         ascstr_t a_nl = {nl, 1};
1070
1071         err = cookiedb_append_astr_recode(fd, &cookie->origin_host);
1072         if (err < 0) {
1073                 return err;
1074         }
1075         err = cookiedb_append_astr_recode(fd, &a_paren);
1076         if (err < 0) {
1077                 return err;
1078         }
1079         err = cookiedb_append_astr_recode(fd, &cookie->origin_path);
1080         if (err < 0) {
1081                 return err;
1082         }
1083         err = cookiedb_append_astr_recode(fd, &a_paren);
1084         if (err < 0) {
1085                 return err;
1086         }
1087         err = cookiedb_append_astr_recode(fd, &cookie->attr);
1088         if (err < 0) {
1089                 return err;
1090         }
1091         err = cookiedb_append_astr_recode(fd, &a_paren);
1092         if (err < 0) {
1093                 return err;
1094         }
1095         err = cookiedb_append_astr_recode(fd, &cookie->name);
1096         if (err < 0) {
1097                 return err;
1098         }
1099         err = cookiedb_append_astr_recode(fd, &a_paren);
1100         if (err < 0) {
1101                 return err;
1102         }
1103         err = cookiedb_append_astr_recode(fd, &cookie->comment);
1104         if (err < 0) {
1105                 return err;
1106         }
1107         err = cookiedb_append_astr_recode(fd, &a_paren);
1108         if (err < 0) {
1109                 return err;
1110         }
1111         err = cookiedb_append_astr_recode(fd, &cookie->domain);
1112         if (err < 0) {
1113                 return err;
1114         }
1115         err = cookiedb_append_astr_recode(fd, &a_paren);
1116         if (err < 0) {
1117                 return err;
1118         }
1119         err = cookiedb_append_STIME_recode(fd, cookie->expires);
1120         if (err < 0) {
1121                 return err;
1122         }
1123         err = cookiedb_append_astr_recode(fd, &a_paren);
1124         if (err < 0) {
1125                 return err;
1126         }
1127         err = cookiedb_append_astr_recode(fd, &cookie->path);
1128         if (err < 0) {
1129                 return err;
1130         }
1131         err = cookiedb_append_astr_recode(fd, &a_paren);
1132         if (err < 0) {
1133                 return err;
1134         }
1135         err = cookiedb_append_astr_recode(fd, &cookie->version);
1136         if (err < 0) {
1137                 return err;
1138         }
1139         err = cookiedb_append_astr_recode(fd, &a_paren);
1140         if (err < 0) {
1141                 return err;
1142         }
1143         if (cookie->secure == True) {
1144                 err = cookiedb_append_astr_recode(fd, &a_secure);
1145                 if (err < 0) {
1146                         return err;
1147                 }
1148         }
1149         err = cookiedb_append_astr_recode(fd, &a_paren);
1150         if (err < 0) {
1151                 return err;
1152         }
1153         err = cookiedb_append_astr_recode(fd, &a_nl);
1154         if (err < 0) {
1155                 return err;
1156         }
1157
1158         return 0;
1159 }
1160
1161 LOCAL W cookiedb_writecookiestorecord(cookiedb_t *db, W fd)
1162 {
1163         httpcookie_t *senti, *node;
1164         W err;
1165
1166         senti = cookiedb_sentinelnode(db);
1167         node = httpcookie_nextnode(senti);
1168         for (; node != senti; node = httpcookie_nextnode(node)) {
1169                 if (node->persistent == False) {
1170                         continue;
1171                 }
1172                 err = cookiedb_writecookietorecord(node, fd);
1173                 if (err < 0) {
1174                         return err;
1175                 }
1176         }
1177         return 0;
1178 }
1179
1180 EXPORT W cookiedb_writefile(cookiedb_t *db)
1181 {
1182         W fd, err = 0;
1183
1184         fd = opn_fil(db->lnk, F_UPDATE, NULL);
1185         if (fd < 0) {
1186                 return fd;
1187         }
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);
1191                 if (err < 0) {
1192                         return -1;
1193                 }
1194                 err = see_rec(fd, -1, 0, NULL);
1195                 if (err < 0) {
1196                         return -1;
1197                 }
1198         } else if (err < 0) {
1199                 cls_fil(fd);
1200                 return err;
1201         }
1202         err = loc_rec(fd, F_LOCK);
1203         if (err < 0) {
1204                 cls_fil(fd);
1205                 return err;
1206         }
1207         trc_rec(fd, 0);
1208         err = cookiedb_writecookiestorecord(db, fd);
1209         if (err < 0) {
1210                 DP_ER("cookiedb_writecookiestorecord error\n", err);
1211                 trc_rec(fd, 0);
1212         }
1213         err = loc_rec(fd, F_UNLOCK);
1214         cls_fil(fd);
1215         return err;
1216 }
1217
1218 struct cookiedb_readfilecontext_t_ {
1219         enum {
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,
1232         } state;
1233         cookiedb_t *db;
1234         httpcookie_t *buf;
1235         UW time;
1236         tokenchecker_t securecheck;
1237 };
1238 typedef struct cookiedb_readfilecontext_t_ cookiedb_readfilecontext_t;
1239
1240 LOCAL Bool cookiedb_readfilecontext_cookiecheck(httpcookie_t *cookie)
1241 {
1242         if (cookie->origin_host.len == 0) {
1243                 return False;
1244         }
1245         if (cookie->origin_path.len == 0) {
1246                 return False;
1247         }
1248         if (cookie->attr.len == 0) {
1249                 return False;
1250         }
1251         if (cookie->name.len == 0) {
1252                 return False;
1253         }
1254         if (cookie->persistent == False) {
1255                 return False;
1256         }
1257         return True;
1258 }
1259
1260 LOCAL W cookiedb_readfilecontext_inputcommand(cookiedb_readfilecontext_t *ctx, psvlexer_result_t *cmd)
1261 {
1262         W i,err,val,ret;
1263         UB c;
1264         Bool ok;
1265
1266         if (cmd->type == PSVLEXER_RESULT_FIELDEND) {
1267                 ok = cookiedb_readfilecontext_cookiecheck(ctx->buf);
1268                 if (ok == False) {
1269                         httpcookie_delete(ctx->buf);
1270                 } else {
1271                         cookiedb_insertcookie(ctx->db, ctx->buf);
1272                 }
1273                 ctx->buf = httpcookie_new(NULL, 0, NULL, 0);
1274                 if (ctx->buf == NULL) {
1275                         return -1; /* TODO */
1276                 }
1277                 ctx->state = COOKIEDB_READFILECONTEXT_STATE_ORIGIN_HOST;
1278         }
1279
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);
1286                         if (err < 0) {
1287                                 return err;
1288                         }
1289                 }
1290                 break;
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);
1296                         if (err < 0) {
1297                                 return err;
1298                         }
1299                 }
1300                 break;
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);
1306                         if (err < 0) {
1307                                 return err;
1308                         }
1309                 }
1310                 break;
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);
1316                         if (err < 0) {
1317                                 return err;
1318                         }
1319                 }
1320                 break;
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);
1326                         if (err < 0) {
1327                                 return err;
1328                         }
1329                 }
1330                 break;
1331         case COOKIEDB_READFILECONTEXT_STATE_DOMAIN:
1332                 if (cmd->type == PSVLEXER_RESULT_SEPARATION) {
1333                         ctx->state = COOKIEDB_READFILECONTEXT_STATE_EXPIRES;
1334                         ctx->time = 0;
1335                 } else if (cmd->type == PSVLEXER_RESULT_VALUE) {
1336                         err = ascstr_appendstr(&ctx->buf->domain, cmd->str, cmd->len);
1337                         if (err < 0) {
1338                                 return err;
1339                         }
1340                 }
1341                 break;
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++) {
1348                                 c = cmd->str[i];
1349                                 if (isdigit(c)) {
1350                                         ctx->time = ctx->time * 10 + c - '0';
1351                                 } else {
1352                                         ctx->state = COOKIEDB_READFILECONTEXT_STATE_EXPIRES_ERROR;
1353                                         break;
1354                                 }
1355                         }
1356                 }
1357                 break;
1358         case COOKIEDB_READFILECONTEXT_STATE_EXPIRES_ERROR:
1359                 if (cmd->type == PSVLEXER_RESULT_SEPARATION) {
1360                         ctx->state = COOKIEDB_READFILECONTEXT_STATE_PATH;
1361                 }
1362                 break;
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);
1368                         if (err < 0) {
1369                                 return err;
1370                         }
1371                 }
1372                 break;
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);
1379                         if (err < 0) {
1380                                 return err;
1381                         }
1382                 }
1383                 break;
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;
1390                         }
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);
1394                         }
1395                 }
1396                 break;
1397         case COOKIEDB_READFILECONTEXT_STATE_OTHER:
1398                 break;
1399         }
1400
1401         return 0;
1402 }
1403
1404 LOCAL tokenchecker_valuetuple_t nList_secure[] = {
1405         {"secure", 1}
1406 };
1407 LOCAL B eToken_secure[] = "<";
1408
1409 LOCAL W cookiedb_readfilecontext_initialize(cookiedb_readfilecontext_t *ctx, cookiedb_t *db)
1410 {
1411         ctx->buf = httpcookie_new(NULL, 0, NULL, 0);
1412         if (ctx->buf == NULL) {
1413                 return -1; /* TODO */
1414         }
1415         ctx->db = db;
1416         ctx->state = COOKIEDB_READFILECONTEXT_STATE_ORIGIN_HOST;
1417         tokenchecker_initialize(&ctx->securecheck, nList_secure, 1, eToken_secure);
1418         return 0;
1419 }
1420
1421 LOCAL VOID cookiedb_readfilecontext_finalize(cookiedb_readfilecontext_t *ctx)
1422 {
1423         tokenchecker_finalize(&ctx->securecheck);
1424         if (ctx->buf != NULL) {
1425                 httpcookie_delete(ctx->buf);
1426         }
1427 }
1428
1429 LOCAL W cookiedb_readcookiesfrommemory(cookiedb_t *db, UB *data, W len)
1430 {
1431         psvlexer_t lexer;
1432         psvlexer_result_t *result;
1433         cookiedb_readfilecontext_t context;
1434         W i,j,err,result_len;
1435
1436         err = psvlexer_initialize(&lexer);
1437         if (err < 0) {
1438                 return err;
1439         }
1440         err = cookiedb_readfilecontext_initialize(&context, db);
1441         if (err < 0) {
1442                 psvlexer_finalize(&lexer);
1443                 return err;
1444         }
1445         for (i = 0; i < len; i++) {
1446                 psvlexer_inputchar(&lexer, data + i, 1, &result, &result_len);
1447                 err = 0;
1448                 for (j = 0; j < result_len; j++) {
1449                         err = cookiedb_readfilecontext_inputcommand(&context, result + j);
1450                         if (err < 0) {
1451                                 break;
1452                         }
1453                 }
1454                 if (err < 0) {
1455                         break;
1456                 }
1457         }
1458         cookiedb_readfilecontext_finalize(&context);
1459         psvlexer_finalize(&lexer);
1460
1461         return 0;
1462 }
1463
1464 LOCAL W cookiedb_readcookiesfromrecord(cookiedb_t *db, W fd)
1465 {
1466         W err, r_len;
1467         UB *r_data;
1468
1469         err = rea_rec(fd, 0, NULL, 0, &r_len, NULL);
1470         if (err < 0) {
1471                 return err;
1472         }
1473         r_data = malloc(r_len);
1474         if (r_data == NULL) {
1475                 return err;
1476         }
1477         err = rea_rec(fd, 0, r_data, r_len, NULL, NULL);
1478         if (err < 0) {
1479                 free(r_data);
1480                 return err;
1481         }
1482
1483 /*
1484         {
1485                 W i;
1486                 printf("r_len = %d\n", r_len);
1487                 for (i = 0; i < r_len; i++) {
1488                         printf("%c", r_data[i]);
1489                 }
1490         }
1491 */
1492
1493         err = cookiedb_readcookiesfrommemory(db, r_data, r_len);
1494
1495         free(r_data);
1496
1497         return err;
1498 }
1499
1500 LOCAL VOID cookiedb_clearpersistentcookie(cookiedb_t *db)
1501 {
1502         httpcookie_t *senti, *node, *node2;
1503
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);
1510                         node = node2;
1511                 } else {
1512                         node = httpcookie_nextnode(node);
1513                 }
1514         }
1515 }
1516
1517 EXPORT W cookiedb_readfile(cookiedb_t *db)
1518 {
1519         W fd, err = 0;
1520
1521         fd = opn_fil(db->lnk, F_UPDATE, NULL);
1522         if (fd < 0) {
1523                 return fd;
1524         }
1525         err = fnd_rec(fd, F_TOPEND, 1 << db->rectype, db->subtype, NULL);
1526         if (err == ER_REC) {
1527                 cookiedb_clearpersistentcookie(db);
1528                 cls_fil(fd);
1529                 return 0;
1530         } else if (err < 0) {
1531                 cls_fil(fd);
1532                 return err;
1533         }
1534         err = loc_rec(fd, F_LOCK);
1535         if (err < 0) {
1536                 cls_fil(fd);
1537                 return err;
1538         }
1539         cookiedb_clearpersistentcookie(db);
1540         err = cookiedb_readcookiesfromrecord(db, fd);
1541         if (err < 0) {
1542                 trc_rec(fd, 0);
1543         }
1544         err = loc_rec(fd, F_UNLOCK);
1545         cls_fil(fd);
1546         return err;
1547 }
1548
1549 LOCAL W cookiedb_initialize(cookiedb_t *db, LINK *db_lnk, W rectype, UH subtype)
1550 {
1551         QueInit(&db->sentinel);
1552         db->lnk = db_lnk;
1553         db->rectype = rectype;
1554         db->subtype = subtype;
1555         return 0;
1556 }
1557
1558 LOCAL VOID cookiedb_finalize(cookiedb_t *db)
1559 {
1560         httpcookie_t *cookie;
1561         Bool empty;
1562
1563         for (;;) {
1564                 empty = isQueEmpty(&db->sentinel);
1565                 if (empty == True) {
1566                         break;
1567                 }
1568                 cookie = (httpcookie_t*)db->sentinel.prev;
1569                 httpcookie_delete(cookie);
1570         }
1571 }
1572
1573 EXPORT cookiedb_t* cookiedb_new(LINK *db_lnk, W rectype, UH subtype)
1574 {
1575         cookiedb_t *db;
1576         W err;
1577
1578         db = malloc(sizeof(cookiedb_t));
1579         if (db == NULL) {
1580                 return NULL;
1581         }
1582         err = cookiedb_initialize(db, db_lnk, rectype, subtype);
1583         if (err < 0) {
1584                 free(db);
1585                 return NULL;
1586         }
1587
1588         return db;
1589 }
1590
1591 EXPORT VOID cookiedb_delete(cookiedb_t *db)
1592 {
1593         cookiedb_finalize(db);
1594         free(db);
1595 }