diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/include/microhttpd.h | 25 | ||||
-rw-r--r-- | src/microhttpd/daemon.c | 64 | ||||
-rw-r--r-- | src/microhttpd/internal.h | 7 | ||||
-rw-r--r-- | src/microhttpd/response.c | 70 | ||||
-rw-r--r-- | src/microhttpd/test_upgrade_ssl.c | 4 |
5 files changed, 79 insertions, 91 deletions
diff --git a/src/include/microhttpd.h b/src/include/microhttpd.h index afb97571..49af7fde 100644 --- a/src/include/microhttpd.h +++ b/src/include/microhttpd.h | |||
@@ -2250,30 +2250,7 @@ enum MHD_UpgradeAction | |||
2250 | * | 2250 | * |
2251 | * Takes no extra arguments. | 2251 | * Takes no extra arguments. |
2252 | */ | 2252 | */ |
2253 | MHD_UPGRADE_ACTION_CLOSE = 0, | 2253 | MHD_UPGRADE_ACTION_CLOSE = 0 |
2254 | |||
2255 | /** | ||
2256 | * Uncork the TCP write buffer (that is, tell the OS to transmit all | ||
2257 | * bytes in the buffer now, and to not use TCP-CORKing). | ||
2258 | * | ||
2259 | * Takes no extra arguments. | ||
2260 | * | ||
2261 | * NOTE: it is unclear if we want to have this in the | ||
2262 | * "final" API, this is just an idea right now. | ||
2263 | */ | ||
2264 | MHD_UPGRADE_ACTION_CORK, | ||
2265 | |||
2266 | /** | ||
2267 | * Try to "flush" our write buffer (to the network), returning | ||
2268 | * #MHD_YES on success (buffer is empty) and #MHD_NO on failure | ||
2269 | * (unsent bytes remain in buffers). This option is useful if | ||
2270 | * the application wants to make sure that all data has been sent, | ||
2271 | * which may be a good idea before closing the socket. | ||
2272 | * | ||
2273 | * NOTE: it is unclear if we want to have this in the | ||
2274 | * "final" API, this is just an idea right now. | ||
2275 | */ | ||
2276 | MHD_UPGRADE_ACTION_FLUSH | ||
2277 | 2254 | ||
2278 | }; | 2255 | }; |
2279 | 2256 | ||
diff --git a/src/microhttpd/daemon.c b/src/microhttpd/daemon.c index 62cd3ce8..08709c80 100644 --- a/src/microhttpd/daemon.c +++ b/src/microhttpd/daemon.c | |||
@@ -883,6 +883,61 @@ call_handlers (struct MHD_Connection *con, | |||
883 | 883 | ||
884 | #if HTTPS_SUPPORT | 884 | #if HTTPS_SUPPORT |
885 | /** | 885 | /** |
886 | * This function finishes the process of closing the | ||
887 | * connection associated with the @a urh. It should | ||
888 | * be called if the `was_closed` flag is set and the | ||
889 | * buffer has been drained. | ||
890 | * | ||
891 | * @param urh handle to the upgraded response we are finished with | ||
892 | */ | ||
893 | static void | ||
894 | finish_upgrade_close (struct MHD_UpgradeResponseHandle *urh) | ||
895 | { | ||
896 | struct MHD_Connection *connection = urh->connection; | ||
897 | struct MHD_Daemon *daemon = connection->daemon; | ||
898 | |||
899 | DLL_remove (daemon->urh_head, | ||
900 | daemon->urh_tail, | ||
901 | urh); | ||
902 | if (0 != (daemon->options & MHD_USE_EPOLL)) | ||
903 | { | ||
904 | /* epoll documentation suggests that closing a FD | ||
905 | automatically removes it from the epoll set; however, | ||
906 | this is not true as if we fail to do manually remove it, | ||
907 | we are still seeing an event for this fd in epoll, | ||
908 | causing grief (use-after-free...) --- at least on my | ||
909 | system. */ | ||
910 | if (0 != epoll_ctl (daemon->epoll_upgrade_fd, | ||
911 | EPOLL_CTL_DEL, | ||
912 | connection->socket_fd, | ||
913 | NULL)) | ||
914 | MHD_PANIC ("Failed to remove FD from epoll set\n"); | ||
915 | } | ||
916 | if (MHD_INVALID_SOCKET != urh->mhd.socket) | ||
917 | { | ||
918 | /* epoll documentation suggests that closing a FD | ||
919 | automatically removes it from the epoll set; however, | ||
920 | this is not true as if we fail to do manually remove it, | ||
921 | we are still seeing an event for this fd in epoll, | ||
922 | causing grief (use-after-free...) --- at least on my | ||
923 | system. */ | ||
924 | if ( (0 != (daemon->options & MHD_USE_EPOLL)) && | ||
925 | (0 != epoll_ctl (daemon->epoll_upgrade_fd, | ||
926 | EPOLL_CTL_DEL, | ||
927 | urh->mhd.socket, | ||
928 | NULL)) ) | ||
929 | MHD_PANIC ("Failed to remove FD from epoll set\n"); | ||
930 | if (0 != MHD_socket_close_ (urh->mhd.socket)) | ||
931 | MHD_PANIC ("close failed\n"); | ||
932 | } | ||
933 | MHD_resume_connection (connection); | ||
934 | MHD_connection_close_ (connection, | ||
935 | MHD_REQUEST_TERMINATED_COMPLETED_OK); | ||
936 | free (urh); | ||
937 | } | ||
938 | |||
939 | |||
940 | /** | ||
886 | * Performs bi-directional forwarding on upgraded HTTPS connections | 941 | * Performs bi-directional forwarding on upgraded HTTPS connections |
887 | * based on the readyness state stored in the @a urh handle. | 942 | * based on the readyness state stored in the @a urh handle. |
888 | * | 943 | * |
@@ -891,6 +946,8 @@ call_handlers (struct MHD_Connection *con, | |||
891 | static void | 946 | static void |
892 | process_urh (struct MHD_UpgradeResponseHandle *urh) | 947 | process_urh (struct MHD_UpgradeResponseHandle *urh) |
893 | { | 948 | { |
949 | int fin_read; | ||
950 | |||
894 | /* handle reading from TLS client and writing to application */ | 951 | /* handle reading from TLS client and writing to application */ |
895 | if ( (0 != (MHD_EPOLL_STATE_READ_READY & urh->app.celi)) && | 952 | if ( (0 != (MHD_EPOLL_STATE_READ_READY & urh->app.celi)) && |
896 | (urh->in_buffer_off < urh->in_buffer_size) ) | 953 | (urh->in_buffer_off < urh->in_buffer_size) ) |
@@ -957,7 +1014,10 @@ process_urh (struct MHD_UpgradeResponseHandle *urh) | |||
957 | { | 1014 | { |
958 | urh->out_buffer_off += res; | 1015 | urh->out_buffer_off += res; |
959 | } | 1016 | } |
1017 | fin_read = (0 == res); | ||
960 | } | 1018 | } |
1019 | else | ||
1020 | fin_read = 0; | ||
961 | if ( (0 != (MHD_EPOLL_STATE_WRITE_READY & urh->app.celi)) && | 1021 | if ( (0 != (MHD_EPOLL_STATE_WRITE_READY & urh->app.celi)) && |
962 | (urh->out_buffer_off > 0) ) | 1022 | (urh->out_buffer_off > 0) ) |
963 | { | 1023 | { |
@@ -986,6 +1046,10 @@ process_urh (struct MHD_UpgradeResponseHandle *urh) | |||
986 | } | 1046 | } |
987 | } | 1047 | } |
988 | } | 1048 | } |
1049 | if ( (fin_read) && | ||
1050 | (0 == urh->out_buffer_off) && | ||
1051 | (MHD_YES == urh->was_closed) ) | ||
1052 | finish_upgrade_close (urh); | ||
989 | } | 1053 | } |
990 | #endif | 1054 | #endif |
991 | 1055 | ||
diff --git a/src/microhttpd/internal.h b/src/microhttpd/internal.h index 7a1e58e1..9549b19a 100644 --- a/src/microhttpd/internal.h +++ b/src/microhttpd/internal.h | |||
@@ -1036,6 +1036,13 @@ struct MHD_UpgradeResponseHandle | |||
1036 | * nothing left. | 1036 | * nothing left. |
1037 | */ | 1037 | */ |
1038 | char e_buf[RESERVE_EBUF_SIZE]; | 1038 | char e_buf[RESERVE_EBUF_SIZE]; |
1039 | |||
1040 | /** | ||
1041 | * Set to #MHD_YES after the application closed the socket | ||
1042 | * via #MHD_UPGRADE_ACTION_CLOSE. | ||
1043 | */ | ||
1044 | int was_closed; | ||
1045 | |||
1039 | #endif | 1046 | #endif |
1040 | 1047 | ||
1041 | }; | 1048 | }; |
diff --git a/src/microhttpd/response.c b/src/microhttpd/response.c index aa79196d..c08117d7 100644 --- a/src/microhttpd/response.c +++ b/src/microhttpd/response.c | |||
@@ -632,55 +632,27 @@ MHD_upgrade_action (struct MHD_UpgradeResponseHandle *urh, | |||
632 | /* just need to signal the thread that we are done */ | 632 | /* just need to signal the thread that we are done */ |
633 | MHD_semaphore_up (connection->upgrade_sem); | 633 | MHD_semaphore_up (connection->upgrade_sem); |
634 | } | 634 | } |
635 | #if HTTPS_SUPPORT | ||
635 | else | 636 | else |
636 | { | 637 | { |
637 | /* signal thread by shutdown() of 'app' socket */ | 638 | /* signal thread by shutdown() of 'app' socket */ |
638 | shutdown (urh->app.socket, SHUT_RDWR); | 639 | shutdown (urh->app.socket, |
640 | SHUT_RDWR); | ||
639 | } | 641 | } |
642 | #endif | ||
640 | return MHD_YES; | 643 | return MHD_YES; |
641 | } | 644 | } |
642 | #if HTTPS_SUPPORT | 645 | #if HTTPS_SUPPORT |
643 | if (0 != (daemon->options & MHD_USE_SSL) ) | 646 | if (0 != (daemon->options & MHD_USE_SSL) ) |
644 | { | 647 | { |
645 | DLL_remove (daemon->urh_head, | 648 | urh->was_closed = MHD_YES; |
646 | daemon->urh_tail, | ||
647 | urh); | ||
648 | if (0 != (daemon->options & MHD_USE_EPOLL)) | ||
649 | { | ||
650 | /* epoll documentation suggests that closing a FD | ||
651 | automatically removes it from the epoll set; however, | ||
652 | this is not true as if we fail to do manually remove it, | ||
653 | we are still seeing an event for this fd in epoll, | ||
654 | causing grief (use-after-free...) --- at least on my | ||
655 | system. */ | ||
656 | if (0 != epoll_ctl (daemon->epoll_upgrade_fd, | ||
657 | EPOLL_CTL_DEL, | ||
658 | connection->socket_fd, | ||
659 | NULL)) | ||
660 | MHD_PANIC ("Failed to remove FD from epoll set\n"); | ||
661 | } | ||
662 | if (MHD_INVALID_SOCKET != urh->app.socket) | 649 | if (MHD_INVALID_SOCKET != urh->app.socket) |
663 | { | 650 | { |
664 | if (0 != MHD_socket_close_ (urh->app.socket)) | 651 | if (0 != MHD_socket_close_ (urh->app.socket)) |
665 | MHD_PANIC ("close failed\n"); | 652 | MHD_PANIC ("close failed\n"); |
653 | urh->app.socket = MHD_INVALID_SOCKET; | ||
666 | } | 654 | } |
667 | if (MHD_INVALID_SOCKET != urh->mhd.socket) | 655 | return MHD_YES; |
668 | { | ||
669 | /* epoll documentation suggests that closing a FD | ||
670 | automatically removes it from the epoll set; however, | ||
671 | this is not true as if we fail to do manually remove it, | ||
672 | we are still seeing an event for this fd in epoll, | ||
673 | causing grief (use-after-free...) --- at least on my | ||
674 | system. */ | ||
675 | if ( (0 != (daemon->options & MHD_USE_EPOLL)) && | ||
676 | (0 != epoll_ctl (daemon->epoll_upgrade_fd, | ||
677 | EPOLL_CTL_DEL, | ||
678 | urh->mhd.socket, | ||
679 | NULL)) ) | ||
680 | MHD_PANIC ("Failed to remove FD from epoll set\n"); | ||
681 | if (0 != MHD_socket_close_ (urh->mhd.socket)) | ||
682 | MHD_PANIC ("close failed\n"); | ||
683 | } | ||
684 | } | 656 | } |
685 | #endif | 657 | #endif |
686 | MHD_resume_connection (connection); | 658 | MHD_resume_connection (connection); |
@@ -688,34 +660,6 @@ MHD_upgrade_action (struct MHD_UpgradeResponseHandle *urh, | |||
688 | MHD_REQUEST_TERMINATED_COMPLETED_OK); | 660 | MHD_REQUEST_TERMINATED_COMPLETED_OK); |
689 | free (urh); | 661 | free (urh); |
690 | return MHD_YES; | 662 | return MHD_YES; |
691 | case MHD_UPGRADE_ACTION_CORK: | ||
692 | /* FIXME: not implemented */ | ||
693 | return MHD_NO; | ||
694 | case MHD_UPGRADE_ACTION_FLUSH: | ||
695 | #if HTTPS_SUPPORT | ||
696 | if (0 != (daemon->options & MHD_USE_SSL)) | ||
697 | { | ||
698 | int avail; | ||
699 | |||
700 | /* First, check that our pipe is empty, to be sure we do | ||
701 | have it all in the buffer. */ | ||
702 | if ( (0 == | ||
703 | #if WINDOWS | ||
704 | ioctlsocket | ||
705 | #else | ||
706 | ioctl | ||
707 | #endif | ||
708 | (urh->mhd.socket, | ||
709 | FIONREAD, | ||
710 | &avail)) && | ||
711 | (0 != avail) ) | ||
712 | return MHD_NO; | ||
713 | /* then, refuse 'flush' unless our buffer is empty */ | ||
714 | if (0 != urh->out_buffer_off) | ||
715 | return MHD_NO; | ||
716 | } | ||
717 | #endif | ||
718 | return MHD_YES; | ||
719 | default: | 663 | default: |
720 | /* we don't understand this one */ | 664 | /* we don't understand this one */ |
721 | return MHD_NO; | 665 | return MHD_NO; |
diff --git a/src/microhttpd/test_upgrade_ssl.c b/src/microhttpd/test_upgrade_ssl.c index 5c663dd9..8077f402 100644 --- a/src/microhttpd/test_upgrade_ssl.c +++ b/src/microhttpd/test_upgrade_ssl.c | |||
@@ -259,10 +259,6 @@ run_usock (void *cls) | |||
259 | "Finished"); | 259 | "Finished"); |
260 | fprintf (stderr, | 260 | fprintf (stderr, |
261 | "Closing socket\n"); | 261 | "Closing socket\n"); |
262 | while (MHD_NO == | ||
263 | MHD_upgrade_action (urh, | ||
264 | MHD_UPGRADE_ACTION_FLUSH)) | ||
265 | usleep (1000); | ||
266 | MHD_upgrade_action (urh, | 262 | MHD_upgrade_action (urh, |
267 | MHD_UPGRADE_ACTION_CLOSE); | 263 | MHD_UPGRADE_ACTION_CLOSE); |
268 | fprintf (stderr, | 264 | fprintf (stderr, |