Skip to content

Commit 9615500

Browse files
committed
Add body-parser
1 parent 8cf57c0 commit 9615500

File tree

6 files changed

+168
-3
lines changed

6 files changed

+168
-3
lines changed

src/express/http/Request.java

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import com.sun.net.httpserver.Headers;
44
import com.sun.net.httpserver.HttpExchange;
55
import express.http.cookie.Cookie;
6+
import express.multipart.MultiPartData;
67

78
import java.io.IOException;
89
import java.io.InputStream;
@@ -21,22 +22,27 @@
2122
*/
2223
public class Request {
2324

24-
private final HttpExchange HTTP_EXCHANGE;
2525
private final URI URI;
26+
private final HttpExchange HTTP_EXCHANGE;
2627
private final InputStream BODY;
2728
private final Headers HEADER;
29+
private final String CONTENT_TYPE;
2830

2931
private final HashMap<String, Cookie> COOKIES;
3032
private final HashMap<String, String> QUERYS;
33+
private HashMap<String, MultiPartData> formData;
3134
private HashMap<String, String> params;
3235

3336
public Request(HttpExchange exchange) {
3437
this.HTTP_EXCHANGE = exchange;
3538
this.URI = exchange.getRequestURI();
3639
this.HEADER = exchange.getRequestHeaders();
3740
this.BODY = exchange.getRequestBody();
41+
this.CONTENT_TYPE = HEADER.get("Content-Type").get(0);
3842

43+
this.formData = new HashMap<>();
3944
this.params = new HashMap<>();
45+
4046
this.QUERYS = parseRawQuery(exchange.getRequestURI());
4147
this.COOKIES = parseCookies(exchange.getRequestHeaders());
4248
}
@@ -100,7 +106,7 @@ public String getHost() {
100106
* @return The request content-type.
101107
*/
102108
public String getContentType() {
103-
return HEADER.get("Content-Type").get(0);
109+
return CONTENT_TYPE;
104110
}
105111

106112
/**
@@ -124,6 +130,14 @@ public String getMethod() {
124130
return HTTP_EXCHANGE.getRequestMethod();
125131
}
126132

133+
public HashMap<String, MultiPartData> getFormData() {
134+
return this.formData;
135+
}
136+
137+
public void setFormData(HashMap<String, MultiPartData> formData) {
138+
this.formData = formData;
139+
}
140+
127141
/**
128142
* Returns an param from a dynamic url.
129143
* see README
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package express.middleware;
2+
3+
import express.events.HttpRequest;
4+
import express.http.Request;
5+
import express.http.Response;
6+
import express.multipart.MultiPartData;
7+
import express.multipart.MultiPartStream;
8+
9+
import java.io.IOException;
10+
import java.util.HashMap;
11+
12+
public class BodyParser implements HttpRequest {
13+
14+
private final long MAX_SIZE;
15+
16+
public BodyParser() {
17+
this.MAX_SIZE = -1;
18+
}
19+
20+
public BodyParser(long maxFieldSize) {
21+
this.MAX_SIZE = maxFieldSize;
22+
}
23+
24+
@Override
25+
public void handle(Request req, Response res) {
26+
27+
HashMap<String, MultiPartData> dataMap = new HashMap<>();
28+
try {
29+
String boundary = "--" + req.getContentType().replaceAll("multipart/form-data; boundary=", "") + "\r\n";
30+
MultiPartStream stream = new MultiPartStream(req.getBody(), boundary.getBytes(), MAX_SIZE);
31+
MultiPartData data;
32+
33+
while ((data = stream.read()) != null) {
34+
dataMap.put(data.getHead(), data);
35+
}
36+
37+
req.setFormData(dataMap);
38+
} catch (IOException e) {
39+
// TODO: Handle error
40+
e.printStackTrace();
41+
}
42+
}
43+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package express.multipart;
2+
3+
public class MultiPartData {
4+
5+
private final MultiPartStatus MPS;
6+
private final String HEAD;
7+
private final byte[] DATA;
8+
9+
public MultiPartData(MultiPartStatus mps, String head, byte[] data) {
10+
this.MPS = mps;
11+
this.HEAD = head;
12+
this.DATA = data;
13+
}
14+
15+
public MultiPartStatus getStatus() {
16+
return MPS;
17+
}
18+
19+
public String getHead() {
20+
return HEAD;
21+
}
22+
23+
public byte[] getBytes() {
24+
return DATA;
25+
}
26+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package express.multipart;
2+
3+
public enum MultiPartStatus {
4+
OUT_OF_SIZE, OK
5+
}
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
package express.multipart;
2+
3+
import java.io.ByteArrayOutputStream;
4+
import java.io.IOException;
5+
import java.io.InputStream;
6+
import java.util.Arrays;
7+
8+
public class MultiPartStream {
9+
10+
private final ByteArrayOutputStream BUFFER = new ByteArrayOutputStream();
11+
private final InputStream IS;
12+
private final byte[] BOUNDARY;
13+
private final long MAX_SIZE;
14+
15+
public MultiPartStream(InputStream body, byte[] boundary, long maxSize) {
16+
this.IS = body;
17+
this.BOUNDARY = boundary;
18+
this.MAX_SIZE = maxSize;
19+
}
20+
21+
public MultiPartData read() throws IOException {
22+
byte[] buffer = new byte[BOUNDARY.length];
23+
ByteArrayOutputStream b = new ByteArrayOutputStream();
24+
String head = null;
25+
26+
int i; // Read index
27+
int il = 0; // Last byte
28+
int boundaryIndex = 0; // Boundary index to detect boundary
29+
30+
// Read up to next boundary
31+
while ((i = IS.read()) != -1) {
32+
33+
// Check if the byte is a boundary start
34+
if ((byte) i == BOUNDARY[boundaryIndex]) {
35+
buffer[boundaryIndex] = (byte) i;
36+
boundaryIndex++;
37+
38+
// Check if the boundary is fully matched
39+
if (boundaryIndex == BOUNDARY.length)
40+
break;
41+
42+
} else {
43+
44+
// Check if the buffer contains data
45+
if (boundaryIndex > 0)
46+
b.write(Arrays.copyOf(buffer, boundaryIndex - 1));
47+
b.write(i);
48+
49+
// Check if the end of the head is reached
50+
if (head == null && i == '\n' && il == '\r') {
51+
head = new String(b.toByteArray());
52+
b.reset();
53+
} else if (head != null) {
54+
55+
// Check if there is an limit
56+
if (MAX_SIZE > 0 && b.size() > MAX_SIZE) {
57+
return new MultiPartData(MultiPartStatus.OUT_OF_SIZE, head, new byte[0]);
58+
}
59+
}
60+
61+
// Reset index, save last byte
62+
boundaryIndex = 0;
63+
il = i;
64+
}
65+
}
66+
67+
// Check if the end is reached
68+
if (i == -1)
69+
return null;
70+
71+
if (b.size() == 0)
72+
return read();
73+
74+
return new MultiPartData(MultiPartStatus.OK, head, b.toByteArray());
75+
}
76+
77+
78+
}

src/test/Use.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
import express.Express;
44
import express.middleware.Static;
5-
65
import java.io.IOException;
76

87
public class Use {

0 commit comments

Comments
 (0)