[an error occurred while processing this directive]

13. Communicating with an HTTP Server


Introduction

<MvCALL>

<MvCALL> uses the HTTP/1.0 protocol to emulate a browser and contact a remote host. Static HTML, XML, and SGML pages can be requested from the remote server, and data can also be sent to the remote server.

Syntax:

<MvCALL
ACTION = "URL"
METHOD = "POST|GET"
FIELDS = "var1,var2,var3,..."
FILES = "fvar1,fvar2,fvar3,...">
...code...
<MvCALLSTOP>
...code...
</MvCALL>

where:

ACTION specifies the URL to be contacted: this must be a full URL starting with http.

METHOD can be POST (send data) or GET (send data or request a document). FIELDS contains variables whose values are sent to the URL when POST is used as the method.

FILES contains variables whose values are filenames that will be uploaded to the specified URL (see the section File uploading).

When <MvCALL> receives a document, it iterates once for each object (text or tag) that it receives. Several special variables (described below) are created with data about the object.

The <MvCALL>...</MvCALL> loop terminates when the entire document has been received, or when an <MvCALLSTOP> (optional) is encountered. <MvCALLSTOP> is an empty tag.

Note: <MvCALL> does not support the HTTPS (secure HTTP) protocol.

Requesting a Document

To request a document using <MvCALL>, set the ACTION attribute to the URL of the document that you want to obtain, and set the METHOD attribute to 'GET'. The FIELDS attribute is not required.

For example:

<MvCALL
ACTION="http://www.your_server.com/company/contact.html"
METHOD="GET">

<MvCALL> retrieves the document as a sequence of tags and text blocks. <MvCALL> passes the document to the program one object at a time; the <MvCALL>...</MvCALL> loop is executed once for each object. Consider the following HTML code:

<P>When in <B>Rome</B> do as the <I>Romans</I> do.</P>

<MvCALL> will split this code into 11 objects:

<P>
When in
<B>
Rome
</B>
do as the
<I>
Romans
</I>
do.
</P>

Each time <MvCALL> returns an object, it sets the value of the special variable callobjecttype. callobjecttype has the value 'tag' if the object is a start- or end-tag, and 'text' if the object consists of text. Your program can use this value inside the <MvCALL> loop to decide how to process the object. The variable callvalue contains the text or tag object itself.

Tags

The variable callobjecttype has the value 'tag' if the object returned by <MvCALL> is a start- or end-tag. If the tag is a start-tag, <MvCALL> then further separates the tag into attribute/value pairs.

The following special variables are set for each tag:

Consider the following example:

<IMG SRC="donkeys.gif" ALT="The Donkey Farm" HEIGHT="100" WIDTH="200">

<MvCALL> will set the following variables for this 'tag' object:

Name
Value
callvalue
the entire tag
callobjectelement
IMG
callobjectnumattributes
4
callobjectattribute1
SRC
callobjectvalue1
donkeys.gif
callobjectattribute2
ALT
callobjectvalue2
The Donkey Farm
callobjectattribute3
HEIGHT
callobjectvalue3
100
callobjectattribute4
WIDTH
callobjectvalue4
200

All values, string and numeric, are returned without quotes.

Sometimes an attribute will be specified without an attribute name, as in:

<TABLE BORDER>

In this case, the attribute name and the attribute value are considered to be the same. In this example, callobjectattribute1 and callobjectvalue1 will each have the value BORDER.

The MvCALL variables callreturnheaderN, callobjectvalueN, and callobjectattributeN are accessible as arrays: callreturnheader[1] would have the same value as callreturnheader1.

Note: All of these variables (except callvalue) will be set to null if the current object is of type 'text'.

Text

The variable callobjecttype has the value 'text' if the object returned by <MvCALL> consists of text.

The variable callvalue will contain the actual string of text and white space.

Note: Sequences of white space between tags (such as new lines, spaces, and tabs) are returned as text objects by MvCALL.

Headers

When it retrieves a document, <MvCALL> also receives HTTP header information sent by the server. This information is stored in the following variables:

The following is an example of header data:

