/* 
 * This file is automaticaly generated, Please dont edit this file! 
 */
#include <http.h> 


























































void http_createServer( http * this, void ( * requestCallback )( request * req,  text * response ) ) {

		this->requestCallback	= requestCallback;


		if( this->useSSL == 1 ) {

			http_initializeOpenSSL( this );

		}

		printf("after initializeOpenSSL\n\n");

	}

void http_initializeOpenSSL( http * this ) {

		
		
		
		

		
		SSL_load_error_strings();

		OpenSSL_add_ssl_algorithms();

		SSLeay_add_ssl_algorithms();

		return;

	}

int http_listen( http * this, int port ) {

		this->socket 		= socket( AF_INET, SOCK_STREAM, 0 );
	
		int iSetOption 		= 1;

		setsockopt( this->socket, SOL_SOCKET, SO_REUSEADDR, ( char * ) & iSetOption, sizeof( iSetOption ) );

		if ( this->socket == -1 ) {

		    perror("webserver (socket)");

		   exit( 0 );

		} else {

			printf("socket created successfully\n");

		}

		
		
		this->hostAddress->sin_family 			= AF_INET;

		this->hostAddress->sin_port 			= htons( port );

		this->hostAddress->sin_addr.s_addr 		= htonl( INADDR_ANY );


		
		if ( bind( this->socket, ( struct sockaddr * ) this->hostAddress, this->hostAddresslength ) != 0 ) {

			perror("webserver (bind)");

			exit( 0 );

		} else {

			printf("socket successfully bound to address\n");

		}

		
		if ( listen( this->socket, SOMAXCONN ) != 0 ) {

			perror("webserver (listen)");

			exit( 0 );

		} else {
		
			printf("server listening for connections\n");

		}



		for (;;) {

			http_acceptConnection( this  );

		}


		

		printf("exit");


		return 0;

	}

char * http_getExtension( http * this, char * path ) {

		array * parts		= char_split( path, ".");

		int count			= array_length( parts );

		return array_get( parts,  count - 1 );

	}

void http_logRequest( http * this, request	* requestInstance ) {

		printf("server address:		[%s:%u]\n", 	requestInstance->address, requestInstance->port );
	
		printf("mimeType:		%-30s \n", 			requestInstance->mimeType);

		printf("header:			%-30s \n",			requestInstance->extension );

		printf("method:			%-30s		 \n", 	requestInstance->method );

		printf("version:		%-30s		 \n\n", requestInstance->version );

	}

void http_acceptConnection( http * this ) {

		fileSystem * filesystem 	= this->filesystem;

		mimeTypes * mimetypes		= this->mimetypes;

		text	* response			= text_newPointer("");


		
		char buffer[ 4096 ];

		
		struct sockaddr_in client_addr;

		int client_addrlen 	= sizeof(client_addr);

		
		int socketConnection 		= accept( 	this->socket, 
										(struct sockaddr *)this->hostAddress,
		                  				( socklen_t * ) & this->hostAddresslength );














		SSL * ssl  = NULL;

		if( this->useSSL == 1 ) {

			const SSL_METHOD * method	= SSLv23_server_method();

			this->sslContext = SSL_CTX_new( method );

			if ( this->sslContext == NULL ) {

				printf("Error loading SSL_CTX_NEW '%s'\n\n", stderr);

			}

			SSL_CTX_set_options( this->sslContext, SSL_OP_SINGLE_DH_USE );

			int use_cert 	= SSL_CTX_use_certificate_file( this->sslContext, "/etc/letsencrypt/live/unifyjs.org/fullchain.pem" , SSL_FILETYPE_PEM );

			int use_prv 	= SSL_CTX_use_PrivateKey_file( this->sslContext, "/etc/letsencrypt/live/unifyjs.org/privkey.pem", SSL_FILETYPE_PEM );

			if( use_cert != 1 ) {

				printf( "error:	SSL_CTX_use_certificate_file\n\n" );

			}

			if( use_prv != 1 ) {

				printf( "error:	SSL_CTX_use_PrivateKey_file\n\n" );

			}

			if ( !SSL_CTX_check_private_key(this->sslContext) ) {

				printf("Private key does not match the certificate public key\n");

				
			}

			ssl = SSL_new( this->sslContext );

			SSL_set_fd( ssl, socketConnection );

			
			int ssl_err = SSL_accept( ssl ); 

			

			

			if( ssl_err == 0 ){

				printf("SSL_accept returned zero\n");

			}


			int n;

			if( ssl_err < 0 ) {

				int err;

				if( ( err = SSL_get_error(ssl,n ) ) == SSL_ERROR_WANT_READ) {

					printf("SSL_accept wants more data\n");

					return ;

				}

				exit(7);

			}























































			



		} else {
			printf("connection accepted\n\n");

			
			int sockn = getsockname(	socketConnection, 
										( struct sockaddr * ) &client_addr,
			                    		( socklen_t * ) &client_addrlen);


			if ( sockn == -1 ) {

				perror("webserver (getsockname)");

			}

		}

		int valread;

		if( this->useSSL == 1 ) { 

			valread = SSL_read( ssl, buffer, 4096 - 1 );

		} else {

			printf("read without ssl\n\n");

			int valread = read( socketConnection, buffer, 4096 -1 );
			
			if ( valread == -1 ) {

				perror("webserver (read)");

				

			}

		}


		if ( valread == -1 ) {

			perror("webserver (read)");


		}


		request	* requestInstance	= request_newPointer();


		sscanf( buffer, "%s %s %s", requestInstance->method, requestInstance->url, requestInstance->version );


		requestInstance->address		= inet_ntoa( client_addr.sin_addr );

		requestInstance->port			= ntohs( client_addr.sin_port );

		requestInstance->extension		= http_getExtension( this,  requestInstance->url );

		requestInstance->mimeType		= mimeTypes_getByExtension( mimetypes,  requestInstance->extension );

		this->requestCallback( requestInstance, response );




		

		int writeResponse;

		if( this->useSSL == 1 ) { 

			writeResponse = SSL_write( ssl, response->value, response->length );

		} else {

			
			int writeResponse = write( socketConnection, response->value, response->length );

			printf("close connection");

			if ( writeResponse == -1 ) {

				perror("webserver (write)");

				return;

			}
		}

		if ( writeResponse == -1 ) {

			perror("webserver (write)");

			return;

		} else {

			

		}


		

		

		

		

		close( socketConnection );

		

		

		
		
			

	}

void http_dump_buffer( http * this, void *buffer,  int buffer_size ) {
		int i;

		for(i = 0;i < buffer_size;++i){

			printf( "%c", (  (char *) buffer )[i]);

		}

	}




void abort(  ) {


}

http http_new() {

	http instance;

	instance.__classIndex = 13;

	instance.hostAddress =  malloc( sizeof( struct sockaddr_in ) );

	instance.hostAddresslength =  sizeof( struct sockaddr_in );

	instance.filesystem = fileSystem_newPointer();

	instance.mimetypes = mimeTypes_newPointer();

	instance.headers = headerManager_newPointer();

	instance.useSSL =  1;

	return instance;

}

http * http_newPointer() {

	struct http * pointer = malloc( sizeof ( struct http ) );

	pointer->__classIndex = 13;

	pointer->hostAddress =  malloc( sizeof( struct sockaddr_in ) );

	pointer->hostAddresslength =  sizeof( struct sockaddr_in );

	pointer->filesystem = fileSystem_newPointer();

	pointer->mimetypes = mimeTypes_newPointer();

	pointer->headers = headerManager_newPointer();

	pointer->useSSL =  1;

	return pointer;

}

