我正在尝试使用套接字在java中编写一个简单的HTTP代理,基本上只需要一个请求,读取它并将其转发到服务器,读取响应并返回浏览器。我遇到的问题是在响应中有一个我解析的Content-Length字段,我写了一个循环来准确读取要发送回浏览器的字节数,但它到达流的末尾之前读取正确的数量(读取返回-1)。我将在下面添加我的代理的简单代码 - 主线程在建立连接时只生成其中一个类。有没有人有任何想法?这将非常有帮助。
public class ProxyClient implements Runnable {
Socket clientSocket;
Socket netflixSocket;
InputStream isClient = null;
OutputStream osClient = null;
BufferedReader brClient = null;
InputStream isNetflix = null;
OutputStream osNetflix = null;
BufferedReader brNetflix = null;
boolean connectedNetflix = false;
String meta = ""; //header data
public ProxyClient(Socket connectionSocket){
this.clientSocket = connectionSocket;
try {
isClient = clientSocket.getInputStream();
osClient = clientSocket.getOutputStream();
brClient = new BufferedReader(new InputStreamReader(isClient));
} catch (IOException e1) {
e1.printStackTrace();
}
}
@Override
public void run() {
String host = "";
String temp; // temp read line from buffer
String getRequest;
int contentLength; //holder for reading bytes.
int bytesRead; // Total number of bytes read during consecutive reads
int numRead; // Number of bytes read in a single read.
byte[] dataBuffer = new byte[2000000];
while(true){
try {
// reading client HTTP request / connecting
host = "";
meta = "";
contentLength = 0;
getRequest = "";
while((temp = brClient.readLine()).length() > 0){
meta += temp + "\r\n";
//connect to server
if(!connectedNetflix && temp.startsWith("Host")){
// extract the host to connect to
host = temp.substring(temp.indexOf(':') + 2);
//connect to the host
try {
netflixSocket = new Socket(host, 80);
osNetflix = netflixSocket.getOutputStream();
isNetflix = netflixSocket.getInputStream();
brNetflix = new BufferedReader(new InputStreamReader(isNetflix));
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
connectedNetflix = true;
}
else if (temp.startsWith("Content-Length:")) {
contentLength = Integer.parseInt(temp.substring(temp.indexOf(':') + 2));
}
}
meta += "\r\n"; // add blank line
//read request content, if any
if(contentLength > 0){
numRead = 0;
bytesRead = 0;
while(bytesRead != contentLength){
numRead = isNetflix.read(dataBuffer, bytesRead, contentLength-bytesRead);
if(numRead >0){
bytesRead += numRead;
}
}
}
//send to server
osNetflix.write(meta.getBytes());
if(contentLength > 0){
osClient.write(dataBuffer, 0, contentLength);
}
osNetflix.flush();
//Read response from server
contentLength = 0;
meta = "";
while((temp = brNetflix.readLine()).length() > 0){
meta += temp + "\r\n";
if (temp.startsWith("Content-Length:")) {
contentLength = Integer.parseInt(temp.substring(temp.indexOf(':') + 2));
}
}
meta += "\r\n"; // add blank line
//read Netflix content
if(contentLength > 0){
numRead = 0;
bytesRead = 0;
while(bytesRead != contentLength){
numRead = isNetflix.read(dataBuffer, bytesRead, contentLength-bytesRead);
if(numRead >0){
bytesRead += numRead;
}
}
}
// write back to browser/client
osClient.write(meta.getBytes());
if(contentLength > 0){
osClient.write(dataBuffer, 0, contentLength);
}
osClient.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
以下是一个示例响应标题:
HTTP/1.1 200 OK
Server: Apache
Accept-Ranges: bytes
Content-Type: text/plain
Content-Type: application/octet-stream
Access-Control-Allow-Origin: *
Content-Type: application/octet-stream
Last-Modified: Fri, 17 Jun 2011 07:52:37 GMT
ETag: "0d6a07a1c0e6772459e73f7c0c4fd899:1308297157"
Date: Thu, 31 May 2012 01:54:10 GMT
Content-Length: 294183
Connection: close
Cache-Control: no-store
答案 0 :(得分:1)
Content-Length
只是您的代理可以知道要读取多少字节的众多方法之一。在某些条件下,您必须忽略 Content-Length
如果它存在(在这些条件下不应该存在,但有时它仍然存在)。请阅读RFC 2616 Section 4.4以了解如何正确读取响应数据的官方规则。
答案 1 :(得分:1)
这不是你编写HTTP代理的方式。您需要解析的唯一事情是初始CONNECT命令。之后的一切都只是向后和向前复制字节。传入的HTTP已经正确(或不是):不要乱用它。