@Override
  public void invoke(Request request, Response response) throws IOException, ServletException {

    /*
     * mod_header converts the '\n' into ' ' so we have to rebuild the client
     * certificate
     */
    String strcert0 = mygetHeader(request, "ssl_client_cert");
    if (strcert0 != null && strcert0.length() > 28) {
      String strcert1 = strcert0.replace(' ', '\n');
      String strcert2 = strcert1.substring(28, strcert1.length() - 26);
      String strcert3 = "-----BEGIN CERTIFICATE-----\n";
      String strcert4 = strcert3.concat(strcert2);
      String strcerts = strcert4.concat("\n-----END CERTIFICATE-----\n");
      // ByteArrayInputStream bais = new
      // ByteArrayInputStream(strcerts.getBytes("UTF-8"));
      ByteArrayInputStream bais =
          new ByteArrayInputStream(strcerts.getBytes(Charset.defaultCharset()));
      X509Certificate jsseCerts[] = null;
      String providerName = (String) request.getConnector().getProperty("clientCertProvider");
      try {
        CertificateFactory cf;
        if (providerName == null) {
          cf = CertificateFactory.getInstance("X.509");
        } else {
          cf = CertificateFactory.getInstance("X.509", providerName);
        }
        X509Certificate cert = (X509Certificate) cf.generateCertificate(bais);
        jsseCerts = new X509Certificate[1];
        jsseCerts[0] = cert;
      } catch (java.security.cert.CertificateException e) {
        log.warn(sm.getString("sslValve.certError", strcerts), e);
      } catch (NoSuchProviderException e) {
        log.error(sm.getString("sslValve.invalidProvider", providerName), e);
      }
      request.setAttribute(Globals.CERTIFICATES_ATTR, jsseCerts);
    }
    strcert0 = mygetHeader(request, "ssl_cipher");
    if (strcert0 != null) {
      request.setAttribute(Globals.CIPHER_SUITE_ATTR, strcert0);
    }
    strcert0 = mygetHeader(request, "ssl_session_id");
    if (strcert0 != null) {
      request.setAttribute(Globals.SSL_SESSION_ID_ATTR, strcert0);
      request.setAttribute(Globals.SSL_SESSION_ID_TOMCAT_ATTR, strcert0);
    }
    strcert0 = mygetHeader(request, "ssl_cipher_usekeysize");
    if (strcert0 != null) {
      request.setAttribute(Globals.KEY_SIZE_ATTR, Integer.valueOf(strcert0));
    }
    getNext().invoke(request, response);
  }
  /**
   * Enforce any user data constraint required by the security constraint guarding this request URI.
   * Return <code>true</code> if this constraint was not violated and processing should continue, or
   * <code>false</code> if we have created a response already.
   *
   * @param request Request we are processing
   * @param response Response we are creating
   * @param constraints Security constraint being checked
   * @exception IOException if an input/output error occurs
   */
  @Override
  public boolean hasUserDataPermission(
      Request request, Response response, SecurityConstraint[] constraints) throws IOException {

    // Is there a relevant user data constraint?
    if (constraints == null || constraints.length == 0) {
      if (log.isDebugEnabled()) log.debug("  No applicable security constraint defined");
      return (true);
    }
    for (int i = 0; i < constraints.length; i++) {
      SecurityConstraint constraint = constraints[i];
      String userConstraint = constraint.getUserConstraint();
      if (userConstraint == null) {
        if (log.isDebugEnabled()) log.debug("  No applicable user data constraint defined");
        return (true);
      }
      if (userConstraint.equals(Constants.NONE_TRANSPORT)) {
        if (log.isDebugEnabled()) log.debug("  User data constraint has no restrictions");
        return (true);
      }
    }
    // Validate the request against the user data constraint
    if (request.getRequest().isSecure()) {
      if (log.isDebugEnabled()) log.debug("  User data constraint already satisfied");
      return (true);
    }
    // Initialize variables we need to determine the appropriate action
    int redirectPort = request.getConnector().getRedirectPort();

    // Is redirecting disabled?
    if (redirectPort <= 0) {
      if (log.isDebugEnabled()) log.debug("  SSL redirect is disabled");
      response.sendError(HttpServletResponse.SC_FORBIDDEN, request.getRequestURI());
      return (false);
    }

    // Redirect to the corresponding SSL port
    StringBuilder file = new StringBuilder();
    String protocol = "https";
    String host = request.getServerName();
    // Protocol
    file.append(protocol).append("://").append(host);
    // Host with port
    if (redirectPort != 443) {
      file.append(":").append(redirectPort);
    }
    // URI
    file.append(request.getRequestURI());
    String requestedSessionId = request.getRequestedSessionId();
    if ((requestedSessionId != null) && request.isRequestedSessionIdFromURL()) {
      file.append(";");
      file.append(SessionConfig.getSessionUriParamName(request.getContext()));
      file.append("=");
      file.append(requestedSessionId);
    }
    String queryString = request.getQueryString();
    if (queryString != null) {
      file.append('?');
      file.append(queryString);
    }
    if (log.isDebugEnabled()) log.debug("  Redirecting to " + file.toString());
    response.sendRedirect(file.toString());
    return (false);
  }