Beispiel #1
0
/**
 * @short Removes the allocated data
 * @memberof onion_t
 */
void onion_free(onion *onion){
	ONION_DEBUG("Onion free");
	
	if (onion->flags&O_LISTENING)
		onion_listen_stop(onion);
	
	if (onion->poller)
		onion_poller_free(onion->poller);
	
	if (onion->username)
		onion_low_free(onion->username);
	
	if (onion->listen_points){
		onion_listen_point **p=onion->listen_points;
		while(*p!=NULL){
			ONION_DEBUG("Free %p listen_point", *p);
			onion_listen_point_free(*p++);
		}
		onion_low_free(onion->listen_points);
	}
	if (onion->root_handler)
		onion_handler_free(onion->root_handler);
	if (onion->internal_error_handler)
		onion_handler_free(onion->internal_error_handler);
	onion_mime_set(NULL);
	if (onion->sessions)
		onion_sessions_free(onion->sessions);
	
#ifdef HAVE_PTHREADS
	if (onion->threads)
		onion_low_free(onion->threads);
#endif
	onion_low_free(onion);
}
Beispiel #2
0
/**
 * @short Helps to prepare each pair.
 */
static void onion_dict_json_preorder(onion_block *block, const char *key, const void *value, int flags){
	if (!onion_block_size(block)) // Error somewhere.
		return;
	char *s;
	s=onion_c_quote_new(key);
	if (s==NULL){
		onion_block_clear(block);
		return;
	}
	onion_block_add_str(block, s);
	onion_low_free(s);
	onion_block_add_char(block, ':');
	if (flags&OD_DICT){
		onion_block *tmp;
		tmp=onion_dict_to_json((onion_dict*)value);
		if (!tmp){
			onion_block_clear(block);
			return;
		}
		onion_block_add_block(block, tmp);
		onion_block_free(tmp);
	}
	else{
		s=onion_c_quote_new(value);
		if (s==NULL){
			onion_block_clear(block);
			return;
		}
		onion_block_add_str(block, s);
		onion_low_free(s);
	}
	onion_block_add_data(block, ", ",2);
}
Beispiel #3
0
/**
 * @short Frees the parser data.
 */
void onion_request_parser_data_free(void *t){
	ONION_DEBUG0("Free parser data");
	onion_token *token=t;
	if (token->extra){
		onion_low_free(token->extra);
		token->extra=NULL;
	}
	onion_low_free(token);
}
Beispiel #4
0
/**
 * @short Cleans a request object to reuse it.
 * @memberof onion_request_t
 */
void onion_request_clean(onion_request* req) {
    ONION_DEBUG0("Clean request %p", req);
    onion_dict_free(req->headers);
    req->headers=onion_dict_new();
    onion_dict_set_flags(req->headers, OD_ICASE);
    req->flags&=OR_NO_KEEP_ALIVE; // I keep keep alive.
    if (req->parser_data) {
        onion_request_parser_data_free(req->parser_data);
        req->parser_data=NULL;
    }
    if (req->fullpath) {
        onion_low_free(req->fullpath);
        req->path=req->fullpath=NULL;
    }
    if (req->GET) {
        onion_dict_free(req->GET);
        req->GET=NULL;
    }
    if (req->POST) {
        onion_dict_free(req->POST);
        req->POST=NULL;
    }
    if (req->FILES) {
        onion_dict_preorder(req->FILES, unlink_files, NULL);
        onion_dict_free(req->FILES);
        req->FILES=NULL;
    }
    if (req->session_id) {
        if (onion_dict_count(req->session)==0) {
            onion_request_session_free(req);
        }
        else {
            onion_sessions_save(req->connection.listen_point->server->sessions, req->session_id, req->session);
            onion_dict_free(req->session); // Not really remove, just dereference
            req->session=NULL;
            onion_low_free(req->session_id);
            req->session_id=NULL;
        }
    }
    if (req->data) {
        onion_block_free(req->data);
        req->data=NULL;
    }
    if (req->connection.cli_info) {
        onion_low_free(req->connection.cli_info);
        req->connection.cli_info=NULL;
    }
    if (req->cookies) {
        onion_dict_free(req->cookies);
        req->cookies=NULL;
    }
    if (req->free_list) {
        onion_ptr_list_foreach(req->free_list, onion_low_free);
        onion_ptr_list_free(req->free_list);
        req->free_list=NULL;
    }
}
Beispiel #5
0
/**
 * @short Free and closes the listen point
 * @memberof onion_listen_point_t
 * 
 * Calls the custom listen_stop mathod, and frees all common structures.
 * 
 * @param op the listen point
 */
