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