Annotation of parser3/src/types/pa_vcookie.C, revision 1.51
1.6 paf 1: /** @file
2: Parser: cookie class.
3:
1.35 paf 4: Copyright(c) 2001, 2002 ArtLebedev Group (http://www.artlebedev.com)
1.34 paf 5: Author: Alexandr Petrosian <paf@design.ru> (http://paf.design.ru)
1.44 paf 6: */
1.6 paf 7:
1.51 ! paf 8: static const char* IDENT_VCOOKIE_C="$Date: 2002/08/28 11:02:58 $";
1.1 paf 9:
1.11 paf 10: #include "pa_sapi.h"
1.3 paf 11: #include "pa_common.h"
1.1 paf 12: #include "pa_vcookie.h"
13: #include "pa_vstring.h"
14: #include "pa_request.h"
1.49 paf 15: #include "pa_vdate.h"
1.1 paf 16:
17: #define SESSION_NAME "session"
18: #define DEFAULT_EXPIRES_DAYS 90
1.9 paf 19:
1.1 paf 20: // VCookie
21:
1.48 paf 22: Value *VCookie::get_element(const String& aname, Value * /*aself*/, bool /*looking_up*/) {
1.28 parser 23: // $CLASS
1.46 paf 24: if(aname==CLASS_NAME)
1.28 parser 25: return this;
26:
1.1 paf 27: // $cookie
1.46 paf 28: if(deleted.get(aname)) // deleted?
1.1 paf 29: return 0;
30:
1.46 paf 31: if(Value *after_meaning=static_cast<Value *>(after.get(aname))) // assigned 'after'?
32: if(Hash *hash=after_meaning->get_hash(&aname))
1.2 paf 33: return static_cast<Value *>(hash->get(*value_name));
34: else
35: return after_meaning;
1.1 paf 36:
37: // neither deleted nor assigned
38: // return any value it had 'before'
1.46 paf 39: return static_cast<Value *>(before.get(aname));
1.1 paf 40: }
41:
1.46 paf 42: bool VCookie::put_element(const String& aname, Value *avalue, bool /*replace*/) {
1.1 paf 43: // $cookie
44: bool remove;
1.50 paf 45: Value *lvalue;
1.46 paf 46: if(Hash *hash=avalue->get_hash(&aname))
1.50 paf 47: lvalue=static_cast<Value *>(hash->get(*value_name));
1.1 paf 48: else
1.50 paf 49: lvalue=avalue;
1.51 ! paf 50:
! 51: if(lvalue && lvalue->is_string()) {
! 52: // taint string being assigned
! 53: VString& vstring=*static_cast<VString *>(lvalue);
! 54: const String& user=vstring.string();
! 55: String& tainted=*NEW String(pool());
! 56: tainted.append(user, String::UL_TAINTED, true /*forced*/);
! 57: vstring.set_string(tainted);
! 58: }
1.1 paf 59:
1.50 paf 60: remove=!lvalue || lvalue->as_string().is_empty();
61:
62: (remove?deleted:after).put(aname, lvalue);
1.46 paf 63: (remove?after:deleted).put(aname, 0);
64:
65: return true;
1.1 paf 66: }
67:
1.26 parser 68: static char *search_stop(char*& current, char cstop_at) {
1.37 paf 69: // sanity check
70: if(!current)
71: return 0;
72:
1.26 parser 73: // skip leading WS
74: while(*current==' ' || *current=='\t')
75: current++;
76: if(!*current)
77: return current=0;
78:
79: char *result=current;
80: if(char *pstop_at=strchr(current, cstop_at)) {
81: *pstop_at=0;
82: current=pstop_at+1;
83: } else
84: current=0;
85: return result;
86: }
87:
88:
1.6 paf 89: //#include <stdio.h>
1.1 paf 90: void VCookie::fill_fields(Request& request) {
1.19 paf 91: //request.info.cookie="test-session=value%3D5; test-default1=value%3D1; test-default2=value%3D2; test-tomorrow=value%3D3";
1.39 paf 92: //request.info.cookie="enabled=yes; auth.uid=196325308053599810; enabled=yes; msnames; msuri"; // mdm
1.1 paf 93: if(!request.info.cookie)
94: return;
95: /*
96: FILE *f=fopen("c:\\temp\\a", "wt");
97: fprintf(f, "cookie=%s", request.info.cookie);
98: fclose(f);*/
99: char *cookies=(char *)malloc(strlen(request.info.cookie)+1);
100: strcpy(cookies, request.info.cookie);
101: char *current=cookies;
1.22 parser 102: uint line=0;
1.26 parser 103: //_asm int 3;
1.1 paf 104: do {
1.26 parser 105: if(char *attribute=search_stop(current, '='))
1.38 paf 106: if(char *meaning=search_stop(current, ';')) {
107: String& sattribute=*NEW String(pool());
108: String& smeaning=*NEW String(pool());
109: sattribute.APPEND_TAINTED(unescape_chars(pool(), attribute, strlen(attribute)), 0,
110: "cookie_name", line);
111: smeaning.APPEND_TAINTED(unescape_chars(pool(), meaning, strlen(meaning)), 0,
112: "cookie_value", line);
113: before.put(sattribute, NEW VString(smeaning));
114: line++;
115: }
1.1 paf 116: } while(current);
117: }
118:
1.49 paf 119: static VDate& expires_vdate(Pool& pool, const String *source, double days_till_expire) {
1.1 paf 120: time_t when=time(NULL)+(time_t)(60*60*24*days_till_expire);
121: struct tm *tms=gmtime(&when);
1.41 paf 122: if(!tms)
1.43 paf 123: throw Exception(0,
1.42 paf 124: source,
1.41 paf 125: "bad expires time (seconds from epoch=%ld)", when);
1.49 paf 126:
127: return *new(pool) VDate(pool, when);
1.1 paf 128: }
129:
1.25 parser 130: /*
1.49 paf 131: @todo
132: http://www.netscape.com/newsref/std/cookie_spec.html
1.25 parser 133: When sending cookies to a server,
134: all cookies with a more specific path mapping should be sent before cookies
135: with less specific path mappings.
136: For example, a cookie "name1=foo" with a path mapping of "/" should be sent after
137: a cookie "name1=foo2" with a path mapping of "/bar" if they are both to be sent.
138:
139: There are limitations on the number of cookies that a client can store at any one time.
140: This is a specification of the minimum number of cookies that a client should be prepared
141: to receive and store.
142: 300 total cookies
143: 4 kilobytes per cookie, where the name and the OPAQUE_STRING combine
144: to form the 4 kilobyte limit.
145: 20 cookies per server or domain. (note that completely specified hosts
146: and domains are treated as separate entities and have a 20 cookie limitation
147: for each, not combined)
148: */
1.4 paf 149: static void output_set_cookie(const Hash::Key& aattribute, Hash::Val *ameaning) {
1.1 paf 150: Pool& pool=aattribute.pool();
151: String string(pool);
152: // attribute
1.16 paf 153: string.append(aattribute, String::UL_HTTP_HEADER, true);
1.1 paf 154: // attribute=
1.19 paf 155: string << "=";
1.1 paf 156: Value *meaning;
157: // figure out 'meaning'
158: if(ameaning) { // assigning value
159: // Set-Cookie: (attribute)=(value); path=/
160: meaning=static_cast<Value *>(ameaning);
1.29 parser 161: if(Hash *hash=meaning->get_hash(&aattribute)) { // ...[hash value]
1.1 paf 162: // $expires
163: if(Value *expires=static_cast<Value *>(hash->get(*expires_name))) {
164: const String *string;
165: if((string=expires->get_string()) && (*string==SESSION_NAME)) {
166: // $expires[session]
1.31 paf 167: hash->remove(*expires_name);
1.1 paf 168: } else {
169: // $expires(days)
1.41 paf 170: if(double days_till_expire=expires->as_double())
1.49 paf 171: hash->put(*expires_name, &expires_vdate(pool, &aattribute, days_till_expire));
1.41 paf 172: else // $expires(0)
173: hash->remove(*expires_name);
1.1 paf 174: }
175: } else // $expires not assigned, defaulting
1.49 paf 176: hash->put(*expires_name, &expires_vdate(pool, &aattribute, DEFAULT_EXPIRES_DAYS));
1.1 paf 177: } else { // ...[string value]
178: Value *wrap_meaning=new(pool) VHash(pool);
179: // wrapping meaning into hash
1.29 parser 180: wrap_meaning->get_hash(&aattribute)->put(*value_name, meaning);
1.1 paf 181: // string = $expires not assigned, defaulting
1.29 parser 182: wrap_meaning->get_hash(&aattribute)->put(*expires_name,
1.49 paf 183: &expires_vdate(pool, &aattribute, DEFAULT_EXPIRES_DAYS));
1.1 paf 184: // replacing meaning with hash-wrapped one
185: meaning=wrap_meaning;
186: }
187: } else {// removing value
1.25 parser 188: /*
189: http://www.netscape.com/newsref/std/cookie_spec.html
190: to delete a cookie, it can do so by returning a cookie with the same name,
191: and an expires time which is in the past
192: */
193:
1.1 paf 194: // Set-Cookie: (attribute)=; path=/
195: meaning=new(pool) VHash(pool);
1.29 parser 196: meaning->get_hash(&aattribute)->put(*expires_name,
1.49 paf 197: &expires_vdate(pool, &aattribute, -DEFAULT_EXPIRES_DAYS));
1.1 paf 198: }
199: // defaulting path
1.29 parser 200: if(!meaning->get_hash(&aattribute)->get(*path_name))
201: meaning->get_hash(&aattribute)->put(*path_name,
1.1 paf 202: new(pool) VString(*new(pool) String(pool, "/")));
203:
204: // append meaning
1.19 paf 205: string << attributed_meaning_to_string(*meaning, String::UL_HTTP_HEADER);
1.1 paf 206:
207: // output
1.30 paf 208: SAPI::add_header_attribute(pool, "set-cookie", string.cstr(String::UL_UNSPECIFIED));
1.1 paf 209: }
1.4 paf 210: static void output_after(const Hash::Key& aattribute, Hash::Val *ameaning, void *) {
1.1 paf 211: output_set_cookie(aattribute, ameaning);
212: }
1.4 paf 213: static void output_deleted(const Hash::Key& aattribute, Hash::Val *ameaning, void *) {
1.1 paf 214: output_set_cookie(aattribute, 0);
215: }
216: void VCookie::output_result() {
1.12 paf 217: after.for_each(output_after, this);
218: deleted.for_each(output_deleted, this);
1.1 paf 219: }
E-mail: