This avoids a handful of failures due to missing str and bytes.
- skip-blame: just a bunch of b'' prefixes
hg-reviewers |
This avoids a handful of failures due to missing str and bytes.
Automatic diff as part of commit; lint not applicable. |
Automatic diff as part of commit; unit tests not applicable. |
configtable = {} | configtable = {} | ||||
configitem = registrar.configitem(configtable) | configitem = registrar.configitem(configtable) | ||||
configitem(b'badserver', b'closeafteraccept', | configitem(b'badserver', b'closeafteraccept', | ||||
default=False, | default=False, | ||||
) | ) | ||||
configitem(b'badserver', b'closeafterrecvbytes', | configitem(b'badserver', b'closeafterrecvbytes', | ||||
default='0', | default=b'0', | ||||
) | ) | ||||
configitem(b'badserver', b'closeaftersendbytes', | configitem(b'badserver', b'closeaftersendbytes', | ||||
default='0', | default=b'0', | ||||
) | ) | ||||
configitem(b'badserver', b'closebeforeaccept', | configitem(b'badserver', b'closebeforeaccept', | ||||
default=False, | default=False, | ||||
) | ) | ||||
# We can't adjust __class__ on a socket instance. So we define a proxy type. | # We can't adjust __class__ on a socket instance. So we define a proxy type. | ||||
class socketproxy(object): | class socketproxy(object): | ||||
__slots__ = ( | __slots__ = ( | ||||
def __delattr__(self, name): | def __delattr__(self, name): | ||||
delattr(object.__getattribute__(self, '_orig'), name) | delattr(object.__getattribute__(self, '_orig'), name) | ||||
def __setattr__(self, name, value): | def __setattr__(self, name, value): | ||||
setattr(object.__getattribute__(self, '_orig'), name, value) | setattr(object.__getattribute__(self, '_orig'), name, value) | ||||
def _writelog(self, msg): | def _writelog(self, msg): | ||||
msg = msg.replace('\r', '\\r').replace('\n', '\\n') | msg = msg.replace(b'\r', b'\\r').replace(b'\n', b'\\n') | ||||
object.__getattribute__(self, '_logfp').write(msg) | object.__getattribute__(self, '_logfp').write(msg) | ||||
object.__getattribute__(self, '_logfp').write('\n') | object.__getattribute__(self, '_logfp').write(b'\n') | ||||
object.__getattribute__(self, '_logfp').flush() | object.__getattribute__(self, '_logfp').flush() | ||||
def read(self, size=-1): | def read(self, size=-1): | ||||
remaining = object.__getattribute__(self, '_closeafterrecvbytes') | remaining = object.__getattribute__(self, '_closeafterrecvbytes') | ||||
# No read limit. Call original function. | # No read limit. Call original function. | ||||
if not remaining: | if not remaining: | ||||
result = object.__getattribute__(self, '_orig').read(size) | result = object.__getattribute__(self, '_orig').read(size) | ||||
self._writelog('read(%d) -> (%d) (%s) %s' % (size, | self._writelog(b'read(%d) -> (%d) (%s) %s' % (size, | ||||
len(result), | len(result), | ||||
result)) | result)) | ||||
return result | return result | ||||
origsize = size | origsize = size | ||||
if size < 0: | if size < 0: | ||||
size = remaining | size = remaining | ||||
else: | else: | ||||
size = min(remaining, size) | size = min(remaining, size) | ||||
result = object.__getattribute__(self, '_orig').read(size) | result = object.__getattribute__(self, '_orig').read(size) | ||||
remaining -= len(result) | remaining -= len(result) | ||||
self._writelog('read(%d from %d) -> (%d) %s' % ( | self._writelog(b'read(%d from %d) -> (%d) %s' % ( | ||||
size, origsize, len(result), result)) | size, origsize, len(result), result)) | ||||
object.__setattr__(self, '_closeafterrecvbytes', remaining) | object.__setattr__(self, '_closeafterrecvbytes', remaining) | ||||
if remaining <= 0: | if remaining <= 0: | ||||
self._writelog('read limit reached, closing socket') | self._writelog(b'read limit reached, closing socket') | ||||
self._sock.close() | self._sock.close() | ||||
# This is the easiest way to abort the current request. | # This is the easiest way to abort the current request. | ||||
raise Exception('connection closed after receiving N bytes') | raise Exception('connection closed after receiving N bytes') | ||||
return result | return result | ||||
def readline(self, size=-1): | def readline(self, size=-1): | ||||
remaining = object.__getattribute__(self, '_closeafterrecvbytes') | remaining = object.__getattribute__(self, '_closeafterrecvbytes') | ||||
# No read limit. Call original function. | # No read limit. Call original function. | ||||
if not remaining: | if not remaining: | ||||
result = object.__getattribute__(self, '_orig').readline(size) | result = object.__getattribute__(self, '_orig').readline(size) | ||||
self._writelog('readline(%d) -> (%d) %s' % ( | self._writelog(b'readline(%d) -> (%d) %s' % ( | ||||
size, len(result), result)) | size, len(result), result)) | ||||
return result | return result | ||||
origsize = size | origsize = size | ||||
if size < 0: | if size < 0: | ||||
size = remaining | size = remaining | ||||
else: | else: | ||||
size = min(remaining, size) | size = min(remaining, size) | ||||
result = object.__getattribute__(self, '_orig').readline(size) | result = object.__getattribute__(self, '_orig').readline(size) | ||||
remaining -= len(result) | remaining -= len(result) | ||||
self._writelog('readline(%d from %d) -> (%d) %s' % ( | self._writelog(b'readline(%d from %d) -> (%d) %s' % ( | ||||
size, origsize, len(result), result)) | size, origsize, len(result), result)) | ||||
object.__setattr__(self, '_closeafterrecvbytes', remaining) | object.__setattr__(self, '_closeafterrecvbytes', remaining) | ||||
if remaining <= 0: | if remaining <= 0: | ||||
self._writelog('read limit reached; closing socket') | self._writelog(b'read limit reached; closing socket') | ||||
self._sock.close() | self._sock.close() | ||||
# This is the easiest way to abort the current request. | # This is the easiest way to abort the current request. | ||||
raise Exception('connection closed after receiving N bytes') | raise Exception('connection closed after receiving N bytes') | ||||
return result | return result | ||||
def write(self, data): | def write(self, data): | ||||
remaining = object.__getattribute__(self, '_closeaftersendbytes') | remaining = object.__getattribute__(self, '_closeaftersendbytes') | ||||
# No byte limit on this operation. Call original function. | # No byte limit on this operation. Call original function. | ||||
if not remaining: | if not remaining: | ||||
self._writelog('write(%d) -> %s' % (len(data), data)) | self._writelog(b'write(%d) -> %s' % (len(data), data)) | ||||
result = object.__getattribute__(self, '_orig').write(data) | result = object.__getattribute__(self, '_orig').write(data) | ||||
return result | return result | ||||
if len(data) > remaining: | if len(data) > remaining: | ||||
newdata = data[0:remaining] | newdata = data[0:remaining] | ||||
else: | else: | ||||
newdata = data | newdata = data | ||||
remaining -= len(newdata) | remaining -= len(newdata) | ||||
self._writelog('write(%d from %d) -> (%d) %s' % ( | self._writelog(b'write(%d from %d) -> (%d) %s' % ( | ||||
len(newdata), len(data), remaining, newdata)) | len(newdata), len(data), remaining, newdata)) | ||||
result = object.__getattribute__(self, '_orig').write(newdata) | result = object.__getattribute__(self, '_orig').write(newdata) | ||||
object.__setattr__(self, '_closeaftersendbytes', remaining) | object.__setattr__(self, '_closeaftersendbytes', remaining) | ||||
if remaining <= 0: | if remaining <= 0: | ||||
self._writelog('write limit reached; closing socket') | self._writelog(b'write limit reached; closing socket') | ||||
self._sock.close() | self._sock.close() | ||||
raise Exception('connection closed after sending N bytes') | raise Exception('connection closed after sending N bytes') | ||||
return result | return result | ||||
def extsetup(ui): | def extsetup(ui): | ||||
# Change the base HTTP server class so various events can be performed. | # Change the base HTTP server class so various events can be performed. | ||||
# See SocketServer.BaseServer for how the specially named methods work. | # See SocketServer.BaseServer for how the specially named methods work. | ||||
class badserver(server.MercurialHTTPServer): | class badserver(server.MercurialHTTPServer): | ||||
def __init__(self, ui, *args, **kwargs): | def __init__(self, ui, *args, **kwargs): | ||||
self._ui = ui | self._ui = ui | ||||
super(badserver, self).__init__(ui, *args, **kwargs) | super(badserver, self).__init__(ui, *args, **kwargs) | ||||
recvbytes = self._ui.config(b'badserver', b'closeafterrecvbytes') | recvbytes = self._ui.config(b'badserver', b'closeafterrecvbytes') | ||||
recvbytes = recvbytes.split(',') | recvbytes = recvbytes.split(b',') | ||||
self.closeafterrecvbytes = [int(v) for v in recvbytes if v] | self.closeafterrecvbytes = [int(v) for v in recvbytes if v] | ||||
sendbytes = self._ui.config(b'badserver', b'closeaftersendbytes') | sendbytes = self._ui.config(b'badserver', b'closeaftersendbytes') | ||||
sendbytes = sendbytes.split(',') | sendbytes = sendbytes.split(b',') | ||||
self.closeaftersendbytes = [int(v) for v in sendbytes if v] | self.closeaftersendbytes = [int(v) for v in sendbytes if v] | ||||
# Need to inherit object so super() works. | # Need to inherit object so super() works. | ||||
class badrequesthandler(self.RequestHandlerClass, object): | class badrequesthandler(self.RequestHandlerClass, object): | ||||
def send_header(self, name, value): | def send_header(self, name, value): | ||||
# Make headers deterministic to facilitate testing. | # Make headers deterministic to facilitate testing. | ||||
if name.lower() == 'date': | if name.lower() == 'date': | ||||
value = 'Fri, 14 Apr 2017 00:00:00 GMT' | value = 'Fri, 14 Apr 2017 00:00:00 GMT' | ||||
self.socket.close() | self.socket.close() | ||||
# Tells the server to stop processing more requests. | # Tells the server to stop processing more requests. | ||||
self.__shutdown_request = True | self.__shutdown_request = True | ||||
# Simulate failure to stop processing this request. | # Simulate failure to stop processing this request. | ||||
raise socket.error('close before accept') | raise socket.error('close before accept') | ||||
if self._ui.configbool('badserver', 'closeafteraccept'): | if self._ui.configbool(b'badserver', b'closeafteraccept'): | ||||
request, client_address = super(badserver, self).get_request() | request, client_address = super(badserver, self).get_request() | ||||
request.close() | request.close() | ||||
raise socket.error('close after accept') | raise socket.error('close after accept') | ||||
return super(badserver, self).get_request() | return super(badserver, self).get_request() | ||||
# Does heavy lifting of processing a request. Invokes | # Does heavy lifting of processing a request. Invokes | ||||
# self.finish_request() which calls self.RequestHandlerClass() which | # self.finish_request() which calls self.RequestHandlerClass() which |