static int uwsgi_webdav_request(struct wsgi_request *wsgi_req) { if (!udav.mountpoints) { uwsgi_500(wsgi_req); return -1; } if (uwsgi_parse_vars(wsgi_req)) { return -1; } if (wsgi_req->path_info_len == 0) { uwsgi_403(wsgi_req); return UWSGI_OK; } wsgi_req->app_id = uwsgi_get_app_id(wsgi_req, wsgi_req->appid, wsgi_req->appid_len, webdav_plugin.modifier1); if (wsgi_req->app_id == -1) { uwsgi_403(wsgi_req); return UWSGI_OK; } // non lockables methods... if (!uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "OPTIONS", 7)) { return uwsgi_wevdav_manage_options(wsgi_req); } if (!uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "GET", 3)) { return uwsgi_wevdav_manage_get(wsgi_req, 1); } if (!uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "HEAD", 4)) { return uwsgi_wevdav_manage_get(wsgi_req, 0); } if (!uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "PROPFIND", 8)) { if (wsgi_req->post_cl > 0) { ssize_t body_len = 0; char *body = uwsgi_request_body_read(wsgi_req, wsgi_req->post_cl, &body_len); #ifdef UWSGI_DEBUG uwsgi_log("%.*s\n", body_len, body); #endif xmlDoc *doc = xmlReadMemory(body, body_len, NULL, NULL, 0); if (!doc) goto end; uwsgi_wevdav_manage_propfind(wsgi_req, doc); xmlFreeDoc(doc); } else { uwsgi_wevdav_manage_propfind(wsgi_req, NULL); } } if (!uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "REPORT", 6)) { if (wsgi_req->post_cl > 0) { ssize_t body_len = 0; char *body = uwsgi_request_body_read(wsgi_req, wsgi_req->post_cl, &body_len); #ifdef UWSGI_DEBUG uwsgi_log("%.*s\n", body_len, body); #endif xmlDoc *doc = xmlReadMemory(body, body_len, NULL, NULL, 0); if (!doc) goto end; xmlFreeDoc(doc); } } // lockable methods ... // check for locking if (!uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "PUT", 3)) { return uwsgi_wevdav_manage_put(wsgi_req); } if (!uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "DELETE", 6)) { return uwsgi_wevdav_manage_delete(wsgi_req); } if (!uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "MKCOL", 5)) { return uwsgi_wevdav_manage_mkcol(wsgi_req); } if (!uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "MKCALENDAR", 10)) { if (wsgi_req->post_cl == 0) goto end; ssize_t body_len = 0; char *body = uwsgi_request_body_read(wsgi_req, wsgi_req->post_cl, &body_len); #ifdef UWSGI_DEBUG uwsgi_log("%.*s\n", body_len, body); #endif xmlDoc *doc = xmlReadMemory(body, body_len, NULL, NULL, 0); if (!doc) goto end; uwsgi_wevdav_manage_mkcalendar(wsgi_req, doc); xmlFreeDoc(doc); } if (!uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "COPY", 4)) { return uwsgi_wevdav_manage_copy(wsgi_req); } if (!uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "MOVE", 4)) { return uwsgi_wevdav_manage_move(wsgi_req); } if (!uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "LOCK", 4)) { if (wsgi_req->post_cl > 0) { ssize_t body_len = 0; char *body = uwsgi_request_body_read(wsgi_req, wsgi_req->post_cl, &body_len); #ifdef UWSGI_DEBUG uwsgi_log("%.*s\n", body_len, body); #endif xmlDoc *doc = xmlReadMemory(body, body_len, NULL, NULL, 0); if (!doc) goto end; xmlFreeDoc(doc); } return uwsgi_wevdav_manage_lock(wsgi_req); } if (!uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "PROPPATCH", 9)) { if (wsgi_req->post_cl == 0) goto end; ssize_t body_len = 0; char *body = uwsgi_request_body_read(wsgi_req, wsgi_req->post_cl, &body_len); #ifdef UWSGI_DEBUG uwsgi_log("%.*s\n", body_len, body); #endif xmlDoc *doc = xmlReadMemory(body, body_len, NULL, NULL, 0); if (!doc) goto end; uwsgi_wevdav_manage_proppatch(wsgi_req, doc); xmlFreeDoc(doc); } end: return UWSGI_OK; }
static int uwsgi_glusterfs_request(struct wsgi_request *wsgi_req) { char filename[PATH_MAX+1]; /* Standard GlusterFS request */ if (!wsgi_req->uh->pktsize) { uwsgi_log( "Empty GlusterFS request. skip.\n"); return -1; } if (uwsgi_parse_vars(wsgi_req)) { return -1; } // blocks empty paths if (wsgi_req->path_info_len == 0 || wsgi_req->path_info_len > PATH_MAX) { uwsgi_403(wsgi_req); return UWSGI_OK; } wsgi_req->app_id = uwsgi_get_app_id(wsgi_req, wsgi_req->appid, wsgi_req->appid_len, glusterfs_plugin.modifier1); if (wsgi_req->app_id == -1 && !uwsgi.no_default_app && uwsgi.default_app > -1) { if (uwsgi_apps[uwsgi.default_app].modifier1 == glusterfs_plugin.modifier1) { wsgi_req->app_id = uwsgi.default_app; } } if (wsgi_req->app_id == -1) { uwsgi_404(wsgi_req); return UWSGI_OK; } struct uwsgi_app *ua = &uwsgi_apps[wsgi_req->app_id]; memcpy(filename, wsgi_req->path_info, wsgi_req->path_info_len); filename[wsgi_req->path_info_len] = 0; glfs_fd_t *fd = glfs_open((glfs_t *) ua->interpreter, filename, O_RDONLY); if (!fd) { uwsgi_404(wsgi_req); return UWSGI_OK; } struct stat st; if (glfs_fstat(fd, &st)) { uwsgi_403(wsgi_req); return UWSGI_OK; } if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6)) goto end; size_t mime_type_len = 0; char *mime_type = uwsgi_get_mime_type(wsgi_req->path_info, wsgi_req->path_info_len, &mime_type_len); if (mime_type) { if (uwsgi_response_add_content_type(wsgi_req, mime_type, mime_type_len)) goto end; } if (uwsgi_response_add_last_modified(wsgi_req, (uint64_t) st.st_mtime)) goto end; if (uwsgi_response_add_content_length(wsgi_req, st.st_size)) goto end; // skip body on HEAD if (uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "HEAD", 4)) { size_t remains = st.st_size; while(remains > 0) { char buf[8192]; ssize_t rlen = glfs_read (fd, buf, UMIN(remains, 8192), 0); if (rlen <= 0) goto end; if (uwsgi_response_write_body_do(wsgi_req, buf, rlen)) goto end; remains -= rlen; } } end: glfs_close(fd); return UWSGI_OK; }
static int uwsgi_ssh_request(struct wsgi_request *wsgi_req) { #if !defined(UWSGI_PLUGIN_API) || UWSGI_PLUGIN_API == 1 if (!wsgi_req->uh->pktsize) #else if (!wsgi_req->len) #endif { uwsgi_log("[SSH] skipping empty request.\n"); return -1; } if (uwsgi_parse_vars(wsgi_req)) { uwsgi_error("uwsgi_ssh_request()/uwsgi_parse_vars()"); return -1; } if (wsgi_req->path_info_len == 0 || wsgi_req->path_info_len > PATH_MAX || wsgi_req->path_info[wsgi_req->path_info_len - 1] == '/') { uwsgi_403(wsgi_req); return UWSGI_OK; } wsgi_req->app_id = uwsgi_get_app_id(wsgi_req, wsgi_req->appid, wsgi_req->appid_len, libssh2_plugin.modifier1); if (wsgi_req->app_id == -1 && !uwsgi.no_default_app && uwsgi.default_app > -1) { if (uwsgi_apps[uwsgi.default_app].modifier1 == libssh2_plugin.modifier1) { wsgi_req->app_id = uwsgi.default_app; } } if (wsgi_req->app_id == -1) { uwsgi_404(wsgi_req); return UWSGI_OK; } struct uwsgi_app *ua = &uwsgi_apps[wsgi_req->app_id]; struct uwsgi_ssh_mountpoint *usm_list = (struct uwsgi_ssh_mountpoint *) ua->callable; char *complete_filepath = NULL; char *filepath = NULL; if (wsgi_req->path_info_len > ua->mountpoint_len && memcmp(wsgi_req->path_info, ua->mountpoint, ua->mountpoint_len) == 0) { filepath = uwsgi_strncopy( wsgi_req->path_info + ua->mountpoint_len, wsgi_req->path_info_len - ua->mountpoint_len ); } else { filepath = uwsgi_strncopy(wsgi_req->path_info, wsgi_req->path_info_len); } complete_filepath = uwsgi_concat2(usm_list->path, filepath); free(filepath); int return_status = 500; struct uwsgi_ssh_mountpoint *usm = usm_list; do { return_status = uwsgi_ssh_request_file( wsgi_req, complete_filepath, usm ); } while (return_status == 500 && ((usm = usm->next) != NULL)); free(complete_filepath); switch (return_status) { case 404: uwsgi_404(wsgi_req); break; case 500: default: uwsgi_500(wsgi_req); } return 0; }
static void uwsgi_ssh_add_mountpoint(char *arg, size_t arg_len) { /* --ssh-mount Required fields: mountpoint=/foo, remote=ssh://user[:password]@host:port/path, Optional fields: ssh_agent=1 (actually, anything will be interpreted as true), identity=priv_key_path;priv_key_passphrase (passphrase is optional) public_identity=pub_key_path (needed only if not using OpenSSL) */ if (uwsgi_apps_cnt >= uwsgi.max_apps) { uwsgi_log("ERROR: you cannot load more than %d apps in a worker\n", uwsgi.max_apps); exit(1); } struct uwsgi_ssh_mountpoint *usm = uwsgi_calloc(sizeof(struct uwsgi_ssh_mountpoint)); char *remote_url = NULL; char *ssh_agent = NULL; char *identity = NULL; if (uwsgi_kvlist_parse(arg, arg_len, ',', '=', "mountpoint", &usm->mountpoint, "remote", &remote_url, "ssh-agent", &ssh_agent, "identity", &identity, "public_identity", &usm->pub_key_path, NULL) ){ uwsgi_log("[SSH] unable to parse ssh mountpoint definition\n"); goto shutdown; } if (uwsgi_ssh_url_parser(remote_url, &usm)) { uwsgi_error("uwsgi_ssh_add_mountpoint()/uwsgi_ssh_url_parser()"); goto shutdown; } if (!usm->mountpoint || !usm->remote) { uwsgi_log("[SSH] mount requires a mountpoint and a remote.\n"); goto shutdown; } if (ssh_agent) { usm->ssh_agent = 1; } else { usm->ssh_agent = 0; } if (identity) { char* semicolon = strchr(identity, ';'); if (semicolon) { usm->priv_key_passphrase = semicolon + 1; } else { usm->priv_key_path = identity; usm->priv_key_passphrase = ""; } usm->priv_key_path = identity; } int app_id = uwsgi_get_app_id(NULL, usm->mountpoint, strlen(usm->mountpoint), libssh2_plugin.modifier1); if (app_id == -1) { time_t now = uwsgi_now(); uwsgi_log("[SSH] mounting %s%s on %s.\n", usm->remote, usm->path, usm->mountpoint); int id = uwsgi_apps_cnt; struct uwsgi_app *ua = uwsgi_add_app( id, libssh2_plugin.modifier1, usm->mountpoint, strlen(usm->mountpoint), NULL, NULL ); if (!ua) { uwsgi_log("[SSH] unable to mount %s\n", usm->mountpoint); goto shutdown; } // App storage area. ua->callable = usm; uwsgi_emulate_cow_for_apps(id); ua->started_at = now; ua->startup_time = uwsgi_now() - now; uwsgi_log("[SSH] mountpoint %d (%s) loaded in %d seconds at %s\n", id, usm->remote, (int) ua->startup_time, usm->mountpoint); } else { uwsgi_log("[SSH] adding %s to high availability configuration for mounpoint %s.\n", usm->remote, usm->mountpoint); struct uwsgi_app *ua = &uwsgi_apps[app_id]; struct uwsgi_ssh_mountpoint *usm_list = (struct uwsgi_ssh_mountpoint *) ua->callable; while (usm_list->next) { usm_list = usm_list->next; } usm_list->next = usm; uwsgi_emulate_cow_for_apps(app_id); } return; shutdown: exit(1); }
int init_uwsgi_app(int loader, void *arg1, struct wsgi_request *wsgi_req, PyThreadState *interpreter, int app_type) { PyObject *app_list = NULL, *applications = NULL; if (uwsgi_apps_cnt >= uwsgi.max_apps) { uwsgi_log("ERROR: you cannot load more than %d apps in a worker\n", uwsgi.max_apps); return -1; } int id = uwsgi_apps_cnt; int multiapp = 0; int i; struct uwsgi_app *wi; time_t now = uwsgi_now(); if (uwsgi_get_app_id(NULL, wsgi_req->appid, wsgi_req->appid_len, -1) != -1) { uwsgi_log( "mountpoint %.*s already configured. skip.\n", wsgi_req->appid_len, wsgi_req->appid); return -1; } wi = &uwsgi_apps[id]; memset(wi, 0, sizeof(struct uwsgi_app)); wi->mountpoint_len = wsgi_req->appid_len < 0xff ? wsgi_req->appid_len : (0xff-1); strncpy(wi->mountpoint, wsgi_req->appid, wi->mountpoint_len); // dynamic chdir ? if (wsgi_req->chdir_len > 0) { strncpy(wi->chdir, wsgi_req->chdir, wsgi_req->chdir_len < 0xff ? wsgi_req->chdir_len : (0xff-1)); #ifdef UWSGI_DEBUG uwsgi_debug("chdir to %s\n", wi->chdir); #endif if (chdir(wi->chdir)) { uwsgi_error("chdir()"); } } // Initialize a new environment for the new interpreter // reload "os" environ to allow dynamic setenv() if (up.reload_os_env) { char **e, *p; PyObject *k, *env_value; PyObject *os_module = PyImport_ImportModule("os"); if (os_module) { PyObject *os_module_dict = PyModule_GetDict(os_module); PyObject *py_environ = PyDict_GetItemString(os_module_dict, "environ"); if (py_environ) { for (e = environ; *e != NULL; e++) { p = strchr(*e, '='); if (p == NULL) continue; k = PyString_FromStringAndSize(*e, (int)(p-*e)); if (k == NULL) { PyErr_Print(); continue; } env_value = PyString_FromString(p+1); if (env_value == NULL) { PyErr_Print(); Py_DECREF(k); continue; } #ifdef UWSGI_DEBUG uwsgi_log("%s = %s\n", PyString_AsString(k), PyString_AsString(env_value)); #endif if (PyObject_SetItem(py_environ, k, env_value)) { PyErr_Print(); } Py_DECREF(k); Py_DECREF(env_value); } } } } if (interpreter == NULL && id) { wi->interpreter = Py_NewInterpreter(); if (!wi->interpreter) { uwsgi_log( "unable to initialize the new python interpreter\n"); exit(1); } PyThreadState_Swap(wi->interpreter); init_pyargv(); // we need to inizialize an embedded module for every interpreter init_uwsgi_embedded_module(); init_uwsgi_vars(); } else if (interpreter) { wi->interpreter = interpreter; } else { wi->interpreter = up.main_thread; } if (wsgi_req->home_len) { set_dyn_pyhome(wsgi_req->home, wsgi_req->home_len); } if (wsgi_req->touch_reload_len > 0 && wsgi_req->touch_reload_len < 0xff) { struct stat trst; strncpy(wi->touch_reload, wsgi_req->touch_reload, wsgi_req->touch_reload_len); if (!stat(wi->touch_reload, &trst)) { wi->touch_reload_mtime = trst.st_mtime; } } wi->callable = up.loaders[loader](arg1); if (!wi->callable) { uwsgi_log("unable to load app %d (mountpoint='%s') (callable not found or import error)\n", id, wi->mountpoint); goto doh; } // the module contains multiple apps if (PyDict_Check((PyObject *)wi->callable)) { applications = wi->callable; uwsgi_log("found a multiapp module...\n"); app_list = PyDict_Keys(applications); multiapp = PyList_Size(app_list); if (multiapp < 1) { uwsgi_log("you have to define at least one app in the apllications dictionary\n"); goto doh; } PyObject *app_mnt = PyList_GetItem(app_list, 0); if (!PyString_Check(app_mnt)) { uwsgi_log("the app mountpoint must be a string\n"); goto doh; } char *tmp_mountpoint = PyString_AsString(app_mnt); wi->mountpoint_len = strlen(wi->mountpoint) < 0xff ? strlen(wi->mountpoint) : (0xff-1); strncpy(wi->mountpoint, tmp_mountpoint, wi->mountpoint_len); wsgi_req->appid = wi->mountpoint; wsgi_req->appid_len = wi->mountpoint_len; #ifdef UWSGI_DEBUG uwsgi_log("main mountpoint = %s\n", wi->mountpoint); #endif wi->callable = PyDict_GetItem(applications, app_mnt); if (PyString_Check((PyObject *) wi->callable)) { PyObject *callables_dict = get_uwsgi_pydict((char *)arg1); if (callables_dict) { wi->callable = PyDict_GetItem(callables_dict, (PyObject *)wi->callable); } } } Py_INCREF((PyObject *)wi->callable); wi->environ = malloc(sizeof(PyObject*)*uwsgi.cores); if (!wi->environ) { uwsgi_error("malloc()"); exit(1); } for(i=0;i<uwsgi.cores;i++) { wi->environ[i] = PyDict_New(); if (!wi->environ[i]) { uwsgi_log("unable to allocate new env dictionary for app\n"); exit(1); } } wi->argc = 1; if (app_type == PYTHON_APP_TYPE_WSGI) { #ifdef UWSGI_DEBUG uwsgi_log("-- WSGI callable selected --\n"); #endif wi->request_subhandler = uwsgi_request_subhandler_wsgi; wi->response_subhandler = uwsgi_response_subhandler_wsgi; wi->argc = 2; } else if (app_type == PYTHON_APP_TYPE_WEB3) { #ifdef UWSGI_DEBUG uwsgi_log("-- Web3 callable selected --\n"); #endif wi->request_subhandler = uwsgi_request_subhandler_web3; wi->response_subhandler = uwsgi_response_subhandler_web3; } else if (app_type == PYTHON_APP_TYPE_PUMP) { #ifdef UWSGI_DEBUG uwsgi_log("-- Pump callable selected --\n"); #endif wi->request_subhandler = uwsgi_request_subhandler_pump; wi->response_subhandler = uwsgi_response_subhandler_pump; } wi->args = malloc(sizeof(PyObject*)*uwsgi.cores); if (!wi->args) { uwsgi_error("malloc()"); exit(1); } for(i=0;i<uwsgi.cores;i++) { wi->args[i] = PyTuple_New(wi->argc); if (!wi->args[i]) { uwsgi_log("unable to allocate new tuple for app args\n"); exit(1); } // add start_response on WSGI app Py_INCREF((PyObject *)up.wsgi_spitout); if (app_type == PYTHON_APP_TYPE_WSGI) { if (PyTuple_SetItem(wi->args[i], 1, up.wsgi_spitout)) { uwsgi_log("unable to set start_response in args tuple\n"); exit(1); } } } if (app_type == PYTHON_APP_TYPE_WSGI) { // prepare sendfile() for WSGI app wi->sendfile = PyCFunction_New(uwsgi_sendfile_method, NULL); wi->eventfd_read = PyCFunction_New(uwsgi_eventfd_read_method, NULL); wi->eventfd_write = PyCFunction_New(uwsgi_eventfd_write_method, NULL); } // cache most used values wi->error = PyFile_FromFile(stderr, "wsgi_errors", "w", NULL); Py_INCREF((PyObject *)wi->error); wi->gateway_version = PyTuple_New(2); PyTuple_SetItem(wi->gateway_version, 0, PyInt_FromLong(1)); PyTuple_SetItem(wi->gateway_version, 1, PyInt_FromLong(0)); Py_INCREF((PyObject *)wi->gateway_version); wi->uwsgi_version = PyString_FromString(UWSGI_VERSION); Py_INCREF((PyObject *)wi->uwsgi_version); wi->uwsgi_node = PyString_FromString(uwsgi.hostname); Py_INCREF((PyObject *)wi->uwsgi_node); if (uwsgi.threads > 1 && id) { // if we have multiple threads we need to initialize a PyThreadState for each one for(i=0;i<uwsgi.threads;i++) { //uwsgi_log("%p\n", uwsgi.core[i]->ts[id]); uwsgi.workers[uwsgi.mywid].cores[i].ts[id] = PyThreadState_New( ((PyThreadState *)wi->interpreter)->interp); if (!uwsgi.workers[uwsgi.mywid].cores[i].ts[id]) { uwsgi_log("unable to allocate new PyThreadState structure for app %s", wi->mountpoint); goto doh; } } PyThreadState_Swap((PyThreadState *) pthread_getspecific(up.upt_save_key) ); } else if (interpreter == NULL && id) { PyThreadState_Swap(up.main_thread); } const char *default_app = ""; if ((wsgi_req->appid_len == 0 || (wsgi_req->appid_len = 1 && wsgi_req->appid[0] == '/')) && uwsgi.default_app == -1) { default_app = " (default app)" ; uwsgi.default_app = id; } wi->started_at = now; wi->startup_time = uwsgi_now() - now; if (app_type == PYTHON_APP_TYPE_WSGI) { uwsgi_log( "WSGI app %d (mountpoint='%.*s') ready in %d seconds on interpreter %p pid: %d%s\n", id, wi->mountpoint_len, wi->mountpoint, (int) wi->startup_time, wi->interpreter, (int) getpid(), default_app); } else if (app_type == PYTHON_APP_TYPE_WEB3) { uwsgi_log( "Web3 app %d (mountpoint='%.*s') ready in %d seconds on interpreter %p pid: %d%s\n", id, wi->mountpoint_len, wi->mountpoint, (int) wi->startup_time, wi->interpreter, (int) getpid(), default_app); } else if (app_type == PYTHON_APP_TYPE_PUMP) { uwsgi_log( "Pump app %d (mountpoint='%.*s') ready in %d seconds on interpreter %p pid: %d%s\n", id, wi->mountpoint_len, wi->mountpoint, (int) wi->startup_time, wi->interpreter, (int) getpid(), default_app); } uwsgi_apps_cnt++; if (multiapp > 1) { for(i=1;i<multiapp;i++) { PyObject *app_mnt = PyList_GetItem(app_list, i); if (!PyString_Check(app_mnt)) { uwsgi_log("applications dictionary key must be a string, skipping.\n"); continue; } wsgi_req->appid = PyString_AsString(app_mnt); wsgi_req->appid_len = strlen(wsgi_req->appid); PyObject *a_callable = PyDict_GetItem(applications, app_mnt); if (PyString_Check(a_callable)) { PyObject *callables_dict = get_uwsgi_pydict((char *)arg1); if (callables_dict) { a_callable = PyDict_GetItem(callables_dict, a_callable); } } if (!a_callable) { uwsgi_log("skipping broken app %s\n", wsgi_req->appid); continue; } init_uwsgi_app(LOADER_CALLABLE, a_callable, wsgi_req, wi->interpreter, app_type); } } // emulate COW uwsgi_emulate_cow_for_apps(id); return id; doh: if (PyErr_Occurred()) PyErr_Print(); if (interpreter == NULL && id) { Py_EndInterpreter(wi->interpreter); if (uwsgi.threads > 1) { PyThreadState_Swap((PyThreadState *) pthread_getspecific(up.upt_save_key)); } else { PyThreadState_Swap(up.main_thread); } } return -1; }
static int uwsgi_rados_request(struct wsgi_request *wsgi_req) { char filename[PATH_MAX+1]; if (!wsgi_req->len) { uwsgi_log( "Empty request. skip.\n"); return -1; } if (uwsgi_parse_vars(wsgi_req)) { return -1; } // blocks empty paths if (wsgi_req->path_info_len == 0 || wsgi_req->path_info_len > PATH_MAX) { uwsgi_403(wsgi_req); return UWSGI_OK; } wsgi_req->app_id = uwsgi_get_app_id(wsgi_req, wsgi_req->appid, wsgi_req->appid_len, rados_plugin.modifier1); if (wsgi_req->app_id == -1 && !uwsgi.no_default_app && uwsgi.default_app > -1) { if (uwsgi_apps[uwsgi.default_app].modifier1 == rados_plugin.modifier1) { wsgi_req->app_id = uwsgi.default_app; } } if (wsgi_req->app_id == -1) { uwsgi_404(wsgi_req); return UWSGI_OK; } struct uwsgi_app *ua = &uwsgi_apps[wsgi_req->app_id]; if (wsgi_req->path_info_len > ua->mountpoint_len && memcmp(wsgi_req->path_info, ua->mountpoint, ua->mountpoint_len) == 0) { memcpy(filename, wsgi_req->path_info+ua->mountpoint_len, wsgi_req->path_info_len-ua->mountpoint_len); filename[wsgi_req->path_info_len-ua->mountpoint_len] = 0; } else { memcpy(filename, wsgi_req->path_info, wsgi_req->path_info_len); filename[wsgi_req->path_info_len] = 0; } // in multithread mode the memory is different (as we need a ctx for each thread) !!! rados_ioctx_t ctx; if (uwsgi.threads > 1) { rados_ioctx_t *ctxes = (rados_ioctx_t *) ua->responder0; ctx = ctxes[wsgi_req->async_id]; } else { ctx = (rados_ioctx_t) ua->responder0; } struct uwsgi_rados_mountpoint *urmp = (struct uwsgi_rados_mountpoint *) ua->responder1; uint64_t stat_size = 0; time_t stat_mtime = 0; struct uwsgi_rados_io *urio = &urados.urio[wsgi_req->async_id]; if (uwsgi.async > 0) { // no need to lock here (the rid protect us) if (pipe(urio->fds)) { uwsgi_error("uwsgi_rados_read_async()/pipe()"); uwsgi_500(wsgi_req); return UWSGI_OK; } } int ret = -1; int timeout = urmp->timeout ? urmp->timeout : urados.timeout; if (!uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "OPTIONS", 7)) { if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6)) goto end; if (uwsgi_response_add_header(wsgi_req, "Dav", 3, "1", 1)) goto end; struct uwsgi_buffer *ub_allow = uwsgi_buffer_new(64); if (uwsgi_buffer_append(ub_allow, "OPTIONS, GET, HEAD", 18)) { uwsgi_buffer_destroy(ub_allow); goto end; } if (urmp->allow_put) { if (uwsgi_buffer_append(ub_allow, ", PUT", 5)) { uwsgi_buffer_destroy(ub_allow); goto end; } } if (urmp->allow_delete) { if (uwsgi_buffer_append(ub_allow, ", DELETE", 8)) { uwsgi_buffer_destroy(ub_allow); goto end; } } if (urmp->allow_mkcol) { if (uwsgi_buffer_append(ub_allow, ", MKCOL", 7)) { uwsgi_buffer_destroy(ub_allow); goto end; } } if (urmp->allow_propfind) { if (uwsgi_buffer_append(ub_allow, ", PROPFIND", 10)) { uwsgi_buffer_destroy(ub_allow); goto end; } } uwsgi_response_add_header(wsgi_req, "Allow", 5, ub_allow->buf, ub_allow->pos); uwsgi_buffer_destroy(ub_allow); goto end; } // empty paths are mapped to propfind if (wsgi_req->path_info_len == 1 && wsgi_req->path_info[0] == '/') { if (urmp->allow_propfind && !uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "PROPFIND", 8)) { uwsgi_rados_propfind(wsgi_req, ctx, NULL, 0, 0, timeout); goto end; } uwsgi_405(wsgi_req); goto end; } // MKCOL does not require stat if (!uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "MKCOL", 5)) { if (!urmp->allow_mkcol) { uwsgi_405(wsgi_req); goto end; } ret = rados_pool_create(urmp->cluster, filename); if (ret < 0) { if (ret == -EEXIST) { uwsgi_405(wsgi_req); } else { uwsgi_500(wsgi_req); } goto end; } uwsgi_response_prepare_headers(wsgi_req, "201 Created", 11); goto end; } if (uwsgi.async > 0) { ret = uwsgi_rados_async_stat(urio, ctx, filename, &stat_size, &stat_mtime, timeout); } else { ret = rados_stat(ctx, filename, &stat_size, &stat_mtime); } // PUT AND MKCOL can be used for non-existent objects if (!uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "PUT", 3)) { if (!urmp->allow_put) { uwsgi_405(wsgi_req); goto end; } if (ret == 0) { if (uwsgi_rados_delete(wsgi_req, ctx, filename, timeout)) { uwsgi_500(wsgi_req); goto end; } } if (uwsgi_rados_put(wsgi_req, ctx, filename, urmp->put_buffer_size, timeout)) { uwsgi_500(wsgi_req); goto end; } uwsgi_response_prepare_headers(wsgi_req, "201 Created", 11); goto end; } else if (ret < 0) { if (ret == -ENOENT) uwsgi_404(wsgi_req); else uwsgi_403(wsgi_req); goto end; } if (!uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "DELETE", 6)) { if (!urmp->allow_delete) { uwsgi_405(wsgi_req); goto end; } if (uwsgi_rados_delete(wsgi_req, ctx, filename, timeout)) { uwsgi_403(wsgi_req); goto end; } uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6); goto end; } if (!uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "PROPFIND", 8)) { if (!urmp->allow_propfind) { uwsgi_405(wsgi_req); goto end; } uwsgi_rados_propfind(wsgi_req, ctx, filename, stat_size, stat_mtime, timeout); goto end; } if (uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "HEAD", 4) && uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "GET", 3)) { uwsgi_405(wsgi_req); goto end; } uint64_t offset = 0; uint64_t remains = stat_size; uwsgi_request_fix_range_for_size(wsgi_req, remains); switch (wsgi_req->range_parsed) { case UWSGI_RANGE_INVALID: if (uwsgi_response_prepare_headers(wsgi_req, "416 Requested Range Not Satisfiable", 35)) goto end; if (uwsgi_response_add_content_range(wsgi_req, -1, -1, stat_size)) goto end; return 0; case UWSGI_RANGE_VALID: offset = wsgi_req->range_from; remains = wsgi_req->range_to - wsgi_req->range_from + 1; if (uwsgi_response_prepare_headers(wsgi_req, "206 Partial Content", 19)) goto end; break; default: /* UWSGI_RANGE_NOT_PARSED */ if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6)) return -1; } size_t mime_type_len = 0; char *mime_type = uwsgi_get_mime_type(wsgi_req->path_info, wsgi_req->path_info_len, &mime_type_len); if (mime_type) { if (uwsgi_response_add_content_type(wsgi_req, mime_type, mime_type_len)) goto end; } if (uwsgi_response_add_last_modified(wsgi_req, (uint64_t) stat_mtime)) goto end; // set Content-Length to actual result size if (uwsgi_response_add_content_length(wsgi_req, remains)) goto end; if (wsgi_req->range_parsed == UWSGI_RANGE_VALID) { // here use the original size !!! if (uwsgi_response_add_content_range(wsgi_req, wsgi_req->range_from, wsgi_req->range_to, stat_size)) goto end; } // skip body on HEAD if (uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "HEAD", 4)) { if (uwsgi.async > 0) { if (uwsgi_rados_read_async(wsgi_req, ctx, filename, offset, remains, urmp->buffer_size, timeout)) goto end; } else { if (uwsgi_rados_read_sync(wsgi_req, ctx, filename, offset, remains, urmp->buffer_size)) goto end; } } end: if (uwsgi.async > 0) { close(urio->fds[0]); close(urio->fds[1]); } return UWSGI_OK; }
static int uwsgi_rados_request(struct wsgi_request *wsgi_req) { char filename[PATH_MAX+1]; if (!wsgi_req->uh->pktsize) { uwsgi_log( "Empty request. skip.\n"); return -1; } if (uwsgi_parse_vars(wsgi_req)) { return -1; } // blocks empty paths if (wsgi_req->path_info_len == 0 || wsgi_req->path_info_len > PATH_MAX) { uwsgi_403(wsgi_req); return UWSGI_OK; } wsgi_req->app_id = uwsgi_get_app_id(wsgi_req, wsgi_req->appid, wsgi_req->appid_len, rados_plugin.modifier1); if (wsgi_req->app_id == -1 && !uwsgi.no_default_app && uwsgi.default_app > -1) { if (uwsgi_apps[uwsgi.default_app].modifier1 == rados_plugin.modifier1) { wsgi_req->app_id = uwsgi.default_app; } } if (wsgi_req->app_id == -1) { uwsgi_404(wsgi_req); return UWSGI_OK; } struct uwsgi_app *ua = &uwsgi_apps[wsgi_req->app_id]; if (wsgi_req->path_info_len > ua->mountpoint_len && memcmp(wsgi_req->path_info, ua->mountpoint, ua->mountpoint_len) == 0) { memcpy(filename, wsgi_req->path_info+ua->mountpoint_len, wsgi_req->path_info_len-ua->mountpoint_len); } else { memcpy(filename, wsgi_req->path_info, wsgi_req->path_info_len); } filename[wsgi_req->path_info_len] = 0; struct { uint64_t size; time_t mtime; } st; rados_ioctx_t ctx = ua->responder1; int r = rados_stat(ctx, filename, &st.size, &st.mtime); if (r < 0) { if (r == -ENOENT) uwsgi_404(wsgi_req); else uwsgi_403(wsgi_req); return UWSGI_OK; } if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6)) goto end; size_t mime_type_len = 0; char *mime_type = uwsgi_get_mime_type(wsgi_req->path_info, wsgi_req->path_info_len, &mime_type_len); if (mime_type) { if (uwsgi_response_add_content_type(wsgi_req, mime_type, mime_type_len)) goto end; } if (uwsgi_response_add_last_modified(wsgi_req, (uint64_t) st.mtime)) goto end; if (uwsgi_response_add_content_length(wsgi_req, st.size)) goto end; // skip body on HEAD if (uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "HEAD", 4)) { size_t remains = st.size; if (uwsgi.async > 1) { if (uwsgi_rados_read_async(wsgi_req, ctx, filename, remains)) goto end; } else { if (uwsgi_rados_read_sync(wsgi_req, ctx, filename, remains)) goto end; } } end: return UWSGI_OK; }