All Downloads are FREE. Search and download functionalities are using the official Maven repository.

gwtuploadsample.server.S3UploadServlet Maven / Gradle / Ivy

The newest version!
package gwtuploadsample.server;

import gwtupload.shared.UConsts;

import java.io.IOException;
import java.io.PrintWriter;
import java.security.GeneralSecurityException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringEscapeUtils;
import org.apache.log4j.Logger;
import org.codehaus.jackson.map.ObjectMapper;

import com.google.common.base.Charsets;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;

public class S3UploadServlet extends HttpServlet {

  private static final long serialVersionUID = 1L;
  private static final Logger logger = Logger.getLogger(S3UploadServlet.class);

  private String awsBucketName;
  private String awsAccessKey;
  private byte[] awsSecretKey;

  @Override
  public void init(ServletConfig config) throws ServletException {
    super.init(config);
    awsBucketName = getInitParameter("awsBucketName");
    if (awsBucketName == null) {
      throw new ServletException(getClass().getSimpleName() + ": awsBucketName init-param is missing.");
    }

    awsAccessKey = getInitParameter("awsAccessKey");
    if (awsAccessKey == null) {
      throw new ServletException(getClass().getSimpleName() + ": awsAccessKey init-param is missing.");
    }

    String awsSecretKeyString = getInitParameter("awsSecretKey");
    if (awsSecretKeyString == null) {
      throw new ServletException(getClass().getSimpleName() + ": awsSecretKey init-param is missing.");
    }
    awsSecretKey = awsSecretKeyString.getBytes(Charsets.UTF_8);
  }

  @Override
  protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
    if ("true".equals(request.getParameter(UConsts.PARAM_SESSION))) {
      doSession(request, response);
      return;
    }

    if ("true".equals(request.getParameter(UConsts.PARAM_BLOBSTORE))) {
      doBlobstore(request, response);
      return;
    }

    if ("true".equals(request.getParameter("done"))) {
      doDone(request, response);
      return;
    }

    if (request.getParameter("show") != null) {
      doShow(request, response);
      return;
    }

    response.setStatus(HttpServletResponse.SC_NOT_IMPLEMENTED);
    logger.warn("Unsupported usage of " + getClass().getSimpleName() + " with queryString: " + request.getQueryString());
  }

  private void doSession(HttpServletRequest request, HttpServletResponse response) throws IOException {
    response.setContentType("text/xml; charset=UTF-8");
    PrintWriter out = response.getWriter();
    out.println("");
    out.println(
      "" +
        "<" + UConsts.TAG_BLOBSTORE +">true" +
      ""
    );
  }

  private void doBlobstore(HttpServletRequest request, HttpServletResponse response) throws IOException {
    response.setContentType("text/xml; charset=UTF-8");
    PrintWriter out = response.getWriter();
    out.println("");

    String redirect = request.getRequestURL().toString() + "?done=true"; // redirect amazon to this servlet for doDone

    DateFormat iso8601 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
    Calendar expiration = Calendar.getInstance();
    expiration.setTime(new Date());
    expiration.add(Calendar.HOUR, 24);
    String policyDocument = new ObjectMapper().writeValueAsString(ImmutableMap.of(
      "expiration", iso8601.format(expiration.getTime()),
      "conditions", ImmutableList.of(
        ImmutableMap.of("bucket", awsBucketName),
        ImmutableList.of("starts-with", "$key", ""),
        ImmutableMap.of("acl", "public-read"),
        ImmutableMap.of("redirect", redirect),
        ImmutableList.of("content-length-range", 0, 10*1024*1024) // maximum 10MB
      )
    ));

    String policy = new String(Base64.encodeBase64(policyDocument.getBytes(Charsets.UTF_8)));
    Mac hmac = null;
    try {
      hmac = Mac.getInstance("HmacSHA1");
      hmac.init(new SecretKeySpec(awsSecretKey, "HmacSHA1"));
    } catch (GeneralSecurityException e) {
      logger.error("Cannot sign policy in " + getClass().getSimpleName() + ".doBlobstore: " + e.getMessage(), e);
      out.println(
        "" +
          "<" + UConsts.TAG_ERROR + ">" + StringEscapeUtils.escapeXml(e.getMessage()) + "" +
        ""
      );
      return;
    }

    String fileKey = request.getParameter(UConsts.PARAM_NAME);
    String signature = new String(Base64.encodeBase64(hmac.doFinal(policy.getBytes(Charsets.UTF_8))));
    String blobPath = "http://s3.amazonaws.com/" + awsBucketName;

    out.println(
      "" +
        "<" + UConsts.TAG_BLOBSTORE_PATH + ">" + StringEscapeUtils.escapeXml(blobPath) + "" +
        "<" + UConsts.TAG_BLOBSTORE_NAME + ">file" +
        blobParam("key", fileKey) +
        blobParam("acl", "public-read") +
        blobParam("AWSAccessKeyId", awsAccessKey) +
        blobParam("policy", policy) +
        blobParam("signature", signature) +
        blobParam("redirect", redirect) +
      ""
    );
  }

  private static String blobParam(String name, String value) {
    return "<" + UConsts.TAG_BLOBSTORE_PARAM + " " + UConsts.ATTR_BLOBSTORE_PARAM_NAME + "=\"" + StringEscapeUtils.escapeXml(name) + "\">" + StringEscapeUtils.escapeXml(value) + "";
  }

  private void doDone(HttpServletRequest request, HttpServletResponse response) throws IOException {
    response.setContentType("text/plain; charset=UTF-8");
    PrintWriter out = response.getWriter();

    StringBuilder xml = new StringBuilder();
    xml.append("\n");
    xml.append(
      "" +
        "<" + UConsts.TAG_FIELD + ">" + StringEscapeUtils.escapeXml(request.getParameter("key")) + "" +
        "<" + UConsts.TAG_FILE + ">" +
          "<" + UConsts.TAG_CTYPE + "> " + // content-type is unknown
          "<" + UConsts.TAG_SIZE + ">0" + // size is unknown
          "<" + UConsts.TAG_NAME + ">" + StringEscapeUtils.escapeXml(request.getParameter("key")) + "" +
        "" +
        "<" + UConsts.TAG_FINISHED + ">" + UConsts.TAG_OK + "" +
        "<" + UConsts.TAG_MESSAGE + ">" +
      ""
    );
    out.print(UConsts.TAG_MSG_START + xml.toString().replaceAll("<", UConsts.TAG_MSG_LT).replaceAll(">", UConsts.TAG_MSG_GT) + UConsts.TAG_MSG_END);
  }

  private void doShow(HttpServletRequest request, HttpServletResponse response) {
    response.setStatus(301);
    String name = request.getParameter(UConsts.PARAM_SHOW);
    name = name.replaceFirst("-[\\d]+$", "");
    response.setHeader("Location", "http://s3.amazonaws.com/" + awsBucketName + "/" + name);
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy