⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 httpconnection.cpp.svn-base

📁 wince c++ 下 开发的 rss 阅读器源代码
💻 SVN-BASE
📖 第 1 页 / 共 2 页
字号:
/**
 *  HttpConnection.cpp
 *
 *  Copyright (C) 2008  David Andrs <pda@jasnapaka.com>
 *
 *  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.
 *
 *  This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

#if defined PRSSR_APP
	#include "../StdAfx.h"
	#include "../prssr.h"
	#include "../resource.h"
#endif

#include "HttpConnection.h"
#include "../../share/helpers.h"
#include "../../zlib/zlib.h"


#ifdef MYDEBUG
#undef THIS_FILE
static TCHAR THIS_FILE[] = _T(__FILE__);
#include "../debug/crtdbg.h"
#define new MYDEBUG_NEW
#endif

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

////

// for shutdown (from winsock2.h)
#define SD_RECEIVE      0x00
#define SD_SEND         0x01
#define SD_BOTH         0x02


//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CHttpConnection::CHttpConnection(DWORD timeout/* = 12000*/) {
	LOG0(5, "CHttpConnection::CHttpConnection()");

	Terminated = FALSE;
	Socket.SetTimeout(timeout);
	Proxy = NULL;

	ResponseBodySize = 0;
	ResponseBodyDownloaded = 0;
}

CHttpConnection::~CHttpConnection() {
	LOG0(5, "CHttpConnection::~CHttpConnection()");

	Close();
	delete Proxy;
}

void CHttpConnection::Terminate() {
	LOG0(3, "CHttpConnection::Terminate()");

	Close();
	Terminated = TRUE;
}

BOOL CHttpConnection::IsTerminated() {
	return Terminated;
}

BOOL CHttpConnection::ReceiveLine(CString &sLine) {
	LOG0(5, "CHttpConnection::ReceiveLine()");

	sLine.Empty();
	
	char ch;
	while (TRUE) {
		int size = Socket.Receive(&ch, sizeof(ch));
		if (size > 0 && size != SOCKET_ERROR) {
			sLine += (TCHAR) ch;
			// althought lines should be terminated by CRLF, there are WEB servers that do not follow this fact
			if (ch == _T('\n'))
				return TRUE;
		}
		else {
			ShutdownConnection();
			return FALSE;
		}
	}

	return TRUE;
}

BOOL CHttpConnection::ShutdownConnection() {
	LOG0(5, "CHttpConnection::ShutdownConnection()");

	Socket.Shutdown();
	Socket.Close();

	return TRUE;
}

void CHttpConnection::SetProxy(CProxy *px) {
	delete Proxy;
	Proxy = NULL;

	if (px != NULL) {
		Proxy = new CProxy;
		*Proxy = *px;		// copy it
	}
}

BOOL CHttpConnection::Open(DWORD serviceType, const CString &serverName, int port) {
	LOG3(3, "CHttpConnection::Open(%d, '%S', %d)", serviceType, serverName, port);

	if (!Socket.Create())
		return FALSE;

	CConnectionProvider *provider = NULL;
	if (Proxy != NULL) {
		switch (Proxy->Type) {
			case PROXY_TYPE_SOCKS4: provider = new CSocks4ConnectionProvider(Proxy); break;
			case PROXY_TYPE_SOCKS5: provider = new CSocks5ConnectionProvider(Proxy); break;
			case PROXY_TYPE_HTTP:   provider = new CHttpProxyConnectionProvider(Proxy); break;
			default:                provider = new CConnectionProvider(); break;
		}
	}
	else
		provider = new CConnectionProvider();

	if (provider != NULL && provider->Connect(&Socket, serviceType, serverName, port)) {
		HostName = serverName;

		delete provider;
		return TRUE;
	}
	else {
		delete provider;

		Socket.Close();
		return FALSE;
	}
}

BOOL CHttpConnection::Close() {
	LOG0(3, "CHttpConnection::Close()");

	ShutdownConnection();
	return TRUE;
}

