1d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/**
2d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * $RCSfile$
3d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * $Revision$
4d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * $Date$
5d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen *
6d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Copyright 2009 Jive Software.
7d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen *
8d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
9d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * you may not use this file except in compliance with the License.
10d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * You may obtain a copy of the License at
11d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen *
12d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen *     http://www.apache.org/licenses/LICENSE-2.0
13d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen *
14d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Unless required by applicable law or agreed to in writing, software
15d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * distributed under the License is distributed on an "AS IS" BASIS,
16d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * See the License for the specific language governing permissions and
18d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * limitations under the License.
19d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */
20d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
21d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpackage org.jivesoftware.smack;
22d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
23d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.io.StringReader;
24d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
25d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smack.util.PacketParserUtils;
26d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smack.sasl.SASLMechanism.Challenge;
27d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smack.sasl.SASLMechanism.Failure;
28d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smack.sasl.SASLMechanism.Success;
29d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.xmlpull.v1.XmlPullParserFactory;
30d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.xmlpull.v1.XmlPullParser;
31d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
32d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport com.kenai.jbosh.AbstractBody;
33d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport com.kenai.jbosh.BOSHClientResponseListener;
34d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport com.kenai.jbosh.BOSHMessageEvent;
35d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport com.kenai.jbosh.BodyQName;
36d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport com.kenai.jbosh.ComposableBody;
37d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
38d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/**
39d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Listens for XML traffic from the BOSH connection manager and parses it into
40d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * packet objects.
41d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen *
42d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @author Guenther Niess
43d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */
44d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpublic class BOSHPacketReader implements BOSHClientResponseListener {
45d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
46d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    private BOSHConnection connection;
47d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
48d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
49d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Create a packet reader which listen on a BOSHConnection for received
50d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * HTTP responses, parse the packets and notifies the connection.
51d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
52d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param connection the corresponding connection for the received packets.
53d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
54d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public BOSHPacketReader(BOSHConnection connection) {
55d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        this.connection = connection;
56d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
57d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
58d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
59d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Parse the received packets and notify the corresponding connection.
60d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
61d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param event the BOSH client response which includes the received packet.
62d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
63d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public void responseReceived(BOSHMessageEvent event) {
64d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        AbstractBody body = event.getBody();
65d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (body != null) {
66d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            try {
67d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                if (connection.sessionID == null) {
68d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    connection.sessionID = body.getAttribute(BodyQName.create(BOSHConnection.BOSH_URI, "sid"));
69d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                }
70d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                if (connection.authID == null) {
71d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    connection.authID = body.getAttribute(BodyQName.create(BOSHConnection.BOSH_URI, "authid"));
72d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                }
73d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                final XmlPullParser parser = XmlPullParserFactory.newInstance().newPullParser();
74d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES,
75d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        true);
76d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                parser.setInput(new StringReader(body.toXML()));
77d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                int eventType = parser.getEventType();
78d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                do {
79d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    eventType = parser.next();
80d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    if (eventType == XmlPullParser.START_TAG) {
81d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        if (parser.getName().equals("body")) {
82d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                            // ignore the container root element
83d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        } else if (parser.getName().equals("message")) {
84d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                            connection.processPacket(PacketParserUtils.parseMessage(parser));
85d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        } else if (parser.getName().equals("iq")) {
86d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                            connection.processPacket(PacketParserUtils.parseIQ(parser, connection));
87d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        } else if (parser.getName().equals("presence")) {
88d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                            connection.processPacket(PacketParserUtils.parsePresence(parser));
89d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        } else if (parser.getName().equals("challenge")) {
90d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                            // The server is challenging the SASL authentication
91d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                            // made by the client
92d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                            final String challengeData = parser.nextText();
93d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                            connection.getSASLAuthentication()
94d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                                    .challengeReceived(challengeData);
95d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                            connection.processPacket(new Challenge(
96d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                                    challengeData));
97d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        } else if (parser.getName().equals("success")) {
98d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                            connection.send(ComposableBody.builder()
99d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                                    .setNamespaceDefinition("xmpp", BOSHConnection.XMPP_BOSH_NS)
100d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                                    .setAttribute(
101d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                                            BodyQName.createWithPrefix(BOSHConnection.XMPP_BOSH_NS, "restart", "xmpp"),
102d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                                            "true")
103d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                                    .setAttribute(
104d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                                            BodyQName.create(BOSHConnection.BOSH_URI, "to"),
105d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                                            connection.getServiceName())
106d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                                    .build());
107d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                            connection.getSASLAuthentication().authenticated();
108d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                            connection.processPacket(new Success(parser.nextText()));
109d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        } else if (parser.getName().equals("features")) {
110d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                            parseFeatures(parser);
111d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        } else if (parser.getName().equals("failure")) {
112d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                            if ("urn:ietf:params:xml:ns:xmpp-sasl".equals(parser.getNamespace(null))) {
113d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                                final Failure failure = PacketParserUtils.parseSASLFailure(parser);
114d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                                connection.getSASLAuthentication().authenticationFailed();
115d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                                connection.processPacket(failure);
116d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                            }
117d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        } else if (parser.getName().equals("error")) {
118d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                            throw new XMPPException(PacketParserUtils.parseStreamError(parser));
119d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        }
120d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    }
121d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                } while (eventType != XmlPullParser.END_DOCUMENT);
122d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            }
123d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            catch (Exception e) {
124d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                if (connection.isConnected()) {
125d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    connection.notifyConnectionError(e);
126d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                }
127d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            }
128d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
129d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
130d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
131d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
132d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Parse and setup the XML stream features.
133d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
134d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param parser the XML parser, positioned at the start of a message packet.
135d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @throws Exception if an exception occurs while parsing the packet.
136d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
137d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    private void parseFeatures(XmlPullParser parser) throws Exception {
138d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        boolean done = false;
139d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        while (!done) {
140d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            int eventType = parser.next();
141d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
142d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            if (eventType == XmlPullParser.START_TAG) {
143d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                if (parser.getName().equals("mechanisms")) {
144d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    // The server is reporting available SASL mechanisms. Store
145d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    // this information
146d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    // which will be used later while logging (i.e.
147d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    // authenticating) into
148d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    // the server
149d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    connection.getSASLAuthentication().setAvailableSASLMethods(
150d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                            PacketParserUtils.parseMechanisms(parser));
151d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                } else if (parser.getName().equals("bind")) {
152d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    // The server requires the client to bind a resource to the
153d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    // stream
154d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    connection.getSASLAuthentication().bindingRequired();
155d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                } else if (parser.getName().equals("session")) {
156d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    // The server supports sessions
157d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    connection.getSASLAuthentication().sessionsSupported();
158d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                } else if (parser.getName().equals("register")) {
159d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    connection.getAccountManager().setSupportsAccountCreation(
160d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                            true);
161d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                }
162d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            } else if (eventType == XmlPullParser.END_TAG) {
163d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                if (parser.getName().equals("features")) {
164d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    done = true;
165d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                }
166d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            }
167d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
168d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
169d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
170