#include <basic.h>
#include <bstdio.h>
#include <bstdlib.h>
+#include <bstring.h>
#include <bsys/queue.h>
#ifdef BCHAN_CONFIG_DEBUG
return 0;
}
+EXPORT W ascstr_cmp(ascstr_t *s1, ascstr_t *s2)
+{
+ W i,len;
+
+ len = s1->len > s2->len ? s2->len : s1->len;
+ for (i = 0; i < len; i++) {
+ if (s1->str[i] > s2->str[i]) {
+ return 1;
+ } else if (s1->str[i] < s2->str[i]) {
+ return -1;
+ }
+ }
+
+ /* check terminate char: '\0' */
+ if (s1->str[i] > s2->str[i]) {
+ return 1;
+ } else if (s1->str[i] < s2->str[i]) {
+ return -1;
+ }
+ return 0; /* same length */
+}
+
+/*
+ * match example
+ * astr: XXXXYYYYZZZZ
+ * suffix: YYYZZZZ
+ *
+ */
+EXPORT Bool ascstr_suffixcmp(ascstr_t *astr, ascstr_t *suffix)
+{
+ if (astr->len < suffix->len) {
+ return False;
+ }
+ if (strncmp(astr->str + astr->len - suffix->len, suffix->str, suffix->len) != 0) {
+ return False;
+ }
+
+ return True;
+}
+
EXPORT W ascstr_initialize(ascstr_t *astr)
{
astr->str = malloc(sizeof(UB));
struct httpcookie_t_ {
QUEUE que;
- /* requested host */
- ascstr_t host;
+ /* requested host and path */
+ ascstr_t origin_host;
+ ascstr_t origin_path;
/* Set-Cookie value */
ascstr_t attr; /* NAME string */
ascstr_t name; /* VALUE string */
};
typedef struct httpcookie_t_ httpcookie_t;
+LOCAL ascstr_t* httpcookie_getvaliddomain(httpcookie_t *cookie)
+{
+ if (cookie->domain.len != 0) {
+ return &cookie->domain;
+ }
+ return &cookie->origin_host;
+}
+
+LOCAL ascstr_t* httpcookie_getvalidpath(httpcookie_t *cookie)
+{
+ if (cookie->path.len != 0) {
+ return &cookie->path;
+ }
+ return &cookie->origin_path;
+}
+
+LOCAL Bool httpcookie_isvalueset(httpcookie_t *cookie)
+{
+ if (cookie->attr.len == 0) {
+ return False;
+ }
+ if (cookie->name.len == 0) {
+ return False;
+ }
+ return True;
+}
+
+/* check replace condition. */
+LOCAL Bool httpcookie_issamekey(httpcookie_t *cookie1, httpcookie_t *cookie2)
+{
+ W cmp;
+ ascstr_t *as1, *as2;
+
+ cmp = ascstr_cmp(&cookie1->attr, &cookie2->attr);
+ if (cmp != 0) {
+ return False;
+ }
+ as1 = httpcookie_getvaliddomain(cookie1);
+ as2 = httpcookie_getvaliddomain(cookie2);
+ cmp = ascstr_cmp(as1, as2);
+ if (cmp != 0) {
+ return False;
+ }
+ return True;
+}
+
LOCAL httpcookie_t* httpcookie_nextnode(httpcookie_t *cookie)
{
return (httpcookie_t*)cookie->que.next;
LOCAL VOID httpcookie_QueRemove(httpcookie_t *cookie)
{
QueRemove(&cookie->que);
+ QueInit(&cookie->que);
+}
+
+LOCAL VOID httpcookie_QueInsert(httpcookie_t *entry, httpcookie_t *que)
+{
+ QueInsert(&entry->que, &que->que);
}
-LOCAL W httpcookie_initialize(httpcookie_t *cookie, UB *host, W host_len)
+LOCAL W httpcookie_initialize(httpcookie_t *cookie, UB *host, W host_len, UB *path, W path_len)
{
W err;
QueInit(&cookie->que);
- err = ascstr_initialize(&cookie->host);
+ err = ascstr_initialize(&cookie->origin_host);
if (err < 0) {
- goto error_host;
+ goto error_originhost;
+ }
+ err = ascstr_appendstr(&cookie->origin_host, host, host_len);
+ if (err < 0) {
+ goto error_originhost_append;
+ }
+ err = ascstr_initialize(&cookie->origin_path);
+ if (err < 0) {
+ goto error_originpath;
+ }
+ err = ascstr_appendstr(&cookie->origin_path, path, path_len);
+ if (err < 0) {
+ goto error_originpath_append;
}
- ascstr_appendstr(&cookie->host, host, host_len);
err = ascstr_initialize(&cookie->attr);
if (err < 0) {
goto error_attr;
error_name:
ascstr_finalize(&cookie->attr);
error_attr:
- ascstr_finalize(&cookie->host);
-error_host:
+error_originpath_append:
+ ascstr_finalize(&cookie->origin_path);
+error_originpath:
+error_originhost_append:
+ ascstr_finalize(&cookie->origin_host);
+error_originhost:
return err;
}
ascstr_finalize(&cookie->comment);
ascstr_finalize(&cookie->name);
ascstr_finalize(&cookie->attr);
- ascstr_finalize(&cookie->host);
+ ascstr_finalize(&cookie->origin_path);
+ ascstr_finalize(&cookie->origin_host);
QueRemove(&cookie->que);
}
-LOCAL httpcookie_t* httpcookie_new(UB *host, W host_len)
+LOCAL httpcookie_t* httpcookie_new(UB *host, W host_len, UB *path, W path_len)
{
httpcookie_t *cookie;
W err;
if (cookie == NULL) {
return NULL;
}
- err = httpcookie_initialize(cookie, host, host_len);
+ err = httpcookie_initialize(cookie, host, host_len, path, path_len);
if (err < 0) {
free(cookie);
return NULL;
free(cookie);
}
-struct cookie_persistentdb_t_ {
+struct cookiedb_t_ {
QUEUE sentinel;
LINK *lnk;
};
-typedef struct cookie_persistentdb_t_ cookie_persistentdb_t;
-
-struct cookie_volatiledb_t_ {
- QUEUE sentinel;
-};
-typedef struct cookie_volatiledb_t_ cookie_volatiledb_t;
-
-struct cookiedb_t_ {
- cookie_volatiledb_t vdb;
- cookie_persistentdb_t pdb;
-};
-LOCAL httpcookie_t* cookie_persistentdb_sentinelnode(cookie_persistentdb_t *db)
+LOCAL httpcookie_t* cookiedb_sentinelnode(cookiedb_t *db)
{
return (httpcookie_t*)&db->sentinel;
}
-LOCAL VOID cookie_persistentdb_insertcookie(cookie_persistentdb_t *db, httpcookie_t *cookie)
-{
- QueInsert(&cookie->que, &db->sentinel);
-}
-
-LOCAL W cookie_persistentdb_initialize(cookie_persistentdb_t *db, LINK *db_lnk)
-{
- QueInit(&db->sentinel);
- db->lnk = db_lnk;
- return 0;
-}
+struct cookiedb_writeiterator_t_ {
+ cookiedb_t *origin;
+ ascstr_t host;
+ ascstr_t path;
+ Bool secure;
+ STIME time;
+ httpcookie_t *current;
+};
+typedef struct cookiedb_writeiterator_t_ cookiedb_writeiterator_t;
-LOCAL VOID cookie_persistentdb_finalize(cookie_persistentdb_t *db)
+LOCAL W count_priod(ascstr_t *str)
{
- httpcookie_t *cookie;
- Bool empty;
+ W i,count;
- for (;;) {
- empty = isQueEmpty(&db->sentinel);
- if (empty == True) {
- break;
+ count = 0;
+ for (i = 0; i < str->len; i++) {
+ if (str->str[i] == '.') {
+ count++;
}
- cookie = (httpcookie_t*)db->sentinel.prev;
- httpcookie_delete(cookie);
}
+
+ return count;
}
-LOCAL httpcookie_t* cookie_volatiledb_sentinelnode(cookie_volatiledb_t *db)
+LOCAL Bool check_specified_TLD(ascstr_t *domain)
{
- return (httpcookie_t*)&db->sentinel;
+ if (strncmp(domain->str + domain->len - 4, ".net", 4) == 0) {
+ return True;
+ }
+ if (strncmp(domain->str + domain->len - 4, ".com", 4) == 0) {
+ return True;
+ }
+ if (strncmp(domain->str + domain->len - 4, ".edu", 4) == 0) {
+ return True;
+ }
+ if (strncmp(domain->str + domain->len - 4, ".org", 4) == 0) {
+ return True;
+ }
+ if (strncmp(domain->str + domain->len - 4, ".gov", 4) == 0) {
+ return True;
+ }
+ if (strncmp(domain->str + domain->len - 4, ".mil", 4) == 0) {
+ return True;
+ }
+ if (strncmp(domain->str + domain->len - 4, ".int", 4) == 0) {
+ return True;
+ }
+ /* TODO: other TLDs. */
+ return False;
}
-LOCAL VOID cookie_volatiledb_insertcookie(cookie_volatiledb_t *db, httpcookie_t *cookie)
+LOCAL Bool cookiedb_writeiterator_checksendcondition_domaincheck(cookiedb_writeiterator_t *iter, httpcookie_t *cookie)
{
- QueInsert(&cookie->que, &db->sentinel);
+ Bool ok;
+ W count;
+
+ if (cookie->domain.len != 0) {
+ ok = ascstr_suffixcmp(&iter->host, &cookie->domain);
+ if (ok == False) {
+ return False;
+ }
+ count = count_priod(&cookie->domain);
+ ok = check_specified_TLD(&cookie->domain);
+ if (ok == True) {
+ if (count < 2) {
+ return False;
+ }
+ } else {
+ if (count < 3) {
+ return False;
+ }
+ }
+ } else {
+ ok = ascstr_suffixcmp(&iter->host, &cookie->origin_host);
+ if (ok == False) {
+ return False;
+ }
+ }
+
+ return True;
}
-LOCAL W cookie_volatiledb_initialize(cookie_volatiledb_t *db)
+LOCAL Bool cookiedb_writeitereator_pathcheck(ascstr_t *send_path, ascstr_t *origin_path)
{
- QueInit(&db->sentinel);
- return 0;
+ if (origin_path->len < send_path->len) {
+ return False;
+ }
+ if (strncmp(origin_path->str, send_path->str, send_path->len) != 0) {
+ return False;
+ }
+ return True;
}
-LOCAL VOID cookie_volatiledb_finalize(cookie_volatiledb_t *db)
+LOCAL Bool cookiedb_writeiterator_checksendcondition(cookiedb_writeiterator_t *iter, httpcookie_t *cookie)
{
- httpcookie_t *cookie;
- Bool empty;
+ Bool ok;
- for (;;) {
- empty = isQueEmpty(&db->sentinel);
- if (empty == True) {
- break;
+ if (cookie->secure == True) {
+ if (iter->secure != True) {
+ return False;
}
- cookie = (httpcookie_t*)db->sentinel.prev;
- httpcookie_delete(cookie);
}
-}
-
-struct cookiedb_writeiterator_t_ {
- cookiedb_t *origin;
- ascstr_t host;
- ascstr_t path;
- Bool secure;
- STIME time;
- httpcookie_t *current;
- enum {
- COOKIEDB_WRITEITERATOR_STATE_VDB,
- COOKIEDB_WRITEITERATOR_STATE_PDB,
- } state;
-};
-typedef struct cookiedb_writeiterator_t_ cookiedb_writeiterator_t;
+ if (cookie->persistent == True) {
+ if (cookie->expires < iter->time) {
+ return False;
+ }
+ }
+ ok = cookiedb_writeiterator_checksendcondition_domaincheck(iter, cookie);
+ if (ok == False) {
+ return False;
+ }
+ if (cookie->path.len != 0) {
+ ok = cookiedb_writeitereator_pathcheck(&iter->path, &cookie->path);
+ } else {
+ ok = cookiedb_writeitereator_pathcheck(&iter->path, &cookie->origin_path);
+ }
+ if (ok == False) {
+ return False;
+ }
-LOCAL Bool cookiedb_writeiterator_checksendcondition(cookiedb_writeiterator_t *iter, httpcookie_t *cookie)
-{
- return False;
+ return True;
}
LOCAL Bool cookiedb_writeiterator_next(cookiedb_writeiterator_t *iter, httpcookie_t **cookie)
httpcookie_t *senti;
Bool send;
- if (iter->state == COOKIEDB_WRITEITERATOR_STATE_VDB) {
- senti = cookie_volatiledb_sentinelnode(&iter->origin->vdb);
- for (;;) {
- if (iter->current == senti) {
- break;
- }
- send = cookiedb_writeiterator_checksendcondition(iter, iter->current);
- if (send == True) {
- break;
- }
- iter->current = httpcookie_nextnode(iter->current);
+ senti = cookiedb_sentinelnode(iter->origin);
+ for (;;) {
+ if (iter->current == senti) {
+ break;
}
- if (iter->current != senti) {
- *cookie = iter->current;
- iter->current = httpcookie_nextnode(iter->current);
- return True;
- } else {
- iter->state = COOKIEDB_WRITEITERATOR_STATE_PDB;
- senti = cookie_persistentdb_sentinelnode(&iter->origin->pdb);
- iter->current = httpcookie_nextnode(senti);
+ send = cookiedb_writeiterator_checksendcondition(iter, iter->current);
+ if (send == True) {
+ break;
}
+ iter->current = httpcookie_nextnode(iter->current);
}
- if (iter->state == COOKIEDB_WRITEITERATOR_STATE_PDB) {
- senti = cookie_persistentdb_sentinelnode(&iter->origin->pdb);
- for (;;) {
- if (iter->current == senti) {
- break;
- }
- send = cookiedb_writeiterator_checksendcondition(iter, iter->current);
- if (send == True) {
- break;
- }
- iter->current = httpcookie_nextnode(iter->current);
- }
- if (iter->current != senti) {
- *cookie = iter->current;
- iter->current = httpcookie_nextnode(iter->current);
- return True;
- }
+ if (iter->current != senti) {
+ *cookie = iter->current;
+ iter->current = httpcookie_nextnode(iter->current);
+ return True;
}
return False;
iter->origin = db;
iter->secure = secure;
iter->time = time;
- iter->state = COOKIEDB_WRITEITERATOR_STATE_VDB;
- senti = cookie_volatiledb_sentinelnode(&db->vdb);
+ senti = cookiedb_sentinelnode(db);
iter->current = httpcookie_nextnode(senti);
return 0;
COOKIEDB_WRITEITERATORCONTEXT_STATE_VALUE,
COOKIEDB_WRITEITERATORCONTEXT_STATE_COLON,
COOKIEDB_WRITEITERATORCONTEXT_STATE_CRLF,
+ COOKIEDB_WRITEITERATORCONTEXT_STATE_END,
} state;
httpcookie_t *current;
};
}
*str = cookiedb_writeheader_context_headername;
*len = 8;
+ context->state = COOKIEDB_WRITEITERATORCONTEXT_STATE_NAME;
return True;
case COOKIEDB_WRITEITERATORCONTEXT_STATE_NAME:
*str = context->current->attr.str;
return True;
case COOKIEDB_WRITEITERATORCONTEXT_STATE_COLON:
*str = cookiedb_writeheader_context_colon;
- *len = 2;
cont = cookiedb_writeiterator_next(&context->iter, &context->current);
if (cont == False) {
+ *len = 1;
context->state = COOKIEDB_WRITEITERATORCONTEXT_STATE_CRLF;
} else {
+ *len = 2;
context->state = COOKIEDB_WRITEITERATORCONTEXT_STATE_NAME;
}
return True;
case COOKIEDB_WRITEITERATORCONTEXT_STATE_CRLF:
*str = cookiedb_writeheader_context_crlf;
*len = 2;
+ context->state = COOKIEDB_WRITEITERATORCONTEXT_STATE_END;
+ return True;
+ case COOKIEDB_WRITEITERATORCONTEXT_STATE_END:
return False;
}
struct cookiedb_readheadercontext_t_ {
ascstr_t host;
+ ascstr_t path;
STIME current;
QUEUE sentinel;
enum {
if (context->reading != NULL) {
cookiedb_readheadercontext_insertcookie(context, context->reading);
}
- context->reading = httpcookie_new(context->host.str, context->host.len);
+ context->reading = httpcookie_new(context->host.str, context->host.len, context->path.str, context->path.len);
if (context->reading == NULL) {
return -1; /* TODO: error value */
}
return (httpcookie_t*)context->sentinel.prev;
}
-LOCAL cookiedb_readheadercontext_t* cookiedb_readheadercontext_new(UB *host, W host_len, STIME time)
+LOCAL cookiedb_readheadercontext_t* cookiedb_readheadercontext_new(UB *host, W host_len, UB *path, W path_len, STIME time)
{
cookiedb_readheadercontext_t *context;
W err;
free(context);
return NULL;
}
- context->reading = httpcookie_new(host, host_len);
- if (context->reading == NULL) {
+ err = ascstr_initialize(&context->path);
+ if (err < 0) {
+ ascstr_finalize(&context->host);
+ free(context);
+ return NULL;
+ }
+ err = ascstr_appendstr(&context->path, path, path_len);
+ if (err < 0) {
+ ascstr_finalize(&context->path);
ascstr_finalize(&context->host);
free(context);
return NULL;
}
- QueInit(&context->sentinel);
context->reading = NULL;
+ QueInit(&context->sentinel);
context->state = COOKIEDB_READHEADERCONTEXT_STATE_START;
return context;
}
httpcookie_delete(cookie);
}
- if (context->reading == NULL) {
+ if (context->reading != NULL) {
httpcookie_delete(context->reading);
}
+ ascstr_finalize(&context->path);
ascstr_finalize(&context->host);
free(context);
}
-EXPORT cookiedb_readheadercontext_t* cookiedb_startheaderread(cookiedb_t *db, UB *host, W host_len, STIME time)
+EXPORT cookiedb_readheadercontext_t* cookiedb_startheaderread(cookiedb_t *db, UB *host, W host_len, UB *path, W path_len, STIME time)
{
cookiedb_readheadercontext_t *context;
- context = cookiedb_readheadercontext_new(host, host_len, time);
+ context = cookiedb_readheadercontext_new(host, host_len, path, path_len, time);
if (context == NULL) {
return NULL;
}
return context;
}
-LOCAL VOID cookiedb_inserteachdb(cookiedb_t *db, httpcookie_t *cookie, STIME current)
+LOCAL VOID cookiedb_insertcookie(cookiedb_t *db, httpcookie_t *cookie)
{
+ httpcookie_t *senti, *node;
+ ascstr_t *as_a, *as_n;
+ W cmp;
+ Bool samekey;
+
+ senti = cookiedb_sentinelnode(db);
+ node = httpcookie_nextnode(senti);
+ for (;;) {
+ if (node == senti) {
+ httpcookie_QueInsert(cookie, senti);
+ break;
+ }
+ as_n = httpcookie_getvalidpath(node);
+ as_a = httpcookie_getvalidpath(cookie);
+ cmp = ascstr_cmp(as_n, as_a);
+ if (cmp == 0) {
+ samekey = httpcookie_issamekey(node, cookie);
+ if (samekey == True) {
+ httpcookie_QueInsert(cookie, node);
+ httpcookie_delete(node);
+ break;
+ }
+ } else if (cmp < 0) {
+ httpcookie_QueInsert(cookie, node);
+ break;
+ }
+ node = httpcookie_nextnode(node);
+ }
+}
+
+LOCAL Bool cookiedb_checkinsertioncondition(cookiedb_t *db, httpcookie_t *cookie, STIME current)
+{
+ W count;
+ Bool ok;
+
+ /* domain check */
+ if (cookie->domain.len != 0) {
+ if (cookie->domain.str[0] != '.') { /* is not error and add period? */
+ return False;
+ }
+ /* same as cookiedb_writeiterator_checksendcondition */
+ count = count_priod(&cookie->domain);
+ ok = check_specified_TLD(&cookie->domain);
+ if (ok == True) {
+ if (count < 2) {
+ return False;
+ }
+ } else {
+ if (count < 3) {
+ return False;
+ }
+ }
+ /* domain and request host check */
+ if (cookie->domain.len == (cookie->origin_host.len + 1)) {
+ /* for
+ * domain = .xxx.yyy.zzz
+ * origin = xxx.yyy.zzz
+ */
+ if (strncmp(cookie->domain.str + 1, cookie->origin_host.str, cookie->origin_host.len) != 0) {
+ return False;
+ }
+ } else {
+ ok = ascstr_suffixcmp(&cookie->origin_host, &cookie->domain);
+ if (ok == False) {
+ return False;
+ }
+ }
+ }
+
+ /* expire check */
if (cookie->expires == 0) {
- cookie_volatiledb_insertcookie(&db->vdb, cookie);
- } if (cookie->expires < current) {
- cookie_persistentdb_insertcookie(&db->pdb, cookie);
- } else { /* cookie->expires >= current */
+ return True;
+ }
+ if (cookie->expires < current) {
+ return True;
+ }
+
+ return False;
+}
+
+LOCAL VOID cookiedb_insertwithcheck(cookiedb_t *db, httpcookie_t *cookie, STIME current)
+{
+ Bool save;
+ save = cookiedb_checkinsertioncondition(db, cookie, current);
+ if (save == True) {
+ cookiedb_insertcookie(db, cookie);
+ } else {
httpcookie_delete(cookie);
}
}
EXPORT VOID cookiedb_endheaderread(cookiedb_t *db, cookiedb_readheadercontext_t *context)
{
httpcookie_t *cookie;
+ Bool ok;
for (;;) {
cookie = cookiedb_readheadercontext_prevcookie(context);
break;
}
httpcookie_QueRemove(cookie);
- cookiedb_inserteachdb(db, cookie, context->current);
+ cookiedb_insertwithcheck(db, cookie, context->current);
}
if (context->reading != NULL) {
- httpcookie_QueRemove(context->reading);
- cookiedb_inserteachdb(db, context->reading, context->current);
+ ok = httpcookie_isvalueset(context->reading);
+ if (ok == True) {
+ httpcookie_QueRemove(context->reading);
+ cookiedb_insertwithcheck(db, context->reading, context->current);
+ } else {
+ httpcookie_delete(context->reading);
+ }
context->reading = NULL;
}
cookiedb_readheadercontext_delete(context);
}
-EXPORT W cookiedb_clearallcookie(cookiedb_t *db)
+EXPORT VOID cookiedb_clearallcookie(cookiedb_t *db)
{
+ httpcookie_t *cookie;
+ Bool empty;
+
+ for (;;) {
+ empty = isQueEmpty(&db->sentinel);
+ if (empty == True) {
+ break;
+ }
+ cookie = (httpcookie_t*)db->sentinel.prev;
+ httpcookie_delete(cookie);
+ }
+
+ /* TODO clear file */
}
-LOCAL W cookiedb_initialize(cookiedb_t *db, LINK *db_lnk)
+EXPORT W cookiedb_writefile(cookiedb_t *db)
{
- W err;
+ /* TODO */
+ return -1;
+}
- err = cookie_volatiledb_initialize(&db->vdb);
- if (err < 0) {
- return err;
- }
- err = cookie_persistentdb_initialize(&db->pdb, db_lnk);
- if (err < 0) {
- cookie_volatiledb_finalize(&db->vdb);
- return err;
- }
+EXPORT W cookiedb_readfile(cookiedb_t *db)
+{
+ /* TODO */
+ return -1;
+}
+LOCAL W cookiedb_initialize(cookiedb_t *db, LINK *db_lnk)
+{
+ QueInit(&db->sentinel);
+ db->lnk = db_lnk;
return 0;
}
LOCAL VOID cookiedb_finalize(cookiedb_t *db)
{
- cookie_persistentdb_finalize(&db->pdb);
- cookie_volatiledb_finalize(&db->vdb);
+ httpcookie_t *cookie;
+ Bool empty;
+
+ for (;;) {
+ empty = isQueEmpty(&db->sentinel);
+ if (empty == True) {
+ break;
+ }
+ cookie = (httpcookie_t*)db->sentinel.prev;
+ httpcookie_delete(cookie);
+ }
}
EXPORT cookiedb_t* cookiedb_new(LINK *db_lnk)