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

📄 httpconnection.cpp.svn-base

📁 wince c++ 下 开发的 rss 阅读器源代码
💻 SVN-BASE
📖 第 1 页 / 共 2 页
字号:
}

// gzip /////////////////////////////////////////////////////////////////////

#define ASCII_FLAG   0x01 /* bit 0 set: file probably ascii text */
#define HEAD_CRC     0x02 /* bit 1 set: header CRC present */
#define EXTRA_FIELD  0x04 /* bit 2 set: extra field present */
#define ORIG_NAME    0x08 /* bit 3 set: original file name present */
#define COMMENT      0x10 /* bit 4 set: file comment present */
#define RESERVED     0xE0 /* bits 5..7: reserved */

static unsigned gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */

int CHttpConnection::CheckGzipHeader(unsigned char *iStr, BOOL *rs) {
	LOG0(5, "CHttpConnection::CheckGzipHeader()");

	enum  { GZIP_INIT = 0, GZIP_OS, GZIP_EXTRA0, GZIP_EXTRA1, GZIP_EXTRA2, GZIP_ORIG, GZIP_COMMENT, GZIP_CRC };
	char c;
	int mSkipCount = 0, mFlags = 0, hMode = GZIP_INIT, mLen = 0;

	*rs = TRUE;

	int streamLen = 0;
	DWORD read;
	BOOL mCheckHeaderDone = FALSE;

	while (!mCheckHeaderDone) {
		if (streamLen == 0) {
			if (!ReceiveBlock(iStr, CHUNK, &read)) {
				*rs = FALSE;
				return 0;
			}

			streamLen = read;
		}

		switch (hMode) {
			case GZIP_INIT:
				c = *iStr++;
				streamLen--;

				if (mSkipCount == 0 && ((unsigned) c & 0377) != gz_magic[0]) {
					*rs = FALSE;
					return 0;
				}

				if (mSkipCount == 1 && ((unsigned)c & 0377) != gz_magic[1]) {
					*rs = FALSE;
					return 0;
				}

				if (mSkipCount == 2 && ((unsigned)c & 0377) != Z_DEFLATED) {
					*rs = FALSE;
					return 0;
				}

				mSkipCount++;
				if (mSkipCount == 4) {
					mFlags = (unsigned) c & 0377;
					if (mFlags & RESERVED) {
						*rs = FALSE;
						return 0;
					}
					hMode = GZIP_OS;
					mSkipCount = 0;
				}
				break;

			case GZIP_OS:
				c = *iStr++;
				streamLen--;
				mSkipCount++;

				if (mSkipCount == 6)
					hMode = GZIP_EXTRA0;
				break;

			case GZIP_EXTRA0:
				if (mFlags & EXTRA_FIELD) {
					c = *iStr++;
					streamLen--;
					mLen = (uInt) c & 0377;
					hMode = GZIP_EXTRA1;
				}
				else
					hMode = GZIP_ORIG;
				break;

			case GZIP_EXTRA1:
				c = *iStr++;
				streamLen--;

				mLen = ((uInt) c & 0377) << 8;
				mSkipCount = 0;
				hMode = GZIP_EXTRA2;
				break;

			case GZIP_EXTRA2:
				if (mSkipCount == mLen)
					hMode = GZIP_ORIG;
				else {
					c = *iStr++;
					streamLen--;
					mSkipCount++;
				}
				break;

			case GZIP_ORIG:
				if (mFlags & ORIG_NAME) {
					c = *iStr++;
					streamLen--;
					if (c == 0)
						hMode = GZIP_COMMENT;
				}
				else
					hMode = GZIP_COMMENT;
				break;

			case GZIP_COMMENT:
				if (mFlags & GZIP_COMMENT) {
					c = *iStr++;
					streamLen--;
					if (c == 0) {
						hMode = GZIP_CRC;
						mSkipCount = 0;
					}
				}
				else {
					hMode = GZIP_CRC;
					mSkipCount = 0;
				}
				break;

			case GZIP_CRC:
				if (mFlags & HEAD_CRC) {
					c = *iStr++;
					streamLen--;

					mSkipCount++;
					if (mSkipCount == 2) {
						mCheckHeaderDone = TRUE;
						return read - streamLen;
					}
				}
				else {
					mCheckHeaderDone = TRUE;
					return read - streamLen;
				}
				break;
		} // switch
	} // while

	return read - streamLen;
}

