📄 httpproxy.cpp
字号:
/***************************************************************************
* *
* This program 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 2 of the License, or *
* (at your option) any later version. *
* *
* copyright : (C) 2003 by Zhang Yong *
* email : z-yong163@163.com *
***************************************************************************/
#include "httpproxy.h"
#include "nullproxy.h"
#include "base64.h"
#include "icqlog.h"
static bool resolveHost(string &host)
{
in_addr addr;
addr.s_addr = inet_addr(host.c_str());
if (addr.s_addr == INADDR_NONE) {
hostent *hent = gethostbyname(host.c_str());
if (!hent)
return false;
addr = *(in_addr *) hent->h_addr;
}
host = inet_ntoa(addr);
return true;
}
enum {
HTTP_STATUS_NOT_CONN,
HTTP_STATUS_ESTABLISHED
};
HTTPProxy::HTTPProxy(PROXY_INFO &info)
{
proxyInfo = info;
listener = NULL;
eventMask = 0;
socketType = -1;
destPort = 0;
status = HTTP_STATUS_NOT_CONN;
bufSize = 0;
tcpSocket = NullProxy::createInstance();
}
HTTPProxy::~HTTPProxy()
{
delete tcpSocket;
}
void HTTPProxy::fireEvent(int event)
{
if (((1 << event) & eventMask) == 0)
return;
switch (event) {
case READ:
listener->onSocketRead();
break;
case WRITE:
eventMask &= ~(1 << event);
listener->onSocketWrite();
break;
case EXCEPTION:
listener->onSocketException();
break;
}
}
void HTTPProxy::addEvent(int event)
{
eventMask |= (1 << event);
if (status == HTTP_STATUS_ESTABLISHED)
tcpSocket->addEvent(event);
}
void HTTPProxy::removeEvent(int event)
{
eventMask &= ~(1 << event);
if (status == HTTP_STATUS_ESTABLISHED)
tcpSocket->removeEvent(event);
}
bool HTTPProxy::create(int type, SocketListener *l)
{
socketType = type;
listener = l;
return tcpSocket->create(SOCK_STREAM, this);
}
void HTTPProxy::connect(const char *host, uint16 port, int timeout)
{
destHost = host;
destPort = (socketType == SOCK_DGRAM ? 443 : port);
tcpSocket->addEvent(WRITE);
tcpSocket->addEvent(EXCEPTION);
tcpSocket->connect(proxyInfo.host.c_str(), proxyInfo.port, timeout);
}
int HTTPProxy::send(const char *data, int size)
{
if (socketType == SOCK_DGRAM) {
uint16 n = htons(size);
if (tcpSocket->send((const char *) &n, sizeof(n)) < 0)
return -1;
}
return tcpSocket->send(data, size);
}
int HTTPProxy::receive(char *data, int n)
{
if (socketType == SOCK_STREAM)
return tcpSocket->receive(data, n);
uint16 len;
if (bufSize <= sizeof(len))
return -1;
len = ntohs(*(uint16 *) buffer);
if (n < len || bufSize < len + sizeof(len))
return -1;
memcpy(data, buffer + sizeof(len), len);
return len;
}
void HTTPProxy::onSocketWrite()
{
if (status == HTTP_STATUS_ESTABLISHED) {
fireEvent(WRITE);
return;
}
tcpSocket->removeEvent(WRITE);
tcpSocket->addEvent(READ);
string host = destHost;
if (proxyInfo.resolve)
resolveHost(host);
char buf[32];
sprintf(buf, "%d", destPort);
// Send 'CONNECT' request
string req = "CONNECT ";
req += destHost + ":";
req += buf;
req += " HTTP/1.1\r\n";
// req += "User-agent: LinQ\r\n";
if (!proxyInfo.user.empty()) {
// Encode using base64
string str = proxyInfo.user + ":" + proxyInfo.passwd;
char *code = NULL;
encode_base64(str.c_str(), str.length(), &code);
if (code) {
req += "Proxy-authorization: Basic ";
req += code;
req += "\r\n";
free(code);
}
}
req += "\r\n";
ICQ_LOG("http request:\n%s\n", req.c_str());
tcpSocket->send(req.c_str(), req.length());
}
void HTTPProxy::onSocketRead()
{
// Since we are already connected, receive real packet data
if (status == HTTP_STATUS_ESTABLISHED) {
if (socketType == SOCK_DGRAM)
recvPacket();
else
fireEvent(READ);
return;
}
int n = tcpSocket->receive(buffer, sizeof(buffer));
if (n <= 0) {
fireEvent(EXCEPTION);
return;
}
ICQ_LOG("http response:\n%.*s\n", n, buffer);
char *seps = " ";
char *p = strtok(buffer, seps);
if (p)
p = strtok(NULL, seps);
if (!p || *p != '2') {
fireEvent(EXCEPTION);
return;
}
ICQ_LOG("http tunnel has been established.\n");
status = HTTP_STATUS_ESTABLISHED;
fireEvent(WRITE);
}
void HTTPProxy::onSocketException()
{
fireEvent(EXCEPTION);
}
/*
* Since TCP connection is really a data stream and there is no packet boundary,
* extra things must be done. we put an extra 2 bytes(WORD) at the head of each
* packet describing its size.
*/
void HTTPProxy::recvPacket()
{
int n;
while ((n = tcpSocket->receive(buffer + bufSize, sizeof(buffer) - bufSize)) > 0) {
bufSize += n;
uint16 len;
while (bufSize > sizeof(len)) {
len = ntohs(*(uint16 *) buffer);
if (bufSize < len + sizeof(len))
break;
// A complete packet is received!
fireEvent(READ);
bufSize -= len + sizeof(len);
if (bufSize > 0)
memmove(buffer, buffer + len + sizeof(len), bufSize);
}
}
if (n == 0) {
ICQ_LOG("Http connection is closed by proxy.\n");
fireEvent(EXCEPTION);
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -