aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--configure.ac22
-rw-r--r--src/microhttpd/Makefile.am1
-rw-r--r--src/microhttpd/connection.c266
-rw-r--r--src/microhttpd/connection_https.c2
-rw-r--r--src/microhttpd/connection_https.h14
-rw-r--r--src/microhttpd/internal.h14
-rw-r--r--src/microhttpd/mhd_send.c586
-rw-r--r--src/microhttpd/mhd_send.h100
-rw-r--r--src/microhttpd/mhd_sockets.c4
-rw-r--r--src/microhttpd/response.c6
11 files changed, 794 insertions, 222 deletions
diff --git a/.gitignore b/.gitignore
index ff6afe00..88f8ab32 100644
--- a/.gitignore
+++ b/.gitignore
@@ -14,6 +14,7 @@ config.rpath
14/config.log 14/config.log
15/app.info 15/app.info
16/debug 16/debug
17/build-aux
17/exclude 18/exclude
18/autom4te.cache 19/autom4te.cache
19/scripts 20/scripts
diff --git a/configure.ac b/configure.ac
index 5292798a..1a0870b7 100644
--- a/configure.ac
+++ b/configure.ac
@@ -642,6 +642,28 @@ AM_CONDITIONAL(USE_MS_LIB_TOOL, [test "x$ac_cv_use_ms_lib_tool" = "xyes"])
642MHD_CHECK_SOCKET_SHUTDOWN_TRIGGER([AC_DEFINE([HAVE_LISTEN_SHUTDOWN],[1],[can use shutdown on listen sockets])]) 642MHD_CHECK_SOCKET_SHUTDOWN_TRIGGER([AC_DEFINE([HAVE_LISTEN_SHUTDOWN],[1],[can use shutdown on listen sockets])])
643AM_CONDITIONAL([HAVE_LISTEN_SHUTDOWN], [test "x$mhd_cv_host_shtdwn_trgr_select" = "xyes"]) 643AM_CONDITIONAL([HAVE_LISTEN_SHUTDOWN], [test "x$mhd_cv_host_shtdwn_trgr_select" = "xyes"])
644 644
645# SENDMSG. Should we check for SCM_RIGHTS instead?
646# https://lists.x.org/archives/xorg-devel/2013-November/038687.html
647AC_MSG_CHECKING([whether sendmsg is available])
648AC_SEARCH_LIBS(sendmsg, socket, AC_DEFINE([HAVE_SENDMSG],1,[Define if your platform supports sendmsg]))
649AC_MSG_CHECKING([whether writev is available])
650AC_CHECK_FUNCS([writev])
651
652# check MSG_MORE defined
653AC_MSG_CHECKING([whether MSG_MORE is defined])
654AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
655#include <sys/types.h>
656#include <sys/socket.h>
657]],[[return MSG_MORE;]]
658 )],
659 [
660 AC_MSG_RESULT(yes)
661 AC_DEFINE(HAVE_MSG_MORE, [1], [have MSG_MORE])
662 ],
663 [
664 AC_MSG_RESULT(no)
665 ])
666
645# set GCC options 667# set GCC options
646# use '-fno-strict-aliasing', but only if the compiler 668# use '-fno-strict-aliasing', but only if the compiler
647# and linker can take it 669# and linker can take it
diff --git a/src/microhttpd/Makefile.am b/src/microhttpd/Makefile.am
index 8bc60879..597a2d56 100644
--- a/src/microhttpd/Makefile.am
+++ b/src/microhttpd/Makefile.am
@@ -62,6 +62,7 @@ libmicrohttpd_la_SOURCES = \
62 mhd_limits.h mhd_byteorder.h \ 62 mhd_limits.h mhd_byteorder.h \
63 sysfdsetsize.c sysfdsetsize.h \ 63 sysfdsetsize.c sysfdsetsize.h \
64 mhd_str.c mhd_str.h \ 64 mhd_str.c mhd_str.h \
65 mhd_send.h mhd_send.c \
65 mhd_assert.h \ 66 mhd_assert.h \
66 mhd_sockets.c mhd_sockets.h \ 67 mhd_sockets.c mhd_sockets.h \
67 mhd_itc.c mhd_itc.h mhd_itc_types.h \ 68 mhd_itc.c mhd_itc.h mhd_itc_types.h \
diff --git a/src/microhttpd/connection.c b/src/microhttpd/connection.c
index 6f33dbc1..dab28878 100644
--- a/src/microhttpd/connection.c
+++ b/src/microhttpd/connection.c
@@ -53,7 +53,7 @@
53/* For FreeBSD version identification */ 53/* For FreeBSD version identification */
54#include <sys/param.h> 54#include <sys/param.h>
55#endif /* HAVE_SYS_PARAM_H */ 55#endif /* HAVE_SYS_PARAM_H */
56 56#include "mhd_send.h"
57 57
58/** 58/**
59 * Message to transmit when http 1.1 request is received 59 * Message to transmit when http 1.1 request is received
@@ -278,187 +278,6 @@ send_param_adapter (struct MHD_Connection *connection,
278} 278}
279 279
280 280
281#if defined(_MHD_HAVE_SENDFILE)
282/**
283 * Function for sending responses backed by file FD.
284 *
285 * @param connection the MHD connection structure
286 * @return actual number of bytes sent
287 */
288static ssize_t
289sendfile_adapter (struct MHD_Connection *connection)
290{
291 ssize_t ret;
292 const int file_fd = connection->response->fd;
293 uint64_t left;
294 uint64_t offsetu64;
295#ifndef HAVE_SENDFILE64
296 const uint64_t max_off_t = (uint64_t)OFF_T_MAX;
297#else /* HAVE_SENDFILE64 */
298 const uint64_t max_off_t = (uint64_t)OFF64_T_MAX;
299#endif /* HAVE_SENDFILE64 */
300#ifdef MHD_LINUX_SOLARIS_SENDFILE
301#ifndef HAVE_SENDFILE64
302 off_t offset;
303#else /* HAVE_SENDFILE64 */
304 off64_t offset;
305#endif /* HAVE_SENDFILE64 */
306#endif /* MHD_LINUX_SOLARIS_SENDFILE */
307#ifdef HAVE_FREEBSD_SENDFILE
308 off_t sent_bytes;
309 int flags = 0;
310#endif
311#ifdef HAVE_DARWIN_SENDFILE
312 off_t len;
313#endif /* HAVE_DARWIN_SENDFILE */
314 const bool used_thr_p_c = (0 != (connection->daemon->options & MHD_USE_THREAD_PER_CONNECTION));
315 const size_t chunk_size = used_thr_p_c ? MHD_SENFILE_CHUNK_THR_P_C_ : MHD_SENFILE_CHUNK_;
316 size_t send_size = 0;
317 mhd_assert (MHD_resp_sender_sendfile == connection->resp_sender);
318
319 offsetu64 = connection->response_write_position + connection->response->fd_off;
320 left = connection->response->total_size - connection->response_write_position;
321 /* Do not allow system to stick sending on single fast connection:
322 * use 128KiB chunks (2MiB for thread-per-connection). */
323 send_size = (left > chunk_size) ? chunk_size : (size_t) left;
324 if (max_off_t < offsetu64)
325 { /* Retry to send with standard 'send()'. */
326 connection->resp_sender = MHD_resp_sender_std;
327 return MHD_ERR_AGAIN_;
328 }
329#ifdef MHD_LINUX_SOLARIS_SENDFILE
330#ifndef HAVE_SENDFILE64
331 offset = (off_t) offsetu64;
332 ret = sendfile (connection->socket_fd,
333 file_fd,
334 &offset,
335 send_size);
336#else /* HAVE_SENDFILE64 */
337 offset = (off64_t) offsetu64;
338 ret = sendfile64 (connection->socket_fd,
339 file_fd,
340 &offset,
341 send_size);
342#endif /* HAVE_SENDFILE64 */
343 if (0 > ret)
344 {
345 const int err = MHD_socket_get_error_();
346 if (MHD_SCKT_ERR_IS_EAGAIN_(err))
347 {
348#ifdef EPOLL_SUPPORT
349 /* EAGAIN --- no longer write-ready */
350 connection->epoll_state &= ~MHD_EPOLL_STATE_WRITE_READY;
351#endif /* EPOLL_SUPPORT */
352 return MHD_ERR_AGAIN_;
353 }
354 if (MHD_SCKT_ERR_IS_EINTR_ (err))
355 return MHD_ERR_AGAIN_;
356#ifdef HAVE_LINUX_SENDFILE
357 if (MHD_SCKT_ERR_IS_(err,
358 MHD_SCKT_EBADF_))
359 return MHD_ERR_BADF_;
360 /* sendfile() failed with EINVAL if mmap()-like operations are not
361 supported for FD or other 'unusual' errors occurred, so we should try
362 to fall back to 'SEND'; see also this thread for info on
363 odd libc/Linux behavior with sendfile:
364 http://lists.gnu.org/archive/html/libmicrohttpd/2011-02/msg00015.html */
365 connection->resp_sender = MHD_resp_sender_std;
366 return MHD_ERR_AGAIN_;
367#else /* HAVE_SOLARIS_SENDFILE */
368 if ( (EAFNOSUPPORT == err) ||
369 (EINVAL == err) ||
370 (EOPNOTSUPP == err) )
371 { /* Retry with standard file reader. */
372 connection->resp_sender = MHD_resp_sender_std;
373 return MHD_ERR_AGAIN_;
374 }
375 if ( (ENOTCONN == err) ||
376 (EPIPE == err) )
377 {
378 return MHD_ERR_CONNRESET_;
379 }
380 return MHD_ERR_BADF_; /* Fail hard */
381#endif /* HAVE_SOLARIS_SENDFILE */
382 }
383#ifdef EPOLL_SUPPORT
384 else if (send_size > (size_t)ret)
385 connection->epoll_state &= ~MHD_EPOLL_STATE_WRITE_READY;
386#endif /* EPOLL_SUPPORT */
387#elif defined(HAVE_FREEBSD_SENDFILE)
388#ifdef SF_FLAGS
389 flags = used_thr_p_c ?
390 freebsd_sendfile_flags_thd_p_c_ : freebsd_sendfile_flags_;
391#endif /* SF_FLAGS */
392 if (0 != sendfile (file_fd,
393 connection->socket_fd,
394 (off_t) offsetu64,
395 send_size,
396 NULL,
397 &sent_bytes,
398 flags))
399 {
400 const int err = MHD_socket_get_error_();
401 if (MHD_SCKT_ERR_IS_EAGAIN_(err) ||
402 MHD_SCKT_ERR_IS_EINTR_(err) ||
403 EBUSY == err)
404 {
405 mhd_assert (SSIZE_MAX >= sent_bytes);
406 if (0 != sent_bytes)
407 return (ssize_t)sent_bytes;
408
409 return MHD_ERR_AGAIN_;
410 }
411 /* Some unrecoverable error. Possibly file FD is not suitable
412 * for sendfile(). Retry with standard send(). */
413 connection->resp_sender = MHD_resp_sender_std;
414 return MHD_ERR_AGAIN_;
415 }
416 mhd_assert (0 < sent_bytes);
417 mhd_assert (SSIZE_MAX >= sent_bytes);
418 ret = (ssize_t)sent_bytes;
419#elif defined(HAVE_DARWIN_SENDFILE)
420 len = (off_t)send_size; /* chunk always fit */
421 if (0 != sendfile (file_fd,
422 connection->socket_fd,
423 (off_t) offsetu64,
424 &len,
425 NULL,
426 0))
427 {
428 const int err = MHD_socket_get_error_();
429 if (MHD_SCKT_ERR_IS_EAGAIN_(err) ||
430 MHD_SCKT_ERR_IS_EINTR_(err))
431 {
432 mhd_assert (0 <= len);
433 mhd_assert (SSIZE_MAX >= len);
434 mhd_assert (send_size >= (size_t)len);
435 if (0 != len)
436 return (ssize_t)len;
437
438 return MHD_ERR_AGAIN_;
439 }
440 if (ENOTCONN == err ||
441 EPIPE == err)
442 return MHD_ERR_CONNRESET_;
443 if (ENOTSUP == err ||
444 EOPNOTSUPP == err)
445 { /* This file FD is not suitable for sendfile().
446 * Retry with standard send(). */
447 connection->resp_sender = MHD_resp_sender_std;
448 return MHD_ERR_AGAIN_;
449 }
450 return MHD_ERR_BADF_; /* Return hard error. */
451 }
452 mhd_assert (0 <= len);
453 mhd_assert (SSIZE_MAX >= len);
454 mhd_assert (send_size >= (size_t)len);
455 ret = (ssize_t)len;
456#endif /* HAVE_FREEBSD_SENDFILE */
457 return ret;
458}
459#endif /* _MHD_HAVE_SENDFILE */
460
461
462/** 281/**
463 * Check whether is possible to force push socket buffer content as 282 * Check whether is possible to force push socket buffer content as
464 * partial packet. 283 * partial packet.
@@ -501,6 +320,7 @@ _MHD_static_inline bool
501socket_start_extra_buffering (struct MHD_Connection *connection) 320socket_start_extra_buffering (struct MHD_Connection *connection)
502{ 321{
503 mhd_assert(NULL != connection); 322 mhd_assert(NULL != connection);
323#if OLD_SOCKOPT
504#if defined(TCP_NODELAY) 324#if defined(TCP_NODELAY)
505 if (connection->sk_tcp_nodelay_on) 325 if (connection->sk_tcp_nodelay_on)
506 { 326 {
@@ -517,7 +337,9 @@ socket_start_extra_buffering (struct MHD_Connection *connection)
517 } 337 }
518 } 338 }
519#endif /* TCP_NODELAY */ 339#endif /* TCP_NODELAY */
340#endif /* OLD_SOCKOPT */
520 341
342#if OLD_SOCKOPT
521#if defined(MHD_TCP_CORK_NOPUSH) 343#if defined(MHD_TCP_CORK_NOPUSH)
522 if (!connection->sk_tcp_cork_nopush_on) 344 if (!connection->sk_tcp_cork_nopush_on)
523 { 345 {
@@ -534,12 +356,15 @@ socket_start_extra_buffering (struct MHD_Connection *connection)
534 } 356 }
535 } 357 }
536#endif /* MHD_TCP_CORK_NOPUSH */ 358#endif /* MHD_TCP_CORK_NOPUSH */
359#endif /* OLD_SOCKOPT */
537 360
361#if OLD_SOCKOPT
538#if defined(TCP_NODELAY) 362#if defined(TCP_NODELAY)
539 return connection->sk_tcp_cork_nopush_on && !connection->sk_tcp_nodelay_on; 363 return connection->sk_tcp_cork_nopush_on && !connection->sk_tcp_nodelay_on;
540#else /* ! TCP_NODELAY */ 364#else /* ! TCP_NODELAY */
541 return connection->sk_tcp_cork_nopush_on; 365 return connection->sk_tcp_cork_nopush_on;
542#endif /* ! TCP_NODELAY */ 366#endif /* ! TCP_NODELAY */
367#endif /* OLD_SOCKOPT */
543} 368}
544 369
545 370
@@ -552,6 +377,7 @@ socket_start_extra_buffering (struct MHD_Connection *connection)
552_MHD_static_inline bool 377_MHD_static_inline bool
553socket_start_no_buffering (struct MHD_Connection *connection) 378socket_start_no_buffering (struct MHD_Connection *connection)
554{ 379{
380#if OLD_SOCKOPT
555#if defined(MHD_TCP_CORK_NOPUSH) 381#if defined(MHD_TCP_CORK_NOPUSH)
556 if (connection->sk_tcp_cork_nopush_on) 382 if (connection->sk_tcp_cork_nopush_on)
557 { 383 {
@@ -584,6 +410,7 @@ socket_start_no_buffering (struct MHD_Connection *connection)
584 } 410 }
585#endif /* TCP_NODELAY */ 411#endif /* TCP_NODELAY */
586 return connection->sk_tcp_nodelay_on && !connection->sk_tcp_cork_nopush_on; 412 return connection->sk_tcp_nodelay_on && !connection->sk_tcp_cork_nopush_on;
413#endif /* OLD_SOCKOPT */
587} 414}
588 415
589 416
@@ -601,6 +428,7 @@ socket_start_no_buffering_flush (struct MHD_Connection *connection)
601#if defined(TCP_NOPUSH) && !defined(TCP_CORK) 428#if defined(TCP_NOPUSH) && !defined(TCP_CORK)
602 const int dummy = 0; 429 const int dummy = 0;
603#endif /* !TCP_CORK */ 430#endif /* !TCP_CORK */
431#if OLD_SOCKOPT
604#if defined(TCP_CORK) || (defined(__FreeBSD__) && __FreeBSD__+0 >= 9) 432#if defined(TCP_CORK) || (defined(__FreeBSD__) && __FreeBSD__+0 >= 9)
605 const MHD_SCKT_OPT_BOOL_ off_val = 0; 433 const MHD_SCKT_OPT_BOOL_ off_val = 0;
606 /* Switching off TCP_CORK flush buffer even 434 /* Switching off TCP_CORK flush buffer even
@@ -614,7 +442,7 @@ socket_start_no_buffering_flush (struct MHD_Connection *connection)
614 connection->sk_tcp_cork_nopush_on = false; 442 connection->sk_tcp_cork_nopush_on = false;
615 } 443 }
616#endif /* MHD_TCP_CORK_NOPUSH */ 444#endif /* MHD_TCP_CORK_NOPUSH */
617 445#endif /* OLD_SOCKOPT */
618 res = socket_start_no_buffering (connection); 446 res = socket_start_no_buffering (connection);
619#if defined(__FreeBSD__) && __FreeBSD__+0 >= 9 447#if defined(__FreeBSD__) && __FreeBSD__+0 >= 9
620 /* FreeBSD do not need zero-send for flushing starting from version 9 */ 448 /* FreeBSD do not need zero-send for flushing starting from version 9 */
@@ -640,6 +468,7 @@ _MHD_static_inline bool
640socket_start_normal_buffering (struct MHD_Connection *connection) 468socket_start_normal_buffering (struct MHD_Connection *connection)
641{ 469{
642 mhd_assert(NULL != connection); 470 mhd_assert(NULL != connection);
471#if OLD_SOCKOPT
643#if defined(MHD_TCP_CORK_NOPUSH) 472#if defined(MHD_TCP_CORK_NOPUSH)
644 if (connection->sk_tcp_cork_nopush_on) 473 if (connection->sk_tcp_cork_nopush_on)
645 { 474 {
@@ -672,6 +501,7 @@ socket_start_normal_buffering (struct MHD_Connection *connection)
672 } 501 }
673#endif /* TCP_NODELAY */ 502#endif /* TCP_NODELAY */
674 return !connection->sk_tcp_nodelay_on && !connection->sk_tcp_cork_nopush_on; 503 return !connection->sk_tcp_nodelay_on && !connection->sk_tcp_cork_nopush_on;
504#endif
675} 505}
676 506
677 507
@@ -3315,11 +3145,12 @@ MHD_connection_handle_write (struct MHD_Connection *connection)
3315 case MHD_CONNECTION_HEADERS_PROCESSED: 3145 case MHD_CONNECTION_HEADERS_PROCESSED:
3316 return; 3146 return;
3317 case MHD_CONNECTION_CONTINUE_SENDING: 3147 case MHD_CONNECTION_CONTINUE_SENDING:
3318 ret = connection->send_cls (connection, 3148 ret = MHD_send_on_connection_ (connection,
3319 &HTTP_100_CONTINUE 3149 &HTTP_100_CONTINUE
3320 [connection->continue_message_write_offset], 3150 [connection->continue_message_write_offset],
3321 MHD_STATICSTR_LEN_ (HTTP_100_CONTINUE) - 3151 MHD_STATICSTR_LEN_ (HTTP_100_CONTINUE) -
3322 connection->continue_message_write_offset); 3152 connection->continue_message_write_offset,
3153 MHD_SSO_NO_CORK);
3323 if (ret < 0) 3154 if (ret < 0)
3324 { 3155 {
3325 if (MHD_ERR_AGAIN_ == ret) 3156 if (MHD_ERR_AGAIN_ == ret)
@@ -3349,11 +3180,27 @@ MHD_connection_handle_write (struct MHD_Connection *connection)
3349 mhd_assert (0); 3180 mhd_assert (0);
3350 return; 3181 return;
3351 case MHD_CONNECTION_HEADERS_SENDING: 3182 case MHD_CONNECTION_HEADERS_SENDING:
3352 ret = connection->send_cls (connection, 3183 /* if the response body is not available, we use MHD_send_on_connection_() */
3353 &connection->write_buffer 3184 if (NULL != connection->response->crc)
3354 [connection->write_buffer_send_offset], 3185 {
3355 connection->write_buffer_append_offset - 3186 ret = MHD_send_on_connection_ (connection,
3356 connection->write_buffer_send_offset); 3187 &connection->write_buffer
3188 [connection->write_buffer_send_offset],
3189 connection->write_buffer_append_offset -
3190 connection->write_buffer_send_offset,
3191 MHD_SSO_MAY_CORK);
3192 }
3193 else
3194 {
3195 ret = MHD_send_on_connection2_ (connection,
3196 &connection->write_buffer
3197 [connection->write_buffer_send_offset],
3198 connection->write_buffer_append_offset -
3199 connection->write_buffer_send_offset,
3200 connection->response->data,
3201 connection->response->data_buffer_size);
3202 }
3203
3357 if (ret < 0) 3204 if (ret < 0)
3358 { 3205 {
3359 if (MHD_ERR_AGAIN_ == ret) 3206 if (MHD_ERR_AGAIN_ == ret)
@@ -3401,11 +3248,12 @@ MHD_connection_handle_write (struct MHD_Connection *connection)
3401 - response->data_start; 3248 - response->data_start;
3402 if (data_write_offset > (uint64_t)SIZE_MAX) 3249 if (data_write_offset > (uint64_t)SIZE_MAX)
3403 MHD_PANIC (_("Data offset exceeds limit")); 3250 MHD_PANIC (_("Data offset exceeds limit"));
3404 ret = connection->send_cls (connection, 3251 ret = MHD_send_on_connection_ (connection,
3405 &response->data 3252 &response->data
3406 [(size_t)data_write_offset], 3253 [(size_t)data_write_offset],
3407 response->data_size - 3254 response->data_size -
3408 (size_t)data_write_offset); 3255 (size_t)data_write_offset,
3256 MHD_SSO_NO_CORK);
3409#if DEBUG_SEND_DATA 3257#if DEBUG_SEND_DATA
3410 if (ret > 0) 3258 if (ret > 0)
3411 fprintf (stderr, 3259 fprintf (stderr,
@@ -3444,11 +3292,12 @@ MHD_connection_handle_write (struct MHD_Connection *connection)
3444 mhd_assert (0); 3292 mhd_assert (0);
3445 return; 3293 return;
3446 case MHD_CONNECTION_CHUNKED_BODY_READY: 3294 case MHD_CONNECTION_CHUNKED_BODY_READY:
3447 ret = connection->send_cls (connection, 3295 ret = MHD_send_on_connection_ (connection,
3448 &connection->write_buffer 3296 &connection->write_buffer
3449 [connection->write_buffer_send_offset], 3297 [connection->write_buffer_send_offset],
3450 connection->write_buffer_append_offset - 3298 connection->write_buffer_append_offset -
3451 connection->write_buffer_send_offset); 3299 connection->write_buffer_send_offset,
3300 MHD_SSO_NO_CORK);
3452 if (ret < 0) 3301 if (ret < 0)
3453 { 3302 {
3454 if (MHD_ERR_AGAIN_ == ret) 3303 if (MHD_ERR_AGAIN_ == ret)
@@ -3472,11 +3321,12 @@ MHD_connection_handle_write (struct MHD_Connection *connection)
3472 mhd_assert (0); 3321 mhd_assert (0);
3473 return; 3322 return;
3474 case MHD_CONNECTION_FOOTERS_SENDING: 3323 case MHD_CONNECTION_FOOTERS_SENDING:
3475 ret = connection->send_cls (connection, 3324 ret = MHD_send_on_connection_ (connection,
3476 &connection->write_buffer 3325 &connection->write_buffer
3477 [connection->write_buffer_send_offset], 3326 [connection->write_buffer_send_offset],
3478 connection->write_buffer_append_offset - 3327 connection->write_buffer_append_offset -
3479 connection->write_buffer_send_offset); 3328 connection->write_buffer_send_offset,
3329 MHD_SSO_HDR_CORK);
3480 if (ret < 0) 3330 if (ret < 0)
3481 { 3331 {
3482 if (MHD_ERR_AGAIN_ == ret) 3332 if (MHD_ERR_AGAIN_ == ret)
diff --git a/src/microhttpd/connection_https.c b/src/microhttpd/connection_https.c
index 5efced33..8202329b 100644
--- a/src/microhttpd/connection_https.c
+++ b/src/microhttpd/connection_https.c
@@ -98,7 +98,7 @@ recv_tls_adapter (struct MHD_Connection *connection,
98 * @return positive value for number of bytes actually sent or 98 * @return positive value for number of bytes actually sent or
99 * negative value for error number MHD_ERR_xxx_ 99 * negative value for error number MHD_ERR_xxx_
100 */ 100 */
101static ssize_t 101ssize_t
102send_tls_adapter (struct MHD_Connection *connection, 102send_tls_adapter (struct MHD_Connection *connection,
103 const void *other, 103 const void *other,
104 size_t i) 104 size_t i)
diff --git a/src/microhttpd/connection_https.h b/src/microhttpd/connection_https.h
index 1c12ea9f..e91a84d3 100644
--- a/src/microhttpd/connection_https.h
+++ b/src/microhttpd/connection_https.h
@@ -60,6 +60,20 @@ MHD_run_tls_handshake_ (struct MHD_Connection *connection);
60 */ 60 */
61bool 61bool
62MHD_tls_connection_shutdown (struct MHD_Connection *connection); 62MHD_tls_connection_shutdown (struct MHD_Connection *connection);
63
64/**
65 * Callback for writing data to the socket.
66 *
67 * @param connection the MHD connection structure
68 * @param other data to write
69 * @param i number of bytes to write
70 * @return positive value for number of bytes actually sent or
71 * negative value for error number MHD_ERR_xxx_
72 */
73ssize_t
74send_tls_adapter (struct MHD_Connection *connection,
75 const void *other,
76 size_t i);
63#endif /* HTTPS_SUPPORT */ 77#endif /* HTTPS_SUPPORT */
64 78
65#endif 79#endif
diff --git a/src/microhttpd/internal.h b/src/microhttpd/internal.h
index 1f5aeaf3..ac43d819 100644
--- a/src/microhttpd/internal.h
+++ b/src/microhttpd/internal.h
@@ -871,19 +871,13 @@ struct MHD_Connection
871 /** 871 /**
872 * true if #socket_fd is non-blocking, false otherwise. 872 * true if #socket_fd is non-blocking, false otherwise.
873 */ 873 */
874 bool sk_nonblck; 874 bool sk_nonblck; // FIXME: hopefully dead?
875 875
876 /** 876 /**
877 * Indicate whether connection socket has TCP_NODELAY turned on / Nagle’s algorithm turned off. 877 * Indicate whether connection socket has TCP_CORK / Nagle’s algorithm turned on/off
878 * TCP_NODELAY should not be turned on when TCP_CORK/TCP_NOPUSH is turned off. 878 * on this socket.
879 */ 879 */
880 bool sk_tcp_nodelay_on; 880 bool sk_cork_on;
881
882 /**
883 * Indicate whether connection socket has TCP_CORK/TCP_NOPUSH turned on.
884 * TCP_CORK/TCP_NOPUSH should not be turned on when TCP_NODELAY is turned off.
885 */
886 bool sk_tcp_cork_nopush_on;
887 881
888 /** 882 /**
889 * Has this socket been closed for reading (i.e. other side closed 883 * Has this socket been closed for reading (i.e. other side closed
diff --git a/src/microhttpd/mhd_send.c b/src/microhttpd/mhd_send.c
new file mode 100644
index 00000000..a41586d9
--- /dev/null
+++ b/src/microhttpd/mhd_send.c
@@ -0,0 +1,586 @@
1/*
2 This file is part of libmicrohttpd
3 Copyright (C) 2019 ng0 <ng0@n0.is>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
19 */
20
21/**
22 * @file microhttpd/mhd_send.c
23 * @brief Implementation of send() wrappers.
24 * @author ng0 (N. Gillmann)
25 * @author Christian Grothoff
26 * @author Evgeny Grin
27 */
28
29/* Worth considering for future improvements and additions:
30 * NetBSD has no sendfile or sendfile64. The way to work
31 * with this seems to be to mmap the file and write(2) as
32 * large a chunk as possible to the socket. Alternatively,
33 * use madvise(..., MADV_SEQUENTIAL). */
34
35/* Functions to be used in: send_param_adapter, MHD_send_
36 * and every place where sendfile(), sendfile64(), setsockopt()
37 * are used. */
38
39#include "mhd_send.h"
40
41/**
42 * Handle setsockopt calls.
43 *
44 * @param connection the MHD_Connection structure
45 * @param want_cork cork state, boolean
46 */
47static void
48pre_cork_setsockopt (struct MHD_Connection *connection,
49 bool want_cork)
50{
51#if HAVE_MSG_MORE
52#else
53 int ret;
54 const MHD_SCKT_OPT_BOOL_ off_val = 0;
55 const MHD_SCKT_OPT_BOOL_ on_val = 1;
56
57 /* If sk_cork_on is already what we pass in, return. */
58 if (connection->sk_cork_on == want_cork)
59 {
60 /* nothing to do, success! */
61 return;
62 }
63
64 ret = -1;
65#if TCP_CORK
66 if (want_cork)
67 ret = setsockopt (connection->socket_fd,
68 IPPROTO_TCP,
69 TCP_CORK,
70 (const void *) &on_val,
71 sizeof (on_val));
72#elif TCP_NODELAY
73 ret = setsockopt (connection->socket_fd,
74 IPPROTO_TCP,
75 TCP_NODELAY,
76 (const void *) want_cork ? &off_val : &on_val,
77 sizeof (on_val));
78#elif TCP_NOPUSH
79 ret = setsockopt (connection->socket_fd,
80 IPPROTO_TCP,
81 TCP_NOPUSH,
82 (const void *) &on_val,
83 sizeof (on_val));
84#endif
85
86 if (0 == ret)
87 {
88 connection->sk_cork_on = want_cork;
89 }
90 return;
91#endif /* MSG_MORE */
92}
93
94/**
95 * Handle setsockopt calls.
96 *
97 * @param connection the MHD_Connection structure
98 * @param want_cork cork state, boolean
99 */
100static void
101post_cork_setsockopt (struct MHD_Connection *connection,
102 bool want_cork)
103{
104#if HAVE_MSG_MORE
105#else
106 int ret;
107 const MHD_SCKT_OPT_BOOL_ off_val = 0;
108 const MHD_SCKT_OPT_BOOL_ on_val = 1;
109
110 /* If sk_cork_on is already what we pass in, return. */
111 if (connection->sk_cork_on == want_cork)
112 {
113 /* nothing to do, success! */
114 return;
115 }
116 ret = -1;
117#if TCP_CORK
118 if (! want_cork)
119 ret = setsockopt (connection->socket_fd,
120 IPPROTO_TCP,
121 TCP_CORK,
122 &off_val,
123 sizeof (off_val));
124#elif TCP_NODELAY
125 /* nothing to do */
126#elif TCP_NOPUSH
127 ret = setsockopt (connection->socket_fd,
128 IPPROTO_TCP,
129 TCP_NOPUSH,
130 (const void *) &off_val,
131 sizeof (off_val));
132#endif
133 if (0 == ret)
134 {
135 connection->sk_cork_on = want_cork;
136 }
137 return;
138#endif /* MSG_MORE */
139}
140
141/**
142 * Send buffer on connection, and remember the current state of
143 * the socket options; only call setsockopt when absolutely
144 * necessary.
145 *
146 * @param connection the MHD_Connection structure
147 * @param buffer content of the buffer to send
148 * @param buffer_size the size of the buffer (in bytes)
149 * @param options the #MHD_SendSocketOptions enum,
150 * #MHD_SSO_NO_CORK: definitely no corking (use NODELAY, or explicitly disable cork),
151 * #MHD_SSO_MAY_CORK: should enable corking (use MSG_MORE, or explicitly enable cork),
152 * #MHD_SSO_HDR_CORK: consider tcpi_snd_mss and consider not corking for the header
153 * part if the size of the header is close to the MSS.
154 * Only used if we are NOT doing 100 Continue and are still sending the
155 * header (provided in full as the buffer to #MHD_send_on_connection_ or as
156 * the header to #MHD_send_on_connection2_).
157 * @return sum of the number of bytes sent from both buffers or
158 * -1 on error
159 */
160ssize_t
161MHD_send_on_connection_ (struct MHD_Connection *connection,
162 const char *buffer,
163 size_t buffer_size,
164 enum MHD_SendSocketOptions options)
165{
166 bool want_cork;
167 bool using_tls = false;
168 MHD_socket s = connection->socket_fd;
169 ssize_t ret;
170 const MHD_SCKT_OPT_BOOL_ off_val = 0;
171 const MHD_SCKT_OPT_BOOL_ on_val = 1;
172
173 /* error handling from send_param_adapter() */
174 if ((MHD_INVALID_SOCKET == s) || (MHD_CONNECTION_CLOSED == connection->state))
175 {
176 return MHD_ERR_NOTCONN_;
177 }
178
179 /* from send_param_adapter() */
180 if (buffer_size > MHD_SCKT_SEND_MAX_SIZE_)
181 buffer_size = MHD_SCKT_SEND_MAX_SIZE_; /* return value limit */
182
183 /* Get socket options, change/set options if necessary. */
184 switch (options)
185 {
186 /* No corking */
187 case MHD_SSO_NO_CORK:
188 want_cork = false;
189 break;
190 /* Do corking, consider MSG_MORE instead if available. */
191 case MHD_SSO_MAY_CORK:
192 want_cork = true;
193 break;
194 /* Cork the header. */
195 case MHD_SSO_HDR_CORK:
196 want_cork = (buffer_size <= 1024);
197 break;
198 }
199
200 /* ! could be avoided by redefining the variable. */
201 // bool have_cork = ! connection->sk_tcp_nodelay_on;
202 bool have_cork = ! connection->sk_cork_on;
203
204#ifdef HTTPS_SUPPORT
205 using_tls = (0 != (connection->daemon->options & MHD_USE_TLS));
206#endif
207
208#ifdef HTTPS_SUPPORT
209 if (using_tls)
210 {
211 if (want_cork && ! have_cork)
212 {
213 gnutls_record_cork (connection->tls_session);
214 connection->sk_cork_on = false;
215 }
216 if (buffer_size > SSIZE_MAX)
217 buffer_size = SSIZE_MAX;
218 ret = gnutls_record_send (connection->tls_session,
219 buffer,
220 buffer_size);
221 if ( (GNUTLS_E_AGAIN == ret) ||
222 (GNUTLS_E_INTERRUPTED == ret) )
223 {
224#ifdef EPOLL_SUPPORT
225 if (GNUTLS_E_AGAIN == ret)
226 connection->epoll_state &= ~MHD_EPOLL_STATE_WRITE_READY;
227#endif
228 return MHD_ERR_AGAIN_;
229 }
230 if (ret < 0)
231 {
232 /* Likely 'GNUTLS_E_INVALID_SESSION' (client communication
233 disrupted); interpret as a hard error */
234 return MHD_ERR_NOTCONN_;
235 }
236#ifdef EPOLL_SUPPORT
237 /* Unlike non-TLS connections, do not reset "write-ready" if
238 * sent amount smaller than provided amount, as TLS
239 * connections may break data into smaller parts for sending. */
240#endif /* EPOLL_SUPPORT */
241
242 if (! want_cork && have_cork)
243 {
244 (void) gnutls_record_uncork (connection->tls_session, 0);
245 connection->sk_cork_on = true;
246 }
247 }
248 else
249#endif /* HTTPS_SUPPORT */
250 {
251 /* plaintext transmission */
252 pre_cork_setsockopt (connection, want_cork);
253#if HAVE_MSG_MORE
254 ret = send (s,
255 buffer,
256 buffer_size,
257 MAYBE_MSG_NOSIGNAL | (want_cork ? MSG_MORE : 0));
258#else
259 ret = send (connection->socket_fd,
260 buffer,
261 buffer_size,
262 MAYBE_MSG_NOSIGNAL);
263#endif
264
265 if (0 > ret)
266 {
267 const int err = MHD_socket_get_error_ ();
268
269 if (MHD_SCKT_ERR_IS_EAGAIN_ (err))
270 {
271#if EPOLL_SUPPORT
272 /* EAGAIN, no longer write-ready */
273 connection->epoll_state &= ~MHD_EPOLL_STATE_WRITE_READY;
274#endif /* EPOLL_SUPPORT */
275 return MHD_ERR_AGAIN_;
276 }
277 if (MHD_SCKT_ERR_IS_EINTR_ (err))
278 return MHD_ERR_AGAIN_;
279 if (MHD_SCKT_ERR_IS_ (err, MHD_SCKT_ECONNRESET_))
280 return MHD_ERR_CONNRESET_;
281 /* Treat any other error as hard error. */
282 return MHD_ERR_NOTCONN_;
283 }
284#if EPOLL_SUPPORT
285 else if (buffer_size > (size_t) ret)
286 connection->epoll_state &= ~MHD_EPOLL_STATE_WRITE_READY;
287#endif /* EPOLL_SUPPORT */
288
289 post_cork_setsockopt (connection, want_cork);
290 }
291
292 return ret;
293}
294
295
296/**
297 * Send header followed by buffer on connection.
298 * Uses writev if possible to send both at once
299 * and returns the sum of the number of bytes sent from
300 * both buffers, or -1 on error;
301 * if writev is unavailable, this call MUST only send from 'header'
302 * (as we cannot handle the case that the first write
303 * succeeds and the 2nd fails!).
304 *
305 * @param connection the MHD_Connection structure
306 * @param header content of header to send
307 * @param header_size the size of the header (in bytes)
308 * @param buffer content of the buffer to send
309 * @param buffer_size the size of the buffer (in bytes)
310 * @return sum of the number of bytes sent from both buffers or
311 * -1 on error
312 */
313ssize_t
314MHD_send_on_connection2_ (struct MHD_Connection *connection,
315 const char *header,
316 size_t header_size,
317 const char *buffer,
318 size_t buffer_size)
319{
320#if defined(HAVE_SENDMSG) || defined(HAVE_WRITEV)
321 MHD_socket s = connection->socket_fd;
322 bool want_cork;
323 int iovcnt;
324 int eno;
325 ssize_t ret;
326 const MHD_SCKT_OPT_BOOL_ off_val = 0;
327 struct iovec vector[2];
328
329 want_cork = ! connection->sk_cork_on;
330
331 pre_cork_setsockopt (connection, want_cork);
332
333 vector[0].iov_base = (void *) header;
334 vector[0].iov_len = strlen (header);
335 vector[1].iov_base = (void *) buffer;
336 vector[1].iov_len = strlen (buffer);
337
338#if HAVE_SENDMSG
339 struct msghdr msg;
340 memset(&msg, 0, sizeof(struct msghdr));
341
342 msg.msg_iov = vector;
343 msg.msg_iovlen = 2;
344
345 /*
346 * questionable for this case, bus maybe worth considering for now:
347 * On at least NetBSD (and FreeBSD?) we need to set both msg_control and
348 * mgs_controllen to 0.
349 * If you set msg_control to nonnull, NetBSD expects you to have
350 * msg_controllen > 0. (sys/kern/uipc_syscalls.c in do_sys_sendmsg_so)
351 * for reference. Thanks to pDNS (for FreeBSD), Riastradh for NetBSD.
352 */
353 /*
354 msg.msg_control = 0;
355 msg.msg_controllen = 0;
356 */
357 ret = sendmsg (s, &msg, MAYBE_MSG_NOSIGNAL);
358#elif HAVE_WRITEV
359 iovcnt = sizeof (vector) / sizeof (struct iovec);
360 ret = writev (s, vector, iovcnt);
361#endif
362
363 if (ret == header_size + buffer_size)
364 want_cork = false;
365
366 post_cork_setsockopt (connection, want_cork);
367
368 return ret;
369
370#else
371 return MHD_send_on_connection_ (connection,
372 header,
373 header_size,
374 MHD_SSO_HDR_CORK);
375#endif
376}
377
378/**
379 * sendfile() chuck size
380 */
381#define MHD_SENFILE_CHUNK_ (0x20000)
382
383/**
384 * sendfile() chuck size for thread-per-connection
385 */
386#define MHD_SENFILE_CHUNK_THR_P_C_ (0x200000)
387
388#ifdef HAVE_FREEBSD_SENDFILE
389#ifdef SF_FLAGS
390/**
391 * FreeBSD sendfile() flags
392 */
393static int freebsd_sendfile_flags_;
394
395/**
396 * FreeBSD sendfile() flags for thread-per-connection
397 */
398static int freebsd_sendfile_flags_thd_p_c_;
399#endif /* SF_FLAGS */
400
401#endif /* HAVE_FREEBSD_SENDFILE */
402
403#if defined(_MHD_HAVE_SENDFILE)
404/**
405 * Function for sending responses backed by file FD.
406 *
407 * @param connection the MHD connection structure
408 * @return actual number of bytes sent
409 */
410ssize_t
411sendfile_adapter (struct MHD_Connection *connection)
412{
413 ssize_t ret;
414 const int file_fd = connection->response->fd;
415 uint64_t left;
416 uint64_t offsetu64;
417#ifndef HAVE_SENDFILE64
418 const uint64_t max_off_t = (uint64_t)OFF_T_MAX;
419#else /* HAVE_SENDFILE64 */
420 const uint64_t max_off_t = (uint64_t)OFF64_T_MAX;
421#endif /* HAVE_SENDFILE64 */
422#ifdef MHD_LINUX_SOLARIS_SENDFILE
423#ifndef HAVE_SENDFILE64
424 off_t offset;
425#else /* HAVE_SENDFILE64 */
426 off64_t offset;
427#endif /* HAVE_SENDFILE64 */
428#endif /* MHD_LINUX_SOLARIS_SENDFILE */
429#ifdef HAVE_FREEBSD_SENDFILE
430 off_t sent_bytes;
431 int flags = 0;
432#endif
433#ifdef HAVE_DARWIN_SENDFILE
434 off_t len;
435#endif /* HAVE_DARWIN_SENDFILE */
436 const bool used_thr_p_c = (0 != (connection->daemon->options & MHD_USE_THREAD_PER_CONNECTION));
437 const size_t chunk_size = used_thr_p_c ? MHD_SENFILE_CHUNK_THR_P_C_ : MHD_SENFILE_CHUNK_;
438 size_t send_size = 0;
439 mhd_assert (MHD_resp_sender_sendfile == connection->resp_sender);
440
441 pre_cork_setsockopt (connection, false);
442
443 offsetu64 = connection->response_write_position + connection->response->fd_off;
444 left = connection->response->total_size - connection->response_write_position;
445 /* Do not allow system to stick sending on single fast connection:
446 * use 128KiB chunks (2MiB for thread-per-connection). */
447 send_size = (left > chunk_size) ? chunk_size : (size_t) left;
448 if (max_off_t < offsetu64)
449 { /* Retry to send with standard 'send()'. */
450 connection->resp_sender = MHD_resp_sender_std;
451 return MHD_ERR_AGAIN_;
452 }
453#ifdef MHD_LINUX_SOLARIS_SENDFILE
454#ifndef HAVE_SENDFILE64
455 offset = (off_t) offsetu64;
456 ret = sendfile (connection->socket_fd,
457 file_fd,
458 &offset,
459 send_size);
460#else /* HAVE_SENDFILE64 */
461 offset = (off64_t) offsetu64;
462 ret = sendfile64 (connection->socket_fd,
463 file_fd,
464 &offset,
465 send_size);
466#endif /* HAVE_SENDFILE64 */
467 if (0 > ret)
468 {
469 const int err = MHD_socket_get_error_();
470 if (MHD_SCKT_ERR_IS_EAGAIN_(err))
471 {
472#ifdef EPOLL_SUPPORT
473 /* EAGAIN --- no longer write-ready */
474 connection->epoll_state &= ~MHD_EPOLL_STATE_WRITE_READY;
475#endif /* EPOLL_SUPPORT */
476 return MHD_ERR_AGAIN_;
477 }
478 if (MHD_SCKT_ERR_IS_EINTR_ (err))
479 return MHD_ERR_AGAIN_;
480#ifdef HAVE_LINUX_SENDFILE
481 if (MHD_SCKT_ERR_IS_(err,
482 MHD_SCKT_EBADF_))
483 return MHD_ERR_BADF_;
484 /* sendfile() failed with EINVAL if mmap()-like operations are not
485 supported for FD or other 'unusual' errors occurred, so we should try
486 to fall back to 'SEND'; see also this thread for info on
487 odd libc/Linux behavior with sendfile:
488 http://lists.gnu.org/archive/html/libmicrohttpd/2011-02/msg00015.html */
489 connection->resp_sender = MHD_resp_sender_std;
490 return MHD_ERR_AGAIN_;
491#else /* HAVE_SOLARIS_SENDFILE */
492 if ( (EAFNOSUPPORT == err) ||
493 (EINVAL == err) ||
494 (EOPNOTSUPP == err) )
495 { /* Retry with standard file reader. */
496 connection->resp_sender = MHD_resp_sender_std;
497 return MHD_ERR_AGAIN_;
498 }
499 if ( (ENOTCONN == err) ||
500 (EPIPE == err) )
501 {
502 return MHD_ERR_CONNRESET_;
503 }
504 return MHD_ERR_BADF_; /* Fail hard */
505#endif /* HAVE_SOLARIS_SENDFILE */
506 }
507#ifdef EPOLL_SUPPORT
508 else if (send_size > (size_t)ret)
509 connection->epoll_state &= ~MHD_EPOLL_STATE_WRITE_READY;
510#endif /* EPOLL_SUPPORT */
511#elif defined(HAVE_FREEBSD_SENDFILE)
512#ifdef SF_FLAGS
513 flags = used_thr_p_c ?
514 freebsd_sendfile_flags_thd_p_c_ : freebsd_sendfile_flags_;
515#endif /* SF_FLAGS */
516 if (0 != sendfile (file_fd,
517 connection->socket_fd,
518 (off_t) offsetu64,
519 send_size,
520 NULL,
521 &sent_bytes,
522 flags))
523 {
524 const int err = MHD_socket_get_error_();
525 if (MHD_SCKT_ERR_IS_EAGAIN_(err) ||
526 MHD_SCKT_ERR_IS_EINTR_(err) ||
527 EBUSY == err)
528 {
529 mhd_assert (SSIZE_MAX >= sent_bytes);
530 if (0 != sent_bytes)
531 return (ssize_t)sent_bytes;
532
533 return MHD_ERR_AGAIN_;
534 }
535 /* Some unrecoverable error. Possibly file FD is not suitable
536 * for sendfile(). Retry with standard send(). */
537 connection->resp_sender = MHD_resp_sender_std;
538 return MHD_ERR_AGAIN_;
539 }
540 mhd_assert (0 < sent_bytes);
541 mhd_assert (SSIZE_MAX >= sent_bytes);
542 ret = (ssize_t)sent_bytes;
543#elif defined(HAVE_DARWIN_SENDFILE)
544 len = (off_t)send_size; /* chunk always fit */
545 if (0 != sendfile (file_fd,
546 connection->socket_fd,
547 (off_t) offsetu64,
548 &len,
549 NULL,
550 0))
551 {
552 const int err = MHD_socket_get_error_();
553 if (MHD_SCKT_ERR_IS_EAGAIN_(err) ||
554 MHD_SCKT_ERR_IS_EINTR_(err))
555 {
556 mhd_assert (0 <= len);
557 mhd_assert (SSIZE_MAX >= len);
558 mhd_assert (send_size >= (size_t)len);
559 if (0 != len)
560 return (ssize_t)len;
561
562 return MHD_ERR_AGAIN_;
563 }
564 if (ENOTCONN == err ||
565 EPIPE == err)
566 return MHD_ERR_CONNRESET_;
567 if (ENOTSUP == err ||
568 EOPNOTSUPP == err)
569 { /* This file FD is not suitable for sendfile().
570 * Retry with standard send(). */
571 connection->resp_sender = MHD_resp_sender_std;
572 return MHD_ERR_AGAIN_;
573 }
574 return MHD_ERR_BADF_; /* Return hard error. */
575 }
576 mhd_assert (0 <= len);
577 mhd_assert (SSIZE_MAX >= len);
578 mhd_assert (send_size >= (size_t)len);
579 ret = (ssize_t)len;
580#endif /* HAVE_FREEBSD_SENDFILE */
581
582 post_cork_setsockopt (connection, false);
583
584 return ret;
585}
586#endif /* _MHD_HAVE_SENDFILE */
diff --git a/src/microhttpd/mhd_send.h b/src/microhttpd/mhd_send.h
new file mode 100644
index 00000000..5f0f8155
--- /dev/null
+++ b/src/microhttpd/mhd_send.h
@@ -0,0 +1,100 @@
1/*
2 This file is part of libmicrohttpd
3 Copyright (C) 2019 ng0
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
19*/
20
21/**
22 * @file mhd_send.h
23 * @brief Implementation of send() wrappers.
24 * @author ng0
25 */
26
27#ifndef MHD_SEND_H
28#define MHD_SEND_H
29
30#include "platform.h"
31#include "internal.h"
32#if defined(HAVE_STDBOOL_H)
33#include <stdbool.h>
34#endif /* HAVE_STDBOOL_H */
35#include <errno.h>
36#include "mhd_sockets.h"
37#include "connection.h"
38#include "connection_https.h"
39
40#ifdef MHD_LINUX_SOLARIS_SENDFILE
41#include <sys/sendfile.h>
42#endif /* MHD_LINUX_SOLARIS_SENDFILE */
43#if defined(HAVE_FREEBSD_SENDFILE) || defined(HAVE_DARWIN_SENDFILE)
44#include <sys/types.h>
45#include <sys/socket.h>
46#include <sys/uio.h>
47#endif /* HAVE_FREEBSD_SENDFILE || HAVE_DARWIN_SENDFILE */
48
49#ifdef HAVE_SYS_PARAM_H
50/* For FreeBSD version identification */
51#include <sys/param.h>
52#endif /* HAVE_SYS_PARAM_H */
53
54/**
55 * The enumeration of send socket options.
56 */
57enum MHD_SendSocketOptions
58{
59 /**
60 * definitely no corking (use NODELAY, or explicitly disable cork)
61 */
62 MHD_SSO_NO_CORK = 0,
63 /**
64 * should enable corking (use MSG_MORE, or explicitly enable cork)
65 */
66 MHD_SSO_MAY_CORK = 1,
67 /**
68 * consider tcpi_snd_mss and consider not corking for the header
69 * part if the size of the header is close to the MSS.
70 * Only used if we are NOT doing 100 Continue and are still
71 * sending the header (provided in full as the buffer to
72 * MHD_send_on_connection_ or as the header to
73 * MHD_send_on_connection2_).
74 */
75 MHD_SSO_HDR_CORK = 2
76};
77
78
79ssize_t
80MHD_send_on_connection_ (struct MHD_Connection *connection,
81 const char *buffer,
82 size_t buffer_size,
83 enum MHD_SendSocketOptions options);
84
85ssize_t
86MHD_send_on_connection2_ (struct MHD_Connection *connection,
87 const char *header,
88 size_t header_size,
89 const char *buffer,
90 size_t buffer_size);
91
92ssize_t
93MHD_sendfile_on_connection_ (struct MHD_Connection *connection);
94
95#if defined(_MHD_HAVE_SENDFILE)
96ssize_t
97sendfile_adapter (struct MHD_Connection *connection);
98#endif
99
100#endif /* MHD_SEND_H */
diff --git a/src/microhttpd/mhd_sockets.c b/src/microhttpd/mhd_sockets.c
index 04405945..0bfe2517 100644
--- a/src/microhttpd/mhd_sockets.c
+++ b/src/microhttpd/mhd_sockets.c
@@ -474,20 +474,24 @@ MHD_socket_buffering_reset_ (MHD_socket sock)
474#if defined(TCP_NODELAY) || defined(MHD_TCP_CORK_NOPUSH) 474#if defined(TCP_NODELAY) || defined(MHD_TCP_CORK_NOPUSH)
475 const MHD_SCKT_OPT_BOOL_ off_val = 0; 475 const MHD_SCKT_OPT_BOOL_ off_val = 0;
476#if defined(MHD_TCP_CORK_NOPUSH) 476#if defined(MHD_TCP_CORK_NOPUSH)
477 //#if OLD_SOCKOPT
477 /* Disable extra buffering */ 478 /* Disable extra buffering */
478 res = (0 == setsockopt (sock, 479 res = (0 == setsockopt (sock,
479 IPPROTO_TCP, 480 IPPROTO_TCP,
480 MHD_TCP_CORK_NOPUSH, 481 MHD_TCP_CORK_NOPUSH,
481 (const void *) &off_val, 482 (const void *) &off_val,
482 sizeof (off_val))) && res; 483 sizeof (off_val))) && res;
484 //#endif
483#endif /* MHD_TCP_CORK_NOPUSH */ 485#endif /* MHD_TCP_CORK_NOPUSH */
484#if defined(TCP_NODELAY) 486#if defined(TCP_NODELAY)
487 //#if OLD_SOCKOPT
485 /* Enable Nagle's algorithm for normal buffering */ 488 /* Enable Nagle's algorithm for normal buffering */
486 res = (0 == setsockopt (sock, 489 res = (0 == setsockopt (sock,
487 IPPROTO_TCP, 490 IPPROTO_TCP,
488 TCP_NODELAY, 491 TCP_NODELAY,
489 (const void *) &off_val, 492 (const void *) &off_val,
490 sizeof (off_val))) && res; 493 sizeof (off_val))) && res;
494 //#endif
491#endif /* TCP_NODELAY */ 495#endif /* TCP_NODELAY */
492#else /* !TCP_NODELAY && !MHD_TCP_CORK_NOPUSH */ 496#else /* !TCP_NODELAY && !MHD_TCP_CORK_NOPUSH */
493 (void) sock; 497 (void) sock;
diff --git a/src/microhttpd/response.c b/src/microhttpd/response.c
index 3e9fb053..7b98a45c 100644
--- a/src/microhttpd/response.c
+++ b/src/microhttpd/response.c
@@ -604,9 +604,9 @@ MHD_create_response_from_fd_at_offset64 (uint64_t size,
604 604
605 response = MHD_create_response_from_callback (size, 605 response = MHD_create_response_from_callback (size,
606 MHD_FILE_READ_BLOCK_SIZE, 606 MHD_FILE_READ_BLOCK_SIZE,
607 &file_reader, 607 &file_reader,
608 NULL, 608 NULL,
609 &free_callback); 609 &free_callback);
610 if (NULL == response) 610 if (NULL == response)
611 return NULL; 611 return NULL;
612 response->fd = fd; 612 response->fd = fd;