由于用户反馈Gorpo 12 无法下载文件,遂公司买了一个来测试
发现HTTP请求报错:
java.net.ProtocolException: Unexpected status line: gpHttpServer: [04327868][INFO ] conn 0:
/videos/DCIM/100GOPRO/GX012560.MP4 @civetweb.c:17872
通过TCP方式手动请求接口发现其返回如下内容:
gpHttpServer: [UTILS_UpdateRecordingStatus: 94] record mode detected HTTP/1.1 503 Service Unavailable Content-Type: application/json Content-Length: 32 { "message": "Camera is busy" }
返回内容的第一行不包含HTTP状态码,不符合HTTP协议,所以HTTP请求被判定为失败。
后修改为用TCP手动发起HTTP请求并手动解析返回数据:
private Pair<String, String> call(){
String requestString = "GET /gopro/media/list HTTP/1.1\nHost: " + goProIp + ":8080\n\n";
byte[] requestBytes = requestString.getBytes(StandardCharsets.US_ASCII);
try {
Socket socket = new Socket(goProIp, 8080);
OutputStream outputStream = socket.getOutputStream();
outputStream.write(requestBytes);
StringBuilder builder = new StringBuilder();
while (true) {
if (socket.isClosed()) break;
final byte[] buffer = new byte[1024];
InputStream InputStream = socket.getInputStream();
final int len = InputStream.read(buffer);
if (len > 0) {
byte[] sub = new byte[len];
System.arraycopy(buffer, 0, sub, 0, len);
String data = new String(sub);
builder.append(data);
} else {
break;
}
}
String fullData = builder.toString();
Log.e("fullData--" , fullData);
if(TextUtils.isEmpty(fullData)){
return null;
}
int httpIndex = fullData.indexOf("HTTP/");
if(httpIndex < 0) return null;
String realHttpData = fullData.substring(httpIndex);
if(TextUtils.isEmpty(realHttpData)) return null;
int firstSpaceIndex = realHttpData.indexOf(" ");
if(firstSpaceIndex < 0) return null;
String httpCode = realHttpData.substring(firstSpaceIndex + 1, firstSpaceIndex + 4);
if(TextUtils.isEmpty(httpCode)) return null;
//定位body
int doubleCrlfIndex = realHttpData.indexOf("\r\n\r\n");
if(doubleCrlfIndex < 0) return null;
//观察数据发现最后一个字符为换行符\r,所以去掉
String httpBody = realHttpData.substring(doubleCrlfIndex + 4, realHttpData.length() -1);
return new Pair<>(httpCode, httpBody);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
下载文件:
String requestString = "GET /videos/DCIM" + goproUrlString + " HTTP/1.1\nHost: " + goProIp +":8080\n\n";
byte[] requestBytes = requestString.getBytes(StandardCharsets.US_ASCII);
try {
Socket socket;
try{
socket = new Socket(goProIp, 8080);
}catch (Throwable throwable){
throwable.printStackTrace();
return null;
}
OutputStream outputStream = socket.getOutputStream();
outputStream.write(requestBytes);
//接收数据
//接收http头
StringBuilder builder = new StringBuilder();
//接收body
File mFilePath = AlbumUtil.randomCache(strings[0]);
FileOutputStream fileOutputStream = new FileOutputStream(mFilePath);
byte[] buffer = new byte[1024];
InputStream inputStream = socket.getInputStream();
boolean isDoubleCrLfFound = false;
boolean isLastSegmentHasCrOrLf = false;
int lastSegmentCrLfLength = 0;
while (true){
if(socket.isClosed()) break;
int len = inputStream.read(buffer);
if(len > 0){
byte[] sub = new byte[len];
System.arraycopy(buffer, 0, sub, 0, len);
//查找双换行(\r\n\r\n)
if(!isDoubleCrLfFound){
String temString = new String(sub, StandardCharsets.US_ASCII);
builder.append(temString);
//如果前一段包含部分\r\n\r\n
if(isLastSegmentHasCrOrLf && lastSegmentCrLfLength > 0){
if(lastSegmentCrLfLength == 3){
if(temString.charAt(0) == '\n'){
isDoubleCrLfFound = true;
fileOutputStream.write(sub, 1, sub.length - 1);
}
} else if(lastSegmentCrLfLength == 2){
if(temString.startsWith("\r\n")){
isDoubleCrLfFound = true;
fileOutputStream.write(sub, 2, sub.length - 2);
}
} else if(lastSegmentCrLfLength == 1){
if(temString.startsWith("\r\r\n")){
isDoubleCrLfFound = true;
fileOutputStream.write(sub, 3, sub.length - 3);
}
}
}
int doubleCrLfIndex = temString.indexOf("\r\n\r\n");
if(doubleCrLfIndex < 0 && !isDoubleCrLfFound){
//确认是否最后几个字节为双换行的一部分
if(len > 3){
String last3Char = temString.substring(temString.length()-3);
if(last3Char.equals("\r\n\r")){
isLastSegmentHasCrOrLf = true;
lastSegmentCrLfLength = 3;
}else if(last3Char.substring(1).equals("\r\n")){
isLastSegmentHasCrOrLf = true;
lastSegmentCrLfLength = 2;
}else if(last3Char.substring(2).equals("\r")){
isLastSegmentHasCrOrLf = true;
lastSegmentCrLfLength = 1;
}
}
} else {
isDoubleCrLfFound = true;
fileOutputStream.write(sub, doubleCrLfIndex + 4, sub.length - doubleCrLfIndex - 4);
}
}else {
fileOutputStream.write(sub);
}
}else {
break;
}
}
fileOutputStream.close();
String fullData = builder.toString();
Log.e("fullData--" , fullData);
if(TextUtils.isEmpty(fullData)){
return null;
}
int httpIndex = fullData.indexOf("HTTP/");
if(httpIndex < 0) return null;
String realHttpData = fullData.substring(httpIndex);
if(TextUtils.isEmpty(realHttpData)) return null;
int firstSpaceIndex = realHttpData.indexOf(" ");
if(firstSpaceIndex < 0) return null;
String httpCode = realHttpData.substring(firstSpaceIndex + 1, firstSpaceIndex + 4);
if(TextUtils.isEmpty(httpCode) || !httpCode.equals("200")) return null;
if(!mFilePath.isFile() || !mFilePath.exists() || mFilePath.length() < 1){
return null;
}
return mFilePath.getAbsolutePath();
} catch (Exception e) {
e.printStackTrace();
return null;
}