Beispiel #1
0
func readPropfind(r io.Reader) (pf propfind, status int, err error) {
	c := countingReader{r: r}
	if err = xml.NewDecoder(&c).Decode(&pf); err != nil {
		if err == io.EOF {
			if c.n == 0 {
				// An empty body means to propfind allprop.
				// http://www.webdav.org/specs/rfc4918.html#METHOD_PROPFIND
				return propfind{Allprop: new(struct{})}, 0, nil
			}
			err = errInvalidPropfind
		}
		return propfind{}, http.StatusBadRequest, err
	}

	if pf.Allprop == nil && pf.Include != nil {
		return propfind{}, http.StatusBadRequest, errInvalidPropfind
	}
	if pf.Allprop != nil && (pf.Prop != nil || pf.Propname != nil) {
		return propfind{}, http.StatusBadRequest, errInvalidPropfind
	}
	if pf.Prop != nil && pf.Propname != nil {
		return propfind{}, http.StatusBadRequest, errInvalidPropfind
	}
	if pf.Propname == nil && pf.Allprop == nil && pf.Prop == nil {
		return propfind{}, http.StatusBadRequest, errInvalidPropfind
	}
	return pf, 0, nil
}
Beispiel #2
0
// normalize writes the normalized XML content of r to w. It applies the
// following rules
//
//     * Rename namespace prefixes according to an internal heuristic.
//     * Remove unnecessary namespace declarations.
//     * Sort attributes in XML start elements in lexical order of their
//       fully qualified name.
//     * Remove XML directives and processing instructions.
//     * Remove CDATA between XML tags that only contains whitespace, if
//       instructed to do so.
//     * Remove comments, if instructed to do so.
//
func (n *xmlNormalizer) normalize(w io.Writer, r io.Reader) error {
	d := ixml.NewDecoder(r)
	e := ixml.NewEncoder(w)
	for {
		t, err := d.Token()
		if err != nil {
			if t == nil && err == io.EOF {
				break
			}
			return err
		}
		switch val := t.(type) {
		case ixml.Directive, ixml.ProcInst:
			continue
		case ixml.Comment:
			if n.omitComments {
				continue
			}
		case ixml.CharData:
			if n.omitWhitespace && len(bytes.TrimSpace(val)) == 0 {
				continue
			}
		case ixml.StartElement:
			start, _ := ixml.CopyToken(val).(ixml.StartElement)
			attr := start.Attr[:0]
			for _, a := range start.Attr {
				if a.Name.Space == "xmlns" || a.Name.Local == "xmlns" {
					continue
				}
				attr = append(attr, a)
			}
			sort.Sort(byName(attr))
			start.Attr = attr
			t = start
		}
		err = e.EncodeToken(t)
		if err != nil {
			return err
		}
	}
	return e.Flush()
}
Beispiel #3
0
func readLockInfo(r io.Reader) (li lockInfo, status int, err error) {
	c := &countingReader{r: r}
	if err = xml.NewDecoder(c).Decode(&li); err != nil {
		if err == io.EOF {
			if c.n == 0 {
				// An empty body means to refresh the lock.
				// http://www.webdav.org/specs/rfc4918.html#refreshing-locks
				return lockInfo{}, 0, nil
			}
			err = errInvalidLockInfo
		}
		return lockInfo{}, http.StatusBadRequest, err
	}
	// We only support exclusive (non-shared) write locks. In practice, these are
	// the only types of locks that seem to matter.
	if li.Exclusive == nil || li.Shared != nil || li.Write == nil {
		return lockInfo{}, http.StatusNotImplemented, errUnsupportedLockInfo
	}
	return li, 0, nil
}
Beispiel #4
0
func readProppatch(r io.Reader) (patches []Proppatch, status int, err error) {
	var pu propertyupdate
	if err = xml.NewDecoder(r).Decode(&pu); err != nil {
		return nil, http.StatusBadRequest, err
	}
	for _, op := range pu.SetRemove {
		remove := false
		switch op.XMLName {
		case xml.Name{Space: "DAV:", Local: "set"}:
			// No-op.
		case xml.Name{Space: "DAV:", Local: "remove"}:
			for _, p := range op.Prop {
				if len(p.InnerXML) > 0 {
					return nil, http.StatusBadRequest, errInvalidProppatch
				}
			}
			remove = true
		default:
			return nil, http.StatusBadRequest, errInvalidProppatch
		}
		patches = append(patches, Proppatch{Remove: remove, Props: op.Prop})
	}
	return patches, 0, nil
}
Beispiel #5
0
func TestUnmarshalXMLValue(t *testing.T) {
	testCases := []struct {
		desc    string
		input   string
		wantVal string
	}{{
		desc:    "simple char data",
		input:   "<root>foo</root>",
		wantVal: "foo",
	}, {
		desc:    "empty element",
		input:   "<root><foo/></root>",
		wantVal: "<foo/>",
	}, {
		desc:    "preserve namespace",
		input:   `<root><foo xmlns="bar"/></root>`,
		wantVal: `<foo xmlns="bar"/>`,
	}, {
		desc:    "preserve root element namespace",
		input:   `<root xmlns:bar="bar"><bar:foo/></root>`,
		wantVal: `<foo xmlns="bar"/>`,
	}, {
		desc:    "preserve whitespace",
		input:   "<root>  \t </root>",
		wantVal: "  \t ",
	}, {
		desc:    "preserve mixed content",
		input:   `<root xmlns="bar">  <foo>a<bam xmlns="baz"/> </foo> </root>`,
		wantVal: `  <foo xmlns="bar">a<bam xmlns="baz"/> </foo> `,
	}, {
		desc: "section 9.2",
		input: `` +
			`<Z:Authors xmlns:Z="http://ns.example.com/z/">` +
			`  <Z:Author>Jim Whitehead</Z:Author>` +
			`  <Z:Author>Roy Fielding</Z:Author>` +
			`</Z:Authors>`,
		wantVal: `` +
			`  <Author xmlns="http://ns.example.com/z/">Jim Whitehead</Author>` +
			`  <Author xmlns="http://ns.example.com/z/">Roy Fielding</Author>`,
	}, {
		desc: "section 4.3.1 (mixed content)",
		input: `` +
			`<x:author ` +
			`    xmlns:x='http://example.com/ns' ` +
			`    xmlns:D="DAV:">` +
			`  <x:name>Jane Doe</x:name>` +
			`  <!-- Jane's contact info -->` +
			`  <x:uri type='email'` +
			`         added='2005-11-26'>mailto:[email protected]</x:uri>` +
			`  <x:uri type='web'` +
			`         added='2005-11-27'>http://www.example.com</x:uri>` +
			`  <x:notes xmlns:h='http://www.w3.org/1999/xhtml'>` +
			`    Jane has been working way <h:em>too</h:em> long on the` +
			`    long-awaited revision of <![CDATA[<RFC2518>]]>.` +
			`  </x:notes>` +
			`</x:author>`,
		wantVal: `` +
			`  <name xmlns="http://example.com/ns">Jane Doe</name>` +
			`  ` +
			`  <uri type='email'` +
			`       xmlns="http://example.com/ns" ` +
			`       added='2005-11-26'>mailto:[email protected]</uri>` +
			`  <uri added='2005-11-27'` +
			`       type='web'` +
			`       xmlns="http://example.com/ns">http://www.example.com</uri>` +
			`  <notes xmlns="http://example.com/ns" ` +
			`         xmlns:h="http://www.w3.org/1999/xhtml">` +
			`    Jane has been working way <h:em>too</h:em> long on the` +
			`    long-awaited revision of &lt;RFC2518&gt;.` +
			`  </notes>`,
	}}

	var n xmlNormalizer
	for _, tc := range testCases {
		d := ixml.NewDecoder(strings.NewReader(tc.input))
		var v xmlValue
		if err := d.Decode(&v); err != nil {
			t.Errorf("%s: got error %v, want nil", tc.desc, err)
			continue
		}
		eq, err := n.equalXML(bytes.NewReader(v), strings.NewReader(tc.wantVal))
		if err != nil {
			t.Errorf("%s: equalXML: %v", tc.desc, err)
			continue
		}
		if !eq {
			t.Errorf("%s:\ngot  %s\nwant %s", tc.desc, string(v), tc.wantVal)
		}
	}
}