/** @see java.io.InputStream#read(byte[], int, int) */
  public int read(final byte b[], final int off, final int len) throws IOException {
    if (LOGGER.isLoggable(LOGGER_LEVEL)) {
      log(
          "InputBuffer %s read byte array of len: %s. Ready content: %s",
          this, len, inputContentBuffer);
    }

    if (closed) {
      throw new IOException();
    }

    if (len == 0) {
      return 0;
    }
    if (!inputContentBuffer.hasRemaining()) {
      if (fill(1) == -1) {
        return -1;
      }
    }

    int nlen = Math.min(inputContentBuffer.remaining(), len);
    inputContentBuffer.get(b, off, nlen);

    if (!checkMarkAfterRead(nlen)) {
      inputContentBuffer.shrink();
    }

    return nlen;
  }
示例#2
0
  @Test
  public void testFormParameters() throws Exception {
    final Map<String, String[]> patternMap = new HashMap<String, String[]>();
    patternMap.put("title", new String[] {"Developing PaaS Components"});
    patternMap.put("authors", new String[] {"Shalini M"});
    patternMap.put("price", new String[] {"100$"});

    final NetworkListener listener = httpServer.getListener(LISTENER_NAME);

    startHttpServer(
        new HttpHandler() {

          @Override
          public void service(Request request, Response response) throws Exception {
            final Map<String, String[]> paramMap = request.getParameterMap();
            boolean isOk = paramMap.size() == patternMap.size();

            if (isOk) {
              // if sizes are equal - compare content
              for (Map.Entry<String, String[]> patternEntry : patternMap.entrySet()) {
                final String key = patternEntry.getKey();
                final String[] value = patternEntry.getValue();
                isOk = paramMap.containsKey(key) && Arrays.equals(value, paramMap.get(key));

                if (!isOk) break;
              }
            }

            if (isOk) {
              response.setStatus(200, "FINE");
            } else {
              response.setStatus(500, "Attributes don't match");
            }
          }
        },
        "/bookstore/BookStoreServlet");

    final MemoryManager mm = listener.getTransport().getMemoryManager();
    final Buffer requestPart1 =
        Buffers.wrap(mm, Utils.loadResourceFile("form-params-payload1.dat"));
    final Buffer requestPart2 =
        Buffers.wrap(mm, Utils.loadResourceFile("form-params-payload2.dat"));

    Buffer responseBuffer =
        send("localhost", PORT, Buffers.appendBuffers(mm, requestPart1, requestPart2))
            .get(10, TimeUnit.SECONDS);

    // Successful response length is 37 bytes.  This includes the status
    // line and a content-length
    boolean isFailure = responseBuffer.remaining() != 37;

    if (isFailure) {
      byte[] response = new byte[responseBuffer.remaining()];
      responseBuffer.get(response);
      String hex = toHexString(response);
      fail("unexpected response length=" + response.length + " content=[" + hex + "]");
    }
  }
 /** {@inheritDoc} */
 @Override
 public byte[] getResponseBodyAsBytes() throws IOException {
   final Buffer responseBody = getResponseBody0();
   final byte[] responseBodyBytes = new byte[responseBody.remaining()];
   final int origPos = responseBody.position();
   responseBody.get(responseBodyBytes);
   responseBody.position(origPos);
   return responseBodyBytes;
 }
  static void decodeRequest(
      final Buffer requestContent, final AjpHttpRequest req, final boolean tomcatAuthentication)
      throws IOException {
    // FORWARD_REQUEST handler

    int offset = requestContent.position();

    // Translate the HTTP method code to a String.
    byte methodCode = requestContent.get(offset++);
    if (methodCode != AjpConstants.SC_M_JK_STORED) {
      String mName = AjpConstants.methodTransArray[(int) methodCode - 1];
      req.getMethodDC().setString(mName);
    }

    offset = getBytesToDataChunk(requestContent, offset, req.getProtocolDC());
    final int requestURILen = readShort(requestContent, offset);
    if (!isNullLength(requestURILen)) {
      req.getRequestURIRef().init(requestContent, offset + 2, offset + 2 + requestURILen);
    }
    // Don't forget to skip the terminating \0 (that's why "+ 1")
    offset += 2 + requestURILen + 1;

    offset = getBytesToDataChunk(requestContent, offset, req.remoteAddr());

    offset = getBytesToDataChunk(requestContent, offset, req.remoteHostRaw());

    offset = getBytesToDataChunk(requestContent, offset, req.localName());

    req.setLocalPort(readShort(requestContent, offset));
    offset += 2;

    final boolean isSSL = requestContent.get(offset++) != 0;
    req.setSecure(isSSL);
    req.getResponse().setSecure(isSSL);

    offset = decodeHeaders(requestContent, offset, req);

    decodeAttributes(requestContent, offset, req, tomcatAuthentication);

    req.setUnparsedHostHeader(req.getHeaders().getValue("host"));
  }
