Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

"""Load / save to libwww-perl (LWP) format files. 

 

Actually, the format is slightly extended from that used by LWP's 

(libwww-perl's) HTTP::Cookies, to avoid losing some RFC 2965 information 

not recorded by LWP. 

 

It uses the version string "2.0", though really there isn't an LWP Cookies 

2.0 format.  This indicates that there is extra information in here 

(domain_dot and # port_spec) while still being compatible with 

libwww-perl, I hope. 

 

""" 

 

import time, re 

from cookielib import (_warn_unhandled_exception, FileCookieJar, LoadError, 

                       Cookie, MISSING_FILENAME_TEXT, 

                       join_header_words, split_header_words, 

                       iso2time, time2isoz) 

 

def lwp_cookie_str(cookie): 

    """Return string representation of Cookie in an the LWP cookie file format. 

 

    Actually, the format is extended a bit -- see module docstring. 

 

    """ 

    h = [(cookie.name, cookie.value), 

         ("path", cookie.path), 

         ("domain", cookie.domain)] 

    if cookie.port is not None: h.append(("port", cookie.port)) 

    if cookie.path_specified: h.append(("path_spec", None)) 

    if cookie.port_specified: h.append(("port_spec", None)) 

    if cookie.domain_initial_dot: h.append(("domain_dot", None)) 

    if cookie.secure: h.append(("secure", None)) 

    if cookie.expires: h.append(("expires", 

                               time2isoz(float(cookie.expires)))) 

    if cookie.discard: h.append(("discard", None)) 

    if cookie.comment: h.append(("comment", cookie.comment)) 

    if cookie.comment_url: h.append(("commenturl", cookie.comment_url)) 

 

    keys = cookie._rest.keys() 

    keys.sort() 

    for k in keys: 

        h.append((k, str(cookie._rest[k]))) 

 

    h.append(("version", str(cookie.version))) 

 

    return join_header_words([h]) 

 

class LWPCookieJar(FileCookieJar): 

    """ 

    The LWPCookieJar saves a sequence of "Set-Cookie3" lines. 

    "Set-Cookie3" is the format used by the libwww-perl libary, not known 

    to be compatible with any browser, but which is easy to read and 

    doesn't lose information about RFC 2965 cookies. 

 

    Additional methods 

 

    as_lwp_str(ignore_discard=True, ignore_expired=True) 

 

    """ 

 

    def as_lwp_str(self, ignore_discard=True, ignore_expires=True): 

        """Return cookies as a string of "\\n"-separated "Set-Cookie3" headers. 

 

        ignore_discard and ignore_expires: see docstring for FileCookieJar.save 

 

        """ 

        now = time.time() 

        r = [] 

        for cookie in self: 

            if not ignore_discard and cookie.discard: 

                continue 

            if not ignore_expires and cookie.is_expired(now): 

                continue 

            r.append("Set-Cookie3: %s" % lwp_cookie_str(cookie)) 

        return "\n".join(r+[""]) 

 

    def save(self, filename=None, ignore_discard=False, ignore_expires=False): 

        if filename is None: 

            if self.filename is not None: filename = self.filename 

            else: raise ValueError(MISSING_FILENAME_TEXT) 

 

        f = open(filename, "w") 

        try: 

            # There really isn't an LWP Cookies 2.0 format, but this indicates 

            # that there is extra information in here (domain_dot and 

            # port_spec) while still being compatible with libwww-perl, I hope. 

            f.write("#LWP-Cookies-2.0\n") 

            f.write(self.as_lwp_str(ignore_discard, ignore_expires)) 

        finally: 

            f.close() 

 

    def _really_load(self, f, filename, ignore_discard, ignore_expires): 

        magic = f.readline() 

        if not re.search(self.magic_re, magic): 

            msg = ("%r does not look like a Set-Cookie3 (LWP) format " 

                   "file" % filename) 

            raise LoadError(msg) 

 

        now = time.time() 

 

        header = "Set-Cookie3:" 

        boolean_attrs = ("port_spec", "path_spec", "domain_dot", 

                         "secure", "discard") 

        value_attrs = ("version", 

                       "port", "path", "domain", 

                       "expires", 

                       "comment", "commenturl") 

 

        try: 

            while 1: 

                line = f.readline() 

                if line == "": break 

                if not line.startswith(header): 

                    continue 

                line = line[len(header):].strip() 

 

                for data in split_header_words([line]): 

                    name, value = data[0] 

                    standard = {} 

                    rest = {} 

                    for k in boolean_attrs: 

                        standard[k] = False 

                    for k, v in data[1:]: 

                        if k is not None: 

                            lc = k.lower() 

                        else: 

                            lc = None 

                        # don't lose case distinction for unknown fields 

                        if (lc in value_attrs) or (lc in boolean_attrs): 

                            k = lc 

                        if k in boolean_attrs: 

                            if v is None: v = True 

                            standard[k] = v 

                        elif k in value_attrs: 

                            standard[k] = v 

                        else: 

                            rest[k] = v 

 

                    h = standard.get 

                    expires = h("expires") 

                    discard = h("discard") 

                    if expires is not None: 

                        expires = iso2time(expires) 

                    if expires is None: 

                        discard = True 

                    domain = h("domain") 

                    domain_specified = domain.startswith(".") 

                    c = Cookie(h("version"), name, value, 

                               h("port"), h("port_spec"), 

                               domain, domain_specified, h("domain_dot"), 

                               h("path"), h("path_spec"), 

                               h("secure"), 

                               expires, 

                               discard, 

                               h("comment"), 

                               h("commenturl"), 

                               rest) 

                    if not ignore_discard and c.discard: 

                        continue 

                    if not ignore_expires and c.is_expired(now): 

                        continue 

                    self.set_cookie(c) 

 

        except IOError: 

            raise 

        except Exception: 

            _warn_unhandled_exception() 

            raise LoadError("invalid Set-Cookie3 format file %r: %r" % 

                            (filename, line))