private ServletAction routeRequest(HttpServletRequest request) {
    //  URL routing for S3 REST calls.
    String pathInfo = request.getPathInfo();
    String bucketName = null;
    String key = null;

    String serviceEndpoint = ServiceProvider.getInstance().getServiceEndpoint();
    String host = request.getHeader("Host");

    // Check for unrecognized forms of URI information in request

    if ((pathInfo == null) || (pathInfo.indexOf('/') != 0))
      if ("POST".equalsIgnoreCase(request.getMethod()))
      // Case where request is POST operation with no pathinfo
      // This is the POST alternative to PUT described at s3.amazonaws.com API doc page 141
      {
        return routePlainPostRequest(request);
      }

    // Irrespective of whether the requester is using subdomain or full host naming of path
    // expressions
    // to buckets, wherever the request is made up of a service endpoint followed by a /, in AWS S3
    // this always
    // conveys a ListAllMyBuckets command

    if ((serviceEndpoint.equalsIgnoreCase(host)) && (pathInfo.equalsIgnoreCase("/"))) {
      request.setAttribute(S3Constants.BUCKET_ATTR_KEY, "/");
      return new S3BucketAction(); // for ListAllMyBuckets
    }

    // Because there is a leading / at position 0 of pathInfo, now subtract this to process the
    // remainder
    pathInfo = pathInfo.substring(1);

    if (ServiceProvider.getInstance().getUseSubDomain()) {

      // -> verify the format of the bucket name
      int endPos = host.indexOf(ServiceProvider.getInstance().getMasterDomain());
      if (endPos > 0) {
        bucketName = host.substring(0, endPos);
        S3Engine.verifyBucketName(bucketName, false);
        request.setAttribute(S3Constants.BUCKET_ATTR_KEY, bucketName);
      } else request.setAttribute(S3Constants.BUCKET_ATTR_KEY, "");

      if (pathInfo == null || pathInfo.equalsIgnoreCase("/")) {
        return new S3BucketAction();
      } else {
        String objectKey = pathInfo.substring(1);
        request.setAttribute(S3Constants.OBJECT_ATTR_KEY, objectKey);
        return new S3ObjectAction();
      }
    } else {

      int endPos = pathInfo.indexOf('/'); // Subsequent / character?

      if (endPos < 1) {
        bucketName = pathInfo;
        S3Engine.verifyBucketName(bucketName, false);
        request.setAttribute(S3Constants.BUCKET_ATTR_KEY, bucketName);
        return new S3BucketAction();
      } else {
        bucketName = pathInfo.substring(0, endPos);
        key = pathInfo.substring(endPos + 1);
        S3Engine.verifyBucketName(bucketName, false);

        if (!key.isEmpty()) {
          request.setAttribute(S3Constants.BUCKET_ATTR_KEY, bucketName);
          request.setAttribute(S3Constants.OBJECT_ATTR_KEY, pathInfo.substring(endPos + 1));
          return new S3ObjectAction();
        } else {
          request.setAttribute(S3Constants.BUCKET_ATTR_KEY, bucketName);
          return new S3BucketAction();
        }
      }
    }
  }