LwHttp: handle 'Connection: close' header

This commit is contained in:
Hannes Janetzek 2014-02-12 01:46:02 +01:00
parent 3409f5ff3c
commit 27153c8093

View File

@ -44,6 +44,8 @@ public class LwHttp {
private final static byte[] HEADER_HTTP_OK = "200 OK".getBytes(); private final static byte[] HEADER_HTTP_OK = "200 OK".getBytes();
//private final static byte[] HEADER_CONTENT_TYPE = "Content-Type".getBytes(); //private final static byte[] HEADER_CONTENT_TYPE = "Content-Type".getBytes();
private final static byte[] HEADER_CONTENT_LENGTH = "Content-Length".getBytes(); private final static byte[] HEADER_CONTENT_LENGTH = "Content-Length".getBytes();
private final static byte[] HEADER_CONNECTION_CLOSE = "Connection: close".getBytes();
private final static int RESPONSE_EXPECTED_LIVES = 100; private final static int RESPONSE_EXPECTED_LIVES = 100;
private final static long RESPONSE_TIMEOUT = (long) 10E9; // 10 second in nanosecond private final static long RESPONSE_TIMEOUT = (long) 10E9; // 10 second in nanosecond
@ -60,6 +62,9 @@ public class LwHttp {
private long mLastRequest = 0; private long mLastRequest = 0;
private SocketAddress mSockAddr; private SocketAddress mSockAddr;
/** Server requested to close the connection */
private boolean mMustClose;
private final byte[] REQUEST_GET_START; private final byte[] REQUEST_GET_START;
private final byte[] REQUEST_GET_END; private final byte[] REQUEST_GET_END;
private final byte[] mRequestBuffer; private final byte[] mRequestBuffer;
@ -119,20 +124,29 @@ public class LwHttp {
} }
public boolean finishedReading() { public boolean finishedReading() {
try {
while (bytesRead < contentLength && read() >= 0);
} catch (IOException e) {
log.debug(e.getMessage());
}
return bytesRead == contentLength; return bytesRead == contentLength;
} }
@Override @Override
public synchronized void mark(int readlimit) { public synchronized void mark(int readlimit) {
if (dbg)
log.debug("mark {}", readlimit);
marked = bytesRead; marked = bytesRead;
super.mark(readlimit); super.mark(readlimit);
} }
@Override @Override
public synchronized long skip(long n) throws IOException { public synchronized long skip(long n) throws IOException {
// Android(4.1.2) image decoder *requires* skip to /* Android(4.1.2) image decoder *requires* skip to
// actually skip the requested amount. * actually skip the requested amount.
// https://code.google.com/p/android/issues/detail?id=6066 * https://code.google.com/p/android/issues/detail?id=6066 */
long sumSkipped = 0L; long sumSkipped = 0L;
while (sumSkipped < n) { while (sumSkipped < n) {
long skipped = super.skip(n - sumSkipped); long skipped = super.skip(n - sumSkipped);
@ -144,18 +158,25 @@ public class LwHttp {
break; // EOF break; // EOF
sumSkipped += 1; sumSkipped += 1;
// was incremented by read() /* was incremented by read() */
bytesRead -= 1; bytesRead -= 1;
} }
if (dbg)
log.debug("skip:{}/{} pos:{}", n, sumSkipped, bytesRead);
bytesRead += sumSkipped; bytesRead += sumSkipped;
return sumSkipped; return sumSkipped;
} }
@Override @Override
public synchronized void reset() throws IOException { public synchronized void reset() throws IOException {
if (dbg)
log.debug("reset");
if (marked >= 0) if (marked >= 0)
bytesRead = marked; bytesRead = marked;
// TODO could check if the mark is already invalid /* TODO could check if the mark is already invalid */
super.reset(); super.reset();
} }
@ -166,6 +187,7 @@ public class LwHttp {
int data = super.read(); int data = super.read();
if (data >= 0)
bytesRead += 1; bytesRead += 1;
if (dbg) if (dbg)
@ -223,12 +245,12 @@ public class LwHttp {
int contentLength = -1; int contentLength = -1;
// header may not be larger than BUFFER_SIZE for this to work /* header may not be larger than BUFFER_SIZE for this to work */
for (; (pos < read) || ((read < BUFFER_SIZE) && for (; (pos < read) || ((read < BUFFER_SIZE) &&
(len = is.read(buf, read, BUFFER_SIZE - read)) >= 0); len = 0) { (len = is.read(buf, read, BUFFER_SIZE - read)) >= 0); len = 0) {
read += len; read += len;
// end of header lines /* end of header lines */
while (end < read && (buf[end] != '\n')) while (end < read && (buf[end] != '\n'))
end++; end++;
@ -239,24 +261,26 @@ public class LwHttp {
if (buf[end] != '\n') if (buf[end] != '\n')
continue; continue;
// empty line (header end) /* empty line (header end) */
if (end - pos == 1) { if (end - pos == 1) {
end += 1; end += 1;
break; break;
} }
if (!ok) { if (!ok) {
// ignore until end of header /* ignore until end of header */
} else if (first) { } else if (first) {
first = false; first = false;
// check only for OK ("HTTP/1.? ".length == 9) /* check only for OK ("HTTP/1.? ".length == 9) */
if (!check(HEADER_HTTP_OK, buf, pos + 9, end)) if (!check(HEADER_HTTP_OK, buf, pos + 9, end))
ok = false; ok = false;
} else if (check(HEADER_CONTENT_LENGTH, buf, pos, end)) { } else if (check(HEADER_CONTENT_LENGTH, buf, pos, end)) {
// parse Content-Length /* parse Content-Length */
contentLength = parseInt(buf, pos + contentLength = parseInt(buf, pos +
HEADER_CONTENT_LENGTH.length + 2, end - 1); HEADER_CONTENT_LENGTH.length + 2, end - 1);
} else if (check(HEADER_CONNECTION_CLOSE, buf, pos, end)) {
mMustClose = true;
} }
//} else if (check(HEADER_CONTENT_TYPE, buf, pos, end)) { //} else if (check(HEADER_CONTENT_TYPE, buf, pos, end)) {
// check that response contains the expected // check that response contains the expected
@ -277,7 +301,7 @@ public class LwHttp {
if (!ok) if (!ok)
return null; return null;
// back to start of content /* back to start of content */
is.reset(); is.reset();
is.mark(0); is.mark(0);
is.skip(end); is.skip(end);
@ -298,10 +322,10 @@ public class LwHttp {
} }
if (mSocket == null) { if (mSocket == null) {
// might throw IOException /* might throw IOException */
lwHttpConnect(); lwHttpConnect();
// TODO parse from header /* TODO parse from header */
mMaxReq = RESPONSE_EXPECTED_LIVES; mMaxReq = RESPONSE_EXPECTED_LIVES;
} }
@ -324,7 +348,7 @@ public class LwHttp {
} catch (IOException e) { } catch (IOException e) {
log.debug("recreate connection"); log.debug("recreate connection");
close(); close();
// might throw IOException /* might throw IOException */
lwHttpConnect(); lwHttpConnect();
mCommandStream.write(request, 0, len); mCommandStream.write(request, 0, len);
@ -348,6 +372,7 @@ public class LwHttp {
close(); close();
throw e; throw e;
} }
mMustClose = false;
return true; return true;
} }
@ -379,18 +404,34 @@ public class LwHttp {
mResponseStream.setCache(null); mResponseStream.setCache(null);
if (!mResponseStream.finishedReading()) { if (!mResponseStream.finishedReading()) {
// StringBuffer sb = new StringBuffer();
// try {
// int val;
// while ((val = mResponseStream.read()) >= 0)
// sb.append((char) val);
// } catch (IOException e) {
//
// }
//log.debug("invalid buffer position {}", sb.toString());
log.debug("invalid buffer position"); log.debug("invalid buffer position");
close(); close();
return false; return true;
} }
if (!success) { if (!success) {
close(); close();
return false; return false;
} }
if (mMustClose) {
close();
return true; return true;
} }
// write (positive) integer to byte array return true;
}
/** write (positive) integer to byte array */
public static int writeInt(int val, int pos, byte[] buf) { public static int writeInt(int val, int pos, byte[] buf) {
if (val == 0) { if (val == 0) {
buf[pos] = '0'; buf[pos] = '0';
@ -406,7 +447,7 @@ public class LwHttp {
return pos + i; return pos + i;
} }
// parse (positive) integer from byte array /** parse (positive) integer from byte array */
protected static int parseInt(byte[] buf, int pos, int end) { protected static int parseInt(byte[] buf, int pos, int end) {
int val = 0; int val = 0;
for (; pos < end; pos++) for (; pos < end; pos++)