コード例 #1
0
ファイル: unit.c プロジェクト: howerj/liblisp
int main(int argc, char **argv)
{
	if (argc > 1)
		while (++argv, --argc) {
			if (!strcmp("-c", argv[0]))
				color_on = 1;
			else if (!strcmp("-h", argv[0]))
				printf("liblisp unit tests\n\tusage ./%s (-c)? (-h)?\n", argv[0]);
			else
				printf("unknown argument '%s'\n", argv[0]);
		}

	unit_test_start("liblisp");
	{
		print_note("util.c");

		test(is_number("0xfAb"));
		test(is_number("-01234567"));
		test(is_number("+1000000000000000000000000000003"));
		test(!is_number(""));
		test(!is_number("+"));
		test(!is_number("-"));

		test(unbalanced("(((", '(', ')') > 0);
		test(unbalanced("))",  '(', ')') < 0);
		test(unbalanced("",    '(', ')') == 0);
		test(unbalanced("\"(", '(', ')') == 0);
		test(unbalanced("( \"))))(()()()(()\\\"())\")",  '(', ')') == 0);
		test(unbalanced("(a (b) c (d (e (f) \")\" g)))", '(', ')') == 0);
		test(unbalanced("((a b) c", '(', ')')  > 0);

		test(!is_fnumber(""));
		test(!is_fnumber("1e"));
		test(!is_fnumber("-1e"));
		test(!is_fnumber("1-e"));
		test(is_fnumber("+0."));
		test(is_fnumber("123"));	/*this passes, see header */
		test(is_fnumber("1e-3"));
		test(is_fnumber("1.003e+34"));
		test(is_fnumber("1e34"));
		test(is_fnumber("93.04"));

		test(match("", ""));
		test(match("abc", "abc"));
		test(!match("abC", "abc"));
		test(match("aaa*", "aaaXX"));
		test(!match("aaa*", "XXaaaXX"));
		test(match(".bc", "abc"));
		test(match("a.c", "aXc"));
		test(!match("a\\.c", "aXc"));
		test(match("a\\.c", "a.c"));

		char *s = NULL;
		state(s = vstrcatsep(",", "a", "b", "c", "", "foo", "bar", NULL));
		test(!sstrcmp("a,b,c,,foo,bar", s));
		free(s);

		char *t = NULL, *s1 = "Hello,", *s2 = " World!";
		state(t = calloc(16, 1));
		state(strcpy(t, s1));
		test(((size_t) (lstrcatend(t, s2) - t)) == (strlen(s1) + strlen(s2)));
		free(t);

		/*test tr, or translate, functionality */
		size_t trinsz = 0;
		uint8_t trout[128] = { 0 }, *trin = (uint8_t *) "aaabbbcdaacccdeeefxxxa";
		tr_state_t *tr1;
		state(tr1 = tr_new());
		state(trinsz = strlen((char *)trin));
		test(tr_init(tr1, "", (uint8_t *) "abc", (uint8_t *) "def") == TR_OK);
		test(tr_block(tr1, trin, trout, trinsz) == trinsz);
		test(!strcmp((char *)trout, "dddeeefdddfffdeeefxxxd"));
		test(tr_init(tr1, "s", (uint8_t *) "abc", (uint8_t *) "def") == TR_OK);
		state(memset(trout, 0, 128));
		test(tr_block(tr1, trin, trout, trinsz) <= trinsz);
		test(!strcmp((char *)trout, "defddfdeeefxxxd"));
		state(tr_delete(tr1));

		/*know collisions for the djb2 hash algorithm */
		test(djb2("heliotropes", strlen("heliotropes")) ==
		     djb2("neurospora", strlen("neurospora")));
		test(djb2("depravement", strlen("depravement")) ==
		     djb2("serafins", strlen("serafins")));
		/*should not collide */
		test(djb2("heliotropes", strlen("heliotropes")) !=
		     djb2("serafins", strlen("serafins")));
	}

	{ /*io.c test */
		io_t *in, *out;
		print_note("io.c");

		/*string input */
		static const char hello[] = "Hello\n";
		/**@note io_sin currently duplicates "hello" internally*/
		state(in = io_sin(hello, strlen(hello)));
		test(io_is_in(in));
		test(io_getc(in) == 'H');
		test(io_getc(in) == 'e');
		test(io_getc(in) == 'l');
		test(io_getc(in) == 'l');
		test(io_getc(in) == 'o');
		test(io_getc(in) == '\n');
		test(io_getc(in) == EOF);
		test(io_getc(in) == EOF);
		test(!io_error(in));
		test(io_seek(in, 0, SEEK_SET) >= 0);
		test(io_getc(in) == 'H');
		test(io_seek(in, 3, SEEK_SET) >= 0);
		test(io_getc(in) == 'l');
		test(io_ungetc('x', in) == 'x');
		test(io_getc(in) == 'x');
		test(io_getc(in) == 'o');
		state(io_close(in));

		/*string output */
		char *s = NULL;
		static const char hello_world[] = "Hello,\n\tWorld!\n";
		/**@note io_sin currently duplicates hello_world internally*/
		state(in = io_sin(hello_world, strlen(hello_world))); 
		test(!strcmp(s = io_getline(in), "Hello,"));
		s = (free(s), NULL);
		test(!strcmp(s = io_getline(in), "\tWorld!"));
		s = (free(s), NULL);
		test(!io_getline(in));
		test(io_seek(in, 0, SEEK_SET) >= 0);
		test(!strcmp(s = io_getdelim(in, EOF), "Hello,\n\tWorld!\n"));
		s = (free(s), NULL);
		state(io_close(in));

		state(out = io_sout(1));
		test(io_puts("Hello, World", out) != EOF);
		test(!strcmp("Hello, World", io_get_string(out)));
		test(io_putc('\n', out) != EOF);
		test(!strcmp("Hello, World\n", io_get_string(out)));
		test(io_seek(out, -6, SEEK_CUR) >= 0);
		test(io_puts("Mars\n", out) != EOF);
		test(!strcmp("Hello, Mars\n\n", io_get_string(out)));
		free(io_get_string(out));
		state(io_close(out));

		static const char block_in[16] = {1, 3, 4, 6};
		static char block_out[16] = {0};
		state((in = io_sin(block_in, 16)));
		test(io_getc(in) == 1);
		test(io_read(block_out, 15, in) == 15);
		test(!memcmp(block_out, block_in+1, 15));

		state(io_close(in));
	}

	{ /* hash.c hash table tests */
		hash_table_t *h = NULL;
		print_note("hash.c");
		state(h = hash_create(1));
		return_if(!h);
		test(!hash_insert(h, "key1", "val1"));
		test(!hash_insert(h, "key2", "val2"));
		/* assuming the hash algorithm is djb2, then
		 *  "heliotropes"  collides with "neurospora"
		 *  "depravement"  collides with "serafins"
		 *  "playwright"   collides with "snush" (for djb2a)
		 * See:
		 * <https://programmers.stackexchange.com/questions/49550/which-hashing-algorithm-is-best-for-uniqueness-and-speed> */
		test(!hash_insert(h, "heliotropes", "val3"));
		test(!hash_insert(h, "neurospora", "val4"));
		test(!hash_insert(h, "depravement", "val5"));
		test(!hash_insert(h, "serafins", "val6"));
		test(!hash_insert(h, "playwright", "val7"));
		test(!hash_insert(h, "snush", "val8"));
		test(!hash_insert(h, "", "val9"));
		test(!hash_insert(h, "nil", ""));
		test(!hash_insert(h, "a", "x"));
		test(!hash_insert(h, "a", "y"));
		test(!hash_insert(h, "a", "z"));
		test(!sstrcmp("val1", hash_lookup(h, "key1")));
		test(!sstrcmp("val2", hash_lookup(h, "key2")));
		test(!sstrcmp("val3", hash_lookup(h, "heliotropes")));
		test(!sstrcmp("val4", hash_lookup(h, "neurospora")));
		test(!sstrcmp("val5", hash_lookup(h, "depravement")));
		test(!sstrcmp("val6", hash_lookup(h, "serafins")));
		test(!sstrcmp("val7", hash_lookup(h, "playwright")));
		test(!sstrcmp("val8", hash_lookup(h, "snush")));
		test(!sstrcmp("val9", hash_lookup(h, "")));
		test(!sstrcmp("", hash_lookup(h, "nil")));
		test(!sstrcmp("z", hash_lookup(h, "a")));
		test(hash_get_load_factor(h) <= 0.75f);

		state(hash_destroy(h));
	}

	{			/* lisp.c (and the lisp interpreter in general) */
		lisp_t *l;

		print_note("lisp.c");
		/*while unit testing eschews state being held across tests it is makes
		 *little sense in this case*/
		state(l = lisp_init());
		state(io_close(lisp_get_logging(l)));
		test(!lisp_set_logging(l, io_nout()));
		return_if(!l);
		test(!lisp_eval_string(l, ""));
		test(is_int(lisp_eval_string(l, "2")));
		test(get_int(lisp_eval_string(l, "(+ 2 2)")) == 4);
		test(get_int(lisp_eval_string(l, "(* 3 2)")) == 6);

		lisp_cell_t *x = NULL, *y = NULL, *z = NULL;
		char *t = NULL;
		state(x = lisp_intern(l, lstrdup_or_abort("foo")));
		state(y = lisp_intern(l, t = lstrdup_or_abort("foo")));	/*this one needs freeing! */
		state(z = lisp_intern(l, lstrdup_or_abort("bar")));
		test(x == y && x != NULL);
		test(x != z);
		free(t);	/*free the non-interned string */

		test(is_proc(lisp_eval_string(l, "(define square (lambda (x) (* x x)))")));
		test(get_int(lisp_eval_string(l, "(square 4)")) == 16);

		test(!is_list(cons(l, gsym_tee(), gsym_tee())));
		test(is_list(cons(l, gsym_tee(), gsym_nil())));
		test(!is_list(cons(l, gsym_nil(), cons(l, gsym_tee(), gsym_tee()))));
		test(is_list(mk_list(l, gsym_tee(), gsym_nil(), gsym_tee(), NULL)));

		test(gsym_error() == lisp_eval_string(l, "(> 'a 1)"));
		test(is_sym(x));
		test(is_asciiz(x));
		test(!is_str(x));
		test(gsym_error() == lisp_eval_string(l, "(eval (cons quote 0))"));

		char *serial = NULL;
		test(!strcmp((serial = lisp_serialize(l, cons(l, gsym_tee(), gsym_error()))), "(t . error)"));
		state(free(serial));

		state(lisp_destroy(l));
	}
	return unit_test_end("liblisp");	/*should be zero! */
}
コード例 #2
0
ファイル: RHCGI.cpp プロジェクト: HaikuArchives/RobinHood
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;
}