Forward port of patch # 500311: Work around for buggy https servers.
Fixes #494762.
diff --git a/Lib/httplib.py b/Lib/httplib.py
index 2faf318..9d01859 100644
--- a/Lib/httplib.py
+++ b/Lib/httplib.py
@@ -633,7 +633,8 @@
if (err[0] == socket.SSL_ERROR_WANT_READ
or err[0] == socket.SSL_ERROR_WANT_WRITE):
continue
- if err[0] == socket.SSL_ERROR_ZERO_RETURN:
+ if (err[0] == socket.SSL_ERROR_ZERO_RETURN
+ or err[0] == socket.SSL_ERROR_EOF):
break
raise
except socket.error, err:
diff --git a/Misc/ACKS b/Misc/ACKS
index 2cafde8..12605fc 100644
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -38,6 +38,7 @@
Thomas Bellman
Juan M. Bello Rivas
Andy Bensky
+Michel Van den Bergh
Eric Beser
Stephen Bevan
Ron Bickers
diff --git a/Modules/_ssl.c b/Modules/_ssl.c
index 17ca3b0..f5ab2b6 100644
--- a/Modules/_ssl.c
+++ b/Modules/_ssl.c
@@ -8,6 +8,20 @@
*/
#include "Python.h"
+enum py_ssl_error {
+ /* these mirror ssl.h */
+ PY_SSL_ERROR_NONE,
+ PY_SSL_ERROR_SSL,
+ PY_SSL_ERROR_WANT_READ,
+ PY_SSL_ERROR_WANT_WRITE,
+ PY_SSL_ERROR_WANT_X509_LOOKUP,
+ PY_SSL_ERROR_SYSCALL, /* look at error stack/return value/errno */
+ PY_SSL_ERROR_ZERO_RETURN,
+ PY_SSL_ERROR_WANT_CONNECT,
+ /* start of non ssl.h errorcodes */
+ PY_SSL_ERROR_EOF, /* special case of SSL_ERROR_SYSCALL */
+ PY_SSL_ERROR_INVALID_ERROR_CODE
+};
/* Include symbols from _socket module */
#include "socketmodule.h"
@@ -64,11 +78,71 @@
PyObject *v, *n, *s;
char *errstr;
int err;
+ enum py_ssl_error p;
assert(ret <= 0);
err = SSL_get_error(obj->ssl, ret);
- n = PyInt_FromLong(err);
+
+ switch (err) {
+ case SSL_ERROR_ZERO_RETURN:
+ errstr = "TLS/SSL connection has been closed";
+ p=PY_SSL_ERROR_ZERO_RETURN;
+ break;
+ case SSL_ERROR_WANT_READ:
+ errstr = "The operation did not complete (read)";
+ p=PY_SSL_ERROR_WANT_READ;
+ break;
+ case SSL_ERROR_WANT_WRITE:
+ p=PY_SSL_ERROR_WANT_WRITE;
+ errstr = "The operation did not complete (write)";
+ break;
+ case SSL_ERROR_WANT_X509_LOOKUP:
+ p=PY_SSL_ERROR_WANT_X509_LOOKUP;
+ errstr = "The operation did not complete (X509 lookup)";
+ break;
+ case SSL_ERROR_WANT_CONNECT:
+ p=PY_SSL_ERROR_WANT_CONNECT;
+ errstr = "The operation did not complete (connect)";
+ break;
+ case SSL_ERROR_SYSCALL:
+ {
+ unsigned long e = ERR_get_error();
+ if(e==0){
+ if(ret==0){
+ p=PY_SSL_ERROR_EOF;
+ errstr = "EOF occurred in violation of protocol";
+ }else if(ret==-1){
+ /* the underlying BIO reported an I/O error */
+ return obj->Socket->errorhandler();
+ }else{ /* possible? */
+ p=PY_SSL_ERROR_SYSCALL;
+ errstr = "Some I/O error occurred";
+ }
+ } else {
+ p=PY_SSL_ERROR_SYSCALL;
+ /* XXX Protected by global interpreter lock */
+ errstr = ERR_error_string(e, NULL);
+ }
+ break;
+ }
+ case SSL_ERROR_SSL:
+ {
+ unsigned long e = ERR_get_error();
+ p=PY_SSL_ERROR_SSL;
+ if (e !=0) {
+ /* XXX Protected by global interpreter lock */
+ errstr = ERR_error_string(e, NULL);
+ } else { /* possible? */
+ errstr="A failure in the SSL library occurred";
+ }
+ break;
+ }
+ default:
+ p=PY_SSL_ERROR_INVALID_ERROR_CODE;
+ errstr = "Invalid error code";
+ }
+ n = PyInt_FromLong((long) p);
if (n == NULL)
return NULL;
v = PyTuple_New(2);
@@ -77,40 +151,6 @@
return NULL;
}
- switch (SSL_get_error(obj->ssl, ret)) {
- case SSL_ERROR_ZERO_RETURN:
- errstr = "TLS/SSL connection has been closed";
- break;
- case SSL_ERROR_WANT_READ:
- errstr = "The operation did not complete (read)";
- break;
- case SSL_ERROR_WANT_WRITE:
- errstr = "The operation did not complete (write)";
- break;
- case SSL_ERROR_WANT_X509_LOOKUP:
- errstr = "The operation did not complete (X509 lookup)";
- break;
- case SSL_ERROR_SYSCALL:
- case SSL_ERROR_SSL:
- {
- unsigned long e = ERR_get_error();
- if (e == 0) {
- /* an EOF was observed that violates the protocol */
- errstr = "EOF occurred in violation of protocol";
- } else if (e == -1) {
- /* the underlying BIO reported an I/O error */
- Py_DECREF(v);
- Py_DECREF(n);
- return obj->Socket->errorhandler();
- } else {
- /* XXX Protected by global interpreter lock */
- errstr = ERR_error_string(e, NULL);
- }
- break;
- }
- default:
- errstr = "Invalid error code";
- }
s = PyString_FromString(errstr);
if (s == NULL) {
Py_DECREF(v);
@@ -447,15 +487,23 @@
(PyObject *)&PySSL_Type) != 0)
return;
PyModule_AddIntConstant(m, "SSL_ERROR_ZERO_RETURN",
- SSL_ERROR_ZERO_RETURN);
+ PY_SSL_ERROR_ZERO_RETURN);
PyModule_AddIntConstant(m, "SSL_ERROR_WANT_READ",
- SSL_ERROR_WANT_READ);
+ PY_SSL_ERROR_WANT_READ);
PyModule_AddIntConstant(m, "SSL_ERROR_WANT_WRITE",
- SSL_ERROR_WANT_WRITE);
+ PY_SSL_ERROR_WANT_WRITE);
PyModule_AddIntConstant(m, "SSL_ERROR_WANT_X509_LOOKUP",
- SSL_ERROR_WANT_X509_LOOKUP);
+ PY_SSL_ERROR_WANT_X509_LOOKUP);
PyModule_AddIntConstant(m, "SSL_ERROR_SYSCALL",
- SSL_ERROR_SYSCALL);
+ PY_SSL_ERROR_SYSCALL);
PyModule_AddIntConstant(m, "SSL_ERROR_SSL",
- SSL_ERROR_SSL);
+ PY_SSL_ERROR_SSL);
+ PyModule_AddIntConstant(m, "SSL_ERROR_WANT_CONNECT",
+ PY_SSL_ERROR_WANT_CONNECT);
+ /* non ssl.h errorcodes */
+ PyModule_AddIntConstant(m, "SSL_ERROR_EOF",
+ PY_SSL_ERROR_EOF);
+ PyModule_AddIntConstant(m, "SSL_ERROR_INVALID_ERROR_CODE",
+ PY_SSL_ERROR_INVALID_ERROR_CODE);
+
}