void onion_listen_point_free(onion_listen_point *op){
	ONION_DEBUG("Free listen point %d", op->listenfd);
	onion_listen_point_listen_stop(op);
	if (op->free_user_data)
		op->free_user_data(op);
	if (op->hostname)
		onion_low_free(op->hostname);
	if (op->port)
		onion_low_free(op->port);
	onion_low_free(op);
}
Beispiel #6
0
/**
 * @short Removes the allocated data
 * @memberof onion_t
 */
void onion_free(onion *onion){
	ONION_DEBUG("Onion free");

	if (onion->flags&O_LISTENING)
		onion_listen_stop(onion);

	if (onion->poller)
		onion_poller_free(onion->poller);

	if (onion->username)
		onion_low_free(onion->username);

	if (onion->listen_points){
		onion_listen_point **p=onion->listen_points;
		while(*p!=NULL){
			ONION_DEBUG("Free %p listen_point", *p);
			onion_listen_point_free(*p++);
		}
		onion_low_free(onion->listen_points);
	}
	if (onion->root_handler)
		onion_handler_free(onion->root_handler);
	if (onion->internal_error_handler)
		onion_handler_free(onion->internal_error_handler);
	onion_mime_set(NULL);
	if (onion->sessions)
		onion_sessions_free(onion->sessions);

	{
#ifdef HAVE_PTHREADS
	  pthread_mutex_lock (&onion->mutex);
#endif
	  void* data = onion->client_data;
	  onion->client_data = NULL;
	  if (data && onion->client_data_free)
	     onion->client_data_free (data);
	  onion->client_data_free = NULL;
#ifdef HAVE_PTHREADS
	  pthread_mutex_unlock (&onion->mutex);
	  pthread_mutex_destroy (&onion->mutex);
#endif
	};
#ifdef HAVE_PTHREADS
	if (onion->threads)
		onion_low_free(onion->threads);
#endif
	if (!(onion->flags&O_NO_SIGTERM)){
		signal(SIGINT,SIG_DFL);
		signal(SIGTERM,SIG_DFL);
	}
	last_onion=NULL;
	onion_low_free(onion);
}
Beispiel #7
0
/// Frees the memory, if necesary of key and value
static void onion_dict_node_data_free(onion_dict_node_data *data){
	if (data->flags&OD_FREE_KEY){
		onion_low_free((char*)data->key);
	}
	if (data->flags&OD_FREE_VALUE){
		if (data->flags&OD_DICT){
			onion_dict_free((onion_dict*)data->value);
		}
		else
			onion_low_free((char*)data->value);
	}
}
Beispiel #8
0
static void onion_sessions_redis_free(onion_sessions *sessions)
{
    ONION_DEBUG0("Free onion sessions redis");
    onion_session_redis *p = sessions->data;

#ifdef HAVE_PTHREADS
    pthread_mutex_destroy(&p->mutex);
#endif

    redisFree(p->context);
    onion_low_free(sessions->data);
    onion_low_free(sessions);
}
Beispiel #9
0
static void onion_sessions_sqlite3_free(onion_sessions *sessions)
{
	ONION_DEBUG0("Free onion sessions sqlite3");
	onion_session_sqlite3 *p=sessions->data;

#ifdef HAVE_PTHREADS
	pthread_mutex_destroy(&p->mutex);
#endif
	sqlite3_finalize(p->save);
	sqlite3_finalize(p->get);
	sqlite3_close(p->db);
	onion_low_free(sessions->data);

	onion_low_free(sessions);
}
Beispiel #10
0
/**
 * @short Returns a poller object that helps polling on sockets and files
 * @memberof onion_poller_t
 *
 * This poller is implemented through epoll, but other implementations are possible
 *
 */
