/*
 * This code is part of Screws project.
 * Copylefted by pancake@phreaker.net at 2003
 */

#include "Request.h"
#include "Modules.h"
#include "Error.h"
#include "Logs.h"
#include "Env.h"

void
doExec(s,n,head)
	int s,n; /* socket and thread? */
	char **head; /* heads array */
{
	char *cwd;
	char file[256];
	char buf[1024];
	char *str[5]=
	{
		"Unknown error",
		"File not found",
		"It's a directory",
		"Does not have the +x bit",
		"Invalid interpreter"
	}; 
	enum {  REASON_UNKNOWN, 
			REASON_NOTFOUND, 
			REASON_ISDIR, 
			REASON_NOX, 
			REASON_INVINT };
	char *reason;
	struct stat st;
	reason=str[REASON_UNKNOWN];

	/* execution */
#if DLOPEN
	if (! execModule(MOD_EXEC) )
	{
#endif
		execve(Svr.Lis[n].S[_EXEC],head,environ);

		/* client log */
		cwd=getcwd(0,0);
		if (cwd)
		{
			snprintf(file,255,"%s/%s",cwd,Svr.Lis[n].S[_EXEC]);
			free(cwd);
		}
		file[254]=0;
		/* check reason */
		if ( stat(file,&st) < 0 )
				reason=str[REASON_NOTFOUND];
		else
		if ( access(Svr.Lis[n].S[_EXEC],X_OK) )
				reason=str[REASON_NOX];
		else
		if ( S_ISDIR(st.st_mode) )
				reason=str[REASON_ISDIR];
		else 
		{
			FILE *fd;
	
			fd=fopen(file,"r");
			fread(buf,2,1,fd);
			if (!memcmp(buf,"#!",2))
			{
				reason=str[REASON_INVINT];
			}
			fclose(fd);
		}
		/* http body */
		snprintf(buf,1024,
			"<html>\n"
			"<head>\n"
			"  <title> Execve Error </title>\n"
			"</head>\n"
			"<body>\n"
			"  <b>An error ocurred while executing '%s'.</b><br>\n"
			"  Reason: %s<br>\n"
			"  Perror: %s<br>\n"
			"</body>\n"
			"</html>\n",file,reason,strerror(errno));
		buf[1023]=0;

		if (HTTP[0]=='1') 
			printf(
				"HTTP/1.1 400 Internal Server Error\r\n"
				"Server: Screws %s\r\n"
				"Connection: close\r\n"
				"Content-Length: %d\r\n"
				"Content-Type: text/html\r\n\r\n",VERSION,strlen(buf));

		printf(buf);

		/* server log */
		fprintf(stderr,"Problem running %s\n",Svr.Lis[n].S[_EXEC]);
		perror("EXECVE FAILED");

		fflush(stdout);
#if DLOPEN
		}
#endif

	exit(0);
}

printExecveFailed(n)
	int n;
{
	char buf[200];
	getcwd(buf,200);
	buf[199]=0;
	if (HTTP[0]=='1')
	{
		printf( "HTTP/1.1 400 File Not Found\r\n"
			"Server: Screws %s\r\n\r\n",VERSION);
	}
	printf("ERROR ON EXEC %s/%s\n",buf,Svr.Lis[n].S[_EXEC]);
}

/* Read from input socket and get basic vars */
/* XXX Pass "n" instead all this argumenets */
int global_socket; // XXX ugly patch for MyReq. (Must be passed as argument)

char *
readRequest(s,heads)
	int  s;       /* socket  */ 
	int* heads;   /* Heads limit */ 
{
	char *b=0,*b2;
	loop_t i=0,j=0;
	int lim=4096, ret=0,nheads=0;
	bool http=false;

	#if DLOPEN
	global_socket=s;
	if ( execModule(MOD_REQ) )
	{
/*
		ARGS=strdup("");
		HTTP=strdup("1.1");
		METHOD=strdup("GET");
		FILER=strdup("/");
*/
		return 0;
	}
	#endif

	b=(char *)calloc(1,lim+1);
	if (!b)   return (char *)ERROR_MALLOC;

	i=0;
	/* ReadRequest main-loop */
	while(1)
	{
		ret=screws_socket_recv(s,b+i,1);
#if 0
#if USESSL
		if (ssl)
			ret = SSL_read(ssl, b+i, 1);
		else
#endif
		ret=recv(s,b+i,1,0);
#endif
		if (!ret)
			return (char *)ERROR_TIMEOUT;

		if (ret==-1)
		{
			if (errno==EAGAIN) /* BSD tip */
			{
				usleep(Svr.usleep);
				continue;
			}
			return (char *)ERROR_TIMEOUT;
		}

		if (b[i]=='\n') /* Terrible loop :S (aka unreadable) */
		{
			int c=0,e=0,ask=0;

			if (!(*heads)) 
			{
					printf("HTTP headers limit reached!\n");
					break;
			}

			if (http) /* HTTP EOF Detector :) */
			{	
				if (!nheads&&b[i-2]=='\n') break; // no headers case
				//i++;
				if (b[i-2]=='\r') break;
			}

			if (http) { nheads++; (*heads)--; continue; }
			i+=ret; j=i; b[i]=0;

			/* METHOD */
			while(b[c]&&b[c]!=' '&&b[c]!='\r'&&b[c]!='\n') c++;
			if (METHOD) free(METHOD);
			b[c]=0; METHOD=strdup(b); b[c]=' '; e=++c;

			/* FILE */
			while(b[e]&&b[e]!=' '&&b[e]!='\r') 
			  {
			   if (!ask&&b[e]=='?')
				ask=e; 
			   e++; 
			  } 

			b[e]=0;
			if (ask) b[ask]=0;
			if (FILER) free(FILER);
			FILER=strdup(b+c); if (ask) b[ask]='?';

			/* ARGS */
			if (!Svr.noargs)
			{
			  if (ARGS) free(ARGS);
			  if (ask)  ARGS=strdup(b+ask+1);
			  else 	   ARGS=strdup("");
			}
			b[e]=' ';

			if (strstr(b,"HTTP/1.0")) strcpy(HTTP,"1.0"); else
			if (strstr(b,"HTTP/1.1")) strcpy(HTTP,"1.1");
			else { strcpy(HTTP,"0.9"); break; } // go out and no read headers.
			http=true; b[i]='\r';
		} 
		else i+=ret;		/* "infinite" input */

		if (i+1==lim) 
		{
			lim+=1024;
			b=(char *)realloc(b,lim+1);
		}
		/* Check for integer overflow */
		if (i>=INT_MAX) return (char *)ERROR_INTOVR;

		/* Check for limit */
		if ((Svr.httplen>0) && (i>=Svr.httplen)) 
			return (char *)ERROR_HTTPLEN;
	}

	/* Eat first line */
	b[i-1]=0; strcpy(b,b+j);
	
	if (Svr.v>=V_SHOW)
	{
	  printf("Method: %s\n",METHOD);
#if DEBUG
	  printf("File : %s [%d:%d:%d:%d]\n",FILER,
			(unsigned char)METHOD[0],
			(unsigned char)METHOD[1],
			(unsigned char)METHOD[2],
			(unsigned char)METHOD[3]
			);
#endif
	}
	return b;
}

