/*
 *  LuaXHttpRequest.c
 *
 *  Requirements: PCRE and the Lua core processing engine
 *
 *  Created by Philippe Hausler on 10/11/08.
 *  Copyright 2008 Philippe Hausler. All rights reserved.
 *
 */
#warning You must change the limits specified for the LuaXHttpRequest additions!
#define DOMAIN_LIMIT1 "test.com"
#define DOMAIN_LIMIT2 "mysecondtest.com"
#define DOMAIN_LIMIT3 "anothertest.com"

#include "LuaXHttpRequest.h"
typedef struct XHttpRequest {
	const char *method;
	const char *url;
	CURL *curl;
} XHttpRequest;
typedef struct xhr_memblock {
	char *memory;
	size_t size;
} xhr_memblock;
extern int lua_xhttprequest_new(lua_State *L);
extern int lua_xhttprequest_open(lua_State *L);
extern int lua_xhttprequest_send(lua_State *L);
extern int lua_xhttprequest_abort(lua_State *L);
static void *xhr_realloc(void *ptr, size_t size);
int xhr_url_in_domain(const char *url, const char *domain);

static void *xhr_realloc(void *ptr, size_t size)
{
	if(ptr)
		return realloc(ptr, size);
	else
		return malloc(size);
}
static size_t xhr_write_memory_callback(void *ptr, size_t size, size_t nmemb, void *data)
{
	size_t realsize = size * nmemb;
	xhr_memblock *mem = (xhr_memblock *)data;
	mem->memory = xhr_realloc(mem->memory, mem->size + realsize + 1);
	if (mem->memory) {
		memcpy(&(mem->memory[mem->size]), ptr, realsize);
		mem->size += realsize;
		mem->memory[mem->size] = 0;
	}
	return realsize;
}
extern int lua_xhttprequest_new(lua_State *L) {
	size_t nbytes = sizeof(XHttpRequest);
	//create a new userdata structure to store the curl object and associated data
	XHttpRequest *a = (XHttpRequest *)lua_newuserdata(L, nbytes);
	
	return 1;
}

extern int lua_xhttprequest_open(lua_State *L) {
	XHttpRequest *a = (XHttpRequest *)lua_touserdata(L, 1);
	size_t l1, l2;
	//initialize the user data object that will store the url, method and the curl object
    a->method = luaL_checklstring(L, 2, &l1);
    a->url = luaL_checklstring(L, 3, &l2);
	curl_global_init(CURL_GLOBAL_ALL);
	a->curl = curl_easy_init();
	return 0;
}

extern int lua_xhttprequest_send(lua_State *L) {
	XHttpRequest *a = (XHttpRequest *)lua_touserdata(L, 1);
	if(a->curl && (xhr_url_in_domain(a->url, DOMAIN_LIMIT1) || xhr_url_in_domain(a->url, DOMAIN_LIMIT2) ||  xhr_url_in_domain(a->url, DOMAIN_LIMIT2)))
	{
		xhr_memblock chunk;
		chunk.memory = NULL;
		chunk.size = 0;
		
		curl_easy_setopt(a->curl, CURLOPT_URL, a->url);
		curl_easy_setopt(a->curl, CURLOPT_WRITEFUNCTION, xhr_write_memory_callback);
		curl_easy_setopt(a->curl, CURLOPT_WRITEDATA, (void *)&chunk);
		curl_easy_perform(a->curl);
		curl_easy_cleanup(a->curl);
		lua_pushstring(L, chunk.memory);
		if(chunk.memory)
			free(chunk.memory);
		curl_global_cleanup();
	}
    return 1;
}
int xhr_url_in_domain(const char *url, const char *domain)
{
	int retval = 0;
	pcre *re;
	const char *err;
	int erro;
	int urlmatches[9];
	int rc;
	char *urlregex = "(http[s]?://)([a-zA-Z0-1\\.\\-_]+)/(.*)"; //make sure this is a properly formatted http or https url, it must contain a protocol type, a host and potentially a path
	re = pcre_compile(urlregex, 0, &err, &erro, NULL);
	if(!re) //for some reason PCRE failed to compile, please auto deny
	{
		return 0;
	}
	rc = pcre_exec(re, NULL,  url, strlen(url), 0, 0, urlmatches, 9);
	char host[1024];
	strncpy(host, &url[urlmatches[4]], urlmatches[5]-urlmatches[4]); //select the slice of the url that contains the host
	host[urlmatches[5]-urlmatches[4]] = 0x00; //ammend the host with a null byte to ensure proper length checking
	if(rc == 0) //the regex passed without error
	{
		int domainmatches[3];
		pcre *domainre;
		char *domainregex;
		sprintf(domainregex, "(%s)$", domain); //regex to match hosts ending in the specified domain limiter
		domainre = pcre_compile(domainregex, 0, &err, &erro, NULL);
		rc = pcre_exec(domainre, NULL,  host, strlen(host), 0, 0, domainmatches, 3);
		if(rc == 0) //the regex was matched so it must be a trusted domain/subdomain
		{
			retval = 1;
		}
	}
	return retval;
}


const luaL_reg lua_xhttprequest_functions[]={
	{"new", lua_xhttprequest_new},
	{"open", lua_xhttprequest_open},
	{"send", lua_xhttprequest_send},
	{NULL,NULL},
};


void lua_xhttprequest_init(lua_State* L)
{
	luaL_openlib(L, "XHttpRequest", lua_xhttprequest_functions, 0);
}