onion_poller *onion_poller_new(int n){
	onion_poller *p=onion_low_malloc(sizeof(onion_poller));
	p->fd=epoll_create1(EPOLL_CLOEXEC);
	if (p->fd < 0){
		ONION_ERROR("Error creating the poller. %s", strerror(errno));
		onion_low_free(p);
		return NULL;
	}
	p->eventfd=eventfd(0,EFD_CLOEXEC | EFD_NONBLOCK);
#if EFD_CLOEXEC == 0
  fcntl(p->eventfd,F_SETFD,FD_CLOEXEC);
#endif
	p->head=NULL;
	p->n=0;
  p->stop=0;

#ifdef HAVE_PTHREADS
  ONION_DEBUG("Init thread stuff for poll. Eventfd at %d", p->eventfd);
  p->npollers=0;
  pthread_mutexattr_t attr;
  pthread_mutexattr_init(&attr);
  pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
  pthread_mutex_init(&p->mutex, &attr);
  pthread_mutexattr_destroy(&attr);
#endif

  onion_poller_slot *ev=onion_poller_slot_new(p->eventfd,onion_poller_stop_helper,p);
  onion_poller_add(p,ev);

	return p;
}
Beispiel #11
0
/**
 * @short Reads from the data to fulfill content-length data.
 * 
 * All data is writen a temporal file, which will be removed later.
 */
static onion_connection_status parse_PUT(onion_request *req, onion_buffer *data){
	onion_token *token=req->parser_data;
	int length=data->size-data->pos;
	int exit=0;
	
	if (length>=token->extra_size-token->pos){
		exit=1;
		length=token->extra_size-token->pos;
	}

	//ONION_DEBUG0("Writing %d. %d / %d bytes", length, token->pos+length, token->extra_size);

	int *fd=(int*)token->extra;
	ssize_t w=write(*fd, &data->data[data->pos], length);
	if (w<0){
		ONION_ERROR("Could not write all data to temporal file.");
		return OCS_INTERNAL_ERROR;
	}
	data->pos+=length;
	token->pos+=length;

#if __DEBUG__
	const char *filename=onion_block_data(req->data);
	ONION_DEBUG0("Done with PUT. Created %s (%d bytes)", filename, token->pos);
#endif
	
	if (exit){
		close (*fd);
		onion_low_free(token->extra);
		token->extra=NULL; 
		return onion_request_process(req);
	}
	
	return OCS_NEED_MORE_DATA;
}
Beispiel #12
0
/// Deinits static data at onion_poller.
static void onion_poller_static_deinit(){
	int16_t nextcount = __sync_sub_and_fetch(&onion_poller_static.refcount, 1);
	if (nextcount!=0)
		return;

	onion_low_free(onion_poller_static.slots);
}
Beispiel #13
0
/**
 * @short Tryes to handle the petition with that handler.
 * @memberof onion_handler_t
 *
 * It needs the handler to handle, the request and the response.
 *
 * It checks this parser, and siblings.
 * 
 * @returns If can not, returns OCS_NOT_PROCESSED (0), else the onion_connection_status. (normally OCS_PROCESSED)
 */
onion_connection_status onion_handler_handle(onion_handler *handler, onion_request *request, onion_response *response){
	onion_connection_status res;
	while (handler){
		if (handler->handler){
#ifdef __DEBUG0__
			char **bs=backtrace_symbols((void * const *)&handler->handler, 1);
			ONION_DEBUG0("Calling handler: %s",bs[0]);
			/* backtrace_symbols is explicitly documented
			   to malloc. We need to call the system free
			   routine, not our onion_low_free ! */
			onion_low_free(bs); /* Can't be onion_low_free.... */
#endif
			res=handler->handler(handler->priv_data, request, response);
			ONION_DEBUG0("Result: %d",res);
			if (res){
				// write pending data.
				if (!(response->flags&OR_HEADER_SENT) && response->buffer_pos<sizeof(response->buffer))
					onion_response_set_length(response, response->buffer_pos);
				onion_response_flush(response);
				if (res==OCS_WEBSOCKET){
					if (request->websocket)
						return onion_websocket_call(request->websocket);
					else{
						ONION_ERROR("Handler did set the OCS_WEBSOCKET, but did not initialize the websocket on this request.");
						return OCS_INTERNAL_ERROR;
					}
				}
				return res;
			}
		}
		handler=handler->next;
	}
	return OCS_NOT_PROCESSED;
}
Beispiel #14
0
/**
 * @short Creates the onion structure to fill with the server data, and later do the onion_listen()
 * @memberof onion_t
 * 
 * Creates an onion structure that can be used to set the server, port, SSL and similar parameters. It works over 
 * the onion structure, which is the main structure to control the listening of new connections throught TCP/IP.
 * 
 * A normal usage would be like this:
 * 
 * @code
 * 
 * onion *o=onion_new(O_THREADED);
 * onion_set_root_handler(o, onion_handler_directory("."));
 * onion_listen(o);
 * 
 * @endcode
 * 
 * @param flags Or'ed flags to use at the listening daemon. Normally one of O_ONE, O_ONE_LOOP or O_THREADED.
 * 
 * @returns The onion structure.
 * 
 * @see onion_mode_e onion_t
 */