BOOL CHttpConnection::ReceiveResponseBodyCompressed(CBufferedFile &file, EContentEncoding contentEnc) {
	LOG1(5, "CHttpConnection::ReceiveResponseBodyCompressed(, %d)", contentEnc);

	BOOL mDummyStreamInitialised = FALSE;

	int ret;
	unsigned have;
	z_stream strm;
	unsigned char in[CHUNK];
	unsigned char out[CHUNK];

	// allocate inflate state
	strm.zalloc = Z_NULL;
	strm.zfree = Z_NULL;
	strm.opaque = Z_NULL;

	int hdrLen = 0;
	if (contentEnc == CONTENT_ENCODING_GZIP) {
		BOOL rv;
		hdrLen = CheckGzipHeader(in, &rv);
		if (!rv)
			return FALSE;

		if (inflateInit2(&strm, -15) != Z_OK)
			return FALSE;

		strm.next_in  = in + hdrLen;
		strm.avail_in = (uInt) CHUNK - hdrLen;
	}
	else {
		// deflate
		if (inflateInit(&strm) != Z_OK)
			return FALSE;

		strm.avail_in = 0;
		strm.next_in = Z_NULL;
	}


	DWORD read;
	// decompress until deflate stream ends or end of file
	do {
		if (strm.avail_in == 0) {
			if (!ReceiveBlock(in, CHUNK, &read)) {
				(void) inflateEnd(&strm);
				return FALSE;
			}

			strm.avail_in = read;
			if (strm.avail_in == 0) {
				break;
			}
			strm.next_in = in;
		}

		// run inflate() on input until output buffer not full
		do {
			strm.avail_out = CHUNK;
			strm.next_out = out;
			ret = inflate(&strm, Z_NO_FLUSH);

			if (ret == Z_DATA_ERROR) {
				unsigned char *org_next_in = strm.next_in;
				uInt org_avail_in = strm.avail_in;

				// this is taken from firefox source code
				//
				// some servers (notably Apache with mod_deflate) don't generate zlib headers
				// insert a dummy header and try again
				static char dummy_head[2] = {
					0x8 + 0x7 * 0x10,
					(((0x8 + 0x7 * 0x10) * 0x100 + 30) / 31 * 31) & 0xFF,
				};
				inflateReset(&strm);
				strm.next_in = (Bytef*) dummy_head;
				strm.avail_in = sizeof(dummy_head);

				ret = inflate(&strm, Z_NO_FLUSH);
				if (ret != Z_OK)
					return FALSE;

				// stop an endless loop caused by non-deflate data being labelled as deflate
				if (mDummyStreamInitialised) {
					// endless loop detected
					return FALSE;
				}

				mDummyStreamInitialised = TRUE;
				// reset stream pointers to our original data
				strm.next_in = org_next_in;
				strm.avail_in = org_avail_in;
			}
			else if (ret == Z_MEM_ERROR) {
				(void) inflateEnd(&strm);
				return FALSE;
			}
			else if (ret == Z_OK || ret == Z_STREAM_END) {
				have = CHUNK - strm.avail_out;
				DWORD written;
				if (!file.Write(out, have, &written) || written != have) {
					(void) inflateEnd(&strm);
					return FALSE;
				}
			}
		} while (strm.avail_out == 0);

		// done when inflate() says it's done
	} while (ret != Z_STREAM_END);

	// clean up and return
	(void) inflateEnd(&strm);

	return ret == Z_STREAM_END ? TRUE : FALSE;
}

BOOL CHttpConnection::GetFile(CHttpResponse *res, const CString &fileName) {
	LOG0(5, "CHttpConnection::GetFile()");

	BOOL ret = FALSE;
	SysError = 0;

	// check response headers

	// Content-Encoding header
	EContentEncoding contentEncoding;
	CString sContentEncoding;
	if (res->GetHeader(_T("Content-Encoding"), sContentEncoding)) {
		if (sContentEncoding.Compare(_T("gzip")) == 0)
			contentEncoding = CONTENT_ENCODING_GZIP;
		else if (sContentEncoding.Compare(_T("deflate")) == 0)
			contentEncoding = CONTENT_ENCODING_DEFLATE;
		else
			contentEncoding = CONTENT_ENCODING_PLAIN;
	}
	else
		contentEncoding = CONTENT_ENCODING_PLAIN;

	// find Transfer-Encoding: chunked
	ChunkedTransfer = FALSE;
	CString sTransferEncoding;
	if (res->GetHeader(_T("Transfer-Encoding"), sTransferEncoding) &&
		sTransferEncoding.Compare(_T("chunked")) == 0) {
		ChunkedTransfer = TRUE;
		ChunkRemain = 0;
	}

	CString sContentLength;
	ResponseBodySize = 0;
	ResponseBodyDownloaded = 0;
	if (res->GetHeader(_T("Content-Range"), sContentLength)) {
		DWORD end;
		swscanf(sContentLength, _T("bytes %d-%d/%d"), &ResponseBodyDownloaded, &end, &ResponseBodySize);
	}
	else if (res->GetHeader(_T("Content-Length"), sContentLength)) {
		swscanf(sContentLength, _T("%d"), &ResponseBodySize);
	}

	BOOL append = res->GetStatusCode() == HTTP_STATUS_PARTIAL_CONTENT;

	// get file
	CBufferedFile file;
	DWORD dwCreationDispostion = append ? OPEN_EXISTING : CREATE_ALWAYS;
	if (file.Create(fileName, GENERIC_WRITE, FILE_SHARE_READ, dwCreationDispostion, FILE_ATTRIBUTE_NORMAL)) {
		if (append) file.Seek(0, FILE_END);

		switch (contentEncoding) {
			case CONTENT_ENCODING_GZIP:
			case CONTENT_ENCODING_DEFLATE:
				ret = ReceiveResponseBodyCompressed(file, contentEncoding);
				break;

			default:
				ret = ReceiveResponseBodyPlain(file);
				break;
		}

		if (!ret) SysError = GetLastError();

		file.Close();
	}
	else {
		SysError = GetLastError();
	}

	return ret;
}

⌨️ 快捷键说明

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