73 object.__setattr__(self, '_logfp', logfp) |
73 object.__setattr__(self, '_logfp', logfp) |
74 object.__setattr__(self, '_closeafterrecvbytes', closeafterrecvbytes) |
74 object.__setattr__(self, '_closeafterrecvbytes', closeafterrecvbytes) |
75 object.__setattr__(self, '_closeaftersendbytes', closeaftersendbytes) |
75 object.__setattr__(self, '_closeaftersendbytes', closeaftersendbytes) |
76 |
76 |
77 def __getattribute__(self, name): |
77 def __getattribute__(self, name): |
78 if name in ('makefile',): |
78 if name in ('makefile', 'sendall', '_writelog'): |
79 return object.__getattribute__(self, name) |
79 return object.__getattribute__(self, name) |
80 |
80 |
81 return getattr(object.__getattribute__(self, '_orig'), name) |
81 return getattr(object.__getattribute__(self, '_orig'), name) |
82 |
82 |
83 def __delattr__(self, name): |
83 def __delattr__(self, name): |
84 delattr(object.__getattribute__(self, '_orig'), name) |
84 delattr(object.__getattribute__(self, '_orig'), name) |
85 |
85 |
86 def __setattr__(self, name, value): |
86 def __setattr__(self, name, value): |
87 setattr(object.__getattribute__(self, '_orig'), name, value) |
87 setattr(object.__getattribute__(self, '_orig'), name, value) |
|
88 |
|
89 def _writelog(self, msg): |
|
90 msg = msg.replace(b'\r', b'\\r').replace(b'\n', b'\\n') |
|
91 |
|
92 object.__getattribute__(self, '_logfp').write(msg) |
|
93 object.__getattribute__(self, '_logfp').write(b'\n') |
|
94 object.__getattribute__(self, '_logfp').flush() |
88 |
95 |
89 def makefile(self, mode, bufsize): |
96 def makefile(self, mode, bufsize): |
90 f = object.__getattribute__(self, '_orig').makefile(mode, bufsize) |
97 f = object.__getattribute__(self, '_orig').makefile(mode, bufsize) |
91 |
98 |
92 logfp = object.__getattribute__(self, '_logfp') |
99 logfp = object.__getattribute__(self, '_logfp') |
96 '_closeaftersendbytes') |
103 '_closeaftersendbytes') |
97 |
104 |
98 return fileobjectproxy(f, logfp, |
105 return fileobjectproxy(f, logfp, |
99 closeafterrecvbytes=closeafterrecvbytes, |
106 closeafterrecvbytes=closeafterrecvbytes, |
100 closeaftersendbytes=closeaftersendbytes) |
107 closeaftersendbytes=closeaftersendbytes) |
|
108 |
|
109 def sendall(self, data, flags=0): |
|
110 remaining = object.__getattribute__(self, '_closeaftersendbytes') |
|
111 |
|
112 # No read limit. Call original function. |
|
113 if not remaining: |
|
114 result = object.__getattribute__(self, '_orig').sendall(data, flags) |
|
115 self._writelog(b'sendall(%d) -> %s' % (len(data), data)) |
|
116 return result |
|
117 |
|
118 if len(data) > remaining: |
|
119 newdata = data[0:remaining] |
|
120 else: |
|
121 newdata = data |
|
122 |
|
123 remaining -= len(newdata) |
|
124 |
|
125 result = object.__getattribute__(self, '_orig').sendall(newdata, flags) |
|
126 |
|
127 self._writelog(b'sendall(%d from %d) -> (%d) %s' % ( |
|
128 len(newdata), len(data), remaining, newdata)) |
|
129 |
|
130 object.__setattr__(self, '_closeaftersendbytes', remaining) |
|
131 |
|
132 if remaining <= 0: |
|
133 self._writelog(b'write limit reached; closing socket') |
|
134 object.__getattribute__(self, '_orig').shutdown(socket.SHUT_RDWR) |
|
135 |
|
136 raise Exception('connection closed after sending N bytes') |
|
137 |
|
138 return result |
|
139 |
101 |
140 |
102 # We can't adjust __class__ on socket._fileobject, so define a proxy. |
141 # We can't adjust __class__ on socket._fileobject, so define a proxy. |
103 class fileobjectproxy(object): |
142 class fileobjectproxy(object): |
104 __slots__ = ( |
143 __slots__ = ( |
105 '_orig', |
144 '_orig', |