libmicrohttpd

HTTP/1.x server C library (MHD 1.x, stable)
Log | Files | Refs | Submodules | README | LICENSE

commit 8d50b032518b292acdda3a5f77edc1648bb51654
parent cd58a0e166ac041b37ea7b671cee3f501afe1aa4
Author: Evgeny Grin (Karlson2k) <k2k@narod.ru>
Date:   Thu,  9 Dec 2021 13:33:50 +0300

Revert formatting broken by uncrustify

This partially reverts commit dbe1d76d9c75a95a7ebe3042dfac7e6a7392bfb0.

Looks like uncrustify has some bug resulting in C++ style comments

Diffstat:
Msrc/examples/websocket_chatserver_example.c | 846++++++++++++++++++++++++++++++++++++++++----------------------------------------
Msrc/examples/websocket_threaded_example.c | 66+++++++++++++++++++++++++++++++++---------------------------------
2 files changed, 456 insertions(+), 456 deletions(-)

diff --git a/src/examples/websocket_chatserver_example.c b/src/examples/websocket_chatserver_example.c @@ -186,429 +186,429 @@ " function window_onload(event)\n" \ " {\n" \ " // Determine the base url (for http:// this is ws:// for https:// this must be wss://)\n" \ - // " baseUrl = 'ws' + (window.location.protocol === 'https:' ? 's' : '') + '://' + window.location.host + '/ChatServerWebSocket';\n" \ - // " chat_generate();\n" \ - // " chat_connect();\n" \ - // " }\n" \ - // "\n" \ - // " /**\n" \ - // " This function generates the chat using DOM\n" \ - // " */\n" \ - // " function chat_generate()\n" \ - // " {\n" \ - // " document.body.innerHTML = '';\n" \ - // " let chat = document.createElement('div');\n" \ - // " document.body.appendChild(chat);\n" \ - // " chat.id = 'Chat';\n" \ - // " let messagesAndInput = document.createElement('div');\n" \ - // " chat.appendChild(messagesAndInput);\n" \ - // " messagesAndInput.classList.add('MessagesAndInput');\n" \ - // " let messages = document.createElement('div');\n" \ - // " messagesAndInput.appendChild(messages);\n" \ - // " messages.id = 'Messages';\n" \ - // " let input = document.createElement('div');\n" \ - // " messagesAndInput.appendChild(input);\n" \ - // " input.classList.add('Input');\n" \ - // " let inputMessage = document.createElement('input');\n" \ - // " input.appendChild(inputMessage);\n" \ - // " inputMessage.type = 'text';\n" \ - // " inputMessage.id = 'InputMessage';\n" \ - // " inputMessage.disabled = true;\n" \ - // " inputMessage.addEventListener('keydown', chat_onKeyDown);\n" \ - // " let inputMessageSend = document.createElement('button');\n" \ - // " input.appendChild(inputMessageSend);\n" \ - // " inputMessageSend.id = 'InputMessageButton';\n" \ - // " inputMessageSend.disabled = true;\n" \ - // " inputMessageSend.innerText = 'send';\n" \ - // " inputMessageSend.addEventListener('click', chat_onSendClicked);\n" \ - // " let inputImage = document.createElement('input');\n" \ - // " input.appendChild(inputImage);\n" \ - // " inputImage.id = 'InputImage';\n" \ - // " inputImage.type = 'file';\n" \ - // " inputImage.accept = 'image/*';\n" \ - // " inputImage.style.display = 'none';\n" \ - // " inputImage.addEventListener('change', chat_onImageSelected);\n" \ - // " let inputImageButton = document.createElement('button');\n" \ - // " input.appendChild(inputImageButton);\n" \ - // " inputImageButton.id = 'InputImageButton';\n" \ - // " inputImageButton.disabled = true;\n" \ - // " inputImageButton.innerText = 'image';\n" \ - // " inputImageButton.addEventListener('click', chat_onImageClicked);\n" \ - // " let users = document.createElement('div');\n" \ - // " chat.appendChild(users);\n" \ - // " users.id = 'Users';\n" \ - // " users.addEventListener('click', chat_onUserClicked);\n" \ - // " let allUsers = document.createElement('div');\n" \ - // " users.appendChild(allUsers);\n" \ - // " allUsers.classList.add('selected');\n" \ - // " allUsers.innerText = '<everyone>';\n" \ - // " allUsers.setAttribute('data-user', '0');\n" \ - // " }\n" \ - // "\n" \ - // " /**\n" \ - // " This function creates and connects a WebSocket\n" \ - // " */\n" \ - // " function chat_connect()\n" \ - // " {\n" \ - // " chat_addMessage(`Connecting to libmicrohttpd chat server demo (${baseUrl})...`, { type: 'system' });\n" \ - // " socket = new WebSocket(baseUrl);\n" \ - // " socket.binaryType = 'arraybuffer';\n" \ - // " socket.onopen = socket_onopen;\n" \ - // " socket.onclose = socket_onclose;\n" \ - // " socket.onerror = socket_onerror;\n" \ - // " socket.onmessage = socket_onmessage;\n" \ - // " }\n" \ - // "\n" \ - // " /**\n" \ - // " This function adds new text to the chat list\n" \ - // " */\n" \ - // " function chat_addMessage(text, options)\n" \ - // " {\n" \ - // " let type = options && options.type || 'regular';\n" \ - // " if(!/^(?:regular|system|error|private|moderator)$/.test(type))\n" \ - // " type = 'regular';\n" \ - // " let message = document.createElement('div');\n" \ - // " message.classList.add('Message');\n" \ - // " message.classList.add(type);\n" \ - // " if(typeof(text) === 'string')\n" \ - // " {\n" \ - // " let content = document.createElement('span');\n" \ - // " message.appendChild(content);\n" \ - // " if(options && options.from)\n" \ - // " content.innerText = `${options.from}: ${text}`;\n" \ - // " else\n" \ - // " content.innerText = text;\n" \ - // " if(options && options.reconnect)\n" \ - // " {\n" \ - // " let span = document.createElement('span');\n" \ - // " span.appendChild(document.createTextNode(' ('));\n" \ - // " let reconnect = document.createElement('a');\n" \ - // " reconnect.href = 'javascript:chat_connect()';\n" \ - // " reconnect.innerText = 'reconnect';\n" \ - // " span.appendChild(reconnect);\n" \ - // " span.appendChild(document.createTextNode(')'));\n" \ - // " message.appendChild(span);\n" \ - // " }\n" \ - // " }\n" \ - // " else\n" \ - // " {\n" \ - // " let content = document.createElement('span');\n" \ - // " message.appendChild(content);\n" \ - // " if(options && options.from)\n" \ - // " {\n" \ - // " content.innerText = `${options.from}:\\n`;\n" \ - // " }\n" \ - // " if(options && options.pictureType && text instanceof Uint8Array)\n" \ - // " {\n" \ - // " let img = document.createElement('img');\n" \ - // " content.appendChild(img);\n" \ - // " img.src = URL.createObjectURL(new Blob([ text.buffer ], { type: options.pictureType }));\n" \ - // " }\n" \ - // " }\n" \ - // " document.getElementById('Messages').appendChild(message);\n" \ - // " message.scrollIntoView();\n" \ - // " }\n" \ - // "\n" \ - // " /**\n" \ - // " This is a keydown event handler, which allows that you can just press enter instead of clicking the 'send' button\n" \ - // " */\n" \ - // " function chat_onKeyDown(event)\n" \ - // " {\n" \ - // " if(event.key == 'Enter')\n" \ - // " chat_onSendClicked();\n" \ - // " }\n" \ - // "\n" \ - // " /**\n" \ - // " This is the code to send a message or command, when clicking the 'send' button\n" \ - // " */\n" \ - // " function chat_onSendClicked(event)\n" \ - // " {\n" \ - // " let message = document.getElementById('InputMessage').value;\n" \ - // " if(message.length == 0)\n" \ - // " return;\n" \ - // " if(message.substr(0, 1) == '/')\n" \ - // " {\n" \ - // " // command\n" \ - // " let match;\n" \ - // " if(/^\\/disconnect\\s*$/.test(message))\n" \ - // " {\n" \ - // " socket.close(1000);\n" \ - // " }\n" \ - // " else if((match = /^\\/m\\s+(\\S+)\\s+/.exec(message)))\n" \ - // " {\n" \ - // " message = message.substr(match[0].length);\n" \ - // " let userId = chat_getUserIdByName(match[1]);\n" \ - // " if(userId !== null)\n" \ - // " {\n" \ - // " socket.send(`private|${userId}|${message}`);\n" \ - // " }\n" \ - // " else\n" \ - // " {\n" \ - // " chat_addMessage(`Unknown user \"${match[1]}\" for private message: ${message}`, { type: 'error' });\n" \ - // " }\n" \ - // " }\n" \ - // " else if((match = /^\\/ping\\s+(\\S+)\\s*$/.exec(message)))\n" \ - // " {\n" \ - // " let userId = chat_getUserIdByName(match[1]);\n" \ - // " if(userId !== null)\n" \ - // " {\n" \ - // " socket.send(`ping|${userId}|`);\n" \ - // " }\n" \ - // " else\n" \ - // " {\n" \ - // " chat_addMessage(`Unknown user \"${match[1]}\" for ping`, { type: 'error' });\n" \ - // " }\n" \ - // " }\n" \ - // " else if((match = /^\\/name\\s+(\\S+)\\s*$/.exec(message)))\n" \ - // " {\n" \ - // " socket.send(`name||${match[1]}`);\n" \ - // " }\n" \ - // " else\n" \ - // " {\n" \ - // " chat_addMessage(`Unsupported command or invalid syntax: ${message}`, { type: 'error' });\n" \ - // " }\n" \ - // " }\n" \ - // " else\n" \ - // " {\n" \ - // " // regular chat message to the selected user\n" \ - // " let selectedUser = document.querySelector('div#Users > div.selected');\n" \ - // " let selectedUserId = parseInt(selectedUser.getAttribute('data-user') || '0', 10);\n" \ - // " if(selectedUserId == 0)\n" \ - // " socket.send(`||${message}`);\n" \ - // " else\n" \ - // " socket.send(`private|${selectedUserId}|${message}`);\n" \ - // " }\n" \ - // " document.getElementById('InputMessage').value = '';\n" \ - // " }\n" \ - // "\n" \ - // " /**\n" \ - // " This is the event when the user hits the 'image' button\n" \ - // " */\n" \ - // " function chat_onImageClicked(event)\n" \ - // " {\n" \ - // " document.getElementById('InputImage').click();\n" \ - // " }\n" \ - // "\n" \ - // " /**\n" \ - // " This is the event when the user selected an image.\n" \ - // " The image will be read with the FileReader (allowed in web, because the user selected the file).\n" \ - // " */\n" \ - // " function chat_onImageSelected(event)\n" \ - // " {\n" \ - // " let file = event.target.files[0];\n" \ - // " if(!file || !/^image\\//.test(file.type))\n" \ - // " return;\n" \ - // " let selectedUser = document.querySelector('div#Users > div.selected');\n" \ - // " let selectedUserId = parseInt(selectedUser.getAttribute('data-user') || '0', 10);\n" \ - // " let reader = new FileReader();\n" \ - // " reader.onload = function(event) {\n" \ - // " chat_onImageRead(event, file.type, selectedUserId);\n" \ - // " };\n" \ - // " reader.readAsArrayBuffer(file);\n" \ - // " }\n" \ - // "\n" \ - // " /**\n" \ - // " This is the event when the user selected image has been read.\n" \ - // " This will add our chat protocol prefix and send it via the websocket.\n" \ - // " */\n" \ - // " function chat_onImageRead(event, fileType, selectedUserId)\n" \ - // " {\n" \ - // " let encoder = new TextEncoder();\n" \ - // " let prefix = ((selectedUserId == 0 ? '||' : `private|${selectedUserId}|`) + fileType + '|');\n" \ - // " prefix = encoder.encode(prefix);\n" \ - // " let byteData = new Uint8Array(event.target.result);\n" \ - // " let totalLength = prefix.length + byteData.length;\n" \ - // " let resultByteData = new Uint8Array(totalLength);\n" \ - // " resultByteData.set(prefix, 0);\n" \ - // " resultByteData.set(byteData, prefix.length);\n" \ - // " socket.send(resultByteData);\n" \ - // " }\n" \ - // "\n" \ - // " /**\n" \ - // " This is the event when the user clicked a name in the user list.\n" \ - // " This is useful to send private messages or images without needing to add the /m prefix.\n" \ - // " */\n" \ - // " function chat_onUserClicked(event, selectedUserId)\n" \ - // " {\n" \ - // " let newSelected = event.target.closest('div#Users > div');\n" \ - // " if(newSelected === null)\n" \ - // " return;\n" \ - // " for(let div of this.querySelectorAll(':scope > div.selected'))\n" \ - // " div.classList.remove('selected');\n" \ - // " newSelected.classList.add('selected');\n" \ - // " }\n" \ - // "\n" \ - // " /**\n" \ - // " This functions returns the current id of a user identified by its name.\n" \ - // " */\n" \ - // " function chat_getUserIdByName(name)\n" \ - // " {\n" \ - // " let nameUpper = name.toUpperCase();\n" \ - // " for(let pair of connectedUsers)\n" \ - // " {\n" \ - // " if(pair[1].toUpperCase() == nameUpper)\n" \ - // " return pair[0];\n" \ - // " }\n" \ - // " return null;\n" \ - // " }\n" \ - // "\n" \ - // " /**\n" \ - // " This functions clears the entire user list (needed for reconnecting).\n" \ - // " */\n" \ - // " function chat_clearUserList()\n" \ - // " {\n" \ - // " let users = document.getElementById('Users');\n" \ - // " for(let div of users.querySelectorAll(':scope > div'))\n" \ - // " {\n" \ - // " if(div.getAttribute('data-user') === '0')\n" \ - // " {\n" \ - // " div.classList.add('selected');\n" \ - // " }\n" \ - // " else\n" \ - // " {\n" \ - // " div.parentNode.removeChild(div);\n" \ - // " }\n" \ - // " }\n" \ - // " return null;\n" \ - // " }\n" \ - // "\n" \ - // " /**\n" \ - // " This is the event when the socket has established a connection.\n" \ - // " This will initialize an empty chat and enable the controls.\n" \ - // " */\n" \ - // " function socket_onopen(event)\n" \ - // " {\n" \ - // " connectedUsers.clear();\n" \ - // " chat_clearUserList();\n" \ - // " chat_addMessage('Connected!', { type: 'system' });\n" \ - // " document.getElementById('InputMessage').disabled = false;\n" \ - // " document.getElementById('InputMessageButton').disabled = false;\n" \ - // " document.getElementById('InputImageButton').disabled = false;\n" \ - // " }\n" \ - // "\n" \ - // " /**\n" \ - // " This is the event when the socket has been closed.\n" \ - // " This will lock the controls.\n" \ - // " */\n" \ - // " function socket_onclose(event)\n" \ - // " {\n" \ - // " chat_addMessage('Connection closed!', { type: 'system', reconnect: true });\n" \ - // " document.getElementById('InputMessage').disabled = true;\n" \ - // " document.getElementById('InputMessageButton').disabled = true;\n" \ - // " document.getElementById('InputImageButton').disabled = true;\n" \ - // " }\n" \ - // "\n" \ - // " /**\n" \ - // " This is the event when the socket reported an error.\n" \ - // " This will just make an output.\n" \ - // " In the web browser console (F12 on many browsers) will show you more detailed error information.\n" \ - // " */\n" \ - // " function socket_onerror(event)\n" \ - // " {\n" \ - // " console.error('WebSocket error reported: ', event);\n" \ - // " chat_addMessage('The socket reported an error!', { type: 'error' });\n" \ - // " }\n" \ - // "\n" \ - // " /**\n" \ - // " This is the event when the socket has received a message.\n" \ - // " This will parse the message and execute the corresponding command (or add the message).\n" \ - // " */\n" \ - // " function socket_onmessage(event)\n" \ - // " {\n" \ - // " if(typeof(event.data) === 'string')\n" \ - // " {\n" \ - // " // text message or command\n" \ - // " let message = event.data.split('|', 3);\n" \ - // " switch(message[0])\n" \ - // " {\n" \ - // " case 'userinit':\n" \ - // " connectedUsers.set(message[1], message[2]);\n" \ - // " {\n" \ - // " let users = document.getElementById('Users');\n" \ - // " let div = document.createElement('div');\n" \ - // " users.appendChild(div);\n" \ - // " div.innerText = message[2];\n" \ - // " div.setAttribute('data-user', message[1]);\n" \ - // " }\n" \ - // " break;\n" \ - // " case 'useradd':\n" \ - // " connectedUsers.set(message[1], message[2]);\n" \ - // " chat_addMessage(`The user '${message[2]}' has joined our lovely chatroom.`, { type: 'moderator' });\n" \ - // " {\n" \ - // " let users = document.getElementById('Users');\n" \ - // " let div = document.createElement('div');\n" \ - // " users.appendChild(div);\n" \ - // " div.innerText = message[2];\n" \ - // " div.setAttribute('data-user', message[1]);\n" \ - // " }\n" \ - // " break;\n" \ - // " case 'userdel':\n" \ - // " chat_addMessage(`The user '${connectedUsers.get(message[1])}' has left our chatroom. We will miss you.`, { type: 'moderator' });\n" \ - // " connectedUsers.delete(message[1]);\n" \ - // " {\n" \ - // " let users = document.getElementById('Users');\n" \ - // " let div = users.querySelector(`div[data-user='${message[1]}']`);\n" \ - // " if(div !== null)\n" \ - // " {\n" \ - // " users.removeChild(div);\n" \ - // " if(div.classList.contains('selected'))\n" \ - // " users.querySelector('div[data-user=\\'0\\']').classList.add('selected');\n" \ - // " }\n" \ - // " }\n" \ - // " break;\n" \ - // " case 'username':\n" \ - // " chat_addMessage(`The user '${connectedUsers.get(message[1])}' has changed his name to '${message[2]}'.`, { type: 'moderator' });\n" \ - // " connectedUsers.set(message[1], message[2]);\n" \ - // " {\n" \ - // " let users = document.getElementById('Users');\n" \ - // " let div = users.querySelector(`div[data-user='${message[1]}']`);\n" \ - // " if(div !== null)\n" \ - // " {\n" \ - // " div.innerText = message[2];\n" \ - // " }\n" \ - // " }\n" \ - // " break;\n" \ - // " case 'ping':\n" \ - // " chat_addMessage(`The user '${connectedUsers.get(message[1])}' has a ping of ${message[2]} ms.`, { type: 'moderator' });\n" \ - // " break;\n" \ - // " default:\n" \ - // " chat_addMessage(message[2], { type: message[0], from: connectedUsers.get(message[1]) });\n" \ - // " break;\n" \ - // " }\n" \ - // " }\n" \ - // " else\n" \ - // " {\n" \ - // " // We received a binary frame, which means a picture here\n" \ - // " let byteData = new Uint8Array(event.data);\n" \ - // " let decoder = new TextDecoder();\n" \ - // " let message = [ ];\n" \ - // " // message type\n" \ - // " let j = 0;\n" \ - // " let i = byteData.indexOf(0x7C, j); // | = 0x7C;\n" \ - // " if(i < 0)\n" \ - // " return;\n" \ - // " message.push(decoder.decode(byteData.slice(0, i)));\n" \ - // " // picture from\n" \ - // " j = i + 1;\n" \ - // " i = byteData.indexOf(0x7C, j);\n" \ - // " if(i < 0)\n" \ - // " return;\n" \ - // " message.push(decoder.decode(byteData.slice(j, i)));\n" \ - // " // picture encoding\n" \ - // " j = i + 1;\n" \ - // " i = byteData.indexOf(0x7C, j);\n" \ - // " if(i < 0)\n" \ - // " return;\n" \ - // " message.push(decoder.decode(byteData.slice(j, i)));\n" \ - // " // picture\n" \ - // " byteData = byteData.slice(i + 1);\n" \ - // " chat_addMessage(byteData, { type: message[0], from: connectedUsers.get(message[1]), pictureType: message[2] });\n" \ - // " }\n" \ - // " }\n" \ - // "</script>" \ - // "</head>" \ - // "<body><noscript>Please enable JavaScript to test the libmicrohttpd Websocket chatserver demo!</noscript></body>" \ - // "</html>" + " baseUrl = 'ws' + (window.location.protocol === 'https:' ? 's' : '') + '://' + window.location.host + '/ChatServerWebSocket';\n" \ + " chat_generate();\n" \ + " chat_connect();\n" \ + " }\n" \ + "\n" \ + " /**\n" \ + " This function generates the chat using DOM\n" \ + " */\n" \ + " function chat_generate()\n" \ + " {\n" \ + " document.body.innerHTML = '';\n" \ + " let chat = document.createElement('div');\n" \ + " document.body.appendChild(chat);\n" \ + " chat.id = 'Chat';\n" \ + " let messagesAndInput = document.createElement('div');\n" \ + " chat.appendChild(messagesAndInput);\n" \ + " messagesAndInput.classList.add('MessagesAndInput');\n" \ + " let messages = document.createElement('div');\n" \ + " messagesAndInput.appendChild(messages);\n" \ + " messages.id = 'Messages';\n" \ + " let input = document.createElement('div');\n" \ + " messagesAndInput.appendChild(input);\n" \ + " input.classList.add('Input');\n" \ + " let inputMessage = document.createElement('input');\n" \ + " input.appendChild(inputMessage);\n" \ + " inputMessage.type = 'text';\n" \ + " inputMessage.id = 'InputMessage';\n" \ + " inputMessage.disabled = true;\n" \ + " inputMessage.addEventListener('keydown', chat_onKeyDown);\n" \ + " let inputMessageSend = document.createElement('button');\n" \ + " input.appendChild(inputMessageSend);\n" \ + " inputMessageSend.id = 'InputMessageButton';\n" \ + " inputMessageSend.disabled = true;\n" \ + " inputMessageSend.innerText = 'send';\n" \ + " inputMessageSend.addEventListener('click', chat_onSendClicked);\n" \ + " let inputImage = document.createElement('input');\n" \ + " input.appendChild(inputImage);\n" \ + " inputImage.id = 'InputImage';\n" \ + " inputImage.type = 'file';\n" \ + " inputImage.accept = 'image/*';\n" \ + " inputImage.style.display = 'none';\n" \ + " inputImage.addEventListener('change', chat_onImageSelected);\n" \ + " let inputImageButton = document.createElement('button');\n" \ + " input.appendChild(inputImageButton);\n" \ + " inputImageButton.id = 'InputImageButton';\n" \ + " inputImageButton.disabled = true;\n" \ + " inputImageButton.innerText = 'image';\n" \ + " inputImageButton.addEventListener('click', chat_onImageClicked);\n" \ + " let users = document.createElement('div');\n" \ + " chat.appendChild(users);\n" \ + " users.id = 'Users';\n" \ + " users.addEventListener('click', chat_onUserClicked);\n" \ + " let allUsers = document.createElement('div');\n" \ + " users.appendChild(allUsers);\n" \ + " allUsers.classList.add('selected');\n" \ + " allUsers.innerText = '<everyone>';\n" \ + " allUsers.setAttribute('data-user', '0');\n" \ + " }\n" \ + "\n" \ + " /**\n" \ + " This function creates and connects a WebSocket\n" \ + " */\n" \ + " function chat_connect()\n" \ + " {\n" \ + " chat_addMessage(`Connecting to libmicrohttpd chat server demo (${baseUrl})...`, { type: 'system' });\n" \ + " socket = new WebSocket(baseUrl);\n" \ + " socket.binaryType = 'arraybuffer';\n" \ + " socket.onopen = socket_onopen;\n" \ + " socket.onclose = socket_onclose;\n" \ + " socket.onerror = socket_onerror;\n" \ + " socket.onmessage = socket_onmessage;\n" \ + " }\n" \ + "\n" \ + " /**\n" \ + " This function adds new text to the chat list\n" \ + " */\n" \ + " function chat_addMessage(text, options)\n" \ + " {\n" \ + " let type = options && options.type || 'regular';\n" \ + " if(!/^(?:regular|system|error|private|moderator)$/.test(type))\n" \ + " type = 'regular';\n" \ + " let message = document.createElement('div');\n" \ + " message.classList.add('Message');\n" \ + " message.classList.add(type);\n" \ + " if(typeof(text) === 'string')\n" \ + " {\n" \ + " let content = document.createElement('span');\n" \ + " message.appendChild(content);\n" \ + " if(options && options.from)\n" \ + " content.innerText = `${options.from}: ${text}`;\n" \ + " else\n" \ + " content.innerText = text;\n" \ + " if(options && options.reconnect)\n" \ + " {\n" \ + " let span = document.createElement('span');\n" \ + " span.appendChild(document.createTextNode(' ('));\n" \ + " let reconnect = document.createElement('a');\n" \ + " reconnect.href = 'javascript:chat_connect()';\n" \ + " reconnect.innerText = 'reconnect';\n" \ + " span.appendChild(reconnect);\n" \ + " span.appendChild(document.createTextNode(')'));\n" \ + " message.appendChild(span);\n" \ + " }\n" \ + " }\n" \ + " else\n" \ + " {\n" \ + " let content = document.createElement('span');\n" \ + " message.appendChild(content);\n" \ + " if(options && options.from)\n" \ + " {\n" \ + " content.innerText = `${options.from}:\\n`;\n" \ + " }\n" \ + " if(options && options.pictureType && text instanceof Uint8Array)\n" \ + " {\n" \ + " let img = document.createElement('img');\n" \ + " content.appendChild(img);\n" \ + " img.src = URL.createObjectURL(new Blob([ text.buffer ], { type: options.pictureType }));\n" \ + " }\n" \ + " }\n" \ + " document.getElementById('Messages').appendChild(message);\n" \ + " message.scrollIntoView();\n" \ + " }\n" \ + "\n" \ + " /**\n" \ + " This is a keydown event handler, which allows that you can just press enter instead of clicking the 'send' button\n" \ + " */\n" \ + " function chat_onKeyDown(event)\n" \ + " {\n" \ + " if(event.key == 'Enter')\n" \ + " chat_onSendClicked();\n" \ + " }\n" \ + "\n" \ + " /**\n" \ + " This is the code to send a message or command, when clicking the 'send' button\n" \ + " */\n" \ + " function chat_onSendClicked(event)\n" \ + " {\n" \ + " let message = document.getElementById('InputMessage').value;\n" \ + " if(message.length == 0)\n" \ + " return;\n" \ + " if(message.substr(0, 1) == '/')\n" \ + " {\n" \ + " // command\n" \ + " let match;\n" \ + " if(/^\\/disconnect\\s*$/.test(message))\n" \ + " {\n" \ + " socket.close(1000);\n" \ + " }\n" \ + " else if((match = /^\\/m\\s+(\\S+)\\s+/.exec(message)))\n" \ + " {\n" \ + " message = message.substr(match[0].length);\n" \ + " let userId = chat_getUserIdByName(match[1]);\n" \ + " if(userId !== null)\n" \ + " {\n" \ + " socket.send(`private|${userId}|${message}`);\n" \ + " }\n" \ + " else\n" \ + " {\n" \ + " chat_addMessage(`Unknown user \"${match[1]}\" for private message: ${message}`, { type: 'error' });\n" \ + " }\n" \ + " }\n" \ + " else if((match = /^\\/ping\\s+(\\S+)\\s*$/.exec(message)))\n" \ + " {\n" \ + " let userId = chat_getUserIdByName(match[1]);\n" \ + " if(userId !== null)\n" \ + " {\n" \ + " socket.send(`ping|${userId}|`);\n" \ + " }\n" \ + " else\n" \ + " {\n" \ + " chat_addMessage(`Unknown user \"${match[1]}\" for ping`, { type: 'error' });\n" \ + " }\n" \ + " }\n" \ + " else if((match = /^\\/name\\s+(\\S+)\\s*$/.exec(message)))\n" \ + " {\n" \ + " socket.send(`name||${match[1]}`);\n" \ + " }\n" \ + " else\n" \ + " {\n" \ + " chat_addMessage(`Unsupported command or invalid syntax: ${message}`, { type: 'error' });\n" \ + " }\n" \ + " }\n" \ + " else\n" \ + " {\n" \ + " // regular chat message to the selected user\n" \ + " let selectedUser = document.querySelector('div#Users > div.selected');\n" \ + " let selectedUserId = parseInt(selectedUser.getAttribute('data-user') || '0', 10);\n" \ + " if(selectedUserId == 0)\n" \ + " socket.send(`||${message}`);\n" \ + " else\n" \ + " socket.send(`private|${selectedUserId}|${message}`);\n" \ + " }\n" \ + " document.getElementById('InputMessage').value = '';\n" \ + " }\n" \ + "\n" \ + " /**\n" \ + " This is the event when the user hits the 'image' button\n" \ + " */\n" \ + " function chat_onImageClicked(event)\n" \ + " {\n" \ + " document.getElementById('InputImage').click();\n" \ + " }\n" \ + "\n" \ + " /**\n" \ + " This is the event when the user selected an image.\n" \ + " The image will be read with the FileReader (allowed in web, because the user selected the file).\n" \ + " */\n" \ + " function chat_onImageSelected(event)\n" \ + " {\n" \ + " let file = event.target.files[0];\n" \ + " if(!file || !/^image\\//.test(file.type))\n" \ + " return;\n" \ + " let selectedUser = document.querySelector('div#Users > div.selected');\n" \ + " let selectedUserId = parseInt(selectedUser.getAttribute('data-user') || '0', 10);\n" \ + " let reader = new FileReader();\n" \ + " reader.onload = function(event) {\n" \ + " chat_onImageRead(event, file.type, selectedUserId);\n" \ + " };\n" \ + " reader.readAsArrayBuffer(file);\n" \ + " }\n" \ + "\n" \ + " /**\n" \ + " This is the event when the user selected image has been read.\n" \ + " This will add our chat protocol prefix and send it via the websocket.\n" \ + " */\n" \ + " function chat_onImageRead(event, fileType, selectedUserId)\n" \ + " {\n" \ + " let encoder = new TextEncoder();\n" \ + " let prefix = ((selectedUserId == 0 ? '||' : `private|${selectedUserId}|`) + fileType + '|');\n" \ + " prefix = encoder.encode(prefix);\n" \ + " let byteData = new Uint8Array(event.target.result);\n" \ + " let totalLength = prefix.length + byteData.length;\n" \ + " let resultByteData = new Uint8Array(totalLength);\n" \ + " resultByteData.set(prefix, 0);\n" \ + " resultByteData.set(byteData, prefix.length);\n" \ + " socket.send(resultByteData);\n" \ + " }\n" \ + "\n" \ + " /**\n" \ + " This is the event when the user clicked a name in the user list.\n" \ + " This is useful to send private messages or images without needing to add the /m prefix.\n" \ + " */\n" \ + " function chat_onUserClicked(event, selectedUserId)\n" \ + " {\n" \ + " let newSelected = event.target.closest('div#Users > div');\n" \ + " if(newSelected === null)\n" \ + " return;\n" \ + " for(let div of this.querySelectorAll(':scope > div.selected'))\n" \ + " div.classList.remove('selected');\n" \ + " newSelected.classList.add('selected');\n" \ + " }\n" \ + "\n" \ + " /**\n" \ + " This functions returns the current id of a user identified by its name.\n" \ + " */\n" \ + " function chat_getUserIdByName(name)\n" \ + " {\n" \ + " let nameUpper = name.toUpperCase();\n" \ + " for(let pair of connectedUsers)\n" \ + " {\n" \ + " if(pair[1].toUpperCase() == nameUpper)\n" \ + " return pair[0];\n" \ + " }\n" \ + " return null;\n" \ + " }\n" \ + "\n" \ + " /**\n" \ + " This functions clears the entire user list (needed for reconnecting).\n" \ + " */\n" \ + " function chat_clearUserList()\n" \ + " {\n" \ + " let users = document.getElementById('Users');\n" \ + " for(let div of users.querySelectorAll(':scope > div'))\n" \ + " {\n" \ + " if(div.getAttribute('data-user') === '0')\n" \ + " {\n" \ + " div.classList.add('selected');\n" \ + " }\n" \ + " else\n" \ + " {\n" \ + " div.parentNode.removeChild(div);\n" \ + " }\n" \ + " }\n" \ + " return null;\n" \ + " }\n" \ + "\n" \ + " /**\n" \ + " This is the event when the socket has established a connection.\n" \ + " This will initialize an empty chat and enable the controls.\n" \ + " */\n" \ + " function socket_onopen(event)\n" \ + " {\n" \ + " connectedUsers.clear();\n" \ + " chat_clearUserList();\n" \ + " chat_addMessage('Connected!', { type: 'system' });\n" \ + " document.getElementById('InputMessage').disabled = false;\n" \ + " document.getElementById('InputMessageButton').disabled = false;\n" \ + " document.getElementById('InputImageButton').disabled = false;\n" \ + " }\n" \ + "\n" \ + " /**\n" \ + " This is the event when the socket has been closed.\n" \ + " This will lock the controls.\n" \ + " */\n" \ + " function socket_onclose(event)\n" \ + " {\n" \ + " chat_addMessage('Connection closed!', { type: 'system', reconnect: true });\n" \ + " document.getElementById('InputMessage').disabled = true;\n" \ + " document.getElementById('InputMessageButton').disabled = true;\n" \ + " document.getElementById('InputImageButton').disabled = true;\n" \ + " }\n" \ + "\n" \ + " /**\n" \ + " This is the event when the socket reported an error.\n" \ + " This will just make an output.\n" \ + " In the web browser console (F12 on many browsers) will show you more detailed error information.\n" \ + " */\n" \ + " function socket_onerror(event)\n" \ + " {\n" \ + " console.error('WebSocket error reported: ', event);\n" \ + " chat_addMessage('The socket reported an error!', { type: 'error' });\n" \ + " }\n" \ + "\n" \ + " /**\n" \ + " This is the event when the socket has received a message.\n" \ + " This will parse the message and execute the corresponding command (or add the message).\n" \ + " */\n" \ + " function socket_onmessage(event)\n" \ + " {\n" \ + " if(typeof(event.data) === 'string')\n" \ + " {\n" \ + " // text message or command\n" \ + " let message = event.data.split('|', 3);\n" \ + " switch(message[0])\n" \ + " {\n" \ + " case 'userinit':\n" \ + " connectedUsers.set(message[1], message[2]);\n" \ + " {\n" \ + " let users = document.getElementById('Users');\n" \ + " let div = document.createElement('div');\n" \ + " users.appendChild(div);\n" \ + " div.innerText = message[2];\n" \ + " div.setAttribute('data-user', message[1]);\n" \ + " }\n" \ + " break;\n" \ + " case 'useradd':\n" \ + " connectedUsers.set(message[1], message[2]);\n" \ + " chat_addMessage(`The user '${message[2]}' has joined our lovely chatroom.`, { type: 'moderator' });\n" \ + " {\n" \ + " let users = document.getElementById('Users');\n" \ + " let div = document.createElement('div');\n" \ + " users.appendChild(div);\n" \ + " div.innerText = message[2];\n" \ + " div.setAttribute('data-user', message[1]);\n" \ + " }\n" \ + " break;\n" \ + " case 'userdel':\n" \ + " chat_addMessage(`The user '${connectedUsers.get(message[1])}' has left our chatroom. We will miss you.`, { type: 'moderator' });\n" \ + " connectedUsers.delete(message[1]);\n" \ + " {\n" \ + " let users = document.getElementById('Users');\n" \ + " let div = users.querySelector(`div[data-user='${message[1]}']`);\n" \ + " if(div !== null)\n" \ + " {\n" \ + " users.removeChild(div);\n" \ + " if(div.classList.contains('selected'))\n" \ + " users.querySelector('div[data-user=\\'0\\']').classList.add('selected');\n" \ + " }\n" \ + " }\n" \ + " break;\n" \ + " case 'username':\n" \ + " chat_addMessage(`The user '${connectedUsers.get(message[1])}' has changed his name to '${message[2]}'.`, { type: 'moderator' });\n" \ + " connectedUsers.set(message[1], message[2]);\n" \ + " {\n" \ + " let users = document.getElementById('Users');\n" \ + " let div = users.querySelector(`div[data-user='${message[1]}']`);\n" \ + " if(div !== null)\n" \ + " {\n" \ + " div.innerText = message[2];\n" \ + " }\n" \ + " }\n" \ + " break;\n" \ + " case 'ping':\n" \ + " chat_addMessage(`The user '${connectedUsers.get(message[1])}' has a ping of ${message[2]} ms.`, { type: 'moderator' });\n" \ + " break;\n" \ + " default:\n" \ + " chat_addMessage(message[2], { type: message[0], from: connectedUsers.get(message[1]) });\n" \ + " break;\n" \ + " }\n" \ + " }\n" \ + " else\n" \ + " {\n" \ + " // We received a binary frame, which means a picture here\n" \ + " let byteData = new Uint8Array(event.data);\n" \ + " let decoder = new TextDecoder();\n" \ + " let message = [ ];\n" \ + " // message type\n" \ + " let j = 0;\n" \ + " let i = byteData.indexOf(0x7C, j); // | = 0x7C;\n" \ + " if(i < 0)\n" \ + " return;\n" \ + " message.push(decoder.decode(byteData.slice(0, i)));\n" \ + " // picture from\n" \ + " j = i + 1;\n" \ + " i = byteData.indexOf(0x7C, j);\n" \ + " if(i < 0)\n" \ + " return;\n" \ + " message.push(decoder.decode(byteData.slice(j, i)));\n" \ + " // picture encoding\n" \ + " j = i + 1;\n" \ + " i = byteData.indexOf(0x7C, j);\n" \ + " if(i < 0)\n" \ + " return;\n" \ + " message.push(decoder.decode(byteData.slice(j, i)));\n" \ + " // picture\n" \ + " byteData = byteData.slice(i + 1);\n" \ + " chat_addMessage(byteData, { type: message[0], from: connectedUsers.get(message[1]), pictureType: message[2] });\n" \ + " }\n" \ + " }\n" \ + "</script>" \ + "</head>" \ + "<body><noscript>Please enable JavaScript to test the libmicrohttpd Websocket chatserver demo!</noscript></body>" \ + "</html>" #define PAGE_NOT_FOUND \ "404 Not Found" diff --git a/src/examples/websocket_threaded_example.c b/src/examples/websocket_threaded_example.c @@ -37,39 +37,39 @@ "<script>\n" \ "document.addEventListener('DOMContentLoaded', function() {\n" \ " const ws = new WebSocket('ws:// ' + window.location.host);\n" /* \ - // " const btn = document.getElementById('send');\n" \ - // " const msg = document.getElementById('msg');\n" \ - // " const log = document.getElementById('log');\n" \ - // " ws.onopen = function() {\n" \ - // " log.value += 'Connected\\n';\n" \ - // " };\n" \ - // " ws.onclose = function() {\n" \ - // " log.value += 'Disconnected\\n';\n" \ - // " };\n" \ - // " ws.onmessage = function(ev) {\n" \ - // " log.value += ev.data + '\\n';\n" \ - // " };\n" \ - // " btn.onclick = function() {\n" \ - // " log.value += '<You>: ' + msg.value + '\\n';\n" \ - // " ws.send(msg.value);\n" \ - // " };\n" \ - // " msg.onkeyup = function(ev) {\n" \ - // " if (ev.keyCode === 13) {\n" \ - // " ev.preventDefault();\n" \ - // " ev.stopPropagation();\n" \ - // " btn.click();\n" \ - // " msg.value = '';\n" \ - // " }\n" \ - // " };\n" \ - // "});\n" \ - // "</script>\n" \ - // "</head>\n" \ - // "<body>\n" \ - // "<input type='text' id='msg' autofocus/>\n" \ - // "<input type='button' id='send' value='Send' /><br /><br />\n" \ - // "<textarea id='log' rows='20' cols='28'></textarea>\n" \ - // "</body>\n" \ - // "</html>" */ + " const btn = document.getElementById('send');\n" \ + " const msg = document.getElementById('msg');\n" \ + " const log = document.getElementById('log');\n" \ + " ws.onopen = function() {\n" \ + " log.value += 'Connected\\n';\n" \ + " };\n" \ + " ws.onclose = function() {\n" \ + " log.value += 'Disconnected\\n';\n" \ + " };\n" \ + " ws.onmessage = function(ev) {\n" \ + " log.value += ev.data + '\\n';\n" \ + " };\n" \ + " btn.onclick = function() {\n" \ + " log.value += '<You>: ' + msg.value + '\\n';\n" \ + " ws.send(msg.value);\n" \ + " };\n" \ + " msg.onkeyup = function(ev) {\n" \ + " if (ev.keyCode === 13) {\n" \ + " ev.preventDefault();\n" \ + " ev.stopPropagation();\n" \ + " btn.click();\n" \ + " msg.value = '';\n" \ + " }\n" \ + " };\n" \ + "});\n" \ + "</script>\n" \ + "</head>\n" \ + "<body>\n" \ + "<input type='text' id='msg' autofocus/>\n" \ + "<input type='button' id='send' value='Send' /><br /><br />\n" \ + "<textarea id='log' rows='20' cols='28'></textarea>\n" \ + "</body>\n" \ + "</html>" */ #define BAD_REQUEST_PAGE \ "<html>\n" \ "<head>\n" \