void t01_server_one(){ INIT_LOCAL(); o=onion_new(O_ONE); onion_set_root_handler(o,onion_handler_new((void*)process_request,NULL,NULL)); do_petition_set(1,0.1,1,0); onion_free(o); o=onion_new(O_ONE_LOOP); onion_set_root_handler(o,onion_handler_new((void*)process_request,NULL,NULL)); do_petition_set(1,0.1,1,1); onion_free(o); o=onion_new(O_ONE_LOOP); // change poller queue size onion_poller *p=onion_get_poller(o); onion_poller_set_queue_size_per_thread(p, 1); onion_set_root_handler(o,onion_handler_new((void*)process_request,NULL,NULL)); do_petition_set(1,0.001,100,1); onion_free(o); END_LOCAL(); }
void t04_server_timeout_threaded(){ INIT_LOCAL(); CURL *curl=prepare_curl("http://localhost:8082"); o=onion_new(O_THREADED | O_DETACH_LISTEN); onion_set_root_handler(o,onion_handler_new((void*)process_request,NULL,NULL)); onion_set_port(o,"8082"); onion_set_timeout(o,2000); onion_listen(o); sleep(1); int fd=connect_to("localhost","8082"); sleep(3); // Should have closed the connection int w=write(fd,"GET /\n\n",7); FAIL_IF_NOT_EQUAL_INT(w,7); char data[256]; FAIL_IF(read(fd, data,sizeof(data))>0); close(fd); FAIL_IF_NOT(curl_get(curl, "http://localhost:8082")); onion_free(o); curl_easy_cleanup(curl); END_LOCAL(); }
void t06_timeouts(){ INIT_LOCAL(); o=onion_new(O_POOL | O_DETACH_LISTEN); onion_set_timeout(o, 100); onion_set_root_handler(o, onion_handler_new((void*)wait_random, NULL, NULL)); onion_set_port(o, "8081"); onion_listen(o); sleep(1); int nthreads=10; pthread_t *thread=malloc(sizeof(pthread_t*)*nthreads); int i; for (i=0;i<nthreads;i++){ pthread_create(&thread[i], NULL, (void*)do_timeout_request, NULL); } for (i=0;i<nthreads;i++){ pthread_join(thread[i], NULL); } free(thread); onion_free(o); END_LOCAL(); }
void t05_post_content_json(){ INIT_LOCAL(); onion *server=onion_new(0); onion_listen_point *lp=onion_buffer_listen_point_new(); json_response post_json = { 0 }; onion_add_listen_point(server,NULL,NULL,lp); onion_set_root_handler(server, onion_handler_new((void*)&post_json_check,&post_json,NULL)); onion_request *req=onion_request_new(lp); #define POST_HEADER "POST / HTTP/1.1\nContent-Type: application/json\nContent-Length: %d\n\n" char tmp[1024]; int json_length=sizeof(JSON_EXAMPLE); ONION_DEBUG("Post size is about %d",json_length); snprintf(tmp, sizeof(tmp), POST_HEADER, json_length); // ONION_DEBUG("%s",tmp); onion_request_write(req,tmp,strlen(tmp)); onion_request_write(req,JSON_EXAMPLE,json_length); // ONION_DEBUG("%s",JSON_EXAMPLE); FAIL_IF_NOT_EQUAL_INT(post_json.processed, 2); onion_request_free(req); onion_free(server); END_LOCAL(); }
/** * @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."); } onion *o=calloc(1,sizeof(onion)); o->flags=(flags&0x0FF)|O_SSL_AVAILABLE; o->timeout=5000; // 5 seconds of timeout, default. o->poller=onion_poller_new(15); if (!o->poller){ 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; }
void t02_long_template(){ INIT_LOCAL(); int count=0; onion *s=onion_new(0); onion_set_root_handler(s, onion_handler_new((void*)AGPL_txt_handler_page, NULL, NULL)); onion_listen_point *lp=onion_buffer_listen_point_new(); onion_add_listen_point(s,NULL,NULL,lp); lp->write=count_bytes; onion_request *req=onion_request_new(lp); req->connection.listen_point->close(req); req->connection.user_data=&count; req->connection.listen_point->close=NULL; FAIL_IF_NOT_EQUAL_INT(onion_request_write0(req, "GET /\n\n"), OCS_REQUEST_READY); FAIL_IF_NOT_EQUAL_INT(onion_request_process(req), OCS_CLOSE_CONNECTION); FAIL_IF(count<30000); onion_request_free(req); onion_free(s); END_LOCAL(); }
int main() { request_list_t request_list; request_list.reqres = onion_ptr_list_new(); request_list.running = true; pthread_mutex_init(&request_list.lock, NULL); pthread_t long_process_thread; o = onion_new(O_POOL); pthread_create(&long_process_thread, NULL, (void *)&long_process, &request_list); onion_set_root_handler(o, onion_handler_new(&handler, &request_list, NULL)); ONION_INFO("Listening at http://localhost:8080"); onion_listen(o); // Close request_list.running = false; onion_ptr_list_foreach(request_list.reqres, (void *)free_reqres); onion_ptr_list_free(request_list.reqres); pthread_join(long_process_thread, NULL); onion_free(o); return 0; }
void t05_server_timeout_threaded_ssl(){ INIT_LOCAL(); CURL *curl=prepare_curl("https://localhost:8081"); ONION_DEBUG("%s",__FUNCTION__); o=onion_new(O_THREADED | O_DETACH_LISTEN); onion_set_root_handler(o,onion_handler_new((void*)process_request,NULL,NULL)); FAIL_IF_NOT_EQUAL_INT(onion_set_certificate(o, O_SSL_CERTIFICATE_KEY, "mycert.pem", "mycert.pem"),0); onion_set_port(o,"8081"); onion_set_timeout(o,3000); onion_listen(o); sleep(1); int fd=connect_to("localhost","8081"); sleep(4); // Should have closed the connection int w=write(fd,"GET /\n\n",7); FAIL_IF_NOT_EQUAL_INT(w,7); char data[256]; FAIL_IF(read(fd, data,sizeof(data))>0); close(fd); FAIL_IF_NOT(curl_get(curl, "https://localhost:8081")); onion_free(o); curl_easy_cleanup(curl); END_LOCAL(); }
/** * @short Creates an local filesystem handler. * * Exports the given localpath and any file inside this localpath is returned. * * It performs security checks, so that the returned data is saftly known to be inside * that localpath. Normal permissions apply. */ onion_handler *onion_handler_export_local_new(const char *localpath){ char *rp=realpath(localpath, NULL); if (!rp){ ONION_ERROR("Cant calculate the realpath of the given directory (%s).",localpath); return NULL; } struct stat st; if (stat(rp, &st)!=0){ ONION_ERROR("Cant access to the exported directory/file (%s).",rp); free(rp); return NULL; } onion_handler_export_local_data *priv_data=malloc(sizeof(onion_handler_export_local_data)); priv_data->localpath=rp; priv_data->renderer_header=onion_handler_export_local_header_default; priv_data->renderer_footer=onion_handler_export_local_footer_default; priv_data->is_file=S_ISREG(st.st_mode); onion_handler *ret=onion_handler_new((onion_handler_handler)onion_handler_export_local_handler, priv_data,(onion_handler_private_data_free) onion_handler_export_local_delete); return ret; }
/** * @short Creates the URL handler to map regex urls to handlers * @memberof onion_url_t * * The onion_url object can be used to add urls as needed using onion_url_add_*. * * The URLs can be regular expressions or simple strings. The way to discriminate them is just * to check the first character; if its ^ its a regular expression. * * If a string is passed then the full path must match. If its a regexp, just the begining is matched, * unless $ is set at the end. When matched, this is removed from the path. * * It is important to note that when the user pretends to match the initial path elements, to later * pass to another handler that will do path transversal (another url object, for example), the * path must be written with a regular expression, for example: "^login/". If the user just writes * the string it will match only for that specific URL, and subpaths are not in the definition. * * When looking for a match, they are looked in order. * * Examples:: * * @code * onion_url_add(url, "index.html", index); // Matches the exact filename. Not compiled. * onion_url_add(url, "^static/", onion_handler_export_local_new(".") ); // Export current directory at static * onion_url_add(url, "^icons/(.*)", directory); // Compiles the regexp, and uses the .* as first argument. * onion_url_add(url, "", redirect_to_index); // Matches an empty path. Not compiled. * @endcode * * Regexp can have groups, and they will be added as request query parameters, with just the number of the * group as key. The groups start at 1, as 0 should be the full match, but its not added for performance * reasons; its a very strange situation that user will need it, and always can access full path with * onion_request_get_fullpath. Also all expression can be a group, and passed as nr 1.: * * @code * onion_url_add(url, "^index(.html)", index); * ... * onion_request_get_query(req, "1") == ".html" * @endcode * * Be careful as . means every character, and dots in URLs must be with a backslash \ (double because of * C escaping), if using regexps. * * Regular expressions are used by the regexec(3) standard C library. Check that documentation to check * how to create proper regular expressions. They are compiled as REG_EXTENDED. */ onion_url *onion_url_new(){ onion_url_data **priv_data=calloc(1,sizeof(onion_url_data*)); *priv_data=NULL; onion_handler *ret=onion_handler_new((onion_handler_handler)onion_url_handler, priv_data,(onion_handler_private_data_free) onion_url_free_data); return (onion_url*)ret; }
/// Prepares the oterm handler onion_handler *oterm_handler(onion *o, const char *exec_command){ oterm_data *data=malloc(sizeof(oterm_data)); data->sessions=onion_dict_new(); data->processes=onion_dict_new(); data->exec_command=strdup(exec_command); data->onion=o; return onion_handler_new((void*)oterm_get_data, data, (void*)oterm_free); }
int add_answer_redirect_page(onion_url *urls, trivia_question* const q) { int r; char *uri; if((r = asprintf(&uri, "%s.data", q->uri)) == -1) { return r; } return onion_url_add_handler(urls, uri, onion_handler_new(check_answer, q, NULL)); }
/** * @short Initializes the server data. * @memberof onion_server_t * * This data is independant of communication channel, and its the data that should be alsays available, even shared between the channels. * * All data have sensitive defaults, except write and root_handler, and can be modified with accessor functions. * * These defaults include: * * internal_error_handler * * max_post_size -- 1MB * * max_file_size -- 1GB */ onion_server *onion_server_new(void){ onion_server *ret=malloc(sizeof(onion_server)); ret->root_handler=NULL; ret->write=NULL; ret->internal_error_handler=onion_handler_new((onion_handler_handler)onion_default_error, NULL, NULL); ret->max_post_size=1024*1024; // 1MB ret->max_file_size=1024*1024*1024; // 1GB ret->sessions=onion_sessions_new(); return ret; }
/** * @short Creates an path handler. If the path matches the regex, it reomves that from the regexp and goes to the inside_level. * * If on the inside level nobody answers, it just returns NULL, so ->next can answer. */ onion_handler *onion_handler_auth_pam(const char *realm, const char *pamname, onion_handler *inside_level){ onion_handler_auth_pam_data *priv_data=malloc(sizeof(onion_handler_auth_pam_data)); priv_data->inside=inside_level; priv_data->pamname=strdup(pamname); priv_data->realm=strdup(realm); onion_handler *ret=onion_handler_new((onion_handler_handler)onion_handler_auth_pam_handler, priv_data, (onion_handler_private_data_free) onion_handler_auth_pam_delete); return ret; }
int main(int argc, char **argv){ onion *onion=onion_new(O_ONE_LOOP); onion_handler *root=onion_handler_new((onion_handler_handler)method, NULL, NULL); onion_set_root_handler(onion, root); onion_listen(onion); return 0; }
/** * @short Creates an opack handler that calls the onion_opack_renderer with length data. * * If on the inside level nobody answers, it just returns NULL, so ->next can answer. * * @param path Path of the current data, for example /. It is a normal string; no regular expressions are allowed. * @param render Function to call to render the response. * @param length Lenght of the data, or 0 if unknown. Needed to keep alive. */ onion_handler *onion_handler_opack(const char *path, onion_opack_renderer render, unsigned int length){ onion_handler_opack_data *priv_data=malloc(sizeof(onion_handler_opack_data)); priv_data->path=strdup(path); priv_data->length=length; priv_data->render=render; onion_handler *ret=onion_handler_new((onion_handler_handler)onion_handler_opack_handler, priv_data, (onion_handler_private_data_free) onion_handler_opack_delete); return ret; }
void t01_url() { INIT_LOCAL(); onion_url *url = onion_url_new(); onion_url_add_handler(url, "^handler1.$", onion_handler_new((onion_handler_handler) handler1, NULL, NULL)); onion_url_add(url, "handler2/", handler2); onion_url_add_with_data(url, "^handler(3|4)/", handler3, NULL, NULL); onion_set_root_handler(server, onion_url_to_handler(url)); onion_request *req = onion_request_new(onion_get_listen_point(server, 0)); #define R "GET /handler1/ HTTP/1.1\n\n" onion_request_write(req, R, sizeof(R)); onion_request_process(req); FAIL_IF_NOT_EQUAL_INT(handler_called, 1); FAIL_IF_NOT_EQUAL_STR(urltxt, ""); free(urltxt); urltxt = NULL; onion_request_clean(req); onion_request_write(req, "GET /handler2/ HTTP/1.1\n\n", sizeof(R)); onion_request_process(req); FAIL_IF_NOT_EQUAL_INT(handler_called, 2); ONION_DEBUG("%s", urltxt); FAIL_IF_NOT_EQUAL_STR(urltxt, ""); free(urltxt); urltxt = NULL; onion_request_clean(req); onion_request_write(req, "GET /handler3/hello HTTP/1.1\n\n", sizeof(R) + 5); onion_request_process(req); FAIL_IF_NOT_EQUAL_INT(handler_called, 3); FAIL_IF_NOT_EQUAL_STR(urltxt, "hello"); free(urltxt); urltxt = NULL; handler_called = 0; onion_request_clean(req); onion_request_write(req, "GET /handler2/hello HTTP/1.1\n\n", sizeof(R) + 5); onion_request_process(req); FAIL_IF_NOT_EQUAL_INT(handler_called, 0); FAIL_IF_EQUAL_STR(urltxt, ""); free(urltxt); urltxt = NULL; onion_request_free(req); onion_url_free(url); onion_set_root_handler(server, NULL); END_LOCAL(); }
/** * @short Creates a static handler that just writes some static data. * * Path is a regex for the url, as arrived here. */ onion_handler *onion_handler_static(const char *text, int code){ onion_handler_static_data *priv_data=onion_low_malloc(sizeof(onion_handler_static_data)); if (!priv_data) return NULL; priv_data->code=code; priv_data->data=onion_low_strdup(text); onion_handler *ret=onion_handler_new((onion_handler_handler)onion_handler_static_handler, priv_data,(onion_handler_private_data_free) onion_handler_static_delete); return ret; }
int main(int argc, char **argv){ o=onion_new(O_ONE_LOOP); onion_handler *root=onion_handler_new((onion_handler_handler)sessions, NULL, NULL); onion_set_root_handler(o, root); signal(SIGINT, free_onion); onion_listen(o); return 0; }
void t02_server_epoll(){ INIT_LOCAL(); o=onion_new(O_POLL); onion_set_root_handler(o,onion_handler_new((void*)process_request,NULL,NULL)); do_petition_set(1,0.1,1,1); onion_free(o); o=onion_new(O_POLL); onion_set_root_handler(o,onion_handler_new((void*)process_request,NULL,NULL)); do_petition_set(1,0.001,100,1); onion_free(o); o=onion_new(O_POOL); onion_set_root_handler(o,onion_handler_new((void*)process_request,NULL,NULL)); do_petition_set(1,0.001,100,1); onion_free(o); o=onion_new(O_POOL); onion_set_root_handler(o,onion_handler_new((void*)process_request,NULL,NULL)); do_petition_set_threaded(1,0.001,100,2,10); onion_free(o); o=onion_new(O_POOL); onion_set_root_handler(o,onion_handler_new((void*)process_request,NULL,NULL)); do_petition_set_threaded(1,0.001,100,2,15); onion_free(o); o=onion_new(O_POOL); onion_set_root_handler(o,onion_handler_new((void*)process_request,NULL,NULL)); do_petition_set_threaded(1,0.001,100,2,100); onion_free(o); END_LOCAL(); }
/** * @short In a simple loop asks the user for the answer of the query. */ int main(int argc, char **argv){ onion *server; server=onion_new(O_ONE_LOOP); onion_set_hostname(server, "0.0.0.0"); onion_set_root_handler(server, onion_handler_new((void*)ask_handler, NULL, NULL)); onion_listen(server); onion_free(server); return 0; }
/** * @short Creates a webdav handler * * The check_permissions parameter, if set, sets a custom security permission checker. * * If not set, the default permissions apply, that will try to do not access files out of the restricted area. * * This permission checker gets the exported path, the path to the file that wants to be exported/checked/moved.., * and the request as it arrived to the handler. * * The exported path and file path might be relative, if onion_handler_webdav was initialized so. * * On move it will check for both the original and final files, on other methods, it will check just the file, and * the semantics is that the user is allowed to do that method. * * It should return 0 on success, any other if error/not allowed. * * @param path Path to share * @returns The onion handler. */ onion_handler *onion_handler_webdav(const char *path, onion_webdav_permissions_check perm){ xmlInitParser(); LIBXML_TEST_VERSION onion_webdav *wd=malloc(sizeof(onion_webdav)); wd->path=strdup(path); if (perm) wd->check_permissions=perm; else wd->check_permissions=onion_webdav_default_check_permissions; onion_handler *ret=onion_handler_new((void*)onion_webdav_handler, wd, (void*)onion_webdav_free); return ret; }
void t02_post_a_lot() { INIT_LOCAL(); onion *o = onion_new(O_ONE); onion_set_root_handler(o, onion_handler_new((void *)return_length, NULL, NULL)); pthread_t pt; pthread_create(&pt, NULL, (void *)POST_a_lot, NULL); onion_listen(o); pthread_join(pt, NULL); onion_free(o); END_LOCAL(); }
/// A BUG were detected: transformed \n to \r\n on files. void t03_post_carriage_return_new_lines_file(){ INIT_LOCAL(); buffer *b=buffer_new(1024); expected_post post={};; post.filename="file.dat"; post.test_ok=0; // Not ok as not called processor yet post.tmpfilename=NULL; post.size=3; onion_server *server=onion_server_new(); onion_server_set_write(server, (void*)&buffer_append); onion_server_set_root_handler(server, onion_handler_new((void*)&post_check,&post,NULL)); onion_request *req=onion_request_new(server,b,"test"); #define POST_EMPTY "POST / HTTP/1.1\nContent-Type: multipart/form-data; boundary=end\nContent-Length:81\n\n--end\nContent-Disposition: text/plain; name=\"file\"; filename=\"file.dat\"\n\n\n\r\n\n--end--" //ONION_DEBUG("%s",POST_EMPTY); onion_request_write(req,POST_EMPTY,sizeof(POST_EMPTY)); FAIL_IF_NOT_EQUAL(post.test_ok,1); #undef POST_EMPTY onion_request_clean(req); post.test_ok=0; // Not ok as not called processor yet #define POST_EMPTYR "POST / HTTP/1.1\r\nContent-Type: multipart/form-data; boundary=end\r\nContent-Length:85\r\n\r\n--end\r\nContent-Disposition: text/plain; name=\"file\"; filename=\"file.dat\"\r\n\r\n\n\r\n\r\n--end--" onion_request_write(req,POST_EMPTYR,sizeof(POST_EMPTYR)); FAIL_IF_NOT_EQUAL(post.test_ok,1); #undef POST_EMPTYR onion_request_free(req); if (post.tmpfilename){ struct stat st; FAIL_IF_EQUAL(stat(post.tmpfilename,&st), 0); // Should not exist free(post.tmpfilename); } if (post.tmplink) free(post.tmplink); onion_server_free(server); buffer_free(b); END_LOCAL(); }
void t01_post_no_type() { INIT_LOCAL(); onion *o = onion_new(O_ONE); onion_set_root_handler(o, onion_handler_new((void *)process_request, NULL, NULL)); pthread_t pt; pthread_create(&pt, NULL, (void *)POST_json, NULL); onion_listen(o); pthread_join(pt, NULL); onion_free(o); END_LOCAL(); }
int main(int argc, char **argv){ o=onion_new(O_ONE_LOOP); #ifdef HAVE_REDIS onion_sessions *session_backend=onion_sessions_redis_new("localhost",6379); onion_set_session_backend(o, session_backend); #endif onion_url *root=onion_root_url(o); onion_url_add_handler(root, "status",onion_internal_status()); onion_url_add_handler(root, "^.*", onion_handler_new((onion_handler_handler)sessions, NULL, NULL)); signal(SIGINT, free_onion); onion_listen(o); return 0; }
void t03_server_https(){ INIT_LOCAL(); CURL *curl=prepare_curl("https://localhost:8080"); o=onion_new(O_ONE_LOOP | O_DETACH_LISTEN); onion_set_root_handler(o,onion_handler_new((void*)process_request,NULL,NULL)); FAIL_IF_NOT_EQUAL_INT(onion_set_certificate(o, O_SSL_CERTIFICATE_KEY, "mycert.pem", "mycert.pem"),0); FAIL_IF_NOT_EQUAL_INT(onion_listen(o),0); //do_petition_set(1,1,1,1); sleep(1); //FAIL_IF_EQUAL_INT( curl_get_to_fail("http://localhost:8080"), HTTP_OK); sleep(1); FAIL_IF_NOT_EQUAL_INT( curl_get(curl, "https://localhost:8080"), HTTP_OK); sleep(1); onion_free(o); curl_easy_cleanup(curl); END_LOCAL(); }
/// A BUG were detected: transformed \n to \r\n on files. void t02_post_new_lines_file(){ INIT_LOCAL(); expected_post post={};; post.filename="file.dat"; post.test_ok=0; // Not ok as not called processor yet post.tmpfilename=NULL; post.size=1; onion *server=onion_new(0); onion_listen_point *lp=onion_buffer_listen_point_new(); onion_add_listen_point(server,NULL,NULL,lp); onion_set_root_handler(server, onion_handler_new((void*)&post_check,&post,NULL)); onion_request *req=onion_request_new(lp); #define POST_EMPTY "POST / HTTP/1.1\nContent-Type: multipart/form-data; boundary=end\nContent-Length:81\n\n--end\nContent-Disposition: text/plain; name=\"file\"; filename=\"file.dat\"\n\n\n\n--end--" onion_request_write(req,POST_EMPTY,sizeof(POST_EMPTY)); FAIL_IF_NOT_EQUAL(post.test_ok,1); #undef POST_EMPTY onion_request_clean(req); post.test_ok=0; // Not ok as not called processor yet #define POST_EMPTYR "POST / HTTP/1.1\r\nContent-Type: multipart/form-data; boundary=end\r\nContent-Length:85\r\n\r\n--end\r\nContent-Disposition: text/plain; name=\"file\"; filename=\"file.dat\"\r\n\r\n\n\r\n--end--" onion_request_write(req,POST_EMPTYR,sizeof(POST_EMPTYR)); FAIL_IF_NOT_EQUAL(post.test_ok,1); #undef POST_EMPTYR onion_request_free(req); if (post.tmpfilename){ struct stat st; FAIL_IF_EQUAL(stat(post.tmpfilename,&st), 0); // Should not exist free(post.tmpfilename); } if (post.tmplink) free(post.tmplink); onion_free(server); END_LOCAL(); }
/** * @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_AVAILABLE; o->nthreads=8; if (o->flags&O_THREADED) o->flags|=O_THREADS_ENABLED; pthread_mutex_init (&o->mutex, NULL); #endif if (!(o->flags&O_NO_SIGTERM)){ signal(SIGINT,shutdown_server); signal(SIGTERM,shutdown_server); } last_onion=o; return o; }
/** * @short Executes each script file passed as argument. * * Optionally a -r sets the new lines to \r\n. It takes care of not changing content types. */ int main(int argc, char **argv){ server=onion_server_new(); onion_server_set_root_handler(server,onion_handler_new((void*)allinfo_handler,NULL,NULL)); onion_server_set_write(server,(void*)buffer_append); int i; int do_r=0; for (i=1;i<argc;i++){ if (strcmp(argv[i],"-r")==0){ ONION_WARNING("Setting the end of lines to \\r\\n"); do_r=1; } else{ ONION_INFO("Launching test %s",argv[i]); prerecorded(argv[i], do_r); } } onion_server_free(server); END(); }