void t02_full_cycle_http10(){ INIT_LOCAL(); onion *server=onion_new(0); onion_add_listen_point(server,NULL,NULL,onion_buffer_listen_point_new()); onion_request *request; char buffer[4096]; memset(buffer,0,sizeof(buffer)); request=onion_request_new(server->listen_points[0]); onion_response *response=onion_response_new(request); onion_response_set_length(response, 30); FAIL_IF_NOT_EQUAL(response->length,30); onion_response_write_headers(response); onion_response_write0(response,"123456789012345678901234567890"); onion_response_flush(response); FAIL_IF_NOT_EQUAL(response->sent_bytes,30); onion_response_free(response); strncpy(buffer,onion_buffer_listen_point_get_buffer_data(request),sizeof(buffer)); onion_request_free(request); onion_free(server); FAIL_IF_NOT_STRSTR(buffer, "HTTP/1.0 200 OK\r\n"); FAIL_IF_NOT_STRSTR(buffer, "Connection: Keep-Alive\r\n"); FAIL_IF_NOT_STRSTR(buffer, "Content-Length: 30\r\n"); FAIL_IF_NOT_STRSTR(buffer, "Server: libonion"); FAIL_IF_NOT_STRSTR(buffer, "coralbits"); FAIL_IF_NOT_STRSTR(buffer, "\r\n\r\n123456789012345678901234567890"); END_LOCAL(); }
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(); }
/** * @short Adds a listen point */ void addListenPoint(const std::string & hostname, const std::string & port, ListenPoint && protocol) { onion_add_listen_point(ptr, hostname.c_str(), port.c_str(), protocol.c_handler()); // Release ownership of the pointer protocol.release(); }
void t01_server_min(){ INIT_LOCAL(); 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_static("Succedded", 200)); onion_request *req=onion_request_new(lp); onion_request_write(req, "GET ",4); onion_request_write(req, "/",1); onion_request_write(req, " HTTP/1.1\r\n",11); onion_request_write(req, "\r\n",2); const char *buffer=onion_buffer_listen_point_get_buffer_data(req); FAIL_IF_EQUAL_STR(buffer,""); FAIL_IF_NOT_STRSTR(buffer, "HTTP/1.1 200 OK\r\n"); FAIL_IF_NOT_STRSTR(buffer, "\r\nContent-Length: 9\r\n"); FAIL_IF_NOT_STRSTR(buffer, "libonion"); FAIL_IF_NOT_STRSTR(buffer, "\r\n\r\nSuccedded"); onion_request_free(req); onion_free(server); END_LOCAL(); }
void t02_server_full(){ INIT_LOCAL(); 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_static("Succedded", 200)); onion_request *req=onion_request_new(lp); #define S "GET / HTTP/1.1\r\nHeader-1: This is header1\r\nHeader-2: This is header 2\r\n" onion_request_write(req, S,sizeof(S)-1); // send it all, but the final 0. #undef S const char *buffer=onion_buffer_listen_point_get_buffer_data(req); FAIL_IF_NOT_EQUAL_STR(buffer,""); onion_request_write(req, "\n",1); // finish this request. no \n\n before to check possible bugs. buffer=onion_buffer_listen_point_get_buffer_data(req); FAIL_IF_EQUAL_STR(buffer,""); FAIL_IF_NOT_STRSTR(buffer, "HTTP/1.1 200 OK\r\n"); FAIL_IF_NOT_STRSTR(buffer, "\r\nContent-Length: 9\r\n"); FAIL_IF_NOT_STRSTR(buffer, "libonion"); FAIL_IF_NOT_STRSTR(buffer, "\r\n\r\nSuccedded"); onion_request_free(req); onion_free(server); END_LOCAL(); }
void t08_server_with_error_404(){ INIT_LOCAL(); onion *server=onion_new(0); onion_listen_point *lp=onion_buffer_listen_point_new(); onion_add_listen_point(server,NULL,NULL,lp); onion_url *urls=onion_url_new(); onion_set_root_handler(server, onion_url_to_handler(urls)); onion_request *req=onion_request_new(lp); #define S "GET / HTTP/1.1" onion_request_write(req, S,sizeof(S)-1); // send it all, but the final 0. #undef S const char *buffer=onion_buffer_listen_point_get_buffer_data(req); FAIL_IF_NOT_EQUAL_STR(buffer,""); onion_request_write(req, "\n",1); // finish this request. no \n\n before to check possible bugs. onion_request_write(req, "\n",1); // finish this request. no \n\n before to check possible bugs. The last \n was not processed, as was overflowing. buffer=onion_buffer_listen_point_get_buffer_data(req); FAIL_IF_EQUAL_STR(buffer,""); FAIL_IF_NOT_STRSTR(buffer, "HTTP/1.1 404 NOT FOUND\r\n"); FAIL_IF_NOT_STRSTR(buffer, "libonion"); onion_request_free(req); onion_free(server); END_LOCAL(); }
void t01_handle_static_request(){ INIT_LOCAL(); char ok; onion *server=onion_new(0); onion_listen_point *lp=onion_buffer_listen_point_new(); onion_add_listen_point(server, NULL, NULL, lp); onion_request *request=onion_request_new(lp); FILL(request,"GET / HTTP/1.1\n"); onion_handler *handler=onion_handler_static("Not ready",302); FAIL_IF_NOT(handler); onion_set_root_handler(server, handler); onion_response *response=onion_response_new(request); ok=onion_handler_handle(handler, request, response); FAIL_IF_NOT_EQUAL(ok, OCS_PROCESSED); onion_response_free(response); const char *buffer=onion_buffer_listen_point_get_buffer_data(request); FAIL_IF_EQUAL_STR(buffer,""); FAIL_IF_NOT_STRSTR(buffer, "HTTP/1.1 302 REDIRECT\r\n"); FAIL_IF_NOT_STRSTR(buffer, "\r\nContent-Length: 9\r\n"); FAIL_IF_NOT_STRSTR(buffer, "libonion"); FAIL_IF_STRSTR(buffer, "License: AGPL"); // License is now LGPL, no need to advertise FAIL_IF_STRSTR(buffer, "License"); FAIL_IF_NOT_STRSTR(buffer, "\r\n\r\nNot ready"); onion_request_free(request); onion_free(server); END_LOCAL(); }
void t04_server_overflow(){ INIT_LOCAL(); 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_static("Succedded", 200)); onion_block *long_req=onion_block_new(); onion_block_add_str(long_req,"GET / HTTP/1.1\n"); int i; for(i=0;i<1000;i++){ onion_block_add_str(long_req,"Header-1: This is header1 Header-2: This is header 2 "); } onion_request *req=onion_request_new(lp); onion_request_write(req, onion_block_data(long_req),onion_block_size(long_req)-1); // send it all, but the final 0. const char *buffer=onion_buffer_listen_point_get_buffer_data(req); FAIL_IF_NOT_EQUAL_STR(buffer,""); onion_request_write(req, "\n\n",2); // finish this request. no \n\n before to check possible bugs. buffer=onion_buffer_listen_point_get_buffer_data(req); FAIL_IF_EQUAL_STR(buffer,""); FAIL_IF_NOT_STRSTR(buffer, "HTTP/1.1 200 OK\r\n"); FAIL_IF_NOT_STRSTR(buffer, "\r\nContent-Length: 9\r\n"); FAIL_IF_NOT_STRSTR(buffer, "libonion"); FAIL_IF_NOT_STRSTR(buffer, "\r\n\r\nSuccedded"); onion_block_free(long_req); onion_request_free(req); onion_free(server); 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(); }
void t06_empty(){ INIT_LOCAL(); onion *server=onion_new(0); onion_add_listen_point(server,NULL,NULL,onion_buffer_listen_point_new()); onion_request *request; char buffer[4096]; memset(buffer,0,sizeof(buffer)); request=onion_request_new(server->listen_points[0]); onion_response *response=onion_response_new(request); // onion_response_write_headers(response); onion_response_flush(response); onion_response_free(response); buffer[sizeof(buffer)-1]=0; strncpy(buffer,onion_buffer_listen_point_get_buffer_data(request),sizeof(buffer)-1); onion_request_free(request); onion_free(server); FAIL_IF_NOT_STRSTR(buffer, "Server:"); FAIL_IF_NOT_STRSTR(buffer, "Content-Type:"); // ONION_DEBUG(buffer); END_LOCAL(); }
void t05_printf(){ INIT_LOCAL(); onion *server=onion_new(0); onion_add_listen_point(server,NULL,NULL,onion_buffer_listen_point_new()); onion_request *request; char buffer[4096]; memset(buffer,0,sizeof(buffer)); request=onion_request_new(server->listen_points[0]); onion_response *response=onion_response_new(request); onion_response_printf(response, "%s %d %p", "Hello world", 123, NULL); onion_response_flush(response); onion_response_free(response); buffer[sizeof(buffer)-1]=0; strncpy(buffer,onion_buffer_listen_point_get_buffer_data(request),sizeof(buffer)-1); onion_request_free(request); onion_free(server); FAIL_IF_NOT_STRSTR(buffer, "Hello world 123 (nil)"); END_LOCAL(); }
/// Sets the hostname on which to listen void onion_set_hostname(onion *server, const char *hostname){ if (server->listen_points){ free(server->listen_points[0]->hostname); server->listen_points[0]->hostname=strdup(hostname); } else{ onion_add_listen_point(server, hostname, NULL, onion_http_new()); } }
/// Sets the port to listen void onion_set_port(onion *server, const char *port){ if (server->listen_points){ free(server->listen_points[0]->port); server->listen_points[0]->port=strdup(port); } else{ onion_add_listen_point(server, NULL, port, onion_http_new()); } }
void t02_handle_generic_request(){ INIT_LOCAL(); onion *server=onion_new(0); onion_listen_point *lp=onion_buffer_listen_point_new(); onion_add_listen_point(server, NULL, NULL, lp); onion_url *url=onion_url_new(); int error; error=onion_url_add_handler(url, "^$", onion_handler_static("Not ready",302)); FAIL_IF(error); error=onion_url_add_handler(url, "^a.*$", onion_handler_static("any",200)); FAIL_IF(error); error=onion_url_add_static(url, "^.*", "Internal error", 500); FAIL_IF(error); onion_set_root_handler(server, onion_url_to_handler(url)); onion_request *request; request=onion_request_new(lp); FILL(request,"GET / HTTP/1.1\n"); onion_request_process(request); const char *buffer=onion_buffer_listen_point_get_buffer_data(request); FAIL_IF_NOT_STRSTR(buffer, "HTTP/1.1 302 REDIRECT\r\n"); FAIL_IF_NOT_STRSTR(buffer, "Content-Length: 9\r\n"); FAIL_IF_NOT_STRSTR(buffer, "\r\n\r\nNot ready"); onion_request_free(request); // gives error, as such url does not exist. request=onion_request_new(lp); FILL(request,"GET /error HTTP/1.1\n"); onion_request_process(request); buffer=onion_buffer_listen_point_get_buffer_data(request); ONION_DEBUG("<%s>", buffer); FAIL_IF_NOT_STRSTR(buffer, "HTTP/1.1 500 INTERNAL ERROR\r\n"); FAIL_IF_NOT_STRSTR(buffer, "Content-Length: 14\r\n"); FAIL_IF_NOT_STRSTR(buffer, "\r\n\r\nInternal error"); onion_request_free(request); request=onion_request_new(lp); FILL(request,"GET /any HTTP/1.1\n"); onion_request_process(request); buffer=onion_buffer_listen_point_get_buffer_data(request); FAIL_IF_NOT_STRSTR(buffer, "HTTP/1.1 200 OK\r\n"); FAIL_IF_NOT_STRSTR(buffer, "Content-Length: 3\r\n"); FAIL_IF_NOT_STRSTR(buffer, "\r\n\r\nany"); onion_request_free(request); onion_free(server); END_LOCAL(); }
onion *websocket_server_new() { onion *o = onion_new(0); onion_url *urls = onion_root_url(o); onion_url_add(urls, "", ws_handler); onion_listen_point *lp = onion_buffer_listen_point_new(); onion_add_listen_point(o, NULL, NULL, lp); return o; }
int main(int argc, char **argv){ o=onion_new(O_THREADED); signal(SIGINT, free_onion); onion_set_root_handler(o, onion_handler_export_local_new(".")); onion_add_listen_point(o, "localhost", "8080", onion_http_new()); onion_add_listen_point(o, "localhost", "8081", onion_http_new()); onion_add_listen_point(o, "localhost", "4443", onion_https_new(O_SSL_CERTIFICATE_KEY, "cert.pem", "cert.key")); /** onion_set_port(o, "localhost", "6121", onion_protocol_spdy()); */ onion_listen(o); onion_free(o); return 0; }
int main(int argc, char **argv){ o=onion_new(O_THREADED); signal(SIGINT, free_onion); onion_set_root_handler(o, onion_handler_export_local_new(".")); onion_add_listen_point(o, "localhost", "8080", onion_http_new()); onion_add_listen_point(o, "localhost", "8081", onion_http_new()); #ifdef HAVE_GNUTLS onion_add_listen_point(o, "localhost", "4443", onion_https_new(O_SSL_CERTIFICATE_KEY, "cert.pem", "cert.key")); #else ONION_WARNING("HTTPS support is not enabled. Recompile with gnutls"); #endif /** onion_set_port(o, "localhost", "6121", onion_protocol_spdy()); */ onion_listen(o); onion_free(o); return 0; }
int trivia(void) { printf("creating web-server\n"); o=onion_new(O_ONE_LOOP); printf("obtaining root url\n"); onion_url *urls=onion_root_url(o); printf("adding css skeleton\n"); if(add_css_page(urls)) { printf("error: add_questions(): %s\n", strerror(errno)); exit(1); } printf("adding questions\n"); if(add_questions(urls)) { printf("error: add_questions(): %s\n", strerror(errno)); exit(1); } printf("adding landing page\n"); if(add_start_page(urls)) { printf("error: add_landing_page(): %s\n", strerror(errno)); exit(1); } printf("adding done page\n"); if(add_done_page(urls)) { printf("error: add_done_page(): %s\n", strerror(errno)); exit(1); } printf("adding reset page\n"); if(add_reset_page(urls)) { printf("error: add_landing_page(): %s\n", strerror(errno)); exit(1); } printf("adding signal handlers\n"); signal(SIGTERM, onexit); signal(SIGINT, onexit); printf("adding listening point\n"); onion_add_listen_point(o, NULL, "80", onion_http_new()); printf("listening\n"); onion_listen(o); printf("freeing\n"); onion_free(o); return 0; }
/// A BUG were detected: transformed \n to \r\n on files. void t03_post_carriage_return_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=3; 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\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_free(server); END_LOCAL(); }
void t00_server_empty(){ INIT_LOCAL(); onion *server=onion_new(0); onion_listen_point *lp=onion_buffer_listen_point_new(); onion_add_listen_point(server,NULL,NULL,lp); onion_request *req=onion_request_new(lp); onion_request_write(req, "GET ",4); onion_request_write(req, "/",1); onion_request_write(req, " HTTP/1.1\r\n",11); onion_request_write(req, "\r\n",2); const char *buffer=onion_buffer_listen_point_get_buffer_data(req); FAIL_IF_EQUAL_STR(buffer,""); FAIL_IF_NOT_STRSTR(buffer,"404"); onion_request_free(req); onion_free(server); END_LOCAL(); }
/// Set a certificate for use in the connection int onion_set_certificate(onion *onion, onion_ssl_certificate_type type, const char *filename,...){ #ifdef HAVE_GNUTLS if (!onion->listen_points){ onion_add_listen_point(onion,NULL,NULL,onion_https_new()); } else{ onion_listen_point *first_listen_point=onion->listen_points[0]; if (first_listen_point->write!=onion_https_write){ if (first_listen_point->write!=onion_http_write){ ONION_ERROR("First listen point is not HTTP not HTTPS. Refusing to promote it to HTTPS. Use proper onion_https_new."); return -1; } ONION_DEBUG("Promoting from HTTP to HTTPS"); char *port=first_listen_point->port ? strdup(first_listen_point->port) : NULL; char *hostname=first_listen_point->hostname ? strdup(first_listen_point->hostname) : NULL; onion_listen_point_free(first_listen_point); onion_listen_point *https=onion_https_new(); if (NULL==https){ ONION_ERROR("Could not promote from HTTP to HTTPS. Certificate not set."); } https->port=port; https->hostname=hostname; onion->listen_points[0]=https; first_listen_point=https; } } va_list va; va_start(va, filename); int r=onion_https_set_certificate_argv(onion->listen_points[0], type, filename,va); va_end(va); return r; #else ONION_ERROR("GNUTLS is not enabled. Recompile onion with GNUTLS support"); return -1; #endif }
void t01_call_otemplate(){ INIT_LOCAL(); onion *s=onion_new(0); onion_set_root_handler(s, onion_handler_new((void*)_13_otemplate_html_handler_page, NULL, NULL)); onion_listen_point *lp=onion_buffer_listen_point_new(); onion_add_listen_point(s,NULL,NULL,lp); struct tests_call_otemplate tests; onion_request *req=onion_request_new(lp); 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); ONION_INFO("Got %s",onion_buffer_listen_point_get_buffer_data(req)); check_tests(onion_buffer_listen_point_get_buffer(req), &tests); FAIL_IF_NOT_EQUAL_INT(tests.ok_hello,1); FAIL_IF_NOT_EQUAL_INT(tests.ok_list,0); FAIL_IF_NOT_EQUAL_INT(tests.ok_title,0); FAIL_IF_NOT_EQUAL_INT(tests.ok_title_title,0); FAIL_IF_NOT_EQUAL_INT(tests.ok_encoding,0); onion_dict *d=onion_dict_new(); onion_dict_add(d, "title", "TITLE",0); onion_dict_add(d, "hello", "SHOULD NOT APPEAR",0); onion_dict_add(d, "quoted", "<\"Hello>",0); onion_request_clean(req); onion_handler_free(onion_get_root_handler(s)); onion_set_root_handler(s, onion_handler_new((void*)_13_otemplate_html_handler_page, d, 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); ONION_INFO("Got %s",onion_buffer_listen_point_get_buffer_data(req)); check_tests(onion_buffer_listen_point_get_buffer(req), &tests); FAIL_IF_NOT_EQUAL_INT(tests.ok_hello,1); FAIL_IF_NOT_EQUAL_INT(tests.ok_list,0); FAIL_IF_NOT_EQUAL_INT(tests.ok_title,1); FAIL_IF_NOT_EQUAL_INT(tests.ok_title_title,1); FAIL_IF_NOT_EQUAL_INT(tests.ok_encoding,1); onion_dict *d2=onion_dict_new(); onion_dict_add(d2,"0","LIST 1",0); onion_dict_add(d2,"1","LIST 2",0); onion_dict_add(d2,"2","LIST 3",0); onion_dict_add(d,"list",d2, OD_DICT|OD_FREE_VALUE); onion_dict *f1=onion_dict_new(); onion_dict *f2=onion_dict_new(); onion_dict_add(f2, "0", "internal",0); onion_dict_add(f2, "1", "loop",0); onion_dict_add(f1, "loop", f2, OD_DICT|OD_FREE_VALUE); onion_dict_add(d, "loop", f1, OD_DICT|OD_FREE_VALUE); onion_request_clean(req); onion_handler_free(onion_get_root_handler(s)); onion_set_root_handler(s, onion_handler_new((void*)_13_otemplate_html_handler_page, d, (void*)onion_dict_free)); 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); check_tests(onion_buffer_listen_point_get_buffer(req), &tests); ONION_INFO("Got %s",onion_buffer_listen_point_get_buffer_data(req)); FAIL_IF_NOT_EQUAL_INT(tests.ok_hello,1); FAIL_IF_NOT_EQUAL_INT(tests.ok_list,1); FAIL_IF_NOT_EQUAL_INT(tests.ok_title,1); FAIL_IF_NOT_EQUAL_INT(tests.ok_title_title,1); FAIL_IF_NOT_EQUAL_INT(tests.ok_internal_loop,1); onion_request_free(req); onion_free(s); END_LOCAL(); }
void t03_handle_path_request(){ INIT_LOCAL(); onion *server=onion_new(0); onion_listen_point *lp=onion_buffer_listen_point_new(); onion_add_listen_point(server, NULL, NULL, lp); onion_url *urls=onion_url_new(); onion_url_add_static(urls, "^$", "Test index\n", HTTP_OK); onion_url_add_static(urls, "^index.html$", "Index test", 200); onion_url *pathu=onion_url_new(); onion_handler *path=onion_url_to_handler(pathu); onion_url_add_url(pathu, "^test/", urls); onion_handler_add(path, onion_handler_static("Internal error", 500 ) ); onion_set_root_handler(server, path); onion_request *request; onion_response *response; request=onion_request_new(lp); FILL(request,"GET / HTTP/1.1\n"); onion_request_polish(request); response=onion_response_new(request); onion_handler_handle(path, request, response); onion_response_free(response); const char *buffer=onion_buffer_listen_point_get_buffer_data(request); FAIL_IF_NOT_STRSTR(buffer, "HTTP/1.1 500 INTERNAL ERROR\r\n"); FAIL_IF_NOT_STRSTR(buffer, "Content-Length: 14\r\n"); FAIL_IF_NOT_STRSTR(buffer, "\r\n\r\nInternal error"); onion_request_free(request); // gives error, as such url does not exist. request=onion_request_new(lp); FILL(request,"GET /test/ HTTP/1.1\n"); onion_request_polish(request); response=onion_response_new(request); onion_handler_handle(path, request, response); onion_response_free(response); buffer=onion_buffer_listen_point_get_buffer_data(request); FAIL_IF_NOT_STRSTR(buffer, "HTTP/1.1 200 OK\r\n"); FAIL_IF_NOT_STRSTR(buffer, "Content-Length: 11\r\n"); FAIL_IF_NOT_STRSTR(buffer, "\r\n\r\nTest index\n"); onion_request_free(request); request=onion_request_new(lp); FILL(request,"GET /test/index.html HTTP/1.1\n"); onion_request_polish(request); response=onion_response_new(request); onion_handler_handle(path, request, response); onion_response_free(response); buffer=onion_buffer_listen_point_get_buffer_data(request); FAIL_IF_NOT_STRSTR(buffer, "HTTP/1.1 200 OK\r\n"); FAIL_IF_NOT_STRSTR(buffer, "Content-Length: 10\r\n"); FAIL_IF_NOT_STRSTR(buffer, "\r\n\r\nIndex test"); onion_request_free(request); onion_free(server); END_LOCAL(); }
void setup(){ server=onion_new(O_ONE); custom_io=onion_buffer_listen_point_new(); onion_add_listen_point(server, NULL, NULL, custom_io); }
/** * @short Performs the listening with the given mode * @memberof onion_t * * This is the main loop for the onion server. * * It initiates the listening on all the selected ports and addresses. * * @returns !=0 if there is any error. It returns actualy errno from the network operations. See socket for more information. */ int onion_listen(onion *o){ #ifdef HAVE_PTHREADS if (!(o->flags&O_DETACHED) && (o->flags&O_DETACH_LISTEN)){ // Must detach and return o->flags|=O_DETACHED; pthread_create(&o->listen_thread,NULL, (void*)onion_listen, o); return 0; } #endif if (!o->listen_points){ onion_add_listen_point(o,NULL,NULL,onion_http_new()); ONION_DEBUG("Created default HTTP listen port"); } /// Start listening size_t successful_listened_points=0; onion_listen_point **lp=o->listen_points; while (*lp){ int listen_result=onion_listen_point_listen(*lp); if (!listen_result) { successful_listened_points++; } lp++; } if (!successful_listened_points){ ONION_ERROR("There are no available listen points"); return 1; } if (o->flags&O_ONE){ onion_listen_point **listen_points=o->listen_points; if (listen_points[1]!=NULL){ ONION_WARNING("Trying to use non-poll and non-thread mode with several listen points. Only the first will be listened"); } onion_listen_point *op=listen_points[0]; do{ onion_request *req=onion_request_new(op); if (!req) continue; ONION_DEBUG("Accepted request %p", req); onion_request_set_no_keep_alive(req); int ret; do{ ret=req->connection.listen_point->read_ready(req); }while(ret>=0); ONION_DEBUG("End of request %p", req); onion_request_free(req); //req->connection.listen_point->close(req); }while(((o->flags&O_ONE_LOOP) == O_ONE_LOOP) && op->listenfd>0); } else{ onion_listen_point **listen_points=o->listen_points; while (*listen_points){ onion_listen_point *p=*listen_points; ONION_DEBUG("Adding listen point fd %d to poller", p->listenfd); onion_poller_slot *slot=onion_poller_slot_new(p->listenfd, (void*)onion_listen_point_accept, p); onion_poller_slot_set_type(slot, O_POLL_ALL); onion_poller_add(o->poller, slot); listen_points++; } #ifdef HAVE_PTHREADS ONION_DEBUG("Start polling / listening %p, %p, %p", o->listen_points, *o->listen_points, *(o->listen_points+1)); if (o->flags&O_THREADED){ o->threads=malloc(sizeof(pthread_t)*(o->nthreads-1)); int i; for (i=0;i<o->nthreads-1;i++){ pthread_create(&o->threads[i],NULL,(void*)onion_poller_poll, o->poller); } // Here is where it waits.. but eventually it will exit at onion_listen_stop onion_poller_poll(o->poller); ONION_DEBUG("Closing onion_listen"); for (i=0;i<o->nthreads-1;i++){ pthread_join(o->threads[i],NULL); } } else #endif onion_poller_poll(o->poller); listen_points=o->listen_points; while (*listen_points){ onion_listen_point *p=*listen_points; if (p->listenfd>0){ ONION_DEBUG("Removing %d from poller", p->listenfd); onion_poller_remove(o->poller, p->listenfd); } listen_points++; } } return 0; }
/// There is a bug when posting large files. Introduced when change write 1 by 1, to write by blocks on the FILE parser void t04_post_largefile(){ INIT_LOCAL(); int postfd=open(BIG_FILE, O_RDONLY); off_t filesize=lseek(postfd, 0, SEEK_END); lseek(postfd, 0, SEEK_SET); expected_post post={};; post.filename=BIG_FILE_BASE; post.test_ok=0; // Not ok as not called processor yet post.tmpfilename=NULL; post.size=filesize; 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_HEADER "POST / HTTP/1.1\nContent-Type: multipart/form-data; boundary=end\nContent-Length: %d\n\n--end\nContent-Disposition: text/plain; name=\"file\"; filename=\"" BIG_FILE_BASE "\"\n\n" char tmp[1024]; ONION_DEBUG("Post size is about %d",filesize+73); snprintf(tmp, sizeof(tmp), POST_HEADER, (int)filesize+73); ONION_DEBUG("%s",tmp); onion_request_write(req,tmp,strlen(tmp)); int r=read(postfd, tmp, sizeof(tmp)); while ( r>0 ){ onion_request_write(req, tmp, r); r=read(postfd, tmp, sizeof(tmp)); } onion_request_write(req,"\n--end--",8); FAIL_IF_NOT_EQUAL_INT(post.test_ok,1); #undef POST_HEADER onion_request_clean(req); //post.test_ok=0; // Not ok as not called processor yet lseek(postfd, 0, SEEK_SET); int difffd=open(post.tmpfilename, O_RDONLY); FAIL_IF_NOT_EQUAL_INT(difffd,-1); // Orig file is removed at handler returns. But i have a copy difffd=open(post.tmplink, O_RDONLY); FAIL_IF_EQUAL_INT(difffd,-1); ONION_DEBUG("tmp filename %s",post.tmpfilename); int r1=1, r2=1; char c1=0, c2=0; int p=0; while ( r1 && r2 && c1==c2){ r1=read(difffd, &c1, 1); r2=read(postfd, &c2, 1); //ONION_DEBUG("%d %d",c1,c2); FAIL_IF_NOT_EQUAL_INT(c1,c2); p++; } if ( r1 || r2 ){ ONION_ERROR("At %d",p); FAIL_IF_NOT_EQUAL_INT(r1,0); FAIL_IF_NOT_EQUAL_INT(r2,0); FAIL_IF_NOT_EQUAL_INT(c1,c2); FAIL("Files are different"); } else ONION_DEBUG("Files are ok"); close(difffd); close(postfd); onion_request_free(req); if (post.tmpfilename){ struct stat st; FAIL_IF_EQUAL(stat(post.tmpfilename,&st), 0); // Should not exist } onion_free(server); if (post.tmpfilename) free(post.tmpfilename); if (post.tmplink) free(post.tmplink); END_LOCAL(); }
void init() { server = onion_new(0); onion_add_listen_point(server, NULL, NULL, onion_buffer_listen_point_new()); }