示例#5
0
 /*
  * 接收
  *
  * @param context 上下文
  * @param channel 通道
  * @param buffer 缓存
  * @param readable 缓存可读
  * @param bytes 输入缓存
  * @param offset 指向已读数据的偏移量,off之前的数据都是已用过的
  * @param limit 有效长度,limit之后的长度是空白或无效数据,off到limit之间的数据是准备使用的数据
  * @return 后续动作
  * @throws IOException
  */
 private NextAction receive(
     FilterChainContext context,
     Channel channel,
     Buffer buffer,
     int readable,
     byte[] bytes,
     int offset,
     int limit)
     throws IOException {
   for (; ; ) {
     int read = Math.min(readable, bytes.length - limit); // 取bytes缓存空闲区,和可读取新数据,的最小值,即:此次最多读写数据的大小
     buffer.get(bytes, limit, read); // 从可读取新数据中,读取数据,尽量填满bytes缓存空闲区
     limit += read; // 有效数据变长
     readable -= read; // 可读数据变少
     UnsafeByteArrayInputStream input =
         new UnsafeByteArrayInputStream(
             bytes, offset, limit - offset); // 将bytes缓存转成InputStream,不需要关闭
     Object msg = upstreamCodec.decode(channel, input); // 调用Codec接口,解码数据
     if (msg == Codec.NEED_MORE_INPUT) { // 如果Codec觉得数据不够,不足以解码成一个对象
       if (readable == 0) { // 如果没有更多可读数据
         channel.setAttribute(
             BUFFER_KEY, new Object[] {bytes, offset, limit}); // 放入通道属性中,等待下一个Buffer的到来
         return context.getStopAction();
       } else { // 扩充或挪出空闲区,并循环,直到可读数据都加载到bytes缓存
         if (offset == 0) { // 如果bytes缓存全部没有被使用,如果这时数据还不够
           bytes = Bytes.copyOf(bytes, bytes.length << 1); // 将bytes缓存扩大一倍
         } else { // 如果bytes缓存有一段数据已被使用
           int len = limit - offset; // 计算有效数据长度
           System.arraycopy(
               bytes, offset, bytes, 0, len); // 将数据向前移到,压缩到已使用的部分,这样limit后面就会多出一些空闲,可以放数据
           offset = 0; // 移到后,bytes缓存没有数据被使用
           limit = len; // 移到后,有效数据都在bytes缓存最前面
         }
       }
     } else { // 如果解析出一个结果
       int position = input.position(); // 记录InputStream用了多少
       if (position == offset) { // 如果InputStream没有被读过,就返回了数据,直接报错,否则InputStream永远读不完,会死递归
         throw new IOException("Decode without read data.");
       }
       offset = position; // 记录已读数据
       context.setMessage(msg); // 将消息改为解码后的对象,以便被后面的Filter使用。
       if (limit - offset > 0 || readable > 0) { // 如果有效数据没有被读完,或者Buffer区还有未读数据
         return context.getInvokeAction(
             new Object[] {
               buffer, readable, bytes, offset, limit
             }); // 正常执行完Filter,并重新发起一轮Filter,继续读
       } else { // 否则所有数据读完
         return context.getInvokeAction(); // 正常执行完Filter
       }
     }
   }
 }
