Review: "HTML 4 & 5: The Complete Reference" By O'Reilly Media for iOS

This is not a book stuffed into an app. It is an application. The second thing to know is that the content is very good.

The content is a refresh of the O’Reilly HTML & XHTML Pocket Reference, Fourth Edition and benefits from have been honed over multiple editions. As a pocket reference it shows a decision to opt for concision over being exhaustively deep. But it is good because it is on point.

The content can be browsed or searched. Browsing includes a list of elements and a list of attributes. From the attribute list attribute entries link back to element entries for the elements that use the given attribute.

The search feature works across both elements and attributes but apparently there’s no word stemming. Searching on ‘sel’ finds no results. ‘select’ finds results that include the select element but not the selected attribute.

The app was developed in HTML5, CSS3, and jQTouch. PhoneGap was used to create an iOS executable. There are plans to bring the app to Android so using PhoneGap probably seemed reasonable. But there are quirks present that probably result from not being directly developed to iOS. Overall I didn’t see performance issues on a first gen iPad and on an iPhone4 but scrolling and scrubbing in the elements and attributes lists was sometimes touchy. What seemed like a light flick would sometimes send the list flying to the end. Touching the scrub bar is not always recognized, so instead of scrubbing through alphabetically the list is only scrolling. There’s no visual cue when the scrub bar has been activated.

Despite a few deficiencies it’s a huge win in convenience and utility to have this content in the form of an application. I’ve been working on updating an older site and this application has proved its worth as what it claims to be: a complete reference.

HTML 4 & 5: The Complete Reference is on the iTunes App Store.

Thanks to O’Reilly for providing the application for review.

Internet Explorer's Maximum URL Length

Note to self: Internet Explorer has a maximum URL size limit of 2,083 characters. Passing a longer URL (like maybe a URL with a dynamically built query string) to IE 7.0 will produce a cryptic error page (even with ‘Friendly’ turned off) that says “Internet Explorer cannot display the webpage” and then misleadingly suggests that the server can not be reached. Don’t waste time troubleshooting network connections or DNS lookups. Don’t be puzzled by why the same URL works in FireFox and Safari.

Using Properties and Tuples to Get Multiple Values from a JavaScript Function

Here’s a word: expando. Here’s a sentence using the word: JavaScript has expando objects.

Expando sounds like a silly made-up word. And it might be. But it’s also an actual word in Latin. It means ‘to spread out.’ The Latin meaning is almost appropriate for JavaScript. Objects in JavaScript are expando objects because properties can be dynamically added (expanding the object) and removed.

var obj = new Object();

// add a property
obj.foo = 'bar';

// remove a property
delete obj.foo;

Since functions in JavaScript are first class objects, properties can be added to functions. A function can be made state-ful by setting a property. In the example below a function named process sets an error property on itself:

function process(input)
{
    process.error = 0;
    ...
    if (...)
    {
        process.error = 1;
    }

    return output;
}

If the process function has never been run, process.error will be undefined.

