• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

zopefoundation / zope.testbrowser / 16098871825

05 Mar 2025 04:01PM UTC coverage: 91.403%. Remained the same
16098871825

push

github

icemac
Back to development: 7.1

427 of 520 branches covered (82.12%)

Branch coverage included in aggregate %.

1859 of 1981 relevant lines covered (93.84%)

0.94 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

31.69
/src/zope/testbrowser/utils.py
1
##############################################################################
2
#
3
# Copyright (c) 2005 Zope Foundation and Contributors.
4
# All Rights Reserved.
5
#
6
# This software is subject to the provisions of the Zope Public License,
7
# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
8
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
9
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
10
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
11
# FOR A PARTICULAR PURPOSE.
12
#
13
##############################################################################
14
"""Various utility functions
15

16
Mostly ported from mechanize soruces for backwards compatibility.
17
"""
18

19
import re
1✔
20
import time
1✔
21
import urllib.parse
1✔
22
from calendar import timegm
1✔
23

24

25
strict_re = re.compile(r"^[SMTWF][a-z][a-z], (\d\d) ([JFMASOND][a-z][a-z]) "
1✔
26
                       r"(\d\d\d\d) (\d\d):(\d\d):(\d\d) GMT$")
27

28
days = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
1✔
29
months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun",
1✔
30
          "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
31
months_lower = []
1✔
32
for month in months:
1✔
33
    months_lower.append(month.lower())
1✔
34
wkday_re = re.compile(
1✔
35
    r"^(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)[a-z]*,?\s*", re.I)
36

37
EPOCH = 1970
1✔
38

39

40
def my_timegm(tt):
1✔
41
    year, month, mday, hour, min, sec = tt[:6]
1✔
42
    if ((year >= EPOCH) and (1 <= month <= 12) and (1 <= mday <= 31) and
1!
43
            (0 <= hour <= 24) and (0 <= min <= 59) and (0 <= sec <= 61)):
44
        return timegm(tt)
1✔
45
    else:
46
        return None
×
47

48

49
loose_http_re = re.compile(
1✔
50
    r"""^
51
    (\d\d?)            # day
52
       (?:\s+|[-\/])
53
    (\w+)              # month
54
        (?:\s+|[-\/])
55
    (\d+)              # year
56
    (?:
57
          (?:\s+|:)    # separator before clock
58
       (\d\d?):(\d\d)  # hour:min
59
       (?::(\d\d))?    # optional seconds
60
    )?                 # optional clock
61
       \s*
62
    ([-+]?\d{2,4}|(?![APap][Mm]\b)[A-Za-z]+)? # timezone
63
       \s*
64
    (?:\(\w+\))?       # ASCII representation of timezone in parens.
65
       \s*$""", re.X)
66

67

68
def http2time(text):
1✔
69
    """Returns time in seconds since epoch of time represented by a string.
70

71
    Return value is an integer.
72

73
    None is returned if the format of str is unrecognized, the time is outside
74
    the representable range, or the timezone string is not recognized.  If the
75
    string contains no timezone, UTC is assumed.
76

77
    The timezone in the string may be numerical (like "-0800" or "+0100") or a
78
    string timezone (like "UTC", "GMT", "BST" or "EST").  Currently, only the
79
    timezone strings equivalent to UTC (zero offset) are known to the function.
80

81
    The function loosely parses the following formats:
82

83
    Wed, 09 Feb 1994 22:23:32 GMT       -- HTTP format
84
    Tuesday, 08-Feb-94 14:15:29 GMT     -- old rfc850 HTTP format
85
    Tuesday, 08-Feb-1994 14:15:29 GMT   -- broken rfc850 HTTP format
86
    09 Feb 1994 22:23:32 GMT            -- HTTP format (no weekday)
87
    08-Feb-94 14:15:29 GMT              -- rfc850 format (no weekday)
88
    08-Feb-1994 14:15:29 GMT            -- broken rfc850 format (no weekday)
89

90
    The parser ignores leading and trailing whitespace.  The time may be
91
    absent.
92

93
    If the year is given with only 2 digits, the function will select the
94
    century that makes the year closest to the current date.
95

96
    Note: This was ported from mechanize' _utils.py
97
    """
98
    # fast exit for strictly conforming string
99
    m = strict_re.search(text)
1✔
100
    if m:
1!
101
        g = m.groups()
1✔
102
        mon = months_lower.index(g[1].lower()) + 1
