Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cleanup external schema fetching #48

Merged
merged 10 commits into from
Dec 10, 2015
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
GHACCOUNT := hooklift
NAME := gowsdl
VERSION := v0.1.2
VERSION := v0.2.0

include common.mk

Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,6 @@ Usage: gowsdl [options] myservice.wsdl
File where the generated code will be saved (default "myservice.go")
-p string
Package under which code will be generated (default "myservice")
-i Skips TLS Verification
-v Shows gowsdl version
```
3 changes: 2 additions & 1 deletion cmd/gowsdl/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ var Name string
var vers = flag.Bool("v", false, "Shows gowsdl version")
var pkg = flag.String("p", "myservice", "Package under which code will be generated")
var outFile = flag.String("o", "myservice.go", "File where the generated code will be saved")
var insecure = flag.Bool("i", false, "Skips TLS Verification")

func init() {
log.SetFlags(0)
Expand Down Expand Up @@ -99,7 +100,7 @@ func main() {
}

// load wsdl
gowsdl, err := gen.NewGoWSDL(wsdlPath, *pkg, false)
gowsdl, err := gen.NewGoWSDL(wsdlPath, *pkg, *insecure)
if err != nil {
log.Fatalln(err)
}
Expand Down
67 changes: 39 additions & 28 deletions gowsdl.go
Original file line number Diff line number Diff line change
Expand Up @@ -178,19 +178,19 @@ func (g *GoWSDL) unmarshal() error {
return nil
}

func (g *GoWSDL) resolveXSDExternals(schema *XSDSchema, url *url.URL) error {
for _, incl := range schema.Includes {
location, err := url.Parse(incl.SchemaLocation)
func (g *GoWSDL) getSchema(schemaLocation string, url *url.URL) error {
_, schemaFile := filepath.Split(schemaLocation)

data, err := ioutil.ReadFile(schemaFile)
if err != nil {

location, err := url.Parse(schemaLocation)
if err != nil {
return err
}

_, schemaName := filepath.Split(location.Path)
if g.resolvedXSDExternals[schemaName] {
continue
}
schemaLocation = location.String()

schemaLocation := location.String()
if !location.IsAbs() {
if !url.IsAbs() {
return fmt.Errorf("Unable to resolve external schema %s through WSDL URL %s", schemaLocation, url)
Expand All @@ -200,55 +200,66 @@ func (g *GoWSDL) resolveXSDExternals(schema *XSDSchema, url *url.URL) error {

log.Println("Downloading external schema", "location", schemaLocation)

data, err := downloadFile(schemaLocation, g.ignoreTLS)
newschema := new(XSDSchema)

err = xml.Unmarshal(data, newschema)
data, err = downloadFile(schemaLocation, g.ignoreTLS)
if err != nil {
return err
}
}
newschema := new(XSDSchema)

if len(newschema.Includes) > 0 &&
maxRecursion > g.currentRecursionLevel {
err = xml.Unmarshal(data, newschema)
if err != nil {
return err
}

if len(newschema.Includes) > 0 || len(newschema.Imports) > 0 {
if maxRecursion > g.currentRecursionLevel {

g.currentRecursionLevel++

//log.Printf("Entering recursion %d\n", g.currentRecursionLevel)
g.resolveXSDExternals(newschema, url)
}
}

g.wsdl.Types.Schemas = append(g.wsdl.Types.Schemas, newschema)
g.wsdl.Types.Schemas = append(g.wsdl.Types.Schemas, newschema)

return nil
}

func (g *GoWSDL) resolveXSDExternals(schema *XSDSchema, url *url.URL) error {
if len(schema.Includes) > 0 || len(schema.Imports) > 0 {
if g.resolvedXSDExternals == nil {
g.resolvedXSDExternals = make(map[string]bool, maxRecursion)
}
g.resolvedXSDExternals[schemaName] = true
}

for _, incl := range schema.Imports {
location, err := url.Parse(incl.SchemaLocation)
var err error
for _, incl := range schema.Includes {
if g.resolvedXSDExternals[incl.SchemaLocation] {
continue
}

err = g.getSchema(incl.SchemaLocation, url)
if err != nil {
return err
}

_, schemaName := filepath.Split(location.Path)
if g.resolvedXSDExternals[schemaName] {
g.resolvedXSDExternals[incl.SchemaLocation] = true
}

for _, imp := range schema.Imports {
if g.resolvedXSDExternals[imp.SchemaLocation] {
continue
}

data, err := ioutil.ReadFile(schemaName)
newschema := new(XSDSchema)
err = xml.Unmarshal(data, newschema)
err = g.getSchema(imp.SchemaLocation, url)
if err != nil {
return err
}

g.wsdl.Types.Schemas = append(g.wsdl.Types.Schemas, newschema)
g.resolvedXSDExternals[imp.SchemaLocation] = true

if g.resolvedXSDExternals == nil {
g.resolvedXSDExternals = make(map[string]bool, maxRecursion)
}
g.resolvedXSDExternals[schemaName] = true
}

return nil
Expand Down
85 changes: 62 additions & 23 deletions soap_tmpl.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,26 @@ func dialTimeout(network, addr string) (net.Conn, error) {

type SOAPEnvelope struct {
XMLName xml.Name ` + "`" + `xml:"http://schemas.xmlsoap.org/soap/envelope/ Envelope"` + "`" + `
Body SOAPBody ` + "`" + `xml:"http://schemas.xmlsoap.org/soap/envelope/ Body"` + "`" + `

Body SOAPBody
}

type SOAPHeader struct {
XMLName xml.Name ` + "`" + `xml:"http://schemas.xmlsoap.org/soap/envelope/ Header"` + "`" + `

Header interface{}
}

type SOAPBody struct {
Fault *SOAPFault ` + "`" + `xml:"http://schemas.xmlsoap.org/soap/envelope/ Fault,omitempty"` + "`" + `
Content string ` + "`" + `xml:",innerxml"` + "`" + `
XMLName xml.Name ` + "`" + `xml:"http://schemas.xmlsoap.org/soap/envelope/ Body"` + "`" + `

Fault *SOAPFault ` + "`" + `xml:",omitempty"` + "`" + `
Content interface{} ` + "`" + `xml:",omitempty"` + "`" + `
}

type SOAPFault struct {
XMLName xml.Name ` + "`" + `xml:"http://schemas.xmlsoap.org/soap/envelope/ Fault"` + "`" + `

Code string ` + "`" + `xml:"faultcode,omitempty"` + "`" + `
String string ` + "`" + `xml:"faultstring,omitempty"` + "`" + `
Actor string ` + "`" + `xml:"faultactor,omitempty"` + "`" + `
Expand All @@ -43,6 +50,56 @@ type SOAPClient struct {
auth *BasicAuth
}

func (b *SOAPBody) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
if b.Content == nil {
return xml.UnmarshalError("Content must be a pointer to a struct")
}

var (
token xml.Token
err error
consumed bool
)

Loop:
for {
if token, err = d.Token(); err != nil {
return err
}

if token == nil {
break
}

switch se := token.(type) {
case xml.StartElement:
if consumed {
return xml.UnmarshalError("Found multiple elements inside SOAP body; not wrapped-document/literal WS-I compliant")
} else if se.Name.Space == "http://schemas.xmlsoap.org/soap/envelope/" && se.Name.Local == "Fault" {
b.Fault = &SOAPFault{}
b.Content = nil

err = d.DecodeElement(b.Fault, &se)
if err != nil {
return err
}

consumed = true
} else {
if err = d.DecodeElement(b.Content, &se); err != nil {
return err
}

consumed = true
}
case xml.EndElement:
break Loop
}
}

return nil
}

func (f *SOAPFault) Error() string {
return f.String
}
Expand All @@ -60,14 +117,7 @@ func (s *SOAPClient) Call(soapAction string, request, response interface{}) erro
//Header: SoapHeader{},
}

if request != nil {
reqXml, err := xml.Marshal(request)
if err != nil {
return err
}

envelope.Body.Content = string(reqXml)
}
envelope.Body.Content = request
buffer := new(bytes.Buffer)

encoder := xml.NewEncoder(buffer)
Expand Down Expand Up @@ -118,28 +168,17 @@ func (s *SOAPClient) Call(soapAction string, request, response interface{}) erro

log.Println(string(rawbody))
respEnvelope := new(SOAPEnvelope)
respEnvelope.Body = SOAPBody{Content: response}
err = xml.Unmarshal(rawbody, respEnvelope)
if err != nil {
return err
}

body := respEnvelope.Body.Content
fault := respEnvelope.Body.Fault
if body == "" {
log.Println("empty response body", "envelope", respEnvelope, "body", body)
return nil
}

log.Println("response", "envelope", respEnvelope, "body", body)
if fault != nil {
return fault
}

err = xml.Unmarshal([]byte(body), response)
if err != nil {
return err
}

return nil
}
`