Using Caché Internet Utilities
Sending HTTP Requests
[Home] [Back] [Next]
InterSystems: The power behind what matters   
Class Reference   
Search:    

This chapter describes how to send HTTP requests (such as POST or GET) and process the responses. It includes the following topics:

Introduction to HTTP Requests
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:
  1. Create an instance of %Net.HttpRequest.
  2. Set properties of this instance to indicate the web server to communicate with. The basic properties are as follows:
  3. Optionally set other properties and call methods of your HTTP request, as described in Specifying HTTP Request Properties.”
  4. Then send an HTTP request, by calling the Get() method or other methods of your instance of %Net.HttpRequest, as described in Sending the HTTP Request.”
    You can make multiple requests from your instance, which will automatically handle cookies and the Referer header.
    Note:
    If you created this HTTP request for use with the Ensemble outbound adapter (EnsLib.HTTP.OutboundAdapter), then instead use the methods of that adapter to send the request.
  5. Use the same instance of %Net.HttpRequest to send additional HTTP requests if needed. By default, Caché keeps the TCP/IP socket open so that you can reuse the socket without closing and reopening it.
    For additional information, see Managing Socket Reuse.”
Specifying HTTP Request Properties
Before you send an HTTP request (see Sending the HTTP Request), you can specify its properties, as described in the following sections:
The Location Property
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.
For example, suppose that you are sending an HTTP request to the URL http://machine_name/cache/index.html
In this case, you would use the following values:
Example Properties for %Net.HttpRequest
Properties Value
Server machine_name
Location cache/index.html
Specifying the Internet Media Type and Character Encoding
You can use the following properties to specify the Internet media type (also called MIME type) and character encoding in your instance of %Net.HttpRequest and its response:
Using a Proxy Server
You can send an HTTP request via a proxy server. In order to set this up, specify the following properties of your HTTP request:
For details, see the class documentation for %Net.HttpRequest.
Providing Login Credentials
If the destination server requires login credentials, your HTTP request can include an HTTP Authorization header that provides the credentials.
Note:
The %Net.HttpRequest class supports only basic HTTP authentication; that is, the credentials are sent in base-64 encoded form. This type of authentication is not secure unless you use SSL (see “Using SSL to Connect”).
You have two general options:
If you are using a proxy server, you can also specify login credentials for the proxy server; to do so, set the ProxyAuthorization property; see Using a Proxy Server.”
For details, see the class documentation for %Net.HttpRequest.
Using SSL to Connect
The %Net.HttpRequest class supports SSL connections. To send the request via SSL, do the following:
  1. Set the SSLConfiguration property to the name of the activated SSL/TLS configuration to use.
    For information on creating and managing SSL/TLS configurations, see Using SSL/TLS with Caché in the Caché Security Administration Guide. The SSL/TLS configuration includes an option called Configuration Name, which is the string to use in this setting.
  2. Also do one of the following, depending on whether you are using a proxy server:
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.
Also see Using a Proxy Server.”
Server Identity Checking
By default, when an instance of %Net.HttpRequest connects to a SSL/TLS secured web server, it checks whether the certificate server name matches the DNS name used to connect to the server. If these names do not match, the connection is not permitted. This default behavior prevents “man in the middle” attacks and is described in RFC 2818, section 3.1; also see RFC 2595, section 2.4.
To disable this check, set the SSLCheckServerIdentity property to 0.
The HTTPVersion, Timeout, WriteTimeout, and FollowRedirect Properties
%Net.HttpRequest also provides the following properties:
Setting and Getting HTTP Headers
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:
The %Net.HttpRequest class provides general methods that you can use to set and get the main HTTP headers. These methods ignore Content-Type and other entity headers.
ReturnHeaders()
Returns a string containing the main HTTP headers in this request.
OutputHeaders()
Writes the main HTTP headers to the current device.
GetHeader()
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
SetHeader()
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:
  1. The name of the header (not case-sensitive), without the colon (:) delimiter; this is a string such as Host or Date
  2. The value of that header
