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

Added configure request callback function, #25

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

notzippy
Copy link
Contributor

this allows caller to modify the body of the request or add authentication
to the header of the request. It is optional to use it.

Signed-off-by: NotZippy notzippy@gmail.com

this allows caller to modify the body of the request or add authentication
to the header of the request. It is optional to use it

Signed-off-by: NotZippy <notzippy@gmail.com>
@notzippy
Copy link
Contributor Author

This allows the user to pass in a function to be called before the request is made. The idea is that I will add a standard function to fix the namespace in the xml and the user can simply pass that function to this request.

@@ -9,9 +9,11 @@ package {{.}}
// Do not modify
// Copyright (c) 2015, Hooklift. All rights reserved.
import (
"net/http"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems like an unused import, are you using gofmt?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is required for the operations https://github.com/notzippy/gowsdl/blob/add_soap_header/generator/operations_tmpl.go#L38

I gofmt the soap.go file, appears I have an extra line in this file though..

@c4milo
Copy link
Member

c4milo commented Mar 18, 2015

@notzippy do you have an example of a function fixing a namespace?

@notzippy
Copy link
Contributor Author

The service

serviceFunction := func(req *http.Request) {

    // Read byte buffer so we can modify it
    var buf bytes.Buffer
    buf.ReadFrom(req.Body);
    doc := fixNameSpace(&buf)
    buf.Reset()
    buf.Write(doc.SaveBytes())
    req.Body = ioutil.NopCloser(&buf)
    req.ContentLength = int64(buf.Len())

}

The fixNameSpace function

    // Fixes namespace and returns xmlxDocument
func fixNameSpace(byteBuffer *bytes.Buffer) (doc *xmlx.Document){
    doc = xmlx.New()
    doc.LoadBytes(byteBuffer.Bytes(),nil)

    fixUpNameSpaceMap := map[string][]*xmlx.Node {}
    checkNode := func(node *xmlx.Node, matcher func(node *xmlx.Node)(bool)) (nextnode *xmlx.Node)  {
        checkMatcher := func(position int, children[] *xmlx.Node) (returnNode *xmlx.Node) {
            if len(children)>position {
                returnNode = children[position];
                for ; !matcher(returnNode); position++ {
                    if position < len(children) {
                        returnNode = children[position]
                    } else {
                        returnNode = nil
                        break
                    }
                }
            }
            return
        }
        if nextnode = checkMatcher(0,node.Children);nextnode!=nil {
            return nextnode
        }

        if node.Parent!=doc.Root {
            checkPosition:=0
            checkParent:=node.Parent
            currentNode := node
            for nextnode==nil {
                // find current in parent
                if currentNode==checkParent.Children[checkPosition] {
                    // Found position
                    if nextnode = checkMatcher(checkPosition+1,checkParent.Children);nextnode!=nil {
                        return nextnode
                    }

                    // Go up a parent
                    currentNode = checkParent
                    checkParent = currentNode.Parent
                    if checkParent==doc.Root {
                        break
                    }
                    checkPosition=0
                } else {
                    checkPosition ++
                }
            }
        }
        return
    }
    next := doc.Root
    var rootNode *xmlx.Node
    for {
        next = checkNode(next, func(node *xmlx.Node)(bool) {
                return node.Type==xmlx.NT_ELEMENT
            })
        if next==nil {
            break
        }
        if next.Name.Local!="xml" {
            if next.Name.Space=="" {
                continue
            }
            fixUpNameSpaceMap[next.Name.Space] = append(fixUpNameSpaceMap[next.Name.Space], next)
            if rootNode==nil {
                rootNode = next
            }
        } else {
            doc.Root.RemoveChild(next)
        }
    }

    nameSpaceStart := []byte("AA")
    for r,a:=range fixUpNameSpaceMap {
        // Determine if value is already declared in root node
        sub:=""
        for _,attribute := range rootNode.Attributes {
            if attribute.Value==r {
                if attribute.Name.Local=="xmlns" {
                    attribute.Name.Space="xmlns"
                    attribute.Name.Local = string(nameSpaceStart)
                    nameSpaceStart[1]++

                }
                sub = attribute.Name.Local
            }
        }
        if sub=="" {
            sub = string(nameSpaceStart)
            nameSpaceStart[1]++
            rootNode.Attributes = append(rootNode.Attributes,&xmlx.Attr{Name:xml.Name{Space:"xmlns", Local:sub},Value:r})
        }
        for _,node := range a {
            node.Name.Space = sub;
            // Remove node attributes with local name space defined in attributes
            for si,sa :=range node.Attributes {
                if sa.Name.Local=="xmlns" {
                    node.Attributes = append(node.Attributes[:si],node.Attributes[si+1:]...)
                    break
                }
            }
        }
    }

    doc.SaveDocType = true

    return doc;
}

@notzippy
Copy link
Contributor Author

Sorry I did not look at your test cases, likely all broke because I changed the function signature in the soap

@c4milo
Copy link
Member

c4milo commented Mar 18, 2015

Is there a way of fixing namespaces for everybody altogether? I'm not feeling very strong about adding the configureRequest function. What else could be configured? basic auth?

@notzippy
Copy link
Contributor Author

Yes that was the thought behind the callback originally. There may be other
headers that people need set as well. Giving a function to call back is the
quickest way to provide this. I guess you could also add a variable in the
package and have it set similarly.

On Wed, Mar 18, 2015, 4:47 PM Camilo Aguilar notifications@github.com
wrote:

Is there a way of fixing namespaces for everybody altogether? I'm not
feeling very strong about adding the configureRequest function. What else
could be configured? basic auth?


Reply to this email directly or view it on GitHub
#25 (comment).

@c4milo
Copy link
Member

c4milo commented Mar 19, 2015

@notzippy ok, let's go with that for now. I will finish reviewing and merging tomorrow morning. Thanks a lot for your help @notzippy!

@notzippy
Copy link
Contributor Author

No problems, on second thought why not add an extended function to the
template (a second service call) The first one would not have any callback,
and it would call the extended version passing in the xml namespace fix
function. So it would remain backyard comparisons but still proved the
extra function to those who need it.

On Wed, Mar 18, 2015, 5:17 PM Camilo Aguilar notifications@github.com
wrote:

@notzippy https://github.com/notzippy ok, let's go with that for now. I
will finish reviewing and merging tomorrow morning. Thanks a lot for your
help @notzippy https://github.com/notzippy!


Reply to this email directly or view it on GitHub
#25 (comment).

@notzippy
Copy link
Contributor Author

Final thoughts...
Some soap elements are required to be present (omitempty must be removed), but they need this attribute set xsi:nil="true" to indicate that they are empty, using the xmlx.Doc this function adds that to the document

// Fixes nil (empty) elements by setting http://www.w3.org/2001/XMLSchema-instance:xsi="true"
// eg <Foobar /> Becomes <Foobar xsi:nil="true"/>
func FixNilSpace(doc *xmlx.Document) {

    next := doc.Root
    var rootNode *xmlx.Node
    for {
        next = nodeWalker(doc,next, func(node *xmlx.Node) (bool) {
            return node.Type==xmlx.NT_ELEMENT
        })
        if next==nil {
            break
        }
        if next.Name.Local!="xml" {
            if rootNode==nil {
                rootNode = next
            }
            if len(next.Children)==1 {
                // Check child type
                node := next.Children[0]
                if node.Type == xmlx.NT_TEXT && node.Value=="" {
                    // This is a nil node, add attribute to it
                    next.Attributes = append(next.Attributes, &xmlx.Attr{Name:xml.Name{Space:"xsi", Local:"nil"}, Value:"true"})
                    next.RemoveChild(node)
                    checkAllChildrenNil(doc,next.Parent)
                }
            } else if len(next.Children)==0 {
                next.Attributes = append(next.Attributes, &xmlx.Attr{Name:xml.Name{Space:"xsi", Local:"nil"}, Value:"true"})
                checkAllChildrenNil(doc,next.Parent)
            }
        }
    }
    rootNode.Attributes = append(rootNode.Attributes, &xmlx.Attr{Name:xml.Name{Space:"xmlns", Local:"xsi"}, Value:"http://www.w3.org/2001/XMLSchema-instance"})


}
func checkAllChildrenNil(doc *xmlx.Document,parent *xmlx.Node) {
    for _,c:=range parent.Children {
        if !c.HasAttr("xsi","nil") {
            return
        }
    }
    // add nil attribute to this node and check parent
    parent.Attributes = append(parent.Attributes, &xmlx.Attr{Name:xml.Name{Space:"xsi", Local:"nil"}, Value:"true"})
    parent.Children=[]*xmlx.Node{}
    if doc.Root!=parent.Parent {
        checkAllChildrenNil(doc, parent.Parent)
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants