Using Internet Utility Classes
Sending HTTP Requests
|
|
This chapter describes how to send HTTP requests (such as POST or GET) and process the responses. It includes the following topics:
You create an instance of
%Net.HttpRequest to send HTTP requests of various kinds and receive the responses. This object is equivalent to a web browser, and you can use it to make multiple requests. It automatically sends the correct cookies and sets the
Referer header as appropriate.
To create an HTTP request, use the following general process:
-
-
Set properties of this instance to indicate the web server to communicate with. The basic properties are as follows:
-
Server specifies the IP address or machine name of the web server. The default is
localhost
-
Port specifies the port to connect to. The default is 80.
-
-
You can make multiple requests from your instance, which will automatically handle cookies and the
Referer header.
-
Use the same instance of
%Net.HttpRequest to send additional HTTP requests if needed. By default, InterSystems IRIS keeps the TCP/IP socket open so that you can reuse the socket without closing and reopening it.
The following shows a simple example:
set request=##class(%Net.HttpRequest).%New()
set request.Server="tools.ietf.org"
set request.Https=1
set request.SSLConfiguration="TEST"
set status=request.Get("/html/rfc7158")
The
Location property specifies the resource that you are requesting from the web server. If you set this property, then when you call the
Get(),
Head(),
Post(), or
Put() method, you can omit the location argument.
In this case, you would use the following values:
Example Properties for %Net.HttpRequest
-
ContentType specifies the
Content-Type header, which specifies the Internet media type of the request body. The default type is none.
Possible values include
application/json,
application/pdf,
application/postscript,
image/jpeg,
image/png,
multipart/form-data,
text/html,
text/plain,
text/xml, and many others. For an extensive list, see
http://www.iana.org/assignments/media-types.
-
The
ContentCharset property controls the desired character set for any content of the request if the content is of type text (
text/html or
text/xml for example). If you do not specify this property, InterSystems IRIS uses the default encoding of the InterSystems IRIS server.
Note:
If you set this property, you must first set the
ContentType property.
-
If this property is true, then if you have content of type
text and if you have not set the
ContentCharset property, no character set is included in the content type; this means that the character set iso-88591 is used for the output of the message.
-
The
WriteRawMode property affects the entity body (if included). It controls how the body of the request is written. By default, this property is false and InterSystems IRIS writes the body in the encoding that is specified in the request headers. If this property is true, InterSystems IRIS writes the body in RAW mode (performing no translation of the character set).
-
The
ReadRawMode property controls how the body of the response is read. By default, this property is false and InterSystems IRIS assumes that the body is in the character set specified in the response headers. If this property is true, InterSystems IRIS reads the body in RAW mode (performing no translation of the character set).
You can send an HTTP request via a proxy server. In order to set this up, specify the following properties of your HTTP request:
-
ProxyServer specifies the host name of the proxy server to use. If this property is not null, the HTTP request is directed to this machine.
To specify a default proxy server for this installation or this namespace, set one of the following global nodes:
The ^%SYS global affects the entire installation, and the ^SYS global affects the current namespace.
-
ProxyPort specifies the port to connect to, on the proxy server. To specify a default proxy port for this installation or this namespace, set one of the following global nodes:
-
-
ProxyHTTPS controls whether the HTTP request is for an HTTPS page, rather than a normal HTTP page. This property is ignored if you have not specified a proxy server. This property changes the default port on the target system to 443, the proxy port. Also see
“Using SSL to Connect.”
-
ProxyTunnel specifies whether to establish a tunnel through the proxy to the target HTTP server. If true, the request uses the HTTP CONNECT command to establish a tunnel. The address of the proxy server is taken from the
ProxyServer and
ProxyPort properties. If
ProxyHttps is true, then once the tunnel is established, InterSystems IRIS negotiates the SSL connection. In this case, the
Https property is ignored because the tunnel establishes a direct connection with the target system.
If the destination server requires login credentials, your HTTP request can include an HTTP
Authorization header that provides the credentials.
You have two general options:
-
-
Set the
Authorization property. For the value, use the authentication information required by the user agent for the resource that you are requesting.
-
Set the
SSLConfiguration property to the name of the activated SSL/TLS configuration to use.
-
Also do one of the following, depending on whether you are using a proxy server:
-
If you are not using a proxy server, set the
Https property to true.
-
If you are using a proxy server, set the
ProxyHTTPS property to true.
In this case, to use an SSL connection to the proxy server itself, set the
Https property to true.
Note that when you use an SSL connection to a given server, the default port on that server is assumed to be 443 (the HTTPS port). For example, if you are not using a proxy server and
Https is true, this changes the default
Port property to 443.
-
-
Timeout specifies how long, in seconds, to wait for a response from the web server. The default is 30 seconds.
-
WriteTimeout specifies how long, in seconds, to wait for a write the web server to complete. By default it will wait indefinitely. The minimum accepted value is 2 seconds.
-
FollowRedirect specifies whether to automatically follow redirection requests from the web server (signalled by the HTTP status codes in the range 300399). The default is true if you are using GET or HEAD; otherwise it is false.
You can set values for and get values of the HTTP headers.
Each of the following properties of
%Net.HttpRequest contains the value of the HTTP header that has the corresponding name. These properties are automatically calculated if you do not set them:
Returns a string containing the main HTTP headers in this request.
Writes the main HTTP headers to the current device.
Returns the current value for any main HTTP header that has been set in this request. This method takes one argument, the name of the header (not case-sensitive); this is a string such as
Host or
Date
Sets the value of a header. Typically you use this to set nonstandard headers; most of the usual headers are set via properties such as
Date. This method takes two arguments:
-
The name of the header (not case-sensitive), without the colon (
:) delimiter; this is a string such as
Host or
Date
-
If you reuse the same instance of
%Net.HttpRequest to send multiple HTTP requests, by default, InterSystems IRIS keeps the TCP/IP socket open so that InterSystems IRIS does not need to close and reopen it.
If you do not want to reuse the TCP/IP socket, do either of the following:
-
-
Add the 'Connection: close' HTTP header in your HTTP request. To do so, add code like the following before you send the request:
Set sc=http.SetHeader("Connection","close")
Note that the HTTP request headers are cleared after each request, so you would need to include this code before each request.
The
SocketTimeout property of
%Net.HttpRequest specifies the window of time, in seconds, during which InterSystems IRIS will reuse a given socket. This timeout is intended to avoid using a socket that may have been silently closed by a firewall. The default value for this property is 115. You can set it to a different value.
Inserts a parameter into the request. This method takes two string arguments: the name of the parameter and the value of the parameter. For example:
do req.InsertParam("arg1","1")
You can insert more than one value for a given parameter. If you do so, the values receive subscripts starting with 1. Within other methods, you use these subscripts to refer to the intended value.
Deletes a parameter from the request. The first argument is the name of the parameter. The second argument is the subscript for the value to delete; use this only if the request contains multiple values for the same parameter.
Counts the number of values that are associated with a given parameter.
Gets the value of a given parameter in the request. The first argument is the name of the parameter. The second argument is the default value to return if the request does not have a parameter with this name; the initial value for this default is the null value. The third argument is the subscript for the value to get; use this only if the request contains multiple values for the same parameter.
Checks whether a given parameter is defined. This method returns true if the parameter has a value. The arguments are the same as for
DeleteParam().
Retrieves the name of the next parameter, if any, after sorting the parameter names via
$Order().
Returns the list of parameters in this request.
An HTTP request can include either a request body or form data. To include a request body, do the following:
-
-
Use the standard stream interface to write data into this stream. For example:
Do oref.EntityBody.Write("Data into stream")
For example, you could read a file and use that as the entity body of your custom HTTP request:
set file=##class(%File).%New("G:\customer\catalog.xml")
set status=file.Open("RS")
if $$$ISERR(status) do $System.Status.DisplayError(status)
set hr=##class(%Net.HttpRequest).%New()
do hr.EntityBody.CopyFrom(file)
do file.Close()
If you use HTTP 1.1, you can send an HTTP request in chunks. This involves setting the Transfer-Encoding to indicate that the message is chunked, and using a zero-sized chunk to indicate completion.
Chunked encoding is useful when the server is returning a large amount of data and the total size of the response is not known until the request is fully processed. In such a case, you would normally need to buffer the entire message until the content length could be computed (which
%Net.HttpRequest does automatically).
To send a chunked request, do the following:
-
-
-
The following methods are available:
Accepts a string argument and writes the string as non-chunked output.
Accepts a string argument. Writes the appropriate Transfer-Encoding heading to indicate a chunked message, and then writes the string as the first chunk.
Accepts a string argument and writes the string as a chunk.
Accepts a string argument and writes the string as a chunk, followed by a zero length chunk to mark the end.
If non-null, the
TranslateTable property specifies the translation table to use to translate each string as it is written. All of the preceding methods check this property.
An HTTP request can include either a request body or form data. To include a form data, use the following methods:
Inserts form data into the request. This method takes two string arguments: the name of the form item and the associated value. You can insert more than one value for a given form item. If you do so, the values receive subscripts starting with 1. Within other methods, you use these subscripts to refer to the intended value
Deletes form data from the request. The first argument is the name of the form item. The second argument is the subscript for the value to delete; use this only if the request contains multiple values for the same form item.
Counts the number of values associated with a given name, in the request.
Checks whether a given name is defined
Retrieves the name of the next form item, if any, after sorting the names via
$Order().
After inserting the form data, you generally call the
Post() method. For example:
Do httprequest.InsertFormData("element","value")
Do httprequest.Post("/cgi-bin/script.CGI")
Set httprequest=##class(%Net.HttpRequest).%New()
set httprequest.SSLConfiguration="MySSLConfiguration"
set httprequest.Https=1
set httprequest.Server="myserver.com"
set httprequest.Port=443
Do httprequest.InsertFormData("portalid","2000000")
set tSc = httprequest.Post("/url-path/")
Quit httprequest.HttpResponse
Inserts a cookie into the request. Specify the following arguments:
-
-
-
Path where the cookie should be stored.
-
Name of the machine from which to download the cookie.
-
Date and time when the cookie expires.
Returns the number of cookies and returns (by reference) an array of cookies.
Deletes a cookie from the request.
Remember that cookies are specific to an HTTP server. When you insert a cookie, you are using a connection to a specific server, and the cookie is not available on other servers.
After you have created the HTTP request, use one of the following methods to send it:
method Delete(location As %String = "",
test As %Integer = 0,
reset As %Boolean = 1) as %Status
Issues the HTTP DELETE request.
method Get(location As %String = "",
test As %Integer = 0,
reset As %Boolean = 1) as %Status
Issues the HTTP GET request. This method causes the web server to return the page requested.
method Head(location As %String,
test As %Integer = 0,
reset As %Boolean = 1) as %Status
Issues the HTTP HEAD request. This method causes the web server to return just the headers of the response and none of the body.
method Post(location As %String = "",
test As %Integer = 0,
reset As %Boolean = 1) as %Status
Issues the HTTP POST request. Use this method to send data to the web server such as the results of a form, or upload a file. For an example, see
“Sending Form Data.”
method Put(location As %String = "",
test As %Integer = 0,
reset As %Boolean = 1) as %Status
Issues the HTTP PUT request. Use this method to upload data to the web server. PUT requests are not common.
method Send(type As %String,
location As %String,
test As %Integer = 0,
reset As %Boolean = 1) as %Status
Sends the specified type of HTTP request to the server. This method is normally called by the other methods, but is provided for use if you want to use a different HTTP verb. Here
type is a string that specifies an HTTP verb such as
"POST".
-
Each method returns a status, which you should check.
-
If the method completes correctly, the response to this request will be in the
HttpResponse property.
-
-
-
Use the
test argument to check that you are sending what you are expecting to send:
-
If
test is 1 then instead of connecting to a remote machine, the method will just output what it would have send to the web server to the current device.
-
If
test is 2 then it will output the response to the current device after issuing the HTTP request.
-
Each method automatically calls the
Reset() method after reading the response from the server, except if
test=1 or if
reset=0.
Set httprequest=##class(%Net.HttpRequest).%New()
Set httprequest.Server="www.intersystems.com"
Do httprequest.Get("/")
To create and send a multipart POST request, use the
%Net.MIMEPart classes, which are discussed more fully
later in this book. The following example sends a POST request with two parts. The first part includes file binary data, and the second part includes the file name.
ClassMethod CorrectWriteMIMEMessage3(header As %String)
{
// Create root MIMEPart
Set RootMIMEPart=##class(%Net.MIMEPart).%New()
//Create binary subpart and insert file data
Set BinaryMIMEPart=##class(%Net.MIMEPart).%New()
Set contentdisp="form-data; name="_$CHAR(34)_"file"_$CHAR(34)_"; filename="
_$CHAR(34)_"task4059.txt"_$CHAR(34)
Do BinaryMIMEPart.SetHeader("Content-Disposition",contentdisp)
Set stream=##class(%FileBinaryStream).%New()
Set stream.Filename="/home/tabaiba/prueba.txt"
Do stream.LinkToFile("/home/tabaiba/prueba.txt")
Set BinaryMIMEPart.Body=stream
Do BinaryMIMEPart.SetHeader("Content-Type","text/plain")
// Create text subpart
Set TextMIMEPart=##class(%Net.MIMEPart).%New()
Set TextMIMEPart.Body=##class(%GlobalCharacterStream).%New()
Do TextMIMEPart.Body.Write("/home/tabaiba/prueba.txt")
// specify some headers
Set TextMIMEPart.ContentType="text/plain"
Set TextMIMEPart.ContentCharset="us-ascii"
Do TextMIMEPart.SetHeader("Custom-header",header)
// Insert both subparts into the root part
Do RootMIMEPart.Parts.Insert(BinaryMIMEPart)
// create MIME writer; write root MIME message
Set writer=##class(%Net.MIMEWriter).%New()
// Prepare outputting to the HttpRequestStream
Set SentHttpRequest=##class(%Net.HttpRequest).%New()
Set status=writer.OutputToStream(SentHttpRequest.EntityBody)
if $$$ISERR(status) {do $SYSTEM.Status.DisplayError(status) Quit}
// Now write down the content
Set status=writer.WriteMIMEBody(RootMIMEPart)
if $$$ISERR(status) {do $SYSTEM.Status.DisplayError(status) Quit}
Set SentHttpRequest.Server="congrio"
Set SentHttpRequest.Port = 8080
Set ContentType= "multipart/form-data; boundary="_RootMIMEPart.Boundary
Set SentHttpRequest.ContentType=ContentType
set url="alfresco/service/sample/upload.json?"
_"alf_ticket=TICKET_caee62bf36f0ea5bd51194fce161f99092b75f62"
set status=SentHttpRequest.Post(url,0)
if $$$ISERR(status) {do $SYSTEM.Status.DisplayError(status) Quit}
}
-
By default, this property is false and InterSystems IRIS assumes that the body is in the character set specified in the HTTP headers of the response (and translates the character set accordingly).
-
If this property is true, InterSystems IRIS reads the body in RAW mode (performing no translation of the character set).
You can also use the
OutputToDevice() method, which writes the full response to the current device. The headers are not in the same order as generated by the web server.
The following shows a simple example in which we copy the response stream to a file and save it:
set request=##class(%Net.HttpRequest).%New()
set request.Server="tools.ietf.org"
set request.Https=1
set request.SSLConfiguration="TEST"
set status=request.Get("/html/rfc7158")
if $$$ISERR(status) {
do $system.OBJ.DisplayError()
} else {
set response=request.HttpResponse
}
Set file=##class(%FileCharacterStream).%New()
set file.Filename="c:/temp/rfc7158.html"
set status=file.CopyFrom(response.Data)
if $$$ISERR(status) {
do $system.OBJ.DisplayError()
}
do file.%Close()
Returns the value of the given header.
Returns the name of the next header after the given header.
Each of these methods takes a single argument, a string that is the name of an HTTP header.
You can also use the
OutputHeaders() method, which writes the HTTP headers to the current device (although not in the same order they were generated).
-
StatusLine stores the HTTP status line, which is the first line of the response.
-
-
-
ContentInfo stores additional information about the response body.
-
-
HttpVersion indicates the version of HTTP that is supported by the web server that sent the response.
Content Date/Time: 2019-02-23 01:10:53