CHttpRequest *CHttpConnection::CreateRequest(const CString &object, EHttpMethod method/* = HTTP_METHOD_GET*/) {
	LOG0(3, "CHttpConnection::CreateRequest()");

	CHttpRequest *req = NULL;
	if (Proxy != NULL && Proxy->Type == PROXY_TYPE_HTTP)
		req = new CHttpRequest(method, object, HostName);
	else
		req = new CHttpRequest(method, object);

	req->SetHeader(_T("Host"), HostName);
	req->SetHeader(_T("Connection"), _T("close"));
	if (!UserAgent.IsEmpty()) req->SetHeader(_T("User-Agent"), UserAgent);
//	req->SetHeader(_T("Accept"), _T("text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5"));
//	req->SetHeader(_T("Accept-Language"), _T("en-us,en;q=0.5"));
	req->SetHeader(_T("Accept-Encoding"), _T("gzip,deflate"));
	// for testing
////	req->SetHeader(_T("Accept-Encoding"), _T("gzip"));
////	req->SetHeader(_T("Accept-Encoding"), _T("deflate"));
//	req->SetHeader(_T("Accept-Charset"), _T("ISO-8859-1,utf-8;q=0.7,*;q=0.7"));

	return req;
}


void CHttpConnection::SendRequest(CHttpRequest *req, CStringArray *addHttpHeaders/* = NULL*/) {
	LOG0(3, "CHttpConnection::SendRequest()");

	req->Send(&Socket, addHttpHeaders);
}

CHttpResponse *CHttpConnection::ReceiveResponse() {
	LOG0(3, "CHttpConnection::ReceiveResponse()");

	CString sLine;
	if (!ReceiveLine(sLine))
		return NULL;

	CHttpResponse *res = new CHttpResponse();
	res->SetStartLine(sLine);

	do {
		if (!ReceiveLine(sLine)) {
			delete res;
			return NULL;
		}

		sLine.TrimLeft();
		sLine.TrimRight();

		int nPos = sLine.Find(':');
		if (nPos != -1) {
			CString value = sLine.Mid(nPos + 1);
			value.TrimLeft();
			value.TrimRight();

			res->AddHeader(sLine.Left(nPos), value);
		}
		else
			break;
	} while (!sLine.IsEmpty());

	return res;
}

BOOL CHttpConnection::ReceiveBlock(unsigned char *buffer, DWORD len, DWORD *received) {
	LOG0(5, "CHttpConnection::ReceiveBlock()");

	BOOL ret = TRUE;
	DWORD totalReceived = 0;

	if (ChunkedTransfer) {
		DWORD remain = len;
		char *buff = (char *) buffer;

		while (remain > 0) {
			if (ChunkRemain == 0) {
				// get chunk header (containing the length of the following chunk)
				CString chunkHead;
				if (ReceiveLine(chunkHead))
					swscanf(chunkHead, _T("%x"), &ChunkRemain);
				else
					return FALSE;

				if (ChunkRemain == 0) {
					// last chunk header read
					ret = TRUE;
					break;
				}
			}
			else {
				int toReceive = min(min(remain, ChunkRemain), SOCK_BUFFER_SIZE);
				int size = Socket.Receive(buff, toReceive);
				totalReceived += size;

				if (size == 0) {
					// end of transfer
					ret = TRUE;
					break;
				}
				else if (size == SOCKET_ERROR) {
					ret = FALSE;
					break;
				}
				else {
//					if (ResponseBodySize > 0)
						ResponseBodyDownloaded += size;

					buff += size;
					remain -= size;
					ChunkRemain -= size;

					if (ChunkRemain == 0) {
						// read to the end of line to get to the start of the next chunk header
						CString empty;
						ReceiveLine(empty);
					}
				}
			}
		}
	}
	else {
		DWORD remain = len;
		char *buff = (char *) buffer;
		while (remain > 0) {
			int toReceive = min(remain, SOCK_BUFFER_SIZE);
			int size = Socket.Receive(buff, toReceive);
			totalReceived += size;

			if (size == 0) {
				// end of transfer
				ret = TRUE;
				break;
			}
			else if (size == SOCKET_ERROR) {
				ret = FALSE;
				break;
			}
			else {
//				if (ResponseBodySize > 0)
					ResponseBodyDownloaded += size;

				buff += size;
				remain -= size;
			}
		}
	}

	if (received != NULL)
		*received = totalReceived;

	return ret;
}

#define CHUNK					2048

// plain ////

BOOL CHttpConnection::ReceiveResponseBodyPlain(CBufferedFile &file) {
	LOG0(5, "CHttpConnection::ReceiveResponseBodyPlain()");

	BOOL ret = FALSE;

	unsigned char in[CHUNK] = { 0 };
	DWORD read;
	while (ReceiveBlock(in, CHUNK, &read)) {
		if (read == 0) {
			ret = TRUE;			// end of transfer
			break;
		}
		else {
			if (!file.Write(in, read)) {
				ret = FALSE;
				break;
			}
		}
	}

	return ret;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -