Пример #1
0
  @Override
  public long skip(long n) throws IOException {

    if (closed) {
      throw new IOException(sm.getString("inputBuffer.streamClosed"));
    }

    if (n < 0) {
      throw new IllegalArgumentException();
    }

    long nRead = 0;
    while (nRead < n) {
      if (cb.getLength() >= n) {
        cb.setOffset(cb.getStart() + (int) n);
        nRead = n;
      } else {
        nRead += cb.getLength();
        cb.setOffset(cb.getEnd());
        int toRead = 0;
        if (cb.getChars().length < (n - nRead)) {
          toRead = cb.getChars().length;
        } else {
          toRead = (int) (n - nRead);
        }
        int nb = realReadChars(cb.getChars(), 0, toRead);
        if (nb < 0) {
          break;
        }
      }
    }

    return nRead;
  }
Пример #2
0
  /**
   * Alternate constructor which allows specifying the initial buffer size.
   *
   * @param size Buffer size to use
   */
  public InputBuffer(int size) {

    this.size = size;
    bb = new ByteChunk(size);
    bb.setLimit(size);
    bb.setByteInputChannel(this);
    cb = new CharChunk(size);
    cb.setLimit(size);
    cb.setOptimizedWrite(false);
    cb.setCharInputChannel(this);
    cb.setCharOutputChannel(this);
  }
Пример #3
0
  @Override
  public int read(char[] cbuf, int off, int len) throws IOException {

    if (closed) {
      throw new IOException(sm.getString("inputBuffer.streamClosed"));
    }

    return cb.substract(cbuf, off, len);
  }
Пример #4
0
  @Override
  public int read() throws IOException {

    if (closed) {
      throw new IOException(sm.getString("inputBuffer.streamClosed"));
    }

    return cb.substract();
  }
Пример #5
0
  @Override
  public void reset() throws IOException {

    if (closed) {
      throw new IOException(sm.getString("inputBuffer.streamClosed"));
    }

    if (state == CHAR_STATE) {
      if (markPos < 0) {
        cb.recycle();
        markPos = -1;
        throw new IOException();
      } else {
        cb.setOffset(markPos);
      }
    } else {
      bb.recycle();
    }
  }
Пример #6
0
  /** Character conversion of the a US-ASCII MessageBytes. */
  protected void convertMB(MessageBytes mb) {

    // This is of course only meaningful for bytes
    if (mb.getType() != MessageBytes.T_BYTES) {
      return;
    }

    ByteChunk bc = mb.getByteChunk();
    CharChunk cc = mb.getCharChunk();
    int length = bc.getLength();
    cc.allocate(length, -1);

    // Default encoding: fast conversion
    byte[] bbuf = bc.getBuffer();
    char[] cbuf = cc.getBuffer();
    int start = bc.getStart();
    for (int i = 0; i < length; i++) {
      cbuf[i] = (char) (bbuf[i + start] & 0xff);
    }
    mb.setChars(cbuf, 0, length);
  }
Пример #7
0
  /** Recycle the output buffer. */
  public void recycle() {

    state = INITIAL_STATE;

    // If usage of mark made the buffer too big, reallocate it
    if (cb.getChars().length > size) {
      cb = new CharChunk(size);
      cb.setLimit(size);
      cb.setOptimizedWrite(false);
      cb.setCharInputChannel(this);
      cb.setCharOutputChannel(this);
    } else {
      cb.recycle();
    }
    markPos = -1;
    bb.recycle();
    closed = false;

    if (conv != null) {
      conv.recycle();
    }

    gotEnc = false;
    enc = null;
  }
Пример #8
0
 public int available() {
   int available = 0;
   if (state == BYTE_STATE) {
     available = bb.getLength();
   } else if (state == CHAR_STATE) {
     available = cb.getLength();
   }
   if (available == 0) {
     coyoteRequest.action(ActionCode.AVAILABLE, null);
     available = (coyoteRequest.getAvailable() > 0) ? 1 : 0;
   }
   return available;
 }
