Previous Page TOC Next Page Home


Appendix H

Windows CGI 1.2 Interface

Introduction

This document describes the implementation of CGI support with a typical Windows program (as opposed to running the CGI program in a DOS virtual machine or a console mode shell).

Windows has no native command interpreter. Therefore, any back end must be an executable program. A goal is to keep the interface simple and minimize back-end programming requirements. Therefore, a file-based interface has been chosen (as opposed to DDE or OLE). Request content is placed into a content file, and results must be written to an output file.

It is expected that many of the CGI applications will be developed using Microsoft Visual Basic (VB). VB supports generation of a .EXE file and supports a wide range of features for accessing data in the Windows environment, such as OLE, DDE, Sockets, and ODBC. The latter permits accessing data in a variety of databases, relational and non-relational. The VB application can be developed without the need for any windows (forms), consisting purely of VB code modules. This makes it possible to meet the recommendation that the CGI program execute invisibly, or at least as an icon.

Eventually, it is hoped that this interface will be standardized among Windows based HTTP servers. Several other servers in development at this time will be supporting Windows CGI.

Launching the CGI program

The server uses the CreateProcess() service to launch the CGI program. The server maintains synchronization with the CGI program so it can detect when the CGI program exits. This is done using the Win32 WaitForSingleObject() service, waiting for the CGI process handle to become signalled, indicating program exit.

Command Line

The server must execute a CGI program request by doing a CreateProcess() with a command line in the following form:

WinCGI-exe cgi-data-file

WinCGI-exe

The complete path to the CGI program executable. The server does not depend on the current directory or the PATH environment variable. Note that the executable need not be a .EXE file. It may be a document, provided an association with a corresponding executable has been established in either WIN.INI or the System Registry (preferred).

cgi-data-file

The complete path to the CGI data file.


Earlier editions of this specification showed additional command-line arguments (the content, output filenames, and any URL arguments). Because of limitations on the length of the command line imposed by the WOW (16-bit emulator) subsystem on Windows NT, and the Windows 95 system itself, it is recommended that servers no longer include these arguments on the command line. These data items are present in the cgi-data-file; therefore, their presence on the command line is redundant.

Launch Method

The server issues the CreateProcess() such that the process being launched has its main window hidden.

The launched process itself should not cause the appearance of a window nor a change in the Z-order of the windows on the desktop.

The server supports a CGI program/script debugging mode. If that mode is enabled, the CGI program is launched so that its window shows and is made active. This can assist in debugging CGI applications.

The CGI Data File

The Windows server passes data to its back end via a Windows private profile file, in key-value format. The CGI program may then use the standard Windows API services for enumerating and retrieving the key-value pairs in the data file.

The CGI data file contains the following sections:

The [CGI] Section

This section contains most of the CGI data items. (Accept types, content, and extra headers are defined in separate sections.) Each item is provided as a string value. If the value is an empty string, the keyword is omitted. The keywords are listed in the following sections.

Request Protocol

The name and revision of the information protocol this request came in with. Format: protocol/revision. Example: HTTP/1.0.

Request Method

The method with which the request was made. For HTTP, this is GET, HEAD, POST, and so on.

Executable Path

The logical path to the CGI program executable, as needed for self-referencing URLs.

Logical Path

A request may specify a path to a resource needed to complete that request. This path may be in a logical pathname space. This item contain the pathname exactly as received by the server, without logical-to-physical translation.

Physical Path

If the request contained logical path information, the server provides the path in physical form, in the native object (for example, file) access syntax of the operating system.

Query String

The information that follows the ? in the URL that generated the request is the query information. The server furnishes this to the back end whenever it is present on the request URL, without any decoding or translation.

Referer

The URL of the document that contained the link pointing to this CGI program. Note that in some browsers the implementation of this is broken, and cannot be relied on.

From

The e-mail address of the browser user. Note that this is in the HTTP specification but is not implemented in some browsers due to privacy concerns.

