StreamError.java

  1. /**
  2.  *
  3.  * Copyright 2003-2005 Jive Software.
  4.  *
  5.  * Licensed under the Apache License, Version 2.0 (the "License");
  6.  * you may not use this file except in compliance with the License.
  7.  * You may obtain a copy of the License at
  8.  *
  9.  *     http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */

  17. package org.jivesoftware.smack.packet;

  18. import java.util.List;
  19. import java.util.Map;

  20. import org.jivesoftware.smack.util.StringUtils;
  21. import org.jivesoftware.smack.util.XmlStringBuilder;

  22. /**
  23.  * Represents a stream error packet. Stream errors are unrecoverable errors where the server
  24.  * will close the underlying TCP connection after the stream error was sent to the client.
  25.  * These is the list of stream errors as defined in the XMPP spec:
  26.  *
  27.  * <table border=1>
  28.  *      <caption>Stream Errors</caption>
  29.  *      <tr><td><b>Code</b></td><td><b>Description</b></td></tr>
  30.  *      <tr><td> bad-format </td><td> the entity has sent XML that cannot be processed </td></tr>
  31.  *      <tr><td> unsupported-encoding </td><td>  the entity has sent a namespace prefix that is
  32.  *          unsupported </td></tr>
  33.  *      <tr><td> bad-namespace-prefix </td><td> Remote Server Timeout </td></tr>
  34.  *      <tr><td> conflict </td><td> the server is closing the active stream for this entity
  35.  *          because a new stream has been initiated that conflicts with the existing
  36.  *          stream. </td></tr>
  37.  *      <tr><td> connection-timeout </td><td> the entity has not generated any traffic over
  38.  *          the stream for some period of time. </td></tr>
  39.  *      <tr><td> host-gone </td><td> the value of the 'to' attribute provided by the initiating
  40.  *          entity in the stream header corresponds to a hostname that is no longer hosted by
  41.  *          the server. </td></tr>
  42.  *      <tr><td> host-unknown </td><td> the value of the 'to' attribute provided by the
  43.  *          initiating entity in the stream header does not correspond to a hostname that is
  44.  *          hosted by the server. </td></tr>
  45.  *      <tr><td> improper-addressing </td><td> a stanza sent between two servers lacks a 'to'
  46.  *          or 'from' attribute </td></tr>
  47.  *      <tr><td> internal-server-error </td><td> the server has experienced a
  48.  *          misconfiguration. </td></tr>
  49.  *      <tr><td> invalid-from </td><td> the JID or hostname provided in a 'from' address does
  50.  *          not match an authorized JID. </td></tr>
  51.  *      <tr><td> invalid-namespace </td><td> the streams namespace name is invalid. </td></tr>
  52.  *      <tr><td> invalid-xml </td><td> the entity has sent invalid XML over the stream. </td></tr>
  53.  *      <tr><td> not-authorized </td><td> the entity has attempted to send data before the
  54.  *          stream has been authenticated </td></tr>
  55.  *      <tr><td> policy-violation </td><td> the entity has violated some local service
  56.  *          policy. </td></tr>
  57.  *      <tr><td> remote-connection-failed </td><td> the server is unable to properly connect
  58.  *          to a remote entity. </td></tr>
  59.  *      <tr><td> resource-constraint </td><td> the server lacks the system resources necessary
  60.  *          to service the stream. </td></tr>
  61.  *      <tr><td> restricted-xml </td><td> the entity has attempted to send restricted XML
  62.  *          features. </td></tr>
  63.  *      <tr><td> see-other-host </td><td>  the server will not provide service to the initiating
  64.  *          entity but is redirecting traffic to another host. </td></tr>
  65.  *      <tr><td> system-shutdown </td><td> the server is being shut down and all active streams
  66.  *          are being closed. </td></tr>
  67.  *      <tr><td> undefined-condition </td><td> the error condition is not one of those defined
  68.  *          by the other conditions in this list. </td></tr>
  69.  *      <tr><td> unsupported-encoding </td><td> the initiating entity has encoded the stream in
  70.  *          an encoding that is not supported. </td></tr>
  71.  *      <tr><td> unsupported-stanza-type </td><td> the initiating entity has sent a first-level
  72.  *          child of the stream that is not supported. </td></tr>
  73.  *      <tr><td> unsupported-version </td><td> the value of the 'version' attribute provided by
  74.  *          the initiating entity in the stream header specifies a version of XMPP that is not
  75.  *          supported. </td></tr>
  76.  *      <tr><td> not-well-formed </td><td> the initiating entity has sent XML that is not
  77.  *          well-formed. </td></tr>
  78.  * </table>
  79.  * <p>
  80.  * Stream error syntax:
  81.  * <pre>
  82.  * {@code
  83.  * <stream:error>
  84.  *   <defined-condition xmlns='urn:ietf:params:xml:ns:xmpp-streams'/>
  85.  *   [<text xmlns='urn:ietf:params:xml:ns:xmpp-streams'
  86.  *      xml:lang='langcode'>
  87.  *   OPTIONAL descriptive text
  88.  *   </text>]
  89.  *   [OPTIONAL application-specific condition element]
  90.  * </stream:error>
  91.  * }
  92.  * </pre>
  93.  *
  94.  * @author Gaston Dombiak
  95.  */
  96. public class StreamError extends AbstractError implements Nonza {

  97.     public static final String ELEMENT = "stream:error";
  98.     public static final String NAMESPACE = "urn:ietf:params:xml:ns:xmpp-streams";

  99.     private final Condition condition;
  100.     private final String conditionText;

  101.     public StreamError(Condition condition, String conditionText, Map<String, String> descriptiveTexts, List<XmlElement> extensions) {
  102.         super(descriptiveTexts, extensions);
  103.         // Some implementations may send the condition as non-empty element containing the empty string, that is
  104.         // <condition xmlns='foo'></condition>, in this case the parser may calls this constructor with the empty string
  105.         // as conditionText, therefore reset it to null if it's the empty string
  106.         if (StringUtils.isNullOrEmpty(conditionText)) {
  107.             conditionText = null;
  108.         }
  109.         if (conditionText != null) {
  110.             switch (condition) {
  111.             case see_other_host:
  112.                 break;
  113.             default:
  114.                 throw new IllegalArgumentException("The given condition '" + condition
  115.                                 + "' can not contain a conditionText");
  116.             }
  117.         }
  118.         this.condition = condition;
  119.         this.conditionText = conditionText;
  120.     }

  121.     public Condition getCondition() {
  122.         return condition;
  123.     }

  124.     public String getConditionText() {
  125.         return conditionText;
  126.     }

  127.     @Override
  128.     public String toString() {
  129.         return toXML().toString();
  130.     }

  131.     @Override
  132.     public XmlStringBuilder toXML(org.jivesoftware.smack.packet.XmlEnvironment enclosingNamespace) {
  133.         XmlStringBuilder xml = new XmlStringBuilder();
  134.         xml.openElement(ELEMENT);
  135.         xml.halfOpenElement(condition.toString()).xmlnsAttribute(NAMESPACE).closeEmptyElement();
  136.         addDescriptiveTextsAndExtensions(xml);
  137.         xml.closeElement(ELEMENT);
  138.         return xml;
  139.     }

  140.     /**
  141.      * The defined stream error conditions, see RFC 6120 ยง 4.9.3.
  142.      *
  143.      */
  144.     public enum Condition {
  145.         bad_format,
  146.         bad_namespace_prefix,
  147.         conflict,
  148.         connection_timeout,
  149.         host_gone,
  150.         host_unknown,
  151.         improper_addressing,
  152.         internal_server_error,
  153.         invalid_from,
  154.         invalid_namespace,
  155.         invalid_xml,
  156.         not_authorized,
  157.         not_well_formed,
  158.         policy_violation,
  159.         remote_connection_failed,
  160.         reset,
  161.         resource_constraint,
  162.         restricted_xml,
  163.         see_other_host,
  164.         system_shutdown,
  165.         undefined_condition,
  166.         unsupported_encoding,
  167.         unsupported_feature,
  168.         unsupported_stanza_type,
  169.         unsupported_version;

  170.         @Override
  171.         public String toString() {
  172.             return this.name().replace('_', '-');
  173.         }

  174.         public static Condition fromString(String string) {
  175.             // Backwards compatibility for older implementations still using RFC 3920. RFC 6120
  176.             // changed 'xml-not-well-formed' to 'not-well-formed'.
  177.             if ("xml-not-well-formed".equals(string)) {
  178.                 string = "not-well-formed";
  179.             }
  180.             string = string.replace('-', '_');
  181.             Condition condition = null;
  182.             try {
  183.                 condition = Condition.valueOf(string);
  184.             } catch (Exception e) {
  185.                 throw new IllegalStateException("Could not transform string '" + string
  186.                                 + "' to XMPPErrorCondition", e);
  187.             }
  188.             return condition;
  189.         }
  190.     }

  191.     @Override
  192.     public String getNamespace() {
  193.         return NAMESPACE;
  194.     }

  195.     @Override
  196.     public String getElementName() {
  197.         return ELEMENT;
  198.     }
  199. }