commit 8f317ea03ee469ccab83292584802c52a352ca3e from: Aleksey Ryndin date: Wed Aug 23 09:36:40 2023 UTC Redirect: directory -> "/gemini.gmi" commit - 86a71674eb8c8c15fcae904bfbc8801629f1742d commit + 8f317ea03ee469ccab83292584802c52a352ca3e blob - 950b8283fb07a4289fe6d1a462651a2b76773d33 blob + 578884b5ab19556c2a0a9a5f37ff01eb6bf91c30 --- vostok/Makefile +++ vostok/Makefile @@ -6,6 +6,7 @@ CXXFILES += error.cc CXXFILES += gemini.cc CXXFILES += args.cc CXXFILES += parse_url.cc +CXXFILES += open_file.cc CXXFILES += vostok.cc OFILES = ${CXXFILES:.cc=.o} blob - /dev/null blob + 224e22e17c796b4e3b805df0d6582f1ad60cc932 (mode 644) --- /dev/null +++ vostok/open_file.cc @@ -0,0 +1,69 @@ +/** Open file for Gemini response */ + +#include "open_file.h" +#include "error.h" + +#include +#include + + +namespace vostok +{ +namespace +{ +not_null index_gmi = "index.gmi"; +} // namespace + + +open_file_result open_file(int directory_fd, not_null file_name, unique_fd &opened_file) +{ + if (!*file_name) + file_name = index_gmi; + + opened_file.reset(openat(directory_fd, file_name, O_RDONLY)); + if (!opened_file) + { + const auto error_code = errno; + error::occurred( + [file_name] + { + error::g_log << "Open file \"" << file_name << "\""; + }, + error::print{error_code} + ); + return (error_code == ENOENT) ? file_not_found : file_opening_error; + } + struct stat sb{}; + if (fstat(opened_file.get(), &sb) == -1) + { + error::occurred( + [file_name] + { + error::g_log << "Stat file \"" << file_name << "\""; + }, + error::print{} + ); + return file_opening_error; + } + if (S_ISDIR(sb.st_mode)) + { + const unique_fd new_parent{opened_file.release()}; + opened_file.reset(openat(new_parent.get(), index_gmi, O_RDONLY)); + if (!opened_file) + { + const auto error_code = errno; + error::occurred( + [file_name] + { + error::g_log << "Open file \"" << file_name << "\" /" << index_gmi; + }, + error::print{error_code} + ); + return (error_code == ENOENT) ? file_not_found : file_opening_error; + } + } + return file_opened; +} + + +} // namespace vostok blob - /dev/null blob + b370afb5847fa49a237389954a908a3b9b1ab47f (mode 644) --- /dev/null +++ vostok/open_file.h @@ -0,0 +1,23 @@ +/** Open file for Gemini response */ + +#include "utils.h" + +#pragma once + + +namespace vostok +{ + + +enum open_file_result +{ + file_opened, + + file_not_found, + file_opening_error, +}; + +open_file_result open_file(int directory_fd, not_null file_name, unique_fd &opened_file); + + +} // namespace vostok blob - 69ec0c58385e435f9305149e1903048a474c0154 blob + aeb7bca4f490ff9d8be8d2958cef7d6a1063092c --- vostok/vostok.cc +++ vostok/vostok.cc @@ -4,9 +4,8 @@ #include "transport.h" #include "args.h" #include "parse_url.h" +#include "open_file.h" -#include -#include #include #include #include @@ -76,59 +75,21 @@ void client_thread(transport::accepted_context::value break; } - const unique_fd opened_file{openat(directory_fd, zs_url_path.data(), O_RDONLY)}; - if (!opened_file) + unique_fd opened_file{}; + const auto open_file_result = open_file(directory_fd, zs_url_path.data(), opened_file); + switch (open_file_result) { - const auto error_code = errno; - error::occurred( - [&zs_url_path] - { - error::g_log << "Open file \"" << zs_url_path.data() << "\""; - }, - error::print{error_code} - ); - switch (error_code) - { - case ENOTDIR: - case ENOENT: - case EACCES: - case ELOOP: - case EISDIR: - case ENXIO: - transport::send_response(ctx.get_ctx(), gemini::STATUS_51_NOT_FOUND, meta::not_found); - break; - - default: - transport::send_response(ctx.get_ctx(), gemini::STATUS_40_TEMPORARY_FAILURE, meta::temporary_failure); - break; - } + case file_not_found: + transport::send_response(ctx.get_ctx(), gemini::STATUS_51_NOT_FOUND, meta::not_found); return; - } - struct stat sb{}; - if (fstat(opened_file.get(), &sb) == -1) - { - error::occurred( - [&zs_url_path] - { - error::g_log << "Stat file \"" << zs_url_path.data() << "\""; - }, - error::print{} - ); + case file_opening_error: transport::send_response(ctx.get_ctx(), gemini::STATUS_40_TEMPORARY_FAILURE, meta::temporary_failure); return; + + case file_opened: + assert(opened_file); + break; } - if (S_ISDIR(sb.st_mode)) - { - error::occurred( - [&zs_url_path] - { - error::g_log << "Open file \"" << zs_url_path.data() << "\""; - }, - error::print{EISDIR} - ); - transport::send_response(ctx.get_ctx(), gemini::STATUS_51_NOT_FOUND, meta::not_found); - return; - } // > If is an empty string, the MIME type MUST default to "text/gemini; charset=utf-8". transport::send_response(ctx.get_ctx(), gemini::STATUS_20_SUCCESS, {});