/**************************************************************************** ** *F SySetInitialGapRootPaths( <string> ) . . . . . set the root directories ** ** Set up GAP's initial root paths, based on the location of the ** GAP executable. */ static void SySetInitialGapRootPaths(void) { if (GAPExecLocation[0] != 0) { // GAPExecLocation might be a subdirectory of GAP root, // so we will go and search for the true GAP root. // We try stepping back up to two levels. char pathbuf[GAP_PATH_MAX]; char initgbuf[GAP_PATH_MAX]; strxcpy(pathbuf, GAPExecLocation, sizeof(pathbuf)); for (Int i = 0; i < 3; ++i) { strxcpy(initgbuf, pathbuf, sizeof(initgbuf)); strxcat(initgbuf, "lib/init.g", sizeof(initgbuf)); if (SyIsReadableFile(initgbuf) == 0) { SySetGapRootPath(pathbuf); // escape from loop return; } // try up a directory level strxcat(pathbuf, "../", sizeof(pathbuf)); } } // Set GAP root path to current directory, if we have no other // idea, and for backwards compatibility. // Note that GAPExecLocation must always end with a slash. SySetGapRootPath("./"); }
// fill in file name in buffer pointed by filename FRESULT philes_nextfile(char *filename, uint8_t terminate) { while ((f_readdir(&dir, &finfo) == FR_OK) && finfo.fname[0]) { if (finfo.fattrib & AM_DIR) { // nowai } else { if (endsWith(finfo.fname, ".FDD")) { if (filename != 0) { if (terminate) { strncpy(filename, finfo.fname, 12); } else { strxcpy(filename, finfo.fname); } } return 0; } } } return FR_NO_FILE; }
static UInt GetMasterPty ( int *pty, Char *nametty, Char *namepty ) { #if HAVE_POSIX_OPENPT && HAVE_PTSNAME /* Attempt to use POSIX 98 pseudo ttys. Opening a master tty is done via posix_openpt, which is available on virtually every current UNIX system; indeed, according to gnulib, it is available on at least the following systems: - glibc >= 2.2.1 (released January 2001; but is a stub on GNU/Hurd), - Mac OS X >= 10.4 (released April 2005), - FreeBSD >= 5.1 (released June 2003), - NetBSD >= 3.0 (released December 2005), - AIX >= 5.2 (released October 2002), - HP-UX >= 11.31 (released February 2007), - Solaris >= 10 (released January 2005), - Cygwin >= 1.7 (released December 2009). Systems lacking posix_openpt (in addition to older versions of the systems listed above) include: - OpenBSD - Minix 3.1.8 - IRIX 6.5 - OSF/1 5.1 - mingw - MSVC 9 - Interix 3.5 - BeOS */ *pty = posix_openpt( O_RDWR | O_NOCTTY ); if (*pty > 0) { if (grantpt(*pty) || unlockpt(*pty)) { close(*pty); return 1; } strxcpy(nametty, ptsname(*pty), 32); return 0; } return 1; #elif HAVE_GETPT && HAVE_PTSNAME_R /* Attempt to use glibc specific APIs, for compatibility with older glibc versions (before 2.2.1, release January 2001). */ *pty = getpt(); if (*pty > 0) { if (grantpt(*pty) || unlockpt(*pty)) { close(*pty); return 1; } ptsname_r(*pty, nametty, 32); return 0; } return 1; #elif HAVE_PTSNAME /* Attempt to use Sys V pseudo ttys on systems that don't have posix_openpt, getpt or openpty, but do have ptsname. Platforms *missing* ptsname include: Mac OS X 10.3, OpenBSD 3.8, Minix 3.1.8, mingw, MSVC 9, BeOS. */ *pty = open( "/dev/ptmx", O_RDWR ); if ( *pty < 0 ) return 1; strxcpy(nametty, ptsname(*pty), 32); return 0; #elif HAVE_GETPSEUDOTTY /* TODO: From which system(s) does getpseudotty originate? */ *pty = getpseudotty( nametty, namepty ); return *pty < 0 ? 1 : 0; #elif HAVE__GETPTY /* Available on SGI IRIX >= 4.0 (released September 1991). See also http://techpubs.sgi.com/library/tpl/cgi-bin/getdoc.cgi?cmd=getdoc&coll=0530&db=man&fname=7%20pty */ char * line; line = _getpty(pty, O_RDWR|O_NDELAY, 0600, 0) ; if (0 == line) return 1; strcpy( nametty, line ); return 0; #else /* fallback to old-style BSD pseudoterminals, doing a brute force search over all pty device files. */ int devindex; int letter; int ttylen, ptylen; ttylen = strlen(nametty); ptylen = strlen(namepty); for ( letter = 0; SYS_PTYCHAR1[letter]; ++letter ) { nametty[ttylen-2] = SYS_PTYCHAR1[letter]; namepty[ptylen-2] = SYS_PTYCHAR1[letter]; for ( devindex = 0; SYS_PTYCHAR2[devindex]; ++devindex ) { nametty[ttylen-1] = SYS_PTYCHAR2[devindex]; namepty[ptylen-1] = SYS_PTYCHAR2[devindex]; *pty = open( namepty, O_RDWR ); if ( *pty >= 0 ) { int slave = open( nametty, O_RDWR ); if ( slave >= 0 ) { close(slave); return 0; } close(*pty); } } } return 1; #endif }
static void SySetGapRootPath( const Char * string ) { const Char * p; Char * q; Int i; Int n; /* set string to a default value if unset */ if ( string == 0 || *string == 0 ) { string = "./"; } /* ** check if we append, prepend or overwrite. */ if( string[0] == ';' ) { /* Count the number of root directories already present. */ n = 0; while( SyGapRootPaths[n][0] != '\0' ) n++; /* Skip leading semicolon. */ string++; } else if( string[ strlen(string) - 1 ] == ';' ) { /* Count the number of directories in 'string'. */ n = 0; p = string; while( *p ) if( *p++ == ';' ) n++; /* Find last root path. */ for( i = 0; i < MAX_GAP_DIRS; i++ ) if( SyGapRootPaths[i][0] == '\0' ) break; i--; #ifdef HPCGAP n *= 2; // for each root <ROOT> we also add <ROOT/hpcgap> as a root #endif /* Move existing root paths to the back */ if( i + n >= MAX_GAP_DIRS ) return; while( i >= 0 ) { memcpy( SyGapRootPaths[i+n], SyGapRootPaths[i], sizeof(SyGapRootPaths[i+n]) ); i--; } n = 0; } else { /* Make sure to wipe out all possibly existing root paths */ for( i = 0; i < MAX_GAP_DIRS; i++ ) SyGapRootPaths[i][0] = '\0'; n = 0; } /* unpack the argument */ p = string; while ( *p ) { if( n >= MAX_GAP_DIRS ) return; q = SyGapRootPaths[n]; while ( *p && *p != ';' ) { *q = *p++; #ifdef SYS_IS_CYGWIN32 /* fix up for DOS */ if (*q == '\\') *q = '/'; #endif q++; } if ( q == SyGapRootPaths[n] ) { strxcpy( SyGapRootPaths[n], "./", sizeof(SyGapRootPaths[n]) ); } else if ( q[-1] != '/' ) { *q++ = '/'; *q = '\0'; } else { *q = '\0'; } if ( *p ) { p++; } n++; #ifdef HPCGAP // or each root <ROOT> we also add <ROOT/hpcgap> as a root (and first) if( n < MAX_GAP_DIRS ) { strlcpy( SyGapRootPaths[n], SyGapRootPaths[n-1], sizeof(SyGapRootPaths[n]) ); } strxcat( SyGapRootPaths[n-1], "hpcgap/", sizeof(SyGapRootPaths[n-1]) ); n++; #endif } }
void InitSystem ( Int argc, Char * argv [] ) { Char * *ptrlist; UInt i; /* loop variable */ Int res; /* return from option processing function */ /* Initialize global and static variables */ SyCTRD = 1; SyCompilePlease = 0; SyDebugLoading = 0; SyLineEdit = 1; #ifdef HPCGAP SyUseReadline = 0; #else SyUseReadline = 1; #endif SyMsgsFlagBags = 0; SyNrCols = 0; SyNrColsLocked = 0; SyNrRows = 0; SyNrRowsLocked = 0; SyQuiet = 0; SyInitializing = 0; #ifdef SYS_IS_64_BIT SyStorMin = 128 * 1024L; SyStorMax = 2048*1024L; /* This is in kB! */ SyAllocPool = 4096L*1024*1024; /* Note this is in bytes! */ #else SyStorMin = 64 * 1024L; SyStorMax = 1024*1024L; /* This is in kB! */ #ifdef SYS_IS_CYGWIN32 SyAllocPool = 0; /* works better on cygwin */ #else SyAllocPool = 1536L*1024*1024; /* Note this is in bytes! */ #endif #endif SyStorOverrun = 0; SyStorKill = 0; SyUseModule = 1; SyWindow = 0; for (i = 0; i < 2; i++) { UInt j; for (j = 0; j < 7; j++) { SyGasmanNumbers[i][j] = 0; } } preAllocAmount = 4*1024*1024; InitSysFiles(); #ifdef HAVE_LIBREADLINE rl_initialize (); #endif SyInstallAnswerIntr(); #if defined(SYS_DEFAULT_PATHS) SySetGapRootPath( SYS_DEFAULT_PATHS ); #else SySetInitialGapRootPaths(); #endif /* save the original command line for export to GAP */ SyOriginalArgc = argc; SyOriginalArgv = argv; /* scan the command line for options that we have to process in the kernel */ /* we just scan the whole command line looking for the keys for the options we recognise */ /* anything else will presumably be dealt with in the library */ while ( argc > 1 ) { if (argv[1][0] == '-' ) { if ( strlen(argv[1]) != 2 && argv[1][1] != '-') { FPUTS_TO_STDERR("gap: sorry, options must not be grouped '"); FPUTS_TO_STDERR(argv[1]); FPUTS_TO_STDERR("'.\n"); goto usage; } for (i = 0; options[i].shortkey != argv[1][1] && (argv[1][1] != '-' || argv[1][2] == 0 || strcmp(options[i].longkey, argv[1] + 2)) && (options[i].shortkey != 0 || options[i].longkey[0] != 0); i++) ; if (argc < 2 + options[i].minargs) { Char buf[2]; FPUTS_TO_STDERR("gap: option "); FPUTS_TO_STDERR(argv[1]); FPUTS_TO_STDERR(" requires at least "); buf[0] = options[i].minargs + '0'; buf[1] = '\0'; FPUTS_TO_STDERR(buf); FPUTS_TO_STDERR(" arguments\n"); goto usage; } if (options[i].handler) { res = (*options[i].handler)(argv+2, options[i].otherArg); switch (res) { case -1: goto usage; /* case -2: goto fullusage; */ default: ; /* fall through and continue */ } } else res = options[i].minargs; /* recordOption(argv[1][1], res, argv+2); */ argv += 1 + res; argc -= 1 + res; } else { argv++; argc--; } } /* adjust SyUseReadline if no readline support available or for XGAP */ #if !defined(HAVE_LIBREADLINE) SyUseReadline = 0; #endif if (SyWindow) SyUseReadline = 0; /* now that the user has had a chance to give -x and -y, we determine the size of the screen ourselves */ getwindowsize(); /* fix max if it is lower than min */ if ( SyStorMax != 0 && SyStorMax < SyStorMin ) { SyStorMax = SyStorMin; } /* fix pool size if larger than SyStorKill */ if ( SyStorKill != 0 && SyAllocPool != 0 && SyAllocPool > 1024 * SyStorKill ) { SyAllocPool = SyStorKill * 1024; } /* fix pool size if it is given and lower than SyStorMax */ if ( SyAllocPool != 0 && SyAllocPool < SyStorMax * 1024) { SyAllocPool = SyStorMax * 1024; } /* when running in package mode set ctrl-d and line editing */ if ( SyWindow ) { /* SyLineEdit = 1; SyCTRD = 1; */ SyRedirectStderrToStdOut(); syWinPut( 0, "@p", "1." ); } if (SyAllocPool == 0) { /* premalloc stuff */ /* allocate in small chunks, and write something to them * (the GNU clib uses mmap for large chunks and give it back to the * system after free'ing; also it seems that memory is only really * allocated (pagewise) when it is first used) */ ptrlist = (Char **)malloc((1+preAllocAmount/1000)*sizeof(Char*)); for (i = 1; i*1000 < preAllocAmount; i++) { ptrlist[i-1] = (Char *)malloc( 1000 ); if (ptrlist[i-1] != NULL) ptrlist[i-1][900] = 13; } for (i = 1; (i+1)*1000 < preAllocAmount; i++) if (ptrlist[i-1] != NULL) free(ptrlist[i-1]); free(ptrlist); /* ptr = (Char *)malloc( preAllocAmount ); ptr1 = (Char *)malloc(4); if ( ptr != 0 ) free( ptr ); */ } /* should GAP load 'init/lib.g' on initialization */ if ( SyCompilePlease || SyRestoring ) { SyLoadSystemInitFile = 0; } /* the compiler will *not* read in the .gaprc file if ( gaprc && ! ( SyCompilePlease || SyRestoring ) ) { sySetGapRCFile(); } */ #ifdef HAVE_DOTGAPRC /* the users home directory */ if ( getenv("HOME") != 0 ) { strxcpy(DotGapPath, getenv("HOME"), sizeof(DotGapPath)); # if defined(SYS_IS_DARWIN) && SYS_IS_DARWIN /* On Darwin, add .gap to the sys roots, but leave */ /* DotGapPath at $HOME/Library/Preferences/GAP */ strxcat(DotGapPath, "/.gap;", sizeof(DotGapPath)); if (!IgnoreGapRC) { SySetGapRootPath(DotGapPath); } strxcpy(DotGapPath, getenv("HOME"), sizeof(DotGapPath)); strxcat(DotGapPath, "/Library/Preferences/GAP;", sizeof(DotGapPath)); # elif defined(__CYGWIN__) strxcat(DotGapPath, "/_gap;", sizeof(DotGapPath)); # else strxcat(DotGapPath, "/.gap;", sizeof(DotGapPath)); # endif if (!IgnoreGapRC) { SySetGapRootPath(DotGapPath); } DotGapPath[strlen(DotGapPath)-1] = '\0'; /* and in this case we can also expand paths which start with a tilde ~ */ Char userhome[GAP_PATH_MAX]; strxcpy(userhome, getenv("HOME"), sizeof(userhome)); const UInt userhomelen = strlen(userhome); for (i = 0; i < MAX_GAP_DIRS && SyGapRootPaths[i][0]; i++) { const UInt pathlen = strlen(SyGapRootPaths[i]); if (SyGapRootPaths[i][0] == '~' && userhomelen + pathlen < sizeof(SyGapRootPaths[i])) { SyMemmove(SyGapRootPaths[i] + userhomelen, /* don't copy the ~ but the trailing '\0' */ SyGapRootPaths[i] + 1, pathlen); memcpy(SyGapRootPaths[i], userhome, userhomelen); } } } #endif /* now we start */ return; /* print a usage message */ usage: FPUTS_TO_STDERR("usage: gap [OPTIONS] [FILES]\n"); FPUTS_TO_STDERR(" run the Groups, Algorithms and Programming system, Version "); FPUTS_TO_STDERR(SyBuildVersion); FPUTS_TO_STDERR("\n"); FPUTS_TO_STDERR(" use '-h' option to get help.\n"); FPUTS_TO_STDERR("\n"); SyExit( 1 ); }
FarString UnMimeHeader( LPCSTR header, int FarEncoding ) { char enc[ 256 ], tmp[ 256 ]; FarString res; CBase64Decoder b64; CQuotedPrintableSubjectDecoder qp; LPCSTR ps = header, pe = ps, pb, pm; while ( ( pb = strstr( ps, "=?" ) ) != NULL ) { if ( pb - ps > 0 ) res += ToOEMString( FarString( ps, pb - ps ), FarEncoding ); pb += 2; if ( ( pm = strchr( pb, '?' ) ) != NULL ) { int dc = FarSF::LUpper( *++pm ); if ( dc == 'B' || dc == 'Q' ) { if ( ( pe = strstr( pm + 2, "?=" ) ) != NULL ) { strxcpy( enc, pb, pm - pb ); strxcpy( tmp, pm + 2, pe - pm - 1 ); CMimeDecoder * d; if ( dc == 'B' ) d = &b64; else d = &qp; dc = d->decode( (PBYTE)tmp, strlen( tmp ) ); if ( dc > 0 ) tmp[ dc ] = '\0'; long d_enc = getCharacterTableNoDefault( enc ); if ( d_enc == FCT__INVALID ) d_enc = FarEncoding; res += ToOEMString( tmp, d_enc ); pe += 2; pb = pe; while ( *pe && isspace( (unsigned char)*pe ) ) pe ++; if ( pe[ 0 ] == '=' && pe[ 1 ] == '?' ) pb = pe; } else pb = pm; } } ps = pb; } if ( *ps != '\0' ) res += ToOEMString( ps, FarEncoding ); return res; }
status_t handle_request( RequestPB *pb ) { HTTPResponse response; pb->closeConnection = false; const char *sPtr; // General purpose string pointer // Temporary buffers int32 fieldSize = 1024; char fieldValue[1024]; char headBuffer[1024]; int32 contentLength = 0; // **** // Get PATH_INFO and SCRIPT_NAME from path; Setup absPath of CGI // **** char PATH_INFO[1024]; char SCRIPT_NAME[256]; // Get SCRIPT_NAME strxcpy( SCRIPT_NAME, pb->resourcePath->Path(), 255 ); strxcpy( PATH_INFO, pb->brURI->path+strlen( pb->resourcePath->Path()+1 ), 1023 ); // Make absolute CGI path from web-directory and requested path BPath absPath( pb->webDirectory->Path(), pb->resourcePath->Path()+1 ); // **** // Make sure CGI exists and Check Permission // **** if( pb->authenticate && !pb->realms->Authenticate( pb->request, &response, pb->brURI->path, absPath.Path(), S_IXOTH ) ) { pb->Logprintf( "%ld Status-Line: %s\n", pb->sn, response.GetStatusLine() ); return B_OK; } // **** // Setup meta-variables in new environment // **** char params[2048]; // Should we use the CGI script command line? // This should be done on a GET or HEAD where the URL query string // does not contain any unencoded '=' characters. if( *pb->brURI->query && ((pb->request->GetMethod() == METHOD_GET)||(pb->request->GetMethod() == METHOD_HEAD))&& !strchr( pb->brURI->query, '=' ) ) { uri_unescape_str( params, pb->brURI->query, 2048 ); } else uri_unescape_str( params, pb->brURI->params, 2048 ); // Environment to be used by the CGI Environment env( pb->environ ); // AUTH_TYPE if( pb->request->FindHeader( kHEAD_AUTHORIZATION, fieldValue, fieldSize ) ) { sPtr = fieldValue; sPtr = get_next_token( headBuffer, sPtr, fieldSize ); env.PutEnv( "AUTH_TYPE", headBuffer ); if( strcasecmp( headBuffer, "Basic" ) == 0 ) { // REMOTE_USER sPtr = get_next_token( headBuffer, sPtr, fieldSize ); decode_base64( headBuffer, headBuffer, fieldSize ); sPtr = get_next_token( fieldValue, headBuffer, fieldSize, ":" ); env.PutEnv( "REMOTE_USER", fieldValue ); } } // CONTENT_LENGTH if( pb->request->FindHeader( kHEAD_LENGTH, fieldValue, fieldSize ) ) env.PutEnv( "CONTENT_LENGTH", fieldValue ); // CONTENT_TYPE if( pb->request->FindHeader( kHEAD_TYPE, fieldValue, fieldSize ) ) env.PutEnv( "CONTENT_TYPE", fieldValue ); // GATEWAY_INTERFACE env.PutEnv( "GATEWAY_INTERFACE", "CGI/1.1" ); // HTTP_* for( int i=0; (sPtr = pb->request->HeaderAt( i )); i++ ) { sPtr = get_next_token( fieldValue, sPtr, fieldSize, ":" ); sprintf( headBuffer, "HTTP_%s", http_to_cgi_header( fieldValue ) ); sPtr = get_next_token( fieldValue, sPtr, fieldSize, ":" ); env.PutEnv( headBuffer, fieldValue ); } // PATH_INFO env.PutEnv( "PATH_INFO", PATH_INFO ); // PATH_TRANSLATED if( *PATH_INFO ) { BPath pathTrans( pb->webDirectory->Path(), PATH_INFO+1 ); if( pathTrans.Path() ) env.PutEnv( "PATH_TRANSLATED", pathTrans.Path() ); } // QUERY_STRING env.PutEnv( "QUERY_STRING", pb->brURI->query ); // REMOTE_ADDR env.PutEnv( "REMOTE_ADDR", pb->request->GetRemoteHost() ); // REMOTE_HOST // Ya, right... like were going to waste valuable time with a DNS lookup! env.PutEnv( "REMOTE_HOST", "" ); // REMOTE_IDENT // Ha! Perform an Ident lookup... I don't think so. // REQUEST_METHOD env.PutEnv( "REQUEST_METHOD", http_find_method( pb->request->GetMethod() ) ); // SCRIPT_NAME env.PutEnv( "SCRIPT_NAME", SCRIPT_NAME ); // SERVER_NAME env.PutEnv( "SERVER_NAME", pb->brURI->host ); // SERVER_PORT sprintf( fieldValue, "%u", pb->request->GetPort() ); env.PutEnv( "SERVER_PORT", fieldValue ); // SERVER_PROTOCOL env.PutEnv( "SERVER_PROTOCOL", pb->request->GetVersion() ); // SERVER_SOFTWARE env.PutEnv( "SERVER_SOFTWARE", "RobinHood" ); // PWD BPath PWD( absPath ); PWD.GetParent( &PWD ); env.PutEnv( "PWD", PWD.Path() ); // **** // Create pipes // **** pid_t pid; int ipipe[2], opipe[2]; if( pipe(ipipe) < 0 ) { response.SetHTMLMessage( 500, "Pipe creation failed!" ); pb->request->SendReply( &response ); return B_OK; } if( pipe(opipe) < 0 ) { close( ipipe[0] ); close( ipipe[1] ); response.SetHTMLMessage( 500, "Pipe creation failed!" ); pb->request->SendReply( &response ); return B_OK; } // **** // Setup args for execve() // **** // Setup command string; copy CGI path and append params char command[4096]; sPtr = strxcpy( command, absPath.Path(), 4095 ); // Disabled because of security risk /* if( *params && !strpbrk( params, ";&" ) ) { sPtr = strxcpy( (char *)sPtr, " ", command+4095-sPtr ); strxcpy( (char *)sPtr, params, command+4095-sPtr ); // Append params }*/ char *args[4]; args[0] = "/bin/sh"; args[1] = "-c"; args[2] = command; args[3] = NULL; pb->Logprintf( "%ld Exec: %s\n", pb->sn, command ); // **** // Start sub-process using fork() dup2() and exec() // **** pid = fork(); if( pid == (pid_t)0 ) // If we are the child process... { // Make this process the process group leader setpgid( 0, 0 ); fflush(stdout); // sync stdout... // Set pipes to stdin and stdout if( dup2( opipe[0], STDIN_FILENO ) < 0 ) exit( 0 ); if( dup2( ipipe[1], STDOUT_FILENO ) < 0 ) exit( 0 ); // Close unused ends of pipes close( opipe[1] ); close( ipipe[0] ); // Set Current Working Directory to that of script chdir( PWD.Path() ); // Execute CGI in this process by means of /bin/sh execve( args[0], args, env.GetEnvironment() ); exit( 0 ); // If for some reason execve() fails... } else if( pid < (pid_t)0 ) // Something Bad happened! { close( opipe[0] ); close( opipe[1] ); close( ipipe[0] ); close( ipipe[1] ); response.SetHTMLMessage( 500, "Fork failed!" ); pb->request->SendReply( &response ); return true; } // Close unused ends of pipes close( opipe[0] ); close( ipipe[1] ); // **** // Talk to CGI // **** bool persistant = true; // Defined to make code easier to read int inDes = ipipe[0]; // input file descripter int outDes = opipe[1]; // output file descripter // Make a BDataIO wrapper for the in and out pipes DesIO pipeIO( inDes, outDes ); // If the request contains a content body, feed it into stdin of the CGI script if( pb->request->GetContentLength() > 0 ) pb->request->SendBody( &pipeIO ); // Buffer the response body for better performance response.SetBodyBuffering( true ); // Read first line to detect use of Non-Parsed Header Output io_getline( &pipeIO, headBuffer, fieldSize ); // Strip the '\r' character if there is one int32 size; size = strlen( headBuffer )-1; if( headBuffer[size] == '\r' ) headBuffer[size] = 0; // Is NPH Output? if( strncmp( "HTTP/", headBuffer, 5 ) == 0 ) { DataIOPump ioPump; BufferedIO bufio( pb->request->GetReplyIO() ); bufio.DoAllocate(); io_printf( &bufio, "%s\r\n", headBuffer ); ioPump.StartPump( &pipeIO, &bufio, contentLength ); bufio.Flush(); persistant = false; } else // using Parsed Header Output { // Add Date header time_t now; struct tm *brokentime; now = time( NULL ); brTimeLock.Lock(); brokentime = gmtime( &now ); strftime (fieldValue, 256, kHTTP_DATE, brokentime); brTimeLock.Unlock(); response.AddHeader( kHEAD_DATE, fieldValue ); // Add line used to detect NPH as CGI header response.AddHeader( headBuffer ); // Receive the CGI headers response.ReceiveHeaders( &pipeIO ); // If Location header, don't expect any more headers if( (sPtr = response.FindHeader( "Location", fieldValue, fieldSize )) ) { response.SetStatusLine( 302 ); // 302 Moved Temporarily } else { if( (sPtr = response.FindHeader( "Status", fieldValue, fieldSize )) ) { response.RemoveHeader( (char *)sPtr ); // Don't forward to client response.SetStatusLine( fieldValue ); } else response.SetStatusLine( 200 ); } // Don't cache the response if( !response.FindHeader( "Cache-Control", fieldValue, fieldSize ) ) response.AddHeader( "Cache-Control: no-cache" ); if( !response.FindHeader( "Pragma", fieldValue, fieldSize ) ) response.AddHeader( "Pragma: no-cache" ); // Content-Length header? int32 contentLength = 0; if( (sPtr = response.FindHeader( kHEAD_LENGTH, fieldValue, fieldSize )) ) { contentLength = strtol( fieldValue, (char **)&headBuffer, 10 ); response.SetContentLength( contentLength ); } else // No content-length provided; close connection on return { response.AddHeader( "Connection: close" ); persistant = false; } pb->Logprintf( "%ld Status-Line: %s\n", pb->sn, response.GetStatusLine() ); if( pb->request->GetMethod() != METHOD_HEAD ) response.SetMessageBody( &pipeIO ); pb->request->SendReply( &response ); } // Close remaining ends of pipes close( ipipe[0] ); close( opipe[1] ); pb->closeConnection = !persistant; return B_OK; }