~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/HttpServer.py

  • Committer: v.ladeuil+lp at free
  • Date: 2006-12-13 12:27:42 UTC
  • mto: (2183.1.1 Aaron's integration)
  • mto: This revision was merged to the branch mainline in revision 2184.
  • Revision ID: v.ladeuil+lp@free.fr-20061213122742-ggox22rvx8auzcdo
Aaron was right. Thanks to him, the http server RFC2616 compliance
progress.

* bzrlib/tests/HttpServer.py:
(TestingHTTPRequestHandler.parse_ranges): Ignore Range header if
it is syntactically invalid.
(TestingHTTPRequestHandler.do_GET): Better explain why we return a
416 error if ranges are not satisfiable (semantically invalid).

Show diffs side-by-side

added added

removed removed

Lines of Context:
88
88
    _tail_regexp = re.compile(r'^-(?P<tail>\d+)$')
89
89
 
90
90
    def parse_ranges(self, ranges_header):
91
 
        """Parse the range header value and returns ranges and tail"""
 
91
        """Parse the range header value and returns ranges and tail.
 
92
 
 
93
        RFC2616 14.35 says that syntactically invalid range
 
94
        specifiers MUST be ignored. In that case, we return 0 for
 
95
        tail and [] for ranges.
 
96
        """
92
97
        tail = 0
93
98
        ranges = []
94
 
        assert ranges_header.startswith('bytes=')
 
99
        if not ranges_header.startswith('bytes='):
 
100
            # Syntactically invalid header
 
101
            return 0, []
 
102
 
95
103
        ranges_header = ranges_header[len('bytes='):]
96
104
        for range_str in ranges_header.split(','):
 
105
            # FIXME: RFC2616 says end is optional and default to file_size
97
106
            range_match = self._range_regexp.match(range_str)
98
107
            if range_match is not None:
99
108
                ranges.append((int(range_match.group('start')),
102
111
                tail_match = self._tail_regexp.match(range_str)
103
112
                if tail_match is not None:
104
113
                    tail = int(tail_match.group('tail'))
 
114
                else:
 
115
                    # Syntactically invalid range
 
116
                    return 0, []
105
117
        return tail, ranges
106
118
 
107
119
    def send_range_content(self, file, start, length):
167
179
        if tail != 0:
168
180
            ranges.append((file_size - tail, file_size))
169
181
 
170
 
        ranges_valid = True
 
182
        satisfiable_ranges = True
171
183
        if len(ranges) == 0:
172
 
            ranges_valid = False
 
184
            satisfiable_ranges = False
173
185
        else:
174
 
            for (start, end) in ranges:
175
 
                if start >= file_size or end >= file_size:
176
 
                    ranges_valid = False
177
 
                    break
178
 
        if not ranges_valid:
179
 
            # RFC2616 14.35 says that invalid Range headers must
180
 
            # be ignored. If they are, the whole file should be
181
 
            # returned as though no Range header was present. If
182
 
            # they aren't, the server should return a 416 error.
183
 
            # FIXME: per 14.35, ranges are only invalid if start > end.
184
 
            # end values should be truncated to file_size -1 if they exceed it.
185
 
            # only start values >= file_size should produce a 416.
 
186
            def check_range(range_specifier):
 
187
                start, end = range_specifier
 
188
                # RFC2616 14.35, ranges are invalid if start > end
 
189
                # or start > file_size
 
190
                if start > end or start > file_size:
 
191
                    satisfiable_ranges = False
 
192
                    return 0, 0
 
193
                # RFC2616 14.35, end values should be truncated
 
194
                # to file_size -1 if they exceed it
 
195
                end = min(end, file_size - 1)
 
196
                return start, end
 
197
 
 
198
            ranges = map(check_range, ranges)
 
199
 
 
200
        if not satisfiable_ranges:
 
201
            # RFC2616 14.16 and 14.35 says that when a server
 
202
            # encounters unsatisfiable range specifiers, it
 
203
            # SHOULD return a 416.
186
204
            file.close()
 
205
            # FIXME: We SHOULD send a Content-Range header too,
 
206
            # but the implementation of send_error does not
 
207
            # allows that. So far.
187
208
            self.send_error(416, "Requested range not satisfiable")
188
209
            return
189
210