HTTPRequest : Object
'headers' is an optional list of additional headers to send with the end of the reply. The HTTP chunked reply mechanism allows a server to send headers at the beginning of the reply (which corresponds to the startChunkedReply() call), at the end of the reply (in this routine), or both. This accommodates situations where the server might not be able to determine the final value for a header until after generating full reply. If this argument is included, it works just like the 'headers' argument to sendReply().
If the body is a text type, the file will be open in text mode, with the character mapping set according to the content type passed from the client; otherwise it's open in raw binary mode.
The message body retrieved here is the raw request payload, without any processing. There are two standard structured body types that are frequently used with POSTs, both of which require further parsing. First is MIME type application/x-www-form-urlencoded, which is used to represent a basic HTML form, and encodes the data entry fields in a form; this type can be parsed via the getFormFields() method. Second is multipart/form-data, which is used to POST forms that include uploaded files; this can be parsed with getFormFields() to retrieve the data fields, and getUploads() to get the uploaded file data.
If the form includes uploaded files (via <INPUT TYPE=FILE>), the value of each file field will be a FileUpload object instead of a string. The 'file' property of this object contains a File object, opened in read-only mode, that can be used to retrieve the contents of the uploaded file. Other properties of object provide the client-side name of the file and the MIME type specified by the browser.
This method is a convenience function that parses the message body information. You can obtain the raw information on the posted data via the getHeader() method.
This method recognizes form data as a message body with content-type application/x-www-form-urlencoded or multipart/form-data. If the request doesn't have a message body at all, or has a message body with a different content-type, this method assumes that the request has no posted form data and returns nil. We return nil rather than an empty lookup table so that the caller can tell that this doesn't appear to be a form submission request at all.
The element table contains the HTTP request line - the first line of the request, which isn't technically a header. This line contains the verb, the query string, and (optionally) the HTTP version string (in that order, with spaces separating the elements). The method includes this so that you can inspect the unparsed request line, if desired.
This is the raw query string, exactly as the client sent it. Any '%xx' character sequences are still present in this version of the string.
we'd generate this table:
table = '/path/resource'
table['a'] = 'one'
table['b'] = 'two'
table['c'] = 'three'
table['d'] = ''
For all of the strings (including the base resource name, the parameter names, and the parameter values), any '%xx' sequences are converted into the corresponding character values. For example, if the base resource name is '/C%C3%A1fe', the resource name will be parsed to 'Cfe' (%C3%A1 is the percent-encoded representation of the UTF-8 character small A with acute accent).
'body' is the content of the reply. For example, for a request for an HTML page, this would contain the HTML text of the page. This can be a string or StringBuffer, in which case the string is sent as UTF-8 data; a ByteArray, in which case the raw bytes of the byte array are sent exactly as given; an integer, in which case the body will be a default HTML page automatically generated for the corresponding HTML status code; a File object opened with read access, in which case the contents of the file will be sent; or nil, in which case no message body is sent at all (just the status code and the headers). A file open in text mode will be sent as text, and raw mode will be sent as binary. "Data" mode isn't allowed. Note that if a file is used, this will send the entire contents of the file, regardless of the current seek position, and the routine will have the side effect of setting the file's seek position to end of file upon return.
'contentType' is an optional string giving the MIME type of the reply body. This is used to generate a Content-type header in the reply. If this is omitted, the server generates a default MIME type according to the type of the 'body' argument. If 'body' is given as a string, and the string starts with <HTML (ignoring any initial whitespace), the default content type is "text/html"; if the string starts with <?XML, the default type is "text/xml"; otherwise the default type is "text/plain". If 'body' is a ByteArray, the server checks the first few bytes for signature strings for a few known types (JPEG, PNG, MP3, Ogg, MIDI), and uses the corresponding MIME type if matched; otherwise the MIME type is set to "application/octet-stream". 'contentType' is ignored when the 'body' argument is an integer (because in this case the body is known to be HTML), or hwen it's nil (since there's no body at all in this case).
When the 'body' is a string, the server automatically adds the "charset" parameter to the Content-type header with value "utf-8".
'status' is an optional HTTP status code. This can be a string, in which case it must have the standard format for an HTTP status code, which consists of a decimal status code number followed by the text description of the code: for example, "404 Not Found. This argument can alternatively be a simple integer giving one of the standard HTTP status code numbers, in which case we'll automatically add the corresponding status code text. If this argument is omitted, AND the 'body' is given as an integer, the 'body' value will be used as the status code. If this is omitted and there's a non-integer 'body' argument, we use "200 OK" as the default status code.
'headers' is an optional list of header strings. Each element of the list is a string giving one header, in the standard format "Name: Value". If this is omitted, the reply will contain only the standard headers synthesized by the server.
The server automatically generates certain headers with each reply. These should not be specified in the 'headers' argument. The standard headers are:
Content-type: per the 'contentType' argument
Content-length: length in bytes of 'body'
After sending the reply, the request is completed, and no further reply can be sent.
The parameters are the same as for sendReply(). If 'body' is a File, this function opens its own separate handle to the file, so you're free to close the File object immediately, or to continue to use it for other operations. Note that if you continue writing to the file after calling this method, it's unpredictable whether the reply data will contain the original or updated data (or a mix of new and old data), since the reply data transfer is handled in a separate thread that runs in parallel with the main program.
When the reply data transfer is completed, or if it fails, the system posts a NetEvent of type NetEvReplyDone to the network message queue. The event contains the original HTTPRequest object, to allow you to relate the event back to the request that generated the reply, and status information indicating whether or not the transfer was successful.
Disconnect exceptions are common with HTTP: the protocol is stateless by design, so clients can close their sockets at any time. Most modern browsers use HTTP 1.1, which allows the client to maintain an open socket indefinitely and reuse it serially for multiple requests, but browsers tend to close these reusable sockets after a few minutes of inactivity.
When this routine encounters a disconnected socket, it deletes the client session record for the request, and then otherwise ignores the error. This generally makes the client's socket management transparent to the server, since if the client is still running they'll just connect again with a new socket and retry any lost requests.
'body' can be a string or StringBuffer, in which case the string data are sent as UTF-8 text; or a ByteArray, in which case the raw bytes are sent.
expires=Fri, 31-Dec-2010 23:59:59 GMT - set expiration date
domain=.tads.org - scope cookie to domain
path=/ - scope cookie within site
secure - only send via https://
(These are all defined by the HTTP protocol, not by TADS. For details, refer to any HTTP reference book or web site.)
A cookie without an expiration date is a session cookie: it implicitly expires as soon as the browser application terminates. The presence of an expiration date makes the cookie persistent, meaning it's to be stored on disk until the given expiration date and should survive even after the browser is closed.
To send a cookie, you must call this BEFORE sending the reply or starting to send a chunked reply. This is a limitation of the protocol, since the cookies must be sent at the start of the reply with the headers. Calling this routine doesn't actually send anything immediately to the client, but simply stores the cookie with the pending request, to be sent with the reply.
This routine doesn't send any initial data, but simply begins the reply process. For this reason, the content type must be specified: there's no way for the routine to infer the content type here since we don't have any body data to look at. The content type, result code, and headers arguments work as they do with sendReply().
After calling this routine, call sendReplyChunk() as many times as needed to send the pieces of the reply. After sending all of the pieces, call endChunkedReply() to finish the reply.