/** * @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){ 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_dict_free(req->session); // Not really remove, just dereference req->session=NULL; free(req->session_id); req->session_id=NULL; } } if (req->data){ onion_block_free(req->data); req->data=NULL; } if (req->connection.cli_info){ free(req->connection.cli_info); req->connection.cli_info=NULL; } if (req->cookies){ onion_dict_free(req->cookies); req->cookies=NULL; } }
/** * @short Prepares the PUT * * It saves the data to a temporal file, which name is stored at data. */ static onion_connection_status prepare_PUT(onion_request *req){ onion_token *token=req->parser_data; const char *content_size=onion_dict_get(req->headers, "Content-Length"); if (!content_size){ ONION_ERROR("I need the Content-Length header to get data"); return OCS_INTERNAL_ERROR; } size_t cl=atol(content_size); if (cl>req->connection.listen_point->server->max_file_size){ ONION_ERROR("Trying to PUT a file bigger than allowed size"); return OCS_INTERNAL_ERROR; } req->data=onion_block_new(); char filename[]="/tmp/onion-XXXXXX"; int fd=mkstemp(filename); if (fd<0) ONION_ERROR("Could not create temporary file at %s.", filename); onion_block_add_str(req->data, filename); ONION_DEBUG0("Creating PUT file %s (%d bytes long)", filename, token->extra_size); if (!req->FILES){ req->FILES=onion_dict_new(); } { const char *filename=onion_block_data(req->data); onion_dict_add(req->FILES,"filename", filename, 0); } if (cl==0){ ONION_DEBUG0("Created 0 length file"); close(fd); return OCS_REQUEST_READY; } int *pfd=onion_low_scalar_malloc(sizeof(fd)); *pfd=fd; assert(token->extra==NULL); token->extra=(char*)pfd; token->extra_size=cl; token->pos=0; req->parser=parse_PUT; return OCS_NEED_MORE_DATA; }
/** * @short Gets the dict with the cookies * @memberof onion_request_t * * @param req Request to get the cookies from * * @returns A dict with all the cookies. It might be empty. * * First call it generates the dict. */ onion_dict* onion_request_get_cookies_dict(onion_request* req) { if (req->cookies) return req->cookies; req->cookies=onion_dict_new(); const char *ccookies=onion_request_get_header(req, "Cookie"); if (!ccookies) return req->cookies; char *cookies=onion_low_strdup(ccookies); // I prepare a temporary string, will modify it. char *val=NULL; char *key=NULL; char *p=cookies; int first=1; while(*p) { if (*p!=' ' && !key && !val) { key=p; } else if (*p=='=' && key && !val) { *p=0; val=p+1; } else if (*p==';' && key && val) { *p=0; if (first) { // The first cookie is special as it is the pointer to the reserved area for all the keys and values // for all th eother cookies, to free at dict free. onion_dict_add(req->cookies, cookies, val, OD_FREE_KEY); first=0; } else onion_dict_add(req->cookies, key, val, 0); /// Can use as static data as will be freed at first cookie free ONION_DEBUG0("Add cookie <%s>=<%s> %d", key, val, first); val=NULL; key=NULL; } p++; } if (key && val && val<p) { // A final element, with value. if (first) onion_dict_add(req->cookies, cookies, val, OD_FREE_KEY); else onion_dict_add(req->cookies, key, val, 0); ONION_DEBUG0("Add cookie <%s>=<%s> %d", key, val, first); } return req->cookies; }
void t06_null_add(){ INIT_LOCAL(); onion_dict *dict; dict=onion_dict_new(); onion_dict_add(dict,"b",NULL,0); onion_dict_add(dict,"a",NULL,0); onion_dict_add(dict,"c","1",0); FAIL_IF_NOT_EQUAL_STR(onion_dict_get(dict,"c"),"1"); FAIL_IF_NOT_EQUAL(onion_dict_get(dict,"a"),NULL); onion_dict_free(dict); END_LOCAL(); }
/* Replace some template variables (filename of last config) call index_html_template */ onion_connection_status OnionServer::index_html( Onion::Request &req, Onion::Response &res) { /* Problem: This cause double free of mem because * onion_dict_free will called twice: in index_html_template and deconstructor. * Onion::Dict d; std::string key("LAST_SETTING_FILENAME"); d.add(key,m_b9CreatorSettings.m_configFilename,0); return index_html_template(d.c_handler(), req.c_handler(), res.c_handler() ); */ onion_dict *d=onion_dict_new();//will free'd in template call onion_dict_add( d, "LAST_SETTING_FILENAME", m_b9CreatorSettings.m_configFilename.c_str(), 0); return index_html_template(d, req.c_handler(), res.c_handler() ); }
void t14_dict_case_insensitive(){ INIT_LOCAL(); onion_dict *d=onion_dict_new(); onion_dict_add(d,"Test","OK", 0); FAIL_IF_NOT_EQUAL(onion_dict_get(d,"test"),NULL); onion_dict_set_flags(d,OD_ICASE); FAIL_IF_NOT_EQUAL_STR(onion_dict_get(d,"test"),"OK"); onion_dict_free(d); END_LOCAL(); }
/* Replace some template variables and send b9creator_settings.js */ onion_connection_status OnionServer::getB9CreatorSettingsWrapped( Onion::Request &req, Onion::Response &res) { /* std::string key("ONION_JSON"); std::string conf(m_b9CreatorSettings.getConfig()); Onion::Dict d; d.add(key, conf, 0); return b9creator_settings_js_template(d.c_handler(), req.c_handler(), res.c_handler()); */ onion_dict *d=onion_dict_new();//will free'd in template call onion_dict_add( d, "ONION_JSON", m_b9CreatorSettings.getConfig(), 0); return b9creator_settings_js_template(d, req.c_handler(), res.c_handler()); }
/** * @short Creates a request object * @memberof onion_request_t * * @param server onion_server that will be used for writing and some other data * @param socket Socket as needed by onion_server write method. * @param client_info String that describes the client, for example, the IP address. */ onion_request *onion_request_new(onion_server *server, void *socket, const char *client_info){ onion_request *req; req=malloc(sizeof(onion_request)); memset(req,0,sizeof(onion_request)); req->server=server; req->headers=onion_dict_new(); req->socket=socket; if (client_info) // This is kept even on clean req->client_info=strdup(client_info); else req->client_info=NULL; ONION_DEBUG0("Create request %p", req); return req; }
/* Replace some template variables (filename of last config) call index_html_template */ onion_connection_status OnionServer::index_html( Onion::Request &req, Onion::Response &res) { /* Issue note: The following cause double free of mem because * onion_dict_free will called twice: in index_html_template and deconstructor. * Onion::Dict d; std::string key("LAST_SETTING_FILENAME"); d.add(key,m_settingKinect.m_configFilename,0); return index_html_template(d.c_handler(), req.c_handler(), res.c_handler() ); => Thus, use pointer, but do not free here. */ onion_dict *d=onion_dict_new();//will free'd in template call onion_dict_add( d, "LAST_SETTING_FILENAME", m_settingKinect.m_configFilename.c_str(), 0); return index_html_template(d, req.c_handler(), res.c_handler() ); }
/** * @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=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; // Sorry for the publicity. onion_dict_add(res->headers, "Server", "libonion v0.5 - 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; }
void t09_thread_war(){ INIT_LOCAL(); pthread_t thread[NWAR]; int i; onion_dict *d=onion_dict_new(); for (i=0;i<NWAR;i++){ onion_dict *dup=onion_dict_dup(d); pthread_create(&thread[i], NULL, (void*)&t09_thread_war_thread, dup); } onion_dict_free(d); for (i=0;i<NWAR;i++){ pthread_join(thread[i], NULL); } END_LOCAL(); }
void external_html(onion_dict *context, onion_response *res){ #line 1 #line 1 int has_context=(context!=NULL); #line 1 if (!has_context) #line 1 context=onion_dict_new(); #line 1 #line 1 external_html_blocks_init(context); #line 2 onion_response_write(res, "This code is in an external html.\n", 34); #line 2 if (!has_context) #line 2 onion_dict_free(context); #line 1 }
void extended_html(onion_dict *context, onion_response *res){ #line 1 #line 1 int has_context=(context!=NULL); #line 1 if (!has_context) #line 1 context=onion_dict_new(); #line 1 #line 1 extended_html_blocks_init(context); #line 1 base_html(context, res); #line 20 if (!has_context) #line 20 onion_dict_free(context); #line 1 }
void t01_basic(){ INIT_LOCAL(); Onion::Dict normal; normal.add("Hello", "World"); onion_dict *d=onion_dict_new(); onion_dict_add(d, "Hello", "2", 0); Onion::Dict non_owner(d); FAIL_IF_NOT_EQUAL_STRING(non_owner.get("Hello"), "2"); Onion::Dict owner(d, true); FAIL_IF_NOT_EQUAL_STRING(owner.get("Hello"), "2"); non_owner.add("non-owner", "true"); FAIL_IF_NOT_EQUAL_STRING(owner.get("non-owner"), "true"); FAIL_IF_NOT_EQUAL_STRING(onion_dict_get(d,"non-owner"), "true"); END_LOCAL(); }
/** * @short Gets the dict with the cookies * @memberof onion_request_t * * @param req Request to get the cookies from * * @returns A dict with all the cookies. It might be empty. * * First call it generates the dict. */ onion_dict* onion_request_get_cookies_dict(onion_request* req){ if (req->cookies) return req->cookies; req->cookies=onion_dict_new(); const char *ccookies=onion_request_get_header(req, "Cookie"); if (!ccookies) return req->cookies; char *cookies=strdup(ccookies); // I prepare a temporal string, will modify it. char *val=NULL; char *key=NULL; char *p=cookies; int dflags=OD_FREE_KEY; while(*p){ if (*p!=' ' && !key && !val){ key=p; } else if (*p=='=' && key && !val){ *p=0; val=p+1; } else if (*p==';' && key && val){ *p=0; onion_dict_add(req->cookies, key, val, dflags); // I duplicate all as will free cookies string later. ONION_DEBUG0("Add cookie <%s>=<%s> %X", key, val, dflags); dflags=0; // On the first element, remove all data as is in key. val=NULL; key=NULL; } p++; } if (key && val && val<p){ // A final element, with value. onion_dict_add(req->cookies, key, val, dflags); ONION_DEBUG0("Add cookie <%s>=<%s> %X", key, val, dflags); } return req->cookies; }
static onion_connection_status parse_headers_VERSION(onion_request *req, onion_buffer *data){ onion_token *token=req->parser_data; int res=token_read_STRING(token, data); if (res<=1000) return res; if (strcmp(token->str,"HTTP/1.1")==0) req->flags|=OR_HTTP11; if (!req->GET) req->GET=onion_dict_new(); if (res==STRING){ req->parser=parse_headers_KEY_skip_NL; return parse_headers_KEY_skip_NL(req, data); } else{ // STRING_NEW_LINE, only when \n as STRING separator, not \r\n. req->parser=parse_headers_KEY; return parse_headers_KEY(req, data); } }
void t08_threaded_lock(){ INIT_LOCAL(); onion_dict *d=onion_dict_new(); pthread_t thread[N_READERS]; int i; for (i=0;i<N_READERS;i++){ onion_dict *d2=onion_dict_dup(d); pthread_create(&thread[i], NULL, (void*)t08_thread_read, d2); } //sleep(1); t08_thread_write(d); for (i=0;i<N_READERS;i++){ char *v; pthread_join(thread[i],(void**) &v); FAIL_IF_NOT_EQUAL(v, (char *)v); } END_LOCAL(); }
void t07_replace(){ INIT_LOCAL(); onion_dict *dict=onion_dict_new(); onion_dict_add(dict,"a","1", OD_DUP_ALL|OD_REPLACE); onion_dict_add(dict,"a","1", OD_REPLACE); onion_dict_add(dict,"a","1", OD_DUP_ALL|OD_REPLACE); onion_dict_add(dict,"a","1", OD_REPLACE); onion_dict_add(dict,"a","1", OD_DUP_ALL|OD_REPLACE); int n=0; onion_dict_preorder(dict, t07_sum, &n); FAIL_IF_NOT_EQUAL_INT(n,1); onion_dict_add(dict,"a","1", 0); n=0; onion_dict_preorder(dict, t07_sum, &n); FAIL_IF_NOT_EQUAL_INT(n,2); onion_dict_free(dict); END_LOCAL(); }
void t05_preorder(){ INIT_LOCAL(); onion_dict *dict; dict=onion_dict_new(); onion_dict_add(dict,"A","B",0); onion_dict_add(dict,"C","D",0); onion_dict_add(dict,"E","F",0); onion_dict_add(dict,"G","H",0); onion_dict_add(dict,"I","J",0); onion_dict_add(dict,"K","L",0); onion_dict_add(dict,"M","N",0); onion_dict_add(dict,"O","P",0); onion_dict_add(dict,"Q","R",0); onion_dict_add(dict,"S","T",0); char buffer[4096]; memset(buffer,0,sizeof(buffer)); onion_dict_preorder(dict, append_as_headers, buffer); FAIL_IF_NOT_EQUAL_STR(buffer,"A: B\nC: D\nE: F\nG: H\nI: J\nK: L\nM: N\nO: P\nQ: R\nS: T\n"); onion_dict_free(dict); END_LOCAL(); }
/** * @short Parses the query to unquote the path and get the query. */ static int onion_request_parse_query(onion_request *req){ if (!req->fullpath) return 0; if (req->GET) // already done return 1; char *p=req->fullpath; char have_query=0; while(*p){ if (*p=='?'){ have_query=1; break; } p++; } *p='\0'; onion_unquote_inplace(req->fullpath); if (have_query){ // There are querys. p++; req->GET=onion_dict_new(); onion_request_parse_query_to_dict(req->GET, p); } return 1; }
void t01_create_add_free_10(){ INIT_LOCAL(); onion_dict *dict; const char *value; dict=onion_dict_new(); FAIL_IF_EQUAL(dict,NULL); // Get before anything in value=onion_dict_get(dict, "Request"); FAIL_IF_NOT_EQUAL(value,NULL); // basic add int i; char tmp[256]; for (i=0;i<10;i++){ snprintf(tmp,sizeof(tmp),"%d",(i*13)%10); ////ONION_DEBUG("add key %s",tmp); onion_dict_add(dict, tmp, "GET /", OD_DUP_ALL); value=onion_dict_get(dict, tmp); FAIL_IF_NOT_EQUAL_STR(value,"GET /"); //onion_dict_print_dot(dict); } for (i=0;i<10;i++){ snprintf(tmp,sizeof(tmp),"%d",i); ////ONION_DEBUG("rm key %s",tmp); onion_dict_remove(dict, tmp); value=onion_dict_get(dict, tmp); FAIL_IF_NOT_EQUAL(value,NULL); //onion_dict_print_dot(dict); } onion_dict_free(dict); END_LOCAL(); }
void t11_hard_dup(){ INIT_LOCAL(); onion_dict *orig=onion_dict_new(); char tmp[9]; int i; for (i=0;i<256;i++){ sprintf(tmp,"%08X",rand()); onion_dict_add(orig, tmp, tmp, OD_DUP_ALL); } onion_dict_add(orig, "0", "no frees", 0); onion_dict *dest=onion_dict_hard_dup(orig); /// Check they have exactly the same keys. onion_dict_preorder(orig, cmpdict, dest); onion_dict_preorder(dest, cmpdict, orig); onion_dict_free(orig); onion_dict_free(dest); END_LOCAL(); }
/** * @short Creates a full duplicate of the dict * @memberof onion_dict_t * * Its actually the same, but with refcount increased, so future frees will free the dict * only on latest one. * * Any change on one dict is made also on the other one, as well as rwlock... This is usefull on a multhreaded * environment so that multiple threads cna have the same dict and free it when not in use anymore. */ onion_dict *onion_dict_hard_dup(onion_dict *dict){ onion_dict *d=onion_dict_new(); onion_dict_preorder(dict, onion_dict_hard_dup_helper, d); return d; }
/** * @short Inits the tag dict * * It calls the init_tag_builtins to fill the builtins tags. */ void tag_init(){ tag_free(); tags=onion_dict_new(); tag_init_builtins(); }
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(); }
/** * @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; }
/** * @short Creates an empty Onion::Dict */ Dict() : ptr(onion_dict_new()){ // ONION_DEBUG0("Dict %p:%p", this, ptr); }
void t10_tojson(){ INIT_LOCAL(); onion_dict *d=onion_dict_new(); const char *tmp; int s; onion_block *b; b=onion_dict_to_json(d); tmp=onion_block_data(b); ONION_DEBUG("Json returned is '%s'", tmp); FAIL_IF_NOT_EQUAL_STR(tmp,"{}"); onion_block_free(b); onion_dict_add(d, "test", "json", 0); b=onion_dict_to_json(d); tmp=onion_block_data(b); s=onion_block_size(b); ONION_DEBUG("Json returned is '%s'", tmp); FAIL_IF(s<=0); FAIL_IF_EQUAL(strstr(tmp,"{"), NULL); FAIL_IF_EQUAL(strstr(tmp,"}"), NULL); FAIL_IF_EQUAL(strstr(tmp,"\"test\""), NULL); FAIL_IF_EQUAL(strstr(tmp,"\"json\""), NULL); FAIL_IF_NOT_EQUAL(strstr(tmp,","), NULL); onion_block_free(b); onion_dict_add(d, "other", "data", 0); b=onion_dict_to_json(d); tmp=onion_block_data(b); s=onion_block_size(b); ONION_DEBUG("Json returned is '%s'", tmp); FAIL_IF(s<=0); FAIL_IF_EQUAL(strstr(tmp,"{"), NULL); FAIL_IF_EQUAL(strstr(tmp,"}"), NULL); FAIL_IF_EQUAL(strstr(tmp,"\"test\""), NULL); FAIL_IF_EQUAL(strstr(tmp,"\"json\""), NULL); FAIL_IF_EQUAL(strstr(tmp,","), NULL); FAIL_IF_EQUAL(strstr(tmp,"\"other\""), NULL); FAIL_IF_EQUAL(strstr(tmp,"\"data\""), NULL); onion_block_free(b); onion_dict_add(d, "with\"", "data\n", 0); b=onion_dict_to_json(d); tmp=onion_block_data(b); s=onion_block_size(b); ONION_DEBUG("Json returned is '%s'", tmp); FAIL_IF(s<=0); FAIL_IF_EQUAL(strstr(tmp,"\\n"), NULL); FAIL_IF_EQUAL(strstr(tmp,"\\\""), NULL); onion_block_free(b); onion_dict_free(d); END_LOCAL(); }
/** * @short Reads the /etc/mime.types file * * */ static void onion_mime_fill(){ onion_mime_set(NULL); onion_mime_dict=onion_dict_new(); //ONION_DEBUG("Filling mime types"); FILE *fd=fopen("/etc/mime.types", "rt"); if (!fd){ ONION_WARNING("Could not read MIME types (etc/mime.types), returned mime types may be incorrect. Adding minimal set."); onion_dict_add(onion_mime_dict, "html", "text/html",0); onion_dict_add(onion_mime_dict, "htm", "text/html",0); onion_dict_add(onion_mime_dict, "js", "application/javascript",0); onion_dict_add(onion_mime_dict, "css", "text/css",0); onion_dict_add(onion_mime_dict, "png", "image/png",0); onion_dict_add(onion_mime_dict, "jpg", "image/jpeg",0); return; } char mimetype[128]; char extension[8]; int mode=0; // 0 mimetype, 1 extension int i=0; int c; while ( (c=getc(fd)) >= 0){ if (c=='#'){ while ( (c=getc(fd)) >= 0 && c!='\n'); } if (c=='\n'){ if (mode==1 && i!=0){ extension[i]=0; onion_dict_add(onion_mime_dict, extension, mimetype, OD_DUP_ALL); //ONION_DEBUG("Add mimetype '%s' (%s).", extension, mimetype); } mode=0; i=0; } else{ if (is_space(c)){ if (mode==0){ mimetype[i]='\0'; mode=1; i=0; } else if (i!=0){ extension[i]='\0'; i=0; onion_dict_add(onion_mime_dict, extension, mimetype, OD_DUP_ALL); //ONION_DEBUG("Add mimetype '%s' (%s)", extension, mimetype); } } else{ if (mode==0){ if (i>=sizeof(mimetype)-1){ while ( (c=getc(fd)) >= 0 && c!='\n'); } else mimetype[i++]=c; } else{ if (i>=sizeof(extension)-1){ while ( (c=getc(fd)) >= 0 && c!='\n'); extension[i]='\0'; i=0; mode=0; onion_dict_add(onion_mime_dict, extension, mimetype, OD_DUP_ALL); //ONION_DEBUG("Add mimetype '%s' (%s)..", extension, mimetype); } else extension[i++]=c; } } } } fclose(fd); ONION_DEBUG("I know %d mime types", onion_dict_count(onion_mime_dict)); }
onion_dict *onion_dict_from_json_(const char **_data){ const char *data=*_data; ONION_DEBUG("Parse %s", *_data); while (is_json_space(*data)) ++data; if (*data!='{') return NULL; ++data; while (is_json_space(*data)) ++data; ; onion_dict *ret=onion_dict_new(); onion_block *key=onion_block_new(); onion_block *value=onion_block_new(); while (*data!='}'){ // Get Key ssize_t read_bytes=onion_json_unquote_add(key, data); if (read_bytes<0) goto error; data+=read_bytes; while (is_json_space(*data)) ++data; /// Get : if (*data!=':'){ // Includes \0 ONION_DEBUG("Expected : got %c", *data); goto error; } ++data; while (is_json_space(*data)) ++data; /// Get Value if (*data=='{'){ // Includes \0 *_data=data; onion_dict *sub=onion_dict_from_json_(_data); if (!sub){ goto error; } onion_dict_add(ret, onion_block_data(key), sub, OD_DUP_KEY|OD_DICT|OD_FREE_VALUE); data=*_data; } else if (is_json_digit(*data)){ while(is_json_digit(*data)){ onion_block_add_char(value, *data); ++data; } onion_dict_add(ret, onion_block_data(key), onion_block_data(value), OD_DUP_ALL); } else if (*data=='"'){ // parse string ssize_t read_bytes=onion_json_unquote_add(value, data); if (read_bytes<0) goto error; data+=read_bytes; onion_dict_add(ret, onion_block_data(key), onion_block_data(value), OD_DUP_ALL); onion_block_clear(value); } else { // Includes \0 ONION_DEBUG("Expected \" got %c", *data); goto error; } onion_block_clear(key); while (is_json_space(*data)) ++data; if (*data=='}'){ ++data; *_data=data; onion_block_free(key); onion_block_free(value); return ret; } if (*data!=','){ ONION_DEBUG("Expected , got %c", *data); goto error; } ++data; while (is_json_space(*data)) ++data; } ++data; *_data=data; onion_block_free(key); onion_block_free(value); return ret; error: onion_block_free(key); onion_block_free(value); onion_dict_free(ret); return NULL; }