示例#6
0
  @Test
  public void testPingPong() throws Exception {
    startHttpServer(
        new HttpHandler() {

          @Override
          public void service(Request request, Response response) throws Exception {
            response.setStatus(200, "FINE");
          }
        },
        "/");

    final MemoryManager mm =
        httpServer.getListener(LISTENER_NAME).getTransport().getMemoryManager();
    final Buffer request = mm.allocate(512);
    request.put((byte) 0x12);
    request.put((byte) 0x34);
    request.putShort((short) 1);
    request.put(AjpConstants.JK_AJP13_CPING_REQUEST);
    request.flip();

    final Future<Buffer> responseFuture = send("localhost", PORT, request);
    Buffer response = responseFuture.get(10, TimeUnit.SECONDS);

    assertEquals('A', response.get());
    assertEquals('B', response.get());
    assertEquals((short) 1, response.getShort());
    assertEquals(AjpConstants.JK_AJP13_CPONG_REPLY, response.get());

    final AjpForwardRequestPacket headersPacket =
        new AjpForwardRequestPacket("GET", "/TestServlet/normal", 80, PORT);
    headersPacket.addHeader("Host", "localhost:80");
    send(headersPacket.toByteArray());

    AjpResponse ajpResponse = Utils.parseResponse(readAjpMessage());
    Assert.assertEquals("FINE", ajpResponse.getResponseMessage());
  }
示例#7
0
  @Test
  public void testSslParams() throws Exception {
    final NetworkListener listener = httpServer.getListener(LISTENER_NAME);

    startHttpServer(
        new HttpHandler() {

          @Override
          public void service(Request request, Response response) throws Exception {
            boolean isOk = request.isSecure();
            String error = "unknown";

            if (isOk) {
              try {
                assertEquals(
                    (Integer) 256, (Integer) request.getAttribute(SSLSupport.KEY_SIZE_KEY));
                assertNotNull(request.getAttribute(SSLSupport.SESSION_ID_KEY));
                assertNotNull(request.getAttribute(SSLSupport.CIPHER_SUITE_KEY));
                assertNotNull(request.getAttribute(SSLSupport.CERTIFICATE_KEY));
              } catch (Exception e) {
                error = e.getClass().getName() + ": " + e.getMessage();
                isOk = false;
              }
            }

            if (isOk) {
              response.setStatus(200, "FINE");
            } else {
              response.setStatus(500, error);
            }
          }
        });

    final MemoryManager mm = listener.getTransport().getMemoryManager();
    final Buffer request = Buffers.wrap(mm, Utils.loadResourceFile("get-secured.dat"));

    Buffer responseBuffer = send("localhost", PORT, request).get(10, TimeUnit.SECONDS);

    // Successful response length is 37 bytes.  This includes the status
    // line and a content-length
    boolean isFailure = responseBuffer.remaining() != 37;

    if (isFailure) {
      byte[] response = new byte[responseBuffer.remaining()];
      responseBuffer.get(response);
      String hex = toHexString(response);
      fail("unexpected response length=" + response.length + " content=[" + hex + "]");
    }
  }
  public Result find(PUContext puc, FilterChainContext fcc) {
    final Buffer buffer = fcc.getMessage();
    if (buffer.remaining() >= signature.length) {
      final int start = buffer.position();

      for (int i = 0; i < signature.length; i++) {
        if (buffer.get(start + i) != signature[i]) {
          return Result.NOT_FOUND;
        }
      }

      return Result.FOUND;
    }

    return Result.NEED_MORE_DATA;
  }
  /**
   * This method always blocks.
   *
   * @see java.io.InputStream#read()
   */
  public int readByte() throws IOException {
    if (LOGGER.isLoggable(LOGGER_LEVEL)) {
      log("InputBuffer %s readByte. Ready content: %s", this, inputContentBuffer);
    }

    if (closed) {
      throw new IOException();
    }
    if (!inputContentBuffer.hasRemaining()) {
      if (fill(1) == -1) {
        return -1;
      }
    }

    checkMarkAfterRead(1);
    return inputContentBuffer.get() & 0xFF;
  }
        @Override
        public void notifyDirectUpdate() {
          if (type == Type.Buffer) {
            final int start = getStart();
            final int end = getEnd();

            final byte[] bytes = new byte[end - start];

            final Buffer currentBuffer = getBufferChunk().getBuffer();
            final int pos = currentBuffer.position();
            final int lim = currentBuffer.limit();

            Buffers.setPositionLimit(currentBuffer, start, end);
            currentBuffer.get(bytes);
            Buffers.setPositionLimit(currentBuffer, pos, lim);

            setBytes(bytes);
          }
        }
