Introduction
One of the popular activities on the web is taking part in web chats - collaborative applications, which provide the mechanism to take part in a dialogue between two or more users in real time. A useful addition to any web site is the ability to group users by interests in separate chat rooms. Some sites allow participation in chat without registration, but most do not, as registering can provide a safer chat and more precise controlling. An even more secure environment for chatting, is where the chat is monitored by administrators or moderators, who watch chat processes and remove threatening traces, preventing their occurrence in the future. But also, the system must automatically prevent wrong user behavior. There are chat rules, bad words filtering, etc. The chat system must also work on various browsers on different platforms. Here, we will describe chat development, using ASP, JavaScript and a tool for sharing server-side data. In our case, this is XML.
Background
To simplify learning tasks and concentrate on details, our chat development is divided into four stages.
- Simple chat: Provides basic functionality: single chat room, messages history, possibilities to send messages, malicious input filtering, sender IP address tracking and invoking a chat help.
- User-friendly chat: In addition to previous functionality, provides active users list. Quantity of users on start page is also required. It has logoff possibility and expiration of inactive users after specified timeout.
- Registrable chat: Here, added persistence of user information and registration. User administration and relational database support can be helpful, but omitted.
- Palace chat: The feature is many chat rooms. Here, quantity of active users represented for each room, after user logins. Useful possibilities are changing room without exiting and opening a separate room without second login. Earned requirements for providing additional toolbar commands: Open room and Change room.
This article describes a Simple chat.
Simple chat
Let's start with the basic design layout. There are three panes: toolbar, messages history and new message form. They are separate and directly not connected.
It is not possible to implement callback mechanism, such as server events listening on client, using HTML only. Thus, to view changes, existent only method is periodical page refreshing. In this case, automatic page refreshing is required only for messages history. Toolbar commands and sending new messages performed by user action, thus doesn't require automatic refreshing. Correct system work requires unique location for storing messages. It is illustrated in Figure 1.
Figure 1 - Simple chat diagram.
The simplest method to perform automatic page refreshing is using a META tag in an HTML header:
<META HTTP-EQUV="Refresh" Content="7">
This definition causes page refreshing each 7 seconds. For ease of maintenance, you can go a step further and set this up as a constant. The example defined in Settings.js:
function getMessagesRefreshTime() {
return 7;
}
So, the header of our message history page will look like this:
<META HTTP-EQUV="Refresh" Content="<%=getMessagesRefreshTime();%>">
All messages are collected on the server. On each message history HTTP request is performed HTML formatting of all messages. It is downloaded by the browser. To prevent too many messages being downloaded, oldest should be removed. This can be implemented using an overflow-enabled mechanism, represented in Figure 2.
Figure 2 - Overflow-enabled mechanism.
After a new item added to the array, the last item is removed. This happens only if the maximum quantity of items is filled in. Thus, the resulting quantity of items in an array does not exceed the allowed maximum. This trick is implemented in the LimitedXML
class.
...
function LimitedXML_add(value) {
var xmlDoc = this.getXMLDocument();
var element = xmlDoc.createElement(this.xmlSection);
var elementText = xmlDoc.createTextNode(value);
var root = xmlDoc.firstChild;
root.appendChild(element);
element.appendChild(elementText);
this.removeSuperfluous(root);
}
function LimitedXML_removeSuperfluous(root) {
var items = this.getItems();
if(this.nMax < items.length) {
root.removeChild(items.item(0));
}
}
...
The Messages store must conform to the following requirements:
- Shared for all client requests
- Thread-safe
- Must provide possibilities to new items addition, removing and fast iteration
XML and the FreeThreadedDOMDocument
of MS XML Parser fit these requirements. Sharing message data for all client requests is implemented with the Application
object. Common functionality of shared XML storing and items retrieving is implemented in LimitedXML
class too. It provides the following public methods: add(value)
and getItems()
. This class also includes obsolete items removing, using previously described method.
To specialize this for chat messages, Messages
class is provided, and defined in MessageClass.js. Here we perform:
- Initial message formatting using sender name, its IP address, message itself and smiley icon
- New message addition
- System message addition
- Formatting messages history as HTML
Illustration of messages processing is shown in this diagram:
Figure 3 - Messages processing diagram
Also, it is strongly recommended to filter user input for malicious behavior. These are non-literary words in messages or username, special symbol combinations, client scripts or closing tags (for example </html>
). All filtering should be performed before messages are added. Most suitable is the Messages
class and its method AddMessage()
. Handling of non-literary words is delegated to Filter
class, represented in IncorrectInputFilter.js. Other possibilities are restricted by calling Server.HtmlEncode()
method. It replaces HTML special symbols with representation analogs (> < & etc.). If user entered multi-line text, it must appear multi-line in messages history too. This is achieved by replacing a new line symbol with <BR>
tag.
Words filtering algorithm is based on replacing all occurrences of unprintable words with dots. This algorithm is implemented using regular expressions. Searching pattern can look like this:
/badword1|badword2|...|badwordN/ig
This pattern provides possibility to search any of the listed "badwords". At the end of the pattern is specified regular expression options: i
causes ignoring case and g
allows to search globally or in the whole document.
Here, badword1
, badword2
,... , badwordN
must be replaced with real unprintable words. Example is available in IncorrectInputFilter_getPattern()
method. Replacing with JavaScript consists of these lines:
function IncorrectInputFilter_processText(inputText) {
var s = new String(inputText);
return s.replace(this.getPattern(), "...");
}
Examine the source code of the simple chat example.
This type of chat has a few shortcomings:
- Possibility to duplicate user name
- Whole frameset refreshing causes the system to add a new user coming message
- If JavaScript is disabled by the browser, most of the links in chat are not able to redirect.
Points of Interest
I'm not a web programmer, but I like to learn something interesting. Web-based chat is an example of such a thing. Currently, I'm working on personal planning in development and increasing of working time efficiency.