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_wevdav_manage_get(struct wsgi_request *wsgi_req, int send_body) { char filename[PATH_MAX]; size_t filename_len = uwsgi_webdav_expand_path(wsgi_req, wsgi_req->path_info, wsgi_req->path_info_len, filename); if (!filename_len) { uwsgi_404(wsgi_req); return UWSGI_OK; } if (uwsgi_is_dir(filename)) { uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6); if (send_body) { uwsgi_webdav_dirlist(wsgi_req, filename); } return UWSGI_OK; } int fd = open(filename, O_RDONLY); if (fd < 0) { uwsgi_403(wsgi_req); return UWSGI_OK; } struct stat st; if (fstat(fd, &st)) { close(fd); uwsgi_403(wsgi_req); return UWSGI_OK; } if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6)) goto end; // add content_length if (uwsgi_response_add_content_length(wsgi_req, st.st_size)) goto end; // add last-modified if (uwsgi_response_add_last_modified(wsgi_req, st.st_mtime)) goto end; // add mime_type size_t mime_type_len = 0; char *mime_type = uwsgi_get_mime_type(filename, filename_len, &mime_type_len); if (mime_type) { if (uwsgi_response_add_content_type(wsgi_req, mime_type, mime_type_len)) goto end; } // add ETag (based on file mtime, not rock-solid, but good enough) char *etag = uwsgi_num2str(st.st_mtime); if (uwsgi_response_add_header(wsgi_req, "ETag", 4, etag, strlen(etag))) { free(etag); goto end; } free(etag); // start sending the file (note: we do not use sendfile() api, for being able to use caching and transformations) if (!send_body) goto end; // use a pretty big buffer (for performance reasons) char buf[32768]; size_t remains = st.st_size; while (remains > 0) { ssize_t rlen = read(fd, buf, UMIN(32768, remains)); if (rlen <= 0) { uwsgi_error("uwsgi_wevdav_manage_get/read()"); break; } remains -= rlen; if (uwsgi_response_write_body_do(wsgi_req, buf, rlen)) { break; } } end: close(fd); return UWSGI_OK; }
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_ssh_request_file( struct wsgi_request *wsgi_req, char* filepath, struct uwsgi_ssh_mountpoint *usm ) { int sock = -1; int return_status = 0; LIBSSH2_SESSION *session = NULL; if (uwsgi_init_ssh_session(usm, &sock, &session)) { uwsgi_log("[SSH] session initialization failed. Is the SSH server up?\n"); return_status = 500; goto shutdown; } LIBSSH2_SFTP *sftp_session = NULL; do { sftp_session = libssh2_sftp_init(session); if (!sftp_session) { if ((libssh2_session_last_errno(session)) == LIBSSH2_ERROR_EAGAIN) { if (uwsgi_ssh_waitsocket(sock, session)) { return_status = 500; goto shutdown; } } else { uwsgi_error("uwsgi_ssh_request_file()/libssh2_sftp_init()"); return_status = 500; goto shutdown; } } } while (!sftp_session); // Request file stats via SFTP LIBSSH2_SFTP_ATTRIBUTES file_attrs; int rc; while ((rc = libssh2_sftp_stat(sftp_session, filepath, &file_attrs)) == LIBSSH2_ERROR_EAGAIN) { if (uwsgi_ssh_waitsocket(sock, session)) { return_status = 500; goto shutdown; } } if (rc < 0) { // If it fails, requested file could not exist. if (rc == LIBSSH2_ERROR_SFTP_PROTOCOL && libssh2_sftp_last_error(sftp_session) == LIBSSH2_FX_NO_SUCH_FILE) { return_status = 404; } else { uwsgi_error("uwsgi_ssh_request_file()/libssh2_sftp_stat()"); return_status = 500; } goto sftp_shutdown; } if (wsgi_req->if_modified_since_len) { time_t ims = uwsgi_parse_http_date(wsgi_req->if_modified_since, wsgi_req->if_modified_since_len); if (file_attrs.mtime <= (unsigned long)ims) { if (uwsgi_response_prepare_headers(wsgi_req, "304 Not Modified", 16) || uwsgi_response_write_headers_do(wsgi_req)) { uwsgi_error("uwsgi_parse_http_date()/uwsgi_response_prepare_headers(do)()"); } return_status = 500; goto sftp_shutdown; } } if (uwsgi_response_prepare_headers(wsgi_req, "200", 3)) { uwsgi_error("uwsgi_ssh_request_file()/uwsgi_response_prepare_headers()"); return_status = 500; goto sftp_shutdown; } if (uwsgi_response_add_content_length(wsgi_req, file_attrs.filesize)) { uwsgi_error("uwsgi_ssh_request_file()/uwsgi_response_add_content_length()"); return_status = 500; goto sftp_shutdown; } if (uwsgi_response_add_last_modified(wsgi_req, file_attrs.mtime)) { uwsgi_error("uwsgi_ssh_request_file()/uwsgi_response_add_last_modified()"); return_status = 500; goto sftp_shutdown; } size_t mime_type_len = 0; char *mime_type = uwsgi_get_mime_type(filepath, strlen(filepath), &mime_type_len); if (mime_type) { if (uwsgi_response_add_content_type(wsgi_req, mime_type, mime_type_len)) { uwsgi_error("uwsgi_ssh_request_file()/uwsgi_response_add_content_type()"); // goto sftp_shutdown; } } // Request a file via SFTP LIBSSH2_SFTP_HANDLE *sftp_handle = NULL; do { sftp_handle = libssh2_sftp_open(sftp_session, filepath, LIBSSH2_FXF_READ, 0); if (!sftp_handle) { if (libssh2_session_last_errno(session) != LIBSSH2_ERROR_EAGAIN) { uwsgi_error("uwsgi_ssh_request_file()/libssh2_sftp_open()"); return_status = 500; goto sftp_shutdown; } else { if (uwsgi_ssh_waitsocket(sock, session)) { return_status = 500; goto sftp_shutdown; } } } } while (!sftp_handle); size_t buffer_size = uwsgi.page_size; void *buffer = alloca(buffer_size); libssh2_uint64_t read_size = 0; while (read_size < file_attrs.filesize) { rc = libssh2_sftp_read(sftp_handle, buffer, buffer_size); if (rc == LIBSSH2_ERROR_EAGAIN) { if (uwsgi_ssh_waitsocket(sock, session)) { return_status = 500; goto sftp_shutdown; } } else if (rc < 0) { uwsgi_error("uwsgi_ssh_request_file()/libssh2_sftp_read()"); break; } else { read_size += rc; if (uwsgi_response_write_body_do(wsgi_req, buffer, rc)) { uwsgi_error("uwsgi_ssh_request_file()/uwsgi_response_write_body_do()"); break; } } } while ((rc = libssh2_sftp_close(sftp_handle)) == LIBSSH2_ERROR_EAGAIN) { if (uwsgi_ssh_waitsocket(sock, session)) { return_status = 500; goto sftp_shutdown; } }; if (rc < 0) { uwsgi_error("uwsgi_ssh_request_file()/libssh2_sftp_close()"); } sftp_shutdown: while ((rc = libssh2_sftp_shutdown(sftp_session)) == LIBSSH2_ERROR_EAGAIN) { uwsgi_ssh_waitsocket(sock, session); } if (rc < 0) { uwsgi_error("uwsgi_ssh_request_file()/libssh2_sftp_shutdown()"); } shutdown: while (libssh2_session_disconnect(session, "Normal Shutdown, thank you!") == LIBSSH2_ERROR_EAGAIN) { uwsgi_ssh_waitsocket(sock, session); } libssh2_session_free(session); close(sock); libssh2_exit(); return return_status; }
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; }