callnumberofheaders=
callreturnheader1=
callreturnheader2=
callreturnheader3=
callreturnheader4=
callreturnheader5=
callreturnheader6=
6
HTTP/1.0 200 OK
Date: Fri., 17 Jan 1997 01:23:24 GMT
Server: Apache/1.1b0a
Content-type: text/html
Content-length: 390
Last-modified: Thu, 16 Jan 1997 23:40:10 GMT

MvCALL Examples

The following code will retrieve and display an HTML page:

<MvCALL ACTION="http://..." METHOD="GET">
<MvEVAL EXPR="{callvalue}">
</MvCALL>

This will display the page as if its URL had been accessed directly by the browser, except that any relative links (to images, for example) will not be resolved. One workaround for this is to put a <BASE> tag in the page being accessed, giving its absolute URL. Another is to put the appropriate <BASE> tag in the output stream that Miva sends to the browser:

<MvASSIGN NAME="url" VALUE="http://...">
<MvCALL ACTION="&[url];" METHOD="GET">
<MvIF EXPR="{callobjecttype EQ 'tag' AND toupper(callobjectelement) EQ '/HEAD'}">
<MvEVAL EXPR="<BASE HREF='&[url];'>">
</MvIF>
<MvEVAL EXPR="{callvalue}">
</MvCALL>

To display the page in its 'raw' HTML form, use:

<PRE>
<MvCALL ACTION="http://..." METHOD="GET">
<MvEVAL EXPR="{encodeentities(callvalue)}">
</MvCALL>
</PRE>

Here is another simple <MvCALL> example:

<MvCALL METHOD="GET" ACTION="http://...">
<MvIF EXPR="{ callobjecttype EQ 'tag' }">
<p>Tag name: <MvEVAL EXPR="{callobjectelement}"></p>
<p>Number of attributes: <MvEVAL EXPR="{callobjectnumattributes}"></p>
<MvELSE>
<p>Text: ==<MvEVAL EXPR="{callvalue}">==</p>
</MvIF>
<HR>
</MvCALL>

This program gets objects from the specified URL. If the object is a tag, the tag's name and the number of attributes are displayed. If the object is text, the text is displayed.

The output from this program will look like this:

...

Tag name: B

Number of attributes: 0

Tag name: FONT

Number of attributes: 2

Text: ==An out-of -office experience==

Tag name: /FONT

Number of attributes: 0

...

Limitations

Nevertheless, <MvCALL> is a useful tool for processing structured documents, particularly those that are valid and well-formed.

