/** * @short Allows to change some properties of the file */ onion_connection_status onion_webdav_proppatch(const char *filename, onion_webdav *wd, onion_request *req, onion_response *res){ xmlDocPtr doc; const onion_block *block=onion_request_get_data(req); ONION_DEBUG("%s",onion_block_data(block)); if (!block) return OCS_INTERNAL_ERROR; doc = xmlParseMemory((char*)onion_block_data(block), onion_block_size(block)); xmlNode *root = NULL; root = xmlDocGetRootElement(doc); int ok=0; while (root){ ONION_DEBUG("%s", root->name); if (strcmp((const char*)root->name,"propertyupdate")==0){ xmlNode *propertyupdate = root->children; while (propertyupdate){ ONION_DEBUG("%s", propertyupdate->name); if (strcmp((const char*)propertyupdate->name,"set")==0){ xmlNode *set = propertyupdate->children; while (set){ ONION_DEBUG("%s", set->name); if (strcmp((const char*)set->name,"prop")==0){ ONION_DEBUG("in prop"); xmlNode *prop = set->children; while (prop){ ONION_DEBUG("prop %s", prop->name); if (strcmp((const char*)prop->name,"executable")==0){ ONION_DEBUG("Setting executable %s", prop->children->content); struct stat st; stat(filename, &st); if (toupper(prop->children->content[0])=='T'){ chmod(filename, st.st_mode | S_IXUSR | S_IXGRP | S_IXOTH); } else{ chmod(filename, st.st_mode & ~( S_IXUSR | S_IXGRP | S_IXOTH) ); } ok=1; } prop=prop->next; } } set=set->next; } } propertyupdate=propertyupdate->next; } } root=root->next; } xmlFreeDoc(doc); if (ok){ onion_response_write_headers(res); return OCS_PROCESSED; } else{ return OCS_INTERNAL_ERROR; } }
void t02_several_add_methods(){ INIT_TEST(); onion_block *block=onion_block_new(); FAIL_IF_EQUAL(block, NULL); int i; for (i=0;i<1024;i++){ onion_block_add_char(block, (char)i); } onion_block_clear(block); onion_block_add_str(block, "first "); for (i=0;i<1024;i++) onion_block_add_str(block, "test "); FAIL_IF_NOT_STRSTR(onion_block_data(block), "test"); for (i=0;i<1024;i++) onion_block_add_data(block, "world", 4); FAIL_IF_STRSTR(onion_block_data(block), "world"); FAIL_IF_NOT_STRSTR(onion_block_data(block), "worl"); int s=onion_block_size(block); onion_block_add_block(block, block); FAIL_IF_NOT_EQUAL(onion_block_size(block), s+s); onion_block_free(block); END_TEST(); }
/// Writes the desired function to st->out static void function_write(parser_status *st, function_data *d){ if (d->code){ if (use_orig_line_numbers) fprintf(st->out, "#line 1\n"); if (d->is_static) fprintf(st->out, "static "); fprintf(st->out, "void %s(%s){\n", d->id, d->signature ? d->signature : "onion_dict *context, onion_response *res" ); if (use_orig_line_numbers){ fprintf(st->out, "#line 1\n"); // Write code, but change \n\n to \n const char *data=onion_block_data(d->code); int ldata=onion_block_size(d->code); int i=0, li=0; char lc=0; for (i=0;i<ldata;i++){ if (data[i]=='\n' && lc=='\n'){ // Two in a row fwrite(&data[li], 1, i-li-1, st->out); li=i; } lc=data[i]; } fwrite(&data[li], 1, i-li, st->out); fprintf(st->out, "#line 1\n"); } else{ fwrite(onion_block_data(d->code), 1, onion_block_size(d->code), st->out); } fprintf(st->out,"}\n"); } }
void POST_a_lot(void) { sleep(1); onion_block *tosend = onion_block_new(); onion_block_add_str(tosend, "POST /configuration HTTP/1.1\nHost: example.com\nContent-Type: x-application/garbage\nContent-Length: 1000000\n\n"); { int i; onion_block *bl = onion_block_new(); for (i = 0; i < 1000; i++) { onion_block_add_char(bl, rand() & 255); } for (i = 0; i < 1000; i++) { onion_block_add_block(tosend, bl); } onion_block_free(bl); } onion_block *bl = connect_and_send("127.0.0.1", "8080", tosend, 1024 * 64); onion_block_free(tosend); ONION_DEBUG("%p", strstr(onion_block_data(bl), "\n1000000\n")); FAIL_IF_NOT(strstr(onion_block_data(bl), "\n1000000\n") != NULL); onion_block_free(bl); }
onion_connection_status process_request(void *_, onion_request * req, onion_response * res) { onion_response_write0(res, "Done"); const onion_block *data = onion_request_get_data(req); FAIL_IF_NOT(data); FAIL_IF_NOT_EQUAL_STR(onion_block_data(data), "{\n \"a\": \"10\",\n \"b\": \"20\"\n}"); ONION_DEBUG(onion_block_data(data)); return OCS_PROCESSED; }
/** * @short Handles a propfind * * @param path the shared path. */ onion_connection_status onion_webdav_propfind(const char *filename, onion_webdav *wd, onion_request* req, onion_response* res){ // Prepare the basepath, necesary for props. char *basepath=NULL; int pathlen=0; const char *current_path=onion_request_get_path(req); const char *fullpath=onion_request_get_fullpath(req); pathlen=(current_path-fullpath); basepath=alloca(pathlen+1); memcpy(basepath, fullpath, pathlen+1); ONION_DEBUG0("Pathbase initial <%s> %d", basepath, pathlen); while(basepath[pathlen]=='/' && pathlen>0) pathlen--; basepath[pathlen+1]=0; ONION_DEBUG0("PROPFIND; pathbase %s", basepath); int depth; { const char *depths=onion_request_get_header(req, "Depth"); if (!depths){ ONION_ERROR("Missing Depth header on webdav request"); return OCS_INTERNAL_ERROR; } if (strcmp(depths,"infinity")==0){ ONION_ERROR("Infinity depth not supported yet."); return OCS_INTERNAL_ERROR; } depth=atoi(depths); } int props=onion_webdav_parse_propfind(onion_request_get_data(req)); ONION_DEBUG("Asking for props %08X, depth %d", props, depth); onion_block *block=onion_webdav_write_propfind(basepath, filename, onion_request_get_path(req), depth, props); if (!block) // No block, resource does not exist return onion_shortcut_response("Not found", HTTP_NOT_FOUND, req, res); ONION_DEBUG0("Printing block %s", onion_block_data(block)); onion_response_set_header(res, "Content-Type", "text/xml; charset=\"utf-8\""); onion_response_set_length(res, onion_block_size(block)); onion_response_set_code(res, HTTP_MULTI_STATUS); onion_response_write_headers(res); onion_response_flush(res); onion_response_write(res, onion_block_data(block), onion_block_size(block)); onion_block_free(block); return OCS_PROCESSED; }
void t18_json_escape_codes(){ INIT_LOCAL(); onion_dict *d=onion_dict_from_json("{ \"hello\": \"Hello\\nworld\", \"second\":\"second\" }"); FAIL_IF_NOT_STRSTR(onion_dict_get(d, "hello"), "Hello\nworld"); FAIL_IF_NOT_STRSTR(onion_dict_get(d, "second"), "second"); onion_dict_free(d); d=onion_dict_from_json("{ \"hello\": \"\\uD83D\\uDE02\" }"); FAIL_IF_NOT_STRSTR(onion_dict_get(d, "hello"), "😂"); onion_dict_free(d); d=onion_dict_from_json("{ \"hello\": \"\\uD83D\\uDE03\" }"); // Another code point FAIL_IF_STRSTR(onion_dict_get(d, "hello"), "😂"); onion_dict_free(d); d=onion_dict_from_json("{ \"hello\": \"\\u007b\" }"); // simple unicode FAIL_IF_NOT_STRSTR(onion_dict_get(d, "hello"), "{"); onion_dict_free(d); d=onion_dict_from_json("{ \"hello\": \"\\\"Quote\" }"); // Escape quote FAIL_IF_NOT_STRSTR(onion_dict_get(d, "hello"), "\"Quote"); onion_dict_free(d); d=onion_dict_from_json("{ \"hello\": \"\"Quote\" }"); // Must fail FAIL_IF_NOT_EQUAL(d, NULL); d=onion_dict_new(); onion_dict_add(d, "hello", "Hello\nWorld\\", 0); onion_dict_add(d, "second", "123", 0); onion_block *b=onion_dict_to_json(d); FAIL_IF_NOT_EQUAL_STR(onion_block_data(b),"{\"hello\":\"Hello\\nWorld\\\\\", \"second\":\"123\"}"); onion_block_free(b); onion_dict_free(d); d=onion_dict_new(); onion_dict_add(d, "hello", "😂\t\n😂", 0); b=onion_dict_to_json(d); FAIL_IF_NOT_EQUAL_STR(onion_block_data(b),"{\"hello\":\"😂\\t\\n😂\"}"); onion_block_free(b); onion_dict_free(d); d=onion_dict_new(); onion_dict_add(d, "hello", "\02\03\x7f", 0); b=onion_dict_to_json(d); FAIL_IF_NOT_EQUAL_STR(onion_block_data(b),"{\"hello\":\"\\u0002\\u0003\\u007F\"}"); onion_block_free(b); onion_dict_free(d); 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(); }
/** * @short Reads from the data to fulfill content-length data. * * All data is writen a temporal file, which will be removed later. */ static onion_connection_status parse_PUT(onion_request *req, onion_buffer *data){ onion_token *token=req->parser_data; int length=data->size-data->pos; int exit=0; if (length>=token->extra_size-token->pos){ exit=1; length=token->extra_size-token->pos; } //ONION_DEBUG0("Writing %d. %d / %d bytes", length, token->pos+length, token->extra_size); int *fd=(int*)token->extra; ssize_t w=write(*fd, &data->data[data->pos], length); if (w<0){ ONION_ERROR("Could not write all data to temporal file."); return OCS_INTERNAL_ERROR; } data->pos+=length; token->pos+=length; #if __DEBUG__ const char *filename=onion_block_data(req->data); ONION_DEBUG0("Done with PUT. Created %s (%d bytes)", filename, token->pos); #endif if (exit){ close (*fd); free(fd); token->extra=NULL; return onion_request_process(req); } return OCS_NEED_MORE_DATA; }
/** * @short One block read from in, prepare the output. * * Depending on the mode of the block it calls the appropiate handler: variable, tag or just write text. */ void write_block(parser_status *st, onion_block *b){ int mode=st->last_wmode; //ONION_DEBUG("Write mode %d, code %s", mode, b->data); switch(mode){ case TEXT: { int oldl; if ( (oldl=onion_block_size(b)) ){ char *safe=onion_c_quote_new(onion_block_data(b)); function_add_code(st, " onion_response_write(res, %s, %d);\n", safe, oldl); free(safe); } } break; case VARIABLE: variable_write(st, b); break; case TAG: tag_write(st, b); break; default: ONION_ERROR("Unknown final mode %d", mode); } onion_block_clear(st->rawblock); }
/** * @short Returns the set of props for this query * * The block contains the propfind xml, and it returns the mask of props to show. * */ static int onion_webdav_parse_propfind(const onion_block *block){ // For parsing the data xmlDocPtr doc; doc = xmlParseMemory((char*)onion_block_data(block), onion_block_size(block)); if (doc == NULL) { ONION_ERROR("Error: unable to parse OPTIONS"); return OCS_INTERNAL_ERROR; } int props=0; xmlNode *root = NULL; root = xmlDocGetRootElement(doc); while (root){ if (strcmp((const char*)root->name,"propfind")==0){ xmlNode *propfind = root->children; while (propfind){ if (strcmp((const char*)propfind->name,"prop")==0){ xmlNode *prop = propfind->children; while (prop){ if (strcmp((const char*)prop->name, "text")==0) // ignore ; else if (strcmp((const char*)prop->name, "resourcetype")==0) props|=WD_RESOURCE_TYPE; else if (strcmp((const char*)prop->name, "getcontentlength")==0) props|=WD_CONTENT_LENGTH; else if (strcmp((const char*)prop->name, "getlastmodified")==0) props|=WD_LAST_MODIFIED; else if (strcmp((const char*)prop->name, "creationdate")==0) props|=WD_CREATION_DATE; else if (strcmp((const char*)prop->name, "getetag")==0) props|=WD_ETAG; else if (strcmp((const char*)prop->name, "getcontenttype")==0) props|=WD_CONTENT_TYPE; else if (strcmp((const char*)prop->name, "displayname")==0) props|=WD_DISPLAY_NAME; else if (strcmp((const char*)prop->name, "executable")==0) props|=WD_EXECUTABLE; else{ char tmp[256]; snprintf(tmp,sizeof(tmp),"g0:%s", prop->name); ONION_DEBUG("Unknown requested property with tag %s", prop->name); } prop=prop->next; } } propfind=propfind->next; } } root=root->next; } xmlFreeDoc(doc); return props; }
/** * @short Parses a block variable and writes the code necesary. * * It can go deep inside a dict or list, and apply filters. */ void variable_write(parser_status *st, onion_block *b){ function_add_code(st, " {\n" " const char *tmp;\n"); variable_solve(st, onion_block_data(b), "tmp", STRING); function_add_code(st, " if (tmp)\n" " onion_response_write_html_safe(res, tmp);\n" " }\n"); }
/** * @short Shortcut to answer some json data * * It converts to json the passed dict and returns it. The dict is freed before returning. */ onion_connection_status onion_shortcut_response_json(onion_dict *d, onion_request *req, onion_response *res){ onion_response_set_header(res, "Content-Type", "application/json"); onion_block *bl=onion_dict_to_json(d); onion_dict_free(d); char tmp[16]; snprintf(tmp,sizeof(tmp),"%ld",(long)onion_block_size(bl)); int ret=onion_shortcut_response_extra_headers(onion_block_data(bl), HTTP_OK, req, res, "Content-Length", tmp, NULL); onion_block_free(bl); return ret; }
void POST_json(void) { sleep(1); onion_block *tosend = onion_block_new(); onion_block_add_str(tosend, "POST /configuration HTTP/1.1\nHost: example.com\nContent-Type: application/json\nContent-Length: 30\n\n" "{\n \"a\": \"10\",\n \"b\": \"20\"\n}"); onion_block *bl = connect_and_send("127.0.0.1", "8080", tosend, 1024 * 1024); FAIL_IF_NOT(strstr(onion_block_data(bl), "Done")); onion_block_free(bl); onion_block_free(tosend); }
void t12_dict_in_dict(){ INIT_LOCAL(); onion_dict *A=onion_dict_new(); onion_dict *B=onion_dict_new(); onion_dict *C=onion_dict_new(); onion_dict *D=onion_dict_new(); int i; for (i=0;i<16;i++){ char tmp[9]; sprintf(tmp,"%08X",rand()); onion_dict_add(A, tmp, tmp, OD_DUP_ALL); sprintf(tmp,"%08X",rand()); onion_dict_add(B, tmp, tmp, OD_DUP_ALL); sprintf(tmp,"%08X",rand()); onion_dict_add(C, tmp, tmp, OD_DUP_ALL); sprintf(tmp,"%08X",rand()); onion_dict_add(D, tmp, tmp, OD_DUP_ALL); } onion_dict_add(A, "B", B, OD_DICT|OD_FREE_VALUE); onion_dict_add(A, "C", C, OD_DICT|OD_FREE_VALUE); onion_dict_add(A, "D", D, OD_DICT|OD_FREE_VALUE); FAIL_IF_NOT_EQUAL((onion_dict*)onion_dict_get(A, "B"), NULL); FAIL_IF_NOT_EQUAL((onion_dict*)onion_dict_get(A, "C"), NULL); FAIL_IF_NOT_EQUAL((onion_dict*)onion_dict_get(A, "D"), NULL); FAIL_IF_NOT_EQUAL((onion_dict*)onion_dict_get_dict(A, "B"), B); FAIL_IF_NOT_EQUAL((onion_dict*)onion_dict_get_dict(A, "C"), C); FAIL_IF_NOT_EQUAL((onion_dict*)onion_dict_get_dict(A, "D"), D); { onion_block *tmpA=onion_dict_to_json(A); onion_block *tmpB=onion_dict_to_json(B); onion_block *tmpC=onion_dict_to_json(C); onion_block *tmpD=onion_dict_to_json(D); /* ONION_DEBUG("Json is: %s",tmpA); ONION_DEBUG("Json is: %s",tmpB); ONION_DEBUG("Json is: %s",tmpC); ONION_DEBUG("Json is: %s",tmpD); */ FAIL_IF_EQUAL( strstr(onion_block_data(tmpA), onion_block_data(tmpB)), NULL); FAIL_IF_EQUAL( strstr(onion_block_data(tmpA), onion_block_data(tmpC)), NULL); FAIL_IF_EQUAL( strstr(onion_block_data(tmpA), onion_block_data(tmpD)), NULL); onion_block_free(tmpA); onion_block_free(tmpB); onion_block_free(tmpC); onion_block_free(tmpD); } B=onion_dict_hard_dup(A); onion_dict_free(A); onion_dict_free(B); END_LOCAL(); }
/// Writes the desired function to st->out static void function_write(parser_status * st, function_data * d) { ONION_DEBUG("Write function %s", d->id); if (d->code) { if (use_orig_line_numbers) fprintf(st->out, "#line 1\n"); if (d->is_static) fprintf(st->out, "static "); fprintf(st->out, "void %s(%s){\n", d->id, d->signature ? d->signature : "onion_dict *context, onion_response *res"); const char *data = onion_block_data(d->code); int ldata = onion_block_size(d->code); if (use_orig_line_numbers) { fprintf(st->out, "#line 1\n"); // Write code, but change \n\n to \n int i = 0, li = 0, diff; char lc = 0; ssize_t r; for (i = 0; i < ldata; i++) { if (data[i] == '\n' && lc == '\n') { // Two in a row diff = i - li - 1; r = fwrite(&data[li], 1, diff, st->out); if (r != diff) { ONION_ERROR("Could not write all data"); abort(); } li = i; } lc = data[i]; } diff = i - li; r = fwrite(&data[li], 1, diff, st->out); if (r != diff) { ONION_ERROR("Could not write all data"); abort(); } fprintf(st->out, "#line 1\n"); } else { ssize_t r = fwrite(data, 1, ldata, st->out); if (r != ldata) { ONION_ERROR("Could not write all data"); abort(); } } fprintf(st->out, "}\n"); } }
/** * @short One block read from in, prepare the output. * * Depending on the mode of the block it calls the appropiate handler: variable, tag or just write text. */ void write_block(parser_status *st, onion_block *b){ int mode=st->last_wmode; //ONION_DEBUG("Write mode %d, code %s", mode, b->data); switch(mode){ case TEXT: { int oldl; if ( (oldl=onion_block_size(b)) ){ if (oldl>0){ // Not Just \0 int use_orig_line_numbers_bak=use_orig_line_numbers; use_orig_line_numbers=0; char *safe=onion_c_quote_new(onion_block_data(b)); function_add_code(st, " onion_response_write(res, "); int pos=0; int size=strlen(safe); char *s=safe; //ONION_DEBUG("------- pos %d, size %d",pos,size); while (pos<size){ //ONION_DEBUG("pos %d, size %d",pos,size); char *e=strstr(s, "\n"); if (!e) break; *e='\0'; if (pos==0) function_add_code(st, "%s\n", s); else function_add_code(st, " %s\n", s); pos+=(e-s)+1; s=e+1; } if (pos==0) function_add_code(st, "%s, %d);\n", s, oldl); else function_add_code(st, " %s, %d);\n", s, oldl); use_orig_line_numbers=use_orig_line_numbers_bak; free(safe); } } } break; case VARIABLE: variable_write(st, b); break; case TAG: tag_write(st, b); break; default: ONION_ERROR("Unknown final mode %d", mode); } onion_block_clear(st->rawblock); }
void onion_sessions_redis_save(onion_sessions *sessions, const char *session_id, onion_dict* data) { onion_block *bl = onion_dict_to_json(data); ONION_DEBUG0("Save session %s: %s", session_id, onion_block_data(bl)); onion_session_redis *p = sessions->data; #ifdef HAVE_PTHREADS pthread_mutex_lock(&p->mutex); #endif if(p == NULL) { redisReply* reply = redisCommand(p->context, "HDEL SESSIONS %b", session_id, strlen(session_id)); if(reply->type != REDIS_REPLY_INTEGER) { ONION_ERROR("Error removing session"); } freeReplyObject(reply); } else { const char* json = onion_block_data(bl); redisReply* reply = redisCommand(p->context, "HSET SESSIONS %b %b", session_id, strlen(session_id), json, strlen(json)); if(reply->type != REDIS_REPLY_INTEGER) { ONION_ERROR("Error saving session"); } freeReplyObject(reply); onion_block_free(bl); } #ifdef HAVE_PTHREADS pthread_mutex_unlock(&p->mutex); #endif return; }
/** * @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; }
void onion_sessions_sqlite3_save(onion_sessions *sessions, const char *session_id, onion_dict *data){ onion_block *bl=onion_dict_to_json(data); ONION_DEBUG0("Save session %s: %s", session_id, onion_block_data(bl)); const char *json=onion_block_data(bl); int rc; onion_session_sqlite3 *p=sessions->data; #ifdef HAVE_PTHREADS pthread_mutex_lock(&p->mutex); #endif sqlite3_reset(p->save); rc=sqlite3_bind_text(p->save, 1, session_id, -1, SQLITE_STATIC); if( rc!=SQLITE_OK ){ ONION_ERROR("Error binding session_id"); goto error; } rc=sqlite3_bind_text(p->save, 2, json, -1, SQLITE_STATIC); if( rc!=SQLITE_OK ){ ONION_ERROR("Error binding json data"); goto error; } rc=sqlite3_step(p->save); if( rc!=SQLITE_DONE ){ ONION_ERROR("Error saving session (%d)", rc); goto error; } ONION_DEBUG0("Session saved"); error: onion_block_free(bl); #ifdef HAVE_PTHREADS pthread_mutex_unlock(&p->mutex); #endif return; }
/** * @short Handles a propfind * * @param path the shared path. */ onion_connection_status onion_webdav_propfind(const char *filename, onion_webdav *wd, onion_request* req, onion_response* res){ ONION_DEBUG0("PROPFIND"); int depth; { const char *depths=onion_request_get_header(req, "Depth"); if (!depths){ ONION_ERROR("Missing Depth header on webdav request"); return OCS_INTERNAL_ERROR; } if (strcmp(depths,"infinity")==0){ ONION_ERROR("Infinity depth not supported yet."); return OCS_INTERNAL_ERROR; } depth=atoi(depths); } int props=onion_webdav_parse_propfind(onion_request_get_data(req)); ONION_DEBUG("Asking for props %08X, depth %d", props, depth); onion_block *block=onion_webdav_write_propfind(filename, onion_request_get_path(req), depth, props); if (!block) // No block, resource does not exist return onion_shortcut_response("Not found", HTTP_NOT_FOUND, req, res); ONION_DEBUG0("Printing block %s", onion_block_data(block)); onion_response_set_header(res, "Content-Type", "text/xml; charset=\"utf-8\""); onion_response_set_length(res, onion_block_size(block)); onion_response_set_code(res, HTTP_MULTI_STATUS); onion_response_write(res, onion_block_data(block), onion_block_size(block)); onion_block_free(block); return OCS_PROCESSED; }
/** * @short Simple put on webdav is just move a file from tmp to the final destination (or copy if could not move). * */ onion_connection_status onion_webdav_put(const char *filename, onion_webdav *wd, onion_request *req, onion_response *res){ ONION_DEBUG("Webdav puts %s", filename); const char *tmpfile=onion_block_data(onion_request_get_data(req)); int ok=onion_shortcut_rename(tmpfile, filename); if (ok==0){ ONION_DEBUG("Created %s succesfully", filename); return onion_shortcut_response("201 Created", 201, req, res); } else{ ONION_ERROR("Could not rename %s to %s (%s)", tmpfile, filename, strerror(errno)); return onion_shortcut_response("Could not create resource", HTTP_FORBIDDEN, req, res); } }
void check_tests(onion_block *data, struct tests_call_otemplate *test){ memset(test, 0, sizeof(*test)); const char *tmp=onion_block_data(data); test->ok_title=test->ok_list=test->ok_hello=test->ok_title_title=0; if (strstr(tmp, "TITLE")) test->ok_title=1; if (strstr(tmp,"LIST")) test->ok_list=1; if (strstr(tmp,"{hello}")) test->ok_hello=1; if (strstr(tmp,"TITLE TITLE")) test->ok_title_title=1; if (strstr(tmp,"<"Hello>")) test->ok_encoding=1; if (strstr(tmp,"internal loop")) test->ok_internal_loop=1; }
/** * @short Main webdav handler, just redirects to the proper handler depending on headers and method */ onion_connection_status onion_webdav_handler(onion_webdav *wd, onion_request *req, onion_response *res){ onion_response_set_header(res, "Dav", "1,2"); onion_response_set_header(res, "MS-Author-Via", "DAV"); #ifdef __DEBUG__ const onion_block *data=onion_request_get_data(req); if (data){ ONION_DEBUG0("Have data!\n %s", onion_block_data(data)); } #endif char filename[512]; snprintf(filename, sizeof(filename), "%s/%s", wd->path, onion_request_get_path(req)); ONION_DEBUG("Check %s and %s", wd->path, filename); if (wd->check_permissions(wd->path, filename, req)!=0){ return onion_shortcut_response("Forbidden", HTTP_FORBIDDEN, req, res); } switch (onion_request_get_flags(req)&OR_METHODS){ case OR_GET: case OR_HEAD: return onion_webdav_get(filename, wd, req, res); case OR_OPTIONS: return onion_webdav_options(filename, wd, req, res); case OR_PROPFIND: return onion_webdav_propfind(filename, wd, req, res); case OR_PUT: return onion_webdav_put(filename, wd, req, res); case OR_DELETE: return onion_webdav_delete(filename, wd, req, res); case OR_MOVE: return onion_webdav_move(filename, wd, req, res); case OR_MKCOL: return onion_webdav_mkcol(filename, wd, req, res); case OR_PROPPATCH: return onion_webdav_proppatch(filename, wd, req, res); } onion_response_set_code(res, HTTP_NOT_IMPLEMENTED); onion_response_write0(res, "<h1>Work in progress...</h1>\n"); return OCS_PROCESSED; }
onion_connection_status post_json_check(json_response *post, onion_request *req, onion_response *res){ post->processed=1; FAIL_IF_NOT_EQUAL_INT(onion_request_get_flags(req)&OR_METHODS, OR_POST); FAIL_IF_NOT_EQUAL_STR(onion_request_get_header(req, "Content-Type"),"application/json"); const onion_block *data=onion_request_get_data(req); FAIL_IF_EQUAL(data, NULL); if (!data) return OCS_INTERNAL_ERROR; FAIL_IF_NOT_EQUAL_INT(onion_block_size(data), sizeof(JSON_EXAMPLE)); FAIL_IF_NOT_EQUAL_INT(memcmp(onion_block_data(data), JSON_EXAMPLE, sizeof(JSON_EXAMPLE)), 0); post->processed=2; return OCS_PROCESSED; }
/** * @short Adds some code to the top function */ void function_add_code(parser_status *st, const char *fmt, ...){ function_data *p=(function_data*)st->function_stack->tail->data; if (p->flags&F_NO_MORE_WRITE) return; char tmp[4096]; va_list ap; va_start(ap, fmt); vsnprintf(tmp, sizeof(tmp), fmt, ap); va_end(ap); if (use_orig_line_numbers){ char line[32]; int p=onion_block_size(st->current_code); if (p && onion_block_data(st->current_code)[p-1]!='\n') onion_block_add_char(st->current_code, '\n'); snprintf(line,sizeof(line),"#line %d\n", st->line); // I have to do it for every \n too. This is going to be slow. const char *orig=tmp; int lorig=strlen(orig); int i=0, li=0; for (i=0;i<lorig;i++){ if (orig[i]=='\n'){ onion_block_add_str(st->current_code, line); onion_block_add_data(st->current_code, &orig[li], i-li+1); li=i; } } if (i-1!=li){ onion_block_add_str(st->current_code, line); onion_block_add_str(st->current_code, &orig[li]); } } else{ //ONION_DEBUG("Add to level %d text %s",list_count(st->function_stack), tmp); onion_block_add_str(st->current_code, tmp); } }
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(); }
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; }
onion_block *connect_and_send(const char *ip, const char *port, const onion_block * msg, size_t maxsize) { int fd; { struct addrinfo hints; struct addrinfo *server; memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_socktype = SOCK_STREAM; hints.ai_family = AF_UNSPEC; hints.ai_flags = AI_PASSIVE | AI_NUMERICSERV; if (getaddrinfo(ip, port, &hints, &server) < 0) { ONION_ERROR("Error getting server info"); return NULL; } fd = socket(server->ai_family, server->ai_socktype | SOCK_CLOEXEC, server->ai_protocol); if (connect(fd, server->ai_addr, server->ai_addrlen) == -1) { close(fd); fd = -1; ONION_ERROR("Error connecting to server %s:%s", ip, port); return NULL; } freeaddrinfo(server); } size_t left = onion_block_size(msg); const char *data = onion_block_data(msg); while (left > 0) { ONION_DEBUG("."); int towrite = (left > maxsize) ? maxsize : left; int ret = write(fd, data, towrite); FAIL_IF(ret <= 0); if (ret <= 0) { ONION_ERROR("Error sending data."); return NULL; } left -= ret; data += ret; } onion_block *bl = onion_block_new(); char tmp[256]; int r = 0; int total = 0; do { r = read(fd, tmp, sizeof(tmp)); ONION_DEBUG("+ %d", r); if (r > 0) { total += r; onion_block_add_data(bl, tmp, r); } } while (r > 0); ONION_DEBUG("Total %d", total); FAIL_IF(total == 0); close(fd); return bl; }
/** * @short Converts the dictionary to a JSON string. */ std::string toJSON() const{ onion_block *bl=onion_dict_to_json(ptr); std::string str=onion_block_data(bl); onion_block_free(bl); return str; }