package io.myweb;
import io.myweb.http.Response;
import java.io.*;
public class ResponseWriter {
public static final int BUFFER_LENGTH = 32 * 1024;
private final OutputStream os;
private boolean closed = false;
public ResponseWriter(OutputStream os) throws IOException {
this.os = os;
}
public void close() throws IOException {
close(null);
}
public synchronized void close(Response r) throws IOException {
if (!isClosed()) {
os.flush();
closed = true;
if (r != null) r.onClose();
}
}
public boolean isClosed() {
return closed;
}
public void write(Response response) throws IOException {
if (!isClosed() && response!=null) {
if (response.getBody() instanceof InputStream) writeInputStream(response);
else writeObject(response);
}
}
private void writeObject(Response response) throws IOException {
if (response.getBody() != null) {
byte[] body = response.getBody().toString().getBytes();
response.withLength(body.length);
os.write(response.toString().getBytes());
os.write(body);
} else {
response.withLength(0);
os.write(response.toString().getBytes());
}
}
private void writeInputStream(Response response) throws IOException {
InputStream is = (InputStream) response.getBody();
final boolean chunked = !response.hasLength();
if (chunked) response.withChunks();
os.write(response.toString().getBytes());
copy(is, os, chunked);
is.close();
}
private long copy(InputStream from, OutputStream to, boolean chunkEncode) throws IOException {
byte[] buf = new byte[BUFFER_LENGTH];
long total = 0;
while (true) {
int r = -1;
boolean tryAgain = true;
while (tryAgain) {
try {
r = from.read(buf);
} catch (IOException e) {
if (e.getMessage().startsWith("Try again")) continue;
e.printStackTrace();
}
tryAgain = false;
}
if (r == -1 || Thread.interrupted()) {
if (chunkEncode) to.write("0\r\n\r\n".getBytes());
break;
}
if(chunkEncode) {
to.write((Integer.toHexString(r)+"\r\n").getBytes());
}
to.write(buf, 0, r);
if(chunkEncode) {
to.write("\r\n".getBytes());
}
total += r;
}
return total;
}
}