]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/boost/beast/http/impl/file_body_win32.ipp
Add patch for failing prerm scripts
[ceph.git] / ceph / src / boost / boost / beast / http / impl / file_body_win32.ipp
CommitLineData
b32b8144
FG
1//
2// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
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/boostorg/beast
8//
9
10#ifndef BOOST_BEAST_HTTP_IMPL_FILE_BODY_WIN32_IPP
11#define BOOST_BEAST_HTTP_IMPL_FILE_BODY_WIN32_IPP
12
13#if BOOST_BEAST_USE_WIN32_FILE
14
15#include <boost/beast/core/bind_handler.hpp>
16#include <boost/beast/core/type_traits.hpp>
17#include <boost/beast/core/detail/clamp.hpp>
18#include <boost/beast/http/serializer.hpp>
19#include <boost/asio/associated_allocator.hpp>
20#include <boost/asio/associated_executor.hpp>
21#include <boost/asio/async_result.hpp>
22#include <boost/asio/basic_stream_socket.hpp>
23#include <boost/asio/handler_continuation_hook.hpp>
11fdf7f2 24#include <boost/asio/handler_invoke_hook.hpp>
b32b8144
FG
25#include <boost/asio/windows/overlapped_ptr.hpp>
26#include <boost/make_unique.hpp>
27#include <boost/smart_ptr/make_shared_array.hpp>
28#include <boost/winapi/basic_types.hpp>
11fdf7f2 29#include <boost/winapi/get_last_error.hpp>
b32b8144
FG
30#include <algorithm>
31#include <cstring>
32
33namespace boost {
34namespace beast {
35namespace http {
36
37namespace detail {
38template<class, class, bool, class>
39class write_some_win32_op;
40} // detail
41
42template<>
43struct basic_file_body<file_win32>
44{
45 using file_type = file_win32;
46
47 class writer;
48 class reader;
49
50 //--------------------------------------------------------------------------
51
52 class value_type
53 {
54 friend class writer;
55 friend class reader;
56 friend struct basic_file_body<file_win32>;
57
58 template<class, class, bool, class>
59 friend class detail::write_some_win32_op;
60 template<
61 class Protocol, bool isRequest, class Fields>
62 friend
63 std::size_t
64 write_some(
65 boost::asio::basic_stream_socket<Protocol>& sock,
66 serializer<isRequest,
67 basic_file_body<file_win32>, Fields>& sr,
68 error_code& ec);
69
70 file_win32 file_;
71 std::uint64_t size_ = 0; // cached file size
72 std::uint64_t first_; // starting offset of the range
73 std::uint64_t last_; // ending offset of the range
74
75 public:
76 ~value_type() = default;
77 value_type() = default;
78 value_type(value_type&& other) = default;
79 value_type& operator=(value_type&& other) = default;
80
81 bool
82 is_open() const
83 {
84 return file_.is_open();
85 }
86
87 std::uint64_t
88 size() const
89 {
90 return size_;
91 }
92
93 void
94 close();
95
96 void
97 open(char const* path, file_mode mode, error_code& ec);
98
99 void
100 reset(file_win32&& file, error_code& ec);
101 };
102
103 //--------------------------------------------------------------------------
104
105 class writer
106 {
107 template<class, class, bool, class>
108 friend class detail::write_some_win32_op;
109 template<
110 class Protocol, bool isRequest, class Fields>
111 friend
112 std::size_t
113 write_some(
114 boost::asio::basic_stream_socket<Protocol>& sock,
115 serializer<isRequest,
116 basic_file_body<file_win32>, Fields>& sr,
117 error_code& ec);
118
119 value_type& body_; // The body we are reading from
120 std::uint64_t pos_; // The current position in the file
121 char buf_[4096]; // Small buffer for reading
122
123 public:
124 using const_buffers_type =
125 boost::asio::const_buffer;
126
127 template<bool isRequest, class Fields>
11fdf7f2
TL
128 writer(header<isRequest, Fields>&, value_type& b)
129 : body_(b)
b32b8144
FG
130 {
131 }
132
133 void
134 init(error_code&)
135 {
136 BOOST_ASSERT(body_.file_.is_open());
137 pos_ = body_.first_;
138 }
139
140 boost::optional<std::pair<const_buffers_type, bool>>
141 get(error_code& ec)
142 {
143 std::size_t const n = (std::min)(sizeof(buf_),
144 beast::detail::clamp(body_.last_ - pos_));
145 if(n == 0)
146 {
147 ec.assign(0, ec.category());
148 return boost::none;
149 }
150 auto const nread = body_.file_.read(buf_, n, ec);
151 if(ec)
152 return boost::none;
153 BOOST_ASSERT(nread != 0);
154 pos_ += nread;
155 ec.assign(0, ec.category());
156 return {{
157 {buf_, nread}, // buffer to return.
158 pos_ < body_.last_}}; // `true` if there are more buffers.
159 }
160 };
161
162 //--------------------------------------------------------------------------
163
164 class reader
165 {
166 value_type& body_;
167
168 public:
169 template<bool isRequest, class Fields>
170 explicit
11fdf7f2
TL
171 reader(header<isRequest, Fields>&, value_type& b)
172 : body_(b)
b32b8144
FG
173 {
174 }
175
176 void
177 init(boost::optional<
178 std::uint64_t> const& content_length,
179 error_code& ec)
180 {
181 // VFALCO We could reserve space in the file
182 boost::ignore_unused(content_length);
183 BOOST_ASSERT(body_.file_.is_open());
184 ec.assign(0, ec.category());
185 }
186
187 template<class ConstBufferSequence>
188 std::size_t
189 put(ConstBufferSequence const& buffers,
190 error_code& ec)
191 {
192 std::size_t nwritten = 0;
193 for(auto buffer : beast::detail::buffers_range(buffers))
194 {
195 nwritten += body_.file_.write(
196 buffer.data(), buffer.size(), ec);
197 if(ec)
198 return nwritten;
199 }
200 ec.assign(0, ec.category());
201 return nwritten;
202 }
203
204 void
205 finish(error_code& ec)
206 {
207 ec.assign(0, ec.category());
208 }
209 };
210
211 //--------------------------------------------------------------------------
212
213 static
214 std::uint64_t
215 size(value_type const& body)
216 {
217 return body.size();
218 }
219};
220
221//------------------------------------------------------------------------------
222
223inline
224void
225basic_file_body<file_win32>::
226value_type::
227close()
228{
229 error_code ignored;
230 file_.close(ignored);
231}
232
233inline
234void
235basic_file_body<file_win32>::
236value_type::
237open(char const* path, file_mode mode, error_code& ec)
238{
239 file_.open(path, mode, ec);
240 if(ec)
241 return;
242 size_ = file_.size(ec);
243 if(ec)
244 {
245 close();
246 return;
247 }
248 first_ = 0;
249 last_ = size_;
250}
251
252inline
253void
254basic_file_body<file_win32>::
255value_type::
256reset(file_win32&& file, error_code& ec)
257{
258 if(file_.is_open())
259 {
260 error_code ignored;
261 file_.close(ignored);
262 }
263 file_ = std::move(file);
264 if(file_.is_open())
265 {
266 size_ = file_.size(ec);
267 if(ec)
268 {
269 close();
270 return;
271 }
272 first_ = 0;
273 last_ = size_;
274 }
275}
276
277//------------------------------------------------------------------------------
278
279namespace detail {
280
281template<class Unsigned>
282inline
283boost::winapi::DWORD_
284lowPart(Unsigned n)
285{
286 return static_cast<
287 boost::winapi::DWORD_>(
288 n & 0xffffffff);
289}
290
291template<class Unsigned>
292inline
293boost::winapi::DWORD_
294highPart(Unsigned n, std::true_type)
295{
296 return static_cast<
297 boost::winapi::DWORD_>(
298 (n>>32)&0xffffffff);
299}
300
301template<class Unsigned>
302inline
303boost::winapi::DWORD_
304highPart(Unsigned, std::false_type)
305{
306 return 0;
307}
308
309template<class Unsigned>
310inline
311boost::winapi::DWORD_
312highPart(Unsigned n)
313{
314 return highPart(n, std::integral_constant<
315 bool, (sizeof(Unsigned)>4)>{});
316}
317
318class null_lambda
319{
320public:
321 template<class ConstBufferSequence>
322 void
323 operator()(error_code&,
324 ConstBufferSequence const&) const
325 {
326 BOOST_ASSERT(false);
327 }
328};
329
330//------------------------------------------------------------------------------
331
332#if BOOST_ASIO_HAS_WINDOWS_OVERLAPPED_PTR
333
334template<
335 class Protocol, class Handler,
336 bool isRequest, class Fields>
337class write_some_win32_op
338{
339 boost::asio::basic_stream_socket<Protocol>& sock_;
340 serializer<isRequest,
341 basic_file_body<file_win32>, Fields>& sr_;
342 std::size_t bytes_transferred_ = 0;
343 Handler h_;
344 bool header_ = false;
345
346public:
347 write_some_win32_op(write_some_win32_op&&) = default;
11fdf7f2 348 write_some_win32_op(write_some_win32_op const&) = delete;
b32b8144
FG
349
350 template<class DeducedHandler>
351 write_some_win32_op(
352 DeducedHandler&& h,
353 boost::asio::basic_stream_socket<Protocol>& s,
354 serializer<isRequest,
355 basic_file_body<file_win32>,Fields>& sr)
356 : sock_(s)
357 , sr_(sr)
358 , h_(std::forward<DeducedHandler>(h))
359 {
360 }
361
362 using allocator_type =
363 boost::asio::associated_allocator_t<Handler>;
364
365 allocator_type
366 get_allocator() const noexcept
367 {
11fdf7f2 368 return (boost::asio::get_associated_allocator)(h_);
b32b8144
FG
369 }
370
371 using executor_type =
372 boost::asio::associated_executor_t<Handler, decltype(std::declval<
373 boost::asio::basic_stream_socket<Protocol>&>().get_executor())>;
374
375 executor_type
376 get_executor() const noexcept
377 {
11fdf7f2 378 return (boost::asio::get_associated_executor)(
b32b8144
FG
379 h_, sock_.get_executor());
380 }
381
382 void
383 operator()();
384
385 void
386 operator()(
387 error_code ec,
388 std::size_t bytes_transferred = 0);
389
390 friend
391 bool asio_handler_is_continuation(write_some_win32_op* op)
392 {
393 using boost::asio::asio_handler_is_continuation;
394 return asio_handler_is_continuation(
395 std::addressof(op->h_));
396 }
11fdf7f2
TL
397
398 template<class Function>
399 friend
400 void asio_handler_invoke(Function&& f, write_some_win32_op* op)
401 {
402 using boost::asio::asio_handler_invoke;
403 asio_handler_invoke(f, std::addressof(op->h_));
404 }
b32b8144
FG
405};
406
407template<
408 class Protocol, class Handler,
409 bool isRequest, class Fields>
410void
411write_some_win32_op<
412 Protocol, Handler, isRequest, Fields>::
413operator()()
414{
415 if(! sr_.is_header_done())
416 {
417 header_ = true;
418 sr_.split(true);
11fdf7f2 419 return detail::async_write_some_impl(
b32b8144
FG
420 sock_, sr_, std::move(*this));
421 }
422 if(sr_.get().chunked())
423 {
11fdf7f2 424 return detail::async_write_some_impl(
b32b8144
FG
425 sock_, sr_, std::move(*this));
426 }
11fdf7f2 427 auto& w = sr_.writer_impl();
b32b8144
FG
428 boost::winapi::DWORD_ const nNumberOfBytesToWrite =
429 static_cast<boost::winapi::DWORD_>(
430 (std::min<std::uint64_t>)(
11fdf7f2 431 (std::min<std::uint64_t>)(w.body_.last_ - w.pos_, sr_.limit()),
b32b8144
FG
432 (std::numeric_limits<boost::winapi::DWORD_>::max)()));
433 boost::asio::windows::overlapped_ptr overlapped{
11fdf7f2
TL
434 sock_.get_executor().context(), std::move(*this)};
435 // Note that we have moved *this, so we cannot access
436 // the handler since it is now moved-from. We can still
437 // access simple things like references and built-in types.
b32b8144 438 auto& ov = *overlapped.get();
11fdf7f2
TL
439 ov.Offset = lowPart(w.pos_);
440 ov.OffsetHigh = highPart(w.pos_);
b32b8144
FG
441 auto const bSuccess = ::TransmitFile(
442 sock_.native_handle(),
443 sr_.get().body().file_.native_handle(),
444 nNumberOfBytesToWrite,
445 0,
446 overlapped.get(),
447 nullptr,
448 0);
11fdf7f2 449 auto const dwError = boost::winapi::GetLastError();
b32b8144
FG
450 if(! bSuccess && dwError !=
451 boost::winapi::ERROR_IO_PENDING_)
452 {
453 // VFALCO This needs review, is 0 the right number?
454 // completed immediately (with error?)
11fdf7f2 455 overlapped.complete(error_code{static_cast<int>(dwError),
b32b8144
FG
456 system_category()}, 0);
457 return;
458 }
459 overlapped.release();
460}
461
462template<
463 class Protocol, class Handler,
464 bool isRequest, class Fields>
465void
466write_some_win32_op<
467 Protocol, Handler, isRequest, Fields>::
468operator()(
469 error_code ec, std::size_t bytes_transferred)
470{
471 bytes_transferred_ += bytes_transferred;
472 if(! ec)
473 {
474 if(header_)
475 {
476 header_ = false;
477 return (*this)();
478 }
11fdf7f2
TL
479 auto& w = sr_.writer_impl();
480 w.pos_ += bytes_transferred;
481 BOOST_ASSERT(w.pos_ <= w.body_.last_);
482 if(w.pos_ >= w.body_.last_)
b32b8144
FG
483 {
484 sr_.next(ec, null_lambda{});
485 BOOST_ASSERT(! ec);
486 BOOST_ASSERT(sr_.is_done());
487 }
488 }
489 h_(ec, bytes_transferred_);
490}
491
492#endif
493
494} // detail
495
496//------------------------------------------------------------------------------
497
498template<class Protocol, bool isRequest, class Fields>
499std::size_t
500write_some(
501 boost::asio::basic_stream_socket<Protocol>& sock,
502 serializer<isRequest,
503 basic_file_body<file_win32>, Fields>& sr,
504 error_code& ec)
505{
506 if(! sr.is_header_done())
507 {
508 sr.split(true);
509 auto const bytes_transferred =
11fdf7f2 510 detail::write_some_impl(sock, sr, ec);
b32b8144
FG
511 if(ec)
512 return bytes_transferred;
513 return bytes_transferred;
514 }
515 if(sr.get().chunked())
516 {
517 auto const bytes_transferred =
11fdf7f2 518 detail::write_some_impl(sock, sr, ec);
b32b8144
FG
519 if(ec)
520 return bytes_transferred;
521 return bytes_transferred;
522 }
11fdf7f2
TL
523 auto& w = sr.writer_impl();
524 w.body_.file_.seek(w.pos_, ec);
b32b8144
FG
525 if(ec)
526 return 0;
527 boost::winapi::DWORD_ const nNumberOfBytesToWrite =
528 static_cast<boost::winapi::DWORD_>(
529 (std::min<std::uint64_t>)(
11fdf7f2 530 (std::min<std::uint64_t>)(w.body_.last_ - w.pos_, sr.limit()),
b32b8144
FG
531 (std::numeric_limits<boost::winapi::DWORD_>::max)()));
532 auto const bSuccess = ::TransmitFile(
533 sock.native_handle(),
11fdf7f2 534 w.body_.file_.native_handle(),
b32b8144
FG
535 nNumberOfBytesToWrite,
536 0,
537 nullptr,
538 nullptr,
539 0);
540 if(! bSuccess)
541 {
542 ec.assign(static_cast<int>(
543 boost::winapi::GetLastError()),
544 system_category());
545 return 0;
546 }
11fdf7f2
TL
547 w.pos_ += nNumberOfBytesToWrite;
548 BOOST_ASSERT(w.pos_ <= w.body_.last_);
549 if(w.pos_ < w.body_.last_)
b32b8144
FG
550 {
551 ec.assign(0, ec.category());
552 }
553 else
554 {
555 sr.next(ec, detail::null_lambda{});
556 BOOST_ASSERT(! ec);
557 BOOST_ASSERT(sr.is_done());
558 }
559 return nNumberOfBytesToWrite;
560}
561
562#if BOOST_ASIO_HAS_WINDOWS_OVERLAPPED_PTR
563
564template<
565 class Protocol,
566 bool isRequest, class Fields,
567 class WriteHandler>
568BOOST_ASIO_INITFN_RESULT_TYPE(
569 WriteHandler, void(error_code, std::size_t))
570async_write_some(
571 boost::asio::basic_stream_socket<Protocol>& sock,
572 serializer<isRequest,
573 basic_file_body<file_win32>, Fields>& sr,
574 WriteHandler&& handler)
575{
11fdf7f2
TL
576 BOOST_BEAST_HANDLER_INIT(
577 WriteHandler, void(error_code, std::size_t));
b32b8144
FG
578 detail::write_some_win32_op<
579 Protocol,
580 BOOST_ASIO_HANDLER_TYPE(WriteHandler,
581 void(error_code, std::size_t)),
582 isRequest, Fields>{
11fdf7f2 583 std::move(init.completion_handler), sock, sr}();
b32b8144
FG
584 return init.result.get();
585}
586
587#endif
588
589} // http
590} // beast
591} // boost
592
593#endif
594
595#endif