blob: b82814d11fd47f348cfdbb5f9ccb23cd66f6f7dd [file] [log] [blame]
package com.android.hotspot2.utils;
import android.util.Base64;
import android.util.Log;
import com.android.hotspot2.osu.OSUManager;
import java.io.ByteArrayInputStream;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
public class HTTPResponse implements HTTPMessage {
private final int mStatusCode;
private final Map<String, String> mHeaders = new LinkedHashMap<>();
private final ByteBuffer mBody;
private static final String csIndicator = "charset=";
public HTTPResponse(InputStream in) throws IOException {
int expected = Integer.MAX_VALUE;
int offset = 0;
int body = -1;
byte[] input = new byte[RX_BUFFER];
int statusCode = -1;
int bodyPattern = 0;
while (offset < expected) {
int amount = in.read(input, offset, input.length - offset);
if (amount < 0) {
throw new EOFException();
}
if (body < 0) {
for (int n = offset; n < offset + amount; n++) {
bodyPattern = (bodyPattern << 8) | (input[n] & 0xff);
if (bodyPattern == 0x0d0a0d0a) {
body = n + 1;
statusCode = parseHeader(input, body, mHeaders);
expected = calculateLength(body, mHeaders);
if (expected > input.length) {
input = Arrays.copyOf(input, expected);
}
break;
}
}
}
offset += amount;
if (offset < expected && offset == input.length) {
input = Arrays.copyOf(input, input.length * 2);
}
}
mStatusCode = statusCode;
mBody = ByteBuffer.wrap(input, body, expected - body);
}
private static int parseHeader(byte[] input, int body, Map<String, String> headers)
throws IOException {
String headerText = new String(input, 0, body - BODY_SEPARATOR_LENGTH,
StandardCharsets.ISO_8859_1);
//System.out.println("Received header: " + headerText);
Iterator<String> headerLines = Arrays.asList(headerText.split(CRLF)).iterator();
if (!headerLines.hasNext()) {
throw new IOException("Bad HTTP Request");
}
int statusCode;
String line0 = headerLines.next();
String[] status = line0.split(" ");
if (status.length != 3 || !"HTTP/1.1".equals(status[0])) {
throw new IOException("Bad HTTP Result: " + line0);
}
try {
statusCode = Integer.parseInt(status[1].trim());
} catch (NumberFormatException nfe) {
throw new IOException("Bad HTTP header line: '" + line0 + "'");
}
while (headerLines.hasNext()) {
String line = headerLines.next();
int keyEnd = line.indexOf(':');
if (keyEnd < 0) {
throw new IOException("Bad header line: '" + line + "'");
}
String key = line.substring(0, keyEnd).trim();
String value = line.substring(keyEnd + 1).trim();
headers.put(key, value);
}
return statusCode;
}
private static int calculateLength(int body, Map<String, String> headers) throws IOException {
String contentLength = headers.get(LengthHeader);
if (contentLength == null) {
throw new IOException("No " + LengthHeader);
}
try {
return body + Integer.parseInt(contentLength);
} catch (NumberFormatException nfe) {
throw new IOException("Bad " + LengthHeader + ": " + contentLength);
}
}
public int getStatusCode() {
return mStatusCode;
}
@Override
public Map<String, String> getHeaders() {
return Collections.unmodifiableMap(mHeaders);
}
public String getHeader(String key) {
return mHeaders.get(key);
}
@Override
public InputStream getPayloadStream() {
return new ByteArrayInputStream(mBody.array(), mBody.position(),
mBody.limit() - mBody.position());
}
@Override
public ByteBuffer getPayload() {
return mBody.duplicate();
}
@Override
public ByteBuffer getBinaryPayload() {
byte[] data = new byte[mBody.remaining()];
mBody.duplicate().get(data);
byte[] binary = Base64.decode(data, Base64.DEFAULT);
return ByteBuffer.wrap(binary);
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("Status: ").append(mStatusCode).append(CRLF);
for (Map.Entry<String, String> entry : mHeaders.entrySet()) {
sb.append(entry.getKey()).append(": ").append(entry.getValue()).append(CRLF);
}
sb.append(CRLF);
Charset charset;
try {
charset = Charset.forName(getCharset());
} catch (IllegalArgumentException iae) {
charset = StandardCharsets.ISO_8859_1;
}
sb.append(new String(mBody.array(), mBody.position(),
mBody.limit() - mBody.position(), charset));
return sb.toString();
}
public String getCharset() {
String contentType = mHeaders.get(ContentTypeHeader);
if (contentType == null) {
return null;
}
int csPos = contentType.indexOf(csIndicator);
return csPos < 0 ? null : contentType.substring(csPos + csIndicator.length()).trim();
}
private static boolean equals(byte[] b1, int offset, byte[] pattern) {
for (int n = 0; n < pattern.length; n++) {
if (b1[n + offset] != pattern[n]) {
return false;
}
}
return true;
}
}