diff options
author | Ben Kochie <superq@gmail.com> | 2018-08-06 16:54:46 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-08-06 16:54:46 +0200 |
commit | 5d23ad0ca7aea9efb4115af73490da6f8e9d7175 (patch) | |
tree | d06f1ef2512fff1b09ce41a074b53a8ecb1d765d /vendor | |
parent | 2c52b8c76147f0f0671029e9fd7454b9866ace0d (diff) | |
download | prometheus_node_collector-5d23ad0ca7aea9efb4115af73490da6f8e9d7175.tar.bz2 prometheus_node_collector-5d23ad0ca7aea9efb4115af73490da6f8e9d7175.tar.xz prometheus_node_collector-5d23ad0ca7aea9efb4115af73490da6f8e9d7175.zip |
Fix supervisord collector (#978)
* Replace supervisord xmlrpc library
* Use `github.com/mattn/go-xmlrpc` that doesn't leak goroutines.
* Fix uptime metric
* Use Prometheus best practices for uptime metric.
* Use "start time" rather than "uptime".
* Don't emit a start time if the process is down.
* Add changelog entry.
* Add example compatibility rules.
Signed-off-by: Ben Kochie <superq@gmail.com>
Diffstat (limited to 'vendor')
-rw-r--r-- | vendor/github.com/kolo/xmlrpc/README.md | 79 | ||||
-rw-r--r-- | vendor/github.com/kolo/xmlrpc/client.go | 144 | ||||
-rw-r--r-- | vendor/github.com/kolo/xmlrpc/decoder.go | 449 | ||||
-rw-r--r-- | vendor/github.com/kolo/xmlrpc/encoder.go | 164 | ||||
-rw-r--r-- | vendor/github.com/kolo/xmlrpc/request.go | 57 | ||||
-rw-r--r-- | vendor/github.com/kolo/xmlrpc/response.go | 52 | ||||
-rw-r--r-- | vendor/github.com/kolo/xmlrpc/test_server.rb | 25 | ||||
-rw-r--r-- | vendor/github.com/kolo/xmlrpc/xmlrpc.go | 19 | ||||
-rw-r--r-- | vendor/github.com/mattn/go-xmlrpc/LICENSE (renamed from vendor/github.com/kolo/xmlrpc/LICENSE) | 12 | ||||
-rw-r--r-- | vendor/github.com/mattn/go-xmlrpc/README.md | 48 | ||||
-rw-r--r-- | vendor/github.com/mattn/go-xmlrpc/xmlrpc.go | 365 | ||||
-rw-r--r-- | vendor/vendor.json | 12 |
12 files changed, 426 insertions, 1000 deletions
diff --git a/vendor/github.com/kolo/xmlrpc/README.md b/vendor/github.com/kolo/xmlrpc/README.md deleted file mode 100644 index 12b7692..0000000 --- a/vendor/github.com/kolo/xmlrpc/README.md +++ /dev/null | |||
@@ -1,79 +0,0 @@ | |||
1 | ## Overview | ||
2 | |||
3 | xmlrpc is an implementation of client side part of XMLRPC protocol in Go language. | ||
4 | |||
5 | ## Installation | ||
6 | |||
7 | To install xmlrpc package run `go get github.com/kolo/xmlrpc`. To use | ||
8 | it in application add `"github.com/kolo/xmlrpc"` string to `import` | ||
9 | statement. | ||
10 | |||
11 | ## Usage | ||
12 | |||
13 | client, _ := xmlrpc.NewClient("https://bugzilla.mozilla.org/xmlrpc.cgi", nil) | ||
14 | result := struct{ | ||
15 | Version string `xmlrpc:"version"` | ||
16 | }{} | ||
17 | client.Call("Bugzilla.version", nil, &result) | ||
18 | fmt.Printf("Version: %s\n", result.Version) // Version: 4.2.7+ | ||
19 | |||
20 | Second argument of NewClient function is an object that implements | ||
21 | [http.RoundTripper](http://golang.org/pkg/net/http/#RoundTripper) | ||
22 | interface, it can be used to get more control over connection options. | ||
23 | By default it initialized by http.DefaultTransport object. | ||
24 | |||
25 | ### Arguments encoding | ||
26 | |||
27 | xmlrpc package supports encoding of native Go data types to method | ||
28 | arguments. | ||
29 | |||
30 | Data types encoding rules: | ||
31 | * int, int8, int16, int32, int64 encoded to int; | ||
32 | * float32, float64 encoded to double; | ||
33 | * bool encoded to boolean; | ||
34 | * string encoded to string; | ||
35 | * time.Time encoded to datetime.iso8601; | ||
36 | * xmlrpc.Base64 encoded to base64; | ||
37 | * slice decoded to array; | ||
38 | |||
39 | Structs decoded to struct by following rules: | ||
40 | * all public field become struct members; | ||
41 | * field name become member name; | ||
42 | * if field has xmlrpc tag, its value become member name. | ||
43 | |||
44 | Server method can accept few arguments, to handle this case there is | ||
45 | special approach to handle slice of empty interfaces (`[]interface{}`). | ||
46 | Each value of such slice encoded as separate argument. | ||
47 | |||
48 | ### Result decoding | ||
49 | |||
50 | Result of remote function is decoded to native Go data type. | ||
51 | |||
52 | Data types decoding rules: | ||
53 | * int, i4 decoded to int, int8, int16, int32, int64; | ||
54 | * double decoded to float32, float64; | ||
55 | * boolean decoded to bool; | ||
56 | * string decoded to string; | ||
57 | * array decoded to slice; | ||
58 | * structs decoded following the rules described in previous section; | ||
59 | * datetime.iso8601 decoded as time.Time data type; | ||
60 | * base64 decoded to string. | ||
61 | |||
62 | ## Implementation details | ||
63 | |||
64 | xmlrpc package contains clientCodec type, that implements [rpc.ClientCodec](http://golang.org/pkg/net/rpc/#ClientCodec) | ||
65 | interface of [net/rpc](http://golang.org/pkg/net/rpc) package. | ||
66 | |||
67 | xmlrpc package works over HTTP protocol, but some internal functions | ||
68 | and data type were made public to make it easier to create another | ||
69 | implementation of xmlrpc that works over another protocol. To encode | ||
70 | request body there is EncodeMethodCall function. To decode server | ||
71 | response Response data type can be used. | ||
72 | |||
73 | ## Contribution | ||
74 | |||
75 | Feel free to fork the project, submit pull requests, ask questions. | ||
76 | |||
77 | ## Authors | ||
78 | |||
79 | Dmitry Maksimov (dmtmax@gmail.com) | ||
diff --git a/vendor/github.com/kolo/xmlrpc/client.go b/vendor/github.com/kolo/xmlrpc/client.go deleted file mode 100644 index fb66b65..0000000 --- a/vendor/github.com/kolo/xmlrpc/client.go +++ /dev/null | |||
@@ -1,144 +0,0 @@ | |||
1 | package xmlrpc | ||
2 | |||
3 | import ( | ||
4 | "fmt" | ||
5 | "io/ioutil" | ||
6 | "net/http" | ||
7 | "net/http/cookiejar" | ||
8 | "net/rpc" | ||
9 | "net/url" | ||
10 | ) | ||
11 | |||
12 | type Client struct { | ||
13 | *rpc.Client | ||
14 | } | ||
15 | |||
16 | // clientCodec is rpc.ClientCodec interface implementation. | ||
17 | type clientCodec struct { | ||
18 | // url presents url of xmlrpc service | ||
19 | url *url.URL | ||
20 | |||
21 | // httpClient works with HTTP protocol | ||
22 | httpClient *http.Client | ||
23 | |||
24 | // cookies stores cookies received on last request | ||
25 | cookies http.CookieJar | ||
26 | |||
27 | // responses presents map of active requests. It is required to return request id, that | ||
28 | // rpc.Client can mark them as done. | ||
29 | responses map[uint64]*http.Response | ||
30 | |||
31 | response *Response | ||
32 | |||
33 | // ready presents channel, that is used to link request and it`s response. | ||
34 | ready chan uint64 | ||
35 | } | ||
36 | |||
37 | func (codec *clientCodec) WriteRequest(request *rpc.Request, args interface{}) (err error) { | ||
38 | httpRequest, err := NewRequest(codec.url.String(), request.ServiceMethod, args) | ||
39 | |||
40 | if codec.cookies != nil { | ||
41 | for _, cookie := range codec.cookies.Cookies(codec.url) { | ||
42 | httpRequest.AddCookie(cookie) | ||
43 | } | ||
44 | } | ||
45 | |||
46 | if err != nil { | ||
47 | return err | ||
48 | } | ||
49 | |||
50 | var httpResponse *http.Response | ||
51 | httpResponse, err = codec.httpClient.Do(httpRequest) | ||
52 | |||
53 | if err != nil { | ||
54 | return err | ||
55 | } | ||
56 | |||
57 | if codec.cookies != nil { | ||
58 | codec.cookies.SetCookies(codec.url, httpResponse.Cookies()) | ||
59 | } | ||
60 | |||
61 | codec.responses[request.Seq] = httpResponse | ||
62 | codec.ready <- request.Seq | ||
63 | |||
64 | return nil | ||
65 | } | ||
66 | |||
67 | func (codec *clientCodec) ReadResponseHeader(response *rpc.Response) (err error) { | ||
68 | seq := <-codec.ready | ||
69 | httpResponse := codec.responses[seq] | ||
70 | |||
71 | if httpResponse.StatusCode < 200 || httpResponse.StatusCode >= 300 { | ||
72 | return fmt.Errorf("request error: bad status code - %d", httpResponse.StatusCode) | ||
73 | } | ||
74 | |||
75 | respData, err := ioutil.ReadAll(httpResponse.Body) | ||
76 | |||
77 | if err != nil { | ||
78 | return err | ||
79 | } | ||
80 | |||
81 | httpResponse.Body.Close() | ||
82 | |||
83 | resp := NewResponse(respData) | ||
84 | |||
85 | if resp.Failed() { | ||
86 | response.Error = fmt.Sprintf("%v", resp.Err()) | ||
87 | } | ||
88 | |||
89 | codec.response = resp | ||
90 | |||
91 | response.Seq = seq | ||
92 | delete(codec.responses, seq) | ||
93 | |||
94 | return nil | ||
95 | } | ||
96 | |||
97 | func (codec *clientCodec) ReadResponseBody(v interface{}) (err error) { | ||
98 | if v == nil { | ||
99 | return nil | ||
100 | } | ||
101 | |||
102 | if err = codec.response.Unmarshal(v); err != nil { | ||
103 | return err | ||
104 | } | ||
105 | |||
106 | return nil | ||
107 | } | ||
108 | |||
109 | func (codec *clientCodec) Close() error { | ||
110 | transport := codec.httpClient.Transport.(*http.Transport) | ||
111 | transport.CloseIdleConnections() | ||
112 | return nil | ||
113 | } | ||
114 | |||
115 | // NewClient returns instance of rpc.Client object, that is used to send request to xmlrpc service. | ||
116 | func NewClient(requrl string, transport http.RoundTripper) (*Client, error) { | ||
117 | if transport == nil { | ||
118 | transport = http.DefaultTransport | ||
119 | } | ||
120 | |||
121 | httpClient := &http.Client{Transport: transport} | ||
122 | |||
123 | jar, err := cookiejar.New(nil) | ||
124 | |||
125 | if err != nil { | ||
126 | return nil, err | ||
127 | } | ||
128 | |||
129 | u, err := url.Parse(requrl) | ||
130 | |||
131 | if err != nil { | ||
132 | return nil, err | ||
133 | } | ||
134 | |||
135 | codec := clientCodec{ | ||
136 | url: u, | ||
137 | httpClient: httpClient, | ||
138 | ready: make(chan uint64), | ||
139 | responses: make(map[uint64]*http.Response), | ||
140 | cookies: jar, | ||
141 | } | ||
142 | |||
143 | return &Client{rpc.NewClientWithCodec(&codec)}, nil | ||
144 | } | ||
diff --git a/vendor/github.com/kolo/xmlrpc/decoder.go b/vendor/github.com/kolo/xmlrpc/decoder.go deleted file mode 100644 index b739559..0000000 --- a/vendor/github.com/kolo/xmlrpc/decoder.go +++ /dev/null | |||
@@ -1,449 +0,0 @@ | |||
1 | package xmlrpc | ||
2 | |||
3 | import ( | ||
4 | "bytes" | ||
5 | "encoding/xml" | ||
6 | "errors" | ||
7 | "fmt" | ||
8 | "io" | ||
9 | "reflect" | ||
10 | "strconv" | ||
11 | "strings" | ||
12 | "time" | ||
13 | ) | ||
14 | |||
15 | const iso8601 = "20060102T15:04:05" | ||
16 | |||
17 | var ( | ||
18 | // CharsetReader is a function to generate reader which converts a non UTF-8 | ||
19 | // charset into UTF-8. | ||
20 | CharsetReader func(string, io.Reader) (io.Reader, error) | ||
21 | |||
22 | invalidXmlError = errors.New("invalid xml") | ||
23 | ) | ||
24 | |||
25 | type TypeMismatchError string | ||
26 | |||
27 | func (e TypeMismatchError) Error() string { return string(e) } | ||
28 | |||
29 | type decoder struct { | ||
30 | *xml.Decoder | ||
31 | } | ||
32 | |||
33 | func unmarshal(data []byte, v interface{}) (err error) { | ||
34 | dec := &decoder{xml.NewDecoder(bytes.NewBuffer(data))} | ||
35 | |||
36 | if CharsetReader != nil { | ||
37 | dec.CharsetReader = CharsetReader | ||
38 | } | ||
39 | |||
40 | var tok xml.Token | ||
41 | for { | ||
42 | if tok, err = dec.Token(); err != nil { | ||
43 | return err | ||
44 | } | ||
45 | |||
46 | if t, ok := tok.(xml.StartElement); ok { | ||
47 | if t.Name.Local == "value" { | ||
48 | val := reflect.ValueOf(v) | ||
49 | if val.Kind() != reflect.Ptr { | ||
50 | return errors.New("non-pointer value passed to unmarshal") | ||
51 | } | ||
52 | if err = dec.decodeValue(val.Elem()); err != nil { | ||
53 | return err | ||
54 | } | ||
55 | |||
56 | break | ||
57 | } | ||
58 | } | ||
59 | } | ||
60 | |||
61 | // read until end of document | ||
62 | err = dec.Skip() | ||
63 | if err != nil && err != io.EOF { | ||
64 | return err | ||
65 | } | ||
66 | |||
67 | return nil | ||
68 | } | ||
69 | |||
70 | func (dec *decoder) decodeValue(val reflect.Value) error { | ||
71 | var tok xml.Token | ||
72 | var err error | ||
73 | |||
74 | if val.Kind() == reflect.Ptr { | ||
75 | if val.IsNil() { | ||
76 | val.Set(reflect.New(val.Type().Elem())) | ||
77 | } | ||
78 | val = val.Elem() | ||
79 | } | ||
80 | |||
81 | var typeName string | ||
82 | for { | ||
83 | if tok, err = dec.Token(); err != nil { | ||
84 | return err | ||
85 | } | ||
86 | |||
87 | if t, ok := tok.(xml.EndElement); ok { | ||
88 | if t.Name.Local == "value" { | ||
89 | return nil | ||
90 | } else { | ||
91 | return invalidXmlError | ||
92 | } | ||
93 | } | ||
94 | |||
95 | if t, ok := tok.(xml.StartElement); ok { | ||
96 | typeName = t.Name.Local | ||
97 | break | ||
98 | } | ||
99 | |||
100 | // Treat value data without type identifier as string | ||
101 | if t, ok := tok.(xml.CharData); ok { | ||
102 | if value := strings.TrimSpace(string(t)); value != "" { | ||
103 | if err = checkType(val, reflect.String); err != nil { | ||
104 | return err | ||
105 | } | ||
106 | |||
107 | val.SetString(value) | ||
108 | return nil | ||
109 | } | ||
110 | } | ||
111 | } | ||
112 | |||
113 | switch typeName { | ||
114 | case "struct": | ||
115 | ismap := false | ||
116 | pmap := val | ||
117 | valType := val.Type() | ||
118 | |||
119 | if err = checkType(val, reflect.Struct); err != nil { | ||
120 | if checkType(val, reflect.Map) == nil { | ||
121 | if valType.Key().Kind() != reflect.String { | ||
122 | return fmt.Errorf("only maps with string key type can be unmarshalled") | ||
123 | } | ||
124 | ismap = true | ||
125 | } else if checkType(val, reflect.Interface) == nil && val.IsNil() { | ||
126 | var dummy map[string]interface{} | ||
127 | pmap = reflect.New(reflect.TypeOf(dummy)).Elem() | ||
128 | valType = pmap.Type() | ||
129 | ismap = true | ||
130 | } else { | ||
131 | return err | ||
132 | } | ||
133 | } | ||
134 | |||
135 | var fields map[string]reflect.Value | ||
136 | |||
137 | if !ismap { | ||
138 | fields = make(map[string]reflect.Value) | ||
139 | |||
140 | for i := 0; i < valType.NumField(); i++ { | ||
141 | field := valType.Field(i) | ||
142 | fieldVal := val.FieldByName(field.Name) | ||
143 | |||
144 | if fieldVal.CanSet() { | ||
145 | if fn := field.Tag.Get("xmlrpc"); fn != "" { | ||
146 | fields[fn] = fieldVal | ||
147 | } else { | ||
148 | fields[field.Name] = fieldVal | ||
149 | } | ||
150 | } | ||
151 | } | ||
152 | } else { | ||
153 | // Create initial empty map | ||
154 | pmap.Set(reflect.MakeMap(valType)) | ||
155 | } | ||
156 | |||
157 | // Process struct members. | ||
158 | StructLoop: | ||
159 | for { | ||
160 | if tok, err = dec.Token(); err != nil { | ||
161 | return err | ||
162 | } | ||
163 | switch t := tok.(type) { | ||
164 | case xml.StartElement: | ||
165 | if t.Name.Local != "member" { | ||
166 | return invalidXmlError | ||
167 | } | ||
168 | |||
169 | tagName, fieldName, err := dec.readTag() | ||
170 | if err != nil { | ||
171 | return err | ||
172 | } | ||
173 | if tagName != "name" { | ||
174 | return invalidXmlError | ||
175 | } | ||
176 | |||
177 | var fv reflect.Value | ||
178 | ok := true | ||
179 | |||
180 | if !ismap { | ||
181 | fv, ok = fields[string(fieldName)] | ||
182 | } else { | ||
183 | fv = reflect.New(valType.Elem()) | ||
184 | } | ||
185 | |||
186 | if ok { | ||
187 | for { | ||
188 | if tok, err = dec.Token(); err != nil { | ||
189 | return err | ||
190 | } | ||
191 | if t, ok := tok.(xml.StartElement); ok && t.Name.Local == "value" { | ||
192 | if err = dec.decodeValue(fv); err != nil { | ||
193 | return err | ||
194 | } | ||
195 | |||
196 | // </value> | ||
197 | if err = dec.Skip(); err != nil { | ||
198 | return err | ||
199 | } | ||
200 | |||
201 | break | ||
202 | } | ||
203 | } | ||
204 | } | ||
205 | |||
206 | // </member> | ||
207 | if err = dec.Skip(); err != nil { | ||
208 | return err | ||
209 | } | ||
210 | |||
211 | if ismap { | ||
212 | pmap.SetMapIndex(reflect.ValueOf(string(fieldName)), reflect.Indirect(fv)) | ||
213 | val.Set(pmap) | ||
214 | } | ||
215 | case xml.EndElement: | ||
216 | break StructLoop | ||
217 | } | ||
218 | } | ||
219 | case "array": | ||
220 | pslice := val | ||
221 | if checkType(val, reflect.Interface) == nil && val.IsNil() { | ||
222 | var dummy []interface{} | ||
223 | pslice = reflect.New(reflect.TypeOf(dummy)).Elem() | ||
224 | } else if err = checkType(val, reflect.Slice); err != nil { | ||
225 | return err | ||
226 | } | ||
227 | |||
228 | ArrayLoop: | ||
229 | for { | ||
230 | if tok, err = dec.Token(); err != nil { | ||
231 | return err | ||
232 | } | ||
233 | |||
234 | switch t := tok.(type) { | ||
235 | case xml.StartElement: | ||
236 | if t.Name.Local != "data" { | ||
237 | return invalidXmlError | ||
238 | } | ||
239 | |||
240 | slice := reflect.MakeSlice(pslice.Type(), 0, 0) | ||
241 | |||
242 | DataLoop: | ||
243 | for { | ||
244 | if tok, err = dec.Token(); err != nil { | ||
245 | return err | ||
246 | } | ||
247 | |||
248 | switch tt := tok.(type) { | ||
249 | case xml.StartElement: | ||
250 | if tt.Name.Local != "value" { | ||
251 | return invalidXmlError | ||
252 | } | ||
253 | |||
254 | v := reflect.New(pslice.Type().Elem()) | ||
255 | if err = dec.decodeValue(v); err != nil { | ||
256 | return err | ||
257 | } | ||
258 | |||
259 | slice = reflect.Append(slice, v.Elem()) | ||
260 | |||
261 | // </value> | ||
262 | if err = dec.Skip(); err != nil { | ||
263 | return err | ||
264 | } | ||
265 | case xml.EndElement: | ||
266 | pslice.Set(slice) | ||
267 | val.Set(pslice) | ||
268 | break DataLoop | ||
269 | } | ||
270 | } | ||
271 | case xml.EndElement: | ||
272 | break ArrayLoop | ||
273 | } | ||
274 | } | ||
275 | default: | ||
276 | if tok, err = dec.Token(); err != nil { | ||
277 | return err | ||
278 | } | ||
279 | |||
280 | var data []byte | ||
281 | |||
282 | switch t := tok.(type) { | ||
283 | case xml.EndElement: | ||
284 | return nil | ||
285 | case xml.CharData: | ||
286 | data = []byte(t.Copy()) | ||
287 | default: | ||
288 | return invalidXmlError | ||
289 | } | ||
290 | |||
291 | switch typeName { | ||
292 | case "int", "i4", "i8": | ||
293 | if checkType(val, reflect.Interface) == nil && val.IsNil() { | ||
294 | i, err := strconv.ParseInt(string(data), 10, 64) | ||
295 | if err != nil { | ||
296 | return err | ||
297 | } | ||
298 | |||
299 | pi := reflect.New(reflect.TypeOf(i)).Elem() | ||
300 | pi.SetInt(i) | ||
301 | val.Set(pi) | ||
302 | } else if err = checkType(val, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64); err != nil { | ||
303 | return err | ||
304 | } else { | ||
305 | i, err := strconv.ParseInt(string(data), 10, val.Type().Bits()) | ||
306 | if err != nil { | ||
307 | return err | ||
308 | } | ||
309 | |||
310 | val.SetInt(i) | ||
311 | } | ||
312 | case "string", "base64": | ||
313 | str := string(data) | ||
314 | if checkType(val, reflect.Interface) == nil && val.IsNil() { | ||
315 | pstr := reflect.New(reflect.TypeOf(str)).Elem() | ||
316 | pstr.SetString(str) | ||
317 | val.Set(pstr) | ||
318 | } else if err = checkType(val, reflect.String); err != nil { | ||
319 | return err | ||
320 | } else { | ||
321 | val.SetString(str) | ||
322 | } | ||
323 | case "dateTime.iso8601": | ||
324 | t, err := time.Parse(iso8601, string(data)) | ||
325 | if err != nil { | ||
326 | return err | ||
327 | } | ||
328 | |||
329 | if checkType(val, reflect.Interface) == nil && val.IsNil() { | ||
330 | ptime := reflect.New(reflect.TypeOf(t)).Elem() | ||
331 | ptime.Set(reflect.ValueOf(t)) | ||
332 | val.Set(ptime) | ||
333 | } else if _, ok := val.Interface().(time.Time); !ok { | ||
334 | return TypeMismatchError(fmt.Sprintf("error: type mismatch error - can't decode %v to time", val.Kind())) | ||
335 | } else { | ||
336 | val.Set(reflect.ValueOf(t)) | ||
337 | } | ||
338 | case "boolean": | ||
339 | v, err := strconv.ParseBool(string(data)) | ||
340 | if err != nil { | ||
341 | return err | ||
342 | } | ||
343 | |||
344 | if checkType(val, reflect.Interface) == nil && val.IsNil() { | ||
345 | pv := reflect.New(reflect.TypeOf(v)).Elem() | ||
346 | pv.SetBool(v) | ||
347 | val.Set(pv) | ||
348 | } else if err = checkType(val, reflect.Bool); err != nil { | ||
349 | return err | ||
350 | } else { | ||
351 | val.SetBool(v) | ||
352 | } | ||
353 | case "double": | ||
354 | if checkType(val, reflect.Interface) == nil && val.IsNil() { | ||
355 | i, err := strconv.ParseFloat(string(data), 64) | ||
356 | if err != nil { | ||
357 | return err | ||
358 | } | ||
359 | |||
360 | pdouble := reflect.New(reflect.TypeOf(i)).Elem() | ||
361 | pdouble.SetFloat(i) | ||
362 | val.Set(pdouble) | ||
363 | } else if err = checkType(val, reflect.Float32, reflect.Float64); err != nil { | ||
364 | return err | ||
365 | } else { | ||
366 | i, err := strconv.ParseFloat(string(data), val.Type().Bits()) | ||
367 | if err != nil { | ||
368 | return err | ||
369 | } | ||
370 | |||
371 | val.SetFloat(i) | ||
372 | } | ||
373 | default: | ||
374 | return errors.New("unsupported type") | ||
375 | } | ||
376 | |||
377 | // </type> | ||
378 | if err = dec.Skip(); err != nil { | ||
379 | return err | ||
380 | } | ||
381 | } | ||
382 | |||
383 | return nil | ||
384 | } | ||
385 | |||
386 | func (dec *decoder) readTag() (string, []byte, error) { | ||
387 | var tok xml.Token | ||
388 | var err error | ||
389 | |||
390 | var name string | ||
391 | for { | ||
392 | if tok, err = dec.Token(); err != nil { | ||
393 | return "", nil, err | ||
394 | } | ||
395 | |||
396 | if t, ok := tok.(xml.StartElement); ok { | ||
397 | name = t.Name.Local | ||
398 | break | ||
399 | } | ||
400 | } | ||
401 | |||
402 | value, err := dec.readCharData() | ||
403 | if err != nil { | ||
404 | return "", nil, err | ||
405 | } | ||
406 | |||
407 | return name, value, dec.Skip() | ||
408 | } | ||
409 | |||
410 | func (dec *decoder) readCharData() ([]byte, error) { | ||
411 | var tok xml.Token | ||
412 | var err error | ||
413 | |||
414 | if tok, err = dec.Token(); err != nil { | ||
415 | return nil, err | ||
416 | } | ||
417 | |||
418 | if t, ok := tok.(xml.CharData); ok { | ||
419 | return []byte(t.Copy()), nil | ||
420 | } else { | ||
421 | return nil, invalidXmlError | ||
422 | } | ||
423 | } | ||
424 | |||
425 | func checkType(val reflect.Value, kinds ...reflect.Kind) error { | ||
426 | if len(kinds) == 0 { | ||
427 | return nil | ||
428 | } | ||
429 | |||
430 | if val.Kind() == reflect.Ptr { | ||
431 | val = val.Elem() | ||
432 | } | ||
433 | |||
434 | match := false | ||
435 | |||
436 | for _, kind := range kinds { | ||
437 | if val.Kind() == kind { | ||
438 | match = true | ||
439 | break | ||
440 | } | ||
441 | } | ||
442 | |||
443 | if !match { | ||
444 | return TypeMismatchError(fmt.Sprintf("error: type mismatch - can't unmarshal %v to %v", | ||
445 | val.Kind(), kinds[0])) | ||
446 | } | ||
447 | |||
448 | return nil | ||
449 | } | ||
diff --git a/vendor/github.com/kolo/xmlrpc/encoder.go b/vendor/github.com/kolo/xmlrpc/encoder.go deleted file mode 100644 index bb1285f..0000000 --- a/vendor/github.com/kolo/xmlrpc/encoder.go +++ /dev/null | |||
@@ -1,164 +0,0 @@ | |||
1 | package xmlrpc | ||
2 | |||
3 | import ( | ||
4 | "bytes" | ||
5 | "encoding/xml" | ||
6 | "fmt" | ||
7 | "reflect" | ||
8 | "strconv" | ||
9 | "time" | ||
10 | ) | ||
11 | |||
12 | type encodeFunc func(reflect.Value) ([]byte, error) | ||
13 | |||
14 | func marshal(v interface{}) ([]byte, error) { | ||
15 | if v == nil { | ||
16 | return []byte{}, nil | ||
17 | } | ||
18 | |||
19 | val := reflect.ValueOf(v) | ||
20 | return encodeValue(val) | ||
21 | } | ||
22 | |||
23 | func encodeValue(val reflect.Value) ([]byte, error) { | ||
24 | var b []byte | ||
25 | var err error | ||
26 | |||
27 | if val.Kind() == reflect.Ptr || val.Kind() == reflect.Interface { | ||
28 | if val.IsNil() { | ||
29 | return []byte("<value/>"), nil | ||
30 | } | ||
31 | |||
32 | val = val.Elem() | ||
33 | } | ||
34 | |||
35 | switch val.Kind() { | ||
36 | case reflect.Struct: | ||
37 | switch val.Interface().(type) { | ||
38 | case time.Time: | ||
39 | t := val.Interface().(time.Time) | ||
40 | b = []byte(fmt.Sprintf("<dateTime.iso8601>%s</dateTime.iso8601>", t.Format(iso8601))) | ||
41 | default: | ||
42 | b, err = encodeStruct(val) | ||
43 | } | ||
44 | case reflect.Map: | ||
45 | b, err = encodeMap(val) | ||
46 | case reflect.Slice: | ||
47 | b, err = encodeSlice(val) | ||
48 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: | ||
49 | b = []byte(fmt.Sprintf("<int>%s</int>", strconv.FormatInt(val.Int(), 10))) | ||
50 | case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: | ||
51 | b = []byte(fmt.Sprintf("<i4>%s</i4>", strconv.FormatUint(val.Uint(), 10))) | ||
52 | case reflect.Float32, reflect.Float64: | ||
53 | b = []byte(fmt.Sprintf("<double>%s</double>", | ||
54 | strconv.FormatFloat(val.Float(), 'g', -1, val.Type().Bits()))) | ||
55 | case reflect.Bool: | ||
56 | if val.Bool() { | ||
57 | b = []byte("<boolean>1</boolean>") | ||
58 | } else { | ||
59 | b = []byte("<boolean>0</boolean>") | ||
60 | } | ||
61 | case reflect.String: | ||
62 | var buf bytes.Buffer | ||
63 | |||
64 | xml.Escape(&buf, []byte(val.String())) | ||
65 | |||
66 | if _, ok := val.Interface().(Base64); ok { | ||
67 | b = []byte(fmt.Sprintf("<base64>%s</base64>", buf.String())) | ||
68 | } else { | ||
69 | b = []byte(fmt.Sprintf("<string>%s</string>", buf.String())) | ||
70 | } | ||
71 | default: | ||
72 | return nil, fmt.Errorf("xmlrpc encode error: unsupported type") | ||
73 | } | ||
74 | |||
75 | if err != nil { | ||
76 | return nil, err | ||
77 | } | ||
78 | |||
79 | return []byte(fmt.Sprintf("<value>%s</value>", string(b))), nil | ||
80 | } | ||
81 | |||
82 | func encodeStruct(val reflect.Value) ([]byte, error) { | ||
83 | var b bytes.Buffer | ||
84 | |||
85 | b.WriteString("<struct>") | ||
86 | |||
87 | t := val.Type() | ||
88 | for i := 0; i < t.NumField(); i++ { | ||
89 | b.WriteString("<member>") | ||
90 | f := t.Field(i) | ||
91 | |||
92 | name := f.Tag.Get("xmlrpc") | ||
93 | if name == "" { | ||
94 | name = f.Name | ||
95 | } | ||
96 | b.WriteString(fmt.Sprintf("<name>%s</name>", name)) | ||
97 | |||
98 | p, err := encodeValue(val.FieldByName(f.Name)) | ||
99 | if err != nil { | ||
100 | return nil, err | ||
101 | } | ||
102 | b.Write(p) | ||
103 | |||
104 | b.WriteString("</member>") | ||
105 | } | ||
106 | |||
107 | b.WriteString("</struct>") | ||
108 | |||
109 | return b.Bytes(), nil | ||
110 | } | ||
111 | |||
112 | func encodeMap(val reflect.Value) ([]byte, error) { | ||
113 | var t = val.Type() | ||
114 | |||
115 | if t.Key().Kind() != reflect.String { | ||
116 | return nil, fmt.Errorf("xmlrpc encode error: only maps with string keys are supported") | ||
117 | } | ||
118 | |||
119 | var b bytes.Buffer | ||
120 | |||
121 | b.WriteString("<struct>") | ||
122 | |||
123 | keys := val.MapKeys() | ||
124 | |||
125 | for i := 0; i < val.Len(); i++ { | ||
126 | key := keys[i] | ||
127 | kval := val.MapIndex(key) | ||
128 | |||
129 | b.WriteString("<member>") | ||
130 | b.WriteString(fmt.Sprintf("<name>%s</name>", key.String())) | ||
131 | |||
132 | p, err := encodeValue(kval) | ||
133 | |||
134 | if err != nil { | ||
135 | return nil, err | ||
136 | } | ||
137 | |||
138 | b.Write(p) | ||
139 | b.WriteString("</member>") | ||
140 | } | ||
141 | |||
142 | b.WriteString("</struct>") | ||
143 | |||
144 | return b.Bytes(), nil | ||
145 | } | ||
146 | |||
147 | func encodeSlice(val reflect.Value) ([]byte, error) { | ||
148 | var b bytes.Buffer | ||
149 | |||
150 | b.WriteString("<array><data>") | ||
151 | |||
152 | for i := 0; i < val.Len(); i++ { | ||
153 | p, err := encodeValue(val.Index(i)) | ||
154 | if err != nil { | ||
155 | return nil, err | ||
156 | } | ||
157 | |||
158 | b.Write(p) | ||
159 | } | ||
160 | |||
161 | b.WriteString("</data></array>") | ||
162 | |||
163 | return b.Bytes(), nil | ||
164 | } | ||
diff --git a/vendor/github.com/kolo/xmlrpc/request.go b/vendor/github.com/kolo/xmlrpc/request.go deleted file mode 100644 index acb8251..0000000 --- a/vendor/github.com/kolo/xmlrpc/request.go +++ /dev/null | |||
@@ -1,57 +0,0 @@ | |||
1 | package xmlrpc | ||
2 | |||
3 | import ( | ||
4 | "bytes" | ||
5 | "fmt" | ||
6 | "net/http" | ||
7 | ) | ||
8 | |||
9 | func NewRequest(url string, method string, args interface{}) (*http.Request, error) { | ||
10 | var t []interface{} | ||
11 | var ok bool | ||
12 | if t, ok = args.([]interface{}); !ok { | ||
13 | if args != nil { | ||
14 | t = []interface{}{args} | ||
15 | } | ||
16 | } | ||
17 | |||
18 | body, err := EncodeMethodCall(method, t...) | ||
19 | if err != nil { | ||
20 | return nil, err | ||
21 | } | ||
22 | |||
23 | request, err := http.NewRequest("POST", url, bytes.NewReader(body)) | ||
24 | if err != nil { | ||
25 | return nil, err | ||
26 | } | ||
27 | |||
28 | request.Header.Set("Content-Type", "text/xml") | ||
29 | request.Header.Set("Content-Length", fmt.Sprintf("%d", len(body))) | ||
30 | |||
31 | return request, nil | ||
32 | } | ||
33 | |||
34 | func EncodeMethodCall(method string, args ...interface{}) ([]byte, error) { | ||
35 | var b bytes.Buffer | ||
36 | b.WriteString(`<?xml version="1.0" encoding="UTF-8"?>`) | ||
37 | b.WriteString(fmt.Sprintf("<methodCall><methodName>%s</methodName>", method)) | ||
38 | |||
39 | if args != nil { | ||
40 | b.WriteString("<params>") | ||
41 | |||
42 | for _, arg := range args { | ||
43 | p, err := marshal(arg) | ||
44 | if err != nil { | ||
45 | return nil, err | ||
46 | } | ||
47 | |||
48 | b.WriteString(fmt.Sprintf("<param>%s</param>", string(p))) | ||
49 | } | ||
50 | |||
51 | b.WriteString("</params>") | ||
52 | } | ||
53 | |||
54 | b.WriteString("</methodCall>") | ||
55 | |||
56 | return b.Bytes(), nil | ||
57 | } | ||
diff --git a/vendor/github.com/kolo/xmlrpc/response.go b/vendor/github.com/kolo/xmlrpc/response.go deleted file mode 100644 index 6742a1c..0000000 --- a/vendor/github.com/kolo/xmlrpc/response.go +++ /dev/null | |||
@@ -1,52 +0,0 @@ | |||
1 | package xmlrpc | ||
2 | |||
3 | import ( | ||
4 | "regexp" | ||
5 | ) | ||
6 | |||
7 | var ( | ||
8 | faultRx = regexp.MustCompile(`<fault>(\s|\S)+</fault>`) | ||
9 | ) | ||
10 | |||
11 | type failedResponse struct { | ||
12 | Code int `xmlrpc:"faultCode"` | ||
13 | Error string `xmlrpc:"faultString"` | ||
14 | } | ||
15 | |||
16 | func (r *failedResponse) err() error { | ||
17 | return &xmlrpcError{ | ||
18 | code: r.Code, | ||
19 | err: r.Error, | ||
20 | } | ||
21 | } | ||
22 | |||
23 | type Response struct { | ||
24 | data []byte | ||
25 | } | ||
26 | |||
27 | func NewResponse(data []byte) *Response { | ||
28 | return &Response{ | ||
29 | data: data, | ||
30 | } | ||
31 | } | ||
32 | |||
33 | func (r *Response) Failed() bool { | ||
34 | return faultRx.Match(r.data) | ||
35 | } | ||
36 | |||
37 | func (r *Response) Err() error { | ||
38 | failedResp := new(failedResponse) | ||
39 | if err := unmarshal(r.data, failedResp); err != nil { | ||
40 | return err | ||
41 | } | ||
42 | |||
43 | return failedResp.err() | ||
44 | } | ||
45 | |||
46 | func (r *Response) Unmarshal(v interface{}) error { | ||
47 | if err := unmarshal(r.data, v); err != nil { | ||
48 | return err | ||
49 | } | ||
50 | |||
51 | return nil | ||
52 | } | ||
diff --git a/vendor/github.com/kolo/xmlrpc/test_server.rb b/vendor/github.com/kolo/xmlrpc/test_server.rb deleted file mode 100644 index 1b1ff87..0000000 --- a/vendor/github.com/kolo/xmlrpc/test_server.rb +++ /dev/null | |||
@@ -1,25 +0,0 @@ | |||
1 | # encoding: utf-8 | ||
2 | |||
3 | require "xmlrpc/server" | ||
4 | |||
5 | class Service | ||
6 | def time | ||
7 | Time.now | ||
8 | end | ||
9 | |||
10 | def upcase(s) | ||
11 | s.upcase | ||
12 | end | ||
13 | |||
14 | def sum(x, y) | ||
15 | x + y | ||
16 | end | ||
17 | |||
18 | def error | ||
19 | raise XMLRPC::FaultException.new(500, "Server error") | ||
20 | end | ||
21 | end | ||
22 | |||
23 | server = XMLRPC::Server.new 5001, 'localhost' | ||
24 | server.add_handler "service", Service.new | ||
25 | server.serve | ||
diff --git a/vendor/github.com/kolo/xmlrpc/xmlrpc.go b/vendor/github.com/kolo/xmlrpc/xmlrpc.go deleted file mode 100644 index 8766403..0000000 --- a/vendor/github.com/kolo/xmlrpc/xmlrpc.go +++ /dev/null | |||
@@ -1,19 +0,0 @@ | |||
1 | package xmlrpc | ||
2 | |||
3 | import ( | ||
4 | "fmt" | ||
5 | ) | ||
6 | |||
7 | // xmlrpcError represents errors returned on xmlrpc request. | ||
8 | type xmlrpcError struct { | ||
9 | code int | ||
10 | err string | ||
11 | } | ||
12 | |||
13 | // Error() method implements Error interface | ||
14 | func (e *xmlrpcError) Error() string { | ||
15 | return fmt.Sprintf("error: \"%s\" code: %d", e.err, e.code) | ||
16 | } | ||
17 | |||
18 | // Base64 represents value in base64 encoding | ||
19 | type Base64 string | ||
diff --git a/vendor/github.com/kolo/xmlrpc/LICENSE b/vendor/github.com/mattn/go-xmlrpc/LICENSE index 8103dd1..740fa93 100644 --- a/vendor/github.com/kolo/xmlrpc/LICENSE +++ b/vendor/github.com/mattn/go-xmlrpc/LICENSE | |||
@@ -1,4 +1,6 @@ | |||
1 | Copyright (C) 2012 Dmitry Maksimov | 1 | The MIT License (MIT) |
2 | |||
3 | Copyright (c) 2017 Yasuhiro Matsumoto | ||
2 | 4 | ||
3 | Permission is hereby granted, free of charge, to any person obtaining a copy | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy |
4 | of this software and associated documentation files (the "Software"), to deal | 6 | of this software and associated documentation files (the "Software"), to deal |
@@ -7,13 +9,13 @@ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
7 | copies of the Software, and to permit persons to whom the Software is | 9 | copies of the Software, and to permit persons to whom the Software is |
8 | furnished to do so, subject to the following conditions: | 10 | furnished to do so, subject to the following conditions: |
9 | 11 | ||
10 | The above copyright notice and this permission notice shall be included in | 12 | The above copyright notice and this permission notice shall be included in all |
11 | all copies or substantial portions of the Software. | 13 | copies or substantial portions of the Software. |
12 | 14 | ||
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
19 | THE SOFTWARE. | 21 | SOFTWARE. |
diff --git a/vendor/github.com/mattn/go-xmlrpc/README.md b/vendor/github.com/mattn/go-xmlrpc/README.md new file mode 100644 index 0000000..de6cb1d --- /dev/null +++ b/vendor/github.com/mattn/go-xmlrpc/README.md | |||
@@ -0,0 +1,48 @@ | |||
1 | # go-xmlrpc | ||
2 | |||
3 | xmlrpc interface for go | ||
4 | |||
5 | ## Usage | ||
6 | |||
7 | ```go | ||
8 | package main | ||
9 | |||
10 | import ( | ||
11 | "github.com/mattn/go-xmlrpc" | ||
12 | "fmt" | ||
13 | "log" | ||
14 | ) | ||
15 | |||
16 | func main() { | ||
17 | res, e := xmlrpc.Call( | ||
18 | "http://your-blog.example.com/xmlrpc.php", | ||
19 | "metaWeblog.getRecentPosts", | ||
20 | "blog-id", | ||
21 | "user-id", | ||
22 | "password", | ||
23 | 10) | ||
24 | if e != nil { | ||
25 | log.Fatal(e) | ||
26 | } | ||
27 | for _, p := range res.(xmlrpc.Array) { | ||
28 | for k, v := range p.(xmlrpc.Struct) { | ||
29 | fmt.Printf("%s=%v\n", k, v) | ||
30 | } | ||
31 | fmt.Println() | ||
32 | } | ||
33 | } | ||
34 | ``` | ||
35 | |||
36 | ## Installation | ||
37 | |||
38 | ``` | ||
39 | $ go get github.com/mattn/go-xmlrpc | ||
40 | ``` | ||
41 | |||
42 | ## License | ||
43 | |||
44 | MIT | ||
45 | |||
46 | ## Author | ||
47 | |||
48 | Yasuhiro Matsumoto (a.k.a. mattn) | ||
diff --git a/vendor/github.com/mattn/go-xmlrpc/xmlrpc.go b/vendor/github.com/mattn/go-xmlrpc/xmlrpc.go new file mode 100644 index 0000000..cfbe4d8 --- /dev/null +++ b/vendor/github.com/mattn/go-xmlrpc/xmlrpc.go | |||
@@ -0,0 +1,365 @@ | |||
1 | package xmlrpc | ||
2 | |||
3 | import ( | ||
4 | "bytes" | ||
5 | "encoding/base64" | ||
6 | "encoding/xml" | ||
7 | "errors" | ||
8 | "fmt" | ||
9 | "io" | ||
10 | "io/ioutil" | ||
11 | "net/http" | ||
12 | "reflect" | ||
13 | "strconv" | ||
14 | "strings" | ||
15 | "time" | ||
16 | ) | ||
17 | |||
18 | type Array []interface{} | ||
19 | type Struct map[string]interface{} | ||
20 | |||
21 | var xmlSpecial = map[byte]string{ | ||
22 | '<': "<", | ||
23 | '>': ">", | ||
24 | '"': """, | ||
25 | '\'': "'", | ||
26 | '&': "&", | ||
27 | } | ||
28 | |||
29 | func xmlEscape(s string) string { | ||
30 | var b bytes.Buffer | ||
31 | for i := 0; i < len(s); i++ { | ||
32 | c := s[i] | ||
33 | if s, ok := xmlSpecial[c]; ok { | ||
34 | b.WriteString(s) | ||
35 | } else { | ||
36 | b.WriteByte(c) | ||
37 | } | ||
38 | } | ||
39 | return b.String() | ||
40 | } | ||
41 | |||
42 | type valueNode struct { | ||
43 | Type string `xml:"attr"` | ||
44 | Body string `xml:"chardata"` | ||
45 | } | ||
46 | |||
47 | func next(p *xml.Decoder) (xml.Name, interface{}, error) { | ||
48 | se, e := nextStart(p) | ||
49 | if e != nil { | ||
50 | return xml.Name{}, nil, e | ||
51 | } | ||
52 | |||
53 | var nv interface{} | ||
54 | switch se.Name.Local { | ||
55 | case "string": | ||
56 | var s string | ||
57 | if e = p.DecodeElement(&s, &se); e != nil { | ||
58 | return xml.Name{}, nil, e | ||
59 | } | ||
60 | return xml.Name{}, s, nil | ||
61 | case "boolean": | ||
62 | var s string | ||
63 | if e = p.DecodeElement(&s, &se); e != nil { | ||
64 | return xml.Name{}, nil, e | ||
65 | } | ||
66 | s = strings.TrimSpace(s) | ||
67 | var b bool | ||
68 | switch s { | ||
69 | case "true", "1": | ||
70 | b = true | ||
71 | case "false", "0": | ||
72 | b = false | ||
73 | default: | ||
74 | e = errors.New("invalid boolean value") | ||
75 | } | ||
76 | return xml.Name{}, b, e | ||
77 | case "int", "i1", "i2", "i4", "i8": | ||
78 | var s string | ||
79 | var i int | ||
80 | if e = p.DecodeElement(&s, &se); e != nil { | ||
81 | return xml.Name{}, nil, e | ||
82 | } | ||
83 | i, e = strconv.Atoi(strings.TrimSpace(s)) | ||
84 | return xml.Name{}, i, e | ||
85 | case "double": | ||
86 | var s string | ||
87 | var f float64 | ||
88 | if e = p.DecodeElement(&s, &se); e != nil { | ||
89 | return xml.Name{}, nil, e | ||
90 | } | ||
91 | f, e = strconv.ParseFloat(strings.TrimSpace(s), 64) | ||
92 | return xml.Name{}, f, e | ||
93 | case "dateTime.iso8601": | ||
94 | var s string | ||
95 | if e = p.DecodeElement(&s, &se); e != nil { | ||
96 | return xml.Name{}, nil, e | ||
97 | } | ||
98 | t, e := time.Parse("20060102T15:04:05", s) | ||
99 | if e != nil { | ||
100 | t, e = time.Parse("2006-01-02T15:04:05-07:00", s) | ||
101 | if e != nil { | ||
102 | t, e = time.Parse("2006-01-02T15:04:05", s) | ||
103 | } | ||
104 | } | ||
105 | return xml.Name{}, t, e | ||
106 | case "base64": | ||
107 | var s string | ||
108 | if e = p.DecodeElement(&s, &se); e != nil { | ||
109 | return xml.Name{}, nil, e | ||
110 | } | ||
111 | if b, e := base64.StdEncoding.DecodeString(s); e != nil { | ||
112 | return xml.Name{}, nil, e | ||
113 | } else { | ||
114 | return xml.Name{}, b, nil | ||
115 | } | ||
116 | case "member": | ||
117 | nextStart(p) | ||
118 | return next(p) | ||
119 | case "value": | ||
120 | nextStart(p) | ||
121 | return next(p) | ||
122 | case "name": | ||
123 | nextStart(p) | ||
124 | return next(p) | ||
125 | case "struct": | ||
126 | st := Struct{} | ||
127 | |||
128 | se, e = nextStart(p) | ||
129 | for e == nil && se.Name.Local == "member" { | ||
130 | // name | ||
131 | se, e = nextStart(p) | ||
132 | if se.Name.Local != "name" { | ||
133 | return xml.Name{}, nil, errors.New("invalid response") | ||
134 | } | ||
135 | if e != nil { | ||
136 | break | ||
137 | } | ||
138 | var name string | ||
139 | if e = p.DecodeElement(&name, &se); e != nil { | ||
140 | return xml.Name{}, nil, e | ||
141 | } | ||
142 | se, e = nextStart(p) | ||
143 | if e != nil { | ||
144 | break | ||
145 | } | ||
146 | |||
147 | // value | ||
148 | _, value, e := next(p) | ||
149 | if se.Name.Local != "value" { | ||
150 | return xml.Name{}, nil, errors.New("invalid response") | ||
151 | } | ||
152 | if e != nil { | ||
153 | break | ||
154 | } | ||
155 | st[name] = value | ||
156 | |||
157 | se, e = nextStart(p) | ||
158 | if e != nil { | ||
159 | break | ||
160 | } | ||
161 | } | ||
162 | return xml.Name{}, st, nil | ||
163 | case "array": | ||
164 | var ar Array | ||
165 | nextStart(p) // data | ||
166 | for { | ||
167 | nextStart(p) // top of value | ||
168 | _, value, e := next(p) | ||
169 | if e != nil { | ||
170 | break | ||
171 | } | ||
172 | ar = append(ar, value) | ||
173 | } | ||
174 | return xml.Name{}, ar, nil | ||
175 | case "nil": | ||
176 | return xml.Name{}, nil, nil | ||
177 | } | ||
178 | |||
179 | if e = p.DecodeElement(nv, &se); e != nil { | ||
180 | return xml.Name{}, nil, e | ||
181 | } | ||
182 | return se.Name, nv, e | ||
183 | } | ||
184 | func nextStart(p *xml.Decoder) (xml.StartElement, error) { | ||
185 | for { | ||
186 | t, e := p.Token() | ||
187 | if e != nil { | ||
188 | return xml.StartElement{}, e | ||
189 | } | ||
190 | switch t := t.(type) { | ||
191 | case xml.StartElement: | ||
192 | return t, nil | ||
193 | } | ||
194 | } | ||
195 | panic("unreachable") | ||
196 | } | ||
197 | |||
198 | func toXml(v interface{}, typ bool) (s string) { | ||
199 | if v == nil { | ||
200 | return "<nil/>" | ||
201 | } | ||
202 | r := reflect.ValueOf(v) | ||
203 | t := r.Type() | ||
204 | k := t.Kind() | ||
205 | |||
206 | if b, ok := v.([]byte); ok { | ||
207 | return "<base64>" + base64.StdEncoding.EncodeToString(b) + "</base64>" | ||
208 | } | ||
209 | |||
210 | switch k { | ||
211 | case reflect.Invalid: | ||
212 | panic("unsupported type") | ||
213 | case reflect.Bool: | ||
214 | return fmt.Sprintf("<boolean>%v</boolean>", v) | ||
215 | case reflect.Int, | ||
216 | reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, | ||
217 | reflect.Uint, | ||
218 | reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: | ||
219 | if typ { | ||
220 | return fmt.Sprintf("<int>%v</int>", v) | ||
221 | } | ||
222 | return fmt.Sprintf("%v", v) | ||
223 | case reflect.Uintptr: | ||
224 | panic("unsupported type") | ||
225 | case reflect.Float32, reflect.Float64: | ||
226 | if typ { | ||
227 | return fmt.Sprintf("<double>%v</double>", v) | ||
228 | } | ||
229 | return fmt.Sprintf("%v", v) | ||
230 | case reflect.Complex64, reflect.Complex128: | ||
231 | panic("unsupported type") | ||
232 | case reflect.Array: | ||
233 | s = "<array><data>" | ||
234 | for n := 0; n < r.Len(); n++ { | ||
235 | s += "<value>" | ||
236 | s += toXml(r.Index(n).Interface(), typ) | ||
237 | s += "</value>" | ||
238 | } | ||
239 | s += "</data></array>" | ||
240 | return s | ||
241 | case reflect.Chan: | ||
242 | panic("unsupported type") | ||
243 | case reflect.Func: | ||
244 | panic("unsupported type") | ||
245 | case reflect.Interface: | ||
246 | return toXml(r.Elem(), typ) | ||
247 | case reflect.Map: | ||
248 | s = "<struct>" | ||
249 | for _, key := range r.MapKeys() { | ||
250 | s += "<member>" | ||
251 | s += "<name>" + xmlEscape(key.Interface().(string)) + "</name>" | ||
252 | s += "<value>" + toXml(r.MapIndex(key).Interface(), typ) + "</value>" | ||
253 | s += "</member>" | ||
254 | } | ||
255 | s += "</struct>" | ||
256 | return s | ||
257 | case reflect.Ptr: | ||
258 | panic("unsupported type") | ||
259 | case reflect.Slice: | ||
260 | s = "<array><data>" | ||
261 | for n := 0; n < r.Len(); n++ { | ||
262 | s += "<value>" | ||
263 | s += toXml(r.Index(n).Interface(), typ) | ||
264 | s += "</value>" | ||
265 | } | ||
266 | s += "</data></array>" | ||
267 | return s | ||
268 | case reflect.String: | ||
269 | if typ { | ||
270 | return fmt.Sprintf("<string>%v</string>", xmlEscape(v.(string))) | ||
271 | } | ||
272 | return xmlEscape(v.(string)) | ||
273 | case reflect.Struct: | ||
274 | s = "<struct>" | ||
275 | for n := 0; n < r.NumField(); n++ { | ||
276 | s += "<member>" | ||
277 | s += "<name>" + t.Field(n).Name + "</name>" | ||
278 | s += "<value>" + toXml(r.FieldByIndex([]int{n}).Interface(), true) + "</value>" | ||
279 | s += "</member>" | ||
280 | } | ||
281 | s += "</struct>" | ||
282 | return s | ||
283 | case reflect.UnsafePointer: | ||
284 | return toXml(r.Elem(), typ) | ||
285 | } | ||
286 | return | ||
287 | } | ||
288 | |||
289 | // Client is client of XMLRPC | ||
290 | type Client struct { | ||
291 | HttpClient *http.Client | ||
292 | url string | ||
293 | } | ||
294 | |||
295 | // NewClient create new Client | ||
296 | func NewClient(url string) *Client { | ||
297 | return &Client{ | ||
298 | HttpClient: &http.Client{Transport: http.DefaultTransport, Timeout: 10 * time.Second}, | ||
299 | url: url, | ||
300 | } | ||
301 | } | ||
302 | |||
303 | func makeRequest(name string, args ...interface{}) *bytes.Buffer { | ||
304 | buf := new(bytes.Buffer) | ||
305 | buf.WriteString(`<?xml version="1.0"?><methodCall>`) | ||
306 | buf.WriteString("<methodName>" + xmlEscape(name) + "</methodName>") | ||
307 | buf.WriteString("<params>") | ||
308 | for _, arg := range args { | ||
309 | buf.WriteString("<param><value>") | ||
310 | buf.WriteString(toXml(arg, true)) | ||
311 | buf.WriteString("</value></param>") | ||
312 | } | ||
313 | buf.WriteString("</params></methodCall>") | ||
314 | return buf | ||
315 | } | ||
316 | |||
317 | func call(client *http.Client, url, name string, args ...interface{}) (v interface{}, e error) { | ||
318 | r, e := httpClient.Post(url, "text/xml", makeRequest(name, args...)) | ||
319 | if e != nil { | ||
320 | return nil, e | ||
321 | } | ||
322 | |||
323 | // Since we do not always read the entire body, discard the rest, which | ||
324 | // allows the http transport to reuse the connection. | ||
325 | defer io.Copy(ioutil.Discard, r.Body) | ||
326 | defer r.Body.Close() | ||
327 | |||
328 | if r.StatusCode/100 != 2 { | ||
329 | return nil, errors.New(http.StatusText(http.StatusBadRequest)) | ||
330 | } | ||
331 | |||
332 | p := xml.NewDecoder(r.Body) | ||
333 | se, e := nextStart(p) // methodResponse | ||
334 | if se.Name.Local != "methodResponse" { | ||
335 | return nil, errors.New("invalid response: missing methodResponse") | ||
336 | } | ||
337 | se, e = nextStart(p) // params | ||
338 | if se.Name.Local != "params" { | ||
339 | return nil, errors.New("invalid response: missing params") | ||
340 | } | ||
341 | se, e = nextStart(p) // param | ||
342 | if se.Name.Local != "param" { | ||
343 | return nil, errors.New("invalid response: missing param") | ||
344 | } | ||
345 | se, e = nextStart(p) // value | ||
346 | if se.Name.Local != "value" { | ||
347 | return nil, errors.New("invalid response: missing value") | ||
348 | } | ||
349 | _, v, e = next(p) | ||
350 | return v, e | ||
351 | } | ||
352 | |||
353 | // Call call remote procedures function name with args | ||
354 | func (c *Client) Call(name string, args ...interface{}) (v interface{}, e error) { | ||
355 | return call(c.HttpClient, c.url, name, args...) | ||
356 | } | ||
357 | |||
358 | // Global httpClient allows us to pool/reuse connections and not wastefully | ||
359 | // re-create transports for each request. | ||
360 | var httpClient = &http.Client{Transport: http.DefaultTransport, Timeout: 10 * time.Second} | ||
361 | |||
362 | // Call call remote procedures function name with args | ||
363 | func Call(url, name string, args ...interface{}) (v interface{}, e error) { | ||
364 | return call(httpClient, url, name, args...) | ||
365 | } | ||
diff --git a/vendor/vendor.json b/vendor/vendor.json index 8dbff89..c8cad52 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json | |||
@@ -65,18 +65,18 @@ | |||
65 | "versionExact": "v1.0.0" | 65 | "versionExact": "v1.0.0" |
66 | }, | 66 | }, |
67 | { | 67 | { |
68 | "checksumSHA1": "tw3ocqSpa9ikzUV6qhcKBAAO6WU=", | ||
69 | "path": "github.com/kolo/xmlrpc", | ||
70 | "revision": "0826b98aaa29c0766956cb40d45cf7482a597671", | ||
71 | "revisionTime": "2015-04-13T19:18:30Z" | ||
72 | }, | ||
73 | { | ||
74 | "checksumSHA1": "IdBAvtVSv0sbi8sEsLovnZubims=", | 68 | "checksumSHA1": "IdBAvtVSv0sbi8sEsLovnZubims=", |
75 | "path": "github.com/lufia/iostat", | 69 | "path": "github.com/lufia/iostat", |
76 | "revision": "9f7362b77ad333b26c01c99de52a11bdb650ded2", | 70 | "revision": "9f7362b77ad333b26c01c99de52a11bdb650ded2", |
77 | "revisionTime": "2017-06-05T15:08:45Z" | 71 | "revisionTime": "2017-06-05T15:08:45Z" |
78 | }, | 72 | }, |
79 | { | 73 | { |
74 | "checksumSHA1": "8uAFFK5p8F39X1MOLsHrgTI0hzw=", | ||
75 | "path": "github.com/mattn/go-xmlrpc", | ||
76 | "revision": "b7a1b57d9142f44a3a8f5a80aadf8d2d6ea2ca22", | ||
77 | "revisionTime": "2018-04-20T00:08:13Z" | ||
78 | }, | ||
79 | { | ||
80 | "checksumSHA1": "aodj/cITRyuaZSh84DDhrZjh76U=", | 80 | "checksumSHA1": "aodj/cITRyuaZSh84DDhrZjh76U=", |
81 | "path": "github.com/matttproud/golang_protobuf_extensions/pbutil", | 81 | "path": "github.com/matttproud/golang_protobuf_extensions/pbutil", |
82 | "revision": "3247c84500bff8d9fb6d579d800f20b3e091582c", | 82 | "revision": "3247c84500bff8d9fb6d579d800f20b3e091582c", |