commit - aedb452477c60551dc13c223da74f0878488caeb
commit + 744cd5d55114a8cc73324a86d0e654c8115b049b
blob - 49612ff96d3235a80905edc5971fcfb2421069b8
blob + 353cef1cf625b5329877f12bc183fb59a1ccf013
--- tests/test_open_file.cc
+++ tests/test_open_file.cc
struct stat sb1{};
IS_TRUE_ERRNO(fstat(dir.get(), &sb1) != -1, "Stat file " << ss.str().c_str())
+ {
+ UniqueFd opened_fd;
+ IS_TRUE(open_file::open(dir.get(), "", opened_fd) == open_file::SUCCESS_DIRECTORY);
- std::string file_name;
+ UniqueFd not_opened_fd;
+ IS_TRUE(open_file::open(opened_fd.get(), "index.gmi", not_opened_fd) == open_file::ERROR_NOT_EXIST);
+ struct stat sb2{};
+ IS_TRUE_ERRNO(fstat(opened_fd.get(), &sb2) != -1, "Stat file " << ss.str().c_str());
+ IS_TRUE((sb1.st_dev == sb2.st_dev) && (sb1.st_ino == sb2.st_ino));
+ }
{
UniqueFd opened_fd;
- file_name = "";
- IS_TRUE(open_file::open(dir.get(), file_name, opened_fd) == open_file::OPENED_DIRECTORY);
+ IS_TRUE(open_file::open(dir.get(), "/", opened_fd) == open_file::SUCCESS_DIRECTORY);
+ UniqueFd not_opened_fd;
+ IS_TRUE(open_file::open(opened_fd.get(), "index.gmi", not_opened_fd) == open_file::ERROR_NOT_EXIST);
+
struct stat sb2{};
IS_TRUE_ERRNO(fstat(opened_fd.get(), &sb2) != -1, "Stat file " << ss.str().c_str());
IS_TRUE((sb1.st_dev == sb2.st_dev) && (sb1.st_ino == sb2.st_ino));
}
{
UniqueFd opened_fd;
- file_name = "/";
- IS_TRUE(open_file::open(dir.get(), file_name, opened_fd) == open_file::OPENED_DIRECTORY);
+ IS_TRUE(open_file::open(dir.get(), ".", opened_fd) == open_file::SUCCESS_DIRECTORY);
+ UniqueFd not_opened_fd;
+ IS_TRUE(open_file::open(opened_fd.get(), "index.gmi", not_opened_fd) == open_file::ERROR_NOT_EXIST);
+
struct stat sb2{};
IS_TRUE_ERRNO(fstat(opened_fd.get(), &sb2) != -1, "Stat file " << ss.str().c_str());
IS_TRUE((sb1.st_dev == sb2.st_dev) && (sb1.st_ino == sb2.st_ino));
}
+
{
UniqueFd opened_fd;
- file_name = "non-existent-file";
- IS_TRUE(open_file::open(dir.get(), file_name, opened_fd) == open_file::NOT_FOUND);
+ IS_TRUE(open_file::open(dir.get(), "non-existent-file", opened_fd) == open_file::ERROR_NOT_EXIST);
}
{
UniqueFd opened_fd;
- file_name = "non-existent-dir/file";
- IS_TRUE(open_file::open(dir.get(), file_name, opened_fd) == open_file::NOT_FOUND);
+ IS_TRUE(open_file::open(dir.get(), "non-existent-dir/file", opened_fd) == open_file::ERROR_NOT_EXIST);
}
const UniqueFd index_gmi{openat(dir.get(), "index.gmi", O_RDONLY | O_CREAT | O_EXCL, S_IRWXU)};
IS_TRUE_ERRNO(index_gmi, "Create file " << ss.str().c_str() << "/index.gmi");
IS_TRUE_ERRNO(fstat(index_gmi.get(), &sb1) != -1, "Stat file " << ss.str().c_str() << "/index.gmi");
-/*
+
+
{
- OpenedFile opened_file;
- file_name = "";
- IS_TRUE(opened_file.open(dir.get(), file_name) == OpenedFile::OPENED);
- IS_TRUE(opened_file.get_path() == "index.gmi");
+ UniqueFd opened_dir;
+ IS_TRUE(open_file::open(dir.get(), "", opened_dir) == open_file::SUCCESS_DIRECTORY);
+ UniqueFd opened_fd;
+ IS_TRUE(open_file::open(opened_dir.get(), "index.gmi", opened_fd) == open_file::SUCCESS_FILE);
+
struct stat sb2{};
- IS_TRUE_ERRNO(fstat(opened_file.get_fd(), &sb2) != -1, "Stat file " << ss.str().c_str() << "/index.gmi");
+ IS_TRUE_ERRNO(fstat(opened_fd.get(), &sb2) != -1, "Stat file " << ss.str().c_str());
IS_TRUE((sb1.st_dev == sb2.st_dev) && (sb1.st_ino == sb2.st_ino));
}
+ {
+ UniqueFd opened_dir;
+ IS_TRUE(open_file::open(dir.get(), "/", opened_dir) == open_file::SUCCESS_DIRECTORY);
+ UniqueFd opened_fd;
+ IS_TRUE(open_file::open(opened_dir.get(), "index.gmi", opened_fd) == open_file::SUCCESS_FILE);
+
+ struct stat sb2{};
+ IS_TRUE_ERRNO(fstat(opened_fd.get(), &sb2) != -1, "Stat file " << ss.str().c_str());
+ IS_TRUE((sb1.st_dev == sb2.st_dev) && (sb1.st_ino == sb2.st_ino));
+ }
{
- OpenedFile opened_file;
- file_name = "index.gmi";
- IS_TRUE(opened_file.open(dir.get(), file_name) == OpenedFile::OPENED);
- IS_TRUE(opened_file.get_path() == "index.gmi");
+ UniqueFd opened_dir;
+ IS_TRUE(open_file::open(dir.get(), ".", opened_dir) == open_file::SUCCESS_DIRECTORY);
+
+ UniqueFd opened_fd;
+ IS_TRUE(open_file::open(opened_dir.get(), "index.gmi", opened_fd) == open_file::SUCCESS_FILE);
+
struct stat sb2{};
- IS_TRUE_ERRNO(fstat(opened_file.get_fd(), &sb2) != -1, "Stat file " << ss.str().c_str() << "/index.gmi");
+ IS_TRUE_ERRNO(fstat(opened_fd.get(), &sb2) != -1, "Stat file " << ss.str().c_str());
IS_TRUE((sb1.st_dev == sb2.st_dev) && (sb1.st_ino == sb2.st_ino));
}
+ {
+ UniqueFd opened_fd;
+ IS_TRUE(open_file::open(dir.get(), "index.gmi", opened_fd) == open_file::SUCCESS_FILE);
+
+ struct stat sb2{};
+ IS_TRUE_ERRNO(fstat(opened_fd.get(), &sb2) != -1, "Stat file " << ss.str().c_str());
+ IS_TRUE((sb1.st_dev == sb2.st_dev) && (sb1.st_ino == sb2.st_ino));
+ }
+
IS_TRUE_ERRNO(mkdirat(dir.get(), "subdir", S_IRWXU) != -1, "Create directory " << ss.str().c_str() << "/subdir");
+ const UniqueFd subdir{openat(dir.get(), "subdir", O_RDONLY | O_DIRECTORY)};
+ IS_TRUE_ERRNO(subdir, "Open directory " << ss.str().c_str() << "/subdir");
+ IS_TRUE_ERRNO(fstat(subdir.get(), &sb1) != -1, "Stat file " << ss.str().c_str())
+
{
- OpenedFile opened_file;
- file_name = "subdir";
- IS_TRUE(opened_file.open(dir.get(), file_name) == OpenedFile::NOT_FOUND);
+ UniqueFd opened_fd;
+ IS_TRUE(open_file::open(dir.get(), "subdir", opened_fd) == open_file::SUCCESS_DIRECTORY);
+
+ UniqueFd not_opened_fd;
+ IS_TRUE(open_file::open(opened_fd.get(), "index.gmi", not_opened_fd) == open_file::ERROR_NOT_EXIST);
+
+ struct stat sb2{};
+ IS_TRUE_ERRNO(fstat(opened_fd.get(), &sb2) != -1, "Stat file " << ss.str().c_str());
+ IS_TRUE((sb1.st_dev == sb2.st_dev) && (sb1.st_ino == sb2.st_ino));
}
{
- OpenedFile opened_file;
- file_name = "subdir/";
- IS_TRUE(opened_file.open(dir.get(), file_name) == OpenedFile::NOT_FOUND);
+ UniqueFd opened_fd;
+ IS_TRUE(open_file::open(dir.get(), "subdir/", opened_fd) == open_file::SUCCESS_DIRECTORY);
+
+ UniqueFd not_opened_fd;
+ IS_TRUE(open_file::open(opened_fd.get(), "index.gmi", not_opened_fd) == open_file::ERROR_NOT_EXIST);
+
+ struct stat sb2{};
+ IS_TRUE_ERRNO(fstat(opened_fd.get(), &sb2) != -1, "Stat file " << ss.str().c_str());
+ IS_TRUE((sb1.st_dev == sb2.st_dev) && (sb1.st_ino == sb2.st_ino));
}
- const UniqueFd subdir{openat(dir.get(), "subdir", O_RDONLY | O_DIRECTORY)};
- IS_TRUE_ERRNO(subdir, "Open directory " << ss.str().c_str() << "/subdir");
const UniqueFd sub_index_gmi{openat(subdir.get(), "index.gmi", O_RDONLY | O_CREAT | O_EXCL, S_IRWXU)};
IS_TRUE_ERRNO(sub_index_gmi, "Create file " << ss.str().c_str() << "/subdir/index.gmi");
IS_TRUE_ERRNO(fstat(sub_index_gmi.get(), &sb1) != -1, "Stat file " << ss.str().c_str() << "/subdir/index.gmi");
{
- OpenedFile opened_file;
- file_name = "subdir";
- IS_TRUE(opened_file.open(dir.get(), file_name) == OpenedFile::OPENED);
- IS_TRUE(opened_file.get_path() == "index.gmi");
+ UniqueFd opened_dir;
+ IS_TRUE(open_file::open(dir.get(), "subdir", opened_dir) == open_file::SUCCESS_DIRECTORY);
+
+ UniqueFd opened_fd;
+ IS_TRUE(open_file::open(opened_dir.get(), "index.gmi", opened_fd) == open_file::SUCCESS_FILE);
+
struct stat sb2{};
- IS_TRUE_ERRNO(fstat(opened_file.get_fd(), &sb2) != -1, "Stat file " << ss.str().c_str() << "/subdir/index.gmi");
+ IS_TRUE_ERRNO(fstat(opened_fd.get(), &sb2) != -1, "Stat file " << ss.str().c_str());
IS_TRUE((sb1.st_dev == sb2.st_dev) && (sb1.st_ino == sb2.st_ino));
}
{
- OpenedFile opened_file;
- file_name = "subdir/";
- IS_TRUE(opened_file.open(dir.get(), file_name) == OpenedFile::OPENED);
- IS_TRUE(opened_file.get_path() == "index.gmi");
+ UniqueFd opened_dir;
+ IS_TRUE(open_file::open(dir.get(), "subdir/", opened_dir) == open_file::SUCCESS_DIRECTORY);
+
+ UniqueFd opened_fd;
+ IS_TRUE(open_file::open(opened_dir.get(), "index.gmi", opened_fd) == open_file::SUCCESS_FILE);
+
struct stat sb2{};
- IS_TRUE_ERRNO(fstat(opened_file.get_fd(), &sb2) != -1, "Stat file " << ss.str().c_str() << "/subdir/index.gmi");
+ IS_TRUE_ERRNO(fstat(opened_fd.get(), &sb2) != -1, "Stat file " << ss.str().c_str());
IS_TRUE((sb1.st_dev == sb2.st_dev) && (sb1.st_ino == sb2.st_ino));
}
+
{
- OpenedFile opened_file;
- file_name = "subdir/index.gmi";
- IS_TRUE(opened_file.open(dir.get(), file_name) == OpenedFile::OPENED);
- IS_TRUE(opened_file.get_path() == "subdir/index.gmi");
+ UniqueFd opened_fd;
+ IS_TRUE(open_file::open(dir.get(), "subdir/index.gmi", opened_fd) == open_file::SUCCESS_FILE);
+
struct stat sb2{};
- IS_TRUE_ERRNO(fstat(opened_file.get_fd(), &sb2) != -1, "Stat file " << ss.str().c_str() << "/subdir/index.gmi");
+ IS_TRUE_ERRNO(fstat(opened_fd.get(), &sb2) != -1, "Stat file " << ss.str().c_str());
IS_TRUE((sb1.st_dev == sb2.st_dev) && (sb1.st_ino == sb2.st_ino));
}
IS_TRUE_ERRNO(eperm, "Create file " << ss.str().c_str() << "/subdir/index.gmi");
{
- OpenedFile opened_file;
- file_name = "subdir/EPERM.gmi";
- IS_TRUE(opened_file.open(dir.get(), file_name) == OpenedFile::OPENING_ERROR);
+ UniqueFd opened_fd;
+ IS_TRUE(open_file::open(dir.get(), "subdir/EPERM.gmi", opened_fd) == open_file::ERROR);
}
IS_TRUE_ERRNO(unlinkat(subdir.get(), "EPERM.gmi", 0) != -1, "Remove file " << ss.str().c_str() << "/subdir/EPERM.gmi");
- IS_TRUE_ERRNO(unlinkat(subdir.get(), "index.gmi", 0) != -1, "Remove file " << ss.str().c_str() << "/subdir/index.gmi");
+ IS_TRUE_ERRNO(unlinkat(subdir.get(), "index.gmi", 0) != -1, "Remove file " << ss.str().c_str() << "/subdir/index.gmi");
IS_TRUE_ERRNO(unlinkat(dir.get(), "subdir", AT_REMOVEDIR) != -1, "Remove directory " << ss.str().c_str() << "/subdir");
-*/
IS_TRUE_ERRNO(unlinkat(dir.get(), "index.gmi", 0) != -1, "Remove file " << ss.str().c_str() << "/index.gmi");
IS_TRUE_ERRNO(rmdir(ss.str().c_str()) != -1, "Remove directory " << ss.str().c_str());
TEST_END()
blob - b5b7f57ed4ca0a2f5dd7b6298a98b2c28431e105
blob + 7f087caa76e95ee647bee77a1c0d230aad3f151a
--- vostok/gemini.cc
+++ vostok/gemini.cc
const std::array<const char, 1> SPACE{' '};
const Status STATUS_20_SUCCESS{'2', '0'};
+const Status STATUS_31_REDIRECT_PERMANENT{'3', '1'};
const Status STATUS_40_TEMPORARY_FAILURE{'4', '0'};
const Status STATUS_50_PERMANENT_FAILURE{'5', '0'};
const Status STATUS_51_NOT_FOUND{'5', '1'};
blob - b2961666037e48305f30dad7d0e7aec54c6ab38f
blob + cc773ff8a5e870b10d30c9be82bc14f75c33ec24
--- vostok/gemini.h
+++ vostok/gemini.h
using Status = std::array<const char, 2>;
extern const Status STATUS_20_SUCCESS;
+extern const Status STATUS_31_REDIRECT_PERMANENT;
extern const Status STATUS_40_TEMPORARY_FAILURE;
extern const Status STATUS_50_PERMANENT_FAILURE;
extern const Status STATUS_51_NOT_FOUND;
blob - 6b9722c01a9c7d891f6f144c06294b9746b0f490
blob + 446f09e8e1c185b1f0dfc5b60b0217c4db190f41
--- vostok/open_file.cc
+++ vostok/open_file.cc
namespace vostok
{
-
namespace open_file
{
+namespace
+{
-static
+
const char *get_pathname(const std::string &path)
{
if (path.empty() || (path.size() == 1 && path[0] == '/'))
return path.c_str();
}
+
+} // namespace <unnamed>
+
+
Result open(
/* in */ int directory_fd,
/* in */ const std::string &path,
},
error::Print{error_code}
);
- return (error_code == ENOENT) ? NOT_FOUND : OPENING_ERROR;
+ return (error_code == ENOENT) ? ERROR_NOT_EXIST : ERROR;
}
struct stat sb{};
if (fstat(opened_fd.get(), &sb) == -1)
},
error::Print{}
);
- return OPENING_ERROR;
+ return ERROR;
}
- return S_ISDIR(sb.st_mode) ? OPENED_DIRECTORY : OPENED;
+ return S_ISDIR(sb.st_mode) ? SUCCESS_DIRECTORY : SUCCESS_FILE;
}
} // namespace open_file
-
-
-namespace open_directory
-{
-
-
-const std::string g_index_gmi{"index.gmi"};
-
-
-Result open(
- /* in */ int directory_fd,
- /* out */ UniqueFd &opened_fd
-)
-{
- opened_fd.reset(openat(directory_fd, g_index_gmi.c_str(), O_RDONLY));
- if (!opened_fd)
- {
- const auto error_code = errno;
- error::occurred(
- []
- {
- error::g_log << "Open file \"" << g_index_gmi << "\"";
- },
- error::Print{error_code}
- );
- return (error_code == ENOENT) ? NOT_FOUND : OPENING_ERROR;
- }
- struct stat sb{};
- if (fstat(opened_fd.get(), &sb) == -1)
- {
- error::occurred(
- []
- {
- error::g_log << "Stat file \"" << g_index_gmi << "\"";
- },
- error::Print{}
- );
- return OPENING_ERROR;
- }
- if (S_ISDIR(sb.st_mode))
- {
- opened_fd.reset();
- return NOT_FOUND;
- }
- return OPENED;
-}
-
-
-} // namespace open_directory
-
-
} // namespace vostok
blob - 1b9e6dcf59466e29a5c2269d3c64da36ed8f34c2
blob + 65b466d343ad662d961706df5f678d590d7e0bfd
--- vostok/open_file.h
+++ vostok/open_file.h
namespace vostok
{
-
namespace open_file
{
enum Result
{
- OPENED,
- OPENED_DIRECTORY,
+ SUCCESS_FILE,
+ SUCCESS_DIRECTORY,
- NOT_FOUND,
- OPENING_ERROR,
+ ERROR_NOT_EXIST,
+ ERROR,
};
Result open(
} // namespace open_file
-
-
-namespace open_directory
-{
-
-
-enum Result
-{
- OPENED,
-
- NOT_FOUND,
- OPENING_ERROR,
-};
-
-Result open(
- /* in */ int directory_fd,
- /* out */ UniqueFd &opened_fd
-);
-
-extern const std::string g_index_gmi;
-
-
-} // namespace open_directory
-
} // namespace vostok
blob - df7bf0dab186cee47db6271b9a9a8be91a51a3b5
blob + 5523241a2da909a0eb343c9dcfcf1bfc999b9e49
--- vostok/vostok.cc
+++ vostok/vostok.cc
const std::string ROOT_TRAVERSE{"Wrong traverse"};
const std::string NOT_FOUND{"Not found"};
const std::string TEMPORARY_FAILURE{"Temporary failure"};
+const std::string ROOT{"/"};
} // namespace meta
+const std::string g_index_gmi{"index.gmi"};
+
bool send_response(NotNull<struct tls *> ctx, gemini::Status status, const std::string &meta)
{
// <STATUS><SPACE><META><CR><LF>
break;
}
- OpenedFile opened_file;
- const auto open_file_result = opened_file.open(directory_fd, path);
+ UniqueFd opened_dir;
+ UniqueFd opened_fd;
+ auto open_file_result = open_file::open(directory_fd, path, opened_fd);
+ const std::string *opened_path{nullptr};
switch (open_file_result)
{
- case OpenedFile::NOT_FOUND:
+ case open_file::ERROR_NOT_EXIST:
send_response(accepted_client->get_ctx(), gemini::STATUS_51_NOT_FOUND, meta::NOT_FOUND);
return;
- case OpenedFile::OPENING_ERROR:
+ case open_file::ERROR:
send_response(accepted_client->get_ctx(), gemini::STATUS_40_TEMPORARY_FAILURE, meta::TEMPORARY_FAILURE);
return;
-
- case OpenedFile::OPENED:
+ case open_file::SUCCESS_DIRECTORY:
+ if (path.empty())
+ {
+ send_response(accepted_client->get_ctx(), gemini::STATUS_31_REDIRECT_PERMANENT, meta::ROOT);
+ error::g_log << "31 " << " -> \"" << meta::ROOT << "\"" << std::endl;
+ return;
+ }
+ if (*path.crbegin() != '/')
+ {
+ assert(path[0] != '/');
+ path.insert(0, 1, '/');
+ path.push_back('/');
+ send_response(accepted_client->get_ctx(), gemini::STATUS_31_REDIRECT_PERMANENT, path);
+ error::g_log << "31 " << " -> \"" << path << "\"" << std::endl;
+ return;
+ }
+ opened_dir.reset(opened_fd.release());
+ open_file_result = open_file::open(opened_dir.get(), g_index_gmi, opened_fd);
+ switch(open_file_result)
+ {
+ case open_file::ERROR_NOT_EXIST:
+ case open_file::SUCCESS_DIRECTORY:
+ send_response(accepted_client->get_ctx(), gemini::STATUS_51_NOT_FOUND, meta::NOT_FOUND);
+ return;
+ case open_file::ERROR:
+ send_response(accepted_client->get_ctx(), gemini::STATUS_40_TEMPORARY_FAILURE, meta::TEMPORARY_FAILURE);
+ return;
+ case open_file::SUCCESS_FILE:
+ opened_path = &g_index_gmi;
+ break;
+ }
break;
+ case open_file::SUCCESS_FILE:
+ opened_path = &path;
+ break;
}
// > If <META> is an empty string, the MIME type MUST default to "text/gemini; charset=utf-8".
- const auto mime_type = mime.lookup(opened_file.get_path());
- send_response(
- accepted_client->get_ctx(),
- gemini::STATUS_20_SUCCESS,
- mime_type ? *mime_type : meta::_EMPTY
- );
+ const auto _mime_type = mime.lookup(*opened_path);
+ const std::string &meta_string = _mime_type ? *_mime_type : meta::_EMPTY;
+ send_response(accepted_client->get_ctx(), gemini::STATUS_20_SUCCESS, meta_string);
std::vector<char> buffer;
buffer.resize(64 * 1024);
for (; ; )
{
- const auto ret = read(opened_file.get_fd(), buffer.data(), buffer.size());
+ const auto ret = read(opened_fd.get(), buffer.data(), buffer.size());
if (ret == -1)
{
error::occurred(
- [&opened_file]
+ [&path]
{
- error::g_log << "Read file \"" << opened_file.get_path() << "\"";
+ error::g_log << "Read file \"" << path << "\"";
},
error::Print{}
);
if (readed < buffer.size())
break;
}
- error::g_log << "20 " << (mime_type ? *mime_type : meta::_EMPTY) << " \"" << opened_file.get_path() << "\"" << std::endl;
+ error::g_log << "20 " << meta_string << " \"" << path << "\"" << std::endl;
}