Note: <MvCALL> may produce unexpected results if the document being requested uses the double-quote character (") instead of the entity &quot; in literal text.

Submitting Data with <MvCALL>

There are two ways to use <MvCALL> to submit data to a CGI program on a server. These are the GET and POST methods, and are used in the same way as with an HTML form. The receiving program must know which method is being used and be set up to process data accordingly.

Note: It is not possible in Miva Script to modify the default HTTP headers when sending a request to a server.

Using GET

To use the GET method to submit data with <MvCALL>, set the METHOD attribute to 'GET'. The data that is submitted must be appended to the URL specified by ACTION. It is separated from the URL by a '?' character, and consists of a sequence of 'name=value' pairs separated by ampersands, '&'.

For example:

http://www.my_isp.com/cgi-bin/prog1?animal1=fish&animal2=dinosaur

If the data contains any special characters, such as space, '=', '~', '&', and '+', it must be URL-encoded. The submitted data will be available to the receiving program via the QUERY_STRING CGI environment variable.

Here is an example using GET:

<MvCALL
ACTION="http://www.my_isp.com/cgi-bin/prog1?animal1=fish&animal2=dinosaur"
METHOD="GET">
...
</MvCALL>

Using POST

If you use the POST method to submit data, the data is not sent to the server appended to the URL, but rather in the HTTP headers. The format in which the data is received is the same as when GET is used. That is, a sequence of 'name=value' pairs separated by ampersands, '&'.

Instead of obtaining the data from the QUERY_STRING variable, the program receiving the data must read it from its standard input.

To use this method, set the METHOD attribute of <MvCALL> to 'POST'. The FIELDS attribute should contain a list of variables whose names, together with their values, are sent to the URL specified with the ACTION attribute. Here is an example:

<MvASSIGN NAME="animal1" VALUE="fish">
<MvASSIGN NAME="animal2" VALUE="dinosaur">
<MvCALL
ACTION="http://www.my_isp.com/cgi-bin/prog2"
METHOD="POST"
FIELDS="animal1,animal2">
...
</MvCALL>

Processing the Response

Since CGI programs generally send a response back to the client that sent it data, the <MvCALL> loop can and should be prepared to deal with the document that is sent back. For example:

<MvCALL
ACTION="http://www.my_isp.com/cgi-bin/prog1?animal1=fish&animal2=dinosaur"
METHOD="GET">
<MvEVAL EXPR="{callvalue}">
</MvCALL>

This very basic code simply displays the document that the CGI program sends back.

Calling Miva Script (and other) Programs

<MvCALL>

You can use <MvCALL> to call another Miva Script program and pass data to it. To do this, GET or POST as explained in the previous section, and specify a Miva Script program with the ACTION attribute.

For example:

<MvCOMMENT>Using GET</MvCOMMENT>
<MvCALL
ACTION="http://www.my_isp.com/prog1.mv?animal1=fish&animal2=dinosaur"
METHOD="GET">
...
</MvCALL>
<MvCOMMENT>Using POST</MvCOMMENT>
<MvASSIGN NAME="animal1" VALUE="fish">
<MvASSIGN NAME="animal2" VALUE="dinosaur">
<MvCALL
ACTION="http://www.my_isp.com/prog2.mv"
METHOD="POST"
FIELDS="animal1,animal2">
...
</MvCALL>

In the two examples above, the Miva Script program that is being called can access the variables animal1 and animal2 with the values provided.

<MvCALL> can also call any CGI program (such as a Perl script), using the same constructions; in the ACTION attribute, just substitute the URL of the CGI program being called.

With GET, you can also use the value list syntax for passing arguments to a program:

<MvCOMMENT>Using GET</MvCOMMENT>
<MvCALL
ACTION="http://www.my_isp.com/prog3.mv?fish+dinosaur"
METHOD="GET">
...
</MvCALL>

In this case, the Miva Script program that is being called can access the submitted values via the arg2 and arg3 variables.

Running System Commands

Miva adheres to the principle of 'site sandboxing', which means that it will not interfere with the server or other users on the server. For this reason Miva does not allow system commands (such as UNIX shell commands) to be run directly from Miva. If you need to run system commands, you may be able to write a CGI program (using Perl, shell, or another language) that can execute system commands, and use <MvCALL> to call that CGI program.

File Uploading

Miva supports two forms of file uploading: sending a file from one host to another, and receiving a file from an end-user.

Sending a file

<MvCALL ACTION="http://www.recipient.com/uploadscript.mv"
METHOD="POST"
FILES="var1,var2,...">

Send the files whose name are given by var1,var2,... (relative to the Miva data directory) to the host and script specified by ACTION, where the upload will be processed by the specified script.

Receiving a file

<FORM ACTION="http://www.recipient.com/uploadscript.mv"
METHOD="POST"
ENCTYPE="multipart/form-data">
<INPUT TYPE="FILE" NAME="some_name">
<INPUT TYPE="SUBMIT">
</FORM>

Enables an end-user to choose a file on the local network and send it to the host and script specified by ACTION, where the upload will be processed by the specified script.

Whether you are sending or receiving a file, if the recipient script is a Miva Script program, it must contain the following user-defined functions:

<MvFUNCTION NAME="Miva_ValidateFileUpload"
PARAMETERS="field, filename, content_type">
<MvFUNCTION NAME="Miva_ProcessFileUpload"
PARAMETERS="field,filename,status,tempfile,content_type,size">

Authenticating the Upload

Files can be uploaded to any CGI script that supports file upload. For security reasons--in order to protect hosts that do not want to receive uploaded files from receiving them--if the script at the receiving end is a Miva Script program, it must contain two user-defined functions: one to validate the upload, and the other to process the uploaded file. If either of these scripts are missing, or have the wrong number of parameters, the upload will fail.

The recipient script must contain the following function, which validates the upload:

<MvFUNCTION NAME="Miva_ValidateFileUpload"
PARAMETERS="field,filename,content_type">
...
<MvFUNCRETURN VALUE="{return_code}">
...
</MvFUNCTION>

Note: The specific parameter names used here are arbitrary.

This function will be called automatically by the Miva processor (your program does not need an explicit call to this function). It will be called with three arguments, the name of the Miva variable (field), the filename itself, and the MIME type (content_type) of the file on the uploading server. The actions of this function can be whatever you want, but the function must eventually return one of three values:

How you arrive at this return value is up to you: for example, if you want to upload all files in their entirety, the body of the function could consist of only:

<MvFUNCRETURN VALUE="0">

To skip GIF images but upload all other files:

<MvIF EXPR="{content_type EQ 'image/gif'}">
<MvFUNCRETURN VALUE="-1">
<MvELSE>
<MvFUNCRETURN VALUE="0">
</MvIF>

To upload only up to 1000 bytes of any file:

<MvFUNCRETURN VALUE="1000">

Processing the Upload

The recipient script must contain the following function, which processes the upload:

<MvFUNCTION NAME="Miva_ProcessFileUpload"
PARAMETERS="field,filename,status,tempfile,content_type,size">
...
</MvFUNCTION>

Note: The specific parameter names used here are arbitrary.

This function will be called by the Miva processor with certain information about the file being uploaded (your program does not need an explicit call to this function):

The actions of this function can be whatever you want, but probably the most important thing you would do in this function would be to make a copy of the temporary file (tempfile). For example:

<MvASSIGN NAME="save_it" VALUE="{frename(tempfile,permfile)}">

Make sure the tempfiles are deleted. Since some servers do not remove their temp files, make sure you delete the temp files, where present.

Sending Files

To send a file to another server, use an <MvCALL> in the following manner:

<MvASSIGN NAME="f1" VALUE="file1.txt">
<MvASSIGN NAME="f2" VALUE="file2.htm">
<MvCALL ACTION="http://www.recipient.com/uploadscript.mv"
METHOD="POST"
FILES="f1,f2">

The FILES attribute specifies a list of one or more variables whose values are the names of files to be uploaded; these filenames must be relative to your Miva data directory. The METHOD must be POST (or PUT, which will generally be implemented as POST). The files are uploaded to the server specified by ACTION, but the results of the upload process depend on how the specified script (uploadscript.mv in this example) processes the data it receives. If this script is a Miva Script program, it must contain definitions for the two functions Miva_ValidateFileUpload() and Miva_ProcessFileUpload() described above; both functions will be called once for each uploaded file, and can skip the file, upload it in its entirety, or upload it partially, and then can save the file, allow it to be deleted without saving, and perform any other desired processing.

Note: For this kind of upload, the field parameter (the first argument passed to Miva_ValidateFileUpload() and Miva_ProcessFileUpload()) is the name of the variable containing the filename.

You can also send data to the recipient script using the FIELDS attribute of <MvCALL> at the same time that you send the file(s) to be uploaded.

Receiving Files from End-users

To enable users of your script to send files to your server (or another server), use an HTML FORM in the following manner:

<FORM ACTION="http://www.recipient.com/uploadscript.mv"
METHOD="POST"
ENCTYPE="multipart/form-data">
<INPUT TYPE="FILE" NAME="some_name">
<INPUT TYPE="SUBMIT">
</FORM>

The METHOD must be POST (or PUT, which will generally be implemented as POST), and the ENCTYPE attribute must be set to 'multipart/form-data'. The <INPUT TYPE="FILE"> element creates a form object.

The user browsing a page containing this object can use it to enter or choose a file on the local network. When the form is submitted, the file is uploaded to the server specified by the ACTION, but the results of the upload process depend on how the specified script (uploadscript.mv in this example) processes the data it receives. This script must contain definitions for the two functions Miva_ValidateFileUpload() and Miva_ProcessFileUpload() described above; both of these functions will be called once for each uploaded file, and can skip the file, upload it in its entirety, or upload it partially, and then can save the file, allow it to be deleted without saving, and perform any other desired processing.

Note: For this kind of upload, the field parameter (the first argument passed to Miva_ValidateFileUpload() and Miva_ProcessFileUpload()) is the NAME of the <INPUT> object used to specify the file.

In general, browsers do not permit files specified with http://-style URLs to be uploaded using this method. Instead, local network drive paths (such as c:\...) should be specified. Some browsers do not allow a default VALUE for <INPUT TYPE="FILE"> fields.