onion *onion_new(int flags){
	ONION_DEBUG0("Some internal sizes: onion size: %d, request size %d, response size %d",sizeof(onion),sizeof(onion_request),sizeof(onion_response));
	if(SOCK_CLOEXEC == 0){
		ONION_WARNING("There is no support for SOCK_CLOEXEC compiled in libonion. This may be a SECURITY PROBLEM as connections may leak into executed programs.");
	}
	
	if (!(flags&O_NO_SIGPIPE)){
		ONION_DEBUG("Ignoring SIGPIPE");
		signal(SIGPIPE, SIG_IGN);
	}
	

	onion *o=onion_low_calloc(1,sizeof(onion));
	if (!o){
		return NULL;
	}
	o->flags=(flags&0x0FF)|O_SSL_AVAILABLE;
	o->timeout=5000; // 5 seconds of timeout, default.
	o->poller=onion_poller_new(15);
	if (!o->poller){
		onion_low_free(o);
		return NULL;
	}
	o->sessions=onion_sessions_new();
	o->internal_error_handler=onion_handler_new((onion_handler_handler)onion_default_error, NULL, NULL);
	o->max_post_size=1024*1024; // 1MB
	o->max_file_size=1024*1024*1024; // 1GB
#ifdef HAVE_PTHREADS
	o->flags|=O_THREADS_AVALIABLE;
	o->nthreads=8;
	if (o->flags&O_THREADED)
		o->flags|=O_THREADS_ENABLED;
#endif
	return o;
}
Beispiel #15
0
/**
 * @short Writes some data to the response. Using sprintf format strings. va_list args version
 *
 * @param args va_list of arguments
 * @memberof onion_response_t
 */
ssize_t onion_response_vprintf(onion_response *res, const char *fmt, va_list args)
{
	char temp[512];
	int l;
	l=vsnprintf(temp, sizeof(temp), fmt, args);
	if (l<0) {
		ONION_ERROR("Invalid vprintf fmt");
		return -1;
	}
	else if (l<sizeof(temp)) {
		return onion_response_write(res, temp, l);
	}
	else {
		ssize_t s;
		char*buf = onion_low_scalar_malloc(l+1);
		if (!buf){
		  // this cannot happen, since onion_low_scalar_malloc
		  // handles that error...
			ONION_ERROR("Could not reserve %d bytes", l+1);
			return -1;
		}
		vsnprintf(buf, l, fmt, args);
		s = onion_response_write (res, buf, l);
		onion_low_free (buf);
		return s;
	}
}
Beispiel #16
0
/// @memberof onion_poller_t
void onion_poller_free(onion_poller *p){
	ONION_DEBUG("Free onion poller: %d waiting", p->n);
	p->stop=1;
	close(p->fd);
	// Wait until all pollers exit.

	if (pthread_mutex_trylock(&p->mutex)>0){
		ONION_WARNING("When cleaning the poller object, some poller is still active; not freeing memory");
	}
	else{
		onion_poller_slot *next=p->head;
		while (next){
			onion_poller_slot *tnext=next->next;
			if (next->shutdown)
				next->shutdown(next->shutdown_data);
			next=tnext;
		}
		pthread_mutex_unlock(&p->mutex);

		if (p->eventfd>=0)
			close(p->eventfd);
		if (p->timerfd>=0)
			close(p->timerfd);

		onion_poller_static_deinit();

		onion_low_free(p);
	}
	ONION_DEBUG0("Done");
}
Beispiel #17
0
/**
 * @short AA tree insert
 *
 * Returns the root node of the subtree
 */
