src/file.cpp

88.2% Lines (15/17) 83.3% List of functions (5/6) 90.0% Branches (9/10)
file.cpp
f(x) Functions (6)
Line Branch TLA Hits Source Code
1 //
2 // Copyright (c) 2026 Mohammad Nejati
3 //
4 // Distributed under the Boost Software License, Version 1.0. (See accompanying
5 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 //
7 // Official repository: https://github.com/cppalliance/burl
8 //
9
10 #include <boost/burl/file.hpp>
11
12 #include "detail/send_file.hpp"
13
14 #include <boost/capy/ex/this_coro.hpp>
15 #include <boost/capy/io/any_buffer_source.hpp>
16 #include <boost/capy/io/push_to.hpp>
17 #include <boost/corosio/file_base.hpp>
18 #include <boost/corosio/stream_file.hpp>
19 #include <boost/http/server/mime_types.hpp>
20
21 #include <cstdint>
22 #include <optional>
23 #include <string>
24 #include <system_error>
25 #include <utility>
26
27 namespace boost
28 {
29 namespace burl
30 {
31 namespace
32 {
33
34 class file_body
35 {
36 std::filesystem::path path_;
37 std::string content_type_;
38 std::uint64_t size_ = 0;
39
40 public:
41 8x explicit file_body(std::filesystem::path path)
42 8x : path_(std::move(path))
43 {
44 content_type_ =
45
3/3
✓ Branch 1 taken 8 times.
✓ Branch 4 taken 8 times.
✓ Branch 8 taken 8 times.
8x http::mime_types::content_type(path_.filename().string());
46
2/2
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 5 times.
8x if(content_type_.empty())
47
1/1
✓ Branch 1 taken 3 times.
3x content_type_ = "application/octet-stream";
48
1/1
✓ Branch 1 taken 7 times.
8x size_ = std::filesystem::file_size(path_);
49 9x }
50
51 std::optional<std::string>
52 7x content_type() const
53 {
54 7x return content_type_;
55 }
56
57 std::optional<std::uint64_t>
58 1x content_length() const noexcept
59 {
60 1x return size_;
61 }
62
63 capy::io_task<>
64 1x write(capy::any_buffer_sink& sink) const
65 {
66 1x return detail::send_file(sink, path_, size_);
67 }
68 };
69
70 } // namespace
71
72 any_request_body
73 8x tag_invoke(body_from_tag<std::filesystem::path>, std::filesystem::path path)
74 {
75
2/2
✓ Branch 3 taken 7 times.
✓ Branch 6 taken 7 times.
9x return file_body{ std::move(path) };
76 }
77
78 capy::io_task<std::filesystem::path>
79 tag_invoke(
80 body_to_tag<std::filesystem::path>,
81 response& resp,
82 std::filesystem::path dest)
83 {
84 corosio::stream_file f(co_await capy::this_coro::executor);
85 // TODO: switch to a non-throwing open() overload once available.
86 try
87 {
88 using enum corosio::file_base::flags;
89 f.open(dest, write_only | create | exclusive);
90 }
91 catch(std::system_error const& e)
92 {
93 co_return { e.code(), {} };
94 }
95
96 auto src = resp.as_buffer_source();
97 if(auto [ec, n] = co_await capy::push_to(src, f); ec)
98 co_return { ec, {} };
99
100 co_return { {}, std::move(dest) };
101 }
102
103 } // namespace burl
104 } // namespace boost
105