public Resource handleCGIOutput( HTTPHeaders headers,
				     File file,
				     URI requestURI,
				     PostDataWrapper postData,
					      
				     ProcessableResource cgiOutput )
	throws IOException {


	// The processable resource stores the system-process's output inside an internal buffer.
	// Now we can read the PHP's generated header data using an InterruptableResource.
	InterruptableResource ir = new InterruptableResource( this.getHTTPHandler(),
							      this.getLogger(),
							      cgiOutput,
							      true    // useFairLocks (this will be the returned instance)
							      );
	

	this.getLogger().log( Level.INFO,
			      getClass().getName() + ".handleCGIOutput(...)",
			      "CGI output received. Reading generated HTTP headers from InterruptableResource ..." );

	// Note that the InterruptableResource allows to simulate the inputstream to be closed,
	// which is nothing more than a byte position reset.
	ir.open( true ); // open in read-only mode


	// Warning: even if the process was executed without any exceptions the system process may have failed!
	// -> check the return code
	if( cgiOutput.getExitValue() == 0 ) {
	    
	    // ???
	    // Store exit code in the resource's meta data?

	} else {

	    /*
	    if( cgiOutput.getExitValue() != 0 ) {
	    */
	    
	    this.getLogger().log( Level.WARNING,
				  getClass().getName() + ".handleCGIOutput(...)",
				  "The execution of the processable resource using the CGI file '" + file.getPath() + "' failed (exit code " + cgiOutput.getExitValue() + "). Continue though." );
	    
	}
	    


	// Continue ...
	BytePositionInputStream in = ir.getInputStream();
	HTTPHeaders phpHeaders = HTTPHeaders.read( in );


	if( phpHeaders.size() == 0 ) {

	    this.getLogger().log( Level.INFO,
				  getClass().getName() + ".handleCGIOutput(...)",
				  "The InterruptableResource has no HTTP headers." );
	}



	try {

	    // Store the generated HTTP headers into the resource's MetaData object.
	    for( int i = 0; i < phpHeaders.size(); i++ ) {


		// PHP creates a special 'Status' line indictating the HTTP respones status.
		// This status has the format "<status_code> <reason_phrase>" (hopefully) and must be converted into the 
		// HTTP-conform header line "HTTP/1.x <status_code> <reason_phrase>".
		HTTPHeaderLine headerLine = phpHeaders.get(i);
		if( headerLine.getKey() != null && headerLine.getKey().equals("Status") ) {

		    // Convert the 'Status' line into the 'HTTP/1.1 <status> <reason_phrase>'
		    // Note: This might throw a HeaderFormatException!
		    HTTPHeaderLine newResponseLine = new HTTPHeaderLine( "HTTP/" + headers.getRequestVersion() + " " + headerLine.getValue(), 
									 null 
									 );
		    this.getLogger().log( Level.INFO,
					  getClass().getName() + ".handleCGIOutput(...)",
					  "Converting PHP-generated HTTPHeaders["+i+"] to a new status line and adding to the resource's meta data: " + phpHeaders.get(i) + ", status line replacement: " + newResponseLine );

		    ir.getMetaData().getOverrideHeaders().replaceResponseLine( newResponseLine );

		} else {

		    // A 'normal' key-value-tuple.
		    this.getLogger().log( Level.INFO,
					  getClass().getName() + ".handleCGIOutput(...)",
					  "Adding PHP-generated HTTPHeaders["+i+"] to the resource's meta data: " + phpHeaders.get(i) );

		    ir.getMetaData().getOverrideHeaders().add( headerLine );


		    // Override resource's MIME type?
		    if( headerLine.getKey() != null && headerLine.getKey().equals(HTTPHeaders.NAME_CONTENT_TYPE) ) {

			ir.getMetaData().setMIMEType( new MIMEType(headerLine.getValue()) );

		    }
		    
		}
	    }

	} catch( HeaderFormatException e ) {

	    ir.close();
	    throw new IOException( "Cannot replace response status line due to HeaderFormatException: " + e.getMessage(),
				   e );
		

	} 

	
	// Now reset the input stream!
	// This will tell the next instance accessing the resource that it's still at the beginning of the 
	// input stream (and the second 'open()' call will not fail).
	ir.resetBytePosition();
	
	    
	return ir;
    }