1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.mycore.frontend.fileupload;
20
21 import java.io.InputStream;
22 import java.util.Collection;
23 import java.util.Locale;
24 import java.util.Objects;
25 import java.util.Optional;
26 import java.util.zip.ZipEntry;
27 import java.util.zip.ZipInputStream;
28
29 import org.apache.logging.log4j.LogManager;
30 import org.apache.logging.log4j.Logger;
31 import org.mycore.common.MCRSession;
32 import org.mycore.common.MCRSessionMgr;
33 import org.mycore.common.MCRTransactionHelper;
34 import org.mycore.common.config.MCRConfiguration2;
35 import org.mycore.common.content.streams.MCRNotClosingInputStream;
36 import org.mycore.frontend.MCRWebsiteWriteProtection;
37 import org.mycore.frontend.servlets.MCRServlet;
38 import org.mycore.frontend.servlets.MCRServletJob;
39
40 import jakarta.persistence.EntityTransaction;
41 import jakarta.servlet.http.HttpServletResponse;
42 import jakarta.servlet.http.Part;
43
44
45
46
47
48
49
50
51
52
53
54
55
56 public final class MCRUploadViaFormServlet extends MCRServlet {
57
58 private static final long serialVersionUID = 1L;
59
60 private static final Logger LOGGER = LogManager.getLogger(MCRUploadViaFormServlet.class);
61
62 @Override
63 public void doGetPost(MCRServletJob job) throws Exception {
64 guardWebsiteCurrentlyReadOnly();
65
66 Optional<MCRUploadHandler> uh = getUploadHandler(job);
67 if (!uh.isPresent()) {
68 job.getResponse().sendError(HttpServletResponse.SC_BAD_REQUEST, "Parameter 'uploadId' is missing!");
69 return;
70 }
71
72 MCRUploadHandler handler = uh.get();
73 LOGGER.info("UploadHandler form based file upload for ID {}", handler.getID());
74
75 handleUploadedFiles(handler, job.getRequest().getParts());
76
77 job.getResponse().sendRedirect(job.getResponse().encodeRedirectURL(handler.getRedirectURL()));
78 handler.finishUpload();
79 handler.unregister();
80 }
81
82 private void guardWebsiteCurrentlyReadOnly() {
83 if (MCRWebsiteWriteProtection.isActive()) {
84 throw new RuntimeException("System is currently in read-only mode");
85 }
86 }
87
88 private Optional<MCRUploadHandler> getUploadHandler(MCRServletJob job) {
89 return Optional.ofNullable(job.getRequest().getParameter("uploadId")).map(MCRUploadHandlerManager::getHandler);
90 }
91
92 private void handleUploadedFiles(MCRUploadHandler handler, Collection<Part> files) throws Exception {
93 int numFiles = (int) files.stream().map(Part::getSubmittedFileName).filter(Objects::nonNull).count();
94 LOGGER.info("UploadHandler uploading {} file(s)", numFiles);
95 handler.startUpload(numFiles);
96
97 MCRSession session = MCRSessionMgr.getCurrentSession();
98 MCRTransactionHelper.commitTransaction();
99
100 for (Part file : files) {
101 try {
102 handleUploadedFile(handler, file);
103 } finally {
104 file.delete();
105 }
106 }
107
108 MCRTransactionHelper.beginTransaction();
109 }
110
111 private void handleUploadedFile(MCRUploadHandler handler, Part file) throws Exception {
112 String submitted = file.getSubmittedFileName();
113 if (submitted == null || "".equals(submitted)) {
114 return;
115 }
116 try (InputStream in = file.getInputStream()) {
117
118 String path = MCRUploadHelper.getFileName(submitted);
119
120 if (requireDecompressZip(path)) {
121 handleZipFile(handler, in);
122 } else {
123 handleUploadedFile(handler, file.getSize(), path, in);
124 }
125 }
126 }
127
128 private boolean requireDecompressZip(String path) {
129 return MCRConfiguration2.getBoolean("MCR.FileUpload.DecompressZip").orElse(true)
130 && path.toLowerCase(Locale.ROOT).endsWith(".zip");
131 }
132
133 private void handleUploadedFile(MCRUploadHandler handler, long size, String path, InputStream in) throws Exception {
134 LOGGER.info("UploadServlet uploading {}", path);
135 MCRUploadHelper.checkPathName(path);
136
137 EntityTransaction tx = MCRUploadHelper.startTransaction();
138 try {
139 handler.receiveFile(path, in, size, null);
140 MCRUploadHelper.commitTransaction(tx);
141 } catch (Exception exc) {
142 MCRUploadHelper.rollbackAnRethrow(tx, exc);
143 }
144 }
145
146 private void handleZipFile(MCRUploadHandler handler, InputStream in) throws Exception {
147 ZipInputStream zis = new ZipInputStream(in);
148 MCRNotClosingInputStream nis = new MCRNotClosingInputStream(zis);
149 for (ZipEntry entry = zis.getNextEntry(); entry != null; entry = zis.getNextEntry()) {
150 String path = convertAbsolutePathToRelativePath(entry.getName());
151 if (entry.isDirectory()) {
152 LOGGER.debug("UploadServlet skipping ZIP entry {}, is a directory", path);
153 } else {
154 handler.incrementNumFiles();
155 handleUploadedFile(handler, entry.getSize(), path, nis);
156 }
157 }
158 handler.decrementNumFiles();
159 nis.reallyClose();
160 }
161
162 private String convertAbsolutePathToRelativePath(String path) {
163 int pos = path.indexOf(":");
164 if (pos >= 0) {
165 path = path.substring(pos + 1);
166 }
167 while (path.startsWith("\\") || path.startsWith("/")) {
168 path = path.substring(1);
169 }
170 return path;
171 }
172
173 }