예제 #1
0
  /**
   * The <body/> element of every client request MUST possess a sequential request ID encapsulated
   * via the 'rid' attribute.
   *
   * @param node node to validate
   * @param previous previous node
   */
  private void assertRequestIDSequential(final Node node, final Node previous) {
    String ridStr = node.getBody().getAttribute(Attributes.RID);
    assertNotNull("Request ID attribute not present", ridStr);

    long rid = Long.parseLong(ridStr);
    if (previous != null) {
      String prevRidStr = previous.getBody().getAttribute(Attributes.RID);
      assertNotNull("Previous request ID attribute not present", prevRidStr);
      long prevRid = Long.parseLong(prevRidStr);
      assertEquals("Request ID is not sequential", prevRid + 1, rid);
    }
  }
예제 #2
0
 /**
  * If the client will be including 'ack' attributes on requests during a session, then it MUST
  * include an 'ack' attribute (set to '1') in its session creation request, and set the 'ack'
  * attribute of requests throughout the session.
  *
  * @param idx message number (zero-based)
  * @param first first message sent
  * @param request message to validate
  */
 private void validateSubsequestRequestAck(final int idx, final Node first, final Node request) {
   if (request == first) {
     // Nothing to check on first request
     return;
   }
   String ack = first.getBody().getAttribute(Attributes.ACK);
   if (ack == null) {
     String subAck = request.getBody().getAttribute(Attributes.ACK);
     assertNull(
         "subsequent request #"
             + idx
             + " can only use acks if "
             + "advertized in session creation request",
         subAck);
   }
 }
예제 #3
0
 /**
  * The <body/> element of the first request SHOULD possess the following attributes (they SHOULD
  * NOT be included in any other requests except as specified under Adding Streams To A Session):
  * "to", "xml:lang", "ver", "wait", "hold".
  *
  * @param message number (zero-based)
  * @param request request message
  * @param previous previous request message
  */
 private void validateRequestHeaders(final int idx, final Node request, final Node previous) {
   AbstractBody body = request.getBody();
   if (previous == null) {
     // session creation request
     assertNotNull(
         "to attribute not present in request #" + idx, body.getAttribute(Attributes.TO));
     assertNotNull(
         "xml:lang attribute not present in request #" + idx,
         body.getAttribute(Attributes.XML_LANG));
     assertNotNull(
         "ver attribute not present in request #" + idx, body.getAttribute(Attributes.VER));
     assertNotNull(
         "wait attribute not present in request #" + idx, body.getAttribute(Attributes.WAIT));
     assertNotNull(
         "hold attribute not present in request #" + idx, body.getAttribute(Attributes.HOLD));
   } else {
     // subsequent request
     assertNull("to attribute was present in request #" + idx, body.getAttribute(Attributes.TO));
     assertNull(
         "xml:lang attribute was present in request #" + idx,
         body.getAttribute(Attributes.XML_LANG));
     assertNull("ver attribute was present in request #" + idx, body.getAttribute(Attributes.VER));
     assertNull(
         "wait attribute was present in request #" + idx, body.getAttribute(Attributes.WAIT));
     assertNull(
         "hold attribute was present in request #" + idx, body.getAttribute(Attributes.HOLD));
   }
 }
예제 #4
0
 /**
  * Validate a request.
  *
  * @param message number (zero-based)
  * @param first message sent
  * @param previous previous request, or {@code null} if this is the first request ever sent
  * @param request request message
  */
 private void validateRequest(
     final int idx, final Node first, final Node previous, final Node request) {
   try {
     assertValidXML(request);
     assertSingleBodyElement(request);
     assertNoComments(request);
     assertNoProcessingInstructions(request);
     assertRequestIDSequential(request, previous);
     if (previous == null) {
       validateRequestHeaders(idx, request, previous);
       assertSessionCreationRequestID(request);
       assertSessionCreationRequestIDRange(request);
       validateSessionCreationAck(idx, request);
       validateSessionCreationSID(idx, request);
       validateSessionCreationHold(idx, request);
     } else {
       validateRequestHeaders(idx, request, previous);
       validateSubsequentRequestSID(idx, request);
       validateSubsequestRequestAck(idx, first, request);
       validateSubsequentPause(idx, request, previous);
     }
   } catch (AssertionError err) {
     LOG.info(
         "Assertion failed for request #"
             + idx
             + ": "
             + err.getMessage()
             + "\n"
             + request.getBody().toXML());
     throw (err);
   }
 }
예제 #5
0
  /*
   * The client MUST generate a large, random, positive integer for the
   * initial 'rid' (see Security Considerations) and then increment that
   * value by one for each subsequent request.
   *
   * @param node node to validate
   */
  private void assertSessionCreationRequestID(final Node node) {
    String ridStr = node.getBody().getAttribute(Attributes.RID);
    assertNotNull("Request ID attribute not present", ridStr);

    long rid = Long.parseLong(ridStr);
    assertTrue("RID was <= 0", rid > 0);

    // Not checking to see if it is "large" since it is already random
  }
예제 #6
0
  /**
   * If the connection manager did not specify a 'maxpause' attribute at the start of the session
   * then the client MUST NOT send a 'pause' attribute during the session.
   *
   * @param idx message number (zero-based)
   * @param request message to validate
   */
  private void validateSubsequentPause(final int idx, final Node request, final Node previous) {
    AbstractBody scr = sessionCreationResponse.get();
    if (scr == null) {
      // Not checking this
      return;
    }

    try {
      // Check the current node:
      AttrPause pause =
          AttrPause.createFromString(request.getBody().getAttribute(Attributes.PAUSE));
      if (pause != null) {
        AttrMaxPause maxPause =
            AttrMaxPause.createFromString(scr.getAttribute(Attributes.MAXPAUSE));
        assertNotNull(
            "Request #"
                + idx
                + " can only use pause when "
                + "advertized in session creation response",
            maxPause);
        assertTrue(pause.intValue() < maxPause.intValue());
      }

      // Check the previous node
      AttrPause prevPause =
          AttrPause.createFromString(previous.getBody().getAttribute(Attributes.PAUSE));
      if (prevPause != null) {
        long delta = request.getTime() - previous.getTime();
        if (delta > prevPause.getInMilliseconds()) {
          fail(
              "Request #"
                  + idx
                  + " was sent too late relative to "
                  + "the previous pause message (delta="
                  + delta
                  + ", pause="
                  + prevPause.getInMilliseconds()
                  + ")");
        }
      }
    } catch (BOSHException boshx) {
      fail("Could not parse pause/maxpause: " + boshx.getMessage());
    }
  }
예제 #7
0
 /*
  * The client MUST take care to choose an initial 'rid' that will never be
  * incremented above 9007199254740991 [21] within the session.
  *
  * @param node node to validate
  */
 private void assertSessionCreationRequestIDRange(final Node node) {
   String ridStr = node.getBody().getAttribute(Attributes.RID);
   long rid = Long.parseLong(ridStr);
   BigInteger biRID = BigInteger.valueOf(rid);
   BigInteger biMax = new BigInteger("9007199254740991");
   BigInteger biThreshold = BigInteger.valueOf(Math.round(Math.pow(2.0, 20.0)));
   assertTrue(
       "Initial RID leaves fewer than "
           + biThreshold.toString()
           + " total requests before max RID limit is hit",
       biRID.compareTo(biMax.subtract(biThreshold)) <= 0);
 }
예제 #8
0
 /**
  * XEP-0124 Section 6:
  *
  * <p>The <body/> element and its content together MUST conform to the specifications set out in
  * XML 1.0 [14]
  *
  * <p>and...
  *
  * <p>They SHOULD also conform to Namespaces in XML [15].
  *
  * <p>and...
  *
  * <p>The content MUST NOT contain Partial XML elements.
  *
  * @param request request to validate
  */
 private void assertValidXML(final Node request) {
   ByteArrayInputStream stream = new ByteArrayInputStream(request.getBody().toXML().getBytes());
   StreamSource source = new StreamSource(stream);
   Throwable thr;
   try {
     synchronized (VALIDATOR) {
       VALIDATOR.validate(source);
     }
     return;
   } catch (IOException iox) {
     thr = iox;
   } catch (SAXException saxx) {
     thr = saxx;
   }
   fail("Request XML validation failed: " + thr.getMessage());
 }
