package org.limewire.swarm.http;
import java.io.IOException;
import java.util.Arrays;
import org.apache.http.Header;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.nio.IOControl;
import org.apache.http.protocol.ExecutionContext;
import org.apache.http.protocol.HttpContext;
import org.limewire.collection.Range;
import org.limewire.io.IOUtils;
import org.limewire.logging.Log;
import org.limewire.logging.LogFactory;
public class SwarmHttpUtils {
private static final Log LOG = LogFactory.getLog(SwarmHttpUtils.class);
private SwarmHttpUtils() {
}
/**
* Closes the connection associated with this HttpContext.
*/
public static void closeConnectionFromContext(HttpContext context) {
IOControl ioctrl = (IOControl) context.getAttribute(ExecutionContext.HTTP_CONNECTION);
try {
ioctrl.shutdown();
} catch (IOException ignored) {
LOG.warn("Error shutting down IOControl.", ignored);
}
}
public static Range rangeForContentRange(String headerValue, long contentLength)
throws IOException {
try {
int start = headerValue.indexOf("bytes") + 6; // skip "bytes " or
// "bytes="
int slash = headerValue.indexOf('/');
// if looks like: "bytes */*" or "bytes */10" -- NOT part of the
// spec
if (headerValue.substring(start, slash).equals("*")) {
return Range.createRange(0, contentLength - 1);
}
int dash = headerValue.lastIndexOf("-");
long numBeforeDash = numberFor(headerValue.substring(start, dash));
long numBeforeSlash = numberFor(headerValue.substring(dash + 1, slash));
if (numBeforeSlash < numBeforeDash) {
IOException e = new IOException("invalid range, high (" + numBeforeSlash
+ ") less than low (" + numBeforeDash + ")");
LOG.warn(e.getMessage(), e);
throw e;
}
return Range.createRange(numBeforeDash, numBeforeSlash);
// TODO: Is it necessary to validate the number after the slash
// matches the fileCoordinator's size (or is '*')?
} catch (IndexOutOfBoundsException e) {
IOException ioException = IOUtils.getIOException("Invalid Header: " + headerValue, e);
LOG.warn(ioException.getMessage(), ioException);
throw ioException;
}
}
public static long numberFor(String number) throws IOException {
try {
return Long.parseLong(number);
} catch (NumberFormatException nfe) {
IOException e = IOUtils.getIOException("Invalid number: " + number, nfe);
LOG.warn(e.getMessage(), e);
throw e;
}
}
public static Range parseContentRange(HttpResponse response) throws IOException {
Range actualRange;
Header contentRange = response.getFirstHeader("Content-Range");
Header contentLengthHeader = response.getFirstHeader("Content-Length");
if (contentLengthHeader != null) {
long contentLength = SwarmHttpUtils.numberFor(contentLengthHeader.getValue());
if (contentLength < 0) {
IOException e = new IOException("Invalid content length: " + contentLength);
LOG.warn(e.getMessage(), e);
throw e;
}
if (contentRange != null) {
// If a range exists, that's what we want.
actualRange = SwarmHttpUtils.rangeForContentRange(contentRange.getValue(),
contentLength);
} else {
// If no range exists, assume 0 -> contentLength
actualRange = Range.createRange(0, contentLength - 1);
}
} else if (contentRange == null) {
// Fail miserably.
IOException e = new IOException("No Content Range Found.");
LOG.warn(e.getMessage(), e);
throw e;
} else {
// Fail miserably.
IOException e = new IOException("No content length, though content range existed.");
LOG.warn(e.getMessage(), e);
throw e;
}
return actualRange;
}
public static String logRequest(String message, HttpRequest request) {
String requestLine = request != null ? request.getRequestLine().toString() : "null";
String headers = request != null ? Arrays.asList(request.getAllHeaders()).toString()
: "null";
String log = message + " request : " + requestLine + " headers: " + headers;
return log;
}
public static String logReponse(String message, HttpResponse response) {
String statusLine = response != null ? response.getStatusLine().toString() : "null";
String headers = response != null ? Arrays.asList(response.getAllHeaders()).toString()
: "null";
String log = message + ": " + statusLine + " headers: " + headers;
return log;
}
}