Example #1
0
// UnmarshalBody extracts the Body from a soap.Envelope and unmarshals to the corresponding govmomi type
func UnmarshalBody(data []byte) (*Method, error) {
	body := struct {
		Content string `xml:",innerxml"`
	}{}

	req := soap.Envelope{
		Body: &body,
	}

	err := xml.Unmarshal(data, &req)
	if err != nil {
		return nil, fmt.Errorf("xml.Unmarshal: %s", err)
	}

	decoder := xml.NewDecoder(bytes.NewReader([]byte(body.Content)))
	decoder.TypeFunc = typeFunc // required to decode interface types

	var start *xml.StartElement

	for {
		tok, derr := decoder.Token()
		if derr != nil {
			return nil, fmt.Errorf("decoding body: %s", err)
		}
		if t, ok := tok.(xml.StartElement); ok {
			start = &t
			break
		}
	}

	kind := start.Name.Local

	rtype, ok := typeFunc(kind)
	if !ok {
		return nil, fmt.Errorf("no vmomi type defined for '%s'", kind)
	}

	var val interface{}
	if rtype != nil {
		val = reflect.New(rtype).Interface()
	}

	err = decoder.DecodeElement(val, start)
	if err != nil {
		return nil, fmt.Errorf("decoding %s: %s", kind, err)
	}

	method := &Method{Name: kind, Body: val}

	field := reflect.ValueOf(val).Elem().FieldByName("This")

	method.This = field.Interface().(types.ManagedObjectReference)

	return method, nil
}
Example #2
0
func load(name string) *Response {
	f, err := os.Open(name)
	if err != nil {
		panic(err)
	}

	defer f.Close()

	var b Response

	dec := xml.NewDecoder(f)
	dec.TypeFunc = types.TypeFunc()
	if err := dec.Decode(&b); err != nil {
		panic(err)
	}

	return &b
}
Example #3
0
func TestFaultDetail(t *testing.T) {
	body := TestBody{}
	env := soap.Envelope{Body: &body}

	dec := xml.NewDecoder(bytes.NewReader([]byte(invalidLoginFault)))
	dec.TypeFunc = types.TypeFunc()

	err := dec.Decode(&env)
	if err != nil {
		t.Fatalf("Decode: %s", err)
	}

	if body.Fault == nil {
		t.Fatal("Expected fault")
	}

	if _, ok := body.Fault.Detail.Fault.(types.InvalidLogin); !ok {
		t.Fatalf("Expected InvalidLogin, got: %#v", body.Fault.Detail.Fault)
	}
}
Example #4
0
func TestAnyType(t *testing.T) {
	x := func(s string) []byte {
		s = `<root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">` + s
		s += `</root>`
		return []byte(s)
	}

	tests := []struct {
		Input []byte
		Value interface{}
	}{
		{
			Input: x(`<name xsi:type="xsd:string">test</name>`),
			Value: "test",
		},
		{
			Input: x(`<name xsi:type="ArrayOfString"><string>AA</string><string>BB</string></name>`),
			Value: ArrayOfString{String: []string{"AA", "BB"}},
		},
	}

	for _, test := range tests {
		var r struct {
			A interface{} `xml:"name,typeattr"`
		}

		dec := xml.NewDecoder(bytes.NewReader(test.Input))
		dec.TypeFunc = TypeFunc()

		err := dec.Decode(&r)
		if err != nil {
			t.Fatalf("Decode: %s", err)
		}

		if !reflect.DeepEqual(r.A, test.Value) {
			t.Errorf("Expected: %#v, actual: %#v", r.A, test.Value)
		}
	}
}
Example #5
0
func (c *Client) RoundTrip(ctx context.Context, reqBody, resBody HasFault) error {
	var err error

	reqEnv := Envelope{Body: reqBody}
	resEnv := Envelope{Body: resBody}

	// Create debugging context for this round trip
	d := c.d.newRoundTrip()
	if d.enabled() {
		defer d.done()
	}

	b, err := xml.Marshal(reqEnv)
	if err != nil {
		panic(err)
	}

	rawReqBody := io.MultiReader(strings.NewReader(xml.Header), bytes.NewReader(b))
	req, err := http.NewRequest("POST", c.u.String(), rawReqBody)
	if err != nil {
		panic(err)
	}

	req.Header.Set(`Content-Type`, `text/xml; charset="utf-8"`)
	soapAction := fmt.Sprintf("%s/%s", c.Namespace, c.Version)
	req.Header.Set(`SOAPAction`, soapAction)
	if c.UserAgent != "" {
		req.Header.Set(`User-Agent`, c.UserAgent)
	}

	if d.enabled() {
		d.debugRequest(req)
	}

	tstart := time.Now()
	res, err := c.do(ctx, req)
	tstop := time.Now()

	if d.enabled() {
		d.logf("%6dms (%T)", tstop.Sub(tstart)/time.Millisecond, resBody)
	}

	if err != nil {
		return err
	}

	if d.enabled() {
		d.debugResponse(res)
	}

	// Close response regardless of what happens next
	defer res.Body.Close()

	switch res.StatusCode {
	case http.StatusOK:
		// OK
	case http.StatusInternalServerError:
		// Error, but typically includes a body explaining the error
	default:
		return errors.New(res.Status)
	}

	dec := xml.NewDecoder(res.Body)
	dec.TypeFunc = types.TypeFunc()
	err = dec.Decode(&resEnv)
	if err != nil {
		return err
	}

	if f := resBody.Fault(); f != nil {
		return WrapSoapFault(f)
	}

	return err
}