/*++ Copyright (c) 1997 Microsoft Corporation Module Name: readcli.c Abstract: This module absorbs input from the client, and then returns it to the client. Revision History: --*/ #define WIN32_LEAN_AND_MEAN #include #include #include #include #define BUFFER_LENGTH 4096 #define STRING_LENGTH 80 // Prototypes BOOL SendErrorToClient( LPEXTENSION_CONTROL_BLOCK pec, CHAR *szErrorText ); BOOL WINAPI GetExtensionVersion( HSE_VERSION_INFO *Version ) /*++ Routine Description: Sets the ISAPI extension version information. Arguments: Version pointer to HSE_VERSION_INFO structure Return Value: TRUE --*/ { Version->dwExtensionVersion = MAKELONG( HSE_VERSION_MINOR, HSE_VERSION_MAJOR ); strcpy( Version->lpszExtensionDesc, "ReadClient Extension" ); return TRUE; } DWORD WINAPI HttpExtensionProc( LPEXTENSION_CONTROL_BLOCK pec ) /*++ Routine Description: This is the main routine for any ISAPI application. We read in all the data from the client, using the ReadClient function, and then spit it all back out to the client using WriteClient. Arguments: pec pointer to ECB containing parameters related to the request. Return Value: Either HSE_STATUS_SUCCESS or HSE_STATUS_ERROR --*/ { BOOL bResult; CHAR *szBuffer; CHAR szTemp[BUFFER_LENGTH]; CHAR szTmpBuf[BUFFER_LENGTH]; DWORD dwBytesRead; DWORD dwBytesWritten; DWORD dwTotalRead; DWORD dwTotalWritten; DWORD dwContentLength; DWORD dwBufferSize; HSE_SEND_HEADER_EX_INFO SendHeaderExInfo; // Determine the amount of data available from the // Content-Length header dwBufferSize = sizeof( szTmpBuf ) - 1; bResult = pec->GetServerVariable( pec->ConnID, "CONTENT_LENGTH", szTmpBuf, &dwBufferSize ); if ( !bResult ) { bResult = SendErrorToClient( pec, "Content-Length header not found" ); if ( !bResult ) { return( HSE_STATUS_ERROR ); } return( HSE_STATUS_SUCCESS ); } dwContentLength = atol( szTmpBuf ); // Allocate the buffer based on the Content-Length szBuffer = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwContentLength + 5 ); if ( szBuffer == NULL ) { sprintf( szTemp, "Unable to allocate %ld bytes of memory for buffer", dwContentLength + 5 ); bResult = SendErrorToClient( pec, szTemp ); if ( !bResult ) { return( HSE_STATUS_ERROR ); } return( HSE_STATUS_SUCCESS ); } // If the client didn't post anything, return and create a nice form // for them if ( pec->cbAvailable == 0 ) { bResult = SendErrorToClient( pec, "Your request did not contain any data" ); if ( !bResult ) { return( HSE_STATUS_ERROR ); } return( HSE_STATUS_SUCCESS ); } // Initialize variables before reading in the data dwTotalWritten = 0; dwTotalRead = pec->cbAvailable; // Copy the first chunk of the data into the buffer strncpy( szBuffer, pec->lpbData, dwTotalRead ); szBuffer[dwTotalRead] = 0; // Loop to read in the rest of the data from the client while ( dwTotalRead < pec->cbTotalBytes ) { // Set the size of our temporary buffer dwBytesRead = sizeof( szTmpBuf ) - 1; if ( (dwTotalRead + dwBytesRead) > pec->cbTotalBytes ) { dwBytesRead = pec->cbTotalBytes - dwTotalRead; } // Read the data into the temporary buffer bResult = pec->ReadClient( pec->ConnID, szTmpBuf, &dwBytesRead ); if ( !bResult ) { HeapFree( GetProcessHeap(), 0, szBuffer ); return( HSE_STATUS_ERROR ); } // NULL-Terminate the temporary buffer szTmpBuf[dwBytesRead] = 0; // Append the temporary buffer to the real buffer if ( dwBytesRead != 0 ) { strcat( szBuffer + dwTotalRead, szTmpBuf ); } dwTotalRead += dwBytesRead; } // while ( dwTotalRead < pec->cbTotalBytes ) // All the data has been read in and stored in our buffer // Now send the data back to the client SendHeaderExInfo.pszStatus = "200 OK"; SendHeaderExInfo.pszHeader = "Content-Type: text/html\r\n\r\n"; SendHeaderExInfo.cchStatus = lstrlen( SendHeaderExInfo.pszStatus ); SendHeaderExInfo.cchHeader = lstrlen( SendHeaderExInfo.pszHeader ); SendHeaderExInfo.fKeepConn = FALSE; bResult = pec->ServerSupportFunction( pec->ConnID, HSE_REQ_SEND_RESPONSE_HEADER_EX, &SendHeaderExInfo, NULL, NULL ); if ( !bResult ) { HeapFree( GetProcessHeap(), 0, szBuffer ); return( HSE_STATUS_ERROR ); } dwBytesWritten = dwTotalRead; bResult = pec->WriteClient( pec->ConnID, szBuffer, &dwBytesWritten, 0 ); if ( !bResult ) { HeapFree( GetProcessHeap(), 0, szBuffer ); return( HSE_STATUS_ERROR ); } HeapFree( GetProcessHeap(), 0, szBuffer ); return( HSE_STATUS_SUCCESS ); } BOOL WINAPI TerminateExtension( DWORD dwFlags ) /*++ Routine Description: This function is called when the WWW service is shutdown Arguments: dwFlags - HSE_TERM_ADVISORY_UNLOAD or HSE_TERM_MUST_UNLOAD Return Value: TRUE if extension is ready to be unloaded, FALSE otherwise --*/ { return TRUE; } BOOL SendErrorToClient( LPEXTENSION_CONTROL_BLOCK pec, CHAR *szErrorText ) /*++ Routine Description: This function sends any error messages and usage information to the client. It also creates a nice little form which can be used to post data. Arguments: pec - pointer to ECB containing parameters related to the request szErrorText - Helpful error text to send to the client Return Value: TRUE or FALSE, depending on the success of WriteClient --*/ { BOOL bResult; CHAR szTemp[BUFFER_LENGTH]; DWORD dwBytesWritten; HSE_SEND_HEADER_EX_INFO SendHeaderExInfo; SendHeaderExInfo.pszStatus = "200 OK"; SendHeaderExInfo.pszHeader = "Content-Type: text/html\r\n\r\n"; SendHeaderExInfo.cchStatus = lstrlen( SendHeaderExInfo.pszStatus ); SendHeaderExInfo.cchHeader = lstrlen( SendHeaderExInfo.pszHeader ); SendHeaderExInfo.fKeepConn = FALSE; bResult = pec->ServerSupportFunction( pec->ConnID, HSE_REQ_SEND_RESPONSE_HEADER_EX, &SendHeaderExInfo, NULL, NULL ); if ( !bResult ) { return FALSE; } dwBytesWritten = sprintf( szTemp, "

Error: %s

\r\n\r\n" "Usage: readcli.dll

\r\n\r\n" "Request must be a POST request, with extra data

\r\n" "

Sample Form

\r\n" "Enter data below:
\r\n" "
\r\n" "
\r\n" "\r\n", szErrorText ); bResult = pec->WriteClient( pec->ConnID, szTemp, &dwBytesWritten, 0 ); return( bResult ); }