From 1b3ad11ef92af31f80fc1b6c35a5b0a922e38b6e Mon Sep 17 00:00:00 2001 From: Lachlan Roberts Date: Tue, 6 Mar 2018 16:22:03 +1100 Subject: [PATCH 01/50] work in progress Signed-off-by: Lachlan Roberts --- .../org/eclipse/jetty/util/SearchPattern.java | 109 ++++++++++++++++++ .../eclipse/jetty/util/SearchPatternTest.java | 36 ++++++ 2 files changed, 145 insertions(+) create mode 100644 jetty-util/src/main/java/org/eclipse/jetty/util/SearchPattern.java create mode 100644 jetty-util/src/test/java/org/eclipse/jetty/util/SearchPatternTest.java diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/SearchPattern.java b/jetty-util/src/main/java/org/eclipse/jetty/util/SearchPattern.java new file mode 100644 index 00000000000..1fcf0fcf54e --- /dev/null +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/SearchPattern.java @@ -0,0 +1,109 @@ +// +// ======================================================================== +// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.util; + +public class SearchPattern +{ + static final int alphabetSize = 256; + int[] table; + + private String pattern; + + + /** + * @param pattern The pattern to search for. + * @return A Pattern instance for the search pattern + */ + static SearchPattern compile(String pattern) + { + SearchPattern sp = new SearchPattern(); + sp.pattern = pattern; + + + /* + Build up pre-processed table for this pattern. + + function preprocess(pattern): + T ← new table of 256 integers + for i from 0 to 256 exclusive + T[i] ← length(pattern) + for i from 0 to length(pattern) - 1 exclusive + T[pattern[i]] ← length(pattern) - 1 - i + return T + */ + + sp.table = new int[alphabetSize]; + for(int i = 0; i Date: Wed, 7 Mar 2018 10:10:50 +1100 Subject: [PATCH 02/50] fully implemented the complile and match methods, written some tests for this Signed-off-by: Lachlan Roberts --- .../org/eclipse/jetty/util/SearchPattern.java | 48 +++++++---------- .../eclipse/jetty/util/SearchPatternTest.java | 52 +++++++++++++++++-- 2 files changed, 69 insertions(+), 31 deletions(-) diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/SearchPattern.java b/jetty-util/src/main/java/org/eclipse/jetty/util/SearchPattern.java index 1fcf0fcf54e..58b255f34cb 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/SearchPattern.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/SearchPattern.java @@ -22,45 +22,28 @@ public class SearchPattern { static final int alphabetSize = 256; int[] table; - - private String pattern; + byte[] pattern; + public int[] getTable(){ return this.table; } /** * @param pattern The pattern to search for. * @return A Pattern instance for the search pattern */ - static SearchPattern compile(String pattern) + static SearchPattern compile(byte[] pattern) { + //Create new SearchPattern instance SearchPattern sp = new SearchPattern(); - sp.pattern = pattern; + //Copy in the Pattern + sp.pattern = pattern.clone(); - /* - Build up pre-processed table for this pattern. - - function preprocess(pattern): - T ← new table of 256 integers - for i from 0 to 256 exclusive - T[i] ← length(pattern) - for i from 0 to length(pattern) - 1 exclusive - T[pattern[i]] ← length(pattern) - 1 - i - return T - */ - + //Build up the pre-processed table for this pattern. sp.table = new int[alphabetSize]; - for(int i = 0; i Date: Wed, 7 Mar 2018 17:38:44 +1100 Subject: [PATCH 03/50] Completed SearchPattern class and tests Signed-off-by: Lachlan Roberts --- .../org/eclipse/jetty/util/SearchPattern.java | 126 ++++++++++---- .../eclipse/jetty/util/SearchPatternTest.java | 160 ++++++++++++++---- 2 files changed, 221 insertions(+), 65 deletions(-) diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/SearchPattern.java b/jetty-util/src/main/java/org/eclipse/jetty/util/SearchPattern.java index 58b255f34cb..1455e617c0e 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/SearchPattern.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/SearchPattern.java @@ -18,34 +18,55 @@ package org.eclipse.jetty.util; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; + + +/** + * SearchPattern + * + * Fast search for patterns within strings and arrays of bytes. + * Uses an implementation of the Boyer–Moore–Horspool algorithm + * with a 256 character alphabet. + * + * The algorithm has an average-case complexity of O(n) + * on random text and O(nm) in the worst case. + * where: + * m = pattern length + * n = length of data to search + */ public class SearchPattern { static final int alphabetSize = 256; - int[] table; - byte[] pattern; - - public int[] getTable(){ return this.table; } + private int[] table; + private byte[] pattern; - /** - * @param pattern The pattern to search for. - * @return A Pattern instance for the search pattern - */ - static SearchPattern compile(byte[] pattern) + + public static SearchPattern compile(byte[] pattern) { - //Create new SearchPattern instance - SearchPattern sp = new SearchPattern(); + return new SearchPattern(Arrays.copyOf(pattern, pattern.length)); + } + + + public static SearchPattern compile(String pattern) + { + return new SearchPattern(pattern.getBytes(StandardCharsets.UTF_8)); + } + + + private SearchPattern(byte[] pattern) + { + this.pattern = pattern; - //Copy in the Pattern - sp.pattern = pattern.clone(); + if(pattern.length == 0) + throw new IllegalArgumentException("Empty Pattern"); //Build up the pre-processed table for this pattern. - sp.table = new int[alphabetSize]; - for(int i = 0; i data.length) + throw new IllegalArgumentException("(offset+length) out of bounds of data[]"); + } + } diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/SearchPatternTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/SearchPatternTest.java index 2add9948e52..90554df8536 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/SearchPatternTest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/SearchPatternTest.java @@ -20,45 +20,46 @@ package org.eclipse.jetty.util; import static org.junit.Assert.*; +import java.nio.charset.StandardCharsets; + import org.junit.Assert; import org.junit.Test; public class SearchPatternTest { + @Test public void testBasicSearch() { - String p1 = "truth"; - String p2 = "evident"; - String p3 = "we"; - String d = "we hold these truths to be self evident"; - + byte[] p1 = new String("truth").getBytes(StandardCharsets.US_ASCII); + byte[] p2 = new String("evident").getBytes(StandardCharsets.US_ASCII); + byte[] p3 = new String("we").getBytes(StandardCharsets.US_ASCII); + byte[] d = new String("we hold these truths to be self evident").getBytes(StandardCharsets.US_ASCII); // Testing Compiled Pattern p1 "truth" - SearchPattern sp1 = SearchPattern.compile(p1.getBytes()); - Assert.assertEquals(14,sp1.match(d.getBytes(), 0, d.length())); - Assert.assertEquals(14,sp1.match(d.getBytes(),14,p1.length())); - Assert.assertEquals(14,sp1.match(d.getBytes(),14,p1.length()+1)); - Assert.assertEquals(-1,sp1.match(d.getBytes(),14,p1.length()-1)); - Assert.assertEquals(-1,sp1.match(d.getBytes(),15,d.length())); + SearchPattern sp1 = SearchPattern.compile(p1); + Assert.assertEquals(14,sp1.match(d, 0, d.length)); + Assert.assertEquals(14,sp1.match(d,14,p1.length)); + Assert.assertEquals(14,sp1.match(d,14,p1.length+1)); + Assert.assertEquals(-1,sp1.match(d,14,p1.length-1)); + Assert.assertEquals(-1,sp1.match(d,15,d.length-15)); // Testing Compiled Pattern p2 "evident" - SearchPattern sp2 = SearchPattern.compile(p2.getBytes()); - Assert.assertEquals(32,sp2.match(d.getBytes(), 0, d.length())); - Assert.assertEquals(32,sp2.match(d.getBytes(),32,p2.length())); - Assert.assertEquals(32,sp2.match(d.getBytes(),32,p2.length()+1)); - Assert.assertEquals(-1,sp2.match(d.getBytes(),32,p2.length()-1)); - Assert.assertEquals(-1,sp2.match(d.getBytes(),33,d.length())); - + SearchPattern sp2 = SearchPattern.compile(p2); + Assert.assertEquals(32,sp2.match(d, 0, d.length)); + Assert.assertEquals(32,sp2.match(d,32,p2.length)); + Assert.assertEquals(32,sp2.match(d,32,p2.length)); + Assert.assertEquals(-1,sp2.match(d,32,p2.length-1)); + Assert.assertEquals(-1,sp2.match(d,33,d.length-33)); // Testing Compiled Pattern p3 "evident" - SearchPattern sp3 = SearchPattern.compile(p3.getBytes()); - Assert.assertEquals( 0,sp3.match(d.getBytes(), 0, d.length())); - Assert.assertEquals( 0,sp3.match(d.getBytes(), 0, p3.length())); - Assert.assertEquals( 0,sp3.match(d.getBytes(), 0, p3.length()+1)); - Assert.assertEquals(-1,sp3.match(d.getBytes(), 0, p3.length()-1)); - Assert.assertEquals(-1,sp3.match(d.getBytes(), 1, d.length())); + SearchPattern sp3 = SearchPattern.compile(p3); + Assert.assertEquals( 0,sp3.match(d, 0, d.length)); + Assert.assertEquals( 0,sp3.match(d, 0, p3.length)); + Assert.assertEquals( 0,sp3.match(d, 0, p3.length+1)); + Assert.assertEquals(-1,sp3.match(d, 0, p3.length-1)); + Assert.assertEquals(-1,sp3.match(d, 1, d.length-1)); } @@ -66,17 +67,106 @@ public class SearchPatternTest @Test public void testDoubleMatch() { - String p = "violent"; - String d = "These violent delights have violent ends."; - - // Testing Compiled Pattern p1 "truth" - SearchPattern sp = SearchPattern.compile(p.getBytes()); - Assert.assertEquals( 6,sp.match(d.getBytes(), 0, d.length())); - Assert.assertEquals(-1,sp.match(d.getBytes(), 6, p.length()-1)); - Assert.assertEquals(28,sp.match(d.getBytes(), 7, d.length())); - Assert.assertEquals(28,sp.match(d.getBytes(), 28, d.length())); - Assert.assertEquals(-1,sp.match(d.getBytes(), 29, d.length())); - + byte[] p = new String("violent").getBytes(StandardCharsets.US_ASCII); + byte[] d = new String("These violent delights have violent ends.").getBytes(StandardCharsets.US_ASCII); + SearchPattern sp = SearchPattern.compile(p); + Assert.assertEquals( 6,sp.match(d, 0, d.length)); + Assert.assertEquals(-1,sp.match(d, 6, p.length-1)); + Assert.assertEquals(28,sp.match(d, 7, d.length-7)); + Assert.assertEquals(28,sp.match(d, 28, d.length-28)); + Assert.assertEquals(-1,sp.match(d, 29, d.length-29)); } + + @Test + public void testAlmostMatch() + { + byte[] p = new String("violent").getBytes(StandardCharsets.US_ASCII); + byte[] d = new String("vio lent violen v iolent violin vioviolenlent viiolent").getBytes(StandardCharsets.US_ASCII); + SearchPattern sp = SearchPattern.compile(p); + Assert.assertEquals(-1,sp.match(d, 0, d.length)); + } + + + @Test + public void testOddSizedPatterns() + { + // Test Large Pattern + byte[] p = new String("pneumonoultramicroscopicsilicovolcanoconiosis").getBytes(StandardCharsets.US_ASCII); + byte[] d = new String("pneumon").getBytes(StandardCharsets.US_ASCII); + SearchPattern sp = SearchPattern.compile(p); + Assert.assertEquals(-1,sp.match(d, 0, d.length)); + + // Test Single Character Pattern + p = new String("s").getBytes(StandardCharsets.US_ASCII); + d = new String("the cake is a lie").getBytes(StandardCharsets.US_ASCII); + sp = SearchPattern.compile(p); + Assert.assertEquals(10,sp.match(d, 0, d.length)); + } + + + @Test + public void testEndsWith() + { + byte[] p = new String("pneumonoultramicroscopicsilicovolcanoconiosis").getBytes(StandardCharsets.US_ASCII); + byte[] d = new String("pneumonoultrami").getBytes(StandardCharsets.US_ASCII); + SearchPattern sp = SearchPattern.compile(p); + Assert.assertEquals(15,sp.endsWith(d,0,d.length)); + + p = new String("abcdefghijklmnopqrstuvwxyz").getBytes(StandardCharsets.US_ASCII); + d = new String("abcdefghijklmnopqrstuvwxyzabcdefghijklmno").getBytes(StandardCharsets.US_ASCII); + sp = SearchPattern.compile(p); + Assert.assertEquals(0,sp.match(d,0,d.length)); + Assert.assertEquals(-1,sp.match(d,1,d.length-1)); + Assert.assertEquals(15,sp.endsWith(d,0,d.length)); + + p = new String("abcdefghijklmnopqrstuvwxyz").getBytes(StandardCharsets.US_ASCII); + d = new String("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz").getBytes(StandardCharsets.US_ASCII); + sp = SearchPattern.compile(p); + Assert.assertEquals(0,sp.match(d,0,d.length)); + Assert.assertEquals(26,sp.match(d,1,d.length-1)); + Assert.assertEquals(26,sp.endsWith(d,0,d.length)); + + //test no match + p = new String("hello world").getBytes(StandardCharsets.US_ASCII); + d = new String("there is definitely no match in here").getBytes(StandardCharsets.US_ASCII); + sp = SearchPattern.compile(p); + Assert.assertEquals(0,sp.endsWith(d,0,d.length)); + } + + + @Test + public void testStartsWith() + { + byte[] p = new String("abcdefghijklmnopqrstuvwxyz").getBytes(StandardCharsets.US_ASCII); + byte[] d = new String("ijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz").getBytes(StandardCharsets.US_ASCII); + SearchPattern sp = SearchPattern.compile(p); + Assert.assertEquals(18,sp.match(d,0,d.length)); + Assert.assertEquals(-1,sp.match(d,19,d.length-19)); + Assert.assertEquals(18,sp.startsWith(d,0,d.length,8)); + + p = new String("abcdefghijklmnopqrstuvwxyz").getBytes(StandardCharsets.US_ASCII); + d = new String("ijklmnopqrstuvwxyz abcdefghijklmnopqrstuvwxyz").getBytes(StandardCharsets.US_ASCII); + sp = SearchPattern.compile(p); + Assert.assertEquals(19,sp.match(d,0,d.length)); + Assert.assertEquals(-1,sp.match(d,20,d.length-20)); + Assert.assertEquals(18,sp.startsWith(d,0,d.length,8)); + + p = new String("abcdefghijklmnopqrstuvwxyz").getBytes(StandardCharsets.US_ASCII); + d = new String("abcdefghijklmnopqrstuvwxyz abcdefghijklmnopqrstuvwxyz").getBytes(StandardCharsets.US_ASCII); + sp = SearchPattern.compile(p); + Assert.assertEquals(26,sp.startsWith(d,0,d.length,0)); + + //test no match + p = new String("hello world").getBytes(StandardCharsets.US_ASCII); + d = new String("there is definitely no match in here").getBytes(StandardCharsets.US_ASCII); + sp = SearchPattern.compile(p); + Assert.assertEquals(0,sp.startsWith(d,0,d.length,0)); + + //test large pattern small buffer + p = new String("abcdefghijklmnopqrstuvwxyz").getBytes(StandardCharsets.US_ASCII); + d = new String("mnopqrs").getBytes(StandardCharsets.US_ASCII); + sp = SearchPattern.compile(p); + Assert.assertEquals(7,sp.startsWith(d,0,d.length,12)); + } } From bfbe52754b3f39587ee5b06ecb918eb40bee1eba Mon Sep 17 00:00:00 2001 From: Lachlan Roberts Date: Wed, 7 Mar 2018 22:10:35 +1100 Subject: [PATCH 04/50] completed some javadoc on compile and constructor methods Signed-off-by: Lachlan Roberts --- .../org/eclipse/jetty/util/SearchPattern.java | 18 +++++++++++++++--- .../eclipse/jetty/util/SearchPatternTest.java | 3 ++- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/SearchPattern.java b/jetty-util/src/main/java/org/eclipse/jetty/util/SearchPattern.java index 1455e617c0e..f429e48ad52 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/SearchPattern.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/SearchPattern.java @@ -41,19 +41,31 @@ public class SearchPattern private int[] table; private byte[] pattern; - + /** + * Produces a SearchPattern instance which can be used + * to find matches of the pattern in data + * @param pattern byte array containing the pattern + * @return a new SearchPattern instance using the given pattern + */ public static SearchPattern compile(byte[] pattern) { return new SearchPattern(Arrays.copyOf(pattern, pattern.length)); } - + /** + * Produces a SearchPattern instance which can be used + * to find matches of the pattern in data + * @param pattern string containing the pattern + * @return a new SearchPattern instance using the given pattern + */ public static SearchPattern compile(String pattern) { return new SearchPattern(pattern.getBytes(StandardCharsets.UTF_8)); } - + /** + * @param pattern byte array containing the pattern used for matching + */ private SearchPattern(byte[] pattern) { this.pattern = pattern; diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/SearchPatternTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/SearchPatternTest.java index 90554df8536..42d21597afc 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/SearchPatternTest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/SearchPatternTest.java @@ -25,7 +25,8 @@ import java.nio.charset.StandardCharsets; import org.junit.Assert; import org.junit.Test; -public class SearchPatternTest +public class + { From 946341bf8568cc0c897ddd9d6f468b602de7c55b Mon Sep 17 00:00:00 2001 From: Lachlan Roberts Date: Thu, 8 Mar 2018 08:28:12 +1100 Subject: [PATCH 05/50] added missing class name SearchPatternTest Signed-off-by: Lachlan Roberts --- .../test/java/org/eclipse/jetty/util/SearchPatternTest.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/SearchPatternTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/SearchPatternTest.java index 42d21597afc..cfd15a80e07 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/SearchPatternTest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/SearchPatternTest.java @@ -18,14 +18,13 @@ package org.eclipse.jetty.util; -import static org.junit.Assert.*; import java.nio.charset.StandardCharsets; import org.junit.Assert; import org.junit.Test; -public class +public class SearchPatternTest { From dc67cb52410dc57e05654d3aaee047455ab4dc8a Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Thu, 8 Mar 2018 17:47:46 +1100 Subject: [PATCH 06/50] Work in progres #1027 Signed-off-by: Greg Wilkins --- .../eclipse/jetty/http/MultiPartParser.java | 866 ++++++++++++++++++ .../jetty/http/MultiPartParserTest.java | 133 +++ .../org/eclipse/jetty/util/SearchPattern.java | 8 + .../eclipse/jetty/util/SearchPatternTest.java | 6 + 4 files changed, 1013 insertions(+) create mode 100644 jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartParser.java create mode 100644 jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParserTest.java diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartParser.java b/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartParser.java new file mode 100644 index 00000000000..41e4593db34 --- /dev/null +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartParser.java @@ -0,0 +1,866 @@ +// +// ======================================================================== +// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http; + +import static org.eclipse.jetty.http.HttpTokens.CARRIAGE_RETURN; +import static org.eclipse.jetty.http.HttpTokens.LINE_FEED; +import static org.eclipse.jetty.http.HttpTokens.SPACE; +import static org.eclipse.jetty.http.HttpTokens.TAB; + +import java.nio.ByteBuffer; +import java.util.Arrays; +import java.util.EnumSet; + +import org.eclipse.jetty.http.HttpParser.RequestHandler; +import org.eclipse.jetty.util.ArrayTrie; +import org.eclipse.jetty.util.BufferUtil; +import org.eclipse.jetty.util.SearchPattern; +import org.eclipse.jetty.util.Trie; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; + + +/* ------------------------------------------------------------ */ +/* + * RFC2046 and RFC7578 + * + * example: +------WebKitFormBoundaryzWHSH95mOxQwmKln +Content-Disposition: form-data; name="TextField" + +Text value:;"' x ---- +------WebKitFormBoundaryzWHSH95mOxQwmKln +Content-Disposition: form-data; name="file1"; filename="file with :%22; in name.txt" +Content-Type: text/plain + + +------WebKitFormBoundaryzWHSH95mOxQwmKln +Content-Disposition: form-data; name="file2"; filename="ManagedSelector.java" +Content-Type: text/x-java + + +------WebKitFormBoundaryzWHSH95mOxQwmKln +Content-Disposition: form-data; name="Action" + +Submit +------WebKitFormBoundaryzWHSH95mOxQwmKln-- + * + * BNF: + * + boundary := 0*69 bcharsnospace + + bchars := bcharsnospace / " " + + bcharsnospace := DIGIT / ALPHA / "'" / "(" / ")" / + "+" / "_" / "," / "-" / "." / + "/" / ":" / "=" / "?" + + dash-boundary := "--" boundary + ; boundary taken from the value of + ; boundary parameter of the + ; Content-Type field. + + multipart-body := [preamble CRLF] + dash-boundary transport-padding CRLF + body-part *encapsulation + close-delimiter transport-padding + [CRLF epilogue] + + + transport-padding := *LWSP-char + ; Composers MUST NOT generate + ; non-zero length transport + ; padding, but receivers MUST + ; be able to handle padding + ; added by message transports. + + encapsulation := delimiter transport-padding + CRLF body-part + + delimiter := CRLF dash-boundary + + close-delimiter := delimiter "--" + + preamble := discard-text + + epilogue := discard-text + + discard-text := *(*text CRLF) *text + ; May be ignored or discarded. + + body-part := MIME-part-headers [CRLF *OCTET] + ; Lines in a body-part must not start + ; with the specified dash-boundary and + ; the delimiter must not appear anywhere + ; in the body part. Note that the + ; semantics of a body-part differ from + ; the semantics of a message, as + ; described in the text. + + OCTET := + * + */ +public class MultiPartParser +{ + public static final Logger LOG = Log.getLogger(MultiPartParser.class); + + public final static Trie CACHE = new ArrayTrie<>(2048); + + // States + public enum FieldState + { + FIELD, + IN_NAME, + AFTER_NAME, + VALUE, + IN_VALUE, + + PARAM, + PARAM_NAME, + PARAM_VALUE + } + + // States + public enum State + { + PREAMBLE, + DELIMITER, + DELIMITER_PADDING, + DELIMITER_CLOSE, + BODY_PART, + PART, + EPILOGUE, + END + } + + private final static EnumSet __delimiterStates = EnumSet.of(State.DELIMITER,State.DELIMITER_CLOSE,State.DELIMITER_PADDING); + + private final boolean DEBUG=LOG.isDebugEnabled(); + private final Handler _handler; + private final String _boundary; + private final SearchPattern _search; + private MimeField _field; + private String _headerString; + private String _valueString; + private int _headerBytes; + + private State _state = State.PREAMBLE; + private FieldState _fieldState = FieldState.FIELD; + private int _partialBoundary = 2; // No CRLF if no preamble + private boolean _cr; + private boolean _quote; + + private final StringBuilder _string=new StringBuilder(); + private int _length; + + static + { + CACHE.put(new MimeField("Content-Disposition","form-data")); + CACHE.put(new MimeField("Content-Type","text/plain")); + } + + + /* ------------------------------------------------------------------------------- */ + public MultiPartParser(Handler handler, String boundary) + { + _handler = handler; + _boundary = boundary; + _search = SearchPattern.compile("\r\n--"+boundary); + } + + /* ------------------------------------------------------------------------------- */ + public Handler getHandler() + { + return _handler; + } + + /* ------------------------------------------------------------------------------- */ + public State getState() + { + return _state; + } + + /* ------------------------------------------------------------------------------- */ + public boolean isState(State state) + { + return _state == state; + } + + /* ------------------------------------------------------------------------------- */ + enum CharState { ILLEGAL, CR, LF, LEGAL } + private final static CharState[] __charState; + static + { + // token = 1*tchar + // tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" + // / "+" / "-" / "." / "^" / "_" / "`" / "|" / "~" + // / DIGIT / ALPHA + // ; any VCHAR, except delimiters + // quoted-string = DQUOTE *( qdtext / quoted-pair ) DQUOTE + // qdtext = HTAB / SP /%x21 / %x23-5B / %x5D-7E / obs-text + // obs-text = %x80-FF + // comment = "(" *( ctext / quoted-pair / comment ) ")" + // ctext = HTAB / SP / %x21-27 / %x2A-5B / %x5D-7E / obs-text + // quoted-pair = "\" ( HTAB / SP / VCHAR / obs-text ) + + __charState=new CharState[256]; + Arrays.fill(__charState,CharState.ILLEGAL); + __charState[LINE_FEED]=CharState.LF; + __charState[CARRIAGE_RETURN]=CharState.CR; + __charState[TAB]=CharState.LEGAL; + __charState[SPACE]=CharState.LEGAL; + + __charState['!']=CharState.LEGAL; + __charState['#']=CharState.LEGAL; + __charState['$']=CharState.LEGAL; + __charState['%']=CharState.LEGAL; + __charState['&']=CharState.LEGAL; + __charState['\'']=CharState.LEGAL; + __charState['*']=CharState.LEGAL; + __charState['+']=CharState.LEGAL; + __charState['-']=CharState.LEGAL; + __charState['.']=CharState.LEGAL; + __charState['^']=CharState.LEGAL; + __charState['_']=CharState.LEGAL; + __charState['`']=CharState.LEGAL; + __charState['|']=CharState.LEGAL; + __charState['~']=CharState.LEGAL; + + __charState['"']=CharState.LEGAL; + + __charState['\\']=CharState.LEGAL; + __charState['(']=CharState.LEGAL; + __charState[')']=CharState.LEGAL; + Arrays.fill(__charState,0x21,0x27+1,CharState.LEGAL); + Arrays.fill(__charState,0x2A,0x5B+1,CharState.LEGAL); + Arrays.fill(__charState,0x5D,0x7E+1,CharState.LEGAL); + Arrays.fill(__charState,0x80,0xFF+1,CharState.LEGAL); + + } + + /* ------------------------------------------------------------------------------- */ + private byte next(ByteBuffer buffer) + { + byte ch = buffer.get(); + + CharState s = __charState[0xff & ch]; + switch(s) + { + case LF: + _cr=false; + return ch; + + case CR: + if (_cr) + throw new BadMessageException("Bad EOL"); + + _cr=true; + if (buffer.hasRemaining()) + return next(buffer); + + // Can return 0 here to indicate the need for more characters, + // because a real 0 in the buffer would cause a BadMessage below + return 0; + + case LEGAL: + if (_cr) + throw new BadMessageException("Bad EOL"); + return ch; + + case ILLEGAL: + default: + throw new IllegalCharacterException(_state,ch,buffer); + } + } + + + /* ------------------------------------------------------------------------------- */ + private void setString(String s) + { + _string.setLength(0); + _string.append(s); + _length=s.length(); + } + + /* ------------------------------------------------------------------------------- */ + private String takeString() + { + _string.setLength(_length); + String s =_string.toString(); + _string.setLength(0); + _length=-1; + return s; + } + + + /* ------------------------------------------------------------------------------- */ + /** + * Parse until next Event. + * @param buffer the buffer to parse + * @return True if an {@link RequestHandler} method was called and it returned true; + */ + public boolean parse(ByteBuffer buffer,boolean last) + { + boolean handle = false; + while(handle==false && BufferUtil.hasContent(buffer)) + { + switch(_state) + { + case PREAMBLE: + parsePreamble(buffer); + continue; + + case DELIMITER: + case DELIMITER_PADDING: + case DELIMITER_CLOSE: + parseDelimiter(buffer); + break; + + + case BODY_PART: + handle = parseFields(buffer); + break; + + case PART: + break; + + case END: + break; + + case EPILOGUE: + break; + + default: + break; + + } + } + + return handle; + } + + /* ------------------------------------------------------------------------------- */ + private void parsePreamble(ByteBuffer buffer) + { + if (_partialBoundary>0) + { + int partial = _search.startsWith(buffer.array(),buffer.arrayOffset()+buffer.position(),buffer.remaining(),_partialBoundary); + if (partial>0) + { + // TODO this should not be needed? + partial+=_partialBoundary; + + if (partial==_search.getLength()) + { + buffer.position(buffer.position()+partial-_partialBoundary); + _partialBoundary = 0; + setState(State.DELIMITER); + return; + } + + _partialBoundary = partial; + BufferUtil.clear(buffer); + return; + } + + _partialBoundary = 0; + } + + int delimiter = _search.match(buffer.array(),buffer.arrayOffset()+buffer.position(),buffer.remaining()); + if (delimiter>=0) + { + buffer.position(delimiter-buffer.arrayOffset()+_search.getLength()); + setState(State.DELIMITER); + return; + } + + _partialBoundary = _search.endsWith(buffer.array(),buffer.arrayOffset()+buffer.position(),buffer.remaining()); + BufferUtil.clear(buffer); + + return; + } + + /* ------------------------------------------------------------------------------- */ + private void parseDelimiter(ByteBuffer buffer) + { + while (__delimiterStates.contains(_state) && buffer.hasRemaining()) + { + byte b=next(buffer); + if (b==0) + return; + + if (b=='\n') + { + setState(State.BODY_PART); + return; + } + + switch(_state) + { + case DELIMITER: + if (b=='-') + setState(State.DELIMITER_CLOSE); + else + setState(State.DELIMITER_PADDING); + continue; + + case DELIMITER_CLOSE: + if (b=='-') + { + setState(State.EPILOGUE); + return; + } + setState(State.DELIMITER_PADDING); + continue; + + case DELIMITER_PADDING: + default: + continue; + } + } + } + + /* ------------------------------------------------------------------------------- */ + /* + * Parse the message headers and return true if the handler has signaled for a return + */ + protected boolean parseFields(ByteBuffer buffer) + { + /* + // Process headers + while ((_state==State.HEADER && buffer.hasRemaining()) + { + // process each character + byte b=next(buffer); + if (b==0) + break; + + + switch (_fieldState) + { + case FIELD: + switch(b) + { + case HttpTokens.COLON: + case HttpTokens.SPACE: + case HttpTokens.TAB: + { + // header value without name - continuation? + if (_valueString==null) + { + _string.setLength(0); + _length=0; + } + else + { + setString(_valueString); + _string.append(' '); + _length++; + _valueString=null; + } + setState(FieldState.VALUE); + break; + } + + case HttpTokens.LINE_FEED: + { + // process previous header + if (_state==State.HEADER) + parsedHeader(); + else + parsedTrailer(); + + _contentPosition=0; + + // End of headers or trailers? + if (_state==State.TRAILER) + { + setState(State.END); + return _handler.messageComplete(); + } + + // Was there a required host header? + if (!_host && _version==HttpVersion.HTTP_1_1 && _requestHandler!=null) + { + throw new BadMessageException(HttpStatus.BAD_REQUEST_400,"No Host"); + } + + // is it a response that cannot have a body? + if (_responseHandler !=null && // response + (_responseStatus == 304 || // not-modified response + _responseStatus == 204 || // no-content response + _responseStatus < 200)) // 1xx response + _endOfContent=EndOfContent.NO_CONTENT; // ignore any other headers set + + // else if we don't know framing + else if (_endOfContent == EndOfContent.UNKNOWN_CONTENT) + { + if (_responseStatus == 0 // request + || _responseStatus == 304 // not-modified response + || _responseStatus == 204 // no-content response + || _responseStatus < 200) // 1xx response + _endOfContent=EndOfContent.NO_CONTENT; + else + _endOfContent=EndOfContent.EOF_CONTENT; + } + + // How is the message ended? + switch (_endOfContent) + { + case EOF_CONTENT: + { + setState(State.EOF_CONTENT); + boolean handle=_handler.headerComplete(); + _headerComplete=true; + return handle; + } + case CHUNKED_CONTENT: + { + setState(State.CHUNKED_CONTENT); + boolean handle=_handler.headerComplete(); + _headerComplete=true; + return handle; + } + case NO_CONTENT: + { + setState(State.END); + return handleHeaderContentMessage(); + } + default: + { + setState(State.CONTENT); + boolean handle=_handler.headerComplete(); + _headerComplete=true; + return handle; + } + } + } + + default: + { + // now handle the ch + if (bHttpTokens.SPACE || b<0) + { + _string.append((char)(0xff&b)); + _length=_string.length(); + setState(FieldState.IN_VALUE); + break; + } + + if (b==HttpTokens.SPACE || b==HttpTokens.TAB) + break; + + if (b==HttpTokens.LINE_FEED) + { + _string.setLength(0); + _valueString=""; + _length=-1; + + setState(FieldState.FIELD); + break; + } + throw new IllegalCharacterException(_state,b,buffer); + + case IN_VALUE: + if (b>=HttpTokens.SPACE || b<0 || b==HttpTokens.TAB) + { + if (_valueString!=null) + { + setString(_valueString); + _valueString=null; + _field=null; + } + _string.append((char)(0xff&b)); + if (b>HttpTokens.SPACE || b<0) + _length=_string.length(); + break; + } + + if (b==HttpTokens.LINE_FEED) + { + if (_length > 0) + { + _valueString=takeString(); + _length=-1; + } + setState(FieldState.FIELD); + break; + } + + throw new IllegalCharacterException(_state,b,buffer); + + default: + throw new IllegalStateException(_state.toString()); + + } + } + */ + return true; + } + + + + /* ------------------------------------------------------------------------------- */ + + protected boolean parseContent(ByteBuffer buffer) + { + return false; + } + + + /* ------------------------------------------------------------------------------- */ + private void setState(State state) + { + if (DEBUG) + LOG.debug("{} --> {}",_state,state); + _state=state; + } + + /* ------------------------------------------------------------------------------- */ + private void setState(FieldState state) + { + if (DEBUG) + LOG.debug("{}:{} --> {}",_state,_field,state); + _fieldState=state; + } + + + /* ------------------------------------------------------------------------------- */ + @Override + public String toString() + { + return String.format("%s{s=%s}", + getClass().getSimpleName(), + _state); + } + + /* ------------------------------------------------------------ */ + /* ------------------------------------------------------------ */ + /* ------------------------------------------------------------ */ + /* Event Handler interface + * These methods return true if the caller should process the events + * so far received (eg return from parseNext and call HttpChannel.handle). + * If multiple callbacks are called in sequence (eg + * headerComplete then messageComplete) from the same point in the parsing + * then it is sufficient for the caller to process the events only once. + */ + public interface Handler + { + public default void parsedHeader(MimeField field) {} + public default void parsedParameter(MimeField field, String name, String value) {}; + public default boolean headerComplete() {return false;} + + public default boolean content(ByteBuffer item, boolean last) {return false;} + + public default boolean messageComplete() {return false;} + + public default void earlyEOF() {} + } + + /* ------------------------------------------------------------------------------- */ + @SuppressWarnings("serial") + private static class IllegalCharacterException extends BadMessageException + { + private IllegalCharacterException(State state,byte ch,ByteBuffer buffer) + { + super(400,String.format("Illegal character 0x%X",ch)); + // Bug #460642 - don't reveal buffers to end user + LOG.warn(String.format("Illegal character 0x%X in state=%s for buffer %s",ch,state,BufferUtil.toDetailString(buffer))); + } + } + + + static class MimeField + { + final String _name; + final String _value; + final String _string; + + public MimeField(String name, String value) + { + _name = name; + _value = value; + _string = name + ": " + value; + } + + @Override + public String toString() + { + return _string; + } + } + +} diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParserTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParserTest.java new file mode 100644 index 00000000000..8e0290c0ae3 --- /dev/null +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParserTest.java @@ -0,0 +1,133 @@ +// +// ======================================================================== +// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http; + +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.*; + +import java.nio.ByteBuffer; + +import org.eclipse.jetty.http.MultiPartParser.State; +import org.eclipse.jetty.util.BufferUtil; +import org.hamcrest.Matchers; +import org.junit.Assert; +import org.junit.Test; + +public class MultiPartParserTest +{ + + @Test + public void testEmptyPreamble() + { + MultiPartParser parser = new MultiPartParser(new MultiPartParser.Handler(){},"BOUNDARY"); + ByteBuffer data = BufferUtil.toBuffer(""); + + parser.parse(data,false); + assertTrue(parser.isState(State.PREAMBLE)); + } + + @Test + public void testNoPreamble() + { + MultiPartParser parser = new MultiPartParser(new MultiPartParser.Handler(){},"BOUNDARY"); + ByteBuffer data = BufferUtil.toBuffer(""); + + data = BufferUtil.toBuffer("--BOUNDARY \r\n"); + parser.parse(data,false); + assertTrue(parser.isState(State.BODY_PART)); + assertThat(data.remaining(),is(0)); + } + + @Test + public void testPreamble() + { + MultiPartParser parser = new MultiPartParser(new MultiPartParser.Handler(){},"BOUNDARY"); + ByteBuffer data; + + data = BufferUtil.toBuffer("This is not part of a part\r\n"); + parser.parse(data,false); + assertThat(parser.getState(),is(State.PREAMBLE)); + assertThat(data.remaining(),is(0)); + + data = BufferUtil.toBuffer("More data that almost includes \n--BOUNDARY but no CR before."); + parser.parse(data,false); + assertThat(parser.getState(),is(State.PREAMBLE)); + assertThat(data.remaining(),is(0)); + + data = BufferUtil.toBuffer("Could be a boundary \r\n--BOUNDAR"); + parser.parse(data,false); + assertThat(parser.getState(),is(State.PREAMBLE)); + assertThat(data.remaining(),is(0)); + + data = BufferUtil.toBuffer("but not it isn't"); + parser.parse(data,false); + assertThat(parser.getState(),is(State.PREAMBLE)); + assertThat(data.remaining(),is(0)); + } + + @Test + public void testPreambleCompleteBoundary() + { + MultiPartParser parser = new MultiPartParser(new MultiPartParser.Handler(){},"BOUNDARY"); + ByteBuffer data; + + data = BufferUtil.toBuffer("This is not part of a part\r\n--BOUNDARY \r\n"); + parser.parse(data,false); + assertThat(parser.getState(),is(State.BODY_PART)); + assertThat(data.remaining(),is(0)); + } + + @Test + public void testPreambleSplitBoundary() + { + MultiPartParser parser = new MultiPartParser(new MultiPartParser.Handler(){},"BOUNDARY"); + ByteBuffer data; + + data = BufferUtil.toBuffer("This is not part of a part\r\n"); + parser.parse(data,false); + assertThat(parser.getState(),is(State.PREAMBLE)); + assertThat(data.remaining(),is(0)); + data = BufferUtil.toBuffer("-"); + parser.parse(data,false); + assertThat(parser.getState(),is(State.PREAMBLE)); + assertThat(data.remaining(),is(0)); + data = BufferUtil.toBuffer("-"); + parser.parse(data,false); + assertThat(parser.getState(),is(State.PREAMBLE)); + assertThat(data.remaining(),is(0)); + data = BufferUtil.toBuffer("B"); + parser.parse(data,false); + assertThat(parser.getState(),is(State.PREAMBLE)); + assertThat(data.remaining(),is(0)); + data = BufferUtil.toBuffer("OUNDARY-"); + parser.parse(data,false); + assertThat(parser.getState(),is(State.DELIMITER_CLOSE)); + assertThat(data.remaining(),is(0)); + data = BufferUtil.toBuffer("ignore\r"); + parser.parse(data,false); + assertThat(parser.getState(),is(State.DELIMITER_PADDING)); + assertThat(data.remaining(),is(0)); + data = BufferUtil.toBuffer("\n"); + parser.parse(data,false); + assertThat(parser.getState(),is(State.BODY_PART)); + assertThat(data.remaining(),is(0)); + } + + +} diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/SearchPattern.java b/jetty-util/src/main/java/org/eclipse/jetty/util/SearchPattern.java index f429e48ad52..a253fc63c6d 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/SearchPattern.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/SearchPattern.java @@ -175,5 +175,13 @@ public class SearchPattern else if (offset + length > data.length) throw new IllegalArgumentException("(offset+length) out of bounds of data[]"); } + + /** + * @return The length of the pattern in bytes. + */ + public int getLength() + { + return pattern.length; + } } diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/SearchPatternTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/SearchPatternTest.java index cfd15a80e07..8ac6f53702f 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/SearchPatternTest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/SearchPatternTest.java @@ -168,5 +168,11 @@ public class SearchPatternTest d = new String("mnopqrs").getBytes(StandardCharsets.US_ASCII); sp = SearchPattern.compile(p); Assert.assertEquals(7,sp.startsWith(d,0,d.length,12)); + + //partial pattern + p = new String("abcdef").getBytes(StandardCharsets.US_ASCII); + d = new String("cde").getBytes(StandardCharsets.US_ASCII); + sp = SearchPattern.compile(p); + Assert.assertEquals(5,sp.startsWith(d,0,d.length,2)); } } From b0325f82999904e1149f7c8a41d14a6aa1e05833 Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Fri, 9 Mar 2018 09:38:23 +1100 Subject: [PATCH 07/50] work in progress Signed-off-by: Greg Wilkins --- .../eclipse/jetty/http/MultiPartParser.java | 318 ++++-------------- .../jetty/http/MultiPartParserTest.java | 61 +++- 2 files changed, 127 insertions(+), 252 deletions(-) diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartParser.java b/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartParser.java index 41e4593db34..4fc4d799e86 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartParser.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartParser.java @@ -28,10 +28,8 @@ import java.util.Arrays; import java.util.EnumSet; import org.eclipse.jetty.http.HttpParser.RequestHandler; -import org.eclipse.jetty.util.ArrayTrie; import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.SearchPattern; -import org.eclipse.jetty.util.Trie; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; @@ -120,7 +118,6 @@ public class MultiPartParser { public static final Logger LOG = Log.getLogger(MultiPartParser.class); - public final static Trie CACHE = new ArrayTrie<>(2048); // States public enum FieldState @@ -129,11 +126,7 @@ public class MultiPartParser IN_NAME, AFTER_NAME, VALUE, - IN_VALUE, - - PARAM, - PARAM_NAME, - PARAM_VALUE + IN_VALUE } // States @@ -155,10 +148,8 @@ public class MultiPartParser private final Handler _handler; private final String _boundary; private final SearchPattern _search; - private MimeField _field; - private String _headerString; - private String _valueString; - private int _headerBytes; + private String _fieldName; + private String _fieldValue; private State _state = State.PREAMBLE; private FieldState _fieldState = FieldState.FIELD; @@ -169,12 +160,6 @@ public class MultiPartParser private final StringBuilder _string=new StringBuilder(); private int _length; - static - { - CACHE.put(new MimeField("Content-Disposition","form-data")); - CACHE.put(new MimeField("Content-Type","text/plain")); - } - /* ------------------------------------------------------------------------------- */ public MultiPartParser(Handler handler, String boundary) @@ -330,24 +315,30 @@ public class MultiPartParser case DELIMITER_PADDING: case DELIMITER_CLOSE: parseDelimiter(buffer); - break; - + continue; case BODY_PART: handle = parseFields(buffer); break; case PART: + // TODO + handle = true; + break; + + + case EPILOGUE: + // TODO + handle = true; break; case END: - break; - - case EPILOGUE: + // TODO + handle = true; break; default: - break; + throw new IllegalStateException(); } } @@ -442,37 +433,38 @@ public class MultiPartParser */ protected boolean parseFields(ByteBuffer buffer) { - /* // Process headers - while ((_state==State.HEADER && buffer.hasRemaining()) + while (_state==State.BODY_PART && buffer.hasRemaining()) { // process each character byte b=next(buffer); if (b==0) break; - switch (_fieldState) { case FIELD: switch(b) { - case HttpTokens.COLON: case HttpTokens.SPACE: case HttpTokens.TAB: { - // header value without name - continuation? - if (_valueString==null) + // Folded field value! + + if (_fieldName==null) + throw new IllegalStateException("First field folded"); + + if (_fieldValue==null) { _string.setLength(0); _length=0; } else { - setString(_valueString); + setString(_fieldValue); _string.append(' '); _length++; - _valueString=null; + _fieldValue=null; } setState(FieldState.VALUE); break; @@ -480,76 +472,11 @@ public class MultiPartParser case HttpTokens.LINE_FEED: { - // process previous header - if (_state==State.HEADER) - parsedHeader(); - else - parsedTrailer(); - - _contentPosition=0; - - // End of headers or trailers? - if (_state==State.TRAILER) - { - setState(State.END); - return _handler.messageComplete(); - } - - // Was there a required host header? - if (!_host && _version==HttpVersion.HTTP_1_1 && _requestHandler!=null) - { - throw new BadMessageException(HttpStatus.BAD_REQUEST_400,"No Host"); - } - - // is it a response that cannot have a body? - if (_responseHandler !=null && // response - (_responseStatus == 304 || // not-modified response - _responseStatus == 204 || // no-content response - _responseStatus < 200)) // 1xx response - _endOfContent=EndOfContent.NO_CONTENT; // ignore any other headers set - - // else if we don't know framing - else if (_endOfContent == EndOfContent.UNKNOWN_CONTENT) - { - if (_responseStatus == 0 // request - || _responseStatus == 304 // not-modified response - || _responseStatus == 204 // no-content response - || _responseStatus < 200) // 1xx response - _endOfContent=EndOfContent.NO_CONTENT; - else - _endOfContent=EndOfContent.EOF_CONTENT; - } - - // How is the message ended? - switch (_endOfContent) - { - case EOF_CONTENT: - { - setState(State.EOF_CONTENT); - boolean handle=_handler.headerComplete(); - _headerComplete=true; - return handle; - } - case CHUNKED_CONTENT: - { - setState(State.CHUNKED_CONTENT); - boolean handle=_handler.headerComplete(); - _headerComplete=true; - return handle; - } - case NO_CONTENT: - { - setState(State.END); - return handleHeaderContentMessage(); - } - default: - { - setState(State.CONTENT); - boolean handle=_handler.headerComplete(); - _headerComplete=true; - return handle; - } - } + handleField(); + setState(State.PART); + if (_handler.headerComplete()) + return true; + break; } default: @@ -559,90 +486,7 @@ public class MultiPartParser throw new BadMessageException(); // process previous header - if (_state==State.HEADER) - parsedHeader(); - else - parsedTrailer(); - - // handle new header - if (buffer.hasRemaining()) - { - // Try a look ahead for the known header name and value. - HttpField cached_field=_fieldCache==null?null:_fieldCache.getBest(buffer,-1,buffer.remaining()); - if (cached_field==null) - cached_field=CACHE.getBest(buffer,-1,buffer.remaining()); - - if (cached_field!=null) - { - String n = cached_field.getName(); - String v = cached_field.getValue(); - - if (!_compliances.contains(HttpComplianceSection.FIELD_NAME_CASE_INSENSITIVE)) - { - // Have to get the fields exactly from the buffer to match case - String en = BufferUtil.toString(buffer,buffer.position()-1,n.length(),StandardCharsets.US_ASCII); - if (!n.equals(en)) - { - handleViolation(HttpComplianceSection.FIELD_NAME_CASE_INSENSITIVE,en); - n = en; - cached_field = new HttpField(cached_field.getHeader(),n,v); - } - } - - if (v!=null && !_compliances.contains(HttpComplianceSection.CASE_INSENSITIVE_FIELD_VALUE_CACHE)) - { - String ev = BufferUtil.toString(buffer,buffer.position()+n.length()+1,v.length(),StandardCharsets.ISO_8859_1); - if (!v.equals(ev)) - { - handleViolation(HttpComplianceSection.CASE_INSENSITIVE_FIELD_VALUE_CACHE,ev+"!="+v); - v = ev; - cached_field = new HttpField(cached_field.getHeader(),n,v); - } - } - - _header=cached_field.getHeader(); - _headerString=n; - - if (v==null) - { - // Header only - setState(FieldState.VALUE); - _string.setLength(0); - _length=0; - buffer.position(buffer.position()+n.length()+1); - break; - } - else - { - // Header and value - int pos=buffer.position()+n.length()+v.length()+1; - byte peek=buffer.get(pos); - - if (peek==HttpTokens.CARRIAGE_RETURN || peek==HttpTokens.LINE_FEED) - { - _field=cached_field; - _valueString=v; - setState(FieldState.IN_VALUE); - - if (peek==HttpTokens.CARRIAGE_RETURN) - { - _cr=true; - buffer.position(pos+1); - } - else - buffer.position(pos); - break; - } - else - { - setState(FieldState.IN_VALUE); - setString(v); - buffer.position(pos); - break; - } - } - } - } + handleField(); // New header setState(FieldState.IN_NAME); @@ -654,61 +498,50 @@ public class MultiPartParser break; case IN_NAME: - if (b>HttpTokens.SPACE && b!=HttpTokens.COLON) + if (b==HttpTokens.COLON) + { + _fieldName=takeString(); + _length=-1; + setState(FieldState.VALUE); + break; + } + + if (b>HttpTokens.SPACE) { - if (_header!=null) - { - setString(_header.asString()); - _header=null; - _headerString=null; - } - _string.append((char)b); _length=_string.length(); break; } - // Fallthrough + //Ignore trailing whitespaces + if (b==HttpTokens.SPACE) + { + setState(FieldState.AFTER_NAME); + break; + } + + throw new IllegalCharacterException(_state,b,buffer); case AFTER_NAME: if (b==HttpTokens.COLON) { - if (_headerString==null) - { - _headerString=takeString(); - _header=HttpHeader.CACHE.get(_headerString); - } + _fieldName=takeString(); _length=-1; - setState(FieldState.VALUE); break; } if (b==HttpTokens.LINE_FEED) { - if (_headerString==null) - { - _headerString=takeString(); - _header=HttpHeader.CACHE.get(_headerString); - } + _fieldName=takeString(); _string.setLength(0); - _valueString=""; + _fieldValue=""; _length=-1; - - if (!complianceViolation(HttpComplianceSection.FIELD_COLON,_headerString)) - { - setState(FieldState.FIELD); - break; - } } - //Ignore trailing whitespaces - if (b==HttpTokens.SPACE && !complianceViolation(HttpComplianceSection.NO_WS_AFTER_FIELD_NAME,null)) - { - setState(FieldState.AFTER_NAME); + if (b==HttpTokens.SPACE) break; - } - + throw new IllegalCharacterException(_state,b,buffer); case VALUE: @@ -726,7 +559,7 @@ public class MultiPartParser if (b==HttpTokens.LINE_FEED) { _string.setLength(0); - _valueString=""; + _fieldValue=""; _length=-1; setState(FieldState.FIELD); @@ -737,11 +570,10 @@ public class MultiPartParser case IN_VALUE: if (b>=HttpTokens.SPACE || b<0 || b==HttpTokens.TAB) { - if (_valueString!=null) + if (_fieldValue!=null) { - setString(_valueString); - _valueString=null; - _field=null; + setString(_fieldValue); + _fieldValue=null; } _string.append((char)(0xff&b)); if (b>HttpTokens.SPACE || b<0) @@ -753,7 +585,7 @@ public class MultiPartParser { if (_length > 0) { - _valueString=takeString(); + _fieldValue=takeString(); _length=-1; } setState(FieldState.FIELD); @@ -767,11 +599,16 @@ public class MultiPartParser } } - */ return true; } - - + + /* ------------------------------------------------------------------------------- */ + private void handleField() + { + if (_fieldName!=null && _fieldValue!=null) + _handler.parsedHeader(_fieldName,_fieldValue); + _fieldName = _fieldValue = null; + } /* ------------------------------------------------------------------------------- */ @@ -793,7 +630,7 @@ public class MultiPartParser private void setState(FieldState state) { if (DEBUG) - LOG.debug("{}:{} --> {}",_state,_field,state); + LOG.debug("{}:{} --> {}",_state,_fieldState,state); _fieldState=state; } @@ -819,8 +656,7 @@ public class MultiPartParser */ public interface Handler { - public default void parsedHeader(MimeField field) {} - public default void parsedParameter(MimeField field, String name, String value) {}; + public default void parsedHeader(String name, String value) {} public default boolean headerComplete() {return false;} public default boolean content(ByteBuffer item, boolean last) {return false;} @@ -842,25 +678,5 @@ public class MultiPartParser } } - - static class MimeField - { - final String _name; - final String _value; - final String _string; - - public MimeField(String name, String value) - { - _name = name; - _value = value; - _string = name + ": " + value; - } - - @Override - public String toString() - { - return _string; - } - } } diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParserTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParserTest.java index 8e0290c0ae3..31082790816 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParserTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParserTest.java @@ -22,7 +22,10 @@ import static org.hamcrest.Matchers.is; import static org.junit.Assert.*; import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; +import org.eclipse.jetty.http.MultiPartParser.Handler; import org.eclipse.jetty.http.MultiPartParser.State; import org.eclipse.jetty.util.BufferUtil; import org.hamcrest.Matchers; @@ -75,7 +78,12 @@ public class MultiPartParserTest assertThat(parser.getState(),is(State.PREAMBLE)); assertThat(data.remaining(),is(0)); - data = BufferUtil.toBuffer("but not it isn't"); + data = BufferUtil.toBuffer("but not it isn't \r\n--BOUN"); + parser.parse(data,false); + assertThat(parser.getState(),is(State.PREAMBLE)); + assertThat(data.remaining(),is(0)); + + data = BufferUtil.toBuffer("DARX nor is this"); parser.parse(data,false); assertThat(parser.getState(),is(State.PREAMBLE)); assertThat(data.remaining(),is(0)); @@ -129,5 +137,56 @@ public class MultiPartParserTest assertThat(data.remaining(),is(0)); } + @Test + public void testFirstPartNoFields() + { + MultiPartParser parser = new MultiPartParser(new MultiPartParser.Handler(){},"BOUNDARY"); + ByteBuffer data = BufferUtil.toBuffer(""); + + data = BufferUtil.toBuffer("--BOUNDARY\r\n\r\n"); + parser.parse(data,false); + assertTrue(parser.isState(State.PART)); + assertThat(data.remaining(),is(0)); + } + + @Test + public void testFirstPartFields() + { + List fields = new ArrayList<>(); + MultiPartParser parser = new MultiPartParser(new MultiPartParser.Handler() + { + + @Override + public void parsedHeader(String name, String value) + { + new Throwable().printStackTrace(); + fields.add(name+": "+value); + } + + @Override + public boolean headerComplete() + { + fields.add("COMPLETE!"); + return true; + } + + },"BOUNDARY"); + ByteBuffer data = BufferUtil.toBuffer(""); + + data = BufferUtil.toBuffer("--BOUNDARY\r\n" + + "name0: value0\r\n" + + "name1 :value1 \r\n" + + "name2:value\r\n" + + " 2\r\n" + + "\r\n" + + "Content"); + parser.parse(data,false); + assertTrue(parser.isState(State.PART)); + assertThat(data.remaining(),is(7)); + assertThat(fields,Matchers.contains("name0: value0","name1: value1", "name2: value 2", "COMPLETE!")); + + + } + } From affb43643337468d0eba8ced9315902e61429017 Mon Sep 17 00:00:00 2001 From: Lachlan Roberts Date: Fri, 9 Mar 2018 10:03:28 +1100 Subject: [PATCH 08/50] changes after review 1 Signed-off-by: Lachlan Roberts --- .../java/org/eclipse/jetty/util/SearchPattern.java | 4 ++-- .../java/org/eclipse/jetty/util/SearchPatternTest.java | 10 ++++------ 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/SearchPattern.java b/jetty-util/src/main/java/org/eclipse/jetty/util/SearchPattern.java index f429e48ad52..e08f92385f3 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/SearchPattern.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/SearchPattern.java @@ -153,10 +153,10 @@ public class SearchPattern if(data[i] == pattern[i+matched]) matchedCount++; else - break; + return 0; } - return matchedCount; + return matched + matchedCount; } /** diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/SearchPatternTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/SearchPatternTest.java index cfd15a80e07..ba75a702f7a 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/SearchPatternTest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/SearchPatternTest.java @@ -143,14 +143,12 @@ public class SearchPatternTest SearchPattern sp = SearchPattern.compile(p); Assert.assertEquals(18,sp.match(d,0,d.length)); Assert.assertEquals(-1,sp.match(d,19,d.length-19)); - Assert.assertEquals(18,sp.startsWith(d,0,d.length,8)); + Assert.assertEquals(26,sp.startsWith(d,0,d.length,8)); p = new String("abcdefghijklmnopqrstuvwxyz").getBytes(StandardCharsets.US_ASCII); - d = new String("ijklmnopqrstuvwxyz abcdefghijklmnopqrstuvwxyz").getBytes(StandardCharsets.US_ASCII); + d = new String("ijklmnopqrstuvwxyNOMATCH").getBytes(StandardCharsets.US_ASCII); sp = SearchPattern.compile(p); - Assert.assertEquals(19,sp.match(d,0,d.length)); - Assert.assertEquals(-1,sp.match(d,20,d.length-20)); - Assert.assertEquals(18,sp.startsWith(d,0,d.length,8)); + Assert.assertEquals(0,sp.startsWith(d,0,d.length,8)); p = new String("abcdefghijklmnopqrstuvwxyz").getBytes(StandardCharsets.US_ASCII); d = new String("abcdefghijklmnopqrstuvwxyz abcdefghijklmnopqrstuvwxyz").getBytes(StandardCharsets.US_ASCII); @@ -167,6 +165,6 @@ public class SearchPatternTest p = new String("abcdefghijklmnopqrstuvwxyz").getBytes(StandardCharsets.US_ASCII); d = new String("mnopqrs").getBytes(StandardCharsets.US_ASCII); sp = SearchPattern.compile(p); - Assert.assertEquals(7,sp.startsWith(d,0,d.length,12)); + Assert.assertEquals(19,sp.startsWith(d,0,d.length,12)); } } From add08caec07c3607dc15fae3d6dab0ec22f373d0 Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Mon, 12 Mar 2018 17:27:05 +1100 Subject: [PATCH 09/50] update after lachlan affb43643337468d0eba8ced9315902e61429017 Signed-off-by: Greg Wilkins --- .../src/main/java/org/eclipse/jetty/http/MultiPartParser.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartParser.java b/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartParser.java index 4fc4d799e86..167a84817b7 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartParser.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartParser.java @@ -354,9 +354,6 @@ public class MultiPartParser int partial = _search.startsWith(buffer.array(),buffer.arrayOffset()+buffer.position(),buffer.remaining(),_partialBoundary); if (partial>0) { - // TODO this should not be needed? - partial+=_partialBoundary; - if (partial==_search.getLength()) { buffer.position(buffer.position()+partial-_partialBoundary); From 1352be4308b87b10c04c8c04175e23e34d449f6a Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Mon, 12 Mar 2018 17:39:11 +1100 Subject: [PATCH 10/50] added some unit tests for part content Signed-off-by: Greg Wilkins --- .../jetty/http/MultiPartParserTest.java | 216 +++++++++++++++++- 1 file changed, 212 insertions(+), 4 deletions(-) diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParserTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParserTest.java index 31082790816..640b8fb296e 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParserTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParserTest.java @@ -155,18 +155,16 @@ public class MultiPartParserTest List fields = new ArrayList<>(); MultiPartParser parser = new MultiPartParser(new MultiPartParser.Handler() { - @Override public void parsedHeader(String name, String value) { - new Throwable().printStackTrace(); fields.add(name+": "+value); } @Override public boolean headerComplete() { - fields.add("COMPLETE!"); + fields.add("<>"); return true; } @@ -183,10 +181,220 @@ public class MultiPartParserTest parser.parse(data,false); assertTrue(parser.isState(State.PART)); assertThat(data.remaining(),is(7)); - assertThat(fields,Matchers.contains("name0: value0","name1: value1", "name2: value 2", "COMPLETE!")); + assertThat(fields,Matchers.contains("name0: value0","name1: value1", "name2: value 2", "<>")); } + @Test + public void testFirstPartNoContent() + { + List fields = new ArrayList<>(); + List content = new ArrayList<>(); + MultiPartParser parser = new MultiPartParser(new MultiPartParser.Handler() + { + + @Override + public void parsedHeader(String name, String value) + { + fields.add(name+": "+value); + } + + @Override + public boolean headerComplete() + { + fields.add("<>"); + return true; + } + + @Override + public boolean content(ByteBuffer buffer, boolean last) + { + if (BufferUtil.hasContent(buffer)) + content.add(BufferUtil.toString(buffer)); + if (last) + content.add("<>"); + return last; + } + + },"BOUNDARY"); + ByteBuffer data = BufferUtil.toBuffer(""); + + data = BufferUtil.toBuffer("--BOUNDARY\r\n" + + "name: value\n" + + "\r\n" + + "--BOUNDARY\r\n"); + parser.parse(data,false); + assertTrue(parser.isState(State.BODY_PART)); + assertThat(data.remaining(),is(0)); + assertThat(fields,Matchers.contains("name: value", "<>")); + assertThat(content,Matchers.contains("<>")); + + + } + + + @Test + public void testFirstPartPartialContent() + { + List fields = new ArrayList<>(); + List content = new ArrayList<>(); + MultiPartParser parser = new MultiPartParser(new MultiPartParser.Handler() + { + + @Override + public void parsedHeader(String name, String value) + { + fields.add(name+": "+value); + } + + @Override + public boolean headerComplete() + { + fields.add("<>"); + return true; + } + + @Override + public boolean content(ByteBuffer buffer, boolean last) + { + if (BufferUtil.hasContent(buffer)) + content.add(BufferUtil.toString(buffer)); + if (last) + content.add("<>"); + return last; + } + + },"BOUNDARY"); + ByteBuffer data = BufferUtil.toBuffer(""); + + data = BufferUtil.toBuffer("--BOUNDARY\r\n" + + "name: value\n" + + "\r\n" + + "Hello\r\n"); + parser.parse(data,false); + assertTrue(parser.isState(State.PART)); + assertThat(data.remaining(),is(0)); + assertThat(fields,Matchers.contains("name: value", "<>")); + assertThat(content,Matchers.contains("Hello")); + + data = BufferUtil.toBuffer( + "Now is the time for all good ment to come to the aid of the party.\r\n" + + "How now brown cow.\r\n" + + "The quick brown fox jumped over the lazy dog.\r\n" + + "this is not a --BOUNDARY\r\n"); + parser.parse(data,false); + assertTrue(parser.isState(State.PART)); + assertThat(data.remaining(),is(0)); + assertThat(fields,Matchers.contains("name: value", "<>")); + assertThat(content,Matchers.contains("Hello","Now is the time for all good ment to come to the aid of the party.\r\n" + + "How now brown cow.\r\n" + + "The quick brown fox jumped over the lazy dog.\r\n" + + "this is not a --BOUNDARY\r\n")); + + + + } + + + + @Test + public void testFirstPartShortContent() + { + List fields = new ArrayList<>(); + List content = new ArrayList<>(); + MultiPartParser parser = new MultiPartParser(new MultiPartParser.Handler() + { + + @Override + public void parsedHeader(String name, String value) + { + fields.add(name+": "+value); + } + + @Override + public boolean headerComplete() + { + fields.add("<>"); + return true; + } + + @Override + public boolean content(ByteBuffer buffer, boolean last) + { + if (BufferUtil.hasContent(buffer)) + content.add(BufferUtil.toString(buffer)); + if (last) + content.add("<>"); + return last; + } + + },"BOUNDARY"); + ByteBuffer data = BufferUtil.toBuffer(""); + + data = BufferUtil.toBuffer("--BOUNDARY\r\n" + + "name: value\n" + + "\r\n" + + "Hello\r\n" + + "--BOUNDARY\r\n"); + parser.parse(data,false); + assertTrue(parser.isState(State.BODY_PART)); + assertThat(data.remaining(),is(0)); + assertThat(fields,Matchers.contains("name: value", "<>")); + assertThat(content,Matchers.contains("Hello","<>")); + + + } + + + @Test + public void testFirstPartLongContent() + { + List fields = new ArrayList<>(); + List content = new ArrayList<>(); + MultiPartParser parser = new MultiPartParser(new MultiPartParser.Handler() + { + + @Override + public void parsedHeader(String name, String value) + { + fields.add(name+": "+value); + } + + @Override + public boolean headerComplete() + { + fields.add("<>"); + return true; + } + + @Override + public boolean content(ByteBuffer buffer, boolean last) + { + if (BufferUtil.hasContent(buffer)) + content.add(BufferUtil.toString(buffer)); + if (last) + content.add("<>"); + return last; + } + + },"BOUNDARY"); + ByteBuffer data = BufferUtil.toBuffer(""); + + data = BufferUtil.toBuffer("--BOUNDARY\r\n" + + "name: value\n" + + "\r\n" + + "Now is the time for all good ment to come to the aid of the party.\r\n" + + "How now brown cow.\r\n" + + "The quick brown fox jumped over the lazy dog.\r\n" + + "--BOUNDARY\r\n"); + parser.parse(data,false); + assertTrue(parser.isState(State.BODY_PART)); + assertThat(data.remaining(),is(0)); + assertThat(fields,Matchers.contains("name: value", "<>")); + assertThat(content,Matchers.contains("Now is the time for all good ment to come to the aid of the party.\r\n" + + "How now brown cow.\r\n" + + "The quick brown fox jumped over the lazy dog.\r\n","<>")); + } } From 267150c9402ef82732044df75349bf5bf220e277 Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Tue, 13 Mar 2018 11:09:14 +1100 Subject: [PATCH 11/50] cleanup field parsing Signed-off-by: Greg Wilkins --- .../eclipse/jetty/http/MultiPartParser.java | 203 +++++++++--------- .../jetty/http/MultiPartParserTest.java | 6 +- 2 files changed, 99 insertions(+), 110 deletions(-) diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartParser.java b/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartParser.java index 167a84817b7..aebc4fb2e24 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartParser.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartParser.java @@ -18,11 +18,6 @@ package org.eclipse.jetty.http; -import static org.eclipse.jetty.http.HttpTokens.CARRIAGE_RETURN; -import static org.eclipse.jetty.http.HttpTokens.LINE_FEED; -import static org.eclipse.jetty.http.HttpTokens.SPACE; -import static org.eclipse.jetty.http.HttpTokens.TAB; - import java.nio.ByteBuffer; import java.util.Arrays; import java.util.EnumSet; @@ -118,6 +113,14 @@ public class MultiPartParser { public static final Logger LOG = Log.getLogger(MultiPartParser.class); + static final byte COLON= (byte)':'; + static final byte TAB= 0x09; + static final byte LINE_FEED= 0x0A; + static final byte CARRIAGE_RETURN= 0x0D; + static final byte SPACE= 0x20; + static final byte[] CRLF = {CARRIAGE_RETURN,LINE_FEED}; + static final byte SEMI_COLON= (byte)';'; + // States public enum FieldState @@ -146,8 +149,7 @@ public class MultiPartParser private final boolean DEBUG=LOG.isDebugEnabled(); private final Handler _handler; - private final String _boundary; - private final SearchPattern _search; + private final SearchPattern _delimiterSearch; private String _fieldName; private String _fieldValue; @@ -155,7 +157,6 @@ public class MultiPartParser private FieldState _fieldState = FieldState.FIELD; private int _partialBoundary = 2; // No CRLF if no preamble private boolean _cr; - private boolean _quote; private final StringBuilder _string=new StringBuilder(); private int _length; @@ -165,8 +166,7 @@ public class MultiPartParser public MultiPartParser(Handler handler, String boundary) { _handler = handler; - _boundary = boundary; - _search = SearchPattern.compile("\r\n--"+boundary); + _delimiterSearch = SearchPattern.compile("\r\n--"+boundary); } /* ------------------------------------------------------------------------------- */ @@ -318,7 +318,7 @@ public class MultiPartParser continue; case BODY_PART: - handle = parseFields(buffer); + handle = parseMimePartHeaders(buffer); break; case PART: @@ -351,10 +351,10 @@ public class MultiPartParser { if (_partialBoundary>0) { - int partial = _search.startsWith(buffer.array(),buffer.arrayOffset()+buffer.position(),buffer.remaining(),_partialBoundary); + int partial = _delimiterSearch.startsWith(buffer.array(),buffer.arrayOffset()+buffer.position(),buffer.remaining(),_partialBoundary); if (partial>0) { - if (partial==_search.getLength()) + if (partial==_delimiterSearch.getLength()) { buffer.position(buffer.position()+partial-_partialBoundary); _partialBoundary = 0; @@ -370,15 +370,15 @@ public class MultiPartParser _partialBoundary = 0; } - int delimiter = _search.match(buffer.array(),buffer.arrayOffset()+buffer.position(),buffer.remaining()); + int delimiter = _delimiterSearch.match(buffer.array(),buffer.arrayOffset()+buffer.position(),buffer.remaining()); if (delimiter>=0) { - buffer.position(delimiter-buffer.arrayOffset()+_search.getLength()); + buffer.position(delimiter-buffer.arrayOffset()+_delimiterSearch.getLength()); setState(State.DELIMITER); return; } - _partialBoundary = _search.endsWith(buffer.array(),buffer.arrayOffset()+buffer.position(),buffer.remaining()); + _partialBoundary = _delimiterSearch.endsWith(buffer.array(),buffer.arrayOffset()+buffer.position(),buffer.remaining()); BufferUtil.clear(buffer); return; @@ -428,7 +428,7 @@ public class MultiPartParser /* * Parse the message headers and return true if the handler has signaled for a return */ - protected boolean parseFields(ByteBuffer buffer) + protected boolean parseMimePartHeaders(ByteBuffer buffer) { // Process headers while (_state==State.BODY_PART && buffer.hasRemaining()) @@ -443,8 +443,8 @@ public class MultiPartParser case FIELD: switch(b) { - case HttpTokens.SPACE: - case HttpTokens.TAB: + case SPACE: + case TAB: { // Folded field value! @@ -467,7 +467,7 @@ public class MultiPartParser break; } - case HttpTokens.LINE_FEED: + case LINE_FEED: { handleField(); setState(State.PART); @@ -478,10 +478,6 @@ public class MultiPartParser default: { - // now handle the ch - if (bHttpTokens.SPACE) - { - _string.append((char)b); - _length=_string.length(); - break; - } - - //Ignore trailing whitespaces - if (b==HttpTokens.SPACE) - { - setState(FieldState.AFTER_NAME); - break; - } - - throw new IllegalCharacterException(_state,b,buffer); + break; case AFTER_NAME: - if (b==HttpTokens.COLON) + switch(b) { - _fieldName=takeString(); - _length=-1; - setState(FieldState.VALUE); - break; + case COLON: + _fieldName=takeString(); + _length=-1; + setState(FieldState.VALUE); + break; + + case LINE_FEED: + _fieldName=takeString(); + _string.setLength(0); + _fieldValue=""; + _length=-1; + break; + + case SPACE: + break; + + default: + throw new IllegalCharacterException(_state,b,buffer); } + break; - if (b==HttpTokens.LINE_FEED) - { - _fieldName=takeString(); - _string.setLength(0); - _fieldValue=""; - _length=-1; - } - - if (b==HttpTokens.SPACE) - break; - - throw new IllegalCharacterException(_state,b,buffer); - case VALUE: - if (b>HttpTokens.SPACE || b<0) + switch(b) { - _string.append((char)(0xff&b)); - _length=_string.length(); - setState(FieldState.IN_VALUE); - break; + case LINE_FEED: + _string.setLength(0); + _fieldValue=""; + _length=-1; + + setState(FieldState.FIELD); + break; + + case SPACE: + case TAB: + break; + + default: + _string.append((char)(0xff&b)); + _length=_string.length(); + setState(FieldState.IN_VALUE); + break; } - - if (b==HttpTokens.SPACE || b==HttpTokens.TAB) - break; - - if (b==HttpTokens.LINE_FEED) - { - _string.setLength(0); - _fieldValue=""; - _length=-1; - - setState(FieldState.FIELD); - break; - } - throw new IllegalCharacterException(_state,b,buffer); + break; case IN_VALUE: - if (b>=HttpTokens.SPACE || b<0 || b==HttpTokens.TAB) + switch(b) { - if (_fieldValue!=null) - { - setString(_fieldValue); - _fieldValue=null; - } - _string.append((char)(0xff&b)); - if (b>HttpTokens.SPACE || b<0) - _length=_string.length(); - break; - } + case SPACE: + _string.append((char)(0xff&b)); + break; - if (b==HttpTokens.LINE_FEED) - { - if (_length > 0) - { - _fieldValue=takeString(); - _length=-1; - } - setState(FieldState.FIELD); - break; - } + case LINE_FEED: + if (_length > 0) + { + _fieldValue=takeString(); + _length=-1; + } + setState(FieldState.FIELD); + break; - throw new IllegalCharacterException(_state,b,buffer); + default: + _string.append((char)(0xff&b)); + if (b>SPACE || b<0) + _length=_string.length(); + break; + } + break; default: throw new IllegalStateException(_state.toString()); @@ -665,11 +656,11 @@ public class MultiPartParser /* ------------------------------------------------------------------------------- */ @SuppressWarnings("serial") - private static class IllegalCharacterException extends BadMessageException + private static class IllegalCharacterException extends IllegalArgumentException { private IllegalCharacterException(State state,byte ch,ByteBuffer buffer) { - super(400,String.format("Illegal character 0x%X",ch)); + super(String.format("Illegal character 0x%X",ch)); // Bug #460642 - don't reveal buffers to end user LOG.warn(String.format("Illegal character 0x%X in state=%s for buffer %s",ch,state,BufferUtil.toDetailString(buffer))); } diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParserTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParserTest.java index 640b8fb296e..28910722852 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParserTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParserTest.java @@ -25,11 +25,9 @@ import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.List; -import org.eclipse.jetty.http.MultiPartParser.Handler; import org.eclipse.jetty.http.MultiPartParser.State; import org.eclipse.jetty.util.BufferUtil; import org.hamcrest.Matchers; -import org.junit.Assert; import org.junit.Test; public class MultiPartParserTest @@ -158,6 +156,7 @@ public class MultiPartParserTest @Override public void parsedHeader(String name, String value) { + System.err.println("Value='"+value+"'"); fields.add(name+": "+value); } @@ -181,9 +180,8 @@ public class MultiPartParserTest parser.parse(data,false); assertTrue(parser.isState(State.PART)); assertThat(data.remaining(),is(7)); + System.err.println(fields); assertThat(fields,Matchers.contains("name0: value0","name1: value1", "name2: value 2", "<>")); - - } @Test From 66a76dae3cb085b9e8ecea649d87730f5612ae57 Mon Sep 17 00:00:00 2001 From: Lachlan Roberts Date: Tue, 13 Mar 2018 11:48:41 +1100 Subject: [PATCH 12/50] work in progress Signed-off-by: Lachlan Roberts --- .../eclipse/jetty/http/MultiPartParser.java | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartParser.java b/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartParser.java index 167a84817b7..acd1472965d 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartParser.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartParser.java @@ -611,6 +611,55 @@ public class MultiPartParser protected boolean parseContent(ByteBuffer buffer) { + + //Starts With + if (_partialBoundary>0) + { + int partial = _search.startsWith(buffer.array(),buffer.arrayOffset()+buffer.position(),buffer.remaining(),_partialBoundary); + if (partial>0) + { + if (partial==_search.getLength()) + { + + + _partialBoundary = 0; + return _handler.content(content, true); + } + + _partialBoundary = partial; + BufferUtil.clear(buffer); + + //TODO + return false; + } + + _partialBoundary = 0; + } + + + // Contains + int delimiter = _search.match(buffer.array(),buffer.arrayOffset()+buffer.position(),buffer.remaining()); + if (delimiter>=0) + { + ByteBuffer content = buffer.slice(); + content.limit(delimiter - buffer.arrayOffset()+buffer.position() - buffer.arrayOffset()); + + buffer.position(delimiter-buffer.arrayOffset()+_search.getLength()); + setState(State.DELIMITER); + + return _handler.content(content, true); + } + + // Ends With + _partialBoundary = _search.endsWith(buffer.array(), buffer.arrayOffset()+buffer.position(), buffer.remaining()); + if(_partialBoundary > 0) + { + ByteBuffer content = buffer.slice(); + content.limit(delimiter - buffer.arrayOffset()+buffer.position() - buffer.arrayOffset()); + } + BufferUtil.clear(buffer); + + //TODO return false; } @@ -676,4 +725,9 @@ public class MultiPartParser } + + public static void main(String[] args) { + System.out.println("hello"); + } + } From 0435eea70810ca1c5eada166a170c8536a09c355 Mon Sep 17 00:00:00 2001 From: Lachlan Roberts Date: Tue, 13 Mar 2018 16:13:07 +1100 Subject: [PATCH 13/50] work in progress implemented OCTETS Signed-off-by: Lachlan Roberts --- .../eclipse/jetty/http/MultiPartParser.java | 81 +++++++++++------ .../jetty/http/MultiPartParserTest.java | 91 ++++++++++++++----- 2 files changed, 124 insertions(+), 48 deletions(-) diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartParser.java b/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartParser.java index 1742f4f4dd5..6816c87b43b 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartParser.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartParser.java @@ -140,7 +140,7 @@ public class MultiPartParser DELIMITER_PADDING, DELIMITER_CLOSE, BODY_PART, - PART, + OCTETS, EPILOGUE, END } @@ -157,6 +157,7 @@ public class MultiPartParser private FieldState _fieldState = FieldState.FIELD; private int _partialBoundary = 2; // No CRLF if no preamble private boolean _cr; + private ByteBuffer _patternBuffer; private final StringBuilder _string=new StringBuilder(); private int _length; @@ -167,6 +168,7 @@ public class MultiPartParser { _handler = handler; _delimiterSearch = SearchPattern.compile("\r\n--"+boundary); + _patternBuffer = ByteBuffer.wrap(boundary.getBytes()); } /* ------------------------------------------------------------------------------- */ @@ -321,9 +323,8 @@ public class MultiPartParser handle = parseMimePartHeaders(buffer); break; - case PART: - // TODO - handle = true; + case OCTETS: + handle = parseOctetContent(buffer); break; @@ -470,7 +471,7 @@ public class MultiPartParser case LINE_FEED: { handleField(); - setState(State.PART); + setState(State.OCTETS); if (_handler.headerComplete()) return true; break; @@ -587,7 +588,7 @@ public class MultiPartParser } } - return true; + return false; } /* ------------------------------------------------------------------------------- */ @@ -600,58 +601,68 @@ public class MultiPartParser /* ------------------------------------------------------------------------------- */ - protected boolean parseContent(ByteBuffer buffer) + protected boolean parseOctetContent(ByteBuffer buffer) { //Starts With if (_partialBoundary>0) { - int partial = _search.startsWith(buffer.array(),buffer.arrayOffset()+buffer.position(),buffer.remaining(),_partialBoundary); + int partial = _delimiterSearch.startsWith(buffer.array(),buffer.arrayOffset()+buffer.position(),buffer.remaining(),_partialBoundary); if (partial>0) { - if (partial==_search.getLength()) + if (partial==_delimiterSearch.getLength()) { - - + buffer.position(buffer.position() + _delimiterSearch.getLength() - _partialBoundary); + setState(State.DELIMITER); _partialBoundary = 0; - return _handler.content(content, true); + return _handler.content(BufferUtil.EMPTY_BUFFER, true); } _partialBoundary = partial; - BufferUtil.clear(buffer); - - //TODO + BufferUtil.clear(buffer); return false; } - - _partialBoundary = 0; + else + { + //print up to _partialBoundary of the search pattern + ByteBuffer content = _patternBuffer.slice(); + content.limit(_partialBoundary); + _partialBoundary = 0; + return _handler.content(BufferUtil.EMPTY_BUFFER, false); + } } // Contains - int delimiter = _search.match(buffer.array(),buffer.arrayOffset()+buffer.position(),buffer.remaining()); + int delimiter = _delimiterSearch.match(buffer.array(),buffer.arrayOffset()+buffer.position(),buffer.remaining()); if (delimiter>=0) { ByteBuffer content = buffer.slice(); - content.limit(delimiter - buffer.arrayOffset()+buffer.position() - buffer.arrayOffset()); + content.limit(delimiter - buffer.arrayOffset() - buffer.position()); - buffer.position(delimiter-buffer.arrayOffset()+_search.getLength()); + buffer.position(delimiter - buffer.arrayOffset() + _delimiterSearch.getLength()); setState(State.DELIMITER); return _handler.content(content, true); } + // Ends With - _partialBoundary = _search.endsWith(buffer.array(), buffer.arrayOffset()+buffer.position(), buffer.remaining()); + _partialBoundary = _delimiterSearch.endsWith(buffer.array(), buffer.arrayOffset()+buffer.position(), buffer.remaining()); if(_partialBoundary > 0) { ByteBuffer content = buffer.slice(); - content.limit(delimiter - buffer.arrayOffset()+buffer.position() - buffer.arrayOffset()); + content.limit(content.limit() - _partialBoundary); + + BufferUtil.clear(buffer); + return _handler.content(content, false); } - BufferUtil.clear(buffer); - //TODO - return false; + + // There is normal content with no delimiter + ByteBuffer content = buffer.slice(); + BufferUtil.clear(buffer); + return _handler.content(content, false); } @@ -718,7 +729,25 @@ public class MultiPartParser public static void main(String[] args) { - System.out.println("hello"); + String s = "hello world"; + + ByteBuffer bb = ByteBuffer.wrap(s.getBytes()); + System.out.println("bb position: "+bb.position()); + for(int i=0; i<4; i++) + System.out.print((char)bb.get()+", "); + System.out.println(); + System.out.println("bb position: "+bb.position()); + + //split + ByteBuffer bb2 = bb.slice(); + bb2.limit(bb2.limit()-3); + + System.out.println("bb2 array offset: "+bb2.arrayOffset()); + System.out.println("bb2 position: "+bb2.position()); + System.out.println((char)bb2.get(0)); + System.out.println((char)bb2.array()[0]); + while(bb2.hasRemaining()) + System.out.print((char)bb2.get()+", "); } } diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParserTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParserTest.java index 28910722852..b878770d0e5 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParserTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParserTest.java @@ -28,6 +28,7 @@ import java.util.List; import org.eclipse.jetty.http.MultiPartParser.State; import org.eclipse.jetty.util.BufferUtil; import org.hamcrest.Matchers; +import org.junit.Ignore; import org.junit.Test; public class MultiPartParserTest @@ -143,7 +144,7 @@ public class MultiPartParserTest data = BufferUtil.toBuffer("--BOUNDARY\r\n\r\n"); parser.parse(data,false); - assertTrue(parser.isState(State.PART)); + assertTrue(parser.isState(State.OCTETS)); assertThat(data.remaining(),is(0)); } @@ -156,7 +157,6 @@ public class MultiPartParserTest @Override public void parsedHeader(String name, String value) { - System.err.println("Value='"+value+"'"); fields.add(name+": "+value); } @@ -178,9 +178,8 @@ public class MultiPartParserTest + "\r\n" + "Content"); parser.parse(data,false); - assertTrue(parser.isState(State.PART)); + assertTrue(parser.isState(State.OCTETS)); assertThat(data.remaining(),is(7)); - System.err.println(fields); assertThat(fields,Matchers.contains("name0: value0","name1: value1", "name2: value 2", "<>")); } @@ -202,7 +201,7 @@ public class MultiPartParserTest public boolean headerComplete() { fields.add("<>"); - return true; + return false; } @Override @@ -219,16 +218,63 @@ public class MultiPartParserTest ByteBuffer data = BufferUtil.toBuffer(""); data = BufferUtil.toBuffer("--BOUNDARY\r\n" - + "name: value\n" + + "name: value\r\n" + "\r\n" - + "--BOUNDARY\r\n"); + + "\r\n" + + "--BOUNDARY"); parser.parse(data,false); - assertTrue(parser.isState(State.BODY_PART)); + //assertThat(parser.getState(), is(State.BODY_PART)); assertThat(data.remaining(),is(0)); - assertThat(fields,Matchers.contains("name: value", "<>")); - assertThat(content,Matchers.contains("<>")); - + assertThat(fields,Matchers.contains("name: value", "<>")); + assertThat(content,Matchers.contains("<>")); + } + + + + @Test + @Ignore + public void testFirstPartNoContentNoCRLF() + { + List fields = new ArrayList<>(); + List content = new ArrayList<>(); + MultiPartParser parser = new MultiPartParser(new MultiPartParser.Handler() + { + + @Override + public void parsedHeader(String name, String value) + { + fields.add(name+": "+value); + } + + @Override + public boolean headerComplete() + { + fields.add("<>"); + return false; + } + + @Override + public boolean content(ByteBuffer buffer, boolean last) + { + if (BufferUtil.hasContent(buffer)) + content.add(BufferUtil.toString(buffer)); + if (last) + content.add("<>"); + return last; + } + + },"BOUNDARY"); + ByteBuffer data = BufferUtil.toBuffer(""); + data = BufferUtil.toBuffer("--BOUNDARY\r\n" + + "name: value\r\n" + + "\r\n" + + "--BOUNDARY"); + parser.parse(data,false); + //assertThat(parser.getState(), is(State.BODY_PART)); + assertThat(data.remaining(),is(0)); + assertThat(fields,Matchers.contains("name: value", "<>")); + assertThat(content,Matchers.contains("<>")); } @@ -250,7 +296,7 @@ public class MultiPartParserTest public boolean headerComplete() { fields.add("<>"); - return true; + return false; } @Override @@ -271,7 +317,7 @@ public class MultiPartParserTest + "\r\n" + "Hello\r\n"); parser.parse(data,false); - assertTrue(parser.isState(State.PART)); + assertTrue(parser.isState(State.OCTETS)); assertThat(data.remaining(),is(0)); assertThat(fields,Matchers.contains("name: value", "<>")); assertThat(content,Matchers.contains("Hello")); @@ -282,13 +328,13 @@ public class MultiPartParserTest + "The quick brown fox jumped over the lazy dog.\r\n" + "this is not a --BOUNDARY\r\n"); parser.parse(data,false); - assertTrue(parser.isState(State.PART)); + assertTrue(parser.isState(State.OCTETS)); assertThat(data.remaining(),is(0)); assertThat(fields,Matchers.contains("name: value", "<>")); assertThat(content,Matchers.contains("Hello","Now is the time for all good ment to come to the aid of the party.\r\n" + "How now brown cow.\r\n" + "The quick brown fox jumped over the lazy dog.\r\n" - + "this is not a --BOUNDARY\r\n")); + + "this is not a --BOUNDARY")); @@ -314,7 +360,7 @@ public class MultiPartParserTest public boolean headerComplete() { fields.add("<>"); - return true; + return false; } @Override @@ -334,9 +380,9 @@ public class MultiPartParserTest + "name: value\n" + "\r\n" + "Hello\r\n" - + "--BOUNDARY\r\n"); + + "--BOUNDARY"); parser.parse(data,false); - assertTrue(parser.isState(State.BODY_PART)); + assertThat(parser.getState(), is(State.DELIMITER)); assertThat(data.remaining(),is(0)); assertThat(fields,Matchers.contains("name: value", "<>")); assertThat(content,Matchers.contains("Hello","<>")); @@ -363,7 +409,7 @@ public class MultiPartParserTest public boolean headerComplete() { fields.add("<>"); - return true; + return false; } @Override @@ -385,11 +431,12 @@ public class MultiPartParserTest + "Now is the time for all good ment to come to the aid of the party.\r\n" + "How now brown cow.\r\n" + "The quick brown fox jumped over the lazy dog.\r\n" - + "--BOUNDARY\r\n"); + + "\r\n" + + "--BOUNDARY"); parser.parse(data,false); - assertTrue(parser.isState(State.BODY_PART)); + assertThat(parser.getState(), is(State.DELIMITER)); assertThat(data.remaining(),is(0)); - assertThat(fields,Matchers.contains("name: value", "<>")); + assertThat(fields,Matchers.contains("name: value", "<>")); assertThat(content,Matchers.contains("Now is the time for all good ment to come to the aid of the party.\r\n" + "How now brown cow.\r\n" + "The quick brown fox jumped over the lazy dog.\r\n","<>")); From 46a8fb5dc43f2cac6f64582c4e3ac0eba5229bd8 Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Tue, 13 Mar 2018 17:40:26 +1100 Subject: [PATCH 14/50] fixes for partial pattern matches and optional CRLF Signed-off-by: Greg Wilkins --- .../eclipse/jetty/http/MultiPartParser.java | 47 ++- .../jetty/http/MultiPartParserTest.java | 282 ++++++------------ .../org/eclipse/jetty/util/SearchPattern.java | 4 +- .../eclipse/jetty/util/SearchPatternTest.java | 42 ++- 4 files changed, 140 insertions(+), 235 deletions(-) diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartParser.java b/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartParser.java index 6816c87b43b..d14dac2cd1b 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartParser.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartParser.java @@ -19,6 +19,7 @@ package org.eclipse.jetty.http; import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.EnumSet; @@ -140,6 +141,7 @@ public class MultiPartParser DELIMITER_PADDING, DELIMITER_CLOSE, BODY_PART, + FIRST_OCTETS, OCTETS, EPILOGUE, END @@ -167,8 +169,10 @@ public class MultiPartParser public MultiPartParser(Handler handler, String boundary) { _handler = handler; - _delimiterSearch = SearchPattern.compile("\r\n--"+boundary); - _patternBuffer = ByteBuffer.wrap(boundary.getBytes()); + + String delimiter = "\r\n--"+boundary; + _patternBuffer = ByteBuffer.wrap(delimiter.getBytes(StandardCharsets.US_ASCII)); + _delimiterSearch = SearchPattern.compile(_patternBuffer.array()); } /* ------------------------------------------------------------------------------- */ @@ -323,6 +327,7 @@ public class MultiPartParser handle = parseMimePartHeaders(buffer); break; + case FIRST_OCTETS: case OCTETS: handle = parseOctetContent(buffer); break; @@ -471,7 +476,8 @@ public class MultiPartParser case LINE_FEED: { handleField(); - setState(State.OCTETS); + setState(State.FIRST_OCTETS); + _partialBoundary = 2; // CRLF is option for empty parts if (_handler.headerComplete()) return true; break; @@ -603,7 +609,6 @@ public class MultiPartParser protected boolean parseOctetContent(ByteBuffer buffer) { - //Starts With if (_partialBoundary>0) { @@ -626,9 +631,16 @@ public class MultiPartParser { //print up to _partialBoundary of the search pattern ByteBuffer content = _patternBuffer.slice(); + if (_state==State.FIRST_OCTETS) + { + setState(State.OCTETS); + content.position(2); + } content.limit(_partialBoundary); _partialBoundary = 0; - return _handler.content(BufferUtil.EMPTY_BUFFER, false); + + if (_handler.content(content, false)) + return true; } } @@ -725,29 +737,4 @@ public class MultiPartParser LOG.warn(String.format("Illegal character 0x%X in state=%s for buffer %s",ch,state,BufferUtil.toDetailString(buffer))); } } - - - - public static void main(String[] args) { - String s = "hello world"; - - ByteBuffer bb = ByteBuffer.wrap(s.getBytes()); - System.out.println("bb position: "+bb.position()); - for(int i=0; i<4; i++) - System.out.print((char)bb.get()+", "); - System.out.println(); - System.out.println("bb position: "+bb.position()); - - //split - ByteBuffer bb2 = bb.slice(); - bb2.limit(bb2.limit()-3); - - System.out.println("bb2 array offset: "+bb2.arrayOffset()); - System.out.println("bb2 position: "+bb2.position()); - System.out.println((char)bb2.get(0)); - System.out.println((char)bb2.array()[0]); - while(bb2.hasRemaining()) - System.out.print((char)bb2.get()+", "); - } - } diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParserTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParserTest.java index b878770d0e5..53f77c2606c 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParserTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParserTest.java @@ -28,7 +28,6 @@ import java.util.List; import org.eclipse.jetty.http.MultiPartParser.State; import org.eclipse.jetty.util.BufferUtil; import org.hamcrest.Matchers; -import org.junit.Ignore; import org.junit.Test; public class MultiPartParserTest @@ -41,7 +40,7 @@ public class MultiPartParserTest ByteBuffer data = BufferUtil.toBuffer(""); parser.parse(data,false); - assertTrue(parser.isState(State.PREAMBLE)); + assertThat(parser.getState(),is(State.PREAMBLE)); } @Test @@ -144,30 +143,24 @@ public class MultiPartParserTest data = BufferUtil.toBuffer("--BOUNDARY\r\n\r\n"); parser.parse(data,false); - assertTrue(parser.isState(State.OCTETS)); + assertThat(parser.getState(),is(State.FIRST_OCTETS)); assertThat(data.remaining(),is(0)); } @Test public void testFirstPartFields() { - List fields = new ArrayList<>(); - MultiPartParser parser = new MultiPartParser(new MultiPartParser.Handler() + TestHandler handler = new TestHandler() { - @Override - public void parsedHeader(String name, String value) - { - fields.add(name+": "+value); - } - @Override public boolean headerComplete() { - fields.add("<>"); + super.headerComplete(); return true; } - - },"BOUNDARY"); + }; + MultiPartParser parser = new MultiPartParser(handler,"BOUNDARY"); + ByteBuffer data = BufferUtil.toBuffer(""); data = BufferUtil.toBuffer("--BOUNDARY\r\n" @@ -178,43 +171,17 @@ public class MultiPartParserTest + "\r\n" + "Content"); parser.parse(data,false); - assertTrue(parser.isState(State.OCTETS)); + assertThat(parser.getState(),is(State.FIRST_OCTETS)); assertThat(data.remaining(),is(7)); - assertThat(fields,Matchers.contains("name0: value0","name1: value1", "name2: value 2", "<>")); + assertThat(handler.fields,Matchers.contains("name0: value0","name1: value1", "name2: value 2", "<>")); } @Test public void testFirstPartNoContent() { - List fields = new ArrayList<>(); - List content = new ArrayList<>(); - MultiPartParser parser = new MultiPartParser(new MultiPartParser.Handler() - { - - @Override - public void parsedHeader(String name, String value) - { - fields.add(name+": "+value); - } - - @Override - public boolean headerComplete() - { - fields.add("<>"); - return false; - } - - @Override - public boolean content(ByteBuffer buffer, boolean last) - { - if (BufferUtil.hasContent(buffer)) - content.add(BufferUtil.toString(buffer)); - if (last) - content.add("<>"); - return last; - } - - },"BOUNDARY"); + TestHandler handler = new TestHandler(); + MultiPartParser parser = new MultiPartParser(handler,"BOUNDARY"); + ByteBuffer data = BufferUtil.toBuffer(""); data = BufferUtil.toBuffer("--BOUNDARY\r\n" @@ -223,47 +190,18 @@ public class MultiPartParserTest + "\r\n" + "--BOUNDARY"); parser.parse(data,false); - //assertThat(parser.getState(), is(State.BODY_PART)); + assertThat(parser.getState(), is(State.DELIMITER)); assertThat(data.remaining(),is(0)); - assertThat(fields,Matchers.contains("name: value", "<>")); - assertThat(content,Matchers.contains("<>")); - } - - + assertThat(handler.fields,Matchers.contains("name: value", "<>")); + assertThat(handler.content,Matchers.contains("<>")); + } @Test - @Ignore public void testFirstPartNoContentNoCRLF() { - List fields = new ArrayList<>(); - List content = new ArrayList<>(); - MultiPartParser parser = new MultiPartParser(new MultiPartParser.Handler() - { - - @Override - public void parsedHeader(String name, String value) - { - fields.add(name+": "+value); - } - - @Override - public boolean headerComplete() - { - fields.add("<>"); - return false; - } - - @Override - public boolean content(ByteBuffer buffer, boolean last) - { - if (BufferUtil.hasContent(buffer)) - content.add(BufferUtil.toString(buffer)); - if (last) - content.add("<>"); - return last; - } - - },"BOUNDARY"); + TestHandler handler = new TestHandler(); + MultiPartParser parser = new MultiPartParser(handler,"BOUNDARY"); + ByteBuffer data = BufferUtil.toBuffer(""); data = BufferUtil.toBuffer("--BOUNDARY\r\n" @@ -271,45 +209,42 @@ public class MultiPartParserTest + "\r\n" + "--BOUNDARY"); parser.parse(data,false); - //assertThat(parser.getState(), is(State.BODY_PART)); + assertThat(parser.getState(), is(State.DELIMITER)); assertThat(data.remaining(),is(0)); - assertThat(fields,Matchers.contains("name: value", "<>")); - assertThat(content,Matchers.contains("<>")); + assertThat(handler.fields,Matchers.contains("name: value", "<>")); + assertThat(handler.content,Matchers.contains("<>")); + + } + + @Test + public void testFirstPartContentLookingLikeNoCRLF() + { + TestHandler handler = new TestHandler(); + MultiPartParser parser = new MultiPartParser(handler,"BOUNDARY"); + + ByteBuffer data = BufferUtil.toBuffer(""); + + data = BufferUtil.toBuffer("--BOUNDARY\r\n" + + "name: value\r\n" + + "\r\n" + + "-"); + parser.parse(data,false); + data = BufferUtil.toBuffer("Content!"); + parser.parse(data,false); + + + assertThat(parser.getState(), is(State.OCTETS)); + assertThat(data.remaining(),is(0)); + assertThat(handler.fields,Matchers.contains("name: value", "<>")); + assertThat(handler.content,Matchers.contains("-","Content!")); } - @Test public void testFirstPartPartialContent() { - List fields = new ArrayList<>(); - List content = new ArrayList<>(); - MultiPartParser parser = new MultiPartParser(new MultiPartParser.Handler() - { - - @Override - public void parsedHeader(String name, String value) - { - fields.add(name+": "+value); - } - - @Override - public boolean headerComplete() - { - fields.add("<>"); - return false; - } - - @Override - public boolean content(ByteBuffer buffer, boolean last) - { - if (BufferUtil.hasContent(buffer)) - content.add(BufferUtil.toString(buffer)); - if (last) - content.add("<>"); - return last; - } - - },"BOUNDARY"); + TestHandler handler = new TestHandler(); + MultiPartParser parser = new MultiPartParser(handler,"BOUNDARY"); + ByteBuffer data = BufferUtil.toBuffer(""); data = BufferUtil.toBuffer("--BOUNDARY\r\n" @@ -317,10 +252,10 @@ public class MultiPartParserTest + "\r\n" + "Hello\r\n"); parser.parse(data,false); - assertTrue(parser.isState(State.OCTETS)); + assertThat(parser.getState(),is(State.OCTETS)); assertThat(data.remaining(),is(0)); - assertThat(fields,Matchers.contains("name: value", "<>")); - assertThat(content,Matchers.contains("Hello")); + assertThat(handler.fields,Matchers.contains("name: value", "<>")); + assertThat(handler.content,Matchers.contains("Hello")); data = BufferUtil.toBuffer( "Now is the time for all good ment to come to the aid of the party.\r\n" @@ -328,52 +263,21 @@ public class MultiPartParserTest + "The quick brown fox jumped over the lazy dog.\r\n" + "this is not a --BOUNDARY\r\n"); parser.parse(data,false); - assertTrue(parser.isState(State.OCTETS)); + assertThat(parser.getState(),is(State.OCTETS)); assertThat(data.remaining(),is(0)); - assertThat(fields,Matchers.contains("name: value", "<>")); - assertThat(content,Matchers.contains("Hello","Now is the time for all good ment to come to the aid of the party.\r\n" + assertThat(handler.fields,Matchers.contains("name: value", "<>")); + assertThat(handler.content,Matchers.contains("Hello","\r\n","Now is the time for all good ment to come to the aid of the party.\r\n" + "How now brown cow.\r\n" + "The quick brown fox jumped over the lazy dog.\r\n" + "this is not a --BOUNDARY")); - - - } - - @Test public void testFirstPartShortContent() { - List fields = new ArrayList<>(); - List content = new ArrayList<>(); - MultiPartParser parser = new MultiPartParser(new MultiPartParser.Handler() - { - - @Override - public void parsedHeader(String name, String value) - { - fields.add(name+": "+value); - } - - @Override - public boolean headerComplete() - { - fields.add("<>"); - return false; - } - - @Override - public boolean content(ByteBuffer buffer, boolean last) - { - if (BufferUtil.hasContent(buffer)) - content.add(BufferUtil.toString(buffer)); - if (last) - content.add("<>"); - return last; - } - - },"BOUNDARY"); + TestHandler handler = new TestHandler(); + MultiPartParser parser = new MultiPartParser(handler,"BOUNDARY"); + ByteBuffer data = BufferUtil.toBuffer(""); data = BufferUtil.toBuffer("--BOUNDARY\r\n" @@ -384,8 +288,8 @@ public class MultiPartParserTest parser.parse(data,false); assertThat(parser.getState(), is(State.DELIMITER)); assertThat(data.remaining(),is(0)); - assertThat(fields,Matchers.contains("name: value", "<>")); - assertThat(content,Matchers.contains("Hello","<>")); + assertThat(handler.fields,Matchers.contains("name: value", "<>")); + assertThat(handler.content,Matchers.contains("Hello","<>")); } @@ -394,35 +298,9 @@ public class MultiPartParserTest @Test public void testFirstPartLongContent() { - List fields = new ArrayList<>(); - List content = new ArrayList<>(); - MultiPartParser parser = new MultiPartParser(new MultiPartParser.Handler() - { - - @Override - public void parsedHeader(String name, String value) - { - fields.add(name+": "+value); - } - - @Override - public boolean headerComplete() - { - fields.add("<>"); - return false; - } - - @Override - public boolean content(ByteBuffer buffer, boolean last) - { - if (BufferUtil.hasContent(buffer)) - content.add(BufferUtil.toString(buffer)); - if (last) - content.add("<>"); - return last; - } - - },"BOUNDARY"); + TestHandler handler = new TestHandler(); + MultiPartParser parser = new MultiPartParser(handler,"BOUNDARY"); + ByteBuffer data = BufferUtil.toBuffer(""); data = BufferUtil.toBuffer("--BOUNDARY\r\n" @@ -436,10 +314,40 @@ public class MultiPartParserTest parser.parse(data,false); assertThat(parser.getState(), is(State.DELIMITER)); assertThat(data.remaining(),is(0)); - assertThat(fields,Matchers.contains("name: value", "<>")); - assertThat(content,Matchers.contains("Now is the time for all good ment to come to the aid of the party.\r\n" + assertThat(handler.fields,Matchers.contains("name: value", "<>")); + assertThat(handler.content,Matchers.contains("Now is the time for all good ment to come to the aid of the party.\r\n" + "How now brown cow.\r\n" + "The quick brown fox jumped over the lazy dog.\r\n","<>")); } + + + static class TestHandler implements MultiPartParser.Handler + { + List fields = new ArrayList<>(); + List content = new ArrayList<>(); + + @Override + public void parsedHeader(String name, String value) + { + fields.add(name+": "+value); + } + + @Override + public boolean headerComplete() + { + fields.add("<>"); + return false; + } + + @Override + public boolean content(ByteBuffer buffer, boolean last) + { + if (BufferUtil.hasContent(buffer)) + content.add(BufferUtil.toString(buffer)); + if (last) + content.add("<>"); + return last; + } + } } diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/SearchPattern.java b/jetty-util/src/main/java/org/eclipse/jetty/util/SearchPattern.java index ee5b91af3a5..1b052dbc19b 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/SearchPattern.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/SearchPattern.java @@ -148,9 +148,9 @@ public class SearchPattern int matchedCount = 0; - for(int i=0; i Date: Tue, 13 Mar 2018 17:52:57 +1100 Subject: [PATCH 15/50] work in progress EPILOGUE and END states implemented, in process of testing them Signed-off-by: Lachlan Roberts --- .../eclipse/jetty/http/MultiPartParser.java | 13 +- .../jetty/http/MultiPartParserTest.java | 129 ++++++++++++++++++ 2 files changed, 137 insertions(+), 5 deletions(-) diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartParser.java b/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartParser.java index 6816c87b43b..d2388ead167 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartParser.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartParser.java @@ -302,7 +302,7 @@ public class MultiPartParser * @param buffer the buffer to parse * @return True if an {@link RequestHandler} method was called and it returned true; */ - public boolean parse(ByteBuffer buffer,boolean last) + public boolean parse(ByteBuffer buffer, boolean last) { boolean handle = false; while(handle==false && BufferUtil.hasContent(buffer)) @@ -327,14 +327,11 @@ public class MultiPartParser handle = parseOctetContent(buffer); break; - case EPILOGUE: - // TODO - handle = true; + BufferUtil.clear(buffer); break; case END: - // TODO handle = true; break; @@ -344,6 +341,12 @@ public class MultiPartParser } } + if(last && _state == State.EPILOGUE) + { + _state = State.END; + _handler.messageComplete(); + } + return handle; } diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParserTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParserTest.java index b878770d0e5..738f0277d74 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParserTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParserTest.java @@ -442,4 +442,133 @@ public class MultiPartParserTest + "The quick brown fox jumped over the lazy dog.\r\n","<>")); } + + @Test + public void testEpilogue() { + List fields = new ArrayList<>(); + List content = new ArrayList<>(); + MultiPartParser parser = new MultiPartParser(new MultiPartParser.Handler() + { + + @Override + public void parsedHeader(String name, String value) + { + fields.add(name+": "+value); + } + + @Override + public boolean headerComplete() + { + fields.add("<>"); + return false; + } + + @Override + public boolean content(ByteBuffer buffer, boolean last) + { + if (BufferUtil.hasContent(buffer)) + content.add(BufferUtil.toString(buffer)); + if (last) + content.add("<>"); + return last; + } + + },"BOUNDARY"); + ByteBuffer data = BufferUtil.toBuffer(""); + + data = BufferUtil.toBuffer("--BOUNDARY\r\n" + + "name: value\n" + + "\r\n" + + "Hello\r\n" + + "--BOUNDARY--" + + "epilogue here:" + + "\r\n" + + "--BOUNDARY--" + + "\r\n" + + "--BOUNDARY"); + parser.parse(data,false); + assertThat(parser.getState(), is(State.DELIMITER)); + assertThat(fields,Matchers.contains("name: value", "<>")); + assertThat(content,Matchers.contains("Hello","<>")); + + parser.parse(data,false); + assertThat(parser.getState(), is(State.EPILOGUE)); + assertThat(data.remaining(),is(0)); + + parser.parse(data,true); + assertThat(parser.getState(), is(State.END)); + } + + + @Test + public void testMultipleContent() { + List fields = new ArrayList<>(); + List content = new ArrayList<>(); + MultiPartParser parser = new MultiPartParser(new MultiPartParser.Handler() + { + + @Override + public void parsedHeader(String name, String value) + { + fields.add(name+": "+value); + } + + @Override + public boolean headerComplete() + { + fields.add("<>"); + return false; + } + + @Override + public boolean content(ByteBuffer buffer, boolean last) + { + if (BufferUtil.hasContent(buffer)) + content.add(BufferUtil.toString(buffer)); + if (last) + content.add("<>"); + return last; + } + + },"BOUNDARY"); + ByteBuffer data = BufferUtil.toBuffer(""); + + data = BufferUtil.toBuffer("--BOUNDARY\r\n" + + "name: value\n" + + "\r\n" + + "Hello" + + "\r\n" + + "--BOUNDARY\r\n" + + "powerLevel: 9001" + + "\r\n" + + "secondary" + + "\r\n" + + "content" + + "\r\n--BOUNDARY--" + + "epilogue here"); + + /* Test First Content Section */ + parser.parse(data,false); + assertThat(parser.getState(), is(State.DELIMITER)); + assertThat(fields,Matchers.contains("name: value", "<>")); + assertThat(content,Matchers.contains("Hello","<>")); + + + /* Test Second Content Section */ + parser.parse(data,false); + assertThat(parser.getState(), is(State.DELIMITER)); + assertThat(fields,Matchers.contains("name: value", "<>","powerLevel: 9001")); + assertThat(content,Matchers.contains("Hello","<>","secondary\r\ncontent")); + + /* Test Progression to EPILOGUE State */ + parser.parse(data,false); + assertThat(parser.getState(), is(State.EPILOGUE)); + assertThat(data.remaining(),is(0)); + + /* Test Progression to END State */ + parser.parse(data,false); + assertThat(parser.getState(), is(State.END)); + assertThat(data.remaining(),is(0)); + } + } From faa32f0c7120f4116add81236a69e5f7ff3e71e0 Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Tue, 13 Mar 2018 18:25:32 +1100 Subject: [PATCH 16/50] improved handler signature Signed-off-by: Greg Wilkins --- .../java/org/eclipse/jetty/http/MultiPartParser.java | 10 ++++++++-- .../org/eclipse/jetty/http/MultiPartParserTest.java | 6 +++--- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartParser.java b/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartParser.java index b09105a4e2a..556a308cd76 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartParser.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartParser.java @@ -351,6 +351,10 @@ public class MultiPartParser _state = State.END; _handler.messageComplete(); } + else + { + _handler.earlyEOF(); + } return handle; } @@ -405,6 +409,7 @@ public class MultiPartParser if (b=='\n') { setState(State.BODY_PART); + _handler.startPart(); return; } @@ -604,7 +609,7 @@ public class MultiPartParser private void handleField() { if (_fieldName!=null && _fieldValue!=null) - _handler.parsedHeader(_fieldName,_fieldValue); + _handler.parsedField(_fieldName,_fieldValue); _fieldName = _fieldValue = null; } @@ -719,7 +724,8 @@ public class MultiPartParser */ public interface Handler { - public default void parsedHeader(String name, String value) {} + public default void startPart() {} + public default void parsedField(String name, String value) {} public default boolean headerComplete() {return false;} public default boolean content(ByteBuffer item, boolean last) {return false;} diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParserTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParserTest.java index 4b5e5167ed9..4add1f8a4dc 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParserTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParserTest.java @@ -329,7 +329,7 @@ public class MultiPartParserTest { @Override - public void parsedHeader(String name, String value) + public void parsedField(String name, String value) { fields.add(name+": "+value); } @@ -386,7 +386,7 @@ public class MultiPartParserTest { @Override - public void parsedHeader(String name, String value) + public void parsedField(String name, String value) { fields.add(name+": "+value); } @@ -456,7 +456,7 @@ public class MultiPartParserTest List content = new ArrayList<>(); @Override - public void parsedHeader(String name, String value) + public void parsedField(String name, String value) { fields.add(name+": "+value); } From 20c9fb45f8fca42d01cca15f8a1c508ce5aecb5d Mon Sep 17 00:00:00 2001 From: Lachlan Roberts Date: Tue, 13 Mar 2018 20:21:10 +1100 Subject: [PATCH 17/50] Reworked the tests on EPILOGUE and multiple content. All tests are passing. Signed-off-by: Lachlan Roberts --- .../jetty/http/MultiPartParserTest.java | 89 ++++--------------- 1 file changed, 18 insertions(+), 71 deletions(-) diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParserTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParserTest.java index 4add1f8a4dc..dbb842d7888 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParserTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParserTest.java @@ -323,38 +323,11 @@ public class MultiPartParserTest @Test public void testEpilogue() { - List fields = new ArrayList<>(); - List content = new ArrayList<>(); - MultiPartParser parser = new MultiPartParser(new MultiPartParser.Handler() - { - - @Override - public void parsedField(String name, String value) - { - fields.add(name+": "+value); - } - - @Override - public boolean headerComplete() - { - fields.add("<>"); - return false; - } - - @Override - public boolean content(ByteBuffer buffer, boolean last) - { - if (BufferUtil.hasContent(buffer)) - content.add(BufferUtil.toString(buffer)); - if (last) - content.add("<>"); - return last; - } - - },"BOUNDARY"); - ByteBuffer data = BufferUtil.toBuffer(""); + TestHandler handler = new TestHandler(); + MultiPartParser parser = new MultiPartParser(handler,"BOUNDARY"); - data = BufferUtil.toBuffer("--BOUNDARY\r\n" + ByteBuffer data = BufferUtil.toBuffer("" + + "--BOUNDARY\r\n" + "name: value\n" + "\r\n" + "Hello\r\n" @@ -364,10 +337,12 @@ public class MultiPartParserTest + "--BOUNDARY--" + "\r\n" + "--BOUNDARY"); + + parser.parse(data,false); assertThat(parser.getState(), is(State.DELIMITER)); - assertThat(fields,Matchers.contains("name: value", "<>")); - assertThat(content,Matchers.contains("Hello","<>")); + assertThat(handler.fields,Matchers.contains("name: value", "<>")); + assertThat(handler.content,Matchers.contains("Hello","<>")); parser.parse(data,false); assertThat(parser.getState(), is(State.EPILOGUE)); @@ -380,44 +355,17 @@ public class MultiPartParserTest @Test public void testMultipleContent() { - List fields = new ArrayList<>(); - List content = new ArrayList<>(); - MultiPartParser parser = new MultiPartParser(new MultiPartParser.Handler() - { - - @Override - public void parsedField(String name, String value) - { - fields.add(name+": "+value); - } - - @Override - public boolean headerComplete() - { - fields.add("<>"); - return false; - } - - @Override - public boolean content(ByteBuffer buffer, boolean last) - { - if (BufferUtil.hasContent(buffer)) - content.add(BufferUtil.toString(buffer)); - if (last) - content.add("<>"); - return last; - } - - },"BOUNDARY"); - ByteBuffer data = BufferUtil.toBuffer(""); + TestHandler handler = new TestHandler(); + MultiPartParser parser = new MultiPartParser(handler,"BOUNDARY"); - data = BufferUtil.toBuffer("--BOUNDARY\r\n" + ByteBuffer data = BufferUtil.toBuffer("" + + "--BOUNDARY\r\n" + "name: value\n" + "\r\n" + "Hello" + "\r\n" + "--BOUNDARY\r\n" - + "powerLevel: 9001" + + "powerLevel: 9001\n" + "\r\n" + "secondary" + "\r\n" @@ -428,15 +376,14 @@ public class MultiPartParserTest /* Test First Content Section */ parser.parse(data,false); assertThat(parser.getState(), is(State.DELIMITER)); - assertThat(fields,Matchers.contains("name: value", "<>")); - assertThat(content,Matchers.contains("Hello","<>")); - + assertThat(handler.fields, Matchers.contains("name: value", "<>")); + assertThat(handler.content, Matchers.contains("Hello","<>")); /* Test Second Content Section */ parser.parse(data,false); assertThat(parser.getState(), is(State.DELIMITER)); - assertThat(fields,Matchers.contains("name: value", "<>","powerLevel: 9001")); - assertThat(content,Matchers.contains("Hello","<>","secondary\r\ncontent")); + assertThat(handler.fields, Matchers.contains("name: value", "<>","powerLevel: 9001","<>")); + assertThat(handler.content, Matchers.contains("Hello","<>","secondary\r\ncontent","<>")); /* Test Progression to EPILOGUE State */ parser.parse(data,false); @@ -444,7 +391,7 @@ public class MultiPartParserTest assertThat(data.remaining(),is(0)); /* Test Progression to END State */ - parser.parse(data,false); + parser.parse(data,true); assertThat(parser.getState(), is(State.END)); assertThat(data.remaining(),is(0)); } From 4dce09c067baf25cca34b94efff65f3262bf4c26 Mon Sep 17 00:00:00 2001 From: Lachlan Roberts Date: Wed, 14 Mar 2018 14:27:03 +1100 Subject: [PATCH 18/50] Completed the split test. Signed-off-by: Lachlan Roberts --- .../eclipse/jetty/http/MultiPartParser.java | 28 ++- .../jetty/http/MultiPartParserTest.java | 175 ++++++++++++++++++ 2 files changed, 195 insertions(+), 8 deletions(-) diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartParser.java b/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartParser.java index 556a308cd76..b813a52532b 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartParser.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartParser.java @@ -175,6 +175,14 @@ public class MultiPartParser _delimiterSearch = SearchPattern.compile(_patternBuffer.array()); } + public void reset() + { + _state = State.PREAMBLE; + _fieldState = FieldState.FIELD; + _partialBoundary = 2; // No CRLF if no preamble + } + + /* ------------------------------------------------------------------------------- */ public Handler getHandler() { @@ -346,16 +354,20 @@ public class MultiPartParser } } - if(last && _state == State.EPILOGUE) + if(last) { - _state = State.END; - _handler.messageComplete(); + if(_state == State.EPILOGUE) + { + _state = State.END; + return _handler.messageComplete(); + } + else if(BufferUtil.isEmpty(buffer)) + { + _handler.earlyEOF(); + return true; + } + } - else - { - _handler.earlyEOF(); - } - return handle; } diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParserTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParserTest.java index dbb842d7888..965e86618a1 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParserTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParserTest.java @@ -28,6 +28,7 @@ import java.util.List; import org.eclipse.jetty.http.MultiPartParser.State; import org.eclipse.jetty.util.BufferUtil; import org.hamcrest.Matchers; +import org.junit.Ignore; import org.junit.Test; public class MultiPartParserTest @@ -320,6 +321,32 @@ public class MultiPartParserTest + "The quick brown fox jumped over the lazy dog.\r\n","<>")); } + @Test + public void testFirstPartLongContentNoCarriageReturn() + { + TestHandler handler = new TestHandler(); + MultiPartParser parser = new MultiPartParser(handler,"BOUNDARY"); + + ByteBuffer data = BufferUtil.toBuffer(""); + + //boundary still requires carriage return + data = BufferUtil.toBuffer("--BOUNDARY\n" + + "name: value\n" + + "\n" + + "Now is the time for all good men to come to the aid of the party.\n" + + "How now brown cow.\n" + + "The quick brown fox jumped over the lazy dog.\n" + + "\r\n" + + "--BOUNDARY"); + parser.parse(data,false); + assertThat(parser.getState(), is(State.DELIMITER)); + assertThat(data.remaining(),is(0)); + assertThat(handler.fields,Matchers.contains("name: value", "<>")); + assertThat(handler.content,Matchers.contains("Now is the time for all good men to come to the aid of the party.\n" + + "How now brown cow.\n" + + "The quick brown fox jumped over the lazy dog.\n","<>")); + } + @Test public void testEpilogue() { @@ -396,6 +423,141 @@ public class MultiPartParserTest assertThat(data.remaining(),is(0)); } + @Test + public void splitTest() + { + TestHandler handler = new TestHandler() + { + @Override + public boolean messageComplete() + { + return true; + } + + @Override + public boolean content(ByteBuffer buffer, boolean last) + { + super.content(buffer,last); + return false; + } + }; + + MultiPartParser parser = new MultiPartParser(handler,"---------------------------9051914041544843365972754266"); + ByteBuffer data = BufferUtil.toBuffer(""+ + "POST / HTTP/1.1\n" + + "Host: localhost:8000\n" + + "User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:29.0) Gecko/20100101 Firefox/29.0\n" + + "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\n" + + "Accept-Language: en-US,en;q=0.5\n" + + "Accept-Encoding: gzip, deflate\n" + + "Cookie: __atuvc=34%7C7; permanent=0; _gitlab_session=226ad8a0be43681acf38c2fab9497240; __profilin=p%3Dt; request_method=GET\n" + + "Connection: keep-alive\n" + + "Content-Type: multipart/form-data; boundary=---------------------------9051914041544843365972754266\n" + + "Content-Length: 554\n" + + "\r\n" + + "-----------------------------9051914041544843365972754266\n" + + "Content-Disposition: form-data; name=\"text\"\n" + + "\n" + + "text default\r\n" + + "-----------------------------9051914041544843365972754266\n" + + "Content-Disposition: form-data; name=\"file1\"; filename=\"a.txt\"\n" + + "Content-Type: text/plain\n" + + "\n" + + "Content of a.txt.\n" + + "\r\n" + + "-----------------------------9051914041544843365972754266\n" + + "Content-Disposition: form-data; name=\"file2\"; filename=\"a.html\"\n" + + "Content-Type: text/html\n" + + "\n" + + "Content of a.html.\n" + + "\r\n" + + "-----------------------------9051914041544843365972754266\n" + + "Field1: value1\n" + + "Field2: value2\n" + + "Field3: value3\n" + + "Field4: value4\n" + + "Field5: value5\n" + + "Field6: value6\n" + + "Field7: value7\n" + + "Field8: value8\n" + + "Field9: value\n" + + " 9\n" + + "\r\n" + + "-----------------------------9051914041544843365972754266\n" + + "Field1: value1\n" + + "\r\n"+ + "But the amount of denudation which the strata have\n" + + "in many places suffered, independently of the rate\n" + + "of accumulation of the degraded matter, probably\n" + + "offers the best evidence of the lapse of time. I remember\n" + + "having been much struck with the evidence of\n" + + "denudation, when viewing volcanic islands, which\n" + + "have been worn by the waves and pared all round\n" + + "into perpendicular cliffs of one or two thousand feet\n" + + "in height; for the gentle slope of the lava-streams,\n" + + "due to their formerly liquid state, showed at a glance\n" + + "how far the hard, rocky beds had once extended into\n" + + "the open ocean.\n" + + "\r\n" + + "-----------------------------9051914041544843365972754266--" + + "===== ajlkfja;lkdj;lakjd;lkjf ==== epilogue here ==== kajflajdfl;kjafl;kjl;dkfja ====\n\r\n\r\r\r\n\n\n"); + + + int length = data.remaining(); + for(int i = 0; i>" + , "Content-Disposition: form-data; name=\"file1\"; filename=\"a.txt\"" + , "Content-Type: text/plain","<>" + , "Content-Disposition: form-data; name=\"file2\"; filename=\"a.html\"" + , "Content-Type: text/html","<>" + , "Field1: value1", "Field2: value2", "Field3: value3" + , "Field4: value4", "Field5: value5", "Field6: value6" + , "Field7: value7", "Field8: value8", "Field9: value 9", "<>" + , "Field1: value1","<>")); + + + System.out.println("iteration "+i); + System.out.println(handler.content); + assertThat(handler.contentString(), is(new String("text default"+"<>" + + "Content of a.txt.\n"+"<>" + + "Content of a.html.\n"+"<>" + + "<>" + + "But the amount of denudation which the strata have\n" + + "in many places suffered, independently of the rate\n" + + "of accumulation of the degraded matter, probably\n" + + "offers the best evidence of the lapse of time. I remember\n" + + "having been much struck with the evidence of\n" + + "denudation, when viewing volcanic islands, which\n" + + "have been worn by the waves and pared all round\n" + + "into perpendicular cliffs of one or two thousand feet\n" + + "in height; for the gentle slope of the lava-streams,\n" + + "due to their formerly liquid state, showed at a glance\n" + + "how far the hard, rocky beds had once extended into\n" + + "the open ocean.\n"+ "<>"))); + + handler.clear(); + parser.reset(); + } + } + static class TestHandler implements MultiPartParser.Handler { @@ -408,6 +570,13 @@ public class MultiPartParserTest fields.add(name+": "+value); } + public String contentString() + { + StringBuilder sb = new StringBuilder(); + for(String s : content) sb.append(s); + return sb.toString(); + } + @Override public boolean headerComplete() { @@ -424,6 +593,12 @@ public class MultiPartParserTest content.add("<>"); return last; } + + public void clear() { + fields.clear(); + content.clear(); + } + } } From a77a127da00c8f4794a36573a653af81860d53a5 Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Wed, 14 Mar 2018 15:02:56 +1100 Subject: [PATCH 19/50] tests and fixes for binary keys and content Signed-off-by: Greg Wilkins --- .../jetty/http/MultiPartParserTest.java | 37 +++++++++++++++++- .../org/eclipse/jetty/util/SearchPattern.java | 7 ++-- .../eclipse/jetty/util/SearchPatternTest.java | 38 +++++++++++++++++++ 3 files changed, 76 insertions(+), 6 deletions(-) diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParserTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParserTest.java index 965e86618a1..0added79b5f 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParserTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParserTest.java @@ -23,7 +23,9 @@ import static org.junit.Assert.*; import java.nio.ByteBuffer; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; +import java.util.concurrent.ThreadLocalRandom; import org.eclipse.jetty.http.MultiPartParser.State; import org.eclipse.jetty.util.BufferUtil; @@ -291,8 +293,6 @@ public class MultiPartParserTest assertThat(data.remaining(),is(0)); assertThat(handler.fields,Matchers.contains("name: value", "<>")); assertThat(handler.content,Matchers.contains("Hello","<>")); - - } @@ -346,7 +346,40 @@ public class MultiPartParserTest + "How now brown cow.\n" + "The quick brown fox jumped over the lazy dog.\n","<>")); } + + @Test + public void testBinaryPart() + { + byte[] random = new byte[8192]; + final ByteBuffer bytes = BufferUtil.allocate(random.length); + ThreadLocalRandom.current().nextBytes(random); + // Arrays.fill(random,(byte)'X'); + + TestHandler handler = new TestHandler() + { + @Override + public boolean content(ByteBuffer buffer, boolean last) + { + BufferUtil.append(bytes,buffer); + return last; + } + }; + MultiPartParser parser = new MultiPartParser(handler,"BOUNDARY"); + + String preamble = "Blah blah blah\r\n--BOUNDARY\r\n\r\n"; + String epilogue = "\r\n--BOUNDARY\r\nBlah blah blah!\r\n"; + + ByteBuffer data = BufferUtil.allocate(preamble.length()+random.length+epilogue.length()); + BufferUtil.append(data,BufferUtil.toBuffer(preamble)); + BufferUtil.append(data,ByteBuffer.wrap(random)); + BufferUtil.append(data,BufferUtil.toBuffer(epilogue)); + + parser.parse(data,true); + assertThat(parser.getState(), is(State.DELIMITER)); + assertThat(data.remaining(),is(19)); + assertThat(bytes.array(),is(random)); + } @Test public void testEpilogue() { diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/SearchPattern.java b/jetty-util/src/main/java/org/eclipse/jetty/util/SearchPattern.java index 1b052dbc19b..ab894211247 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/SearchPattern.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/SearchPattern.java @@ -78,7 +78,7 @@ public class SearchPattern for(int i = 0; i Date: Wed, 14 Mar 2018 15:51:43 +1100 Subject: [PATCH 20/50] Moved a copy of MultipartInputStreamParser and MultipartInputStreamTest into jetty.http Signed-off-by: Lachlan Roberts --- jetty-http/pom.xml | 5 + .../http/MultiPartInputStreamParser.java | 928 ++++++++++++++ .../jetty/http/MultiPartInputStreamTest.java | 1076 +++++++++++++++++ 3 files changed, 2009 insertions(+) create mode 100644 jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartInputStreamParser.java create mode 100644 jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartInputStreamTest.java diff --git a/jetty-http/pom.xml b/jetty-http/pom.xml index 2d0b5735314..cae6d2d1cbb 100644 --- a/jetty-http/pom.xml +++ b/jetty-http/pom.xml @@ -23,6 +23,11 @@ jetty-io ${project.version} + + javax.servlet + javax.servlet-api + provided + org.eclipse.jetty.toolchain jetty-test-helper diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartInputStreamParser.java b/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartInputStreamParser.java new file mode 100644 index 00000000000..01703a8785f --- /dev/null +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartInputStreamParser.java @@ -0,0 +1,928 @@ +// +// ======================================================================== +// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http; + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.FilterInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardCopyOption; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Locale; +import java.util.Map; + +import javax.servlet.MultipartConfigElement; +import javax.servlet.ServletInputStream; +import javax.servlet.http.Part; + +import org.eclipse.jetty.util.B64Code; +import org.eclipse.jetty.util.ByteArrayOutputStream2; +import org.eclipse.jetty.util.LazyList; +import org.eclipse.jetty.util.MultiException; +import org.eclipse.jetty.util.MultiMap; +import org.eclipse.jetty.util.QuotedStringTokenizer; +import org.eclipse.jetty.util.ReadLineInputStream; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; + + + +/** + * MultiPartInputStream + * + * Handle a MultiPart Mime input stream, breaking it up on the boundary into files and strings. + */ +public class MultiPartInputStreamParser +{ + private static final Logger LOG = Log.getLogger(MultiPartInputStreamParser.class); + public static final MultipartConfigElement __DEFAULT_MULTIPART_CONFIG = new MultipartConfigElement(System.getProperty("java.io.tmpdir")); + public static final MultiMap EMPTY_MAP = new MultiMap<>(Collections.emptyMap()); + protected InputStream _in; + protected MultipartConfigElement _config; + protected String _contentType; + protected MultiMap _parts; + protected Exception _err; + protected File _tmpDir; + protected File _contextTmpDir; + protected boolean _deleteOnExit; + protected boolean _writeFilesWithFilenames; + + + + public class MultiPart implements Part + { + protected String _name; + protected String _filename; + protected File _file; + protected OutputStream _out; + protected ByteArrayOutputStream2 _bout; + protected String _contentType; + protected MultiMap _headers; + protected long _size = 0; + protected boolean _temporary = true; + + public MultiPart (String name, String filename) + throws IOException + { + _name = name; + _filename = filename; + } + + @Override + public String toString() + { + return String.format("Part{n=%s,fn=%s,ct=%s,s=%d,t=%b,f=%s}",_name,_filename,_contentType,_size,_temporary,_file); + } + protected void setContentType (String contentType) + { + _contentType = contentType; + } + + + protected void open() + throws IOException + { + //We will either be writing to a file, if it has a filename on the content-disposition + //and otherwise a byte-array-input-stream, OR if we exceed the getFileSizeThreshold, we + //will need to change to write to a file. + if (isWriteFilesWithFilenames() && _filename != null && _filename.trim().length() > 0) + { + createFile(); + } + else + { + //Write to a buffer in memory until we discover we've exceed the + //MultipartConfig fileSizeThreshold + _out = _bout= new ByteArrayOutputStream2(); + } + } + + protected void close() + throws IOException + { + _out.close(); + } + + + protected void write (int b) + throws IOException + { + if (MultiPartInputStreamParser.this._config.getMaxFileSize() > 0 && _size + 1 > MultiPartInputStreamParser.this._config.getMaxFileSize()) + throw new IllegalStateException ("Multipart Mime part "+_name+" exceeds max filesize"); + + if (MultiPartInputStreamParser.this._config.getFileSizeThreshold() > 0 && _size + 1 > MultiPartInputStreamParser.this._config.getFileSizeThreshold() && _file==null) + createFile(); + + _out.write(b); + _size ++; + } + + protected void write (byte[] bytes, int offset, int length) + throws IOException + { + if (MultiPartInputStreamParser.this._config.getMaxFileSize() > 0 && _size + length > MultiPartInputStreamParser.this._config.getMaxFileSize()) + throw new IllegalStateException ("Multipart Mime part "+_name+" exceeds max filesize"); + + if (MultiPartInputStreamParser.this._config.getFileSizeThreshold() > 0 && _size + length > MultiPartInputStreamParser.this._config.getFileSizeThreshold() && _file==null) + createFile(); + + _out.write(bytes, offset, length); + _size += length; + } + + protected void createFile () + throws IOException + { + /* Some statics just to make the code below easier to understand + * This get optimized away during the compile anyway */ + final boolean USER = true; + final boolean WORLD = false; + + _file = File.createTempFile("MultiPart", "", MultiPartInputStreamParser.this._tmpDir); + _file.setReadable(false,WORLD); // (reset) disable it for everyone first + _file.setReadable(true,USER); // enable for user only + + if (_deleteOnExit) + _file.deleteOnExit(); + FileOutputStream fos = new FileOutputStream(_file); + BufferedOutputStream bos = new BufferedOutputStream(fos); + + if (_size > 0 && _out != null) + { + //already written some bytes, so need to copy them into the file + _out.flush(); + _bout.writeTo(bos); + _out.close(); + _bout = null; + } + _out = bos; + } + + + + protected void setHeaders(MultiMap headers) + { + _headers = headers; + } + + /** + * @see javax.servlet.http.Part#getContentType() + */ + @Override + public String getContentType() + { + return _contentType; + } + + /** + * @see javax.servlet.http.Part#getHeader(java.lang.String) + */ + @Override + public String getHeader(String name) + { + if (name == null) + return null; + return _headers.getValue(name.toLowerCase(Locale.ENGLISH), 0); + } + + /** + * @see javax.servlet.http.Part#getHeaderNames() + */ + @Override + public Collection getHeaderNames() + { + return _headers.keySet(); + } + + /** + * @see javax.servlet.http.Part#getHeaders(java.lang.String) + */ + @Override + public Collection getHeaders(String name) + { + return _headers.getValues(name); + } + + /** + * @see javax.servlet.http.Part#getInputStream() + */ + @Override + public InputStream getInputStream() throws IOException + { + if (_file != null) + { + //written to a file, whether temporary or not + return new BufferedInputStream (new FileInputStream(_file)); + } + else + { + //part content is in memory + return new ByteArrayInputStream(_bout.getBuf(),0,_bout.size()); + } + } + + + /** + * @see javax.servlet.http.Part#getSubmittedFileName() + */ + @Override + public String getSubmittedFileName() + { + return getContentDispositionFilename(); + } + + public byte[] getBytes() + { + if (_bout!=null) + return _bout.toByteArray(); + return null; + } + + /** + * @see javax.servlet.http.Part#getName() + */ + @Override + public String getName() + { + return _name; + } + + /** + * @see javax.servlet.http.Part#getSize() + */ + @Override + public long getSize() + { + return _size; + } + + /** + * @see javax.servlet.http.Part#write(java.lang.String) + */ + @Override + public void write(String fileName) throws IOException + { + if (_file == null) + { + _temporary = false; + + //part data is only in the ByteArrayOutputStream and never been written to disk + _file = new File (_tmpDir, fileName); + + BufferedOutputStream bos = null; + try + { + bos = new BufferedOutputStream(new FileOutputStream(_file)); + _bout.writeTo(bos); + bos.flush(); + } + finally + { + if (bos != null) + bos.close(); + _bout = null; + } + } + else + { + //the part data is already written to a temporary file, just rename it + _temporary = false; + + Path src = _file.toPath(); + Path target = src.resolveSibling(fileName); + Files.move(src, target, StandardCopyOption.REPLACE_EXISTING); + _file = target.toFile(); + } + } + + /** + * Remove the file, whether or not Part.write() was called on it + * (ie no longer temporary) + * @see javax.servlet.http.Part#delete() + */ + @Override + public void delete() throws IOException + { + if (_file != null && _file.exists()) + _file.delete(); + } + + /** + * Only remove tmp files. + * + * @throws IOException if unable to delete the file + */ + public void cleanUp() throws IOException + { + if (_temporary && _file != null && _file.exists()) + _file.delete(); + } + + + /** + * Get the file + * @return the file, if any, the data has been written to. + */ + public File getFile () + { + return _file; + } + + + /** + * Get the filename from the content-disposition. + * @return null or the filename + */ + public String getContentDispositionFilename () + { + return _filename; + } + } + + + + + /** + * @param in Request input stream + * @param contentType Content-Type header + * @param config MultipartConfigElement + * @param contextTmpDir javax.servlet.context.tempdir + */ + public MultiPartInputStreamParser (InputStream in, String contentType, MultipartConfigElement config, File contextTmpDir) + { + _contentType = contentType; + _config = config; + _contextTmpDir = contextTmpDir; + if (_contextTmpDir == null) + _contextTmpDir = new File (System.getProperty("java.io.tmpdir")); + + if (_config == null) + _config = new MultipartConfigElement(_contextTmpDir.getAbsolutePath()); + + if (in instanceof ServletInputStream) + { + if (((ServletInputStream)in).isFinished()) + { + _parts = EMPTY_MAP; + return; + } + } + _in = new ReadLineInputStream(in); + } + + /** + * Get the already parsed parts. + * @return the parts that were parsed + */ + public Collection getParsedParts() + { + if (_parts == null) + return Collections.emptyList(); + + Collection> values = _parts.values(); + List parts = new ArrayList<>(); + for (List o: values) + { + List asList = LazyList.getList(o, false); + parts.addAll(asList); + } + return parts; + } + + /** + * Delete any tmp storage for parts, and clear out the parts list. + * + * @throws MultiException if unable to delete the parts + */ + public void deleteParts () + throws MultiException + { + Collection parts = getParsedParts(); + MultiException err = new MultiException(); + for (Part p:parts) + { + try + { + ((MultiPartInputStreamParser.MultiPart)p).cleanUp(); + } + catch(Exception e) + { + err.add(e); + } + } + _parts.clear(); + + err.ifExceptionThrowMulti(); + } + + + /** + * Parse, if necessary, the multipart data and return the list of Parts. + * + * @return the parts + * @throws IOException if unable to get the parts + */ + public Collection getParts() + throws IOException + { + parse(); + throwIfError(); + + + Collection> values = _parts.values(); + List parts = new ArrayList<>(); + for (List o: values) + { + List asList = LazyList.getList(o, false); + parts.addAll(asList); + } + return parts; + } + + + /** + * Get the named Part. + * + * @param name the part name + * @return the parts + * @throws IOException if unable to get the part + */ + public Part getPart(String name) + throws IOException + { + parse(); + throwIfError(); + return _parts.getValue(name, 0); + } + + /** + * Throws an exception if one has been latched. + * + * @throws IOException the exception (if present) + */ + protected void throwIfError () + throws IOException + { + if (_err != null) + { + if (_err instanceof IOException) + throw (IOException)_err; + if (_err instanceof IllegalStateException) + throw (IllegalStateException)_err; + throw new IllegalStateException(_err); + } + } + + /** + * Parse, if necessary, the multipart stream. + * + */ + protected void parse () + { + //have we already parsed the input? + if (_parts != null || _err != null) + return; + + + //initialize + long total = 0; //keep running total of size of bytes read from input and throw an exception if exceeds MultipartConfigElement._maxRequestSize + _parts = new MultiMap<>(); + + //if its not a multipart request, don't parse it + if (_contentType == null || !_contentType.startsWith("multipart/form-data")) + return; + + try + { + //sort out the location to which to write the files + + if (_config.getLocation() == null) + _tmpDir = _contextTmpDir; + else if ("".equals(_config.getLocation())) + _tmpDir = _contextTmpDir; + else + { + File f = new File (_config.getLocation()); + if (f.isAbsolute()) + _tmpDir = f; + else + _tmpDir = new File (_contextTmpDir, _config.getLocation()); + } + + if (!_tmpDir.exists()) + _tmpDir.mkdirs(); + + String contentTypeBoundary = ""; + int bstart = _contentType.indexOf("boundary="); + if (bstart >= 0) + { + int bend = _contentType.indexOf(";", bstart); + bend = (bend < 0? _contentType.length(): bend); + contentTypeBoundary = QuotedStringTokenizer.unquote(value(_contentType.substring(bstart,bend)).trim()); + } + + String boundary="--"+contentTypeBoundary; + String lastBoundary=boundary+"--"; + byte[] byteBoundary=lastBoundary.getBytes(StandardCharsets.ISO_8859_1); + + // Get first boundary + String line = null; + try + { + line=((ReadLineInputStream)_in).readLine(); + } + catch (IOException e) + { + LOG.warn("Badly formatted multipart request"); + throw e; + } + + if (line == null) + throw new IOException("Missing content for multipart request"); + + boolean badFormatLogged = false; + line=line.trim(); + while (line != null && !line.equals(boundary) && !line.equals(lastBoundary)) + { + if (!badFormatLogged) + { + LOG.warn("Badly formatted multipart request"); + badFormatLogged = true; + } + line=((ReadLineInputStream)_in).readLine(); + line=(line==null?line:line.trim()); + } + + if (line == null || line.length() == 0) + throw new IOException("Missing initial multi part boundary"); + + // Empty multipart. + if (line.equals(lastBoundary)) + return; + + // Read each part + boolean lastPart=false; + + outer:while(!lastPart) + { + String contentDisposition=null; + String contentType=null; + String contentTransferEncoding=null; + + MultiMap headers = new MultiMap<>(); + while(true) + { + line=((ReadLineInputStream)_in).readLine(); + + //No more input + if(line==null) + break outer; + + //end of headers: + if("".equals(line)) + break; + + total += line.length(); + if (_config.getMaxRequestSize() > 0 && total > _config.getMaxRequestSize()) + throw new IllegalStateException ("Request exceeds maxRequestSize ("+_config.getMaxRequestSize()+")"); + + //get content-disposition and content-type + int c=line.indexOf(':',0); + if(c>0) + { + String key=line.substring(0,c).trim().toLowerCase(Locale.ENGLISH); + String value=line.substring(c+1,line.length()).trim(); + headers.put(key, value); + if (key.equalsIgnoreCase("content-disposition")) + contentDisposition=value; + if (key.equalsIgnoreCase("content-type")) + contentType = value; + if(key.equals("content-transfer-encoding")) + contentTransferEncoding=value; + } + } + + // Extract content-disposition + boolean form_data=false; + if(contentDisposition==null) + { + throw new IOException("Missing content-disposition"); + } + + QuotedStringTokenizer tok=new QuotedStringTokenizer(contentDisposition,";", false, true); + String name=null; + String filename=null; + while(tok.hasMoreTokens()) + { + String t=tok.nextToken().trim(); + String tl=t.toLowerCase(Locale.ENGLISH); + if(t.startsWith("form-data")) + form_data=true; + else if(tl.startsWith("name=")) + name=value(t); + else if(tl.startsWith("filename=")) + filename=filenameValue(t); + } + + // Check disposition + if(!form_data) + { + continue; + } + //It is valid for reset and submit buttons to have an empty name. + //If no name is supplied, the browser skips sending the info for that field. + //However, if you supply the empty string as the name, the browser sends the + //field, with name as the empty string. So, only continue this loop if we + //have not yet seen a name field. + if(name==null) + { + continue; + } + + //Have a new Part + MultiPart part = new MultiPart(name, filename); + part.setHeaders(headers); + part.setContentType(contentType); + _parts.add(name, part); + part.open(); + + InputStream partInput = null; + if ("base64".equalsIgnoreCase(contentTransferEncoding)) + { + partInput = new Base64InputStream((ReadLineInputStream)_in); + } + else if ("quoted-printable".equalsIgnoreCase(contentTransferEncoding)) + { + partInput = new FilterInputStream(_in) + { + @Override + public int read() throws IOException + { + int c = in.read(); + if (c >= 0 && c == '=') + { + int hi = in.read(); + int lo = in.read(); + if (hi < 0 || lo < 0) + { + throw new IOException("Unexpected end to quoted-printable byte"); + } + char[] chars = new char[] { (char)hi, (char)lo }; + c = Integer.parseInt(new String(chars),16); + } + return c; + } + }; + } + else + partInput = _in; + + + try + { + int state=-2; + int c; + boolean cr=false; + boolean lf=false; + + // loop for all lines + while(true) + { + int b=0; + while((c=(state!=-2)?state:partInput.read())!=-1) + { + total ++; + if (_config.getMaxRequestSize() > 0 && total > _config.getMaxRequestSize()) + throw new IllegalStateException("Request exceeds maxRequestSize ("+_config.getMaxRequestSize()+")"); + + state=-2; + + // look for CR and/or LF + if(c==13||c==10) + { + if(c==13) + { + partInput.mark(1); + int tmp=partInput.read(); + if (tmp!=10) + partInput.reset(); + else + state=tmp; + } + break; + } + + // Look for boundary + if(b>=0&&b0) + part.write(byteBoundary,0,b); + + b=-1; + part.write(c); + } + } + + // Check for incomplete boundary match, writing out the chars we matched along the way + if((b>0&&b0||c==-1) + { + + if(b==byteBoundary.length) + lastPart=true; + if(state==10) + state=-2; + break; + } + + // handle CR LF + if(cr) + part.write(13); + + if(lf) + part.write(10); + + cr=(c==13); + lf=(c==10||state==10); + if(state==10) + state=-2; + } + } + finally + { + part.close(); + } + } + if (lastPart) + { + while(line!=null) + line=((ReadLineInputStream)_in).readLine(); + } + else + throw new IOException("Incomplete parts"); + } + catch (Exception e) + { + _err = e; + } + } + + public void setDeleteOnExit(boolean deleteOnExit) + { + _deleteOnExit = deleteOnExit; + } + + public void setWriteFilesWithFilenames (boolean writeFilesWithFilenames) + { + _writeFilesWithFilenames = writeFilesWithFilenames; + } + + public boolean isWriteFilesWithFilenames () + { + return _writeFilesWithFilenames; + } + + public boolean isDeleteOnExit() + { + return _deleteOnExit; + } + + + /* ------------------------------------------------------------ */ + private String value(String nameEqualsValue) + { + int idx = nameEqualsValue.indexOf('='); + String value = nameEqualsValue.substring(idx+1).trim(); + return QuotedStringTokenizer.unquoteOnly(value); + } + + + /* ------------------------------------------------------------ */ + private String filenameValue(String nameEqualsValue) + { + int idx = nameEqualsValue.indexOf('='); + String value = nameEqualsValue.substring(idx+1).trim(); + + if (value.matches(".??[a-z,A-Z]\\:\\\\[^\\\\].*")) + { + //incorrectly escaped IE filenames that have the whole path + //we just strip any leading & trailing quotes and leave it as is + char first=value.charAt(0); + if (first=='"' || first=='\'') + value=value.substring(1); + char last=value.charAt(value.length()-1); + if (last=='"' || last=='\'') + value = value.substring(0,value.length()-1); + + return value; + } + else + //unquote the string, but allow any backslashes that don't + //form a valid escape sequence to remain as many browsers + //even on *nix systems will not escape a filename containing + //backslashes + return QuotedStringTokenizer.unquoteOnly(value, true); + } + + + + private static class Base64InputStream extends InputStream + { + ReadLineInputStream _in; + String _line; + byte[] _buffer; + int _pos; + + + public Base64InputStream(ReadLineInputStream rlis) + { + _in = rlis; + } + + @Override + public int read() throws IOException + { + if (_buffer==null || _pos>= _buffer.length) + { + //Any CR and LF will be consumed by the readLine() call. + //We need to put them back into the bytes returned from this + //method because the parsing of the multipart content uses them + //as markers to determine when we've reached the end of a part. + _line = _in.readLine(); + if (_line==null) + return -1; //nothing left + if (_line.startsWith("--")) + _buffer=(_line+"\r\n").getBytes(); //boundary marking end of part + else if (_line.length()==0) + _buffer="\r\n".getBytes(); //blank line + else + { + ByteArrayOutputStream baos = new ByteArrayOutputStream((4*_line.length()/3)+2); + B64Code.decode(_line, baos); + baos.write(13); + baos.write(10); + _buffer = baos.toByteArray(); + } + + _pos=0; + } + + return _buffer[_pos++]; + } + } +} diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartInputStreamTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartInputStreamTest.java new file mode 100644 index 00000000000..e833e16d1cb --- /dev/null +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartInputStreamTest.java @@ -0,0 +1,1076 @@ +// +// ======================================================================== +// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http; + +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.not; +import static org.hamcrest.Matchers.notNullValue; +import static org.hamcrest.Matchers.nullValue; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.Collection; +import java.util.concurrent.TimeUnit; + +import javax.servlet.MultipartConfigElement; +import javax.servlet.ReadListener; +import javax.servlet.ServletException; +import javax.servlet.ServletInputStream; +import javax.servlet.http.Part; + +import org.eclipse.jetty.http.MultiPartInputStreamParser.MultiPart; +import org.eclipse.jetty.util.B64Code; +import org.eclipse.jetty.util.IO; +import org.hamcrest.Matchers; +import org.junit.Test; + +/** + * MultiPartInputStreamTest + * + * + */ +public class MultiPartInputStreamTest +{ + private static final String FILENAME = "stuff.txt"; + protected String _contentType = "multipart/form-data, boundary=AaB03x"; + protected String _multi = createMultipartRequestString(FILENAME); + protected String _dirname = System.getProperty("java.io.tmpdir")+File.separator+"myfiles-"+TimeUnit.NANOSECONDS.toMillis(System.nanoTime()); + protected File _tmpDir = new File(_dirname); + + public MultiPartInputStreamTest () + { + _tmpDir.deleteOnExit(); + } + + @Test + public void testBadMultiPartRequest() + throws Exception + { + String boundary = "X0Y0"; + String str = "--" + boundary + "\r\n"+ + "Content-Disposition: form-data; name=\"fileup\"; filename=\"test.upload\"\r\n"+ + "Content-Type: application/octet-stream\r\n\r\n"+ + "How now brown cow."+ + "\r\n--" + boundary + "-\r\n\r\n"; + + MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50); + MultiPartInputStreamParser mpis = new MultiPartInputStreamParser(new ByteArrayInputStream(str.getBytes()), + "multipart/form-data, boundary="+boundary, + config, + _tmpDir); + mpis.setDeleteOnExit(true); + try + { + mpis.getParts(); + fail ("Multipart incomplete"); + } + catch (IOException e) + { + assertTrue(e.getMessage().startsWith("Incomplete")); + } + } + + + @Test + public void testFinalBoundaryOnly() + throws Exception + { + String delimiter = "\r\n"; + final String boundary = "MockMultiPartTestBoundary"; + + + // Malformed multipart request body containing only an arbitrary string of text, followed by the final boundary marker, delimited by empty lines. + String str = + delimiter + + "Hello world" + + delimiter + // Two delimiter markers, which make an empty line. + delimiter + + "--" + boundary + "--" + delimiter; + + MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50); + MultiPartInputStreamParser mpis = new MultiPartInputStreamParser(new ByteArrayInputStream(str.getBytes()), + "multipart/form-data, boundary="+boundary, + config, + _tmpDir); + mpis.setDeleteOnExit(true); + Collection parts = mpis.getParts(); + assertTrue(mpis.getParts().isEmpty()); + } + + + + @Test + public void testEmpty() + throws Exception + { + String delimiter = "\r\n"; + final String boundary = "MockMultiPartTestBoundary"; + + String str = + delimiter + + "--" + boundary + "--" + delimiter; + + MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50); + MultiPartInputStreamParser mpis = new MultiPartInputStreamParser(new ByteArrayInputStream(str.getBytes()), + "multipart/form-data, boundary="+boundary, + config, + _tmpDir); + mpis.setDeleteOnExit(true); + assertTrue(mpis.getParts().isEmpty()); + } + + @Test + public void testNoBoundaryRequest() + throws Exception + { + String str = "--\r\n"+ + "Content-Disposition: form-data; name=\"fileName\"\r\n"+ + "Content-Type: text/plain; charset=US-ASCII\r\n"+ + "Content-Transfer-Encoding: 8bit\r\n"+ + "\r\n"+ + "abc\r\n"+ + "--\r\n"+ + "Content-Disposition: form-data; name=\"desc\"\r\n"+ + "Content-Type: text/plain; charset=US-ASCII\r\n"+ + "Content-Transfer-Encoding: 8bit\r\n"+ + "\r\n"+ + "123\r\n"+ + "--\r\n"+ + "Content-Disposition: form-data; name=\"title\"\r\n"+ + "Content-Type: text/plain; charset=US-ASCII\r\n"+ + "Content-Transfer-Encoding: 8bit\r\n"+ + "\r\n"+ + "ttt\r\n"+ + "--\r\n"+ + "Content-Disposition: form-data; name=\"datafile5239138112980980385.txt\"; filename=\"datafile5239138112980980385.txt\"\r\n"+ + "Content-Type: application/octet-stream; charset=ISO-8859-1\r\n"+ + "Content-Transfer-Encoding: binary\r\n"+ + "\r\n"+ + "000\r\n"+ + "----\r\n"; + + MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50); + MultiPartInputStreamParser mpis = new MultiPartInputStreamParser(new ByteArrayInputStream(str.getBytes()), + "multipart/form-data", + config, + _tmpDir); + mpis.setDeleteOnExit(true); + Collection parts = mpis.getParts(); + assertThat(parts.size(), is(4)); + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + Part fileName = mpis.getPart("fileName"); + assertThat(fileName, notNullValue()); + assertThat(fileName.getSize(), is(3L)); + IO.copy(fileName.getInputStream(), baos); + assertThat(baos.toString("US-ASCII"), is("abc")); + + baos = new ByteArrayOutputStream(); + Part desc = mpis.getPart("desc"); + assertThat(desc, notNullValue()); + assertThat(desc.getSize(), is(3L)); + IO.copy(desc.getInputStream(), baos); + assertThat(baos.toString("US-ASCII"), is("123")); + + baos = new ByteArrayOutputStream(); + Part title = mpis.getPart("title"); + assertThat(title, notNullValue()); + assertThat(title.getSize(), is(3L)); + IO.copy(title.getInputStream(), baos); + assertThat(baos.toString("US-ASCII"), is("ttt")); + } + + @Test + public void testNonMultiPartRequest() + throws Exception + { + MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50); + MultiPartInputStreamParser mpis = new MultiPartInputStreamParser(new ByteArrayInputStream(_multi.getBytes()), + "Content-type: text/plain", + config, + _tmpDir); + mpis.setDeleteOnExit(true); + assertTrue(mpis.getParts().isEmpty()); + } + + @Test + public void testNoBody() + throws Exception + { + String body = ""; + + MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50); + MultiPartInputStreamParser mpis = new MultiPartInputStreamParser(new ByteArrayInputStream(body.getBytes()), + _contentType, + config, + _tmpDir); + mpis.setDeleteOnExit(true); + try + { + mpis.getParts(); + fail ("Multipart missing body"); + } + catch (IOException e) + { + assertTrue(e.getMessage().startsWith("Missing content")); + } + } + + + @Test + public void testBodyAlreadyConsumed() + throws Exception + { + ServletInputStream is = new ServletInputStream() { + + @Override + public boolean isFinished() + { + return true; + } + + @Override + public boolean isReady() + { + return false; + } + + @Override + public void setReadListener(ReadListener readListener) + { + } + + @Override + public int read() throws IOException + { + return 0; + } + + }; + + MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50); + MultiPartInputStreamParser mpis = new MultiPartInputStreamParser(is, + _contentType, + config, + _tmpDir); + mpis.setDeleteOnExit(true); + Collection parts = mpis.getParts(); + assertEquals(0, parts.size()); + } + + + + @Test + public void testWhitespaceBodyWithCRLF() + throws Exception + { + String whitespace = " \n\n\n\r\n\r\n\r\n\r\n"; + + + MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50); + MultiPartInputStreamParser mpis = new MultiPartInputStreamParser(new ByteArrayInputStream(whitespace.getBytes()), + _contentType, + config, + _tmpDir); + mpis.setDeleteOnExit(true); + try + { + mpis.getParts(); + fail ("Multipart missing body"); + } + catch (IOException e) + { + assertTrue(e.getMessage().startsWith("Missing initial")); + } + } + + @Test + public void testWhitespaceBody() + throws Exception + { + String whitespace = " "; + + MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50); + MultiPartInputStreamParser mpis = new MultiPartInputStreamParser(new ByteArrayInputStream(whitespace.getBytes()), + _contentType, + config, + _tmpDir); + mpis.setDeleteOnExit(true); + try + { + mpis.getParts(); + fail ("Multipart missing body"); + } + catch (IOException e) + { + assertTrue(e.getMessage().startsWith("Missing initial")); + } + } + + @Test + public void testLeadingWhitespaceBodyWithCRLF() + throws Exception + { + String body = " \n\n\n\r\n\r\n\r\n\r\n"+ + "--AaB03x\r\n"+ + "content-disposition: form-data; name=\"field1\"\r\n"+ + "\r\n"+ + "Joe Blow\r\n"+ + "--AaB03x\r\n"+ + "content-disposition: form-data; name=\"stuff\"; filename=\"" + "foo.txt" + "\"\r\n"+ + "Content-Type: text/plain\r\n"+ + "\r\n"+"aaaa"+ + "bbbbb"+"\r\n" + + "--AaB03x--\r\n"; + + + MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50); + MultiPartInputStreamParser mpis = new MultiPartInputStreamParser(new ByteArrayInputStream(body.getBytes()), + _contentType, + config, + _tmpDir); + mpis.setDeleteOnExit(true); + + Collection parts = mpis.getParts(); + assertThat(parts, notNullValue()); + assertThat(parts.size(), is(2)); + Part field1 = mpis.getPart("field1"); + assertThat(field1, notNullValue()); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + IO.copy(field1.getInputStream(), baos); + assertThat(baos.toString("US-ASCII"), is("Joe Blow")); + + Part stuff = mpis.getPart("stuff"); + assertThat(stuff, notNullValue()); + baos = new ByteArrayOutputStream(); + IO.copy(stuff.getInputStream(), baos); + assertTrue(baos.toString("US-ASCII").contains("aaaa")); + } + + + + @Test + public void testLeadingWhitespaceBodyWithoutCRLF() + throws Exception + { + String body = " "+ + "--AaB03x\r\n"+ + "content-disposition: form-data; name=\"field1\"\r\n"+ + "\r\n"+ + "Joe Blow\r\n"+ + "--AaB03x\r\n"+ + "content-disposition: form-data; name=\"stuff\"; filename=\"" + "foo.txt" + "\"\r\n"+ + "Content-Type: text/plain\r\n"+ + "\r\n"+"aaaa"+ + "bbbbb"+"\r\n" + + "--AaB03x--\r\n"; + + MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50); + MultiPartInputStreamParser mpis = new MultiPartInputStreamParser(new ByteArrayInputStream(body.getBytes()), + _contentType, + config, + _tmpDir); + mpis.setDeleteOnExit(true); + + Collection parts = mpis.getParts(); + assertThat(parts, notNullValue()); + assertThat(parts.size(), is(2)); + Part field1 = mpis.getPart("field1"); + assertThat(field1, notNullValue()); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + IO.copy(field1.getInputStream(), baos); + assertThat(baos.toString("US-ASCII"), is("Joe Blow")); + + Part stuff = mpis.getPart("stuff"); + assertThat(stuff, notNullValue()); + baos = new ByteArrayOutputStream(); + IO.copy(stuff.getInputStream(), baos); + assertTrue(baos.toString("US-ASCII").contains("bbbbb")); + } + + + + + + + @Test + public void testNoLimits() + throws Exception + { + MultipartConfigElement config = new MultipartConfigElement(_dirname); + MultiPartInputStreamParser mpis = new MultiPartInputStreamParser(new ByteArrayInputStream(_multi.getBytes()), + _contentType, + config, + _tmpDir); + mpis.setDeleteOnExit(true); + Collection parts = mpis.getParts(); + assertFalse(parts.isEmpty()); + } + + @Test + public void testRequestTooBig () + throws Exception + { + MultipartConfigElement config = new MultipartConfigElement(_dirname, 60, 100, 50); + MultiPartInputStreamParser mpis = new MultiPartInputStreamParser(new ByteArrayInputStream(_multi.getBytes()), + _contentType, + config, + _tmpDir); + mpis.setDeleteOnExit(true); + Collection parts = null; + try + { + parts = mpis.getParts(); + fail("Request should have exceeded maxRequestSize"); + } + catch (IllegalStateException e) + { + assertTrue(e.getMessage().startsWith("Request exceeds maxRequestSize")); + } + } + + + @Test + public void testRequestTooBigThrowsErrorOnGetParts () + throws Exception + { + MultipartConfigElement config = new MultipartConfigElement(_dirname, 60, 100, 50); + MultiPartInputStreamParser mpis = new MultiPartInputStreamParser(new ByteArrayInputStream(_multi.getBytes()), + _contentType, + config, + _tmpDir); + mpis.setDeleteOnExit(true); + Collection parts = null; + + //cause parsing + try + { + parts = mpis.getParts(); + fail("Request should have exceeded maxRequestSize"); + } + catch (IllegalStateException e) + { + assertTrue(e.getMessage().startsWith("Request exceeds maxRequestSize")); + } + + //try again + try + { + parts = mpis.getParts(); + fail("Request should have exceeded maxRequestSize"); + } + catch (IllegalStateException e) + { + assertTrue(e.getMessage().startsWith("Request exceeds maxRequestSize")); + } + } + + @Test + public void testFileTooBig() + throws Exception + { + MultipartConfigElement config = new MultipartConfigElement(_dirname, 40, 1024, 30); + MultiPartInputStreamParser mpis = new MultiPartInputStreamParser(new ByteArrayInputStream(_multi.getBytes()), + _contentType, + config, + _tmpDir); + mpis.setDeleteOnExit(true); + Collection parts = null; + try + { + parts = mpis.getParts(); + fail("stuff.txt should have been larger than maxFileSize"); + } + catch (IllegalStateException e) + { + assertTrue(e.getMessage().startsWith("Multipart Mime part")); + } + } + + @Test + public void testFileTooBigThrowsErrorOnGetParts() + throws Exception + { + MultipartConfigElement config = new MultipartConfigElement(_dirname, 40, 1024, 30); + MultiPartInputStreamParser mpis = new MultiPartInputStreamParser(new ByteArrayInputStream(_multi.getBytes()), + _contentType, + config, + _tmpDir); + mpis.setDeleteOnExit(true); + Collection parts = null; + try + { + parts = mpis.getParts(); //caused parsing + fail("stuff.txt should have been larger than maxFileSize"); + } + catch (IllegalStateException e) + { + assertTrue(e.getMessage().startsWith("Multipart Mime part")); + } + + //test again after the parsing + try + { + parts = mpis.getParts(); //caused parsing + fail("stuff.txt should have been larger than maxFileSize"); + } + catch (IllegalStateException e) + { + assertTrue(e.getMessage().startsWith("Multipart Mime part")); + } + } + + + + @Test + public void testPartFileNotDeleted () throws Exception + { + MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50); + MultiPartInputStreamParser mpis = new MultiPartInputStreamParser(new ByteArrayInputStream(createMultipartRequestString("tptfd").getBytes()), + _contentType, + config, + _tmpDir); + mpis.setDeleteOnExit(true); + Collection parts = mpis.getParts(); + + MultiPart part = (MultiPart)mpis.getPart("stuff"); + File stuff = ((MultiPartInputStreamParser.MultiPart)part).getFile(); + assertThat(stuff,notNullValue()); // longer than 100 bytes, should already be a tmp file + part.write("tptfd.txt"); + File tptfd = new File (_dirname+File.separator+"tptfd.txt"); + assertThat(tptfd.exists(), is(true)); + assertThat(stuff.exists(), is(false)); //got renamed + part.cleanUp(); + assertThat(tptfd.exists(), is(true)); //explicitly written file did not get removed after cleanup + tptfd.deleteOnExit(); //clean up test + } + + @Test + public void testPartTmpFileDeletion () throws Exception + { + MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50); + MultiPartInputStreamParser mpis = new MultiPartInputStreamParser(new ByteArrayInputStream(createMultipartRequestString("tptfd").getBytes()), + _contentType, + config, + _tmpDir); + mpis.setDeleteOnExit(true); + Collection parts = mpis.getParts(); + + MultiPart part = (MultiPart)mpis.getPart("stuff"); + File stuff = ((MultiPartInputStreamParser.MultiPart)part).getFile(); + assertThat(stuff,notNullValue()); // longer than 100 bytes, should already be a tmp file + assertThat (stuff.exists(), is(true)); + part.cleanUp(); + assertThat(stuff.exists(), is(false)); //tmp file was removed after cleanup + } + + @Test + public void testLFOnlyRequest() + throws Exception + { + String str = "--AaB03x\n"+ + "content-disposition: form-data; name=\"field1\"\n"+ + "\n"+ + "Joe Blow\n"+ + "--AaB03x\n"+ + "content-disposition: form-data; name=\"field2\"\n"+ + "\n"+ + "Other\n"+ + "--AaB03x--\n"; + + MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50); + MultiPartInputStreamParser mpis = new MultiPartInputStreamParser(new ByteArrayInputStream(str.getBytes()), + _contentType, + config, + _tmpDir); + mpis.setDeleteOnExit(true); + Collection parts = mpis.getParts(); + assertThat(parts.size(), is(2)); + Part p1 = mpis.getPart("field1"); + assertThat(p1, notNullValue()); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + IO.copy(p1.getInputStream(), baos); + assertThat(baos.toString("UTF-8"), is("Joe Blow")); + + Part p2 = mpis.getPart("field2"); + assertThat(p2, notNullValue()); + baos = new ByteArrayOutputStream(); + IO.copy(p2.getInputStream(), baos); + assertThat(baos.toString("UTF-8"), is("Other")); + } + + @Test + public void testCROnlyRequest() + throws Exception + { + String str = "--AaB03x\r"+ + "content-disposition: form-data; name=\"field1\"\r"+ + "\r"+ + "Joe Blow\r"+ + "--AaB03x\r"+ + "content-disposition: form-data; name=\"field2\"\r"+ + "\r"+ + "Other\r"+ + "--AaB03x--\r"; + + MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50); + MultiPartInputStreamParser mpis = new MultiPartInputStreamParser(new ByteArrayInputStream(str.getBytes()), + _contentType, + config, + _tmpDir); + mpis.setDeleteOnExit(true); + Collection parts = mpis.getParts(); + assertThat(parts.size(), is(2)); + + assertThat(parts.size(), is(2)); + Part p1 = mpis.getPart("field1"); + assertThat(p1, notNullValue()); + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + IO.copy(p1.getInputStream(), baos); + assertThat(baos.toString("UTF-8"), is("Joe Blow")); + + Part p2 = mpis.getPart("field2"); + assertThat(p2, notNullValue()); + baos = new ByteArrayOutputStream(); + IO.copy(p2.getInputStream(), baos); + assertThat(baos.toString("UTF-8"), is("Other")); + } + + @Test + public void testCRandLFMixRequest() + throws Exception + { + String str = "--AaB03x\r"+ + "content-disposition: form-data; name=\"field1\"\r"+ + "\r"+ + "\nJoe Blow\n"+ + "\r"+ + "--AaB03x\r"+ + "content-disposition: form-data; name=\"field2\"\r"+ + "\r"+ + "Other\r"+ + "--AaB03x--\r"; + + MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50); + MultiPartInputStreamParser mpis = new MultiPartInputStreamParser(new ByteArrayInputStream(str.getBytes()), + _contentType, + config, + _tmpDir); + mpis.setDeleteOnExit(true); + Collection parts = mpis.getParts(); + assertThat(parts.size(), is(2)); + + Part p1 = mpis.getPart("field1"); + assertThat(p1, notNullValue()); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + IO.copy(p1.getInputStream(), baos); + assertThat(baos.toString("UTF-8"), is("\nJoe Blow\n")); + + Part p2 = mpis.getPart("field2"); + assertThat(p2, notNullValue()); + baos = new ByteArrayOutputStream(); + IO.copy(p2.getInputStream(), baos); + assertThat(baos.toString("UTF-8"), is("Other")); + } + + @Test + public void testBufferOverflowNoCRLF () throws Exception + { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + baos.write("--AaB03x".getBytes()); + for (int i=0; i< 8500; i++) //create content that will overrun default buffer size of BufferedInputStream + { + baos.write('a'); + } + + MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50); + MultiPartInputStreamParser mpis = new MultiPartInputStreamParser(new ByteArrayInputStream(baos.toByteArray()), + _contentType, + config, + _tmpDir); + mpis.setDeleteOnExit(true); + try + { + mpis.getParts(); + fail ("Multipart buffer overrun"); + } + catch (IOException e) + { + assertTrue(e.getMessage().startsWith("Buffer size exceeded")); + } + + } + + @Test + public void testCharsetEncoding () throws Exception + { + String contentType = "multipart/form-data; boundary=TheBoundary; charset=ISO-8859-1"; + String str = "--TheBoundary\r"+ + "content-disposition: form-data; name=\"field1\"\r"+ + "\r"+ + "\nJoe Blow\n"+ + "\r"+ + "--TheBoundary--\r"; + + MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50); + MultiPartInputStreamParser mpis = new MultiPartInputStreamParser(new ByteArrayInputStream(str.getBytes()), + contentType, + config, + _tmpDir); + mpis.setDeleteOnExit(true); + Collection parts = mpis.getParts(); + assertThat(parts.size(), is(1)); + } + + + @Test + public void testBadlyEncodedFilename() throws Exception + { + + String contents = "--AaB03x\r\n"+ + "content-disposition: form-data; name=\"stuff\"; filename=\"" +"Taken on Aug 22 \\ 2012.jpg" + "\"\r\n"+ + "Content-Type: text/plain\r\n"+ + "\r\n"+"stuff"+ + "aaa"+"\r\n" + + "--AaB03x--\r\n"; + + MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50); + MultiPartInputStreamParser mpis = new MultiPartInputStreamParser(new ByteArrayInputStream(contents.getBytes()), + _contentType, + config, + _tmpDir); + mpis.setDeleteOnExit(true); + Collection parts = mpis.getParts(); + assertThat(parts.size(), is(1)); + assertThat(((MultiPartInputStreamParser.MultiPart)parts.iterator().next()).getSubmittedFileName(), is("Taken on Aug 22 \\ 2012.jpg")); + } + + @Test + public void testBadlyEncodedMSFilename() throws Exception + { + + String contents = "--AaB03x\r\n"+ + "content-disposition: form-data; name=\"stuff\"; filename=\"" +"c:\\this\\really\\is\\some\\path\\to\\a\\file.txt" + "\"\r\n"+ + "Content-Type: text/plain\r\n"+ + "\r\n"+"stuff"+ + "aaa"+"\r\n" + + "--AaB03x--\r\n"; + + MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50); + MultiPartInputStreamParser mpis = new MultiPartInputStreamParser(new ByteArrayInputStream(contents.getBytes()), + _contentType, + config, + _tmpDir); + mpis.setDeleteOnExit(true); + Collection parts = mpis.getParts(); + assertThat(parts.size(), is(1)); + assertThat(((MultiPartInputStreamParser.MultiPart)parts.iterator().next()).getSubmittedFileName(), is("c:\\this\\really\\is\\some\\path\\to\\a\\file.txt")); + } + + @Test + public void testCorrectlyEncodedMSFilename() throws Exception + { + String contents = "--AaB03x\r\n"+ + "content-disposition: form-data; name=\"stuff\"; filename=\"" +"c:\\\\this\\\\really\\\\is\\\\some\\\\path\\\\to\\\\a\\\\file.txt" + "\"\r\n"+ + "Content-Type: text/plain\r\n"+ + "\r\n"+"stuff"+ + "aaa"+"\r\n" + + "--AaB03x--\r\n"; + + MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50); + MultiPartInputStreamParser mpis = new MultiPartInputStreamParser(new ByteArrayInputStream(contents.getBytes()), + _contentType, + config, + _tmpDir); + mpis.setDeleteOnExit(true); + Collection parts = mpis.getParts(); + assertThat(parts.size(), is(1)); + assertThat(((MultiPartInputStreamParser.MultiPart)parts.iterator().next()).getSubmittedFileName(), is("c:\\this\\really\\is\\some\\path\\to\\a\\file.txt")); + } + + public void testMulti () + throws Exception + { + testMulti(FILENAME); + } + + @Test + public void testMultiWithSpaceInFilename() throws Exception + { + testMulti("stuff with spaces.txt"); + } + + + @Test + public void testWriteFilesIfContentDispositionFilename () + throws Exception + { + String s = "--AaB03x\r\n"+ + "content-disposition: form-data; name=\"field1\"; filename=\"frooble.txt\"\r\n"+ + "\r\n"+ + "Joe Blow\r\n"+ + "--AaB03x\r\n"+ + "content-disposition: form-data; name=\"stuff\"\r\n"+ + "Content-Type: text/plain\r\n"+ + "\r\n"+"sss"+ + "aaa"+"\r\n" + + "--AaB03x--\r\n"; + //all default values for multipartconfig, ie file size threshold 0 + MultipartConfigElement config = new MultipartConfigElement(_dirname); + MultiPartInputStreamParser mpis = new MultiPartInputStreamParser(new ByteArrayInputStream(s.getBytes()), + _contentType, + config, + _tmpDir); + mpis.setDeleteOnExit(true); + mpis.setWriteFilesWithFilenames(true); + Collection parts = mpis.getParts(); + assertThat(parts.size(), is(2)); + Part field1 = mpis.getPart("field1"); //has a filename, should be written to a file + File f = ((MultiPartInputStreamParser.MultiPart)field1).getFile(); + assertThat(f,notNullValue()); // longer than 100 bytes, should already be a tmp file + + Part stuff = mpis.getPart("stuff"); + f = ((MultiPartInputStreamParser.MultiPart)stuff).getFile(); //should only be in memory, no filename + assertThat(f, nullValue()); + } + + + private void testMulti(String filename) throws IOException, ServletException, InterruptedException + { + MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50); + MultiPartInputStreamParser mpis = new MultiPartInputStreamParser(new ByteArrayInputStream(createMultipartRequestString(filename).getBytes()), + _contentType, + config, + _tmpDir); + mpis.setDeleteOnExit(true); + Collection parts = mpis.getParts(); + assertThat(parts.size(), is(2)); + Part field1 = mpis.getPart("field1"); //field 1 too small to go into tmp file, should be in internal buffer + assertThat(field1,notNullValue()); + assertThat(field1.getName(),is("field1")); + InputStream is = field1.getInputStream(); + ByteArrayOutputStream os = new ByteArrayOutputStream(); + IO.copy(is, os); + assertEquals("Joe Blow", new String(os.toByteArray())); + assertEquals(8, field1.getSize()); + + assertNotNull(((MultiPartInputStreamParser.MultiPart)field1).getBytes());//in internal buffer + field1.write("field1.txt"); + assertNull(((MultiPartInputStreamParser.MultiPart)field1).getBytes());//no longer in internal buffer + File f = new File (_dirname+File.separator+"field1.txt"); + assertTrue(f.exists()); + field1.write("another_field1.txt"); //write after having already written + File f2 = new File(_dirname+File.separator+"another_field1.txt"); + assertTrue(f2.exists()); + assertFalse(f.exists()); //should have been renamed + field1.delete(); //file should be deleted + assertFalse(f.exists()); //original file was renamed + assertFalse(f2.exists()); //2nd written file was explicitly deleted + + MultiPart stuff = (MultiPart)mpis.getPart("stuff"); + assertThat(stuff.getSubmittedFileName(), is(filename)); + assertThat(stuff.getContentType(),is("text/plain")); + assertThat(stuff.getHeader("Content-Type"),is("text/plain")); + assertThat(stuff.getHeaders("content-type").size(),is(1)); + assertThat(stuff.getHeader("content-disposition"),is("form-data; name=\"stuff\"; filename=\"" + filename + "\"")); + assertThat(stuff.getHeaderNames().size(),is(2)); + assertThat(stuff.getSize(),is(51L)); + + File tmpfile = ((MultiPartInputStreamParser.MultiPart)stuff).getFile(); + assertThat(tmpfile,notNullValue()); // longer than 100 bytes, should already be a tmp file + assertThat(((MultiPartInputStreamParser.MultiPart)stuff).getBytes(),nullValue()); //not in an internal buffer + assertThat(tmpfile.exists(),is(true)); + assertThat(tmpfile.getName(),is(not("stuff with space.txt"))); + stuff.write(filename); + f = new File(_dirname+File.separator+filename); + assertThat(f.exists(),is(true)); + assertThat(tmpfile.exists(), is(false)); + try + { + stuff.getInputStream(); + } + catch (Exception e) + { + fail("Part.getInputStream() after file rename operation"); + } + f.deleteOnExit(); //clean up after test + } + + @Test + public void testMultiSameNames () + throws Exception + { + String sameNames = "--AaB03x\r\n"+ + "content-disposition: form-data; name=\"stuff\"; filename=\"stuff1.txt\"\r\n"+ + "Content-Type: text/plain\r\n"+ + "\r\n"+ + "00000\r\n"+ + "--AaB03x\r\n"+ + "content-disposition: form-data; name=\"stuff\"; filename=\"stuff2.txt\"\r\n"+ + "Content-Type: text/plain\r\n"+ + "\r\n"+ + "110000000000000000000000000000000000000000000000000\r\n"+ + "--AaB03x--\r\n"; + + MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50); + MultiPartInputStreamParser mpis = new MultiPartInputStreamParser(new ByteArrayInputStream(sameNames.getBytes()), + _contentType, + config, + _tmpDir); + mpis.setDeleteOnExit(true); + Collection parts = mpis.getParts(); + assertEquals(2, parts.size()); + for (Part p:parts) + assertEquals("stuff", p.getName()); + + //if they all have the name name, then only retrieve the first one + Part p = mpis.getPart("stuff"); + assertNotNull(p); + assertEquals(5, p.getSize()); + } + + @Test + public void testBase64EncodedContent () throws Exception + { + String contentWithEncodedPart = + "--AaB03x\r\n"+ + "Content-disposition: form-data; name=\"other\"\r\n"+ + "Content-Type: text/plain\r\n"+ + "\r\n"+ + "other" + "\r\n"+ + "--AaB03x\r\n"+ + "Content-disposition: form-data; name=\"stuff\"; filename=\"stuff.txt\"\r\n"+ + "Content-Transfer-Encoding: base64\r\n"+ + "Content-Type: application/octet-stream\r\n"+ + "\r\n"+ + B64Code.encode("hello jetty") + "\r\n"+ + "--AaB03x\r\n"+ + "Content-disposition: form-data; name=\"final\"\r\n"+ + "Content-Type: text/plain\r\n"+ + "\r\n"+ + "the end" + "\r\n"+ + "--AaB03x--\r\n"; + + MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50); + MultiPartInputStreamParser mpis = new MultiPartInputStreamParser(new ByteArrayInputStream(contentWithEncodedPart.getBytes()), + _contentType, + config, + _tmpDir); + mpis.setDeleteOnExit(true); + Collection parts = mpis.getParts(); + assertEquals(3, parts.size()); + + Part p1 = mpis.getPart("other"); + assertNotNull(p1); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + IO.copy(p1.getInputStream(), baos); + assertEquals("other", baos.toString("US-ASCII")); + + Part p2 = mpis.getPart("stuff"); + assertNotNull(p2); + baos = new ByteArrayOutputStream(); + IO.copy(p2.getInputStream(), baos); + assertEquals("hello jetty", baos.toString("US-ASCII")); + + Part p3 = mpis.getPart("final"); + assertNotNull(p3); + baos = new ByteArrayOutputStream(); + IO.copy(p3.getInputStream(), baos); + assertEquals("the end", baos.toString("US-ASCII")); + } + + @Test + public void testQuotedPrintableEncoding () throws Exception + { + String contentWithEncodedPart = + "--AaB03x\r\n"+ + "Content-disposition: form-data; name=\"other\"\r\n"+ + "Content-Type: text/plain\r\n"+ + "\r\n"+ + "other" + "\r\n"+ + "--AaB03x\r\n"+ + "Content-disposition: form-data; name=\"stuff\"; filename=\"stuff.txt\"\r\n"+ + "Content-Transfer-Encoding: quoted-printable\r\n"+ + "Content-Type: text/plain\r\n"+ + "\r\n"+ + "truth=3Dbeauty" + "\r\n"+ + "--AaB03x--\r\n"; + MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50); + MultiPartInputStreamParser mpis = new MultiPartInputStreamParser(new ByteArrayInputStream(contentWithEncodedPart.getBytes()), + _contentType, + config, + _tmpDir); + mpis.setDeleteOnExit(true); + Collection parts = mpis.getParts(); + assertEquals(2, parts.size()); + + Part p1 = mpis.getPart("other"); + assertNotNull(p1); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + IO.copy(p1.getInputStream(), baos); + assertEquals("other", baos.toString("US-ASCII")); + + Part p2 = mpis.getPart("stuff"); + assertNotNull(p2); + baos = new ByteArrayOutputStream(); + IO.copy(p2.getInputStream(), baos); + assertEquals("truth=beauty", baos.toString("US-ASCII")); + } + + + + + + private String createMultipartRequestString(String filename) + { + int length = filename.length(); + String name = filename; + if (length > 10) + name = filename.substring(0,10); + StringBuffer filler = new StringBuffer(); + int i = name.length(); + while (i < 51) + { + filler.append("0"); + i++; + } + + return "--AaB03x\r\n"+ + "content-disposition: form-data; name=\"field1\"; filename=\"frooble.txt\"\r\n"+ + "\r\n"+ + "Joe Blow\r\n"+ + "--AaB03x\r\n"+ + "content-disposition: form-data; name=\"stuff\"; filename=\"" + filename + "\"\r\n"+ + "Content-Type: text/plain\r\n"+ + "\r\n"+name+ + filler.toString()+"\r\n" + + "--AaB03x--\r\n"; + } +} From df83cca0100b9b2a7935cbc100d6d18336ea615e Mon Sep 17 00:00:00 2001 From: Lachlan Roberts Date: Sun, 18 Mar 2018 21:53:54 +1100 Subject: [PATCH 21/50] Rewrote the parse method to use the MultiPartParser, some error handling not implemented so only passing half of the tests. Signed-off-by: Lachlan Roberts --- .../http/MultiPartInputStreamParser.java | 358 +++++++----------- .../eclipse/jetty/http/MultiPartParser.java | 8 +- .../jetty/http/MultiPartParserTest.java | 52 ++- 3 files changed, 176 insertions(+), 242 deletions(-) diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartInputStreamParser.java b/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartInputStreamParser.java index 01703a8785f..bfa01590f23 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartInputStreamParser.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartInputStreamParser.java @@ -29,6 +29,7 @@ import java.io.FilterInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; @@ -44,7 +45,9 @@ import javax.servlet.MultipartConfigElement; import javax.servlet.ServletInputStream; import javax.servlet.http.Part; +import org.eclipse.jetty.http.HttpGenerator.State; import org.eclipse.jetty.util.B64Code; +import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.ByteArrayOutputStream2; import org.eclipse.jetty.util.LazyList; import org.eclipse.jetty.util.MultiException; @@ -208,7 +211,7 @@ public class MultiPartInputStreamParser */ @Override public String getHeader(String name) - { + { if (name == null) return null; return _headers.getValue(name.toLowerCase(Locale.ENGLISH), 0); @@ -514,17 +517,14 @@ public class MultiPartInputStreamParser //initialize - long total = 0; //keep running total of size of bytes read from input and throw an exception if exceeds MultipartConfigElement._maxRequestSize _parts = new MultiMap<>(); //if its not a multipart request, don't parse it if (_contentType == null || !_contentType.startsWith("multipart/form-data")) return; - try - { + //sort out the location to which to write the files - if (_config.getLocation() == null) _tmpDir = _contextTmpDir; else if ("".equals(_config.getLocation())) @@ -550,94 +550,95 @@ public class MultiPartInputStreamParser contentTypeBoundary = QuotedStringTokenizer.unquote(value(_contentType.substring(bstart,bend)).trim()); } - String boundary="--"+contentTypeBoundary; - String lastBoundary=boundary+"--"; - byte[] byteBoundary=lastBoundary.getBytes(StandardCharsets.ISO_8859_1); - - // Get first boundary - String line = null; - try + + // ============ MY CODE ============= // + Handler handler = new Handler(); + MultiPartParser parser = new MultiPartParser(handler,contentTypeBoundary); + + + // Create a buffer to store data from stream // + final int _bufferSize = 16*1024; // <---- need to rename and move somewhere else + byte[] data = new byte[_bufferSize]; + int len=0; + + + while(true) { - line=((ReadLineInputStream)_in).readLine(); - } - catch (IOException e) - { - LOG.warn("Badly formatted multipart request"); - throw e; - } - - if (line == null) - throw new IOException("Missing content for multipart request"); - - boolean badFormatLogged = false; - line=line.trim(); - while (line != null && !line.equals(boundary) && !line.equals(lastBoundary)) - { - if (!badFormatLogged) + try { - LOG.warn("Badly formatted multipart request"); - badFormatLogged = true; + len = _in.read(data); + } + catch (IOException e) + { + _err = e; + return; + } + + if(len > 0) + { + ByteBuffer buffer = BufferUtil.toBuffer(data); + buffer.limit(len); + parser.parse(buffer, false); + } + else if (len == -1) + { + parser.parse(BufferUtil.EMPTY_BUFFER, true); + break; } - line=((ReadLineInputStream)_in).readLine(); - line=(line==null?line:line.trim()); } - - if (line == null || line.length() == 0) - throw new IOException("Missing initial multi part boundary"); - - // Empty multipart. - if (line.equals(lastBoundary)) + + //check for exceptions + if(_err != null) + { return; - - // Read each part - boolean lastPart=false; - - outer:while(!lastPart) + } + + //check we read to the end of the message + if(parser.getState() != MultiPartParser.State.END) { - String contentDisposition=null; - String contentType=null; - String contentTransferEncoding=null; + _err = new IllegalStateException("Parser Not in End State: "+parser.getState()); + } + + } + + class Handler implements MultiPartParser.Handler + { + /* keep running total of size of bytes read from input + * and throw an exception if exceeds MultipartConfigElement._maxRequestSize */ + private long total = 0; + + private MultiPart _part=null; + private String contentDisposition=null; + private String contentType=null; + private MultiMap headers = new MultiMap<>(); + + @Override + public boolean messageComplete() { return true; } + + @Override + public void parsedField(String key, String value) + { + // Add to headers and mark if one of these fields. // + headers.put(key.toLowerCase(Locale.ENGLISH), value); + if (key.equalsIgnoreCase("content-disposition")) + contentDisposition=value; + else if (key.equalsIgnoreCase("content-type")) + contentType = value; - MultiMap headers = new MultiMap<>(); - while(true) - { - line=((ReadLineInputStream)_in).readLine(); - - //No more input - if(line==null) - break outer; - - //end of headers: - if("".equals(line)) - break; - - total += line.length(); - if (_config.getMaxRequestSize() > 0 && total > _config.getMaxRequestSize()) - throw new IllegalStateException ("Request exceeds maxRequestSize ("+_config.getMaxRequestSize()+")"); - - //get content-disposition and content-type - int c=line.indexOf(':',0); - if(c>0) - { - String key=line.substring(0,c).trim().toLowerCase(Locale.ENGLISH); - String value=line.substring(c+1,line.length()).trim(); - headers.put(key, value); - if (key.equalsIgnoreCase("content-disposition")) - contentDisposition=value; - if (key.equalsIgnoreCase("content-type")) - contentType = value; - if(key.equals("content-transfer-encoding")) - contentTransferEncoding=value; - } - } + } + @Override + public boolean headerComplete() { + + try { + // Extract content-disposition boolean form_data=false; if(contentDisposition==null) { throw new IOException("Missing content-disposition"); } - + QuotedStringTokenizer tok=new QuotedStringTokenizer(contentDisposition,";", false, true); String name=null; String filename=null; @@ -652,11 +653,11 @@ public class MultiPartInputStreamParser else if(tl.startsWith("filename=")) filename=filenameValue(t); } - + // Check disposition if(!form_data) { - continue; + return false; } //It is valid for reset and submit buttons to have an empty name. //If no name is supplied, the browser skips sending the info for that field. @@ -665,163 +666,68 @@ public class MultiPartInputStreamParser //have not yet seen a name field. if(name==null) { - continue; + return false; } - + //Have a new Part - MultiPart part = new MultiPart(name, filename); - part.setHeaders(headers); - part.setContentType(contentType); - _parts.add(name, part); - part.open(); - - InputStream partInput = null; - if ("base64".equalsIgnoreCase(contentTransferEncoding)) - { - partInput = new Base64InputStream((ReadLineInputStream)_in); - } - else if ("quoted-printable".equalsIgnoreCase(contentTransferEncoding)) - { - partInput = new FilterInputStream(_in) - { - @Override - public int read() throws IOException - { - int c = in.read(); - if (c >= 0 && c == '=') - { - int hi = in.read(); - int lo = in.read(); - if (hi < 0 || lo < 0) - { - throw new IOException("Unexpected end to quoted-printable byte"); - } - char[] chars = new char[] { (char)hi, (char)lo }; - c = Integer.parseInt(new String(chars),16); - } - return c; - } - }; - } - else - partInput = _in; - - + System.out.println("-------------------------"); + System.out.println("Creating New Part"); + System.out.println("Name: "+name); + System.out.println("Filename: "+filename); + System.out.println("Headers:\n"+headers); + System.out.println("ContentType:\n"+contentType); + System.out.println("-------------------------"); + + _part = new MultiPart(name, filename); + _part.setHeaders(headers); + _part.setContentType(contentType); + _parts.add(name, _part); + } + catch (Exception e) + { + _err = e; + return true; + } + + return false; + } + + @Override + public boolean content(ByteBuffer buffer, boolean last) + { + if (BufferUtil.hasContent(buffer)) + { try { - int state=-2; - int c; - boolean cr=false; - boolean lf=false; - - // loop for all lines - while(true) - { - int b=0; - while((c=(state!=-2)?state:partInput.read())!=-1) - { - total ++; - if (_config.getMaxRequestSize() > 0 && total > _config.getMaxRequestSize()) - throw new IllegalStateException("Request exceeds maxRequestSize ("+_config.getMaxRequestSize()+")"); - - state=-2; - - // look for CR and/or LF - if(c==13||c==10) - { - if(c==13) - { - partInput.mark(1); - int tmp=partInput.read(); - if (tmp!=10) - partInput.reset(); - else - state=tmp; - } - break; - } - - // Look for boundary - if(b>=0&&b0) - part.write(byteBoundary,0,b); - - b=-1; - part.write(c); - } - } - - // Check for incomplete boundary match, writing out the chars we matched along the way - if((b>0&&b0||c==-1) - { - - if(b==byteBoundary.length) - lastPart=true; - if(state==10) - state=-2; - break; - } - - // handle CR LF - if(cr) - part.write(13); - - if(lf) - part.write(10); - - cr=(c==13); - lf=(c==10||state==10); - if(state==10) - state=-2; - } + //write the content data to the part + _part.open(); + _part.write(buffer.array(),buffer.arrayOffset()+buffer.position(),buffer.remaining()); + _part.close(); } - finally + catch (IOException e) { - part.close(); + _err = e; + return true; } } - if (lastPart) - { - while(line!=null) - line=((ReadLineInputStream)_in).readLine(); - } - else - throw new IOException("Incomplete parts"); + + if (last) + reset(); + + return false; } - catch (Exception e) + + public void reset() { - _err = e; + _part = null; + contentDisposition = null; + contentType = null; + headers = new MultiMap<>(); } + } - + + public void setDeleteOnExit(boolean deleteOnExit) { _deleteOnExit = deleteOnExit; diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartParser.java b/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartParser.java index b813a52532b..847a807e6c6 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartParser.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartParser.java @@ -354,20 +354,20 @@ public class MultiPartParser } } - if(last) + if(last && BufferUtil.isEmpty(buffer)) { if(_state == State.EPILOGUE) { _state = State.END; return _handler.messageComplete(); } - else if(BufferUtil.isEmpty(buffer)) + else { _handler.earlyEOF(); return true; } - } + return handle; } @@ -649,7 +649,7 @@ public class MultiPartParser } else { - //print up to _partialBoundary of the search pattern + //output up to _partialBoundary of the search pattern ByteBuffer content = _patternBuffer.slice(); if (_state==State.FIRST_OCTETS) { diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParserTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParserTest.java index 965e86618a1..aaa6f08f5ac 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParserTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParserTest.java @@ -371,10 +371,6 @@ public class MultiPartParserTest assertThat(handler.fields,Matchers.contains("name: value", "<>")); assertThat(handler.content,Matchers.contains("Hello","<>")); - parser.parse(data,false); - assertThat(parser.getState(), is(State.EPILOGUE)); - assertThat(data.remaining(),is(0)); - parser.parse(data,true); assertThat(parser.getState(), is(State.END)); } @@ -412,17 +408,51 @@ public class MultiPartParserTest assertThat(handler.fields, Matchers.contains("name: value", "<>","powerLevel: 9001","<>")); assertThat(handler.content, Matchers.contains("Hello","<>","secondary\r\ncontent","<>")); - /* Test Progression to EPILOGUE State */ - parser.parse(data,false); - assertThat(parser.getState(), is(State.EPILOGUE)); - assertThat(data.remaining(),is(0)); - /* Test Progression to END State */ parser.parse(data,true); assertThat(parser.getState(), is(State.END)); assertThat(data.remaining(),is(0)); } + + + @Test + public void testEndState() { + TestHandler handler = new TestHandler() + { + @Override public boolean messageComplete(){ return true; } + + @Override + public boolean content(ByteBuffer buffer, boolean last) + { + super.content(buffer,last); + return false; + } + }; + MultiPartParser parser = new MultiPartParser(handler,"AaB03x"); + + ByteBuffer data = BufferUtil.toBuffer(" "+ + "--AaB03x\r\n"+ + "content-disposition: form-data; name=\"field1\"\r\n"+ + "\r\n"+ + "Joe Blow\r\n"+ + "--AaB03x\r\n"+ + "content-disposition: form-data; name=\"stuff\"; filename=\"" + "foo.txt" + "\"\r\n"+ + "Content-Type: text/plain\r\n"+ + "\r\n"+"aaaa"+ + "bbbbb"+"\r\n" + + "--AaB03x--\r\n"); + + + /* Test Progression to END State */ + parser.parse(data,true); + assertThat(parser.getState(), is(State.END)); + assertThat(data.remaining(),is(0)); + + } + + + @Test public void splitTest() { @@ -504,7 +534,7 @@ public class MultiPartParserTest int length = data.remaining(); - for(int i = 0; i>")); - System.out.println("iteration "+i); - System.out.println(handler.content); assertThat(handler.contentString(), is(new String("text default"+"<>" + "Content of a.txt.\n"+"<>" + "Content of a.html.\n"+"<>" From 93b8161afb6738e06c9872690dc0e97bc40e9f03 Mon Sep 17 00:00:00 2001 From: Lachlan Roberts Date: Tue, 20 Mar 2018 11:40:55 +1100 Subject: [PATCH 22/50] Reworked MultipartParser with additional option to accept CR as CRLF. Signed-off-by: Lachlan Roberts --- .../http/MultiPartInputStreamParser.java | 21 +++-- .../eclipse/jetty/http/MultiPartParser.java | 80 +++++++++++++++---- .../jetty/http/MultiPartInputStreamTest.java | 5 +- .../jetty/http/MultiPartParserTest.java | 19 ++--- 4 files changed, 86 insertions(+), 39 deletions(-) diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartInputStreamParser.java b/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartInputStreamParser.java index bfa01590f23..857909f6bd4 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartInputStreamParser.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartInputStreamParser.java @@ -497,6 +497,7 @@ public class MultiPartInputStreamParser { if (_err != null) { + _err.addSuppressed(new Throwable()); if (_err instanceof IOException) throw (IOException)_err; if (_err instanceof IllegalStateException) @@ -551,7 +552,6 @@ public class MultiPartInputStreamParser } - // ============ MY CODE ============= // Handler handler = new Handler(); MultiPartParser parser = new MultiPartParser(handler,contentTypeBoundary); @@ -596,7 +596,12 @@ public class MultiPartInputStreamParser //check we read to the end of the message if(parser.getState() != MultiPartParser.State.END) { - _err = new IllegalStateException("Parser Not in End State: "+parser.getState()); + _err = new IOException("Incomplete Multipart"); + } + + if(LOG.isDebugEnabled()) + { + LOG.debug("Parsing Complete {} err={}",parser,_err); } } @@ -668,16 +673,8 @@ public class MultiPartInputStreamParser { return false; } - - //Have a new Part - System.out.println("-------------------------"); - System.out.println("Creating New Part"); - System.out.println("Name: "+name); - System.out.println("Filename: "+filename); - System.out.println("Headers:\n"+headers); - System.out.println("ContentType:\n"+contentType); - System.out.println("-------------------------"); - + + //create the new part _part = new MultiPart(name, filename); _part.setHeaders(headers); _part.setContentType(contentType); diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartParser.java b/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartParser.java index 847a807e6c6..851054ea789 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartParser.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartParser.java @@ -152,6 +152,8 @@ public class MultiPartParser private final boolean DEBUG=LOG.isDebugEnabled(); private final Handler _handler; private final SearchPattern _delimiterSearch; + private final boolean _acceptCrAsLineTermination; + private String _fieldName; private String _fieldValue; @@ -159,6 +161,7 @@ public class MultiPartParser private FieldState _fieldState = FieldState.FIELD; private int _partialBoundary = 2; // No CRLF if no preamble private boolean _cr; + private byte _next; private ByteBuffer _patternBuffer; private final StringBuilder _string=new StringBuilder(); @@ -167,12 +170,25 @@ public class MultiPartParser /* ------------------------------------------------------------------------------- */ public MultiPartParser(Handler handler, String boundary) + { + this(handler,boundary,false); + } + + /* ------------------------------------------------------------------------------- */ + /** TODO complete + * + * @param handler + * @param boundary + * @param acceptCR + */ + public MultiPartParser(Handler handler, String boundary, boolean acceptCR) { _handler = handler; String delimiter = "\r\n--"+boundary; _patternBuffer = ByteBuffer.wrap(delimiter.getBytes(StandardCharsets.US_ASCII)); _delimiterSearch = SearchPattern.compile(_patternBuffer.array()); + _acceptCrAsLineTermination = acceptCR; } public void reset() @@ -254,9 +270,23 @@ public class MultiPartParser } /* ------------------------------------------------------------------------------- */ - private byte next(ByteBuffer buffer) + private boolean hasNextByte(ByteBuffer buffer) { - byte ch = buffer.get(); + return BufferUtil.hasContent(buffer) || _next!=0; + } + + /* ------------------------------------------------------------------------------- */ + private byte getNextByte(ByteBuffer buffer, boolean last) + { + + byte ch; + if (_next==0) + ch = buffer.get(); + else + { + ch = _next; + _next = 0; + } CharState s = __charState[0xff & ch]; switch(s) @@ -267,11 +297,18 @@ public class MultiPartParser case CR: if (_cr) - throw new BadMessageException("Bad EOL"); - + { + if (!_acceptCrAsLineTermination) + throw new BadMessageException("Bad EOL"); + // TODO log compliance violation + return (byte)'\n'; + } + _cr=true; if (buffer.hasRemaining()) - return next(buffer); + return getNextByte(buffer, last); + else if (_acceptCrAsLineTermination && last) + return '\n'; // Can return 0 here to indicate the need for more characters, // because a real 0 in the buffer would cause a BadMessage below @@ -279,7 +316,14 @@ public class MultiPartParser case LEGAL: if (_cr) - throw new BadMessageException("Bad EOL"); + { + if (!_acceptCrAsLineTermination) + throw new BadMessageException("Bad EOL"); + // TODO log compliance violation + _next = ch; + _cr = false; + return (byte)'\n'; + } return ch; case ILLEGAL: @@ -328,11 +372,11 @@ public class MultiPartParser case DELIMITER: case DELIMITER_PADDING: case DELIMITER_CLOSE: - parseDelimiter(buffer); + parseDelimiter(buffer, last); continue; case BODY_PART: - handle = parseMimePartHeaders(buffer); + handle = parseMimePartHeaders(buffer, last); break; case FIRST_OCTETS: @@ -410,11 +454,11 @@ public class MultiPartParser } /* ------------------------------------------------------------------------------- */ - private void parseDelimiter(ByteBuffer buffer) + private void parseDelimiter(ByteBuffer buffer, boolean last) { - while (__delimiterStates.contains(_state) && buffer.hasRemaining()) + while (__delimiterStates.contains(_state) && hasNextByte(buffer)) { - byte b=next(buffer); + byte b=getNextByte(buffer, last); if (b==0) return; @@ -454,13 +498,13 @@ public class MultiPartParser /* * Parse the message headers and return true if the handler has signaled for a return */ - protected boolean parseMimePartHeaders(ByteBuffer buffer) + protected boolean parseMimePartHeaders(ByteBuffer buffer, boolean last) { // Process headers - while (_state==State.BODY_PART && buffer.hasRemaining()) + while (_state==State.BODY_PART && hasNextByte(buffer)) { // process each character - byte b=next(buffer); + byte b=getNextByte(buffer, last); if (b==0) break; @@ -629,6 +673,14 @@ public class MultiPartParser protected boolean parseOctetContent(ByteBuffer buffer) { + + //handle the next content that was held because of \r as \r\n + if (_next!=0) + { + _handler.content(BufferUtil.toBuffer(new byte[] {_next}),false); + _next = 0; + } + //Starts With if (_partialBoundary>0) { diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartInputStreamTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartInputStreamTest.java index e833e16d1cb..1ee35872e2b 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartInputStreamTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartInputStreamTest.java @@ -77,7 +77,9 @@ public class MultiPartInputStreamTest "Content-Disposition: form-data; name=\"fileup\"; filename=\"test.upload\"\r\n"+ "Content-Type: application/octet-stream\r\n\r\n"+ "How now brown cow."+ - "\r\n--" + boundary + "-\r\n\r\n"; + "\r\n--" + boundary + "-\r\n" + + "Content-Disposition: form-data; name=\"fileup\"; filename=\"test.upload\"\r\n" + + "\r\n"; MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50); MultiPartInputStreamParser mpis = new MultiPartInputStreamParser(new ByteArrayInputStream(str.getBytes()), @@ -92,6 +94,7 @@ public class MultiPartInputStreamTest } catch (IOException e) { + System.err.println(e.getMessage()); assertTrue(e.getMessage().startsWith("Incomplete")); } } diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParserTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParserTest.java index 58e573bcae2..4dfe141969c 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParserTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParserTest.java @@ -450,7 +450,7 @@ public class MultiPartParserTest @Test - public void testEndState() { + public void testCrAsLineTermination() { TestHandler handler = new TestHandler() { @Override public boolean messageComplete(){ return true; } @@ -462,19 +462,14 @@ public class MultiPartParserTest return false; } }; - MultiPartParser parser = new MultiPartParser(handler,"AaB03x"); + MultiPartParser parser = new MultiPartParser(handler,"AaB03x",true); - ByteBuffer data = BufferUtil.toBuffer(" "+ - "--AaB03x\r\n"+ - "content-disposition: form-data; name=\"field1\"\r\n"+ - "\r\n"+ + ByteBuffer data = BufferUtil.toBuffer( + "--AaB03x\r"+ + "content-disposition: form-data; name=\"field1\"\r"+ + "\r"+ "Joe Blow\r\n"+ - "--AaB03x\r\n"+ - "content-disposition: form-data; name=\"stuff\"; filename=\"" + "foo.txt" + "\"\r\n"+ - "Content-Type: text/plain\r\n"+ - "\r\n"+"aaaa"+ - "bbbbb"+"\r\n" + - "--AaB03x--\r\n"); + "--AaB03x--\r"); /* Test Progression to END State */ From 0f28107a9c064bbb528c2cb3ff24737eb98b509e Mon Sep 17 00:00:00 2001 From: Lachlan Roberts Date: Wed, 21 Mar 2018 16:24:21 +1100 Subject: [PATCH 23/50] Implemented warnings for old MultiPartInputStreamParser when successfully parsing content not conforming to RFC. Modified tests in new MultiPartInputStreamTest which were failing because they didn't comply with RFC. Signed-off-by: Lachlan Roberts --- .../http/MultiPartInputStreamParser.java | 135 +++++++---------- .../eclipse/jetty/http/MultiPartParser.java | 78 +++------- .../jetty/http/MultiPartInputStreamTest.java | 137 ++++++++++-------- .../jetty/http/MultiPartParserTest.java | 21 ++- .../util/MultiPartInputStreamParser.java | 44 +++++- .../jetty/util/ReadLineInputStream.java | 29 +++- .../jetty/util/MultiPartInputStreamTest.java | 30 +++- .../jetty/util/ReadLineInputStreamTest.java | 13 ++ 8 files changed, 267 insertions(+), 220 deletions(-) diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartInputStreamParser.java b/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartInputStreamParser.java index 857909f6bd4..1cbde8dda3e 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartInputStreamParser.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartInputStreamParser.java @@ -21,16 +21,13 @@ package org.eclipse.jetty.http; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; -import java.io.FilterInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.nio.ByteBuffer; -import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardCopyOption; @@ -39,14 +36,11 @@ import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Locale; -import java.util.Map; import javax.servlet.MultipartConfigElement; import javax.servlet.ServletInputStream; import javax.servlet.http.Part; -import org.eclipse.jetty.http.HttpGenerator.State; -import org.eclipse.jetty.util.B64Code; import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.ByteArrayOutputStream2; import org.eclipse.jetty.util.LazyList; @@ -67,13 +61,14 @@ import org.eclipse.jetty.util.log.Logger; public class MultiPartInputStreamParser { private static final Logger LOG = Log.getLogger(MultiPartInputStreamParser.class); + private final int _bufferSize = 16*1024; public static final MultipartConfigElement __DEFAULT_MULTIPART_CONFIG = new MultipartConfigElement(System.getProperty("java.io.tmpdir")); public static final MultiMap EMPTY_MAP = new MultiMap<>(Collections.emptyMap()); protected InputStream _in; protected MultipartConfigElement _config; protected String _contentType; protected MultiMap _parts; - protected Exception _err; + protected Throwable _err; protected File _tmpDir; protected File _contextTmpDir; protected boolean _deleteOnExit; @@ -185,8 +180,8 @@ public class MultiPartInputStreamParser _out.flush(); _bout.writeTo(bos); _out.close(); - _bout = null; } + _bout = null; _out = bos; } @@ -515,16 +510,17 @@ public class MultiPartInputStreamParser //have we already parsed the input? if (_parts != null || _err != null) return; + try + { + + //initialize + _parts = new MultiMap<>(); + + //if its not a multipart request, don't parse it + if (_contentType == null || !_contentType.startsWith("multipart/form-data")) + return; - //initialize - _parts = new MultiMap<>(); - - //if its not a multipart request, don't parse it - if (_contentType == null || !_contentType.startsWith("multipart/form-data")) - return; - - //sort out the location to which to write the files if (_config.getLocation() == null) _tmpDir = _contextTmpDir; @@ -551,31 +547,33 @@ public class MultiPartInputStreamParser contentTypeBoundary = QuotedStringTokenizer.unquote(value(_contentType.substring(bstart,bend)).trim()); } - + Handler handler = new Handler(); MultiPartParser parser = new MultiPartParser(handler,contentTypeBoundary); - - + + // Create a buffer to store data from stream // - final int _bufferSize = 16*1024; // <---- need to rename and move somewhere else byte[] data = new byte[_bufferSize]; int len=0; - - + + /* keep running total of size of bytes read from input + * and throw an exception if exceeds MultipartConfigElement._maxRequestSize */ + long total = 0; + while(true) { - try - { - len = _in.read(data); - } - catch (IOException e) - { - _err = e; - return; - } - + + len = _in.read(data); + if(len > 0) { + total+=len; + if(_config.getMaxRequestSize() > 0 && total > _config.getMaxRequestSize()) + { + _err = new IllegalStateException ("Request exceeds maxRequestSize ("+_config.getMaxRequestSize()+")"); + return; + } + ByteBuffer buffer = BufferUtil.toBuffer(data); buffer.limit(len); parser.parse(buffer, false); @@ -585,33 +583,43 @@ public class MultiPartInputStreamParser parser.parse(BufferUtil.EMPTY_BUFFER, true); break; } + } - + + //check for exceptions if(_err != null) { return; } - + //check we read to the end of the message if(parser.getState() != MultiPartParser.State.END) { - _err = new IOException("Incomplete Multipart"); + if(parser.getState() == MultiPartParser.State.PREAMBLE) + _err = new IOException("Missing initial multi part boundary"); + else + _err = new IOException("Incomplete Multipart"); } - + if(LOG.isDebugEnabled()) { LOG.debug("Parsing Complete {} err={}",parser,_err); } - + + + } + catch (Throwable e) + { + _err = e; + return; + } + } class Handler implements MultiPartParser.Handler { - /* keep running total of size of bytes read from input - * and throw an exception if exceeds MultipartConfigElement._maxRequestSize */ - private long total = 0; - + private MultiPart _part=null; private String contentDisposition=null; private String contentType=null; @@ -783,49 +791,4 @@ public class MultiPartInputStreamParser } - - private static class Base64InputStream extends InputStream - { - ReadLineInputStream _in; - String _line; - byte[] _buffer; - int _pos; - - - public Base64InputStream(ReadLineInputStream rlis) - { - _in = rlis; - } - - @Override - public int read() throws IOException - { - if (_buffer==null || _pos>= _buffer.length) - { - //Any CR and LF will be consumed by the readLine() call. - //We need to put them back into the bytes returned from this - //method because the parsing of the multipart content uses them - //as markers to determine when we've reached the end of a part. - _line = _in.readLine(); - if (_line==null) - return -1; //nothing left - if (_line.startsWith("--")) - _buffer=(_line+"\r\n").getBytes(); //boundary marking end of part - else if (_line.length()==0) - _buffer="\r\n".getBytes(); //blank line - else - { - ByteArrayOutputStream baos = new ByteArrayOutputStream((4*_line.length()/3)+2); - B64Code.decode(_line, baos); - baos.write(13); - baos.write(10); - _buffer = baos.toByteArray(); - } - - _pos=0; - } - - return _buffer[_pos++]; - } - } } diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartParser.java b/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartParser.java index 851054ea789..b6a74c6b70b 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartParser.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartParser.java @@ -152,7 +152,6 @@ public class MultiPartParser private final boolean DEBUG=LOG.isDebugEnabled(); private final Handler _handler; private final SearchPattern _delimiterSearch; - private final boolean _acceptCrAsLineTermination; private String _fieldName; private String _fieldValue; @@ -161,34 +160,22 @@ public class MultiPartParser private FieldState _fieldState = FieldState.FIELD; private int _partialBoundary = 2; // No CRLF if no preamble private boolean _cr; - private byte _next; private ByteBuffer _patternBuffer; private final StringBuilder _string=new StringBuilder(); private int _length; + private int _totalHeaderLineLength = -1; + private int _maxHeaderLineLength = 998; /* ------------------------------------------------------------------------------- */ public MultiPartParser(Handler handler, String boundary) - { - this(handler,boundary,false); - } - - /* ------------------------------------------------------------------------------- */ - /** TODO complete - * - * @param handler - * @param boundary - * @param acceptCR - */ - public MultiPartParser(Handler handler, String boundary, boolean acceptCR) { _handler = handler; String delimiter = "\r\n--"+boundary; _patternBuffer = ByteBuffer.wrap(delimiter.getBytes(StandardCharsets.US_ASCII)); _delimiterSearch = SearchPattern.compile(_patternBuffer.array()); - _acceptCrAsLineTermination = acceptCR; } public void reset() @@ -272,21 +259,14 @@ public class MultiPartParser /* ------------------------------------------------------------------------------- */ private boolean hasNextByte(ByteBuffer buffer) { - return BufferUtil.hasContent(buffer) || _next!=0; + return BufferUtil.hasContent(buffer); } /* ------------------------------------------------------------------------------- */ - private byte getNextByte(ByteBuffer buffer, boolean last) + private byte getNextByte(ByteBuffer buffer) { - byte ch; - if (_next==0) - ch = buffer.get(); - else - { - ch = _next; - _next = 0; - } + byte ch = buffer.get(); CharState s = __charState[0xff & ch]; switch(s) @@ -297,18 +277,11 @@ public class MultiPartParser case CR: if (_cr) - { - if (!_acceptCrAsLineTermination) - throw new BadMessageException("Bad EOL"); - // TODO log compliance violation - return (byte)'\n'; - } + throw new BadMessageException("Bad EOL"); _cr=true; if (buffer.hasRemaining()) - return getNextByte(buffer, last); - else if (_acceptCrAsLineTermination && last) - return '\n'; + return getNextByte(buffer); // Can return 0 here to indicate the need for more characters, // because a real 0 in the buffer would cause a BadMessage below @@ -316,14 +289,8 @@ public class MultiPartParser case LEGAL: if (_cr) - { - if (!_acceptCrAsLineTermination) - throw new BadMessageException("Bad EOL"); - // TODO log compliance violation - _next = ch; - _cr = false; - return (byte)'\n'; - } + throw new BadMessageException("Bad EOL"); + return ch; case ILLEGAL: @@ -372,11 +339,11 @@ public class MultiPartParser case DELIMITER: case DELIMITER_PADDING: case DELIMITER_CLOSE: - parseDelimiter(buffer, last); + parseDelimiter(buffer); continue; case BODY_PART: - handle = parseMimePartHeaders(buffer, last); + handle = parseMimePartHeaders(buffer); break; case FIRST_OCTETS: @@ -454,11 +421,11 @@ public class MultiPartParser } /* ------------------------------------------------------------------------------- */ - private void parseDelimiter(ByteBuffer buffer, boolean last) + private void parseDelimiter(ByteBuffer buffer) { while (__delimiterStates.contains(_state) && hasNextByte(buffer)) { - byte b=getNextByte(buffer, last); + byte b=getNextByte(buffer); if (b==0) return; @@ -498,15 +465,22 @@ public class MultiPartParser /* * Parse the message headers and return true if the handler has signaled for a return */ - protected boolean parseMimePartHeaders(ByteBuffer buffer, boolean last) + protected boolean parseMimePartHeaders(ByteBuffer buffer) { // Process headers while (_state==State.BODY_PART && hasNextByte(buffer)) { // process each character - byte b=getNextByte(buffer, last); + byte b=getNextByte(buffer); if (b==0) break; + + if(b!=LINE_FEED) + _totalHeaderLineLength++; + + if(_totalHeaderLineLength > _maxHeaderLineLength) + throw new IllegalStateException("Header Line Exceeded Max Length"); + switch (_fieldState) { @@ -641,6 +615,7 @@ public class MultiPartParser { _fieldValue=takeString(); _length=-1; + _totalHeaderLineLength=-1; } setState(FieldState.FIELD); break; @@ -673,13 +648,6 @@ public class MultiPartParser protected boolean parseOctetContent(ByteBuffer buffer) { - - //handle the next content that was held because of \r as \r\n - if (_next!=0) - { - _handler.content(BufferUtil.toBuffer(new byte[] {_next}),false); - _next = 0; - } //Starts With if (_partialBoundary>0) diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartInputStreamTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartInputStreamTest.java index 1ee35872e2b..cf8dd525289 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartInputStreamTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartInputStreamTest.java @@ -90,11 +90,10 @@ public class MultiPartInputStreamTest try { mpis.getParts(); - fail ("Multipart incomplete"); + fail ("Incomplete Multipart"); } catch (IOException e) { - System.err.println(e.getMessage()); assertTrue(e.getMessage().startsWith("Incomplete")); } } @@ -237,11 +236,11 @@ public class MultiPartInputStreamTest try { mpis.getParts(); - fail ("Multipart missing body"); + fail ("Missing initial multi part boundary"); } catch (IOException e) { - assertTrue(e.getMessage().startsWith("Missing content")); + assertTrue(e.getMessage().contains("Missing initial multi part boundary")); } } @@ -305,11 +304,11 @@ public class MultiPartInputStreamTest try { mpis.getParts(); - fail ("Multipart missing body"); + fail("Missing initial multi part boundary"); } catch (IOException e) { - assertTrue(e.getMessage().startsWith("Missing initial")); + assertTrue(e.getMessage().contains("Missing initial multi part boundary")); } } @@ -403,13 +402,9 @@ public class MultiPartInputStreamTest Collection parts = mpis.getParts(); assertThat(parts, notNullValue()); - assertThat(parts.size(), is(2)); - Part field1 = mpis.getPart("field1"); - assertThat(field1, notNullValue()); + assertThat(parts.size(), is(1)); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); - IO.copy(field1.getInputStream(), baos); - assertThat(baos.toString("US-ASCII"), is("Joe Blow")); - Part stuff = mpis.getPart("stuff"); assertThat(stuff, notNullValue()); baos = new ByteArrayOutputStream(); @@ -446,10 +441,10 @@ public class MultiPartInputStreamTest config, _tmpDir); mpis.setDeleteOnExit(true); - Collection parts = null; + try { - parts = mpis.getParts(); + mpis.getParts(); fail("Request should have exceeded maxRequestSize"); } catch (IllegalStateException e) @@ -534,6 +529,7 @@ public class MultiPartInputStreamTest } catch (IllegalStateException e) { + e.printStackTrace(); assertTrue(e.getMessage().startsWith("Multipart Mime part")); } @@ -600,12 +596,12 @@ public class MultiPartInputStreamTest String str = "--AaB03x\n"+ "content-disposition: form-data; name=\"field1\"\n"+ "\n"+ - "Joe Blow\n"+ - "--AaB03x\n"+ + "Joe Blow"+ + "\r\n--AaB03x\n"+ "content-disposition: form-data; name=\"field2\"\n"+ "\n"+ - "Other\n"+ - "--AaB03x--\n"; + "Other"+ + "\r\n--AaB03x--\n"; MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50); MultiPartInputStreamParser mpis = new MultiPartInputStreamParser(new ByteArrayInputStream(str.getBytes()), @@ -620,12 +616,14 @@ public class MultiPartInputStreamTest ByteArrayOutputStream baos = new ByteArrayOutputStream(); IO.copy(p1.getInputStream(), baos); assertThat(baos.toString("UTF-8"), is("Joe Blow")); - + Part p2 = mpis.getPart("field2"); assertThat(p2, notNullValue()); baos = new ByteArrayOutputStream(); IO.copy(p2.getInputStream(), baos); assertThat(baos.toString("UTF-8"), is("Other")); + + } @Test @@ -648,22 +646,30 @@ public class MultiPartInputStreamTest config, _tmpDir); mpis.setDeleteOnExit(true); - Collection parts = mpis.getParts(); - assertThat(parts.size(), is(2)); - assertThat(parts.size(), is(2)); - Part p1 = mpis.getPart("field1"); - assertThat(p1, notNullValue()); - - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - IO.copy(p1.getInputStream(), baos); - assertThat(baos.toString("UTF-8"), is("Joe Blow")); - - Part p2 = mpis.getPart("field2"); - assertThat(p2, notNullValue()); - baos = new ByteArrayOutputStream(); - IO.copy(p2.getInputStream(), baos); - assertThat(baos.toString("UTF-8"), is("Other")); + try + { + Collection parts = mpis.getParts(); + assertThat(parts.size(), is(2)); + + assertThat(parts.size(), is(2)); + Part p1 = mpis.getPart("field1"); + assertThat(p1, notNullValue()); + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + IO.copy(p1.getInputStream(), baos); + assertThat(baos.toString("UTF-8"), is("Joe Blow")); + + Part p2 = mpis.getPart("field2"); + assertThat(p2, notNullValue()); + baos = new ByteArrayOutputStream(); + IO.copy(p2.getInputStream(), baos); + assertThat(baos.toString("UTF-8"), is("Other")); + } + catch(Throwable e) + { + assertTrue(e.getMessage().contains("Bad EOL")); + } } @Test @@ -687,28 +693,37 @@ public class MultiPartInputStreamTest config, _tmpDir); mpis.setDeleteOnExit(true); - Collection parts = mpis.getParts(); - assertThat(parts.size(), is(2)); - - Part p1 = mpis.getPart("field1"); - assertThat(p1, notNullValue()); - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - IO.copy(p1.getInputStream(), baos); - assertThat(baos.toString("UTF-8"), is("\nJoe Blow\n")); - Part p2 = mpis.getPart("field2"); - assertThat(p2, notNullValue()); - baos = new ByteArrayOutputStream(); - IO.copy(p2.getInputStream(), baos); - assertThat(baos.toString("UTF-8"), is("Other")); + + try + { + Collection parts = mpis.getParts(); + assertThat(parts.size(), is(2)); + + Part p1 = mpis.getPart("field1"); + assertThat(p1, notNullValue()); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + IO.copy(p1.getInputStream(), baos); + assertThat(baos.toString("UTF-8"), is("\nJoe Blow\n")); + + Part p2 = mpis.getPart("field2"); + assertThat(p2, notNullValue()); + baos = new ByteArrayOutputStream(); + IO.copy(p2.getInputStream(), baos); + assertThat(baos.toString("UTF-8"), is("Other")); + } + catch(Throwable e) + { + assertTrue(e.getMessage().contains("Bad EOL")); + } } @Test public void testBufferOverflowNoCRLF () throws Exception { ByteArrayOutputStream baos = new ByteArrayOutputStream(); - baos.write("--AaB03x".getBytes()); - for (int i=0; i< 8500; i++) //create content that will overrun default buffer size of BufferedInputStream + baos.write("--AaB03x\r\n".getBytes()); + for (int i=0; i< 3000; i++) //create content that will overrun default buffer size of BufferedInputStream { baos.write('a'); } @@ -722,11 +737,11 @@ public class MultiPartInputStreamTest try { mpis.getParts(); - fail ("Multipart buffer overrun"); + fail ("Header Line Exceeded Max Length"); } - catch (IOException e) + catch (Throwable e) { - assertTrue(e.getMessage().startsWith("Buffer size exceeded")); + assertTrue(e.getMessage().startsWith("Header Line Exceeded Max Length")); } } @@ -735,12 +750,12 @@ public class MultiPartInputStreamTest public void testCharsetEncoding () throws Exception { String contentType = "multipart/form-data; boundary=TheBoundary; charset=ISO-8859-1"; - String str = "--TheBoundary\r"+ - "content-disposition: form-data; name=\"field1\"\r"+ - "\r"+ + String str = "--TheBoundary\r\n"+ + "content-disposition: form-data; name=\"field1\"\r\n"+ + "\r\n"+ "\nJoe Blow\n"+ - "\r"+ - "--TheBoundary--\r"; + "\r\n"+ + "--TheBoundary--\r\n"; MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50); MultiPartInputStreamParser mpis = new MultiPartInputStreamParser(new ByteArrayInputStream(str.getBytes()), @@ -907,8 +922,8 @@ public class MultiPartInputStreamTest assertThat(stuff.getSize(),is(51L)); File tmpfile = ((MultiPartInputStreamParser.MultiPart)stuff).getFile(); - assertThat(tmpfile,notNullValue()); // longer than 100 bytes, should already be a tmp file - assertThat(((MultiPartInputStreamParser.MultiPart)stuff).getBytes(),nullValue()); //not in an internal buffer + assertThat(tmpfile,notNullValue()); // longer than 50 bytes, should already be a tmp file + assertThat(stuff.getBytes(),nullValue()); //not in an internal buffer assertThat(tmpfile.exists(),is(true)); assertThat(tmpfile.getName(),is(not("stuff with space.txt"))); stuff.write(filename); @@ -1000,7 +1015,7 @@ public class MultiPartInputStreamTest assertNotNull(p2); baos = new ByteArrayOutputStream(); IO.copy(p2.getInputStream(), baos); - assertEquals("hello jetty", baos.toString("US-ASCII")); + assertEquals(B64Code.encode("hello jetty"), baos.toString("US-ASCII")); Part p3 = mpis.getPart("final"); assertNotNull(p3); @@ -1044,7 +1059,7 @@ public class MultiPartInputStreamTest assertNotNull(p2); baos = new ByteArrayOutputStream(); IO.copy(p2.getInputStream(), baos); - assertEquals("truth=beauty", baos.toString("US-ASCII")); + assertEquals("truth=3Dbeauty", baos.toString("US-ASCII")); } diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParserTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParserTest.java index 4dfe141969c..07b38af84b0 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParserTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParserTest.java @@ -462,20 +462,25 @@ public class MultiPartParserTest return false; } }; - MultiPartParser parser = new MultiPartParser(handler,"AaB03x",true); + MultiPartParser parser = new MultiPartParser(handler,"AaB03x"); ByteBuffer data = BufferUtil.toBuffer( - "--AaB03x\r"+ - "content-disposition: form-data; name=\"field1\"\r"+ + "--AaB03x\r\n"+ + "content-disposition: form-data; name=\"field1\"\r\n"+ "\r"+ "Joe Blow\r\n"+ - "--AaB03x--\r"); + "--AaB03x--\r\n"); - /* Test Progression to END State */ - parser.parse(data,true); - assertThat(parser.getState(), is(State.END)); - assertThat(data.remaining(),is(0)); + try + { + parser.parse(data,true); + fail("Invalid End of Line"); + } + catch(BadMessageException e) { + assertTrue(e.getMessage().contains("Bad EOL")); + } + } diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/MultiPartInputStreamParser.java b/jetty-util/src/main/java/org/eclipse/jetty/util/MultiPartInputStreamParser.java index a7455e4e698..23c55ddb90c 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/MultiPartInputStreamParser.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/MultiPartInputStreamParser.java @@ -36,6 +36,7 @@ import java.nio.file.StandardCopyOption; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.EnumSet; import java.util.List; import java.util.Locale; import java.util.Map; @@ -44,6 +45,7 @@ import javax.servlet.MultipartConfigElement; import javax.servlet.ServletInputStream; import javax.servlet.http.Part; +import org.eclipse.jetty.util.ReadLineInputStream.Termination; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; @@ -69,8 +71,29 @@ public class MultiPartInputStreamParser protected boolean _deleteOnExit; protected boolean _writeFilesWithFilenames; + EnumSet nonComplianceWarnings = EnumSet.noneOf(NonCompliance.class); + public enum NonCompliance + { + CR_TERMINATION, + LF_TERMINATION, + NO_INITIAL_CRLF, + BASE64_TRANSFER_ENCODING, + QUOTED_PRINTABLE_TRANSFER_ENCODING + } + public EnumSet getNonComplianceWarnings() + { + EnumSet term = ((ReadLineInputStream)_in).getLineTerminations(); + + if(term.contains(Termination.CR)) + nonComplianceWarnings.add(NonCompliance.CR_TERMINATION); + if(term.contains(Termination.LF)) + nonComplianceWarnings.add(NonCompliance.LF_TERMINATION); + + return nonComplianceWarnings; + } + public class MultiPart implements Part { protected String _name; @@ -175,8 +198,8 @@ public class MultiPartInputStreamParser _out.flush(); _bout.writeTo(bos); _out.close(); - _bout = null; } + _bout = null; _out = bos; } @@ -563,6 +586,8 @@ public class MultiPartInputStreamParser throw new IOException("Missing content for multipart request"); boolean badFormatLogged = false; + + String untrimmed = line; line=line.trim(); while (line != null && !line.equals(boundary) && !line.equals(lastBoundary)) { @@ -572,16 +597,22 @@ public class MultiPartInputStreamParser badFormatLogged = true; } line=((ReadLineInputStream)_in).readLine(); - line=(line==null?line:line.trim()); + untrimmed = line; + if(line!=null) + line = line.trim(); } - if (line == null || line.length() == 0) + if (line == null || line.length() == 0) throw new IOException("Missing initial multi part boundary"); // Empty multipart. if (line.equals(lastBoundary)) return; + // check compliance of preamble + if (Character.isWhitespace(untrimmed.charAt(0))) + nonComplianceWarnings.add(NonCompliance.NO_INITIAL_CRLF); + // Read each part boolean lastPart=false; @@ -671,10 +702,12 @@ public class MultiPartInputStreamParser InputStream partInput = null; if ("base64".equalsIgnoreCase(contentTransferEncoding)) { + nonComplianceWarnings.add(NonCompliance.BASE64_TRANSFER_ENCODING); partInput = new Base64InputStream((ReadLineInputStream)_in); } else if ("quoted-printable".equalsIgnoreCase(contentTransferEncoding)) { + nonComplianceWarnings.add(NonCompliance.QUOTED_PRINTABLE_TRANSFER_ENCODING); partInput = new FilterInputStream(_in) { @Override @@ -917,5 +950,8 @@ public class MultiPartInputStreamParser return _buffer[_pos++]; } - } + } + + + } diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/ReadLineInputStream.java b/jetty-util/src/main/java/org/eclipse/jetty/util/ReadLineInputStream.java index ff430e35c83..a6acd0c391f 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/ReadLineInputStream.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/ReadLineInputStream.java @@ -22,6 +22,9 @@ import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; import java.nio.charset.StandardCharsets; +import java.util.EnumSet; + +import org.eclipse.jetty.util.MultiPartInputStreamParser.NonCompliance; /** * ReadLineInputStream @@ -32,6 +35,15 @@ public class ReadLineInputStream extends BufferedInputStream { boolean _seenCRLF; boolean _skipLF; + private EnumSet _lineTerminations = EnumSet.noneOf(Termination.class); + public EnumSet getLineTerminations() { return _lineTerminations; } + public enum Termination + { + CRLF, + LF, + CR, + EOF + } public ReadLineInputStream(InputStream in) { @@ -54,13 +66,18 @@ public class ReadLineInputStream extends BufferedInputStream if (markpos < 0) throw new IOException("Buffer size exceeded: no line terminator"); + if(_skipLF && b!='\n') + _lineTerminations.add(Termination.CR); + if (b==-1) { int m=markpos; markpos=-1; if (pos>m) + { + _lineTerminations.add(Termination.EOF); return new String(buf,m,pos-m, StandardCharsets.UTF_8); - + } return null; } @@ -72,10 +89,18 @@ public class ReadLineInputStream extends BufferedInputStream if (_seenCRLF && pos parts = mpis.getParts(); assertTrue(mpis.getParts().isEmpty()); + assertEquals(EnumSet.noneOf(NonCompliance.class), mpis.getNonComplianceWarnings()); } @@ -141,6 +144,7 @@ public class MultiPartInputStreamTest _tmpDir); mpis.setDeleteOnExit(true); assertTrue(mpis.getParts().isEmpty()); + assertEquals(EnumSet.noneOf(NonCompliance.class), mpis.getNonComplianceWarnings()); } @Test @@ -201,7 +205,10 @@ public class MultiPartInputStreamTest assertThat(title, notNullValue()); assertThat(title.getSize(), is(3L)); IO.copy(title.getInputStream(), baos); - assertThat(baos.toString("US-ASCII"), is("ttt")); + assertThat(baos.toString("US-ASCII"), is("ttt")); + + assertEquals(EnumSet.noneOf(NonCompliance.class), mpis.getNonComplianceWarnings()); + } @Test @@ -215,6 +222,7 @@ public class MultiPartInputStreamTest _tmpDir); mpis.setDeleteOnExit(true); assertTrue(mpis.getParts().isEmpty()); + assertEquals(EnumSet.noneOf(NonCompliance.class), mpis.getNonComplianceWarnings()); } @Test @@ -369,10 +377,11 @@ public class MultiPartInputStreamTest baos = new ByteArrayOutputStream(); IO.copy(stuff.getInputStream(), baos); assertTrue(baos.toString("US-ASCII").contains("aaaa")); + + assertEquals(EnumSet.of(NonCompliance.LF_TERMINATION), mpis.getNonComplianceWarnings()); } - @Test public void testLeadingWhitespaceBodyWithoutCRLF() throws Exception @@ -410,13 +419,12 @@ public class MultiPartInputStreamTest baos = new ByteArrayOutputStream(); IO.copy(stuff.getInputStream(), baos); assertTrue(baos.toString("US-ASCII").contains("bbbbb")); + + assertEquals(EnumSet.of(NonCompliance.NO_INITIAL_CRLF), mpis.getNonComplianceWarnings()); } - - - @Test public void testNoLimits() throws Exception @@ -431,6 +439,7 @@ public class MultiPartInputStreamTest assertFalse(parts.isEmpty()); } + @Test public void testRequestTooBig () throws Exception @@ -621,6 +630,8 @@ public class MultiPartInputStreamTest baos = new ByteArrayOutputStream(); IO.copy(p2.getInputStream(), baos); assertThat(baos.toString("UTF-8"), is("Other")); + + assertEquals(EnumSet.of(NonCompliance.LF_TERMINATION), mpis.getNonComplianceWarnings()); } @Test @@ -659,6 +670,8 @@ public class MultiPartInputStreamTest baos = new ByteArrayOutputStream(); IO.copy(p2.getInputStream(), baos); assertThat(baos.toString("UTF-8"), is("Other")); + + assertEquals(EnumSet.of(NonCompliance.CR_TERMINATION), mpis.getNonComplianceWarnings()); } @Test @@ -696,6 +709,8 @@ public class MultiPartInputStreamTest baos = new ByteArrayOutputStream(); IO.copy(p2.getInputStream(), baos); assertThat(baos.toString("UTF-8"), is("Other")); + + assertEquals(EnumSet.of(NonCompliance.CR_TERMINATION), mpis.getNonComplianceWarnings()); } @Test @@ -745,6 +760,7 @@ public class MultiPartInputStreamTest mpis.setDeleteOnExit(true); Collection parts = mpis.getParts(); assertThat(parts.size(), is(1)); + } @@ -1002,6 +1018,8 @@ public class MultiPartInputStreamTest baos = new ByteArrayOutputStream(); IO.copy(p3.getInputStream(), baos); assertEquals("the end", baos.toString("US-ASCII")); + + assertEquals(EnumSet.of(NonCompliance.BASE64_TRANSFER_ENCODING), mpis.getNonComplianceWarnings()); } @Test @@ -1040,6 +1058,8 @@ public class MultiPartInputStreamTest baos = new ByteArrayOutputStream(); IO.copy(p2.getInputStream(), baos); assertEquals("truth=beauty", baos.toString("US-ASCII")); + + assertEquals(EnumSet.of(NonCompliance.QUOTED_PRINTABLE_TRANSFER_ENCODING), mpis.getNonComplianceWarnings()); } diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/ReadLineInputStreamTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/ReadLineInputStreamTest.java index 6a41d1de765..e1e53708c14 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/ReadLineInputStreamTest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/ReadLineInputStreamTest.java @@ -22,8 +22,10 @@ import java.io.OutputStream; import java.io.PipedInputStream; import java.io.PipedOutputStream; import java.nio.charset.StandardCharsets; +import java.util.EnumSet; import java.util.concurrent.TimeUnit; +import org.eclipse.jetty.util.ReadLineInputStream.Termination; import org.junit.After; import org.junit.Assert; import org.junit.Before; @@ -101,6 +103,7 @@ public class ReadLineInputStreamTest Assert.assertEquals("World",_in.readLine()); Assert.assertEquals("",_in.readLine()); Assert.assertEquals(null,_in.readLine()); + Assert.assertEquals(EnumSet.of(Termination.CR), _in.getLineTerminations()); } @Test @@ -114,6 +117,7 @@ public class ReadLineInputStreamTest Assert.assertEquals("World",_in.readLine()); Assert.assertEquals("",_in.readLine()); Assert.assertEquals(null,_in.readLine()); + Assert.assertEquals(EnumSet.of(Termination.LF), _in.getLineTerminations()); } @Test @@ -127,6 +131,7 @@ public class ReadLineInputStreamTest Assert.assertEquals("World",_in.readLine()); Assert.assertEquals("",_in.readLine()); Assert.assertEquals(null,_in.readLine()); + Assert.assertEquals(EnumSet.of(Termination.CRLF), _in.getLineTerminations()); } @@ -145,6 +150,7 @@ public class ReadLineInputStreamTest Assert.assertEquals("World",_in.readLine()); Assert.assertEquals("",_in.readLine()); Assert.assertEquals(null,_in.readLine()); + Assert.assertEquals(EnumSet.of(Termination.CR), _in.getLineTerminations()); } @Test @@ -162,6 +168,7 @@ public class ReadLineInputStreamTest Assert.assertEquals("World",_in.readLine()); Assert.assertEquals("",_in.readLine()); Assert.assertEquals(null,_in.readLine()); + Assert.assertEquals(EnumSet.of(Termination.LF), _in.getLineTerminations()); } @Test @@ -180,6 +187,7 @@ public class ReadLineInputStreamTest Assert.assertEquals("World",_in.readLine()); Assert.assertEquals("",_in.readLine()); Assert.assertEquals(null,_in.readLine()); + Assert.assertEquals(EnumSet.of(Termination.CRLF), _in.getLineTerminations()); } @@ -201,6 +209,7 @@ public class ReadLineInputStreamTest Assert.assertEquals("",_in.readLine()); Assert.assertEquals(null,_in.readLine()); + Assert.assertEquals(EnumSet.of(Termination.LF), _in.getLineTerminations()); } @Test @@ -221,6 +230,8 @@ public class ReadLineInputStreamTest Assert.assertEquals("",_in.readLine()); Assert.assertEquals(null,_in.readLine()); + Assert.assertEquals(EnumSet.of(Termination.CR), _in.getLineTerminations()); + } @Test @@ -241,6 +252,8 @@ public class ReadLineInputStreamTest Assert.assertEquals("",_in.readLine()); Assert.assertEquals(null,_in.readLine()); + Assert.assertEquals(EnumSet.of(Termination.CRLF), _in.getLineTerminations()); + } From c0dcf9a0a27948c549846784d636647ca0d331a9 Mon Sep 17 00:00:00 2001 From: Joakim Erdfelt Date: Wed, 21 Mar 2018 16:14:43 -0500 Subject: [PATCH 24/50] Issue #1027 - multipart testing examples Adding raw/binary gitattributes Signed-off-by: Joakim Erdfelt --- .gitattributes | 3 +- .../server/handler/ResourceHandlerTest.java | 4 +- .../jetty/util/MultiPartParsingTest.java | 282 +++++ .../multipart-base64-long.expected.txt | 4 + .../multipart/multipart-base64-long.raw | 8 + .../multipart/multipart-base64.expected.txt | 4 + .../resources/multipart/multipart-base64.raw | 389 +++++++ .../multipart/multipart-complex.expected.txt | 9 + .../resources/multipart/multipart-complex.raw | Bin 0 -> 22929 bytes .../multipart-duplicate-names-1.expected.txt | 2 + .../multipart/multipart-duplicate-names-1.raw | Bin 0 -> 1859 bytes .../multipart-encoding-mess.expected.txt | 4 + .../multipart/multipart-encoding-mess.raw | 1009 +++++++++++++++++ ...ultipart-inside-itself-binary.expected.txt | 6 + .../multipart-inside-itself-binary.raw | 50 + .../multipart-inside-itself.expected.txt | 6 + .../multipart/multipart-inside-itself.raw | 42 + .../multipart-number-browser.expected.txt | 3 + .../multipart/multipart-number-browser.raw | 5 + .../multipart-number-strict.expected.txt | 3 + .../multipart/multipart-number-strict.raw | 7 + .../multipart/multipart-sjis.expected.txt | 4 + .../resources/multipart/multipart-sjis.raw | 13 + .../multipart-strange-quoting.expected.txt | 5 + .../multipart/multipart-strange-quoting.raw | 26 + .../multipart-text-files.expected.txt | 9 + .../multipart/multipart-text-files.raw | 23 + .../multipart-unicode-names.expected.txt | 5 + .../multipart/multipart-unicode-names.raw | 13 + .../multipart-uppercase.expected.txt | 5 + .../multipart/multipart-uppercase.raw | 13 + ...ltipart-x-www-form-urlencoded.expected.txt | 5 + .../multipart-x-www-form-urlencoded.raw | 7 + .../multipart-zencoding.expected.txt | 8 + .../multipart/multipart-zencoding.raw | Bin 0 -> 1830 bytes 35 files changed, 1973 insertions(+), 3 deletions(-) create mode 100644 jetty-util/src/test/java/org/eclipse/jetty/util/MultiPartParsingTest.java create mode 100644 jetty-util/src/test/resources/multipart/multipart-base64-long.expected.txt create mode 100644 jetty-util/src/test/resources/multipart/multipart-base64-long.raw create mode 100644 jetty-util/src/test/resources/multipart/multipart-base64.expected.txt create mode 100644 jetty-util/src/test/resources/multipart/multipart-base64.raw create mode 100644 jetty-util/src/test/resources/multipart/multipart-complex.expected.txt create mode 100644 jetty-util/src/test/resources/multipart/multipart-complex.raw create mode 100644 jetty-util/src/test/resources/multipart/multipart-duplicate-names-1.expected.txt create mode 100644 jetty-util/src/test/resources/multipart/multipart-duplicate-names-1.raw create mode 100644 jetty-util/src/test/resources/multipart/multipart-encoding-mess.expected.txt create mode 100644 jetty-util/src/test/resources/multipart/multipart-encoding-mess.raw create mode 100644 jetty-util/src/test/resources/multipart/multipart-inside-itself-binary.expected.txt create mode 100644 jetty-util/src/test/resources/multipart/multipart-inside-itself-binary.raw create mode 100644 jetty-util/src/test/resources/multipart/multipart-inside-itself.expected.txt create mode 100644 jetty-util/src/test/resources/multipart/multipart-inside-itself.raw create mode 100644 jetty-util/src/test/resources/multipart/multipart-number-browser.expected.txt create mode 100644 jetty-util/src/test/resources/multipart/multipart-number-browser.raw create mode 100644 jetty-util/src/test/resources/multipart/multipart-number-strict.expected.txt create mode 100644 jetty-util/src/test/resources/multipart/multipart-number-strict.raw create mode 100644 jetty-util/src/test/resources/multipart/multipart-sjis.expected.txt create mode 100644 jetty-util/src/test/resources/multipart/multipart-sjis.raw create mode 100644 jetty-util/src/test/resources/multipart/multipart-strange-quoting.expected.txt create mode 100644 jetty-util/src/test/resources/multipart/multipart-strange-quoting.raw create mode 100644 jetty-util/src/test/resources/multipart/multipart-text-files.expected.txt create mode 100644 jetty-util/src/test/resources/multipart/multipart-text-files.raw create mode 100644 jetty-util/src/test/resources/multipart/multipart-unicode-names.expected.txt create mode 100644 jetty-util/src/test/resources/multipart/multipart-unicode-names.raw create mode 100644 jetty-util/src/test/resources/multipart/multipart-uppercase.expected.txt create mode 100644 jetty-util/src/test/resources/multipart/multipart-uppercase.raw create mode 100644 jetty-util/src/test/resources/multipart/multipart-x-www-form-urlencoded.expected.txt create mode 100644 jetty-util/src/test/resources/multipart/multipart-x-www-form-urlencoded.raw create mode 100644 jetty-util/src/test/resources/multipart/multipart-zencoding.expected.txt create mode 100644 jetty-util/src/test/resources/multipart/multipart-zencoding.raw diff --git a/.gitattributes b/.gitattributes index 2d74f3a7f01..b9b0a86549a 100644 --- a/.gitattributes +++ b/.gitattributes @@ -5,4 +5,5 @@ *.java eol=lf *.xml eol=lf Jenkinsfile eol=lf -*.js eol=lf \ No newline at end of file +*.js eol=lf +*.raw binary \ No newline at end of file diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ResourceHandlerTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ResourceHandlerTest.java index 91d0ededdd1..17d48320c00 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ResourceHandlerTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ResourceHandlerTest.java @@ -170,14 +170,14 @@ public class ResourceHandlerTest assertThat(response.getContent(),containsString("big.txt")); assertThat(response.getContent(),containsString("bigger.txt")); assertThat(response.getContent(),containsString("directory")); - assertThat(response.getContent(),containsString("simple.txt")); + assertThat(response.getContent(),containsString("simple.raw")); } @Test public void testHeaders() throws Exception { HttpTester.Response response = HttpTester.parseResponse( - _local.getResponse("GET /resource/simple.txt HTTP/1.0\r\n\r\n")); + _local.getResponse("GET /resource/simple.raw HTTP/1.0\r\n\r\n")); assertThat(response.getStatus(),equalTo(200)); assertThat(response.get(CONTENT_TYPE),equalTo("text/plain")); assertThat(response.get(LAST_MODIFIED),Matchers.notNullValue()); diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/MultiPartParsingTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/MultiPartParsingTest.java new file mode 100644 index 00000000000..67e156f6cc9 --- /dev/null +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/MultiPartParsingTest.java @@ -0,0 +1,282 @@ +// +// ======================================================================== +// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.util; + +import static java.nio.charset.StandardCharsets.UTF_8; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.junit.Assert.assertThat; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.charset.Charset; +import java.nio.file.Files; +import java.nio.file.Path; +import java.security.DigestOutputStream; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +import javax.servlet.MultipartConfigElement; +import javax.servlet.http.Part; + +import org.eclipse.jetty.toolchain.test.Hex; +import org.eclipse.jetty.toolchain.test.MavenTestingUtils; +import org.eclipse.jetty.toolchain.test.TestingDir; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +@RunWith(Parameterized.class) +public class MultiPartParsingTest +{ + + public static final int MAX_FILE_SIZE = 60 * 1024; + public static final int MAX_REQUEST_SIZE = 1024 * 1024; + public static final int FILE_SIZE_THRESHOLD = 50; + + @Parameterized.Parameters(name = "{0}") + public static List data() + { + List ret = new ArrayList<>(); + + ret.add(new String[]{"multipart-text-files"}); + ret.add(new String[]{"multipart-base64"}); + ret.add(new String[]{"multipart-base64-long"}); + ret.add(new String[]{"multipart-complex"}); + ret.add(new String[]{"multipart-duplicate-names-1"}); + ret.add(new String[]{"multipart-encoding-mess"}); + ret.add(new String[]{"multipart-inside-itself"}); + ret.add(new String[]{"multipart-inside-itself-binary"}); + ret.add(new String[]{"multipart-number-browser"}); + ret.add(new String[]{"multipart-number-strict"}); + ret.add(new String[]{"multipart-sjis"}); + ret.add(new String[]{"multipart-strange-quoting"}); + ret.add(new String[]{"multipart-unicode-names"}); + ret.add(new String[]{"multipart-uppercase"}); + ret.add(new String[]{"multipart-x-www-form-urlencoded"}); + ret.add(new String[]{"multipart-zencoding"}); + + return ret; + } + + @Rule + public TestingDir testingDir = new TestingDir(); + + private final Path multipartRawFile; + private final MultipartExpectations multipartExpectations; + + public MultiPartParsingTest(String rawPrefix) throws IOException + { + multipartRawFile = MavenTestingUtils.getTestResourcePathFile("multipart/" + rawPrefix + ".raw"); + Path expectationPath = MavenTestingUtils.getTestResourcePathFile("multipart/" + rawPrefix + ".expected.txt"); + multipartExpectations = new MultipartExpectations(expectationPath); + } + + @Test + public void testParse() throws IOException, NoSuchAlgorithmException + { + Path outputDir = testingDir.getEmptyPathDir(); + MultipartConfigElement config = newMultipartConfigElement(outputDir); + try (InputStream in = Files.newInputStream(multipartRawFile)) + { + MultiPartInputStreamParser parser = new MultiPartInputStreamParser( + in, multipartExpectations.contentType, config, outputDir.toFile()); + parser.parse(); + + // Evaluate Count + if (multipartExpectations.partCount >= 0) + { + assertThat("Mulitpart.parts.size", parser.getParts().size(), is(multipartExpectations.partCount)); + } + + // Evaluate expected Contents + for (NameValue expected : multipartExpectations.partContainsContents) + { + Part part = parser.getPart(expected.name); + assertThat("Part[" + expected.name + "]", part, is(notNullValue())); + try (InputStream partInputStream = part.getInputStream()) + { + String charset = getCharsetFromContentType(part.getContentType(), UTF_8); + String contents = IO.toString(partInputStream, charset); + assertThat("Part[" + expected.name + "].contents", contents, containsString(expected.value)); + } + } + + // Evaluate expected filenames + for (NameValue expected : multipartExpectations.partFilenames) + { + Part part = parser.getPart(expected.name); + assertThat("Part[" + expected.name + "]", part, is(notNullValue())); + assertThat("Part[" + expected.name + "]", part.getSubmittedFileName(), is(expected.value)); + } + + // Evaluate expected contents checksums + for (NameValue expected : multipartExpectations.partSha1sums) + { + Part part = parser.getPart(expected.name); + assertThat("Part[" + expected.name + "]", part, is(notNullValue())); + MessageDigest digest = MessageDigest.getInstance("SHA1"); + try (InputStream partInputStream = part.getInputStream(); + NoOpOutputStream noop = new NoOpOutputStream(); + DigestOutputStream digester = new DigestOutputStream(noop, digest)) + { + IO.copy(partInputStream, digester); + String actualSha1sum = Hex.asHex(digest.digest()); + assertThat("Part[" + expected.name + "].sha1sum", actualSha1sum, containsString(expected.value)); + } + } + } + } + + private MultipartConfigElement newMultipartConfigElement(Path path) + { + return new MultipartConfigElement(path.toString(), MAX_FILE_SIZE, MAX_REQUEST_SIZE, FILE_SIZE_THRESHOLD); + } + + private String getCharsetFromContentType(String contentType, Charset defaultCharset) + { + if(StringUtil.isBlank(contentType)) + { + return defaultCharset.toString(); + } + + QuotedStringTokenizer tok = new QuotedStringTokenizer(contentType, ";", false, false); + while(tok.hasMoreTokens()) + { + String str = tok.nextToken().trim(); + if(str.startsWith("charset=")) + { + return str.substring("charset=".length()); + } + } + + return defaultCharset.toString(); + } + + public static class NameValue + { + public String name; + public String value; + } + + public static class MultipartExpectations + { + public final String contentType; + public final int partCount; + public final List partFilenames = new ArrayList<>(); + public final List partSha1sums = new ArrayList<>(); + public final List partContainsContents = new ArrayList<>(); + + public MultipartExpectations(Path expectationsPath) throws IOException + { + String parsedContentType = null; + String parsedPartCount = "-1"; + + try (BufferedReader reader = Files.newBufferedReader(expectationsPath)) + { + String line; + while ((line = reader.readLine()) != null) + { + line = line.trim(); + if (StringUtil.isBlank(line) || line.startsWith("#")) + { + // skip blanks and comments + continue; + } + + String split[] = line.split("\\|"); + switch (split[0]) + { + case "Content-Type": + parsedContentType = split[1]; + break; + case "Parts-Count": + parsedPartCount = split[1]; + break; + case "Part-ContainsContents": + { + NameValue pair = new NameValue(); + pair.name = split[1]; + pair.value = split[2]; + partContainsContents.add(pair); + break; + } + case "Part-Filename": + { + NameValue pair = new NameValue(); + pair.name = split[1]; + pair.value = split[2]; + partFilenames.add(pair); + break; + } + case "Part-Sha1sum": + { + NameValue pair = new NameValue(); + pair.name = split[1]; + pair.value = split[2]; + partSha1sums.add(pair); + break; + } + default: + throw new IOException("Bad Line in " + expectationsPath + ": " + line); + } + } + } + + Objects.requireNonNull(parsedContentType, "Missing required 'Content-Type' declaration: " + expectationsPath); + this.contentType = parsedContentType; + this.partCount = Integer.parseInt(parsedPartCount); + } + } + + class NoOpOutputStream extends OutputStream + { + @Override + public void write(byte[] b) throws IOException + { + } + + @Override + public void write(byte[] b, int off, int len) throws IOException + { + } + + @Override + public void flush() throws IOException + { + } + + @Override + public void close() throws IOException + { + } + + @Override + public void write(int b) throws IOException + { + } + } +} diff --git a/jetty-util/src/test/resources/multipart/multipart-base64-long.expected.txt b/jetty-util/src/test/resources/multipart/multipart-base64-long.expected.txt new file mode 100644 index 00000000000..2b1d5ded060 --- /dev/null +++ b/jetty-util/src/test/resources/multipart/multipart-base64-long.expected.txt @@ -0,0 +1,4 @@ +Content-Type|multipart/form-data; boundary="JuH4rALGPJfmAquncS_U1du8s59GjKKiG9a8" +Parts-Count|1 +Part-Filename|png|jetty-avatar-256.png +Part-Sha1sum|png|e75b73644afe9b234d70da9ff225229de68cdff8 \ No newline at end of file diff --git a/jetty-util/src/test/resources/multipart/multipart-base64-long.raw b/jetty-util/src/test/resources/multipart/multipart-base64-long.raw new file mode 100644 index 00000000000..2e2b4991568 --- /dev/null +++ b/jetty-util/src/test/resources/multipart/multipart-base64-long.raw @@ -0,0 +1,8 @@ +--JuH4rALGPJfmAquncS_U1du8s59GjKKiG9a8 +Content-ID: +Content-Disposition: form-data; name="png"; filename="jetty-avatar-256.png" +Content-Type: image/png; name=jetty-avatar-256.png +Content-Transfer-Encoding: base64 + +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 +--JuH4rALGPJfmAquncS_U1du8s59GjKKiG9a8-- diff --git a/jetty-util/src/test/resources/multipart/multipart-base64.expected.txt b/jetty-util/src/test/resources/multipart/multipart-base64.expected.txt new file mode 100644 index 00000000000..5d4a189b8dc --- /dev/null +++ b/jetty-util/src/test/resources/multipart/multipart-base64.expected.txt @@ -0,0 +1,4 @@ +Content-Type|multipart/form-data; boundary="8GbcZNTauFWYMt7GeM9BxFMdlNBJ6aLJhGdXp" +Parts-Count|1 +Part-Filename|png|jetty-avatar-256.png +Part-Sha1sum|png|e75b73644afe9b234d70da9ff225229de68cdff8 \ No newline at end of file diff --git a/jetty-util/src/test/resources/multipart/multipart-base64.raw b/jetty-util/src/test/resources/multipart/multipart-base64.raw new file mode 100644 index 00000000000..514a6a1ed3c --- /dev/null +++ b/jetty-util/src/test/resources/multipart/multipart-base64.raw @@ -0,0 +1,389 @@ +--8GbcZNTauFWYMt7GeM9BxFMdlNBJ6aLJhGdXp +Content-ID: +Content-Disposition: form-data; name="png"; filename="jetty-avatar-256.png" +Content-Type: image/png; name=jetty-avatar-256.png +Content-Transfer-Encoding: base64 + +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 +--8GbcZNTauFWYMt7GeM9BxFMdlNBJ6aLJhGdXp-- diff --git a/jetty-util/src/test/resources/multipart/multipart-complex.expected.txt b/jetty-util/src/test/resources/multipart/multipart-complex.expected.txt new file mode 100644 index 00000000000..1eed38785c1 --- /dev/null +++ b/jetty-util/src/test/resources/multipart/multipart-complex.expected.txt @@ -0,0 +1,9 @@ +Content-Type|multipart/form-data; boundary="PMyKOsh8JrSZm-rUF8EJej42yqbh-UWw9FG-" +Parts-Count|6 +Part-ContainsContents|pi|3.14159265358979323846264338327950288419716939937510 +Part-ContainsContents|company|bob & frank's shoe repair +Part-ContainsContents|power|ꬵо𝗋ⲥ𝖾 +Part-ContainsContents|japanese|健治 +Part-ContainsContents|hello|ャユ戆タ +Part-Filename|upload_file|filename +Part-Sha1sum|upload_file|e75b73644afe9b234d70da9ff225229de68cdff8 diff --git a/jetty-util/src/test/resources/multipart/multipart-complex.raw b/jetty-util/src/test/resources/multipart/multipart-complex.raw new file mode 100644 index 0000000000000000000000000000000000000000..e74c27a67daacc6680c483bc89a9952531c1646d GIT binary patch literal 22929 zcmb@ubx>4){4acVX^@l_w=b40pvbDX4 zkk8v!w!AueUXstA^O6!jadvXIc5>%^YUk$S>}Ka~=jDj_K@DJ&!`AtELuCL$~>AuJ>= zDJmc&At53tDK01`DJ&@|EG{Z2KuXN}e|2P*&W6g^<$o6Le}DCV9G|nLyR|#7o4c#Eh2#HmSg-7yEL?qVmhOXw+H+E324VmJ zNRT1ZYbfWKho^~iq1T$7CVDAep3B43^4u6=chkco^)#|2zX54FWnMx zs*-1(4|y6v{R%B9CN_cS5}YM5*V@-XSe`V;I`wDMad8oh0u%ER3WSx{F9P?+W#T+s zR+zf(LnbKvCr`4{$xnRgC+HqDv~2s1c2b4I^?mTwO!|UpA%#p`4Hby!p^>zKN8Ujy||_|kOC1dj*c9fwJE*%F(#h*Xlwyub9X>^E`p}UQ{ z5VP>DOIxY65TCmtU&rz1Jv`HULR118@lIF#C(P`dT)c8K9~Tfr{OOwrndp}{WJ>z29G!c;rKq1ypRa~>3wPZPk& zLnyoG3{JA+OiC7y6Hg|&8P`v7TCJXD zLSDjvyY1!K3J+NmORc+}US?ZzQ8X#aedF~FZ0w{UqYDgT($r-)OSn9OMSP6dw0%#g z-DlG!l-bMeyVrQeOH54s0k$a*$JbT$H~6Z>4&f$EsCA}mq*HWExeICdd=;&I_aPf~ zR_#SY!bd zP*9Rx54gJN=$x1GJu_%mz}20L*z{YP?P}Bw)XDN{hq?rHxBq3%!EQW+JhVqPw3k)h-3>H2k94GYY`(?VD@{bu6U6x~{8SrFO41O-&nA@Q zN|;EsPqb+{Q{K$@w*s)rG1ogc$Qq*=l$=x?$YjW%5ss#DIsNjW?g2G7jQa8SC*Rj< zZWUSeN_ROO!F=aEl~4o;rx(2XW5Hc#%ucsLrAsHP1in_FWP4@ozAK9F?C{%D^7GZ#aQSKO9_f(ML{^S|i z8Uv2h`WF_LFn}ld+A}nR%JnE&iY^MjsHhM?bbPW4VD3v%YMmhz(Z2^d+AH)8dE8kP z0{s4dOBdJl8SSHr9i80Ls`bgsiUm7ly1>yKJ@@$nCY?P9aDc_}0qW=0;}ewr#nVMr zz;Cf~zHM1+NP&QC@s7u9M_O~;{Wi>Jyh|hI65uW4%!EvnwL!C%NyXXb>0usStRcg#{X%(WT*P~I}O#sXo^W6Av_1>?LkTTrGR(8 zJ3U~0yUBox5EfE#8`X+gCkj^#(+20lX|nxVO~I&8Of&Yo&>nd3Jf~macCy*u8Nu4+ zxi!|`Y_qKh-_AFZ6GFY!OQs-i5nrR6+;#rZMRTi#A)Gaqs}2Y)8l) z0XdP=JLPSKge@wIsl=28BAT0ccQvg2l$Vb}GHUl3@K0Jg-zIdb6SWkvciwZ4rTCDk zoab2r#I|d)LZoq9x#fy+^&_GK2Dg!S9y`yGbE)4agdYn;iu$FWp>+BKbQesBr>mYR zQ$osRskIq+_Hz3|=C~iSG*pZM>H_*2q_agd&tgk`rZGrr?NC#9CO>l1rpc;;M>eKR zPd#Es<$o>R=2R0H-|QCzESL$Y+f%Q($P?C~VIfA))x8GUMfDNHQSN6TiM}+}S=k4}y9f zROxI=puN;D*fP(OWAM?kv4&7KW6Bnc<}a0@i=0shWB(hDMxjPYyGn^0s{c2(QYR9l2Sjn_XoIOCx~m z*8|B+dt;?WfB*gcN-|aJY&KB%tz>u2QFj98l!TZ#x$%4{qRDe_ZZ?j$!6&0A7(JRY zg{nNqAX@mPr7!iz%S_JXF#8=wQl8u0V@fNVE=usbvi^0M*JG`ffcMl~qiQ9m^`=(x z+`wd+oUXq97s0nnKjm+JWDt3=k#Aa4Q&VVB=pP>&AMakJlE`N^=et!J@jx}Xn$)A+ znWu4qb@lGu1p`Y@n%Fo%_%4-%=*h_aL)`r4*B@;V;ljC|9)hW zuuU0(Bc#I6=>EPGuoJ=GYoglmK+e3)&?A+bpU=V|>AF%<3%;2&ZnGOd zK+Z7NRKXh(3fvDy77%a=^K%YsJ~)QpYP@_IJ5*{^n@`64Xo7o%xJy9FWAhljJKK=Y zS|`6hL(EN!B4#D&@%a@_Gf>`gePP4R#bp@sqxbWlCciUh+4F_qvy0;mEyP;P!&8fr zP~80i@%a^FH7rLcxlMK7>m(YD+)p`=DA3KlJPq=zKSrzEIpfu2(1|WY^Y!5fup#@dwI4uct_U%{Ptg3 z1TfJYaG4v7PwI=9t@n_$eJE^1U}0ijG#o~G@0x$AogBD4-D%i;ch~8>YbaO64c=9y zPZg|%YYwNy75rUThbuJy$uae$PjuYaZEI~HrTmu7uUGUWbbO4Lz1-#Q&DffG$X!c4B$jSSl?{+ODJm}W&CJQk2@vTW zeB$WnIQ(|Ga~4{;;6|5E)OySGBmCFACJ~0{?&?-~3u1RY1Bplx)(KbjZkmfHy8Ymh ziK%Hi)MKaIo-=HQC!Kwv`Ra7KoSTQIaRO~<)Dcd@{f?TBF8|&is5w!f3fb4^(arYY z&XoD8=>i28o~hDiFkO3p^__!n$tRErQkgaQ%ir8RBzQ2w{=g$q_3c??6>!JWfvcg*+S?p+}hfD(6v$R za}k;a_B2}V`n)wfJUo?9dzAJwzu6oe?G+XrFs2dwuya@D>B>`0DSJ1Ad0!bdqG5g- zt>cStrHiT#{2U*j!zAf?KZ9%Hiucps5vC0M_Cr^4-3+TPln6M{_enek+kwkQAF!f| zz80dTd>&)8aDOo(C}~{1&{dJ0Sn}iZo}Q2J5O%#edQ}iogBEmf6Hd5>v!Ese3vMd z+fI{l7@dNoCXoZ;KYxCm9k?QjOGYNd@UGx)%=1Q}#d757rw6L_b=B3?qB_m<)h{~Z z$vCZ;9=DwbjIN-`n4}mLDyXQrGU$b0yUV$*C^CBt+KzLIi=P41K}eTw=z^W+qz5%+ zh3v-?mZ|Oh`sVA4t)qhW(*c)XrTaLoT#qkt;F_9o@9;@lc`$3$ntx%iQyH*Iiv!~g zd(D2lI^RW@?hH>!s`|_(k@FDXe6R87w+x{> z1hufv%|M#J>5F%Q-*`IZU_#C)5u;ACTh?f`!YT+UL~ro@l-|I^^*%nWgvUI1@x z`t4x4%ud1Oug7V=Cz~EXb)%#`q~P(-7mrH$??HB#j?go5SI1g5MHDzyONl@;Z+;CD zT(EHPVx7>NCvx3YTIhEUI^CGt6o16unOL{~&5B_+F@8g{G80-oTHJ6 zNg5wliAu2>WQk@z{WxZQP;xyLx*s|}k@pJVfpDi_SptqKU@{(1W*~+`=n=aG*E{Klfud zhV#vcl$I~kf|G}~2-4-AI`o3gKuarMZ5FD4#r{}N-|AD^y#=q{ijRwPT>=a3HRG%K z3~s+z7s$i{j`el%1y+-4qQU~FXX0QRo9K&~c)5D7oL=nBgpWtOVL{Iu~ns4qW?Fc z-i&9Y5Q)9csIeRFWMp+8gH}jjK|FDkVQo%NUnk+9CoeD0Q3S(T`U2>t9TN|q0WcYv zrlpIma=CX4XAbF4VtVmcewpRq3fK+hw8^rhnTwT`x`7+_b&sg^z(}E%cvhR#l0o5# zN5&%`*9`sgPt!YPz6ZbP=q7%6)$sr{*!d{5Gp)N0m5bwK6?;QT$;bXj5nDj!Pt4xT zk0VpuWN?V~F(^s=)*yDk)XM=yQsFROR#M)4Q6#QYmSI!pV({7R+4_2y%!G!LT*_Ui zIt!Hs&z(nv4^WxkYrXd7s((e$dFAiYk$7y*Hk=KaHu>r#lfCSfTnLaBC2O5{J>Wkl zIagD(iy~np74_OR9>VO!WPc5)a)aE>XC(nl-Tx}c$zz;+1c5nGUBXrwi}nx*hzhm~ z>Vc2WTQdMX@P&0ee$FP{=k>jyp1=A8)wMmJIL!35w4U@TR&V8O)!R%}+hMKAh9M-k zvjwSQ*oe~6|w200|u17N!vS{uy3 zx)r@x&)v9_ylm`dq_y}2Zy6$^T--zgthuzq#lu2}E`N2)I1;FM=Js0JgXrGneF*l$6qqoPLCE z&XaLK>L7LLh>H!`e6=*Td_BKLRppqG(A&afL&=)MA}`V(`P^m*$q>P21e{LpCL|=} z_(prC0p}V1hdqO^vGeT%n5Ikp-58k%RGt*;*0k_e*X@bQ6&wPx>MY_rgE9a&`!y1Q zK)m$zm1^bi;>Lx!LZF&~#YIJN*pqVPNpA1R1A~s8A30tWRGzw*`%3gOPrp0QH~SHg zG3rN|?~n`Zl-Aczoy_^|#Tw*PYUJ~o)R%yTW11{&GI!0JS}lly47z}K<_&dvf2Sl4 zwKb2u_L3D9w9HfKz$5dVlpsyQBEj;)93s&cN`pAHWbM3Mz%%*5*II2i?8^*7-cMY^ z9i>_^Z@OM<|4a?em-mW;s6RUR`Fh`yS$<~+y`HgWY-l(Ya&vU-`o9Ri+fz3Hcqnlh zqphSWD!)?!D?fm2W(Wvx(TA&OZTSo9dPdRd)ORHW=KBk6zce@iXO}DFYSJPrHI#|YGlc5ECPqz*HhgHQB*d~^6znrcfp^wGqyn{!s!Qr0nOz(OB z%X&`?OQ$lX#vz2^_TicjW7p*swu$y1{th_9o!`r_gS z$n1cdA^*)L0(|p^-TJ`xEiAwO_9a7cyd~L7ZD$QBi@Tv*3M-wVrBm zoc`W5RpYR(FzaWXQTeYUvr+Oufe#L6To~0eyQ0@g*Jir2W$wF8RLrJM8mT|ol!5Mrw0FDSrTE$m^qw9nakvCAIUn zdSx9OmA?*;C+4qDYo}YCBeswJ%3b{XIs@KyEKc{UEVbHM&uKROk>hN)*j_w=Fva4pY$Z^A|mv7;xn(2 zt}MtSF0=BkY7D-;j{SNK{${WQ=YpN_f|+zL`l`M)0OJ=$68QIJ2<0f8df^B%0GyNH~i9Z1CTX2Gf3y?Dyb*G>34t#P^D{@;L zJ5#oI(T`)k+%m&nbb7};bU*lrLwl|N8=bg`~4|E zi-YpKLdLcX-U|Yt6P1<(lMk0AfjYxDV5G$0+oo*5#hu%zFB$jvAz^d?t}V2n769>{ zXBLl)r*ZtS<+rLTwP+SO1o_W0Teu8ZE~a?Lwm@K|D`@jOm4<>uqCsOGb!!qY6XV;9 zt+hYYT0>rmrieTL=HlgLmm3y=2^-#qg_7Z6TW+9JCiU@{UUi<4jm_fn>%)G%OoP(F z%eAj@G!(xB;Z+X$JN#1o_n=P8nDgc6qe7_ri@$%zdSdUAS?2!4?v0mc#9sILsWtA( zN#ka!Ckf@|k8iQFtauZMvIG6`w_-ueeDdgIL@Sh{b^zt8240|2GS11#xp53mPIHh) zAO~H(PIkAlz*tdo#`qna-ypt-#^^tJl!C26ED$I`|0L*{`au1m6be`a=t5H>$_Ba6 z8d$9^cNO1XjWKvfl4v76Uh+A8-@NI*jOY3OqMu={ljCu&9cGhhd>oqzodq z)*xBnZpHR~dq@l0q1Px&_=&A$``2j6MrDp?QjnA^=IEQug$-3TmSEj5{h(7)z8{nf zJY;A8Wh!P8BYF?etEHh}{t1nt+2(asc*s zr71^Z-zr$xZCU`{<0?yw9lV94!|e|1!C*;eQ8L)bHE^7o%6P~rTUpMat|(hXQNDk9 z)jc@aa{Pj#&zbQ_u*(zokElF5kMhAC&r6U?m{r;S&Hg?@UZ1yF$JzCRwaS6J@mw>G z*>9(2e0L8l5u-^aRaXg#i4EA(+7^%O|J|pPudgl>v(&x}$N)lmuq8fJQET6Cqsm+E zfMEnJuOdmN;McsoXZ(D84~E}9`PJxi)V*>C@GdF+woxg}{?b)-cz;AoeMiKTl5t*O zi~$Jf{78@HP*1-<>Q}vm+bRc={6SV)-^s_Fc=3d=TWIWdrHd^Vb=BDTXyen1R>^9m zF_-tj8`d$ieJVrxM%y@wZ@H z8$kS-^YRAl${cpz%lN9c5DCgsy7f4Y2IBEaLy;^rg4EwsA6P6xKjrqGJK zE8br?sdor}POlpPjYn*B@PF8Hvldyuo;daue|I8@2m&L?3}!#WY_1!`{BlLk_Oj`0 z&Y{L;klB^$lYYT)Ir3^N*OtOpXUEx&2Q>mE9L6Bm92?~2%COjVIjn(Hh%jV5)8Vgr z^bQFA&}m+CKKd?Fian38n4_H2=+O9iur4wu3s|(%;u6=>Rqq?I2gTr|3SsB{`=b`L z4^$BNUXMTuxrnGWTj=-F79lT!TdYf%k6Ke11aL`8fSMC zQW#I9A{iwQNpOi9brutUK;d5+AOm?adtdrxV(k2!uvk#a>K2^g_fY;7IgrY<@2w|K z)6CjDcB!~!^;|Uklf({zuVVq~pUR2>S#nQ)fHG%GKH_qEo|!t8%-&7-bw8}8Wtg*t z%cJ-AZ$3Zpbd19$juRsxF?In04t=SG?8E4Mg$1 z7pK$CMw(}LV?TxbCdIn zdmFpn^571H&Srdix~ZVUScy(%Fp`?J;z^(q8!Wfu8KAL-Ju3Tz#2bBj2Iy$65+4uc7w6i9NkasP|fnr93=VJuvL$XWNsyFFqi@A;|5an-#UpPK6L3wGW<3z>gi zcS$l=@by^%t}h(-phq5TLJRn4SOq>Ai)^az{(}5aMnuSd4A8~N7^)$M$;TDirD`2aV^XS8WTJ1 zV<%-;*RePEFsJL{24h2ibC&&*^w=Cx8yy{W?=A1Rjp*J48H3m6NMTeEt?)s%Mk+_1jBAT-LOowX1OkVN9@Ej|5YmPdQztUb7wq zzd>-xh3g<9ECM{_=l8k-vGqXy?l`+nSH;?I(o1kKgNV~_9#@xV{CH;P2J-puaI|y* zit~~;MgW^I$eejVz9Ym93nLVBo_leD6|}hSI^g+<3irE>_++rg;gJ09!)=b;#}$8$ z{+XtTI_SPXJam;>tyQi1#@Rw_hE5Z(fbws=XTr&(!qwim{>F&AB5RCGT+{2}iGzYT zM0b6qqos|boK+;8SAMlmPBFiROzMheVNb&>mYK=dkh6e2{|55Ul$*)9_3}p(iU5YH zs*$H-M$WNHuS!3O&ctq|qRTb^tG`TA?*CZ#d#+x%{O>G4=zRD>aUBHz%?VWFnP~2; zeCln_qriI@pc;L&UMm%FQN2IC!&mwn&xI;MR!%G}4%g#`;(|NEd2!6e)X@7RFEZXt z=rJ0UE2?Gu&nrY$$Cdb1bJfV@Fcn!>2DjznEm~d+0l2h~+D(gVprA63@NqnLumG~o_1YEEdKO3Nn#4yc!$kI2iYN)qvilGDwv=U0WysPG)JA-lBgH?xlsm zspJ(oSX16Tnz_RA(~Rn?qSd~ebi36`N zX(^yUg|}*rhd#zNCV_tjsEOtq1PK5KOe;f=$jaias?UB`-e13r#ivPmaIuKmYYYAh zl$ZJfhYKoYW z7Q#p}^^m)GxI6Zq!OkGbbzwiW{~na^yW2bsM}4jqTych`Cok#j$0ZvHfQL za!kwgaJBQ&rdv<3yHx!h_nW|P!_87!NsmoU=L!WaI~h^NmpCY~fD3oc%Pkk#RXyGO z?d@&L;XGAKErbFsDqJCxio~398ya#Bp_mgiHExyQAjS~!qV}3EqizAuaxT?R)0&@M z(;vDdV_Cq%JLfeYP!(@xX=K#o>#^3Gz}>^T)RDrmXiT657E+Nn69O-L%bCpP?Xk#! z#mA)3!x`wy7p>uIbZS7A$JUsq_9EL7R^jS_nxTlC|gLbYqPL@PT~s-zz_NON;X_%596tah;=Ul=ud3rfPbi{6Oyc?zuR z<*I=i`hYm7FY8p$V!qwJh5MEf?)?g2W6KQ5NZwPwgY!k&%gK)m@{lTE@4Y={f?E}^ zZ_HrbOD?)6{-RBIQtz#%mR8ek4z-!c*3LIDMNXNce&MvQ>4)5fTAG@g1N}+DEkXVh z<=t4l(Q7a_5F7~!v4c`rW<0;em24^@T-G@jLTDqN z`S6d87ZEW%|GQ~q$FoS7W}Df>p$6s{#;2`_w{A0 z0u~b3D!i@)0`@b7YuP;pn)wXz>x@KTC5|0XczkXp0~|a89%>T7x44`1xv;%^ZBDcG zI+TecwOL^CJG(h~AL`8#wV67YZrX)bhHStXDWgOM^{Y1Wt`HWsok4{HK_J~FCHmXC zew$u8V0Dc_^L|YO+5Ukavoo7_hIx%_L#_bH=9v^m^J!w8U}%p%)<}MFC$pl%kmg z%;9gb*H`Lsbffacg@u3T{f|_IR%> z3; zqLGcP_sp+2FdBl`9kT0}L)WMYJPk_kO{s>d3>(NlK*SEJaSIn%{(&{)ggpFttF?o8 zqms_pMScT|8N|jve!DQ($KUdT>~g@>&O0-~ZOSZH4Rj%A+^|=`94<5-U^Gb2(RkCqV-n~)wry~MM6uRHa3)RnYBvdp?KCG# z60kCcQUP0o)voH^ExO0_vSzy{%j$8*6BvyDXuKI<&)Gu$U&YcgH8ri=;BL{)$5ajP zk+;cuUrJF_;=+`>m5$7k0cuKY#%VOa{nF$5-8U3NN)lpuxNrjC#yAvK_Gd&N z!dk=kkDw^|H7v-|ra;-tLh_q2gRj(=Sv)`i1V^##faGyxqau6_>!marYcm{w3i;v| zGZqh$ebF1?O?H@7^Rnw{Z+VWIot<66H=Dt0TK`gK>wo3;bTIOqQ-a5CkcWD$jm`>} z1WDMwM1GD2?8URpy?|1y<9W%#`mfD-!!Cy;aF)ceSNVp$QqU^NIvl9JddDw;q;po#!Sb=|Uk!lBOB}ofQ6gv>$(|(W1_y*?hIZS`wvBMSrmno)gY|NvI zZmI(dp5%XX9Ed|uwhP+fk}IDAp50$fd{24r*?FKjR3P&ejYdvp_G<3W3iGz0&mf$% zf@<7ZTL>nhDk8356Hp8F5u=KOTu@UsLnW>EOd^8i&ew%qB1 zcr&Fmcat+v?N}uVdww-3cw!xl)bB0{es|c*r-7?NyymF#pvC8gFy5awyOY%;4obY1 zojQ|Fg)H42@09sv<mb7$0c>?D*J$R;5$WdPX;Xj<&@7$?qa+;Nj1Mr_cJZrYDde`~L&wj967SiF9zy2wnD=9LBtu|GA6Us-8zD%ijXIzY8obQAeN_0*65~AhNWNNKjJhKY*F6)~)gKK|XHo zPxk?Zvb`q9s&`($*}tjXrFkc=-u{g#WRZ?)kfkWlDukyqnq_eK+PJ`f)$0xJe-%mE zv&5&J+yL3~@UVRIOzS0reTQ5>8WN_RX(DV!%^3dxP_R54xSR4rFv}#o+DKsT;OG|J zoV57B=RIWISoGQbjY`mV=ehjFk9etUO!Y_B6oIzZynN1f19m{?a@%LWjlfG@c5~2a zg@usT-#{;82bS576=(Toc|mf8u#^MaulMro+c6VNGsyRWlVkI8d}dyVXp#)yUT4#Njl0DY+%_ARdhDUT z6>D;^U3}aiyfm5oC82_gEBU7tApH5VkM*%l$XTou>+vp86&lm=tyCF`{{2d?hWyi6 z#QV4h?Cj`yFlM2gsPZF<0eF!nCF%jf$#xcYyH*mkoj}7$GJa}e(Q>=M$5iPJuo}P5 z{bZTixK-8={y_yA-+44Br*4m}k2mux3n$jzj8921VtiMQ(Y$vBlfYklR5KX*m-?Z_ z8d0^+y#I_E5L0vOBW~uSqJ_#sbm^R`@#ptxzds+do4NL|&%ONm?11kTLC=WgYHxy* z@;Ss@+f-=RdDU2a^6qSE1tv{Ycnx zAe=3tE&P;R=%$Mu$fEPMms7xug^+Mab%f207BtT}3pL90DV|6bF!KajuH@ z-k?}%QMa}JgvTRTztw*?N^$)a<%y3?DK*HYNHkE7UJj>P`V|`)% z!|GM6nB&wrEss9MLV;G0%l3re6$|#9fF4g;ZZtL19m`%k`TA;5N~@;xvjxlZ6`Tf7-KG)4)R(WH2@ zzi<{Xd8rQt%q}A+T-5Te0vGPU?_-cJu`Of?xS51@SkeU3ndWare~IKG(ne)xDvOn+ z`gL$ayjK-->lO-bNFVP=f_2krbmG!Z`VGYvuS>l@w%O4vY)D86xMODyJf-D8BNU{+_vX zUis8~PS=B^pb~o$vVYLU@@Wl;2#*pY;{a%MFLT^hM4z1ln5_aS$adMOMcGP3-HkB9 zEa9?1geyLh`Q7!w>KWrEf)@nLAg%|qTHmAZ2rdEVT7CxfXXR7}1U5$XD;8(rnXlW!@EVB1FKl^%tk)-&P;GYwGPF97mu|~1A@EXa4YId9!o5Du7o+Bq2 z(d+qJ|LF5OVy+P8PIjdN6+Xs-RNgsb(O&Eul{XosNmcP#cj_f`9n@p*joid;ixyCd zAg^{;yDT0leDa>m4|$X_f5!}+aB^iNcon$}7oe|*F~IrUN`^~?#x86d{XG;Sf%9{6 zDoMI5pjJrWzb~;uN61$V)R>_*pY_zAyWp`<{Zdy%i~1FBCR{g#1?6D}QwxhMk=5G5 z;M;-)BOB>{yB7JER0I1CbFV{F^UjPumBjpZx+;9oQRPg((4u z-x>PTv52``GL-XFF_gb=!%8e}wUQ^)y^%8>Jx-&E04ez{+YKV@Yd%aVk<0+Kf*Y4` z5d<^6pl~33W_{hlL)-d9zeX-ojI*G~0XB5e*p2*iu-cb+qbpLOtjxMUbn-l14EYH7 zipR<=)>02y-b}={)KP-jQRoaoEofQ1275V&76L0S-t%_>6g|LfikR5yxIOSk`KMU| z1=L*U5(nc1|BH~IGlgo5Tw<-Sk&lo7bqsRJ_!KXbL2f_$zKoc-cVl8?9HjD5q6bRYheep;tYQ3iWXt5y*spE%c3mMYlNzUd=N0+a;S;#tVRphv$CF z87#+cpaAj3h8Sp(zXu_7` z&4}N@sus{#HWGREP4(YEHTZj@v|0J>spgJ#m=Oj0L9RHE(z0xdv_B8|nkoLhuiIF0X?$vUkhCn$0-6W@BB!H!$p+#GgG zz#}a3O+Ic?` z#ed8-Ca<{g3n&OUdRrVQy9i|JD*}d`Nd@=PZCHy=o?I&!Wh46fWX??wFTw2Q4j3^> zlU&sc1Ff0+H@*gIX){Smol9h7IaT4~Ts0j0Tl%wLjL#(pqq!zWao%q=C0Ftk_R5@+ zQa^mV*tiyq50-#4iv~)Ze#(F$i>6GTS#74eF9J2zpDgQ)`LJ5*GCDWA0v|L~$6kWP ztL`*09|OW}Yx?t8M7}1%fNjB%07iYplDUqnJ$fvp3A@6o%c4U@aMLv1pXUeQqa5@7 zCFE}fM;?QF`CWe#8Z;EMpEni`Mf?JrI_r~nj1r*d!mZP*X<)G7yVrEqos;3F=`pjk zV5^cKW#WJEYYWVq8bf`5W<1<~9(nOC`^tw;UcYU4M4)saGYDCv3#XtgF>R8<@5ByA zX6gB^yk>QUarf?9qRv`!>W*efVJzDCY` z9x9MQ7rC!>h_yBY!W99HCG7J};T5$uC-Tj z65%&sAZsn&jCpf6kW{Cf>JLc(4k z#`@QHBA_Tpgb3te$1l=nA-Agr-G2o@V}4@k48-~AMq^|M0P$75i2{(%w5-!mQ^#<& zoGHL=AUxQJyS6WlHZE-f0+Q|mOA;Sk?2s^TMwE}EtdsbXdMA)W1Q!&5D1z=YD#))x z2`JKdfo@t)_X~$H7qsJJb3mO!`acdiGc(fxdeFxY3W!>i&oYRKD$FzTEy0N$nE}kE zzg@;>l)s?_Y0ypdYorAj`9c6B_+rjqW*>T=_-!fjMkx(hg5bX`NSLz)RTpayRDk)@ zysG&5=`^rA77T+qMJ^RIsa}g**fM2kH&kQvyvnx4#Q;cm#GL$Wd1{}RthO%j%uvc@n+KZ;Y99FUqRpP zLpSB+lJH}>R)f5ul$Ia%jGx&WREp>r=V%#ee{tjnQCu6#w` zE*k!)i$Bf5grDyG!~qQdSYJj3+CaeQYhUubK8V3-uE1j6Q77>GHp&Vob%J%Qsz>lQ zXp-aZbd0fNh&dV}jqy0wJK?#2@1SpU;#8HW*~2a$pjKW6MJ;={9xJ2b{-T}LZt*bTe26-Bs39_WNJ39 z*_j#Pr{edPKBFe_G)MtMTHm88u-6rwVZrz{ zSa`6=yoeeQfwq95t_F`ST`4ej+M#i$01Ed50cgGESzj2ux4cAcXR2me+;e*(Ehgo< z@e8VCi#*7ZCueZjZil?v1Sp=GS8%+M%fO(sp%z|v2zLI9FrZ?8HNkn+YG-m~%K16J zOBM`EOlQ&d4}l@BmQ@;BTCv<+FSEY;B5wc5HlRZzev)7|$|o!B1b^{AwUTCszlzY9 zf}#z4qTmP=yt0!4?Zp#Iw|nY9w)uTP$NS2=RKJL`4{VmEFNdP(82~KU+#0}a2B9OG|87}#`8^fj9&n9b&p{*K-cJ15%nJDHEwW#A zc&p#^kY~qOM=%ryS_H_HvaM%01kk%B29cLHapP|m9r#sVHdan?Un^-6q^=GVTSW3P znxJBSS{!xpZHw$FW04?A<13aAxByWy#mP1HDu2UfR($R@DrYzHE*Lh#>*=op(-3ke zV1e0t_T;P0;`1jB`=FmzD(xXh`uj$i=M)w`ItQH?y$;jbj095v&a=-|86OtNL})cf zOL|esjscEA>%BG$wD;*zR$6KvD#MlPLkf3_3r=vhsGEV~v#&K08c)U#qNH~x(vy>w z*{??Ay7yYJvToqRCHH@j54`=F@(J{QJ?alS@3!=JcNYYT?x+(rCYWau%CECoU*ntx zp>%_gCw*Xet160FM)@}p-G}D0JgO+49|idQbUg&IKktE3j2}sH_tp(^6$WEEER>H5 zexd%Jl|%l3#dhck2$eEV&v3r*(w~Ak9AA6z(V=-1^Xc8+L~;{0c~p19B%bo2n05y7 zvC!^?Z-cV;M4zr}Gl9enfUevqm4m{@`u_dFJ8=SN-rAX}CZD6VwLQ!MAsh#lChe8S zYub1Y620JW#{af5{mu-M8rAfS-~JK@qk*FN7{k$PT@2FY)F-Uyl;9jU(=F;C%E%Q5 zEMN*LSjzCm+80BMLolX?LwDY4sl{pb?&T3Y_5IiwA%IlMDEpt-z~SW<0qI#_#*`iKz<9YR7sQ z9@MC}4a@zF%&W{&DT+GM^w@Z=Q4XdunLw}h)hEQnzZQHrHy@uG8Z6b_Wi4Pfz3z8g z{Je8-(~#83&a{_KxoMLcoDY*_i$u}7Pa=MTENP7NAr*p^mB;8i&mQ>n&vuhP`q1>( zuU|j7@ZS1DDTLE)Q-VODp>i8{)_P3;&rIp!@a~4UyR)cITG`fheg?u9XA@VR7BdV! z6*U5;F~eVMM4X1OBD4ZQoLXt zz=nqtpS4_{l#>)(uIB%%8wCf+o9{m)W#ZC?xApE8y<%^p697;f-27bt*E@mj>Pgs= zeWL@kLYUGHdDvBe0Y5MZ8c( zb1XDIt4K-W1CPKdb;x}Ezz@6sUd~SKavFgDf?li*&VyV%rR$XWi{FXfu z_=7^pQW*Q zvfLp=KF449i@8U_m$n8WN2ZjQ>e(=hi0-;ajhBdDtvdGPfjns|dPB;|cCC|iV8%AX z*hXhZX6H%m3C#-izb4<4sTBTd z`@|2o^-_>_A#pWSc$kN$8Vfp!v=t$+ZkXW|OGP@V?byZ1<$E$F<+~u(YVr(eDKzT% z_h`NUDUDT~$V^g7h_qX2;&M}*;YU7-vtsaRiM-Q4Sx;6XGn^8Gh;~vV;;{!Bq?`|d z{eNGh5%25Y@ozN`<*8@Pg;F7aJHx%8?4KYdv)_tC@)y?lD2o<-`DVoI!9Q5kw=hnX zRz@6@oe?bo;r`_f2=?OQ=jV{Sy5GL+7`I&SY2TI^O+Puxb9yUe2g ze6n;06En6W1uy+5XHL4FVIgq8o4{1oO`Onvw*Dj?^u7J>LPhJDsP^5yThAf{(s16& z7J?6*BjC_;=aTcpJ{B4r7KnYcrivZgE*V;R|(>{{&MPS(nnB@GSA zKIS?7|Ht#{d5-6}U;Lj}*PA)!IN99|0CBeh z|I8v~sD$KDu zBm@sj?jXQ2>IhjZ*|*oFP@m7vRatx&h*h^+x!TD*=;i6zr5f(idv(9q@HXw9WVyro znwirm?GQ=w7riW&=TsT+aD6hy%TnUj<3psD>-yjB=rf6RjcUk_yRE7J@^XYE zAIr19jrYbqFjFu5f@}Hy^kt0^;EnxdX)n78NEzJg?*&{uJUpLJ!?*Exs0CO)uMN`x zObzhb`3_J(+eEMat;n`pp|Q{X_ST6rMc|n8Col^07i_qe5dqYTa7q}0lhzPk;@}3< zc_y}rvOjs=bJ**9dU}2W*m)g?+X`kFQ4S=h%0kJB!1EU`YX9y82D1PpOH1a_(xbbU zw_tW}6E+#6+##9AZg9cG#ZpmxAlO;E-%ok;C`?&d`HV)xA@AFe4^|4UX-4|k`x2Ng zI4C@3R7MyX0%h(yu)Jt9)tuET_QfylylviOM9c4SohlHiU{#kB#lK&IckR=kX@#a8 zmgeH@(htS!zpPGx!6mCtjaAzq)#oPrZ%swe%YXxb+n{h*$x+U>AIyhzmcW^GLmJsL zTgPl3HVSu8@{nfxeZ7iIGm1YslL)jZrQ3@|QK95vhFE+3F~Q=n zHvjHU)g!FD)|#Hfq#S@>`DyCCyVPOG?euE}ED5`R;CTn#=NjDS3r#aCwIwANU6p#| z^gw^KID#^zRY>q7t~59bM??Zi=55|4Bisp^Ok#xbr87~%TYqSUnHpB2{~mR5Ihwn9 zI%21{^5RoSK2yo=J!yy%(zpaP#zlfPk%YEl1jKd@SfMz?RrF zBP#|cc_4!wn#|*xRx-2t(Gp~v!ZQrsWf`udz%o6Ma%%~w0JG%=YeYh0bE0+tj>T+`b7)`l;u zq`ur`{|3+Xjg3~o)~r>7Px9HdUes&4%hiKP<-NH}dx&*sh#f91%?ei$VaY9@h?!5x zB!K^U4Ij=N(}r3AvHufTOIt#~6gDYgn&HX7ws-ESW9|M~YO z5MhJ0a}u#f?zn_oJbjdsQmhfUTzv)LLOSt)SJelWsp4Ff9&?ph^OtlNhjYZaGmQN| zx9aq#9iau{Qx+lDW01RstgO$)z`z=6T=_el0fRWT58I0Fv*v|oo@T^$tlS9&hU~B3 z$10wmL6D_}42}mDC=6X4?XAV`)-*Wb%b$t8Uq!UHUsW{l;LuWa)-^xAG$&3Ys2_u} zef(Fp$69C&^H>`dueaT)x)BVIhp%48gW9 zrdru|x!dm{BF{jAaeo=(#UX{h(UVbl$>wlPxlF7o_`0_NCEdt!8=y`H`bL~1Zv_45a?&A&ug;?2WVDkw#&fz8>BGl19E~fQcaD|`$vC$W?sncD1-*x7t z3>=#>S*O~Y+6Q9twPxmsBJ+RTcO9Rz&=&vE82;HYU z=InR@7F|OUmah_61Ms{&yiD-&^YBXIbu8(|y$AB{&SSyT_RxEWO@({Vz4`h1go*vr zq|GaRf)l?O@c_G`QLA!j6e+zp^%7JIsl8ZmE?LWTPX_G0gD)FW$@S2J5BnJhVI)_j zM-H*UyYl+++cJXHI%sd06iZ8mF_X|kR(yviCcNP}Ggk^5Q$az2O*5F+bTEZNugM;x!3xmPa=ul3=;2FW$=PDEJ~oPP&b3=r!u>GE4}Dlc*A$|s#MK%XTc z(TSOO?cp$q{i2+U7bJ6#cyN^T&4t_Pw&fp72RBZEx*);V19tsM6xS*I-LFjrLX}X^ z??Pi;gW}3X-~`d725_)T;J1ek@ZeyLEpW&&Z$UK;*q_gNz$m2knNcFvPTXWmc@WIz z*a5Ar>|pr$#uIpK{|nErm$|~-bHW0O#o9DFzeY1A!!L=$QfmarIFs!;*6YnI<&6_D z%Bjw!WU8APk*(yErrL_to(~9!iUStwxrlsU{@12^Rzph`yv1B_Xi+m`PR9BR^tEF+l|pV%0j{{D_MCt}gFbT}N${b$-$fJ#59{jRTg}M>eu# zy|iY{_7MKuZLti36v4nWzVz%f_l|?DJ6#k#i!&wt$Mor8*=&?_op29#WchCgM z4cf{8eeDeJ_h%M$M#KyiV@o=KXJYX?aIFqtv(1c@$S0KDSv3*`l&i=+GOCZc@>6&U z*AEQ0@{Nh zNq(?Q&l=l`WrH481_<2t3@9$0ce_LrDTI*dm&kZ=o6K$;@DY|4`CwzKHD3NE-$wTK zNEhF&mlYMS!o=cM*oN746_t>`>^LmMqjrC<&2?J&*3aCZyt^_HXlZXh{%2*kUOubY z$9>@EHUw1m*hjFf>}Zc>?ay{t_0m``FN z#iJ;t!5%lOK}p80Yo&yS5|N~OC=tD!K07;GtwY}#Z~`3v=izz(oA2{~gwQ5d?z|Zr z2^6?~VnapAOtF@hRdDnA$e>dH!1yMD+TbYHT5vPm?Bl(H8a8~z&;IW2qScRu18d+I z*~P!EV~W|D;FJoH{JRL&FTtF3 zP|6uDB+rePl+xAb7Bbxvp{~y8zp;bs4>qI3_*j)-_^NC4blGTqIKT4T$7T#@h)~4H=>J8OmNBH?nJ- zR&bA_$#E3}%>3dn6v)1xM(g-~Ap+vHJ_x$k1@BeP<^Q;9(AHR3T$`TSTYQ9Vemq;b zgN@46hPD>uiFIv>ISYS%Q$TK}?ujXU5Gf=IKNU4lB_{=U>+LCF#P$1@P{zl~*Z5&I?5&Yeli?-pyfkL&3uGaN~XM;ai7ID;~$ zV|potwMFj3YZhnOBcCdehP#i!97c9^=Z=R9`AL<-up($>S4CJX;p>A1TLJTnH%-6h z>me0j=}gVo8Mc@aZUL)5xsRP>79S2J39@Zf2r1djFm6vV$k(#Aj|xk`6zyg%o!K!& zLUx?twUo!MYlLJjYph;wSvpfoF}1{Z;~9dXBq57=mdJMp)yFR4-Pgf}96%wJP_HUj zk&p1k&$AewX`Rd5e@rboB0TN`L?-@6$xtFBC5r(BV{OsvzcxWAT;wv%nzm;_AMpK> z+B-5v#7uKSZIZC6BZFp>@AHMrXR2;NnbVht4y2vVE1Uwb#T{a{B&EqcUtw(o1f})$ z>{#R}luKF@9E>h_sPiGG@Ualyl|!CjZ-88QhEO5h*uQ81p(#&Bi_z?0F|CcQuJ2I^ z#SGCO^q}0H)ScFli>BNyj(#P=^od^WSX*VX4O=U0KUyy4ijq%6^+mlp3$i7`N;+`w z802x2!mu8NBqr?|YR~gajFw@BC|mv7kQ@tO{G^Yr;-KuXC|sL2EcTx2d3=AX;)gx6 z#r{d&D56VEuX&B-UxX<;@DDs70WBnXdU9yDGGItote0~=;wd=_hhJexV(_zrsZ{Hj zPunY$7yriA09kD?HdcuLs;kjtO#V*MoQOejWXy$)Dpcssz@0qRXaN+m%cQMz1=eD- zcr)TW)x%-xJhxCIMw;DXvGhi0W7Mm^?cDRucIxpEj8R$`X*mcj(}%aC21l*FSXfL= z{gRf951y10j$Liv!xWe1hmEfxO^s1ayg`UaDDadnc3XH{<<&SC%?+Bv6@DDBKvvun zhm9V&k_&JNF{GAKc{8NYuIkdcTEZMk%F3bPinA#yp{7I>#n;NqdHjvUHdCIlF4w|I z2yG0vDTUIIeOuOCAzV2*TE3}J-=qy0UeX!l<(%om60SGMiQ>w4hCmn- zJ*fhn%g4rVHG=rq<3yx{?I#NWZ8`s1J;ueC6D-wKqdA4VXac7IkVsy)jL9+`vT~|;3TF@X&&msB4=|StIp+Q^gc5C$Z6CKZ$xC4 z%R6TI=o$%9DDe?w?FhT0W9^??i`_&dfgg!5R576avd2IoAMFff;z2<_7Y1oDmxw)>;_o3@~YG7Hi?93Ni=H)6J#;kmA7g|7uP6+r{Z5y z?CJ@c?BnJ_*V;LBX}5-cGk5AWV;D}&K|#4?b^6T1TB$v0=mTUv)6m_$zIOHTTPhig zSEG;p{%XS{l->ESCb_{X+3xnl;1lD}2~@=r*B$7kzLXr?3T;h`deOaT! z7?-cvt+1sW1qr2)iQz?qGCkL*|8!=nAMUP)|NjVP{oitRvDW8g)&9?9*8h&wT`sK| zY@t3)kDIN0Nqw5u@}F+A=M|8a>k;7bkD6_Dx>a+UWKE`P5ib-i z6gpw0;3ZRx7d^P(GDmZwNFNp?r-Ng`jz3nDM$jHqv{qe_5mxkJdPihQ)!-_LQSfO| zlA>HtiAF`r=d4)vU@&7!*K`ecEXQ&~+jFrSgno!^95|lsIT#1n_CwdSgTS#u-||8n zhS+y4Q`b;yg0+LS6_o4MA7K(9GM1990$rXes!*vUCHdF?w!FO_{Q2eR=^wajR89^bn6|R?*(i`u@SVxvGocLVAS2@`u##!uMW_3hX8%Q*ACddu09k(@|xvD(X4^n xRz3)8JTl_gFtHJtJBWWM8W;kx83{P30RuT8KmiIe&;ST9=l~0RD-}Yz_6kWmUd#Xh literal 0 HcmV?d00001 diff --git a/jetty-util/src/test/resources/multipart/multipart-encoding-mess.expected.txt b/jetty-util/src/test/resources/multipart/multipart-encoding-mess.expected.txt new file mode 100644 index 00000000000..44148c5505f --- /dev/null +++ b/jetty-util/src/test/resources/multipart/multipart-encoding-mess.expected.txt @@ -0,0 +1,4 @@ +Content-Type|multipart/form-data; boundary="CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl" +Parts-Count|168 +Part-ContainsContents|persian-UTF-8|برج بابل +Part-ContainsContents|persian-CESU-8|برج بابل diff --git a/jetty-util/src/test/resources/multipart/multipart-encoding-mess.raw b/jetty-util/src/test/resources/multipart/multipart-encoding-mess.raw new file mode 100644 index 00000000000..a1348ecccf8 --- /dev/null +++ b/jetty-util/src/test/resources/multipart/multipart-encoding-mess.raw @@ -0,0 +1,1009 @@ +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-Big5" +Content-Type: text/plain; charset=Big5 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-Big5-HKSCS" +Content-Type: text/plain; charset=Big5-HKSCS +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-CESU-8" +Content-Type: text/plain; charset=CESU-8 +Content-Transfer-Encoding: 8bit + +برج بابل +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-EUC-JP" +Content-Type: text/plain; charset=EUC-JP +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-EUC-KR" +Content-Type: text/plain; charset=EUC-KR +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-GB18030" +Content-Type: text/plain; charset=GB18030 +Content-Transfer-Encoding: 8bit + +101914 10191018 +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-GB2312" +Content-Type: text/plain; charset=GB2312 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-GBK" +Content-Type: text/plain; charset=GBK +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-IBM-Thai" +Content-Type: text/plain; charset=IBM-Thai +Content-Transfer-Encoding: 8bit + +???@???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-IBM00858" +Content-Type: text/plain; charset=IBM00858 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-IBM01140" +Content-Type: text/plain; charset=IBM01140 +Content-Transfer-Encoding: 8bit + +???@???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-IBM01141" +Content-Type: text/plain; charset=IBM01141 +Content-Transfer-Encoding: 8bit + +???@???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-IBM01142" +Content-Type: text/plain; charset=IBM01142 +Content-Transfer-Encoding: 8bit + +???@???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-IBM01143" +Content-Type: text/plain; charset=IBM01143 +Content-Transfer-Encoding: 8bit + +???@???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-IBM01144" +Content-Type: text/plain; charset=IBM01144 +Content-Transfer-Encoding: 8bit + +???@???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-IBM01145" +Content-Type: text/plain; charset=IBM01145 +Content-Transfer-Encoding: 8bit + +???@???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-IBM01146" +Content-Type: text/plain; charset=IBM01146 +Content-Transfer-Encoding: 8bit + +???@???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-IBM01147" +Content-Type: text/plain; charset=IBM01147 +Content-Transfer-Encoding: 8bit + +???@???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-IBM01148" +Content-Type: text/plain; charset=IBM01148 +Content-Transfer-Encoding: 8bit + +???@???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-IBM01149" +Content-Type: text/plain; charset=IBM01149 +Content-Transfer-Encoding: 8bit + +???@???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-IBM037" +Content-Type: text/plain; charset=IBM037 +Content-Transfer-Encoding: 8bit + +???@???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-IBM1026" +Content-Type: text/plain; charset=IBM1026 +Content-Transfer-Encoding: 8bit + +???@???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-IBM1047" +Content-Type: text/plain; charset=IBM1047 +Content-Transfer-Encoding: 8bit + +???@???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-IBM273" +Content-Type: text/plain; charset=IBM273 +Content-Transfer-Encoding: 8bit + +???@???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-IBM277" +Content-Type: text/plain; charset=IBM277 +Content-Transfer-Encoding: 8bit + +???@???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-IBM278" +Content-Type: text/plain; charset=IBM278 +Content-Transfer-Encoding: 8bit + +???@???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-IBM280" +Content-Type: text/plain; charset=IBM280 +Content-Transfer-Encoding: 8bit + +???@???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-IBM284" +Content-Type: text/plain; charset=IBM284 +Content-Transfer-Encoding: 8bit + +???@???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-IBM285" +Content-Type: text/plain; charset=IBM285 +Content-Transfer-Encoding: 8bit + +???@???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-IBM290" +Content-Type: text/plain; charset=IBM290 +Content-Transfer-Encoding: 8bit + +???@???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-IBM297" +Content-Type: text/plain; charset=IBM297 +Content-Transfer-Encoding: 8bit + +???@???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-IBM420" +Content-Type: text/plain; charset=IBM420 +Content-Transfer-Encoding: 8bit + +Xug@XVX +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-IBM424" +Content-Type: text/plain; charset=IBM424 +Content-Transfer-Encoding: 8bit + +???@???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-IBM437" +Content-Type: text/plain; charset=IBM437 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-IBM500" +Content-Type: text/plain; charset=IBM500 +Content-Transfer-Encoding: 8bit + +???@???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-IBM775" +Content-Type: text/plain; charset=IBM775 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-IBM850" +Content-Type: text/plain; charset=IBM850 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-IBM852" +Content-Type: text/plain; charset=IBM852 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-IBM855" +Content-Type: text/plain; charset=IBM855 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-IBM857" +Content-Type: text/plain; charset=IBM857 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-IBM860" +Content-Type: text/plain; charset=IBM860 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-IBM861" +Content-Type: text/plain; charset=IBM861 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-IBM862" +Content-Type: text/plain; charset=IBM862 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-IBM863" +Content-Type: text/plain; charset=IBM863 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-IBM864" +Content-Type: text/plain; charset=IBM864 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-IBM865" +Content-Type: text/plain; charset=IBM865 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-IBM866" +Content-Type: text/plain; charset=IBM866 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-IBM868" +Content-Type: text/plain; charset=IBM868 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-IBM869" +Content-Type: text/plain; charset=IBM869 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-IBM870" +Content-Type: text/plain; charset=IBM870 +Content-Transfer-Encoding: 8bit + +???@???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-IBM871" +Content-Type: text/plain; charset=IBM871 +Content-Transfer-Encoding: 8bit + +???@???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-IBM918" +Content-Type: text/plain; charset=IBM918 +Content-Transfer-Encoding: 8bit + +???@???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-ISO-2022-JP" +Content-Type: text/plain; charset=ISO-2022-JP +Content-Transfer-Encoding: 8bit + +$B!)!)!)(B $B!)!)!)!)(B +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-ISO-2022-JP-2" +Content-Type: text/plain; charset=ISO-2022-JP-2 +Content-Transfer-Encoding: 8bit + +$B!)!)!)(B $B!)!)!)!)(B +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-ISO-2022-KR" +Content-Type: text/plain; charset=ISO-2022-KR +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-ISO-8859-1" +Content-Type: text/plain; charset=ISO-8859-1 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-ISO-8859-13" +Content-Type: text/plain; charset=ISO-8859-13 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-ISO-8859-15" +Content-Type: text/plain; charset=ISO-8859-15 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-ISO-8859-2" +Content-Type: text/plain; charset=ISO-8859-2 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-ISO-8859-3" +Content-Type: text/plain; charset=ISO-8859-3 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-ISO-8859-4" +Content-Type: text/plain; charset=ISO-8859-4 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-ISO-8859-5" +Content-Type: text/plain; charset=ISO-8859-5 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-ISO-8859-6" +Content-Type: text/plain; charset=ISO-8859-6 +Content-Transfer-Encoding: 8bit + + +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-ISO-8859-7" +Content-Type: text/plain; charset=ISO-8859-7 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-ISO-8859-8" +Content-Type: text/plain; charset=ISO-8859-8 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-ISO-8859-9" +Content-Type: text/plain; charset=ISO-8859-9 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-JIS_X0201" +Content-Type: text/plain; charset=JIS_X0201 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-JIS_X0212-1990" +Content-Type: text/plain; charset=JIS_X0212-1990 +Content-Transfer-Encoding: 8bit + +"D"D"D"D"D"D"D"D +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-KOI8-R" +Content-Type: text/plain; charset=KOI8-R +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-KOI8-U" +Content-Type: text/plain; charset=KOI8-U +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-Shift_JIS" +Content-Type: text/plain; charset=Shift_JIS +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-TIS-620" +Content-Type: text/plain; charset=TIS-620 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-US-ASCII" +Content-Type: text/plain; charset=US-ASCII +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-UTF-16" +Content-Type: text/plain; charset=UTF-16 +Content-Transfer-Encoding: 8bit + +(1, ('(D +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-UTF-16BE" +Content-Type: text/plain; charset=UTF-16BE +Content-Transfer-Encoding: 8bit + +(1, ('(D +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-UTF-16LE" +Content-Type: text/plain; charset=UTF-16LE +Content-Transfer-Encoding: 8bit + +(1, ('(D +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-UTF-32" +Content-Type: text/plain; charset=UTF-32 +Content-Transfer-Encoding: 8bit + +(1, ('(D +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-UTF-32BE" +Content-Type: text/plain; charset=UTF-32BE +Content-Transfer-Encoding: 8bit + +(1, ('(D +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-UTF-32LE" +Content-Type: text/plain; charset=UTF-32LE +Content-Transfer-Encoding: 8bit + +(1, ('(D +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-UTF-8" +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +برج بابل +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-windows-1250" +Content-Type: text/plain; charset=windows-1250 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-windows-1251" +Content-Type: text/plain; charset=windows-1251 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-windows-1252" +Content-Type: text/plain; charset=windows-1252 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-windows-1253" +Content-Type: text/plain; charset=windows-1253 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-windows-1254" +Content-Type: text/plain; charset=windows-1254 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-windows-1255" +Content-Type: text/plain; charset=windows-1255 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-windows-1256" +Content-Type: text/plain; charset=windows-1256 +Content-Transfer-Encoding: 8bit + + +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-windows-1257" +Content-Type: text/plain; charset=windows-1257 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-windows-1258" +Content-Type: text/plain; charset=windows-1258 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-windows-31j" +Content-Type: text/plain; charset=windows-31j +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-Big5-HKSCS-2001" +Content-Type: text/plain; charset=x-Big5-HKSCS-2001 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-Big5-Solaris" +Content-Type: text/plain; charset=x-Big5-Solaris +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-euc-jp-linux" +Content-Type: text/plain; charset=x-euc-jp-linux +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-EUC-TW" +Content-Type: text/plain; charset=x-EUC-TW +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-eucJP-Open" +Content-Type: text/plain; charset=x-eucJP-Open +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-IBM1006" +Content-Type: text/plain; charset=x-IBM1006 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-IBM1025" +Content-Type: text/plain; charset=x-IBM1025 +Content-Transfer-Encoding: 8bit + +???@???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-IBM1046" +Content-Type: text/plain; charset=x-IBM1046 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-IBM1097" +Content-Type: text/plain; charset=x-IBM1097 +Content-Transfer-Encoding: 8bit + +???@???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-IBM1098" +Content-Type: text/plain; charset=x-IBM1098 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-IBM1112" +Content-Type: text/plain; charset=x-IBM1112 +Content-Transfer-Encoding: 8bit + +???@???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-IBM1122" +Content-Type: text/plain; charset=x-IBM1122 +Content-Transfer-Encoding: 8bit + +???@???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-IBM1123" +Content-Type: text/plain; charset=x-IBM1123 +Content-Transfer-Encoding: 8bit + +???@???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-IBM1124" +Content-Type: text/plain; charset=x-IBM1124 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-IBM1166" +Content-Type: text/plain; charset=x-IBM1166 +Content-Transfer-Encoding: 8bit + +???@???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-IBM1364" +Content-Type: text/plain; charset=x-IBM1364 +Content-Transfer-Encoding: 8bit + +ooo@oooo +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-IBM1381" +Content-Type: text/plain; charset=x-IBM1381 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-IBM1383" +Content-Type: text/plain; charset=x-IBM1383 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-IBM300" +Content-Type: text/plain; charset=x-IBM300 +Content-Transfer-Encoding: 8bit + +BoBoBoBoBoBoBoBo +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-IBM33722" +Content-Type: text/plain; charset=x-IBM33722 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-IBM737" +Content-Type: text/plain; charset=x-IBM737 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-IBM833" +Content-Type: text/plain; charset=x-IBM833 +Content-Transfer-Encoding: 8bit + +???@???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-IBM834" +Content-Type: text/plain; charset=x-IBM834 +Content-Transfer-Encoding: 8bit + + +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-IBM856" +Content-Type: text/plain; charset=x-IBM856 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-IBM874" +Content-Type: text/plain; charset=x-IBM874 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-IBM875" +Content-Type: text/plain; charset=x-IBM875 +Content-Transfer-Encoding: 8bit + +???@???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-IBM921" +Content-Type: text/plain; charset=x-IBM921 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-IBM922" +Content-Type: text/plain; charset=x-IBM922 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-IBM930" +Content-Type: text/plain; charset=x-IBM930 +Content-Transfer-Encoding: 8bit + +ooo@oooo +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-IBM933" +Content-Type: text/plain; charset=x-IBM933 +Content-Transfer-Encoding: 8bit + +ooo@oooo +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-IBM935" +Content-Type: text/plain; charset=x-IBM935 +Content-Transfer-Encoding: 8bit + +ooo@oooo +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-IBM937" +Content-Type: text/plain; charset=x-IBM937 +Content-Transfer-Encoding: 8bit + +ooo@oooo +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-IBM939" +Content-Type: text/plain; charset=x-IBM939 +Content-Transfer-Encoding: 8bit + +ooo@oooo +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-IBM942" +Content-Type: text/plain; charset=x-IBM942 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-IBM942C" +Content-Type: text/plain; charset=x-IBM942C +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-IBM943" +Content-Type: text/plain; charset=x-IBM943 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-IBM943C" +Content-Type: text/plain; charset=x-IBM943C +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-IBM948" +Content-Type: text/plain; charset=x-IBM948 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-IBM949" +Content-Type: text/plain; charset=x-IBM949 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-IBM949C" +Content-Type: text/plain; charset=x-IBM949C +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-IBM950" +Content-Type: text/plain; charset=x-IBM950 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-IBM964" +Content-Type: text/plain; charset=x-IBM964 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-IBM970" +Content-Type: text/plain; charset=x-IBM970 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-ISCII91" +Content-Type: text/plain; charset=x-ISCII91 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-ISO-2022-CN-CNS" +Content-Type: text/plain; charset=x-ISO-2022-CN-CNS +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-ISO-2022-CN-GB" +Content-Type: text/plain; charset=x-ISO-2022-CN-GB +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-iso-8859-11" +Content-Type: text/plain; charset=x-iso-8859-11 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-JIS0208" +Content-Type: text/plain; charset=x-JIS0208 +Content-Transfer-Encoding: 8bit + +!)!)!)!)!)!)!)!) +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-Johab" +Content-Type: text/plain; charset=x-Johab +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-MacArabic" +Content-Type: text/plain; charset=x-MacArabic +Content-Transfer-Encoding: 8bit + + +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-MacCentralEurope" +Content-Type: text/plain; charset=x-MacCentralEurope +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-MacCroatian" +Content-Type: text/plain; charset=x-MacCroatian +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-MacCyrillic" +Content-Type: text/plain; charset=x-MacCyrillic +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-MacDingbat" +Content-Type: text/plain; charset=x-MacDingbat +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-MacGreek" +Content-Type: text/plain; charset=x-MacGreek +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-MacHebrew" +Content-Type: text/plain; charset=x-MacHebrew +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-MacIceland" +Content-Type: text/plain; charset=x-MacIceland +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-MacRoman" +Content-Type: text/plain; charset=x-MacRoman +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-MacRomania" +Content-Type: text/plain; charset=x-MacRomania +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-MacSymbol" +Content-Type: text/plain; charset=x-MacSymbol +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-MacThai" +Content-Type: text/plain; charset=x-MacThai +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-MacTurkish" +Content-Type: text/plain; charset=x-MacTurkish +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-MacUkraine" +Content-Type: text/plain; charset=x-MacUkraine +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-MS932_0213" +Content-Type: text/plain; charset=x-MS932_0213 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-MS950-HKSCS" +Content-Type: text/plain; charset=x-MS950-HKSCS +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-MS950-HKSCS-XP" +Content-Type: text/plain; charset=x-MS950-HKSCS-XP +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-mswin-936" +Content-Type: text/plain; charset=x-mswin-936 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-PCK" +Content-Type: text/plain; charset=x-PCK +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-SJIS_0213" +Content-Type: text/plain; charset=x-SJIS_0213 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-UTF-16LE-BOM" +Content-Type: text/plain; charset=x-UTF-16LE-BOM +Content-Transfer-Encoding: 8bit + +(1, ('(D +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-X-UTF-32BE-BOM" +Content-Type: text/plain; charset=X-UTF-32BE-BOM +Content-Transfer-Encoding: 8bit + +(1, ('(D +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-X-UTF-32LE-BOM" +Content-Type: text/plain; charset=X-UTF-32LE-BOM +Content-Transfer-Encoding: 8bit + +(1, ('(D +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-windows-50220" +Content-Type: text/plain; charset=x-windows-50220 +Content-Transfer-Encoding: 8bit + +$B!)!)!)(B $B!)!)!)!)(B +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-windows-50221" +Content-Type: text/plain; charset=x-windows-50221 +Content-Transfer-Encoding: 8bit + +$B!)!)!)(B $B!)!)!)!)(B +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-windows-874" +Content-Type: text/plain; charset=x-windows-874 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-windows-949" +Content-Type: text/plain; charset=x-windows-949 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-windows-950" +Content-Type: text/plain; charset=x-windows-950 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-windows-iso2022jp" +Content-Type: text/plain; charset=x-windows-iso2022jp +Content-Transfer-Encoding: 8bit + +$B!)!)!)(B $B!)!)!)!)(B +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl-- diff --git a/jetty-util/src/test/resources/multipart/multipart-inside-itself-binary.expected.txt b/jetty-util/src/test/resources/multipart/multipart-inside-itself-binary.expected.txt new file mode 100644 index 00000000000..1074a9a759b --- /dev/null +++ b/jetty-util/src/test/resources/multipart/multipart-inside-itself-binary.expected.txt @@ -0,0 +1,6 @@ +Content-Type|multipart/form-data; boundary="94GJ2MW4vpjh92qj-CHjUUIwb9X8Y2LqkU2Yxn0vTU2oHy5jk6_Kpxn2aE9EokEiRGox4eWfAYP8-" +Parts-Count|4 +Part-ContainsContents|reporter| +Part-ContainsContents|timestamp|2018-03-21T19:00:18+00:00 +Part-ContainsContents|comments|this also couldn't be parsed +Part-ContainsContents|attachment|cherry \ No newline at end of file diff --git a/jetty-util/src/test/resources/multipart/multipart-inside-itself-binary.raw b/jetty-util/src/test/resources/multipart/multipart-inside-itself-binary.raw new file mode 100644 index 00000000000..200235e6d3b --- /dev/null +++ b/jetty-util/src/test/resources/multipart/multipart-inside-itself-binary.raw @@ -0,0 +1,50 @@ +--94GJ2MW4vpjh92qj-CHjUUIwb9X8Y2LqkU2Yxn0vTU2oHy5jk6_Kpxn2aE9EokEiRGox4eWfAYP8- +Content-Disposition: form-data; name="reporter" +Content-Type: text/plain; charset=ISO-8859-1 +Content-Transfer-Encoding: 8bit + + +--94GJ2MW4vpjh92qj-CHjUUIwb9X8Y2LqkU2Yxn0vTU2oHy5jk6_Kpxn2aE9EokEiRGox4eWfAYP8- +Content-Disposition: form-data; name="timestamp" +Content-Type: text/plain; charset=ISO-8859-1 +Content-Transfer-Encoding: 8bit + +2018-03-21T19:00:18+00:00 +--94GJ2MW4vpjh92qj-CHjUUIwb9X8Y2LqkU2Yxn0vTU2oHy5jk6_Kpxn2aE9EokEiRGox4eWfAYP8- +Content-Disposition: form-data; name="comments" +Content-Type: text/plain; charset=ISO-8859-1 +Content-Transfer-Encoding: 8bit + +this also couldn't be parsed +--94GJ2MW4vpjh92qj-CHjUUIwb9X8Y2LqkU2Yxn0vTU2oHy5jk6_Kpxn2aE9EokEiRGox4eWfAYP8- +Content-Disposition: form-data; name="attachment" +Content-Type: application/octet-stream +Content-Transfer-Encoding: binary + +--94GJ2MW4vpjh92qj-CHjUUIwb9X8Y2LqkU2Yxn0v +Content-Disposition: form-data; name="fruit" +Content-Type: text/plain; charset=ISO-8859-1 +Content-Transfer-Encoding: 8bit + +cherry +--94GJ2MW4vpjh92qj-CHjUUIwb9X8Y2LqkU2Yxn0v +Content-Disposition: form-data; name="color" +Content-Type: text/plain; charset=ISO-8859-1 +Content-Transfer-Encoding: 8bit + +red +--94GJ2MW4vpjh92qj-CHjUUIwb9X8Y2LqkU2Yxn0v +Content-Disposition: form-data; name="cost" +Content-Type: text/plain; charset=ISO-8859-1 +Content-Transfer-Encoding: 8bit + +$1.20 USG +--94GJ2MW4vpjh92qj-CHjUUIwb9X8Y2LqkU2Yxn0v +Content-Disposition: form-data; name="comments" +Content-Type: text/plain; charset=ISO-8859-1 +Content-Transfer-Encoding: 8bit + +--94GJ2MW4vpjh92qj-CHjUUIwb9X8Y2LqkU2Yxn0vTU2oHy5jk6_Kpxn2aE9EokEiRGox4eWfAYP8- +--94GJ2MW4vpjh92qj-CHjUUIwb9X8Y2LqkU2Yxn0v-- + +--94GJ2MW4vpjh92qj-CHjUUIwb9X8Y2LqkU2Yxn0vTU2oHy5jk6_Kpxn2aE9EokEiRGox4eWfAYP8--- diff --git a/jetty-util/src/test/resources/multipart/multipart-inside-itself.expected.txt b/jetty-util/src/test/resources/multipart/multipart-inside-itself.expected.txt new file mode 100644 index 00000000000..4f68cd2fa81 --- /dev/null +++ b/jetty-util/src/test/resources/multipart/multipart-inside-itself.expected.txt @@ -0,0 +1,6 @@ +Content-Type|multipart/form-data; boundary="kCFSwstIsIZkZtQ5JM7193kJYcK5WkyvoxsGjx5eCuVFbaeUZ9oK57JCp_p5wP86S5nY4re5x" +Parts-Count|4 +Part-ContainsContents|reporter| +Part-ContainsContents|timestamp|2018-03-21T18:52:18+00:00 +Part-ContainsContents|comments|this couldn't be parsed +Part-ContainsContents|attachment|banana \ No newline at end of file diff --git a/jetty-util/src/test/resources/multipart/multipart-inside-itself.raw b/jetty-util/src/test/resources/multipart/multipart-inside-itself.raw new file mode 100644 index 00000000000..9157af95046 --- /dev/null +++ b/jetty-util/src/test/resources/multipart/multipart-inside-itself.raw @@ -0,0 +1,42 @@ +--kCFSwstIsIZkZtQ5JM7193kJYcK5WkyvoxsGjx5eCuVFbaeUZ9oK57JCp_p5wP86S5nY4re5x +Content-Disposition: form-data; name="reporter" +Content-Type: text/plain; charset=ISO-8859-1 +Content-Transfer-Encoding: 8bit + + +--kCFSwstIsIZkZtQ5JM7193kJYcK5WkyvoxsGjx5eCuVFbaeUZ9oK57JCp_p5wP86S5nY4re5x +Content-Disposition: form-data; name="timestamp" +Content-Type: text/plain; charset=ISO-8859-1 +Content-Transfer-Encoding: 8bit + +2018-03-21T18:52:18+00:00 +--kCFSwstIsIZkZtQ5JM7193kJYcK5WkyvoxsGjx5eCuVFbaeUZ9oK57JCp_p5wP86S5nY4re5x +Content-Disposition: form-data; name="comments" +Content-Type: text/plain; charset=ISO-8859-1 +Content-Transfer-Encoding: 8bit + +this couldn't be parsed +--kCFSwstIsIZkZtQ5JM7193kJYcK5WkyvoxsGjx5eCuVFbaeUZ9oK57JCp_p5wP86S5nY4re5x +Content-Disposition: form-data; name="attachment" +Content-Type: text/plain; charset=ISO-8859-1 +Content-Transfer-Encoding: 8bit + +--kCFSwstIsIZkZtQ5JM7193kJYcK5WkyvoxsGj +Content-Disposition: form-data; name="fruit" + +banana +--kCFSwstIsIZkZtQ5JM7193kJYcK5WkyvoxsGj +Content-Disposition: form-data; name="color" + +yellow +--kCFSwstIsIZkZtQ5JM7193kJYcK5WkyvoxsGj +Content-Disposition: form-data; name="cost" + +$0.12 USG +--kCFSwstIsIZkZtQ5JM7193kJYcK5WkyvoxsGj +Content-Disposition: form-data; name="comments" + +--kCFSwstIsIZkZtQ5JM7193kJYcK5WkyvoxsGjx5eCuVFbaeUZ9oK57JCp_p5wP86S5nY4re5x +--kCFSwstIsIZkZtQ5JM7193kJYcK5WkyvoxsGj-- + +--kCFSwstIsIZkZtQ5JM7193kJYcK5WkyvoxsGjx5eCuVFbaeUZ9oK57JCp_p5wP86S5nY4re5x-- diff --git a/jetty-util/src/test/resources/multipart/multipart-number-browser.expected.txt b/jetty-util/src/test/resources/multipart/multipart-number-browser.expected.txt new file mode 100644 index 00000000000..ebc9f5eea84 --- /dev/null +++ b/jetty-util/src/test/resources/multipart/multipart-number-browser.expected.txt @@ -0,0 +1,3 @@ +Content-Type|multipart/form-data; boundary="RjYiyHVV9Phv7tYylzT1f94fvTC-s7oNKwB9_Y" +Parts-Count|1 +Part-ContainsContents|pi|3.14159265358979323846264338327950288419716939937510 diff --git a/jetty-util/src/test/resources/multipart/multipart-number-browser.raw b/jetty-util/src/test/resources/multipart/multipart-number-browser.raw new file mode 100644 index 00000000000..11776ddfb78 --- /dev/null +++ b/jetty-util/src/test/resources/multipart/multipart-number-browser.raw @@ -0,0 +1,5 @@ +--RjYiyHVV9Phv7tYylzT1f94fvTC-s7oNKwB9_Y +Content-Disposition: form-data; name="pi" + +3.14159265358979323846264338327950288419716939937510 +--RjYiyHVV9Phv7tYylzT1f94fvTC-s7oNKwB9_Y-- diff --git a/jetty-util/src/test/resources/multipart/multipart-number-strict.expected.txt b/jetty-util/src/test/resources/multipart/multipart-number-strict.expected.txt new file mode 100644 index 00000000000..9156fb21e2b --- /dev/null +++ b/jetty-util/src/test/resources/multipart/multipart-number-strict.expected.txt @@ -0,0 +1,3 @@ +Content-Type|multipart/form-data; boundary="P6Uyk-Vikfbk_NqTfVF4DwNXrIxpN451pD1" +Parts-Count|1 +Part-ContainsContents|pi|3.14159265358979323846264338327950288419716939937510 diff --git a/jetty-util/src/test/resources/multipart/multipart-number-strict.raw b/jetty-util/src/test/resources/multipart/multipart-number-strict.raw new file mode 100644 index 00000000000..5c5681665ba --- /dev/null +++ b/jetty-util/src/test/resources/multipart/multipart-number-strict.raw @@ -0,0 +1,7 @@ +--P6Uyk-Vikfbk_NqTfVF4DwNXrIxpN451pD1 +Content-Disposition: form-data; name="pi" +Content-Type: text/plain +Content-Transfer-Encoding: 8bit + +3.14159265358979323846264338327950288419716939937510 +--P6Uyk-Vikfbk_NqTfVF4DwNXrIxpN451pD1-- diff --git a/jetty-util/src/test/resources/multipart/multipart-sjis.expected.txt b/jetty-util/src/test/resources/multipart/multipart-sjis.expected.txt new file mode 100644 index 00000000000..35e678b66df --- /dev/null +++ b/jetty-util/src/test/resources/multipart/multipart-sjis.expected.txt @@ -0,0 +1,4 @@ +Content-Type|multipart/form-data; boundary="VA2isIGmYNkgC3qrrGXnlQcWO17WB3a4npVQey" +Parts-Count|2 +Part-ContainsContents|japanese|健治 +Part-ContainsContents|hello|ャユ戆タ diff --git a/jetty-util/src/test/resources/multipart/multipart-sjis.raw b/jetty-util/src/test/resources/multipart/multipart-sjis.raw new file mode 100644 index 00000000000..59e713a28b0 --- /dev/null +++ b/jetty-util/src/test/resources/multipart/multipart-sjis.raw @@ -0,0 +1,13 @@ +--VA2isIGmYNkgC3qrrGXnlQcWO17WB3a4npVQey +Content-Disposition: form-data; name="japanese" +Content-Type: text/plain; charset=Shift_JIS +Content-Transfer-Encoding: 8bit + + +--VA2isIGmYNkgC3qrrGXnlQcWO17WB3a4npVQey +Content-Disposition: form-data; name="hello" +Content-Type: text/plain; charset=Shift_JIS +Content-Transfer-Encoding: 8bit + +?^ +--VA2isIGmYNkgC3qrrGXnlQcWO17WB3a4npVQey-- diff --git a/jetty-util/src/test/resources/multipart/multipart-strange-quoting.expected.txt b/jetty-util/src/test/resources/multipart/multipart-strange-quoting.expected.txt new file mode 100644 index 00000000000..76408aa202a --- /dev/null +++ b/jetty-util/src/test/resources/multipart/multipart-strange-quoting.expected.txt @@ -0,0 +1,5 @@ +Content-Type|multipart/form-data; boundary="tR61vgdxSzzv2FDycET2lt-OUZ1IW1GqA" +Parts-Count|4 +Part-ContainsContents|and "I" quote|Value 1 +Part-ContainsContents|and+%22I%22+quote|Value 2 +Part-ContainsContents|value"; what="whoa"|Value 3 diff --git a/jetty-util/src/test/resources/multipart/multipart-strange-quoting.raw b/jetty-util/src/test/resources/multipart/multipart-strange-quoting.raw new file mode 100644 index 00000000000..38fa8862abc --- /dev/null +++ b/jetty-util/src/test/resources/multipart/multipart-strange-quoting.raw @@ -0,0 +1,26 @@ +--tR61vgdxSzzv2FDycET2lt-OUZ1IW1GqA +Content-Disposition: form-data; name="and \"I\" quote" +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Value 1 +--tR61vgdxSzzv2FDycET2lt-OUZ1IW1GqA +Content-Disposition: form-data; name="and+%22I%22+quote" +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Value 2 +--tR61vgdxSzzv2FDycET2lt-OUZ1IW1GqA +Content-Disposition: form-data; name="value\"; what=\"whoa\"" +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Value 3 +--tR61vgdxSzzv2FDycET2lt-OUZ1IW1GqA +Content-Disposition: form-data; name="other\"; +what=\"Something\"" +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Value 4 +--tR61vgdxSzzv2FDycET2lt-OUZ1IW1GqA-- diff --git a/jetty-util/src/test/resources/multipart/multipart-text-files.expected.txt b/jetty-util/src/test/resources/multipart/multipart-text-files.expected.txt new file mode 100644 index 00000000000..82fe6e3a904 --- /dev/null +++ b/jetty-util/src/test/resources/multipart/multipart-text-files.expected.txt @@ -0,0 +1,9 @@ +Content-Type|multipart/form-data; boundary="ny9C5eIZL7fsfPY9ONPy8Lxb6tkgEv1" +Parts-Count|3 +Part-ContainsContents|text|text default +Part-ContainsContents|file1|Content of a.txt +Part-ContainsContents|file2|Content of a.html +Part-Filename|file1|a.txt +Part-Filename|file2|a.html +Part-Sha1sum|file1|588A0F273CB5AFE9C8D76DD081812E672F2061E2 +Part-Sha1sum|file2|9A9005159AB90A6D2D9BACB5414EFE932F0CED85 \ No newline at end of file diff --git a/jetty-util/src/test/resources/multipart/multipart-text-files.raw b/jetty-util/src/test/resources/multipart/multipart-text-files.raw new file mode 100644 index 00000000000..c72d60aaea1 --- /dev/null +++ b/jetty-util/src/test/resources/multipart/multipart-text-files.raw @@ -0,0 +1,23 @@ +--ny9C5eIZL7fsfPY9ONPy8Lxb6tkgEv1 +Content-Disposition: form-data; name="text" +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +text default + +--ny9C5eIZL7fsfPY9ONPy8Lxb6tkgEv1 +Content-Type: text/plain; charset=UTF-8 +X-SHA1: 588A0F273CB5AFE9C8D76DD081812E672F2061E2 +Content-Disposition: form-data; name="file1"; filename="a.txt" +Content-Transfer-Encoding: binary + +Content of a.txt + +--ny9C5eIZL7fsfPY9ONPy8Lxb6tkgEv1 +Content-Type: text/html; charset=UTF-8 +X-SHA1: 9A9005159AB90A6D2D9BACB5414EFE932F0CED85 +Content-Disposition: form-data; name="file2"; filename="a.html" +Content-Transfer-Encoding: binary + +<!DOCTYPE html><title>Content of a.html. +--ny9C5eIZL7fsfPY9ONPy8Lxb6tkgEv1-- diff --git a/jetty-util/src/test/resources/multipart/multipart-unicode-names.expected.txt b/jetty-util/src/test/resources/multipart/multipart-unicode-names.expected.txt new file mode 100644 index 00000000000..2c15cb6f6b4 --- /dev/null +++ b/jetty-util/src/test/resources/multipart/multipart-unicode-names.expected.txt @@ -0,0 +1,5 @@ +Content-Type|multipart/form-data; boundary="1R40qTSaEjDJPcArQiccT7vdpp0l02248R" +Parts-Count|2 +Part-ContainsContents|こんにちは世界|Greetings 1 +Part-ContainsContents|%E3%81%93%E3%82%93%E3%81%AB%E3%81%A1%E3%81%AF%E4%B8%96%E7%95%8C|Greetings 2 + diff --git a/jetty-util/src/test/resources/multipart/multipart-unicode-names.raw b/jetty-util/src/test/resources/multipart/multipart-unicode-names.raw new file mode 100644 index 00000000000..5afab43ef54 --- /dev/null +++ b/jetty-util/src/test/resources/multipart/multipart-unicode-names.raw @@ -0,0 +1,13 @@ +--1R40qTSaEjDJPcArQiccT7vdpp0l02248R +Content-Disposition: form-data; name="こんにちは世界" +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Greetings 1 +--1R40qTSaEjDJPcArQiccT7vdpp0l02248R +Content-Disposition: form-data; name="%E3%81%93%E3%82%93%E3%81%AB%E3%81%A1%E3%81%AF%E4%B8%96%E7%95%8C" +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Greetings 2 +--1R40qTSaEjDJPcArQiccT7vdpp0l02248R-- diff --git a/jetty-util/src/test/resources/multipart/multipart-uppercase.expected.txt b/jetty-util/src/test/resources/multipart/multipart-uppercase.expected.txt new file mode 100644 index 00000000000..ef8470f4cc7 --- /dev/null +++ b/jetty-util/src/test/resources/multipart/multipart-uppercase.expected.txt @@ -0,0 +1,5 @@ +Content-Type|multipart/form-data; boundary="8Q4MHJ3LWIQEQQ_OXYU5U9ZLYEH60_CFZQYANCZ" +Parts-Count|2 +Part-ContainsContents|STATE|TEXAS +Part-ContainsContents|CITY|AUSTIN + diff --git a/jetty-util/src/test/resources/multipart/multipart-uppercase.raw b/jetty-util/src/test/resources/multipart/multipart-uppercase.raw new file mode 100644 index 00000000000..3aecb111bc7 --- /dev/null +++ b/jetty-util/src/test/resources/multipart/multipart-uppercase.raw @@ -0,0 +1,13 @@ +--8Q4MHJ3LWIQEQQ_OXYU5U9ZLYEH60_CFZQYANCZ +CONTENT-DISPOSITION: FORM-DATA; NAME="STATE" +CONTENT-TYPE: TEXT/PLAIN; CHARSET=WINDOWS-1252 +CONTENT-TRANSFER-ENCODING: 8BIT + +TEXAS +--8Q4MHJ3LWIQEQQ_OXYU5U9ZLYEH60_CFZQYANCZ +CONTENT-DISPOSITION: FORM-DATA; NAME="CITY" +CONTENT-TYPE: TEXT/PLAIN; CHARSET=WINDOWS-1252 +CONTENT-TRANSFER-ENCODING: 8BIT + +AUSTIN +--8Q4MHJ3LWIQEQQ_OXYU5U9ZLYEH60_CFZQYANCZ-- diff --git a/jetty-util/src/test/resources/multipart/multipart-x-www-form-urlencoded.expected.txt b/jetty-util/src/test/resources/multipart/multipart-x-www-form-urlencoded.expected.txt new file mode 100644 index 00000000000..e1863757719 --- /dev/null +++ b/jetty-util/src/test/resources/multipart/multipart-x-www-form-urlencoded.expected.txt @@ -0,0 +1,5 @@ +Content-Type|multipart/form-data; boundary="qjIkwQOhaYfC2VEcL5j-9sjEK1FIsYMd5" +Parts-Count|1 +Part-ContainsContents|company|bob & frank's shoe repair + + diff --git a/jetty-util/src/test/resources/multipart/multipart-x-www-form-urlencoded.raw b/jetty-util/src/test/resources/multipart/multipart-x-www-form-urlencoded.raw new file mode 100644 index 00000000000..994b267b26c --- /dev/null +++ b/jetty-util/src/test/resources/multipart/multipart-x-www-form-urlencoded.raw @@ -0,0 +1,7 @@ +--qjIkwQOhaYfC2VEcL5j-9sjEK1FIsYMd5 +Content-Disposition: form-data; name="company" +Content-Type: application/x-www-form-urlencoded; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +bob+%26+frank%27s+shoe+repair +--qjIkwQOhaYfC2VEcL5j-9sjEK1FIsYMd5-- diff --git a/jetty-util/src/test/resources/multipart/multipart-zencoding.expected.txt b/jetty-util/src/test/resources/multipart/multipart-zencoding.expected.txt new file mode 100644 index 00000000000..fda05113c8f --- /dev/null +++ b/jetty-util/src/test/resources/multipart/multipart-zencoding.expected.txt @@ -0,0 +1,8 @@ +Content-Type|multipart/form-data; boundary="UuAU1liVuDVE7wfJUYE72PUF9DZafZ" +Parts-Count|4 +Part-ContainsContents|zalgo-8|y͔͕͍o̪̞͎̥͇̤̕u'̛̰̫̳̰v̧̘̪̠̟̟e̥͈̱ ̥̠͇͎͕̜s̤e̺e̙ͅņ̜ ̲̟͝za̴͖̱̲͈̘l͖̖͓̙̮͔g͕̞͖͘o͕̤͈̗ ̯̲̹̲͓b͙͟e̞͎̜̗͈͉̭͞f̸or̰̩e̡̝̺,̸͕̙̥̼͇̜ ̪͇̹r̘̪ͅị͔̥͈ͅg̠̟̯͖̦͇ht͖̪͍͚̖͡?͙̝͖̞ +Part-ContainsContents|zalgo-16|y͔͕͍o̪̞͎̥͇̤̕u'̛̰̫̳̰v̧̘̪̠̟̟e̥͈̱ ̥̠͇͎͕̜s̤e̺e̙ͅņ̜ ̲̟͝za̴͖̱̲͈̘l͖̖͓̙̮͔g͕̞͖͘o͕̤͈̗ ̯̲̹̲͓b͙͟e̞͎̜̗͈͉̭͞f̸or̰̩e̡̝̺,̸͕̙̥̼͇̜ ̪͇̹r̘̪ͅị͔̥͈ͅg̠̟̯͖̦͇ht͖̪͍͚̖͡?͙̝͖̞ +Part-ContainsContents|zalgo-16-be|y͔͕͍o̪̞͎̥͇̤̕u'̛̰̫̳̰v̧̘̪̠̟̟e̥͈̱ ̥̠͇͎͕̜s̤e̺e̙ͅņ̜ ̲̟͝za̴͖̱̲͈̘l͖̖͓̙̮͔g͕̞͖͘o͕̤͈̗ ̯̲̹̲͓b͙͟e̞͎̜̗͈͉̭͞f̸or̰̩e̡̝̺,̸͕̙̥̼͇̜ ̪͇̹r̘̪ͅị͔̥͈ͅg̠̟̯͖̦͇ht͖̪͍͚̖͡?͙̝͖̞ +Part-ContainsContents|zalgo-16-le|y͔͕͍o̪̞͎̥͇̤̕u'̛̰̫̳̰v̧̘̪̠̟̟e̥͈̱ ̥̠͇͎͕̜s̤e̺e̙ͅņ̜ ̲̟͝za̴͖̱̲͈̘l͖̖͓̙̮͔g͕̞͖͘o͕̤͈̗ ̯̲̹̲͓b͙͟e̞͎̜̗͈͉̭͞f̸or̰̩e̡̝̺,̸͕̙̥̼͇̜ ̪͇̹r̘̪ͅị͔̥͈ͅg̠̟̯͖̦͇ht͖̪͍͚̖͡?͙̝͖̞ + + diff --git a/jetty-util/src/test/resources/multipart/multipart-zencoding.raw b/jetty-util/src/test/resources/multipart/multipart-zencoding.raw new file mode 100644 index 0000000000000000000000000000000000000000..74d78b79fb5014723b7ed76f18238d714597fc57 GIT binary patch literal 1830 zcmeH{Pfrt36vbb1c1^leBqEN85|I(BMoQHXl>!`{U zPxi;#&fH9PwRa9!nSpTVs^n#axcpf_^4N`Jkt>dX9yQy5KRaFg5d|D3McDP$H{# zp`?plC|Oy75@|&!+4mPHkx@}r_=-?6TZR%X{H+Q~_9;UNpRP(1IE=ec^4%&ZK`8mx SQGpU2Y8OiUo=VdUhrR=F$o@_M literal 0 HcmV?d00001 From 2004f0eb78cd646a4ee575ef821c534772ed5e52 Mon Sep 17 00:00:00 2001 From: Joakim Erdfelt Date: Thu, 22 Mar 2018 10:21:57 -0500 Subject: [PATCH 25/50] Issue #1027 - Adding jetty-http version of newer MultiPartParsingTest Signed-off-by: Joakim Erdfelt --- .../jetty/http/MultiPartParsingTest.java | 284 +++++ .../multipart-base64-long.expected.txt | 4 + .../multipart/multipart-base64-long.raw | 8 + .../multipart/multipart-base64.expected.txt | 4 + .../resources/multipart/multipart-base64.raw | 389 +++++++ .../multipart/multipart-complex.expected.txt | 9 + .../resources/multipart/multipart-complex.raw | Bin 0 -> 22929 bytes .../multipart-duplicate-names-1.expected.txt | 2 + .../multipart/multipart-duplicate-names-1.raw | Bin 0 -> 1859 bytes .../multipart-encoding-mess.expected.txt | 4 + .../multipart/multipart-encoding-mess.raw | 1009 +++++++++++++++++ ...ultipart-inside-itself-binary.expected.txt | 6 + .../multipart-inside-itself-binary.raw | 50 + .../multipart-inside-itself.expected.txt | 6 + .../multipart/multipart-inside-itself.raw | 42 + .../multipart-number-browser.expected.txt | 3 + .../multipart/multipart-number-browser.raw | 5 + .../multipart-number-strict.expected.txt | 3 + .../multipart/multipart-number-strict.raw | 7 + .../multipart/multipart-sjis.expected.txt | 4 + .../resources/multipart/multipart-sjis.raw | 13 + .../multipart-strange-quoting.expected.txt | 5 + .../multipart/multipart-strange-quoting.raw | 26 + .../multipart-text-files.expected.txt | 9 + .../multipart/multipart-text-files.raw | 23 + .../multipart-unicode-names.expected.txt | 5 + .../multipart/multipart-unicode-names.raw | 13 + .../multipart-uppercase.expected.txt | 5 + .../multipart/multipart-uppercase.raw | 13 + ...ltipart-x-www-form-urlencoded.expected.txt | 5 + .../multipart-x-www-form-urlencoded.raw | 7 + .../multipart-zencoding.expected.txt | 8 + .../multipart/multipart-zencoding.raw | Bin 0 -> 1830 bytes 33 files changed, 1971 insertions(+) create mode 100644 jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParsingTest.java create mode 100644 jetty-http/src/test/resources/multipart/multipart-base64-long.expected.txt create mode 100644 jetty-http/src/test/resources/multipart/multipart-base64-long.raw create mode 100644 jetty-http/src/test/resources/multipart/multipart-base64.expected.txt create mode 100644 jetty-http/src/test/resources/multipart/multipart-base64.raw create mode 100644 jetty-http/src/test/resources/multipart/multipart-complex.expected.txt create mode 100644 jetty-http/src/test/resources/multipart/multipart-complex.raw create mode 100644 jetty-http/src/test/resources/multipart/multipart-duplicate-names-1.expected.txt create mode 100644 jetty-http/src/test/resources/multipart/multipart-duplicate-names-1.raw create mode 100644 jetty-http/src/test/resources/multipart/multipart-encoding-mess.expected.txt create mode 100644 jetty-http/src/test/resources/multipart/multipart-encoding-mess.raw create mode 100644 jetty-http/src/test/resources/multipart/multipart-inside-itself-binary.expected.txt create mode 100644 jetty-http/src/test/resources/multipart/multipart-inside-itself-binary.raw create mode 100644 jetty-http/src/test/resources/multipart/multipart-inside-itself.expected.txt create mode 100644 jetty-http/src/test/resources/multipart/multipart-inside-itself.raw create mode 100644 jetty-http/src/test/resources/multipart/multipart-number-browser.expected.txt create mode 100644 jetty-http/src/test/resources/multipart/multipart-number-browser.raw create mode 100644 jetty-http/src/test/resources/multipart/multipart-number-strict.expected.txt create mode 100644 jetty-http/src/test/resources/multipart/multipart-number-strict.raw create mode 100644 jetty-http/src/test/resources/multipart/multipart-sjis.expected.txt create mode 100644 jetty-http/src/test/resources/multipart/multipart-sjis.raw create mode 100644 jetty-http/src/test/resources/multipart/multipart-strange-quoting.expected.txt create mode 100644 jetty-http/src/test/resources/multipart/multipart-strange-quoting.raw create mode 100644 jetty-http/src/test/resources/multipart/multipart-text-files.expected.txt create mode 100644 jetty-http/src/test/resources/multipart/multipart-text-files.raw create mode 100644 jetty-http/src/test/resources/multipart/multipart-unicode-names.expected.txt create mode 100644 jetty-http/src/test/resources/multipart/multipart-unicode-names.raw create mode 100644 jetty-http/src/test/resources/multipart/multipart-uppercase.expected.txt create mode 100644 jetty-http/src/test/resources/multipart/multipart-uppercase.raw create mode 100644 jetty-http/src/test/resources/multipart/multipart-x-www-form-urlencoded.expected.txt create mode 100644 jetty-http/src/test/resources/multipart/multipart-x-www-form-urlencoded.raw create mode 100644 jetty-http/src/test/resources/multipart/multipart-zencoding.expected.txt create mode 100644 jetty-http/src/test/resources/multipart/multipart-zencoding.raw diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParsingTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParsingTest.java new file mode 100644 index 00000000000..1334824afe0 --- /dev/null +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParsingTest.java @@ -0,0 +1,284 @@ +// +// ======================================================================== +// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http; + +import static java.nio.charset.StandardCharsets.UTF_8; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.junit.Assert.assertThat; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.charset.Charset; +import java.nio.file.Files; +import java.nio.file.Path; +import java.security.DigestOutputStream; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +import javax.servlet.MultipartConfigElement; +import javax.servlet.http.Part; + +import org.eclipse.jetty.toolchain.test.Hex; +import org.eclipse.jetty.toolchain.test.MavenTestingUtils; +import org.eclipse.jetty.toolchain.test.TestingDir; +import org.eclipse.jetty.util.IO; +import org.eclipse.jetty.util.QuotedStringTokenizer; +import org.eclipse.jetty.util.StringUtil; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +@RunWith(Parameterized.class) +public class MultiPartParsingTest +{ + + public static final int MAX_FILE_SIZE = 60 * 1024; + public static final int MAX_REQUEST_SIZE = 1024 * 1024; + public static final int FILE_SIZE_THRESHOLD = 50; + + @Parameterized.Parameters(name = "{0}") + public static List data() + { + List ret = new ArrayList<>(); + + ret.add(new String[]{"multipart-text-files"}); + ret.add(new String[]{"multipart-base64"}); + ret.add(new String[]{"multipart-base64-long"}); + ret.add(new String[]{"multipart-complex"}); + ret.add(new String[]{"multipart-duplicate-names-1"}); + ret.add(new String[]{"multipart-encoding-mess"}); + ret.add(new String[]{"multipart-inside-itself"}); + ret.add(new String[]{"multipart-inside-itself-binary"}); + ret.add(new String[]{"multipart-number-browser"}); + ret.add(new String[]{"multipart-number-strict"}); + ret.add(new String[]{"multipart-sjis"}); + ret.add(new String[]{"multipart-strange-quoting"}); + ret.add(new String[]{"multipart-unicode-names"}); + ret.add(new String[]{"multipart-uppercase"}); + ret.add(new String[]{"multipart-x-www-form-urlencoded"}); + ret.add(new String[]{"multipart-zencoding"}); + + return ret; + } + + @Rule + public TestingDir testingDir = new TestingDir(); + + private final Path multipartRawFile; + private final MultipartExpectations multipartExpectations; + + public MultiPartParsingTest(String rawPrefix) throws IOException + { + multipartRawFile = MavenTestingUtils.getTestResourcePathFile("multipart/" + rawPrefix + ".raw"); + Path expectationPath = MavenTestingUtils.getTestResourcePathFile("multipart/" + rawPrefix + ".expected.txt"); + multipartExpectations = new MultipartExpectations(expectationPath); + } + + @Test + public void testParse() throws IOException, NoSuchAlgorithmException + { + Path outputDir = testingDir.getEmptyPathDir(); + MultipartConfigElement config = newMultipartConfigElement(outputDir); + try (InputStream in = Files.newInputStream(multipartRawFile)) + { + MultiPartInputStreamParser parser = new MultiPartInputStreamParser(in, multipartExpectations.contentType, config, outputDir.toFile()); + parser.parse(); + + // Evaluate Count + if (multipartExpectations.partCount >= 0) + { + assertThat("Mulitpart.parts.size", parser.getParts().size(), is(multipartExpectations.partCount)); + } + + // Evaluate expected Contents + for (NameValue expected : multipartExpectations.partContainsContents) + { + Part part = parser.getPart(expected.name); + assertThat("Part[" + expected.name + "]", part, is(notNullValue())); + try (InputStream partInputStream = part.getInputStream()) + { + String charset = getCharsetFromContentType(part.getContentType(), UTF_8); + String contents = IO.toString(partInputStream, charset); + assertThat("Part[" + expected.name + "].contents", contents, containsString(expected.value)); + } + } + + // Evaluate expected filenames + for (NameValue expected : multipartExpectations.partFilenames) + { + Part part = parser.getPart(expected.name); + assertThat("Part[" + expected.name + "]", part, is(notNullValue())); + assertThat("Part[" + expected.name + "]", part.getSubmittedFileName(), is(expected.value)); + } + + // Evaluate expected contents checksums + for (NameValue expected : multipartExpectations.partSha1sums) + { + Part part = parser.getPart(expected.name); + assertThat("Part[" + expected.name + "]", part, is(notNullValue())); + MessageDigest digest = MessageDigest.getInstance("SHA1"); + try (InputStream partInputStream = part.getInputStream(); + NoOpOutputStream noop = new NoOpOutputStream(); + DigestOutputStream digester = new DigestOutputStream(noop, digest)) + { + IO.copy(partInputStream, digester); + String actualSha1sum = Hex.asHex(digest.digest()); + assertThat("Part[" + expected.name + "].sha1sum", actualSha1sum, containsString(expected.value)); + } + } + } + } + + private MultipartConfigElement newMultipartConfigElement(Path path) + { + return new MultipartConfigElement(path.toString(), MAX_FILE_SIZE, MAX_REQUEST_SIZE, FILE_SIZE_THRESHOLD); + } + + private String getCharsetFromContentType(String contentType, Charset defaultCharset) + { + if(StringUtil.isBlank(contentType)) + { + return defaultCharset.toString(); + } + + QuotedStringTokenizer tok = new QuotedStringTokenizer(contentType, ";", false, false); + while(tok.hasMoreTokens()) + { + String str = tok.nextToken().trim(); + if(str.startsWith("charset=")) + { + return str.substring("charset=".length()); + } + } + + return defaultCharset.toString(); + } + + public static class NameValue + { + public String name; + public String value; + } + + public static class MultipartExpectations + { + public final String contentType; + public final int partCount; + public final List partFilenames = new ArrayList<>(); + public final List partSha1sums = new ArrayList<>(); + public final List partContainsContents = new ArrayList<>(); + + public MultipartExpectations(Path expectationsPath) throws IOException + { + String parsedContentType = null; + String parsedPartCount = "-1"; + + try (BufferedReader reader = Files.newBufferedReader(expectationsPath)) + { + String line; + while ((line = reader.readLine()) != null) + { + line = line.trim(); + if (StringUtil.isBlank(line) || line.startsWith("#")) + { + // skip blanks and comments + continue; + } + + String split[] = line.split("\\|"); + switch (split[0]) + { + case "Content-Type": + parsedContentType = split[1]; + break; + case "Parts-Count": + parsedPartCount = split[1]; + break; + case "Part-ContainsContents": + { + NameValue pair = new NameValue(); + pair.name = split[1]; + pair.value = split[2]; + partContainsContents.add(pair); + break; + } + case "Part-Filename": + { + NameValue pair = new NameValue(); + pair.name = split[1]; + pair.value = split[2]; + partFilenames.add(pair); + break; + } + case "Part-Sha1sum": + { + NameValue pair = new NameValue(); + pair.name = split[1]; + pair.value = split[2]; + partSha1sums.add(pair); + break; + } + default: + throw new IOException("Bad Line in " + expectationsPath + ": " + line); + } + } + } + + Objects.requireNonNull(parsedContentType, "Missing required 'Content-Type' declaration: " + expectationsPath); + this.contentType = parsedContentType; + this.partCount = Integer.parseInt(parsedPartCount); + } + } + + class NoOpOutputStream extends OutputStream + { + @Override + public void write(byte[] b) throws IOException + { + } + + @Override + public void write(byte[] b, int off, int len) throws IOException + { + } + + @Override + public void flush() throws IOException + { + } + + @Override + public void close() throws IOException + { + } + + @Override + public void write(int b) throws IOException + { + } + } +} diff --git a/jetty-http/src/test/resources/multipart/multipart-base64-long.expected.txt b/jetty-http/src/test/resources/multipart/multipart-base64-long.expected.txt new file mode 100644 index 00000000000..2b1d5ded060 --- /dev/null +++ b/jetty-http/src/test/resources/multipart/multipart-base64-long.expected.txt @@ -0,0 +1,4 @@ +Content-Type|multipart/form-data; boundary="JuH4rALGPJfmAquncS_U1du8s59GjKKiG9a8" +Parts-Count|1 +Part-Filename|png|jetty-avatar-256.png +Part-Sha1sum|png|e75b73644afe9b234d70da9ff225229de68cdff8 \ No newline at end of file diff --git a/jetty-http/src/test/resources/multipart/multipart-base64-long.raw b/jetty-http/src/test/resources/multipart/multipart-base64-long.raw new file mode 100644 index 00000000000..2e2b4991568 --- /dev/null +++ b/jetty-http/src/test/resources/multipart/multipart-base64-long.raw @@ -0,0 +1,8 @@ +--JuH4rALGPJfmAquncS_U1du8s59GjKKiG9a8 +Content-ID: +Content-Disposition: form-data; name="png"; filename="jetty-avatar-256.png" +Content-Type: image/png; name=jetty-avatar-256.png +Content-Transfer-Encoding: base64 + +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 +--JuH4rALGPJfmAquncS_U1du8s59GjKKiG9a8-- diff --git a/jetty-http/src/test/resources/multipart/multipart-base64.expected.txt b/jetty-http/src/test/resources/multipart/multipart-base64.expected.txt new file mode 100644 index 00000000000..5d4a189b8dc --- /dev/null +++ b/jetty-http/src/test/resources/multipart/multipart-base64.expected.txt @@ -0,0 +1,4 @@ +Content-Type|multipart/form-data; boundary="8GbcZNTauFWYMt7GeM9BxFMdlNBJ6aLJhGdXp" +Parts-Count|1 +Part-Filename|png|jetty-avatar-256.png +Part-Sha1sum|png|e75b73644afe9b234d70da9ff225229de68cdff8 \ No newline at end of file diff --git a/jetty-http/src/test/resources/multipart/multipart-base64.raw b/jetty-http/src/test/resources/multipart/multipart-base64.raw new file mode 100644 index 00000000000..514a6a1ed3c --- /dev/null +++ b/jetty-http/src/test/resources/multipart/multipart-base64.raw @@ -0,0 +1,389 @@ +--8GbcZNTauFWYMt7GeM9BxFMdlNBJ6aLJhGdXp +Content-ID: +Content-Disposition: form-data; name="png"; filename="jetty-avatar-256.png" +Content-Type: image/png; name=jetty-avatar-256.png +Content-Transfer-Encoding: base64 + +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 +--8GbcZNTauFWYMt7GeM9BxFMdlNBJ6aLJhGdXp-- diff --git a/jetty-http/src/test/resources/multipart/multipart-complex.expected.txt b/jetty-http/src/test/resources/multipart/multipart-complex.expected.txt new file mode 100644 index 00000000000..1eed38785c1 --- /dev/null +++ b/jetty-http/src/test/resources/multipart/multipart-complex.expected.txt @@ -0,0 +1,9 @@ +Content-Type|multipart/form-data; boundary="PMyKOsh8JrSZm-rUF8EJej42yqbh-UWw9FG-" +Parts-Count|6 +Part-ContainsContents|pi|3.14159265358979323846264338327950288419716939937510 +Part-ContainsContents|company|bob & frank's shoe repair +Part-ContainsContents|power|ꬵо𝗋ⲥ𝖾 +Part-ContainsContents|japanese|健治 +Part-ContainsContents|hello|ャユ戆タ +Part-Filename|upload_file|filename +Part-Sha1sum|upload_file|e75b73644afe9b234d70da9ff225229de68cdff8 diff --git a/jetty-http/src/test/resources/multipart/multipart-complex.raw b/jetty-http/src/test/resources/multipart/multipart-complex.raw new file mode 100644 index 0000000000000000000000000000000000000000..e74c27a67daacc6680c483bc89a9952531c1646d GIT binary patch literal 22929 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 literal 0 HcmV?d00001 diff --git a/jetty-http/src/test/resources/multipart/multipart-encoding-mess.expected.txt b/jetty-http/src/test/resources/multipart/multipart-encoding-mess.expected.txt new file mode 100644 index 00000000000..44148c5505f --- /dev/null +++ b/jetty-http/src/test/resources/multipart/multipart-encoding-mess.expected.txt @@ -0,0 +1,4 @@ +Content-Type|multipart/form-data; boundary="CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl" +Parts-Count|168 +Part-ContainsContents|persian-UTF-8|برج بابل +Part-ContainsContents|persian-CESU-8|برج بابل diff --git a/jetty-http/src/test/resources/multipart/multipart-encoding-mess.raw b/jetty-http/src/test/resources/multipart/multipart-encoding-mess.raw new file mode 100644 index 00000000000..a1348ecccf8 --- /dev/null +++ b/jetty-http/src/test/resources/multipart/multipart-encoding-mess.raw @@ -0,0 +1,1009 @@ +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-Big5" +Content-Type: text/plain; charset=Big5 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-Big5-HKSCS" +Content-Type: text/plain; charset=Big5-HKSCS +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-CESU-8" +Content-Type: text/plain; charset=CESU-8 +Content-Transfer-Encoding: 8bit + +برج بابل +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-EUC-JP" +Content-Type: text/plain; charset=EUC-JP +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-EUC-KR" +Content-Type: text/plain; charset=EUC-KR +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-GB18030" +Content-Type: text/plain; charset=GB18030 +Content-Transfer-Encoding: 8bit + +101914 10191018 +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-GB2312" +Content-Type: text/plain; charset=GB2312 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-GBK" +Content-Type: text/plain; charset=GBK +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-IBM-Thai" +Content-Type: text/plain; charset=IBM-Thai +Content-Transfer-Encoding: 8bit + +???@???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-IBM00858" +Content-Type: text/plain; charset=IBM00858 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-IBM01140" +Content-Type: text/plain; charset=IBM01140 +Content-Transfer-Encoding: 8bit + +???@???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-IBM01141" +Content-Type: text/plain; charset=IBM01141 +Content-Transfer-Encoding: 8bit + +???@???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-IBM01142" +Content-Type: text/plain; charset=IBM01142 +Content-Transfer-Encoding: 8bit + +???@???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-IBM01143" +Content-Type: text/plain; charset=IBM01143 +Content-Transfer-Encoding: 8bit + +???@???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-IBM01144" +Content-Type: text/plain; charset=IBM01144 +Content-Transfer-Encoding: 8bit + +???@???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-IBM01145" +Content-Type: text/plain; charset=IBM01145 +Content-Transfer-Encoding: 8bit + +???@???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-IBM01146" +Content-Type: text/plain; charset=IBM01146 +Content-Transfer-Encoding: 8bit + +???@???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-IBM01147" +Content-Type: text/plain; charset=IBM01147 +Content-Transfer-Encoding: 8bit + +???@???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-IBM01148" +Content-Type: text/plain; charset=IBM01148 +Content-Transfer-Encoding: 8bit + +???@???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-IBM01149" +Content-Type: text/plain; charset=IBM01149 +Content-Transfer-Encoding: 8bit + +???@???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-IBM037" +Content-Type: text/plain; charset=IBM037 +Content-Transfer-Encoding: 8bit + +???@???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-IBM1026" +Content-Type: text/plain; charset=IBM1026 +Content-Transfer-Encoding: 8bit + +???@???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-IBM1047" +Content-Type: text/plain; charset=IBM1047 +Content-Transfer-Encoding: 8bit + +???@???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-IBM273" +Content-Type: text/plain; charset=IBM273 +Content-Transfer-Encoding: 8bit + +???@???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-IBM277" +Content-Type: text/plain; charset=IBM277 +Content-Transfer-Encoding: 8bit + +???@???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-IBM278" +Content-Type: text/plain; charset=IBM278 +Content-Transfer-Encoding: 8bit + +???@???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-IBM280" +Content-Type: text/plain; charset=IBM280 +Content-Transfer-Encoding: 8bit + +???@???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-IBM284" +Content-Type: text/plain; charset=IBM284 +Content-Transfer-Encoding: 8bit + +???@???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-IBM285" +Content-Type: text/plain; charset=IBM285 +Content-Transfer-Encoding: 8bit + +???@???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-IBM290" +Content-Type: text/plain; charset=IBM290 +Content-Transfer-Encoding: 8bit + +???@???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-IBM297" +Content-Type: text/plain; charset=IBM297 +Content-Transfer-Encoding: 8bit + +???@???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-IBM420" +Content-Type: text/plain; charset=IBM420 +Content-Transfer-Encoding: 8bit + +Xug@XVX +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-IBM424" +Content-Type: text/plain; charset=IBM424 +Content-Transfer-Encoding: 8bit + +???@???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-IBM437" +Content-Type: text/plain; charset=IBM437 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-IBM500" +Content-Type: text/plain; charset=IBM500 +Content-Transfer-Encoding: 8bit + +???@???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-IBM775" +Content-Type: text/plain; charset=IBM775 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-IBM850" +Content-Type: text/plain; charset=IBM850 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-IBM852" +Content-Type: text/plain; charset=IBM852 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-IBM855" +Content-Type: text/plain; charset=IBM855 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-IBM857" +Content-Type: text/plain; charset=IBM857 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-IBM860" +Content-Type: text/plain; charset=IBM860 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-IBM861" +Content-Type: text/plain; charset=IBM861 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-IBM862" +Content-Type: text/plain; charset=IBM862 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-IBM863" +Content-Type: text/plain; charset=IBM863 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-IBM864" +Content-Type: text/plain; charset=IBM864 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-IBM865" +Content-Type: text/plain; charset=IBM865 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-IBM866" +Content-Type: text/plain; charset=IBM866 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-IBM868" +Content-Type: text/plain; charset=IBM868 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-IBM869" +Content-Type: text/plain; charset=IBM869 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-IBM870" +Content-Type: text/plain; charset=IBM870 +Content-Transfer-Encoding: 8bit + +???@???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-IBM871" +Content-Type: text/plain; charset=IBM871 +Content-Transfer-Encoding: 8bit + +???@???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-IBM918" +Content-Type: text/plain; charset=IBM918 +Content-Transfer-Encoding: 8bit + +???@???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-ISO-2022-JP" +Content-Type: text/plain; charset=ISO-2022-JP +Content-Transfer-Encoding: 8bit + +$B!)!)!)(B $B!)!)!)!)(B +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-ISO-2022-JP-2" +Content-Type: text/plain; charset=ISO-2022-JP-2 +Content-Transfer-Encoding: 8bit + +$B!)!)!)(B $B!)!)!)!)(B +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-ISO-2022-KR" +Content-Type: text/plain; charset=ISO-2022-KR +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-ISO-8859-1" +Content-Type: text/plain; charset=ISO-8859-1 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-ISO-8859-13" +Content-Type: text/plain; charset=ISO-8859-13 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-ISO-8859-15" +Content-Type: text/plain; charset=ISO-8859-15 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-ISO-8859-2" +Content-Type: text/plain; charset=ISO-8859-2 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-ISO-8859-3" +Content-Type: text/plain; charset=ISO-8859-3 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-ISO-8859-4" +Content-Type: text/plain; charset=ISO-8859-4 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-ISO-8859-5" +Content-Type: text/plain; charset=ISO-8859-5 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-ISO-8859-6" +Content-Type: text/plain; charset=ISO-8859-6 +Content-Transfer-Encoding: 8bit + + +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-ISO-8859-7" +Content-Type: text/plain; charset=ISO-8859-7 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-ISO-8859-8" +Content-Type: text/plain; charset=ISO-8859-8 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-ISO-8859-9" +Content-Type: text/plain; charset=ISO-8859-9 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-JIS_X0201" +Content-Type: text/plain; charset=JIS_X0201 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-JIS_X0212-1990" +Content-Type: text/plain; charset=JIS_X0212-1990 +Content-Transfer-Encoding: 8bit + +"D"D"D"D"D"D"D"D +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-KOI8-R" +Content-Type: text/plain; charset=KOI8-R +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-KOI8-U" +Content-Type: text/plain; charset=KOI8-U +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-Shift_JIS" +Content-Type: text/plain; charset=Shift_JIS +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-TIS-620" +Content-Type: text/plain; charset=TIS-620 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-US-ASCII" +Content-Type: text/plain; charset=US-ASCII +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-UTF-16" +Content-Type: text/plain; charset=UTF-16 +Content-Transfer-Encoding: 8bit + +(1, ('(D +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-UTF-16BE" +Content-Type: text/plain; charset=UTF-16BE +Content-Transfer-Encoding: 8bit + +(1, ('(D +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-UTF-16LE" +Content-Type: text/plain; charset=UTF-16LE +Content-Transfer-Encoding: 8bit + +(1, ('(D +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-UTF-32" +Content-Type: text/plain; charset=UTF-32 +Content-Transfer-Encoding: 8bit + +(1, ('(D +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-UTF-32BE" +Content-Type: text/plain; charset=UTF-32BE +Content-Transfer-Encoding: 8bit + +(1, ('(D +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-UTF-32LE" +Content-Type: text/plain; charset=UTF-32LE +Content-Transfer-Encoding: 8bit + +(1, ('(D +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-UTF-8" +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +برج بابل +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-windows-1250" +Content-Type: text/plain; charset=windows-1250 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-windows-1251" +Content-Type: text/plain; charset=windows-1251 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-windows-1252" +Content-Type: text/plain; charset=windows-1252 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-windows-1253" +Content-Type: text/plain; charset=windows-1253 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-windows-1254" +Content-Type: text/plain; charset=windows-1254 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-windows-1255" +Content-Type: text/plain; charset=windows-1255 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-windows-1256" +Content-Type: text/plain; charset=windows-1256 +Content-Transfer-Encoding: 8bit + + +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-windows-1257" +Content-Type: text/plain; charset=windows-1257 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-windows-1258" +Content-Type: text/plain; charset=windows-1258 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-windows-31j" +Content-Type: text/plain; charset=windows-31j +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-Big5-HKSCS-2001" +Content-Type: text/plain; charset=x-Big5-HKSCS-2001 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-Big5-Solaris" +Content-Type: text/plain; charset=x-Big5-Solaris +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-euc-jp-linux" +Content-Type: text/plain; charset=x-euc-jp-linux +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-EUC-TW" +Content-Type: text/plain; charset=x-EUC-TW +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-eucJP-Open" +Content-Type: text/plain; charset=x-eucJP-Open +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-IBM1006" +Content-Type: text/plain; charset=x-IBM1006 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-IBM1025" +Content-Type: text/plain; charset=x-IBM1025 +Content-Transfer-Encoding: 8bit + +???@???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-IBM1046" +Content-Type: text/plain; charset=x-IBM1046 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-IBM1097" +Content-Type: text/plain; charset=x-IBM1097 +Content-Transfer-Encoding: 8bit + +???@???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-IBM1098" +Content-Type: text/plain; charset=x-IBM1098 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-IBM1112" +Content-Type: text/plain; charset=x-IBM1112 +Content-Transfer-Encoding: 8bit + +???@???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-IBM1122" +Content-Type: text/plain; charset=x-IBM1122 +Content-Transfer-Encoding: 8bit + +???@???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-IBM1123" +Content-Type: text/plain; charset=x-IBM1123 +Content-Transfer-Encoding: 8bit + +???@???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-IBM1124" +Content-Type: text/plain; charset=x-IBM1124 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-IBM1166" +Content-Type: text/plain; charset=x-IBM1166 +Content-Transfer-Encoding: 8bit + +???@???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-IBM1364" +Content-Type: text/plain; charset=x-IBM1364 +Content-Transfer-Encoding: 8bit + +ooo@oooo +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-IBM1381" +Content-Type: text/plain; charset=x-IBM1381 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-IBM1383" +Content-Type: text/plain; charset=x-IBM1383 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-IBM300" +Content-Type: text/plain; charset=x-IBM300 +Content-Transfer-Encoding: 8bit + +BoBoBoBoBoBoBoBo +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-IBM33722" +Content-Type: text/plain; charset=x-IBM33722 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-IBM737" +Content-Type: text/plain; charset=x-IBM737 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-IBM833" +Content-Type: text/plain; charset=x-IBM833 +Content-Transfer-Encoding: 8bit + +???@???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-IBM834" +Content-Type: text/plain; charset=x-IBM834 +Content-Transfer-Encoding: 8bit + + +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-IBM856" +Content-Type: text/plain; charset=x-IBM856 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-IBM874" +Content-Type: text/plain; charset=x-IBM874 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-IBM875" +Content-Type: text/plain; charset=x-IBM875 +Content-Transfer-Encoding: 8bit + +???@???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-IBM921" +Content-Type: text/plain; charset=x-IBM921 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-IBM922" +Content-Type: text/plain; charset=x-IBM922 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-IBM930" +Content-Type: text/plain; charset=x-IBM930 +Content-Transfer-Encoding: 8bit + +ooo@oooo +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-IBM933" +Content-Type: text/plain; charset=x-IBM933 +Content-Transfer-Encoding: 8bit + +ooo@oooo +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-IBM935" +Content-Type: text/plain; charset=x-IBM935 +Content-Transfer-Encoding: 8bit + +ooo@oooo +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-IBM937" +Content-Type: text/plain; charset=x-IBM937 +Content-Transfer-Encoding: 8bit + +ooo@oooo +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-IBM939" +Content-Type: text/plain; charset=x-IBM939 +Content-Transfer-Encoding: 8bit + +ooo@oooo +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-IBM942" +Content-Type: text/plain; charset=x-IBM942 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-IBM942C" +Content-Type: text/plain; charset=x-IBM942C +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-IBM943" +Content-Type: text/plain; charset=x-IBM943 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-IBM943C" +Content-Type: text/plain; charset=x-IBM943C +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-IBM948" +Content-Type: text/plain; charset=x-IBM948 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-IBM949" +Content-Type: text/plain; charset=x-IBM949 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-IBM949C" +Content-Type: text/plain; charset=x-IBM949C +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-IBM950" +Content-Type: text/plain; charset=x-IBM950 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-IBM964" +Content-Type: text/plain; charset=x-IBM964 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-IBM970" +Content-Type: text/plain; charset=x-IBM970 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-ISCII91" +Content-Type: text/plain; charset=x-ISCII91 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-ISO-2022-CN-CNS" +Content-Type: text/plain; charset=x-ISO-2022-CN-CNS +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-ISO-2022-CN-GB" +Content-Type: text/plain; charset=x-ISO-2022-CN-GB +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-iso-8859-11" +Content-Type: text/plain; charset=x-iso-8859-11 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-JIS0208" +Content-Type: text/plain; charset=x-JIS0208 +Content-Transfer-Encoding: 8bit + +!)!)!)!)!)!)!)!) +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-Johab" +Content-Type: text/plain; charset=x-Johab +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-MacArabic" +Content-Type: text/plain; charset=x-MacArabic +Content-Transfer-Encoding: 8bit + + +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-MacCentralEurope" +Content-Type: text/plain; charset=x-MacCentralEurope +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-MacCroatian" +Content-Type: text/plain; charset=x-MacCroatian +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-MacCyrillic" +Content-Type: text/plain; charset=x-MacCyrillic +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-MacDingbat" +Content-Type: text/plain; charset=x-MacDingbat +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-MacGreek" +Content-Type: text/plain; charset=x-MacGreek +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-MacHebrew" +Content-Type: text/plain; charset=x-MacHebrew +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-MacIceland" +Content-Type: text/plain; charset=x-MacIceland +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-MacRoman" +Content-Type: text/plain; charset=x-MacRoman +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-MacRomania" +Content-Type: text/plain; charset=x-MacRomania +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-MacSymbol" +Content-Type: text/plain; charset=x-MacSymbol +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-MacThai" +Content-Type: text/plain; charset=x-MacThai +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-MacTurkish" +Content-Type: text/plain; charset=x-MacTurkish +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-MacUkraine" +Content-Type: text/plain; charset=x-MacUkraine +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-MS932_0213" +Content-Type: text/plain; charset=x-MS932_0213 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-MS950-HKSCS" +Content-Type: text/plain; charset=x-MS950-HKSCS +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-MS950-HKSCS-XP" +Content-Type: text/plain; charset=x-MS950-HKSCS-XP +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-mswin-936" +Content-Type: text/plain; charset=x-mswin-936 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-PCK" +Content-Type: text/plain; charset=x-PCK +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-SJIS_0213" +Content-Type: text/plain; charset=x-SJIS_0213 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-UTF-16LE-BOM" +Content-Type: text/plain; charset=x-UTF-16LE-BOM +Content-Transfer-Encoding: 8bit + +(1, ('(D +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-X-UTF-32BE-BOM" +Content-Type: text/plain; charset=X-UTF-32BE-BOM +Content-Transfer-Encoding: 8bit + +(1, ('(D +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-X-UTF-32LE-BOM" +Content-Type: text/plain; charset=X-UTF-32LE-BOM +Content-Transfer-Encoding: 8bit + +(1, ('(D +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-windows-50220" +Content-Type: text/plain; charset=x-windows-50220 +Content-Transfer-Encoding: 8bit + +$B!)!)!)(B $B!)!)!)!)(B +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-windows-50221" +Content-Type: text/plain; charset=x-windows-50221 +Content-Transfer-Encoding: 8bit + +$B!)!)!)(B $B!)!)!)!)(B +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-windows-874" +Content-Type: text/plain; charset=x-windows-874 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-windows-949" +Content-Type: text/plain; charset=x-windows-949 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-windows-950" +Content-Type: text/plain; charset=x-windows-950 +Content-Transfer-Encoding: 8bit + +??? ???? +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +Content-Disposition: form-data; name="persian-x-windows-iso2022jp" +Content-Type: text/plain; charset=x-windows-iso2022jp +Content-Transfer-Encoding: 8bit + +$B!)!)!)(B $B!)!)!)!)(B +--CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl-- diff --git a/jetty-http/src/test/resources/multipart/multipart-inside-itself-binary.expected.txt b/jetty-http/src/test/resources/multipart/multipart-inside-itself-binary.expected.txt new file mode 100644 index 00000000000..1074a9a759b --- /dev/null +++ b/jetty-http/src/test/resources/multipart/multipart-inside-itself-binary.expected.txt @@ -0,0 +1,6 @@ +Content-Type|multipart/form-data; boundary="94GJ2MW4vpjh92qj-CHjUUIwb9X8Y2LqkU2Yxn0vTU2oHy5jk6_Kpxn2aE9EokEiRGox4eWfAYP8-" +Parts-Count|4 +Part-ContainsContents|reporter| +Part-ContainsContents|timestamp|2018-03-21T19:00:18+00:00 +Part-ContainsContents|comments|this also couldn't be parsed +Part-ContainsContents|attachment|cherry \ No newline at end of file diff --git a/jetty-http/src/test/resources/multipart/multipart-inside-itself-binary.raw b/jetty-http/src/test/resources/multipart/multipart-inside-itself-binary.raw new file mode 100644 index 00000000000..200235e6d3b --- /dev/null +++ b/jetty-http/src/test/resources/multipart/multipart-inside-itself-binary.raw @@ -0,0 +1,50 @@ +--94GJ2MW4vpjh92qj-CHjUUIwb9X8Y2LqkU2Yxn0vTU2oHy5jk6_Kpxn2aE9EokEiRGox4eWfAYP8- +Content-Disposition: form-data; name="reporter" +Content-Type: text/plain; charset=ISO-8859-1 +Content-Transfer-Encoding: 8bit + + +--94GJ2MW4vpjh92qj-CHjUUIwb9X8Y2LqkU2Yxn0vTU2oHy5jk6_Kpxn2aE9EokEiRGox4eWfAYP8- +Content-Disposition: form-data; name="timestamp" +Content-Type: text/plain; charset=ISO-8859-1 +Content-Transfer-Encoding: 8bit + +2018-03-21T19:00:18+00:00 +--94GJ2MW4vpjh92qj-CHjUUIwb9X8Y2LqkU2Yxn0vTU2oHy5jk6_Kpxn2aE9EokEiRGox4eWfAYP8- +Content-Disposition: form-data; name="comments" +Content-Type: text/plain; charset=ISO-8859-1 +Content-Transfer-Encoding: 8bit + +this also couldn't be parsed +--94GJ2MW4vpjh92qj-CHjUUIwb9X8Y2LqkU2Yxn0vTU2oHy5jk6_Kpxn2aE9EokEiRGox4eWfAYP8- +Content-Disposition: form-data; name="attachment" +Content-Type: application/octet-stream +Content-Transfer-Encoding: binary + +--94GJ2MW4vpjh92qj-CHjUUIwb9X8Y2LqkU2Yxn0v +Content-Disposition: form-data; name="fruit" +Content-Type: text/plain; charset=ISO-8859-1 +Content-Transfer-Encoding: 8bit + +cherry +--94GJ2MW4vpjh92qj-CHjUUIwb9X8Y2LqkU2Yxn0v +Content-Disposition: form-data; name="color" +Content-Type: text/plain; charset=ISO-8859-1 +Content-Transfer-Encoding: 8bit + +red +--94GJ2MW4vpjh92qj-CHjUUIwb9X8Y2LqkU2Yxn0v +Content-Disposition: form-data; name="cost" +Content-Type: text/plain; charset=ISO-8859-1 +Content-Transfer-Encoding: 8bit + +$1.20 USG +--94GJ2MW4vpjh92qj-CHjUUIwb9X8Y2LqkU2Yxn0v +Content-Disposition: form-data; name="comments" +Content-Type: text/plain; charset=ISO-8859-1 +Content-Transfer-Encoding: 8bit + +--94GJ2MW4vpjh92qj-CHjUUIwb9X8Y2LqkU2Yxn0vTU2oHy5jk6_Kpxn2aE9EokEiRGox4eWfAYP8- +--94GJ2MW4vpjh92qj-CHjUUIwb9X8Y2LqkU2Yxn0v-- + +--94GJ2MW4vpjh92qj-CHjUUIwb9X8Y2LqkU2Yxn0vTU2oHy5jk6_Kpxn2aE9EokEiRGox4eWfAYP8--- diff --git a/jetty-http/src/test/resources/multipart/multipart-inside-itself.expected.txt b/jetty-http/src/test/resources/multipart/multipart-inside-itself.expected.txt new file mode 100644 index 00000000000..4f68cd2fa81 --- /dev/null +++ b/jetty-http/src/test/resources/multipart/multipart-inside-itself.expected.txt @@ -0,0 +1,6 @@ +Content-Type|multipart/form-data; boundary="kCFSwstIsIZkZtQ5JM7193kJYcK5WkyvoxsGjx5eCuVFbaeUZ9oK57JCp_p5wP86S5nY4re5x" +Parts-Count|4 +Part-ContainsContents|reporter| +Part-ContainsContents|timestamp|2018-03-21T18:52:18+00:00 +Part-ContainsContents|comments|this couldn't be parsed +Part-ContainsContents|attachment|banana \ No newline at end of file diff --git a/jetty-http/src/test/resources/multipart/multipart-inside-itself.raw b/jetty-http/src/test/resources/multipart/multipart-inside-itself.raw new file mode 100644 index 00000000000..9157af95046 --- /dev/null +++ b/jetty-http/src/test/resources/multipart/multipart-inside-itself.raw @@ -0,0 +1,42 @@ +--kCFSwstIsIZkZtQ5JM7193kJYcK5WkyvoxsGjx5eCuVFbaeUZ9oK57JCp_p5wP86S5nY4re5x +Content-Disposition: form-data; name="reporter" +Content-Type: text/plain; charset=ISO-8859-1 +Content-Transfer-Encoding: 8bit + + +--kCFSwstIsIZkZtQ5JM7193kJYcK5WkyvoxsGjx5eCuVFbaeUZ9oK57JCp_p5wP86S5nY4re5x +Content-Disposition: form-data; name="timestamp" +Content-Type: text/plain; charset=ISO-8859-1 +Content-Transfer-Encoding: 8bit + +2018-03-21T18:52:18+00:00 +--kCFSwstIsIZkZtQ5JM7193kJYcK5WkyvoxsGjx5eCuVFbaeUZ9oK57JCp_p5wP86S5nY4re5x +Content-Disposition: form-data; name="comments" +Content-Type: text/plain; charset=ISO-8859-1 +Content-Transfer-Encoding: 8bit + +this couldn't be parsed +--kCFSwstIsIZkZtQ5JM7193kJYcK5WkyvoxsGjx5eCuVFbaeUZ9oK57JCp_p5wP86S5nY4re5x +Content-Disposition: form-data; name="attachment" +Content-Type: text/plain; charset=ISO-8859-1 +Content-Transfer-Encoding: 8bit + +--kCFSwstIsIZkZtQ5JM7193kJYcK5WkyvoxsGj +Content-Disposition: form-data; name="fruit" + +banana +--kCFSwstIsIZkZtQ5JM7193kJYcK5WkyvoxsGj +Content-Disposition: form-data; name="color" + +yellow +--kCFSwstIsIZkZtQ5JM7193kJYcK5WkyvoxsGj +Content-Disposition: form-data; name="cost" + +$0.12 USG +--kCFSwstIsIZkZtQ5JM7193kJYcK5WkyvoxsGj +Content-Disposition: form-data; name="comments" + +--kCFSwstIsIZkZtQ5JM7193kJYcK5WkyvoxsGjx5eCuVFbaeUZ9oK57JCp_p5wP86S5nY4re5x +--kCFSwstIsIZkZtQ5JM7193kJYcK5WkyvoxsGj-- + +--kCFSwstIsIZkZtQ5JM7193kJYcK5WkyvoxsGjx5eCuVFbaeUZ9oK57JCp_p5wP86S5nY4re5x-- diff --git a/jetty-http/src/test/resources/multipart/multipart-number-browser.expected.txt b/jetty-http/src/test/resources/multipart/multipart-number-browser.expected.txt new file mode 100644 index 00000000000..ebc9f5eea84 --- /dev/null +++ b/jetty-http/src/test/resources/multipart/multipart-number-browser.expected.txt @@ -0,0 +1,3 @@ +Content-Type|multipart/form-data; boundary="RjYiyHVV9Phv7tYylzT1f94fvTC-s7oNKwB9_Y" +Parts-Count|1 +Part-ContainsContents|pi|3.14159265358979323846264338327950288419716939937510 diff --git a/jetty-http/src/test/resources/multipart/multipart-number-browser.raw b/jetty-http/src/test/resources/multipart/multipart-number-browser.raw new file mode 100644 index 00000000000..11776ddfb78 --- /dev/null +++ b/jetty-http/src/test/resources/multipart/multipart-number-browser.raw @@ -0,0 +1,5 @@ +--RjYiyHVV9Phv7tYylzT1f94fvTC-s7oNKwB9_Y +Content-Disposition: form-data; name="pi" + +3.14159265358979323846264338327950288419716939937510 +--RjYiyHVV9Phv7tYylzT1f94fvTC-s7oNKwB9_Y-- diff --git a/jetty-http/src/test/resources/multipart/multipart-number-strict.expected.txt b/jetty-http/src/test/resources/multipart/multipart-number-strict.expected.txt new file mode 100644 index 00000000000..9156fb21e2b --- /dev/null +++ b/jetty-http/src/test/resources/multipart/multipart-number-strict.expected.txt @@ -0,0 +1,3 @@ +Content-Type|multipart/form-data; boundary="P6Uyk-Vikfbk_NqTfVF4DwNXrIxpN451pD1" +Parts-Count|1 +Part-ContainsContents|pi|3.14159265358979323846264338327950288419716939937510 diff --git a/jetty-http/src/test/resources/multipart/multipart-number-strict.raw b/jetty-http/src/test/resources/multipart/multipart-number-strict.raw new file mode 100644 index 00000000000..5c5681665ba --- /dev/null +++ b/jetty-http/src/test/resources/multipart/multipart-number-strict.raw @@ -0,0 +1,7 @@ +--P6Uyk-Vikfbk_NqTfVF4DwNXrIxpN451pD1 +Content-Disposition: form-data; name="pi" +Content-Type: text/plain +Content-Transfer-Encoding: 8bit + +3.14159265358979323846264338327950288419716939937510 +--P6Uyk-Vikfbk_NqTfVF4DwNXrIxpN451pD1-- diff --git a/jetty-http/src/test/resources/multipart/multipart-sjis.expected.txt b/jetty-http/src/test/resources/multipart/multipart-sjis.expected.txt new file mode 100644 index 00000000000..35e678b66df --- /dev/null +++ b/jetty-http/src/test/resources/multipart/multipart-sjis.expected.txt @@ -0,0 +1,4 @@ +Content-Type|multipart/form-data; boundary="VA2isIGmYNkgC3qrrGXnlQcWO17WB3a4npVQey" +Parts-Count|2 +Part-ContainsContents|japanese|健治 +Part-ContainsContents|hello|ャユ戆タ diff --git a/jetty-http/src/test/resources/multipart/multipart-sjis.raw b/jetty-http/src/test/resources/multipart/multipart-sjis.raw new file mode 100644 index 00000000000..59e713a28b0 --- /dev/null +++ b/jetty-http/src/test/resources/multipart/multipart-sjis.raw @@ -0,0 +1,13 @@ +--VA2isIGmYNkgC3qrrGXnlQcWO17WB3a4npVQey +Content-Disposition: form-data; name="japanese" +Content-Type: text/plain; charset=Shift_JIS +Content-Transfer-Encoding: 8bit + + +--VA2isIGmYNkgC3qrrGXnlQcWO17WB3a4npVQey +Content-Disposition: form-data; name="hello" +Content-Type: text/plain; charset=Shift_JIS +Content-Transfer-Encoding: 8bit + +?^ +--VA2isIGmYNkgC3qrrGXnlQcWO17WB3a4npVQey-- diff --git a/jetty-http/src/test/resources/multipart/multipart-strange-quoting.expected.txt b/jetty-http/src/test/resources/multipart/multipart-strange-quoting.expected.txt new file mode 100644 index 00000000000..76408aa202a --- /dev/null +++ b/jetty-http/src/test/resources/multipart/multipart-strange-quoting.expected.txt @@ -0,0 +1,5 @@ +Content-Type|multipart/form-data; boundary="tR61vgdxSzzv2FDycET2lt-OUZ1IW1GqA" +Parts-Count|4 +Part-ContainsContents|and "I" quote|Value 1 +Part-ContainsContents|and+%22I%22+quote|Value 2 +Part-ContainsContents|value"; what="whoa"|Value 3 diff --git a/jetty-http/src/test/resources/multipart/multipart-strange-quoting.raw b/jetty-http/src/test/resources/multipart/multipart-strange-quoting.raw new file mode 100644 index 00000000000..38fa8862abc --- /dev/null +++ b/jetty-http/src/test/resources/multipart/multipart-strange-quoting.raw @@ -0,0 +1,26 @@ +--tR61vgdxSzzv2FDycET2lt-OUZ1IW1GqA +Content-Disposition: form-data; name="and \"I\" quote" +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Value 1 +--tR61vgdxSzzv2FDycET2lt-OUZ1IW1GqA +Content-Disposition: form-data; name="and+%22I%22+quote" +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Value 2 +--tR61vgdxSzzv2FDycET2lt-OUZ1IW1GqA +Content-Disposition: form-data; name="value\"; what=\"whoa\"" +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Value 3 +--tR61vgdxSzzv2FDycET2lt-OUZ1IW1GqA +Content-Disposition: form-data; name="other\"; +what=\"Something\"" +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Value 4 +--tR61vgdxSzzv2FDycET2lt-OUZ1IW1GqA-- diff --git a/jetty-http/src/test/resources/multipart/multipart-text-files.expected.txt b/jetty-http/src/test/resources/multipart/multipart-text-files.expected.txt new file mode 100644 index 00000000000..82fe6e3a904 --- /dev/null +++ b/jetty-http/src/test/resources/multipart/multipart-text-files.expected.txt @@ -0,0 +1,9 @@ +Content-Type|multipart/form-data; boundary="ny9C5eIZL7fsfPY9ONPy8Lxb6tkgEv1" +Parts-Count|3 +Part-ContainsContents|text|text default +Part-ContainsContents|file1|Content of a.txt +Part-ContainsContents|file2|Content of a.html +Part-Filename|file1|a.txt +Part-Filename|file2|a.html +Part-Sha1sum|file1|588A0F273CB5AFE9C8D76DD081812E672F2061E2 +Part-Sha1sum|file2|9A9005159AB90A6D2D9BACB5414EFE932F0CED85 \ No newline at end of file diff --git a/jetty-http/src/test/resources/multipart/multipart-text-files.raw b/jetty-http/src/test/resources/multipart/multipart-text-files.raw new file mode 100644 index 00000000000..c72d60aaea1 --- /dev/null +++ b/jetty-http/src/test/resources/multipart/multipart-text-files.raw @@ -0,0 +1,23 @@ +--ny9C5eIZL7fsfPY9ONPy8Lxb6tkgEv1 +Content-Disposition: form-data; name="text" +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +text default + +--ny9C5eIZL7fsfPY9ONPy8Lxb6tkgEv1 +Content-Type: text/plain; charset=UTF-8 +X-SHA1: 588A0F273CB5AFE9C8D76DD081812E672F2061E2 +Content-Disposition: form-data; name="file1"; filename="a.txt" +Content-Transfer-Encoding: binary + +Content of a.txt + +--ny9C5eIZL7fsfPY9ONPy8Lxb6tkgEv1 +Content-Type: text/html; charset=UTF-8 +X-SHA1: 9A9005159AB90A6D2D9BACB5414EFE932F0CED85 +Content-Disposition: form-data; name="file2"; filename="a.html" +Content-Transfer-Encoding: binary + +<!DOCTYPE html><title>Content of a.html. +--ny9C5eIZL7fsfPY9ONPy8Lxb6tkgEv1-- diff --git a/jetty-http/src/test/resources/multipart/multipart-unicode-names.expected.txt b/jetty-http/src/test/resources/multipart/multipart-unicode-names.expected.txt new file mode 100644 index 00000000000..2c15cb6f6b4 --- /dev/null +++ b/jetty-http/src/test/resources/multipart/multipart-unicode-names.expected.txt @@ -0,0 +1,5 @@ +Content-Type|multipart/form-data; boundary="1R40qTSaEjDJPcArQiccT7vdpp0l02248R" +Parts-Count|2 +Part-ContainsContents|こんにちは世界|Greetings 1 +Part-ContainsContents|%E3%81%93%E3%82%93%E3%81%AB%E3%81%A1%E3%81%AF%E4%B8%96%E7%95%8C|Greetings 2 + diff --git a/jetty-http/src/test/resources/multipart/multipart-unicode-names.raw b/jetty-http/src/test/resources/multipart/multipart-unicode-names.raw new file mode 100644 index 00000000000..5afab43ef54 --- /dev/null +++ b/jetty-http/src/test/resources/multipart/multipart-unicode-names.raw @@ -0,0 +1,13 @@ +--1R40qTSaEjDJPcArQiccT7vdpp0l02248R +Content-Disposition: form-data; name="こんにちは世界" +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Greetings 1 +--1R40qTSaEjDJPcArQiccT7vdpp0l02248R +Content-Disposition: form-data; name="%E3%81%93%E3%82%93%E3%81%AB%E3%81%A1%E3%81%AF%E4%B8%96%E7%95%8C" +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Greetings 2 +--1R40qTSaEjDJPcArQiccT7vdpp0l02248R-- diff --git a/jetty-http/src/test/resources/multipart/multipart-uppercase.expected.txt b/jetty-http/src/test/resources/multipart/multipart-uppercase.expected.txt new file mode 100644 index 00000000000..ef8470f4cc7 --- /dev/null +++ b/jetty-http/src/test/resources/multipart/multipart-uppercase.expected.txt @@ -0,0 +1,5 @@ +Content-Type|multipart/form-data; boundary="8Q4MHJ3LWIQEQQ_OXYU5U9ZLYEH60_CFZQYANCZ" +Parts-Count|2 +Part-ContainsContents|STATE|TEXAS +Part-ContainsContents|CITY|AUSTIN + diff --git a/jetty-http/src/test/resources/multipart/multipart-uppercase.raw b/jetty-http/src/test/resources/multipart/multipart-uppercase.raw new file mode 100644 index 00000000000..3aecb111bc7 --- /dev/null +++ b/jetty-http/src/test/resources/multipart/multipart-uppercase.raw @@ -0,0 +1,13 @@ +--8Q4MHJ3LWIQEQQ_OXYU5U9ZLYEH60_CFZQYANCZ +CONTENT-DISPOSITION: FORM-DATA; NAME="STATE" +CONTENT-TYPE: TEXT/PLAIN; CHARSET=WINDOWS-1252 +CONTENT-TRANSFER-ENCODING: 8BIT + +TEXAS +--8Q4MHJ3LWIQEQQ_OXYU5U9ZLYEH60_CFZQYANCZ +CONTENT-DISPOSITION: FORM-DATA; NAME="CITY" +CONTENT-TYPE: TEXT/PLAIN; CHARSET=WINDOWS-1252 +CONTENT-TRANSFER-ENCODING: 8BIT + +AUSTIN +--8Q4MHJ3LWIQEQQ_OXYU5U9ZLYEH60_CFZQYANCZ-- diff --git a/jetty-http/src/test/resources/multipart/multipart-x-www-form-urlencoded.expected.txt b/jetty-http/src/test/resources/multipart/multipart-x-www-form-urlencoded.expected.txt new file mode 100644 index 00000000000..e1863757719 --- /dev/null +++ b/jetty-http/src/test/resources/multipart/multipart-x-www-form-urlencoded.expected.txt @@ -0,0 +1,5 @@ +Content-Type|multipart/form-data; boundary="qjIkwQOhaYfC2VEcL5j-9sjEK1FIsYMd5" +Parts-Count|1 +Part-ContainsContents|company|bob & frank's shoe repair + + diff --git a/jetty-http/src/test/resources/multipart/multipart-x-www-form-urlencoded.raw b/jetty-http/src/test/resources/multipart/multipart-x-www-form-urlencoded.raw new file mode 100644 index 00000000000..994b267b26c --- /dev/null +++ b/jetty-http/src/test/resources/multipart/multipart-x-www-form-urlencoded.raw @@ -0,0 +1,7 @@ +--qjIkwQOhaYfC2VEcL5j-9sjEK1FIsYMd5 +Content-Disposition: form-data; name="company" +Content-Type: application/x-www-form-urlencoded; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +bob+%26+frank%27s+shoe+repair +--qjIkwQOhaYfC2VEcL5j-9sjEK1FIsYMd5-- diff --git a/jetty-http/src/test/resources/multipart/multipart-zencoding.expected.txt b/jetty-http/src/test/resources/multipart/multipart-zencoding.expected.txt new file mode 100644 index 00000000000..fda05113c8f --- /dev/null +++ b/jetty-http/src/test/resources/multipart/multipart-zencoding.expected.txt @@ -0,0 +1,8 @@ +Content-Type|multipart/form-data; boundary="UuAU1liVuDVE7wfJUYE72PUF9DZafZ" +Parts-Count|4 +Part-ContainsContents|zalgo-8|y͔͕͍o̪̞͎̥͇̤̕u'̛̰̫̳̰v̧̘̪̠̟̟e̥͈̱ ̥̠͇͎͕̜s̤e̺e̙ͅņ̜ ̲̟͝za̴͖̱̲͈̘l͖̖͓̙̮͔g͕̞͖͘o͕̤͈̗ ̯̲̹̲͓b͙͟e̞͎̜̗͈͉̭͞f̸or̰̩e̡̝̺,̸͕̙̥̼͇̜ ̪͇̹r̘̪ͅị͔̥͈ͅg̠̟̯͖̦͇ht͖̪͍͚̖͡?͙̝͖̞ +Part-ContainsContents|zalgo-16|y͔͕͍o̪̞͎̥͇̤̕u'̛̰̫̳̰v̧̘̪̠̟̟e̥͈̱ ̥̠͇͎͕̜s̤e̺e̙ͅņ̜ ̲̟͝za̴͖̱̲͈̘l͖̖͓̙̮͔g͕̞͖͘o͕̤͈̗ ̯̲̹̲͓b͙͟e̞͎̜̗͈͉̭͞f̸or̰̩e̡̝̺,̸͕̙̥̼͇̜ ̪͇̹r̘̪ͅị͔̥͈ͅg̠̟̯͖̦͇ht͖̪͍͚̖͡?͙̝͖̞ +Part-ContainsContents|zalgo-16-be|y͔͕͍o̪̞͎̥͇̤̕u'̛̰̫̳̰v̧̘̪̠̟̟e̥͈̱ ̥̠͇͎͕̜s̤e̺e̙ͅņ̜ ̲̟͝za̴͖̱̲͈̘l͖̖͓̙̮͔g͕̞͖͘o͕̤͈̗ ̯̲̹̲͓b͙͟e̞͎̜̗͈͉̭͞f̸or̰̩e̡̝̺,̸͕̙̥̼͇̜ ̪͇̹r̘̪ͅị͔̥͈ͅg̠̟̯͖̦͇ht͖̪͍͚̖͡?͙̝͖̞ +Part-ContainsContents|zalgo-16-le|y͔͕͍o̪̞͎̥͇̤̕u'̛̰̫̳̰v̧̘̪̠̟̟e̥͈̱ ̥̠͇͎͕̜s̤e̺e̙ͅņ̜ ̲̟͝za̴͖̱̲͈̘l͖̖͓̙̮͔g͕̞͖͘o͕̤͈̗ ̯̲̹̲͓b͙͟e̞͎̜̗͈͉̭͞f̸or̰̩e̡̝̺,̸͕̙̥̼͇̜ ̪͇̹r̘̪ͅị͔̥͈ͅg̠̟̯͖̦͇ht͖̪͍͚̖͡?͙̝͖̞ + + diff --git a/jetty-http/src/test/resources/multipart/multipart-zencoding.raw b/jetty-http/src/test/resources/multipart/multipart-zencoding.raw new file mode 100644 index 0000000000000000000000000000000000000000..74d78b79fb5014723b7ed76f18238d714597fc57 GIT binary patch literal 1830 zcmeH{Pfrt36vbb1c1^leBqEN85|I(BMoQHXl>!`{U zPxi;#&fH9PwRa9!nSpTVs^n#axcpf_^4N`Jkt>dX9yQy5KRaFg5d|D3McDP$H{# zp`?plC|Oy75@|&!+4mPHkx@}r_=-?6TZR%X{H+Q~_9;UNpRP(1IE=ec^4%&ZK`8mx SQGpU2Y8OiUo=VdUhrR=F$o@_M literal 0 HcmV?d00001 From 9d1809f43e6fb711574b13f5019627b1171461f6 Mon Sep 17 00:00:00 2001 From: Joakim Erdfelt Date: Thu, 22 Mar 2018 13:24:47 -0500 Subject: [PATCH 26/50] Issue #1027 - Adding raw browser multipart captures to jetty-http + Many more decoding issues identified in MultiPartParsingTest + Including Part.getInputStream() related issues Signed-off-by: Joakim Erdfelt --- .../jetty/http/MultiPartParsingTest.java | 60 +++++++++++++++++- ...re-form-fileupload-alt-chrome.expected.txt | 21 ++++++ ...ser-capture-form-fileupload-alt-chrome.raw | Bin 0 -> 22759 bytes ...ture-form-fileupload-alt-edge.expected.txt | 17 +++++ ...owser-capture-form-fileupload-alt-edge.raw | Bin 0 -> 22824 bytes ...e-form-fileupload-alt-firefox.expected.txt | 17 +++++ ...er-capture-form-fileupload-alt-firefox.raw | Bin 0 -> 22774 bytes ...orm-fileupload-alt-ios-safari.expected.txt | 18 ++++++ ...capture-form-fileupload-alt-ios-safari.raw | Bin 0 -> 22359 bytes ...ture-form-fileupload-alt-msie.expected.txt | 17 +++++ ...owser-capture-form-fileupload-alt-msie.raw | Bin 0 -> 22814 bytes ...re-form-fileupload-alt-safari.expected.txt | 18 ++++++ ...ser-capture-form-fileupload-alt-safari.raw | Bin 0 -> 22774 bytes ...orm-fileupload-android-chrome.expected.txt | 17 +++++ ...capture-form-fileupload-android-chrome.raw | Bin 0 -> 22054 bytes ...rm-fileupload-android-firefox.expected.txt | 14 ++++ ...apture-form-fileupload-android-firefox.raw | Bin 0 -> 22105 bytes ...apture-form-fileupload-chrome.expected.txt | 18 ++++++ ...browser-capture-form-fileupload-chrome.raw | Bin 0 -> 22054 bytes ...-capture-form-fileupload-edge.expected.txt | 14 ++++ .../browser-capture-form-fileupload-edge.raw | Bin 0 -> 22085 bytes ...pture-form-fileupload-firefox.expected.txt | 14 ++++ ...rowser-capture-form-fileupload-firefox.raw | Bin 0 -> 22063 bytes ...re-form-fileupload-ios-safari.expected.txt | 15 +++++ ...ser-capture-form-fileupload-ios-safari.raw | Bin 0 -> 22074 bytes ...-capture-form-fileupload-msie.expected.txt | 14 ++++ .../browser-capture-form-fileupload-msie.raw | Bin 0 -> 22082 bytes ...apture-form-fileupload-safari.expected.txt | 15 +++++ ...browser-capture-form-fileupload-safari.raw | Bin 0 -> 22054 bytes ...-capture-form1-android-chrome.expected.txt | 16 +++++ .../browser-capture-form1-android-chrome.raw | 9 +++ ...capture-form1-android-firefox.expected.txt | 13 ++++ .../browser-capture-form1-android-firefox.raw | 9 +++ .../browser-capture-form1-chrome.expected.txt | 17 +++++ .../browser-capture-form1-chrome.raw | 9 +++ .../browser-capture-form1-edge.expected.txt | 13 ++++ .../multipart/browser-capture-form1-edge.raw | 9 +++ ...browser-capture-form1-firefox.expected.txt | 13 ++++ .../browser-capture-form1-firefox.raw | 9 +++ ...wser-capture-form1-ios-safari.expected.txt | 14 ++++ .../browser-capture-form1-ios-safari.raw | 9 +++ .../browser-capture-form1-msie.expected.txt | 13 ++++ .../multipart/browser-capture-form1-msie.raw | 9 +++ ...wser-capture-form1-osx-safari.expected.txt | 14 ++++ .../browser-capture-form1-osx-safari.raw | 9 +++ ...s-charset-form-android-chrome.expected.txt | 17 +++++ ...pture-sjis-charset-form-android-chrome.raw | 13 ++++ ...-charset-form-android-firefox.expected.txt | 14 ++++ ...ture-sjis-charset-form-android-firefox.raw | 13 ++++ ...ture-sjis-charset-form-chrome.expected.txt | 18 ++++++ ...owser-capture-sjis-charset-form-chrome.raw | 13 ++++ ...apture-sjis-charset-form-edge.expected.txt | 14 ++++ ...browser-capture-sjis-charset-form-edge.raw | 13 ++++ ...ure-sjis-charset-form-firefox.expected.txt | 14 ++++ ...wser-capture-sjis-charset-form-firefox.raw | 13 ++++ ...-sjis-charset-form-ios-safari.expected.txt | 15 +++++ ...r-capture-sjis-charset-form-ios-safari.raw | 13 ++++ ...apture-sjis-charset-form-msie.expected.txt | 14 ++++ ...browser-capture-sjis-charset-form-msie.raw | 13 ++++ ...ture-sjis-charset-form-safari.expected.txt | 15 +++++ ...owser-capture-sjis-charset-form-safari.raw | 13 ++++ ...ture-sjis-form-android-chrome.expected.txt | 16 +++++ ...owser-capture-sjis-form-android-chrome.raw | 9 +++ ...ure-sjis-form-android-firefox.expected.txt | 13 ++++ ...wser-capture-sjis-form-android-firefox.raw | 9 +++ ...wser-capture-sjis-form-chrome.expected.txt | 17 +++++ .../browser-capture-sjis-form-chrome.raw | 9 +++ ...rowser-capture-sjis-form-edge.expected.txt | 13 ++++ .../browser-capture-sjis-form-edge.raw | 9 +++ ...ser-capture-sjis-form-firefox.expected.txt | 13 ++++ .../browser-capture-sjis-form-firefox.raw | 9 +++ ...-capture-sjis-form-ios-safari.expected.txt | 14 ++++ .../browser-capture-sjis-form-ios-safari.raw | 9 +++ ...rowser-capture-sjis-form-msie.expected.txt | 13 ++++ .../browser-capture-sjis-form-msie.raw | 9 +++ ...wser-capture-sjis-form-safari.expected.txt | 14 ++++ .../browser-capture-sjis-form-safari.raw | 9 +++ 77 files changed, 883 insertions(+), 1 deletion(-) create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-form-fileupload-alt-chrome.expected.txt create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-form-fileupload-alt-chrome.raw create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-form-fileupload-alt-edge.expected.txt create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-form-fileupload-alt-edge.raw create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-form-fileupload-alt-firefox.expected.txt create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-form-fileupload-alt-firefox.raw create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-form-fileupload-alt-ios-safari.expected.txt create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-form-fileupload-alt-ios-safari.raw create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-form-fileupload-alt-msie.expected.txt create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-form-fileupload-alt-msie.raw create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-form-fileupload-alt-safari.expected.txt create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-form-fileupload-alt-safari.raw create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-form-fileupload-android-chrome.expected.txt create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-form-fileupload-android-chrome.raw create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-form-fileupload-android-firefox.expected.txt create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-form-fileupload-android-firefox.raw create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-form-fileupload-chrome.expected.txt create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-form-fileupload-chrome.raw create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-form-fileupload-edge.expected.txt create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-form-fileupload-edge.raw create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-form-fileupload-firefox.expected.txt create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-form-fileupload-firefox.raw create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-form-fileupload-ios-safari.expected.txt create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-form-fileupload-ios-safari.raw create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-form-fileupload-msie.expected.txt create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-form-fileupload-msie.raw create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-form-fileupload-safari.expected.txt create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-form-fileupload-safari.raw create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-form1-android-chrome.expected.txt create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-form1-android-chrome.raw create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-form1-android-firefox.expected.txt create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-form1-android-firefox.raw create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-form1-chrome.expected.txt create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-form1-chrome.raw create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-form1-edge.expected.txt create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-form1-edge.raw create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-form1-firefox.expected.txt create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-form1-firefox.raw create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-form1-ios-safari.expected.txt create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-form1-ios-safari.raw create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-form1-msie.expected.txt create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-form1-msie.raw create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-form1-osx-safari.expected.txt create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-form1-osx-safari.raw create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-sjis-charset-form-android-chrome.expected.txt create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-sjis-charset-form-android-chrome.raw create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-sjis-charset-form-android-firefox.expected.txt create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-sjis-charset-form-android-firefox.raw create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-sjis-charset-form-chrome.expected.txt create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-sjis-charset-form-chrome.raw create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-sjis-charset-form-edge.expected.txt create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-sjis-charset-form-edge.raw create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-sjis-charset-form-firefox.expected.txt create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-sjis-charset-form-firefox.raw create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-sjis-charset-form-ios-safari.expected.txt create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-sjis-charset-form-ios-safari.raw create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-sjis-charset-form-msie.expected.txt create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-sjis-charset-form-msie.raw create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-sjis-charset-form-safari.expected.txt create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-sjis-charset-form-safari.raw create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-sjis-form-android-chrome.expected.txt create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-sjis-form-android-chrome.raw create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-sjis-form-android-firefox.expected.txt create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-sjis-form-android-firefox.raw create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-sjis-form-chrome.expected.txt create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-sjis-form-chrome.raw create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-sjis-form-edge.expected.txt create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-sjis-form-edge.raw create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-sjis-form-firefox.expected.txt create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-sjis-form-firefox.raw create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-sjis-form-ios-safari.expected.txt create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-sjis-form-ios-safari.raw create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-sjis-form-msie.expected.txt create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-sjis-form-msie.raw create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-sjis-form-safari.expected.txt create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-sjis-form-safari.raw diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParsingTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParsingTest.java index 1334824afe0..c3b71b32a57 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParsingTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParsingTest.java @@ -36,6 +36,7 @@ import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.List; +import java.util.Locale; import java.util.Objects; import javax.servlet.MultipartConfigElement; @@ -65,6 +66,7 @@ public class MultiPartParsingTest { List ret = new ArrayList<>(); + // Capture of raw request body contents from Apache HttpComponents 4.5.5 ret.add(new String[]{"multipart-text-files"}); ret.add(new String[]{"multipart-base64"}); ret.add(new String[]{"multipart-base64-long"}); @@ -82,6 +84,56 @@ public class MultiPartParsingTest ret.add(new String[]{"multipart-x-www-form-urlencoded"}); ret.add(new String[]{"multipart-zencoding"}); + // Capture of raw request body contents from various browsers + + // simple form - 2 fields + ret.add(new String[]{"browser-capture-form1-android-chrome"}); + ret.add(new String[]{"browser-capture-form1-android-firefox"}); + ret.add(new String[]{"browser-capture-form1-chrome"}); + ret.add(new String[]{"browser-capture-form1-edge"}); + ret.add(new String[]{"browser-capture-form1-firefox"}); + ret.add(new String[]{"browser-capture-form1-ios-safari"}); + ret.add(new String[]{"browser-capture-form1-msie"}); + ret.add(new String[]{"browser-capture-form1-osx-safari"}); + + // form submitted as shift-jis + ret.add(new String[]{"browser-capture-sjis-form-android-chrome"}); + ret.add(new String[]{"browser-capture-sjis-form-android-firefox"}); + ret.add(new String[]{"browser-capture-sjis-form-chrome"}); + ret.add(new String[]{"browser-capture-sjis-form-edge"}); + ret.add(new String[]{"browser-capture-sjis-form-firefox"}); + ret.add(new String[]{"browser-capture-sjis-form-ios-safari"}); + ret.add(new String[]{"browser-capture-sjis-form-msie"}); + ret.add(new String[]{"browser-capture-sjis-form-safari"}); + + // form submitted as shift-jis (with HTML5 specific hidden _charset_ field) + ret.add(new String[]{"browser-capture-sjis-charset-form-android-chrome"}); + ret.add(new String[]{"browser-capture-sjis-charset-form-android-firefox"}); + ret.add(new String[]{"browser-capture-sjis-charset-form-chrome"}); + ret.add(new String[]{"browser-capture-sjis-charset-form-edge"}); + ret.add(new String[]{"browser-capture-sjis-charset-form-firefox"}); + ret.add(new String[]{"browser-capture-sjis-charset-form-ios-safari"}); + ret.add(new String[]{"browser-capture-sjis-charset-form-msie"}); + ret.add(new String[]{"browser-capture-sjis-charset-form-safari"}); + + // form submitted with simple file upload + ret.add(new String[]{"browser-capture-form-fileupload-android-chrome"}); + ret.add(new String[]{"browser-capture-form-fileupload-android-firefox"}); + ret.add(new String[]{"browser-capture-form-fileupload-chrome"}); + ret.add(new String[]{"browser-capture-form-fileupload-edge"}); + ret.add(new String[]{"browser-capture-form-fileupload-firefox"}); + ret.add(new String[]{"browser-capture-form-fileupload-ios-safari"}); + ret.add(new String[]{"browser-capture-form-fileupload-msie"}); + ret.add(new String[]{"browser-capture-form-fileupload-safari"}); + + // form submitted with 2 files (1 binary, 1 text) and 2 text fields + ret.add(new String[]{"browser-capture-form-fileupload-alt-chrome"}); + ret.add(new String[]{"browser-capture-form-fileupload-alt-edge"}); + ret.add(new String[]{"browser-capture-form-fileupload-alt-firefox"}); + ret.add(new String[]{"browser-capture-form-fileupload-alt-ios-safari"}); + ret.add(new String[]{"browser-capture-form-fileupload-alt-msie"}); + ret.add(new String[]{"browser-capture-form-fileupload-alt-safari"}); + return ret; } @@ -146,7 +198,7 @@ public class MultiPartParsingTest DigestOutputStream digester = new DigestOutputStream(noop, digest)) { IO.copy(partInputStream, digester); - String actualSha1sum = Hex.asHex(digest.digest()); + String actualSha1sum = Hex.asHex(digest.digest()).toLowerCase(Locale.US); assertThat("Part[" + expected.name + "].sha1sum", actualSha1sum, containsString(expected.value)); } } @@ -212,6 +264,12 @@ public class MultiPartParsingTest String split[] = line.split("\\|"); switch (split[0]) { + case "Request-Header": + if(split[1].equalsIgnoreCase("Content-Type")) + { + parsedContentType = split[2]; + } + break; case "Content-Type": parsedContentType = split[1]; break; diff --git a/jetty-http/src/test/resources/multipart/browser-capture-form-fileupload-alt-chrome.expected.txt b/jetty-http/src/test/resources/multipart/browser-capture-form-fileupload-alt-chrome.expected.txt new file mode 100644 index 00000000000..7b689768bb9 --- /dev/null +++ b/jetty-http/src/test/resources/multipart/browser-capture-form-fileupload-alt-chrome.expected.txt @@ -0,0 +1,21 @@ +Request-Header|Accept|text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8 +Request-Header|Accept-Encoding|gzip, deflate, br +Request-Header|Accept-Language|en-US,en;q=0.9 +Request-Header|Cache-Control|max-age=0 +Request-Header|Connection|keep-alive +Request-Header|Content-Length|22759 +Request-Header|Content-Type|multipart/form-data; boundary=----WebKitFormBoundaryafpkbdzB5Ciqre2z +Request-Header|Cookie|visited=yes +Request-Header|DNT|1 +Request-Header|Host|localhost:9090 +Request-Header|Origin|http://localhost:9090 +Request-Header|Referer|http://localhost:9090/form-fileupload-multi.html +Request-Header|Upgrade-Insecure-Requests|1 +Request-Header|User-Agent|Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.162 Safari/537.36 +Parts-Count|4 +Part-ContainsContents|description|the larger icon +Part-ContainsContents|alternate|text.raw +Part-Filename|file|jetty-avatar-256.png +Part-Sha1sum|file|e75b73644afe9b234d70da9ff225229de68cdff8 +Part-Filename|file-alt|text.raw +Part-Sha1sum|file-alt|5fb031816a27d80cc88c390819addab0ec3c189b diff --git a/jetty-http/src/test/resources/multipart/browser-capture-form-fileupload-alt-chrome.raw b/jetty-http/src/test/resources/multipart/browser-capture-form-fileupload-alt-chrome.raw new file mode 100644 index 0000000000000000000000000000000000000000..cb7809cf0d41fd3d69aefe7a7ba0962d080f6e6e GIT binary patch literal 22759 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�^R73OX67wz+p-s%}PSx19s*u$|V`^<;{Q+-FA4 zV?)Kf+?qlr&RgZ%RTi1V-2$y#hvFYg$;`sWy4Oaw4a(qNOIRxuIC-G*S%7l{Xb_I^taKa?<|(slj*Fz805~ z;^zZ8Z>OdFO50Vcj0I9dZb;x0-!=H2JCDQ+DGpIeO2eg);Dh*bcwUS@kFzLpR{_9r;Kul*TH zLHeGneT&zBE-Ca-iaGeiD7S~d{{l(k{2n)Ja6&QoYXfz30~It9e*H)Jt=i6zCO-sb%EDLFBB>d)%MSffx5M74Xo znb3#qHZ#vjcd|bKTnZ37NZyi!Zi zer%+a`<6&YAEG-hd}RXh+ycy52=E;VK}0C|ZRe>cCj@cJ^R|CNKQUpxmr);#miQc! z-u`!)Z|h!Z@7{`8vXq1VyWQP4vWwN~Ujk_@q&UW zF=bVUy9W^l<`C8PnT44-mVQ!&eERY89a_5SC3Iq26c=wQezw?Lsfv~h^!y9RKT%?? z=-MF~MJ@>$tE)#G4w*Q|s6H?HAT<%Qo`NgU{$Ks&kab((-uZp@#O42G0Yaw3W(vN; zNM9YmwH``+nN&)-?6DVc4G&e~_Li$<{ZA@)#y3TZ{*bsZ#49M?PK_mYzo58aML5q6 zxtJMy9ppsBnM>Tm0lA`5-tV|na&cHyRQ-zvts=fO^UUb7Vw@%Rg#<**469zVJcshi za>(z+5qheik3vTGP6+b-&mv#Efi)h*(!WU*p_b>MxhG4Jh~wH?LBB5I+E(kc@&($6 z&wPaRN2OQi!_~=#Dqw->pit*qr(3no(t$x}9xBYyQ@X_%v{17Q7pCmnI1%y$zjOe& zy9z;(A<5u2bdy0zg^xS=?cIqpf+*9Vp*oJYig3D(oqlt)HEG?kO;i-i!IAw%I~PcQ zq9N{01`$Na(r4H_I!suj&Tz;*VpA&QM~IPPx>lSFa=o(7IhT%-$Emx!yJ0spQogg=$Dq?NCYvWzfvEw=EdM?6r!HE0 zdsHFlvy+3-wn&a^*y*jx9USDx$BhBBVA#M*DZ)^F2%})hE^(SW$F>@`Y1R6k-j0yr zaT|S(Pf<_4t*V1EkxAJVEa-2Kxn{K4Lv{YO3*L1NPX5jD0N!r#XvC%oS&Sq6=1Y&h zRx`%8{xW^z)%59*j@j;F>#1$Kfl7Ok=3Bv60TulXvO0{~id(g^V@ywpFt`0r z+_X>ET@)4#^m8{hHmv${)U9+-%FLKBTO5Dt}@eUs)oQNwp9;7^}4hApvZK;`c1Lms-bJaYuK6T&?1)&k}pTPAId{9*saDNPnKd@77B=2_KI=g>ys}&J^P@C(JMPyp<@7LXR-0Nkjr8*pvbmyZF{tb>hu>`ZWDbFjJC#)W=jQs*Tu zgWSk}B`xA1wrKE018C^o(m-FDH*hYi%8!`pbM86A_KAuMjHy@_SvkQa`8d3Vzkm z*4FOsO1y;)^cyK@Cm0N#gWNz+1T5GNPG^<==#oH^*&PWNK$NW^F=htL+}W*#KH?0q zAJUx~UZwhdgI=KRZ97iZNbx>BaLmigyQ%tdcf9sLDg)V1y9L_0N3K3;7Ao-=r@D)6VSlNxWGOCkb{?%nFK8OL-G3m zWE<9FRR#SQr!mR|SU}^gWmN#!kCe|9w%M4b)1}YT6QG4yUP$@gv9&z(?=Eyxn*zBm zSZ^pm=-6&@nyk^IPZ+4q1jX;@V(0x=W1gVP(ZX@jE_Bir{D-L7@02n=Z=!7r=Hl7x zQO*;G(p-|GDwYkK4ALO$b39J?b1LN4vE26XccI9?SFm;lOwv1kn2Pw~@ZDj>uV=s- z5LUNkrWwmJs8sOv>)&a=J#~r2YQ5OEavU1C_`$D_qBzIjQeX9; z%Z&J!Kth11#<;|cAZ{8ctIK~%N`P4jLqbPOfjpCV7HQ9#%dHMkw%kIQ2`?Jl-l%SH ztUp;RpybE?j?BU553FXs<9yDC*Agde(wsl-JI9QWXwiGE$<~gg+rm~LNjtdKC1Pm) z2f>^lcJt?@#um!eG8R)8rBwpHhY)w~^-NEvDE0}>Y4;mDuZ(!tG4n4Pz=fP}C7d0x zAXE07ZJTL7(m~;4Tv}Y@*TP8QNiExY=9diMX;ej za%j6%y551k9OvgsgcgP{YM?b(Z>euzV!6kvV7_%QuNk{Pg2(#}#+gI*{8-xmRV*Dd zGqbW)L9Bi*zPx{%wn@S3RF-mQgi$@yoF6zjBf%%#J*Wz`~Je#wpXXpBGv_)ja_yKv_ zd!+7@#>i=|2bAJ5&_HN6x^WbSbYCsY{p|pXbAD?iNA0v*Xl&sXRos{LxYSht4Ine0 z!se{GDjN54PO_du`R59Y3@#MN>`5c8^y(fnH6s!p7DOZb&Ijm0j_1ScFqK%?l^$ZP z85el3dDKu=-rEKOa9}}8JZ#Rmy+7$WZBuAi7Wjm+_J=n^&7J>k#?1TgQ2e-#l8#_5 z0V02-DG{Bu{Sn1~p^afXdvJ`>5&^KZF(7+c%2b%L`N)2nB!QFxIEvwgWcDNKRFF#q zPu0N~+y1yi*eBQMp*TSHr7nawg??`B)3yg4CD|Hwc6RXDzpBr-eU3RIETnR(ZbB#Mn$SB9q zzptuw0S6kiU2HH4f7Yn7{2X{%zBa zSb8PnwyvqEkUFmZJ1BTE|C{3gBC_HwV28^reDHsGeKFx3{k4b30TytvjOR>R*%?`j zUw)QaGzESHaMBvCb^XS4*T+wgi3YB8G0s|2C55N0C^NYmp!XcNAEphtX+B{`@#dUB z_{?z!DjLt1@qcmVs;O?zj)2;+NEQ0%Y*hTfCJ1fVUKsRtw?jmWSdDVYQSAoS`+_iD zA2+{}`CA%DyjHDxqfTGB+FRZ}7FAHxXk!KlKPhOk)>Dy$WSX$>`-6y4$M%n}vJd}n zp-k2LmSFe$)JEgX3mUMgY0%>lqCc!)Pbbr2JiEevIP+e)Qd;jcDH{usKD>F2=C77v;mn(aSff%yHDRzvOQF9&XS8IuMGBn+6i^(SQL;?*^gN{*Vl>DD)EDIF_Bk z14!jmWG|I4#_$+U_lI#QNM!Y;NI2dVzt+Zxy1xN5K3qucAet>nbP-_%dPye}T zp5LP9E8_oEBsq^l?`B#fH1_6h$=Z?5Qxxwetzi@_R5#<;_Lraz3Pb_)sB0j&JU9m?(wAkGrpJux4~Xk98Szj?5pl+GnxBruA*vC& zJt6e`=)_aP|72fxElnf0ZRmJV8^z_bl1cQF7q)2)f*KbRiY)N;Ig)`md!$A9{%*1X zjVwM38UELWM(hV5dBU5*4rwJWy4XJjT+YUPGRRm++zPG?w_P79DhA}|L#$XKsM)fK zoF>}g_dz4`-TIM>kdYaEIRj-jH4x5E-#a(p-af%agvd_1^{bnI`SQiv!u(jTO3{WX znvOyd*+bSS_u|pG3B{$>C-7*U5u?rf6fwRfc5G^p#IbGHrx*eCD0eNL6R1mH1;?R? z!Yjp!yoh_}Esi7|#|Bb%JHu^XLY2>IJ-&#Tevf`dWMEzUx2@?eUA!zctHeUG zevxsa4$8X$+s>x7dID4qZLKjb^7pX3O7bwqds2jW1`LlpZt0Ib*SX13Q{X&jq0kXh z;S23i>W0$Jibj`a-yW93W-OD#BAT+Tq1tWk05*JNfD_mS}kG-2bG50_{xgTR?cycd?&M zapquX>~~xS6XVSPBDp~F(hv@rpN7-9Xylv)%v?cU$D^MTur%?+8RT{Z>Ugt>hKl^Z z6pG=gg9;O61&?LB^oT>^%n6Al_2rIehm=0HHN>70D43W&?Ed02FX6fnP(mvsNyzL z@~s|3x>~X7t_{?BZo7l!DN89;q=_TMF+q0<&jLu{bQHIIyVhv^)U zjp9Sg;)U?<7s3eV9hVsjV(Ed5Z*Oia9mjE$6PUu;#WzpP?+A?25!ny-md#yt0R)Jb72kE;34^>e7>LjB^%x zn0sEUUlQ6au|SHTt#s2kEg1NE{~e7ldM|nUia9R+;LJq)EMguh##$O}MD($dhL{0I znAtG-yDLG36y@hvm2sKDEKni;oDwAV(9dfb@qJC+%PBv%z_w8T^gW*$^DEB$*7q?2 zkcS=2EG;u77puPpT^7$9SWWZYvdleY=-zRddJ&S6i=*C=Y*>*MDf~ph9Pl?iXzr1F z_zR>u2p75vM?4g_+1J}Li$9$+R`gIaR=RG>O(|`?kR#E)nmrsf%%qJ1lzfZl0ugpL z>?Rk=qyw$s!X=yqV5S2I2e*!F&apzwjrR?!6f17uTf z-(DQHhk76XG>@l)Tj-q<;hm6wQFmC(;93Kx1egIwGOgux8NhGnkQ78 z^5~>Lfdqtvu49jwDP}*=Bd-TWYs`Lci*k&ON@!2}H~rZDwN~1$$*0)ZIc1Cci}~A9 z4nx+cvx8yliRB!2+yAK$z%D3BlC;yNa=3M_#f-c;4}CBFd>UWA$vc5y8fd1%p}^Tt!^Bhs*X?nwggJ} zV|8_T@R@~7q4RO(ly4E`GdKbdl@jlo<{zjM{N6}iZc%%NseL_8RNhYD8=`qMGtYnS z*SM=SJMNBfC!V@2w8y;a5JmK!16%ik`XF>rqCFn-%Ya69th*fy8a%qSXh7isL=H~M zOE1!Si3=JULN7`FRDnl#;iHa>LiOA6Xw~i3C%+f20Qy;YxP4s>$FV#U%!R4b0C|S0 z{#;E0WhT(hyU-ZXeSsk*m6=~qp8wwKf&hhCD8o<%GUiXryOw6loquruT-hWG)!8Y3 zY_@v}vYVSAVv;JeXb=jlnd=w626s^dRq}V2h=>w~ulK%a5RqOooCGmGmu$TDk|N!4 zm-U!p;RD2T3wnCPu#E!KY7ieR1T%|+3Y~t+gOEjihR~!g$M;WSRW={2zMF~=bTsAl zE>;C8FjR-0g5vf4Fd-KYV7CqHaSSR~8)d{Z<4A^J+~dkvCe|I?m(WI>5i}KW!2`sp z+HQ|>{Yf#7xqf$)E(JyGgSGs&s~!go#jHnlU;Dy;fu_!V|1J9+;JFCub!ZzIt@>=& zAGK$vyK1{n%+0)1i@EFp>xO z40f4`kujPdd!&rGfbgIZw{4u7te)EX`zKz7=I;FGVuwa}v17a)6`Z8!G+Uu;3Z%Fg zOa-{lm_XkaRVZKU39f!Q%{L6enb%B8$Obxv-2XV_#Kc4k@Syi^ z-(&2dQjkB*DUX{TPX*mEuOH+T1=MiV23W<=dHRrcxYpot`Ae*e5l|g*BpKJKBO{5( zFptx@k~O5JU`PQ94;*Mzd4-2r?F2WHu+@9O5{0XstpU7uc+rfXdkWA6uqz~vJwccun}Az(zGGK;7n(rn74cv`*Rs%O_Vai zJyiZ%{0}h6i8ot@xYBPs8l(1gP^+@5HCv}GT<1F^$D^qHNwh}|9;8{XyawCY7|J9* z6N+g9+K3ej-uqn>Di>?8+~XHz2CKECW-XuSLT2RsNo-O21zTR;cXocd4P^C;TB=x@ zrJWltQuFd`F~JZK**r?rws2jOo)&Ff(M~fZ{17= z3S_3`qj=g!|DCH-2Ry@oD~4u(F);yq9YiA*4@~UA+2eon)-R`ls1hP8&X3KSF~6gY zf+aEX2<*Qooy6#8o#}^|lVzas|JoeC5@)<{qMqc?fMm7iTQno?z*HVOEfHscI@A*a zYvfHZ)%F8v4i2K}^uZ^mNp16gr+|+8X2jVn_HFHM$}NK4+5j-0H^G^Kf|y+gsX+tf z^`MHLdjiKAV1rmlXV{BkirN+b&@~yD`zxOi&LpnIKo6)?>cDDIgr4`EhneHf=-sYK z&!9mxV~m-JNh)(oI>%jto&Cs)chSJ+8&~{ObXG=s*rD{bxsRAp5-n=TnAvBq9Q3-p zBLawDgTg~V=Y&@Q1d0Wru3GnXeOVAYZPB`t2S@q>09vDc)ESEGC@Iv~9IG0a_ShIn zjZQwV`-CZ6rwz0c%I@j6+oWxO1{I7=D?47uWgzHmtV0qOOql+33sSQ`8{t1|w0m}D z#{V(5O#y@@#xt3_`ap;ayU4`MeEZ9mr+MdfN!S0$Ho&2gK8QCT6j6|KLO%JwTFJC2 zT25|CN7n>S6zl=PD=P`oojtH}y`~9eSzL$oyw1Fe4DTM<`5*ofqJ*LRSH zP&@zyX8Ym&&$hFV?$_=BKdng4U6K0Fg)+~7>(<^eaAFKv%&ODl%^;-EjzC#lXaEPf z^%OJpNf|F5+6UHqbtbU)Suxf+8t!WSWtx4;R|@hDh}Ib!p#7uIRd=-R5C4ml+Zstr zN_xzDHlWzPjU_0!g2N@(f6#Wn{+#>)c)#v7|5~qNyV~3H0;D!IDeB@aGRT#dd2G&! z4g)dzf#`!y5Z)?}hl1t5hNB#YNbetcq@pap$zpz915%7HRYCju1#-OwVme&( zck_N>{vMUUdO@-6yAPmJ#^DjsCt=n@ki+q@2S z9AUG%V?gwRDoj__GklMX66-V!Oke+!2GKyNT)gq%xjr84a_AkJe@J#roZ%YzFVf@< z5h!5F$preay6Pu=vwaATn|)Va>uAJkcWh^?e)xtgJcH@TeFEd5jcU8!aF>q{4-IIe zay8TcsGU6BgfG~kIk}>@qzFFqB^tx*Hj4TQSke&nO$HP1&bXQSQ^w`=z6 z*RLM}B(Htobhpx8CIy)JqNUV?$bJQjS@GZOFd{PM{nh?9l@so6 zLRc8(5%&C`gevcJF?Z$rAQ+@@u3w+*GnXck^|zN;RXXaNAc)cE;_m{yxf0Nat$^O@moU~0f@k*JtHIcM6 z*_K)#)nsKzp}Sy89Wq|r@FncLQ*@JmJx7d7Rb19VExNNwJ5BHaEH#+fs1FZBUb06+ zy?7Lwla1$CWWb1|b&MMEyYlwOgOF$7Urkz8 z?k;ydV6y%$IgywgEazI3Fkc^Q{9c6ar~sUn$T{rIyuT2U?vxNnv6&JcNBE~j&3_Zx zS@|4=dROySbiJW3M>BmYgaHLz>F)rtf4r>xP9qW3Uqs#AOlI8as{!*HD~QO7P=2*W zb|Q?O2{Re_&glgR_7o5mPG~<_bC3pnZ@;T>sTvN39oKI*lPIxNqSp%f zV7Ll=2+x#8P*;1K*0}iW8W#@vk5gOxe`?&n{i7WO&f2#k%$H@7IZy4MQfuH=ZhK7o zANhyN&eG9?5H}W_pIP3R#$uV=u^=1=G7Bsi=Rfc6!FehaM5+|&HsH`uJCZ14bF|_e z`+}?8M=F-=+TI5xw{X5WwY|W{E}Him;y`ZBCo{%M&d`%tae*+3S$uZe(&A!#B#3EU z4ZJExJC=UFpPR08kr2F~++HBdsEE*7F>0!g-T6E>U!k?i5h`oAY28NI`~TH)=Fw30 ze;>bQkwLO0A&g~k3)w0AAQU0SmR(a>$6A&!n29@t%9^rNj5T|dy~Q5xWUY{-ga&0F z^ZUB*=RUvloaZ^u`TcP}f6aAf=3L+9y1vWj`+2?JUY?#^s*%pU7k5hxf@s$zD(zQS zOdUsQ`$$rN=moKS$LhdatCMkF7UKSQ_mNue%YV3!pMHZy5P=@>HrKPiK;ctUa{=A( zuxbn9-ETrirnD!%Xt%M!`OKG&3}0+-RkQht?K)5RZDthGSkBvdcw6vZS{hCZFj>Kr zgqU8ws;gfI^M~(9m|eR0XaE24sJn^>=sfwmBBJbG3n?Fht{_3UQ487fv^Di#ScsC~ zXL<04(atztXzGz)Xg&W)U)DGQzWAROb~5XLlp#F(R>;lE%li&B97H5SEkN>lX_y9J zYJk_yb$|fcI(GRFMYioK^LQB{3)l~lF%@s5~Q4}izFt3&zw7_^{W#I%mR@tEm;T44sKic z!)#wBtuw~BL(+HM;DX8XWunAju(Ni*ar@4l2xVnudG*G9-nX#;tQ6eSjP$YBr7#_E zP;F%?Cx015ye{i0zd2U(kbFdx!cf@d-eXyu-f z=r^_6gF27~5Ag%f0aUZo30}mN#3MwI0{|I?-$DV*7L{o3FFgYoGG{*^fk+p&?Rre| z1Bcjs$!GF0M>RsI@At9W7{XrZEt<`@)tYjeVdBx5WRQze3YssD2`?XJh_}-l6D)~n z3+V1tJ;2ImrQtbD$p!e8p9c2T`3?gf$Dd1JN!b34$T#Rd+vq-5WRg{_B_T2IqSPac z1^vi3nbKDK8Qna~Uwy*NdHn`Z?XmNTC^Sc+^@cpyY{UVtkpuuKo!_Wug90y5qG{pCpWz_~OV!ErF$ zTZKZVqtm*(yDhS!U(N-*%K;&%mo_*^;ZaajEY-c-X>2@G@qBrr21rsQ2u&-mTN^(t zQ~L520vbJ6*VbAATeDINUdacSdQs2l&KLJ4m3L;(?;uv4AP%^c6f0asge9+XB5v+> z775(v8GJZvObcoO#QqN;Eo}({Q`n@qNv2;nfQ_?-G{cm7^>bhYfG6-Y91hj~5dwIc z;0#&Edax(q{w@^0Sk+%{U+1>76DmsAXH}CF2l)M$tshbJogqV^h}y8#&)qL>9Xt8Q zI!MBXYUL*54qSDPG{1l6_U#h&;DuUOfD36S0$x=QNTy2iRC>%*KAAnHJKLWo&&o6Q z|JZn{H|+p@A>U^~yBvbt)n#OS&IJe8Q4=a(X%FZpsJ+=#bpK>lB!53MzGLZXI1pri z{5DqgP##e(Ii!C$xKLr};%IL@Zo970ky!aa?DaCDz5Sx1KAuxk)k(+f@Yh)kjdbb| zl;h)9?>@52xInt+HF9rVSk1Y0^Lk5-+cDxOTayj;LQ{rAfUzz}0rt8!S9K#t-eik# zbI+)vMPVQN&Oe*Jwy0^alx)M34vi_BQ4L0Wkj}3bGnk{wUa&hj<=dst%IAW|egx?) zE!ze%IERfd(Hqy^sH^6+@7iDhK{csq=y;qnGLWJC^9_phqGrF#~*2z0!`+5xs6wieNsQm6RftY}!p;gyO0Z7w@#Q8B^8bw2vtd#ucW-F0Xeu<4I> zPc2I$(M1IE7xzzxjT)8PTN7R?bj8qL)Yi#=8`6M zPf*rf`vfO`G7aKrL^8zW8v++Y2MP ztMR$yM(^s&hl8XAYqi^Lp+)qm z%*EcUO~sY_+I&yoQ#14GMG-aM>{%nZ=iJFCE0WW%(5eCQQ=tsG4LFsL{MGfH_86eg zQjqM)SwyYj2=U$G+;e9oa*;%El=Rt|$1%v_x37Cwj)S-$$rlg1d@qLkIPu!Yrb2Wz z6!NRcNJqb)Opnhxa8r}3~w%IeH08E1fhA&X>YX2B8B^isF|f2cfpUWJ<}B;wW|qq5 z6LHFEPG#j(H&ZfO>2VFUCCeQjU=Wo6B-XQ01-{3gne12&eKqGR;f6!=8kw`wRv(~` z^*vz{2Xl zTDFXr<|oq~L;z1)JOk1rQYmqJ737E-`S&x=yGA@(e16YA)V0!SKb*l~c+Y{Znm78f z=Xa;?=tw4|bB3vB=Q3c%r0lh=SlXHdD#+KOJp0p?m)kjsZ0#0~xgPzP7;qpP1aPk? zZRt;sljZDduT({W%sC+$2sKoP$sn48mekD<;QA1^L2s%qzMZ#t?1$5E_C$qY6SFq^*t0>k#0{0;N;`mNV*VRYtq$OFObwOFk0`sdswWF5*Od22tKQ`< zxXoL%x@WLaV3ewPI<<&9<0b}|8jKM=)K)<4R99-9%8fl`ts)Ke@cD^`tfp+wf~mcy z0q8{~j)7(RlaY;B4(MTJfWU3efZ)<;yGt~AkrWpD7@3H%&gv!r9bs9q4=%n|{qe8z zAY^ZkRLQjl8Bt7)P&{FYZJ0wxQ3?6emeU*)v;Avjw$swLVdloC>lLZTi-LBjEVo56=a7ye{}2Mw?i= z`eJM(Sm5%JH5DaO#d=zHp~vNsL8bnI@pS~X(LuJg&?D0H?e)SsHe%I}{_gJL<+nux zE8rN}eo(xyWUv?2HeeTbb`#$@=ChE=E7jp`@V(a!YI4tKt`|j)+oI6?(MYri9H%fX zBjPrcMgM}yh~G{Rbz!*iH2&F)e#_&ofjW`hMS3wiq&7KhA7p}`VzweVra_c|E|S$_ zFlX(RaYdr#c!&~`I(j^4lN}N2@{HaKTe#j}GfIq~RS8C{xkS&9iKS?GkB1;#$OrXD zt2gFottHcOdXuHh{4A-jM>2tZR$5>I5PdbwTvxeFrXt)xlDx@iGijF*$aOq zr_OPSa5uI*p=yBn80L{ex$nEtr~E$=fr*-L1l^y8?o`hfe7~sQ_PnU1J|nHS^!t`B_TI9r z#3HNdLx+1oMJa)H^=M-Lbxy zAz9OLy^BTl#qPr^=DHlw_Z29^-G^ZIBilN&ha=H`l9e!=2)nY2A}pTt@#YsB0kd-+ zCLas1NCj91Q!{RcEpCKI!15%|p`*;0;c$u|+eQ^y$$ExybBaN(p0#~cSRAHkJ9A!s z%K!=4az)lJ-gQ|arE**0uz3|3Of4nUQs1=)2!_(6Z01j7{;Q}y4iWFZ4mRWf3aNy8 zQpJkALo|Ar&G10;bk^=&YUu&taUYOmI(8=&N`@q5gaE-UC zd_Sc1j*O9orn#Ut30Td6LDR|C1;UjxHU3c6^o5~4DaSJk#{q0{m7F87*yLWIurdOS z()xO~%<~m0C9FvHhG+4o_>oh@c!=o2DMzx?M}B#LP@!DeJ*N+`FWwt1VdnsgX?=Wc zLytO^i@Yd?AQvDEPPzZc}(%<;gf0&5atvReqeX zU{=CC`?Vg~(z9@JF{GwaWizDEuIk*mT*@3y$oO=E*|%ZE9mbuTtLd8t^-Wrr!%I6uyqvOpSR%25Tqy1WCkU8P!O8cz zue+NvU6(A>zHn&V|2eSzD&IRDWMbu1tRq3viuQ}ChWfzhDNxR!U+xZoU-uKark(% zKHdlw1(!#FeSN~SnUGE^vYq(X8I>)(Ifp*Zt+M9CDeGj?v;;eACKF^n+Lga-Nyn%c z!PAJ37i}9z8XV(h=u7RKIyC>GU(B7@W+8^-vrtH0#Zx`zVa>FjboM=D0n^a6oxb){ z^r^6fWrQp>FeLcfwKQMqu2AgHv5&5k+JZ{o_8a7C>oldHoxYh8t89GFtELL@rsd+ zDZ#|m&eKTl-#7Tbjc#Y7@65*BnT;-;jn1Eqe)72?eLgMme-yu8uM>XWt{%SXX!k3w z0fG1+O`O$f8MS{GV-?`)8+ZvHAY78mH+$VG{!&)gH^+vRKXaiVooY!)b#$}nyK)gHB(0B Nuc!H+Sr_mB`(KlU60`sS literal 0 HcmV?d00001 diff --git a/jetty-http/src/test/resources/multipart/browser-capture-form-fileupload-alt-edge.expected.txt b/jetty-http/src/test/resources/multipart/browser-capture-form-fileupload-alt-edge.expected.txt new file mode 100644 index 00000000000..9c3e2549453 --- /dev/null +++ b/jetty-http/src/test/resources/multipart/browser-capture-form-fileupload-alt-edge.expected.txt @@ -0,0 +1,17 @@ +Request-Header|Accept|text/html, application/xhtml+xml, image/jxr, */* +Request-Header|Accept-Encoding|gzip, deflate +Request-Header|Accept-Language|en-US +Request-Header|Cache-Control|no-cache +Request-Header|Connection|keep-alive +Request-Header|Content-Length|22824 +Request-Header|Content-Type|multipart/form-data; boundary=---------------------------7e21c038151054 +Request-Header|Host|localhost:9090 +Request-Header|Referer|http://localhost:9090/form-fileupload-multi.html +Request-Header|User-Agent|Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 Edge/16.16299 +Parts-Count|4 +Part-ContainsContents|description|the larger icon +Part-ContainsContents|alternate|text.raw +Part-Filename|file|C:\Users\joakim\Pictures\jetty-avatar-256.png +Part-Sha1sum|file|e75b73644afe9b234d70da9ff225229de68cdff8 +Part-Filename|file-alt|C:\Users\joakim\Pictures\text.raw +Part-Sha1sum|file-alt|5fb031816a27d80cc88c390819addab0ec3c189b diff --git a/jetty-http/src/test/resources/multipart/browser-capture-form-fileupload-alt-edge.raw b/jetty-http/src/test/resources/multipart/browser-capture-form-fileupload-alt-edge.raw new file mode 100644 index 0000000000000000000000000000000000000000..13fa9572fdd5fcf90366a32ceb8267048897f765 GIT binary patch literal 22824 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 literal 0 HcmV?d00001 diff --git a/jetty-http/src/test/resources/multipart/browser-capture-form-fileupload-alt-firefox.expected.txt b/jetty-http/src/test/resources/multipart/browser-capture-form-fileupload-alt-firefox.expected.txt new file mode 100644 index 00000000000..f918d12a4f6 --- /dev/null +++ b/jetty-http/src/test/resources/multipart/browser-capture-form-fileupload-alt-firefox.expected.txt @@ -0,0 +1,17 @@ +Request-Header|Accept|text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 +Request-Header|Accept-Encoding|gzip, deflate +Request-Header|Accept-Language|en-US,en;q=0.5 +Request-Header|Connection|keep-alive +Request-Header|Content-Length|22774 +Request-Header|Content-Type|multipart/form-data; boundary=---------------------------23281168279961 +Request-Header|Host|localhost:9090 +Request-Header|Referer|http://localhost:9090/form-fileupload-multi.html +Request-Header|Upgrade-Insecure-Requests|1 +Request-Header|User-Agent|Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:58.0) Gecko/20100101 Firefox/58.0 +Parts-Count|4 +Part-ContainsContents|description|the larger icon +Part-ContainsContents|alternate|text.raw +Part-Filename|file|jetty-avatar-256.png +Part-Sha1sum|file|e75b73644afe9b234d70da9ff225229de68cdff8 +Part-Filename|file-alt|text.raw +Part-Sha1sum|file-alt|5fb031816a27d80cc88c390819addab0ec3c189b diff --git a/jetty-http/src/test/resources/multipart/browser-capture-form-fileupload-alt-firefox.raw b/jetty-http/src/test/resources/multipart/browser-capture-form-fileupload-alt-firefox.raw new file mode 100644 index 0000000000000000000000000000000000000000..ca094b5a9fc1eb6f660d21f82d5fe674bbc1a62b GIT binary patch literal 22774 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 literal 0 HcmV?d00001 diff --git a/jetty-http/src/test/resources/multipart/browser-capture-form-fileupload-alt-msie.expected.txt b/jetty-http/src/test/resources/multipart/browser-capture-form-fileupload-alt-msie.expected.txt new file mode 100644 index 00000000000..b1534812a61 --- /dev/null +++ b/jetty-http/src/test/resources/multipart/browser-capture-form-fileupload-alt-msie.expected.txt @@ -0,0 +1,17 @@ +Request-Header|Accept|text/html, application/xhtml+xml, image/jxr, */* +Request-Header|Accept-Encoding|gzip, deflate +Request-Header|Accept-Language|en-US +Request-Header|Cache-Control|no-cache +Request-Header|Connection|keep-alive +Request-Header|Content-Length|22814 +Request-Header|Content-Type|multipart/form-data; boundary=---------------------------7e226692109c +Request-Header|Host|localhost:9090 +Request-Header|Referer|http://localhost:9090/form-fileupload-multi.html +Request-Header|User-Agent|Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko +Parts-Count|4 +Part-ContainsContents|description|the larger icon +Part-ContainsContents|alternate|text.raw +Part-Filename|file|C:\Users\joakim\Pictures\jetty-avatar-256.png +Part-Sha1sum|file|e75b73644afe9b234d70da9ff225229de68cdff8 +Part-Filename|file-alt|C:\Users\joakim\Pictures\text.raw +Part-Sha1sum|file-alt|5fb031816a27d80cc88c390819addab0ec3c189b diff --git a/jetty-http/src/test/resources/multipart/browser-capture-form-fileupload-alt-msie.raw b/jetty-http/src/test/resources/multipart/browser-capture-form-fileupload-alt-msie.raw new file mode 100644 index 0000000000000000000000000000000000000000..786215f3d902932280049fa3cedd2099c78abb56 GIT binary patch literal 22814 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 Wf7VSInZKUqzcC>GpZ3H1fB!Ekh6gSH literal 0 HcmV?d00001 diff --git a/jetty-http/src/test/resources/multipart/browser-capture-form-fileupload-alt-safari.expected.txt b/jetty-http/src/test/resources/multipart/browser-capture-form-fileupload-alt-safari.expected.txt new file mode 100644 index 00000000000..12c657e8258 --- /dev/null +++ b/jetty-http/src/test/resources/multipart/browser-capture-form-fileupload-alt-safari.expected.txt @@ -0,0 +1,18 @@ +Request-Header|Accept|text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 +Request-Header|Accept-Encoding|gzip, deflate +Request-Header|Accept-Language|en-us +Request-Header|Connection|keep-alive +Request-Header|Content-Length|22774 +Request-Header|Content-Type|multipart/form-data; boundary=----WebKitFormBoundaryEQhxWUv9r38x3LyB +Request-Header|Host|192.168.0.119:9090 +Request-Header|Origin|http://192.168.0.119:9090 +Request-Header|Referer|http://192.168.0.119:9090/form-fileupload-multi.html +Request-Header|Upgrade-Insecure-Requests|1 +Request-Header|User-Agent|Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/604.5.6 (KHTML, like Gecko) Version/11.0.3 Safari/604.5.6 +Parts-Count|4 +Part-ContainsContents|description|the larger icon +Part-ContainsContents|alternate|text.raw +Part-Filename|file|jetty-avatar-256.png +Part-Sha1sum|file|e75b73644afe9b234d70da9ff225229de68cdff8 +Part-Filename|file-alt|text.raw +Part-Sha1sum|file-alt|5fb031816a27d80cc88c390819addab0ec3c189b diff --git a/jetty-http/src/test/resources/multipart/browser-capture-form-fileupload-alt-safari.raw b/jetty-http/src/test/resources/multipart/browser-capture-form-fileupload-alt-safari.raw new file mode 100644 index 0000000000000000000000000000000000000000..125321970b1b1f6e1dff93ffb07a91c0f3efcc63 GIT binary patch literal 22774 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≪YBlk?kPYQz^;%u_5@*uYyy5+ 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 literal 0 HcmV?d00001 diff --git a/jetty-http/src/test/resources/multipart/browser-capture-form-fileupload-android-chrome.expected.txt b/jetty-http/src/test/resources/multipart/browser-capture-form-fileupload-android-chrome.expected.txt new file mode 100644 index 00000000000..ef15f1eba25 --- /dev/null +++ b/jetty-http/src/test/resources/multipart/browser-capture-form-fileupload-android-chrome.expected.txt @@ -0,0 +1,17 @@ +Request-Header|Accept|text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8 +Request-Header|Accept-Encoding|gzip, deflate +Request-Header|Accept-Language|en-US,en;q=0.9 +Request-Header|Cache-Control|max-age=0 +Request-Header|Connection|keep-alive +Request-Header|Content-Length|22054 +Request-Header|Content-Type|multipart/form-data; boundary=----WebKitFormBoundary2oBNepLIldUG8YwL +Request-Header|DNT|1 +Request-Header|Host|192.168.0.119:9090 +Request-Header|Origin|http://192.168.0.119:9090 +Request-Header|Referer|http://192.168.0.119:9090/form-fileupload.html +Request-Header|Upgrade-Insecure-Requests|1 +Request-Header|User-Agent|Mozilla/5.0 (Linux; Android 8.1.0; Pixel 2 XL Build/OPM1.171019.021) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.109 Mobile Safari/537.36 +Parts-Count|2 +Part-ContainsContents|description|the larger icon +Part-Filename|file|jetty-avatar-256.png +Part-Sha1sum|file|e75b73644afe9b234d70da9ff225229de68cdff8 diff --git a/jetty-http/src/test/resources/multipart/browser-capture-form-fileupload-android-chrome.raw b/jetty-http/src/test/resources/multipart/browser-capture-form-fileupload-android-chrome.raw new file mode 100644 index 0000000000000000000000000000000000000000..2263dfdaf686fcf138d8189eaa5073691a290833 GIT binary patch literal 22054 zcmb@uhdv~?-<8faXVd0C1fz5L@JGY01HX1aI$o? zk>|0takYA5=W_8X4>ct?#)Rh1Gy#F6R@P*wg8y-2t#nb;? zfxV5Jo42r~2e_y=!V*%qMO>V0!KM7a%h&aGv5`gCIa=DF@2ws60lf z_PxO;gNSyyPp5=@5b{js7uB{WebeCdTtQyput;7>%?u@FcxXy-^?F%x+Z0t=Cx6yW za)BfMXqWaFqzWcFI=buM={2`L9i0PR_nv)r%Z7AK^hruu{+3Te&(i~4hn9D=kKh#7 zT|DkZdB7M{5CJRPN)Y&(`P%TYz1P>s_@@+qW$q)yPIvP1Lnu>< z<3f|KwC(sUatfY%p@MMo5501{EBQz6<+H6pT0a^78vC3574bEkDoMOF7YN;>^OM7d zAFAb8WPRtL{MEL(*^ zLgZMz*(HwZ`*ixnPXkD+962;Duu|Eq3%F;Vv!zObR}Jylhh%?o#IvAD7rmZQUZPQ%f?>+hL|4jxRIrwHh3b4ix+P40vuo3;n1Sylpc^(u-L!af0Yt#mXj0f8La`n=}xr+bL-_u*?V z-;wKf+O|n#bO`!v*BuE{Qd0hhSW`lh>Z|)1eb(WH2~x*bJG0cWs5mBHh1GsMi_*P% zlZP?0`XuFR`PYZ7dcmEPx*d6s;kq(j9pL^5I0l@KhcaLuoQ^Z0^qQ*gUm5_ThHsO6 zC2x4iL8G0~k&}V-L@Mgwi9g1W)JB zm`v&$?R5yqwg%tjRIRv*=0W4Al`nH0AT!Oc|VU6;Otq2-9ZCY7KD_ zx9Oe>zG23+H1{~YEAOf0(-ZmIK<@Db6|)mwTy|A5R_UPLklUnIAH&owdJWRcs|?Xn z>B6LXG+rZ~@((Huc-aPRP-4ThIwMWE;bt-q+@qC3R!6Iz9D6ed2+-%*D~;BcJ+7;B zoI-y^4u)iX<2PhN)w(}*r1F@q!l8MrV02^C`8%C#$$GQ7#fy&N9XH2pGqcV%$>nRW z*p!Xmd0??#ysMxa8Bp<}nm>;c%c0iz_-Z`I2PNgbf=Z%2LU~)4HP>Zk3`}lJS+CJO z#6h9qs$?u9+^>dkCLt4^<3V{9#5P^QER?lD2L_CX9vw^XoynR&YAsN`9N}Z;Zi> zy(9xZBF4@N2ToY2sF7_Xt{2hU`kIv@<v2#6rnhaM$(_t6VC8pG81MCSQhl+Q$M_ zc1DkAme`17mp^g2ghE0|=N=*H3~%<5WLY9f^Ygz#sFn|Q{+yl3s*Mxml7`n{d)r@q zg73BF2Sb0pUD78ud&qpZbW`t3QTg)dY3Ym|I!$bEidFD<2A{?o2st2PMIg;%o8b|9 zzk>06Yv|AI5|IrB8(5y0Lcyl{3rA)P{hcQKN0L($&O%BorTAW&)SdBHtnW`s$IERy zPSH#LW=1yFjkR1pEHhU+|jo6zu%Y`W(Jd=b&?~q5nk@} z^q=yCciPkZhd1ht7|0R9rI#^{_+^SPl~7$U7fz$i=Nif;UvF#2e3RG)8_#3>32`fr z{gnZNU5;yA&BZcX5BF((B{L$?QCTlQ@oAgSCq1sQbL?%{8?7>U_x3nG&1lwky)_o; z@15lcyCSA2d3dFy=_@%_Z8n9HK2K76jpVA9jql_6z2Nlf9X8SfZ0qazR!s_QK5y$a zw-~zrG9Kr66hbl0+T1WX;zmKm0%F7PDF2=f^p$(gQ?vq_*U6FlVi8ilX-62nE`R-* zXO!dR45qtoZZgcoClql-z1Is)_iw$+6HO0oCmM4@VT@kxEd2Q@43P49ooDwsnF-&= zOMXb}cku9F<%h&PO}WA5HYS5?;Qb|;NlmxMw1UkaA?R0f96yqeEUW&2zmgd}F{DRz zFzEQVZlIH!E}JEi#{YmXof-|EOHjpVhe@bKGobc-bG978JS6uMBLon>riU4Nm6rrp zMCQH=P-qcnoW#PsKQrO*OTUEhg)S>RU+|wiBL9@sKTxo>lm>-d$gd)6=k>t?0KiH^0Ccp+71%(5J)%l$rs^Lea_Rg zdU9fuM;rmn$g{a@5=6eFJGf|@oLnmR0CoNLphylm46#Y z%v*9O==?=@636yXk;&hczn`hbs-4Zdzg84(Ejj9s5FJucQYO_M&xO}}Y)?(b3fFq4 z=Lg{ilgBV+$9NQ0R8H>HaJcx{ks^Ml#YEO)qkTwqVa-Jqc~!yhd&c=tV;ST%HdUuy z#&5HxlQh*mTCAvVX!uF|_1sUTiy!GhpRDGZRaI4ewfyQA7ZVrfR<4#HVm{@wUKD;q zJ*kq~z1dl)ZiajD>eU$|D-YAs6D#n#)&>*nP3Dn_kCrvdK&e*J(~Lq`E@95hpdt$72O$a zIoL(EK$~id%BKswit%m4z-VuK%#vZ`eGg5~!p-q>4@bg7N_##U8%@|i_`e<=O6bJ4M8TIlp}vv%w4Rj1>& zzAtL7$hLArh9Dhc3nVkK_@A%ei6y2#IHnwQN)4O3t}k^bmt3;_^_-Q8MTGsdL$JgR zp3bP3mieC8tGUM{Hou@ir}+C^*gLhyk7Z@dUMuSw7}!Q|DW1#Tq?D^oQSg^N$S)}N z$;i&m_LuDFx$o%c*#COIbrN1Sf(9{7PYmUjz%Tl(hF1f zs-KFZxP0U8Gc&U^xcg>_J%8wgP#W({!`b0@iJ*{B-3ZRuq$P|=@GT zq>YWunr*s2^M@g8b#?WMzn>pXlcSFE%c%RydMS{WyR-%Wp!mFsF7qPiJUP#;yVI!6 zxvLj9>7iF;Lq3iR@gPd^{J1eJEG&gwcaZs`sQDBN^BDmQ7+(h-c5aV_+H%yBi{DP* z-<3rUXjvRa>G_aa>tiYdKE}mmbI828o-QzQCj8;=07p7$^X?m3{dDU#j3k)o>s0PN z&CqF`H>jvmFC>`hA4QwY?BQa;o%H0;JI`^VKB|7A|21EjaqxHtrCPM(SMj1-BTJ*S zTWnYn8Fb>OFsyj~FG?_v@ZKY}ufM;OPDpy`9~W$wW!23>Fh{ZHUD#0nzE@UO zO6fIBS3YTtqv5yaxYu;-Ke&LS;gDrlE@fa8NN2tE!cFnbf(oa5&&y$cY3U<~F%a$2 z4xh2}7;R~yvigYZ(Zy^>xs?&3`1bo=Ooh}U4>Jj)BD?s9vYYsDs4;D2Y0K4KaM z9dFm|{gEekgJEWt1=*-`*L+A0Nb3&A9G=m#--*^_+A6NIUf`8!YbfC=Zc-J+`SsR% zI&;EY#%I8#jlb?mli$oc{dF(Z=U~kps;rZ-hvnV-`Q&bq=r!2Z+#YU1@oZnmHlL2D zd@ccM5YDYagBunG-mDigL+bR0rMD>xmd5}|BaXrLyp-9o)Q5RAekYf|z`wCmS!zK_ zMn-R2n(s!QFzEjEo71Z_w#aXMvfaSH~|XmqWbMFU~IlX`l*)i zoqE4tQ_<1n*|Ss;fkL$cSJ)iWblQIOa*xb%3VbJIdL-vLBm@&oCUE)hKds#yulD@h zaoD+}x)L`xK^Nz#X77^yaVYNEqe#=#l$2Kk5pMTcgpK2>?fP$MC;q&bDpI>q?ya6A zDK4Tdp`20*8TL=r2|wovyW|y&aECFAn0krmwNv#yYkxlvHC8hau$t)#Z*e`Bom|7p ze(+)V$Uk-wR{L|!DOBfAQ-hNF*2&ToA2@V?W}u^!t1$^zCJ=rsr>%FYZe2oFuE)j3 zzL^7s_MH9sbh@B#j0evy6Ii*7cF>AA5SC)1IiKWr7NE17ExR&8%R{~1~}IywpwaKv28D)y<7>=?2EL*R=jl~;{jKcWZbR_WI|P6y_R?)ESXsZ{aWGI)QsT=;5Y2sp z^i%gK`;Q=mynOxK$$E+6+nFPWwENK=qzk{yvx&v*`m&o8xKb@{7ZSluh@* zR~_lhCfPZouLthwcfH@F899m@EL-=6rfXGWX^hG-v+ks)miPuOV4w_3saS=7u^t_d8T7*R$7a zY{x3?2sSkRFsjR0;tbI|6lu5;HnKc({Svdum)!(5#nPO>A@cigFO5dca5uI#C({uJ zI>gsNpk4JX^`sMA^Pen#S-p}pZ|Z8IGyBVc@8$D4{BEabD*7BZm{$b*EWAM;F z-BD$gfAGzDy1|!>hTSmIVv|;Ev#6$K>|n}wJH{xxOepqhFT17&QXf zXy7v>M_zEJcUKByG3(QWb58{+ajP7)77`kd(L2Nt-JdBzxk{d~FwMLFe!keT;#At)#4V?9n;ILB1z&6( zyRJ{-Z?`p#AR&5U_9$!F(z0(1(83QWixURmEpB%ar>k^gQ^PJbp7OSk%wlJz>6aEC zB*%=b-#PVDIFj40bEVKryXbaRZW=nA`TypLc;uNOpTi9!zkYS;c%G3t;!lT*d$@h+ zDX*Y`b1>Y)&GBuomCSdPh%^RMMj~P>yIp05GA!*_OQC$4#8zkS+_hHy(Kb}8*;L9yI->U^J0G1 z5w;2E&VnnPQ70!CKxPvxhTK2h3IxA57Z zDB*He>9g9~+l!iX?U7f0=|!V^lzu)JE*cv{FwE0&a@q>u*U5Pmc+ithLPC;yh5S0@ z)<0B>KSkHKH4B9QY;#Caetv%N--K@3{m^@OpWSEk8vKu zf&DDkm<|%LA$=<-PL-`v$gJ*8x`0ZF8;iu8EG(1;qPZeAa}(Z;MvUN>afCV%@mOf7 zEAf8hNqETq$VXuleFeZHPBU}Ps*EaL#C$#nzZsO^FQ7A?a8hqaoz+x^>CLFn^@drO zi8j^=Uq*4W7Cx)}C`lmu^>1g|ic|4hde(gN@H5X;@g|bfiLP|!gddRZB_!F*3E&JS z?P&+X-5*>u@?B?#jvm{)7{+p*uA381+5o;nzJd*i3hEcOgL)@r_ZKv?w=^6l-uCta zYD*iwOpZa5-yT5BL>P}VbPTrVS|9`;DYGIQy*V!feK(GU1`3TT))f3tu3W}^O1~xw z3uS?bU&8aMA%OQhGKJ(lOyl~kD$2_>qPP@Mv_FeqBIQB37!w{^2f#{S-1bij6CKr^ zTCHi!rBRX$yiW(A+J0AO34JD&EbaV9KvitfzT0JxVN}#}y7W1giSADTvfRONQ&d*;8r*3fe>@+x_Z9B;D$DDWiYSe8h$`NO1CQ5wC9bV_}`22^S)p2c-l;*H)?CD_Uh7k*6Jv8cZ;?{T~{>uX%?p3>GBM@)DD7JNhIE5JJ>V z?{Kf0{ij!0vJ;pD-Q?x{Pv5Bb z?+oZ@Zc2L4vrmf+u|fW=?^$ttnrYVueJj_A8x;Y`@8M?l8NJs^5=V}>gd=Q}xx6G` z&g$y!u6}sZC{w9AlSl4lZ$=hitZ9-Q3(cR{U1D}ngc9CvQN742YN zHhzmSh0@+v6pMdT3-D+5(+jXGzuSH-{j$eKG#~)_|-`)|a+iCtRJ>e20F2&50+z0fJL$E1grz5}; zT3lXc0qwFrq%`MD_!m*i74o0s%SKS$9uEt0g-~LSRq*{C%e&y`MsX*c%tR)g)7Lml z-~ur}T~K^^T7NXet z2}ZKPw_wW|4u3VHHUap?odx$%Lu2(|!z8V-LLDw|s&F|xgGOM;N;>miW>9-1} z8x<+t$WuU~=z}+x(sinz`!$u^74Pgh(wHO@6W}�^R73OX67wz+p-s%}PSx19s*u$|V`^<;{Q+-FA4 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

#dCoO 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 V%uUW1R~UN4{U6D!ii+Hv{{fi79?k#& literal 0 HcmV?d00001 diff --git a/jetty-http/src/test/resources/multipart/browser-capture-form-fileupload-chrome.expected.txt b/jetty-http/src/test/resources/multipart/browser-capture-form-fileupload-chrome.expected.txt new file mode 100644 index 00000000000..491fe431b37 --- /dev/null +++ b/jetty-http/src/test/resources/multipart/browser-capture-form-fileupload-chrome.expected.txt @@ -0,0 +1,18 @@ +Request-Header|Accept|text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8 +Request-Header|Accept-Encoding|gzip, deflate, br +Request-Header|Accept-Language|en-US,en;q=0.9 +Request-Header|Cache-Control|max-age=0 +Request-Header|Connection|keep-alive +Request-Header|Content-Length|22054 +Request-Header|Content-Type|multipart/form-data; boundary=----WebKitFormBoundarylxcKjAyTlRs3jNP2 +Request-Header|Cookie|visited=yes +Request-Header|DNT|1 +Request-Header|Host|localhost:9090 +Request-Header|Origin|http://localhost:9090 +Request-Header|Referer|http://localhost:9090/form-fileupload.html +Request-Header|Upgrade-Insecure-Requests|1 +Request-Header|User-Agent|Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.162 Safari/537.36 +Parts-Count|2 +Part-ContainsContents|description|the larger icon +Part-Filename|file|jetty-avatar-256.png +Part-Sha1sum|file|e75b73644afe9b234d70da9ff225229de68cdff8 diff --git a/jetty-http/src/test/resources/multipart/browser-capture-form-fileupload-chrome.raw b/jetty-http/src/test/resources/multipart/browser-capture-form-fileupload-chrome.raw new file mode 100644 index 0000000000000000000000000000000000000000..b31c88589892ec7febf716e58b78b243de115654 GIT binary patch literal 22054 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 UlQYH@h8}VMe-NvpA~)xM0KxJn_y7O^ literal 0 HcmV?d00001 diff --git a/jetty-http/src/test/resources/multipart/browser-capture-form-fileupload-edge.expected.txt b/jetty-http/src/test/resources/multipart/browser-capture-form-fileupload-edge.expected.txt new file mode 100644 index 00000000000..3086e324bc9 --- /dev/null +++ b/jetty-http/src/test/resources/multipart/browser-capture-form-fileupload-edge.expected.txt @@ -0,0 +1,14 @@ +Request-Header|Accept|text/html, application/xhtml+xml, image/jxr, */* +Request-Header|Accept-Encoding|gzip, deflate +Request-Header|Accept-Language|en-US +Request-Header|Cache-Control|no-cache +Request-Header|Connection|keep-alive +Request-Header|Content-Length|22085 +Request-Header|Content-Type|multipart/form-data; boundary=---------------------------7e225f6151054 +Request-Header|Host|localhost:9090 +Request-Header|Referer|http://localhost:9090/form-fileupload.html +Request-Header|User-Agent|Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 Edge/16.16299 +Parts-Count|2 +Part-ContainsContents|description|the larger icon +Part-Filename|file|C:\Users\joakim\Pictures\jetty-avatar-256.png +Part-Sha1sum|file|e75b73644afe9b234d70da9ff225229de68cdff8 diff --git a/jetty-http/src/test/resources/multipart/browser-capture-form-fileupload-edge.raw b/jetty-http/src/test/resources/multipart/browser-capture-form-fileupload-edge.raw new file mode 100644 index 0000000000000000000000000000000000000000..6f60b77cd3ef4f8e3e3e9471ba95c10736665755 GIT binary patch literal 22085 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⪙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 literal 0 HcmV?d00001 diff --git a/jetty-http/src/test/resources/multipart/browser-capture-form-fileupload-msie.expected.txt b/jetty-http/src/test/resources/multipart/browser-capture-form-fileupload-msie.expected.txt new file mode 100644 index 00000000000..e2f6482cadb --- /dev/null +++ b/jetty-http/src/test/resources/multipart/browser-capture-form-fileupload-msie.expected.txt @@ -0,0 +1,14 @@ +Request-Header|Accept|text/html, application/xhtml+xml, image/jxr, */* +Request-Header|Accept-Encoding|gzip, deflate +Request-Header|Accept-Language|en-US +Request-Header|Cache-Control|no-cache +Request-Header|Connection|keep-alive +Request-Header|Content-Length|22082 +Request-Header|Content-Type|multipart/form-data; boundary=---------------------------7e223ef2109c +Request-Header|Host|localhost:9090 +Request-Header|Referer|http://localhost:9090/form-fileupload.html +Request-Header|User-Agent|Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko +Parts-Count|2 +Part-ContainsContents|description|the larger icon +Part-Filename|file|C:\Users\joakim\Pictures\jetty-avatar-256.png +Part-Sha1sum|file|e75b73644afe9b234d70da9ff225229de68cdff8 \ No newline at end of file diff --git a/jetty-http/src/test/resources/multipart/browser-capture-form-fileupload-msie.raw b/jetty-http/src/test/resources/multipart/browser-capture-form-fileupload-msie.raw new file mode 100644 index 0000000000000000000000000000000000000000..9b27e7677b4023dc866b4337dbb484f3c33a240c GIT binary patch literal 22082 zcmbTecRbba|3Cgb$0jo)G7cr#J0TpEB8BXg5fU=WUgsREL}ny=BxKK&b&Ntr%HDhL z?8D*wF0c3P^Y8bM-?`noolfU)p4aufuE*oPu7rjE9}gKD2?>N$C z?5y0}U)g}yHg0a-!j>N3a$gBcNZ$}~ak2#$`F{h`^>(q5L)bZ5+S-VMch0Z=t(L}p zYDzXr2!g29RPSm-5Dfek29cA3C(~DX&%hJ0>uoh%a`5mYw+;obDO^;ITp@^j{QM6r zecAjL_(xVZ6+<^2=Vxx7mal9ePft$~J0}NMD@zv}5$9L7$(y&>AP51e-Bs50O4;!D z_G45TB~<%fpHo>A%C<>dkj()6CEAh_3z}0Td$7JzOH-E9=l~jx+eNKB`tr`r=jQZzOF;d z8`}GDimNUjx1&5@462BLWo~5%yk@@gzo!+ zfbAiLSa+9sj<&0?VLHE&{meAleIM3gmTR@xb)SJ&hA^a|H>t*x&LAe`muwz{C<8LV z`4W7jRU{-tspMX?oRT^f>{CSE+WGi<0#2oa*sKbcCndmFSn5JotS9*PjbQ{#i(s|? z!fq>;Aiw z?sW8blr6IJe!<%~??EAG$>iuF-a**^*W3 z?lf7}UC5FSB{;Tj?2(#xVTK15qtqtf<{O}|irn+vZNPnG3Vv^WhnGlDpK{ysK zOHON$i?~hqOz;&mrlq;Z=}mc0EuWsq-v)Azhp3qC@Zz$|QnAYW^@iLgwfY#QZqX}{ zUS4I0mTDI!)uZtW@uYuHVZie?Xq^%prqvl~!VNc*z3U#W9I`S}_3+4>IY59u&t7?? zw(LP&o#Q0>3vwVN>npz@6ROtzu_KkoR22@*V+ErdoyyO)>=slK?Gnn{x~#b_GGk!! zqbhoh?ja7kRq=U+SvAlrS3SL>B9VJW%__wDli{nrvlDG~`T=^Gp3QKV!1m_9oY{nx z>#*zg=-TFz^3Y)Odz4v(oQ~gPWY6JR;`@anilLVSjE*84nQmLGv3JN*ko^keuLwKP z#Zgn$28!}XB)%d~VA!TuwHhyJVET@xN}9fqW7TI;DCzU0v{y+kYuWfdnA;6buij=O-N&}RjBnMX zz~=L|UU7?|dz>6Qt&!gZRsGSDQ2ieJ(16JFQ&+Q43B2i4KZ`$ z@TE1YA1TkfWoyQ9*F9!H`RD9Kehsmq)h=Zv>zlLb2<9QVj~F3<@HIWi z(5t*4xGXaJO@Km+IO8}L=KYBYhhO|DgfE<~hzNXAaktSJwpgC1EbYaVS#9MQk}qr1 zTyooQk?_IJ_wiWiZEKH^DZy_tCZbAgrck3bbuef%u4gu*lYXhoP5ICL1jCtxRpJwi z(qT*ypJ&(Ba;g%E-${hBkwg`C#aPFP<=LYJMJ}npC16iGZB>qJUeb1ukcU9Jp$|U` zm+Et#q}7uXo80FJU`C$KW|JWDrQE?q+vMa@xd%MbZx4#(koOR>`JE!GFjQiWrhyVX zNNb9Rob8ixV3=otWzJ?~y0cy4*eR}Tqjy$yRpg54J)X}TCl7IcirAi|UH9cbGmR;- zuKJ6Mi)r`7xJ!G+#;JdV6SYsieR!ldF3bY?Fa1t^Wac#!5`M5g(#M9$S@ZcLxu9Ua z>uQr`ewryMkAlvgbtiFb4HlXFUHF{xH!26(wa--O+4#y~oz% zM67VFcY1yhZXkISQ+9+$VMXQTPYj2OpByUTw_8l)Jl5L>)#g`S)R31I{k~ zeb$P?uRThtq;_w17OI=(UbuXD+Q`bowDi~tyzlt0nM%~O#75lgr8!%;CRpN z;CJud#gcLPZATJ!b*)zu5Qag8{wi2&;RXoiXNI&J57X;(Q>Y{{gV5fo6E%} z`)aO-{Y`m$oKlb(L&;6`%ll^-Q+EmW?ATUNK)^Wod&h@A^}dJBibvBy zhsS#>I;h3y>j##FA;jC=GE?)W=+k{oJ$?Nft~KL~VCKFpZ&XjAUbaVbe1nt*e)isQct~l_2V=u>cOunU z;giFyo=b{;M;HGxqoCmi|C7%_q|`pBi5hp==hr1o$Sj{&b+yiey8-1sq5NecXG)E+n-NasaQnV zPdWrk+~DbqdTE*Oh`pM7Ok(p33UrFU&4#^EfABy~*6gK}-Fjj-ES?j*fjV=UOM=Wz()KxfG2T%-$h?PH9u%DK0Opm0(euOX+A- zvZP+vBd_|&IEstcZapzGOM|;_l-To!jtiynPB)w$jFkuq3Dphbj7?g?m;_%lvasY{ z`2)A02vDc_bU&)W9;{4-PuebUaN{}3Y zbOJkqU+2?ZZ*T9jA#?NuJKl`G;I0L;Q)V*By-X`^x@MAT4)j3;sdzc@7>m&uW0qtt=lkC zV4|;5x%V_fCw1PSqDnuLV5YwxZ8E)!iv@SmlSA(;$BFu|`l0@pd|}3cqivL0(Y9a3 zvu=$njnZzhAthwcv7h3Q(%HW#!92n{kJR42zD_zJnZzct70rX&A>c^nOg9J@*>1EWAXtK>5`rC0N+obEl(hxlb= z4k5-sv`agD+RkIdosqs&@m(R;=z4BV!`boLZeH_2x699>ZK6hj+b2XwZSC0Cq*RSU z_{B=?zX-&E0;tk5&`|AGgRijOS1FE5eWS9EyvOI-lHdGHVt{HqHjKlNtQmz|8%5QV zY!4?ynOFOZpVS6TC!f4nrzRhOmx}F{{2}8m&LmE^kKT`X3HHsCyg=$Mx5v3wZ1M&E zH&^K+reM&~R^9Gz1#&kSW_n4GjXHPLhh(3$?qJm62`&50XicWg;yUYjUfH&W60YJV zHBp@3pIT36PMFKsG`O^}mpy3;8+j)`Z>Rd~uew8(b+Y!byxTt>-YOEk0^6M3#f>YS z?&;X((-D==CO{3sxm9Rz!@|Ia^+Kjeoqn_YX^Mj7F+ehiBd|R$WOgj}V(yRK%;hie zZ|qc&o|l%Dm2GpX-S~PX`XYt~={pm`LaKEb9&%m_Srq>LxLBK!;|2>(fC9Uyez^-6 zo6nPetR;M--s{s;ax{7JBvnM9P`$tvHp?`XwimtBBfFFW-wv4?&Up$6!32{DT>g8H zYd6NKJwJ6EbS|nb$IXt@#d)gRyJUYDjJt9_(lj+C}ZaY>F|&5wo28N%(Vq8wvtbOgjS7= zj6eh&F_2Vllhk>?TF7RErzMMXq4s zKKmtY)7}3?M<%mLZr13_zI*yD?^o%DCGW>Jihch5WMLWp?)gm!Vj@gM;+&b?^cY+m zN6L9?3k%YqIiZIE!cQCJUAO>O}2fuUWm1 zUJ}jY4%umcd1;!);b+}`ld_Xl`I{Ijc4}$QP19cdR&>@U|8iH@wm$jt4pijp$k z$y*$nl-4J2RIqFgh5=Nto>v3Cb6y*VSfP*HLvfR~Y2MGS1pfMKNLE?>>ph>jp^na- z4%N!F?6n%((Mmgl4NV`6>SC5SLo^RX8m@$mEYDoO#BAbuH-Sy5G$(M7{LbqOBT>`b zjjheebi{!U@ih==SG|ip=>*sOhfAMVE+x&Gx|-b59z9t9J_}l!z+B2~w=yfS$!FTX1evckqf;-AI|~Cat>67m4*c>F z{~khXf^`|Q%4%wAX(mqJLsq9~_+Z~)-_lUWD~h=qsXVy`zIBftME8eWl%(lR((aRb zn0CwiB3p2}6d~RJU}Q5sK0ezg$|DszO849O)q@y3TK|X8cB#1>t#FOOgKo)&8QJ)1 zeYk9%h>WH(lk!rJ0wlg0i4m`0aP5GC{QOwLehGU2b4UL*qn3^D z*`9O^9{MNSYOD%(zdBDf_>$4E8%A1e(28vo)zpmcPx@}f7-g4f<%&G1DFlUMj3#yD z^P(4{Mj#sve46CY3-0vhQeiA+ZHjQ_sVFUOm80H5LgO)VlRA-r2IYk__-0cG6Y9W< zyY*z6_MT6nbgr-LA?_Lx(f}-y9K-0yE@uux{kn_edt5XLy$Q z?E2#er4EJDTY|Cpo^9>~;jlq(aSW;G5E3hXVBd0+NmDfhI z^_-!VtD@Lx^6l818gPp((`1mlR2TW$eG3*uNv)PWtZt`6aEVjSEl*Z&k<8?pyxi>0 z=d8ZGm>+e7Ey9_z;4){_@$os3*#L_n_r)p-e0l9=P3Q7qE;;gR@C(@XaNI=or_(Rf z>Cub;=N6QfmJ;brdmRvLMzM}#U)x5j9F|ljd~MRpmRmCFWdEs%Ad&3T0|w@&ta@p> z9GBKCeAX#SxSUmct#)^Jqb6K?6jYvj(dZtgpUsAg#>Nl~^K_h?HUs!|a$W@P_oS1M zkfdHBze>6J57pvN(e-uJ0^vW?98#2@pCA19c><{^!w>~h3bwa8uqFoQgTx14PhSo~ z>+-?rzeC07v)%L!kIiv4jiZ+a#VspkKX>+qr_K(l#~Pi(*LVLa9WQ?x2Ui_K)c!P6 zqk6()jK{ElFUvKigG6jl-wKLTW2+Q0tGk&lpjzU_A~7om3#EZ*E{RQFhj*h9!}ui} zp-x0R7Fz5|yc2mG9@RWsq{5HYp!|diD#;K6UoVVS2}aTcS!dF zl5F}Ia0Zk1w0+_3_bwXwt}}y&5A0nGV>wUO%n8SB0AC?r!1_f6^$XiUy_2^43!2$$ z8jfRcdwT)(#dTjM$DoO?cOhmXjK?WD2HSHb5P}bvS&@xgpOb~Y8OK8Xg+>*tivGu! zE@D2WUlE0cvOvVo;d#{%zeYtTuLa~AH~m+3ZPt!3J1^#2K225}$L2)_A$*y~w0_p{}?KF#t2~-`elj38Aa* z#`tJ}52zOo@$>Vq?19N?2y_qNW69OaYJVU$n4gqBbcyIUz!yLN{?IG(?V?P3pM~APa(xgpP{q%!mzEt>X9}gleAUIx8Lq3z8>!iAgsc zeUbzSA&*RNa<7=Z)hjI74orfs^YZ@m9I;8z%d$ktGi^90LOB|#K9c~Cs9odO+Md5u zPRv?8wvjAl*DJCp=HQ*=PxxJC#+T5!01CS;782eox3b(InNHkUZ?WkKl697*LG+(N zdnqaGJN$}eC2X3iiurUU+b5^(Jw4dHhjg9J?014(?zp|f!p;x@Y}gpH4bEJxR#a z_}HxgNf;nzMKJk|oxe@WF1SI);mpFSR2kx*a&qp8iilk6dwJ()o%e40{3Xb%u&83C zOp^EUt4Dp?{W_W(QXcf|Q(}W`kbmntRve#Z+SLKy$~EFfB|!3fxS4%MZnu)eks~hP z2B*~UUYt(%HIOHdsyqX{?v9IzHR-cp8D($^9uim1SK>T8s zJGak@b|5bszsZM2af!6QjrUAy zpP{2|#N3wuINWd=S1tF3|K=Y1JcAmw-W!uB~is8LsUSA3NbnWwVIv>3aXFDNGKb*V|k6v`F zRaPn{5SEk(MsmTDu%!%#znW1S0Q})nJtw^lUF1}M-6G(3vk#&|;-)}d(uU!8J{McO7 z$=DPpV+xJEtK_pTL>0D=A1mPA@%y)kFW4PJh~d422w1e8znDWOG1AWSKu&_r%9R2U zP~|Z643xxM;R4$PDc4UyLFSJ8uwg?rc~{^Kefkt+-{bMqQS1;`*_OMkXi8x!c>?b(93Pp!8Pb($dVt9R>^aGJ?>I+@*H{)OZk|Tkb(x zi-g_c_c%iHCU&5}z%zsL;#*=wBF6O3kA=L%bt&r#I$7zq**Bl7u19CLodN8ymDbhu zaFUALXIkE4UDdqYnnE_tTlMQ@7TLs|0+@$q5x1u-=CqcDnbICeNjtlssS~k^g5TO|GW{`(?;=Wq!^N`Y$(}u#JS$$r2X|n zgYUF`H7+H^&j)ngPD_R5w#!r*^Q4B{kibX2EAU-+9*JpE9HNwzhD$NUXM0+?H$6Of z`xiMPtuNYBEr**7b4Js@6@HPk@O>_R(_tV#{<~=R_2<#iEKE$i=%bl8*;T`QEg^#J z4{>^5`ZAP*^gUO47q0$TRP3P?bMT2*Mv9fRY#<6KYr|GF>4O!WC+j?b;?Ta#Dneb~ zo66J>B#l~s|86nV79Jfl=4~fu{H0LDeJ!4uQ4z%;MP&nauLP1iB9#1w^W?*0g1F^b+drWnm@waq zsP{&Td=5#k-(KX~yj}WdciAji+Cl%#&dw{jh3ZG;75rFAb6l#JC0umn4F^#M1F`PP zSp_@syrL;FWmSi}2N4G55Y_gHg_${)enORe>cP`(TDqx4bYfc+7jG(lrr2D$ik1uX z{By`ZUSh7~+94W6E(IAsdK7UmXyP2B_O$4|^mxo#3a&)^zxvA|=eEqf{p<9h%l~Bo zLZ-r|3%GNR=S0MrOWei*xuR0R@2FI2VMtB%(Ps@>C46b-snJEHI7{p^35b{( zR=sL@2IZCIkl&6Y^i)9~gp6(<6BPQML_T{3Ydnmlf0Zagt-wKZTaF?T$F;ePep$q| zrQU1h3$ziRxd@pL$}i4_s*?>>!2;7kq0Tl>Hfx<_0)x;zRG7oZbPF+Pp=MbwOxf2l zBIGfCaUXDZRe};jlEDq=I)kz*A9wQWTjQq$QKkXIM>yUp!pRnP>eb=qgmuRjQBf=h zNA_p!Tp<04hPXEwL=YiMpJ4OoFky{4Lm{_`O{tI{AV!L*T5&SS0pG~>OKN`RLiq>Z zQ?E}S2jf!Z+y%I#?RCYM1C&~glXjA4T{=o0r0(qOgk94}`NnD=gHFSkY#dVsrUoFh z{CCA4yJ+d{QiY&TkM~E~A~~*Lr#36MagZM$HwMsxApQr;~Ww%xv-sGdi zQwU?W8crfFK=-mwG!If6?wzsjxFiv{z~-IwoboS^Gq*A^srPYT?1&fq#XZ}S%r|37 zrUMG8)Qe%U#~mdc=2P|rwExU)YWU7L{PDxautgRPsN8*R&_j2IXO^ITOqjz-&SP%F zwLX$UIIW>a_qYWG3l=@GCliXQfhgOIN2zlArbZnl@70t9+#i7A5A2j{$vd5rr+3b8 zwGx64N)*#MS)B6-3V>bJ0@C6ufE)F71Fp>Y@-bkVb+Azn9Lm(wc53AX1;c%&_cs>W zxX=$x>b%5dk?Z*{WJEl~77RXX01drc2I$LrrOfz>ix-GrvLn5oLOeVf!Rbj`nwN+^ z%6mHb3c#*2_;0% z^;6o8;1?ZjZSC%^L`iI*-*8Dg!C>GFTgGh^3 zN2}J<+TWaNQz&H~5n$xDG8xzZ*m_b>(seLk7%pOhBUO2!Ukug{K?5J<0{8rV4qi@n z0I_Zl3gVgLdOBtUw z(Y6J1@oe;{{rXYPJqUq&;gc_alh1MG|Eu zykKx+y}H4%{&=;3k{|mkG6$dEzmoZe^C=%*OPsJlbN0CR3^PokMensLS38<+3tNVy z?BH4#h@rXf1ap4a^&b}+TPRn`SWI1%R|xnXLfq|_(>pNX9hHgv7Z{Ya8+QQEY?3xSx}|yP&V<3M>pv<8 zTyKdp62k1;2~d076vAQW^l-|V|D?nDsy52TolU`KZ)w`$SnC>Ii~0yhG6vnIg1_cj z2RBHXU_*iA&~~eIy$O3h#?O@q%@1PKL2Izye6)3eL3759y$R1Ln?l2~z=xEz-@O@XZvM9!Gw-}X z@#8v5I)b?bi2RYJM0D2nhZJu^8^gAD;TYvb0$^#QK=!hftuSTtk^4A70;vFS6vGS2 z?nTt8A{PmsY6CI0eQ^h{kFL>!ae(Ygp9^n_ecak7ZFf6LvNi1N?BXkId(N2sikxkh zOYB(?wAlw_w_Rb^4I1m5RZhqf37rX|e6@t*dl_5)Mb>*$vR`UGHRSZU>`)=O5(b~< z8h4bCQI4X4^ZW(yNS-Inf)x|X8yVVKU;2PD#UaR#y`94@{xsOUnjW(50g${%+#tF1}4_)l1Y96bdqnu{WpJR49IS=24$4voaNa#(?wtV7_;3yeX z>ipr*Lgkr)dqn=0<^jR?7UvK!WwxzjyN$4%2g( zzvVFYb;FKWW;x@AuBoZeBV7GAQ1E2`o8tf?vf@o(hs(~t_rG^_A>j@Em3v147I3kQ zr%YPe8CeUTf0SA@1%3c<(i*OH_1aX|hmVkn2Cj4=&RR+}g{Q43Gr1d}_Z+wHrVY7i zK4FLP=A1zI%y9=Q8qepke{tq&scugWf!eV^6?*@4M10>S2yNJ281#ClLqv;MopRAp z{TkN$oG@M;GryGiO9n{1R;_v?PG7j%TV6j9RaDYwV+II6DQKeBQ;CFRiZK7{y@*lA z*7q-R_x`s~ChL7muzS7gBXQ;h4cOE)=)o}2Z&t9UlW8%YU18syc`scmt#_J`i-kz< zT|aEFDSzGcGG&R2^4`M8#p_h&IBL0{@;7`B)@cA82*t%s0g3mp-vFg|jZkWTK!#Tm zdX8=!&CcKfq;fLy50x;+@CZ)#n{hEnWaYU?IOz?EcMi#cYe~k3xl{%I9}TW);?9et z><{Xy27j+xoEs4`lhHZ&$XEY0M=*@38-7PFHx>-sTe<$`DgB-1a*5mpS_l#W(}F27 z-=f0EX?};sGaJ{2N_s>D1>awVREoFi9m`*P{^qUFxXkogMzgtsBY1{|p@%C!z&co{ zHHxdJ@60sMZ^82g@qZOb-lNdFnbru6y}nbjdZ_al#k)ak7zGQ}&3Gbd&d45j4N|e% z>Asx&T|DziSfz>BmM*V(jP(}OxF#JvIHC|ra6o^?oNKpSC$p$@4m6LV{aI%?;*RGKYXD3#> zpG2CHkU!Tf_AW(!1ytiVpWj=h)U6fQhP_pX$F=VEC~4XgYU0d&i^C{&SL2eCP1s+T z;I*%uB5sl{-m2;e`OA3Sa*?9ad&+NI1B$M?@Qyg+R{nI^4z6hOk?DswslPw$@tVK- z#XI@<)4hKpPsx7uTP<|NJ3TmpS?HQcY&tKP%8XoozQ0!J`3f6qnC(CeaUG*oHL-YMe_ba=_Q;NCx8U zp%&rWn~4TAviLM)=wBBau@`{k32zEJpp`i9V*eCzIqP%DAY&mR8C)4|yEa%<49L&> zSg}G-v*i*wO|--BfJWxK`8^jQD?9Rh8p>>HAe^1Nb8f)Beu#?*k(+Sqdu0Ck^Ji}h z^CP_~B^#z_ItnFZ4_Tx9v-@Kv6c<__!lQMDjW+I3#Q2ujv8h86N48xbV+0;Wxohbh zLtXl+I1VKgUU4=SqSE1Ckm)!_vGUTci(T;<{^-A7QyaNxwKp`IsLL96iBoH?>F$~n zJ>`RizPV_o)WCn3r9H^~(BixG)0i8Mqesj_hIG?;I)N_h!{Vo0gd;Lm5_zSGkU)Db z%6$KJ7rSpf@^yU){@T|xqw0ZeaVX_D+Mlx18E*R=s(e!G@ma+5Tl5Pe1MAwqZB4i6 z;^nAWCFYa$i;NR>P~HvLb~de*W1w5@8Zy|vRm0u85%}ftRFngI8PhA*5WQ3VmOfK5t5$5Thrb$r$ zkC1EhNq)Q7wp*9Z=J*ZQ=EMEt04ZBi6`qvU4ln*9_aP-XlLqQ z1HzNOiT!AbGY3Oszv(iN7-#+$$pw;^hH%LIB%IDgBj+?=`V#Ug9{rerrHLobAh#n> z$D55eROJ7qPzp~SP#iBScp%rMM;sDoPDm`l=Oe+|SeoTt81e-Bx;#K>X8CxIqW-}P zBt`x&WV!1MIb@G~aTVgo`)9cvm8-SlIy@Og@29i*v!BSVG5k#g&?91i9^t<~K=v`t zJoCUn4Y!e!Z*@1))rwVjwZGPL%N;CFIZEjwO&lSP3A$N$8bAuCqmcCNTD`GAS=wCU zJpN7m8UyCuW?`%cLF&dW-)X52>Wie-+`Expq@A_-y$j`Xux%v} z7kJT2D>_=jKvr6C>OJ-~WA>=*uEnIjJ5^p8VLy2LUmMr^MKmfb@&*kb#H4?c?K&@g z?+C)L<;lU;iw`V|=fl693nQF2U8X6BW%@I|zPh$>$i9ja27nphdXUxn8g)s07CO@L zHDWz1VfaU8Yf@8^e+qNhg?)?)VI!MPA`}>uMEVd2^${vjJ_qN02vyhZr9QC$T!?K)6;YR{y zpTFsDbC3MJpCHviIM-D;;-R>W-ajof_>);mbW^ z3qF#nIYPw=k52kSNI*#FD)x|>V&*+P@@inT#>}_2D96~Sg!Z(5QxEK4YNhR%e2k5q zRk66UkiRAEFldcB-5;_ZU&>*({ZEAec0oy!l$|z}gXEbOGxGWz^sV&MDa@S(IWWY6 z!)KF}f^pV8=YvvraAnFn^nbj*o@YE_h51F*TD}Ko;9y;f*?aL*_2mC|=(V5_0hXcH6KX#h`MvQARw|j${bNU9OBJV%>o~32nqF zK~oVI+)tdU?RG!cpA_Sm>vvQ6LQupWSj(@w>T$qO%(`Fqr8oR1XzJW|UbEi>o{OMf zhqjT?iqBU4VS9GEtG4_2?DTW>c)2Hj|9-B4ys0VN=STYW?fVhO6xXZ{)YE4UypQ3@#o^M~6$g|Z6?Lr5aVj`fj>u{Pxn zQ2=U1)p2?eM4?aN$hayciz&ERI!na1&JMxG912r~v}OtSS0(2)nw)4G)A|(g_hUK7 zfcw+}TEOgQd{QP1(_w(xjg=Z-usGKl&lT(qEPg@s@DBTi0SEr#11{_wXwKK57!r#% z;c5CijoQY>NkZySR;A82I(rr)p-&m3Z?5!9%|pjjt1JNWks3yT(5p{!R#w(W0P-cD zy^~!ST5aSq!eU`DOmyNKw8Y6P7zIlfJKqoF@WFCXNZMUK9dgTSjjGRGX_)rXfMRik ziC(vPm-6)o_NQKlVm-Zy16zubGsP4Ri|m|2X9M_;?HOp!crjQD7e& zrc+XsTBPS%fr;%Ohs?(+PU6x_UeE&?bRPZc$3p!d$)I>2{L$mA9j|@gHC5qAwO%U# z{+j|N`LUR9G4@a?$e-qv$4!l;g6^2t2Xcx6>NsixtWxM4eMmc8Yv8E-Io8DpsE#<2 zjH}dSVUizN_hT#PH$_aBWfAduyinLk^WOR zD60A;pkMmAU0q!lfgKn98Q&3X9&!P4-{1-ck}T3i1QUi6-6iOm!k&QYt9ljkM{5I~ zU7?0&z;xl4K+vxE!;VQ~HlDJ~V`KE)c`r~`1Wj<(1mTc(apt{;qSvphJ}I?;;nGAqU(GR)JyG}%v0AGn-*D96 zu8cF6zlx-AyZaRWdKi~fJKi)zdK0l`+?BI~25mf#J+M@;!(yW(W zf^BRJWfGqX#WVqJ#0mxf^Gy>f7i+NG!n_ z2cc7M-Ao1wWTxf)c-s4K&mK_+Ji&k~hNgirF%EkfL?adtOzeS~qknVO&!>Q>5+Wzg zkIkAkzp0IaB{A{{>^&=;!02b4>W7$_ss}?MlDtnhebSRgMX#5?5lNyHu)mV6`YgPkYb8 z%yFmmZdYWc(IA>J%FM(how+HK<1WF@erUzJU|{o=EB-M$Df91YwD>Oy;g$5aPlvFflXV_`K<9-g#BZ^*`ALI5aZ*@#X^}it(9MmfZY7ga7)=Z^vjD0 zpBlI!KZ6BX6oZIUOco1toQ0nVDGbHtaUWp)%(gcdsQwK={ORj#W?SAM zD=+cboDm%aV)O&i`<)=XRUXNy@ZdKE%iD&-9EM2m?|G!6EWgNNep~@kj4xF|``S5j zl>{*zF8W(}KQVs~OJILMvF*JBpi;)cA<;)+)&r2k@v#R-ho&%`2bX_SC=J`@FkBA3 zc~=C(vC%_HfVWRq^eA4DzPqH$0f-v}pFdYBdn8Q_{knoSV#RR6)#K&$-n)y7TljzE zNFq$Cyl0NES=|vJdO;PY%WE0FhenBY8V05>f69PppmZ+Yc;HMQk9Ilm4$VIxJ0i|- zjrOD}aaVzoQAven*yMHZgIbmTvR@z6%K-D$YR z$A^ddwNbg6>A%&FA8)|t?a-Xu(9?~cu}HZ*C*;?Hp5Mz#{(rMngbj*KM>awHzB8AS z;Y)G#;4ijoRhmtGN`E7A$}-jSBX_mkSMF<-fK(<2@M@pFM-4AyNs)pgA{sbQs@sdP zAe;W}cT?Pyb4Puz-2TRxr(TI!y#`VQpZOe(VRjoq{QxX!kor0Uikn-=JD#~@(8mlSudQ*Zy%Aky)Qtjhgb~qVYC>e6qQ#8(FLoFa8S~ys zUz_SNcQ+v{jPekBwqHV(ce0SX{A~aXQaIPISMG^R6Uo}^3#_Ugbxsh(XmtMn0=&8u z(5#tADBL#rhf@hv+n^0S^*0iQhU6~Ed%Q3&Xr}F_)_Cjoyx6_`b;v~D%ll5+rkZ%= zOxv1B+L~-jtq7W+e*<_r?c>tCg$ZXVy z2O=-nqoF@|6q=Kb=SZaAh@^Ft8u6?0#)o-H_0t1z2Fzts;c$HSW7}NWL!6{s&aC(w z+c%k7Gy8Kb610<|Uw(4_y6MAQg;JtX%SrL5oj^skU120iAgz2fc;}ijbt7&?&guDL zD|Pqy^K?^Ny$ywpJJtJ4^Nh>&KKrBRyd&z*pLQ5(kBc+vzB4cqChkYF(?_24JnAj2 z^~|xlA`kk+ch{vNK)cYyTIxcaeWP`GtrWVdFho1Tc$BL&jr#fE@&3sh8jc5-0oJPb z2*!RfX<5Ft)ODB1`kT~vVsfy&Yf-{neXQ|25xT(KV{rzq5$n%AOh4ZS&<>60N0DCkmO2ax^aTYE+<4#`mn_pW- zL{^0It2eR}VeCwp$;h`)&OxxJfT$>+(&^RaImg(!8fUYEf8F`{0_Cqjx&~{vkh1UE zKi6g+`RBcr8%WGN@6UVeOFzEfc8>r<`kn`-GSB0L_7gSxX~6gPy9}4E;b7Qy{c1CT z5=$j|shAIjtH_7&Olbsl^-t3(7oT0@`~m+_YK#95jXO8Kw}Zf0`(}jsl58^PiTz`0 z4czh#k178{|8Th(I(iV|#)9)ROY2iuER#DHgyTSFfd%9I`^{}QPlcjLl@i@L92#s# z5@l?RRJ>uIceVRK#gbk7=WdB4&Nrv_5Ad;z=DY?ukQ;N!jImPF^ki0CAdF%bpWU{& zun->!Vp^92FU!-8rl0NQrt6$11kWkA7sxUyA+(l_nyO>BKh4fnXsvLB${GHDm7MuM zRBa!}&n%cB86+WQ>~101@2puu5n^oFA}wTzl-apAPw=&ox%S`>QY&!jgV*TE_l77K_yOjz2h|KQ^o1%7YZPUOG5lUuOG2dS>cwg4);_d&A|A(htm4d+MDbg7g!cly(rh@0VHJw4%o)Ak9l&4~jOJ?2-dDD7+vXa= z@lEnNN1PX=@W2x(mNHi+35S4_wb!kC_wPrktE(T=ZurCdHWY%LLST}EHS(?$VE`J1 z`%TM9Lj$19eG9f1J#6g>U8+AkzxAeRodc)5BXFchqLTZ#k|g|Y9@)9edaN6f@uxJG z=9RxIUH@fy3`{OXBSxau8l^rzEofsRhE)z60D{KFgK92H4!vMKWO0Q|WtuQ)KGB5t zHTwMqkd7eyMUWlSyTf%GArP{!v!*lk?EUg=$?!}rx{8q@U7p{W$0MX6n%D~XGs4YDOV8I6chqgsQy zIyBk2h3#~F1}S*}zY5ebe0#RtM9}ru64(;9|AK}4y`~$yW{NGctMp`L=RDNtN`_!O znq5Gd(n1jX7*G}#7eGb>N#;$#ItS7f8c*dwh-6|J;HlrW#ZL^Xv3?J`yYI_iKN_>u zU3KQsanWR#?{C1X^}6nllhx1h^c^gLEwh`b3UKqx;Nakmlg;dHmp>Nu77Z=bLDS|4hs--6`b(ot^mA_gZs|J=7*?`8CcP$NHmMJ~? z3qcJ&t7~g5fUQ}n0k7oai`|%)EcXk0N{|p5@O-QDa zYaKX~2>ifDELQf?oNGOIcETiC#@t$RG627y-TE2B+8Hp#N7aO{{@eBX?%}^btOF4? zOfN5m$bQ2;+WOJ`d-tf?AqzF<0WPF}2k@#!z%oV6*PvTze6xDSa(6ySo<7FW`*Y)k z(WDDBOMb*f@YoM|X)7xFoe2r4Wh7O+)$cP-(t5wC>h;a4_}HVY#P+2d5x|iB_4`QW zlVd2F+<@_ckRp|V3&Y)Y#O>M!SGeM_)VpO=TiXRyV{blPO*aFp1M}0;Ow#fFP_AEK zo!8JV#{%i0@6f|_aV__j&B*3z&%^LAPosn3xyDSFAoCMI0_;BDRM~|ddY>a9ATXs# zkVJg#Is0<*=Ay32Qi_9M1~j5>#V{GBqut*wW^%@qy~eq?6*y%~AIk%e{UG|Pf>J9` za1NMXWHqe4*VfE$+jWoz1l72%sp}EG=wLS5zqcp~i@LoY;|I@Or1M#equ0ZUZFA|i zPMuy(JE+)WkXX_`X0SA*(ldN04wh|-)=|nPYJ#_W6HwBxxUQqr)<J)9WHOVb@GAG6`))?Jpbx#FI^;Y}u}o+Ew@n8p}9+Opz> zMY#-2C`6GeU=4tUg@m!lic`oc@+BhWa^!7gFSn7fNhj!?^SVkT6ge|9lRUP2l(K%l zM{MjD2Mn+)CZjr!xhQ9tbi5SPOlhNvO{eKv>?nYkUT9?3U!6IW3!qhCwUoUw1**>o$MQ?_E9u>Vjl{Z^WgCaRNu+n_nA?2vtz%?_x6p zV`|kLaDo^xg86u5;LU+O7&O*+LIzw4W;HW_{rRLfVv({sHB2TtN}F$}_k-1(*r&UZ z8-_gf>L5()ed_b|oItc!UQ{qus#Uw=Ydl99@~ku>y;hVKV7@uceW{77;?-D!db(Q~ zjp1oY<|#d*qqSta;|Btwl7Pi}I;PP7@Jovw+kts&VX6QUn$yXeRQsjU@hp0`r}lGZME<*!DeW_DKj(I1Cw|$Z=a>xDokm~u z#=oCYML&3kx35{OhY2BElrrbu3c5#@dUt1}PhQHkQG$I8=(}PBtzwDY$*T{C7wd#1 zkjg_6u`d>oiS(jVko=DQV?6QXLQZ|$il2dK>;%VwDB09r-awR@&)3E+d^erGD(SW@ zcValC?@5Z@_AKzlgcij})#zV6jHf5XWbbRmr{l#lt_{26M*BO&dA&aU-8Pe8hoL?yLin8}!rx z`q~j36vQd%hDsQq5=+~GXJYO|wA? ze=~EC$^|2=4iLD_DNtOxZFfqhERw?GpP}za+h=zL03Tsli61esM*G=s+I4g{U7mWg zUQtrI8lM=j#52fipsI%c<;Z6(9k=~^WxB)Gzkcf0_|2uU5F00_(Z8#@3=6p}KkfoQ zw+W!KM?QjMWqVsZhalL6f+mD)-JcG~B^MW-pyljMUj6e&U-j6sJe0MYTL|<M2|XR2qLj)f&`MNGN~xxIgrho zmCj7u&It2hyY(XR<&<&rv(CO+iQPq32@cX4A9TKM;XT1=M{-SvC_$YhyJuj{+AHIa zCMXNSvT_DSf&_~l3C8l2(Q8MfQGXLgN`zYt0assSWh%x~bgqtuqCLp_jEAc>W|%G1 z$poYEQce-Bw0A>UAU-QSxDc4W>Zc+#E|D21Pau*vnr$XeG-O58XQ}&oU(T&{T?%** zPfM!o<2)?=RE6gMY50Z6FI4ay-S=W%FT!@JrVD>uFm8QSOs&gI@20Zz%#7x$xAQQt ztvEX|p+t}7gcHb@S45SjUOcow_M-`s$Rlxm)k<0H!? zH@Hwr@cA&MWXnyU*ekmwI&Bi!+@*d=vmX`%=8DDFLPN9) zA`{z0oZ?9s5)`%lTX6p&PU*o2iWtvEB|*)8ieqzvO}UP{ZCG3eq3Sqw_SlvQ8gk^1 zu3LQIu|i4{up=7gmuF&|sf<$pwZ|y7(&QY@Z)A}hm>ynQUSodW1?gK_CyZERd5Sb3&PlHk*IYm4m80$)2{<983;bIqUTz$m9+dg7j+0ND~zrR@Q4*^~pu z#SwIsRIFYtgZ|_!hfS0T#=)pAJkJ^!KUu@e0Z?vKTtMqpL}H}oDY&;q_5F_JT<^GW z9NE3L+p5;)AJT*)_yr-5fEJ!MIX;9)wRP`FhxEn!TJO*p+)jfvRmyHTJSFN#5TnzxoMA)4*yuEd;T zcsoy=5+uCB%kx^#m0gZ_75DsuqgTO+4nrZ58AcZ`uLR)~dSFLJSlsf{*}3%eFBxfY z*tn8-;&R&#o?2EIHM)YfFvBzohoWMkkRt}fP4Q8U=c8aYH|Pvj2J#_7xC0(KuhErC zPa|cd(7I|BO^`~PrhCV7DQ5&FCyyCG&0W-pupna={cU~SMqkTpVhhX+1ZEFGI5VVu z8I*zU*{~A`7s$)g^-qU-#_egy(vDDHw`@PIXv2Pfj6k6q1j4A0iOj>uLqtPV?pW`xM!bmIua*ZYHB#o zAIO^uNLEO-{3(Bt}uA@@Hmn7J#*>HimBOsA5!2QN&&RiMfXp^zG872mK3Z8Z)Q%IAtIPNSgWIfzjux!hc)-Fb-!_O8S>q$Di zqgI5AZF~mIYXiSII}DrfY)7V{(ERcjMx2AX>GTZT9=Z@aaC4`p?fB?5jjXu~@%w*& zwZ{^2JN|n~o`@=*oAg9jw?jm~Ra?w*lh-dvV+#D@#pT zg1f7{LqIA^8mmxPDaxNE&tj4)WWeBuBFv$Sq<{9+dk4-p>uAYjVGFDXVg(kEj+Pnc zu@q9PZ2ut~AA-?;$Xr}}5vyiTdIbGR_1r`plsa&?D~uh-g(*v~?-<8faXVd0C1fz5L@JGY0 zwW`VkZ3u#a|H2@0Qt)K@ChrA!B6hu}s!I+Ye&p7n;A;vO6(d&&BA>YU2TNZuzYD&} z>ZWYyrsMp=&C~LY4dm(RDPrg3;A&;*Vk6@G#x{BDE*k_PAk_y-x?U-p{@#9!%439T z-y3`~h-jDlbV|qvAho%%)ua_0KO;M$F@@L&7 z7dYaNc4?16s$im{qr3i{UUTcy(K*m{@7ZU!Y)IEcpQNPaZ}~LzJU!5LXn9Bb2u^X` z#p7O-2aG`l5wOCo1c9%aul?Us3&$q>0o&eEcYoHiw<=aYL+Q_7CNv=>)6w74gD$)O zw_n@G=0LaeiqWl>yy`D+n)^Q8TCD>kF&zj=w@TI`0;U@Joy($Je!<5_1AlhSK84?>gynczYRKGG@@ z5~5UeFIq`SoeuUXB5&<{`Xd3S+(B$s1Vn-hm?$Ywlq~PPn%QmIqE_DtO@+_B$ zXQF2++H_SLzmf{p=IS~AyhdVnjUxWigVK|fd)yORmcRPSiE`JG{7`{oqu(DcceoZK zYOwY4mjCGMc!whUXY{U}TP?Rq1+5V$=4LqEo{%6Hn`NsnThiz-~B?RK*ztJZ@VvaAP? zB^^p|e8boyHSf|a4=hHpO|H#1Kwky9@4MH4`@|Id!TLTgk)S@~_IJHIU#{PDbc}Db zevkosih!;*mt-m5=RJeN=L&I5Xhme&ubokx`zmVAHMeT z9l36&ZJR_!hoH}P-H|XQCFOsJH6 zDfCz5U`W$D+v@ZK^fEo0;Vyyg&3`$w39C0@H|^22 z%_Zfb!R8Msvj{mIf5ypP!nMQ?3Plt`uLc+$M>sOwvsh>EkfR{`9mro1cBqS^rm77T z<&j8yL!Q8}L$PKxQPRNvw-mC@wlFw0${b?qkr`F#&R|Ptx)sIba`@@S_Zy6Y2*!Kg z?tfdVx|DC-A=l=#hwz#9P{okNA7=D1UuqgAY3n9r!e|&UzaFG(1*h|^iH%5h`4g8*C?u40?h%sC@MbSbmL-xjKmRL)YWZO2&)J!*+BiWjX?P8`xBb;8 z_+D#%F!bl!C4FMEhs<|NH}$?0l`oH;md@Cr)5P|sSOt$~@M*k(kOLxC1kyaV86Khc zD;UqWhW^|x5!q0%f#r!Q6l}V`aAda7-)X{sBsn$VETqIzitnXK-5Gzy`u?PJyxg`! zj<1I06usncW@KaCSj$CaBq!$JGFAIxxXz|`;CcVW-$3#Cpj`3;pI+G z|0z#+r#;Poc%$BkfgBNBdKuG*U#19C3DpI2;WXNOuAyx5^|p4*H;HYq@jS+#5V!K! zUl}0S<+#?>Tr9KoaG%y!G9wZlmGuG?pSJmY(&HLC$KHm$(JF&?Z;#{CjAm`uTVs*_ z-dT>YD`JY0hgV9PzLI0rW>YBX^CY#`NUmzx_&%QB3r?@zVIw`jw!V&U)uh1Y^R`}d zi=q23<8h8hAr#ZB%?*XsppXp&tk@q+r&8Qn<=EmVmYgRv6 zo_E*QjN^fO%%IY*xy$?-V#8});*cdLIb(Cmxd3haGCVZcq*9-oNRI)sb)5S4{JbCu zZ?+SX{)kxUCc{j8LJ?Qgd%fUv|JJ)a(e%)EqA@oV#^~kF!k@3g04bl>d3K+ZnectQ z5@zQ(N9wF0$-=$4N71>OoMr-O|&}LlEZN{ejQdgStU-}7#GYKolCl;l{m?FN+ zt*_@)B@(}v2xTLQD(s4}juFeVM+=HvQHD#vo_E?RAKSd9?I0l!fpkNkd=W0y=R8fT zCnq*}#1X)ZJe$iVLF7xigNwGw$)$1+P}gq{isX><5VHA`A|pRsVveSP5wJ9Kf{UIr~Z3#tT!Rd0{JihNmV!Vnhgm*+!*a=!{n^{^xj&OH{Wx$Ni#po zyd{T%&R=vVacmD2nfzV(`XEchl`&bDdKlpOk_Pa+J{sZ)?8GPR~7ueXPgf;mO)-)Q+4WP z{5ESkNmJdU#ftidhM&Y=&;3-o_>ms;$!e}yRaMnj%ddWMF>!Hj!9<{%fWZHLbC1c{`=7tUT$bkS;jUb1(S)`}eVA zTz)$diMMQv$sA#&#wOQyWTDM)(T11*b~{CnOsbtGL&#`3H`sp5e#y<{Vv~8ZP*@E< zOpdt0RTQFSo2oAr4i15?2ch%G1a67)_iNwShY@Q%eHznOWKx|=!+Cc^aDlQ-OxAsE zAGbAGo6G%OX=j2`kQqbCP4(ORR~S=w3HJQNR!~5|IQU1$$KHD1BWH!* zQuNJ3%fb-ioo?yr1yl6dfu^3m{%zNq2}Uq;-&Z!Pr%|ulqq)D3Ux(6m$SO%v(Vfwj zgI#0`w5hhJe7eA^7~e(=jP|z2EEz`L_t5k#+#Emma3nmWwCAI-VYxez%AD}&(RR-j z1;69Vf05O`5neU0cntM!Q^9u@eioef=y;FPqSXRdDwX&{(fo%kr;<@ZiO1at;1%KIt{DNYi zjO^@ef60!X`;Lx|{jcX+C*fr?t}M9}jhD>cBY#b6Q{XACF0PkgQCrLDXjJkoy)bpJ z`l&dI%Qx;mGc!wryKk1*^M_6drSZ-*oE?sr2nq?+jo^$;TEdtF-!ihW({iNb>S68q2`}xr{IqE3CjJm(9mjY?IOIz>{iqEU)GB0w@lk?oVJB`|$ zyLxex9(q+aMn=>j8X!XN$)aHNwq@4lhcPq%KvNP>yJPUYUy z44u|_gNiEkLV}t8QMAd-9xfK#Nly;F^BgDYqv|L6U-N|-2ak79szp0~6)(CqvNTG& z#fBA;K_`9+!;0tsq6G5@?>$oc`ujWSgrt}Lalv+3R^2QFa};~tl|6@jR|L!Zk3zbp zVcVsIw+XUenwipfqmt2#REkjC$B!?v0v4o*X=o(a-sWA6epDwhTY^6Pa6`T3du3&% zlwQMh<&)Mp8h&ezdrimwg9|ts4q0~PQU*qWbkw9_4huto}igt(^1@4^^A+@z*-;z=_3gMS3wf`az zhw`9GOGCr8+YP?Ldfy~DuJn(|sC!S$w&7-nW!kc~Qb&4=WGwC-@s;TbLaooG#_t>QZC1zwr9h7zvgCRI_KUvI6a zGbhYtd;oK@TxM5-7&3Yj-q)vZWdYhtPc?^&=;uvhtOPL)@eV9k%cXIg){2M!!r52=Q zWMtZ$YB#@Ki@uDZLHf>yu#jpUg@;_!LKgXdKQGs2JT-tC_Cw7T0sx$u+F( z2Ooxy{9_kkwLjOKLUsN$H7KcXoh(i9fkOvq20A*q8k2Bk0^!GU+Ipwz)+J=+dR%Pm zn>kQu&)J_(rwjVVxWGnch-}UaP6*lzBc+x^zeoOU5E6XwBTpBvm9XA^HR2?BOjxpg zn$l z)sfC@lASa9df=XZ*ZWPnVabQ_&0?Q_zgSpCet3Qtf|v-?kvL~&H$4Uy$I)`$+QP#3 zU3bIRp^TsS?TH_IX2eNgi1yJK8Pdi;UdYVT0Yg>lFkD<%(r}V5tyi3G``yLpqwB-v z^dEmg(jt4`l7)oML9?~>oZWPGdk+@7lZ70%+ByTwA~zBXBV)Mr-jqnAYUv_odb zUrvgqapXm}-;~T$RsI%+ik(`@bIY_3za5?R*}vQsb~Trq3Nmy1tE{Mmck&j8rlj=A z8|5vVgJA#_Y~z zcC6BlU_;Xnqq>|W&JfK*k%lW_Bg-?_FEN{Z*-cnARWur-y#|h<{I@b-}uf zIVDw9)ie{QA0cbgG<>k{ul1oA0MCX6XlT#9jE*4{_a5x9dG-r@Ac3aa35~3$&kFu66E&Ij*E&PD8IAH+Z;&vBtx=JTDHSAL3DQ^qOEOus^erfSR za?Hs3ol`%BBf0H5R|>tfi*8rtrlG@`|8Jg%N1hq-IovSv>sObK=NXwJ{&cvwhufE) z@(LO_2g5zw9N+d@$$UqNNMkT%BqB!;cM@Cl6PA^f*9+_kC&(GlLglp4Y(3{_rK%`) zntVGprv}_o%M2OhF4;xC{>Xv_QBtdA53Ael5M1Vzb<2~{TOu>LAtyVx`z5PCFXm?* zVViL7EV#lMb#ih6WH!NK$bGej0v}$xRnxh0luM5M7W@jfGZHsh{rT+cOnNjUz_|sb zrKLoAGhT-Tn=!28__wyPDu-p|Nne}vvXz#MI+=gUB1k0r%%Fk!8LM8JF2|L13!e>& z5-w+zKC8XGy{Jjo9(m=LUNpK#>F0CdqOmaq!#o`)r>y{fot#&J2R-Q|BqXU<$gfjw z{X@0*Q*?b>vq1RIHis1D=jR9ieVIUN$}miUl!WcC4X%s9`5^J3w=-9R(7JqZ`X5j+ z`g|{a(_?EwRpa=zL2=7!*{|LGk?Hfp>hVVB@QuB{iYF_dC%{$55Vb$g)To~H80Rq@ z*w1o}=^zms(zk-*RM{$p%3#gR1u}I9x!a`{vnk!;6H{soA#0Y*FN2n7KkA;@H z67NTzgoo^pd=xg(R{%WXG&AR{%BbQ+%;$6Pn?VWw0y^UfC-rvJSxse_-i!)eZQOT%&EZEr82 zwzT2PzB|NVh0(j3OQ%K&!G_K#OqP$!qic1ki`?L5ZQXZ6xG2x+g0Ic-IZU3Y&(NW#0 z)tbg!8YRiV`*aYh?RRyS&}UM~($0SbgoSw(`y~;#j4vZXXh;ayOHIwrD32@{@*}xL z=SSg0a};h-M%Sp=<4Ho#YU1!6nnDAs zYXv3eyIlquMnyfROP^zz=>7yC%N-0iMP)^=!JX#u$MaEpU*T>~{{9{M9dnh&>dQ~U z_Haph%z3A;M%|X89C3zbqQsZn;dNfF1urrwUZ^YXQVhV%2X_w!bVBH=yD>f*;0+VgzQ)x~j{9Hi5Nlqb zROlw|hK9&evq`?R0c1h2kCz7Xg?)|eV1RM ztb|QdMIoQAWasp(y{8Ae|Aem7nf-o{%YC=^m>fIzlAcYEQ@|z6%U}M@`ZhpYle6}n zzwHNixr1Qcv34w{?`GBT);1^+gNe_|&*BpjY6*wcSof^|*Qb-t&rTCEH9mFALlOpv zIT1{LW9J`}vP*7|aX7QE3RQ;q=bW5}q9P(U`d{DwRp-6ezHkNdDlDp4ExX10^o@G| z&VY{Qrlbcw`?S~)8|2^mo)yQZnRb29w{o4hQ4x^*9&Toz(R-~VapZ_gIKoDm%S!_0 ztgi0v>W3$dGL@=BF7JX?%WCuekMrUlUEZ&B@UEd!|HQ#TBW>q7t~s`5{O^Tap(41(GKQi z1e+puIsz=A z#pPud&@SskN^{PHe-WizA^$nPYy{Qq@vtCQ2qorN1>fJXybFGA6nDbOOk~nIeT}mO zE)et61;v-A^+!_lr=1sJ0`q= z(L^Z{glWI7$Qd0aC2C9q(0n4fhqwdidL>lvtARlhbWMZa{63B-vufKSo~$>Teyec0 zQIXP}EWNCCbTvMi{XjN?U1pbxn6gf9HsJ>x`KcDxog=^fsY^cE&ew@R08&=F_=KqY z<6jZoDI7aq21-l~+zmsgD(lvdq{2Sj*(CFE%)_jxEf~=x{m%7&%#Y1QosLg)GN#bj zyWV=yg{Z>z^J4|vJO2C;@ddkM7%{S+5CMy}^A~gIBu3hK9?DA4S-Dam0;(K_Ux1Q$ zH(X$cAnE!!D9GIL05)Q%D(4Ekq0gU#Y+M)$G<`yvX))}XR|KX6zbchomp=q|M_5He zwHpi|<%-+v}DVRZ~+dP|lbsc!?Tq$3nAY_dH=< zbTL8Crqip7V7(U%tPk&;P$(yWhf2TnsU^9}Vj5njyh9|vtxLUsX06Z;YIa41X4F+_ zC$67MXk>Ddth>FfT}Me!3rcS-E-lSW++nCtFCz%e$X$9rK$QparR5={wM5t}{(vJi zZ(#=u3_LR^FaJl3NW_@-{#?vU+>o@cpp%hmn|t@A>SlCy+d04v+i6{0Po}8IeP-l5 zHdM^Zttn*Uyj8wkWsynTEzrt!DE_gO%q(oIdu?RfpbYM{gtbya#%S&RdAA04DGC5p z^usy&x&kE7*&ns6suEBmO0RQeruUt=o;He4BgK$hc~jA*BhK|MC++W_8hmH%YjG(l zemv|XjjSRggzh6FzGU4!qr^GM8);t-{zG+YWPK07l?ed*!BJHN>hY5mcj zsyWMl0pxqn1fHe5>l+BWfM_ASsS*hNgu4>JXPlb6o>W|RuSs@zEq}$ASu+w zhxbdNw(#hfac?_W0gb`ILAQ>QmdmL2HNY4=*9N|J zW{4c?2cd^dF?4wJ=xf0n*gO-hQ$W0aLl)DQSW-OdZO&hxk`r^M{;Xb%H45cGRJ+HU z34O?JGxMBuC;J1yr2w&mciS;9qE-*FISFc9mmo>#CFFDRH2 zQ&x4jdk|q@4pD8NS(uq)=_gglryoDxp{1K%LMOIGaq*_&XN%31s%W`D&%c2D6D8(~ zt{tLLhq!xQWG)jDYz2t|J7d(S+^DLo!@6qT>f7cAY?jhrr!H+_Nu`v_9(w`T@K7agZ@F65|D zif5e9Tp~4(JrCW?a3pLAdVamRZ6CqFVO9z0v zs}K|!k_>J`HyM;v__&kb-kmrjh%yZts^fU82&dcF={HAPlhz&EL`AV29NAyAbAj|H z8sgq$5J7}2eTL1W!-O^J42Rq!Hl;#-gcvENYsJYR2Ye&jZ^?z(OXVMZ&%8c=8j4Gm zbr;~0vey+~2~cb`PTEbLbLl8~oVvTa8+Jn@Pi0^4}AG>Y}B$ zM-_rTJ2@C_i{!Y5o!+Y4!9jj}+!#O$h7G)wA`I1sFbbCJ5~sOyY^!mbR;};p?Fbnj zx6$YL6!qlWsyZkWnUr0@g8ufHYet(rROes2;9b|?sI(Vpz7>2GP|@EYtCM)o%xvnbxK%4V#`Kg3bKC#K zP5X4+MPboEKX+qe!>T_=-AV_g%!~*b<8dRPMe$WI40oP`I`4}+GI@qYk4rOX-yR~wHg5f?h2b+s+T<9kzbzb5! z$c_A0(jp#Wiw0jbfQH^J4fJKbQf7R`f;;;8z`O zZSC%^#9P=vzmbx5g2CW9$PENVz=G}IbXMt)E(s)=-H~tsMA;e=V`jk2o!wgKBhC=} zA>FCrRjS`N=mpx|w&P@t6z|gm$Gp6}o2nmo$7}ziGLZeWTcDk*6hvCIHdeK++WziL zn?f=3m;fWUmCm@?YwJltN!P)EVYrM5j#S}=elu7<0S$bN3*7S$Ie1x_Nx*_X6tDkJ zwqZS1RnUKN8ly~r1vK7TRt13lNcmi0n~iBYUHUvd0a}RVg_Q3dTgyZL?m{=UDUj=e z^@ak3j_oF=$r?TSgn{ZzQ2dTAcHVzA<_WqSEgTo^LML6pe~6m>PATK_Cfc@OE}qRE zLJvq7Xm?$M=UrwAs#nXEvq6T$%*xkX#@IfIb z!BqMFpZHXxIK(WFuL)-0Bcz%Po|d@S?%(jp_!+ z`jfQ+N`CC`$Q*qBz-s0@&gXo1Epfso&H2;5bIb^d7QNS+Z0%UOEo=pnw1aD1B8KLF z5X|{uH-BDgY@u8&V=;A6S|#9n2yypb&-8SPVxQ2QcE7Rn%7}LzGykFiT*wJm!r2iE zGG))%wwd-L9TYysrNu>leM~y?UtmzyUfdx-vq{?U=$7W?`;!K5ZvLzwaQ#P|kq~Cz zPJr6urV$RiXGhb{{HGnx*R@eL?rict`^z&9Ct5e~TGYoll5yxB75pvF2Dm{|1RDw@ zhqha#>mAt3ael5uXkiGW23mvlmiqQ3mV2xU=358znz8#Mc)Z_WoH=CAkEQ)z#nLe| zGb>va#Omkb%lo%!n-siGW$DU@5s%wd_so+ZMtVZ}VU(!-+`XEuS9E=-5D zxM{fhyu$r&sdiM%LNC9)o_{E@c%<>}qK@nrn4j5yEner$vpIWucCHUcTSQijACR}b zN9sOljGX3rKq(#r4TN^18%JSC_tmo8-wvQS=eI_3)K0sF#ui>t#eG?iOHK9P05bC_ zY|fgiqH!2Ntx%!{&_J`;(s2Hid>|flnxFe|R(0-1*;T%)I{&#gFSK=?LZ$ zAo53=646=PA5r`l+8DO82gfKa5dcdY1G1N;Oob_%kL;&O5=a?Oy!^=;zixZF|sBlC5E9XBS^#+jGwBSLAH7Qew}7pv^uc zyXOkKY0y~btb9tANa#!u<*Ox}Jj~ekFS6dBmib!qxgn?DWtR%cl`!-?*SMpEjB*SO zoae8ANAf&t7Oa?D+04+^`q~eaDGot??7bXz@#n$j)%1{c4~Qfs^3s*o14E#k48d@Y z-PrT|H$kAyd*Wh0UGr4+0_8Mw{u;N_$$9c$c-%BFhJ@bL?8qhV3XYLMrOqFZERzbMhspIOugMugXzc~&dA}ihkcDT&K2mgoH7ZcvmUwe2QU;!7)c+RAiosqTp zhzVXz2)s=Q3XYfHfDhElY%B|JrzkvrU?tbKZqE0Z2$Nw`|$r3 z%2d5?33k6vZ8XljpaGkj20b1j`ojwLbTTc*vn%X}Gw+ovrS(pevat~9!<$D9Hsx=d zUZ*T`Q9fK8y?m3(97iqtOYXMs;RX$$1EILMX&~_)4H%&GZV*cC56SR~LNC#cW7!!z zfK*OJ_EHIB43FV-e;Aj7L{?vlgp=Nuc<+!LxSnKuluK3M|HMy<_=X&p*5s8dsU#N^3S(a0Jh?F!XTc2UrISwMKFE^q-sN z`7L_BBK}`RlJh9^Zl*OtV{h)3tR3k*Me%OZ8b-lFbu*sbGG}Cuy8$U%?RH;H{vn?E zEUeN*Z0g_MC6*~U>F$r)=ON7q-&fbA}H`b!k`^sy;JuYws0XQO@ki01CM6y9oQe~yw0i0~+;bB;?OG zi@i^gTLsnl-IotmDRt|`wPF9M!Q)!@dK5M72{m!%zQtjbx@&RC$tLV?OYqv)&JcG< zm+n^eg#2Z^X}LsE={@Z?p#eo#U3yQPaW{XaY!_EFrEdE1UFx5Y`@H6Fe)CQ}{rvEs z$aAva16GS2@lKDAVHUb(5?juTrqZKV-#NTaNs^>@H^&W1s@pYoG>1^R0#~j#rDiE| z!n)FidQCvPNnM6N%VVl+RZM_PpM?DUV+x4NMVnBXA#EKPynk}2i zX`&r|A2c%Gtsl7v8JW?SGf-wz1L6Giy>kQZ?Gs!?i0q_Wzq^V&$Y$6eRtVR zv4Q_6OM8g>iNz1==P|b($BvnW4C!X_bOK#AM#Rs!2*+fsByx(AA%XT>l==ScE_UB} zUGp1w4Q$OtpBm|C*KBh1r1O_QL3pCLEsll=Cu zZFjGn&+{9uFNFKY0aCWCB0MFd9bWuZ_G3!Aldt|_iH6tC{ZBe5(9YDp1%xMk7yH>1 zXAXwOe#d1nG0yxik_#j+4dIaaX*ivWM$TEl%oXHyJo+gCOA}9=L2gH&jyIcVsL20I zp%|Vzs4!7h@L0A>k2oaGoRC<8&qso_u{_7UIP3}bb$Ni|?8?bJMg8MfNQ(U5$a2?N za>yR}>N>=c_s?=ADpzaObz~}v-cM)i*8q`QWB9uWphv_2J;MKBknB^OdFG*kDsD3+ z-|9i6s}-y6+CZ)6wmVp!vXoLqnm9rn6LhEWEPxbFM{&!yYwh+TWodJX^Tc=Y8w{9- zTZOS61j*ZXeP<*;sx6UPbN9#DYNO(-2!ImFvMZuYlXlk^_Aiyo!gdrvT;Nq7t>{<@ z16gUonfLg&jJe~o2NqNM?o@eYgoEIne{EbJme8oM$lEl05R?9Cw(Ek_!(#})o+k_2 zC_c0-UI_nwA&hX|ahahYmLACX_U6Xo5&IfS7yxE~>p@oQThtZtIp|o&*NF9~gyA2V ztw~Ku{u#_+5B4c4gpF(_iBMor66r%AlwTgIw6F?%)n33Vuv#|X8evt1<$_o5Rt=ju zn3$TTXiPf4T3?7((7X}!yrTpshZcxIckJh8ozJjS6&#YSI3cGL)X3|qR2sjYqd71Q zj^nq-2vLp4=uvjua_;&HYi>*Q8Op-Ru1KuZ+fG5BIc1|tfkRLL?0Vzh#7E% znGKV_yAo7LQGR|^8J8K%0u}PlDM4Zn{k)bD-`C{5obq!EYzy^I-}9L(-Dqc~g5*k^Sy5gW35@#cFW6J*uEvUmY{IiC)SAT9m-?+g$}GNL+_P$FE>n>mbW^3qF#nc|yf0 zk52j%NI*#FI`)W}V)g?)@_Jyj#_adDD96~Sg!Z(5(~s?6Yo+a)e2R^oQ?|Ijn7=LM zFl3E7I~cZ}Sk7U${htZ}?1GXcNjq&Shg;`b%*dPb(D%~MXE1jbo1zmOrmYt>c-Kj>iE=eOQ3{5 zR#%q?pIOKhIv;0F`4&+=gCp=zDey4%5^!J}J?1{5AZ zX1k{#ySWJ>CaE%u2BE;3xqjhma2GXDC4YB`h$vzBdhd${5$PqvNf6_6$;N9hDbgKx zS&u0eK0rLTprvu=#Qc%P`Sj%s_>T$qO%z9M!wJ-b^XzJYe-?HBUo{OMfhqjT?s?T=) zQG0f}tG4^Z+{{b0c-d!u|9-85ys0VN=V$uOoktNT6XW<3+8@M1ZQ3@#o^T&HWg))l?!$=~=j*ZcZ@iwInQ2=U1)o^+d zM4`{&$hay+i)px6I!nZk&Mv{m912r`wB`tp)^06mG&#{Wru8e}AH{Nx1NW%~w1BxU z_@qo2ro#ZW7b`ijXmO!4UMSd`Sp1^s(S7z!0}lM<$6VNX(422TF(ejk!ZY;u8?}v% zlZ4cutV*5lboMMpLZ36n-d!7zT!2of)>r`KBQ=Zwp;w>etgNh00Oa3#@m^+ec&(Ak z2#bZqFwu!`(h?`HV&pAZ?0i3x!-vX6At`scbjU5QHL5;$wPD6f1B%5FCi~nLT*@~d z+n;$Ikvj?;0V4bg1hSUm%sJP_htx#t9{|C^&CaX$f4#TLc^b9-N!-eV+m9cc{{qWO z|MwhngoQpq4RtMVhQl$ia7ozBmS5BlgD;o&xc%~nNB<Zz^2f8teW?#_QMc4&kbJI32l!AW{fvlYswK#GgO zRDk=83G{7Ih4QtY;Odvte8Ui&dCjDRY@k!f{f|RVOiZ)@4|@Mb9tHOCQ930>sYQCO z6`0t83CMiB;xsP3ogf7~@`%*Ioed2Eiozvu<>^7maQ?ud5(umEfAA{=2u&W|mhNe?4w44T&u@YX=q zKJzc^6^v;FF7@Xr0yYcCYQIULvihs2k;gbGY3+#7p`0g)Z;J0O4$Eu;Ct_e=KnuGo z$OC)4EPT*ZArMk@If`Oa4hYq{K2J3+QMlUK8o+yp7tQ#&rvP05yF%jF6NDME3HW72 z+`yTS)azN}|LNinvhiVun?H#l<6fK7$N*ayh`x3vO&bCX&U6NfdCPaPKbJAqL@6WO zL*>84{{WMmc(Y}QEB&^kF=}52wJN(>vvu0Sb-qJ#Jc`PnM0?cWL7Mf-Yp{)tp-kd4 zp_nG1jaZ@Jz27yVaJ$_MUuv$xM*7AuiWJcbf#1^Gru;t}_XXmHeKvut~rHZ9l z+PUE(H80N=6UPZd_NLFjUMKj_KOy!}|5^)BoLp>p| zM&1NdZ9kCa;2@e#AAE9})HeTj3h20RMx4!J-`4J?+#=|$4FL0b6Py_+h}m_J8Z=N| z531<7CvdC*Hi(6EhP^1Js9o_7U6X;izw!y;OyXJ$^ngmG4y+bM=y~6Hm^to@-tC(7 z3>ri;#+aFyq%yapbKE7^*^jJv7Y%H_am7DHXJw>^9ZFxD`-mAO(V~WonSJ)kL9fd@ zB7pccC_DsoPIwhSpjZ&aPxbWPwy!5$F2vXUU(*#j%rYno7&#dS!}>&&ajFrU8@G)uFmeNn7z5CJr|T9C~E z>SLjXuyN&`yCBLDQObF2)s4D+%;y@_6-x2HOV*!%#{jwcpW~LZap>2V6FxU^Lw*Lc zyk{+5nioCf;Xc6;gu;MDfKD!6e@H|IzglP%ae5IquCQz&E%&swc8dL6#uP7mwwr*J z%*AU1#r&`!@}y#&<^g-YI7aI;K?FJhD4FiyoN$)AYC9=Cbs3Yr6>$}WjYxiXeFtd> z#RE`awjbXAY&-kte(etM(~9KW6{-JRDD(WcZtWcdC&r+~tU5j33_=R+2$aQz25^vD zPcc)Ul=0%BePF#;X99bl6=SWV;jY$SrrD=_r6BKsXq~YE+CTbSbw}&|@V`j8t&y~( zq{qBx1B&h2Sb~BpI9zi52W|K3&&eNv_v>Esuk|XntGzuhKx$KyqAuPdgIsBu$L5^q zFc703h(729;jQvWPWi`wC|Le$ILcv&^!|}YD$4SkEavAmAjSAn6|}EkAlF+Uro%;l zH}4nb?@d#TyTv>*LWbhu)$2hh)dZ8LpB4B2C^9 zfdZzSOrQ^|tA5fq+lSz|*>~l&jz+9@$9A^rhi}NjGnkItComq`sJ8nJclr46(1127 zS2O*O+R4*R_<|jplN)-z*)tv~o9Bf5R?zcjMbZCnma?!xvFYd*h~IbSQZjrkt{(c$ zcB4wOsbBGLL{3?zT7Kl7w)^TMtrC#RFqo|*NB@I#EWI%Cq3z>Wq+6Je8HtPLwyJo+B z{rVw5^4bSZcPs5>av%^I$~K56ZH5ecCyHkKw^qH}oTa=|i`UO{(@{P|Ys5;-_{qau75~i+BO+toU+r&GIpOXm zgoRNaVb2drsPax1b636(f-3e|w2lrK8RXf*6f1{w~0qD*?@#iG;!( zlYcnnP}NP^&@+D{QD|89ik!zQ^MYpD0cwr^++G&Dm%j~}?0@~pN!wHtuas$96G>Z> zZK?H9O;&~!x(lY%A>+jjU&78iMK}4^bHun*#bq7TqC18r$EXp%D{p^XxTSV>2+n}HY{?%@?0ssRFMEQ!C7UxR{?7JYrq=Ai ze2WC_l<3!AoWJk*Fjt`zX;gDkJZdLVQEk^4NfJma)raoiP@-Y5zr z6F*#+ivaCH6KkmnarTeZ<+W1is=yHK2;(uX(lqLqLnjBP?`Sw4Uje&nPtUy(Dsl3L;79>rZO+$g!Yp)2Wi0f_PYv~s^MVRas6g9i4sdCdaaNT zhO5Ab@Jwk0b+xx?jf>B&ap92vIJL$9r^fx;KiWaytbHrOd|4)$^VI$+wFYkGw#T&p zk$<@CEFC=vabv;xndOaXESAX~3&L?Av%rFJ{`2l0oToxTq)L%)0}c(fBZ)FLM=Rd3 zFSy!$q+-dg?R`*k3+J0t+Y5Z`qIs_&4&>&1GGnad3_Y0@7YL)6#b>uIEiT4Kf|%CT zz^ih!W9jGnx#>C=3Be1>?FF)oiU_S0qo(TEozHXg6=UTqs&-?T7_3`P_jCSw2uv=AbpP={n5(gCqq> zo|7tYtq#7sI-cNbBXjM+AEZ{`(g&~6lkW{tFz^H3iN9=|6xRVM6Y%nTk${kp&?gN2It)WC!18&K&IB+uz-wnZKmlzZ zzx+X!XS+&!SMbfXgU3ohoAW0y3Lh?7^Qa&Ls2Am$Jcy*MpnRplA24RHJYyAq3%%oW zGV<~9`2?`@7kr*ecsi;QNKVzovST5q&YaQv-3bh4!Dz0Q?0x0?wr#E<9N#3bbHsT; z3J*MyVkvXwl5hw(S$o~OcmIBry1M!??Z!X6Z(||YDFh}tSR?Ps5C))8xZkvbG&Bgx z+_zwR(ZklA&@J_c=eOQ8uXEs(cLa_UNmOwkSCWL^%_F;ZS&wxiGX9k2(!BC_r5nC1 zkAcahXv9d=TB9`Nrv+_H#IP!W13=KYn6BocJv?PU#mZ00O<(A zUj*4P&2C49P?zrG} zzP|yl*6aE|PF6q1(|520w#*))D!|P%gM))NPPVYOU;bFsS41qcZ$?)Qj0-`=TTF!q zb*)s+@_J|(T z0*L*ez*^c84wkTS8H=pIZU7tS;B~{*dW>@s{eUO%F{Ov;{|p5@O-QDaYdtuV2>ifD zELQbVo$EYzcETiC#@t$RG627y-TE2B+8H#(N7aU}{@eZf?%}^btOF4?OfN5m$bQ2; z+WOJ`d-qDULl$b!16)Y|4&YUdfMu#QUxQ|)@y+TP%iZ}TdHNVf-_MN~Mw2ekEcp=^ z!DBz|GG+ z;cHR7sdcK4PfLbZ99S9a+vazI7FCn3oS%#R^x06c-zgH>1#J4$-Qx}FJ2v@_9a*}c zNh7UeQ9p%6u? zfi(aY781rHD^DS-$(M+f%aOO0z1&8^CY_*n&g&|XP~^q$5YGpbi(CjNG98jkmB2+`6zl+Tbj7zKMfD^=k z5zNOc18)xQ!Jx6m6Ef&hFsqpX?9V5?5sQ@7sbMnFQQCY%eE_WH#D3k4+%V*+R|jEY z-&3Ej=LDj?@}h!ErP{PRzs7TR$b*%7u>PMw-iAf83<_SSvQjL3hNGNpZ{{pZ|n?8Gm7^c<6+y3^!~-uU-3s^|yL z@b)!}^)MlXi&Ey?TS528GVh*@^vO%PHcGIM0c}@|pj9lfJ9+it@M67?1X6iOBKE}s zGLcqv3X;Gh#csocVU-jGAv9IMQ`s#kO+(88iwk5Km zuSBce*-92XTA`Sq|U9ZV^Q-ER5T|=+a~eZaG!lNbe!=&C3E%Y0*sIiCwr3%pC!$_p=kW z;|JtUWQy{CN!VaDRhQh$Up)NNjh-`BVcNv0j~n^a=_3x5a%UZo+@Plp(AUo3pde03 zH&nu4DY2{rcqZn)1J`OlG1t;mje1bsi(5NIRK12uQ_y@MPooMyIw~>qK7saeEB~h$b8;8M>OfJq?z2S_ANl${q&W^fxmHsa!C^ z>HvY;oC3wA+jf^^$|5N|{u%m?w0(AW0Pqo(m-rDAYqg*Krd~()(Bw;RHYiF;*WeQa zmU!sA2C8c4Uygj%(sA3rSEf5{{Trrkjo(}v3$bx>8vVPv+pv(^^5ZV>bDIDvd*mZH zR(7<+2s~M==^*lv<0fL|cB0EUM#ytA6%%cb6=GEbdfuL90`N%W{Ah9DA)CP*NODwB#5o`cz}S?SEg?Tj!F zwp%X}UrrgfJnQPOlh|EkmEa()ak}$$3-1X|JCbWUL<#C5**ybm)?PV(G(lMqmX$Lw z5+qpcNHCVCj9xn;jRu-AQX<@H2)O1VD^oF^qH}dL6zxIYXFOcJF~e*volGzqFXI&9 zN_#hy1>&>PgA0M_t6?fq;}V&H@&qDzli6nSL}OM&LzcR)_vPF=*QJ05@zkWMe$K?3?#ijL`={=?FJTs%Y>K!}`Y#Yu_OeoQ# zCE*0}P zDcN!pDE7*3iB6kDHg~CC677Q7%))M|cBdp-M}^5y@*T7>n!q2LJ(K>|yMAFyWvkszGXRcU$Ei^={ATqJd#3`PH zAwf~wzXkUn;*_RGP{epPst9WKQyiNUY|8cA?Ze_S2vx_av&Xhf(2yg4bp7H3j}=my zfF02=zakUcQpzavUwe#VD@)Gd{6-eJf$8OyxZ2yngYL(m)iBSixY74vvnM%hk9ALG z?>=CZv5SxT0g>tO{WK^Al2gP3g0a5j$|cp*C4W z4f}xQ_`5>!%Bh-bQ1;}x!997`Qz}OQY;l8}E4$d_Rj9Hu1cK6fXDwVQ!Bxlpp z-p57I6L2B~d+;ffoQ%=4k5L+w%e!ZcA>87_;Zhtg*i7paYa3`95%@vYZ5qb&;ftf% zO7V*~OXHtQU_Y^HUFvJhHxVnv?fWXFJTS^BnBKVOCqTADR9Q#BTQ=o@ad8AqB^9ez z$Dlnq%V85`f^jga56`m(#!uGpasZSY6&KKU6_FUJc?#}pReir>IoCHX97lGq>#?e{ z`G+*&2!25bB%p<-O^y$4R|gLoNcHfq#yq0N1;9&esceCc2#s2Ot4Sx7%F^G&Iv}eJ zBqkCLU+^#;Pbl0fnU*jvjZHYcR)dMy>c3H-883=KcbT`9FCkj&=dQ$@Vt6}GoDw9w z!prko&y`<}cop~jgQHi$iB3Zyk{L!9FRujQ6nbGtMp)eP)7iQ7^e-7{aM-w#c;a&V z4!*R!FluxKZDEFK5)MVhLLo;Ch@0Z08qY_;Y;M${R|WDRLbwASI@ zsCy@`TiCgk7|4?JVguu z=YqJQZx@tbPh3Z(f-gz1)v)0Lb4NfTVSxLM&z!k3$kAqFZ!=5`@)!!7>yutig?8GJ zon+>xG`760d5wvll{H6?+ozBwWpUhDSjc*~t6IyR7Wct@=W7u)#^ znAZk>b9Ndwz+=&NJEkSY@cC+l?3eh|Jz4Qh>>K$7Y#VGTL1}d-MSF4FAS+8vS%SN(xb$HGO&C7yfxKtd^G UZgR%B!q6k`{|{nSROIIT5At6ot^fc4 literal 0 HcmV?d00001 diff --git a/jetty-http/src/test/resources/multipart/browser-capture-form1-android-chrome.expected.txt b/jetty-http/src/test/resources/multipart/browser-capture-form1-android-chrome.expected.txt new file mode 100644 index 00000000000..271e31b1181 --- /dev/null +++ b/jetty-http/src/test/resources/multipart/browser-capture-form1-android-chrome.expected.txt @@ -0,0 +1,16 @@ +Request-Header|Accept|text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8 +Request-Header|Accept-Encoding|gzip, deflate +Request-Header|Accept-Language|en-US,en;q=0.9 +Request-Header|Cache-Control|max-age=0 +Request-Header|Connection|keep-alive +Request-Header|Content-Length|245 +Request-Header|Content-Type|multipart/form-data; boundary=----WebKitFormBoundaryD4GyXQgjBRmK3aBz +Request-Header|DNT|1 +Request-Header|Host|192.168.0.119:9090 +Request-Header|Origin|http://192.168.0.119:9090 +Request-Header|Referer|http://192.168.0.119:9090/form.html +Request-Header|Upgrade-Insecure-Requests|1 +Request-Header|User-Agent|Mozilla/5.0 (Linux; Android 8.1.0; Pixel 2 XL Build/OPM1.171019.021) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.109 Mobile Safari/537.36 +Parts-Count|2 +Part-ContainsContents|user|Androiduser +Part-ContainsContents|comment|Dyac! \ No newline at end of file diff --git a/jetty-http/src/test/resources/multipart/browser-capture-form1-android-chrome.raw b/jetty-http/src/test/resources/multipart/browser-capture-form1-android-chrome.raw new file mode 100644 index 00000000000..f5ce1cab07d --- /dev/null +++ b/jetty-http/src/test/resources/multipart/browser-capture-form1-android-chrome.raw @@ -0,0 +1,9 @@ +------WebKitFormBoundaryD4GyXQgjBRmK3aBz +Content-Disposition: form-data; name="user" + +Androiduser +------WebKitFormBoundaryD4GyXQgjBRmK3aBz +Content-Disposition: form-data; name="comment" + +Dyac! +------WebKitFormBoundaryD4GyXQgjBRmK3aBz-- diff --git a/jetty-http/src/test/resources/multipart/browser-capture-form1-android-firefox.expected.txt b/jetty-http/src/test/resources/multipart/browser-capture-form1-android-firefox.expected.txt new file mode 100644 index 00000000000..9f7d2307e87 --- /dev/null +++ b/jetty-http/src/test/resources/multipart/browser-capture-form1-android-firefox.expected.txt @@ -0,0 +1,13 @@ +Request-Header|Accept|text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 +Request-Header|Accept-Encoding|gzip, deflate +Request-Header|Accept-Language|en-US,en;q=0.5 +Request-Header|Connection|keep-alive +Request-Header|Content-Length|306 +Request-Header|Content-Type|multipart/form-data; boundary=---------------------------6390283156237600831344307695 +Request-Header|Host|192.168.0.119:9090 +Request-Header|Referer|http://192.168.0.119:9090/form.html +Request-Header|Upgrade-Insecure-Requests|1 +Request-Header|User-Agent|Mozilla/5.0 (Android 8.1.0; Mobile; rv:59.0) Gecko/59.0 Firefox/59.0 +Parts-Count|2 +Part-ContainsContents|user|androidfireuser +Part-ContainsContents|comment|More to say \ No newline at end of file diff --git a/jetty-http/src/test/resources/multipart/browser-capture-form1-android-firefox.raw b/jetty-http/src/test/resources/multipart/browser-capture-form1-android-firefox.raw new file mode 100644 index 00000000000..75dbbde1a6f --- /dev/null +++ b/jetty-http/src/test/resources/multipart/browser-capture-form1-android-firefox.raw @@ -0,0 +1,9 @@ +-----------------------------6390283156237600831344307695 +Content-Disposition: form-data; name="user" + +androidfireuser +-----------------------------6390283156237600831344307695 +Content-Disposition: form-data; name="comment" + +More to say +-----------------------------6390283156237600831344307695-- diff --git a/jetty-http/src/test/resources/multipart/browser-capture-form1-chrome.expected.txt b/jetty-http/src/test/resources/multipart/browser-capture-form1-chrome.expected.txt new file mode 100644 index 00000000000..d36342fb640 --- /dev/null +++ b/jetty-http/src/test/resources/multipart/browser-capture-form1-chrome.expected.txt @@ -0,0 +1,17 @@ +Request-Header|Accept|text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8 +Request-Header|Accept-Encoding|gzip, deflate, br +Request-Header|Accept-Language|en-US,en;q=0.9 +Request-Header|Cache-Control|max-age=0 +Request-Header|Connection|keep-alive +Request-Header|Content-Length|256 +Request-Header|Content-Type|multipart/form-data; boundary=----WebKitFormBoundary46EP6zTN86hbbaJC +Request-Header|Cookie|visited=yes +Request-Header|DNT|1 +Request-Header|Host|localhost:9090 +Request-Header|Origin|http://localhost:9090 +Request-Header|Referer|http://localhost:9090/form.html +Request-Header|Upgrade-Insecure-Requests|1 +Request-Header|User-Agent|Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.162 Safari/537.36 +Parts-Count|2 +Part-ContainsContents|user|joe +Part-ContainsContents|comment|this is a simple comment \ No newline at end of file diff --git a/jetty-http/src/test/resources/multipart/browser-capture-form1-chrome.raw b/jetty-http/src/test/resources/multipart/browser-capture-form1-chrome.raw new file mode 100644 index 00000000000..7f8bfc267d8 --- /dev/null +++ b/jetty-http/src/test/resources/multipart/browser-capture-form1-chrome.raw @@ -0,0 +1,9 @@ +------WebKitFormBoundary46EP6zTN86hbbaJC +Content-Disposition: form-data; name="user" + +joe +------WebKitFormBoundary46EP6zTN86hbbaJC +Content-Disposition: form-data; name="comment" + +this is a simple comment +------WebKitFormBoundary46EP6zTN86hbbaJC-- diff --git a/jetty-http/src/test/resources/multipart/browser-capture-form1-edge.expected.txt b/jetty-http/src/test/resources/multipart/browser-capture-form1-edge.expected.txt new file mode 100644 index 00000000000..0b7f887ddc6 --- /dev/null +++ b/jetty-http/src/test/resources/multipart/browser-capture-form1-edge.expected.txt @@ -0,0 +1,13 @@ +Request-Header|Accept|text/html, application/xhtml+xml, image/jxr, */* +Request-Header|Accept-Encoding|gzip, deflate +Request-Header|Accept-Language|en-US +Request-Header|Cache-Control|no-cache +Request-Header|Connection|keep-alive +Request-Header|Content-Length|267 +Request-Header|Content-Type|multipart/form-data; boundary=---------------------------7e25e1e151054 +Request-Header|Host|localhost:9090 +Request-Header|Referer|http://localhost:9090/form.html +Request-Header|User-Agent|Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 Edge/16.16299 +Parts-Count|2 +Part-ContainsContents|user|anotheruser +Part-ContainsContents|comment|with something to say \ No newline at end of file diff --git a/jetty-http/src/test/resources/multipart/browser-capture-form1-edge.raw b/jetty-http/src/test/resources/multipart/browser-capture-form1-edge.raw new file mode 100644 index 00000000000..48aa4e73f1c --- /dev/null +++ b/jetty-http/src/test/resources/multipart/browser-capture-form1-edge.raw @@ -0,0 +1,9 @@ +-----------------------------7e25e1e151054 +Content-Disposition: form-data; name="user" + +anotheruser +-----------------------------7e25e1e151054 +Content-Disposition: form-data; name="comment" + +with something to say +-----------------------------7e25e1e151054-- diff --git a/jetty-http/src/test/resources/multipart/browser-capture-form1-firefox.expected.txt b/jetty-http/src/test/resources/multipart/browser-capture-form1-firefox.expected.txt new file mode 100644 index 00000000000..9f0e4ee9899 --- /dev/null +++ b/jetty-http/src/test/resources/multipart/browser-capture-form1-firefox.expected.txt @@ -0,0 +1,13 @@ +Request-Header|Accept|text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 +Request-Header|Accept-Encoding|gzip, deflate +Request-Header|Accept-Language|en-US,en;q=0.5 +Request-Header|Connection|keep-alive +Request-Header|Content-Length|258 +Request-Header|Content-Type|multipart/form-data; boundary=---------------------------41184676334 +Request-Header|Host|localhost:9090 +Request-Header|Referer|http://localhost:9090/form.html +Request-Header|Upgrade-Insecure-Requests|1 +Request-Header|User-Agent|Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:58.0) Gecko/20100101 Firefox/58.0 +Parts-Count|2 +Part-ContainsContents|user|fireuser +Part-ContainsContents|comment|with detailed message \ No newline at end of file diff --git a/jetty-http/src/test/resources/multipart/browser-capture-form1-firefox.raw b/jetty-http/src/test/resources/multipart/browser-capture-form1-firefox.raw new file mode 100644 index 00000000000..a7c65315450 --- /dev/null +++ b/jetty-http/src/test/resources/multipart/browser-capture-form1-firefox.raw @@ -0,0 +1,9 @@ +-----------------------------41184676334 +Content-Disposition: form-data; name="user" + +fireuser +-----------------------------41184676334 +Content-Disposition: form-data; name="comment" + +with detailed message +-----------------------------41184676334-- diff --git a/jetty-http/src/test/resources/multipart/browser-capture-form1-ios-safari.expected.txt b/jetty-http/src/test/resources/multipart/browser-capture-form1-ios-safari.expected.txt new file mode 100644 index 00000000000..4d0533dfb0f --- /dev/null +++ b/jetty-http/src/test/resources/multipart/browser-capture-form1-ios-safari.expected.txt @@ -0,0 +1,14 @@ +Request-Header|Accept|text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 +Request-Header|Accept-Encoding|gzip, deflate +Request-Header|Accept-Language|en-us +Request-Header|Connection|keep-alive +Request-Header|Content-Length|268 +Request-Header|Content-Type|multipart/form-data; boundary=----WebKitFormBoundary56m5uMm4gNcn4rL1 +Request-Header|Host|192.168.0.119:9090 +Request-Header|Origin|http://192.168.0.119:9090 +Request-Header|Referer|http://192.168.0.119:9090/form.html +Request-Header|Upgrade-Insecure-Requests|1 +Request-Header|User-Agent|Mozilla/5.0 (iPad; CPU OS 11_2_6 like Mac OS X) AppleWebKit/604.5.6 (KHTML, like Gecko) Version/11.0 Mobile/15D100 Safari/604.1 +Parts-Count|2 +Part-ContainsContents|user|UseriPad +Part-ContainsContents|comment|This form isn’t pretty \ No newline at end of file diff --git a/jetty-http/src/test/resources/multipart/browser-capture-form1-ios-safari.raw b/jetty-http/src/test/resources/multipart/browser-capture-form1-ios-safari.raw new file mode 100644 index 00000000000..9664c903572 --- /dev/null +++ b/jetty-http/src/test/resources/multipart/browser-capture-form1-ios-safari.raw @@ -0,0 +1,9 @@ +------WebKitFormBoundary56m5uMm4gNcn4rL1 +Content-Disposition: form-data; name="user" + +UseriPad +------WebKitFormBoundary56m5uMm4gNcn4rL1 +Content-Disposition: form-data; name="comment" + +This form isn’t pretty enough +------WebKitFormBoundary56m5uMm4gNcn4rL1-- diff --git a/jetty-http/src/test/resources/multipart/browser-capture-form1-msie.expected.txt b/jetty-http/src/test/resources/multipart/browser-capture-form1-msie.expected.txt new file mode 100644 index 00000000000..60cbe9e5956 --- /dev/null +++ b/jetty-http/src/test/resources/multipart/browser-capture-form1-msie.expected.txt @@ -0,0 +1,13 @@ +Request-Header|Accept|text/html, application/xhtml+xml, image/jxr, */* +Request-Header|Accept-Encoding|gzip, deflate +Request-Header|Accept-Language|en-US +Request-Header|Cache-Control|no-cache +Request-Header|Connection|keep-alive +Request-Header|Content-Length|285 +Request-Header|Content-Type|multipart/form-data; boundary=---------------------------7e21b6f2109c +Request-Header|Host|localhost:9090 +Request-Header|Referer|http://localhost:9090/form.html +Request-Header|User-Agent|Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko +Parts-Count|2 +Part-ContainsContents|user|msieuser +Part-ContainsContents|comment|with information that they think is important \ No newline at end of file diff --git a/jetty-http/src/test/resources/multipart/browser-capture-form1-msie.raw b/jetty-http/src/test/resources/multipart/browser-capture-form1-msie.raw new file mode 100644 index 00000000000..e562e721397 --- /dev/null +++ b/jetty-http/src/test/resources/multipart/browser-capture-form1-msie.raw @@ -0,0 +1,9 @@ +-----------------------------7e21b6f2109c +Content-Disposition: form-data; name="user" + +msieuser +-----------------------------7e21b6f2109c +Content-Disposition: form-data; name="comment" + +with information that they think is important +-----------------------------7e21b6f2109c-- diff --git a/jetty-http/src/test/resources/multipart/browser-capture-form1-osx-safari.expected.txt b/jetty-http/src/test/resources/multipart/browser-capture-form1-osx-safari.expected.txt new file mode 100644 index 00000000000..236c06f15e8 --- /dev/null +++ b/jetty-http/src/test/resources/multipart/browser-capture-form1-osx-safari.expected.txt @@ -0,0 +1,14 @@ +Request-Header|Accept|text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 +Request-Header|Accept-Encoding|gzip, deflate +Request-Header|Accept-Language|en-us +Request-Header|Connection|keep-alive +Request-Header|Content-Length|284 +Request-Header|Content-Type|multipart/form-data; boundary=----WebKitFormBoundaryjwqONTsAFgubfMZc +Request-Header|Host|192.168.0.119:9090 +Request-Header|Origin|http://192.168.0.119:9090 +Request-Header|Referer|http://192.168.0.119:9090/form.html +Request-Header|Upgrade-Insecure-Requests|1 +Request-Header|User-Agent|Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/604.5.6 (KHTML, like Gecko) Version/11.0.3 Safari/604.5.6 +Parts-Count|2 +Part-ContainsContents|user|safariuser +Part-ContainsContents|comment|with rambling thoughts about bellybutton lint \ No newline at end of file diff --git a/jetty-http/src/test/resources/multipart/browser-capture-form1-osx-safari.raw b/jetty-http/src/test/resources/multipart/browser-capture-form1-osx-safari.raw new file mode 100644 index 00000000000..0e6b82ffd18 --- /dev/null +++ b/jetty-http/src/test/resources/multipart/browser-capture-form1-osx-safari.raw @@ -0,0 +1,9 @@ +------WebKitFormBoundaryjwqONTsAFgubfMZc +Content-Disposition: form-data; name="user" + +safariuser +------WebKitFormBoundaryjwqONTsAFgubfMZc +Content-Disposition: form-data; name="comment" + +with rambling thoughts about bellybutton lint +------WebKitFormBoundaryjwqONTsAFgubfMZc-- diff --git a/jetty-http/src/test/resources/multipart/browser-capture-sjis-charset-form-android-chrome.expected.txt b/jetty-http/src/test/resources/multipart/browser-capture-sjis-charset-form-android-chrome.expected.txt new file mode 100644 index 00000000000..57ae9b6b42c --- /dev/null +++ b/jetty-http/src/test/resources/multipart/browser-capture-sjis-charset-form-android-chrome.expected.txt @@ -0,0 +1,17 @@ +Request-Header|Accept|text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8 +Request-Header|Accept-Encoding|gzip, deflate +Request-Header|Accept-Language|en-US,en;q=0.9 +Request-Header|Cache-Control|max-age=0 +Request-Header|Connection|keep-alive +Request-Header|Content-Length|354 +Request-Header|Content-Type|multipart/form-data; boundary=----WebKitFormBoundaryN7pYBoDaXhEcUl13 +Request-Header|DNT|1 +Request-Header|Host|192.168.0.119:9090 +Request-Header|Origin|http://192.168.0.119:9090 +Request-Header|Referer|http://192.168.0.119:9090/sjis-form-charset.html +Request-Header|Upgrade-Insecure-Requests|1 +Request-Header|User-Agent|Mozilla/5.0 (Linux; Android 8.1.0; Pixel 2 XL Build/OPM1.171019.021) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.109 Mobile Safari/537.36 +Parts-Count|3 +Part-ContainsContents|_charset_|Shift_JIS +Part-ContainsContents|japanese|健治 +Part-ContainsContents|hello|ャユ戆タ \ No newline at end of file diff --git a/jetty-http/src/test/resources/multipart/browser-capture-sjis-charset-form-android-chrome.raw b/jetty-http/src/test/resources/multipart/browser-capture-sjis-charset-form-android-chrome.raw new file mode 100644 index 00000000000..5c77075588e --- /dev/null +++ b/jetty-http/src/test/resources/multipart/browser-capture-sjis-charset-form-android-chrome.raw @@ -0,0 +1,13 @@ +------WebKitFormBoundaryN7pYBoDaXhEcUl13 +Content-Disposition: form-data; name="_charset_" + +Shift_JIS +------WebKitFormBoundaryN7pYBoDaXhEcUl13 +Content-Disposition: form-data; name="japanese" + + +------WebKitFormBoundaryN7pYBoDaXhEcUl13 +Content-Disposition: form-data; name="hello" + +戆^ +------WebKitFormBoundaryN7pYBoDaXhEcUl13-- diff --git a/jetty-http/src/test/resources/multipart/browser-capture-sjis-charset-form-android-firefox.expected.txt b/jetty-http/src/test/resources/multipart/browser-capture-sjis-charset-form-android-firefox.expected.txt new file mode 100644 index 00000000000..b8ad28cd14f --- /dev/null +++ b/jetty-http/src/test/resources/multipart/browser-capture-sjis-charset-form-android-firefox.expected.txt @@ -0,0 +1,14 @@ +Request-Header|Accept|text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 +Request-Header|Accept-Encoding|gzip, deflate +Request-Header|Accept-Language|en-US,en;q=0.5 +Request-Header|Connection|keep-alive +Request-Header|Content-Length|430 +Request-Header|Content-Type|multipart/form-data; boundary=---------------------------117031256520586657911714164254 +Request-Header|Host|192.168.0.119:9090 +Request-Header|Referer|http://192.168.0.119:9090/sjis-form-charset.html +Request-Header|Upgrade-Insecure-Requests|1 +Request-Header|User-Agent|Mozilla/5.0 (Android 8.1.0; Mobile; rv:59.0) Gecko/59.0 Firefox/59.0 +Parts-Count|3 +Part-ContainsContents|_charset_|Shift_JIS +Part-ContainsContents|japanese|健治 +Part-ContainsContents|hello|ャユ戆タ \ No newline at end of file diff --git a/jetty-http/src/test/resources/multipart/browser-capture-sjis-charset-form-android-firefox.raw b/jetty-http/src/test/resources/multipart/browser-capture-sjis-charset-form-android-firefox.raw new file mode 100644 index 00000000000..b3c4ae8f72e --- /dev/null +++ b/jetty-http/src/test/resources/multipart/browser-capture-sjis-charset-form-android-firefox.raw @@ -0,0 +1,13 @@ +-----------------------------117031256520586657911714164254 +Content-Disposition: form-data; name="_charset_" + +Shift_JIS +-----------------------------117031256520586657911714164254 +Content-Disposition: form-data; name="japanese" + + +-----------------------------117031256520586657911714164254 +Content-Disposition: form-data; name="hello" + +戆^ +-----------------------------117031256520586657911714164254-- diff --git a/jetty-http/src/test/resources/multipart/browser-capture-sjis-charset-form-chrome.expected.txt b/jetty-http/src/test/resources/multipart/browser-capture-sjis-charset-form-chrome.expected.txt new file mode 100644 index 00000000000..ffa6809c986 --- /dev/null +++ b/jetty-http/src/test/resources/multipart/browser-capture-sjis-charset-form-chrome.expected.txt @@ -0,0 +1,18 @@ +Request-Header|Accept|text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8 +Request-Header|Accept-Encoding|gzip, deflate, br +Request-Header|Accept-Language|en-US,en;q=0.9 +Request-Header|Cache-Control|max-age=0 +Request-Header|Connection|keep-alive +Request-Header|Content-Length|354 +Request-Header|Content-Type|multipart/form-data; boundary=----WebKitFormBoundaryDHtjXxgNUcgLjcKs +Request-Header|Cookie|visited=yes +Request-Header|DNT|1 +Request-Header|Host|localhost:9090 +Request-Header|Origin|http://localhost:9090 +Request-Header|Referer|http://localhost:9090/sjis-form-charset.html +Request-Header|Upgrade-Insecure-Requests|1 +Request-Header|User-Agent|Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.162 Safari/537.36 +Parts-Count|3 +Part-ContainsContents|_charset_|Shift_JIS +Part-ContainsContents|japanese|健治 +Part-ContainsContents|hello|ャユ戆タ \ No newline at end of file diff --git a/jetty-http/src/test/resources/multipart/browser-capture-sjis-charset-form-chrome.raw b/jetty-http/src/test/resources/multipart/browser-capture-sjis-charset-form-chrome.raw new file mode 100644 index 00000000000..64314612ecc --- /dev/null +++ b/jetty-http/src/test/resources/multipart/browser-capture-sjis-charset-form-chrome.raw @@ -0,0 +1,13 @@ +------WebKitFormBoundaryDHtjXxgNUcgLjcKs +Content-Disposition: form-data; name="_charset_" + +Shift_JIS +------WebKitFormBoundaryDHtjXxgNUcgLjcKs +Content-Disposition: form-data; name="japanese" + + +------WebKitFormBoundaryDHtjXxgNUcgLjcKs +Content-Disposition: form-data; name="hello" + +戆^ +------WebKitFormBoundaryDHtjXxgNUcgLjcKs-- diff --git a/jetty-http/src/test/resources/multipart/browser-capture-sjis-charset-form-edge.expected.txt b/jetty-http/src/test/resources/multipart/browser-capture-sjis-charset-form-edge.expected.txt new file mode 100644 index 00000000000..4b4cc724c95 --- /dev/null +++ b/jetty-http/src/test/resources/multipart/browser-capture-sjis-charset-form-edge.expected.txt @@ -0,0 +1,14 @@ +Request-Header|Accept|text/html, application/xhtml+xml, image/jxr, */* +Request-Header|Accept-Encoding|gzip, deflate +Request-Header|Accept-Language|en-US +Request-Header|Cache-Control|no-cache +Request-Header|Connection|keep-alive +Request-Header|Content-Length|362 +Request-Header|Content-Type|multipart/form-data; boundary=---------------------------7e227e17151054 +Request-Header|Host|localhost:9090 +Request-Header|Referer|http://localhost:9090/sjis-form-charset.html +Request-Header|User-Agent|Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 Edge/16.16299 +Parts-Count|3 +Part-ContainsContents|_charset_|utf-8 +Part-ContainsContents|japanese|健治 +Part-ContainsContents|hello|ャユ戆タ \ No newline at end of file diff --git a/jetty-http/src/test/resources/multipart/browser-capture-sjis-charset-form-edge.raw b/jetty-http/src/test/resources/multipart/browser-capture-sjis-charset-form-edge.raw new file mode 100644 index 00000000000..71dac77ca76 --- /dev/null +++ b/jetty-http/src/test/resources/multipart/browser-capture-sjis-charset-form-edge.raw @@ -0,0 +1,13 @@ +-----------------------------7e227e17151054 +Content-Disposition: form-data; name="_charset_" + +utf-8 +-----------------------------7e227e17151054 +Content-Disposition: form-data; name="japanese" + +健治 +-----------------------------7e227e17151054 +Content-Disposition: form-data; name="hello" + +ャユ戆タ +-----------------------------7e227e17151054-- diff --git a/jetty-http/src/test/resources/multipart/browser-capture-sjis-charset-form-firefox.expected.txt b/jetty-http/src/test/resources/multipart/browser-capture-sjis-charset-form-firefox.expected.txt new file mode 100644 index 00000000000..cb6458d4e2f --- /dev/null +++ b/jetty-http/src/test/resources/multipart/browser-capture-sjis-charset-form-firefox.expected.txt @@ -0,0 +1,14 @@ +Request-Header|Accept|text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 +Request-Header|Accept-Encoding|gzip, deflate +Request-Header|Accept-Language|en-US,en;q=0.5 +Request-Header|Connection|keep-alive +Request-Header|Content-Length|370 +Request-Header|Content-Type|multipart/form-data; boundary=---------------------------114782935826962 +Request-Header|Host|localhost:9090 +Request-Header|Referer|http://localhost:9090/sjis-form-charset.html +Request-Header|Upgrade-Insecure-Requests|1 +Request-Header|User-Agent|Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:58.0) Gecko/20100101 Firefox/58.0 +Parts-Count|3 +Part-ContainsContents|_charset_|Shift_JIS +Part-ContainsContents|japanese|健治 +Part-ContainsContents|hello|ャユ戆タ \ No newline at end of file diff --git a/jetty-http/src/test/resources/multipart/browser-capture-sjis-charset-form-firefox.raw b/jetty-http/src/test/resources/multipart/browser-capture-sjis-charset-form-firefox.raw new file mode 100644 index 00000000000..921df609d8a --- /dev/null +++ b/jetty-http/src/test/resources/multipart/browser-capture-sjis-charset-form-firefox.raw @@ -0,0 +1,13 @@ +-----------------------------114782935826962 +Content-Disposition: form-data; name="_charset_" + +Shift_JIS +-----------------------------114782935826962 +Content-Disposition: form-data; name="japanese" + + +-----------------------------114782935826962 +Content-Disposition: form-data; name="hello" + +戆^ +-----------------------------114782935826962-- diff --git a/jetty-http/src/test/resources/multipart/browser-capture-sjis-charset-form-ios-safari.expected.txt b/jetty-http/src/test/resources/multipart/browser-capture-sjis-charset-form-ios-safari.expected.txt new file mode 100644 index 00000000000..c098400ec3d --- /dev/null +++ b/jetty-http/src/test/resources/multipart/browser-capture-sjis-charset-form-ios-safari.expected.txt @@ -0,0 +1,15 @@ +Request-Header|Accept|text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 +Request-Header|Accept-Encoding|gzip, deflate +Request-Header|Accept-Language|en-us +Request-Header|Connection|keep-alive +Request-Header|Content-Length|354 +Request-Header|Content-Type|multipart/form-data; boundary=----WebKitFormBoundaryvshQXGBfIsRjfMBN +Request-Header|Host|192.168.0.119:9090 +Request-Header|Origin|http://192.168.0.119:9090 +Request-Header|Referer|http://192.168.0.119:9090/sjis-form-charset.html +Request-Header|Upgrade-Insecure-Requests|1 +Request-Header|User-Agent|Mozilla/5.0 (iPad; CPU OS 11_2_6 like Mac OS X) AppleWebKit/604.5.6 (KHTML, like Gecko) Version/11.0 Mobile/15D100 Safari/604.1 +Parts-Count|3 +Part-ContainsContents|_charset_|Shift_JIS +Part-ContainsContents|japanese|健治 +Part-ContainsContents|hello|ャユ戆タ \ No newline at end of file diff --git a/jetty-http/src/test/resources/multipart/browser-capture-sjis-charset-form-ios-safari.raw b/jetty-http/src/test/resources/multipart/browser-capture-sjis-charset-form-ios-safari.raw new file mode 100644 index 00000000000..9892c9c05fe --- /dev/null +++ b/jetty-http/src/test/resources/multipart/browser-capture-sjis-charset-form-ios-safari.raw @@ -0,0 +1,13 @@ +------WebKitFormBoundaryvshQXGBfIsRjfMBN +Content-Disposition: form-data; name="_charset_" + +Shift_JIS +------WebKitFormBoundaryvshQXGBfIsRjfMBN +Content-Disposition: form-data; name="japanese" + + +------WebKitFormBoundaryvshQXGBfIsRjfMBN +Content-Disposition: form-data; name="hello" + +戆^ +------WebKitFormBoundaryvshQXGBfIsRjfMBN-- diff --git a/jetty-http/src/test/resources/multipart/browser-capture-sjis-charset-form-msie.expected.txt b/jetty-http/src/test/resources/multipart/browser-capture-sjis-charset-form-msie.expected.txt new file mode 100644 index 00000000000..5d84aa6eb75 --- /dev/null +++ b/jetty-http/src/test/resources/multipart/browser-capture-sjis-charset-form-msie.expected.txt @@ -0,0 +1,14 @@ +Request-Header|Accept|text/html, application/xhtml+xml, image/jxr, */* +Request-Header|Accept-Encoding|gzip, deflate +Request-Header|Accept-Language|en-US +Request-Header|Cache-Control|no-cache +Request-Header|Connection|keep-alive +Request-Header|Content-Length|358 +Request-Header|Content-Type|multipart/form-data; boundary=---------------------------7e226e1b2109c +Request-Header|Host|localhost:9090 +Request-Header|Referer|http://localhost:9090/sjis-form-charset.html +Request-Header|User-Agent|Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko +Parts-Count|3 +Part-ContainsContents|_charset_|utf-8 +Part-ContainsContents|japanese|健治 +Part-ContainsContents|hello|ャユ戆タ \ No newline at end of file diff --git a/jetty-http/src/test/resources/multipart/browser-capture-sjis-charset-form-msie.raw b/jetty-http/src/test/resources/multipart/browser-capture-sjis-charset-form-msie.raw new file mode 100644 index 00000000000..9a043e69d64 --- /dev/null +++ b/jetty-http/src/test/resources/multipart/browser-capture-sjis-charset-form-msie.raw @@ -0,0 +1,13 @@ +-----------------------------7e226e1b2109c +Content-Disposition: form-data; name="_charset_" + +utf-8 +-----------------------------7e226e1b2109c +Content-Disposition: form-data; name="japanese" + +健治 +-----------------------------7e226e1b2109c +Content-Disposition: form-data; name="hello" + +ャユ戆タ +-----------------------------7e226e1b2109c-- diff --git a/jetty-http/src/test/resources/multipart/browser-capture-sjis-charset-form-safari.expected.txt b/jetty-http/src/test/resources/multipart/browser-capture-sjis-charset-form-safari.expected.txt new file mode 100644 index 00000000000..39581ae2257 --- /dev/null +++ b/jetty-http/src/test/resources/multipart/browser-capture-sjis-charset-form-safari.expected.txt @@ -0,0 +1,15 @@ +Request-Header|Accept|text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 +Request-Header|Accept-Encoding|gzip, deflate +Request-Header|Accept-Language|en-us +Request-Header|Connection|keep-alive +Request-Header|Content-Length|354 +Request-Header|Content-Type|multipart/form-data; boundary=----WebKitFormBoundaryHFCTTESrC7sXQ2Gf +Request-Header|Host|192.168.0.119:9090 +Request-Header|Origin|http://192.168.0.119:9090 +Request-Header|Referer|http://192.168.0.119:9090/sjis-form-charset.html +Request-Header|Upgrade-Insecure-Requests|1 +Request-Header|User-Agent|Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/604.5.6 (KHTML, like Gecko) Version/11.0.3 Safari/604.5.6 +Parts-Count|3 +Part-ContainsContents|_charset_|Shift_JIS +Part-ContainsContents|japanese|健治 +Part-ContainsContents|hello|ャユ戆タ \ No newline at end of file diff --git a/jetty-http/src/test/resources/multipart/browser-capture-sjis-charset-form-safari.raw b/jetty-http/src/test/resources/multipart/browser-capture-sjis-charset-form-safari.raw new file mode 100644 index 00000000000..ce14357da86 --- /dev/null +++ b/jetty-http/src/test/resources/multipart/browser-capture-sjis-charset-form-safari.raw @@ -0,0 +1,13 @@ +------WebKitFormBoundaryHFCTTESrC7sXQ2Gf +Content-Disposition: form-data; name="_charset_" + +Shift_JIS +------WebKitFormBoundaryHFCTTESrC7sXQ2Gf +Content-Disposition: form-data; name="japanese" + + +------WebKitFormBoundaryHFCTTESrC7sXQ2Gf +Content-Disposition: form-data; name="hello" + +戆^ +------WebKitFormBoundaryHFCTTESrC7sXQ2Gf-- diff --git a/jetty-http/src/test/resources/multipart/browser-capture-sjis-form-android-chrome.expected.txt b/jetty-http/src/test/resources/multipart/browser-capture-sjis-form-android-chrome.expected.txt new file mode 100644 index 00000000000..f5e2236ce9b --- /dev/null +++ b/jetty-http/src/test/resources/multipart/browser-capture-sjis-form-android-chrome.expected.txt @@ -0,0 +1,16 @@ +Request-Header|Accept|text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8 +Request-Header|Accept-Encoding|gzip, deflate +Request-Header|Accept-Language|en-US,en;q=0.9 +Request-Header|Cache-Control|max-age=0 +Request-Header|Connection|keep-alive +Request-Header|Content-Length|249 +Request-Header|Content-Type|multipart/form-data; boundary=----WebKitFormBoundaryjJR29nbr1TDUu2yh +Request-Header|DNT|1 +Request-Header|Host|192.168.0.119:9090 +Request-Header|Origin|http://192.168.0.119:9090 +Request-Header|Referer|http://192.168.0.119:9090/sjis-form.html +Request-Header|Upgrade-Insecure-Requests|1 +Request-Header|User-Agent|Mozilla/5.0 (Linux; Android 8.1.0; Pixel 2 XL Build/OPM1.171019.021) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.109 Mobile Safari/537.36 +Parts-Count|2 +Part-ContainsContents|japanese|健治 +Part-ContainsContents|hello|ャユ戆タ \ No newline at end of file diff --git a/jetty-http/src/test/resources/multipart/browser-capture-sjis-form-android-chrome.raw b/jetty-http/src/test/resources/multipart/browser-capture-sjis-form-android-chrome.raw new file mode 100644 index 00000000000..618c30e3c98 --- /dev/null +++ b/jetty-http/src/test/resources/multipart/browser-capture-sjis-form-android-chrome.raw @@ -0,0 +1,9 @@ +------WebKitFormBoundaryjJR29nbr1TDUu2yh +Content-Disposition: form-data; name="japanese" + + +------WebKitFormBoundaryjJR29nbr1TDUu2yh +Content-Disposition: form-data; name="hello" + +戆^ +------WebKitFormBoundaryjJR29nbr1TDUu2yh-- diff --git a/jetty-http/src/test/resources/multipart/browser-capture-sjis-form-android-firefox.expected.txt b/jetty-http/src/test/resources/multipart/browser-capture-sjis-form-android-firefox.expected.txt new file mode 100644 index 00000000000..b3baf194689 --- /dev/null +++ b/jetty-http/src/test/resources/multipart/browser-capture-sjis-form-android-firefox.expected.txt @@ -0,0 +1,13 @@ +Request-Header|Accept|text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 +Request-Header|Accept-Encoding|gzip, deflate +Request-Header|Accept-Language|en-US,en;q=0.5 +Request-Header|Connection|keep-alive +Request-Header|Content-Length|303 +Request-Header|Content-Type|multipart/form-data; boundary=---------------------------18591390852002031541755421242 +Request-Header|Host|192.168.0.119:9090 +Request-Header|Referer|http://192.168.0.119:9090/sjis-form.html +Request-Header|Upgrade-Insecure-Requests|1 +Request-Header|User-Agent|Mozilla/5.0 (Android 8.1.0; Mobile; rv:59.0) Gecko/59.0 Firefox/59.0 +Parts-Count|2 +Part-ContainsContents|japanese|健治 +Part-ContainsContents|hello|ャユ戆タ \ No newline at end of file diff --git a/jetty-http/src/test/resources/multipart/browser-capture-sjis-form-android-firefox.raw b/jetty-http/src/test/resources/multipart/browser-capture-sjis-form-android-firefox.raw new file mode 100644 index 00000000000..5c8d5b47190 --- /dev/null +++ b/jetty-http/src/test/resources/multipart/browser-capture-sjis-form-android-firefox.raw @@ -0,0 +1,9 @@ +-----------------------------18591390852002031541755421242 +Content-Disposition: form-data; name="japanese" + + +-----------------------------18591390852002031541755421242 +Content-Disposition: form-data; name="hello" + +戆^ +-----------------------------18591390852002031541755421242-- diff --git a/jetty-http/src/test/resources/multipart/browser-capture-sjis-form-chrome.expected.txt b/jetty-http/src/test/resources/multipart/browser-capture-sjis-form-chrome.expected.txt new file mode 100644 index 00000000000..6cba2d9e365 --- /dev/null +++ b/jetty-http/src/test/resources/multipart/browser-capture-sjis-form-chrome.expected.txt @@ -0,0 +1,17 @@ +Request-Header|Accept|text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8 +Request-Header|Accept-Encoding|gzip, deflate, br +Request-Header|Accept-Language|en-US,en;q=0.9 +Request-Header|Cache-Control|max-age=0 +Request-Header|Connection|keep-alive +Request-Header|Content-Length|249 +Request-Header|Content-Type|multipart/form-data; boundary=----WebKitFormBoundarysKD6As9BBil2g6Fc +Request-Header|Cookie|visited=yes +Request-Header|DNT|1 +Request-Header|Host|localhost:9090 +Request-Header|Origin|http://localhost:9090 +Request-Header|Referer|http://localhost:9090/sjis-form.html +Request-Header|Upgrade-Insecure-Requests|1 +Request-Header|User-Agent|Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.162 Safari/537.36 +Parts-Count|2 +Part-ContainsContents|japanese|健治 +Part-ContainsContents|hello|ャユ戆タ \ No newline at end of file diff --git a/jetty-http/src/test/resources/multipart/browser-capture-sjis-form-chrome.raw b/jetty-http/src/test/resources/multipart/browser-capture-sjis-form-chrome.raw new file mode 100644 index 00000000000..02e44b0913e --- /dev/null +++ b/jetty-http/src/test/resources/multipart/browser-capture-sjis-form-chrome.raw @@ -0,0 +1,9 @@ +------WebKitFormBoundarysKD6As9BBil2g6Fc +Content-Disposition: form-data; name="japanese" + + +------WebKitFormBoundarysKD6As9BBil2g6Fc +Content-Disposition: form-data; name="hello" + +戆^ +------WebKitFormBoundarysKD6As9BBil2g6Fc-- diff --git a/jetty-http/src/test/resources/multipart/browser-capture-sjis-form-edge.expected.txt b/jetty-http/src/test/resources/multipart/browser-capture-sjis-form-edge.expected.txt new file mode 100644 index 00000000000..f51c4cc1399 --- /dev/null +++ b/jetty-http/src/test/resources/multipart/browser-capture-sjis-form-edge.expected.txt @@ -0,0 +1,13 @@ +Request-Header|Accept|text/html, application/xhtml+xml, image/jxr, */* +Request-Header|Accept-Encoding|gzip, deflate +Request-Header|Accept-Language|en-US +Request-Header|Cache-Control|no-cache +Request-Header|Connection|keep-alive +Request-Header|Content-Length|255 +Request-Header|Content-Type|multipart/form-data; boundary=---------------------------7e28636151054 +Request-Header|Host|localhost:9090 +Request-Header|Referer|http://localhost:9090/sjis-form.html +Request-Header|User-Agent|Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 Edge/16.16299 +Parts-Count|2 +Part-ContainsContents|japanese|健治 +Part-ContainsContents|hello|ャユ戆タ \ No newline at end of file diff --git a/jetty-http/src/test/resources/multipart/browser-capture-sjis-form-edge.raw b/jetty-http/src/test/resources/multipart/browser-capture-sjis-form-edge.raw new file mode 100644 index 00000000000..b6a9a545c58 --- /dev/null +++ b/jetty-http/src/test/resources/multipart/browser-capture-sjis-form-edge.raw @@ -0,0 +1,9 @@ +-----------------------------7e28636151054 +Content-Disposition: form-data; name="japanese" + +健治 +-----------------------------7e28636151054 +Content-Disposition: form-data; name="hello" + +ャユ戆タ +-----------------------------7e28636151054-- diff --git a/jetty-http/src/test/resources/multipart/browser-capture-sjis-form-firefox.expected.txt b/jetty-http/src/test/resources/multipart/browser-capture-sjis-form-firefox.expected.txt new file mode 100644 index 00000000000..ad25c45b321 --- /dev/null +++ b/jetty-http/src/test/resources/multipart/browser-capture-sjis-form-firefox.expected.txt @@ -0,0 +1,13 @@ +Request-Header|Accept|text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 +Request-Header|Accept-Encoding|gzip, deflate +Request-Header|Accept-Language|en-US,en;q=0.5 +Request-Header|Connection|keep-alive +Request-Header|Content-Length|261 +Request-Header|Content-Type|multipart/form-data; boundary=---------------------------265001916915724 +Request-Header|Host|localhost:9090 +Request-Header|Referer|http://localhost:9090/sjis-form.html +Request-Header|Upgrade-Insecure-Requests|1 +Request-Header|User-Agent|Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:58.0) Gecko/20100101 Firefox/58.0 +Parts-Count|2 +Part-ContainsContents|japanese|健治 +Part-ContainsContents|hello|ャユ戆タ \ No newline at end of file diff --git a/jetty-http/src/test/resources/multipart/browser-capture-sjis-form-firefox.raw b/jetty-http/src/test/resources/multipart/browser-capture-sjis-form-firefox.raw new file mode 100644 index 00000000000..5c8def3fffc --- /dev/null +++ b/jetty-http/src/test/resources/multipart/browser-capture-sjis-form-firefox.raw @@ -0,0 +1,9 @@ +-----------------------------265001916915724 +Content-Disposition: form-data; name="japanese" + + +-----------------------------265001916915724 +Content-Disposition: form-data; name="hello" + +戆^ +-----------------------------265001916915724-- diff --git a/jetty-http/src/test/resources/multipart/browser-capture-sjis-form-ios-safari.expected.txt b/jetty-http/src/test/resources/multipart/browser-capture-sjis-form-ios-safari.expected.txt new file mode 100644 index 00000000000..e4b4d8168e7 --- /dev/null +++ b/jetty-http/src/test/resources/multipart/browser-capture-sjis-form-ios-safari.expected.txt @@ -0,0 +1,14 @@ +Request-Header|Accept|text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 +Request-Header|Accept-Encoding|gzip, deflate +Request-Header|Accept-Language|en-us +Request-Header|Connection|keep-alive +Request-Header|Content-Length|249 +Request-Header|Content-Type|multipart/form-data; boundary=----WebKitFormBoundaryj1Xj6oPRT7sp3VPE +Request-Header|Host|192.168.0.119:9090 +Request-Header|Origin|http://192.168.0.119:9090 +Request-Header|Referer|http://192.168.0.119:9090/sjis-form.html +Request-Header|Upgrade-Insecure-Requests|1 +Request-Header|User-Agent|Mozilla/5.0 (iPad; CPU OS 11_2_6 like Mac OS X) AppleWebKit/604.5.6 (KHTML, like Gecko) Version/11.0 Mobile/15D100 Safari/604.1 +Parts-Count|2 +Part-ContainsContents|japanese|健治 +Part-ContainsContents|hello|ャユ戆タ \ No newline at end of file diff --git a/jetty-http/src/test/resources/multipart/browser-capture-sjis-form-ios-safari.raw b/jetty-http/src/test/resources/multipart/browser-capture-sjis-form-ios-safari.raw new file mode 100644 index 00000000000..f0d39757789 --- /dev/null +++ b/jetty-http/src/test/resources/multipart/browser-capture-sjis-form-ios-safari.raw @@ -0,0 +1,9 @@ +------WebKitFormBoundaryj1Xj6oPRT7sp3VPE +Content-Disposition: form-data; name="japanese" + + +------WebKitFormBoundaryj1Xj6oPRT7sp3VPE +Content-Disposition: form-data; name="hello" + +戆^ +------WebKitFormBoundaryj1Xj6oPRT7sp3VPE-- diff --git a/jetty-http/src/test/resources/multipart/browser-capture-sjis-form-msie.expected.txt b/jetty-http/src/test/resources/multipart/browser-capture-sjis-form-msie.expected.txt new file mode 100644 index 00000000000..d8ddc61a07e --- /dev/null +++ b/jetty-http/src/test/resources/multipart/browser-capture-sjis-form-msie.expected.txt @@ -0,0 +1,13 @@ +Request-Header|Accept|text/html, application/xhtml+xml, image/jxr, */* +Request-Header|Accept-Encoding|gzip, deflate +Request-Header|Accept-Language|en-US +Request-Header|Cache-Control|no-cache +Request-Header|Connection|keep-alive +Request-Header|Content-Length|255 +Request-Header|Content-Type|multipart/form-data; boundary=---------------------------7e21df392109c +Request-Header|Host|localhost:9090 +Request-Header|Referer|http://localhost:9090/sjis-form.html +Request-Header|User-Agent|Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko +Parts-Count|2 +Part-ContainsContents|japanese|健治 +Part-ContainsContents|hello|ャユ戆タ \ No newline at end of file diff --git a/jetty-http/src/test/resources/multipart/browser-capture-sjis-form-msie.raw b/jetty-http/src/test/resources/multipart/browser-capture-sjis-form-msie.raw new file mode 100644 index 00000000000..b60882cec82 --- /dev/null +++ b/jetty-http/src/test/resources/multipart/browser-capture-sjis-form-msie.raw @@ -0,0 +1,9 @@ +-----------------------------7e21df392109c +Content-Disposition: form-data; name="japanese" + +健治 +-----------------------------7e21df392109c +Content-Disposition: form-data; name="hello" + +ャユ戆タ +-----------------------------7e21df392109c-- diff --git a/jetty-http/src/test/resources/multipart/browser-capture-sjis-form-safari.expected.txt b/jetty-http/src/test/resources/multipart/browser-capture-sjis-form-safari.expected.txt new file mode 100644 index 00000000000..2acbd52718b --- /dev/null +++ b/jetty-http/src/test/resources/multipart/browser-capture-sjis-form-safari.expected.txt @@ -0,0 +1,14 @@ +Request-Header|Accept|text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 +Request-Header|Accept-Encoding|gzip, deflate +Request-Header|Accept-Language|en-us +Request-Header|Connection|keep-alive +Request-Header|Content-Length|249 +Request-Header|Content-Type|multipart/form-data; boundary=----WebKitFormBoundarytsFILMzOBBWaETUj +Request-Header|Host|192.168.0.119:9090 +Request-Header|Origin|http://192.168.0.119:9090 +Request-Header|Referer|http://192.168.0.119:9090/sjis-form.html +Request-Header|Upgrade-Insecure-Requests|1 +Request-Header|User-Agent|Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/604.5.6 (KHTML, like Gecko) Version/11.0.3 Safari/604.5.6 +Parts-Count|2 +Part-ContainsContents|japanese|健治 +Part-ContainsContents|hello|ャユ戆タ \ No newline at end of file diff --git a/jetty-http/src/test/resources/multipart/browser-capture-sjis-form-safari.raw b/jetty-http/src/test/resources/multipart/browser-capture-sjis-form-safari.raw new file mode 100644 index 00000000000..82475faa9e7 --- /dev/null +++ b/jetty-http/src/test/resources/multipart/browser-capture-sjis-form-safari.raw @@ -0,0 +1,9 @@ +------WebKitFormBoundarytsFILMzOBBWaETUj +Content-Disposition: form-data; name="japanese" + + +------WebKitFormBoundarytsFILMzOBBWaETUj +Content-Disposition: form-data; name="hello" + +戆^ +------WebKitFormBoundarytsFILMzOBBWaETUj-- From 2f07940052cf1a5884d8e43d9cbe35ae71faa32e Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Fri, 23 Mar 2018 10:18:03 +1100 Subject: [PATCH 27/50] compare MH5 hash without case sensitivity Signed-off-by: Greg Wilkins --- .../test/java/org/eclipse/jetty/http/MultiPartParsingTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParsingTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParsingTest.java index c3b71b32a57..1f29462c84e 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParsingTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParsingTest.java @@ -48,6 +48,7 @@ import org.eclipse.jetty.toolchain.test.TestingDir; import org.eclipse.jetty.util.IO; import org.eclipse.jetty.util.QuotedStringTokenizer; import org.eclipse.jetty.util.StringUtil; +import org.hamcrest.Matchers; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; @@ -199,7 +200,7 @@ public class MultiPartParsingTest { IO.copy(partInputStream, digester); String actualSha1sum = Hex.asHex(digest.digest()).toLowerCase(Locale.US); - assertThat("Part[" + expected.name + "].sha1sum", actualSha1sum, containsString(expected.value)); + assertThat("Part[" + expected.name + "].sha1sum", actualSha1sum, Matchers.equalToIgnoringCase(expected.value)); } } } From 8416c31ff819f5ec7fc239284c45a9022d729068 Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Tue, 27 Mar 2018 08:33:07 +1100 Subject: [PATCH 28/50] compare MH5 hash without case sensitivity Signed-off-by: Greg Wilkins --- .../test/java/org/eclipse/jetty/http/MultiPartParsingTest.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParsingTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParsingTest.java index 1f29462c84e..c3b71b32a57 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParsingTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParsingTest.java @@ -48,7 +48,6 @@ import org.eclipse.jetty.toolchain.test.TestingDir; import org.eclipse.jetty.util.IO; import org.eclipse.jetty.util.QuotedStringTokenizer; import org.eclipse.jetty.util.StringUtil; -import org.hamcrest.Matchers; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; @@ -200,7 +199,7 @@ public class MultiPartParsingTest { IO.copy(partInputStream, digester); String actualSha1sum = Hex.asHex(digest.digest()).toLowerCase(Locale.US); - assertThat("Part[" + expected.name + "].sha1sum", actualSha1sum, Matchers.equalToIgnoringCase(expected.value)); + assertThat("Part[" + expected.name + "].sha1sum", actualSha1sum, containsString(expected.value)); } } } From ca534d08fb312d662f8c01f241f030058aa75fb1 Mon Sep 17 00:00:00 2001 From: Lachlan Roberts Date: Tue, 27 Mar 2018 09:11:57 +1100 Subject: [PATCH 29/50] Minor changes to code, documentation and formatting after review. Signed-off-by: Lachlan Roberts --- ...ser.java => MultiPartFormInputStream.java} | 477 +++++++++--------- .../eclipse/jetty/http/MultiPartParser.java | 438 ++++++++-------- ...java => MultiPartFormInputStreamTest.java} | 91 ++-- .../util/MultiPartInputStreamParser.java | 31 +- .../jetty/util/ReadLineInputStream.java | 1 + .../jetty/util/MultiPartInputStreamTest.java | 2 +- 6 files changed, 538 insertions(+), 502 deletions(-) rename jetty-http/src/main/java/org/eclipse/jetty/http/{MultiPartInputStreamParser.java => MultiPartFormInputStream.java} (59%) rename jetty-http/src/test/java/org/eclipse/jetty/http/{MultiPartInputStreamTest.java => MultiPartFormInputStreamTest.java} (88%) diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartInputStreamParser.java b/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartFormInputStream.java similarity index 59% rename from jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartInputStreamParser.java rename to jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartFormInputStream.java index 1cbde8dda3e..504781e0dd8 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartInputStreamParser.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartFormInputStream.java @@ -47,22 +47,21 @@ import org.eclipse.jetty.util.LazyList; import org.eclipse.jetty.util.MultiException; import org.eclipse.jetty.util.MultiMap; import org.eclipse.jetty.util.QuotedStringTokenizer; -import org.eclipse.jetty.util.ReadLineInputStream; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; - - /** * MultiPartInputStream * * Handle a MultiPart Mime input stream, breaking it up on the boundary into files and strings. + * + * @see https://tools.ietf.org/html/rfc7578 */ -public class MultiPartInputStreamParser +public class MultiPartFormInputStream { - private static final Logger LOG = Log.getLogger(MultiPartInputStreamParser.class); - private final int _bufferSize = 16*1024; - public static final MultipartConfigElement __DEFAULT_MULTIPART_CONFIG = new MultipartConfigElement(System.getProperty("java.io.tmpdir")); + private static final Logger LOG = Log.getLogger(MultiPartFormInputStream.class); + private final int _bufferSize = 16 * 1024; + public static final MultipartConfigElement __DEFAULT_MULTIPART_CONFIG = new MultipartConfigElement(System.getProperty("java.io.tmpdir")); public static final MultiMap EMPTY_MAP = new MultiMap<>(Collections.emptyMap()); protected InputStream _in; protected MultipartConfigElement _config; @@ -74,8 +73,6 @@ public class MultiPartInputStreamParser protected boolean _deleteOnExit; protected boolean _writeFilesWithFilenames; - - public class MultiPart implements Part { protected String _name; @@ -88,8 +85,7 @@ public class MultiPartInputStreamParser protected long _size = 0; protected boolean _temporary = true; - public MultiPart (String name, String filename) - throws IOException + public MultiPart(String name, String filename) throws IOException { _name = name; _filename = filename; @@ -100,72 +96,69 @@ public class MultiPartInputStreamParser { return String.format("Part{n=%s,fn=%s,ct=%s,s=%d,t=%b,f=%s}",_name,_filename,_contentType,_size,_temporary,_file); } - protected void setContentType (String contentType) + + protected void setContentType(String contentType) { _contentType = contentType; } - - protected void open() - throws IOException + protected void open() throws IOException { - //We will either be writing to a file, if it has a filename on the content-disposition - //and otherwise a byte-array-input-stream, OR if we exceed the getFileSizeThreshold, we - //will need to change to write to a file. + // We will either be writing to a file, if it has a filename on the content-disposition + // and otherwise a byte-array-input-stream, OR if we exceed the getFileSizeThreshold, we + // will need to change to write to a file. if (isWriteFilesWithFilenames() && _filename != null && _filename.trim().length() > 0) { createFile(); } else { - //Write to a buffer in memory until we discover we've exceed the - //MultipartConfig fileSizeThreshold - _out = _bout= new ByteArrayOutputStream2(); + // Write to a buffer in memory until we discover we've exceed the + // MultipartConfig fileSizeThreshold + _out = _bout = new ByteArrayOutputStream2(); } } - protected void close() - throws IOException + protected void close() throws IOException { _out.close(); } - - protected void write (int b) - throws IOException + protected void write(int b) throws IOException { - if (MultiPartInputStreamParser.this._config.getMaxFileSize() > 0 && _size + 1 > MultiPartInputStreamParser.this._config.getMaxFileSize()) - throw new IllegalStateException ("Multipart Mime part "+_name+" exceeds max filesize"); + if (MultiPartFormInputStream.this._config.getMaxFileSize() > 0 && _size + 1 > MultiPartFormInputStream.this._config.getMaxFileSize()) + throw new IllegalStateException("Multipart Mime part " + _name + " exceeds max filesize"); - if (MultiPartInputStreamParser.this._config.getFileSizeThreshold() > 0 && _size + 1 > MultiPartInputStreamParser.this._config.getFileSizeThreshold() && _file==null) + if (MultiPartFormInputStream.this._config.getFileSizeThreshold() > 0 && _size + 1 > MultiPartFormInputStream.this._config.getFileSizeThreshold() + && _file == null) createFile(); _out.write(b); - _size ++; + _size++; } - protected void write (byte[] bytes, int offset, int length) - throws IOException + protected void write(byte[] bytes, int offset, int length) throws IOException { - if (MultiPartInputStreamParser.this._config.getMaxFileSize() > 0 && _size + length > MultiPartInputStreamParser.this._config.getMaxFileSize()) - throw new IllegalStateException ("Multipart Mime part "+_name+" exceeds max filesize"); + if (MultiPartFormInputStream.this._config.getMaxFileSize() > 0 && _size + length > MultiPartFormInputStream.this._config.getMaxFileSize()) + throw new IllegalStateException("Multipart Mime part " + _name + " exceeds max filesize"); - if (MultiPartInputStreamParser.this._config.getFileSizeThreshold() > 0 && _size + length > MultiPartInputStreamParser.this._config.getFileSizeThreshold() && _file==null) + if (MultiPartFormInputStream.this._config.getFileSizeThreshold() > 0 + && _size + length > MultiPartFormInputStream.this._config.getFileSizeThreshold() && _file == null) createFile(); - _out.write(bytes, offset, length); + _out.write(bytes,offset,length); _size += length; } - protected void createFile () - throws IOException + protected void createFile() throws IOException { - /* Some statics just to make the code below easier to understand - * This get optimized away during the compile anyway */ + /* + * Some statics just to make the code below easier to understand This get optimized away during the compile anyway + */ final boolean USER = true; final boolean WORLD = false; - - _file = File.createTempFile("MultiPart", "", MultiPartInputStreamParser.this._tmpDir); + + _file = File.createTempFile("MultiPart","",MultiPartFormInputStream.this._tmpDir); _file.setReadable(false,WORLD); // (reset) disable it for everyone first _file.setReadable(true,USER); // enable for user only @@ -176,7 +169,7 @@ public class MultiPartInputStreamParser if (_size > 0 && _out != null) { - //already written some bytes, so need to copy them into the file + // already written some bytes, so need to copy them into the file _out.flush(); _bout.writeTo(bos); _out.close(); @@ -185,8 +178,6 @@ public class MultiPartInputStreamParser _out = bos; } - - protected void setHeaders(MultiMap headers) { _headers = headers; @@ -206,10 +197,10 @@ public class MultiPartInputStreamParser */ @Override public String getHeader(String name) - { + { if (name == null) return null; - return _headers.getValue(name.toLowerCase(Locale.ENGLISH), 0); + return _headers.getValue(name.toLowerCase(Locale.ENGLISH),0); } /** @@ -227,7 +218,7 @@ public class MultiPartInputStreamParser @Override public Collection getHeaders(String name) { - return _headers.getValues(name); + return _headers.getValues(name); } /** @@ -236,19 +227,18 @@ public class MultiPartInputStreamParser @Override public InputStream getInputStream() throws IOException { - if (_file != null) - { - //written to a file, whether temporary or not - return new BufferedInputStream (new FileInputStream(_file)); - } - else - { - //part content is in memory - return new ByteArrayInputStream(_bout.getBuf(),0,_bout.size()); - } + if (_file != null) + { + // written to a file, whether temporary or not + return new BufferedInputStream(new FileInputStream(_file)); + } + else + { + // part content is in memory + return new ByteArrayInputStream(_bout.getBuf(),0,_bout.size()); + } } - /** * @see javax.servlet.http.Part#getSubmittedFileName() */ @@ -260,7 +250,7 @@ public class MultiPartInputStreamParser public byte[] getBytes() { - if (_bout!=null) + if (_bout != null) return _bout.toByteArray(); return null; } @@ -271,7 +261,7 @@ public class MultiPartInputStreamParser @Override public String getName() { - return _name; + return _name; } /** @@ -293,8 +283,8 @@ public class MultiPartInputStreamParser { _temporary = false; - //part data is only in the ByteArrayOutputStream and never been written to disk - _file = new File (_tmpDir, fileName); + // part data is only in the ByteArrayOutputStream and never been written to disk + _file = new File(_tmpDir,fileName); BufferedOutputStream bos = null; try @@ -312,19 +302,19 @@ public class MultiPartInputStreamParser } else { - //the part data is already written to a temporary file, just rename it + // the part data is already written to a temporary file, just rename it _temporary = false; Path src = _file.toPath(); Path target = src.resolveSibling(fileName); - Files.move(src, target, StandardCopyOption.REPLACE_EXISTING); + Files.move(src,target,StandardCopyOption.REPLACE_EXISTING); _file = target.toFile(); } } /** - * Remove the file, whether or not Part.write() was called on it - * (ie no longer temporary) + * Remove the file, whether or not Part.write() was called on it (ie no longer temporary) + * * @see javax.servlet.http.Part#delete() */ @Override @@ -337,7 +327,8 @@ public class MultiPartInputStreamParser /** * Only remove tmp files. * - * @throws IOException if unable to delete the file + * @throws IOException + * if unable to delete the file */ public void cleanUp() throws IOException { @@ -345,47 +336,48 @@ public class MultiPartInputStreamParser _file.delete(); } - /** * Get the file + * * @return the file, if any, the data has been written to. */ - public File getFile () + public File getFile() { return _file; } - /** * Get the filename from the content-disposition. + * * @return null or the filename */ - public String getContentDispositionFilename () + public String getContentDispositionFilename() { return _filename; } } - - - /** - * @param in Request input stream - * @param contentType Content-Type header - * @param config MultipartConfigElement - * @param contextTmpDir javax.servlet.context.tempdir + * @param in + * Request input stream + * @param contentType + * Content-Type header + * @param config + * MultipartConfigElement + * @param contextTmpDir + * javax.servlet.context.tempdir */ - public MultiPartInputStreamParser (InputStream in, String contentType, MultipartConfigElement config, File contextTmpDir) + public MultiPartFormInputStream(InputStream in, String contentType, MultipartConfigElement config, File contextTmpDir) { _contentType = contentType; _config = config; _contextTmpDir = contextTmpDir; if (_contextTmpDir == null) - _contextTmpDir = new File (System.getProperty("java.io.tmpdir")); + _contextTmpDir = new File(System.getProperty("java.io.tmpdir")); if (_config == null) _config = new MultipartConfigElement(_contextTmpDir.getAbsolutePath()); - + if (in instanceof ServletInputStream) { if (((ServletInputStream)in).isFinished()) @@ -394,11 +386,12 @@ public class MultiPartInputStreamParser return; } } - _in = new ReadLineInputStream(in); + _in = new BufferedInputStream(in); } /** * Get the already parsed parts. + * * @return the parts that were parsed */ public Collection getParsedParts() @@ -408,9 +401,9 @@ public class MultiPartInputStreamParser Collection> values = _parts.values(); List parts = new ArrayList<>(); - for (List o: values) + for (List o : values) { - List asList = LazyList.getList(o, false); + List asList = LazyList.getList(o,false); parts.addAll(asList); } return parts; @@ -419,20 +412,20 @@ public class MultiPartInputStreamParser /** * Delete any tmp storage for parts, and clear out the parts list. * - * @throws MultiException if unable to delete the parts + * @throws MultiException + * if unable to delete the parts */ - public void deleteParts () - throws MultiException + public void deleteParts() throws MultiException { Collection parts = getParsedParts(); MultiException err = new MultiException(); - for (Part p:parts) + for (Part p : parts) { try { - ((MultiPartInputStreamParser.MultiPart)p).cleanUp(); + ((MultiPart)p).cleanUp(); } - catch(Exception e) + catch (Exception e) { err.add(e); } @@ -442,53 +435,51 @@ public class MultiPartInputStreamParser err.ifExceptionThrowMulti(); } - /** * Parse, if necessary, the multipart data and return the list of Parts. * * @return the parts - * @throws IOException if unable to get the parts + * @throws IOException + * if unable to get the parts */ - public Collection getParts() - throws IOException + public Collection getParts() throws IOException { parse(); throwIfError(); - Collection> values = _parts.values(); List parts = new ArrayList<>(); - for (List o: values) + for (List o : values) { - List asList = LazyList.getList(o, false); + List asList = LazyList.getList(o,false); parts.addAll(asList); } return parts; } - /** * Get the named Part. * - * @param name the part name + * @param name + * the part name * @return the parts - * @throws IOException if unable to get the part + * @throws IOException + * if unable to get the part */ - public Part getPart(String name) - throws IOException + public Part getPart(String name) throws IOException { parse(); - throwIfError(); - return _parts.getValue(name, 0); + throwIfError(); + return _parts.getValue(name,0); } /** * Throws an exception if one has been latched. * - * @throws IOException the exception (if present) + * @throws IOException + * the exception (if present) */ - protected void throwIfError () - throws IOException + protected void throwIfError() throws IOException { if (_err != null) { @@ -505,34 +496,33 @@ public class MultiPartInputStreamParser * Parse, if necessary, the multipart stream. * */ - protected void parse () + protected void parse() { - //have we already parsed the input? + // have we already parsed the input? if (_parts != null || _err != null) return; try { - //initialize + // initialize _parts = new MultiMap<>(); - //if its not a multipart request, don't parse it + // if its not a multipart request, don't parse it if (_contentType == null || !_contentType.startsWith("multipart/form-data")) return; - - //sort out the location to which to write the files + // sort out the location to which to write the files if (_config.getLocation() == null) _tmpDir = _contextTmpDir; else if ("".equals(_config.getLocation())) _tmpDir = _contextTmpDir; else { - File f = new File (_config.getLocation()); + File f = new File(_config.getLocation()); if (f.isAbsolute()) _tmpDir = f; else - _tmpDir = new File (_contextTmpDir, _config.getLocation()); + _tmpDir = new File(_contextTmpDir,_config.getLocation()); } if (!_tmpDir.exists()) @@ -542,72 +532,74 @@ public class MultiPartInputStreamParser int bstart = _contentType.indexOf("boundary="); if (bstart >= 0) { - int bend = _contentType.indexOf(";", bstart); - bend = (bend < 0? _contentType.length(): bend); + int bend = _contentType.indexOf(";",bstart); + bend = (bend < 0?_contentType.length():bend); contentTypeBoundary = QuotedStringTokenizer.unquote(value(_contentType.substring(bstart,bend)).trim()); } - Handler handler = new Handler(); - MultiPartParser parser = new MultiPartParser(handler,contentTypeBoundary); - + MultiPartParser parser = new MultiPartParser(handler,contentTypeBoundary); // Create a buffer to store data from stream // byte[] data = new byte[_bufferSize]; - int len=0; + int len = 0; - /* keep running total of size of bytes read from input - * and throw an exception if exceeds MultipartConfigElement._maxRequestSize */ - long total = 0; + /* + * keep running total of size of bytes read from input and throw an exception if exceeds MultipartConfigElement._maxRequestSize + */ + long total = 0; - while(true) + while (true) { len = _in.read(data); - if(len > 0) + if (len > 0) { - total+=len; - if(_config.getMaxRequestSize() > 0 && total > _config.getMaxRequestSize()) + total += len; + if (_config.getMaxRequestSize() > 0 && total > _config.getMaxRequestSize()) { - _err = new IllegalStateException ("Request exceeds maxRequestSize ("+_config.getMaxRequestSize()+")"); + _err = new IllegalStateException("Request exceeds maxRequestSize (" + _config.getMaxRequestSize() + ")"); return; } ByteBuffer buffer = BufferUtil.toBuffer(data); buffer.limit(len); - parser.parse(buffer, false); - } - else if (len == -1) + if (parser.parse(buffer,false)) + break; + + if(buffer.hasRemaining()) + throw new IllegalStateException("Buffer did not fully consume"); + + } + else if (len == -1) { - parser.parse(BufferUtil.EMPTY_BUFFER, true); + parser.parse(BufferUtil.EMPTY_BUFFER,true); break; } } - - //check for exceptions - if(_err != null) + // check for exceptions + if (_err != null) { return; } - //check we read to the end of the message - if(parser.getState() != MultiPartParser.State.END) + // check we read to the end of the message + if (parser.getState() != MultiPartParser.State.END) { - if(parser.getState() == MultiPartParser.State.PREAMBLE) + if (parser.getState() == MultiPartParser.State.PREAMBLE) _err = new IOException("Missing initial multi part boundary"); else _err = new IOException("Incomplete Multipart"); } - if(LOG.isDebugEnabled()) + if (LOG.isDebugEnabled()) { LOG.debug("Parsing Complete {} err={}",parser,_err); } - } catch (Throwable e) { @@ -616,98 +608,83 @@ public class MultiPartInputStreamParser } } - + class Handler implements MultiPartParser.Handler { - - private MultiPart _part=null; - private String contentDisposition=null; - private String contentType=null; + + private MultiPart _part = null; + private String contentDisposition = null; + private String contentType = null; private MultiMap headers = new MultiMap<>(); - + @Override - public boolean messageComplete() { return true; } - + public boolean messageComplete() + { + return true; + } + @Override public void parsedField(String key, String value) { // Add to headers and mark if one of these fields. // - headers.put(key.toLowerCase(Locale.ENGLISH), value); + headers.put(key.toLowerCase(Locale.ENGLISH),value); if (key.equalsIgnoreCase("content-disposition")) - contentDisposition=value; + contentDisposition = value; else if (key.equalsIgnoreCase("content-type")) - contentType = value; - + contentType = value; } @Override - public boolean headerComplete() { - - try { - + public boolean headerComplete() + { + try + { // Extract content-disposition - boolean form_data=false; - if(contentDisposition==null) + boolean form_data = false; + if (contentDisposition == null) { throw new IOException("Missing content-disposition"); } - - QuotedStringTokenizer tok=new QuotedStringTokenizer(contentDisposition,";", false, true); - String name=null; - String filename=null; - while(tok.hasMoreTokens()) + + QuotedStringTokenizer tok = new QuotedStringTokenizer(contentDisposition,";",false,true); + String name = null; + String filename = null; + while (tok.hasMoreTokens()) { - String t=tok.nextToken().trim(); - String tl=t.toLowerCase(Locale.ENGLISH); - if(t.startsWith("form-data")) - form_data=true; - else if(tl.startsWith("name=")) - name=value(t); - else if(tl.startsWith("filename=")) - filename=filenameValue(t); + String t = tok.nextToken().trim(); + String tl = t.toLowerCase(Locale.ENGLISH); + if (t.startsWith("form-data")) + form_data = true; + else if (tl.startsWith("name=")) + name = value(t); + else if (tl.startsWith("filename=")) + filename = filenameValue(t); } - + // Check disposition - if(!form_data) + if (!form_data) { return false; } - //It is valid for reset and submit buttons to have an empty name. - //If no name is supplied, the browser skips sending the info for that field. - //However, if you supply the empty string as the name, the browser sends the - //field, with name as the empty string. So, only continue this loop if we - //have not yet seen a name field. - if(name==null) + // It is valid for reset and submit buttons to have an empty name. + // If no name is supplied, the browser skips sending the info for that field. + // However, if you supply the empty string as the name, the browser sends the + // field, with name as the empty string. So, only continue this loop if we + // have not yet seen a name field. + if (name == null) { return false; } - //create the new part - _part = new MultiPart(name, filename); + // create the new part + _part = new MultiPart(name,filename); _part.setHeaders(headers); _part.setContentType(contentType); - _parts.add(name, _part); - } - catch (Exception e) - { - _err = e; - return true; - } - - return false; - } - - @Override - public boolean content(ByteBuffer buffer, boolean last) - { - if (BufferUtil.hasContent(buffer)) - { + _parts.add(name,_part); + try { - //write the content data to the part _part.open(); - _part.write(buffer.array(),buffer.arrayOffset()+buffer.position(),buffer.remaining()); - _part.close(); } catch (IOException e) { @@ -715,13 +692,48 @@ public class MultiPartInputStreamParser return true; } } - - if (last) - reset(); - + catch (Exception e) + { + _err = e; + return true; + } + return false; } - + + @Override + public boolean content(ByteBuffer buffer, boolean last) + { + if (BufferUtil.hasContent(buffer)) + { + try + { + _part.write(buffer.array(),buffer.arrayOffset() + buffer.position(),buffer.remaining()); + } + catch (IOException e) + { + _err = e; + return true; + } + } + + if (last) + { + try + { + _part.close(); + } + catch (IOException e) + { + _err = e; + return true; + } + reset(); + } + + return false; + } + public void reset() { _part = null; @@ -729,21 +741,27 @@ public class MultiPartInputStreamParser contentType = null; headers = new MultiMap<>(); } - + + @Override + public void earlyEOF() + { + if (LOG.isDebugEnabled()) + LOG.debug("Early EOF {}",MultiPartFormInputStream.this); + } + } - - + public void setDeleteOnExit(boolean deleteOnExit) { _deleteOnExit = deleteOnExit; } - public void setWriteFilesWithFilenames (boolean writeFilesWithFilenames) + public void setWriteFilesWithFilenames(boolean writeFilesWithFilenames) { _writeFilesWithFilenames = writeFilesWithFilenames; } - - public boolean isWriteFilesWithFilenames () + + public boolean isWriteFilesWithFilenames() { return _writeFilesWithFilenames; } @@ -753,42 +771,39 @@ public class MultiPartInputStreamParser return _deleteOnExit; } - /* ------------------------------------------------------------ */ private String value(String nameEqualsValue) { int idx = nameEqualsValue.indexOf('='); - String value = nameEqualsValue.substring(idx+1).trim(); + String value = nameEqualsValue.substring(idx + 1).trim(); return QuotedStringTokenizer.unquoteOnly(value); } - /* ------------------------------------------------------------ */ private String filenameValue(String nameEqualsValue) { int idx = nameEqualsValue.indexOf('='); - String value = nameEqualsValue.substring(idx+1).trim(); + String value = nameEqualsValue.substring(idx + 1).trim(); if (value.matches(".??[a-z,A-Z]\\:\\\\[^\\\\].*")) { - //incorrectly escaped IE filenames that have the whole path - //we just strip any leading & trailing quotes and leave it as is - char first=value.charAt(0); - if (first=='"' || first=='\'') - value=value.substring(1); - char last=value.charAt(value.length()-1); - if (last=='"' || last=='\'') - value = value.substring(0,value.length()-1); + // incorrectly escaped IE filenames that have the whole path + // we just strip any leading & trailing quotes and leave it as is + char first = value.charAt(0); + if (first == '"' || first == '\'') + value = value.substring(1); + char last = value.charAt(value.length() - 1); + if (last == '"' || last == '\'') + value = value.substring(0,value.length() - 1); return value; } else - //unquote the string, but allow any backslashes that don't - //form a valid escape sequence to remain as many browsers - //even on *nix systems will not escape a filename containing - //backslashes - return QuotedStringTokenizer.unquoteOnly(value, true); + // unquote the string, but allow any backslashes that don't + // form a valid escape sequence to remain as many browsers + // even on *nix systems will not escape a filename containing + // backslashes + return QuotedStringTokenizer.unquoteOnly(value,true); } - } diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartParser.java b/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartParser.java index b6a74c6b70b..7e6c40ec103 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartParser.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartParser.java @@ -29,7 +29,6 @@ import org.eclipse.jetty.util.SearchPattern; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; - /* ------------------------------------------------------------ */ /* * RFC2046 and RFC7578 @@ -114,42 +113,42 @@ public class MultiPartParser { public static final Logger LOG = Log.getLogger(MultiPartParser.class); - static final byte COLON= (byte)':'; - static final byte TAB= 0x09; - static final byte LINE_FEED= 0x0A; - static final byte CARRIAGE_RETURN= 0x0D; - static final byte SPACE= 0x20; - static final byte[] CRLF = {CARRIAGE_RETURN,LINE_FEED}; - static final byte SEMI_COLON= (byte)';'; - + static final byte COLON = (byte)':'; + static final byte TAB = 0x09; + static final byte LINE_FEED = 0x0A; + static final byte CARRIAGE_RETURN = 0x0D; + static final byte SPACE = 0x20; + static final byte[] CRLF = + { CARRIAGE_RETURN, LINE_FEED }; + static final byte SEMI_COLON = (byte)';'; // States public enum FieldState { FIELD, IN_NAME, - AFTER_NAME, + AFTER_NAME, VALUE, IN_VALUE } - + // States public enum State { PREAMBLE, DELIMITER, - DELIMITER_PADDING, - DELIMITER_CLOSE, + DELIMITER_PADDING, + DELIMITER_CLOSE, BODY_PART, - FIRST_OCTETS, - OCTETS, - EPILOGUE, + FIRST_OCTETS, + OCTETS, + EPILOGUE, END } private final static EnumSet __delimiterStates = EnumSet.of(State.DELIMITER,State.DELIMITER_CLOSE,State.DELIMITER_PADDING); - - private final boolean DEBUG=LOG.isDebugEnabled(); + + private final boolean DEBUG = LOG.isDebugEnabled(); private final Handler _handler; private final SearchPattern _delimiterSearch; @@ -162,7 +161,7 @@ public class MultiPartParser private boolean _cr; private ByteBuffer _patternBuffer; - private final StringBuilder _string=new StringBuilder(); + private final StringBuilder _string = new StringBuilder(); private int _length; private int _totalHeaderLineLength = -1; @@ -173,7 +172,7 @@ public class MultiPartParser { _handler = handler; - String delimiter = "\r\n--"+boundary; + String delimiter = "\r\n--" + boundary; _patternBuffer = ByteBuffer.wrap(delimiter.getBytes(StandardCharsets.US_ASCII)); _delimiterSearch = SearchPattern.compile(_patternBuffer.array()); } @@ -184,14 +183,13 @@ public class MultiPartParser _fieldState = FieldState.FIELD; _partialBoundary = 2; // No CRLF if no preamble } - - + /* ------------------------------------------------------------------------------- */ public Handler getHandler() { return _handler; } - + /* ------------------------------------------------------------------------------- */ public State getState() { @@ -205,54 +203,57 @@ public class MultiPartParser } /* ------------------------------------------------------------------------------- */ - enum CharState { ILLEGAL, CR, LF, LEGAL } + enum CharState + { + ILLEGAL, CR, LF, LEGAL + } private final static CharState[] __charState; static { - // token = 1*tchar - // tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" - // / "+" / "-" / "." / "^" / "_" / "`" / "|" / "~" - // / DIGIT / ALPHA - // ; any VCHAR, except delimiters - // quoted-string = DQUOTE *( qdtext / quoted-pair ) DQUOTE - // qdtext = HTAB / SP /%x21 / %x23-5B / %x5D-7E / obs-text - // obs-text = %x80-FF - // comment = "(" *( ctext / quoted-pair / comment ) ")" - // ctext = HTAB / SP / %x21-27 / %x2A-5B / %x5D-7E / obs-text - // quoted-pair = "\" ( HTAB / SP / VCHAR / obs-text ) + // token = 1*tchar + // tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" + // / "+" / "-" / "." / "^" / "_" / "`" / "|" / "~" + // / DIGIT / ALPHA + // ; any VCHAR, except delimiters + // quoted-string = DQUOTE *( qdtext / quoted-pair ) DQUOTE + // qdtext = HTAB / SP /%x21 / %x23-5B / %x5D-7E / obs-text + // obs-text = %x80-FF + // comment = "(" *( ctext / quoted-pair / comment ) ")" + // ctext = HTAB / SP / %x21-27 / %x2A-5B / %x5D-7E / obs-text + // quoted-pair = "\" ( HTAB / SP / VCHAR / obs-text ) - __charState=new CharState[256]; + __charState = new CharState[256]; Arrays.fill(__charState,CharState.ILLEGAL); - __charState[LINE_FEED]=CharState.LF; - __charState[CARRIAGE_RETURN]=CharState.CR; - __charState[TAB]=CharState.LEGAL; - __charState[SPACE]=CharState.LEGAL; + __charState[LINE_FEED] = CharState.LF; + __charState[CARRIAGE_RETURN] = CharState.CR; + __charState[TAB] = CharState.LEGAL; + __charState[SPACE] = CharState.LEGAL; - __charState['!']=CharState.LEGAL; - __charState['#']=CharState.LEGAL; - __charState['$']=CharState.LEGAL; - __charState['%']=CharState.LEGAL; - __charState['&']=CharState.LEGAL; - __charState['\'']=CharState.LEGAL; - __charState['*']=CharState.LEGAL; - __charState['+']=CharState.LEGAL; - __charState['-']=CharState.LEGAL; - __charState['.']=CharState.LEGAL; - __charState['^']=CharState.LEGAL; - __charState['_']=CharState.LEGAL; - __charState['`']=CharState.LEGAL; - __charState['|']=CharState.LEGAL; - __charState['~']=CharState.LEGAL; + __charState['!'] = CharState.LEGAL; + __charState['#'] = CharState.LEGAL; + __charState['$'] = CharState.LEGAL; + __charState['%'] = CharState.LEGAL; + __charState['&'] = CharState.LEGAL; + __charState['\''] = CharState.LEGAL; + __charState['*'] = CharState.LEGAL; + __charState['+'] = CharState.LEGAL; + __charState['-'] = CharState.LEGAL; + __charState['.'] = CharState.LEGAL; + __charState['^'] = CharState.LEGAL; + __charState['_'] = CharState.LEGAL; + __charState['`'] = CharState.LEGAL; + __charState['|'] = CharState.LEGAL; + __charState['~'] = CharState.LEGAL; - __charState['"']=CharState.LEGAL; + __charState['"'] = CharState.LEGAL; - __charState['\\']=CharState.LEGAL; - __charState['(']=CharState.LEGAL; - __charState[')']=CharState.LEGAL; - Arrays.fill(__charState,0x21,0x27+1,CharState.LEGAL); - Arrays.fill(__charState,0x2A,0x5B+1,CharState.LEGAL); - Arrays.fill(__charState,0x5D,0x7E+1,CharState.LEGAL); - Arrays.fill(__charState,0x80,0xFF+1,CharState.LEGAL); + __charState['\\'] = CharState.LEGAL; + __charState['('] = CharState.LEGAL; + __charState[')'] = CharState.LEGAL; + Arrays.fill(__charState,0x21,0x27 + 1,CharState.LEGAL); + Arrays.fill(__charState,0x2A,0x5B + 1,CharState.LEGAL); + Arrays.fill(__charState,0x5D,0x7E + 1,CharState.LEGAL); + Arrays.fill(__charState,0x80,0xFF + 1,CharState.LEGAL); } @@ -261,7 +262,7 @@ public class MultiPartParser { return BufferUtil.hasContent(buffer); } - + /* ------------------------------------------------------------------------------- */ private byte getNextByte(ByteBuffer buffer) { @@ -269,17 +270,17 @@ public class MultiPartParser byte ch = buffer.get(); CharState s = __charState[0xff & ch]; - switch(s) + switch (s) { case LF: - _cr=false; + _cr = false; return ch; case CR: if (_cr) throw new BadMessageException("Bad EOL"); - - _cr=true; + + _cr = true; if (buffer.hasRemaining()) return getNextByte(buffer); @@ -299,75 +300,75 @@ public class MultiPartParser } } - /* ------------------------------------------------------------------------------- */ private void setString(String s) { _string.setLength(0); _string.append(s); - _length=s.length(); + _length = s.length(); } /* ------------------------------------------------------------------------------- */ private String takeString() { _string.setLength(_length); - String s =_string.toString(); + String s = _string.toString(); _string.setLength(0); - _length=-1; + _length = -1; return s; } - - + /* ------------------------------------------------------------------------------- */ /** * Parse until next Event. - * @param buffer the buffer to parse + * + * @param buffer + * the buffer to parse * @return True if an {@link RequestHandler} method was called and it returned true; */ public boolean parse(ByteBuffer buffer, boolean last) { boolean handle = false; - while(handle==false && BufferUtil.hasContent(buffer)) + while (handle == false && BufferUtil.hasContent(buffer)) { - switch(_state) + switch (_state) { case PREAMBLE: parsePreamble(buffer); continue; - + case DELIMITER: case DELIMITER_PADDING: case DELIMITER_CLOSE: parseDelimiter(buffer); continue; - + case BODY_PART: handle = parseMimePartHeaders(buffer); break; - + case FIRST_OCTETS: case OCTETS: handle = parseOctetContent(buffer); break; - + case EPILOGUE: BufferUtil.clear(buffer); break; - + case END: handle = true; break; - + default: throw new IllegalStateException(); - + } } - - if(last && BufferUtil.isEmpty(buffer)) + + if (last && BufferUtil.isEmpty(buffer)) { - if(_state == State.EPILOGUE) + if (_state == State.EPILOGUE) { _state = State.END; return _handler.messageComplete(); @@ -378,21 +379,21 @@ public class MultiPartParser return true; } } - + return handle; } - + /* ------------------------------------------------------------------------------- */ private void parsePreamble(ByteBuffer buffer) { - if (_partialBoundary>0) + if (_partialBoundary > 0) { - int partial = _delimiterSearch.startsWith(buffer.array(),buffer.arrayOffset()+buffer.position(),buffer.remaining(),_partialBoundary); - if (partial>0) + int partial = _delimiterSearch.startsWith(buffer.array(),buffer.arrayOffset() + buffer.position(),buffer.remaining(),_partialBoundary); + if (partial > 0) { - if (partial==_delimiterSearch.getLength()) + if (partial == _delimiterSearch.getLength()) { - buffer.position(buffer.position()+partial-_partialBoundary); + buffer.position(buffer.position() + partial - _partialBoundary); _partialBoundary = 0; setState(State.DELIMITER); return; @@ -402,61 +403,61 @@ public class MultiPartParser BufferUtil.clear(buffer); return; } - + _partialBoundary = 0; } - - int delimiter = _delimiterSearch.match(buffer.array(),buffer.arrayOffset()+buffer.position(),buffer.remaining()); - if (delimiter>=0) + + int delimiter = _delimiterSearch.match(buffer.array(),buffer.arrayOffset() + buffer.position(),buffer.remaining()); + if (delimiter >= 0) { - buffer.position(delimiter-buffer.arrayOffset()+_delimiterSearch.getLength()); + buffer.position(delimiter - buffer.arrayOffset() + _delimiterSearch.getLength()); setState(State.DELIMITER); return; } - _partialBoundary = _delimiterSearch.endsWith(buffer.array(),buffer.arrayOffset()+buffer.position(),buffer.remaining()); + _partialBoundary = _delimiterSearch.endsWith(buffer.array(),buffer.arrayOffset() + buffer.position(),buffer.remaining()); BufferUtil.clear(buffer); return; } - + /* ------------------------------------------------------------------------------- */ private void parseDelimiter(ByteBuffer buffer) - { + { while (__delimiterStates.contains(_state) && hasNextByte(buffer)) { - byte b=getNextByte(buffer); - if (b==0) + byte b = getNextByte(buffer); + if (b == 0) return; - - if (b=='\n') + + if (b == '\n') { setState(State.BODY_PART); _handler.startPart(); return; - } + } - switch(_state) + switch (_state) { case DELIMITER: - if (b=='-') + if (b == '-') setState(State.DELIMITER_CLOSE); else setState(State.DELIMITER_PADDING); continue; - + case DELIMITER_CLOSE: - if (b=='-') + if (b == '-') { setState(State.EPILOGUE); return; } setState(State.DELIMITER_PADDING); continue; - + case DELIMITER_PADDING: default: - continue; + continue; } } } @@ -468,44 +469,43 @@ public class MultiPartParser protected boolean parseMimePartHeaders(ByteBuffer buffer) { // Process headers - while (_state==State.BODY_PART && hasNextByte(buffer)) + while (_state == State.BODY_PART && hasNextByte(buffer)) { // process each character - byte b=getNextByte(buffer); - if (b==0) + byte b = getNextByte(buffer); + if (b == 0) break; - - if(b!=LINE_FEED) - _totalHeaderLineLength++; - - if(_totalHeaderLineLength > _maxHeaderLineLength) - throw new IllegalStateException("Header Line Exceeded Max Length"); + if (b != LINE_FEED) + _totalHeaderLineLength++; + + if (_totalHeaderLineLength > _maxHeaderLineLength) + throw new IllegalStateException("Header Line Exceeded Max Length"); switch (_fieldState) { case FIELD: - switch(b) + switch (b) { case SPACE: case TAB: { // Folded field value! - - if (_fieldName==null) + + if (_fieldName == null) throw new IllegalStateException("First field folded"); - - if (_fieldValue==null) + + if (_fieldValue == null) { _string.setLength(0); - _length=0; + _length = 0; } else { setString(_fieldValue); _string.append(' '); _length++; - _fieldValue=null; + _fieldValue = null; } setState(FieldState.VALUE); break; @@ -530,100 +530,100 @@ public class MultiPartParser setState(FieldState.IN_NAME); _string.setLength(0); _string.append((char)b); - _length=1; + _length = 1; } } break; case IN_NAME: - switch(b) + switch (b) { case COLON: - _fieldName=takeString(); - _length=-1; + _fieldName = takeString(); + _length = -1; setState(FieldState.VALUE); break; - + case SPACE: - //Ignore trailing whitespaces + // Ignore trailing whitespaces setState(FieldState.AFTER_NAME); break; - + default: _string.append((char)b); - _length=_string.length(); + _length = _string.length(); break; } break; - + case AFTER_NAME: - switch(b) + switch (b) { case COLON: - _fieldName=takeString(); - _length=-1; + _fieldName = takeString(); + _length = -1; setState(FieldState.VALUE); break; - + case LINE_FEED: - _fieldName=takeString(); + _fieldName = takeString(); _string.setLength(0); - _fieldValue=""; - _length=-1; + _fieldValue = ""; + _length = -1; break; - + case SPACE: break; - + default: throw new IllegalCharacterException(_state,b,buffer); } break; - + case VALUE: - switch(b) + switch (b) { case LINE_FEED: _string.setLength(0); - _fieldValue=""; - _length=-1; + _fieldValue = ""; + _length = -1; setState(FieldState.FIELD); break; - + case SPACE: case TAB: break; - + default: - _string.append((char)(0xff&b)); - _length=_string.length(); + _string.append((char)(0xff & b)); + _length = _string.length(); setState(FieldState.IN_VALUE); break; } break; case IN_VALUE: - switch(b) + switch (b) { case SPACE: - _string.append((char)(0xff&b)); + _string.append((char)(0xff & b)); break; case LINE_FEED: if (_length > 0) { - _fieldValue=takeString(); - _length=-1; - _totalHeaderLineLength=-1; + _fieldValue = takeString(); + _length = -1; + _totalHeaderLineLength = -1; } setState(FieldState.FIELD); break; default: - _string.append((char)(0xff&b)); - if (b>SPACE || b<0) - _length=_string.length(); + _string.append((char)(0xff & b)); + if (b > SPACE || b < 0) + _length = _string.length(); break; } break; @@ -635,95 +635,91 @@ public class MultiPartParser } return false; } - + /* ------------------------------------------------------------------------------- */ private void handleField() { - if (_fieldName!=null && _fieldValue!=null) + if (_fieldName != null && _fieldValue != null) _handler.parsedField(_fieldName,_fieldValue); _fieldName = _fieldValue = null; } - + /* ------------------------------------------------------------------------------- */ protected boolean parseOctetContent(ByteBuffer buffer) { - - //Starts With - if (_partialBoundary>0) + + // Starts With + if (_partialBoundary > 0) { - int partial = _delimiterSearch.startsWith(buffer.array(),buffer.arrayOffset()+buffer.position(),buffer.remaining(),_partialBoundary); - if (partial>0) + int partial = _delimiterSearch.startsWith(buffer.array(),buffer.arrayOffset() + buffer.position(),buffer.remaining(),_partialBoundary); + if (partial > 0) { - if (partial==_delimiterSearch.getLength()) + if (partial == _delimiterSearch.getLength()) { buffer.position(buffer.position() + _delimiterSearch.getLength() - _partialBoundary); setState(State.DELIMITER); _partialBoundary = 0; - return _handler.content(BufferUtil.EMPTY_BUFFER, true); + return _handler.content(BufferUtil.EMPTY_BUFFER,true); } _partialBoundary = partial; - BufferUtil.clear(buffer); + BufferUtil.clear(buffer); return false; } else { - //output up to _partialBoundary of the search pattern + // output up to _partialBoundary of the search pattern ByteBuffer content = _patternBuffer.slice(); - if (_state==State.FIRST_OCTETS) + if (_state == State.FIRST_OCTETS) { setState(State.OCTETS); content.position(2); } content.limit(_partialBoundary); _partialBoundary = 0; - - if (_handler.content(content, false)) + + if (_handler.content(content,false)) return true; } } - - + // Contains - int delimiter = _delimiterSearch.match(buffer.array(),buffer.arrayOffset()+buffer.position(),buffer.remaining()); - if (delimiter>=0) + int delimiter = _delimiterSearch.match(buffer.array(),buffer.arrayOffset() + buffer.position(),buffer.remaining()); + if (delimiter >= 0) { ByteBuffer content = buffer.slice(); content.limit(delimiter - buffer.arrayOffset() - buffer.position()); - + buffer.position(delimiter - buffer.arrayOffset() + _delimiterSearch.getLength()); setState(State.DELIMITER); - - return _handler.content(content, true); + + return _handler.content(content,true); } - // Ends With - _partialBoundary = _delimiterSearch.endsWith(buffer.array(), buffer.arrayOffset()+buffer.position(), buffer.remaining()); - if(_partialBoundary > 0) + _partialBoundary = _delimiterSearch.endsWith(buffer.array(),buffer.arrayOffset() + buffer.position(),buffer.remaining()); + if (_partialBoundary > 0) { ByteBuffer content = buffer.slice(); content.limit(content.limit() - _partialBoundary); - + BufferUtil.clear(buffer); - return _handler.content(content, false); + return _handler.content(content,false); } - - + // There is normal content with no delimiter ByteBuffer content = buffer.slice(); BufferUtil.clear(buffer); - return _handler.content(content, false); + return _handler.content(content,false); } - /* ------------------------------------------------------------------------------- */ private void setState(State state) { if (DEBUG) LOG.debug("{} --> {}",_state,state); - _state=state; + _state = state; } /* ------------------------------------------------------------------------------- */ @@ -731,47 +727,59 @@ public class MultiPartParser { if (DEBUG) LOG.debug("{}:{} --> {}",_state,_fieldState,state); - _fieldState=state; + _fieldState = state; } - /* ------------------------------------------------------------------------------- */ @Override public String toString() { - return String.format("%s{s=%s}", - getClass().getSimpleName(), - _state); + return String.format("%s{s=%s}",getClass().getSimpleName(),_state); } /* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */ - /* Event Handler interface - * These methods return true if the caller should process the events - * so far received (eg return from parseNext and call HttpChannel.handle). - * If multiple callbacks are called in sequence (eg - * headerComplete then messageComplete) from the same point in the parsing - * then it is sufficient for the caller to process the events only once. + /* + * Event Handler interface These methods return true if the caller should process the events so far received (eg return from parseNext and call + * HttpChannel.handle). If multiple callbacks are called in sequence (eg headerComplete then messageComplete) from the same point in the parsing then it is + * sufficient for the caller to process the events only once. */ public interface Handler { - public default void startPart() {} - public default void parsedField(String name, String value) {} - public default boolean headerComplete() {return false;} - - public default boolean content(ByteBuffer item, boolean last) {return false;} - - public default boolean messageComplete() {return false;} + public default void startPart() + { + } - public default void earlyEOF() {} + public default void parsedField(String name, String value) + { + } + + public default boolean headerComplete() + { + return false; + } + + public default boolean content(ByteBuffer item, boolean last) + { + return false; + } + + public default boolean messageComplete() + { + return false; + } + + public default void earlyEOF() + { + } } /* ------------------------------------------------------------------------------- */ @SuppressWarnings("serial") private static class IllegalCharacterException extends IllegalArgumentException { - private IllegalCharacterException(State state,byte ch,ByteBuffer buffer) + private IllegalCharacterException(State state, byte ch, ByteBuffer buffer) { super(String.format("Illegal character 0x%X",ch)); // Bug #460642 - don't reveal buffers to end user diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartInputStreamTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartFormInputStreamTest.java similarity index 88% rename from jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartInputStreamTest.java rename to jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartFormInputStreamTest.java index cf8dd525289..c7b558108cb 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartInputStreamTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartFormInputStreamTest.java @@ -44,7 +44,7 @@ import javax.servlet.ServletException; import javax.servlet.ServletInputStream; import javax.servlet.http.Part; -import org.eclipse.jetty.http.MultiPartInputStreamParser.MultiPart; +import org.eclipse.jetty.http.MultiPartFormInputStream.MultiPart; import org.eclipse.jetty.util.B64Code; import org.eclipse.jetty.util.IO; import org.hamcrest.Matchers; @@ -55,7 +55,7 @@ import org.junit.Test; * * */ -public class MultiPartInputStreamTest +public class MultiPartFormInputStreamTest { private static final String FILENAME = "stuff.txt"; protected String _contentType = "multipart/form-data, boundary=AaB03x"; @@ -63,7 +63,7 @@ public class MultiPartInputStreamTest protected String _dirname = System.getProperty("java.io.tmpdir")+File.separator+"myfiles-"+TimeUnit.NANOSECONDS.toMillis(System.nanoTime()); protected File _tmpDir = new File(_dirname); - public MultiPartInputStreamTest () + public MultiPartFormInputStreamTest () { _tmpDir.deleteOnExit(); } @@ -82,7 +82,7 @@ public class MultiPartInputStreamTest + "\r\n"; MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50); - MultiPartInputStreamParser mpis = new MultiPartInputStreamParser(new ByteArrayInputStream(str.getBytes()), + MultiPartFormInputStream mpis = new MultiPartFormInputStream(new ByteArrayInputStream(str.getBytes()), "multipart/form-data, boundary="+boundary, config, _tmpDir); @@ -116,7 +116,7 @@ public class MultiPartInputStreamTest "--" + boundary + "--" + delimiter; MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50); - MultiPartInputStreamParser mpis = new MultiPartInputStreamParser(new ByteArrayInputStream(str.getBytes()), + MultiPartFormInputStream mpis = new MultiPartFormInputStream(new ByteArrayInputStream(str.getBytes()), "multipart/form-data, boundary="+boundary, config, _tmpDir); @@ -139,7 +139,7 @@ public class MultiPartInputStreamTest "--" + boundary + "--" + delimiter; MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50); - MultiPartInputStreamParser mpis = new MultiPartInputStreamParser(new ByteArrayInputStream(str.getBytes()), + MultiPartFormInputStream mpis = new MultiPartFormInputStream(new ByteArrayInputStream(str.getBytes()), "multipart/form-data, boundary="+boundary, config, _tmpDir); @@ -178,7 +178,7 @@ public class MultiPartInputStreamTest "----\r\n"; MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50); - MultiPartInputStreamParser mpis = new MultiPartInputStreamParser(new ByteArrayInputStream(str.getBytes()), + MultiPartFormInputStream mpis = new MultiPartFormInputStream(new ByteArrayInputStream(str.getBytes()), "multipart/form-data", config, _tmpDir); @@ -213,7 +213,7 @@ public class MultiPartInputStreamTest throws Exception { MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50); - MultiPartInputStreamParser mpis = new MultiPartInputStreamParser(new ByteArrayInputStream(_multi.getBytes()), + MultiPartFormInputStream mpis = new MultiPartFormInputStream(new ByteArrayInputStream(_multi.getBytes()), "Content-type: text/plain", config, _tmpDir); @@ -228,7 +228,7 @@ public class MultiPartInputStreamTest String body = ""; MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50); - MultiPartInputStreamParser mpis = new MultiPartInputStreamParser(new ByteArrayInputStream(body.getBytes()), + MultiPartFormInputStream mpis = new MultiPartFormInputStream(new ByteArrayInputStream(body.getBytes()), _contentType, config, _tmpDir); @@ -277,7 +277,7 @@ public class MultiPartInputStreamTest }; MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50); - MultiPartInputStreamParser mpis = new MultiPartInputStreamParser(is, + MultiPartFormInputStream mpis = new MultiPartFormInputStream(is, _contentType, config, _tmpDir); @@ -296,7 +296,7 @@ public class MultiPartInputStreamTest MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50); - MultiPartInputStreamParser mpis = new MultiPartInputStreamParser(new ByteArrayInputStream(whitespace.getBytes()), + MultiPartFormInputStream mpis = new MultiPartFormInputStream(new ByteArrayInputStream(whitespace.getBytes()), _contentType, config, _tmpDir); @@ -319,7 +319,7 @@ public class MultiPartInputStreamTest String whitespace = " "; MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50); - MultiPartInputStreamParser mpis = new MultiPartInputStreamParser(new ByteArrayInputStream(whitespace.getBytes()), + MultiPartFormInputStream mpis = new MultiPartFormInputStream(new ByteArrayInputStream(whitespace.getBytes()), _contentType, config, _tmpDir); @@ -353,7 +353,7 @@ public class MultiPartInputStreamTest MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50); - MultiPartInputStreamParser mpis = new MultiPartInputStreamParser(new ByteArrayInputStream(body.getBytes()), + MultiPartFormInputStream mpis = new MultiPartFormInputStream(new ByteArrayInputStream(body.getBytes()), _contentType, config, _tmpDir); @@ -394,7 +394,7 @@ public class MultiPartInputStreamTest "--AaB03x--\r\n"; MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50); - MultiPartInputStreamParser mpis = new MultiPartInputStreamParser(new ByteArrayInputStream(body.getBytes()), + MultiPartFormInputStream mpis = new MultiPartFormInputStream(new ByteArrayInputStream(body.getBytes()), _contentType, config, _tmpDir); @@ -422,7 +422,7 @@ public class MultiPartInputStreamTest throws Exception { MultipartConfigElement config = new MultipartConfigElement(_dirname); - MultiPartInputStreamParser mpis = new MultiPartInputStreamParser(new ByteArrayInputStream(_multi.getBytes()), + MultiPartFormInputStream mpis = new MultiPartFormInputStream(new ByteArrayInputStream(_multi.getBytes()), _contentType, config, _tmpDir); @@ -436,7 +436,7 @@ public class MultiPartInputStreamTest throws Exception { MultipartConfigElement config = new MultipartConfigElement(_dirname, 60, 100, 50); - MultiPartInputStreamParser mpis = new MultiPartInputStreamParser(new ByteArrayInputStream(_multi.getBytes()), + MultiPartFormInputStream mpis = new MultiPartFormInputStream(new ByteArrayInputStream(_multi.getBytes()), _contentType, config, _tmpDir); @@ -459,7 +459,7 @@ public class MultiPartInputStreamTest throws Exception { MultipartConfigElement config = new MultipartConfigElement(_dirname, 60, 100, 50); - MultiPartInputStreamParser mpis = new MultiPartInputStreamParser(new ByteArrayInputStream(_multi.getBytes()), + MultiPartFormInputStream mpis = new MultiPartFormInputStream(new ByteArrayInputStream(_multi.getBytes()), _contentType, config, _tmpDir); @@ -494,7 +494,7 @@ public class MultiPartInputStreamTest throws Exception { MultipartConfigElement config = new MultipartConfigElement(_dirname, 40, 1024, 30); - MultiPartInputStreamParser mpis = new MultiPartInputStreamParser(new ByteArrayInputStream(_multi.getBytes()), + MultiPartFormInputStream mpis = new MultiPartFormInputStream(new ByteArrayInputStream(_multi.getBytes()), _contentType, config, _tmpDir); @@ -516,7 +516,7 @@ public class MultiPartInputStreamTest throws Exception { MultipartConfigElement config = new MultipartConfigElement(_dirname, 40, 1024, 30); - MultiPartInputStreamParser mpis = new MultiPartInputStreamParser(new ByteArrayInputStream(_multi.getBytes()), + MultiPartFormInputStream mpis = new MultiPartFormInputStream(new ByteArrayInputStream(_multi.getBytes()), _contentType, config, _tmpDir); @@ -527,9 +527,8 @@ public class MultiPartInputStreamTest parts = mpis.getParts(); //caused parsing fail("stuff.txt should have been larger than maxFileSize"); } - catch (IllegalStateException e) + catch (Throwable e) { - e.printStackTrace(); assertTrue(e.getMessage().startsWith("Multipart Mime part")); } @@ -551,7 +550,7 @@ public class MultiPartInputStreamTest public void testPartFileNotDeleted () throws Exception { MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50); - MultiPartInputStreamParser mpis = new MultiPartInputStreamParser(new ByteArrayInputStream(createMultipartRequestString("tptfd").getBytes()), + MultiPartFormInputStream mpis = new MultiPartFormInputStream(new ByteArrayInputStream(createMultipartRequestString("tptfd").getBytes()), _contentType, config, _tmpDir); @@ -559,7 +558,7 @@ public class MultiPartInputStreamTest Collection parts = mpis.getParts(); MultiPart part = (MultiPart)mpis.getPart("stuff"); - File stuff = ((MultiPartInputStreamParser.MultiPart)part).getFile(); + File stuff = ((MultiPartFormInputStream.MultiPart)part).getFile(); assertThat(stuff,notNullValue()); // longer than 100 bytes, should already be a tmp file part.write("tptfd.txt"); File tptfd = new File (_dirname+File.separator+"tptfd.txt"); @@ -574,7 +573,7 @@ public class MultiPartInputStreamTest public void testPartTmpFileDeletion () throws Exception { MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50); - MultiPartInputStreamParser mpis = new MultiPartInputStreamParser(new ByteArrayInputStream(createMultipartRequestString("tptfd").getBytes()), + MultiPartFormInputStream mpis = new MultiPartFormInputStream(new ByteArrayInputStream(createMultipartRequestString("tptfd").getBytes()), _contentType, config, _tmpDir); @@ -582,7 +581,7 @@ public class MultiPartInputStreamTest Collection parts = mpis.getParts(); MultiPart part = (MultiPart)mpis.getPart("stuff"); - File stuff = ((MultiPartInputStreamParser.MultiPart)part).getFile(); + File stuff = ((MultiPartFormInputStream.MultiPart)part).getFile(); assertThat(stuff,notNullValue()); // longer than 100 bytes, should already be a tmp file assertThat (stuff.exists(), is(true)); part.cleanUp(); @@ -604,7 +603,7 @@ public class MultiPartInputStreamTest "\r\n--AaB03x--\n"; MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50); - MultiPartInputStreamParser mpis = new MultiPartInputStreamParser(new ByteArrayInputStream(str.getBytes()), + MultiPartFormInputStream mpis = new MultiPartFormInputStream(new ByteArrayInputStream(str.getBytes()), _contentType, config, _tmpDir); @@ -641,7 +640,7 @@ public class MultiPartInputStreamTest "--AaB03x--\r"; MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50); - MultiPartInputStreamParser mpis = new MultiPartInputStreamParser(new ByteArrayInputStream(str.getBytes()), + MultiPartFormInputStream mpis = new MultiPartFormInputStream(new ByteArrayInputStream(str.getBytes()), _contentType, config, _tmpDir); @@ -688,7 +687,7 @@ public class MultiPartInputStreamTest "--AaB03x--\r"; MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50); - MultiPartInputStreamParser mpis = new MultiPartInputStreamParser(new ByteArrayInputStream(str.getBytes()), + MultiPartFormInputStream mpis = new MultiPartFormInputStream(new ByteArrayInputStream(str.getBytes()), _contentType, config, _tmpDir); @@ -729,7 +728,7 @@ public class MultiPartInputStreamTest } MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50); - MultiPartInputStreamParser mpis = new MultiPartInputStreamParser(new ByteArrayInputStream(baos.toByteArray()), + MultiPartFormInputStream mpis = new MultiPartFormInputStream(new ByteArrayInputStream(baos.toByteArray()), _contentType, config, _tmpDir); @@ -758,7 +757,7 @@ public class MultiPartInputStreamTest "--TheBoundary--\r\n"; MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50); - MultiPartInputStreamParser mpis = new MultiPartInputStreamParser(new ByteArrayInputStream(str.getBytes()), + MultiPartFormInputStream mpis = new MultiPartFormInputStream(new ByteArrayInputStream(str.getBytes()), contentType, config, _tmpDir); @@ -780,14 +779,14 @@ public class MultiPartInputStreamTest "--AaB03x--\r\n"; MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50); - MultiPartInputStreamParser mpis = new MultiPartInputStreamParser(new ByteArrayInputStream(contents.getBytes()), + MultiPartFormInputStream mpis = new MultiPartFormInputStream(new ByteArrayInputStream(contents.getBytes()), _contentType, config, _tmpDir); mpis.setDeleteOnExit(true); Collection parts = mpis.getParts(); assertThat(parts.size(), is(1)); - assertThat(((MultiPartInputStreamParser.MultiPart)parts.iterator().next()).getSubmittedFileName(), is("Taken on Aug 22 \\ 2012.jpg")); + assertThat(((MultiPartFormInputStream.MultiPart)parts.iterator().next()).getSubmittedFileName(), is("Taken on Aug 22 \\ 2012.jpg")); } @Test @@ -802,14 +801,14 @@ public class MultiPartInputStreamTest "--AaB03x--\r\n"; MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50); - MultiPartInputStreamParser mpis = new MultiPartInputStreamParser(new ByteArrayInputStream(contents.getBytes()), + MultiPartFormInputStream mpis = new MultiPartFormInputStream(new ByteArrayInputStream(contents.getBytes()), _contentType, config, _tmpDir); mpis.setDeleteOnExit(true); Collection parts = mpis.getParts(); assertThat(parts.size(), is(1)); - assertThat(((MultiPartInputStreamParser.MultiPart)parts.iterator().next()).getSubmittedFileName(), is("c:\\this\\really\\is\\some\\path\\to\\a\\file.txt")); + assertThat(((MultiPartFormInputStream.MultiPart)parts.iterator().next()).getSubmittedFileName(), is("c:\\this\\really\\is\\some\\path\\to\\a\\file.txt")); } @Test @@ -823,14 +822,14 @@ public class MultiPartInputStreamTest "--AaB03x--\r\n"; MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50); - MultiPartInputStreamParser mpis = new MultiPartInputStreamParser(new ByteArrayInputStream(contents.getBytes()), + MultiPartFormInputStream mpis = new MultiPartFormInputStream(new ByteArrayInputStream(contents.getBytes()), _contentType, config, _tmpDir); mpis.setDeleteOnExit(true); Collection parts = mpis.getParts(); assertThat(parts.size(), is(1)); - assertThat(((MultiPartInputStreamParser.MultiPart)parts.iterator().next()).getSubmittedFileName(), is("c:\\this\\really\\is\\some\\path\\to\\a\\file.txt")); + assertThat(((MultiPartFormInputStream.MultiPart)parts.iterator().next()).getSubmittedFileName(), is("c:\\this\\really\\is\\some\\path\\to\\a\\file.txt")); } public void testMulti () @@ -862,7 +861,7 @@ public class MultiPartInputStreamTest "--AaB03x--\r\n"; //all default values for multipartconfig, ie file size threshold 0 MultipartConfigElement config = new MultipartConfigElement(_dirname); - MultiPartInputStreamParser mpis = new MultiPartInputStreamParser(new ByteArrayInputStream(s.getBytes()), + MultiPartFormInputStream mpis = new MultiPartFormInputStream(new ByteArrayInputStream(s.getBytes()), _contentType, config, _tmpDir); @@ -871,11 +870,11 @@ public class MultiPartInputStreamTest Collection parts = mpis.getParts(); assertThat(parts.size(), is(2)); Part field1 = mpis.getPart("field1"); //has a filename, should be written to a file - File f = ((MultiPartInputStreamParser.MultiPart)field1).getFile(); + File f = ((MultiPartFormInputStream.MultiPart)field1).getFile(); assertThat(f,notNullValue()); // longer than 100 bytes, should already be a tmp file Part stuff = mpis.getPart("stuff"); - f = ((MultiPartInputStreamParser.MultiPart)stuff).getFile(); //should only be in memory, no filename + f = ((MultiPartFormInputStream.MultiPart)stuff).getFile(); //should only be in memory, no filename assertThat(f, nullValue()); } @@ -883,7 +882,7 @@ public class MultiPartInputStreamTest private void testMulti(String filename) throws IOException, ServletException, InterruptedException { MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50); - MultiPartInputStreamParser mpis = new MultiPartInputStreamParser(new ByteArrayInputStream(createMultipartRequestString(filename).getBytes()), + MultiPartFormInputStream mpis = new MultiPartFormInputStream(new ByteArrayInputStream(createMultipartRequestString(filename).getBytes()), _contentType, config, _tmpDir); @@ -899,9 +898,9 @@ public class MultiPartInputStreamTest assertEquals("Joe Blow", new String(os.toByteArray())); assertEquals(8, field1.getSize()); - assertNotNull(((MultiPartInputStreamParser.MultiPart)field1).getBytes());//in internal buffer + assertNotNull(((MultiPartFormInputStream.MultiPart)field1).getBytes());//in internal buffer field1.write("field1.txt"); - assertNull(((MultiPartInputStreamParser.MultiPart)field1).getBytes());//no longer in internal buffer + assertNull(((MultiPartFormInputStream.MultiPart)field1).getBytes());//no longer in internal buffer File f = new File (_dirname+File.separator+"field1.txt"); assertTrue(f.exists()); field1.write("another_field1.txt"); //write after having already written @@ -921,7 +920,7 @@ public class MultiPartInputStreamTest assertThat(stuff.getHeaderNames().size(),is(2)); assertThat(stuff.getSize(),is(51L)); - File tmpfile = ((MultiPartInputStreamParser.MultiPart)stuff).getFile(); + File tmpfile = ((MultiPartFormInputStream.MultiPart)stuff).getFile(); assertThat(tmpfile,notNullValue()); // longer than 50 bytes, should already be a tmp file assertThat(stuff.getBytes(),nullValue()); //not in an internal buffer assertThat(tmpfile.exists(),is(true)); @@ -958,7 +957,7 @@ public class MultiPartInputStreamTest "--AaB03x--\r\n"; MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50); - MultiPartInputStreamParser mpis = new MultiPartInputStreamParser(new ByteArrayInputStream(sameNames.getBytes()), + MultiPartFormInputStream mpis = new MultiPartFormInputStream(new ByteArrayInputStream(sameNames.getBytes()), _contentType, config, _tmpDir); @@ -997,7 +996,7 @@ public class MultiPartInputStreamTest "--AaB03x--\r\n"; MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50); - MultiPartInputStreamParser mpis = new MultiPartInputStreamParser(new ByteArrayInputStream(contentWithEncodedPart.getBytes()), + MultiPartFormInputStream mpis = new MultiPartFormInputStream(new ByteArrayInputStream(contentWithEncodedPart.getBytes()), _contentType, config, _tmpDir); @@ -1041,7 +1040,7 @@ public class MultiPartInputStreamTest "truth=3Dbeauty" + "\r\n"+ "--AaB03x--\r\n"; MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50); - MultiPartInputStreamParser mpis = new MultiPartInputStreamParser(new ByteArrayInputStream(contentWithEncodedPart.getBytes()), + MultiPartFormInputStream mpis = new MultiPartFormInputStream(new ByteArrayInputStream(contentWithEncodedPart.getBytes()), _contentType, config, _tmpDir); diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/MultiPartInputStreamParser.java b/jetty-util/src/main/java/org/eclipse/jetty/util/MultiPartInputStreamParser.java index 23c55ddb90c..c3378d9e794 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/MultiPartInputStreamParser.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/MultiPartInputStreamParser.java @@ -55,7 +55,15 @@ import org.eclipse.jetty.util.log.Logger; * MultiPartInputStream * * Handle a MultiPart Mime input stream, breaking it up on the boundary into files and strings. + * + * Non Compliance warnings are documented by the method {@link #getNonComplianceWarnings()} + * + * @deprecated Replaced by {@link org.eclipse.jetty.http#MultiPartFormInputStream} + * The code for MultiPartInputStream is slower than its replacement MultiPartFormInputStream. However + * this class accepts formats non compliant the RFC that the new MultiPartFormInputStream does not accept. + * */ +@Deprecated public class MultiPartInputStreamParser { private static final Logger LOG = Log.getLogger(MultiPartInputStreamParser.class); @@ -71,7 +79,7 @@ public class MultiPartInputStreamParser protected boolean _deleteOnExit; protected boolean _writeFilesWithFilenames; - EnumSet nonComplianceWarnings = EnumSet.noneOf(NonCompliance.class); + private EnumSet nonComplianceWarnings = EnumSet.noneOf(NonCompliance.class); public enum NonCompliance { CR_TERMINATION, @@ -80,15 +88,12 @@ public class MultiPartInputStreamParser BASE64_TRANSFER_ENCODING, QUOTED_PRINTABLE_TRANSFER_ENCODING } + + /** + * @return an EnumSet of non compliances with the RFC that were accepted by this parser + */ public EnumSet getNonComplianceWarnings() - { - EnumSet term = ((ReadLineInputStream)_in).getLineTerminations(); - - if(term.contains(Termination.CR)) - nonComplianceWarnings.add(NonCompliance.CR_TERMINATION); - if(term.contains(Termination.LF)) - nonComplianceWarnings.add(NonCompliance.LF_TERMINATION); - + { return nonComplianceWarnings; } @@ -838,6 +843,13 @@ public class MultiPartInputStreamParser { while(line!=null) line=((ReadLineInputStream)_in).readLine(); + + EnumSet term = ((ReadLineInputStream)_in).getLineTerminations(); + + if(term.contains(Termination.CR)) + nonComplianceWarnings.add(NonCompliance.CR_TERMINATION); + if(term.contains(Termination.LF)) + nonComplianceWarnings.add(NonCompliance.LF_TERMINATION); } else throw new IOException("Incomplete parts"); @@ -846,6 +858,7 @@ public class MultiPartInputStreamParser { _err = e; } + } public void setDeleteOnExit(boolean deleteOnExit) diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/ReadLineInputStream.java b/jetty-util/src/main/java/org/eclipse/jetty/util/ReadLineInputStream.java index a6acd0c391f..427c8a65e91 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/ReadLineInputStream.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/ReadLineInputStream.java @@ -31,6 +31,7 @@ import org.eclipse.jetty.util.MultiPartInputStreamParser.NonCompliance; * * Read from an input stream, accepting CR/LF, LF or just CR. */ +@Deprecated public class ReadLineInputStream extends BufferedInputStream { boolean _seenCRLF; diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/MultiPartInputStreamTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/MultiPartInputStreamTest.java index d9246b225f6..dd623cd7072 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/MultiPartInputStreamTest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/MultiPartInputStreamTest.java @@ -47,7 +47,6 @@ import javax.servlet.http.Part; import org.eclipse.jetty.util.MultiPartInputStreamParser.MultiPart; import org.eclipse.jetty.util.MultiPartInputStreamParser.NonCompliance; -import org.hamcrest.Matchers; import org.junit.Test; /** @@ -55,6 +54,7 @@ import org.junit.Test; * * */ +@SuppressWarnings("deprecation") public class MultiPartInputStreamTest { private static final String FILENAME = "stuff.txt"; From a59f681b00e8242287d0d4c2ce7228911f1bf8ef Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Tue, 27 Mar 2018 10:10:55 +1100 Subject: [PATCH 30/50] run old and new parser in test Signed-off-by: Greg Wilkins --- .../jetty/http/MultiPartParsingTest.java | 123 ++++++++++++------ 1 file changed, 83 insertions(+), 40 deletions(-) diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParsingTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParsingTest.java index c3b71b32a57..f608a5fdfb4 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParsingTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParsingTest.java @@ -35,9 +35,11 @@ import java.security.DigestOutputStream; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; +import java.util.Collection; import java.util.List; import java.util.Locale; import java.util.Objects; +import java.util.function.Function; import javax.servlet.MultipartConfigElement; import javax.servlet.http.Part; @@ -45,13 +47,16 @@ import javax.servlet.http.Part; import org.eclipse.jetty.toolchain.test.Hex; import org.eclipse.jetty.toolchain.test.MavenTestingUtils; import org.eclipse.jetty.toolchain.test.TestingDir; +import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.IO; import org.eclipse.jetty.util.QuotedStringTokenizer; import org.eclipse.jetty.util.StringUtil; +import org.hamcrest.Matchers; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; +import org.openjdk.jmh.runner.RunnerException; @RunWith(Parameterized.class) public class MultiPartParsingTest @@ -151,56 +156,94 @@ public class MultiPartParsingTest } @Test - public void testParse() throws IOException, NoSuchAlgorithmException + public void testUtilParse() throws Exception + { + Path outputDir = testingDir.getEmptyPathDir(); + MultipartConfigElement config = newMultipartConfigElement(outputDir); + try (InputStream in = Files.newInputStream(multipartRawFile)) + { + org.eclipse.jetty.util.MultiPartInputStreamParser parser = new org.eclipse.jetty.util.MultiPartInputStreamParser(in,multipartExpectations.contentType,config,outputDir.toFile()); + + checkParts(parser.getParts(),s-> + { + try + { + return parser.getPart(s); + } + catch (Exception e) + { + throw new RuntimeException(e); + } + }); + } + } + + @Test + public void testHttpParse() throws Exception { Path outputDir = testingDir.getEmptyPathDir(); MultipartConfigElement config = newMultipartConfigElement(outputDir); try (InputStream in = Files.newInputStream(multipartRawFile)) { MultiPartInputStreamParser parser = new MultiPartInputStreamParser(in, multipartExpectations.contentType, config, outputDir.toFile()); - parser.parse(); - // Evaluate Count - if (multipartExpectations.partCount >= 0) - { - assertThat("Mulitpart.parts.size", parser.getParts().size(), is(multipartExpectations.partCount)); - } - - // Evaluate expected Contents - for (NameValue expected : multipartExpectations.partContainsContents) - { - Part part = parser.getPart(expected.name); - assertThat("Part[" + expected.name + "]", part, is(notNullValue())); - try (InputStream partInputStream = part.getInputStream()) + checkParts(parser.getParts(),s-> + { + try { - String charset = getCharsetFromContentType(part.getContentType(), UTF_8); - String contents = IO.toString(partInputStream, charset); - assertThat("Part[" + expected.name + "].contents", contents, containsString(expected.value)); + return parser.getPart(s); } - } - - // Evaluate expected filenames - for (NameValue expected : multipartExpectations.partFilenames) - { - Part part = parser.getPart(expected.name); - assertThat("Part[" + expected.name + "]", part, is(notNullValue())); - assertThat("Part[" + expected.name + "]", part.getSubmittedFileName(), is(expected.value)); - } - - // Evaluate expected contents checksums - for (NameValue expected : multipartExpectations.partSha1sums) - { - Part part = parser.getPart(expected.name); - assertThat("Part[" + expected.name + "]", part, is(notNullValue())); - MessageDigest digest = MessageDigest.getInstance("SHA1"); - try (InputStream partInputStream = part.getInputStream(); - NoOpOutputStream noop = new NoOpOutputStream(); - DigestOutputStream digester = new DigestOutputStream(noop, digest)) + catch (Exception e) { - IO.copy(partInputStream, digester); - String actualSha1sum = Hex.asHex(digest.digest()).toLowerCase(Locale.US); - assertThat("Part[" + expected.name + "].sha1sum", actualSha1sum, containsString(expected.value)); - } + throw new RuntimeException(e); + } + }); + } + } + + private void checkParts(Collection parts, Function getPart) throws Exception + { + // Evaluate Count + if (multipartExpectations.partCount >= 0) + { + assertThat("Mulitpart.parts.size", parts.size(), is(multipartExpectations.partCount)); + } + + // Evaluate expected Contents + for (NameValue expected : multipartExpectations.partContainsContents) + { + Part part = getPart.apply(expected.name); + assertThat("Part[" + expected.name + "]", part, is(notNullValue())); + try (InputStream partInputStream = part.getInputStream()) + { + String charset = getCharsetFromContentType(part.getContentType(), UTF_8); + String contents = IO.toString(partInputStream, charset); + assertThat("Part[" + expected.name + "].contents", contents, containsString(expected.value)); + } + } + + // Evaluate expected filenames + for (NameValue expected : multipartExpectations.partFilenames) + { + Part part = getPart.apply(expected.name); + assertThat("Part[" + expected.name + "]", part, is(notNullValue())); + assertThat("Part[" + expected.name + "]", part.getSubmittedFileName(), is(expected.value)); + } + + // Evaluate expected contents checksums + for (NameValue expected : multipartExpectations.partSha1sums) + { + Part part = getPart.apply(expected.name); + assertThat("Part[" + expected.name + "]", part, is(notNullValue())); + // System.err.println(BufferUtil.toDetailString(BufferUtil.toBuffer(IO.readBytes(part.getInputStream())))); + MessageDigest digest = MessageDigest.getInstance("SHA1"); + try (InputStream partInputStream = part.getInputStream(); + NoOpOutputStream noop = new NoOpOutputStream(); + DigestOutputStream digester = new DigestOutputStream(noop, digest)) + { + IO.copy(partInputStream, digester); + String actualSha1sum = Hex.asHex(digest.digest()).toLowerCase(Locale.US); + assertThat("Part[" + expected.name + "].sha1sum", actualSha1sum, Matchers.equalToIgnoringCase(expected.value)); } } } From 6ac5970680ddc37360f37d7289ca38f77ceda8d0 Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Tue, 27 Mar 2018 10:32:13 +1100 Subject: [PATCH 31/50] renamed test Signed-off-by: Greg Wilkins --- ...PartParsingTest.java => MultiPartCaptureTest.java} | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) rename jetty-http/src/test/java/org/eclipse/jetty/http/{MultiPartParsingTest.java => MultiPartCaptureTest.java} (97%) diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParsingTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartCaptureTest.java similarity index 97% rename from jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParsingTest.java rename to jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartCaptureTest.java index f608a5fdfb4..c35548b031e 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParsingTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartCaptureTest.java @@ -33,7 +33,6 @@ import java.nio.file.Files; import java.nio.file.Path; import java.security.DigestOutputStream; import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -56,10 +55,9 @@ import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; -import org.openjdk.jmh.runner.RunnerException; @RunWith(Parameterized.class) -public class MultiPartParsingTest +public class MultiPartCaptureTest { public static final int MAX_FILE_SIZE = 60 * 1024; @@ -148,7 +146,7 @@ public class MultiPartParsingTest private final Path multipartRawFile; private final MultipartExpectations multipartExpectations; - public MultiPartParsingTest(String rawPrefix) throws IOException + public MultiPartCaptureTest(String rawPrefix) throws IOException { multipartRawFile = MavenTestingUtils.getTestResourcePathFile("multipart/" + rawPrefix + ".raw"); Path expectationPath = MavenTestingUtils.getTestResourcePathFile("multipart/" + rawPrefix + ".expected.txt"); @@ -185,7 +183,7 @@ public class MultiPartParsingTest MultipartConfigElement config = newMultipartConfigElement(outputDir); try (InputStream in = Files.newInputStream(multipartRawFile)) { - MultiPartInputStreamParser parser = new MultiPartInputStreamParser(in, multipartExpectations.contentType, config, outputDir.toFile()); + MultiPartFormInputStream parser = new MultiPartFormInputStream(in, multipartExpectations.contentType, config, outputDir.toFile()); checkParts(parser.getParts(),s-> { @@ -233,9 +231,10 @@ public class MultiPartParsingTest // Evaluate expected contents checksums for (NameValue expected : multipartExpectations.partSha1sums) { + System.err.println(expected.name); Part part = getPart.apply(expected.name); assertThat("Part[" + expected.name + "]", part, is(notNullValue())); - // System.err.println(BufferUtil.toDetailString(BufferUtil.toBuffer(IO.readBytes(part.getInputStream())))); + System.err.println(BufferUtil.toDetailString(BufferUtil.toBuffer(IO.readBytes(part.getInputStream())))); MessageDigest digest = MessageDigest.getInstance("SHA1"); try (InputStream partInputStream = part.getInputStream(); NoOpOutputStream noop = new NoOpOutputStream(); From a756ac50c60b16e9bde5306a5a0f4a049c2bf37c Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Tue, 27 Mar 2018 11:45:38 +1100 Subject: [PATCH 32/50] Use UTF-8 for part headers Signed-off-by: Greg Wilkins --- .../eclipse/jetty/http/MultiPartParser.java | 111 ++++-------------- .../jetty/http/MultiPartCaptureTest.java | 2 - 2 files changed, 22 insertions(+), 91 deletions(-) diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartParser.java b/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartParser.java index 7e6c40ec103..26a97e86682 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartParser.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartParser.java @@ -26,87 +26,15 @@ import java.util.EnumSet; import org.eclipse.jetty.http.HttpParser.RequestHandler; import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.SearchPattern; +import org.eclipse.jetty.util.Utf8StringBuilder; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; /* ------------------------------------------------------------ */ -/* - * RFC2046 and RFC7578 +/** A parser for MultiPart content type. * - * example: -------WebKitFormBoundaryzWHSH95mOxQwmKln -Content-Disposition: form-data; name="TextField" - -Text value:;"' x ---- -------WebKitFormBoundaryzWHSH95mOxQwmKln -Content-Disposition: form-data; name="file1"; filename="file with :%22; in name.txt" -Content-Type: text/plain - - -------WebKitFormBoundaryzWHSH95mOxQwmKln -Content-Disposition: form-data; name="file2"; filename="ManagedSelector.java" -Content-Type: text/x-java - - -------WebKitFormBoundaryzWHSH95mOxQwmKln -Content-Disposition: form-data; name="Action" - -Submit -------WebKitFormBoundaryzWHSH95mOxQwmKln-- - * - * BNF: - * - boundary := 0*69 bcharsnospace - - bchars := bcharsnospace / " " - - bcharsnospace := DIGIT / ALPHA / "'" / "(" / ")" / - "+" / "_" / "," / "-" / "." / - "/" / ":" / "=" / "?" - - dash-boundary := "--" boundary - ; boundary taken from the value of - ; boundary parameter of the - ; Content-Type field. - - multipart-body := [preamble CRLF] - dash-boundary transport-padding CRLF - body-part *encapsulation - close-delimiter transport-padding - [CRLF epilogue] - - - transport-padding := *LWSP-char - ; Composers MUST NOT generate - ; non-zero length transport - ; padding, but receivers MUST - ; be able to handle padding - ; added by message transports. - - encapsulation := delimiter transport-padding - CRLF body-part - - delimiter := CRLF dash-boundary - - close-delimiter := delimiter "--" - - preamble := discard-text - - epilogue := discard-text - - discard-text := *(*text CRLF) *text - ; May be ignored or discarded. - - body-part := MIME-part-headers [CRLF *OCTET] - ; Lines in a body-part must not start - ; with the specified dash-boundary and - ; the delimiter must not appear anywhere - ; in the body part. Note that the - ; semantics of a body-part differ from - ; the semantics of a message, as - ; described in the text. - - OCTET := + * @see https://tools.ietf.org/html/rfc2046#section-5.1 + * @see https://tools.ietf.org/html/rfc2045 * */ public class MultiPartParser @@ -161,7 +89,7 @@ public class MultiPartParser private boolean _cr; private ByteBuffer _patternBuffer; - private final StringBuilder _string = new StringBuilder(); + private final Utf8StringBuilder _string = new Utf8StringBuilder(); private int _length; private int _totalHeaderLineLength = -1; @@ -303,17 +231,22 @@ public class MultiPartParser /* ------------------------------------------------------------------------------- */ private void setString(String s) { - _string.setLength(0); + _string.reset(); _string.append(s); _length = s.length(); } /* ------------------------------------------------------------------------------- */ + /* + * Mime Field strings are treated as UTF-8 as per https://tools.ietf.org/html/rfc7578#section-5.1 + */ private String takeString() { - _string.setLength(_length); String s = _string.toString(); - _string.setLength(0); + // trim trailing whitespace. + if (s.length()>_length) + s = s.substring(0,_length); + _string.reset(); _length = -1; return s; } @@ -497,7 +430,7 @@ public class MultiPartParser if (_fieldValue == null) { - _string.setLength(0); + _string.reset(); _length = 0; } else @@ -528,8 +461,8 @@ public class MultiPartParser // New header setState(FieldState.IN_NAME); - _string.setLength(0); - _string.append((char)b); + _string.reset(); + _string.append(b); _length = 1; } } @@ -550,7 +483,7 @@ public class MultiPartParser break; default: - _string.append((char)b); + _string.append(b); _length = _string.length(); break; } @@ -567,7 +500,7 @@ public class MultiPartParser case LINE_FEED: _fieldName = takeString(); - _string.setLength(0); + _string.reset(); _fieldValue = ""; _length = -1; break; @@ -584,7 +517,7 @@ public class MultiPartParser switch (b) { case LINE_FEED: - _string.setLength(0); + _string.reset(); _fieldValue = ""; _length = -1; @@ -596,7 +529,7 @@ public class MultiPartParser break; default: - _string.append((char)(0xff & b)); + _string.append(b); _length = _string.length(); setState(FieldState.IN_VALUE); break; @@ -607,7 +540,7 @@ public class MultiPartParser switch (b) { case SPACE: - _string.append((char)(0xff & b)); + _string.append(b); break; case LINE_FEED: @@ -621,7 +554,7 @@ public class MultiPartParser break; default: - _string.append((char)(0xff & b)); + _string.append(b); if (b > SPACE || b < 0) _length = _string.length(); break; diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartCaptureTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartCaptureTest.java index c35548b031e..b261ab88ea1 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartCaptureTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartCaptureTest.java @@ -231,10 +231,8 @@ public class MultiPartCaptureTest // Evaluate expected contents checksums for (NameValue expected : multipartExpectations.partSha1sums) { - System.err.println(expected.name); Part part = getPart.apply(expected.name); assertThat("Part[" + expected.name + "]", part, is(notNullValue())); - System.err.println(BufferUtil.toDetailString(BufferUtil.toBuffer(IO.readBytes(part.getInputStream())))); MessageDigest digest = MessageDigest.getInstance("SHA1"); try (InputStream partInputStream = part.getInputStream(); NoOpOutputStream noop = new NoOpOutputStream(); From ba56bc7994d1ec0ce20d3757999e69187fe1c11b Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Tue, 27 Mar 2018 11:55:20 +1100 Subject: [PATCH 33/50] Deprecated transfer encoding for parts Signed-off-by: Greg Wilkins --- .../org/eclipse/jetty/http/MultiPartFormInputStream.java | 7 ++++++- .../java/org/eclipse/jetty/http/MultiPartCaptureTest.java | 4 ++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartFormInputStream.java b/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartFormInputStream.java index 504781e0dd8..ecde9c8e12e 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartFormInputStream.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartFormInputStream.java @@ -47,6 +47,7 @@ import org.eclipse.jetty.util.LazyList; import org.eclipse.jetty.util.MultiException; import org.eclipse.jetty.util.MultiMap; import org.eclipse.jetty.util.QuotedStringTokenizer; +import org.eclipse.jetty.util.StringUtil; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; @@ -625,13 +626,17 @@ public class MultiPartFormInputStream @Override public void parsedField(String key, String value) - { + { // Add to headers and mark if one of these fields. // headers.put(key.toLowerCase(Locale.ENGLISH),value); if (key.equalsIgnoreCase("content-disposition")) contentDisposition = value; else if (key.equalsIgnoreCase("content-type")) contentType = value; + + // Transfer encoding is not longer considers as it is deprecated as per + // https://tools.ietf.org/html/rfc7578#section-4.7 + } @Override diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartCaptureTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartCaptureTest.java index b261ab88ea1..444b5c8b53f 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartCaptureTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartCaptureTest.java @@ -71,8 +71,8 @@ public class MultiPartCaptureTest // Capture of raw request body contents from Apache HttpComponents 4.5.5 ret.add(new String[]{"multipart-text-files"}); - ret.add(new String[]{"multipart-base64"}); - ret.add(new String[]{"multipart-base64-long"}); + // ret.add(new String[]{"multipart-base64"}); // base64 transfer encoding deprecated + // ret.add(new String[]{"multipart-base64-long"}); // base64 transfer encoding deprecated ret.add(new String[]{"multipart-complex"}); ret.add(new String[]{"multipart-duplicate-names-1"}); ret.add(new String[]{"multipart-encoding-mess"}); From 9557f02feac8fd3ad2fccf05321d7aab660fb4e5 Mon Sep 17 00:00:00 2001 From: Lachlan Roberts Date: Tue, 27 Mar 2018 12:02:10 +1100 Subject: [PATCH 34/50] Fixed converstion to lower case by using StringUtil.asciiToLowerCase method. Signed-off-by: Lachlan Roberts --- .../org/eclipse/jetty/http/MultiPartFormInputStream.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartFormInputStream.java b/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartFormInputStream.java index ecde9c8e12e..c3f60562eb3 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartFormInputStream.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartFormInputStream.java @@ -201,7 +201,7 @@ public class MultiPartFormInputStream { if (name == null) return null; - return _headers.getValue(name.toLowerCase(Locale.ENGLISH),0); + return _headers.getValue(StringUtil.asciiToLowerCase(name),0); } /** @@ -628,7 +628,7 @@ public class MultiPartFormInputStream public void parsedField(String key, String value) { // Add to headers and mark if one of these fields. // - headers.put(key.toLowerCase(Locale.ENGLISH),value); + headers.put(StringUtil.asciiToLowerCase(key),value); if (key.equalsIgnoreCase("content-disposition")) contentDisposition = value; else if (key.equalsIgnoreCase("content-type")) @@ -657,7 +657,7 @@ public class MultiPartFormInputStream while (tok.hasMoreTokens()) { String t = tok.nextToken().trim(); - String tl = t.toLowerCase(Locale.ENGLISH); + String tl = StringUtil.asciiToLowerCase(t); if (t.startsWith("form-data")) form_data = true; else if (tl.startsWith("name=")) @@ -708,7 +708,7 @@ public class MultiPartFormInputStream @Override public boolean content(ByteBuffer buffer, boolean last) - { + { if (BufferUtil.hasContent(buffer)) { try From 4a8c5867608b4c756c6fe06569059f4b330a205d Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Tue, 27 Mar 2018 13:03:23 +1100 Subject: [PATCH 35/50] removed duplicated test Signed-off-by: Greg Wilkins --- .../util/MultiPartInputStreamParser.java | 2 +- .../jetty/util/MultiPartParsingTest.java | 282 ----- .../multipart-base64-long.expected.txt | 4 - .../multipart/multipart-base64-long.raw | 8 - .../multipart/multipart-base64.expected.txt | 4 - .../resources/multipart/multipart-base64.raw | 389 ------- .../multipart/multipart-complex.expected.txt | 9 - .../resources/multipart/multipart-complex.raw | Bin 22929 -> 0 bytes .../multipart-duplicate-names-1.expected.txt | 2 - .../multipart/multipart-duplicate-names-1.raw | Bin 1859 -> 0 bytes .../multipart-encoding-mess.expected.txt | 4 - .../multipart/multipart-encoding-mess.raw | 1009 ----------------- ...ultipart-inside-itself-binary.expected.txt | 6 - .../multipart-inside-itself-binary.raw | 50 - .../multipart-inside-itself.expected.txt | 6 - .../multipart/multipart-inside-itself.raw | 42 - .../multipart-number-browser.expected.txt | 3 - .../multipart/multipart-number-browser.raw | 5 - .../multipart-number-strict.expected.txt | 3 - .../multipart/multipart-number-strict.raw | 7 - .../multipart/multipart-sjis.expected.txt | 4 - .../resources/multipart/multipart-sjis.raw | 13 - .../multipart-strange-quoting.expected.txt | 5 - .../multipart/multipart-strange-quoting.raw | 26 - .../multipart-text-files.expected.txt | 9 - .../multipart/multipart-text-files.raw | 23 - .../multipart-unicode-names.expected.txt | 5 - .../multipart/multipart-unicode-names.raw | 13 - .../multipart-uppercase.expected.txt | 5 - .../multipart/multipart-uppercase.raw | 13 - ...ltipart-x-www-form-urlencoded.expected.txt | 5 - .../multipart-x-www-form-urlencoded.raw | 7 - .../multipart-zencoding.expected.txt | 8 - .../multipart/multipart-zencoding.raw | Bin 1830 -> 0 bytes 34 files changed, 1 insertion(+), 1970 deletions(-) delete mode 100644 jetty-util/src/test/java/org/eclipse/jetty/util/MultiPartParsingTest.java delete mode 100644 jetty-util/src/test/resources/multipart/multipart-base64-long.expected.txt delete mode 100644 jetty-util/src/test/resources/multipart/multipart-base64-long.raw delete mode 100644 jetty-util/src/test/resources/multipart/multipart-base64.expected.txt delete mode 100644 jetty-util/src/test/resources/multipart/multipart-base64.raw delete mode 100644 jetty-util/src/test/resources/multipart/multipart-complex.expected.txt delete mode 100644 jetty-util/src/test/resources/multipart/multipart-complex.raw delete mode 100644 jetty-util/src/test/resources/multipart/multipart-duplicate-names-1.expected.txt delete mode 100644 jetty-util/src/test/resources/multipart/multipart-duplicate-names-1.raw delete mode 100644 jetty-util/src/test/resources/multipart/multipart-encoding-mess.expected.txt delete mode 100644 jetty-util/src/test/resources/multipart/multipart-encoding-mess.raw delete mode 100644 jetty-util/src/test/resources/multipart/multipart-inside-itself-binary.expected.txt delete mode 100644 jetty-util/src/test/resources/multipart/multipart-inside-itself-binary.raw delete mode 100644 jetty-util/src/test/resources/multipart/multipart-inside-itself.expected.txt delete mode 100644 jetty-util/src/test/resources/multipart/multipart-inside-itself.raw delete mode 100644 jetty-util/src/test/resources/multipart/multipart-number-browser.expected.txt delete mode 100644 jetty-util/src/test/resources/multipart/multipart-number-browser.raw delete mode 100644 jetty-util/src/test/resources/multipart/multipart-number-strict.expected.txt delete mode 100644 jetty-util/src/test/resources/multipart/multipart-number-strict.raw delete mode 100644 jetty-util/src/test/resources/multipart/multipart-sjis.expected.txt delete mode 100644 jetty-util/src/test/resources/multipart/multipart-sjis.raw delete mode 100644 jetty-util/src/test/resources/multipart/multipart-strange-quoting.expected.txt delete mode 100644 jetty-util/src/test/resources/multipart/multipart-strange-quoting.raw delete mode 100644 jetty-util/src/test/resources/multipart/multipart-text-files.expected.txt delete mode 100644 jetty-util/src/test/resources/multipart/multipart-text-files.raw delete mode 100644 jetty-util/src/test/resources/multipart/multipart-unicode-names.expected.txt delete mode 100644 jetty-util/src/test/resources/multipart/multipart-unicode-names.raw delete mode 100644 jetty-util/src/test/resources/multipart/multipart-uppercase.expected.txt delete mode 100644 jetty-util/src/test/resources/multipart/multipart-uppercase.raw delete mode 100644 jetty-util/src/test/resources/multipart/multipart-x-www-form-urlencoded.expected.txt delete mode 100644 jetty-util/src/test/resources/multipart/multipart-x-www-form-urlencoded.raw delete mode 100644 jetty-util/src/test/resources/multipart/multipart-zencoding.expected.txt delete mode 100644 jetty-util/src/test/resources/multipart/multipart-zencoding.raw diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/MultiPartInputStreamParser.java b/jetty-util/src/main/java/org/eclipse/jetty/util/MultiPartInputStreamParser.java index c3378d9e794..2dd81111fa0 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/MultiPartInputStreamParser.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/MultiPartInputStreamParser.java @@ -674,7 +674,7 @@ public class MultiPartInputStreamParser { String t=tok.nextToken().trim(); String tl=t.toLowerCase(Locale.ENGLISH); - if(t.startsWith("form-data")) + if(tl.startsWith("form-data")) form_data=true; else if(tl.startsWith("name=")) name=value(t); diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/MultiPartParsingTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/MultiPartParsingTest.java deleted file mode 100644 index 67e156f6cc9..00000000000 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/MultiPartParsingTest.java +++ /dev/null @@ -1,282 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.util; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.hamcrest.Matchers.containsString; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.notNullValue; -import static org.junit.Assert.assertThat; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.nio.charset.Charset; -import java.nio.file.Files; -import java.nio.file.Path; -import java.security.DigestOutputStream; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; - -import javax.servlet.MultipartConfigElement; -import javax.servlet.http.Part; - -import org.eclipse.jetty.toolchain.test.Hex; -import org.eclipse.jetty.toolchain.test.MavenTestingUtils; -import org.eclipse.jetty.toolchain.test.TestingDir; -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; - -@RunWith(Parameterized.class) -public class MultiPartParsingTest -{ - - public static final int MAX_FILE_SIZE = 60 * 1024; - public static final int MAX_REQUEST_SIZE = 1024 * 1024; - public static final int FILE_SIZE_THRESHOLD = 50; - - @Parameterized.Parameters(name = "{0}") - public static List data() - { - List ret = new ArrayList<>(); - - ret.add(new String[]{"multipart-text-files"}); - ret.add(new String[]{"multipart-base64"}); - ret.add(new String[]{"multipart-base64-long"}); - ret.add(new String[]{"multipart-complex"}); - ret.add(new String[]{"multipart-duplicate-names-1"}); - ret.add(new String[]{"multipart-encoding-mess"}); - ret.add(new String[]{"multipart-inside-itself"}); - ret.add(new String[]{"multipart-inside-itself-binary"}); - ret.add(new String[]{"multipart-number-browser"}); - ret.add(new String[]{"multipart-number-strict"}); - ret.add(new String[]{"multipart-sjis"}); - ret.add(new String[]{"multipart-strange-quoting"}); - ret.add(new String[]{"multipart-unicode-names"}); - ret.add(new String[]{"multipart-uppercase"}); - ret.add(new String[]{"multipart-x-www-form-urlencoded"}); - ret.add(new String[]{"multipart-zencoding"}); - - return ret; - } - - @Rule - public TestingDir testingDir = new TestingDir(); - - private final Path multipartRawFile; - private final MultipartExpectations multipartExpectations; - - public MultiPartParsingTest(String rawPrefix) throws IOException - { - multipartRawFile = MavenTestingUtils.getTestResourcePathFile("multipart/" + rawPrefix + ".raw"); - Path expectationPath = MavenTestingUtils.getTestResourcePathFile("multipart/" + rawPrefix + ".expected.txt"); - multipartExpectations = new MultipartExpectations(expectationPath); - } - - @Test - public void testParse() throws IOException, NoSuchAlgorithmException - { - Path outputDir = testingDir.getEmptyPathDir(); - MultipartConfigElement config = newMultipartConfigElement(outputDir); - try (InputStream in = Files.newInputStream(multipartRawFile)) - { - MultiPartInputStreamParser parser = new MultiPartInputStreamParser( - in, multipartExpectations.contentType, config, outputDir.toFile()); - parser.parse(); - - // Evaluate Count - if (multipartExpectations.partCount >= 0) - { - assertThat("Mulitpart.parts.size", parser.getParts().size(), is(multipartExpectations.partCount)); - } - - // Evaluate expected Contents - for (NameValue expected : multipartExpectations.partContainsContents) - { - Part part = parser.getPart(expected.name); - assertThat("Part[" + expected.name + "]", part, is(notNullValue())); - try (InputStream partInputStream = part.getInputStream()) - { - String charset = getCharsetFromContentType(part.getContentType(), UTF_8); - String contents = IO.toString(partInputStream, charset); - assertThat("Part[" + expected.name + "].contents", contents, containsString(expected.value)); - } - } - - // Evaluate expected filenames - for (NameValue expected : multipartExpectations.partFilenames) - { - Part part = parser.getPart(expected.name); - assertThat("Part[" + expected.name + "]", part, is(notNullValue())); - assertThat("Part[" + expected.name + "]", part.getSubmittedFileName(), is(expected.value)); - } - - // Evaluate expected contents checksums - for (NameValue expected : multipartExpectations.partSha1sums) - { - Part part = parser.getPart(expected.name); - assertThat("Part[" + expected.name + "]", part, is(notNullValue())); - MessageDigest digest = MessageDigest.getInstance("SHA1"); - try (InputStream partInputStream = part.getInputStream(); - NoOpOutputStream noop = new NoOpOutputStream(); - DigestOutputStream digester = new DigestOutputStream(noop, digest)) - { - IO.copy(partInputStream, digester); - String actualSha1sum = Hex.asHex(digest.digest()); - assertThat("Part[" + expected.name + "].sha1sum", actualSha1sum, containsString(expected.value)); - } - } - } - } - - private MultipartConfigElement newMultipartConfigElement(Path path) - { - return new MultipartConfigElement(path.toString(), MAX_FILE_SIZE, MAX_REQUEST_SIZE, FILE_SIZE_THRESHOLD); - } - - private String getCharsetFromContentType(String contentType, Charset defaultCharset) - { - if(StringUtil.isBlank(contentType)) - { - return defaultCharset.toString(); - } - - QuotedStringTokenizer tok = new QuotedStringTokenizer(contentType, ";", false, false); - while(tok.hasMoreTokens()) - { - String str = tok.nextToken().trim(); - if(str.startsWith("charset=")) - { - return str.substring("charset=".length()); - } - } - - return defaultCharset.toString(); - } - - public static class NameValue - { - public String name; - public String value; - } - - public static class MultipartExpectations - { - public final String contentType; - public final int partCount; - public final List partFilenames = new ArrayList<>(); - public final List partSha1sums = new ArrayList<>(); - public final List partContainsContents = new ArrayList<>(); - - public MultipartExpectations(Path expectationsPath) throws IOException - { - String parsedContentType = null; - String parsedPartCount = "-1"; - - try (BufferedReader reader = Files.newBufferedReader(expectationsPath)) - { - String line; - while ((line = reader.readLine()) != null) - { - line = line.trim(); - if (StringUtil.isBlank(line) || line.startsWith("#")) - { - // skip blanks and comments - continue; - } - - String split[] = line.split("\\|"); - switch (split[0]) - { - case "Content-Type": - parsedContentType = split[1]; - break; - case "Parts-Count": - parsedPartCount = split[1]; - break; - case "Part-ContainsContents": - { - NameValue pair = new NameValue(); - pair.name = split[1]; - pair.value = split[2]; - partContainsContents.add(pair); - break; - } - case "Part-Filename": - { - NameValue pair = new NameValue(); - pair.name = split[1]; - pair.value = split[2]; - partFilenames.add(pair); - break; - } - case "Part-Sha1sum": - { - NameValue pair = new NameValue(); - pair.name = split[1]; - pair.value = split[2]; - partSha1sums.add(pair); - break; - } - default: - throw new IOException("Bad Line in " + expectationsPath + ": " + line); - } - } - } - - Objects.requireNonNull(parsedContentType, "Missing required 'Content-Type' declaration: " + expectationsPath); - this.contentType = parsedContentType; - this.partCount = Integer.parseInt(parsedPartCount); - } - } - - class NoOpOutputStream extends OutputStream - { - @Override - public void write(byte[] b) throws IOException - { - } - - @Override - public void write(byte[] b, int off, int len) throws IOException - { - } - - @Override - public void flush() throws IOException - { - } - - @Override - public void close() throws IOException - { - } - - @Override - public void write(int b) throws IOException - { - } - } -} diff --git a/jetty-util/src/test/resources/multipart/multipart-base64-long.expected.txt b/jetty-util/src/test/resources/multipart/multipart-base64-long.expected.txt deleted file mode 100644 index 2b1d5ded060..00000000000 --- a/jetty-util/src/test/resources/multipart/multipart-base64-long.expected.txt +++ /dev/null @@ -1,4 +0,0 @@ -Content-Type|multipart/form-data; boundary="JuH4rALGPJfmAquncS_U1du8s59GjKKiG9a8" -Parts-Count|1 -Part-Filename|png|jetty-avatar-256.png -Part-Sha1sum|png|e75b73644afe9b234d70da9ff225229de68cdff8 \ No newline at end of file diff --git a/jetty-util/src/test/resources/multipart/multipart-base64-long.raw b/jetty-util/src/test/resources/multipart/multipart-base64-long.raw deleted file mode 100644 index 2e2b4991568..00000000000 --- a/jetty-util/src/test/resources/multipart/multipart-base64-long.raw +++ /dev/null @@ -1,8 +0,0 @@ ---JuH4rALGPJfmAquncS_U1du8s59GjKKiG9a8 -Content-ID: -Content-Disposition: form-data; name="png"; filename="jetty-avatar-256.png" -Content-Type: image/png; name=jetty-avatar-256.png -Content-Transfer-Encoding: base64 - -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 ---JuH4rALGPJfmAquncS_U1du8s59GjKKiG9a8-- diff --git a/jetty-util/src/test/resources/multipart/multipart-base64.expected.txt b/jetty-util/src/test/resources/multipart/multipart-base64.expected.txt deleted file mode 100644 index 5d4a189b8dc..00000000000 --- a/jetty-util/src/test/resources/multipart/multipart-base64.expected.txt +++ /dev/null @@ -1,4 +0,0 @@ -Content-Type|multipart/form-data; boundary="8GbcZNTauFWYMt7GeM9BxFMdlNBJ6aLJhGdXp" -Parts-Count|1 -Part-Filename|png|jetty-avatar-256.png -Part-Sha1sum|png|e75b73644afe9b234d70da9ff225229de68cdff8 \ No newline at end of file diff --git a/jetty-util/src/test/resources/multipart/multipart-base64.raw b/jetty-util/src/test/resources/multipart/multipart-base64.raw deleted file mode 100644 index 514a6a1ed3c..00000000000 --- a/jetty-util/src/test/resources/multipart/multipart-base64.raw +++ /dev/null @@ -1,389 +0,0 @@ ---8GbcZNTauFWYMt7GeM9BxFMdlNBJ6aLJhGdXp -Content-ID: -Content-Disposition: form-data; name="png"; filename="jetty-avatar-256.png" -Content-Type: image/png; name=jetty-avatar-256.png -Content-Transfer-Encoding: base64 - -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 ---8GbcZNTauFWYMt7GeM9BxFMdlNBJ6aLJhGdXp-- diff --git a/jetty-util/src/test/resources/multipart/multipart-complex.expected.txt b/jetty-util/src/test/resources/multipart/multipart-complex.expected.txt deleted file mode 100644 index 1eed38785c1..00000000000 --- a/jetty-util/src/test/resources/multipart/multipart-complex.expected.txt +++ /dev/null @@ -1,9 +0,0 @@ -Content-Type|multipart/form-data; boundary="PMyKOsh8JrSZm-rUF8EJej42yqbh-UWw9FG-" -Parts-Count|6 -Part-ContainsContents|pi|3.14159265358979323846264338327950288419716939937510 -Part-ContainsContents|company|bob & frank's shoe repair -Part-ContainsContents|power|ꬵо𝗋ⲥ𝖾 -Part-ContainsContents|japanese|健治 -Part-ContainsContents|hello|ャユ戆タ -Part-Filename|upload_file|filename -Part-Sha1sum|upload_file|e75b73644afe9b234d70da9ff225229de68cdff8 diff --git a/jetty-util/src/test/resources/multipart/multipart-complex.raw b/jetty-util/src/test/resources/multipart/multipart-complex.raw deleted file mode 100644 index e74c27a67daacc6680c483bc89a9952531c1646d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 22929 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 diff --git a/jetty-util/src/test/resources/multipart/multipart-encoding-mess.expected.txt b/jetty-util/src/test/resources/multipart/multipart-encoding-mess.expected.txt deleted file mode 100644 index 44148c5505f..00000000000 --- a/jetty-util/src/test/resources/multipart/multipart-encoding-mess.expected.txt +++ /dev/null @@ -1,4 +0,0 @@ -Content-Type|multipart/form-data; boundary="CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl" -Parts-Count|168 -Part-ContainsContents|persian-UTF-8|برج بابل -Part-ContainsContents|persian-CESU-8|برج بابل diff --git a/jetty-util/src/test/resources/multipart/multipart-encoding-mess.raw b/jetty-util/src/test/resources/multipart/multipart-encoding-mess.raw deleted file mode 100644 index a1348ecccf8..00000000000 --- a/jetty-util/src/test/resources/multipart/multipart-encoding-mess.raw +++ /dev/null @@ -1,1009 +0,0 @@ ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-Big5" -Content-Type: text/plain; charset=Big5 -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-Big5-HKSCS" -Content-Type: text/plain; charset=Big5-HKSCS -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-CESU-8" -Content-Type: text/plain; charset=CESU-8 -Content-Transfer-Encoding: 8bit - -برج بابل ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-EUC-JP" -Content-Type: text/plain; charset=EUC-JP -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-EUC-KR" -Content-Type: text/plain; charset=EUC-KR -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-GB18030" -Content-Type: text/plain; charset=GB18030 -Content-Transfer-Encoding: 8bit - -101914 10191018 ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-GB2312" -Content-Type: text/plain; charset=GB2312 -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-GBK" -Content-Type: text/plain; charset=GBK -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-IBM-Thai" -Content-Type: text/plain; charset=IBM-Thai -Content-Transfer-Encoding: 8bit - -???@???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-IBM00858" -Content-Type: text/plain; charset=IBM00858 -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-IBM01140" -Content-Type: text/plain; charset=IBM01140 -Content-Transfer-Encoding: 8bit - -???@???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-IBM01141" -Content-Type: text/plain; charset=IBM01141 -Content-Transfer-Encoding: 8bit - -???@???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-IBM01142" -Content-Type: text/plain; charset=IBM01142 -Content-Transfer-Encoding: 8bit - -???@???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-IBM01143" -Content-Type: text/plain; charset=IBM01143 -Content-Transfer-Encoding: 8bit - -???@???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-IBM01144" -Content-Type: text/plain; charset=IBM01144 -Content-Transfer-Encoding: 8bit - -???@???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-IBM01145" -Content-Type: text/plain; charset=IBM01145 -Content-Transfer-Encoding: 8bit - -???@???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-IBM01146" -Content-Type: text/plain; charset=IBM01146 -Content-Transfer-Encoding: 8bit - -???@???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-IBM01147" -Content-Type: text/plain; charset=IBM01147 -Content-Transfer-Encoding: 8bit - -???@???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-IBM01148" -Content-Type: text/plain; charset=IBM01148 -Content-Transfer-Encoding: 8bit - -???@???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-IBM01149" -Content-Type: text/plain; charset=IBM01149 -Content-Transfer-Encoding: 8bit - -???@???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-IBM037" -Content-Type: text/plain; charset=IBM037 -Content-Transfer-Encoding: 8bit - -???@???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-IBM1026" -Content-Type: text/plain; charset=IBM1026 -Content-Transfer-Encoding: 8bit - -???@???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-IBM1047" -Content-Type: text/plain; charset=IBM1047 -Content-Transfer-Encoding: 8bit - -???@???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-IBM273" -Content-Type: text/plain; charset=IBM273 -Content-Transfer-Encoding: 8bit - -???@???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-IBM277" -Content-Type: text/plain; charset=IBM277 -Content-Transfer-Encoding: 8bit - -???@???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-IBM278" -Content-Type: text/plain; charset=IBM278 -Content-Transfer-Encoding: 8bit - -???@???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-IBM280" -Content-Type: text/plain; charset=IBM280 -Content-Transfer-Encoding: 8bit - -???@???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-IBM284" -Content-Type: text/plain; charset=IBM284 -Content-Transfer-Encoding: 8bit - -???@???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-IBM285" -Content-Type: text/plain; charset=IBM285 -Content-Transfer-Encoding: 8bit - -???@???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-IBM290" -Content-Type: text/plain; charset=IBM290 -Content-Transfer-Encoding: 8bit - -???@???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-IBM297" -Content-Type: text/plain; charset=IBM297 -Content-Transfer-Encoding: 8bit - -???@???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-IBM420" -Content-Type: text/plain; charset=IBM420 -Content-Transfer-Encoding: 8bit - -Xug@XVX ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-IBM424" -Content-Type: text/plain; charset=IBM424 -Content-Transfer-Encoding: 8bit - -???@???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-IBM437" -Content-Type: text/plain; charset=IBM437 -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-IBM500" -Content-Type: text/plain; charset=IBM500 -Content-Transfer-Encoding: 8bit - -???@???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-IBM775" -Content-Type: text/plain; charset=IBM775 -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-IBM850" -Content-Type: text/plain; charset=IBM850 -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-IBM852" -Content-Type: text/plain; charset=IBM852 -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-IBM855" -Content-Type: text/plain; charset=IBM855 -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-IBM857" -Content-Type: text/plain; charset=IBM857 -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-IBM860" -Content-Type: text/plain; charset=IBM860 -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-IBM861" -Content-Type: text/plain; charset=IBM861 -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-IBM862" -Content-Type: text/plain; charset=IBM862 -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-IBM863" -Content-Type: text/plain; charset=IBM863 -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-IBM864" -Content-Type: text/plain; charset=IBM864 -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-IBM865" -Content-Type: text/plain; charset=IBM865 -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-IBM866" -Content-Type: text/plain; charset=IBM866 -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-IBM868" -Content-Type: text/plain; charset=IBM868 -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-IBM869" -Content-Type: text/plain; charset=IBM869 -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-IBM870" -Content-Type: text/plain; charset=IBM870 -Content-Transfer-Encoding: 8bit - -???@???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-IBM871" -Content-Type: text/plain; charset=IBM871 -Content-Transfer-Encoding: 8bit - -???@???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-IBM918" -Content-Type: text/plain; charset=IBM918 -Content-Transfer-Encoding: 8bit - -???@???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-ISO-2022-JP" -Content-Type: text/plain; charset=ISO-2022-JP -Content-Transfer-Encoding: 8bit - -$B!)!)!)(B $B!)!)!)!)(B ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-ISO-2022-JP-2" -Content-Type: text/plain; charset=ISO-2022-JP-2 -Content-Transfer-Encoding: 8bit - -$B!)!)!)(B $B!)!)!)!)(B ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-ISO-2022-KR" -Content-Type: text/plain; charset=ISO-2022-KR -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-ISO-8859-1" -Content-Type: text/plain; charset=ISO-8859-1 -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-ISO-8859-13" -Content-Type: text/plain; charset=ISO-8859-13 -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-ISO-8859-15" -Content-Type: text/plain; charset=ISO-8859-15 -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-ISO-8859-2" -Content-Type: text/plain; charset=ISO-8859-2 -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-ISO-8859-3" -Content-Type: text/plain; charset=ISO-8859-3 -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-ISO-8859-4" -Content-Type: text/plain; charset=ISO-8859-4 -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-ISO-8859-5" -Content-Type: text/plain; charset=ISO-8859-5 -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-ISO-8859-6" -Content-Type: text/plain; charset=ISO-8859-6 -Content-Transfer-Encoding: 8bit - - ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-ISO-8859-7" -Content-Type: text/plain; charset=ISO-8859-7 -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-ISO-8859-8" -Content-Type: text/plain; charset=ISO-8859-8 -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-ISO-8859-9" -Content-Type: text/plain; charset=ISO-8859-9 -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-JIS_X0201" -Content-Type: text/plain; charset=JIS_X0201 -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-JIS_X0212-1990" -Content-Type: text/plain; charset=JIS_X0212-1990 -Content-Transfer-Encoding: 8bit - -"D"D"D"D"D"D"D"D ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-KOI8-R" -Content-Type: text/plain; charset=KOI8-R -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-KOI8-U" -Content-Type: text/plain; charset=KOI8-U -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-Shift_JIS" -Content-Type: text/plain; charset=Shift_JIS -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-TIS-620" -Content-Type: text/plain; charset=TIS-620 -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-US-ASCII" -Content-Type: text/plain; charset=US-ASCII -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-UTF-16" -Content-Type: text/plain; charset=UTF-16 -Content-Transfer-Encoding: 8bit - -(1, ('(D ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-UTF-16BE" -Content-Type: text/plain; charset=UTF-16BE -Content-Transfer-Encoding: 8bit - -(1, ('(D ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-UTF-16LE" -Content-Type: text/plain; charset=UTF-16LE -Content-Transfer-Encoding: 8bit - -(1, ('(D ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-UTF-32" -Content-Type: text/plain; charset=UTF-32 -Content-Transfer-Encoding: 8bit - -(1, ('(D ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-UTF-32BE" -Content-Type: text/plain; charset=UTF-32BE -Content-Transfer-Encoding: 8bit - -(1, ('(D ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-UTF-32LE" -Content-Type: text/plain; charset=UTF-32LE -Content-Transfer-Encoding: 8bit - -(1, ('(D ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-UTF-8" -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -برج بابل ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-windows-1250" -Content-Type: text/plain; charset=windows-1250 -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-windows-1251" -Content-Type: text/plain; charset=windows-1251 -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-windows-1252" -Content-Type: text/plain; charset=windows-1252 -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-windows-1253" -Content-Type: text/plain; charset=windows-1253 -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-windows-1254" -Content-Type: text/plain; charset=windows-1254 -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-windows-1255" -Content-Type: text/plain; charset=windows-1255 -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-windows-1256" -Content-Type: text/plain; charset=windows-1256 -Content-Transfer-Encoding: 8bit - - ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-windows-1257" -Content-Type: text/plain; charset=windows-1257 -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-windows-1258" -Content-Type: text/plain; charset=windows-1258 -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-windows-31j" -Content-Type: text/plain; charset=windows-31j -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-x-Big5-HKSCS-2001" -Content-Type: text/plain; charset=x-Big5-HKSCS-2001 -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-x-Big5-Solaris" -Content-Type: text/plain; charset=x-Big5-Solaris -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-x-euc-jp-linux" -Content-Type: text/plain; charset=x-euc-jp-linux -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-x-EUC-TW" -Content-Type: text/plain; charset=x-EUC-TW -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-x-eucJP-Open" -Content-Type: text/plain; charset=x-eucJP-Open -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-x-IBM1006" -Content-Type: text/plain; charset=x-IBM1006 -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-x-IBM1025" -Content-Type: text/plain; charset=x-IBM1025 -Content-Transfer-Encoding: 8bit - -???@???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-x-IBM1046" -Content-Type: text/plain; charset=x-IBM1046 -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-x-IBM1097" -Content-Type: text/plain; charset=x-IBM1097 -Content-Transfer-Encoding: 8bit - -???@???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-x-IBM1098" -Content-Type: text/plain; charset=x-IBM1098 -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-x-IBM1112" -Content-Type: text/plain; charset=x-IBM1112 -Content-Transfer-Encoding: 8bit - -???@???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-x-IBM1122" -Content-Type: text/plain; charset=x-IBM1122 -Content-Transfer-Encoding: 8bit - -???@???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-x-IBM1123" -Content-Type: text/plain; charset=x-IBM1123 -Content-Transfer-Encoding: 8bit - -???@???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-x-IBM1124" -Content-Type: text/plain; charset=x-IBM1124 -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-x-IBM1166" -Content-Type: text/plain; charset=x-IBM1166 -Content-Transfer-Encoding: 8bit - -???@???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-x-IBM1364" -Content-Type: text/plain; charset=x-IBM1364 -Content-Transfer-Encoding: 8bit - -ooo@oooo ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-x-IBM1381" -Content-Type: text/plain; charset=x-IBM1381 -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-x-IBM1383" -Content-Type: text/plain; charset=x-IBM1383 -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-x-IBM300" -Content-Type: text/plain; charset=x-IBM300 -Content-Transfer-Encoding: 8bit - -BoBoBoBoBoBoBoBo ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-x-IBM33722" -Content-Type: text/plain; charset=x-IBM33722 -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-x-IBM737" -Content-Type: text/plain; charset=x-IBM737 -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-x-IBM833" -Content-Type: text/plain; charset=x-IBM833 -Content-Transfer-Encoding: 8bit - -???@???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-x-IBM834" -Content-Type: text/plain; charset=x-IBM834 -Content-Transfer-Encoding: 8bit - - ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-x-IBM856" -Content-Type: text/plain; charset=x-IBM856 -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-x-IBM874" -Content-Type: text/plain; charset=x-IBM874 -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-x-IBM875" -Content-Type: text/plain; charset=x-IBM875 -Content-Transfer-Encoding: 8bit - -???@???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-x-IBM921" -Content-Type: text/plain; charset=x-IBM921 -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-x-IBM922" -Content-Type: text/plain; charset=x-IBM922 -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-x-IBM930" -Content-Type: text/plain; charset=x-IBM930 -Content-Transfer-Encoding: 8bit - -ooo@oooo ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-x-IBM933" -Content-Type: text/plain; charset=x-IBM933 -Content-Transfer-Encoding: 8bit - -ooo@oooo ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-x-IBM935" -Content-Type: text/plain; charset=x-IBM935 -Content-Transfer-Encoding: 8bit - -ooo@oooo ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-x-IBM937" -Content-Type: text/plain; charset=x-IBM937 -Content-Transfer-Encoding: 8bit - -ooo@oooo ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-x-IBM939" -Content-Type: text/plain; charset=x-IBM939 -Content-Transfer-Encoding: 8bit - -ooo@oooo ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-x-IBM942" -Content-Type: text/plain; charset=x-IBM942 -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-x-IBM942C" -Content-Type: text/plain; charset=x-IBM942C -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-x-IBM943" -Content-Type: text/plain; charset=x-IBM943 -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-x-IBM943C" -Content-Type: text/plain; charset=x-IBM943C -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-x-IBM948" -Content-Type: text/plain; charset=x-IBM948 -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-x-IBM949" -Content-Type: text/plain; charset=x-IBM949 -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-x-IBM949C" -Content-Type: text/plain; charset=x-IBM949C -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-x-IBM950" -Content-Type: text/plain; charset=x-IBM950 -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-x-IBM964" -Content-Type: text/plain; charset=x-IBM964 -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-x-IBM970" -Content-Type: text/plain; charset=x-IBM970 -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-x-ISCII91" -Content-Type: text/plain; charset=x-ISCII91 -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-x-ISO-2022-CN-CNS" -Content-Type: text/plain; charset=x-ISO-2022-CN-CNS -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-x-ISO-2022-CN-GB" -Content-Type: text/plain; charset=x-ISO-2022-CN-GB -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-x-iso-8859-11" -Content-Type: text/plain; charset=x-iso-8859-11 -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-x-JIS0208" -Content-Type: text/plain; charset=x-JIS0208 -Content-Transfer-Encoding: 8bit - -!)!)!)!)!)!)!)!) ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-x-Johab" -Content-Type: text/plain; charset=x-Johab -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-x-MacArabic" -Content-Type: text/plain; charset=x-MacArabic -Content-Transfer-Encoding: 8bit - - ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-x-MacCentralEurope" -Content-Type: text/plain; charset=x-MacCentralEurope -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-x-MacCroatian" -Content-Type: text/plain; charset=x-MacCroatian -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-x-MacCyrillic" -Content-Type: text/plain; charset=x-MacCyrillic -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-x-MacDingbat" -Content-Type: text/plain; charset=x-MacDingbat -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-x-MacGreek" -Content-Type: text/plain; charset=x-MacGreek -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-x-MacHebrew" -Content-Type: text/plain; charset=x-MacHebrew -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-x-MacIceland" -Content-Type: text/plain; charset=x-MacIceland -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-x-MacRoman" -Content-Type: text/plain; charset=x-MacRoman -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-x-MacRomania" -Content-Type: text/plain; charset=x-MacRomania -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-x-MacSymbol" -Content-Type: text/plain; charset=x-MacSymbol -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-x-MacThai" -Content-Type: text/plain; charset=x-MacThai -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-x-MacTurkish" -Content-Type: text/plain; charset=x-MacTurkish -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-x-MacUkraine" -Content-Type: text/plain; charset=x-MacUkraine -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-x-MS932_0213" -Content-Type: text/plain; charset=x-MS932_0213 -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-x-MS950-HKSCS" -Content-Type: text/plain; charset=x-MS950-HKSCS -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-x-MS950-HKSCS-XP" -Content-Type: text/plain; charset=x-MS950-HKSCS-XP -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-x-mswin-936" -Content-Type: text/plain; charset=x-mswin-936 -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-x-PCK" -Content-Type: text/plain; charset=x-PCK -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-x-SJIS_0213" -Content-Type: text/plain; charset=x-SJIS_0213 -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-x-UTF-16LE-BOM" -Content-Type: text/plain; charset=x-UTF-16LE-BOM -Content-Transfer-Encoding: 8bit - -(1, ('(D ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-X-UTF-32BE-BOM" -Content-Type: text/plain; charset=X-UTF-32BE-BOM -Content-Transfer-Encoding: 8bit - -(1, ('(D ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-X-UTF-32LE-BOM" -Content-Type: text/plain; charset=X-UTF-32LE-BOM -Content-Transfer-Encoding: 8bit - -(1, ('(D ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-x-windows-50220" -Content-Type: text/plain; charset=x-windows-50220 -Content-Transfer-Encoding: 8bit - -$B!)!)!)(B $B!)!)!)!)(B ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-x-windows-50221" -Content-Type: text/plain; charset=x-windows-50221 -Content-Transfer-Encoding: 8bit - -$B!)!)!)(B $B!)!)!)!)(B ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-x-windows-874" -Content-Type: text/plain; charset=x-windows-874 -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-x-windows-949" -Content-Type: text/plain; charset=x-windows-949 -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-x-windows-950" -Content-Type: text/plain; charset=x-windows-950 -Content-Transfer-Encoding: 8bit - -??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl -Content-Disposition: form-data; name="persian-x-windows-iso2022jp" -Content-Type: text/plain; charset=x-windows-iso2022jp -Content-Transfer-Encoding: 8bit - -$B!)!)!)(B $B!)!)!)!)(B ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl-- diff --git a/jetty-util/src/test/resources/multipart/multipart-inside-itself-binary.expected.txt b/jetty-util/src/test/resources/multipart/multipart-inside-itself-binary.expected.txt deleted file mode 100644 index 1074a9a759b..00000000000 --- a/jetty-util/src/test/resources/multipart/multipart-inside-itself-binary.expected.txt +++ /dev/null @@ -1,6 +0,0 @@ -Content-Type|multipart/form-data; boundary="94GJ2MW4vpjh92qj-CHjUUIwb9X8Y2LqkU2Yxn0vTU2oHy5jk6_Kpxn2aE9EokEiRGox4eWfAYP8-" -Parts-Count|4 -Part-ContainsContents|reporter| -Part-ContainsContents|timestamp|2018-03-21T19:00:18+00:00 -Part-ContainsContents|comments|this also couldn't be parsed -Part-ContainsContents|attachment|cherry \ No newline at end of file diff --git a/jetty-util/src/test/resources/multipart/multipart-inside-itself-binary.raw b/jetty-util/src/test/resources/multipart/multipart-inside-itself-binary.raw deleted file mode 100644 index 200235e6d3b..00000000000 --- a/jetty-util/src/test/resources/multipart/multipart-inside-itself-binary.raw +++ /dev/null @@ -1,50 +0,0 @@ ---94GJ2MW4vpjh92qj-CHjUUIwb9X8Y2LqkU2Yxn0vTU2oHy5jk6_Kpxn2aE9EokEiRGox4eWfAYP8- -Content-Disposition: form-data; name="reporter" -Content-Type: text/plain; charset=ISO-8859-1 -Content-Transfer-Encoding: 8bit - - ---94GJ2MW4vpjh92qj-CHjUUIwb9X8Y2LqkU2Yxn0vTU2oHy5jk6_Kpxn2aE9EokEiRGox4eWfAYP8- -Content-Disposition: form-data; name="timestamp" -Content-Type: text/plain; charset=ISO-8859-1 -Content-Transfer-Encoding: 8bit - -2018-03-21T19:00:18+00:00 ---94GJ2MW4vpjh92qj-CHjUUIwb9X8Y2LqkU2Yxn0vTU2oHy5jk6_Kpxn2aE9EokEiRGox4eWfAYP8- -Content-Disposition: form-data; name="comments" -Content-Type: text/plain; charset=ISO-8859-1 -Content-Transfer-Encoding: 8bit - -this also couldn't be parsed ---94GJ2MW4vpjh92qj-CHjUUIwb9X8Y2LqkU2Yxn0vTU2oHy5jk6_Kpxn2aE9EokEiRGox4eWfAYP8- -Content-Disposition: form-data; name="attachment" -Content-Type: application/octet-stream -Content-Transfer-Encoding: binary - ---94GJ2MW4vpjh92qj-CHjUUIwb9X8Y2LqkU2Yxn0v -Content-Disposition: form-data; name="fruit" -Content-Type: text/plain; charset=ISO-8859-1 -Content-Transfer-Encoding: 8bit - -cherry ---94GJ2MW4vpjh92qj-CHjUUIwb9X8Y2LqkU2Yxn0v -Content-Disposition: form-data; name="color" -Content-Type: text/plain; charset=ISO-8859-1 -Content-Transfer-Encoding: 8bit - -red ---94GJ2MW4vpjh92qj-CHjUUIwb9X8Y2LqkU2Yxn0v -Content-Disposition: form-data; name="cost" -Content-Type: text/plain; charset=ISO-8859-1 -Content-Transfer-Encoding: 8bit - -$1.20 USG ---94GJ2MW4vpjh92qj-CHjUUIwb9X8Y2LqkU2Yxn0v -Content-Disposition: form-data; name="comments" -Content-Type: text/plain; charset=ISO-8859-1 -Content-Transfer-Encoding: 8bit - ---94GJ2MW4vpjh92qj-CHjUUIwb9X8Y2LqkU2Yxn0vTU2oHy5jk6_Kpxn2aE9EokEiRGox4eWfAYP8- ---94GJ2MW4vpjh92qj-CHjUUIwb9X8Y2LqkU2Yxn0v-- - ---94GJ2MW4vpjh92qj-CHjUUIwb9X8Y2LqkU2Yxn0vTU2oHy5jk6_Kpxn2aE9EokEiRGox4eWfAYP8--- diff --git a/jetty-util/src/test/resources/multipart/multipart-inside-itself.expected.txt b/jetty-util/src/test/resources/multipart/multipart-inside-itself.expected.txt deleted file mode 100644 index 4f68cd2fa81..00000000000 --- a/jetty-util/src/test/resources/multipart/multipart-inside-itself.expected.txt +++ /dev/null @@ -1,6 +0,0 @@ -Content-Type|multipart/form-data; boundary="kCFSwstIsIZkZtQ5JM7193kJYcK5WkyvoxsGjx5eCuVFbaeUZ9oK57JCp_p5wP86S5nY4re5x" -Parts-Count|4 -Part-ContainsContents|reporter| -Part-ContainsContents|timestamp|2018-03-21T18:52:18+00:00 -Part-ContainsContents|comments|this couldn't be parsed -Part-ContainsContents|attachment|banana \ No newline at end of file diff --git a/jetty-util/src/test/resources/multipart/multipart-inside-itself.raw b/jetty-util/src/test/resources/multipart/multipart-inside-itself.raw deleted file mode 100644 index 9157af95046..00000000000 --- a/jetty-util/src/test/resources/multipart/multipart-inside-itself.raw +++ /dev/null @@ -1,42 +0,0 @@ ---kCFSwstIsIZkZtQ5JM7193kJYcK5WkyvoxsGjx5eCuVFbaeUZ9oK57JCp_p5wP86S5nY4re5x -Content-Disposition: form-data; name="reporter" -Content-Type: text/plain; charset=ISO-8859-1 -Content-Transfer-Encoding: 8bit - - ---kCFSwstIsIZkZtQ5JM7193kJYcK5WkyvoxsGjx5eCuVFbaeUZ9oK57JCp_p5wP86S5nY4re5x -Content-Disposition: form-data; name="timestamp" -Content-Type: text/plain; charset=ISO-8859-1 -Content-Transfer-Encoding: 8bit - -2018-03-21T18:52:18+00:00 ---kCFSwstIsIZkZtQ5JM7193kJYcK5WkyvoxsGjx5eCuVFbaeUZ9oK57JCp_p5wP86S5nY4re5x -Content-Disposition: form-data; name="comments" -Content-Type: text/plain; charset=ISO-8859-1 -Content-Transfer-Encoding: 8bit - -this couldn't be parsed ---kCFSwstIsIZkZtQ5JM7193kJYcK5WkyvoxsGjx5eCuVFbaeUZ9oK57JCp_p5wP86S5nY4re5x -Content-Disposition: form-data; name="attachment" -Content-Type: text/plain; charset=ISO-8859-1 -Content-Transfer-Encoding: 8bit - ---kCFSwstIsIZkZtQ5JM7193kJYcK5WkyvoxsGj -Content-Disposition: form-data; name="fruit" - -banana ---kCFSwstIsIZkZtQ5JM7193kJYcK5WkyvoxsGj -Content-Disposition: form-data; name="color" - -yellow ---kCFSwstIsIZkZtQ5JM7193kJYcK5WkyvoxsGj -Content-Disposition: form-data; name="cost" - -$0.12 USG ---kCFSwstIsIZkZtQ5JM7193kJYcK5WkyvoxsGj -Content-Disposition: form-data; name="comments" - ---kCFSwstIsIZkZtQ5JM7193kJYcK5WkyvoxsGjx5eCuVFbaeUZ9oK57JCp_p5wP86S5nY4re5x ---kCFSwstIsIZkZtQ5JM7193kJYcK5WkyvoxsGj-- - ---kCFSwstIsIZkZtQ5JM7193kJYcK5WkyvoxsGjx5eCuVFbaeUZ9oK57JCp_p5wP86S5nY4re5x-- diff --git a/jetty-util/src/test/resources/multipart/multipart-number-browser.expected.txt b/jetty-util/src/test/resources/multipart/multipart-number-browser.expected.txt deleted file mode 100644 index ebc9f5eea84..00000000000 --- a/jetty-util/src/test/resources/multipart/multipart-number-browser.expected.txt +++ /dev/null @@ -1,3 +0,0 @@ -Content-Type|multipart/form-data; boundary="RjYiyHVV9Phv7tYylzT1f94fvTC-s7oNKwB9_Y" -Parts-Count|1 -Part-ContainsContents|pi|3.14159265358979323846264338327950288419716939937510 diff --git a/jetty-util/src/test/resources/multipart/multipart-number-browser.raw b/jetty-util/src/test/resources/multipart/multipart-number-browser.raw deleted file mode 100644 index 11776ddfb78..00000000000 --- a/jetty-util/src/test/resources/multipart/multipart-number-browser.raw +++ /dev/null @@ -1,5 +0,0 @@ ---RjYiyHVV9Phv7tYylzT1f94fvTC-s7oNKwB9_Y -Content-Disposition: form-data; name="pi" - -3.14159265358979323846264338327950288419716939937510 ---RjYiyHVV9Phv7tYylzT1f94fvTC-s7oNKwB9_Y-- diff --git a/jetty-util/src/test/resources/multipart/multipart-number-strict.expected.txt b/jetty-util/src/test/resources/multipart/multipart-number-strict.expected.txt deleted file mode 100644 index 9156fb21e2b..00000000000 --- a/jetty-util/src/test/resources/multipart/multipart-number-strict.expected.txt +++ /dev/null @@ -1,3 +0,0 @@ -Content-Type|multipart/form-data; boundary="P6Uyk-Vikfbk_NqTfVF4DwNXrIxpN451pD1" -Parts-Count|1 -Part-ContainsContents|pi|3.14159265358979323846264338327950288419716939937510 diff --git a/jetty-util/src/test/resources/multipart/multipart-number-strict.raw b/jetty-util/src/test/resources/multipart/multipart-number-strict.raw deleted file mode 100644 index 5c5681665ba..00000000000 --- a/jetty-util/src/test/resources/multipart/multipart-number-strict.raw +++ /dev/null @@ -1,7 +0,0 @@ ---P6Uyk-Vikfbk_NqTfVF4DwNXrIxpN451pD1 -Content-Disposition: form-data; name="pi" -Content-Type: text/plain -Content-Transfer-Encoding: 8bit - -3.14159265358979323846264338327950288419716939937510 ---P6Uyk-Vikfbk_NqTfVF4DwNXrIxpN451pD1-- diff --git a/jetty-util/src/test/resources/multipart/multipart-sjis.expected.txt b/jetty-util/src/test/resources/multipart/multipart-sjis.expected.txt deleted file mode 100644 index 35e678b66df..00000000000 --- a/jetty-util/src/test/resources/multipart/multipart-sjis.expected.txt +++ /dev/null @@ -1,4 +0,0 @@ -Content-Type|multipart/form-data; boundary="VA2isIGmYNkgC3qrrGXnlQcWO17WB3a4npVQey" -Parts-Count|2 -Part-ContainsContents|japanese|健治 -Part-ContainsContents|hello|ャユ戆タ diff --git a/jetty-util/src/test/resources/multipart/multipart-sjis.raw b/jetty-util/src/test/resources/multipart/multipart-sjis.raw deleted file mode 100644 index 59e713a28b0..00000000000 --- a/jetty-util/src/test/resources/multipart/multipart-sjis.raw +++ /dev/null @@ -1,13 +0,0 @@ ---VA2isIGmYNkgC3qrrGXnlQcWO17WB3a4npVQey -Content-Disposition: form-data; name="japanese" -Content-Type: text/plain; charset=Shift_JIS -Content-Transfer-Encoding: 8bit - - ---VA2isIGmYNkgC3qrrGXnlQcWO17WB3a4npVQey -Content-Disposition: form-data; name="hello" -Content-Type: text/plain; charset=Shift_JIS -Content-Transfer-Encoding: 8bit - -?^ ---VA2isIGmYNkgC3qrrGXnlQcWO17WB3a4npVQey-- diff --git a/jetty-util/src/test/resources/multipart/multipart-strange-quoting.expected.txt b/jetty-util/src/test/resources/multipart/multipart-strange-quoting.expected.txt deleted file mode 100644 index 76408aa202a..00000000000 --- a/jetty-util/src/test/resources/multipart/multipart-strange-quoting.expected.txt +++ /dev/null @@ -1,5 +0,0 @@ -Content-Type|multipart/form-data; boundary="tR61vgdxSzzv2FDycET2lt-OUZ1IW1GqA" -Parts-Count|4 -Part-ContainsContents|and "I" quote|Value 1 -Part-ContainsContents|and+%22I%22+quote|Value 2 -Part-ContainsContents|value"; what="whoa"|Value 3 diff --git a/jetty-util/src/test/resources/multipart/multipart-strange-quoting.raw b/jetty-util/src/test/resources/multipart/multipart-strange-quoting.raw deleted file mode 100644 index 38fa8862abc..00000000000 --- a/jetty-util/src/test/resources/multipart/multipart-strange-quoting.raw +++ /dev/null @@ -1,26 +0,0 @@ ---tR61vgdxSzzv2FDycET2lt-OUZ1IW1GqA -Content-Disposition: form-data; name="and \"I\" quote" -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Value 1 ---tR61vgdxSzzv2FDycET2lt-OUZ1IW1GqA -Content-Disposition: form-data; name="and+%22I%22+quote" -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Value 2 ---tR61vgdxSzzv2FDycET2lt-OUZ1IW1GqA -Content-Disposition: form-data; name="value\"; what=\"whoa\"" -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Value 3 ---tR61vgdxSzzv2FDycET2lt-OUZ1IW1GqA -Content-Disposition: form-data; name="other\"; -what=\"Something\"" -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Value 4 ---tR61vgdxSzzv2FDycET2lt-OUZ1IW1GqA-- diff --git a/jetty-util/src/test/resources/multipart/multipart-text-files.expected.txt b/jetty-util/src/test/resources/multipart/multipart-text-files.expected.txt deleted file mode 100644 index 82fe6e3a904..00000000000 --- a/jetty-util/src/test/resources/multipart/multipart-text-files.expected.txt +++ /dev/null @@ -1,9 +0,0 @@ -Content-Type|multipart/form-data; boundary="ny9C5eIZL7fsfPY9ONPy8Lxb6tkgEv1" -Parts-Count|3 -Part-ContainsContents|text|text default -Part-ContainsContents|file1|Content of a.txt -Part-ContainsContents|file2|Content of a.html -Part-Filename|file1|a.txt -Part-Filename|file2|a.html -Part-Sha1sum|file1|588A0F273CB5AFE9C8D76DD081812E672F2061E2 -Part-Sha1sum|file2|9A9005159AB90A6D2D9BACB5414EFE932F0CED85 \ No newline at end of file diff --git a/jetty-util/src/test/resources/multipart/multipart-text-files.raw b/jetty-util/src/test/resources/multipart/multipart-text-files.raw deleted file mode 100644 index c72d60aaea1..00000000000 --- a/jetty-util/src/test/resources/multipart/multipart-text-files.raw +++ /dev/null @@ -1,23 +0,0 @@ ---ny9C5eIZL7fsfPY9ONPy8Lxb6tkgEv1 -Content-Disposition: form-data; name="text" -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -text default - ---ny9C5eIZL7fsfPY9ONPy8Lxb6tkgEv1 -Content-Type: text/plain; charset=UTF-8 -X-SHA1: 588A0F273CB5AFE9C8D76DD081812E672F2061E2 -Content-Disposition: form-data; name="file1"; filename="a.txt" -Content-Transfer-Encoding: binary - -Content of a.txt - ---ny9C5eIZL7fsfPY9ONPy8Lxb6tkgEv1 -Content-Type: text/html; charset=UTF-8 -X-SHA1: 9A9005159AB90A6D2D9BACB5414EFE932F0CED85 -Content-Disposition: form-data; name="file2"; filename="a.html" -Content-Transfer-Encoding: binary - -<!DOCTYPE html><title>Content of a.html. ---ny9C5eIZL7fsfPY9ONPy8Lxb6tkgEv1-- diff --git a/jetty-util/src/test/resources/multipart/multipart-unicode-names.expected.txt b/jetty-util/src/test/resources/multipart/multipart-unicode-names.expected.txt deleted file mode 100644 index 2c15cb6f6b4..00000000000 --- a/jetty-util/src/test/resources/multipart/multipart-unicode-names.expected.txt +++ /dev/null @@ -1,5 +0,0 @@ -Content-Type|multipart/form-data; boundary="1R40qTSaEjDJPcArQiccT7vdpp0l02248R" -Parts-Count|2 -Part-ContainsContents|こんにちは世界|Greetings 1 -Part-ContainsContents|%E3%81%93%E3%82%93%E3%81%AB%E3%81%A1%E3%81%AF%E4%B8%96%E7%95%8C|Greetings 2 - diff --git a/jetty-util/src/test/resources/multipart/multipart-unicode-names.raw b/jetty-util/src/test/resources/multipart/multipart-unicode-names.raw deleted file mode 100644 index 5afab43ef54..00000000000 --- a/jetty-util/src/test/resources/multipart/multipart-unicode-names.raw +++ /dev/null @@ -1,13 +0,0 @@ ---1R40qTSaEjDJPcArQiccT7vdpp0l02248R -Content-Disposition: form-data; name="こんにちは世界" -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Greetings 1 ---1R40qTSaEjDJPcArQiccT7vdpp0l02248R -Content-Disposition: form-data; name="%E3%81%93%E3%82%93%E3%81%AB%E3%81%A1%E3%81%AF%E4%B8%96%E7%95%8C" -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Greetings 2 ---1R40qTSaEjDJPcArQiccT7vdpp0l02248R-- diff --git a/jetty-util/src/test/resources/multipart/multipart-uppercase.expected.txt b/jetty-util/src/test/resources/multipart/multipart-uppercase.expected.txt deleted file mode 100644 index ef8470f4cc7..00000000000 --- a/jetty-util/src/test/resources/multipart/multipart-uppercase.expected.txt +++ /dev/null @@ -1,5 +0,0 @@ -Content-Type|multipart/form-data; boundary="8Q4MHJ3LWIQEQQ_OXYU5U9ZLYEH60_CFZQYANCZ" -Parts-Count|2 -Part-ContainsContents|STATE|TEXAS -Part-ContainsContents|CITY|AUSTIN - diff --git a/jetty-util/src/test/resources/multipart/multipart-uppercase.raw b/jetty-util/src/test/resources/multipart/multipart-uppercase.raw deleted file mode 100644 index 3aecb111bc7..00000000000 --- a/jetty-util/src/test/resources/multipart/multipart-uppercase.raw +++ /dev/null @@ -1,13 +0,0 @@ ---8Q4MHJ3LWIQEQQ_OXYU5U9ZLYEH60_CFZQYANCZ -CONTENT-DISPOSITION: FORM-DATA; NAME="STATE" -CONTENT-TYPE: TEXT/PLAIN; CHARSET=WINDOWS-1252 -CONTENT-TRANSFER-ENCODING: 8BIT - -TEXAS ---8Q4MHJ3LWIQEQQ_OXYU5U9ZLYEH60_CFZQYANCZ -CONTENT-DISPOSITION: FORM-DATA; NAME="CITY" -CONTENT-TYPE: TEXT/PLAIN; CHARSET=WINDOWS-1252 -CONTENT-TRANSFER-ENCODING: 8BIT - -AUSTIN ---8Q4MHJ3LWIQEQQ_OXYU5U9ZLYEH60_CFZQYANCZ-- diff --git a/jetty-util/src/test/resources/multipart/multipart-x-www-form-urlencoded.expected.txt b/jetty-util/src/test/resources/multipart/multipart-x-www-form-urlencoded.expected.txt deleted file mode 100644 index e1863757719..00000000000 --- a/jetty-util/src/test/resources/multipart/multipart-x-www-form-urlencoded.expected.txt +++ /dev/null @@ -1,5 +0,0 @@ -Content-Type|multipart/form-data; boundary="qjIkwQOhaYfC2VEcL5j-9sjEK1FIsYMd5" -Parts-Count|1 -Part-ContainsContents|company|bob & frank's shoe repair - - diff --git a/jetty-util/src/test/resources/multipart/multipart-x-www-form-urlencoded.raw b/jetty-util/src/test/resources/multipart/multipart-x-www-form-urlencoded.raw deleted file mode 100644 index 994b267b26c..00000000000 --- a/jetty-util/src/test/resources/multipart/multipart-x-www-form-urlencoded.raw +++ /dev/null @@ -1,7 +0,0 @@ ---qjIkwQOhaYfC2VEcL5j-9sjEK1FIsYMd5 -Content-Disposition: form-data; name="company" -Content-Type: application/x-www-form-urlencoded; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -bob+%26+frank%27s+shoe+repair ---qjIkwQOhaYfC2VEcL5j-9sjEK1FIsYMd5-- diff --git a/jetty-util/src/test/resources/multipart/multipart-zencoding.expected.txt b/jetty-util/src/test/resources/multipart/multipart-zencoding.expected.txt deleted file mode 100644 index fda05113c8f..00000000000 --- a/jetty-util/src/test/resources/multipart/multipart-zencoding.expected.txt +++ /dev/null @@ -1,8 +0,0 @@ -Content-Type|multipart/form-data; boundary="UuAU1liVuDVE7wfJUYE72PUF9DZafZ" -Parts-Count|4 -Part-ContainsContents|zalgo-8|y͔͕͍o̪̞͎̥͇̤̕u'̛̰̫̳̰v̧̘̪̠̟̟e̥͈̱ ̥̠͇͎͕̜s̤e̺e̙ͅņ̜ ̲̟͝za̴͖̱̲͈̘l͖̖͓̙̮͔g͕̞͖͘o͕̤͈̗ ̯̲̹̲͓b͙͟e̞͎̜̗͈͉̭͞f̸or̰̩e̡̝̺,̸͕̙̥̼͇̜ ̪͇̹r̘̪ͅị͔̥͈ͅg̠̟̯͖̦͇ht͖̪͍͚̖͡?͙̝͖̞ -Part-ContainsContents|zalgo-16|y͔͕͍o̪̞͎̥͇̤̕u'̛̰̫̳̰v̧̘̪̠̟̟e̥͈̱ ̥̠͇͎͕̜s̤e̺e̙ͅņ̜ ̲̟͝za̴͖̱̲͈̘l͖̖͓̙̮͔g͕̞͖͘o͕̤͈̗ ̯̲̹̲͓b͙͟e̞͎̜̗͈͉̭͞f̸or̰̩e̡̝̺,̸͕̙̥̼͇̜ ̪͇̹r̘̪ͅị͔̥͈ͅg̠̟̯͖̦͇ht͖̪͍͚̖͡?͙̝͖̞ -Part-ContainsContents|zalgo-16-be|y͔͕͍o̪̞͎̥͇̤̕u'̛̰̫̳̰v̧̘̪̠̟̟e̥͈̱ ̥̠͇͎͕̜s̤e̺e̙ͅņ̜ ̲̟͝za̴͖̱̲͈̘l͖̖͓̙̮͔g͕̞͖͘o͕̤͈̗ ̯̲̹̲͓b͙͟e̞͎̜̗͈͉̭͞f̸or̰̩e̡̝̺,̸͕̙̥̼͇̜ ̪͇̹r̘̪ͅị͔̥͈ͅg̠̟̯͖̦͇ht͖̪͍͚̖͡?͙̝͖̞ -Part-ContainsContents|zalgo-16-le|y͔͕͍o̪̞͎̥͇̤̕u'̛̰̫̳̰v̧̘̪̠̟̟e̥͈̱ ̥̠͇͎͕̜s̤e̺e̙ͅņ̜ ̲̟͝za̴͖̱̲͈̘l͖̖͓̙̮͔g͕̞͖͘o͕̤͈̗ ̯̲̹̲͓b͙͟e̞͎̜̗͈͉̭͞f̸or̰̩e̡̝̺,̸͕̙̥̼͇̜ ̪͇̹r̘̪ͅị͔̥͈ͅg̠̟̯͖̦͇ht͖̪͍͚̖͡?͙̝͖̞ - - diff --git a/jetty-util/src/test/resources/multipart/multipart-zencoding.raw b/jetty-util/src/test/resources/multipart/multipart-zencoding.raw deleted file mode 100644 index 74d78b79fb5014723b7ed76f18238d714597fc57..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1830 zcmeH{Pfrt36vbb1c1^leBqEN85|I(BMoQHXl>!`{U zPxi;#&fH9PwRa9!nSpTVs^n#axcpf_^4N`Jkt>dX9yQy5KRaFg5d|D3McDP$H{# zp`?plC|Oy75@|&!+4mPHkx@}r_=-?6TZR%X{H+Q~_9;UNpRP(1IE=ec^4%&ZK`8mx SQGpU2Y8OiUo=VdUhrR=F$o@_M From ba88b3917912991aeecdfffe869ff3be9ab9ddeb Mon Sep 17 00:00:00 2001 From: Lachlan Roberts Date: Tue, 27 Mar 2018 15:43:16 +1100 Subject: [PATCH 36/50] Work on resolving issues with the new tests in MultiPartCaptureTest. Signed-off-by: Lachlan Roberts --- .../jetty/http/MultiPartFormInputStream.java | 17 ++++-- .../eclipse/jetty/http/MultiPartParser.java | 8 +++ .../jetty/http/MultiPartCaptureTest.java | 54 +++++++++++-------- 3 files changed, 53 insertions(+), 26 deletions(-) diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartFormInputStream.java b/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartFormInputStream.java index c3f60562eb3..20e97b33031 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartFormInputStream.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartFormInputStream.java @@ -610,6 +610,8 @@ public class MultiPartFormInputStream } + //TODO implement proper toString + //TODO more debugging class Handler implements MultiPartParser.Handler { @@ -642,8 +644,13 @@ public class MultiPartFormInputStream @Override public boolean headerComplete() { - try + if(LOG.isDebugEnabled()) { + LOG.debug("headerComplete {}",this); + } + + try + { // Extract content-disposition boolean form_data = false; if (contentDisposition == null) @@ -658,7 +665,7 @@ public class MultiPartFormInputStream { String t = tok.nextToken().trim(); String tl = StringUtil.asciiToLowerCase(t); - if (t.startsWith("form-data")) + if (tl.startsWith("form-data")) form_data = true; else if (tl.startsWith("name=")) name = value(t); @@ -708,7 +715,10 @@ public class MultiPartFormInputStream @Override public boolean content(ByteBuffer buffer, boolean last) - { + { + if(_part == null) + return false; + if (BufferUtil.hasContent(buffer)) { try @@ -718,6 +728,7 @@ public class MultiPartFormInputStream catch (IOException e) { _err = e; + reset(); return true; } } diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartParser.java b/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartParser.java index 26a97e86682..4d6ffdacb64 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartParser.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartParser.java @@ -482,6 +482,14 @@ public class MultiPartParser setState(FieldState.AFTER_NAME); break; + case LINE_FEED: + { + // TODO warn? debug? + handleField(); + setState(FieldState.FIELD); + break; + } + default: _string.append(b); _length = _string.length(); diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartCaptureTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartCaptureTest.java index 444b5c8b53f..4ea4da84283 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartCaptureTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartCaptureTest.java @@ -73,18 +73,18 @@ public class MultiPartCaptureTest ret.add(new String[]{"multipart-text-files"}); // ret.add(new String[]{"multipart-base64"}); // base64 transfer encoding deprecated // ret.add(new String[]{"multipart-base64-long"}); // base64 transfer encoding deprecated - ret.add(new String[]{"multipart-complex"}); + // ret.add(new String[]{"multipart-complex"}); // TODO joakime bad capture includes ? in sjis content ret.add(new String[]{"multipart-duplicate-names-1"}); ret.add(new String[]{"multipart-encoding-mess"}); - ret.add(new String[]{"multipart-inside-itself"}); - ret.add(new String[]{"multipart-inside-itself-binary"}); + // ret.add(new String[]{"multipart-inside-itself"}); // impossible test, badly chosen boundary + // ret.add(new String[]{"multipart-inside-itself-binary"}); // impossible test, badly chosen boundary ret.add(new String[]{"multipart-number-browser"}); ret.add(new String[]{"multipart-number-strict"}); - ret.add(new String[]{"multipart-sjis"}); + // ret.add(new String[]{"multipart-sjis"}); // TODO joakime bad capture includes ? in sjis content ret.add(new String[]{"multipart-strange-quoting"}); ret.add(new String[]{"multipart-unicode-names"}); ret.add(new String[]{"multipart-uppercase"}); - ret.add(new String[]{"multipart-x-www-form-urlencoded"}); + // ret.add(new String[]{"multipart-x-www-form-urlencoded"}); // not our job to decode content ret.add(new String[]{"multipart-zencoding"}); // Capture of raw request body contents from various browsers @@ -100,24 +100,24 @@ public class MultiPartCaptureTest ret.add(new String[]{"browser-capture-form1-osx-safari"}); // form submitted as shift-jis - ret.add(new String[]{"browser-capture-sjis-form-android-chrome"}); - ret.add(new String[]{"browser-capture-sjis-form-android-firefox"}); - ret.add(new String[]{"browser-capture-sjis-form-chrome"}); - ret.add(new String[]{"browser-capture-sjis-form-edge"}); - ret.add(new String[]{"browser-capture-sjis-form-firefox"}); - ret.add(new String[]{"browser-capture-sjis-form-ios-safari"}); + // ret.add(new String[]{"browser-capture-sjis-form-android-chrome"}); // contains html encoded character and unspecified charset defaults to utf-8 + // ret.add(new String[]{"browser-capture-sjis-form-android-firefox"}); // contains html encoded character and unspecified charset defaults to utf-8 + // ret.add(new String[]{"browser-capture-sjis-form-chrome"}); // contains html encoded character and unspecified charset defaults to utf-8 + ret.add(new String[]{"browser-capture-sjis-form-edge"}); + // ret.add(new String[]{"browser-capture-sjis-form-firefox"}); // contains html encoded character and unspecified charset defaults to utf-8 + // ret.add(new String[]{"browser-capture-sjis-form-ios-safari"}); // contains html encoded character and unspecified charset defaults to utf-8 ret.add(new String[]{"browser-capture-sjis-form-msie"}); - ret.add(new String[]{"browser-capture-sjis-form-safari"}); + // ret.add(new String[]{"browser-capture-sjis-form-safari"}); // contains html encoded character and unspecified charset defaults to utf-8 // form submitted as shift-jis (with HTML5 specific hidden _charset_ field) - ret.add(new String[]{"browser-capture-sjis-charset-form-android-chrome"}); - ret.add(new String[]{"browser-capture-sjis-charset-form-android-firefox"}); - ret.add(new String[]{"browser-capture-sjis-charset-form-chrome"}); + // ret.add(new String[]{"browser-capture-sjis-charset-form-android-chrome"}); // contains html encoded character + // ret.add(new String[]{"browser-capture-sjis-charset-form-android-firefox"}); // contains html encoded character + // ret.add(new String[]{"browser-capture-sjis-charset-form-chrome"}); // contains html encoded character ret.add(new String[]{"browser-capture-sjis-charset-form-edge"}); - ret.add(new String[]{"browser-capture-sjis-charset-form-firefox"}); - ret.add(new String[]{"browser-capture-sjis-charset-form-ios-safari"}); + // ret.add(new String[]{"browser-capture-sjis-charset-form-firefox"}); // contains html encoded character + // ret.add(new String[]{"browser-capture-sjis-charset-form-ios-safari"}); // contains html encoded character ret.add(new String[]{"browser-capture-sjis-charset-form-msie"}); - ret.add(new String[]{"browser-capture-sjis-charset-form-safari"}); + // ret.add(new String[]{"browser-capture-sjis-charset-form-safari"}); // contains html encoded character // form submitted with simple file upload ret.add(new String[]{"browser-capture-form-fileupload-android-chrome"}); @@ -133,7 +133,7 @@ public class MultiPartCaptureTest ret.add(new String[]{"browser-capture-form-fileupload-alt-chrome"}); ret.add(new String[]{"browser-capture-form-fileupload-alt-edge"}); ret.add(new String[]{"browser-capture-form-fileupload-alt-firefox"}); - ret.add(new String[]{"browser-capture-form-fileupload-alt-ios-safari"}); + // ret.add(new String[]{"browser-capture-form-fileupload-alt-ios-safari"}); // is Sha1sum correct new parser gives same result as old parser ret.add(new String[]{"browser-capture-form-fileupload-alt-msie"}); ret.add(new String[]{"browser-capture-form-fileupload-alt-safari"}); @@ -207,6 +207,14 @@ public class MultiPartCaptureTest assertThat("Mulitpart.parts.size", parts.size(), is(multipartExpectations.partCount)); } + String defaultCharset = UTF_8.toString(); + Part charSetPart = getPart.apply("_charset_"); + if(charSetPart != null) + { + defaultCharset = IO.toString(charSetPart.getInputStream()); + } + + // Evaluate expected Contents for (NameValue expected : multipartExpectations.partContainsContents) { @@ -214,7 +222,7 @@ public class MultiPartCaptureTest assertThat("Part[" + expected.name + "]", part, is(notNullValue())); try (InputStream partInputStream = part.getInputStream()) { - String charset = getCharsetFromContentType(part.getContentType(), UTF_8); + String charset = getCharsetFromContentType(part.getContentType(), defaultCharset); String contents = IO.toString(partInputStream, charset); assertThat("Part[" + expected.name + "].contents", contents, containsString(expected.value)); } @@ -250,11 +258,11 @@ public class MultiPartCaptureTest return new MultipartConfigElement(path.toString(), MAX_FILE_SIZE, MAX_REQUEST_SIZE, FILE_SIZE_THRESHOLD); } - private String getCharsetFromContentType(String contentType, Charset defaultCharset) + private String getCharsetFromContentType(String contentType, String defaultCharset) { if(StringUtil.isBlank(contentType)) { - return defaultCharset.toString(); + return defaultCharset; } QuotedStringTokenizer tok = new QuotedStringTokenizer(contentType, ";", false, false); @@ -267,7 +275,7 @@ public class MultiPartCaptureTest } } - return defaultCharset.toString(); + return defaultCharset; } public static class NameValue From 7cea305269a61efded7f893fbec1c59b7043e3b8 Mon Sep 17 00:00:00 2001 From: Lachlan Roberts Date: Tue, 27 Mar 2018 16:47:21 +1100 Subject: [PATCH 37/50] Added some extra Debug information in the LOG Signed-off-by: Lachlan Roberts --- .../jetty/http/MultiPartFormInputStream.java | 23 ++++++----- .../eclipse/jetty/http/MultiPartParser.java | 39 ++++++++++++++++++- 2 files changed, 51 insertions(+), 11 deletions(-) diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartFormInputStream.java b/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartFormInputStream.java index 20e97b33031..49eb302ca03 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartFormInputStream.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartFormInputStream.java @@ -728,7 +728,6 @@ public class MultiPartFormInputStream catch (IOException e) { _err = e; - reset(); return true; } } @@ -744,12 +743,24 @@ public class MultiPartFormInputStream _err = e; return true; } - reset(); } return false; } + @Override + public void startPart() + { + reset(); + } + + @Override + public void earlyEOF() + { + if (LOG.isDebugEnabled()) + LOG.debug("Early EOF {}",MultiPartFormInputStream.this); + } + public void reset() { _part = null; @@ -757,14 +768,6 @@ public class MultiPartFormInputStream contentType = null; headers = new MultiMap<>(); } - - @Override - public void earlyEOF() - { - if (LOG.isDebugEnabled()) - LOG.debug("Early EOF {}",MultiPartFormInputStream.this); - } - } public void setDeleteOnExit(boolean deleteOnExit) diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartParser.java b/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartParser.java index 4d6ffdacb64..63aec8605e9 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartParser.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartParser.java @@ -304,10 +304,17 @@ public class MultiPartParser if (_state == State.EPILOGUE) { _state = State.END; + + if(LOG.isDebugEnabled()) + LOG.debug("messageComplete {}", this); + return _handler.messageComplete(); } else { + if(LOG.isDebugEnabled()) + LOG.debug("earlyEOF {}", this); + _handler.earlyEOF(); return true; } @@ -366,6 +373,10 @@ public class MultiPartParser if (b == '\n') { setState(State.BODY_PART); + + if(LOG.isDebugEnabled()) + LOG.debug("startPart {}",this); + _handler.startPart(); return; } @@ -449,6 +460,10 @@ public class MultiPartParser handleField(); setState(State.FIRST_OCTETS); _partialBoundary = 2; // CRLF is option for empty parts + + if(LOG.isDebugEnabled()) + LOG.debug("headerComplete {}", this); + if (_handler.headerComplete()) return true; break; @@ -484,7 +499,9 @@ public class MultiPartParser case LINE_FEED: { - // TODO warn? debug? + if(LOG.isDebugEnabled()) + LOG.debug("Line Feed in Name {}", this); + handleField(); setState(FieldState.FIELD); break; @@ -580,6 +597,9 @@ public class MultiPartParser /* ------------------------------------------------------------------------------- */ private void handleField() { + if(LOG.isDebugEnabled()) + LOG.debug("parsedField: _fieldName={} _fieldValue={} {}", _fieldName, _fieldValue, this); + if (_fieldName != null && _fieldValue != null) _handler.parsedField(_fieldName,_fieldValue); _fieldName = _fieldValue = null; @@ -601,6 +621,10 @@ public class MultiPartParser buffer.position(buffer.position() + _delimiterSearch.getLength() - _partialBoundary); setState(State.DELIMITER); _partialBoundary = 0; + + if(LOG.isDebugEnabled()) + LOG.debug("Content={}, Last={} {}",BufferUtil.toDetailString(BufferUtil.EMPTY_BUFFER),true,this); + return _handler.content(BufferUtil.EMPTY_BUFFER,true); } @@ -620,6 +644,9 @@ public class MultiPartParser content.limit(_partialBoundary); _partialBoundary = 0; + if(LOG.isDebugEnabled()) + LOG.debug("Content={}, Last={} {}",BufferUtil.toDetailString(content),false,this); + if (_handler.content(content,false)) return true; } @@ -635,6 +662,9 @@ public class MultiPartParser buffer.position(delimiter - buffer.arrayOffset() + _delimiterSearch.getLength()); setState(State.DELIMITER); + if(LOG.isDebugEnabled()) + LOG.debug("Content={}, Last={} {}",BufferUtil.toDetailString(content),true,this); + return _handler.content(content,true); } @@ -645,12 +675,19 @@ public class MultiPartParser ByteBuffer content = buffer.slice(); content.limit(content.limit() - _partialBoundary); + if(LOG.isDebugEnabled()) + LOG.debug("Content={}, Last={} {}",BufferUtil.toDetailString(content),false,this); + BufferUtil.clear(buffer); return _handler.content(content,false); } // There is normal content with no delimiter ByteBuffer content = buffer.slice(); + + if(LOG.isDebugEnabled()) + LOG.debug("Content={}, Last={} {}",BufferUtil.toDetailString(content),false,this); + BufferUtil.clear(buffer); return _handler.content(content,false); } From 8a8324cb18b30438de26dfd8e8463860af89bec0 Mon Sep 17 00:00:00 2001 From: Lachlan Roberts Date: Thu, 29 Mar 2018 16:29:48 +1100 Subject: [PATCH 38/50] Completed benchmark for UTIL vs HTTP multipart parser. Fixed some tests in MultiPartCaptureTest. Signed-off-by: Lachlan Roberts --- jetty-http/pom.xml | 56 +++- .../jetty/http/MultiPartFormInputStream.java | 8 +- .../jetty/http/MultiPartCaptureTest.java | 12 +- .../http/MultiPartFormInputStreamTest.java | 33 ++ .../jetty/http/MultiPartParserTest.java | 46 +++ .../jetty/http/jmh/MultiPartBenchmark.java | 297 ++++++++++++++++++ ...s-charset-form-android-chrome.expected.txt | 2 +- ...-charset-form-android-firefox.expected.txt | 2 +- ...ture-sjis-charset-form-chrome.expected.txt | 2 +- ...ure-sjis-charset-form-firefox.expected.txt | 2 +- ...-sjis-charset-form-ios-safari.expected.txt | 2 +- ...ture-sjis-charset-form-safari.expected.txt | 2 +- 12 files changed, 449 insertions(+), 15 deletions(-) create mode 100644 jetty-http/src/test/java/org/eclipse/jetty/http/jmh/MultiPartBenchmark.java diff --git a/jetty-http/pom.xml b/jetty-http/pom.xml index 6c174f5e67d..e371ebe3e98 100644 --- a/jetty-http/pom.xml +++ b/jetty-http/pom.xml @@ -33,6 +33,18 @@ jetty-test-helper test + + org.openjdk.jmh + jmh-core + ${jmh.version} + test + + + org.openjdk.jmh + jmh-generator-annprocess + ${jmh.version} + test + @@ -69,7 +81,49 @@ org.eclipse.jetty.http.* - + + org.apache.maven.plugins + maven-shade-plugin + + + package + + shade + + + ${jmhjar.name} + true + + + org.openjdk.jmh:jmh-core + + + + + org.openjdk.jmh.Main + + + + + org.openjdk.jmh:jmh-core + + ** + + + + *:* + + META-INF/*.SF + META-INF/*.DSA + META-INF/*.RSA + + + + + + + diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartFormInputStream.java b/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartFormInputStream.java index 49eb302ca03..c2d1d14fe29 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartFormInputStream.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartFormInputStream.java @@ -610,8 +610,6 @@ public class MultiPartFormInputStream } - //TODO implement proper toString - //TODO more debugging class Handler implements MultiPartParser.Handler { @@ -768,6 +766,12 @@ public class MultiPartFormInputStream contentType = null; headers = new MultiMap<>(); } + + @Override + public String toString() { + return("contentDisposition: "+contentDisposition+" contentType:"+contentType); + } + } public void setDeleteOnExit(boolean deleteOnExit) diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartCaptureTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartCaptureTest.java index 4ea4da84283..347614f4573 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartCaptureTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartCaptureTest.java @@ -110,14 +110,14 @@ public class MultiPartCaptureTest // ret.add(new String[]{"browser-capture-sjis-form-safari"}); // contains html encoded character and unspecified charset defaults to utf-8 // form submitted as shift-jis (with HTML5 specific hidden _charset_ field) - // ret.add(new String[]{"browser-capture-sjis-charset-form-android-chrome"}); // contains html encoded character - // ret.add(new String[]{"browser-capture-sjis-charset-form-android-firefox"}); // contains html encoded character - // ret.add(new String[]{"browser-capture-sjis-charset-form-chrome"}); // contains html encoded character + ret.add(new String[]{"browser-capture-sjis-charset-form-android-chrome"}); // contains html encoded character + ret.add(new String[]{"browser-capture-sjis-charset-form-android-firefox"}); // contains html encoded character + ret.add(new String[]{"browser-capture-sjis-charset-form-chrome"}); // contains html encoded character ret.add(new String[]{"browser-capture-sjis-charset-form-edge"}); - // ret.add(new String[]{"browser-capture-sjis-charset-form-firefox"}); // contains html encoded character - // ret.add(new String[]{"browser-capture-sjis-charset-form-ios-safari"}); // contains html encoded character + ret.add(new String[]{"browser-capture-sjis-charset-form-firefox"}); // contains html encoded character + ret.add(new String[]{"browser-capture-sjis-charset-form-ios-safari"}); // contains html encoded character ret.add(new String[]{"browser-capture-sjis-charset-form-msie"}); - // ret.add(new String[]{"browser-capture-sjis-charset-form-safari"}); // contains html encoded character + ret.add(new String[]{"browser-capture-sjis-charset-form-safari"}); // contains html encoded character // form submitted with simple file upload ret.add(new String[]{"browser-capture-form-fileupload-android-chrome"}); diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartFormInputStreamTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartFormInputStreamTest.java index c7b558108cb..f48b4d4a309 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartFormInputStreamTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartFormInputStreamTest.java @@ -1062,8 +1062,41 @@ public class MultiPartFormInputStreamTest } + @Test + public void testGeneratedForm() + throws Exception + { + String contentType = "multipart/form-data, boundary=WebKitFormBoundary7MA4YWf7OaKlSxkTrZu0gW"; + String body = "Content-Type: multipart/form-data; boundary=WebKitFormBoundary7MA4YWf7OaKlSxkTrZu0gW\r\n" + + "\r\n" + + "--WebKitFormBoundary7MA4YWf7OaKlSxkTrZu0gW\r\n" + + "Content-Disposition: form-data; name=\"part1\"\r\n" + + "\n" + + "wNfミxVam﾿t\r\n" + + "--WebKitFormBoundary7MA4YWf7OaKlSxkTrZu0gW\n" + + "Content-Disposition: form-data; name=\"part2\"\r\n" + + "\r\n" + + "&ᄈᄎ￙ᅱᅢO\r\n" + + "--WebKitFormBoundary7MA4YWf7OaKlSxkTrZu0gW--"; + MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50); + MultiPartFormInputStream mpis = new MultiPartFormInputStream(new ByteArrayInputStream(body.getBytes()), + contentType, + config, + _tmpDir); + mpis.setDeleteOnExit(true); + + Collection parts = mpis.getParts(); + assertThat(parts, notNullValue()); + assertThat(parts.size(), is(2)); + + Part part1 = mpis.getPart("part1"); + assertThat(part1, notNullValue()); + Part part2 = mpis.getPart("part2"); + assertThat(part2, notNullValue()); + } + private String createMultipartRequestString(String filename) { diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParserTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParserTest.java index 07b38af84b0..bc1c77b8fad 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParserTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParserTest.java @@ -620,6 +620,52 @@ public class MultiPartParserTest } + @Test + public void testGeneratedForm() + { + TestHandler handler = new TestHandler() + { + @Override + public boolean messageComplete() + { + return true; + } + + @Override + public boolean content(ByteBuffer buffer, boolean last) + { + super.content(buffer,last); + return false; + } + + @Override + public boolean headerComplete() + { + return false; + } + }; + + MultiPartParser parser = new MultiPartParser(handler,"WebKitFormBoundary7MA4YWf7OaKlSxkTrZu0gW"); + ByteBuffer data = BufferUtil.toBuffer("" + + "Content-Type: multipart/form-data; boundary=WebKitFormBoundary7MA4YWf7OaKlSxkTrZu0gW\r\n" + + "\r\n" + + "--WebKitFormBoundary7MA4YWf7OaKlSxkTrZu0gW\r\n" + + "Content-Disposition: form-data; name=\"part1\"\r\n" + + "\n" + + "wNfミxVam﾿t\r\n" + + "--WebKitFormBoundary7MA4YWf7OaKlSxkTrZu0gW\n" + + "Content-Disposition: form-data; name=\"part2\"\r\n" + + "\r\n" + + "&ᄈᄎ￙ᅱᅢO\r\n" + + "--WebKitFormBoundary7MA4YWf7OaKlSxkTrZu0gW--"); + + parser.parse(data,true); + assertThat(parser.getState(), is(State.END)); + assertThat(handler.fields.size(), is(2)); + + } + + static class TestHandler implements MultiPartParser.Handler { List fields = new ArrayList<>(); diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/jmh/MultiPartBenchmark.java b/jetty-http/src/test/java/org/eclipse/jetty/http/jmh/MultiPartBenchmark.java new file mode 100644 index 00000000000..49924222a0c --- /dev/null +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/jmh/MultiPartBenchmark.java @@ -0,0 +1,297 @@ +// +// ======================================================================== +// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http.jmh; + +import java.io.File; +import java.io.InputStream; +import java.nio.ByteBuffer; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardOpenOption; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +import javax.servlet.MultipartConfigElement; +import javax.servlet.http.Part; + +import org.eclipse.jetty.http.MultiPartFormInputStream; +import org.eclipse.jetty.http.MultiPartCaptureTest.MultipartExpectations; +import org.eclipse.jetty.toolchain.test.MavenTestingUtils; +import org.eclipse.jetty.toolchain.test.TestingDir; +import org.eclipse.jetty.util.BufferUtil; +import org.junit.Rule; +import org.junit.runner.Description; +import org.junit.runners.model.Statement; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Level; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.TearDown; +import org.openjdk.jmh.profile.CompilerProfiler; +import org.openjdk.jmh.runner.Runner; +import org.openjdk.jmh.runner.RunnerException; +import org.openjdk.jmh.runner.options.Options; +import org.openjdk.jmh.runner.options.OptionsBuilder; + +@State(Scope.Benchmark) +public class MultiPartBenchmark +{ + + public static final int MAX_FILE_SIZE = Integer.MAX_VALUE; + public static final int MAX_REQUEST_SIZE = Integer.MAX_VALUE; + public static final int FILE_SIZE_THRESHOLD = 50; + + public int count = 0; + static String _contentType; + static File _file; + static int _numSections; + static int _numBytesPerSection; + + + public static List data = new ArrayList<>(); + static + { + // Capture of raw request body contents from various browsers + + // simple form - 2 fields + data.add("browser-capture-form1-android-chrome"); + data.add("browser-capture-form1-android-firefox"); + data.add("browser-capture-form1-chrome"); + data.add("browser-capture-form1-edge"); + data.add("browser-capture-form1-firefox"); + data.add("browser-capture-form1-ios-safari"); + data.add("browser-capture-form1-msie"); + data.add("browser-capture-form1-osx-safari"); + + // form submitted as shift-jis + data.add("browser-capture-sjis-form-edge"); + data.add("browser-capture-sjis-form-msie"); + + // form submitted as shift-jis (with HTML5 specific hidden _charset_ field) + data.add("browser-capture-sjis-charset-form-edge"); + data.add("browser-capture-sjis-charset-form-msie"); + + // form submitted with simple file upload + data.add("browser-capture-form-fileupload-android-chrome"); + data.add("browser-capture-form-fileupload-android-firefox"); + data.add("browser-capture-form-fileupload-chrome"); + data.add("browser-capture-form-fileupload-edge"); + data.add("browser-capture-form-fileupload-firefox"); + data.add("browser-capture-form-fileupload-ios-safari"); + data.add("browser-capture-form-fileupload-msie"); + data.add("browser-capture-form-fileupload-safari"); + + // form submitted with 2 files (1 binary, 1 text) and 2 text fields + data.add("browser-capture-form-fileupload-alt-chrome"); + data.add("browser-capture-form-fileupload-alt-edge"); + data.add("browser-capture-form-fileupload-alt-firefox"); + data.add("browser-capture-form-fileupload-alt-msie"); + data.add("browser-capture-form-fileupload-alt-safari"); + } + + + @Param({"UTIL","HTTP"}) + public static String parserType; + + @Setup(Level.Trial) + public static void setupTrial() throws Exception + { + _file = File.createTempFile("test01",null); + _file.deleteOnExit(); + + _numSections = 1; + _numBytesPerSection = 1024*1024*10; + + _contentType = "multipart/form-data, boundary=WebKitFormBoundary7MA4YWf7OaKlSxkTrZu0gW"; + String initialBoundary = "--WebKitFormBoundary7MA4YWf7OaKlSxkTrZu0gW\r\n"; + String boundary = "\r\n--WebKitFormBoundary7MA4YWf7OaKlSxkTrZu0gW\r\n"; + String closingBoundary = "\r\n--WebKitFormBoundary7MA4YWf7OaKlSxkTrZu0gW--\r\n"; + String headerStart = "Content-Disposition: form-data; name=\""; + + + for(int i=0; i<_numSections; i++) { + //boundary and headers + if(i==0) + Files.write(_file.toPath(), initialBoundary.getBytes(), StandardOpenOption.APPEND); + else + Files.write(_file.toPath(), boundary.getBytes(), StandardOpenOption.APPEND); + + Files.write(_file.toPath(), headerStart.getBytes(), StandardOpenOption.APPEND); + Files.write(_file.toPath(), new String("part"+(i+1)).getBytes(), StandardOpenOption.APPEND); + Files.write(_file.toPath(), new String("\"\r\n\r\n").getBytes(), StandardOpenOption.APPEND); + + //append random data + byte[] data = new byte[_numBytesPerSection]; + new Random().nextBytes(data); + Files.write(_file.toPath(), data, StandardOpenOption.APPEND); + } + + //closing boundary + Files.write(_file.toPath(), closingBoundary.getBytes(), StandardOpenOption.APPEND); + + /* + // print out file to verify that it contains valid contents (just for testing) + InputStream in = Files.newInputStream(_file.toPath()); + System.out.println(); + while(in.available()>0) { + byte b[] = new byte[100]; + int read = in.read(b,0,100); + for(int i=0; i Date: Thu, 29 Mar 2018 18:04:42 +1100 Subject: [PATCH 39/50] Minor cleanups Signed-off-by: Lachlan Roberts --- .../org/eclipse/jetty/http/MimeTypes.java | 1 + .../org/eclipse/jetty/server/Request.java | 20 ++++++++++--------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/MimeTypes.java b/jetty-http/src/main/java/org/eclipse/jetty/http/MimeTypes.java index 2079ed1d3fc..4be2f977bb5 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/MimeTypes.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/MimeTypes.java @@ -58,6 +58,7 @@ public class MimeTypes FORM_ENCODED("application/x-www-form-urlencoded"), MESSAGE_HTTP("message/http"), MULTIPART_BYTERANGES("multipart/byteranges"), + MULTIPART_FORM_DATA("multipart/form-data"), TEXT_HTML("text/html"), TEXT_PLAIN("text/plain"), diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java index 63930e8bd3c..a2e3a7cc450 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java @@ -465,14 +465,14 @@ public class Request implements HttpServletRequest _contentParameters=new MultiMap<>(); contentType = HttpFields.valueParameters(contentType, null); int contentLength = getContentLength(); - if (contentLength != 0) + if (contentLength != 0 && _inputState == __NONE) { - if (MimeTypes.Type.FORM_ENCODED.is(contentType) && _inputState == __NONE && + if (MimeTypes.Type.FORM_ENCODED.is(contentType) && _channel.getHttpConfiguration().isFormEncodedMethod(getMethod())) { extractFormParameters(_contentParameters); } - else if (contentType.startsWith("multipart/form-data") && + else if (MimeTypes.Type.MULTIPART_FORM_DATA.is(contentType) && getAttribute(__MULTIPART_CONFIG_ELEMENT) != null && _multiPartInputStream == null) { @@ -550,6 +550,7 @@ public class Request implements HttpServletRequest /* ------------------------------------------------------------ */ private void extractMultipartParameters(MultiMap result) { + // TODO do we need this method? try { getParts(result); @@ -2321,7 +2322,9 @@ public class Request implements HttpServletRequest @Override public Collection getParts() throws IOException, ServletException { - if (getContentType() == null || !getContentType().startsWith("multipart/form-data")) + // TODO should content type be case sensitive + if (getContentType() == null || + !MimeTypes.Type.MULTIPART_FORM_DATA.is(HttpFields.valueParameters(getContentType(),null))) throw new ServletException("Content-Type != multipart/form-data"); return getParts(null); } @@ -2334,7 +2337,6 @@ public class Request implements HttpServletRequest if (_multiPartInputStream == null) { MultipartConfigElement config = (MultipartConfigElement)getAttribute(__MULTIPART_CONFIG_ELEMENT); - if (config == null) throw new IllegalStateException("No multipart config for servlet"); @@ -2353,10 +2355,10 @@ public class Request implements HttpServletRequest { // Servlet Spec 3.0 pg 23, parts without filename must be put into params. String charset = null; - if (mp.getContentType() != null) - charset = MimeTypes.getCharsetFromContentType(mp.getContentType()); + if (p.getContentType() != null) + charset = MimeTypes.getCharsetFromContentType(p.getContentType()); - try (InputStream is = mp.getInputStream()) + try (InputStream is = p.getInputStream()) { if (os == null) os = new ByteArrayOutputStream(); @@ -2364,7 +2366,7 @@ public class Request implements HttpServletRequest String content=new String(os.toByteArray(),charset==null?StandardCharsets.UTF_8:Charset.forName(charset)); if (_contentParameters == null) _contentParameters = params == null ? new MultiMap<>() : params; - _contentParameters.add(mp.getName(), content); + _contentParameters.add(p.getName(), content); } os.reset(); } From b196596055d4c993145321d4741018842c8a2190 Mon Sep 17 00:00:00 2001 From: Lachlan Roberts Date: Fri, 30 Mar 2018 19:16:59 +1100 Subject: [PATCH 40/50] Replaced usages of MultiPartInputStreamParser to Request.MultiPartInputStream which provides runtime switching between old and new parser. Signed-off-by: Lachlan Roberts --- .../server/MultiPartCleanerListener.java | 4 +- .../org/eclipse/jetty/server/Request.java | 129 ++++++++++++++---- .../org/eclipse/jetty/server/RequestTest.java | 4 +- 3 files changed, 109 insertions(+), 28 deletions(-) diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/MultiPartCleanerListener.java b/jetty-server/src/main/java/org/eclipse/jetty/server/MultiPartCleanerListener.java index 11c9ffc4bb4..2d176b37c2d 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/MultiPartCleanerListener.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/MultiPartCleanerListener.java @@ -24,7 +24,7 @@ import javax.servlet.ServletRequestListener; import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.util.MultiException; -import org.eclipse.jetty.util.MultiPartInputStreamParser; + public class MultiPartCleanerListener implements ServletRequestListener { @@ -38,7 +38,7 @@ public class MultiPartCleanerListener implements ServletRequestListener public void requestDestroyed(ServletRequestEvent sre) { //Clean up any tmp files created by MultiPartInputStream - MultiPartInputStreamParser mpis = (MultiPartInputStreamParser)sre.getServletRequest().getAttribute(Request.__MULTIPART_INPUT_STREAM); + Request.MultiPartInputStream mpis = (Request.MultiPartInputStream)sre.getServletRequest().getAttribute(Request.__MULTIPART_INPUT_STREAM); if (mpis != null) { ContextHandler.Context context = (ContextHandler.Context)sre.getServletRequest().getAttribute(Request.__MULTIPART_CONTEXT); diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java index a2e3a7cc450..3dac341d7d4 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java @@ -75,6 +75,7 @@ import org.eclipse.jetty.http.HttpURI; import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.http.MetaData; import org.eclipse.jetty.http.MimeTypes; +import org.eclipse.jetty.http.MultiPartFormInputStream; import org.eclipse.jetty.io.RuntimeIOException; import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.server.handler.ContextHandler.Context; @@ -83,6 +84,7 @@ import org.eclipse.jetty.server.session.SessionHandler; import org.eclipse.jetty.util.Attributes; import org.eclipse.jetty.util.AttributesMap; import org.eclipse.jetty.util.IO; +import org.eclipse.jetty.util.MultiException; import org.eclipse.jetty.util.MultiMap; import org.eclipse.jetty.util.MultiPartInputStreamParser; import org.eclipse.jetty.util.StringUtil; @@ -214,7 +216,7 @@ public class Request implements HttpServletRequest private HttpSession _session; private SessionHandler _sessionHandler; private long _timeStamp; - private MultiPartInputStreamParser _multiPartInputStream; //if the request is a multi-part mime + private MultiPartInputStream _multiPartInputStream; //if the request is a multi-part mime private AsyncContextState _async; /* ------------------------------------------------------------ */ @@ -476,7 +478,15 @@ public class Request implements HttpServletRequest getAttribute(__MULTIPART_CONFIG_ELEMENT) != null && _multiPartInputStream == null) { - extractMultipartParameters(_contentParameters); + try + { + getParts(_contentParameters); + } + catch (IOException | ServletException e) + { + LOG.debug(e); + throw new RuntimeIOException(e); + } } } } @@ -547,21 +557,6 @@ public class Request implements HttpServletRequest } } - /* ------------------------------------------------------------ */ - private void extractMultipartParameters(MultiMap result) - { - // TODO do we need this method? - try - { - getParts(result); - } - catch (IOException | ServletException e) - { - LOG.debug(e); - throw new RuntimeIOException(e); - } - } - /* ------------------------------------------------------------ */ @Override public AsyncContext getAsyncContext() @@ -2322,7 +2317,6 @@ public class Request implements HttpServletRequest @Override public Collection getParts() throws IOException, ServletException { - // TODO should content type be case sensitive if (getContentType() == null || !MimeTypes.Type.MULTIPART_FORM_DATA.is(HttpFields.valueParameters(getContentType(),null))) throw new ServletException("Content-Type != multipart/form-data"); @@ -2332,7 +2326,7 @@ public class Request implements HttpServletRequest private Collection getParts(MultiMap params) throws IOException, ServletException { if (_multiPartInputStream == null) - _multiPartInputStream = (MultiPartInputStreamParser)getAttribute(__MULTIPART_INPUT_STREAM); + _multiPartInputStream = (MultiPartInputStream)getAttribute(__MULTIPART_INPUT_STREAM); if (_multiPartInputStream == null) { @@ -2340,9 +2334,9 @@ public class Request implements HttpServletRequest if (config == null) throw new IllegalStateException("No multipart config for servlet"); - _multiPartInputStream = new MultiPartInputStreamParser(getInputStream(), - getContentType(), config, - (_context != null?(File)_context.getAttribute("javax.servlet.context.tempdir"):null)); + _multiPartInputStream = new MultiPartInputStream(getInputStream(), + getContentType(), config, + (_context != null?(File)_context.getAttribute("javax.servlet.context.tempdir"):null)); setAttribute(__MULTIPART_INPUT_STREAM, _multiPartInputStream); setAttribute(__MULTIPART_CONTEXT, _context); @@ -2350,8 +2344,7 @@ public class Request implements HttpServletRequest ByteArrayOutputStream os = null; for (Part p:parts) { - MultiPartInputStreamParser.MultiPart mp = (MultiPartInputStreamParser.MultiPart)p; - if (mp.getContentDispositionFilename() == null) + if (_multiPartInputStream.getContentDispositionFilename(p) == null) { // Servlet Spec 3.0 pg 23, parts without filename must be put into params. String charset = null; @@ -2376,6 +2369,7 @@ public class Request implements HttpServletRequest return _multiPartInputStream.getParts(); } + /* ------------------------------------------------------------ */ @Override public void login(String username, String password) throws ServletException @@ -2475,4 +2469,91 @@ public class Request implements HttpServletRequest { throw new ServletException("HttpServletRequest.upgrade() not supported in Jetty"); } + + + + /* --------------------------------------------------------------------------------------------------- */ + /* + * Used to switch between the old and new implementation of MultiPart Form InputStream Parsing. + * The new implementation is prefered will be used as default unless specified otherwise constructor. + */ + @SuppressWarnings("deprecation") + public class MultiPartInputStream + { + private boolean usingNewParser = true; + private MultiPartFormInputStream _newParser = null; + private MultiPartInputStreamParser _oldParser = null; + + public MultiPartInputStream(InputStream in, String contentType, MultipartConfigElement config, File contextTmpDir) + { + this(in, contentType, config, contextTmpDir, false); + } + + public MultiPartInputStream(InputStream in, String contentType, MultipartConfigElement config, File contextTmpDir, boolean useOldParser) + { + if(useOldParser) + usingNewParser = false; + else + usingNewParser = true; + + if(usingNewParser) + _newParser = new MultiPartFormInputStream(in, contentType, config, contextTmpDir); + else + _oldParser = new MultiPartInputStreamParser(in, contentType, config, contextTmpDir); + } + + public Collection getParts() throws IOException { + Collection parts = null; + + if(usingNewParser) + parts = _newParser.getParts(); + else + parts = _oldParser.getParts(); + + return parts; + } + + public Part getPart(String name) throws IOException { + Part part = null; + + if(usingNewParser) + part = _newParser.getPart(name); + else + part = _oldParser.getPart(name); + + return part; + } + + public String getContentDispositionFilename(Part p) + { + String contentDisposition = null; + + if(usingNewParser) + contentDisposition = ((MultiPartFormInputStream.MultiPart)p).getContentDispositionFilename(); + else + contentDisposition = ((MultiPartInputStreamParser.MultiPart)p).getContentDispositionFilename(); + + return contentDisposition; + } + + public void deleteParts() throws MultiException + { + if(usingNewParser) + _newParser.deleteParts(); + else + _oldParser.deleteParts(); + } + + public Collection getParsedParts() + { + Collection parsedParts = null; + + if(usingNewParser) + parsedParts = _newParser.getParsedParts(); + else + parsedParts = _oldParser.getParsedParts(); + + return parsedParts; + } + } } diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/RequestTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/RequestTest.java index 318a3ffcdc5..eeefa299e7f 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/RequestTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/RequestTest.java @@ -364,7 +364,7 @@ public class RequestTest @Override public void requestDestroyed(ServletRequestEvent sre) { - MultiPartInputStreamParser m = (MultiPartInputStreamParser)sre.getServletRequest().getAttribute(Request.__MULTIPART_INPUT_STREAM); + Request.MultiPartInputStream m = (Request.MultiPartInputStream)sre.getServletRequest().getAttribute(Request.__MULTIPART_INPUT_STREAM); ContextHandler.Context c = (ContextHandler.Context)sre.getServletRequest().getAttribute(Request.__MULTIPART_CONTEXT); assertNotNull (m); assertNotNull (c); @@ -426,7 +426,7 @@ public class RequestTest @Override public void requestDestroyed(ServletRequestEvent sre) { - MultiPartInputStreamParser m = (MultiPartInputStreamParser)sre.getServletRequest().getAttribute(Request.__MULTIPART_INPUT_STREAM); + Request.MultiPartInputStream m = (Request.MultiPartInputStream)sre.getServletRequest().getAttribute(Request.__MULTIPART_INPUT_STREAM); ContextHandler.Context c = (ContextHandler.Context)sre.getServletRequest().getAttribute(Request.__MULTIPART_CONTEXT); assertNotNull (m); assertNotNull (c); From 87498220bc6cffe93185d7ed4ee94bcfd81cc3ce Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Tue, 3 Apr 2018 10:49:03 +1000 Subject: [PATCH 41/50] Added a multipart form-data compliance configuration Signed-off-by: Greg Wilkins --- jetty-server/src/main/config/etc/jetty.xml | 1 + .../src/main/config/modules/server.mod | 3 ++ .../jetty/server/HttpConfiguration.java | 18 ++++++++- .../server/MultiPartFormDataCompliance.java | 38 +++++++++++++++++++ .../org/eclipse/jetty/server/Request.java | 3 ++ 5 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 jetty-server/src/main/java/org/eclipse/jetty/server/MultiPartFormDataCompliance.java diff --git a/jetty-server/src/main/config/etc/jetty.xml b/jetty-server/src/main/config/etc/jetty.xml index 9f93b35c739..d86e28aea18 100644 --- a/jetty-server/src/main/config/etc/jetty.xml +++ b/jetty-server/src/main/config/etc/jetty.xml @@ -65,6 +65,7 @@ + diff --git a/jetty-server/src/main/config/modules/server.mod b/jetty-server/src/main/config/modules/server.mod index 441a463bea2..ed7d608d01f 100644 --- a/jetty-server/src/main/config/modules/server.mod +++ b/jetty-server/src/main/config/modules/server.mod @@ -65,6 +65,9 @@ etc/jetty.xml ## Cookie compliance mode of: RFC2965, RFC6265 # jetty.httpConfig.cookieCompliance=RFC6265 +## multipart/form-data compliance mode of: LEGACY(slow), RFC7578(fast) +# jetty.httpConfig.multiPartFormDataCompliance=LEGACY + ### Server configuration ## Whether ctrl+c on the console gracefully stops the Jetty server # jetty.server.stopAtShutdown=true diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConfiguration.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConfiguration.java index 801a89887e3..59e6f23aff9 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConfiguration.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConfiguration.java @@ -47,7 +47,6 @@ import org.eclipse.jetty.util.annotation.ManagedObject; public class HttpConfiguration { public static final String SERVER_VERSION = "Jetty(" + Jetty.VERSION + ")"; - private final List _customizers=new CopyOnWriteArrayList<>(); private final Trie _formEncodedMethods = new TreeTrie<>(); private int _outputBufferSize=32*1024; @@ -68,6 +67,7 @@ public class HttpConfiguration private long _minRequestDataRate; private long _minResponseDataRate; private CookieCompliance _cookieCompliance = CookieCompliance.RFC6265; + private MultiPartFormDataCompliance _multiPartCompliance = MultiPartFormDataCompliance.LEGACY; // TODO change default in jetty-10 private boolean _notifyRemoteAsyncErrors = true; /** @@ -536,6 +536,22 @@ public class HttpConfiguration return _cookieCompliance.equals(compliance); } + /** + * Sets the compliance level for multipart/form-data handling. + * + * @param multiPartCompliance The multipart/form-data compliance level. + */ + public void setMultiPartFormDataCompliance(MultiPartFormDataCompliance multiPartCompliance) + { + // TODO change default in jetty-10 + _multiPartCompliance = multiPartCompliance==null?MultiPartFormDataCompliance.LEGACY:multiPartCompliance; + } + + public MultiPartFormDataCompliance getMultipartFormDataCompliance() + { + return _multiPartCompliance; + } + /** * @param notifyRemoteAsyncErrors whether remote errors, when detected, are notified to async applications */ diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/MultiPartFormDataCompliance.java b/jetty-server/src/main/java/org/eclipse/jetty/server/MultiPartFormDataCompliance.java new file mode 100644 index 00000000000..1616d0785bd --- /dev/null +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/MultiPartFormDataCompliance.java @@ -0,0 +1,38 @@ +// +// ======================================================================== +// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.server; + +/** + * The compliance level for parsing multiPart/form-data + * + */ +public enum MultiPartFormDataCompliance +{ + /** + * Legacy multiPart/form-data parsing which is slow but forgiving. + * It will accept non compliant preambles and inconsistent line termination. + * @see org.eclipse.jetty.util.MultiPartInputStreamParser + */ + LEGACY, + /** + * RFC7578 compliant parsing that is a fast but strict parser. + * @see org.eclipse.jetty.http.MultiPartFormInputStream + */ + RFC7578 +} \ No newline at end of file diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java index 63930e8bd3c..30929c20734 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java @@ -2328,6 +2328,9 @@ public class Request implements HttpServletRequest private Collection getParts(MultiMap params) throws IOException, ServletException { + // TODO use this + MultiPartFormDataCompliance compliance = getHttpChannel().getHttpConfiguration().getMultipartFormDataCompliance(); + if (_multiPartInputStream == null) _multiPartInputStream = (MultiPartInputStreamParser)getAttribute(__MULTIPART_INPUT_STREAM); From 13b15e35669ef7fb344944c3627e3daa8d640a42 Mon Sep 17 00:00:00 2001 From: Lachlan Roberts Date: Tue, 3 Apr 2018 15:24:54 +1000 Subject: [PATCH 42/50] Resolved Charset Issues and Reworked Request.MultiPartInputStream Changed Request.MultiPartInputStream to an interface called MultiParts where there is an implementation for both the HTTP and UTIL parsers. Resolved some issues with default charsets in regards to request.setCharacterEncoding and the _charset_ part for issue #2398. Changed HTTP parser to operate the same as UTIL parser in situtions with parts not of type form-data or without name field. HTTP parser was ignoring these parts, UTIL parser was throwing exceptions. Replaced the context attribute with a field in MultiParts. Signed-off-by: Lachlan Roberts --- .../jetty/http/MultiPartFormInputStream.java | 70 +++-- .../http/MultiPartFormInputStreamTest.java | 1 + .../jetty/http/MultiPartParserTest.java | 6 +- .../jetty/server/HttpChannelOverHttp.java | 2 +- .../server/MultiPartCleanerListener.java | 10 +- .../org/eclipse/jetty/server/Request.java | 271 ++++++++++++------ .../org/eclipse/jetty/server/RequestTest.java | 18 +- .../util/MultiPartInputStreamParser.java | 47 ++- .../jetty/util/MultiPartInputStreamTest.java | 10 +- 9 files changed, 291 insertions(+), 144 deletions(-) diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartFormInputStream.java b/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartFormInputStream.java index c2d1d14fe29..35d4f2a9f6c 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartFormInputStream.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartFormInputStream.java @@ -35,7 +35,6 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; -import java.util.Locale; import javax.servlet.MultipartConfigElement; import javax.servlet.ServletInputStream; @@ -73,6 +72,7 @@ public class MultiPartFormInputStream protected File _contextTmpDir; protected boolean _deleteOnExit; protected boolean _writeFilesWithFilenames; + protected boolean _parsed; public class MultiPart implements Part { @@ -384,17 +384,37 @@ public class MultiPartFormInputStream if (((ServletInputStream)in).isFinished()) { _parts = EMPTY_MAP; + _parsed = true; return; } } _in = new BufferedInputStream(in); } + /** + * @return whether the list of parsed parts is empty + */ + public boolean isEmpty() + { + if (_parts == null) + return true; + + Collection> values = _parts.values(); + for (List partList : values) + { + if(partList.size() != 0) + return false; + } + + return true; + } + /** * Get the already parsed parts. * * @return the parts that were parsed */ + @Deprecated public Collection getParsedParts() { if (_parts == null) @@ -412,14 +432,23 @@ public class MultiPartFormInputStream /** * Delete any tmp storage for parts, and clear out the parts list. - * - * @throws MultiException - * if unable to delete the parts */ - public void deleteParts() throws MultiException + public void deleteParts() { - Collection parts = getParsedParts(); + if (!_parsed) + return; + + Collection parts; + try + { + parts = getParts(); + } + catch (IOException e) + { + throw new RuntimeException(e); + } MultiException err = new MultiException(); + for (Part p : parts) { try @@ -433,7 +462,7 @@ public class MultiPartFormInputStream } _parts.clear(); - err.ifExceptionThrowMulti(); + err.ifExceptionThrowRuntime(); } /** @@ -445,7 +474,8 @@ public class MultiPartFormInputStream */ public Collection getParts() throws IOException { - parse(); + if (!_parsed) + parse(); throwIfError(); Collection> values = _parts.values(); @@ -469,7 +499,8 @@ public class MultiPartFormInputStream */ public Part getPart(String name) throws IOException { - parse(); + if(!_parsed) + parse(); throwIfError(); return _parts.getValue(name,0); } @@ -500,8 +531,10 @@ public class MultiPartFormInputStream protected void parse() { // have we already parsed the input? - if (_parts != null || _err != null) + if (_parsed) return; + _parsed = true; + try { @@ -612,7 +645,6 @@ public class MultiPartFormInputStream class Handler implements MultiPartParser.Handler { - private MultiPart _part = null; private String contentDisposition = null; private String contentType = null; @@ -673,18 +705,16 @@ public class MultiPartFormInputStream // Check disposition if (!form_data) - { - return false; - } + throw new IOException("Part not form-data"); + // It is valid for reset and submit buttons to have an empty name. // If no name is supplied, the browser skips sending the info for that field. // However, if you supply the empty string as the name, the browser sends the // field, with name as the empty string. So, only continue this loop if we // have not yet seen a name field. if (name == null) - { - return false; - } + throw new IOException("No name in part"); + // create the new part _part = new MultiPart(name,filename); @@ -766,12 +796,6 @@ public class MultiPartFormInputStream contentType = null; headers = new MultiMap<>(); } - - @Override - public String toString() { - return("contentDisposition: "+contentDisposition+" contentType:"+contentType); - } - } public void setDeleteOnExit(boolean deleteOnExit) diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartFormInputStreamTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartFormInputStreamTest.java index f48b4d4a309..c12109383a7 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartFormInputStreamTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartFormInputStreamTest.java @@ -24,6 +24,7 @@ import static org.hamcrest.Matchers.notNullValue; import static org.hamcrest.Matchers.nullValue; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertThat; diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParserTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParserTest.java index bc1c77b8fad..009be1af293 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParserTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParserTest.java @@ -19,18 +19,18 @@ package org.eclipse.jetty.http; import static org.hamcrest.Matchers.is; -import static org.junit.Assert.*; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import java.nio.ByteBuffer; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import java.util.concurrent.ThreadLocalRandom; import org.eclipse.jetty.http.MultiPartParser.State; import org.eclipse.jetty.util.BufferUtil; import org.hamcrest.Matchers; -import org.junit.Ignore; import org.junit.Test; public class MultiPartParserTest diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java index 79f0a8d7ea0..c2fbf69bdd8 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java @@ -51,7 +51,7 @@ public class HttpChannelOverHttp extends HttpChannel implements HttpParser.Reque { private static final Logger LOG = Log.getLogger(HttpChannelOverHttp.class); private final static HttpField PREAMBLE_UPGRADE_H2C = new HttpField(HttpHeader.UPGRADE, "h2c"); - private static final String ATTR_COMPLIANCE_VIOLATIONS = "org.eclipse.jetty.http.compliance.violations"; + public static final String ATTR_COMPLIANCE_VIOLATIONS = "org.eclipse.jetty.http.compliance.violations"; private final HttpFields _fields = new HttpFields(); private final MetaData.Request _metadata = new MetaData.Request(_fields); diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/MultiPartCleanerListener.java b/jetty-server/src/main/java/org/eclipse/jetty/server/MultiPartCleanerListener.java index 2d176b37c2d..af7310c706c 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/MultiPartCleanerListener.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/MultiPartCleanerListener.java @@ -38,19 +38,19 @@ public class MultiPartCleanerListener implements ServletRequestListener public void requestDestroyed(ServletRequestEvent sre) { //Clean up any tmp files created by MultiPartInputStream - Request.MultiPartInputStream mpis = (Request.MultiPartInputStream)sre.getServletRequest().getAttribute(Request.__MULTIPART_INPUT_STREAM); - if (mpis != null) + Request.MultiParts parts = (Request.MultiParts)sre.getServletRequest().getAttribute(Request.__MULTIPARTS); + if (parts != null) { - ContextHandler.Context context = (ContextHandler.Context)sre.getServletRequest().getAttribute(Request.__MULTIPART_CONTEXT); + ContextHandler.Context context = parts.getContext(); //Only do the cleanup if we are exiting from the context in which a servlet parsed the multipart files if (context == sre.getServletContext()) { try { - mpis.deleteParts(); + parts.close(); } - catch (MultiException e) + catch (Exception e) { sre.getServletContext().log("Errors deleting multipart tmp files", e); } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java index 3dac341d7d4..9a4e4f49dea 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java @@ -20,6 +20,7 @@ package org.eclipse.jetty.server; import java.io.BufferedReader; import java.io.ByteArrayOutputStream; +import java.io.Closeable; import java.io.File; import java.io.IOException; import java.io.InputStream; @@ -34,6 +35,7 @@ import java.security.Principal; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.EnumSet; import java.util.Enumeration; import java.util.EventListener; import java.util.List; @@ -84,9 +86,9 @@ import org.eclipse.jetty.server.session.SessionHandler; import org.eclipse.jetty.util.Attributes; import org.eclipse.jetty.util.AttributesMap; import org.eclipse.jetty.util.IO; -import org.eclipse.jetty.util.MultiException; import org.eclipse.jetty.util.MultiMap; import org.eclipse.jetty.util.MultiPartInputStreamParser; +import org.eclipse.jetty.util.MultiPartInputStreamParser.NonCompliance; import org.eclipse.jetty.util.StringUtil; import org.eclipse.jetty.util.URIUtil; import org.eclipse.jetty.util.UrlEncoded; @@ -136,8 +138,7 @@ import org.eclipse.jetty.util.log.Logger; public class Request implements HttpServletRequest { public static final String __MULTIPART_CONFIG_ELEMENT = "org.eclipse.jetty.multipartConfig"; - public static final String __MULTIPART_INPUT_STREAM = "org.eclipse.jetty.multiPartInputStream"; - public static final String __MULTIPART_CONTEXT = "org.eclipse.jetty.multiPartContext"; + public static final String __MULTIPARTS = "org.eclipse.jetty.multiPartInputStream"; private static final Logger LOG = Log.getLogger(Request.class); private static final Collection __defaultLocale = Collections.singleton(Locale.getDefault()); @@ -216,7 +217,7 @@ public class Request implements HttpServletRequest private HttpSession _session; private SessionHandler _sessionHandler; private long _timeStamp; - private MultiPartInputStream _multiPartInputStream; //if the request is a multi-part mime + private MultiParts _multiParts; //if the request is a multi-part mime private AsyncContextState _async; /* ------------------------------------------------------------ */ @@ -476,7 +477,7 @@ public class Request implements HttpServletRequest } else if (MimeTypes.Type.MULTIPART_FORM_DATA.is(contentType) && getAttribute(__MULTIPART_CONFIG_ELEMENT) != null && - _multiPartInputStream == null) + _multiParts == null) { try { @@ -1869,7 +1870,7 @@ public class Request implements HttpServletRequest _parameters = null; _contentParamsExtracted = false; _inputState = __NONE; - _multiPartInputStream = null; + _multiParts = null; _remote=null; _input.recycle(); } @@ -2310,7 +2311,7 @@ public class Request implements HttpServletRequest { getParts(); - return _multiPartInputStream.getPart(name); + return _multiParts.getPart(name); } /* ------------------------------------------------------------ */ @@ -2325,26 +2326,52 @@ public class Request implements HttpServletRequest private Collection getParts(MultiMap params) throws IOException, ServletException { - if (_multiPartInputStream == null) - _multiPartInputStream = (MultiPartInputStream)getAttribute(__MULTIPART_INPUT_STREAM); + if (_multiParts == null) + _multiParts = (MultiParts)getAttribute(__MULTIPARTS); - if (_multiPartInputStream == null) + if (_multiParts == null) { MultipartConfigElement config = (MultipartConfigElement)getAttribute(__MULTIPART_CONFIG_ELEMENT); if (config == null) throw new IllegalStateException("No multipart config for servlet"); - _multiPartInputStream = new MultiPartInputStream(getInputStream(), + _multiParts = newMultiParts(getInputStream(), getContentType(), config, - (_context != null?(File)_context.getAttribute("javax.servlet.context.tempdir"):null)); + (_context != null?(File)_context.getAttribute("javax.servlet.context.tempdir"):null), + true); - setAttribute(__MULTIPART_INPUT_STREAM, _multiPartInputStream); - setAttribute(__MULTIPART_CONTEXT, _context); - Collection parts = _multiPartInputStream.getParts(); //causes parsing + setAttribute(__MULTIPARTS, _multiParts); + Collection parts = _multiParts.getParts(); //causes parsing + + String _charset_ = null; + Part charsetPart = _multiParts.getPart("_charset_"); + if(charsetPart != null) + { + try (InputStream is = charsetPart.getInputStream()) + { + ByteArrayOutputStream os = new ByteArrayOutputStream(); + IO.copy(is, os); + _charset_ = new String(os.toByteArray(),StandardCharsets.UTF_8); + } + } + + // charset should be: + // 1. the charset set in the parts content type; else + // 2. the default charset set in the _charset_ part; else + // 3. the default charset set in the request.setCharacterEncoding; else + // 4. the default charset set to UTF_8 + Charset defaultCharset; + if (_charset_ != null) + defaultCharset = Charset.forName(_charset_); + else if (getCharacterEncoding() != null) + defaultCharset = Charset.forName(getCharacterEncoding()); + else + defaultCharset = StandardCharsets.UTF_8; + ByteArrayOutputStream os = null; for (Part p:parts) { - if (_multiPartInputStream.getContentDispositionFilename(p) == null) + if (p.getSubmittedFileName() == null) { // Servlet Spec 3.0 pg 23, parts without filename must be put into params. String charset = null; @@ -2356,7 +2383,8 @@ public class Request implements HttpServletRequest if (os == null) os = new ByteArrayOutputStream(); IO.copy(is, os); - String content=new String(os.toByteArray(),charset==null?StandardCharsets.UTF_8:Charset.forName(charset)); + + String content=new String(os.toByteArray(),charset==null?defaultCharset:Charset.forName(charset)); if (_contentParameters == null) _contentParameters = params == null ? new MultiMap<>() : params; _contentParameters.add(p.getName(), content); @@ -2366,10 +2394,28 @@ public class Request implements HttpServletRequest } } - return _multiPartInputStream.getParts(); + return _multiParts.getParts(); } + private MultiParts newMultiParts(ServletInputStream inputStream, String contentType, MultipartConfigElement config, Object object, boolean useNewParser) throws IOException + { + MultiParts multiParts; + + if(useNewParser) + { + multiParts = new MultiPartsHttpParser(getInputStream(), getContentType(), config, + (_context != null?(File)_context.getAttribute("javax.servlet.context.tempdir"):null)); + } + else + { + multiParts = new MultiPartsUtilParser(getInputStream(), getContentType(), config, + (_context != null?(File)_context.getAttribute("javax.servlet.context.tempdir"):null)); + } + + return multiParts; + } + /* ------------------------------------------------------------ */ @Override public void login(String username, String password) throws ServletException @@ -2477,83 +2523,144 @@ public class Request implements HttpServletRequest * Used to switch between the old and new implementation of MultiPart Form InputStream Parsing. * The new implementation is prefered will be used as default unless specified otherwise constructor. */ - @SuppressWarnings("deprecation") - public class MultiPartInputStream + public interface MultiParts extends Closeable { - private boolean usingNewParser = true; - private MultiPartFormInputStream _newParser = null; - private MultiPartInputStreamParser _oldParser = null; - - public MultiPartInputStream(InputStream in, String contentType, MultipartConfigElement config, File contextTmpDir) - { - this(in, contentType, config, contextTmpDir, false); - } + public Collection getParts(); + public Part getPart(String name); + public boolean isEmpty(); + public ContextHandler.Context getContext(); + } + + + public class MultiPartsHttpParser implements MultiParts + { + private final MultiPartFormInputStream _httpParser; + private final ContextHandler.Context _context; - public MultiPartInputStream(InputStream in, String contentType, MultipartConfigElement config, File contextTmpDir, boolean useOldParser) + public MultiPartsHttpParser(InputStream in, String contentType, MultipartConfigElement config, File contextTmpDir) throws IOException { - if(useOldParser) - usingNewParser = false; - else - usingNewParser = true; - - if(usingNewParser) - _newParser = new MultiPartFormInputStream(in, contentType, config, contextTmpDir); - else - _oldParser = new MultiPartInputStreamParser(in, contentType, config, contextTmpDir); + _httpParser = new MultiPartFormInputStream(in, contentType, config, contextTmpDir); + _context = Request.this._context; + _httpParser.getParts(); } - public Collection getParts() throws IOException { - Collection parts = null; - - if(usingNewParser) - parts = _newParser.getParts(); - else - parts = _oldParser.getParts(); - - return parts; - } - - public Part getPart(String name) throws IOException { - Part part = null; - - if(usingNewParser) - part = _newParser.getPart(name); - else - part = _oldParser.getPart(name); - - return part; - } - - public String getContentDispositionFilename(Part p) + @Override + public Collection getParts() { - String contentDisposition = null; + try + { + return _httpParser.getParts(); + } + catch (IOException e) + { + throw new RuntimeException(e); + } + } - if(usingNewParser) - contentDisposition = ((MultiPartFormInputStream.MultiPart)p).getContentDispositionFilename(); - else - contentDisposition = ((MultiPartInputStreamParser.MultiPart)p).getContentDispositionFilename(); - - return contentDisposition; + @Override + public Part getPart(String name) { + try + { + return _httpParser.getPart(name); + } + catch (IOException e) + { + throw new RuntimeException(e); + } } - public void deleteParts() throws MultiException + @Override + public void close() { - if(usingNewParser) - _newParser.deleteParts(); - else - _oldParser.deleteParts(); + _httpParser.deleteParts(); } - public Collection getParsedParts() + @Override + public boolean isEmpty() { - Collection parsedParts = null; - - if(usingNewParser) - parsedParts = _newParser.getParsedParts(); - else - parsedParts = _oldParser.getParsedParts(); - - return parsedParts; + return _httpParser.isEmpty(); } + + @Override + public Context getContext() + { + return _context; + } + + } + + + @SuppressWarnings("deprecation") + public class MultiPartsUtilParser implements MultiParts + { + private final MultiPartInputStreamParser _utilParser; + private final ContextHandler.Context _context; + + public MultiPartsUtilParser(InputStream in, String contentType, MultipartConfigElement config, File contextTmpDir) throws IOException + { + _utilParser = new MultiPartInputStreamParser(in, contentType, config, contextTmpDir); + _context = Request.this._context; + _utilParser.getParts(); + + EnumSet nonComplianceWarnings = _utilParser.getNonComplianceWarnings(); + if (!nonComplianceWarnings.isEmpty()) + { + @SuppressWarnings("unchecked") + List violations = (List)getAttribute(HttpChannelOverHttp.ATTR_COMPLIANCE_VIOLATIONS); + if (violations==null) + { + violations = new ArrayList<>(); + setAttribute(HttpChannelOverHttp.ATTR_COMPLIANCE_VIOLATIONS,violations); + } + + for(NonCompliance nc : nonComplianceWarnings) + violations.add(nc.name()+": "+nc.getURL()); + } + } + + @Override + public Collection getParts() + { + try + { + return _utilParser.getParts(); + } + catch (IOException e) + { + throw new RuntimeException(e); + } + } + + @Override + public Part getPart(String name) + { + try + { + return _utilParser.getPart(name); + } + catch (IOException e) + { + throw new RuntimeException(e); + } + } + + @Override + public void close() + { + _utilParser.deleteParts(); + } + + @Override + public boolean isEmpty() + { + return _utilParser.getParsedParts().isEmpty(); + } + + @Override + public Context getContext() + { + return _context; + } + } } diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/RequestTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/RequestTest.java index eeefa299e7f..d788de882c8 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/RequestTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/RequestTest.java @@ -44,7 +44,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Enumeration; import java.util.Locale; -import java.util.Map; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; @@ -70,7 +69,6 @@ import org.eclipse.jetty.toolchain.test.FS; import org.eclipse.jetty.toolchain.test.MavenTestingUtils; import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.IO; -import org.eclipse.jetty.util.MultiPartInputStreamParser; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.log.StacklessLogging; @@ -162,7 +160,7 @@ public class RequestTest @Override public boolean check(HttpServletRequest request,HttpServletResponse response) { - Map map = request.getParameterMap(); + request.getParameterMap(); // should have thrown a BadMessageException return false; } @@ -189,7 +187,7 @@ public class RequestTest @Override public boolean check(HttpServletRequest request,HttpServletResponse response) { - Map map = request.getParameterMap(); + request.getParameterMap(); // should have thrown a BadMessageException return false; } @@ -364,12 +362,12 @@ public class RequestTest @Override public void requestDestroyed(ServletRequestEvent sre) { - Request.MultiPartInputStream m = (Request.MultiPartInputStream)sre.getServletRequest().getAttribute(Request.__MULTIPART_INPUT_STREAM); - ContextHandler.Context c = (ContextHandler.Context)sre.getServletRequest().getAttribute(Request.__MULTIPART_CONTEXT); + Request.MultiParts m = (Request.MultiParts)sre.getServletRequest().getAttribute(Request.__MULTIPARTS); assertNotNull (m); + ContextHandler.Context c = m.getContext(); assertNotNull (c); assertTrue(c == sre.getServletContext()); - assertTrue(!m.getParsedParts().isEmpty()); + assertTrue(!m.isEmpty()); assertTrue(testTmpDir.list().length == 2); super.requestDestroyed(sre); String[] files = testTmpDir.list(); @@ -401,7 +399,7 @@ public class RequestTest multipart; String responses=_connector.getResponse(request); - // System.err.println(responses); + //System.err.println(responses); assertTrue(responses.startsWith("HTTP/1.1 200")); } @@ -426,9 +424,9 @@ public class RequestTest @Override public void requestDestroyed(ServletRequestEvent sre) { - Request.MultiPartInputStream m = (Request.MultiPartInputStream)sre.getServletRequest().getAttribute(Request.__MULTIPART_INPUT_STREAM); - ContextHandler.Context c = (ContextHandler.Context)sre.getServletRequest().getAttribute(Request.__MULTIPART_CONTEXT); + Request.MultiParts m = (Request.MultiParts)sre.getServletRequest().getAttribute(Request.__MULTIPARTS); assertNotNull (m); + ContextHandler.Context c = m.getContext(); assertNotNull (c); assertTrue(c == sre.getServletContext()); super.requestDestroyed(sre); diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/MultiPartInputStreamParser.java b/jetty-util/src/main/java/org/eclipse/jetty/util/MultiPartInputStreamParser.java index 2dd81111fa0..131a5587c78 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/MultiPartInputStreamParser.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/MultiPartInputStreamParser.java @@ -78,15 +78,28 @@ public class MultiPartInputStreamParser protected File _contextTmpDir; protected boolean _deleteOnExit; protected boolean _writeFilesWithFilenames; + protected boolean _parsed; private EnumSet nonComplianceWarnings = EnumSet.noneOf(NonCompliance.class); public enum NonCompliance { - CR_TERMINATION, - LF_TERMINATION, - NO_INITIAL_CRLF, - BASE64_TRANSFER_ENCODING, - QUOTED_PRINTABLE_TRANSFER_ENCODING + CR_LINE_TERMINATION("https://tools.ietf.org/html/rfc2046#section-4.1.1"), + LF_LINE_TERMINATION("https://tools.ietf.org/html/rfc2046#section-4.1.1"), + NO_CRLF_AFTER_PREAMBLE("https://tools.ietf.org/html/rfc2046#section-5.1.1"), + BASE64_TRANSFER_ENCODING("https://tools.ietf.org/html/rfc7578#section-4.7"), + QUOTED_PRINTABLE_TRANSFER_ENCODING("https://tools.ietf.org/html/rfc7578#section-4.7"); + + final String _rfcRef; + + NonCompliance(String rfcRef) + { + _rfcRef = rfcRef; + } + + public String getURL() + { + return _rfcRef; + } } /** @@ -414,6 +427,7 @@ public class MultiPartInputStreamParser if (((ServletInputStream)in).isFinished()) { _parts = EMPTY_MAP; + _parsed = true; return; } } @@ -441,12 +455,12 @@ public class MultiPartInputStreamParser /** * Delete any tmp storage for parts, and clear out the parts list. - * - * @throws MultiException if unable to delete the parts */ public void deleteParts () - throws MultiException { + if(!_parsed) + return; + Collection parts = getParsedParts(); MultiException err = new MultiException(); for (Part p:parts) @@ -462,7 +476,7 @@ public class MultiPartInputStreamParser } _parts.clear(); - err.ifExceptionThrowMulti(); + err.ifExceptionThrowRuntime(); } @@ -475,7 +489,8 @@ public class MultiPartInputStreamParser public Collection getParts() throws IOException { - parse(); + if(!_parsed) + parse(); throwIfError(); @@ -500,7 +515,8 @@ public class MultiPartInputStreamParser public Part getPart(String name) throws IOException { - parse(); + if(_parsed) + parse(); throwIfError(); return _parts.getValue(name, 0); } @@ -530,8 +546,9 @@ public class MultiPartInputStreamParser protected void parse () { //have we already parsed the input? - if (_parts != null || _err != null) + if (_parsed) return; + _parsed = true; //initialize @@ -616,7 +633,7 @@ public class MultiPartInputStreamParser // check compliance of preamble if (Character.isWhitespace(untrimmed.charAt(0))) - nonComplianceWarnings.add(NonCompliance.NO_INITIAL_CRLF); + nonComplianceWarnings.add(NonCompliance.NO_CRLF_AFTER_PREAMBLE); // Read each part boolean lastPart=false; @@ -847,9 +864,9 @@ public class MultiPartInputStreamParser EnumSet term = ((ReadLineInputStream)_in).getLineTerminations(); if(term.contains(Termination.CR)) - nonComplianceWarnings.add(NonCompliance.CR_TERMINATION); + nonComplianceWarnings.add(NonCompliance.CR_LINE_TERMINATION); if(term.contains(Termination.LF)) - nonComplianceWarnings.add(NonCompliance.LF_TERMINATION); + nonComplianceWarnings.add(NonCompliance.LF_LINE_TERMINATION); } else throw new IOException("Incomplete parts"); diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/MultiPartInputStreamTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/MultiPartInputStreamTest.java index dd623cd7072..2463d398f78 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/MultiPartInputStreamTest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/MultiPartInputStreamTest.java @@ -378,7 +378,7 @@ public class MultiPartInputStreamTest IO.copy(stuff.getInputStream(), baos); assertTrue(baos.toString("US-ASCII").contains("aaaa")); - assertEquals(EnumSet.of(NonCompliance.LF_TERMINATION), mpis.getNonComplianceWarnings()); + assertEquals(EnumSet.of(NonCompliance.LF_LINE_TERMINATION), mpis.getNonComplianceWarnings()); } @@ -420,7 +420,7 @@ public class MultiPartInputStreamTest IO.copy(stuff.getInputStream(), baos); assertTrue(baos.toString("US-ASCII").contains("bbbbb")); - assertEquals(EnumSet.of(NonCompliance.NO_INITIAL_CRLF), mpis.getNonComplianceWarnings()); + assertEquals(EnumSet.of(NonCompliance.NO_CRLF_AFTER_PREAMBLE), mpis.getNonComplianceWarnings()); } @@ -631,7 +631,7 @@ public class MultiPartInputStreamTest IO.copy(p2.getInputStream(), baos); assertThat(baos.toString("UTF-8"), is("Other")); - assertEquals(EnumSet.of(NonCompliance.LF_TERMINATION), mpis.getNonComplianceWarnings()); + assertEquals(EnumSet.of(NonCompliance.LF_LINE_TERMINATION), mpis.getNonComplianceWarnings()); } @Test @@ -671,7 +671,7 @@ public class MultiPartInputStreamTest IO.copy(p2.getInputStream(), baos); assertThat(baos.toString("UTF-8"), is("Other")); - assertEquals(EnumSet.of(NonCompliance.CR_TERMINATION), mpis.getNonComplianceWarnings()); + assertEquals(EnumSet.of(NonCompliance.CR_LINE_TERMINATION), mpis.getNonComplianceWarnings()); } @Test @@ -710,7 +710,7 @@ public class MultiPartInputStreamTest IO.copy(p2.getInputStream(), baos); assertThat(baos.toString("UTF-8"), is("Other")); - assertEquals(EnumSet.of(NonCompliance.CR_TERMINATION), mpis.getNonComplianceWarnings()); + assertEquals(EnumSet.of(NonCompliance.CR_LINE_TERMINATION), mpis.getNonComplianceWarnings()); } @Test From b3d5333d421990d54a117d8556b81a498e4eed67 Mon Sep 17 00:00:00 2001 From: Lachlan Roberts Date: Tue, 3 Apr 2018 16:13:19 +1000 Subject: [PATCH 43/50] Implemented switch between LEGACY and RFC7578 modes. Added tests to check this worked correctly. Signed-off-by: Lachlan Roberts --- .../org/eclipse/jetty/server/Request.java | 30 ++--- .../org/eclipse/jetty/server/RequestTest.java | 118 +++++++++++++++++- 2 files changed, 129 insertions(+), 19 deletions(-) diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java index 9676f3cef79..2904ba684a6 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java @@ -2325,10 +2325,7 @@ public class Request implements HttpServletRequest } private Collection getParts(MultiMap params) throws IOException, ServletException - { - // TODO use this - MultiPartFormDataCompliance compliance = getHttpChannel().getHttpConfiguration().getMultipartFormDataCompliance(); - + { if (_multiParts == null) _multiParts = (MultiParts)getAttribute(__MULTIPARTS); @@ -2340,8 +2337,7 @@ public class Request implements HttpServletRequest _multiParts = newMultiParts(getInputStream(), getContentType(), config, - (_context != null?(File)_context.getAttribute("javax.servlet.context.tempdir"):null), - true); + (_context != null?(File)_context.getAttribute("javax.servlet.context.tempdir"):null)); setAttribute(__MULTIPARTS, _multiParts); Collection parts = _multiParts.getParts(); //causes parsing @@ -2401,22 +2397,22 @@ public class Request implements HttpServletRequest } - private MultiParts newMultiParts(ServletInputStream inputStream, String contentType, MultipartConfigElement config, Object object, boolean useNewParser) throws IOException + private MultiParts newMultiParts(ServletInputStream inputStream, String contentType, MultipartConfigElement config, Object object) throws IOException { - MultiParts multiParts; + MultiPartFormDataCompliance compliance = getHttpChannel().getHttpConfiguration().getMultipartFormDataCompliance(); - if(useNewParser) + switch(compliance) { - multiParts = new MultiPartsHttpParser(getInputStream(), getContentType(), config, - (_context != null?(File)_context.getAttribute("javax.servlet.context.tempdir"):null)); - } - else - { - multiParts = new MultiPartsUtilParser(getInputStream(), getContentType(), config, + case RFC7578: + return new MultiPartsHttpParser(getInputStream(), getContentType(), config, + (_context != null?(File)_context.getAttribute("javax.servlet.context.tempdir"):null)); + + case LEGACY: + default: + return new MultiPartsUtilParser(getInputStream(), getContentType(), config, (_context != null?(File)_context.getAttribute("javax.servlet.context.tempdir"):null)); + } - - return multiParts; } /* ------------------------------------------------------------ */ diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/RequestTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/RequestTest.java index d788de882c8..5de3d7d67d5 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/RequestTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/RequestTest.java @@ -43,6 +43,7 @@ import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; import java.util.Enumeration; +import java.util.List; import java.util.Locale; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; @@ -340,8 +341,7 @@ public class RequestTest String response = _connector.getResponse(request); assertThat(response, containsString(" 200 OK")); } - - + @Test public void testMultiPart() throws Exception { @@ -402,6 +402,114 @@ public class RequestTest //System.err.println(responses); assertTrue(responses.startsWith("HTTP/1.1 200")); } + + @Test + public void testUtilMultiPart() throws Exception + { + final File testTmpDir = File.createTempFile("reqtest", null); + if (testTmpDir.exists()) + testTmpDir.delete(); + testTmpDir.mkdir(); + testTmpDir.deleteOnExit(); + assertTrue(testTmpDir.list().length == 0); + + ContextHandler contextHandler = new ContextHandler(); + contextHandler.setContextPath("/foo"); + contextHandler.setResourceBase("."); + contextHandler.setHandler(new MultiPartRequestHandler(testTmpDir)); + contextHandler.addEventListener(new MultiPartCleanerListener() + { + + @Override + public void requestDestroyed(ServletRequestEvent sre) + { + Request.MultiParts m = (Request.MultiParts)sre.getServletRequest().getAttribute(Request.__MULTIPARTS); + assertNotNull (m); + ContextHandler.Context c = m.getContext(); + assertNotNull (c); + assertTrue(c == sre.getServletContext()); + assertTrue(!m.isEmpty()); + assertTrue(testTmpDir.list().length == 2); + super.requestDestroyed(sre); + String[] files = testTmpDir.list(); + assertTrue(files.length == 0); + } + + }); + _server.stop(); + _server.setHandler(contextHandler); + _connector.getBean(HttpConnectionFactory.class).getHttpConfiguration().setMultiPartFormDataCompliance(MultiPartFormDataCompliance.LEGACY); + _server.start(); + + String multipart = " --AaB03x\r"+ + "content-disposition: form-data; name=\"field1\"\r"+ + "\r"+ + "Joe Blow\r"+ + "--AaB03x\r"+ + "content-disposition: form-data; name=\"stuff\"; filename=\"foo.upload\"\r"+ + "Content-Type: text/plain;charset=ISO-8859-1\r"+ + "\r"+ + "000000000000000000000000000000000000000000000000000\r"+ + "--AaB03x--\r"; + + String request="GET /foo/x.html HTTP/1.1\r\n"+ + "Host: whatever\r\n"+ + "Content-Type: multipart/form-data; boundary=\"AaB03x\"\r\n"+ + "Content-Length: "+multipart.getBytes().length+"\r\n"+ + "Connection: close\r\n"+ + "\r\n"+ + multipart; + + String responses=_connector.getResponse(request); + //System.err.println(responses); + assertThat(responses, Matchers.startsWith("HTTP/1.1 200")); + assertThat(responses, Matchers.containsString("Violation: CR_LINE_TERMINATION")); + assertThat(responses, Matchers.containsString("Violation: NO_CRLF_AFTER_PREAMBLE")); + } + + @Test + public void testHttpMultiPart() throws Exception + { + final File testTmpDir = File.createTempFile("reqtest", null); + if (testTmpDir.exists()) + testTmpDir.delete(); + testTmpDir.mkdir(); + testTmpDir.deleteOnExit(); + assertTrue(testTmpDir.list().length == 0); + + ContextHandler contextHandler = new ContextHandler(); + contextHandler.setContextPath("/foo"); + contextHandler.setResourceBase("."); + contextHandler.setHandler(new MultiPartRequestHandler(testTmpDir)); + + _server.stop(); + _server.setHandler(contextHandler); + _connector.getBean(HttpConnectionFactory.class).getHttpConfiguration().setMultiPartFormDataCompliance(MultiPartFormDataCompliance.RFC7578); + _server.start(); + + String multipart = " --AaB03x\r"+ + "content-disposition: form-data; name=\"field1\"\r"+ + "\r"+ + "Joe Blow\r"+ + "--AaB03x\r"+ + "content-disposition: form-data; name=\"stuff\"; filename=\"foo.upload\"\r"+ + "Content-Type: text/plain;charset=ISO-8859-1\r"+ + "\r"+ + "000000000000000000000000000000000000000000000000000\r"+ + "--AaB03x--\r"; + + String request="GET /foo/x.html HTTP/1.1\r\n"+ + "Host: whatever\r\n"+ + "Content-Type: multipart/form-data; boundary=\"AaB03x\"\r\n"+ + "Content-Length: "+multipart.getBytes().length+"\r\n"+ + "Connection: close\r\n"+ + "\r\n"+ + multipart; + + String responses=_connector.getResponse(request); + //System.err.println(responses); + assertThat(responses,Matchers.startsWith("HTTP/1.1 500")); + } @Test public void testBadMultiPart() throws Exception @@ -1710,6 +1818,12 @@ public class RequestTest assertNotNull(foo); assertTrue(foo.getSize() > 0); response.setStatus(200); + List violations = (List)request.getAttribute(HttpChannelOverHttp.ATTR_COMPLIANCE_VIOLATIONS); + if(violations != null) + { + for(String v : violations) + response.addHeader("Violation",v); + } } catch (IllegalStateException e) { From 1eec23433632b6de47077bf78076cfb754e65148 Mon Sep 17 00:00:00 2001 From: Lachlan Roberts Date: Tue, 3 Apr 2018 21:22:16 +1000 Subject: [PATCH 44/50] Minor changes after review by gregw. Signed-off-by: Lachlan Roberts --- .../src/main/java/org/eclipse/jetty/http/HttpCompliance.java | 4 +++- .../java/org/eclipse/jetty/server/HttpChannelOverHttp.java | 4 +--- .../org/eclipse/jetty/server/MultiPartCleanerListener.java | 2 +- .../src/main/java/org/eclipse/jetty/server/Request.java | 5 +++-- .../src/test/java/org/eclipse/jetty/server/RequestTest.java | 3 ++- 5 files changed, 10 insertions(+), 8 deletions(-) diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpCompliance.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpCompliance.java index c51bc0f32eb..9e7022b35e4 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpCompliance.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpCompliance.java @@ -49,7 +49,7 @@ import org.eclipse.jetty.util.log.Logger; * be altered in code and will affect all usages of the mode. */ public enum HttpCompliance // TODO in Jetty-10 convert this enum to a class so that extra custom modes can be defined dynamically -{ +{ /** A Legacy compliance mode to match jetty's behavior prior to RFC2616 and RFC7230. It only * contains {@link HttpComplianceSection#METHOD_CASE_SENSITIVE} */ @@ -82,6 +82,8 @@ public enum HttpCompliance // TODO in Jetty-10 convert this enum to a class so t @Deprecated CUSTOM3(sectionsByProperty("CUSTOM3")); + public static final String VIOLATIONS_ATTR = "org.eclipse.jetty.http.compliance.violations"; + private static final Logger LOG = Log.getLogger(HttpParser.class); private static EnumSet sectionsByProperty(String property) { diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java index c2fbf69bdd8..3e2f0cbd654 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java @@ -51,8 +51,6 @@ public class HttpChannelOverHttp extends HttpChannel implements HttpParser.Reque { private static final Logger LOG = Log.getLogger(HttpChannelOverHttp.class); private final static HttpField PREAMBLE_UPGRADE_H2C = new HttpField(HttpHeader.UPGRADE, "h2c"); - public static final String ATTR_COMPLIANCE_VIOLATIONS = "org.eclipse.jetty.http.compliance.violations"; - private final HttpFields _fields = new HttpFields(); private final MetaData.Request _metadata = new MetaData.Request(_fields); private final HttpConnection _httpConnection; @@ -291,7 +289,7 @@ public class HttpChannelOverHttp extends HttpChannel implements HttpParser.Reque { if (_complianceViolations != null && !_complianceViolations.isEmpty()) { - this.getRequest().setAttribute(ATTR_COMPLIANCE_VIOLATIONS, _complianceViolations); + this.getRequest().setAttribute(HttpCompliance.VIOLATIONS_ATTR, _complianceViolations); _complianceViolations=null; } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/MultiPartCleanerListener.java b/jetty-server/src/main/java/org/eclipse/jetty/server/MultiPartCleanerListener.java index af7310c706c..40ae2cb04e8 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/MultiPartCleanerListener.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/MultiPartCleanerListener.java @@ -50,7 +50,7 @@ public class MultiPartCleanerListener implements ServletRequestListener { parts.close(); } - catch (Exception e) + catch (Throwable e) { sre.getServletContext().log("Errors deleting multipart tmp files", e); } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java index 2904ba684a6..7eb705f2a0d 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java @@ -66,6 +66,7 @@ import javax.servlet.http.Part; import org.eclipse.jetty.http.BadMessageException; import org.eclipse.jetty.http.HostPortHttpField; +import org.eclipse.jetty.http.HttpCompliance; import org.eclipse.jetty.http.HttpCookie; import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpFields; @@ -2605,11 +2606,11 @@ public class Request implements HttpServletRequest if (!nonComplianceWarnings.isEmpty()) { @SuppressWarnings("unchecked") - List violations = (List)getAttribute(HttpChannelOverHttp.ATTR_COMPLIANCE_VIOLATIONS); + List violations = (List)getAttribute(HttpCompliance.VIOLATIONS_ATTR); if (violations==null) { violations = new ArrayList<>(); - setAttribute(HttpChannelOverHttp.ATTR_COMPLIANCE_VIOLATIONS,violations); + setAttribute(HttpCompliance.VIOLATIONS_ATTR,violations); } for(NonCompliance nc : nonComplianceWarnings) diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/RequestTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/RequestTest.java index 5de3d7d67d5..2d6c06f4763 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/RequestTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/RequestTest.java @@ -59,6 +59,7 @@ import javax.servlet.http.HttpServletResponse; import javax.servlet.http.Part; import org.eclipse.jetty.http.BadMessageException; +import org.eclipse.jetty.http.HttpCompliance; import org.eclipse.jetty.http.HttpTester; import org.eclipse.jetty.http.MimeTypes; import org.eclipse.jetty.server.LocalConnector.LocalEndPoint; @@ -1818,7 +1819,7 @@ public class RequestTest assertNotNull(foo); assertTrue(foo.getSize() > 0); response.setStatus(200); - List violations = (List)request.getAttribute(HttpChannelOverHttp.ATTR_COMPLIANCE_VIOLATIONS); + List violations = (List)request.getAttribute(HttpCompliance.VIOLATIONS_ATTR); if(violations != null) { for(String v : violations) From 81ff77108c3ab3387cf53e7b3edd77eb8aa11ec5 Mon Sep 17 00:00:00 2001 From: Lachlan Roberts Date: Tue, 3 Apr 2018 23:55:08 +1000 Subject: [PATCH 45/50] Moved the MultiParts interface and implementations from Request into new file MultiParts.java Signed-off-by: Lachlan Roberts --- .../server/MultiPartCleanerListener.java | 2 +- .../org/eclipse/jetty/server/MultiParts.java | 183 ++++++++++++++++++ .../org/eclipse/jetty/server/Request.java | 162 +--------------- .../org/eclipse/jetty/server/RequestTest.java | 6 +- 4 files changed, 191 insertions(+), 162 deletions(-) create mode 100644 jetty-server/src/main/java/org/eclipse/jetty/server/MultiParts.java diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/MultiPartCleanerListener.java b/jetty-server/src/main/java/org/eclipse/jetty/server/MultiPartCleanerListener.java index 40ae2cb04e8..99acef7d50f 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/MultiPartCleanerListener.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/MultiPartCleanerListener.java @@ -38,7 +38,7 @@ public class MultiPartCleanerListener implements ServletRequestListener public void requestDestroyed(ServletRequestEvent sre) { //Clean up any tmp files created by MultiPartInputStream - Request.MultiParts parts = (Request.MultiParts)sre.getServletRequest().getAttribute(Request.__MULTIPARTS); + MultiParts parts = (MultiParts)sre.getServletRequest().getAttribute(Request.__MULTIPARTS); if (parts != null) { ContextHandler.Context context = parts.getContext(); diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/MultiParts.java b/jetty-server/src/main/java/org/eclipse/jetty/server/MultiParts.java new file mode 100644 index 00000000000..670e61a7ee2 --- /dev/null +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/MultiParts.java @@ -0,0 +1,183 @@ +// +// ======================================================================== +// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.server; + +import java.io.Closeable; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Collection; +import java.util.EnumSet; +import java.util.List; + +import javax.servlet.MultipartConfigElement; +import javax.servlet.http.Part; + +import org.eclipse.jetty.http.HttpCompliance; +import org.eclipse.jetty.http.MultiPartFormInputStream; +import org.eclipse.jetty.server.handler.ContextHandler; +import org.eclipse.jetty.server.handler.ContextHandler.Context; +import org.eclipse.jetty.util.MultiPartInputStreamParser; +import org.eclipse.jetty.util.MultiPartInputStreamParser.NonCompliance; + + +/* + * Used to switch between the old and new implementation of MultiPart Form InputStream Parsing. + * The new implementation is prefered will be used as default unless specified otherwise constructor. + */ +public interface MultiParts extends Closeable +{ + public Collection getParts(); + public Part getPart(String name); + public boolean isEmpty(); + public ContextHandler.Context getContext(); + + + public class MultiPartsHttpParser implements MultiParts + { + private final MultiPartFormInputStream _httpParser; + private final ContextHandler.Context _context; + + public MultiPartsHttpParser(InputStream in, String contentType, MultipartConfigElement config, File contextTmpDir, Request request) throws IOException + { + _httpParser = new MultiPartFormInputStream(in, contentType, config, contextTmpDir); + _context = request.getContext(); + _httpParser.getParts(); + } + + @Override + public Collection getParts() + { + try + { + return _httpParser.getParts(); + } + catch (IOException e) + { + throw new RuntimeException(e); + } + } + + @Override + public Part getPart(String name) { + try + { + return _httpParser.getPart(name); + } + catch (IOException e) + { + throw new RuntimeException(e); + } + } + + @Override + public void close() + { + _httpParser.deleteParts(); + } + + @Override + public boolean isEmpty() + { + return _httpParser.isEmpty(); + } + + @Override + public Context getContext() + { + return _context; + } + + } + + + @SuppressWarnings("deprecation") + public class MultiPartsUtilParser implements MultiParts + { + private final MultiPartInputStreamParser _utilParser; + private final ContextHandler.Context _context; + + public MultiPartsUtilParser(InputStream in, String contentType, MultipartConfigElement config, File contextTmpDir, Request request) throws IOException + { + _utilParser = new MultiPartInputStreamParser(in, contentType, config, contextTmpDir); + _context = request.getContext(); + _utilParser.getParts(); + + EnumSet nonComplianceWarnings = _utilParser.getNonComplianceWarnings(); + if (!nonComplianceWarnings.isEmpty()) + { + @SuppressWarnings("unchecked") + List violations = (List)request.getAttribute(HttpCompliance.VIOLATIONS_ATTR); + if (violations==null) + { + violations = new ArrayList<>(); + request.setAttribute(HttpCompliance.VIOLATIONS_ATTR,violations); + } + + for(NonCompliance nc : nonComplianceWarnings) + violations.add(nc.name()+": "+nc.getURL()); + } + } + + @Override + public Collection getParts() + { + try + { + return _utilParser.getParts(); + } + catch (IOException e) + { + throw new RuntimeException(e); + } + } + + @Override + public Part getPart(String name) + { + try + { + return _utilParser.getPart(name); + } + catch (IOException e) + { + throw new RuntimeException(e); + } + } + + @Override + public void close() + { + _utilParser.deleteParts(); + } + + @Override + public boolean isEmpty() + { + return _utilParser.getParsedParts().isEmpty(); + } + + @Override + public Context getContext() + { + return _context; + } + } +} diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java index 7eb705f2a0d..20c2de107c3 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java @@ -20,7 +20,6 @@ package org.eclipse.jetty.server; import java.io.BufferedReader; import java.io.ByteArrayOutputStream; -import java.io.Closeable; import java.io.File; import java.io.IOException; import java.io.InputStream; @@ -35,7 +34,6 @@ import java.security.Principal; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; -import java.util.EnumSet; import java.util.Enumeration; import java.util.EventListener; import java.util.List; @@ -66,7 +64,6 @@ import javax.servlet.http.Part; import org.eclipse.jetty.http.BadMessageException; import org.eclipse.jetty.http.HostPortHttpField; -import org.eclipse.jetty.http.HttpCompliance; import org.eclipse.jetty.http.HttpCookie; import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpFields; @@ -78,7 +75,6 @@ import org.eclipse.jetty.http.HttpURI; import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.http.MetaData; import org.eclipse.jetty.http.MimeTypes; -import org.eclipse.jetty.http.MultiPartFormInputStream; import org.eclipse.jetty.io.RuntimeIOException; import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.server.handler.ContextHandler.Context; @@ -88,8 +84,6 @@ import org.eclipse.jetty.util.Attributes; import org.eclipse.jetty.util.AttributesMap; import org.eclipse.jetty.util.IO; import org.eclipse.jetty.util.MultiMap; -import org.eclipse.jetty.util.MultiPartInputStreamParser; -import org.eclipse.jetty.util.MultiPartInputStreamParser.NonCompliance; import org.eclipse.jetty.util.StringUtil; import org.eclipse.jetty.util.URIUtil; import org.eclipse.jetty.util.UrlEncoded; @@ -2405,13 +2399,13 @@ public class Request implements HttpServletRequest switch(compliance) { case RFC7578: - return new MultiPartsHttpParser(getInputStream(), getContentType(), config, - (_context != null?(File)_context.getAttribute("javax.servlet.context.tempdir"):null)); + return new MultiParts.MultiPartsHttpParser(getInputStream(), getContentType(), config, + (_context != null?(File)_context.getAttribute("javax.servlet.context.tempdir"):null), this); case LEGACY: default: - return new MultiPartsUtilParser(getInputStream(), getContentType(), config, - (_context != null?(File)_context.getAttribute("javax.servlet.context.tempdir"):null)); + return new MultiParts.MultiPartsUtilParser(getInputStream(), getContentType(), config, + (_context != null?(File)_context.getAttribute("javax.servlet.context.tempdir"):null), this); } } @@ -2515,152 +2509,4 @@ public class Request implements HttpServletRequest { throw new ServletException("HttpServletRequest.upgrade() not supported in Jetty"); } - - - - /* --------------------------------------------------------------------------------------------------- */ - /* - * Used to switch between the old and new implementation of MultiPart Form InputStream Parsing. - * The new implementation is prefered will be used as default unless specified otherwise constructor. - */ - public interface MultiParts extends Closeable - { - public Collection getParts(); - public Part getPart(String name); - public boolean isEmpty(); - public ContextHandler.Context getContext(); - } - - - public class MultiPartsHttpParser implements MultiParts - { - private final MultiPartFormInputStream _httpParser; - private final ContextHandler.Context _context; - - public MultiPartsHttpParser(InputStream in, String contentType, MultipartConfigElement config, File contextTmpDir) throws IOException - { - _httpParser = new MultiPartFormInputStream(in, contentType, config, contextTmpDir); - _context = Request.this._context; - _httpParser.getParts(); - } - - @Override - public Collection getParts() - { - try - { - return _httpParser.getParts(); - } - catch (IOException e) - { - throw new RuntimeException(e); - } - } - - @Override - public Part getPart(String name) { - try - { - return _httpParser.getPart(name); - } - catch (IOException e) - { - throw new RuntimeException(e); - } - } - - @Override - public void close() - { - _httpParser.deleteParts(); - } - - @Override - public boolean isEmpty() - { - return _httpParser.isEmpty(); - } - - @Override - public Context getContext() - { - return _context; - } - - } - - - @SuppressWarnings("deprecation") - public class MultiPartsUtilParser implements MultiParts - { - private final MultiPartInputStreamParser _utilParser; - private final ContextHandler.Context _context; - - public MultiPartsUtilParser(InputStream in, String contentType, MultipartConfigElement config, File contextTmpDir) throws IOException - { - _utilParser = new MultiPartInputStreamParser(in, contentType, config, contextTmpDir); - _context = Request.this._context; - _utilParser.getParts(); - - EnumSet nonComplianceWarnings = _utilParser.getNonComplianceWarnings(); - if (!nonComplianceWarnings.isEmpty()) - { - @SuppressWarnings("unchecked") - List violations = (List)getAttribute(HttpCompliance.VIOLATIONS_ATTR); - if (violations==null) - { - violations = new ArrayList<>(); - setAttribute(HttpCompliance.VIOLATIONS_ATTR,violations); - } - - for(NonCompliance nc : nonComplianceWarnings) - violations.add(nc.name()+": "+nc.getURL()); - } - } - - @Override - public Collection getParts() - { - try - { - return _utilParser.getParts(); - } - catch (IOException e) - { - throw new RuntimeException(e); - } - } - - @Override - public Part getPart(String name) - { - try - { - return _utilParser.getPart(name); - } - catch (IOException e) - { - throw new RuntimeException(e); - } - } - - @Override - public void close() - { - _utilParser.deleteParts(); - } - - @Override - public boolean isEmpty() - { - return _utilParser.getParsedParts().isEmpty(); - } - - @Override - public Context getContext() - { - return _context; - } - - } } diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/RequestTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/RequestTest.java index 2d6c06f4763..14743f5a801 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/RequestTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/RequestTest.java @@ -363,7 +363,7 @@ public class RequestTest @Override public void requestDestroyed(ServletRequestEvent sre) { - Request.MultiParts m = (Request.MultiParts)sre.getServletRequest().getAttribute(Request.__MULTIPARTS); + MultiParts m = (MultiParts)sre.getServletRequest().getAttribute(Request.__MULTIPARTS); assertNotNull (m); ContextHandler.Context c = m.getContext(); assertNotNull (c); @@ -424,7 +424,7 @@ public class RequestTest @Override public void requestDestroyed(ServletRequestEvent sre) { - Request.MultiParts m = (Request.MultiParts)sre.getServletRequest().getAttribute(Request.__MULTIPARTS); + MultiParts m = (MultiParts)sre.getServletRequest().getAttribute(Request.__MULTIPARTS); assertNotNull (m); ContextHandler.Context c = m.getContext(); assertNotNull (c); @@ -533,7 +533,7 @@ public class RequestTest @Override public void requestDestroyed(ServletRequestEvent sre) { - Request.MultiParts m = (Request.MultiParts)sre.getServletRequest().getAttribute(Request.__MULTIPARTS); + MultiParts m = (MultiParts)sre.getServletRequest().getAttribute(Request.__MULTIPARTS); assertNotNull (m); ContextHandler.Context c = m.getContext(); assertNotNull (c); From 3b32e1c984e63b1c9d4c3381ea1cd319c082c017 Mon Sep 17 00:00:00 2001 From: Joakim Erdfelt Date: Tue, 3 Apr 2018 14:55:38 -0500 Subject: [PATCH 46/50] Issue #1027 - MultiPartCaptureTest cleanup + Regenerated many of the captures - Better SJIS Encoding Test Samples + Added more - file consisting of only random whitespace - file with 1 very long line - Jetty Http Client captures Signed-off-by: Joakim Erdfelt --- .../jetty/http/MultiPartCaptureTest.java | 60 +- ...ny-urlencoded-apache-httpcomp.expected.txt | 9 + ...re-company-urlencoded-apache-httpcomp.raw} | 4 +- ...pture-complex-apache-httpcomp.expected.txt | 15 + ...owser-capture-complex-apache-httpcomp.raw} | Bin 22929 -> 22940 bytes ...-capture-complex-jetty-client.expected.txt | 15 + ... browser-capture-complex-jetty-client.raw} | Bin 22359 -> 22754 bytes ...plicate-names-apache-httpcomp.expected.txt | 8 + ...pture-duplicate-names-apache-httpcomp.raw} | Bin 1859 -> 1815 bytes ...-duplicate-names-jetty-client.expected.txt | 8 + ...r-capture-duplicate-names-jetty-client.raw | 51 + ...encoding-mess-apache-httpcomp.expected.txt | 11 + ...capture-encoding-mess-apache-httpcomp.raw} | 344 +- ...re-encoding-mess-jetty-client.expected.txt | 11 + ...ser-capture-encoding-mess-jetty-client.raw | 846 + ...orm-fileupload-alt-ios-safari.expected.txt | 18 - ...apture-nested-apache-httpcomp.expected.txt | 12 + ...rowser-capture-nested-apache-httpcomp.raw} | 22 +- ...nested-binary-apache-httpcomp.expected.txt | 12 + ...capture-nested-binary-apache-httpcomp.raw} | 22 +- ...r-capture-nested-jetty-client.expected.txt | 12 + .../browser-capture-nested-jetty-client.raw | 42 + ...e-number-only-apache-httpcomp.expected.txt | 9 + ...r-capture-number-only-apache-httpcomp.raw} | 4 +- ...ture-number-only-jetty-client.expected.txt | 12 + ...owser-capture-number-only-jetty-client.raw | 6 + ...-number-only2-apache-httpcomp.expected.txt | 9 + ...-capture-number-only2-apache-httpcomp.raw} | 4 +- ...-capture-sjis-apache-httpcomp.expected.txt | 10 + ... browser-capture-sjis-apache-httpcomp.raw} | 10 +- ...ser-capture-sjis-jetty-client.expected.txt | 10 + .../browser-capture-sjis-jetty-client.raw | 11 + ...range-quoting-apache-httpcomp.expected.txt | 11 + ...pture-strange-quoting-apache-httpcomp.raw} | 10 +- ...re-text-files-apache-httpcomp.expected.txt | 15 + ...er-capture-text-files-apache-httpcomp.raw} | 8 +- ...ture-text-files-jetty-client.expected.txt} | 8 +- ...rowser-capture-text-files-jetty-client.raw | 20 + ...unicode-names-apache-httpcomp.expected.txt | 11 + ...capture-unicode-names-apache-httpcomp.raw} | 6 +- ...re-unicode-names-jetty-client.expected.txt | 11 + ...ser-capture-unicode-names-jetty-client.raw | 11 + ...-whitespace-only-jetty-client.expected.txt | 10 + ...r-capture-whitespace-only-jetty-client.raw | 209748 +++++++++++++++ ...o-text-plain-apache-httpcomp.expected.txt} | 10 +- ...ture-zalgo-text-plain-apache-httpcomp.raw} | Bin 1830 -> 1870 bytes .../multipart/multipart-complex.expected.txt | 9 - .../multipart-duplicate-names-1.expected.txt | 2 - .../multipart-encoding-mess.expected.txt | 4 - ...ultipart-inside-itself-binary.expected.txt | 6 - .../multipart-inside-itself.expected.txt | 6 - .../multipart-number-browser.expected.txt | 3 - .../multipart-number-strict.expected.txt | 3 - .../multipart/multipart-sjis.expected.txt | 4 - .../multipart-strange-quoting.expected.txt | 5 - .../multipart-unicode-names.expected.txt | 5 - ...ltipart-x-www-form-urlencoded.expected.txt | 5 - 57 files changed, 211227 insertions(+), 311 deletions(-) create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-company-urlencoded-apache-httpcomp.expected.txt rename jetty-http/src/test/resources/multipart/{multipart-x-www-form-urlencoded.raw => browser-capture-company-urlencoded-apache-httpcomp.raw} (68%) create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-complex-apache-httpcomp.expected.txt rename jetty-http/src/test/resources/multipart/{multipart-complex.raw => browser-capture-complex-apache-httpcomp.raw} (98%) create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-complex-jetty-client.expected.txt rename jetty-http/src/test/resources/multipart/{browser-capture-form-fileupload-alt-ios-safari.raw => browser-capture-complex-jetty-client.raw} (95%) create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-duplicate-names-apache-httpcomp.expected.txt rename jetty-http/src/test/resources/multipart/{multipart-duplicate-names-1.raw => browser-capture-duplicate-names-apache-httpcomp.raw} (73%) create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-duplicate-names-jetty-client.expected.txt create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-duplicate-names-jetty-client.raw create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-encoding-mess-apache-httpcomp.expected.txt rename jetty-http/src/test/resources/multipart/{multipart-encoding-mess.raw => browser-capture-encoding-mess-apache-httpcomp.raw} (77%) create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-encoding-mess-jetty-client.expected.txt create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-encoding-mess-jetty-client.raw delete mode 100644 jetty-http/src/test/resources/multipart/browser-capture-form-fileupload-alt-ios-safari.expected.txt create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-nested-apache-httpcomp.expected.txt rename jetty-http/src/test/resources/multipart/{multipart-inside-itself.raw => browser-capture-nested-apache-httpcomp.raw} (52%) create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-nested-binary-apache-httpcomp.expected.txt rename jetty-http/src/test/resources/multipart/{multipart-inside-itself-binary.raw => browser-capture-nested-binary-apache-httpcomp.raw} (59%) create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-nested-jetty-client.expected.txt create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-nested-jetty-client.raw create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-number-only-apache-httpcomp.expected.txt rename jetty-http/src/test/resources/multipart/{multipart-number-browser.raw => browser-capture-number-only-apache-httpcomp.raw} (51%) create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-number-only-jetty-client.expected.txt create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-number-only-jetty-client.raw create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-number-only2-apache-httpcomp.expected.txt rename jetty-http/src/test/resources/multipart/{multipart-number-strict.raw => browser-capture-number-only2-apache-httpcomp.raw} (63%) create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-sjis-apache-httpcomp.expected.txt rename jetty-http/src/test/resources/multipart/{multipart-sjis.raw => browser-capture-sjis-apache-httpcomp.raw} (60%) create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-sjis-jetty-client.expected.txt create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-sjis-jetty-client.raw create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-strange-quoting-apache-httpcomp.expected.txt rename jetty-http/src/test/resources/multipart/{multipart-strange-quoting.raw => browser-capture-strange-quoting-apache-httpcomp.raw} (70%) create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-text-files-apache-httpcomp.expected.txt rename jetty-http/src/test/resources/multipart/{multipart-text-files.raw => browser-capture-text-files-apache-httpcomp.raw} (77%) rename jetty-http/src/test/resources/multipart/{multipart-text-files.expected.txt => browser-capture-text-files-jetty-client.expected.txt} (50%) create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-text-files-jetty-client.raw create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-unicode-names-apache-httpcomp.expected.txt rename jetty-http/src/test/resources/multipart/{multipart-unicode-names.raw => browser-capture-unicode-names-apache-httpcomp.raw} (70%) create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-unicode-names-jetty-client.expected.txt create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-unicode-names-jetty-client.raw create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-whitespace-only-jetty-client.expected.txt create mode 100644 jetty-http/src/test/resources/multipart/browser-capture-whitespace-only-jetty-client.raw rename jetty-http/src/test/resources/multipart/{multipart-zencoding.expected.txt => browser-capture-zalgo-text-plain-apache-httpcomp.expected.txt} (76%) rename jetty-http/src/test/resources/multipart/{multipart-zencoding.raw => browser-capture-zalgo-text-plain-apache-httpcomp.raw} (88%) delete mode 100644 jetty-http/src/test/resources/multipart/multipart-complex.expected.txt delete mode 100644 jetty-http/src/test/resources/multipart/multipart-duplicate-names-1.expected.txt delete mode 100644 jetty-http/src/test/resources/multipart/multipart-encoding-mess.expected.txt delete mode 100644 jetty-http/src/test/resources/multipart/multipart-inside-itself-binary.expected.txt delete mode 100644 jetty-http/src/test/resources/multipart/multipart-inside-itself.expected.txt delete mode 100644 jetty-http/src/test/resources/multipart/multipart-number-browser.expected.txt delete mode 100644 jetty-http/src/test/resources/multipart/multipart-number-strict.expected.txt delete mode 100644 jetty-http/src/test/resources/multipart/multipart-sjis.expected.txt delete mode 100644 jetty-http/src/test/resources/multipart/multipart-strange-quoting.expected.txt delete mode 100644 jetty-http/src/test/resources/multipart/multipart-unicode-names.expected.txt delete mode 100644 jetty-http/src/test/resources/multipart/multipart-x-www-form-urlencoded.expected.txt diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartCaptureTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartCaptureTest.java index 347614f4573..030ace1131b 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartCaptureTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartCaptureTest.java @@ -28,7 +28,6 @@ import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.nio.charset.Charset; import java.nio.file.Files; import java.nio.file.Path; import java.security.DigestOutputStream; @@ -46,7 +45,6 @@ import javax.servlet.http.Part; import org.eclipse.jetty.toolchain.test.Hex; import org.eclipse.jetty.toolchain.test.MavenTestingUtils; import org.eclipse.jetty.toolchain.test.TestingDir; -import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.IO; import org.eclipse.jetty.util.QuotedStringTokenizer; import org.eclipse.jetty.util.StringUtil; @@ -60,8 +58,8 @@ import org.junit.runners.Parameterized; public class MultiPartCaptureTest { - public static final int MAX_FILE_SIZE = 60 * 1024; - public static final int MAX_REQUEST_SIZE = 1024 * 1024; + public static final int MAX_FILE_SIZE = 2 * 1024 * 1024; + public static final int MAX_REQUEST_SIZE = MAX_FILE_SIZE + (60 * 1024); public static final int FILE_SIZE_THRESHOLD = 50; @Parameterized.Parameters(name = "{0}") @@ -69,25 +67,41 @@ public class MultiPartCaptureTest { List ret = new ArrayList<>(); - // Capture of raw request body contents from Apache HttpComponents 4.5.5 - ret.add(new String[]{"multipart-text-files"}); + // == Arbitrary / Non-Standard Examples == + + ret.add(new String[]{"multipart-uppercase"}); // ret.add(new String[]{"multipart-base64"}); // base64 transfer encoding deprecated // ret.add(new String[]{"multipart-base64-long"}); // base64 transfer encoding deprecated - // ret.add(new String[]{"multipart-complex"}); // TODO joakime bad capture includes ? in sjis content - ret.add(new String[]{"multipart-duplicate-names-1"}); - ret.add(new String[]{"multipart-encoding-mess"}); - // ret.add(new String[]{"multipart-inside-itself"}); // impossible test, badly chosen boundary - // ret.add(new String[]{"multipart-inside-itself-binary"}); // impossible test, badly chosen boundary - ret.add(new String[]{"multipart-number-browser"}); - ret.add(new String[]{"multipart-number-strict"}); - // ret.add(new String[]{"multipart-sjis"}); // TODO joakime bad capture includes ? in sjis content - ret.add(new String[]{"multipart-strange-quoting"}); - ret.add(new String[]{"multipart-unicode-names"}); - ret.add(new String[]{"multipart-uppercase"}); - // ret.add(new String[]{"multipart-x-www-form-urlencoded"}); // not our job to decode content - ret.add(new String[]{"multipart-zencoding"}); - // Capture of raw request body contents from various browsers + // == Capture of raw request body contents from Apache HttpClient 4.5.5 == + + ret.add(new String[]{"browser-capture-company-urlencoded-apache-httpcomp"}); + ret.add(new String[]{"browser-capture-complex-apache-httpcomp"}); + ret.add(new String[]{"browser-capture-duplicate-names-apache-httpcomp"}); + ret.add(new String[]{"browser-capture-encoding-mess-apache-httpcomp"}); + ret.add(new String[]{"browser-capture-nested-apache-httpcomp"}); + ret.add(new String[]{"browser-capture-nested-binary-apache-httpcomp"}); + ret.add(new String[]{"browser-capture-number-only2-apache-httpcomp"}); + ret.add(new String[]{"browser-capture-number-only-apache-httpcomp"}); + ret.add(new String[]{"browser-capture-sjis-apache-httpcomp"}); + ret.add(new String[]{"browser-capture-strange-quoting-apache-httpcomp"}); + ret.add(new String[]{"browser-capture-text-files-apache-httpcomp"}); + ret.add(new String[]{"browser-capture-unicode-names-apache-httpcomp"}); + ret.add(new String[]{"browser-capture-zalgo-text-plain-apache-httpcomp"}); + + // == Capture of raw request body contents from Eclipse Jetty Http Client 9.4.9 == + + ret.add(new String[]{"browser-capture-complex-jetty-client"}); + ret.add(new String[]{"browser-capture-duplicate-names-jetty-client"}); + ret.add(new String[]{"browser-capture-encoding-mess-jetty-client"}); + ret.add(new String[]{"browser-capture-nested-jetty-client"}); + ret.add(new String[]{"browser-capture-number-only-jetty-client"}); + ret.add(new String[]{"browser-capture-sjis-jetty-client"}); + ret.add(new String[]{"browser-capture-text-files-jetty-client"}); + ret.add(new String[]{"browser-capture-unicode-names-jetty-client"}); + ret.add(new String[]{"browser-capture-whitespace-only-jetty-client"}); + + // == Capture of raw request body contents from various browsers == // simple form - 2 fields ret.add(new String[]{"browser-capture-form1-android-chrome"}); @@ -100,13 +114,14 @@ public class MultiPartCaptureTest ret.add(new String[]{"browser-capture-form1-osx-safari"}); // form submitted as shift-jis + ret.add(new String[]{"browser-capture-sjis-form-edge"}); + ret.add(new String[]{"browser-capture-sjis-form-msie"}); + // TODO: these might be addressable via Issue #2398 // ret.add(new String[]{"browser-capture-sjis-form-android-chrome"}); // contains html encoded character and unspecified charset defaults to utf-8 // ret.add(new String[]{"browser-capture-sjis-form-android-firefox"}); // contains html encoded character and unspecified charset defaults to utf-8 // ret.add(new String[]{"browser-capture-sjis-form-chrome"}); // contains html encoded character and unspecified charset defaults to utf-8 - ret.add(new String[]{"browser-capture-sjis-form-edge"}); // ret.add(new String[]{"browser-capture-sjis-form-firefox"}); // contains html encoded character and unspecified charset defaults to utf-8 // ret.add(new String[]{"browser-capture-sjis-form-ios-safari"}); // contains html encoded character and unspecified charset defaults to utf-8 - ret.add(new String[]{"browser-capture-sjis-form-msie"}); // ret.add(new String[]{"browser-capture-sjis-form-safari"}); // contains html encoded character and unspecified charset defaults to utf-8 // form submitted as shift-jis (with HTML5 specific hidden _charset_ field) @@ -133,7 +148,6 @@ public class MultiPartCaptureTest ret.add(new String[]{"browser-capture-form-fileupload-alt-chrome"}); ret.add(new String[]{"browser-capture-form-fileupload-alt-edge"}); ret.add(new String[]{"browser-capture-form-fileupload-alt-firefox"}); - // ret.add(new String[]{"browser-capture-form-fileupload-alt-ios-safari"}); // is Sha1sum correct new parser gives same result as old parser ret.add(new String[]{"browser-capture-form-fileupload-alt-msie"}); ret.add(new String[]{"browser-capture-form-fileupload-alt-safari"}); diff --git a/jetty-http/src/test/resources/multipart/browser-capture-company-urlencoded-apache-httpcomp.expected.txt b/jetty-http/src/test/resources/multipart/browser-capture-company-urlencoded-apache-httpcomp.expected.txt new file mode 100644 index 00000000000..1eed1a48357 --- /dev/null +++ b/jetty-http/src/test/resources/multipart/browser-capture-company-urlencoded-apache-httpcomp.expected.txt @@ -0,0 +1,9 @@ +Request-Header|Accept-Encoding|gzip,deflate +Request-Header|Connection|keep-alive +Request-Header|Content-Length|248 +Request-Header|Content-Type|multipart/form-data; boundary=DHbU6ChASebwm4iE8z9Lakv4ybMmkp +Request-Header|Host|localhost:9090 +Request-Header|User-Agent|Apache-HttpClient/4.5.5 (Java/1.8.0_162) +Request-Header|X-BrowserId|apache-httpcomp +Parts-Count|1 +Part-ContainsContents|company|bob+%26+frank%27s+shoe+repair diff --git a/jetty-http/src/test/resources/multipart/multipart-x-www-form-urlencoded.raw b/jetty-http/src/test/resources/multipart/browser-capture-company-urlencoded-apache-httpcomp.raw similarity index 68% rename from jetty-http/src/test/resources/multipart/multipart-x-www-form-urlencoded.raw rename to jetty-http/src/test/resources/multipart/browser-capture-company-urlencoded-apache-httpcomp.raw index 994b267b26c..7059e4760c7 100644 --- a/jetty-http/src/test/resources/multipart/multipart-x-www-form-urlencoded.raw +++ b/jetty-http/src/test/resources/multipart/browser-capture-company-urlencoded-apache-httpcomp.raw @@ -1,7 +1,7 @@ ---qjIkwQOhaYfC2VEcL5j-9sjEK1FIsYMd5 +--DHbU6ChASebwm4iE8z9Lakv4ybMmkp Content-Disposition: form-data; name="company" Content-Type: application/x-www-form-urlencoded; charset=UTF-8 Content-Transfer-Encoding: 8bit bob+%26+frank%27s+shoe+repair ---qjIkwQOhaYfC2VEcL5j-9sjEK1FIsYMd5-- +--DHbU6ChASebwm4iE8z9Lakv4ybMmkp-- diff --git a/jetty-http/src/test/resources/multipart/browser-capture-complex-apache-httpcomp.expected.txt b/jetty-http/src/test/resources/multipart/browser-capture-complex-apache-httpcomp.expected.txt new file mode 100644 index 00000000000..fde7344fec7 --- /dev/null +++ b/jetty-http/src/test/resources/multipart/browser-capture-complex-apache-httpcomp.expected.txt @@ -0,0 +1,15 @@ +Request-Header|Accept-Encoding|gzip,deflate +Request-Header|Connection|keep-alive +Request-Header|Content-Length|22940 +Request-Header|Content-Type|multipart/form-data; boundary=owr6UQGvVNunA_sx2AsizBtyq_uK-OjsQXrF +Request-Header|Host|localhost:9090 +Request-Header|User-Agent|Apache-HttpClient/4.5.5 (Java/1.8.0_162) +Request-Header|X-BrowserId|apache-httpcomp +Parts-Count|6 +Part-ContainsContents|pi|3.14159265358979323846264338327950288419716939937510 +Part-ContainsContents|company|bob & frank's shoe repair +Part-ContainsContents|power|ꬵо𝗋ⲥ𝖾 +Part-ContainsContents|japanese|オープンソース +Part-ContainsContents|hello|日食桟橋 +Part-Filename|upload_file|filename +Part-Sha1sum|upload_file|e75b73644afe9b234d70da9ff225229de68cdff8 diff --git a/jetty-http/src/test/resources/multipart/multipart-complex.raw b/jetty-http/src/test/resources/multipart/browser-capture-complex-apache-httpcomp.raw similarity index 98% rename from jetty-http/src/test/resources/multipart/multipart-complex.raw rename to jetty-http/src/test/resources/multipart/browser-capture-complex-apache-httpcomp.raw index e74c27a67daacc6680c483bc89a9952531c1646d..87f46ff9258dea558e4d2e23798c34304d9f1cb3 100644 GIT binary patch delta 339 zcmbQZnQ_i$Mm1gC{PH5R&_MUHFu&3~$N1t3Bgf**DyNdl!uV2eUH`1&z=$HZNsJm3 z{rXghQ@WT)bsC%BGiHPmt9bI_@C>5WhDSu3HG4KjH5WhDSu}^i1ko$je2v|0WAWMi@6YH@De0#}TVd ISC^Ly0Iy4G&Hw-a diff --git a/jetty-http/src/test/resources/multipart/browser-capture-complex-jetty-client.expected.txt b/jetty-http/src/test/resources/multipart/browser-capture-complex-jetty-client.expected.txt new file mode 100644 index 00000000000..df6340cc7da --- /dev/null +++ b/jetty-http/src/test/resources/multipart/browser-capture-complex-jetty-client.expected.txt @@ -0,0 +1,15 @@ +Request-Header|Accept-Encoding|gzip +Request-Header|Connection|close +Request-Header|Content-Type|multipart/form-data; boundary=JettyHttpClientBoundary1275gffetpxz8o0q +Request-Header|Host|localhost:9090 +Request-Header|Transfer-Encoding|chunked +Request-Header|User-Agent|Jetty/9.4.9.v20180320 +Request-Header|X-BrowserId|jetty-client +Parts-Count|6 +Part-ContainsContents|pi|3.14159265358979323846264338327950288419716939937510 +Part-ContainsContents|company|bob & frank's shoe repair +Part-ContainsContents|power|ꬵо𝗋ⲥ𝖾 +Part-ContainsContents|japanese|オープンソース +Part-ContainsContents|hello|日食桟橋 +Part-Filename|upload_file|filename +Part-Sha1sum|upload_file|e75b73644afe9b234d70da9ff225229de68cdff8 diff --git a/jetty-http/src/test/resources/multipart/browser-capture-form-fileupload-alt-ios-safari.raw b/jetty-http/src/test/resources/multipart/browser-capture-complex-jetty-client.raw similarity index 95% rename from jetty-http/src/test/resources/multipart/browser-capture-form-fileupload-alt-ios-safari.raw rename to jetty-http/src/test/resources/multipart/browser-capture-complex-jetty-client.raw index 5a6bf414f80cc3cb09aae9c69235515b3a2c861a..04514a19dcb58314dfd2cf4cc75fdeb84be013dd 100644 GIT binary patch delta 833 zcmbW#ze~eF6bEqX7zi%noScO_L}tDq>x&MNp74eX*zM-Fdm%)W<4(Tk&arcvsM*u1#~MS_e_CCScr9P*r0hB$Q3~MIs|mlZ&}oc}Z(Z_uS3Pnl+Dc$xZUUNfTrNS#9zun&{nCFZ8$A{+0 z@qXjxta)(NAwUG37{OQJs^HLoIA+x-*xdcLb~<_zLO?U delta 454 zcmb7=!A^rf5Qf8*geUMqIGA2`SqcRfV|z0m`2n$)qNPUgIhe^|i@vLuQ z;z8)mo6KbnfAanF&DT-;c-Lm+JUMLcD@AHBz*Ga+-$9#6T zh37(59agQh4BgOi2WBl)3CgUBRvP*g+QVa2gLP$&ONs`rE!SsmkS3gjp0gxg$XpV~ z!HT#GZi8jL)Ny#k8D}<5?k2?0e*yY) Blk)%o diff --git a/jetty-http/src/test/resources/multipart/browser-capture-duplicate-names-apache-httpcomp.expected.txt b/jetty-http/src/test/resources/multipart/browser-capture-duplicate-names-apache-httpcomp.expected.txt new file mode 100644 index 00000000000..796af8952ce --- /dev/null +++ b/jetty-http/src/test/resources/multipart/browser-capture-duplicate-names-apache-httpcomp.expected.txt @@ -0,0 +1,8 @@ +Request-Header|Accept-Encoding|gzip,deflate +Request-Header|Connection|keep-alive +Request-Header|Content-Length|1815 +Request-Header|Content-Type|multipart/form-data; boundary=QW3F8Fg64P2J2dpfEKGKlX0Q9QF2a8SK_7YH +Request-Header|Host|localhost:9090 +Request-Header|User-Agent|Apache-HttpClient/4.5.5 (Java/1.8.0_162) +Request-Header|X-BrowserId|apache-httpcomp +Parts-Count|10 diff --git a/jetty-http/src/test/resources/multipart/multipart-duplicate-names-1.raw b/jetty-http/src/test/resources/multipart/browser-capture-duplicate-names-apache-httpcomp.raw similarity index 73% rename from jetty-http/src/test/resources/multipart/multipart-duplicate-names-1.raw rename to jetty-http/src/test/resources/multipart/browser-capture-duplicate-names-apache-httpcomp.raw index 06f32f09f4bb137551ab0ac44bbdfa614790c315..e48b5a6285618d7faf96ec090bab649c2901dff3 100644 GIT binary patch literal 1815 zcmdUvy-ve06hQk8u;S5<*BZukI}yb!~VmYvVl*-DE(G@>y*opV_ZVEV|bTA1PWj3M%6vEpSt z7Zn_rq)isR68 zZ43R2P{+@C^n{!BA0TqAbD8p8<$EeM!l2qzf*0TW>_x2#{qlP9{Kw1x>a+UWKE`P5ib-i z6gpw0;3ZRx7d^P(GDmZwNFNp?r-Ng`jz3nDM$jHqv{qe_5mxkJdPihQ)!-_LQSfO| zlA>HtiAF`r=d4)vU@&7!*K`ecEXQ&~+jFrSgno!^95|lsIT#1n_CwdSgTS#u-||8n zhS+y4Q`b;yg0+LS6_o4MA7K(9GM1990$rXes!*vUCHdF?w!FO_{Q2eR=^wajR89^bn6|R?*(i`u@SVxvGocLVAS2@`u##!uMW_3hX8%Q*ACddu09k(@|xvD(X4^n xRz3)8JTl_gFtHJtJBWWM8W;kx83{P30RuT8KmiIe&;ST9=l~0RD-}Yz_6kWmUd#Xh diff --git a/jetty-http/src/test/resources/multipart/browser-capture-duplicate-names-jetty-client.expected.txt b/jetty-http/src/test/resources/multipart/browser-capture-duplicate-names-jetty-client.expected.txt new file mode 100644 index 00000000000..bc73cca6fc6 --- /dev/null +++ b/jetty-http/src/test/resources/multipart/browser-capture-duplicate-names-jetty-client.expected.txt @@ -0,0 +1,8 @@ +Request-Header|Accept-Encoding|gzip +Request-Header|Connection|close +Request-Header|Content-Type|multipart/form-data; boundary=JettyHttpClientBoundary14beb4to333d91v8 +Request-Header|Host|localhost:9090 +Request-Header|Transfer-Encoding|chunked +Request-Header|User-Agent|Jetty/9.4.9.v20180320 +Request-Header|X-BrowserId|jetty-client +Parts-Count|10 diff --git a/jetty-http/src/test/resources/multipart/browser-capture-duplicate-names-jetty-client.raw b/jetty-http/src/test/resources/multipart/browser-capture-duplicate-names-jetty-client.raw new file mode 100644 index 00000000000..44646fda28c --- /dev/null +++ b/jetty-http/src/test/resources/multipart/browser-capture-duplicate-names-jetty-client.raw @@ -0,0 +1,51 @@ +--JettyHttpClientBoundary14beb4to333d91v8 +Content-Disposition: form-data; name="pi" +Content-Type: text/plain;charset=UTF-8 + +3.14159265358979323846264338327950288419716939937510 +--JettyHttpClientBoundary14beb4to333d91v8 +Content-Disposition: form-data; name="pi" +Content-Type: text/plain;charset=UTF-8 + +3.14159 +--JettyHttpClientBoundary14beb4to333d91v8 +Content-Disposition: form-data; name="pi" +Content-Type: text/plain;charset=UTF-8 + +3 +--JettyHttpClientBoundary14beb4to333d91v8 +Content-Disposition: form-data; name="pi" +Content-Type: text/plain;charset=UTF-8 + +π +--JettyHttpClientBoundary14beb4to333d91v8 +Content-Disposition: form-data; name="pi" +Content-Type: text/plain;charset=UTF-8 + +π +--JettyHttpClientBoundary14beb4to333d91v8 +Content-Disposition: form-data; name="pi" +Content-Type: text/plain;charset=UTF-8 + +%CF%80 +--JettyHttpClientBoundary14beb4to333d91v8 +Content-Disposition: form-data; name="pi" +Content-Type: text/plain;charset=UTF-8 + +π = C/d +--JettyHttpClientBoundary14beb4to333d91v8 +Content-Disposition: form-data; name="π" +Content-Type: text/plain;charset=UTF-8 + +3.14 +--JettyHttpClientBoundary14beb4to333d91v8 +Content-Disposition: form-data; name="%CF%80" +Content-Type: text/plain;charset=UTF-8 + +Approximately 3.14 +--JettyHttpClientBoundary14beb4to333d91v8 +Content-Disposition: form-data; name="%FE%FF%03%C0" +Content-Type: text/plain;charset=UTF-8 + +Approximately 3.14 +--JettyHttpClientBoundary14beb4to333d91v8-- diff --git a/jetty-http/src/test/resources/multipart/browser-capture-encoding-mess-apache-httpcomp.expected.txt b/jetty-http/src/test/resources/multipart/browser-capture-encoding-mess-apache-httpcomp.expected.txt new file mode 100644 index 00000000000..5769e300b10 --- /dev/null +++ b/jetty-http/src/test/resources/multipart/browser-capture-encoding-mess-apache-httpcomp.expected.txt @@ -0,0 +1,11 @@ +Request-Header|Accept-Encoding|gzip,deflate +Request-Header|Connection|keep-alive +Request-Header|Content-Length|31148 +Request-Header|Content-Type|multipart/form-data; boundary=qqr2YBBR31U4xVib4vaVuIsrwNY1iw +Request-Header|Host|localhost:9090 +Request-Header|User-Agent|Apache-HttpClient/4.5.5 (Java/1.8.0_162) +Request-Header|X-BrowserId|apache-httpcomp +Parts-Count|169 +Part-ContainsContents|count|168 +Part-ContainsContents|persian-UTF-8|برج بابل +Part-ContainsContents|persian-CESU-8|برج بابل diff --git a/jetty-http/src/test/resources/multipart/multipart-encoding-mess.raw b/jetty-http/src/test/resources/multipart/browser-capture-encoding-mess-apache-httpcomp.raw similarity index 77% rename from jetty-http/src/test/resources/multipart/multipart-encoding-mess.raw rename to jetty-http/src/test/resources/multipart/browser-capture-encoding-mess-apache-httpcomp.raw index a1348ecccf8..17948f0419e 100644 --- a/jetty-http/src/test/resources/multipart/multipart-encoding-mess.raw +++ b/jetty-http/src/test/resources/multipart/browser-capture-encoding-mess-apache-httpcomp.raw @@ -1,1009 +1,1015 @@ ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-Big5" Content-Type: text/plain; charset=Big5 Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-Big5-HKSCS" Content-Type: text/plain; charset=Big5-HKSCS Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-CESU-8" Content-Type: text/plain; charset=CESU-8 Content-Transfer-Encoding: 8bit برج بابل ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-EUC-JP" Content-Type: text/plain; charset=EUC-JP Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-EUC-KR" Content-Type: text/plain; charset=EUC-KR Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-GB18030" Content-Type: text/plain; charset=GB18030 Content-Transfer-Encoding: 8bit 101914 10191018 ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-GB2312" Content-Type: text/plain; charset=GB2312 Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-GBK" Content-Type: text/plain; charset=GBK Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-IBM-Thai" Content-Type: text/plain; charset=IBM-Thai Content-Transfer-Encoding: 8bit ???@???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-IBM00858" Content-Type: text/plain; charset=IBM00858 Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-IBM01140" Content-Type: text/plain; charset=IBM01140 Content-Transfer-Encoding: 8bit ???@???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-IBM01141" Content-Type: text/plain; charset=IBM01141 Content-Transfer-Encoding: 8bit ???@???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-IBM01142" Content-Type: text/plain; charset=IBM01142 Content-Transfer-Encoding: 8bit ???@???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-IBM01143" Content-Type: text/plain; charset=IBM01143 Content-Transfer-Encoding: 8bit ???@???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-IBM01144" Content-Type: text/plain; charset=IBM01144 Content-Transfer-Encoding: 8bit ???@???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-IBM01145" Content-Type: text/plain; charset=IBM01145 Content-Transfer-Encoding: 8bit ???@???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-IBM01146" Content-Type: text/plain; charset=IBM01146 Content-Transfer-Encoding: 8bit ???@???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-IBM01147" Content-Type: text/plain; charset=IBM01147 Content-Transfer-Encoding: 8bit ???@???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-IBM01148" Content-Type: text/plain; charset=IBM01148 Content-Transfer-Encoding: 8bit ???@???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-IBM01149" Content-Type: text/plain; charset=IBM01149 Content-Transfer-Encoding: 8bit ???@???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-IBM037" Content-Type: text/plain; charset=IBM037 Content-Transfer-Encoding: 8bit ???@???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-IBM1026" Content-Type: text/plain; charset=IBM1026 Content-Transfer-Encoding: 8bit ???@???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-IBM1047" Content-Type: text/plain; charset=IBM1047 Content-Transfer-Encoding: 8bit ???@???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-IBM273" Content-Type: text/plain; charset=IBM273 Content-Transfer-Encoding: 8bit ???@???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-IBM277" Content-Type: text/plain; charset=IBM277 Content-Transfer-Encoding: 8bit ???@???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-IBM278" Content-Type: text/plain; charset=IBM278 Content-Transfer-Encoding: 8bit ???@???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-IBM280" Content-Type: text/plain; charset=IBM280 Content-Transfer-Encoding: 8bit ???@???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-IBM284" Content-Type: text/plain; charset=IBM284 Content-Transfer-Encoding: 8bit ???@???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-IBM285" Content-Type: text/plain; charset=IBM285 Content-Transfer-Encoding: 8bit ???@???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-IBM290" Content-Type: text/plain; charset=IBM290 Content-Transfer-Encoding: 8bit ???@???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-IBM297" Content-Type: text/plain; charset=IBM297 Content-Transfer-Encoding: 8bit ???@???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-IBM420" Content-Type: text/plain; charset=IBM420 Content-Transfer-Encoding: 8bit Xug@XVX ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-IBM424" Content-Type: text/plain; charset=IBM424 Content-Transfer-Encoding: 8bit ???@???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-IBM437" Content-Type: text/plain; charset=IBM437 Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-IBM500" Content-Type: text/plain; charset=IBM500 Content-Transfer-Encoding: 8bit ???@???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-IBM775" Content-Type: text/plain; charset=IBM775 Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-IBM850" Content-Type: text/plain; charset=IBM850 Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-IBM852" Content-Type: text/plain; charset=IBM852 Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-IBM855" Content-Type: text/plain; charset=IBM855 Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-IBM857" Content-Type: text/plain; charset=IBM857 Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-IBM860" Content-Type: text/plain; charset=IBM860 Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-IBM861" Content-Type: text/plain; charset=IBM861 Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-IBM862" Content-Type: text/plain; charset=IBM862 Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-IBM863" Content-Type: text/plain; charset=IBM863 Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-IBM864" Content-Type: text/plain; charset=IBM864 Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-IBM865" Content-Type: text/plain; charset=IBM865 Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-IBM866" Content-Type: text/plain; charset=IBM866 Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-IBM868" Content-Type: text/plain; charset=IBM868 Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-IBM869" Content-Type: text/plain; charset=IBM869 Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-IBM870" Content-Type: text/plain; charset=IBM870 Content-Transfer-Encoding: 8bit ???@???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-IBM871" Content-Type: text/plain; charset=IBM871 Content-Transfer-Encoding: 8bit ???@???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-IBM918" Content-Type: text/plain; charset=IBM918 Content-Transfer-Encoding: 8bit ???@???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-ISO-2022-JP" Content-Type: text/plain; charset=ISO-2022-JP Content-Transfer-Encoding: 8bit $B!)!)!)(B $B!)!)!)!)(B ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-ISO-2022-JP-2" Content-Type: text/plain; charset=ISO-2022-JP-2 Content-Transfer-Encoding: 8bit $B!)!)!)(B $B!)!)!)!)(B ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-ISO-2022-KR" Content-Type: text/plain; charset=ISO-2022-KR Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-ISO-8859-1" Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-ISO-8859-13" Content-Type: text/plain; charset=ISO-8859-13 Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-ISO-8859-15" Content-Type: text/plain; charset=ISO-8859-15 Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-ISO-8859-2" Content-Type: text/plain; charset=ISO-8859-2 Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-ISO-8859-3" Content-Type: text/plain; charset=ISO-8859-3 Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-ISO-8859-4" Content-Type: text/plain; charset=ISO-8859-4 Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-ISO-8859-5" Content-Type: text/plain; charset=ISO-8859-5 Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-ISO-8859-6" Content-Type: text/plain; charset=ISO-8859-6 Content-Transfer-Encoding: 8bit ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-ISO-8859-7" Content-Type: text/plain; charset=ISO-8859-7 Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-ISO-8859-8" Content-Type: text/plain; charset=ISO-8859-8 Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-ISO-8859-9" Content-Type: text/plain; charset=ISO-8859-9 Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-JIS_X0201" Content-Type: text/plain; charset=JIS_X0201 Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-JIS_X0212-1990" Content-Type: text/plain; charset=JIS_X0212-1990 Content-Transfer-Encoding: 8bit "D"D"D"D"D"D"D"D ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-KOI8-R" Content-Type: text/plain; charset=KOI8-R Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-KOI8-U" Content-Type: text/plain; charset=KOI8-U Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-Shift_JIS" Content-Type: text/plain; charset=Shift_JIS Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-TIS-620" Content-Type: text/plain; charset=TIS-620 Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-US-ASCII" Content-Type: text/plain; charset=US-ASCII Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-UTF-16" Content-Type: text/plain; charset=UTF-16 Content-Transfer-Encoding: 8bit (1, ('(D ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-UTF-16BE" Content-Type: text/plain; charset=UTF-16BE Content-Transfer-Encoding: 8bit (1, ('(D ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-UTF-16LE" Content-Type: text/plain; charset=UTF-16LE Content-Transfer-Encoding: 8bit (1, ('(D ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-UTF-32" Content-Type: text/plain; charset=UTF-32 Content-Transfer-Encoding: 8bit (1, ('(D ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-UTF-32BE" Content-Type: text/plain; charset=UTF-32BE Content-Transfer-Encoding: 8bit (1, ('(D ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-UTF-32LE" Content-Type: text/plain; charset=UTF-32LE Content-Transfer-Encoding: 8bit (1, ('(D ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-UTF-8" Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit برج بابل ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-windows-1250" Content-Type: text/plain; charset=windows-1250 Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-windows-1251" Content-Type: text/plain; charset=windows-1251 Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-windows-1252" Content-Type: text/plain; charset=windows-1252 Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-windows-1253" Content-Type: text/plain; charset=windows-1253 Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-windows-1254" Content-Type: text/plain; charset=windows-1254 Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-windows-1255" Content-Type: text/plain; charset=windows-1255 Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-windows-1256" Content-Type: text/plain; charset=windows-1256 Content-Transfer-Encoding: 8bit ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-windows-1257" Content-Type: text/plain; charset=windows-1257 Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-windows-1258" Content-Type: text/plain; charset=windows-1258 Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-windows-31j" Content-Type: text/plain; charset=windows-31j Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-x-Big5-HKSCS-2001" Content-Type: text/plain; charset=x-Big5-HKSCS-2001 Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-x-Big5-Solaris" Content-Type: text/plain; charset=x-Big5-Solaris Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-x-euc-jp-linux" Content-Type: text/plain; charset=x-euc-jp-linux Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-x-EUC-TW" Content-Type: text/plain; charset=x-EUC-TW Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-x-eucJP-Open" Content-Type: text/plain; charset=x-eucJP-Open Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-x-IBM1006" Content-Type: text/plain; charset=x-IBM1006 Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-x-IBM1025" Content-Type: text/plain; charset=x-IBM1025 Content-Transfer-Encoding: 8bit ???@???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-x-IBM1046" Content-Type: text/plain; charset=x-IBM1046 Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-x-IBM1097" Content-Type: text/plain; charset=x-IBM1097 Content-Transfer-Encoding: 8bit ???@???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-x-IBM1098" Content-Type: text/plain; charset=x-IBM1098 Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-x-IBM1112" Content-Type: text/plain; charset=x-IBM1112 Content-Transfer-Encoding: 8bit ???@???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-x-IBM1122" Content-Type: text/plain; charset=x-IBM1122 Content-Transfer-Encoding: 8bit ???@???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-x-IBM1123" Content-Type: text/plain; charset=x-IBM1123 Content-Transfer-Encoding: 8bit ???@???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-x-IBM1124" Content-Type: text/plain; charset=x-IBM1124 Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-x-IBM1166" Content-Type: text/plain; charset=x-IBM1166 Content-Transfer-Encoding: 8bit ???@???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-x-IBM1364" Content-Type: text/plain; charset=x-IBM1364 Content-Transfer-Encoding: 8bit ooo@oooo ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-x-IBM1381" Content-Type: text/plain; charset=x-IBM1381 Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-x-IBM1383" Content-Type: text/plain; charset=x-IBM1383 Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-x-IBM300" Content-Type: text/plain; charset=x-IBM300 Content-Transfer-Encoding: 8bit BoBoBoBoBoBoBoBo ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-x-IBM33722" Content-Type: text/plain; charset=x-IBM33722 Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-x-IBM737" Content-Type: text/plain; charset=x-IBM737 Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-x-IBM833" Content-Type: text/plain; charset=x-IBM833 Content-Transfer-Encoding: 8bit ???@???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-x-IBM834" Content-Type: text/plain; charset=x-IBM834 Content-Transfer-Encoding: 8bit ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-x-IBM856" Content-Type: text/plain; charset=x-IBM856 Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-x-IBM874" Content-Type: text/plain; charset=x-IBM874 Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-x-IBM875" Content-Type: text/plain; charset=x-IBM875 Content-Transfer-Encoding: 8bit ???@???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-x-IBM921" Content-Type: text/plain; charset=x-IBM921 Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-x-IBM922" Content-Type: text/plain; charset=x-IBM922 Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-x-IBM930" Content-Type: text/plain; charset=x-IBM930 Content-Transfer-Encoding: 8bit ooo@oooo ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-x-IBM933" Content-Type: text/plain; charset=x-IBM933 Content-Transfer-Encoding: 8bit ooo@oooo ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-x-IBM935" Content-Type: text/plain; charset=x-IBM935 Content-Transfer-Encoding: 8bit ooo@oooo ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-x-IBM937" Content-Type: text/plain; charset=x-IBM937 Content-Transfer-Encoding: 8bit ooo@oooo ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-x-IBM939" Content-Type: text/plain; charset=x-IBM939 Content-Transfer-Encoding: 8bit ooo@oooo ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-x-IBM942" Content-Type: text/plain; charset=x-IBM942 Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-x-IBM942C" Content-Type: text/plain; charset=x-IBM942C Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-x-IBM943" Content-Type: text/plain; charset=x-IBM943 Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-x-IBM943C" Content-Type: text/plain; charset=x-IBM943C Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-x-IBM948" Content-Type: text/plain; charset=x-IBM948 Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-x-IBM949" Content-Type: text/plain; charset=x-IBM949 Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-x-IBM949C" Content-Type: text/plain; charset=x-IBM949C Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-x-IBM950" Content-Type: text/plain; charset=x-IBM950 Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-x-IBM964" Content-Type: text/plain; charset=x-IBM964 Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-x-IBM970" Content-Type: text/plain; charset=x-IBM970 Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-x-ISCII91" Content-Type: text/plain; charset=x-ISCII91 Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-x-ISO-2022-CN-CNS" Content-Type: text/plain; charset=x-ISO-2022-CN-CNS Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-x-ISO-2022-CN-GB" Content-Type: text/plain; charset=x-ISO-2022-CN-GB Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-x-iso-8859-11" Content-Type: text/plain; charset=x-iso-8859-11 Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-x-JIS0208" Content-Type: text/plain; charset=x-JIS0208 Content-Transfer-Encoding: 8bit !)!)!)!)!)!)!)!) ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-x-Johab" Content-Type: text/plain; charset=x-Johab Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-x-MacArabic" Content-Type: text/plain; charset=x-MacArabic Content-Transfer-Encoding: 8bit ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-x-MacCentralEurope" Content-Type: text/plain; charset=x-MacCentralEurope Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-x-MacCroatian" Content-Type: text/plain; charset=x-MacCroatian Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-x-MacCyrillic" Content-Type: text/plain; charset=x-MacCyrillic Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-x-MacDingbat" Content-Type: text/plain; charset=x-MacDingbat Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-x-MacGreek" Content-Type: text/plain; charset=x-MacGreek Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-x-MacHebrew" Content-Type: text/plain; charset=x-MacHebrew Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-x-MacIceland" Content-Type: text/plain; charset=x-MacIceland Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-x-MacRoman" Content-Type: text/plain; charset=x-MacRoman Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-x-MacRomania" Content-Type: text/plain; charset=x-MacRomania Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-x-MacSymbol" Content-Type: text/plain; charset=x-MacSymbol Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-x-MacThai" Content-Type: text/plain; charset=x-MacThai Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-x-MacTurkish" Content-Type: text/plain; charset=x-MacTurkish Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-x-MacUkraine" Content-Type: text/plain; charset=x-MacUkraine Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-x-MS932_0213" Content-Type: text/plain; charset=x-MS932_0213 Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-x-MS950-HKSCS" Content-Type: text/plain; charset=x-MS950-HKSCS Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-x-MS950-HKSCS-XP" Content-Type: text/plain; charset=x-MS950-HKSCS-XP Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-x-mswin-936" Content-Type: text/plain; charset=x-mswin-936 Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-x-PCK" Content-Type: text/plain; charset=x-PCK Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-x-SJIS_0213" Content-Type: text/plain; charset=x-SJIS_0213 Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-x-UTF-16LE-BOM" Content-Type: text/plain; charset=x-UTF-16LE-BOM Content-Transfer-Encoding: 8bit (1, ('(D ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-X-UTF-32BE-BOM" Content-Type: text/plain; charset=X-UTF-32BE-BOM Content-Transfer-Encoding: 8bit (1, ('(D ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-X-UTF-32LE-BOM" Content-Type: text/plain; charset=X-UTF-32LE-BOM Content-Transfer-Encoding: 8bit (1, ('(D ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-x-windows-50220" Content-Type: text/plain; charset=x-windows-50220 Content-Transfer-Encoding: 8bit $B!)!)!)(B $B!)!)!)!)(B ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-x-windows-50221" Content-Type: text/plain; charset=x-windows-50221 Content-Transfer-Encoding: 8bit $B!)!)!)(B $B!)!)!)!)(B ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-x-windows-874" Content-Type: text/plain; charset=x-windows-874 Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-x-windows-949" Content-Type: text/plain; charset=x-windows-949 Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-x-windows-950" Content-Type: text/plain; charset=x-windows-950 Content-Transfer-Encoding: 8bit ??? ???? ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw Content-Disposition: form-data; name="persian-x-windows-iso2022jp" Content-Type: text/plain; charset=x-windows-iso2022jp Content-Transfer-Encoding: 8bit $B!)!)!)(B $B!)!)!)!)(B ---CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl-- +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw +Content-Disposition: form-data; name="count" +Content-Type: text/plain; charset=ISO-8859-1 +Content-Transfer-Encoding: 8bit + +168 +--qqr2YBBR31U4xVib4vaVuIsrwNY1iw-- diff --git a/jetty-http/src/test/resources/multipart/browser-capture-encoding-mess-jetty-client.expected.txt b/jetty-http/src/test/resources/multipart/browser-capture-encoding-mess-jetty-client.expected.txt new file mode 100644 index 00000000000..473743d99e6 --- /dev/null +++ b/jetty-http/src/test/resources/multipart/browser-capture-encoding-mess-jetty-client.expected.txt @@ -0,0 +1,11 @@ +Request-Header|Accept-Encoding|gzip +Request-Header|Connection|close +Request-Header|Content-Type|multipart/form-data; boundary=JettyHttpClientBoundary1jcfdl0zps9nf362 +Request-Header|Host|localhost:9090 +Request-Header|Transfer-Encoding|chunked +Request-Header|User-Agent|Jetty/9.4.9.v20180320 +Request-Header|X-BrowserId|jetty-client +Parts-Count|169 +Part-ContainsContents|count|168 +Part-ContainsContents|persian-UTF-8|برج بابل +Part-ContainsContents|persian-CESU-8|برج بابل diff --git a/jetty-http/src/test/resources/multipart/browser-capture-encoding-mess-jetty-client.raw b/jetty-http/src/test/resources/multipart/browser-capture-encoding-mess-jetty-client.raw new file mode 100644 index 00000000000..7f374670a10 --- /dev/null +++ b/jetty-http/src/test/resources/multipart/browser-capture-encoding-mess-jetty-client.raw @@ -0,0 +1,846 @@ +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-Big5" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-Big5-HKSCS" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-CESU-8" +Content-Type: text/plain + +برج بابل +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-EUC-JP" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-EUC-KR" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-GB18030" +Content-Type: text/plain + +101914 10191018 +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-GB2312" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-GBK" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-IBM-Thai" +Content-Type: text/plain + +???@???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-IBM00858" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-IBM01140" +Content-Type: text/plain + +???@???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-IBM01141" +Content-Type: text/plain + +???@???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-IBM01142" +Content-Type: text/plain + +???@???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-IBM01143" +Content-Type: text/plain + +???@???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-IBM01144" +Content-Type: text/plain + +???@???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-IBM01145" +Content-Type: text/plain + +???@???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-IBM01146" +Content-Type: text/plain + +???@???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-IBM01147" +Content-Type: text/plain + +???@???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-IBM01148" +Content-Type: text/plain + +???@???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-IBM01149" +Content-Type: text/plain + +???@???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-IBM037" +Content-Type: text/plain + +???@???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-IBM1026" +Content-Type: text/plain + +???@???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-IBM1047" +Content-Type: text/plain + +???@???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-IBM273" +Content-Type: text/plain + +???@???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-IBM277" +Content-Type: text/plain + +???@???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-IBM278" +Content-Type: text/plain + +???@???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-IBM280" +Content-Type: text/plain + +???@???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-IBM284" +Content-Type: text/plain + +???@???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-IBM285" +Content-Type: text/plain + +???@???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-IBM290" +Content-Type: text/plain + +???@???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-IBM297" +Content-Type: text/plain + +???@???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-IBM420" +Content-Type: text/plain + +Xug@XVX +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-IBM424" +Content-Type: text/plain + +???@???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-IBM437" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-IBM500" +Content-Type: text/plain + +???@???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-IBM775" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-IBM850" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-IBM852" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-IBM855" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-IBM857" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-IBM860" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-IBM861" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-IBM862" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-IBM863" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-IBM864" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-IBM865" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-IBM866" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-IBM868" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-IBM869" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-IBM870" +Content-Type: text/plain + +???@???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-IBM871" +Content-Type: text/plain + +???@???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-IBM918" +Content-Type: text/plain + +???@???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-ISO-2022-JP" +Content-Type: text/plain + +$B!)!)!)(B $B!)!)!)!)(B +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-ISO-2022-JP-2" +Content-Type: text/plain + +$B!)!)!)(B $B!)!)!)!)(B +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-ISO-2022-KR" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-ISO-8859-1" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-ISO-8859-13" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-ISO-8859-15" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-ISO-8859-2" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-ISO-8859-3" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-ISO-8859-4" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-ISO-8859-5" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-ISO-8859-6" +Content-Type: text/plain + + +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-ISO-8859-7" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-ISO-8859-8" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-ISO-8859-9" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-JIS_X0201" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-JIS_X0212-1990" +Content-Type: text/plain + +"D"D"D"D"D"D"D"D +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-KOI8-R" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-KOI8-U" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-Shift_JIS" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-TIS-620" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-US-ASCII" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-UTF-16" +Content-Type: text/plain + +(1, ('(D +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-UTF-16BE" +Content-Type: text/plain + +(1, ('(D +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-UTF-16LE" +Content-Type: text/plain + +(1, ('(D +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-UTF-32" +Content-Type: text/plain + +(1, ('(D +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-UTF-32BE" +Content-Type: text/plain + +(1, ('(D +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-UTF-32LE" +Content-Type: text/plain + +(1, ('(D +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-UTF-8" +Content-Type: text/plain + +برج بابل +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-windows-1250" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-windows-1251" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-windows-1252" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-windows-1253" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-windows-1254" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-windows-1255" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-windows-1256" +Content-Type: text/plain + + +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-windows-1257" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-windows-1258" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-windows-31j" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-x-Big5-HKSCS-2001" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-x-Big5-Solaris" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-x-euc-jp-linux" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-x-EUC-TW" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-x-eucJP-Open" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-x-IBM1006" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-x-IBM1025" +Content-Type: text/plain + +???@???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-x-IBM1046" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-x-IBM1097" +Content-Type: text/plain + +???@???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-x-IBM1098" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-x-IBM1112" +Content-Type: text/plain + +???@???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-x-IBM1122" +Content-Type: text/plain + +???@???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-x-IBM1123" +Content-Type: text/plain + +???@???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-x-IBM1124" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-x-IBM1166" +Content-Type: text/plain + +???@???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-x-IBM1364" +Content-Type: text/plain + +ooo@oooo +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-x-IBM1381" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-x-IBM1383" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-x-IBM300" +Content-Type: text/plain + +BoBoBoBoBoBoBoBo +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-x-IBM33722" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-x-IBM737" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-x-IBM833" +Content-Type: text/plain + +???@???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-x-IBM834" +Content-Type: text/plain + + +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-x-IBM856" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-x-IBM874" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-x-IBM875" +Content-Type: text/plain + +???@???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-x-IBM921" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-x-IBM922" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-x-IBM930" +Content-Type: text/plain + +ooo@oooo +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-x-IBM933" +Content-Type: text/plain + +ooo@oooo +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-x-IBM935" +Content-Type: text/plain + +ooo@oooo +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-x-IBM937" +Content-Type: text/plain + +ooo@oooo +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-x-IBM939" +Content-Type: text/plain + +ooo@oooo +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-x-IBM942" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-x-IBM942C" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-x-IBM943" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-x-IBM943C" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-x-IBM948" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-x-IBM949" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-x-IBM949C" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-x-IBM950" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-x-IBM964" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-x-IBM970" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-x-ISCII91" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-x-ISO-2022-CN-CNS" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-x-ISO-2022-CN-GB" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-x-iso-8859-11" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-x-JIS0208" +Content-Type: text/plain + +!)!)!)!)!)!)!)!) +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-x-Johab" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-x-MacArabic" +Content-Type: text/plain + + +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-x-MacCentralEurope" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-x-MacCroatian" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-x-MacCyrillic" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-x-MacDingbat" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-x-MacGreek" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-x-MacHebrew" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-x-MacIceland" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-x-MacRoman" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-x-MacRomania" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-x-MacSymbol" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-x-MacThai" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-x-MacTurkish" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-x-MacUkraine" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-x-MS932_0213" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-x-MS950-HKSCS" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-x-MS950-HKSCS-XP" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-x-mswin-936" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-x-PCK" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-x-SJIS_0213" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-x-UTF-16LE-BOM" +Content-Type: text/plain + +(1, ('(D +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-X-UTF-32BE-BOM" +Content-Type: text/plain + +(1, ('(D +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-X-UTF-32LE-BOM" +Content-Type: text/plain + +(1, ('(D +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-x-windows-50220" +Content-Type: text/plain + +$B!)!)!)(B $B!)!)!)!)(B +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-x-windows-50221" +Content-Type: text/plain + +$B!)!)!)(B $B!)!)!)!)(B +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-x-windows-874" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-x-windows-949" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-x-windows-950" +Content-Type: text/plain + +??? ???? +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="persian-x-windows-iso2022jp" +Content-Type: text/plain + +$B!)!)!)(B $B!)!)!)!)(B +--JettyHttpClientBoundary1jcfdl0zps9nf362 +Content-Disposition: form-data; name="count" +Content-Type: text/plain;charset=UTF-8 + +168 +--JettyHttpClientBoundary1jcfdl0zps9nf362-- diff --git a/jetty-http/src/test/resources/multipart/browser-capture-form-fileupload-alt-ios-safari.expected.txt b/jetty-http/src/test/resources/multipart/browser-capture-form-fileupload-alt-ios-safari.expected.txt deleted file mode 100644 index a235dfb9fee..00000000000 --- a/jetty-http/src/test/resources/multipart/browser-capture-form-fileupload-alt-ios-safari.expected.txt +++ /dev/null @@ -1,18 +0,0 @@ -Request-Header|Accept|text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 -Request-Header|Accept-Encoding|gzip, deflate -Request-Header|Accept-Language|en-us -Request-Header|Connection|keep-alive -Request-Header|Content-Length|22359 -Request-Header|Content-Type|multipart/form-data; boundary=----WebKitFormBoundaryb59mxzeFXckWXDD0 -Request-Header|Host|192.168.0.119:9090 -Request-Header|Origin|http://192.168.0.119:9090 -Request-Header|Referer|http://192.168.0.119:9090/form-fileupload-multi.html -Request-Header|Upgrade-Insecure-Requests|1 -Request-Header|User-Agent|Mozilla/5.0 (iPad; CPU OS 11_2_6 like Mac OS X) AppleWebKit/604.5.6 (KHTML, like Gecko) Version/11.0 Mobile/15D100 Safari/604.1 -Parts-Count|4 -Part-ContainsContents|description|the larger icon -Part-ContainsContents|alternate|Text.raw -Part-Filename|file|36037FD9-841C-4803-AA7E-354EF727AA06.png -Part-Sha1sum|file|e75b73644afe9b234d70da9ff225229de68cdff8 -Part-Filename|file-alt|Text File.txt -Part-Sha1sum|file-alt|5fb031816a27d80cc88c390819addab0ec3c189b diff --git a/jetty-http/src/test/resources/multipart/browser-capture-nested-apache-httpcomp.expected.txt b/jetty-http/src/test/resources/multipart/browser-capture-nested-apache-httpcomp.expected.txt new file mode 100644 index 00000000000..fc44839cac2 --- /dev/null +++ b/jetty-http/src/test/resources/multipart/browser-capture-nested-apache-httpcomp.expected.txt @@ -0,0 +1,12 @@ +Request-Header|Accept-Encoding|gzip,deflate +Request-Header|Connection|keep-alive +Request-Header|Content-Length|1203 +Request-Header|Content-Type|multipart/form-data; boundary=Cku4UvJrPFCXkXjge2a2Y2sgq1bbOa +Request-Header|Host|localhost:9090 +Request-Header|User-Agent|Apache-HttpClient/4.5.5 (Java/1.8.0_162) +Request-Header|X-BrowserId|apache-httpcomp +Parts-Count|4 +Part-ContainsContents|reporter| +Part-ContainsContents|timestamp|2018-03-21T18:52:18+00:00 +Part-ContainsContents|comments|this couldn't be parsed +Part-ContainsContents|attachment|banana \ No newline at end of file diff --git a/jetty-http/src/test/resources/multipart/multipart-inside-itself.raw b/jetty-http/src/test/resources/multipart/browser-capture-nested-apache-httpcomp.raw similarity index 52% rename from jetty-http/src/test/resources/multipart/multipart-inside-itself.raw rename to jetty-http/src/test/resources/multipart/browser-capture-nested-apache-httpcomp.raw index 9157af95046..12ce1761a03 100644 --- a/jetty-http/src/test/resources/multipart/multipart-inside-itself.raw +++ b/jetty-http/src/test/resources/multipart/browser-capture-nested-apache-httpcomp.raw @@ -1,42 +1,42 @@ ---kCFSwstIsIZkZtQ5JM7193kJYcK5WkyvoxsGjx5eCuVFbaeUZ9oK57JCp_p5wP86S5nY4re5x +--Cku4UvJrPFCXkXjge2a2Y2sgq1bbOa Content-Disposition: form-data; name="reporter" Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 8bit ---kCFSwstIsIZkZtQ5JM7193kJYcK5WkyvoxsGjx5eCuVFbaeUZ9oK57JCp_p5wP86S5nY4re5x +--Cku4UvJrPFCXkXjge2a2Y2sgq1bbOa Content-Disposition: form-data; name="timestamp" Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 8bit 2018-03-21T18:52:18+00:00 ---kCFSwstIsIZkZtQ5JM7193kJYcK5WkyvoxsGjx5eCuVFbaeUZ9oK57JCp_p5wP86S5nY4re5x +--Cku4UvJrPFCXkXjge2a2Y2sgq1bbOa Content-Disposition: form-data; name="comments" Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 8bit this couldn't be parsed ---kCFSwstIsIZkZtQ5JM7193kJYcK5WkyvoxsGjx5eCuVFbaeUZ9oK57JCp_p5wP86S5nY4re5x +--Cku4UvJrPFCXkXjge2a2Y2sgq1bbOa Content-Disposition: form-data; name="attachment" Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 8bit ---kCFSwstIsIZkZtQ5JM7193kJYcK5WkyvoxsGj +--nM8_n8ugj9L3fIomqyU6h9Wpb6Wt-3w Content-Disposition: form-data; name="fruit" banana ---kCFSwstIsIZkZtQ5JM7193kJYcK5WkyvoxsGj +--nM8_n8ugj9L3fIomqyU6h9Wpb6Wt-3w Content-Disposition: form-data; name="color" yellow ---kCFSwstIsIZkZtQ5JM7193kJYcK5WkyvoxsGj +--nM8_n8ugj9L3fIomqyU6h9Wpb6Wt-3w Content-Disposition: form-data; name="cost" $0.12 USG ---kCFSwstIsIZkZtQ5JM7193kJYcK5WkyvoxsGj +--nM8_n8ugj9L3fIomqyU6h9Wpb6Wt-3w Content-Disposition: form-data; name="comments" ---kCFSwstIsIZkZtQ5JM7193kJYcK5WkyvoxsGjx5eCuVFbaeUZ9oK57JCp_p5wP86S5nY4re5x ---kCFSwstIsIZkZtQ5JM7193kJYcK5WkyvoxsGj-- +--divc688gD49-GaZcLkprfUb8-PWOjF3Z +--nM8_n8ugj9L3fIomqyU6h9Wpb6Wt-3w-- ---kCFSwstIsIZkZtQ5JM7193kJYcK5WkyvoxsGjx5eCuVFbaeUZ9oK57JCp_p5wP86S5nY4re5x-- +--Cku4UvJrPFCXkXjge2a2Y2sgq1bbOa-- diff --git a/jetty-http/src/test/resources/multipart/browser-capture-nested-binary-apache-httpcomp.expected.txt b/jetty-http/src/test/resources/multipart/browser-capture-nested-binary-apache-httpcomp.expected.txt new file mode 100644 index 00000000000..12e9da8703e --- /dev/null +++ b/jetty-http/src/test/resources/multipart/browser-capture-nested-binary-apache-httpcomp.expected.txt @@ -0,0 +1,12 @@ +Request-Header|Accept-Encoding|gzip,deflate +Request-Header|Connection|keep-alive +Request-Header|Content-Length|1577 +Request-Header|Content-Type|multipart/form-data; boundary=xDeLGHDDsXrlJSXfqDmg5IRop7auqTTBXuI +Request-Header|Host|localhost:9090 +Request-Header|User-Agent|Apache-HttpClient/4.5.5 (Java/1.8.0_162) +Request-Header|X-BrowserId|apache-httpcomp +Parts-Count|4 +Part-ContainsContents|reporter| +Part-ContainsContents|timestamp|2018-03-21T19:00:18+00:00 +Part-ContainsContents|comments|this also couldn't be parsed +Part-ContainsContents|attachment|cherry \ No newline at end of file diff --git a/jetty-http/src/test/resources/multipart/multipart-inside-itself-binary.raw b/jetty-http/src/test/resources/multipart/browser-capture-nested-binary-apache-httpcomp.raw similarity index 59% rename from jetty-http/src/test/resources/multipart/multipart-inside-itself-binary.raw rename to jetty-http/src/test/resources/multipart/browser-capture-nested-binary-apache-httpcomp.raw index 200235e6d3b..bf8c06a969d 100644 --- a/jetty-http/src/test/resources/multipart/multipart-inside-itself-binary.raw +++ b/jetty-http/src/test/resources/multipart/browser-capture-nested-binary-apache-httpcomp.raw @@ -1,50 +1,50 @@ ---94GJ2MW4vpjh92qj-CHjUUIwb9X8Y2LqkU2Yxn0vTU2oHy5jk6_Kpxn2aE9EokEiRGox4eWfAYP8- +--xDeLGHDDsXrlJSXfqDmg5IRop7auqTTBXuI Content-Disposition: form-data; name="reporter" Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 8bit ---94GJ2MW4vpjh92qj-CHjUUIwb9X8Y2LqkU2Yxn0vTU2oHy5jk6_Kpxn2aE9EokEiRGox4eWfAYP8- +--xDeLGHDDsXrlJSXfqDmg5IRop7auqTTBXuI Content-Disposition: form-data; name="timestamp" Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 8bit 2018-03-21T19:00:18+00:00 ---94GJ2MW4vpjh92qj-CHjUUIwb9X8Y2LqkU2Yxn0vTU2oHy5jk6_Kpxn2aE9EokEiRGox4eWfAYP8- +--xDeLGHDDsXrlJSXfqDmg5IRop7auqTTBXuI Content-Disposition: form-data; name="comments" Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 8bit this also couldn't be parsed ---94GJ2MW4vpjh92qj-CHjUUIwb9X8Y2LqkU2Yxn0vTU2oHy5jk6_Kpxn2aE9EokEiRGox4eWfAYP8- +--xDeLGHDDsXrlJSXfqDmg5IRop7auqTTBXuI Content-Disposition: form-data; name="attachment" Content-Type: application/octet-stream Content-Transfer-Encoding: binary ---94GJ2MW4vpjh92qj-CHjUUIwb9X8Y2LqkU2Yxn0v +--GiQ7DQPSJdaP5c43_Zd1P6xVJTQVLzZ8T9ovx Content-Disposition: form-data; name="fruit" Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 8bit cherry ---94GJ2MW4vpjh92qj-CHjUUIwb9X8Y2LqkU2Yxn0v +--GiQ7DQPSJdaP5c43_Zd1P6xVJTQVLzZ8T9ovx Content-Disposition: form-data; name="color" Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 8bit red ---94GJ2MW4vpjh92qj-CHjUUIwb9X8Y2LqkU2Yxn0v +--GiQ7DQPSJdaP5c43_Zd1P6xVJTQVLzZ8T9ovx Content-Disposition: form-data; name="cost" Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 8bit $1.20 USG ---94GJ2MW4vpjh92qj-CHjUUIwb9X8Y2LqkU2Yxn0v +--GiQ7DQPSJdaP5c43_Zd1P6xVJTQVLzZ8T9ovx Content-Disposition: form-data; name="comments" Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 8bit ---94GJ2MW4vpjh92qj-CHjUUIwb9X8Y2LqkU2Yxn0vTU2oHy5jk6_Kpxn2aE9EokEiRGox4eWfAYP8- ---94GJ2MW4vpjh92qj-CHjUUIwb9X8Y2LqkU2Yxn0v-- +--gq4lBOlNh8FRiH6MLw4GaWE40UC-GeDRTy8bF +--GiQ7DQPSJdaP5c43_Zd1P6xVJTQVLzZ8T9ovx-- ---94GJ2MW4vpjh92qj-CHjUUIwb9X8Y2LqkU2Yxn0vTU2oHy5jk6_Kpxn2aE9EokEiRGox4eWfAYP8--- +--xDeLGHDDsXrlJSXfqDmg5IRop7auqTTBXuI-- diff --git a/jetty-http/src/test/resources/multipart/browser-capture-nested-jetty-client.expected.txt b/jetty-http/src/test/resources/multipart/browser-capture-nested-jetty-client.expected.txt new file mode 100644 index 00000000000..294f1eefd47 --- /dev/null +++ b/jetty-http/src/test/resources/multipart/browser-capture-nested-jetty-client.expected.txt @@ -0,0 +1,12 @@ +Request-Header|Accept-Encoding|gzip +Request-Header|Connection|close +Request-Header|Content-Type|multipart/form-data; boundary=JettyHttpClientBoundary1uz60vid2bq7x1t9 +Request-Header|Host|localhost:9090 +Request-Header|Transfer-Encoding|chunked +Request-Header|User-Agent|Jetty/9.4.9.v20180320 +Request-Header|X-BrowserId|jetty-client +Parts-Count|4 +Part-ContainsContents|reporter| +Part-ContainsContents|timestamp|2018-03-21T18:52:18+00:00 +Part-ContainsContents|comments|this couldn't be parsed +Part-ContainsContents|attachment|banana \ No newline at end of file diff --git a/jetty-http/src/test/resources/multipart/browser-capture-nested-jetty-client.raw b/jetty-http/src/test/resources/multipart/browser-capture-nested-jetty-client.raw new file mode 100644 index 00000000000..38f849cc89b --- /dev/null +++ b/jetty-http/src/test/resources/multipart/browser-capture-nested-jetty-client.raw @@ -0,0 +1,42 @@ +--JettyHttpClientBoundary1uz60vid2bq7x1t9 +Content-Disposition: form-data; name="reporter" +Content-Type: text/plain;charset=UTF-8 + + +--JettyHttpClientBoundary1uz60vid2bq7x1t9 +Content-Disposition: form-data; name="timestamp" +Content-Type: text/plain;charset=UTF-8 + +2018-03-21T18:52:18+00:00 +--JettyHttpClientBoundary1uz60vid2bq7x1t9 +Content-Disposition: form-data; name="comments" +Content-Type: text/plain;charset=UTF-8 + +this couldn't be parsed +--JettyHttpClientBoundary1uz60vid2bq7x1t9 +Content-Disposition: form-data; name="attachment"; filename="sample" +Content-Type: multipart/form-data; boundary=JettyHttpClientBoundary10bb1gdlzug0xmmi + +--JettyHttpClientBoundary10bb1gdlzug0xmmi +Content-Disposition: form-data; name="fruit" +Content-Type: text/plain;charset=UTF-8 + +banana +--JettyHttpClientBoundary10bb1gdlzug0xmmi +Content-Disposition: form-data; name="color" +Content-Type: text/plain;charset=UTF-8 + +yellow +--JettyHttpClientBoundary10bb1gdlzug0xmmi +Content-Disposition: form-data; name="cost" +Content-Type: text/plain;charset=UTF-8 + +$0.12 USD +--JettyHttpClientBoundary10bb1gdlzug0xmmi +Content-Disposition: form-data; name="comments" +Content-Type: text/plain;charset=UTF-8 + +--gx1KGV2f8WMHHwtWog9AFqjD3IGHzEvk +--JettyHttpClientBoundary10bb1gdlzug0xmmi-- + +--JettyHttpClientBoundary1uz60vid2bq7x1t9-- diff --git a/jetty-http/src/test/resources/multipart/browser-capture-number-only-apache-httpcomp.expected.txt b/jetty-http/src/test/resources/multipart/browser-capture-number-only-apache-httpcomp.expected.txt new file mode 100644 index 00000000000..e090188dbfd --- /dev/null +++ b/jetty-http/src/test/resources/multipart/browser-capture-number-only-apache-httpcomp.expected.txt @@ -0,0 +1,9 @@ +Request-Header|Accept-Encoding|gzip,deflate +Request-Header|Connection|keep-alive +Request-Header|Content-Length|173 +Request-Header|Content-Type|multipart/form-data; boundary=xE8WoYDcbqAfj08bxPk669iK22hMMlZL +Request-Header|Host|localhost:9090 +Request-Header|User-Agent|Apache-HttpClient/4.5.5 (Java/1.8.0_162) +Request-Header|X-BrowserId|apache-httpcomp +Parts-Count|1 +Part-ContainsContents|pi|3.14159265358979323846264338327950288419716939937510 diff --git a/jetty-http/src/test/resources/multipart/multipart-number-browser.raw b/jetty-http/src/test/resources/multipart/browser-capture-number-only-apache-httpcomp.raw similarity index 51% rename from jetty-http/src/test/resources/multipart/multipart-number-browser.raw rename to jetty-http/src/test/resources/multipart/browser-capture-number-only-apache-httpcomp.raw index 11776ddfb78..0af35a6be1f 100644 --- a/jetty-http/src/test/resources/multipart/multipart-number-browser.raw +++ b/jetty-http/src/test/resources/multipart/browser-capture-number-only-apache-httpcomp.raw @@ -1,5 +1,5 @@ ---RjYiyHVV9Phv7tYylzT1f94fvTC-s7oNKwB9_Y +--xE8WoYDcbqAfj08bxPk669iK22hMMlZL Content-Disposition: form-data; name="pi" 3.14159265358979323846264338327950288419716939937510 ---RjYiyHVV9Phv7tYylzT1f94fvTC-s7oNKwB9_Y-- +--xE8WoYDcbqAfj08bxPk669iK22hMMlZL-- diff --git a/jetty-http/src/test/resources/multipart/browser-capture-number-only-jetty-client.expected.txt b/jetty-http/src/test/resources/multipart/browser-capture-number-only-jetty-client.expected.txt new file mode 100644 index 00000000000..a9f21f2f65f --- /dev/null +++ b/jetty-http/src/test/resources/multipart/browser-capture-number-only-jetty-client.expected.txt @@ -0,0 +1,12 @@ +Request-Header|Accept-Encoding|gzip +Request-Header|Connection|close +Request-Header|Content-Type|multipart/form-data; boundary=JettyHttpClientBoundary1shlqpw2yahae6jf +Request-Header|Host|localhost:9090 +Request-Header|Transfer-Encoding|chunked +Request-Header|User-Agent|Jetty/9.4.9.v20180320 +Request-Header|X-BrowserId|jetty-client +Parts-Count|1 +# Start of sequence +Part-ContainsContents|pi|3.14159 26535 89793 23846 26433 83279 50288 +# End of sequence +Part-ContainsContents|pi|81592 05600 10165 52563 7567 diff --git a/jetty-http/src/test/resources/multipart/browser-capture-number-only-jetty-client.raw b/jetty-http/src/test/resources/multipart/browser-capture-number-only-jetty-client.raw new file mode 100644 index 00000000000..ab78f173b7c --- /dev/null +++ b/jetty-http/src/test/resources/multipart/browser-capture-number-only-jetty-client.raw @@ -0,0 +1,6 @@ +--JettyHttpClientBoundary1shlqpw2yahae6jf +Content-Disposition: form-data; name="pi" +Content-Type: application/octet-stream + +3.14159 26535 89793 23846 26433 83279 50288 41971 69399 37510 58209 74944 59230 78164 06286 20899 86280 34825 34211 70679 82148 08651 32823 06647 09384 46095 50582 23172 53594 08128 48111 74502 84102 70193 85211 05559 64462 29489 54930 38196 44288 10975 66593 34461 28475 64823 37867 83165 27120 19091 45648 56692 34603 48610 45432 66482 13393 60726 02491 41273 72458 70066 06315 58817 48815 20920 96282 92540 91715 36436 78925 90360 01133 05305 48820 46652 13841 46951 94151 16094 33057 27036 57595 91953 09218 61173 81932 61179 31051 18548 07446 23799 62749 56735 18857 52724 89122 79381 83011 94912 98336 73362 44065 66430 86021 39494 63952 24737 19070 21798 60943 70277 05392 17176 29317 67523 84674 81846 76694 05132 00056 81271 45263 56082 77857 71342 75778 96091 73637 17872 14684 40901 22495 34301 46549 58537 10507 92279 68925 89235 42019 95611 21290 21960 86403 44181 59813 62977 47713 09960 51870 72113 49999 99837 29780 49951 05973 17328 16096 31859 50244 59455 34690 83026 42522 30825 33446 85035 26193 11881 71010 00313 78387 52886 58753 32083 81420 61717 76691 47303 59825 34904 28755 46873 11595 62863 88235 37875 93751 95778 18577 80532 17122 68066 13001 92787 66111 95909 21642 01989 38095 25720 10654 85863 27886 59361 53381 82796 82303 01952 03530 18529 68995 77362 25994 13891 24972 17752 83479 13151 55748 57242 45415 06959 50829 53311 68617 27855 88907 50983 81754 63746 49393 19255 06040 09277 01671 13900 98488 24012 85836 16035 63707 66010 47101 81942 95559 61989 46767 83744 94482 55379 77472 68471 04047 53464 62080 46684 25906 94912 93313 67702 89891 52104 75216 20569 66024 05803 81501 93511 25338 24300 35587 64024 74964 73263 91419 92726 04269 92279 67823 54781 63600 93417 21641 21992 45863 15030 28618 29745 55706 74983 85054 94588 58692 69956 90927 21079 75093 02955 32116 53449 87202 75596 02364 80665 49911 98818 34797 75356 63698 07426 54252 78625 51818 41757 46728 90977 77279 38000 81647 06001 61452 49192 17321 72147 72350 14144 19735 68548 16136 11573 52552 13347 57418 49468 43852 33239 07394 14333 45477 62416 86251 89835 69485 56209 92192 22184 27255 02542 56887 67179 04946 01653 46680 49886 27232 79178 60857 84383 82796 79766 81454 10095 38837 86360 95068 00642 25125 20511 73929 84896 08412 84886 26945 60424 19652 85022 21066 11863 06744 27862 20391 94945 04712 37137 86960 95636 43719 17287 46776 46575 73962 41389 08658 32645 99581 33904 78027 59009 94657 64078 95126 94683 98352 59570 98258 22620 52248 94077 26719 47826 84826 01476 99090 26401 36394 43745 53050 68203 49625 24517 49399 65143 14298 09190 65925 09372 21696 46151 57098 58387 41059 78859 59772 97549 89301 61753 92846 81382 68683 86894 27741 55991 85592 52459 53959 43104 99725 24680 84598 72736 44695 84865 38367 36222 62609 91246 08051 24388 43904 51244 13654 97627 80797 71569 14359 97700 12961 60894 41694 86855 58484 06353 42207 22258 28488 64815 84560 28506 01684 27394 52267 46767 88952 52138 52254 99546 66727 82398 64565 96116 35488 62305 77456 49803 55936 34568 17432 41125 15076 06947 94510 96596 09402 52288 79710 89314 56691 36867 22874 89405 60101 50330 86179 28680 92087 47609 17824 93858 90097 14909 67598 52613 65549 78189 31297 84821 68299 89487 22658 80485 75640 14270 47755 51323 79641 45152 37462 34364 54285 84447 95265 86782 10511 41354 73573 95231 13427 16610 21359 69536 23144 29524 84937 18711 01457 65403 59027 99344 03742 00731 05785 39062 19838 74478 08478 48968 33214 45713 86875 19435 06430 21845 31910 48481 00537 06146 80674 91927 81911 97939 95206 14196 63428 75444 06437 45123 71819 21799 98391 01591 95618 14675 14269 12397 48940 90718 64942 31961 56794 52080 95146 55022 52316 03881 93014 20937 62137 85595 66389 37787 08303 90697 92077 34672 21825 62599 66150 14215 03068 03844 77345 49202 60541 46659 25201 49744 28507 32518 66600 21324 34088 19071 04863 31734 64965 14539 05796 26856 10055 08106 65879 69981 63574 73638 40525 71459 10289 70641 40110 97120 62804 39039 75951 56771 57700 42033 78699 36007 23055 87631 76359 42187 31251 47120 53292 81918 26186 12586 73215 79198 41484 88291 64470 60957 52706 95722 09175 67116 72291 09816 90915 28017 35067 12748 58322 28718 35209 35396 57251 21083 57915 13698 82091 44421 00675 10334 67110 31412 67111 36990 86585 16398 31501 97016 51511 68517 14376 57618 35155 65088 49099 89859 98238 73455 28331 63550 76479 18535 89322 61854 89632 13293 30898 57064 20467 52590 70915 48141 65498 59461 63718 02709 81994 30992 44889 57571 28289 05923 23326 09729 97120 84433 57326 54893 82391 19325 97463 66730 58360 41428 13883 03203 82490 37589 85243 74417 02913 27656 18093 77344 40307 07469 21120 19130 20330 38019 76211 01100 44929 32151 60842 44485 96376 69838 95228 68478 31235 52658 21314 49576 85726 24334 41893 03968 64262 43410 77322 69780 28073 18915 44110 10446 82325 27162 01052 65227 21116 60396 66557 30925 47110 55785 37634 66820 65310 98965 26918 62056 47693 12570 58635 66201 85581 00729 36065 98764 86117 91045 33488 50346 11365 76867 53249 44166 80396 26579 78771 85560 84552 96541 26654 08530 61434 44318 58676 97514 56614 06800 70023 78776 59134 40171 27494 70420 56223 05389 94561 31407 11270 00407 85473 32699 39081 45466 46458 80797 27082 66830 63432 85878 56983 05235 80893 30657 57406 79545 71637 75254 20211 49557 61581 40025 01262 28594 13021 64715 50979 25923 09907 96547 37612 55176 56751 35751 78296 66454 77917 45011 29961 48903 04639 94713 29621 07340 43751 89573 59614 58901 93897 13111 79042 97828 56475 03203 19869 15140 28708 08599 04801 09412 14722 13179 47647 77262 24142 54854 54033 21571 85306 14228 81375 85043 06332 17518 29798 66223 71721 59160 77166 92547 48738 98665 49494 50114 65406 28433 66393 79003 97692 65672 14638 53067 36096 57120 91807 63832 71664 16274 88880 07869 25602 90228 47210 40317 21186 08204 19000 42296 61711 96377 92133 75751 14959 50156 60496 31862 94726 54736 42523 08177 03675 15906 73502 35072 83540 56704 03867 43513 62222 47715 89150 49530 98444 89333 09634 08780 76932 59939 78054 19341 44737 74418 42631 29860 80998 88687 41326 04721 56951 62396 58645 73021 63159 81931 95167 35381 29741 67729 47867 24229 24654 36680 09806 76928 23828 06899 64004 82435 40370 14163 14965 89794 09243 23789 69070 69779 42236 25082 21688 95738 37986 23001 59377 64716 51228 93578 60158 81617 55782 97352 33446 04281 51262 72037 34314 65319 77774 16031 99066 55418 76397 92933 44195 21541 34189 94854 44734 56738 31624 99341 91318 14809 27777 10386 38773 43177 20754 56545 32207 77092 12019 05166 09628 04909 26360 19759 88281 61332 31666 36528 61932 66863 36062 73567 63035 44776 28035 04507 77235 54710 58595 48702 79081 43562 40145 17180 62464 36267 94561 27531 81340 78330 33625 42327 83944 97538 24372 05835 31147 71199 26063 81334 67768 79695 97030 98339 13077 10987 04085 91337 46414 42822 77263 46594 70474 58784 77872 01927 71528 07317 67907 70715 72134 44730 60570 07334 92436 93113 83504 93163 12840 42512 19256 51798 06941 13528 01314 70130 47816 43788 51852 90928 54520 11658 39341 96562 13491 43415 95625 86586 55705 52690 49652 09858 03385 07224 26482 93972 85847 83163 05777 75606 88876 44624 82468 57926 03953 52773 48030 48029 00587 60758 25104 74709 16439 61362 67604 49256 27420 42083 20856 61190 62545 43372 13153 59584 50687 72460 29016 18766 79524 06163 42522 57719 54291 62991 93064 55377 99140 37340 43287 52628 88963 99587 94757 29174 64263 57455 25407 90914 51357 11136 94109 11939 32519 10760 20825 20261 87985 31887 70584 29725 91677 81314 96990 09019 21169 71737 27847 68472 68608 49003 37702 42429 16513 00500 51683 23364 35038 95170 29893 92233 45172 20138 12806 96501 17844 08745 19601 21228 59937 16231 30171 14448 46409 03890 64495 44400 61986 90754 85160 26327 50529 83491 87407 86680 88183 38510 22833 45085 04860 82503 93021 33219 71551 84306 35455 00766 82829 49304 13776 55279 39751 75461 39539 84683 39363 83047 46119 96653 85815 38420 56853 38621 86725 23340 28308 71123 28278 92125 07712 62946 32295 63989 89893 58211 67456 27010 21835 64622 01349 67151 88190 97303 81198 00497 34072 39610 36854 06643 19395 09790 19069 96395 52453 00545 05806 85501 95673 02292 19139 33918 56803 44903 98205 95510 02263 53536 19204 19947 45538 59381 02343 95544 95977 83779 02374 21617 27111 72364 34354 39478 22181 85286 24085 14006 66044 33258 88569 86705 43154 70696 57474 58550 33232 33421 07301 54594 05165 53790 68662 73337 99585 11562 57843 22988 27372 31989 87571 41595 78111 96358 33005 94087 30681 21602 87649 62867 44604 77464 91599 50549 73742 56269 01049 03778 19868 35938 14657 41268 04925 64879 85561 45372 34786 73303 90468 83834 36346 55379 49864 19270 56387 29317 48723 32083 76011 23029 91136 79386 27089 43879 93620 16295 15413 37142 48928 30722 01269 01475 46684 76535 76164 77379 46752 00490 75715 55278 19653 62132 39264 06160 13635 81559 07422 02020 31872 77605 27721 90055 61484 25551 87925 30343 51398 44253 22341 57623 36106 42506 39049 75008 65627 10953 59194 65897 51413 10348 22769 30624 74353 63256 91607 81547 81811 52843 66795 70611 08615 33150 44521 27473 92454 49454 23682 88606 13408 41486 37767 00961 20715 12491 40430 27253 86076 48236 34143 34623 51897 57664 52164 13767 96903 14950 19108 57598 44239 19862 91642 19399 49072 36234 64684 41173 94032 65918 40443 78051 33389 45257 42399 50829 65912 28508 55582 15725 03107 12570 12668 30240 29295 25220 11872 67675 62204 15420 51618 41634 84756 51699 98116 14101 00299 60783 86909 29160 30288 40026 91041 40792 88621 50784 24516 70908 70006 99282 12066 04183 71806 53556 72525 32567 53286 12910 42487 76182 58297 65157 95984 70356 22262 93486 00341 58722 98053 49896 50226 29174 87882 02734 20922 22453 39856 26476 69149 05562 84250 39127 57710 28402 79980 66365 82548 89264 88025 45661 01729 67026 64076 55904 29099 45681 50652 65305 37182 94127 03369 31378 51786 09040 70866 71149 65583 43434 76933 85781 71138 64558 73678 12301 45876 87126 60348 91390 95620 09939 36103 10291 61615 28813 84379 09904 23174 73363 94804 57593 14931 40529 76347 57481 19356 70911 01377 51721 00803 15590 24853 09066 92037 67192 20332 29094 33467 68514 22144 77379 39375 17034 43661 99104 03375 11173 54719 18550 46449 02636 55128 16228 82446 25759 16333 03910 72253 83742 18214 08835 08657 39177 15096 82887 47826 56995 99574 49066 17583 44137 52239 70968 34080 05355 98491 75417 38188 39994 46974 86762 65516 58276 58483 58845 31427 75687 90029 09517 02835 29716 34456 21296 40435 23117 60066 51012 41200 65975 58512 76178 58382 92041 97484 42360 80071 93045 76189 32349 22927 96501 98751 87212 72675 07981 25547 09589 04556 35792 12210 33346 69749 92356 30254 94780 24901 14195 21238 28153 09114 07907 38602 51522 74299 58180 72471 62591 66854 51333 12394 80494 70791 19153 26734 30282 44186 04142 63639 54800 04480 02670 49624 82017 92896 47669 75831 83271 31425 17029 69234 88962 76684 40323 26092 75249 60357 99646 92565 04936 81836 09003 23809 29345 95889 70695 36534 94060 34021 66544 37558 90045 63288 22505 45255 64056 44824 65151 87547 11962 18443 96582 53375 43885 69094 11303 15095 26179 37800 29741 20766 51479 39425 90298 96959 46995 56576 12186 56196 73378 62362 56125 21632 08628 69222 10327 48892 18654 36480 22967 80705 76561 51446 32046 92790 68212 07388 37781 42335 62823 60896 32080 68222 46801 22482 61177 18589 63814 09183 90367 36722 20888 32151 37556 00372 79839 40041 52970 02878 30766 70944 47456 01345 56417 25437 09069 79396 12257 14298 94671 54357 84687 88614 44581 23145 93571 98492 25284 71605 04922 12424 70141 21478 05734 55105 00801 90869 96033 02763 47870 81081 75450 11930 71412 23390 86639 38339 52942 57869 05076 43100 63835 19834 38934 15961 31854 34754 64955 69781 03829 30971 64651 43840 70070 73604 11237 35998 43452 25161 05070 27056 23526 60127 64848 30840 76118 30130 52793 20542 74628 65403 60367 45328 65105 70658 74882 25698 15793 67897 66974 22057 50596 83440 86973 50201 41020 67235 85020 07245 22563 26513 41055 92401 90274 21624 84391 40359 98953 53945 90944 07046 91209 14093 87001 26456 00162 37428 80210 92764 57931 06579 22955 24988 72758 46101 26483 69998 92256 95968 81592 05600 10165 52563 7567 +--JettyHttpClientBoundary1shlqpw2yahae6jf-- diff --git a/jetty-http/src/test/resources/multipart/browser-capture-number-only2-apache-httpcomp.expected.txt b/jetty-http/src/test/resources/multipart/browser-capture-number-only2-apache-httpcomp.expected.txt new file mode 100644 index 00000000000..aa49e327f1c --- /dev/null +++ b/jetty-http/src/test/resources/multipart/browser-capture-number-only2-apache-httpcomp.expected.txt @@ -0,0 +1,9 @@ +Request-Header|Accept-Encoding|gzip,deflate +Request-Header|Connection|keep-alive +Request-Header|Content-Length|240 +Request-Header|Content-Type|multipart/form-data; boundary=L8vdau8TpP0o-AYJDjCuYFQYnjB5gcHIFyap +Request-Header|Host|localhost:9090 +Request-Header|User-Agent|Apache-HttpClient/4.5.5 (Java/1.8.0_162) +Request-Header|X-BrowserId|apache-httpcomp +Parts-Count|1 +Part-ContainsContents|pi|3.14159265358979323846264338327950288419716939937510 diff --git a/jetty-http/src/test/resources/multipart/multipart-number-strict.raw b/jetty-http/src/test/resources/multipart/browser-capture-number-only2-apache-httpcomp.raw similarity index 63% rename from jetty-http/src/test/resources/multipart/multipart-number-strict.raw rename to jetty-http/src/test/resources/multipart/browser-capture-number-only2-apache-httpcomp.raw index 5c5681665ba..641c1a14837 100644 --- a/jetty-http/src/test/resources/multipart/multipart-number-strict.raw +++ b/jetty-http/src/test/resources/multipart/browser-capture-number-only2-apache-httpcomp.raw @@ -1,7 +1,7 @@ ---P6Uyk-Vikfbk_NqTfVF4DwNXrIxpN451pD1 +--L8vdau8TpP0o-AYJDjCuYFQYnjB5gcHIFyap Content-Disposition: form-data; name="pi" Content-Type: text/plain Content-Transfer-Encoding: 8bit 3.14159265358979323846264338327950288419716939937510 ---P6Uyk-Vikfbk_NqTfVF4DwNXrIxpN451pD1-- +--L8vdau8TpP0o-AYJDjCuYFQYnjB5gcHIFyap-- diff --git a/jetty-http/src/test/resources/multipart/browser-capture-sjis-apache-httpcomp.expected.txt b/jetty-http/src/test/resources/multipart/browser-capture-sjis-apache-httpcomp.expected.txt new file mode 100644 index 00000000000..77ad18f6899 --- /dev/null +++ b/jetty-http/src/test/resources/multipart/browser-capture-sjis-apache-httpcomp.expected.txt @@ -0,0 +1,10 @@ +Request-Header|Accept-Encoding|gzip,deflate +Request-Header|Connection|keep-alive +Request-Header|Content-Length|406 +Request-Header|Content-Type|multipart/form-data; boundary=u7tfLQaHJEHHUJjnVDbFdc_Oqz4jmkA25mgWd +Request-Header|Host|localhost:9090 +Request-Header|User-Agent|Apache-HttpClient/4.5.5 (Java/1.8.0_162) +Request-Header|X-BrowserId|apache-httpcomp +Parts-Count|2 +Part-ContainsContents|japanese|オープンソース +Part-ContainsContents|hello|日食桟橋 \ No newline at end of file diff --git a/jetty-http/src/test/resources/multipart/multipart-sjis.raw b/jetty-http/src/test/resources/multipart/browser-capture-sjis-apache-httpcomp.raw similarity index 60% rename from jetty-http/src/test/resources/multipart/multipart-sjis.raw rename to jetty-http/src/test/resources/multipart/browser-capture-sjis-apache-httpcomp.raw index 59e713a28b0..dfe4e57ab49 100644 --- a/jetty-http/src/test/resources/multipart/multipart-sjis.raw +++ b/jetty-http/src/test/resources/multipart/browser-capture-sjis-apache-httpcomp.raw @@ -1,13 +1,13 @@ ---VA2isIGmYNkgC3qrrGXnlQcWO17WB3a4npVQey +--u7tfLQaHJEHHUJjnVDbFdc_Oqz4jmkA25mgWd Content-Disposition: form-data; name="japanese" Content-Type: text/plain; charset=Shift_JIS Content-Transfer-Encoding: 8bit - ---VA2isIGmYNkgC3qrrGXnlQcWO17WB3a4npVQey +I[v\[X +--u7tfLQaHJEHHUJjnVDbFdc_Oqz4jmkA25mgWd Content-Disposition: form-data; name="hello" Content-Type: text/plain; charset=Shift_JIS Content-Transfer-Encoding: 8bit -?^ ---VA2isIGmYNkgC3qrrGXnlQcWO17WB3a4npVQey-- +HV +--u7tfLQaHJEHHUJjnVDbFdc_Oqz4jmkA25mgWd-- diff --git a/jetty-http/src/test/resources/multipart/browser-capture-sjis-jetty-client.expected.txt b/jetty-http/src/test/resources/multipart/browser-capture-sjis-jetty-client.expected.txt new file mode 100644 index 00000000000..a0ec6edc7ed --- /dev/null +++ b/jetty-http/src/test/resources/multipart/browser-capture-sjis-jetty-client.expected.txt @@ -0,0 +1,10 @@ +Request-Header|Accept-Encoding|gzip +Request-Header|Connection|close +Request-Header|Content-Type|multipart/form-data; boundary=JettyHttpClientBoundaryny8fndkswj5ot6hx +Request-Header|Host|localhost:9090 +Request-Header|Transfer-Encoding|chunked +Request-Header|User-Agent|Jetty/9.4.9.v20180320 +Request-Header|X-BrowserId|jetty-client +Parts-Count|2 +Part-ContainsContents|japanese|オープンソース +Part-ContainsContents|hello|日食桟橋 \ No newline at end of file diff --git a/jetty-http/src/test/resources/multipart/browser-capture-sjis-jetty-client.raw b/jetty-http/src/test/resources/multipart/browser-capture-sjis-jetty-client.raw new file mode 100644 index 00000000000..eb7b56fcc39 --- /dev/null +++ b/jetty-http/src/test/resources/multipart/browser-capture-sjis-jetty-client.raw @@ -0,0 +1,11 @@ +--JettyHttpClientBoundaryny8fndkswj5ot6hx +Content-Disposition: form-data; name="japanese" +Content-Type: text/plain; charset=Shift-JIS + +I[v\[X +--JettyHttpClientBoundaryny8fndkswj5ot6hx +Content-Disposition: form-data; name="hello" +Content-Type: text/plain; charset=Shift-JIS + +HV +--JettyHttpClientBoundaryny8fndkswj5ot6hx-- diff --git a/jetty-http/src/test/resources/multipart/browser-capture-strange-quoting-apache-httpcomp.expected.txt b/jetty-http/src/test/resources/multipart/browser-capture-strange-quoting-apache-httpcomp.expected.txt new file mode 100644 index 00000000000..42010b4fa30 --- /dev/null +++ b/jetty-http/src/test/resources/multipart/browser-capture-strange-quoting-apache-httpcomp.expected.txt @@ -0,0 +1,11 @@ +Request-Header|Accept-Encoding|gzip,deflate +Request-Header|Connection|keep-alive +Request-Header|Content-Length|798 +Request-Header|Content-Type|multipart/form-data; boundary=z5xWs05oeiE0TAdFlrrlAX5RSgHrHzVcgskrru +Request-Header|Host|localhost:9090 +Request-Header|User-Agent|Apache-HttpClient/4.5.5 (Java/1.8.0_162) +Request-Header|X-BrowserId|apache-httpcomp +Parts-Count|4 +Part-ContainsContents|and "I" quote|Value 1 +Part-ContainsContents|and+%22I%22+quote|Value 2 +Part-ContainsContents|value"; what="whoa"|Value 3 diff --git a/jetty-http/src/test/resources/multipart/multipart-strange-quoting.raw b/jetty-http/src/test/resources/multipart/browser-capture-strange-quoting-apache-httpcomp.raw similarity index 70% rename from jetty-http/src/test/resources/multipart/multipart-strange-quoting.raw rename to jetty-http/src/test/resources/multipart/browser-capture-strange-quoting-apache-httpcomp.raw index 38fa8862abc..04ac9e43574 100644 --- a/jetty-http/src/test/resources/multipart/multipart-strange-quoting.raw +++ b/jetty-http/src/test/resources/multipart/browser-capture-strange-quoting-apache-httpcomp.raw @@ -1,26 +1,26 @@ ---tR61vgdxSzzv2FDycET2lt-OUZ1IW1GqA +--z5xWs05oeiE0TAdFlrrlAX5RSgHrHzVcgskrru Content-Disposition: form-data; name="and \"I\" quote" Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Value 1 ---tR61vgdxSzzv2FDycET2lt-OUZ1IW1GqA +--z5xWs05oeiE0TAdFlrrlAX5RSgHrHzVcgskrru Content-Disposition: form-data; name="and+%22I%22+quote" Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Value 2 ---tR61vgdxSzzv2FDycET2lt-OUZ1IW1GqA +--z5xWs05oeiE0TAdFlrrlAX5RSgHrHzVcgskrru Content-Disposition: form-data; name="value\"; what=\"whoa\"" Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Value 3 ---tR61vgdxSzzv2FDycET2lt-OUZ1IW1GqA +--z5xWs05oeiE0TAdFlrrlAX5RSgHrHzVcgskrru Content-Disposition: form-data; name="other\"; what=\"Something\"" Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Value 4 ---tR61vgdxSzzv2FDycET2lt-OUZ1IW1GqA-- +--z5xWs05oeiE0TAdFlrrlAX5RSgHrHzVcgskrru-- diff --git a/jetty-http/src/test/resources/multipart/browser-capture-text-files-apache-httpcomp.expected.txt b/jetty-http/src/test/resources/multipart/browser-capture-text-files-apache-httpcomp.expected.txt new file mode 100644 index 00000000000..c246ce67c29 --- /dev/null +++ b/jetty-http/src/test/resources/multipart/browser-capture-text-files-apache-httpcomp.expected.txt @@ -0,0 +1,15 @@ +Request-Header|Accept-Encoding|gzip,deflate +Request-Header|Connection|keep-alive +Request-Header|Content-Length|737 +Request-Header|Content-Type|multipart/form-data; boundary=B8x_673_DRSeYGTpUMgof-qN1nircWQA +Request-Header|Host|localhost:9090 +Request-Header|User-Agent|Apache-HttpClient/4.5.5 (Java/1.8.0_162) +Request-Header|X-BrowserId|apache-httpcomp +Parts-Count|3 +Part-ContainsContents|text|text default +Part-ContainsContents|file1|Content of a.txt +Part-ContainsContents|file2|Content of a.html +Part-Filename|file1|a.txt +Part-Filename|file2|a.html +Part-Sha1sum|file1|588A0F273CB5AFE9C8D76DD081812E672F2061E2 +Part-Sha1sum|file2|9A9005159AB90A6D2D9BACB5414EFE932F0CED85 \ No newline at end of file diff --git a/jetty-http/src/test/resources/multipart/multipart-text-files.raw b/jetty-http/src/test/resources/multipart/browser-capture-text-files-apache-httpcomp.raw similarity index 77% rename from jetty-http/src/test/resources/multipart/multipart-text-files.raw rename to jetty-http/src/test/resources/multipart/browser-capture-text-files-apache-httpcomp.raw index c72d60aaea1..b8fee37ca7e 100644 --- a/jetty-http/src/test/resources/multipart/multipart-text-files.raw +++ b/jetty-http/src/test/resources/multipart/browser-capture-text-files-apache-httpcomp.raw @@ -1,11 +1,11 @@ ---ny9C5eIZL7fsfPY9ONPy8Lxb6tkgEv1 +--B8x_673_DRSeYGTpUMgof-qN1nircWQA Content-Disposition: form-data; name="text" Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit text default ---ny9C5eIZL7fsfPY9ONPy8Lxb6tkgEv1 +--B8x_673_DRSeYGTpUMgof-qN1nircWQA Content-Type: text/plain; charset=UTF-8 X-SHA1: 588A0F273CB5AFE9C8D76DD081812E672F2061E2 Content-Disposition: form-data; name="file1"; filename="a.txt" @@ -13,11 +13,11 @@ Content-Transfer-Encoding: binary Content of a.txt ---ny9C5eIZL7fsfPY9ONPy8Lxb6tkgEv1 +--B8x_673_DRSeYGTpUMgof-qN1nircWQA Content-Type: text/html; charset=UTF-8 X-SHA1: 9A9005159AB90A6D2D9BACB5414EFE932F0CED85 Content-Disposition: form-data; name="file2"; filename="a.html" Content-Transfer-Encoding: binary <!DOCTYPE html><title>Content of a.html. ---ny9C5eIZL7fsfPY9ONPy8Lxb6tkgEv1-- +--B8x_673_DRSeYGTpUMgof-qN1nircWQA-- diff --git a/jetty-http/src/test/resources/multipart/multipart-text-files.expected.txt b/jetty-http/src/test/resources/multipart/browser-capture-text-files-jetty-client.expected.txt similarity index 50% rename from jetty-http/src/test/resources/multipart/multipart-text-files.expected.txt rename to jetty-http/src/test/resources/multipart/browser-capture-text-files-jetty-client.expected.txt index 82fe6e3a904..7e0b528d284 100644 --- a/jetty-http/src/test/resources/multipart/multipart-text-files.expected.txt +++ b/jetty-http/src/test/resources/multipart/browser-capture-text-files-jetty-client.expected.txt @@ -1,4 +1,10 @@ -Content-Type|multipart/form-data; boundary="ny9C5eIZL7fsfPY9ONPy8Lxb6tkgEv1" +Request-Header|Accept-Encoding|gzip +Request-Header|Connection|close +Request-Header|Content-Type|multipart/form-data; boundary=JettyHttpClientBoundary1e87p8a551psw1al +Request-Header|Host|localhost:9090 +Request-Header|Transfer-Encoding|chunked +Request-Header|User-Agent|Jetty/9.4.9.v20180320 +Request-Header|X-BrowserId|jetty-client Parts-Count|3 Part-ContainsContents|text|text default Part-ContainsContents|file1|Content of a.txt diff --git a/jetty-http/src/test/resources/multipart/browser-capture-text-files-jetty-client.raw b/jetty-http/src/test/resources/multipart/browser-capture-text-files-jetty-client.raw new file mode 100644 index 00000000000..53405425431 --- /dev/null +++ b/jetty-http/src/test/resources/multipart/browser-capture-text-files-jetty-client.raw @@ -0,0 +1,20 @@ +--JettyHttpClientBoundary1e87p8a551psw1al +Content-Disposition: form-data; name="text" +Content-Type: text/plain;charset=UTF-8 + +text default + +--JettyHttpClientBoundary1e87p8a551psw1al +Content-Disposition: form-data; name="file1"; filename="a.txt" +Content-Type: application/octet-stream +X-SHA1: 588A0F273CB5AFE9C8D76DD081812E672F2061E2 + +Content of a.txt + +--JettyHttpClientBoundary1e87p8a551psw1al +Content-Disposition: form-data; name="file2"; filename="a.html" +Content-Type: application/octet-stream +X-SHA1: 9A9005159AB90A6D2D9BACB5414EFE932F0CED85 + +Content of a.html. +--JettyHttpClientBoundary1e87p8a551psw1al-- diff --git a/jetty-http/src/test/resources/multipart/browser-capture-unicode-names-apache-httpcomp.expected.txt b/jetty-http/src/test/resources/multipart/browser-capture-unicode-names-apache-httpcomp.expected.txt new file mode 100644 index 00000000000..446b69d34fc --- /dev/null +++ b/jetty-http/src/test/resources/multipart/browser-capture-unicode-names-apache-httpcomp.expected.txt @@ -0,0 +1,11 @@ +Request-Header|Accept-Encoding|gzip,deflate +Request-Header|Connection|keep-alive +Request-Header|Content-Length|475 +Request-Header|Content-Type|multipart/form-data; boundary=yRxfRSltW63lJPc9oHOOVyCn-SmDG6i4Ts9M4E6 +Request-Header|Host|localhost:9090 +Request-Header|User-Agent|Apache-HttpClient/4.5.5 (Java/1.8.0_162) +Request-Header|X-BrowserId|apache-httpcomp +Parts-Count|2 +Part-ContainsContents|こんにちは世界|Greetings 1 +Part-ContainsContents|%E3%81%93%E3%82%93%E3%81%AB%E3%81%A1%E3%81%AF%E4%B8%96%E7%95%8C|Greetings 2 + diff --git a/jetty-http/src/test/resources/multipart/multipart-unicode-names.raw b/jetty-http/src/test/resources/multipart/browser-capture-unicode-names-apache-httpcomp.raw similarity index 70% rename from jetty-http/src/test/resources/multipart/multipart-unicode-names.raw rename to jetty-http/src/test/resources/multipart/browser-capture-unicode-names-apache-httpcomp.raw index 5afab43ef54..938bdbdce6b 100644 --- a/jetty-http/src/test/resources/multipart/multipart-unicode-names.raw +++ b/jetty-http/src/test/resources/multipart/browser-capture-unicode-names-apache-httpcomp.raw @@ -1,13 +1,13 @@ ---1R40qTSaEjDJPcArQiccT7vdpp0l02248R +--yRxfRSltW63lJPc9oHOOVyCn-SmDG6i4Ts9M4E6 Content-Disposition: form-data; name="こんにちは世界" Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Greetings 1 ---1R40qTSaEjDJPcArQiccT7vdpp0l02248R +--yRxfRSltW63lJPc9oHOOVyCn-SmDG6i4Ts9M4E6 Content-Disposition: form-data; name="%E3%81%93%E3%82%93%E3%81%AB%E3%81%A1%E3%81%AF%E4%B8%96%E7%95%8C" Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Greetings 2 ---1R40qTSaEjDJPcArQiccT7vdpp0l02248R-- +--yRxfRSltW63lJPc9oHOOVyCn-SmDG6i4Ts9M4E6-- diff --git a/jetty-http/src/test/resources/multipart/browser-capture-unicode-names-jetty-client.expected.txt b/jetty-http/src/test/resources/multipart/browser-capture-unicode-names-jetty-client.expected.txt new file mode 100644 index 00000000000..bc9e8e69dab --- /dev/null +++ b/jetty-http/src/test/resources/multipart/browser-capture-unicode-names-jetty-client.expected.txt @@ -0,0 +1,11 @@ +Request-Header|Accept-Encoding|gzip +Request-Header|Connection|close +Request-Header|Content-Type|multipart/form-data; boundary=JettyHttpClientBoundary9iv9jofnq5dkzmgl +Request-Header|Host|localhost:9090 +Request-Header|Transfer-Encoding|chunked +Request-Header|User-Agent|Jetty/9.4.9.v20180320 +Request-Header|X-BrowserId|jetty-client +Parts-Count|2 +Part-ContainsContents|こんにちは世界|Greetings 1 +Part-ContainsContents|%E3%81%93%E3%82%93%E3%81%AB%E3%81%A1%E3%81%AF%E4%B8%96%E7%95%8C|Greetings 2 + diff --git a/jetty-http/src/test/resources/multipart/browser-capture-unicode-names-jetty-client.raw b/jetty-http/src/test/resources/multipart/browser-capture-unicode-names-jetty-client.raw new file mode 100644 index 00000000000..4188d3e81d2 --- /dev/null +++ b/jetty-http/src/test/resources/multipart/browser-capture-unicode-names-jetty-client.raw @@ -0,0 +1,11 @@ +--JettyHttpClientBoundary9iv9jofnq5dkzmgl +Content-Disposition: form-data; name="こんにちは世界" +Content-Type: text/plain + +Greetings 1 +--JettyHttpClientBoundary9iv9jofnq5dkzmgl +Content-Disposition: form-data; name="%E3%81%93%E3%82%93%E3%81%AB%E3%81%A1%E3%81%AF%E4%B8%96%E7%95%8C" +Content-Type: text/plain + +Greetings 2 +--JettyHttpClientBoundary9iv9jofnq5dkzmgl-- diff --git a/jetty-http/src/test/resources/multipart/browser-capture-whitespace-only-jetty-client.expected.txt b/jetty-http/src/test/resources/multipart/browser-capture-whitespace-only-jetty-client.expected.txt new file mode 100644 index 00000000000..8b7f3212c67 --- /dev/null +++ b/jetty-http/src/test/resources/multipart/browser-capture-whitespace-only-jetty-client.expected.txt @@ -0,0 +1,10 @@ +Request-Header|Accept-Encoding|gzip +Request-Header|Connection|close +Request-Header|Content-Type|multipart/form-data; boundary=JettyHttpClientBoundary1evz7ehqg8tvo10h +Request-Header|Host|localhost:9090 +Request-Header|Transfer-Encoding|chunked +Request-Header|User-Agent|Jetty/9.4.9.v20180320 +Request-Header|X-BrowserId|jetty-client +Parts-Count|1 +Part-Filename|whitespace|whitespace.txt +Part-Sha1sum|whitespace|353E2CCDDE1069706B950414B230B6C047F98491 \ No newline at end of file diff --git a/jetty-http/src/test/resources/multipart/browser-capture-whitespace-only-jetty-client.raw b/jetty-http/src/test/resources/multipart/browser-capture-whitespace-only-jetty-client.raw new file mode 100644 index 00000000000..64f39f6ee0f --- /dev/null +++ b/jetty-http/src/test/resources/multipart/browser-capture-whitespace-only-jetty-client.raw @@ -0,0 +1,209748 @@ +--JettyHttpClientBoundary1evz7ehqg8tvo10h +Content-Disposition: form-data; name="whitespace"; filename="whitespace.txt" +Content-Type: application/octet-stream +X-SHA1: 353E2CCDDE1069706B950414B230B6C047F98491 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +--JettyHttpClientBoundary1evz7ehqg8tvo10h-- diff --git a/jetty-http/src/test/resources/multipart/multipart-zencoding.expected.txt b/jetty-http/src/test/resources/multipart/browser-capture-zalgo-text-plain-apache-httpcomp.expected.txt similarity index 76% rename from jetty-http/src/test/resources/multipart/multipart-zencoding.expected.txt rename to jetty-http/src/test/resources/multipart/browser-capture-zalgo-text-plain-apache-httpcomp.expected.txt index fda05113c8f..9fecae5916c 100644 --- a/jetty-http/src/test/resources/multipart/multipart-zencoding.expected.txt +++ b/jetty-http/src/test/resources/multipart/browser-capture-zalgo-text-plain-apache-httpcomp.expected.txt @@ -1,8 +1,12 @@ -Content-Type|multipart/form-data; boundary="UuAU1liVuDVE7wfJUYE72PUF9DZafZ" +Request-Header|Accept-Encoding|gzip,deflate +Request-Header|Connection|keep-alive +Request-Header|Content-Length|1870 +Request-Header|Content-Type|multipart/form-data; boundary=V9oY7Ug2J-n4sFXLWdb7yd2LtU0hdK36ejhKYh +Request-Header|Host|localhost:9090 +Request-Header|User-Agent|Apache-HttpClient/4.5.5 (Java/1.8.0_162) +Request-Header|X-BrowserId|apache-httpcomp Parts-Count|4 Part-ContainsContents|zalgo-8|y͔͕͍o̪̞͎̥͇̤̕u'̛̰̫̳̰v̧̘̪̠̟̟e̥͈̱ ̥̠͇͎͕̜s̤e̺e̙ͅņ̜ ̲̟͝za̴͖̱̲͈̘l͖̖͓̙̮͔g͕̞͖͘o͕̤͈̗ ̯̲̹̲͓b͙͟e̞͎̜̗͈͉̭͞f̸or̰̩e̡̝̺,̸͕̙̥̼͇̜ ̪͇̹r̘̪ͅị͔̥͈ͅg̠̟̯͖̦͇ht͖̪͍͚̖͡?͙̝͖̞ Part-ContainsContents|zalgo-16|y͔͕͍o̪̞͎̥͇̤̕u'̛̰̫̳̰v̧̘̪̠̟̟e̥͈̱ ̥̠͇͎͕̜s̤e̺e̙ͅņ̜ ̲̟͝za̴͖̱̲͈̘l͖̖͓̙̮͔g͕̞͖͘o͕̤͈̗ ̯̲̹̲͓b͙͟e̞͎̜̗͈͉̭͞f̸or̰̩e̡̝̺,̸͕̙̥̼͇̜ ̪͇̹r̘̪ͅị͔̥͈ͅg̠̟̯͖̦͇ht͖̪͍͚̖͡?͙̝͖̞ Part-ContainsContents|zalgo-16-be|y͔͕͍o̪̞͎̥͇̤̕u'̛̰̫̳̰v̧̘̪̠̟̟e̥͈̱ ̥̠͇͎͕̜s̤e̺e̙ͅņ̜ ̲̟͝za̴͖̱̲͈̘l͖̖͓̙̮͔g͕̞͖͘o͕̤͈̗ ̯̲̹̲͓b͙͟e̞͎̜̗͈͉̭͞f̸or̰̩e̡̝̺,̸͕̙̥̼͇̜ ̪͇̹r̘̪ͅị͔̥͈ͅg̠̟̯͖̦͇ht͖̪͍͚̖͡?͙̝͖̞ Part-ContainsContents|zalgo-16-le|y͔͕͍o̪̞͎̥͇̤̕u'̛̰̫̳̰v̧̘̪̠̟̟e̥͈̱ ̥̠͇͎͕̜s̤e̺e̙ͅņ̜ ̲̟͝za̴͖̱̲͈̘l͖̖͓̙̮͔g͕̞͖͘o͕̤͈̗ ̯̲̹̲͓b͙͟e̞͎̜̗͈͉̭͞f̸or̰̩e̡̝̺,̸͕̙̥̼͇̜ ̪͇̹r̘̪ͅị͔̥͈ͅg̠̟̯͖̦͇ht͖̪͍͚̖͡?͙̝͖̞ - - diff --git a/jetty-http/src/test/resources/multipart/multipart-zencoding.raw b/jetty-http/src/test/resources/multipart/browser-capture-zalgo-text-plain-apache-httpcomp.raw similarity index 88% rename from jetty-http/src/test/resources/multipart/multipart-zencoding.raw rename to jetty-http/src/test/resources/multipart/browser-capture-zalgo-text-plain-apache-httpcomp.raw index 74d78b79fb5014723b7ed76f18238d714597fc57..2cd8c76db09458c7d1f49555b0a908815bd78465 100644 GIT binary patch delta 233 zcmZ3+caBd(S2xTuKhiuj-N;Kf&!pHb!Y4c>$-FYf$fqRKAS1=w*eo?G!#gr#qe2^_ i8gWV|D(G$g#8^X$@?FgJq$qD?t!LCC&M~^Wyj%cjPfE4` delta 193 zcmX@dw~S9gS2wiOG1M?8Gpy7l%+=JW5G0K**)-x*Mw^Ub`mkR(cZ9Inn diff --git a/jetty-http/src/test/resources/multipart/multipart-complex.expected.txt b/jetty-http/src/test/resources/multipart/multipart-complex.expected.txt deleted file mode 100644 index 1eed38785c1..00000000000 --- a/jetty-http/src/test/resources/multipart/multipart-complex.expected.txt +++ /dev/null @@ -1,9 +0,0 @@ -Content-Type|multipart/form-data; boundary="PMyKOsh8JrSZm-rUF8EJej42yqbh-UWw9FG-" -Parts-Count|6 -Part-ContainsContents|pi|3.14159265358979323846264338327950288419716939937510 -Part-ContainsContents|company|bob & frank's shoe repair -Part-ContainsContents|power|ꬵо𝗋ⲥ𝖾 -Part-ContainsContents|japanese|健治 -Part-ContainsContents|hello|ャユ戆タ -Part-Filename|upload_file|filename -Part-Sha1sum|upload_file|e75b73644afe9b234d70da9ff225229de68cdff8 diff --git a/jetty-http/src/test/resources/multipart/multipart-duplicate-names-1.expected.txt b/jetty-http/src/test/resources/multipart/multipart-duplicate-names-1.expected.txt deleted file mode 100644 index 5cc43031f34..00000000000 --- a/jetty-http/src/test/resources/multipart/multipart-duplicate-names-1.expected.txt +++ /dev/null @@ -1,2 +0,0 @@ -Content-Type|multipart/form-data; boundary="mToTaXZk2RQZb6TrQRLOgqW-44MPpVbs5wyJTlyl" -Parts-Count|10 diff --git a/jetty-http/src/test/resources/multipart/multipart-encoding-mess.expected.txt b/jetty-http/src/test/resources/multipart/multipart-encoding-mess.expected.txt deleted file mode 100644 index 44148c5505f..00000000000 --- a/jetty-http/src/test/resources/multipart/multipart-encoding-mess.expected.txt +++ /dev/null @@ -1,4 +0,0 @@ -Content-Type|multipart/form-data; boundary="CVnTR46ddexmZjsh1ORHg9QbCOiLhUYl" -Parts-Count|168 -Part-ContainsContents|persian-UTF-8|برج بابل -Part-ContainsContents|persian-CESU-8|برج بابل diff --git a/jetty-http/src/test/resources/multipart/multipart-inside-itself-binary.expected.txt b/jetty-http/src/test/resources/multipart/multipart-inside-itself-binary.expected.txt deleted file mode 100644 index 1074a9a759b..00000000000 --- a/jetty-http/src/test/resources/multipart/multipart-inside-itself-binary.expected.txt +++ /dev/null @@ -1,6 +0,0 @@ -Content-Type|multipart/form-data; boundary="94GJ2MW4vpjh92qj-CHjUUIwb9X8Y2LqkU2Yxn0vTU2oHy5jk6_Kpxn2aE9EokEiRGox4eWfAYP8-" -Parts-Count|4 -Part-ContainsContents|reporter| -Part-ContainsContents|timestamp|2018-03-21T19:00:18+00:00 -Part-ContainsContents|comments|this also couldn't be parsed -Part-ContainsContents|attachment|cherry \ No newline at end of file diff --git a/jetty-http/src/test/resources/multipart/multipart-inside-itself.expected.txt b/jetty-http/src/test/resources/multipart/multipart-inside-itself.expected.txt deleted file mode 100644 index 4f68cd2fa81..00000000000 --- a/jetty-http/src/test/resources/multipart/multipart-inside-itself.expected.txt +++ /dev/null @@ -1,6 +0,0 @@ -Content-Type|multipart/form-data; boundary="kCFSwstIsIZkZtQ5JM7193kJYcK5WkyvoxsGjx5eCuVFbaeUZ9oK57JCp_p5wP86S5nY4re5x" -Parts-Count|4 -Part-ContainsContents|reporter| -Part-ContainsContents|timestamp|2018-03-21T18:52:18+00:00 -Part-ContainsContents|comments|this couldn't be parsed -Part-ContainsContents|attachment|banana \ No newline at end of file diff --git a/jetty-http/src/test/resources/multipart/multipart-number-browser.expected.txt b/jetty-http/src/test/resources/multipart/multipart-number-browser.expected.txt deleted file mode 100644 index ebc9f5eea84..00000000000 --- a/jetty-http/src/test/resources/multipart/multipart-number-browser.expected.txt +++ /dev/null @@ -1,3 +0,0 @@ -Content-Type|multipart/form-data; boundary="RjYiyHVV9Phv7tYylzT1f94fvTC-s7oNKwB9_Y" -Parts-Count|1 -Part-ContainsContents|pi|3.14159265358979323846264338327950288419716939937510 diff --git a/jetty-http/src/test/resources/multipart/multipart-number-strict.expected.txt b/jetty-http/src/test/resources/multipart/multipart-number-strict.expected.txt deleted file mode 100644 index 9156fb21e2b..00000000000 --- a/jetty-http/src/test/resources/multipart/multipart-number-strict.expected.txt +++ /dev/null @@ -1,3 +0,0 @@ -Content-Type|multipart/form-data; boundary="P6Uyk-Vikfbk_NqTfVF4DwNXrIxpN451pD1" -Parts-Count|1 -Part-ContainsContents|pi|3.14159265358979323846264338327950288419716939937510 diff --git a/jetty-http/src/test/resources/multipart/multipart-sjis.expected.txt b/jetty-http/src/test/resources/multipart/multipart-sjis.expected.txt deleted file mode 100644 index 35e678b66df..00000000000 --- a/jetty-http/src/test/resources/multipart/multipart-sjis.expected.txt +++ /dev/null @@ -1,4 +0,0 @@ -Content-Type|multipart/form-data; boundary="VA2isIGmYNkgC3qrrGXnlQcWO17WB3a4npVQey" -Parts-Count|2 -Part-ContainsContents|japanese|健治 -Part-ContainsContents|hello|ャユ戆タ diff --git a/jetty-http/src/test/resources/multipart/multipart-strange-quoting.expected.txt b/jetty-http/src/test/resources/multipart/multipart-strange-quoting.expected.txt deleted file mode 100644 index 76408aa202a..00000000000 --- a/jetty-http/src/test/resources/multipart/multipart-strange-quoting.expected.txt +++ /dev/null @@ -1,5 +0,0 @@ -Content-Type|multipart/form-data; boundary="tR61vgdxSzzv2FDycET2lt-OUZ1IW1GqA" -Parts-Count|4 -Part-ContainsContents|and "I" quote|Value 1 -Part-ContainsContents|and+%22I%22+quote|Value 2 -Part-ContainsContents|value"; what="whoa"|Value 3 diff --git a/jetty-http/src/test/resources/multipart/multipart-unicode-names.expected.txt b/jetty-http/src/test/resources/multipart/multipart-unicode-names.expected.txt deleted file mode 100644 index 2c15cb6f6b4..00000000000 --- a/jetty-http/src/test/resources/multipart/multipart-unicode-names.expected.txt +++ /dev/null @@ -1,5 +0,0 @@ -Content-Type|multipart/form-data; boundary="1R40qTSaEjDJPcArQiccT7vdpp0l02248R" -Parts-Count|2 -Part-ContainsContents|こんにちは世界|Greetings 1 -Part-ContainsContents|%E3%81%93%E3%82%93%E3%81%AB%E3%81%A1%E3%81%AF%E4%B8%96%E7%95%8C|Greetings 2 - diff --git a/jetty-http/src/test/resources/multipart/multipart-x-www-form-urlencoded.expected.txt b/jetty-http/src/test/resources/multipart/multipart-x-www-form-urlencoded.expected.txt deleted file mode 100644 index e1863757719..00000000000 --- a/jetty-http/src/test/resources/multipart/multipart-x-www-form-urlencoded.expected.txt +++ /dev/null @@ -1,5 +0,0 @@ -Content-Type|multipart/form-data; boundary="qjIkwQOhaYfC2VEcL5j-9sjEK1FIsYMd5" -Parts-Count|1 -Part-ContainsContents|company|bob & frank's shoe repair - - From 9397ae2d77170f7621d04bcf5bfa5a6ba21f70e7 Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Wed, 4 Apr 2018 09:10:57 +1000 Subject: [PATCH 47/50] revert ResourceHandlerTest changes Signed-off-by: Greg Wilkins --- .../org/eclipse/jetty/server/handler/ResourceHandlerTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ResourceHandlerTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ResourceHandlerTest.java index 17d48320c00..91d0ededdd1 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ResourceHandlerTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ResourceHandlerTest.java @@ -170,14 +170,14 @@ public class ResourceHandlerTest assertThat(response.getContent(),containsString("big.txt")); assertThat(response.getContent(),containsString("bigger.txt")); assertThat(response.getContent(),containsString("directory")); - assertThat(response.getContent(),containsString("simple.raw")); + assertThat(response.getContent(),containsString("simple.txt")); } @Test public void testHeaders() throws Exception { HttpTester.Response response = HttpTester.parseResponse( - _local.getResponse("GET /resource/simple.raw HTTP/1.0\r\n\r\n")); + _local.getResponse("GET /resource/simple.txt HTTP/1.0\r\n\r\n")); assertThat(response.getStatus(),equalTo(200)); assertThat(response.get(CONTENT_TYPE),equalTo("text/plain")); assertThat(response.get(LAST_MODIFIED),Matchers.notNullValue()); From 1c35324f5b0e8b03c2bc7b3dd8bca95c4866b079 Mon Sep 17 00:00:00 2001 From: Lachlan Roberts Date: Wed, 4 Apr 2018 09:46:50 +1000 Subject: [PATCH 48/50] Fixed some javadoc errors and warnings Signed-off-by: Lachlan Roberts --- .../org/eclipse/jetty/http/MultiPartFormInputStream.java | 2 +- .../java/org/eclipse/jetty/http/MultiPartParser.java | 9 ++++----- .../eclipse/jetty/util/MultiPartInputStreamParser.java | 2 +- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartFormInputStream.java b/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartFormInputStream.java index 35d4f2a9f6c..4c71a941c86 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartFormInputStream.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartFormInputStream.java @@ -55,7 +55,7 @@ import org.eclipse.jetty.util.log.Logger; * * Handle a MultiPart Mime input stream, breaking it up on the boundary into files and strings. * - * @see https://tools.ietf.org/html/rfc7578 + * @see https://tools.ietf.org/html/rfc7578 */ public class MultiPartFormInputStream { diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartParser.java b/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartParser.java index 63aec8605e9..5554e64094a 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartParser.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartParser.java @@ -33,9 +33,8 @@ import org.eclipse.jetty.util.log.Logger; /* ------------------------------------------------------------ */ /** A parser for MultiPart content type. * - * @see https://tools.ietf.org/html/rfc2046#section-5.1 - * @see https://tools.ietf.org/html/rfc2045 - * + * @see https://tools.ietf.org/html/rfc2046#section-5.1 + * @see https://tools.ietf.org/html/rfc2045 */ public class MultiPartParser { @@ -255,8 +254,8 @@ public class MultiPartParser /** * Parse until next Event. * - * @param buffer - * the buffer to parse + * @param buffer the buffer to parse + * @param last whether this buffer contains last bit of content * @return True if an {@link RequestHandler} method was called and it returned true; */ public boolean parse(ByteBuffer buffer, boolean last) diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/MultiPartInputStreamParser.java b/jetty-util/src/main/java/org/eclipse/jetty/util/MultiPartInputStreamParser.java index 131a5587c78..1280e6f29d5 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/MultiPartInputStreamParser.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/MultiPartInputStreamParser.java @@ -58,7 +58,7 @@ import org.eclipse.jetty.util.log.Logger; * * Non Compliance warnings are documented by the method {@link #getNonComplianceWarnings()} * - * @deprecated Replaced by {@link org.eclipse.jetty.http#MultiPartFormInputStream} + * @deprecated Replaced by org.eclipse.jetty.http.MultiPartFormInputStream * The code for MultiPartInputStream is slower than its replacement MultiPartFormInputStream. However * this class accepts formats non compliant the RFC that the new MultiPartFormInputStream does not accept. * From 4a0e4294b9d0942d9b70242c4d807c05af0f7f62 Mon Sep 17 00:00:00 2001 From: Lachlan Roberts Date: Wed, 4 Apr 2018 11:18:57 +1000 Subject: [PATCH 49/50] fixed path of MultiPartFormDataCompliance in jetty.xml added some debug info changes to jetty test webapp to display parts from multi-part forms Signed-off-by: Lachlan Roberts --- .../jetty/http/MultiPartFormInputStream.java | 2 +- jetty-server/src/main/config/etc/jetty.xml | 2 +- .../org/eclipse/jetty/server/Request.java | 2 ++ .../src/main/java/com/acme/Dump.java | 23 +++++++++++++++++++ .../src/main/webapp/WEB-INF/web.xml | 19 ++++----------- 5 files changed, 31 insertions(+), 17 deletions(-) diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartFormInputStream.java b/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartFormInputStream.java index 4c71a941c86..5fb4d85bd15 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartFormInputStream.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartFormInputStream.java @@ -95,7 +95,7 @@ public class MultiPartFormInputStream @Override public String toString() { - return String.format("Part{n=%s,fn=%s,ct=%s,s=%d,t=%b,f=%s}",_name,_filename,_contentType,_size,_temporary,_file); + return String.format("Part{n=%s,fn=%s,ct=%s,s=%d,tmp=%b,file=%s}",_name,_filename,_contentType,_size,_temporary,_file); } protected void setContentType(String contentType) diff --git a/jetty-server/src/main/config/etc/jetty.xml b/jetty-server/src/main/config/etc/jetty.xml index d86e28aea18..d056f22c927 100644 --- a/jetty-server/src/main/config/etc/jetty.xml +++ b/jetty-server/src/main/config/etc/jetty.xml @@ -65,7 +65,7 @@ - + diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java index 20c2de107c3..ad1377d053a 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java @@ -2395,6 +2395,8 @@ public class Request implements HttpServletRequest private MultiParts newMultiParts(ServletInputStream inputStream, String contentType, MultipartConfigElement config, Object object) throws IOException { MultiPartFormDataCompliance compliance = getHttpChannel().getHttpConfiguration().getMultipartFormDataCompliance(); + if(LOG.isDebugEnabled()) + LOG.debug("newMultiParts {} {}",compliance, this); switch(compliance) { diff --git a/tests/test-webapps/test-jetty-webapp/src/main/java/com/acme/Dump.java b/tests/test-webapps/test-jetty-webapp/src/main/java/com/acme/Dump.java index b6ef83400c3..dfab09d08aa 100644 --- a/tests/test-webapps/test-jetty-webapp/src/main/java/com/acme/Dump.java +++ b/tests/test-webapps/test-jetty-webapp/src/main/java/com/acme/Dump.java @@ -29,6 +29,7 @@ import java.io.Reader; import java.lang.reflect.Array; import java.lang.reflect.Field; import java.net.URL; +import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.Enumeration; @@ -54,6 +55,7 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponseWrapper; +import javax.servlet.http.Part; /** @@ -579,6 +581,27 @@ public class Dump extends HttpServlet } } + try + { + Collection parts = request.getParts(); + if (parts!=null && !parts.isEmpty()) + { + pout.write("\n"); + pout.write("
Parts:
"); + for (Part p : parts) + { + pout.write("\n"); + pout.write(""+notag(p.getName())+": "); + pout.write(""+p+""); + } + } + } + catch(ServletException e) + { + pout.write("\n"); + pout.write("
No Parts!
"); + } + pout.write("\n"); pout.write("
Cookies:
"); Cookie[] cookies = request.getCookies(); diff --git a/tests/test-webapps/test-jetty-webapp/src/main/webapp/WEB-INF/web.xml b/tests/test-webapps/test-jetty-webapp/src/main/webapp/WEB-INF/web.xml index bf3f3302d9b..507771f7dbe 100644 --- a/tests/test-webapps/test-jetty-webapp/src/main/webapp/WEB-INF/web.xml +++ b/tests/test-webapps/test-jetty-webapp/src/main/webapp/WEB-INF/web.xml @@ -46,21 +46,6 @@ /* - - - MultiPart - org.eclipse.jetty.servlets.MultiPartFilter - true - - deleteFiles - true - - - - MultiPart - /dump/* - - Login com.acme.LoginServlet @@ -90,6 +75,10 @@ 1 true admin + + upload + 4096 + From 92f44389b9362c2afe2c73ae4c0ddd7239f833ae Mon Sep 17 00:00:00 2001 From: Lachlan Roberts Date: Wed, 4 Apr 2018 12:00:11 +1000 Subject: [PATCH 50/50] fixed value of public static String __MULTIPARTS Signed-off-by: Lachlan Roberts --- .../src/main/java/org/eclipse/jetty/server/Request.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java index ad1377d053a..ae7d629e7a4 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java @@ -133,7 +133,7 @@ import org.eclipse.jetty.util.log.Logger; public class Request implements HttpServletRequest { public static final String __MULTIPART_CONFIG_ELEMENT = "org.eclipse.jetty.multipartConfig"; - public static final String __MULTIPARTS = "org.eclipse.jetty.multiPartInputStream"; + public static final String __MULTIPARTS = "org.eclipse.jetty.multiParts"; private static final Logger LOG = Log.getLogger(Request.class); private static final Collection __defaultLocale = Collections.singleton(Locale.getDefault());