Search in sources :

Example 6 with Clock

use of com.google.appengine.tools.development.Clock in project appengine-java-standard by GoogleCloudPlatform.

the class UploadBlobServlet method handleUpload.

// <internal25>
@SuppressWarnings("InputStreamSlowMultibyteRead")
private void handleUpload(final HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    String sessionId = getSessionId(req);
    BlobUploadSession session = uploadSessionStorage.loadSession(sessionId);
    if (session == null) {
        resp.sendError(HttpServletResponse.SC_NOT_FOUND, "No upload session: " + sessionId);
        return;
    }
    Map<String, List<String>> blobKeys = new HashMap<String, List<String>>();
    Map<String, List<Map<String, String>>> blobInfos = new HashMap<String, List<Map<String, String>>>();
    final Map<String, List<String>> otherParams = new HashMap<String, List<String>>();
    try {
        MimeMultipart multipart = MultipartMimeUtils.parseMultipartRequest(req);
        int parts = multipart.getCount();
        // partial uploads.
        if (session.hasMaxUploadSizeBytes() || session.hasMaxUploadSizeBytesPerBlob()) {
            int totalSize = 0;
            int largestBlobSize = 0;
            for (int i = 0; i < parts; i++) {
                BodyPart part = multipart.getBodyPart(i);
                if (part.getFileName() != null && !part.getFileName().isEmpty()) {
                    int size = part.getSize();
                    if (size != -1) {
                        totalSize += size;
                        largestBlobSize = Math.max(size, largestBlobSize);
                    } else {
                        logger.log(Level.WARNING, "Unable to determine size of upload part named " + part.getFileName() + "." + " Upload limit checks may not be accurate.");
                    }
                }
            }
            if (session.hasMaxUploadSizeBytesPerBlob() && session.getMaxUploadSizeBytesPerBlob() < largestBlobSize) {
                resp.sendError(HttpServletResponse.SC_REQUEST_ENTITY_TOO_LARGE, UPLOAD_BLOB_TOO_LARGE_RESPONSE);
                return;
            }
            if (session.hasMaxUploadSizeBytes() && session.getMaxUploadSizeBytes() < totalSize) {
                resp.sendError(HttpServletResponse.SC_REQUEST_ENTITY_TOO_LARGE, UPLOAD_TOTAL_TOO_LARGE_RESPONSE);
                return;
            }
        }
        for (int i = 0; i < parts; i++) {
            BodyPart part = multipart.getBodyPart(i);
            String fieldName = MultipartMimeUtils.getFieldName(part);
            if (part.getFileName() != null) {
                if (part.getFileName().length() > 0) {
                    BlobKey blobKey = assignBlobKey(session);
                    List<String> keys = blobKeys.get(fieldName);
                    if (keys == null) {
                        keys = new ArrayList<String>();
                        blobKeys.put(fieldName, keys);
                    }
                    keys.add(blobKey.getKeyString());
                    MessageDigest digest = MessageDigest.getInstance("MD5");
                    boolean swallowDueToThrow = true;
                    OutputStream outStream = getBlobStorage().storeBlob(blobKey);
                    try {
                        InputStream inStream = part.getInputStream();
                        try {
                            final int bufferSize = (1 << 16);
                            byte[] buffer = new byte[bufferSize];
                            while (true) {
                                int bytesRead = inStream.read(buffer);
                                if (bytesRead == -1) {
                                    break;
                                }
                                outStream.write(buffer, 0, bytesRead);
                                digest.update(buffer, 0, bytesRead);
                            }
                            outStream.close();
                            byte[] hash = digest.digest();
                            StringBuilder hashString = new StringBuilder();
                            for (int j = 0; j < hash.length; j++) {
                                String hexValue = Integer.toHexString(0xFF & hash[j]);
                                if (hexValue.length() == 1) {
                                    hashString.append("0");
                                }
                                hashString.append(hexValue);
                            }
                            String originalContentType = part.getContentType();
                            String newContentType = createContentType(blobKey);
                            DataSource dataSource = MultipartMimeUtils.createDataSource(newContentType, new byte[0]);
                            part.setDataHandler(new DataHandler(dataSource));
                            part.addHeader("Content-type", newContentType);
                            Clock clock = apiProxyLocal.getClock();
                            blobInfoStorage.saveBlobInfo(new BlobInfo(blobKey, originalContentType, new Date(clock.getCurrentTime()), part.getFileName(), part.getSize(), hashString.toString()));
                            swallowDueToThrow = false;
                        } finally {
                            Closeables.close(inStream, swallowDueToThrow);
                        }
                    } finally {
                        Closeables.close(outStream, swallowDueToThrow);
                    }
                    // This codes must be run after the BlobInfo is persisted locally.
                    List<Map<String, String>> infos = blobInfos.get(fieldName);
                    if (infos == null) {
                        infos = new ArrayList<Map<String, String>>();
                        blobInfos.put(fieldName, infos);
                    }
                    infos.add(getInfoFromStorage(blobKey, session));
                }
            } else {
                List<String> values = otherParams.get(fieldName);
                if (values == null) {
                    values = new ArrayList<String>();
                    otherParams.put(fieldName, values);
                }
                values.add(MultipartMimeUtils.getTextContent(part));
            }
        }
        req.setAttribute(UPLOADED_BLOBKEY_ATTR, blobKeys);
        req.setAttribute(UPLOADED_BLOBINFO_ATTR, blobInfos);
        uploadSessionStorage.deleteSession(sessionId);
        ByteArrayOutputStream modifiedRequest = new ByteArrayOutputStream();
        String oldValue = System.setProperty("mail.mime.foldtext", "false");
        try {
            multipart.writeTo(modifiedRequest);
        } finally {
            if (oldValue == null) {
                System.clearProperty("mail.mime.foldtext");
            } else {
                System.setProperty("mail.mime.foldtext", oldValue);
            }
        }
        final byte[] modifiedRequestBytes = modifiedRequest.toByteArray();
        final ByteArrayInputStream modifiedRequestStream = new ByteArrayInputStream(modifiedRequestBytes);
        final BufferedReader modifiedReader = new BufferedReader(new InputStreamReader(modifiedRequestStream));
        HttpServletRequest wrappedRequest = new HttpServletRequestWrapper(req) {

            @Override
            public String getHeader(String name) {
                if (Ascii.equalsIgnoreCase(name, UPLOAD_HEADER)) {
                    return "true";
                } else if (Ascii.equalsIgnoreCase(name, "Content-Length")) {
                    return String.valueOf(modifiedRequestBytes.length);
                } else {
                    return super.getHeader(name);
                }
            }

            @Override
            public Enumeration<String> getHeaderNames() {
                List<String> headers = Collections.list(super.getHeaderNames());
                headers.add(UPLOAD_HEADER);
                return Collections.enumeration(headers);
            }

            @Override
            public Enumeration<String> getHeaders(String name) {
                if (Ascii.equalsIgnoreCase(name, UPLOAD_HEADER)) {
                    return Collections.enumeration(ImmutableList.of("true"));
                } else if (Ascii.equalsIgnoreCase(name, "Content-Length")) {
                    return Collections.enumeration(ImmutableList.of(String.valueOf(modifiedRequestBytes.length)));
                } else {
                    return super.getHeaders(name);
                }
            }

            @Override
            public int getIntHeader(String name) {
                if (Ascii.equalsIgnoreCase(name, UPLOAD_HEADER)) {
                    throw new NumberFormatException(UPLOAD_HEADER + "does not have an integer value");
                } else if (Ascii.equalsIgnoreCase(name, "Content-Length")) {
                    return modifiedRequestBytes.length;
                } else {
                    return super.getIntHeader(name);
                }
            }

            @Override
            public ServletInputStream getInputStream() {
                return new ServletInputStream() {

                    @Override
                    public int read() {
                        return modifiedRequestStream.read();
                    }

                    @Override
                    public void close() throws IOException {
                        modifiedRequestStream.close();
                    }

                    @Override
                    public boolean isFinished() {
                        return true;
                    }

                    @Override
                    public boolean isReady() {
                        return true;
                    }

                    @Override
                    public void setReadListener(ReadListener readListener) {
                        throw new UnsupportedOperationException();
                    }
                };
            }

            @Override
            public BufferedReader getReader() {
                return modifiedReader;
            }

            @Override
            public Map<String, String[]> getParameterMap() {
                Map<String, String[]> parameters = super.getParameterMap();
                if (otherParams.isEmpty()) {
                    return parameters;
                } else {
                    // HttpServlet.getParameterMap() result is immutable so we need to take a copy.
                    Map<String, String[]> map = new HashMap<>(parameters);
                    for (Map.Entry<String, List<String>> entry : otherParams.entrySet()) {
                        map.put(entry.getKey(), entry.getValue().toArray(new String[0]));
                    }
                    // an immutable map.
                    return Collections.unmodifiableMap(map);
                }
            }

            @Override
            public Enumeration<String> getParameterNames() {
                List<String> allNames = new ArrayList<>();
                Enumeration<String> names = super.getParameterNames();
                while (names.hasMoreElements()) {
                    allNames.add(names.nextElement());
                }
                allNames.addAll(otherParams.keySet());
                return Collections.enumeration(allNames);
            }

            @Override
            public String[] getParameterValues(String name) {
                if (otherParams.containsKey(name)) {
                    return otherParams.get(name).toArray(new String[0]);
                } else {
                    return super.getParameterValues(name);
                }
            }

            @Override
            public String getParameter(String name) {
                if (otherParams.containsKey(name)) {
                    return otherParams.get(name).get(0);
                } else {
                    return super.getParameter(name);
                }
            }
        };
        String successPath = session.getSuccessPath();
        getServletContext().getRequestDispatcher(successPath).forward(wrappedRequest, resp);
    } catch (MessagingException | NoSuchAlgorithmException ex) {
        throw new ServletException(ex);
    }
}
Also used : BodyPart(javax.mail.BodyPart) HashMap(java.util.HashMap) ByteArrayOutputStream(java.io.ByteArrayOutputStream) OutputStream(java.io.OutputStream) ArrayList(java.util.ArrayList) DataHandler(javax.activation.DataHandler) NoSuchAlgorithmException(java.security.NoSuchAlgorithmException) Clock(com.google.appengine.tools.development.Clock) ReadListener(javax.servlet.ReadListener) HttpServletRequest(javax.servlet.http.HttpServletRequest) ServletException(javax.servlet.ServletException) BlobKey(com.google.appengine.api.blobstore.BlobKey) ServletInputStream(javax.servlet.ServletInputStream) MimeMultipart(javax.mail.internet.MimeMultipart) HttpServletRequestWrapper(javax.servlet.http.HttpServletRequestWrapper) ArrayList(java.util.ArrayList) ImmutableList(com.google.common.collect.ImmutableList) List(java.util.List) MessageDigest(java.security.MessageDigest) InputStreamReader(java.io.InputStreamReader) MessagingException(javax.mail.MessagingException) ServletInputStream(javax.servlet.ServletInputStream) ByteArrayInputStream(java.io.ByteArrayInputStream) InputStream(java.io.InputStream) BlobInfo(com.google.appengine.api.blobstore.BlobInfo) ByteArrayOutputStream(java.io.ByteArrayOutputStream) Date(java.util.Date) DataSource(javax.activation.DataSource) ByteArrayInputStream(java.io.ByteArrayInputStream) BufferedReader(java.io.BufferedReader) HashMap(java.util.HashMap) Map(java.util.Map)