Пример #9
0
  @Override
  public int realReadChars(char cbuf[], int off, int len) throws IOException {

    if (!gotEnc) {
      setConverter();
    }

    boolean eof = false;

    if (bb.getLength() <= 0) {
      int nRead = realReadBytes(bb.getBytes(), 0, bb.getBytes().length);
      if (nRead < 0) {
        eof = true;
      }
    }

    if (markPos == -1) {
      cb.setOffset(0);
      cb.setEnd(0);
    } else {
      // Make sure there's enough space in the worst case
      cb.makeSpace(bb.getLength());
      if ((cb.getBuffer().length - cb.getEnd()) == 0) {
        // We went over the limit
        cb.setOffset(0);
        cb.setEnd(0);
        markPos = -1;
      }
    }

    state = CHAR_STATE;
    conv.convert(bb, cb, eof);

    if (cb.getLength() == 0 && eof) {
      return -1;
    } else {
      return cb.getLength();
    }
  }
Пример #10
0
  /**
   * Check that the URI is normalized following character decoding.
   *
   * <p>This method checks for "\", 0, "//", "/./" and "/../". This method will return false if
   * sequences that are supposed to be normalized are still present in the URI.
   *
   * @param uriMB URI to be checked (should be chars)
   */
  public static boolean checkNormalize(MessageBytes uriMB) {

    CharChunk uriCC = uriMB.getCharChunk();
    char[] c = uriCC.getChars();
    int start = uriCC.getStart();
    int end = uriCC.getEnd();

    int pos = 0;

    // Check for '\' and 0
    for (pos = start; pos < end; pos++) {
      if (c[pos] == '\\') {
        return false;
      }
      if (c[pos] == 0) {
        return false;
      }
    }

    // Check for "//"
    for (pos = start; pos < (end - 1); pos++) {
      if (c[pos] == '/') {
        if (c[pos + 1] == '/') {
          return false;
        }
      }
    }

    // Check for ending with "/." or "/.."
    if (((end - start) >= 2) && (c[end - 1] == '.')) {
      if ((c[end - 2] == '/') || ((c[end - 2] == '.') && (c[end - 3] == '/'))) {
        return false;
      }
    }

    // Check for "/./"
    if (uriCC.indexOf("/./", 0, 3, 0) >= 0) {
      return false;
    }

    // Check for "/../"
    if (uriCC.indexOf("/../", 0, 4, 0) >= 0) {
      return false;
    }

    return true;
  }
Пример #11
0
  /** Character conversion of the URI. */
  protected void convertURI(MessageBytes uri, Request request) throws Exception {

    ByteChunk bc = uri.getByteChunk();
    int length = bc.getLength();
    CharChunk cc = uri.getCharChunk();
    cc.allocate(length, -1);

    String enc = connector.getURIEncoding();
    if (enc != null) {
      B2CConverter conv = request.getURIConverter();
      try {
        if (conv == null) {
          conv = new B2CConverter(enc, true);
          request.setURIConverter(conv);
        } else {
          conv.recycle();
        }
      } catch (IOException e) {
        log.error("Invalid URI encoding; using HTTP default");
        connector.setURIEncoding(null);
      }
      if (conv != null) {
        try {
          conv.convert(bc, cc, true);
          uri.setChars(cc.getBuffer(), cc.getStart(), cc.getLength());
          return;
        } catch (IOException ioe) {
          // Should never happen as B2CConverter should replace
          // problematic characters
          request.getResponse().sendError(HttpServletResponse.SC_BAD_REQUEST);
        }
      }
    }

    // Default encoding: fast conversion for ISO-8859-1
    byte[] bbuf = bc.getBuffer();
    char[] cbuf = cc.getBuffer();
    int start = bc.getStart();
    for (int i = 0; i < length; i++) {
      cbuf[i] = (char) (bbuf[i + start] & 0xff);
    }
    uri.setChars(cbuf, 0, length);
  }
Пример #12
0
  /*
   * Removes /./ and /../ sequences from absolute URLs.
   * Code borrowed heavily from CoyoteAdapter.normalize()
   */
  private void normalize(CharChunk cc) {
    // Strip query string and/or fragment first as doing it this way makes
    // the normalization logic a lot simpler
    int truncate = cc.indexOf('?');
    if (truncate == -1) {
      truncate = cc.indexOf('#');
    }
    char[] truncateCC = null;
    if (truncate > -1) {
      truncateCC = Arrays.copyOfRange(cc.getBuffer(), cc.getStart() + truncate, cc.getEnd());
      cc.setEnd(cc.getStart() + truncate);
    }

    if (cc.endsWith("/.") || cc.endsWith("/..")) {
      try {
        cc.append('/');
      } catch (IOException e) {
        throw new IllegalArgumentException(cc.toString(), e);
      }
    }

    char[] c = cc.getChars();
    int start = cc.getStart();
    int end = cc.getEnd();
    int index = 0;
    int startIndex = 0;

    // Advance past the first three / characters (should place index just
    // scheme://host[:port]

    for (int i = 0; i < 3; i++) {
      startIndex = cc.indexOf('/', startIndex + 1);
    }

    // Remove /./
    index = startIndex;
    while (true) {
      index = cc.indexOf("/./", 0, 3, index);
      if (index < 0) {
        break;
      }
      copyChars(c, start + index, start + index + 2, end - start - index - 2);
      end = end - 2;
      cc.setEnd(end);
    }

    // Remove /../
    index = startIndex;
    int pos;
    while (true) {
      index = cc.indexOf("/../", 0, 4, index);
      if (index < 0) {
        break;
      }
      // Can't go above the server root
      if (index == startIndex) {
        throw new IllegalArgumentException();
      }
      int index2 = -1;
      for (pos = start + index - 1; (pos >= 0) && (index2 < 0); pos--) {
        if (c[pos] == (byte) '/') {
          index2 = pos;
        }
      }
      copyChars(c, start + index2, start + index + 3, end - start - index - 3);
      end = end + index2 - index - 3;
      cc.setEnd(end);
      index = index2;
    }

    // Add the query string and/or fragment (if present) back in
    if (truncateCC != null) {
      try {
        cc.append(truncateCC, 0, truncateCC.length);
      } catch (IOException ioe) {
        throw new IllegalArgumentException(ioe);
      }
    }
  }
Пример #13
0
  /**
   * Convert (if necessary) and return the absolute URL that represents the resource referenced by
   * this possibly relative URL. If this URL is already absolute, return it unchanged.
   *
   * @param location URL to be (possibly) converted and then returned
   * @exception IllegalArgumentException if a MalformedURLException is thrown when converting the
   *     relative URL to an absolute one
   */
  protected String toAbsolute(String location) {

    if (location == null) {
      return (location);
    }

    boolean leadingSlash = location.startsWith("/");

    if (location.startsWith("//")) {
      // Scheme relative
      redirectURLCC.recycle();
      // Add the scheme
      String scheme = request.getScheme();
      try {
        redirectURLCC.append(scheme, 0, scheme.length());
        redirectURLCC.append(':');
        redirectURLCC.append(location, 0, location.length());
        return redirectURLCC.toString();
      } catch (IOException e) {
        IllegalArgumentException iae = new IllegalArgumentException(location);
        iae.initCause(e);
        throw iae;
      }

    } else if (leadingSlash || !hasScheme(location)) {

      redirectURLCC.recycle();

      String scheme = request.getScheme();
      String name = request.getServerName();
      int port = request.getServerPort();

      try {
        redirectURLCC.append(scheme, 0, scheme.length());
        redirectURLCC.append("://", 0, 3);
        redirectURLCC.append(name, 0, name.length());
        if ((scheme.equals("http") && port != 80) || (scheme.equals("https") && port != 443)) {
          redirectURLCC.append(':');
          String portS = port + "";
          redirectURLCC.append(portS, 0, portS.length());
        }
        if (!leadingSlash) {
          String relativePath = request.getDecodedRequestURI();
          int pos = relativePath.lastIndexOf('/');
          CharChunk encodedURI = null;
          final String frelativePath = relativePath;
          final int fend = pos;
          if (SecurityUtil.isPackageProtectionEnabled()) {
            try {
              encodedURI =
                  AccessController.doPrivileged(
                      new PrivilegedExceptionAction<CharChunk>() {
                        @Override
                        public CharChunk run() throws IOException {
                          return urlEncoder.encodeURL(frelativePath, 0, fend);
                        }
                      });
            } catch (PrivilegedActionException pae) {
              IllegalArgumentException iae = new IllegalArgumentException(location);
              iae.initCause(pae.getException());
              throw iae;
            }
          } else {
            encodedURI = urlEncoder.encodeURL(relativePath, 0, pos);
          }
          redirectURLCC.append(encodedURI);
          encodedURI.recycle();
          redirectURLCC.append('/');
        }
        redirectURLCC.append(location, 0, location.length());

        normalize(redirectURLCC);
      } catch (IOException e) {
        IllegalArgumentException iae = new IllegalArgumentException(location);
        iae.initCause(e);
        throw iae;
      }

      return redirectURLCC.toString();

    } else {

      return (location);
    }
  }
