diff options
Diffstat (limited to 'doc')
-rw-r--r-- | doc/chapters/bibliography.inc | 3 | ||||
-rw-r--r-- | doc/chapters/websocket.inc | 886 | ||||
-rw-r--r-- | doc/examples/websocket.c | 446 | ||||
-rw-r--r-- | doc/libmicrohttpd-tutorial.texi | 12 | ||||
-rw-r--r-- | doc/libmicrohttpd.texi | 1281 |
5 files changed, 2628 insertions, 0 deletions
diff --git a/doc/chapters/bibliography.inc b/doc/chapters/bibliography.inc index cc288bc0..bdaa6187 100644 --- a/doc/chapters/bibliography.inc +++ b/doc/chapters/bibliography.inc | |||
@@ -16,6 +16,9 @@ All referenced RFCs can be found on the website of @emph{The Internet Engineerin | |||
16 | @emph{RFC 2617}: Franks, J., Hallam-Baker, P., Hostetler, J., Lawrence, S., Leach, P., | 16 | @emph{RFC 2617}: Franks, J., Hallam-Baker, P., Hostetler, J., Lawrence, S., Leach, P., |
17 | Luotonen, A., and L. Stewart, "HTTP Authentication: Basic and Digest Access Authentication", RFC 2617, June 1999. | 17 | Luotonen, A., and L. Stewart, "HTTP Authentication: Basic and Digest Access Authentication", RFC 2617, June 1999. |
18 | 18 | ||
19 | @item | ||
20 | @emph{RFC 6455}: Fette, I., Melnikov, A., "The WebSocket Protocol", RFC 6455, December 2011. | ||
21 | |||
19 | 22 | ||
20 | @item | 23 | @item |
21 | A well--structured @emph{HTML} reference can be found on | 24 | A well--structured @emph{HTML} reference can be found on |
diff --git a/doc/chapters/websocket.inc b/doc/chapters/websocket.inc new file mode 100644 index 00000000..a480fd13 --- /dev/null +++ b/doc/chapters/websocket.inc | |||
@@ -0,0 +1,886 @@ | |||
1 | Websockets are a genuine way to implement push notifications, | ||
2 | where the server initiates the communication while the client can be idle. | ||
3 | Usually a HTTP communication is half-duplex and always requested by the client, | ||
4 | but websockets are full-duplex and only initialized by the client. | ||
5 | In the further communication both sites can use the websocket at any time | ||
6 | to send data to the other site. | ||
7 | |||
8 | To initialize a websocket connection the client sends a special HTTP request | ||
9 | to the server and initializes | ||
10 | a handshake between client and server which switches from the HTTP protocol | ||
11 | to the websocket protocol. | ||
12 | Thus both the server as well as the client must support websockets. | ||
13 | If proxys are used, they must support websockets too. | ||
14 | In this chapter we take a look on server and client, but with a focus on | ||
15 | the server with @emph{libmicrohttpd}. | ||
16 | |||
17 | Since version 0.9.52 @emph{libmicrohttpd} supports upgrading requests, | ||
18 | which is required for switching from the HTTP protocol. | ||
19 | Since version 0.9.74 the library @emph{libmicrohttpd_ws} has been added | ||
20 | to support the websocket protocol. | ||
21 | |||
22 | @heading Upgrading connections with libmicrohttpd | ||
23 | |||
24 | To support websockets we need to enable upgrading of HTTP connections first. | ||
25 | This is done by passing the flag @code{MHD_ALLOW_UPGRADE} to | ||
26 | @code{MHD_start_daemon()}. | ||
27 | |||
28 | |||
29 | @verbatim | ||
30 | daemon = MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD | | ||
31 | MHD_USE_THREAD_PER_CONNECTION | | ||
32 | MHD_ALLOW_UPGRADE | | ||
33 | MHD_USE_ERROR_LOG, | ||
34 | PORT, NULL, NULL, | ||
35 | &access_handler, NULL, | ||
36 | MHD_OPTION_END); | ||
37 | @end verbatim | ||
38 | @noindent | ||
39 | |||
40 | |||
41 | The next step is to turn a specific request into an upgraded connection. | ||
42 | This done in our @code{access_handler} by calling | ||
43 | @code{MHD_create_response_for_upgrade()}. | ||
44 | An @code{upgrade_handler} will be passed to perform the low-level actions | ||
45 | on the socket. | ||
46 | |||
47 | @emph{Please note that the socket here is just a regular socket as provided | ||
48 | by the operating system. | ||
49 | To use it as a websocket, some more steps from the following | ||
50 | chapters are required.} | ||
51 | |||
52 | |||
53 | @verbatim | ||
54 | static enum MHD_Result | ||
55 | access_handler (void *cls, | ||
56 | struct MHD_Connection *connection, | ||
57 | const char *url, | ||
58 | const char *method, | ||
59 | const char *version, | ||
60 | const char *upload_data, | ||
61 | size_t *upload_data_size, | ||
62 | void **ptr) | ||
63 | { | ||
64 | /* ... */ | ||
65 | /* some code to decide whether to upgrade or not */ | ||
66 | /* ... */ | ||
67 | |||
68 | /* create the response for upgrade */ | ||
69 | response = MHD_create_response_for_upgrade (&upgrade_handler, | ||
70 | NULL); | ||
71 | |||
72 | /* ... */ | ||
73 | /* additional headers, etc. */ | ||
74 | /* ... */ | ||
75 | |||
76 | ret = MHD_queue_response (connection, | ||
77 | MHD_HTTP_SWITCHING_PROTOCOLS, | ||
78 | response); | ||
79 | MHD_destroy_response (response); | ||
80 | |||
81 | return ret; | ||
82 | } | ||
83 | @end verbatim | ||
84 | @noindent | ||
85 | |||
86 | |||
87 | In the @code{upgrade_handler} we receive the low-level socket, | ||
88 | which is used for the communication with the specific client. | ||
89 | In addition to the low-level socket we get: | ||
90 | @itemize @bullet | ||
91 | @item | ||
92 | Some data, which has been read too much while @emph{libmicrohttpd} was | ||
93 | switching the protocols. | ||
94 | This value is usually empty, because it would mean that the client | ||
95 | has sent data before the handshake was complete. | ||
96 | |||
97 | @item | ||
98 | A @code{struct MHD_UpgradeResponseHandle} which is used to perform | ||
99 | special actions like closing, corking or uncorking the socket. | ||
100 | These commands are executed by passing the handle | ||
101 | to @code{MHD_upgrade_action()}. | ||
102 | |||
103 | |||
104 | @end itemize | ||
105 | |||
106 | Depending of the flags specified while calling @code{MHD_start_deamon()} | ||
107 | our @code{upgrade_handler} is either executed in the same thread | ||
108 | as our deamon or in a thread specific for each connection. | ||
109 | If it is executed in the same thread then @code{upgrade_handler} is | ||
110 | a blocking call for our webserver and | ||
111 | we should finish it as fast as possible (i. e. by creating a thread and | ||
112 | passing the information there). | ||
113 | If @code{MHD_USE_THREAD_PER_CONNECTION} was passed to | ||
114 | @code{MHD_start_daemon()} then a separate thread is used and | ||
115 | thus our @code{upgrade_handler} needs not to start a separate thread. | ||
116 | |||
117 | An @code{upgrade_handler}, which is called with a separate thread | ||
118 | per connection, could look like this: | ||
119 | |||
120 | |||
121 | @verbatim | ||
122 | static void | ||
123 | upgrade_handler (void *cls, | ||
124 | struct MHD_Connection *connection, | ||
125 | void *con_cls, | ||
126 | const char *extra_in, | ||
127 | size_t extra_in_size, | ||
128 | MHD_socket fd, | ||
129 | struct MHD_UpgradeResponseHandle *urh) | ||
130 | { | ||
131 | /* ... */ | ||
132 | /* do something with the socket `fd` like `recv()` or `send()` */ | ||
133 | /* ... */ | ||
134 | |||
135 | /* close the socket when it is not needed anymore */ | ||
136 | MHD_upgrade_action (urh, | ||
137 | MHD_UPGRADE_ACTION_CLOSE); | ||
138 | } | ||
139 | @end verbatim | ||
140 | @noindent | ||
141 | |||
142 | |||
143 | This is all you need to know for upgrading connections | ||
144 | with @emph{libmicrohttpd}. | ||
145 | The next chapters focus on using the websocket protocol | ||
146 | with @emph{libmicrohttpd_ws}. | ||
147 | |||
148 | |||
149 | @heading Websocket handshake with libmicrohttpd_ws | ||
150 | |||
151 | To request a websocket connection the client must send | ||
152 | the following information with the HTTP request: | ||
153 | |||
154 | @itemize @bullet | ||
155 | @item | ||
156 | A @code{GET} request must be sent. | ||
157 | |||
158 | @item | ||
159 | The version of the HTTP protocol must be 1.1 or higher. | ||
160 | |||
161 | @item | ||
162 | A @code{Host} header field must be sent | ||
163 | |||
164 | @item | ||
165 | A @code{Upgrade} header field containing the keyword "websocket" | ||
166 | (case-insensitive). | ||
167 | Please note that the client could pass multiple protocols separated by comma. | ||
168 | |||
169 | @item | ||
170 | A @code{Connection} header field that includes the token "Upgrade" | ||
171 | (case-insensitive). | ||
172 | Please note that the client could pass multiple tokens separated by comma. | ||
173 | |||
174 | @item | ||
175 | A @code{Sec-WebSocket-Key} header field with a base64-encoded value. | ||
176 | The decoded the value is 16 bytes long | ||
177 | and has been generated randomly by the client. | ||
178 | |||
179 | @item | ||
180 | A @code{Sec-WebSocket-Version} header field with the value "13". | ||
181 | |||
182 | @end itemize | ||
183 | |||
184 | |||
185 | Optionally the client can also send the following information: | ||
186 | |||
187 | |||
188 | @itemize @bullet | ||
189 | @item | ||
190 | A @code{Origin} header field can be used to determine the source | ||
191 | of the client (i. e. the website). | ||
192 | |||
193 | @item | ||
194 | A @code{Sec-WebSocket-Protocol} header field can contain a list | ||
195 | of supported protocols by the client, which can be sent over the websocket. | ||
196 | |||
197 | @item | ||
198 | A @code{Sec-WebSocket-Extensions} header field which may contain extensions | ||
199 | to the websocket protocol. The extensions must be registered by IANA. | ||
200 | |||
201 | @end itemize | ||
202 | |||
203 | |||
204 | A valid example request from the client could look like this: | ||
205 | |||
206 | |||
207 | @verbatim | ||
208 | GET /chat HTTP/1.1 | ||
209 | Host: server.example.com | ||
210 | Upgrade: websocket | ||
211 | Connection: Upgrade | ||
212 | Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ== | ||
213 | Sec-WebSocket-Version: 13 | ||
214 | @end verbatim | ||
215 | @noindent | ||
216 | |||
217 | |||
218 | To complete the handshake the server must respond with | ||
219 | some specific response headers: | ||
220 | |||
221 | @itemize @bullet | ||
222 | @item | ||
223 | The HTTP response code @code{101 Switching Protocols} must be answered. | ||
224 | |||
225 | @item | ||
226 | An @code{Upgrade} header field containing the value "websocket" must be sent. | ||
227 | |||
228 | @item | ||
229 | A @code{Connection} header field containing the value "Upgrade" must be sent. | ||
230 | |||
231 | @item | ||
232 | A @code{Sec-WebSocket-Accept} header field containing a value, which | ||
233 | has been calculated from the @code{Sec-WebSocket-Key} request header field, | ||
234 | must be sent. | ||
235 | |||
236 | @end itemize | ||
237 | |||
238 | |||
239 | Optionally the server may send following headers: | ||
240 | |||
241 | |||
242 | @itemize @bullet | ||
243 | @item | ||
244 | A @code{Sec-WebSocket-Protocol} header field containing a protocol | ||
245 | of the list specified in the corresponding request header field. | ||
246 | |||
247 | @item | ||
248 | A @code{Sec-WebSocket-Extension} header field containing all used extensions | ||
249 | of the list specified in the corresponding request header field. | ||
250 | |||
251 | @end itemize | ||
252 | |||
253 | |||
254 | A valid websocket HTTP response could look like this: | ||
255 | |||
256 | @verbatim | ||
257 | HTTP/1.1 101 Switching Protocols | ||
258 | Upgrade: websocket | ||
259 | Connection: Upgrade | ||
260 | Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo= | ||
261 | @end verbatim | ||
262 | @noindent | ||
263 | |||
264 | |||
265 | To upgrade a connection to a websocket the @emph{libmicrohttpd_ws} provides | ||
266 | some helper functions for the @code{access_handler} callback function: | ||
267 | |||
268 | @itemize @bullet | ||
269 | @item | ||
270 | @code{MHD_websocket_check_http_version()} checks whether the HTTP version | ||
271 | is 1.1 or above. | ||
272 | |||
273 | @item | ||
274 | @code{MHD_websocket_check_connection_header()} checks whether the value | ||
275 | of the @code{Connection} request header field contains | ||
276 | an "Upgrade" token (case-insensitive). | ||
277 | |||
278 | @item | ||
279 | @code{MHD_websocket_check_upgrade_header()} checks whether the value | ||
280 | of the @code{Upgrade} request header field contains | ||
281 | the "websocket" keyword (case-insensitive). | ||
282 | |||
283 | @item | ||
284 | @code{MHD_websocket_check_version_header()} checks whether the value | ||
285 | of the @code{Sec-WebSocket-Version} request header field is "13". | ||
286 | |||
287 | @item | ||
288 | @code{MHD_websocket_create_accept_header()} takes the value from | ||
289 | the @code{Sec-WebSocket-Key} request header and calculates the value | ||
290 | for the @code{Sec-WebSocket-Accept} response header field. | ||
291 | |||
292 | @end itemize | ||
293 | |||
294 | |||
295 | The @code{access_handler} example of the previous chapter can now be | ||
296 | extended with these helper functions to perform the websocket handshake: | ||
297 | |||
298 | @verbatim | ||
299 | static enum MHD_Result | ||
300 | access_handler (void *cls, | ||
301 | struct MHD_Connection *connection, | ||
302 | const char *url, | ||
303 | const char *method, | ||
304 | const char *version, | ||
305 | const char *upload_data, | ||
306 | size_t *upload_data_size, | ||
307 | void **ptr) | ||
308 | { | ||
309 | static int aptr; | ||
310 | struct MHD_Response *response; | ||
311 | int ret; | ||
312 | |||
313 | (void) cls; /* Unused. Silent compiler warning. */ | ||
314 | (void) upload_data; /* Unused. Silent compiler warning. */ | ||
315 | (void) upload_data_size; /* Unused. Silent compiler warning. */ | ||
316 | |||
317 | if (0 != strcmp (method, "GET")) | ||
318 | return MHD_NO; /* unexpected method */ | ||
319 | if (&aptr != *ptr) | ||
320 | { | ||
321 | /* do never respond on first call */ | ||
322 | *ptr = &aptr; | ||
323 | return MHD_YES; | ||
324 | } | ||
325 | *ptr = NULL; /* reset when done */ | ||
326 | |||
327 | if (0 == strcmp (url, "/")) | ||
328 | { | ||
329 | /* Default page for visiting the server */ | ||
330 | struct MHD_Response *response = MHD_create_response_from_buffer ( | ||
331 | strlen (PAGE), | ||
332 | PAGE, | ||
333 | MHD_RESPMEM_PERSISTENT); | ||
334 | ret = MHD_queue_response (connection, | ||
335 | MHD_HTTP_OK, | ||
336 | response); | ||
337 | MHD_destroy_response (response); | ||
338 | } | ||
339 | else if (0 == strcmp (url, "/chat")) | ||
340 | { | ||
341 | char is_valid = 1; | ||
342 | const char* value = NULL; | ||
343 | char sec_websocket_accept[29]; | ||
344 | |||
345 | if (0 != MHD_websocket_check_http_version (version)) | ||
346 | { | ||
347 | is_valid = 0; | ||
348 | } | ||
349 | value = MHD_lookup_connection_value (connection, | ||
350 | MHD_HEADER_KIND, | ||
351 | MHD_HTTP_HEADER_CONNECTION); | ||
352 | if (0 != MHD_websocket_check_connection_header (value)) | ||
353 | { | ||
354 | is_valid = 0; | ||
355 | } | ||
356 | value = MHD_lookup_connection_value (connection, | ||
357 | MHD_HEADER_KIND, | ||
358 | MHD_HTTP_HEADER_UPGRADE); | ||
359 | if (0 != MHD_websocket_check_upgrade_header (value)) | ||
360 | { | ||
361 | is_valid = 0; | ||
362 | } | ||
363 | value = MHD_lookup_connection_value (connection, | ||
364 | MHD_HEADER_KIND, | ||
365 | MHD_HTTP_HEADER_SEC_WEBSOCKET_VERSION); | ||
366 | if (0 != MHD_websocket_check_version_header (value)) | ||
367 | { | ||
368 | is_valid = 0; | ||
369 | } | ||
370 | value = MHD_lookup_connection_value (connection, | ||
371 | MHD_HEADER_KIND, | ||
372 | MHD_HTTP_HEADER_SEC_WEBSOCKET_KEY); | ||
373 | if (0 != MHD_websocket_create_accept_header (value, sec_websocket_accept)) | ||
374 | { | ||
375 | is_valid = 0; | ||
376 | } | ||
377 | |||
378 | if (1 == is_valid) | ||
379 | { | ||
380 | /* upgrade the connection */ | ||
381 | response = MHD_create_response_for_upgrade (&upgrade_handler, | ||
382 | NULL); | ||
383 | MHD_add_response_header (response, | ||
384 | MHD_HTTP_HEADER_CONNECTION, | ||
385 | "Upgrade"); | ||
386 | MHD_add_response_header (response, | ||
387 | MHD_HTTP_HEADER_UPGRADE, | ||
388 | "websocket"); | ||
389 | MHD_add_response_header (response, | ||
390 | MHD_HTTP_HEADER_SEC_WEBSOCKET_ACCEPT, | ||
391 | sec_websocket_accept); | ||
392 | ret = MHD_queue_response (connection, | ||
393 | MHD_HTTP_SWITCHING_PROTOCOLS, | ||
394 | response); | ||
395 | MHD_destroy_response (response); | ||
396 | } | ||
397 | else | ||
398 | { | ||
399 | /* return error page */ | ||
400 | struct MHD_Response*response = MHD_create_response_from_buffer ( | ||
401 | strlen (PAGE_INVALID_WEBSOCKET_REQUEST), | ||
402 | PAGE_INVALID_WEBSOCKET_REQUEST, | ||
403 | MHD_RESPMEM_PERSISTENT); | ||
404 | ret = MHD_queue_response (connection, | ||
405 | MHD_HTTP_BAD_REQUEST, | ||
406 | response); | ||
407 | MHD_destroy_response (response); | ||
408 | } | ||
409 | } | ||
410 | else | ||
411 | { | ||
412 | struct MHD_Response*response = MHD_create_response_from_buffer ( | ||
413 | strlen (PAGE_NOT_FOUND), | ||
414 | PAGE_NOT_FOUND, | ||
415 | MHD_RESPMEM_PERSISTENT); | ||
416 | ret = MHD_queue_response (connection, | ||
417 | MHD_HTTP_NOT_FOUND, | ||
418 | response); | ||
419 | MHD_destroy_response (response); | ||
420 | } | ||
421 | |||
422 | return ret; | ||
423 | } | ||
424 | @end verbatim | ||
425 | @noindent | ||
426 | |||
427 | Please note that we skipped the check of the Host header field here, | ||
428 | because we don't know the host for this example. | ||
429 | |||
430 | @heading Decoding/encoding the websocket protocol with libmicrohttpd_ws | ||
431 | |||
432 | Once the websocket connection is established you can receive/send frame data | ||
433 | with the low-level socket functions @code{recv()} and @code{send()}. | ||
434 | The frame data which goes over the low-level socket is encoded according | ||
435 | to the websocket protocol. | ||
436 | To use received payload data, you need to decode the frame data first. | ||
437 | To send payload data, you need to encode it into frame data first. | ||
438 | |||
439 | @emph{libmicrohttpd_ws} provides serveral functions for encoding of | ||
440 | payload data and decoding of frame data: | ||
441 | |||
442 | @itemize @bullet | ||
443 | @item | ||
444 | @code{MHD_websocket_decode()} decodes received frame data. | ||
445 | The payload data may be of any kind, depending upon what the client has sent. | ||
446 | So this decode function is used for all kind of frames and returns | ||
447 | the frame type along with the payload data. | ||
448 | |||
449 | @item | ||
450 | @code{MHD_websocket_encode_text()} encodes text. | ||
451 | The text must be encoded with UTF-8. | ||
452 | |||
453 | @item | ||
454 | @code{MHD_websocket_encode_binary()} encodes binary data. | ||
455 | |||
456 | @item | ||
457 | @code{MHD_websocket_encode_ping()} encodes a ping request to | ||
458 | check whether the websocket is still valid and to test latency. | ||
459 | |||
460 | @item | ||
461 | @code{MHD_websocket_encode_ping()} encodes a pong response to | ||
462 | answer a received ping request. | ||
463 | |||
464 | @item | ||
465 | @code{MHD_websocket_encode_close()} encodes a close request. | ||
466 | |||
467 | @item | ||
468 | @code{MHD_websocket_free()} frees data returned by the encode/decode functions. | ||
469 | |||
470 | @end itemize | ||
471 | |||
472 | Since you could receive or send fragmented data (i. e. due to a too | ||
473 | small buffer passed to @code{recv}) all of these encode/decode | ||
474 | functions require a pointer to a @code{struct MHD_WebSocketStream} passed | ||
475 | as argument. | ||
476 | In this structure @emph{libmicrohttpd_ws} stores information | ||
477 | about encoding/decoding of the particular websocket. | ||
478 | For each websocket you need a unique @code{struct MHD_WebSocketStream} | ||
479 | to encode/decode with this library. | ||
480 | |||
481 | To create or destroy @code{struct MHD_WebSocketStream} | ||
482 | we have additional functions: | ||
483 | |||
484 | @itemize @bullet | ||
485 | @item | ||
486 | @code{MHD_websocket_stream_init()} allocates and initializes | ||
487 | a new @code{struct MHD_WebSocketStream}. | ||
488 | You can specify some options here to alter the behavior of the websocket stream. | ||
489 | |||
490 | @item | ||
491 | @code{MHD_websocket_stream_free()} frees a previously allocated | ||
492 | @code{struct MHD_WebSocketStream}. | ||
493 | |||
494 | @end itemize | ||
495 | |||
496 | With these encode/decode functions we can improve our @code{upgrade_handler} | ||
497 | callback function from an earlier example to a working websocket: | ||
498 | |||
499 | |||
500 | @verbatim | ||
501 | static void | ||
502 | upgrade_handler (void *cls, | ||
503 | struct MHD_Connection *connection, | ||
504 | void *con_cls, | ||
505 | const char *extra_in, | ||
506 | size_t extra_in_size, | ||
507 | MHD_socket fd, | ||
508 | struct MHD_UpgradeResponseHandle *urh) | ||
509 | { | ||
510 | /* make the socket blocking (operating-system-dependent code) */ | ||
511 | make_blocking (fd); | ||
512 | |||
513 | /* create a websocket stream for this connection */ | ||
514 | struct MHD_WebSocketStream* ws; | ||
515 | int result = MHD_websocket_stream_init (&ws, | ||
516 | 0, | ||
517 | 0); | ||
518 | if (0 != result) | ||
519 | { | ||
520 | /* Couldn't create the websocket stream. | ||
521 | * So we close the socket and leave | ||
522 | */ | ||
523 | MHD_upgrade_action (urh, | ||
524 | MHD_UPGRADE_ACTION_CLOSE); | ||
525 | return; | ||
526 | } | ||
527 | |||
528 | /* Let's wait for incoming data */ | ||
529 | const size_t buf_len = 256; | ||
530 | char buf[buf_len]; | ||
531 | ssize_t got; | ||
532 | while (MHD_WEBSOCKET_VALIDITY_VALID == MHD_websocket_stream_is_valid (ws)) | ||
533 | { | ||
534 | got = recv (fd, | ||
535 | buf, | ||
536 | buf_len, | ||
537 | 0); | ||
538 | if (0 >= got) | ||
539 | { | ||
540 | /* the TCP/IP socket has been closed */ | ||
541 | break; | ||
542 | } | ||
543 | |||
544 | /* parse the entire received data */ | ||
545 | size_t buf_offset = 0; | ||
546 | while (buf_offset < (size_t) got) | ||
547 | { | ||
548 | size_t new_offset = 0; | ||
549 | char *frame_data = NULL; | ||
550 | size_t frame_len = 0; | ||
551 | int status = MHD_websocket_decode (ws, | ||
552 | buf + buf_offset, | ||
553 | ((size_t) got) - buf_offset, | ||
554 | &new_offset, | ||
555 | &frame_data, | ||
556 | &frame_len); | ||
557 | if (0 > status) | ||
558 | { | ||
559 | /* an error occurred and the connection must be closed */ | ||
560 | if (NULL != frame_data) | ||
561 | { | ||
562 | MHD_websocket_free (ws, frame_data); | ||
563 | } | ||
564 | break; | ||
565 | } | ||
566 | else | ||
567 | { | ||
568 | buf_offset += new_offset; | ||
569 | if (0 < status) | ||
570 | { | ||
571 | /* the frame is complete */ | ||
572 | switch (status) | ||
573 | { | ||
574 | case MHD_WEBSOCKET_STATUS_TEXT_FRAME: | ||
575 | /* The client has sent some text. | ||
576 | * We will display it and answer with a text frame. | ||
577 | */ | ||
578 | if (NULL != frame_data) | ||
579 | { | ||
580 | printf ("Received message: %s\n", frame_data); | ||
581 | MHD_websocket_free (ws, frame_data); | ||
582 | frame_data = NULL; | ||
583 | } | ||
584 | result = MHD_websocket_encode_text (ws, | ||
585 | "Hello", | ||
586 | 5, /* length of "Hello" */ | ||
587 | 0, | ||
588 | &frame_data, | ||
589 | &frame_len, | ||
590 | NULL); | ||
591 | if (0 == result) | ||
592 | { | ||
593 | send_all (fd, | ||
594 | frame_data, | ||
595 | frame_len); | ||
596 | } | ||
597 | break; | ||
598 | |||
599 | case MHD_WEBSOCKET_STATUS_CLOSE_FRAME: | ||
600 | /* if we receive a close frame, we will respond with one */ | ||
601 | MHD_websocket_free (ws, | ||
602 | frame_data); | ||
603 | frame_data = NULL; | ||
604 | |||
605 | result = MHD_websocket_encode_close (ws, | ||
606 | 0, | ||
607 | NULL, | ||
608 | 0, | ||
609 | &frame_data, | ||
610 | &frame_len); | ||
611 | if (0 == result) | ||
612 | { | ||
613 | send_all (fd, | ||
614 | frame_data, | ||
615 | frame_len); | ||
616 | } | ||
617 | break; | ||
618 | |||
619 | case MHD_WEBSOCKET_STATUS_PING_FRAME: | ||
620 | /* if we receive a ping frame, we will respond */ | ||
621 | /* with the corresponding pong frame */ | ||
622 | { | ||
623 | char *pong = NULL; | ||
624 | size_t pong_len = 0; | ||
625 | result = MHD_websocket_encode_pong (ws, | ||
626 | frame_data, | ||
627 | frame_len, | ||
628 | &pong, | ||
629 | &pong_len); | ||
630 | if (0 == result) | ||
631 | { | ||
632 | send_all (fd, | ||
633 | pong, | ||
634 | pong_len); | ||
635 | } | ||
636 | MHD_websocket_free (ws, | ||
637 | pong); | ||
638 | } | ||
639 | break; | ||
640 | |||
641 | default: | ||
642 | /* Other frame types are ignored | ||
643 | * in this minimal example. | ||
644 | * This is valid, because they become | ||
645 | * automatically skipped if we receive them unexpectedly | ||
646 | */ | ||
647 | break; | ||
648 | } | ||
649 | } | ||
650 | if (NULL != frame_data) | ||
651 | { | ||
652 | MHD_websocket_free (ws, frame_data); | ||
653 | } | ||
654 | } | ||
655 | } | ||
656 | } | ||
657 | |||
658 | /* free the websocket stream */ | ||
659 | MHD_websocket_stream_free (ws); | ||
660 | |||
661 | /* close the socket when it is not needed anymore */ | ||
662 | MHD_upgrade_action (urh, | ||
663 | MHD_UPGRADE_ACTION_CLOSE); | ||
664 | } | ||
665 | |||
666 | /* This helper function is used for the case that | ||
667 | * we need to resend some data | ||
668 | */ | ||
669 | static void | ||
670 | send_all (MHD_socket fd, | ||
671 | const char *buf, | ||
672 | size_t len) | ||
673 | { | ||
674 | ssize_t ret; | ||
675 | size_t off; | ||
676 | |||
677 | for (off = 0; off < len; off += ret) | ||
678 | { | ||
679 | ret = send (fd, | ||
680 | &buf[off], | ||
681 | (int) (len - off), | ||
682 | 0); | ||
683 | if (0 > ret) | ||
684 | { | ||
685 | if (EAGAIN == errno) | ||
686 | { | ||
687 | ret = 0; | ||
688 | continue; | ||
689 | } | ||
690 | break; | ||
691 | } | ||
692 | if (0 == ret) | ||
693 | break; | ||
694 | } | ||
695 | } | ||
696 | |||
697 | /* This helper function contains operating-system-dependent code and | ||
698 | * is used to make a socket blocking. | ||
699 | */ | ||
700 | static void | ||
701 | make_blocking (MHD_socket fd) | ||
702 | { | ||
703 | #if defined(MHD_POSIX_SOCKETS) | ||
704 | int flags; | ||
705 | |||
706 | flags = fcntl (fd, F_GETFL); | ||
707 | if (-1 == flags) | ||
708 | return; | ||
709 | if ((flags & ~O_NONBLOCK) != flags) | ||
710 | if (-1 == fcntl (fd, F_SETFL, flags & ~O_NONBLOCK)) | ||
711 | abort (); | ||
712 | #elif defined(MHD_WINSOCK_SOCKETS) | ||
713 | unsigned long flags = 0; | ||
714 | |||
715 | ioctlsocket (fd, FIONBIO, &flags); | ||
716 | #endif /* MHD_WINSOCK_SOCKETS */ | ||
717 | } | ||
718 | |||
719 | @end verbatim | ||
720 | @noindent | ||
721 | |||
722 | |||
723 | Please note that the websocket in this example is only half-duplex. | ||
724 | It waits until the blocking @code{recv()} call returns and | ||
725 | only does then something. | ||
726 | In this example all frame types are decoded by @emph{libmicrohttpd_ws}, | ||
727 | but we only do something when a text, ping or close frame is received. | ||
728 | Binary and pong frames are ignored in our code. | ||
729 | This is legit, because the server is only required to implement at | ||
730 | least support for ping frame or close frame (the other frame types | ||
731 | could be skipped in theory, because they don't require an answer). | ||
732 | The pong frame doesn't require an answer and whether text frames or | ||
733 | binary frames get an answer simply belongs to your server application. | ||
734 | So this is a valid minimal example. | ||
735 | |||
736 | Until this point you've learned everything you need to basically | ||
737 | use websockets with @emph{libmicrohttpd} and @emph{libmicrohttpd_ws}. | ||
738 | These libraries offer much more functions for some specific cases. | ||
739 | |||
740 | |||
741 | The further chapters of this tutorial focus on some specific problems | ||
742 | and the client site programming. | ||
743 | |||
744 | |||
745 | @heading Using full-duplex websockets | ||
746 | |||
747 | To use full-duplex websockets you can simply create two threads | ||
748 | per websocket connection. | ||
749 | One of these threads is used for receiving data with | ||
750 | a blocking @code{recv()} call and the other thread is triggered | ||
751 | by the application internal codes and sends the data. | ||
752 | |||
753 | A full-duplex websocket example is implemented in the example file | ||
754 | @code{websocket_chatserver_example.c}. | ||
755 | |||
756 | @heading Error handling | ||
757 | |||
758 | The most functions of @emph{libmicrohttpd_ws} return a value | ||
759 | of @code{enum MHD_WEBSOCKET_STATUS}. | ||
760 | The values of this enumeration can be converted into an integer | ||
761 | and have an easy interpretation: | ||
762 | |||
763 | @itemize @bullet | ||
764 | @item | ||
765 | If the value is less than zero an error occurred and the call has failed. | ||
766 | Check the enumeration values for more specific information. | ||
767 | |||
768 | @item | ||
769 | If the value is equal to zero, the call succeeded. | ||
770 | |||
771 | @item | ||
772 | If the value is greater than zero, the call succeeded and the value | ||
773 | specifies the decoded frame type. | ||
774 | Currently positive values are only returned by @code{MHD_websocket_decode()} | ||
775 | (of the functions with this return enumeration type). | ||
776 | |||
777 | @end itemize | ||
778 | |||
779 | A websocket stream can also get broken when invalid frame data is received. | ||
780 | Also the other site could send a close frame which puts the stream into | ||
781 | a state where it may not be used for regular communication. | ||
782 | Whether a stream has become broken, can be checked with | ||
783 | @code{MHD_websocket_stream_is_valid()}. | ||
784 | |||
785 | |||
786 | @heading Fragmentation | ||
787 | |||
788 | In addition to the regular TCP/IP fragmentation the websocket protocol also | ||
789 | supports fragmentation. | ||
790 | Fragmentation could be used for continuous payload data such as video data | ||
791 | from a webcam. | ||
792 | Whether or not you want to receive fragmentation is specified upon | ||
793 | initialization of the websocket stream. | ||
794 | If you pass @code{MHD_WEBSOCKET_FLAG_WANT_FRAGMENTS} in the flags parameter | ||
795 | of @code{MHD_websocket_stream_init()} then you can receive fragments. | ||
796 | If you don't pass this flag (in the most cases you just pass zero as flags) | ||
797 | then you don't want to handle fragments on your own. | ||
798 | @emph{libmicrohttpd_ws} removes then the fragmentation for you | ||
799 | in the background. | ||
800 | You only get the completely assembled frames. | ||
801 | |||
802 | Upon encoding you specify whether or not you want to create a fragmented frame | ||
803 | by passing a flag to the corresponding encode function. | ||
804 | Only @code{MHD_websocket_encode_text()} and @code{MHD_websocket_encode_binary()} | ||
805 | can be used for fragmentation, because the other frame types may | ||
806 | not be fragmented. | ||
807 | Encoding fragmented frames is independent of | ||
808 | the @code{MHD_WEBSOCKET_FLAG_WANT_FRAGMENTS} flag upon initialization. | ||
809 | |||
810 | @heading Quick guide to websockets in JavaScript | ||
811 | |||
812 | Websockets are supported in all modern web browsers. | ||
813 | You initialize a websocket connection by creating an instance of | ||
814 | the @code{WebSocket} class provided by the web browser. | ||
815 | |||
816 | There are some simple rules for using websockets in the browser: | ||
817 | |||
818 | @itemize @bullet | ||
819 | @item | ||
820 | When you initialize the instance of the websocket class you must pass an URL. | ||
821 | The URL must either start with @code{ws://} | ||
822 | (for not encrypted websocket protocol) or @code{wss://} | ||
823 | (for TLS-encrypted websocket protocol). | ||
824 | |||
825 | @strong{IMPORTANT:} If your website is accessed via @code{https://} | ||
826 | then you are in a security context, which means that you are only allowed to | ||
827 | access other secure protocols. | ||
828 | So you can only use @code{wss://} for websocket connections then. | ||
829 | If you try to @code{ws://} instead then your websocket connection will | ||
830 | automatically fail. | ||
831 | |||
832 | @item | ||
833 | The WebSocket class uses events to handle the receiving of data. | ||
834 | JavaScript is per definition a single-threaded language so | ||
835 | the receiving events will never overlap. | ||
836 | Sending is done directly by calling a method of the instance of | ||
837 | the WebSocket class. | ||
838 | |||
839 | @end itemize | ||
840 | |||
841 | |||
842 | Here is a short example for receiving/sending data to the same host | ||
843 | as the website is running on: | ||
844 | |||
845 | @verbatim | ||
846 | <!DOCTYPE html> | ||
847 | <html> | ||
848 | <head> | ||
849 | <meta charset="UTF-8"> | ||
850 | <title>Websocket Demo</title> | ||
851 | <script> | ||
852 | |||
853 | let url = 'ws' + (window.location.protocol === 'https:' ? 's' : '') + '://' + | ||
854 | window.location.host + '/chat'; | ||
855 | let socket = null; | ||
856 | |||
857 | window.onload = function(event) { | ||
858 | socket = new WebSocket(url); | ||
859 | socket.onopen = function(event) { | ||
860 | document.write('The websocket connection has been established.<br>'); | ||
861 | |||
862 | // Send some text | ||
863 | socket.send('Hello from JavaScript!'); | ||
864 | } | ||
865 | |||
866 | socket.onclose = function(event) { | ||
867 | document.write('The websocket connection has been closed.<br>'); | ||
868 | } | ||
869 | |||
870 | socket.onerror = function(event) { | ||
871 | document.write('An error occurred during the websocket communication.<br>'); | ||
872 | } | ||
873 | |||
874 | socket.onmessage = function(event) { | ||
875 | document.write('Websocket message received: ' + event.data + '<br>'); | ||
876 | } | ||
877 | } | ||
878 | |||
879 | </script> | ||
880 | </head> | ||
881 | <body> | ||
882 | </body> | ||
883 | </html> | ||
884 | |||
885 | @end verbatim | ||
886 | @noindent | ||
diff --git a/doc/examples/websocket.c b/doc/examples/websocket.c new file mode 100644 index 00000000..39995479 --- /dev/null +++ b/doc/examples/websocket.c | |||
@@ -0,0 +1,446 @@ | |||
1 | /* Feel free to use this example code in any way | ||
2 | you see fit (Public Domain) */ | ||
3 | |||
4 | #include <sys/types.h> | ||
5 | #ifndef _WIN32 | ||
6 | #include <sys/select.h> | ||
7 | #include <sys/socket.h> | ||
8 | #include <fcntl.h> | ||
9 | #else | ||
10 | #include <winsock2.h> | ||
11 | #endif | ||
12 | #include <microhttpd.h> | ||
13 | #include <microhttpd_ws.h> | ||
14 | #include <time.h> | ||
15 | #include <string.h> | ||
16 | #include <stdlib.h> | ||
17 | #include <stdio.h> | ||
18 | #include <errno.h> | ||
19 | |||
20 | #define PORT 80 | ||
21 | |||
22 | #define PAGE \ | ||
23 | "<!DOCTYPE html>\n" \ | ||
24 | "<html>\n" \ | ||
25 | "<head>\n" \ | ||
26 | "<meta charset=\"UTF-8\">\n" \ | ||
27 | "<title>Websocket Demo</title>\n" \ | ||
28 | "<script>\n" \ | ||
29 | "\n" \ | ||
30 | "let url = 'ws' + (window.location.protocol === 'https:' ? 's' : '')" \ | ||
31 | " + '://' +\n" \ | ||
32 | " window.location.host + '/chat';\n" \ | ||
33 | "let socket = null;\n" \ | ||
34 | "\n" \ | ||
35 | "window.onload = function(event) {\n" \ | ||
36 | " socket = new WebSocket(url);\n" \ | ||
37 | " socket.onopen = function(event) {\n" \ | ||
38 | " document.write('The websocket connection has been " \ | ||
39 | "established.<br>');\n" \ | ||
40 | "\n" \ | ||
41 | " // Send some text\n" \ | ||
42 | " socket.send('Hello from JavaScript!');\n" \ | ||
43 | " }\n" \ | ||
44 | "\n" \ | ||
45 | " socket.onclose = function(event) {\n" \ | ||
46 | " document.write('The websocket connection has been closed.<br>');\n" \ | ||
47 | " }\n" \ | ||
48 | "\n" \ | ||
49 | " socket.onerror = function(event) {\n" \ | ||
50 | " document.write('An error occurred during the websocket " \ | ||
51 | "communication.<br>');\n" \ | ||
52 | " }\n" \ | ||
53 | "\n" \ | ||
54 | " socket.onmessage = function(event) {\n" \ | ||
55 | " document.write('Websocket message received: ' + " \ | ||
56 | "event.data + '<br>');\n" \ | ||
57 | " }\n" \ | ||
58 | "}\n" \ | ||
59 | "\n" \ | ||
60 | "</script>\n" \ | ||
61 | "</head>\n" \ | ||
62 | "<body>\n" \ | ||
63 | "</body>\n" \ | ||
64 | "</html>" | ||
65 | |||
66 | #define PAGE_NOT_FOUND \ | ||
67 | "404 Not Found" | ||
68 | |||
69 | #define PAGE_INVALID_WEBSOCKET_REQUEST \ | ||
70 | "Invalid WebSocket request!" | ||
71 | |||
72 | static void | ||
73 | send_all (MHD_socket fd, | ||
74 | const char *buf, | ||
75 | size_t len); | ||
76 | static void | ||
77 | make_blocking (MHD_socket fd); | ||
78 | |||
79 | static void | ||
80 | upgrade_handler (void *cls, | ||
81 | struct MHD_Connection *connection, | ||
82 | void *con_cls, | ||
83 | const char *extra_in, | ||
84 | size_t extra_in_size, | ||
85 | MHD_socket fd, | ||
86 | struct MHD_UpgradeResponseHandle *urh) | ||
87 | { | ||
88 | /* make the socket blocking (operating-system-dependent code) */ | ||
89 | make_blocking (fd); | ||
90 | |||
91 | /* create a websocket stream for this connection */ | ||
92 | struct MHD_WebSocketStream* ws; | ||
93 | int result = MHD_websocket_stream_init (&ws, | ||
94 | 0, | ||
95 | 0); | ||
96 | if (0 != result) | ||
97 | { | ||
98 | /* Couldn't create the websocket stream. | ||
99 | * So we close the socket and leave | ||
100 | */ | ||
101 | MHD_upgrade_action (urh, | ||
102 | MHD_UPGRADE_ACTION_CLOSE); | ||
103 | return; | ||
104 | } | ||
105 | |||
106 | /* Let's wait for incoming data */ | ||
107 | const size_t buf_len = 256; | ||
108 | char buf[buf_len]; | ||
109 | ssize_t got; | ||
110 | while (MHD_WEBSOCKET_VALIDITY_VALID == MHD_websocket_stream_is_valid (ws)) | ||
111 | { | ||
112 | got = recv (fd, | ||
113 | buf, | ||
114 | buf_len, | ||
115 | 0); | ||
116 | if (0 >= got) | ||
117 | { | ||
118 | /* the TCP/IP socket has been closed */ | ||
119 | break; | ||
120 | } | ||
121 | |||
122 | /* parse the entire received data */ | ||
123 | size_t buf_offset = 0; | ||
124 | while (buf_offset < (size_t) got) | ||
125 | { | ||
126 | size_t new_offset = 0; | ||
127 | char *frame_data = NULL; | ||
128 | size_t frame_len = 0; | ||
129 | int status = MHD_websocket_decode (ws, | ||
130 | buf + buf_offset, | ||
131 | ((size_t) got) - buf_offset, | ||
132 | &new_offset, | ||
133 | &frame_data, | ||
134 | &frame_len); | ||
135 | if (0 > status) | ||
136 | { | ||
137 | /* an error occurred and the connection must be closed */ | ||
138 | if (NULL != frame_data) | ||
139 | { | ||
140 | MHD_websocket_free (ws, frame_data); | ||
141 | } | ||
142 | break; | ||
143 | } | ||
144 | else | ||
145 | { | ||
146 | buf_offset += new_offset; | ||
147 | if (0 < status) | ||
148 | { | ||
149 | /* the frame is complete */ | ||
150 | switch (status) | ||
151 | { | ||
152 | case MHD_WEBSOCKET_STATUS_TEXT_FRAME: | ||
153 | /* The client has sent some text. | ||
154 | * We will display it and answer with a text frame. | ||
155 | */ | ||
156 | if (NULL != frame_data) | ||
157 | { | ||
158 | printf ("Received message: %s\n", frame_data); | ||
159 | MHD_websocket_free (ws, frame_data); | ||
160 | frame_data = NULL; | ||
161 | } | ||
162 | result = MHD_websocket_encode_text (ws, | ||
163 | "Hello", | ||
164 | 5, /* length of "Hello" */ | ||
165 | 0, | ||
166 | &frame_data, | ||
167 | &frame_len, | ||
168 | NULL); | ||
169 | if (0 == result) | ||
170 | { | ||
171 | send_all (fd, | ||
172 | frame_data, | ||
173 | frame_len); | ||
174 | } | ||
175 | break; | ||
176 | |||
177 | case MHD_WEBSOCKET_STATUS_CLOSE_FRAME: | ||
178 | /* if we receive a close frame, we will respond with one */ | ||
179 | MHD_websocket_free (ws, | ||
180 | frame_data); | ||
181 | frame_data = NULL; | ||
182 | |||
183 | result = MHD_websocket_encode_close (ws, | ||
184 | 0, | ||
185 | NULL, | ||
186 | 0, | ||
187 | &frame_data, | ||
188 | &frame_len); | ||
189 | if (0 == result) | ||
190 | { | ||
191 | send_all (fd, | ||
192 | frame_data, | ||
193 | frame_len); | ||
194 | } | ||
195 | break; | ||
196 | |||
197 | case MHD_WEBSOCKET_STATUS_PING_FRAME: | ||
198 | /* if we receive a ping frame, we will respond */ | ||
199 | /* with the corresponding pong frame */ | ||
200 | { | ||
201 | char *pong = NULL; | ||
202 | size_t pong_len = 0; | ||
203 | result = MHD_websocket_encode_pong (ws, | ||
204 | frame_data, | ||
205 | frame_len, | ||
206 | &pong, | ||
207 | &pong_len); | ||
208 | if (0 == result) | ||
209 | { | ||
210 | send_all (fd, | ||
211 | pong, | ||
212 | pong_len); | ||
213 | } | ||
214 | MHD_websocket_free (ws, | ||
215 | pong); | ||
216 | } | ||
217 | break; | ||
218 | |||
219 | default: | ||
220 | /* Other frame types are ignored | ||
221 | * in this minimal example. | ||
222 | * This is valid, because they become | ||
223 | * automatically skipped if we receive them unexpectedly | ||
224 | */ | ||
225 | break; | ||
226 | } | ||
227 | } | ||
228 | if (NULL != frame_data) | ||
229 | { | ||
230 | MHD_websocket_free (ws, frame_data); | ||
231 | } | ||
232 | } | ||
233 | } | ||
234 | } | ||
235 | |||
236 | /* free the websocket stream */ | ||
237 | MHD_websocket_stream_free (ws); | ||
238 | |||
239 | /* close the socket when it is not needed anymore */ | ||
240 | MHD_upgrade_action (urh, | ||
241 | MHD_UPGRADE_ACTION_CLOSE); | ||
242 | } | ||
243 | |||
244 | /* This helper function is used for the case that | ||
245 | * we need to resend some data | ||
246 | */ | ||
247 | static void | ||
248 | send_all (MHD_socket fd, | ||
249 | const char *buf, | ||
250 | size_t len) | ||
251 | { | ||
252 | ssize_t ret; | ||
253 | size_t off; | ||
254 | |||
255 | for (off = 0; off < len; off += ret) | ||
256 | { | ||
257 | ret = send (fd, | ||
258 | &buf[off], | ||
259 | (int) (len - off), | ||
260 | 0); | ||
261 | if (0 > ret) | ||
262 | { | ||
263 | if (EAGAIN == errno) | ||
264 | { | ||
265 | ret = 0; | ||
266 | continue; | ||
267 | } | ||
268 | break; | ||
269 | } | ||
270 | if (0 == ret) | ||
271 | break; | ||
272 | } | ||
273 | } | ||
274 | |||
275 | /* This helper function contains operating-system-dependent code and | ||
276 | * is used to make a socket blocking. | ||
277 | */ | ||
278 | static void | ||
279 | make_blocking (MHD_socket fd) | ||
280 | { | ||
281 | #ifndef _WIN32 | ||
282 | int flags; | ||
283 | |||
284 | flags = fcntl (fd, F_GETFL); | ||
285 | if (-1 == flags) | ||
286 | return; | ||
287 | if ((flags & ~O_NONBLOCK) != flags) | ||
288 | if (-1 == fcntl (fd, F_SETFL, flags & ~O_NONBLOCK)) | ||
289 | abort (); | ||
290 | #else | ||
291 | unsigned long flags = 0; | ||
292 | |||
293 | ioctlsocket (fd, FIONBIO, &flags); | ||
294 | #endif | ||
295 | } | ||
296 | |||
297 | static enum MHD_Result | ||
298 | access_handler (void *cls, | ||
299 | struct MHD_Connection *connection, | ||
300 | const char *url, | ||
301 | const char *method, | ||
302 | const char *version, | ||
303 | const char *upload_data, | ||
304 | size_t *upload_data_size, | ||
305 | void **ptr) | ||
306 | { | ||
307 | static int aptr; | ||
308 | struct MHD_Response *response; | ||
309 | int ret; | ||
310 | |||
311 | (void) cls; /* Unused. Silent compiler warning. */ | ||
312 | (void) upload_data; /* Unused. Silent compiler warning. */ | ||
313 | (void) upload_data_size; /* Unused. Silent compiler warning. */ | ||
314 | |||
315 | if (0 != strcmp (method, "GET")) | ||
316 | return MHD_NO; /* unexpected method */ | ||
317 | if (&aptr != *ptr) | ||
318 | { | ||
319 | /* do never respond on first call */ | ||
320 | *ptr = &aptr; | ||
321 | return MHD_YES; | ||
322 | } | ||
323 | *ptr = NULL; /* reset when done */ | ||
324 | |||
325 | if (0 == strcmp (url, "/")) | ||
326 | { | ||
327 | /* Default page for visiting the server */ | ||
328 | struct MHD_Response *response = MHD_create_response_from_buffer ( | ||
329 | strlen (PAGE), | ||
330 | PAGE, | ||
331 | MHD_RESPMEM_PERSISTENT); | ||
332 | ret = MHD_queue_response (connection, | ||
333 | MHD_HTTP_OK, | ||
334 | response); | ||
335 | MHD_destroy_response (response); | ||
336 | } | ||
337 | else if (0 == strcmp (url, "/chat")) | ||
338 | { | ||
339 | char is_valid = 1; | ||
340 | const char* value = NULL; | ||
341 | char sec_websocket_accept[29]; | ||
342 | |||
343 | if (0 != MHD_websocket_check_http_version (version)) | ||
344 | { | ||
345 | is_valid = 0; | ||
346 | } | ||
347 | value = MHD_lookup_connection_value (connection, | ||
348 | MHD_HEADER_KIND, | ||
349 | MHD_HTTP_HEADER_CONNECTION); | ||
350 | if (0 != MHD_websocket_check_connection_header (value)) | ||
351 | { | ||
352 | is_valid = 0; | ||
353 | } | ||
354 | value = MHD_lookup_connection_value (connection, | ||
355 | MHD_HEADER_KIND, | ||
356 | MHD_HTTP_HEADER_UPGRADE); | ||
357 | if (0 != MHD_websocket_check_upgrade_header (value)) | ||
358 | { | ||
359 | is_valid = 0; | ||
360 | } | ||
361 | value = MHD_lookup_connection_value (connection, | ||
362 | MHD_HEADER_KIND, | ||
363 | MHD_HTTP_HEADER_SEC_WEBSOCKET_VERSION); | ||
364 | if (0 != MHD_websocket_check_version_header (value)) | ||
365 | { | ||
366 | is_valid = 0; | ||
367 | } | ||
368 | value = MHD_lookup_connection_value (connection, | ||
369 | MHD_HEADER_KIND, | ||
370 | MHD_HTTP_HEADER_SEC_WEBSOCKET_KEY); | ||
371 | if (0 != MHD_websocket_create_accept_header (value, sec_websocket_accept)) | ||
372 | { | ||
373 | is_valid = 0; | ||
374 | } | ||
375 | |||
376 | if (1 == is_valid) | ||
377 | { | ||
378 | /* upgrade the connection */ | ||
379 | response = MHD_create_response_for_upgrade (&upgrade_handler, | ||
380 | NULL); | ||
381 | MHD_add_response_header (response, | ||
382 | MHD_HTTP_HEADER_CONNECTION, | ||
383 | "Upgrade"); | ||
384 | MHD_add_response_header (response, | ||
385 | MHD_HTTP_HEADER_UPGRADE, | ||
386 | "websocket"); | ||
387 | MHD_add_response_header (response, | ||
388 | MHD_HTTP_HEADER_SEC_WEBSOCKET_ACCEPT, | ||
389 | sec_websocket_accept); | ||
390 | ret = MHD_queue_response (connection, | ||
391 | MHD_HTTP_SWITCHING_PROTOCOLS, | ||
392 | response); | ||
393 | MHD_destroy_response (response); | ||
394 | } | ||
395 | else | ||
396 | { | ||
397 | /* return error page */ | ||
398 | struct MHD_Response*response = MHD_create_response_from_buffer ( | ||
399 | strlen (PAGE_INVALID_WEBSOCKET_REQUEST), | ||
400 | PAGE_INVALID_WEBSOCKET_REQUEST, | ||
401 | MHD_RESPMEM_PERSISTENT); | ||
402 | ret = MHD_queue_response (connection, | ||
403 | MHD_HTTP_BAD_REQUEST, | ||
404 | response); | ||
405 | MHD_destroy_response (response); | ||
406 | } | ||
407 | } | ||
408 | else | ||
409 | { | ||
410 | struct MHD_Response*response = MHD_create_response_from_buffer ( | ||
411 | strlen (PAGE_NOT_FOUND), | ||
412 | PAGE_NOT_FOUND, | ||
413 | MHD_RESPMEM_PERSISTENT); | ||
414 | ret = MHD_queue_response (connection, | ||
415 | MHD_HTTP_NOT_FOUND, | ||
416 | response); | ||
417 | MHD_destroy_response (response); | ||
418 | } | ||
419 | |||
420 | return ret; | ||
421 | } | ||
422 | |||
423 | int | ||
424 | main (int argc, | ||
425 | char *const *argv) | ||
426 | { | ||
427 | (void) argc; /* Unused. Silent compiler warning. */ | ||
428 | (void) argv; /* Unused. Silent compiler warning. */ | ||
429 | struct MHD_Daemon *daemon; | ||
430 | |||
431 | daemon = MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD | | ||
432 | MHD_USE_THREAD_PER_CONNECTION | | ||
433 | MHD_ALLOW_UPGRADE | | ||
434 | MHD_USE_ERROR_LOG, | ||
435 | PORT, NULL, NULL, | ||
436 | &access_handler, NULL, | ||
437 | MHD_OPTION_END); | ||
438 | |||
439 | if (NULL == daemon) | ||
440 | return 1; | ||
441 | (void) getc (stdin); | ||
442 | |||
443 | MHD_stop_daemon (daemon); | ||
444 | |||
445 | return 0; | ||
446 | } | ||
diff --git a/doc/libmicrohttpd-tutorial.texi b/doc/libmicrohttpd-tutorial.texi index de040fe8..7d3cd23a 100644 --- a/doc/libmicrohttpd-tutorial.texi +++ b/doc/libmicrohttpd-tutorial.texi | |||
@@ -68,6 +68,7 @@ Free Documentation License". | |||
68 | * Improved processing of POST data:: | 68 | * Improved processing of POST data:: |
69 | * Session management:: | 69 | * Session management:: |
70 | * Adding a layer of security:: | 70 | * Adding a layer of security:: |
71 | * Websockets:: | ||
71 | * Bibliography:: | 72 | * Bibliography:: |
72 | * License text:: | 73 | * License text:: |
73 | * Example programs:: | 74 | * Example programs:: |
@@ -109,6 +110,10 @@ Free Documentation License". | |||
109 | @chapter Adding a layer of security | 110 | @chapter Adding a layer of security |
110 | @include chapters/tlsauthentication.inc | 111 | @include chapters/tlsauthentication.inc |
111 | 112 | ||
113 | @node Websockets | ||
114 | @chapter Websockets | ||
115 | @include chapters/websocket.inc | ||
116 | |||
112 | @node Bibliography | 117 | @node Bibliography |
113 | @appendix Bibliography | 118 | @appendix Bibliography |
114 | @include chapters/bibliography.inc | 119 | @include chapters/bibliography.inc |
@@ -128,6 +133,7 @@ Free Documentation License". | |||
128 | * largepost.c:: | 133 | * largepost.c:: |
129 | * sessions.c:: | 134 | * sessions.c:: |
130 | * tlsauthentication.c:: | 135 | * tlsauthentication.c:: |
136 | * websocket.c:: | ||
131 | @end menu | 137 | @end menu |
132 | 138 | ||
133 | @node hellobrowser.c | 139 | @node hellobrowser.c |
@@ -178,4 +184,10 @@ Free Documentation License". | |||
178 | @verbatiminclude examples/tlsauthentication.c | 184 | @verbatiminclude examples/tlsauthentication.c |
179 | @end smalldisplay | 185 | @end smalldisplay |
180 | 186 | ||
187 | @node websocket.c | ||
188 | @section websocket.c | ||
189 | @smalldisplay | ||
190 | @verbatiminclude examples/websocket.c | ||
191 | @end smalldisplay | ||
192 | |||
181 | @bye | 193 | @bye |
diff --git a/doc/libmicrohttpd.texi b/doc/libmicrohttpd.texi index 8e275a3b..a6bd12eb 100644 --- a/doc/libmicrohttpd.texi +++ b/doc/libmicrohttpd.texi | |||
@@ -67,6 +67,7 @@ Free Documentation License". | |||
67 | * microhttpd-post:: Adding a @code{POST} processor. | 67 | * microhttpd-post:: Adding a @code{POST} processor. |
68 | * microhttpd-info:: Obtaining and modifying status information. | 68 | * microhttpd-info:: Obtaining and modifying status information. |
69 | * microhttpd-util:: Utilities. | 69 | * microhttpd-util:: Utilities. |
70 | * microhttpd-websocket:: Websockets. | ||
70 | 71 | ||
71 | Appendices | 72 | Appendices |
72 | 73 | ||
@@ -1246,6 +1247,493 @@ list. | |||
1246 | @end deftp | 1247 | @end deftp |
1247 | 1248 | ||
1248 | 1249 | ||
1250 | @deftp {Enumeration} MHD_WEBSOCKET_FLAG | ||
1251 | @cindex websocket | ||
1252 | Options for the MHD websocket stream. | ||
1253 | |||
1254 | This is used for initialization of a websocket stream when calling | ||
1255 | @code{MHD_websocket_stream_init} or @code{MHD_websocket_stream_init2} and | ||
1256 | alters the behavior of the websocket stream. | ||
1257 | |||
1258 | Note that websocket streams are only available if you include the header file | ||
1259 | @code{microhttpd_ws.h} and compiled @emph{libmicrohttpd} with websockets. | ||
1260 | |||
1261 | @table @code | ||
1262 | @item MHD_WEBSOCKET_FLAG_SERVER | ||
1263 | The websocket stream is initialized in server mode (default). | ||
1264 | Thus all outgoing payload will not be masked. | ||
1265 | All incoming payload must be masked. | ||
1266 | |||
1267 | This flag cannot be used together with @code{MHD_WEBSOCKET_FLAG_CLIENT}. | ||
1268 | |||
1269 | @item MHD_WEBSOCKET_FLAG_CLIENT | ||
1270 | The websocket stream is initialized in client mode. | ||
1271 | You will usually never use that mode in combination with @emph{libmicrohttpd}, | ||
1272 | because @emph{libmicrohttpd} provides a server and not a client. | ||
1273 | In client mode all outgoing payload will be masked | ||
1274 | (XOR-ed with random values). | ||
1275 | All incoming payload must be unmasked. | ||
1276 | If you use this mode, you must always call @code{MHD_websocket_stream_init2} | ||
1277 | instead of @code{MHD_websocket_stream_init}, because you need | ||
1278 | to pass a random number generator callback function for masking. | ||
1279 | |||
1280 | This flag cannot be used together with @code{MHD_WEBSOCKET_FLAG_SERVER}. | ||
1281 | |||
1282 | @item MHD_WEBSOCKET_FLAG_NO_FRAGMENTS | ||
1283 | You don't want to get fragmented data while decoding (default). | ||
1284 | Fragmented frames will be internally put together until | ||
1285 | they are complete. | ||
1286 | Whether or not data is fragmented is decided | ||
1287 | by the sender of the data during encoding. | ||
1288 | |||
1289 | This cannot be used together with @code{MHD_WEBSOCKET_FLAG_WANT_FRAGMENTS}. | ||
1290 | |||
1291 | @item MHD_WEBSOCKET_FLAG_WANT_FRAGMENTS | ||
1292 | You want fragmented data, if it appears while decoding. | ||
1293 | You will receive the content of the fragmented frame, | ||
1294 | but if you are decoding text, you will never get an unfinished | ||
1295 | UTF-8 sequence (if the sequence appears between two fragments). | ||
1296 | Instead the text will end before the unfinished UTF-8 sequence. | ||
1297 | With the next fragment, which finishes the UTF-8 sequence, | ||
1298 | you will get the complete UTF-8 sequence. | ||
1299 | |||
1300 | This cannot be used together with @code{MHD_WEBSOCKET_FLAG_NO_FRAGMENTS}. | ||
1301 | |||
1302 | @item MHD_WEBSOCKET_FLAG_GENERATE_CLOSE_FRAMES_ON_ERROR | ||
1303 | If the websocket stream becomes invalid during decoding due to | ||
1304 | protocol errors, a matching close frame will automatically | ||
1305 | be generated. | ||
1306 | The close frame will be returned via the parameters | ||
1307 | @code{payload} and @code{payload_len} of @code{MHD_websocket_decode} and | ||
1308 | the return value is negative (a value of @code{enum MHD_WEBSOCKET_STATUS}). | ||
1309 | |||
1310 | The generated close frame must be freed by the caller | ||
1311 | with @code{MHD_websocket_free}. | ||
1312 | |||
1313 | @end table | ||
1314 | @end deftp | ||
1315 | |||
1316 | |||
1317 | @deftp {Enumeration} MHD_WEBSOCKET_FRAGMENTATION | ||
1318 | @cindex websocket | ||
1319 | This enumeration is used to specify the fragmentation behavior | ||
1320 | when encoding of data (text/binary) for a websocket stream. | ||
1321 | This is used with @code{MHD_websocket_encode_text} or | ||
1322 | @code{MHD_websocket_encode_binary}. | ||
1323 | |||
1324 | Note that websocket streams are only available if you include the header file | ||
1325 | @code{microhttpd_ws.h} and compiled @emph{libmicrohttpd} with websockets. | ||
1326 | |||
1327 | @table @code | ||
1328 | @item MHD_WEBSOCKET_FRAGMENTATION_NONE | ||
1329 | You don't want to use fragmentation. | ||
1330 | The encoded frame consists of only one frame. | ||
1331 | |||
1332 | @item MHD_WEBSOCKET_FRAGMENTATION_FIRST | ||
1333 | You want to use fragmentation. | ||
1334 | The encoded frame is the first frame of | ||
1335 | a series of data frames of the same type | ||
1336 | (text or binary). | ||
1337 | You may send control frames (ping, pong or close) | ||
1338 | between these data frames. | ||
1339 | |||
1340 | @item MHD_WEBSOCKET_FRAGMENTATION_FOLLOWING | ||
1341 | You want to use fragmentation. | ||
1342 | The encoded frame is not the first frame of | ||
1343 | the series of data frames, but also not the last one. | ||
1344 | You may send control frames (ping, pong or close) | ||
1345 | between these data frames. | ||
1346 | |||
1347 | @item MHD_WEBSOCKET_FRAGMENTATION_LAST | ||
1348 | You want to use fragmentation. | ||
1349 | The encoded frame is the last frame of | ||
1350 | the series of data frames, but also not the first one. | ||
1351 | After this frame, you may send all types of frames again. | ||
1352 | |||
1353 | @end table | ||
1354 | @end deftp | ||
1355 | |||
1356 | |||
1357 | @deftp {Enumeration} MHD_WEBSOCKET_STATUS | ||
1358 | @cindex websocket | ||
1359 | This enumeration is used for the return value of almost | ||
1360 | every websocket stream function. | ||
1361 | Errors are negative and values equal to or above zero mean a success. | ||
1362 | Positive values are only used by @code{MHD_websocket_decode}. | ||
1363 | |||
1364 | Note that websocket streams are only available if you include the header file | ||
1365 | @code{microhttpd_ws.h} and compiled @emph{libmicrohttpd} with websockets. | ||
1366 | |||
1367 | @table @code | ||
1368 | @item MHD_WEBSOCKET_STATUS_OK | ||
1369 | The call succeeded. | ||
1370 | Especially for @code{MHD_websocket_decode} this means that no error occurred, | ||
1371 | but also no frame has been completed yet. | ||
1372 | For other functions this means simply a success. | ||
1373 | |||
1374 | @item MHD_WEBSOCKET_STATUS_TEXT_FRAME | ||
1375 | @code{MHD_websocket_decode} has decoded a text frame. | ||
1376 | The parameters @code{payload} and @code{payload_len} are filled with | ||
1377 | the decoded text (if any). | ||
1378 | You must free the returned @code{payload} after use with | ||
1379 | @code{MHD_websocket_free}. | ||
1380 | |||
1381 | @item MHD_WEBSOCKET_STATUS_BINARY_FRAME | ||
1382 | @code{MHD_websocket_decode} has decoded a binary frame. | ||
1383 | The parameters @code{payload} and @code{payload_len} are filled with | ||
1384 | the decoded binary data (if any). | ||
1385 | You must free the returned @code{payload} after use with | ||
1386 | @code{MHD_websocket_free}. | ||
1387 | |||
1388 | @item MHD_WEBSOCKET_STATUS_CLOSE_FRAME | ||
1389 | @code{MHD_websocket_decode} has decoded a close frame. | ||
1390 | This means you must close the socket using @code{MHD_upgrade_action} | ||
1391 | with @code{MHD_UPGRADE_ACTION_CLOSE}. | ||
1392 | You may respond with a close frame before closing. | ||
1393 | The parameters @code{payload} and @code{payload_len} are filled with | ||
1394 | the close reason (if any). | ||
1395 | The close reason starts with a two byte sequence of close code | ||
1396 | in network byte order (see @code{enum MHD_WEBSOCKET_CLOSEREASON}). | ||
1397 | After these two bytes a UTF-8 encoded close reason may follow. | ||
1398 | You can call @code{MHD_websocket_split_close_reason} to split that | ||
1399 | close reason. | ||
1400 | You must free the returned @code{payload} after use with | ||
1401 | @code{MHD_websocket_free}. | ||
1402 | |||
1403 | @item MHD_WEBSOCKET_STATUS_PING_FRAME | ||
1404 | @code{MHD_websocket_decode} has decoded a ping frame. | ||
1405 | You should respond to this with a pong frame. | ||
1406 | The pong frame must contain the same binary data as | ||
1407 | the corresponding ping frame (if it had any). | ||
1408 | The parameters @code{payload} and @code{payload_len} are filled with | ||
1409 | the binary ping data (if any). | ||
1410 | You must free the returned @code{payload} after use with | ||
1411 | @code{MHD_websocket_free}. | ||
1412 | |||
1413 | @item MHD_WEBSOCKET_STATUS_PONG_FRAME | ||
1414 | @code{MHD_websocket_decode} has decoded a pong frame. | ||
1415 | You should usually only receive pong frames if you sent | ||
1416 | a ping frame before. | ||
1417 | The binary data should be equal to your ping frame and can be | ||
1418 | used to distinguish the response if you sent multiple ping frames. | ||
1419 | The parameters @code{payload} and @code{payload_len} are filled with | ||
1420 | the binary pong data (if any). | ||
1421 | You must free the returned @code{payload} after use with | ||
1422 | @code{MHD_websocket_free}. | ||
1423 | |||
1424 | @item MHD_WEBSOCKET_STATUS_TEXT_FIRST_FRAGMENT | ||
1425 | @code{MHD_websocket_decode} has decoded a text frame fragment. | ||
1426 | The parameters @code{payload} and @code{payload_len} are filled with | ||
1427 | the decoded text (if any). | ||
1428 | This is like @code{MHD_WEBSOCKET_STATUS_TEXT_FRAME}, but it can only | ||
1429 | appear if you specified @code{MHD_WEBSOCKET_FLAG_WANT_FRAGMENTS} during | ||
1430 | the call of @code{MHD_websocket_stream_init} or | ||
1431 | @code{MHD_websocket_stream_init2}. | ||
1432 | You must free the returned @code{payload} after use with | ||
1433 | @code{MHD_websocket_free}. | ||
1434 | |||
1435 | @item MHD_WEBSOCKET_STATUS_TEXT_FIRST_FRAGMENT | ||
1436 | @code{MHD_websocket_decode} has decoded a binary frame fragment. | ||
1437 | The parameters @code{payload} and @code{payload_len} are filled with | ||
1438 | the decoded binary data (if any). | ||
1439 | This is like @code{MHD_WEBSOCKET_STATUS_BINARY_FRAME}, but it can only | ||
1440 | appear if you specified @code{MHD_WEBSOCKET_FLAG_WANT_FRAGMENTS} during | ||
1441 | the call of @code{MHD_websocket_stream_init} or | ||
1442 | @code{MHD_websocket_stream_init2}. | ||
1443 | You must free the returned @code{payload} after use with | ||
1444 | @code{MHD_websocket_free}. | ||
1445 | |||
1446 | @item MHD_WEBSOCKET_STATUS_TEXT_NEXT_FRAGMENT | ||
1447 | @code{MHD_websocket_decode} has decoded the next text frame fragment. | ||
1448 | The parameters @code{payload} and @code{payload_len} are filled with | ||
1449 | the decoded text (if any). | ||
1450 | This is like @code{MHD_WEBSOCKET_STATUS_TEXT_FIRST_FRAGMENT}, but it appears | ||
1451 | only after the first and before the last fragment of a series of fragments. | ||
1452 | It can only appear if you specified @code{MHD_WEBSOCKET_FLAG_WANT_FRAGMENTS} | ||
1453 | during the call of @code{MHD_websocket_stream_init} or | ||
1454 | @code{MHD_websocket_stream_init2}. | ||
1455 | You must free the returned @code{payload} after use with | ||
1456 | @code{MHD_websocket_free}. | ||
1457 | |||
1458 | @item MHD_WEBSOCKET_STATUS_BINARY_NEXT_FRAGMENT | ||
1459 | @code{MHD_websocket_decode} has decoded the next binary frame fragment. | ||
1460 | The parameters @code{payload} and @code{payload_len} are filled with | ||
1461 | the decoded binary data (if any). | ||
1462 | This is like @code{MHD_WEBSOCKET_STATUS_BINARY_FIRST_FRAGMENT}, but it appears | ||
1463 | only after the first and before the last fragment of a series of fragments. | ||
1464 | It can only appear if you specified @code{MHD_WEBSOCKET_FLAG_WANT_FRAGMENTS} | ||
1465 | during the call of @code{MHD_websocket_stream_init} or | ||
1466 | @code{MHD_websocket_stream_init2}. | ||
1467 | You must free the returned @code{payload} after use with | ||
1468 | @code{MHD_websocket_free}. | ||
1469 | |||
1470 | @item MHD_WEBSOCKET_STATUS_TEXT_LAST_FRAGMENT | ||
1471 | @code{MHD_websocket_decode} has decoded the last text frame fragment. | ||
1472 | The parameters @code{payload} and @code{payload_len} are filled with | ||
1473 | the decoded text (if any). | ||
1474 | This is like @code{MHD_WEBSOCKET_STATUS_TEXT_FIRST_FRAGMENT}, but it appears | ||
1475 | only for the last fragment of a series of fragments. | ||
1476 | It can only appear if you specified @code{MHD_WEBSOCKET_FLAG_WANT_FRAGMENTS} | ||
1477 | during the call of @code{MHD_websocket_stream_init} or | ||
1478 | @code{MHD_websocket_stream_init2}. | ||
1479 | You must free the returned @code{payload} after use with | ||
1480 | @code{MHD_websocket_free}. | ||
1481 | |||
1482 | @item MHD_WEBSOCKET_STATUS_BINARY_LAST_FRAGMENT | ||
1483 | @code{MHD_websocket_decode} has decoded the last binary frame fragment. | ||
1484 | The parameters @code{payload} and @code{payload_len} are filled with | ||
1485 | the decoded binary data (if any). | ||
1486 | This is like @code{MHD_WEBSOCKET_STATUS_BINARY_FIRST_FRAGMENT}, but it appears | ||
1487 | only for the last fragment of a series of fragments. | ||
1488 | It can only appear if you specified @code{MHD_WEBSOCKET_FLAG_WANT_FRAGMENTS} | ||
1489 | during the call of @code{MHD_websocket_stream_init} or | ||
1490 | @code{MHD_websocket_stream_init2}. | ||
1491 | You must free the returned @code{payload} after use with | ||
1492 | @code{MHD_websocket_free}. | ||
1493 | |||
1494 | @item MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR | ||
1495 | The call failed and the stream is invalid now for decoding. | ||
1496 | You must close the websocket now using @code{MHD_upgrade_action} | ||
1497 | with @code{MHD_UPGRADE_ACTION_CLOSE}. | ||
1498 | You may send a close frame before closing. | ||
1499 | This is only used by @code{MHD_websocket_decode} and happens | ||
1500 | if the stream contains errors (i. e. invalid byte data). | ||
1501 | |||
1502 | @item MHD_WEBSOCKET_STATUS_STREAM_BROKEN | ||
1503 | You tried to decode something, but the stream has already | ||
1504 | been marked invalid. | ||
1505 | You must close the websocket now using @code{MHD_upgrade_action} | ||
1506 | with @code{MHD_UPGRADE_ACTION_CLOSE}. | ||
1507 | You may send a close frame before closing. | ||
1508 | This is only used by @code{MHD_websocket_decode} and happens | ||
1509 | if you call @code{MDM_websocket_decode} again after | ||
1510 | has been invalidated. | ||
1511 | You can call @code{MHD_websocket_stream_is_valid} at any time | ||
1512 | to check whether a stream is invalid or not. | ||
1513 | |||
1514 | @item MHD_WEBSOCKET_STATUS_MEMORY_ERROR | ||
1515 | A memory allocation failed. The stream remains valid. | ||
1516 | If this occurred while decoding, the decoding could be | ||
1517 | possible later if enough memory is available. | ||
1518 | This could happen while decoding if you received a too big data frame. | ||
1519 | You could try to specify max_payload_size during the call of | ||
1520 | @code{MHD_websocket_stream_init} or @code{MHD_websocket_stream_init2} to | ||
1521 | avoid this and close the websocket instead. | ||
1522 | |||
1523 | @item MHD_WEBSOCKET_STATUS_PARAMETER_ERROR | ||
1524 | You passed invalid parameters during the function call | ||
1525 | (i. e. a NULL pointer for a required parameter). | ||
1526 | The stream remains valid. | ||
1527 | |||
1528 | @item MHD_WEBSOCKET_STATUS_MAXIMUM_SIZE_EXCEEDED | ||
1529 | The maximum payload size has been exceeded. | ||
1530 | If you got this return code from @code{MHD_websocket_decode} then | ||
1531 | the stream becomes invalid and the websocket must be closed | ||
1532 | using @code{MHD_upgrade_action} with @code{MHD_UPGRADE_ACTION_CLOSE}. | ||
1533 | You may send a close frame before closing. | ||
1534 | The maximum payload size is specified during the call of | ||
1535 | @code{MHD_websocket_stream_init} or @code{MHD_websocket_stream_init2}. | ||
1536 | This can also appear if you specified 0 as maximum payload size | ||
1537 | when the message is greater than the maximum allocatable memory size | ||
1538 | (i. e. more than 4 GiB on 32 bit systems). | ||
1539 | If you got this return code from @code{MHD_websocket_encode_close}, | ||
1540 | @code{MHD_websocket_encode_ping} or @code{MHD_websocket_encode_pong} then | ||
1541 | you passed to much payload data. The stream remains valid then. | ||
1542 | |||
1543 | @item MHD_WEBSOCKET_STATUS_UTF8_ENCODING_ERROR | ||
1544 | An UTF-8 sequence is invalid. | ||
1545 | If you got this return code from @code{MHD_websocket_decode} then | ||
1546 | the stream becomes invalid and you must close the websocket | ||
1547 | using @code{MHD_upgrade_action} with @code{MHD_UPGRADE_ACTION_CLOSE}. | ||
1548 | You may send a close frame before closing. | ||
1549 | If you got this from @code{MHD_websocket_encode_text} or | ||
1550 | @code{MHD_websocket_encode_close} then you passed invalid UTF-8 text. | ||
1551 | The stream remains valid then. | ||
1552 | |||
1553 | @item MHD_WEBSOCKET_STATUS_NO_WEBSOCKET_HANDSHAKE_HEADER | ||
1554 | A check routine for the HTTP headers came to the conclusion that | ||
1555 | the header value isn't valid for a websocket handshake request. | ||
1556 | This value can only be returned from the following functions: | ||
1557 | @code{MHD_websocket_check_http_version}, | ||
1558 | @code{MHD_websocket_check_connection_header}, | ||
1559 | @code{MHD_websocket_check_upgrade_header}, | ||
1560 | @code{MHD_websocket_check_version_header}, | ||
1561 | @code{MHD_websocket_create_accept_header} | ||
1562 | |||
1563 | @end table | ||
1564 | @end deftp | ||
1565 | |||
1566 | |||
1567 | @deftp {Enumeration} MHD_WEBSOCKET_CLOSEREASON | ||
1568 | @cindex websocket | ||
1569 | Enumeration of possible close reasons for websocket close frames. | ||
1570 | |||
1571 | The possible values are specified in RFC 6455 7.4.1 | ||
1572 | These close reasons here are the default set specified by RFC 6455, | ||
1573 | but also other close reasons could be used. | ||
1574 | |||
1575 | The definition is for short: | ||
1576 | @itemize @bullet | ||
1577 | @item 0-999 are never used (if you pass 0 in | ||
1578 | @code{MHD_websocket_encode_close} then no close reason is used). | ||
1579 | @item 1000-2999 are specified by RFC 6455. | ||
1580 | @item 3000-3999 are specified by libraries, etc. but must be registered by IANA. | ||
1581 | @item 4000-4999 are reserved for private use. | ||
1582 | @end itemize | ||
1583 | |||
1584 | Note that websocket streams are only available if you include the header file | ||
1585 | @code{microhttpd_ws.h} and compiled @emph{libmicrohttpd} with websockets. | ||
1586 | |||
1587 | @table @code | ||
1588 | @item MHD_WEBSOCKET_CLOSEREASON_NO_REASON | ||
1589 | This value is used as placeholder for @code{MHD_websocket_encode_close} | ||
1590 | to tell that you don't want to specify any reason. | ||
1591 | If you use this value then no reason text may be used. | ||
1592 | This value cannot be a result of decoding, because this value | ||
1593 | is not a valid close reason for the websocket protocol. | ||
1594 | |||
1595 | @item MHD_WEBSOCKET_CLOSEREASON_REGULAR | ||
1596 | You close the websocket because it fulfilled its purpose and shall | ||
1597 | now be closed in a normal, planned way. | ||
1598 | |||
1599 | @item MHD_WEBSOCKET_CLOSEREASON_GOING_AWAY | ||
1600 | You close the websocket because you are shutting down the server or | ||
1601 | something similar. | ||
1602 | |||
1603 | @item MHD_WEBSOCKET_CLOSEREASON_PROTOCOL_ERROR | ||
1604 | You close the websocket because a protocol error occurred | ||
1605 | during decoding (i. e. invalid byte data). | ||
1606 | |||
1607 | @item MHD_WEBSOCKET_CLOSEREASON_UNSUPPORTED_DATATYPE | ||
1608 | You close the websocket because you received data which you don't accept. | ||
1609 | For example if you received a binary frame, | ||
1610 | but your application only expects text frames. | ||
1611 | |||
1612 | @item MHD_WEBSOCKET_CLOSEREASON_MALFORMED_UTF8 | ||
1613 | You close the websocket because it contains malformed UTF-8. | ||
1614 | The UTF-8 validity is automatically checked by @code{MHD_websocket_decode}, | ||
1615 | so you don't need to check it on your own. | ||
1616 | UTF-8 is specified in RFC 3629. | ||
1617 | |||
1618 | @item MHD_WEBSOCKET_CLOSEREASON_POLICY_VIOLATED | ||
1619 | You close the websocket because you received a frame which is too big | ||
1620 | to process. | ||
1621 | You can specify the maximum allowed payload size during the call of | ||
1622 | @code{MHD_websocket_stream_init} or @code{MHD_websocket_stream_init2}. | ||
1623 | |||
1624 | @item MHD_WEBSOCKET_CLOSEREASON_MISSING_EXTENSION | ||
1625 | This status code can be sent by the client if it | ||
1626 | expected a specific extension, but this extension hasn't been negotiated. | ||
1627 | |||
1628 | @item MHD_WEBSOCKET_CLOSEREASON_UNEXPECTED_CONDITION | ||
1629 | The server closes the websocket because it encountered | ||
1630 | an unexpected condition that prevented it from fulfilling the request. | ||
1631 | |||
1632 | @end table | ||
1633 | @end deftp | ||
1634 | |||
1635 | |||
1636 | @deftp {Enumeration} MHD_WEBSOCKET_UTF8STEP | ||
1637 | @cindex websocket | ||
1638 | Enumeration of possible UTF-8 check steps for websocket functions | ||
1639 | |||
1640 | These values are used during the encoding of fragmented text frames | ||
1641 | or for error analysis while encoding text frames. | ||
1642 | Its values specify the next step of the UTF-8 check. | ||
1643 | UTF-8 sequences consist of one to four bytes. | ||
1644 | This enumeration just says how long the current UTF-8 sequence is | ||
1645 | and what is the next expected byte. | ||
1646 | |||
1647 | Note that websocket streams are only available if you include the header file | ||
1648 | @code{microhttpd_ws.h} and compiled @emph{libmicrohttpd} with websockets. | ||
1649 | |||
1650 | @table @code | ||
1651 | @item MHD_WEBSOCKET_UTF8STEP_NORMAL | ||
1652 | There is no open UTF-8 sequence. | ||
1653 | The next byte must be 0x00-0x7F or 0xC2-0xF4. | ||
1654 | |||
1655 | @item MHD_WEBSOCKET_UTF8STEP_UTF2TAIL_1OF1 | ||
1656 | The second byte of a two byte UTF-8 sequence. | ||
1657 | The first byte was 0xC2-0xDF. | ||
1658 | The next byte must be 0x80-0xBF. | ||
1659 | |||
1660 | @item MHD_WEBSOCKET_UTF8STEP_UTF3TAIL1_1OF2 | ||
1661 | The second byte of a three byte UTF-8 sequence. | ||
1662 | The first byte was 0xE0. | ||
1663 | The next byte must be 0xA0-0xBF. | ||
1664 | |||
1665 | @item MHD_WEBSOCKET_UTF8STEP_UTF3TAIL2_1OF2 | ||
1666 | The second byte of a three byte UTF-8 sequence. | ||
1667 | The first byte was 0xED. | ||
1668 | The next byte must by 0x80-0x9F. | ||
1669 | |||
1670 | @item MHD_WEBSOCKET_UTF8STEP_UTF3TAIL_1OF2 | ||
1671 | The second byte of a three byte UTF-8 sequence. | ||
1672 | The first byte was 0xE1-0xEC or 0xEE-0xEF. | ||
1673 | The next byte must be 0x80-0xBF. | ||
1674 | |||
1675 | @item MHD_WEBSOCKET_UTF8STEP_UTF3TAIL_2OF2 | ||
1676 | The third byte of a three byte UTF-8 sequence. | ||
1677 | The next byte must be 0x80-0xBF. | ||
1678 | |||
1679 | @item MHD_WEBSOCKET_UTF8STEP_UTF4TAIL1_1OF3 | ||
1680 | The second byte of a four byte UTF-8 sequence. | ||
1681 | The first byte was 0xF0. | ||
1682 | The next byte must be 0x90-0xBF. | ||
1683 | |||
1684 | @item MHD_WEBSOCKET_UTF8STEP_UTF4TAIL2_1OF3 | ||
1685 | The second byte of a four byte UTF-8 sequence. | ||
1686 | The first byte was 0xF4. | ||
1687 | The next byte must be 0x80-0x8F. | ||
1688 | |||
1689 | @item MHD_WEBSOCKET_UTF8STEP_UTF4TAIL_1OF3 | ||
1690 | The second byte of a four byte UTF-8 sequence. | ||
1691 | The first byte was 0xF1-0xF3. | ||
1692 | The next byte must be 0x80-0xBF. | ||
1693 | |||
1694 | @item MHD_WEBSOCKET_UTF8STEP_UTF4TAIL_2OF3 | ||
1695 | The third byte of a four byte UTF-8 sequence. | ||
1696 | The next byte must be 0x80-0xBF. | ||
1697 | |||
1698 | @item MHD_WEBSOCKET_UTF8STEP_UTF4TAIL_3OF3 | ||
1699 | The fourth byte of a four byte UTF-8 sequence. | ||
1700 | The next byte must be 0x80-0xBF. | ||
1701 | |||
1702 | @end table | ||
1703 | @end deftp | ||
1704 | |||
1705 | |||
1706 | @deftp {Enumeration} MHD_WEBSOCKET_VALIDITY | ||
1707 | @cindex websocket | ||
1708 | Enumeration of validity values of a websocket stream | ||
1709 | |||
1710 | These values are used for @code{MHD_websocket_stream_is_valid} | ||
1711 | and specify the validity status. | ||
1712 | |||
1713 | Note that websocket streams are only available if you include the header file | ||
1714 | @code{microhttpd_ws.h} and compiled @emph{libmicrohttpd} with websockets. | ||
1715 | |||
1716 | @table @code | ||
1717 | @item MHD_WEBSOCKET_VALIDITY_INVALID | ||
1718 | The stream is invalid. | ||
1719 | It cannot be used for decoding anymore. | ||
1720 | |||
1721 | @item MHD_WEBSOCKET_VALIDITY_VALID | ||
1722 | The stream is valid. | ||
1723 | Decoding works as expected. | ||
1724 | |||
1725 | @item MHD_WEBSOCKET_VALIDITY_ONLY_VALID_FOR_CONTROL_FRAMES | ||
1726 | The stream has received a close frame and | ||
1727 | is partly invalid. | ||
1728 | You can still use the stream for decoding, | ||
1729 | but if a data frame is received an error will be reported. | ||
1730 | After a close frame has been sent, no data frames | ||
1731 | may follow from the sender of the close frame. | ||
1732 | |||
1733 | @end table | ||
1734 | @end deftp | ||
1735 | |||
1736 | |||
1249 | @c ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | 1737 | @c ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
1250 | 1738 | ||
1251 | @c ------------------------------------------------------------ | 1739 | @c ------------------------------------------------------------ |
@@ -1291,6 +1779,12 @@ Information about an MHD daemon. | |||
1291 | @end deftp | 1779 | @end deftp |
1292 | 1780 | ||
1293 | 1781 | ||
1782 | @deftp {C Struct} MHD_WebSocketStream | ||
1783 | @cindex websocket | ||
1784 | Information about a MHD websocket stream. | ||
1785 | @end deftp | ||
1786 | |||
1787 | |||
1294 | @c ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | 1788 | @c ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
1295 | 1789 | ||
1296 | @c ------------------------------------------------------------ | 1790 | @c ------------------------------------------------------------ |
@@ -1549,6 +2043,95 @@ iteration. | |||
1549 | @end deftypefn | 2043 | @end deftypefn |
1550 | 2044 | ||
1551 | 2045 | ||
2046 | @deftypefn {Function Pointer} void* {*MHD_WebSocketMallocCallback} (size_t buf_len) | ||
2047 | @cindex websocket | ||
2048 | This callback function is used internally by many websocket functions | ||
2049 | for allocating data. | ||
2050 | By default @code{malloc} is used. | ||
2051 | You can use your own allocation function with @code{MHD_websocket_stream_init2} | ||
2052 | if you wish to. | ||
2053 | This can be useful for operating systems like Windows | ||
2054 | where @code{malloc}, @code{realloc} and @code{free} are compiler-dependent. | ||
2055 | You can call the associated @code{malloc} callback of | ||
2056 | a websocket stream with @code{MHD_websocket_malloc}. | ||
2057 | |||
2058 | @table @var | ||
2059 | @item buf_len | ||
2060 | size of the buffer to allocate in bytes. | ||
2061 | @end table | ||
2062 | |||
2063 | Return the pointer of the allocated buffer or @code{NULL} on failure. | ||
2064 | @end deftypefn | ||
2065 | |||
2066 | |||
2067 | @deftypefn {Function Pointer} void* {*MHD_WebSocketReallocCallback} (void *buf, size_t new_buf_len) | ||
2068 | @cindex websocket | ||
2069 | This callback function is used internally by many websocket | ||
2070 | functions for reallocating data. | ||
2071 | By default @code{realloc} is used. | ||
2072 | You can use your own reallocation function with | ||
2073 | @code{MHD_websocket_stream_init2} if you wish to. | ||
2074 | This can be useful for operating systems like Windows | ||
2075 | where @code{malloc}, @code{realloc} and @code{free} are compiler-dependent. | ||
2076 | You can call the associated @code{realloc} callback of | ||
2077 | a websocket stream with @code{MHD_websocket_realloc}. | ||
2078 | |||
2079 | @table @var | ||
2080 | @item buf | ||
2081 | current buffer, may be @code{NULL}; | ||
2082 | |||
2083 | @item new_buf_len | ||
2084 | new size of the buffer in bytes. | ||
2085 | @end table | ||
2086 | |||
2087 | Return the pointer of the reallocated buffer or @code{NULL} on failure. | ||
2088 | On failure the old pointer must remain valid. | ||
2089 | @end deftypefn | ||
2090 | |||
2091 | |||
2092 | @deftypefn {Function Pointer} void {*MHD_WebSocketFreeCallback} (void *buf) | ||
2093 | @cindex websocket | ||
2094 | This callback function is used internally by many websocket | ||
2095 | functions for freeing data. | ||
2096 | By default @code{free} is used. | ||
2097 | You can use your own free function with | ||
2098 | @code{MHD_websocket_stream_init2} if you wish to. | ||
2099 | This can be useful for operating systems like Windows | ||
2100 | where @code{malloc}, @code{realloc} and @code{free} are compiler-dependent. | ||
2101 | You can call the associated @code{free} callback of | ||
2102 | a websocket stream with @code{MHD_websocket_free}. | ||
2103 | |||
2104 | @table @var | ||
2105 | @item cls | ||
2106 | current buffer to free, this may be @code{NULL} then nothing happens. | ||
2107 | @end table | ||
2108 | @end deftypefn | ||
2109 | |||
2110 | |||
2111 | @deftypefn {Function Pointer} size_t {*MHD_WebSocketRandomNumberGenerator} (void *cls, void* buf, size_t buf_len) | ||
2112 | @cindex websocket | ||
2113 | This callback function is used for generating random numbers | ||
2114 | for masking payload data in client mode. | ||
2115 | If you use websockets in server mode with @emph{libmicrohttpd} then | ||
2116 | you don't need a random number generator, because | ||
2117 | the server doesn't mask its outgoing messages. | ||
2118 | However if you wish to use a websocket stream in client mode, | ||
2119 | you must pass this callback function to @code{MHD_websocket_stream_init2}. | ||
2120 | |||
2121 | @table @var | ||
2122 | @item cls | ||
2123 | closure specified in @code{MHD_websocket_stream_init2}; | ||
2124 | @item buf | ||
2125 | buffer to fill with random values; | ||
2126 | @item buf_len | ||
2127 | size of buffer in bytes. | ||
2128 | @end table | ||
2129 | |||
2130 | Return the number of generated random bytes. | ||
2131 | The return value should usually equal to buf_len. | ||
2132 | @end deftypefn | ||
2133 | |||
2134 | |||
1552 | @c ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | 2135 | @c ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
1553 | 2136 | ||
1554 | @c ------------------------------------------------------------ | 2137 | @c ------------------------------------------------------------ |
@@ -3346,6 +3929,704 @@ shorter afterwards due to elimination of escape sequences). | |||
3346 | 3929 | ||
3347 | 3930 | ||
3348 | 3931 | ||
3932 | |||
3933 | @c ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | ||
3934 | |||
3935 | @c ------------------------------------------------------------ | ||
3936 | @node microhttpd-websocket | ||
3937 | @chapter Websocket functions. | ||
3938 | |||
3939 | @noindent | ||
3940 | Websocket functions provide what you need to use an upgraded connection | ||
3941 | as a websocket. | ||
3942 | These functions are only available if you include the header file | ||
3943 | @code{microhttpd_ws.h} and compiled @emph{libmicrohttpd} with websockets. | ||
3944 | |||
3945 | @menu | ||
3946 | * microhttpd-websocket handshake:: Websocket handshake functions | ||
3947 | * microhttpd-websocket stream:: Websocket stream functions | ||
3948 | * microhttpd-websocket decode:: Websocket decode functions | ||
3949 | * microhttpd-websocket encode:: Websocket encode functions | ||
3950 | * microhttpd-websocket memory:: Websocket memory functions | ||
3951 | @end menu | ||
3952 | |||
3953 | @c ------------------------------------------------------------ | ||
3954 | @node microhttpd-websocket handshake | ||
3955 | @section Websocket handshake functions | ||
3956 | |||
3957 | |||
3958 | @deftypefun {enum MHD_WEBSOCKET_STATUS} MHD_websocket_check_http_version (const char* http_version) | ||
3959 | @cindex websocket | ||
3960 | Checks the HTTP version of the incoming request. | ||
3961 | Websocket requests are only allowed for HTTP/1.1 or above. | ||
3962 | |||
3963 | @table @var | ||
3964 | @item http_version | ||
3965 | The value of the @code{version} parameter of your | ||
3966 | @code{access_handler} callback. | ||
3967 | If you pass @code{NULL} then this is handled like a not | ||
3968 | matching HTTP version. | ||
3969 | @end table | ||
3970 | |||
3971 | Returns 0 when the HTTP version is | ||
3972 | valid for a websocket request and | ||
3973 | a value less than zero when the HTTP version isn't | ||
3974 | valid for a websocket request. | ||
3975 | Can be compared with @code{enum MHD_WEBSOCKET_STATUS}. | ||
3976 | @end deftypefun | ||
3977 | |||
3978 | |||
3979 | @deftypefun {enum MHD_WEBSOCKET_STATUS} MHD_websocket_check_connection_header (const char* connection_header) | ||
3980 | @cindex websocket | ||
3981 | Checks the value of the @code{Connection} HTTP request header. | ||
3982 | Websocket requests require the token @code{Upgrade} in | ||
3983 | the @code{Connection} HTTP request header. | ||
3984 | |||
3985 | @table @var | ||
3986 | @item connection_header | ||
3987 | Value of the @code{Connection} request header. | ||
3988 | You can get this request header value by passing | ||
3989 | @code{MHD_HTTP_HEADER_CONNECTION} to | ||
3990 | @code{MHD_lookup_connection_value()}. | ||
3991 | If you pass @code{NULL} then this is handled like a not | ||
3992 | matching @code{Connection} header value. | ||
3993 | @end table | ||
3994 | |||
3995 | Returns 0 when the @code{Connection} header is | ||
3996 | valid for a websocket request and | ||
3997 | a value less than zero when the @code{Connection} header isn't | ||
3998 | valid for a websocket request. | ||
3999 | Can be compared with @code{enum MHD_WEBSOCKET_STATUS}. | ||
4000 | @end deftypefun | ||
4001 | |||
4002 | |||
4003 | @deftypefun {enum MHD_WEBSOCKET_STATUS} MHD_websocket_check_upgrade_header (const char* upgrade_header) | ||
4004 | @cindex websocket | ||
4005 | Checks the value of the @code{Upgrade} HTTP request header. | ||
4006 | Websocket requests require the value @code{websocket} in | ||
4007 | the @code{Upgrade} HTTP request header. | ||
4008 | |||
4009 | @table @var | ||
4010 | @item upgrade_header | ||
4011 | Value of the @code{Upgrade} request header. | ||
4012 | You can get this request header value by passing | ||
4013 | @code{MHD_HTTP_HEADER_UPGRADE} to | ||
4014 | @code{MHD_lookup_connection_value()}. | ||
4015 | If you pass @code{NULL} then this is handled like a not | ||
4016 | matching @code{Upgrade} header value. | ||
4017 | @end table | ||
4018 | |||
4019 | Returns 0 when the @code{Upgrade} header is | ||
4020 | valid for a websocket request and | ||
4021 | a value less than zero when the @code{Upgrade} header isn't | ||
4022 | valid for a websocket request. | ||
4023 | Can be compared with @code{enum MHD_WEBSOCKET_STATUS}. | ||
4024 | @end deftypefun | ||
4025 | |||
4026 | |||
4027 | @deftypefun {enum MHD_WEBSOCKET_STATUS} MHD_websocket_check_version_header (const char* version_header) | ||
4028 | @cindex websocket | ||
4029 | Checks the value of the @code{Sec-WebSocket-Version} HTTP request header. | ||
4030 | Websocket requests require the value @code{13} in | ||
4031 | the @code{Sec-WebSocket-Version} HTTP request header. | ||
4032 | |||
4033 | @table @var | ||
4034 | @item version_header | ||
4035 | Value of the @code{Sec-WebSocket-Version} request header. | ||
4036 | You can get this request header value by passing | ||
4037 | @code{MHD_HTTP_HEADER_SEC_WEBSOCKET_VERSION} to | ||
4038 | @code{MHD_lookup_connection_value()}. | ||
4039 | If you pass @code{NULL} then this is handled like a not | ||
4040 | matching @code{Sec-WebSocket-Version} header value. | ||
4041 | @end table | ||
4042 | |||
4043 | Returns 0 when the @code{Sec-WebSocket-Version} header is | ||
4044 | valid for a websocket request and | ||
4045 | a value less than zero when the @code{Sec-WebSocket-Version} header isn't | ||
4046 | valid for a websocket request. | ||
4047 | Can be compared with @code{enum MHD_WEBSOCKET_STATUS}. | ||
4048 | @end deftypefun | ||
4049 | |||
4050 | |||
4051 | @deftypefun {enum MHD_WEBSOCKET_STATUS} MHD_websocket_create_accept_header (const char* sec_websocket_key, char* sec_websocket_accept) | ||
4052 | @cindex websocket | ||
4053 | Checks the value of the @code{Sec-WebSocket-Key} | ||
4054 | HTTP request header and generates the value for | ||
4055 | the @code{Sec-WebSocket-Accept} HTTP response header. | ||
4056 | The generated value must be sent to the client. | ||
4057 | |||
4058 | @table @var | ||
4059 | @item sec_websocket_key | ||
4060 | Value of the @code{Sec-WebSocket-Key} request header. | ||
4061 | You can get this request header value by passing | ||
4062 | @code{MHD_HTTP_HEADER_SEC_WEBSOCKET_KEY} to | ||
4063 | @code{MHD_lookup_connection_value()}. | ||
4064 | If you pass @code{NULL} then this is handled like a not | ||
4065 | matching @code{Sec-WebSocket-Key} header value. | ||
4066 | |||
4067 | @item sec_websocket_accept | ||
4068 | Response buffer, which will receive | ||
4069 | the generated value for the @code{Sec-WebSocket-Accept} | ||
4070 | HTTP response header. | ||
4071 | This buffer must be at least 29 bytes long and | ||
4072 | will contain the response value plus a terminating @code{NUL} | ||
4073 | character on success. | ||
4074 | Must not be @code{NULL}. | ||
4075 | You can add this HTTP header to your response by passing | ||
4076 | @code{MHD_HTTP_HEADER_SEC_WEBSOCKET_ACCEPT} to | ||
4077 | @code{MHD_add_response_header()}. | ||
4078 | @end table | ||
4079 | |||
4080 | Returns 0 when the @code{Sec-WebSocket-Key} header was | ||
4081 | not empty and a result value for the @code{Sec-WebSocket-Accept} | ||
4082 | was calculated. | ||
4083 | A value less than zero is returned when the @code{Sec-WebSocket-Key} | ||
4084 | header isn't valid for a websocket request or when any | ||
4085 | error occurred. | ||
4086 | Can be compared with @code{enum MHD_WEBSOCKET_STATUS}. | ||
4087 | @end deftypefun | ||
4088 | |||
4089 | |||
4090 | @c ------------------------------------------------------------ | ||
4091 | @node microhttpd-websocket stream | ||
4092 | @section Websocket stream functions | ||
4093 | |||
4094 | @deftypefun {enum MHD_WEBSOCKET_STATUS} MHD_websocket_stream_init (struct MHD_WebSocketStream **ws, int flags, size_t max_payload_size) | ||
4095 | @cindex websocket | ||
4096 | Creates a new websocket stream, used for decoding/encoding. | ||
4097 | |||
4098 | @table @var | ||
4099 | @item ws | ||
4100 | pointer a variable to fill with the newly created | ||
4101 | @code{struct MHD_WebSocketStream}, | ||
4102 | receives @code{NULL} on error. May not be @code{NULL}. | ||
4103 | |||
4104 | If not required anymore, free the created websocket stream with | ||
4105 | @code{MHD_websocket_stream_free()}. | ||
4106 | |||
4107 | @item flags | ||
4108 | combination of @code{enum MHD_WEBSOCKET_FLAG} values to | ||
4109 | modify the behavior of the websocket stream. | ||
4110 | |||
4111 | @item max_payload_size | ||
4112 | maximum size for incoming payload data in bytes. Use 0 to allow each size. | ||
4113 | @end table | ||
4114 | |||
4115 | Returns 0 on success, negative values on error. | ||
4116 | Can be compared with @code{enum MHD_WEBSOCKET_STATUS}. | ||
4117 | @end deftypefun | ||
4118 | |||
4119 | |||
4120 | @deftypefun {enum MHD_WEBSOCKET_STATUS} MHD_websocket_stream_init2 (struct MHD_WebSocketStream **ws, int flags, size_t max_payload_size, MHD_WebSocketMallocCallback callback_malloc, MHD_WebSocketReallocCallback callback_realloc, MHD_WebSocketFreeCallback callback_free, void* cls_rng, MHD_WebSocketRandomNumberGenerator callback_rng) | ||
4121 | @cindex websocket | ||
4122 | Creates a new websocket stream, used for decoding/encoding, | ||
4123 | but with custom memory functions for malloc, realloc and free. | ||
4124 | Also a random number generator can be specified for client mode. | ||
4125 | |||
4126 | @table @var | ||
4127 | @item ws | ||
4128 | pointer a variable to fill with the newly created | ||
4129 | @code{struct MHD_WebSocketStream}, | ||
4130 | receives @code{NULL} on error. Must not be @code{NULL}. | ||
4131 | |||
4132 | If not required anymore, free the created websocket stream with | ||
4133 | @code{MHD_websocket_stream_free}. | ||
4134 | |||
4135 | @item flags | ||
4136 | combination of @code{enum MHD_WEBSOCKET_FLAG} values to | ||
4137 | modify the behavior of the websocket stream. | ||
4138 | |||
4139 | @item max_payload_size | ||
4140 | maximum size for incoming payload data in bytes. Use 0 to allow each size. | ||
4141 | |||
4142 | @item callback_malloc | ||
4143 | callback function for allocating memory. Must not be @code{NULL}. | ||
4144 | The shorter @code{MHD_websocket_stream_init()} passes a reference to @code{malloc} here. | ||
4145 | |||
4146 | @item callback_realloc | ||
4147 | callback function for reallocating memory. Must not be @code{NULL}. | ||
4148 | The shorter @code{MHD_websocket_stream_init()} passes a reference to @code{realloc} here. | ||
4149 | |||
4150 | @item callback_free | ||
4151 | callback function for freeing memory. Must not be @code{NULL}. | ||
4152 | The shorter @code{MHD_websocket_stream_init()} passes a reference to @code{free} here. | ||
4153 | |||
4154 | @item cls_rng | ||
4155 | closure for the random number generator. | ||
4156 | This is only required when | ||
4157 | @code{MHD_WEBSOCKET_FLAG_CLIENT} is passed in @code{flags}. | ||
4158 | The given value is passed to the random number generator callback. | ||
4159 | May be @code{NULL} if not needed. | ||
4160 | Should be @code{NULL} when you are not using @code{MHD_WEBSOCKET_FLAG_CLIENT}. | ||
4161 | The shorter @code{MHD_websocket_stream_init} passes @code{NULL} here. | ||
4162 | |||
4163 | @item callback_rng | ||
4164 | callback function for a secure random number generator. | ||
4165 | This is only required when @code{MHD_WEBSOCKET_FLAG_CLIENT} is | ||
4166 | passed in @code{flags} and must not be @code{NULL} then. | ||
4167 | Should be @code{NULL} otherwise. | ||
4168 | The shorter @code{MHD_websocket_stream_init()} passes @code{NULL} here. | ||
4169 | @end table | ||
4170 | |||
4171 | Returns 0 on success, negative values on error. | ||
4172 | Can be compared with @code{enum MHD_WEBSOCKET_STATUS}. | ||
4173 | @end deftypefun | ||
4174 | |||
4175 | |||
4176 | @deftypefun {enum MHD_WEBSOCKET_STATUS} MHD_websocket_stream_free (struct MHD_WebSocketStream *ws) | ||
4177 | @cindex websocket | ||
4178 | Frees a previously allocated websocket stream | ||
4179 | |||
4180 | @table @var | ||
4181 | @item ws | ||
4182 | websocket stream to free, this value may be @code{NULL}. | ||
4183 | @end table | ||
4184 | |||
4185 | Returns 0 on success, negative values on error. | ||
4186 | Can be compared with @code{enum MHD_WEBSOCKET_STATUS}. | ||
4187 | @end deftypefun | ||
4188 | |||
4189 | |||
4190 | @deftypefun {enum MHD_WEBSOCKET_STATUS} MHD_websocket_stream_invalidate (struct MHD_WebSocketStream *ws) | ||
4191 | @cindex websocket | ||
4192 | Invalidates a websocket stream. | ||
4193 | After invalidation a websocket stream cannot be used for decoding anymore. | ||
4194 | Encoding is still possible. | ||
4195 | |||
4196 | @table @var | ||
4197 | @item ws | ||
4198 | websocket stream to invalidate. | ||
4199 | @end table | ||
4200 | |||
4201 | Returns 0 on success, negative values on error. | ||
4202 | Can be compared with @code{enum MHD_WEBSOCKET_STATUS}. | ||
4203 | @end deftypefun | ||
4204 | |||
4205 | |||
4206 | @deftypefun {enum MHD_WEBSOCKET_VALIDITY} MHD_websocket_stream_is_valid (struct MHD_WebSocketStream *ws) | ||
4207 | @cindex websocket | ||
4208 | Queries whether a websocket stream is valid. | ||
4209 | Invalidated websocket streams cannot be used for decoding anymore. | ||
4210 | Encoding is still possible. | ||
4211 | |||
4212 | @table @var | ||
4213 | @item ws | ||
4214 | websocket stream to invalidate. | ||
4215 | @end table | ||
4216 | |||
4217 | Returns 0 if invalid, 1 if valid for all types or | ||
4218 | 2 if valid only for control frames. | ||
4219 | Can be compared with @code{enum MHD_WEBSOCKET_VALIDITY}. | ||
4220 | @end deftypefun | ||
4221 | |||
4222 | |||
4223 | @c ------------------------------------------------------------ | ||
4224 | @node microhttpd-websocket decode | ||
4225 | @section Websocket decode functions | ||
4226 | |||
4227 | |||
4228 | @deftypefun {enum MHD_WEBSOCKET_STATUS} MHD_websocket_decode (struct MHD_WebSocketStream* ws, const char* streambuf, size_t streambuf_len, size_t* streambuf_read_len, char** payload, size_t* payload_len) | ||
4229 | @cindex websocket | ||
4230 | Decodes a byte sequence for a websocket stream. | ||
4231 | Decoding is done until either a frame is complete or | ||
4232 | the end of the byte sequence is reached. | ||
4233 | |||
4234 | @table @var | ||
4235 | @item ws | ||
4236 | websocket stream for decoding. | ||
4237 | |||
4238 | @item streambuf | ||
4239 | byte sequence for decoding. | ||
4240 | This is what you typically received via @code{recv()}. | ||
4241 | |||
4242 | @item streambuf_len | ||
4243 | length of the byte sequence in parameter @code{streambuf}. | ||
4244 | |||
4245 | @item streambuf_read_len | ||
4246 | pointer to a variable, which receives the number of bytes, | ||
4247 | that has been processed by this call. | ||
4248 | This value may be less than the value of @code{streambuf_len} when | ||
4249 | a frame is decoded before the end of the buffer is reached. | ||
4250 | The remaining bytes of @code{buf} must be passed to | ||
4251 | the next call of this function. | ||
4252 | |||
4253 | @item payload | ||
4254 | pointer to a variable, which receives the allocated buffer with the payload | ||
4255 | data of the decoded frame. Must not be @code{NULL}. | ||
4256 | If no decoded data is available or an error occurred @code{NULL} is returned. | ||
4257 | When the returned value is not @code{NULL} then the buffer contains always | ||
4258 | @code{payload_len} bytes plus one terminating @code{NUL} character | ||
4259 | (regardless of the frame type). | ||
4260 | |||
4261 | The caller must free this buffer using @code{MHD_websocket_free()}. | ||
4262 | |||
4263 | If you passed the flag @code{MHD_WEBSOCKET_FLAG_GENERATE_CLOSE_FRAMES_ON_ERROR} | ||
4264 | upon creation of the websocket stream and a decoding error occurred | ||
4265 | (function return value less than 0), then this buffer contains | ||
4266 | a generated close frame, which must be sent via the socket to the recipient. | ||
4267 | |||
4268 | If you passed the flag @code{MHD_WEBSOCKET_FLAG_WANT_FRAGMENTS} | ||
4269 | upon creation of the websocket stream then | ||
4270 | this payload may only be a part of the complete message. | ||
4271 | Only complete UTF-8 sequences are returned for fragmented text frames. | ||
4272 | If necessary the UTF-8 sequence will be completed with the next text fragment. | ||
4273 | |||
4274 | @item payload_len | ||
4275 | pointer to a variable, which receives length of the result | ||
4276 | @code{payload} buffer in bytes. | ||
4277 | Must not be @code{NULL}. | ||
4278 | This receives 0 when no data is available, when the decoded payload | ||
4279 | has a length of zero or when an error occurred. | ||
4280 | @end table | ||
4281 | |||
4282 | Returns a value greater than zero when a frame is complete. | ||
4283 | Compare with @code{enum MHD_WEBSOCKET_STATUS} to distinguish the frame type. | ||
4284 | Returns 0 when the call succeeded, but no frame is available. | ||
4285 | Returns a value less than zero on errors. | ||
4286 | @end deftypefun | ||
4287 | |||
4288 | |||
4289 | @deftypefun {enum MHD_WEBSOCKET_STATUS} MHD_websocket_split_close_reason (const char* payload, size_t payload_len, unsigned short* reason_code, const char** reason_utf8, size_t* reason_utf8_len) | ||
4290 | @cindex websocket | ||
4291 | Splits the payload of a decoded close frame. | ||
4292 | |||
4293 | @table @var | ||
4294 | @item payload | ||
4295 | payload of the close frame. | ||
4296 | This parameter may only be @code{NULL} if @code{payload_len} is 0. | ||
4297 | |||
4298 | @item payload_len | ||
4299 | length of @code{payload}. | ||
4300 | |||
4301 | @item reason_code | ||
4302 | pointer to a variable, which receives the numeric close reason. | ||
4303 | If there was no close reason, this is 0. | ||
4304 | This value can be compared with @code{enum MHD_WEBSOCKET_CLOSEREASON}. | ||
4305 | May be @code{NULL}. | ||
4306 | |||
4307 | @item reason_utf8 | ||
4308 | pointer to a variable, which receives the literal close reason. | ||
4309 | If there was no literal close reason, this will be @code{NULL}. | ||
4310 | May be @code{NULL}. | ||
4311 | |||
4312 | Please note that no memory is allocated in this function. | ||
4313 | If not @code{NULL} the returned value of this parameter | ||
4314 | points to a position in the specified @code{payload}. | ||
4315 | |||
4316 | @item reason_utf8_len | ||
4317 | pointer to a variable, which receives the length of the literal close reason. | ||
4318 | If there was no literal close reason, this is 0. | ||
4319 | May be @code{NULL}. | ||
4320 | @end table | ||
4321 | |||
4322 | Returns 0 on success or a value less than zero on errors. | ||
4323 | Can be compared with @code{enum MHD_WEBSOCKET_STATUS}. | ||
4324 | @end deftypefun | ||
4325 | |||
4326 | |||
4327 | @c ------------------------------------------------------------ | ||
4328 | @node microhttpd-websocket encode | ||
4329 | @section Websocket encode functions | ||
4330 | |||
4331 | |||
4332 | @deftypefun {enum MHD_WEBSOCKET_STATUS} MHD_websocket_encode_text (struct MHD_WebSocketStream* ws, const char* payload_utf8, size_t payload_utf8_len, int fragmentation, char** frame, size_t* frame_len, int* utf8_step) | ||
4333 | @cindex websocket | ||
4334 | Encodes an UTF-8 encoded text into websocket text frame | ||
4335 | |||
4336 | @table @var | ||
4337 | @item ws | ||
4338 | websocket stream; | ||
4339 | |||
4340 | @item payload_utf8 | ||
4341 | text to send. This must be UTF-8 encoded. | ||
4342 | If you don't want UTF-8 then send a binary frame | ||
4343 | with @code{MHD_websocket_encode_binary()} instead. | ||
4344 | May be be @code{NULL} if @code{payload_utf8_len} is 0, | ||
4345 | must not be @code{NULL} otherwise. | ||
4346 | |||
4347 | @item payload_utf8_len | ||
4348 | length of @code{payload_utf8} in bytes. | ||
4349 | |||
4350 | @item fragmentation | ||
4351 | A value of @code{enum MHD_WEBSOCKET_FRAGMENTATION} | ||
4352 | to specify the fragmentation behavior. | ||
4353 | Specify @code{MHD_WEBSOCKET_FRAGMENTATION_NONE} or just 0 | ||
4354 | if you don't want to use fragmentation (default). | ||
4355 | |||
4356 | @item frame | ||
4357 | pointer to a variable, which receives a buffer with the encoded text frame. | ||
4358 | Must not be @code{NULL}. | ||
4359 | The buffer contains what you typically send via @code{send()} to the recipient. | ||
4360 | If no encoded data is available the variable receives @code{NULL}. | ||
4361 | |||
4362 | If the variable is not @code{NULL} then the buffer contains always | ||
4363 | @code{frame_len} bytes plus one terminating @code{NUL} character. | ||
4364 | The caller must free this buffer using @code{MHD_websocket_free()}. | ||
4365 | |||
4366 | @item frame_len | ||
4367 | pointer to a variable, which receives the length of the encoded frame in bytes. | ||
4368 | Must not be @code{NULL}. | ||
4369 | |||
4370 | @item utf8_step | ||
4371 | If fragmentation is used (the parameter @code{fragmentation} is not 0) | ||
4372 | then is parameter is required and must not be @code{NULL}. | ||
4373 | If no fragmentation is used, this parameter is optional and | ||
4374 | should be @code{NULL}. | ||
4375 | |||
4376 | This parameter is a pointer to a variable which contains the last check status | ||
4377 | of the UTF-8 sequence. It is required to continue a previous | ||
4378 | UTF-8 sequence check when fragmentation is used, because a UTF-8 sequence | ||
4379 | could be splitted upon fragments. | ||
4380 | |||
4381 | @code{enum MHD_WEBSOCKET_UTF8STEP} is used for this value. | ||
4382 | If you start a new fragment using | ||
4383 | @code{MHD_WEBSOCKET_FRAGMENTATION_NONE} or | ||
4384 | @code{MHD_WEBSOCKET_FRAGMENTATION_FIRST} the old value of this variable | ||
4385 | will be discarded and the value of this variable will be initialized | ||
4386 | to @code{MHD_WEBSOCKET_UTF8STEP_NORMAL}. | ||
4387 | On all other fragmentation modes the previous value of the pointed variable | ||
4388 | will be used to continue the UTF-8 sequence check. | ||
4389 | @end table | ||
4390 | |||
4391 | Returns 0 on success or a value less than zero on errors. | ||
4392 | Can be compared with @code{enum MHD_WEBSOCKET_STATUS}. | ||
4393 | @end deftypefun | ||
4394 | |||
4395 | |||
4396 | @deftypefun {enum MHD_WEBSOCKET_STATUS} MHD_websocket_encode_binary (struct MHD_WebSocketStream* ws, const char* payload, size_t payload_len, int fragmentation, char** frame, size_t* frame_len) | ||
4397 | @cindex websocket | ||
4398 | Encodes binary data into websocket binary frame | ||
4399 | |||
4400 | @table @var | ||
4401 | @item ws | ||
4402 | websocket stream; | ||
4403 | |||
4404 | @item payload | ||
4405 | binary data to send. | ||
4406 | May be be @code{NULL} if @code{payload_len} is 0, | ||
4407 | must not be @code{NULL} otherwise. | ||
4408 | |||
4409 | @item payload_len | ||
4410 | length of @code{payload} in bytes. | ||
4411 | |||
4412 | @item fragmentation | ||
4413 | A value of @code{enum MHD_WEBSOCKET_FRAGMENTATION} | ||
4414 | to specify the fragmentation behavior. | ||
4415 | Specify @code{MHD_WEBSOCKET_FRAGMENTATION_NONE} or just 0 | ||
4416 | if you don't want to use fragmentation (default). | ||
4417 | |||
4418 | @item frame | ||
4419 | pointer to a variable, which receives a buffer with the encoded binary frame. | ||
4420 | Must not be @code{NULL}. | ||
4421 | The buffer contains what you typically send via @code{send()} to the recipient. | ||
4422 | If no encoded data is available the variable receives @code{NULL}. | ||
4423 | |||
4424 | If the variable is not @code{NULL} then the buffer contains always | ||
4425 | @code{frame_len} bytes plus one terminating @code{NUL} character. | ||
4426 | The caller must free this buffer using @code{MHD_websocket_free()}. | ||
4427 | |||
4428 | @item frame_len | ||
4429 | pointer to a variable, which receives the length of the encoded frame in bytes. | ||
4430 | Must not be @code{NULL}. | ||
4431 | @end table | ||
4432 | |||
4433 | Returns 0 on success or a value less than zero on errors. | ||
4434 | Can be compared with @code{enum MHD_WEBSOCKET_STATUS}. | ||
4435 | @end deftypefun | ||
4436 | |||
4437 | |||
4438 | @deftypefun {enum MHD_WEBSOCKET_STATUS} MHD_websocket_encode_ping (struct MHD_WebSocketStream* ws, const char* payload, size_t payload_len, char** frame, size_t* frame_len) | ||
4439 | @cindex websocket | ||
4440 | Encodes a websocket ping frame. | ||
4441 | Ping frames are used to check whether a recipient is still available | ||
4442 | and what latency the websocket connection has. | ||
4443 | |||
4444 | @table @var | ||
4445 | @item ws | ||
4446 | websocket stream; | ||
4447 | |||
4448 | @item payload | ||
4449 | binary ping data to send. | ||
4450 | May be @code{NULL} if @code{payload_len} is 0. | ||
4451 | |||
4452 | @item payload_len | ||
4453 | length of @code{payload} in bytes. | ||
4454 | This may not exceed 125 bytes. | ||
4455 | |||
4456 | @item frame | ||
4457 | pointer to a variable, which receives a buffer with the encoded ping frame. | ||
4458 | Must not be @code{NULL}. | ||
4459 | The buffer contains what you typically send via @code{send()} to the recipient. | ||
4460 | If no encoded data is available the variable receives @code{NULL}. | ||
4461 | |||
4462 | If the variable is not @code{NULL} then the buffer contains always | ||
4463 | @code{frame_len} bytes plus one terminating @code{NUL} character. | ||
4464 | The caller must free this buffer using @code{MHD_websocket_free()}. | ||
4465 | |||
4466 | @item frame_len | ||
4467 | pointer to a variable, which receives the length of the encoded frame in bytes. | ||
4468 | Must not be @code{NULL}. | ||
4469 | @end table | ||
4470 | |||
4471 | Returns 0 on success or a value less than zero on errors. | ||
4472 | Can be compared with @code{enum MHD_WEBSOCKET_STATUS}. | ||
4473 | @end deftypefun | ||
4474 | |||
4475 | |||
4476 | @deftypefun {enum MHD_WEBSOCKET_STATUS} MHD_websocket_encode_pong (struct MHD_WebSocketStream* ws, const char* payload, size_t payload_len, char** frame, size_t* frame_len) | ||
4477 | @cindex websocket | ||
4478 | Encodes a websocket pong frame. | ||
4479 | Pong frames are used to answer a previously received websocket ping frame. | ||
4480 | |||
4481 | @table @var | ||
4482 | @item ws | ||
4483 | websocket stream; | ||
4484 | |||
4485 | @item payload | ||
4486 | binary pong data to send, which should be | ||
4487 | the decoded payload from the received ping frame. | ||
4488 | May be @code{NULL} if @code{payload_len} is 0. | ||
4489 | |||
4490 | @item payload_len | ||
4491 | length of @code{payload} in bytes. | ||
4492 | This may not exceed 125 bytes. | ||
4493 | |||
4494 | @item frame | ||
4495 | pointer to a variable, which receives a buffer with the encoded pong frame. | ||
4496 | Must not be @code{NULL}. | ||
4497 | The buffer contains what you typically send via @code{send()} to the recipient. | ||
4498 | If no encoded data is available the variable receives @code{NULL}. | ||
4499 | |||
4500 | If the variable is not @code{NULL} then the buffer contains always | ||
4501 | @code{frame_len} bytes plus one terminating @code{NUL} character. | ||
4502 | The caller must free this buffer using @code{MHD_websocket_free()}. | ||
4503 | |||
4504 | @item frame_len | ||
4505 | pointer to a variable, which receives the length of the encoded frame in bytes. | ||
4506 | Must not be @code{NULL}. | ||
4507 | @end table | ||
4508 | |||
4509 | Returns 0 on success or a value less than zero on errors. | ||
4510 | Can be compared with @code{enum MHD_WEBSOCKET_STATUS}. | ||
4511 | @end deftypefun | ||
4512 | |||
4513 | |||
4514 | @deftypefun {enum MHD_WEBSOCKET_STATUS} MHD_websocket_encode_close (struct MHD_WebSocketStream* ws, unsigned short reason_code, const char* reason_utf8, size_t reason_utf8_len, char** frame, size_t* frame_len) | ||
4515 | @cindex websocket | ||
4516 | Encodes a websocket close frame. | ||
4517 | Close frames are used to close a websocket connection in a formal way. | ||
4518 | |||
4519 | @table @var | ||
4520 | @item ws | ||
4521 | websocket stream; | ||
4522 | |||
4523 | @item reason_code | ||
4524 | reason for close. | ||
4525 | You can use @code{enum MHD_WEBSOCKET_CLOSEREASON} for typical reasons, | ||
4526 | but you are not limited to these values. | ||
4527 | The allowed values are specified in RFC 6455 7.4. | ||
4528 | If you don't want to enter a reason, you can specify | ||
4529 | @code{MHD_WEBSOCKET_CLOSEREASON_NO_REASON} (or just 0) then | ||
4530 | no reason is encoded. | ||
4531 | |||
4532 | @item reason_utf8 | ||
4533 | An UTF-8 encoded text reason why the connection is closed. | ||
4534 | This may be @code{NULL} if @code{reason_utf8_len} is 0. | ||
4535 | This must be @code{NULL} if @code{reason_code} equals to zero | ||
4536 | (@code{MHD_WEBSOCKET_CLOSEREASON_NO_REASON}). | ||
4537 | |||
4538 | @item reason_utf8_len | ||
4539 | length of the UTF-8 encoded text reason in bytes. | ||
4540 | This may not exceed 123 bytes. | ||
4541 | |||
4542 | @item frame | ||
4543 | pointer to a variable, which receives a buffer with the encoded close frame. | ||
4544 | Must not be @code{NULL}. | ||
4545 | The buffer contains what you typically send via @code{send()} to the recipient. | ||
4546 | If no encoded data is available the variable receives @code{NULL}. | ||
4547 | |||
4548 | If the variable is not @code{NULL} then the buffer contains always | ||
4549 | @code{frame_len} bytes plus one terminating @code{NUL} character. | ||
4550 | The caller must free this buffer using @code{MHD_websocket_free()}. | ||
4551 | |||
4552 | @item frame_len | ||
4553 | pointer to a variable, which receives the length of the encoded frame in bytes. | ||
4554 | Must not be @code{NULL}. | ||
4555 | @end table | ||
4556 | |||
4557 | Returns 0 on success or a value less than zero on errors. | ||
4558 | Can be compared with @code{enum MHD_WEBSOCKET_STATUS}. | ||
4559 | @end deftypefun | ||
4560 | |||
4561 | |||
4562 | @c ------------------------------------------------------------ | ||
4563 | @node microhttpd-websocket memory | ||
4564 | @section Websocket memory functions | ||
4565 | |||
4566 | |||
4567 | @deftypefun {void*} MHD_websocket_malloc (struct MHD_WebSocketStream* ws, size_t buf_len) | ||
4568 | @cindex websocket | ||
4569 | Allocates memory with the associated @code{malloc()} function | ||
4570 | of the websocket stream. | ||
4571 | The memory allocation function could be different for a websocket stream if | ||
4572 | @code{MHD_websocket_stream_init2()} has been used for initialization. | ||
4573 | |||
4574 | @table @var | ||
4575 | @item ws | ||
4576 | websocket stream; | ||
4577 | |||
4578 | @item buf_len | ||
4579 | size of the buffer to allocate in bytes. | ||
4580 | @end table | ||
4581 | |||
4582 | Returns the pointer of the allocated buffer or @code{NULL} on failure. | ||
4583 | @end deftypefun | ||
4584 | |||
4585 | |||
4586 | @deftypefun {void*} MHD_websocket_realloc (struct MHD_WebSocketStream* ws, void* buf, size_t new_buf_len) | ||
4587 | @cindex websocket | ||
4588 | Reallocates memory with the associated @code{realloc()} function | ||
4589 | of the websocket stream. | ||
4590 | The memory reallocation function could be different for a websocket stream if | ||
4591 | @code{MHD_websocket_stream_init2()} has been used for initialization. | ||
4592 | |||
4593 | @table @var | ||
4594 | @item ws | ||
4595 | websocket stream; | ||
4596 | |||
4597 | @item buf | ||
4598 | current buffer, may be @code{NULL}; | ||
4599 | |||
4600 | @item new_buf_len | ||
4601 | new size of the buffer in bytes. | ||
4602 | @end table | ||
4603 | |||
4604 | Return the pointer of the reallocated buffer or @code{NULL} on failure. | ||
4605 | On failure the old pointer remains valid. | ||
4606 | @end deftypefun | ||
4607 | |||
4608 | |||
4609 | @deftypefun {void} MHD_websocket_free (struct MHD_WebSocketStream* ws, void* buf) | ||
4610 | @cindex websocket | ||
4611 | Frees memory with the associated @code{free()} function | ||
4612 | of the websocket stream. | ||
4613 | The memory free function could be different for a websocket stream if | ||
4614 | @code{MHD_websocket_stream_init2()} has been used for initialization. | ||
4615 | |||
4616 | @table @var | ||
4617 | @item ws | ||
4618 | websocket stream; | ||
4619 | |||
4620 | @item buf | ||
4621 | buffer to free, this may be @code{NULL} then nothing happens. | ||
4622 | @end table | ||
4623 | |||
4624 | @end deftypefun | ||
4625 | |||
4626 | |||
4627 | |||
4628 | |||
4629 | |||
3349 | @c ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | 4630 | @c ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
3350 | 4631 | ||
3351 | 4632 | ||