You cannot use this method to set entity headers or read-only headers (Content-Length and Connection).
For details, see the class documentation for %Net.HttpRequest.
Managing Keep-alive Behavior
If you reuse the same instance of %Net.HttpRequest to send multiple HTTP requests, by default, Caché keeps the TCP/IP socket open so that Caché does not need to close and reopen it.
If you do not want to reuse the TCP/IP socket, do either of the following:
The SocketTimeout property of %Net.HttpRequest specifies the window of time, in seconds, during which Caché 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.
Handling HTTP Request Parameters
When you send an HTTP request (see Sending the HTTP Request), you can include parameters in the location argument; for example: "/test.html?PARAM=%25VALUE" sets PARAM equal to %VALUE.
You can also use the following methods to control how your instance of %Net.HttpRequest handles parameters:
InsertParam()
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.
DeleteParam()
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.
CountParam()
Counts the number of values that are associated with a given parameter.
GetParam()
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.
IsParamDefined()
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().
NextParam()
Retrieves the name of the next parameter, if any, after sorting the parameter names via $Order().
ReturnParams()
Returns the list of parameters in this request.
For details, see the class documentation for %Net.HttpRequest.
Including a Request Body
An HTTP request can include either a request body or form data. To include a request body, do the following:
  1. Create an instance of %GlobalBinaryStream or a subclass. Use this instance for the EntityBody property of your HTTP request.
  2. 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()
Sending a Chunked Request
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:
  1. Create a subclass of %Net.ChunkedWriter, which is an abstract stream class that defines an interface for writing data in chunks.
    In this subclass, implement the OutputStream() method.
  2. In your instance of %Net.HttpRequest, create an instance of your %Net.ChunkedWriter subclass and populate it with the request data that you want to send.
  3. Set the EntityBody property of your %Net.HttpRequest instance equal to this instance of %Net.ChunkedWriter.
    When you send the HTTP request (see Sending the HTTP Request), it calls the OutputStream() method of the EntityBody property.
In your subclass of %Net.ChunkedWriter, the OutputStream() method should examine the stream data, decide whether to chunk it and how to do so, and invoke the inherited methods of the class to write the output.
The following methods are available:
WriteSingleChunk()
Accepts a string argument and writes the string as non-chunked output.
WriteFirstChunk()
Accepts a string argument. Writes the appropriate Transfer-Encoding heading to indicate a chunked message, and then writes the string as the first chunk.
WriteChunk()
Accepts a string argument and writes the string as a chunk.
WriteLastChunk()
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.
Sending Form Data
An HTTP request can include either a request body or form data. To include a form data, use the following methods:
InsertFormData()
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
DeleteFormData()
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.
CountFormData()
Counts the number of values associated with a given name, in the request.
IsFormDataDefined()
Checks whether a given name is defined
NextFormData()
Retrieves the name of the next form item, if any, after sorting the names via $Order().
For details on these methods, see the class documentation for %Net.HttpRequest.
Example 1
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")
Example 2
For another example:
    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
Inserting, Listing, and Deleting Cookies
%Net.HttpRequest automatically manages cookies sent from the server; if the server sends a cookie, your instance of %Net.HttpRequest will return this cookie on the next request. (For this mechanism to work, you need to reuse the same instance of %Net.HttpRequest.)
Use the following methods to manage cookies within your instance of %Net.HttpRequest:
InsertCookie()
Inserts a cookie into the request. Specify the following arguments:
  1. Name of the cookie.
  2. Value of the cookie.
  3. Path where the cookie should be stored.
  4. Name of the machine from which to download the cookie.
  5. Date and time when the cookie expires.
GetFullCookieList()
Returns the number of cookies and returns (by reference) an array of cookies.
DeleteCookie()
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.
For details on these methods, see the class documentation for %Net.HttpRequest.
Sending the HTTP Request
After you have created the HTTP request, use one of the following methods to send it:
Get()
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.
Head()
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.
Post()
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.”
Put()
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.
Send()
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".
In all cases:
For example:
 Set httprequest=##class(%Net.HttpRequest).%New()
 Set httprequest.Server="www.intersystems.com"
 Do httprequest.Get("/")
For other examples, see the class documentation for %Net.HttpRequest.
Creating and Sending Multipart POST Requests
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}
}
Accessing the HTTP Response
After you send an HTTP request, the HttpResponse property of the request is updated. This property is an instance of %Net.HttpResponse. This section describes how to use the response object. It includes the following topics:
For details, see the class documentation for %Net.HttpRequest.
Accessing the Data of the Response
The body of the HTTP response is contained in the Data property of the response. This property contains a stream object (specifically %GlobalBinaryStream), To work with this stream, use the standard stream methods: Write(), WriteLine(), Read(), ReadLine(), Rewind(), MoveToEnd(), and Clear(). You can also use the Size property of the stream.
The ReadRawMode property of the request controls how the body of the response is read.
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.
Getting an HTTP Header by Name
The %Net.HttpResponse class stores its HTTP headers in a Caché multidimensional array. To access the headers, use the following methods:
GetHeader()
Returns the value of the given header.
GetNextHeader()
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).
Accessing Other Information about the Response
The %Net.HttpResponse class provides properties that store other specific parts of the HTTP response: