/** Shutdown read-half of the socket connection; */
 protected void shutdownInput() throws IOException {
   if (fd != null) {
     socketShutdown(SHUT_RD);
     if (socketInputStream != null) {
       socketInputStream.setEOF(true);
     }
     shut_rd = true;
   }
 }
  /**
   * This method is the simplified version of the similar method in
   * org.apache.catalina.connector.http.HttpProcessor. However, this method only parses some "easy"
   * headers, such as "cookie", "content-length", and "content-type", and ignore other headers.
   *
   * @param input The input stream connected to our socket
   * @exception IOException if an input/output error occurs
   * @exception ServletException if a parsing error occurs
   */
  private void parseHeaders(SocketInputStream input) throws IOException, ServletException {
    while (true) {
      HttpHeader header = new HttpHeader();
      ;

      // Read the next header
      input.readHeader(header);
      if (header.nameEnd == 0) {
        if (header.valueEnd == 0) {
          return;
        } else {
          throw new ServletException(sm.getString("httpProcessor.parseHeaders.colon"));
        }
      }

      String name = new String(header.name, 0, header.nameEnd);
      String value = new String(header.value, 0, header.valueEnd);
      request.addHeader(name, value);
      // do something for some headers, ignore others.
      if (name.equals("cookie")) {
        Cookie cookies[] = RequestUtil.parseCookieHeader(value);
        for (int i = 0; i < cookies.length; i++) {
          if (cookies[i].getName().equals("jsessionid")) {
            // Override anything requested in the URL
            if (!request.isRequestedSessionIdFromCookie()) {
              // Accept only the first session id cookie
              request.setRequestedSessionId(cookies[i].getValue());
              request.setRequestedSessionCookie(true);
              request.setRequestedSessionURL(false);
            }
          }
          request.addCookie(cookies[i]);
        }
      } else if (name.equals("content-length")) {
        int n = -1;
        try {
          n = Integer.parseInt(value);
        } catch (Exception e) {
          throw new ServletException(sm.getString("httpProcessor.parseHeaders.contentLength"));
        }
        request.setContentLength(n);
      } else if (name.equals("content-type")) {
        request.setContentType(value);
      }
    } // end while
  }
  /** Execute the given command in the target VM. */
  InputStream execute(String cmd, Object... args) throws AgentLoadException, IOException {
    assert args.length <= 3; // includes null

    // did we detach?
    String p;
    synchronized (this) {
      if (this.path == null) {
        throw new IOException("Detached from target VM");
      }
      p = this.path;
    }

    // create UNIX socket
    int s = socket();

    // connect to target VM
    try {
      connect(s, p);
    } catch (IOException x) {
      close(s);
      throw x;
    }

    IOException ioe = null;

    // connected - write request
    // <ver> <cmd> <args...>
    try {
      writeString(s, PROTOCOL_VERSION);
      writeString(s, cmd);

      for (int i = 0; i < 3; i++) {
        if (i < args.length && args[i] != null) {
          writeString(s, (String) args[i]);
        } else {
          writeString(s, "");
        }
      }
    } catch (IOException x) {
      ioe = x;
    }

    // Create an input stream to read reply
    SocketInputStream sis = new SocketInputStream(s);

    // Read the command completion status
    int completionStatus;
    try {
      completionStatus = readInt(sis);
    } catch (IOException x) {
      sis.close();
      if (ioe != null) {
        throw ioe;
      } else {
        throw x;
      }
    }

    if (completionStatus != 0) {
      sis.close();

      // In the event of a protocol mismatch then the target VM
      // returns a known error so that we can throw a reasonable
      // error.
      if (completionStatus == ATTACH_ERROR_BADVERSION) {
        throw new IOException("Protocol mismatch with target VM");
      }

      // Special-case the "load" command so that the right exception is
      // thrown.
      if (cmd.equals("load")) {
        throw new AgentLoadException("Failed to load agent library");
      } else {
        throw new IOException("Command failed in target VM");
      }
    }

    // Return the input stream so that the command output can be read
    return sis;
  }
  private void parseRequest(SocketInputStream input, OutputStream output)
      throws IOException, ServletException {

    // Parse the incoming request line
    input.readRequestLine(requestLine);
    String method = new String(requestLine.method, 0, requestLine.methodEnd);
    String uri = null;
    String protocol = new String(requestLine.protocol, 0, requestLine.protocolEnd);

    // Validate the incoming request line
    if (method.length() < 1) {
      throw new ServletException("Missing HTTP request method");
    } else if (requestLine.uriEnd < 1) {
      throw new ServletException("Missing HTTP request URI");
    }
    // Parse any query parameters out of the request URI
    int question = requestLine.indexOf("?");
    if (question >= 0) {
      request.setQueryString(
          new String(requestLine.uri, question + 1, requestLine.uriEnd - question - 1));
      uri = new String(requestLine.uri, 0, question);
    } else {
      request.setQueryString(null);
      uri = new String(requestLine.uri, 0, requestLine.uriEnd);
    }

    // Checking for an absolute URI (with the HTTP protocol)
    if (!uri.startsWith("/")) {
      int pos = uri.indexOf("://");
      // Parsing out protocol and host name
      if (pos != -1) {
        pos = uri.indexOf('/', pos + 3);
        if (pos == -1) {
          uri = "";
        } else {
          uri = uri.substring(pos);
        }
      }
    }

    // Parse any requested session ID out of the request URI
    String match = ";jsessionid=";
    int semicolon = uri.indexOf(match);
    if (semicolon >= 0) {
      String rest = uri.substring(semicolon + match.length());
      int semicolon2 = rest.indexOf(';');
      if (semicolon2 >= 0) {
        request.setRequestedSessionId(rest.substring(0, semicolon2));
        rest = rest.substring(semicolon2);
      } else {
        request.setRequestedSessionId(rest);
        rest = "";
      }
      request.setRequestedSessionURL(true);
      uri = uri.substring(0, semicolon) + rest;
    } else {
      request.setRequestedSessionId(null);
      request.setRequestedSessionURL(false);
    }

    // Normalize URI (using String operations at the moment)
    String normalizedUri = normalize(uri);

    // Set the corresponding request properties
    ((HttpRequest) request).setMethod(method);
    request.setProtocol(protocol);
    if (normalizedUri != null) {
      ((HttpRequest) request).setRequestURI(normalizedUri);
    } else {
      ((HttpRequest) request).setRequestURI(uri);
    }

    if (normalizedUri == null) {
      throw new ServletException("Invalid URI: " + uri + "'");
    }
  }
  /**
   * Parse the incoming HTTP request and set the corresponding HTTP request properties.
   *
   * @param input The input stream attached to our socket
   * @param output The output stream of the socket
   * @exception IOException if an input/output error occurs
   * @exception ServletException if a parsing error occurs
   */
  private void parseRequest(SocketInputStream input, OutputStream output)
      throws IOException, ServletException {

    // Parse the incoming request line
    input.readRequestLine(requestLine);

    // When the previous method returns, we're actually processing a
    // request
    status = Constants.PROCESSOR_ACTIVE;

    String method = new String(requestLine.method, 0, requestLine.methodEnd);
    String uri = null;
    String protocol = new String(requestLine.protocol, 0, requestLine.protocolEnd);

    // System.out.println(" Method:" + method + "_ Uri:" + uri
    //                   + "_ Protocol:" + protocol);

    if (protocol.length() == 0) protocol = "HTTP/0.9";

    // Now check if the connection should be kept alive after parsing the
    // request.
    if (protocol.equals("HTTP/1.1")) {
      http11 = true;
      sendAck = false;
    } else {
      http11 = false;
      sendAck = false;
      // For HTTP/1.0, connection are not persistent by default,
      // unless specified with a Connection: Keep-Alive header.
      keepAlive = false;
    }

    // Validate the incoming request line
    if (method.length() < 1) {
      throw new ServletException(sm.getString("httpProcessor.parseRequest.method"));
    } else if (requestLine.uriEnd < 1) {
      throw new ServletException(sm.getString("httpProcessor.parseRequest.uri"));
    }

    // Parse any query parameters out of the request URI
    int question = requestLine.indexOf("?");
    if (question >= 0) {
      request.setQueryString(
          new String(requestLine.uri, question + 1, requestLine.uriEnd - question - 1));
      if (debug >= 1)
        log(" Query string is " + ((HttpServletRequest) request.getRequest()).getQueryString());
      uri = new String(requestLine.uri, 0, question);
    } else {
      request.setQueryString(null);
      uri = new String(requestLine.uri, 0, requestLine.uriEnd);
    }

    // Checking for an absolute URI (with the HTTP protocol)
    if (!uri.startsWith("/")) {
      int pos = uri.indexOf("://");
      // Parsing out protocol and host name
      if (pos != -1) {
        pos = uri.indexOf('/', pos + 3);
        if (pos == -1) {
          uri = "";
        } else {
          uri = uri.substring(pos);
        }
      }
    }

    // Parse any requested session ID out of the request URI
    int semicolon = uri.indexOf(match);
    if (semicolon >= 0) {
      String rest = uri.substring(semicolon + match.length());
      int semicolon2 = rest.indexOf(';');
      if (semicolon2 >= 0) {
        request.setRequestedSessionId(rest.substring(0, semicolon2));
        rest = rest.substring(semicolon2);
      } else {
        request.setRequestedSessionId(rest);
        rest = "";
      }
      request.setRequestedSessionURL(true);
      uri = uri.substring(0, semicolon) + rest;
      if (debug >= 1)
        log(
            " Requested URL session id is "
                + ((HttpServletRequest) request.getRequest()).getRequestedSessionId());
    } else {
      request.setRequestedSessionId(null);
      request.setRequestedSessionURL(false);
    }

    // Normalize URI (using String operations at the moment)
    String normalizedUri = normalize(uri);
    if (debug >= 1) log("Normalized: '" + uri + "' to '" + normalizedUri + "'");

    // Set the corresponding request properties
    ((HttpRequest) request).setMethod(method);
    request.setProtocol(protocol);
    if (normalizedUri != null) {
      ((HttpRequest) request).setRequestURI(normalizedUri);
    } else {
      ((HttpRequest) request).setRequestURI(uri);
    }
    request.setSecure(connector.getSecure());
    request.setScheme(connector.getScheme());

    if (normalizedUri == null) {
      log(" Invalid request URI: '" + uri + "'");
      throw new ServletException("Invalid URI: " + uri + "'");
    }

    if (debug >= 1)
      log(" Request is '" + method + "' for '" + uri + "' with protocol '" + protocol + "'");
  }
  /**
   * Parse the incoming HTTP request headers, and set the appropriate request headers.
   *
   * @param input The input stream connected to our socket
   * @exception IOException if an input/output error occurs
   * @exception ServletException if a parsing error occurs
   */
  private void parseHeaders(SocketInputStream input) throws IOException, ServletException {

    while (true) {

      HttpHeader header = request.allocateHeader();

      // Read the next header
      input.readHeader(header);
      if (header.nameEnd == 0) {
        if (header.valueEnd == 0) {
          return;
        } else {
          throw new ServletException(sm.getString("httpProcessor.parseHeaders.colon"));
        }
      }

      String value = new String(header.value, 0, header.valueEnd);
      if (debug >= 1) log(" Header " + new String(header.name, 0, header.nameEnd) + " = " + value);

      // Set the corresponding request headers
      if (header.equals(DefaultHeaders.AUTHORIZATION_NAME)) {
        request.setAuthorization(value);
      } else if (header.equals(DefaultHeaders.ACCEPT_LANGUAGE_NAME)) {
        parseAcceptLanguage(value);
      } else if (header.equals(DefaultHeaders.COOKIE_NAME)) {
        Cookie cookies[] = RequestUtil.parseCookieHeader(value);
        for (int i = 0; i < cookies.length; i++) {
          if (cookies[i].getName().equals(Globals.SESSION_COOKIE_NAME)) {
            // Override anything requested in the URL
            if (!request.isRequestedSessionIdFromCookie()) {
              // Accept only the first session id cookie
              request.setRequestedSessionId(cookies[i].getValue());
              request.setRequestedSessionCookie(true);
              request.setRequestedSessionURL(false);
              if (debug >= 1)
                log(
                    " Requested cookie session id is "
                        + ((HttpServletRequest) request.getRequest()).getRequestedSessionId());
            }
          }
          if (debug >= 1)
            log(" Adding cookie " + cookies[i].getName() + "=" + cookies[i].getValue());
          request.addCookie(cookies[i]);
        }
      } else if (header.equals(DefaultHeaders.CONTENT_LENGTH_NAME)) {
        int n = -1;
        try {
          n = Integer.parseInt(value);
        } catch (Exception e) {
          throw new ServletException(sm.getString("httpProcessor.parseHeaders.contentLength"));
        }
        request.setContentLength(n);
      } else if (header.equals(DefaultHeaders.CONTENT_TYPE_NAME)) {
        request.setContentType(value);
      } else if (header.equals(DefaultHeaders.HOST_NAME)) {
        int n = value.indexOf(':');
        if (n < 0) {
          if (connector.getScheme().equals("http")) {
            request.setServerPort(80);
          } else if (connector.getScheme().equals("https")) {
            request.setServerPort(443);
          }
          if (proxyName != null) request.setServerName(proxyName);
          else request.setServerName(value);
        } else {
          if (proxyName != null) request.setServerName(proxyName);
          else request.setServerName(value.substring(0, n).trim());
          if (proxyPort != 0) request.setServerPort(proxyPort);
          else {
            int port = 80;
            try {
              port = Integer.parseInt(value.substring(n + 1).trim());
            } catch (Exception e) {
              throw new ServletException(sm.getString("httpProcessor.parseHeaders.portNumber"));
            }
            request.setServerPort(port);
          }
        }
      } else if (header.equals(DefaultHeaders.CONNECTION_NAME)) {
        if (header.valueEquals(DefaultHeaders.CONNECTION_CLOSE_VALUE)) {
          keepAlive = false;
          response.setHeader("Connection", "close");
        }
        // request.setConnection(header);
        /*
          if ("keep-alive".equalsIgnoreCase(value)) {
          keepAlive = true;
          }
        */
      } else if (header.equals(DefaultHeaders.EXPECT_NAME)) {
        if (header.valueEquals(DefaultHeaders.EXPECT_100_VALUE)) sendAck = true;
        else
          throw new ServletException(sm.getString("httpProcessor.parseHeaders.unknownExpectation"));
      } else if (header.equals(DefaultHeaders.TRANSFER_ENCODING_NAME)) {
        // request.setTransferEncoding(header);
      }

      request.nextHeader();
    }
  }