/** * @short Deletes a resource */ onion_connection_status onion_webdav_delete(const char *filename, onion_webdav *wd, onion_request *req, onion_response *res){ ONION_DEBUG("Webdav delete %s", filename); int error=remove(filename); if (error==0) return onion_shortcut_response("Deleted", HTTP_OK, req, res); else{ ONION_ERROR("Could not remove WebDAV resource"); return onion_shortcut_response("Could not delete resource", HTTP_INTERNAL_ERROR, req, res); } }
/// Sets internally the window title, for reference. int oterm_title(process *p, onion_request* req, onion_response *res){ const char *t=onion_request_get_post(req, "title"); if (!t) return onion_shortcut_response("Error, must set title", HTTP_INTERNAL_ERROR, req, res); if (p->title) free(p->title); p->title=strdup(t); ONION_DEBUG("Set term %d title %s", p->pid, p->title); return onion_shortcut_response("OK", HTTP_OK, req, res); }
/** * @short Moves a resource */ onion_connection_status onion_webdav_move(const char *filename, onion_webdav *wd, onion_request *req, onion_response *res){ const char *dest=onion_request_get_header(req,"Destination"); if (!dest) return OCS_INTERNAL_ERROR; const char *dest_orig=dest; // Skip the http... part. Just 3 /. int i; for (i=0;i<3;i+=(*dest++=='/')) if (*dest==0) return OCS_INTERNAL_ERROR; dest--; const char *fullpath=onion_request_get_fullpath(req); const char *partialpath=onion_request_get_path(req); // Not the fixed URL part for this handler. int fpl=strlen(fullpath); // Full path length int ppl=strlen(onion_request_get_path(req)); // Partial, the fullpath[fpl-ppl] is the end point of the handler path if (strncmp(fullpath, dest, fpl-ppl)!=0){ char tmp[512]; int l=fpl-ppl < sizeof(tmp)-1 ? fpl-ppl : sizeof(tmp)-1; strncpy(tmp, fullpath, l); tmp[l]=0; ONION_WARNING("Move to out of this webdav share! (%s is out of %s)", dest, tmp); return onion_shortcut_response("Moving out of shared share", HTTP_FORBIDDEN, req, res); } dest=&dest[fpl-ppl]; char orig[512]; snprintf(orig, sizeof(orig), "%s/%s", wd->path, partialpath); if (wd->check_permissions(wd->path, orig, req)!=0){ return onion_shortcut_response("Forbidden", HTTP_FORBIDDEN, req, res); } const char *fdest=filename; ONION_INFO("Move %s to %s (webdav)", fullpath, dest_orig); int ok=onion_shortcut_rename(orig, fdest); if (ok==0){ ONION_DEBUG("Created %s succesfully", fdest); return onion_shortcut_response("201 Created", 201, req, res); } else{ ONION_ERROR("Could not rename %s to %s (%s)", orig, fdest, strerror(errno)); return onion_shortcut_response("Could not create resource", HTTP_FORBIDDEN, req, res); } }
/// Plexes the request depending on arguments. int oterm_get_data(oterm_data *data, onion_request *req, onion_response *res){ const char *username=onion_request_get_session(req,"username"); if (!username){ ONION_WARNING("Trying to enter authenticated area without username."); return OCS_FORBIDDEN; } oterm_session *o=(oterm_session*)onion_dict_get(data->sessions, onion_request_get_session(req,"username")); if (!o){ o=oterm_session_new(); onion_dict_lock_write(data->sessions); onion_dict_add(data->sessions,onion_request_get_session(req,"username"),o, 0); onion_dict_unlock(data->sessions); } const char *path=onion_request_get_path(req); ONION_DEBUG("Ask path %s (%p)", path, data); if (strcmp(path,"new")==0){ if (onion_request_get_post(req, "command")){ free(data->exec_command); data->exec_command=strdup(onion_request_get_post(req, "command")); } oterm_new(data, o, onion_request_get_session(req, "username"), onion_request_get_session(req, "nopam") ? 0 : 1 ); return onion_shortcut_response("ok", 200, req, res); } if (strcmp(path,"status")==0) return oterm_status(o,req, res); return OCS_NOT_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); } }
/// Input data to the process int oterm_in(process *p, onion_request *req, onion_response *res){ oterm_check_running(p); const char *data; data=onion_request_get_post(req,"type"); ssize_t w; if (data){ //fprintf(stderr,"%s:%d write %ld bytes\n",__FILE__,__LINE__,strlen(data)); size_t r=strlen(data); w=write(p->fd, data, r); if (w!=r){ ONION_WARNING("Error writing data to process. Not all data written. (%d).",w); return onion_shortcut_response("Error", HTTP_INTERNAL_ERROR, req, res); } } return onion_shortcut_response("OK", HTTP_OK, req, res); }
/// Resize the window. int oterm_resize(process *p, onion_request* req, onion_response *res){ //const char *data=onion_request_get_query(req,"resize"); //int ok=kill(o->pid, SIGWINCH); struct winsize winSize; memset(&winSize, 0, sizeof(winSize)); const char *t=onion_request_get_post(req,"width"); winSize.ws_row = (unsigned short)atoi(t ? t : "80"); t=onion_request_get_post(req,"height"); winSize.ws_col = (unsigned short)atoi(t ? t : "25"); int ok=ioctl(p->fd, TIOCSWINSZ, (char *)&winSize) == 0; if (ok>=0) return onion_shortcut_response("OK",HTTP_OK, req, res); else return onion_shortcut_response("Error",HTTP_INTERNAL_ERROR, req, res); }
/** * @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; }
static onion_connection_status oterm_process(oterm_data *data, process *term, const char *function, onion_request *req, onion_response *res){ if (!term) return onion_shortcut_response("Terminal Id unknown", 404, req, res); if (strcmp(function,"out")==0) return oterm_out(term,req,res); if (strcmp(function,"in")==0) return oterm_in(term,req,res); if (strcmp(function,"resize")==0) return oterm_resize(term,req,res); if (strcmp(function,"title")==0) return oterm_title(term,req,res); return OCS_NOT_PROCESSED; }
/** * @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; }
/** * @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 Creates a collection / directory. * * Spec says it must create only if the parent exists. */ onion_connection_status onion_webdav_mkcol(const char *filename, onion_webdav *wd, onion_request *req, onion_response *res){ if (mkdir(filename,0777)!=0){ return onion_shortcut_response("403 Forbidden", HTTP_FORBIDDEN, req, res); } return onion_shortcut_response("201 Created", 201, req, res); }