package me.zacherl.proxy;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.UnknownHostException;
import java.nio.CharBuffer;
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.StringTokenizer;
import me.zacherl.proxy.HttpProxyContext.TransferMode;
public class HttpProxyConnection implements Runnable{
protected Socket localSocket = null;
protected Socket remoteSocket = null;
protected BufferedReader localInput = null;
protected BufferedWriter localOutput = null;
protected BufferedReader remoteInput = null;
protected BufferedWriter remoteOutput = null;
public HttpProxyConnection(Socket localSocket) {
this.localSocket = localSocket;
}
private void BeforeHttpRequest(HttpProxyRequest request) {
}
private void BeforeHttpResponse(HttpProxyResponse response) {
}
private void HttpRequest(HttpProxyRequest request, HttpProxyData data) {
}
private void HttpResponse(HttpProxyResponse response, HttpProxyData data) {
}
private HttpProxyRequest parseRequest(BufferedReader input) {
HttpProxyRequest request = new HttpProxyRequest();
try {
String line = input.readLine();
String[] header = line.split(" ");
if (header.length < 3) {
return null;
}
request.setMethod(header[0]);
request.setProtocol(header[2]);
if (request.getMethod().equalsIgnoreCase("CONNECT")) {
request.setSslConnection(true);
header = header[1].split(":");
if (header.length < 1) {
return null;
}
request.setToHost(header[0]);
try {
request.setToPort(Integer.parseInt(header[1]));
} catch (
Exception e) {
request.setToPort(443);
}
} else {
request.setSslConnection(false);
try {
request.setUri(new
URI(header[1]));
} catch (URISyntaxException e) {
return null;
}
while ((line = input.readLine()).length() > 0) {
header = line.split(": ");
StringBuffer sb = new StringBuffer();
for (int i = 1; i < header.length; i++) {
sb.append(header[i]);
}
request.setHeader(header[0], sb.toString());
}
}
} catch (IOException e) {
return null;
}
return request;
}
private void sendRequestHeader(BufferedWriter output, HttpProxyRequest request) {
try {
StringBuffer sb = new StringBuffer();
sb.append(request.getMethod() + " ");
URI uri = request.getUri();
sb.append(
uri.getPath());
if (
uri.getQuery() != null) {
sb.append(
uri.getQuery());
}
if (
uri.getFragment() != null) {
sb.append(
uri.getFragment());
}
sb.append(" " + request.getProtocol());
output.write(sb.toString() + "\r\n");
System.out.print(sb.toString() + "\r\n");
Iterator it = request.getHeaders().entrySet().iterator();
while (it.hasNext()) {
Entry pairs = (Entry)it.next();
output.write(pairs.getKey() + ": " + pairs.getValue() + "\r\n");
System.out.print(pairs.getKey() + ": " + pairs.getValue() + "\r\n");
}
output.write("\r\n");
} catch (IOException e) {
return;
}
}
private void receiveData(BufferedReader input, HttpProxyData data) {
try {
char[] buf = new char[1024 * 8];
while (input.ready()) {
int size = input.read(buf, 0, buf.length);
if (size < 1) {
break;
}
data.addContent(buf, size);
if (size < buf.length) {
break;
}
}
} catch (IOException e) {
return;
}
}
private void sendData(BufferedWriter output, HttpProxyData data) {
try {
output.write(data.getContent(), 0, data.getContentLength());
} catch (IOException e) {
}
}
private void tunnelData(BufferedReader input, BufferedWriter output) {
try {
char[] buf = new char[1024*8];
while (input.ready()) {
int size = input.read(buf, 0, buf.length);
if (size < 1) {
break;
}
output.write(buf, 0, size);
if (size < buf.length) {
break;
}
}
} catch (IOException e) {
return;
}
}
public void run() {
try {
localInput = new BufferedReader(new InputStreamReader(localSocket.getInputStream()));
localOutput = new BufferedWriter(new OutputStreamWriter(localSocket.getOutputStream()));
HttpProxyRequest request = parseRequest(localInput);
if (request == null) {
return;
}
System.out.println("REQUEST:");
System.out.println(request.getToHost() + ":" + request.getToPort());
System.out.println(request.getDocument());
BeforeHttpRequest(request);
try {
remoteSocket = new Socket(request.getToHost(), request.getToPort());
remoteInput = new BufferedReader(new InputStreamReader(remoteSocket.getInputStream()));
remoteOutput = new BufferedWriter(new OutputStreamWriter(remoteSocket.getOutputStream()));
} catch (UnknownHostException e) {
return;
}
// request.setTransferMode(TransferMode.TRANSFER_MODE_FULL_DOCUMENT);
HttpProxyData requestData = new HttpProxyData();
if (!request.getSslConnection() && (request.getTransferMode() == TransferMode.TRANSFER_MODE_FULL_DOCUMENT)) {
receiveData(localInput, requestData);
HttpRequest(request, requestData);
request.setHeader(HttpProxyContext.HEADER_CONTENT_LENGTH, Integer.toString(requestData.getContentLength()));
}
if (!request.getSslConnection()) {
sendRequestHeader(remoteOutput, request);
if (request.getTransferMode() == TransferMode.TRANSFER_MODE_FULL_DOCUMENT) {
sendData(remoteOutput, requestData);
}
}
if (request.getSslConnection() || (request.getTransferMode() == TransferMode.TRANSFER_MODE_STREAM)) {
String contentLength = request.getHeader(HttpProxyContext.HEADER_CONTENT_LENGTH);
if ((contentLength != null) && (Integer.parseInt(contentLength) > 0)) {
tunnelData(localInput, remoteOutput);
}
}
remoteOutput.flush();
HttpProxyResponse response = parseResponse(remoteInput);
if (response == null) {
return;
}
response.setSslConnection(request.getSslConnection());
response.setTransferMode(TransferMode.TRANSFER_MODE_FULL_DOCUMENT);
HttpProxyData responseData = new HttpProxyData();
if (!response.getSslConnection() && (response.getTransferMode() == TransferMode.TRANSFER_MODE_FULL_DOCUMENT)) {
System.out.println(Integer.toString(remoteSocket.getInputStream().available()));
receiveData(remoteInput, responseData);
HttpResponse(response, responseData);
//response.setHeader(HttpProxyContext.HEADER_CONTENT_LENGTH, Integer.toString(responseData.getContentLength()));
System.out.println(Integer.toString(responseData.getContentLength()));
}
if (!response.getSslConnection()) {
sendResponseHeader(localOutput, response);
if (response.getTransferMode() == TransferMode.TRANSFER_MODE_FULL_DOCUMENT) {
sendData(localOutput, responseData);
}
}
if (response.getSslConnection() || (response.getTransferMode() == TransferMode.TRANSFER_MODE_STREAM)) {
tunnelData(remoteInput, localOutput);
}
localOutput.flush();
if (remoteSocket != null) {
remoteSocket.close();
}
if (localSocket != null) {
localSocket.close();
}
} catch (IOException e) {
}
}
private void sendResponseHeader(BufferedWriter output, HttpProxyResponse response) {
try {
StringBuffer sb = new StringBuffer();
sb.append(response.getProtocol() + " ");
sb.append(Integer.toString(response.getStatusCode()) + " ");
sb.append(response.getStatusMessage());
output.write(sb.toString() + "\r\n");
Iterator it = response.getHeaders().entrySet().iterator();
while (it.hasNext()) {
Entry pairs = (Entry)it.next();
output.write(pairs.getKey() + ": " + pairs.getValue() + "\r\n");
}
output.write("\r\n");
} catch (IOException e) {
return;
}
}
private HttpProxyResponse parseResponse(BufferedReader input) {
HttpProxyResponse response = new HttpProxyResponse();
try {
String line = input.readLine();
String[] header = line.split(" ");
if (header.length < 3) {
return null;
}
response.setProtocol(header[0]);
try {
response.setStatusCode(Integer.parseInt(header[1]));
} catch (
Exception e) {
return null;
}
response.setStatusMessage(header[2]);
while ((line = input.readLine()).length() > 0) {
header = line.split(": ");
StringBuffer sb = new StringBuffer();
for (int i = 1; i < header.length; i++) {
sb.append(header[i]);
}
response.setHeader(header[0], sb.toString());
}
} catch (IOException e) {
return null;
}
return response;
}
}