예제 #1
0
  @Override
  public TransformationResult getMoreData(byte opCode, boolean fin, int rsv, ByteBuffer dest)
      throws IOException {
    // Control frames are never compressed and may appear in the middle of
    // a WebSocket method. Pass them straight through.
    if (Util.isControl(opCode)) {
      return next.getMoreData(opCode, fin, rsv, dest);
    }

    if (!Util.isContinuation(opCode)) {
      // First frame in new message
      skipDecompression = (rsv & RSV_BITMASK) == 0;
    }

    // Pass uncompressed frames straight through.
    if (skipDecompression) {
      return next.getMoreData(opCode, fin, rsv, dest);
    }

    int written;
    boolean usedEomBytes = false;

    while (dest.remaining() > 0) {
      // Space available in destination. Try and fill it.
      try {
        written =
            inflater.inflate(dest.array(), dest.arrayOffset() + dest.position(), dest.remaining());
      } catch (DataFormatException e) {
        throw new IOException(sm.getString("perMessageDeflate.deflateFailed"), e);
      }
      dest.position(dest.position() + written);

      if (inflater.needsInput() && !usedEomBytes) {
        if (dest.hasRemaining()) {
          readBuffer.clear();
          TransformationResult nextResult =
              next.getMoreData(opCode, fin, (rsv ^ RSV_BITMASK), readBuffer);
          inflater.setInput(readBuffer.array(), readBuffer.arrayOffset(), readBuffer.position());
          if (TransformationResult.UNDERFLOW.equals(nextResult)) {
            return nextResult;
          } else if (TransformationResult.END_OF_FRAME.equals(nextResult)
              && readBuffer.position() == 0) {
            if (fin) {
              inflater.setInput(EOM_BYTES);
              usedEomBytes = true;
            } else {
              return TransformationResult.END_OF_FRAME;
            }
          }
        }
      } else if (written == 0) {
        if (fin && (isServer && !clientContextTakeover || !isServer && !serverContextTakeover)) {
          inflater.reset();
        }
        return TransformationResult.END_OF_FRAME;
      }
    }

    return TransformationResult.OVERFLOW;
  }
예제 #2
0
  private boolean processDataBinary() throws IOException {
    // Copy the available data to the buffer
    TransformationResult tr = transformation.getMoreData(opCode, fin, rsv, messageBufferBinary);
    while (!TransformationResult.END_OF_FRAME.equals(tr)) {
      // Frame not complete - what did we run out of?
      if (TransformationResult.UNDERFLOW.equals(tr)) {
        // Ran out of input data - get some more
        return false;
      }

      // Ran out of message buffer - flush it
      if (!usePartial()) {
        CloseReason cr =
            new CloseReason(
                CloseCodes.TOO_BIG,
                sm.getString(
                    "wsFrame.bufferTooSmall",
                    Integer.valueOf(messageBufferBinary.capacity()),
                    Long.valueOf(payloadLength)));
        throw new WsIOException(cr);
      }
      messageBufferBinary.flip();
      ByteBuffer copy = ByteBuffer.allocate(messageBufferBinary.limit());
      copy.put(messageBufferBinary);
      copy.flip();
      sendMessageBinary(copy, false);
      messageBufferBinary.clear();
      // Read more data
      tr = transformation.getMoreData(opCode, fin, rsv, messageBufferBinary);
    }

    // Frame is fully received
    // Send the message if either:
    // - partial messages are supported
    // - the message is complete
    if (usePartial() || !continuationExpected) {
      messageBufferBinary.flip();
      ByteBuffer copy = ByteBuffer.allocate(messageBufferBinary.limit());
      copy.put(messageBufferBinary);
      copy.flip();
      sendMessageBinary(copy, !continuationExpected);
      messageBufferBinary.clear();
    }

    if (continuationExpected) {
      // More data for this message expected, start a new frame
      newFrame();
    } else {
      // Message is complete, start a new message
      newMessage();
    }

    return true;
  }
예제 #3
0
  private boolean processDataControl() throws IOException {
    TransformationResult tr = transformation.getMoreData(opCode, fin, rsv, controlBufferBinary);
    if (TransformationResult.UNDERFLOW.equals(tr)) {
      return false;
    }
    // Control messages have fixed message size so
    // TransformationResult.OVERFLOW is not possible here

    controlBufferBinary.flip();
    if (opCode == Constants.OPCODE_CLOSE) {
      open = false;
      String reason = null;
      int code = CloseCodes.NORMAL_CLOSURE.getCode();
      if (controlBufferBinary.remaining() == 1) {
        controlBufferBinary.clear();
        // Payload must be zero or greater than 2
        throw new WsIOException(
            new CloseReason(CloseCodes.PROTOCOL_ERROR, sm.getString("wsFrame.oneByteCloseCode")));
      }
      if (controlBufferBinary.remaining() > 1) {
        code = controlBufferBinary.getShort();
        if (controlBufferBinary.remaining() > 0) {
          CoderResult cr = utf8DecoderControl.decode(controlBufferBinary, controlBufferText, true);
          if (cr.isError()) {
            controlBufferBinary.clear();
            controlBufferText.clear();
            throw new WsIOException(
                new CloseReason(
                    CloseCodes.PROTOCOL_ERROR, sm.getString("wsFrame.invalidUtf8Close")));
          }
          // There will be no overflow as the output buffer is big
          // enough. There will be no underflow as all the data is
          // passed to the decoder in a single call.
          controlBufferText.flip();
          reason = controlBufferText.toString();
        }
      }
      wsSession.onClose(new CloseReason(Util.getCloseCode(code), reason));
    } else if (opCode == Constants.OPCODE_PING) {
      if (wsSession.isOpen()) {
        wsSession.getBasicRemote().sendPong(controlBufferBinary);
      }
    } else if (opCode == Constants.OPCODE_PONG) {
      MessageHandler.Whole<PongMessage> mhPong = wsSession.getPongMessageHandler();
      if (mhPong != null) {
        try {
          mhPong.onMessage(new WsPongMessage(controlBufferBinary));
        } catch (Throwable t) {
          handleThrowableOnSend(t);
        } finally {
          controlBufferBinary.clear();
        }
      }
    } else {
      // Should have caught this earlier but just in case...
      controlBufferBinary.clear();
      throw new WsIOException(
          new CloseReason(
              CloseCodes.PROTOCOL_ERROR,
              sm.getString("wsFrame.invalidOpCode", Integer.valueOf(opCode))));
    }
    controlBufferBinary.clear();
    newFrame();
    return true;
  }