if (typeof(process.error) != 'undefined')
{
    // test for an error
    ...

In newer versions of JavaScript this test could be written more directly as (process.error != undefined) but using the typeof operator is more portable.

The undefined state could be eliminated by initializing the property outside the function:

var process = function(input) { ... };
process.error = 0;

Are state-ful functions a good practice? It would be problematic if the function can be called again before the previous state has been handled so, in general, keeping state in a function should probably be avoided.

Yes, I just said don’t do the thing I just showed how to do.

Instead of creating state within the function, the function can return a tuple. (Like expando, tuple has a Latin etymology. Did you think you would be learning so much Latin from a blog post on JavaScript?) Tuple is a term used in set theory and by extension the relational database model but in terms of functional programming a tuple is an object that holds several other objects.

A tuple could be implemented as an Array. Using an array would require knowing the position in the array of each specific datum. Depending on positional information is brittle especially for large sets. A better way is an implementation that supports named datums. With named datums the order is irrelevant and the code is more literate.

Here’s the process function modified to use an ad-hoc tuple:

function process(input)
{
    var tuple = new Object();
    tuple.output = null;
    tuple.error = 0;
    ...
    if (...)
    {
        tuple.error = 1;
    }

    return tuple;
}

Using the object literal syntax the tuple object and its properties can be created in one line instead of three:

    var tuple = {output: null, error: 0};

Finally the returned tuple result could be handled as follows:

var result = process(in);
if (result.error == 0)
{
    // do something with result.output
    ...
}

Related Posts:
JavaScript Closures

JavaScript Closures

JavaScript doesn’t get enough respect. Sure it has warts but it also has elegant features like closures.

What, you may be asking, is a closure?

Many programming languages make a sharp distinction between code and data. JavaScript does not. In JavaScript a Function is a ‘first class’ type just like a String or an Array. Functions can be assigned to variables and properties and returned from other functions.

Declaring a function in JavaScript creates a function object. The following statement creates an object named example whose type, as reported by the typeof operator, is ‘function’.

function example(arg)
{
    return "example: " + arg;
}

The example function could also be created by a function literal1:

var example = function(arg) { return "example: " + arg; };

What gives rise to closures is the way the scope chain is handled when a function is created.

Consider:

var test0;
function outer()
{
    var test1;
 
    function inner()
    {
        var test2;
    }
}

JavaScript is a lexically scoped language. In the code above test0 is a global variable and test1 is local to the outer function. outer gets a reference to the global scope and test0 and test1 are both within scope for outer. test2 is local to the inner function. A function, in this case inner, always gets a reference to the scope chain in effect at the place where the function is defined. That is, inner gets a reference to outer’s local scope which in turn chains to the global scope. test0, test1, and test2 are all in scope for inner.

If the preceding description of scope makes sense, then consider this code:

function makeFish(color)
{
    function fish()
    {
        return color + " fish";
    }
 
    return fish;
}
 
var fish0 = makeFish('red');
var fish1 = makeFish('blue');
 
var str = fish0() + '; ' + fish1();

The variable str will be assigned the value “red fish; blue fish”. Why? Because the scope chain persists with the function object. The function is said to be ‘closed’ over the scope in which it was defined.

This isn’t just a neat parlor trick. Closures, along with first class functions and recursion, are generally considered the essentials for a style of programming known as functional programming.

Effective JavaScript Closures

Defining a function in JavaScript always creates a closure. Closure creation can not be disabled or turned off.

If the function is in the global scope then only the global scope is captured in the closure. In general that’s not useful so it’s often ignored as a case of a closure. But be aware that implicitly defined variables, that is variables defined without a var statement, are always in the global scope.

JavaScript is not block scoped. C/C++, Java, and C# are all C style syntax languages and all are block scoped languages. JavaScript has a C style syntax but it is not block scoped.

It’s a common technique to leverage block scope to control the lifetime of variables. In JavaScript, variables are in scope throughout the function they are declared in, not just the block they are within. In function foo below the idx variable exists before and after the for statement’s block. In JavaScript a variable can’t be forced out of scope prior to exitting its function.

function foo()
{
    var str = '';
    for (var idx = 0; idx < 5; ++idx)
    {
        str += idx;
    }
    return str;
}

Closure Conniptions

You may have heard that JavaScript closures are evil and cause memory leaks. Nonsense. Closures are not evil.

Oh. The memory leak thing? Well, yeah. There’s an Internet Explorer memory leak issue2 that closures often get the brunt of the blame for. That’s unfortunate because the memory leak issue is not really a closure problem. It’s a host object integration issue.

JavaScript supports native objects and host objects. Native objects are the built-ins (e.g. Object, Function, Array, String, Number) and user defined objects. Host objects are provided by the hosting application.

For an example take the window object. The window object is not part of the JavaScript language. Yes I know your JavaScript book spends chapters on the window object. That’s because most JavaScript programmers are writing to web browsers and every web browser has a window object. But although every web browser provides a window object not every JavaScript host is a web browser.

With closures it can be very easy to create circular references between objects. (That’s bad.) But JavaScript’s garbage collector is capable of detecting and handling circular references. (That’s good.) Except that, in IE, COM based host objects aren’t managed by the JavaScript garbage collector. (That’s bad.) DOM objects in IE are COM host objects. (That’s more bad.)

The fix is easy. Don’t depend on the garbage collector. Clean up after yourself. Release and null out object references when you’re done with them.

Link: Scott's "SiteExperts" Place: Closures and IE Circular References.
Link: Fabulous Adventures In Coding : What are closures?.

Related Posts:
Using Properties and Tuples to Get Multiple Values from a JavaScript Function

1 In addition to function statements and function literals, a function can also be created by the Function constructor.

var example = new Function("arg", 'return "example: " + arg;');

The Function constructor behaves differently from statements and literals with respect to scope. It always creates the function in the global scope. That difference makes the function constructor generally non-useful for closures.

2 I would assume that the other JScript script engine hosts, WSH and ‘classic’ ASP, have the same issue.

ASP.NET QueryString Parse Gotcha

There are times when it’s useful to throw a token parameter on a URL and have the receiving page test for the existence of the parameter. For example:

/website/page.aspx?foo

What’s significant is whether the token exists or not. It doesn’t need to have a value.

When I tried to use this trick in an ASP.NET 2.0 based application I found an issue. I expected to be able to test something like:

if (Request.QueryString["foo"] != null)

Parameters have the form <name>=<value> and I expected “foo” to be taken as a name with no value. But “foo” wasn’t a key in the QueryString collection. “foo” was interpreted as a value and the key was null.

That’s not very useful.

And I don’t recall any other web development environment behaving that way. I quickly tested against JSP and ‘classic’ ASP. Sure enough. In JSP/ASP “foo” is interpreted as a name with a null or empty value.

So how to test for “foo” in ASP.NET? I didn’t want to iterate the whole QueryString collection. That would be wasteful. I didn’t want to depend on an index position. Depending on fixed positions is brittle and counter to the whole point of using name/value pairs.

My solution? I changed my URL to

/website/page.aspx?foo=

Trouble POSTing to a classic ASP page?

POSTing to an ASP? ASP’s Request.Form requires application/x-www-form-urlencoded.

If you’re writing a web client of some sort that is trying to push data at an ASP based page via a POST request, you need to set up your HTTP headers correctly. To get ASP to parse the request body into the Request.Form collection the content-type must be “application/x-www-form-urlencoded” and the content-length must be set.

“application/x-www-form-urlencoded” is the default value for the HTML <form> element’s enctype attribute.

Using HTML Comments for printf() Debugging

printf() debugging is the practice of inserting ad-hoc calls to printf() (or an equivalent) in an effort to see the code path and/or the changes in variable state. printf() debugging isn’t pretty but even when sophisticated logging and diagnostics are available it can still have a place as a useful technique.

I’ve seen debugging techniques for web applications where diagnostic information is cached and then displayed by writing it out as formatted HTML at the end of the page or setting it as the value of a textarea element or something similar.

But there’s a simpler, less obtrusive way.

Instead of building or borrowing the plumbing to cache the diagnostics and messing up the appearance of the page with stuff that doesn’t belong, generate inline HTML comments.

Sure. It’s an extra step to choose ‘View Source’ to see the comments. But it’s not really an inconvenience. And there’s no harm in leaving in comments that don’t contain sensitive information. They might just prove to be invaluable when used to support in-the-field troubleshooting.

The Back Button is Not an Undo Button

In the film Starman, Jenny (Karen Allen) and Starman (Jeff Bridges), an extra-terrestrial who has crash landed on Earth, road trip across the United States in Jenny’s Mustang while evading government agents. Starman offers to drive and explains to Jenny, “I watched you very carefully. Red light stop, green light go, yellow light go very fast.”

Much has been written about web applications, particularly AJAX applications, that ‘break’ the web browser’s back button. There’s more than one type of back button breakage but what is usually discussed in relation to AJAX is the ability (or un-ability) to use the back button to undo the application’s last action.

I think the concern is misguided. The back button is not an undo button.

The back and forward buttons are part of the model of the web as a repository of documents. They allow a user to move back or forward in the chain of visited hypertext nodes, i.e. web pages.

The ‘back as undo’ argument is often supported by a usability study that shows mere mortal users depend on using the back button as an undo. I think that’s a little bit like using a study that shows automobile drivers speed up on a yellow light to argue for swapping the meanings of green and yellow traffic signals.

I don’t think browser back button behavior is quite as important as road safety but I do think there is an impedance mismatch between the web browser as hypertext document platform and the web browser as application platform.

‘Undo’ is an application action. The back button doesn’t undo anything. It loads a previous page. Spackling over the difference is a bad idea.

Link: Hypertext and Application Workflow (or The Case for Single Node Apps).

Problem with the Script Element for ASP Server-Side Object-Oriented JavaScript

‘Classic’ ASP (Active Server Pages) is a very quirky environment. A case in point is the handling of server side script elements.

For an ASP project I wanted to use object-oriented JavaScript (AKA JScript) on the server and I wanted to be able to reuse the JavaScript code across multiple pages. I didn’t expect to be pushing any boundaries but I quickly found myself in deep weeds.

Two parts of what I wanted to do could be considered unusual.

First, I wanted to use JavaScript on the server.

Microsoft encouraged the use of VBScript for ASP but I prefer JavaScript’s C style syntax, I think JScript’s exception handling has advantages over VBScript’s “on error”, and I like being able to use essentially the same language on both the client and the server.

Second, I wanted to write object-oriented JavaScript.

The JavaScript language is fundamentally object based yet, incongruously, object-oriented programming in JavaScript is often considered to be esoteric.

ASP server side code can be placed either within ‘<%’ and ‘%>’ delimiters (which is called a ‘scriplet’ in other environments) or within a script element with a non-standard runat="server" attribute.

In ASP reusing code across multiple pages means including shared files and in ASP 3.0 there are two ways to include a file: use a server side include directive* or a script element with a src attribute.

Link: Microsoft documentation on “Including Files in ASP Applications”

An example server side include directive:
<!-- #include file="server/include.inc" -->

The server side include directive performs a textual include of the referenced file. The included file can contain a mix of HTML and ASP scriptlets.

Since I wanted to just pull in code only, my include file would be one large scriplet.

But scriplets aren’t supported in the global.asa file. One of my goals was to avoid code duplication so I needed a way to include code without using a scriplet.

Here’s an example of a script element that includes a file server side:
<script language="javascript" runat="server" src="server/include.js"></script>

The included file can only contain code in the specified language. There’s no scriplet. That’s good.

However using script elements created a new set of issues.

In violation of the principle of least astonishment, ASP does not execute server side script in the order of its appearance within the page. The documented order of execution is:

  1. Script elements for non-default languages.
  2. Scriptlets (i.e. <% %> blocks).
  3. Script elements for the default language.

My default language was JavaScript. I would have a non-default language only if I were mixing languages, which I wasn’t.

This order of execution isn’t the whole story. Script elements for the default language appear to always be executed after the end of the page with the exception of function definitions. There’s apparently some auto-magical fix-up being performed so that functions defined in script elements can be called from scriplets.

In his blog, Fabulous Adventures in Coding, Eric Lippert wrote:

Ideally you want the server side <SCRIPT> blocks to contain only global function definitions, and the <% %> blocks to contain only “inline” code.

Link: Fabulous Adventures in Coding: VBScript and JScript Don’t Mix, at least in ASP

The apparent function definition fix-up seems to be half-baked.

In JavaScript functions are actually objects. A function named test could be equivalently defined either as:
function test() { return "test"; }

or as:
var test = function() { return "test"; }

Except in ASP the former definition would be available to scriplets and the latter definition wouldn’t be executed until the end of the page.

A bigger problem is that the order of execution has the unfortunate effect of blowing out prototype assignments.

An example will illustrate. Assume two files: circle.js and default.asp.

circle.js defines a constructor for a Circle type and assigns some additional properties to the Circle prototype. (The Circle type is borrowed from an example in the Microsoft JScript documentation.)

default.asp includes circle.js, creates an instance of a Circle, and iterates all of the members of the Circle object.

circle.js:

// circle.js

function Circle (xPoint, yPoint, radius)
{
    this.x = xPoint; // The x component of the center of the circle.
    this.y = yPoint; // The y component of the center of the circle.
    this.r = radius; // The radius of the circle.
}
Circle.prototype.pi = Math.PI;
Circle.prototype.area = function ()
    {
        return this.pi * this.r * this.r;
    }

default.asp:

<%@ language="jscript" %>
<script language="javascript" runat="server" src="server/circle.js"></script>
<html>
<head></head>
<body>
<%
var aCircle = new Circle(5, 11, 99);
    
// iterate the members/properties of the Circle object
for (var x in aCircle)
{
    Response.Write(x + " = " + aCircle[x] + "<br>");
}
%>
</body>
</html>

The output that might normally be expected:

area = function () { return this.pi * this.r * this.r; }
pi = 3.141592653589793
x = 5
y = 11
r = 99

The output that this page will actually produce:

x = 5
y = 11
r = 99

Why? Because the prototype assignments that add the pi and area members don’t execute until after the closing </html> tag.

Being able to set the prototype property is important because the prototype is an essential part of JavaScript’s support for object inheritance.

At this point some might settle for living with the evil of code duplication. That might be viable if the global.asa does little or nothing. My global.asa wasn’t going to be simple enough for that solution.

I needed a work-around. What I came up with was to create factory functions that wrapped the constructor definitions and the prototype assignments in a function scope.

Here’s a revised circle.js:

// circle.js

function createCircle(xPoint, yPoint, radius) // Circle factory
{
    function Circle (xPoint, yPoint, radius)
    {
        this.x = xPoint;
        this.y = yPoint;
        this.r = radius;
    }
    Circle.prototype.pi = Math.PI;
    Circle.prototype.area = function ()
        {
            return this.pi * this.r * this.r;
        }
    
    return new Circle(xPoint, yPoint, radius);
}

Constructing a Circle now looks like:
var aCircle = createCircle(5, 11, 99);

If there is an inheritance chain, all of the objects could be defined within the scope of the factory function and the factory function could take a selector argument to determine which type of object to construct.

The function scope trick is not a perfect solution. One issue is that a type defined within a function scope can’t be used with the instanceof operator. But the function scope trick does give me a way to get most of the benefit of leveraging JavaScript’s object oriented capabilities despite ASP’s best efforts to confound.

* The server side include directive is often confused with real SSI. It’s not SSI. It’s ASP aping the syntax of SSI. It’s a curious choice because ASP otherwise follows a very different syntax model. Another curiosity is that the documentation states “ASP includes files before executing script commands” and then belies that statement with an example of including a file multiple times by using a server side include directive within a for loop.

Hypertext and Application Workflow (or The Case for Single Node Apps)

Hypertext is a terrible platform for some types of web applications.

Consider an e-commerce web site. The browsing/shopping part of an online store fits rather well with the hypertext model but the checkout/payment part does not. For example, the checkout portion probably shouldn’t run the credit card transaction until after the customer has confirmed her order.

Many applications, even well-behaved non-modal event-driven applications, have some notion of workflow or an ordering of actions where task Y shouldn’t be available unless task X has been completed. Workflow-based constraints are at odds with the non-linear nature of hypertext.

Here’s a diagram with circles and arrows:

Consider this a state diagram. The circles represent states and the arrows represent state transitions. With A as a starting point there are two paths through this hypothetical application to reach state D: ‘ABD’ and ‘ABCD’. It should not be possible to reach D without traversing one of these two paths.

The workflow constraints this state diagram represents could be considered in procedural terms (step A must be followed by step B) or in temporal terms (event B can not be initiated until event A completes).

If this is a web application it could be built as a series of HTML pages. The relations between pages in a web application can be represented as a directed graph where pages and other resources addressable by URL are nodes, and links and transfers are edges. Here’s a page diagram for the hypothetical application:

Bears a striking resemblance to the state diagram, doesn’t it?

If an application has workflow constraints then it has a state machine. The state machine may not be explicit in the application’s architecture. It may only be implicit, arising from the relations between pages.

Now I’ll add the obligatory network cloud:

Oops! Since all URLs have equal visibility, a user can jump directly to any state/page if she knows (or guesses) the URL. Purely in terms of hypertext, this is a feature. But it’s a feature that the Web application developer will need to compensate for. The hypertext model is fundamentally working against the application.

There are three broad strategies for dealing with the “hypertext/workflow impedance mismatch”:

  1. Design the application to detect out-of-order page requests and enforce the workflow model.
  2. There is no sense in allowing a user to jump into a broken fragment of an application. URLs are effectively APIs. Taking it further, if a web application can be thought of as an object and its URLs as its methods then the methods should enforce the application’s invariants and do something reasonable with error conditions.
  3. Redesign or re-envision the application to either eliminate the workflow constraints or move the constraints out of application scope and down to the level of a single page.
  4. Design the application to use a single URL; i.e. create a single page or single node application.

It’s possible to build a single page text pump type of application but a more popularized approach is to push some or all of the application logic down to the web browser client. The client-side code then depends on a service layer of URLs but the service layer can be stateless and/or protected.

In the past ‘single page with client-side app logic’ applications might have used Java Applets, or ActiveX controls, or DHTML. Currently there is a single page application renaissance driven by the buzz around AJAX.

Cross-Language Gotcha: split() with a Limit

I have always assumed that the split() and join() methods of JavaScript’s String and Array objects were inspired by Perl. It’s a striking resemblance if my assumption is wrong.

Briefly the split() function splits a string on a delimiter producing an array of substrings. join() is a complementary function. join() operates on an array and produces a string by concatenating all the elements of the array with the specified delimiter.

In Perl, split() looks something like:
      split separator, stringExpr, limit

And in JavaScript:
      stringObj.split(separator, limit)

In both languages separator can be a literal string or a regular expression. Languages vary in their support of regular expressions so it’s no surprise that Perl and JavaScript interpret certain separators differently.

The gothca that tripped me up is that JavaScript and Perl don’t agree on what limit means. In both languages limit is optional but when specified split() will produce an array with only limit number of elements.

This Perl code:

my $str = "apple:boat:cat";
my @vec = split(':', $str, 2);

will produce an array with the elements “apple” and “boat:cat”.

This JavaScript code:

var str = "apple:boat:cat";
var vec = str.split(':', 2);

will produce an array with the elements “apple” and “boat”.

Conceptually JavaScript splits the whole string but only returns the first limit number of substrings while Perl returns the first limit - 1 substrings and the ‘unsplit’ balance of the string.

The JavaScript behavior can be imitated in Perl something like this:

my $str = "apple:boat:cat";
my @vec;
($vec[0], $vec[1]) = split(':', $str);

There is no equivalent for the Perl behavior in JavaScript.

iisreset

An essential tool for sysadmins and developers working with Microsoft’s Internet Information Server (IIS) is the iisreset command. iisreset was introduced with IIS version 5.0 and can be used to stop and start IIS from the command line.

IIS is composed of several Win32 services. A Win32 service is a background process like a Unix daemon. NT kernel based versions of Windows (e.g. Windows NT 4.0, Windows 2000, Windows XP, Windows 2003) support a sophisticated service infrastructure.1

In versions of IIS prior to 6.0 all of the services that compose IIS are housed in inetinfo.exe. In IIS 5.0 (Win2k) and 5.1 (WinXP) these services include the following:

Service Name Protocol Description IISADMIN IIS Administration MSFTPSVC FTP File Transfer Protocol Server NNTPSVC NNTP Network News Server (available on server versions of Windows) SMTPSVC SMTP Mail Transport Server W3SVC HTTP Web Server

The command
iisreset /stop

stops all IIS services. When all the services are stopped the inetinfo process terminates.

To restart use
iisreset /start

The /start switch starts all IIS services that are configured as ‘autostart’.

Prior to 5.0, cycling the web server could be achieved via the net (stop|start) commands.

For example,
net stop iisadmin /y

is equivalent to
iisreset /stop

The other services in IIS are dependent services of IISADMIN. Stopping a superordinate service will also stop any subordinate or dependent services. So stopping IISADMIN is sufficient to stop all the IIS services. (When a service has dependent services, as is the case with IISADMIN, the net stop command will prompt for confirmation. The /y switch provides an automatic confirmation.)

net (stop|start) is still useful because it can be used more selectively than iisreset. net stop w3svc stops the web server only. There is no equivalent with iisreset. But net stop doesn’t have iisreset’s /timeout switch.

The GUI tool for managing IIS, the Internet Services Manager, has start, stop, and pause buttons. Interestingly clicking the stop button in the IIS Manager doesn’t stop the selected service. The web server, for example, will stop responding to requests but any files in use remain locked and in use.

1In the past NT Services have had a reputation for being hard to develop. Services run in a unique context and require some special considerations.

I know of a case where an engineer saved himself the trouble and built a desktop application for something that really truly was a service. It was a short-sighted decision. Some of the consequences include no autostart and no remote administration. The operations staff must curse that guy.

Netscape Cookies (circa 1997)

Here’s a short note I originally published on the web in July 1997. I dredged it up recently because I had forgotten the syntax of the cookie meta element.

Cookies are supported by both Netscape Navigator and Microsoft Internet Explorer. A cookie may be set by a header response directive or an http-equiv meta tag.

Header Directive Format:
Set-Cookie: NAME=VALUE; expires=DATE; path=PATH; domain=DOMAIN_NAME; secure

Meta Tag Format:
<meta http-equiv="Set-Cookie" content="NAME=VALUE; expires=DATE; path=PATH; domain=DOMAIN_NAME; secure">

A more complete description of cookies is available in the following Netscape documents:

Tech Note: Cookies: what they are and how they workTech Note: How to write a server-side CGI program to set and read cookiesSpecification: Client Side State - HTTP Cookies

The GMT string for the first second of January 1, 1970 UTC, as required by the expires attribute, is

Thu, 01-Jan-1970 00:00:01 GMT

This is the beginning of time on Unix and Win32 systems.

Also of interest is RFC 2109, a proposed standard for an “HTTP State Management Mechanism.”

I didn’t explain seven years ago but there is a reason why it’s good to know the “GMT string for the first second of January 1, 1970 UTC.” It’s an arbitrary but consistent value to use for removing cookies.

Update January 2014

Updated Netscape document links to use the Internet Archive Wayback Machine.

RFC 2109 has been obsoleted. See RFC 6265.