Annotation of parser3/src/types/pa_vcookie.C, revision 1.41
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.41 ! paf 7: $Id: pa_vcookie.C,v 1.40 2002/02/20 10:40:08 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.40 paf 47: remove=value->as_string().is_empty();
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:
1.41 ! paf 104: static VString *expires_timestamp(const String& source, double days_till_expire) {
! 105: Pool& pool=source.pool();
1.1 paf 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);
1.41 ! paf 113: if(!tms)
! 114: throw Exception(0, 0,
! 115: &source,
! 116: "bad expires time (seconds from epoch=%ld)", when);
1.1 paf 117: char *buf=(char *)pool.malloc(MAX_STRING);
118: snprintf(buf, MAX_STRING, "%s, %.2d-%s-%.4d %.2d:%.2d:%.2d GMT",
119: days[tms->tm_wday],
120: tms->tm_mday,month_names[tms->tm_mon],tms->tm_year+1900,
121: tms->tm_hour,tms->tm_min,tms->tm_sec);
122: return new(pool) VString(*new(pool) String(pool, buf));
123: }
124:
1.25 parser 125: /*
1.27 parser 126: @todo http://www.netscape.com/newsref/std/cookie_spec.html
1.25 parser 127: When sending cookies to a server,
128: all cookies with a more specific path mapping should be sent before cookies
129: with less specific path mappings.
130: For example, a cookie "name1=foo" with a path mapping of "/" should be sent after
131: a cookie "name1=foo2" with a path mapping of "/bar" if they are both to be sent.
132:
133: There are limitations on the number of cookies that a client can store at any one time.
134: This is a specification of the minimum number of cookies that a client should be prepared
135: to receive and store.
136: 300 total cookies
137: 4 kilobytes per cookie, where the name and the OPAQUE_STRING combine
138: to form the 4 kilobyte limit.
139: 20 cookies per server or domain. (note that completely specified hosts
140: and domains are treated as separate entities and have a 20 cookie limitation
141: for each, not combined)
142: */
1.4 paf 143: static void output_set_cookie(const Hash::Key& aattribute, Hash::Val *ameaning) {
1.1 paf 144: Pool& pool=aattribute.pool();
145: String string(pool);
146: // attribute
1.16 paf 147: string.append(aattribute, String::UL_HTTP_HEADER, true);
1.1 paf 148: // attribute=
1.19 paf 149: string << "=";
1.1 paf 150: Value *meaning;
151: // figure out 'meaning'
152: if(ameaning) { // assigning value
153: // Set-Cookie: (attribute)=(value); path=/
154: meaning=static_cast<Value *>(ameaning);
1.29 parser 155: if(Hash *hash=meaning->get_hash(&aattribute)) { // ...[hash value]
1.1 paf 156: // $expires
157: if(Value *expires=static_cast<Value *>(hash->get(*expires_name))) {
158: const String *string;
159: if((string=expires->get_string()) && (*string==SESSION_NAME)) {
160: // $expires[session]
1.31 paf 161: hash->remove(*expires_name);
1.1 paf 162: } else {
163: // $expires(days)
1.41 ! paf 164: if(double days_till_expire=expires->as_double())
! 165: hash->put(*expires_name, expires_timestamp(aattribute, days_till_expire));
! 166: else // $expires(0)
! 167: hash->remove(*expires_name);
1.1 paf 168: }
169: } else // $expires not assigned, defaulting
170: hash->put(*expires_name, expires_timestamp(pool, DEFAULT_EXPIRES_DAYS));
171: } else { // ...[string value]
172: Value *wrap_meaning=new(pool) VHash(pool);
173: // wrapping meaning into hash
1.29 parser 174: wrap_meaning->get_hash(&aattribute)->put(*value_name, meaning);
1.1 paf 175: // string = $expires not assigned, defaulting
1.29 parser 176: wrap_meaning->get_hash(&aattribute)->put(*expires_name,
1.1 paf 177: expires_timestamp(pool, DEFAULT_EXPIRES_DAYS));
178: // replacing meaning with hash-wrapped one
179: meaning=wrap_meaning;
180: }
181: } else {// removing value
1.25 parser 182: /*
183: http://www.netscape.com/newsref/std/cookie_spec.html
184: to delete a cookie, it can do so by returning a cookie with the same name,
185: and an expires time which is in the past
186: */
187:
1.1 paf 188: // Set-Cookie: (attribute)=; path=/
189: meaning=new(pool) VHash(pool);
1.29 parser 190: meaning->get_hash(&aattribute)->put(*expires_name,
1.25 parser 191: expires_timestamp(pool, -DEFAULT_EXPIRES_DAYS));
1.1 paf 192: }
193: // defaulting path
1.29 parser 194: if(!meaning->get_hash(&aattribute)->get(*path_name))
195: meaning->get_hash(&aattribute)->put(*path_name,
1.1 paf 196: new(pool) VString(*new(pool) String(pool, "/")));
197:
198: // append meaning
1.19 paf 199: string << attributed_meaning_to_string(*meaning, String::UL_HTTP_HEADER);
1.1 paf 200:
201: // output
1.30 paf 202: SAPI::add_header_attribute(pool, "set-cookie", string.cstr(String::UL_UNSPECIFIED));
1.1 paf 203: }
1.4 paf 204: static void output_after(const Hash::Key& aattribute, Hash::Val *ameaning, void *) {
1.1 paf 205: output_set_cookie(aattribute, ameaning);
206: }
1.4 paf 207: static void output_deleted(const Hash::Key& aattribute, Hash::Val *ameaning, void *) {
1.1 paf 208: output_set_cookie(aattribute, 0);
209: }
210: void VCookie::output_result() {
1.12 paf 211: after.for_each(output_after, this);
212: deleted.for_each(output_deleted, this);
1.1 paf 213: }
E-mail: