mirror of
https://github.com/Hopiu/linkchecker.git
synced 2026-04-13 02:41:03 +00:00
use Pythons builtin HTTPS support
git-svn-id: https://linkchecker.svn.sourceforge.net/svnroot/linkchecker/trunk/linkchecker@317 e7d03fd6-7b0d-0410-9947-9c21f3af8025
This commit is contained in:
parent
3f18aafa43
commit
d54f2ba8da
13 changed files with 58 additions and 694 deletions
6
debian/changelog
vendored
6
debian/changelog
vendored
|
|
@ -1,3 +1,9 @@
|
|||
linkchecker (1.3.10) unstable; urgency=low
|
||||
|
||||
* use Pythons builtin HTTPS support
|
||||
|
||||
-- Bastian Kleineidam <calvin@debian.org> Tue, 20 Nov 2001 21:24:28 +0100
|
||||
|
||||
linkchecker (1.3.9) unstable; urgency=low
|
||||
|
||||
* new config option --interactive for interactive URL input
|
||||
|
|
|
|||
10
debian/control
vendored
10
debian/control
vendored
|
|
@ -3,13 +3,13 @@ Section: web
|
|||
Priority: optional
|
||||
Maintainer: Bastian Kleineidam <calvin@debian.org>
|
||||
Build-Depends-Indep: python-dev (>= 2.1), python-dev (<< 2.2), debhelper (>= 3.0.0), gettext
|
||||
Standards-Version: 3.5.6
|
||||
Standards-Version: 3.5.6.0
|
||||
|
||||
Package: linkchecker
|
||||
Architecture: all
|
||||
Architecture: any
|
||||
Depends: python (>= 2.1)
|
||||
Conflicts: python (>= 2.2)
|
||||
Suggests: linkchecker-ssl
|
||||
Conflicts: python (>= 2.2), python-ssl (>= 2.2)
|
||||
Suggests: python-ssl (>= 2.1)
|
||||
Description: check HTML documents for broken links
|
||||
Features:
|
||||
o recursive checking
|
||||
|
|
@ -25,3 +25,5 @@ Description: check HTML documents for broken links
|
|||
o i18n support
|
||||
o command line interface
|
||||
o (Fast)CGI web interface (requires HTTP server)
|
||||
|
||||
You have to install python-ssl for HTTPS support.
|
||||
|
|
|
|||
32
debian/linkchecker-ssl.postinst
vendored
32
debian/linkchecker-ssl.postinst
vendored
|
|
@ -1,32 +0,0 @@
|
|||
#!/bin/sh -e
|
||||
#
|
||||
# Written 1998 by Gregor Hoffleit <flight@debian.org>.
|
||||
# used by Bastian Kleineidam for LinkChecker
|
||||
|
||||
PYTHON=python2.1
|
||||
FILELIST=
|
||||
SITEPACKAGES=/usr/lib/$PYTHON/site-packages
|
||||
DIRLIST=linkcheckssl
|
||||
COMMAND="'import sys,py_compile;py_compile.compile(sys.argv[1])'"
|
||||
|
||||
case "$1" in
|
||||
configure|abort-upgrade|abort-remove|abort-deconfigure)
|
||||
for i in $DIRLIST; do
|
||||
$PYTHON -O /usr/lib/$PYTHON/compileall.py -q $SITEPACKAGES/$i
|
||||
$PYTHON /usr/lib/$PYTHON/compileall.py -q $SITEPACKAGES/$i
|
||||
done
|
||||
# use /bin/sh -c, otherwise I get a SyntaxError from Python
|
||||
for i in $FILELIST; do
|
||||
/bin/sh -c "$PYTHON -O -c $COMMAND $SITEPACKAGES/$i"
|
||||
/bin/sh -c "$PYTHON -c $COMMAND $SITEPACKAGES/$i"
|
||||
done
|
||||
;;
|
||||
*)
|
||||
echo "postinst called with unknown argument \`$1'" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
#DEBHELPER#
|
||||
|
||||
exit 0
|
||||
17
debian/linkchecker-ssl.prerm
vendored
17
debian/linkchecker-ssl.prerm
vendored
|
|
@ -1,17 +0,0 @@
|
|||
#!/bin/sh -e
|
||||
#
|
||||
# Written 1998 by Gregor Hoffleit <flight@debian.org>.
|
||||
# used by Bastian Kleineidam for LinkChecker
|
||||
|
||||
PYTHON=python2.1
|
||||
PACKAGE=linkchecker-ssl
|
||||
|
||||
#DEBHELPER#
|
||||
|
||||
dpkg --listfiles $PACKAGE |
|
||||
awk '$0~/\.py$/ {print $0"c\n" $0"o"}' |
|
||||
xargs rm -f >&2
|
||||
|
||||
rmdir /usr/lib/$PYTHON/site-packages/linkcheckssl 2>/dev/null || true
|
||||
|
||||
exit 0
|
||||
5
debian/rules
vendored
5
debian/rules
vendored
|
|
@ -17,14 +17,13 @@ export DH_OPTIONS
|
|||
configure: configure-stamp
|
||||
configure-stamp:
|
||||
dh_testdir
|
||||
$(PYTHON) setup.py config -lcrypto
|
||||
$(PYTHON) setup.py config
|
||||
touch configure-stamp
|
||||
|
||||
|
||||
build: configure-stamp build-stamp
|
||||
build-stamp:
|
||||
dh_testdir
|
||||
rm -rf debian/linkchecker debian/linkchecker-ssl
|
||||
$(PYTHON) setup.py build
|
||||
touch build-stamp
|
||||
|
||||
|
|
@ -44,8 +43,6 @@ install: build
|
|||
rm -r debian/$(PACKAGE)/usr/man
|
||||
# remove files, we install them below
|
||||
rm -r debian/$(PACKAGE)/usr/share/linkchecker/examples
|
||||
# remove any SSL related files
|
||||
rm -r debian/$(PACKAGE)/usr/lib/$(PYTHON)/site-packages/linkcheckssl
|
||||
# install additional doc files
|
||||
install -c -m 644 DNS/README $(DOCDIR)/README_DNS.txt
|
||||
install -c -m 644 test/*.py $(DOCDIR)/test
|
||||
|
|
|
|||
|
|
@ -15,10 +15,13 @@
|
|||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
import re,string,os,urlparse,urllib
|
||||
from UrlData import UrlData
|
||||
import re, os, urlparse, urllib
|
||||
from UrlData import UrlData, ExcList
|
||||
from linkcheck import _
|
||||
|
||||
# OSError is thrown on Windows when a file is not found
|
||||
ExcList.append(OSError)
|
||||
|
||||
html_re = re.compile(r'(?i)\.s?html?$')
|
||||
html_content_re = re.compile(r'(?i)<html>.*</html>')
|
||||
opera_re = re.compile(r'^(?i)opera.adr$')
|
||||
|
|
@ -48,7 +51,7 @@ class FileUrlData(UrlData):
|
|||
self.urlName = os.getcwd()+"/"+self.urlName
|
||||
if winre.search(self.urlName):
|
||||
self.adjustWinPath()
|
||||
self.urlName = string.replace(self.urlName, "\\", "/")
|
||||
self.urlName = self.urlName.replace("\\", "/")
|
||||
self.urlName = "file://"+self.urlName
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -15,8 +15,8 @@
|
|||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
import httplib,urlparse,sys,time,re
|
||||
import Config,StringUtil,robotparser2
|
||||
import httplib, urlparse, sys, time, re
|
||||
import Config, StringUtil, robotparser2
|
||||
from UrlData import UrlData
|
||||
from urllib import splittype, splithost, splituser, splitpasswd
|
||||
from linkcheck import _
|
||||
|
|
@ -223,7 +223,10 @@ class HttpUrlData(UrlData):
|
|||
return self.urlConnection.getreply()
|
||||
|
||||
def _getHTTPObject(self, host):
|
||||
return httplib.HTTP(host)
|
||||
h = httplib.HTTP()
|
||||
h.set_debuglevel(Config.DebugLevel)
|
||||
h.connect(host)
|
||||
return h
|
||||
|
||||
def getContent(self):
|
||||
if not self.has_content:
|
||||
|
|
|
|||
|
|
@ -17,19 +17,16 @@
|
|||
|
||||
from UrlData import UrlData
|
||||
from HttpUrlData import HttpUrlData
|
||||
from linkcheck import _
|
||||
_supportHttps=1
|
||||
try:
|
||||
from linkcheckssl import httpslib
|
||||
except ImportError:
|
||||
_supportHttps=0
|
||||
from linkcheck import _, Config
|
||||
_supportHttps = hasattr(httplib, "HTTPS")
|
||||
|
||||
|
||||
class HttpsUrlData(HttpUrlData):
|
||||
"""Url link with https scheme"""
|
||||
|
||||
def _getHTTPObject(self, host):
|
||||
h = httpslib.HTTPS()
|
||||
h = httplib.HTTPS()
|
||||
h.set_debuglevel(Config.DebugLevel)
|
||||
h.connect(host)
|
||||
return h
|
||||
|
||||
|
|
|
|||
|
|
@ -15,10 +15,10 @@
|
|||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
import sys,re,string,urlparse,urllib,time,DNS
|
||||
import Config,StringUtil,linkcheck,linkname
|
||||
import sys, re, urlparse, urllib, time, DNS, traceback
|
||||
import Config, StringUtil, linkcheck, linkname
|
||||
debug = Config.debug
|
||||
from linkcheck import _
|
||||
debug = linkcheck.Config.debug
|
||||
from debuglevels import *
|
||||
|
||||
# we catch these exceptions, all other exceptions are internal
|
||||
|
|
@ -43,7 +43,7 @@ _linkMatcher = r"""
|
|||
\s* # whitespace
|
||||
%s # tag name
|
||||
\s+ # whitespace
|
||||
[^>]*? # skip leading attributes
|
||||
[^>]*? # skip leading attributes (fails on Python 2.2b2)
|
||||
%s # attrib name
|
||||
\s* # whitespace
|
||||
= # equal sign
|
||||
|
|
@ -108,8 +108,7 @@ BasePattern = {
|
|||
'attr': 'href',
|
||||
}
|
||||
|
||||
CommentPattern = re.compile("<!--.*?--\s*>", re.DOTALL)
|
||||
|
||||
#CommentPattern = re.compile("<!--.*?--\s*>", re.DOTALL)
|
||||
# Workaround for Python 2.0 re module bug
|
||||
CommentPatternBegin = re.compile("<!--")
|
||||
CommentPatternEnd = re.compile("--\s*>")
|
||||
|
|
@ -189,8 +188,8 @@ class UrlData:
|
|||
self.url = self.urlName
|
||||
self.urlTuple = urlparse.urlparse(self.url)
|
||||
# make host lowercase
|
||||
self.urlTuple = (self.urlTuple[0],string.lower(self.urlTuple[1]),
|
||||
self.urlTuple[2],self.urlTuple[3],self.urlTuple[4],
|
||||
self.urlTuple = (self.urlTuple[0], self.urlTuple[1].lower(),
|
||||
self.urlTuple[2], self.urlTuple[ 3],self.urlTuple[4],
|
||||
self.urlTuple[5])
|
||||
self.url = urlparse.urlunparse(self.urlTuple)
|
||||
# resolve HTML entities
|
||||
|
|
@ -221,7 +220,8 @@ class UrlData:
|
|||
self.buildUrl()
|
||||
self.extern = self._getExtern(config)
|
||||
except tuple(ExcList):
|
||||
type, value = sys.exc_info()[:2]
|
||||
type, value, tb = sys.exc_info()
|
||||
debug(HURT_ME_PLENTY, "exception", traceback.format_tb(tb))
|
||||
self.setError(str(value))
|
||||
self.logMe(config)
|
||||
return
|
||||
|
|
@ -248,8 +248,8 @@ class UrlData:
|
|||
if self.urlTuple and config["anchors"]:
|
||||
self.checkAnchors(self.urlTuple[5])
|
||||
except tuple(ExcList):
|
||||
type, value = sys.exc_info()[:2]
|
||||
#print type, value
|
||||
type, value, tb = sys.exc_info()
|
||||
debug(HURT_ME_PLENTY, "exception", traceback.format_tb(tb))
|
||||
self.setError(str(value))
|
||||
|
||||
# check content
|
||||
|
|
@ -258,7 +258,8 @@ class UrlData:
|
|||
debug(BRING_IT_ON, "checking content")
|
||||
try: self.checkContent(warningregex)
|
||||
except tuple(ExcList):
|
||||
type, value = sys.exc_info()[:2]
|
||||
type, value, tb = sys.exc_info()
|
||||
debug(HURT_ME_PLENTY, "exception", traceback.format_tb(tb))
|
||||
self.setError(str(value))
|
||||
|
||||
self.checktime = time.time() - t
|
||||
|
|
@ -417,7 +418,7 @@ class UrlData:
|
|||
index = match.end()
|
||||
if self.is_in_comment(match.start()): continue
|
||||
# need to strip optional ending quotes for the meta tag
|
||||
url = string.strip(StringUtil.stripQuotes(match.group('value')))
|
||||
url = StringUtil.stripQuotes(match.group('value')).strip()
|
||||
# need to resolve HTML entities
|
||||
url = StringUtil.unhtmlify(url)
|
||||
lineno=StringUtil.getLineNumber(self.getContent(), match.start())
|
||||
|
|
@ -480,11 +481,11 @@ def GetUrlDataFrom(urlName, recursionLevel, parentName = None,
|
|||
# search for the absolute url
|
||||
url=""
|
||||
if urlName and ":" in urlName:
|
||||
url = string.lower(urlName)
|
||||
url = urlName.lower()
|
||||
elif baseRef and ":" in baseRef:
|
||||
url = string.lower(baseRef)
|
||||
url = baseRef.lower()
|
||||
elif parentName and ":" in parentName:
|
||||
url = string.lower(parentName)
|
||||
url = parentName.lower()
|
||||
# test scheme
|
||||
if re.search("^http:", url):
|
||||
klass = HttpUrlData
|
||||
|
|
|
|||
|
|
@ -1 +0,0 @@
|
|||
"""ssl wrapper module"""
|
||||
|
|
@ -1,175 +0,0 @@
|
|||
# @(#)httpslib.py 1.1 VMS-99/01/30 https support
|
||||
|
||||
import ssl,httplib,string,socket,mimetools
|
||||
|
||||
HTTP_PREF = 'HTTP/'
|
||||
HTTPS_PORT = 443
|
||||
|
||||
class HTTPS(httplib.HTTP):
|
||||
|
||||
def connect (self, host, port = 0):
|
||||
"""Connect to a host on a given port.
|
||||
|
||||
Note: This method is automatically invoked by __init__,
|
||||
if a host is specified during instantiation.
|
||||
|
||||
"""
|
||||
if not port:
|
||||
i = string.find(host, ':')
|
||||
if i >= 0:
|
||||
host, port = host[:i], host[i+1:]
|
||||
try: port = string.atoi(port)
|
||||
except string.atoi_error:
|
||||
raise socket.error, "nonnumeric port"
|
||||
if not port: port = HTTPS_PORT
|
||||
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
if self.debuglevel > 0: print 'connect:', (host, port)
|
||||
self.sock.connect((host, port))
|
||||
self.ssl = ssl.ssl(self.sock.fileno())
|
||||
|
||||
def send (self, str):
|
||||
if self.debuglevel > 0: print 'send:', `str`
|
||||
self.ssl.write(str,len(str))
|
||||
|
||||
def makefile (self, mode='r', bufsize=-1):
|
||||
return _fileobject(self.sock,self.ssl,mode,bufsize)
|
||||
|
||||
def getreply (self):
|
||||
self.file = self.makefile('rb')
|
||||
# self.sock = None
|
||||
line = self.file.readline()
|
||||
if self.debuglevel > 0: print 'reply:',`line`
|
||||
try:
|
||||
[ver,code,msg] = string.split(line,None,2)
|
||||
except ValueError:
|
||||
try:
|
||||
[ver,code] = string.split(line,None,1)
|
||||
msg = ""
|
||||
except ValueError:
|
||||
ver = ""
|
||||
if ver[:len(HTTP_PREF)] != HTTP_PREF:
|
||||
self.headers = None
|
||||
return -1, line, self.headers
|
||||
self.headers = mimetools.Message(self.file,0)
|
||||
return string.atoi(code), string.strip(msg), self.headers
|
||||
|
||||
def close (self):
|
||||
if self.file:
|
||||
self.file.close()
|
||||
self.file = self.sock = self.ssl = None
|
||||
|
||||
class _fileobject:
|
||||
|
||||
def __init__ (self, sock, ssl, mode, bufsize):
|
||||
import string
|
||||
self._sock = sock
|
||||
self._ssl = ssl
|
||||
self._mode = mode
|
||||
if bufsize < 0:
|
||||
bufsize = 512
|
||||
self._rbufsize = max(1,bufsize)
|
||||
self._wbufsize = bufsize
|
||||
self._wbuf = self._rbuf = ""
|
||||
|
||||
def close (self):
|
||||
try:
|
||||
if self._sock:
|
||||
self.flush()
|
||||
finally:
|
||||
self._sock = None
|
||||
|
||||
def __del__ (self):
|
||||
self.close()
|
||||
|
||||
def flush (self):
|
||||
if self._wbuf:
|
||||
self._sock.write(self._wbuf,len(self._wbuf))
|
||||
self._wbuf = ""
|
||||
|
||||
def fileno (self):
|
||||
return self._sock.fileno()
|
||||
|
||||
def write (self, data):
|
||||
self._wbuf += data
|
||||
if self._wbufsize == 1:
|
||||
if '\n' in data:
|
||||
self.flush()
|
||||
else:
|
||||
if len(self._wbuf) >= self._wbufsize:
|
||||
self.flush()
|
||||
|
||||
def writelines (self, lst):
|
||||
filter(self._sock.send,lst)
|
||||
self.flush()
|
||||
|
||||
def read (self, n=-1):
|
||||
if n >= 0:
|
||||
while len(self._rbuf) < n:
|
||||
new = self._ssl.read(self._rbufsize)
|
||||
if not new: break
|
||||
self._rbuf += new
|
||||
data,self._rbuf = self._rbuf[:n],self._rbuf[n:]
|
||||
return data
|
||||
while 1:
|
||||
new = self._ssl.read(self._rbufsize)
|
||||
if not new: break
|
||||
self._rbuf += new
|
||||
data,self._rbuf = self._rbuf,""
|
||||
return data
|
||||
|
||||
def readline (self):
|
||||
data = ""
|
||||
i = string.find(self._rbuf,'\n')
|
||||
while i < 0:
|
||||
new = self._ssl.read(self._rbufsize)
|
||||
if not new: break
|
||||
i = string.find(new,'\n')
|
||||
if i >= 0:
|
||||
i += len(self._rbuf)
|
||||
self._rbuf += new
|
||||
if i < 0:
|
||||
i = len(self._rbuf)
|
||||
else:
|
||||
i += 1
|
||||
data,self._rbuf = self._rbuf[:i],self._rbuf[i:]
|
||||
return data
|
||||
|
||||
def readlines (self):
|
||||
l = []
|
||||
while 1:
|
||||
line = self.readline()
|
||||
if not line: break
|
||||
l.append(line)
|
||||
return l
|
||||
|
||||
def _test():
|
||||
import sys
|
||||
import getopt
|
||||
opts, args = getopt.getopt(sys.argv[1:], 'd')
|
||||
dl = 0
|
||||
for o, a in opts:
|
||||
if o == '-d':
|
||||
dl += 1
|
||||
if args[0:]:
|
||||
host = args[0]
|
||||
if args[1:]:
|
||||
selector = args[1]
|
||||
h = HTTPS()
|
||||
host = 'synergy.as.cmu.edu'
|
||||
selector = '/~geek/'
|
||||
h.set_debuglevel(dl)
|
||||
h.connect(host)
|
||||
h.putrequest('GET', selector)
|
||||
h.endheaders()
|
||||
errcode, errmsg, headers = h.getreply()
|
||||
print 'errcode =', errcode
|
||||
print 'errmsg =', errmsg
|
||||
print "\tHEADERS:"
|
||||
if headers:
|
||||
for header in headers.headers:
|
||||
print string.strip(header)
|
||||
print "\tTEXT:"
|
||||
print h.getfile().read()
|
||||
|
||||
if __name__ == '__main__':
|
||||
_test()
|
||||
|
|
@ -1,356 +0,0 @@
|
|||
/* @(#)ssl.c 1.1 VMS-99/01/30 python wrapper for SSLeay https
|
||||
*/
|
||||
|
||||
#include "Python.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#ifndef MS_WINDOWS
|
||||
#include <sys/socket.h>
|
||||
#else
|
||||
#include <winsock.h>
|
||||
#endif
|
||||
|
||||
#if defined(PYOS_OS2)
|
||||
#define INCL_DOS
|
||||
#define INCL_DOSERRORS
|
||||
#define INCL_NOPMAPI
|
||||
#include <os2.h>
|
||||
#endif
|
||||
|
||||
#include "ssl.h"
|
||||
#include "err.h"
|
||||
|
||||
/* Global variable holding the exception type for errors detected
|
||||
by this module (but not argument type or memory errors, etc.). */
|
||||
|
||||
static PyObject *PySslError;
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
int sock_fd;
|
||||
PyObject *x_attr; /* attributes dictionary */
|
||||
SSL_CTX *ctx;
|
||||
SSL *ssl;
|
||||
X509 *server_cert;
|
||||
BIO *sbio;
|
||||
char server[256];
|
||||
char issuer[256];
|
||||
} PySslObject;
|
||||
|
||||
staticforward PyTypeObject SSL_Type;
|
||||
#define PySslObject_Check(v) ((v)->ob_type == &SSL_Type)
|
||||
#define PY_SSL_ERR_MAX 256
|
||||
|
||||
/*
|
||||
* raise an error according to errno, return NULL
|
||||
*/
|
||||
static PyObject* PySsl_errno (void) {
|
||||
#ifdef MS_WINDOWS
|
||||
if (WSAGetLastError()) {
|
||||
PyObject *v = Py_BuildValue("(is)",WSAGetLastError(),"winsock error");
|
||||
|
||||
if (v) {
|
||||
PyErr_SetObject(PySslError,v);
|
||||
Py_DECREF(v);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
return PyErr_SetFromErrno(PySslError);
|
||||
}
|
||||
|
||||
/*
|
||||
* format SSl error string
|
||||
*/
|
||||
static int PySsl_err_str (unsigned long e, char* buf) {
|
||||
unsigned long l = ERR_GET_LIB(e);
|
||||
unsigned long f = ERR_GET_FUNC(e);
|
||||
unsigned long r = ERR_GET_REASON(e);
|
||||
char* ls = (char*)ERR_lib_error_string(e);
|
||||
char* fs = (char*)ERR_func_error_string(e);
|
||||
char* rs = (char*)ERR_reason_error_string(e);
|
||||
char* bp = buf + 2; /* skip two initial blanks */
|
||||
|
||||
(void)strcpy(buf," none:"); /* initialize buffer */
|
||||
bp += (ls) ? sprintf(bp,"%s:",ls) :
|
||||
((l) ? sprintf(bp,"lib %lu:",l) : 0);
|
||||
bp += (fs) ? sprintf(bp,"%s ",fs) :
|
||||
((f) ? sprintf(bp,"func %lu:",f) : 0);
|
||||
bp += (rs) ? sprintf(bp,"%s:",rs) :
|
||||
((r) ? sprintf(bp,"reason(%lu):",r) : 0);
|
||||
*bp-- = 0; /* suppress last divider (:) */
|
||||
return (bp - buf);
|
||||
}
|
||||
|
||||
/*
|
||||
* report SSL core errors
|
||||
*/
|
||||
static PySslObject* PySsl_errors (void) {
|
||||
unsigned long e;
|
||||
char buf[2 * PY_SSL_ERR_MAX];
|
||||
char *bf = buf;
|
||||
|
||||
while (((bf - buf) < PY_SSL_ERR_MAX) && (e = ERR_get_error()))
|
||||
bf += PySsl_err_str(e,bf);
|
||||
{
|
||||
PyObject *v = Py_BuildValue("(sss)", "ssl","core",buf+2);
|
||||
if (v != NULL) {
|
||||
PyErr_SetObject(PySslError,v);
|
||||
Py_DECREF(v);
|
||||
}
|
||||
}
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* report SSL application layer errors
|
||||
*/
|
||||
static PySslObject* PySsl_app_errors (SSL* s, int ret) {
|
||||
int err = SSL_get_error(s,ret);
|
||||
char *str;
|
||||
|
||||
switch (err) {
|
||||
case SSL_ERROR_SSL:
|
||||
return (PySsl_errors());
|
||||
case SSL_ERROR_SYSCALL:
|
||||
return ((PySslObject *)PySsl_errno());
|
||||
case SSL_ERROR_ZERO_RETURN:
|
||||
str = "End of data";
|
||||
break;
|
||||
case SSL_ERROR_WANT_READ:
|
||||
str = "Want read";
|
||||
break;
|
||||
case SSL_ERROR_WANT_WRITE:
|
||||
str = "Want write";
|
||||
break;
|
||||
case SSL_ERROR_WANT_X509_LOOKUP:
|
||||
str = "Want x509 lookup";
|
||||
break;
|
||||
case SSL_ERROR_WANT_CONNECT:
|
||||
str = "Want connect";
|
||||
break;
|
||||
default:
|
||||
str = "Unknown";
|
||||
break;
|
||||
}
|
||||
{
|
||||
PyObject *v = Py_BuildValue("(sis)", "ssl",err, str);
|
||||
if (v != NULL) {
|
||||
PyErr_SetObject(PySslError,v);
|
||||
Py_DECREF(v);
|
||||
}
|
||||
}
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* ssl.read(len) method */
|
||||
|
||||
static PyObject* PySslObj_read (PySslObject* self, PyObject* args) {
|
||||
int len, n;
|
||||
PyObject *buf;
|
||||
|
||||
if (!PyArg_ParseTuple(args,"i",&len))
|
||||
return (NULL);
|
||||
if (!(buf = PyString_FromStringAndSize((char *)0,len)))
|
||||
return (NULL);
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
|
||||
n = SSL_read(self->ssl,PyString_AsString(buf),len);
|
||||
|
||||
Py_END_ALLOW_THREADS
|
||||
|
||||
switch (SSL_get_error(self->ssl,n)) {
|
||||
case SSL_ERROR_NONE: /* good return value */
|
||||
break;
|
||||
case SSL_ERROR_ZERO_RETURN:
|
||||
case SSL_ERROR_SYSCALL:
|
||||
if (!n) /* fix SSL_ERROR_SYCSALL errno=0 case */
|
||||
break;
|
||||
/* fall thru here */
|
||||
default:
|
||||
Py_DECREF(buf);
|
||||
(void)PySsl_app_errors(self->ssl,n);
|
||||
return (NULL);
|
||||
}
|
||||
if ((n != len) && (_PyString_Resize(&buf,n) < 0))
|
||||
return (NULL);
|
||||
return (buf);
|
||||
}
|
||||
|
||||
/* ssl.write(data,len) method */
|
||||
|
||||
static PyObject* PySslObj_write (PySslObject* self, PyObject * args) {
|
||||
char *buf;
|
||||
int len, n;
|
||||
if (!PyArg_ParseTuple(args, "si", &buf, &len))
|
||||
return NULL;
|
||||
|
||||
/* Note: flags are ignored */
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
|
||||
n = SSL_write(self->ssl,buf,len);
|
||||
|
||||
Py_END_ALLOW_THREADS
|
||||
if (n < 0)
|
||||
return (PySsl_errno());
|
||||
return (PyInt_FromLong((long)n));
|
||||
}
|
||||
|
||||
/* ssl.server() method */
|
||||
|
||||
static PyObject* PySslObj_server (PySslObject* self, PyObject* args) {
|
||||
if (!PyArg_NoArgs(args))
|
||||
return (NULL);
|
||||
return (PyString_FromString(self->server));
|
||||
}
|
||||
|
||||
/* ssl.issuer() method */
|
||||
|
||||
static PyObject* PySslObj_issuer (PySslObject* self, PyObject* args) {
|
||||
if (!PyArg_NoArgs(args))
|
||||
return (NULL);
|
||||
return (PyString_FromString(self->issuer));
|
||||
}
|
||||
|
||||
/* SSL object methods */
|
||||
|
||||
static PyMethodDef PySslObj_methods[] = {
|
||||
{"read", (PyCFunction)PySslObj_read,1},
|
||||
{"write", (PyCFunction)PySslObj_write,1},
|
||||
{"server", (PyCFunction)PySslObj_server},
|
||||
{"issuer", (PyCFunction)PySslObj_issuer},
|
||||
{ NULL, NULL}
|
||||
};
|
||||
|
||||
static void PySsl_dealloc (PySslObject * self) {
|
||||
if (self->server_cert) /* possible not to have one? */
|
||||
X509_free(self->server_cert);
|
||||
SSL_CTX_free(self->ctx);
|
||||
SSL_free(self->ssl);
|
||||
Py_XDECREF(self->x_attr);
|
||||
PyMem_DEL(self);
|
||||
}
|
||||
|
||||
static PyObject* PySsl_getattr (PySslObject* self, char * name) {
|
||||
return (Py_FindMethod(PySslObj_methods,(PyObject *)self,name));
|
||||
}
|
||||
|
||||
staticforward PyTypeObject SSL_Type = {
|
||||
PyObject_HEAD_INIT(&PyType_Type)
|
||||
0, /*ob_size*/
|
||||
"SSL", /*tp_name*/
|
||||
sizeof(PySslObject), /*tp_basicsize*/
|
||||
0, /*tp_itemsize*/
|
||||
/* methods */
|
||||
(destructor)PySsl_dealloc, /*tp_dealloc*/
|
||||
0, /*tp_print*/
|
||||
(getattrfunc)PySsl_getattr, /*tp_getattr*/
|
||||
0, /*tp_setattr*/
|
||||
0, /*tp_compare*/
|
||||
0, /*tp_repr*/
|
||||
0, /*tp_as_number*/
|
||||
0, /*tp_as_sequence*/
|
||||
0, /*tp_as_mapping*/
|
||||
0, /*tp_hash*/
|
||||
};
|
||||
|
||||
/*
|
||||
* C function called for new object initialization
|
||||
* Note: SSL protocol version 2, 3, or 2+3 set at compile time
|
||||
*/
|
||||
static PySslObject* newPySslObject (int sock_fd) {
|
||||
PySslObject *self;
|
||||
SSL_METHOD *meth;
|
||||
int ret;
|
||||
|
||||
#if 0
|
||||
meth=SSLv3_client_method();
|
||||
meth=SSLv23_client_method();
|
||||
#endif
|
||||
|
||||
meth=SSLv2_client_method();
|
||||
|
||||
if (!(self = PyObject_NEW(PySslObject,&SSL_Type))) /* create new object */
|
||||
return (NULL);
|
||||
(void)memset(self->server,0,sizeof(self->server));
|
||||
(void)memset(self->issuer,0,sizeof(self->issuer));
|
||||
|
||||
self->x_attr = PyDict_New();
|
||||
if (!(self->ctx = SSL_CTX_new(meth))) { /* set up context */
|
||||
PyMem_DEL(self);
|
||||
return (PySsl_errors());
|
||||
}
|
||||
#if 0 /* Note: set this for v23, Netscape server */
|
||||
SSL_CTX_set_options(self->ctx,SSL_OP_ALL);
|
||||
#endif
|
||||
self->ssl = SSL_new(self->ctx); /* new ssl struct */
|
||||
if (!(ret = SSL_set_fd(self->ssl,sock_fd))) { /* set the socket for SSL */
|
||||
PyMem_DEL(self);
|
||||
return (PySsl_app_errors(self->ssl,ret));
|
||||
}
|
||||
SSL_CTX_set_verify(self->ctx,SSL_VERIFY_NONE,NULL); /* set verify lvl */
|
||||
SSL_set_connect_state(self->ssl);
|
||||
|
||||
if ((ret = SSL_connect(self->ssl)) < 0) { /* negotiate SSL connection */
|
||||
PyMem_DEL(self);
|
||||
return (PySsl_app_errors(self->ssl,ret));
|
||||
}
|
||||
self->ssl->debug = 1;
|
||||
|
||||
if ((self->server_cert = SSL_get_peer_certificate(self->ssl))) {
|
||||
X509_NAME_oneline(X509_get_subject_name(self->server_cert),
|
||||
self->server,sizeof(self->server));
|
||||
X509_NAME_oneline(X509_get_issuer_name(self->server_cert),
|
||||
self->issuer, sizeof(self->issuer));
|
||||
}
|
||||
self->x_attr = NULL;
|
||||
self->sock_fd = sock_fd;
|
||||
return (self);
|
||||
}
|
||||
|
||||
/*
|
||||
* Python function called for new object initialization
|
||||
*/
|
||||
static PyObject* PySsl_ssl_new (PyObject* self, PyObject* args) {
|
||||
int sock_fd;
|
||||
if (!PyArg_ParseTuple(args, "i", &sock_fd))
|
||||
return (NULL);
|
||||
return ((PyObject *)newPySslObject(sock_fd));
|
||||
}
|
||||
|
||||
/* List of functions exported by this module. */
|
||||
|
||||
static PyMethodDef PySsl_methods[] = {
|
||||
{"ssl", (PyCFunction)PySsl_ssl_new, METH_VARARGS},
|
||||
{NULL, NULL} /* sentinel */
|
||||
|
||||
};
|
||||
|
||||
/*
|
||||
* Initialize this module, called when the first 'import ssl' is done
|
||||
*/
|
||||
void
|
||||
#ifdef WIN32
|
||||
__declspec(dllexport)
|
||||
#endif
|
||||
initssl (void) {
|
||||
PyObject *m, *d;
|
||||
m = Py_InitModule("ssl", PySsl_methods);
|
||||
d = PyModule_GetDict(m);
|
||||
|
||||
SSL_load_error_strings();
|
||||
SSLeay_add_ssl_algorithms();
|
||||
|
||||
/* *** Python 1.5 ***
|
||||
if (!(PySssl_Error = PyErr_NewException("ssl.error",NULL,NULL)))
|
||||
return;
|
||||
*/
|
||||
|
||||
if (!(PySslError = PyString_FromString("ssl.error")) ||
|
||||
PyDict_SetItemString(d,"error",PySslError))
|
||||
Py_FatalError("can't define ssl.error");
|
||||
if (PyDict_SetItemString(d,"SSLType",(PyObject *)&SSL_Type))
|
||||
return;
|
||||
}
|
||||
|
||||
88
setup.py
88
setup.py
|
|
@ -82,57 +82,6 @@ class MyInstall(install):
|
|||
print " %s: %s" % (opt_name, val)
|
||||
|
||||
|
||||
class MyConfig(config):
|
||||
user_options = config.user_options + [
|
||||
('ssl-include-dirs=', None,
|
||||
"directories to search for SSL header files"),
|
||||
('ssl-library-dirs=', None,
|
||||
"directories to search for SSL library files"),
|
||||
]
|
||||
|
||||
|
||||
def initialize_options (self):
|
||||
config.initialize_options(self)
|
||||
self.ssl_include_dirs = None
|
||||
self.ssl_library_dirs = None
|
||||
|
||||
|
||||
def finalize_options(self):
|
||||
# we have some default include and library directories
|
||||
# suitable for each platform
|
||||
config.finalize_options(self)
|
||||
if self.ssl_include_dirs is None:
|
||||
if os.name=='posix':
|
||||
self.ssl_include_dirs = ['/usr/include/openssl',
|
||||
'/usr/local/include/openssl']
|
||||
else:
|
||||
# dont know default incldirs on other platforms
|
||||
self.ssl_include_dirs = []
|
||||
if self.ssl_library_dirs is None:
|
||||
if os.name=='posix':
|
||||
self.ssl_library_dirs = ['/usr/lib', '/usr/local/lib']
|
||||
else:
|
||||
# dont know default libdirs on other platforms
|
||||
self.ssl_library_dirs = []
|
||||
|
||||
|
||||
def run (self):
|
||||
# try to compile a test program with SSL
|
||||
config.run(self)
|
||||
self.libraries.append('ssl')
|
||||
have_ssl = self.check_lib("ssl",
|
||||
library_dirs = self.ssl_library_dirs,
|
||||
include_dirs = self.ssl_include_dirs,
|
||||
headers = ["ssl.h"])
|
||||
# write the result in the configuration file
|
||||
data = []
|
||||
data.append("have_ssl = %d" % (have_ssl))
|
||||
data.append("ssl_library_dirs = %s" % `self.ssl_library_dirs`)
|
||||
data.append("ssl_include_dirs = %s" % `self.ssl_include_dirs`)
|
||||
data.append("libraries = %s" % `self.libraries`)
|
||||
data.append("install_data = %s" % `os.getcwd()`)
|
||||
self.distribution.create_conf_file(".", data)
|
||||
|
||||
|
||||
class MyDistribution(Distribution):
|
||||
def __init__(self, attrs=None):
|
||||
|
|
@ -141,34 +90,23 @@ class MyDistribution(Distribution):
|
|||
|
||||
|
||||
def run_commands(self):
|
||||
if "config" not in self.commands:
|
||||
self.check_ssl()
|
||||
cwd = os.getcwd()
|
||||
data = []
|
||||
data.append('config_dir = %s' % `os.path.join(cwd, "config")`)
|
||||
data.append("install_data = %s" % `cwd`)
|
||||
self.create_conf_file(".", data)
|
||||
Distribution.run_commands(self)
|
||||
|
||||
|
||||
def check_ssl(self):
|
||||
if not os.path.exists(self.config_file):
|
||||
#raise SystemExit, "please run 'python setup.py config'"
|
||||
self.announce("generating default configuration")
|
||||
self.run_command('config')
|
||||
import _linkchecker_configdata
|
||||
if 'bdist_wininst' in self.commands and os.name != 'nt':
|
||||
self.announce("bdist_wininst command found on non-Windows "
|
||||
"platform. Disabling SSL compilation")
|
||||
elif _linkchecker_configdata.have_ssl:
|
||||
self.ext_modules = [Extension('linkcheckssl.ssl',
|
||||
['linkcheckssl/ssl.c'],
|
||||
include_dirs=_linkchecker_configdata.ssl_include_dirs,
|
||||
library_dirs=_linkchecker_configdata.ssl_library_dirs,
|
||||
libraries=_linkchecker_configdata.libraries)]
|
||||
|
||||
|
||||
def create_conf_file(self, directory, data=[]):
|
||||
data.insert(0, "# this file is automatically created by setup.py")
|
||||
filename = os.path.join(directory, self.config_file)
|
||||
# add metadata
|
||||
metanames = dir(self.metadata) + \
|
||||
['fullname', 'contact', 'contact_email']
|
||||
metanames = ("name", "version", "author", "author_email",
|
||||
"maintainer", "maintainer_email", "url",
|
||||
"licence", "description", "long_description",
|
||||
"keywords", "platforms", "fullname", "contact",
|
||||
"contact_email", "licence", "fullname")
|
||||
for name in metanames:
|
||||
method = "get_" + name
|
||||
cmd = "%s = %s" % (name, `getattr(self.metadata, method)()`)
|
||||
|
|
@ -189,7 +127,7 @@ myname = "Bastian Kleineidam"
|
|||
myemail = "calvin@users.sourceforge.net"
|
||||
|
||||
setup (name = "linkchecker",
|
||||
version = "1.3.9",
|
||||
version = "1.3.10",
|
||||
description = "check HTML documents for broken links",
|
||||
author = myname,
|
||||
author_email = myemail,
|
||||
|
|
@ -213,9 +151,7 @@ o a command line interface
|
|||
o a (Fast)CGI web interface (requires HTTP server)
|
||||
""",
|
||||
distclass = MyDistribution,
|
||||
cmdclass = {'config': MyConfig,
|
||||
'install': MyInstall,
|
||||
},
|
||||
cmdclass = {'install': MyInstall},
|
||||
packages = ['','DNS','linkcheck','linkcheckssl'],
|
||||
scripts = ['linkchecker'],
|
||||
data_files = [('share/locale/de/LC_MESSAGES',
|
||||
|
|
|
|||
Loading…
Reference in a new issue