throw new IllegalStateException("Not multipart!");
}
ErrorUtils.errorIfNull(selectedType, "type");
ObjectField previewField = getPreviewField(selectedType);
if (previewField == null) {
throw new IllegalStateException("No file field!");
}
FileItem[] files = request.getFileItems("file");
StringBuilder js = new StringBuilder();
if (files != null && files.length > 0) {
Object common = selectedType.createObject(page.param(UUID.class, "typeForm-" + selectedType.getId()));
page.updateUsingParameters(common);
for (FileItem file : files) {
// Checks to make sure the file's content type is valid
String groupsPattern = Settings.get(String.class, "cms/tool/fileContentTypeGroups");
Set<String> contentTypeGroups = new SparseSet(ObjectUtils.isBlank(groupsPattern) ? "+/" : groupsPattern);
if (!contentTypeGroups.contains(file.getContentType())) {
page.getErrors().add(new IllegalArgumentException(String.format(
"Invalid content type [%s]. Must match the pattern [%s].",
file.getContentType(), contentTypeGroups)));
continue;
}
// Disallow HTML disguising as other content types per:
// http://www.adambarth.com/papers/2009/barth-caballero-song.pdf
if (!contentTypeGroups.contains("text/html")) {
InputStream input = file.getInputStream();
try {
byte[] buffer = new byte[1024];
String data = new String(buffer, 0, input.read(buffer)).toLowerCase(Locale.ENGLISH);
String ptr = data.trim();
if (ptr.startsWith("<!") ||
ptr.startsWith("<?") ||
data.startsWith("<html") ||
data.startsWith("<script") ||
data.startsWith("<title") ||
data.startsWith("<body") ||
data.startsWith("<head") ||
data.startsWith("<plaintext") ||
data.startsWith("<table") ||
data.startsWith("<img") ||
data.startsWith("<pre") ||
data.startsWith("text/html") ||
data.startsWith("<a") ||
ptr.startsWith("<frameset") ||
ptr.startsWith("<iframe") ||
ptr.startsWith("<link") ||
ptr.startsWith("<base") ||
ptr.startsWith("<style") ||
ptr.startsWith("<div") ||
ptr.startsWith("<p") ||
ptr.startsWith("<font") ||
ptr.startsWith("<applet") ||
ptr.startsWith("<meta") ||
ptr.startsWith("<center") ||
ptr.startsWith("<form") ||
ptr.startsWith("<isindex") ||
ptr.startsWith("<h1") ||
ptr.startsWith("<h2") ||
ptr.startsWith("<h3") ||
ptr.startsWith("<h4") ||
ptr.startsWith("<h5") ||
ptr.startsWith("<h6") ||
ptr.startsWith("<b") ||
ptr.startsWith("<br")) {
page.getErrors().add(new IllegalArgumentException(String.format(
"Can't upload [%s] file disguising as HTML!",
file.getContentType())));
continue;
}
} finally {
input.close();
}
}
if (file.getSize() == 0) {
continue;
}
StringBuilder path = new StringBuilder();
String random = UUID.randomUUID().toString().replace("-", "");
String fileName = file.getName();
int lastDotAt = fileName.indexOf('.');
String extension;
if (lastDotAt > -1) {
extension = fileName.substring(lastDotAt);
fileName = fileName.substring(0, lastDotAt);
} else {
extension = "";
}
if (ObjectUtils.isBlank(fileName)) {
fileName = UUID.randomUUID().toString().replace("-", "");
}
path.append(random.substring(0, 2));
path.append('/');
path.append(random.substring(2, 4));
path.append('/');
path.append(random.substring(4));
path.append('/');
path.append(StringUtils.toNormalized(fileName));
path.append(extension);
Map<String, List<String>> httpHeaders = new LinkedHashMap<String, List<String>>();
httpHeaders.put("Cache-Control", Collections.singletonList("public, max-age=31536000"));
httpHeaders.put("Content-Length", Collections.singletonList(String.valueOf(file.getSize())));
httpHeaders.put("Content-Type", Collections.singletonList(file.getContentType()));
String storageSetting = previewField.as(ToolUi.class).getStorageSetting();
StorageItem item = StorageItem.Static.createIn(storageSetting != null ? Settings.getOrDefault(String.class, storageSetting, null) : null);
String contentType = file.getContentType();
item.setPath(path.toString());
item.setContentType(contentType);
item.getMetadata().put("http.headers", httpHeaders);
item.getMetadata().put("originalFilename", fileName);
item.setData(file.getInputStream());
if (contentType != null && contentType.startsWith("image/")) {
InputStream fileInput = file.getInputStream();
try {
ImageMetadataMap metadata = new ImageMetadataMap(fileInput);
List<Throwable> errors = metadata.getErrors();
item.getMetadata().putAll(metadata);
if (!errors.isEmpty()) {
LOGGER.info("Can't read image metadata!", new AggregateException(errors));
}
} finally {
IoUtils.closeQuietly(fileInput);
}
}
item.save();
Object object = selectedType.createObject(null);
State state = State.getInstance(object);
state.setValues(State.getInstance(common));
Site site = page.getSite();
if (site != null &&
site.getDefaultVariation() != null) {
state.as(Variation.Data.class).setInitialVariation(site.getDefaultVariation());
}
state.put(previewField.getInternalName(), item);
state.as(BulkUploadDraft.class).setContainerId(containerId);
page.publish(state);
js.append("$addButton.repeatable('add', function() {");
js.append("var $added = $(this);");
js.append("$input = $added.find(':input.objectId').eq(0);");
js.append("$input.attr('data-label', '").append(StringUtils.escapeJavaScript(state.getLabel())).append("');");
js.append("$input.attr('data-preview', '").append(StringUtils.escapeJavaScript(page.getPreviewThumbnailUrl(object))).append("');");
js.append("$input.val('").append(StringUtils.escapeJavaScript(state.getId().toString())).append("');");
js.append("$input.change();");
js.append("});");
}
}
if (page.getErrors().isEmpty()) {
page.writeStart("div", "id", page.createId()).writeEnd();
page.writeStart("script", "type", "text/javascript");
page.write("if (typeof jQuery !== 'undefined') (function($, win, undef) {");
page.write("var $page = $('#" + page.getId() + "'),");
page.write("$init = $page.popup('source').repeatable('closestInit'),");
page.write("$addButton = $init.find('.addButton').eq(0),");
page.write("$input;");
page.write("if ($addButton.length > 0) {");
page.write(js.toString());
page.write("$page.popup('close');");
page.write("} else {");
page.write("win.location.reload();");
page.write("}");
page.write("})(jQuery, window);");
page.writeEnd();
return;
}
} catch (Exception error) {
postError = error;
}
}
Set<ObjectType> typesSet = new HashSet<ObjectType>();
for (UUID typeId : page.params(UUID.class, "typeId")) {
ObjectType type = environment.getTypeById(typeId);
if (type != null) {
for (ObjectType t : type.as(ToolUi.class).findDisplayTypes()) {
for (ObjectField field : t.getFields()) {
if (ObjectField.FILE_TYPE.equals(field.getInternalItemType())) {
typesSet.add(t);
break;
}
}
}
}
}
List<ObjectType> types = new ArrayList<ObjectType>(typesSet);
Collections.sort(types, new ObjectFieldComparator("name", false));
page.writeStart("h1").writeHtml("Upload Files").writeEnd();
page.writeStart("form",
"method", "post",
"enctype", "multipart/form-data",
"action", page.url(null));
page.writeElement("input",
"type", "hidden",
"name", CONTAINER_ID_PARAMETER,
"value", containerId);
for (ObjectType type : types) {
page.writeElement("input", "type", "hidden", "name", "typeId", "value", type.getId());
}
if (postError != null) {
page.writeStart("div", "class", "message message-error");
page.writeObject(postError);
page.writeEnd();
} else if (!page.getErrors().isEmpty()) {
page.writeStart("div", "class", "message message-error");
for (Throwable error : page.getErrors()) {
page.writeHtml(error.getMessage());
}
page.writeEnd();
}
page.writeStart("div", "class", "inputContainer");
page.writeStart("div", "class", "inputLabel");
page.writeStart("label", "for", page.createId()).writeHtml("Files").writeEnd();
page.writeEnd();
page.writeStart("div", "class", "inputSmall");
page.writeElement("input",
"id", page.getId(),
"type", "file",
"name", "file",
"multiple", "multiple");
page.writeEnd();
page.writeEnd();
page.writeStart("div", "class", "inputContainer");
page.writeStart("div", "class", "inputLabel");
page.writeStart("label", "for", page.createId()).writeHtml("Type").writeEnd();
page.writeEnd();
page.writeStart("div", "class", "inputSmall");
page.writeStart("select",
"class", "toggleable",
"data-root", "form",
"id", page.getId(),
"name", "type");
for (ObjectType type : types) {
page.writeStart("option",
"data-hide", ".typeForm",
"data-show", ".typeForm-" + type.getId(),
"selected", type.equals(selectedType) ? "selected" : null,
"value", type.getId());
page.writeHtml(type.getDisplayName());
page.writeEnd();
}
page.writeEnd();
page.writeEnd();
page.writeEnd();
for (ObjectType type : types) {
String name = "typeForm-" + type.getId();
Object common = type.createObject(null);
page.writeStart("div", "class", "typeForm " + name);
page.writeElement("input",
"type", "hidden",
"name", name,
"value", State.getInstance(common).getId());
ObjectField previewField = getPreviewField(type);
HttpServletRequest request = page.getRequest();
Object oldExcludes = request.getAttribute("excludeFields");
try {
if (previewField != null) {
request.setAttribute("excludeFields", Arrays.asList(previewField.getInternalName()));
}
page.writeFormFields(common);
} finally {