mirror of
https://github.com/foomo/soap.git
synced 2025-10-16 12:45:36 +00:00
141 lines
2.8 KiB
Go
141 lines
2.8 KiB
Go
package soap
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/xml"
|
|
"io/ioutil"
|
|
"log"
|
|
"net"
|
|
"net/http"
|
|
"time"
|
|
)
|
|
|
|
// ClientDialTimeout default timeout 30s
|
|
var ClientDialTimeout = time.Duration(30 * time.Second)
|
|
|
|
// UserAgent is the default user agent
|
|
var UserAgent = "go-soap-0.1"
|
|
|
|
// Verbose be verbose
|
|
var Verbose = false
|
|
|
|
func l(m ...interface{}) {
|
|
if Verbose {
|
|
log.Println(m...)
|
|
}
|
|
}
|
|
|
|
// XMLMarshaller lets you inject your favourite custom xml implementation
|
|
type XMLMarshaller interface {
|
|
Marshal(v interface{}) ([]byte, error)
|
|
Unmarshal(xml []byte, v interface{}) error
|
|
}
|
|
|
|
type defaultMarshaller struct {
|
|
}
|
|
|
|
func (dm *defaultMarshaller) Marshal(v interface{}) (xmlBytes []byte, err error) {
|
|
return xml.Marshal(v)
|
|
}
|
|
|
|
func (dm *defaultMarshaller) Unmarshal(xmlBytes []byte, v interface{}) error {
|
|
return xml.Unmarshal(xmlBytes, v)
|
|
}
|
|
|
|
func newDefaultMarshaller() XMLMarshaller {
|
|
return &defaultMarshaller{}
|
|
}
|
|
|
|
func dialTimeout(network, addr string) (net.Conn, error) {
|
|
return net.DialTimeout(network, addr, ClientDialTimeout)
|
|
}
|
|
|
|
// BasicAuth credentials for the client
|
|
type BasicAuth struct {
|
|
Login string
|
|
Password string
|
|
}
|
|
|
|
// Client generic SOAP client
|
|
type Client struct {
|
|
url string
|
|
tls bool
|
|
auth *BasicAuth
|
|
tr *http.Transport
|
|
Marshaller XMLMarshaller
|
|
}
|
|
|
|
// NewClient constructor
|
|
func NewClient(url string, auth *BasicAuth, tr *http.Transport) *Client {
|
|
return &Client{
|
|
url: url,
|
|
auth: auth,
|
|
tr: tr,
|
|
Marshaller: newDefaultMarshaller(),
|
|
}
|
|
}
|
|
|
|
// Call make a SOAP call
|
|
func (s *Client) Call(soapAction string, request, response interface{}) (httpResponse *http.Response, err error) {
|
|
envelope := Envelope{}
|
|
|
|
envelope.Body.Content = request
|
|
|
|
xmlBytes, err := s.Marshaller.Marshal(envelope)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
req, err := http.NewRequest("POST", s.url, bytes.NewBuffer(xmlBytes))
|
|
if err != nil {
|
|
return
|
|
}
|
|
if s.auth != nil {
|
|
req.SetBasicAuth(s.auth.Login, s.auth.Password)
|
|
}
|
|
|
|
req.Header.Add("Content-Type", "text/xml; charset=\"utf-8\"")
|
|
req.Header.Set("User-Agent", UserAgent)
|
|
|
|
if soapAction != "" {
|
|
req.Header.Add("SOAPAction", soapAction)
|
|
}
|
|
|
|
req.Close = true
|
|
tr := s.tr
|
|
if tr == nil {
|
|
tr = http.DefaultTransport.(*http.Transport)
|
|
}
|
|
client := &http.Client{Transport: tr}
|
|
l("POST to", s.url, "with", string(xmlBytes))
|
|
httpResponse, err = client.Do(req)
|
|
if err != nil {
|
|
return
|
|
}
|
|
defer httpResponse.Body.Close()
|
|
|
|
rawbody, err := ioutil.ReadAll(httpResponse.Body)
|
|
if err != nil {
|
|
return
|
|
}
|
|
if len(rawbody) == 0 {
|
|
l("empty response")
|
|
return
|
|
}
|
|
|
|
l("response", string(rawbody))
|
|
respEnvelope := new(Envelope)
|
|
respEnvelope.Body = Body{Content: response}
|
|
err = xml.Unmarshal(rawbody, respEnvelope)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
fault := respEnvelope.Body.Fault
|
|
if fault != nil {
|
|
err = fault
|
|
return
|
|
}
|
|
return
|
|
}
|