Merge ServerProxy into Audinaut
This commit is contained in:
parent
293fa9748c
commit
20e981fe59
|
@ -1,3 +0,0 @@
|
||||||
[submodule "ServerProxy"]
|
|
||||||
path = ServerProxy
|
|
||||||
url = https://github.com/daneren2005/ServerProxy.git
|
|
|
@ -1 +0,0 @@
|
||||||
Subproject commit a4d957353db2634906e0d5099d7a078a111bfab9
|
|
|
@ -46,7 +46,6 @@ android {
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compile project(':Server Proxy')
|
|
||||||
compile fileTree(include: ['*.jar'], dir: 'libs')
|
compile fileTree(include: ['*.jar'], dir: 'libs')
|
||||||
compile 'com.android.support:support-v4:23.4.+'
|
compile 'com.android.support:support-v4:23.4.+'
|
||||||
compile 'com.android.support:appcompat-v7:23.4.+'
|
compile 'com.android.support:appcompat-v7:23.4.+'
|
||||||
|
|
|
@ -31,12 +31,12 @@ import android.os.PowerManager;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import net.nullsum.audinaut.domain.MusicDirectory;
|
import net.nullsum.audinaut.domain.MusicDirectory;
|
||||||
import net.nullsum.audinaut.util.Constants;
|
import net.nullsum.audinaut.util.BufferFile;
|
||||||
import net.nullsum.audinaut.util.SilentBackgroundTask;
|
|
||||||
import net.nullsum.audinaut.util.FileUtil;
|
|
||||||
import net.nullsum.audinaut.util.Util;
|
|
||||||
import net.nullsum.audinaut.util.CacheCleaner;
|
import net.nullsum.audinaut.util.CacheCleaner;
|
||||||
import github.daneren2005.serverproxy.BufferFile;
|
import net.nullsum.audinaut.util.Constants;
|
||||||
|
import net.nullsum.audinaut.util.FileUtil;
|
||||||
|
import net.nullsum.audinaut.util.SilentBackgroundTask;
|
||||||
|
import net.nullsum.audinaut.util.Util;
|
||||||
|
|
||||||
import org.apache.http.Header;
|
import org.apache.http.Header;
|
||||||
|
|
||||||
|
|
|
@ -36,17 +36,17 @@ import net.nullsum.audinaut.domain.MusicDirectory;
|
||||||
import net.nullsum.audinaut.domain.PlayerState;
|
import net.nullsum.audinaut.domain.PlayerState;
|
||||||
import net.nullsum.audinaut.domain.RepeatMode;
|
import net.nullsum.audinaut.domain.RepeatMode;
|
||||||
import net.nullsum.audinaut.receiver.MediaButtonIntentReceiver;
|
import net.nullsum.audinaut.receiver.MediaButtonIntentReceiver;
|
||||||
|
import net.nullsum.audinaut.util.BufferProxy;
|
||||||
|
import net.nullsum.audinaut.util.Constants;
|
||||||
import net.nullsum.audinaut.util.ImageLoader;
|
import net.nullsum.audinaut.util.ImageLoader;
|
||||||
import net.nullsum.audinaut.util.Notifications;
|
import net.nullsum.audinaut.util.Notifications;
|
||||||
import net.nullsum.audinaut.util.SilentBackgroundTask;
|
|
||||||
import net.nullsum.audinaut.util.Constants;
|
|
||||||
import net.nullsum.audinaut.util.ShufflePlayBuffer;
|
import net.nullsum.audinaut.util.ShufflePlayBuffer;
|
||||||
|
import net.nullsum.audinaut.util.SilentBackgroundTask;
|
||||||
import net.nullsum.audinaut.util.SimpleServiceBinder;
|
import net.nullsum.audinaut.util.SimpleServiceBinder;
|
||||||
import net.nullsum.audinaut.util.UpdateHelper;
|
import net.nullsum.audinaut.util.UpdateHelper;
|
||||||
import net.nullsum.audinaut.util.Util;
|
import net.nullsum.audinaut.util.Util;
|
||||||
import net.nullsum.audinaut.util.tags.BastpUtil;
|
import net.nullsum.audinaut.util.tags.BastpUtil;
|
||||||
import net.nullsum.audinaut.view.UpdateView;
|
import net.nullsum.audinaut.view.UpdateView;
|
||||||
import github.daneren2005.serverproxy.BufferProxy;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
/*
|
||||||
|
This file is part of ServerProxy.
|
||||||
|
SocketProxy is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
Subsonic is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
Copyright 2014 (C) Scott Jackson
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.nullsum.audinaut.util;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
public interface BufferFile {
|
||||||
|
File getFile();
|
||||||
|
Long getContentLength();
|
||||||
|
long getEstimatedSize();
|
||||||
|
boolean isWorkDone();
|
||||||
|
void onStart();
|
||||||
|
void onStop();
|
||||||
|
void onResume();
|
||||||
|
}
|
|
@ -0,0 +1,82 @@
|
||||||
|
/*
|
||||||
|
This file is part of ServerProxy.
|
||||||
|
SocketProxy is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
Subsonic is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
Copyright 2014 (C) Scott Jackson
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.nullsum.audinaut.util;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.net.Socket;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
|
||||||
|
import net.nullsum.audinaut.util.FileProxy;
|
||||||
|
|
||||||
|
public class BufferProxy extends FileProxy {
|
||||||
|
private static final String TAG = BufferProxy.class.getSimpleName();
|
||||||
|
protected BufferFile progress;
|
||||||
|
|
||||||
|
public BufferProxy(Context context) {
|
||||||
|
super(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ProxyTask getTask(Socket client) {
|
||||||
|
return new BufferFileTask(client);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBufferFile(BufferFile progress) {
|
||||||
|
this.progress = progress;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected class BufferFileTask extends StreamFileTask {
|
||||||
|
public BufferFileTask(Socket client) {
|
||||||
|
super(client);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
File getFile(String path) {
|
||||||
|
return progress.getFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
Long getContentLength() {
|
||||||
|
Long contentLength = progress.getContentLength();
|
||||||
|
if(contentLength == null && progress.isWorkDone()) {
|
||||||
|
contentLength = file.length();
|
||||||
|
}
|
||||||
|
return contentLength;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
long getFileSize() {
|
||||||
|
return progress.getEstimatedSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStart() {
|
||||||
|
progress.onStart();
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void onStop() {
|
||||||
|
progress.onStop();
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void onResume() {
|
||||||
|
progress.onResume();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isWorkDone() {
|
||||||
|
return progress.isWorkDone() && cbSkip >= file.length();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,219 @@
|
||||||
|
/*
|
||||||
|
This file is part of ServerProxy.
|
||||||
|
SocketProxy is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
Subsonic is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
Copyright 2014 (C) Scott Jackson
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.nullsum.audinaut.util;
|
||||||
|
|
||||||
|
import java.io.BufferedOutputStream;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.net.Socket;
|
||||||
|
import java.net.SocketException;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import net.nullsum.audinaut.util.ServerProxy;
|
||||||
|
|
||||||
|
public class FileProxy extends ServerProxy {
|
||||||
|
private static final String TAG = FileProxy.class.getSimpleName();
|
||||||
|
|
||||||
|
public FileProxy(Context context) {
|
||||||
|
super(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ProxyTask getTask(Socket client) {
|
||||||
|
return new StreamFileTask(client);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected class StreamFileTask extends ProxyTask {
|
||||||
|
File file;
|
||||||
|
|
||||||
|
public StreamFileTask(Socket client) {
|
||||||
|
super(client);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean processRequest() {
|
||||||
|
if(!super.processRequest()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.i(TAG, "Processing request for file " + path);
|
||||||
|
file = getFile(path);
|
||||||
|
if (!file.exists()) {
|
||||||
|
Log.e(TAG, "File " + path + " does not exist");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure to not try to read past where the file is downloaded
|
||||||
|
if(cbSkip != 0 && cbSkip >= file.length()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
File getFile(String path) {
|
||||||
|
return new File(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
Long getContentLength() {
|
||||||
|
return file.length();
|
||||||
|
}
|
||||||
|
long getFileSize() {
|
||||||
|
return file.length();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
Long contentLength = getContentLength();
|
||||||
|
|
||||||
|
// Create HTTP header
|
||||||
|
String headers;
|
||||||
|
if(cbSkip == 0) {
|
||||||
|
headers = "HTTP/1.0 200 OK\r\n";
|
||||||
|
} else {
|
||||||
|
headers = "HTTP/1.0 206 OK\r\n";
|
||||||
|
headers += "Content-Range: bytes " + cbSkip + "-" + (file.length() - 1) + "/";
|
||||||
|
if(contentLength == null) {
|
||||||
|
headers += "*";
|
||||||
|
} else {
|
||||||
|
headers += contentLength;
|
||||||
|
}
|
||||||
|
headers += "\r\n";
|
||||||
|
|
||||||
|
Log.i(TAG, "Streaming starts from: " + cbSkip);
|
||||||
|
}
|
||||||
|
|
||||||
|
String name = file.getPath();
|
||||||
|
int index = name.lastIndexOf('.');
|
||||||
|
String ext = "";
|
||||||
|
if(index != -1) {
|
||||||
|
ext = name.substring(index + 1).toLowerCase();
|
||||||
|
}
|
||||||
|
if("mp3".equals(ext)) {
|
||||||
|
headers += "Content-Type: audio/mpeg\r\n";
|
||||||
|
} else {
|
||||||
|
headers += "Content-Type: " + "application/octet-stream" + "\r\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
long fileSize;
|
||||||
|
if(contentLength == null) {
|
||||||
|
fileSize = getFileSize();
|
||||||
|
} else {
|
||||||
|
fileSize = contentLength;
|
||||||
|
if(cbSkip > 0) {
|
||||||
|
headers += "Content-Length: " + (fileSize - cbSkip) + "\r\n";
|
||||||
|
} else {
|
||||||
|
headers += "Content-Length: " + fileSize + "\r\n";
|
||||||
|
}
|
||||||
|
headers += "Accept-Ranges: bytes \r\n";
|
||||||
|
}
|
||||||
|
Log.i(TAG, "Streaming fileSize: " + fileSize);
|
||||||
|
|
||||||
|
headers += "Connection: close\r\n";
|
||||||
|
headers += "\r\n";
|
||||||
|
|
||||||
|
long cbToSend = fileSize - cbSkip;
|
||||||
|
OutputStream output = null;
|
||||||
|
byte[] buff = new byte[64 * 1024];
|
||||||
|
try {
|
||||||
|
output = new BufferedOutputStream(client.getOutputStream(), 32*1024);
|
||||||
|
output.write(headers.getBytes());
|
||||||
|
|
||||||
|
// Make sure to have file lock
|
||||||
|
onStart();
|
||||||
|
|
||||||
|
// Loop as long as there's stuff to send
|
||||||
|
while (isRunning && !client.isClosed()) {
|
||||||
|
onResume();
|
||||||
|
|
||||||
|
// See if there's more to send
|
||||||
|
int cbSentThisBatch = 0;
|
||||||
|
if (file.exists()) {
|
||||||
|
FileInputStream input = new FileInputStream(file);
|
||||||
|
input.skip(cbSkip);
|
||||||
|
int cbToSendThisBatch = input.available();
|
||||||
|
while (cbToSendThisBatch > 0) {
|
||||||
|
int cbToRead = Math.min(cbToSendThisBatch, buff.length);
|
||||||
|
int cbRead = input.read(buff, 0, cbToRead);
|
||||||
|
if (cbRead == -1) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
cbToSendThisBatch -= cbRead;
|
||||||
|
cbToSend -= cbRead;
|
||||||
|
output.write(buff, 0, cbRead);
|
||||||
|
output.flush();
|
||||||
|
cbSkip += cbRead;
|
||||||
|
cbSentThisBatch += cbRead;
|
||||||
|
}
|
||||||
|
input.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Done regardless of whether or not it thinks it is
|
||||||
|
if(isWorkDone()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we did nothing this batch, block for a second
|
||||||
|
if (cbSentThisBatch == 0) {
|
||||||
|
Log.d(TAG, "Blocking until more data appears (" + cbToSend + ")");
|
||||||
|
Thread.sleep(1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Release file lock, use of stream proxy means nothing else is using it
|
||||||
|
onStop();
|
||||||
|
}
|
||||||
|
catch (SocketException socketException) {
|
||||||
|
Log.e(TAG, "SocketException() thrown, proxy client has probably closed. This can exit harmlessly");
|
||||||
|
|
||||||
|
// Release file lock, use of stream proxy means nothing else is using it
|
||||||
|
onStop();
|
||||||
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
Log.e(TAG, "Exception thrown from streaming task:");
|
||||||
|
Log.e(TAG, e.getClass().getName() + " : " + e.getLocalizedMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cleanup
|
||||||
|
try {
|
||||||
|
if (output != null) {
|
||||||
|
output.close();
|
||||||
|
}
|
||||||
|
client.close();
|
||||||
|
}
|
||||||
|
catch (IOException e) {
|
||||||
|
Log.e(TAG, "IOException while cleaning up streaming task:");
|
||||||
|
Log.e(TAG, e.getClass().getName() + " : " + e.getLocalizedMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onStart() {
|
||||||
|
|
||||||
|
}
|
||||||
|
public void onStop() {
|
||||||
|
|
||||||
|
}
|
||||||
|
public void onResume() {
|
||||||
|
|
||||||
|
}
|
||||||
|
public boolean isWorkDone() {
|
||||||
|
return cbSkip >= file.length();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,231 @@
|
||||||
|
/*
|
||||||
|
This file is part of ServerProxy.
|
||||||
|
SocketProxy is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
Subsonic is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
Copyright 2014 (C) Scott Jackson
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.nullsum.audinaut.util;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.net.ServerSocket;
|
||||||
|
import java.net.Socket;
|
||||||
|
import java.net.SocketTimeoutException;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.net.URLDecoder;
|
||||||
|
import java.net.URLEncoder;
|
||||||
|
import java.net.UnknownHostException;
|
||||||
|
import java.nio.ByteOrder;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.StringTokenizer;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.net.wifi.WifiManager;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
public abstract class ServerProxy implements Runnable {
|
||||||
|
private static final String TAG = ServerProxy.class.getSimpleName();
|
||||||
|
|
||||||
|
private Thread thread;
|
||||||
|
protected boolean isRunning;
|
||||||
|
private ServerSocket socket;
|
||||||
|
private int port;
|
||||||
|
private Context context;
|
||||||
|
|
||||||
|
public ServerProxy(Context context) {
|
||||||
|
// Create listening socket
|
||||||
|
try {
|
||||||
|
socket = new ServerSocket(0);
|
||||||
|
socket.setSoTimeout(5000);
|
||||||
|
port = socket.getLocalPort();
|
||||||
|
this.context = context;
|
||||||
|
} catch (UnknownHostException e) { // impossible
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.e(TAG, "IOException initializing server", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void start() {
|
||||||
|
if(socket.isBound()) {
|
||||||
|
thread = new Thread(this, "Socket Proxy");
|
||||||
|
thread.start();
|
||||||
|
} else {
|
||||||
|
Log.e(TAG, "Attempting to start a non-initialized proxy");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stop() {
|
||||||
|
isRunning = false;
|
||||||
|
if(thread != null) {
|
||||||
|
thread.interrupt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPrivateAddress(String request) {
|
||||||
|
return getAddress("127.0.0.1", request);
|
||||||
|
}
|
||||||
|
public String getPublicAddress(String request) {
|
||||||
|
WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
|
||||||
|
int ipAddress = wifiManager.getConnectionInfo().getIpAddress();
|
||||||
|
|
||||||
|
if (ByteOrder.nativeOrder().equals(ByteOrder.LITTLE_ENDIAN)) {
|
||||||
|
ipAddress = Integer.reverseBytes(ipAddress);
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] ipByteArray = BigInteger.valueOf(ipAddress).toByteArray();
|
||||||
|
String ipAddressString = null;
|
||||||
|
try {
|
||||||
|
ipAddressString = InetAddress.getByAddress(ipByteArray).getHostAddress();
|
||||||
|
} catch(UnknownHostException ex) {
|
||||||
|
Log.e(TAG, "Unable to get host address.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return getAddress(ipAddressString, request);
|
||||||
|
}
|
||||||
|
private String getAddress(String host, String request) {
|
||||||
|
try {
|
||||||
|
return String.format("http://%s:%d/%s", host, port, URLEncoder.encode(request, "UTF-8"));
|
||||||
|
} catch (UnsupportedEncodingException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
isRunning = true;
|
||||||
|
while (isRunning) {
|
||||||
|
try {
|
||||||
|
Socket client = socket.accept();
|
||||||
|
if (client == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Log.i(TAG, "client connected");
|
||||||
|
|
||||||
|
ProxyTask task = getTask(client);
|
||||||
|
if (task.processRequest()) {
|
||||||
|
new Thread(task, "ProxyTask").start();
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (SocketTimeoutException e) {
|
||||||
|
// Do nothing
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.e(TAG, "Error connecting to client", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Log.i(TAG, "Proxy interrupted. Shutting down.");
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract ProxyTask getTask(Socket client);
|
||||||
|
|
||||||
|
protected abstract class ProxyTask implements Runnable {
|
||||||
|
protected Socket client;
|
||||||
|
protected String path;
|
||||||
|
protected int cbSkip = 0;
|
||||||
|
protected Map<String, String> requestHeaders = new HashMap<>();
|
||||||
|
|
||||||
|
public ProxyTask(Socket client) {
|
||||||
|
this.client = client;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean readRequest() {
|
||||||
|
InputStream is;
|
||||||
|
String firstLine;
|
||||||
|
BufferedReader reader;
|
||||||
|
try {
|
||||||
|
is = client.getInputStream();
|
||||||
|
reader = new BufferedReader(new InputStreamReader(is), 8192);
|
||||||
|
firstLine = reader.readLine();
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.e(TAG, "Error parsing request", e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (firstLine == null) {
|
||||||
|
Log.i(TAG, "Proxy client closed connection without a request.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
StringTokenizer st = new StringTokenizer(firstLine);
|
||||||
|
if(!st.hasMoreTokens()) {
|
||||||
|
Log.w(TAG, "Unknown request with no tokens");
|
||||||
|
return false;
|
||||||
|
} else if(st.countTokens() < 2) {
|
||||||
|
Log.w(TAG, "Unknown request with no uri: \"" + firstLine + '"');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
String method = st.nextToken();
|
||||||
|
String uri = st.nextToken();
|
||||||
|
String realUri = uri.substring(1);
|
||||||
|
|
||||||
|
// Process path
|
||||||
|
try {
|
||||||
|
path = URLDecoder.decode(realUri, "UTF-8");
|
||||||
|
} catch (UnsupportedEncodingException e) {
|
||||||
|
Log.e(TAG, "Unsupported encoding", e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get all of the headers
|
||||||
|
try {
|
||||||
|
String line;
|
||||||
|
while((line = reader.readLine()) != null && !"".equals(line)) {
|
||||||
|
int index = line.indexOf(':');
|
||||||
|
// Ignore headers without ':' or where ':' is the last thing in the string
|
||||||
|
if(index != -1 && (index + 2) < line.length()) {
|
||||||
|
String headerName = line.substring(0, index);
|
||||||
|
String headerValue = line.substring(index + 2);
|
||||||
|
|
||||||
|
requestHeaders.put(headerName, headerValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch(IOException e) {
|
||||||
|
// Don't really care once past first line
|
||||||
|
} catch(Exception e) {
|
||||||
|
Log.w(TAG, "Exception reading request", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean processRequest() {
|
||||||
|
if (!readRequest()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Log.i(TAG, "Processing request for " + path);
|
||||||
|
|
||||||
|
// Try to get range requested
|
||||||
|
String range = requestHeaders.get("Range");
|
||||||
|
if(range != null) {
|
||||||
|
int index = range.indexOf("=");
|
||||||
|
if(index >= 0) {
|
||||||
|
range = range.substring(index + 1);
|
||||||
|
|
||||||
|
index = range.indexOf("-");
|
||||||
|
if(index > 0) {
|
||||||
|
range = range.substring(0, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
cbSkip = Integer.parseInt(range);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,2 +1 @@
|
||||||
include ':app', ':Server Proxy'
|
include ':app'
|
||||||
project(':Server Proxy').projectDir = new File('ServerProxy')
|
|
||||||
|
|
Loading…
Reference in New Issue