@@ -536,23 +536,15 @@ func handleInputStream(s *Session, handler Handler) (err error) {
536
536
}
537
537
}
538
538
539
- var id string
540
- var needsResp bool
541
- if isIQ (start .Name ) {
542
- _ , id = attr .Get (start .Attr , "id" )
543
-
544
- // If this is a response IQ (ie. an "error" or "result") check if we're
545
- // handling it as part of a SendIQ call.
546
- // If not, record this so that we can check if the user sends a response
547
- // later.
548
- if ! iqNeedsResp (start .Attr ) {
549
- s .sentIQMutex .Lock ()
550
- c := s .sentIQs [id ]
551
- s .sentIQMutex .Unlock ()
552
- if c == nil {
553
- goto noreply
554
- }
539
+ iqOk := isIQ (start .Name )
540
+ _ , _ , id , typ := getIDTyp (start .Attr )
541
+ iqNeedsResp := typ == string (stanza .GetIQ ) || typ == string (stanza .SetIQ )
555
542
543
+ if ! iqNeedsResp {
544
+ s .sentIQMutex .Lock ()
545
+ c := s .sentIQs [id ]
546
+ s .sentIQMutex .Unlock ()
547
+ if c != nil {
556
548
inner := xmlstream .Inner (r )
557
549
c <- iqResponder {
558
550
r : xmlstream .MultiReader (xmlstream .Token (start ), inner , xmlstream .Token (start .End ())),
@@ -566,11 +558,8 @@ func handleInputStream(s *Session, handler Handler) (err error) {
566
558
}
567
559
return nil
568
560
}
569
- needsResp = true
570
561
}
571
562
572
- noreply:
573
-
574
563
w := s .TokenWriter ()
575
564
defer w .Close ()
576
565
rw := & responseChecker {
@@ -583,7 +572,7 @@ noreply:
583
572
}
584
573
585
574
// If the user did not write a response to an IQ, send a default one.
586
- if needsResp && ! rw .wroteResp {
575
+ if iqOk && iqNeedsResp && ! rw .wroteResp {
587
576
_ , toAttr := attr .Get (start .Attr , "to" )
588
577
var to jid.JID
589
578
if toAttr != "" {
@@ -615,6 +604,26 @@ noreply:
615
604
return err
616
605
}
617
606
607
+ func getIDTyp (attrs []xml.Attr ) (int , int , string , string ) {
608
+ var id , typ string
609
+ idIdx := - 1
610
+ typIdx := - 1
611
+ for idx , attr := range attrs {
612
+ switch attr .Name .Local {
613
+ case "id" :
614
+ id = attr .Value
615
+ idIdx = idx
616
+ case "type" :
617
+ typ = attr .Value
618
+ typIdx = idx
619
+ }
620
+ if idIdx > - 1 && typIdx > - 1 {
621
+ break
622
+ }
623
+ }
624
+ return idIdx , typIdx , id , typ
625
+ }
626
+
618
627
type responseChecker struct {
619
628
xml.TokenReader
620
629
xmlstream.TokenWriter
@@ -626,8 +635,8 @@ type responseChecker struct {
626
635
func (rw * responseChecker ) EncodeToken (t xml.Token ) error {
627
636
switch tok := t .(type ) {
628
637
case xml.StartElement :
629
- _ , id := attr . Get (tok .Attr , "id" )
630
- if rw .level < 1 && isIQEmptySpace (tok .Name ) && id == rw .id && ! iqNeedsResp ( tok . Attr ) {
638
+ _ , _ , id , typ := getIDTyp (tok .Attr )
639
+ if rw .level < 1 && isIQEmptySpace (tok .Name ) && id == rw .id && ( typ != string ( stanza . GetIQ ) && typ != string ( stanza . SetIQ ) ) {
631
640
rw .wroteResp = true
632
641
}
633
642
rw .level ++
@@ -846,32 +855,6 @@ func (s *Session) SetCloseDeadline(t time.Time) error {
846
855
return s .Conn ().SetReadDeadline (t )
847
856
}
848
857
849
- // EncodeIQ is like Encode except that it returns an error if v does not marshal
850
- // to an IQ stanza and like SendIQ it blocks until a response is received.
851
- // For more information see SendIQ.
852
- //
853
- // EncodeIQ is safe for concurrent use by multiple goroutines.
854
- func (s * Session ) EncodeIQ (ctx context.Context , v interface {}) (xmlstream.TokenReadCloser , error ) {
855
- r , err := marshal .TokenReader (v )
856
- if err != nil {
857
- return nil , err
858
- }
859
- return s .SendIQ (ctx , r )
860
- }
861
-
862
- // EncodeIQElement is like EncodeIQ except that it wraps the payload in an
863
- // Info/Query (IQ) element.
864
- // For more information see SendIQ.
865
- //
866
- // EncodeIQElement is safe for concurrent use by multiple goroutines.
867
- func (s * Session ) EncodeIQElement (ctx context.Context , payload interface {}, iq stanza.IQ ) (xmlstream.TokenReadCloser , error ) {
868
- r , err := marshal .TokenReader (payload )
869
- if err != nil {
870
- return nil , err
871
- }
872
- return s .SendIQElement (ctx , r , iq )
873
- }
874
-
875
858
// Encode writes the XML encoding of v to the stream.
876
859
//
877
860
// For more information see "encoding/xml".Encode.
@@ -945,18 +928,6 @@ func send(ctx context.Context, s *Session, r xml.TokenReader, start *xml.StartEl
945
928
return s .out .e .Flush ()
946
929
}
947
930
948
- func iqNeedsResp (attrs []xml.Attr ) bool {
949
- var typ string
950
- for _ , attr := range attrs {
951
- if attr .Name .Local == "type" {
952
- typ = attr .Value
953
- break
954
- }
955
- }
956
-
957
- return typ == string (stanza .GetIQ ) || typ == string (stanza .SetIQ )
958
- }
959
-
960
931
func isIQ (name xml.Name ) bool {
961
932
return name .Local == "iq" && (name .Space == ns .Client || name .Space == ns .Server )
962
933
}
@@ -970,172 +941,6 @@ func isStanzaEmptySpace(name xml.Name) bool {
970
941
(name .Space == ns .Client || name .Space == ns .Server || name .Space == "" )
971
942
}
972
943
973
- // SendIQ is like Send except that it returns an error if the first token read
974
- // from the stream is not an Info/Query (IQ) start element and blocks until a
975
- // response is received.
976
- //
977
- // If the input stream is not being processed (a call to Serve is not running),
978
- // SendIQ will never receive a response and will block until the provided
979
- // context is canceled.
980
- // If the response is non-nil, it does not need to be consumed in its entirety,
981
- // but it must be closed before stream processing will resume.
982
- // If the IQ type does not require a response—ie. it is a result or error IQ,
983
- // meaning that it is a response itself—SendIQElemnt does not block and the
984
- // response is nil.
985
- //
986
- // If the context is closed before the response is received, SendIQ immediately
987
- // returns the context error.
988
- // Any response received at a later time will not be associated with the
989
- // original request but can still be handled by the Serve handler.
990
- //
991
- // If an error is returned, the response will be nil; the converse is not
992
- // necessarily true.
993
- // SendIQ is safe for concurrent use by multiple goroutines.
994
- func (s * Session ) SendIQ (ctx context.Context , r xml.TokenReader ) (xmlstream.TokenReadCloser , error ) {
995
- tok , err := r .Token ()
996
- if err != nil {
997
- return nil , err
998
- }
999
- start , ok := tok .(xml.StartElement )
1000
- if ! ok {
1001
- return nil , fmt .Errorf ("expected IQ start element, got %T" , tok )
1002
- }
1003
- if ! isIQEmptySpace (start .Name ) {
1004
- return nil , fmt .Errorf ("expected start element to be an IQ" )
1005
- }
1006
-
1007
- // If there's no ID, add one.
1008
- idx , id := attr .Get (start .Attr , "id" )
1009
- if idx == - 1 {
1010
- idx = len (start .Attr )
1011
- start .Attr = append (start .Attr , xml.Attr {Name : xml.Name {Local : "id" }, Value : "" })
1012
- }
1013
- if id == "" {
1014
- id = attr .RandomID ()
1015
- start .Attr [idx ].Value = id
1016
- }
1017
-
1018
- // If this an IQ of type "set" or "get" we expect a response.
1019
- if iqNeedsResp (start .Attr ) {
1020
- return s .sendResp (ctx , id , xmlstream .Inner (r ), start )
1021
- }
1022
-
1023
- // If this is an IQ of type result or error, we don't expect a response so
1024
- // just send it normally.
1025
- return nil , s .SendElement (ctx , xmlstream .Inner (r ), start )
1026
- }
1027
-
1028
- // SendIQElement is like SendIQ except that it wraps the payload in an
1029
- // Info/Query (IQ) element.
1030
- // For more information see SendIQ.
1031
- //
1032
- // SendIQElement is safe for concurrent use by multiple goroutines.
1033
- func (s * Session ) SendIQElement (ctx context.Context , payload xml.TokenReader , iq stanza.IQ ) (xmlstream.TokenReadCloser , error ) {
1034
- return s .SendIQ (ctx , iq .Wrap (payload ))
1035
- }
1036
-
1037
- // UnmarshalIQ is like SendIQ except that error replies are unmarshaled into a
1038
- // stanza.Error and returned and otherwise the response payload is unmarshaled
1039
- // into v.
1040
- // For more information see SendIQ.
1041
- //
1042
- // UnmarshalIQ is safe for concurrent use by multiple goroutines.
1043
- func (s * Session ) UnmarshalIQ (ctx context.Context , iq xml.TokenReader , v interface {}) error {
1044
- return unmarshalIQ (ctx , iq , v , s )
1045
- }
1046
-
1047
- // UnmarshalIQElement is like UnmarshalIQ but it wraps a payload in the provided IQ.
1048
- // For more information see SendIQ.
1049
- //
1050
- // UnmarshalIQElement is safe for concurrent use by multiple goroutines.
1051
- func (s * Session ) UnmarshalIQElement (ctx context.Context , payload xml.TokenReader , iq stanza.IQ , v interface {}) error {
1052
- return unmarshalIQ (ctx , iq .Wrap (payload ), v , s )
1053
- }
1054
-
1055
- // IterIQ is like SendIQ except that error replies are unmarshaled into a
1056
- // stanza.Error and returned and otherwise an iterator over the children of the
1057
- // response payload is returned.
1058
- // For more information see SendIQ.
1059
- //
1060
- // IterIQ is safe for concurrent use by multiple goroutines.
1061
- func (s * Session ) IterIQ (ctx context.Context , iq xml.TokenReader ) (* xmlstream.Iter , error ) {
1062
- return iterIQ (ctx , iq , s )
1063
- }
1064
-
1065
- // IterIQElement is like IterIQ but it wraps a payload in the provided IQ.
1066
- // For more information see SendIQ.
1067
- //
1068
- // IterIQElement is safe for concurrent use by multiple goroutines.
1069
- func (s * Session ) IterIQElement (ctx context.Context , payload xml.TokenReader , iq stanza.IQ ) (* xmlstream.Iter , error ) {
1070
- return iterIQ (ctx , iq .Wrap (payload ), s )
1071
- }
1072
-
1073
- func iterIQ (ctx context.Context , iq xml.TokenReader , s * Session ) (_ * xmlstream.Iter , e error ) {
1074
- resp , err := s .SendIQ (ctx , iq )
1075
- if err != nil {
1076
- return nil , err
1077
- }
1078
- defer func () {
1079
- if e != nil {
1080
- /* #nosec */
1081
- resp .Close ()
1082
- }
1083
- }()
1084
-
1085
- tok , err := resp .Token ()
1086
- if err != nil {
1087
- return nil , err
1088
- }
1089
- start , ok := tok .(xml.StartElement )
1090
- if ! ok {
1091
- return nil , fmt .Errorf ("stanza: expected IQ start token, got %T %[1]v" , tok )
1092
- }
1093
- _ , err = stanza .UnmarshalIQError (resp , start )
1094
- if err != nil {
1095
- return nil , err
1096
- }
1097
-
1098
- // Pop the payload start token, we want to iterate over its children.
1099
- _ , err = resp .Token ()
1100
- // Discard early EOF so that the iterator doesn't end up returning it.
1101
- if err != nil && err != io .EOF {
1102
- return nil , err
1103
- }
1104
- return xmlstream .NewIter (resp ), nil
1105
- }
1106
-
1107
- func unmarshalIQ (ctx context.Context , iq xml.TokenReader , v interface {}, s * Session ) (e error ) {
1108
- resp , err := s .SendIQ (ctx , iq )
1109
- if err != nil {
1110
- return err
1111
- }
1112
- defer func () {
1113
- ee := resp .Close ()
1114
- if e == nil {
1115
- e = ee
1116
- }
1117
- }()
1118
-
1119
- tok , err := resp .Token ()
1120
- if err != nil {
1121
- return err
1122
- }
1123
- start , ok := tok .(xml.StartElement )
1124
- if ! ok {
1125
- return fmt .Errorf ("stanza: expected IQ start token, got %T %[1]v" , tok )
1126
- }
1127
-
1128
- _ , err = stanza .UnmarshalIQError (resp , start )
1129
- if err != nil {
1130
- return err
1131
- }
1132
- d := xml .NewTokenDecoder (resp )
1133
- if v == nil {
1134
- return nil
1135
- }
1136
- return d .Decode (v )
1137
- }
1138
-
1139
944
func (s * Session ) sendResp (ctx context.Context , id string , payload xml.TokenReader , start xml.StartElement ) (xmlstream.TokenReadCloser , error ) {
1140
945
c := make (chan xmlstream.TokenReadCloser )
1141
946
0 commit comments