Statistics
| Revision:

svn-gvsig-desktop / tags / v1_1_Build_1013 / extensions / extScripting / scripts / jython / Lib / Cookie.py @ 13521

History | View | Annotate | Download (24.3 KB)

1 5782 jmvivo
#!/usr/bin/env python
2
#
3
4
####
5
# Copyright 2000 by Timothy O'Malley <timo@alum.mit.edu>
6
#
7
#                All Rights Reserved
8
#
9
# Permission to use, copy, modify, and distribute this software
10
# and its documentation for any purpose and without fee is hereby
11
# granted, provided that the above copyright notice appear in all
12
# copies and that both that copyright notice and this permission
13
# notice appear in supporting documentation, and that the name of
14
# Timothy O'Malley  not be used in advertising or publicity
15
# pertaining to distribution of the software without specific, written
16
# prior permission.
17
#
18
# Timothy O'Malley DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
19
# SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
20
# AND FITNESS, IN NO EVENT SHALL Timothy O'Malley BE LIABLE FOR
21
# ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
22
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
23
# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
24
# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
25
# PERFORMANCE OF THIS SOFTWARE.
26
#
27
####
28
#
29
# Id: Cookie.py,v 2.29 2000/08/23 05:28:49 timo Exp
30
#   by Timothy O'Malley <timo@alum.mit.edu>
31
#
32
#  Cookie.py is a Python module for the handling of HTTP
33
#  cookies as a Python dictionary.  See RFC 2109 for more
34
#  information on cookies.
35
#
36
#  The original idea to treat Cookies as a dictionary came from
37
#  Dave Mitchell (davem@magnet.com) in 1995, when he released the
38
#  first version of nscookie.py.
39
#
40
####
41
42
r"""
43
Here's a sample session to show how to use this module.
44
At the moment, this is the only documentation.
45

46
The Basics
47
----------
48

49
Importing is easy..
50

51
   >>> import Cookie
52

53
Most of the time you start by creating a cookie.  Cookies come in
54
three flavors, each with slighly different encoding semanitcs, but
55
more on that later.
56

57
   >>> C = Cookie.SimpleCookie()
58
   >>> C = Cookie.SerialCookie()
59
   >>> C = Cookie.SmartCookie()
60

61
[Note: Long-time users of Cookie.py will remember using
62
Cookie.Cookie() to create an Cookie object.  Although deprecated, it
63
is still supported by the code.  See the Backward Compatibility notes
64
for more information.]
65

66
Once you've created your Cookie, you can add values just as if it were
67
a dictionary.
68

69
   >>> C = Cookie.SmartCookie()
70
   >>> C["fig"] = "newton"
71
   >>> C["sugar"] = "wafer"
72
   >>> print C
73
   Set-Cookie: sugar=wafer;
74
   Set-Cookie: fig=newton;
75

76
Notice that the printable representation of a Cookie is the
77
appropriate format for a Set-Cookie: header.  This is the
78
default behavior.  You can change the header and printed
79
attributes by using the the .output() function
80

81
   >>> C = Cookie.SmartCookie()
82
   >>> C["rocky"] = "road"
83
   >>> C["rocky"]["path"] = "/cookie"
84
   >>> print C.output(header="Cookie:")
85
   Cookie: rocky=road; Path=/cookie;
86
   >>> print C.output(attrs=[], header="Cookie:")
87
   Cookie: rocky=road;
88

89
The load() method of a Cookie extracts cookies from a string.  In a
90
CGI script, you would use this method to extract the cookies from the
91
HTTP_COOKIE environment variable.
92

93
   >>> C = Cookie.SmartCookie()
94
   >>> C.load("chips=ahoy; vienna=finger")
95
   >>> print C
96
   Set-Cookie: vienna=finger;
97
   Set-Cookie: chips=ahoy;
98

99
The load() method is darn-tootin smart about identifying cookies
100
within a string.  Escaped quotation marks, nested semicolons, and other
101
such trickeries do not confuse it.
102

103
   >>> C = Cookie.SmartCookie()
104
   >>> C.load('keebler="E=everybody; L=\\"Loves\\"; fudge=\\012;";')
105
   >>> print C
106
   Set-Cookie: keebler="E=everybody; L=\"Loves\"; fudge=\012;";
107

108
Each element of the Cookie also supports all of the RFC 2109
109
Cookie attributes.  Here's an example which sets the Path
110
attribute.
111

112
   >>> C = Cookie.SmartCookie()
113
   >>> C["oreo"] = "doublestuff"
114
   >>> C["oreo"]["path"] = "/"
115
   >>> print C
116
   Set-Cookie: oreo=doublestuff; Path=/;
117

118
Each dictionary element has a 'value' attribute, which gives you
119
back the value associated with the key.
120

121
   >>> C = Cookie.SmartCookie()
122
   >>> C["twix"] = "none for you"
123
   >>> C["twix"].value
124
   'none for you'
125

126

127
A Bit More Advanced
128
-------------------
129

130
As mentioned before, there are three different flavors of Cookie
131
objects, each with different encoding/decoding semantics.  This
132
section briefly discusses the differences.
133

134
SimpleCookie
135

136
The SimpleCookie expects that all values should be standard strings.
137
Just to be sure, SimpleCookie invokes the str() builtin to convert
138
the value to a string, when the values are set dictionary-style.
139

140
   >>> C = Cookie.SimpleCookie()
141
   >>> C["number"] = 7
142
   >>> C["string"] = "seven"
143
   >>> C["number"].value
144
   '7'
145
   >>> C["string"].value
146
   'seven'
147
   >>> print C
148
   Set-Cookie: number=7;
149
   Set-Cookie: string=seven;
150

151

152
SerialCookie
153

154
The SerialCookie expects that all values should be serialized using
155
cPickle (or pickle, if cPickle isn't available).  As a result of
156
serializing, SerialCookie can save almost any Python object to a
157
value, and recover the exact same object when the cookie has been
158
returned.  (SerialCookie can yield some strange-looking cookie
159
values, however.)
160

161
   >>> C = Cookie.SerialCookie()
162
   >>> C["number"] = 7
163
   >>> C["string"] = "seven"
164
   >>> C["number"].value
165
   7
166
   >>> C["string"].value
167
   'seven'
168
   >>> print C
169
   Set-Cookie: number="I7\012.";
170
   Set-Cookie: string="S'seven'\012p1\012.";
171

172
Be warned, however, if SerialCookie cannot de-serialize a value (because
173
it isn't a valid pickle'd object), IT WILL RAISE AN EXCEPTION.
174

175

176
SmartCookie
177

178
The SmartCookie combines aspects of each of the other two flavors.
179
When setting a value in a dictionary-fashion, the SmartCookie will
180
serialize (ala cPickle) the value *if and only if* it isn't a
181
Python string.  String objects are *not* serialized.  Similarly,
182
when the load() method parses out values, it attempts to de-serialize
183
the value.  If it fails, then it fallsback to treating the value
184
as a string.
185

186
   >>> C = Cookie.SmartCookie()
187
   >>> C["number"] = 7
188
   >>> C["string"] = "seven"
189
   >>> C["number"].value
190
   7
191
   >>> C["string"].value
192
   'seven'
193
   >>> print C
194
   Set-Cookie: number="I7\012.";
195
   Set-Cookie: string=seven;
196

197

198
Backwards Compatibility
199
-----------------------
200

201
In order to keep compatibilty with earlier versions of Cookie.py,
202
it is still possible to use Cookie.Cookie() to create a Cookie.  In
203
fact, this simply returns a SmartCookie.
204

205
   >>> C = Cookie.Cookie()
206
   >>> print C.__class__.__name__
207
   SmartCookie
208

209

210
Finis.
211
"""  #"
212
#     ^
213
#     |----helps out font-lock
214
215
#
216
# Import our required modules
217
#
218
import string, sys
219
from UserDict import UserDict
220
221
try:
222
    from cPickle import dumps, loads
