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

📄 buffio.cpp

📁 Windows CE 6.0 Server 源码
💻 CPP
📖 第 1 页 / 共 2 页
字号:
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft shared
// source or premium shared source license agreement under which you licensed
// this source code. If you did not accept the terms of the license agreement,
// you are not authorized to use this source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the SOURCE.RTF on your install media or the root of your tools installation.
// THE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES.
//
/*--
Module Name: BUFFIO.CPP
Abstract: Buffer handling class & socket IO helpers
--*/

#include "httpd.h"

// Wait for input on socket with timeout
int MySelect(SOCKET sock, DWORD dwMillisecs) {
	fd_set set;
	struct timeval t;

	if(dwMillisecs != INFINITE) 	{
		t.tv_sec = (dwMillisecs / 1000);
		t.tv_usec = (dwMillisecs % 1000)*1000;
	}
	FD_ZERO(&set);
	FD_SET(sock, &set);

	DEBUGMSG(ZONE_SOCKET, (L"HTTPD: Calling select(%x). Timeout=%d\r\n", sock, dwMillisecs));
	int iRet = select(0, &set, NULL, NULL, ((dwMillisecs==INFINITE) ? NULL : (&t)));
	DEBUGMSG(ZONE_SOCKET, (L"HTTPD: Select(%x) got %d\r\n", sock, iRet));
	return iRet;
}

// need space for iLen more data
BOOL CBuffer::AllocMem(DWORD dwLen) {
	// figure out buffer size
	DWORD dwAlloc = max(MINBUFSIZE, dwLen);
	
	// allocate or reallocate buffer
	if(!m_pszBuf) {
		m_pszBuf = MyRgAllocZ(char, dwAlloc);
		DEBUGMSG(ZONE_REQUEST_VERBOSE, (L"HTTPD: New buffer (data=%d size=%d buf=0x%08x)\r\n", dwLen, dwAlloc, m_pszBuf));
		m_iSize = dwAlloc;
	}
	else if((m_iSize-m_iNextIn) <= (int)dwLen) 	{
		DWORD dwBytesToReAlloc;

		if (! safeIntUAdd(dwAlloc,m_iSize,(UINT*)&dwBytesToReAlloc)) {
			DEBUGMSG(ZONE_ERROR,(L"HTTPD: ERROR: Integer overflow on buffer alloc\r\n"));
			DEBUGCHK(0);
			return FALSE;
		}

		PSTR pszTemp = MyRgReAlloc(char, m_pszBuf, m_iSize, dwBytesToReAlloc);
		if (!pszTemp) {
			DEBUGMSG(ZONE_ERROR, (L"HTTPD: CBuffer:AllocMem(%d) failed. GLE=%d\r\n", dwLen, GetLastError()));
			return FALSE;
		}

		m_pszBuf = pszTemp;
		m_iSize  = dwBytesToReAlloc;
		DEBUGMSG(ZONE_REQUEST_VERBOSE, (L"HTTPD: Realloc buffer (datasize=%d oldsize=%d size=%d buf=0x%08x)\r\n", dwLen, m_iSize, dwAlloc+m_iSize, m_pszBuf));
	}
	if(!m_pszBuf) 	{
		DEBUGMSG(ZONE_ERROR, (L"HTTPD: CBuffer:AllocMem(%d) failed. GLE=%d\r\n", dwLen, GetLastError()));
		m_iNextDecrypt = m_iNextInFollow = m_iSize = m_iNextOut = m_iNextIn = 0;
		m_chSaved = 0;
		return FALSE;
	}
	return TRUE;
}



// Suck in all white space before a request.  Note:  We techinally should let
// the filter get this too, but too much work.  Also note that we could read
// past a double CRLF if there was only white space before it, again this
// is an condition so we don't care about it.

// We don't read forever or else we set ourselves up for a DoS attack.
// If we get > MAX_WHITESPACE_READ characters then we give up. 
#define MAX_WHITESPACE_READ   8

BOOL CBuffer::TrimWhiteSpace(BOOL *pfAbort) {
	int i = 0, j = 0;
	DEBUGCHK(*pfAbort == FALSE);

	while (isspace(m_pszBuf[i]) && (i < m_iNextIn) && (i < MAX_WHITESPACE_READ)) { 
		i++;
	}

	if (i == MAX_WHITESPACE_READ) {
		DEBUGMSG(ZONE_ERROR,(L"HTTPD: Web server has been sent greater than %d whitespace chars before HTTP headers begin.  Refusing request\r\n",MAX_WHITESPACE_READ));
		*pfAbort = TRUE;
		return FALSE;
	}
	
	if (i == 0)
		return TRUE;
		
	if (i == m_iNextIn)
		return FALSE;  // need to read more data, all white spaces so far.

	for (j = 0; j < m_iNextIn - i; j++)
		m_pszBuf[j] = m_pszBuf[j+i];

	m_iNextIn -= i;

	DEBUGMSG(ZONE_PARSER,(L"HTTPD: TrimWhiteSpace removing first %d bytes from steam\r\n",i));
	return TRUE;
}


