char *t08_thread_read(onion_dict *d){ char done=0; char *ret=NULL; while (!done){ //ONION_DEBUG("Lock read"); onion_dict_lock_write(d); //ONION_DEBUG("Got read lock"); const char *test=onion_dict_get(d,"test"); if (test){ //ONION_DEBUG("Unlock"); //onion_dict_lock_write(d); //ONION_DEBUG("Got write lock"); char tmp[16]; snprintf(tmp,16,"%d",onion_dict_count(d)); onion_dict_remove(d,"test"); onion_dict_add(d,tmp,"test",OD_DUP_ALL); ONION_DEBUG("Write answer %d", onion_dict_count(d)); done=1; //ONION_DEBUG("Unlock"); onion_dict_unlock(d); ret=(char*)1; break; } //ONION_DEBUG("Unlock"); onion_dict_unlock(d); usleep(200); } //ONION_DEBUG("dict free"); onion_dict_free(d); return ret; }
onion_connection_status method(void *ignore, onion_request *req, onion_response *res){ if (onion_response_write_headers(res)==OR_SKIP_CONTENT) // Head return OCS_PROCESSED; onion_response_write0(res, "<html><body>\n<h1>Petition resume</h1>\n"); int flags=onion_request_get_flags(req); if (flags&OR_GET) onion_response_write0(res,"<h2>GET"); else if (flags&OR_POST) onion_response_write0(res,"<h2>POST"); else onion_response_write0(res,"<h2>UNKNOWN"); onion_response_printf(res," %s</h2>\n<ul>",onion_request_get_path(req)); const onion_dict *get=onion_request_get_query_dict(req); const onion_dict *post=onion_request_get_post_dict(req); const onion_dict *headers=onion_request_get_header_dict(req); onion_response_printf(res,"<li>Header %d elements<ul>",onion_dict_count(headers)); if (headers) onion_dict_preorder(headers, print_dict_element, res); onion_response_printf(res,"</ul></li>\n"); onion_response_printf(res,"<li>GET %d elements<ul>",onion_dict_count(get)); if (get) onion_dict_preorder(get, print_dict_element, res); onion_response_printf(res,"</ul></li>\n"); onion_response_printf(res,"<li>POST %d elements<ul>",onion_dict_count(post)); if (post) onion_dict_preorder(post, print_dict_element, res); onion_response_printf(res,"</ul></li>\n"); onion_response_write0(res,"<p>\n"); onion_response_write0(res,"<form method=\"GET\">" "<input type=\"text\" name=\"test\">" "<input type=\"submit\" name=\"submit\" value=\"GET\">" "</form><p>\n"); onion_response_write0(res,"<form method=\"POST\" enctype=\"application/x-www-form-urlencoded\">" "<textarea name=\"text\"></textarea>" "<input type=\"text\" name=\"test\">" "<input type=\"submit\" name=\"submit\" value=\"POST urlencoded\">" "</form>" "<p>\n"); onion_response_write0(res,"<form method=\"POST\" enctype=\"multipart/form-data\">" "<input type=\"file\" name=\"file\">" "<textarea name=\"text\"></textarea>" "<input type=\"text\" name=\"test\">" "<input type=\"submit\" name=\"submit\" value=\"POST multipart\">" "</form>" "<p>\n"); onion_response_write0(res,"</body></html>"); return OCS_PROCESSED; }
// This fixes that whenever a session is created, but no new data is added, it does not set the proper cookie void t04_lot_of_sessionid(){ INIT_LOCAL(); onion *o=onion_new(O_ONE_LOOP); onion_server_set_write(o->server, empty_write); onion_url *url=onion_root_url(o); onion_url_add(url, "^.*", ask_session); char sessionid[256]; char tmp[1024]; char tmp2[4096]; onion_request *req; int i; set_data_on_session=1; req=onion_request_new(o->server, NULL, NULL); req->fullpath="/"; onion_request_process(req); FAIL_IF_NOT_EQUAL_INT(onion_dict_count(o->server->sessions->sessions), 1); FAIL_IF_EQUAL_STR(lastsessionid,""); strcpy(sessionid, lastsessionid); req->fullpath=NULL; onion_request_free(req); req=onion_request_new(o->server, NULL, NULL); req->fullpath="/"; snprintf(tmp,sizeof(tmp)," sessionid=xx%sxx;",lastsessionid); strcpy(tmp2,"Cookie:"); for(i=0;i<64;i++) strncat(tmp2, tmp, sizeof(tmp2)); snprintf(tmp,sizeof(tmp)," sessionid=%s\n",lastsessionid); strncat(tmp2, tmp, sizeof(tmp2)); ONION_DEBUG("Set cookies (%d bytes): %s",strlen(tmp2),tmp2); strcpy(tmp,"GET /\n"); onion_request_write(req,tmp,strlen(tmp)); // Here is the problem, at parsing too long headers onion_request_write(req,tmp2,strlen(tmp2)); // Here is the problem, at parsing too long headers onion_request_write(req,"\n",1); //onion_dict_add(req->headers, "Cookie", tmp2, 0); onion_request_process(req); FAIL_IF_NOT_EQUAL_INT(onion_dict_count(o->server->sessions->sessions), 1); FAIL_IF_EQUAL_STR(lastsessionid,""); FAIL_IF_NOT_EQUAL_STR(lastsessionid, sessionid); FAIL_IF_NOT(has_set_cookie); onion_request_free(req); onion_free(o); END_LOCAL(); }
/** * @short Writes all the header to the given response * @memberof onion_response_t * @ingroup response * * It writes the headers and depending on the method, return OR_SKIP_CONTENT. this is set when in head mode. Handlers * should react to this return by not trying to write more, but if they try this object will just skip those writtings. * * Explicit calling to this function is not necessary, as as soon as the user calls any write function this will * be performed. * * As soon as the headers are written, any modification on them will be just ignored. * * @returns 0 if should procced to normal data write, or OR_SKIP_CONTENT if should not write content. */ int onion_response_write_headers(onion_response * res) { if (!res->request) { ONION_ERROR ("Bad formed response. Need a request at creation. Will not write headers."); return -1; } res->flags |= OR_HEADER_SENT; // I Set at the begining so I can do normal writing. res->request->flags |= OR_HEADER_SENT; char chunked = 0; if (res->request->flags & OR_HTTP11) { onion_response_printf(res, "HTTP/1.1 %d %s\r\n", res->code, onion_response_code_description(res->code)); //ONION_DEBUG("Response header: HTTP/1.1 %d %s\n",res->code, onion_response_code_description(res->code)); if (!(res->flags & OR_LENGTH_SET) && onion_request_keep_alive(res->request)) { onion_response_write(res, CONNECTION_CHUNK_ENCODING, sizeof(CONNECTION_CHUNK_ENCODING) - 1); chunked = 1; } } else { onion_response_printf(res, "HTTP/1.0 %d %s\r\n", res->code, onion_response_code_description(res->code)); //ONION_DEBUG("Response header: HTTP/1.0 %d %s\n",res->code, onion_response_code_description(res->code)); if (res->flags & OR_LENGTH_SET) // On HTTP/1.0, i need to state it. On 1.1 it is default. onion_response_write(res, CONNECTION_KEEP_ALIVE, sizeof(CONNECTION_KEEP_ALIVE) - 1); } if (!(res->flags & OR_LENGTH_SET) && !chunked && !(res->flags & OR_CONNECTION_UPGRADE)) onion_response_write(res, CONNECTION_CLOSE, sizeof(CONNECTION_CLOSE) - 1); if (res->flags & OR_CONNECTION_UPGRADE) onion_response_write(res, CONNECTION_UPGRADE, sizeof(CONNECTION_UPGRADE) - 1); onion_dict_preorder(res->headers, write_header, res); if (res->request->session_id && (onion_dict_count(res->request->session) > 0)) // I have session with something, tell user onion_response_printf(res, "Set-Cookie: sessionid=%s; httponly; Path=/\n", res->request->session_id); onion_response_write(res, "\r\n", 2); ONION_DEBUG0("Headers written"); res->sent_bytes = -res->buffer_pos; // the header size is not counted here. It will add again so start negative. if ((res->request->flags & OR_METHODS) == OR_HEAD) { onion_response_flush(res); res->flags |= OR_SKIP_CONTENT; return OR_SKIP_CONTENT; } if (chunked) { onion_response_flush(res); res->flags |= OR_CHUNKED; } return 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; } }
static onion_connection_status ask_session(void *_, onion_request *req, onion_response *res){ onion_dict *session=onion_request_get_session_dict(req); if (set_data_on_session) onion_dict_add(session,"Test","New data to create the session",0); has_set_cookie=0; onion_response_write0(res, "If I write before getting session, then there is no Set-Cookie.\n"); onion_response_printf(res, "%d elements at the session.\n", onion_dict_count(session)); ONION_DEBUG("Session ID is %s, cookies %s",req->session_id, onion_request_get_header(req, "Cookie")); strcpy(lastsessionid, req->session_id); return OCS_PROCESSED; }
/** * @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); }
/** * @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)); }
/** * @short Count of elements on the dictionary. */ size_t count() const{ return onion_dict_count(ptr); }
// This fixes that whenever a session is created, but no new data is added, it does not set the proper cookie, and should not create a new session. void t03_bug_empty_session_is_new_session(){ INIT_LOCAL(); onion *o=onion_new(O_ONE_LOOP); onion_server_set_write(o->server, empty_write); onion_url *url=onion_root_url(o); onion_url_add(url, "^.*", ask_session); char sessionid[256]; char tmp[256]; set_data_on_session=1; onion_request *req=onion_request_new(o->server, NULL, NULL); req->fullpath="/"; onion_request_process(req); FAIL_IF_EQUAL_STR(lastsessionid,""); strcpy(sessionid, lastsessionid); req->fullpath=NULL; onion_request_free(req); FAIL_IF_NOT_EQUAL_INT(onion_dict_count(o->server->sessions->sessions), 1); req=onion_request_new(o->server, NULL, NULL); req->fullpath="/"; onion_dict_add(req->headers, "Cookie", "sessionid=xxx", 0); onion_request_process(req); FAIL_IF_EQUAL_STR(lastsessionid,""); FAIL_IF_EQUAL_STR(lastsessionid, sessionid); FAIL_IF_NOT(has_set_cookie); req->fullpath=NULL; onion_request_free(req); FAIL_IF_NOT_EQUAL_INT(onion_dict_count(o->server->sessions->sessions), 2); req=onion_request_new(o->server, NULL, NULL); req->fullpath="/"; snprintf(tmp,sizeof(tmp),"sessionid=%s",lastsessionid); onion_dict_add(req->headers, "Cookie", tmp, 0); onion_request_process(req); FAIL_IF_EQUAL_STR(lastsessionid,""); FAIL_IF_EQUAL_STR(lastsessionid, sessionid); FAIL_IF_NOT(has_set_cookie); strcpy(sessionid, lastsessionid); req->fullpath=NULL; onion_request_free(req); FAIL_IF_NOT_EQUAL_INT(onion_dict_count(o->server->sessions->sessions), 2); req=onion_request_new(o->server, NULL, NULL); req->fullpath="/"; snprintf(tmp,sizeof(tmp),"sessionid=%sxx",lastsessionid); onion_dict_add(req->headers, "Cookie", tmp, 0); onion_request_process(req); FAIL_IF_EQUAL_STR(lastsessionid,""); FAIL_IF_EQUAL_STR(lastsessionid, sessionid); FAIL_IF_NOT(has_set_cookie); req->fullpath=NULL; onion_request_free(req); FAIL_IF_NOT_EQUAL_INT(onion_dict_count(o->server->sessions->sessions), 3); // Ask for new, without session data, but I will not set data on session, so session is not created. set_data_on_session=0; req=onion_request_new(o->server, NULL, NULL); req->fullpath="/"; onion_request_process(req); FAIL_IF_EQUAL_STR(lastsessionid,""); strcpy(sessionid, lastsessionid); req->fullpath=NULL; FAIL_IF_NOT_EQUAL_INT(onion_dict_count(o->server->sessions->sessions), 4); // For a moment it exists, until onion realizes is not necesary. onion_request_free(req); FAIL_IF_NOT_EQUAL_INT(onion_dict_count(o->server->sessions->sessions), 3); onion_free(o); END_LOCAL(); }