~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/smart/protocol.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2009-03-02 06:21:02 UTC
  • mfrom: (4064.1.4 streaming-body-error)
  • Revision ID: pqm@pqm.ubuntu.com-20090302062102-9hcytxohu3q8qxan
Improve error-handling while sending body_streams in HPSS requests
        and responses. (Andrew Bennetts)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1158
1158
        if response.body is not None:
1159
1159
            self._write_prefixed_body(response.body)
1160
1160
        elif response.body_stream is not None:
1161
 
            for chunk in response.body_stream:
1162
 
                self._write_prefixed_body(chunk)
1163
 
                self.flush()
 
1161
            for exc_info, chunk in _iter_with_errors(response.body_stream):
 
1162
                if exc_info is not None:
 
1163
                    self._write_error_status()
 
1164
                    error_struct = request._translate_error(exc_info[1])
 
1165
                    self._write_structure(error_struct)
 
1166
                    break
 
1167
                else:
 
1168
                    self._write_prefixed_body(chunk)
 
1169
                    self.flush()
1164
1170
        self._write_end()
1165
1171
 
1166
1172
 
 
1173
def _iter_with_errors(iterable):
 
1174
    """Handle errors from iterable.next().
 
1175
 
 
1176
    Use like::
 
1177
 
 
1178
        for exc_info, value in _iter_with_errors(iterable):
 
1179
            ...
 
1180
 
 
1181
    This is a safer alternative to::
 
1182
 
 
1183
        try:
 
1184
            for value in iterable:
 
1185
               ...
 
1186
        except:
 
1187
            ...
 
1188
 
 
1189
    Because the latter will catch errors from the for-loop body, not just
 
1190
    iterable.next()
 
1191
 
 
1192
    If an error occurs, exc_info will be a exc_info tuple, and the generator
 
1193
    will terminate.  Otherwise exc_info will be None, and value will be the
 
1194
    value from iterable.next().  Note that KeyboardInterrupt and SystemExit
 
1195
    will not be itercepted.
 
1196
    """
 
1197
    iterator = iter(iterable)
 
1198
    while True:
 
1199
        try:
 
1200
            yield None, iterator.next()
 
1201
        except StopIteration:
 
1202
            return
 
1203
        except (KeyboardInterrupt, SystemExit):
 
1204
            raise
 
1205
        except Exception:
 
1206
            yield sys.exc_info(), None
 
1207
            return
 
1208
 
 
1209
 
1167
1210
class ProtocolThreeRequester(_ProtocolThreeEncoder, Requester):
1168
1211
 
1169
1212
    def __init__(self, medium_request):
1242
1285
        #       have finished sending the stream.  We would notice at the end
1243
1286
        #       anyway, but if the medium can deliver it early then it's good
1244
1287
        #       to short-circuit the whole request...
1245
 
        try:
1246
 
            for part in stream:
 
1288
        for exc_info, part in _iter_with_errors(stream):
 
1289
            if exc_info is not None:
 
1290
                # Iterating the stream failed.  Cleanly abort the request.
 
1291
                self._write_error_status()
 
1292
                # Currently the client unconditionally sends ('error',) as the
 
1293
                # error args.
 
1294
                self._write_structure(('error',))
 
1295
                self._write_end()
 
1296
                self._medium_request.finished_writing()
 
1297
                raise exc_info[0], exc_info[1], exc_info[2]
 
1298
            else:
1247
1299
                self._write_prefixed_body(part)
1248
1300
                self.flush()
1249
 
        except Exception:
1250
 
            exc_info = sys.exc_info()
1251
 
            # Iterating the stream failed.  Cleanly abort the request.
1252
 
            self._write_error_status()
1253
 
            # Currently the client unconditionally sends ('error',) as the
1254
 
            # error args.
1255
 
            self._write_structure(('error',))
1256
 
            self._write_end()
1257
 
            self._medium_request.finished_writing()
1258
 
            raise exc_info[0], exc_info[1], exc_info[2]
1259
1301
        self._write_end()
1260
1302
        self._medium_request.finished_writing()
1261
1303