예제 #9
0
  /**
   * Checks that the validator didn't encounter any problems. If it did, it should perform the
   * assertions here.
   *
   * @param scr session creation response message to use in validation, or {@code null} to skip
   *     those checks
   */
  public void checkAssertions(final AbstractBody scr) {
    if (requests == null) {
      // Nothing to validate.
      LOG.fine("Nothing to validate");
      return;
    }
    sessionCreationResponse.set(scr);
    LOG.fine("Validating " + requests.size() + " message(s)");
    Node previous = null;
    Node first = null;
    int index = 0;
    for (Node node : requests) {
      if (first == null) {
        first = node;
      }

      String rid = node.getBody().getAttribute(Attributes.RID);
      LOG.fine("Validating msg #" + index + " (RID: " + rid + ")");
      validateRequest(index, first, previous, node);
      previous = node;
      index++;
    }
  }
예제 #10
0
  /**
   * Execute an XPath against a AbstractBody instance.
   *
   * @param body node with body to XPath against
   * @param xpath the XPath expression
   * @param returnType type to return
   * @return resulting node
   */
  private Object bodyXPath(final Node node, final String xpath, final QName returnType) {
    try {
      String xml = node.getBody().toXML();
      ByteArrayInputStream stream = new ByteArrayInputStream(xml.getBytes());
      DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
      factory.setNamespaceAware(true);
      DocumentBuilder builder = factory.newDocumentBuilder();
      Document document = builder.parse(stream);
      XPathFactory xpf = XPathFactory.newInstance();
      XPath xp = xpf.newXPath();
      xp.setNamespaceContext(
          new NamespaceContext() {
            Map<String, String> map = new HashMap<String, String>();

            {
              map.put("bosh", BodyQName.BOSH_NS_URI);
              map.put("xml", XMLConstants.XML_NS_URI);
            }

            public String getNamespaceURI(String prefix) {
              return map.get(prefix);
            }

            public String getPrefix(String namespaceURI) {
              throw new UnsupportedOperationException("Not supported.");
            }

            public Iterator getPrefixes(String namespaceURI) {
              throw new UnsupportedOperationException("Not supported.");
            }
          });
      return xp.evaluate(xpath, document, returnType);
    } catch (Throwable thr) {
      fail("Could not parse body to DOM document: " + thr.getMessage());
    }
    return null;
  }
예제 #11
0
 /**
  * All requests after the first one MUST include a valid 'sid' attribute.
  *
  * @param message number (zero-based)
  * @param request request message
  * @param previous previous request, or {@code null} if this is the first request ever sent
  */
 private void validateSubsequentRequestSID(final int idx, final Node request) {
   assertNotNull(
       "sid attribute not present in request #" + idx,
       request.getBody().getAttribute(Attributes.SID));
 }
예제 #12
0
 /**
  * If the client is not able to use HTTP Pipelining then the "hold" attribute SHOULD be set to
  * "1".
  *
  * @param message number (zero-based)
  * @param request request message
  */
 private void validateSessionCreationHold(final int idx, final Node request) {
   String hold = request.getBody().getAttribute(Attributes.HOLD);
   assertNotNull("hold attribute was not present in initial request", hold);
   assertEquals("incorrect hold attrivute value", "1", hold);
 }
예제 #13
0
 /**
  * A client MAY include an 'ack' attribute (set to "1") to indicate that it will be using
  * acknowledgements throughout the session If the client will be including 'ack' attributes on
  * requests during a session, then it MUST include an 'ack' attribute (set to '1') in its session
  * creation request, and set the 'ack' attribute of requests throughout the session.
  *
  * @param message number (zero-based)
  * @param request request message
  */
 private void validateSessionCreationAck(final int idx, final Node request) {
   String ack = request.getBody().getAttribute(Attributes.ACK);
   if (ack != null) {
     assertEquals("intial ack must be 1", "1", ack);
   }
 }
예제 #14
0
 /**
  * The initialization request is unique in that the <body/> element MUST NOT possess a 'sid'
  * attribute.
  *
  * @param message number (zero-based)
  * @param request request message
  */
 private void validateSessionCreationSID(final int idx, final Node request) {
   assertNull(
       "sid attribute was present in request #" + idx,
       request.getBody().getAttribute(Attributes.SID));
 }