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