223
except ImportError:
224
    from pickle import dumps, loads
225
226
try:
227
    import re
228
except ImportError:
229
    raise ImportError, "Cookie.py requires 're' from Python 1.5 or later"
230
231
__all__ = ["CookieError","BaseCookie","SimpleCookie","SerialCookie",
232
           "SmartCookie","Cookie"]
233
234
#
235
# Define an exception visible to External modules
236
#
237
class CookieError(Exception):
238
    pass
239
240
241
# These quoting routines conform to the RFC2109 specification, which in
242
# turn references the character definitions from RFC2068.  They provide
243
# a two-way quoting algorithm.  Any non-text character is translated
244
# into a 4 character sequence: a forward-slash followed by the
245
# three-digit octal equivalent of the character.  Any '\' or '"' is
246
# quoted with a preceeding '\' slash.
247
#
248
# These are taken from RFC2068 and RFC2109.
249
#       _LegalChars       is the list of chars which don't require "'s
250
#       _Translator       hash-table for fast quoting
251
#
252
_LegalChars       = string.letters + string.digits + "!#$%&'*+-.^_`|~"
253
_Translator       = {
254
    '\000' : '\\000',  '\001' : '\\001',  '\002' : '\\002',
255
    '\003' : '\\003',  '\004' : '\\004',  '\005' : '\\005',
256
    '\006' : '\\006',  '\007' : '\\007',  '\010' : '\\010',
257
    '\011' : '\\011',  '\012' : '\\012',  '\013' : '\\013',
258
    '\014' : '\\014',  '\015' : '\\015',  '\016' : '\\016',
259
    '\017' : '\\017',  '\020' : '\\020',  '\021' : '\\021',
260
    '\022' : '\\022',  '\023' : '\\023',  '\024' : '\\024',
261
    '\025' : '\\025',  '\026' : '\\026',  '\027' : '\\027',
262
    '\030' : '\\030',  '\031' : '\\031',  '\032' : '\\032',
263
    '\033' : '\\033',  '\034' : '\\034',  '\035' : '\\035',
264
    '\036' : '\\036',  '\037' : '\\037',
265
266
    '"' : '\\"',       '\\' : '\\\\',
267
268
    '\177' : '\\177',  '\200' : '\\200',  '\201' : '\\201',
269
    '\202' : '\\202',  '\203' : '\\203',  '\204' : '\\204',
270
    '\205' : '\\205',  '\206' : '\\206',  '\207' : '\\207',
271
    '\210' : '\\210',  '\211' : '\\211',  '\212' : '\\212',
272
    '\213' : '\\213',  '\214' : '\\214',  '\215' : '\\215',
273
    '\216' : '\\216',  '\217' : '\\217',  '\220' : '\\220',
274
    '\221' : '\\221',  '\222' : '\\222',  '\223' : '\\223',
275
    '\224' : '\\224',  '\225' : '\\225',  '\226' : '\\226',
276
    '\227' : '\\227',  '\230' : '\\230',  '\231' : '\\231',
277
    '\232' : '\\232',  '\233' : '\\233',  '\234' : '\\234',
278
    '\235' : '\\235',  '\236' : '\\236',  '\237' : '\\237',
279
    '\240' : '\\240',  '\241' : '\\241',  '\242' : '\\242',
280
    '\243' : '\\243',  '\244' : '\\244',  '\245' : '\\245',
281
    '\246' : '\\246',  '\247' : '\\247',  '\250' : '\\250',
282
    '\251' : '\\251',  '\252' : '\\252',  '\253' : '\\253',
283
    '\254' : '\\254',  '\255' : '\\255',  '\256' : '\\256',
284
    '\257' : '\\257',  '\260' : '\\260',  '\261' : '\\261',
285
    '\262' : '\\262',  '\263' : '\\263',  '\264' : '\\264',
286
    '\265' : '\\265',  '\266' : '\\266',  '\267' : '\\267',
287
    '\270' : '\\270',  '\271' : '\\271',  '\272' : '\\272',
288
    '\273' : '\\273',  '\274' : '\\274',  '\275' : '\\275',
289
    '\276' : '\\276',  '\277' : '\\277',  '\300' : '\\300',
290
    '\301' : '\\301',  '\302' : '\\302',  '\303' : '\\303',
291
    '\304' : '\\304',  '\305' : '\\305',  '\306' : '\\306',
292
    '\307' : '\\307',  '\310' : '\\310',  '\311' : '\\311',
293
    '\312' : '\\312',  '\313' : '\\313',  '\314' : '\\314',
294
    '\315' : '\\315',  '\316' : '\\316',  '\317' : '\\317',
295
    '\320' : '\\320',  '\321' : '\\321',  '\322' : '\\322',
296
    '\323' : '\\323',  '\324' : '\\324',  '\325' : '\\325',
297
    '\326' : '\\326',  '\327' : '\\327',  '\330' : '\\330',
298
    '\331' : '\\331',  '\332' : '\\332',  '\333' : '\\333',
299
    '\334' : '\\334',  '\335' : '\\335',  '\336' : '\\336',
300
    '\337' : '\\337',  '\340' : '\\340',  '\341' : '\\341',
301
    '\342' : '\\342',  '\343' : '\\343',  '\344' : '\\344',
302
    '\345' : '\\345',  '\346' : '\\346',  '\347' : '\\347',
303
    '\350' : '\\350',  '\351' : '\\351',  '\352' : '\\352',
304
    '\353' : '\\353',  '\354' : '\\354',  '\355' : '\\355',
305
    '\356' : '\\356',  '\357' : '\\357',  '\360' : '\\360',
306
    '\361' : '\\361',  '\362' : '\\362',  '\363' : '\\363',
307
    '\364' : '\\364',  '\365' : '\\365',  '\366' : '\\366',
308
    '\367' : '\\367',  '\370' : '\\370',  '\371' : '\\371',
309
    '\372' : '\\372',  '\373' : '\\373',  '\374' : '\\374',
310
    '\375' : '\\375',  '\376' : '\\376',  '\377' : '\\377'
311
    }