Content Type

For requests that have attached data, this is the MIME content type of that data. Format: type/subtype.

Content Length

For requests that have attached data, this is the length of the content in bytes.

Content File

For requests that have attached data, the server makes the data available to the CGI program by putting it into this file. The value of this item is the complete pathname of that file.

Server Software

The name and version of the information server software answering the request (and running the CGI program). Format: name/version.

Server Name

The network hostname or alias of the server, as needed for self-referencing URLs. This (in combination with the ServerPort) could be used to manufacture a full URL to the server, for URL fixups.

Server Port

The network port number on which the server is listening. This is also needed for self-referencing URLs.

Server Admin

The e-mail address of the server's administrator. This is used in error messages, and might be used to send MAPI mail to the administrator, or to form mailto: URLs in generated documents.

CGI Version

The revision of the CGI specification to which this server complies. Format: CGI/revision—for this version, CGI/1.2 (Win).

Remote Host

The network hostname of the client (requestor) system, if available. This item is used for logging.

Remote Address

The network (IP) address of the client (requestor) system. This item is used for logging if the hostname is not available.

Authentication Method

If execution of the CGI program is protected, this is the protocol-specific authentication method used to authenticate the user.

Authentication Realm

If execution of the CGI program is protected, this is the method-specific authentication realm used to authenticate the user. The list of users for the given realm is checked for authentication.

Authenticated Username

If execution of the CGI program is protected, this is the username (in the indicated realm) that the client used to authenticate for access to the CGI program.

The [Accept] Section

This section contains the client's acceptable data types found in the request header. For example:

Accept: type/subtype {parameters}

If the parameters (such as q=0.100) are present, they are passed as the value of the item. If there are no parameters, the value is Yes.


The accept types may easily be enumerated by the CGI program with a call to GetPrivateProfileString(), with NULL for the key name. This returns all of the keys in the section as a null-delimited string with a double-null terminator.

The [System] Section

This section contains items that are specific to the Windows implementation of CGI. The following keys are used.

GMT Offset

(New in WinCGI Version 1.2) The number of seconds to be added to GMT time to reach local time. For Pacific Standard time, this number is -28,800. Useful for computing GMT times.

Debug Mode

This is No unless the server's CGI/script tracing mode is enabled (in which case, the mode is Yes). This is useful for providing conditional tracing within the CGI program.

Output File

The full path/name of the file in which the server expects to receive the CGI program's results.

Content File

The full path/name of the file that contains the content (if any) that came with the request.

The [Extra Headers] Section

This section contains the extra headers that were included with the request, in key=value form.


Note: The extra headers may easily be enumerated by the CGI program with a call to GetPrivateProfileString(), with NULL for the key name. This returns all of the keys in the section as a null-delimited string with a double-null terminator.

The [Form Literal] Section

If the request is an HTTP POST from an HTTP form (with content type of application/x-www-form-urlencoded), the server will decode the form data and put it into the [Form Literal] section.

Raw form input is of the form key=value&key=value&..., with the value parts in url-encoded format. The server splits the key=value pairs at the &, and then splits the key and value at the =,url-decodes the value string and puts the result into key=(decoded)value form in the [Form Literal] section.

If the form contains any SELECT MULTIPLE elements, there will be multiple occurrences of the same key. In this case, the server generates a normal "key=value" pair for the first occurrence, and it appends a sequence number to subsequent occurrences. It is up to the CGI program to know about this possibility and to properly recognize the tagged keys.

The [Form External] Section

If the decoded value string is more than 254 characters long or if the decoded value string contains any control characters or double-quotes, the server puts the decoded value into an external tempfile and lists the field into the [Form External] section as:

key=pathname length

where pathname is the path and name of the tempfile containing the decoded value string, and length is the length in bytes of the decoded value string.


Be sure to open this file in binary mode unless you are certain that the form data is text.

The [Form Huge] Section

