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