httpd-users mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Andrus" <eetas...@online.ee>
Subject [users@httpd] Help compiling CGI connector in windows to return binary data
Date Tue, 08 Apr 2003 19:50:58 GMT
I have found that the CGI connector which I use with Apache destroys binary
data.

Very small file, mycgi.c uses the following code to return data:

// Return results to web server.
while ( !feof( datFile ) )
{
if ( NULL != fgets( buffer, DATA_BUFFER_LENGTH, datFile ) )
 printf( "%s", buffer );
 }


This code uses printf() to return data to Apache web server.
Unfortunately, using printf() discards 0x00 bytes.
fwrite() must be used instead of printf() and problably fgets() should
be replaced with fread()

I don't have C compiler to fix this and create a fixed exe file.

Can anybody fix the c code and create a fixed .exe file ?
Result exe file must be capable to run as Apache windows CGI program.

This is created in Microsoft C++ but any Windows C compiled can actually
be used. I have included a makefile and some Microsoft Developer Studio conf
files originally used to create a vfpcgi.exe file.

The zip file with code is included with this letter.
This file creates a temp file in disk containing a whole cgi request.
Maybe such fixed connectors for windows already exist somewhere ?

The exe file needs to be created from the following c code:

#include <io.h>
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <winbase.h>
#include <time.h>
#include <direct.h>
#include <sys/timeb.h>

#define TEMP_PREFIX_LENGTH 8  // Length of temporary file prefix excluding
null terminator
#define DATA_BUFFER_LENGTH 1000  // Length of data buffer.

#define MAX_FILE_ATTEMPTS  10  // Number of times to attempt creating temp
file.
#define ACK_RETRY_MILLISECONDS 250  // Number of milliseconds for each retry
attempt to read ACK file.
#define ACK_TIMEOUT_SECONDS     60  // Number of seconds until attempts to
read ACK file time out.

#define SERVER_INACCESSIBLE_TITLE_LOC "Server Inaccessible"
#define SERVER_INACCESSIBLE_TEXT_LOC "Communication with the server is not
possible at this time."
#define SERVER_TIMEOUT_TITLE_LOC "Server Timeout"
#define SERVER_TIMEOUT_TEXT_LOC  "The server timed out. It is probably too
busy to fulfill your request."
#define SERVER_NODATA_TITLE_LOC "Server Error"
#define SERVER_NODATA_TEXT_LOC "A server error occurred.  No return data was
sent."

void errorform( char *errorstring, char *errortitle );

void main( int argc, char *argv[] )
{

 char tmpPrefix[TEMP_PREFIX_LENGTH+1];
 char tmpFolder[] = "\\temp";
 char tmpName[_MAX_PATH];

 char *t1   = NULL;
 char *tempbuffer = NULL;

 char datFileName[_MAX_PATH];
 char ackFileName[_MAX_PATH];
 char atnFileName[_MAX_PATH];

 FILE *datFile    = NULL;
 FILE *atnFile    = NULL;
 FILE *tempFile   = NULL;
 struct _timeb timebuffer;


 char buffer[DATA_BUFFER_LENGTH];
 int cont_len, bytesread, fileattempts;
 time_t begintout, chktout;
 char **envptr;
 fpos_t pos;

 // Turn stdin buffering off
 setvbuf( stdin, NULL, _IONBF, 0 );

 // Create server.app compatible temporary folder.
 // Note:  Server.app is looking for files in <current drive>:\temp,
 // not in the actual system temporary folder.
 _mkdir( tmpFolder );

 // Seed random number generator and zero fileattempts counter.
 _ftime( &timebuffer );
 srand( ((timebuffer.time & 0xFF)<<10) | timebuffer.millitm );
 fileattempts = 0;

 for (;;)
 {

  fileattempts++;

  // If we've tried MAX_FILE_ATTEMPTS times, give error message.
  if ( fileattempts > MAX_FILE_ATTEMPTS )
  {
   errorform( SERVER_INACCESSIBLE_TEXT_LOC, SERVER_INACCESSIBLE_TITLE_LOC );
   goto CleanupAndExit;
  }

  // Create random file name. Format is "VF" plus unique 4 digit hex number
  // representing the processid, plus 2 digit random number (in case
multiple
  // machines are running the CGI scripts).
  sprintf( tmpPrefix, "VF%04X%02X", (DWORD) GetCurrentProcessId(), rand() &
0xFF);

  // Build temporary file name.
  sprintf( tmpName, "%s\\%s", tmpFolder, tmpPrefix );

  // Create the names for the three files.
  sprintf( datFileName, "%s.dat", tmpName );
  sprintf( ackFileName, "%s.ack", tmpName );
  sprintf( atnFileName, "%s.atn", tmpName );

  // Create data file.
  datFile = fopen( datFileName, "a" );

  // Make sure data file didn't already exist.
  if ( NULL != datFile )
  {
   // Seek to the end of the file.
   fseek( datFile, 0, SEEK_END );
   if( 0 == fgetpos( datFile, &pos ) )
   {
    // We know fgetpos was successful, now check position.
    // If pos is zero, we know we have a new file and can break out of loop.
    if ( 0 == pos ) break;
   }
   fclose( datFile );
  }

 }

 // We could check REQUEST_METHOD here, but what would be the point?
 // If CONTENT_LENGTH is NULL, we won't read the stdin, otherwise we will.
 // This is entirely for POST method requests.
 t1 = getenv( "CONTENT_LENGTH" );
 if ( NULL != t1 )
 {
  cont_len = atoi( t1 );

  tempbuffer = (char *) malloc( sizeof(char) * cont_len );
  if ( NULL == tempbuffer )
  {
   goto CleanupAndExit;
  }

  bytesread = fread( tempbuffer, sizeof(char), cont_len, stdin );
  if ( 0 != bytesread )
   fwrite( tempbuffer, sizeof(char), bytesread, datFile );

  free( tempbuffer );
 }

 // This part reads all of the environment variables and sends
 // them along in the DAT file as well. All ampersand delimited.
 envptr = environ;
 while ( NULL != *envptr )
 {
  fputs( "&", datFile );
  fputs( *envptr, datFile );
  envptr++;
 }
 fclose( datFile );

 // Create ATN File
 atnFile = fopen( atnFileName,"w" );
 if ( NULL == atnFile )
 {
  errorform( SERVER_INACCESSIBLE_TEXT_LOC , SERVER_INACCESSIBLE_TITLE_LOC );
  goto CleanupAndExit;
 }

 fclose( atnFile );

 _flushall();

 // Wait for Server to ACK
 time( &begintout );
 do
 {
  tempFile = fopen( ackFileName, "r" );
  if ( NULL != tempFile ) break; // Break before sleep if successful.
  time( &chktout );
  Sleep( ACK_RETRY_MILLISECONDS );
 //if _access() can't find the file, then the query is currently being
processed.
 //Keep looping for another ACK_TIMEOUT_SECONDS.
 } while ( ( NULL == tempFile ) && (( difftime( chktout, begintout ) <
ACK_TIMEOUT_SECONDS )
  || ((_access(atnFileName,0) == -1) && ( difftime( chktout, begintout ) <
(2*ACK_TIMEOUT_SECONDS) ))));

 if ( NULL != tempFile )
 {
  fclose( tempFile );
 }
 else
 {
  errorform( SERVER_TIMEOUT_TEXT_LOC , SERVER_TIMEOUT_TITLE_LOC);
  goto CleanupAndExit;
 }

 // Send the Data file to stdout.
 datFile = fopen( datFileName, "r" );
 if ( NULL == datFile )
 {
  errorform( SERVER_NODATA_TEXT_LOC , SERVER_NODATA_TITLE_LOC);
  goto CleanupAndExit;
 }
 else
 {
  // Return results to web server.
  while ( !feof( datFile ) )
  {
   if ( NULL != fgets( buffer, DATA_BUFFER_LENGTH, datFile ) )
    printf( "%s", buffer );
  }
  fclose( datFile );
 }

CleanupAndExit:

 // Close all file handles.
 _fcloseall();

 // Remove temporary files.
 remove( ackFileName );
 remove( datFileName );
 remove( atnFileName );

 return;

}

void errorform( char *errorstring, char *errortitle )
{
 printf( "Content-Type: text/html\n\n" );
 printf( "<head><title>%s</title></head>\n", errortitle );
 printf( "<body>\n<h1>%s</h1>\n", errortitle );
 printf( "%s<hr>\n</body>", errorstring );
}


Mime
View raw message