312
313
def _quote(str, LegalChars=_LegalChars,
314
    join=string.join, idmap=string._idmap, translate=string.translate):
315
    #
316
    # If the string does not need to be double-quoted,
317
    # then just return the string.  Otherwise, surround
318
    # the string in doublequotes and precede quote (with a \)
319
    # special characters.
320
    #
321
    if "" == translate(str, idmap, LegalChars):
322
        return str
323
    else:
324
        return '"' + join( map(_Translator.get, str, str), "" ) + '"'
325
# end _quote
326
327
328
_OctalPatt = re.compile(r"\\[0-3][0-7][0-7]")
329
_QuotePatt = re.compile(r"[\\].")
330
331
def _unquote(str, join=string.join, atoi=string.atoi):
332
    # If there aren't any doublequotes,
333
    # then there can't be any special characters.  See RFC 2109.
334
    if  len(str) < 2:
335
        return str
336
    if str[0] != '"' or str[-1] != '"':
337
        return str
338
339
    # We have to assume that we must decode this string.
340
    # Down to work.
341
342
    # Remove the "s
343
    str = str[1:-1]
344
345
    # Check for special sequences.  Examples:
346
    #    \012 --> \n
347
    #    \"   --> "
348
    #
349
    i = 0
350
    n = len(str)