// This function reads eithr request-headers from the socket
// terminated by a double CRLF, OR reads a post-body from the socket
// terminated by having read the right number of bytes
// 
// We are keeping the really simple--we read the entire header
// into one contigous buffer before we do anything.
//
// dwLength is -1 for reading headers, or Content-Length for reading body
// or 0 is content-length is unknown, in which case it reads until EOF

// Note: This function is more than just a generic receive, it takes into account
// HTTP headers + POST status of current request.

HRINPUT CBuffer::RecvToBuf(SOCKET sock, DWORD dwLength, BOOL fFromFilter, BOOL fFirstPostRead, CHttpRequest *pRequest, BOOL fSSLRenegotiate) {
	DEBUG_CODE_INIT;
	int iScan = 0;
	HRINPUT ret = INPUT_ERROR;

	BOOL  fReadHeaders        = (dwLength == (DWORD)-1);
	BOOL  fIsSecure           = pRequest->IsSecure();
	BOOL  fScanHeadersForCRLF = fIsSecure ? FALSE : TRUE;

	// fSSLSkipFirstRead = TRUE when we have data was read in as part of the SSL handshake 
	// that is actually part of the HTTP request.  In this case decrypt what we have before calling recv(),
	// it's possible the entire HTTP request has already been read in so a recv() would block.
	BOOL  fSSLSkipFirstRead = (fIsSecure && m_iNextIn && fReadHeaders) ? TRUE : FALSE;
	DWORD dwBytesDecrypted = 0;
	DWORD dwBytesRemainingToBeRead;

	// dwSSLOffset is pointer to data that remains encrypted.
	// It's possible we have unencrypted data from a previous HTTP request (but 
	// when fSSLSkipFirstRead=TRUE we use different code path, so set=0).
	DWORD dwSSLOffset  = !fSSLSkipFirstRead ? m_iNextIn - m_iNextDecrypt : 0;

	// In cases web server requests a renegotiate *after* client has sent us all its POST
	// data, we read POST data first but then have to keep reading to get renegotiate params.
	// To do this we allocate extra data and keep listening.
	BOOL fForceSSLRenegotiate;

	// In typical case (i.e. reading HTTP headers) we read up to maximum header size.
	// However when we force SSL renegotiation, we'll read up to max header size+max POST size
	// as we've read the headers already.
	DWORD dwMaxBufferSize = g_pVars->m_dwMaxHeaderReadSize;
	if (!fReadHeaders)
		dwMaxBufferSize += g_pVars->m_dwPostReadSize;

	DEBUGMSG(ZONE_REQUEST_VERBOSE,(L"HTTPD: RecvToBuf() sock=%d,dwLength=%d,fFromFilter=%d,fFirstPostRead=%d,fSSLRenegotiate=%d,fReadHeaders=%d,fIsSecure=%d\r\n",
	                                sock,dwLength,fFromFilter,fFirstPostRead,fSSLRenegotiate,fReadHeaders,fIsSecure));
	WriteBufferToDebugOut(FALSE);
	BufferConsistencyChecks();

	// Some clients ignore the fact that we're an HTTP 1.0 server and send
	// us multiple HTTP requests on the same packet.  If we detect this situation when
	// reading in data we make note of it at the time and clean things up when reading 
	// in the headers to the next request.
	if (fReadHeaders && m_iNextRequestBegin) {
		DEBUGCHK(m_pszBuf[m_iNextRequestBegin] == 0);
		m_pszBuf[0] = m_chNextRequestSaved;

		DEBUGMSG(ZONE_REQUEST_VERBOSE,(L"HTTPD: End Cleanup: m_iNextRequestSize=%d,m_iNextRequestBegin=%d\r\n",m_iNextRequestSize,m_iNextRequestBegin));
		
		for (int i = 1; i < m_iNextRequestSize; i++)
			m_pszBuf[i] = m_pszBuf[m_iNextRequestBegin+i];

		m_iNextIn = m_iNextRequestSize;

		m_iNextRequestBegin  = m_iNextRequestSize = 0;
		m_chNextRequestSaved = 0;
		fScanHeadersForCRLF = TRUE;
	}

	// Both IE and Netscape tack on a trailing \r\n to POST data but don't
	// count it as part of the Content-length.  IIS doesn't pass the \r\n
	// to the script engine, so we don't either.  To do this, we set
	// the \r to \0.  Also we reset m_iNextIn.  This \r\n code is only
	// relevant when RecvToBuf is called from HandleRequest, otherwise
	// we assume it's a filter calling us and don't interfere.
	if (!fReadHeaders) {
		if (!fSSLRenegotiate && !fFromFilter && ((m_iNextIn-m_iNextOut) >= (int) dwLength))  {
			if (fFirstPostRead && (m_iNextIn-m_iNextOut) > (int) dwLength+2) {
				DEBUGMSG(ZONE_ERROR,(L"HTTPD: WARNING: more than one HTTP messages have been sent in one packet!  This is not valid HTTP 1.0! "
				                       L"Web server is cleaning up message and will process normally now, FIX CLIENT to make it HTTP 1.0 (not only 1.1) aware\r\n"));
				// client has sent us more than one HTTP request (or at least beginning of 2nd request)
				// in the packet we read on initial header read-in.  Save off information for next request.

				DEBUGMSG(ZONE_REQUEST_VERBOSE,(L"HTTPD: Begin cleanup: m_iNextRequestBegin=%d, m_iNextRequestSize=%d, m_iNextIn=%d,m_iNextOut=%d,dwLength=%d",m_iNextRequestBegin,m_iNextRequestSize,m_iNextIn,m_iNextOut,dwLength));
				
				m_iNextRequestBegin  = m_iNextOut + dwLength;
				m_iNextRequestSize   = m_iNextIn - m_iNextRequestBegin; // length of buffer
				m_iNextInFollow      = m_iNextIn = m_iNextRequestBegin;
				m_chNextRequestSaved = m_pszBuf[m_iNextIn];
				myretleave(INPUT_NOCHANGE,0);
			}

			m_iNextInFollow = m_iNextIn = m_iNextOut + dwLength;
			// Everything has been read into POST request already, no processing.
			myretleave(INPUT_NOCHANGE,0);
		}
		if (!fFromFilter) {
			dwLength = dwLength - (m_iNextIn - m_iNextOut);   // account for amount of POST data already in
		}
		m_iNextInFollow = m_iNextIn;

		// allocate or reallocate buffer.  Since we already know size we want, do it here rather than later.
		if(!AllocMem(dwLength+1))
			myretleave(INPUT_ERROR, 103);		
	}
	dwBytesRemainingToBeRead = dwLength;
	fForceSSLRenegotiate = (fSSLRenegotiate && (dwLength == 0));

	for(;;)  {
		// see if we got the double CRLF for HTTP Headers.
		if(fReadHeaders && fScanHeadersForCRLF)  {
			BOOL fScan = TRUE;		
			if (iScan == 0 && m_iNextIn) {
				BOOL fAbort = FALSE;
				fScan = TrimWhiteSpace(&fAbort);
				if (fAbort)  // too much white space was sent between keep-alive requests
					myretleave(INPUT_ERROR,111);
			}
			if (fScan) {
				while(iScan+3 < (fIsSecure ? (int) dwBytesDecrypted : m_iNextIn))  {
					if(m_pszBuf[iScan]=='\r' && m_pszBuf[iScan+1]=='\n' && m_pszBuf[iScan+2]=='\r' && m_pszBuf[iScan+3]=='\n') {
						DEBUGMSG(ZONE_REQUEST_VERBOSE,(L"HTTPD: RecvToBuf: found double CRLF to close headers\r\n"));
						myretleave(INPUT_OK,0);
					}
					iScan++;
				}
			}
		}
		// else see if we have the number of bytes we want.  
		// Browsers sometimes tack an extra \r\n to very end of POST data, even
		// though they don't include it in the Content-Length field.  IIS
		// never passes this extra \r\n to ISAPI extensions, neither do we.
		else if((!fSSLRenegotiate || (fSSLRenegotiate && !fForceSSLRenegotiate)) && 
		         !fReadHeaders && (dwBytesRemainingToBeRead == 0))  {
			DEBUGCHK(fIsSecure || ((int)dwLength  + 2 == (m_iNextIn-m_iNextInFollow) ||
			         (int)dwLength == (m_iNextIn-m_iNextInFollow)));

			DEBUGMSG(ZONE_REQUEST_VERBOSE,(L"HTTPD: RecvToBuf: we've got required # of bytes on POST!\r\n"));
//			m_iNextIn = m_iNextInFollow+(int)dwLength;	// don't copy trailing \r\n
			myretleave(INPUT_OK,0);
		}

		if ((fReadHeaders || fForceSSLRenegotiate) && ((int)dwMaxBufferSize <= m_iNextIn)) {
			DEBUGMSG(ZONE_ERROR,(L"HTTPD: Client has sent >= %d bytes in HTTP headers or SSL renegotiate, rejecting request!\r\n",dwMaxBufferSize));
			myretleave(INPUT_ERROR,109);
		}
		// fSSLSkipFirstRead = TRUE in case where we have data already read in but haven't decrypted
		// it yet - it's possible that the client will send no more data so select would timeout if we call it.
		if (!fSSLSkipFirstRead) {
			// check if we have input.
			switch(MySelect(sock, g_pVars->m_dwConnectionTimeout)) {
				case 0: 			myretleave((m_iNextIn ? INPUT_ERROR : INPUT_TIMEOUT),100);
				case SOCKET_ERROR: 	myretleave(INPUT_ERROR, 101);
			}
		}

		// check how much input is waiting
		DWORD dwAvailable   = 0;
		DWORD dwBytesToRecv = 0;

		if (!fSSLSkipFirstRead) {
			if(ioctlsocket(sock, FIONREAD, &dwAvailable))
				myretleave(INPUT_ERROR, 102);

			if (fReadHeaders || fForceSSLRenegotiate) {
				// only read up to dwMaxBufferSize.  If we don't get double CRLF on 
				// next pass through loop then we'll bomb out.
				if (dwAvailable + m_iNextIn > dwMaxBufferSize)

⌨️ 快捷键说明

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