static onion_dict_node  *onion_dict_node_add(onion_dict *d, onion_dict_node *node, onion_dict_node *nnode){
	if (node==NULL){
		//ONION_DEBUG("Add here %p",nnode);
		return nnode;
	}
	signed int cmp=d->cmp(nnode->data.key, node->data.key);
	//ONION_DEBUG0("cmp %d, %X, %X %X",cmp, nnode->data.flags,nnode->data.flags&OD_REPLACE, OD_REPLACE);
	if ((cmp==0) && (nnode->data.flags&OD_REPLACE)){
		//ONION_DEBUG("Replace %s with %s", node->data.key, nnode->data.key);
		onion_dict_node_data_free(&node->data);
		memcpy(&node->data, &nnode->data, sizeof(onion_dict_node_data));
		onion_low_free(nnode);
		return node;
	}
	else if (cmp<0){
		node->left=onion_dict_node_add(d, node->left, nnode);
		//ONION_DEBUG("%p[%s]->left=%p[%s]",node, node->data.key, node->left, node->left->data.key);
	}
	else{ // >=
		node->right=onion_dict_node_add(d, node->right, nnode);
		//ONION_DEBUG("%p[%s]->right=%p[%s]",node, node->data.key, node->right, node->right->data.key);
	}

	node=skew(node);
	node=split(node);

	return node;
}
Beispiel #18
0
/// Removes a node and its data
static void onion_dict_node_free(onion_dict_node *node){
	if (node->left)
		onion_dict_node_free(node->left);
	if (node->right)
		onion_dict_node_free(node->right);

	onion_dict_node_data_free(&node->data);
	onion_low_free(node);
}
Beispiel #19
0
/// Sets the hostname on which to listen
void onion_set_hostname(onion *server, const char *hostname){
	if (server->listen_points){
		onion_low_free(server->listen_points[0]->hostname);
		server->listen_points[0]->hostname=onion_low_strdup(hostname);
	}
	else{
		onion_add_listen_point(server, hostname, NULL, onion_http_new());
	}
}
Beispiel #20
0
/// Sets the port to listen
void onion_set_port(onion *server, const char *port){
	if (server->listen_points){
		onion_low_free(server->listen_points[0]->port);
		server->listen_points[0]->port=onion_low_strdup(port);
	}
	else{
		onion_add_listen_point(server, NULL, port, onion_http_new());
	}
}
Beispiel #21
0
/**
 * @short Writes the given string to the res, but encodes the data using html entities
 * @ingroup response
 *
 * The encoding mens that <code><html> whould become &lt;html&gt;</code>
 */
ssize_t onion_response_write_html_safe(onion_response * res, const char *data) {
  char *tmp = onion_html_quote(data);
  if (tmp) {
    int r = onion_response_write0(res, tmp);
    onion_low_free(tmp);
    return r;
  } else
    return onion_response_write0(res, data);
}
Beispiel #22
0
/**
 * @short Deletes a request and all its data
 * @memberof onion_request_t
 */
void onion_request_free(onion_request *req) {
    ONION_DEBUG0("Free request %p", req);
    onion_dict_free(req->headers);

    if (req->connection.listen_point!=NULL && req->connection.listen_point->close)
        req->connection.listen_point->close(req);
    if (req->fullpath)
        onion_low_free(req->fullpath);
    if (req->GET)
        onion_dict_free(req->GET);
    if (req->POST)
        onion_dict_free(req->POST);
    if (req->FILES) {
        onion_dict_preorder(req->FILES, unlink_files, NULL);
        onion_dict_free(req->FILES);
    }
    if (req->session) {
        if (onion_dict_count(req->session)==0)
            onion_request_session_free(req);
        else {
            onion_sessions_save(req->connection.listen_point->server->sessions, req->session_id, req->session);
            onion_dict_free(req->session); // Not really remove, just dereference
            onion_low_free(req->session_id);
        }
    }
    if (req->data)
        onion_block_free(req->data);
    if (req->connection.cli_info)
        onion_low_free(req->connection.cli_info);

    if (req->websocket)
        onion_websocket_free(req->websocket);

    if (req->parser_data) {
        onion_low_free(req->parser_data);
    }
    if (req->cookies)
        onion_dict_free(req->cookies);
    if (req->free_list) {
        onion_ptr_list_foreach(req->free_list, onion_low_free);
        onion_ptr_list_free(req->free_list);
    }
    onion_low_free(req);
}
Beispiel #23
0
/**
 * @short Frees the user data
 * @memberof onion_https_t
 * 
 * @param op
 */
