/**
   * A DIME request is really a SOAP request that we are dealing with, and so its authentication is
   * the SOAP authentication approach. Since Axis2 does not handle DIME messages we deal with them
   * here.
   *
   * @param request
   * @param response
   */
  private void processDimeRequest(HttpServletRequest request, HttpServletResponse response) {
    S3PutObjectRequest putRequest = null;
    S3PutObjectResponse putResponse = null;
    int bytesRead = 0;

    S3Engine engine = new S3Engine();

    try {
      logRequest(request);

      MultiPartDimeInputStream ds = new MultiPartDimeInputStream(request.getInputStream());

      // -> the first stream MUST be the SOAP party
      if (ds.nextInputStream()) {
        // logger.debug( "DIME msg [" + ds.getStreamType() + "," + ds.getStreamTypeFormat() + "," +
        // ds.getStreamId() + "]" );
        byte[] buffer = new byte[8192];
        bytesRead = ds.read(buffer, 0, 8192);
        // logger.debug( "DIME SOAP Bytes read: " + bytesRead );
        ByteArrayInputStream bis = new ByteArrayInputStream(buffer, 0, bytesRead);
        putRequest = toEnginePutObjectRequest(bis);
      }

      // -> we only need to support a DIME message with two bodyparts
      if (null != putRequest && ds.nextInputStream()) {
        InputStream is = ds.getInputStream();
        putRequest.setData(is);
      }

      // -> need to do SOAP level auth here, on failure return the SOAP fault
      StringBuffer xml = new StringBuffer();
      String AWSAccessKey = putRequest.getAccessKey();
      UserInfo info = ServiceProvider.getInstance().getUserInfo(AWSAccessKey);
      try {
        S3SoapAuth.verifySignature(
            putRequest.getSignature(),
            "PutObject",
            putRequest.getRawTimestamp(),
            AWSAccessKey,
            info.getSecretKey());

      } catch (AxisFault e) {
        String reason = e.toString();
        int start = reason.indexOf(".AxisFault:");
        if (-1 != start) reason = reason.substring(start + 11);

        xml.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
        xml.append(
            "<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" >\n");
        xml.append("<soap:Body>\n");
        xml.append("<soap:Fault>\n");
        xml.append("<faultcode>").append(e.getFaultCode().toString()).append("</faultcode>\n");
        xml.append("<faultstring>").append(reason).append("</faultstring>\n");
        xml.append("</soap:Fault>\n");
        xml.append("</soap:Body></soap:Envelope>");

        endResponse(response, xml.toString());
        return;
      }

      // -> PutObject S3 Bucket Policy would be done in the engine.handleRequest() call
      UserContext.current()
          .initContext(AWSAccessKey, info.getSecretKey(), AWSAccessKey, "S3 DIME request", request);
      putResponse = engine.handleRequest(putRequest);

      xml.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
      xml.append(
          "<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:tns=\"http://s3.amazonaws.com/doc/2006-03-01/\">");
      xml.append("<soap:Body>");
      xml.append("<tns:PutObjectResponse>");
      xml.append("<tns:PutObjectResponse>");
      xml.append("<tns:ETag>\"").append(putResponse.getETag()).append("\"</tns:ETag>");
      xml.append("<tns:LastModified>")
          .append(DatatypeConverter.printDateTime(putResponse.getLastModified()))
          .append("</tns:LastModified>");
      xml.append("</tns:PutObjectResponse></tns:PutObjectResponse>");
      xml.append("</soap:Body></soap:Envelope>");

      endResponse(response, xml.toString());
    } catch (PermissionDeniedException e) {
      logger.error("Unexpected exception " + e.getMessage(), e);
      response.setStatus(403);
      endResponse(response, "Access denied");
    } catch (Throwable e) {
      logger.error("Unexpected exception " + e.getMessage(), e);
    } finally {
    }
  }
  /**
   * POST requests do not get authenticated on entry. The associated access key and signature
   * headers are embedded in the message not encoded as HTTP headers.
   */
  private void processRequest(
      HttpServletRequest request, HttpServletResponse response, String method) {
    Transaction txn = Transaction.open("cloudbridge", Transaction.AWSAPI_DB, true);
    try {
      logRequest(request);

      // Our extensions to the S3 REST API for simple management actions
      // are conveyed with Request parameter "Action".
      // The present extensions are either to set up the user credentials
      // (see the cloud-bridge-register script for more detail) or
      // to report our version of this capability.
      // -> unauthenticated calls, should still be done over HTTPS
      String cloudAction = request.getParameter("Action");

      if (!isS3APIEnabled) {
        throw new RuntimeException("Amazon S3 API is disabled.");
      }

      if (null != cloudAction) {
        if (cloudAction.equalsIgnoreCase("SetUserKeys")) {
          setUserKeys(request, response);
          return;
        }

        if (cloudAction.equalsIgnoreCase("SetCertificate"))
          // At present a noop
          return;

        if (cloudAction.equalsIgnoreCase("CloudS3Version")) {
          cloudS3Version(request, response);
          return;
        }
      }

      txn.start();
      // -> authenticated calls
      if (!((method.equalsIgnoreCase("POST")
          && !(request.getQueryString().equalsIgnoreCase("delete"))))) {
        S3AuthParams params = extractRequestHeaders(request);
        authenticateRequest(request, params);
      }

      ServletAction action = routeRequest(request);
      if (action != null) {
        action.execute(request, response);
      } else {
        response.setStatus(404);
        endResponse(response, "File not found");
      }
      txn.close();
    } catch (InvalidBucketName e) {
      logger.error("Unexpected exception " + e.getMessage(), e);
      response.setStatus(400);
      endResponse(response, "Invalid Bucket Name - " + e.toString());
    } catch (PermissionDeniedException e) {
      logger.error("Unexpected exception " + e.getMessage(), e);
      response.setStatus(403);
      endResponse(response, "Access denied - " + e.toString());
    } catch (Throwable e) {
      logger.error("Unexpected exception " + e.getMessage(), e);
      response.setStatus(404);
      endResponse(response, "Bad request");

    } finally {

      try {
        response.flushBuffer();
      } catch (IOException e) {
        logger.error("Unexpected exception " + e.getMessage(), e);
      }
    }
  }