From dc37ddb368ff35fa3975d9e3ba37b0ab1dc6d365 Mon Sep 17 00:00:00 2001 From: Ross Kinder Date: Wed, 23 Dec 2015 17:17:48 -0500 Subject: [PATCH] capture errors from libxml2 fixes #4 --- decrypt_test.go | 4 ++-- encrypt_realworld_test.go | 4 ++-- error.go | 12 ++++++++++-- error_thunk.go | 34 ++++++++++++++++++++++++++-------- xmldsig_test.go | 4 ++-- xmlsec.go | 15 ++++++--------- 6 files changed, 48 insertions(+), 25 deletions(-) diff --git a/decrypt_test.go b/decrypt_test.go index d71a0d3..d1533ee 100644 --- a/decrypt_test.go +++ b/decrypt_test.go @@ -139,7 +139,7 @@ func (testSuite *DecryptTest) TestInvalid(c *C) { c.Assert(err, IsNil) _, err = Decrypt(testSuite.Key, []byte("")) c.Assert(err, ErrorMatches, "xmlSecFindNode cannot find EncryptedData node") @@ -149,7 +149,7 @@ func (testSuite *DecryptTest) TestInvalid(c *C) { docStr = []byte(`https://idp.testshib.org/idp/shibbolethinvalid<`) _, err = Decrypt(testSuite.Key, docStr) - c.Assert(err, ErrorMatches, "malformed XML") + c.Assert(err, ErrorMatches, ".*Premature end of data in tag.*") docStr = []byte(` diff --git a/encrypt_realworld_test.go b/encrypt_realworld_test.go index 543873c..33bbbbe 100644 --- a/encrypt_realworld_test.go +++ b/encrypt_realworld_test.go @@ -95,7 +95,7 @@ func (testSuite *XmlencRealWorldTest) TestInvalid(c *C) { c.Assert(err, IsNil) _, err = Decrypt(testSuite.Key, []byte("")) c.Assert(err, ErrorMatches, "xmlSecFindNode cannot find EncryptedData node") @@ -105,7 +105,7 @@ func (testSuite *XmlencRealWorldTest) TestInvalid(c *C) { docStr := []byte(`https://idp.testshib.org/idp/shibbolethinvalid<`) _, err = Decrypt(testSuite.Key, docStr) - c.Assert(err, ErrorMatches, "malformed XML") + c.Assert(err, ErrorMatches, ".*Premature end of data in tag.*") docStr = []byte(` diff --git a/error.go b/error.go index dfce98f..414b593 100644 --- a/error.go +++ b/error.go @@ -4,6 +4,7 @@ import ( "C" "fmt" "runtime" + "strings" "github.com/crewjam/errset" ) @@ -32,8 +33,8 @@ func (e libraryError) Error() string { e.Message) } -//export onError -func onError(file *C.char, line C.int, funcName *C.char, errorObject *C.char, errorSubject *C.char, reason C.int, msg *C.char) { +//export onXmlsecError +func onXmlsecError(file *C.char, line C.int, funcName *C.char, errorObject *C.char, errorSubject *C.char, reason C.int, msg *C.char) { err := libraryError{ FuncName: C.GoString(funcName), FileName: C.GoString(file), @@ -46,6 +47,13 @@ func onError(file *C.char, line C.int, funcName *C.char, errorObject *C.char, er globalErrors[threadID] = append(globalErrors[threadID], err) } +//export onXmlError +func onXmlError(msg *C.char) { + threadID := getThreadID() + globalErrors[threadID] = append(globalErrors[threadID], + fmt.Errorf("%s", strings.TrimSuffix(C.GoString(msg), "\n"))) +} + // startProcessingXML is called whenever we enter a function exported by this package. // It locks the current goroutine to the current thread and establishes a thread-local // error object. If the library later calls onError then the error will be appended diff --git a/error_thunk.go b/error_thunk.go index d6211a4..068f12d 100644 --- a/error_thunk.go +++ b/error_thunk.go @@ -1,13 +1,31 @@ package xmlsec -// onError_cgo is a C function that can be passed to xmlSecErrorsSetCallback which -// in turn invokes the go function onError which captures errors generated by -// libxmlsec. +// #include +// #include +// #include +// #include +// #include +// #include +// #include // -// For reasons I do not completely understand, it must be defined in a different -// file from onError. - -// void onError_cgo(char *file, int line, char *funcName, char *errorObject, char *errorSubject, int reason, char *msg) { -// onError(file, line, funcName, errorObject, errorSubject, reason, msg); +// void onXmlError(const char *msg); // implemented in go +// void onXmlsecError(const char *file, int line, const char *funcName, const char *errorObject, const char *errorSubject, int reason, const char *msg); // implemented in go +// +// static void onXmlGenericError_cgo(void *ctx, const char *format, ...) { +// char buffer[256]; +// va_list args; +// va_start(args, format); +// vsnprintf(buffer, 256, format, args); +// va_end (args); +// onXmlError(buffer); +// } +// +// static void onXmlsecError_cgo(const char *file, int line, const char *funcName, const char *errorObject, const char *errorSubject, int reason, const char *msg) { +// onXmlsecError(file, line, funcName, errorObject, errorSubject, reason, msg); +// } +// +// void captureXmlErrors() { +// xmlSecErrorsSetCallback(onXmlsecError_cgo); +// xmlSetGenericErrorFunc(NULL, onXmlGenericError_cgo); // } import "C" diff --git a/xmldsig_test.go b/xmldsig_test.go index b699179..42b52f5 100644 --- a/xmldsig_test.go +++ b/xmldsig_test.go @@ -218,7 +218,7 @@ func (testSuite *XMLDSigTest) TestVerifyFailsWhenMessageModified(c *C) { func (testSuite *XMLDSigTest) TestInvalidXML(c *C) { _, err := Sign(testSuite.Key, []byte(""), SignatureOptions{}) c.Assert(err, ErrorMatches, "cannot find start node") @@ -227,7 +227,7 @@ func (testSuite *XMLDSigTest) TestInvalidXML(c *C) { c.Assert(err, ErrorMatches, "failed to load pem key") err = Verify(testSuite.Cert, []byte(""), SignatureOptions{}) c.Assert(err, ErrorMatches, "cannot find start node") diff --git a/xmlsec.go b/xmlsec.go index f66a528..8b1029d 100644 --- a/xmlsec.go +++ b/xmlsec.go @@ -1,9 +1,6 @@ package xmlsec -import ( - "errors" - "unsafe" -) +import "unsafe" // Note: on mac you need: // brew install libxmlsec1 libxml2 @@ -30,7 +27,7 @@ import "C" // } import "C" -// void onError_cgo(char *file, int line, char *funcName, char *errorObject, char *errorSubject, int reason, char *msg); +// void captureXmlErrors(); import "C" func init() { @@ -46,26 +43,26 @@ func init() { panic("xmlsec crypto initialization failed.") } - C.xmlSecErrorsSetCallback((C.xmlSecErrorsCallback)(unsafe.Pointer(C.onError_cgo))) + C.captureXmlErrors() } func newDoc(buf []byte, idattrs []XMLIDOption) (*C.xmlDoc, error) { ctx := C.xmlCreateMemoryParserCtxt((*C.char)(unsafe.Pointer(&buf[0])), C.int(len(buf))) if ctx == nil { - return nil, errors.New("error creating parser") + return nil, mustPopError() } defer C.xmlFreeParserCtxt(ctx) C.xmlParseDocument(ctx) if ctx.wellFormed == C.int(0) { - return nil, errors.New("malformed XML") + return nil, mustPopError() } doc := ctx.myDoc if doc == nil { - return nil, errors.New("parse failed") + return nil, mustPopError() } for _, idattr := range idattrs {