forked from tiaguinho/gosoap
-
Notifications
You must be signed in to change notification settings - Fork 0
/
soap.go
123 lines (98 loc) 路 2.36 KB
/
soap.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
package gosoap
import (
"bytes"
"encoding/xml"
"fmt"
"io/ioutil"
"net/http"
"net/url"
"strings"
)
// Params type is used to set the params in soap request
type Params map[string]string
// SoapClient return new *Client to handle the requests with the WSDL
func SoapClient(wsdl string) (*Client, error) {
_, err := url.Parse(wsdl)
if err != nil {
return nil, err
}
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 {
WSDL string
URL string
Method string
Params Params
Definitions *wsdlDefinitions
Body []byte
payload []byte
}
// Call call's the method m with Params p
func (c *Client) Call(m string, p Params) (err error) {
c.Method = m
c.Params = p
c.payload, err = xml.MarshalIndent(c, "", "")
if err != nil {
return err
}
b, err := c.doRequest()
if err != nil {
return err
}
var soap SoapEnvelope
err = xml.Unmarshal(b, &soap)
c.Body = soap.Body.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() ([]byte, error) {
req, err := http.NewRequest("POST", c.WSDL, bytes.NewBuffer(c.payload))
if err != nil {
return nil, err
}
client := &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", fmt.Sprintf("%s/%s", c.URL, c.Method))
resp, err := client.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"`
Body SoapBody
}
// SoapBody struct
type SoapBody struct {
XMLName struct{} `xml:"Body"`
Contents []byte `xml:",innerxml"`
}