1✔
103
        tt = (int(g[2]), mon, int(g[0]),
1✔
104
              int(g[3]), int(g[4]), float(g[5]))
105
        return my_timegm(tt)
1✔
106

107
    # No, we need some messy parsing...
108

109
    # clean up
110
    text = text.lstrip()
×
111
    text = wkday_re.sub("", text, 1)  # Useless weekday
×
112

113
    # tz is time zone specifier string
114
    day, mon, yr, hr, min, sec, tz = [None] * 7
×
115

116
    # loose regexp parse
117
    m = loose_http_re.search(text)
×
118
    if m is not None:
×
119
        day, mon, yr, hr, min, sec, tz = m.groups()
×
120
    else:
121
        return None  # bad format
×
122

123
    return _str2time(day, mon, yr, hr, min, sec, tz)
×
124

125

126
UTC_ZONES = {"GMT": None, "UTC": None, "UT": None, "Z": None}
1✔
127

128
timezone_re = re.compile(r"^([-+])?(\d\d?):?(\d\d)?$")
1✔
129

130

131
def offset_from_tz_string(tz):
1✔
132
    offset = None
×
133
    if tz in UTC_ZONES:
×
134
        offset = 0
×
135
    else:
136
        m = timezone_re.search(tz)
×
137
        if m:
×
138
            offset = 3600 * int(m.group(2))
×
139
            if m.group(3):
×
140
                offset = offset + 60 * int(m.group(3))
×
141
            if m.group(1) == '-':
×
142
                offset = -offset
×
143
    return offset
×
144

145

146
def _str2time(day, mon, yr, hr, min, sec, tz):
1✔
147
    # translate month name to number
148
    # month numbers start with 1 (January)
149
    try:
×
150
        mon = months_lower.index(mon.lower()) + 1
×
151
    except ValueError:
×
152
        # maybe it's already a number
153
        try:
×
154
            imon = int(mon)
×
155
        except ValueError:
×
156
            return None
×
157
        if 1 <= imon <= 12:
×
158
            mon = imon
×
159
        else:
160
            return None
×
161

162
    # make sure clock elements are defined
163
    if hr is None:
×
164
        hr = 0
×
165
    if min is None:
×
166
        min = 0
×
167
    if sec is None:
×
168
        sec = 0
×
169

170
    yr = int(yr)
×
171
    day = int(day)
×
172
    hr = int(hr)
×
173
    min = int(min)
×
174
    sec = int(sec)
×
175

176
    if yr < 1000:
×
177
        # find "obvious" year
178
        cur_yr = time.localtime(time.time())[0]
×
179
        m = cur_yr % 100
×
180
        tmp = yr
×
181
        yr = yr + cur_yr - m
×
182
        m = m - tmp
×
183
        if abs(m) > 50:
×
184
            if m > 0:
×
185
                yr = yr + 100
×
186
            else:
187
                yr = yr - 100
×
188

189
    # convert UTC time tuple to seconds since epoch (not timezone-adjusted)
190
    t = my_timegm((yr, mon, day, hr, min, sec, tz))
×
191

192
    if t is not None:
×
193
        # adjust time using timezone string, to get absolute time since epoch
194
        if tz is None:
×
195
            tz = "UTC"
×
196
        tz = tz.upper()
×
197
        offset = offset_from_tz_string(tz)
×
198
        if offset is None:
×
199
            return None
×
200
        t = t - offset
×
201

202
    return t
×
203

204

205
cut_port_re = re.compile(r":\d+$")
1✔
206
IPV4_RE = re.compile(r"\.\d+$")
1✔
207

208

209
def request_host(request):
1✔
210
    """Return request-host, as defined by RFC 2965.
211

212
    Variation from RFC: returned value is lowercased, for convenient
213
    comparison.
214

215
    """
216
    url = request.get_full_url()
1✔
217
    host = urllib.parse.urlsplit(url)[1]
1✔
218
    if host is None:
1!
219
        host = request.get_header("Host", "")
×
220
    # remove port, if present
221
    return cut_port_re.sub("", host, 1)
1✔
222

223

224
def effective_request_host(request):
1✔
225
    """Return a tuple (request-host, effective request-host name)."""
226
    erhn = request_host(request)
1✔
227
    if '.' not in erhn and not IPV4_RE.search(erhn):
1!
228
        erhn = erhn + ".local"
×
229
    return erhn
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc