#include #include #include #include #include #include "cgi.h" Cgi::Cgi( const char *strSource ) : aContent( new HashFunctionString(), 151, true ) { int length, j, k, mode = 0, slen = 0; char hexbuf[3] = { 0, 0, 0 }; char *buf, chr; Item *cur = NULL; int nCur = 0; if( strSource != NULL ) { loadContent( strSource ); } if( ( getenv( "CONTENT_LENGTH" ) ) ) { if( !strcmp ( getenv( "CONTENT_TYPE" ), "application/x-www-form-urlencoded" ) ) { length = atoi( getenv( "CONTENT_LENGTH" ) ); buf = new char[length + 1]; fread( buf, 1, length, stdin ); cur = new Item( ); aVars.append( cur ); cur->type = VAR_STDINPUT; for( j = 0; j < length; j++ ) { switch ( buf[j] ) { case '=': cur->name = new char[slen + 1]; slen = 0; break; case '&': cur->value = new char[slen + 1]; cur->len = slen; slen = 0; cur = new Item( ); aVars.append( cur ); cur->type = VAR_STDINPUT; break; default: switch ( buf[j] ) { case '%': /* per-cents mean a hex-code for an ASCII char */ j += 2; slen++; break; default: /* Nothing special, move along, folks... */ slen++; break; } break; } } cur->value = new char[slen + 1]; cur->len = slen; slen = 0; mode = 0; cur = ( Item * ) aVars.getAt( 0 ); k = 0; nCur = 0; for( j = 0; j < length; j++ ) { switch ( buf[j] ) { case '=': mode = 1; k = 0; break; case '&': mode = 0; k = 0; nCur++; cur = ( Item * ) aVars.getAt( nCur ); break; default: switch ( buf[j] ) { case '%': /* per-cents mean a hex-code for an ASCII char */ hexbuf[0] = buf[++j]; hexbuf[1] = buf[++j]; chr = ( char ) ( strtol( hexbuf, NULL, 16 ) ); break; case '+': /* Pluses mean spaces, odd, I know... */ chr = ' '; break; default: /* Nothing special, move along, folks... */ chr = buf[j]; break; } if( mode == 0 ) { cur->name[k] = chr; cur->name[++k] = '\0'; } else { cur->value[k] = chr; cur->value[++k] = '\0'; } break; } } delete buf; } else if( !strncmp ( getenv( "CONTENT_TYPE" ), "multipart/form-data;", 20 ) ) { char *boundary, *oname; int blen, j, k, olen; length = atoi( getenv( "CONTENT_LENGTH" ) ); buf = new char[length + 1]; fread( buf, 1, length, stdin ); for( blen = 0; buf[blen + 1] != '\n'; blen++ ); boundary = new char[blen + 1]; memcpy( boundary, buf, blen ); boundary[blen] = '\0'; j = blen + 2; for( ;; ) { cur = new Item( ); aVars.append( cur ); cur->type = VAR_STDINPUT; if( !strncmp ( buf + j, "Content-Disposition: form-data; name=\"", 38 ) ) { j += 38; for( k = 0; buf[j + k] != '\"'; k++ ); oname = cur->name = new char[k + 1]; memcpy( cur->name, buf + j, k ); olen = k; cur->name[k] = '\0'; j += k + 1; if( !strncmp( buf + j, "; filename=\"", 12 ) ) /* Must be a file */ { /* Acquire file name */ j += 12; for( k = 0; buf[j + k] != '\"'; k++ ); cur->value = new char[k + 1]; memcpy( cur->value, buf + j, k ); cur->value[k] = '\0'; cur->len = k; j += k + 3; /* Acquire content type */ if( !strncmp( "Content-Type: ", buf + j, 14 ) ) { j += 14; cur = new Item( ); aVars.append( cur ); cur->type = VAR_STDINPUT; cur->name = new char[olen + 1]; memcpy( cur->name, oname, olen + 1 ); for( k = 0; buf[j + k + 1] != '\n'; k++ ); cur->value = new char[k + 1]; memcpy( cur->value, buf + j, k ); cur->value[k] = '\0'; cur->len = k; j += k; } else { cur = new Item( ); aVars.append( cur ); cur->type = VAR_STDINPUT; cur->name = new char[olen + 1]; memcpy( cur->name, oname, olen + 1 ); cur->value = new char[1]; cur->value[0] = '\0'; cur->len = 0; } j += 4; /* Acquire content */ cur = new Item( ); aVars.append( cur ); cur->type = VAR_STDINPUT; cur->name = new char[olen + 1]; memcpy( cur->name, oname, olen + 1 ); if( !strncmp( buf + j + k, boundary, blen ) ) { cur->value = new char[1]; cur->value[0] = '\0'; j += blen + 4; } else if( !strncmp( buf + j + k + 1, boundary, blen ) ) { cur->value = new char[1]; cur->value[0] = '\0'; j += blen + 5; } else { for( k = 0; strncmp( buf + j + k + 2, boundary, blen ); k++ ); cur->value = new char[k + 1]; memcpy( cur->value, buf + j, k ); cur->value[k] = '\0'; cur->len = k; j += k + blen + 4; } } else { j += 4; for( k = 0; strncmp( buf + j + k + 2, boundary, blen ); k++ ); cur->value = new char[k + 1]; memcpy( cur->value, buf + j, k ); cur->value[k] = '\0'; cur->len = k; j += k + blen + 4; } if( buf[j + 1] == '\n' ) j += 2; if( j >= length ) break; } else { cur->name = ( char * ) "ERROR"; cur->value = ( char * ) "Error here"; } } } delete buf; } if( ( buf = getenv( "HTTP_COOKIE" ) ) ) { int lbase = aVars.getSize( ); length = strlen( buf ); cur = new Item( ); aVars.append( cur ); cur->type = VAR_COOKIE; for( j = 0; j < length; j++ ) { switch ( buf[j] ) { case '=': cur->name = new char[slen + 1]; slen = 0; break; case ';': cur->value = new char[slen + 1]; cur->len = slen; slen = 0; cur = new Item( ); aVars.append( cur ); cur->type = VAR_COOKIE; break; default: switch ( buf[j] ) { case '%': /* per-cents mean a hex-code for an ASCII char */ j += 2; slen++; break; default: /* Nothing special, move along, folks... */ slen++; break; } break; } } cur->value = new char[slen + 1]; cur->len = slen; slen = 0; cur = ( Item * ) aVars.getAt( lbase ); mode = 0; k = 0; nCur = lbase; for( j = 0; j < length; j++ ) { switch ( buf[j] ) { case '=': mode = 1; k = 0; break; case ';': mode = 0; k = 0; nCur++; cur = ( Item * ) aVars.getAt( nCur ); break; default: switch ( buf[j] ) { case '%': /* per-cents mean a hex-code for an ASCII char */ hexbuf[0] = buf[++j]; hexbuf[1] = buf[++j]; chr = ( char ) ( strtol( hexbuf, NULL, 16 ) ); break; case '+': /* Pluses mean spaces, odd, I know... */ chr = ' '; break; case ' ': continue; break; default: /* Nothing special, move along, folks... */ chr = buf[j]; break; } if( mode == 0 ) { cur->name[k] = chr; cur->name[++k] = '\0'; } else { cur->value[k] = chr; cur->value[++k] = '\0'; } break; } } } if( ( buf = getenv( "QUERY_STRING" ) ) ) { if( strlen( buf ) > 0 ) { int lbase = aVars.getSize( ); length = strlen( buf ); cur = new Item( ); aVars.append( cur ); cur->type = VAR_CMDLINE; for( j = 0; j < length; j++ ) { switch ( buf[j] ) { case '=': cur->name = new char[slen + 1]; slen = 0; break; case '&': cur->value = new char[slen + 1]; cur->len = slen; slen = 0; cur = new Item( ); aVars.append( cur ); cur->type = VAR_CMDLINE; break; default: switch ( buf[j] ) { case '%': /* per-cents mean a hex-code for an ASCII char */ j += 2; slen++; break; default: /* Nothing special, move along, folks... */ slen++; break; } break; } } cur->value = new char[slen + 1]; cur->len = slen; slen = 0; cur = ( Item * ) aVars.getAt( lbase ); nCur = lbase; mode = 0; k = 0; for( j = 0; j < length; j++ ) { switch ( buf[j] ) { case '=': mode = 1; k = 0; break; case '&': mode = 0; k = 0; nCur++; cur = ( Item * ) aVars.getAt( nCur ); break; default: switch ( buf[j] ) { case '%': /* per-cents mean a hex-code for an ASCII char */ hexbuf[0] = buf[++j]; hexbuf[1] = buf[++j]; chr = ( char ) ( strtol( hexbuf, NULL, 16 ) ); break; case '+': /* Pluses mean spaces, odd, I know... */ chr = ' '; break; default: /* Nothing special, move along, folks... */ chr = buf[j]; break; } if( mode == 0 ) { cur->name[k] = chr; cur->name[++k] = '\0'; } else { cur->value[k] = chr; cur->value[++k] = '\0'; } break; } } } } } Cgi::~Cgi( ) { } char *Cgi::getVarValue( const char *name, int skip, unsigned char type ) { for( int j = 0; j < aVars.getSize( ); j++ ) { Item *cur = ( Item * ) aVars.getAt( j ); if( !strcmp( cur->name, name ) ) { if( ( cur->type & type ) ) { if( skip <= 0 ) { return cur->value; } else { skip--; } } } } return NULL; } int Cgi::getVarLength( const char *name, int skip, unsigned char type ) { for( int j = 0; j < aVars.getSize( ); j++ ) { Item *cur = ( Item * ) aVars.getAt( j ); if( !strcmp( cur->name, name ) ) { if( ( cur->type & type ) ) { if( skip <= 0 ) { return cur->len; } else { skip--; } } } } return -1; } void Cgi::writeDebugInfo() { printf( "
\n" );
    printf( "0x%02X - stdInput | 0x%02X - cookie | 0x%02X - cmdLine\n\n",
             VAR_STDINPUT, VAR_COOKIE, VAR_CMDLINE );
    for( int j = 0; j < aVars.getSize(  ); j++ )
    {
        Item *item = ( Item * ) aVars.getAt( j );
        printf("[%s] = \"%s\" [0x%02X]\n", item->name,
                 item->value, item->type );
    }
    printf( "
\n" ); } void Cgi::writeContentHeader( int type ) { switch( type ) { case headerHTML: printf("Content-type: text/html\n\n"); break; } } void Cgi::writeContent( const char *name, ...) { char *templ = (char *)aContent.get(name); if( templ ) { va_list ap; va_start (ap, name); vprintf (templ, ap); va_end (ap); } else { printf("Error finding content labeled \"%s\"\n", name ); } } void Cgi::loadContent( const char *strSource ) { FILE *fh = NULL; if( strSource == NULL ) { extern char *program_invocation_short_name; char *tmpName = new char[strlen(program_invocation_short_name)+10]; memset( tmpName, 0, strlen(program_invocation_short_name)+10 ); strcpy( tmpName, program_invocation_short_name ); strcat( tmpName, ".content" ); fh = fopen( tmpName, "rt" ); delete tmpName; } else { fh = fopen( strSource, "rt" ); } if( fh == NULL ) return; struct stat xStats; fstat( fileno( fh ), &xStats ); char *bigBuf = new char[xStats.st_size+1]; memset( bigBuf, 0, xStats.st_size+1 ); fread( bigBuf, 1, xStats.st_size, fh ); fclose( fh ); // Now we can actually load stuff from the file, first we need to make us up a format... int lSize=0; struct Content { char *name; char *value; } xCont; int j = 0; while( j < xStats.st_size ) { // We're looking for a content-block init statement for( ; j < xStats.st_size; j++ ) { if( bigBuf[j] == '#' ) { if( bigBuf[j+1] == '{' ) { break; } } } j=j+2; if( j >= xStats.st_size ) break; for( ; bigBuf[j] == ' ' || bigBuf[j] == '\t'; j++ ); for( lSize = 0; lSize+j < xStats.st_size && bigBuf[lSize+j] != '\n' && bigBuf[lSize+j] != '\r'; lSize++ ); xCont.name = new char[lSize+1]; memset( xCont.name, 0, lSize+1 ); memcpy( xCont.name, &bigBuf[j], lSize ); j += lSize+1; for( lSize = 0; lSize+j < xStats.st_size; lSize++ ) { if( bigBuf[lSize+j] == '#' ) { if( bigBuf[lSize+j+1] == '}' ) { break; } } } xCont.value = new char[lSize+1]; memset( xCont.value, 0, lSize+1 ); memcpy( xCont.value, &bigBuf[j], lSize ); aContent.insert( xCont.name, xCont.value ); j += lSize + 2; } } void Cgi::writeCookie( char const *name, char const *value, char const *expires, char const *path, char const *domain, bool secure ) { printf("Set-Cookie: %s=%s", name, value ); if( expires != NULL ) { printf("; expires=%s", expires ); } if( path != NULL ) { printf("; path=%s", path ); } if( domain != NULL ) { printf("; domain=%s", domain ); } if( secure ) { printf("; secure"); } printf("\n"); }