If the raw value string is more than 65,535 bytes long, the server does no decoding, but it does get the keyword and mark the location and size of the value in the Content File. The server lists the huge field in the [Form Huge] section as

key=offset length

where offset is the offset from the beginning of the Content File at which the raw value string for this key is located, and length is the length in bytes of the raw value string. You can use the offset to perform a Seek to the start of the raw value string, and use the length to know when you have read the entire raw string into your decoder. Be sure to open this file in binary mode unless you are certain that the form data is text!

Example of Form Decoding

In the following example, the form contained a small field, a SELECT MULTIPLE with 2 small selections, a field with 300 characters in it, one with line breaks (a text area), and a 230KB field.

[Form Literal]

smallfield=123 Main St. #122

multiple=first selection

multiple_1=second selection

[Form External]

field300chars=C:\TEMP\HS19AF6C.000 300

fieldwithlinebreaks=C:\TEMP\HS19AF6C.001 43

[Form Huge]

field230K=C:\TEMP\HS19AF6C.002 276920

Results Processing

The CGI program returns its results to the server as a data stream representing (directly or indirectly) the goal of the request. The server is responsible for packaging the data stream according to HTTP, and for using HTTP to transport the data stream to the requesting client. This means that the server normally adds the needed HTTP headers to the CGI program's results.

The data stream consists of two parts: the header and the body. The header consists of one or more lines of text, and is separated from the body by a blank line. The body contains MIME-conforming data whose content type must be reflected in the header.

The server does not interpret or modify the body in any way. It is essential that the client receive exactly the data that was generated by the back end.

Special Header Lines

The server recognizes the following header lines in the results data stream:

Content-Type

Indicates that the body contains data of the specified MIME content type. The value must be a MIME content type/subtype.

Status

Indicates that the server is to return the specified status. The value must be a status indication appropriate for HTTP. Note that the CGI program is responsible for generating a Status value that is legal for that protocol.

If the CGI program's response does not contain a Status: header, the server assumes that the CGI operation succeeded normally, and generates a 200 OK status.

URI: <value> (value enclosed in angle brackets)

The value is either a full URL or a local file reference, either of which points to an object to be returned to the client in lieu of the body (which the server shall ignore in this type of result). If the value is a local file, the server sends it as the results of the request, as though the client issued a GET for that object. If the value is a full URL, the server returns a 401 redirect to the client to retrieve the specified object directly.

Location

Same as URI, but this form is now deprecated. The value must not be enclosed in angle brackets with this form.

Other Headers

Any other headers in the result stream are passed (unmodified) by the server to the client. It is the responsibility of the CGI program to avoid including headers that clash with those used by HTTP.

Direct Return

The server provides for the back end to return its results directly to the client, bypassing the server's packaging of the data stream for its information protocol. In this case, it is the responsibility of the CGI program to generate a complete message packaged for HTTP.

The server looks at the results in the Output file, and if the first line starts with HTTP/1.0, it assumes that the results contain a complete HTTP response, and sends the results to the client without packaging.

Examples

The following example represents a response made by a CGI program that was invoked by an HTTP server, and consists of an HTML-formatted body:

--- BEGIN ---

Content-type: text/html           <== MIME type of body

Status: 200 OK                    <== HTTP status (optional)

                                  <== Header-body separator

<HTML>                            <== Body starts here

<HEAD>

<TITLE>Sample Document</TITLE>

</HEAD>

<BODY>

<H1>Sample Document</H1>

[... etc.]

</BODY>

<HTML>

---  END  ---

This example represents a redirection response, where the server is to direct the client to fetch the object indicated by the URL (using FTP):

--- BEGIN ---

Location: ftp://ftp.netcom.com/pub/www/object.dat  <== URL of object

                                                   <== Blank line

---  END  ---

This example represents a direct-return response from a CGI program that was invoked by an HTTP server, where the results contain a complete HTTP response:

--- BEGIN ---

HTTP/1.0 200 OK                   <== Start of HTTP Header

