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