示例#11
0
  @Test
  public void testNullAttribute() throws Exception {
    final NetworkListener listener = httpServer.getListener(LISTENER_NAME);

    startHttpServer(
        new HttpHandler() {

          @Override
          public void service(Request request, Response response) throws Exception {
            final Set<String> attributeNames = request.getAttributeNames();
            final boolean isOk =
                attributeNames.contains("JK_LB_ACTIVATION")
                    && request.getAttribute("JK_LB_ACTIVATION") == null
                    && attributeNames.contains("AJP_REMOTE_PORT")
                    && "60955".equals(request.getAttribute("AJP_REMOTE_PORT"));

            if (isOk) {
              response.setStatus(200, "FINE");
            } else {
              response.setStatus(500, "Attributes don't match");
            }
          }
        },
        "/SimpleWebApp/SimpleServlet");

    final MemoryManager mm = listener.getTransport().getMemoryManager();
    final Buffer request = Buffers.wrap(mm, Utils.loadResourceFile("null-attr-payload.dat"));

    Buffer responseBuffer = send("localhost", PORT, request).get(10, TimeUnit.SECONDS);

    // Successful response length is 37 bytes.  This includes the status
    // line and a content-length
    boolean isFailure = responseBuffer.remaining() != 37;

    if (isFailure) {
      byte[] response = new byte[responseBuffer.remaining()];
      responseBuffer.get(response);
      String hex = toHexString(response);
      fail("unexpected response length=" + response.length + " content=[" + hex + "]");
    }
  }
  @Override
  public void process(Buffer source, HeaderFieldTable.DecTable table, HeaderListener handler) {
    ObjectHolder<String> s = new ObjectHolder<>();
    String name;
    int beginning = source.position();
    byte b = source.get();
    if ((b & 0b111111) == 0) {
      readString(source, s);
      name = s.getObj();
    } else {
      source.position(beginning);
      int index = readInteger(source, 6);
      HeaderField e = table.get(index);
      name = e.getName();
    }
    readString(source, s);
    String value = s.getObj();
    HeaderField f = new HeaderField(name, value);
    table.put(f);

    handler.onDecodedHeader(name, value);
  }
示例#13
0
  /**
   * Create a multipath based NFSv4.1 file layout address.
   *
   * @param stripingPattern of the device
   * @param deviceAddress
   * @return device address
   */
  public static device_addr4 deviceAddrOf(
      StripingPattern<InetSocketAddress[]> stripingPattern, InetSocketAddress[]... deviceAddress) {

    nfsv4_1_file_layout_ds_addr4 file_type = new nfsv4_1_file_layout_ds_addr4();

    file_type.nflda_multipath_ds_list = new multipath_list4[deviceAddress.length];

    for (int i = 0; i < deviceAddress.length; i++) {
      file_type.nflda_multipath_ds_list[i] = toMultipath(deviceAddress[i]);
    }

    file_type.nflda_stripe_indices = stripingPattern.getPattern(deviceAddress);

    XdrBuffer xdr = new XdrBuffer(128);
    try {
      xdr.beginEncoding();
      file_type.xdrEncode(xdr);
      xdr.endEncoding();
    } catch (OncRpcException e) {
      /* forced by interface, should never happen. */
      throw new RuntimeException("Unexpected OncRpcException:", e);
    } catch (IOException e) {
      /* forced by interface, should never happen. */
      throw new RuntimeException("Unexpected IOException:", e);
    }

    Buffer body = xdr.asBuffer();
    byte[] retBytes = new byte[body.remaining()];
    body.get(retBytes);

    device_addr4 addr = new device_addr4();
    addr.da_layout_type = layouttype4.LAYOUT4_NFSV4_1_FILES;
    addr.da_addr_body = retBytes;

    return addr;
  }