static void onion_https_free_user_data(onion_listen_point *op){
	ONION_DEBUG("Free HTTPS %s:%s", op->hostname, op->port);
	onion_https *https=(onion_https*)op->user_data;
	
	gnutls_certificate_free_credentials (https->x509_cred);
	gnutls_dh_params_deinit(https->dh_params);
	gnutls_priority_deinit (https->priority_cache);
	//if (op->server->flags&O_SSL_NO_DEINIT)
	gnutls_global_deinit(); // This may cause problems if several characters use the gnutls on the same binary.
	onion_low_free(https);
}
Beispiel #24
0
/**
 * @short Frees the session dictionary.
 * @memberof onion_request_t
 *
 * It removes the session from the sessions dictionary, so this session does not exist anymore.
 *
 * If data is under onion_dict scope (just dicts into dicts and strings), all data is freed.
 * If the user has set some custom data, THAT MEMORY IS LEAKED.
 */
void onion_request_session_free(onion_request *req) {
    if (!req->session_id)
        onion_request_guess_session_id(req);
    if (req->session_id) {
        ONION_DEBUG("Removing from session storage session id: %s",req->session_id);
        onion_sessions_remove(req->connection.listen_point->server->sessions, req->session_id);
        onion_dict_free(req->session);
        req->session=NULL;
        onion_low_free(req->session_id);
        req->session_id=NULL;
    }
}
Beispiel #25
0
/**
 * @short Frees the memory used by this handler.
 * @memberof onion_handler_t
 *
 * It calls the private data handler free if available, and free the 'next' handler too.
 *
 * It should be called when this handler is not going to be used anymore. Most of the cases you
 * call it over the root handler, and from there it removes all the handlers.
 *
 * Returns the number of handlers freed on this level.
 */
int onion_handler_free(onion_handler *handler){
	int n=0;
	onion_handler *next=handler;
	while (next){
		handler=next;
		if (handler->priv_data_free && handler->priv_data){
			handler->priv_data_free(handler->priv_data);
		}
		next=handler->next;
		onion_low_free(handler);
		n++;
	}
	return n;
}
Beispiel #26
0
/// AA tree remove the node
static onion_dict_node *onion_dict_node_remove(const onion_dict *d, onion_dict_node *node, const char *key){
	if (!node)
		return NULL;
	int cmp=d->cmp(key, node->data.key);
	if (cmp<0){
		node->left=onion_dict_node_remove(d, node->left, key);
		//ONION_DEBUG("%p[%s]->left=%p[%s]",node, node->data.key, node->left, node->left ? node->left->data.key : "NULL");
	}
	else if (cmp>0){
		node->right=onion_dict_node_remove(d, node->right, key);
		//ONION_DEBUG("%p[%s]->right=%p[%s]",node, node->data.key, node->right, node->right ? node->right->data.key : "NULL");
	}
	else{ // Real remove
		//ONION_DEBUG("Remove here %p", node);
		onion_dict_node_data_free(&node->data);
		if (node->left==NULL && node->right==NULL){
			onion_low_free(node);
			return NULL;
		}
		if (node->left==NULL){
			onion_dict_node *t=node->right; // Get next key node
			while (t->left) t=t->left;
			//ONION_DEBUG("Set data from %p[%s] to %p[already deleted %s]",t,t->data.key, node, key);
			memcpy(&node->data, &t->data, sizeof(onion_dict_node_data));
			t->data.flags=0; // No double free later, please
			node->right=onion_dict_node_remove(d, node->right, t->data.key);
			//ONION_DEBUG("%p[%s]->right=%p[%s]",node, node->data.key, node->right, node->right ? node->right->data.key : "NULL");
		}
		else{
			onion_dict_node *t=node->left; // Get prev key node
			while (t->right) t=t->right;

			memcpy(&node->data, &t->data, sizeof(onion_dict_node_data));
			t->data.flags=0; // No double free later, please
			node->left=onion_dict_node_remove(d, node->left, t->data.key);
			//ONION_DEBUG("%p[%s]->left=%p[%s]",node, node->data.key, node->left, node->left ? node->left->data.key : "NULL");
		}
	}
	decrease_level(node);
	node=skew(node);
	if (node->right){
		node->right=skew(node->right);
		if (node->right->right)
			node->right->right=skew(node->right->right);
	}
	node=split(node);
	if (node->right)
		node->right=split(node->right);
	return node;
}
Beispiel #27
0
/**
 * @short Frees the memory consumed by this object
 * @memberof onion_response_t
 * @ingroup response
 *
 * This function returns the close status: OR_KEEP_ALIVE or OR_CLOSE_CONNECTION as needed.
 *
 * @returns Whether the connection should be closed or not, or an error status to be handled by server.
 * @see onion_connection_status
 */
