nwg(3) | AFNIX Module | nwg(3) |
nwg - standard network working group module
The Standard Network Working Groupmodule is an original implemtation of the recommendations proposed by the NWG and currently found in the form of Request for Comments(RFC). Most of the objects are used with networking application, with the most common one beeing the Universal Resource Identifier(URI) object.
The uri class
The Uriclass is a base class that parses a Uniform Resource Identifieror uri
string and provides methods to access individual component of that uri. The
implementation conforms to RFC 3986. The URI components are the scheme, the
authority, the path, the query and the fragment. The class also takes care
of the character escaping.
const uri (afnix:www:Uri "http://www.afnix.org")
An uri can be broken into several components called the scheme, the authority, the path, optionally the queryand the fragment. The Uriclass provide a method to retrieve each component of the parsed uri.
const uri (afnix:www:Uri "http://www.afnix.org/") println (uri:get-scheme) # http println (uri:get-authority) # www.afnix.org println (uri:get-path) # /
Character conversion
The Uriclass performs automatically the character conversion in the input uri.
For example, the +character is replaced by a blank. The %character followed
by two hexadecimal values is replaced by the corresponding ASCII character.
Note that this conversion does now apply to the query string.
Query string
The get-querymethod returns the query string of the uri. The query string
starts after the ?character. The query string is a series of key-pair values
separated by the &character.
const uri (afnix:www:Uri
"http://www.afnix.org?name=hello&value=world") println (uri:get-query) # name=hello&value=world
The module also provides the UriQueryclass that parses the query string and store the result in the form of a property list. The query string parse is particularly useful when writing automated scripts.
# create a query string object const qs (afnix:nwg:UriQuery (uri:get-query)) # get the name value qs:get-value "name"
Managing a cgi request
Managing a cgi request involves primarily the parsing of the requesting uri.
The uri generally contains the http referrer as well as parameter which are
stored in the form of a query string. However, depending on the cgi method
which can be of type GETor POST, the treatment is somewhat different.
Checking the protocol version
In the presence of a cgi protocol, it is always a good idea to check the
protocol version, or at least to put an assertion. The protocol version is
normally CGI/1.1and is stored in the GATEWAY_INTERFACEenvironment
variable.
# check the cgi protocol assert "CGI/1.1" (
afnix:sys:get-env "GATEWAY_INTERFACE")
Getting the query string
If the request method is GET, then the query string is available in the
environment variable QUERY_STRING. If the request method is POST, the query
string is available in the input stream. The length of the query string is
given by the CONTENT_LENGTHenvironment variable. The following example
illustrates the extraction of the query string.
# check the cgi protocol assert "CGI/.1" (
afnix:sys:get-env "GATEWAY_INTERFACE") # initialize the query string const query (afnix:sys:get-env "QUERY_STRING") # get the request method const rqm (afnix:sys:get-env "REQUEST_METHOD") # check for a post request and update the query string if (== rqm "POST") {
# create a buffer from the content length
const len (
Integer (afnix:sys:get-env "CONTENT_LENGTH"))
# get the standard input stream and read content
const is (interp:get-input-stream)
const buf (is:read len)
# set the query string
query:= (buf:to-string) }
Parsing the query string
The UriQueryclass is designed to parse a cgi query string. Once the string has
been parsed, it is possible to perform a query by key since the class
operates with a property list.
const query (
afnix:www:UriQuery "name=hello&value=world") query:length # 2 query:get-value "name" # hello query:get-value "value" # world
The UriQueryclass is the foundation to build cgi script. When the library is combined with the web application management (wam)service, powerful applications can be built easily.
Special functions
Several dedicated functions are available in the library as a way to ease the
object manipulations. Theses functions operate mostly on uri and files as
described below.
Uri functions
Several functions are designed to ease the uri manipulation. Most of them
operate on the uri name or their associated system name. The
normalize-uri-namefunction normalizes a string argument by adding a uri
scheme if missing in the original string. If the function detects that the
name starts with a host name, the httpscheme is added. If the function
detects that the string starts with a path, the filescheme is added.
otherwise, the name argument is left untouched. The system-uri-namefunction
normalizes the string argument by prioritizing the system name. The function
attempts to find a file that match the sring argument and eventually build a
uri file scheme. If the file is not fond, the normalization process occurs
with the normalize-uri-namefunction.
# normalize a uri name trans unm "http://www.afnix.org" assert unm (
afnix:nwg:normalize-uri-name unm) assert unm (
afnix:nwg:normalize-uri-name "www.afnix.org") assert unm (
afnix:nwg:normalize-uri-name "//www.afnix.org")
Mime functions
Mime functions are dedicated to easee the mainpulation of media types or mime.
A media type is defined by a string in the form of a type and content value
such as text/plain. The mime-value-ppredicate returns true if a string mime
value is a valid media type. From a file perspective, the
mime-extension-ppredicate returns true if the string extension has a valid
media type associated to it. Finally, the extension-to-mimefunction can be
used to get the string mime value associated with a file extension.
# check a media type assert true (afnix:nwg:mime-value-p "text/plain") # check the mime extension predicate assert true (afnix:nwg:mime-extension-p "txt") # check the extension to mime assert "text/plain" (
afnix:nwg:extension-to-mime "txt")
HTTP transaction objects
The concept of HTTP transactions is defined in RFC 2616. In the client/server
approach, a client issues a request which is answered with a response. A
special case arise when the server is asked to perform some extra works,
such like executing a script. In this case, the answer is called a reply
which is formatted into a response when the server does its job correctly.
The nature of the HTTP objects determines how the associated stream behaves.
With a HTTP request, the object is filled by reading an input stream when
operating on the server side. On the other hand, the request is filled by
data when operating on the client side. With a HTTP response, the opposite
situation occurs. The HTTP response is filled by reading an input stream
when operating on the client side and filled by data when operating on the
server side.
HTTP protocol
The HttpProtoclass is a base class designed to handle a HTTP header that is
found in both HTTP request and response. The class is built around a
property list that is filled either by parsing an input stream or by
processing specific methods. The HttpProtodefines also some methods which
are often used with a HTTP request or response.
HTTP response
The HttpResponseclass is a class designed to handle a HTTP response. When
operating on the client side, the response object is built by reading an
input stream. When operating on the server side, the response object is
built by calling specific methods.
Creating a server response
A server response is created by specifying the response status code. By
default, a HTTP response is created with the default media type text/html.
If the media type needs to be changed, it can be passed as the second
argument to the response constructor. By default, the empty constructor
creates an empty constructor with a valid status code.
#create a valid response const hr (afnix:nwg:HttpResponse 200)
Once the server response is created, it can be augmented with some headed values. Typically, a server will add some information about the response, such like the content length, the modification time or a tag. The HttpResponseprovides several methods that ease the generation of these header values.
Creating a client response
A client response is created by binding an input stream to a response object.
During the construction, the input stream is read and the HTTP protocol
header is filled. It is also during this phase that the status code is
processed. It is therefore important to ensure that a response object is
built correctly before attempting to access it.
# create a client response by stream const hr (afnix:nwg:HttpResponse is)
Reading a client response
When the response has been created, it is important to check its status code.
Most of the time, the response is valid and its content can be read
directly. The status-ok-ppredicate returns true if the status code is valid.
In such case, a HTTP stream can be built in order to read the response.
# check that a response is valid if (hr:status-ok-p) {
# create a http stream
const rs (afnix:nwg:HttpStream ht is)
# read the response stream
while (rs:eos-p) (rs:read) }
Before reading a http stream, it is important to detect and verify the nature of the response content. The media-type-ppredicate returns true if the media type is defined and the get-media-typemethod returns the response type in the form of a mime code such like text/html. Eventually, the character set associated with the media type can also be detected. The encoding-mode-ppredicate and the get-encoding-modemethod can be used to detect the content encoding mode. However, it is worth to note that the HttpStreamobject is automatically sets with the proper encoding if it can be found in the response header.
Special client response
Certain response can sometime contains special status codes that require a
specific treatment. This is the case when the response corresponds to a http
redirection. In this case, the new uri must be fetched to get the desired
response. The location-ppredicate returns true if the response corresponds
to a http redirect and the get-locationmethod can be used to get the new
location uri. If this situation arises, it is up to the implementation to
decide what to do with the new uri. In most cases, a new request will be
sent to the server.
Cookie object
The Cookieobject is a special object that can be used during a http session,
to post data to the http client. The idea behind cookiesis to be able to
maintain some state, during the user session for some time. A cookie is a
name/valuepair and eventually an expiration time. By default, the cookie
object are defined for one http client session, but this behavior can be
changed.
Managing cookies
A cookie is created with a name/valuepair and eventually an expiration time.
Such expiration time is called the maximum-ageand is automatically formatted
by the object. With two arguments a session cookie is created. With a third
argument as an integer, the constructor set the maximum age in seconds.
# create a cookie with name/value const cookie (afnix:nwg:Cookie "cartid" "123456789")
The cookie implementation follows the recommendation of the RFC-2965 for http state management. The most important point to remember is the interpretation of the maximum age that differs from one cookie version to another. With version 1, which is the default, the maximum age is defined relatively in seconds, while it is absolute with version 0.The maximum age is set either at construction or with the set-max-agemethod. The set-max-agemethod sets the cookie life time in seconds, in reference to the current time. A negative value is always reset to -1 and defined a session cookie. A 0 value tells the http client to remove the cookie. The set-pathmethod defines the path for which this cookie apply.
Adding a cookie
Once the cookie is defined, the set-cookiemethod of the HttpResponseobject can
be used to install the cookie. Combined with the writemethod, the cookie can
be send to the http client.
Uri
The Uriclass is a base object used to parse or build a uniform resource
identifier as defined by RFC 3986. The URI can be built by specifying each
component or by parsing a string. When a string is given in the constructor,
the class parses the string and extract all components. The uri components
are the scheme, the authority, the path, the query and the fragment. The
class also takes care of the character escaping.
Predicate
Inheritance
Constructors
Methods
UriQuery
The UriQueryclass is a simple class that parses a uri query string and build
property list. during the parsing process, a special transliteration process
is done as specified by RFC 3986. This class is primarily used with
cgiscripts. Note that the string to parse is exactly the one produced by the
get-querymethod of the Uriclass.
Predicate
Inheritance
Constructors
Methods
UriPath
The UriPathclass is a class designed for the management of file system path
associated with a uri. Typically, this class will be used with a http server
or client when an association between a uri and a file name needs to be
made. The general operation principle is to associate a path with a uri
authority. The uri path is then concatanated to produce a new path. If the
uri path is empty, it can be eventually replaced by a file name, known as
the diretory index in the http terminology.
Predicate
Inheritance
Constructors
Methods
HttpProto
The HttpProtoclass is a base class that ease the deployment of the http
protocol. The base class is built with a property list which is used to
define the message header. The class also defines the write methods which
are used to write a message either on an output stream or into a buffer.
Predicate
Inheritance
Methods
HttpRequest
The HttpRequestclass is a base class designed to handle a http request. The
class operates with the protocol version 1.1 as defined by RFC 2616. For a
server request, the request is built by reading an input stream and setting
the request command with its associated header. For a client request, the
request is formatted with a request command and a eventually a uri. In both
cases, the header is filled automatically depending on the request side.
Predicate
Inheritance
Constructors
Methods
HttpResponse
The HttpResponseclass is a base class designed to handle a http response. The
class operates with the protocol version 1.1 as defined by RFC 2616. For a
client response, the response is built by reading an input stream and
setting the response status code with its associated header. For a server
response, the response is formatted with a response status and additional
header information. In both cases, the header is filled automatically
depending on the response side. On the other hand, trying to set some header
with an input stream bound to the response object might render the response
object unusable.
Predicate
Inheritance
Constructors
Methods
Cookie
The Cookieclass is a special class designed to handle cookie setting within a
http transaction. A cookie is name/valuepair that is set by the server and
stored by the http client. Further connection with the client will result
with the cookie value transmitted by the client to the server. A cookie has
various parameters that controls its existence and behavior. The most
important one is the cookie maximum agethat is defined in seconds. A null
value tells the client to discard the cookie. A cookie without maximum age
is valid only during the http client session. A cookie can be added to the
HttpReplyobject with the set-cookiemethod. A cookie can be constructed with
a name/valuepair. An optional third argument is the maximum age. The default
cookie version is 1 as specified by RFC 2965. With a version 1, the maximum
age is interpreted as the number of seconds before the cookie expires. With
version 0, the maximum age is the absolute time.
Predicate
Inheritance
Constructors
Methods
Functions
2018-07-20 | AFNIX |