Annotation of parser3/src/types/pa_vcookie.C, revision 1.37
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.37 ! paf 7: $Id: pa_vcookie.C,v 1.36 2002/02/08 15:07:47 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.36 paf 77: //mdm request.info.cookie="enabled=yes; auth.uid=196325308053599810; enabled=yes; msnames; msuri";
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.36 paf 91: if(current) // not "name" without =
92: if(char *meaning=search_stop(current, ';')) {
93: String& sattribute=*NEW String(pool());
94: String& smeaning=*NEW String(pool());
95: sattribute.APPEND_TAINTED(unescape_chars(pool(), attribute, strlen(attribute)), 0,
96: "cookie_name", line);
97: smeaning.APPEND_TAINTED(unescape_chars(pool(), meaning, strlen(meaning)), 0,
98: "cookie_value", line);
99: before.put(sattribute, NEW VString(smeaning));
100: line++;
101: }
1.1 paf 102: } while(current);
103: }
104:
105: static VString *expires_timestamp(Pool& pool, double days_till_expire) {
106: const char month_names[12][4]={
107: "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};
108: const char days[7][4]={
109: "Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
110:
111: time_t when=time(NULL)+(time_t)(60*60*24*days_till_expire);
112: struct tm *tms=gmtime(&when);
113: char *buf=(char *)pool.malloc(MAX_STRING);
114: snprintf(buf, MAX_STRING, "%s, %.2d-%s-%.4d %.2d:%.2d:%.2d GMT",
115: days[tms->tm_wday],
116: tms->tm_mday,month_names[tms->tm_mon],tms->tm_year+1900,
117: tms->tm_hour,tms->tm_min,tms->tm_sec);
118: return new(pool) VString(*new(pool) String(pool, buf));
119: }
120:
1.25 parser 121: /*
1.27 parser 122: @todo http://www.netscape.com/newsref/std/cookie_spec.html
1.25 parser 123: When sending cookies to a server,
124: all cookies with a more specific path mapping should be sent before cookies
125: with less specific path mappings.
126: For example, a cookie "name1=foo" with a path mapping of "/" should be sent after
127: a cookie "name1=foo2" with a path mapping of "/bar" if they are both to be sent.
128:
129: There are limitations on the number of cookies that a client can store at any one time.
130: This is a specification of the minimum number of cookies that a client should be prepared
131: to receive and store.
132: 300 total cookies
133: 4 kilobytes per cookie, where the name and the OPAQUE_STRING combine
134: to form the 4 kilobyte limit.
135: 20 cookies per server or domain. (note that completely specified hosts
136: and domains are treated as separate entities and have a 20 cookie limitation
137: for each, not combined)
138: */
1.4 paf 139: static void output_set_cookie(const Hash::Key& aattribute, Hash::Val *ameaning) {
1.1 paf 140: Pool& pool=aattribute.pool();
141: String string(pool);
142: // attribute
1.16 paf 143: string.append(aattribute, String::UL_HTTP_HEADER, true);
1.1 paf 144: // attribute=
1.19 paf 145: string << "=";
1.1 paf 146: Value *meaning;
147: // figure out 'meaning'
148: if(ameaning) { // assigning value
149: // Set-Cookie: (attribute)=(value); path=/
150: meaning=static_cast<Value *>(ameaning);
1.29 parser 151: if(Hash *hash=meaning->get_hash(&aattribute)) { // ...[hash value]
1.1 paf 152: // $expires
153: if(Value *expires=static_cast<Value *>(hash->get(*expires_name))) {
154: const String *string;
155: if((string=expires->get_string()) && (*string==SESSION_NAME)) {
156: // $expires[session]
1.31 paf 157: hash->remove(*expires_name);
1.1 paf 158: } else {
159: // $expires(days)
160: hash->put(*expires_name,
1.14 paf 161: expires_timestamp(pool, expires->as_double()));
1.1 paf 162: }
163: } else // $expires not assigned, defaulting
164: hash->put(*expires_name, expires_timestamp(pool, DEFAULT_EXPIRES_DAYS));
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.1 paf 171: expires_timestamp(pool, DEFAULT_EXPIRES_DAYS));
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.25 parser 185: expires_timestamp(pool, -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: