Skip to content

Commit 11936f5

Browse files
committed
fix: Close HttpExchange after sending one-shot or streaming responses
1 parent 6766e30 commit 11936f5

1 file changed

Lines changed: 34 additions & 9 deletions

File tree

src/main/java/com/retailsvc/http/internal/DefaultResponseBuilder.java

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import com.retailsvc.http.ResponseBuilder;
44
import com.retailsvc.http.TypeMapper;
55
import com.sun.net.httpserver.HttpExchange;
6+
import java.io.FilterOutputStream;
67
import java.io.IOException;
78
import java.io.OutputStream;
89
import java.nio.charset.StandardCharsets;
@@ -41,18 +42,22 @@ public ResponseBuilder contentType(String contentType) {
4142
@Override
4243
public void empty() throws IOException {
4344
terminate();
44-
applyHeaders();
45-
exchange.sendResponseHeaders(status, -1);
45+
try (exchange) {
46+
applyHeaders();
47+
exchange.sendResponseHeaders(status, -1);
48+
}
4649
}
4750

4851
@Override
4952
public void bytes(byte[] body) throws IOException {
5053
terminate();
51-
applyHeaders();
52-
exchange.sendResponseHeaders(status, body.length == 0 ? -1 : body.length);
53-
if (body.length > 0) {
54-
try (OutputStream out = exchange.getResponseBody()) {
55-
out.write(body);
54+
try (exchange) {
55+
applyHeaders();
56+
exchange.sendResponseHeaders(status, body.length == 0 ? -1 : body.length);
57+
if (body.length > 0) {
58+
try (OutputStream out = exchange.getResponseBody()) {
59+
out.write(body);
60+
}
5661
}
5762
}
5863
}
@@ -83,7 +88,7 @@ public OutputStream stream() throws IOException {
8388
terminate();
8489
applyHeaders();
8590
exchange.sendResponseHeaders(status, 0);
86-
return exchange.getResponseBody();
91+
return closingExchange(exchange.getResponseBody());
8792
}
8893

8994
@Override
@@ -94,7 +99,27 @@ public OutputStream stream(long length) throws IOException {
9499
terminate();
95100
applyHeaders();
96101
exchange.sendResponseHeaders(status, length);
97-
return exchange.getResponseBody();
102+
return closingExchange(exchange.getResponseBody());
103+
}
104+
105+
/**
106+
* Wraps the response body so the underlying {@link HttpExchange} is closed once the caller closes
107+
* the stream.
108+
*/
109+
private OutputStream closingExchange(OutputStream body) {
110+
return new FilterOutputStream(body) {
111+
@Override
112+
public void write(byte[] b, int off, int len) throws IOException {
113+
out.write(b, off, len);
114+
}
115+
116+
@Override
117+
public void close() throws IOException {
118+
try (exchange) {
119+
super.close();
120+
}
121+
}
122+
};
98123
}
99124

100125
private void terminate() {

0 commit comments

Comments
 (0)