Revision 73a59d9e lib/http.py
b/lib/http.py | ||
---|---|---|
90 | 90 |
|
91 | 91 |
_SSL_UNEXPECTED_EOF = "Unexpected EOF" |
92 | 92 |
|
93 |
# Socket operations |
|
94 |
(SOCKOP_SEND, |
|
95 |
SOCKOP_RECV, |
|
96 |
SOCKOP_SHUTDOWN) = range(3) |
|
97 |
|
|
93 | 98 |
|
94 | 99 |
class SocketClosed(socket.error): |
95 | 100 |
pass |
... | ... | |
101 | 106 |
This should only be used for internal error reporting. |
102 | 107 |
|
103 | 108 |
""" |
104 |
pass |
|
109 |
|
|
110 |
|
|
111 |
class _HttpSocketTimeout(Exception): |
|
112 |
"""Internal exception for socket timeouts. |
|
113 |
|
|
114 |
This should only be used for internal error reporting. |
|
115 |
|
|
116 |
""" |
|
105 | 117 |
|
106 | 118 |
|
107 | 119 |
class HTTPException(Exception): |
... | ... | |
160 | 172 |
return serializer.LoadJson(data) |
161 | 173 |
|
162 | 174 |
|
163 |
def WaitForSocketCondition(sock, poller, event, timeout):
|
|
175 |
def WaitForSocketCondition(poller, sock, event, timeout):
|
|
164 | 176 |
"""Waits for a condition to occur on the socket. |
165 | 177 |
|
166 |
@type sock: socket |
|
167 |
@param socket: Wait for events on this socket |
|
168 | 178 |
@type poller: select.Poller |
169 | 179 |
@param poller: Poller object as created by select.poll() |
180 |
@type sock: socket |
|
181 |
@param socket: Wait for events on this socket |
|
170 | 182 |
@type event: int |
171 | 183 |
@param event: ORed condition (see select module) |
172 | 184 |
@type timeout: float or None |
... | ... | |
199 | 211 |
poller.unregister(sock) |
200 | 212 |
|
201 | 213 |
|
214 |
def SocketOperation(poller, sock, op, arg1, timeout): |
|
215 |
"""Wrapper around socket functions. |
|
216 |
|
|
217 |
This function abstracts error handling for socket operations, especially |
|
218 |
for the complicated interaction with OpenSSL. |
|
219 |
|
|
220 |
@type poller: select.Poller |
|
221 |
@param poller: Poller object as created by select.poll() |
|
222 |
@type sock: socket |
|
223 |
@param socket: Socket for the operation |
|
224 |
@type op: int |
|
225 |
@param op: Operation to execute (SOCKOP_* constants) |
|
226 |
@type arg1: any |
|
227 |
@param arg1: Parameter for function (if needed) |
|
228 |
@type timeout: None or float |
|
229 |
@param timeout: Timeout in seconds or None |
|
230 |
|
|
231 |
""" |
|
232 |
# TODO: event_poll/event_check/override |
|
233 |
if op == SOCKOP_SEND: |
|
234 |
event_poll = select.POLLOUT |
|
235 |
event_check = select.POLLOUT |
|
236 |
|
|
237 |
elif op == SOCKOP_RECV: |
|
238 |
event_poll = select.POLLIN |
|
239 |
event_check = select.POLLIN | select.POLLPRI |
|
240 |
|
|
241 |
elif op == SOCKOP_SHUTDOWN: |
|
242 |
event_poll = None |
|
243 |
event_check = None |
|
244 |
|
|
245 |
# The timeout is only used when OpenSSL requests polling for a condition. |
|
246 |
# It is not advisable to have no timeout for shutdown. |
|
247 |
assert timeout |
|
248 |
|
|
249 |
else: |
|
250 |
raise AssertionError("Invalid socket operation") |
|
251 |
|
|
252 |
# No override by default |
|
253 |
event_override = 0 |
|
254 |
|
|
255 |
while True: |
|
256 |
# Poll only for certain operations and when asked for by an override |
|
257 |
if event_override or op in (SOCKOP_SEND, SOCKOP_RECV): |
|
258 |
if event_override: |
|
259 |
wait_for_event = event_override |
|
260 |
else: |
|
261 |
wait_for_event = event_poll |
|
262 |
|
|
263 |
event = WaitForSocketCondition(poller, sock, wait_for_event, timeout) |
|
264 |
if event is None: |
|
265 |
raise _HttpSocketTimeout() |
|
266 |
|
|
267 |
if (op == SOCKOP_RECV and |
|
268 |
event & (select.POLLNVAL | select.POLLHUP | select.POLLERR)): |
|
269 |
return "" |
|
270 |
|
|
271 |
if not event & wait_for_event: |
|
272 |
continue |
|
273 |
|
|
274 |
# Reset override |
|
275 |
event_override = 0 |
|
276 |
|
|
277 |
try: |
|
278 |
try: |
|
279 |
if op == SOCKOP_SEND: |
|
280 |
return sock.send(arg1) |
|
281 |
|
|
282 |
elif op == SOCKOP_RECV: |
|
283 |
return sock.recv(arg1) |
|
284 |
|
|
285 |
elif op == SOCKOP_SHUTDOWN: |
|
286 |
if isinstance(sock, OpenSSL.SSL.ConnectionType): |
|
287 |
# PyOpenSSL's shutdown() doesn't take arguments |
|
288 |
return sock.shutdown() |
|
289 |
else: |
|
290 |
return sock.shutdown(arg1) |
|
291 |
|
|
292 |
except OpenSSL.SSL.WantWriteError: |
|
293 |
# OpenSSL wants to write, poll for POLLOUT |
|
294 |
event_override = select.POLLOUT |
|
295 |
continue |
|
296 |
|
|
297 |
except OpenSSL.SSL.WantReadError: |
|
298 |
# OpenSSL wants to read, poll for POLLIN |
|
299 |
event_override = select.POLLIN | select.POLLPRI |
|
300 |
continue |
|
301 |
|
|
302 |
except OpenSSL.SSL.WantX509LookupError: |
|
303 |
continue |
|
304 |
|
|
305 |
except OpenSSL.SSL.SysCallError, err: |
|
306 |
if op == SOCKOP_SEND: |
|
307 |
# arg1 is the data when writing |
|
308 |
if err.args and err.args[0] == -1 and arg1 == "": |
|
309 |
# errors when writing empty strings are expected |
|
310 |
# and can be ignored |
|
311 |
return 0 |
|
312 |
|
|
313 |
elif op == SOCKOP_RECV: |
|
314 |
if err.args == (-1, _SSL_UNEXPECTED_EOF): |
|
315 |
return "" |
|
316 |
|
|
317 |
raise socket.error(err.args) |
|
318 |
|
|
319 |
except OpenSSL.SSL.Error, err: |
|
320 |
raise socket.error(err.args) |
|
321 |
|
|
322 |
except socket.error, err: |
|
323 |
if err.args and err.args[0] == errno.EAGAIN: |
|
324 |
# Ignore EAGAIN |
|
325 |
continue |
|
326 |
|
|
327 |
raise |
|
328 |
|
|
329 |
|
|
202 | 330 |
class HttpSslParams(object): |
203 | 331 |
"""Data class for SSL key and certificate. |
204 | 332 |
|
... | ... | |
773 | 901 |
PS_BODY = "body" |
774 | 902 |
PS_COMPLETE = "complete" |
775 | 903 |
|
776 |
# Socket operations |
|
777 |
(OP_SEND, |
|
778 |
OP_RECV, |
|
779 |
OP_CLOSE_CHECK, |
|
780 |
OP_SHUTDOWN) = range(4) |
|
781 |
|
|
782 | 904 |
def __init__(self, req): |
783 | 905 |
"""Initializes the HttpClientRequestExecutor class. |
784 | 906 |
|
... | ... | |
1045 | 1167 |
|
1046 | 1168 |
return buf |
1047 | 1169 |
|
1048 |
def _SocketOperation(self, op, arg1, error_msg, timeout_msg): |
|
1049 |
"""Wrapper around socket functions. |
|
1050 |
|
|
1051 |
This function abstracts error handling for socket operations, especially |
|
1052 |
for the complicated interaction with OpenSSL. |
|
1053 |
|
|
1054 |
""" |
|
1055 |
if op == self.OP_SEND: |
|
1056 |
event_poll = select.POLLOUT |
|
1057 |
event_check = select.POLLOUT |
|
1058 |
timeout = self.WRITE_TIMEOUT |
|
1059 |
|
|
1060 |
elif op in (self.OP_RECV, self.OP_CLOSE_CHECK): |
|
1061 |
event_poll = select.POLLIN |
|
1062 |
event_check = select.POLLIN | select.POLLPRI |
|
1063 |
if op == self.OP_CLOSE_CHECK: |
|
1064 |
timeout = self.CLOSE_TIMEOUT |
|
1065 |
else: |
|
1066 |
timeout = self.READ_TIMEOUT |
|
1067 |
|
|
1068 |
elif op == self.OP_SHUTDOWN: |
|
1069 |
event_poll = None |
|
1070 |
event_check = None |
|
1071 |
|
|
1072 |
# The timeout is only used when OpenSSL requests polling for a condition. |
|
1073 |
# It is not advisable to have no timeout for shutdown. |
|
1074 |
timeout = self.WRITE_TIMEOUT |
|
1075 |
|
|
1076 |
else: |
|
1077 |
raise AssertionError("Invalid socket operation") |
|
1078 |
|
|
1079 |
# No override by default |
|
1080 |
event_override = 0 |
|
1081 |
|
|
1082 |
while True: |
|
1083 |
# Poll only for certain operations and when asked for by an override |
|
1084 |
if (event_override or |
|
1085 |
op in (self.OP_SEND, self.OP_RECV, self.OP_CLOSE_CHECK)): |
|
1086 |
if event_override: |
|
1087 |
wait_for_event = event_override |
|
1088 |
else: |
|
1089 |
wait_for_event = event_poll |
|
1090 |
|
|
1091 |
event = WaitForSocketCondition(self.sock, self.poller, wait_for_event, |
|
1092 |
timeout) |
|
1093 |
if event is None: |
|
1094 |
raise _HttpClientTimeout(timeout_msg) |
|
1095 |
|
|
1096 |
if (op == self.OP_RECV and |
|
1097 |
event & (select.POLLNVAL | select.POLLHUP | select.POLLERR)): |
|
1098 |
return "" |
|
1099 |
|
|
1100 |
if not event & wait_for_event: |
|
1101 |
continue |
|
1102 |
|
|
1103 |
# Reset override |
|
1104 |
event_override = 0 |
|
1105 |
|
|
1106 |
try: |
|
1107 |
try: |
|
1108 |
if op == self.OP_SEND: |
|
1109 |
return self.sock.send(arg1) |
|
1110 |
|
|
1111 |
elif op in (self.OP_RECV, self.OP_CLOSE_CHECK): |
|
1112 |
return self.sock.recv(arg1) |
|
1113 |
|
|
1114 |
elif op == self.OP_SHUTDOWN: |
|
1115 |
if self._using_ssl: |
|
1116 |
# PyOpenSSL's shutdown() doesn't take arguments |
|
1117 |
return self.sock.shutdown() |
|
1118 |
else: |
|
1119 |
return self.sock.shutdown(arg1) |
|
1120 |
|
|
1121 |
except OpenSSL.SSL.WantWriteError: |
|
1122 |
# OpenSSL wants to write, poll for POLLOUT |
|
1123 |
event_override = select.POLLOUT |
|
1124 |
continue |
|
1125 |
|
|
1126 |
except OpenSSL.SSL.WantReadError: |
|
1127 |
# OpenSSL wants to read, poll for POLLIN |
|
1128 |
event_override = select.POLLIN | select.POLLPRI |
|
1129 |
continue |
|
1130 |
|
|
1131 |
except OpenSSL.SSL.WantX509LookupError: |
|
1132 |
continue |
|
1133 |
|
|
1134 |
except OpenSSL.SSL.SysCallError, err: |
|
1135 |
if op == self.OP_SEND: |
|
1136 |
# arg1 is the data when writing |
|
1137 |
if err.args and err.args[0] == -1 and arg1 == "": |
|
1138 |
# errors when writing empty strings are expected |
|
1139 |
# and can be ignored |
|
1140 |
return 0 |
|
1141 |
|
|
1142 |
elif op == self.OP_RECV: |
|
1143 |
if err.args == (-1, _SSL_UNEXPECTED_EOF): |
|
1144 |
return "" |
|
1145 |
|
|
1146 |
raise socket.error(err.args) |
|
1147 |
|
|
1148 |
except OpenSSL.SSL.Error, err: |
|
1149 |
raise socket.error(err.args) |
|
1150 |
|
|
1151 |
except socket.error, err: |
|
1152 |
if err.args and err.args[0] == errno.EAGAIN: |
|
1153 |
# Ignore EAGAIN |
|
1154 |
continue |
|
1155 |
|
|
1156 |
raise _HttpClientError("%s: %s" % (error_msg, str(err))) |
|
1157 |
|
|
1158 | 1170 |
def _Connect(self): |
1159 | 1171 |
"""Non-blocking connect to host with timeout. |
1160 | 1172 |
|
... | ... | |
1185 | 1197 |
|
1186 | 1198 |
if not connected: |
1187 | 1199 |
# Wait for connection |
1188 |
event = WaitForSocketCondition(self.sock, self.poller,
|
|
1200 |
event = WaitForSocketCondition(self.poller, self.sock,
|
|
1189 | 1201 |
select.POLLOUT, self.CONNECT_TIMEOUT) |
1190 | 1202 |
if event is None: |
1191 | 1203 |
raise _HttpClientError("Timeout while connecting to server") |
... | ... | |
1213 | 1225 |
# Send only 4 KB at a time |
1214 | 1226 |
data = buf[:4096] |
1215 | 1227 |
|
1216 |
sent = self._SocketOperation(self.OP_SEND, data, |
|
1217 |
"Error while sending request", |
|
1218 |
"Timeout while sending request") |
|
1228 |
try: |
|
1229 |
sent = SocketOperation(self.poller, self.sock, SOCKOP_SEND, data, |
|
1230 |
self.WRITE_TIMEOUT) |
|
1231 |
except _HttpSocketTimeout: |
|
1232 |
raise _HttpClientError("Timeout while sending request") |
|
1233 |
except socket.error, err: |
|
1234 |
raise _HttpClientError("Error sending request: %s" % err) |
|
1219 | 1235 |
|
1220 | 1236 |
# Remove sent bytes |
1221 | 1237 |
buf = buf[sent:] |
... | ... | |
1231 | 1247 |
buf = "" |
1232 | 1248 |
eof = False |
1233 | 1249 |
while self.parser_status != self.PS_COMPLETE: |
1234 |
data = self._SocketOperation(self.OP_RECV, 4096, |
|
1235 |
"Error while reading response", |
|
1236 |
"Timeout while reading response") |
|
1250 |
try: |
|
1251 |
data = SocketOperation(self.poller, self.sock, SOCKOP_RECV, 4096, |
|
1252 |
self.READ_TIMEOUT) |
|
1253 |
except _HttpSocketTimeout: |
|
1254 |
raise _HttpClientError("Timeout while reading response") |
|
1255 |
except socket.error, err: |
|
1256 |
raise _HttpClientError("Error while reading response: %s" % err) |
|
1237 | 1257 |
|
1238 | 1258 |
if data: |
1239 | 1259 |
buf += data |
... | ... | |
1263 | 1283 |
# Wait for server to close |
1264 | 1284 |
try: |
1265 | 1285 |
# Check whether it's actually closed |
1266 |
if not self._SocketOperation(self.OP_CLOSE_CHECK, 1,
|
|
1267 |
"Error", "Timeout"):
|
|
1286 |
if not SocketOperation(self.poller, self.sock, SOCKOP_RECV, 1,
|
|
1287 |
self.CLOSE_TIMEOUT):
|
|
1268 | 1288 |
return |
1269 |
except (socket.error, _HttpClientError): |
|
1289 |
except (socket.error, _HttpClientError, _HttpSocketTimeout):
|
|
1270 | 1290 |
# Ignore errors at this stage |
1271 | 1291 |
pass |
1272 | 1292 |
|
1273 | 1293 |
# Close the connection from our side |
1274 |
self._SocketOperation(self.OP_SHUTDOWN, socket.SHUT_RDWR, |
|
1275 |
"Error while shutting down connection", |
|
1276 |
"Timeout while shutting down connection") |
|
1294 |
try: |
|
1295 |
SocketOperation(self.poller, self.sock, SOCKOP_SHUTDOWN, |
|
1296 |
socket.SHUT_RDWR, self.WRITE_TIMEOUT) |
|
1297 |
except _HttpSocketTimeout: |
|
1298 |
raise _HttpClientError("Timeout while shutting down connection") |
|
1299 |
except socket.error, err: |
|
1300 |
raise _HttpClientError("Error while shutting down connection: %s" % err) |
|
1277 | 1301 |
|
1278 | 1302 |
|
1279 | 1303 |
class _HttpClientPendingRequest(object): |
Also available in: Unified diff