aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2016-08-26 21:15:34 +0000
committerChristian Grothoff <christian@grothoff.org>2016-08-26 21:15:34 +0000
commit2669ca22a4d30949c54cead24958d24215276967 (patch)
tree4369262a3228072acf980cc624e84e1ca13cb376
parenta0dcd1ab1b234bbdfb5e2d4c92e48c7ea949cc6c (diff)
downloadlibmicrohttpd-2669ca22a4d30949c54cead24958d24215276967.tar.gz
libmicrohttpd-2669ca22a4d30949c54cead24958d24215276967.zip
sketching how I envision handling Upgrade
-rw-r--r--src/include/microhttpd.h12
-rw-r--r--src/microhttpd/internal.h145
-rw-r--r--src/microhttpd/response.c239
-rw-r--r--src/microhttpd/response.h5
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,
2324typedef void 2332typedef 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
2855MHD_is_feature_supported(enum MHD_FEATURE feature); 2865MHD_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 */
104enum MHD_EpollState 104enum 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 */
145enum MHD_ConnectionEventLoopInfo 145enum 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 */
203void 203void
204MHD_DLOG (const struct MHD_Daemon *daemon, 204MHD_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 */
102int 102int
103MHD_add_response_header (struct MHD_Response *response, 103MHD_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 */
122int 123int
123MHD_add_response_footer (struct MHD_Response *response, 124MHD_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 */
185int 187int
186MHD_get_response_headers (struct MHD_Response *response, 188MHD_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 */
318static ssize_t 321static ssize_t
319file_reader (void *cls, uint64_t pos, char *buf, size_t max) 322file_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 *
461MHD_create_response_from_fd (size_t size, 469MHD_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 *
482MHD_create_response_from_fd64 (uint64_t size, 492MHD_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 */
503struct MHD_Response * 515struct MHD_Response *
504MHD_create_response_from_data (size_t size, 516MHD_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 */
586struct 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
623MHD_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).
665int
666MHD_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 *
756MHD_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 */
604void 825void
605MHD_increment_response_rc (struct MHD_Response *response) 826MHD_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 */
34void 35void
35MHD_increment_response_rc (struct MHD_Response *response); 36MHD_increment_response_rc (struct MHD_Response *response);