com.google.appinventor.server.UploadServlet.java Source code

Java tutorial

Introduction

Here is the source code for com.google.appinventor.server.UploadServlet.java

Source

// -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2009-2011 Google, All Rights reserved
// Copyright 2011-2012 MIT, All rights reserved
// Released under the MIT License https://raw.github.com/mit-cml/app-inventor/master/mitlicense.txt

package com.google.appinventor.server;

import com.google.appinventor.server.util.CacheHeaders;
import com.google.appinventor.server.util.CacheHeadersImpl;
import com.google.appinventor.shared.rpc.ServerLayout;
import com.google.appinventor.shared.rpc.UploadResponse;
import com.google.appinventor.shared.rpc.project.UserProject;

import org.apache.commons.fileupload.FileItemStream;
import org.apache.commons.fileupload.FileItemIterator;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.logging.Logger;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Servlet for uploading files.
 *
 */
public class UploadServlet extends OdeServlet {

    /*
     * URIs for upload requests are structured as follows:
     *    /<baseurl>/upload/project/<projectname>}
     *    /<baseurl>/upload/file/<projectId>/<filePath>
     *    /<baseurl>/upload/userfile/<filePath>
     */

    // Constants for accessing split URI
    /*
     * Upload kind can be: "project", "file", or "userfile".
     * Constants for these are defined in ServerLayout.
     */
    private static final int UPLOAD_KIND_INDEX = 3;

    // Constants used when upload kind is "project".
    private static final int PROJECT_TITLE_INDEX = 4;
    private static final int SPLIT_LIMIT_PROJECT_SOURCE = 5;

    // Constants used when upload kind is "file".
    // Since the file path may contain slashes, it must be the last component in the URI.
    private static final int PROJECT_ID_INDEX = 4;
    private static final int FILE_PATH_INDEX = 5;
    private static final int SPLIT_LIMIT_FILE = 6;

    // Constants used when upload kind is "userfile".
    // Since the file path may contain slashes, it must be the last component in the URI.
    private static final int USERFILE_PATH_INDEX = 4;
    private static final int SPLIT_LIMIT_USERFILE = 5;

    // Logging support
    private static final Logger LOG = Logger.getLogger(UploadServlet.class.getName());

    // Object used to safely set cache headers in responses
    private static final CacheHeaders CACHE_HEADERS = new CacheHeadersImpl();

    // Content type for response header (to avoid security vulnerabilities)
    private static final String CONTENT_TYPE = "text/html; charset=utf-8";

    private final FileImporter fileImporter = new FileImporterImpl();

    @Override
    public void doPost(HttpServletRequest req, HttpServletResponse resp) {
        setDefaultHeader(resp);

        UploadResponse uploadResponse;

        try {
            String uri = req.getRequestURI();
            // First, call split with no limit parameter.
            String[] uriComponents = uri.split("/");
            String uploadKind = uriComponents[UPLOAD_KIND_INDEX];

            if (uploadKind.equals(ServerLayout.UPLOAD_PROJECT)) {
                uriComponents = uri.split("/", SPLIT_LIMIT_PROJECT_SOURCE);
                String projectName = uriComponents[PROJECT_TITLE_INDEX];
                InputStream uploadedStream;
                try {
                    uploadedStream = getRequestStream(req, ServerLayout.UPLOAD_PROJECT_ARCHIVE_FORM_ELEMENT);
                } catch (Exception e) {
                    throw CrashReport.createAndLogError(LOG, req, null, e);
                }

                try {
                    UserProject userProject = fileImporter.importProject(userInfoProvider.getUserId(), projectName,
                            uploadedStream);
                    String info = userProject.toString();
                    uploadResponse = new UploadResponse(UploadResponse.Status.SUCCESS, 0, info);
                } catch (FileImporterException e) {
                    uploadResponse = e.uploadResponse;
                }
            } else if (uploadKind.equals(ServerLayout.UPLOAD_FILE)) {
                uriComponents = uri.split("/", SPLIT_LIMIT_FILE);
                long projectId = Long.parseLong(uriComponents[PROJECT_ID_INDEX]);
                String fileName = uriComponents[FILE_PATH_INDEX];
                InputStream uploadedStream;
                try {
                    uploadedStream = getRequestStream(req, ServerLayout.UPLOAD_FILE_FORM_ELEMENT);
                } catch (Exception e) {
                    throw CrashReport.createAndLogError(LOG, req, null, e);
                }

                try {
                    long modificationDate = fileImporter.importFile(userInfoProvider.getUserId(), projectId,
                            fileName, uploadedStream);
                    uploadResponse = new UploadResponse(UploadResponse.Status.SUCCESS, modificationDate);
                } catch (FileImporterException e) {
                    uploadResponse = e.uploadResponse;
                }
            } else if (uploadKind.equals(ServerLayout.UPLOAD_USERFILE)) {
                uriComponents = uri.split("/", SPLIT_LIMIT_USERFILE);
                if (USERFILE_PATH_INDEX >= uriComponents.length) {
                    throw CrashReport.createAndLogError(LOG, req, null,
                            new IllegalArgumentException("Missing user file path."));
                }
                String fileName = uriComponents[USERFILE_PATH_INDEX];
                InputStream uploadedStream;
                try {
                    uploadedStream = getRequestStream(req, ServerLayout.UPLOAD_USERFILE_FORM_ELEMENT);
                } catch (Exception e) {
                    throw CrashReport.createAndLogError(LOG, req, null, e);
                }

                fileImporter.importUserFile(userInfoProvider.getUserId(), fileName, uploadedStream);
                uploadResponse = new UploadResponse(UploadResponse.Status.SUCCESS);
            } else {
                throw CrashReport.createAndLogError(LOG, req, null,
                        new IllegalArgumentException("Unknown upload kind: " + uploadKind));
            }

            // Now, get the PrintWriter for the servlet response and print the UploadResponse.
            // On the client side, in the onSubmitComplete method in ode/client/utils/Uploader.java, the
            // UploadResponse value will be retrieved as a String via the
            // FormSubmitCompleteEvent.getResults() method.
            PrintWriter out = resp.getWriter();
            out.print(uploadResponse.formatAsHtml());

        } catch (IOException e) {
            throw CrashReport.createAndLogError(LOG, req, null, e);
        }

        // Set http response information
        resp.setStatus(HttpServletResponse.SC_OK);
    }

    private InputStream getRequestStream(HttpServletRequest req, String expectedFieldName) throws Exception {
        ServletFileUpload upload = new ServletFileUpload();
        FileItemIterator iterator = upload.getItemIterator(req);
        while (iterator.hasNext()) {
            FileItemStream item = iterator.next();
            if (item.getFieldName().equals(expectedFieldName)) {
                return item.openStream();
            }
        }

        throw new IllegalArgumentException("Field " + expectedFieldName + " not found in upload");
    }

    /**
     * Set a default http header to avoid security vulnerabilities.
     */
    private static void setDefaultHeader(HttpServletResponse resp) {
        CACHE_HEADERS.setNotCacheable(resp);
        resp.setContentType(CONTENT_TYPE);
    }
}