Skip to content
This repository was archived by the owner on Jul 31, 2022. It is now read-only.

Commit fe4f21a

Browse files
authored
Add multipart/form-data class. Fixed map issue. (#105)
* Add multipart/form-data class and subclasses * Added required documentation * Bug fixes, added required tests * Added negative test
1 parent 37692cc commit fe4f21a

File tree

8 files changed

+450
-38
lines changed

8 files changed

+450
-38
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
package com.kttdevelopment.simplehttpserver;
2+
3+
import java.nio.charset.StandardCharsets;
4+
import java.util.*;
5+
6+
/**
7+
* This class represents on set of headers and parameters in a multipart/form-data that is expected of a file input.
8+
*
9+
* @see MultipartFormData
10+
* @see Record
11+
* @see com.kttdevelopment.simplehttpserver.Record.Header
12+
* @since 4.0.0
13+
* @version 4.0.0
14+
* @author Ktt Development
15+
*/
16+
public class FileRecord extends Record {
17+
18+
private final String fileName, contentType;
19+
private final byte[] bytes;
20+
21+
/**
22+
* Creates a record from a map entry. Throws a {@link NullPointerException} if the entry doesn't have all the required fields for a {@link Record#Record(Map.Entry)}; and a filename and Content-Type field.
23+
*
24+
* @param entry map entry
25+
*
26+
* @since 4.0.0
27+
* @author Ktt Development
28+
*/
29+
@SuppressWarnings("rawtypes")
30+
FileRecord(final Map.Entry<String,Map> entry){
31+
super(entry);
32+
33+
Header header = Objects.requireNonNull(getHeader("Content-Disposition"));
34+
fileName = Objects.requireNonNull(header.getParameter("filename"));
35+
header = Objects.requireNonNull(getHeader("Content-Type"));
36+
contentType = Objects.requireNonNull(header.getHeaderValue());
37+
bytes = getValue().getBytes(StandardCharsets.UTF_8);
38+
}
39+
40+
/**
41+
* Returns the file name.
42+
*
43+
* @return file name
44+
*
45+
* @since 4.0.0
46+
* @author Ktt Development
47+
*/
48+
public final String getFileName(){
49+
return fileName;
50+
}
51+
52+
/**
53+
* Returns the content type of the file.
54+
*
55+
* @return content type
56+
*
57+
* @since 4.0.0
58+
* @author Ktt Development
59+
*/
60+
public final String getContentType(){
61+
return contentType;
62+
}
63+
64+
/**
65+
* Returns the file as bytes.
66+
*
67+
* @return file in bytes
68+
*
69+
* @see #getValue()
70+
* @since 4.0.0
71+
* @author Ktt Development
72+
*/
73+
public final byte[] getBytes(){
74+
return bytes;
75+
}
76+
77+
@Override
78+
public String toString(){
79+
return
80+
"FileRecord" + '{' +
81+
"name" + '=' + '\'' + getName() + '\'' + ", " +
82+
"fileName" + '=' + '\'' + fileName + '\'' + ", " +
83+
"contentType" + '=' + '\'' + contentType + '\'' + ", " +
84+
"value" + '=' + '\'' + Arrays.toString(bytes) + '\'' + ", " +
85+
"headers" + '=' + getHeaders() +
86+
'}';
87+
}
88+
89+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
package com.kttdevelopment.simplehttpserver;
2+
3+
import java.util.Collections;
4+
import java.util.Map;
5+
6+
/**
7+
* This class represents a POST request map as a multipart/form-data.
8+
*
9+
* @see SimpleHttpExchange
10+
* @see Record
11+
* @see FileRecord
12+
* @since 4.0.0
13+
* @version 4.0.0
14+
* @author Ktt Development
15+
*/
16+
public class MultipartFormData {
17+
18+
private final Map<String,Record> records;
19+
20+
/**
21+
* Creates a multipart/form-data.
22+
*
23+
* @param records map of records and record keys
24+
*
25+
* @see Record
26+
* @see FileRecord
27+
* @since 4.0.0
28+
* @author Ktt Development
29+
*/
30+
MultipartFormData(final Map<String,Record> records){
31+
this.records = Collections.unmodifiableMap(records);
32+
}
33+
34+
/**
35+
* Returns the record for key or null if none is found. If the record is supposed to be a FileRecord then cast it to {@link FileRecord}.
36+
*
37+
* @param key record key
38+
* @return {@link Record} or {@link FileRecord} or null if none is found.
39+
*
40+
* @see Record
41+
* @see FileRecord
42+
* @since 4.0.0
43+
* @author Ktt Development
44+
*/
45+
public final Record getRecord(final String key){
46+
return records.get(key);
47+
}
48+
49+
/**
50+
* Returns all the records in the multipart/form-data;
51+
*
52+
* @return map of all records
53+
*
54+
* @see Record
55+
* @see FileRecord
56+
* @since 4.0.0
57+
* @author Ktt Development
58+
*/
59+
public final Map<String,Record> getRecords(){
60+
return records;
61+
}
62+
63+
@Override
64+
public String toString(){
65+
return
66+
"MultipartFormData" + '{' +
67+
"record" + '=' + records +
68+
'}';
69+
}
70+
71+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
package com.kttdevelopment.simplehttpserver;
2+
3+
import java.util.*;
4+
5+
/**
6+
* This class represents one set of headers and parameters in a multipart/form-data.
7+
*
8+
* @see MultipartFormData
9+
* @see FileRecord
10+
* @see Header
11+
* @since 4.0.0
12+
* @version 4.0.0
13+
* @author Ktt Development
14+
*/
15+
public class Record {
16+
17+
private final Map<String,Header> headers;
18+
private final String name, value;
19+
20+
/**
21+
* Creates a record from a map entry. Throws a {@link NullPointerException} if the entry doesn't have a: header-name, header-value, and parameters field.
22+
*
23+
* @param entry map entry
24+
*
25+
* @since 4.0.0
26+
* @author Ktt Development
27+
*/
28+
@SuppressWarnings({"rawtypes", "unchecked"})
29+
Record(final Map.Entry<String,Map> entry){
30+
name = Objects.requireNonNull(entry.getKey());
31+
value = Objects.requireNonNull(entry.getValue().get("value").toString());
32+
33+
final Map<String,Header> headers = new HashMap<>();
34+
Objects.requireNonNull((Map<String,Map>) entry.getValue().get("headers")).forEach((k, v) -> headers.put(
35+
k,
36+
new Header(
37+
Objects.requireNonNull(v.get("header-name")).toString(),
38+
Objects.requireNonNull(v.get("header-value")).toString(),
39+
(Map) Objects.requireNonNull(v.get("parameters"))
40+
)
41+
));
42+
this.headers = Collections.unmodifiableMap(headers);
43+
}
44+
45+
/**
46+
* Returns form input name.
47+
*
48+
* @return form input name
49+
*
50+
* @since 4.0.0
51+
* @author Ktt Development
52+
*/
53+
public final String getName(){
54+
return name;
55+
}
56+
57+
/**
58+
* Returns a specified header.
59+
*
60+
* @param key header key
61+
* @return header
62+
*
63+
* @see Header
64+
* @see #getHeaders()
65+
* @since 4.0.0
66+
* @author Ktt Development
67+
*/
68+
public final Header getHeader(final String key){
69+
return headers.get(key);
70+
}
71+
72+
/**
73+
* Returns all the headers.
74+
*
75+
* @return headers
76+
*
77+
* @see Header
78+
* @see #getHeader(String)
79+
* @since 4.0.0
80+
* @author Ktt Development
81+
*/
82+
public final Map<String,Header> getHeaders(){
83+
return headers;
84+
}
85+
86+
/**
87+
* Returns the value as a string.
88+
*
89+
* @return value
90+
*
91+
* @since 4.0.0
92+
* @author Ktt Development
93+
*/
94+
public final String getValue(){
95+
return value;
96+
}
97+
98+
@Override
99+
public String toString(){
100+
return
101+
"Record" + '{' +
102+
"name" + '=' + '\'' + name + '\'' + ", " +
103+
"value" + '=' + '\'' + value + '\'' + ", " +
104+
"headers" + '=' + headers +
105+
'}';
106+
}
107+
108+
/**
109+
* Represents a header in a multipart/form-data.
110+
*
111+
* @since 4.0.0
112+
* @version 4.0.0
113+
* @author Ktt Development
114+
*/
115+
public static class Header {
116+
117+
private final String headerName, headerValue;
118+
private final Map<String,String> headerParams;
119+
120+
/**
121+
* Creates header.
122+
*
123+
* @param headerName header name
124+
* @param headerValue header value
125+
* @param headerParams header parameters
126+
*
127+
* @since 4.0.0
128+
* @author Ktt Development
129+
*/
130+
Header(final String headerName, final String headerValue, final Map<String,String> headerParams){
131+
this.headerName = headerName;
132+
this.headerValue = headerValue;
133+
this.headerParams = Collections.unmodifiableMap(headerParams);
134+
}
135+
136+
/**
137+
* Returns the header name
138+
*
139+
* @return header name
140+
*
141+
* @since 4.0.0
142+
* @author Ktt Development
143+
*/
144+
public final String getHeaderName(){
145+
return headerName;
146+
}
147+
148+
/**
149+
* Returns the header value
150+
*
151+
* @return header value
152+
*
153+
* @since 4.0.0
154+
* @author Ktt Development
155+
*/
156+
public final String getHeaderValue(){
157+
return headerValue;
158+
}
159+
160+
/**
161+
* Returns specific header parameter.
162+
*
163+
* @param key parameter key
164+
* @return parameter value
165+
*
166+
* @see #getParameters()
167+
* @since 4.0.0
168+
* @author Ktt Development
169+
*/
170+
public final String getParameter(final String key){
171+
return headerParams.get(key);
172+
}
173+
174+
/**
175+
* Returns all the header parameters.
176+
*
177+
* @return header parameters
178+
*
179+
* @see #getParameter(String)
180+
* @since 4.0.0
181+
* @author Ktt Development
182+
*/
183+
public final Map<String,String> getParameters(){
184+
return headerParams;
185+
}
186+
187+
@Override
188+
public String toString(){
189+
return
190+
"Header" + '{' +
191+
"headerName" + '=' + '\'' + headerName + '\'' + ", " +
192+
"headerValue" + '=' + '\'' + headerValue + '\'' + ", " +
193+
"headerParams" + '=' + headerParams +
194+
'}';
195+
}
196+
197+
}
198+
199+
}

0 commit comments

Comments
 (0)