/** * @short Writes some data to the response. Using sprintf format strings. va_list args version * * @param args va_list of arguments * @memberof onion_response_t */ ssize_t onion_response_vprintf(onion_response *res, const char *fmt, va_list args) { char temp[512]; int l; l=vsnprintf(temp, sizeof(temp), fmt, args); if (l<0) { ONION_ERROR("Invalid vprintf fmt"); return -1; } else if (l<sizeof(temp)) { return onion_response_write(res, temp, l); } else { ssize_t s; char*buf = onion_low_scalar_malloc(l+1); if (!buf){ // this cannot happen, since onion_low_scalar_malloc // handles that error... ONION_ERROR("Could not reserve %d bytes", l+1); return -1; } vsnprintf(buf, l, fmt, args); s = onion_response_write (res, buf, l); onion_low_free (buf); return s; } }
/** * @short Generates a unique id. * @memberof onion_sessions_t * @ingroup sessions * * This unique id is also dificult to guess, so that blind guessing will not work. * * Just now random 32 bytes string with alphanum chars. Not really safe as using simple C rand. * * The memory is malloc'ed and will be freed somewhere. */ char *onion_sessions_generate_id(){ char allowed_chars[]="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; char *ret=onion_low_scalar_malloc(33); onion_random_generate(ret,32); int i; for (i=0;i<32;i++){ ret[i]=allowed_chars[ ret[i]%(sizeof(allowed_chars)-1) ]; } ret[i]='\0'; return ret; }
/** * @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 Prepares the POST */ static onion_connection_status prepare_POST(onion_request *req){ // ok post onion_token *token=req->parser_data; const char *content_type=onion_dict_get(req->headers, "Content-Type"); const char *content_size=onion_dict_get(req->headers, "Content-Length"); if (!content_size){ ONION_ERROR("I need the content size header to support POST data"); return OCS_INTERNAL_ERROR; } size_t cl=atol(content_size); if (cl==0) return OCS_REQUEST_READY; //ONION_DEBUG("Content type %s",content_type); if (!content_type || (strstr(content_type, "application/x-www-form-urlencoded"))){ if (cl>req->connection.listen_point->server->max_post_size){ ONION_ERROR("Asked to send much POST data. Limit %d. Failing.",req->connection.listen_point->server->max_post_size); return OCS_INTERNAL_ERROR; } assert(token->extra==NULL); token->extra=onion_low_scalar_malloc(cl+1); // Cl + \0 token->extra_size=cl; req->free_list=onion_ptr_list_add(req->free_list, token->extra); // Free when the request is freed. req->parser=parse_POST_urlencode; return OCS_NEED_MORE_DATA; } // multipart. const char *mp_token=strstr(content_type, "boundary="); if (!mp_token){ ONION_ERROR("No boundary set at content-type"); return OCS_INTERNAL_ERROR; } mp_token+=9; if (cl>req->connection.listen_point->server->max_post_size) // I hope the missing part is files, else error later. cl=req->connection.listen_point->server->max_post_size; int mp_token_size=strlen(mp_token); token->extra_size=cl; // Max size of the multipart->data onion_multipart_buffer *multipart=onion_low_malloc(token->extra_size+sizeof(onion_multipart_buffer)+mp_token_size+2); assert(token->extra==NULL); token->extra=(char*)multipart; multipart->boundary=(char*)multipart+sizeof(onion_multipart_buffer)+1; multipart->size=mp_token_size+4; multipart->pos=2; // First boundary already have [\r]\n readen multipart->post_total_size=cl; multipart->file_total_size=0; multipart->boundary[0]='\r'; multipart->boundary[1]='\n'; multipart->boundary[2]='-'; multipart->boundary[3]='-'; strcpy(&multipart->boundary[4],mp_token); multipart->data=(char*)multipart+sizeof(onion_multipart_buffer)+multipart->size+1; //ONION_DEBUG("Multipart POST boundary '%s'",multipart->boundary); req->parser=parse_POST_multipart_start; return OCS_NEED_MORE_DATA; }