src.dualinventive.com/go/cp3000-interface/vendor/github.com/tiaguinho/gosoap/soap.go

167 lines
3.5 KiB
Go

package gosoap
import (
"bytes"
"encoding/xml"
"errors"
"fmt"
"io/ioutil"
"net/http"
"strings"
)
// HeaderParams holds params specific to the header
type HeaderParams []Param
// Params type is used to set the params in soap request
type Params []Param
// Para contains the key and value of the header or param
type Param struct {
Key string
Value interface{}
}
// SoapClient return new *Client to handle the requests with the WSDL
func SoapClient(wsdl string) (*Client, error) {
d, err := getWsdlDefinitions(wsdl)
if err != nil {
return nil, err
}
c := &Client{
WSDL: wsdl,
URL: strings.TrimSuffix(d.TargetNamespace, "/"),
Definitions: d,
}
return c, nil
}
// Client struct hold all the informations about WSDL,
// request and response of the server
type Client struct {
HttpClient *http.Client
WSDL string
URL string
Method string
SoapAction string
Params Params
HeaderName string
HeaderParams HeaderParams
Definitions *wsdlDefinitions
Body []byte
Header []byte
Username string
Password string
payload []byte
}
// GetLastRequest returns the last request
func (c *Client) GetLastRequest() []byte {
return c.payload
}
// Call call's the method m with Params p
func (c *Client) Call(m string, p Params) (err error) {
if c.Definitions == nil {
return errors.New("WSDL definitions not found")
}
if c.Definitions.Services == nil {
return errors.New("No Services found in WSDL definitions")
}
c.Method = m
c.Params = p
c.SoapAction = c.Definitions.GetSoapActionFromWsdlOperation(c.Method)
if c.SoapAction == "" {
c.SoapAction = fmt.Sprintf("%s/%s", c.URL, c.Method)
}
c.payload, err = xml.MarshalIndent(c, "", " ")
if err != nil {
return err
}
b, err := c.doRequest(c.Definitions.Services[0].Ports[0].SoapAddresses[0].Location)
if err != nil {
return err
}
var soap SoapEnvelope
err = xml.Unmarshal(b, &soap)
c.Body = soap.Body.Contents
c.Header = soap.Header.Contents
return err
}
// Unmarshal get the body and unmarshal into the interface
func (c *Client) Unmarshal(v interface{}) error {
if len(c.Body) == 0 {
return fmt.Errorf("Body is empty")
}
var f Fault
xml.Unmarshal(c.Body, &f)
if f.Code != "" {
return fmt.Errorf("[%s]: %s", f.Code, f.Description)
}
return xml.Unmarshal(c.Body, v)
}
// doRequest makes new request to the server using the c.Method, c.URL and the body.
// body is enveloped in Call method
func (c *Client) doRequest(url string) ([]byte, error) {
req, err := http.NewRequest("POST", url, bytes.NewBuffer(c.payload))
if err != nil {
return nil, err
}
if c.Username != "" && c.Password != "" {
req.SetBasicAuth(c.Username, c.Password)
}
if c.HttpClient == nil {
c.HttpClient = &http.Client{}
}
req.ContentLength = int64(len(c.payload))
req.Header.Add("Content-Type", "text/xml;charset=UTF-8")
req.Header.Add("Accept", "text/xml")
req.Header.Add("SOAPAction", c.SoapAction)
req.Header.Add("User-Agent", "PHP-SOAP/4.0 MTinfo/4.0")
resp, err := c.HttpClient.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
return ioutil.ReadAll(resp.Body)
}
// SoapEnvelope struct
type SoapEnvelope struct {
XMLName struct{} `xml:"Envelope"`
Header SoapHeader
Body SoapBody
}
// SoapHeader struct
type SoapHeader struct {
XMLName struct{} `xml:"Header"`
Contents []byte `xml:",innerxml"`
}
// SoapBody struct
type SoapBody struct {
XMLName struct{} `xml:"Body"`
Contents []byte `xml:",innerxml"`
}