Пример #14
0
  @Override
  public void mark(int readAheadLimit) throws IOException {

    if (closed) {
      throw new IOException(sm.getString("inputBuffer.streamClosed"));
    }

    if (cb.getLength() <= 0) {
      cb.setOffset(0);
      cb.setEnd(0);
    } else {
      if ((cb.getBuffer().length > (2 * size)) && (cb.getLength()) < (cb.getStart())) {
        System.arraycopy(cb.getBuffer(), cb.getStart(), cb.getBuffer(), 0, cb.getLength());
        cb.setEnd(cb.getLength());
        cb.setOffset(0);
      }
    }
    cb.setLimit(cb.getStart() + readAheadLimit + size);
    markPos = cb.getStart();
  }
Пример #15
0
 /**
  * Since the converter will use append, it is possible to get chars to be removed from the buffer
  * for "writing". Since the chars have already been read before, they are ignored. If a mark was
  * set, then the mark is lost.
  */
 @Override
 public void realWriteChars(char c[], int off, int len) throws IOException {
   markPos = -1;
   cb.setOffset(0);
   cb.setEnd(0);
 }
Пример #16
0
  /**
   * Authenticate the user making this request, based on the specified login configuration. Return
   * <code>true</code> if any specified constraint has been satisfied, or <code>false</code> if we
   * have created a response challenge already.
   *
   * @param request Request we are processing
   * @param response Response we are creating
   * @param config Login configuration describing how authentication should be performed
   * @exception IOException if an input/output error occurs
   */
  @Override
  public boolean authenticate(Request request, HttpServletResponse response, LoginConfig config)
      throws IOException {

    // Have we already authenticated someone?
    Principal principal = request.getUserPrincipal();
    String ssoId = (String) request.getNote(Constants.REQ_SSOID_NOTE);
    if (principal != null) {
      if (log.isDebugEnabled()) log.debug("Already authenticated '" + principal.getName() + "'");
      // Associate the session with any existing SSO session
      if (ssoId != null) associate(ssoId, request.getSessionInternal(true));
      return (true);
    }

    // Is there an SSO session against which we can try to reauthenticate?
    if (ssoId != null) {
      if (log.isDebugEnabled())
        log.debug("SSO Id " + ssoId + " set; attempting " + "reauthentication");
      /* Try to reauthenticate using data cached by SSO.  If this fails,
      either the original SSO logon was of DIGEST or SSL (which
      we can't reauthenticate ourselves because there is no
      cached username and password), or the realm denied
      the user's reauthentication for some reason.
      In either case we have to prompt the user for a logon */
      if (reauthenticateFromSSO(ssoId, request)) return true;
    }

    // Validate any credentials already included with this request
    String username = null;
    String password = null;

    MessageBytes authorization =
        request.getCoyoteRequest().getMimeHeaders().getValue("authorization");

    if (authorization != null) {
      authorization.toBytes();
      ByteChunk authorizationBC = authorization.getByteChunk();
      if (authorizationBC.startsWithIgnoreCase("basic ", 0)) {
        authorizationBC.setOffset(authorizationBC.getOffset() + 6);
        // FIXME: Add trimming
        // authorizationBC.trim();

        CharChunk authorizationCC = authorization.getCharChunk();
        Base64.decode(authorizationBC, authorizationCC);

        // Get username and password
        int colon = authorizationCC.indexOf(':');
        if (colon < 0) {
          username = authorizationCC.toString();
        } else {
          char[] buf = authorizationCC.getBuffer();
          username = new String(buf, 0, colon);
          password = new String(buf, colon + 1, authorizationCC.getEnd() - colon - 1);
        }

        authorizationBC.setOffset(authorizationBC.getOffset() - 6);
      }

      principal = context.getRealm().authenticate(username, password);
      if (principal != null) {
        register(request, response, principal, Constants.BASIC_METHOD, username, password);
        return (true);
      }
    }

    StringBuilder value = new StringBuilder(16);
    value.append("Basic realm=\"");
    if (config.getRealmName() == null) {
      value.append(REALM_NAME);
    } else {
      value.append(config.getRealmName());
    }
    value.append('\"');
    response.setHeader(AUTH_HEADER_NAME, value.toString());
    response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
    return (false);
  }