Every user agent should set an HTTP header called "User-Agent" when making a request. The User-Agent header contains a free-form ASCII string that should uniquely identify the user agent making the request. It is common practice for this string to name the user agent's hardware and browser, and versions. For example, the Nokia 6600 series sends a header like:
User-Agent: Nokia6600/1.0 (4.03.24) SymbianOS/6.1 Series60/2.0 Profile/MIDP-2.0 Configuration/CLDC-1.0
Compare this to User-Agent strings typically sent by a desktop browser, like Microsoft Internet Explorer:
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)
The header value has no official format or structure, unfortunately. It is merely a helpful "fingerprint" of the user agent making the request. Therefore it is not possible to consistently extract information about the device from the User-Agent header value alone. For example, nothing about this string indicates whether the requesting device supports Macromedia Flash animations; one might have to resort to scripting hacks to figure out this capability within the page.
However, knowing something about the device and browser can tell you something about the device's capabilities. This is especially useful when servicing requests from mobile devices, since limitations like screen size may be important to know about.
One could maintain a database of information for every unique user agent string. This would be prohibitively difficult, and is not 100% reliable as new strings might appear at any time. Several open-source solutions have been created to collect and provide easy access to device information based on User-Agent header strings, including WURFL (http://wurfl.sourceforge.net/) and DELI (http://delicon.sourceforge.net/). Note also related standards for communicating device capability information such as UAProf (http://www.openmobilealliance.org/tech/profiles/), CC/PP (http://www.w3.org/Mobile/CCPP/), and forthcoming standards from the W3C's Mobile Web Initiative's Device Independence Working Group (http://www.w3.org/2001/di/).
User-Agent header strings do tend to follow a pattern; for example, the User-Agent strings for all NTT DoCoMo devices begin with "DoCoMo", and devices using OpenWave's browser tend to contain "UP.Browser" in their User-Agent header. These patterns are often reliable enough to detect broad classes of user agents (using a particular browser, or from a particular carrier), and can sometimes be used to infer capabilities. For example, all NTT DoCoMo devices support cHTML and the Shift_JIS character encoding. (See User Agents and XHTML for full DoCoMo device info.)
Wikipedia has a fairly well documented entry on User Agents as well.
Pattern-matching is a crude but simple approach to inferring device capability. It may be sufficient in some contexts, but, is not generally recommended. Using a more reliable source of information like DELI or WURFL is preferable.