diff options
author | David Gausmann <David.Gausmann@measX.com> | 2021-10-17 19:53:09 +0200 |
---|---|---|
committer | Evgeny Grin (Karlson2k) <k2k@narod.ru> | 2021-10-31 16:02:31 +0300 |
commit | ddad59c1e3a5d20b19003b1d47673501b0665b36 (patch) | |
tree | 8cd367e724477bc092d7dd38c83cd15f4c12c95f /src/examples/websocket_chatserver_example.c | |
parent | ffbb000f890f23e14d972a6660168aff4a97b66c (diff) | |
download | libmicrohttpd-ddad59c1e3a5d20b19003b1d47673501b0665b36.tar.gz libmicrohttpd-ddad59c1e3a5d20b19003b1d47673501b0665b36.zip |
websocket update
- added API documentation to libmicrohttpd.texi
- added websocket tutorial chapter to libmicrohttpd-tutorial and an much easier example for the tutorial
- added additional helper functions to ease the HTTP websocket handshake
- the code can now be compiled on Linux without errors
- changed sha1.c and sha1.h to the files provided by Evgeny (I replaced those files in src/microhttpd_ws/ with the files from src/microhttpd/ - maybe there is a smarter way...?)
- removed dependency for "htons" and "htonl" (these functions are now implemented in MHD_websocket.c; no need for OS-dependent files anymore)
- added an additional test script for testing of the library with any webbrowser (for manual practice test)
- several bugfixes
- parameters renamed
- special things clarified (fragmentation, RNG for client mode)
The new version of the API is at some points incompatible with the old version, but since it was in an experimental phase and it didn't compile on Linux, I guess this shouldn't bother anyone.
From my point of view, I am now finished with the library and it could go out of experimental.
Diffstat (limited to 'src/examples/websocket_chatserver_example.c')
-rw-r--r-- | src/examples/websocket_chatserver_example.c | 1051 |
1 files changed, 510 insertions, 541 deletions
diff --git a/src/examples/websocket_chatserver_example.c b/src/examples/websocket_chatserver_example.c index 701684cc..0893279b 100644 --- a/src/examples/websocket_chatserver_example.c +++ b/src/examples/websocket_chatserver_example.c | |||
@@ -43,6 +43,12 @@ | |||
43 | See: https://github.com/coapp-packages/pthreads/issues/2 | 43 | See: https://github.com/coapp-packages/pthreads/issues/2 |
44 | */ | 44 | */ |
45 | #include "pthread_windows.h" | 45 | #include "pthread_windows.h" |
46 | |||
47 | /* | ||
48 | On Windows we will use stricmp instead of strcasecmp (strcasecmp is undefined there). | ||
49 | */ | ||
50 | #define strcasecmp stricmp | ||
51 | |||
46 | #else | 52 | #else |
47 | /* | 53 | /* |
48 | On Unix systems we can use pthread. | 54 | On Unix systems we can use pthread. |
@@ -180,429 +186,429 @@ | |||
180 | " function window_onload(event)\n" \ | 186 | " function window_onload(event)\n" \ |
181 | " {\n" \ | 187 | " {\n" \ |
182 | " // Determine the base url (for http:// this is ws:// for https:// this must be wss://)\n" \ | 188 | " // Determine the base url (for http:// this is ws:// for https:// this must be wss://)\n" \ |
183 | // " baseUrl = 'ws' + (window.location.protocol === 'https:' ? 's' : '') + '://' + window.location.host + '/ChatServerWebSocket';\n" \ | 189 | " baseUrl = 'ws' + (window.location.protocol === 'https:' ? 's' : '') + '://' + window.location.host + '/ChatServerWebSocket';\n" \ |
184 | // " chat_generate();\n" \ | 190 | " chat_generate();\n" \ |
185 | // " chat_connect();\n" \ | 191 | " chat_connect();\n" \ |
186 | // " }\n" \ | 192 | " }\n" \ |
187 | // "\n" \ | 193 | "\n" \ |
188 | // " /**\n" \ | 194 | " /**\n" \ |
189 | // " This function generates the chat using DOM\n" \ | 195 | " This function generates the chat using DOM\n" \ |
190 | // " */\n" \ | 196 | " */\n" \ |
191 | // " function chat_generate()\n" \ | 197 | " function chat_generate()\n" \ |
192 | // " {\n" \ | 198 | " {\n" \ |
193 | // " document.body.innerHTML = '';\n" \ | 199 | " document.body.innerHTML = '';\n" \ |
194 | // " let chat = document.createElement('div');\n" \ | 200 | " let chat = document.createElement('div');\n" \ |
195 | // " document.body.appendChild(chat);\n" \ | 201 | " document.body.appendChild(chat);\n" \ |
196 | // " chat.id = 'Chat';\n" \ | 202 | " chat.id = 'Chat';\n" \ |
197 | // " let messagesAndInput = document.createElement('div');\n" \ | 203 | " let messagesAndInput = document.createElement('div');\n" \ |
198 | // " chat.appendChild(messagesAndInput);\n" \ | 204 | " chat.appendChild(messagesAndInput);\n" \ |
199 | // " messagesAndInput.classList.add('MessagesAndInput');\n" \ | 205 | " messagesAndInput.classList.add('MessagesAndInput');\n" \ |
200 | // " let messages = document.createElement('div');\n" \ | 206 | " let messages = document.createElement('div');\n" \ |
201 | // " messagesAndInput.appendChild(messages);\n" \ | 207 | " messagesAndInput.appendChild(messages);\n" \ |
202 | // " messages.id = 'Messages';\n" \ | 208 | " messages.id = 'Messages';\n" \ |
203 | // " let input = document.createElement('div');\n" \ | 209 | " let input = document.createElement('div');\n" \ |
204 | // " messagesAndInput.appendChild(input);\n" \ | 210 | " messagesAndInput.appendChild(input);\n" \ |
205 | // " input.classList.add('Input');\n" \ | 211 | " input.classList.add('Input');\n" \ |
206 | // " let inputMessage = document.createElement('input');\n" \ | 212 | " let inputMessage = document.createElement('input');\n" \ |
207 | // " input.appendChild(inputMessage);\n" \ | 213 | " input.appendChild(inputMessage);\n" \ |
208 | // " inputMessage.type = 'text';\n" \ | 214 | " inputMessage.type = 'text';\n" \ |
209 | // " inputMessage.id = 'InputMessage';\n" \ | 215 | " inputMessage.id = 'InputMessage';\n" \ |
210 | // " inputMessage.disabled = true;\n" \ | 216 | " inputMessage.disabled = true;\n" \ |
211 | // " inputMessage.addEventListener('keydown', chat_onKeyDown);\n" \ | 217 | " inputMessage.addEventListener('keydown', chat_onKeyDown);\n" \ |
212 | // " let inputMessageSend = document.createElement('button');\n" \ | 218 | " let inputMessageSend = document.createElement('button');\n" \ |
213 | // " input.appendChild(inputMessageSend);\n" \ | 219 | " input.appendChild(inputMessageSend);\n" \ |
214 | // " inputMessageSend.id = 'InputMessageButton';\n" \ | 220 | " inputMessageSend.id = 'InputMessageButton';\n" \ |
215 | // " inputMessageSend.disabled = true;\n" \ | 221 | " inputMessageSend.disabled = true;\n" \ |
216 | // " inputMessageSend.innerText = 'send';\n" \ | 222 | " inputMessageSend.innerText = 'send';\n" \ |
217 | // " inputMessageSend.addEventListener('click', chat_onSendClicked);\n" \ | 223 | " inputMessageSend.addEventListener('click', chat_onSendClicked);\n" \ |
218 | // " let inputImage = document.createElement('input');\n" \ | 224 | " let inputImage = document.createElement('input');\n" \ |
219 | // " input.appendChild(inputImage);\n" \ | 225 | " input.appendChild(inputImage);\n" \ |
220 | // " inputImage.id = 'InputImage';\n" \ | 226 | " inputImage.id = 'InputImage';\n" \ |
221 | // " inputImage.type = 'file';\n" \ | 227 | " inputImage.type = 'file';\n" \ |
222 | // " inputImage.accept = 'image/*';\n" \ | 228 | " inputImage.accept = 'image/*';\n" \ |
223 | // " inputImage.style.display = 'none';\n" \ | 229 | " inputImage.style.display = 'none';\n" \ |
224 | // " inputImage.addEventListener('change', chat_onImageSelected);\n" \ | 230 | " inputImage.addEventListener('change', chat_onImageSelected);\n" \ |
225 | // " let inputImageButton = document.createElement('button');\n" \ | 231 | " let inputImageButton = document.createElement('button');\n" \ |
226 | // " input.appendChild(inputImageButton);\n" \ | 232 | " input.appendChild(inputImageButton);\n" \ |
227 | // " inputImageButton.id = 'InputImageButton';\n" \ | 233 | " inputImageButton.id = 'InputImageButton';\n" \ |
228 | // " inputImageButton.disabled = true;\n" \ | 234 | " inputImageButton.disabled = true;\n" \ |
229 | // " inputImageButton.innerText = 'image';\n" \ | 235 | " inputImageButton.innerText = 'image';\n" \ |
230 | // " inputImageButton.addEventListener('click', chat_onImageClicked);\n" \ | 236 | " inputImageButton.addEventListener('click', chat_onImageClicked);\n" \ |
231 | // " let users = document.createElement('div');\n" \ | 237 | " let users = document.createElement('div');\n" \ |
232 | // " chat.appendChild(users);\n" \ | 238 | " chat.appendChild(users);\n" \ |
233 | // " users.id = 'Users';\n" \ | 239 | " users.id = 'Users';\n" \ |
234 | // " users.addEventListener('click', chat_onUserClicked);\n" \ | 240 | " users.addEventListener('click', chat_onUserClicked);\n" \ |
235 | // " let allUsers = document.createElement('div');\n" \ | 241 | " let allUsers = document.createElement('div');\n" \ |
236 | // " users.appendChild(allUsers);\n" \ | 242 | " users.appendChild(allUsers);\n" \ |
237 | // " allUsers.classList.add('selected');\n" \ | 243 | " allUsers.classList.add('selected');\n" \ |
238 | // " allUsers.innerText = '<everyone>';\n" \ | 244 | " allUsers.innerText = '<everyone>';\n" \ |
239 | // " allUsers.setAttribute('data-user', '0');\n" \ | 245 | " allUsers.setAttribute('data-user', '0');\n" \ |
240 | // " }\n" \ | 246 | " }\n" \ |
241 | // "\n" \ | 247 | "\n" \ |
242 | // " /**\n" \ | 248 | " /**\n" \ |
243 | // " This function creates and connects a WebSocket\n" \ | 249 | " This function creates and connects a WebSocket\n" \ |
244 | // " */\n" \ | 250 | " */\n" \ |
245 | // " function chat_connect()\n" \ | 251 | " function chat_connect()\n" \ |
246 | // " {\n" \ | 252 | " {\n" \ |
247 | // " chat_addMessage(`Connecting to libmicrohttpd chat server demo (${baseUrl})...`, { type: 'system' });\n" \ | 253 | " chat_addMessage(`Connecting to libmicrohttpd chat server demo (${baseUrl})...`, { type: 'system' });\n" \ |
248 | // " socket = new WebSocket(baseUrl);\n" \ | 254 | " socket = new WebSocket(baseUrl);\n" \ |
249 | // " socket.binaryType = 'arraybuffer';\n" \ | 255 | " socket.binaryType = 'arraybuffer';\n" \ |
250 | // " socket.onopen = socket_onopen;\n" \ | 256 | " socket.onopen = socket_onopen;\n" \ |
251 | // " socket.onclose = socket_onclose;\n" \ | 257 | " socket.onclose = socket_onclose;\n" \ |
252 | // " socket.onerror = socket_onerror;\n" \ | 258 | " socket.onerror = socket_onerror;\n" \ |
253 | // " socket.onmessage = socket_onmessage;\n" \ | 259 | " socket.onmessage = socket_onmessage;\n" \ |
254 | // " }\n" \ | 260 | " }\n" \ |
255 | // "\n" \ | 261 | "\n" \ |
256 | // " /**\n" \ | 262 | " /**\n" \ |
257 | // " This function adds new text to the chat list\n" \ | 263 | " This function adds new text to the chat list\n" \ |
258 | // " */\n" \ | 264 | " */\n" \ |
259 | // " function chat_addMessage(text, options)\n" \ | 265 | " function chat_addMessage(text, options)\n" \ |
260 | // " {\n" \ | 266 | " {\n" \ |
261 | // " let type = options && options.type || 'regular';\n" \ | 267 | " let type = options && options.type || 'regular';\n" \ |
262 | // " if(!/^(?:regular|system|error|private|moderator)$/.test(type))\n" \ | 268 | " if(!/^(?:regular|system|error|private|moderator)$/.test(type))\n" \ |
263 | // " type = 'regular';\n" \ | 269 | " type = 'regular';\n" \ |
264 | // " let message = document.createElement('div');\n" \ | 270 | " let message = document.createElement('div');\n" \ |
265 | // " message.classList.add('Message');\n" \ | 271 | " message.classList.add('Message');\n" \ |
266 | // " message.classList.add(type);\n" \ | 272 | " message.classList.add(type);\n" \ |
267 | // " if(typeof(text) === 'string')\n" \ | 273 | " if(typeof(text) === 'string')\n" \ |
268 | // " {\n" \ | 274 | " {\n" \ |
269 | // " let content = document.createElement('span');\n" \ | 275 | " let content = document.createElement('span');\n" \ |
270 | // " message.appendChild(content);\n" \ | 276 | " message.appendChild(content);\n" \ |
271 | // " if(options && options.from)\n" \ | 277 | " if(options && options.from)\n" \ |
272 | // " content.innerText = `${options.from}: ${text}`;\n" \ | 278 | " content.innerText = `${options.from}: ${text}`;\n" \ |
273 | // " else\n" \ | 279 | " else\n" \ |
274 | // " content.innerText = text;\n" \ | 280 | " content.innerText = text;\n" \ |
275 | // " if(options && options.reconnect)\n" \ | 281 | " if(options && options.reconnect)\n" \ |
276 | // " {\n" \ | 282 | " {\n" \ |
277 | // " let span = document.createElement('span');\n" \ | 283 | " let span = document.createElement('span');\n" \ |
278 | // " span.appendChild(document.createTextNode(' ('));\n" \ | 284 | " span.appendChild(document.createTextNode(' ('));\n" \ |
279 | // " let reconnect = document.createElement('a');\n" \ | 285 | " let reconnect = document.createElement('a');\n" \ |
280 | // " reconnect.href = 'javascript:chat_connect()';\n" \ | 286 | " reconnect.href = 'javascript:chat_connect()';\n" \ |
281 | // " reconnect.innerText = 'reconnect';\n" \ | 287 | " reconnect.innerText = 'reconnect';\n" \ |
282 | // " span.appendChild(reconnect);\n" \ | 288 | " span.appendChild(reconnect);\n" \ |
283 | // " span.appendChild(document.createTextNode(')'));\n" \ | 289 | " span.appendChild(document.createTextNode(')'));\n" \ |
284 | // " message.appendChild(span);\n" \ | 290 | " message.appendChild(span);\n" \ |
285 | // " }\n" \ | 291 | " }\n" \ |
286 | // " }\n" \ | 292 | " }\n" \ |
287 | // " else\n" \ | 293 | " else\n" \ |
288 | // " {\n" \ | 294 | " {\n" \ |
289 | // " let content = document.createElement('span');\n" \ | 295 | " let content = document.createElement('span');\n" \ |
290 | // " message.appendChild(content);\n" \ | 296 | " message.appendChild(content);\n" \ |
291 | // " if(options && options.from)\n" \ | 297 | " if(options && options.from)\n" \ |
292 | // " {\n" \ | 298 | " {\n" \ |
293 | // " content.innerText = `${options.from}:\\n`;\n" \ | 299 | " content.innerText = `${options.from}:\\n`;\n" \ |
294 | // " }\n" \ | 300 | " }\n" \ |
295 | // " if(options && options.pictureType && text instanceof Uint8Array)\n" \ | 301 | " if(options && options.pictureType && text instanceof Uint8Array)\n" \ |
296 | // " {\n" \ | 302 | " {\n" \ |
297 | // " let img = document.createElement('img');\n" \ | 303 | " let img = document.createElement('img');\n" \ |
298 | // " content.appendChild(img);\n" \ | 304 | " content.appendChild(img);\n" \ |
299 | // " img.src = URL.createObjectURL(new Blob([ text.buffer ], { type: options.pictureType }));\n" \ | 305 | " img.src = URL.createObjectURL(new Blob([ text.buffer ], { type: options.pictureType }));\n" \ |
300 | // " }\n" \ | 306 | " }\n" \ |
301 | // " }\n" \ | 307 | " }\n" \ |
302 | // " document.getElementById('Messages').appendChild(message);\n" \ | 308 | " document.getElementById('Messages').appendChild(message);\n" \ |
303 | // " message.scrollIntoView();\n" \ | 309 | " message.scrollIntoView();\n" \ |
304 | // " }\n" \ | 310 | " }\n" \ |
305 | // "\n" \ | 311 | "\n" \ |
306 | // " /**\n" \ | 312 | " /**\n" \ |
307 | // " This is a keydown event handler, which allows that you can just press enter instead of clicking the 'send' button\n" \ | 313 | " This is a keydown event handler, which allows that you can just press enter instead of clicking the 'send' button\n" \ |
308 | // " */\n" \ | 314 | " */\n" \ |
309 | // " function chat_onKeyDown(event)\n" \ | 315 | " function chat_onKeyDown(event)\n" \ |
310 | // " {\n" \ | 316 | " {\n" \ |
311 | // " if(event.key == 'Enter')\n" \ | 317 | " if(event.key == 'Enter')\n" \ |
312 | // " chat_onSendClicked();\n" \ | 318 | " chat_onSendClicked();\n" \ |
313 | // " }\n" \ | 319 | " }\n" \ |
314 | // "\n" \ | 320 | "\n" \ |
315 | // " /**\n" \ | 321 | " /**\n" \ |
316 | // " This is the code to send a message or command, when clicking the 'send' button\n" \ | 322 | " This is the code to send a message or command, when clicking the 'send' button\n" \ |
317 | // " */\n" \ | 323 | " */\n" \ |
318 | // " function chat_onSendClicked(event)\n" \ | 324 | " function chat_onSendClicked(event)\n" \ |
319 | // " {\n" \ | 325 | " {\n" \ |
320 | // " let message = document.getElementById('InputMessage').value;\n" \ | 326 | " let message = document.getElementById('InputMessage').value;\n" \ |
321 | // " if(message.length == 0)\n" \ | 327 | " if(message.length == 0)\n" \ |
322 | // " return;\n" \ | 328 | " return;\n" \ |
323 | // " if(message.substr(0, 1) == '/')\n" \ | 329 | " if(message.substr(0, 1) == '/')\n" \ |
324 | // " {\n" \ | 330 | " {\n" \ |
325 | // " // command\n" \ | 331 | " // command\n" \ |
326 | // " let match;\n" \ | 332 | " let match;\n" \ |
327 | // " if(/^\\/disconnect\\s*$/.test(message))\n" \ | 333 | " if(/^\\/disconnect\\s*$/.test(message))\n" \ |
328 | // " {\n" \ | 334 | " {\n" \ |
329 | // " socket.close(1000);\n" \ | 335 | " socket.close(1000);\n" \ |
330 | // " }\n" \ | 336 | " }\n" \ |
331 | // " else if((match = /^\\/m\\s+(\\S+)\\s+/.exec(message)))\n" \ | 337 | " else if((match = /^\\/m\\s+(\\S+)\\s+/.exec(message)))\n" \ |
332 | // " {\n" \ | 338 | " {\n" \ |
333 | // " message = message.substr(match[0].length);\n" \ | 339 | " message = message.substr(match[0].length);\n" \ |
334 | // " let userId = chat_getUserIdByName(match[1]);\n" \ | 340 | " let userId = chat_getUserIdByName(match[1]);\n" \ |
335 | // " if(userId !== null)\n" \ | 341 | " if(userId !== null)\n" \ |
336 | // " {\n" \ | 342 | " {\n" \ |
337 | // " socket.send(`private|${userId}|${message}`);\n" \ | 343 | " socket.send(`private|${userId}|${message}`);\n" \ |
338 | // " }\n" \ | 344 | " }\n" \ |
339 | // " else\n" \ | 345 | " else\n" \ |
340 | // " {\n" \ | 346 | " {\n" \ |
341 | // " chat_addMessage(`Unknown user \"${match[1]}\" for private message: ${message}`, { type: 'error' });\n" \ | 347 | " chat_addMessage(`Unknown user \"${match[1]}\" for private message: ${message}`, { type: 'error' });\n" \ |
342 | // " }\n" \ | 348 | " }\n" \ |
343 | // " }\n" \ | 349 | " }\n" \ |
344 | // " else if((match = /^\\/ping\\s+(\\S+)\\s*$/.exec(message)))\n" \ | 350 | " else if((match = /^\\/ping\\s+(\\S+)\\s*$/.exec(message)))\n" \ |
345 | // " {\n" \ | 351 | " {\n" \ |
346 | // " let userId = chat_getUserIdByName(match[1]);\n" \ | 352 | " let userId = chat_getUserIdByName(match[1]);\n" \ |
347 | // " if(userId !== null)\n" \ | 353 | " if(userId !== null)\n" \ |
348 | // " {\n" \ | 354 | " {\n" \ |
349 | // " socket.send(`ping|${userId}|`);\n" \ | 355 | " socket.send(`ping|${userId}|`);\n" \ |
350 | // " }\n" \ | 356 | " }\n" \ |
351 | // " else\n" \ | 357 | " else\n" \ |
352 | // " {\n" \ | 358 | " {\n" \ |
353 | // " chat_addMessage(`Unknown user \"${match[1]}\" for ping`, { type: 'error' });\n" \ | 359 | " chat_addMessage(`Unknown user \"${match[1]}\" for ping`, { type: 'error' });\n" \ |
354 | // " }\n" \ | 360 | " }\n" \ |
355 | // " }\n" \ | 361 | " }\n" \ |
356 | // " else if((match = /^\\/name\\s+(\\S+)\\s*$/.exec(message)))\n" \ | 362 | " else if((match = /^\\/name\\s+(\\S+)\\s*$/.exec(message)))\n" \ |
357 | // " {\n" \ | 363 | " {\n" \ |
358 | // " socket.send(`name||${match[1]}`);\n" \ | 364 | " socket.send(`name||${match[1]}`);\n" \ |
359 | // " }\n" \ | 365 | " }\n" \ |
360 | // " else\n" \ | 366 | " else\n" \ |
361 | // " {\n" \ | 367 | " {\n" \ |
362 | // " chat_addMessage(`Unsupported command or invalid syntax: ${message}`, { type: 'error' });\n" \ | 368 | " chat_addMessage(`Unsupported command or invalid syntax: ${message}`, { type: 'error' });\n" \ |
363 | // " }\n" \ | 369 | " }\n" \ |
364 | // " }\n" \ | 370 | " }\n" \ |
365 | // " else\n" \ | 371 | " else\n" \ |
366 | // " {\n" \ | 372 | " {\n" \ |
367 | // " // regular chat message to the selected user\n" \ | 373 | " // regular chat message to the selected user\n" \ |
368 | // " let selectedUser = document.querySelector('div#Users > div.selected');\n" \ | 374 | " let selectedUser = document.querySelector('div#Users > div.selected');\n" \ |
369 | // " let selectedUserId = parseInt(selectedUser.getAttribute('data-user') || '0', 10);\n" \ | 375 | " let selectedUserId = parseInt(selectedUser.getAttribute('data-user') || '0', 10);\n" \ |
370 | // " if(selectedUserId == 0)\n" \ | 376 | " if(selectedUserId == 0)\n" \ |
371 | // " socket.send(`||${message}`);\n" \ | 377 | " socket.send(`||${message}`);\n" \ |
372 | // " else\n" \ | 378 | " else\n" \ |
373 | // " socket.send(`private|${selectedUserId}|${message}`);\n" \ | 379 | " socket.send(`private|${selectedUserId}|${message}`);\n" \ |
374 | // " }\n" \ | 380 | " }\n" \ |
375 | // " document.getElementById('InputMessage').value = '';\n" \ | 381 | " document.getElementById('InputMessage').value = '';\n" \ |
376 | // " }\n" \ | 382 | " }\n" \ |
377 | // "\n" \ | 383 | "\n" \ |
378 | // " /**\n" \ | 384 | " /**\n" \ |
379 | // " This is the event when the user hits the 'image' button\n" \ | 385 | " This is the event when the user hits the 'image' button\n" \ |
380 | // " */\n" \ | 386 | " */\n" \ |
381 | // " function chat_onImageClicked(event)\n" \ | 387 | " function chat_onImageClicked(event)\n" \ |
382 | // " {\n" \ | 388 | " {\n" \ |
383 | // " document.getElementById('InputImage').click();\n" \ | 389 | " document.getElementById('InputImage').click();\n" \ |
384 | // " }\n" \ | 390 | " }\n" \ |
385 | // "\n" \ | 391 | "\n" \ |
386 | // " /**\n" \ | 392 | " /**\n" \ |
387 | // " This is the event when the user selected an image.\n" \ | 393 | " This is the event when the user selected an image.\n" \ |
388 | // " The image will be read with the FileReader (allowed in web, because the user selected the file).\n" \ | 394 | " The image will be read with the FileReader (allowed in web, because the user selected the file).\n" \ |
389 | // " */\n" \ | 395 | " */\n" \ |
390 | // " function chat_onImageSelected(event)\n" \ | 396 | " function chat_onImageSelected(event)\n" \ |
391 | // " {\n" \ | 397 | " {\n" \ |
392 | // " let file = event.target.files[0];\n" \ | 398 | " let file = event.target.files[0];\n" \ |
393 | // " if(!file || !/^image\\//.test(file.type))\n" \ | 399 | " if(!file || !/^image\\//.test(file.type))\n" \ |
394 | // " return;\n" \ | 400 | " return;\n" \ |
395 | // " let selectedUser = document.querySelector('div#Users > div.selected');\n" \ | 401 | " let selectedUser = document.querySelector('div#Users > div.selected');\n" \ |
396 | // " let selectedUserId = parseInt(selectedUser.getAttribute('data-user') || '0', 10);\n" \ | 402 | " let selectedUserId = parseInt(selectedUser.getAttribute('data-user') || '0', 10);\n" \ |
397 | // " let reader = new FileReader();\n" \ | 403 | " let reader = new FileReader();\n" \ |
398 | // " reader.onload = function(event) {\n" \ | 404 | " reader.onload = function(event) {\n" \ |
399 | // " chat_onImageRead(event, file.type, selectedUserId);\n" \ | 405 | " chat_onImageRead(event, file.type, selectedUserId);\n" \ |
400 | // " };\n" \ | 406 | " };\n" \ |
401 | // " reader.readAsArrayBuffer(file);\n" \ | 407 | " reader.readAsArrayBuffer(file);\n" \ |
402 | // " }\n" \ | 408 | " }\n" \ |
403 | // "\n" \ | 409 | "\n" \ |
404 | // " /**\n" \ | 410 | " /**\n" \ |
405 | // " This is the event when the user selected image has been read.\n" \ | 411 | " This is the event when the user selected image has been read.\n" \ |
406 | // " This will add our chat protocol prefix and send it via the websocket.\n" \ | 412 | " This will add our chat protocol prefix and send it via the websocket.\n" \ |
407 | // " */\n" \ | 413 | " */\n" \ |
408 | // " function chat_onImageRead(event, fileType, selectedUserId)\n" \ | 414 | " function chat_onImageRead(event, fileType, selectedUserId)\n" \ |
409 | // " {\n" \ | 415 | " {\n" \ |
410 | // " let encoder = new TextEncoder();\n" \ | 416 | " let encoder = new TextEncoder();\n" \ |
411 | // " let prefix = ((selectedUserId == 0 ? '||' : `private|${selectedUserId}|`) + fileType + '|');\n" \ | 417 | " let prefix = ((selectedUserId == 0 ? '||' : `private|${selectedUserId}|`) + fileType + '|');\n" \ |
412 | // " prefix = encoder.encode(prefix);\n" \ | 418 | " prefix = encoder.encode(prefix);\n" \ |
413 | // " let byteData = new Uint8Array(event.target.result);\n" \ | 419 | " let byteData = new Uint8Array(event.target.result);\n" \ |
414 | // " let totalLength = prefix.length + byteData.length;\n" \ | 420 | " let totalLength = prefix.length + byteData.length;\n" \ |
415 | // " let resultByteData = new Uint8Array(totalLength);\n" \ | 421 | " let resultByteData = new Uint8Array(totalLength);\n" \ |
416 | // " resultByteData.set(prefix, 0);\n" \ | 422 | " resultByteData.set(prefix, 0);\n" \ |
417 | // " resultByteData.set(byteData, prefix.length);\n" \ | 423 | " resultByteData.set(byteData, prefix.length);\n" \ |
418 | // " socket.send(resultByteData);\n" \ | 424 | " socket.send(resultByteData);\n" \ |
419 | // " }\n" \ | 425 | " }\n" \ |
420 | // "\n" \ | 426 | "\n" \ |
421 | // " /**\n" \ | 427 | " /**\n" \ |
422 | // " This is the event when the user clicked a name in the user list.\n" \ | 428 | " This is the event when the user clicked a name in the user list.\n" \ |
423 | // " This is useful to send private messages or images without needing to add the /m prefix.\n" \ | 429 | " This is useful to send private messages or images without needing to add the /m prefix.\n" \ |
424 | // " */\n" \ | 430 | " */\n" \ |
425 | // " function chat_onUserClicked(event, selectedUserId)\n" \ | 431 | " function chat_onUserClicked(event, selectedUserId)\n" \ |
426 | // " {\n" \ | 432 | " {\n" \ |
427 | // " let newSelected = event.target.closest('div#Users > div');\n" \ | 433 | " let newSelected = event.target.closest('div#Users > div');\n" \ |
428 | // " if(newSelected === null)\n" \ | 434 | " if(newSelected === null)\n" \ |
429 | // " return;\n" \ | 435 | " return;\n" \ |
430 | // " for(let div of this.querySelectorAll(':scope > div.selected'))\n" \ | 436 | " for(let div of this.querySelectorAll(':scope > div.selected'))\n" \ |
431 | // " div.classList.remove('selected');\n" \ | 437 | " div.classList.remove('selected');\n" \ |
432 | // " newSelected.classList.add('selected');\n" \ | 438 | " newSelected.classList.add('selected');\n" \ |
433 | // " }\n" \ | 439 | " }\n" \ |
434 | // "\n" \ | 440 | "\n" \ |
435 | // " /**\n" \ | 441 | " /**\n" \ |
436 | // " This functions returns the current id of a user identified by its name.\n" \ | 442 | " This functions returns the current id of a user identified by its name.\n" \ |
437 | // " */\n" \ | 443 | " */\n" \ |
438 | // " function chat_getUserIdByName(name)\n" \ | 444 | " function chat_getUserIdByName(name)\n" \ |
439 | // " {\n" \ | 445 | " {\n" \ |
440 | // " let nameUpper = name.toUpperCase();\n" \ | 446 | " let nameUpper = name.toUpperCase();\n" \ |
441 | // " for(let pair of connectedUsers)\n" \ | 447 | " for(let pair of connectedUsers)\n" \ |
442 | // " {\n" \ | 448 | " {\n" \ |
443 | // " if(pair[1].toUpperCase() == nameUpper)\n" \ | 449 | " if(pair[1].toUpperCase() == nameUpper)\n" \ |
444 | // " return pair[0];\n" \ | 450 | " return pair[0];\n" \ |
445 | // " }\n" \ | 451 | " }\n" \ |
446 | // " return null;\n" \ | 452 | " return null;\n" \ |
447 | // " }\n" \ | 453 | " }\n" \ |
448 | // "\n" \ | 454 | "\n" \ |
449 | // " /**\n" \ | 455 | " /**\n" \ |
450 | // " This functions clears the entire user list (needed for reconnecting).\n" \ | 456 | " This functions clears the entire user list (needed for reconnecting).\n" \ |
451 | // " */\n" \ | 457 | " */\n" \ |
452 | // " function chat_clearUserList()\n" \ | 458 | " function chat_clearUserList()\n" \ |
453 | // " {\n" \ | 459 | " {\n" \ |
454 | // " let users = document.getElementById('Users');\n" \ | 460 | " let users = document.getElementById('Users');\n" \ |
455 | // " for(let div of users.querySelectorAll(':scope > div'))\n" \ | 461 | " for(let div of users.querySelectorAll(':scope > div'))\n" \ |
456 | // " {\n" \ | 462 | " {\n" \ |
457 | // " if(div.getAttribute('data-user') === '0')\n" \ | 463 | " if(div.getAttribute('data-user') === '0')\n" \ |
458 | // " {\n" \ | 464 | " {\n" \ |
459 | // " div.classList.add('selected');\n" \ | 465 | " div.classList.add('selected');\n" \ |
460 | // " }\n" \ | 466 | " }\n" \ |
461 | // " else\n" \ | 467 | " else\n" \ |
462 | // " {\n" \ | 468 | " {\n" \ |
463 | // " div.parentNode.removeChild(div);\n" \ | 469 | " div.parentNode.removeChild(div);\n" \ |
464 | // " }\n" \ | 470 | " }\n" \ |
465 | // " }\n" \ | 471 | " }\n" \ |
466 | // " return null;\n" \ | 472 | " return null;\n" \ |
467 | // " }\n" \ | 473 | " }\n" \ |
468 | // "\n" \ | 474 | "\n" \ |
469 | // " /**\n" \ | 475 | " /**\n" \ |
470 | // " This is the event when the socket has established a connection.\n" \ | 476 | " This is the event when the socket has established a connection.\n" \ |
471 | // " This will initialize an empty chat and enable the controls.\n" \ | 477 | " This will initialize an empty chat and enable the controls.\n" \ |
472 | // " */\n" \ | 478 | " */\n" \ |
473 | // " function socket_onopen(event)\n" \ | 479 | " function socket_onopen(event)\n" \ |
474 | // " {\n" \ | 480 | " {\n" \ |
475 | // " connectedUsers.clear();\n" \ | 481 | " connectedUsers.clear();\n" \ |
476 | // " chat_clearUserList();\n" \ | 482 | " chat_clearUserList();\n" \ |
477 | // " chat_addMessage('Connected!', { type: 'system' });\n" \ | 483 | " chat_addMessage('Connected!', { type: 'system' });\n" \ |
478 | // " document.getElementById('InputMessage').disabled = false;\n" \ | 484 | " document.getElementById('InputMessage').disabled = false;\n" \ |
479 | // " document.getElementById('InputMessageButton').disabled = false;\n" \ | 485 | " document.getElementById('InputMessageButton').disabled = false;\n" \ |
480 | // " document.getElementById('InputImageButton').disabled = false;\n" \ | 486 | " document.getElementById('InputImageButton').disabled = false;\n" \ |
481 | // " }\n" \ | 487 | " }\n" \ |
482 | // "\n" \ | 488 | "\n" \ |
483 | // " /**\n" \ | 489 | " /**\n" \ |
484 | // " This is the event when the socket has been closed.\n" \ | 490 | " This is the event when the socket has been closed.\n" \ |
485 | // " This will lock the controls.\n" \ | 491 | " This will lock the controls.\n" \ |
486 | // " */\n" \ | 492 | " */\n" \ |
487 | // " function socket_onclose(event)\n" \ | 493 | " function socket_onclose(event)\n" \ |
488 | // " {\n" \ | 494 | " {\n" \ |
489 | // " chat_addMessage('Connection closed!', { type: 'system', reconnect: true });\n" \ | 495 | " chat_addMessage('Connection closed!', { type: 'system', reconnect: true });\n" \ |
490 | // " document.getElementById('InputMessage').disabled = true;\n" \ | 496 | " document.getElementById('InputMessage').disabled = true;\n" \ |
491 | // " document.getElementById('InputMessageButton').disabled = true;\n" \ | 497 | " document.getElementById('InputMessageButton').disabled = true;\n" \ |
492 | // " document.getElementById('InputImageButton').disabled = true;\n" \ | 498 | " document.getElementById('InputImageButton').disabled = true;\n" \ |
493 | // " }\n" \ | 499 | " }\n" \ |
494 | // "\n" \ | 500 | "\n" \ |
495 | // " /**\n" \ | 501 | " /**\n" \ |
496 | // " This is the event when the socket reported an error.\n" \ | 502 | " This is the event when the socket reported an error.\n" \ |
497 | // " This will just make an output.\n" \ | 503 | " This will just make an output.\n" \ |
498 | // " In the web browser console (F12 on many browsers) will show you more detailed error information.\n" \ | 504 | " In the web browser console (F12 on many browsers) will show you more detailed error information.\n" \ |
499 | // " */\n" \ | 505 | " */\n" \ |
500 | // " function socket_onerror(event)\n" \ | 506 | " function socket_onerror(event)\n" \ |
501 | // " {\n" \ | 507 | " {\n" \ |
502 | // " console.error('WebSocket error reported: ', event);\n" \ | 508 | " console.error('WebSocket error reported: ', event);\n" \ |
503 | // " chat_addMessage('The socket reported an error!', { type: 'error' });\n" \ | 509 | " chat_addMessage('The socket reported an error!', { type: 'error' });\n" \ |
504 | // " }\n" \ | 510 | " }\n" \ |
505 | // "\n" \ | 511 | "\n" \ |
506 | // " /**\n" \ | 512 | " /**\n" \ |
507 | // " This is the event when the socket has received a message.\n" \ | 513 | " This is the event when the socket has received a message.\n" \ |
508 | // " This will parse the message and execute the corresponding command (or add the message).\n" \ | 514 | " This will parse the message and execute the corresponding command (or add the message).\n" \ |
509 | // " */\n" \ | 515 | " */\n" \ |
510 | // " function socket_onmessage(event)\n" \ | 516 | " function socket_onmessage(event)\n" \ |
511 | // " {\n" \ | 517 | " {\n" \ |
512 | // " if(typeof(event.data) === 'string')\n" \ | 518 | " if(typeof(event.data) === 'string')\n" \ |
513 | // " {\n" \ | 519 | " {\n" \ |
514 | // " // text message or command\n" \ | 520 | " // text message or command\n" \ |
515 | // " let message = event.data.split('|', 3);\n" \ | 521 | " let message = event.data.split('|', 3);\n" \ |
516 | // " switch(message[0])\n" \ | 522 | " switch(message[0])\n" \ |
517 | // " {\n" \ | 523 | " {\n" \ |
518 | // " case 'userinit':\n" \ | 524 | " case 'userinit':\n" \ |
519 | // " connectedUsers.set(message[1], message[2]);\n" \ | 525 | " connectedUsers.set(message[1], message[2]);\n" \ |
520 | // " {\n" \ | 526 | " {\n" \ |
521 | // " let users = document.getElementById('Users');\n" \ | 527 | " let users = document.getElementById('Users');\n" \ |
522 | // " let div = document.createElement('div');\n" \ | 528 | " let div = document.createElement('div');\n" \ |
523 | // " users.appendChild(div);\n" \ | 529 | " users.appendChild(div);\n" \ |
524 | // " div.innerText = message[2];\n" \ | 530 | " div.innerText = message[2];\n" \ |
525 | // " div.setAttribute('data-user', message[1]);\n" \ | 531 | " div.setAttribute('data-user', message[1]);\n" \ |
526 | // " }\n" \ | 532 | " }\n" \ |
527 | // " break;\n" \ | 533 | " break;\n" \ |
528 | // " case 'useradd':\n" \ | 534 | " case 'useradd':\n" \ |
529 | // " connectedUsers.set(message[1], message[2]);\n" \ | 535 | " connectedUsers.set(message[1], message[2]);\n" \ |
530 | // " chat_addMessage(`The user '${message[2]}' has joined our lovely chatroom.`, { type: 'moderator' });\n" \ | 536 | " chat_addMessage(`The user '${message[2]}' has joined our lovely chatroom.`, { type: 'moderator' });\n" \ |
531 | // " {\n" \ | 537 | " {\n" \ |
532 | // " let users = document.getElementById('Users');\n" \ | 538 | " let users = document.getElementById('Users');\n" \ |
533 | // " let div = document.createElement('div');\n" \ | 539 | " let div = document.createElement('div');\n" \ |
534 | // " users.appendChild(div);\n" \ | 540 | " users.appendChild(div);\n" \ |
535 | // " div.innerText = message[2];\n" \ | 541 | " div.innerText = message[2];\n" \ |
536 | // " div.setAttribute('data-user', message[1]);\n" \ | 542 | " div.setAttribute('data-user', message[1]);\n" \ |
537 | // " }\n" \ | 543 | " }\n" \ |
538 | // " break;\n" \ | 544 | " break;\n" \ |
539 | // " case 'userdel':\n" \ | 545 | " case 'userdel':\n" \ |
540 | // " chat_addMessage(`The user '${connectedUsers.get(message[1])}' has left our chatroom. We will miss you.`, { type: 'moderator' });\n" \ | 546 | " chat_addMessage(`The user '${connectedUsers.get(message[1])}' has left our chatroom. We will miss you.`, { type: 'moderator' });\n" \ |
541 | // " connectedUsers.delete(message[1]);\n" \ | 547 | " connectedUsers.delete(message[1]);\n" \ |
542 | // " {\n" \ | 548 | " {\n" \ |
543 | // " let users = document.getElementById('Users');\n" \ | 549 | " let users = document.getElementById('Users');\n" \ |
544 | // " let div = users.querySelector(`div[data-user='${message[1]}']`);\n" \ | 550 | " let div = users.querySelector(`div[data-user='${message[1]}']`);\n" \ |
545 | // " if(div !== null)\n" \ | 551 | " if(div !== null)\n" \ |
546 | // " {\n" \ | 552 | " {\n" \ |
547 | // " users.removeChild(div);\n" \ | 553 | " users.removeChild(div);\n" \ |
548 | // " if(div.classList.contains('selected'))\n" \ | 554 | " if(div.classList.contains('selected'))\n" \ |
549 | // " users.querySelector('div[data-user=\\'0\\']').classList.add('selected');\n" \ | 555 | " users.querySelector('div[data-user=\\'0\\']').classList.add('selected');\n" \ |
550 | // " }\n" \ | 556 | " }\n" \ |
551 | // " }\n" \ | 557 | " }\n" \ |
552 | // " break;\n" \ | 558 | " break;\n" \ |
553 | // " case 'username':\n" \ | 559 | " case 'username':\n" \ |
554 | // " chat_addMessage(`The user '${connectedUsers.get(message[1])}' has changed his name to '${message[2]}'.`, { type: 'moderator' });\n" \ | 560 | " chat_addMessage(`The user '${connectedUsers.get(message[1])}' has changed his name to '${message[2]}'.`, { type: 'moderator' });\n" \ |
555 | // " connectedUsers.set(message[1], message[2]);\n" \ | 561 | " connectedUsers.set(message[1], message[2]);\n" \ |
556 | // " {\n" \ | 562 | " {\n" \ |
557 | // " let users = document.getElementById('Users');\n" \ | 563 | " let users = document.getElementById('Users');\n" \ |
558 | // " let div = users.querySelector(`div[data-user='${message[1]}']`);\n" \ | 564 | " let div = users.querySelector(`div[data-user='${message[1]}']`);\n" \ |
559 | // " if(div !== null)\n" \ | 565 | " if(div !== null)\n" \ |
560 | // " {\n" \ | 566 | " {\n" \ |
561 | // " div.innerText = message[2];\n" \ | 567 | " div.innerText = message[2];\n" \ |
562 | // " }\n" \ | 568 | " }\n" \ |
563 | // " }\n" \ | 569 | " }\n" \ |
564 | // " break;\n" \ | 570 | " break;\n" \ |
565 | // " case 'ping':\n" \ | 571 | " case 'ping':\n" \ |
566 | // " chat_addMessage(`The user '${connectedUsers.get(message[1])}' has a ping of ${message[2]} ms.`, { type: 'moderator' });\n" \ | 572 | " chat_addMessage(`The user '${connectedUsers.get(message[1])}' has a ping of ${message[2]} ms.`, { type: 'moderator' });\n" \ |
567 | // " break;\n" \ | 573 | " break;\n" \ |
568 | // " default:\n" \ | 574 | " default:\n" \ |
569 | // " chat_addMessage(message[2], { type: message[0], from: connectedUsers.get(message[1]) });\n" \ | 575 | " chat_addMessage(message[2], { type: message[0], from: connectedUsers.get(message[1]) });\n" \ |
570 | // " break;\n" \ | 576 | " break;\n" \ |
571 | // " }\n" \ | 577 | " }\n" \ |
572 | // " }\n" \ | 578 | " }\n" \ |
573 | // " else\n" \ | 579 | " else\n" \ |
574 | // " {\n" \ | 580 | " {\n" \ |
575 | // " // We received a binary frame, which means a picture here\n" \ | 581 | " // We received a binary frame, which means a picture here\n" \ |
576 | // " let byteData = new Uint8Array(event.data);\n" \ | 582 | " let byteData = new Uint8Array(event.data);\n" \ |
577 | // " let decoder = new TextDecoder();\n" \ | 583 | " let decoder = new TextDecoder();\n" \ |
578 | // " let message = [ ];\n" \ | 584 | " let message = [ ];\n" \ |
579 | // " // message type\n" \ | 585 | " // message type\n" \ |
580 | // " let j = 0;\n" \ | 586 | " let j = 0;\n" \ |
581 | // " let i = byteData.indexOf(0x7C, j); // | = 0x7C;\n" \ | 587 | " let i = byteData.indexOf(0x7C, j); // | = 0x7C;\n" \ |
582 | // " if(i < 0)\n" \ | 588 | " if(i < 0)\n" \ |
583 | // " return;\n" \ | 589 | " return;\n" \ |
584 | // " message.push(decoder.decode(byteData.slice(0, i)));\n" \ | 590 | " message.push(decoder.decode(byteData.slice(0, i)));\n" \ |
585 | // " // picture from\n" \ | 591 | " // picture from\n" \ |
586 | // " j = i + 1;\n" \ | 592 | " j = i + 1;\n" \ |
587 | // " i = byteData.indexOf(0x7C, j);\n" \ | 593 | " i = byteData.indexOf(0x7C, j);\n" \ |
588 | // " if(i < 0)\n" \ | 594 | " if(i < 0)\n" \ |
589 | // " return;\n" \ | 595 | " return;\n" \ |
590 | // " message.push(decoder.decode(byteData.slice(j, i)));\n" \ | 596 | " message.push(decoder.decode(byteData.slice(j, i)));\n" \ |
591 | // " // picture encoding\n" \ | 597 | " // picture encoding\n" \ |
592 | // " j = i + 1;\n" \ | 598 | " j = i + 1;\n" \ |
593 | // " i = byteData.indexOf(0x7C, j);\n" \ | 599 | " i = byteData.indexOf(0x7C, j);\n" \ |
594 | // " if(i < 0)\n" \ | 600 | " if(i < 0)\n" \ |
595 | // " return;\n" \ | 601 | " return;\n" \ |
596 | // " message.push(decoder.decode(byteData.slice(j, i)));\n" \ | 602 | " message.push(decoder.decode(byteData.slice(j, i)));\n" \ |
597 | // " // picture\n" \ | 603 | " // picture\n" \ |
598 | // " byteData = byteData.slice(i + 1);\n" \ | 604 | " byteData = byteData.slice(i + 1);\n" \ |
599 | // " chat_addMessage(byteData, { type: message[0], from: connectedUsers.get(message[1]), pictureType: message[2] });\n" \ | 605 | " chat_addMessage(byteData, { type: message[0], from: connectedUsers.get(message[1]), pictureType: message[2] });\n" \ |
600 | // " }\n" \ | 606 | " }\n" \ |
601 | // " }\n" \ | 607 | " }\n" \ |
602 | // "</script>" \ | 608 | "</script>" \ |
603 | // "</head>" \ | 609 | "</head>" \ |
604 | // "<body><noscript>Please enable JavaScript to test the libmicrohttpd Websocket chatserver demo!</noscript></body>" \ | 610 | "<body><noscript>Please enable JavaScript to test the libmicrohttpd Websocket chatserver demo!</noscript></body>" \ |
605 | // "</html>" | 611 | "</html>" |
606 | 612 | ||
607 | #define PAGE_NOT_FOUND \ | 613 | #define PAGE_NOT_FOUND \ |
608 | "404 Not Found" | 614 | "404 Not Found" |
@@ -708,7 +714,7 @@ make_blocking (MHD_socket fd) | |||
708 | #elif defined(MHD_WINSOCK_SOCKETS) | 714 | #elif defined(MHD_WINSOCK_SOCKETS) |
709 | unsigned long flags = 0; | 715 | unsigned long flags = 0; |
710 | 716 | ||
711 | ioctlsocket (fd, (int) FIONBIO, &flags); | 717 | ioctlsocket (fd, FIONBIO, &flags); |
712 | #endif /* MHD_WINSOCK_SOCKETS */ | 718 | #endif /* MHD_WINSOCK_SOCKETS */ |
713 | 719 | ||
714 | } | 720 | } |
@@ -739,7 +745,6 @@ send_all (struct ConnectedUser*cu, | |||
739 | 0); | 745 | 0); |
740 | if (0 > ret) | 746 | if (0 > ret) |
741 | { | 747 | { |
742 | int err = errno; | ||
743 | if (EAGAIN == errno) | 748 | if (EAGAIN == errno) |
744 | { | 749 | { |
745 | ret = 0; | 750 | ret = 0; |
@@ -927,7 +932,7 @@ chat_adduser (struct ConnectedUser*cu) | |||
927 | { | 932 | { |
928 | /* initialize the notification message of the new user */ | 933 | /* initialize the notification message of the new user */ |
929 | char user_index[32]; | 934 | char user_index[32]; |
930 | itoa ((int) cu->user_id, user_index, 10); | 935 | snprintf (user_index, 32, "%d", (int) cu->user_id); |
931 | size_t user_index_len = strlen (user_index); | 936 | size_t user_index_len = strlen (user_index); |
932 | size_t data_len = user_index_len + cu->user_name_len + 9; | 937 | size_t data_len = user_index_len + cu->user_name_len + 9; |
933 | char*data = (char*) malloc (data_len + 1); | 938 | char*data = (char*) malloc (data_len + 1); |
@@ -998,7 +1003,7 @@ chat_removeuser (struct ConnectedUser*cu) | |||
998 | char user_index[32]; | 1003 | char user_index[32]; |
999 | 1004 | ||
1000 | /* initialize the chat message for the removed user */ | 1005 | /* initialize the chat message for the removed user */ |
1001 | itoa ((int) cu->user_id, user_index, 10); | 1006 | snprintf (user_index, 32, "%d", (int) cu->user_id); |
1002 | size_t user_index_len = strlen (user_index); | 1007 | size_t user_index_len = strlen (user_index); |
1003 | size_t data_len = user_index_len + 9; | 1008 | size_t data_len = user_index_len + 9; |
1004 | char*data = (char*) malloc (data_len + 1); | 1009 | char*data = (char*) malloc (data_len + 1); |
@@ -1071,9 +1076,8 @@ chat_renameuser (struct ConnectedUser*cu, | |||
1071 | { | 1076 | { |
1072 | if (cu != users[i]) | 1077 | if (cu != users[i]) |
1073 | { | 1078 | { |
1074 | if ((users[i]->user_name_len == new_name_len) && (0 == stricmp ( | 1079 | if ((users[i]->user_name_len == new_name_len) && |
1075 | users[i]->user_name, | 1080 | (0 == strcasecmp (users[i]->user_name, new_name))) |
1076 | new_name))) | ||
1077 | { | 1081 | { |
1078 | pthread_mutex_unlock (&chat_mutex); | 1082 | pthread_mutex_unlock (&chat_mutex); |
1079 | return 2; | 1083 | return 2; |
@@ -1083,7 +1087,7 @@ chat_renameuser (struct ConnectedUser*cu, | |||
1083 | 1087 | ||
1084 | /* generate the notification message */ | 1088 | /* generate the notification message */ |
1085 | char user_index[32]; | 1089 | char user_index[32]; |
1086 | itoa ((int) cu->user_id, user_index, 10); | 1090 | snprintf (user_index, 32, "%d", (int) cu->user_id); |
1087 | size_t user_index_len = strlen (user_index); | 1091 | size_t user_index_len = strlen (user_index); |
1088 | size_t data_len = user_index_len + new_name_len + 10; | 1092 | size_t data_len = user_index_len + new_name_len + 10; |
1089 | char*data = (char*) malloc (data_len + 1); | 1093 | char*data = (char*) malloc (data_len + 1); |
@@ -1202,17 +1206,17 @@ connecteduser_parse_received_websocket_stream (struct ConnectedUser*cu, | |||
1202 | /* no command means regular message */ | 1206 | /* no command means regular message */ |
1203 | command = 0; | 1207 | command = 0; |
1204 | } | 1208 | } |
1205 | else if (0 == stricmp (frame_data, "private")) | 1209 | else if (0 == strcasecmp (frame_data, "private")) |
1206 | { | 1210 | { |
1207 | /* private means private message */ | 1211 | /* private means private message */ |
1208 | command = 1; | 1212 | command = 1; |
1209 | } | 1213 | } |
1210 | else if (0 == stricmp (frame_data, "name")) | 1214 | else if (0 == strcasecmp (frame_data, "name")) |
1211 | { | 1215 | { |
1212 | /* name means chat user rename */ | 1216 | /* name means chat user rename */ |
1213 | command = 2; | 1217 | command = 2; |
1214 | } | 1218 | } |
1215 | else if (0 == stricmp (frame_data, "ping")) | 1219 | else if (0 == strcasecmp (frame_data, "ping")) |
1216 | { | 1220 | { |
1217 | /* ping means a ping request */ | 1221 | /* ping means a ping request */ |
1218 | command = 3; | 1222 | command = 3; |
@@ -1263,7 +1267,7 @@ connecteduser_parse_received_websocket_stream (struct ConnectedUser*cu, | |||
1263 | * This is useful for debugging with an IDE. | 1267 | * This is useful for debugging with an IDE. |
1264 | */ | 1268 | */ |
1265 | char user_index[32]; | 1269 | char user_index[32]; |
1266 | itoa ((int) from_user_id, user_index, 10); | 1270 | snprintf (user_index, 32, "%d", (int) cu->user_id); |
1267 | size_t user_index_len = strlen (user_index); | 1271 | size_t user_index_len = strlen (user_index); |
1268 | size_t data_len = user_index_len + frame_len - j + 9; | 1272 | size_t data_len = user_index_len + frame_len - j + 9; |
1269 | char*data = (char*) malloc (data_len + 1); | 1273 | char*data = (char*) malloc (data_len + 1); |
@@ -1300,7 +1304,7 @@ connecteduser_parse_received_websocket_stream (struct ConnectedUser*cu, | |||
1300 | * The difference is the prefix "private" | 1304 | * The difference is the prefix "private" |
1301 | */ | 1305 | */ |
1302 | char user_index[32]; | 1306 | char user_index[32]; |
1303 | itoa ((int) from_user_id, user_index, 10); | 1307 | snprintf (user_index, 32, "%d", (int) cu->user_id); |
1304 | size_t user_index_len = strlen (user_index); | 1308 | size_t user_index_len = strlen (user_index); |
1305 | size_t data_len = user_index_len + frame_len - j + 9; | 1309 | size_t data_len = user_index_len + frame_len - j + 9; |
1306 | char*data = (char*) malloc (data_len + 1); | 1310 | char*data = (char*) malloc (data_len + 1); |
@@ -1538,14 +1542,10 @@ connecteduser_parse_received_websocket_stream (struct ConnectedUser*cu, | |||
1538 | char result_text[240]; | 1542 | char result_text[240]; |
1539 | strcpy (result_text, | 1543 | strcpy (result_text, |
1540 | "ping|"); | 1544 | "ping|"); |
1541 | itoa ((int) cu->user_id, | 1545 | snprintf (result_text + 5, 235, "%d", (int) cu->user_id); |
1542 | result_text + 5, | ||
1543 | 10); | ||
1544 | strcat (result_text, | 1546 | strcat (result_text, |
1545 | "|"); | 1547 | "|"); |
1546 | itoa (ping, | 1548 | snprintf (result_text + strlen (result_text), 240 - strlen (result_text), "%d", (int) ping); |
1547 | result_text + strlen (result_text), | ||
1548 | 10); | ||
1549 | chat_addmessage (0, | 1549 | chat_addmessage (0, |
1550 | 0, | 1550 | 0, |
1551 | result_text, | 1551 | result_text, |
@@ -1627,9 +1627,7 @@ connecteduser_send_messages (void*cls) | |||
1627 | ++cu->ping_counter; | 1627 | ++cu->ping_counter; |
1628 | strcpy (cu->ping_message, | 1628 | strcpy (cu->ping_message, |
1629 | "libmicrohttpdchatserverpingdata"); | 1629 | "libmicrohttpdchatserverpingdata"); |
1630 | itoa (cu->ping_counter, | 1630 | snprintf (cu->ping_message + 31, 97, "%d", (int) cu->ping_counter); |
1631 | cu->ping_message + 31, | ||
1632 | 10); | ||
1633 | cu->ping_message_len = strlen (cu->ping_message); | 1631 | cu->ping_message_len = strlen (cu->ping_message); |
1634 | char*frame_data = NULL; | 1632 | char*frame_data = NULL; |
1635 | size_t frame_len = 0; | 1633 | size_t frame_len = 0; |
@@ -1750,7 +1748,7 @@ connecteduser_receive_messages (void *cls) | |||
1750 | { | 1748 | { |
1751 | char user_name[32]; | 1749 | char user_name[32]; |
1752 | strcpy (user_name, "User"); | 1750 | strcpy (user_name, "User"); |
1753 | itoa ((int) cu->user_id, user_name + 4, 10); | 1751 | snprintf (user_name + 4, 28, "%d", (int) cu->user_id); |
1754 | cu->user_name_len = strlen (user_name); | 1752 | cu->user_name_len = strlen (user_name); |
1755 | cu->user_name = malloc (cu->user_name_len + 1); | 1753 | cu->user_name = malloc (cu->user_name_len + 1); |
1756 | if (NULL == cu->user_name) | 1754 | if (NULL == cu->user_name) |
@@ -1831,7 +1829,7 @@ connecteduser_receive_messages (void *cls) | |||
1831 | for (size_t i = 0; i < user_count; ++i) | 1829 | for (size_t i = 0; i < user_count; ++i) |
1832 | { | 1830 | { |
1833 | char user_index[32]; | 1831 | char user_index[32]; |
1834 | itoa ((int) users[i]->user_id, user_index, 10); | 1832 | snprintf (user_index, 32, "%d", (int) users[i]->user_id); |
1835 | size_t user_index_len = strlen (user_index); | 1833 | size_t user_index_len = strlen (user_index); |
1836 | struct UserInit iu; | 1834 | struct UserInit iu; |
1837 | iu.user_init_len = user_index_len + users[i]->user_name_len + 10; | 1835 | iu.user_init_len = user_index_len + users[i]->user_name_len + 10; |
@@ -1891,15 +1889,16 @@ connecteduser_receive_messages (void *cls) | |||
1891 | " /ping <user> - sends a ping to the specified user\n" \ | 1889 | " /ping <user> - sends a ping to the specified user\n" \ |
1892 | " /name <name> - changes your name to the specified name\n" \ | 1890 | " /name <name> - changes your name to the specified name\n" \ |
1893 | " /disconnect - disconnects your websocket\n\n" \ | 1891 | " /disconnect - disconnects your websocket\n\n" \ |
1894 | "All messages, which does not start a slash, are regular messages, which will be sent to selected user.\n\n" \ | 1892 | "All messages, which does not start with a slash, " \ |
1893 | "are regular messages and will be sent to the selected user.\n\n" \ | ||
1895 | "Have fun!"; | 1894 | "Have fun!"; |
1896 | int r = MHD_websocket_encode_text (cu->ws, | 1895 | MHD_websocket_encode_text (cu->ws, |
1897 | welcome_msg, | 1896 | welcome_msg, |
1898 | strlen (welcome_msg), | 1897 | strlen (welcome_msg), |
1899 | MHD_WEBSOCKET_FRAGMENTATION_NONE, | 1898 | MHD_WEBSOCKET_FRAGMENTATION_NONE, |
1900 | &frame_data, | 1899 | &frame_data, |
1901 | &frame_len, | 1900 | &frame_len, |
1902 | NULL); | 1901 | NULL); |
1903 | send_all (cu, | 1902 | send_all (cu, |
1904 | frame_data, | 1903 | frame_data, |
1905 | frame_len); | 1904 | frame_len); |
@@ -2132,7 +2131,7 @@ upgrade_handler (void *cls, | |||
2132 | * @param ptr A pointer for request specific data | 2131 | * @param ptr A pointer for request specific data |
2133 | * @return MHD_YES on success or MHD_NO on error. | 2132 | * @return MHD_YES on success or MHD_NO on error. |
2134 | */ | 2133 | */ |
2135 | static int | 2134 | static enum MHD_Result |
2136 | access_handler (void *cls, | 2135 | access_handler (void *cls, |
2137 | struct MHD_Connection *connection, | 2136 | struct MHD_Connection *connection, |
2138 | const char *url, | 2137 | const char *url, |
@@ -2185,118 +2184,88 @@ access_handler (void *cls, | |||
2185 | * Furthermore it must be a HTTP/1.1 or higher GET request. | 2184 | * Furthermore it must be a HTTP/1.1 or higher GET request. |
2186 | * See: https://tools.ietf.org/html/rfc6455#section-4.2.1 | 2185 | * See: https://tools.ietf.org/html/rfc6455#section-4.2.1 |
2187 | * | 2186 | * |
2188 | * To ease this example we skip the following checks: | 2187 | * To make this example portable we skip the Host check |
2189 | * - Whether the HTTP version is 1.1 or newer | ||
2190 | * - Whether Connection is Upgrade, because this header may | ||
2191 | * contain multiple values. | ||
2192 | * - The requested Host (because we don't know) | ||
2193 | */ | 2188 | */ |
2194 | 2189 | ||
2190 | char is_valid = 1; | ||
2191 | const char* value = NULL; | ||
2192 | char sec_websocket_accept[29]; | ||
2193 | |||
2195 | /* check whether an websocket upgrade is requested */ | 2194 | /* check whether an websocket upgrade is requested */ |
2196 | const char*value = MHD_lookup_connection_value (connection, | 2195 | if (0 != MHD_websocket_check_http_version (version)) |
2197 | MHD_HEADER_KIND, | ||
2198 | MHD_HTTP_HEADER_UPGRADE); | ||
2199 | if ((0 == value) || (0 != stricmp (value, "websocket"))) | ||
2200 | { | 2196 | { |
2201 | struct MHD_Response*response = MHD_create_response_from_buffer (strlen ( | 2197 | is_valid = 0; |
2202 | PAGE_INVALID_WEBSOCKET_REQUEST), | 2198 | } |
2203 | PAGE_INVALID_WEBSOCKET_REQUEST, | 2199 | value = MHD_lookup_connection_value (connection, |
2204 | MHD_RESPMEM_PERSISTENT); | 2200 | MHD_HEADER_KIND, |
2205 | ret = MHD_queue_response (connection, | 2201 | MHD_HTTP_HEADER_CONNECTION); |
2206 | MHD_HTTP_BAD_REQUEST, | 2202 | if (0 != MHD_websocket_check_connection_header (value)) |
2207 | response); | 2203 | { |
2208 | MHD_destroy_response (response); | 2204 | is_valid = 0; |
2209 | return ret; | 2205 | } |
2206 | value = MHD_lookup_connection_value (connection, | ||
2207 | MHD_HEADER_KIND, | ||
2208 | MHD_HTTP_HEADER_UPGRADE); | ||
2209 | if (0 != MHD_websocket_check_upgrade_header (value)) | ||
2210 | { | ||
2211 | is_valid = 0; | ||
2210 | } | 2212 | } |
2211 | |||
2212 | /* check the protocol version */ | ||
2213 | value = MHD_lookup_connection_value (connection, | 2213 | value = MHD_lookup_connection_value (connection, |
2214 | MHD_HEADER_KIND, | 2214 | MHD_HEADER_KIND, |
2215 | MHD_HTTP_HEADER_SEC_WEBSOCKET_VERSION); | 2215 | MHD_HTTP_HEADER_SEC_WEBSOCKET_VERSION); |
2216 | if ((0 == value) || (0 != stricmp (value, "13"))) | 2216 | if (0 != MHD_websocket_check_version_header (value)) |
2217 | { | 2217 | { |
2218 | struct MHD_Response*response = MHD_create_response_from_buffer (strlen ( | 2218 | is_valid = 0; |
2219 | PAGE_INVALID_WEBSOCKET_REQUEST), | ||
2220 | PAGE_INVALID_WEBSOCKET_REQUEST, | ||
2221 | MHD_RESPMEM_PERSISTENT); | ||
2222 | ret = MHD_queue_response (connection, | ||
2223 | MHD_HTTP_BAD_REQUEST, | ||
2224 | response); | ||
2225 | MHD_destroy_response (response); | ||
2226 | return ret; | ||
2227 | } | 2219 | } |
2228 | 2220 | value = MHD_lookup_connection_value (connection, | |
2229 | /* read the websocket key (required for the response) */ | 2221 | MHD_HEADER_KIND, |
2230 | value = MHD_lookup_connection_value (connection, MHD_HEADER_KIND, | ||
2231 | MHD_HTTP_HEADER_SEC_WEBSOCKET_KEY); | 2222 | MHD_HTTP_HEADER_SEC_WEBSOCKET_KEY); |
2232 | if (0 == value) | 2223 | if (0 != MHD_websocket_create_accept_header (value, sec_websocket_accept)) |
2233 | { | 2224 | { |
2234 | struct MHD_Response*response = MHD_create_response_from_buffer (strlen ( | 2225 | is_valid = 0; |
2235 | PAGE_INVALID_WEBSOCKET_REQUEST), | ||
2236 | PAGE_INVALID_WEBSOCKET_REQUEST, | ||
2237 | MHD_RESPMEM_PERSISTENT); | ||
2238 | ret = MHD_queue_response (connection, | ||
2239 | MHD_HTTP_BAD_REQUEST, | ||
2240 | response); | ||
2241 | MHD_destroy_response (response); | ||
2242 | return ret; | ||
2243 | } | 2226 | } |
2244 | 2227 | ||
2245 | /* generate the response accept header */ | 2228 | if (1 == is_valid) |
2246 | char sec_websocket_accept[29]; | ||
2247 | if (0 != MHD_websocket_create_accept (value, sec_websocket_accept)) | ||
2248 | { | 2229 | { |
2249 | struct MHD_Response*response = MHD_create_response_from_buffer (strlen ( | 2230 | /* create the response for upgrade */ |
2250 | PAGE_INVALID_WEBSOCKET_REQUEST), | 2231 | response = MHD_create_response_for_upgrade (&upgrade_handler, |
2251 | PAGE_INVALID_WEBSOCKET_REQUEST, | 2232 | NULL); |
2252 | MHD_RESPMEM_PERSISTENT); | 2233 | |
2234 | /** | ||
2235 | * For the response we need at least the following headers: | ||
2236 | * 1. "Connection: Upgrade" | ||
2237 | * 2. "Upgrade: websocket" | ||
2238 | * 3. "Sec-WebSocket-Accept: <base64value>" | ||
2239 | * The value for Sec-WebSocket-Accept can be generated with MHD_websocket_create_accept_header. | ||
2240 | * It requires the value of the Sec-WebSocket-Key header of the request. | ||
2241 | * See also: https://tools.ietf.org/html/rfc6455#section-4.2.2 | ||
2242 | */ | ||
2243 | MHD_add_response_header (response, | ||
2244 | MHD_HTTP_HEADER_CONNECTION, | ||
2245 | "Upgrade"); | ||
2246 | MHD_add_response_header (response, | ||
2247 | MHD_HTTP_HEADER_UPGRADE, | ||
2248 | "websocket"); | ||
2249 | MHD_add_response_header (response, | ||
2250 | MHD_HTTP_HEADER_SEC_WEBSOCKET_ACCEPT, | ||
2251 | sec_websocket_accept); | ||
2253 | ret = MHD_queue_response (connection, | 2252 | ret = MHD_queue_response (connection, |
2254 | MHD_HTTP_BAD_REQUEST, | 2253 | MHD_HTTP_SWITCHING_PROTOCOLS, |
2255 | response); | 2254 | response); |
2256 | MHD_destroy_response (response); | 2255 | MHD_destroy_response (response); |
2257 | return ret; | ||
2258 | } | 2256 | } |
2259 | 2257 | else | |
2260 | /* only for this example: don't accept incoming connection when we are already shutting down */ | ||
2261 | if (0 != disconnect_all) | ||
2262 | { | 2258 | { |
2259 | /* return error page */ | ||
2263 | struct MHD_Response*response = MHD_create_response_from_buffer (strlen ( | 2260 | struct MHD_Response*response = MHD_create_response_from_buffer (strlen ( |
2264 | PAGE_INVALID_WEBSOCKET_REQUEST), | 2261 | PAGE_INVALID_WEBSOCKET_REQUEST), |
2265 | PAGE_INVALID_WEBSOCKET_REQUEST, | 2262 | PAGE_INVALID_WEBSOCKET_REQUEST, |
2266 | MHD_RESPMEM_PERSISTENT); | 2263 | MHD_RESPMEM_PERSISTENT); |
2267 | ret = MHD_queue_response (connection, | 2264 | ret = MHD_queue_response (connection, |
2268 | MHD_HTTP_SERVICE_UNAVAILABLE, | 2265 | MHD_HTTP_BAD_REQUEST, |
2269 | response); | 2266 | response); |
2270 | MHD_destroy_response (response); | 2267 | MHD_destroy_response (response); |
2271 | return ret; | ||
2272 | } | 2268 | } |
2273 | |||
2274 | /* create the response for upgrade */ | ||
2275 | response = MHD_create_response_for_upgrade (&upgrade_handler, | ||
2276 | NULL); | ||
2277 | |||
2278 | /** | ||
2279 | * For the response we need at least the following headers: | ||
2280 | * 1. "Connection: Upgrade" | ||
2281 | * 2. "Upgrade: websocket" | ||
2282 | * 3. "Sec-WebSocket-Accept: <base64value>" | ||
2283 | * The value for Sec-WebSocket-Accept can be generated with MHD_websocket_create_accept. | ||
2284 | * It requires the value of the Sec-WebSocket-Key header of the request. | ||
2285 | * See also: https://tools.ietf.org/html/rfc6455#section-4.2.2 | ||
2286 | */ | ||
2287 | MHD_add_response_header (response, | ||
2288 | MHD_HTTP_HEADER_CONNECTION, | ||
2289 | "Upgrade"); | ||
2290 | MHD_add_response_header (response, | ||
2291 | MHD_HTTP_HEADER_UPGRADE, | ||
2292 | "websocket"); | ||
2293 | MHD_add_response_header (response, | ||
2294 | MHD_HTTP_HEADER_SEC_WEBSOCKET_ACCEPT, | ||
2295 | sec_websocket_accept); | ||
2296 | ret = MHD_queue_response (connection, | ||
2297 | MHD_HTTP_SWITCHING_PROTOCOLS, | ||
2298 | response); | ||
2299 | MHD_destroy_response (response); | ||
2300 | } | 2269 | } |
2301 | else | 2270 | else |
2302 | { | 2271 | { |
@@ -2353,7 +2322,7 @@ main (int argc, | |||
2353 | MHD_OPTION_END); | 2322 | MHD_OPTION_END); |
2354 | #endif | 2323 | #endif |
2355 | 2324 | ||
2356 | if (d == NULL) | 2325 | if (NULL == d) |
2357 | return 1; | 2326 | return 1; |
2358 | (void) getc (stdin); | 2327 | (void) getc (stdin); |
2359 | 2328 | ||