onion_connection_status onion_response_free(onion_response * res) {
  // write pending data.
  if (!(res->flags & OR_HEADER_SENT) && res->buffer_pos < sizeof(res->buffer))
    onion_response_set_length(res, res->buffer_pos);

  if (!(res->flags & OR_HEADER_SENT))
    onion_response_write_headers(res);

  onion_response_flush(res);
  onion_request *req = res->request;

  if (res->flags & OR_CHUNKED) {        // Set the chunked data end.
    req->connection.listen_point->write(req, "0\r\n\r\n", 5);
  }

  int r = OCS_CLOSE_CONNECTION;

  // it is a rare ocasion that there is no request, but although unlikely, it may happen
  if (req) {
    // keep alive only on HTTP/1.1.
    ONION_DEBUG0
        ("keep alive [req wants] %d && ([skip] %d || [lenght ok] %d==%d || [chunked] %d)",
         onion_request_keep_alive(req), res->flags & OR_SKIP_CONTENT,
         res->length, res->sent_bytes, res->flags & OR_CHUNKED);
    if (onion_request_keep_alive(req)
        && (res->flags & OR_SKIP_CONTENT || res->length == res->sent_bytes
            || res->flags & OR_CHUNKED)
        )
      r = OCS_KEEP_ALIVE;

    if ((onion_log_flags & OF_NOINFO) != OF_NOINFO)
      // FIXME! This is no proper logging at all. Maybe use a handler.
      ONION_INFO("[%s] \"%s %s\" %d %d (%s)",
                 onion_request_get_client_description(res->request),
                 onion_request_methods[res->request->flags & OR_METHODS],
                 res->request->fullpath, res->code, res->sent_bytes,
                 (r == OCS_KEEP_ALIVE) ? "Keep-Alive" : "Close connection");
  }

  onion_dict_free(res->headers);
  onion_low_free(res);

  return r;
}
Beispiel #28
0
/**
 * @short Gets the sessionid cookie, if any, and sets it to req->session_id.
 * @memberof onion_request_t
 */
void onion_request_guess_session_id(onion_request *req) {
    if (req->session_id) // already known.
        return;
    const char *ov=onion_dict_get(req->headers, "Cookie");
    const char *v=ov;
    ONION_DEBUG("Session ID, maybe from %s",v);
    char *r=NULL;
    onion_dict *session=NULL;

    do { // Check all possible sessions
        if (r) {
            onion_low_free(r);
            r=NULL;
        }
        if (!v)
            return;
        v=strstr(v,"sessionid=");
        if (!v) // exit point, no session found.
            return;
        if (v>ov && isalnum(v[-1])) {
            ONION_DEBUG("At -1: %c %d (%p %p)",v[-1],isalnum(v[-1]),v,ov);
            v=strstr(v,";");
        }
        else {
            v+=10;
            r=onion_low_strdup(v); // Maybe allocated more memory, not much anyway.
            char *p=r;
            while (*p!='\0' && *p!=';') p++;
            *p='\0';
            ONION_DEBUG0("Checking if %s exists in sessions", r);
            session=onion_sessions_get(req->connection.listen_point->server->sessions, r);
        }
    } while(!session);

    req->session_id=r;
    req->session=session;
    ONION_DEBUG("Session ID, from cookie, is %s",req->session_id);
}
Beispiel #29
0
/**
 * @short Removes the full dict struct from mem.
 * @memberof onion_dict_t
 */
