Skip to content

Commit c15dd31

Browse files
authored
Merge branch 'apache:main' into main
2 parents f0cffd6 + 7f6e87e commit c15dd31

File tree

347 files changed

+2095
-1080
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

347 files changed

+2095
-1080
lines changed

bom/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
<parent>
2121
<groupId>org.apache.cxf</groupId>
2222
<artifactId>cxf</artifactId>
23-
<version>4.1.4-SNAPSHOT</version>
23+
<version>4.1.5-SNAPSHOT</version>
2424
</parent>
2525
<modelVersion>4.0.0</modelVersion>
2626
<artifactId>cxf-bom</artifactId>

core/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
<parent>
2828
<groupId>org.apache.cxf</groupId>
2929
<artifactId>cxf-parent</artifactId>
30-
<version>4.1.4-SNAPSHOT</version>
30+
<version>4.1.5-SNAPSHOT</version>
3131
<relativePath>../parent/pom.xml</relativePath>
3232
</parent>
3333
<properties>
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
/**
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
package org.apache.cxf.attachment;
21+
22+
import java.io.IOException;
23+
import java.io.InputStream;
24+
import java.io.PushbackInputStream;
25+
import java.nio.charset.StandardCharsets;
26+
import java.util.List;
27+
import java.util.Map;
28+
import java.util.regex.Matcher;
29+
import java.util.regex.Pattern;
30+
31+
import org.apache.cxf.helpers.IOUtils;
32+
import org.apache.cxf.message.Attachment;
33+
import org.apache.cxf.message.Message;
34+
import org.apache.cxf.message.MessageUtils;
35+
36+
public class AttachmentBoundaryDeserializer {
37+
private static final Pattern INPUT_STREAM_BOUNDARY_PATTERN = Pattern.compile("^--(\\S*)$", Pattern.MULTILINE);
38+
private static final int PUSHBACK_AMOUNT = 2048;
39+
40+
private final int maxHeaderLength;
41+
private final Message message;
42+
43+
public AttachmentBoundaryDeserializer(Message message) {
44+
this.message = message;
45+
this.maxHeaderLength = MessageUtils.getContextualInteger(message,
46+
AttachmentDeserializer.ATTACHMENT_MAX_HEADER_SIZE, AttachmentDeserializer.DEFAULT_MAX_HEADER_SIZE);
47+
}
48+
49+
public Attachment read(InputStream body) throws IOException {
50+
final PushbackInputStream stream = new PushbackInputStream(body, PUSHBACK_AMOUNT);
51+
final String boundaryString = findBoundaryFromInputStream(stream);
52+
53+
// If a boundary still wasn't found, throw an exception
54+
if (null == boundaryString) {
55+
throw new IOException("Couldn't determine the boundary from the message!");
56+
}
57+
58+
final byte[] boundary = boundaryString.getBytes(StandardCharsets.UTF_8);
59+
if (!AttachmentDeserializerUtil.readTillFirstBoundary(stream, boundary)) {
60+
throw new IOException("Couldn't find MIME boundary: " + boundaryString);
61+
}
62+
63+
Map<String, List<String>> ih = AttachmentDeserializerUtil.loadPartHeaders(stream, maxHeaderLength);
64+
String val = AttachmentUtil.getHeader(ih, "Content-Transfer-Encoding");
65+
66+
MimeBodyPartInputStream mmps = new MimeBodyPartInputStream(stream, boundary, PUSHBACK_AMOUNT);
67+
InputStream ins = AttachmentUtil.decode(mmps, val);
68+
if (ins != mmps) {
69+
ih.remove("Content-Transfer-Encoding");
70+
}
71+
72+
return AttachmentUtil.createAttachment(new DelegatingInputStream(ins, is -> stream.close()), ih, message);
73+
}
74+
75+
private String findBoundaryFromInputStream(PushbackInputStream stream) throws IOException {
76+
//boundary should definitely be in the first 2K;
77+
byte[] buf = new byte[2048];
78+
int i = stream.read(buf);
79+
int len = i;
80+
while (i > 0 && len < buf.length) {
81+
i = stream.read(buf, len, buf.length - len);
82+
if (i > 0) {
83+
len += i;
84+
}
85+
}
86+
String msg = IOUtils.newStringFromBytes(buf, 0, len);
87+
stream.unread(buf, 0, len);
88+
89+
// Use regex to get the boundary and return null if it's not found
90+
Matcher m = INPUT_STREAM_BOUNDARY_PATTERN.matcher(msg);
91+
return m.find() ? "--" + m.group(1) : null;
92+
}
93+
}

core/src/main/java/org/apache/cxf/attachment/AttachmentDeserializer.java

Lines changed: 3 additions & 144 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,10 @@
3030
import java.util.List;
3131
import java.util.Map;
3232
import java.util.Set;
33-
import java.util.TreeMap;
34-
import java.util.logging.Logger;
3533
import java.util.regex.Matcher;
3634
import java.util.regex.Pattern;
3735

3836
import jakarta.activation.DataSource;
39-
import org.apache.cxf.common.logging.LogUtils;
4037
import org.apache.cxf.common.util.StringUtils;
4138
import org.apache.cxf.common.util.SystemPropertyAction;
4239
import org.apache.cxf.helpers.HttpHeaderHelper;
@@ -84,8 +81,6 @@ public class AttachmentDeserializer {
8481
private static final Pattern INPUT_STREAM_BOUNDARY_PATTERN =
8582
Pattern.compile("^--(\\S*)$", Pattern.MULTILINE);
8683

87-
private static final Logger LOG = LogUtils.getL7dLogger(AttachmentDeserializer.class);
88-
8984
private static final int PUSHBACK_AMOUNT = 2048;
9085

9186
private boolean lazyLoading = true;
@@ -161,11 +156,11 @@ protected void initializeRootMessage() throws IOException {
161156
boundary = boundaryString.getBytes(StandardCharsets.UTF_8);
162157

163158
stream = new PushbackInputStream(message.getContent(InputStream.class), PUSHBACK_AMOUNT);
164-
if (!readTillFirstBoundary(stream, boundary)) {
159+
if (!AttachmentDeserializerUtil.readTillFirstBoundary(stream, boundary)) {
165160
throw new IOException("Couldn't find MIME boundary: " + boundaryString);
166161
}
167162

168-
Map<String, List<String>> ih = loadPartHeaders(stream);
163+
Map<String, List<String>> ih = AttachmentDeserializerUtil.loadPartHeaders(stream, maxHeaderLength);
169164
message.put(ATTACHMENT_PART_HEADERS, ih);
170165
String val = AttachmentUtil.getHeader(ih, "Content-Type", "; ");
171166
if (!StringUtils.isEmpty(val)) {
@@ -230,7 +225,7 @@ public AttachmentImpl readNext() throws IOException {
230225
}
231226
stream.unread(v);
232227

233-
Map<String, List<String>> headers = loadPartHeaders(stream);
228+
Map<String, List<String>> headers = AttachmentDeserializerUtil.loadPartHeaders(stream, maxHeaderLength);
234229
return (AttachmentImpl)createAttachment(headers);
235230
}
236231

@@ -271,48 +266,6 @@ private void cache(DelegatingInputStream input) throws IOException {
271266
}
272267
}
273268

274-
/**
275-
* Move the read pointer to the begining of the first part read till the end
276-
* of first boundary
277-
*
278-
* @param pushbackInStream
279-
* @param boundary
280-
* @throws IOException
281-
*/
282-
private static boolean readTillFirstBoundary(PushbackInputStream pushbackInStream,
283-
byte[] boundary) throws IOException {
284-
285-
// work around a bug in PushBackInputStream where the buffer isn't
286-
// initialized
287-
// and available always returns 0.
288-
int value = pushbackInStream.read();
289-
pushbackInStream.unread(value);
290-
while (value != -1) {
291-
value = pushbackInStream.read();
292-
if ((byte) value == boundary[0]) {
293-
int boundaryIndex = 0;
294-
while (value != -1
295-
&& boundaryIndex < boundary.length
296-
&& (byte)value == boundary[boundaryIndex]) {
297-
298-
value = pushbackInStream.read();
299-
if (value == -1) {
300-
throw new IOException("Unexpected End while searching for first Mime Boundary");
301-
}
302-
boundaryIndex++;
303-
}
304-
if (boundaryIndex == boundary.length) {
305-
// boundary found, read the newline
306-
if (value == 13) {
307-
pushbackInStream.read();
308-
}
309-
return true;
310-
}
311-
}
312-
}
313-
return false;
314-
}
315-
316269
/**
317270
* Create an Attachment from the MIME stream. If there is a previous attachment
318271
* that is not read, cache that attachment.
@@ -366,98 +319,4 @@ public boolean hasNext() throws IOException {
366319
stream.unread(v);
367320
return true;
368321
}
369-
370-
371-
372-
private Map<String, List<String>> loadPartHeaders(InputStream in) throws IOException {
373-
StringBuilder buffer = new StringBuilder(128);
374-
StringBuilder b = new StringBuilder(128);
375-
Map<String, List<String>> heads = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
376-
377-
// loop until we hit the end or a null line
378-
while (readLine(in, b)) {
379-
// lines beginning with white space get special handling
380-
char c = b.charAt(0);
381-
if (c == ' ' || c == '\t') {
382-
if (buffer.length() != 0) {
383-
// preserve the line break and append the continuation
384-
buffer.append("\r\n");
385-
buffer.append(b);
386-
}
387-
} else {
388-
// if we have a line pending in the buffer, flush it
389-
if (buffer.length() > 0) {
390-
addHeaderLine(heads, buffer);
391-
buffer.setLength(0);
392-
}
393-
// add this to the accumulator
394-
buffer.append(b);
395-
}
396-
}
397-
398-
// if we have a line pending in the buffer, flush it
399-
if (buffer.length() > 0) {
400-
addHeaderLine(heads, buffer);
401-
}
402-
return heads;
403-
}
404-
405-
private boolean readLine(InputStream in, StringBuilder buffer) throws IOException {
406-
if (buffer.length() != 0) {
407-
buffer.setLength(0);
408-
}
409-
int c;
410-
411-
while ((c = in.read()) != -1) {
412-
// a linefeed is a terminator, always.
413-
if (c == '\n') {
414-
break;
415-
} else if (c == '\r') {
416-
//just ignore the CR. The next character SHOULD be an NL. If not, we're
417-
//just going to discard this
418-
continue;
419-
} else {
420-
// just add to the buffer
421-
buffer.append((char)c);
422-
}
423-
424-
if (buffer.length() > maxHeaderLength) {
425-
LOG.fine("The attachment header size has exceeded the configured parameter: " + maxHeaderLength);
426-
throw new HeaderSizeExceededException();
427-
}
428-
}
429-
430-
// no characters found...this was either an eof or a null line.
431-
return buffer.length() != 0;
432-
}
433-
434-
private void addHeaderLine(Map<String, List<String>> heads, StringBuilder line) {
435-
// null lines are a nop
436-
final int size = line.length();
437-
if (size == 0) {
438-
return;
439-
}
440-
int separator = line.indexOf(":");
441-
final String name;
442-
String value = "";
443-
if (separator == -1) {
444-
name = line.toString().trim();
445-
} else {
446-
name = line.substring(0, separator);
447-
// step past the separator. Now we need to remove any leading white space characters.
448-
separator++;
449-
450-
while (separator < size) {
451-
char ch = line.charAt(separator);
452-
if (ch != ' ' && ch != '\t' && ch != '\r' && ch != '\n') {
453-
break;
454-
}
455-
separator++;
456-
}
457-
value = line.substring(separator);
458-
}
459-
List<String> v = heads.computeIfAbsent(name, k -> new ArrayList<>(1));
460-
v.add(value);
461-
}
462-
463322
}

0 commit comments

Comments
 (0)