diff options
author | Christian Grothoff <christian@grothoff.org> | 2016-08-26 21:15:34 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2016-08-26 21:15:34 +0000 |
commit | 2669ca22a4d30949c54cead24958d24215276967 (patch) | |
tree | 4369262a3228072acf980cc624e84e1ca13cb376 | |
parent | a0dcd1ab1b234bbdfb5e2d4c92e48c7ea949cc6c (diff) | |
download | libmicrohttpd-2669ca22a4d30949c54cead24958d24215276967.tar.gz libmicrohttpd-2669ca22a4d30949c54cead24958d24215276967.zip |
sketching how I envision handling Upgrade
-rw-r--r-- | src/include/microhttpd.h | 12 | ||||
-rw-r--r-- | src/microhttpd/internal.h | 145 | ||||
-rw-r--r-- | src/microhttpd/response.c | 239 | ||||
-rw-r--r-- | src/microhttpd/response.h | 5 |
4 files changed, 322 insertions, 79 deletions
diff --git a/src/include/microhttpd.h b/src/include/microhttpd.h index eef50c70..27576f5f 100644 --- a/src/include/microhttpd.h +++ b/src/include/microhttpd.h | |||
@@ -2311,6 +2311,14 @@ MHD_upgrade_action (struct MHD_UpgradeResponseHandle *urh, | |||
2311 | * @param connection original HTTP connection handle, | 2311 | * @param connection original HTTP connection handle, |
2312 | * giving the function a last chance | 2312 | * giving the function a last chance |
2313 | * to inspect the original HTTP request | 2313 | * to inspect the original HTTP request |
2314 | * @param extra_in if we happened to have read bytes after the | ||
2315 | * HTTP header already (because the client sent | ||
2316 | * more than the HTTP header of the request before | ||
2317 | * we sent the upgrade response), | ||
2318 | * these are the extra bytes already read from @a sock | ||
2319 | * by MHD. The application should treat these as if | ||
2320 | * it had read them from @a sock. | ||
2321 | * @param extra_in_size number of bytes in @a extra_in | ||
2314 | * @param sock socket to use for bi-directional communication | 2322 | * @param sock socket to use for bi-directional communication |
2315 | * with the client. For HTTPS, this may not be a socket | 2323 | * with the client. For HTTPS, this may not be a socket |
2316 | * that is directly connected to the client and thus certain | 2324 | * that is directly connected to the client and thus certain |
@@ -2324,6 +2332,8 @@ MHD_upgrade_action (struct MHD_UpgradeResponseHandle *urh, | |||
2324 | typedef void | 2332 | typedef void |
2325 | (*MHD_UpgradeHandler)(void *cls, | 2333 | (*MHD_UpgradeHandler)(void *cls, |
2326 | struct MHD_Connection *connection, | 2334 | struct MHD_Connection *connection, |
2335 | const char *extra_in, | ||
2336 | size_t extra_in_size, | ||
2327 | MHD_SOCKET sock, | 2337 | MHD_SOCKET sock, |
2328 | struct MHD_UpgradeResponseHandle *urh); | 2338 | struct MHD_UpgradeResponseHandle *urh); |
2329 | 2339 | ||
@@ -2852,7 +2862,7 @@ enum MHD_FEATURE | |||
2852 | * @ingroup specialized | 2862 | * @ingroup specialized |
2853 | */ | 2863 | */ |
2854 | _MHD_EXTERN int | 2864 | _MHD_EXTERN int |
2855 | MHD_is_feature_supported(enum MHD_FEATURE feature); | 2865 | MHD_is_feature_supported (enum MHD_FEATURE feature); |
2856 | 2866 | ||
2857 | 2867 | ||
2858 | #if 0 /* keep Emacsens' auto-indent happy */ | 2868 | #if 0 /* keep Emacsens' auto-indent happy */ |
diff --git a/src/microhttpd/internal.h b/src/microhttpd/internal.h index 863def56..d6f1177c 100644 --- a/src/microhttpd/internal.h +++ b/src/microhttpd/internal.h | |||
@@ -102,68 +102,68 @@ extern void *mhd_panic_cls; | |||
102 | * State of the socket with respect to epoll (bitmask). | 102 | * State of the socket with respect to epoll (bitmask). |
103 | */ | 103 | */ |
104 | enum MHD_EpollState | 104 | enum MHD_EpollState |
105 | { | 105 | { |
106 | 106 | ||
107 | /** | 107 | /** |
108 | * The socket is not involved with a defined state in epoll() right | 108 | * The socket is not involved with a defined state in epoll() right |
109 | * now. | 109 | * now. |
110 | */ | 110 | */ |
111 | MHD_EPOLL_STATE_UNREADY = 0, | 111 | MHD_EPOLL_STATE_UNREADY = 0, |
112 | 112 | ||
113 | /** | 113 | /** |
114 | * epoll() told us that data was ready for reading, and we did | 114 | * epoll() told us that data was ready for reading, and we did |
115 | * not consume all of it yet. | 115 | * not consume all of it yet. |
116 | */ | 116 | */ |
117 | MHD_EPOLL_STATE_READ_READY = 1, | 117 | MHD_EPOLL_STATE_READ_READY = 1, |
118 | 118 | ||
119 | /** | 119 | /** |
120 | * epoll() told us that space was available for writing, and we did | 120 | * epoll() told us that space was available for writing, and we did |
121 | * not consume all of it yet. | 121 | * not consume all of it yet. |
122 | */ | 122 | */ |
123 | MHD_EPOLL_STATE_WRITE_READY = 2, | 123 | MHD_EPOLL_STATE_WRITE_READY = 2, |
124 | 124 | ||
125 | /** | 125 | /** |
126 | * Is this connection currently in the 'eready' EDLL? | 126 | * Is this connection currently in the 'eready' EDLL? |
127 | */ | 127 | */ |
128 | MHD_EPOLL_STATE_IN_EREADY_EDLL = 4, | 128 | MHD_EPOLL_STATE_IN_EREADY_EDLL = 4, |
129 | 129 | ||
130 | /** | 130 | /** |
131 | * Is this connection currently in the epoll() set? | 131 | * Is this connection currently in the epoll() set? |
132 | */ | 132 | */ |
133 | MHD_EPOLL_STATE_IN_EPOLL_SET = 8, | 133 | MHD_EPOLL_STATE_IN_EPOLL_SET = 8, |
134 | 134 | ||
135 | /** | 135 | /** |
136 | * Is this connection currently suspended? | 136 | * Is this connection currently suspended? |
137 | */ | 137 | */ |
138 | MHD_EPOLL_STATE_SUSPENDED = 16 | 138 | MHD_EPOLL_STATE_SUSPENDED = 16 |
139 | }; | 139 | }; |
140 | 140 | ||
141 | 141 | ||
142 | /** | 142 | /** |
143 | * What is this connection waiting for? | 143 | * What is this connection waiting for? |
144 | */ | 144 | */ |
145 | enum MHD_ConnectionEventLoopInfo | 145 | enum MHD_ConnectionEventLoopInfo |
146 | { | 146 | { |
147 | /** | 147 | /** |
148 | * We are waiting to be able to read. | 148 | * We are waiting to be able to read. |
149 | */ | 149 | */ |
150 | MHD_EVENT_LOOP_INFO_READ = 0, | 150 | MHD_EVENT_LOOP_INFO_READ = 0, |
151 | 151 | ||
152 | /** | 152 | /** |
153 | * We are waiting to be able to write. | 153 | * We are waiting to be able to write. |
154 | */ | 154 | */ |
155 | MHD_EVENT_LOOP_INFO_WRITE = 1, | 155 | MHD_EVENT_LOOP_INFO_WRITE = 1, |
156 | 156 | ||
157 | /** | 157 | /** |
158 | * We are waiting for the application to provide data. | 158 | * We are waiting for the application to provide data. |
159 | */ | 159 | */ |
160 | MHD_EVENT_LOOP_INFO_BLOCK = 2, | 160 | MHD_EVENT_LOOP_INFO_BLOCK = 2, |
161 | 161 | ||
162 | /** | 162 | /** |
163 | * We are finished and are awaiting cleanup. | 163 | * We are finished and are awaiting cleanup. |
164 | */ | 164 | */ |
165 | MHD_EVENT_LOOP_INFO_CLEANUP = 3 | 165 | MHD_EVENT_LOOP_INFO_CLEANUP = 3 |
166 | }; | 166 | }; |
167 | 167 | ||
168 | 168 | ||
169 | /** | 169 | /** |
@@ -202,7 +202,8 @@ struct MHD_NonceNc | |||
202 | */ | 202 | */ |
203 | void | 203 | void |
204 | MHD_DLOG (const struct MHD_Daemon *daemon, | 204 | MHD_DLOG (const struct MHD_Daemon *daemon, |
205 | const char *format, ...); | 205 | const char *format, |
206 | ...); | ||
206 | #endif | 207 | #endif |
207 | 208 | ||
208 | 209 | ||
@@ -273,6 +274,20 @@ struct MHD_Response | |||
273 | */ | 274 | */ |
274 | MHD_ContentReaderFreeCallback crfc; | 275 | MHD_ContentReaderFreeCallback crfc; |
275 | 276 | ||
277 | #if 0 | ||
278 | /** | ||
279 | * Application function to call once we are done sending the headers | ||
280 | * of the response; NULL unless this is a response created with | ||
281 | * #MHD_create_response_for_upgrade(). | ||
282 | */ | ||
283 | MHD_UpgradeHandler upgrade_handler; | ||
284 | |||
285 | /** | ||
286 | * Closure for @e uh. | ||
287 | */ | ||
288 | void *upgrade_handler_cls; | ||
289 | #endif | ||
290 | |||
276 | /** | 291 | /** |
277 | * Mutex to synchronize access to @e data, @e size and | 292 | * Mutex to synchronize access to @e data, @e size and |
278 | * @e reference_count. | 293 | * @e reference_count. |
@@ -569,14 +584,12 @@ struct MHD_Connection | |||
569 | struct MHD_Response *response; | 584 | struct MHD_Response *response; |
570 | 585 | ||
571 | /** | 586 | /** |
572 | * The memory pool is created whenever we first read | 587 | * The memory pool is created whenever we first read from the TCP |
573 | * from the TCP stream and destroyed at the end of | 588 | * stream and destroyed at the end of each request (and re-created |
574 | * each request (and re-created for the next request). | 589 | * for the next request). In the meantime, this pointer is NULL. |
575 | * In the meantime, this pointer is NULL. The | 590 | * The pool is used for all connection-related data except for the |
576 | * pool is used for all connection-related data | 591 | * response (which maybe shared between connections) and the IP |
577 | * except for the response (which maybe shared between | 592 | * address (which persists across individual requests). |
578 | * connections) and the IP address (which persists | ||
579 | * across individual requests). | ||
580 | */ | 593 | */ |
581 | struct MemoryPool *pool; | 594 | struct MemoryPool *pool; |
582 | 595 | ||
@@ -598,8 +611,7 @@ struct MHD_Connection | |||
598 | void *socket_context; | 611 | void *socket_context; |
599 | 612 | ||
600 | /** | 613 | /** |
601 | * Request method. Should be GET/POST/etc. Allocated | 614 | * Request method. Should be GET/POST/etc. Allocated in pool. |
602 | * in pool. | ||
603 | */ | 615 | */ |
604 | char *method; | 616 | char *method; |
605 | 617 | ||
@@ -616,9 +628,8 @@ struct MHD_Connection | |||
616 | char *version; | 628 | char *version; |
617 | 629 | ||
618 | /** | 630 | /** |
619 | * Buffer for reading requests. Allocated | 631 | * Buffer for reading requests. Allocated in pool. Actually one |
620 | * in pool. Actually one byte larger than | 632 | * byte larger than @e read_buffer_size (if non-NULL) to allow for |
621 | * @e read_buffer_size (if non-NULL) to allow for | ||
622 | * 0-termination. | 633 | * 0-termination. |
623 | */ | 634 | */ |
624 | char *read_buffer; | 635 | char *read_buffer; |
diff --git a/src/microhttpd/response.c b/src/microhttpd/response.c index 3e967e68..f0ebf5c6 100644 --- a/src/microhttpd/response.c +++ b/src/microhttpd/response.c | |||
@@ -101,7 +101,8 @@ add_response_entry (struct MHD_Response *response, | |||
101 | */ | 101 | */ |
102 | int | 102 | int |
103 | MHD_add_response_header (struct MHD_Response *response, | 103 | MHD_add_response_header (struct MHD_Response *response, |
104 | const char *header, const char *content) | 104 | const char *header, |
105 | const char *content) | ||
105 | { | 106 | { |
106 | return add_response_entry (response, | 107 | return add_response_entry (response, |
107 | MHD_HEADER_KIND, | 108 | MHD_HEADER_KIND, |
@@ -121,7 +122,8 @@ MHD_add_response_header (struct MHD_Response *response, | |||
121 | */ | 122 | */ |
122 | int | 123 | int |
123 | MHD_add_response_footer (struct MHD_Response *response, | 124 | MHD_add_response_footer (struct MHD_Response *response, |
124 | const char *footer, const char *content) | 125 | const char *footer, |
126 | const char *content) | ||
125 | { | 127 | { |
126 | return add_response_entry (response, | 128 | return add_response_entry (response, |
127 | MHD_FOOTER_KIND, | 129 | MHD_FOOTER_KIND, |
@@ -184,7 +186,8 @@ MHD_del_response_header (struct MHD_Response *response, | |||
184 | */ | 186 | */ |
185 | int | 187 | int |
186 | MHD_get_response_headers (struct MHD_Response *response, | 188 | MHD_get_response_headers (struct MHD_Response *response, |
187 | MHD_KeyValueIterator iterator, void *iterator_cls) | 189 | MHD_KeyValueIterator iterator, |
190 | void *iterator_cls) | ||
188 | { | 191 | { |
189 | struct MHD_HTTP_Header *pos; | 192 | struct MHD_HTTP_Header *pos; |
190 | int numHeaders = 0; | 193 | int numHeaders = 0; |
@@ -316,7 +319,10 @@ MHD_set_response_options (struct MHD_Response *response, | |||
316 | * @return number of bytes written | 319 | * @return number of bytes written |
317 | */ | 320 | */ |
318 | static ssize_t | 321 | static ssize_t |
319 | file_reader (void *cls, uint64_t pos, char *buf, size_t max) | 322 | file_reader (void *cls, |
323 | uint64_t pos, | ||
324 | char *buf, | ||
325 | size_t max) | ||
320 | { | 326 | { |
321 | struct MHD_Response *response = cls; | 327 | struct MHD_Response *response = cls; |
322 | ssize_t n; | 328 | ssize_t n; |
@@ -397,7 +403,9 @@ MHD_create_response_from_fd_at_offset (size_t size, | |||
397 | int fd, | 403 | int fd, |
398 | off_t offset) | 404 | off_t offset) |
399 | { | 405 | { |
400 | return MHD_create_response_from_fd_at_offset64 (size, fd, offset); | 406 | return MHD_create_response_from_fd_at_offset64 (size, |
407 | fd, | ||
408 | offset); | ||
401 | } | 409 | } |
402 | 410 | ||
403 | 411 | ||
@@ -461,7 +469,9 @@ struct MHD_Response * | |||
461 | MHD_create_response_from_fd (size_t size, | 469 | MHD_create_response_from_fd (size_t size, |
462 | int fd) | 470 | int fd) |
463 | { | 471 | { |
464 | return MHD_create_response_from_fd_at_offset64 (size, fd, 0); | 472 | return MHD_create_response_from_fd_at_offset64 (size, |
473 | fd, | ||
474 | 0); | ||
465 | } | 475 | } |
466 | 476 | ||
467 | 477 | ||
@@ -482,7 +492,9 @@ _MHD_EXTERN struct MHD_Response * | |||
482 | MHD_create_response_from_fd64 (uint64_t size, | 492 | MHD_create_response_from_fd64 (uint64_t size, |
483 | int fd) | 493 | int fd) |
484 | { | 494 | { |
485 | return MHD_create_response_from_fd_at_offset64 (size, fd, 0); | 495 | return MHD_create_response_from_fd_at_offset64 (size, |
496 | fd, | ||
497 | 0); | ||
486 | } | 498 | } |
487 | 499 | ||
488 | 500 | ||
@@ -502,7 +514,9 @@ MHD_create_response_from_fd64 (uint64_t size, | |||
502 | */ | 514 | */ |
503 | struct MHD_Response * | 515 | struct MHD_Response * |
504 | MHD_create_response_from_data (size_t size, | 516 | MHD_create_response_from_data (size_t size, |
505 | void *data, int must_free, int must_copy) | 517 | void *data, |
518 | int must_free, | ||
519 | int must_copy) | ||
506 | { | 520 | { |
507 | struct MHD_Response *response; | 521 | struct MHD_Response *response; |
508 | void *tmp; | 522 | void *tmp; |
@@ -513,7 +527,7 @@ MHD_create_response_from_data (size_t size, | |||
513 | return NULL; | 527 | return NULL; |
514 | memset (response, 0, sizeof (struct MHD_Response)); | 528 | memset (response, 0, sizeof (struct MHD_Response)); |
515 | response->fd = -1; | 529 | response->fd = -1; |
516 | if (!MHD_mutex_init_ (&response->mutex)) | 530 | if (! MHD_mutex_init_ (&response->mutex)) |
517 | { | 531 | { |
518 | free (response); | 532 | free (response); |
519 | return NULL; | 533 | return NULL; |
@@ -563,6 +577,208 @@ MHD_create_response_from_buffer (size_t size, | |||
563 | } | 577 | } |
564 | 578 | ||
565 | 579 | ||
580 | #if 0 | ||
581 | /** | ||
582 | * Handle given to the application to manage special | ||
583 | * actions relating to MHD responses that "upgrade" | ||
584 | * the HTTP protocol (i.e. to WebSockets). | ||
585 | */ | ||
586 | struct MHD_UpgradeResponseHandle | ||
587 | { | ||
588 | |||
589 | /** | ||
590 | * The connection for which this is an upgrade handle. Note that | ||
591 | * because a response may be shared over many connections, this may | ||
592 | * not be the only upgrade handle for the response of this connection. | ||
593 | */ | ||
594 | struct MHD_Connection *connection; | ||
595 | |||
596 | /** | ||
597 | * The socket we gave to the application (r/w). | ||
598 | */ | ||
599 | MHD_SOCKET app_sock; | ||
600 | |||
601 | /** | ||
602 | * If @a app_sock was a socketpair, our end of it, otherwise | ||
603 | * #MHD_INVALID_SOCKET; (r/w). | ||
604 | */ | ||
605 | MHD_SOCKET mhd_sock; | ||
606 | |||
607 | }; | ||
608 | |||
609 | |||
610 | /** | ||
611 | * This connection-specific callback is provided by MHD to | ||
612 | * applications (unusual) during the #MHD_UpgradeHandler. | ||
613 | * It allows applications to perform 'special' actions on | ||
614 | * the underlying socket from the upgrade. | ||
615 | * | ||
616 | * @param urh the handle identifying the connection to perform | ||
617 | * the upgrade @a action on. | ||
618 | * @param action which action should be performed | ||
619 | * @param ... arguments to the action (depends on the action) | ||
620 | * @return #MHD_NO on error, #MHD_YES on success | ||
621 | */ | ||
622 | _MHD_EXTERN int | ||
623 | MHD_upgrade_action (struct MHD_UpgradeResponseHandle *urh, | ||
624 | enum MHD_UpgradeAction action, | ||
625 | ...) | ||
626 | { | ||
627 | switch (action) | ||
628 | { | ||
629 | case MHD_UPGRADE_ACTION_CLOSE: | ||
630 | /* Application is done with this connection, tear it down! */ | ||
631 | if ( (MHD_INVALID_SOCKET != urh->app_socket) && | ||
632 | (0 != MHD_socket_close (urh->app_socket)) ) | ||
633 | MHD_PANIC ("close failed\n"); | ||
634 | if ( (MHD_INVALID_SOCKET != urh->mhd_socket) && | ||
635 | (0 != MHD_socket_close (urh->mhd_socket)) ) | ||
636 | MHD_PANIC ("close failed\n"); | ||
637 | MHD_connection_resume (urh->connection); | ||
638 | MHD_connection_close_ (urh->connection, | ||
639 | MHD_REQUEST_TERMINATED_COMPLETED_OK); | ||
640 | free (urh); | ||
641 | return MHD_YES; | ||
642 | case MHD_UPGRADE_ACTION_CORK: | ||
643 | /* FIXME: not implemented */ | ||
644 | return MHD_NO; | ||
645 | default: | ||
646 | /* we don't understand this one */ | ||
647 | return MHD_NO; | ||
648 | } | ||
649 | } | ||
650 | |||
651 | |||
652 | /** | ||
653 | * We are done sending the header of a given response | ||
654 | * to the client. Now it is time to perform the upgrade | ||
655 | * and hand over the connection to the application. | ||
656 | * | ||
657 | * @param response the response that was created for an upgrade | ||
658 | * @param connection the specific connection we are upgrading | ||
659 | * @return #MHD_YES on success, #MHD_NO on failure (will cause | ||
660 | * connection to be closed) | ||
661 | */ | ||
662 | // FIXME: This function will need to be called at the right place(s) | ||
663 | // in the connection processing (just after we are done sending the header) | ||
664 | // (for responses that have the 'upgrade_header' callback set). | ||
665 | int | ||
666 | MHD_response_execute_upgrade_ (struct MHD_Response *response, | ||
667 | struct MHD_Connection *connection) | ||
668 | { | ||
669 | struct MHD_UpgradeResponseHandle *urh; | ||
670 | int sv[2]; | ||
671 | size_t rbo; | ||
672 | |||
673 | urh = malloc (sizeof (struct MHD_UpgradeResponseHandle)); | ||
674 | if (NULL == urh) | ||
675 | return MHD_NO; | ||
676 | #if HTTPS_SUPPORT | ||
677 | if (0 != (connection->daemon->flags & MHD_USE_SSL) ) | ||
678 | { | ||
679 | /* FIXME: this is non-portable for now; W32 port pending... */ | ||
680 | if (0 != socketpair (AF_UNIX, | ||
681 | SOCK_STREAM, | ||
682 | 0, | ||
683 | sv)) | ||
684 | { | ||
685 | free (urh); | ||
686 | return MHD_NO; | ||
687 | } | ||
688 | urh->app_socket = sv[0]; | ||
689 | urh->mhd_socket = sv[1]; | ||
690 | urh->connection = connection; | ||
691 | rbo = connection->read_buffer_offset; | ||
692 | connection->read_buffer_offset = 0; | ||
693 | response->upgrade_handler (response->upgrade_handler_cls, | ||
694 | connection, | ||
695 | connection->read_buffer, | ||
696 | rbo, | ||
697 | urh->app_sock, | ||
698 | urh); | ||
699 | /* As far as MHD is concerned, this connection is | ||
700 | suspended; it will be resumed once we are done | ||
701 | in the #MHD_upgrade_action() function */ | ||
702 | MHD_connection_suspend (connection); | ||
703 | /* FIXME: also need to start some processing logic in _all_ MHD | ||
704 | event loops for the sv traffic! (NOT IMPLEMENTED!!!) */ | ||
705 | return MHD_YES; | ||
706 | } | ||
707 | #endif | ||
708 | urh->app_socket = MHD_INVALID_SOCKET; | ||
709 | urh->mhd_socket = MHD_INVALID_SOCKET; | ||
710 | rbo = connection->read_buffer_offset; | ||
711 | connection->read_buffer_offset = 0; | ||
712 | response->upgrade_handler (response->upgrade_handler_cls, | ||
713 | connection, | ||
714 | connection->read_buffer, | ||
715 | rbo, | ||
716 | connection->socket_fd, | ||
717 | urh); | ||
718 | /* As far as MHD is concerned, this connection is | ||
719 | suspended; it will be resumed once we are done | ||
720 | in the #MHD_upgrade_action() function */ | ||
721 | MHD_connection_suspend (connection); | ||
722 | return MHD_YES; | ||
723 | } | ||
724 | |||
725 | |||
726 | /** | ||
727 | * Create a response object that can be used for 101 UPGRADE | ||
728 | * responses, for example to implement WebSockets. After sending the | ||
729 | * response, control over the data stream is given to the callback (which | ||
730 | * can then, for example, start some bi-directional communication). | ||
731 | * If the response is queued for multiple connections, the callback | ||
732 | * will be called for each connection. The callback | ||
733 | * will ONLY be called after the response header was successfully passed | ||
734 | * to the OS; if there are communication errors before, the usual MHD | ||
735 | * connection error handling code will be performed. | ||
736 | * | ||
737 | * Setting the correct HTTP code (i.e. MHD_HTTP_SWITCHING_PROTOCOLS) | ||
738 | * and setting correct HTTP headers for the upgrade must be done | ||
739 | * manually (this way, it is possible to implement most existing | ||
740 | * WebSocket versions using this API; in fact, this API might be useful | ||
741 | * for any protocol switch, not just WebSockets). Note that | ||
742 | * draft-ietf-hybi-thewebsocketprotocol-00 cannot be implemented this | ||
743 | * way as the header "HTTP/1.1 101 WebSocket Protocol Handshake" | ||
744 | * cannot be generated; instead, MHD will always produce "HTTP/1.1 101 | ||
745 | * Switching Protocols" (if the response code 101 is used). | ||
746 | * | ||
747 | * As usual, the response object can be extended with header | ||
748 | * information and then be used any number of times (as long as the | ||
749 | * header information is not connection-specific). | ||
750 | * | ||
751 | * @param upgrade_handler function to call with the 'upgraded' socket | ||
752 | * @param upgrade_handler_cls closure for @a upgrade_handler | ||
753 | * @return NULL on error (i.e. invalid arguments, out of memory) | ||
754 | */ | ||
755 | _MHD_EXTERN struct MHD_Response * | ||
756 | MHD_create_response_for_upgrade (MHD_UpgradeHandler upgrade_handler, | ||
757 | void *upgrade_handler_cls) | ||
758 | { | ||
759 | struct MHD_Response *response; | ||
760 | |||
761 | if (NULL == upgrade_header) | ||
762 | return NULL; /* invalid request */ | ||
763 | response = malloc (sizeof (struct MHD_Response)); | ||
764 | if (NULL == response) | ||
765 | return NULL; | ||
766 | memset (response, 0, sizeof (struct MHD_Response)); | ||
767 | if (! MHD_mutex_init_ (&response->mutex)) | ||
768 | { | ||
769 | free (response); | ||
770 | return NULL; | ||
771 | } | ||
772 | urh->response = response; | ||
773 | response->upgrade_handler = upgrade_handler; | ||
774 | response->upgrade_handler_cls = upgrade_handler_cls; | ||
775 | response->total_size = MHD_SIZE_UNKNOWN; | ||
776 | response->reference_count = 1; | ||
777 | return response; | ||
778 | } | ||
779 | #endif | ||
780 | |||
781 | |||
566 | /** | 782 | /** |
567 | * Destroy a response object and associated resources. Note that | 783 | * Destroy a response object and associated resources. Note that |
568 | * libmicrohttpd may keep some of the resources around if the response | 784 | * libmicrohttpd may keep some of the resources around if the response |
@@ -601,6 +817,11 @@ MHD_destroy_response (struct MHD_Response *response) | |||
601 | } | 817 | } |
602 | 818 | ||
603 | 819 | ||
820 | /** | ||
821 | * Increments the reference counter for the @a response. | ||
822 | * | ||
823 | * @param response object to modify | ||
824 | */ | ||
604 | void | 825 | void |
605 | MHD_increment_response_rc (struct MHD_Response *response) | 826 | MHD_increment_response_rc (struct MHD_Response *response) |
606 | { | 827 | { |
diff --git a/src/microhttpd/response.h b/src/microhttpd/response.h index 5785ec96..a13683d1 100644 --- a/src/microhttpd/response.h +++ b/src/microhttpd/response.h | |||
@@ -28,8 +28,9 @@ | |||
28 | #define RESPONSE_H | 28 | #define RESPONSE_H |
29 | 29 | ||
30 | /** | 30 | /** |
31 | * Increment response RC. Should this be part of the | 31 | * Increments the reference counter for the @a response. |
32 | * public API? | 32 | * |
33 | * @param response object to modify | ||
33 | */ | 34 | */ |
34 | void | 35 | void |
35 | MHD_increment_response_rc (struct MHD_Response *response); | 36 | MHD_increment_response_rc (struct MHD_Response *response); |