2020import lombok .Data ;
2121import org .eclipse .jetty .util .IO ;
2222
23+
2324@ Data
2425public class MultipartParser {
25- private Scanner scanner ;
26- private String boundary = "" ;
27- private HashMap <String , String > headers = new HashMap <String , String >();
26+ private byte [] boundary ;
27+ private byte [] finalBoundary ;
2828 private byte [] content ;
29- private String contentString ;
30- public boolean noMoreParts = false ;
29+ private byte [] responseContent ;
30+ private HashMap <String , String > headers = new HashMap <String , String >();
31+ private ArrayList <byte []> sections = new ArrayList <byte []>();
32+ private final byte [] CONTENT_DELIMITER = ("\r \n \r \n " ).getBytes ();
33+
34+ public MultipartParser (byte [] responseContent , String boundary ) throws IOException {
35+ this .responseContent = responseContent ;
36+ this .boundary = ("--" + boundary ).getBytes ();
37+ this .finalBoundary = ("--" + boundary + "--" ).getBytes ();
38+ splitIntoParts ();
39+ }
40+
41+ /**
42+ * Code to find the index of a particular byte[] inside a larger byte[]
43+ * `indexOf` and `computeFailure` taken from StackOverflow user janko. Original response can be found at this link:
44+ * https://stackoverflow.com/questions/1507780/searching-for-a-sequence-of-bytes-in-a-binary-file-with-java
45+ */
46+ private int indexOf (byte [] data , byte [] pattern ) {
47+ int [] failure = computeFailure (pattern );
48+
49+ int j = 0 ;
50+ if (data .length == 0 ) return -1 ;
51+
52+ for (int i = 0 ; i < data .length ; i ++) {
53+ while (j > 0 && pattern [j ] != data [i ]) {
54+ j = failure [j - 1 ];
55+ }
56+ if (pattern [j ] == data [i ]) { j ++; }
57+ if (j == pattern .length ) {
58+ return i - pattern .length + 1 ;
59+ }
60+ }
61+ return -1 ;
62+ }
63+
64+ /**
65+ * Computes the failure function using a boot-strapping process,
66+ * where the pattern is matched against itself.
67+ */
68+ private int [] computeFailure (byte [] pattern ) {
69+ int [] failure = new int [pattern .length ];
70+
71+ int j = 0 ;
72+ for (int i = 1 ; i < pattern .length ; i ++) {
73+ while (j > 0 && pattern [j ] != pattern [i ]) {
74+ j = failure [j - 1 ];
75+ }
76+ if (pattern [j ] == pattern [i ]) {
77+ j ++;
78+ }
79+ failure [i ] = j ;
80+ }
81+
82+ return failure ;
83+ }
84+
85+ private void splitIntoParts () {
86+ byte [] beforeFinalBoundary = Arrays .copyOfRange (responseContent , 0 , indexOf (responseContent , finalBoundary ));
87+
88+ int index ;
89+ while ((index = indexOf (beforeFinalBoundary , boundary )) >= 0 ) {
90+ sections .add (Arrays .copyOfRange (beforeFinalBoundary , 0 , index ));
91+ beforeFinalBoundary = Arrays .copyOfRange (beforeFinalBoundary , index + this .boundary .length , beforeFinalBoundary .length );
92+ }
93+ while (beforeFinalBoundary [beforeFinalBoundary .length - 1 ] == (byte ) '\n' || beforeFinalBoundary [beforeFinalBoundary .length - 1 ] == (byte ) '\r' ) {
94+ beforeFinalBoundary = Arrays .copyOfRange (beforeFinalBoundary , 0 , beforeFinalBoundary .length - 1 );
95+ }
96+ sections .add (beforeFinalBoundary );
97+ }
3198
32- public MultipartParser (String contentString , String boundary ) throws IOException {
33- this .contentString = contentString ;
34- this .scanner = new Scanner (contentString );
35- this .boundary = "--" + boundary ;
99+ private ArrayList <byte []> splitDelimited (byte [] original , byte [] delimiter ) {
100+ ArrayList <byte []> parts = new ArrayList <byte []>();
101+
102+ int index ;
103+ while ((index = indexOf (original , delimiter )) >= 0 ) {
104+ parts .add (Arrays .copyOfRange (original , 0 , index ));
105+ original = Arrays .copyOfRange (original , index + delimiter .length , original .length );
106+ }
107+ while (original [original .length - 1 ] == (byte ) '\n' || original [original .length - 1 ] == (byte ) '\r' ) {
108+ original = Arrays .copyOfRange (original , 0 , original .length - 1 );
109+ }
110+ parts .add (original );
111+
112+ return parts ;
36113 }
37114
38- public void nextPart () throws IOException {
115+ public void parsePart (int i ) throws IOException {
116+ ArrayList <byte []> sectionParts = splitDelimited (sections .get (i ), CONTENT_DELIMITER );
117+ Scanner scanner = new Scanner (new String (sectionParts .get (0 )));
118+
39119 String line = scanner .nextLine ();
40120
41121 // Check if the first line is "\r\n" or one of the headers
@@ -62,16 +142,18 @@ public void nextPart() throws IOException {
62142 }
63143 }
64144
65- // Read in the content
66- String contentString = "" ;
67- while (scanner .hasNextLine () && !(line = scanner .nextLine ()).equals (boundary )) {
68- if (line .equals (boundary + "--" )) {
69- noMoreParts = true ;
70- break ;
145+ if (headers .get ("Content-Type" ).contains ("application/json" )) {
146+ scanner = new Scanner (new String (sectionParts .get (1 )));
147+
148+ // Read in the content
149+ String contentString = "" ;
150+ while (scanner .hasNextLine () && !(line = scanner .nextLine ()).equals (boundary )) {
151+ contentString += line ;
71152 }
72- contentString += line ;
153+ content = contentString .getBytes ();
154+ }
155+ else {
156+ content = sectionParts .get (1 );
73157 }
74-
75- content = contentString .getBytes ();
76158 }
77159}
0 commit comments