This is an automated email from the ASF dual-hosted git repository. rombert pushed a commit to branch issue/SLING-13083 in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-starter-test-services.git
commit a28a37b53a8a723a04832c392e9b2dcd87bca8d6 Author: Robert Munteanu <[email protected]> AuthorDate: Thu Jan 29 15:08:00 2026 +0100 SLING-13083 - Code acessing the "request-parts-iterator" request attribute broken after migration to Jakarta Add a streaming test servlet using the javax.servlet APIs to access uploaded parts. --- .../servlets/StreamedUploadServlet.java | 98 ++++++++++++++++++++++ 1 file changed, 98 insertions(+) diff --git a/src/main/java/org/apache/sling/starter/testservices/servlets/StreamedUploadServlet.java b/src/main/java/org/apache/sling/starter/testservices/servlets/StreamedUploadServlet.java new file mode 100644 index 0000000..a66dce1 --- /dev/null +++ b/src/main/java/org/apache/sling/starter/testservices/servlets/StreamedUploadServlet.java @@ -0,0 +1,98 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.sling.starter.testservices.servlets; + +import javax.servlet.Servlet; +import javax.servlet.ServletException; +import javax.servlet.http.Part; + +import java.io.IOException; +import java.util.Iterator; + +import org.apache.sling.api.SlingHttpServletRequest; +import org.apache.sling.api.SlingHttpServletResponse; +import org.apache.sling.api.servlets.SlingAllMethodsServlet; +import org.apache.sling.servlets.annotations.SlingServletPathsStrict; +import org.osgi.service.component.annotations.Component; + +/** + * Servlet to test streamed upload compatibility with javax.servlet.http.Part. + * + * <p>This servlet retrieves the "request-parts-iterator" request attribute + * set by the Sling Engine during streamed multipart uploads and casts each + * part to {@link javax.servlet.http.Part}.</p> + * + * <p>To trigger streamed upload mode, use either: + * <ul> + * <li>Header: {@code Sling-uploadmode: stream}</li> + * <li>Query parameter: {@code uploadmode=stream}</li> + * </ul> + * </p> + * + * @see <a href="https://issues.apache.org/jira/browse/SLING-13083">SLING-13083</a> + */ +@Component(service = Servlet.class) +@SlingServletPathsStrict(paths = "/bin/streamed-upload", extensions = "txt", methods = "POST") +public class StreamedUploadServlet extends SlingAllMethodsServlet { + + private static final long serialVersionUID = 1L; + private static final String REQUEST_PARTS_ITERATOR_ATTR = "request-parts-iterator"; + + @Override + protected void doPost(SlingHttpServletRequest request, SlingHttpServletResponse response) + throws ServletException, IOException { + + response.setContentType("text/plain"); + response.setCharacterEncoding("UTF-8"); + + // Get the request-parts-iterator attribute set by the Sling Engine + Object iteratorAttr = request.getAttribute(REQUEST_PARTS_ITERATOR_ATTR); + + if (iteratorAttr == null) { + response.getWriter() + .write("ERROR: " + REQUEST_PARTS_ITERATOR_ATTR + " attribute not found. " + + "Make sure to use 'Sling-uploadmode: stream' header or 'uploadmode=stream' parameter."); + response.setStatus(SlingHttpServletResponse.SC_BAD_REQUEST); + return; + } + + @SuppressWarnings("unchecked") + Iterator<Part> partsIterator = (Iterator<Part>) iteratorAttr; + + int partCount = 0; + StringBuilder sb = new StringBuilder(); + + while (partsIterator.hasNext()) { + // This cast to javax.servlet.http.Part will throw ClassCastException + // if the engine bug (SLING-13083) is present + Part part = partsIterator.next(); + + partCount++; + sb.append("Part ").append(partCount).append(": name=").append(part.getName()); + String filename = part.getSubmittedFileName(); + if (filename != null) { + sb.append(", filename=").append(filename); + } + sb.append("\n"); + } + + response.getWriter().write("OK: Processed " + partCount + " part(s) as javax.servlet.http.Part\n"); + response.getWriter().write(sb.toString()); + } +}
