]> git.proxmox.com Git - ceph.git/blob - 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
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>
24 #include <boost/asio/handler_invoke_hook.hpp>
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>
29 #include <boost/winapi/get_last_error.hpp>
30 #include <algorithm>
31 #include <cstring>
32
33 namespace boost {
34 namespace beast {
35 namespace http {
36
37 namespace detail {
38 template<class, class, bool, class>
39 class write_some_win32_op;
40 } // detail
41
42 template<>
43 struct 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>
128 writer(header<isRequest, Fields>&, value_type& b)
129 : body_(b)
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
171 reader(header<isRequest, Fields>&, value_type& b)
172 : body_(b)
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
223 inline
224 void
225 basic_file_body<file_win32>::
226 value_type::
227 close()
228 {
229 error_code ignored;
230 file_.close(ignored);
231 }
232
233 inline
234 void
235 basic_file_body<file_win32>::
236 value_type::
237 open(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
252 inline
253 void
254 basic_file_body<file_win32>::
255 value_type::
256 reset(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
279 namespace detail {
280
281 template<class Unsigned>
282 inline
283 boost::winapi::DWORD_
284 lowPart(Unsigned n)
285 {
286 return static_cast<
287 boost::winapi::DWORD_>(
288 n & 0xffffffff);
289 }
290
291 template<class Unsigned>
292 inline
293 boost::winapi::DWORD_
294 highPart(Unsigned n, std::true_type)
295 {
296 return static_cast<
297 boost::winapi::DWORD_>(
298 (n>>32)&0xffffffff);
299 }
300
301 template<class Unsigned>
302 inline
303 boost::winapi::DWORD_
304 highPart(Unsigned, std::false_type)
305 {
306 return 0;
307 }
308
309 template<class Unsigned>
310 inline
311 boost::winapi::DWORD_
312 highPart(Unsigned n)
313 {
314 return highPart(n, std::integral_constant<
315 bool, (sizeof(Unsigned)>4)>{});
316 }
317
318 class null_lambda
319 {
320 public:
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
334 template<
335 class Protocol, class Handler,
336 bool isRequest, class Fields>
337 class 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
346 public:
347 write_some_win32_op(write_some_win32_op&&) = default;
348 write_some_win32_op(write_some_win32_op const&) = delete;
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 {
368 return (boost::asio::get_associated_allocator)(h_);
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 {
378 return (boost::asio::get_associated_executor)(
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 }
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 }
405 };
406
407 template<
408 class Protocol, class Handler,
409 bool isRequest, class Fields>
410 void
411 write_some_win32_op<
412 Protocol, Handler, isRequest, Fields>::
413 operator()()
414 {
415 if(! sr_.is_header_done())
416 {
417 header_ = true;
418 sr_.split(true);
419 return detail::async_write_some_impl(
420 sock_, sr_, std::move(*this));
421 }
422 if(sr_.get().chunked())
423 {
424 return detail::async_write_some_impl(
425 sock_, sr_, std::move(*this));
426 }
427 auto& w = sr_.writer_impl();
428 boost::winapi::DWORD_ const nNumberOfBytesToWrite =
429 static_cast<boost::winapi::DWORD_>(
430 (std::min<std::uint64_t>)(
431 (std::min<std::uint64_t>)(w.body_.last_ - w.pos_, sr_.limit()),
432 (std::numeric_limits<boost::winapi::DWORD_>::max)()));
433 boost::asio::windows::overlapped_ptr overlapped{
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.
438 auto& ov = *overlapped.get();
439 ov.Offset = lowPart(w.pos_);
440 ov.OffsetHigh = highPart(w.pos_);
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);
449 auto const dwError = boost::winapi::GetLastError();
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?)
455 overlapped.complete(error_code{static_cast<int>(dwError),
456 system_category()}, 0);
457 return;
458 }
459 overlapped.release();
460 }
461
462 template<
463 class Protocol, class Handler,
464 bool isRequest, class Fields>
465 void
466 write_some_win32_op<
467 Protocol, Handler, isRequest, Fields>::
468 operator()(
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 }
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_)
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
498 template<class Protocol, bool isRequest, class Fields>
499 std::size_t
500 write_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 =
510 detail::write_some_impl(sock, sr, ec);
511 if(ec)
512 return bytes_transferred;
513 return bytes_transferred;
514 }
515 if(sr.get().chunked())
516 {
517 auto const bytes_transferred =
518 detail::write_some_impl(sock, sr, ec);
519 if(ec)
520 return bytes_transferred;
521 return bytes_transferred;
522 }
523 auto& w = sr.writer_impl();
524 w.body_.file_.seek(w.pos_, ec);
525 if(ec)
526 return 0;
527 boost::winapi::DWORD_ const nNumberOfBytesToWrite =
528 static_cast<boost::winapi::DWORD_>(
529 (std::min<std::uint64_t>)(
530 (std::min<std::uint64_t>)(w.body_.last_ - w.pos_, sr.limit()),
531 (std::numeric_limits<boost::winapi::DWORD_>::max)()));
532 auto const bSuccess = ::TransmitFile(
533 sock.native_handle(),
534 w.body_.file_.native_handle(),
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 }
547 w.pos_ += nNumberOfBytesToWrite;
548 BOOST_ASSERT(w.pos_ <= w.body_.last_);
549 if(w.pos_ < w.body_.last_)
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
564 template<
565 class Protocol,
566 bool isRequest, class Fields,
567 class WriteHandler>
568 BOOST_ASIO_INITFN_RESULT_TYPE(
569 WriteHandler, void(error_code, std::size_t))
570 async_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 {
576 BOOST_BEAST_HANDLER_INIT(
577 WriteHandler, void(error_code, std::size_t));
578 detail::write_some_win32_op<
579 Protocol,
580 BOOST_ASIO_HANDLER_TYPE(WriteHandler,
581 void(error_code, std::size_t)),
582 isRequest, Fields>{
583 std::move(init.completion_handler), sock, sr}();
584 return init.result.get();
585 }
586
587 #endif
588
589 } // http
590 } // beast
591 } // boost
592
593 #endif
594
595 #endif