/**
   * Process the call to the servlet.
   *
   * <p>With regard to reading data from the request, a {@link javax.servlet.ServletInputStream}
   * object for binary data can be obtained by {@link HttpServletRequest#getInputStream()} or a
   * {@link java.io.BufferedReader} can be obtained for character data by using {@link
   * HttpServletRequest#getReader}.
   *
   * <p>With regard to writing data to the response a {@link javax.servlet.ServletOutputStream}
   * object for binary data can be obtained using {@link HttpServletResponse#getOutputStream()}
   * while a {@link java.io.PrintWriter} object can be obtained using {@link
   * HttpServletResponse#getWriter()}.
   *
   * <p>The {@link java.io.ByteArrayOutputStream} class can be used as a means of collecting the
   * bytes contained in the attached file.
   *
   * <p>It would be desirable to have tests for enctype and method.
   *
   * @param req Request object
   * @param res Response object
   * @throws IOException if io problems
   */
  public void service(HttpServletRequest req, HttpServletResponse res) throws IOException {
    ThisPage thisPage = new ThisPage(req, res, config);
    GenericPrinter output = thisPage.getPrinter();
    if (!req.getMethod().equalsIgnoreCase("post")) {
      output.println("<html><head>");
      output.println("<title>Must use POST method</title>");
      output.println("</head><body>");
      output.println("<h1>Must use POST method</h1>");
      output.println("<p>Request used " + req.getMethod() + " method</p>");
      output.println("<p>Must use POST method</p>");
      output.println("</body></html>");
      thisPage.sendContents();
      return;
    } else if (req.getHeader("content-type") == null) {
      output.println("<html><head>");
      output.println("<title>Missing content-type header</title>");
      output.println("</head><body>");
      output.println("<h1>Missing content-type header</h1>");
      output.println(
          "<p>Must use content-type header " + "to specify multipart/form-data encoding</p>");
      output.println("</body></html>");
      thisPage.sendContents();
      return;
    } else if (!req.getHeader("content-type").toLowerCase().startsWith("multipart/form-data")) {
      output.println("<html><head>");
      output.println("<title>Must use multipart/form-data encoding</title>");
      output.println("</head><body>");
      output.println("<h1>Must use multipart/form-data encoding</h1>");
      output.println("<p>content-type is " + req.getHeader("content-type") + " </p>");
      output.println("<p>Must use multipart/form-data encoding</p>");
      output.println("</body></html>");
      thisPage.sendContents();
      return;
    }
    String boundary = extractBoundary(req);
    if (boundary == null) {
      thisPage.addMessage("Unable to extract boundary value");
      thisPage.addMessage(req.getHeader("content-type"));
      thisPage.errorMessage();
      return;
    }
    int counter = 0;
    byte buffer[] = new byte[4096];
    byte extract[];
    int bytesRead = -1;
    ServletInputStream input = req.getInputStream();
    bytesRead = input.readLine(buffer, 0, buffer.length);
    if (!new String(buffer, 0, bytesRead, "ISO8859_1").startsWith("--" + boundary)) {
      thisPage.addMessage(
          "Should be separator "
              + "--"
              + boundary
              + " : "
              + " found "
              + new String(buffer, 0, bytesRead));
      thisPage.errorMessage();
      return;
    }
    while (true) {
      counter++;
      Contents part = new Contents();
      thisPage.addMessage("Starting part " + Integer.toString(counter) + " of form");
      while (true) {

        bytesRead = input.readLine(buffer, 0, buffer.length);
        if (bytesRead < 0) {
          thisPage.addMessage("Unexpected end of packet");
          thisPage.errorMessage();
          return;
        } else {
          String value = new String(buffer, 0, bytesRead, "ISO8859_1");
          if (value.endsWith("\r\n")) {
            value = stripEOL(value);
          }
          if (value.length() == 0) {
            extract = readPart(input, thisPage, part.getTransferEncoding());
            if (thisPage.getTerminateRequest()) {
              return;
            }
            part.setContents(extract);
            thisPage.addElement(part);
            break;
          } else {
            thisPage.addMessage("service method - Parsing line: " + value);
            part.parseLine(value);
          }
        }
      }
      if (thisPage.getEndOfPacket()) {
        break;
      }
    }
    if (thisPage.getTerminateRequest()) {
      return;
    }
    starter(thisPage);
    if (thisPage.getTerminateRequest()) {
      return;
    }
    processor(thisPage);
    if (thisPage.getTerminateRequest()) {
      return;
    }
    ender(thisPage);
    if (thisPage.getTerminateRequest()) {
      return;
    }
    if (thisPage.getRedirectAddress() != null) {
      thisPage
          .getResponse()
          .sendRedirect(thisPage.getResponse().encodeRedirectURL(thisPage.getRedirectAddress()));
    }
  }
 /**
  * Obtain the byte array for this part of the request.
  *
  * <p>It may be necessary to modify this code to handle additional encoding types such as Base64.
  *
  * @param input Object from which data is read
  * @param thisPage Object containing information for this request
  * @param encoding type of character encoding to be used
  * @return Byte array for this part of request
  * @throws IOException if io errors
  */
 protected byte[] readPart(ServletInputStream input, ThisPage thisPage, String encoding)
     throws IOException {
   HttpServletRequest req = thisPage.getRequest();
   String boundary = extractBoundary(req);
   byte buffer[] = new byte[4096];
   int bytesRead = -1;
   ByteArrayOutputStream working = null;
   boolean pendingRN = false;
   working = new ByteArrayOutputStream();
   /*
    * Read body of part
    */
   while (true) {
     bytesRead = input.readLine(buffer, 0, buffer.length);
     if (bytesRead < 0) {
       thisPage.addMessage("readPart method - Section of form not properly ended");
       thisPage.errorMessage();
       return null;
     } else if (bytesRead == 0) {
       thisPage.addMessage("readPart method - Read yielded 0 characters");
       thisPage.errorMessage();
       return null;
     } else if (bytesRead == 1 && buffer[0] == '\n') {
       if (pendingRN) {
         working.write('\r');
         working.write('\n');
         pendingRN = false;
       }
       working.write(buffer[0]);
     } else if (new String(buffer, 0, bytesRead).equals("--" + boundary + "\r\n")) {
       if (!pendingRN) {
         thisPage.addMessage("readPart method - Boundary reached without preceding end of line");
         thisPage.errorMessage();
         return null;
       }
       if (working.size() == 0) {
         return null;
       }
       return working.toByteArray();
     } else if (new String(buffer, 0, bytesRead).equals("--" + boundary + "--\r\n")) {
       thisPage.setEndOfPacket(true);
       if (!pendingRN) {
         thisPage.addMessage(
             "readPart method - Final boundary reached with preceding end of line");
         thisPage.errorMessage();
         return null;
       }
       if (working.size() == 0) {
         return null;
       }
       return working.toByteArray();
     } else if (buffer[bytesRead - 2] == '\r' && buffer[bytesRead - 1] == '\n') {
       if (pendingRN) {
         working.write('\r');
         working.write('\n');
       }
       if (bytesRead > 2) {
         working.write(buffer, 0, bytesRead - 2);
       }
       pendingRN = true;
     } else if (buffer[bytesRead - 1] == '\r') {
       if (pendingRN) {
         working.write('\r');
         working.write('\n');
         pendingRN = false;
       }
       if (bytesRead > 1) {
         working.write(buffer, 0, bytesRead - 1);
       }
       int nextChar = input.read();
       if (nextChar == '\n') {
         pendingRN = true;
       } else {
         working.write('\r');
         working.write(nextChar);
       }
     } else {
       if (pendingRN) {
         working.write('\r');
         working.write('\n');
         pendingRN = false;
       }
       working.write(buffer, 0, bytesRead);
     }
   }
 }
 /**
  * Processing after calling processor method.
  *
  * <p>This method can be overridden in subclasses to provide a class that carries out the desired
  * operation for a group of classes.
  *
  * @see #processor(ThisPage)
  * @param thisPage Information on this HTTP transaction
  * @throws IOException
  */
 public void ender(ThisPage thisPage) throws IOException {
   if (thisPage != null) {
     thisPage.addMessage("Running Servlet.ender");
     thisPage.addMessage("This is a dummy stub that doesn't do any work");
   }
 }