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