Aggregations

Clock (com.google.appengine.tools.development.Clock)6 Test (org.junit.Test)5 TaskQueueBulkAddResponse (com.google.appengine.api.taskqueue.TaskQueuePb.TaskQueueBulkAddResponse)4 TaskQueueQueryAndOwnTasksRequest (com.google.appengine.api.taskqueue.TaskQueuePb.TaskQueueQueryAndOwnTasksRequest)4 TaskQueueQueryAndOwnTasksResponse (com.google.appengine.api.taskqueue.TaskQueuePb.TaskQueueQueryAndOwnTasksResponse)4 Status (com.google.appengine.tools.development.LocalRpcService.Status)4 BlobInfo (com.google.appengine.api.blobstore.BlobInfo)1 BlobKey (com.google.appengine.api.blobstore.BlobKey)1 TaskQueueModifyTaskLeaseRequest (com.google.appengine.api.taskqueue.TaskQueuePb.TaskQueueModifyTaskLeaseRequest)1 TaskQueueModifyTaskLeaseResponse (com.google.appengine.api.taskqueue.TaskQueuePb.TaskQueueModifyTaskLeaseResponse)1 ImmutableList (com.google.common.collect.ImmutableList)1 BufferedReader (java.io.BufferedReader)1 ByteArrayInputStream (java.io.ByteArrayInputStream)1 ByteArrayOutputStream (java.io.ByteArrayOutputStream)1 InputStream (java.io.InputStream)1 InputStreamReader (java.io.InputStreamReader)1 OutputStream (java.io.OutputStream)1 MessageDigest (java.security.MessageDigest)1 NoSuchAlgorithmException (java.security.NoSuchAlgorithmException)1 ArrayList (java.util.ArrayList)1