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);
}
}
Aggregations