Date: Tuesday, 31-May-94 19:04:30 GMT

Server: WebSite 2.0

MIME-version: 1.0

Content-type: text/html

Last-modified: Sunday, 15-May-94 02:12:32 GMT

Content-length: 4109

                                  <== Header-body separator

<HTML> <HEAD>

<TITLE>A document</TITLE>

[... etc.]

---  END  ---

Reference Code Example

This section contains a reference example that shows, in Visual Basic, how a CGI programmer can enumerate the keys in a CGI Data File section, and get their values.

Enumerating CGI keys and Values

The following Visual Basic example shows how to enumerate the keys in a section and fetch the key-value pairs into a user-defined structure. Note that the declaration of GetPrivateProfileString() differs from that normally seen in VB programs. The difference is compatible, and allows enumeration by passing NULL for the key name. A \ at the end of a line indicates continuation. The code must actually be all on one line.

Declare Function GetPrivateProfileString Lib "Kernel" \

        (ByVal lpSection As String, \

         ByVal lpKeyName As Any, \        <== This permits NULL key name

         ByVal lpDefault As String, \

         ByVal lpReturnedString As String, \

         ByVal nSize As Integer, \

         ByVal lpFileName As String) As Integer

Type Tuple                  ' Used for Accept: and "extra" headers

    Key As String           ' and for holding POST form key=value pairs

    value As String

End Type

Global CGI_ProfileFile as String              ' Pathname of CGI Data File

Global CGIAcceptTypes(MAX_ACCTYPE) as Tuple   ' Accept: types array

Global CGINumAcceptTypes as Integer           ' Number of Accept: types in array

Const ENUM_BUF_SIZE 8192                      ' Size of key enumeration buffer

'---------------------------------------------------------------------------

'

'   GetProfile() - Get a value or enumerate keys in CGI_Data file

'

' Get a value given the section and key, or enumerate keys given the

' section name and "" for the key. If enumerating, the list of keys for

' the given section is returned as a null-separated string, with a

' double null at the end.

'

' VB handles this with flair! I couldn't believe my eyes when I tried this.

'---------------------------------------------------------------------------

Private Function GetProfile (sSection As String, sKey As String) As String

    Dim retLen As Integer

    Dim buf As String * ENUM_BUF_SIZE

    If sKey <> "" Then

        retLen = GetPrivateProfileString(sSection, sKey, "", buf, ENUM_BUF_SIZE, CGI_ProfileFile)

    Else

        retLen = GetPrivateProfileString(sSection, 0&, "", buf, ENUM_BUF_SIZE, CGI_ProfileFile)

    End If

    If retLen = 0 Then

        GetProfile = ""

    Else

        GetProfile = Left$(buf, retLen)

    End If

End Function

'---------------------------------------------------------------------------

'

'   GetAcceptTypes() - Create the array of accept type structs

'

' Enumerate the keys in the [Accept] section of the profile file,

' then get the value for each of the keys.

'---------------------------------------------------------------------------

Private Sub GetAcceptTypes ()

    Dim sList As String

    Dim i As Integer, j As Integer, l As Integer, n As Integer

    sList = GetProfile("Accept", "")        ' Get key list

    l = Len(sList)                          ' Length incl. trailing null

    i = 1                                   ' Start at 1st character

    n = 0                                   ' Index in array

    Do While ((i < l) And (n < MAX_ACCTYPE))' Safety stop here

        j = InStr(i, sList, Chr$)        ' J -> next null

        CGI_AcceptTypes(n).Key = Mid$(sList, i, j - i) ' Get Key, then value

        CGI_AcceptTypes(n).value = GetProfile("Accept", CGI_AcceptTypes(n).Key)

        i = j + 1                           ' Bump pointer

        n = n + 1                           ' Bump array index

    Loop

    CGI_NumAcceptTypes = n                  ' Fill in global count

End Sub

Previous Page TOC Next Page Home