package com.librato.metrics.client;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Map;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
public class DefaultPoster implements IPoster {
private static final Logger log = LoggerFactory.getLogger(DefaultPoster.class);
@Override
public HttpResponse post(String uri, Duration connectTimeout, Duration readTimeout, Map<String, String> headers, byte[] payload) {
try {
HttpURLConnection connection = open(uri);
final int responseCode;
final byte[] responseBody;
connection.setDoOutput(true);
connection.setDoInput(true);
connection.setConnectTimeout((int) connectTimeout.to(MILLISECONDS));
connection.setReadTimeout((int) readTimeout.to(MILLISECONDS));
connection.setRequestMethod("POST");
connection.setInstanceFollowRedirects(false);
for (String header : headers.keySet()) {
connection.setRequestProperty(header, headers.get(header));
}
connection.connect();
OutputStream outputStream = connection.getOutputStream();
try {
outputStream.write(payload);
} finally {
close(outputStream);
}
responseCode = connection.getResponseCode();
InputStream responseStream;
if (responseCode / 100 == 2) {
responseStream = connection.getInputStream();
} else {
responseStream = connection.getErrorStream();
}
if(responseStream == null) {
log.warn("responseStream null for {} responseCode {}", uri, responseCode);
responseBody = new byte[0];
} else {
responseBody = readResponse(responseStream);
}
return new HttpResponse() {
@Override
public int getResponseCode() {
return responseCode;
}
@Override
public byte[] getResponseBody() {
return responseBody;
}
};
} catch (Exception e) {
throw new RuntimeException(e);
}
}
HttpURLConnection open(String url) throws IOException {
try {
return (HttpURLConnection) new URL(url).openConnection();
} catch (ClassCastException ignore) {
throw new RuntimeException("URL " + url + " must use either http or https");
}
}
private byte[] readResponse(InputStream in) throws IOException {
try {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = in.read(buffer)) > 0) {
bos.write(buffer, 0, bytesRead);
}
return bos.toByteArray();
} finally {
close(in);
}
}
void close(Closeable closeable) {
try {
if (closeable != null) {
closeable.close();
}
} catch (IOException e) {
log.warn("Could not close " + closeable, e);
}
}
}