]> err.no Git - sope/blob - sope-appserver/NGObjWeb/WOCookie.m
use %p for pointer formats, fixed gcc 4.1 warnings, minor code improvs
[sope] / sope-appserver / NGObjWeb / WOCookie.m
1 /*
2   Copyright (C) 2000-2005 SKYRIX Software AG
3
4   This file is part of SOPE.
5
6   SOPE is free software; you can redistribute it and/or modify it under
7   the terms of the GNU Lesser General Public License as published by the
8   Free Software Foundation; either version 2, or (at your option) any
9   later version.
10
11   SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
12   WARRANTY; without even the implied warranty of MERCHANTABILITY or
13   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
14   License for more details.
15
16   You should have received a copy of the GNU Lesser General Public
17   License along with SOPE; see the file COPYING.  If not, write to the
18   Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
19   02111-1307, USA.
20 */
21
22 #include <NGObjWeb/WOCookie.h>
23 #include "common.h"
24
25 @interface WOCookie(PrivateMethods)
26
27 - (id)initWithName:(NSString *)_name value:(NSString *)_value
28   path:(NSString *)_path domain:(NSString *)_domain
29   expires:(NSDate *)_date
30   isSecure:(BOOL)_secure;
31
32 @end
33
34 @implementation WOCookie
35
36 static WOCookie *_parseCookie(const char *_bytes, unsigned _len);
37
38 // abbr weekday, day-of-month, abbr-month, year hour:min:sec GMT
39 static NSString *cookieDateFormat =  @"%a, %d-%b-%Y %H:%M:%S %Z";
40
41 + (id)cookieWithString:(NSString *)_string {
42   /* private method ! */
43   return _parseCookie([_string cString], [_string cStringLength]);
44 }
45
46 + (id)cookieWithName:(NSString *)_name value:(NSString *)_value {
47   return [[[self alloc] initWithName:_name value:_value
48                         path:nil domain:nil
49                         expires:nil isSecure:NO]
50                         autorelease];
51 }
52
53 + (id)cookieWithName:(NSString *)_name value:(NSString *)_value
54   path:(NSString *)_path domain:(NSString *)_domain
55   expires:(NSDate *)_date
56   isSecure:(BOOL)_secure
57 {
58   return [[[self alloc] initWithName:_name value:_value
59                         path:_path domain:_domain
60                         expires:_date isSecure:_secure]
61                         autorelease];
62 }
63
64 - (id)initWithName:(NSString *)_name value:(NSString *)_value
65   path:(NSString *)_path domain:(NSString *)_domain
66   expires:(NSDate *)_date
67   isSecure:(BOOL)_secure
68 {
69   if ((self = [super init])) {
70     NSZone *z = [self zone];
71     self->name         = [_name   copyWithZone:z];
72     self->value        = [_value  copyWithZone:z];
73     self->path         = [_path   copyWithZone:z];
74     self->domainName   = [_domain copyWithZone:z];
75     self->expireDate   = [expireDate retain];
76     self->onlyIfSecure = _secure;
77   }
78   return self;
79 }
80
81 - (void)dealloc {
82   [self->name       release];
83   [self->value      release];
84   [self->expireDate release];
85   [self->path       release];
86   [self->domainName release];
87   [super dealloc];
88 }
89
90 /* accessors */
91
92 - (NSString *)cookieName {
93   /* ?? */
94   return self->name;
95 }
96
97 - (void)setName:(NSString *)_name {
98   ASSIGNCOPY(self->name, _name);
99 }
100 - (NSString *)name {
101   return self->name;
102 }
103
104 - (void)setValue:(NSString *)_value {
105   ASSIGNCOPY(self->value, _value);
106 }
107 - (NSString *)value {
108   return self->value;
109 }
110
111 - (void)setPath:(NSString *)_path {
112   ASSIGNCOPY(self->path, _path);
113 }
114 - (NSString *)path {
115   return self->path;
116 }
117
118 - (void)setExpires:(NSDate *)_date {
119   ASSIGNCOPY(self->expireDate, _date);
120 }
121 - (NSDate *)expires {
122   return self->expireDate;
123 }
124
125 - (void)setDomain:(NSString *)_domain {
126   ASSIGNCOPY(self->domainName, _domain);
127 }
128 - (NSString *)domain {
129   return self->domainName;
130 }
131
132 - (void)setIsSecure:(BOOL)_flag {
133   self->onlyIfSecure = _flag ? YES : NO;
134 }
135 - (BOOL)isSecure {
136   return self->onlyIfSecure;
137 }
138
139 - (NSDate *)expireDate {
140   // DEPRECATED
141   return self->expireDate;
142 }
143
144 /* NSCopying */
145
146 - (id)copyWithZone:(NSZone *)_zone {
147   return [[WOCookie alloc] initWithName:self->name value:self->value 
148                            path:self->path domain:self->domainName
149                            expires:self->expireDate
150                            isSecure:self->onlyIfSecure];
151 }
152
153 /* description */
154
155 - (NSString *)headerString {
156   return [@"set-cookie: " stringByAppendingString:[self stringValue]];
157 }
158
159 - (NSString *)stringValue {
160   NSMutableString *str;
161   
162   str = [NSMutableString stringWithCapacity:512];
163   [str appendString:[self->name stringByEscapingURL]];
164   [str appendString:@"="];
165   [str appendString:[[self->value stringValue] stringByEscapingURL]];
166   
167   if (self->expireDate) {
168     static NSTimeZone *gmt = nil;
169     NSString *s;
170     if (gmt == nil) 
171       gmt = [[NSTimeZone timeZoneWithAbbreviation:@"GMT"] retain];
172     
173     // TODO: replace, -descriptionWithCalendarFormat is *slow*
174     s = [self->expireDate descriptionWithCalendarFormat:cookieDateFormat
175                           timeZone:gmt
176                           locale:nil];
177     
178     [str appendString:@"; expires="];
179     [str appendString:s];
180   }
181   if (self->path) {
182     [str appendString:@"; path="];
183     [str appendString:self->path];
184   }
185   if (self->domainName) {
186     [str appendString:@"; domain="];
187     [str appendString:self->domainName];
188   }
189   if (self->onlyIfSecure)
190     [str appendString:@"; secure"];
191   
192   return str;
193 }
194
195 - (NSString *)description {
196   NSMutableString *str;
197
198   str = [NSMutableString stringWithCapacity:128];
199   [str appendFormat:@"<%@[0x%p]: name=%@ value=%@",
200          NSStringFromClass([self class]), self,
201          self->name, self->value];
202
203   if (self->expireDate) {
204     [str appendString:@" expires="];
205     [str appendString:[self->expireDate description]];
206   }
207   
208   if (self->path) {
209     [str appendString:@" path="];
210     [str appendString:self->path];
211   }
212   if (self->domainName) {
213     [str appendString:@" domain="];
214     [str appendString:self->domainName];
215   }
216   if (self->onlyIfSecure)
217     [str appendString:@" secure"];
218
219   [str appendString:@">"];
220   
221   return str;
222 }
223
224 /* cookie parsing */
225
226 static WOCookie *_parseCookie(const char *_bytes, unsigned _len) {
227   WOCookie *cookie   = nil;
228   unsigned pos, toGo;
229   
230   for (pos = 0, toGo = _len; (toGo > 0) && (_bytes[pos] != '='); toGo--, pos++)
231     ;
232
233   if (toGo > 0) {
234     NSString *name   = nil;
235     NSString *value  = nil;
236
237     // NSLog(@"pos=%i toGo=%i", pos, toGo);
238     
239     name  = [[NSString alloc]
240                        initWithCString:_bytes
241                        length:pos];
242     value = [[NSString alloc]
243                        initWithCString:&(_bytes[pos + 1])
244                        length:(toGo - 1)];
245     
246     //NSLog(@"pair='%@'", [NSString stringWithCString:_bytes length:_len]);
247     //NSLog(@"name='%@' value='%@'", name, value);
248     
249     if ((name == nil) || (value == nil)) {
250       NSLog(@"ERROR: invalid cookie pair%s%s: %@",
251             value ? "" : ", no value",
252             name  ? "" : ", no name",
253             [NSString stringWithCString:_bytes length:_len]);
254       [name  release];
255       [value release];
256       return nil;
257     }
258     else {
259       cookie = [WOCookie cookieWithName:[name stringByUnescapingURL]
260                          value:[value stringByUnescapingURL]];
261     }
262     
263     [name  release];  name  = nil;
264     [value release]; value = nil;
265   }
266 #if DEBUG
267   else {
268     NSLog(@"ERROR(%s:%i): invalid cookie pair: %@",
269           __PRETTY_FUNCTION__, __LINE__,
270           [NSString stringWithCString:_bytes length:_len]);
271   }
272 #endif
273   return cookie;
274 }
275
276 @end /* WOCookie */