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 }
// 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() }
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 }
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 }
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 <RFC2518>.` + ` </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) } } }