HttpProxy.h
#ifndef HTTPROXY_HEAD_FILE
#define HTTPROXY_HEAD_FILE
#pragma once
#include <windows.h>
#include <stdio.h>
#include <wininet.h>
#include <errno.h>
#include <tchar.h>
#include <assert.h>
#pragma comment(lib,"Ws2_32.lib")
//删除指针
#define SafeDelete(pData){if (pData) {free(pData);pData=NULL;}}
//关闭句柄删除指针
#define SafeCloseHandleDelete(pData){if (pData){closesocket(pData[0]);closesocket(pData[1]);free(pData);pData=NULL;}}
//宏定义
#define MAX_HOSTNAME 1024 //最大主机名称
#define DEFAULTPORT 80 //默认主机端口
#define LISTENPORT 8000 //代理服务器监听端口
#define DEFLISNUM 500 //linsten最大队列
#define HEADLEN 7 //http://头长度
#define TIMEOUT 10000 //recv延时时间
#define MAXSIZE 20480 //缓冲大小
#define GET_STYLE 1 //get请求类型 请求指定的页面信息,并返回实体主体
#define HEAD_STYLE 2 //head请求类型 只请求页面的首部
#define POST_STYLE 3 //post请求类型 请求服务器接受所指定的文档作为对所标识的URI的新的从属实体
#define CONNECT_STYLE 4 //connect请求类型
#define ErrorMsg "HTTP/1.1 403 Forbidden\r\n\r\n<body><h1>403 Forbidden</h1></body>"
#define ConnectionEstablished "HTTP/1.0 200 OK\r\n\r\n"
//char ErrorMsg[]="HTTP/1.1 403 Forbidden\r\n\r\n<body><h1>403 Forbidden</h1></body>"; //SOCK错误消息
//char ConnectionEstablished[]="HTTP/1.0 200 OK\r\n\r\n"; //HTTP成功
//HTTP代理服务器
class CHttpProxyServer
{
//变量定义
public:
SOCKET m_ProxyServer; //sock句柄
UINT m_nPort; //监听端口
//静态变量
protected:
static CHttpProxyServer * m_pHttpProxyServer; //对象指针
//函数定义
public:
//构造函数
CHttpProxyServer();
//析构函数
~CHttpProxyServer();
//辅助函数
protected:
// 地址解释
DWORD TranslateAddr(char* pszServerAddr);
//功能函数
public:
//启动服务
BOOL OnStart(int nPort=LISTENPORT);
//发送请求
static BOOL SendRequest(SOCKET* CSsocket, char *SenderBuf, char *ReceiveBuf, int DataLen);
//查询请求
static int CheckRequest(char *ReceiveBuf,int *MethodLength);
//修改请求
static int ModifyRequest(char *SenderBuf,char *ReceiveBuf,int DataLen,int MethodLength);
//获取根目录节点
static char *GetURLRootPoint(char * ReceiveBuf,int DataLen,int *HostNaneLen);
//获取主机名和端口
static void GetHostNameAndPort(char *ReceiveBuf,int datalen,char *HostName,UINT *RemotePort);
//连接远程主机
static BOOL ConnectToRemoteHost(SOCKET *ServerSocket,char *HostName,const UINT RemotePort);
//主机名解析IP地址
static char *DNS(char *HostName);
//线程函数
protected:
//启动服务线程
static DWORD StartThread( LPVOID lpParameter);
//HTTP代理线程
static DWORD ZXHTTPProxyThread(LPVOID lpParameter);
//信息传递线程
static DWORD TransferData(LPVOID lpParameter);
//静态函数
public:
//获取对象
static CHttpProxyServer * GetInstance() { return m_pHttpProxyServer; }
};
#endif
HttpProxy.cpp
#include "HttpProxy.h"
//////////////////////////////////////////////////////////////////////////////////
//静态变量
CHttpProxyServer * CHttpProxyServer::m_pHttpProxyServer=NULL; //对象指针
//////////////////////////////////////////////////////////////////////////////////
//构造函数
CHttpProxyServer::CHttpProxyServer()
{
//设置对象
assert(m_pHttpProxyServer==NULL);
if (m_pHttpProxyServer==NULL)m_pHttpProxyServer=this;
//初始化变量
m_ProxyServer=INVALID_SOCKET;
m_nPort=LISTENPORT;
//初始化网络库
WSADATA WSAData;
WSAStartup(MAKEWORD(2,2), &WSAData);
}
//析构函数
CHttpProxyServer::~CHttpProxyServer()
{
WSACleanup( );
}
//启动服务
BOOL CHttpProxyServer::OnStart(int nPort)
{
//参数效验
assert(m_ProxyServer==INVALID_SOCKET);
assert(nPort>0 && nPort<65535);
if (m_ProxyServer!=INVALID_SOCKET)return FALSE;
if (nPort<0 || nPort>=65535)return FALSE;
//创建socket
m_ProxyServer= socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
assert(m_ProxyServer!=SOCKET_ERROR);
if(m_ProxyServer == SOCKET_ERROR)return FALSE;
//设置变量
m_nPort=nPort;
//创建线程启动服务
HANDLE hThread=CreateThread(NULL,NULL,(LPTHREAD_START_ROUTINE)StartThread,this,NULL,NULL);
CloseHandle(hThread);
return TRUE;
}
//启动服务线程
DWORD CHttpProxyServer::StartThread( LPVOID lpParameter)
{
//设置变量
CHttpProxyServer* pHttpProxyServer=(CHttpProxyServer*)lpParameter;
assert(pHttpProxyServer!=NULL);
if (pHttpProxyServer==NULL)return false;
//绑定端口
struct sockaddr_in Server={0};
Server.sin_family = AF_INET;
Server.sin_port = htons(pHttpProxyServer->m_nPort);
Server.sin_addr.S_un.S_addr = INADDR_ANY;
if(bind(pHttpProxyServer->m_ProxyServer, (LPSOCKADDR)&Server, sizeof(Server)) == SOCKET_ERROR) return FALSE;
//监听连接
if(listen(pHttpProxyServer->m_ProxyServer, DEFLISNUM) == SOCKET_ERROR)return FALSE;
//定义变量
SOCKET AcceptSocket = INVALID_SOCKET;
SOCKET *CSsocket=NULL;
while(true)
{
//接受客户端连接
AcceptSocket = accept(pHttpProxyServer->m_ProxyServer, NULL, NULL);
CSsocket = (SOCKET*)malloc(sizeof(SOCKET)*2);
if (CSsocket == NULL)continue;
//创建线程处理客户端连接请求
CSsocket[0] = AcceptSocket;
HANDLE hThread = CreateThread (NULL,0, (LPTHREAD_START_ROUTINE)ZXHTTPProxyThread,CSsocket,NULL,NULL);
if (hThread == NULL) Sleep(1000);
else CloseHandle(hThread);
}
return true;
}
//HTTP代理线程
DWORD CHttpProxyServer::ZXHTTPProxyThread(LPVOID lpParameter)
{
//设置变量
SOCKET* CSsocket=(SOCKET*)lpParameter;
assert(CSsocket!=NULL);
if (CSsocket==NULL)return false;
//分配内存
char *ReceiveBuf = (char*)malloc(sizeof(char)*MAXSIZE);
char *SenderBuf = (char*)malloc(sizeof(char)*MAXSIZE);
memset(ReceiveBuf,0,MAXSIZE);
memset( SenderBuf,0,MAXSIZE);
//接受数据
int DataLen = 0;
DataLen = recv(CSsocket[0],ReceiveBuf,MAXSIZE,0);
if(DataLen == SOCKET_ERROR || DataLen == 0)
{
SafeDelete(ReceiveBuf);
SafeDelete(SenderBuf);
SafeCloseHandleDelete(CSsocket);
return 0;
}
//发送请求
if(SendRequest(CSsocket, SenderBuf, ReceiveBuf, DataLen)==FALSE)
send(CSsocket[0],ErrorMsg,strlen(ErrorMsg),0);
//清理资源
SafeDelete(ReceiveBuf);
SafeDelete(SenderBuf);
SafeCloseHandleDelete(CSsocket);
return true;
}
//发送请求
BOOL CHttpProxyServer::SendRequest(SOCKET* CSsocket, char *SenderBuf, char *ReceiveBuf, int DataLen)
{
//参数效验
assert(CSsocket!=NULL);
assert(SenderBuf!=NULL);
assert(ReceiveBuf!=NULL);
assert(DataLen>0);
if (CSsocket==NULL)return false;
if (SenderBuf==NULL)return false;
if (ReceiveBuf==NULL)return false;
if (DataLen<0)return false;
//CSsocket[0] ClientSocket //客户端socket
//CSsocket[1] ServerSocket //服务端socket
//定义变量
char HostName[MAX_HOSTNAME] = {0};
UINT RemotePort = 0;
int Flag=0, MethodLength=0, SendLength=0;
//查询请求
Flag = CheckRequest(ReceiveBuf,&MethodLength);
if(Flag==0) return 0;
if(Flag==GET_STYLE || Flag==HEAD_STYLE || Flag==POST_STYLE)
{
//修改请求
SendLength=ModifyRequest(SenderBuf,ReceiveBuf,DataLen,MethodLength);
if(SendLength==NULL)return 0;
//获取主机名和端口
GetHostNameAndPort(ReceiveBuf+MethodLength+HEADLEN,DataLen-MethodLength-HEADLEN,HostName,&RemotePort);
//连接远程主机 //pc.qq.com 80
if(ConnectToRemoteHost(&CSsocket[1],HostName,RemotePort)==FALSE)return 0;
//发送数据 //这里是向服务器请求域名后面的页面,比如http://pc.qq.com/all.html 实际请求的是all.html
if(send(CSsocket[1],SenderBuf,SendLength,0) == SOCKET_ERROR) return 0;
}
else if(Flag==CONNECT_STYLE)
{
//获取主机名和端口
GetHostNameAndPort(ReceiveBuf+MethodLength,DataLen-MethodLength,HostName,&RemotePort);
//连接远程主机
if(ConnectToRemoteHost(&CSsocket[1],HostName,RemotePort)==FALSE) return 0;
//发送数据
send(CSsocket[0], ConnectionEstablished, strlen(ConnectionEstablished),0);
}
//转发线程
if(CSsocket[0] && CSsocket[1])
{
//开启线程
HANDLE ThreadHandle = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)TransferData,CSsocket,NULL,NULL);
if (ThreadHandle != NULL)WaitForSingleObject(ThreadHandle, INFINITE);
CloseHandle(ThreadHandle);
}
else return FALSE;
return TRUE;
}
//查询请求 返回请求的类型
int CHttpProxyServer::CheckRequest(char *ReceiveBuf,int *MethodLength)
{
//参数效验
assert(ReceiveBuf!=NULL);
assert(MethodLength!=NULL);
if (ReceiveBuf==NULL)return NULL;
if (MethodLength==NULL)return NULL;
if(! _strnicmp(ReceiveBuf,"GET ",4))
{
*MethodLength = 4;
return GET_STYLE;
}
else if(! _strnicmp(ReceiveBuf,"HEAD ",5)) //Looks like the same with GET
{
*MethodLength = 5;
return HEAD_STYLE;
}
else if(! _strnicmp(ReceiveBuf,"POST ",5))
{
*MethodLength = 5;
return POST_STYLE;
}
else if(! _strnicmp(ReceiveBuf,"CONNECT ",8))
{
*MethodLength = 8;
return CONNECT_STYLE;
}
else
{
return 0;
}
return 0;
}
//修改请求 返回域名后面的路径
int CHttpProxyServer::ModifyRequest(char *SenderBuf,char *ReceiveBuf,int DataLen,int MethodLength)
{
//参数效验
assert(SenderBuf!=NULL);
assert(ReceiveBuf!=NULL);
assert(DataLen>0);
assert(MethodLength>0);
if (SenderBuf==NULL)return NULL;
if (ReceiveBuf==NULL)return NULL;
if (DataLen<0)return NULL;
if (MethodLength<0)return NULL;
//设置变量
strncpy(SenderBuf,ReceiveBuf,MethodLength);
int HedLen = 0;
//http头判断
if(strncmp(ReceiveBuf+MethodLength,"http://",HEADLEN)) return 0;
//获取域名后面的部分
char * Getrootfp = GetURLRootPoint(ReceiveBuf+MethodLength+HEADLEN,DataLen
-MethodLength-HEADLEN,&HedLen);
if(Getrootfp == NULL)
return 0;
memcpy(SenderBuf+MethodLength,Getrootfp,DataLen-MethodLength-HEADLEN-HedLen);
//返回长度
return DataLen-HEADLEN-HedLen;
}
//获取根目录节点 获取域名后面的部分
char* CHttpProxyServer::GetURLRootPoint(char * ReceiveBuf,int DataLen,int *HostNaneLen)
{
//参数效验
assert(DataLen>0);
assert(ReceiveBuf!=NULL);
assert(HostNaneLen!=NULL);
if (DataLen<0)return NULL;
if (ReceiveBuf==NULL)return NULL;
if (HostNaneLen==NULL)return NULL;
//解析操作
for(int i = 0;i < DataLen; i++)
{
if(ReceiveBuf[i] == '/')
{
*HostNaneLen = i;
return &ReceiveBuf[i];
}
}
return NULL;
}
//获取主机名和端口
void CHttpProxyServer::GetHostNameAndPort(char *ReceiveBuf,int datalen,char *HostName,UINT *RemotePort)
{
//参数效验
assert(datalen>0);
assert(RemotePort!=NULL);
assert(HostName!=NULL);
if (datalen<0)return;
if (RemotePort==NULL)return;
if (HostName==NULL)return;
//解析主机端口
char *fp = ReceiveBuf;
for(int i = 0;i < datalen && *fp != ':' && *fp != '\0' && *fp != '\r' && *fp != '/';i++)
{
//解析主机
HostName[i]=*fp++;
//解析端口
if(*fp == ':') *RemotePort=atoi(fp+1);
else *RemotePort=DEFAULTPORT;
}
return;
}
//连接远程主机
BOOL CHttpProxyServer::ConnectToRemoteHost(SOCKET *ServerSocket,char *HostName,const UINT RemotePort)
{
//参数效验
assert(*ServerSocket!=SOCKET_ERROR);
assert(HostName!=NULL);
assert(RemotePort>0);
if (*ServerSocket==SOCKET_ERROR)return false;
if (*HostName==NULL)return false;
if (RemotePort<0)return false;
//地址信息
sockaddr_in Server={0};
Server.sin_family = AF_INET;
Server.sin_port = htons(RemotePort);
if (inet_addr(HostName) != INADDR_NONE)
{
Server.sin_addr.s_addr = inet_addr(HostName);
}
else
{
//解析主机地址
if (DNS(HostName) != NULL)
{
Server.sin_addr.s_addr = inet_addr(DNS(HostName));
}
else
{
assert(FALSE);
return FALSE;
}
}
//创建socket
*ServerSocket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if (*ServerSocket == INVALID_SOCKET) return FALSE;
//设置socket接收的超时时间为10秒
UINT TimeOut = TIMEOUT;
setsockopt(*ServerSocket,SOL_SOCKET,SO_RCVTIMEO,(char *)&TimeOut,sizeof(TimeOut));
// 连接远程主机
if (connect(*ServerSocket, (const SOCKADDR *)&Server,sizeof(Server)) == SOCKET_ERROR)
{
closesocket(*ServerSocket);
return FALSE;
}
return TRUE;
}
//主机名解析IP地址
char* CHttpProxyServer::DNS(char *HostName)
{
//参数效验
assert(HostName);
if (HostName==NULL)return NULL;
//获取主机地址
HOSTENT *hostent = NULL;
IN_ADDR iaddr;
hostent = gethostbyname(HostName);
if (hostent == NULL)return NULL;
iaddr = *((LPIN_ADDR)*hostent->h_addr_list);
return inet_ntoa(iaddr);
}
//信息传递线程
DWORD CHttpProxyServer::TransferData(LPVOID lpParameter)
{
//参数效验
SOCKET* CSsocket=(SOCKET*)lpParameter;
assert(CSsocket!=NULL);
if (CSsocket==NULL)return false;
//定义变量
SOCKET ClientSocket = CSsocket[0];
SOCKET ServerSocket = CSsocket[1];
timeval timeset={0}; //超时时间
fd_set readfd,writefd;
int result,i=0;
char read_in1[MAXSIZE]={0};
char send_out1[MAXSIZE]={0};
char read_in2[MAXSIZE]={0};
char send_out2[MAXSIZE]={0}; //ServerSocket套接字接受数据
char SenderBuf[MAXSIZE]={0};
int read1=0;
int Clienttotalread1=0; //ClientSocket套接字接受长度
int send1=0;
int read2=0;
int Servertotalread2=0; //ServerSocket套接字接受长度
int send2=0;
int sendcount1=0;
int sendcount2=0;
int maxfd=0; //最大套接字范围
maxfd=max(ClientSocket,ServerSocket)+1;
memset(read_in1,0,MAXSIZE);
memset(read_in2,0,MAXSIZE);
memset(send_out1,0,MAXSIZE);
memset(send_out2,0,MAXSIZE);
timeset.tv_sec=TIMEOUT;
timeset.tv_usec=0;
while(true)
{
//初始化为空集合
FD_ZERO(&readfd);
FD_ZERO(&writefd);
//添加套接字到集合
FD_SET((UINT)ClientSocket, &readfd);
FD_SET((UINT)ClientSocket, &writefd);
FD_SET((UINT)ServerSocket, &writefd);
FD_SET((UINT)ServerSocket, &readfd);
//查询事件
result=select(maxfd,&readfd,&writefd,NULL,×et);
if((result<0) && (errno!=EINTR)) break;
else if(result==0) break;
//1.接受远程服务端数据
if(FD_ISSET(ServerSocket, &readfd)) //检查s是不是set的成员,如果是返回TRTUE
{
//fx 2016年5月17日16:18:03
//由于已近连接了远程服务器,所有会先收到服务器的数据
//收到服务器返回http://pc.qq.com/all.html
//最大长度判断
if(Servertotalread2<MAXSIZE)
{
read2=recv(ServerSocket,read_in2,MAXSIZE-Servertotalread2, 0);
if(read2==0)break;
if((read2<0) && (errno!=EINTR)) break;
memcpy(send_out2+Servertotalread2,read_in2,read2);
Servertotalread2+=read2;
memset(read_in2,0,MAXSIZE);
}
}
//2.转发数据到客户端
if(FD_ISSET(ClientSocket, &writefd)) //检查s是不是set的成员,如果是返回TRTUE
{
//收到远程服务器的数据直接转发给客户端
//1和2相当于是一套组合,收到远程服务器的数据转发到客户端
//http://pc.qq.com/all.html发送到客户端
int err2=0;
sendcount2=0;
while(Servertotalread2>0) //接受长度
{
send2=send(ClientSocket, send_out2+sendcount2, Servertotalread2, 0);
if(send2==0)break;
if((send2<0) && (errno!=EINTR))
{
err2=1;
break;
}
if((send2<0) && (errno==ENOSPC)) break;
sendcount2+=send2;
Servertotalread2-=send2;
}
if(err2==1) break;
if((Servertotalread2>0) && (sendcount2 > 0))
{
/* move not sended data to start addr */
memcpy(send_out2, send_out2+sendcount2, Servertotalread2);
memset(send_out2+Servertotalread2, 0, MAXSIZE-Servertotalread2);
}
else memset(send_out2,0,MAXSIZE);
}
//3.接受客户端请求
if(FD_ISSET(ClientSocket, &readfd)) //检查s是不是set的成员,如果是返回TRTUE
{
//是否收到客户端数据,如果有接受客户端发来的请求
//客户端请求比如http://pc.qq.com/all.html
if(Clienttotalread1<MAXSIZE)
{
read1=recv(ClientSocket, read_in1, MAXSIZE-Clienttotalread1, 0);
if((read1==SOCKET_ERROR) || (read1==0)) break;
memcpy(send_out1+Clienttotalread1,read_in1,read1);
Clienttotalread1+=read1;
memset(read_in1,0,MAXSIZE);
}
//发送请求 到远程服务器比如http://pc.qq.com/all.html
if(SendRequest(CSsocket,SenderBuf,send_out1,Clienttotalread1))
Clienttotalread1=0;
}
//2.收到客户端请求转发到服务器
if(FD_ISSET(ServerSocket, &writefd))
{
//发送请求 到远程服务器比如http://pc.qq.com/all.html
int err=0;
sendcount1=0;
while(Clienttotalread1>0)
{
send1=send(ServerSocket, send_out1+sendcount1, Clienttotalread1, 0);
if(send1==0)break;
if((send1<0) && (errno!=EINTR))
{
err=1;
break;
}
if((send1<0) && (errno==ENOSPC)) break;
sendcount1+=send1;
Clienttotalread1-=send1;
}
if(err==1) break;
if((Clienttotalread1>0) && (sendcount1>0))
{
memcpy(send_out1,send_out1+sendcount1,Clienttotalread1);
memset(send_out1+Clienttotalread1,0,MAXSIZE-Clienttotalread1);
}
else
memset(send_out1,0,MAXSIZE);
}
Sleep(5);
}
closesocket(ClientSocket);
closesocket(ServerSocket);
return true;
}
// 地址解释
DWORD CHttpProxyServer::TranslateAddr(char* pszServerAddr)
{
// 转化地址
DWORD dwServerIP = inet_addr(pszServerAddr);
if (dwServerIP == INADDR_NONE)
{
LPHOSTENT lpHost = gethostbyname(pszServerAddr);
if (lpHost == NULL) return INADDR_NONE;
dwServerIP = ((LPIN_ADDR)lpHost->h_addr)->s_addr;
}
return dwServerIP;
}
main.cpp
#include "HttpProxy.h"
int main (void)
{
CHttpProxyServer httpProxyServer;
httpProxyServer.OnStart();
getchar();
return 0;
}