#charset "us-ascii"
#pragma once
/*
* Copyright 2010 Michael J. Roberts.
*
* This file is part of TADS 3.
*
* This module defines the HTTPRequest intrinsic class. This class
* represents a request sent from a network client to the byte-code program
* via the program's HTTP server object.
*
* See the HTTPServer object for details on setting up an HTTP server
* within the program.
*
* HTTPRequest objects are not created with 'new'. Instead, the system
* creates them when HTTP requests arrive, and returns them to the
* byte-code program via the netEvent() built-in function.
*/
/*
* HTTP Request object. This object represents an HTTP protocol request
* from a client to one of our servers. HTTPRequest objects are created by
* the HTTPServer object as requests arrive, and are passed to the byte
* code program as network events, via the getNetEvent() function. The
* program uses the object to get information on the request and to send
* back the reply.
*/
intrinsic class HTTPRequest 'http-request/030001': Object
{
/*
* Get the HTTPServer object. This is the server that received the
* network request that 'self' represents.
*/
getServer();
/*
* Get the verb. This is the HTTP verb that the client sent with the
* request to indicate what action to perform. The standard HTTP verbs
* are GET (this is the most common request type; it simply retrieves a
* resource from the server), POST (used to submit form data), OPTIONS,
* HEAD, PUT, DELETE, TRACE, CONNECT, and PATCH. If the client sends a
* non-standard verb, the system simply passes it through to the
* request, allowing you to write a custom server for a custom client;
* however, this isn't recommended, since proxies and firewalls often
* block what they consider ill-formed requests.
*/
getVerb();
/*
* Get the query string. This is the portion of the URL after the
* server address. For example, if the client web browser navigated to
* the URL "http://www.tads.org:1234/path/resource?a=1&b=2" would
* return "/path/resource?a=1&b=2".
*
* 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.
*/
getQuery();
/*
* Parse the query string. This returns a LookupTable containing the
* parsed elements of the query. The element table[1] is the base
* resource name: this is the part of the query string up to the first
* '?', if any, or the entire query string if there are no parameters.
* If there are any parameters, they're entered in the table under the
* parameter names as keys. For example, for this query string:
*
*. http://www.tads.org:1234/path/resource?a=one&b=two&c=three&d
*
* we'd generate this table:
*
*. table[1] = '/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 'Cáfe' (%C3%A1 is the percent-encoded representation of
* the UTF-8 character small A with acute accent).
*/
parseQuery();
/*
* Get a parameter from the query string. This parses the query string
* and returns the parameter with the specified name, if present, or
* nil if not. This does the same parsing as parseQuery(), but it
* returns just the specified parameter value rather than building a
* lookup table with all of the parameters. This is more efficient
* than parseQuery() if you're just looking up one or two parameters,
* since it avoids building the whole table, but it's less efficient if
* you're looking up many parameters because this routine has to
* re-parse the query string on each call.
*/
getQueryParam(name);
/*
* Get the headers sent with the request by the client. This returns a
* LookupTable object: the keys are the header names, and the values
* are the corresponding header values. For example, for a POST, there
* might be a 'Content-type' key with the corresponding value
* 'application/x-www-form-urlencoded'.
*
* The element table[1] 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.
*/
getHeaders();
/*
* Look up a cookie. This looks for the given cookie name in the
* cookies sent by the client, and returns a string containing the
* cookie's text if found. If the cookie isn't found, returns nil.
*/
getCookie(name);
/*
* Get the cookies sent with the request by the client. This returns a
* LookupTable of the cookies, with each key set to a cookie name and
* the corresponding value set to the cookie's text. Cookies are
* assumed to contain only plan ASCII characters; any 8-bit characters
* in a cookie's name or value will be replaced by '?' characters.
*/
getCookies();
/*
* Get the form data-entry field values. This returns a LookupTable
* containing the field values sent with the request. Each key in the
* table is a field name (given by the NAME property of the HTML
* tag for the field), and each corresponding value is a string
* giving the value of the field as entered by the user.
*
* If the form includes uploaded files (via ), 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.
*/
getFormFields();
/*
* Get the body of the request, if any. Some types of HTTP requests,
* such as POST and PUT, contain a message body. This returns the raw,
* unparsed message body. Returns a File object, open with read-only
* access. If there's no message body at all, this returns nil.
*
* 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.
*/
getBody();
/*
* Get the network address of the client. This returns a list:
* ['ip-address', port], where 'ip-address' is a string with the IP
* address of the client, in decimal notation ('192.168.1.15', for
* example), and 'port' is an integer giving the network port number on
* the client side.
*/
getClientAddress();
/*
* Set a cookie in the reply. This sets a cookie with the given name
* and value, both given as strings. The value string starts with the
* text to set for the cookie, and can be followed by additional
* parameters, delimited by semicolons:
*
*. expires=Fri, 31-Dec-2010 23:59:59 GMT - set expiration date
*. domain=.tads.org - scope cookie to domain
*. path=/ - scope cookie within site
*. httponly - hide cookie from Javascript
*. 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.
*/
setCookie(name, value);
/*
* Send the reply to the request.
*
* '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