示例#14
0
  @Test
  public void testAddresses() throws Exception {
    final String expectedRemoteAddr = "10.163.27.8";
    final String expectedLocalAddr = "10.163.25.1";
    final NetworkListener listener = httpServer.getListener(LISTENER_NAME);

    startHttpServer(
        new HttpHandler() {

          @Override
          public void service(Request request, Response response) throws Exception {
            boolean isOk = false;
            final StringBuilder errorBuilder = new StringBuilder();
            try {
              String result = request.getRemoteAddr();
              isOk = expectedRemoteAddr.equals(result);
              if (!isOk) {
                errorBuilder
                    .append("Remote host don't match. Expected ")
                    .append(expectedRemoteAddr)
                    .append(" but was ")
                    .append(result)
                    .append('\n');
              }

              String localName = request.getLocalName();
              String localAddr = request.getLocalAddr();
              isOk = expectedLocalAddr.equals(localName) && localName.equals(localAddr);
              if (!isOk) {
                errorBuilder
                    .append("Local address and host don't match. Expected=")
                    .append(expectedLocalAddr)
                    .append(" Addr=")
                    .append(localAddr)
                    .append(" name=")
                    .append(localName)
                    .append('\n');
              }
            } catch (Exception e) {
              errorBuilder.append(e.toString());
            }

            if (isOk) {
              response.setStatus(200, "FINE");
            } else {
              LOGGER.warning(errorBuilder.toString());
              response.setStatus(500, "ERROR");
            }
          }
        });

    final MemoryManager mm = listener.getTransport().getMemoryManager();
    final Buffer request = Buffers.wrap(mm, Utils.loadResourceFile("peer-addr-check.dat"));

    Buffer responseBuffer = send("localhost", PORT, request).get(60, TimeUnit.SECONDS);

    // Successful response length is 37 bytes.  This includes the status
    // line and a content-length
    boolean isFailure = responseBuffer.remaining() != 37;

    if (isFailure) {
      byte[] response = new byte[responseBuffer.remaining()];
      responseBuffer.get(response);
      String hex = toHexString(response);
      fail("unexpected response length=" + response.length + " content=[" + hex + "]");
    }
  }
  /** Parse host. */
  static void parseHost(
      final DataChunk hostDC, final DataChunk serverNameDC, final HttpRequestPacket request) {

    if (hostDC == null) {
      // HTTP/1.0
      // Default is what the socket tells us. Overriden if a host is
      // found/parsed
      request.setServerPort(request.getLocalPort());
      serverNameDC.setString(request.getLocalName());
      return;
    }

    final BufferChunk valueBC = hostDC.getBufferChunk();
    final int valueS = valueBC.getStart();
    final int valueL = valueBC.getEnd() - valueS;
    int colonPos = -1;

    final Buffer valueB = valueBC.getBuffer();
    final boolean ipv6 = (valueB.get(valueS) == '[');
    boolean bracketClosed = false;
    for (int i = 0; i < valueL; i++) {
      final byte b = valueB.get(i + valueS);
      if (b == ']') {
        bracketClosed = true;
      } else if (b == ':') {
        if (!ipv6 || bracketClosed) {
          colonPos = i;
          break;
        }
      }
    }

    if (colonPos < 0) {
      if (!request.isSecure()) {
        // 80 - Default HTTTP port
        request.setServerPort(80);
      } else {
        // 443 - Default HTTPS port
        request.setServerPort(443);
      }
      serverNameDC.setBuffer(valueB, valueS, valueS + valueL);
    } else {
      serverNameDC.setBuffer(valueB, valueS, valueS + colonPos);

      int port = 0;
      int mult = 1;
      for (int i = valueL - 1; i > colonPos; i--) {
        int charValue = DEC[(int) valueB.get(i + valueS)];
        if (charValue == -1) {
          // Invalid character
          throw new IllegalStateException(
              String.format(
                  "Host header %s contained a non-decimal value in the port definition.",
                  hostDC.toString()));
        }
        port = port + (charValue * mult);
        mult = 10 * mult;
      }
      request.setServerPort(port);
    }
  }
  private static int decodeAttributes(
      final Buffer requestContent,
      int offset,
      final AjpHttpRequest req,
      final boolean tomcatAuthentication) {

    final DataChunk tmpDataChunk = req.tmpDataChunk;

    boolean moreAttr = true;

    while (moreAttr) {
      final byte attributeCode = requestContent.get(offset++);
      if (attributeCode == AjpConstants.SC_A_ARE_DONE) {
        return offset;
      }

      /* Special case ( XXX in future API make it separate type !)
       */
      if (attributeCode == AjpConstants.SC_A_SSL_KEY_SIZE) {
        // Bug 1326: it's an Integer.
        req.setAttribute(SSLSupport.KEY_SIZE_KEY, readShort(requestContent, offset));
        offset += 2;
      }

      if (attributeCode == AjpConstants.SC_A_REQ_ATTRIBUTE) {
        // 2 strings ???...
        offset = setStringAttribute(req, requestContent, offset);
      }

      // 1 string attributes
      switch (attributeCode) {
        case AjpConstants.SC_A_CONTEXT:
          // nothing
          offset = skipBytes(requestContent, offset);
          break;

        case AjpConstants.SC_A_REMOTE_USER:
          if (tomcatAuthentication) {
            // ignore server
            offset = skipBytes(requestContent, offset);
          } else {
            offset = getBytesToDataChunk(requestContent, offset, req.remoteUser());
          }
          break;

        case AjpConstants.SC_A_AUTH_TYPE:
          if (tomcatAuthentication) {
            // ignore server
            offset = skipBytes(requestContent, offset);
          } else {
            offset = getBytesToDataChunk(requestContent, offset, req.authType());
          }
          break;

        case AjpConstants.SC_A_QUERY_STRING:
          offset = getBytesToDataChunk(requestContent, offset, req.getQueryStringDC());
          break;

        case AjpConstants.SC_A_JVM_ROUTE:
          offset = getBytesToDataChunk(requestContent, offset, req.instanceId());
          break;

        case AjpConstants.SC_A_SSL_CERT:
          req.setSecure(true);
          // SSL certificate extraction is costy, initialize on demand
          offset = getBytesToDataChunk(requestContent, offset, req.sslCert());
          break;

        case AjpConstants.SC_A_SSL_CIPHER:
          req.setSecure(true);
          offset =
              setStringAttributeValue(req, SSLSupport.CIPHER_SUITE_KEY, requestContent, offset);
          break;

        case AjpConstants.SC_A_SSL_SESSION:
          req.setSecure(true);
          offset = setStringAttributeValue(req, SSLSupport.SESSION_ID_KEY, requestContent, offset);
          break;

        case AjpConstants.SC_A_SECRET:
          offset = getBytesToDataChunk(requestContent, offset, tmpDataChunk);

          req.setSecret(tmpDataChunk.toString());
          tmpDataChunk.recycle();

          break;

        case AjpConstants.SC_A_STORED_METHOD:
          offset = getBytesToDataChunk(requestContent, offset, req.getMethodDC());
          break;

        default:
          break; // ignore, we don't know about it - backward compat
      }
    }

    return offset;
  }