void onion_dict_free(onion_dict *dict){
	if (!dict) // No free NULL
		return;
	ONION_DEBUG0("Free %p", dict);
#ifdef HAVE_PTHREADS
	pthread_mutex_lock(&dict->refmutex);
#endif
	dict->refcount--;
	ONION_DEBUG0("Free %p refcount %d", dict, dict->refcount);
	int remove=(dict->refcount==0);
#ifdef HAVE_PTHREADS
	pthread_mutex_unlock(&dict->refmutex);
#endif
	if(remove){
#ifdef HAVE_PTHREADS
		pthread_rwlock_destroy(&dict->lock);
		pthread_mutex_destroy(&dict->refmutex);
#endif
		if (dict->root)
			onion_dict_node_free(dict->root);
		onion_low_free(dict);
	}
}
Beispiel #30
0
/**
 * @short Generates a new response object
 * @memberof onion_response_t
 *
 * This response is generated from a request, and gets from there the writer and writer data.
 *
 * Also fills some important data, as server Id, License type, and the default content type.
 *
 * Default content type is HTML, as normally this is what is needed. This is nontheless just
 * the default, and can be changed to any other with a call to:
 *
 *   onion_response_set_header(res, "Content-Type", my_type);
 *
 * The response object must be freed with onion_response_free, which also returns the keep alive
 * status.
 *
 * onion_response objects are passed by onion internally to process the request, and should not be
 * created by user normally. Nontheless the option exist.
 *
 * @returns An onion_response object for that request.
 */
onion_response *onion_response_new(onion_request *req){
	onion_response *res=onion_low_malloc(sizeof(onion_response));

	res->request=req;
	res->headers=onion_dict_new();
	res->code=200; // The most normal code, so no need to overwrite it in other codes.
	res->flags=0;
	res->sent_bytes_total=res->length=res->sent_bytes=0;
	res->buffer_pos=0;

#ifndef DONT_USE_DATE_HEADER
	{
		time_t t;
		struct tm *tmp;

		t = time(NULL);

		// onion_response_last_date_header is set to t later. It should be more or less atomic.
		// If not no big deal, as we will just use slightly more CPU on those "ephemeral" moments.

		if (t!=onion_response_last_time){
			ONION_DEBUG("Recalculating date header");
			char current_datetime[200];

			tmp = localtime(&t);
			if (tmp == NULL) {
					perror("localtime");
					exit(EXIT_FAILURE);
			}

			if (strftime(current_datetime, sizeof(current_datetime), "%a, %d %b %Y %H:%M:%S %Z", tmp) == 0) {
					fprintf(stderr, "strftime returned 0");
					exit(EXIT_FAILURE);
			}
			// Risky, not using mutex...
#ifdef HAVE_PTHREAD
			pthread_rwlock_wrlock(&onion_response_date_lock);
#endif
			onion_response_last_time=t;
			if (onion_response_last_date_header)
				onion_low_free(onion_response_last_date_header);
			onion_response_last_date_header=onion_low_strdup(current_datetime);
#ifdef HAVE_PTHREAD
			pthread_rwlock_unlock(&onion_response_date_lock);
#endif
		}
	}
#ifdef HAVE_PTHREAD
	pthread_rwlock_rdlock(&onion_response_date_lock);
#endif
	assert(onion_response_last_date_header);
	onion_dict_add(res->headers, "Date", onion_response_last_date_header, OD_DUP_VALUE);
#ifdef HAVE_PTHREAD
	pthread_rwlock_unlock(&onion_response_date_lock);
#endif
#endif // USE_DATE_HEADER
	// Sorry for the advertisment.
	onion_dict_add(res->headers, "Server", "libonion v" ONION_VERSION " - coralbits.com", 0);
	onion_dict_add(res->headers, "Content-Type", "text/html", 0); // Maybe not the best guess, but really useful.
	//time_t t=time(NULL);
	//onion_dict_add(res->headers, "Date", asctime(localtime(&t)), OD_DUP_VALUE);

	return res;
}