📄 dbfunct.c
字号:
---------------------------------------------------------------------
coo/cookies rec rec list, cookie list, backup
set
<> rec field list a cookie, nameless record
name/name field str mandatory
val/value field str mandatory
ver/version field int mandatory
dom/domain field str mandatory
path/path field str optional
exp/expires field int optional
The cookie components/fields domain, path and name identifies a cookie.
Domain and name are case insensitive, while path is case sensitive.
The order of component/fields for a cookie is significant. The order is
as listed above.
(Ordering was introduced to speed up access, not using the get<field>
access functions which searches keywords, but instead directly position
field pointers based on the ordering. This is the same technique as
used in the authenticate part of the database.)
The order of elements within the cookie list is significant.
The cookie list is in recently used order with the least recently used, last.
A counter cookieListSize is used for saving the list lengths.
It can be at most cfg_wae_wspif_CookieItems elements long.
If new optional components are added in the future, these should be
assigned a position among the other optionals last in the component list.
In this case one should evaluate to let all optionals still be last in the
list but among each other without any specific ordering. If this will be
chosen, optionals are probably best accessed using get<Field> functions and
the faster access used presently of the path component must be abandoned.
SEARCHING
Searching is done giving an url as input, finding any cookies with
a matching domain and path.
A match as defined in rfc2109 is:
- the url domain part is domain matched against the cookie domain,
domains are case insensitive
- the cookie path must be a prefix of the url path part,
paths are case sensitive
The found cookies must be returned in the following order:
- for a specific domain, more specific paths precedes less specific paths,
- the order between domains is unspecified.
All matched cookies will be stored internally. The found cookies are retrieved
one by one calling getNextCookie().
During the search, the expires date is checked and
if a cookie is expired it will be removed from the database.
All matching cookies found during the search, are moved to the beginning of
the cookie list to keep the list in recently used order.
*/
/*************
* Constants *
*************/
/*********
* Types *
*********/
/*
Typedefs for a list of integers.
*/
typedef struct IntItem* IntItemPtr;
typedef struct IntItem {
IntItemPtr next;
UINT32 i;
} *IntListPtr;
/*
Typedef for cookie id
*/
typedef struct CookieId {
BYTE* name; /* null terminated string */
BYTE* domain;
BYTE* dEnd; /* one byte past domain end */
BYTE* path;
BYTE* pEnd; /* one byte past path end */
} CookieId;
/*************
* Variables *
*************/
static RecordPtr cookiesPtr; /* pointer to cookies record/set */
static UINT8 cookieListSize; /* size of cookie list */
static IntListPtr pathLenList; /* sorted path lengths used when */
/* searching for cookies */
static RecordPtr nextCookie; /* next found cookie to return */
static RecordPtr lastCookie; /* last found cookie to return */
/*
The items in pathLenList are accumulated, i.e. items are not deleted as long
as the database is open.
*/
/********************************
* Static function declarations *
********************************/
static void deleteExpired(void);
static void setCookieId(CookieId* cookieId, UrlParts* urlParts,
BYTE* name, BYTE* domain, BYTE* path);
static RecordPtr getCookie(CookieId* cookieId, RecordPtr* last);
static BOOL setCookie(DB_ref ref, BOOL created, CookieId* cookieId,
BYTE* value, UINT32* expires, UINT32 version);
static BOOL updateCookie(DB_ref ref, BYTE* value, UINT32* expires,
UINT32 version);
static void moveElement(RecordPtr parent, ElementPtr prevPtr, ElementPtr ePtr,
UINT32 pos);
static UINT8 checkCookieList(RecordPtr parent);
/************************
* Function definitions *
************************/
/* Stores a cookie.
*
* If no domain is given (i.e. NULL is passed in), the storeCookie function
* will set a default value for the cookie domain before storing the cookie.
* The default value used is the domain (host) part of the passed in url
* inparameter.
*
* If no path is given, the storeCookie function will set the default value
* which is the path part up to the rightmost but not including '/' of the
* url.
*
* Next, this function checks that the passed in parameter url, the domain
* and path follows the rules as defined in rfc2109 chapter 4.3.2. I.e. it
* checks if a cookie received in a response should be rejected. The
* following rules apply:
* - the url domain part is domain matched against the cookie domain,
* domains are case insensitive
* - the cookie path must be a prefix of the url path part,
* paths are case sensitive
* - the cookie domain must not be a top domain, i.e. it must start with a
* dot or contain embedded dots
* - a url host of the form HD must not contain any dots in H where D is
* the value of the cookie domain.
*
* If the check fails, the cookie is rejected.
*
* A missing value (NULL) for expires will be interpreted as keeping the
* cookie until the next time the database is closed down, i.e the
* next time cookiesTerminate() is called.
*
* For mandatory values, NULL must not be passed in, except when a zero
* expire value is given, see below.
*
* A cookie is identified by the components domain, path and name.
*
* If already cfg_wae_wspif_CookieItems are present, the
* least reasently used element is replaced by the new one.
*
* Trying to store a cookie that already exists updates the existing cookie.
* The exception is when a zero expires value is given. This is
* interpreted as immediate expiration and any cookie matching the cookie
* beeing passed in will be deleted. In either case, a cookie with
* an expires value 0 will not be stored.
*
* When a zero expire value is given, the value parameter may be NULL.
*
* All input parameters are copied and stored.
*
* Returns TRUE if successfull.
*/
BOOL storeCookie(BYTE* url, BYTE* name, BYTE* value, BYTE* domain,
BYTE* path, UINT32* expires, UINT32 version)
{
UrlParts urlParts;
CookieId cookieId;
BYTE* s;
BYTE* t;
RecordPtr rPtr;
RecordPtr lastPtr;
DB_ref ref;
UINT8 error;
BOOL created;
BOOL res;
if (!url || !name || !*name || (!value && (!expires || *expires)))
return FALSE;
/* treat empty domain and path strings as NULL */
if (domain && !*domain) domain = NULL;
if (path && !*path) path = NULL;
/* invalidate search result and delete expired cookies */
nextCookie = NULL;
lastCookie = NULL;
deleteExpired();
if (!parseUrl(url, &urlParts))
return FALSE;
if (domain) {
if (!domainMatch(&urlParts, domain, NULL, TRUE, FALSE, 1, NULL))
return FALSE;
} else {
/* check that url host part has embedded dot */
s = urlParts.host + 1;
t = urlParts.hEnd;
while ((s != t) && (*s++ != '.'));
if (s == t)
return FALSE;
}
if (path && !pathMatch(&urlParts, path, FALSE, NULL))
return FALSE;
/* sets cookie id: name, domain & path, for the input cookie */
/* if needed, default values are set from urlParts */
setCookieId(&cookieId, &urlParts, name, domain, path);
/* check if cookie already exists, i.e. compare cookie id:s */
rPtr = getCookie(&cookieId, &lastPtr);
/* check if we must delete any found cookie */
if (expires && (*expires <= CLNTa_currentTime())) {
if (rPtr) {
error = db_deleteItem_ptr(cookiesPtr, (ElementPtr) rPtr);
cookieListSize--;
}
else
error = 0;
return !error;
}
if (!rPtr) { /* cookie not found */
if (cookieListSize == cfg_wae_wspif_CookieItems) {
/* List full, reuse the least recently used, i.e. last record */
db_moveToFront(cookiesPtr, (ElementPtr) lastPtr);
ref = lastPtr->ref;
created = FALSE;
} else {
ref = db_createRecord(cookiesPtr->ref, NULL, DB_rec, &error);
/* creates it first in list */
if (error) return FALSE;
created = TRUE;
cookieListSize++;
}
res = setCookie(ref, created, &cookieId, value, expires, version);
} else { /* cookie found */
db_moveToFront(cookiesPtr, (ElementPtr) rPtr);
ref = rPtr->ref;
res = updateCookie(ref, value, expires, version);
}
if (!res) {
db_deleteItem_ptr(cookiesPtr, (ElementPtr) rPtr);
cookieListSize--;
}
return res;
}
/*
* Searches the database for all cookies valid for the passed in url.
* To retrieve the result of the search, call getNextCookie repeatedly
* unitl false is returned.
*
* This function is intended to be called before a http request.
* The url must be well formed containing the domain and optionally
* the path.
*
* A match as defined in rfc2109 is:
* - the url domain part is domain matched against the cookie domain,
* domains are case insensitive
* - the cookie path must be a prefix of the url path part,
* paths are case sensitive
*
* All matched cookies will be stored internally. Calling
* getNextCookie retrieves cookies from the stored search result.
*
* Calling storeCookie, checkCookie, or deleteAllCookies
* invalidates the internally stored search result from the previous
* checkCookie call.
*
* Side effect: during the search, the expires date is checked and
* if a cookie is expired it will be removed from the database.
*
* The cookie list will be kept in least recently used order.
* All cookies found to match in this function are regarded as used
* simultanously. Therefore, the matched cookies are put in the first
* positions of the cookie list. The order of these matched cookies
* are with more specific (longer) paths first.
*
* To sort the matched cookies, a helping list pathLenList is used which
* stores path lengths in order.
*
* Returns TRUE if one or more cookies matched.
*/
BOOL checkCookies(BYTE* url)
{
UrlParts urlParts;
UINT32 matched;
RecordPtr rPtr;
RecordPtr prevRPtr;
RecordPtr nextRPtr;
FieldPtr fPtr;
BYTE* domain;
BYTE* path;
UINT32 pLen;
UINT32 pos;
IntItemPtr freeLenPtr;
IntItemPtr prevFreeLenPtr;
IntItemPtr lenPtr;
IntItemPtr prevLenPtr;
IntItemPtr matchedLenPtr;
/* invalidate search result and delete expired cookies */
nextCookie = NULL;
lastCookie = NULL;
deleteExpired();
if (!parseUrl(url, &urlParts))
return FALSE;
matched = 0;
freeLenPtr = pathLenList;
prevFreeLenPtr = NULL;
prevRPtr = NULL;
rPtr = cookiesPtr->data.r;
while (rPtr != cookiesPtr) {
fPtr = (FieldPtr) (rPtr->data.f->next->next->next);
domain = fPtr->data.s;
fPtr = (FieldPtr) fPtr->next;
if ((fPtr != (FieldPtr) rPtr) &&
(B_COMPARESTRING(fPtr->key, COOKIE_PATH) == 0))
path = fPtr->data.s;
else
path = NULL;
if (!domainMatch(&urlParts, domain, NULL, FALSE, FALSE, -1, NULL) ||
!pathMatch(&urlParts, path, FALSE, &pLen)) {
prevRPtr = rPtr;
rPtr = (RecordPtr) rPtr->next;
continue;
}
/* cookie matched */
/* reuse or create an IntItem */
if (freeLenPtr) {
/* unlink the next free IntItem */
matchedLenPtr = freeLenPtr;
if (prevFreeLenPtr)
prevFreeLenPtr->next = matchedLenPtr->next;
else
pathLenList = matchedLenPtr->next;
freeLenPtr = matchedLenPtr->next;
} else {
matchedLenPtr = OSConnectorAlloc(sizeof(struct IntItem));
#ifndef HAS_SETJMP
if (matchedLenPtr == NULL) {
return FALSE;
}
#endif
}
/* sort the IntItem into pathLenList */
/* since it is relatively small, use linear search */
/* longest path first */
pos = 0;
lenPtr = pathLenList;
prevLenPtr = NULL;
while ((pos < matched) && (pLen <= lenPtr->i)) {
pos++;
prevLenPtr = lenPtr;
lenPtr = lenPtr->next;
}
matchedLenPtr->i = pLen;
matchedLenPtr->next = lenPtr;
if (prevLenPtr)
prevLenPtr->next = matchedLenPtr;
else
pathLenList = matchedLenPtr;
nextRPtr = (RecordPtr) rPtr->next;
/* move the record ahead in the cookie list to the position in pos */
moveElement(cookiesPtr, (ElementPtr) prevRPtr, (ElementPtr) rPtr, pos);
if (pos == matched) { /* matched cookie put last in search result */
lastCookie = rPtr;
freeLenPtr = matchedLenPtr->next;
prevFreeLenPtr = matchedLenPtr;
}
matched++;
if ((ElementPtr) nextRPtr == rPtr->next)
prevRPtr = rPtr;
rPtr = nextRPtr;
} /* end of while loop over cookies */
if (matched)
nextCookie = cookiesPtr->data.r;
return matched;
}
/*
* Retrieves the next cookie from the set of matched cookies found
* in a previous checkCookies() call.
*
* This
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -