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