351
    res = []
352
    while 0 <= i < n:
353
        Omatch = _OctalPatt.search(str, i)
354
        Qmatch = _QuotePatt.search(str, i)
355
        if not Omatch and not Qmatch:              # Neither matched
356
            res.append(str[i:])
357
            break
358
        # else:
359
        j = k = -1
360
        if Omatch: j = Omatch.start(0)
361
        if Qmatch: k = Qmatch.start(0)
362
        if Qmatch and ( not Omatch or k < j ):     # QuotePatt matched
363
            res.append(str[i:k])
364
            res.append(str[k+1])
365
            i = k+2
366
        else:                                      # OctalPatt matched
367
            res.append(str[i:j])
368
            res.append( chr( atoi(str[j+1:j+4], 8) ) )
369
            i = j+4
370
    return join(res, "")
371
# end _unquote
372
373
# The _getdate() routine is used to set the expiration time in
374
# the cookie's HTTP header.      By default, _getdate() returns the
375
# current time in the appropriate "expires" format for a
376
# Set-Cookie header.     The one optional argument is an offset from
377
# now, in seconds.      For example, an offset of -3600 means "one hour ago".
378
# The offset may be a floating point number.
379
#
380
381
_weekdayname = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
382
383
_monthname = [None,
384
              'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
385
              'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
386
387
def _getdate(future=0, weekdayname=_weekdayname, monthname=_monthname):
388
    from time import gmtime, time
389
    now = time()
390
    year, month, day, hh, mm, ss, wd, y, z = gmtime(now + future)
391
    return "%s, %02d-%3s-%4d %02d:%02d:%02d GMT" % \
392
           (weekdayname[wd], day, monthname[month], year, hh, mm, ss)
393
394
395
#
396
# A class to hold ONE key,value pair.
397
# In a cookie, each such pair may have several attributes.
398
#       so this class is used to keep the attributes associated
399
#       with the appropriate key,value pair.
400
# This class also includes a coded_value attribute, which
401
#       is used to hold the network representation of the
402
#       value.  This is most useful when Python objects are
403
#       pickled for network transit.
404
#
405
406
class Morsel(UserDict):
407
    # RFC 2109 lists these attributes as reserved:
408
    #   path       comment         domain
409
    #   max-age    secure      version
410
    #
411
    # For historical reasons, these attributes are also reserved:
412
    #   expires
413
    #
414
    # This dictionary provides a mapping from the lowercase
415
    # variant on the left to the appropriate traditional
416
    # formatting on the right.
417
    _reserved = { "expires" : "expires",
418
                   "path"        : "Path",
419
                   "comment" : "Comment",
420
                   "domain"      : "Domain",
421
                   "max-age" : "Max-Age",
422
                   "secure"      : "secure",
423
                   "version" : "Version",
424
                   }
425
    _reserved_keys = _reserved.keys()
426
427
    def __init__(self):
428
        # Set defaults
429
        self.key = self.value = self.coded_value = None
430
        UserDict.__init__(self)
431
432
        # Set default attributes
433
        for K in self._reserved_keys:
434
            UserDict.__setitem__(self, K, "")
435
    # end __init__
436
437
    def __setitem__(self, K, V):
438
        K = string.lower(K)
439
        if not K in self._reserved_keys:
440
            raise CookieError("Invalid Attribute %s" % K)
441
        UserDict.__setitem__(self, K, V)
442
    # end __setitem__
443
444
    def isReservedKey(self, K):
445
        return string.lower(K) in self._reserved_keys
446
    # end isReservedKey
447
448
    def set(self, key, val, coded_val,
449
            LegalChars=_LegalChars,
450
            idmap=string._idmap, translate=string.translate ):
451
        # First we verify that the key isn't a reserved word
452
        # Second we make sure it only contains legal characters
453
        if string.lower(key) in self._reserved_keys:
454
            raise CookieError("Attempt to set a reserved key: %s" % key)
455
        if "" != translate(key, idmap, LegalChars):
456
            raise CookieError("Illegal key value: %s" % key)
457
458
        # It's a good key, so save it.
459
        self.key                 = key
460
        self.value               = val
461
        self.coded_value         = coded_val
462
    # end set
463
464
    def output(self, attrs=None, header = "Set-Cookie:"):
465
        return "%s %s" % ( header, self.OutputString(attrs) )
466
467
    __str__ = output
468
469
    def __repr__(self):
470
        return '<%s: %s=%s>' % (self.__class__.__name__,
471
                                self.key, repr(self.value) )
472
473
    def js_output(self, attrs=None):
474
        # Print javascript
475
        return """
476
        <SCRIPT LANGUAGE="JavaScript">
477
        <!-- begin hiding
478
        document.cookie = \"%s\"
479
        // end hiding -->
480
        </script>
481
        """ % ( self.OutputString(attrs), )
482
    # end js_output()
483
484
    def OutputString(self, attrs=None):
485
        # Build up our result
486
        #
487
        result = []
488
        RA = result.append
489
490
        # First, the key=value pair
491
        RA("%s=%s;" % (self.key, self.coded_value))
492
493
        # Now add any defined attributes
494
        if attrs is None:
495
            attrs = self._reserved_keys
496
        for K,V in self.items():
497
            if V == "": continue
498
            if K not in attrs: continue
499
            if K == "expires" and type(V) == type(1):
500
                RA("%s=%s;" % (self._reserved[K], _getdate(V)))
501
            elif K == "max-age" and type(V) == type(1):
502
                RA("%s=%d;" % (self._reserved[K], V))
503
            elif K == "secure":
504
                RA("%s;" % self._reserved[K])
505
            else:
506
                RA("%s=%s;" % (self._reserved[K], V))
507
508
        # Return the result
509
        return string.join(result, " ")
510
    # end OutputString
511
# end Morsel class
512
513
514
515
#
516
# Pattern for finding cookie
517
#
518
# This used to be strict parsing based on the RFC2109 and RFC2068
519
# specifications.  I have since discovered that MSIE 3.0x doesn't
520
# follow the character rules outlined in those specs.  As a
521
# result, the parsing rules here are less strict.
522
#
523
524
_LegalCharsPatt  = r"[\w\d!#%&'~_`><@,:/\$\*\+\-\.\^\|\)\(\?\}\{\=]"
525
_CookiePattern = re.compile(
526
    r"(?x)"                       # This is a Verbose pattern
527
    r"(?P<key>"                   # Start of group 'key'
528
    ""+ _LegalCharsPatt +"+?"     # Any word of at least one letter, nongreedy
529
    r")"                          # End of group 'key'
530
    r"\s*=\s*"                    # Equal Sign
531
    r"(?P<val>"                   # Start of group 'val'
532
    r'"(?:[^\\"]|\\.)*"'            # Any doublequoted string
533
    r"|"                            # or
534
    ""+ _LegalCharsPatt +"*"        # Any word or empty string
535
    r")"                          # End of group 'val'
536
    r"\s*;?"                      # Probably ending in a semi-colon
537
    )
538
539
540
# At long last, here is the cookie class.
541
#   Using this class is almost just like using a dictionary.
542
# See this module's docstring for example usage.
543
#
544
class BaseCookie(UserDict):
545
    # A container class for a set of Morsels
546
    #
547
548
    def value_decode(self, val):
549
        """real_value, coded_value = value_decode(STRING)
550
        Called prior to setting a cookie's value from the network
551
        representation.  The VALUE is the value read from HTTP
552
        header.
553
        Override this function to modify the behavior of cookies.
554
        """
555
        return val, val
556
    # end value_encode
557
558
    def value_encode(self, val):
559
        """real_value, coded_value = value_encode(VALUE)
560
        Called prior to setting a cookie's value from the dictionary
561
        representation.  The VALUE is the value being assigned.
562
        Override this function to modify the behavior of cookies.
563
        """
564
        strval = str(val)
565
        return strval, strval
566
    # end value_encode
567
568
    def __init__(self, input=None):
569
        UserDict.__init__(self)
570
        if input: self.load(input)
571
    # end __init__
572
573
    def __set(self, key, real_value, coded_value):
574
        """Private method for setting a cookie's value"""
575
        M = self.get(key, Morsel())
576
        M.set(key, real_value, coded_value)
577
        UserDict.__setitem__(self, key, M)
578
    # end __set
579
580
    def __setitem__(self, key, value):
581
        """Dictionary style assignment."""
582
        rval, cval = self.value_encode(value)
583
        self.__set(key, rval, cval)
584
    # end __setitem__
585
586
    def output(self, attrs=None, header="Set-Cookie:", sep="\n"):
587
        """Return a string suitable for HTTP."""
588
        result = []
589
        for K,V in self.items():
590
            result.append( V.output(attrs, header) )
591
        return string.join(result, sep)
592
    # end output
593
594
    __str__ = output
595
596
    def __repr__(self):
597
        L = []
598
        for K,V in self.items():
599
            L.append( '%s=%s' % (K,repr(V.value) ) )
600
        return '<%s: %s>' % (self.__class__.__name__, string.join(L))
601
602
    def js_output(self, attrs=None):
603
        """Return a string suitable for JavaScript."""
604
        result = []
605
        for K,V in self.items():
606
            result.append( V.js_output(attrs) )
607
        return string.join(result, "")
608
    # end js_output
609
610
    def load(self, rawdata):
611
        """Load cookies from a string (presumably HTTP_COOKIE) or
612
        from a dictionary.  Loading cookies from a dictionary 'd'
613
        is equivalent to calling:
614
            map(Cookie.__setitem__, d.keys(), d.values())
615
        """
616
        if type(rawdata) == type(""):
617
            self.__ParseString(rawdata)
618
        else:
619
            self.update(rawdata)
620
        return
621
    # end load()
622
623
    def __ParseString(self, str, patt=_CookiePattern):
624
        i = 0            # Our starting point
625
        n = len(str)     # Length of string
626
        M = None         # current morsel
627
628
        while 0 <= i < n:
629
            # Start looking for a cookie
630
            match = patt.search(str, i)
631
            if not match: break          # No more cookies
632
633
            K,V = match.group("key"), match.group("val")
634
            i = match.end(0)
635
636
            # Parse the key, value in case it's metainfo
637
            if K[0] == "$":
638
                # We ignore attributes which pertain to the cookie
639
                # mechanism as a whole.  See RFC 2109.
640
                # (Does anyone care?)
641
                if M:
642
                    M[ K[1:] ] = V
643
            elif string.lower(K) in Morsel._reserved_keys:
644
                if M:
645
                    M[ K ] = _unquote(V)
646
            else:
647
                rval, cval = self.value_decode(V)
648
                self.__set(K, rval, cval)
649
                M = self[K]
650
    # end __ParseString
651
# end BaseCookie class
652
653
class SimpleCookie(BaseCookie):
654
    """SimpleCookie
655
    SimpleCookie supports strings as cookie values.  When setting
656
    the value using the dictionary assignment notation, SimpleCookie
657
    calls the builtin str() to convert the value to a string.  Values
658
    received from HTTP are kept as strings.
659
    """
660
    def value_decode(self, val):
661
        return _unquote( val ), val
662
    def value_encode(self, val):
663
        strval = str(val)
664
        return strval, _quote( strval )
665
# end SimpleCookie
666
667
class SerialCookie(BaseCookie):
668
    """SerialCookie
669
    SerialCookie supports arbitrary objects as cookie values. All
670
    values are serialized (using cPickle) before being sent to the
671
    client.  All incoming values are assumed to be valid Pickle
672
    representations.  IF AN INCOMING VALUE IS NOT IN A VALID PICKLE
673
    FORMAT, THEN AN EXCEPTION WILL BE RAISED.
674

675
    Note: Large cookie values add overhead because they must be
676
    retransmitted on every HTTP transaction.
677

678
    Note: HTTP has a 2k limit on the size of a cookie.  This class
679
    does not check for this limit, so be careful!!!
680
    """
681
    def value_decode(self, val):
682
        # This could raise an exception!
683
        return loads( _unquote(val) ), val
684
    def value_encode(self, val):
685
        return val, _quote( dumps(val) )
686
# end SerialCookie
687
688
class SmartCookie(BaseCookie):
689
    """SmartCookie
690
    SmartCookie supports arbitrary objects as cookie values.  If the
691
    object is a string, then it is quoted.  If the object is not a
692
    string, however, then SmartCookie will use cPickle to serialize
693
    the object into a string representation.
694

695
    Note: Large cookie values add overhead because they must be
696
    retransmitted on every HTTP transaction.
697

698
    Note: HTTP has a 2k limit on the size of a cookie.  This class
699
    does not check for this limit, so be careful!!!
700
    """
701
    def value_decode(self, val):
702
        strval = _unquote(val)
703
        try:
704
            return loads(strval), val
705
        except:
706
            return strval, val
707
    def value_encode(self, val):
708
        if type(val) == type(""):
709
            return val, _quote(val)
710
        else:
711
            return val, _quote( dumps(val) )
712
# end SmartCookie
713
714
715
###########################################################
716
# Backwards Compatibility:  Don't break any existing code!
717
718
# We provide Cookie() as an alias for SmartCookie()
719
Cookie = SmartCookie
720
721
#
722
###########################################################
723
724
def _test():
725
    import doctest, Cookie
726
    return doctest.testmod(Cookie)
727
728
if __name__ == "__main__":
729
    _test()
730
731
732
#Local Variables:
733
#tab-width: 4
734
#end: