// StructToXML writes an XMLNode to a xml.Encoder as tokens. func StructToXML(e *xml.Encoder, node *XMLNode, sorted bool) error { e.EncodeToken(xml.StartElement{Name: node.Name, Attr: node.Attr}) if node.Text != "" { e.EncodeToken(xml.CharData([]byte(node.Text))) } else if sorted { sortedNames := []string{} for k := range node.Children { sortedNames = append(sortedNames, k) } sort.Strings(sortedNames) for _, k := range sortedNames { for _, v := range node.Children[k] { StructToXML(e, v, sorted) } } } else { for _, c := range node.Children { for _, v := range c { StructToXML(e, v, sorted) } } } e.EncodeToken(xml.EndElement{Name: node.Name}) return e.Flush() }
// TransformXML parses the XML tree, traverses it and calls TransformFunc // on each XML token, writing the output to the writer, resulting in a // transformed XML tree func TransformXML(decoder *xml.Decoder, encoder *xml.Encoder, fn TransformFunc) error { parentNodes := &NodeList{} for { token, err := decoder.Token() if err != nil { if err != io.EOF { return trace.Wrap(err) } break } for _, t := range fn(parentNodes, token) { if err := encoder.EncodeToken(t); err != nil { return err } } switch e := token.(type) { case xml.StartElement: parentNodes.Push(e) case xml.EndElement: parentNodes.Pop() } } encoder.Flush() return nil }
// writeNewline is used to force conventional XML plist formatting when // writing the file header. func writeNewline(w io.Writer, e *xml.Encoder) error { // Flush before writing to the Writer ourselves. if err := e.Flush(); err != nil { return err } if _, err := fmt.Fprintln(w); err != nil { return err } return nil }
func (fc *FeatureContainer) MarshalXML(e *xml.Encoder, start xml.StartElement) error { start = xml.StartElement{Name: xml.Name{Local: "stream:features"}} if err := e.EncodeToken(start); err != nil { return err } fs := make([]Feature, 0, len(fc.features)) for _, v := range fc.features { fs = append(fs, v) } if err := e.Encode(fs); err != nil { return err } if err := e.EncodeToken(start.End()); err != nil { return err } return e.Flush() }
// MarshalXML is a custom XML marshaler for InstanceMetadata. func (i InstanceMetadata) MarshalXML(e *xml.Encoder, start xml.StartElement) error { tokens := []xml.Token{start} if i.parsed != nil { for key, value := range i.parsed { t := xml.StartElement{Name: xml.Name{"", key}} tokens = append(tokens, t, xml.CharData(value.(string)), xml.EndElement{t.Name}) } } tokens = append(tokens, xml.EndElement{start.Name}) for _, t := range tokens { err := e.EncodeToken(t) if err != nil { return err } } // flush to ensure tokens are written return e.Flush() }
func (s *MetaData) MarshalXML(e *xml.Encoder, start xml.StartElement) error { var attributes []xml.Attr = make([]xml.Attr, 0) if s.Class != "" { attributes = append(attributes, xml.Attr{ Name: xml.Name{ Local: "class", }, Value: s.Class, }) } start.Attr = attributes tokens := []xml.Token{start} for key, value := range s.Map { t := xml.StartElement{Name: xml.Name{"", key}} tokens = append(tokens, t, xml.CharData(value), xml.EndElement{t.Name}) } tokens = append(tokens, xml.EndElement{ Name: start.Name, }) for _, t := range tokens { err := e.EncodeToken(t) if err != nil { return err } } // flush to ensure tokens are written err := e.Flush() if err != nil { return err } return nil }
func xmppHandshake(xmlEncoder *xml.Encoder, xmlDecoder *xml.Decoder, domain, proxyName string) (string, error) { handshake := xml.StartElement{ Name: xml.Name{"jabber:client", "stream:stream"}, Attr: []xml.Attr{ xml.Attr{xml.Name{Local: "to"}, domain}, xml.Attr{xml.Name{Local: "xml:lang"}, "en"}, xml.Attr{xml.Name{Local: "version"}, "1.0"}, xml.Attr{xml.Name{Local: "xmlns:stream"}, "http://etherx.jabber.org/streams"}, }, } if err := xmlEncoder.EncodeToken(handshake); err != nil { return "", fmt.Errorf("Failed to write SASL handshake: %s", err) } if err := xmlEncoder.Flush(); err != nil { return "", fmt.Errorf("Failed to flush encoding stream: %s", err) } if startElement, err := readStartElement(xmlDecoder); err != nil { return "", err } else if startElement.Name.Space != "http://etherx.jabber.org/streams" || startElement.Name.Local != "stream" { return "", fmt.Errorf("Read unexpected XMPP XML stanza: %s", startElement.Name.Local) } var features struct { XMLName xml.Name `xml:"http://etherx.jabber.org/streams features"` Bind *struct { XMLName xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-bind bind"` } Session *struct { XMLName xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-session session"` } } if err := xmlDecoder.Decode(&features); err != nil { return "", fmt.Errorf("Read unexpected XMPP XML element: %s", err) } else if features.Bind == nil || features.Session == nil { return "", errors.New("XMPP bind or session missing from handshake") } var resource struct { XMLName xml.Name `xml:"jabber:client iq"` Type string `xml:"type,attr"` ID string `xml:"id,attr"` Bind struct { XMLName xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-bind bind"` Resource struct { XMLName xml.Name `xml:"resource"` ResourceName string `xml:",chardata"` } } } resource.Type = "set" resource.ID = "0" resource.Bind.Resource.ResourceName = proxyName if err := xmlEncoder.Encode(&resource); err != nil { return "", fmt.Errorf("Failed to set resource during XMPP handshake: %s", err) } var jid struct { XMLName xml.Name `xml:"jabber:client iq"` Bind *struct { XMLName xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-bind bind"` JID string `xml:"jid"` } } if err := xmlDecoder.Decode(&jid); err != nil { return "", err } else if jid.Bind == nil || jid.Bind.JID == "" { return "", errors.New("Received unexpected XML element during XMPP handshake") } fullJID := jid.Bind.JID var session struct { XMLName xml.Name `xml:"jabber:client iq"` Type string `xml:"type,attr"` ID string `xml:"id,attr"` Session struct { XMLName xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-session session"` } } session.Type = "set" session.ID = "1" if err := xmlEncoder.Encode(&session); err != nil { return "", fmt.Errorf("Failed to complete XMPP handshake: %s", err) } var done struct { XMLName xml.Name `xml:"jabber:client iq"` ID string `xml:"id,attr"` } if err := xmlDecoder.Decode(&done); err != nil { return "", err } else if done.ID != "1" { return "", errors.New("Received unexpected result at end of XMPP handshake") } return fullJID, nil }
func saslHandshake(xmlEncoder *xml.Encoder, xmlDecoder *xml.Decoder, domain, user, accessToken string) error { handshake := xml.StartElement{ Name: xml.Name{"jabber:client", "stream:stream"}, Attr: []xml.Attr{ xml.Attr{xml.Name{Local: "to"}, domain}, xml.Attr{xml.Name{Local: "xml:lang"}, "en"}, xml.Attr{xml.Name{Local: "version"}, "1.0"}, xml.Attr{xml.Name{Local: "xmlns:stream"}, "http://etherx.jabber.org/streams"}, }, } if err := xmlEncoder.EncodeToken(handshake); err != nil { return fmt.Errorf("Failed to write SASL handshake: %s", err) } if err := xmlEncoder.Flush(); err != nil { return fmt.Errorf("Failed to flush encoding stream: %s", err) } if startElement, err := readStartElement(xmlDecoder); err != nil { return err } else if startElement.Name.Space != "http://etherx.jabber.org/streams" || startElement.Name.Local != "stream" { return fmt.Errorf("Read unexpected SASL XML stanza: %s", startElement.Name.Local) } var features struct { XMLName xml.Name `xml:"http://etherx.jabber.org/streams features"` Mechanisms *struct { XMLName xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-sasl mechanisms"` } } if err := xmlDecoder.Decode(&features); err != nil { return fmt.Errorf("Read unexpected SASL XML element: %s", err) } else if features.Mechanisms == nil { return errors.New("SASL mechanisms missing from handshake") } credential := base64.StdEncoding.EncodeToString([]byte("\x00" + user + "\x00" + accessToken)) var auth struct { XMLName xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-sasl auth"` Mechanism string `xml:"mechanism,attr"` Service string `xml:"auth:service,attr"` Allow string `xml:"auth:allow-generated-jid,attr"` FullBind string `xml:"auth:client-uses-full-bind-result,attr"` XMLNS string `xml:"xmlns:auth,attr"` Credential string `xml:",chardata"` } auth.Mechanism = "X-OAUTH2" auth.Service = "chromiumsync" auth.Allow = "true" auth.FullBind = "true" auth.XMLNS = "http://www.google.com/talk/protocol/auth" auth.Credential = credential if err := xmlEncoder.Encode(auth); err != nil { return fmt.Errorf("Failed to write SASL credentials: %s", err) } var success struct { XMLName xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-sasl success"` } if err := xmlDecoder.Decode(&success); err != nil { return fmt.Errorf("Failed to complete SASL handshake: %s", err) } return nil }
func spl1t(bunch net.Conn, errHandler func(error)) (ret chan []byte) { ret = make(chan []byte) go func() { d := xml.NewDecoder(bunch) d.Strict = false var ( _t xml.Token err error buf *bytes.Buffer e *xml.Encoder ) init := func() { buf = bytes.NewBuffer(nil) e = xml.NewEncoder(buf) } flush := func() { e.Flush() if buf.Len() > 0 { ret <- buf.Bytes() } init() } join := func(n xml.Name) (ret string) { if n.Space != "" { ret = n.Space + ":" } ret = ret + n.Local return } depth := 0 init() for stop := false; !stop && err == nil; { bunch.SetDeadline(time.Now().Add(10 * time.Second)) if _t, err = d.RawToken(); err == nil { switch t := _t.(type) { case xml.ProcInst: e.EncodeToken(t.Copy()) case xml.StartElement: tt := t.Copy() tt.Name = xml.Name{Local: join(t.Name)} var tmp []xml.Attr for _, a := range tt.Attr { a.Name = xml.Name{Local: join(a.Name)} tmp = append(tmp, a) } tt.Attr = tmp e.EncodeToken(tt) if tt.Name.Local == "stream:stream" { depth-- flush() } depth++ case xml.EndElement: tt := t tt.Name = xml.Name{Local: join(t.Name)} e.EncodeToken(tt) depth-- if depth == 0 { flush() } case xml.CharData: e.EncodeToken(t) default: halt.As(100, reflect.TypeOf(t)) } } else { flush() errHandler(err) } //log.Println("raw token read", err) } close(ret) }() return }