public String newNonce(Request request) {
    long ts = request.getTimeStamp();
    long sk = _nonceSecret;

    byte[] nounce = new byte[24];
    for (int i = 0; i < 8; i++) {
      nounce[i] = (byte) (ts & 0xff);
      ts = ts >> 8;
      nounce[8 + i] = (byte) (sk & 0xff);
      sk = sk >> 8;
    }

    byte[] hash = null;
    try {
      MessageDigest md = MessageDigest.getInstance("MD5");
      md.reset();
      md.update(nounce, 0, 16);
      hash = md.digest();
    } catch (Exception e) {
      Log.warn(e);
    }

    for (int i = 0; i < hash.length; i++) {
      nounce[8 + i] = hash[i];
      if (i == 23) {
        break;
      }
    }

    return new String(B64Code.encode(nounce));
  }
 private void updateResponses(Request request) {
   final int response = request.getResponse().getStatus() / 100;
   if (response >= 1 && response <= 5) {
     responses[response - 1].mark();
   }
   activeRequests.dec();
   final long elapsedTime = System.currentTimeMillis() - request.getTimeStamp();
   requests.update(elapsedTime, TimeUnit.MILLISECONDS);
   requestTimer(request.getMethod()).update(elapsedTime, TimeUnit.MILLISECONDS);
 }
  /* ------------------------------------------------------------ */
  private int checkNonce(String nonce, Request request) {
    try {
      byte[] n = B64Code.decode(nonce.toCharArray());
      if (n.length != 24) {
        return -1;
      }

      long ts = 0;
      long sk = _nonceSecret;
      byte[] n2 = new byte[16];
      System.arraycopy(n, 0, n2, 0, 8);
      for (int i = 0; i < 8; i++) {
        n2[8 + i] = (byte) (sk & 0xff);
        sk = sk >> 8;
        ts = (ts << 8) + (0xff & (long) n[7 - i]);
      }

      long age = request.getTimeStamp() - ts;
      if (Log.isDebugEnabled()) {
        Log.debug("age=" + age);
      }

      byte[] hash = null;
      try {
        MessageDigest md = MessageDigest.getInstance("MD5");
        md.reset();
        md.update(n2, 0, 16);
        hash = md.digest();
      } catch (Exception e) {
        Log.warn(e);
      }

      for (int i = 0; i < 16; i++) {
        if (n[i + 8] != hash[i]) {
          return -1;
        }
      }

      if (_maxNonceAge > 0 && (age < 0 || age > _maxNonceAge)) {
        return 0; // stale
      }

      return 1;
    } catch (Exception e) {
      Log.ignore(e);
    }
    return -1;
  }
  @Override
  public void handle(
      String path,
      Request request,
      HttpServletRequest httpRequest,
      HttpServletResponse httpResponse)
      throws IOException, ServletException {

    activeDispatches.inc();

    final long start;
    final HttpChannelState state = request.getHttpChannelState();
    if (state.isInitial()) {
      // new request
      activeRequests.inc();
      start = request.getTimeStamp();
    } else {
      // resumed request
      start = System.currentTimeMillis();
      activeSuspended.dec();
      if (state.getState() == State.DISPATCHED) {
        asyncDispatches.mark();
      }
    }

    try {
      super.handle(path, request, httpRequest, httpResponse);
    } finally {
      final long now = System.currentTimeMillis();
      final long dispatched = now - start;

      activeDispatches.dec();
      dispatches.update(dispatched, TimeUnit.MILLISECONDS);

      if (state.isSuspended()) {
        if (state.isInitial()) {
          state.addListener(listener);
        }
        activeSuspended.inc();
      } else if (state.isInitial()) {
        requests.update(dispatched, TimeUnit.MILLISECONDS);
        updateResponses(request);
      }
      // else onCompletion will handle it.
    }
  }
  @Override
  public void log(Request request, Response response) {
    // copied almost entirely from NCSARequestLog
    final StringBuilder buf = new StringBuilder(256);
    String address = request.getHeader(HttpHeaders.X_FORWARDED_FOR);
    if (address == null) {
      address = request.getRemoteAddr();
    }

    buf.append(address);
    buf.append(" - ");
    final Authentication authentication = request.getAuthentication();
    if (authentication instanceof Authentication.User) {
      buf.append(
          ((Authentication.User) authentication).getUserIdentity().getUserPrincipal().getName());
    } else {
      buf.append('-');
    }

    buf.append(" [");
    buf.append(dateCache.format(request.getTimeStamp()));

    buf.append("] \"");
    buf.append(request.getMethod());
    buf.append(' ');
    buf.append(request.getUri().toString());
    buf.append(' ');
    buf.append(request.getProtocol());
    buf.append("\" ");

    // TODO: Handle async requests?
    // e.g. if (request.getAsyncContinuation().isInitial())
    assert !request.isAsyncStarted();

    int status = response.getStatus();
    if (status <= 0) {
      if (request.isHandled()) {
        status = 200;
      } else {
        status = 404;
      }
    }
    buf.append((char) ('0' + ((status / 100) % 10)));
    buf.append((char) ('0' + ((status / 10) % 10)));
    buf.append((char) ('0' + (status % 10)));

    final long responseLength = response.getContentCount();
    if (responseLength >= 0) {
      buf.append(' ');
      if (responseLength > 99999) {
        buf.append(responseLength);
      } else {
        if (responseLength > 9999) {
          buf.append((char) ('0' + ((responseLength / 10000) % 10)));
        }
        if (responseLength > 999) {
          buf.append((char) ('0' + ((responseLength / 1000) % 10)));
        }
        if (responseLength > 99) {
          buf.append((char) ('0' + ((responseLength / 100) % 10)));
        }
        if (responseLength > 9) {
          buf.append((char) ('0' + ((responseLength / 10) % 10)));
        }
        buf.append((char) ('0' + (responseLength % 10)));
      }
    } else {
      buf.append(" -");
    }

    final long now = System.currentTimeMillis();
    final long dispatchTime = request.getDispatchTime();

    buf.append(' ');
    buf.append(now - ((dispatchTime == 0) ? request.getTimeStamp() : dispatchTime));

    buf.append(' ');
    buf.append(now - request.getTimeStamp());

    System.out.println(buf.toString());
  }