<|start_filename|>src/common-utils/common_utils.h<|end_filename|>
/*
 *  Created by <NAME> on 01/04/14.
 *
 */
#ifndef __TCREWRITE_COMMON_UTILS__H_
#define __TCREWRITE_COMMON_UTILS__H_
#ifdef __cplusplus
	extern "C" {
#endif
#include <apr_general.h>
#include <apr_pools.h>
#include <apr_tables.h>
#include <apr_hash.h>
#include <apr_strings.h>
#include <sys/types.h>
#include <time.h>
#include <string.h>

#define SAFESTR(str) (str!=NULL?str:"NULL")
#define SAFESTRBLANK(str) (str!=NULL?str:"")
#define SAFESTRELSE(str,elstr) (str!=NULL?str:elstr)
#define SAFESTRLEN(str) (str!=NULL?strlen(str):0)
#define BOOLTOSTR(bol) (bol!=1?"FALSE":"TRUE")
#define STRTOBOOL(str) ((str!=NULL&&(strcmp(str,"true")==0||strcmp(str,"TRUE")==0||strcmp(str,"on")==0))?1:0)
#define SAFEDUP(p,str) (str==NULL?NULL:apr_pstrdup(p,str))

// Use this macro instead of cu_getElement
#ifndef APR_ARRAY_IDX
	#define APR_ARRAY_IDX(ary,i,type) (((type *)(ary)->elts)[i])
#endif

// Use this macro instead of apr_array_push
#ifndef APR_ARRAY_PUSH
	#define APR_ARRAY_PUSH(ary,type) (*((type *)apr_array_push(ary)))
#endif

// Use this macro instead of cu_getElementRef
#ifndef APR_ARRAY_REF_IDX
	#define APR_ARRAY_REF_IDX(ary,i,type) (((type *)(ary)->elts)+i)
#endif

// Use this macro instead of cu_getElementCount
#ifndef APR_ARRAY_NUM_ELTS
	#define APR_ARRAY_NUM_ELTS(ary) ( (ary!=NULL) ? (ary)->nelts : 0 )
#endif

int cu_getElementCount(apr_array_header_t* data);

char* cu_getElement(apr_array_header_t* data, int element);

void** cu_getElementRef(apr_array_header_t* data, int element);

char* cu_getNodeDetails(apr_pool_t* p,unsigned int defaultHttpPort);
char* cu_templateString(apr_pool_t* p, char* src, apr_hash_t* vals);

time_t cu_dateStringToSeconds(const char* dateString);
char* cu_nonHtmlToHtmlChar(apr_pool_t*p, char*src);
char* cu_getCurrentDateByFormat2(apr_pool_t* p, const char* format);

char* cu_getFormattedUrl(apr_pool_t *p, char* cur, char* namespaceid);
char* cu_getTrimmedStr(apr_pool_t* p, char* str);
apr_array_header_t* cu_parseStringArrayFromCsv(apr_pool_t* p, int arraySz, const char* delim, char* src);
char* cu_serializeCsvFromStringArray(apr_pool_t* p, apr_array_header_t* arr);
apr_table_t* cu_parseNvpTableFromCsv(apr_pool_t* p,const char* itemDelim,const char* nvpDelim, char* src);

//
// RSA implementation
//
// by key
char* comu_rsa256Sign(apr_pool_t*p, unsigned char * data,int dataLen,unsigned char * privateKey, char** error);
int comu_rsa256Verify(apr_pool_t*p, unsigned char * data,int dataLen, unsigned char * publicKey, char* encodedSign, char** error);
int comu_rsaVerifyByModulus(apr_pool_t*p, const char* algorithm, unsigned char * data,int dataLen, const char* modulus, const char* exponent, char* encodedSign, char** error);
char* comu_rsaEncrypt(apr_pool_t*p, unsigned char * data,int data_len,unsigned char * publicKey, char** error);
char* comu_rsaDecrypt(apr_pool_t*p, unsigned char * encrypted, unsigned char * privateKey, char** error);

// by keyFile
char* comu_rsa256SignFromFile(apr_pool_t*p, unsigned char * data,int dataLen,unsigned char * privateKeyFile, char** error);
int comu_rsa256VerifyFromFile(apr_pool_t*p, unsigned char * data,int dataLen, unsigned char * publicKeyFile, char* encodedSign, char** error);
char* comu_rsaEncryptFromFile(apr_pool_t*p, unsigned char * data,int data_len,unsigned char * publicKeyFile, char** error);
char* comu_rsaDecryptFromFile(apr_pool_t*p, unsigned char * encrypted, unsigned char * privateKeyFile, char** error);
char* comu_rsaPrintModulusFromFile(apr_pool_t*p, unsigned char * publicKeyFile, int isPublic);

// AES encryption/decryption
typedef struct oidc_cipher_cfg{
	apr_pool_t*p;
	char* crypto_passphrase;
	void* encrypt_ctx;
	void* decrypt_ctx;
}oidc_cipher_cfg;
apr_byte_t comu_aesCryptoInit(apr_pool_t*p, oidc_cipher_cfg *cfg,
		char** error);
unsigned char *comu_aesEncrypt(apr_pool_t*p, oidc_cipher_cfg *cfg,
		unsigned char *plaintext, int *len, char** error);
unsigned char *comu_aesDecrypt(apr_pool_t*p, oidc_cipher_cfg *cfg,
		unsigned char *ciphertext, int *len, char** error);
apr_byte_t comu_aesCryptoDestroy(oidc_cipher_cfg *cfg);
int cu_encryptAndBase64urlEncode(apr_pool_t*p, oidc_cipher_cfg*cfg, char **dst,
		const char *src, char** error);
int cu_base64urlDecodeAndDecrypt(apr_pool_t*p, oidc_cipher_cfg*cfg, char **dst,
		const char *src, char** error);

// uuid function
char* cu_generateGuid(apr_pool_t* p);

// base64 functions
int cu_base64urlEncode(apr_pool_t*p, char **dst, const char *src,
		int src_len, int remove_padding);
int cu_base64urlDecode(apr_pool_t*p, char **dst, const char *src);

#ifdef __cplusplus
	}
#endif
#endif//__TCREWRITE_COMMON_UTILS__H_


<|start_filename|>src/xml-core/xml_core.c<|end_filename|>
/*
 *  Created by <NAME> on 01/04/14.
 *
 */
#include <xml_core.h>
#include <expat.h>
#include <stdio.h>
#include <string.h>
#include <token_utils.h>
#include "apr_strings.h"

#define BUFFSIZE	8192
#ifdef XML_LARGE_SIZE
#if defined(XML_USE_MSC_EXTENSIONS) && _MSC_VER < 1400
#define XML_FMT_INT_MOD "I64"
#else
#define XML_FMT_INT_MOD "ll"
#endif
#else
#define XML_FMT_INT_MOD "l"
#endif

#define CONST_FAILURE_FILE_OPEN	-1
#define CONST_FAILURE_CREATE	-2
#define CONST_FAILURE_READ		-4
#define CONST_FAILURE_XMLERROR	-8
#define CONST_SUCCESS			1

	DLinkedList* xc_getLinkedList(pool *p){
		DLinkedList* dlist;
		dlist=apr_palloc(p,sizeof(DLinkedList));
		dlist->head=NULL;
		dlist->tail=NULL;
		dlist->elts=0;
		return dlist;
	}
	
	int xc_AddToTail(pool* p, DLinkedList* ll, void* elt){
		llnode* node;
		node=apr_palloc(p,sizeof(llnode));
		node->data=elt;
		node->prev=NULL;
		node->next=NULL;
		if(ll->head==NULL||ll->tail==NULL){					
			ll->head=ll->tail=node;
		}else{
			ll->tail->next=node;
			node->prev=ll->tail;
			ll->tail=ll->tail->next;
		}
		ll->elts++;
	return ll->elts;
	}

	void* xc_peekTail(pool* p, DLinkedList* ll){
		if(ll->tail!=NULL){
			return ll->tail->data;
		}
		return NULL;
	}

	void* xc_RemoveFromTail(pool* p, DLinkedList* ll){
		void* elt=NULL;
		if(ll->head==ll->tail){
			elt=ll->head->data;
			ll->head=ll->tail=NULL;
		}else if(ll->head!=NULL&&ll->tail!=NULL){
			elt=ll->tail->data;
			ll->tail=ll->tail->prev;
			ll->tail->next=NULL;
		}
		return elt;
	}

	static void xc_printxrec_list(pool* p, DLinkedList* ll){
		llnode* node;
		x_rec* xrec;

		node=ll->head;
		while(node!=NULL){
			xrec=(x_rec*)(node->data);
			printf("xrec: %s\n",xrec->path);
			node=node->next;
		}
	}

	static void xc_printNodeInfo_list(pool* p, DLinkedList* ll){
		llnode* node;
		node_info *ninfo;

		node=ll->head;
		while(node!=NULL){
			ninfo=(node_info*)(node->data);
			printf("node: %s\n",ninfo->name);
			node=node->next;
		}
	}
	
	static DLinkedList* xc_parseXpathNodes(pool* p, char* str){
		node_info *ninfo;
		DLinkedList* ll;
		Tokener* tk;
		char* tok;
		
		ll=xc_getLinkedList(p);		
		tk=tu_getTokenizer(p,str,"/");

		//printf("str:%s\n",str);	
		
		while((tok=tu_next_token(tk))!=NULL){		
			ninfo=apr_palloc(p,sizeof(node_info));
			ninfo->name=tok;
			//printf("tok:%s\n",ninfo->name);	
			xc_AddToTail(p,ll,ninfo);
		}
		return ll;	
	}

	XmlCore* xc_getXmlCore(pool *p){
		XmlCore *c=apr_palloc(p,sizeof(XmlCore));
		c->p=p;
		c->xpath_nodes=xc_getLinkedList(p);
		c->xpath_handlers=xc_getLinkedList(p);
		return c;
	}
		

	int xc_addXPathHandler(XmlCore* xCore, char* path, int options, const xfunc sfunction, const bfunc bfunction, const efunc efunction, void* udata){
		int ret;
		x_rec* xrec;
		xrec=apr_palloc(xCore->p,sizeof(x_rec));
		//printf("Add Handler:%s\n",path);
		xrec->path=apr_pstrdup(xCore->p,path);
		xrec->userdata=udata;
		xrec->start_function=sfunction;
		xrec->body_function=bfunction;
		xrec->end_function=efunction;
		xrec->xpath_nodes=xc_parseXpathNodes(xCore->p,path);
		xrec->body=NULL;
		

		ret=xc_AddToTail(xCore->p,xCore->xpath_handlers,xrec);
		//xc_printxrec_list(xCore->p,xCore->xpath_handlers);
		return ret;
	}
	
	static int xc_matchNodeDLists(DLinkedList* l1, DLinkedList* l2){
		llnode *node1, *node2;
		node_info* ninfo1, *ninfo2;
		
		node1=l1->head;
		node2=l2->head;
			while(node1!=NULL&&node2!=NULL){
				ninfo1=(node_info*)node1->data;
				ninfo2=(node_info*)node2->data;
				//printf("1:%s, 2:%s\r\n",ninfo1->name,ninfo2->name);
				if(strcmp(ninfo1->name,"*")!=0&&strcmp(ninfo2->name,ninfo1->name)!=0){  //allows for wildcard all
					//printf("no match: %s,%s\n",ninfo2->name,ninfo1->name);
					return 0;
				}
				
				node1=node1->next;
				node2=node2->next;
				if((node1==NULL && node2==NULL)){
					//printf("MATC\r\n");
					return 1;
				}
			}
			//printf("no match3: %s,%s\n",ninfo2->name,ninfo1->name);
		
		return 0;
	}

	static void XMLCALL elementStart(void *data, const char *el, const char **attr){
		XmlCore* xCore=(XmlCore*)data;
		node_info* ninfo;

		//start handler data
		llnode* node;
		x_rec* xrec;

		//begin process element
		ninfo=(node_info*)apr_palloc(xCore->p,sizeof(node_info));
		ninfo->name=apr_pstrdup(xCore->p,el);
		//printf("add node:%s\n",el);
		xc_AddToTail(xCore->p,xCore->xpath_nodes,ninfo);
		//xc_printNodeInfo_list(xCore->p,xCore->xpath_nodes);

		//fire start handlers
		node=xCore->xpath_handlers->head;
		while(node!=NULL){
			xrec=(x_rec*)(node->data);
			//xc_printNodeInfo_list(xCore->p,xrec->xpath_nodes);
			if(xc_matchNodeDLists(xrec->xpath_nodes,xCore->xpath_nodes)){
				//printf("node match!\n");
				if(xrec->start_function!=NULL){
					(*xrec->start_function)(xCore->p,(char*)el,0,attr,xrec->userdata);
				}
			}
			node=node->next;
		}
		
	}
	static void XMLCALL elementEnd(void *data, const char *el){
		XmlCore* xCore=(XmlCore*)data;
		//start handler data
		llnode* node;
		x_rec* xrec;
		node_info* ninfo;
		
		//printf("END ELEMENT BEGIN\r\n");
		// fire end element handlers	
		node=xCore->xpath_handlers->head;
		while(node!=NULL){
			xrec=(x_rec*)(node->data);		
			//printf("ELEMENT END\r\n");
			if(xc_matchNodeDLists(xrec->xpath_nodes,xCore->xpath_nodes)){
				//printf("endnode match!\n");
				//fire end body handler
				if(xrec->body_function!=NULL){
					(*xrec->body_function)(xCore->p,(char*)el,0,xrec->body,xrec->userdata);
				}
				
				//fire end element handler
				if(xrec->end_function!=NULL){
					(*xrec->end_function)(xCore->p,(char*)el,0,xrec->userdata);
				}
				xrec->body=NULL;
			}
			node=node->next;
		}
		
		//clean up nodes
		ninfo=xc_RemoveFromTail(xCore->p,xCore->xpath_nodes);
		//printf("rem node:%s\n",ninfo->name);
		//xc_printNodeInfo_list(xCore->p,xCore->xpath_nodes);
	}
	static void XMLCALL cdataHandler(void *data, const XML_Char *s, int len){
		XmlCore* xCore=(XmlCore*)data;
		llnode* node;
		x_rec* xrec;
		node_info* ninfo;
		char* str=NULL;

				
		node=xCore->xpath_handlers->head;
		while(node!=NULL){
			xrec=(x_rec*)(node->data);
			
			if(xc_matchNodeDLists(xrec->xpath_nodes,xCore->xpath_nodes)){
				//printf("cdata!! match:!\n");
				if(str==NULL){
					str=apr_palloc(xCore->p,(len+1)*sizeof(char));
					memset(str,'\0',len+1);
					strncpy(str,s,len);
				}				
				
				if(xrec->body==NULL){					
					xrec->body=str;
				}else{
					xrec->body=apr_pstrcat(xCore->p,xrec->body,str,NULL);
				}
				//printf("val: [%s]\n",xrec->body);
				
			}
			node=node->next;
		}
		
		
		//printf("len: %d: %s\n",len,s);
	}
	static void XMLCALL cdataSectionHandlerStart(void *userData){
		//printf("!!!!!!!!!!!!!!!: \n");
	}
	static void XMLCALL cdataSectionHandlerEnd(void *userData){
		//printf("lenSecE\n");
	}
	
	int xc_beginParsing(XmlCore* xCore,const char* file){
		XML_Parser parser=NULL;
		FILE* xFile=NULL;		
		char xBuffer[BUFFSIZE];
		memset (xBuffer,'\0',BUFFSIZE);
		if(file!=NULL){xFile=fopen(file,"r");}
		if(xFile!=NULL){
			parser=XML_ParserCreate(NULL);
			if (! parser) {
    			fclose(xFile);
    			return CONST_FAILURE_CREATE;
 			}
			
			XML_SetUserData(parser,xCore);
			XML_SetElementHandler(parser, elementStart, elementEnd);
			XML_SetCdataSectionHandler(parser,cdataSectionHandlerStart,cdataSectionHandlerEnd);
			XML_SetCharacterDataHandler(parser,cdataHandler);

			//begin actual parsing
			for (;;) {
   				int done;
    			int len;
			
   				len = fread(xBuffer, 1, BUFFSIZE, xFile);
				if (ferror(stdin)) {
					fclose(xFile);
					XML_ParserFree(parser);
      				return CONST_FAILURE_READ;
    			}
			
    			done = feof(xFile);
			
				//printf("done: %d\n",done);
    			if (XML_Parse(parser, xBuffer, len, done) == XML_STATUS_ERROR) {
      				//fprintf(stderr, "Parse error at line %" XML_FMT_INT_MOD "u:\n%s\n",
          	    	//XML_GetCurrentLineNumber(parser),
         	     	//XML_ErrorString(XML_GetErrorCode(parser)));
					//printf("code: %d\n",XML_GetErrorCode(parser));
      				fclose(xFile);
      				XML_ParserFree(parser);
					return CONST_FAILURE_XMLERROR;
    			}
			
    			if (done){
      				break;
  				}
			}

			fclose(xFile);
			XML_ParserFree(parser);
			return 1;
		}
	return CONST_FAILURE_FILE_OPEN;
	}
	
	
	int xc_parseFromStringSource(XmlCore* xCore,const char* source){
		XML_Parser parser=NULL;
		char xBuffer[BUFFSIZE];


		if(source!=NULL){
			parser=XML_ParserCreate(NULL);
			if (! parser) {
    			return CONST_FAILURE_CREATE;
 			}
			
			XML_SetUserData(parser,xCore);
			XML_SetElementHandler(parser, elementStart, elementEnd);
			XML_SetCdataSectionHandler(parser,cdataSectionHandlerStart,cdataSectionHandlerEnd);
			XML_SetCharacterDataHandler(parser,cdataHandler);

			//begin actual parsing
			if (XML_Parse(parser, source, strlen(source), 1) == XML_STATUS_ERROR) {
				XML_ParserFree(parser);
				return CONST_FAILURE_XMLERROR;
			}
			XML_ParserFree(parser);
			return 1;
		}
	return CONST_FAILURE_READ;
	}
	
	static char* xc_parseTextResponse(apr_pool_t* p, int code, char* file){
		if(code==CONST_FAILURE_FILE_OPEN){
			return apr_pstrcat(p,"Failure to open file:",file!=NULL?file:"NULL",NULL);	
		}else if(code==CONST_FAILURE_XMLERROR){
			return apr_pstrcat(p,"Failure parsing xml:",file!=NULL?file:"NULL",NULL);
		}else if(code==CONST_FAILURE_READ){
			return apr_pstrcat(p,"Failure reading file:",file!=NULL?file:"NULL",NULL);
		}else if(code==CONST_FAILURE_CREATE){
			return apr_pstrcat(p,"Failure creating parser:",file!=NULL?file:"NULL",NULL);
		}
		return NULL;
	}
	char* xc_parseFromStringSourceTextResponse(XmlCore* xCore, char* source){
		int ret;
		ret=xc_parseFromStringSource(xCore,source);
		return xc_parseTextResponse(xCore->p,ret,source);
	}
	char* xc_beginParsingTextResponse(XmlCore* xCore, char* file){
		int ret;
		ret=xc_beginParsing(xCore,file);
		return xc_parseTextResponse(xCore->p,ret,file);
	}


<|start_filename|>src/config-core/config_bindings.c<|end_filename|>
#include <unistd.h>
#include <sys/time.h>
#include <string.h>
#include <stdlib.h>
#include <config-core/config_bindings.h>
#include <common_utils.h>
#include <http-utils/http_client.h>
#include "rewrite_core.h"

#ifndef __USE_GNU
#define __USE_GNU
#endif
#include <dlfcn.h>

#define URI_POSTFIX_AUTOREFRESH_TIMESTAMP		"autoRefreshTimestamp.txt"

	cfg_service_descriptor* cb_newServiceDescriptorObj(pool* p){
		cfg_service_descriptor* ret=(cfg_service_descriptor*)apr_palloc(p,sizeof(cfg_service_descriptor));
		ret->id=NULL;
		ret->name=NULL;
		ret->uri=NULL;
		ret->userColonPass=NULL;
		ret->timeoutSeconds=2;
		ret->params=apr_hash_make(p);
		return ret;
	}

	cfg_globals* cb_newGlobalsObj(pool* p){
		cfg_globals* ret=(cfg_globals*)apr_pcalloc(p,sizeof(cfg_globals));
		ret->homeDir=NULL;
		ret->logsDir=NULL;
		ret->resourceService=NULL;
		return ret;
	}
	char* cb_initGlobals(pool* p,cfg_globals* globals){
		if(globals->logsDir!=NULL){
			apr_dir_make_recursive(globals->logsDir,APR_OS_DEFAULT,p);
		}
		return NULL;
	}
	
	char* cb_writeRemoteResourceToDisk(pool* p, char* homeDir, char* reqUri, char* resource, long timeoutSeconds, char* userColonPass,
			apr_pool_t* tp, char**details, int* responseCode){
		char* ret=NULL, * bakFile=NULL,* filename=NULL;
		http_util_result* result=NULL;
		//file vars
		apr_file_t* file=NULL;
		apr_status_t status;
		apr_size_t file_written;
		char* errorMsg=NULL;
	
		if(resource==NULL) return NULL;
		
		result=hc_get_verbose(p,reqUri,timeoutSeconds,userColonPass,NULL,&errorMsg);

		if(hc_is200_OK(result)){
				//write file to filesystem
			if(result->size>0){
				bakFile=apr_pstrcat(tp,homeDir,"/",resource,".part",NULL);
				status=apr_file_open(&file,bakFile,APR_WRITE|APR_CREATE|APR_TRUNCATE,APR_OS_DEFAULT,tp);
				if(apr_file_write_full(file,result->data,result->size,&file_written)==APR_SUCCESS){
					filename=apr_pstrcat(p,homeDir,"/",resource,NULL);
					apr_file_close(file);
					if(apr_file_rename(bakFile,filename,tp)==APR_SUCCESS){
						ret=filename;
					}
				}else{				
					apr_file_close(file);
					if(details!=NULL){
						*details=apr_pstrcat(p,"Failure to write file:",SAFESTR(bakFile),NULL);
					}
				}
			}
		}else{
			if(details!=NULL){
				*details=apr_pstrcat(p,"Failure to write file (Response Code!=200): ",SAFESTR(resource),",",SAFESTR(errorMsg),NULL);
			}
			if(responseCode!=NULL&&result!=NULL){
				*responseCode=result->responseCode;
			}
		}
		
		return ret;
	}

	int cb_canAutoRefreshNow(pool* p, cfg_service_descriptor* resourceService, time_t lastRefreshTimestamp, time_t currentTimestamp, char* namespace,char**error){
		http_util_result* httpResult=NULL;
		char* endptr=NULL;
		char* reqQuery=NULL;
		long long value=-1;
		
		if(resourceService==NULL) return FALSE;
		
		reqQuery=apr_pstrcat(p,resourceService->uri,namespace,"/",URI_POSTFIX_AUTOREFRESH_TIMESTAMP,NULL);
		httpResult=hc_get_verbose2(p,reqQuery,resourceService->timeoutSeconds,5,resourceService->userColonPass,NULL,error);
		
		if(httpResult==NULL||httpResult->data==NULL||!hc_is200_OK(httpResult)) return FALSE;
		
		time_t autoRefreshTimestamp = cu_dateStringToSeconds(httpResult->data);
		
		if(autoRefreshTimestamp<0 || currentTimestamp<autoRefreshTimestamp) return FALSE;

		return TRUE;
	}


<|start_filename|>src/oidc-core/oidc_config_xml.c<|end_filename|>
#include <xml_core.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <common_utils.h>
#include <oidc-core/oidc_config_xml.h>
#include <oidc-core/rewrite_core.h>
#include <oidc-core/match_list.h>

#define CONST_INIT_PAGE_ACTIONS_ELTS		4
#define CONST_INIT_MATCH_LIST_ELTS			4
#define CONST_INIT_OIDC_PROVIDERS_ELTS		2

	typedef struct actmap_tmp{
		oidc_config_xml* conf;
		void* tmp;
		void* tmp2;
		void* tmp3;
		void* tmp4;
		void* tmp5;
		void* tmp6;
		void* tmp7;
		void* tmp8;
		void* tmp9;
		void* tmp10;
		void* tmp11;
		void* tmp12;
		void* tmp13;
		void* tmp14;
		void* tmp15;
		char* str, *errorStr;
	}actmap_tmp;
	
	static int doc_uid=0;

	oidc_config_xml* amx_newObj(pool* p){
		oidc_config_xml* ret=apr_palloc(p,sizeof(oidc_config_xml));
		ret->uid=0;
		ret->page_actions_hash=apr_hash_make (p);
		ret->path_mappings_arr=apr_array_make (p,CONST_INIT_PAGE_ACTIONS_ELTS,sizeof(path_mapping_xml*));
		ret->match_list_arr=apr_array_make (p,CONST_INIT_MATCH_LIST_ELTS,sizeof(mlx_matchlist*));
		ret->rpSession=cookie_newObj(p);
		cookie_setCookieName(p, ret->rpSession, (char*)"rp_session");
		ret->oidcSession=cookie_newObj(p);
		cookie_setCookieName(p, ret->oidcSession, (char*)"oidc_session");
		ret->relyingPartyHash=apr_hash_make (p);
		ret->oidcProviders=apr_array_make (p,CONST_INIT_OIDC_PROVIDERS_ELTS,sizeof(oidc_provider_xml*));
		ret->accessToken=NULL;
		return ret;
	}
	static void amx_printPathMappingMatchList(pool* p, array_header* arr){
			int i=0;
			char* match=NULL;
			if(arr!=NULL&&arr->nelts>0){
				printf("\r\n\t\t -- MatchLists[%d]: ",arr->nelts);
				for(i=0;i<arr->nelts;i++){
					match=(char*)cu_getElement(arr,i);
					if(i!=0){printf(",");}
					printf("%s",match);
				}
			}
			
		}
	
	void amx_printActions(pool*p, char*type, array_header* actions){
		int i;
		if(actions!=NULL&&actions->nelts>0){
			printf("\t* %s={",type);
			for(i=0;i<actions->nelts;i++){
				pathmapping_action_xml* action=(pathmapping_action_xml*)cu_getElement(actions,i);
				if(i!=0){printf(",");}
				printf("id=%s matchList=%s",action->id,action->matchList);
			}
			printf("}\r\n");
		}
	}
	
	void amx_printAll(pool* p,oidc_config_xml* conf){
		int x=0, i=0;
		page_action_xml* pa=NULL;
		apr_hash_index_t * hi=NULL;
		void *val=NULL;
		const void *key=NULL;
		
		path_mapping_xml* pmx=NULL;
		mlx_matchlist* mlist=NULL;
		char* includeXml=NULL;
		
		printf("<OIDC Configuration XML>\r\n");
		
		printf("Page Actions (%d)\r\n",apr_hash_count (conf->page_actions_hash));
		for (hi = apr_hash_first(p,conf->page_actions_hash); hi; hi = apr_hash_next(hi)) {
				apr_hash_this(hi, &key, NULL, &val);
				printf("\t* %s",key);
				if(val!=NULL){
					pa=(page_action_xml*)val;
					printf("uri:%s",pa->uri);
					if(pa->handler!=NULL){
						printf(",handler:%s",pa->handler);
					}
					if(pa->type){
						printf(",type:%d",pa->type);
					}
					if(pa->oidcProvider!=NULL){
						printf(",OidcProvider:%s",pa->oidcProvider);
					}
					if(pa->relyingParty!=NULL){
						printf(",RelyingParty:%s",pa->relyingParty);
					}
					printf(", isForward:%d,description:%s}",pa->isForward,pa->description);
					if(pa->requestHeaders!=NULL&&pa->requestHeaders->nelts>0){
						printf("\r\n\t\t>Request headers [%d]\n", pa->requestHeaders->nelts);
						for (i=0; i < pa->requestHeaders->nelts; i++){
							action_header_xml* hdr = 
								(action_header_xml*)cu_getElement(pa->requestHeaders, i);
							printf("\t\t\tHeader{name:%s, value:%s}\r\n", hdr->name, (hdr->value)?hdr->value:"null");
						}
					}
					if(pa->responseHeaders!=NULL&&pa->responseHeaders->nelts>0){
						printf("\r\n\t\t>Response headers [%d]\n", pa->responseHeaders->nelts);
						for (i=0; i < pa->responseHeaders->nelts; i++){
							action_header_xml* hdr = 
								(action_header_xml*)cu_getElement(pa->responseHeaders, i);
							printf("\t\t\tHeader{name:%s, value:%s}\r\n", hdr->name, (hdr->value)?hdr->value:"null");
						}
					}
				}
				printf("\r\n");
		}
		printf("Match Lists (%d):\r\n",conf->match_list_arr->nelts);
		for(x=0;x<conf->match_list_arr->nelts;x++){
			mlist=(mlx_matchlist*)cu_getElement(conf->match_list_arr,x);
			printf("\t* %s",mlist->name);
			if(mlist->matches->nelts>0){
				ml_printMatchList(p,mlist->matches);
			}
			printf("\r\n");
		}
		
		
		printf("Path Mappings (%d):\r\n",conf->path_mappings_arr->nelts);
		for(x=0;x<conf->path_mappings_arr->nelts;x++){
			pmx=(path_mapping_xml*)cu_getElement(conf->path_mappings_arr,x);
			printf("\t* %s",pmx->pathRegex);
			if(pmx->ignoreCase==TRUE){ printf("\t* ignoreCase=true"); }
			if(pmx->postAuthActions!=NULL){
				//printf(", PostAuth:%s",pmx->oidcAction);
				amx_printActions(p,"PostAuth", pmx->postAuthActions);
			}			
			amx_printPathMappingMatchList(p,pmx->matchLists);
			printf("\r\n");
		}

		if(conf->relyingPartyHash!=NULL) {
			printf("RelyingParties (%d):\r\n",apr_hash_count (conf->relyingPartyHash));
			for(hi = apr_hash_first(p,conf->relyingPartyHash); hi; hi = apr_hash_next(hi)){
				apr_hash_this(hi, &key, NULL, &val);
				relying_party_xml* relyingRarty=(relying_party_xml*)val;
				printf("\t\r\nID=%s",relyingRarty->id);
				printf("\t\r\nclientID=%s",relyingRarty->clientID);
				printf("\t\t\r\n* clientSecret=%s",relyingRarty->clientSecret);
				printf("\t\t\r\n* description=%s",relyingRarty->description);
				printf("\t\t\r\n* issuer=%s",relyingRarty->issuer);
				printf("\t\t\r\n* postLoginDefaultLandingPage=%s",relyingRarty->postLoginDefaultLandingPage);
				printf("\r\n");
			}
		}

		if(conf->oidcProviders!=NULL) {
			printf("OidcProviders (%d):\r\n",conf->oidcProviders->nelts);
			for(x=0;x<conf->oidcProviders->nelts;x++){
				oidc_provider_xml* oidcProviderX=(oidc_provider_xml*)cu_getElement(conf->oidcProviders,x);
				printf("\t\r\nID=%s[%d]", SAFESTR(oidcProviderX->id), x);
				printf("\t\r\nIssuer=%s[%d]", SAFESTR(oidcProviderX->issuer), x);
				printf("\t\r\nMetadataUrl=%s[%d]", SAFESTR(oidcProviderX->metadataUrl), x);
				printf("\r\n");
			}
		}

	}
	
	static page_action_xml* amx_newPageActionXml(pool* p){
		page_action_xml* ret;
		ret=apr_palloc(p,sizeof(page_action_xml));
		ret->id=NULL;
		ret->directory=NULL;
		ret->description=NULL;
		ret->isForward=1;
		ret->isPermanent=0;
		ret->type=action_authorize;
		ret->regex=NULL;
		ret->handler=NULL;
		ret->isDebug=0;
		ret->advancedTemplate=FALSE;
		ret->requestHeaders = apr_array_make(p, 1, sizeof(action_header_xml*));
		ret->responseHeaders = apr_array_make(p, 1, sizeof(action_header_xml*));
		ret->uri =NULL;
		ret->response = NULL;
		ret->oidcProvider=NULL;
		ret->relyingParty=NULL;
		return ret;
	}
	
	static int amx_oidcConfigAttributes(pool* p,char* xPath,int type,const char ** attributes,void* userdata){
		int i;
		//page_action_xml* pax=NULL;
		actmap_tmp* ctmp=(actmap_tmp*)userdata;
		return 1;
	}

	static int amx_newPageAction(pool* p,char* xPath,int type,const char ** attributes,void* userdata){
		int i;
		page_action_xml* pax=NULL;
		actmap_tmp* ctmp=(actmap_tmp*)userdata;
		pax=(void*)amx_newPageActionXml(p);
		ctmp->tmp=pax;
		
		for(i=0;attributes[i]; i += 2) {
			if(strcmp(attributes[i],"id")==0){
				pax->id=apr_pstrdup(p,(char*)attributes[i + 1]);
				if(ctmp->conf->uid!=0){
					pax->id=apr_psprintf(p,"%s_%d",pax->id,ctmp->conf->uid);
				}
			}else if(strcmp(attributes[i],"debug")==0){
				pax->isDebug=STRTOBOOL((char*)attributes[i + 1]);				
			}else if(strcmp(attributes[i],"type")==0){
				if (strcmp((char*)attributes[i + 1], "login")==0)
					pax->type = action_login;
			    else if (strcmp((char*)attributes[i + 1], "callback")==0)
			    	pax->type = action_callback;
			    else if (strcmp((char*)attributes[i + 1], "authorize")==0)
			    	pax->type = action_authorize;
			    else if (strcmp((char*)attributes[i + 1], "denial")==0)
			    	pax->type = action_denial;
			}
		}
		return 1;
	}
	static int amx_setPageActionId(pool* p,char* xPath,int type,const char *body,void* userdata){
		actmap_tmp* ctmp=(actmap_tmp*)userdata;
		page_action_xml* pa=(page_action_xml*)ctmp->tmp;
		if(pa!=NULL&&pa->id==NULL){
			pa->id=apr_pstrdup(p,body);
			if(ctmp->conf->uid!=0){
				pa->id=apr_psprintf(p,"%s_%d",pa->id,ctmp->conf->uid);
			}
		}
		return 1;
	}
	static int amx_setPageActionDescription(pool* p,char* xPath,int type,const char *body,void* userdata){
		actmap_tmp* ctmp=(actmap_tmp*)userdata;
		page_action_xml* pa=(page_action_xml*)ctmp->tmp;
		pa->description=apr_pstrdup(p,body);
		return 1;
	}
	static int amx_setPageActionRegex(pool* p,char* xPath,int type,const char *body,void* userdata){
		actmap_tmp* ctmp=(actmap_tmp*)userdata;
		page_action_xml* pa=(page_action_xml*)ctmp->tmp;
		pa->regex=apr_pstrdup(p,body);
		return 1;
	}
	static int amx_setPageActionHandler(pool* p,char* xPath,int type,const char *body,void* userdata){
		actmap_tmp* ctmp=(actmap_tmp*)userdata;
		page_action_xml* pa=(page_action_xml*)ctmp->tmp;
		pa->handler=apr_pstrdup(p,body);
		return 1;
	}
	
	static int amx_setPageActionUri(pool* p,char* xPath,int type,const char *body,void* userdata){
		actmap_tmp* ctmp=(actmap_tmp*)userdata;
		page_action_xml* pa=(page_action_xml*)ctmp->tmp;

		if(pa!=NULL){
			pa->uri=apr_pstrdup(p,body);
		}
		
		return 1;
	}
	static int amx_setPageActionOidcProvider(pool* p,char* xPath,int type,const char *body,void* userdata){
		actmap_tmp* ctmp=(actmap_tmp*)userdata;
		page_action_xml* pa=(page_action_xml*)ctmp->tmp;
		if(pa!=NULL){
			pa->oidcProvider=apr_pstrdup(p,body);
		}
		return 1;
	}
	static int amx_setPageActionRelyingParty(pool* p,char* xPath,int type,const char *body,void* userdata){
		actmap_tmp* ctmp=(actmap_tmp*)userdata;
		page_action_xml* pa=(page_action_xml*)ctmp->tmp;
		if(pa!=NULL){
			pa->relyingParty=apr_pstrdup(p,body);
		}
		return 1;
	}
	static int amx_setPageActionIsForward(pool* p,char* xPath,int type,const char *body,void* userdata){
		actmap_tmp* ctmp=(actmap_tmp*)userdata;
		page_action_xml* pa=(page_action_xml*)ctmp->tmp;
		pa->isForward=strcmp(body,"true")==0?1:0;
		return 1;
	}
	static int amx_setPageActionIsPermanent(pool* p,char* xPath,int type,const char *body,void* userdata){
		actmap_tmp* ctmp=(actmap_tmp*)userdata;
		page_action_xml* pa=(page_action_xml*)ctmp->tmp;
		pa->isPermanent=strcmp(body,"true")==0?1:0;
		return 1;
	}
	static int amx_setPageActionAdvancedTemplate(pool* p,char* xPath,int type,const char *body,void* userdata){
		actmap_tmp* ctmp=(actmap_tmp*)userdata;
		page_action_xml* pa=(page_action_xml*)ctmp->tmp;
		pa->advancedTemplate=STRTOBOOL(body);
		return 1;
	}
	static int amx_setPageActionBase64UrlEncodeState(pool* p,char* xPath,int type,const char *body,void* userdata){
		actmap_tmp* ctmp=(actmap_tmp*)userdata;
		page_action_xml* pa=(page_action_xml*)ctmp->tmp;
		pa->base64UrlEncodeState=STRTOBOOL(body);
		return 1;
	}
	static int amx_addPageAction(pool* p,char* xPath,int type,void* userdata){
		oidc_config_xml* amx=NULL;
			page_action_xml* pageact=NULL;
			actmap_tmp* ctmp=(actmap_tmp*)userdata;
			amx=(oidc_config_xml*)ctmp->conf;
			
			if(amx!=NULL&&ctmp->tmp!=NULL){
				pageact=(page_action_xml*)ctmp->tmp;
				apr_hash_set (amx->page_actions_hash,pageact->id,APR_HASH_KEY_STRING,ctmp->tmp);
				// loginRedirect means always 302 meaning isForward false
				if(pageact->type==action_login||pageact->response!=NULL) { pageact->isForward = FALSE; }
			}
			ctmp->tmp=NULL;
			return 1;
	}
	
	//path mapping handlers
	static path_mapping_xml* amx_newPathMappingXml(pool* p){
		path_mapping_xml* ret;
		ret=apr_palloc(p,sizeof(path_mapping_xml));
		ret->pathRegex=NULL;
		ret->ignoreCase=FALSE;// Case sensitive by default
		ret->postAuthActions=apr_array_make(p,1,sizeof(pathmapping_action_xml*));
		ret->matchLists=apr_array_make(p,1,sizeof(char*));
		return ret;
	}

	static void amx_appendMatchListsToMatchListArray(pool*p,char* matchListsStr,int uniqueId,array_header*matchLists){
		array_header* arr;
		char* tmp,**pos;
		int i;
		
		if(matchListsStr==NULL)	return;
		arr=cu_parseStringArrayFromCsv(p,4,",",matchListsStr);
		if(arr==NULL||arr->nelts<1)	return;
		for(i=0;i<arr->nelts;i++){
			tmp=(char*)cu_getElement(arr,i);
			if(uniqueId!=0){tmp=apr_psprintf(p,"%s_%d",tmp,uniqueId);}
			pos=apr_array_push(matchLists);
			*pos=tmp;
		}
		return;
	}		
	static int amx_newPathMapping(pool* p,char* xPath,int type,const char ** attributes,void* userdata){\
		int i;
		path_mapping_xml* map=NULL;
		actmap_tmp* ctmp=(actmap_tmp*)userdata;
		map=amx_newPathMappingXml(p);
		ctmp->tmp=(void*)map;
		char*matchListsStr;
		
		for(i=0;attributes[i]; i += 2) {
			if(strcmp(attributes[i],"path")==0){
				map->pathRegex=apr_pstrdup(p,(char*)attributes[i + 1]);				
			}else if(strcmp(attributes[i],"matchLists")==0){
				matchListsStr=apr_pstrdup(p,(char*)attributes[i + 1]);
				amx_appendMatchListsToMatchListArray(p,matchListsStr,ctmp->conf->uid,map->matchLists);
			}else if(strcmp(attributes[i],"ignoreCase")==0){
				map->ignoreCase=STRTOBOOL((char*)attributes[i + 1]);
			}
		}
		return 1;
	}
	static int amx_addPathMapping(pool* p,char* xPath,int type,void* userdata){
		oidc_config_xml* amx=NULL;
		path_mapping_xml* pm=NULL, **placepm=NULL;
		actmap_tmp* ctmp=(actmap_tmp*)userdata;
		
		amx=(oidc_config_xml*)ctmp->conf;
		if(amx!=NULL&&ctmp->tmp!=NULL){
			pm=(path_mapping_xml*)ctmp->tmp;
			placepm=(path_mapping_xml**)apr_array_push (amx->path_mappings_arr);
			*placepm=pm;
		}
		ctmp->tmp=NULL;
		return 1;
	}
	static int amx_setPath(pool* p,char* xPath,int type,const char *body,void* userdata){
		actmap_tmp* ctmp=(actmap_tmp*)userdata;
		path_mapping_xml* pa=(path_mapping_xml*)ctmp->tmp;
		if(pa!=NULL){
			pa->pathRegex=apr_pstrdup(p,body);
		}
		return 1;
	}

	static int amx_newPathMappingAction(pool* p,char* xPath,int type,const char ** attributes,void* userdata){
		int i;
		actmap_tmp* ctmp=(actmap_tmp*)userdata;
		pathmapping_action_xml* action=apr_palloc(p,sizeof(pathmapping_action_xml));
		action->id=NULL;
		action->matchList=NULL;
		
		for(i=0;attributes[i]; i += 2) {
			if(strcmp(attributes[i],"matchList")==0){
				action->matchList=apr_pstrdup(p,(char*)attributes[i + 1]);
				if(ctmp->conf->uid!=0){
					action->matchList=apr_psprintf(p,"%s_%d",action->matchList,ctmp->conf->uid);
				}
			}
		}
		ctmp->tmp6=(void*)action;
		return 1;
	}
	static int amx_setPathMappingAction(pool* p,char* xPath,int type,const char *body,void* userdata){
		actmap_tmp* ctmp=(actmap_tmp*)userdata;
		pathmapping_action_xml* action=(pathmapping_action_xml*)ctmp->tmp6;
		
		if(action!=NULL){
			if(ctmp->conf->uid!=0){
				action->id=apr_psprintf(p,"%s_%d",body,ctmp->conf->uid);
			}else{
				action->id=apr_pstrdup(p,body);
			}
		}
		return 1;
	}	
	static int amx_addPathMappingAction(pool* p,void* userdata,array_header* actions){
		actmap_tmp* ctmp=(actmap_tmp*)userdata;
		path_mapping_xml* pa=(path_mapping_xml*)ctmp->tmp;
		pathmapping_action_xml* action=(pathmapping_action_xml*)ctmp->tmp6, **pos=NULL;	
		if(actions!=NULL){
			pos=(pathmapping_action_xml**)apr_array_push(actions);
			*pos=action;
			printf("matchlist=%s id=%s \r\n",action->matchList, action->id);
		}
		ctmp->tmp6=NULL;
		return 1;
	}
	static int amx_addPathMappingPostAuth(pool* p,char* xPath,int type,void* userdata){
		actmap_tmp* ctmp=(actmap_tmp*)userdata;
		path_mapping_xml* pa=(path_mapping_xml*)ctmp->tmp;
		if(pa!=NULL){
			amx_addPathMappingAction(p,userdata,pa->postAuthActions);
		}
		return 1;
	}	
	static int amx_addPathMappingMatchList(pool* p,char* xPath,int type,const char *body,void* userdata){
		actmap_tmp* ctmp=(actmap_tmp*)userdata;
		path_mapping_xml* pa=(path_mapping_xml*)ctmp->tmp;
		char** pos=NULL, *tmp;
		if(pa!=NULL){
			pos=apr_array_push(pa->matchLists);
			tmp=apr_pstrdup(p,body);
			if(ctmp->conf->uid!=0){
				tmp=apr_psprintf(p,"%s_%d",tmp,ctmp->conf->uid);
			}
			*pos=tmp;
		}
		return 1;
	}

	static int amx_newPathMappingMatchHeader(pool* p,char* xPath,int type,const char ** attributes,void* userdata){
		actmap_tmp* ctmp=(actmap_tmp*)userdata;
		mlx_ml_match* match=(mlx_ml_match*)ctmp->tmp2;
		int i=0;
		mlx_match_header* hdr=NULL;
		
		if(match!=NULL){
			hdr=ml_newMatchHeaderObj(p);
			for(i=0;attributes[i]; i += 2) {
				if(strcmp(attributes[i],"name")==0){
					hdr->name=apr_pstrdup(p,(char*)attributes[i + 1]);
				}else if(strcmp(attributes[i],"delimAnd")==0){
					hdr->delimAnd=apr_pstrdup(p,(char*)attributes[i + 1]);
				}else if(strcmp(attributes[i],"negate")==0){
					hdr->negate=STRTOBOOL(apr_pstrdup(p,(char*)attributes[i + 1]));
				}else if(strcmp(attributes[i],"isregex")==0){
					hdr->isRegex=STRTOBOOL(apr_pstrdup(p,(char*)attributes[i + 1]));
				}
			}
			ctmp->tmp5=(void*)hdr;
		}
		return 1;
	}
	static char* amx_getGlobalPrefixedParam(pool* p, const char* key){
		if(key==NULL) return NULL;
		if(strstr(key,"global:")==key){
			return apr_pstrdup(p,key+7);
		}
		return NULL;
	}
		
	time_t amx_dateStringToSeconds(const char* dateString){
	//Functionality moved to common_utils.c
		return cu_dateStringToSeconds(dateString);
	}
	
	static int amx_newPathMappingMatchEvent(pool* p,char* xPath,int type,const char ** attributes,void* userdata){
		actmap_tmp* ctmp=(actmap_tmp*)userdata;
		mlx_ml_match* match=(mlx_ml_match*)ctmp->tmp2;
		int i=0;
		mlx_match_event* e=NULL;
		
		if(match!=NULL){
			e=ml_newMatchEventObj(p);
			for(i=0;attributes[i]; i += 2) {
				if(strcmp(attributes[i],"start")==0){
					e->start=amx_dateStringToSeconds(apr_pstrdup(p,(char*)attributes[i + 1]));
				}else if(strcmp(attributes[i],"end")==0){
					e->end=amx_dateStringToSeconds(apr_pstrdup(p,(char*)attributes[i + 1]));
				}
			}
			match->event=e;
		}
		return 1;
	}

	static int amx_setPathMappingMatchHeader(pool* p,char* xPath,int type,const char *body,void* userdata){
		actmap_tmp* ctmp=(actmap_tmp*)userdata;
		mlx_ml_match* match=(mlx_ml_match*)ctmp->tmp2;
		mlx_match_header* hdr=(mlx_match_header*)ctmp->tmp5, **headerPlace;
		
		if(match!=NULL&&hdr!=NULL){
			hdr->value=apr_pstrdup(p,body);
			headerPlace=(mlx_match_header**)apr_array_push(match->headerList);
			*headerPlace=hdr;
			
			if(ctmp->errorStr==NULL&&!rc_isRegexValid(p,hdr->value)){
				ctmp->errorStr=apr_pstrcat(p,"Header Regex not valid: (",hdr->name,"=",hdr->value,")",NULL);
			}
			ctmp->tmp5=NULL;
		}
		return 1;
	}
	
	static action_header_xml* amx_newActionHeaderObj(pool* p){
		action_header_xml* ret=apr_palloc(p,sizeof(action_header_xml));
		ret->name=NULL;
		ret->value=NULL;
		ret->regex=NULL;
		ret->action=header_set;
		return ret;
	}
	
	static header_actions amx_getHeaderAction(const char* action) {
		header_actions header_action;
		
		if(action==NULL) return header_set;
		
		if (!strcasecmp(action, "set"))
			header_action = header_set;
	    else if (!strcasecmp(action, "add"))
	    	header_action = header_add;
	    else if (!strcasecmp(action, "append"))
	    	header_action = header_append;
	    else if (!strcasecmp(action, "merge"))
	    	header_action = header_merge;
	    else if (!strcasecmp(action, "unset"))
	    	header_action = header_unset;
	    else if (!strcasecmp(action, "echo"))
	    	header_action = header_echo;
	    else if (!strcasecmp(action, "edit"))
	    	header_action = header_edit;
	    else header_action = header_set;
		
		return header_action;
	}
	
	static int amx_newActionHeader(pool* p,char* xPath,int type,const char ** attributes,void* userdata){
		actmap_tmp* ctmp=(actmap_tmp*)userdata;
		action_header_xml* hdr = amx_newActionHeaderObj(p);
		int i;
		for(i=0;attributes[i]; i += 2) {
			if(strcmp(attributes[i],"name")==0){
				hdr->name=apr_pstrdup(p,(char*)attributes[i + 1]);
			}
			else if(strcmp(attributes[i],"regex")==0) {
				hdr->regex = apr_pstrdup(p,(char*)attributes[i + 1]);
			}
			else if(strcmp(attributes[i],"do")==0) {
				hdr->action = amx_getHeaderAction((char*)attributes[i + 1]); 
			}			
		}
		ctmp->tmp8=(void*)hdr;
		return 1;
	}
	
	static int amx_setActionResponseHeader(pool* p,char* xPath,int type,const char *body,void* userdata){
		actmap_tmp* ctmp=(actmap_tmp*)userdata;
		page_action_xml* pa=(page_action_xml*)ctmp->tmp;
		action_header_xml* hdr=(action_header_xml*)ctmp->tmp8, **headerPlace;

		if(pa!=NULL&&pa->responseHeaders!=NULL&&hdr!=NULL){
			hdr->value=apr_pstrdup(p,body);
			headerPlace=(action_header_xml**)apr_array_push(pa->responseHeaders);
			*headerPlace=hdr;
			//printf("responseheaders=%s:%s\n", hdr->name, hdr->value);
			ctmp->tmp8=NULL;
		}
		return 1;
	}

	static int amx_setActionRequestHeader(pool* p,char* xPath,int type,const char *body,void* userdata){
		actmap_tmp* ctmp=(actmap_tmp*)userdata;
		page_action_xml* pa=(page_action_xml*)ctmp->tmp;
		action_header_xml* hdr=(action_header_xml*)ctmp->tmp8, **headerPlace;

		if(pa!=NULL&&pa->requestHeaders!=NULL&&hdr!=NULL){
			hdr->value=apr_pstrdup(p,body);
			headerPlace=(action_header_xml**)apr_array_push(pa->requestHeaders);
			*headerPlace=hdr;
			//printf("requestHeaders=%s:%s\n", hdr->name, hdr->value);
			ctmp->tmp8=NULL;
		}
		return 1;
	}
	
	static int amx_newMatchList(pool* p,char* xPath,int type,const char ** attributes,void* userdata){\
		int i;
		actmap_tmp* ctmp=(actmap_tmp*)userdata;
		mlx_matchlist* mlist=apr_palloc(p,sizeof(mlx_matchlist));
		mlist->name=NULL;
		mlist->matches=apr_array_make(p,2,sizeof(mlx_ml_match*));
		
		for(i=0;attributes[i]; i += 2) {
			if(strcmp(attributes[i],"name")==0){
				mlist->name=apr_pstrdup(p,(char*)attributes[i + 1]);
				if(ctmp->conf->uid!=0){
					mlist->name=apr_psprintf(p,"%s_%d",mlist->name,ctmp->conf->uid);
				}
				ctmp->tmp=(void*)mlist;
			}
		}
		return 1;
	}
	static int amx_addMatchList(pool* p,char* xPath,int type,void* userdata){
		actmap_tmp* ctmp=(actmap_tmp*)userdata;
		oidc_config_xml* amx=(oidc_config_xml*)ctmp->conf;
		mlx_matchlist* mlist=(mlx_matchlist*)ctmp->tmp, **mlistPos=NULL;
		
		if(ctmp!=NULL&&mlist!=NULL&&mlist->name!=NULL){
			mlistPos=(mlx_matchlist**)apr_array_push(amx->match_list_arr);
			*mlistPos=mlist;
		}
		ctmp->tmp=NULL;
		return 1;
	}
	static int amx_newPathMappingMatch(pool* p,char* xPath,int type,const char ** attributes,void* userdata){
		actmap_tmp* ctmp=(actmap_tmp*)userdata;
		mlx_ml_match* match=ml_newMatchListMatchObj(p);
		int i;
		if(match!=NULL){
			for(i=0;attributes[i]; i += 2){
				if(strcmp(attributes[i],"host")==0){
					match->host=apr_pstrdup(p,(char*)attributes[i + 1]);
				}else if(strcmp(attributes[i],"cascade")==0){
					match->cascade=STRTOBOOL((char*)attributes[i + 1]);
				}
			}
		}		
		ctmp->tmp2=(void*)match;
		return 1;
	}
	
	static int amx_addPathMappingMatch(pool* p,char* xPath,int type,void* userdata){
		actmap_tmp* ctmp=(actmap_tmp*)userdata;
		mlx_matchlist* matchlist=(mlx_matchlist*)ctmp->tmp;
		mlx_ml_match* match=(mlx_ml_match*)ctmp->tmp2, **matchPos=NULL;
		if(match!=NULL&&matchlist!=NULL){
			matchPos=(mlx_ml_match**)apr_array_push(matchlist->matches);
			*matchPos=match;
			ctmp->tmp2=NULL;
		}
		return 1;
	}
	static int amx_setMatchHost(pool* p,char* xPath,int type,const char *body,void* userdata){
		actmap_tmp* ctmp=(actmap_tmp*)userdata;
		mlx_ml_match* match=(mlx_ml_match*)ctmp->tmp2;
		if(match!=NULL){
			match->host=apr_pstrdup(p,body);
		}
		return 1;
	}
	static int amx_newMatchListMatchIp(pool* p,char* xPath,int type,const char ** attributes,void* userdata){
		int i;
		actmap_tmp* ctmp=(actmap_tmp*)userdata;
		mlx_match_ip* ip=ml_newMatchIpObj(p);
		
		for(i=0;attributes[i]; i += 2){
			if(strcmp(attributes[i],"isregex")==0){
				ip->isRegex=STRTOBOOL((char*)attributes[i + 1]);
			}else if(strcmp(attributes[i],"negate")==0){
				ip->negate=STRTOBOOL((char*)attributes[i + 1]);
			}
		}
		ctmp->tmp6=(void*)ip;
		return 1;
	}
	static int amx_setPathMappingMatchIp(pool* p,char* xPath,int type,const char *body,void* userdata){
		actmap_tmp* ctmp=(actmap_tmp*)userdata;
		mlx_ml_match* match=(mlx_ml_match*)ctmp->tmp2;	
		mlx_match_ip* ip=(mlx_match_ip*)ctmp->tmp6;
		
		if(match!=NULL&&ip!=NULL){
			ip->ip=apr_pstrdup(p,body);
			if(ctmp->errorStr==NULL&&ip->isRegex==TRUE&&!rc_isRegexValid(p,ip->ip)){
				ctmp->errorStr=apr_pstrcat(p,"IP Regex not valid:",ip->ip,NULL);
			}
			match->ip=ip;
		}
		ctmp->tmp6=NULL;
		
		return 1;
	}
	static int amx_newMatchListMatchPath(pool* p,char* xPath,int type,const char ** attributes,void* userdata){
		int i;
		actmap_tmp* ctmp=(actmap_tmp*)userdata;
		mlx_match_path* path=ml_newMatchPathObj(p);
		
		for(i=0;attributes[i]; i += 2){
			if(strcmp(attributes[i],"negate")==0){
				path->negate=STRTOBOOL((char*)attributes[i + 1]);
			}
		}
		ctmp->tmp7=(void*)path;
		return 1;
	}
	static int amx_setPathMappingMatchPath(pool* p,char* xPath,int type,const char *body,void* userdata){
		actmap_tmp* ctmp=(actmap_tmp*)userdata;
		mlx_ml_match* match=(mlx_ml_match*)ctmp->tmp2;	
		mlx_match_path* path=(mlx_match_path*)ctmp->tmp7;
		
		if(match!=NULL&&path!=NULL){
			path->path=apr_pstrdup(p,body);
			if(ctmp->errorStr==NULL&&!rc_isRegexValid(p,path->path)){
				ctmp->errorStr=apr_pstrcat(p,"IP Regex not valid:",path->path,NULL);
			}
			match->path=path;
		}
		ctmp->tmp7=NULL;
		
		return 1;
	}	
	static int amx_newInclude(pool* p,char* xPath,int type,const char ** attributes,void* userdata){
		int i;
	
		actmap_tmp* ctmp=(actmap_tmp*)userdata;
		for(i=0;attributes[i]; i += 2) {
			if(strcmp(attributes[i],"path")==0){
				ctmp->tmp4=apr_pstrdup(p,(char*)attributes[i + 1]);
			}
		}
		return 1;
	}

	static action_response_xml* actionmapxml_newPageActionResponseObj(pool* p){
		action_response_xml* ret=(action_response_xml*)apr_palloc(p,sizeof(action_response_xml));
		ret->code=200;
		ret->contentType=NULL;
		ret->body=NULL;
		return ret;
	}
	
	static int amx_newPageActionResponse(pool* p,char* xPath,int type,const char ** attributes,void* userdata){
		int i;
		actmap_tmp* ctmp=(actmap_tmp*)userdata;
		action_response_xml* response=actionmapxml_newPageActionResponseObj(p);
		
		
		for(i=0;attributes[i]; i += 2) {
			if(strcmp(attributes[i],"code")==0){
				response->code=atoi(attributes[i + 1]);			
			}else if(strcmp(attributes[i],"contentType")==0){
				response->contentType=apr_pstrdup(p, attributes[i + 1]);			
			}
		}
		ctmp->tmp11=(void*)response;
		
		return 1;
	}
	
	static int amx_setPageActionResponseBody(pool* p,char* xPath,int type,const char *body,void* userdata){
		actmap_tmp* ctmp=(actmap_tmp*)userdata;
		action_response_xml* response=(action_response_xml*)ctmp->tmp11;
		
		if(response!=NULL){
			response->body = apr_pstrdup(p,body);
		}		
		return 1;
	}
	
	static int amx_addPageActionResponse(pool* p,char* xPath,int type,void* userdata){
			actmap_tmp* ctmp=(actmap_tmp*)userdata;
			 
			if(ctmp->tmp!=NULL&&ctmp->tmp11!=NULL){
				page_action_xml* pa=(page_action_xml*)ctmp->tmp;
				if(pa!=NULL) {
					pa->response=(action_response_xml*)ctmp->tmp11;
				}
			}
			ctmp->tmp11=NULL;
			return 1;
	}

	static int cc_setACCSessionCookieAttributes(pool* p,char* xPath,int type,const char ** attributes,void* userdata){
		int i;
		actmap_tmp* stmp=(actmap_tmp*)userdata;
		oidc_config_xml* conf=(oidc_config_xml*)stmp->conf;
		for (i = 0; attributes[i]; i += 2) {
			if(strcmp(attributes[i],"name")==0){
				cookie_setCookieName(p, conf->rpSession, (char*)attributes[i + 1]);
			}else if(strcmp(attributes[i],"lifetime")==0){
				cookie_setCookieLifeTime(conf->rpSession,atoi(attributes[i + 1]));
			}else if(strcmp(attributes[i],"httpOnly")==0){
				cookie_setCookieHttpOnlyflag(conf->rpSession,
						STRTOBOOL(attributes[i + 1]));
			}else if(strcmp(attributes[i],"secureHttpOnly")==0){
				cookie_setCookieSecureHttpOnlyflag(conf->rpSession,
						STRTOBOOL(attributes[i + 1]));
			}
  		}
		return 1;
	}

	static int cc_setACCPermCookieAttributes(pool* p,char* xPath,int type,const char ** attributes,void* userdata){
		int i;
		actmap_tmp* stmp=(actmap_tmp*)userdata;
		oidc_config_xml* conf=(oidc_config_xml*)stmp->conf;

		for (i = 0; attributes[i]; i += 2) {
			if(strcmp(attributes[i],"name")==0){
				cookie_setCookieName(p, conf->oidcSession,(char*)attributes[i + 1]);
			}else if(strcmp(attributes[i],"lifetime")==0){
				cookie_setCookieLifeTime(conf->oidcSession,atoi(attributes[i + 1]));
			}else if(strcmp(attributes[i],"httpOnly")==0){
				cookie_setCookieHttpOnlyflag(conf->oidcSession,STRTOBOOL(attributes[i + 1]));
			}else if(strcmp(attributes[i],"secureHttpOnly")==0){
				cookie_setCookieSecureHttpOnlyflag(conf->oidcSession,
						STRTOBOOL(attributes[i + 1]));
			}
  		}
		return 1;
	}

	static int cc_setACCAccessTokenCookieAttributes(pool* p,char* xPath,int type,const char ** attributes,void* userdata){
		int i;
		actmap_tmp* stmp=(actmap_tmp*)userdata;
		oidc_config_xml* conf=(oidc_config_xml*)stmp->conf;
		conf->accessToken = cookie_newObj(p);
		cookie_setCookieName(p, conf->accessToken, (char*)"access_token");
		for (i = 0; attributes[i]; i += 2) {
			if(strcmp(attributes[i],"name")==0){
				cookie_setCookieName(p, conf->accessToken,(char*)attributes[i + 1]);
			}else if(strcmp(attributes[i],"lifetime")==0){
				cookie_setCookieLifeTime(conf->accessToken,atoi(attributes[i + 1]));
			}else if(strcmp(attributes[i],"httpOnly")==0){
				cookie_setCookieHttpOnlyflag(conf->accessToken,STRTOBOOL(attributes[i + 1]));
			}else if(strcmp(attributes[i],"secureHttpOnly")==0){
				cookie_setCookieSecureHttpOnlyflag(conf->accessToken,
						STRTOBOOL(attributes[i + 1]));
			}
  		}
		return 1;
	}

	static relying_party_xml* amx_newRelyingPartyXml(pool* p){
		relying_party_xml* ret;
		ret=apr_palloc(p,sizeof(relying_party_xml));
		ret->clientID=NULL;
		ret->clientSecret=NULL;
		ret->description=NULL;
		ret->issuer=NULL;
		ret->validateNonce=TRUE;
		ret->redirectUri=NULL;
		ret->id=NULL;
		ret->postLoginDefaultLandingPage=NULL;
		return ret;
	}

	static int amx_defaultRelyingParty(pool* p,char* xPath,int type,const char ** attributes,void* userdata){
		int i;
		actmap_tmp* ctmp=(actmap_tmp*)userdata;
		oidc_config_xml* amx=(oidc_config_xml*)ctmp->conf;
		return 1;
	}

	static int amx_newRelyingParty(pool* p,char* xPath,int type,const char ** attributes,void* userdata){
		int i;
		actmap_tmp* ctmp=(actmap_tmp*)userdata;
		relying_party_xml* rpX=(relying_party_xml*)amx_newRelyingPartyXml(p);
		for(i=0;attributes[i]; i += 2) {
			if(strcmp(attributes[i],"id")==0){
				rpX->id=apr_pstrdup(p,(char*)attributes[i + 1]);
			}else if(strcmp(attributes[i],"clientID")==0){
				rpX->clientID=apr_pstrdup(p,(char*)attributes[i + 1]);
			}else if(strcmp(attributes[i],"clientSecret")==0){
				rpX->clientSecret=apr_pstrdup(p,(char*)attributes[i + 1]);
			}else if(strcmp(attributes[i],"validateNonce")==0){
				rpX->validateNonce=STRTOBOOL(attributes[i + 1]);
			}
		}
		ctmp->tmp14=rpX;
		return 1;
	}
	static int amx_addRelyingParty(pool* p,char* xPath,int type,void* userdata){
		oidc_config_xml* amx=NULL;
			relying_party_xml* rpX=NULL;
			actmap_tmp* ctmp=(actmap_tmp*)userdata;
			amx=(oidc_config_xml*)ctmp->conf;

			if(amx!=NULL&&ctmp->tmp14!=NULL){
				rpX=(relying_party_xml*)ctmp->tmp14;
				apr_hash_set (amx->relyingPartyHash,rpX->id,APR_HASH_KEY_STRING,rpX);
			}
			ctmp->tmp14=NULL;
			return 1;
	}

	static int amx_setRelyingPartyClientID(pool* p,char* xPath,int type,const char *body,void* userdata){
		actmap_tmp* ctmp=(actmap_tmp*)userdata;
		relying_party_xml* rpX=(relying_party_xml*)ctmp->tmp14;
		if(rpX!=NULL&&rpX->clientID==NULL){
			rpX->clientID=apr_pstrdup(p,body);
		}
		return 1;
	}
	static int amx_setRelyingPartyDescription(pool* p,char* xPath,int type,const char *body,void* userdata){
		actmap_tmp* ctmp=(actmap_tmp*)userdata;
		relying_party_xml* rpX=(relying_party_xml*)ctmp->tmp14;
		if(rpX!=NULL&&rpX->description==NULL){
			rpX->description=apr_pstrdup(p,body);
		}
		return 1;
	}
	static int amx_setRelyingPartyClientSecret(pool* p,char* xPath,int type,const char *body,void* userdata){
		actmap_tmp* ctmp=(actmap_tmp*)userdata;
		relying_party_xml* rpX=(relying_party_xml*)ctmp->tmp14;
		if(rpX!=NULL&&rpX->clientSecret==NULL){
			rpX->clientSecret=apr_pstrdup(p,body);
		}
		return 1;
	}
	static int amx_setRelyingPartyIssuer(pool* p,char* xPath,int type,const char *body,void* userdata){
		actmap_tmp* ctmp=(actmap_tmp*)userdata;
		relying_party_xml* rpX=(relying_party_xml*)ctmp->tmp14;
		if(rpX!=NULL&&rpX->issuer==NULL){
			rpX->issuer=apr_pstrdup(p,body);
		}
		return 1;
	}
	static int amx_setRelyingPartyValidateNonce(pool* p,char* xPath,int type,const char *body,void* userdata){
		actmap_tmp* ctmp=(actmap_tmp*)userdata;
		relying_party_xml* rpX=(relying_party_xml*)ctmp->tmp14;
		if(rpX!=NULL&&rpX->issuer==NULL){
			rpX->validateNonce=STRTOBOOL(body);
		}
		return 1;
	}
	static int amx_setRelyingPartyRedirectUri(pool* p,char* xPath,int type,const char *body,void* userdata){
		actmap_tmp* ctmp=(actmap_tmp*)userdata;
		relying_party_xml* rpX=(relying_party_xml*)ctmp->tmp14;
		if(rpX!=NULL&&rpX->redirectUri==NULL){
			rpX->redirectUri=apr_pstrdup(p,body);
		}
		return 1;
	}
	static int amx_setRelyingPartyPostLoginDefaultLandingPage(pool* p,char* xPath,int type,const char *body,void* userdata){
		actmap_tmp* ctmp=(actmap_tmp*)userdata;
		relying_party_xml* rpX=(relying_party_xml*)ctmp->tmp14;
		if(rpX!=NULL&&rpX->postLoginDefaultLandingPage==NULL){
			rpX->postLoginDefaultLandingPage=apr_pstrdup(p,body);
		}
		return 1;
	}
	static oidc_provider_xml* amx_newOIDCProviderXml(pool* p){
		oidc_provider_xml* ret;
		ret=apr_pcalloc(p,sizeof(oidc_provider_xml));
		ret->id=NULL;
		ret->issuer=NULL;
		ret->metadataUrl=NULL;
		ret->isDefault=FALSE;
		return ret;
	}

	static int amx_newOIDCProvider(pool* p,char* xPath,int type,const char ** attributes,void* userdata){
		int i;
		actmap_tmp* ctmp=(actmap_tmp*)userdata;
		oidc_config_xml* amx=(oidc_config_xml*)ctmp->conf;
		oidc_provider_xml* oidcProviderX=(oidc_provider_xml*)amx_newOIDCProviderXml(p);
		for(i=0;attributes[i]; i += 2) {
			if(strcmp(attributes[i],"id")==0){
				oidcProviderX->id=apr_pstrdup(p,(char*)attributes[i + 1]);
			}else if(strcmp(attributes[i],"issuer")==0){
				oidcProviderX->issuer=apr_pstrdup(p,(char*)attributes[i + 1]);
			}else if(strcmp(attributes[i],"isDefault")==0){
				oidcProviderX->isDefault=STRTOBOOL(attributes[i + 1]);
			}
		}

		ctmp->tmp15=oidcProviderX;
		return 1;
	}

	static int amx_addOIDCProvider(pool* p,char* xPath,int type,void* userdata){
		oidc_config_xml* amx=NULL;
		oidc_provider_xml* oidcProviderX=NULL, **position;
			actmap_tmp* ctmp=(actmap_tmp*)userdata;
			amx=(oidc_config_xml*)ctmp->conf;

			if(amx!=NULL&&ctmp->tmp15!=NULL){
				oidcProviderX=(oidc_provider_xml*)ctmp->tmp15;
				position=(oidc_provider_xml**)apr_array_push(amx->oidcProviders);
				*position=oidcProviderX;
			}
			ctmp->tmp15=NULL;
			return 1;
	}

	static int amx_setOIDCProviderMetadataUrl(pool* p,char* xPath,int type,const char *body,void* userdata){
		actmap_tmp* ctmp=(actmap_tmp*)userdata;
		oidc_provider_xml* oidcProviderX=(oidc_provider_xml*)ctmp->tmp15;
		if(oidcProviderX!=NULL) {
			oidcProviderX->metadataUrl=apr_pstrdup(p,body);
		}
		return 1;
	}
	static int amx_setOIDCProviderIssuer(pool* p,char* xPath,int type,const char *body,void* userdata){
		actmap_tmp* ctmp=(actmap_tmp*)userdata;
		oidc_provider_xml* oidcProviderX=(oidc_provider_xml*)ctmp->tmp15;
		if(oidcProviderX!=NULL) {
			oidcProviderX->issuer=apr_pstrdup(p,body);
		}
		return 1;
	}
	static int amx_setOIDCProviderAuthorizationEndpoint(pool* p,char* xPath,int type,const char *body,void* userdata){
		actmap_tmp* ctmp=(actmap_tmp*)userdata;
		oidc_provider_xml* oidcProviderX=(oidc_provider_xml*)ctmp->tmp15;
		if(oidcProviderX!=NULL) {
			oidcProviderX->authorizationEndpoint=apr_pstrdup(p,body);
		}
		return 1;
	}
	static int amx_setOIDCProviderTokenEndpoint(pool* p,char* xPath,int type,const char *body,void* userdata){
		actmap_tmp* ctmp=(actmap_tmp*)userdata;
		oidc_provider_xml* oidcProviderX=(oidc_provider_xml*)ctmp->tmp15;
		if(oidcProviderX!=NULL) {
			oidcProviderX->tokenEndpoint=apr_pstrdup(p,body);
		}
		return 1;
	}
	static int amx_setOIDCProviderJwksUri(pool* p,char* xPath,int type,const char *body,void* userdata){
		actmap_tmp* ctmp=(actmap_tmp*)userdata;
		oidc_provider_xml* oidcProviderX=(oidc_provider_xml*)ctmp->tmp15;
		if(oidcProviderX!=NULL) {
			oidcProviderX->jwksUri=apr_pstrdup(p,body);
		}
		return 1;
	}

	static int amx_setOIDCProviderJwksJson(pool* p,char* xPath,int type,const char *body,void* userdata){
		actmap_tmp* ctmp=(actmap_tmp*)userdata;
		oidc_provider_xml* oidcProviderX=(oidc_provider_xml*)ctmp->tmp15;
		if(oidcProviderX!=NULL) {
			oidcProviderX->jwksJson=apr_pstrdup(p,body);
		}
		return 1;
	}

	char* amx_loadConfFile(pool* p, char* file, oidc_config_xml* conf){
		XmlCore* xCore;
		actmap_tmp tmp;
		char* result=NULL;
		
		tmp.conf=conf;
		tmp.tmp=NULL;
		tmp.tmp2=NULL;
		tmp.tmp3=NULL;
		tmp.tmp4=NULL;
		tmp.tmp5=NULL;
		tmp.tmp6=NULL;
		tmp.tmp7=NULL;
		tmp.tmp8=NULL;
		tmp.tmp9=NULL;
		tmp.tmp10=NULL;
		tmp.tmp11=NULL;
		tmp.tmp12=NULL;
		tmp.tmp13=NULL;
		tmp.tmp14=NULL;
		tmp.tmp15=NULL;
		tmp.str=NULL;
		tmp.errorStr=NULL;
		
		xCore=xc_getXmlCore(p);
		
		xc_addXPathHandler(xCore,"/oidcConfig",0,amx_oidcConfigAttributes,NULL,NULL, &tmp);
		
		//page action stuff
		xc_addXPathHandler(xCore,"/oidcConfig/oidcActions/action",0,amx_newPageAction,NULL,amx_addPageAction, &tmp);
		xc_addXPathHandler(xCore,"/oidcConfig/oidcActions/action/id",0,NULL,amx_setPageActionId,NULL, &tmp);
		xc_addXPathHandler(xCore,"/oidcConfig/oidcActions/action/description",0,NULL,amx_setPageActionDescription,NULL, &tmp);
		xc_addXPathHandler(xCore,"/oidcConfig/oidcActions/action/isForward",0,NULL,amx_setPageActionIsForward,NULL, &tmp);
		xc_addXPathHandler(xCore,"/oidcConfig/oidcActions/action/isPermanent",0,NULL,amx_setPageActionIsPermanent,NULL, &tmp);
		xc_addXPathHandler(xCore,"/oidcConfig/oidcActions/action/advancedTemplate",0,NULL,amx_setPageActionAdvancedTemplate,NULL, &tmp);
		xc_addXPathHandler(xCore,"/oidcConfig/oidcActions/action/uri",0,NULL,amx_setPageActionUri,NULL, &tmp);
		xc_addXPathHandler(xCore,"/oidcConfig/oidcActions/action/regex",0,NULL,amx_setPageActionRegex,NULL, &tmp);
		xc_addXPathHandler(xCore,"/oidcConfig/oidcActions/action/handler",0,NULL,amx_setPageActionHandler,NULL, &tmp);
		xc_addXPathHandler(xCore,"/oidcConfig/oidcActions/action/requestHeaders/header",0,amx_newActionHeader,amx_setActionRequestHeader,NULL, &tmp);
		xc_addXPathHandler(xCore,"/oidcConfig/oidcActions/action/responseHeaders/header",0,amx_newActionHeader,amx_setActionResponseHeader,NULL, &tmp);
		xc_addXPathHandler(xCore,"/oidcConfig/oidcActions/action/response",0,amx_newPageActionResponse,amx_setPageActionResponseBody,amx_addPageActionResponse, &tmp);
		xc_addXPathHandler(xCore,"/oidcConfig/oidcActions/action/oidcProvider",0,NULL,amx_setPageActionOidcProvider,NULL, &tmp);
		xc_addXPathHandler(xCore,"/oidcConfig/oidcActions/action/relyingParty",0,NULL,amx_setPageActionRelyingParty,NULL, &tmp);
		xc_addXPathHandler(xCore,"/oidcConfig/oidcActions/action/base64UrlEncodeState",0,NULL,amx_setPageActionBase64UrlEncodeState,NULL, &tmp);
			
		//path mapping stuff
		xc_addXPathHandler(xCore,"/oidcConfig/locations/location",0,amx_newPathMapping,NULL,amx_addPathMapping, &tmp);
		xc_addXPathHandler(xCore,"/oidcConfig/locations/location/path",0,NULL,amx_setPath,NULL, &tmp);
		xc_addXPathHandler(xCore,"/oidcConfig/locations/location/oidcAction",0,amx_newPathMappingAction,amx_setPathMappingAction,amx_addPathMappingPostAuth, &tmp);
		xc_addXPathHandler(xCore,"/oidcConfig/locations/location/matchList",0,NULL,amx_addPathMappingMatchList,NULL, &tmp);
		
		//match list stuff
		xc_addXPathHandler(xCore,"/oidcConfig/matchLists/matchList",0,amx_newMatchList,NULL,amx_addMatchList, &tmp);
		xc_addXPathHandler(xCore,"/oidcConfig/matchLists/matchList/match",0,amx_newPathMappingMatch,NULL,amx_addPathMappingMatch, &tmp);
		xc_addXPathHandler(xCore,"/oidcConfig/matchLists/matchList/match/host",0,NULL,amx_setMatchHost,NULL, &tmp);
		xc_addXPathHandler(xCore,"/oidcConfig/matchLists/matchList/match/ip",0,amx_newMatchListMatchIp,amx_setPathMappingMatchIp,NULL, &tmp);
		xc_addXPathHandler(xCore,"/oidcConfig/matchLists/matchList/match/path",0,amx_newMatchListMatchPath,amx_setPathMappingMatchPath,NULL, &tmp);
		xc_addXPathHandler(xCore,"/oidcConfig/matchLists/matchList/match/header",0,amx_newPathMappingMatchHeader,amx_setPathMappingMatchHeader,NULL, &tmp);
		xc_addXPathHandler(xCore,"/oidcConfig/matchLists/matchList/match/event",0,amx_newPathMappingMatchEvent,NULL,NULL, &tmp);
				
		xc_addXPathHandler(xCore,"/oidcConfig/rpSession",0,cc_setACCSessionCookieAttributes,NULL,NULL, &tmp);
		xc_addXPathHandler(xCore,"/oidcConfig/oidcSession",0,cc_setACCPermCookieAttributes,NULL,NULL, &tmp);
		xc_addXPathHandler(xCore,"/oidcConfig/accessToken",0,cc_setACCAccessTokenCookieAttributes,NULL,NULL, &tmp);

		xc_addXPathHandler(xCore,"/oidcConfig/relyingParties",0,amx_defaultRelyingParty,NULL,NULL, &tmp);
		xc_addXPathHandler(xCore,"/oidcConfig/relyingParties/relyingParty",0,amx_newRelyingParty,NULL,amx_addRelyingParty, &tmp);
		xc_addXPathHandler(xCore,"/oidcConfig/relyingParties/relyingParty/clientID",0,NULL,amx_setRelyingPartyClientID,NULL, &tmp);
		xc_addXPathHandler(xCore,"/oidcConfig/relyingParties/relyingParty/description",0,NULL,amx_setRelyingPartyDescription,NULL, &tmp);
		xc_addXPathHandler(xCore,"/oidcConfig/relyingParties/relyingParty/clientSecret",0,NULL,amx_setRelyingPartyClientSecret,NULL, &tmp);
		xc_addXPathHandler(xCore,"/oidcConfig/relyingParties/relyingParty/issuer",0,NULL,amx_setRelyingPartyIssuer,NULL, &tmp);
		xc_addXPathHandler(xCore,"/oidcConfig/relyingParties/relyingParty/validateNonce",0,NULL,amx_setRelyingPartyValidateNonce,NULL, &tmp);
		xc_addXPathHandler(xCore,"/oidcConfig/relyingParties/relyingParty/redirectUri",0,NULL,amx_setRelyingPartyRedirectUri,NULL, &tmp);
		xc_addXPathHandler(xCore,"/oidcConfig/relyingParties/relyingParty/postLoginDefaultLandingPage",0,NULL,amx_setRelyingPartyPostLoginDefaultLandingPage,NULL, &tmp);

		xc_addXPathHandler(xCore,"/oidcConfig/oidcProviders/oidcProvider",0,amx_newOIDCProvider,NULL,amx_addOIDCProvider, &tmp);
		xc_addXPathHandler(xCore,"/oidcConfig/oidcProviders/oidcProvider/metadataUrl",0,NULL,amx_setOIDCProviderMetadataUrl,NULL, &tmp);
		xc_addXPathHandler(xCore,"/oidcConfig/oidcProviders/oidcProvider/issuer",0,NULL,amx_setOIDCProviderIssuer,NULL, &tmp);
		xc_addXPathHandler(xCore,"/oidcConfig/oidcProviders/oidcProvider/authorizationEndpoint",0,NULL,amx_setOIDCProviderAuthorizationEndpoint,NULL, &tmp);
		xc_addXPathHandler(xCore,"/oidcConfig/oidcProviders/oidcProvider/tokenEndpoint",0,NULL,amx_setOIDCProviderTokenEndpoint,NULL, &tmp);
		xc_addXPathHandler(xCore,"/oidcConfig/oidcProviders/oidcProvider/jwksUri",0,NULL,amx_setOIDCProviderJwksUri,NULL, &tmp);
		xc_addXPathHandler(xCore,"/oidcConfig/oidcProviders/oidcProvider/jwksJson",0,NULL,amx_setOIDCProviderJwksJson,NULL, &tmp);

		result=xc_beginParsingTextResponse(xCore,file);
		return result;
	}



<|start_filename|>src/apache-utils/apache_typedefs.h<|end_filename|>
/*
 *  Created by <NAME> on 01/04/14.
 *
 */
#ifndef __TCREWRITE_APACHE_TYPEDEFS__H_
#define __TCREWRITE_APACHE_TYPEDEFS__H_
 
#include <apr_network_io.h>
#include <apr_strings.h>
#include <apr_tables.h>
#include <apr_hash.h>
#include <apache_macros.h>
#include <apr_general.h>
#include <apr_pools.h>
#include <apr_uri.h>

	typedef struct apr_pool_t pool;
	typedef struct apr_pool_t ap_pool;
	typedef struct apr_array_header_t array_header;
	typedef apr_uri_t uri_components;
	typedef struct apr_table_t table;
 
#endif


<|start_filename|>src/oidc-core/oidc_core_constants.h<|end_filename|>
#ifndef ACTION_MAPPINGS_CONSTANTS_H_
#define ACTION_MAPPINGS_CONSTANTS_H_

typedef enum {
    header_add = 'a',              /* add header (could mean multiple hdrs) */
    header_set = 's',              /* set (replace old value) */
    header_append = 'm',           /* append (merge into any old value) */
    header_merge = 'g',            /* merge (merge, but avoid duplicates) */
    header_unset = 'u',            /* unset header */
    header_echo = 'e',             /* echo headers from request to response */
    header_edit = 'r'              /* change value by regexp */
} header_actions;

typedef enum {
    action_login = 'l',              /* login action */
    action_denial = 'd',              /* denial action*/
    action_authorize = 'a',           /*  authorize action */
    action_callback = 'c'            /* callback action */
} action_types;


// token encryption/decryption buffer size
#define OAUTH_CRYPTO_BUFSIZE				1024
#define OAUTH_BASE64_BUFSIZE				4096

// delimiters and wildcard
#define OAUTH_TOKEN_DELIM      			":"
#define OAUTH_TOKEN_WILDCARD			"*"

// versions
#define OAUTH_AUTHORIZED_CODE_VERSION1 	"V1"
#define OAUTH_ACCESS_TOKEN_VERSION1   	"V1"
#define OAUTH_REFRESH_TOKEN_VERSION1   	"V1"
#define OAUTH_USER_TOKEN_VERSION1   	"V1"
#define OAUTH_PAGE_TOKEN_VERSION1   	"V1"

// response types
#define OAUTH_TYPE_UNKNOWN					0
#define OAUTH_TYPE_AUTHORIZE_CODE			1
#define OAUTH_TYPE_ACCESS_TOKEN				2
#define OAUTH_TYPE_AUTHENTICATE_CODE		3
#define OAUTH_TYPE_ID_TOKEN					4
#define OAUTH_TYPE_CODE_AND_ID_TOKEN		5

// subject types
#define OAUTH_SUBJECT_TYPE_UNKNOWN			0
#define OAUTH_SUBJECT_TYPE_UUID				1
#define OAUTH_SUBJECT_TYPE_APP				2

// response types
#define OAUTH_GRANT_TYPE_UNKNOWN				0
#define OAUTH_GRANT_TYPE_AUTHORIZE_CODE			1
#define OAUTH_GRANT_TYPE_PASSWORD				2
#define OAUTH_GRANT_TYPE_JWT					3
#define OAUTH_GRANT_TYPE_REFRESH_TOKEN			4
#define OAUTH_GRANT_TYPE_CLIENT_CREDENTIALS		5
#define OAUTH_GRANT_TYPE_PWD_WITH_CLIENT_CREDENTIALS		6
#define OAUTH_GRANT_TYPE_UUID_WITH_CLIENT_CREDENTIALS		7

// versions
#define OAUTH_TCS_RESPONSE_SUCCESS			 	0
#define OAUTH_TCS_RESPONSE_FAILURE   			1

#define OAUTH_LIS_RESPONSE_SUCCESS			 	0
#define OAUTH_LIS_RESPONSE_FAILURE   			1
#define OAUTH_LIS_RESPONSE_UNAVILABLE   		2

#define OAUTH_AUTHID_SUCCESS					0
#define OAUTH_AUTHID_FAILURE   					1

// OIDC headers
#define OIDC_STATUS_HEADER				"VALIDATE-STATUS"
#define OIDC_DESC_HEADER				"VALIDATE-DESCRIPTION"
#define OIDC_ISSUER_HEADER				"ISSUER"
#define OIDC_AUDIENCE_HEADER			"AUDIENCE"
#define OIDC_SUBJECT_HEADER			"SUBJECT"
#define OIDC_ROLES_HEADER				"ROLES"

#define OIDC_RP_SESSIONID					"X-RP-SESSION"

#endif /*ACTION_MAPPINGS_CONSTANTS_H_*/


<|start_filename|>src/xml-core/token_utils.h<|end_filename|>
/*
 *  Created by <NAME> on 01/04/14.
 *
 */
#ifndef __TCREWRITE_TOKEN_UTILS__H_
#define __TCREWRITE_TOKEN_UTILS__H_

#include "apache_typedefs.h"

typedef struct {
	char*	text;
	char*	delim;
	int	delim_len;
	size_t	offset;
	pool* p;
} Tokener;


Tokener* tu_getTokenizer (pool* p, char* text, char* delim);
char *tu_next_token(Tokener* tok);
char *tu_remaining_text (Tokener* tok);

#endif


<|start_filename|>src/config-core/config_bindings.h<|end_filename|>
#ifndef __TCREWRITE_CONFIG_BINDINGS__H_
#define __TCREWRITE_CONFIG_BINDINGS__H_

#include <sys/types.h>
#include "apache_typedefs.h"

	typedef struct cfg_service_descriptor{
		char* id;
		char* name;
		char* uri;
		char* userColonPass;
		long timeoutSeconds;
		apr_hash_t * params;
	}cfg_service_descriptor;

	// old version of cfg_globals (pool version).
	typedef struct cfg_globals{
		char* homeDir;
		char* logsDir;
		cfg_service_descriptor* resourceService;
	}cfg_globals;
	
	cfg_service_descriptor* cb_newServiceDescriptorObj(pool* p);
	cfg_globals* cb_newGlobalsObj(pool* p);
	char* cb_initGlobals(pool* p,cfg_globals* globals);
	char* cb_writeRemoteResourceToDisk(pool* p, char* homeDir, char* reqUri, char* resource, 
			long timeoutSeconds, char* userColonPass, apr_pool_t* tp, char**details, int* responseCode);
	int cb_canAutoRefreshNow(pool* p, cfg_service_descriptor* resourceService, time_t lastRefreshTimestamp, time_t currentTimestamp, char* namespace,char**error);
#endif



<|start_filename|>src/oidc-core/oidc_config_core.h<|end_filename|>
#ifndef __TCREWRITE_ACTION_MAPPINGS_CORE__H_
#define __TCREWRITE_ACTION_MAPPINGS_CORE__H_
#include "apache_typedefs.h"
#include "config_bindings_shm.h"
	char* amc_initialize(pool* p,shared_heap* sheap,cbs_globals* globals,cfg_service_descriptor* svcdesc,void** userdata);
	char* amc_refresh(pool* p,shared_heap* sheap,cbs_globals* globals,cfg_service_descriptor* svcdesc,void** userdata);
	char* amc_postRefresh(pool* p,shared_heap* sheap,cfg_globals* globals,cfg_service_descriptor* svcdesc,void** userdata);
#endif


<|start_filename|>src/apache-utils/apache_macros.h<|end_filename|>
/*
 *  Created by <NAME> on 01/04/14.
 *
 */
#ifndef __TCREWRITE_APACHE_MACROS__H_
#define __TCREWRITE_APACHE_MACROS__H_

#define SAFESTR(str) (str!=NULL?str:"NULL")
#define SAFESTRBLANK(str) (str!=NULL?str:"") 
#define SAFESTRELSE(str,elstr) (str!=NULL?str:elstr) 
#define SAFESTRLEN(str) (str!=NULL?strlen(str):0)
#define BOOLTOSTR(bol) (bol!=1?"FALSE":"TRUE")
#define STRTOBOOL(str) ((str!=NULL&&(strcmp(str,"true")==0||strcmp(str,"TRUE")==0||strcmp(str,"on")==0))?1:0)
#define SAFEDUP(p,str) (str==NULL?NULL:apr_pstrdup(p,str))

#define str(s) #s
#define PIDWRAP(msg) "INFO: ID>%d< " msg "" , getpid ()
#define PIDWRAPC(msg) "CRITICAL: ID>%d< " msg "" , getpid ()

#define APACHE_LOG_DEBUG(msg)
#define APACHE_LOG_DEBUG1(msg, arg1)
#define APACHE_FREE_CHAR_ARRAY(arr)
#define AP_LOG_CRITICAL1(req,msg,arg){ap_log_error(APLOG_MARK, APLOG_CRIT,APR_SUCCESS, req->server, PIDWRAPC(msg),arg);}
#define AP_LOG_ERROR(req,msg){ap_log_error(APLOG_MARK, APLOG_INFO,APR_SUCCESS,req->server, PIDWRAP(msg));}
#define AP_LOG_ERROR1(req,msg,arg){ap_log_error(APLOG_MARK, APLOG_INFO,APR_SUCCESS,req->server, PIDWRAP(msg),arg);}
#define AP_LOG_ERROR2(req,msg,arg,arg1){ap_log_error(APLOG_MARK, APLOG_INFO,APR_SUCCESS,req->server,PIDWRAP(msg),arg,arg1);}
#define AP_LOG_ERROR3(req,msg,arg,arg1,arg2){ap_log_error(APLOG_MARK, APLOG_INFO,APR_SUCCESS,req->server,PIDWRAP(msg),arg,arg1,arg2);}

#define AP_RPRINTF(req,arg1){ap_rprintf(req,arg1);}
#define AP_RPRINTF1(req,tem,arg1){ap_rprintf(req,tem,arg1);}
#define AP_RPRINTF2(req,tem,arg1,arg2){ap_rprintf(req,tem,arg1,arg2);}
#define AP_RPRINTF3(req,tem,arg1,arg2,arg3){ap_rprintf(req,tem,arg1,arg2,arg3);}
#define AP_RPRINTF4(req,tem,arg1,arg2,arg3,arg4){ap_rprintf(req,tem,arg1,arg2,arg3,arg4);}
#define AP_RPRINTF5(req,tem,arg1,arg2,arg3,arg4,arg5){ap_rprintf(req,tem,arg1,arg2,arg3,arg4,arg5);}
 
#endif


<|start_filename|>src/template-core/template_handler_url.h<|end_filename|>
#ifndef TOKEN_TEMPLATE_URL_H_
#define TOKEN_TEMPLATE_URL_H_
#include "apache_typedefs.h"

	char* temphand_url_encodeToken(pool* p,void* config,char* src);
	char* temphand_url_decodeToken(pool* p,void* config,char* src);

	// base64 encode decode
	char* temphand_base64_encodeToken(pool* p,void* config,char* src);
	char* temphand_base64_decodeToken(pool* p,void* config,char* src);
	
#endif /*TOKEN_TEMPLATE_ENCRYPTION_H_*/


<|start_filename|>src/oidc-core/oidc_config_core.c<|end_filename|>
#include "oidc_config.h"
#include "oidc_config_core.h"
#define PARAM_CONFIG_XML	"config-xml"
#define PARAM_IS_REFRESH	"initialized"
	char* amc_initialize(pool* p,shared_heap* sheap,cbs_globals* globals,cfg_service_descriptor* svcdesc,void** userdata){
		char* result=NULL;
		char* error=NULL;
		char* isRefresh=NULL;
		char* configFile=NULL;
		char* param_configFile=(char*)apr_hash_get(svcdesc->params,PARAM_CONFIG_XML,APR_HASH_KEY_STRING);
		if(param_configFile==NULL){
			return apr_pstrcat(p,"Missing service param:",PARAM_CONFIG_XML,NULL);
		}
		//get Latest Action Mappings Resource
		configFile=cbs_getRemoteResourcePath(p,globals,param_configFile,&error);
		if(configFile==NULL){
			configFile=cbs_getLocalResourcePath(p, globals,param_configFile,NULL);
		}
		
		result=am_build(p,sheap,(apr_hash_get(svcdesc->params,PARAM_IS_REFRESH,APR_HASH_KEY_STRING)!=NULL),globals,configFile);
		if(result!=NULL){
			return apr_pstrcat(p,"Problem loading action-mappings : ",result,NULL);
		}		
		
		apr_hash_set(svcdesc->params,PARAM_IS_REFRESH,APR_HASH_KEY_STRING,apr_pstrdup(p,"TRUE"));
		return NULL;
	}
	char* amc_refresh(pool* p,shared_heap* sheap,cbs_globals* globals,cfg_service_descriptor* svcdesc,void** userdata){
			return amc_initialize(p,sheap,globals,svcdesc,userdata);
	}
	
	char* amc_postRefresh(pool* p,shared_heap* sheap, cfg_globals* globals,cfg_service_descriptor* svcdesc,void** userdata){
		oidc_config* mappings=NULL;
		mappings=am_fetchFromSheap(sheap);
		if(mappings==NULL){
			return apr_pstrdup(p,"Action Mappings unable to be retrieved from sheap");
		}
		*userdata=mappings;
		return NULL;	
	}




<|start_filename|>src/shm_core/shm_dup.c<|end_filename|>

#include <string.h>
#include <shm_dup.h>
#include <math.h>


int shdup_32BitString_size(char* str){
	int tmp, mod;
	if(str==NULL) return 0;
	
	tmp=strlen(str)+1;
	mod=tmp%4;

	if(mod>0){
		tmp=tmp-mod+4;
	}
return tmp;
}
int shdup_arrayheader_size(array_header* arr){
        int sz=0;
        sz+=sizeof(array_header);
        sz+=arr->elt_size*arr->nelts;
return sz;
}
/**
 * Copies str to icharbuf and returns the beginning of the new string. icharbuf is updated rollingly
 */
char* shdup_32BitString_copy(char** icharbuf, char* str){
	int slen;
	char* buf;
	
	if(str==NULL){
		return NULL;
	}
	
	buf=*icharbuf;

	slen=shdup_32BitString_size(str);	
        memset(buf,'\0',(int)slen);
        memcpy(buf,str, strlen(str));

	*icharbuf+=(int)slen;	
	
return buf;
}



<|start_filename|>src/apache-utils/apache_mappings.h<|end_filename|>
/*
 *  Created by <NAME> on 01/04/14.
 *
 */
#ifndef __TCREWRITE_APACHE_MAPPINGS__H_
#define __TCREWRITE_APACHE_MAPPINGS__H_

#ifdef NGX_HTTP_OPENIDC
	#include <ngx_config.h>
	#include <ngx_core.h>
	#include <ngx_http.h>
	#include <nginx.h>
#else
	#include "httpd.h"
	#include "http_config.h"
	#include "http_log.h"
	#include "ap_compat.h"
#endif

#endif


<|start_filename|>src/config-core/config_messaging.c<|end_filename|>
#include <unistd.h>
#include <sys/time.h>
#include <string.h>
#include <stdlib.h>
#include <common_utils.h>
#include <config-core/config_messaging.h>
#include <config-core/config_core.h>
#include <config-core/config_messaging_parsing.h>
#include <log-utils/logging.h>
#include <http-utils/http_client.h>
#include "xml_core.h"

#ifdef NGX_HTTP_OPENIDC
#else // APACHE
	#include <ap_mpm.h>
#endif

	cfgm_connection* cfgm_newConnectionObj(pool* p){
			cfgm_connection* ret=(cfgm_connection*)apr_palloc(p,sizeof(cfgm_connection));
			ret->wireHeader=cfgm_newWireHeader(p);
			return ret;
	}

	static char* cfgm_getMessageType(cfgm_wire_message* msg){
		if(msg!=NULL){
			return msg->type;
		}
		return NULL;
	}
	
	static char* cfgm_getMessageNodeName(cfgm_wire_message* msg){
		if(msg!=NULL&&msg->header!=NULL){
			return msg->header->nodeName;
		}
		return NULL;
	}
	int cfgm_isRefreshMessage(cfgm_wire_message* msg){
		return (msg!=NULL&&(strcmp(msg->type,"AUTO-REFRESH")==0));
	}
	
	static cfgm_wire_message* cfgm_generateAutoRefreshMessage(pool* p){
		cfgm_wire_header* wireHeader=cfgm_newWireHeader(p);
		cfgm_wire_message* msg=cfgm_newWireMessageType(p,"AUTO-REFRESH",wireHeader);
		return msg;
	}
	
	typedef struct next_refresh_info{
		time_t nextRefreshTimestamp;
	}next_refresh_info;

	static int cfgm_setRefreshTimestampAttribute(pool* p,char* xPath,int type,const char ** attributes,void* userdata){
		int i;
		next_refresh_info* refreshInfo=(next_refresh_info*)userdata;
		for(i=0;attributes[i]; i += 2) {
			if(strcmp(attributes[i],"nextRefreshTime")==0){
				refreshInfo->nextRefreshTimestamp=cu_dateStringToSeconds((char*)attributes[i + 1]);
			}
		}
		return 1;
	}

	static int cfgm_canAutoRefreshNow(pool* p, cfg_service_descriptor* resourceService, char*oidcConfigFile, const time_t lastRefreshTimestamp, mm_logger* logger){
		http_util_result* httpResult=NULL;
		char* reqQuery=NULL;
		char* error = NULL;
		time_t currentTimestamp;
		XmlCore* xCore=NULL;
		char* result=NULL;
		
		if(resourceService==NULL) return FALSE;
		
		currentTimestamp = time(NULL);
		
		reqQuery=apr_pstrcat(p,resourceService->uri,"/",oidcConfigFile, NULL);
		httpResult=hc_get_verbose2(p,reqQuery,resourceService->timeoutSeconds,5,resourceService->userColonPass,NULL,&error);
		
		if(httpResult==NULL||httpResult->data==NULL||!hc_is200_OK(httpResult)) {
			logging_log(logger,"Refresh httpResult Error: %s", (error!=NULL) ? error : "unknown");
			return FALSE;
		}
		
		next_refresh_info refreshInfo;
		refreshInfo.nextRefreshTimestamp = -1;

		xCore=xc_getXmlCore(p);
		xc_addXPathHandler(xCore,"/oidcConfig",0,cfgm_setRefreshTimestampAttribute,NULL,NULL, &refreshInfo);
		result=xc_parseFromStringSourceTextResponse(xCore, httpResult->data);
		if(result!=NULL) {
			logging_log(logger,"Refresh error : %s", result);
			return FALSE;
		}

		if(refreshInfo.nextRefreshTimestamp<0) {
			logging_log(logger,"Refresh nextRefresh not configued");
			return TRUE;
		}
		
		logging_log(logger,"Refresh lastRefreshTimestamp:%d, refreshTimestamp : %d, currentTimestamp:%d",lastRefreshTimestamp,refreshInfo.nextRefreshTimestamp, currentTimestamp);
		
		if( (lastRefreshTimestamp<refreshInfo.nextRefreshTimestamp) && (refreshInfo.nextRefreshTimestamp<=currentTimestamp)) return TRUE;

		logging_log(logger,"Refresh refreshTimestamp : %d is tool old or already processed", refreshInfo.nextRefreshTimestamp);
		return FALSE;
	}

	static void cfgm_internalMessagingLoop(pool* p, char* logsDir, void* localConfig, void* userdata,cfgm_message_recieved_func msgRecFunc){
		#define BUFSIZE 256 
		cfgm_connection* cmConn=cfgm_newConnectionObj(p);
		cfgm_wire_message* msg=NULL;
		char* error=NULL;
		apr_status_t rc;
		apr_time_t 	lastHello=0;
		char errorbuf[512];	
		int errorCode = 0,maxLogFileSizeMB=2;
		time_t lastAutoRefreshTimestamp = time(NULL); // startup time
		
		sprintf(errorbuf,"%s/monitor.log",logsDir);
		mm_logger* logger=logging_getLogger(p,errorbuf,maxLogFileSizeMB);

		cfg_service_descriptor* resourceService=((config_core*)userdata)->globals->resourceService;
		int refreshWaitSeconds = ((config_core*)userdata)->refreshWaitSeconds;
		char* oidcConfigFile=((config_core*)userdata)->oidcConfigFile;
		
		//start wait for message loop
		while(1){
			logging_log(logger,"AutoRefreshing...");
			if(cfgm_canAutoRefreshNow(p, resourceService, oidcConfigFile, lastAutoRefreshTimestamp, logger)){
				msg=cfgm_generateAutoRefreshMessage(p);
				if(msg!=NULL){
					logging_log(logger,"AutoRefresh processing message: %s (%s)",cfgm_getMessageType(msg),cfgm_getMessageNodeName(msg));
					//internal hello handling
					if(msgRecFunc!=NULL){
						(*msgRecFunc)(p,NULL,msg,localConfig,userdata);
					}
					logging_log(logger,"AutoRefresh complete");
					lastAutoRefreshTimestamp = time(NULL); // update with current timestamp;
				}
			}
			usleep(refreshWaitSeconds*1000*1000);
		}
	}
	
	typedef struct openidc_messaging_proc_rec{
		char* logDir;
		void* userdata;
		cfgm_init_messaging_func initFunc;
		cfgm_message_recieved_func msgRecFunc;
		apr_proc_t* proc;
	}openidc_messaging_proc_rec;
	
	static openidc_messaging_proc_rec*cfgm_newMessagingProcRecObj(pool* p, char* logDir,
		void* userdata,
		cfgm_init_messaging_func initFunc, cfgm_message_recieved_func msgRecFunc){
		openidc_messaging_proc_rec* mpr=(openidc_messaging_proc_rec*)apr_palloc(p,sizeof(openidc_messaging_proc_rec));
		mpr->logDir = logDir;
		mpr->userdata = userdata;
		mpr->initFunc = initFunc;
		mpr->msgRecFunc = msgRecFunc;
		mpr->proc = (apr_proc_t*)apr_palloc(p,sizeof(apr_proc_t));
		return mpr;
	}
	
	pool* root_mpr_pool = NULL;	// root process pool created by root process
	void cfgm_startMessagingProcess(openidc_messaging_proc_rec*msg,int disableProcessRecovery);

#if 0/*APR_HAS_OTHER_CHILD && !NGX_HTTP_OPENIDC*/
	static void cfgm_messageProcessRestartCallback(int reason, void *data, apr_wait_t status) {
		openidc_messaging_proc_rec* mpr = (openidc_messaging_proc_rec*)data;
		int mpm_state;
		int stopping;

		switch (reason) {
			case APR_OC_REASON_DEATH:
				apr_proc_other_child_unregister(data);
				/* If apache is not terminating or restarting,
				 * restart the message processer
				 */
				stopping = 1; 	/* if MPM doesn't support query,
	                           	 * assume we shouldn't restart message process
	                             */
				if (ap_mpm_query(AP_MPMQ_MPM_STATE, &mpm_state) == APR_SUCCESS &&
					mpm_state != AP_MPMQ_STOPPING) {
					stopping = 0;
				}
				if (!stopping) {
					ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "openidc refresh recieved APR_OC_REASON_DEATH, restarting");
					if(mpr!=NULL){
						cfgm_startMessagingProcess(mpr,FALSE);
					}
				}
				break;
              
			case APR_OC_REASON_RESTART:
				/* don't do anything; server is stopping or restarting */
				apr_proc_other_child_unregister(data);
				break;
               
			case APR_OC_REASON_LOST:
				/* Restart the child messaging processor as we lost it */
				apr_proc_other_child_unregister(data);
				ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "openidc refresh recieved APR_OC_REASON_LOST");
				cfgm_startMessagingProcess(mpr, FALSE);
              	break;
              
			case APR_OC_REASON_UNREGISTER:
				/* we get here when child message processor is cleaned up; it gets cleaned
				 * up when pconf gets cleaned up
				 */
				if(mpr!=NULL&&mpr->proc!=NULL){
					kill(mpr->proc->pid, SIGHUP); /* send signal to message processor to die */
				}
				break;
       }
   }
#endif

	void cfgm_startMessagingProcess(openidc_messaging_proc_rec*mpr, int disableProcessRecovery){
		apr_status_t rv;
		void* localConfig=NULL;
		if((rv=apr_proc_fork(mpr->proc,root_mpr_pool))==APR_INCHILD){
			if(mpr->initFunc!=NULL){
				localConfig=(*mpr->initFunc)(root_mpr_pool,mpr->userdata);
			}
			cfgm_internalMessagingLoop(root_mpr_pool,mpr->logDir, localConfig, mpr->userdata,mpr->msgRecFunc);
			exit(1);
		}else{
			apr_pool_note_subprocess (root_mpr_pool,mpr->proc,APR_KILL_AFTER_TIMEOUT);
			if ( !disableProcessRecovery ) {
			#if 0/*APR_HAS_OTHER_CHILD && !NGX_HTTP_OPENIDC*/
				apr_proc_other_child_register(mpr->proc, cfgm_messageProcessRestartCallback, mpr, NULL, root_mpr_pool);
			#endif
			}
		}
	}
	
	apr_proc_t* cfgm_initializeMessagingLoop(pool* p, char* logDir, void* messageBroker, void* userdata,
			cfgm_init_messaging_func initFunc, cfgm_message_recieved_func msgRecFunc,
			int disableProcessRecovery){
		root_mpr_pool = p;
		openidc_messaging_proc_rec* mpr = cfgm_newMessagingProcRecObj(root_mpr_pool, logDir, userdata, initFunc, msgRecFunc);
		cfgm_startMessagingProcess(mpr, disableProcessRecovery);
		return mpr->proc;	
	}
	


<|start_filename|>src/json-api-core/unit-test/json_api_core_unit_test.c<|end_filename|>
#include <stdlib.h>
#include <apr_general.h>
#include <apr_pools.h>
#include <stdio.h>
#include <assert.h>
#include "CuTest.h"
#include "json_parser.h"
#include "json_api.h"
#include "common_utils.h"

// Used by some code below as an example datatype.
struct record {const char *precision;double lat,lon;const char *address,*city,*state,*zip,*country; };

// Create a bunch of objects as demonstration.
void JSON_CreateObject_test(mm_logger* logger, CuTest*tc) {
	pool*p = logger->pool;

	Value *root,*fmt,*img,*thm,*fld;char *out;int i;        // declare a few.

	// Here we construct some JSON standards, from the JSON site.

	// Our "Video" datatype:
	root=JSON_CreateObject(p);
	JSON_AddItemToObject(p,root, "name", JSON_CreateString(p,"Jack (\"Bee\") Nimble"));
	JSON_AddItemToObject(p,root, "format", fmt=JSON_CreateObject(p));
	JSON_AddStringToObject(p,fmt,"type",             "rect");
	JSON_AddNumberToObject(p,fmt,"width",            1920);
	JSON_AddNumberToObject(p,fmt,"height",           1080);
	JSON_AddFalseToObject (p,fmt,"interlace");
	JSON_AddNumberToObject(p,fmt,"frame rate",       24);

	out=JSON_Serialize(p,root);

	CuAssertPtrNotNullMsg(tc,"Failed to serialize data from JSON_CreateObject_test", out);

}

// Create a bunch of objects as demonstration.
void JSON_CreateArray_test(mm_logger* logger, CuTest*tc) {
	pool*p = logger->pool;

	Value *root,*fmt,*img,*thm,*fld;char *out;int i;        // declare a few.

	// Our matrix:
	int numbers[3][3]={{0,-1,0},{1,0,0},{0,0,1}};
	root=JSON_CreateArray(p);
	for (i=0;i<3;i++) JSON_AddItemToArray(p,root,JSON_CreateIntArray(p,numbers[i],3));

	out=JSON_Serialize(p,root);

	CuAssertPtrNotNullMsg(tc,"Failed to serialize data from JSON_CreateArray_test", out);

}

// Create a bunch of objects as demonstration.
void JSON_CreateStringArray_test(mm_logger* logger, CuTest*tc) {
	pool*p = logger->pool;

	Value *root,*fmt,*img,*thm,*fld;char *out;int i;        // declare a few.

	// Our "days of the week" array:
	const char *strings[7]={"Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"};
	root=JSON_CreateStringArray(p,strings,7);

	out=JSON_Serialize(p,root);

	CuAssertPtrNotNullMsg(tc,"Failed to serialize data from JSON_CreateStringArray_test", out);

}

// Create a bunch of objects as demonstration.
void JSON_AddItemToObject_test(mm_logger* logger, CuTest*tc) {
	pool*p = logger->pool;

	Value *root,*fmt,*img,*thm,*fld;char *out;int i;        // declare a few.

	// Our "gallery" item:
	int ids[4]={116,943,234,38793};
	root=JSON_CreateObject(p);
	JSON_AddItemToObject(p,root, "Image", img=JSON_CreateObject(p));
	JSON_AddNumberToObject(p,img,"Width",800);
	JSON_AddNumberToObject(p,img,"Height",600);
	JSON_AddStringToObject(p,img,"Title","View from 15th Floor");
	JSON_AddItemToObject(p,img, "Thumbnail", thm=JSON_CreateObject(p));
	JSON_AddStringToObject(p,thm, "Url", "http://www.example.com/image/481989943");
	JSON_AddNumberToObject(p,thm,"Height",125);
	JSON_AddStringToObject(p,thm,"Width","100");
	JSON_AddItemToObject(p,img,"IDs", JSON_CreateIntArray(p,ids,4));

	out=JSON_Serialize(p,root);
	CuAssertPtrNotNullMsg(tc,"Failed to serialize data from JSON_AddItemToObject_test", out);
}


// Create a bunch of objects as demonstration.
void JSON_AddItemToArray_test(mm_logger* logger, CuTest*tc) {
	pool*p = logger->pool;

	Value *root,*fmt,*img,*thm,*fld;char *out;int i;        // declare a few.

	// Our array of "records":
	struct record fields[2]={
			{"zip",37.7668,-1.223959e+2,"","SAN FRANCISCO","CA","94107","US"},
			{"zip",37.371991,-1.22026e+2,"","SUNNYVALE","CA","94085","US"}};

	root=JSON_CreateArray(p);
	for (i=0;i<2;i++)
	{
			JSON_AddItemToArray(p,root,fld=JSON_CreateObject(p));
			JSON_AddStringToObject(p,fld, "precision", fields[i].precision);
			JSON_AddNumberToObject(p,fld, "Latitude", fields[i].lat);
			JSON_AddNumberToObject(p,fld, "Longitude", fields[i].lon);
			JSON_AddStringToObject(p,fld, "Address", fields[i].address);
			JSON_AddStringToObject(p,fld, "City", fields[i].city);
			JSON_AddStringToObject(p,fld, "State", fields[i].state);
			JSON_AddStringToObject(p,fld, "Zip", fields[i].zip);
			JSON_AddStringToObject(p,fld, "Country", fields[i].country);
	}

	out=JSON_Serialize(p,root);

	CuAssertPtrNotNullMsg(tc,"Failed to serialize data from JSON_AddItemToArray_test", out);

}

void jsonapi_deserializeJsonStringMap_test(mm_logger* logger, CuTest*tc) {
	pool*p = logger->pool;

    const char* requestBody = "{\"username\":\"testuser\",\"password\":\"<PASSWORD>\",\"savelogin\":\"true\",\"template\":\"default\", \"realm\":\"test\", \"url\":\"http%3A%2F%2Fonline.s.dev.wsj.com%2Fmyaccount\"}\r\n";

	apr_hash_t* params=jsonapi_deserializeJsonStringMap(p, requestBody);

	CuAssertPtrNotNullMsg(tc,"Unable to desrializeString map using jsonapi_deserializeJsonStringMap", params);

}

void jsonapi_getJsonIdentityFromParams_test(mm_logger* logger, CuTest*tc) {
	pool*p = logger->pool;

    const char* requestBody = "{\"username\":\"testuser\",\"password\":\"<PASSWORD>\",\"savelogin\":\"true\",\"template\":\"default\", \"realm\":\"test\", \"url\":\"http%3A%2F%2Fonline.s.dev.wsj.com%2Fmyaccount\"}\r\n";

	apr_hash_t* params=jsonapi_deserializeJsonStringMap(p, requestBody);

	CuAssertPtrNotNullMsg(tc,"Unable to desrializeString map using jsonapi_deserializeJsonStringMap", params);

	jsonIdentity* identity=jsonapi_getJsonIdentityFromParams(p, params);

	CuAssertPtrNotNullMsg(tc,"Unable to build json_identity in jsonapi_getJsonIdentityFromParams", params);

	//preconditions
	statusMessage* statusMsg=jsonapi_preconditionFailureStatus(p,identity);
	CuAssertPtrNotNullMsg(tc,"statusMsg is null", statusMsg);

	jsonapi_statusMessageAddEntry(p,statusMsg,"username","parameter","The user does not exist or password does not match.","invalid-credentials");
	int count = jsonapi_getStatusErrorCount(p,statusMsg->entries);
	CuAssertIntEquals(tc,1,count);

}

static jsonSession* jsonapiunittest_createMockJsonSession(pool*p){
	char *tmp;
	jsonSession* jsonSess=jsonapi_newJsonSessionObj(p);
	apr_hash_t* tokenMap=NULL;

	tokenMap=apr_hash_make(p);
	apr_hash_set(tokenMap,JSON_TOKEN_USER,APR_HASH_KEY_STRING,"dj_chandt");
	apr_hash_set(tokenMap,JSON_TOKEN_PASSWORD,APR_HASH_KEY_STRING,"<PASSWORD>");
	apr_hash_set(tokenMap,JSON_TOKEN_UUID,APR_HASH_KEY_STRING,"dj_chandt");
	apr_hash_set(tokenMap,JSON_TOKEN_TIMESTAMP,APR_HASH_KEY_STRING,apr_ltoa(p,time(NULL)));
	apr_hash_set(tokenMap,JSON_TOKEN_SAVE_LOGIN,APR_HASH_KEY_STRING,apr_pstrdup(p,"true"));
	apr_hash_set(tokenMap,JSON_TOKEN_REALM,APR_HASH_KEY_STRING,"default");
	apr_hash_set(tokenMap,JSON_TOKEN_TEMPLATE,APR_HASH_KEY_STRING,"default");
	jsonSess->token=astru_serializeStringMapEscapeQuote(p,tokenMap);

	jsonSess->profileMsg=jsonapi_newProfileMessageObj(p);

	tmp=apr_pstrdup(p,"success");
	jsonapi_profileMessageAddEntry(p,jsonSess->profileMsg, "result",tmp);

	tmp=SAFEDUP(p,"dj_chandt");
	jsonapi_profileMessageAddEntry(p,jsonSess->profileMsg, "username",tmp);

	tmp=SAFEDUP(p,"dj_chandt");
	jsonapi_profileMessageAddEntry(p,jsonSess->profileMsg, "uuid", tmp);

	return jsonSess;
}

void jsonapi_profileMessageToJson_test(mm_logger* logger, CuTest*tc) {
	pool*p = logger->pool;

	jsonSession* jsonSess = jsonapiunittest_createMockJsonSession(p);

	CuAssertPtrNotNullMsg(tc,"jsonSess is null", jsonSess);

	char* responseBody=jsonapi_profileMessageToJson(p, jsonSess->profileMsg);

	CuAssertPtrNotNullMsg(tc,"statusMsg is null", responseBody);

}

void jsonapi_statusMessageToJson_test(mm_logger* logger, CuTest*tc) {
	pool*p = logger->pool;

    const char* requestBody = "{\"username_missing\":\"testuser\",\"password_missing\":\"<PASSWORD>\",\"savelogin\":\"true\",\"template_missing\":\"default\", \"realm_missing\":\"test\", \"url_missing\":\"http%3A%2F%2Fonline.s.dev.wsj.com%2Fmyaccount\"}\r\n";

	apr_hash_t* params=jsonapi_deserializeJsonStringMap(p, requestBody);

	CuAssertPtrNotNullMsg(tc,"Unable to desrializeString map in jsonapi_statusMessageToJson_test", params);

	jsonIdentity* identity=jsonapi_getJsonIdentityFromParams(p, params);

	//preconditions
	statusMessage* statusMsg=jsonapi_preconditionFailureStatus(p,identity);
	CuAssertPtrNotNullMsg(tc,"statusMsg is null", statusMsg);

	char* responseBody=jsonapi_statusMessageToJson(p, statusMsg);

	CuAssertPtrNotNullMsg(tc,"statusMsg is null", responseBody);

}

CuSuite* jsonapi_GetSuite() {
  CuSuite* suite = CuSuiteNew();
  SUITE_ADD_TEST(suite, JSON_CreateObject_test);
  SUITE_ADD_TEST(suite, JSON_CreateArray_test);
  SUITE_ADD_TEST(suite, JSON_CreateStringArray_test);
  SUITE_ADD_TEST(suite, JSON_AddItemToObject_test);
  SUITE_ADD_TEST(suite, JSON_AddItemToArray_test);
  SUITE_ADD_TEST(suite, jsonapi_deserializeJsonStringMap_test);
  SUITE_ADD_TEST(suite, jsonapi_getJsonIdentityFromParams_test);
  SUITE_ADD_TEST(suite, jsonapi_profileMessageToJson_test);
  SUITE_ADD_TEST(suite, jsonapi_statusMessageToJson_test);

return suite;
}


<|start_filename|>src/oidc-globals/oidc_globals.h<|end_filename|>
#ifndef __TCREWRITE_GLOBALS__H_
#define __TCREWRITE_GLOBALS__H_

	//Exposed functions for the Enable unnamed shared memory flag.
	void djrglobals_setEnableUnnamedSHM(const char * arg);
	int djrglobals_isUnnamedSHMEnabled();

	//Exposed functions to set/get config check phase delay seconds.
	void djrglobals_setConfigCheckPhaseDelaySec(const char * arg);
	int djrglobals_getConfigCheckPhaseDelaySec();

#endif


<|start_filename|>src/common-utils/cookie.c<|end_filename|>
#ifndef _COOKIE_C_
#define _COOKIE_C_

#include "cookie.h"
#include "url_utils.h"

//Creater methods
Cookie* cookie_newObj(pool*p){
	Cookie* ret=(Cookie*)apr_pcalloc(p,sizeof(Cookie));
	ret->name=NULL;
	ret->nameLen=0;
	ret->age=-1;
	ret->httpOnly=FALSE;
	ret->secure=FALSE;
	return ret;
}

Cookie* cookie_createCookieByName(pool*p, char*name) {
		Cookie* cookie = NULL;
		if(name){
			cookie = cookie_newObj(p);
			cookie->name= apr_pstrdup(p, name);
			cookie->nameLen=strlen(cookie->name);
		}
		return cookie;
}

Cookie* cookie_cookieDup(pool*p, Cookie*src){
	Cookie* ret=NULL;
	if(src){
		ret = cookie_newObj(p);
		ret->name=apr_pstrdup(p, src->name);
		ret->nameLen=src->nameLen;
		ret->age=src->age;
		ret->httpOnly=src->httpOnly;
		ret->secure=src->secure;
	}
	return ret;
}

//Accessor Methods
void cookie_setCookieName(pool*p, Cookie*cookie, char*name) {
	if(cookie && name){
		cookie->name= apr_pstrdup(p, name);
		cookie->nameLen=strlen(cookie->name);
	}
}

char* cookie_getCookieName(Cookie*cookie) {
	return cookie->name;
}

void cookie_setCookieLifeTime(Cookie* cookie, int lifeTime){
	cookie->age = lifeTime;
}

int cookie_getCookieLifeTime(Cookie* cookie){
	return cookie->age;
}

void cookie_setCookieHttpOnlyflag(Cookie* cookie, unsigned int httpOnly){
	cookie->httpOnly = httpOnly;
}

void cookie_setCookieSecureHttpOnlyflag(Cookie* cookie, int secure){
	cookie->secure = secure;
}

unsigned int cookie_getCookieHttpOnlyflag(Cookie* cookie){
	return cookie->httpOnly;
}

//Cookie sheap methods
Cookie* cookie_newShmObj(shared_heap*sheap){
        Cookie* ret=(Cookie*)shdata_shpalloc(sheap,sizeof(Cookie));
        ret->name=NULL;
        ret->nameLen=0;
        ret->age=-1;
        ret->httpOnly=FALSE;
        ret->secure=FALSE;
        return ret;
}

Cookie* cookie_cookieShmDup(shared_heap*sheap, Cookie*src){
	Cookie* ret=NULL;
	if(src) {
		ret = cookie_newShmObj(sheap);
		ret->name=shdata_32BitString_copy(sheap,src->name);
		ret->nameLen=src->nameLen;
		ret->age=src->age;
		ret->httpOnly=src->httpOnly;
		ret->secure=src->secure;
	}
	return ret;
}

//Cookie utility methods
char* cookie_cookieTemplateByName(pool* p,char* icookiename, char *ivalue, 
		char *idomain, long maxAge, unsigned int httpOnly) {
		char* ret=NULL;
		char* value=SAFESTRBLANK(ivalue),*domain=SAFESTRBLANK(idomain),*cookiename=SAFESTRBLANK(icookiename);
		int sz=0,ulen=0;
		char* encoded_url=NULL;
		
		sz=strlen(domain)+strlen(cookiename)+64;
		ulen=strlen(value)*3+1;
		
		encoded_url=apr_pcalloc(p,ulen);
		url_encode(value, encoded_url, ulen);
		sz+=strlen(encoded_url);
		
		ret=apr_pcalloc(p,sz);
		if (maxAge < 0) {
			sprintf(ret,
			"%s=%s; domain=%s; path=/",
		cookiename == NULL ? "" : cookiename,
		value == NULL ? "" : encoded_url, 
		domain == NULL ? "" : domain);
	} else {
		sprintf(ret, 
		"%s=%s; domain=%s; path=/; Expires=%s; max-age=%d%s",
		cookiename == NULL ? "" : cookiename,
		value == NULL ? "" : encoded_url, 
		domain == NULL ? "" : domain,
		cookie_getGMTDate(p,maxAge),
		maxAge,
		httpOnly == TRUE ? "; httpOnly" : "");
	}
	return ret;
}

//Assuming the cookie age in and needs to convert in seconds.
char* cookie_cookieTemplate(pool* p, Cookie* cookie, char *ivalue, char *idomain) {
	char* ret=NULL;
	char* value=SAFESTRBLANK(ivalue),*domain=SAFESTRBLANK(idomain);
	int sz=0,ulen=0;
	char* encoded_url=NULL;
	long maxAge=0;
	
	if(cookie==NULL) return NULL;
	maxAge = cookie_convertDaysToSeconds(cookie->age);
	
	sz=strlen(domain)+strlen(cookie->name)+96;
	ulen=strlen(value)*3+1;
	
	encoded_url=apr_pcalloc(p,ulen);
	url_encode(value, encoded_url, ulen);
	sz+=strlen(encoded_url);

	ret=apr_pcalloc(p,sz);
	if (maxAge < 0) {
		if(cookie->secure == TRUE) {
			sprintf(ret, "%s=%s; domain=%s; path=/%s",
			cookie->name == NULL ? "" : cookie->name,
			value == NULL ? "" : encoded_url, 
			domain == NULL ? "" : domain, "; httpOnly; Secure");			
		} else {
			sprintf(ret, "%s=%s; domain=%s; path=/%s",
			cookie->name == NULL ? "" : cookie->name,
			value == NULL ? "" : encoded_url, 
			domain == NULL ? "" : domain,
			cookie->httpOnly == TRUE ? "; httpOnly" : "");
		}
	} else {
		if(cookie->secure == TRUE) {
			sprintf(ret, "%s=%s; domain=%s; path=/; Expires=%s; max-age=%d%s",
			cookie->name == NULL ? "" : cookie->name,
			value == NULL ? "" : encoded_url, 
			domain == NULL ? "" : domain,
			cookie_getGMTDate(p,maxAge),
			maxAge, "; httpOnly; Secure");
		} else {
			sprintf(ret, "%s=%s; domain=%s; path=/; Expires=%s; max-age=%d%s",
			cookie->name == NULL ? "" : cookie->name,
			value == NULL ? "" : encoded_url, 
			domain == NULL ? "" : domain,
			cookie_getGMTDate(p,maxAge),
			maxAge,
			cookie->httpOnly == TRUE ? "; httpOnly" : "");			
		}
	}
	return ret;
}
char* cookie_cookieUntemplate(pool* p,char* name){
	char* ret=NULL;
	int rlen=0;
	if(name==NULL)return NULL;
	rlen=strlen(name)+1;
	ret=apr_pcalloc(p,rlen);
	url_decode(name,ret,rlen);
	return ret;
}

int cookie_convertDaysToSeconds(int days){
		if(days<0) return days;
		return days*86400;
}

char* cookie_getGMTDate(pool* p, int secondsInFuture){
	char buf[64];
	apr_time_t date=apr_time_now();
	date=date+(APR_USEC_PER_SEC*secondsInFuture);
	
	memset(buf,'\0',64);
	apr_ctime(buf,date);		
	return apr_pstrdup(p,buf);
}

char* cookie_parseCookie(pool* p, char* name, char* cookies){
	char *cursor, *strCookie, *cookiereturn,*cend, *cnamestart;
	int len,x,found=0;
	int cookieLen=0;
	
	if(cookies==NULL||name==NULL) return NULL;
	
	cend=cnamestart=cookiereturn=strCookie=NULL;
	cookieLen=strlen(name);
	strCookie=cookies;
	
	while(1){
		cnamestart=strstr(strCookie, name);	
		//printf("\n\nCycle:%s\n\n\n",cnamestart);
		if(cnamestart){
			cursor=cnamestart+cookieLen;
			//printf("cursorFOUND:%s\n",cursor);
			if(*cursor&&(*cursor=='='||*cursor==' ')){
				while(*cursor&&*cursor!='='){
					cursor++;
				}
				cursor++;
				//printf("\n\nCURSOR:%s\n\n",cursor);
				cend=strchr(cursor,';');
				
				if(cend){
					//printf("cend:%s\n",cend);
				}else{
					cend=strchr(cursor,'\0');
				}
				
				
				len=cend-cursor;
                            	cookiereturn=(char*)apr_palloc(p,len+1);
                            	strncpy(cookiereturn,cursor,len);
                            	cookiereturn[len]='\0';
				//printf("COOKIERETURN: [%s]\n",cookiereturn);
				break;
			}else{
				strCookie=cursor;
				//printf("cursor:%s\n",cursor);
			}
		}else{
			break;
		}
	}	
    return cookiereturn;
}

char *cookie_getCookie(pool* p, apr_table_t* headers_in, Cookie* cookie)
{
	char *cursor, *strCookie, *cookiereturn,*cend, *cnamestart;
	int len,x,found=0;
	cend=cnamestart=cookiereturn=strCookie=NULL;

        if (cookie==NULL||cookie->name == NULL||cookie->nameLen<0)
                return NULL;

	
        if ((strCookie = (char*)apr_table_get(headers_in, "Cookie")) != NULL)
        {
		while(1){
			cnamestart=strstr(strCookie, cookie->name);	
			//printf("\n\nCycle:%s\n\n\n",cnamestart);
			if(cnamestart){
				cursor=cnamestart+cookie->nameLen;
				//printf("cursorFOUND:%s\n",cursor);
				if(*cursor&&(*cursor=='='||*cursor==' ')){
					while(*cursor&&*cursor!='='){
						cursor++;
					}
					cursor++;
					//printf("\n\nCURSOR:%s\n\n",cursor);
					cend=strchr(cursor,';');
					
					if(cend){
						//printf("cend:%s\n",cend);
					}else{
						cend=strchr(cursor,'\0');
					}
					
					
					len=cend-cursor;
                                	cookiereturn=(char*)apr_palloc(p,len+1);
                                	strncpy(cookiereturn,cursor,len);
                                	cookiereturn[len]='\0';
					//printf("COOKIERETURN: [%s]\n",cookiereturn);
					break;
				}else{
					strCookie=cursor;
					//printf("cursor:%s\n",cursor);
				}
			}else{
				break;
			}
		}	
        }
    return cookiereturn;
}

char *cookie_getCookieByName(pool* p, apr_table_t* headers_in, char *cookie_name, int cookie_name_len)
{
	char *cursor, *strCookie, *cookiereturn,*cend, *cnamestart;
	int len,x,found=0;
	cend=cnamestart=cookiereturn=strCookie=NULL;

        if (cookie_name == NULL||cookie_name_len<0)
                return NULL;

	
        if ((strCookie = (char*)apr_table_get(headers_in, "Cookie")) != NULL)
        {
		while(1){
			cnamestart=strstr(strCookie, cookie_name);	
			//printf("\n\nCycle:%s\n\n\n",cnamestart);
			if(cnamestart){
				cursor=cnamestart+cookie_name_len;
				//printf("cursorFOUND:%s\n",cursor);
				if(*cursor&&(*cursor=='='||*cursor==' ')){
					while(*cursor&&*cursor!='='){
						cursor++;
					}
					cursor++;
					//printf("\n\nCURSOR:%s\n\n",cursor);
					cend=strchr(cursor,';');
					
					if(cend){
						//printf("cend:%s\n",cend);
					}else{
						cend=strchr(cursor,'\0');
					}
					
					
					len=cend-cursor;
                                	cookiereturn=(char*)apr_palloc(p,len+1);
                                	strncpy(cookiereturn,cursor,len);
                                	cookiereturn[len]='\0';
					//printf("COOKIERETURN: [%s]\n",cookiereturn);
					break;
				}else{
					strCookie=cursor;
					//printf("cursor:%s\n",cursor);
				}
			}else{
				break;
			}
		}	
        }
    return cookiereturn;
}
void cookie_deleteCookie(pool* p, apr_table_t* err_headers_out, Cookie* cookie, char* domain){
    char delstr[768];
    if(cookie!=NULL&&cookie->name!=NULL){
        sprintf(delstr,"%s=remove;domain=%s;path=/;Expires=Thu, 01-Jan-1970 00:00:10 GMT;max-age=0",
            cookie->name== NULL ? "" : cookie->name,
            domain == NULL ? "" : domain
            );
        apr_table_add(err_headers_out,"Set-Cookie",delstr);
    }
}

void cookie_deleteCookieByName(pool* p, apr_table_t* err_headers_out, char* cookie_name, char* domain){
    char delstr[768];
    if(cookie_name!=NULL){
        sprintf(delstr,"%s=remove;domain=%s;path=/;Expires=Thu, 01-Jan-1970 00:00:10 GMT;max-age=0",
            cookie_name== NULL ? "" : cookie_name,
            domain == NULL ? "" : domain
            );
        apr_table_add(err_headers_out,"Set-Cookie",delstr);
    }
}

#endif //_COOKIE_C_


<|start_filename|>src/url-utils/url_utils.c<|end_filename|>
#include <stdio.h>
#include <ctype.h>
#include <string.h>

#include "url_utils.h"

#define MAX_VAR_SIZE	256
#define URL_MAX_VAR_SIZE 1280

const int STAGE=0;
const int STEP=1;
const int CURSOR=2;

int c_to_hex(char c) {
  return 0xF & (('0' <= c && c <= '9')? (c - '0') : (toupper(c) - 'A' + 10));
}

int containsValidSlots(int slotsneeded, int slotlen){
  return slotsneeded<slotlen;
}

int marshallError(char* dst,int cursor){
       dst[cursor]='\0';
       return -cursor;
}

void resetUrlState(int state[]){
   state[STAGE]=0;
   state[STEP]=0;
   state[CURSOR]=0;
}
int validHex(char* ch){
    return ((int)*ch>=48&&(int)*ch<=57)||((int)*ch>=65&&(int)*ch<=70)||((int)*ch>=97&&(int)*ch<=102);
}

void url_stream_decode(const char *ch,char* dest, int state[]){
  //printf("%c,%d\n",*ch,state[CURSOR]);
   if(state[STAGE]==0){
      if(*ch=='+'){
        dest[state[CURSOR]++]=' ';
      }else if(*ch=='%'){
        state[STAGE]=1;
      }else{
        dest[state[CURSOR]++]=*ch;
      }
   }else if(state[STAGE]==1){
      state[STAGE]=2; 
   }else if (state[STAGE]==2){
//printf("Make char %c:%d, %c:%d\n",*(ch-1),(int)(*(ch-1)),*ch,(int)(*ch));
      if(validHex((char*)ch)&&validHex((char *)(ch-1))){ 
       dest[state[CURSOR]++] = (c_to_hex(*(ch-1)) << 4) + c_to_hex(*ch);
      }
      state[STAGE]=0;
   }
}


int url_get_param(const char *queryString, const char *paramName, char *dest, int dlen){
  int stage,paramLen,cursor,maxslots;
  int decodeState[3];
  if(paramName==NULL||queryString==NULL) return -1;

  paramLen=strlen(paramName);
  stage=-1;
  cursor=0;
  maxslots=dlen-1;
  resetUrlState(decodeState);


//printf("orig maxslots:%d,%d,%d,%d\n",maxslots,dlen,decodeState[STEP],decodeState[CURSOR]);

  while(*queryString){
    if(stage==-1){
     //find param
     if(!cursor){
       if(*queryString==paramName[cursor]){
        cursor++;
       }else{
         //this is not the param we are looking for..reset
         stage=-21;
       }
     }else{
      if(*queryString==paramName[cursor]){
        cursor++;
      }else{
        //this is not the param we are looking for..reset
         stage=-21;
      }
     } 
     if(paramLen==cursor){
       //printf("FOUND\n");
       stage=-2;
     }
    }else if(stage==-2){
      //find equals sign
      if(*queryString=='='){
        stage=-3;
      }else{
        //could not find equals...must reset to nearest &
        stage=-21;
      }
    }else if(stage==-21){
       if(*queryString=='?'||*queryString=='&'){
        stage=-1;
        cursor=0;
       }
    }else if(stage==-3){
       //fill buffer until end 
       if(decodeState[CURSOR]>=maxslots){
         //printf("cursor:%d, slots:%d",decodeState[CURSOR],maxslots);
         decodeState[CURSOR]=-decodeState[CURSOR];
         break;
       }else if(*queryString!='\0'&&*queryString!='&'){
        url_stream_decode(queryString,dest,decodeState);
       }else{
         stage=4;
       }
    }
    
  queryString++; 
  }
if(decodeState[CURSOR]>=0){
   dest[decodeState[CURSOR]]='\0';
}else{
   dest[-decodeState[CURSOR]]='\0';
}
return decodeState[CURSOR];
}


/* Decodes a url encoded cstring given as src
*and places result into dst
*
*@returns length of decoded string on success, -length of
*what was decoded on failure
*/
int url_decode(const char *src, char *dst, int dlen){
  int maxSlots;
  int decodeState[3];

  if (!src || !dst)
    return 0;

  maxSlots=dlen-1;
  resetUrlState(decodeState);
    while (*src) {
       if(decodeState[CURSOR]>=maxSlots){
         //printf("cursor:%d, slots:%d",decodeState[CURSOR],maxSlots);
         decodeState[CURSOR]=-decodeState[CURSOR];
         break;
       }else if(*src!='\0'){
        url_stream_decode(src,dst,decodeState);
       }
     src++; 
    }

if(decodeState[CURSOR]>=0){
   dst[decodeState[CURSOR]]='\0';
}else{
   dst[-decodeState[CURSOR]]='\0';
}

return decodeState[CURSOR];

}



/**
*Encodes a url encoded cstring given as src
*and places result into dst
*
*@returns length of Encoded string on success, -length of 
*what was Encoded on failure
*/
int url_encode(const char *src, char *dst, int dlen) {
  int  i, j, len;
  int maxslots=dlen-1;
  char c;

  static const char hc[] = "0123456789ABCDEF";

  len = strlen(src);
  j   = 0;
  //  for (i = 0; i < len, j<dlen; i++) {
  for (i = 0; i < len; i++) {
    switch (c = src[i]) {
      case ' ':
        if(containsValidSlots(j,maxslots)){
           dst[j++] = '+';
        }else{
           return marshallError(dst,j); 
        }
        break;

      case '!': case '"': case '#': case '$': case '%': case '&': case '(': case ')':
      case '+': case ',': case ':': case ';': case '<': case '=': case '>': case '?':
      case '[': case '\'': case '\\': case ']': case '^': case '`': case '{': case '|':
      case '}': case '~': case '/': case '@':
      if(containsValidSlots(j+2,maxslots)){
        dst[j++] = '%';
        dst[j++] = hc[(c >> 4) & 0xF];
        dst[j++] = hc[c & 0xF];
      }else{
        return marshallError(dst,j);
      }
        break;

      default:
        if (iscntrl(c) || !isascii(c)) {
            if(containsValidSlots(j+2,maxslots)){
              dst[j++] = '%';
              dst[j++] = hc[(c >> 4) & 0xF];
              dst[j++] = hc[c & 0xF];
            }else{
              return marshallError(dst,j);
            }

        }
        else
           if(containsValidSlots(j,maxslots)){
             dst[j++] = c;
           }else{
            return  marshallError(dst,j);
           }

    }
  }
 
  dst[j] = '\0';
  return j;
}


char b64string[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

long base64_encode (char *to, char *from, unsigned int len){
	char *fromp = from;
	char *top = to;
	unsigned char cbyte;
	unsigned char obyte;
	char end[3];

	for (; len >= 3; len -= 3) {
		cbyte = *fromp++;
		*top++ = b64string[(int)(cbyte >> 2)];
		obyte = (cbyte << 4) & 0x30;		/* 0011 0000 */

		cbyte = *fromp++;
		obyte |= (cbyte >> 4);			/* 0000 1111 */
		*top++ = b64string[(int)obyte];
		obyte = (cbyte << 2) & 0x3C;		/* 0011 1100 */

		cbyte = *fromp++;
		obyte |= (cbyte >> 6);			/* 0000 0011 */
		*top++ = b64string[(int)obyte];
		*top++ = b64string[(int)(cbyte & 0x3F)];/* 0011 1111 */
	}

	if (len) {
		end[0] = *fromp++;
		if (--len) end[1] = *fromp++; else end[1] = 0;
		end[2] = 0;

		cbyte = end[0];
		*top++ = b64string[(int)(cbyte >> 2)];
		obyte = (cbyte << 4) & 0x30;		/* 0011 0000 */

		cbyte = end[1];
		obyte |= (cbyte >> 4);
		*top++ = b64string[(int)obyte];
		obyte = (cbyte << 2) & 0x3C;		/* 0011 1100 */

		if (len) *top++ = b64string[(int)obyte];
		else *top++ = '=';
		*top++ = '=';
	}
	*top = 0;
	return top - to;
}

char b64Urlstring[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
long base64Url_encode (char *to, char *from, unsigned int len){
	char *fromp = from;
	char *top = to;
	unsigned char cbyte;
	unsigned char obyte;
	char end[3];

	for (; len >= 3; len -= 3) {
		cbyte = *fromp++;
		*top++ = b64Urlstring[(int)(cbyte >> 2)];
		obyte = (cbyte << 4) & 0x30;		/* 0011 0000 */

		cbyte = *fromp++;
		obyte |= (cbyte >> 4);			/* 0000 1111 */
		*top++ = b64Urlstring[(int)obyte];
		obyte = (cbyte << 2) & 0x3C;		/* 0011 1100 */

		cbyte = *fromp++;
		obyte |= (cbyte >> 6);			/* 0000 0011 */
		*top++ = b64Urlstring[(int)obyte];
		*top++ = b64Urlstring[(int)(cbyte & 0x3F)];/* 0011 1111 */
	}

	if (len) {
		end[0] = *fromp++;
		if (--len) end[1] = *fromp++; else end[1] = 0;
		end[2] = 0;

		cbyte = end[0];
		*top++ = b64Urlstring[(int)(cbyte >> 2)];
		obyte = (cbyte << 4) & 0x30;		/* 0011 0000 */

		cbyte = end[1];
		obyte |= (cbyte >> 4);
		*top++ = b64Urlstring[(int)obyte];
		obyte = (cbyte << 2) & 0x3C;		/* 0011 1100 */

		if (len) *top++ = b64Urlstring[(int)obyte];
	}
	*top = 0;

	return top - to;
}

#define badchar(c,p) (!(p = memchr(b64string, c, 64)))

long base64_decode (char *to, char *from, unsigned int len){
	char *fromp = from;
	char *top = to;
	char *p;
	unsigned char cbyte;
	unsigned char obyte;
	int padding = 0;

	for (; len >= 4; len -= 4) {
		if ((cbyte = *fromp++) == '=') cbyte = 0;
		else {
			if (badchar(cbyte, p)) return -1;
			cbyte = (p - b64string);
		}
		obyte = cbyte << 2;		/* 1111 1100 */

		if ((cbyte = *fromp++) == '=') cbyte = 0;
		else {
			if (badchar(cbyte, p)) return -1;
			cbyte = p - b64string;
		}
		obyte |= cbyte >> 4;		/* 0000 0011 */
		*top++ = obyte;

		obyte = cbyte << 4;		/* 1111 0000 */
		if ((cbyte = *fromp++) == '=') { cbyte = 0; padding++; }
		else {
			padding = 0;
			if (badchar (cbyte, p)) return -1;
			cbyte = p - b64string;
		}
		obyte |= cbyte >> 2;		/* 0000 1111 */
		*top++ = obyte;

		obyte = cbyte << 6;		/* 1100 0000 */
		if ((cbyte = *fromp++) == '=') { cbyte = 0; padding++; }
		else {
			padding = 0;
			if (badchar (cbyte, p)) return -1;
			cbyte = p - b64string;
		}
		obyte |= cbyte;			/* 0011 1111 */
		*top++ = obyte;
	}

	*top = 0;
	if (len) return -1;
	return (top - to) - padding;
}

long base64Url_decode (char *to, char *from, unsigned int len){
	char *fromp = from;
	char *top = to;
	char *p;
	unsigned char cbyte;
	unsigned char obyte;
	int padding = 0;
	char padded_src[URL_MAX_VAR_SIZE];

	// add padding
	if(len%4) {
		memcpy(padded_src,  from, len);
		memcpy(padded_src+len, "====", 4);
		fromp = padded_src;
		len+=4;
	}

	for (; len >= 4; len -= 4) {
		if ((cbyte = *fromp++) == '=') cbyte = 0;
		else {
			if(cbyte=='-') { cbyte='+'; } else if(cbyte=='_') { cbyte='/'; }
			if (badchar(cbyte, p)) return -1;
			cbyte = (p - b64string);
		}
		obyte = cbyte << 2;		/* 1111 1100 */

		if ((cbyte = *fromp++) == '=') cbyte = 0;
		else {
			if(cbyte=='-') { cbyte='+'; } else if(cbyte=='_') { cbyte='/'; }
			if (badchar(cbyte, p)) return -1;
			cbyte = p - b64string;
		}
		obyte |= cbyte >> 4;		/* 0000 0011 */
		*top++ = obyte;

		obyte = cbyte << 4;		/* 1111 0000 */
		if ((cbyte = *fromp++) == '=') { cbyte = 0; padding++; }
		else {
			padding = 0;
			if(cbyte=='-') { cbyte='+'; } else if(cbyte=='_') { cbyte='/'; }
			if (badchar (cbyte, p)) return -1;
			cbyte = p - b64string;
		}
		obyte |= cbyte >> 2;		/* 0000 1111 */
		*top++ = obyte;

		obyte = cbyte << 6;		/* 1100 0000 */
		if ((cbyte = *fromp++) == '=') { cbyte = 0; padding++; }
		else {
			padding = 0;
			if(cbyte=='-') { cbyte='+'; } else if(cbyte=='_') { cbyte='/'; }
			if (badchar (cbyte, p)) return -1;
			cbyte = p - b64string;
		}
		obyte |= cbyte;			/* 0011 1111 */
		*top++ = obyte;
	}

	// handle the remaining bytes
	*top = 0;

	return (top - to) - padding;
}

char* url_getParam(pool* p, char* queryString,const char* name){
	char tmp[URL_MAX_VAR_SIZE];		
	if(url_get_param(queryString,name,tmp,URL_MAX_VAR_SIZE)>0){
		return apr_pstrdup(p,tmp);
	}
	return NULL;
}

char* url_addParam(pool* p, char* url, char* pName, char* pVal){
	char tmp[URL_MAX_VAR_SIZE];
	char* ret=NULL;
	
	if(pName==NULL||pVal==NULL||url==NULL){
		return url;		
	}
	
	if(url_encode(pVal,tmp,URL_MAX_VAR_SIZE)>0){
		ret=apr_pstrcat(p,url,"?",pName,"=",tmp,NULL);
	}else{
		ret=url;
	}
	
	return ret;
}
//This appends param to query string.
char* url_appendParamToQuery(pool*p, char*query, char*pName,char*pVal){
	char* tmp;
	
	if(pName==NULL||pVal==NULL)	return query;//return query as is
	
	tmp=url_encode2(p,pVal);
	if(query==NULL) {return apr_pstrcat(p,pName,"=",tmp,NULL);}
	return apr_pstrcat(p,query,"&",pName,"=",tmp,NULL);
}
char* url_encode2(pool* p, char* src){
	int dlen=0;
	int slen=0;
	char* tmp=NULL;
	if(src==NULL) return NULL;
	
	slen=strlen(src);
	if(slen==0) return NULL;
	
	dlen=(slen*3)+1;
	tmp=apr_pcalloc(p,dlen);
	url_encode(src,tmp,dlen);

	return apr_pstrdup(p,tmp);
}
char* url_decode2(pool* p, char* src){
	int dlen=0;
	int slen=0;
	char* tmp=NULL;
	if(src==NULL) return NULL;
	
	slen=strlen(src);
	if(slen==0) return NULL;
	
	dlen=slen+1;
	tmp=apr_pcalloc(p,dlen);
	url_decode(src,tmp,dlen);
	
	return apr_pstrdup(p,tmp);
}



<|start_filename|>src/oidc-core/unit-test/oidc_core_unit_test.c<|end_filename|>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <apr_general.h>
#include <apr_pools.h>
#include <rewrite_core.h>
#include <CuTest.h>
#include <common_utils.h>
#include <oidc_config_xml.h>
#include <shm_data.h>
#include <match_list.h>
#include "config-core/config_bindings_shm.h"
#include "doc_parser_utils.h"
#include "http-utils/http_client.h"
#include "template_engine.h"
#include "oidc_globals.h"
#include "oidc_config_core.h"
#include "oidc_config.h"

void rc_getInfoTest(mm_logger* logger, CuTest*tc){
//	char* version = rc_getInfo(logger->p);
//	CuAssertPtrNotNull(tc,version);
}
void rc_matchByStringsTest(mm_logger* logger, CuTest*tc){
	int matched = rc_matchByStrings(logger->p, "^/company", "/company/");
	CuAssert(tc, "rc_matchByStrings failed to match ", matched==0);
}
void rc_matchByStringsIgnoreCaseTest(mm_logger* logger, CuTest*tc){
	int matched = rc_matchByStringsIgnoreCase(logger->p, "^/company", "/Company/");
	CuAssert(tc, "rc_matchByStringsIgnoreCase failed to match ", matched==0);
}
void rc_matchByStringsReturnDetailsTest(mm_logger* logger, CuTest*tc){
	char* details = rc_matchByStringsReturnDetails(logger->p, "^/company", "/company/");
	CuAssertPtrEquals(tc,NULL,details); // null expected
}
void rc_matchByStringsPatternTest(mm_logger* logger, CuTest*tc){
	//http://proto.wsj.com/wsjacl/qa/rewrite-match?valueParam=%2Fdemographic%2Fuser%2Ftara&regexParam=%2Fuser%2F%28.*%29&templateParam=
	char* value ="/demographic/user/tara";
	char* regex = "/user/(.*)";
	array_header* matches=NULL;
	char* elt=NULL;
	int i=0;
	int ret=0;

	ret=rc_matchByStringsPattern(logger->p,regex,value,&matches);
	if(matches!=NULL){

		logging_printf(logger,"Found Matches (%d)\n",matches->nelts);
		
		if(matches->nelts>0){
			for(i=0;i<matches->nelts;i++){
				elt=cu_getElement(matches,i);
				logging_printf(logger,"$%d: %s\n",i,elt);
			}
		}
	}
}
void rc_isRegexValidTest(mm_logger* logger, CuTest*tc){
	int result = rc_isRegexValid(logger->p,"^/test");
	CuAssertIntEquals(tc,1,result);
}

static oauth_jwk* oauth_getSignatureValidationKey(pool*p, oauth_jwt_header* header, const char* issuer, void* data, char** error) {
	oidc_config* oauthConfig = (oidc_config *)data;

	int i;

	if(header==NULL||header->algorithm==NULL||oauthConfig==NULL) {
		if(error!=NULL) { *error = apr_pstrdup(p, "header or jwsKeys null"); }
		return NULL;
	}
	oauth_jwk* jwk =oauthutil_newJWKObj(p);

	if(header->keyID!=NULL) {
		oauth_jwskey* jwsKey = am_getJWSKeyByKeyID(oauthConfig->oidcProvider->jwsKeys, header->keyID);

		if(jwsKey==NULL) {
			if(error!=NULL) { *error = apr_pstrdup(p, "jwsKey by keyID not found"); }
			return NULL;
		}
		jwk->keyID = apr_pstrdup(p, jwsKey->id);
		jwk->use = apr_pstrdup(p, jwsKey->use);
		jwk->modulus = apr_pstrdup(p, jwsKey->modulus);
		jwk->exponent = apr_pstrdup(p, jwsKey->exponent);
	}else if(issuer!=NULL){
		relying_party* relyingParty = am_getRelyingPartyByClientID(oauthConfig->relyingPartyHash, issuer);
		if(relyingParty==NULL) {
			if(error!=NULL) { *error = apr_pstrdup(p, "relyingParty not configured"); }
			return NULL;
		}
		jwk->key = apr_pstrdup(p, relyingParty->clientSecret);
	}

	return jwk;
}

void oidc_loadConfFile_test(mm_logger* logger, CuTest*tc){
	pool* p=logger->p;
	shared_heap* sheap=NULL;
	char* error=NULL;
	int handlerResponseCode=-1;
	cbs_globals* globals=NULL;
	cfg_service_descriptor *rs=NULL; // in pool
	cfg_service_descriptor* svcdesc = cb_newServiceDescriptorObj(p);
	apr_hash_set(svcdesc->params, "config-xml", APR_HASH_KEY_STRING, "oidc-config.xml");
	void* userdata = NULL;

	djrglobals_setEnableUnnamedSHM("true");

	// create resource service.
	rs=cb_newServiceDescriptorObj(p);
	rs->uri=apr_pstrdup(p,"https://raw.githubusercontent.com/tarachandverma/nginx-openidc/master/example-conf/");
	rs->timeoutSeconds=5;

	sheap=shdata_sheap_make(p,200000,"./unit-test/oidc.shm");
	shdata_BeginTagging(sheap);
	shdata_OpenItemTag(sheap,"oidc_test");

	//build globals
	globals=(cbs_globals*)shdata_shpcalloc(sheap,sizeof(cbs_globals));
	globals->homeDir=shdata_32BitString_copy(sheap,"./unit-test");
	globals->resourceService=cbs_copyServiceDescripterOnSheap(p,sheap,rs);

	error=amc_initialize(p,sheap,globals,svcdesc, &userdata);
	CuAssertPtrEquals_Msg(tc,error,NULL,error);

	shdata_PublishBackSeg(sheap);
	shdata_syncself(p,sheap,NULL,NULL);

	oidc_config* actmap = NULL;
	error=amc_postRefresh(p,sheap, NULL, svcdesc,(void**)&actmap);
	CuAssertPtrNotNullMsg(tc,"Error : oidcConfig is null", actmap);

	am_printAll(p, actmap);

	const char* id_token = "<KEY>";

	if(id_token!=NULL) {
		oauth_jwt* jwt = oauthutil_parseIDToken(p, id_token, NULL, &error);
		CuAssert(tc,error, jwt!=NULL);

		oauthutil_printIDToken(p, jwt);

		oidc_cipher_cfg* cipherConfig = (oidc_cipher_cfg*)apr_palloc(p, sizeof(oidc_cipher_cfg));
		cipherConfig->crypto_passphrase = apr_pstrdup(p, "<PASSWORD>");
		cipherConfig->decrypt_ctx=NULL;
		cipherConfig->encrypt_ctx=NULL;
		cipherConfig->p = p;

		const char* serializedClaim = "tarachandverma";
		int crypted_len = strlen(serializedClaim) + 1;

		// encrypt
		char *encrypted = "";
		int status = cu_encryptAndBase64urlEncode(p, cipherConfig, &encrypted, (unsigned char *) serializedClaim, &error);
		if(status>0){
			char* decrypted = "";
			status = cu_base64urlDecodeAndDecrypt(p, cipherConfig, &decrypted, encrypted, &error);
			printf("decrypted=%s\r\n", decrypted);
		}


	}

	apr_table_t* headers_in = apr_table_make(p, 1);

	char* sessionID = cookie_getCookie(p, headers_in, actmap->oidcSession);
	if(sessionID==NULL) {
		sessionID = cu_generateGuid(p);
		char* cookieDrop = cookie_cookieTemplate(p, actmap->oidcSession, sessionID, NULL);
		if(cookieDrop!=NULL){
			printf("cookieDrop=%s", cookieDrop);
			apr_table_add(headers_in, "Set-Cookie", cookieDrop);
		}
	}

}

static const char* oauthtest_getPublicKey(pool*p, oauth_jwt_header* header, const char* issuer, void* data, char** error) {
	const char* publicKey =
			"-----BEGIN PUBLIC KEY-----\n"\
"<KEY>
"<KEY>
"<KEY>
"<KEY>"\
"-----END PUBLIC KEY-----\n"
;
	oauth_jwk* jwk =oauthutil_newJWKObj(p);
	jwk->key = apr_pstrdup(p, publicKey);
	return jwk;
}

static void oauthutil_generateAndParseAndValidateIDToken_test(mm_logger* logger,CuTest*tc) {
	pool*p = logger->p;
	char* error = NULL;

	const char* privateKey =
			"-----BEGIN RSA PRIVATE KEY-----\n"\
"<KEY>
"<KEY>
"<KEY>"\
"<KEY>"\
"<KEY>"\
"<KEY>
"<KEY>
"<KEY>"\
"<KEY>"\
"<KEY>"\
"<KEY>"\
"<KEY>"\
"<KEY>"\
"-----END RSA PRIVATE KEY-----\n"
;
	oauth_jwt_header* header = oauthutil_newJWTHeaderObj(p);
	header->algorithm = apr_pstrdup(p, "RS256");

	oauth_jwt_claim* claim = oauthutil_newJWTClaimObj(p);
	claim->issuer = apr_pstrdup(p, "https://login.wsj.com");
	claim->subject = apr_pstrdup(p, "<EMAIL>");
	claim->audience = apr_pstrdup(p, "test123");
	claim->issuedAt = time(NULL);
	claim->expiry = 600+time(NULL);
	// set optional params
	claim->options = apr_hash_make(p);
	apr_hash_set(claim->options,"nonce", APR_HASH_KEY_STRING, "n-0S6_WzA2Mj");

	char* IDTokenSerial = oauthutil_generateIDToken(p, header, claim, privateKey);

	CuAssert(tc,"Error: unable to generate IDToken ", IDTokenSerial!=NULL);

	printf("IDTokenSerial=%s\r\n", IDTokenSerial);

	// parse and test
	oauth_jwt* IDToken = oauthutil_parseAndValidateIDToken(p, IDTokenSerial, oauthtest_getPublicKey, NULL, &error);

	CuAssert(tc,error, IDToken!=NULL);

	oauthutil_printIDToken(p, IDToken);


}

static void oauthutil_parseAndValidateExpiredIDToken_test(mm_logger* logger,CuTest*tc) {
	pool*p = logger->p;
	char* error = NULL;

	const char* IDTokenSerial = "<KEY>";

	oauth_jwt* IDToken = oauthutil_parseAndValidateIDToken(p, IDTokenSerial, oauthtest_getPublicKey, NULL, &error);

	CuAssert(tc,error, IDToken==NULL);

}

typedef struct oauth_jws_uri{
	char* uri;
	int timeout;
}oauth_jws_uri;

static oauth_jwk* oauthtest_getGooglePublicKey(pool*p, oauth_jwt_header* header, const char* issuer, void* data, char** error) {
	oauth_jws_uri* jwsUri = (oauth_jws_uri*)data;
	int i;

	if(header==NULL||jwsUri==NULL||jwsUri->uri==NULL) {
		if(error!=NULL) { *error = apr_pstrdup(p, "header or jwsUri null"); }
		return NULL;
	}

	http_util_result* httpResult=hc_get_verbose(p, jwsUri->uri, jwsUri->timeout, NULL, NULL, error);
	if(httpResult==NULL) {
		if(error!=NULL) { *error = apr_pstrdup(p, "jwsUri response null"); }
		return NULL;
	}

	oauth_jwk* jwk =oauthutil_newJWKObj(p);

	Value* json = 	JSON_Parse(p, httpResult->data);
	if(json!=NULL){
		Value* array = JSON_GetObjectItem(json, "keys");
		if(array==NULL||JSON_GetItemType(array)!=JSON_Array) {
			if(error!=NULL) { *error = apr_pstrdup(p, "keys object is not array"); }
			return NULL;
		}

		int	arrSz = JSON_GetArraySize(array);

		// Retrieve item number "item" from array "array". Returns NULL if unsuccessful.
		for (i=0; i<arrSz; i++) {
			Value* element = JSON_GetArrayItem(array, i);
			Value* keyIDObj = JSON_GetObjectItem(element, "kid");
			const char* keyID = (keyIDObj) ? (char*)JSON_GetStringFromStringItem(keyIDObj) : NULL;
			if(keyID!=NULL&&(strcmp(keyID,header->keyID)==0)) {
				jwk->keyID = keyID;
				Value* val = JSON_GetObjectItem(element, "use");
				jwk->use = (val) ? (char*)JSON_GetStringFromStringItem(val) : NULL;
				val = JSON_GetObjectItem(element, "n");
				jwk->modulus = (val) ? (char*)JSON_GetStringFromStringItem(val) : NULL;
				val = JSON_GetObjectItem(element, "e");
				jwk->exponent = (val) ? (char*)JSON_GetStringFromStringItem(val) : NULL;
			}
		}
	}

	return jwk;
}

static void oauthutil_parseAndValidateGoogleIDToken_test(mm_logger* logger,CuTest*tc) {
	pool*p = logger->p;
	char* error = NULL;

	const char* googleIDToken = "<KEY>";
	oauth_jws_uri* jwsUri=(oauth_jws_uri*)apr_pcalloc(p, sizeof(oauth_jws_uri));
	jwsUri->uri = apr_pstrdup(p, "https://www.googleapis.com/oauth2/v3/certs");
	jwsUri->timeout = 10;

	oauth_jwt* jwt = oauthutil_parseAndValidateIDToken(p, googleIDToken, oauthtest_getGooglePublicKey, jwsUri, &error);

	CuAssert(tc, error, jwt==NULL); // expired ID token

//	oauthutil_printIDToken(p, jwt);
}

CuSuite* oidccore_GetSuite() {
  CuSuite* suite = CuSuiteNew();
//  SUITE_ADD_TEST(suite, rc_getInfoTest);
//  SUITE_ADD_TEST(suite, rc_matchByStringsTest);
//  SUITE_ADD_TEST(suite, rc_matchByStringsIgnoreCaseTest);
//  SUITE_ADD_TEST(suite, rc_matchByStringsReturnDetailsTest);
//  SUITE_ADD_TEST(suite, rc_matchByStringsPatternTest);
//  SUITE_ADD_TEST(suite, rc_isRegexValidTest);
  SUITE_ADD_TEST(suite, oidc_loadConfFile_test);
//  SUITE_ADD_TEST(suite, oauthutil_generateAndParseAndValidateIDToken_test);
//  SUITE_ADD_TEST(suite, oauthutil_parseAndValidateExpiredIDToken_test);
//  SUITE_ADD_TEST(suite, oauthutil_parseAndValidateGoogleIDToken_test);
return suite;
}


<|start_filename|>src/oidc-globals/oidc_version.h<|end_filename|>
/*
 *  Created by <NAME> on 01/07/14.
 *
 */
#ifndef __TCREWRITE_VERSION__H_
#define __TCREWRITE_VERSION__H_

#include <sys/types.h>

#define MODULE_COMPONENT_ID "ngx_openidc"

#define MODULE_VERSION_ID "0.0.5"

#define VERSION_ID	MODULE_COMPONENT_ID" "MODULE_VERSION_ID


#endif // __TCREWRITE_VERSION__H_

/*
---------------------------------------------------------------------------------------------------
 *
 *
 * Add new version, date, and short description here.
  * ---------------------------------------------------------------------------------------------------
 *  0.0.5   -       01/15/2018
 *
 *  added support for multiple OIDC providers
 *  Changed by vermat
 * ---------------------------------------------------------------------------------------------------
 *  0.0.4   -       12/28/2017
 *
 *  added support for multiple OIDC providers
 *  Changed by vermat
 * ---------------------------------------------------------------------------------------------------
 *  0.0.3   -       12/22/2017
 *
 *  added new flag isLoginRedirect to directly send to OP login
 *  Changed by vermat
 * ---------------------------------------------------------------------------------------------------
 *  0.0.2   -       07/22/2017
 *
 *  Fixed unit test
 *  Changed by vermat
 * ---------------------------------------------------------------------------------------------------
 *  0.0.1   -       02/03/2016
 *
 *  First version.
 *  Changed by vermat
 * ---------------------------------------------------------------------------------------------------
 */


<|start_filename|>src/template-core/template_handler_url.c<|end_filename|>
#include "template_handler_url.h"
#include "url_utils.h"

	char* temphand_url_encodeToken(pool* p,void* config,char* src){
		return url_encode2(p,src);
	}

	char* temphand_url_decodeToken(pool* p,void* config,char* src){
		return url_decode2(p,src);
	}
	
// base64 encode decode
	char* temphand_base64_encodeToken(pool* p,void* config,char* src){
		char encoded[2048];
		if(src==NULL) return "(null)";
		base64_encode(encoded, (char*)src, strlen(src));
		return apr_pstrdup(p, encoded);
	}

	char* temphand_base64_decodeToken(pool* p,void* config,char* src){
		char decoded[2048];
		if(src==NULL) return "(null)";
		base64_decode(decoded, (char*)src, strlen(src));
		return apr_pstrdup(p, decoded);
	}

	


<|start_filename|>src/config-core/config_core.h<|end_filename|>
#ifndef __TCREWRITE_CONFIG_CORE__H_
#define __TCREWRITE_CONFIG_CORE__H_

#include <sys/types.h>
#include "apache_typedefs.h"
#include "shm_apr.h"
#include "config_bindings.h"
#include "oidc_config_core.h"
#include "config_messaging.h"
#include "config_bindings_shm.h"
#include "common_utils.h"

	typedef struct config_core{
		cfg_globals* globals;
		cfg_service_descriptor* service;
		shared_heap* sheap;
		char* sheapMapFile;
		int sheapPageSize;
		void* serviceConfig;
		char* passPhrase;
		char* refreshLogFile;
		int disableProcessRecovery;
		char* oidcHeaderPrefix;
		int refreshWaitSeconds;
		char* oidcConfigFile;
		oidc_cipher_cfg* cipherConfig;
	}config_core;
	
	config_core* configcore_newConfigCoreObj(pool* p);
	char* configcore_loadConfigCoreFile(pool* p, char* file, config_core* conf);
	char* configcore_initializeConfigCore(pool* p,config_core* conf);
	void configcore_printConfigCoreDetails(pool* p,config_core* conf);
	int cfg_syncSelf(apr_pool_t* pool,config_core* configCore);
	void* configcore_getModuleConfigByName(config_core* conf,char* name);

#endif



<|start_filename|>src/shm_core/shm_data.c<|end_filename|>
#include <shm_data.h>
#include <signal.h>
#include <time.h>
#include <string.h>
#include <stdio.h>
#include <shm_dup.h>
#include "apache_macros.h"
#include <common_utils.h>
#include <log-utils/logging.h>
#include <oidc_globals.h>

	static smutex_refresh_mutex* shdata_getMutex(pool *p){
		smutex_refresh_mutex* mutex;
		apr_status_t status;
		
		mutex=apr_palloc(p,sizeof(smutex_refresh_mutex));
		mutex->isRefreshing=0;
		status = apr_thread_mutex_create(&(mutex->thread_mutex),APR_THREAD_MUTEX_DEFAULT, p);
		if (status != APR_SUCCESS) {
			return NULL;
		}
		return mutex;
	}
	
	static int shdata_getMutexLock(smutex_refresh_mutex* mutex){	
		apr_status_t status;	
		status=apr_thread_mutex_lock(mutex->thread_mutex);
		if(status==APR_SUCCESS){
			if(!(mutex->isRefreshing)){
				mutex->isRefreshing=1;
				apr_thread_mutex_unlock(mutex->thread_mutex);
				return 1;
			}
			apr_thread_mutex_unlock(mutex->thread_mutex);
		}
		return 0;
	}
	
	static int shdata_isRefreshing(smutex_refresh_mutex* mutex){
		return mutex->isRefreshing;
	}
	
	static void shdata_unLockMutex(smutex_refresh_mutex* mutex){
		 mutex->isRefreshing=0;
	}


	int shdata_syncself(pool* p, shared_heap* sheap, rfunc function, void* userdata){
		APACHE_LOG_DEBUG("SHMCLIENT CHECK SYNC");
		if(sheap!=NULL&&sheap->page!=NULL){
			APACHE_LOG_DEBUG("SHMCLIENT CHECK SYNC1");
			if(sheap->timestamp!=sheap->page->timestamp){
				APACHE_LOG_DEBUG("CLIENT REFRESH");
				if(!shdata_isRefreshing(sheap->refresh_mutex)){
					if(shdata_getMutexLock(sheap->refresh_mutex)){				
						sheap->local_segment=sheap->page->frontsegment;
						sheap->timestamp=sheap->page->timestamp;
						sheap->flipcount++;

						//do attach logic
						APACHE_LOG_DEBUG("Attaching to new update");
						if(function!=NULL){
							(*function)(p,sheap,userdata);
						}
						shdata_unLockMutex(sheap->refresh_mutex);
						return 2;
					}
				}
				return 1;		
			}
			APACHE_LOG_DEBUG("SHMCLIENT CHECK SYNC2");
		}else{
			return -1;
		}
	return 0;
	}

char* shdata_32BitString_copy(shared_heap* sheap, char* str){
	int slen;
	char* nstr;
	
	if(str==NULL){
		return NULL;
	}
	slen=shdup_32BitString_size(str);	
	nstr=shdata_shpalloc(sheap,slen);
	memset(nstr,'\0',slen);
	memcpy(nstr,str,strlen(str));
	//APACHE_LOG_DEBUG("reach1");
return nstr;
}

// Copies source array of native data types to sheap array.
array_header* array_headerToSheap(shared_heap* sheap, array_header* sarray){
        array_header* dst;

        dst=(array_header*)shdata_shpalloc(sheap, sizeof(array_header));
        memcpy(dst,sarray,sizeof(array_header));

        if(sarray->elts!=NULL){
                dst->elts=shdata_shpalloc(sheap,(sarray->nelts*sarray->elt_size));
                memcpy(dst->elts,(void*)(sarray->elts), (sarray->nelts*sarray->elt_size));
        }else{
                dst->elts=NULL;
        }
	dst->pool=NULL;
return dst;
}

	shared_page* shdata_getNewSharedPage(pool* p, apr_shm_t** shm_t, int segmentsize, char* path){
		int overheadsize,usersize, x;
		shared_page* page;
		apr_status_t rv;
		overheadsize=sizeof(shared_page);
		usersize=segmentsize*2;
		char buf[200];

		rv=apr_shm_create(shm_t,overheadsize+usersize,path,p);
		lc_printLog("\n shdata_getNewSharedPage - apr_shm_create status : ec:%d desc:%s size %ld path %s \n",
									 rv, SAFESTR(apr_strerror(rv, buf, sizeof(buf))), (overheadsize+usersize), SAFESTR(path) );
		
#ifdef WIN32
		if(rv==APR_EEXIST) { // try to attach it; seems windows specific behaviour
			rv = apr_shm_attach(shm_t,path,p);
		}
#endif
		if(rv!=APR_SUCCESS){
			//if failure then try to remove shm segment and try again
			rv = apr_shm_attach(shm_t,path,p);
			lc_printLog("\n shdata_getNewSharedPage - apr_shm_attach status : ec:%d desc:%s \n", rv, SAFESTR(apr_strerror(rv, buf, sizeof(buf))) );
			if(rv==APR_SUCCESS){
				rv = apr_shm_destroy(*shm_t);
				lc_printLog("\n shdata_getNewSharedPage - apr_shm_destroy status : ec:%d desc:%s \n", rv, SAFESTR(apr_strerror(rv, buf, sizeof(buf))) );
				rv=apr_shm_create(shm_t,overheadsize+usersize,path,p);
				lc_printLog("\n shdata_getNewSharedPage - apr_shm_create status : ec:%d desc:%s \n", rv, SAFESTR(apr_strerror(rv, buf, sizeof(buf))) );
				//if again failure..possible bad shm file...remove and retry
				if(rv!=APR_SUCCESS){
					rv=apr_file_remove(path,p);
					lc_printLog("\n shdata_getNewSharedPage - apr_file_remove status : ec:%d desc:%s \n", rv, SAFESTR(apr_strerror(rv, buf, sizeof(buf))) );
					if(rv==APR_SUCCESS){
						rv=apr_shm_create(shm_t,overheadsize+usersize,path,p);
						lc_printLog("\n shdata_getNewSharedPage - apr_shm_create status : ec:%d desc:%s \n", rv, SAFESTR(apr_strerror(rv, buf, sizeof(buf))) );
					}
				}
			}else{ //if cannot attach blow file away and try again
				rv=apr_file_remove(path,p);
				lc_printLog("\n shdata_getNewSharedPage - apr_file_remove status : ec:%d desc:%s \n", rv, SAFESTR(apr_strerror(rv, buf, sizeof(buf))) );
				if(rv==APR_SUCCESS){
					rv=apr_shm_create(shm_t,overheadsize+usersize,path,p);
					lc_printLog("\n shdata_getNewSharedPage - apr_shm_create status : ec:%d desc:%s \n", rv, SAFESTR(apr_strerror(rv, buf, sizeof(buf))) );
				}
			}
		}
		
		if(rv==APR_SUCCESS){
			APACHE_LOG_DEBUG1("SHARED PAGES CREATED: Path=%s",path);
			page=apr_shm_baseaddr_get(*shm_t);
			page->itemmax=MAX_PAGE_ITEMS;
			page->segmentsize=segmentsize;
			page->timestamp=SHM_TIMESTAMP_INIT;
			page->flipcount=0;
			page->frontsegment=1;
			page->backsegment=0;
			page->data=(char*)(page+1);
			page->cursor=page->data;
			for(x=0;x<SEGMENTS_PER_PAGE;x++){
				page->segments[x].itemcount=0;
			}			
			return page;
		}
		APACHE_LOG_DEBUG("SHARED PAGE BAD");
	return NULL;
	}

	static shared_page* shdata_attachToSharedPage(pool* p, apr_shm_t** shm_t, int segmentsize, char* path){
		int overheadsize,usersize, x;
		shared_page* page;
		apr_status_t rv;
		overheadsize=sizeof(shared_page);
		usersize=segmentsize*2;
			
		rv = apr_shm_attach(shm_t,path,p); 
		if(rv!=APR_SUCCESS){
			APACHE_LOG_DEBUG("UNABLE TO ATTACH TO SHARED PAGE BAD");
		}
		
		if(rv==APR_SUCCESS){
			APACHE_LOG_DEBUG1("SHARED PAGES CREATED: Path=%s",path);
			page=apr_shm_baseaddr_get(*shm_t);
			page->itemmax=MAX_PAGE_ITEMS;
			page->segmentsize=segmentsize;
			page->timestamp=SHM_TIMESTAMP_INIT;
			page->flipcount=0;
			page->frontsegment=1;
			page->backsegment=0;
			page->data=(char*)(page+1);
			page->cursor=page->data;
			for(x=0;x<SEGMENTS_PER_PAGE;x++){
				page->segments[x].itemcount=0;
			}			
			return page;
		}
		APACHE_LOG_DEBUG("SHARED PAGE BAD");
	return NULL;
	}	

	shared_page* shdata_getNewUnNamedSharedPage(pool* p, apr_shm_t** shm_t, int segmentsize, char* path){
		int overheadsize,usersize, x;
		shared_page* page;
		apr_status_t rv;
		overheadsize=sizeof(shared_page);
		usersize=segmentsize*2;
		char buf[200];

		rv=apr_shm_create(shm_t,overheadsize+usersize,NULL,p);
		lc_printLog("\n shdata_getNewUnNamedSharedPage - apr_shm_create with unnamed shm status : ec:%d desc:%s size %ld  \n",
									rv, SAFESTR(apr_strerror(rv, buf, sizeof(buf))), (overheadsize+usersize));
		if(rv != APR_SUCCESS) {
			if(rv == APR_ENOTIMPL && path != NULL) {
				return shdata_getNewSharedPage(p, shm_t, segmentsize, path);
			}
		}
		else {
			APACHE_LOG_DEBUG("UNNAMED SHARED PAGES CREATED");
			page=apr_shm_baseaddr_get(*shm_t);
			page->itemmax=MAX_PAGE_ITEMS;
			page->segmentsize=segmentsize;
			page->timestamp=SHM_TIMESTAMP_INIT;
			page->flipcount=0;
			page->frontsegment=1;
			page->backsegment=0;
			page->data=(char*)(page+1);
			page->cursor=page->data;
			for(x=0;x<SEGMENTS_PER_PAGE;x++){
				page->segments[x].itemcount=0;
			}
			return page;
		}
		APACHE_LOG_DEBUG("UNNAMED SHARED PAGE BAD");
		return NULL;
	}

	shared_heap* shdata_sheap_make(pool* p, int segmentSize, char* path){
		int x;
		shared_heap* sheap;
		apr_shm_t* shm_t;
		//struct shmid_ds ds;
		
		sheap=(shared_heap*)apr_palloc(p,sizeof(shared_heap));

#ifdef WIN32
		sheap->page=shdata_getNewSharedPage(p,&shm_t,segmentSize,path);
#else
		if(djrglobals_isUnnamedSHMEnabled() == FALSE && path != NULL) {
			sheap->page=shdata_getNewSharedPage(p,&shm_t,segmentSize,path);
		}
		else {
			sheap->page=shdata_getNewUnNamedSharedPage(p,&shm_t,segmentSize,path);
		}
#endif
		
		sheap->timestamp=-1;
		sheap->flipcount=0;
		sheap->local_segment=-1;		
		sheap->shm_main=shm_t;
		sheap->refresh_mutex=shdata_getMutex(p);
		if(sheap->page==NULL){return NULL;}
	return sheap;
	}

	shared_heap* shdata_sheap_attach(pool* p, int segmentSize, char* path){
		int x;
		shared_heap* sheap;
		apr_shm_t* shm_t;
		//struct shmid_ds ds;
		
		sheap=(shared_heap*)apr_palloc(p,sizeof(shared_heap));
		sheap->page=shdata_attachToSharedPage(p,&shm_t,segmentSize,path);
		
		sheap->timestamp=-1;
		sheap->flipcount=0;
		sheap->local_segment=-1;		
		sheap->shm_main=shm_t;
		sheap->refresh_mutex=shdata_getMutex(p);
		if(sheap->page==NULL){return NULL;}
	return sheap;
	}

	char* shdata_getItem(shared_heap* sheap,const char* ID){
		int x;
		char* buf=NULL;
		segment_header* sh;

		sh=&(sheap->page->segments[sheap->local_segment]);	
		for(x=0;x<sh->itemcount;x++){
			if(strcmp(sh->items[x].ITEMID,ID)==0){
				buf=((char*)(sheap->page->data))+(sh->items[x].offset);	
				//printf("D:%ld, b: %ld, o:%d\n",sheap->page->data,buf, sh->items[x].offset);
				return buf;
			}
		}
	return buf;
	}
	int shdata_getFlipCount(shared_heap* sheap){
		return sheap->page->flipcount;
	}
	time_t* shdata_getLastFlipTime(shared_heap* sheap){
		return &(sheap->page->timestamp);
	}

	void shdata_PublishBackSeg(shared_heap* sheap){
		int tmp;
		tmp=sheap->page->backsegment;
		sheap->page->backsegment=sheap->page->frontsegment;
		sheap->page->frontsegment=tmp;
		sheap->page->flipcount++;
		APACHE_LOG_DEBUG1("PUBLISH PAGE: %d",sheap->page->flipcount);
		sheap->page->timestamp=time(NULL);
	}
	void shdata_rollback(shared_heap* sheap){
		int x,y;
		page_item* item;
		shared_page* p;
		segment_header* sh;

		APACHE_LOG_DEBUG("ROLLBACK BACKBUFFER SHEAP");

		p=sheap->page;
		sh=&(sheap->page->segments[sheap->page->backsegment]);

		if(sh->itemcount>=MAX_PAGE_ITEMS){
			y=MAX_PAGE_ITEMS-1;
		}else{
			y=sh->itemcount;
		}
		for(x=0;x<=y;x++){			
			item=&(sh->items[x]);
			memset(item->ITEMID,'\0',PAGE_ITEM_CHARS);	
			memset(item->INFO,'\0',PAGE_ITEM_CHARS);
		}
		p->cursor=p->data+(p->backsegment*p->segmentsize);
		sh->itemcount=0;
	}
	void shdata_BeginTagging(shared_heap* sheap){
		shared_page* p=sheap->page;		
		p->cursor=p->data+(p->backsegment*p->segmentsize);
		APACHE_LOG_DEBUG1("BEGIN TAGGING @ %d",p->cursor);
		p->segments[p->backsegment].itemcount=0;
	}
	void shdata_OpenItemTag(shared_heap* sheap,const char* ID){
		segment_header* sh=&(sheap->page->segments[sheap->page->backsegment]);
		page_item* item;
		item=&(sh->items[sh->itemcount]);
		memset(item->ITEMID,'\0',PAGE_ITEM_CHARS);
		memset(item->INFO,'\0',PAGE_ITEM_CHARS);
		strcpy(item->ITEMID,ID);	
		item->offset=sheap->page->cursor-sheap->page->data;
	}
	void shdata_AppendInfo(shared_heap* sheap,char* info){
		segment_header* sh=&(sheap->page->segments[sheap->page->backsegment]);
		page_item* item=&(sh->items[sh->itemcount]);
		strcat(item->INFO,info);
	}
	void shdata_CloseItemTag(shared_heap* sheap){
		segment_header* sh=&(sheap->page->segments[sheap->page->backsegment]);
		page_item* item;
		item=&(sh->items[sh->itemcount]);
		item->size=sheap->page->cursor-sheap->page->data-item->offset;		
		sh->itemcount++;
	}
	void shdata_CloseItemTagWithInfo(shared_heap* sheap, char* info){
		segment_header* sh=&(sheap->page->segments[sheap->page->backsegment]);
		page_item* item;	
		item=&(sh->items[sh->itemcount]);
		strncpy(item->INFO,info,PAGE_ITEM_CHARS-1);
		shdata_CloseItemTag(sheap);
	}
	int shdata_cursor(shared_heap* sheap){
			if(sheap==NULL||sheap->page==NULL){
				return -1;	
			}
			return sheap->page->cursor-sheap->page->data;
	}
	char* shdata_shpalloc(shared_heap* sheap, int size){
                shared_page* page;
                char* retchar;
                int spaceleft;

                page=sheap->page;
		spaceleft=page->segmentsize-(page->cursor-page->data)+(page->segmentsize*page->backsegment);
                if(spaceleft<size){
					APACHE_LOG_DEBUG("OUT OF SHEAP SPACE");
                    return NULL;
                }
				
                retchar=page->cursor;
                page->cursor+=size;
        return retchar;
    }

	char* shdata_shpcalloc(shared_heap* sheap, int size){
		char* tmp;
		tmp=shdata_shpalloc(sheap,size);
		memset(tmp,0,size);
		return tmp;
	}
	void* shdata_memcpy(shared_heap* sheap, void* src, int size){
		void* ret=NULL;
		
		if(src!=NULL&&size>0){
			ret=shdata_shpcalloc(sheap,size);
			memcpy(ret,src,size);
		}
		return ret;
	}
	
	static apr_sockaddr_t* shdata_copyAddr1(shared_heap* sheap,apr_sockaddr_t* addr){
		apr_sockaddr_t* ret=NULL;
		ret=(apr_sockaddr_t*)shdata_memcpy(sheap,addr,sizeof(apr_sockaddr_t));
		ret->hostname=shdata_32BitString_copy(sheap,addr->hostname);
		ret->hostname=shdata_32BitString_copy(sheap,addr->servname);
		ret->ipaddr_ptr=shdata_memcpy(sheap,addr->ipaddr_ptr,addr->ipaddr_len);
		ret->next=NULL;
		return ret;
	}
	apr_sockaddr_t* shdata_sockAddrCpy(shared_heap* sheap, apr_sockaddr_t* addr){
		apr_sockaddr_t* ret=NULL, *cur=NULL,*curShm=NULL;
		
		if(addr!=NULL){
			cur=addr;
			ret=curShm=shdata_copyAddr1(sheap,addr);
			while(cur->next!=NULL){
				cur=cur->next;
				curShm->next=shdata_copyAddr1(sheap,cur);
				curShm=curShm->next;
			}
		}
		
		return ret;
	}


<|start_filename|>src/oidc-core/rewrite_core.c<|end_filename|>
#include <oidc-core/rewrite_core.h>
#include "common_utils.h"
#include "url_utils.h"

#ifdef NGX_TCREWRITE_PCRE
    #include <pcre.h>
	#include <pcreposix.h>
	static void * oidc_pcre_malloc(size_t size);
	static void oidc_pcre_free(void *ptr);
	static pool* oidc_pcre_malloc_init(pool *new_pool);
	static void oidc_pcre_malloc_done(pool *old_pool);
#else // APACHE PCRE
	#include "httpd.h"

	#if (AP_SERVER_MINORVERSION_NUMBER == 2 || AP_SERVER_MINORVERSION_NUMBER == 4)
	
		#include <ap_config.h>
		#include <ap_regex.h>
	
		typedef ap_regex_t regex_t;
		typedef ap_regmatch_t regmatch_t;
	
		#define REG_ESPACE 			AP_REG_ESPACE
		#define REG_ICASE			AP_REG_ICASE
		#define regcomp(arg1,arg2,arg3)		ap_regcomp(arg1,arg2,arg3)
		#define regfree(arg1)			ap_regfree(arg1)
		#define regexec(arg1,arg2,arg3,arg4,arg5) 	ap_regexec(arg1,arg2,arg3,arg4,arg5)
		//apache2.2 has built-in pcre  but we don't know which version it it, 64-bit compiler stll needs the declaration.
		#ifdef __cplusplus
			extern "C" const char *pcre_version(void);
		#else
			extern const char *pcre_version(void);
		#endif
	
	#else //#if AP_SERVER_MINORVERSION_NUMBER
		#include <pcreposix.h>
	#endif //#ifdef AP_SERVER_MINORVERSION_NUMBER
#endif //#ifdef NGX_TCREWRITE_PCRE
		
			char* rc_getInfo(pool* p){
				return apr_pstrcat(p,"[",REWRITE_CORE_VERSION,"], PCRE ",pcre_version(),NULL);
			}
			int   rc_matchByStrings(pool* p, char* regex, char* value){
				int ret=0;
				regex_t *preg=NULL;


				//do regex match
				preg=apr_palloc(p,sizeof(regex_t));
		#ifdef NGX_TCREWRITE_PCRE
				// set custom pcre func for NGX_TCREWRITE_PCRE
				pool *ip = (pool *) oidc_pcre_malloc_init(p);
		#endif
				ret=regcomp(preg,regex,0);
				if(ret!=0){
		#ifdef NGX_TCREWRITE_PCRE
					// reset pcre func for NGX_PCRE
					oidc_pcre_malloc_done(ip);
		#endif
					return -555;
				}

				ret=regexec(preg,value,0,NULL,0);
				regfree(preg);

		#ifdef NGX_TCREWRITE_PCRE
				// reset pcre func for NGX_TCREWRITE_PCRE
				oidc_pcre_malloc_done(ip);
		#endif
				return ret;
			}
			int   rc_matchByStringsIgnoreCase(pool* p, char* regex, char* value){
				int ret=0;
				regex_t *preg=NULL;


				//do regex match
				preg=apr_palloc(p,sizeof(regex_t));

		#ifdef NGX_TCREWRITE_PCRE
				// set custom pcre func for NGX_TCREWRITE_PCRE
				pool *ip = (pool *) oidc_pcre_malloc_init(p);
		#endif

				ret=regcomp(preg,regex,REG_ICASE);
				if(ret!=0){
		#ifdef NGX_TCREWRITE_PCRE
					// reset pcre func for NGX_TCREWRITE_PCRE
					oidc_pcre_malloc_done(ip);
		#endif
					return -555;
				}

				ret=regexec(preg,value,0,NULL,0);
				regfree(preg);
		#ifdef NGX_TCREWRITE_PCRE
				// reset pcre func for NGX_TCREWRITE_PCRE
				oidc_pcre_malloc_done(ip);
		#endif
				return ret;
			}
			int rc_matchByStringsPattern(pool* p, char* regex, char* value, array_header** matches){
				int ret=0;
				regex_t *preg=NULL;
				regmatch_t pmatch[9];
				int i=0;

				memset(pmatch,-1, sizeof(pmatch));

				//match vars
				array_header* nmatches=NULL;
				char** foundPlace=NULL, *found=NULL;
				int chars=0;

				//do regex match
				preg=apr_palloc(p,sizeof(regex_t));

		#ifdef NGX_TCREWRITE_PCRE
				// set custom pcre func for NGX_TCREWRITE_PCRE
				pool *ip = (pool *) oidc_pcre_malloc_init(p);
		#endif

				ret=regcomp(preg,regex,0);
				if(ret!=0){
		#ifdef NGX_TCREWRITE_PCRE
					// reset pcre func for NGX_TCREWRITE_PCRE
					oidc_pcre_malloc_done(ip);
		#endif
					return -555;
				}
				if(matches!=NULL){
					ret=regexec(preg,value,9,pmatch,0);

					if(pmatch[0].rm_so!=-1){
						nmatches=apr_array_make(p,4,sizeof(char*));
						for(i=0;i<9;i++){
							if(pmatch[i].rm_so!=-1){
								chars=pmatch[i].rm_eo-pmatch[i].rm_so;
								found=apr_pstrndup(p,value+(int)pmatch[i].rm_so,chars);

								foundPlace=(char**)apr_array_push(nmatches);
								*foundPlace=found;
							}
						}

						*matches=nmatches;
					}
				}else{
					ret=regexec(preg,value,0,NULL,0);
				}
				regfree(preg);

		#ifdef NGX_TCREWRITE_PCRE
				// reset pcre func for NGX_TCREWRITE_PCRE
				oidc_pcre_malloc_done(ip);
		#endif
				return ret;
			}
			char* rc_matchByStringsPatternReturnDetails(pool* p, char* regex, char* value, array_header** matches){
				int ret=0;

				ret=rc_matchByStringsPattern(p,regex,value,matches);
				if(ret==-555){
					return apr_pstrdup(p,"error - compiling regex");
				}

				if(ret!=0){
					if(ret==REG_ESPACE){
						return apr_pstrdup(p,"error - matching took excessive memory");
					}else{
						return apr_pstrdup(p,"NO MATCH");
					}
				}
				return NULL;
			}

			char* rc_matchByStringsReturnDetails(pool* p, char* regex, char* value){
				int ret=0;

				ret=rc_matchByStrings(p,regex,value);
				if(ret==-555){
					return apr_pstrdup(p,"error - compiling regex");
				}

				if(ret!=0){
					if(ret==REG_ESPACE){
						return apr_pstrdup(p,"error - matching took excessive memory");
					}else{
						return apr_pstrdup(p,"NO MATCH");
					}
				}
				return NULL;
			}

	int rc_isRegexValid(pool* p,char* regex){
		if(regex==NULL||rc_matchByStrings(p,regex,"")==-555){
			return 0;	
		}
		return 1;
	}			

#ifdef NGX_TCREWRITE_PCRE

pool* oidc_pcre_pool=NULL;

static void *(*old_pcre_malloc)(size_t);
static void (*old_pcre_free)(void *ptr);


/* XXX: work-around to nginx regex subsystem, must init a memory pool
 * * to use PCRE functions. As PCRE still has memory-leaking problems,
 * * and nginx overwrote pcre_malloc/free hooks with its own static
 * * functions, so nobody else can reuse nginx regex subsystem... */

static void * oidc_pcre_malloc(size_t size)
{
	if (oidc_pcre_pool) {
		return apr_palloc(oidc_pcre_pool, size);
	}

	fprintf(stderr, "error: iota pcre malloc failed due to empty pcre pool");

	return NULL;
}


static void oidc_pcre_free(void *ptr)
{
	if (oidc_pcre_pool) {
		//apr_pool_clear(ptr);
		return;
	}

	fprintf(stderr, "error: iota pcre free failed due to empty pcre pool");
}


static pool* oidc_pcre_malloc_init(pool *new_pool)
{
	pool* old_pool;

	if (pcre_malloc != oidc_pcre_malloc) {

		oidc_pcre_pool = new_pool;

		old_pcre_malloc = pcre_malloc;
		old_pcre_free = pcre_free;

		pcre_malloc = oidc_pcre_malloc;
		pcre_free = oidc_pcre_free;

		return NULL;
	}

	old_pool = oidc_pcre_pool;
	oidc_pcre_pool = new_pool;

	return old_pool;
}


static void oidc_pcre_malloc_done(pool *old_pool)
{
    oidc_pcre_pool = old_pool;

    if (old_pool == NULL) {
        pcre_malloc = old_pcre_malloc;
        pcre_free = old_pcre_free;
    }
}

#endif /* NGX_TCREWRITE_PCRE */


<|start_filename|>src/json-api-core/json_parser.h<|end_filename|>
#ifndef JSON_PARSER_H
#define JSON_PARSER_H
#include "apache_typedefs.h"

#ifdef __cplusplus
extern "C"
{
#endif

enum {
	JSON_False=0,
	JSON_True=1,
	JSON_NULL=2,
	JSON_Number=3,
	JSON_String=4,
	JSON_Array=5,
	JSON_Object=6
};

#define JSON_IsReference 256

//Forward declaration.

typedef struct Value Value;

// Supply a block of JSON, and this returns a JSON object you can interrogate.
Value* JSON_Parse(pool* p, const char *value);
// Render a JSON entity to text for transfer/storage.
char* JSON_Serialize(pool* p, Value *item);
// Render a JSON entity to text for transfer/storage without any formatting.
char* JSON_SerializeUnformatted(pool* p,Value *item);

// Returns the number of items in an array (or object).
int	JSON_GetArraySize(Value *array);
// Retrieve item number "item" from array "array". Returns NULL if unsuccessful.
Value* JSON_GetArrayItem(Value *array,int item);
// Get item "string" from object. Case insensitive.
Value* JSON_GetObjectItem(Value *object,const char *string);

typedef void (*peek_item_callback) (Value* value, void* data);
void JSON_IterateObjectItemCallback(Value *object, void* data, peek_item_callback peekItemCallback);

// Get item string.
const char* JSON_GetItemString(Value *item);
// Get string fron string type item.
const char* JSON_GetStringFromStringItem(Value *item);
// Get number fron number item.
int JSON_GetNumberFromNumberItem(Value *item);
// Get double fron number item.
double JSON_GetDoubleFromNumberItem(Value *item);
// Get item type.
int JSON_GetItemType(Value *item);

// These calls create a JSON item of the appropriate type.
Value* JSON_CreateNull(pool* p);
Value* JSON_CreateTrue(pool* p);
Value* JSON_CreateFalse(pool* p);
Value* JSON_CreateNumber(pool* p,double num);
Value* JSON_CreateString(pool* p,const char *string);
Value* JSON_CreateArray(pool* p);
Value* JSON_CreateObject(pool* p);

// These utilities create an Array of count items.
Value* JSON_CreateIntArray(pool* p,int *numbers,int count);
Value* JSON_CreateFloatArray(pool* p,float *numbers,int count);
Value* JSON_CreateDoubleArray(pool* p,double *numbers,int count);
Value* JSON_CreateStringArray(pool* p,const char **strings,int count);

// Append item to the specified array/object.
void JSON_AddItemToArray(pool* p,Value *array, Value *item);
void JSON_AddItemToObject(pool* p,Value *object,const char *string,Value *item);
// Append reference to item to the specified array/object. Use this when you want to add an existing JSON to a new JSON, but don't want to corrupt your existing JSON.
void JSON_AddItemReferenceToArray(pool* p,Value *array, Value *item);
void JSON_AddItemReferenceToObject(pool* p,Value *object,const char *string,Value *item);

// Remove/Detatch items from Arrays/Objects.
Value* JSON_DetachItemFromArray(Value *array,int which);
void   JSON_DeleteItemFromArray(Value *array,int which);
Value* JSON_DetachItemFromObject(Value *object,const char *string);
void   JSON_DeleteItemFromObject(Value *object,const char *string);

// Update array items.
void JSON_ReplaceItemInArray(Value *array,int which,Value *newitem);
void JSON_ReplaceItemInObject(pool* p,Value *object,const char *string,Value *newitem);

#define JSON_AddNullToObject(p,object,name)      JSON_AddItemToObject(p,object, name, JSON_CreateNull(p))
#define JSON_AddTrueToObject(p,object,name)      JSON_AddItemToObject(p,object, name, JSON_CreateTrue(p))
#define JSON_AddFalseToObject(p,object,name)     JSON_AddItemToObject(p,object, name, JSON_CreateFalse(p))
#define JSON_AddNumberToObject(p,object,name,n)  JSON_AddItemToObject(p,object, name, JSON_CreateNumber(p,n))
#define JSON_AddStringToObject(p,object,name,s)  JSON_AddItemToObject(p,object, name, JSON_CreateString(p,s))

#ifdef __cplusplus
}
#endif

#endif // #if JSON_PARSER_H



<|start_filename|>src/unit-test/runalltest.c<|end_filename|>
#include <stdlib.h>
#include <apr_general.h>
#include <apr_pools.h>
#include <stdio.h>
#include <assert.h>
#include <CuTest.h>
#include <logging.h>

// Declare xxx_GetSuite() from xxx module here
// i.e. CuSuite* prodDefinitions_GetSuite();
static int die(int exitCode, const char *message, apr_status_t reason) {
    char msgbuf[80];
	apr_strerror(reason, msgbuf, sizeof(msgbuf));
	fprintf(stderr, "%s: %s (%d)\n", message, msgbuf, reason);
	exit(exitCode);
	return reason;
}

static void terminate()
{
   apr_terminate();
}
static apr_pool_t* initializePool()
{
	apr_status_t rc;
	apr_pool_t *pool;
	rc = apr_initialize();
	rc==APR_SUCCESS || die(-2, "Could not initialize !", rc);
	//atexit(terminate);	
	
	rc = apr_pool_create(&pool, NULL);
	rc==APR_SUCCESS || die(-2, "Could not allocate pool", rc);
	return pool;
}
static void destroyPool(apr_pool_t*p){
	apr_pool_destroy(p);
}

CuSuite* oidccore_GetSuite();

void RunAllTests(void) {
	CuString *output = CuStringNew();
	CuSuite* suite = CuSuiteNew();
	apr_pool_t*pool=NULL;
	mm_logger* logger=NULL;
	char* logsDir="./unit-test"; //Write the log in current directory.
	char logBuff[512];
	apr_status_t status;
	int size=2;
	
	setbuf(stdout, NULL);
	printf("Initializing pool...");
	pool=initializePool();
	if(pool==NULL){
		printf("FAILURE\r\n");
		printf("Could not initialize pool\r\n");
	}else{
		printf("OK\r\n");
	}
	
	sprintf(logBuff,"%s/results.txt",logsDir);
	//Remove any existing log file.
	apr_file_remove(logBuff,pool);
	
	printf("Initializing logger...");
	logger=logging_getLogger(pool,logBuff,size);
	if(logger==NULL){
		printf("FAILURE\r\n");
		printf("Could not initialize logger\r\n");
	}else{
		printf("OK\r\n");
	}
	
	printf("Check the results for unit test result in unit-test/results.txt \r\n");
	/* Add a new suite from xxx module here
	** i.e.  CuSuiteAddSuite(suite, xxx_GetSuite());
	*/
	CuSuiteAddSuite(suite, oidccore_GetSuite());
	
	//Run and print the summary
	CuSuiteRun(logger,suite);
	CuSuiteSummary(suite, output);
	CuSuiteDetails(suite, output);
	logging_printf(logger,"%s\n", output->buffer);
	printf("%s\n", output->buffer);
	
	   // write the results to html	
	mm_logger* html=NULL;
	sprintf(logBuff, "%s/summary.html", logsDir);

	apr_file_remove(logBuff, pool);

	printf("Writing to html...");
	html=logging_getLogger(pool,logBuff,size);
	if(html!=NULL){
		CuSuiteResultsToHtml(suite, html);
	}else{
		printf("FAILURE:Could not initialize html document\r\n\r\n");
	}
	
	destroyPool(logger->p);
	
	//Close the log file.
	logging_closeLogger(logger);
}

int main(int argc, char**argv) {
   RunAllTests();
   return 0;
}



<|start_filename|>src/log-utils/logging.c<|end_filename|>
#include <unistd.h>
#include <apr_time.h>
#include <sys/stat.h>
#include "logging.h"
#include "common_utils.h"

	#define BUFFERSIZE 2048

	mm_logger* logging_getLogger(pool* p,char* path,long maxLogFileSizeMB){
		apr_status_t rc;
		if(path==NULL) return NULL;
		
		mm_logger* ret=(mm_logger*)apr_pcalloc(p,sizeof(mm_logger));
		ret->filepath=apr_pstrdup(p,path);
		ret->maxLogFileSizeMB=maxLogFileSizeMB;

		if((rc=apr_file_open(&(ret->file),path,APR_READ|APR_WRITE|APR_CREATE|APR_APPEND,APR_OS_DEFAULT,p))!=APR_SUCCESS){
			return NULL;
		}
		
		ret->p=p;
		return ret;
	}
	
	
	void logging_log(mm_logger* log,const char* a_format, ...){
		va_list va;
		//int i=0;
		apr_time_t tnow;
		char tbuf[64];
		char buffer[BUFFERSIZE];
		memset(buffer, '\0', BUFFERSIZE);
		
		if(log->maxLogFileSizeMB>0) logging_rotateLogFile(log);

		va_start(va, a_format);
		vsnprintf(buffer, BUFFERSIZE-1, a_format, va);
		
		tnow=apr_time_now();
		memset(tbuf,'\0',64);
		apr_ctime(tbuf,tnow);
		apr_file_printf(log->file,"%s mm.monitor.refresh [%d] %s\r\n",tbuf,getpid(),buffer);
		va_end(va);
	}

	int logging_rotateLogFile(mm_logger* log){
		mm_logger* ltmp;
		apr_finfo_t finfo;
		apr_time_t tnow;
		apr_time_exp_t texp;
		apr_status_t st;
		apr_size_t tbuflen,tbufmax=64;
		char tbuf[64],*newPath;

		st=apr_stat(&finfo,log->filepath,APR_FINFO_SIZE,log->p);

		if(finfo.size > log->maxLogFileSizeMB*1024*1024){
			apr_file_printf(log->file,"Monitor File Size [%dB], Max Value [%dB].\r\n",finfo.size,log->maxLogFileSizeMB*1024*1024);
			logging_closeLogger(log);
			log->file=NULL;

			tnow=apr_time_now();
			memset(tbuf,'\0',64);
			apr_time_exp_lt(&texp,tnow);
			apr_strftime(tbuf,&tbuflen,tbufmax,"%F-%H_%M_%S",&texp);
			newPath=apr_psprintf(log->p,"%s.%s.%d",log->filepath,tbuf,texp.tm_usec);
			apr_file_rename(log->filepath,newPath,log->p);
			ltmp=logging_getLogger(log->p,log->filepath,log->maxLogFileSizeMB);
			log->file=ltmp->file;

			return TRUE;
		}
		return FALSE;
	}

	void logging_printf(mm_logger* log,const char* a_format, ...){
		va_list va;
		//int i=0;
		//apr_time_t tnow;
		//char tbuf[64];
		char buffer[BUFFERSIZE];
		memset(buffer, '\0', BUFFERSIZE);
		
		va_start(va, a_format);
		vsnprintf(buffer, BUFFERSIZE-1, a_format, va);
		apr_file_printf(log->file,"%s\r\n",buffer);
		va_end(va);
	}		
	//Returns True if file successully closed.
	int logging_closeLogger(mm_logger* log){
		apr_status_t rc;
		if(log==NULL) return FALSE;
		if((rc=apr_file_close(log->file))!=APR_SUCCESS){
			return FALSE;
		}
		return TRUE;
	}
	void logging_setMaxFileSize(mm_logger* log,int maxLogFileSizeMB){
		log->maxLogFileSizeMB=maxLogFileSizeMB;
	}
	
// startup logs
	
	// startup log
	#define MAX_LOGFILE_SIZE 51200
	
	typedef struct process_logger {
		mm_logger logger;
		apr_status_t status;
		int pid;
	}process_logger;
		
	static process_logger refreshLogger;
	
	int lc_openLogFile(apr_pool_t* p,char* filepath){
		
		if(filepath==NULL){
			//printf("\nLogfile name not specified \n");
			return FALSE;
		}
		refreshLogger.status=apr_file_open(&refreshLogger.logger.file,filepath,APR_APPEND | APR_WRITE | APR_CREATE,APR_OS_DEFAULT,p);
		if(refreshLogger.status!=APR_SUCCESS){
		//printf("\nFailed to open logfile - %s\n", filepath);
		}
		refreshLogger.logger.p=p;
		refreshLogger.logger.filepath=apr_pstrdup(p,filepath);
		refreshLogger.logger.maxLogFileSizeMB=2;
		refreshLogger.pid=getpid();
		
		return refreshLogger.status;
	}
		
	int lc_closeLogFile(void){
		int cur_pid=getpid();
		if(refreshLogger.status!=APR_SUCCESS||cur_pid!=refreshLogger.pid){
			//printf("\nFailed to close logfile - %s\n", filepath);
			return FALSE;
		}
		apr_file_close(refreshLogger.logger.file);
		refreshLogger.status=-1;
		return APR_SUCCESS;
	}
		
	int lc_rotateLogFile(){
		apr_status_t status=0;
		int cur_pid;
		cur_pid=getpid();
		if(refreshLogger.status!=APR_SUCCESS||cur_pid!=refreshLogger.pid){
			//printf("\nLogfile has not been opened.\n");
			return FALSE;
		}

		lc_closeLogFile();

		apr_time_t tnow;
		apr_time_exp_t texp;
		apr_size_t tbuflen,tbufmax=64;
		char tbuf[64],*renamedPath;

		tnow=apr_time_now();
		memset(tbuf,'\0',64);
		apr_time_exp_lt(&texp,tnow);
		apr_strftime(tbuf,&tbuflen,tbufmax,"%F-%H_%M_%S",&texp);
		renamedPath=apr_psprintf(refreshLogger.logger.p,"%s.%s.%d",refreshLogger.logger.filepath,tbuf,texp.tm_usec);
		status = apr_file_rename(refreshLogger.logger.filepath,renamedPath,refreshLogger.logger.p);
		// open a new file
		status = lc_openLogFile(refreshLogger.logger.p, refreshLogger.logger.filepath);
		return status;
	}

	int lc_truncateLogFile(void){
		apr_status_t status=0;
		int cur_pid=getpid();
		if(refreshLogger.status!=APR_SUCCESS||cur_pid!=refreshLogger.pid){
			//printf("\nLogfile has not been opened.\n");
			return FALSE;
		}
		status=apr_file_trunc(refreshLogger.logger.file,0);
		//if(status!=APR_SUCCESS)
			//printf("\nFailed to truncate logfile - %s\n", refreshLogger.filepath);
		
		return status;
	}
		
	int lc_trimLogFile(void){
		//To ensure that logfile size never grows to a crazy size
		struct stat file_stat;
		
		int rc = stat(refreshLogger.logger.filepath,&file_stat);
		if(rc == 0 && file_stat.st_size > MAX_LOGFILE_SIZE){
			lc_rotateLogFile();
			return TRUE;
		}
		return FALSE;
	}
		
	int lc_printLog(const char* format,...){
		
		va_list ap;
		apr_size_t out_bytes;
		char logs[1024];
		apr_status_t status=0;
		int cur_pid;
		
		//Print to stdout to keep current behaviour
		va_start(ap,format);
		vfprintf(stdout,format,ap);
		va_end(ap);
		
		va_start(ap,format);
		vsprintf(logs,format,ap);
		va_end(ap);
		
		lc_trimLogFile();
		cur_pid=getpid();
		
		if(refreshLogger.status!=APR_SUCCESS||cur_pid!=refreshLogger.pid){
			//printf("\nLogfile has not been opened by this pool.\n");
			return FALSE;
		}
		status=apr_file_write_full(refreshLogger.logger.file,logs,strlen(logs),&out_bytes);
		//if(status!=APR_SUCCESS)
			//printf("\nFailed to write logfile - %s\n", refreshLogger.filepath);
		
		return status;
	}		


<|start_filename|>src/oidc-core/match_list.h<|end_filename|>
#ifndef MATCH_LIST_H_
#define MATCH_LIST_H_

	typedef struct mlx_match_event{
		time_t start;
		time_t end;
	}mlx_match_event;

	typedef struct mlx_match_header{
		char* name;
		char* value;
		char* delimAnd;
		int negate;
		int isRegex;
	}mlx_match_header;

	typedef struct mlx_match_ip{
		char* ip;
		int negate;
		int isRegex;
	}mlx_match_ip;

	typedef struct mlx_match_path{
		char* path;
		int negate;
	}mlx_match_path;
	
	typedef struct mlx_match_env{
		char* name;
		char* value;
		int negate;
		int isRegex;
	}mlx_match_env;
	
	typedef struct mlx_ml_match{
		char* host;
		int cascade;		
		mlx_match_path*	path;
		mlx_match_ip* ip;
		array_header* headerList;
		mlx_match_event* event;
	}mlx_ml_match;
	
	typedef struct mlx_matchlist{
		char* name;
		array_header* matches;
	}mlx_matchlist;
	
	mlx_match_event* ml_newMatchEventObj(pool*p);
	mlx_match_ip*ml_newMatchIpObj(pool*p);
	mlx_match_path*ml_newMatchPathObj(pool*p);
	mlx_match_header* ml_newMatchHeaderObj(pool* p);
	mlx_match_env* ml_newMatchEnvObj(pool* p);
	mlx_ml_match* ml_newMatchListMatchObj(pool* p);
//	mlx_match_header* ml_newMatchHeaderObjExt(pool* p,char*name,char*value,char* delimAnd,char* negate,char* isregex);
	int ml_isSubsetFound(pool*p,array_header* subset, array_header* set,int isRegex);
	int ml_isNegateSubsetFound(pool*p,array_header* subset, array_header* set, int isRegex);
	int matchList_isMatched(pool*p,char* regex, char* value, int isRegex);
	int matchList_isHostMatched(pool*p, char* matchHost, apr_table_t *headers_in);
	void ml_printMatchList(pool* p, array_header* arr);
#endif /*MATCH_LIST_H_*/



<|start_filename|>src/service-utils/http-utils/http_client.c<|end_filename|>
#include <http-utils/http_client.h>

//curl stuff
#include <curl/curl.h>
//#include <curl/types.h>
#include <curl/easy.h>

void hc_init(){
	curl_global_init(CURL_GLOBAL_ALL);
}
char* hc_getInfo(apr_pool_t* p){
	return curl_version();
}
void hc_cleanup(){
		curl_global_cleanup();
}

int hc_is200_OK(http_util_result* ret){
	return ret!=NULL&&ret->responseCode==200;	
}

static size_t hc_memory_callback(void* ptr,size_t size, size_t nmemb, void* data){
	size_t realsize=size*nmemb;
	http_util_result* res=(http_util_result*)data;
	char* tmp=NULL;
	if(res->size<=0){
		res->size=realsize;
		res->data=apr_pcalloc(res->p,realsize+1);
		memcpy(res->data,ptr,realsize);
		//res->data=(char*)apr_pstrndup(res->p,ptr,realsize);
	}else{
		tmp=apr_pcalloc(res->p,res->size+realsize+1);
		memcpy(tmp,res->data,res->size);
		res->data=tmp;
		memcpy(tmp+res->size,ptr,realsize);
		res->size+=realsize;
		//res->data=(char*)apr_pstrcat(res->p,res->data,apr_pstrndup(res->p,(char*)ptr,realsize),NULL);
	}
	
	
	return realsize;
}

static http_util_result* hc_createNewHttpUtilResult(apr_pool_t *p){
	http_util_result* ret=ret=apr_pcalloc(p,sizeof(http_util_result));
	ret->p=p;
	ret->data=NULL;
	ret->content_type=NULL;
	ret->size=0;
	ret->totalTime=0.0;
	ret->responseCode=-1;
	ret->headers_out=NULL;
	return ret;	
}


static void hc_setBasicAuthOpts(CURL *curl_handle,char* userAndPass){
		curl_easy_setopt(curl_handle,CURLOPT_HTTPAUTH,CURLAUTH_BASIC);
		curl_easy_setopt(curl_handle,CURLOPT_USERPWD,userAndPass);
}


http_util_result* hc_head_verbose(apr_pool_t *p,char* uri,long timeout,char* userColonPass,char** error){
	CURL *curl_handle=NULL;
		CURLcode res;
		
		http_util_result* ret=hc_createNewHttpUtilResult(p);		
		
		curl_handle=curl_easy_init();
		curl_easy_setopt(curl_handle, CURLOPT_URL,uri);
		curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION,hc_memory_callback);
		curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA,ret);
		curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, HTTP_USER_AGENT);
		curl_easy_setopt(curl_handle, CURLOPT_NOSIGNAL, 1);
		curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT, timeout);
		curl_easy_setopt(curl_handle, CURLOPT_CONNECTTIMEOUT, 5);
		curl_easy_setopt(curl_handle, CURLOPT_CUSTOMREQUEST, "HEAD");
		/*SSL Options*/ 
		//Allow connect to server using self signed certificate
		curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, FALSE);
		
		//Allow connect to server with cert hostname (CN) not matching connect string
		curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 0);
		
		if(userColonPass!=NULL){
			hc_setBasicAuthOpts(curl_handle,userColonPass);
		}
		
		//perform
		res=curl_easy_perform(curl_handle);
		if(error!=NULL&&res!=CURLE_OK&&res!=CURLE_PARTIAL_FILE){
			*error=apr_pstrdup(p,curl_easy_strerror(res));
		}

		//get option info
		res = curl_easy_getinfo(curl_handle, CURLINFO_TOTAL_TIME, &(ret->totalTime));
		res = curl_easy_getinfo(curl_handle, CURLINFO_RESPONSE_CODE, &(ret->responseCode));
		res = curl_easy_getinfo(curl_handle, CURLINFO_CONTENT_TYPE, &(ret->content_type));
		if(ret->content_type!=NULL){
			ret->content_type=apr_pstrdup(p,ret->content_type);	
		}		
		curl_easy_cleanup(curl_handle);
		if(ret!=NULL&&ret->responseCode!=0){
			return ret;
		}
		return NULL;
}

typedef struct header_cyc{
	struct curl_slist * slist;
	apr_pool_t* p;	
}header_cyc;

static int hc_bind_headers(void *rec, const char *key, const char *value){
	header_cyc* hcyc=(header_cyc*)rec;
	char* val=NULL;
	if(key!=NULL){
		if(value!=NULL){
			val=apr_pstrcat(hcyc->p,key,":",value,NULL);
		}else{
			val=apr_pstrcat(hcyc->p,key,":",NULL);
		}
//		fprintf(stderr,"Header: %s\n",val);
//		fflush(stderr);
		hcyc->slist = curl_slist_append(hcyc->slist, val);
	}
	return 1;
}

typedef struct header_out_pack{
	apr_table_t* headers_out;
	apr_pool_t* pool;
	int cnt;
}header_out_pack;

static char* hc_getTrimmedStr(apr_pool_t* p, char* str){
	char* start=NULL,*end=NULL;
	int len=0,size=0;
	
	if(str==NULL){
		return NULL;
	}
	
	start=str;
	while(*start!='\0'&&(*start==' '||*start=='\t'||*start=='\n'||*start=='\r')){
		start++;
	}
	len=strlen(str);
	end=&(str[len-1]);
	while(*end!='\0'&&(*end==' '||*end=='\t'||*end=='\n'||*end=='\r')){
		end--;
	}
	
	size=end-start+1;
	if(size<=0){return NULL;}
	return apr_pstrndup(p,start,size);
}

static int hc_isContentChunked(apr_pool_t*p, char* contentType){
	char* tmp=hc_getTrimmedStr(p,contentType);
	return (tmp!=NULL&&strcasecmp(tmp,"chunked")==0)?TRUE:FALSE;
}

static size_t hc_bind_headers_out(void *ptr, size_t size, size_t nmemb, void *userdata){
	size_t retSize=size*nmemb;
	char* data=NULL;
	char* p1=NULL, *p2=NULL, *cursor=NULL, *cend=NULL;
	http_util_result* ret=(http_util_result*)userdata;
	
	
	data=(char*)apr_pstrndup(ret->p,ptr,retSize);
	cursor=strstr(data,":");

	if(cursor!=NULL){
		*cursor='\0';
		cursor++;
		cend=strstr(cursor,"\r");
		if(cend!=NULL){
			*cend='\0';
			//
			if(1/*strcasecmp(data,"location")==0||strcasecmp(data,"set-cookie")==0
					||strcasecmp(data,"set-cookie2")==0||strcasecmp(data,"www-authenticate")==0
					||strcasecmp(data,"content-encoding")==0||strcasecmp(data,"vary")==0
					||strcasecmp(data,"content-disposition")==0
					||strcasecmp(data,"content-transfer-encoding")==0
					||(strcasecmp(data,"transfer-encoding")==0&&!hc_isContentChunked(ret->p,cursor))*/){
				apr_table_setn(ret->headers_out,apr_pstrdup(ret->p,data),cursor);
			}else{
				apr_table_setn(ret->headers_out,apr_pstrcat(ret->p,"X-P-",data,NULL),cursor);		
			}
		}
	}
	return retSize;
}


static void hc_setup_headerbind(apr_pool_t *p,CURL *curl_handle,http_util_result* ret,apr_table_t * headers_in){
	header_cyc headcyc;
	if(headers_in!=NULL){
			headcyc.p=p;
			headcyc.slist=NULL;
			apr_table_do(hc_bind_headers,&headcyc,headers_in,NULL);
			if(headcyc.slist!=NULL){
				curl_easy_setopt(curl_handle, CURLOPT_HTTPHEADER, headcyc.slist);
			}
			
			//capture headers out
			ret->headers_out=apr_table_make(p,8);
			curl_easy_setopt(curl_handle, CURLOPT_HEADERFUNCTION, hc_bind_headers_out);
			curl_easy_setopt(curl_handle, CURLOPT_WRITEHEADER,ret); 
	}	
}

http_util_result* hc_get_verbose(apr_pool_t *p,char* uri,long timeout,char* userColonPass, apr_table_t * headers_in,char** error){
		CURL *curl_handle=NULL;
		CURLcode res;
//		header_cyc headcyc;
//		header_out_pack houtp;
//		apr_table_t* headers_out=NULL;
		http_util_result* ret=hc_createNewHttpUtilResult(p);		
		
		curl_handle=curl_easy_init();
//		curl_easy_setopt(curl_handle, CURLOPT_VERBOSE, 1);
		curl_easy_setopt(curl_handle, CURLOPT_URL,uri);
		curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION,hc_memory_callback);
		curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA,ret);
		curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, HTTP_USER_AGENT);
		curl_easy_setopt(curl_handle, CURLOPT_NOSIGNAL, 1);
		curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT, timeout);
		curl_easy_setopt(curl_handle, CURLOPT_CONNECTTIMEOUT, 5);
		hc_setup_headerbind(p,curl_handle,ret,headers_in);

		
		/*SSL Options*/ 
		//Allow connect to server using self signed certificate
		curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, FALSE);
		
		//Allow connect to server with cert hostname (CN) not matching connect string
		curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 0);
		
		if(userColonPass!=NULL){
			hc_setBasicAuthOpts(curl_handle,userColonPass);
		}
		
		//perform
		res=curl_easy_perform(curl_handle);
		if(error!=NULL&&res!=CURLE_OK){
			*error=apr_pstrdup(p,curl_easy_strerror(res));
		}
		
		//get option info
		res = curl_easy_getinfo(curl_handle, CURLINFO_TOTAL_TIME, &(ret->totalTime));
		res = curl_easy_getinfo(curl_handle, CURLINFO_RESPONSE_CODE, &(ret->responseCode));
		res = curl_easy_getinfo(curl_handle, CURLINFO_CONTENT_TYPE, &(ret->content_type));
		if(ret->content_type!=NULL){
			ret->content_type=apr_pstrdup(p,ret->content_type);	
		}
		
		curl_easy_cleanup(curl_handle);
//		fprintf(stderr,"Response: %d\n",ret->responseCode);
//		fprintf(stderr,"ResponseSize: %d\n",ret->size);
//		fflush(stderr);
		if(ret!=NULL&&ret->responseCode!=0){
			return ret;
		}
		return NULL;
}
http_util_result* hc_get_verbose2(apr_pool_t *p,char* uri,long timeout,long connectionTimeout,char* userColonPass, apr_table_t * headers_in,char** error){
		CURL *curl_handle=NULL;
		CURLcode res;
//		header_cyc headcyc;
//		header_out_pack houtp;
//		apr_table_t* headers_out=NULL;
		http_util_result* ret=hc_createNewHttpUtilResult(p);		
		
		curl_handle=curl_easy_init();
//		curl_easy_setopt(curl_handle, CURLOPT_VERBOSE, 1);
		curl_easy_setopt(curl_handle, CURLOPT_URL,uri);
		curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION,hc_memory_callback);
		curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA,ret);
		curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, HTTP_USER_AGENT);
		curl_easy_setopt(curl_handle, CURLOPT_NOSIGNAL, 1);
		curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT, timeout);
		curl_easy_setopt(curl_handle, CURLOPT_CONNECTTIMEOUT, connectionTimeout);
		hc_setup_headerbind(p,curl_handle,ret,headers_in);

		
		/*SSL Options*/ 
		//Allow connect to server using self signed certificate
		curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, FALSE);
		
		//Allow connect to server with cert hostname (CN) not matching connect string
		curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 0);
		
		if(userColonPass!=NULL){
			hc_setBasicAuthOpts(curl_handle,userColonPass);
		}
		
		//perform
		res=curl_easy_perform(curl_handle);
		if(error!=NULL&&res!=CURLE_OK){
			*error=apr_pstrdup(p,curl_easy_strerror(res));
		}
		
		//get option info
		res = curl_easy_getinfo(curl_handle, CURLINFO_TOTAL_TIME, &(ret->totalTime));
		res = curl_easy_getinfo(curl_handle, CURLINFO_RESPONSE_CODE, &(ret->responseCode));
		res = curl_easy_getinfo(curl_handle, CURLINFO_CONTENT_TYPE, &(ret->content_type));
		if(ret->content_type!=NULL){
			ret->content_type=apr_pstrdup(p,ret->content_type);	
		}
		
		curl_easy_cleanup(curl_handle);
//		fprintf(stderr,"Response: %d\n",ret->responseCode);
//		fprintf(stderr,"ResponseSize: %d\n",ret->size);
//		fflush(stderr);
		if(ret!=NULL&&ret->responseCode!=0){
			return ret;
		}
		return NULL;
}

http_ssl_options* hc_createNewHttpSSLOptions(apr_pool_t *p) {
	http_ssl_options* ret=ret=apr_palloc(p,sizeof(http_ssl_options));
	ret->certType=NULL;
	ret->certFile=NULL;
	ret->passPhrase=NULL;
	ret->keyType=NULL;
	ret->keyName=NULL;
	ret->caCertFile=NULL;
	return ret;	
}

http_util_result* hc_ssl_get_verbose(apr_pool_t *p,char* uri,long timeout,long connectionTimeout,char* userColonPass, http_ssl_options* sslOptions, apr_table_t * headers_in, char** error) {
	CURL *curl_handle=NULL;
	CURLcode res;
//		header_cyc headcyc;
//		header_out_pack houtp;
//		apr_table_t* headers_out=NULL;
	http_util_result* ret=hc_createNewHttpUtilResult(p);		
	
	curl_handle=curl_easy_init();
//		curl_easy_setopt(curl_handle, CURLOPT_VERBOSE, 1);
	curl_easy_setopt(curl_handle, CURLOPT_URL,uri);
	curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION,hc_memory_callback);
	curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA,ret);
	curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, HTTP_USER_AGENT);
	curl_easy_setopt(curl_handle, CURLOPT_NOSIGNAL, 1);
	curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT, timeout);
	curl_easy_setopt(curl_handle, CURLOPT_CONNECTTIMEOUT, connectionTimeout);
	hc_setup_headerbind(p,curl_handle,ret,headers_in);


	/*SSL Options*/
	if(sslOptions!=NULL) {
		/* since PEM is default, we needn't set it for PEM */
		if(sslOptions->certType!=NULL) {
			curl_easy_setopt(curl_handle,CURLOPT_SSLCERTTYPE,sslOptions->certType);
		}
	
		/* set the cert for client authentication */
		if(sslOptions->certFile!=NULL) {
			curl_easy_setopt(curl_handle,CURLOPT_SSLCERT,sslOptions->certFile);
		}
	
		/* ket passphrase */
		if(sslOptions->passPhrase!=NULL) {
			curl_easy_setopt(curl_handle,CURLOPT_SSLKEYPASSWD,sslOptions->passPhrase);
		}
	
      /* if we use a key stored in a crypto engine,
         we must set the key type to "ENG" */
		if(sslOptions->keyType!=NULL) {
			curl_easy_setopt(curl_handle,CURLOPT_SSLKEYTYPE,sslOptions->keyType);
		}
 
      /* set the private key (file or ID in engine) */
		if(sslOptions->keyName!=NULL) {
			curl_easy_setopt(curl_handle,CURLOPT_SSLKEY,sslOptions->keyName);
		}
 
		if(sslOptions->caCertFile!=NULL) {
			/* set the file with the certs vaildating the server */ 
			curl_easy_setopt(curl_handle,CURLOPT_CAINFO,sslOptions->caCertFile);
	 
			/* disconnect if we can't validate server's cert */ 
			curl_easy_setopt(curl_handle,CURLOPT_SSL_VERIFYPEER,1L);
		}else{
	      
			//Allow connect to server using self signed certificate
			curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, FALSE);
		
			//Allow connect to server with cert hostname (CN) not matching connect string
			curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 0);
		}
	}else{		
		//Allow connect to server using self signed certificate
		curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, FALSE);
		
		//Allow connect to server with cert hostname (CN) not matching connect string
		curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 0);
	}
	
	if(userColonPass!=NULL){
		hc_setBasicAuthOpts(curl_handle,userColonPass);
	}
  
	//perform
	res=curl_easy_perform(curl_handle);
	if(error!=NULL&&res!=CURLE_OK){
		*error=apr_pstrdup(p,curl_easy_strerror(res));
	}
	
	//get option info
	res = curl_easy_getinfo(curl_handle, CURLINFO_TOTAL_TIME, &(ret->totalTime));
	res = curl_easy_getinfo(curl_handle, CURLINFO_RESPONSE_CODE, &(ret->responseCode));
	res = curl_easy_getinfo(curl_handle, CURLINFO_CONTENT_TYPE, &(ret->content_type));
	if(ret->content_type!=NULL){
		ret->content_type=apr_pstrdup(p,ret->content_type);	
	}
	
	curl_easy_cleanup(curl_handle);
//		fprintf(stderr,"Response: %d\n",ret->responseCode);
//		fprintf(stderr,"ResponseSize: %d\n",ret->size);
//		fflush(stderr);
	if(ret!=NULL&&ret->responseCode!=0){
		return ret;
	}
	return NULL;
}

http_util_result* hc_get(apr_pool_t *p,char* uri,long timeout){
	return hc_get_verbose(p,uri,timeout,NULL,NULL,NULL);
}

http_util_result* hc_post_verbose(apr_pool_t *p,char* uri,long timeout,char* userColonPass,const char* postData,int postDataLen, apr_table_t * headers_in){
		CURL *curl_handle=NULL;
		CURLcode res;
		http_util_result* ret=hc_createNewHttpUtilResult(p);		
		
		
		curl_handle=curl_easy_init();
		curl_easy_setopt(curl_handle, CURLOPT_POST,1);
		//curl_easy_setopt(curl_handle, CURLOPT_VERBOSE, 1);
		if(postData!=NULL){
			curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDS , postData) ;
			curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDSIZE , postDataLen) ;
//			fprintf(stderr,"PostSize: %d\n",postDataLen);
//			fflush(stderr);
			//curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDSIZE , strlen(postData)) ;
		}else{
			curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDSIZE , 0);
		}
		
		curl_easy_setopt(curl_handle, CURLOPT_URL,uri);
		curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION,hc_memory_callback);
		curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA,ret);
		curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, HTTP_USER_AGENT);
		curl_easy_setopt(curl_handle, CURLOPT_NOSIGNAL, 1);
		curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT, timeout);
		curl_easy_setopt(curl_handle, CURLOPT_CONNECTTIMEOUT, 5);
		
		hc_setup_headerbind(p,curl_handle,ret,headers_in);
		
		/*SSL Options*/ 
		//Allow connect to server using self signed certificate
		curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, FALSE);
		
		//Allow connect to server with cert hostname (CN) not matching connect string
		curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 0);
		
		if(userColonPass!=NULL){
			hc_setBasicAuthOpts(curl_handle,userColonPass);
		}
		
		//perform
		curl_easy_perform(curl_handle);
		
		//get option info
		res = curl_easy_getinfo(curl_handle, CURLINFO_TOTAL_TIME, &(ret->totalTime));
		res = curl_easy_getinfo(curl_handle, CURLINFO_RESPONSE_CODE, &(ret->responseCode));
		res = curl_easy_getinfo(curl_handle, CURLINFO_CONTENT_TYPE, &(ret->content_type));
		if(ret->content_type!=NULL){
			ret->content_type=apr_pstrdup(p,ret->content_type);	
		}		
		curl_easy_cleanup(curl_handle);
//		fprintf(stderr,"Response: %d\n",ret->responseCode);
//		fprintf(stderr,"ResponseSize: %d\n",ret->size);
//		fflush(stderr);
		if(ret!=NULL&&ret->responseCode!=0){
			return ret;
		}
		return NULL;
}

http_util_result* hc_ssl_post_verbose(apr_pool_t *p,char* uri,long timeout,char* userColonPass,const char* postData,int postDataLen, http_ssl_options* sslOptions, apr_table_t * headers_in){
		CURL *curl_handle=NULL;
		CURLcode res;
		http_util_result* ret=hc_createNewHttpUtilResult(p);		
		
		
		curl_handle=curl_easy_init();
		curl_easy_setopt(curl_handle, CURLOPT_POST,1);
		//curl_easy_setopt(curl_handle, CURLOPT_VERBOSE, 1);
		if(postData!=NULL){
			curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDS , postData) ;
			curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDSIZE , postDataLen) ;
//			fprintf(stderr,"PostSize: %d\n",postDataLen);
//			fflush(stderr);
			//curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDSIZE , strlen(postData)) ;
		}else{
			curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDSIZE , 0);
		}
		
		curl_easy_setopt(curl_handle, CURLOPT_URL,uri);
		curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION,hc_memory_callback);
		curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA,ret);
		curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, HTTP_USER_AGENT);
		curl_easy_setopt(curl_handle, CURLOPT_NOSIGNAL, 1);
		curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT, timeout);
		curl_easy_setopt(curl_handle, CURLOPT_CONNECTTIMEOUT, 5);
		
		hc_setup_headerbind(p,curl_handle,ret,headers_in);
		
		/*SSL Options*/
		/*SSL Options*/
		if(sslOptions!=NULL) {
			/* since PEM is default, we needn't set it for PEM */
			if(sslOptions->certType!=NULL) {
				curl_easy_setopt(curl_handle,CURLOPT_SSLCERTTYPE,sslOptions->certType);
			}
		
			/* set the cert for client authentication */
			if(sslOptions->certFile!=NULL) {
				curl_easy_setopt(curl_handle,CURLOPT_SSLCERT,sslOptions->certFile);
			}
		
			/* ket passphrase */
			if(sslOptions->passPhrase!=NULL) {
				curl_easy_setopt(curl_handle,CURLOPT_SSLKEYPASSWD,sslOptions->passPhrase);
			}
		
	      /* if we use a key stored in a crypto engine,
	         we must set the key type to "ENG" */
			if(sslOptions->keyType!=NULL) {
				curl_easy_setopt(curl_handle,CURLOPT_SSLKEYTYPE,sslOptions->keyType);
			}
	 
	      /* set the private key (file or ID in engine) */
			if(sslOptions->keyName!=NULL) {
				curl_easy_setopt(curl_handle,CURLOPT_SSLKEY,sslOptions->keyName);
			}
	 
			if(sslOptions->caCertFile!=NULL) {
				/* set the file with the certs vaildating the server */ 
				curl_easy_setopt(curl_handle,CURLOPT_CAINFO,sslOptions->caCertFile);
		 
				/* disconnect if we can't validate server's cert */ 
				curl_easy_setopt(curl_handle,CURLOPT_SSL_VERIFYPEER,1L);
			}else{
		      
				//Allow connect to server using self signed certificate
				curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, FALSE);
			
				//Allow connect to server with cert hostname (CN) not matching connect string
				curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 0);
			}
		}else{		
			//Allow connect to server using self signed certificate
			curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, FALSE);
			
			//Allow connect to server with cert hostname (CN) not matching connect string
			curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 0);
		}
		
		if(userColonPass!=NULL){
			hc_setBasicAuthOpts(curl_handle,userColonPass);
		}
		
		//perform
		curl_easy_perform(curl_handle);
		
		//get option info
		res = curl_easy_getinfo(curl_handle, CURLINFO_TOTAL_TIME, &(ret->totalTime));
		res = curl_easy_getinfo(curl_handle, CURLINFO_RESPONSE_CODE, &(ret->responseCode));
		res = curl_easy_getinfo(curl_handle, CURLINFO_CONTENT_TYPE, &(ret->content_type));
		if(ret->content_type!=NULL){
			ret->content_type=apr_pstrdup(p,ret->content_type);	
		}		
		curl_easy_cleanup(curl_handle);
//		fprintf(stderr,"Response: %d\n",ret->responseCode);
//		fprintf(stderr,"ResponseSize: %d\n",ret->size);
//		fflush(stderr);
		if(ret!=NULL&&ret->responseCode!=0){
			return ret;
		}
		return NULL;
}

typedef struct http_put_data{
	size_t len;
	char* data;
	char* cursor;
}http_put_data;

static http_put_data* http_newPutDataObj(apr_pool_t *p, char* str, int datalen){
	http_put_data* ret=NULL;
	ret=apr_palloc(p,sizeof(http_put_data));
	ret->len=datalen;
	ret->data=str;
	ret->cursor=str;
	return ret;	
} 

size_t http_put_callback(void *buffer, size_t size, size_t nmemb, void *userp){
	http_put_data* putData=(http_put_data*)userp;
	int copyBytes=0;
	
	//max size to out buffer can hold
    int maxbytes = size*nmemb;
    
    if(putData->len>0){
    	if(putData->len>maxbytes){
    		copyBytes=maxbytes;
    	}else{
    		copyBytes=putData->len;
    	}
    	memcpy(buffer,putData->cursor,copyBytes);
    	//printf("out:%s,%d", buffer,putData->len);
    	putData->cursor+=copyBytes;
    	putData->len-=copyBytes;    	
    	return copyBytes;
    }else{
    	return 0;	
    }
} 

http_util_result* hc_put_verbose2(apr_pool_t *p,char* uri,long timeout,char* userColonPass, const char* putData,int putDataLen, apr_table_t * headers_in){
	CURL *curl_handle=NULL;
		CURLcode res;
		http_util_result* ret=hc_createNewHttpUtilResult(p);		
		http_put_data* putObj=NULL;
	    		
		curl_handle=curl_easy_init();

		if(putData!=NULL){
			putObj=http_newPutDataObj(p,(char*)putData,putDataLen);
			curl_easy_setopt(curl_handle, CURLOPT_READFUNCTION,http_put_callback);
			curl_easy_setopt(curl_handle, CURLOPT_READDATA,putObj);
			curl_easy_setopt(curl_handle, CURLOPT_INFILESIZE,putObj->len);
		}else{
			curl_easy_setopt(curl_handle, CURLOPT_INFILESIZE,0);
		}
		curl_easy_setopt(curl_handle, CURLOPT_UPLOAD, TRUE);
		curl_easy_setopt(curl_handle, CURLOPT_PUT, TRUE);
		
		
		curl_easy_setopt(curl_handle, CURLOPT_URL,uri);
		curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION,hc_memory_callback);
		curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA,ret);
		curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, HTTP_USER_AGENT);
		curl_easy_setopt(curl_handle, CURLOPT_NOSIGNAL, 1);
		curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT, timeout);
		curl_easy_setopt(curl_handle, CURLOPT_CONNECTTIMEOUT, 5);
		
		hc_setup_headerbind(p,curl_handle,ret,headers_in);
		
		/*SSL Options*/ 
		//Allow connect to server using self signed certificate
		curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, FALSE);
		
		//Allow connect to server with cert hostname (CN) not matching connect string
		curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 0);
		
		if(userColonPass!=NULL){
			hc_setBasicAuthOpts(curl_handle,userColonPass);
		}
		
		//perform
		curl_easy_perform(curl_handle);
		
		//get option info
		res = curl_easy_getinfo(curl_handle, CURLINFO_TOTAL_TIME, &(ret->totalTime));
		res = curl_easy_getinfo(curl_handle, CURLINFO_RESPONSE_CODE, &(ret->responseCode));
		res = curl_easy_getinfo(curl_handle, CURLINFO_CONTENT_TYPE, &(ret->content_type));
		if(ret->content_type!=NULL){
			ret->content_type=apr_pstrdup(p,ret->content_type);	
		}		
		curl_easy_cleanup(curl_handle);
		if(ret!=NULL&&ret->responseCode!=0){
			return ret;
		}
		return NULL;
}
http_util_result* hc_put_verbose(apr_pool_t *p,char* uri,long timeout,char* userColonPass, char* putData){
		CURL *curl_handle=NULL;
		CURLcode res;
		http_util_result* ret=hc_createNewHttpUtilResult(p);		
		http_put_data* putObj=NULL;
		//struct curl_slist *slist = NULL;
		//slist = curl_slist_append(slist, "Accept: text/xml");
	    //slist = curl_slist_append(slist, "Content-Type: text/xml");
	    //slist = curl_slist_append(slist, "Expect:"); 
	    		
		curl_handle=curl_easy_init();
		//curl_easy_setopt(curl_handle, CURLOPT_VERBOSE, 1);
		//curl_easy_setopt(curl_handle, CURLOPT_CUSTOMREQUEST, "PUT");
		//curl_easy_setopt(curl_handle, CURLOPT_HTTPHEADER, slist);
		if(putData!=NULL){
			putObj=http_newPutDataObj(p,putData,strlen(putData));
			curl_easy_setopt(curl_handle, CURLOPT_READFUNCTION,http_put_callback);
			curl_easy_setopt(curl_handle, CURLOPT_READDATA,putObj);
			curl_easy_setopt(curl_handle, CURLOPT_INFILESIZE,putObj->len);
		}else{
			curl_easy_setopt(curl_handle, CURLOPT_INFILESIZE,0);
		}
		curl_easy_setopt(curl_handle, CURLOPT_UPLOAD, TRUE);
		curl_easy_setopt(curl_handle, CURLOPT_PUT, TRUE);
		
		
		curl_easy_setopt(curl_handle, CURLOPT_URL,uri);
		curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION,hc_memory_callback);
		curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA,ret);
		curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, HTTP_USER_AGENT);
		curl_easy_setopt(curl_handle, CURLOPT_NOSIGNAL, 1);
		curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT, timeout);
		curl_easy_setopt(curl_handle, CURLOPT_CONNECTTIMEOUT, 5);
		
		
		
		/*SSL Options*/ 
		//Allow connect to server using self signed certificate
		curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, FALSE);
		
		//Allow connect to server with cert hostname (CN) not matching connect string
		curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 0);
		
		if(userColonPass!=NULL){
			hc_setBasicAuthOpts(curl_handle,userColonPass);
		}
		
		//perform
		curl_easy_perform(curl_handle);
		
		//get option info
		res = curl_easy_getinfo(curl_handle, CURLINFO_TOTAL_TIME, &(ret->totalTime));
		res = curl_easy_getinfo(curl_handle, CURLINFO_RESPONSE_CODE, &(ret->responseCode));
		res = curl_easy_getinfo(curl_handle, CURLINFO_CONTENT_TYPE, &(ret->content_type));
		if(ret->content_type!=NULL){
			ret->content_type=apr_pstrdup(p,ret->content_type);	
		}		
		curl_easy_cleanup(curl_handle);
		if(ret!=NULL&&ret->responseCode!=0){
			return ret;
		}
		return NULL;
}
http_util_result* hc_delete_verbose(apr_pool_t *p,char* uri,long timeout,char* userColonPass){
		CURL *curl_handle=NULL;
		CURLcode res;
		http_util_result* ret=hc_createNewHttpUtilResult(p);		
		
		curl_handle=curl_easy_init();
		curl_easy_setopt(curl_handle, CURLOPT_URL,uri);
		curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION,hc_memory_callback);
		curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA,ret);
		curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, HTTP_USER_AGENT);
		curl_easy_setopt(curl_handle, CURLOPT_NOSIGNAL, 1);
		curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT, timeout);
		curl_easy_setopt(curl_handle, CURLOPT_CONNECTTIMEOUT, 5);
		curl_easy_setopt(curl_handle, CURLOPT_CUSTOMREQUEST, "DELETE");
		
		/*SSL Options*/ 
		//Allow connect to server using self signed certificate
		curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, FALSE);
		
		//Allow connect to server with cert hostname (CN) not matching connect string
		curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 0);
		
		if(userColonPass!=NULL){
			hc_setBasicAuthOpts(curl_handle,userColonPass);
		}
		
		//perform
		curl_easy_perform(curl_handle);
		
		//get option info
		res = curl_easy_getinfo(curl_handle, CURLINFO_TOTAL_TIME, &(ret->totalTime));
		res = curl_easy_getinfo(curl_handle, CURLINFO_RESPONSE_CODE, &(ret->responseCode));
		res = curl_easy_getinfo(curl_handle, CURLINFO_CONTENT_TYPE, &(ret->content_type));
		if(ret->content_type!=NULL){
			ret->content_type=apr_pstrdup(p,ret->content_type);	
		}		
		curl_easy_cleanup(curl_handle);
		if(ret!=NULL&&ret->responseCode!=0){
			return ret;
		}
		return NULL;
}

http_util_result* hc_method(apr_pool_t *p,const char* methodName,char* uri,long timeout,char* userColonPass,const char* data,int dataLen, apr_table_t * headers_in){
	CURL *curl_handle=NULL;
			CURLcode res;
			http_util_result* ret=hc_createNewHttpUtilResult(p);		
			
			
			curl_handle=curl_easy_init();
			curl_easy_setopt(curl_handle, CURLOPT_POST,1);
			curl_easy_setopt(curl_handle, CURLOPT_VERBOSE, 1);
			curl_easy_setopt(curl_handle, CURLOPT_CUSTOMREQUEST, methodName);
			if(data!=NULL){
				curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDS , data) ;
				curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDSIZE , dataLen) ;
	//			fprintf(stderr,"PostSize: %d\n",postDataLen);
	//			fflush(stderr);
				//curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDSIZE , strlen(postData)) ;
			}else{
				curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDSIZE , 0);
			}
			
			curl_easy_setopt(curl_handle, CURLOPT_URL,uri);
			curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION,hc_memory_callback);
			curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA,ret);
			curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, HTTP_USER_AGENT);
			curl_easy_setopt(curl_handle, CURLOPT_NOSIGNAL, 1);
			curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT, timeout);
			curl_easy_setopt(curl_handle, CURLOPT_CONNECTTIMEOUT, 5);
			
			hc_setup_headerbind(p,curl_handle,ret,headers_in);
			
			/*SSL Options*/ 
			//Allow connect to server using self signed certificate
			curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, FALSE);
			
			//Allow connect to server with cert hostname (CN) not matching connect string
			curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 0);
			
			if(userColonPass!=NULL){
				hc_setBasicAuthOpts(curl_handle,userColonPass);
			}
			
			//perform
			curl_easy_perform(curl_handle);
			
			//get option info
			res = curl_easy_getinfo(curl_handle, CURLINFO_TOTAL_TIME, &(ret->totalTime));
			res = curl_easy_getinfo(curl_handle, CURLINFO_RESPONSE_CODE, &(ret->responseCode));
			res = curl_easy_getinfo(curl_handle, CURLINFO_CONTENT_TYPE, &(ret->content_type));
			if(ret->content_type!=NULL){
				ret->content_type=apr_pstrdup(p,ret->content_type);	
			}		
			curl_easy_cleanup(curl_handle);
			fprintf(stderr,"Response: %d\n",ret->responseCode);
			fprintf(stderr,"Response: data: %s\n",ret->data);
			fprintf(stderr,"ResponseSize: %d\n",ret->size);
			fprintf(stderr,"ResponseSize STR: %d\n",strlen(ret->data));
			//fflush(stderr);
			if(ret!=NULL&&ret->responseCode!=0){
				return ret;
			}
			return NULL;
}


<|start_filename|>src/ngx_http_openidc_module.c<|end_filename|>
#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_http.h>
#include <nginx.h>
#include <apr_pools.h>
#include <apr_tables.h>
#include <apr_strings.h>
#include "oidc_config.h"
#include "config_core.h"
#include "common_utils.h"
#include "http-utils/http_client.h"
#include "logging.h"
#include "url_utils.h"
#include "rewrite_core.h"
#include "oidc_version.h"
#include "oidc_globals.h"

#define MODULE_NAME_ACTION_MAPPINGS	"oidcConfig"
#define HOST_BUFSIZE	256
#define RBUF_SIZE				64000
#define OAUTH_IDTOKEN_MAX_SIZE		8192

// subrequest types
#define SUB_REQUEST_TYPE_UNKNOWN					0
#define SUB_REQUEST_TYPE_OAUTH_TOKEN				1
#define SUB_REQUEST_TYPE_AUTHENTICATE			2
#define SUB_REQUEST_TYPE_AUTHORIZE					3

typedef struct oidc_authz_sub_request_type{
	ngx_uint_t type;	// request type authenticate or token
	ngx_str_t uri;		// subrequest uri
	ngx_str_t content_type;		// requestBody content type
}oidc_authz_sub_request_type;

oidc_authz_sub_request_type oidc_authz_subrequest_type_oauth_token =
		{ SUB_REQUEST_TYPE_OAUTH_TOKEN, ngx_string("/internal/oauth2/token"), ngx_string("application/x-www-form-urlencoded")};

	#define ALLOC_IF_NULL(r) \
		{if(r->data==NULL) { r->data = (char*)apr_palloc(r->pool,RBUF_SIZE); memset(r->data,'\0', RBUF_SIZE);}}

	#define ngx_http_openidc_rprintf(r,arg1) \
		{char temp[6144]; sprintf(temp,arg1); int cnt = strlen(temp); if(r->cur+cnt<RBUF_SIZE) { ALLOC_IF_NULL(r) memcpy(r->data+r->cur,temp, cnt); r->cur+=cnt;}}
	#define ngx_http_openidc_rprintf1(r,tem,arg1) \
		{char temp[6144]; sprintf(temp,tem,arg1); int cnt = strlen(temp); if(r->cur+cnt<RBUF_SIZE) {ALLOC_IF_NULL(r) memcpy(r->data+r->cur,temp, cnt); r->cur+=cnt;}}
	#define ngx_http_openidc_rprintf2(r,tem,arg1,arg2) \
		{char temp[6144]; sprintf(temp,tem,arg1,arg2); int cnt = strlen(temp); if(r->cur+cnt<RBUF_SIZE) {ALLOC_IF_NULL(r) memcpy(r->data+r->cur,temp, cnt); r->cur+=cnt;}}
	#define ngx_http_openidc_rprintf3(r,tem,arg1,arg2,arg3) \
		{char temp[6144]; sprintf(temp,tem,arg1,arg2,arg3); int cnt = strlen(temp); if(r->cur+cnt<RBUF_SIZE) {ALLOC_IF_NULL(r) memcpy(r->data+r->cur,temp, cnt); r->cur+=cnt;}}
	#define ngx_http_openidc_rprintf4(r,tem,arg1,arg2,arg3,arg4) \
		{char temp[6144]; sprintf(temp,tem,arg1,arg2,arg3,arg4); int cnt = strlen(temp); if(r->cur+cnt<RBUF_SIZE) {ALLOC_IF_NULL(r) memcpy(r->data+r->cur,temp, cnt); r->cur+=cnt;}}
	#define ngx_http_openidc_rprintf5(r,tem,arg1,arg2,arg3,arg4,arg5) \
		{char temp[6144]; sprintf(temp,tem,arg1,arg2,arg3,arg4,arg5); int cnt = strlen(temp); if(r->cur+cnt<RBUF_SIZE) {ALLOC_IF_NULL(r) memcpy(r->data+r->cur,temp, cnt); r->cur+=cnt;}}
	#define ngx_http_openidc_rputs(str,r) \
		{ if(str) { int cnt = strlen(str); if(r->cur<RBUF_SIZE) { ALLOC_IF_NULL(r) memcpy(r->data+r->cur,str, cnt); r->cur+=cnt;} } }


apr_pool_t* mainPool = NULL;
int initializedAPR = 0;

typedef struct {
  char*					homeDir;	
  char* 				logFile;
  char*				sheapMapFile;
  int					sheapPageSize;
  char* 				remotePath;
  char* 				remoteAuth;
  int					remotePathTimeout;
  char* 				passPhrase;
  char* 				oidcHeaderPrefix;
  int 					refreshWaitSeconds;
  char* 				oidcConfigFile;
  oidc_config* 		oidcConfig;
  config_core* 			configCore;
} Config;

typedef struct {
    ngx_str_t	homeDir;	
    ngx_str_t 	logFile;
    ngx_str_t 	sheapMapFile;
    ngx_int_t	sheapPageSize;
    ngx_str_t 	remotePath;
    ngx_str_t 	remoteAuth;
    ngx_int_t	remotePathTimeout;
    ngx_str_t 	passPhrase;
    ngx_str_t 	oidcHeaderPrefix;
    ngx_str_t 	oidcConfigFile;
    ngx_int_t	refreshWaitSeconds;
    Config* config;
} ngx_http_openidc_srv_conf_t;

/** A structure that represents the current rewrite request */
typedef struct  {
    apr_pool_t *pool;
    char *connection_remote_ip;
    const char *hostname;
    apr_table_t *headers_in;
    apr_table_t *headers_out;
    apr_hash_t* variableHash;
    const char *handler;	/* What we *really* dispatch on */
    char *unparsed_uri;	
    char *uri;
    apr_uri_t parsed_uri;
    ngx_http_request_t*	httpRequest;
    char* data;
    long cur;
}ngx_http_openidc_request_t;

typedef struct {
    ngx_uint_t                done;
    ngx_uint_t                status;
    ngx_http_request_t       *subrequest;
    ngx_str_t 					responseBody;
    ngx_str_t 					responseType;
} ngx_http_openidc_subrequest_ctx_t;

static void *ngx_http_openidc_create_srv_conf(ngx_conf_t *cf);
static char *ngx_http_openidc_merge_srv_conf(ngx_conf_t *cf,
    void *parent, void *child);
static ngx_int_t ngx_http_openidc_post_config(ngx_conf_t *cf);
static ngx_int_t ngx_http_openidc_checkForAccess(ngx_http_request_t * httpRequest);
static ngx_int_t ngx_http_openidc_handler(ngx_http_request_t *r);
static void ngx_http_openidc_setActionHeaders(ngx_http_openidc_request_t*r, apr_table_t* headers, array_header* actionHeaders, template_engine* tengine, char* originUri, int addHeaderToHttpRequest);
static int ngx_http_openidc_execUri(ngx_http_openidc_request_t* r, char* uri,int isForward, int isPermanent, char* originUri);
static char* ngx_http_openidc_getPostEntity(ngx_http_openidc_request_t* r, long* sz);
static void ngx_http_openidc_deleteHeader(ngx_http_request_t *r, u_char *key);
static ngx_int_t ngx_http_openidc_setHeader(ngx_http_request_t *r, const char *key, const char *val);
static ngx_int_t ngx_http_openidc_deleteHeaderPart(ngx_list_t *l, ngx_list_part_t *cur, ngx_uint_t i);
static int oidc_index(ngx_http_openidc_request_t *r, Config* config);
static int oidc_version(ngx_http_openidc_request_t *r, Config* config);
static int oidc_rewrite_actionmappings(ngx_http_openidc_request_t *r, Config *config);
static int oidc_rewrite_match(ngx_http_openidc_request_t *r, Config *config);
static int oidc_rewrite_pageactions(ngx_http_openidc_request_t *r, Config *config);
static int oidc_config_core_status(ngx_http_openidc_request_t *r, Config *config);
static int oidc_headers(ngx_http_openidc_request_t *r, Config *config);
static char* ngx_http_openidc_getFullRequestUrl(ngx_http_openidc_request_t* r);
static ngx_int_t ngx_http_openidc_subrequest_post_handler(ngx_http_request_t *r, void *data, ngx_int_t rc);
static ngx_int_t ngx_http_openidc_set_subrequest_post_body(ngx_http_request_t * r, ngx_http_request_t * sr, const char* requestBody, ngx_str_t contentType);
static ngx_int_t ngx_http_openidc_preAuthorize(ngx_http_openidc_request_t* r, Config* config);
static ngx_int_t ngx_http_openidc_create_post_subrequest(ngx_http_request_t * r, oidc_authz_sub_request_type sub_request_type, const char* requestBody);

ngx_str_t  ngx_http_openidc_content_length_header_key =
        ngx_string("Content-Length");
ngx_str_t  ngx_http_openidc_content_type_header_key =
        ngx_string("Content-Type");
ngx_str_t  ngx_http_openidc_content_type_formurlencoded =
        ngx_string("application/x-www-form-urlencoded");
ngx_str_t  ngx_http_openidc_content_type_json =
        ngx_string("application/json");

static void ngx_http_openidc_terminate() {
	if(mainPool) apr_pool_destroy(mainPool);
   apr_terminate();
}

static int ngx_http_openidc_die(int exitCode, const char *message, apr_status_t reason) {
    char msgbuf[80];
	apr_strerror(reason, msgbuf, sizeof(msgbuf));
	fprintf(stderr, "%s: %s (%d)\n", message, msgbuf, reason);
	exit(exitCode);
	return reason;
}

static void ngx_http_openidc_initializeAPR() {
	apr_status_t status;
	// Initialize library
	status = apr_initialize();
	if(status!=APR_SUCCESS) { ngx_http_openidc_die(-2, "Could not initialize", status); }
	atexit(ngx_http_openidc_terminate);
	
	// create mainPool
	status = apr_pool_create(&mainPool, NULL);
	if(status!=APR_SUCCESS) { ngx_http_openidc_die(-2, "Could not initialize main pool", status); }
	
	initializedAPR = 1;
}

static char *
ngx_http_openidc_set_home_dir(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
	ngx_http_openidc_srv_conf_t *sscf = conf;

    ngx_str_t                  *value;
    
    value = cf->args->elts;
    
    sscf->homeDir = value[1];
//	printf("ngx_http_openidc_set_home_dir:%d", getpid());

    return NGX_CONF_OK;
}

static char *
ngx_http_openidc_set_log_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
	ngx_http_openidc_srv_conf_t *sscf = conf;

    ngx_str_t                  *value, *url;
    
    value = cf->args->elts;
    url = &value[1];
    
    sscf->logFile = value[1];
//	printf("ngx_http_openidc_set_log_file:%d", getpid());

    return NGX_CONF_OK;
}

static char *
ngx_http_openidc_set_shm(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
	ngx_http_openidc_srv_conf_t *sscf = conf;

    ngx_str_t* value;
    int i;

    value = cf->args->elts;

    for (i = 1; i < cf->args->nelts; i++) {

        if (ngx_strncmp(value[i].data, "file=", 5) == 0) {
        	 	 sscf->sheapMapFile.len = value[i].len - 5;
        	 	 sscf->sheapMapFile.data = value[i].data + 5;
        	 	 continue;
        }

        if (ngx_strncmp(value[i].data, "size=", 5) == 0) {
        		sscf->sheapPageSize= ngx_atoi(value[i].data + 5, value[i].len - 5);
            continue;
        }

    }

//	printf("ngx_http_openidc_set_shm:%d", getpid());

    return NGX_CONF_OK;
}

static char *
ngx_http_openidc_set_remote_path(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
	ngx_http_openidc_srv_conf_t *sscf = conf;

    ngx_str_t* value;
    int i;

    value = cf->args->elts;

    for (i = 1; i < cf->args->nelts; i++) {

        if (ngx_strncmp(value[i].data, "uri=", 4) == 0) {
        	 	 sscf->remotePath.len = value[i].len - 4;
        	 	 sscf->remotePath.data = value[i].data + 4;
        	 	 continue;
        }

        if (ngx_strncmp(value[i].data, "timeout=", 8) == 0) {
        		sscf->remotePathTimeout= ngx_atoi(value[i].data + 8, value[i].len - 8);
            continue;
        }

        if (ngx_strncmp(value[i].data, "user:pass=", 10) == 0) {
        	 	 sscf->remoteAuth.len = value[i].len - 10;
        	 	 sscf->remoteAuth.data = value[i].data + 10;
        	 	 continue;
        }

    }

//	printf("ngx_http_openidc_set_remote_path:%d", getpid());

    return NGX_CONF_OK;
}

static char *
ngx_http_openidc_set_pass_phrase(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
	ngx_http_openidc_srv_conf_t *sscf = conf;

    ngx_str_t                  *value, *url;

    value = cf->args->elts;
    url = &value[1];

    sscf->passPhrase = value[1];
//	printf("ngx_http_openidc_set_pass_phrase:%d", getpid());

    return NGX_CONF_OK;
}

static char *
ngx_http_openidc_set_header_prefix(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
	ngx_http_openidc_srv_conf_t *sscf = conf;

    ngx_str_t                  *value, *url;

    value = cf->args->elts;
    url = &value[1];

    sscf->oidcHeaderPrefix = value[1];
//	printf("ngx_http_openidc_set_header_prefix:%d", getpid());

    return NGX_CONF_OK;
}

static char *
ngx_http_openidc_set_refresh_wait(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
	ngx_http_openidc_srv_conf_t *sscf = conf;

    ngx_str_t                  *value, *url;

    value = cf->args->elts;
    url = &value[1];

    sscf->refreshWaitSeconds= ngx_atoi(value[1].data, value[1].len);
//	printf("ngx_http_openidc_set_header_prefix:%d", getpid());

    return NGX_CONF_OK;
}

typedef struct ce_error_list{
	apr_array_header_t* data;
}ce_error_list;

static ce_error_list* ce_newErrorListObj(pool* p){
	ce_error_list* ret=(ce_error_list*)apr_pcalloc(p,sizeof(ce_error_list));
	ret->data=apr_array_make(p,4,sizeof(char*));\
	return ret;
}

static void ce_addErrorWithType(pool* p, ce_error_list* elist, char* mtype, char* msg){
	char** place=NULL;
	char* item=NULL;
	
	if(elist==NULL||msg==NULL) return;

	if(mtype!=NULL){
		item=apr_pstrcat(p,"[",mtype,"] ",msg,NULL);	
	}else{
		item=apr_pstrdup(p,msg);
	}
	place=(char**)apr_array_push(elist->data);
	*place=item;
}

static void ce_printList(pool* p,ce_error_list* elist){
	int i=0;
	char* item=NULL;
	apr_array_header_t* arry=NULL;
	if(elist==NULL) return;
	
	arry=elist->data;
	for(i=0;i<arry->nelts;i++){
		item=cu_getElement(arry,i);
		printf("• %s\n",item);
	}
}

static int ce_hasErrors(ce_error_list* elist){
	return elist!=NULL&&elist->data->nelts>0;
}

static char* ngx_http_openidc_postRefreshBind(apr_pool_t* p,Config* config){
	if(config->configCore==NULL){
		return apr_pstrdup(p,"Config Core is NULL");
	}
	
	config->oidcConfig=(oidc_config*)configcore_getModuleConfigByName(config->configCore,MODULE_NAME_ACTION_MAPPINGS);
	if(config->oidcConfig==NULL){
		return apr_pstrcat(p,"! Missing Required Service Name:",MODULE_NAME_ACTION_MAPPINGS,NULL);
	}
	
	return NULL;
}

static void ngx_http_openidc_postConfigStarting(apr_pool_t* p, const char* defn_name, int is_virtual, Config* config){
	printf("\n¬ª¬ª¬ª Initializing(%s)%s \n",defn_name!=NULL?defn_name:"-",is_virtual?"**VIRTUAL**":"");
	printf("* Note: If initialization seems slow. Check your DNS. It may have become slow or unresponsive.\r\n");
	if(config->oidcConfigFile!=NULL){
		config_core* ccore=NULL;
		ce_error_list* errorList=NULL;
		char* error=NULL;
		char cbuf[APR_CTIME_LEN + 1];
		
		config->logFile = apr_pstrcat(p,config->homeDir,"/",config->logFile,NULL);
		
		lc_openLogFile(p,config->logFile);
		lc_truncateLogFile();
		apr_time_t t1 = apr_time_now();
		apr_ctime(cbuf, t1);
		lc_printLog("\n¬∞\t Initializing %s [%s]\n",VERSION_ID,cbuf);
		fflush(stdout);
		hc_init();
				
		//init Error Obj
		errorList=ce_newErrorListObj(p);
		
		//load crypto core
		lc_printLog("\r\n\r\n");
		ccore=configcore_newConfigCoreObj(p);
		ccore->globals->homeDir=apr_pstrdup(p,config->homeDir);
		ccore->globals->logsDir=apr_pstrcat(p,config->homeDir,"/logs",NULL);		
		ccore->refreshLogFile=apr_pstrdup(p,config->logFile);

		// shared memory
		ccore->sheapMapFile=apr_pstrdup(p,config->sheapMapFile);
		ccore->sheapPageSize=config->sheapPageSize;

		// remote path
		if(config->remotePath!=NULL) {
			ccore->globals->resourceService = cb_newServiceDescriptorObj(p);
			ccore->globals->resourceService->uri=apr_pstrdup(p,config->remotePath);
			ccore->globals->resourceService->userColonPass=apr_pstrdup(p,config->remoteAuth);
			ccore->globals->resourceService->timeoutSeconds=config->remotePathTimeout;
		}

		// oidc stuff
		ccore->passPhrase=apr_pstrdup(p,config->passPhrase);
		ccore->cipherConfig->crypto_passphrase=ccore->passPhrase;
		ccore->oidcHeaderPrefix=apr_pstrdup(p,config->oidcHeaderPrefix);
		ccore->refreshWaitSeconds=config->refreshWaitSeconds;
		ccore->oidcConfigFile=apr_pstrdup(p,config->oidcConfigFile);

		ce_addErrorWithType(p,errorList,"Config Core Load File",error);
		if(error==NULL){
			configcore_printConfigCoreDetails(p,ccore);
			error=configcore_initializeConfigCore(p,ccore);
			ce_addErrorWithType(p,errorList,"Config Core Init",error);
			config->configCore=ccore;
			lc_printLog("‚àö Config Core Initialized\n");
			
			lc_printLog("¬∞ Binding Config Core Services\n");
			error=ngx_http_openidc_postRefreshBind(p,config);
			ce_addErrorWithType(p,errorList,"Config Core Bind",error);
		}
		
		if(!ce_hasErrors(errorList)){
			long timeTakenMillis = ((apr_time_now() - t1) / 1000);
			lc_printLog("\r\n>> %s - SUCCESS - Configuration loaded successfully [time taken : %d milliseconds]<<\r\n",VERSION_ID,timeTakenMillis);
		}else{
			lc_printLog("\r\n>> %s - ERRORS - Please check with development support if its ok to continue deployment..<<\r\n\n\n",VERSION_ID);
			ce_printList(p,errorList);
		}
		lc_closeLogFile();	
	}else{
		printf("!\n!\n!\t%sModule Config un-initializable!\n",is_virtual?"**VIRTUAL** ":"");
		printf("!\tThis is usually because you are missing settings for the default host.\n!\n!\n\n");
	}
}


static char *
ngx_http_openidc_set_configcore_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
	ngx_http_openidc_srv_conf_t *sscf = conf;

    ngx_str_t                  *value;
    
    value = cf->args->elts;
    
    sscf->oidcConfigFile = value[1];
//	printf("ngx_http_openidc_set_configcore_file:%d", getpid());
	if(!initializedAPR) {
		ngx_http_openidc_initializeAPR();
	}

	if(sscf->homeDir.data==NULL) {
//        ngx_log_error(NGX_LOG_ERR, cmd->log, 0, "rewrite home directory missing");
//        return NGX_ERROR;
	}
	sscf->config=ngx_pcalloc(cf->pool, sizeof(Config));
	sscf->config->homeDir=apr_pstrndup(mainPool, (char*)sscf->homeDir.data, sscf->homeDir.len);
	sscf->config->logFile=apr_pstrndup(mainPool, (char*)sscf->logFile.data, sscf->logFile.len);

	// shared memory
	sscf->config->sheapMapFile = (sscf->sheapMapFile.len>0)
			? apr_pstrndup(mainPool, (char*)sscf->sheapMapFile.data, sscf->sheapMapFile.len)
			: apr_pstrdup(mainPool, "/config.shm");

	sscf->config->sheapPageSize=(sscf->sheapPageSize>0) ? sscf->sheapPageSize : 64000;


	// remote path
	if(sscf->remotePath.len>0) {
		sscf->config->remotePath=apr_pstrndup(mainPool, (char*)sscf->remotePath.data, sscf->remotePath.len);
		sscf->config->remoteAuth = (sscf->remoteAuth.len>0)
				? apr_pstrndup(mainPool, (char*)sscf->remoteAuth.data, sscf->remoteAuth.len)
				: NULL;
		sscf->config->remotePathTimeout=(sscf->remotePathTimeout>0) ? sscf->remotePathTimeout : 10;
	}

	sscf->config->passPhrase = (sscf->passPhrase.len>0)
			? apr_pstrndup(mainPool, (char*)sscf->passPhrase.data, sscf->passPhrase.len)
			: NULL;

	sscf->config->oidcHeaderPrefix = (sscf->oidcHeaderPrefix.len>0)
			? apr_pstrndup(mainPool, (char*)sscf->oidcHeaderPrefix.data, sscf->oidcHeaderPrefix.len)
			: apr_pstrdup(mainPool, "X-OIDC-");

	sscf->config->refreshWaitSeconds=(sscf->refreshWaitSeconds>0) ? sscf->refreshWaitSeconds : 0;

	sscf->config->oidcConfigFile = (sscf->oidcConfigFile.len>0)
			? apr_pstrndup(mainPool, (char*)sscf->oidcConfigFile.data, sscf->oidcConfigFile.len)
			: apr_pstrdup(mainPool, "oidc-config.xml");

    djrglobals_setEnableUnnamedSHM("true");

	ngx_http_openidc_postConfigStarting(mainPool,"authz_oidc",FALSE,sscf->config);

    return NGX_CONF_OK;
}
static ngx_command_t  ngx_http_openidc_commands[] = {
    { ngx_string("OPENIDC_HomeDir"),
	  NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE12,
	  ngx_http_openidc_set_home_dir,
	  NGX_HTTP_SRV_CONF_OFFSET,
	  0,
	  NULL }, 
    { ngx_string("OPENIDC_LogFile"),
	  NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE12,
	  ngx_http_openidc_set_log_file,
	  NGX_HTTP_SRV_CONF_OFFSET,
	  0,
	  NULL },
	{ ngx_string("OPENIDC_SharedMemory"),
	  NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE12,
	  ngx_http_openidc_set_shm,
	  NGX_HTTP_SRV_CONF_OFFSET,
	  0,
	  NULL },
	{ ngx_string("OPENIDC_RemotePath"),
	  NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE123,
	  ngx_http_openidc_set_remote_path,
	  NGX_HTTP_SRV_CONF_OFFSET,
	  0,
	  NULL },
	{ ngx_string("OPENIDC_PassPhrase"),
	  NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE12,
	  ngx_http_openidc_set_pass_phrase,
	  NGX_HTTP_SRV_CONF_OFFSET,
	  0,
	  NULL },
	{ ngx_string("OPENIDC_HeaderPrefix"),
	  NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE12,
	  ngx_http_openidc_set_header_prefix,
	  NGX_HTTP_SRV_CONF_OFFSET,
	  0,
	  NULL },
    { ngx_string("OPENIDC_RefreshWaitSeconds"),
	  NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE12,
	  ngx_http_openidc_set_refresh_wait,
	  NGX_HTTP_SRV_CONF_OFFSET,
	  0,
	  NULL },
	{ ngx_string("OPENIDC_ConfigFile"),
	  NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE12,
	  ngx_http_openidc_set_configcore_file,
	  NGX_HTTP_SRV_CONF_OFFSET,
	  0,
	  NULL },	  
      ngx_null_command
};

static ngx_http_module_t  ngx_http_openidc_module_ctx = {
    NULL,            						/* preconfiguration */
    ngx_http_openidc_post_config,            /* postconfiguration */

    NULL,                                  /* create main configuration */
    NULL,                                  /* init main configuration */

    ngx_http_openidc_create_srv_conf,          /* create server configuration */
    ngx_http_openidc_merge_srv_conf,           /* merge server configuration */

    NULL,                                  /* create location configuration */
    NULL                                   /* merge location configuration */
};

ngx_int_t ainit_master(ngx_log_t *log) {
//	printf("ainit_master:%d", getpid());
	return NGX_OK;
}

ngx_int_t ainit_module(ngx_cycle_t *cycle) {
//	printf("ainit_module:%d", getpid());
	return NGX_OK;
}

ngx_int_t ainit_process(ngx_cycle_t *cycle) {
//	printf("ainit_process:%d", getpid());
	return NGX_OK;
}

void aexit_process(ngx_cycle_t *cycle) {
	ngx_http_openidc_terminate();
//	printf("aexit_process:%d", getpid());
}

void aexit_master(ngx_cycle_t *cycle) {
	ngx_http_openidc_terminate();
//	printf("aexit_master:%d", getpid());
}


ngx_module_t  ngx_http_openidc_module = {
    NGX_MODULE_V1,
    &ngx_http_openidc_module_ctx,              /* module context */
    ngx_http_openidc_commands,                 /* module directives */
    NGX_HTTP_MODULE,                       /* module type */
    ainit_master,                                  /* init master */
    ainit_module,                                  /* init module */
    ainit_process,                                  /* init process */
    NULL,                                  /* init thread */
    NULL,                                  /* exit thread */
    aexit_process,                                  /* exit process */
    aexit_master,                                  /* exit master */
    NGX_MODULE_V1_PADDING
};

static void *
ngx_http_openidc_create_srv_conf(ngx_conf_t *cf)
{
	ngx_http_openidc_srv_conf_t  *sscf;

    sscf = ngx_pcalloc(cf->pool, sizeof(ngx_http_openidc_srv_conf_t));
    if (sscf == NULL) {
        return NULL;
    }
//    printf("ngx_http_openidc_create_srv_conf:%p %d\r\n", sscf, getpid());
    return sscf;
}


static char *
ngx_http_openidc_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
{
	ngx_http_openidc_srv_conf_t *prev = parent;
	ngx_http_openidc_srv_conf_t *conf = child;
	
	if(conf->homeDir.data==NULL) {
		conf->homeDir = prev->homeDir;
	}
	if(conf->logFile.data==NULL) {
		conf->logFile = prev->logFile;
	}
	if(conf->sheapMapFile.data==NULL) {
		conf->sheapMapFile = prev->sheapMapFile;
	}
	if(conf->sheapPageSize==0) {
		conf->sheapPageSize = prev->sheapPageSize;
	}
	if(conf->remotePath.data==NULL) {
		conf->remotePath = prev->remotePath;
	}
	if(conf->remoteAuth.data==NULL) {
		conf->remoteAuth = prev->remoteAuth;
	}
	if(conf->remotePathTimeout==0) {
		conf->remotePathTimeout = prev->remotePathTimeout;
	}
	if(conf->passPhrase.data==NULL) {
		conf->passPhrase = prev->passPhrase;
	}
	if(conf->oidcHeaderPrefix.data==NULL) {
		conf->oidcHeaderPrefix = prev->oidcHeaderPrefix;
	}
	if(conf->refreshWaitSeconds==0) {
		conf->refreshWaitSeconds = prev->refreshWaitSeconds;
	}
	if(conf->oidcConfigFile.data==NULL) {
		conf->oidcConfigFile = prev->oidcConfigFile;
	}
	if(conf->config==NULL) {
		conf->config = prev->config;
	}
//    printf("ngx_http_openidc_merge_srv_conf:%p %p %d\r\n", prev,conf,getpid());
    return NGX_CONF_OK;
}

static ngx_http_openidc_request_t* ngx_http_openidc_createRequest(apr_pool_t* p) {
	ngx_http_openidc_request_t* r = (ngx_http_openidc_request_t *) apr_pcalloc(p, sizeof(ngx_http_openidc_request_t));
    r->pool = p;
    r->connection_remote_ip=NULL;
    r->headers_in      = apr_table_make(r->pool, 12);
    r->headers_out     = apr_table_make(r->pool, 12);
    r->variableHash = apr_hash_make(r->pool);
    //memset(r_buf,'\0', RBUF_SIZE);
    r->data=NULL;
    r->cur=0;
    return r;
}

static void ngx_http_openidc_setHeadersIn(ngx_http_request_t *httpRequest, ngx_http_openidc_request_t* r, char* headerPrefix) {
    ngx_list_part_t            *part;
    ngx_table_elt_t            *h;
    ngx_uint_t                  i;
    apr_pool_t* p = r->pool;
    apr_table_t* headersIn = r->headers_in;
    size_t prefixLen = (headerPrefix!=NULL) ? strlen(headerPrefix) : 0;

    /*
    Get the first part of the list. There is usual only one part.
    */
    part = &httpRequest->headers_in.headers.part;
    h = part->elts;
 
    /*
    Headers list array may consist of more than one part,
    so loop through all of it
    */
    for (i = 0; /* void */ ; i++) {
        if (i >= part->nelts) {
            if (part->next == NULL) {
                /* The last part, search is done. */
                break;
            }
 
            part = part->next;
            h = part->elts;
            i = 0;
        }
 
		if ( prefixLen>0 && prefixLen < h[i].key.len && (ngx_strcasestrn(h[i].key.data, headerPrefix, prefixLen-1)==h[i].key.data) ) {
			/* This is incompletion. */
			/*
			  h[i].hash = 0;
			  h[i].key.len = 0;
			  h[i].key.data = NULL;
			  h[i].value.len = 0;
			  h[i].value.data = NULL;
			*/
			ngx_http_openidc_deleteHeaderPart(&httpRequest->headers_in.headers, part, i);
		}else{
			char* key = apr_pstrndup(p, (char*)h[i].key.data, h[i].key.len);
			char* value = apr_pstrndup(p, (char*)h[i].value.data, h[i].value.len);
			apr_table_set(headersIn,key,value);
		}
    }
 
    /*
    No headers was found
    */
    return ;
}

ngx_int_t ngx_http_openidc_setHeaderInHeadersOut(ngx_http_request_t *r, const char *key, const char *val) {
    ngx_table_elt_t   *h;

    h = ngx_list_push(&r->headers_out.headers);
    if (h == NULL) {
        return NGX_ERROR;
    }

    h->key.len = strlen(key);
    h->value.len = strlen(val);;

    h->key.data = ngx_pnalloc(r->pool,
                       h->key.len + 1 + h->value.len + 1 + h->key.len);
    if (h->key.data == NULL) {
        return NGX_ERROR;
    }

    h->value.data = h->key.data + h->key.len + 1;
    h->lowcase_key = h->key.data + h->key.len + 1 + h->value.len + 1;

    ngx_memcpy(h->key.data, key, h->key.len);
    h->key.data[h->key.len] = '\0';

    ngx_memcpy(h->value.data, val, h->value.len);
    h->value.data[h->value.len] = '\0';

    ngx_strlow(h->lowcase_key, h->key.data, h->key.len);

    h->hash = r->header_hash;

    return NGX_OK;
}

ngx_int_t ngx_http_openidc_setHeaderInHeadersIn(ngx_http_request_t *r, const char *keyStr, const char *valueStr) {
    ngx_table_elt_t   *h;

    h = ngx_list_push(&r->headers_in.headers);
    if (h == NULL) {
        return NGX_ERROR;
    }

    h->key.len = strlen(keyStr);
    h->value.len = strlen(valueStr);;

    h->key.data = ngx_pnalloc(r->pool,
                       h->key.len + 1 + h->value.len + 1 + h->key.len);
    if (h->key.data == NULL) {
        return NGX_ERROR;
    }

    h->value.data = h->key.data + h->key.len + 1;
    h->lowcase_key = h->key.data + h->key.len + 1 + h->value.len + 1;

    ngx_memcpy(h->key.data, keyStr, h->key.len);
    h->key.data[h->key.len] = '\0';

    ngx_memcpy(h->value.data, valueStr, h->value.len);
    h->value.data[h->value.len] = '\0';

    ngx_strlow(h->lowcase_key, h->key.data, h->key.len);

    h->hash = r->header_hash;


    return NGX_OK;
}

static ngx_int_t ngx_http_openidc_post_config(ngx_conf_t *cf) {
    ngx_http_handler_pt        *h;
    ngx_http_core_main_conf_t  *cmcf;
    
    cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);

    // check access phase
    h = ngx_array_push(&cmcf->phases[NGX_HTTP_ACCESS_PHASE].handlers);
    if (h == NULL) {
        return NGX_ERROR;
    }

    *h = ngx_http_openidc_checkForAccess;

    // custom content generator handler
//    h = ngx_array_push(&cmcf->phases[NGX_HTTP_CONTENT_PHASE].handlers);
//    if (h == NULL) {
//        return NGX_ERROR;
//    }

//    *h = ngx_http_openidc_handler;

//    printf("ngx_http_openidc_post_config:%d\r\n", getpid());
    return NGX_OK;
}

static int ngx_http_openidc_addResponseHeaderCallback(void *rec, const char *keyStr, const char *valueStr){
	ngx_http_request_t *httpRequest = (ngx_http_request_t*)rec;
	if(keyStr&&valueStr&&httpRequest) {
	    ngx_http_openidc_setHeaderInHeadersOut(httpRequest, keyStr, valueStr);
	}
	return 1;
}

static ngx_int_t ngx_http_openidc_sendResponse(ngx_http_openidc_request_t* r) {
	
    ngx_int_t    rc;
    ngx_buf_t   *b;
    ngx_chain_t  out;
    int dataLen=0;
    
	// return if contentType or body not found
	if(r->data==NULL) return NGX_HTTP_INTERNAL_SERVER_ERROR;
	
    /* set the 'Content-type' header */
	r->httpRequest->headers_out.content_type_len = sizeof("text/html") - 1;
	r->httpRequest->headers_out.content_type.len = sizeof("text/html") - 1;
	r->httpRequest->headers_out.content_type.data = (u_char *) "text/html";

    /* allocate a buffer for your response body */
    b = ngx_pcalloc(r->httpRequest->pool, sizeof(ngx_buf_t));
    if (b == NULL) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    /* attach this buffer to the buffer chain */
    out.buf = b;
    out.next = NULL;
    //r->data = apr_psprintf(workerPool, "r->handler=%s retCode=%d", r->handler, retCode); 
    /* adjust the pointers of the buffer */
	dataLen = strlen(r->data);
    b->pos = (u_char*)r->data;
    b->last = (u_char*)r->data + dataLen;
    b->memory = 1;    /* this buffer is in memory */
    b->last_buf = 1;  /* this is the last buffer in the buffer chain */

    /* set the status line */
    r->httpRequest->headers_out.status = NGX_HTTP_OK;
    r->httpRequest->headers_out.content_length_n = dataLen;
	 
    /* send the headers of your response */
    rc = ngx_http_send_header(r->httpRequest);

    if (rc == NGX_ERROR || rc > NGX_OK || r->httpRequest->header_only) {
        return rc;
    }

    /* send the buffer chain of your response */
    return ngx_http_output_filter(r->httpRequest, &out);			    
}

ngx_table_elt_t* ngx_http_openidc_lookupHeader(ngx_http_request_t *r, u_char *key) {
    ngx_list_part_t *part;
    ngx_table_elt_t *h;
    ngx_uint_t i;
    size_t len = strlen((char *)key);

    part = &r->headers_in.headers.part;
    h = part->elts;
    for (i = 0; ; i++) {
        if (i >= part->nelts) {
            if (part->next == NULL) {
                break;
            }
            part = part->next;
            h = part->elts;
            i = 0;
        }
        if (len != h[i].key.len || ngx_strcasecmp(key, h[i].key.data) != 0) {
            continue;
        }
        return &h[i];
    }
    return NULL;
}

ngx_int_t ngx_http_openidc_setHeader(ngx_http_request_t *r, const char *key, const char *val) {
    ngx_table_elt_t   *h;

    h = ngx_list_push(&r->headers_in.headers);
    if (h == NULL) {
        return NGX_ERROR;
    }

    h->key.len = strlen(key);
    h->value.len = strlen(val);;

    h->key.data = ngx_pnalloc(r->pool,
                       h->key.len + 1 + h->value.len + 1 + h->key.len);
    if (h->key.data == NULL) {
        return NGX_ERROR;
    }

    h->value.data = h->key.data + h->key.len + 1;
    h->lowcase_key = h->key.data + h->key.len + 1 + h->value.len + 1;

    ngx_memcpy(h->key.data, key, h->key.len);
    h->key.data[h->key.len] = '\0';

    ngx_memcpy(h->value.data, val, h->value.len);
    h->value.data[h->value.len] = '\0';

    ngx_strlow(h->lowcase_key, h->key.data, h->key.len);

    h->hash = r->header_hash;


    return NGX_OK;
}

/*
 * delete header part
 */
static ngx_int_t ngx_http_openidc_deleteHeaderPart(ngx_list_t *l,
                               ngx_list_part_t *cur,
                               ngx_uint_t i) {
    ngx_table_elt_t *elts = cur->elts;
    ngx_list_part_t *new, *part;

    if (i == 0) {
        cur->elts = (char *) cur->elts + l->size;
        cur->nelts--;

        if (cur == l->last) {
            if (l->nalloc > 1) {
                l->nalloc--;
                return NGX_OK;
            }
            part = &l->part;
            while (part->next != cur) {
                if (part->next == NULL) {
                    return NGX_ERROR;
                }
                part = part->next;
            }
            part->next = NULL;
            l->last = part;
            return NGX_OK;
        }

        if (cur->nelts == 0) {
            part = &l->part;
            while (part->next != cur) {
                if (part->next == NULL) {
                    return NGX_ERROR;
                }
                part = part->next;
            }

            part->next = cur->next;
            return NGX_OK;
        }
        return NGX_OK;
    }

    if (i == cur->nelts - 1) {
        cur->nelts--;
        if (cur == l->last) {
            l->nalloc--;
        }
        return NGX_OK;
    }

    new = ngx_palloc(l->pool, sizeof(ngx_list_part_t));
    if (new == NULL) {
        return NGX_ERROR;
    }

    new->elts = &elts[i + 1];
    new->nelts = cur->nelts - i - 1;
    new->next = cur->next;

    l->nalloc = new->nelts;

    cur->nelts = i;
    cur->next = new;
    if (cur == l->last) {
        l->last = new;
    }

    cur = new;
    return NGX_OK;
}

/*
 * delete header if exists
 */
void ngx_http_openidc_deleteHeader(ngx_http_request_t *r, u_char *key) {
    ngx_list_part_t *part;
    ngx_table_elt_t *h;
    ngx_uint_t i;
    size_t len = strlen((char *)key);

    part = &r->headers_in.headers.part;
    h = part->elts;
    for (i = 0; ; i++) {
        if (i >= part->nelts) {
            if (part->next == NULL) {
                break;
            }
            part = part->next;
            h = part->elts;
            i = 0;
        }
        if (len == h[i].key.len && ngx_strcasecmp(key, h[i].key.data) == 0) {
            /* This is incompletion. */
            /*
              h[i].hash = 0;
              h[i].key.len = 0;
              h[i].key.data = NULL;
              h[i].value.len = 0;
              h[i].value.data = NULL;
            */
        	ngx_http_openidc_deleteHeaderPart(&r->headers_in.headers, part, i);
        }
    }
}

static const char *ngx_http_openidc_requestVar(ngx_http_openidc_request_t *r, const char* arg)
{
	char* start = NULL;
	if(arg==NULL) return NULL;

	if((start = strstr(arg, "HTTP_"))) {
		   return apr_table_get(r->headers_in, start+5);
	} else if(strcmp(arg,"REQ_URI")==0) {
		return r->uri;
	} else if(strcmp(arg,"REQ_UNPARSED_URI")==0) {
		return r->unparsed_uri;
	}else if(strcmp(arg,"REQ_URI_ENCODED")==0) {
		return url_encode2(r->pool, r->uri);
	} else if(strcmp(arg,"REQ_UNPARSED_URI_ENCODED")==0) {
		return url_encode2(r->pool, r->unparsed_uri);
	} else if(strcmp(arg,"REQ_QUERY")==0) {
		uri_components *url = &r->parsed_uri;
		return url_getParam(r->pool, url->query, arg);
	}
	return NULL;
}
static const char *ngx_http_openidc_serverVars(ngx_http_openidc_request_t *r, const char* arg)
{
	 return (arg!=NULL) ? apr_hash_get(r->variableHash, arg, APR_HASH_KEY_STRING) : NULL;
}
static const char *ngx_http_openidc_requestCookie(ngx_http_openidc_request_t *r, const char *arg)
{
	if(arg==NULL) return "(null)";
	const char *s = cookie_getCookieByName(r->pool, r->headers_in, arg, strlen(arg));
   if (s)
       return s;
   else
       return "(null)";
}

static const char *ngx_http_openidc_urlDecodeToken(ngx_http_openidc_request_t *r, const char *arg){
	return url_decode2(r->pool,(char*)arg);
}

static const char *ngx_http_openidc_urlEncodeToken(ngx_http_openidc_request_t *r, const char *arg){
	return url_encode2(r->pool,(char*)arg);
}

static const char *ngx_http_openidc_requestQuery(ngx_http_openidc_request_t *r, const char *arg)
{
	uri_components *url = &r->parsed_uri;
	if(arg==NULL) return "(null)";
	const char *s = url_getParam(r->pool, url->query, arg);
   if (s)
       return s;
   else
       return "(null)";
}

	typedef struct tag_handler{
		const char c;
		const char* (*func)(ngx_http_openidc_request_t*,const char* arg);
	}tag_handler;
	
	static const tag_handler tagHandlers[] = {
			{'r', ngx_http_openidc_requestVar},
			{'s', ngx_http_openidc_serverVars},
			{'c', ngx_http_openidc_requestCookie},
			{'u', ngx_http_openidc_urlDecodeToken},
			{'U', ngx_http_openidc_urlEncodeToken},
			{'q', ngx_http_openidc_requestQuery},
	};

static const char* ngx_http_openidc_getTagValue(char* s, ngx_http_openidc_request_t*r, char**next) {
	unsigned int i;
	char* arg = NULL, *end=NULL;
	s++;
    if (*s == '{') {
        if((end = strchr(s, '}'))!=NULL) {
	        arg = apr_pstrndup(r->pool, s+1, end-s-1);
	        s=end+1;	// pass by '}'
        }
    }
	for(i=0; i < sizeof(tagHandlers)/sizeof(tag_handler); i++ ){
		if(tagHandlers[i].c==*s) {
			*next = s+1; // pass by the current character.
			return (*tagHandlers[i].func)(r, arg);
		}
	}
	return NULL;
}

static char* ngx_http_openidc_parseString(pool*p, char*src, ngx_http_openidc_request_t *r){
	#define HDR_BUF_SIZE	4096
	if(src==NULL) return NULL;
	char*ret=(char*)apr_palloc(p, HDR_BUF_SIZE);
	char*q=ret;
	const char* str = NULL;
	
	while(*src!='\0'){
		if(*src=='%'&&(str = ngx_http_openidc_getTagValue(src, r, &src))){
			strcpy(q, str);
			q += strlen(str);
		}else{
			*q++=*src++;
		}
	}
	*q='\0';
	
	return ret;
}

static char* ngx_http_openidc_processTags(action_header *hdr, ngx_http_openidc_request_t *r, template_engine* tengine, char* originUri)
{
   char* hdrValue = ngx_http_openidc_parseString(r->pool, apr_pstrdup(r->pool, hdr->value), r);
	if(hdr->regex!=NULL&&hdrValue!=NULL){
		array_header* matches=NULL;
		rc_matchByStringsPattern(r->pool, hdr->regex, originUri, &matches);
		hdrValue=te_templateString(r->pool,tengine,hdrValue,matches);
	}
   return (hdrValue!=NULL) ? apr_pstrdup(r->pool, hdrValue) : "";
}

static void ngx_http_openidc_setActionHeaders(ngx_http_openidc_request_t*r, apr_table_t* headers, array_header* actionHeaders, template_engine* tengine, char* originUri, int addHeaderToHttpRequest){
   int i;
   char* headerValue=NULL;		
		if(actionHeaders==NULL||actionHeaders->nelts<0 || headers==NULL) return;

		for(i=0; i<actionHeaders->nelts; i++){
			action_header* hdr = (action_header*)cu_getElement(actionHeaders, i);
			if(hdr!=NULL){
				switch (hdr->action) {
				case header_add:
					headerValue = ngx_http_openidc_processTags(hdr, r, tengine, originUri);
					apr_table_add(headers, hdr->name, headerValue);
					if(addHeaderToHttpRequest){
						ngx_http_openidc_setHeader(r->httpRequest, hdr->name, headerValue);
					}
					break;
				case header_append:
					headerValue = ngx_http_openidc_processTags(hdr, r, tengine, originUri);
					apr_table_merge(headers, hdr->name, headerValue);
					if(addHeaderToHttpRequest){
						ngx_http_openidc_setHeader(r->httpRequest, hdr->name, headerValue);
					}
					break;
//				case header_merge:
//					val = apr_table_get(headers, hdr->name);
//					if (val == NULL) {
//						headerValue = ngx_http_openidc_processTags(hdr, r, tengine, originUri);
//						apr_table_add(headers, hdr->name, headerValue);
//						if(addHeaderToHttpRequest){
//							ngx_http_openidc_setHeader(r->httpRequest, hdr->name, headerValue);
//						}
//					} else {
//						char *new_val = ngx_http_openidc_processTags(hdr, r, tengine, originUri);
//						apr_size_t new_val_len = strlen(new_val);
//						int tok_found = 0;
//
//						/* modified version of logic in ap_get_token() */
//						while (*val) {
//							const char *tok_start;
//
//							while (*val && apr_isspace(*val))
//								++val;
//
//							tok_start = val;
//
//							while (*val && *val != ',') {
//								if (*val++ == '"')
//									while (*val)
//										if (*val++ == '"')
//											break;
//							}
//
//							if (new_val_len == (apr_size_t)(val - tok_start)
//									&& !strncmp(tok_start, new_val, new_val_len)) {
//								tok_found = 1;
//								break;
//							}
//
//							if (*val)
//								++val;
//						}
//
//						if (!tok_found) {
//							apr_table_merge(headers, hdr->name, new_val);
//						}
//					}
//					break;
				case header_set:
		            if (!strcasecmp(hdr->name, "Content-Type")) {
		            	char* content_type = ngx_http_openidc_processTags(hdr, r, tengine, originUri);
		            	if(content_type!=NULL){
		            		r->httpRequest->headers_out.content_type.len = strlen(content_type);
		            		r->httpRequest->headers_out.content_type.data = (u_char *)content_type;
		            	}
		            }
		            headerValue = ngx_http_openidc_processTags(hdr, r, tengine, originUri);
					apr_table_set(headers, hdr->name, headerValue);
					if(addHeaderToHttpRequest){
						ngx_http_openidc_setHeader(r->httpRequest, hdr->name, headerValue);
					}
					break;
				case header_unset:
					apr_table_unset(headers, hdr->name);
					if(addHeaderToHttpRequest){
						ngx_http_openidc_deleteHeader(r->httpRequest,hdr->name);
					}
					break;
				case header_merge:
				case header_echo:
				case header_edit:
					apr_table_add(r->headers_out,"X-HEADER-OPERATION","not supported");
					break;					
				}  	  			
	  		}
		}
}

static int ngx_http_openidc_execCustomResponse(ngx_http_openidc_request_t *r, int responseCode, char* contentType, const char* responseBodyTemplate, template_engine* tengine) {

		if(responseBodyTemplate!=NULL){

			// process template
			char* responseBody = ngx_http_openidc_parseString(r->pool, apr_pstrdup(r->pool, responseBodyTemplate), r);
			/**
			 * Set the headers in response stream.
			 */
			apr_table_do(ngx_http_openidc_addResponseHeaderCallback, r->httpRequest, r->headers_out, NULL);
			if(responseBody!=NULL){ // have response data from proxy
			    ngx_int_t    rc;
			    ngx_buf_t   *b;
			    ngx_chain_t  out;

				// return if contentType or body not found
				if(contentType==NULL||responseBody==NULL) return NGX_HTTP_INTERNAL_SERVER_ERROR;

				rc = ngx_http_discard_request_body(r->httpRequest);
			    if (rc != NGX_OK) {
			        return rc;
			    }

			    /* set the 'Content-type' header */
			    r->httpRequest->headers_out.content_type_len = strlen(contentType);
			    r->httpRequest->headers_out.content_type.len = strlen(contentType);
			    r->httpRequest->headers_out.content_type.data = (u_char *)contentType;

			    /* allocate a buffer for your response body */
			    b = ngx_pcalloc(r->httpRequest->pool, sizeof(ngx_buf_t));
			    if (b == NULL) {
			        return NGX_HTTP_INTERNAL_SERVER_ERROR;
			    }

			    /* attach this buffer to the buffer chain */
			    out.buf = b;
			    out.next = NULL;
			    //r->data = apr_psprintf(workerPool, "r->handler=%s retCode=%d", r->handler, retCode);
			    /* adjust the pointers of the buffer */
			    b->pos = (u_char*)responseBody;
			    b->last = (u_char*)responseBody + strlen(responseBody);
			    b->memory = 1;    /* this buffer is in memory */
			    b->last_buf = 1;  /* this is the last buffer in the buffer chain */

			    /* set the status line */
			    r->httpRequest->headers_out.status = ( responseCode > 0 ) ? responseCode : NGX_HTTP_OK;
			    r->httpRequest->headers_out.content_length_n = strlen(responseBody);

			    /* send the headers of your response */
			    rc = ngx_http_send_header(r->httpRequest);

			    if (rc == NGX_ERROR || rc > NGX_OK || r->httpRequest->header_only) {
			        return rc;
			    }

			    /* send the buffer chain of your response */
			    return ngx_http_output_filter(r->httpRequest, &out);
			}
			return NGX_HTTP_OK;
		}
		return NGX_DECLINED;
 }

static int ngx_http_openidc_execPageAction(ngx_http_openidc_request_t *r, page_action* paction, char* originUri){
	char* destUri=NULL;
	array_header* matches=NULL;
	int ret=0;

//		AP_LOG_ERROR(r,"ngx_http_openidc_execPageAction");
	if(paction!=NULL){

		if(paction->isDebug==1){
			char buf[256];
			if(gethostname(buf,256)==0){
				apr_table_add(r->headers_out,"X-DEBUG-BOX-IDENT",apr_pstrdup(r->pool,buf));
			}
		}
		
		if (paction->requestHeaders!=NULL) {
			ngx_http_openidc_setActionHeaders(r, r->headers_in, paction->requestHeaders, paction->templateEngineRef, originUri, TRUE);
		}			

		if(paction->handler_internal!=NULL){
//				AP_LOG_ERROR1(r,"paction->handler_internal=%s",paction->handler_internal);
			r->handler=paction->handler_internal;
		}

		if(paction->type==action_callback) {
			// send to target url if found in state
			uri_components *url = &r->parsed_uri;

			char* state = url_getParam(r->pool, url->query, "state");
			if(state!=NULL&&strstr(state, "http")==0) {
				unsigned char base64UrlDecoded[4096];
				memset(base64UrlDecoded,'\0',4096);
				base64Url_decode(base64UrlDecoded, state, strlen(state));
				state = base64UrlDecoded;
			}
			if(state==NULL || (state!=NULL&&strstr(state, "http")==0)) {
				char* scheme=(char*)apr_table_get(r->headers_in, "X-Forwarded-Proto");
				if(scheme==NULL) { scheme=(char*)apr_table_get(r->headers_in, "X-REQUEST-SCHEME"); }
				state=apr_pstrcat(r->pool, scheme,"://", r->hostname, NULL);
			}
			return ngx_http_openidc_execUri(r, state, FALSE, FALSE, NULL);
		}

		if(paction->uri!=NULL){
			
			char* paction_uri = paction->uri;

			//do url Templating
			//destUri
			if(paction->regex!=NULL){
				rc_matchByStringsPattern(r->pool, paction->regex, originUri, &matches);
				destUri=te_templateString(r->pool,paction->templateEngineRef,paction_uri,matches);
			}

			//ensure dest url is valid
			if(destUri==NULL){
				destUri=paction_uri;
			}
			
			//process dateTemplate
			if(paction->advancedTemplate==TRUE){
				destUri = ngx_http_openidc_parseString(r->pool, apr_pstrdup(r->pool, destUri), r);
			}

			if(paction->type==action_login){
				destUri = apr_pstrcat(r->pool, destUri, "&nonce=", apr_table_get(r->headers_in, OIDC_RP_SESSIONID), NULL);
				if(paction->base64UrlEncodeState) {
					unsigned char base64UrlEncoded[4096];
					memset(base64UrlEncoded,'\0',4096);
					base64Url_encode(base64UrlEncoded, originUri, strlen(originUri));
					destUri = apr_pstrcat(r->pool, destUri, "&state=", base64UrlEncoded, NULL);
				}else {
					destUri = apr_pstrcat(r->pool, destUri, "&state=", url_encode2(r->pool, originUri), NULL);
				}
			}

			if (paction->responseHeaders!=NULL) {
				ngx_http_openidc_setActionHeaders(r, r->headers_out, paction->responseHeaders, paction->templateEngineRef, originUri, FALSE);
			}
			ret = ngx_http_openidc_execUri(r,destUri,paction->isForward,paction->isPermanent,originUri);
			return ret;

		}else{	// allowing to set the response headers even if uri is not configured.
			if (paction->responseHeaders!=NULL) {
				ngx_http_openidc_setActionHeaders(r, r->headers_out, paction->responseHeaders, paction->templateEngineRef, originUri, FALSE);
			}
			if(paction->response!=NULL) {
				return ngx_http_openidc_execCustomResponse(r, paction->response->code, paction->response->contentType, paction->response->body, paction->templateEngineRef);
			}
		}
	}
	return NGX_DECLINED;
}

int ngx_http_openidc_execUri(ngx_http_openidc_request_t* r, char* uri,int isForward, int isPermanent, char* originUri) {
	if(uri!=NULL){
		//execute
		if(isForward){
			if(originUri!=NULL){
				ngx_http_openidc_setHeader(r->httpRequest, "X-MODAUTH-ORIGIN-URI", originUri);
			}
	//		if(r->filename!=NULL){
	//			apr_table_setn(r->headers_in, "X-MODAUTH-ORIGIN-FILENAME", r->filename);
	//		}
			int len = strlen(uri);
			u_char* ngxUri = ngx_palloc(r->httpRequest->pool, len + 1);
			ngx_cpystrn(ngxUri, (u_char*)uri, len + 1);
		    ngx_str_t internalRedirect = { len, ngxUri };			
			ngx_http_internal_redirect(r->httpRequest, &internalRedirect , &r->httpRequest->args);
			return NGX_HTTP_OK;
		}else if(isPermanent){
			apr_table_setn(r->headers_out, "Location", uri);
			return NGX_HTTP_MOVED_PERMANENTLY;
		}else {
			apr_table_setn(r->headers_out, "Location", uri);
			return NGX_HTTP_MOVED_TEMPORARILY;
		}
	}
	return NGX_DECLINED;	
}

static void ngx_oidc_body_handler ( ngx_http_request_t *r ) {
        ngx_int_t rc = NGX_OK;
 
     // TODO: Read request body here
     if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
        ngx_http_finalize_request(r,0); 
    }
    
    return;
}

static ngx_int_t ngx_http_openidc_getPostEntityINT(ngx_http_request_t *r) {
    ngx_int_t                   rc;

    //TODO: Add handler
    rc = ngx_http_read_client_request_body(r, ngx_oidc_body_handler);

    if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
        return rc;
    }

    return NGX_DONE;
}

static char* ngx_http_openidc_getPostEntity(ngx_http_openidc_request_t* r, long* sz) {
	char* buf=NULL;
	
	ngx_http_openidc_getPostEntityINT(r->httpRequest);

	*sz = 0;
	
	return buf;
}

static char* ngx_http_openidc_getFullRequestUrl(ngx_http_openidc_request_t *req){
	uri_components *url = &req->parsed_uri;
	char* relativeUrl;

	char* scheme=(char*)apr_table_get(req->headers_in, "X-Forwarded-Proto");
	if(scheme==NULL) {
		scheme=(char*)apr_table_get(req->headers_in, "X-REQUEST-SCHEME");
	}

	if(((strcmp(scheme,"http")!=0&&url->port!=80)||(strcmp(scheme,"https")!=0&&url->port!=443))&&url->port_str!=NULL){
		relativeUrl=apr_pstrcat(req->pool,scheme,"://", req->hostname,":",url->port_str,req->unparsed_uri, NULL);
	}else{
		relativeUrl=apr_pstrcat(req->pool,scheme,"://", req->hostname,req->unparsed_uri, NULL);
	}

	return relativeUrl;
}

typedef int (*ngx_http_openidc_handler_func)(ngx_http_openidc_request_t*r, Config* config);

typedef struct ngx_http_openidc_handler_t{
	ngx_http_openidc_handler_func handlerFunc;
}ngx_http_openidc_handler_t;

static const ngx_http_openidc_handler_t ngx_http_oidcHandlers[] = {
		{oidc_index},
		{oidc_version},
		{oidc_rewrite_match},
		{oidc_rewrite_pageactions},
		{oidc_rewrite_actionmappings},
		{oidc_config_core_status},
		{oidc_headers}
};

static oauth_jwk* oauth_getSignatureValidationKey(pool*p, oauth_jwt_header* header, const char* issuer, const char* audience, void* data, char** error) {
	oidc_config* oauthConfig = (oidc_config *)data;

	int i;

	if(header==NULL||header->algorithm==NULL||oauthConfig==NULL) {
		if(error!=NULL) { *error = apr_pstrdup(p, "header or jwsKeys null"); }
		return NULL;
	}
	oauth_jwk* jwk =oauthutil_newJWKObj(p);

	if(header->keyID!=NULL) {
		oidc_provider* oidcProvider = am_getOidcProviderByIssuer(oauthConfig->oidcProviderHash, issuer);
		if(oidcProvider==NULL) {
			if(error!=NULL) { *error = apr_pstrdup(p, "issuer is not configured"); }
			return NULL;
		}

		oauth_jwskey* jwsKey = am_getJWSKeyByKeyID(oidcProvider->jwsKeys, header->keyID);
		if(jwsKey==NULL) {
			if(error!=NULL) { *error = apr_pstrdup(p, "jwsKey by keyID not found"); }
			return NULL;
		}
		jwk->keyID = apr_pstrdup(p, jwsKey->id);
		jwk->use = apr_pstrdup(p, jwsKey->use);
		jwk->modulus = apr_pstrdup(p, jwsKey->modulus);
		jwk->exponent = apr_pstrdup(p, jwsKey->exponent);
	}else if(audience!=NULL){
		relying_party* relyingParty = am_getRelyingPartyByClientID(oauthConfig->relyingPartyHash, audience);
		if(relyingParty==NULL) {
			if(error!=NULL) { *error = apr_pstrdup(p, "relyingParty not configured"); }
			return NULL;
		}
		jwk->key = apr_pstrdup(p, relyingParty->clientSecret);
	}

	return jwk;
}


static const char* oauth_toupper(pool*p, char* src) {
		if(src==NULL) return NULL;

	char* s = apr_pstrdup(p, src);
	char* cursor;
	for ( cursor = s; *cursor!='\0'; cursor++ ) {
		*cursor = toupper( (unsigned char)*cursor );
	}
	return s;
}

void ngx_http_openidc_addHeaderWithPrefix(ngx_http_openidc_request_t* r,
		char* headerPrefix, int addHeaderToHttpRequest,
		const char* header, const char* value) {
	if(headerPrefix!=NULL) {
		char* headerName = apr_psprintf(r->pool, "%s%s", headerPrefix, oauth_toupper(r->pool, (char*)header));
		apr_table_set(r->headers_in, headerName, value);
		if(addHeaderToHttpRequest) {
			ngx_http_openidc_setHeader(r->httpRequest, headerName, value);
		}
	}
}

void ngx_http_openidc_processState(ngx_http_openidc_request_t* r) {
	uri_components *url = &r->parsed_uri;
	char tmp[OAUTH_IDTOKEN_MAX_SIZE];

	// set session state
	if(url_get_param(url->query,(char*)"session_state", tmp,OAUTH_IDTOKEN_MAX_SIZE)>0){
		char* session_state = apr_pstrdup(r->pool,tmp);
		if(session_state!=NULL) {
			char* cookieDrop=cookie_cookieTemplateByName(r->pool, "session_state", session_state, NULL, -1, FALSE);
			if(cookieDrop!=NULL){
				apr_table_add(r->headers_out, "Set-Cookie", cookieDrop);
			}
		}
	}
}

static ngx_inline ngx_uint_t
ngx_http_openidc_hash_str(u_char *src, size_t n)
{
    ngx_uint_t  key;

    key = 0;

    while (n--) {
        key = ngx_hash(key, *src);
        src++;
    }

    return key;
}

#define ngx_http_openidc_hash_literal(s)                                        \
    ngx_http_openidc_hash_str((u_char *) s, sizeof(s) - 1)


static ngx_int_t
ngx_http_openidc_set_content_headers(ngx_http_request_t *r, off_t contentLength, ngx_str_t contentType)
{
    ngx_table_elt_t                 *h, *header;
    u_char                          *p;
    ngx_list_part_t                 *part;
    ngx_http_request_t              *pr;
    ngx_uint_t                       i;

    r->headers_in.content_length_n = contentLength;

    if (ngx_list_init(&r->headers_in.headers, r->pool, 20,
                sizeof(ngx_table_elt_t)) != NGX_OK) {
        return NGX_ERROR;
    }

    // set content length
    h = ngx_list_push(&r->headers_in.headers);
    if (h == NULL) {
        return NGX_ERROR;
    }

    h->key = ngx_http_openidc_content_length_header_key;
    h->lowcase_key = ngx_pnalloc(r->pool, h->key.len);
    if (h->lowcase_key == NULL) {
        return NGX_ERROR;
    }

    ngx_strlow(h->lowcase_key, h->key.data, h->key.len);

    r->headers_in.content_length = h;

    p = ngx_palloc(r->pool, NGX_OFF_T_LEN);
    if (p == NULL) {
        return NGX_ERROR;
    }

    h->value.data = p;

    h->value.len = ngx_sprintf(h->value.data, "%O", contentLength) - h->value.data;

    h->hash = ngx_http_openidc_hash_literal("content-length");

    // set content-type
    h = ngx_list_push(&r->headers_in.headers);
    if (h == NULL) {
        return NGX_ERROR;
    }

    h->key = ngx_http_openidc_content_type_header_key;
    h->lowcase_key = ngx_pnalloc(r->pool, h->key.len);
    if (h->lowcase_key == NULL) {
        return NGX_ERROR;
    }

    ngx_strlow(h->lowcase_key, h->key.data, h->key.len);

    h->value = contentType;
    h->hash = ngx_http_openidc_hash_literal("content-type");
    r->headers_in.content_type = h;

    return NGX_OK;
}

int ngx_http_openidc_processRequest(ngx_http_openidc_request_t* r, config_core* 	configCore,
		oidc_config* oauthConfig, int addHeaderToHttpRequest, char* headerPrefix){

	if(oauthConfig==NULL||oauthConfig->oidcProvider==NULL) return NGX_DECLINED;

	if(oauthConfig->oidcProvider->issuer!=NULL) {
		apr_hash_set(r->variableHash,"issuer", APR_HASH_KEY_STRING, apr_pstrdup(r->pool, oauthConfig->oidcProvider->issuer));
	}
	if(oauthConfig->oidcProvider->authorizationEndpoint!=NULL) {
		apr_hash_set(r->variableHash,"authorization_endpoint", APR_HASH_KEY_STRING, apr_pstrdup(r->pool, oauthConfig->oidcProvider->authorizationEndpoint));
	}

    ngx_log_error(NGX_LOG_DEBUG, r->httpRequest->connection->log, 0, "oauth_processRequest");

	uri_components *url = &r->parsed_uri;
	char tmp[OAUTH_IDTOKEN_MAX_SIZE];
	int oidcSessionFound = FALSE;
	oauth_jwt_claim* claimObj = NULL;
	char* error = NULL;

	char* id_token=NULL;
	char* authHeader = (char*)apr_table_get(r->headers_in, "Authorization");
	if(authHeader==NULL) {
		if(url_get_param(url->query,(char*)"id_token",tmp,OAUTH_IDTOKEN_MAX_SIZE)>0){
			id_token = apr_pstrdup(r->pool,tmp);
		}
	}else{
		char* start = strstr(authHeader, "Bearer ");
		if(start!=NULL) {
			id_token = url_decode2(r->pool, start + 7);
		}
	}

	if(id_token!=NULL) {
		oauth_jwt* jwt = oauthutil_parseAndValidateIDToken(r->pool, id_token, oauth_getSignatureValidationKey, oauthConfig, &error);
		if(jwt==NULL||jwt->claim==NULL||jwt->claim->issuer==NULL||(strcmp(jwt->claim->issuer,oauthConfig->oidcProvider->issuer)!=0)) {
			ngx_http_openidc_addHeaderWithPrefix(r, headerPrefix, addHeaderToHttpRequest, OIDC_STATUS_HEADER, "failure");
			ngx_http_openidc_addHeaderWithPrefix(r, headerPrefix, addHeaderToHttpRequest, OIDC_DESC_HEADER, "oidc_parsing_failed");
			if(error!=NULL) { apr_table_add(r->headers_out, "X-OIDC-ERROR", error); }
			return NGX_DECLINED;
		}

		if(jwt->claim->issuer==NULL||oauthConfig->oidcProvider->issuer==NULL||(strcmp(jwt->claim->issuer,oauthConfig->oidcProvider->issuer)!=0)) {
			ngx_http_openidc_addHeaderWithPrefix(r, headerPrefix, addHeaderToHttpRequest, OIDC_STATUS_HEADER, "failure");
			ngx_http_openidc_addHeaderWithPrefix(r, headerPrefix, addHeaderToHttpRequest, OIDC_DESC_HEADER, "oidc_issuer_mismatch");
			apr_table_add(r->headers_out, "X-OIDC-ERROR", "oidc_issuer_mismatch");
			return NGX_DECLINED;
		}

		// check expiry
		if(oauthConfig->oidcSession->age>0) {
			jwt->claim->expiry = jwt->claim->issuedAt + (oauthConfig->oidcSession->age*86400);
		}

		if(configCore->cipherConfig!=NULL&&configCore->cipherConfig->crypto_passphrase!=NULL) {
			const char* serializedClaim = oauthutil_serializeJWTClaimNoEncoding(r->pool, jwt->claim);

			char* crypted = "";
			int status = cu_encryptAndBase64urlEncode(r->pool, configCore->cipherConfig, &crypted, (unsigned char *) serializedClaim, &error);
			if(status>0){
				char* cookieDrop=cookie_cookieTemplate(r->pool, oauthConfig->oidcSession, crypted, NULL);
				if(cookieDrop!=NULL){
					apr_table_add(r->headers_out, "Set-Cookie", cookieDrop);
				}
			}else{
				ngx_http_openidc_addHeaderWithPrefix(r, headerPrefix, addHeaderToHttpRequest, OIDC_STATUS_HEADER, "failure");
				ngx_http_openidc_addHeaderWithPrefix(r, headerPrefix, addHeaderToHttpRequest, OIDC_DESC_HEADER, "oidc_parsing_failed");
				apr_table_add(r->headers_out, "X-OIDC-ERROR", "oidc_claim_invalid");
				return NGX_DECLINED;
			}
		}

		claimObj = jwt->claim;

		// set session state
		ngx_http_openidc_processState(r);
	}


	if(claimObj==NULL&&configCore->cipherConfig!=NULL&&configCore->cipherConfig->crypto_passphrase!=NULL) { // check for cookie
		char* oidc_session = cookie_getCookie(r->pool, r->headers_in, oauthConfig->oidcSession);
		if(oidc_session!=NULL) {
			char* decrypted = "";
			int status = cu_base64urlDecodeAndDecrypt(r->pool, configCore->cipherConfig, &decrypted, oidc_session, &error);
			if(status>0){
				claimObj = oauthutil_deserializeJWTClaimNoDecoding(r->pool, decrypted);
			}else{
				ngx_http_openidc_addHeaderWithPrefix(r, headerPrefix, addHeaderToHttpRequest, OIDC_STATUS_HEADER, "failure");
				ngx_http_openidc_addHeaderWithPrefix(r, headerPrefix, addHeaderToHttpRequest, OIDC_DESC_HEADER, "oidc_session_expired");
				// delete current cookie
				cookie_deleteCookie(r->pool, r->headers_in, oauthConfig->oidcSession, NULL);
				return NGX_DECLINED;
			}
			oidcSessionFound = TRUE;
		}
	}

	if(claimObj!=NULL) {
		if(claimObj->expiry>apr_time_sec(apr_time_now())) {
			ngx_http_openidc_addHeaderWithPrefix(r, headerPrefix, addHeaderToHttpRequest, OIDC_STATUS_HEADER, "success");

		// set headers
			if(claimObj->issuer!=NULL) {
				// validate issuer
				if(oauthConfig->oidcProvider->issuer!=NULL&&(strcmp(claimObj->issuer,oauthConfig->oidcProvider->issuer)!=0)) {
					ngx_http_openidc_addHeaderWithPrefix(r, headerPrefix, addHeaderToHttpRequest, OIDC_STATUS_HEADER, "failure");
					ngx_http_openidc_addHeaderWithPrefix(r, headerPrefix, addHeaderToHttpRequest, OIDC_DESC_HEADER, "oidc_issuer_mismatch");
					apr_table_add(r->headers_out, "X-OIDC-ERROR", "oidc_issuer_mismatch");
					return NGX_DECLINED;
				}
				ngx_http_openidc_addHeaderWithPrefix(r, headerPrefix, addHeaderToHttpRequest, OIDC_ISSUER_HEADER, claimObj->issuer);
			}
			if(claimObj->subject!=NULL) {
				ngx_http_openidc_addHeaderWithPrefix(r, headerPrefix, addHeaderToHttpRequest, OIDC_SUBJECT_HEADER, claimObj->subject);
			}
			if(claimObj->audience!=NULL) {
				ngx_http_openidc_addHeaderWithPrefix(r, headerPrefix, addHeaderToHttpRequest, OIDC_AUDIENCE_HEADER, claimObj->audience);
			}
			if(claimObj->roles!=NULL) {
				char* rolesCsv = cu_serializeCsvFromStringArray(r->pool, claimObj->roles);
				if(rolesCsv!=NULL) {
					ngx_http_openidc_addHeaderWithPrefix(r, headerPrefix, addHeaderToHttpRequest, OIDC_ROLES_HEADER, rolesCsv);
				}
			}
			if(claimObj->options!=NULL) {
				//validate nonce
				char* oidcNonce = apr_hash_get(claimObj->options,"nonce", APR_HASH_KEY_STRING);
				char* rpSessionID = apr_table_get(r->headers_in, OIDC_RP_SESSIONID);
				if(oidcNonce!=NULL&&rpSessionID!=NULL&&(strcmp(oidcNonce,rpSessionID)!=0)) {
					ngx_http_openidc_addHeaderWithPrefix(r, headerPrefix, addHeaderToHttpRequest, OIDC_STATUS_HEADER, "failure");
					ngx_http_openidc_addHeaderWithPrefix(r, headerPrefix, addHeaderToHttpRequest, OIDC_DESC_HEADER, "oidc_nonce_mismatch");
					apr_table_add(r->headers_out, "X-OIDC-ERROR", "oidc_nonce_mismatch");
					return NGX_DECLINED;
				}

				apr_hash_index_t *hi;
				char* name=NULL,*value=NULL;
				for (hi = apr_hash_first(r->pool, claimObj->options); hi; hi = apr_hash_next(hi)) {
					apr_hash_this(hi,(const void**)&name, NULL, (void**)&value);
					ngx_http_openidc_addHeaderWithPrefix(r, headerPrefix, addHeaderToHttpRequest, name, value);
				}
			}
		}else{
			ngx_http_openidc_addHeaderWithPrefix(r, headerPrefix, addHeaderToHttpRequest, OIDC_STATUS_HEADER, "failure");
			ngx_http_openidc_addHeaderWithPrefix(r, headerPrefix, addHeaderToHttpRequest, OIDC_DESC_HEADER, "oidc_claim_expired");
			if(oidcSessionFound==TRUE) {
				cookie_deleteCookie(r->pool, r->headers_in, oauthConfig->oidcSession,NULL);
			}
		}
	}

	return NGX_DECLINED;
}

static ngx_int_t ngx_http_openidc_checkForAccess(ngx_http_request_t *httpRequest) {
    char* hostname=NULL;
    pool* p;
    
    // care about only primary request
    if (httpRequest != httpRequest->main) return NGX_DECLINED;
    
    ngx_http_openidc_srv_conf_t* conf =(ngx_http_openidc_srv_conf_t*) ngx_http_get_module_srv_conf(httpRequest, ngx_http_openidc_module);
    
	if(conf==NULL||conf->config==NULL||conf->config->configCore==NULL||conf->config->oidcConfig==NULL) return NGX_DECLINED;
	
    // create a request pool.
	if(apr_pool_create(&p, mainPool)!=APR_SUCCESS){
		return NGX_DECLINED;
	}
    
	//sync config core
	if(cfg_syncSelf(p,conf->config->configCore)>0){
		ngx_http_openidc_postRefreshBind(p,conf->config);
	}

	//set method type
	ngx_http_openidc_deleteHeader(httpRequest, (u_char *)"X-REQUEST-METHOD");
	char* method = apr_pstrndup(p, (char*)httpRequest->method_name.data, httpRequest->method_name.len);
	ngx_http_openidc_setHeader(httpRequest, "X-REQUEST-METHOD", method);

	//set scheme
	int isHttps = FALSE;
#if (NGX_SSL)
	if (httpRequest->connection->ssl&&httpRequest->connection->ssl->connection) {
		isHttps = TRUE;
	}
#endif
	ngx_http_openidc_deleteHeader(httpRequest, (u_char *)"X-REQUEST-SCHEME");
	ngx_http_openidc_setHeader(httpRequest, "X-REQUEST-SCHEME", (isHttps) ? "https" : "http");

	// create the request.
	ngx_http_openidc_request_t* r = ngx_http_openidc_createRequest(p);
	r->httpRequest = httpRequest;

	//set url
	char* uri = apr_pstrndup(r->pool, (char*)httpRequest->unparsed_uri.data, httpRequest->unparsed_uri.len);
	r->unparsed_uri = apr_pstrdup(r->pool, uri);
    while ((uri[0] == '/') && (uri[1] == '/')) {
        ++uri ;
    }
    apr_uri_parse(r->pool, uri, &r->parsed_uri);
    r->uri = r->parsed_uri.path ? r->parsed_uri.path : apr_pstrdup(r->pool, "/");
    
	//printf("%s, %d r->uri%s: internal=%d\n", __FILE__, __LINE__, r->uri, httpRequest->internal);

	// set headers_in
	ngx_http_openidc_setHeadersIn(httpRequest, r, conf->config->configCore->oidcHeaderPrefix);

	 //set hostname
	ngx_table_elt_t* host = httpRequest->headers_in.host;
	if (host!=NULL) {
		hostname = apr_pstrndup(r->pool, (char*)host->value.data, host->value.len);
	}else{
		hostname = (char*)apr_table_get(r->headers_in, "Host");
	}
	r->hostname = hostname;
	 
	//client-ip
	char* xff = (char*)apr_table_get(r->headers_in, "X-Forwarded-For");
	if(xff==NULL) {
		struct sockaddr_in *sin = (struct sockaddr_in *) httpRequest->connection->sockaddr;
		if(sin!=NULL) {
			r->connection_remote_ip = apr_pstrdup(r->pool, inet_ntoa(sin->sin_addr));
		}else{
			r->connection_remote_ip = apr_pstrdup(r->pool, "127.0.0.1");
		}
	}else{
		char* second=NULL;
		char* srccpy = apr_pstrdup(r->pool, xff);
		r->connection_remote_ip = apr_strtok(srccpy, ",", &second);
	}

    // run preAuth
	int retCode = ngx_http_openidc_preAuthorize(r, conf->config);
	if(retCode!=NGX_DECLINED) {
		apr_pool_destroy(p);
		return retCode;
	}

	// generate unique sessionID;
	// TODO: needs to be replace with ACS session
	char* rpSessionID = cookie_getCookie(p, r->headers_in, conf->config->oidcConfig->rpSession);
	if(rpSessionID==NULL) {
		rpSessionID = cu_generateGuid(r->pool);
		char* cookieDrop = cookie_cookieTemplate(r->pool, conf->config->oidcConfig->rpSession, rpSessionID, NULL);
		if(cookieDrop!=NULL){
			apr_table_add(r->headers_out, "Set-Cookie", cookieDrop);
		}
	}
	apr_table_set(r->headers_in, OIDC_RP_SESSIONID, rpSessionID);
	ngx_http_openidc_setHeader(r->httpRequest, OIDC_RP_SESSIONID, rpSessionID);

	// Authorization phase
	retCode = ngx_http_openidc_processRequest(r, conf->config->configCore, conf->config->oidcConfig, TRUE, conf->config->configCore->oidcHeaderPrefix);
	if(retCode!=NGX_DECLINED) {
		apr_table_do(ngx_http_openidc_addResponseHeaderCallback, httpRequest, r->headers_out, NULL);
		retCode = ngx_http_openidc_sendResponse(r);
		apr_pool_destroy(p);
		return retCode;
	}

	// post Auth phase
	path_mapping* pathmapping=am_getPathMapping_PostAuth(r->pool,conf->config->oidcConfig,r->unparsed_uri,r->connection_remote_ip,r->headers_in,NULL);
	if(pathmapping!=NULL){
		page_action* action=am_getMatchingPageAction(r->pool,pathmapping->pmactions,r->unparsed_uri,r->connection_remote_ip,r->headers_in,NULL);
		char* originUri=ngx_http_openidc_getFullRequestUrl(r);
		retCode = ngx_http_openidc_execPageAction(r, action,originUri);
		apr_table_do(ngx_http_openidc_addResponseHeaderCallback, httpRequest, r->headers_out, NULL);
		if(action!=NULL&&action->handler_internal!=NULL) {
			r->handler = apr_pstrdup(r->pool, action->handler_internal);
			int i;
			int numHandlers=sizeof(ngx_http_oidcHandlers)/sizeof(ngx_http_openidc_handler_t);
			for(i=0; i<numHandlers; i++){
				retCode=(*ngx_http_oidcHandlers[i].handlerFunc)(r, conf->config);
				if(retCode!=NGX_DECLINED) {
					retCode = ngx_http_openidc_sendResponse(r);
					break;
				}
			}
		}
	}
	
	// release memory
	apr_pool_destroy(p);
	
	return retCode;
}

static ngx_int_t ngx_http_openidc_handler(ngx_http_request_t * httpRequest) {
	char* hostname;
    pool* p;
    int retCode = NGX_DECLINED;
    
	ngx_http_openidc_srv_conf_t* conf =(ngx_http_openidc_srv_conf_t*) ngx_http_get_module_srv_conf(httpRequest, ngx_http_openidc_module);
	
	if(conf==NULL||conf->config==NULL||conf->config->configCore==NULL) return NGX_DECLINED;
		
    // create a request pool.
	if(apr_pool_create(&p, mainPool)!=APR_SUCCESS){
		return NGX_DECLINED;
	}
    
	// create the request.
	ngx_http_openidc_request_t* r = ngx_http_openidc_createRequest(p);
	r->httpRequest = httpRequest;
	
	//set url
	char* uri = apr_pstrndup(r->pool, (char*)httpRequest->unparsed_uri.data, httpRequest->unparsed_uri.len);
	r->unparsed_uri = apr_pstrdup(r->pool, uri);
	
	if(rc_matchByStrings(p, "^/oidc", uri)!=0) {
		// release memory
		apr_pool_destroy(p);
		return NGX_DECLINED;
	}
	
    while ((uri[0] == '/') && (uri[1] == '/')) {
        ++uri ;
    }
    apr_uri_parse(r->pool, uri, &r->parsed_uri);
    r->uri = r->parsed_uri.path ? r->parsed_uri.path : apr_pstrdup(r->pool, "/");
    
	// set headers_in
	ngx_http_openidc_setHeadersIn(httpRequest, r, conf->config->configCore->oidcHeaderPrefix);

	 //set hostname
	ngx_table_elt_t* host = httpRequest->headers_in.host;
	if (host!=NULL) {
		hostname = apr_pstrndup(r->pool, (char*)host->value.data, host->value.len);
	}else{
		hostname = (char*)apr_table_get(r->headers_in, "Host");
	}
	r->hostname = hostname;
	 
	//client-ip
	struct sockaddr_in *sin = (struct sockaddr_in *) httpRequest->connection->sockaddr;
	if(sin!=NULL) {
		r->connection_remote_ip = apr_pstrdup(r->pool, inet_ntoa(sin->sin_addr));
	}else{
		r->connection_remote_ip = apr_pstrdup(r->pool, "127.0.0.1");
	}
	
	//sync config core
	if(cfg_syncSelf(r->pool,conf->config->configCore)>0){
		ngx_http_openidc_postRefreshBind(r->pool,conf->config);
	}
	
	path_mapping* pathmapping=am_getPathMapping_PostAuth(r->pool,conf->config->oidcConfig,r->unparsed_uri,r->connection_remote_ip,r->headers_in,NULL);
	if(pathmapping!=NULL){
		page_action* action=am_getMatchingPageAction(r->pool,pathmapping->pmactions,r->unparsed_uri,r->connection_remote_ip,r->headers_in,NULL);
		if(action!=NULL&&action->handler_internal!=NULL) {
			r->handler = apr_pstrdup(r->pool, action->handler_internal);
			int i;
			int numHandlers=sizeof(ngx_http_oidcHandlers)/sizeof(ngx_http_openidc_handler_t);
			for(i=0; i<numHandlers; i++){
				int retCode=(*ngx_http_oidcHandlers[i].handlerFunc)(r, conf->config);
				if(retCode!=NGX_DECLINED) {
					retCode = ngx_http_openidc_sendResponse(r);
					break;
				}
			}
			
		}
	}
	
	// release memory
	apr_pool_destroy(p);
	
	return retCode;
	
}

int oidc_index(ngx_http_openidc_request_t *r, Config* config) {

	if (strcmp(r->handler, "oidc_index")) {
		return NGX_DECLINED;
	}

	ngx_http_openidc_rputs("<HTML>\n",r);
	ngx_http_openidc_rprintf(r,"<HEAD><TITLE>Tool Index</TITLE></HEAD>\n");
	ngx_http_openidc_rputs("<BODY>\n",r);
	ngx_http_openidc_rprintf(r,"<LEFT><H1>Tool Index</H1></LEFT><BR>\n");
	ngx_http_openidc_rputs("<TABLE align='left'><tr>",r);
	ngx_http_openidc_rputs("<td valign='top'><table><tr><td><b><font color='green'>Handlers</font></b></td></tr>",r);
	ngx_http_openidc_rputs("<TR><TD><a href='/oidc/version'>Version Details</a></TD></TR>",r);
    ngx_http_openidc_rputs("<TR><TD><a href='/oidc/config-status'>ConfigCore Details</a></TD></TR>",r);
	ngx_http_openidc_rputs("<TR><TD><a href='/oidc/rewrite-pageactions'>OIDC Actions Details</a></TD></TR>",r);
	ngx_http_openidc_rputs("<TR><TD><a href='/oidc/rewrite-actionmappings'>OIDC Config Details</a></TD></TR>",r);
    ngx_http_openidc_rputs("<TR><TD><a href='/oidc/headers'>Show Headers</a></TD></TR>",r);
	ngx_http_openidc_rputs("</table>",r);
	ngx_http_openidc_rputs("</td>",r);

	ngx_http_openidc_rputs("</table>",r);

	ngx_http_openidc_rputs("</td>",r);

	ngx_http_openidc_rputs("</tr></TABLE>",r);

	ngx_http_openidc_rputs("</BODY></HTML>",r);
    return NGX_OK;
}

int oidc_version(ngx_http_openidc_request_t *r, Config* config){
	
    if (strcmp(r->handler, "oidc_version")) {
            return NGX_DECLINED;
    }

	ngx_http_openidc_rputs("<HTML>\n",r);
	ngx_http_openidc_rprintf(r,"<HEAD><TITLE>Version Info</TITLE></HEAD>\n");
	ngx_http_openidc_rputs("<BODY>\n",r);
	
	ngx_http_openidc_rputs("<TABLE>",r);
	ngx_http_openidc_rprintf(r,"<TR><TD colspan='2'><b>Version Info</b></td></tr>\n");
	ngx_http_openidc_rprintf1(r,"<TR><TD>Module: </td><td>%s</td></tr>\n",VERSION_ID);
	ngx_http_openidc_rprintf1(r,"<TR><TD>LibCurl: </td><td>%s</td></tr>\n",hc_getInfo(r->pool));
	ngx_http_openidc_rprintf1(r,"<TR><TD>RewriteCore: </td><td>PCRE/%s</td></tr>\n",rc_getInfo(r->pool));
	ngx_http_openidc_rprintf1(r,"<TR><TD>Server: </td><td>%s</td></tr>\n",NGINX_VER);
	ngx_http_openidc_rputs("</TABLE>",r);
	return NGX_OK;
}

/*
 * Rewrite Handlers
 */
static void rewrite_pageaction_display(ngx_http_openidc_request_t *r,page_action* pa,match_list* ml){
	if(pa!=NULL){
		ngx_http_openidc_rprintf1(r,"<td>%s",pa->id);
		if(ml&&ml->name!=NULL){
			ngx_http_openidc_rprintf1(r,"<br/>MatchList:%s",ml->name);
		}
		ngx_http_openidc_rprintf(r,"</td>");
		ngx_http_openidc_rprintf1(r,"<td>%s</td>",pa->handler_internal);
		ngx_http_openidc_rprintf1(r,"<td>%s</td>",SAFESTR(pa->uri));
		ngx_http_openidc_rprintf1(r,"<td>%s</td>",SAFESTR(pa->regex));
		ngx_http_openidc_rprintf1(r,"<td>%s</td>",pa->isForward!=1?"false":"true");
		ngx_http_openidc_rprintf1(r,"<td>%s</td>",pa->isPermanent!=1?"false":"true");
		ngx_http_openidc_rprintf1(r,"<td>%s</td>",pa->description);
	}else{
		ngx_http_openidc_rputs("<td colspan='5'>&nbsp</td>",r);
	}
}

static const char* authzoidc_getActionStr(header_actions action) {
	if (action==header_add)
		return "add";
    else if (action==header_set)
		return "set";
    else if (action==header_append)
		return "append";
    else if (action==header_merge)
		return "merge";
    else if (action==header_unset)
		return "unset";
    else if (action==header_echo)
		return "echo";
    else if (action==header_edit)
		return "edit";
	return "null";
}

static const char* authzoidc_getActionTypeStr(action_types type) {
	if (type==action_login)
		return "login";
    else if (type==action_denial)
		return "denial";
    else if (type==action_authorize)
		return "authorize";
    else if (type==action_callback)
		return "callback";
	return "null";
}

void authzoidc_displayActionHeader(ngx_http_openidc_request_t*r, action_header* hdr) {
	
	if(hdr==NULL) return;
	
	if(hdr->action==header_unset) {
		ngx_http_openidc_rprintf2(r,"<tr><td>&nbsp;&nbsp;</td><td><li>%s&nbsp;{%s}</td></tr>",
				authzoidc_getActionStr(hdr->action),hdr->name);
	}
	else {
		if(hdr->regex!=NULL) {
			ngx_http_openidc_rprintf4(r,"<tr><td>&nbsp;&nbsp;</td><td><li>%s&nbsp;{%s:%s}&nbsp;regex:%s</td></tr>",
					authzoidc_getActionStr(hdr->action),hdr->name, hdr->value, hdr->regex);
		}else{
			ngx_http_openidc_rprintf3(r,"<tr><td>&nbsp;&nbsp;</td><td><li>%s&nbsp;{%s:%s}</td></tr>",
					authzoidc_getActionStr(hdr->action),hdr->name, hdr->value);
		}
	}
}

static void rewrite_pageaction_displayAll(ngx_http_openidc_request_t *r,page_action* pa){
	int i=0;
	array_header* arry=NULL;
	if(pa!=NULL){
		ngx_http_openidc_rputs("<table>",r);
		ngx_http_openidc_rprintf1(r,"<tr><td>&nbsp;</td><td><strong>%s</strong>",SAFESTR(pa->id));
		if(pa->isDebug==1){ngx_http_openidc_rprintf(r," <font color='maroon'>DEBUG</font> ");}
		if(pa->description!=NULL){ngx_http_openidc_rprintf1(r," [%s]</td></tr>",pa->description);}else{ngx_http_openidc_rprintf(r,"</td></tr>");}
		
		if(pa->regex!=NULL){ngx_http_openidc_rprintf1(r,"<tr><td>&nbsp;</td><td>Regex: %s</td></tr>",SAFESTR(pa->regex));}
		if(pa->oidcProvider!=NULL){ngx_http_openidc_rprintf1(r,"<tr><td>&nbsp;</td><td>OIDCProvider: %s</td></tr>",SAFESTR(pa->oidcProvider));}
		if(pa->relyingParty!=NULL){ngx_http_openidc_rprintf1(r,"<tr><td>&nbsp;</td><td>RelyingParty: %s</td></tr>",SAFESTR(pa->relyingParty));}
		if(pa->handler_internal!=NULL){ngx_http_openidc_rprintf1(r,"<tr><td>&nbsp;</td><td>Handler: %s</td></tr>",pa->handler_internal);}
		if(pa->response!=NULL){ngx_http_openidc_rprintf3(r,"<tr><td>&nbsp;</td><td>Response[%d:%s]: <xmp>%s</xmp></td></tr>",pa->response->code, pa->response->contentType, pa->response->body);}
		if(pa->uri!=NULL) { ngx_http_openidc_rprintf1(r,"<tr><td>&nbsp;</td><td>Uri:%s</td></tr>",pa->uri); }
		ngx_http_openidc_rprintf1(r,"<tr><td>&nbsp;</td><td>isForward: %s</td></tr>",pa->isForward!=1?"false":"true");
		ngx_http_openidc_rprintf1(r,"<tr><td>&nbsp;</td><td>isPermanent: %s</td></tr>",pa->isPermanent!=1?"false":"true");
		ngx_http_openidc_rprintf1(r,"<tr><td>&nbsp;</td><td>type: %s</td></tr>", authzoidc_getActionTypeStr(pa->type));
		if(pa->advancedTemplate==TRUE){
			ngx_http_openidc_rprintf(r,"<tr><td>&nbsp;</td><td>advancedTemplate: true</td></tr>");
		}
		if(pa->base64UrlEncodeState==TRUE){
			ngx_http_openidc_rprintf(r,"<tr><td>&nbsp;</td><td>base64UrlEncodeState: true</td></tr>");
		}
		if(pa->requestHeaders!=NULL){
			ngx_http_openidc_rprintf1(r,"<tr><td>&nbsp;</td><td>RequestHeaders[%d]</td></tr>",pa->requestHeaders->nelts);
			for(i=0; i<pa->requestHeaders->nelts; i++){
				action_header* hdr = (action_header*)cu_getElement(pa->requestHeaders, i);
				authzoidc_displayActionHeader(r,hdr);
			}
		}			
		if(pa->responseHeaders!=NULL){
			ngx_http_openidc_rprintf1(r,"<tr><td>&nbsp;</td><td>ResponseHeaders[%d]</td></tr>",pa->responseHeaders->nelts);
			for(i=0; i<pa->responseHeaders->nelts; i++){
				action_header* hdr = (action_header*)cu_getElement(pa->responseHeaders, i);
				authzoidc_displayActionHeader(r,hdr);
			}
		}
		ngx_http_openidc_rputs("</table>",r);
	}else{
		ngx_http_openidc_rputs("NULL",r);
	}
	
}
	
static void authzoidc_errorMessage(ngx_http_openidc_request_t *r){
	ngx_http_openidc_rputs("<HTML>\n",r);
	ngx_http_openidc_rprintf(r,"<HEAD><TITLE>Rewrite Page Actions - NULL</TITLE></HEAD>\n");
	ngx_http_openidc_rprintf(r,"<body>ActionMappings are NULL</body>\n");
	ngx_http_openidc_rprintf(r,"</html>\n");
}

static void authzoidc_pathmappings_displayMatchList(ngx_http_openidc_request_t *r,array_header* arr){
	int i=0;
	match_list* list=NULL;
	if(arr!=NULL&&arr->nelts>0){
		ngx_http_openidc_rprintf(r,"<br/>MatchLists:");
		for(i=0;i<arr->nelts;i++){
			list=(match_list*)cu_getElement(arr,i);
			if(i!=0){ngx_http_openidc_rprintf(r,",");}
			ngx_http_openidc_rprintf1(r,"%s",list->name);
		}
	}
}

static void authzoidc_pathmappings_display(ngx_http_openidc_request_t *r,array_header* arr,char* name){
	int x=0;
	path_mapping* pmap=NULL;
	int i=0;
	pathmapping_action* pmaction=NULL;
	
	ngx_http_openidc_rprintf2(r,"<br><b><font color='blue'>Path Mappings - %s (%d)</font></b>",name,arr->nelts);
	if(name,arr->nelts>0){
		ngx_http_openidc_rputs("<TABLE border='1'>",r);
		ngx_http_openidc_rputs("<tr><td>Path Regex</td><td>ID</td><td>handler</td><td>uri</td><td>Regex</td><td>isForward</td><td>isPermanent</td><td>Description</td></tr>",r);
		for(x=0;x<arr->nelts;x++){
			pmap=(path_mapping*)cu_getElement(arr,x);
			if(pmap->pmactions!=NULL&&pmap->pmactions->nelts>0){
				for(i=0;i<pmap->pmactions->nelts;i++){
					if ( pmap->ignoreCase==TRUE ) {
						ngx_http_openidc_rprintf1(r,"<tr><td><b>%s</b><br>IgnoreCase=true</br>",pmap->pathRegex);
					}else{
						ngx_http_openidc_rprintf1(r,"<tr><td><b>%s</b>",pmap->pathRegex);
					}
					authzoidc_pathmappings_displayMatchList(r,pmap->matchLists);
					ngx_http_openidc_rprintf(r,"</td>");
					pmaction=(pathmapping_action*)cu_getElement(pmap->pmactions,i);
					rewrite_pageaction_display(r,pmaction->action,pmaction->matchList);
					ngx_http_openidc_rputs("</td></tr>",r);
				}
			}
		}
		ngx_http_openidc_rputs("</TABLE>",r);
	}
}


static void authzoidc_pathmapping_display_withnote(ngx_http_openidc_request_t *r,path_mapping* pathMap,page_action*action,char* note, apr_time_t startTime){
		
		if(pathMap!=NULL){
				ngx_http_openidc_rprintf2(r,"<tr><td>%s</td><td>%d us</td>",note, apr_time_now()-startTime);
				ngx_http_openidc_rprintf1(r,"<td><font color='darkgreen'>%s</font>",pathMap->pathRegex);
				authzoidc_pathmappings_displayMatchList(r,pathMap->matchLists);
				ngx_http_openidc_rprintf(r,"</td>");
				rewrite_pageaction_display(r,action,NULL);
		}else{
				ngx_http_openidc_rprintf1(r,"<tr><td>%s</td><td>(Default)</td>",note);
				rewrite_pageaction_display(r,NULL,NULL);
		}
		ngx_http_openidc_rputs("</tr>",r);
}


static int authzoidc_printTableCallBack(void *rec, const char *key, const char *value){
		ngx_http_openidc_request_t *r=(ngx_http_openidc_request_t*)rec;
		if(strstr(key,"Cookie")==0) {
			ngx_http_openidc_rprintf2(r,"<tr><td>%s = </td><td>%s</td></tr>\r\n",key,value);
		}
		return 1;
	}
static void authzoidc_printTable(ngx_http_openidc_request_t *r,apr_table_t* table){
	if(table!=NULL&&!apr_is_empty_table(table)){
		ngx_http_openidc_rputs("<TABLE><tr><td valign='top'>Table Headers:</td><td><table>",r);
		apr_table_do(authzoidc_printTableCallBack,(void*)r,table,NULL);
		ngx_http_openidc_rputs("</table></td></tr></TABLE>",r);
	}
}
	
static int authzoidc_pathMatchSection(ngx_http_openidc_request_t *r, Config* config){
	oidc_config* actm=config->oidcConfig;
	uri_components *url = &r->parsed_uri;
	path_mapping* pathMap=NULL;
	char* pathParam=NULL;
	char* overlayParam=NULL;
	char* headersInParam=NULL;
	char* ipParam=NULL;
	apr_table_t* headers_in=NULL, *r_headers=NULL;
	page_action*action=NULL;
	apr_time_t startTime;
	
	if(actm==NULL){
		authzoidc_errorMessage(r);
		return NGX_OK;
	}
	pathParam=url_getParam(r->pool,url->query,"pathParam");
	
	headersInParam=url_getParam(r->pool,url->query,"headersInParam");
		
	ipParam=url_getParam(r->pool,url->query,"ipParam");
	if(ipParam==NULL){
		ipParam=r->connection_remote_ip;
	}
	
	ngx_http_openidc_rputs("Check Path Mapping:<br>",r);
	ngx_http_openidc_rputs("<form><table>",r);
	ngx_http_openidc_rprintf1(r,"<tr><td>IP:</td><td><input type='text' name='ipParam' size='30'  value='%s'></td></tr>\r\n",SAFESTRBLANK(ipParam));
	ngx_http_openidc_rprintf1(r,"<tr><td>Path:</td><td><input type='text' name='pathParam' size='80' value='%s'/></td></tr>",SAFESTRBLANK(pathParam));
	ngx_http_openidc_rprintf1(r,"<tr><td valign='top'>HeadersIn:</td><td><textarea name='headersInParam' cols='60' rows='4'>%s</textarea></td></tr>\r\n",SAFESTRBLANK(headersInParam));
	ngx_http_openidc_rputs("<tr><td colspan='2'><INPUT type='submit' value='Match' /></td></tr>\n",r);
	ngx_http_openidc_rputs("</table></form>\n",r);
	if(pathParam!=NULL){
		headers_in=cu_parseNvpTableFromCsv(r->pool,"\n",":",headersInParam);
		if(overlayParam!=NULL){
			if(headers_in!=NULL){
				//headers_in=apr_table_overlay(r->pool,headers_in,r->headers_in);
				//apr_table_compress(headers_in,APR_OVERLAP_TABLES_SET);
				r_headers=apr_table_copy(r->pool,r->headers_in);
				apr_table_overlap(r_headers,headers_in,APR_OVERLAP_TABLES_SET);
				headers_in=r_headers;
			}else{
				headers_in=r->headers_in;
			}
		}
		
		ngx_http_openidc_rputs("<TABLE border='1' cellspacing='0' bordercolor='blue'>",r);

		//postauth
		startTime=apr_time_now();
		pathMap=am_getPathMapping_PostAuth(r->pool,actm,pathParam,ipParam,headers_in,NULL);
		if(pathMap!=NULL){
			action=am_getMatchingPageAction(r->pool,pathMap->pmactions,r->unparsed_uri,ipParam,headers_in,NULL);
			if(action!=NULL){authzoidc_pathmapping_display_withnote(r,pathMap,action,"PostAuth",startTime);}
		}
					
		ngx_http_openidc_rputs("</TABLE>",r);
		authzoidc_printTable(r,headers_in);
	}
	
	
	return 1;
}
static char* authzoidc_getMatchIpDetails(pool*p,match_ip*ip){
	char* ipDetails;
	
	if(ip==NULL||ip->ip==NULL)	return NULL;
	
	ipDetails=apr_pstrdup(p,ip->ip);
	if(ip->negate==TRUE){ipDetails=apr_pstrcat(p,ipDetails,"\tnegate=true",NULL);}
	if(ip->isRegex==FALSE){ipDetails=apr_pstrcat(p,ipDetails,"\tisregex=false",NULL);};
	
	return ipDetails;
}
static char* authzoidc_getMatchPathDetails(pool*p,match_path*path){
	char* pathDetails;
	
	if(path==NULL||path->path==NULL)	return NULL;
	
	pathDetails=apr_pstrdup(p,path->path);
	if(path->negate==TRUE){pathDetails=apr_pstrcat(p,pathDetails,"\tnegate=true",NULL);}
	
	return pathDetails;
}	
static char* authzoidc_getHeaderDetails(pool*p,match_list_header*hdr){
	char* hdrDetails;
	
	if(hdr==NULL)	return NULL;
	
	hdrDetails=apr_pstrcat(p,hdr->name,"=",hdr->value,NULL);
	if(hdr->delimAnd){hdrDetails=apr_pstrcat(p,hdrDetails,"\tdelimAnd=\"",hdr->delimAnd,"\"",NULL);}
	if(hdr->negate==TRUE){hdrDetails=apr_pstrcat(p,hdrDetails,"\tnegate=true",NULL);}
	if(hdr->isRegex==FALSE){hdrDetails=apr_pstrcat(p,hdrDetails,"\tisregex=false",NULL);};
	
	return hdrDetails;
} 

static char* authzoidc_timeString(pool*p, time_t t, const char* def){
	if(t<=0) return (char*)def;
	char tmp[40]={0};
	ctime_r(&t, tmp);
	return apr_psprintf(p, "%s[%d]", tmp, t);
}

static char* authzoidc_getEventColor(pool*p, match_event*e){
	char*color=NULL;
	time_t currentTime = time(NULL);
	
	if(( e->start < currentTime ) 
					&& ( currentTime < ( (e->end>0) ? e->end : TIME_MAX) )){
		color =  apr_pstrdup(p, "green");
	}else if(e->start > currentTime){//Future events
		color =  apr_pstrdup(p, "yellow");
	}else{//Past events
		color =  apr_pstrdup(p, "red");
	}
	return color;
}

static void authzoidc_printMatchListMatch(ngx_http_openidc_request_t *r,match_list_match* match){
	int i=0;
	//match_list_match_nvp* nvp=NULL;
	match_list_header* hdr=NULL;
	match_list_env* env=NULL;
	if(match==NULL) return;
	ngx_http_openidc_rprintf(r,"<table><tr><td valign='top'><li/></td>");
	if(match->cascade==FALSE){
		ngx_http_openidc_rprintf(r,"<td valign='top'>Cascade:</td><td align='left'>false</td></tr><tr><td>&nbsp;</td>");
	}		
	if(match->host!=NULL){
		ngx_http_openidc_rprintf1(r,"<td valign='top'>Host:</td><td align='left'>%s</td></tr><tr><td>&nbsp;</td>", match->host);
	}		
	if(match->ip!=NULL){
		ngx_http_openidc_rprintf1(r,"<td valign='top'>IP:</td><td align='left'>%s</td></tr><tr><td>&nbsp;</td>",
				authzoidc_getMatchIpDetails(r->pool,match->ip));
	}
	if(match->path!=NULL){
		ngx_http_openidc_rprintf1(r,"<td valign='top'>Path:</td><td align='left'>%s</td></tr><tr><td>&nbsp;</td>",
				authzoidc_getMatchPathDetails(r->pool,match->path));
	}
	if(match->event!=NULL){
		ngx_http_openidc_rprintf3(r, "<td valign='top'>Event:</td><td valign='top'><font color='%s'><li/></td><td><table><tr><td><i/>Start:</td><td>%s</td><td><i/>End:</td><td>%s</td></font></tr></tr></table></td></tr><td>&nbsp;</td>",
				authzoidc_getEventColor(r->pool, match->event),
				authzoidc_timeString(r->pool, match->event->start, "Unknown"),
				authzoidc_timeString(r->pool, match->event->end, "Never") );
	}		
	if(match->headerList!=NULL&&match->headerList->nelts>0){
		ngx_http_openidc_rprintf(r,"<td valign='top'>Headers:</td><td>");
		ngx_http_openidc_rprintf(r,"<table>");
		for(i=0;i<match->headerList->nelts;i++){
			hdr=(match_list_header*)cu_getElement(match->headerList,i);
			ngx_http_openidc_rprintf1(r,"<tr><td valign='top'>%s</td></tr>",authzoidc_getHeaderDetails(r->pool,hdr));
		}
		ngx_http_openidc_rprintf(r,"</table>");
		ngx_http_openidc_rprintf(r,"</td></tr>");
	}
	ngx_http_openidc_rprintf(r,"</table>");
}
static void authzoidc_matchLists(ngx_http_openidc_request_t *r,oidc_config* actm){
	match_list* list=NULL;
	shapr_hash_index_t * hi=NULL;
	match_list_match* match=NULL;
	int i=0;
	void* val=NULL;
	unsigned int cnt=0;
	
	ngx_http_openidc_rputs("<TABLE>",r);
	cnt=shapr_hash_count(actm->match_lists);
	ngx_http_openidc_rprintf1(r,"<tr><td colspan='4'><font color='maroon'><strong>MatchLists [%d]:</strong></font></td></tr>",cnt);
	if(cnt>0){
		for (hi = shapr_hash_first(r->pool,actm->match_lists); hi; hi = shapr_hash_next(hi)) {
	           shapr_hash_this(hi, NULL, NULL, &val);
	     	   if(val!=NULL){
	     		  list=(match_list*)val;
	     		  ngx_http_openidc_rprintf1(r,"<tr><td width='15'>&nbsp;</td><td>&nbsp;</td><td valign='top'>%s</td><td>",list->name);
	     		  
	     		  ngx_http_openidc_rputs("<table>",r);
	     		  for(i=0;i<list->list->nelts;i++){
	     			  match=(match_list_match*)cu_getElement(list->list,i);
	     			  ngx_http_openidc_rputs("<tr><td>",r);
	     			 authzoidc_printMatchListMatch(r,match);
	     			  ngx_http_openidc_rputs("</td></tr>",r);
	     		  }
	     		  ngx_http_openidc_rputs("</table>",r);
	     		  ngx_http_openidc_rputs("</td></tr>",r);
	     	   }
		}
	}
	ngx_http_openidc_rputs("</TABLE>",r);
}

static void authzoidc_displayTemplateEngine(ngx_http_openidc_request_t *r,template_engine* tengine){
	shapr_hash_index_t* hi;
	template_eng_livetemplate* lt=NULL;
	void* val, * key;
	
	ngx_http_openidc_rputs("<TABLE>",r);
	ngx_http_openidc_rprintf1(r,"<tr><td>Template Engine:</td><td>%s</td></tr>",tengine!=NULL?"VALID":"FAIL");
	if(tengine!=NULL){
		
		ngx_http_openidc_rputs("<tr><td colspan='2'><TABLE>",r);
		ngx_http_openidc_rprintf(r,"<tr><td>Token:</td><td> Description</td><td> Test Result</td></tr>");
		for(hi=shapr_hash_first(r->pool,tengine->templateHash);hi;hi=shapr_hash_next(hi)){
			shapr_hash_this(hi,(const void**)&key,NULL,&val);
			lt=(template_eng_livetemplate*)val;
			if(lt->engineTemplate!=NULL){
				ngx_http_openidc_rprintf2(r,"<tr><td><li/> %s:</td><td> %s</td></tr>",lt->engineTemplate->id,lt->engineTemplate->description);
			}else{
				ngx_http_openidc_rprintf(r,"<tr><td colspan='3'><li/> NULL Template</td></tr>");
			}
		}
		ngx_http_openidc_rputs("<TABLE></td></tr>",r);
		
	}
	ngx_http_openidc_rputs("<TABLE>",r);
}

static void authzoidc_displayOidcProviders(ngx_http_openidc_request_t *r, shapr_hash_t* oidcProviderHash){
	match_list* list=NULL;
	shapr_hash_index_t * hi=NULL;
	oidc_provider* oidcProvider=NULL;
	int i=0;
	void* val=NULL;
	unsigned int cnt=0;

	if(oidcProviderHash==NULL) return;

	ngx_http_openidc_rputs("<TABLE>",r);
	cnt=shapr_hash_count(oidcProviderHash);
	ngx_http_openidc_rprintf1(r,"<tr><td colspan='4'><font color='maroon'><strong>OIDCProviders [%d]:</strong></font></td></tr>",cnt);
	if(cnt>0){
		for (hi = shapr_hash_first(r->pool,oidcProviderHash); hi; hi = shapr_hash_next(hi)) {
		   shapr_hash_this(hi, NULL, NULL, &val);
		   if(val!=NULL){
			  oidcProvider=(oidc_provider*)val;
				if(oidcProvider!=NULL) {
					ngx_http_openidc_rprintf1(r,"<tr><td><font color='black'><strong>ID</strong></font><td>%s</td></td></tr>", oidcProvider->id);
					ngx_http_openidc_rprintf1(r,"<tr><td>Issuer</td><td>%s</td></tr>",oidcProvider->issuer);
					ngx_http_openidc_rprintf1(r,"<tr><td>MetadataUrl</td><td>%s</td></tr>",oidcProvider->metadataUrl);
					ngx_http_openidc_rprintf1(r,"<tr><td>AuthorizationEndpoint</td><td>%s</td></tr>",oidcProvider->authorizationEndpoint);
					ngx_http_openidc_rprintf1(r,"<tr><td>JwksUri</td><td>%s</td></tr>",oidcProvider->jwksUri);
					ngx_http_openidc_rprintf1(r,"<tr><td>Default</td><td>%s</td></tr>",BOOLTOSTR(oidcProvider->isDefault));
				}
			  ngx_http_openidc_rputs("</td></tr>",r);
		   }
		}
	}
	ngx_http_openidc_rputs("</TABLE>",r);
}

static void authzoidc_displayRelyingParties(ngx_http_openidc_request_t *r, shapr_hash_t* relyingPartyHash){
	match_list* list=NULL;
	shapr_hash_index_t * hi=NULL;
	relying_party* relyingParty=NULL;
	int i=0;
	void* val=NULL;
	unsigned int cnt=0;

	if(relyingPartyHash==NULL) return;

	ngx_http_openidc_rputs("<TABLE>",r);
	cnt=shapr_hash_count(relyingPartyHash);
	ngx_http_openidc_rprintf1(r,"<tr><td colspan='4'><font color='maroon'><strong>RelyingParties [%d]:</strong></font></td></tr>",cnt);
	if(cnt>0){
		for (hi = shapr_hash_first(r->pool,relyingPartyHash); hi; hi = shapr_hash_next(hi)) {
		   shapr_hash_this(hi, NULL, NULL, &val);
		   if(val!=NULL){
			   relyingParty=(relying_party*)val;
				if(relyingParty!=NULL) {
					ngx_http_openidc_rprintf1(r,"<tr><td><font color='black'><strong>id</strong></font><td>%s</td></td></tr>", relyingParty->id);
					ngx_http_openidc_rprintf1(r,"<tr><td>Description</td><td>%s</td></tr>",relyingParty->description);
					ngx_http_openidc_rprintf1(r,"<tr><td>ClientID</td><td>%s</td></tr>",relyingParty->clientID);
					ngx_http_openidc_rprintf1(r,"<tr><td>ClientSecret</td><td>********</td></tr>",relyingParty->clientSecret);
					ngx_http_openidc_rprintf1(r,"<tr><td>RedirectUri</td><td>%s</td></tr>",relyingParty->redirectUri);
					ngx_http_openidc_rprintf1(r,"<tr><td>Issuer</td><td>%s</td></tr>",relyingParty->issuer);
					ngx_http_openidc_rprintf1(r,"<tr><td>ValidateNonce</td><td>%s</td></tr>",BOOLTOSTR(relyingParty->validateNonce));
					ngx_http_openidc_rprintf1(r,"<tr><td>PostLoginDefaultLandingPage</td><td>%s</td></tr>",relyingParty->postLoginDefaultLandingPage);
				}
			  ngx_http_openidc_rputs("</td></tr>",r);
		   }
		}
	}
	ngx_http_openidc_rputs("</TABLE>",r);
}

  int oidc_rewrite_actionmappings(ngx_http_openidc_request_t *r, Config *config) {

	  if (strcmp(r->handler, "oidc_rewrite_actionmappings")) {
                return NGX_DECLINED;
        }

	oidc_config* actm=config->oidcConfig;
	int i=0;
	pathmapping_action* pmaction=NULL;
	array_header* arr;
	
	if(actm==NULL){
		authzoidc_errorMessage(r);
		return NGX_OK;
	}
	
	
	//begin logic
	
	ngx_http_openidc_rputs("<HTML>\n",r);
	ngx_http_openidc_rprintf(r,"<HEAD><TITLE>OIDC Config</TITLE></HEAD>\n");
	ngx_http_openidc_rputs("<BODY>\n",r);

	authzoidc_displayOidcProviders(r, actm->oidcProviderHash);
	authzoidc_displayRelyingParties(r, actm->relyingPartyHash);

	ngx_http_openidc_rprintf(r,"<TABLE><tr><td><font color='black'><strong>Session</strong></font></td></tr>");
	ngx_http_openidc_rprintf2(r,"<tr><td>RelyingParty</td><td>name=%s</td><td>expiry(days)=%d</td></tr>",actm->rpSession->name, actm->rpSession->age);
	ngx_http_openidc_rprintf2(r,"<tr><td>OIDCProvider</td><td>name=%s</td><td>expiry(days)=%d</td></tr></TABLE>",actm->oidcSession->name, actm->oidcSession->age);
	if(actm->accessToken) {
		ngx_http_openidc_rprintf2(r,"<tr><td>AccessTokenCookie</td><td>name=%s</td><td>expiry(days)=%d</td></tr>",actm->accessToken->name, actm->accessToken->age);
	}

	authzoidc_displayTemplateEngine(r,actm->templateEngine);
	
	//do path matching
	authzoidc_pathMatchSection(r,config);
	
	authzoidc_pathmappings_display(r,actm->path_mappings->postauth,"PostAuth");
	
	//display matchlists
	authzoidc_matchLists(r,actm);

//	authzoidc_printTable(r,r->headers_in);

	ngx_http_openidc_rputs("</BODY>",r);
	ngx_http_openidc_rputs("</HTML>\n",r);

	return NGX_OK;
}
 
  int oidc_rewrite_pageactions(ngx_http_openidc_request_t *r, Config *config) {
	if (strcmp(r->handler, "oidc_rewrite_pageactions")) {
                return NGX_DECLINED;
        }

	shapr_hash_index_t * hi=NULL;
	void* val=NULL;
	const void *key=NULL;
	page_action* paction=NULL;
	oidc_config* actm=config->oidcConfig;
	uri_components *url = &r->parsed_uri;
	
	
	if(actm==NULL){
		authzoidc_errorMessage(r);
		return NGX_OK;
	}
	
	//begin logic
	
	ngx_http_openidc_rputs("<HTML>\n",r);
	ngx_http_openidc_rputs("<HEAD><TITLE>Rewrite Page Actions</TITLE></HEAD>\n",r);
	ngx_http_openidc_rputs("<BODY>\n",r);
	
	ngx_http_openidc_rputs("<TABLE border='0'>",r);
	ngx_http_openidc_rputs("<tr><td>&nbsp</td><td>",r);
	for (hi = shapr_hash_first(r->pool,actm->page_actions); hi; hi = shapr_hash_next(hi)) {
           shapr_hash_this(hi, &key, NULL, &val);
     	   if(key!=NULL&&val!=NULL){
     	   		paction=(page_action*)val;
     	   		rewrite_pageaction_displayAll(r,paction);
     	   		ngx_http_openidc_rputs("<br>",r);
//	        		ngx_http_openidc_rprintf1(r,"<td>%s</td>",key);
        	}
	}
	ngx_http_openidc_rputs("</td></tr></TABLE>",r);
	
	ngx_http_openidc_rputs("</BODY>",r);
	ngx_http_openidc_rputs("</HTML>\n",r);
	return NGX_OK;

}
 
 int oidc_rewrite_match(ngx_http_openidc_request_t *r, Config *config) {
	if (strcmp(r->handler, "oidc_rewrite_match")) {
                return NGX_DECLINED;
        }

	char* regexParam=NULL, *valueParam=NULL, *templateParam=NULL;
	uri_components *url = &r->parsed_uri;
	char* rcoreRet=NULL;
	
	apr_time_t startTime;
	
	//rewrite vars to support templating
	array_header* pmatches=NULL;
	char* elt=NULL;
	int i=0;
	
	//begin logic
	
	regexParam=url_getParam(r->pool,url->query,"regexParam");
	valueParam=url_getParam(r->pool,url->query,"valueParam");
	templateParam=url_getParam(r->pool,url->query,"templateParam");
	//display
	ngx_http_openidc_rputs("<HTML>\n",r);
	ngx_http_openidc_rputs("<HEAD><TITLE>Rewrite Match Testing</TITLE></HEAD>\n",r);
	ngx_http_openidc_rputs("<BODY>\n",r);
	ngx_http_openidc_rputs("<TABLE>",r);
	ngx_http_openidc_rprintf1(r,"<tr><td>RewriteCore: </td><td>%s</td></tr>",rc_getInfo(r->pool));
	ngx_http_openidc_rputs("<form>",r);
	ngx_http_openidc_rputs("<tr><td>Value(Url): </td><td>",r);
	ngx_http_openidc_rprintf1(r,"<input type='text' value='%s' name='valueParam' size='180'/>\r\n",
			(valueParam!=NULL) ? cu_nonHtmlToHtmlChar(r->pool, valueParam) : SAFESTRBLANK(valueParam));
	ngx_http_openidc_rputs("</td></tr>\r\n",r);
	ngx_http_openidc_rputs("<tr><td>Regex: </td><td>",r);
	ngx_http_openidc_rprintf1(r,"<input type='text' value='%s' name='regexParam' size='180'/>\r\n",
			(regexParam!=NULL) ? cu_nonHtmlToHtmlChar(r->pool, regexParam) : SAFESTRBLANK(regexParam));
	ngx_http_openidc_rputs("</td></tr>\r\n",r);
	ngx_http_openidc_rputs("<tr><td>Template: </td><td>",r);
	ngx_http_openidc_rprintf1(r,"<input type='text' value='%s' name='templateParam' size='180'/>\r\n",SAFESTRBLANK(templateParam));
	ngx_http_openidc_rputs("</td></tr>\r\n",r);
	ngx_http_openidc_rputs("<tr><td></td><td><INPUT type='submit' value='go!' /></td></tr>\r\n</form>",r);
	
	if(regexParam!=NULL&&valueParam!=NULL){
		startTime=apr_time_now();
		
		rcoreRet=rc_matchByStringsPatternReturnDetails(r->pool,regexParam,valueParam,&pmatches);
		startTime=apr_time_now()-startTime;
		ngx_http_openidc_rprintf1(r,"<tr><td>Result: (%ld usecs)</td><td>",startTime);
		if(rcoreRet!=NULL){
			ngx_http_openidc_rprintf1(r,"FAILURE: %s</td></tr>",rcoreRet);
		}else{
			ngx_http_openidc_rputs("SUCCESS</td></tr>",r);
		}
		if(templateParam!=NULL){
			ngx_http_openidc_rprintf1(r,"<tr><td></strong>Template Engine String</strong>:</td><td>%s</td></tr>",SAFESTR(te_templateString(r->pool,config->oidcConfig->templateEngine,templateParam,pmatches)));
		}
		
		if(pmatches!=NULL){
			
			ngx_http_openidc_rprintf1(r,"<tr><td colspan='2'></strong>Found Matches (%d)</strong></td></tr>",pmatches->nelts);
			
			if(pmatches->nelts>0){
				ngx_http_openidc_rprintf(r,"<tr><td>&nbsp</td><td><table>");
				for(i=0;i<pmatches->nelts;i++){
					elt=cu_getElement(pmatches,i);
					ngx_http_openidc_rprintf2(r,"<tr><td><strong>$%d: </strong></td><td>%s</td></tr>",i,
							cu_nonHtmlToHtmlChar(r->pool, elt));
				}
				ngx_http_openidc_rprintf(r,"</table></td></tr>");
			}
		}
	}
	
	ngx_http_openidc_rputs("</TABLE>",r);
	ngx_http_openidc_rputs("</BODY>",r);
	ngx_http_openidc_rputs("</HTML>\n",r);
	return NGX_OK;
}

 static int oidc_section_SharedHeap(const char* title, ngx_http_openidc_request_t *r,shared_heap* sheap){
 	shared_page* pg;
 	segment_header* seg;
 	int x;
 	if(sheap!=NULL){
 		ngx_http_openidc_rprintf1(r,"\n<TR><TD colspan='2'><b>Shared Heap Page - %s </b></TD></TR>",title);
 		ngx_http_openidc_rprintf1(r,"<TR><TD>TimeStamp: </TD><TD>%s</TD></TR>",ctime(&(sheap->timestamp)));
 		ngx_http_openidc_rprintf1(r,"<TR><TD>FlipCount: </TD><TD>%d</TD></TR>",sheap->flipcount);
 		ngx_http_openidc_rprintf1(r,"<TR><TD>Cursor byte: </TD><TD>%d</TD></TR>",shdata_cursor(sheap));
 		
 		ngx_http_openidc_rprintf1(r,"<TR><TD>Local Seg: </TD><TD>%d</TD></TR>",sheap->local_segment);
 		ngx_http_openidc_rprintf1(r,"<TR><TD>apr_shm_t* valid: </TD><TD>%s</TD></TR>",sheap->shm_main==NULL?"FALSE":"TRUE");
 		ngx_http_openidc_rprintf(r,"<TR><TD colspan='2'>&nbsp;<TD></TR>");
 		if(sheap->page!=NULL){
 			pg=sheap->page;
 			ngx_http_openidc_rprintf(r,"\n<TR><TD colspan='2'><b>------Shared Portion--|</b></TD></TR>");
 			ngx_http_openidc_rprintf(r,"\n<TR><TD colspan='2'>");
 			
 			ngx_http_openidc_rprintf(r,"<TABLE>");
 			ngx_http_openidc_rprintf1(r,"\t<TR><TD width='5'>&nbsp;</TD><TD>TimeStamp: </TD><TD>%s</TD></TR>",ctime(&(pg->timestamp)));
 			ngx_http_openidc_rprintf1(r,"\t<TR><TD width='5'>&nbsp;</TD><TD>SegmentSize: </TD><TD>%d</TD></TR>",pg->segmentsize);
 			ngx_http_openidc_rprintf1(r,"\t<TR><TD width='5'>&nbsp;</TD><TD>FlipCount: </TD><TD>%d</TD></TR>",pg->flipcount);
 			ngx_http_openidc_rprintf1(r,"\t<TR><TD width='5'>&nbsp;</TD><TD>ItemsMax: </TD><TD>%d</TD></TR>",pg->itemmax);
 			ngx_http_openidc_rprintf2(r,"\t<TR><TD width='5'>&nbsp;</TD><TD>Front/Back Segment: <TD>%d/%d</TD></TR>",pg->frontsegment,pg->backsegment);
 			seg=&(sheap->page->segments[sheap->page->frontsegment]);
 			
 			ngx_http_openidc_rprintf1(r,"\t<TR><TD width='5'>&nbsp;</TD><TD colspan='2'>* Items(%d)---</TD></TR>",seg->itemcount);
 			ngx_http_openidc_rprintf(r,"\t<TR><TD width='5'>&nbsp;</TD><TD colspan='2'>");
 				if(seg->itemcount>0){
 				ngx_http_openidc_rprintf(r,"\t\t<TABLE>");
 				for(x=0;x<seg->itemcount;x++){	
 				ngx_http_openidc_rprintf1(r,"<TR><TD>ID: </TD><TD>%s</TD></TR>",seg->items[x].ITEMID);
 				ngx_http_openidc_rprintf1(r,"<TR><TD>INFO: </TD><TD>%s</TD></TR>",seg->items[x].INFO);
 				ngx_http_openidc_rprintf1(r,"<TR><TD>Offset: </TD><TD>%d</TD>",seg->items[x].offset);
 				ngx_http_openidc_rprintf1(r,"<TR><TD>Size: </TD><TD>%d</TD>",seg->items[x].size);
 				}
 				ngx_http_openidc_rprintf(r,"\t\t</TABLE>");
 				}
 			ngx_http_openidc_rprintf(r,"\t</TD></TR>");
 			ngx_http_openidc_rprintf(r,"\t</TABLE>");
 			ngx_http_openidc_rprintf(r,"\n</TD></TR>");
 			
 		}
 	}else{
 		ngx_http_openidc_rprintf1(r,"\n<TR><TD colspan='2'>Shared Heap - %s - NULL</TD></TR>",title);
 	}
 	return 1;
 }

 int oidc_showHeaders(ngx_http_openidc_request_t *r, Config* config){

	oidc_config* actm=config->oidcConfig;

	if(actm==NULL){
		authzoidc_errorMessage(r);
		return NGX_OK;
	}


	//begin logic

	ngx_http_openidc_rputs("<HTML>\n",r);
	ngx_http_openidc_rprintf(r,"<HEAD><TITLE>Headers</TITLE></HEAD>\n");
	ngx_http_openidc_rputs("<BODY>\n",r);

	authzoidc_printTable(r,r->headers_in);

	ngx_http_openidc_rputs("</BODY>",r);
	ngx_http_openidc_rputs("</HTML>\n",r);

	return NGX_OK;
}

 int oidc_headers(ngx_http_openidc_request_t *r, Config *config) {
 	if (strcmp(r->handler, "oidc_headers")) {
                 return NGX_DECLINED;
         }
 	return oidc_showHeaders(r,config);
 }

int oidc_config_core_status(ngx_http_openidc_request_t *r, Config *config) {

 	if (strcmp(r->handler, "oidc_config_core_status")) {
 		return NGX_DECLINED;
 	}

 	ngx_http_openidc_rputs("<HTML>\n",r);
 	ngx_http_openidc_rprintf(r,"<HEAD><TITLE>Config Core Status</TITLE></HEAD>\n");
 	ngx_http_openidc_rputs("<BODY>\n",r);
 	ngx_http_openidc_rputs("<TABLE width='100%'>",r);
 	ngx_http_openidc_rprintf1(r,"<tr><td>HomeDir: </td><td>%s</td></tr>",SAFESTR(config->homeDir));
 	ngx_http_openidc_rprintf1(r,"<tr><td>ConfigFile: </td><td>%s</td></tr>",SAFESTR(config->oidcConfigFile));
 	ngx_http_openidc_rprintf1(r,"<tr><td>LogFile: </td><td>%s</td></tr>",SAFESTR(config->logFile));
 	if(config->configCore!=NULL){
 		int i=0;
 		config_core* core=config->configCore;

 		ngx_http_openidc_rprintf(r,"<tr><td colspan='2' align='left'><strong>Globals</strong></td></tr>");
 		ngx_http_openidc_rprintf1(r,"<tr><td>HomeDirectory: </td><td>%s</td></tr>",SAFESTR(core->globals->homeDir));
 		ngx_http_openidc_rprintf1(r,"<tr><td>PassPhrase: </td><td>%s</td></tr>", core->passPhrase ? "non null" : "NULL");

 		ngx_http_openidc_rprintf1(r,"<tr><td>DisableProcessRecovery: <td>%s</td></tr>",BOOLTOSTR(core->disableProcessRecovery));
 		ngx_http_openidc_rprintf1(r,"<tr><td>OIDCHeaderPrefix: <td>%s</td></tr>",SAFESTR(core->oidcHeaderPrefix));

 		ngx_http_openidc_rprintf(r,"<tr><td colspan='2' align='left'><strong>AutoRefresh settings</strong></td></tr>");
 		ngx_http_openidc_rprintf1(r,"<tr><td>RefreshWaitSeconds: <td>%d</td></tr>",core->refreshWaitSeconds);
 		
 		if(core->globals->resourceService!=NULL){
 	 		ngx_http_openidc_rprintf(r,"<tr><td colspan='2' align='left'><strong>Resource Service</strong></td></tr>");
 			ngx_http_openidc_rprintf1(r,"<tr><td>Url: </td><td>%s</td></tr>",SAFESTR(core->globals->resourceService->uri));
 			ngx_http_openidc_rprintf1(r,"<tr><td>Timeout: </td><td>%d</td></tr>",core->globals->resourceService->timeoutSeconds);
 		}

 		oidc_section_SharedHeap("Config Core",r,config->configCore->sheap);
 	}else{
 		ngx_http_openidc_rprintf(r,"<tr><td>ConfigCore: </td><td>NULL</td></tr>");
 	}
 	ngx_http_openidc_rputs("</TABLE>",r);
 	ngx_http_openidc_rputs("</BODY></HTML>",r);
 	return NGX_OK;
 }
 
static ngx_int_t ngx_http_openidc_subrequest_post_handler(ngx_http_request_t *r, void *data, ngx_int_t rc) {
    ngx_http_request_t          *pr;
    ngx_http_openidc_subrequest_ctx_t* ctx;

    pr = r->parent;

    ctx = ngx_http_get_module_ctx(pr, ngx_http_openidc_module);
    ctx->done = 1;
    ctx->status = r->headers_out.status;
    ctx->responseType = r->headers_out.content_type;
    ctx->subrequest = r;

    char tmp[8192]={0};
    memcpy(tmp, r->upstream->buffer.pos, r->upstream->buffer.last - r->upstream->buffer.pos);
//    printf("%s:%d body=[%s]\n", __FILE__, __LINE__, tmp);

    size_t bodylen = r->upstream->buffer.last - r->upstream->buffer.pos;
    ctx->responseBody.data = ngx_palloc(r->pool, bodylen);
    ctx->responseBody.len  = bodylen;
    memcpy(ctx->responseBody.data, r->upstream->buffer.pos, bodylen);

    return NGX_OK;
}

static ngx_int_t
ngx_http_openidc_set_subrequest_post_body(ngx_http_request_t * r, ngx_http_request_t * sr, const char* requestBody, ngx_str_t  contentType) {
	if(requestBody==NULL) return NGX_ERROR;

	ngx_http_request_body_t     *rb = NULL;
	ngx_buf_t                   *b;

	// set method
	sr->method = NGX_HTTP_POST;
	sr->method_name.data = (u_char *)"POST ";
	sr->method_name.len = 4;

	// create request body
	rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t));
	if (rb == NULL) {
		return NGX_ERROR;
	}

	b = ngx_calloc_buf(r->pool);
	if (b == NULL) {
		return NGX_ERROR;
	}

	b->temporary = 1;
	/* b->memory = 1; */
	b->start = b->pos = requestBody;
	b->end = b->last = requestBody + strlen(requestBody);

	rb->bufs = ngx_alloc_chain_link(r->pool);
	if (rb->bufs == NULL) {
		return NGX_ERROR;
	}

	rb->bufs->buf = b;
	rb->bufs->next = NULL;

	rb->buf = b;

	/* set the 'Content-type' header */
	ngx_int_t rc = ngx_http_openidc_set_content_headers(sr, rb->buf ? ngx_buf_size(rb->buf) : 0, contentType);
	if (rc != NGX_OK) {
		return NGX_ERROR;
	}

	sr->request_body = rb;

	return NGX_OK;
}

static ngx_int_t ngx_http_openidc_preAuthorize(ngx_http_openidc_request_t* r, Config* config) {
    ngx_http_post_subrequest_t *psr;
    ngx_http_request_t *sr;
    ngx_int_t rc;
	uri_components *url = &r->parsed_uri;
	char tmp[OAUTH_IDTOKEN_MAX_SIZE];
	oidc_config* 	oidcConfig = config->oidcConfig;

    ngx_http_openidc_subrequest_ctx_t* ctx = ngx_http_get_module_ctx(r->httpRequest, ngx_http_openidc_module);
    if (ctx != NULL) {

        ngx_chain_t out;
        int bodylen;
        ngx_buf_t* b;
        ngx_int_t ret;

        if (!ctx->done) {
            return NGX_AGAIN;
        }

        if (ctx->status == NGX_HTTP_FORBIDDEN||ctx->status == NGX_HTTP_BAD_REQUEST) {
            return ctx->status;
        }

        if (ctx->status == NGX_HTTP_UNAUTHORIZED) {
        		ngx_http_request_t* sr = ctx->subrequest;

        		ngx_table_elt_t* h = sr->headers_out.www_authenticate;

            if (!h && sr->upstream) {
                h = sr->upstream->headers_in.www_authenticate;
            }

            if (h) {
            		ngx_table_elt_t   *ho = ngx_list_push(&r->httpRequest->headers_out.headers);
                if (ho == NULL) {
                    return NGX_ERROR;
                }

                *ho = *h;

                r->httpRequest->headers_out.www_authenticate = ho;
            }

            return ctx->status;
        }

        if (ctx->status == NGX_HTTP_OK){
            // print
            char tmp[8192]={0};
            memcpy(tmp, ctx->responseBody.data, ctx->responseBody.len);
//            printf("%s:%d body=[%s]\n", __FILE__, __LINE__, tmp);

            char* responseBody = apr_pstrndup(r->pool, ctx->responseBody.data, ctx->responseBody.len);
            if(responseBody!=NULL) {
				Value* json = JSON_Parse(r->pool, responseBody);
				if(json!=NULL) {
					Value* idTokenObj = JSON_GetObjectItem(json, "id_token");
					if(idTokenObj!=NULL) {
						char* id_token = JSON_GetStringFromStringItem(idTokenObj);
						if(id_token!=NULL) {
							apr_table_set(r->headers_in, "Authorization", apr_pstrcat(r->pool, "Bearer ", id_token, NULL));
						}
					}
					// set access_token as cookie
					if(oidcConfig!=NULL&&oidcConfig->accessToken!=NULL) {
						Value* accessTokenObj = JSON_GetObjectItem(json, "access_token");
						if(accessTokenObj!=NULL) {
							char* access_token = JSON_GetStringFromStringItem(accessTokenObj);
							if(access_token!=NULL) {
								char* cookieDrop=cookie_cookieTemplate(r->pool, oidcConfig->accessToken, access_token, NULL);
								if(cookieDrop!=NULL){
									apr_table_add(r->headers_out, "Set-Cookie", cookieDrop);
								}
							}
						}
					}
				}
            }
            return NGX_DECLINED;
        }

        // default
        ngx_http_finalize_request(r->httpRequest, ctx->status);
        return ctx->status;

    }else if(url_get_param(url->query, (char*)"code", tmp, OAUTH_IDTOKEN_MAX_SIZE)>0){
		char* authorizationCode = apr_pstrdup(r->pool, tmp);
		char* currentRedirectUri = ngx_http_openidc_getFullRequestUrl(r);
		page_action* action = NULL;

		// get callback action
		path_mapping* pathmapping=am_getPathMapping_PostAuth(r->pool, oidcConfig, r->unparsed_uri,r->connection_remote_ip,r->headers_in,NULL);
		if(pathmapping!=NULL){
			action=am_getMatchingPageAction(r->pool,pathmapping->pmactions,r->unparsed_uri,r->connection_remote_ip,r->headers_in,NULL);
		}
		if(action==NULL||action->type!=action_callback||action->relyingParty==NULL||action->oidcProvider==NULL) {
			return NGX_DECLINED;
		}
		//printf("%s:%d CurrentRedirectUri=[%s]\n", __FILE__, __LINE__, currentRedirectUri);
		relying_party* relyingParty = am_getRelyingPartyById(oidcConfig->relyingPartyIdsHash, action->relyingParty);
		if(relyingParty!=NULL) {
			char* requestBody = apr_pstrcat(r->pool,
					"grant_type=authorization_code",
					"&code=", authorizationCode,
					"&client_id=", relyingParty->clientID,
					"&client_secret=", relyingParty->clientSecret,
					NULL);
			if(relyingParty->redirectUri!=NULL) {
					requestBody = apr_pstrcat(r->pool, requestBody,
					"&redirect_uri=", relyingParty->redirectUri,
					NULL);
			}
			ngx_int_t rc = ngx_http_openidc_create_post_subrequest(r->httpRequest, oidc_authz_subrequest_type_oauth_token, requestBody);
			if (rc != NGX_OK) {
				return rc;
			}
			return NGX_AGAIN;
		}
    }

    	 return NGX_DECLINED;
}

static ngx_int_t
ngx_http_openidc_create_post_subrequest(ngx_http_request_t * r, oidc_authz_sub_request_type sub_request_type, const char* requestBody) {
    ngx_http_post_subrequest_t *psr;
    ngx_http_request_t *sr;
    ngx_int_t rc;

    // create new context
    ngx_http_openidc_subrequest_ctx_t* ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_openidc_subrequest_ctx_t));
	if (ctx == NULL) {
		return NGX_ERROR;
	}

	ngx_http_set_ctx(r, ctx, ngx_http_openidc_module);

    psr = ngx_palloc(r->pool, sizeof(ngx_http_post_subrequest_t));
    if (psr == NULL) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    psr->handler = ngx_http_openidc_subrequest_post_handler;
    psr->data = ctx;

    ngx_str_t subrequest_uri = sub_request_type.uri;
//    printf("subrequest_uri=%s\n", (const char*)subrequest_uri.data);
//    printf("requestBody=%s\n", requestBody);

    rc = ngx_http_subrequest(r, &subrequest_uri, NULL, &sr, psr, NGX_HTTP_SUBREQUEST_IN_MEMORY);
    if (rc != NGX_OK) {
        return NGX_ERROR;
    }

    /* allocate a buffer for your response body */
    rc = ngx_http_openidc_set_subrequest_post_body(r, sr, requestBody, sub_request_type.content_type);
    if (rc != NGX_OK) {
        return rc;
    }

    return NGX_OK;
}



<|start_filename|>src/oidc-globals/oidc_globals.c<|end_filename|>
/*
 *  Created by <NAME> on 04/27/15.
 *
 */
#include <oidc_globals.h>
#include <common_utils.h>

static int DJRE_EnableUnnamedSHM = FALSE;
static int DJRE_ConfigCheckPhaseDelaySec = 0;

void djrglobals_setEnableUnnamedSHM(const char * arg) {
	DJRE_EnableUnnamedSHM = STRTOBOOL(arg);
}

int djrglobals_isUnnamedSHMEnabled() {
	return DJRE_EnableUnnamedSHM;
}

void djrglobals_setConfigCheckPhaseDelaySec(const char * arg) {
	if(arg != NULL) {
		DJRE_ConfigCheckPhaseDelaySec = atoi(arg);
	}
}
int djrglobals_getConfigCheckPhaseDelaySec() {
	return DJRE_ConfigCheckPhaseDelaySec;
}


<|start_filename|>src/shm_core/shm_dup.h<|end_filename|>
#ifndef __TCREWRITE_SHM_DUP__H_
#define __TCREWRITE_SHM_DUP__H_

#include <sys/types.h>
#include "apache_typedefs.h"

#ifdef __cplusplus
extern "C" {
#endif
	
int shdup_32BitString_size(char* str);
char* shdup_32BitString_copy(char** icharbuf, char* str);

int shdup_arrayheader_size(array_header* arr);

#ifdef __cplusplus
}
#endif
	
#endif


<|start_filename|>src/config-core/config_messaging.h<|end_filename|>
#ifndef __TCREWRITE_CONFIG_MESSAGING__H_
#define __TCREWRITE_CONFIG_MESSAGING__H_

#include <sys/types.h>
#include "apache_typedefs.h"
#include <config-core/config_messaging_parsing.h>
#include "apr_thread_proc.h"
	
	typedef struct cfgm_connection{
		cfgm_wire_header* wireHeader;
	}cfgm_connection;
		
	typedef char* (*cfgm_message_recieved_func) (pool*,cfgm_connection*,cfgm_wire_message*,void*, void*);
	typedef void* (*cfgm_init_messaging_func)(pool*,void*);

	apr_proc_t* cfgm_initializeMessagingLoop(pool* p, char* homeDir, void* messageBroker, void* userdata,
			cfgm_init_messaging_func initFunc, cfgm_message_recieved_func msgRecFunc,
			int disableProcessRecovery);
	cfgm_connection* cfgm_newConnectionObj(pool* p);
	int cfgm_isRefreshMessage(cfgm_wire_message* msg);
		
#endif



<|start_filename|>src/common-utils/common_utils.c<|end_filename|>
/*
 *  Created by <NAME> on 01/04/14.
 *
 */
#include <common_utils.h>
#include <sys/stat.h>
#include <stdio.h>
#include <string.h>

#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <ifaddrs.h>
#include <stdlib.h>
#include <sys/time.h>
#include <time.h>
#include <unistd.h>
#include <apr_time.h>
#include <errno.h>
#include <openssl/err.h>
#include <openssl/hmac.h>
#include <openssl/evp.h>
#include <openssl/pem.h>
#include <openssl/ssl.h>
#include <openssl/rsa.h>
#include <openssl/bio.h>
#include <openssl/crypto.h>
#include <openssl/aes.h>
#include <apr_file_io.h>
#include <apr_uuid.h>

char* cu_getElement(apr_array_header_t* data, int element){
	 if(data!=NULL&&data->nelts>element&&element>=0){
     	return ((char**)data->elts)[element];
	 }
	 return NULL;
}

void** cu_getElementRef(apr_array_header_t* data, int element){
	if(data!=NULL&&data->nelts>element&&element>=0){
     	return ((void**)data->elts)+element;
	}
	return NULL;
}

char* cu_getNodeDetails(apr_pool_t* p,unsigned int defaultHttpPort){
	int i;
	//for second ip get test
	struct ifaddrs *ifa = NULL, *ifp = NULL;
	socklen_t salen;
	char ip[512];
	char* ret=NULL;

	if (getifaddrs (&ifp) >= 0){
		i=0;
		for (ifa = ifp; ifa&&ifa->ifa_addr; ifa = ifa->ifa_next){
			if (ifa->ifa_addr->sa_family == AF_INET)
				salen = sizeof (struct sockaddr_in);
			else if (ifa->ifa_addr->sa_family == AF_INET6)
				salen = sizeof (struct sockaddr_in6);
			else
				continue;

			if (getnameinfo (ifa->ifa_addr, salen,ip, sizeof (ip), NULL, 0, NI_NUMERICHOST) < 0){
				continue;
				}

			if(strcmp(ip,"127.0.0.1")!=0&&strcmp(ip,"::1")!=0){ //don't need to know localhost ip4 or ip6
				if(ifa->ifa_addr->sa_family == AF_INET){
					if(i==0)
						ret=apr_psprintf(p,"%s:%u",ip,defaultHttpPort);
					else
						ret=apr_psprintf(p,"%s,%s:%u",ret,ip,defaultHttpPort);
					}
				else{
					if(i==0)
						ret=apr_pstrdup(p,ip);
					else
						ret=apr_pstrcat(p,ret,",",ip,NULL);
					}
				i++;
				}
			}
		 freeifaddrs (ifp);
		}
	return ret;
}

#define CTEM_PRE	"{"
#define CTEP_POST	"}"
	char* cu_templateString(apr_pool_t* p, char* src, apr_hash_t* vals){
		char* cpy=NULL;
		char* ret=NULL,*begin=NULL, *end=NULL, *token=NULL, *tval=NULL;
		if(src==NULL){ return NULL; }

		cpy=apr_pstrdup(p,src);

		begin=strstr(cpy,"{");
		while(begin!=NULL){

			//find end
			end=strstr(begin,"}");

			//do append
			if(end!=NULL){
				*begin='\0';
				*end='\0';
				token=begin+1;
				tval=vals!=NULL?SAFESTRBLANK(apr_hash_get(vals,token,APR_HASH_KEY_STRING)):"";
				if(ret==NULL){
					ret=apr_pstrcat(p,cpy,tval,NULL);
				}else{
					ret=apr_pstrcat(p,ret,cpy,tval,NULL);
				}
				begin=cpy=end+1;
			}else{
				begin++;
			}

			//continue
			begin=strstr(begin,"{");
		}
		if(cpy!=NULL&&*cpy!='\0'){
			ret=apr_pstrcat(p,ret,cpy,NULL);
		}
		return ret;
	}

        time_t cu_dateStringToSeconds(const char* dateString){
        		struct tm tm;

        		if(dateString==NULL||strptime(dateString, "%a %b %d %H:%M:%S %Y", &tm)==0) return -1;
        		tm.tm_isdst=-1;//daylight saving
        		return mktime(&tm);
        	}

	// format is same asa apr_strftime
	/*
	%a	Abbreviated weekday name *	Thu
	%A	Full weekday name * 	Thursday
	%b	Abbreviated month name *	Aug
	%B	Full month name *	August
	%c	Date and time representation *	Thu Aug 23 14:55:02 2001
	%d	Day of the month (01-31)	23
	%H	Hour in 24h format (00-23)	14
	%I	Hour in 12h format (01-12)	02
	%j	Day of the year (001-366)	235
	%m	Month as a decimal number (01-12)	08
	%M	Minute (00-59)	55
	%p	AM or PM designation	PM
	%S	Second (00-61)	02
	%U	Week number with the first Sunday as the first day of week one (00-53)	33
	%w	Weekday as a decimal number with Sunday as 0 (0-6)	4
	%W	Week number with the first Monday as the first day of week one (00-53)	34
	%x	Date representation *	08/23/01
	%X	Time representation *	14:55:02
	%y	Year, last two digits (00-99)	01
	%Y	Year	2001
	%Z	Timezone name or abbreviation	CDT
	%%	A % sign	%
	*/
	char* cu_getCurrentDateByFormat2(apr_pool_t* p, const char* format){
		#define STR_SIZE	80
		apr_status_t status;
		apr_time_exp_t t;
		apr_size_t sz;
		char buf[STR_SIZE];

		if ( format==NULL ) return NULL;

		memset(buf, '\0', STR_SIZE);

		apr_time_exp_lt(&t, apr_time_now());
		status = apr_strftime(buf, &sz, STR_SIZE, format, &t);
		//assert (status == APR_SUCCESS );

		return apr_pstrdup(p, buf);
	}

	int cu_getElementCount(apr_array_header_t* data){
		return (data!=NULL) ? data->nelts : 0;
	}

	typedef struct html_char{
		const char c;
		const char* str;
	}html_char;

	static const html_char html_table[] = {
			{'<',"&lt;"},
			{'>',"&gt;"},
			{'\'',"&#39;"}
	};

	static const char* cu_getHtmlString(const char c) {
		int i;
		for(i=0; i < sizeof(html_table)/sizeof(html_char); i++ ){
			if(html_table[i].c==c) return html_table[i].str;
		}
		return NULL;
	}

	char* cu_nonHtmlToHtmlChar(apr_pool_t*p, char*src){
		if(src==NULL) return NULL;
		int size=8*strlen(src);
		char*ret=apr_palloc(p, size+1);
		char*q=ret;
		const char* str = NULL;

		while(*src!='\0'){
			if(str = cu_getHtmlString(*src)){
				strcpy(q, str);
				q += strlen(str);
				src++;
			}else{
				*q++=*src++;
			}
		}
		*q='\0';

		return ret;
	}

	char* cu_getFormattedUrl(apr_pool_t *p, char* cur, char* namespaceid) {
		int x,queryStrState=0;
		int curlen=0;
		if(cur==NULL|namespaceid==NULL) return cur;

		curlen=strlen(cur);
		for(x=curlen-1;x>=0;x--){
			if(cur[x]=='?'){
				if(x==curlen-1){
					queryStrState=2;
				}else{
					queryStrState=1;
				}
			}
		}
		if(queryStrState==0){
			return apr_pstrcat(p,cur,"?ns=",namespaceid,NULL);
		}else if(queryStrState==1){
			return apr_pstrcat(p,cur,"&ns=",namespaceid,NULL);
		}else if(queryStrState==2){
			return apr_pstrcat(p,cur,"ns=",namespaceid,NULL);
		}
	}

	char* cu_getTrimmedStr(apr_pool_t* p, char* str){
		char* start=NULL,*end=NULL;
		int len=0,size=0;

		if(str==NULL){
			return NULL;
		}

		start=str;
		while(*start!='\0'&&(*start==' '||*start=='\t'||*start=='\n'||*start=='\r')){
			start++;
		}
		len=strlen(str);
		end=&(str[len-1]);
		while(*end!='\0'&&(*end==' '||*end=='\t'||*end=='\n'||*end=='\r')){
			end--;
		}

		size=end-start+1;
		if(size<=0){return NULL;}
		return apr_pstrndup(p,start,size);
	}

	apr_array_header_t* cu_parseStringArrayFromCsv(apr_pool_t* p, int arraySz, const char* delim, char* src){
		char *srccpy=NULL, *prodStr=NULL, *p1=NULL;
        char **val=NULL;
        apr_array_header_t* arr=(apr_array_header_t*)apr_array_make(p,arraySz,sizeof(char*));
        if(src==NULL){return arr;}

        srccpy=apr_pstrdup(p,src);

        if(arr==NULL){
                return NULL;
        }
        prodStr=apr_strtok(srccpy,delim,&p1);
        while(prodStr!=NULL){
                val= (char**) apr_array_push(arr);
                *val = (char*) apr_pstrdup(p,prodStr);
                prodStr =strtok_r(NULL,delim,&p1);
        }

		return arr;
	}
	char* cu_serializeCsvFromStringArray(apr_pool_t* p, apr_array_header_t* arr){
		char* ret=NULL;
		int i=0;
		if(arr!=NULL){
			for(i=0;i<arr->nelts;i++){
				if(i==0){
					ret=apr_pstrdup(p,cu_getElement(arr,i));
				}else{
					ret=apr_pstrcat(p,ret,",",cu_getElement(arr,i),NULL);
				}
			}
		}
		return ret;
	}
	apr_table_t* cu_parseNvpTableFromCsv(apr_pool_t* p,const char* itemDelim,const char* nvpDelim, char* src){
		apr_array_header_t* list=NULL;
		apr_table_t* ret=NULL;
		char* item=NULL, *name=NULL,*val=NULL;
		int i=0;

		if(src==NULL){return NULL;}
		list=cu_parseStringArrayFromCsv(p,4,itemDelim,src);
		if(list!=NULL&&list->nelts>0){
			ret=apr_table_make(p,list->nelts);
			for(i=0;i<list->nelts;i++){
				item=cu_getElement(list,i);
				name=item;
				val=strstr(item,nvpDelim);
				if(val!=NULL&&(*(val+1))!='\0'){
					*val='\0';
					val++;
					apr_table_set(ret,name,val);
				}
			}
		}
		if(apr_is_empty_table(ret)){
			return NULL;
		}else{
			return ret;
		}
	}

	// RSA implementation
	int padding = RSA_PKCS1_PADDING;
	#define OAUTH_ERROR_STRING_MAX_LENGTH	256

	static void comu_printHex(const char *title, const unsigned char *s, int len) {
		int     n;
		printf("%s:", title);
		for (n = 0; n < len; ++n) {
			if ((n % 16) == 0) {
				printf("\n%04x", n);
			}
			printf(" %02x", s[n]);
		}
		printf("\n");
	}

	static RSA* comu_createRSA(apr_pool_t* p, unsigned char* key, int public, char** error) {
		BIO* mem = NULL;
		RSA* rsa = NULL;
		char errorBuffer[OAUTH_ERROR_STRING_MAX_LENGTH];

		ERR_load_crypto_strings();

		mem = BIO_new_mem_buf(key, -1);
		if (mem == NULL) {
			ERR_error_string(ERR_get_error(), errorBuffer);
			if(error!=NULL) { *error = apr_pstrdup(p, errorBuffer); }
			 return NULL;
		}

		if(public) {
			rsa = PEM_read_bio_RSA_PUBKEY(mem, NULL, NULL, NULL);
		}else{
			rsa = PEM_read_bio_RSAPrivateKey(mem, NULL, NULL, NULL);
		}
		BIO_free (mem);

		if (rsa == NULL) {
			ERR_error_string(ERR_get_error(), errorBuffer);
			if(error!=NULL) { *error = apr_pstrdup(p, errorBuffer); }
		}

		return rsa;
	}

	static RSA* comu_createRSAFromFile(apr_pool_t* p, unsigned char* keyFile, int public, char** error) {
		RSA* rsa = NULL;
		char errorBuffer[OAUTH_ERROR_STRING_MAX_LENGTH];

		FILE * fp = fopen(keyFile, "rb");
		if (fp == NULL) {
			if(error!=NULL) { *error = apr_pstrdup(p, "unable to open file"); }
			 return NULL;
		}

		ERR_load_crypto_strings();

		rsa= RSA_new() ;
		if(public) {
			rsa = PEM_read_RSA_PUBKEY(fp, &rsa,NULL, NULL);
		}else{
			rsa = PEM_read_RSAPrivateKey(fp, &rsa,NULL, NULL);
		}
		fclose(fp);

		if (rsa == NULL) {
			ERR_error_string(ERR_get_error(), errorBuffer);
			if(error!=NULL) { *error = apr_pstrdup(p, errorBuffer); }
		}

		return rsa;
	}

	char* comu_rsa256Sign(apr_pool_t*p, unsigned char * data,int dataLen, unsigned char * privateKey, char** error) {
		int retEr;
		unsigned char sign[256]={0};
		unsigned int signLen = 0;
		unsigned char encodeSign[1024];

		RSA* rsa = comu_createRSA(p, privateKey, FALSE, error);
	    if(rsa==NULL) return NULL;

		// sha256
		unsigned char hash[SHA256_DIGEST_LENGTH];

		SHA256(data, dataLen, hash);

		//  signing
		retEr = RSA_sign(NID_sha256, hash, SHA256_DIGEST_LENGTH, sign, &signLen, rsa);
		RSA_free(rsa);

		if(retEr != 1) {
			char errorBuffer[OAUTH_ERROR_STRING_MAX_LENGTH];
			ERR_error_string(ERR_get_error(), errorBuffer);
			if(error!=NULL) { *error = apr_pstrdup(p, errorBuffer); }
			return NULL;
		}

		memset(encodeSign,'\0',1024);
	    base64Url_encode(encodeSign, sign, signLen);
	    return apr_pstrdup(p, encodeSign);

	}

	int comu_rsa256Verify(apr_pool_t*p, unsigned char * data,int dataLen, unsigned char * publicKey, char* encodedSign, char** error) {
		int retEr;
		unsigned char sign[1024];

		RSA* rsa = comu_createRSA(p, publicKey, TRUE, error);
	    if(rsa==NULL) return FALSE;

	    // sha256
	    unsigned char hash[SHA256_DIGEST_LENGTH];

	    SHA256(data, dataLen, hash);

	    //  verification
		memset(sign,'\0',1024);
	    int signLen = base64Url_decode(sign, (char*)encodedSign, strlen(encodedSign));

	    retEr = RSA_verify(NID_sha256, hash, SHA256_DIGEST_LENGTH, sign, signLen, rsa);
		RSA_free(rsa);

		if(retEr != 1) {
			char errorBuffer[OAUTH_ERROR_STRING_MAX_LENGTH];
			ERR_error_string(ERR_get_error(), errorBuffer);
			if(error!=NULL) { *error = apr_pstrdup(p, errorBuffer); }
		}

		return (retEr == 1) ?  TRUE : FALSE;
	}

static RSA* comu_createRSAByModulus(apr_pool_t* p, const char* modulus, const char* exponent, char** error) {
	RSA* rsa = NULL;
	char errorBuffer[OAUTH_ERROR_STRING_MAX_LENGTH];
	unsigned char decoded[1024];

	BIGNUM* bn = NULL;
	int len;

	if(modulus==NULL||exponent==NULL) return NULL;

	memset(decoded,'\0',1024);
	len = base64Url_decode(decoded, modulus, strlen(modulus));
	if(len==0) return NULL;

	BIGNUM *n = BN_bin2bn(decoded, len, NULL);
	if (n == NULL) {
		if(error!=NULL) { *error = apr_pstrdup(p, "Invalid encoding for modulus\n"); }
		return NULL;
	}

	memset(decoded,'\0',1024);
	len = base64Url_decode(decoded, exponent, strlen(exponent));
	if(len==0) return NULL;

	BIGNUM *e = BN_bin2bn(decoded, len, NULL);
	if (e == NULL) {
		if(error!=NULL) { *error = apr_pstrdup(p, "Invalid encoding for public exponent\n"); }
		return NULL;
	}

	ERR_load_crypto_strings();
	rsa = RSA_new();
	rsa->e = e;
	rsa->n = n;

	if (rsa == NULL) {
		ERR_error_string(ERR_get_error(), errorBuffer);
		if(error!=NULL) { *error = apr_pstrdup(p, errorBuffer); }
	}

		return rsa;
	}

	int comu_rsaVerifyByModulus(apr_pool_t*p, const char* algorithm, unsigned char * data,int dataLen, const char* modulus, const char* exponent, char* encodedSign, char** error) {
		int retEr;

		RSA* rsa = comu_createRSAByModulus(p, modulus, exponent, error);
	    if(rsa==NULL) return FALSE;

		// RSA sha256
	    if(algorithm!=NULL&&(strcasecmp(algorithm,"RS256")==0)) {
			unsigned char sign[1024];
			unsigned char hash[SHA256_DIGEST_LENGTH];

			SHA256(data, dataLen, hash);

			//  verification
			memset(sign,'\0',1024);
			int signLen = base64Url_decode(sign, (char*)encodedSign, strlen(encodedSign));

			retEr = RSA_verify(NID_sha256, hash, SHA256_DIGEST_LENGTH, sign, signLen, rsa);
			if(retEr != 1) {
				char errorBuffer[OAUTH_ERROR_STRING_MAX_LENGTH];
				ERR_error_string(ERR_get_error(), errorBuffer);
				if(error!=NULL) { *error = apr_pstrdup(p, errorBuffer); }
			}
	    }else{
	    		if(error!=NULL) { *error = apr_pstrdup(p, "algorithm not supported\n"); }
	    		retEr = 0;
	    }

		RSA_free(rsa);

		return (retEr == 1) ?  TRUE : FALSE;
	}
	char* comu_rsaEncrypt(apr_pool_t*p, unsigned char * data,int dataLen,unsigned char * publicKey, char** error) {
		unsigned char encoded[4098];
		unsigned char  encrypted[4098]={};

		RSA* rsa = comu_createRSA(p, publicKey, TRUE, error);
	    if(rsa==NULL) return NULL;

	    int retEr = RSA_public_encrypt(dataLen,data,encrypted,rsa,padding);
	    RSA_free(rsa);

		if(retEr == -1) {
			char errorBuffer[OAUTH_ERROR_STRING_MAX_LENGTH];
			ERR_error_string(ERR_get_error(), errorBuffer);
			if(error!=NULL) { *error = apr_pstrdup(p, errorBuffer); }
			return NULL;
		}

		memset(encoded,'\0',4098);
	    base64Url_encode(encoded, encrypted, retEr);
	    return apr_pstrdup(p, encoded);
	}

	char* comu_rsaDecrypt(apr_pool_t*p, unsigned char * encrypted, unsigned char * privateKey, char** error){
		unsigned char decrypted[4098]={};
		unsigned char decoded[4098];


		RSA* rsa = comu_createRSA(p, privateKey, FALSE, error);
	    if(rsa==NULL) return NULL;

	    int decodedLen = base64Url_decode(decoded, (char*)encrypted, strlen(encrypted));

	    int  retEr = RSA_private_decrypt(decodedLen,decoded,decrypted,rsa,padding);
	    RSA_free(rsa);

		if(retEr == -1) {
			char errorBuffer[OAUTH_ERROR_STRING_MAX_LENGTH];
			ERR_error_string(ERR_get_error(), errorBuffer);
			if(error!=NULL) { *error = apr_pstrdup(p, errorBuffer); }
			return NULL;
		}

	    return apr_pstrdup(p, decrypted);
	}

	char* comu_rsa256SignFromFile(apr_pool_t*p, unsigned char * data,int dataLen, unsigned char * privateKeyFile, char** error) {
		int retEr;
		unsigned char sign[256]={0};
		unsigned int signLen = 0;
		unsigned char encodeSign[1024];

		RSA* rsa = comu_createRSAFromFile(p, privateKeyFile, FALSE, error);
	    if(rsa==NULL) return NULL;

		// sha256
		unsigned char hash[SHA256_DIGEST_LENGTH];

		SHA256(data, dataLen, hash);

		//  signing
		retEr = RSA_sign(NID_sha256, hash, SHA256_DIGEST_LENGTH, sign, &signLen, rsa);
		RSA_free(rsa);

		if(retEr != 1) {
			char errorBuffer[OAUTH_ERROR_STRING_MAX_LENGTH];
			ERR_error_string(ERR_get_error(), errorBuffer);
			if(error!=NULL) { *error = apr_pstrdup(p, errorBuffer); }
			return NULL;
		}

		memset(encodeSign,'\0',1024);
	    base64Url_encode(encodeSign, sign, signLen);
	    return apr_pstrdup(p, encodeSign);

	}

	int comu_rsa256VerifyFromFile(apr_pool_t*p, unsigned char * data,int dataLen, unsigned char * publicKeyFile, char* encodedSign, char** error) {
		int retEr;
		unsigned char sign[1024];

		RSA* rsa = comu_createRSAFromFile(p, publicKeyFile, TRUE, error);
	    if(rsa==NULL) return FALSE;

	    // sha256
	    unsigned char hash[SHA256_DIGEST_LENGTH];

	    SHA256(data, dataLen, hash);

	    //  verification
		memset(sign,'\0',1024);
	    int signLen = base64Url_decode(sign, (char*)encodedSign, strlen(encodedSign));

	    retEr = RSA_verify(NID_sha256, hash, SHA256_DIGEST_LENGTH, sign, signLen, rsa);
		RSA_free(rsa);

		if(retEr != 1) {
			char errorBuffer[OAUTH_ERROR_STRING_MAX_LENGTH];
			ERR_error_string(ERR_get_error(), errorBuffer);
			if(error!=NULL) { *error = apr_pstrdup(p, errorBuffer); }
		}

		return (retEr == 1) ?  TRUE : FALSE;
	}

	char* comu_rsaEncryptFromFile(apr_pool_t*p, unsigned char * data,int dataLen,unsigned char * publicKeyFile, char** error) {
		unsigned char encoded[4098];
		unsigned char  encrypted[4098]={};

		RSA* rsa = comu_createRSAFromFile(p, publicKeyFile, TRUE, error);
	    if(rsa==NULL) return NULL;

	    int retEr = RSA_public_encrypt(dataLen,data,encrypted,rsa,padding);
	    RSA_free(rsa);

		if(retEr == -1) {
			char errorBuffer[OAUTH_ERROR_STRING_MAX_LENGTH];
			ERR_error_string(ERR_get_error(), errorBuffer);
			if(error!=NULL) { *error = apr_pstrdup(p, errorBuffer); }
			return NULL;
		}

		memset(encoded,'\0',4098);
	    base64Url_encode(encoded, encrypted, retEr);
	    return apr_pstrdup(p, encoded);
	}

	char* comu_rsaDecryptFromFile(apr_pool_t*p, unsigned char * encrypted, unsigned char * privateKeyFile, char** error){
		unsigned char decrypted[4098]={};
		unsigned char decoded[4098];


		RSA* rsa = comu_createRSAFromFile(p, privateKeyFile, FALSE, error);
	    if(rsa==NULL) return NULL;

	    int decodedLen = base64Url_decode(decoded, (char*)encrypted, strlen(encrypted));

	    int  retEr = RSA_private_decrypt(decodedLen,decoded,decrypted,rsa,padding);
	    RSA_free(rsa);

		if(retEr == -1) {
			char errorBuffer[OAUTH_ERROR_STRING_MAX_LENGTH];
			ERR_error_string(ERR_get_error(), errorBuffer);
			if(error!=NULL) { *error = apr_pstrdup(p, errorBuffer); }
			return NULL;
		}

	    return apr_pstrdup(p, decrypted);
	}

	char* comu_rsaPrintModulusFromFile(apr_pool_t*p, unsigned char * publicKeyFile, int isPublic) {
		int retEr;
		unsigned char encoded[1024];
		unsigned char buf[1024];
		int len;
		char* error = NULL;

		RSA* rsa = comu_createRSAFromFile(p, publicKeyFile, isPublic, &error);
	    if(rsa==NULL) {
			RSA_free(rsa);
	    		return (error!=NULL) ? error : apr_pstrdup(p, "unable to create rsa");
	    }

		memset(buf,'\0',1024);
		len = BN_bn2bin(rsa->n, buf);
		if(len<0) {
			RSA_free(rsa);
			return apr_pstrdup(p, "unable to retrieve modulus");
		}

		memset(encoded,'\0',1024);
		len = base64Url_encode(encoded, buf, len);
		if(len<0) {
			RSA_free(rsa);
			return apr_pstrdup(p, "unable to encode modulus");
		}
		printf("modulus : %s\r\n", encoded);

		memset(buf,'\0',1024);
		len = BN_bn2bin(rsa->e, buf);
		if(len<0) {
			RSA_free(rsa);
			return apr_pstrdup(p, "unable to retrieve modulus");
		}

		memset(encoded,'\0',1024);
		len = base64Url_encode(encoded, buf, len);
		if(len<0) {
			RSA_free(rsa);
			return apr_pstrdup(p, "unable to encode exponent");
		}
		printf("exponent : %s\r\n", encoded);

		RSA_free(rsa);

		return NULL;
	}

	// generate base64Url encoded signature ( used in JWT)
	const char* comu_generateHS256Signature(apr_pool_t*p, char* payload, unsigned char* secretKey, char** error) {
		unsigned char out[EVP_MAX_MD_SIZE];
		unsigned int outlen;
		char* tmp;
		unsigned char encode[64];
		unsigned char* result = NULL;

		if(secretKey==NULL||payload==NULL) return NULL;

		ERR_clear_error();

		//Generate signature
		result = HMAC(EVP_sha256(), secretKey, strlen(secretKey), (const unsigned char*)payload, strlen(payload), out, &outlen);
		if(result==NULL) {
				return NULL;
		}

		memset(encode,'\0',64);
		base64Url_encode(encode, out, outlen);
		return apr_pstrdup(p, encode);
	}

	// verifies base64Url encoded signature ( used in JWT)
	int comu_verifyHS256Signature(apr_pool_t*p, char* payload, char* encodedSignature, unsigned char* secretKey, char** error) {
		unsigned char out[EVP_MAX_MD_SIZE];
		unsigned int outlen;
		char* tmp;
		unsigned char signature[64];
		unsigned char* result = NULL;

		if(secretKey==NULL||payload==NULL) return FALSE;

		ERR_clear_error();

		//Generate signature
			result = HMAC(EVP_sha256(), secretKey, strlen(secretKey), (const unsigned char*)payload, strlen(payload), out, &outlen);
		if(result==0) {
				return FALSE;
		}

		memset(signature,'\0',64);
		base64Url_decode(signature, (char*)encodedSignature, 64);
		return (memcmp(out, signature, outlen)==0);
	}

	// generate HMAC-Sha1 signature
	char* comu_generateHS1Signature(apr_pool_t* p, char* payload, unsigned char* secretKey, char** error) {
		unsigned char out[EVP_MAX_MD_SIZE];
		unsigned int outlen;
		char* tmp;
		unsigned char* result = NULL;
		int i; char *signature = NULL;

		if(secretKey==NULL||payload==NULL) return NULL;

		ERR_clear_error();

		//Generate signature
		result = HMAC(EVP_sha1(), secretKey, strlen(secretKey), (const unsigned char*)payload, strlen(payload), out, &outlen);
		if(result==NULL) {
				return NULL;
		}
		for(i=0;i<outlen;i++){
			  	tmp=apr_psprintf(p,"%02x", out[i]);
			  	if(i!=0) signature=apr_pstrcat(p,signature,tmp,NULL);
			  	else signature=apr_pstrdup(p,tmp);
	    }

		return signature;
	}

	/*
	 * initialize the crypto context in the server configuration record; the passphrase is set already
	 */
	apr_byte_t comu_aesCryptoInit(apr_pool_t*p, oidc_cipher_cfg *cfg,
			char** error) {

		if (cfg->encrypt_ctx != NULL)
			return TRUE;

		unsigned char *key_data = (unsigned char *) cfg->crypto_passphrase;
		int key_data_len = strlen(cfg->crypto_passphrase);

		unsigned int s_salt[] = { 41892, 72930 };
		unsigned char *salt = (unsigned char *) &s_salt;

		int i, nrounds = 5;
		unsigned char key[32], iv[32];

		/*
		 * Gen key & IV for AES 256 CBC mode. A SHA1 digest is used to hash the supplied key material.
		 * nrounds is the number of times the we hash the material. More rounds are more secure but
		 * slower.
		 */
		i = EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha1(), salt, key_data,
				key_data_len, nrounds, key, iv);
		if (i != 32) {
			if(error!=NULL) *error=apr_psprintf(cfg->p,  "key size must be 256 bits!");
			return FALSE;
		}

		cfg->encrypt_ctx = apr_palloc(cfg->p, sizeof(EVP_CIPHER_CTX));
		cfg->decrypt_ctx = apr_palloc(cfg->p, sizeof(EVP_CIPHER_CTX));

		/* initialize the encoding context */
		EVP_CIPHER_CTX_init(cfg->encrypt_ctx);
		if (!EVP_EncryptInit_ex(cfg->encrypt_ctx, EVP_aes_256_cbc(), NULL, key,
				iv)) {
			if(error!=NULL) *error=apr_psprintf(p,  "EVP_EncryptInit_ex on the encrypt context failed: %s",
					ERR_error_string(ERR_get_error(), NULL));
			return FALSE;
		}

		/* initialize the decoding context */
		EVP_CIPHER_CTX_init(cfg->decrypt_ctx);
		if (!EVP_DecryptInit_ex(cfg->decrypt_ctx, EVP_aes_256_cbc(), NULL, key,
				iv)) {
			if(error!=NULL) *error=apr_psprintf(p,  "EVP_DecryptInit_ex on the decrypt context failed: %s",
					ERR_error_string(ERR_get_error(), NULL));
			return FALSE;
		}

		return TRUE;
	}

	/*
	 * AES encrypt plaintext
	 */
	unsigned char *comu_aesEncrypt(apr_pool_t*p, oidc_cipher_cfg *cfg,
			unsigned char *plaintext, int *len, char** error) {

		if (comu_aesCryptoInit(p, cfg, error) == FALSE)
			return NULL;

		/* max ciphertext len for a n bytes of plaintext is n + AES_BLOCK_SIZE -1 bytes */
		int c_len = *len + AES_BLOCK_SIZE, f_len = 0;
		unsigned char *ciphertext = apr_palloc(p, c_len);

		/* allows reusing of 'e' for multiple encryption cycles */
		if (!EVP_EncryptInit_ex(cfg->encrypt_ctx, NULL, NULL, NULL, NULL)) {
			if(error!=NULL) *error=apr_psprintf(p, "EVP_EncryptInit_ex failed: %s",
					ERR_error_string(ERR_get_error(), NULL));
			return NULL;
		}

		/* update ciphertext, c_len is filled with the length of ciphertext generated, len is the size of plaintext in bytes */
		if (!EVP_EncryptUpdate(cfg->encrypt_ctx, ciphertext, &c_len, plaintext,
				*len)) {
			if(error!=NULL) *error=apr_psprintf(p, "EVP_EncryptUpdate failed: %s",
					ERR_error_string(ERR_get_error(), NULL));
			return NULL;
		}

		/* update ciphertext with the final remaining bytes */
		if (!EVP_EncryptFinal_ex(cfg->encrypt_ctx, ciphertext + c_len, &f_len)) {
			if(error!=NULL) *error=apr_psprintf(p, "EVP_EncryptFinal_ex failed: %s",
					ERR_error_string(ERR_get_error(), NULL));
			return NULL;
		}

		*len = c_len + f_len;

		return ciphertext;
	}

	/*
	 * AES decrypt ciphertext
	 */
	unsigned char *comu_aesDecrypt(apr_pool_t*p, oidc_cipher_cfg *cfg,
			unsigned char *ciphertext, int *len, char** error) {

		if (comu_aesCryptoInit(p, cfg, error) == FALSE)
			return NULL;

		/* because we have padding ON, we must allocate an extra cipher block size of memory */
		int p_len = *len, f_len = 0;
		unsigned char *plaintext = apr_palloc(p, p_len + AES_BLOCK_SIZE);

		/* allows reusing of 'e' for multiple encryption cycles */
		if (!EVP_DecryptInit_ex(cfg->decrypt_ctx, NULL, NULL, NULL, NULL)) {
			if(error!=NULL) *error=apr_psprintf(p, "EVP_DecryptInit_ex failed: %s",
					ERR_error_string(ERR_get_error(), NULL));
			return NULL;
		}

		/* update plaintext, p_len is filled with the length of plaintext generated, len is the size of ciphertext in bytes */
		if (!EVP_DecryptUpdate(cfg->decrypt_ctx, plaintext, &p_len, ciphertext,
				*len)) {
			if(error!=NULL) *error=apr_psprintf(p, "EVP_DecryptUpdate failed: %s",
					ERR_error_string(ERR_get_error(), NULL));
			return NULL;
		}

		/* update plaintext with the final remaining bytes */
		if (!EVP_DecryptFinal_ex(cfg->decrypt_ctx, plaintext + p_len, &f_len)) {
			if(error!=NULL) *error=apr_psprintf(p, "EVP_DecryptFinal_ex failed: %s",
					ERR_error_string(ERR_get_error(), NULL));
			return NULL;
		}

		*len = p_len + f_len;

		return plaintext;
	}

	/*
	 * cleanup the crypto context in the server configuration record
	 */
	apr_byte_t comu_aesCryptoDestroy(oidc_cipher_cfg *cfg) {

		if (cfg->encrypt_ctx == NULL)
			return TRUE;

		EVP_CIPHER_CTX_cleanup(cfg->encrypt_ctx);
		EVP_CIPHER_CTX_cleanup(cfg->decrypt_ctx);

		cfg->encrypt_ctx = NULL;
		cfg->decrypt_ctx = NULL;

		return TRUE;
	}

	char* cu_generateGuid(apr_pool_t* p){
	    apr_uuid_t uuid;
	    char buf[APR_UUID_FORMATTED_LENGTH + 1];

	    apr_uuid_get(&uuid);
	    apr_uuid_format(buf, &uuid);
		return apr_pstrdup(p,buf);
	}

	/*
	 * base64url encode a string
	 */
	int cu_base64urlEncode(apr_pool_t*p, char **dst, const char *src,
			int src_len, int remove_padding) {
		if ((src == NULL) || (src_len <= 0)) {
	//		printf("not encoding anything; src=NULL and/or src_len<1");
			return -1;
		}
		int enc_len = apr_base64_encode_len(src_len);
		char *enc = apr_palloc(p, enc_len);
		apr_base64_encode(enc, (const char *) src, src_len);
		int i = 0;
		while (enc[i] != '\0') {
			if (enc[i] == '+')
				enc[i] = '-';
			if (enc[i] == '/')
				enc[i] = '_';
			if (enc[i] == '=')
				enc[i] = ',';
			i++;
		}
		if (remove_padding) {
			/* remove /0 and padding */
			enc_len--;
			if (enc[enc_len - 1] == ',')
				enc_len--;
			if (enc[enc_len - 1] == ',')
				enc_len--;
			enc[enc_len] = '\0';
		}
		*dst = enc;
		return enc_len;
	}

	/*
	 * base64url decode a string
	 */
	int cu_base64urlDecode(apr_pool_t*p, char **dst, const char *src) {
		if (src == NULL) {
	//		printf("not decoding anything; src=NULL");
			return -1;
		}
		char *dec = apr_pstrdup(p, src);
		int i = 0;
		while (dec[i] != '\0') {
			if (dec[i] == '-')
				dec[i] = '+';
			if (dec[i] == '_')
				dec[i] = '/';
			if (dec[i] == ',')
				dec[i] = '=';
			i++;
		}
		switch (strlen(dec) % 4) {
		case 0:
			break;
		case 2:
			dec = apr_pstrcat(p, dec, "==", NULL);
			break;
		case 3:
			dec = apr_pstrcat(p, dec, "=", NULL);
			break;
		default:
			return 0;
		}
		int dlen = apr_base64_decode_len(dec);
		*dst = apr_palloc(p, dlen);
		return apr_base64_decode(*dst, dec);
	}

	/*
	 * encrypt and base64url encode a string
	 */
	int cu_encryptAndBase64urlEncode(apr_pool_t*p, oidc_cipher_cfg*cfg, char **dst,
			const char *src, char** error) {
		int crypted_len = strlen(src) + 1;
		unsigned char *crypted = comu_aesEncrypt(p, cfg, (unsigned char *) src, &crypted_len, error);
		if (crypted == NULL) {
	//		printf("cu_crypto_aes_encrypt failed");
			return -1;
		}
		return cu_base64urlEncode(p, dst, (const char *) crypted, crypted_len, 1);
	}

	/*
	 * decrypt and base64url decode a string
	 */
	int cu_base64urlDecodeAndDecrypt(apr_pool_t*p, oidc_cipher_cfg*cfg, char **dst,
			const char *src, char** error) {
		char *decbuf = NULL;
		int dec_len = cu_base64urlDecode(p, &decbuf, src);
		if (dec_len <= 0) {
			if(error!=NULL) *error = apr_pstrdup(p, "cu_base64urlDecode failed");
			return -1;
		}
		*dst = (char *) comu_aesDecrypt(p, cfg, (unsigned char *) decbuf,
				&dec_len, error);
		if (*dst == NULL) {
			if(error!=NULL) *error = apr_pstrdup(p, "comu_aesDecrypt failed");
			return -1;
		}
		return dec_len;
	}


<|start_filename|>src/shm_core/shm_apr.c<|end_filename|>
#include "shm_apr.h"
#include "shm_data.h"
#include "common_utils.h"

	static void shapr_make_array_core(array_header *res, shared_heap* sheap,int nelts, int elt_size, int clear){			    
 	   /*
    	* Assure sanity if someone asks for
   		* array of zero elts.
    	*/
    	if (nelts < 1) {
    	    nelts = 1;
    	}

   		if (clear) {
    	    res->elts = shdata_shpcalloc(sheap, nelts * elt_size);
    	}else {
        	res->elts = shdata_shpalloc(sheap, nelts * elt_size);
    	}

    	res->pool = NULL;
    	res->elt_size = elt_size;
    	res->nelts = 0;		/* No active elements yet... */
    	res->nalloc = nelts;	/* ...but this many allocated */
	}

	array_header* shapr_array_make(shared_heap* sheap, int nelts, int elt_size){
	    array_header *res;
		
	    res = (array_header*) shdata_shpalloc(sheap,sizeof(array_header));
    	shapr_make_array_core(res, sheap, nelts, elt_size, 1);
    	return res;
	}

	void * shapr_array_push(shared_heap* sheap, array_header *arr){
		int new_size;
		char *new_data;

		if (arr->nelts == arr->nalloc) {
        	new_size = (arr->nalloc <= 0) ? 1 : arr->nalloc * 2;       		

        	new_data = shdata_shpalloc(sheap, arr->elt_size * new_size);

        	memcpy(new_data, arr->elts, arr->nalloc * arr->elt_size);
        	memset(new_data + arr->nalloc * arr->elt_size, 0, arr->elt_size * (new_size - arr->nalloc));
               
        	arr->elts = new_data;
        	arr->nalloc = new_size;
    	}

    	++arr->nelts;
    	return arr->elts + (arr->elt_size * (arr->nelts - 1));
	}

	array_header* shapr_parseLongArrayFromCsv(shared_heap* sheap, int arraySz, const char* delim, char* src){
		char *srccpy=NULL, *prodStr=NULL, *p1=NULL;
        long *prodId=NULL, prodlook=0;
        char* end=NULL;
        array_header* arr=(array_header*)shapr_array_make(sheap,arraySz,sizeof(long));
        if(src==NULL){return arr;}
        
        srccpy=shdata_32BitString_copy(sheap,src);
        
        if(arr==NULL){
                return NULL;
        }
        prodStr=apr_strtok(srccpy,delim,&p1);
        while(prodStr!=NULL){
               // prodId= (long *) shapr_array_push(sheap,arr);
               // *prodId = (long) atol(prodStr);
               prodlook = strtol(prodStr,&end,10);
                if(*end=='\0'){
                	prodId= (long *) shapr_array_push(sheap,arr);
                	*prodId=prodlook;
                }
                prodStr =strtok_r(NULL,delim,&p1);
        }
		return arr;
	}
	// Copies source array of char* to sheap array.
	array_header* shapr_copyStringArrayToSheap(shared_heap* sheap, array_header* sarray){
		int i;
		char**place;
		array_header* dstArr;
		
		if(sarray==NULL||sarray->nelts<1) return NULL;
		
		dstArr=shapr_array_make(sheap,sarray->nelts,sizeof(char*));
		for(i=0;i<sarray->nelts;i++){
			place=(char**)shapr_array_push(sheap,dstArr);
			*place=shdata_32BitString_copy(sheap,(char*)cu_getElement(sarray,i));
		}
		return dstArr;
	}	
	array_header* shapr_parseStringArrayFromCsv(shared_heap* sheap, int arraySz, const char* delim, char* src){
		char *srccpy=NULL, *prodStr=NULL, *p1=NULL;
        char **val=NULL;
        array_header* arr=(array_header*)shapr_array_make(sheap,arraySz,sizeof(char*));
        if(src==NULL){return arr;}
        
        srccpy=shdata_32BitString_copy(sheap,src);
        
        if(arr==NULL){
                return NULL;
        }
        prodStr=apr_strtok(srccpy,delim,&p1);
        while(prodStr!=NULL){
                val= (char**) shapr_array_push(sheap,arr);
                *val = prodStr;
                prodStr =strtok_r(NULL,delim,&p1);
        }
                
		return arr;
	}

	typedef struct shapr_hash_entry_t shapr_hash_entry_t;

	struct shapr_hash_entry_t {
  		shapr_hash_entry_t *next;
    	unsigned int      hash;
    	const void       *key;
    	apr_ssize_t       klen;
    	const void       *val;
	};

	/*
	 * Data structure for iterating through a hash table.
	 *
	 * We keep a pointer to the next hash entry here to allow the current
	 * hash entry to be freed or otherwise mangled between calls to
	 * apr_hash_next().
	 */
	struct shapr_hash_index_t {
 	   shapr_hash_t         *ht;
 	   shapr_hash_entry_t   *this, *next;
 	   unsigned int        index;
	};

	/*
	 * The size of the array is always a power of two. We use the maximum
	 * index rather than the size so that we can use bitwise-AND for
 	 * modular arithmetic.
	 * The count of hash entries may be greater depending on the chosen
	 * collision rate.
	 */
	struct shapr_hash_t {
	    shapr_hash_entry_t   **array;
	    shapr_hash_index_t     iterator;  /* For apr_hash_first(NULL, ...) */
	    unsigned int         count, max;
	    shapr_hash_entry_t    *free;  /* List of recycled entries */
	};

	#define INITIAL_MAX 127 /* tunable == 2^n - 1 */


	static shapr_hash_entry_t **shapr_alloc_array(shared_heap* sheap, shapr_hash_t *ht, unsigned int max){
  		return (shapr_hash_entry_t **)shdata_shpcalloc(sheap, sizeof(*ht->array) * (max + 1));
	}

	shapr_hash_t* shapr_hash_make(shared_heap* sheap){
    	shapr_hash_t *ht;
    	ht = (shapr_hash_t*)shdata_shpalloc(sheap, sizeof(shapr_hash_t));
    	ht->free = NULL;
    	ht->count = 0;
    	ht->max = INITIAL_MAX;
    	ht->array = shapr_alloc_array(sheap,ht, ht->max);
    	return ht;
	}


	void shapr_hash_this(shapr_hash_index_t *hi,
                                const void **key,
                                apr_ssize_t *klen,
                                void **val){
	    if (key)  *key  = hi->this->key;
	    if (klen) *klen = hi->this->klen;
	    if (val)  *val  = (void *)hi->this->val;
	}

	/*
	 * This is where we keep the details of the hash function and control
	 * the maximum collision rate.
	 *
	 * If val is non-NULL it creates and initializes a new hash entry if
	 * there isn't already one there; it returns an updatable pointer so
	 * that hash entries can be removed.
	 */

	static shapr_hash_entry_t **shapr_find_entry(shared_heap* sheap,shapr_hash_t *ht,const void *key,apr_ssize_t klen,const void *val){
                       
    	shapr_hash_entry_t **hep, *he;
    	const unsigned char *p;
    	unsigned int hash;
    	apr_ssize_t i;

    /*
     * This is the popular `times 33' hash algorithm which is used by
     * perl and also appears in Berkeley DB. This is one of the best
     * known hash functions for strings because it is both computed
     * very fast and distributes very well.
     *
     * The originator may be <NAME> but the code in Berkeley DB
     * cites <NAME> as the source. The best citation I have found
     * is "<NAME>, Hash function for text in C, Usenet message
     * <<EMAIL>> in comp.lang.c , October, 1990." in Rich
     * Salz's USENIX 1992 paper about INN which can be found at
     * <http://citeseer.nj.nec.com/salz92internetnews.html>.
     *
     * The magic of number 33, i.e. why it works better than many other
     * constants, prime or not, has never been adequately explained by
     * anyone. So I try an explanation: if one experimentally tests all
     * multipliers between 1 and 256 (as I did while writing a low-level
     * data structure library some time ago) one detects that even
     * numbers are not useable at all. The remaining 128 odd numbers
     * (except for the number 1) work more or less all equally well.
     * They all distribute in an acceptable way and this way fill a hash
     * table with an average percent of approx. 86%.
     *
     * If one compares the chi^2 values of the variants (see
     * <NAME> ``Hashing Frequently Asked Questions'' at
     * http://burtleburtle.net/bob/hash/hashfaq.html for a description
     * of chi^2), the number 33 not even has the best value. But the
     * number 33 and a few other equally good numbers like 17, 31, 63,
     * 127 and 129 have nevertheless a great advantage to the remaining
     * numbers in the large set of possible multipliers: their multiply
     * operation can be replaced by a faster operation based on just one
     * shift plus either a single addition or subtraction operation. And
     * because a hash function has to both distribute good _and_ has to
     * be very fast to compute, those few numbers should be preferred.
     *
     *                  -- <NAME> <<EMAIL>>
     */
    	hash = 0;
    	if (klen == APR_HASH_KEY_STRING) {
        	for (p = key; *p; p++) {
            	hash = hash * 33 + *p;
        	}
        	klen = p - (const unsigned char *)key;
    	}else {
        	for (p = key, i = klen; i; i--, p++) {
            	hash = hash * 33 + *p;
        	}
    	}

    	/* scan linked list */
    	for (hep = &ht->array[hash & ht->max], he = *hep;
         	he; hep = &he->next, he = *hep) {
        	if (he->hash == hash
            	&& he->klen == klen
            	&& memcmp(he->key, key, klen) == 0)
            	break;
    	}
    	if (he || !val)
        	return hep;

    	/* add a new entry for non-NULL values */
    	if ((he = ht->free) != NULL)
        	ht->free = he->next;
    	else
        	he = (shapr_hash_entry_t*)shdata_shpalloc(sheap, sizeof(*he));
    	he->next = NULL;
    	he->hash = hash;
    	
    	/*allocate shared memory for key
    	 * this used to be he->key=key;
    	 **/
    	he->key  = shdata_32BitString_copy(sheap,(char*)key);
    	he->klen = klen;
    	he->val  = val;
    	*hep = he;
    	ht->count++;
    	return hep;
	}
	
	shapr_hash_index_t * shapr_hash_next(shapr_hash_index_t *hi){
    	hi->this = hi->next;
    	while (!hi->this) {
        	if (hi->index > hi->ht->max)
            	return NULL;

        	hi->this = hi->ht->array[hi->index++];
    	}
    	hi->next = hi->this->next;
    	return hi;
	}

	shapr_hash_index_t * shapr_hash_first(apr_pool_t* pool, shapr_hash_t *ht){
    	shapr_hash_index_t *hi;
    	if (pool)
        	hi = (shapr_hash_index_t*)apr_palloc(pool, sizeof(*hi));
    	else
        	hi = &ht->iterator;

    	hi->ht = ht;
    	hi->index = 0;
    	hi->this = NULL;
    	hi->next = NULL;
    	return shapr_hash_next(hi);
	}


	/*
	 * Expanding a hash table
	 */
	static void shapr_expand_array(shared_heap* sheap,shapr_hash_t *ht){
	    shapr_hash_index_t *hi;
	    shapr_hash_entry_t **new_array;
	    unsigned int new_max;

	    new_max = ht->max * 2 + 1;
	    new_array = shapr_alloc_array(sheap,ht, new_max);
	    for (hi = shapr_hash_first(NULL, ht); hi; hi = shapr_hash_next(hi)) {
	        unsigned int i = hi->this->hash & new_max;
	        hi->this->next = new_array[i];
	        new_array[i] = hi->this;
	    }
	    ht->array = new_array;
	    ht->max = new_max;
	}

	void shapr_hash_set(shared_heap* sheap,shapr_hash_t *ht,const void *key,apr_ssize_t klen,const void *val){
  		shapr_hash_entry_t **hep;
  		
  		if(key==NULL) return;
  		
  		hep = shapr_find_entry(sheap,ht, key, klen, val);
	    if (*hep) {
        	if (!val) {
            	/* delete entry */
            	shapr_hash_entry_t *old = *hep;
            	*hep = (*hep)->next;
            	old->next = ht->free;
            	ht->free = old;
            	--ht->count;
        	}else {        	
            	/* replace entry */
            	(*hep)->val = val;
            	/* check that the collision rate isn't too high */
            	if (ht->count > ht->max) {
                	shapr_expand_array(sheap,ht);
            	}
        	}
    	}
    	/* else key not present and val==NULL */
	}


	void* shapr_hash_get(shapr_hash_t *ht,const void *key,apr_ssize_t klen){
	    shapr_hash_entry_t *he, **he_p;
		he_p=shapr_find_entry(NULL,ht, key, klen, NULL);
    	he = *he_p;
    	if (he)
    	    return (void *)he->val;
    	else
    	    return NULL;
	}
	unsigned int shapr_hash_count(shapr_hash_t *ht){
		return ht->count;
	}



<|start_filename|>src/xml-core/xml_core.h<|end_filename|>
/*
 *  Created by <NAME> on 01/04/14.
 *
 */
#ifndef __TCREWRITE_XML_CORE__H_
#define __TCREWRITE_XML_CORE__H_

#ifdef __cplusplus
extern "C" {
#endif

#include "apache_typedefs.h"
	typedef struct llnode {
    	void* data;
    	struct llnode *next;
		struct llnode *prev;
  	}llnode;

	typedef struct DLinkedList{
		llnode *head;
		llnode *tail;
		int elts;
	}DLinkedList;

	typedef struct xc_rec{
		DLinkedList* xpath_nodes;
		DLinkedList* xpath_handlers;
		pool* p;	
	}XmlCore;

	typedef int (*xfunc) (pool*,char*,int,const char **,void*);
	typedef int (*bfunc) (pool*,char*,int,const char *,void*);
	typedef int (*efunc) (pool*,char*,int,void*);

	typedef struct x_rec{ 
		char* path;
		DLinkedList* xpath_nodes;
		void* userdata;
		xfunc start_function;
		bfunc body_function;
		efunc end_function;
		char* body;
	}x_rec;
	typedef struct node_info_rec{
		char* name;
	}node_info;

	DLinkedList* xc_getLinkedList(pool *p);
	int xc_AddToTail(pool* p, DLinkedList* xCore, void* elt);
	void* xc_peekTail(pool* p, DLinkedList* ll);
	XmlCore* xc_getXmlCore(pool *p);
	int xc_addXPathHandler(XmlCore* xCore, char* path, int options, const xfunc sfunction, const bfunc bfunction, const efunc efunction, void* udata);
	int xc_beginParsing(XmlCore* xCore,const char* file);
	int xc_parseFromStringSource(XmlCore* xCore,const char* source);
	char* xc_beginParsingTextResponse(XmlCore* xCore, char* file);
	char* xc_parseFromStringSourceTextResponse(XmlCore* xCore, char* source);

#ifdef __cplusplus
}
#endif
#endif	//__TCREWRITE_XML_CORE__H_


<|start_filename|>src/oidc-core/match_list.c<|end_filename|>
#include <xml_core.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <oidc-core/match_list.h>
#include <oidc-core/rewrite_core.h>
#include <common-utils/common_utils.h>

	mlx_match_event* ml_newMatchEventObj(pool*p){
		mlx_match_event*ret=(mlx_match_event*)apr_pcalloc(p,sizeof(mlx_match_event));
		ret->start=ret->end=0;
		return ret;
	}
	mlx_match_ip*ml_newMatchIpObj(pool*p){
		mlx_match_ip* ip=apr_palloc(p,sizeof(mlx_match_ip));
		ip->isRegex=TRUE;
		ip->negate=FALSE;
		ip->ip=NULL;
		return ip;
	}
	mlx_match_path*ml_newMatchPathObj(pool*p){
		mlx_match_path* ret=apr_palloc(p,sizeof(mlx_match_path));
		ret->negate=FALSE;
		ret->path=NULL;
		return ret;
	}
	mlx_match_header* ml_newMatchHeaderObj(pool* p){
		mlx_match_header* ret=apr_palloc(p,sizeof(mlx_match_header));
		ret->name=NULL;
		ret->value=NULL;
		ret->delimAnd=NULL;
		ret->negate=FALSE;
		ret->isRegex=TRUE;
		return ret;
	}
	
	mlx_match_env* ml_newMatchEnvObj(pool* p){
		mlx_match_env* ret=(mlx_match_env*)apr_palloc(p,sizeof(mlx_match_env));
		ret->name=NULL;
		ret->value=NULL;
		ret->negate=FALSE;
		ret->isRegex=TRUE;
		return ret;
	}
	
	mlx_ml_match* ml_newMatchListMatchObj(pool* p){
		mlx_ml_match* ret=NULL;
		ret=(mlx_ml_match*)apr_palloc(p,sizeof(mlx_ml_match));
		ret->host=NULL;
		ret->cascade=TRUE;
		ret->ip=NULL;
		ret->path=NULL;
		ret->headerList=apr_array_make(p,2,sizeof(mlx_match_header*));
		ret->event=NULL;
		return ret;
	}
//	mlx_match_header* ml_newMatchHeaderObjExt(pool* p,char*name,char*value,char* delimAnd,char* isregex,char* negate){
//		mlx_match_header* ret=apr_palloc(p,sizeof(mlx_match_header));
//		ret->name=name?apr_pstrdup(p,name):NULL;
//		ret->value=value?apr_pstrdup(p,value):NULL;
//		ret->delimAnd=delimAnd?apr_pstrdup(p,delimAnd):NULL;
//		ret->isRegex=isregex?STRTOBOOL(isregex):TRUE;
//		ret->negate=negate?STRTOBOOL(negate):FALSE;
//		return ret;
//	}
	// Return TRUE if all subset elements(string type) are found in a given set.
	int ml_isSubsetFound(pool*p,array_header* subset, array_header* set,int isRegex){
		int i,j,count;
		char* e1,*e2;
		int isValueMatch=FALSE;
		
		if(subset==NULL||set==NULL||subset->nelts>set->nelts) return FALSE;
		
		for(i=0,count=0;i<subset->nelts;i++){
			e1=cu_getElement(subset,i);
			for(j=0;j<set->nelts;j++){
				e2=cu_getElement(set,j);
				isValueMatch=isRegex?(rc_matchByStringsReturnDetails(p,e1,e2)==NULL):(strcmp(e1,e2)==0);
				if(isValueMatch){
					count++;
					break;
				}
			}
		}
		
		if(count==subset->nelts) return TRUE;
		
		return FALSE;
	}
	// Return TRUE if none of subset elements(string type) are found in a given set.
	int ml_isNegateSubsetFound(pool*p,array_header* subset, array_header* set, int isRegex){
		int i,j;
		char* e1,*e2;
		int isValueMatch=FALSE;
		
		if(subset==NULL||set==NULL) return FALSE;
		
		for(i=0;i<subset->nelts;i++){
			e1=cu_getElement(subset,i);
			for(j=0;j<set->nelts;j++){
				e2=cu_getElement(set,j);
				isValueMatch=isRegex?(rc_matchByStringsReturnDetails(p,e1,e2)==NULL):(strcmp(e1,e2)==0);
				if(isValueMatch){
					return FALSE;
				}
			}
		}
		return TRUE;
	}
	
	int matchList_isMatched(pool*p,char* regex, char* value, int isRegex)
	{
		return (isRegex==TRUE
				?(rc_matchByStringsReturnDetails(p,regex,value)==NULL)
				:(strcmp(regex,value)==0));
	}

	int matchList_isHostMatched(pool*p, char* matchHost, apr_table_t *headers_in){
		if ( matchHost==NULL || headers_in==NULL ) return TRUE;
		
		char* host = (char*)apr_table_get(headers_in, "Host");

		return ( host==NULL || (rc_matchByStringsReturnDetails(p, matchHost, host)==NULL) );
	}
	
	void ml_printMatchList(pool* p, array_header* arr){
		int i=0, j=0;
		mlx_ml_match* match=NULL;
		mlx_match_header* hdr=NULL;
		mlx_match_env* env=NULL;
		if(arr!=NULL&&arr->nelts>0){
			printf("\r\n\t\t -- MatchList[%d]",arr->nelts);
			for(i=0;i<arr->nelts;i++){
				match=(mlx_ml_match*)cu_getElement(arr,i);
				printf("\r\n\t>\t");
				if(match->host!=NULL){
					printf("Host: %s ",match->host);
				}
				if(match->ip!=NULL&&match->ip->ip!=NULL){
					printf("IP: %s ",match->ip->ip);
					printf("\tisregex: %s ",BOOLTOSTR(match->ip->isRegex));
					printf("\tnegate: %s ",BOOLTOSTR(match->ip->negate));
					printf("\n");
				}
				if(match->headerList!=NULL&&match->headerList->nelts>0){
					printf("Headers [%d]",match->headerList->nelts);
					for(j=0;j<match->headerList->nelts;j++){
						hdr=(mlx_match_header*)cu_getElement(match->headerList,j);
						printf("\r\n\t\t\t %s = %s",hdr->name,hdr->value);
						if(hdr->delimAnd) printf("\r\n\t\t\t delimAnd = \"%s\"",hdr->delimAnd);
						printf("\tisregex: %s ",BOOLTOSTR(hdr->isRegex));
						printf("\tnegate: %s ",BOOLTOSTR(hdr->negate));
						printf("\n");
					}
				}
				printf("\r\n");
			}
		}
		
	}	


<|start_filename|>src/url-utils/url_utils.h<|end_filename|>
#ifndef __TCREWRITE_URL_UTILS__H_
#define __TCREWRITE_URL_UTILS__H_
#include <apr_general.h>
#include <apr_pools.h>
#include <apr_tables.h>
#include <apr_strings.h>
#include <apr_lib.h>
#include "apache_typedefs.h"
#ifdef __cplusplus
	extern "C" {
#endif
int url_get_param(const char *queryString, const char *paramName, char *dest, int dlen);
char* url_getParam(pool* p, char* queryString,const char* name);

int url_decode(const char *src, char *dst, int dlen); 

int url_encode(const char *src, char *dst, int dlen);

long base64_encode (char *to, char *from, unsigned int len);
long base64_decode (char *to, char *from, unsigned int len);
char* url_addParam(pool* p, char* url, char* pName, char* pVal);

char* url_encode2(pool* p, char* src);
char* url_decode2(pool* p, char* src);
char* url_appendParamToQuery(pool*p, char*query, char*pName,char*pVal);

long base64Url_encode (char *to, char *from, unsigned int len);
long base64Url_decode (char *to, char *from, unsigned int len);

#ifdef __cplusplus
}
#endif
#endif


<|start_filename|>src/config-core/config_bindings_shm.c<|end_filename|>
#include <shm_data.h>
#include <shm_apr.h>
#include <common_utils.h>
#include <http-utils/http_client.h>
#include <config-core/config_bindings.h>
#include <config-core/config_bindings_shm.h>

#define SHEAP_ITEM_ID_CONFIG_CORE_GLOBALS "CONFIG_CORE_GLOBALS"

	shapr_hash_t* cbs_copyParamsOnSheap(pool*p, shared_heap*sheap, apr_hash_t*params){	
		apr_hash_index_t* hi=NULL;
		char* val, *key;
		char* shmVal, *shmKey;
		shapr_hash_t* ret= shapr_hash_make(sheap);
		for (hi = apr_hash_first(p, params); hi; hi = apr_hash_next(hi)) {
			apr_hash_this(hi,(const void**)(&key),NULL,(void**)(&val));
			shmKey=shdata_32BitString_copy(sheap,key);
			shmVal=shdata_32BitString_copy(sheap,val);
			shapr_hash_set(sheap,ret,shmKey,APR_HASH_KEY_STRING,shmVal);
		}
		return ret;
	}
	
	cbs_service_descriptor* cbs_copyServiceDescripterOnSheap(pool*p, shared_heap* sheap,cfg_service_descriptor* sd){
		if(sd==NULL) return NULL;
		cbs_service_descriptor* ret=(cbs_service_descriptor*)shdata_shpcalloc(sheap,sizeof(cbs_service_descriptor));
		ret->id=shdata_32BitString_copy(sheap,sd->id);
		ret->name=shdata_32BitString_copy(sheap,sd->name);
		ret->uri=shdata_32BitString_copy(sheap,sd->uri);
		ret->userColonPass=shdata_32BitString_copy(sheap,sd->userColonPass);
		ret->timeoutSeconds=sd->timeoutSeconds;
		ret->params=cbs_copyParamsOnSheap(p, sheap,sd->params);
		return ret;
	}
	
	cbs_globals* cbs_copyGlobalsOnSheap(pool*p, shared_heap* sheap, cfg_globals* globals, int isRefresh){
		
		shdata_OpenItemTag(sheap,SHEAP_ITEM_ID_CONFIG_CORE_GLOBALS);
		
		cbs_globals* ret=(cbs_globals*)shdata_shpcalloc(sheap,sizeof(cbs_globals));
		ret->homeDir=shdata_32BitString_copy(sheap,globals->homeDir);
		ret->logsDir=shdata_32BitString_copy(sheap,globals->logsDir);
		ret->resourceService=cbs_copyServiceDescripterOnSheap(p,sheap,globals->resourceService);
		ret->isRefresh = isRefresh;
		shdata_CloseItemTagWithInfo(sheap,"Config Core Globals");
		return ret;
	}

	char* cbs_getRemoteResourcePath(pool* p, cbs_globals* globals,char* resource,char**details){
		char* ret=NULL,*reqUri;
		cbs_service_descriptor* rs=NULL;
		int responseCode=-1;
		pool* tp;
		apr_finfo_t finfo;
		apr_status_t rv;
		char* localPath=NULL;
		
		if(resource==NULL) return NULL;
		
		if(globals->resourceService!=NULL){
			rs=globals->resourceService;
			//setup filepool
			if(apr_pool_create(&tp,p)!=APR_SUCCESS){
				if(details!=NULL){
					*details=apr_pstrdup(p,"Failure to create subpool");
				}
				return NULL;
			}
			
			//try to load from local name space.
			reqUri=apr_pstrcat(p,rs->uri,"/",resource,NULL);
			ret=cb_writeRemoteResourceToDisk(p,globals->homeDir,reqUri,resource,rs->timeoutSeconds,rs->userColonPass,tp,details,&responseCode);
			
			apr_pool_destroy(tp);
		}
		
		return ret;
	}

	char* cbs_getLocalResourcePath(pool* p, cbs_globals* globals,char* resource,char**details){
		if(resource==NULL){return NULL;}
		return apr_pstrcat(p,globals->homeDir,"/",resource,NULL);
	}

	
	


<|start_filename|>src/oidc-core/oidc_config.h<|end_filename|>
#ifndef __TCREWRITE_ACTION_MAPPINGS__H_
#define __TCREWRITE_ACTION_MAPPINGS__H_
#include <apr_general.h>
#include <apr_pools.h>
#include <apr_tables.h>
#include <apache_typedefs.h>
#include <shm_data.h>
#include <shm_apr.h>
#include <template-core/template_engine.h>
#include <config-core/config_bindings_shm.h>
#include <json-api-core/json_parser.h>
#include "oidc_core_constants.h"
#include "cookie.h"

#define TIME_MAX 	(~ (~ (time_t) 0 << (sizeof (time_t) * CHAR_BIT - 1)))

	typedef struct oauth_jwskey{
		char* id;
		char* type;
		char* algorithm;
		char* use;
		char* modulus;
		char* exponent;
		char* x5c;
	}oauth_jwskey;

	typedef struct match_event{
		time_t start;
		time_t end;
	}match_event;
	
	typedef struct match_ip{
		char* ip;
		unsigned short negate;
		unsigned short isRegex;
	}match_ip;
	typedef struct match_path{
		char* path;
		unsigned short negate;
	}match_path;	
	typedef struct match_list_header{
		char* name;
		char* value;
		char* delimAnd;
		unsigned short negate;
		unsigned short isRegex;
	}match_list_header;
	
	typedef struct match_list_env{
		char* name;
		char* value;
		unsigned short negate;
		unsigned short isRegex;
	}match_list_env;
	
	typedef struct match_list_match{
		match_ip* ip;
		match_path*path;
		array_header* headerList;
		match_event*event;
		char* host;
		int cascade;
	}match_list_match;
	
	typedef struct match_list{
		char* name;
		array_header* list;
	}match_list;

	typedef struct action_header{
		char* name;
		char* value;
		char* regex;
		header_actions action;
	}action_header;
	
	typedef struct action_uri{
		char* uri;
		int weight;
	}action_uri;

	// custom response
	typedef struct action_response{
		int code;
		char* contentType;
		char* body;
	}action_response;
		
	typedef struct page_action{
		char *id, *description;		
		char* regex;
		char* handler_internal;
		template_engine* templateEngineRef;
		array_header* requestHeaders;		// array of action_header*
		array_header* responseHeaders;		// array of action_header*
		action_response* response;		
		char* uri, *oidcProvider, *relyingParty;
		int type;
		unsigned int isForward:1,isPermanent:1,isDebug:1, advancedTemplate:1,base64UrlEncodeState:1;
	}page_action;

	typedef struct pathmapping_action{
		page_action *action;
		match_list* matchList;
	}pathmapping_action;
	
	typedef struct path_mapping{
		char* pathRegex;
		int ignoreCase;
		array_header* pmactions;//array of pathmapping_action
		array_header* matchLists;
	}path_mapping;
	
	typedef struct path_mappings_rec{
		array_header* postauth;
	}path_mappings_rec;
	
	typedef struct relying_party{
		char* id;
		char* description;
		char *clientID;
		char* clientSecret;
		char* issuer;
		int	validateNonce;
		char* redirectUri;
		char* postLoginDefaultLandingPage;
	}relying_party;
	
	typedef struct oidc_providerl{
		char* id;
		char* metadataUrl;
		char* issuer;
		char* authorizationEndpoint;
		char* tokenEndpoint;
		char* jwksUri;
		shapr_hash_t* jwsKeys;
		int isDefault;
	}oidc_provider;

	typedef struct oidc_config{
		shapr_hash_t* page_actions;
		path_mappings_rec* path_mappings;
		shapr_hash_t* match_lists;
		template_engine* templateEngine;
		Cookie*	 rpSession;
		Cookie*	 oidcSession;
		Cookie*	 accessToken;
		shapr_hash_t* relyingPartyHash;
		shapr_hash_t* relyingPartyIdsHash;
		shapr_hash_t* oidcProviderHash;
		shapr_hash_t* oidcProviderIdsHash;
		oidc_provider* oidcProvider;
	}oidc_config;
	
	char* am_build(pool* p,shared_heap* sheap,int isRefresh,cbs_globals* globals,char* filepath);
	oidc_config* am_fetchFromSheap(shared_heap* sheap);
	page_action* am_getPageActionById(oidc_config* actmap,char* id);
	path_mapping* am_getPathMapping_PostAuth(pool* p,oidc_config* actmap,char* path,char* ip, apr_table_t* headers, apr_table_t* subprocess_env);
	page_action* am_getMatchingPageAction(pool* p,array_header* pactions,char* path,char* ip, apr_table_t* headers, apr_table_t* subprocess_env);
	match_list_match* am_isMatchListMatch(pool* p, match_list* matchlist, char* path, char* ip,apr_table_t *headers_in, apr_table_t* subprocess_env);
	void am_printAll(pool* p, oidc_config* oidcConfig);
	oauth_jwskey* am_getJWSKeyByKeyID(shapr_hash_t* keyHash, char* keyID);
	relying_party* am_getRelyingPartyByClientID(shapr_hash_t* relyingPartyHash, const char* clientID);
	relying_party* am_getRelyingPartyById(shapr_hash_t* relyingPartyIdsHash, const char* id);
	relying_party* am_getRelyingPartyByRedirectUri(pool*p, shapr_hash_t* relyingPartyHash, const char* currentRedirectUri);
	oidc_provider* am_getOidcProviderByIssuer(shapr_hash_t* oidcProviderHash, const char* issuer);
	oidc_provider* am_getOidcProviderById(shapr_hash_t* oidcProviderIdsHash, const char* id);

	typedef struct oauth_jwt_header {
		char* algorithm;
		char* type;
		char* keyID;
	}oauth_jwt_header;

	typedef struct oauth_jwt_claim {
		char* issuer;
		char* scope;
		char* subject;
		char* audience;
		time_t expiry;
		time_t issuedAt;
		time_t auth_time;
		apr_hash_t* options;
		array_header* roles;
	}oauth_jwt_claim;

	typedef struct oauth_jwt {
		oauth_jwt_header* header;
		oauth_jwt_claim*  claim;
		char* signature;
	}oauth_jwt;

	// JSON Web Key
	typedef struct oauth_jwk{
		char* algorithm;
		char* use;
		char* keyID;
		char* key;		// symmetric key
		char* modulus;	// rsa public key modulus
		char* exponent;	// rsa public key exponent
	}oauth_jwk;

	// JWT routines
	oauth_jwt_header* oauthutil_newJWTHeaderObj(pool* p);
	const char* oauthutil_serializeJWTHeader(pool* p, oauth_jwt_header* hdr);
	oauth_jwt_header* oauthutil_deserializeJWTHeader(pool* p, char* encodedHeader);

	oauth_jwt_claim* oauthutil_newJWTClaimObj(pool* p);
	const char* oauthutil_serializeJWTClaim(pool* p, oauth_jwt_claim* claim);
	oauth_jwt_claim* oauthutil_deserializeJWTClaim(pool* p, char* encodedClaim);
	oauth_jwt_claim* oauthutil_deserializeJWTClaimNoDecoding(pool* p, char* claimJson);

	oauth_jwt* oauthutil_newJWTObj(pool* p);
	const char* oauthutil_serializeJWT(pool*p, oauth_jwt* jwt, const char* secretKey) ;
	typedef const char* (*getClientSecretKeyByClientId_func)(pool*p, char* client_id, void* data);
	oauth_jwt* oauthutil_parseAndValidateJWT(pool* p, const char* src, getClientSecretKeyByClientId_func getClientSecretKeyByClientIdFunc, void* data);
	void oauthutil_printJWT(pool* p, oauth_jwt* jwt);

	//ID Token ( JWT format)
	oauth_jwk* oauthutil_newJWKObj(pool *p);
	const char* oauthutil_generateIDToken(pool* p, oauth_jwt_header* header, oauth_jwt_claim*  claim, const char* secretKey) ;
	typedef oauth_jwk* (*getJSONWebKey_func)(pool*p, oauth_jwt_header* header, const char* issuer, const char* audience, void* data, char** error);
	oauth_jwt* oauthutil_parseIDToken(pool* p, const char* src, char** payloadP, char** error);
	oauth_jwt* oauthutil_parseAndValidateIDToken(pool* p, const char* src, getJSONWebKey_func getJSONWebKeyFunc, void* data, char** error);
	void oauthutil_printIDToken(pool* p, oauth_jwt* IDToken);
	const char* oauthutil_serializeJWTClaimNoEncoding(pool* p, oauth_jwt_claim* claim);

	const char* am_getActionTypeStr(action_types type) ;
#endif //__TCREWRITE_ACTION_MAPPINGS__H_


<|start_filename|>src/oidc-core/oidc_config_xml.h<|end_filename|>
#ifndef __TCREWRITE_ACTION_MAPPINGS_XML__H_
#define __TCREWRITE_ACTION_MAPPINGS_XML__H_
#include "apache_typedefs.h"
#include "oidc_core_constants.h"
#include "cookie.h"

	typedef struct action_header_xml{
		char* name;
		char* value;
		char* regex;
		header_actions action;
	}action_header_xml;
	
	// custom response
	typedef struct action_response_xml{
		int code;
		char* contentType;
		char* body;
	}action_response_xml;
	
	typedef struct page_action_xml{
		char *id,*directory,*description;		
		char* regex;
		char* handler;
		array_header* responseHeaders;		// array of action_header_xml*
		array_header* requestHeaders;		// array of action_header_xml*
		action_response_xml* response;		// custom response		
		char* uri, *oidcProvider, *relyingParty;
		int type;
		int isDebug:1, isForward:1,isPermanent:1,advancedTemplate:1,base64UrlEncodeState:1;
	}page_action_xml;
	
	typedef struct pathmapping_action_xml{
		char *id;
		char* matchList;//matchlist name
	}pathmapping_action_xml;
		
	typedef struct path_mapping_xml{
		char* pathRegex;
		int ignoreCase;
		array_header*  postAuthActions;
		array_header* matchLists;
	}path_mapping_xml;

	typedef struct relying_party_xml{
		char* id;
		char* description;
		char *clientID;
		char* clientSecret;
		char* issuer;
		int 	validateNonce;
		char* redirectUri;
		char* postLoginDefaultLandingPage;
		int setCurrentPageAsState;
	}relying_party_xml;

	typedef struct oidc_provider_xml{
		char* id;
		char* metadataUrl;
		char* issuer;
		char* authorizationEndpoint;
		char* tokenEndpoint;
		char* jwksUri;
		char* jwksJson;
		int isDefault;
	}oidc_provider_xml;

	typedef struct oidc_config_xml{
		int uid;					// unique id for document
		apr_hash_t* page_actions_hash;
		array_header* path_mappings_arr;
		array_header* match_list_arr;
		Cookie*				rpSession;
		Cookie*				oidcSession;
		Cookie*				accessToken;
		apr_hash_t* relyingPartyHash;
		array_header* oidcProviders;
	}oidc_config_xml;
	
	oidc_config_xml* amx_newObj(pool* p);
	char* amx_loadConfFile(pool* p, char* file, oidc_config_xml* conf);
	void amx_printAll(pool* p,oidc_config_xml* conf);
	
#endif


<|start_filename|>src/template-core/template_engine.c<|end_filename|>
#include "template_engine.h"
#include "common_utils.h"
#include <apr_lib.h>

	static int templatecore_templateCount(){
		return sizeof(template_eng_templates)/sizeof(template_eng_template);
	}

	static template_eng_template* templatecore_findTemplate(char* id){
		int x;
		int len=templatecore_templateCount();
		for(x=0;x<len;x++){
			if(template_eng_templates[x].id!=NULL&&strcmp(template_eng_templates[x].id,id)==0){
				return (template_eng_template*)&(template_eng_templates[x]);
			}
		}
		return NULL;
	}

	template_engine* te_newEngineObj(shared_heap* sheap){
		template_engine* ret=NULL;
		ret=(template_engine*)shdata_shpcalloc(sheap,sizeof(template_engine));
		ret->templateHash=shapr_hash_make(sheap);
		return ret;
	}
	
	static template_eng_livetemplate* te_newLiveTemplate(shared_heap* sheap,template_eng_template* etemplate){
		template_eng_livetemplate* ret=NULL;
		ret=(template_eng_livetemplate*)shdata_shpcalloc(sheap,sizeof(template_eng_livetemplate));
		ret->engineTemplate=etemplate;
		return ret;
	}


	char* te_initialize(pool* p,shared_heap* sheap,cbs_globals* globals,template_engine* teng){
		char* ret=NULL;
		void* config=NULL;
		int x=0;
		template_eng_livetemplate* ltemplate=NULL;
		int len=templatecore_templateCount();
		
		for(x=0;x<len;x++){
			ltemplate=te_newLiveTemplate(sheap,(template_eng_template*)&(template_eng_templates[x]));
					
			//initialize template
			if(template_eng_templates[x].initFunc!=NULL){
				ret=(*template_eng_templates[x].initFunc)(p,sheap,globals,&config);
				if(ret!=NULL){
					return ret;
				}
				
				ltemplate->config=config;
			}
			
			//attach template to live template hash
			if(teng!=NULL){
				shapr_hash_set(sheap,teng->templateHash,template_eng_templates[x].id,APR_HASH_KEY_STRING,ltemplate);
			}
		}
		
		return ret;
	}
	char* te_getToken(pool* p, template_engine* tengine,char* tid, char* src){
		template_eng_livetemplate* ltemplate=NULL;
		char* ret=NULL;
		
		ltemplate=shapr_hash_get(tengine->templateHash,tid,APR_HASH_KEY_STRING);
		if(ltemplate!=NULL&&ltemplate->engineTemplate!=NULL&&ltemplate->engineTemplate->tokenFunc!=NULL){
			ret=(*ltemplate->engineTemplate->tokenFunc)(p,ltemplate->config,src);
		}
		
		return ret;
	}

	static int te_isToken(pool* p, char* token,template_engine* tengine){
		shapr_hash_index_t* hi;
		void* val, * key;
		
		if(tengine!=NULL&&token!=NULL){
			for(hi=shapr_hash_first(p,tengine->templateHash);hi;hi=shapr_hash_next(hi)){
				shapr_hash_this(hi,(const void**)&key,NULL,&val);
				if(strncmp(token,(char*)key,1)==0){
					return 1;
				}
			}
		}
		
		return 0;
	}
	
	
	
	typedef struct template_token{
		int num;
		char* prefix;
		char* postfix;
		char* id;
	}	template_token;
	
	static te_zeroToken(template_token* token){
		token->num=-1;
		token->prefix=NULL;
		token->postfix=NULL;
		token->id=NULL;
	}
	static char* te_append(pool* p, char* base, char* add1, char* add2){
		char* ret=NULL;
		if(base==NULL){
			ret=apr_pstrcat(p,add1,add2,NULL);	
		}else{
			ret=apr_pstrcat(p,base,add1,add2,NULL);	
		}
		return ret;
	}
	static char* te_appendToken(pool* p, array_header* matches,char* base,char* space,template_token* token,template_engine* tengine){
		char* ret=NULL;
		char* el=NULL;
		char* tmp=NULL;
		int dlen=0;
		
		if(matches!=NULL&&token!=NULL&&token->num>=0&&token->num<matches->nelts){
			el=cu_getElement(matches,token->num);
			if(token->id!=NULL){
				el=te_getToken(p,tengine,token->id,el);
			}
//			if(token->urlEncode==1){
//				dlen=(strlen(el)*3)+1;
//				tmp=apr_pcalloc(p,dlen);
//				url_encode(el,tmp,dlen);
//				el=tmp;
//			}else if (token->urlEncode==2){
//				dlen=strlen(el)+1;
//				tmp=apr_pcalloc(p,dlen);
//				url_decode(el,tmp,dlen);
//				el=tmp;
//			}
		}
		if(token!=NULL){
			ret=apr_pstrcat(p,SAFESTRBLANK(base),SAFESTRBLANK(space),SAFESTRBLANK(token->prefix),SAFESTRBLANK(el),SAFESTRBLANK(token->postfix),NULL);
		}else{
			ret=apr_pstrcat(p,SAFESTRBLANK(base),SAFESTRBLANK(space),NULL);	
		}
			
		return ret;
	}
	
	char* te_templateString(pool* p,template_engine* tengine,char* sourcestr,array_header* matches){
		char* ret=NULL;
		char* num=NULL;
		char code='\0';
		template_token token;
		char* match,*start=NULL, *str=NULL, *end=NULL,*begin=NULL,*cursor=NULL;
		
		str=apr_pstrdup(p,sourcestr);
		begin=str;
		cursor=str;
		
		match=strstr(begin,"($");
		while(match!=NULL){
			te_zeroToken(&token);
			
			//find number
			start=match+2;
			end=start;
			while(apr_isdigit(*end)){
				end++;
			}
			if(*end==')'||*end=='^'||*end=='$' || te_isToken(p,end,tengine)){   ///replace with IS TOKEN FROM TOKEN ENGINE!!!
				num=apr_pstrndup(p,start, (end-start));
				token.num=atoi(num);
			}
			if(te_isToken(p,end,tengine)){
				token.id=apr_pstrndup(p,end,1);
				end++;
			}
						
			//get pre/postfix stuff
			if(*end=='^'||*end=='$'){
				code=*end;
				start=end+1;
				end=start;
				while(*end!='\0'&&*end!=')'){
					end++;
				}
				if(*end==')'){
					if(code=='^'){
						token.prefix=apr_pstrndup(p,start, (end-start));
					}else if(code=='$'){
						token.postfix=apr_pstrndup(p,start, (end-start));
					}
				}
			}
				
			if(*end==')'){
				*match='\0';
				if(matches!=NULL&&token.num<matches->nelts){
					//do template
					ret=te_appendToken(p,matches,ret,cursor,&token,tengine);
				}else{
					ret=te_appendToken(p,NULL,ret,cursor,NULL,tengine);
				}
				cursor=end+1;
			}

			begin=end+1;
			match=strstr(begin,"($");
		}
		
		if(cursor!=NULL&&*cursor!='\0'){
			ret=te_append(p,ret,cursor,NULL);
		}
		return ret;
	}


<|start_filename|>src/log-utils/logging.h<|end_filename|>
#ifndef __TCREWRITE_LOGGING__H_
#define __TCREWRITE_LOGGING__H_

#include <apr_file_io.h>
#include "apache_typedefs.h"

	typedef struct mm_logger{
		pool* p;
		char* filepath;
		apr_file_t* file;
		long maxLogFileSizeMB;
	}mm_logger;

	mm_logger* logging_getLogger(pool* p,char* path,long maxLogFileSizeMB);
	
	void logging_log(mm_logger* log,const char* a_format, ...);
	void logging_printf(mm_logger* log,const char* a_format, ...);
	void logging_setMaxFileSize(mm_logger* log,int maxLogFileSizeMB);
	int logging_rotateLogFile(mm_logger* log);
	int logging_closeLogger(mm_logger* log);
	
	// static refresh log
	int lc_openLogFile(apr_pool_t* p,char* filepath);
	int lc_closeLogFile(void);
	int lc_rotateLogFile();
	int lc_truncateLogFile(void);
	int lc_trimLogFile(void);
	int lc_printLog(const char* format,...);
	
#endif



<|start_filename|>src/oidc-core/oidc_config.c<|end_filename|>
#include <oidc-core/oidc_config.h>
#include <oidc-core/oidc_config_xml.h>
#include <oidc-core/rewrite_core.h>
#include <common_utils.h>
#include <oidc-core/match_list.h>
#include <doc_parser_utils.h>
#include <http-utils/http_client.h>

#define CONST_PATH_ACTION_DEF_ELTS	4
#define SHEAP_ITEM_ID_AUTHZ_OIDC	"NGX_OPENIDC"
#define KEYBUFFSIZE 8192

	static path_mappings_rec* am_newPathMappingObj(shared_heap* sheap){
		path_mappings_rec* ret;
		ret=(path_mappings_rec*)shdata_shpalloc(sheap,sizeof(path_mappings_rec));
		ret->postauth=shapr_array_make (sheap,CONST_PATH_ACTION_DEF_ELTS,sizeof(path_mapping*));
		return ret;	
	}
	
	static oidc_config* am_newObj(shared_heap* sheap){
		oidc_config* ret;
		
		ret=(oidc_config*)shdata_shpalloc(sheap,sizeof(oidc_config));
		ret->path_mappings=am_newPathMappingObj(sheap);
		ret->page_actions=shapr_hash_make(sheap);
		ret->match_lists=shapr_hash_make(sheap);
		ret->templateEngine=NULL;
		ret->relyingPartyHash=shapr_hash_make(sheap);
		ret->relyingPartyIdsHash=shapr_hash_make(sheap);
		ret->oidcProviderHash=shapr_hash_make(sheap);
		ret->oidcProviderIdsHash=shapr_hash_make(sheap);
		ret->oidcProvider=NULL;
		return ret;		
	}
	
	static page_action* am_newPageAction(shared_heap* sheap){
		page_action* ret=NULL;
		ret=(page_action*)shdata_shpalloc(sheap,sizeof(page_action));
		ret->id=NULL;
		ret->regex=NULL;
		ret->handler_internal=NULL;
		ret->description=NULL;
		ret->isForward=0;
		ret->isPermanent=0;
		ret->type=action_authorize;
		ret->isDebug=0;
		ret->templateEngineRef=NULL;
		ret->advancedTemplate=FALSE;
		ret->requestHeaders=NULL;
		ret->responseHeaders=NULL;
		ret->response=NULL;		
		ret->uri=NULL;
		ret->oidcProvider=NULL;
		ret->relyingParty=NULL;
		ret->base64UrlEncodeState=1;
		return ret;	
	}
	
	page_action* am_getPageActionById(oidc_config* actmap,char* id){
		if(actmap==NULL||actmap->page_actions==NULL||id==NULL){return NULL;}
		return shapr_hash_get(actmap->page_actions,id,APR_HASH_KEY_STRING);
	}
	match_list* am_getMatchListByName(oidc_config* actmap,char* name){
		if(actmap==NULL||actmap->match_lists==NULL||name==NULL){return NULL;}
		return shapr_hash_get(actmap->match_lists,name,APR_HASH_KEY_STRING);
	}
	pathmapping_action* am_getPathMappingAction(shared_heap* sheap,oidc_config* actmap,pathmapping_action_xml* pmaX){
		pathmapping_action*ret=NULL;
		
		if(actmap==NULL||actmap->page_actions==NULL||pmaX==NULL){return NULL;}
		
		ret=(pathmapping_action*)shdata_shpcalloc(sheap,sizeof(pathmapping_action));
		ret->action=am_getPageActionById(actmap,pmaX->id);
		ret->matchList=am_getMatchListByName(actmap,pmaX->matchList);
		return ret;
	}	
//	char* am_getFormattedUrl(pool *p, char* cur, char* namespaceid){
//		int x,queryStrState=0;
//		int curlen=strlen(cur);
//		for(x=0;x<curlen;x++){
//			if(cur[x]=='?'){
//				if(x==curlen-1){
//					queryStrState=2;
//				}else{
//					queryStrState=1;	
//				}
//			}
//		}
//		if(queryStrState==0){
//			return apr_pstrcat(p,cur,"?mg=",namespaceid,NULL);
//		}else if(queryStrState==1){
//			return apr_pstrcat(p,cur,"&mg=",namespaceid,NULL);
//		}else if(queryStrState==2){
//			return apr_pstrcat(p,cur,"mg=",namespaceid,NULL);
//		}
//	}
	
	static action_header* am_newActionHeaderObj(shared_heap* sheap, action_header_xml* hdrX,shapr_hash_t* matchLists){
		action_header* ret= 
			(action_header*)shdata_shpcalloc(sheap, sizeof(action_header));
		ret->name = 
			shdata_32BitString_copy(sheap, hdrX->name);
		ret->value = 
			shdata_32BitString_copy(sheap, hdrX->value);
		ret->regex = 
			shdata_32BitString_copy(sheap, hdrX->regex);
		ret->action = hdrX->action;
		return ret;
	}
	
	static array_header* am_copyActionHeaders(pool* p, shared_heap* sheap, array_header* actionHeadersX,shapr_hash_t* matchLists){
		array_header* ret=NULL;
		action_header_xml* hdrX=NULL;
		int i=0;
		
		if(actionHeadersX==NULL || actionHeadersX->nelts<1) return NULL;
		
		ret = shapr_array_make(sheap, actionHeadersX->nelts, sizeof(action_header*));
		for(i=0; i<actionHeadersX->nelts; i++){
			action_header_xml* hdrX = (action_header_xml*)cu_getElement(actionHeadersX, i);
			if(hdrX!=NULL&&hdrX->name!=NULL) {
				action_header** pos = (action_header**)shapr_array_push(sheap, ret);
				*pos = am_newActionHeaderObj(sheap, hdrX,matchLists);
			}
		}
		return ret;
	}
	
	static action_response* am_copyActionResponse(shared_heap* sheap, action_response_xml* responseX){
		action_response* ret = NULL;
		
		if(responseX==NULL) return NULL;
		
		ret= (action_response*)shdata_shpcalloc(sheap, sizeof(action_response));
		ret->code = responseX->code;
		ret->contentType = shdata_32BitString_copy(sheap, responseX->contentType);
		ret->body = shdata_32BitString_copy(sheap, responseX->body);
		return ret;
	}

	static char* am_build_pageActions(pool* p,shared_heap* sheap,cbs_globals* globals,oidc_config_xml* axml,shapr_hash_t* hash,template_engine* templateEngine,
			shapr_hash_t* matchLists){
		apr_hash_index_t * hi=NULL;
		void *val=NULL;
		page_action_xml* pax=NULL;
		page_action* paction=NULL;
		int i=0;
		
		for (hi = apr_hash_first(p,axml->page_actions_hash); hi; hi = apr_hash_next(hi)) {
			apr_hash_this(hi, NULL, NULL, &val);
			if(val!=NULL){
				pax=(page_action_xml*)val;
				paction=am_newPageAction(sheap);
				
				//set global structures
				paction->templateEngineRef=templateEngine;
				
				//transfer details
				paction->isForward=pax->isForward;
				paction->isPermanent=pax->isPermanent;
				paction->type=pax->type;
				paction->advancedTemplate=pax->advancedTemplate;
				paction->id=shdata_32BitString_copy(sheap,pax->id);
				paction->description=shdata_32BitString_copy(sheap,pax->description);
				paction->regex=shdata_32BitString_copy(sheap,pax->regex);
				paction->handler_internal=shdata_32BitString_copy(sheap,pax->handler);	
				paction->isDebug=pax->isDebug;
				paction->requestHeaders=am_copyActionHeaders(p,sheap,pax->requestHeaders,matchLists);
				paction->responseHeaders=am_copyActionHeaders(p,sheap,pax->responseHeaders,matchLists);
				paction->response=am_copyActionResponse(sheap,pax->response);
				paction->uri=shdata_32BitString_copy(sheap,pax->uri);
				paction->oidcProvider=shdata_32BitString_copy(sheap,pax->oidcProvider);
				paction->relyingParty=shdata_32BitString_copy(sheap,pax->relyingParty);
				paction->base64UrlEncodeState=pax->base64UrlEncodeState;
				shapr_hash_set(sheap,hash,pax->id,APR_HASH_KEY_STRING,paction);
			}
		}
		return NULL;
	}
	static match_ip* am_newMatchIpFromXmlMatchIpObj(shared_heap*sheap,mlx_match_ip*matchIp){
		match_ip*ret;
		
		if(matchIp==NULL)	return NULL;
		
		ret=(match_ip*)shdata_shpalloc(sheap,sizeof(match_ip));
		ret->ip=shdata_32BitString_copy(sheap,matchIp->ip);
		ret->isRegex=matchIp->isRegex;
		ret->negate=matchIp->negate;
		return ret;
	}
	static match_path* am_newMatchPathFromXmlMatchPathObj(shared_heap*sheap,mlx_match_path*matchPath){
		match_path*ret;
		
		if(matchPath==NULL)	return NULL;
		
		ret=(match_path*)shdata_shpalloc(sheap,sizeof(match_path));
		ret->path=shdata_32BitString_copy(sheap,matchPath->path);
		ret->negate=matchPath->negate;
		return ret;
	}
	
	static match_event* am_newMatchEventObj(shared_heap*sheap,mlx_match_event* e){
		match_event* ret;
		
		if(e==NULL)	return NULL;
		
		ret=(match_event*)shdata_shpalloc(sheap,sizeof(match_event));
		ret->start=e->start;
		ret->end=e->end;
		return ret;
	}	
	
	static match_list_match* am_copyMatchListMatch(shared_heap* sheap,mlx_ml_match* matchX){
		match_list_match* ret=NULL;
		//page_action_nvp_xml* nvpX=NULL;
		//match_list_match_nvp* nvp=NULL, **nvpPlace=NULL;
		mlx_match_header* hdrX=NULL;
		match_list_header*hdr=NULL, **headerPlace;
		mlx_match_env* envX=NULL;
		match_list_env*env=NULL, **envPlace;		
		int i=0;
		
		if(matchX==NULL) return NULL;
		
		ret=(match_list_match*)shdata_shpalloc(sheap,sizeof(match_list_match));
		ret->cascade=matchX->cascade;
		ret->host=shdata_32BitString_copy(sheap,matchX->host);
		ret->ip=am_newMatchIpFromXmlMatchIpObj(sheap,matchX->ip);
		ret->path=am_newMatchPathFromXmlMatchPathObj(sheap,matchX->path);
		ret->event=am_newMatchEventObj(sheap,matchX->event);
		if(matchX->headerList!=NULL&&matchX->headerList->nelts>0){
			ret->headerList=shapr_array_make(sheap,matchX->headerList->nelts,sizeof(match_list_header*));
			for(i=0;i<matchX->headerList->nelts;i++){
				hdrX=(mlx_match_header*)cu_getElement(matchX->headerList,i);
				hdr=(match_list_header*)shdata_shpalloc(sheap,sizeof(match_list_header));
				hdr->name=shdata_32BitString_copy(sheap,hdrX->name);
				hdr->value=shdata_32BitString_copy(sheap,hdrX->value);
				hdr->delimAnd=shdata_32BitString_copy(sheap,hdrX->delimAnd);
				hdr->negate=hdrX->negate;
				hdr->isRegex=hdrX->isRegex;
				headerPlace=(match_list_header**)shapr_array_push(sheap,ret->headerList);
				*headerPlace=hdr;
			}
		}else{
			ret->headerList=NULL;
		}

		return ret;		
	}
	static char* am_build_matchLists(pool* p,shared_heap* sheap,oidc_config_xml* axml,shapr_hash_t* hash){
		mlx_matchlist* mlx=NULL;
		match_list* ml=NULL;
		mlx_ml_match* matchX=NULL;
		match_list_match* match=NULL, **matchPos=NULL;
		int i=0,j=0;
		
		if(axml->match_list_arr==NULL||axml->match_list_arr->nelts==0){return NULL;}
		
		for(i=0;i<axml->match_list_arr->nelts;i++){
			mlx=(mlx_matchlist*)cu_getElement(axml->match_list_arr,i);
			ml=(match_list*)shdata_shpalloc(sheap,sizeof(match_list));
			ml->name=shdata_32BitString_copy(sheap,mlx->name);
			if(mlx->matches!=NULL&&mlx->matches->nelts>0){
				ml->list=shapr_array_make(sheap,mlx->matches->nelts,sizeof(match_list_match*));
				for(j=0;j<mlx->matches->nelts;j++){
					matchX=(mlx_ml_match*)cu_getElement(mlx->matches,j);
					match=am_copyMatchListMatch(sheap,matchX);
					matchPos=(match_list_match**)shapr_array_push(sheap,ml->list);
					*matchPos=match;
				}
			}else{
				ml->list=NULL;
			}
			shapr_hash_set(sheap,hash,ml->name,APR_HASH_KEY_STRING,ml);
		}
		
		return NULL;
	}

	
	static path_mapping* am_buildMapping(shared_heap* sheap,oidc_config* actmap, path_mapping_xml* pathX){
		path_mapping* ret=NULL;
		int i=0;
		char* match=NULL;
		match_list* mlist=NULL, **mlistPos;
		pathmapping_action_xml* pmaX;
		pathmapping_action* pma,**pos;
		
		if(pathX==NULL||pathX->postAuthActions==NULL||pathX->postAuthActions->nelts<0){
			return NULL;
		}
		ret=(path_mapping*)shdata_shpalloc(sheap,sizeof(path_mapping));
		ret->pathRegex=shdata_32BitString_copy(sheap,pathX->pathRegex);
		ret->ignoreCase=pathX->ignoreCase;
		
		ret->pmactions=shapr_array_make(sheap,pathX->postAuthActions->nelts,sizeof(pathmapping_action*));
		for(i=0;i<pathX->postAuthActions->nelts;i++){
			pmaX=(pathmapping_action_xml*)cu_getElement(pathX->postAuthActions,i);
			pma=am_getPathMappingAction(sheap,actmap,pmaX);	
			pos=shapr_array_push(sheap,ret->pmactions);
			*pos=pma;
		}
		
		if(pathX->matchLists==NULL){
			ret->matchLists=NULL;
		}else{
			ret->matchLists=shapr_array_make(sheap,pathX->matchLists->nelts,sizeof(match_list*));
			
			//added linked match lists
			for(i=0;i<pathX->matchLists->nelts;i++){
				match=(char*)cu_getElement(pathX->matchLists,i);
				mlist=shapr_hash_get(actmap->match_lists,match,APR_HASH_KEY_STRING);
				if(mlist!=NULL){
					mlistPos=(match_list**)shapr_array_push(sheap,ret->matchLists);
					*mlistPos=mlist;
				}
			}
		}
		return ret;
	}
	static void am_addMapping(shared_heap* sheap,array_header* maparr,path_mapping* pmap){
			path_mapping** pmapholder=NULL;
			
			if(maparr!=NULL&&pmap!=NULL){
				pmapholder=(path_mapping**)shapr_array_push(sheap,maparr);
				*pmapholder=pmap;
			}
	}

	static relying_party* am_newRelyingParty(shared_heap* sheap){
		relying_party* ret=NULL;
		ret=(relying_party*)shdata_shpalloc(sheap,sizeof(relying_party));
		ret->id=NULL;
		ret->clientID=NULL;
		ret->clientSecret=NULL;
		ret->description=NULL;
		ret->issuer=NULL;
		ret->redirectUri=NULL;
		ret->postLoginDefaultLandingPage=NULL;
		return ret;
	}

	static char* am_copyRelyingsParties(pool* p,shared_heap* sheap, apr_hash_t* relyingPartyHashX, shapr_hash_t* relyingPartyHash, shapr_hash_t* relyingPartyIdsHash){
		apr_hash_index_t * hi=NULL;
		void *val=NULL;
		relying_party_xml* rpX=NULL;
		relying_party* rp=NULL;
		int i=0;

		for (hi = apr_hash_first(p, relyingPartyHashX); hi; hi = apr_hash_next(hi)) {
			apr_hash_this(hi, NULL, NULL, &val);
			if(val!=NULL){
				rpX=(relying_party_xml*)val;
				rp=am_newRelyingParty(sheap);

				//transfer details
				rp->id=shdata_32BitString_copy(sheap,rpX->id);
				rp->clientID=shdata_32BitString_copy(sheap,rpX->clientID);
				rp->description=shdata_32BitString_copy(sheap,rpX->description);
				rp->clientSecret=shdata_32BitString_copy(sheap,rpX->clientSecret);
				rp->issuer=shdata_32BitString_copy(sheap,rpX->issuer);
				rp->validateNonce = rpX->validateNonce;
				rp->redirectUri=shdata_32BitString_copy(sheap,rpX->redirectUri);
				rp->postLoginDefaultLandingPage=shdata_32BitString_copy(sheap,rpX->postLoginDefaultLandingPage);
				shapr_hash_set(sheap,relyingPartyIdsHash,rp->id,APR_HASH_KEY_STRING,rp);
				shapr_hash_set(sheap,relyingPartyHash,rp->clientID,APR_HASH_KEY_STRING,rp);
			}
		}
		return NULL;
	}

	static char* oauthconf_downloadOIDCProviderMetadata(pool*p, shared_heap* sheap, char* homeDir, char* metadataUrl){
		oidc_provider* oidcProvider=NULL;
		char *error=NULL;
		apr_file_t* file=NULL;
		apr_status_t status;
		char key[KEYBUFFSIZE];
		apr_size_t bytes_read = KEYBUFFSIZE-1;
		pool* tp=NULL;

		if(metadataUrl==NULL) return NULL;

		//setup filepool
		if(apr_pool_create(&tp,p)!=APR_SUCCESS){
			return NULL;
		}

		char* keyPath=docp_getRemoteResourcePathEx(tp,metadataUrl,homeDir,&error);
		if(keyPath==NULL){
			keyPath=docp_getLocalResourcePath(tp,metadataUrl,homeDir);
		}

		status = apr_file_open (&file, keyPath, APR_READ,APR_OS_DEFAULT,tp);
		if(status!=APR_SUCCESS)	{
			//File open operation failed.
			apr_pool_destroy(tp);
			return NULL;
		}

		memset(key, '\0', KEYBUFFSIZE);
		if( (status = apr_file_read(file, key, &bytes_read)) != APR_SUCCESS) {
			//File read operation failed.
			apr_pool_destroy(tp);
			apr_file_close(file);
			return NULL;
		}


		apr_file_close ( file );
		apr_pool_destroy(tp);

		return apr_pstrdup(p, key);
	}

	char* am_build(pool* p,shared_heap* sheap, int isRefresh,cbs_globals* globals,char* filepath){
		apr_status_t status;
		oidc_config_xml* axml=NULL;
		oidc_config*	ret=NULL;
		char* result=NULL;
		
		//stuff to handle config
		pool* subp=NULL;
		path_mapping_xml* pathx=NULL;
		int x=0, i=0;
		
		//stuff to map path mappings
		path_mapping* pmap=NULL;
		
		//Subdoc processing
		char* homeDir=globals->homeDir;
		cbs_service_descriptor *rs=globals->resourceService;
		char* error=NULL;
		apr_hash_index_t * hi=NULL;
		
		//do on subpool
		if((status=apr_pool_create(&subp,p))!=APR_SUCCESS){
			return apr_pstrdup(p,"Could not create subpool");	
		}
		axml=amx_newObj(subp);
		result=amx_loadConfFile(subp,filepath,axml);

		if(isRefresh==0){
			amx_printAll(subp,axml);
		}
		//end
		shdata_OpenItemTag(sheap,SHEAP_ITEM_ID_AUTHZ_OIDC);
		ret=am_newObj(sheap);
		
		//initialize template engine
		ret->templateEngine=te_newEngineObj(sheap);
		result=te_initialize(p,sheap,globals,ret->templateEngine);
		
		
		//parse through matchlists in config
		am_build_matchLists(p,sheap,axml,ret->match_lists);
		
		//parse through page_actions in config
		am_build_pageActions(p,sheap,globals,axml,ret->page_actions,ret->templateEngine,ret->match_lists);
				
		//parse through path mappings in config;
		for(x=0;x<axml->path_mappings_arr->nelts;x++){
			pathx=(path_mapping_xml*)cu_getElement(axml->path_mappings_arr,x);
			if(pathx->postAuthActions!=NULL&&pathx->postAuthActions->nelts>0){
				pmap=am_buildMapping(sheap,ret,pathx);
				if(pmap!=NULL){
					am_addMapping(sheap,ret->path_mappings->postauth,pmap);	
				}
			}
		}

		if(axml->oidcProviders==NULL||axml->oidcProviders->nelts==0) {
			return apr_pstrdup(p,"oidcProviders are missing");
		}

		// set default to NULL
		ret->oidcProvider = NULL;

		// iterate thru all the providers
		for(x=0;x<axml->oidcProviders->nelts;x++) {
			oidc_provider_xml* oidcProviderX=(oidc_provider_xml*)cu_getElement(axml->oidcProviders,x);
			if(oidcProviderX!=NULL){
				oidc_provider* oidcProvider=(oidc_provider*)shdata_shpcalloc(sheap,sizeof(oidc_provider));

				// copy one by one
				// download oidcProvider url and read it.
				oidcProvider=(oidc_provider*)shdata_shpcalloc(sheap,sizeof(oidc_provider));
				oidcProvider->isDefault = oidcProviderX->isDefault;
				oidcProvider->id=shdata_32BitString_copy(sheap,oidcProviderX->id);
				char* jwksJson = NULL;
				if(oidcProviderX->metadataUrl!=NULL) {
					oidcProvider->metadataUrl=shdata_32BitString_copy(sheap,oidcProviderX->metadataUrl);
					char* metadata = oauthconf_downloadOIDCProviderMetadata(p, sheap, homeDir, oidcProviderX->metadataUrl);
					Value* json = 	JSON_Parse(p, metadata);
					if(json==NULL) return NULL;

					Value* item = JSON_GetObjectItem(json, "issuer");
					char* issuer = (item!=NULL) ? (char*)JSON_GetStringFromStringItem(item) : NULL;
					oidcProvider->issuer=shdata_32BitString_copy(sheap,issuer);

					item = JSON_GetObjectItem(json, "authorization_endpoint");
					char* authorizationEndpoint = (item!=NULL) ? (char*)JSON_GetStringFromStringItem(item) : NULL;
					oidcProvider->authorizationEndpoint=shdata_32BitString_copy(sheap,authorizationEndpoint);

					item = JSON_GetObjectItem(json, "token_endpoint");
					char* tokenEndpoint = (item!=NULL) ? (char*)JSON_GetStringFromStringItem(item) : NULL;
					oidcProvider->tokenEndpoint=shdata_32BitString_copy(sheap,tokenEndpoint);

					item = JSON_GetObjectItem(json, "jwks_uri");
					char* jwksUri = (item!=NULL) ? (char*)JSON_GetStringFromStringItem(item) : NULL;
					oidcProvider->jwksUri=shdata_32BitString_copy(sheap,jwksUri);

					// download JWT verification keys from url
					if(oidcProvider->jwksUri!=NULL) {
						http_util_result* httpResult=hc_get_verbose(p, oidcProvider->jwksUri, 10, NULL, NULL, error);
						if(!hc_is200_OK(httpResult)) {
							if(error!=NULL) { *error = apr_pstrdup(p, "jwsUri response and cache file both failed"); }
							apr_pool_destroy (subp);
							return NULL;
						}
						jwksJson = httpResult->data;
					}
				} else {
					oidcProvider->issuer=shdata_32BitString_copy(sheap, oidcProviderX->issuer);
					oidcProvider->authorizationEndpoint=shdata_32BitString_copy(sheap,oidcProviderX->authorizationEndpoint);
					oidcProvider->tokenEndpoint=shdata_32BitString_copy(sheap,oidcProviderX->tokenEndpoint);
					oidcProvider->jwksUri=shdata_32BitString_copy(sheap,oidcProviderX->jwksUri);
					// download JWT verification keys from url
					if(oidcProvider->jwksUri!=NULL) {

						http_util_result* httpResult=hc_get_verbose(p, oidcProvider->jwksUri, 10, NULL, NULL, error);
						if(!hc_is200_OK(httpResult)) {
							if(error!=NULL) { *error = apr_pstrdup(p, "jwsUri response and cache file both failed"); }
							apr_pool_destroy (subp);
							return NULL;
						}
						jwksJson = httpResult->data;
					} else {
						jwksJson = shdata_32BitString_copy(sheap,oidcProviderX->jwksJson);
					}
				}

				if(jwksJson!=NULL) {
					Value* json = 	JSON_Parse(p, jwksJson);
					if(json==NULL) {
						if(error!=NULL) { *error = apr_pstrdup(p, "jwsUri response parsing failed"); }
						apr_pool_destroy (subp);
						return NULL;
					}

					Value* array = JSON_GetObjectItem(json, "keys");
					if(array==NULL||JSON_GetItemType(array)!=JSON_Array) {
						if(error!=NULL) { *error = apr_pstrdup(p, "keys object is not array"); }
						apr_pool_destroy (subp);
						return NULL;
					}

					int	arrSz = JSON_GetArraySize(array);
					oidcProvider->jwsKeys=shapr_hash_make(sheap);

					// Retrieve item number "item" from array "array". Returns NULL if unsuccessful.
					for (i=0; i<arrSz; i++) {

						oauth_jwskey* jwsKey=(oauth_jwskey*)shdata_shpcalloc(sheap,sizeof(oauth_jwskey));

						Value* element = JSON_GetArrayItem(array, i);
						Value* keyIDObj = JSON_GetObjectItem(element, "kid");
						const char* keyID = (keyIDObj) ? JSON_GetStringFromStringItem(keyIDObj) : NULL;
						jwsKey->id = shdata_32BitString_copy(sheap,keyID);

						Value* val = JSON_GetObjectItem(element, "kty");
						char* type = (val) ? (char*)JSON_GetStringFromStringItem(val) : NULL;
						jwsKey->type=shdata_32BitString_copy(sheap,type);

						val = JSON_GetObjectItem(element, "alg");
						char* algorithm = (val) ? (char*)JSON_GetStringFromStringItem(val) : NULL;
						jwsKey->algorithm=shdata_32BitString_copy(sheap, algorithm);

						val = JSON_GetObjectItem(element, "use");
						char* use = (val) ? (char*)JSON_GetStringFromStringItem(val) : NULL;
						jwsKey->use=shdata_32BitString_copy(sheap, use);

						val = JSON_GetObjectItem(element, "n");
						char* modulus = (val) ? (char*)JSON_GetStringFromStringItem(val) : NULL;
						jwsKey->modulus=shdata_32BitString_copy(sheap, modulus);

						val = JSON_GetObjectItem(element, "e");
						char* exponent = (val) ? (char*)JSON_GetStringFromStringItem(val) : NULL;
						jwsKey->exponent=shdata_32BitString_copy(sheap, exponent);

						shapr_hash_set(sheap,oidcProvider->jwsKeys,jwsKey->id,APR_HASH_KEY_STRING,jwsKey);

					}

				}

				shapr_hash_set(sheap,ret->oidcProviderHash,oidcProvider->issuer,APR_HASH_KEY_STRING,oidcProvider);
				shapr_hash_set(sheap,ret->oidcProviderIdsHash,oidcProvider->id,APR_HASH_KEY_STRING,oidcProvider);
				if(ret->oidcProvider==NULL) { // set the first valid one
					ret->oidcProvider = oidcProvider;
				}else if(oidcProvider->isDefault) { // override from default
					ret->oidcProvider = oidcProvider;
				}
			}
		}

		ret->rpSession=
			cookie_cookieShmDup(sheap,axml->rpSession);
		ret->oidcSession=
			cookie_cookieShmDup(sheap,axml->oidcSession);
		ret->accessToken=
			cookie_cookieShmDup(sheap,axml->accessToken);

		am_copyRelyingsParties(p, sheap, axml->relyingPartyHash,ret->relyingPartyHash, ret->relyingPartyIdsHash);

		shdata_CloseItemTagWithInfo(sheap,"Action Mappings");
		apr_pool_destroy(subp);
		
		return result;
	}
	
	oidc_config* am_fetchFromSheap(shared_heap* sheap){
		return (oidc_config*)shdata_getItem(sheap,	SHEAP_ITEM_ID_AUTHZ_OIDC);
	}

	static int am_isHeaderMatched(pool*p, match_list_header* hdr, char*header){
		array_header* matchHeaderValues=NULL, *headerValues=NULL;
		int isRegex=hdr->isRegex;
		int negate=hdr->negate;
		int hasDelim=(hdr->delimAnd==NULL)?FALSE:TRUE;
		int isHeaderMatch=FALSE;
		
		if(hdr->value==NULL) return FALSE;
		
		if(header==NULL){
			if(strcasecmp(hdr->value,"nil")==0) {
				return TRUE;
			}else {
				return FALSE;
			}
		}
		isHeaderMatch=matchList_isMatched(p,hdr->value, header, isRegex);
		
		if(hasDelim){
			matchHeaderValues=cu_parseStringArrayFromCsv(p, 4, hdr->delimAnd, hdr->value);
			headerValues=cu_parseStringArrayFromCsv(p, 4, hdr->delimAnd, header);		
			if(matchHeaderValues==NULL||headerValues==NULL) return FALSE;
		}
		if(negate==FALSE){
			if(!hasDelim&&isHeaderMatch||(hasDelim&&ml_isSubsetFound(p,matchHeaderValues,headerValues,isRegex))){
				return TRUE;
			}
		}else{
			if(!hasDelim&&isHeaderMatch==FALSE||(hasDelim&&ml_isNegateSubsetFound(p,matchHeaderValues,headerValues,isRegex))){
				return TRUE;
			}
		}

		return FALSE;
	}	
	static int am_isIpMatched(pool*p, match_ip* matchIp, char*ip){
		int isIpMatch;
		
		if(matchIp==NULL||matchIp->ip==NULL||ip==NULL) return TRUE;	
		
		isIpMatch=matchList_isMatched(p,matchIp->ip, ip, matchIp->isRegex);
		if(matchIp->negate==TRUE){isIpMatch=!isIpMatch;}
		
		return isIpMatch;
	}
	static int am_isPathMatched(pool*p, match_path* matchPath, char*path){
		int isPathMatch;
		
		if(matchPath==NULL||matchPath->path==NULL||path==NULL) return TRUE;	
		
		isPathMatch=(rc_matchByStringsReturnDetails(p,matchPath->path,path)==NULL);
		if(matchPath->negate==TRUE){isPathMatch=!isPathMatch;}
		
		return isPathMatch;
	}

	static int am_isEventScheduled(pool*p, match_event* e){
		int i;
		time_t currentTime=time(NULL);
		
		//No event configured
		if(e==NULL) return TRUE;
		
		if(( e->start < currentTime ) && ( currentTime < ( (e->end>0) ? e->end : TIME_MAX) ) ) {
			return TRUE;
		}

		return FALSE;
	}
	
	match_list_match* am_isMatchListMatch(pool* p, match_list* matchlist, char* path, char* ip,apr_table_t *headers_in,apr_table_t* subprocess_env){
		int i=0,j=0;
		char* header=NULL;
		//match_list_match_nvp* nvp=NULL;
		match_list_header* matchHeader=NULL;
		match_list_match* ret=NULL;
		
		for(i=0;i<matchlist->list->nelts;i++){
			ret=(match_list_match*)cu_getElement(matchlist->list,i);
			//verify regex
			if(matchList_isHostMatched(p, ret->host, headers_in)){
				if(am_isEventScheduled(p,ret->event)){
					if(am_isPathMatched(p,ret->path,path)){
						if(am_isIpMatched(p,ret->ip,ip)){
							//now verify headers
							if(ret->headerList!=NULL&&ret->headerList->nelts>0) { //need to match headers
								if(headers_in==NULL||apr_is_empty_table(headers_in)){ //no headers to match
									return NULL;
								}else{ //match headers
									int cascade = ret->cascade;
									for(j=0;j<ret->headerList->nelts;j++){
										matchHeader=(match_list_header*)cu_getElement(ret->headerList,j);
										header=(char*)apr_table_get(headers_in,matchHeader->name);
										if(am_isHeaderMatched(p,matchHeader,header)==FALSE){
											ret = NULL;
											break;
										}
									}
									/*
									 * Bug: As soon as any match headers failed to match
									 * above for loop used to return NULL from this function
									 * For backward compatibility, this bug is kept asis
									 * And can be triggered by setting by <match cascade="false"> tag
									 * in runtime.xml
									 * Fix: Cascade would allow next match to be matched
									 * if current match is failed to match.
									 */
									if ( cascade==TRUE && ret==NULL ) { continue; }

									return ret;
								}
							}else{
								return ret;
							}
						}
					}
				}
			}
		}
		return NULL;
	}
	static match_list_match* am_isMatchListsMatch(pool* p, array_header* matchLists, char* path, char* ip,apr_table_t *headers_in,apr_table_t* subprocess_env){
		match_list* list=NULL;
		int i=0;
		
		match_list_match* ret=NULL;
		
		if(matchLists==NULL||matchLists->nelts==0){return NULL;}
		
		for(i=0;i<matchLists->nelts;i++){
			list=(match_list*)cu_getElement(matchLists,i);
			ret=am_isMatchListMatch(p,list,path,ip,headers_in,subprocess_env);
			if(ret!=NULL){return ret;}
		}
		
		return NULL;
	}
	static path_mapping* am_getPathMapping(pool* p,array_header* pgmaps,char* path,char* ip, apr_table_t* headers, apr_table_t* subprocess_env){
		path_mapping* pmap=NULL;
		int x=0;
		if(pgmaps==NULL||path==NULL){return NULL;}
		
		for(x=0;x<pgmaps->nelts;x++){
			pmap=(path_mapping*)cu_getElement(pgmaps,x);
			if(rc_matchByStrings(p, pmap->pathRegex, path)==0
				||(pmap->ignoreCase==TRUE&&(rc_matchByStringsIgnoreCase(p, pmap->pathRegex, path)==0)) ){
				if(pmap->matchLists==NULL||pmap->matchLists->nelts==0){
					return pmap;
				}else if(am_isMatchListsMatch(p,pmap->matchLists,path,ip,headers,subprocess_env)!=NULL){
					return pmap;
				}
			}
		}
		
		return NULL;
	}
	
	page_action* am_getMatchingPageAction(pool* p,array_header* pmactions,char* path,char* ip, apr_table_t* headers, apr_table_t* subprocess_env){
			pathmapping_action* pmaction=NULL;
			int x=0;
			if(pmactions==NULL||path==NULL){return NULL;}
			
			for(x=0;x<pmactions->nelts;x++){
				pmaction=(pathmapping_action*)cu_getElement(pmactions,x);
				if(pmaction->matchList==NULL){
					return pmaction->action;
				}else if(am_isMatchListMatch(p,pmaction->matchList,path,ip,headers,subprocess_env)!=NULL){
					return pmaction->action;
				}
			}
			return NULL;
		}	

	path_mapping* am_getPathMapping_PostAuth(pool* p,oidc_config* actmap,char* path,char* ip, apr_table_t* headers, apr_table_t* subprocess_env){
		if(actmap==NULL||actmap->path_mappings==NULL) return NULL;
		return am_getPathMapping(p,actmap->path_mappings->postauth,path,ip,headers,subprocess_env);
	}

#define OAUTH_TOKEN_WILDCARDNULL(str) (str!=NULL?str:"*")
#define OAUTH_TOKEN_URLENCODE_WILDCARDNULL(p, str) (str!=NULL?url_encode2(p,str):"*")

oauth_jwt_header* oauthutil_newJWTHeaderObj(pool* p) {
	return (oauth_jwt_header*)apr_pcalloc(p, sizeof(oauth_jwt_header));
}

const char* oauthutil_serializeJWTHeader(pool* p, oauth_jwt_header* hdr) {
	Value* json = JSON_CreateObject(p);
	JSON_AddStringToObject(p, json, "alg", hdr->algorithm);
	JSON_AddStringToObject(p, json, "typ", (hdr->type!=NULL) ? hdr->type : "JWT");
	if(hdr->keyID!=NULL) {
		JSON_AddStringToObject(p, json, "kid", hdr->keyID);
	}
	char* headerJson = JSON_SerializeUnformatted(p, json);

	unsigned char encodedHeader[OAUTH_BASE64_BUFSIZE];
	memset(encodedHeader, '\0', OAUTH_BASE64_BUFSIZE);
	base64Url_encode(encodedHeader, headerJson, strlen(headerJson));

	return apr_pstrdup(p, encodedHeader);
}

oauth_jwt_header* oauthutil_deserializeJWTHeader(pool* p, char* encodedHeader) {
	Value* json, *item;
	oauth_jwt_header* header;

	unsigned char headerJson[OAUTH_BASE64_BUFSIZE];
	memset(headerJson, '\0', OAUTH_BASE64_BUFSIZE);
	base64Url_decode(headerJson, encodedHeader, strlen(encodedHeader));

	json = 	JSON_Parse(p, headerJson);
	if(json==NULL) return NULL;

	item = JSON_GetObjectItem(json, "alg");

	header = oauthutil_newJWTHeaderObj(p);
    header->algorithm = (item!=NULL) ? (char*)JSON_GetStringFromStringItem(item) : NULL;

	item = JSON_GetObjectItem(json, "kid");
    header->keyID = (item!=NULL) ? (char*)JSON_GetStringFromStringItem(item) : NULL;

	item = JSON_GetObjectItem(json, "typ");
    header->type = (item!=NULL) ? (char*)JSON_GetStringFromStringItem(item) :  NULL;

    return header;
}

 oauth_jwt_claim* oauthutil_newJWTClaimObj(pool* p) {
	return (oauth_jwt_claim*)apr_pcalloc(p, sizeof(oauth_jwt_claim));
}

const char* oauthutil_serializeJWTClaim(pool* p, oauth_jwt_claim* claim) {
	Value* json = JSON_CreateObject(p);
	if(claim->issuer!=NULL) {
		JSON_AddStringToObject(p, json, "iss", claim->issuer);
	}
	if(claim->scope!=NULL) {
		JSON_AddStringToObject(p, json, "scope", claim->scope);
	}
	if(claim->subject!=NULL) {
		JSON_AddStringToObject(p, json, "sub", claim->subject);
	}
	if(claim->audience!=NULL) {
		JSON_AddStringToObject(p, json, "aud", claim->audience);
	}
	if(claim->expiry>0) {
		JSON_AddNumberToObject(p, json, "exp", claim->expiry);
	}
	if(claim->issuedAt>0){
		JSON_AddNumberToObject(p, json, "iat", claim->issuedAt);
	}
	if(claim->auth_time>0){
		JSON_AddNumberToObject(p, json, "auth_time", claim->auth_time);
	}
	if(claim->options!=NULL) {
		apr_hash_index_t *hi;
		char* name=NULL,*value=NULL;
		for (hi = apr_hash_first(p, claim->options); hi; hi = apr_hash_next(hi)) {
			apr_hash_this(hi,(const void**)&name, NULL, (void**)&value);
			JSON_AddStringToObject(p, json, name, value);
		}
	}

	if(claim->roles!=NULL){
		int i;
		Value* rolesArray = JSON_CreateArray(p);
		JSON_AddItemToObject(p, json, "roles", rolesArray);
		for(i=0;i<claim->roles->nelts;i++){
			char* roleName = (char*)cu_getElement(claim->roles, i);
			if(roleName!=NULL) {
				JSON_AddItemToArray(p, rolesArray, JSON_CreateString(p, roleName));
			}
		}
	}
	char* claimJson = JSON_SerializeUnformatted(p, json);

	unsigned char encodedClaim[OAUTH_BASE64_BUFSIZE];
	memset(encodedClaim, '\0', OAUTH_BASE64_BUFSIZE);
	base64Url_encode(encodedClaim, claimJson, strlen(claimJson));

	return apr_pstrdup(p, encodedClaim);
}

static void oauthutil_itemCallback(Value* item, void* data) {
	oauth_jwt_claim* claim = (oauth_jwt_claim*)data;

	const char* name = (item!=NULL) ? JSON_GetItemString(item) : NULL ;
	if(name==NULL) return;

	if(JSON_GetItemType(item)==JSON_Number) {
		if(strcmp(name,"exp")==0) {
			claim->expiry = JSON_GetNumberFromNumberItem(item);
		}else if(strcmp(name,"iat")==0) {
			claim->issuedAt = JSON_GetNumberFromNumberItem(item);
		}
	}else if(JSON_GetItemType(item)==JSON_String) {// string
		if(strcmp(name,"iss")==0) {
			claim->issuer = (char*)JSON_GetStringFromStringItem(item);
		}else if(strcmp(name,"scope")==0) {
			claim->scope = (char*)JSON_GetStringFromStringItem(item);
		}else if(strcmp(name,"sub")==0) {
			claim->subject = (char*)JSON_GetStringFromStringItem(item);
		}else if(strcmp(name,"aud")==0) {
			claim->audience = (char*)JSON_GetStringFromStringItem(item);
		}else{
			apr_hash_set(claim->options,name, APR_HASH_KEY_STRING, JSON_GetStringFromStringItem(item));
		}
	}else if(JSON_GetItemType(item)==JSON_Array) {// string
		int i;
		if(strcmp(name,"roles")==0) {
			char** place, *role;

			int count = JSON_GetArraySize(item);
			for (i=0; i < count; i++){
				Value* el = JSON_GetArrayItem(item, i);
				if (el!=NULL&&JSON_GetItemType(el)==JSON_String) {
					role = (char*)JSON_GetStringFromStringItem(el);
					if(role!=NULL){
						place=(char**)apr_array_push(claim->roles);
						*place=role;
					}
				}
			}
		}
	}
}

oauth_jwt_claim* oauthutil_deserializeJWTClaim(pool* p, char* encodedClaim) {
	Value* json, *item;
	oauth_jwt_claim* claim;

	unsigned char claimJson[OAUTH_BASE64_BUFSIZE];
	memset(claimJson, '\0', OAUTH_BASE64_BUFSIZE);
	base64Url_decode(claimJson, encodedClaim, strlen(encodedClaim));

	json = 	JSON_Parse(p, claimJson);
	if(json==NULL) return NULL;

	claim = oauthutil_newJWTClaimObj(p);
	claim->options = apr_hash_make(p);
	claim->expiry = -1;
	claim->issuedAt = -1;
	claim->roles = apr_array_make(p,8,sizeof(char*));

	JSON_IterateObjectItemCallback(json, claim, oauthutil_itemCallback);

    return claim;
}

oauth_jwt_claim* oauthutil_deserializeJWTClaimNoDecoding(pool* p, char* claimJson) {
	Value* json, *item;
	oauth_jwt_claim* claim;

	if(claimJson==NULL) return NULL;

	json = 	JSON_Parse(p, claimJson);
	if(json==NULL) return NULL;

	claim = oauthutil_newJWTClaimObj(p);
	claim->options = apr_hash_make(p);
	claim->expiry = -1;
	claim->issuedAt = -1;
	claim->roles = apr_array_make(p,8,sizeof(char*));

	JSON_IterateObjectItemCallback(json, claim, oauthutil_itemCallback);

    return claim;
}

static const char* oauthutil_generateJWTSignature(pool*p, const char* algorithm, unsigned char* secretKey, char* payload) {
		char* error = NULL;
		const char* signature = NULL;

	    if(strcasecmp(algorithm,"HS256")==0){
	    		signature = comu_generateHS256Signature(p, payload, secretKey, &error);
	    } else if(strcasecmp(algorithm,"RS256")==0){
    			signature = comu_rsa256Sign(p, payload, strlen(payload), secretKey, &error);
	    }

	    return signature;
	}

oauth_jwt* oauthutil_newJWTObj(pool* p) {
	return (oauth_jwt*)apr_pcalloc(p, sizeof(oauth_jwt));
}

static int oauthutil_verifyJWTSignature(pool*p, const char* algorithm, unsigned char* secretKey, char* payload, char* encodedSignature) {
		char* error = NULL;
		int verified = FALSE;

	    if(secretKey==NULL||payload==NULL) return FALSE;

	    //Generate signature
	    if(strcasecmp(algorithm,"HS256")==0){
	    		verified = comu_verifyHS256Signature(p, payload, encodedSignature, secretKey, &error);
	    }else	 if(strcasecmp(algorithm,"RS256")==0){
    			verified = comu_rsa256Verify(p, payload,strlen(payload),secretKey, encodedSignature, &error);
	    }

	    return verified;
	}

const char* oauthutil_serializeJWT(pool*p, oauth_jwt* jwt, const char* secretKey) {

	if(jwt==NULL||jwt->header==NULL||jwt->claim==NULL)	return NULL;

	const char* encodedHeader = oauthutil_serializeJWTHeader(p, jwt->header);
	const char* encodedClaim = oauthutil_serializeJWTClaim(p, jwt->claim);

	// generate JWT
	if(encodedHeader==NULL||encodedClaim==NULL) return NULL;

	char* payload = apr_pstrcat(p, encodedHeader, ".", encodedClaim, NULL);

	const char* signature = oauthutil_generateJWTSignature(p, jwt->header->algorithm, (unsigned char*)secretKey, payload);

	return apr_pstrcat(p, payload, ".", signature, NULL);
}

oauth_jwt* oauthutil_parseAndValidateJWT(pool* p, const char* src, getClientSecretKeyByClientId_func getClientSecretKeyByClientIdFunc, void* data) {
	char* srccpy = NULL;
	char* token, *last, *payload;
	char* encodedHeader = NULL;
	char* encodedClaim = NULL;
	int verified;

	oauth_jwt* jwt = oauthutil_newJWTObj(p);


	if (src == NULL)	return NULL;

	srccpy = apr_pstrdup(p, src);

	token = apr_strtok(srccpy, ".", &last);
	if (token != NULL) {
		// header
		encodedHeader = token;
		jwt->header = oauthutil_deserializeJWTHeader(p, encodedHeader);
		if(jwt->header==NULL||jwt->header->algorithm==NULL) return NULL;

		// claim
		token = apr_strtok(NULL, ".", &last);
		if (token != NULL) {
			encodedClaim = token;
			jwt->claim = oauthutil_deserializeJWTClaim(p, encodedClaim);
			if(jwt->claim==NULL||jwt->claim->issuer==NULL) return NULL;
		} else {
			return NULL;
		}

		// signature
		token = apr_strtok(NULL, ".", &last);
		if (token != NULL) {
			jwt->signature = token;
		} else {
			return NULL;
		}

		if(getClientSecretKeyByClientIdFunc==NULL) return NULL;

		const char* secretKey = (*getClientSecretKeyByClientIdFunc)(p, jwt->claim->issuer, data);

//		printf("encodedHeader=%s, encodedClaim=%s encodedSignature=%s\r\n", encodedHeader, encodedClaim, jwt->signature);

    		payload = apr_pstrcat(p, encodedHeader, ".", encodedClaim, NULL);

	    verified = oauthutil_verifyJWTSignature(p, jwt->header->algorithm, (unsigned char*)secretKey, payload, jwt->signature);

	    if(verified==FALSE) return NULL;

	}

	return jwt;
}

void oauthutil_printJWT(pool* p, oauth_jwt* jwt) {
	if(jwt==NULL||jwt->header==NULL||jwt->claim==NULL)	return;

	if(jwt->header!=NULL) {
		printf("algorithm=%s\r\n", jwt->header->algorithm);
	}

	if(jwt->claim!=NULL) {
		if(jwt->claim->issuer!=NULL) {
			printf("issuer=%s\r\n", jwt->claim->issuer);
		}
		if(jwt->claim->scope!=NULL) {
			printf("scope=%s\r\n", jwt->claim->scope);
		}
		if(jwt->claim->subject!=NULL) {
			printf("subject=%s\r\n", jwt->claim->subject);
		}
		if(jwt->claim->audience!=NULL) {
			printf("audience=%s\r\n", jwt->claim->audience);
		}
		if(jwt->claim->expiry>0) {
			printf("expiry=%ld\r\n", jwt->claim->expiry);
		}
		if(jwt->claim->issuedAt>0) {
			printf("issuedAt=%ld\r\n", jwt->claim->issuedAt);
		}

		if(jwt->claim->options!=NULL) {
			apr_hash_index_t *hi;
			char* name=NULL,*value=NULL;
			for (hi = apr_hash_first(p, jwt->claim->options); hi; hi = apr_hash_next(hi)) {
				apr_hash_this(hi,(const void**)&name, NULL, (void**)&value);
				printf("%s=%s\r\n", name,value);
			}
		}

	}

	printf("signature = %s\r\n", jwt->signature);

}

// ID token ( openid) routines
// returns JWT formatted ID Token
const char* oauthutil_generateIDToken(pool* p, oauth_jwt_header* header, oauth_jwt_claim*  claim, const char* secretKey) {

	if(header==NULL || claim==NULL||secretKey==NULL) return NULL;

	oauth_jwt* jwt = oauthutil_newJWTObj(p);
	jwt->header = header;
	jwt->claim = claim;

	return oauthutil_serializeJWT(p, jwt, secretKey);
}

oauth_jwk* oauthutil_newJWKObj(pool *p){
	oauth_jwk* jwk=(oauth_jwk*)apr_pcalloc(p, sizeof(oauth_jwk));
	return jwk;
}

// parse JWT formatted ID Token
oauth_jwt* oauthutil_parseIDToken(pool* p, const char* src, char** payloadP, char** error){

	char* srccpy = NULL;
	char* token, *last;
	char* encodedHeader = NULL;
	char* encodedClaim = NULL;

	if (src == NULL)	{
		if(error!=NULL) { *error = apr_pstrdup(p, "id_token is null"); }
		return NULL;
	}

	srccpy = apr_pstrdup(p, src);

	token = apr_strtok(srccpy, ".", &last);
	if(token==NULL) {
		if(error!=NULL) { *error = apr_pstrdup(p, "id_token.header is null"); }
		return NULL;
	}

	oauth_jwt* jwt = oauthutil_newJWTObj(p);

	// header
	encodedHeader = token;
	jwt->header = oauthutil_deserializeJWTHeader(p, encodedHeader);

	// claim
	token = apr_strtok(NULL, ".", &last);
	if (token != NULL) {
		encodedClaim = token;
		jwt->claim = oauthutil_deserializeJWTClaim(p, encodedClaim);
	} else {
		if(error!=NULL) { *error = apr_pstrdup(p, "id_token.claim is null"); }
		return NULL;
	}

	// signature
	token = apr_strtok(NULL, ".", &last);
	if (token != NULL) {
		jwt->signature = token;
	} else {
		if(error!=NULL) { *error = apr_pstrdup(p, "id_token.signature is null"); }
		return NULL;
	}

	if(payloadP!=NULL) { *payloadP = apr_pstrcat(p, encodedHeader, ".", encodedClaim, NULL); }

//	printf("encodedHeader=%s, encodedClaim=%s encodedSignature=%s\r\n", encodedHeader, encodedClaim, jwt->signature);

	return jwt;

}

// validates JWT formatted ID Token
oauth_jwt* oauthutil_parseAndValidateIDToken(pool* p, const char* src, getJSONWebKey_func getJSONWebKeyFunc, void* data, char** error){
	char* payload = NULL;

	oauth_jwt* jwt = oauthutil_parseIDToken(p, src, &payload, error);
	if(jwt==NULL||payload==NULL) {
		if(error!=NULL) { *error = apr_pstrdup(p, "id_token parsing failed"); }
		return NULL;
	}

	if(jwt->header==NULL||jwt->header->algorithm==NULL) {
		if(error!=NULL) { *error = apr_pstrdup(p, "id_token.header is null"); }
		return NULL;
	}

	// claim
	if(jwt->claim==NULL) {
		if(error!=NULL) { *error = apr_pstrdup(p, "id_token.claim is null"); }
		return NULL;
	}

	if(jwt->claim->issuer==NULL||jwt->claim->audience==NULL) {
		if(error!=NULL) { *error = apr_pstrdup(p, "id_token.claim audience or issuer null"); }
		return NULL;
	}

	// validate claim expiry
	if(jwt->claim->expiry>0&&jwt->claim->expiry<apr_time_sec(apr_time_now())) {
		if(error!=NULL) { *error = apr_pstrdup(p, "id_token.claim expired"); }
		return NULL;
	}

	// signature
	if(jwt->signature==NULL) {
		if(error!=NULL) { *error = apr_pstrdup(p, "id_token.signature is null"); }
		return NULL;
	}

	if(getJSONWebKeyFunc==NULL) {
		if(error!=NULL) { *error = apr_pstrdup(p, "id_token.webkey function is null"); }
		return NULL;
	}

	oauth_jwk* jwk = (*getJSONWebKeyFunc)(p, jwt->header, jwt->claim->issuer, jwt->claim->audience, data, error);
	if(jwk==NULL) return NULL;

	int verified=FALSE;
	if(strcasecmp(jwt->header->algorithm,"HS256")==0){
		verified = comu_verifyHS256Signature(p, payload, jwt->signature, jwk->key, error);
	}else	 if(strcasecmp(jwt->header->algorithm,"RS256")==0){
		if(jwk->modulus!=NULL&&jwk->exponent!=NULL) {
			verified = comu_rsaVerifyByModulus(p, jwt->header->algorithm, payload,strlen(payload), jwk->modulus, jwk->exponent, jwt->signature, error);
		}else if(jwk->key!=NULL) {
			verified = comu_rsa256Verify(p, payload,strlen(payload), jwk->key, jwt->signature, error);
		}
	}

	if(verified==FALSE) {
		if(error!=NULL) { *error = apr_pstrdup(p, "id_token.signature failed"); }
		return NULL;
	}

	return jwt;

}

const char* oauthutil_serializeJWTClaimNoEncoding(pool* p, oauth_jwt_claim* claim) {
	Value* json = JSON_CreateObject(p);
	if(claim->issuer!=NULL) {
		JSON_AddStringToObject(p, json, "iss", claim->issuer);
	}
	if(claim->scope!=NULL) {
		JSON_AddStringToObject(p, json, "scope", claim->scope);
	}
	if(claim->subject!=NULL) {
		JSON_AddStringToObject(p, json, "sub", claim->subject);
	}
	if(claim->audience!=NULL) {
		JSON_AddStringToObject(p, json, "aud", claim->audience);
	}
	if(claim->expiry>0) {
		JSON_AddNumberToObject(p, json, "exp", claim->expiry);
	}
	if(claim->issuedAt>0){
		JSON_AddNumberToObject(p, json, "iat", claim->issuedAt);
	}

	if(claim->options!=NULL) {
		apr_hash_index_t *hi;
		char* name=NULL,*value=NULL;
		for (hi = apr_hash_first(p, claim->options); hi; hi = apr_hash_next(hi)) {
			apr_hash_this(hi,(const void**)&name, NULL, (void**)&value);
			JSON_AddStringToObject(p, json, name, value);
		}
	}
	return JSON_SerializeUnformatted(p, json);
}

// prints JWT formatted ID Token
void oauthutil_printIDToken(pool* p, oauth_jwt* IDToken){
	oauthutil_printJWT(p, IDToken);
}

static void am_printMatchList(pool* p, array_header* arr){
	int i=0, j=0;
	match_list_match* match=NULL;
	match_list_header* hdr=NULL;
	match_list_env* env=NULL;
	if(arr!=NULL&&arr->nelts>0){
		printf("\r\n\t\t -- MatchList[%d]",arr->nelts);
		for(i=0;i<arr->nelts;i++){
			match=(match_list_match*)cu_getElement(arr,i);
			printf("\r\n\t>\t");
			if(match->host!=NULL){
				printf("Host: %s ",match->host);
			}
			if(match->ip!=NULL&&match->ip->ip!=NULL){
				printf("IP: %s ",match->ip->ip);
				printf("\tisregex: %s ",BOOLTOSTR(match->ip->isRegex));
				printf("\tnegate: %s ",BOOLTOSTR(match->ip->negate));
				printf("\n");
			}
			if(match->headerList!=NULL&&match->headerList->nelts>0){
				printf("Headers [%d]",match->headerList->nelts);
				for(j=0;j<match->headerList->nelts;j++){
					hdr=(match_list_header*)cu_getElement(match->headerList,j);
					printf("\r\n\t\t\t %s = %s",hdr->name,hdr->value);
					if(hdr->delimAnd) printf("\r\n\t\t\t delimAnd = \"%s\"",hdr->delimAnd);
					printf("\tisregex: %s ",BOOLTOSTR(hdr->isRegex));
					printf("\tnegate: %s ",BOOLTOSTR(hdr->negate));
					printf("\n");
				}
			}
			printf("\r\n");
		}
	}

}

void am_printAll(pool* p, oidc_config* oidcConfig){
	int x=0, i=0;
	page_action* pa=NULL;
	shapr_hash_index_t * hi=NULL;
	void *val=NULL;
	const void *key=NULL;

	match_list* mlist=NULL;
	char* includeXml=NULL;

	printf("<OIDC Configuration>\r\n");

	printf("Page Actions (%d)\r\n",shapr_hash_count (oidcConfig->page_actions));
	for (hi = shapr_hash_first(p,oidcConfig->page_actions); hi; hi = shapr_hash_next(hi)) {
			shapr_hash_this(hi, &key, NULL, &val);
			printf("\t* %s",key);
			if(val!=NULL){
				pa=(page_action*)val;

				if(pa->uri!=NULL){
					printf(",{uri:%s",pa->uri);
				}
				if(pa->handler_internal!=NULL){
					printf(",handler:%s",pa->handler_internal);
				}
				printf(",type=%s",am_getActionTypeStr(pa->type));
				if(pa->oidcProvider!=NULL){
					printf(",OidcProvider:%s",pa->oidcProvider);
				}
				if(pa->relyingParty!=NULL){
					printf(",RelyingParty:%s",pa->relyingParty);
				}
				printf(", isForward:%d,description:%s}",pa->isForward,pa->description);
				if(pa->requestHeaders!=NULL&&pa->requestHeaders->nelts>0){
					printf("\r\n\t\t>Request headers [%d]\n", pa->requestHeaders->nelts);
					for (i=0; i < pa->requestHeaders->nelts; i++){
						action_header* hdr =
							(action_header*)cu_getElement(pa->requestHeaders, i);
						printf("\t\t\tHeader{name:%s, value:%s}\r\n", hdr->name, (hdr->value)?hdr->value:"null");
					}
				}
				if(pa->responseHeaders!=NULL&&pa->responseHeaders->nelts>0){
					printf("\r\n\t\t>Response headers [%d]\n", pa->responseHeaders->nelts);
					for (i=0; i < pa->responseHeaders->nelts; i++){
						action_header* hdr =
							(action_header*)cu_getElement(pa->responseHeaders, i);
						printf("\t\t\tHeader{name:%s, value:%s}\r\n", hdr->name, (hdr->value)?hdr->value:"null");
					}
				}
			}
			printf("\r\n");
	}
	printf("Match Lists (%d):\r\n",shapr_hash_count (oidcConfig->match_lists));
	for(hi = shapr_hash_first(p,oidcConfig->match_lists); hi; hi = shapr_hash_next(hi)){
		shapr_hash_this(hi, &key, NULL, &val);
		mlist=(match_list*)val;
		printf("\t* %s",mlist->name);
		if(mlist->list->nelts>0){
			am_printMatchList(p,mlist->list);
		}
		printf("\r\n");
	}

	if(oidcConfig->oidcProvider!=NULL) {
		printf("ID: %s\r\n",oidcConfig->oidcProvider->id);
		printf("Metadataurl: %s\r\n",oidcConfig->oidcProvider->metadataUrl);
		printf("Issuer: %s\r\n",oidcConfig->oidcProvider->authorizationEndpoint);
		printf("JWKSUri: %s\r\n",oidcConfig->oidcProvider->jwksUri);
		printf("JWKSKeys (%d):\r\n",shapr_hash_count (oidcConfig->oidcProvider->jwsKeys));
		for(hi = shapr_hash_first(p,oidcConfig->oidcProvider->jwsKeys); hi; hi = shapr_hash_next(hi)){
			shapr_hash_this(hi, &key, NULL, &val);
			oauth_jwskey* jwk=(oauth_jwskey*)val;
			printf("\t\r\nkid=%s",jwk->id);
			printf("\t\t\r\n* type=%s",jwk->type);
			printf("\t\t\r\n* algorithm=%s",jwk->algorithm);
			printf("\t\t\r\n* use=%s",jwk->use);
			printf("\t\t\r\n* modulus=%s",jwk->modulus);
			printf("\t\t\r\n* exponent=%s",jwk->exponent);
			printf("\r\n");
		}
	}

	if(oidcConfig->relyingPartyHash!=NULL) {
		printf("RelyingParties (%d):\r\n",shapr_hash_count (oidcConfig->relyingPartyHash));
		for(hi = shapr_hash_first(p,oidcConfig->relyingPartyHash); hi; hi = shapr_hash_next(hi)){
			shapr_hash_this(hi, &key, NULL, &val);
			relying_party* relyingRarty=(relying_party*)val;
			printf("\t\r\nID=%s",relyingRarty->id);
			printf("\t\r\n* clientID=%s",relyingRarty->clientID);
			printf("\t\t\r\n* clientSecret=%s",relyingRarty->clientSecret);
			printf("\t\t\r\n* description=%s",relyingRarty->description);
			printf("\r\n");
		}
	}

}

oauth_jwskey* am_getJWSKeyByKeyID(shapr_hash_t* keyHash, char* keyID) {
	if(keyHash==NULL || keyID==NULL) {return NULL;}

	return (oauth_jwskey*)shapr_hash_get(keyHash, keyID, APR_HASH_KEY_STRING);
}

relying_party* am_getRelyingPartyByClientID(shapr_hash_t* relyingPartyHash, const char* clientID) {

	if (relyingPartyHash==NULL || clientID==NULL) return NULL;

	return (relying_party*)shapr_hash_get(relyingPartyHash, clientID, APR_HASH_KEY_STRING);
}

relying_party* am_getRelyingPartyById(shapr_hash_t* relyingPartyIdsHash, const char* id) {

	if (relyingPartyIdsHash==NULL || id==NULL) return NULL;

	return (relying_party*)shapr_hash_get(relyingPartyIdsHash, id, APR_HASH_KEY_STRING);
}

relying_party* am_getRelyingPartyByRedirectUri(pool*p, shapr_hash_t* relyingPartyHash, const char* currentRedirectUri) {
	shapr_hash_index_t * hi=NULL;
	void *val=NULL;
	const void *key=NULL;

	if (relyingPartyHash==NULL || currentRedirectUri==NULL) return NULL;

	relying_party* defaultRelyingParty=NULL;
	for(hi = shapr_hash_first(p, relyingPartyHash); hi; hi = shapr_hash_next(hi)){
		shapr_hash_this(hi, &key, NULL, &val);
		relying_party* relyingParty=(relying_party*)val;
		if(defaultRelyingParty==NULL) { defaultRelyingParty = relyingParty ; } // save the first one
		if(relyingParty!=NULL&&relyingParty->redirectUri!=NULL) {
			if(strstr(currentRedirectUri, relyingParty->redirectUri)!=0) {
				return relyingParty;
			}
		}
	}

	return defaultRelyingParty;
}

oidc_provider* am_getOidcProviderByIssuer(shapr_hash_t* oidcProviderHash, const char* issuer) {

	if (oidcProviderHash==NULL || issuer==NULL) return NULL;

	return (oidc_provider*)shapr_hash_get(oidcProviderHash, issuer, APR_HASH_KEY_STRING);
}

oidc_provider* am_getOidcProviderById(shapr_hash_t* oidcProviderIdsHash, const char* id) {

	if (oidcProviderIdsHash==NULL || id==NULL) return NULL;

	return (oidc_provider*)shapr_hash_get(oidcProviderIdsHash, id, APR_HASH_KEY_STRING);
}

const char* am_getActionTypeStr(action_types type) {
	printf("YYYYYYYYYYYYY=%d", type);
	if (type==action_login)
		return "login";
    else if (type==action_denial)
		return "denial";
    else if (type==action_authorize)
		return "authorize";
    else if (type==action_callback)
		return "callback";
	return "null";
}


<|start_filename|>Dockerfile<|end_filename|>
FROM centos:centos7
MAINTAINER http://www.centos.org
LABEL Vendor="CentOS"
LABEL License=GPLv2
LABEL Version=2.4.6-31

#RUN	yum -y update
#RUN	yum -y install epel-release

RUN yum -y install unzip wget tar gcc gcc-c++ git make apr-util-devel curl-devel
RUN yum -y install libuuid-devel && yum -y install openssl-devel && yum -y install pcre-devel

EXPOSE 80
EXPOSE 443

WORKDIR /
# test config
COPY test-conf/nginx.conf /usr/local/nginx/conf/
COPY test-conf/oidc-config.xml /usr/local/nginx/conf/

# copy success


# copy oidc source and nginx source to docker for compilation
COPY src /src

# copy scripts
ADD *.sh /

# make it executable
RUN chmod -v +x /*.sh

CMD ["/run-server.sh", "-DFOREGROUND"]

<|start_filename|>src/service-utils/http-utils/http_client.h<|end_filename|>
#ifndef HTTP_CLIENT_H_
#define HTTP_CLIENT_H_
#ifdef __cplusplus
	extern "C" {
#endif
//apr stuff
#include <apr_general.h>
#include <apr_pools.h>
#include <apr_strings.h>
#include <apr_tables.h>

#define HTTP_USER_AGENT	"openidc-libcurl"
	typedef struct http_util_result {
	   char *data;
	   char *content_type; 
	   size_t size;
	   double totalTime;
	   long responseCode;
	   apr_pool_t *p;
	   apr_table_t* headers_out;
	}http_util_result;


	typedef struct http_ssl_options {
		char* certType;
		char* certFile;
		char* passPhrase;
		char* keyType;
		char* keyName;
		char* caCertFile;
	}http_ssl_options;
	
	http_ssl_options* hc_createNewHttpSSLOptions(apr_pool_t *p);
	
	void hc_cleanup();
	void hc_init();
	http_util_result* hc_post_verbose(apr_pool_t *p,char* uri,long timeout,char* userColonPass,const char* postData,int postDataLen, apr_table_t * headers_in);
	http_util_result* hc_ssl_post_verbose(apr_pool_t *p,char* uri,long timeout,char* userColonPass,const char* postData,int postDataLen, http_ssl_options* sslOptions, apr_table_t * headers_in);
	http_util_result* hc_get_verbose(apr_pool_t *p,char* uri,long timeout,char* userColonPass, apr_table_t * headers_in,char** error);
	http_util_result* hc_get_verbose2(apr_pool_t *p,char* uri,long timeout,long connectionTimeout,char* userColonPass, apr_table_t * headers_in,char** error);
	http_util_result* hc_ssl_get_verbose(apr_pool_t *p,char* uri,long timeout,long connectionTimeout,char* userColonPass, http_ssl_options* sslOptions, apr_table_t * headers_in, char** error);
	http_util_result* hc_put_verbose(apr_pool_t *p,char* uri,long timeout,char* userColonPass, char* putData);
	http_util_result* hc_put_verbose2(apr_pool_t *p,char* uri,long timeout,char* userColonPass, const char* putData,int putDataLen, apr_table_t * headers_in);
	http_util_result* hc_method(apr_pool_t *p,const char* methodName,char* uri,long timeout,char* userColonPass,const char* data,int dataLen, apr_table_t * headers_in);
	http_util_result* hc_delete_verbose(apr_pool_t *p,char* uri,long timeout,char* userColonPass);
	http_util_result* hc_head_verbose(apr_pool_t *p,char* uri,long timeout,char* userColonPass,char** error);
	char* hc_getInfo(apr_pool_t* p);
	http_util_result* hc_get(apr_pool_t *p,char* uri,long timeout);
	int hc_is200_OK(http_util_result* ret);
	
#ifdef __cplusplus
	}
#endif	
#endif /*HTTP_CLIENT_H_*/


<|start_filename|>src/shm_core/shm_data.h<|end_filename|>
#ifndef __TCREWRITE_SHM_DATA__H_
#define __TCREWRITE_SHM_DATA__H_

#include <sys/types.h>
#include "apache_typedefs.h"
#include <apr_shm.h>

#ifdef __cplusplus
extern "C" {
#endif
	
#define MAX_PAGE_ITEMS		16	
#define PAGE_ITEM_CHARS		128	
#define SEGMENTS_PER_PAGE	2
//#define TOKEN_KEY_OFFSET	12


//#define SHM_BOOT_STATUS_UP_GREEN        1
//#define SHM_BOOT_STATUS_DOWN_BLUE	0
//#define SHM_BOOT_STATUS_FAILED_RED	-1

#define SHM_TIMESTAMP_INIT	-1
#define SHM_FAILHARD_SHEAP	16

	
	typedef struct page_item{
                int offset, size;
                char ITEMID[PAGE_ITEM_CHARS];
		char INFO[PAGE_ITEM_CHARS];
        }page_item;

	typedef struct segment_header{
		page_item items[MAX_PAGE_ITEMS];
		int itemcount;
	}segment_header;

	typedef struct shared_page{
		time_t timestamp;
		int segmentsize, flipcount;
		char *cursor, *data;
		int itemmax,frontsegment, backsegment;
		segment_header segments[SEGMENTS_PER_PAGE];		
	}shared_page;
	
	//for static use
	typedef struct smutex_refresh_mutex{
		apr_thread_mutex_t *thread_mutex;
		sig_atomic_t isRefreshing;		
	}smutex_refresh_mutex;
	
	//stored per process
	typedef struct shared_heap{
		shared_page* page;
		apr_shm_t* shm_main;
		time_t timestamp;
		sig_atomic_t flipcount;
		sig_atomic_t local_segment;
		//for thread sync
		smutex_refresh_mutex* refresh_mutex;		
	}shared_heap;

	typedef int (*rfunc) (pool*, shared_heap*, void*);
	int shdata_syncself(pool* p, shared_heap* sheap, rfunc function, void* userdata);

	int shdata_cursor(shared_heap* sheap);
	char* shdata_shpalloc(shared_heap* sheap, int size);
	char* shdata_shpcalloc(shared_heap* sheap, int size);
	void shdata_BeginTagging(shared_heap* sheap);
	void shdata_CloseItemTag(shared_heap* sheap);
	void shdata_CloseItemTagWithInfo(shared_heap* sheap, char* info);
	void shdata_OpenItemTag(shared_heap* sheap,const char* ID);
	void shdata_AppendInfo(shared_heap* sheap,char* info);
	void shdata_PublishBackSeg(shared_heap* sheap);
	void shdata_rollback(shared_heap* sheap);
	int shdata_getFlipCount(shared_heap* sheap);
	time_t* shdata_getLastFlipTime(shared_heap* sheap);
	shared_heap* shdata_sheap_make(pool* p, int segmentSize, char* path);
	shared_page* shdata_getNewSharedPage(pool* p, apr_shm_t** shm_t, int segmentsize, char* path);
	shared_heap* shdata_sheap_attach(pool* p, int segmentSize, char* path);
	char* shdata_getItem(shared_heap* sheap,const char* ID);

	//sheap copy stuff
	array_header* array_headerToSheap(shared_heap* sheap, array_header* sarray);
	char* shdata_32BitString_copy(shared_heap* sheap, char* str);
	apr_sockaddr_t* shdata_sockAddrCpy(shared_heap* sheap, apr_sockaddr_t* addr);
	void* shdata_memcpy(shared_heap* sheap, void* src, int size);
	
#ifdef __cplusplus
}
#endif

#endif


<|start_filename|>src/oidc-core/rewrite_core.h<|end_filename|>
#ifndef __TCREWRITE_REWRITE_CORE__H_
#define __TCREWRITE_REWRITE_CORE__H_
#include <apr_general.h>
#include <apr_pools.h>
#include <apr_tables.h>
#include <apr_strings.h>
#include <apr_lib.h>
#include <apache_typedefs.h>
#define REWRITE_CORE_VERSION	"1.0"

	char* rc_getInfo(pool* p);
	int   rc_matchByStrings(pool* p, char* regex, char* value);
	int   rc_matchByStringsIgnoreCase(pool* p, char* regex, char* value);
	char* rc_matchByStringsReturnDetails(pool* p, char* regex, char* value);
	int   rc_matchByStringsPattern(pool* p, char* regex, char* value, array_header** matches);
	char* rc_matchByStringsPatternReturnDetails(pool* p, char* regex, char* value, array_header** matches);
	int rc_isRegexValid(pool* p,char* regex);
#endif


<|start_filename|>src/template-core/template_engine.h<|end_filename|>
#ifndef TEMPLATE_ENGINE_H_
#define TEMPLATE_ENGINE_H_
#include <apache_typedefs.h>
#include <shm_apr.h>
#include <shm_data.h>
#include "config_bindings.h"
#include "template_handler_url.h"
#include "config_bindings_shm.h"

typedef char* (*tengine_template_init)(pool*,shared_heap*,cbs_globals*,void**);
typedef char* (*tengine_template_getToken)(pool*,void*,char*);

typedef struct template_engine{
	shapr_hash_t* templateHash;
}template_engine;

typedef struct template_eng_template{
	char* id;
	char* description;
	tengine_template_init initFunc;
	tengine_template_getToken tokenFunc;
}template_eng_template;


typedef struct template_eng_livetemplate{
	void* config;
	template_eng_template* engineTemplate;
}template_eng_livetemplate;

template_engine* te_newEngineObj(shared_heap* sheap);

char* te_initialize(pool* p,shared_heap* sheap,cbs_globals* globals,template_engine* teng);

char* te_getToken(pool* p, template_engine* tengine,char* tid, char* src);

char* te_templateString(pool* p,template_engine* tengine,char* sourcestr,array_header* matches);

static const template_eng_template template_eng_templates[]={
		{"U","Url Encode",NULL,temphand_url_encodeToken},
		{"u","Url Decode",NULL,temphand_url_decodeToken},
		{"B","Url Encode",NULL,temphand_base64_encodeToken},
		{"b","Url Decode",NULL,temphand_base64_decodeToken}	
};
#endif /*TEMPLATE_CORE_H_*/


<|start_filename|>src/config-core/config_messaging_parsing.h<|end_filename|>
#ifndef __TCREWRITE_CONFIG_MESSAGING_PARSING__H_
#define __TCREWRITE_CONFIG_MESSAGING_PARSING__H_

#include <sys/types.h>
#include "apache_typedefs.h"
	typedef struct cfgm_wire_header{
		char* nodeName;
		char* componentId;
		char* version;
	}cfgm_wire_header;
	
	typedef struct cfgm_wire_message{
		char* type;
		cfgm_wire_header* header;
		apr_hash_t* params;
	}cfgm_wire_message;
	
	cfgm_wire_header* cfgm_newWireHeader(pool* p);
	cfgm_wire_message* cfgm_newWireMessage(pool* p,cfgm_wire_header* header);
	cfgm_wire_message* cfgm_newWireMessageType(pool* p,const char* type,cfgm_wire_header* header);
	char* cfgm_serializeMessage(apr_pool_t* p, cfgm_wire_message* msg);
#endif



<|start_filename|>src/json-api-core/json_parser.cpp<|end_filename|>
#include <string.h>
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <float.h>
#include <limits.h>
#include <ctype.h>
#include <apr_strings.h>

#include "json_parser.h"

static int JSON_strcasecmp(const char *s1,const char *s2)
{
        if (!s1) return (s1==s2)?0:1;if (!s2) return 1;
        for(; tolower(*s1) == tolower(*s2); ++s1, ++s2) if(*s1 == 0)    return 0;
        return tolower(*(const unsigned char *)s1) - tolower(*(const unsigned char *)s2);
}

// The Value structure:
struct Value {
        struct Value *next,*prev;       // next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem
        struct Value *child;            // An array or object item will have a child pointer pointing to a chain of the items in the array/object.

        int type;                                       // The type of the item, as above.

        char *valuestring;                      // The item's string, if type==JSON_String
        int valueint;                           // The item's number, if type==JSON_Number
        double valuedouble;                     // The item's number, if type==JSON_Number

        char *string;                           // The item's name string, if this item is the child of, or is in the list of subitems of an object.
};

// Internal constructor.
inline Value *JSON_newValueObj(pool* p)
{
        return (Value*)apr_pcalloc(p, sizeof(Value));
}

inline Value *JSON_newValueObj(pool* p, int valueType)
{
        Value* value = (Value*)apr_pcalloc(p, sizeof(Value));
        value->type = valueType;
        return value;
}

inline Value *JSON_newValueObj(pool* p, int valueType, double num)
{
        Value* value = (Value*)apr_pcalloc(p, sizeof(Value));
        value->type = valueType;
        value->valuedouble=num;
        value->valueint=(int)num;
        return value;
}

inline Value *JSON_newValueObj(pool* p, int valueType, const char *string)
{
        Value* value = (Value*)apr_pcalloc(p, sizeof(Value));
        value->type = valueType;
        value->valuestring=apr_pstrdup(p,string);
        return value;
}
// Parse the input text to generate a number, and populate the result into item.
static const char *parse_number(pool* p,Value *item,const char *num)
{
        double n=0,sign=1,scale=0;int subscale=0,signsubscale=1;

        // Could use sscanf for this?
        if (*num=='-') sign=-1,num++;   // Has sign?
        if (*num=='0') num++;                   // is zero
        if (*num>='1' && *num<='9')     do      n=(n*10.0)+(*num++ -'0');       while (*num>='0' && *num<='9'); // Number?
        if (*num=='.') {num++;          do      n=(n*10.0)+(*num++ -'0'),scale--; while (*num>='0' && *num<='9');}      // Fractional part?
        if (*num=='e' || *num=='E')             // Exponent?
        {       num++;if (*num=='+') num++;     else if (*num=='-') signsubscale=-1,num++;              // With sign?
                while (*num>='0' && *num<='9') subscale=(subscale*10)+(*num++ - '0');   // Number?
        }

        n=sign*n*pow(10.0,(scale+subscale*signsubscale));       // number = +/- number.fraction * 10^+/- exponent

        item->valuedouble=n;
        item->valueint=(int)n;
        item->type=JSON_Number;
        return num;
}

// Render the number nicely from the given item into a string.
static char *print_number(pool* p,Value *item)
{
        char *str;
        double d=item->valuedouble;
        if (fabs(((double)item->valueint)-d)<=DBL_EPSILON && d<=INT_MAX && d>=INT_MIN)
        {
                str=(char*)apr_palloc(p, 21);    // 2^64+1 can be represented in 21 chars.
                sprintf(str,"%d",item->valueint);
        }
        else
        {
                str=(char*)apr_palloc(p, 64);    // This is a nice tradeoff.
                if (fabs(floor(d)-d)<=DBL_EPSILON)                      sprintf(str,"%.0f",d);
                else if (fabs(d)<1.0e-6 || fabs(d)>1.0e9)       sprintf(str,"%e",d);
                else                                                                            sprintf(str,"%f",d);
        }
        return str;
}

// Parse the input text into an unescaped cstring, and populate item.
static const unsigned char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
static const char *parse_string(pool* p,Value *item,const char *str)
{
        const char *ptr=str+1;char *ptr2;char *out;int len=0;unsigned uc;
        if (*str!='\"') return 0;       // not a string!

        while (*ptr!='\"' && (unsigned char)*ptr>31 && ++len) if (*ptr++ == '\\') ptr++;        // Skip escaped quotes.

        out=(char*)apr_palloc(p, len+1); // This is how long we need for the string, roughly.
        if (!out) return 0;

        ptr=str+1;ptr2=out;
        while (*ptr!='\"' && (unsigned char)*ptr>31)
        {
                if (*ptr!='\\') *ptr2++=*ptr++;
                else
                {
                        ptr++;
                        switch (*ptr)
                        {
                                case 'b': *ptr2++='\b'; break;
                                case 'f': *ptr2++='\f'; break;
                                case 'n': *ptr2++='\n'; break;
                                case 'r': *ptr2++='\r'; break;
                                case 't': *ptr2++='\t'; break;
                                case 'u':        // transcode utf16 to utf8. DOES NOT SUPPORT SURROGATE PAIRS CORRECTLY.
                                        sscanf(ptr+1,"%4x",&uc);        // get the unicode char.
                                        len=3;if (uc<0x80) len=1;else if (uc<0x800) len=2;ptr2+=len;

                                        switch (len) {
                                                case 3: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
                                                case 2: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
                                                case 1: *--ptr2 =(uc | firstByteMark[len]);
                                        }
                                        ptr2+=len;ptr+=4;
                                        break;
                                default:  *ptr2++=*ptr; break;
                        }
                        ptr++;
                }
        }
        *ptr2=0;
        if (*ptr=='\"') ptr++;
        item->valuestring=out;
        item->type=JSON_String;
        return ptr;
}

// Render the cstring provided to an escaped version that can be printed.
static char *print_string_ptr(pool* p,const char *str)
{
        const char *ptr;char *ptr2,*out;int len=0;

        if (!str) return apr_pstrdup(p,"");
        ptr=str;while (*ptr && ++len) {if ((unsigned char)*ptr<32 || *ptr=='\"' || *ptr=='\\') len++;ptr++;}

        out=(char*)apr_palloc(p, len+3);
        ptr2=out;ptr=str;
        *ptr2++='\"';
        while (*ptr)
        {
                if ((unsigned char)*ptr>31 && *ptr!='\"' && *ptr!='\\') *ptr2++=*ptr++;
                else
                {
                        *ptr2++='\\';
                        switch (*ptr++)
                        {
                                case '\\':      *ptr2++='\\';   break;
                                case '\"':      *ptr2++='\"';   break;
                                case '\b':      *ptr2++='b';    break;
                                case '\f':      *ptr2++='f';    break;
                                case '\n':      *ptr2++='n';    break;
                                case '\r':      *ptr2++='r';    break;
                                case '\t':      *ptr2++='t';    break;
                                default: ptr2--;        break;  // eviscerate with prejudice.
                        }
                }
        }
        *ptr2++='\"';*ptr2++=0;
        return out;
}
// Invote print_string_ptr (which is useful) on an item.
static char *print_string(pool* p,Value *item)  {return print_string_ptr(p, item->valuestring);}

// Predeclare these prototypes.
static const char *parse_value(pool* p,Value *item,const char *value);
static char *print_value(pool* p,Value *item,int depth,int fmt);
static const char *parse_array(pool* p,Value *item,const char *value);
static char *print_array(pool* p,Value *item,int depth,int fmt);
static const char *parse_object(pool* p,Value *item,const char *value);
static char *print_object(pool* p,Value *item,int depth,int fmt);

// Utility to jump whitespace and cr/lf
static const char *skip(const char *in) {while (in && (unsigned char)*in<=32) in++; return in;}

// Parse an object - create a new root, and populate.
Value* JSON_Parse(pool* p, const char *value)
{
        Value *c=JSON_newValueObj(p);
        if (!c) return NULL;       /* memory fail */

        if (!parse_value(p,c,skip(value))) {return NULL;}
        return c;
}

// Render a JSON item/entity/structure to text.
char* JSON_Serialize(pool* p,Value *item)                          {return print_value(p,item,0,1);}
char* JSON_SerializeUnformatted(pool* p,Value *item)       {return print_value(p,item,0,0);}

// Parser core - when encountering text, process appropriately.
static const char* parse_value(pool* p,Value *item,const char *value)
{
        if (!value)                                             return NULL;       // Fail on null.
        if (!strncmp(value,"null",4))   { item->type=JSON_NULL;  return value+4; }
        if (!strncmp(value,"false",5))  { item->type=JSON_False; return value+5; }
        if (!strncmp(value,"true",4))   { item->type=JSON_True; item->valueint=1;      return value+4; }
        if (*value=='\"')                               	{ return parse_string(p,item,value); }
        if (*value=='-' || (*value>='0' && *value<='9'))	{ return parse_number(p,item,value); }
        if (*value=='[')                                	{ return parse_array(p,item,value); }
        if (*value=='{')                                	{ return parse_object(p,item,value); }

        return NULL;       // failure.
}

// Render a value to text.
static char* print_value(pool* p,Value *item,int depth,int fmt)
{
        char *out=0;
        if (!item) return NULL;
        switch ((item->type)&255)
        {
                case JSON_NULL:        out=apr_pstrdup(p,"null");       break;
                case JSON_False:       out=apr_pstrdup(p,"false");break;
                case JSON_True:        out=apr_pstrdup(p,"true"); break;
                case JSON_Number:      out=print_number(p,item);break;
                case JSON_String:      out=print_string(p,item);break;
                case JSON_Array:       out=print_array(p,item,depth,fmt);break;
                case JSON_Object:      out=print_object(p,item,depth,fmt);break;
        }
        return out;
}

// Build an array from input text.
static const char* parse_array(pool* p,Value *item,const char *value)
{
        Value *child;
        if (*value!='[')        return NULL;       // not an array!

        item->type=JSON_Array;
        value=skip(value+1);
        if (*value==']') return value+1;        // empty array.

        item->child=child=JSON_newValueObj(p);
        if (!item->child) return NULL;              // memory fail
        value=skip(parse_value(p,child,skip(value)));     // skip any spacing, get the value.
        if (!value) return NULL;

        while (*value==',')
        {
                Value *new_item;
                if (!(new_item=JSON_newValueObj(p))) return NULL;     // memory fail
                child->next=new_item;new_item->prev=child;child=new_item;
                value=skip(parse_value(p,child,skip(value+1)));
                if (!value) return NULL;   // memory fail
        }

        if (*value==']') return value+1;        // end of array
        return NULL;       // malformed.
}

// Render an array to text
static char* print_array(pool* p,Value *item,int depth,int fmt)
{
        char **entries;
        char *out=0,*ptr,*ret;int len=5;
        Value *child=item->child;
        int numentries=0,i=0,fail=0;

        // How many entries in the array?
        while (child) numentries++,child=child->next;
        // Allocate an array to hold the values for each
        entries=(char**)apr_palloc(p, numentries*sizeof(char*));
        if (!entries) return 0;
        memset(entries,0,numentries*sizeof(char*));
        // Retrieve all the results:
        child=item->child;
        while (child && !fail)
        {
                ret=print_value(p,child,depth+1,fmt);
                entries[i++]=ret;
                if (ret) len+=strlen(ret)+2+(fmt?1:0); else fail=1;
                child=child->next;
        }

        // If we didn't fail, try to malloc the output string
        if (!fail) out=(char*)apr_palloc(p, len);
        // If that fails, we fail.
        if (!out) fail=1;

        // Handle failure.
        if (fail)
        {
                return 0;
        }

        // Compose the output array.
        *out='[';
        ptr=out+1;*ptr=0;
        for (i=0;i<numentries;i++)
        {
                strcpy(ptr,entries[i]);ptr+=strlen(entries[i]);
                if (i!=numentries-1) {*ptr++=',';if(fmt)*ptr++=' ';*ptr=0;}
        }
        *ptr++=']';*ptr++=0;
        return out;
}

// Build an object from the text.
static const char* parse_object(pool* p,Value *item,const char *value)
{
        Value *child;
        if (*value!='{')        return 0;       // not an object!

        item->type=JSON_Object;
        value=skip(value+1);
        if (*value=='}') return value+1;        // empty array.

        item->child=child=JSON_newValueObj(p);
        value=skip(parse_string(p,child,skip(value)));
        if (!value) return 0;
        child->string=child->valuestring;child->valuestring=0;
        if (*value!=':') return 0;      // fail!
        value=skip(parse_value(p,child,skip(value+1)));   // skip any spacing, get the value.
        if (!value) return 0;

        while (*value==',')
        {
                Value *new_item;
                if (!(new_item=JSON_newValueObj(p)))       return 0; // memory fail
                child->next=new_item;new_item->prev=child;child=new_item;
                value=skip(parse_string(p,child,skip(value+1)));
                if (!value) return 0;
                child->string=child->valuestring;child->valuestring=0;
                if (*value!=':') return 0;      // fail!
                value=skip(parse_value(p,child,skip(value+1)));   // skip any spacing, get the value.
                if (!value) return 0;
        }

        if (*value=='}') return value+1;        // end of array
        return 0;       // malformed.
}

// Render an object to text.
static char* print_object(pool* p,Value *item,int depth,int fmt)
{
        char **entries=0,**names=0;
        char *out=0,*ptr,*ret,*str;int len=7,i=0,j;
        Value *child=item->child;
        int numentries=0,fail=0;
        // Count the number of entries.
        while (child) numentries++,child=child->next;
        // Allocate space for the names and the objects
        entries=(char**)apr_palloc(p, numentries*sizeof(char*));
        if (!entries) return 0;
        names=(char**)apr_palloc(p, numentries*sizeof(char*));
        if (!names) {return 0;}
        memset(entries,0,sizeof(char*)*numentries);
        memset(names,0,sizeof(char*)*numentries);

        // Collect all the results into our arrays:
        child=item->child;depth++;if (fmt) len+=depth;
        while (child)
        {
                names[i]=str=print_string_ptr(p,child->string);
                entries[i++]=ret=print_value(p,child,depth,fmt);
                if (str && ret) len+=strlen(ret)+strlen(str)+2+(fmt?2+depth:0); else fail=1;
                child=child->next;
        }

        // Try to allocate the output string
        if (!fail) out=(char*)apr_palloc(p, len);
        if (!out) fail=1;

        // Handle failure
        if (fail)
        {
                for (i=0;i<numentries;i++) {
                	//if (names[i]) free(names[i]);
                	//if (entries[i]) free(entries[i]);
                }
                //free(names);free(entries);
                return 0;
        }

        // Compose the output:
        *out='{';ptr=out+1;if (fmt)*ptr++='\n';*ptr=0;
        for (i=0;i<numentries;i++)
        {
                if (fmt) for (j=0;j<depth;j++) *ptr++='\t';
                strcpy(ptr,names[i]);ptr+=strlen(names[i]);
                *ptr++=':';if (fmt) *ptr++='\t';
                strcpy(ptr,entries[i]);ptr+=strlen(entries[i]);
                if (i!=numentries-1) *ptr++=',';
                if (fmt) *ptr++='\n';*ptr=0;
        }

        if (fmt) for (i=0;i<depth-1;i++) *ptr++='\t';
        *ptr++='}';*ptr++=0;
        return out;
}

// Get Array size/item / object item.
int    JSON_GetArraySize(Value *array)                                                 {Value *c=array->child;int i=0;while(c)i++,c=c->next;return i;}
Value* JSON_GetArrayItem(Value *array,int item)                                {Value *c=array->child;  while (c && item>0) item--,c=c->next; return c;}
Value* JSON_GetObjectItem(Value *object,const char *string)    {Value *c=object->child; while (c && JSON_strcasecmp(c->string,string)) c=c->next; return c;}
void JSON_IterateObjectItemCallback(Value *object, void* data, peek_item_callback peekItemCallback) {
	Value *c=object->child; 
	while (c) {
		if(peekItemCallback) {
			(*peekItemCallback)(c, data);
		}
		c=c->next;
	}
}
const char* JSON_GetItemString(Value *item){
	return item->string;
}
const char* JSON_GetStringFromStringItem(Value *item){
	return item->valuestring;
}
int JSON_GetNumberFromNumberItem(Value *item){
	return item->valueint;
}
double JSON_GetDoubleFromNumberItem(Value *item) {
	return item->valuedouble;
}
int JSON_GetItemType(Value *item){
	return item->type;
}

// Utility for array list handling.
static void suffix_object(Value *prev,Value *item) {prev->next=item;item->prev=prev;}
// Utility for handling references.
static Value *create_reference(pool* p,Value *item) {Value *ref=JSON_newValueObj(p);memcpy(ref,item,sizeof(Value));ref->string=0;ref->type|=JSON_IsReference;ref->next=ref->prev=0;return ref;}

// Add item to array/object.
void JSON_AddItemToArray(pool* p,Value *array, Value *item)                                          {Value *c=array->child;if (!c) {array->child=item;} else {while (c && c->next) c=c->next; suffix_object(c,item);}}
void JSON_AddItemToObject(pool* p,Value *object,const char *string,Value *item)      {item->string=apr_pstrdup(p,string);JSON_AddItemToArray(p,object,item);}
void JSON_AddItemReferenceToArray(pool* p,Value *array, Value *item)                                                {JSON_AddItemToArray(p,array,create_reference(p,item));}
void JSON_AddItemReferenceToObject(pool* p,Value *object,const char *string,Value *item)    {JSON_AddItemToObject(p,object,string,create_reference(p,item));}

Value* JSON_DetachItemFromArray(Value *array,int which)                        {Value *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return 0;
        if (c->prev) c->prev->next=c->next;if (c->next) c->next->prev=c->prev;if (c==array->child) array->child=c->next;c->prev=c->next=0;return c;}
void   JSON_DeleteItemFromArray(Value *array,int which)                        {JSON_DetachItemFromArray(array,which);}
Value* JSON_DetachItemFromObject(Value *object,const char *string) {int i=0;Value *c=object->child;while (c && JSON_strcasecmp(c->string,string)) i++,c=c->next;if (c) return JSON_DetachItemFromArray(object,i);return 0;}
void   JSON_DeleteItemFromObject(Value *object,const char *string) {JSON_DetachItemFromObject(object,string);}

// Replace array/object items with new ones.
void   JSON_ReplaceItemInArray(Value *array,int which,Value *newitem)          {Value *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return;
        newitem->next=c->next;newitem->prev=c->prev;if (newitem->next) newitem->next->prev=newitem;
        if (c==array->child) array->child=newitem; else newitem->prev->next=newitem;c->next=c->prev=0;}
void   JSON_ReplaceItemInObject(pool* p, Value *object,const char *string,Value *newitem){int i=0;Value *c=object->child;while(c && JSON_strcasecmp(c->string,string))i++,c=c->next;if(c){newitem->string=apr_pstrdup(p,string);JSON_ReplaceItemInArray(object,i,newitem);}}

// Create basic types:
Value* JSON_CreateNull(pool* p)				{ return JSON_newValueObj(p,JSON_NULL); }
Value* JSON_CreateTrue(pool* p)             { return JSON_newValueObj(p,JSON_True); }
Value* JSON_CreateFalse(pool* p)            { return JSON_newValueObj(p,JSON_False); }
Value* JSON_CreateNumber(pool* p,
		double num)            				{ return JSON_newValueObj(p, JSON_Number,num); }
Value* JSON_CreateString(pool* p,
		const char *string)   				{ return JSON_newValueObj(p, JSON_String, string); }
Value* JSON_CreateArray(pool* p)            { return JSON_newValueObj(p,JSON_Array); }
Value* JSON_CreateObject(pool* p)           { return JSON_newValueObj(p,JSON_Object); }

// Create Arrays:
Value* JSON_CreateIntArray(pool*_pool,int *numbers,int count)				{int i;Value *n=0,*p=0,*a=JSON_CreateArray(_pool);for(i=0;i<count;i++){n=JSON_CreateNumber(_pool,numbers[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}
Value* JSON_CreateFloatArray(pool*_pool,float *numbers,int count)       	{int i;Value *n=0,*p=0,*a=JSON_CreateArray(_pool);for(i=0;i<count;i++){n=JSON_CreateNumber(_pool,numbers[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}
Value* JSON_CreateDoubleArray(pool*_pool,double *numbers,int count)     	{int i;Value *n=0,*p=0,*a=JSON_CreateArray(_pool);for(i=0;i<count;i++){n=JSON_CreateNumber(_pool,numbers[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}
Value* JSON_CreateStringArray(pool*_pool,const char **strings,int count)	{int i;Value *n=0,*p=0,*a=JSON_CreateArray(_pool);for(i=0;i<count;i++){n=JSON_CreateString(_pool,strings[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}



<|start_filename|>src/config-core/config_bindings_shm.h<|end_filename|>
#ifndef CONFIG_BINDINGS_SHM_H_
#define CONFIG_BINDINGS_SHM_H_
#include <shm_data.h>
#include <shm_apr.h>
#include <config-core/config_bindings.h>

	typedef struct cbs_service_descriptor{
		char* id;
		char* name;
		char* uri;
		char* userColonPass;
		long timeoutSeconds;
		shapr_hash_t * params;
	}cbs_service_descriptor;
		
	typedef struct cbs_globals{
		char* homeDir;
		char* logsDir;
		cbs_service_descriptor* resourceService;
		int isRefresh;
	}cbs_globals;
	
	cbs_globals* cbs_copyGlobalsOnSheap(pool*p, shared_heap* sheap, cfg_globals* globals, int isRefresh);
	char* cbs_getRemoteResourcePath(pool* p, cbs_globals* globals,char* resource,char**details);
	char* cbs_getLocalResourcePath(pool* p, cbs_globals* globals,char* resource,char**details);
#endif /*CONFIG_BINDINGS_SHM_H_*/


<|start_filename|>src/shm_core/shm_apr.h<|end_filename|>
#ifndef __TCREWRITE_SHM_APR__H_
#define __TCREWRITE_SHM_APR__H_
#include <sys/types.h>
#include <shm_data.h>

#ifdef __cplusplus
extern "C" {
#endif
	
	/**
 	* Abstract type for hash tables.
 	*/
	typedef struct shapr_hash_t shapr_hash_t;

	/**
	* Abstract type for scanning hash tables.
	*/
	typedef struct shapr_hash_index_t shapr_hash_index_t;

	array_header* shapr_array_make(shared_heap* sheap, int nelts, int elt_size);
	void * shapr_array_push(shared_heap* sheap, array_header *arr);
	array_header* shapr_parseStringArrayFromCsv(shared_heap* sheap, int arraySz, const char* delim, char* src);
	array_header* shapr_parseLongArrayFromCsv(shared_heap* sheap, int arraySz, const char* delim, char* src);
	array_header* shapr_copyStringArrayToSheap(shared_heap* sheap, array_header* sarray);
	
	shapr_hash_t* shapr_hash_make(shared_heap* sheap);
	void* shapr_hash_get(shapr_hash_t *ht,const void *key,apr_ssize_t klen);
	void shapr_hash_set(shared_heap* sheap,shapr_hash_t *ht,const void *key,apr_ssize_t klen,const void *val);
	shapr_hash_index_t * shapr_hash_first(apr_pool_t* pool, shapr_hash_t *ht);
	shapr_hash_index_t* shapr_hash_next(shapr_hash_index_t *hi);
	void shapr_hash_this(shapr_hash_index_t *hi,const void **key,apr_ssize_t *klen,void **val);
	unsigned int shapr_hash_count(shapr_hash_t *ht);
#ifdef __cplusplus
}
#endif

#endif


<|start_filename|>src/common-utils/cookie.h<|end_filename|>
#ifndef _COOKIE_H_
#define _COOKIE_H_
#ifdef __cplusplus
	extern "C" {
#endif
		
#include <sys/types.h>
#include <shm_data.h>
#include <shm_apr.h>

typedef struct Cookie {
	char*	  	name;		// Cookie
	int	      	nameLen;	// Cookie name length
	int	      	age;		// in Days
	unsigned int  	httpOnly;	// httpOnly support.
	int  		secure;			// httpOnly; Secure support.
}Cookie;

//Creater methods
Cookie* cookie_newObj(pool*p);
Cookie* cookie_createCookieByName(pool*p, char*name);
Cookie* cookie_cookieDup(pool*p, Cookie*src);

//Accessor Methods
void cookie_setCookieName(pool*p, Cookie*cookie, char*name);
char* cookie_getCookieName(Cookie*cookie) ;
void cookie_setCookieLifeTime(Cookie* cookie, int lifeTime);
int cookie_getCookieLifeTime(Cookie* cookie);
void cookie_setCookieHttpOnlyflag(Cookie* cookie, unsigned int httpOnly);
unsigned int cookie_getCookieHttpOnlyflag(Cookie* cookie);
void cookie_setCookieSecureHttpOnlyflag(Cookie* cookie, int secure);

//Cookie sheap methods
Cookie* cookie_newShmObj(shared_heap*sheap);
Cookie* cookie_cookieShmDup(shared_heap*sheap, Cookie*src);

//Cookie utility methods
int cookie_convertDaysToSeconds(int days);
char* cookie_cookieTemplate(pool* p, Cookie* cookie, char *ivalue, char *iDomain);
char* cookie_cookieTemplateByName(pool* p,char* icookiename, char *ivalue, 
		char *idomain, long maxAge, unsigned int httpOnly);
char* cookie_cookieUntemplate(pool* p,char* src);
char* cookie_getGMTDate(pool* p, int secondsInFuture);
char *cookie_getCookie(pool* p, apr_table_t* headers_in, Cookie* cookie);
char *cookie_getCookieByName(pool* p, apr_table_t* headers_in, char *cookie_name, int cookie_name_len);
void cookie_deleteCookie(pool* p, apr_table_t* err_headers_out, Cookie* cookie, char* domain);
void cookie_deleteCookieByName(pool* p, apr_table_t* err_headers_out, char* cookie_name, char* domain);
char* cookie_parseCookie(pool* p, char* name, char* cookies);

#ifdef __cplusplus
	}
#endif
#endif //_COOKIE_H_


<|start_filename|>src/doc-parser-core/doc_parser_utils.c<|end_filename|>
#include <doc_parser_utils.h>
#include "apr_lib.h"
#include "apr_strings.h"

	char* docp_getRemoteResourcePath(pool* p, char* resource,
			cbs_service_descriptor *rs,char* homeDir,char**details){
		char* ret=NULL,*reqUri;
		apr_pool_t* tp;
		char* fileName=NULL;
		if(resource==NULL) return NULL;
		
		if(rs!=NULL){
			//setup filepool
			if(apr_pool_create(&tp,p)!=APR_SUCCESS){
				if(details!=NULL){
					*details=apr_pstrdup(p,"Failure to create subpool");
				}
				return NULL;
			}		
			//load remote path.
			reqUri=apr_pstrcat(p,rs->uri,"/",resource,NULL);
			fileName=(char*)apr_filepath_name_get(resource);
			ret=cb_writeRemoteResourceToDisk(p,homeDir,reqUri,fileName,rs->timeoutSeconds,rs->userColonPass,tp,details,NULL);		
			apr_pool_destroy(tp);
		}
		return ret;
	}
	char* docp_getRemoteResourcePathEx(pool* p, char* resourceUri, char* homeDir,char**details){
		char* ret=NULL,*reqUri;
		apr_pool_t* tp;
		char* fileName=NULL;
		apr_finfo_t finfo;
		apr_status_t rv;
		char* localPath=NULL;

		if(resourceUri!=NULL){
			//setup filepool
			if(apr_pool_create(&tp,p)!=APR_SUCCESS){
				if(details!=NULL){
					*details=apr_pstrdup(p,"Failure to create subpool");
				}
				return NULL;
			}		
			//load remote path.
			fileName=(char*)apr_filepath_name_get(resourceUri);
			ret=cb_writeRemoteResourceToDisk(p, homeDir,resourceUri,fileName,20,NULL,tp,details,NULL);
			apr_pool_destroy(tp);
		}
		return ret;
	}	
	char* docp_getLocalResourcePath(pool*p,char* resource,char* homeDir){
		if(resource==NULL){return NULL;}
		return apr_pstrcat(p,homeDir,"/",apr_filepath_name_get(resource),NULL);
	}


<|start_filename|>src/doc-parser-core/doc_parser_utils.h<|end_filename|>
#ifndef DOC_PARSER_UTILS_H_
#define DOC_PARSER_UTILS_H_
#include <config-core/config_bindings_shm.h>
	char* docp_getRemoteResourcePath(pool* p, char* resource,cbs_service_descriptor *rs,char* homeDir,char**details);
	char* docp_getLocalResourcePath(pool*p,char* resource,char* homeDir);
	char* docp_getRemoteResourcePathEx(pool* p, char* resourceUri, char* homeDir,char**details);
#endif /*DOC_PARSER_UTILS_H_*/


<|start_filename|>src/config-core/config_messaging_parsing.c<|end_filename|>
#include <unistd.h>
#include <sys/time.h>
#include <string.h>
#include <stdlib.h>
#include <limits.h>
#include "xml_core.h"
#include "config_messaging_parsing.h"
#include "common_utils.h"
#include "oidc_version.h"
	
	typedef struct cfgm_parse_bundle{
		char* tmp;
		cfgm_wire_message* msg;
	}cfgm_parse_bundle;
		
		
	/**
	 * Begin Wire Message Code
	 */
	static cfgm_wire_header* cfgm_newWireHeaderBlank(pool* p){	
		cfgm_wire_header* ret=(cfgm_wire_header*)apr_palloc(p,sizeof(cfgm_wire_header));
		ret->nodeName=NULL;
		ret->componentId=NULL;
		ret->version=NULL;
		return ret;
	} 
	cfgm_wire_header* cfgm_newWireHeader(pool* p){
		int i;
		char buf[128];
		
		//for second ip get test		
		cfgm_wire_header* ret=cfgm_newWireHeaderBlank(p);
		if(gethostname(buf,128)==0){
			ret->nodeName=apr_pstrdup(p,buf);
		}
		ret->componentId=apr_pstrdup(p,MODULE_COMPONENT_ID);
		ret->version=apr_pstrdup(p,MODULE_VERSION_ID);

		return ret; 
	}
	cfgm_wire_message* cfgm_newWireMessage(pool* p,cfgm_wire_header* header){
		char buf[64];
		cfgm_wire_message* ret=(cfgm_wire_message*)apr_palloc(p,sizeof(cfgm_wire_message));
		ret->type=NULL;
		ret->header=header;
		ret->params=apr_hash_make(p);
				
		sprintf(buf,"%d",getpid());
		apr_hash_set(ret->params,"pid",APR_HASH_KEY_STRING,apr_pstrdup(p,buf));
		
		return ret;
	}
	cfgm_wire_message* cfgm_newWireMessageType(pool* p,const char* type,cfgm_wire_header* header){
		cfgm_wire_message* ret=cfgm_newWireMessage(p,header);
		ret->type=apr_pstrdup(p,type);
		return ret;
	}
	
	char* cfgm_serializeMessage(apr_pool_t* p, cfgm_wire_message* msg){
		apr_hash_index_t *hi;
		char* name=NULL,*value=NULL;
		char* ret=NULL;
		apr_pool_t* subp=NULL;
		

		if(msg==NULL) return NULL;
		if(apr_pool_create(&subp,p)!=APR_SUCCESS){
			return NULL;	
		}
		ret=apr_pstrcat(subp,"<message type=\"",msg->type,"\"",NULL);
		if(msg->header!=NULL){
			if(msg->header->nodeName!=NULL){
				ret=apr_pstrcat(subp,ret," node=\"",msg->header->nodeName,"\"",NULL);	
			}
			if(msg->header->componentId!=NULL){
				ret=apr_pstrcat(subp,ret," com=\"",msg->header->componentId,"\"",NULL);
			}
			if(msg->header->version!=NULL){
				ret=apr_pstrcat(subp,ret," ver=\"",msg->header->version,"\"",NULL);
			}
		}
		ret=apr_pstrcat(subp,ret,">\n",NULL);
		for (hi = apr_hash_first(subp, msg->params); hi; hi = apr_hash_next(hi)) {
        	apr_hash_this(hi,(const void**)&name, NULL, (void**)&value);
        	ret=apr_pstrcat(subp,ret,"\t<param name=\"",name,"\"><![CDATA[",value,"]]></param>\n",NULL);
        }
        
        //make last concat to non temporary memory pool
		ret=apr_pstrcat(p,ret,"</message>",NULL);
		//destroy temporary memeory pool
		apr_pool_destroy(subp);
		return ret;        		
	}
	


<|start_filename|>src/config-core/config_core.c<|end_filename|>
#include <unistd.h>
#include <sys/time.h>
#include <string.h>
#include <stdlib.h>
#include "config_core.h"
#include "xml_core.h"
#include "common_utils.h"
#include "oidc_globals.h"
#include "config_bindings_shm.h"
#include "oidc_version.h"
#include "logging.h"

	config_core* configcore_newConfigCoreObj(pool* p){
		config_core* ret=(config_core*)apr_palloc(p,sizeof(config_core));
		ret->globals=cb_newGlobalsObj(p);
		ret->oidcConfigFile=apr_pstrdup(p,"oidc-config.xml");
		ret->service=cb_newServiceDescriptorObj(p);
		ret->service->id=apr_pstrdup(p,"OIDC-CONFIG");
		ret->service->name=apr_pstrdup(p,"oidcConfig");
		apr_hash_set(ret->service->params,"config-xml",APR_HASH_KEY_STRING,ret->oidcConfigFile);
		ret->sheapMapFile=apr_pstrdup(p, "/configcore.shm");
		ret->sheapPageSize=64000;
		ret->sheap=NULL;
		ret->serviceConfig=NULL;
		ret->passPhrase=NULL;
		ret->disableProcessRecovery=FALSE;
		ret->oidcHeaderPrefix=apr_pstrdup(p, "X-OIDC-");
		ret->refreshWaitSeconds=0;
		ret->cipherConfig = (oidc_cipher_cfg*)apr_palloc(p, sizeof(oidc_cipher_cfg));
		ret->cipherConfig->crypto_passphrase = NULL;
		ret->cipherConfig->decrypt_ctx=NULL;
		ret->cipherConfig->encrypt_ctx=NULL;
		ret->cipherConfig->p = p;
		return ret;		
	}
	
	typedef struct cfg_bundle{
		config_core* cc;
		void* userdata, *userdata2;
	}cfg_bundle;
	
	static int cfg_setCCAttributes(pool* p,char* xPath,int type,const char ** attributes,void* userdata){
		int i;
		cfg_bundle* bundle=(cfg_bundle*)userdata;
		return 1;
	}
	static int cfg_setCCDisableProcessRecoveryBody(pool* p,char* xPath,int type,const char *body,void* userdata){
		int len;
		cfg_bundle* bundle=(cfg_bundle*)userdata;
		
		bundle->cc->disableProcessRecovery=STRTOBOOL(body);
		return 1;
	}
	static int cfg_setCCHeaderPrefixBody(pool* p,char* xPath,int type,const char *body,void* userdata){
		int len;
		cfg_bundle* bundle=(cfg_bundle*)userdata;
		
		bundle->cc->oidcHeaderPrefix=apr_pstrdup(p, body);
		return 1;
	}
	static int cfg_setCCRefreshWaitSecondsBody(pool* p,char* xPath,int type,const char *body,void* userdata){
		int len;
		cfg_bundle* bundle=(cfg_bundle*)userdata;
		if(body!=NULL) {
			bundle->cc->refreshWaitSeconds=atol(body);
		}
		return 1;
	}	
	static int cfg_setCCPassPhraseBody(pool* p,char* xPath,int type,const char *body,void* userdata){
		int len;
		cfg_bundle* bundle=(cfg_bundle*)userdata;
		
		bundle->cc->passPhrase=apr_pstrdup(p,body);
		if(bundle->cc->passPhrase) {
			bundle->cc->cipherConfig->crypto_passphrase=apr_pstrdup(p,body);
		}
		return 1;
	}
	static int cfg_setCCOIDCConfigFileBody(pool* p,char* xPath,int type,const char *body,void* userdata){
		int len;
		cfg_bundle* bundle=(cfg_bundle*)userdata;

		bundle->cc->oidcConfigFile=apr_pstrdup(p,body);
		if(bundle->cc->oidcConfigFile!=NULL){
			apr_hash_set(bundle->cc->service->params,"config-xml",APR_HASH_KEY_STRING,bundle->cc->oidcConfigFile);
		}
		return 1;
	}
	static int cfg_setCCSheapMapFileBody(pool* p,char* xPath,int type,const char *body,void* userdata){
		cfg_bundle* bundle=(cfg_bundle*)userdata;
		bundle->cc->sheapMapFile=apr_pstrdup(p,body);
		return 1;
	}
	static int cfg_setCCSheapPageSizeBody(pool* p,char* xPath,int type,const char *body,void* userdata){
		cfg_bundle* bundle=(cfg_bundle*)userdata;
		bundle->cc->sheapPageSize=atoi(body);
		return 1;
	}
	
	static int cfg_setResourceServiceAttributes(pool* p,char* xPath,int type,const char ** attributes,void* userdata){
		int i;
		cfg_bundle* bundle=(cfg_bundle*)userdata;
		cfg_service_descriptor* svc=NULL;
		
		svc=bundle->cc->globals->resourceService=cb_newServiceDescriptorObj(p);
		svc->id=apr_pstrdup(p,"RESOURCE_SERVICE");
		svc->name=apr_pstrdup(p,"RESOURCE_SERVICE");
  		return 1;
	}
	static int cfg_setResourceServiceUriBody(pool* p,char* xPath,int type,const char *body,void* userdata){
		cfg_bundle* bundle=(cfg_bundle*)userdata;
		cfg_service_descriptor* svc=bundle->cc->globals->resourceService;
		if(svc!=NULL){
			svc->uri=apr_pstrdup(p,body);
		}
		return 1;
	}
	static int cfg_setResourceServiceParamAttributes(pool* p,char* xPath,int type,const char ** attributes,void* userdata){
		int i;
		cfg_bundle* bundle=(cfg_bundle*)userdata;
		bundle->userdata2=NULL;
		for (i = 0; attributes[i]; i += 2) {
			if(strcmp(attributes[i],"name")==0){
				bundle->userdata2=(void*)apr_pstrdup(p,attributes[i + 1]);
			} 		
  		}
		return 1;
	}
	static int cfg_setResourceServiceTimeoutBody(pool* p,char* xPath,int type,const char *body,void* userdata){
		cfg_bundle* bundle=(cfg_bundle*)userdata;
		cfg_service_descriptor* svc=bundle->cc->globals->resourceService;
		if(svc!=NULL){
			svc->timeoutSeconds=atol(body);
		}
		return 1;
	}
	static int cfg_setResourceServiceUserColonPassBody(pool* p,char* xPath,int type,const char *body,void* userdata){
		cfg_bundle* bundle=(cfg_bundle*)userdata;
		cfg_service_descriptor* svc=bundle->cc->globals->resourceService;
		if(svc!=NULL){
			svc->userColonPass=apr_pstrdup(p,body);
		}
		return 1;
	}

	char* configcore_loadConfigCoreFile(pool* p, char* file, config_core* conf){
		char* result=NULL;
		XmlCore* xCore;
		
		cfg_bundle* bundle=(cfg_bundle*)apr_palloc(p,sizeof(cfg_bundle));
		bundle->userdata=NULL;
		bundle->userdata2=NULL;
		bundle->cc=conf;
		
		xCore=xc_getXmlCore(p);
		xc_addXPathHandler(xCore,"/config-core",0,cfg_setCCAttributes,NULL,NULL, bundle);
		xc_addXPathHandler(xCore,"/config-core/sheapMapFile",0,NULL,cfg_setCCSheapMapFileBody,NULL, bundle);
		xc_addXPathHandler(xCore,"/config-core/sheapPageSize",0,NULL,cfg_setCCSheapPageSizeBody,NULL, bundle);
		xc_addXPathHandler(xCore,"/config-core/disableProcessRecovery",0,NULL,cfg_setCCDisableProcessRecoveryBody,NULL, bundle);
		xc_addXPathHandler(xCore,"/config-core/oidcHeaderPrefix",0,NULL,cfg_setCCHeaderPrefixBody,NULL, bundle);
		xc_addXPathHandler(xCore,"/config-core/refreshWaitSeconds",0,NULL,cfg_setCCRefreshWaitSecondsBody,NULL, bundle);
		xc_addXPathHandler(xCore,"/config-core/passPhrase",0,NULL,cfg_setCCPassPhraseBody,NULL, bundle);
		xc_addXPathHandler(xCore,"/config-core/oidcConfigFile",0,NULL,cfg_setCCOIDCConfigFileBody,NULL, bundle);
		
		xc_addXPathHandler(xCore,"/config-core/resourceService",0,cfg_setResourceServiceAttributes,NULL,NULL, bundle);
		xc_addXPathHandler(xCore,"/config-core/resourceService/uri",0,NULL,cfg_setResourceServiceUriBody,NULL, bundle);
		xc_addXPathHandler(xCore,"/config-core/resourceService/timeoutSeconds",0,NULL,cfg_setResourceServiceTimeoutBody,NULL, bundle);
		xc_addXPathHandler(xCore,"/config-core/resourceService/userColonPass",0,NULL,cfg_setResourceServiceUserColonPassBody,NULL, bundle);
		xc_addXPathHandler(xCore,"/config-core/resourceService/param",0,cfg_setResourceServiceParamAttributes,cfg_setResourceServiceTimeoutBody,NULL, bundle);
		
		result=xc_beginParsingTextResponse(xCore,file);
		
		
		return result;	
	}
	
	static int cfg_onSheapPageFlip(pool* p, shared_heap* sheap, void* userdata){
		config_core* configCore=(config_core*)userdata;
		int i=0;
		cfg_service_descriptor* svc=NULL;
		char* error=NULL;
		void* moduleConfig=NULL;

		svc=configCore->service;
		error=amc_postRefresh(p,configCore->sheap,configCore->globals,svc,&moduleConfig);
		if(error==NULL){
			//set as post initialized
			if(moduleConfig!=NULL){
				if(svc->name!=NULL){
					configCore->serviceConfig = moduleConfig;
				}
			}
		}
		return 1;
	}
	int cfg_syncSelf(apr_pool_t* pool,config_core* configCore){
		int ret=0;
		if(configCore!=NULL&&(ret=shdata_syncself(pool,configCore->sheap,cfg_onSheapPageFlip,configCore))==2){
			return 1;	
		}
		return 0;
	}
	
	static void* cfg_initMessaging(pool* p, void* userdata){
		config_core* configCore=(config_core*)userdata;
		return (void*)NULL;
	}
	
	static char* cfg_refreshConfigCore(pool* p,config_core* conf){
		int i;
		cfg_service_descriptor* svc=NULL;
		void* moduleConfig=NULL;
		char* error=NULL;
//		alerts_core* alertsCore=NULL;
//		diagnostics_core* diagCore=NULL;	
		cbs_globals* cbshmGlobals=NULL;
		char cbuf[APR_CTIME_LEN + 1];
		long timeTakenMillis;
		
		lc_openLogFile(p,conf->refreshLogFile);
		lc_rotateLogFile();
		
		apr_time_t t1 = apr_time_now();
		apr_ctime(cbuf, t1);
		lc_printLog("\n\t Refreshing config [%s]\n", cbuf); fflush(stdout);
		
		if(conf->service!=NULL){
			
			shdata_BeginTagging(conf->sheap);
			
			//duplicate cfg_globals and globals on sheap
			cbshmGlobals=cbs_copyGlobalsOnSheap(p,conf->sheap,conf->globals,TRUE);		

			svc=conf->service;
			error=amc_refresh(p,conf->sheap,cbshmGlobals,svc,&moduleConfig);
			if(error!=NULL){
				return apr_pstrcat(p,"[",svc->id,"] Service failed to refresh: ",error,NULL);
			}else{
				//set as initialized
				if(moduleConfig!=NULL){
					if(svc->name!=NULL){
						conf->serviceConfig  = moduleConfig;
					}
				}
			}
			//publish bash segment
			if(error==NULL){
				shdata_PublishBackSeg(conf->sheap);
				cfg_syncSelf(p,conf);
			}
		}
		timeTakenMillis = ((apr_time_now() - t1) / 1000);
		lc_printLog("\n\t Refresh complete [time taken : %d milliseconds]\n", timeTakenMillis); fflush(stdout);
		lc_closeLogFile();
		return error;	
	}
	
	static char* cfg_handleMessageRecieved(pool* p, cfgm_connection* cmConn,cfgm_wire_message* msg,void* localConfig, void* userdata){
		char* result=NULL;
		config_core* configCore=(config_core*)userdata;

		//now we can do out actions that we would like to do...like refresh the config core:)
		if(cfgm_isRefreshMessage(msg)){
			result=cfg_refreshConfigCore(p,configCore);
			if(result==NULL){
				lc_printLog("Refresh succeded\n"); fflush(stdout);
			}else{
				lc_printLog("Refresh failed:%s\n", result); fflush(stdout);
			}
		}
		return NULL;
	}
		
	char* configcore_initializeConfigCore(pool* p,config_core* conf){
		int i=0;
		cfg_service_descriptor* svc=NULL;
		char* error=NULL;
		char* sheapfile=apr_pstrcat(p,conf->globals->homeDir,conf->sheapMapFile,NULL);
		void* moduleConfig=NULL;
		char* errorRet=NULL;
		cbs_globals* cbshmGlobals=NULL;
		char buf[100];
		apr_status_t status=0;

		lc_printLog("Initializing Config Core \n\r");
		lc_printLog("\tSetup filesystem");
		cb_initGlobals(p,conf->globals);
		
		
		lc_printLog("\tSheapFile:\t%s\n",sheapfile);
		lc_printLog("\tSheapPageSize:\t%d\n",conf->sheapPageSize);
		conf->sheap=shdata_sheap_make(p, conf->sheapPageSize,sheapfile);
		if(conf->sheap==NULL){
			return apr_pstrdup(p,"Could not create Config Core shared heap");	
		}
		shdata_BeginTagging(conf->sheap);
			
		//duplicate cfg_globals on sheap and merge global options. 
		cbshmGlobals=cbs_copyGlobalsOnSheap(p,conf->sheap,conf->globals,FALSE);

		if(conf->service!=NULL){
			lc_printLog("\tService Init-\n");

			svc=conf->service;
			if(svc->name!=NULL){
				lc_printLog("\t\t%s [%s] Initializing...\n",svc->id, SAFESTRBLANK(svc->name));
			}else{
				lc_printLog("\t\t%s Initializing...\n",svc->id);
			}
			fflush(stdout);
			error=amc_initialize(p,conf->sheap,cbshmGlobals,svc,&moduleConfig);
			if(error!=NULL){
				if(errorRet==NULL){
					errorRet=apr_pstrdup(p,"�");
				}else{
					errorRet=apr_pstrcat(p,errorRet,"\r\n�",NULL);
				}
				errorRet=apr_pstrcat(p,errorRet,"[",svc->id,"] Service failed to initialize: ",error,NULL);
			}else{
				//set as initialized
				if(moduleConfig!=NULL){
					//set config by name
					if(svc->name!=NULL){
						conf->serviceConfig = moduleConfig;
					}
				}
			}
			fflush(stdout);

			//publish bash segment
			lc_printLog("\tPublishing Config Core Sheap...");
			fflush(stdout);
			shdata_PublishBackSeg(conf->sheap);
			lc_printLog("OK\r\n");
			cfg_syncSelf(p,conf);
			
			if(conf->refreshWaitSeconds>0) {

				lc_printLog("\tStarting Config Core Realm Process:\n");
				lc_closeLogFile();//closing before forking
				cfgm_initializeMessagingLoop(p, conf->globals->logsDir,NULL, conf,
						cfg_initMessaging,cfg_handleMessageRecieved,
						conf->disableProcessRecovery);
				lc_openLogFile(p,conf->refreshLogFile);
			}
			
			
		}
		return errorRet;
	}
	
	static void cfg_printServiceDescriptor(pool* p, cfg_service_descriptor*svc){
		apr_hash_index_t *hi;
		char *name,*val;
		if(svc!=NULL){
			if(svc->name!=NULL){
				lc_printLog("\t�\t%s [%s]\n",svc->id,svc->name);	
			}else{
				lc_printLog("\t�\t%s\n",svc->id);
			}
			lc_printLog("\t\tUri:\t%s\n",svc->uri);
			lc_printLog("\t\tTimeoutSeconds:\t%d\n",svc->timeoutSeconds);
			for (hi = apr_hash_first(p, svc->params); hi; hi = apr_hash_next(hi)) {
				apr_hash_this(hi,(const void**)&name, NULL, (void**)&val);
				lc_printLog("\t\t%s:\t%s\n",name,val);
			}
			lc_printLog("\r\n");
		}else{
			lc_printLog("!!! SERVICE IS NULL\n");	
		}
	}
	void configcore_printConfigCoreDetails(pool* p,config_core* conf){
//		apr_hash_index_t *hi;
		cfg_service_descriptor* svc=NULL;
//		char *name,*val;
		int i=0;
		if(conf==NULL){
			lc_printLog("Config-Core: NULL!!\n");
			return;
		}
		lc_printLog("Config-Core:\n");
		lc_printLog("�\tGlobals-\n");
		lc_printLog("\t\tHomeDir:%s\n",conf->globals->homeDir);
		lc_printLog("\t\tOIDCHeaderPrefix:%s\n",conf->oidcHeaderPrefix);
		lc_printLog("\t\tEnableUnnamedSHM:%d\n",djrglobals_isUnnamedSHMEnabled());
		lc_printLog("\t\tConfigCheckPhaseDelaySec:%d\n",djrglobals_getConfigCheckPhaseDelaySec());
		
		lc_printLog("�\tSystem Services-\n");
		
		if(conf->globals->resourceService!=NULL){
			cfg_printServiceDescriptor(p,conf->globals->resourceService);
		}else{
			lc_printLog("�\tResourceService: NOT ACTIVATED\n");	
		}
		
		lc_printLog("\t\tSheapMapFile:%s\n",conf->sheapMapFile);
		lc_printLog("\t\tSheapPageSize:%d\n",conf->sheapPageSize);
		lc_printLog("\t\tPassPhrase:%s\n",conf->passPhrase);
		if(conf->service!=NULL){
			lc_printLog("�\tServices-\n");		
			svc=conf->service;
			cfg_printServiceDescriptor(p,svc);
		}
		
	}
	
	void* configcore_getModuleConfigByName(config_core* conf,char* name){
		return conf->serviceConfig;
	}

