upload/koji: add helpers to upload to koji
This does not yet actually upload the image, and it only supports empty images. You need to place a an empty file named <filename>, with a valid extension (e.g., .qcow2) in /mnt/koji/work/<directory>/. Signed-off-by: Tom Gundersen <teg@jklm.no>
This commit is contained in:
parent
c508582a63
commit
76515066a8
13 changed files with 1443 additions and 0 deletions
19
vendor/github.com/kolo/xmlrpc/LICENSE
generated
vendored
Normal file
19
vendor/github.com/kolo/xmlrpc/LICENSE
generated
vendored
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
Copyright (C) 2012 Dmitry Maksimov
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
89
vendor/github.com/kolo/xmlrpc/README.md
generated
vendored
Normal file
89
vendor/github.com/kolo/xmlrpc/README.md
generated
vendored
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
[](https://godoc.org/github.com/kolo/xmlrpc)
|
||||
|
||||
## Overview
|
||||
|
||||
xmlrpc is an implementation of client side part of XMLRPC protocol in Go language.
|
||||
|
||||
## Status
|
||||
|
||||
This project is in minimal maintenance mode with no further development. Bug fixes
|
||||
are accepted, but it might take some time until they will be merged.
|
||||
|
||||
## Installation
|
||||
|
||||
To install xmlrpc package run `go get github.com/kolo/xmlrpc`. To use
|
||||
it in application add `"github.com/kolo/xmlrpc"` string to `import`
|
||||
statement.
|
||||
|
||||
## Usage
|
||||
|
||||
client, _ := xmlrpc.NewClient("https://bugzilla.mozilla.org/xmlrpc.cgi", nil)
|
||||
result := struct{
|
||||
Version string `xmlrpc:"version"`
|
||||
}{}
|
||||
client.Call("Bugzilla.version", nil, &result)
|
||||
fmt.Printf("Version: %s\n", result.Version) // Version: 4.2.7+
|
||||
|
||||
Second argument of NewClient function is an object that implements
|
||||
[http.RoundTripper](http://golang.org/pkg/net/http/#RoundTripper)
|
||||
interface, it can be used to get more control over connection options.
|
||||
By default it initialized by http.DefaultTransport object.
|
||||
|
||||
### Arguments encoding
|
||||
|
||||
xmlrpc package supports encoding of native Go data types to method
|
||||
arguments.
|
||||
|
||||
Data types encoding rules:
|
||||
|
||||
* int, int8, int16, int32, int64 encoded to int;
|
||||
* float32, float64 encoded to double;
|
||||
* bool encoded to boolean;
|
||||
* string encoded to string;
|
||||
* time.Time encoded to datetime.iso8601;
|
||||
* xmlrpc.Base64 encoded to base64;
|
||||
* slice encoded to array;
|
||||
|
||||
Structs decoded to struct by following rules:
|
||||
|
||||
* all public field become struct members;
|
||||
* field name become member name;
|
||||
* if field has xmlrpc tag, its value become member name.
|
||||
|
||||
Server method can accept few arguments, to handle this case there is
|
||||
special approach to handle slice of empty interfaces (`[]interface{}`).
|
||||
Each value of such slice encoded as separate argument.
|
||||
|
||||
### Result decoding
|
||||
|
||||
Result of remote function is decoded to native Go data type.
|
||||
|
||||
Data types decoding rules:
|
||||
|
||||
* int, i4 decoded to int, int8, int16, int32, int64;
|
||||
* double decoded to float32, float64;
|
||||
* boolean decoded to bool;
|
||||
* string decoded to string;
|
||||
* array decoded to slice;
|
||||
* structs decoded following the rules described in previous section;
|
||||
* datetime.iso8601 decoded as time.Time data type;
|
||||
* base64 decoded to string.
|
||||
|
||||
## Implementation details
|
||||
|
||||
xmlrpc package contains clientCodec type, that implements [rpc.ClientCodec](http://golang.org/pkg/net/rpc/#ClientCodec)
|
||||
interface of [net/rpc](http://golang.org/pkg/net/rpc) package.
|
||||
|
||||
xmlrpc package works over HTTP protocol, but some internal functions
|
||||
and data type were made public to make it easier to create another
|
||||
implementation of xmlrpc that works over another protocol. To encode
|
||||
request body there is EncodeMethodCall function. To decode server
|
||||
response Response data type can be used.
|
||||
|
||||
## Contribution
|
||||
|
||||
See [project status](#status).
|
||||
|
||||
## Authors
|
||||
|
||||
Dmitry Maksimov (dmtmax@gmail.com)
|
||||
161
vendor/github.com/kolo/xmlrpc/client.go
generated
vendored
Normal file
161
vendor/github.com/kolo/xmlrpc/client.go
generated
vendored
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
package xmlrpc
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/cookiejar"
|
||||
"net/rpc"
|
||||
"net/url"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
*rpc.Client
|
||||
}
|
||||
|
||||
// clientCodec is rpc.ClientCodec interface implementation.
|
||||
type clientCodec struct {
|
||||
// url presents url of xmlrpc service
|
||||
url *url.URL
|
||||
|
||||
// httpClient works with HTTP protocol
|
||||
httpClient *http.Client
|
||||
|
||||
// cookies stores cookies received on last request
|
||||
cookies http.CookieJar
|
||||
|
||||
// responses presents map of active requests. It is required to return request id, that
|
||||
// rpc.Client can mark them as done.
|
||||
responses map[uint64]*http.Response
|
||||
mutex sync.Mutex
|
||||
|
||||
response Response
|
||||
|
||||
// ready presents channel, that is used to link request and it`s response.
|
||||
ready chan uint64
|
||||
|
||||
// close notifies codec is closed.
|
||||
close chan uint64
|
||||
}
|
||||
|
||||
func (codec *clientCodec) WriteRequest(request *rpc.Request, args interface{}) (err error) {
|
||||
httpRequest, err := NewRequest(codec.url.String(), request.ServiceMethod, args)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if codec.cookies != nil {
|
||||
for _, cookie := range codec.cookies.Cookies(codec.url) {
|
||||
httpRequest.AddCookie(cookie)
|
||||
}
|
||||
}
|
||||
|
||||
var httpResponse *http.Response
|
||||
httpResponse, err = codec.httpClient.Do(httpRequest)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if codec.cookies != nil {
|
||||
codec.cookies.SetCookies(codec.url, httpResponse.Cookies())
|
||||
}
|
||||
|
||||
codec.mutex.Lock()
|
||||
codec.responses[request.Seq] = httpResponse
|
||||
codec.mutex.Unlock()
|
||||
|
||||
codec.ready <- request.Seq
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (codec *clientCodec) ReadResponseHeader(response *rpc.Response) (err error) {
|
||||
var seq uint64
|
||||
select {
|
||||
case seq = <-codec.ready:
|
||||
case <-codec.close:
|
||||
return errors.New("codec is closed")
|
||||
}
|
||||
response.Seq = seq
|
||||
|
||||
codec.mutex.Lock()
|
||||
httpResponse := codec.responses[seq]
|
||||
delete(codec.responses, seq)
|
||||
codec.mutex.Unlock()
|
||||
|
||||
defer httpResponse.Body.Close()
|
||||
|
||||
if httpResponse.StatusCode < 200 || httpResponse.StatusCode >= 300 {
|
||||
response.Error = fmt.Sprintf("request error: bad status code - %d", httpResponse.StatusCode)
|
||||
return nil
|
||||
}
|
||||
|
||||
body, err := ioutil.ReadAll(httpResponse.Body)
|
||||
if err != nil {
|
||||
response.Error = err.Error()
|
||||
return nil
|
||||
}
|
||||
|
||||
resp := Response(body)
|
||||
if err := resp.Err(); err != nil {
|
||||
response.Error = err.Error()
|
||||
return nil
|
||||
}
|
||||
|
||||
codec.response = resp
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (codec *clientCodec) ReadResponseBody(v interface{}) (err error) {
|
||||
if v == nil {
|
||||
return nil
|
||||
}
|
||||
return codec.response.Unmarshal(v)
|
||||
}
|
||||
|
||||
func (codec *clientCodec) Close() error {
|
||||
if transport, ok := codec.httpClient.Transport.(*http.Transport); ok {
|
||||
transport.CloseIdleConnections()
|
||||
}
|
||||
|
||||
close(codec.close)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewClient returns instance of rpc.Client object, that is used to send request to xmlrpc service.
|
||||
func NewClient(requrl string, transport http.RoundTripper) (*Client, error) {
|
||||
if transport == nil {
|
||||
transport = http.DefaultTransport
|
||||
}
|
||||
|
||||
httpClient := &http.Client{Transport: transport}
|
||||
|
||||
jar, err := cookiejar.New(nil)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
u, err := url.Parse(requrl)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
codec := clientCodec{
|
||||
url: u,
|
||||
httpClient: httpClient,
|
||||
close: make(chan uint64),
|
||||
ready: make(chan uint64),
|
||||
responses: make(map[uint64]*http.Response),
|
||||
cookies: jar,
|
||||
}
|
||||
|
||||
return &Client{rpc.NewClientWithCodec(&codec)}, nil
|
||||
}
|
||||
473
vendor/github.com/kolo/xmlrpc/decoder.go
generated
vendored
Normal file
473
vendor/github.com/kolo/xmlrpc/decoder.go
generated
vendored
Normal file
|
|
@ -0,0 +1,473 @@
|
|||
package xmlrpc
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/xml"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
iso8601 = "20060102T15:04:05"
|
||||
iso8601Z = "20060102T15:04:05Z07:00"
|
||||
iso8601Hyphen = "2006-01-02T15:04:05"
|
||||
iso8601HyphenZ = "2006-01-02T15:04:05Z07:00"
|
||||
)
|
||||
|
||||
var (
|
||||
// CharsetReader is a function to generate reader which converts a non UTF-8
|
||||
// charset into UTF-8.
|
||||
CharsetReader func(string, io.Reader) (io.Reader, error)
|
||||
|
||||
timeLayouts = []string{iso8601, iso8601Z, iso8601Hyphen, iso8601HyphenZ}
|
||||
invalidXmlError = errors.New("invalid xml")
|
||||
)
|
||||
|
||||
type TypeMismatchError string
|
||||
|
||||
func (e TypeMismatchError) Error() string { return string(e) }
|
||||
|
||||
type decoder struct {
|
||||
*xml.Decoder
|
||||
}
|
||||
|
||||
func unmarshal(data []byte, v interface{}) (err error) {
|
||||
dec := &decoder{xml.NewDecoder(bytes.NewBuffer(data))}
|
||||
|
||||
if CharsetReader != nil {
|
||||
dec.CharsetReader = CharsetReader
|
||||
}
|
||||
|
||||
var tok xml.Token
|
||||
for {
|
||||
if tok, err = dec.Token(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if t, ok := tok.(xml.StartElement); ok {
|
||||
if t.Name.Local == "value" {
|
||||
val := reflect.ValueOf(v)
|
||||
if val.Kind() != reflect.Ptr {
|
||||
return errors.New("non-pointer value passed to unmarshal")
|
||||
}
|
||||
if err = dec.decodeValue(val.Elem()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// read until end of document
|
||||
err = dec.Skip()
|
||||
if err != nil && err != io.EOF {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dec *decoder) decodeValue(val reflect.Value) error {
|
||||
var tok xml.Token
|
||||
var err error
|
||||
|
||||
if val.Kind() == reflect.Ptr {
|
||||
if val.IsNil() {
|
||||
val.Set(reflect.New(val.Type().Elem()))
|
||||
}
|
||||
val = val.Elem()
|
||||
}
|
||||
|
||||
var typeName string
|
||||
for {
|
||||
if tok, err = dec.Token(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if t, ok := tok.(xml.EndElement); ok {
|
||||
if t.Name.Local == "value" {
|
||||
return nil
|
||||
} else {
|
||||
return invalidXmlError
|
||||
}
|
||||
}
|
||||
|
||||
if t, ok := tok.(xml.StartElement); ok {
|
||||
typeName = t.Name.Local
|
||||
break
|
||||
}
|
||||
|
||||
// Treat value data without type identifier as string
|
||||
if t, ok := tok.(xml.CharData); ok {
|
||||
if value := strings.TrimSpace(string(t)); value != "" {
|
||||
if err = checkType(val, reflect.String); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
val.SetString(value)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch typeName {
|
||||
case "struct":
|
||||
ismap := false
|
||||
pmap := val
|
||||
valType := val.Type()
|
||||
|
||||
if err = checkType(val, reflect.Struct); err != nil {
|
||||
if checkType(val, reflect.Map) == nil {
|
||||
if valType.Key().Kind() != reflect.String {
|
||||
return fmt.Errorf("only maps with string key type can be unmarshalled")
|
||||
}
|
||||
ismap = true
|
||||
} else if checkType(val, reflect.Interface) == nil && val.IsNil() {
|
||||
var dummy map[string]interface{}
|
||||
valType = reflect.TypeOf(dummy)
|
||||
pmap = reflect.New(valType).Elem()
|
||||
val.Set(pmap)
|
||||
ismap = true
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
var fields map[string]reflect.Value
|
||||
|
||||
if !ismap {
|
||||
fields = make(map[string]reflect.Value)
|
||||
|
||||
for i := 0; i < valType.NumField(); i++ {
|
||||
field := valType.Field(i)
|
||||
fieldVal := val.FieldByName(field.Name)
|
||||
|
||||
if fieldVal.CanSet() {
|
||||
if fn := field.Tag.Get("xmlrpc"); fn != "" {
|
||||
fields[fn] = fieldVal
|
||||
} else {
|
||||
fields[field.Name] = fieldVal
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Create initial empty map
|
||||
pmap.Set(reflect.MakeMap(valType))
|
||||
}
|
||||
|
||||
// Process struct members.
|
||||
StructLoop:
|
||||
for {
|
||||
if tok, err = dec.Token(); err != nil {
|
||||
return err
|
||||
}
|
||||
switch t := tok.(type) {
|
||||
case xml.StartElement:
|
||||
if t.Name.Local != "member" {
|
||||
return invalidXmlError
|
||||
}
|
||||
|
||||
tagName, fieldName, err := dec.readTag()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if tagName != "name" {
|
||||
return invalidXmlError
|
||||
}
|
||||
|
||||
var fv reflect.Value
|
||||
ok := true
|
||||
|
||||
if !ismap {
|
||||
fv, ok = fields[string(fieldName)]
|
||||
} else {
|
||||
fv = reflect.New(valType.Elem())
|
||||
}
|
||||
|
||||
if ok {
|
||||
for {
|
||||
if tok, err = dec.Token(); err != nil {
|
||||
return err
|
||||
}
|
||||
if t, ok := tok.(xml.StartElement); ok && t.Name.Local == "value" {
|
||||
if err = dec.decodeValue(fv); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// </value>
|
||||
if err = dec.Skip(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// </member>
|
||||
if err = dec.Skip(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if ismap {
|
||||
pmap.SetMapIndex(reflect.ValueOf(string(fieldName)), reflect.Indirect(fv))
|
||||
val.Set(pmap)
|
||||
}
|
||||
case xml.EndElement:
|
||||
break StructLoop
|
||||
}
|
||||
}
|
||||
case "array":
|
||||
slice := val
|
||||
if checkType(val, reflect.Interface) == nil && val.IsNil() {
|
||||
slice = reflect.ValueOf([]interface{}{})
|
||||
} else if err = checkType(val, reflect.Slice); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ArrayLoop:
|
||||
for {
|
||||
if tok, err = dec.Token(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch t := tok.(type) {
|
||||
case xml.StartElement:
|
||||
var index int
|
||||
if t.Name.Local != "data" {
|
||||
return invalidXmlError
|
||||
}
|
||||
DataLoop:
|
||||
for {
|
||||
if tok, err = dec.Token(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch tt := tok.(type) {
|
||||
case xml.StartElement:
|
||||
if tt.Name.Local != "value" {
|
||||
return invalidXmlError
|
||||
}
|
||||
|
||||
if index < slice.Len() {
|
||||
v := slice.Index(index)
|
||||
if v.Kind() == reflect.Interface {
|
||||
v = v.Elem()
|
||||
}
|
||||
if v.Kind() != reflect.Ptr {
|
||||
return errors.New("error: cannot write to non-pointer array element")
|
||||
}
|
||||
if err = dec.decodeValue(v); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
v := reflect.New(slice.Type().Elem())
|
||||
if err = dec.decodeValue(v); err != nil {
|
||||
return err
|
||||
}
|
||||
slice = reflect.Append(slice, v.Elem())
|
||||
}
|
||||
|
||||
// </value>
|
||||
if err = dec.Skip(); err != nil {
|
||||
return err
|
||||
}
|
||||
index++
|
||||
case xml.EndElement:
|
||||
val.Set(slice)
|
||||
break DataLoop
|
||||
}
|
||||
}
|
||||
case xml.EndElement:
|
||||
break ArrayLoop
|
||||
}
|
||||
}
|
||||
default:
|
||||
if tok, err = dec.Token(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var data []byte
|
||||
|
||||
switch t := tok.(type) {
|
||||
case xml.EndElement:
|
||||
return nil
|
||||
case xml.CharData:
|
||||
data = []byte(t.Copy())
|
||||
default:
|
||||
return invalidXmlError
|
||||
}
|
||||
|
||||
switch typeName {
|
||||
case "int", "i4", "i8":
|
||||
if checkType(val, reflect.Interface) == nil && val.IsNil() {
|
||||
i, err := strconv.ParseInt(string(data), 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pi := reflect.New(reflect.TypeOf(i)).Elem()
|
||||
pi.SetInt(i)
|
||||
val.Set(pi)
|
||||
} else if err = checkType(val, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64); err != nil {
|
||||
return err
|
||||
} else {
|
||||
i, err := strconv.ParseInt(string(data), 10, val.Type().Bits())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
val.SetInt(i)
|
||||
}
|
||||
case "string", "base64":
|
||||
str := string(data)
|
||||
if checkType(val, reflect.Interface) == nil && val.IsNil() {
|
||||
pstr := reflect.New(reflect.TypeOf(str)).Elem()
|
||||
pstr.SetString(str)
|
||||
val.Set(pstr)
|
||||
} else if err = checkType(val, reflect.String); err != nil {
|
||||
return err
|
||||
} else {
|
||||
val.SetString(str)
|
||||
}
|
||||
case "dateTime.iso8601":
|
||||
var t time.Time
|
||||
var err error
|
||||
|
||||
for _, layout := range timeLayouts {
|
||||
t, err = time.Parse(layout, string(data))
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if checkType(val, reflect.Interface) == nil && val.IsNil() {
|
||||
ptime := reflect.New(reflect.TypeOf(t)).Elem()
|
||||
ptime.Set(reflect.ValueOf(t))
|
||||
val.Set(ptime)
|
||||
} else if _, ok := val.Interface().(time.Time); !ok {
|
||||
return TypeMismatchError(fmt.Sprintf("error: type mismatch error - can't decode %v to time", val.Kind()))
|
||||
} else {
|
||||
val.Set(reflect.ValueOf(t))
|
||||
}
|
||||
case "boolean":
|
||||
v, err := strconv.ParseBool(string(data))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if checkType(val, reflect.Interface) == nil && val.IsNil() {
|
||||
pv := reflect.New(reflect.TypeOf(v)).Elem()
|
||||
pv.SetBool(v)
|
||||
val.Set(pv)
|
||||
} else if err = checkType(val, reflect.Bool); err != nil {
|
||||
return err
|
||||
} else {
|
||||
val.SetBool(v)
|
||||
}
|
||||
case "double":
|
||||
if checkType(val, reflect.Interface) == nil && val.IsNil() {
|
||||
i, err := strconv.ParseFloat(string(data), 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pdouble := reflect.New(reflect.TypeOf(i)).Elem()
|
||||
pdouble.SetFloat(i)
|
||||
val.Set(pdouble)
|
||||
} else if err = checkType(val, reflect.Float32, reflect.Float64); err != nil {
|
||||
return err
|
||||
} else {
|
||||
i, err := strconv.ParseFloat(string(data), val.Type().Bits())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
val.SetFloat(i)
|
||||
}
|
||||
default:
|
||||
return errors.New("unsupported type")
|
||||
}
|
||||
|
||||
// </type>
|
||||
if err = dec.Skip(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dec *decoder) readTag() (string, []byte, error) {
|
||||
var tok xml.Token
|
||||
var err error
|
||||
|
||||
var name string
|
||||
for {
|
||||
if tok, err = dec.Token(); err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
if t, ok := tok.(xml.StartElement); ok {
|
||||
name = t.Name.Local
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
value, err := dec.readCharData()
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
return name, value, dec.Skip()
|
||||
}
|
||||
|
||||
func (dec *decoder) readCharData() ([]byte, error) {
|
||||
var tok xml.Token
|
||||
var err error
|
||||
|
||||
if tok, err = dec.Token(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if t, ok := tok.(xml.CharData); ok {
|
||||
return []byte(t.Copy()), nil
|
||||
} else {
|
||||
return nil, invalidXmlError
|
||||
}
|
||||
}
|
||||
|
||||
func checkType(val reflect.Value, kinds ...reflect.Kind) error {
|
||||
if len(kinds) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
if val.Kind() == reflect.Ptr {
|
||||
val = val.Elem()
|
||||
}
|
||||
|
||||
match := false
|
||||
|
||||
for _, kind := range kinds {
|
||||
if val.Kind() == kind {
|
||||
match = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !match {
|
||||
return TypeMismatchError(fmt.Sprintf("error: type mismatch - can't unmarshal %v to %v",
|
||||
val.Kind(), kinds[0]))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
174
vendor/github.com/kolo/xmlrpc/encoder.go
generated
vendored
Normal file
174
vendor/github.com/kolo/xmlrpc/encoder.go
generated
vendored
Normal file
|
|
@ -0,0 +1,174 @@
|
|||
package xmlrpc
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Base64 represents value in base64 encoding
|
||||
type Base64 string
|
||||
|
||||
type encodeFunc func(reflect.Value) ([]byte, error)
|
||||
|
||||
func marshal(v interface{}) ([]byte, error) {
|
||||
if v == nil {
|
||||
return []byte{}, nil
|
||||
}
|
||||
|
||||
val := reflect.ValueOf(v)
|
||||
return encodeValue(val)
|
||||
}
|
||||
|
||||
func encodeValue(val reflect.Value) ([]byte, error) {
|
||||
var b []byte
|
||||
var err error
|
||||
|
||||
if val.Kind() == reflect.Ptr || val.Kind() == reflect.Interface {
|
||||
if val.IsNil() {
|
||||
return []byte("<value/>"), nil
|
||||
}
|
||||
|
||||
val = val.Elem()
|
||||
}
|
||||
|
||||
switch val.Kind() {
|
||||
case reflect.Struct:
|
||||
switch val.Interface().(type) {
|
||||
case time.Time:
|
||||
t := val.Interface().(time.Time)
|
||||
b = []byte(fmt.Sprintf("<dateTime.iso8601>%s</dateTime.iso8601>", t.Format(iso8601)))
|
||||
default:
|
||||
b, err = encodeStruct(val)
|
||||
}
|
||||
case reflect.Map:
|
||||
b, err = encodeMap(val)
|
||||
case reflect.Slice:
|
||||
b, err = encodeSlice(val)
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
b = []byte(fmt.Sprintf("<int>%s</int>", strconv.FormatInt(val.Int(), 10)))
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
b = []byte(fmt.Sprintf("<i4>%s</i4>", strconv.FormatUint(val.Uint(), 10)))
|
||||
case reflect.Float32, reflect.Float64:
|
||||
b = []byte(fmt.Sprintf("<double>%s</double>",
|
||||
strconv.FormatFloat(val.Float(), 'f', -1, val.Type().Bits())))
|
||||
case reflect.Bool:
|
||||
if val.Bool() {
|
||||
b = []byte("<boolean>1</boolean>")
|
||||
} else {
|
||||
b = []byte("<boolean>0</boolean>")
|
||||
}
|
||||
case reflect.String:
|
||||
var buf bytes.Buffer
|
||||
|
||||
xml.Escape(&buf, []byte(val.String()))
|
||||
|
||||
if _, ok := val.Interface().(Base64); ok {
|
||||
b = []byte(fmt.Sprintf("<base64>%s</base64>", buf.String()))
|
||||
} else {
|
||||
b = []byte(fmt.Sprintf("<string>%s</string>", buf.String()))
|
||||
}
|
||||
default:
|
||||
return nil, fmt.Errorf("xmlrpc encode error: unsupported type")
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return []byte(fmt.Sprintf("<value>%s</value>", string(b))), nil
|
||||
}
|
||||
|
||||
func encodeStruct(val reflect.Value) ([]byte, error) {
|
||||
var b bytes.Buffer
|
||||
|
||||
b.WriteString("<struct>")
|
||||
|
||||
t := val.Type()
|
||||
for i := 0; i < t.NumField(); i++ {
|
||||
b.WriteString("<member>")
|
||||
f := t.Field(i)
|
||||
|
||||
name := f.Tag.Get("xmlrpc")
|
||||
if name == "" {
|
||||
name = f.Name
|
||||
}
|
||||
b.WriteString(fmt.Sprintf("<name>%s</name>", name))
|
||||
|
||||
p, err := encodeValue(val.FieldByName(f.Name))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b.Write(p)
|
||||
|
||||
b.WriteString("</member>")
|
||||
}
|
||||
|
||||
b.WriteString("</struct>")
|
||||
|
||||
return b.Bytes(), nil
|
||||
}
|
||||
|
||||
var sortMapKeys bool
|
||||
|
||||
func encodeMap(val reflect.Value) ([]byte, error) {
|
||||
var t = val.Type()
|
||||
|
||||
if t.Key().Kind() != reflect.String {
|
||||
return nil, fmt.Errorf("xmlrpc encode error: only maps with string keys are supported")
|
||||
}
|
||||
|
||||
var b bytes.Buffer
|
||||
|
||||
b.WriteString("<struct>")
|
||||
|
||||
keys := val.MapKeys()
|
||||
|
||||
if sortMapKeys {
|
||||
sort.Slice(keys, func(i, j int) bool { return keys[i].String() < keys[j].String() })
|
||||
}
|
||||
|
||||
for i := 0; i < val.Len(); i++ {
|
||||
key := keys[i]
|
||||
kval := val.MapIndex(key)
|
||||
|
||||
b.WriteString("<member>")
|
||||
b.WriteString(fmt.Sprintf("<name>%s</name>", key.String()))
|
||||
|
||||
p, err := encodeValue(kval)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
b.Write(p)
|
||||
b.WriteString("</member>")
|
||||
}
|
||||
|
||||
b.WriteString("</struct>")
|
||||
|
||||
return b.Bytes(), nil
|
||||
}
|
||||
|
||||
func encodeSlice(val reflect.Value) ([]byte, error) {
|
||||
var b bytes.Buffer
|
||||
|
||||
b.WriteString("<array><data>")
|
||||
|
||||
for i := 0; i < val.Len(); i++ {
|
||||
p, err := encodeValue(val.Index(i))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
b.Write(p)
|
||||
}
|
||||
|
||||
b.WriteString("</data></array>")
|
||||
|
||||
return b.Bytes(), nil
|
||||
}
|
||||
57
vendor/github.com/kolo/xmlrpc/request.go
generated
vendored
Normal file
57
vendor/github.com/kolo/xmlrpc/request.go
generated
vendored
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
package xmlrpc
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func NewRequest(url string, method string, args interface{}) (*http.Request, error) {
|
||||
var t []interface{}
|
||||
var ok bool
|
||||
if t, ok = args.([]interface{}); !ok {
|
||||
if args != nil {
|
||||
t = []interface{}{args}
|
||||
}
|
||||
}
|
||||
|
||||
body, err := EncodeMethodCall(method, t...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
request, err := http.NewRequest("POST", url, bytes.NewReader(body))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
request.Header.Set("Content-Type", "text/xml")
|
||||
request.Header.Set("Content-Length", fmt.Sprintf("%d", len(body)))
|
||||
|
||||
return request, nil
|
||||
}
|
||||
|
||||
func EncodeMethodCall(method string, args ...interface{}) ([]byte, error) {
|
||||
var b bytes.Buffer
|
||||
b.WriteString(`<?xml version="1.0" encoding="UTF-8"?>`)
|
||||
b.WriteString(fmt.Sprintf("<methodCall><methodName>%s</methodName>", method))
|
||||
|
||||
if args != nil {
|
||||
b.WriteString("<params>")
|
||||
|
||||
for _, arg := range args {
|
||||
p, err := marshal(arg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
b.WriteString(fmt.Sprintf("<param>%s</param>", string(p)))
|
||||
}
|
||||
|
||||
b.WriteString("</params>")
|
||||
}
|
||||
|
||||
b.WriteString("</methodCall>")
|
||||
|
||||
return b.Bytes(), nil
|
||||
}
|
||||
42
vendor/github.com/kolo/xmlrpc/response.go
generated
vendored
Normal file
42
vendor/github.com/kolo/xmlrpc/response.go
generated
vendored
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
package xmlrpc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
var (
|
||||
faultRx = regexp.MustCompile(`<fault>(\s|\S)+</fault>`)
|
||||
)
|
||||
|
||||
// FaultError is returned from the server when an invalid call is made
|
||||
type FaultError struct {
|
||||
Code int `xmlrpc:"faultCode"`
|
||||
String string `xmlrpc:"faultString"`
|
||||
}
|
||||
|
||||
// Error implements the error interface
|
||||
func (e FaultError) Error() string {
|
||||
return fmt.Sprintf("Fault(%d): %s", e.Code, e.String)
|
||||
}
|
||||
|
||||
type Response []byte
|
||||
|
||||
func (r Response) Err() error {
|
||||
if !faultRx.Match(r) {
|
||||
return nil
|
||||
}
|
||||
var fault FaultError
|
||||
if err := unmarshal(r, &fault); err != nil {
|
||||
return err
|
||||
}
|
||||
return fault
|
||||
}
|
||||
|
||||
func (r Response) Unmarshal(v interface{}) error {
|
||||
if err := unmarshal(r, v); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
25
vendor/github.com/kolo/xmlrpc/test_server.rb
generated
vendored
Normal file
25
vendor/github.com/kolo/xmlrpc/test_server.rb
generated
vendored
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
# encoding: utf-8
|
||||
|
||||
require "xmlrpc/server"
|
||||
|
||||
class Service
|
||||
def time
|
||||
Time.now
|
||||
end
|
||||
|
||||
def upcase(s)
|
||||
s.upcase
|
||||
end
|
||||
|
||||
def sum(x, y)
|
||||
x + y
|
||||
end
|
||||
|
||||
def error
|
||||
raise XMLRPC::FaultException.new(500, "Server error")
|
||||
end
|
||||
end
|
||||
|
||||
server = XMLRPC::Server.new 5001, 'localhost'
|
||||
server.add_handler "service", Service.new
|
||||
server.serve
|
||||
2
vendor/modules.txt
vendored
2
vendor/modules.txt
vendored
|
|
@ -100,6 +100,8 @@ github.com/google/uuid
|
|||
github.com/jmespath/go-jmespath
|
||||
# github.com/julienschmidt/httprouter v1.2.0
|
||||
github.com/julienschmidt/httprouter
|
||||
# github.com/kolo/xmlrpc v0.0.0-20190909154602-56d5ec7c422e
|
||||
github.com/kolo/xmlrpc
|
||||
# github.com/mattn/go-ieproxy v0.0.0-20190610004146-91bb50d98149
|
||||
github.com/mattn/go-ieproxy
|
||||
# github.com/mitchellh/go-homedir v1.1.0
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue