Xb2.NET - Internet Library for Xbase++

Release: 4.3.10
Copyright © 2001-2023, Xb2.Net inc.
All rights reserved

CLASS HIERARCHY

   xbSocket
    |    Complete TCP and UDP sockets class library that provides a protocol-independent base for
    |    developing virtually any kind of communications software.
    |
    |__ xbWebSocket (derived from: xbSocket)
    |          This class implements the WebSocket protocol as defined in RFC 6455. Instances of this class
    |          may be used in both client and server implementations.
    |
    |__ xbServer (derived from: xbSocket, Thread)
    |      |    A generic, easily configured and protocol-independent server class.
    |      |
    |      |__ xbHTTPServer (derived from: xbServer)
    |                A powerful object-oriented HTTP 1.1 web and SOAP server that is build right into your
    |                Xbase++ application. No need to configure and manage complex 3P web servers,
    |                gateways and CGI scripts. Your Xbase++ program is the server!
    |
    |__ xbSocketThread (derived from: xbSocket, Thread)
    |          This is the client thread that is spawned by xbServer when a connection with a peer is accepted.
    |          This "worker" thread will handle the request and send a response back to the connected client.
    |
    |__ xbHTTPThread (derived from: xbSocket, Thread)
               This is the client thread that is spawned by xbHTTPServer when a connection is accepted
               from a user agent (a browser). This "worker" thread is responsible for handling the client
               request and generating an appropriate xbHTTPResponse that will be sent back to the client.

   xbHTTPMessage
    |   An abstract class for composing and parsing HTTP messages for client and server.
    |
    |__ xbHTTPRequest (derived from: xbHTTPMessage, xbURI)
    |        Client side: Compose HTTP request and send to HTTP server.
    |        Server side: Parse HTTP request received from client.
    |
    |__ xbHTTPResponse (derived from: xbHTTPMessage)
             Client side: Parse HTTP response received from server.
             Server side: Compose HTTP response and send to client.

   xbHTTPClient
    |    Provides a higher level interface for developing HTTP client applications.
    |
    |__ xbXMLDocument (derived from: xbHTTPClient)
    |        This class provides a simplified means for generating XML requests and parsing XML responses.
    |
    |__ xbSOAPEnvelope (derived from: xbHTTPClient)
             This class provides the code necessary to generate and parse SOAP messages. SOAP is a
             remote procedure calling protocol that encodes requests and responses in XML format.
             Using SOAP a client can execute methods or functions on a server and receive an XML
             response containing the return values.

   xbComplexType
        Used to represent complex data structures. Data structures can be nested, and may contain any
        other type, including an array. Instances of xbComplexType are typically used by the
        xbSOAPEnvelope class to serialize and deserialize complex data structures.

   xbForm
        This class represents a url-encoded form. The form typically contains data expressed as
        "name=value" pairs, encoded for safe transport over the net. This class allows you to parse
        an existing form as well as create a brand new form.

   xbFTPClient
        FTP (File Transfer Protocol) client provides methods for managing directories and files on a remote
        FTP or FTPS server. The class is fully compliant with RFC's 959, 2228, 2428 and 4217. It provides
        support for AUTH TLS, AUTH SSL and Implicit SSL connections.

   xbJSON
        This class provides methods for serializing and deserializing JSON objects.

   xbPayload
        Provides methods for serializing and deserializing one or more attachments of any size (files,
        character strings, objects or any Xbase++ data) for transmission between an HTTP client and
        server. This class is also used by the xbSOAPEnvelope class for sending SOAP attachments.

   xbSession
        HTTP by nature is stateless and in itself provides limited session management capability. This
        class simplifies session management and provides the ability of saving persistent data across
        multiple HTTP requests. Sessions are automatically managed by the xbHTTPServer class.

   xbSSLContext
        Provides a context for implementing secure network communications using the OpenSSL library.
        Once initialized, an xbSSLContext object can be attached to an xbSocket, xbServer, xbHTTPServer,
        xbHTTPClient, xbXMLDocument or xbSOAPEnvelope instance to provide secure communications.

   xbStream
        Provides generic methods for reading and writing to data stream files.

   xbTLog
        Class for logging client requests using Extended Log File Format (W3C Working Draft
        WD-logfile-960323). This log format is compatible with Microsoft Internet Information Server
        (IIS) and is supported by many third party web log analyzers.

   xbURI
        Create, parse, encode and decode URI and URL strings.

FUNCTIONS

Generic functions

xbCompile( cPrgFile ) → lSuccess Compiles a single Xbase++ PRG file to generate a DLL. cPrgFile is the file name (including path) pointing to a standard Xbase++ PRG file to be compiled. The function returns .T. if cPrgFile is successfully compiled. When compiled, the DLL will have the same name and reside in the same folder as the input PRG file.
! The Xbase++ compiler must be (a) installed on the same operating system where the executable is running, and (b) accessible to the running executable program (permissions / access rights). xbCPConvert( cString, [nFromCP], [nToCP] ) → cOutput Translates an input character string from one codepage to another. The return value is a character string in the desired codepage. Parameters: cString The character string to be converted. nFromCP An integer numeric value indicating the codepage of the input string. This parameter is optional and can be given the value of any code page that is installed or available in the system. If not supplied it defaults to ANSI (codepage 0 or CP_ACP). nToCP An integer numeric value indicating the codepage to convert to. This parameter is optional and can be given the value of any code page that is installed or available in the system. If not supplied it defaults to UTF8 (codepage 65001 or CP_UTF8). xbCreateGuid( [lSeparator] ) → cGuid Returns a Globally Unique Identifier as a hex (base16) encoded string. The optional parameter lSeparator determines the format of the output. When lSeparator is NIL or .T., the output will be 36-characters long in the following format: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx". When lSeparator is set to .F., the returned value will be a shorter 32-character (lower-case) hex string with no dashes.

When the originating computer does not have an ethernet address, the generated ID is only guaranteed to be unique among all IDs generated on the same computer. Although very small, the possibility however does exists that another computer without an ethernet address generated the identical ID. Computers with ethernet addresses generate GUIDs that are guaranteed to be globally unique.

Example: xbCreateGuid() // → "6B29FC40-CA47-1067-B31D-00DD010662DA"
xbCreateGuid(.T.) // → "0e0384ada455de45bcf335756d07b7b1"
xbDec2Hex( nPositiveInt ) → cHex Converts a positive integer value into hexadecimal (base 16) format. Negative input values return a null string.
! Largest value that may be converted without loss of precision is 9,007,199,254,740,991 (0x1fffffffffffff)

Example: xbDec2Hex(9876543210) // → "24CB016EA"
xbDec2Hex(-10) // → ""
xbErrorLog( xError, [nErrorCode], [isSSL], [cFile], [lFlash], [lLogCallstack] ) → cErrorMessage This function will log an error or event to a file. It is typically called from within an xbSocket:OnError codeblock. The function returns the complete error message as a string. Parameters: xError This parameter specifies the type of event that will be logged. The options are as follows:
- An error object, derived from the Xbase++ "Error" class.
- An object derived from the "xbSocket" class.
- A character string. nErrorCode The WinSock or OpenSSL error code number. isSSL A logical value, which when set to .T., indicates that the error was raised by the OpenSSL library. cFile The name of the file where the information will be logged. If not specified, the default is xbSocket():ErrorLogFile. lFlash An optional logical value that is used to provide visual feedback of the error. When set to .T., the error message will be briefly flashed on the console display screen. The default is .F., meaning that no visual feedback is provided. lLogCallstack An optional logical value specifying if the callstack will be written to the file. The default is to log the callstack, however this can be turned off by setting this parameter to .F. xbEval( cFileName, [xParamList,...] ) → xRet Execute the function cFileName with parameters xParamList.
cFileName is a standard Xbase++ PRG file that is dynamically compiled into a DLL when called using xbEval. If the PRG script is modified, the DLL is automatically recompiled and the new code is loaded (with no user intervention).
? Compiled .PRG Scripts F.A.Q.

Example: aLines := xbEval("SearchLog.prg", cSearchStr, dDateStart, Date(), .T.)
xbGetComputerName() → cName Retrieves the NetBIOS name of the local computer. This name is established at system startup, when the system reads it from the registry. xbGetErrorString( [nError] ) → cErrorMessage Retrieve the message text for a system defined error code. The nError parameter is optional, if not suppled it defaults to xbGetLastError. xbGetFileMimeType( cFileName ) → cMimeType Return the MIME media type for a given file name. The MIME media type is determined by file name's 3 or 4 character extension. For example; file names with the extension .HTM will have a MIME media type of "text/html". xbGetLastError() → nErrorCode Retrieves the calling thread's last system error code. The last error code is maintained on a per-thread basis (multiple threads do not overwrite each other's last-error code). To obtain an error string for system error codes, use the xbGetErrorString function. xbGetMachineID() → cMachineGuid Returns the GUID of host system that is hardware independent (no usage of MAC, BIOS or CPU) and is unique to the installed OS. The ID is generated during the installation of Windows and will remain the same for the host system unless the OS is reinstalled. Note that the ID would be the same on multiple machines if a machine is restored from a backup or clone.

! The machine ID should be considered 'confidential' because it uniquely identifies a host. Therefore, for privacy reasons do not store the returned value in clear text. Use the xbHMAC() function to hash the ID with a fixed application-specific key prior to storage. This way, the hashed value will still uniquely identify the host but the ID will remain private and application specific. Example:

cHostID := xbHexEncode(xbHMAC(SHA1, "My Secret Key", xbGetMachineID()))
xbGetTempPath() → cPath Retrieves the path of the directory designated for temporary files. xbGetTickCount() → nMilliseconds Return the number of milliseconds that have elapsed since the system was started. The maximum return value is limited to a 32 bit integer (0 to 4294967295) therefore, the time will wrap around to zero if the system is run continuously for 49.7 days. xbGMTDate( [dDate], [cnTime] ) → cGMTDate Return a string representing the date and time in GMT using Internet conventions in the following form:
Day, DD Mon YYYY HH:MM:SS GMT, eg:
Wed, 07 Oct 2004 19:23:50 GMT

Both parameters are optional if not specified the current date/time is used. cnTime can be a numeric as returned by SECONDS(), or a string as returned by TIME(). The timezone is based on the return value of xbTimezoneOffset(). xbHex2Dec( cHex ) → nVal Converts a string representing a hexadecimal (base 16) value into it's decimal numeric format.
! Largest value that may be converted without loss of precision is 0x1fffffffffffff.

Example: xbHex2Dec("24CB026F") // → 617284207
xbHex2Dec("0x24cb026f") // → 617284207
xbHex2Dec("D8:13:47:4B") // → 3625142091
xbHex2Dec("1fffffffffffff") // → 9007199254740991
xbHTTPErrorHandler( oError, [cFile], [lLogError] ) → cErrorMessage This is the default HTTP error handler that will be used in the absence of an xbHTTPServer:onHTTPError codeblock. The function is evaluated when a runtime error occurs during the processing of an HTTP request. It will log the error to a file, prepare an HTML error message and send it to the client. The function returns the HTML formatted string that will be sent to the client. Parameters: oError An Xbase++ error object. cFile The name of the file where the error will be logged. If not specified, the default is xbSocket():ErrorLogFile. lLogError An optional logical value that determines whether the error is logged to a file. The default behavior is to log the error to a file, however this can be disabled by setting lLogError to .F.

Example: // use default error handler but don't log errors:
oServer:onHTTPError := {|oError| xbHTTPErrorHandler(oError,nil,.f.)}
xbHTTPReverseProxy( oClient, cOriginHost, nOriginPort ) → lSuccess Allows your HTTP server to act as a middleman (or proxy), relaying HTTP requests to a different server on behalf of the connected client. The function will return .T. if the connection to the origin server is successful, or .F. if the connection failed. The resources returned to the client appear as if they originated from the proxy server itself.

Here are some benefits of a reverse proxy:

Parameters: oClient The xbHTTPThread object containing the HTTP request to be relayed to the origin server. cOriginHost A character string representing the hostname, a dotted-decimal IPv4 address, an IPv6 hex address of the origin server. nOriginPort The port number the origin server is listening on.

Example: oServer:FilterRequest := {|o|FilterRequest(o)}

FUNCTION FilterRequest(oClient)
Local cHost := oClient:HTTPRequest:Host()
// send all requests for the 'mail' subdomain to NGINX
if !empty(cHost) .and. "mail." $ lower(cHost)
  if ! xbHttpReverseProxy(oClient, "192.168.10.9", 8080)
    // unable to relay request to origin server
    oClient:HTTPResponse:StatusCode := 504
    oClient:HTTPResponse:ContentType("text/plain")
  endif
  // request handled, no further processing needed
  Return .F.
endif
Return .T.

xbHTTPStatusText( nStatusCode ) → cStatusText Return a text message corresponding to an HTTP response status code. An HTTP status code is a 3-digit integer where the first digit defines the class of response. There are 5 values for the first digit (the remaining two digits are not categorized)

1xx: Informational - Request received, continuing process
2xx: Success - The action was successfully received, understood, and accepted
3xx: Redirection - Further action must be taken to complete the request
4xx: Client Error - The request contains bad syntax or cannot be fulfilled
5xx: Server Error - The server failed to fulfill an apparently valid request

The following is a list of HTTP response status codes and their associated text message:
CodeText Message
100Continue
101Switching Protocols
200OK
201Created
202Accepted
203Non-Authoritative Information
204No Content
205Reset Content
206Partial Content
300Multiple Choices
301Moved Permanently
302Found
303See Other
304Not Modified
307Temporary Redirect
308Permanent Redirect
400Bad Request
401Unauthorized
402Payment Required
403Forbidden
404Not Found
405Method Not Allowed
406Not Acceptable
407Proxy Authentication Required
408Request Timeout
409Conflict
410Gone
411Length Required
412Precondition Failed
413Payload Too Large
414URI Too Long
415Unsupported Media Type
416Range Not Satisfiable
417Expectation Failed
418I'm a teapot
421Misdirected Request
426Upgrade Required
428Precondition Required
429Too Many Requests
431Request Header Fields Too Large
500Internal Server Error
501Not Implemented
502Bad Gateway
503Service Unavailable
504Gateway Timeout
505HTTP Version Not Supported
xbIP2Decimal( cAddress ) → nAddress Converts a dotted-decimal IP address into its equivalent decimal format. The return value is a 32-bit unsigned integer.

Example: nIP := xbIP2Decimal('216.19.71.75') // returns 3625142091
xbRand( [nInt1 [,nInt2]] ) → nRand Alternative to the Xbase++ function RandomInt(). Returns a wider range of random numbers than the native Xbase++ function. xbRandomID( [nLen] ) → cString Generate a random base 36 string with a length of nLen, eg: 'XCF9GNM5'. The parameter nLen is optional with a default value of 8. xbSaveToFile( cString, [cFile], [lAppend], [nMaxSize] ) → lSuccess Write the string cString to a file. If not specified, cFile defaults to xbSocket():ErrorLogFile. If the file does not exist, it will be created. If lAppend is set to .T. (the default), then cString will be appended to the end of the file. Otherwise the current file (if there is one) will be overwritten. The function returns .T. if the data was written successfully.

The optional parameter nMaxSize can be used to specify the maximum size in bytes of the log file. When the file reaches this size, it will be renamed with a tilde "~" extension and a new file will be created. If not provided nMaxSize defaults to 1000000 bytes. xbSetFileMimeType( cFileExtension, cMimeType ) → NIL This function allows programmer to add new file MIME types to be returned by function xbGetFileMimeType. These new MIME media types will also be used by the xbHTTPServer class when serving media files to a connected HTTP client. The function may be called repeatedly to add multiple file extension and MIME type pairs.

Example: xbSetFileMimeType("PDF", "application/pdf")
xbSetFileMimeType("AVI", "video/avi")
xbSocketErrorText( [nErrorCode], [isSSL] ) → cErrorText When isSSL is NIL or .F., return error description of WinSock error code nErrorCode. Otherwise, when isSSL is .T., return error description of OpenSSL error code nErrorCode. If not supplied, nErrorCode defaults to the most recent error code produced in this thread. xbTcpWindowSize( [nSize] ) → nTcpWindowSize Get or set the system's TCP window size parameter. The TCP window is the amount of unacknowledged data in flight between the sender and the receiver. Although TCP tries to optimize the transmit window to maximize throughput over the lifetime of a connection, the value returned by xbTcpWindowSize puts a hard limit on the window size.

The TCP window size is stored in the system registry under the following path:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\TcpWindowSize

The system's TCP window size registry value can be changed by setting nSize to the desired number of bytes. The optimal window size for a given TCP connection can be determined by multiplying the network bandwidth by the delay. For example a 1.5Mbps DSL connection with a round-trip delay of 200ms gives a window size of 37,500 bytes. Keep in mind that this parameter cannot be changed at will. A system reboot is typically required for the change to become effective. The window size should therefore be made large enough to accommodate the fastest networks with the slowest delay. xbTimer() → nTimestamp Returns a timestamp that may be used with the HR (high resolution) timer functions xbTimerDelta() and xbTimerDelta1000() to measure elapsed time.

Example: t := xbTimer()
DoSomething()
? "elapsed time:", xbTimerDelta(t), "microseconds"
xbTimerDelta( nStart ) → nMicroseconds HR timer that returns a decimal value representing elapsed time in microseconds. nStart is the starting timestamp returned by xbTimer(). xbTimerDelta1000( nStart ) → nMilliseconds HR timer that returns an integer value representing elapsed time in milliseconds. nStart is the starting timestamp returned by xbTimer(). xbTimerResolution() → nMicroseconds Returns resolution in microseconds of HR timer (typically 0.1 microseconds). xbTimezoneOffset( [nMinutes] ) → nTimezoneOffset Get/set the difference between the local time and GMT as an integer representing the number of minutes. Unless the local time is GMT, this function should be called at program start so that xbGMTDate() can return the correct GMT date. If a parameter is not specified, the function returns the current timezone offset. When using Xbase++ 1.7 or higher, the timezone offset will be automatically set on startup to the return value of SetLocale(NLS_ITZBIAS). xbU32( nSignedInt32 ) → nUnsignedInt32 Convert a 32-bit signed integer to a 32-bit unsigned value. The return value will an integer numeric value in the range of 0 to 4294967295. xbUniqueFile( [cPath], [cPrefix], [cExt], [nAttr], [@nHandle] ) → cFileName Creates and returns a file name that is unique within the directory specified. The file name is returned including path information. If an error occurs, the return value is a null string and the error code can be retrieved using FError(). Parameters: cPath Optional character string that specifies the directory in which the file will be created. If not provided, the system temporary file directory (defined in the 'TEMP' environment variable) is used. cPrefix Optional character string to use as the file name prefix. If not specified, the file prefix will default to "~". cExt Optional character string to use as the file name extension. If not specified, the file extension will default to ".tmp". nAttr An integer numeric value which sets the access mode for the file. Various symbolic constants are defined in the Xbase++ include file "Fileio.ch". For more information, consult the Xbase++ documentation for FCREATE. This parameter is optional and defaults to FC_NORMAL: nHandle This is an optional output parameter. If provided, the reference operator "@" must be placed in front of the argument nHandle. In this case, the newly created file will be left in an open state with the low-level file handle returned in the memory variable nHandle. The file remains open for write access until the file handle is passed to the Xbase++ function FClose(). xbUnixTime() → nUTCTime Returns an integer representing the current UTC UNIX Epoch time (number of seconds that have elapsed since 1970-01-01T00:00:00Z). xbUnixTime2Date( nTime ) → dDate Returns date given a UTC UNIX Epoch time (number of seconds that have elapsed since 1970-01-01T00:00:00Z). xbWChar( cString, [nCodePage] ) → cUnicodeString Convert a character string from multi-byte order to wide-char unicode. Parameters: cString The character string to be converted. nCodePage An integer numeric value indicating the codepage of the input string. This parameter is optional and may be given the value of any code page that is installed or available in the system. If not supplied it defaults to ANSI (codepage 0 or CP_ACP). xbWindowHandle( [nHandle] ) → nWindowHandle Get or set the application's default window handle. A specific window handle can be set by calling this function with a numeric nHandle value. The return value is used as the parent window by certain Internet error dialogs.

Bitwise functions

xbAND( n1, n2 ) → nResult Returns the bitwise AND of the values provided by n1 and n2. xbOR( n1, n2 ) → nResult Returns the bitwise OR of the values provided by n1 and n2. xbXOR( n1, n2 ) → nResult Returns the bitwise XOR of the values provided by n1 and n2. xbNOT( nVal ) → nResult Returns the bitwise complement of nVal. xbSHL( nVal, [nCount] ) → nResult Returns the value of nVal, shifted left by nCount bits. As bits are shifted left, zero's are placed on the right. If not specified, nCount defaults to 1. xbSHR( nVal, [nCount] ) → nResult Returns the value of nVal, shifted right by nCount bits. As bits are shifted right, zero's are placed on the left. If not specified, nCount defaults to 1. xbHtonl( nULong ) → nResult Convert a 32-bit unsigned long integer from host byte order to network byte order (little-Endian to big-Endian). xbHtons( nUShort ) → nResult Convert a 16-bit unsigned short integer from host byte order to network byte order (little-Endian to big-Endian). xbNtohl( nULong ) → nResult Convert a 32-bit unsigned long integer from network byte order to host byte order (big-Endian to little-Endian). xbNtohs( nUShort ) → nResult Convert a 16-bit unsigned short integer from network byte order to host byte order (big-Endian to little-Endian).

Encoding functions

xbBase64Encode( cString, [lCRLF76] ) → cBase64String Return cString in base64 encoded format. Base64 encoding coverts binary data from 8 bits per byte to 6 bits per byte. Information in 3-8bit bytes (24 bits) is converted into 4-6bit bytes (same 24 bits), resulting in a encoded string that is 1.333 times larger than the original.

The optional parameter lCRLF76 can be set to .T. in order to have the encoded output stream formatted in lines of 76 characters. The default for lCRLF76 is .F. xbBase64Decode( cBase64String ) → cOriginalString Decodes a base64 encoded string into its original form. xbCrypt( cInString, [nLen], [nSeed] ) → cOutString Encrypt or decrypt a string. Parameters: cInString The string to be encrypted or decrypted. nLen Optional number of characters within cInString to process. nSeed Optional random number seed. If cInString is the encrypted string, then the same random number seed as was used to encrypt the string must be supplied to decrypt it.

Example: cCrypt := xbCrypt("ABCD")
? xbCrypt(cCrypt) // → "ABCD"
xbEscape( cString ) → cEscapedString Convert an input string cString into URL encoded format where reserved characters are replaced with a % followed by two hexadecimal digits. For example, the space character is replaced with %20, a question mark (?) is replaced with %27. The following is a list of characters that are never escaped:
0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_.!~()

Example: xbEscape("C:\Program Files\Microsoft SQL Server") // → "C%3A%5CProgram%20Files%5CMicrosoft%20SQL%20Server"
xbUnEscape( cString ) → cOriginalString Decodes a URL encoded string into its original form. xbHexEncode( cString, [cSeparator] ) → cHexString Return cString in hex (base16) encoded format. Hex encoding coverts binary data from 8 bits per byte to 4 bits per byte, resulting in a encoded string that is 2 times larger than the original. The optional parameter cSeparator can be specified as a single (non-hex) character to separate each byte in the output string.

Example: xbHexEncode("Zanzibar") // → "5a616e7a69626172"
xbHexEncode("Zanzibar",":") // → "5a:61:6e:7a:69:62:61:72"
xbHexDecode( cHexString, [cSeparator] ) → cOriginalString Decodes a hex encoded string into its original form. If the encoded string contains a special character separating each byte, then it must be provided in the second parameter cSeparator. The default value for cSeparator is ":" (the colon character).

Example: xbHexDecode("5a616e7a69626172") // → "Zanzibar"
xbHexDecode("5a:61:6e:7a:69:62:61:72") // → "Zanzibar"


OpenSSL functions

xbHash( nMethod, cMessage, [nLen] ) → cMessageDigest Compute message digest (hash) of a character string. A hash or message digest is a fixed-size bit string, such that any change to the message will (with very high probability) change the hash value. A message digest may be used in security applications to provide digital signatures and message authentication. It may also be used to index data in hash tables, uniquely identify files and as checksums to detect data corruption. Parameters: nMethod The algorithm to use. The following options defined in Xb2NET.CH are available:

AlgorithmDigest Size (bits)Security Confidence
MD4 128insecure
MD5 128very low
RIPEMD160 160high
SHA1 160high
SHA224 224very high
SHA256 256very high
SHA384 384very high
SHA512 512very high
SHA512_224224very high
SHA512_256256very high
WHIRLPOOL 512very high
MDC2 128very high
SHA3_224 224very high
SHA3_256 256very high
SHA3_384 384very high
SHA3_512 512very high
cMessage A character string representing the message for which the hash will be computed. nLen The number of bytes within cMessage to examine. This parameter is optional, if not supplied it defaults to the length of cMessage. xbHMAC( nMethod, cKey, cMessage, nLen ) → cMessageDigest Compute HMAC (Hash-based Message Authentication Code). The output is a keyed hash that may be used to authenticate the message with a shared secret key. Parameters: nMethod The hashing algorithm to use. See xbHash(). cKey The shared (secret) key. cMessage A character string representing the message to be authenticated. nLen The number of bytes within cMessage to examine. This parameter is optional, if not supplied it defaults to the length of cMessage.

Example: cKey := "secret-key"
cMsg := "The quick brown fox jumps over the lazy dog"
cRet := xbHMAC( SHA1, cKey, cMsg )
? xbHexEncode(cRet) // → b37ccb01ca6a0f8b1908d131d8bee89e63f12fa3
xbRandBytes( [nLen] ) → cString Returns a binary string of length nLen filled with random bytes generated using a cryptographically secure pseudo random generator. xbRC4( cKey, cData, [nLen] ) → cOutput Encrypt/decrypt a character string using RC4 stream cipher. Repeated xbRC4() calls with the same key yield a continuous key stream. Parameters: cKey A character string representing the key used to encrypt/decrypt the input data. The key is generated by calling the function xbRC4SetKey. cData A character string containing the data to be encrypted/decrypted. nLen The number of bytes within cData to use. This parameter is optional, if not supplied it defaults to the length of cData.

Example: cData := "The quick brown fox jumps over the lazy dog"
cKey := xbRC4SetKey("passW0rd-96317sy$")
cEncrypted := xbRC4( cKey, cData )
cDecrypted := xbRC4( cKey, cEncrypted )
? cData == cDecrypted // → .T.
xbRC4SetKey( cPassword ) → cKey Generate a key to be used by xbRC4 function given a password. xbSSLAvailable() → lSuccess Indicates whether the OpenSSL library has been loaded. The function returns .T. when the OpenSSL library is loaded and ready for use. Possible reasons why the OpenSSL library cannot be loaded include:

xbSSLFreeErrorQueue() → NIL Destroy a thread's error queue. This method must be called at end of a thread that uses an xbSSLContext. Failure to do this may result in memory leaks. The xbServer, xbSocketThread and xbHTTPThread classes already perform a proper cleanup at thread termination. It is therefore not necessary to call this method when the xbSSLContext is used in conjunction with one of these classes. xbSSLGetErrorString( [nError] ) → cError Return a human-readable string representing the OpenSSL error code nError. The returned string will have the following format:
error:[error code]:[library name]:[function name]:[reason string]

Where error code is an 8 digit hexadecimal number, library name, function name and reason string are ASCII text.

If nError is not provided, it defaults to the return value of xbSSLGetLastError(). xbSSLGetLastError() → nError Returns the earliest error code from the thread's OpenSSL error queue and removes the entry. This function can be called repeatedly until there are no more error codes to return.

JSON functions

xbJSONEncode( cString ) → cJSONString | NIL Convert an Xbase++ character string to a JSON string format where the followng ASCII characters are escaped: 0x08, 0x09, 0x0A, 0x0C, 0x0D, 0x22, 0x2F, 0x5C
The function returns NIL if the input is invalid.

Example: ? xbJSONEncode('Following chars are escaped: "/\' +chr(0x08)+chr(0x09)+chr(0x0a)+chr(0x0c)+chr(0x0d))
/* output */
Following chars are escaped: \"\/\\\b\t\n\f\r
xbJSONDecode( cJSONString ) → cString | NIL Convert a JSON escaped character string to an Xbase++ character string. The function returns NIL if the input is invalid.

Example: ? xbJSONDecode('Quoth the Raven, \"Nevermore.\"')
/* output */
Quoth the Raven, "Nevermore."
xbJSONParse( cJSON ) → aArray | xbJSON | NIL Convert a JSON string into an Xbase++ array or object of name/value pairs. The datatype of the return value is determined by the first charater of the input string. If the input string begins with a "[" character, then the output is an Xbase++ array. If the input string begins with a "{" character, then the output will be an xbJSON object. The function returns NIL if the input is invalid.

Example: s1 := '[[1, 2, 3], [4, 5, 6], 7, 8, []]'
s2 := '[["aaa", "\"c:\\Program Files\\Intel\\\"", -1.23, true], ["fff", null, false, 456], {"date":"20170821"}]'
s3 := '[{"color":"red", "value":"#f00"}, {"color":"green", "value":"#0f0"}, {"color":"blue", "value":"#00f"}]'
s4 := '{"Product":"1508720880", "Name":"Swiss Army Knife (Red)", "Price":27.72}'

? xbJSONParse(s1)
? xbJSONParse(s2)
? xbJSONParse(s3)
? xbJSONParse(s4)

/* output */
{{1, 2, 3}, {4, 5, 6}, 7, 8, {}}
{{aaa, "c:\Program Files\Intel\", -1.23, Y}, {fff, NIL, N, 456}, xbJSON}
{xbJSON, xbJSON, xbJSON}
xbJSON
xb2JSON( aData ) → cJSONString Convert an Xbase++ array into a corresponding JSON string.
! Elements within the input array may be any Xbase++ datatype with the exception that only objects with an :AsString() method are supported.
! This function will not create JSON objects (name/value pairs). To create a JSON object, use the xbJSON class instead.

Example: a1 := { {1, 2, 3}, {4, 5, 6}, 7, 8, {} }
a2 := { {"alice",-1.23,.T.},{"bob",NIL,.F.,884},'aaa' + Chr(13) + Chr(10) + 'bbb"', stod("20170125"), {|a,b|a+b} }

? xb2JSON(a1)
? xb2JSON(a2)

/* output */
[[1,2,3],[4,5,6],7,8,[]]
[["alice",-1.23,true],["bob",null,false,884],"aaa\r\nbbb\"","20170125","{|a,b|a+b}"]


XML functions

xbXML2Array( cXMLDocument ) → aXMLTree Parse an XML document into a hierarchical array of XML tags. The returned array contains subarrays of 4 elements each which may be accessed with the following define constants available in Xb2NET.CH. An empty array will be returned when the passed string is not a valid XML document.

XTAG_NAME - xml tag element name as string.
XTAG_ATTRIB - element attributes as string.
XTAG_CONTENT - tag contents; a string (tag value) or array containing subnodes (XTAG_TYPE = XTYPE_NODE)
XTAG_TYPE - numeric value indicating type of XTAG_CONTENT. The following values are possible:
    XTYPE_NODE - a subnode
    XTYPE_TEXT - a data value

Example: TEXT INTO cString
<env:Envelope
    xmlns:env="http://schemas.xmlsoap.org/soap/envelope/"
    xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"
    xmlns:xsd="http://www.w3.org/1999/XMLSchema">
    <env:Body>
      <ns:getQuote
        xmlns:ns="urn:xmethods-delayed-quotes"
        env:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
        <symbol xsi:type="xsd:string">IBM</symbol>
      </ns:getQuote>
    </env:Body>
</env:Envelope>
ENDTEXT

aXMLTree := xbXML2Array(cString)

// aXMLTree will contain the following:

{{env:Envelope, xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance" xmlns:xsd="http://www.w3.org/1999/XMLSchema",
{{env:Body, ,
{{ns:getQuote, xmlns:ns="urn:xmethods-delayed-quotes" env:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/",
{{symbol, xsi:type="xsd:string", IBM, 1}}, 0}}, 0}}, 0}}
xbXMLDateTime( [dDate], [cnTime] ) → cXMLDate Return a string representing the date and time with timezone offset in the following format:
yyyy-mm-ddThh:mm:ss.0000000-hh:mm, eg:
2004-12-05T23:33:38.0000000-05:00

Both parameters are optional if not specified the current date/time is used. cnTime can be a numeric as returned by SECONDS(), or a string as returned by TIME(). The timezone is based on the return value of xbTimezoneOffset(). xbXMLGetAttribute( cAttrib | aXMLNode, [cAttribName] ) → cAttribValue | NIL Return attribute value for a given attribute item. The first parameter can be specified as a string representing the entire attribute value, or as a XML Node array. If cAttribName is NIL, then the entire attribute is returned. When aXMLNode contains no attributes, the function returns NIL, otherwise if cAttribName is not found, the function returns a null string.

Example: // using aXMLTree from xbXML2Array example above...
xbXMLGetAttribute( aXMLTree[1], "xsd" )
// returns: http://www.w3.org/1999/XMLSchema
xbXMLGetAttribute('se:arrayType="xsd:int[3]" xsi:type="se:Array"', 'type' )
// returns: se:Array
xbXMLGetNode( aXMLTree, cName ) → aChildNode | NIL Scan aXMLTree for a node with the name cName and return the first node found with that name. Note, the returned node may itself contain other subnodes. The XTAG_TYPE element will specify the type of content (see above). If cNode cannot be found, the function returns NIL.

Example: // using aXMLTree from xbXML2Array example above...
xbXMLGetNode( aXMLTree, "getQuote" )

// returns the following array:
{ns:getQuote, xmlns:ns="urn:xmethods-delayed-quotes" env:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/",
{{symbol, xsi:type="xsd:string", IBM, 1}}, 0}


ZLIB functions

These functions provide an interface to the free and open-source ZLib compression library written by Jean-Loup Gailly and Mark Adler. Technical information, source code and compiled versions of the library can be found on the ZLib homepage: http://www.zlib.net/. xbZCompress( cData, [nLevel], [@nError], [lRaw] ) → cCompressedData | NIL Compress an input string using the 'deflate' compression method. The function will return NIL if an error occurred. Parameters: cData The input string to be compressed. nLevel Optional parameter specifying the compression level to use. Where 0 = no compression, 1 = minimum compression, maximum speed, and 9 = maximum compression, slowest speed. If not specified, the compression level defaults to 6. nError Optional parameter that must be passed by reference. On return, nError will contain one of the following numeric codes:

Z_OK - the input string was successfully compressed.
Z_MEM_ERROR - failed; insufficient memory.
Z_BUF_ERROR - failed; output buffer was too small.
Z_STREAM_ERROR - failed; the nLevel parameter is invalid.
lRaw Optional logical parameter specifying whether to include a 2-byte ZLib header in the output cCompressedData string. When set to .T. (the default), the ZLib signature will NOT be included. xbZCompressFile( cFileIn, cFileOut, [nLevel], [cFileAttr] ) → lSuccess Compress a file using the 'deflate' compression method. The function will return .F. if an error occurs, and .T. if successful. Parameters: cFileIn The name of a file to be compressed. cFileOut The name of an output file where the compressed version of cFileIn will be stored. nLevel Optional parameter specifying the compression level to use. Where 0 = no compression, 1 = minimum compression, maximum speed, and 9 = maximum compression, slowest speed. If not specified, the compression level defaults to 6. cFileAttr An optional character string describing the attributes to be set for the output file. One or more of the following characters can be specified. Example, "HR" indicates a hidden, read-only file:

H - Hidden
S - System
R - Read-only
A - Archive
N - Normal (the default)
xbZCRC32( [nCRC], cBuffer, [nLen] ) → nCRC32 Calculate a running CRC (Cyclic Redundancy Check) value of an input buffer. nCRC is the previous CRC value, which defaults to zero if not provided. cBuffer is a character string buffer that we wish to calculate a CRC for, and nLen is the number of bytes within cBuffer to examine. nLen defaults to the length of cBuffer if not directly specified.

Example: // calculate CRC32 value for a file
cBuffer := Space(32768)
nFile := FOpen("xb2net.dll", FO_READ)
nCRC := 0

while (nBytes := FRead(nFile, @cBuffer, 32768)) > 0
   nCRC := xbZCRC32(nCRC, cBuffer, nBytes)
end
FClose(nFile)
? "CRC32 value = ", nCRC
xbZError( nError ) → cErrorString Returns a character string corresponding to a ZLib error code nError. xbZUnCompress( cCompressedData, nOriginalSize, [@nError], [lRaw] ) → cOriginalData | NIL Inflate an input string that was previously compressed using the 'deflate' compression method. The function will return NIL if an error occurred. Parameters: cCompressedData The compressed string to be inflated. nOriginalSize The (exact) original size of the uncompressed data. nError Optional parameter that must be passed by reference. On return, nError will contain one of the following numeric codes:

Z_OK - the input string was successfully uncompressed.
Z_MEM_ERROR - failed; insufficient memory.
Z_BUF_ERROR - failed; output buffer was too small.
Z_DATA_ERROR - failed, the input buffer cCompressedData was corrupted.
lRaw Optional logical parameter specifying whether the input string cCompressedData contains a 2-byte ZLib header. Setting lRaw to .T. (the default), indicates that the input string does NOT contain a header. xbZUnload() → lSuccess Unload the ZLIB.DLL library. Returns .T. if the DLL file was unloaded successfully. Note that the ZLIB.DLL file is automatically loaded whenever a ZLIB function is executed. xbZVersion() → cVersion Returns the ZLIB.DLL version number as a string.

CLASSES

xbSocket

xbSocket: class methods

:New([nAddrFamily], [nSocketType], [nProtocol], [oSSLContext]) → self, or;
:New(oParent, [nHandle]) → self
Creates a new instance of the xbSocket class and allocates system resources to bind the newly created socket to a specific transport service provider. All parameters are optional.

Connection-oriented sockets such as SOCK_STREAM provide full-duplex connections, and must be in a connected state before any data can be sent or received on it. A connection to another socket is created with a :Connect call. Once connected, data can be transferred using :Send and :Recv calls. When a session has been completed, a :Close or :Destroy must be performed.

The communications protocols used to implement a reliable, connection-oriented socket ensure that data is not lost or duplicated. If data for which the peer protocol has buffer space cannot be successfully transmitted within a reasonable length of time, the connection is considered broken and subsequent calls will fail with the :ErrorCode set to WSAETIMEDOUT.

Connectionless, message-oriented sockets allow sending and receiving of datagrams to and from arbitrary peers. If such a socket is connected to a specific peer (see :Connect), datagrams can be sent/received only to/from this peer. Parameters: nAddrFamily An address family, define constant AF_*. Default is AF_INET. nSocketType One of the following socket types: SOCK_STREAM, SOCK_DGRAM, SOCK_RAW, SOCK_RDM, SOCK_SEQPACKET. Defaults to SOCK_STREAM.

SOCK_STREAM - Provides sequenced, reliable, two-way, connection-based byte streams with an out-of-band data transmission mechanism. Uses TCP for the Internet address family.

SOCK_DGRAM - Supports datagrams, which are connectionless, unreliable buffers of a fixed (typically small) maximum length. Uses UDP for the Internet address family. nProtocol A particular protocol to be used with the socket that is specific to the indicated address family. Default is IPPROTO_IP. Other values can be discovered by using the :GetProtoByName and :GetProtoByNumber methods. oSSLContext This parameter can be set to an instance of xbSSLContext to secure data transmission on this socket. oParent A parent/child relation can be established between sockets by using this parameter. The new instance will inherit :AddrFamily, :SockType, :Protocol, :SSLContext, :Encode, :Decode and :onError properties from oParent. This is done implicitly when a connection is accepted by the :Accept method. nHandle The :Handle of an already open socket. If a handle is not specified, a brand new socket will be created with the same address family, socket type and protocol as the oParent socket. :DefaultSSLContext(oSSLContext) → self Designate an default (client-side) xbSSLContext object, oSSLContext to be used for securing connections with remote servers. A programmer may override the default SSL context at the object level by using the :SetSSLContext() method. :DllLoad() → lSuccess Load and initialize WinSock dll. :DllUnload() → lSuccess Close all sockets and unload WinSock dll. :DllReset() → lSuccess Close all sockets and reinitialize WinSock dll. :ErrorText(nErrorCode, [isSSL]) → cErrorText When isSSL is NIL or .F., return error description of WinSock error code nErrorCode. Otherwise, when isSSL is .T., return error description of OpenSSL error code nErrorCode. :GetAddrInfo(xHostName, [nPort], [nAddrFamily], [nSocketType], [nProtocol], [nFlags]) → cSockAddr Returns the sockaddr structure corresponding to a hostname. Parameters: xHostName A character string representing the hostname, a dotted-decimal IPv4 address, an IPv6 hex address or a numeric IPv4 address in network byte order. nPort This is the numeric port number on the remote computer. Default is 0. nAddrFamily An address family, define constant AF_*. Default is AF_INET. nSocketType One of the following socket types: SOCK_STREAM, SOCK_DGRAM, SOCK_RAW, SOCK_RDM, SOCK_SEQPACKET. Defaults to SOCK_STREAM. nProtocol A particular protocol to be used with the socket that is specific to the indicated address family. Default is IPPROTO_IP. nFlags Can be a combination of flags of the AI_* member to modify the behaviour of the :GetAddrInfo function, eg. AI_PASSIVE, AI_CANONNAME, AI_NUMERICHOST, AI_NUMERICSERV, etc. A complete list of constants can be found in XB2NET.CH. :GetHostByAddr(nAddress, nType) → aHostInfo | NIL Retrieves the host information corresponding to an IPv4 network address. nAddress is a numeric IPv4 address in network byte order, nType is the address family, eg. AF_INET. This method is now deprecated, use :GetNameInfo instead. The method returns an array containing host information, or NIL on failure. The following array constants available in Xb2NET.CH provide access to the individual array elements:

HOSTENT_CNAME - character string representing the name of the host
HOSTENT_ALIAS - a one dimension array holding alternate names of the host. If none exist the array will be empty
HOSTENT_NTYPE - numeric value indicating the address family, eg. AF_INET
HOSTENT_NLEN - length, in bytes required to represent the network byte order addresses in HOSTENT_ADDR
HOSTENT_ADDR - a one dimensional array of numeric IP addresses for the host in network byte order :GetHostByName(cHostName) → aHostInfo | NIL Retrieves IPv4 host information corresponding to a host name. cHostName is a character string representing the name of the host (eg. "sqlexpress.net") for which to retrieve the information. This method is now deprecated, use :GetAddrInfo instead. The method returns an array containing host information, or NIL on failure. The following array constants available in Xb2NET.CH provide access to the individual array elements:

HOSTENT_CNAME - character string representing the name of the host
HOSTENT_ALIAS - a one dimension array holding alternate names of the host. If none exist the array will be empty
HOSTENT_NTYPE - numeric value indicating the address family, eg. AF_INET
HOSTENT_NLEN - length, in bytes required to represent the network byte order addresses in HOSTENT_ADDR
HOSTENT_ADDR - a one dimensional array of numeric IPv4 addresses for the host in network byte order :GetNameInfo(cSockAddr, [nFlag]) → aNameInfo | NIL Retrieves the hostname and port number corresponding with the socket address structure cSockAddr. cSockAddr is a sockaddr structure obtained from :GetAddrInfo. nFlag is an optional flag used to specify the type of hostname output, eg. NI_NOFQDN, NI_NUMERICHOST. The method returns an array containing the name information, or NIL on failure. The following array constants available in Xb2NET.CH provide access to the individual array elements:

NAMEINFO_HOST - character string representing the name of the host
NAMEINFO_SERV - the numeric protocol number :GetProtoByName(cProtocolName) → aProtocolInfo | NIL Retrieves protocol information corresponding to a protocol name. The method returns an array containing protocol information, or NIL on failure. The following array constants available in Xb2NET.CH provide access to the individual array elements:

PROTOENT_CNAME - character string representing the official name of the protocol.
PROTOENT_ALIAS - a one dimension array holding alternate names of the protocol. If none exist the array will be empty.
PROTOENT_NUMBER - a numeric protocol number, in host byte order. :GetProtoByNumber(nProtocolNumber) → aProtocolInfo | NIL Retrieves protocol information corresponding to a protocol number. The method returns an array containing protocol information, or NIL on failure. The following array constants available in Xb2NET.CH provide access to the individual array elements:

PROTOENT_CNAME - character string representing the official name of the protocol.
PROTOENT_ALIAS - a one dimension array holding alternate names of the protocol. If none exist the array will be empty.
PROTOENT_NUMBER - a numeric protocol number, in host byte order. :GetServByName(cServiceName, [cProtocolName]) → aServiceInfo | NIL Retrieves service information corresponding to a service name and protocol. cProtocolName is optional, if not specified, the method returns the first service where the name matches cServiceName. The method returns an array containing service information, or NIL on failure. The following array constants available in Xb2NET.CH provide access to the individual array elements:

SERVENT_CNAME - character string representing the official name of the service.
SERVENT_ALIAS - a one dimension array holding alternate names of the service. If none exist the array will be empty.
SERVENT_NPORT - a numeric port number at which the service can be contacted.
SERVENT_CPROT - the name of the protocol to use when contacting the service. :GetServByPort(nPort, [cProtocolName]) → aServiceInfo | NIL Retrieves service information corresponding to a port and protocol. cProtocolName is optional, if not specified, the method returns the first service where the port number matches nPort. The method returns an array containing service information, or NIL on failure. The following array constants available in Xb2NET.CH provide access to the individual array elements:

SERVENT_CNAME - character string representing the official name of the service.
SERVENT_ALIAS - a one dimension array holding alternate names of the service. If none exist the array will be empty.
SERVENT_NPORT - a numeric port number at which the service can be contacted.
SERVENT_CPROT - the name of the protocol to use when contacting the service. :InetAddr(cAddress) → nAddress Converts an IPv4 dotted-decimal IP address (eg. '127.0.0.1') to a numeric Internet address in network byte order. This method is now deprecated for IPv6. :InetNtoA(xAddress) → cAddress Converts a numeric IPv4 network byte order address into its human readable dotted-decimal string format, eg. '127.0.0.1'. Note that if xAddress is non-numeric, the method echoes back the same value. This method is now deprecated for IPv6.


xbSocket: class properties

:Copyright readonly/character Returns Xb2.NET library copyright information :DisplayErrors exported/logical Enable/disable console display of WinSock error and warning messages. When set to .T., a console dialog box will be displayed whenever a WinSock error occurs. The default setting is .F.. The most recent WinSock error is saved in the :ErrorCode ivar. :DllDescription readonly/character Description of the Windows Sockets implementation. :DllStatus readonly/character Relevant status or configuration information as returned by WinSock. :DllVersion readonly/character The version of the Windows Sockets specification used on the local machine. :ErrorLogFile exported/character The name of the file where errors are logged. Default is XB2ERROR.LOG. This property is used by the xbErrorLog function. :LocalName readonly/character Standard host name of the local machine. :UserAgent readonly/character Returns library name + version number + xbase runtime build number as a string. Example: "Xb2.NET/3.3.13.355" :Version readonly/character Returns Xb2.NET library version number as a string.


xbSocket: object methods

Life Cycle :Open([nAddrFamily], [nSocketType], [nProtocol]) → lSuccess Allocates system resources and causes the socket to be bound to a specific transport service provider. Technically this is equivalent to calling :New() except that a new class instance is not created. For additional information on parameters, see :New(). :Bind([xLocalAddr], [nPort]) → lSuccess Associate a local address with a socket. This method is used to bind to either connection-oriented (stream) or connectionless (datagram) sockets before subsequent calls to the :Connect or :Listen methods. When a socket is instantiated or opened using :Open, it is associated with an address family only. In order for the socket to be able to communicate with a remote process it should be bound to a local address and port. Parameters: xLocalAddr The local address can be specified either as a numeric address in network byte order, or as an IP address in form of a dotted octet string (eg. '127.0.0.1', '::1'). If an application does not care what local address is assigned, specify the constant value INADDR_ANY (the default). This allows the underlying service provider to use any appropriate network address, potentially simplifying application programming in the presence of multihomed hosts (hosts that have more than one network interface and address). nPort This is the numeric port number on the local computer to bind the socket to. The default is zero and this allows the underlying service provider to assign a unique port to the application with a value between 1024 and 5000. Binding to a specific port number other than port 0 is discouraged for client applications, since there is a danger of conflicting with another socket already using that port number. :Connect(xRemoteAddr, nPort) → lSuccess This method is used to establish a connection to a specified destination. If the socket is unbound, unique values are assigned to the local association by the system, and the socket is marked as bound.

Connection-oriented sockets (eg. SOCK_STREAM), must be in a connected state before data can be transmitted using :Send/:Recv. Any attempt to reconnect an active connection will fail with the :ErrorCode WSAEISCONN.

For a connectionless socket (eg. SOCK_DGRAM), the operation performed by :Connect is merely to establish a default destination address that will be used on subsequent :Send and :Recv calls. Any datagrams received from an address other than the destination address specified will be discarded. If the xRemoteAddr parameter is specified as zero, the socket will be "disconnected". The default destination can be changed by simply calling connect again, even if the socket is already connected. Any datagrams queued for receipt are discarded if xRemoteAddr or nPort are different from the previous connect.

Any valid xRemoteAddr and nPort can be specified for connectionless sockets, including a broadcast address. However, to connect to a broadcast address, :Broadcast(.t.) must be set first. Otherwise, :Connect will fail with the :ErrorCode WSAEACCES.

The behavior of :Connect is determined by the setting of :TryAlternateAF. When :Connect fails, and :TryAlternateAF is .T., it will automatically attempt to connect to xRemoteAddr using the alternate address family (AF_INET / AF_INET6). Parameters: xRemoteAddr The remote address can be specified as a host name (eg. 'www.example.com'), an IPv4 numeric address in network byte order, an IPv4 address in form of a dotted octet string (eg. '127.0.0.1'), or as an IPv6 address in the form of a 8 groups of hextets separated by colons (eg. '2001:db8::ff00:42:8329'). Note that IPv6 addresses may be abbreviated. For example, the loopback address, '0000:0000:0000:0000:0000:0000:0000:0001', may be shortened to '::1'. nPort This is the numeric port number on the remote computer to connect to. :SSLConnect([oContext]) → lSuccess Initiate a TLS handshake with a connected peer. The socket must be of type SOCK_STREAM and it must already be in a connected state when this method is called.

oContext is optional and may be set to either an instance of the class xbSSLContext or xbSocket. An xbSSLContext is only needed in cases where specific SSL/TLS properties need to be set, such as a client certificate, CA lists, cypher suites, etc...

If another secure connection already exists to the same peer, the time to perform a full handshake can be substantially reduced. When the input parameter is an xbSocket object, the system will attempt to reuse the existing SSL/TLS session and avoid a full TLS handshake.

The method returns .T. when a secure connection is successfully established. Otherwise it returns .F. :Listen([nBacklog]) → lSuccess Place a socket in a state where it is listening for incoming connections. This method is typically used by servers that can have more than one connection request at a time. If a connection request arrives and the queue is full, the client will receive an error with an indication of WSAECONNREFUSED.

nBacklog is an optional parameter that specifies the maximum length of the queue of pending connections. If this value is SOMAXCONN (the default), then the underlying service provider responsible for this socket will set the backlog to a maximum "reasonable" value. There is no standard provision to find out the actual backlog value.

Subsequent calls to :Listen will update the current backlog for the listening socket. If there are more pending connections than the new backlog value, the excess pending connections will be reset and dropped. :Accept([oSocketClass], [lSSLHandshake]) → oClientSocket | NIL This method is used by a server process for accepting incoming connections. The method extracts the first connection in the queue of pending connections and then creates a new socket object that is bound to the extracted connection. The newly created socket inherits most of its properties from the parent (this socket) and is the socket that will handle the actual communication with the remote process.

The optional parameter oSocketClass can be used to provide a reference to the class function from which the new socket object will be instantiated. If oSocketClass is NIL, then the client socket will be created based on one of the following conditions: (1) if the parent (this socket) is derived from either xbServer or xbHTTPServer, the client socket will be instantiated from the class object referenced by the server's :WorkerClass property (usually xbSocketThread or xbHTTPThread), (2) otherwise the new socket will be instantiated from xbSocket.

If the socket is defined with an SSL context, the SSL/TLS handshake is automatically initiated after a peer connection is accepted. This can be disabled by setting the optional parameter lSSLHandshake to .F. In this case, the SSL/TLS handshake can be initiated separately by calling the :SSLAccept() method.

If the socket is marked as blocking (see :SetBlockingMode) and there are no pending connections on the queue, then the :Accept method will block the calling routine until a connection is present. If the socket is marked nonblocking and no pending connections are present on the queue, :Accept returns NIL. After the successful completion of :Accept, the method returns a new socket object. The original socket remains open and listens for new connection requests. :SSLAccept([oSSLContext]) → lSuccess Wait for a TLS/SSL client to initiate a TLS/SSL handshake. The socket must be of type SOCK_STREAM and it must already be in a connected state when this method is called.

oSSLContext is an optional parameter than can be set to an instance of the xbSSLContext class. This is only necessary if specific SSL/TLS properties need to be set, such as a server certificate, CA lists, cypher suites, etc.

The method will return .T. if an SSL/TLS connection has been successfully established with the peer. Otherwise, the method returns .F. :Recv([nBytes], [nFlag], [cBuffer], [nDelayTime]) → cReceived | NIL Read incoming data. Calling :Recv on a connection-oriented socket (eg. SOCK_STREAM), will return as much information as is currently available; up to nBytes. If the socket has been configured for in-line reception of out-of-band data (see :OOBInLine) and out-of-band data is available; only out-of-band data will be returned. The application can use :CatMark to determine whether any more out-of-band data remains to be read.

For message-oriented or connectionless sockets (eg. SOCK_DGRAM), data is extracted from the first enqueued datagram (message); up to nBytes. If the datagram or message is larger than nBytes, the first part of the datagram is returned, and :ErrorCode will be set to WSAEMSGSIZE. For unreliable protocols (eg. UDP) the excess data is lost; for reliable protocols, the data is retained by the service provider until it is successfully read by calling :Recv with a large enough buffer. If the socket is not connected, the network address of the peer that sent the data will be copied into the :RemoteAddr and :RemotePort ivar.

If there is no incoming data available and the socket is in blocking mode (see :SetBlockingMode), then :Recv will block the calling routine and wait for data to arrive. If the socket is nonblocking and the input queue is empty, :Recv returns a zero length string and :ErrorCode is set to WSAEWOULDBLOCK. After successfully reading data from the input queue :Recv returns a string containing the data read. If an error occurs, other than the ones specified above, the method returns NIL. The number of bytes read is saved in the :BytesReceived ivar and a cumulative total in :RecvCount. Parameters: nBytes The number of bytes to read from the input queue. If not specified, nBytes will default to 1460 bytes or if supplied; the size of cBuffer. nFlag Specifies the way data will be read from the input queue. The following options defined in XB2NET.CH are available:
MSG_NORMAL - Read incoming data and remove it from the input queue (this is the default).
MSG_PEEK - Peek at the incoming data but do not remove it from the input queue.
MSG_OOB - Process out-of-band data. cBuffer An optional character string buffer that will be used to receive data into. If supplied, it must be passed by reference and its size must be greater than or equal to nBytes. If nBytes is NIL, then the method will continue reading until cBuffer is full. If :Recv is called continuously (eg. in a loop), then it's good programming practice to receive into a static buffer since it results in more efficient memory usage. nDelayTime Specifies an optional delay period in milliseconds to hold-off reading from the input queue until nBytes is available to be read. This can be useful when the peer is transmitting large amounts of data over a slow network since it will result in more efficient buffer and memory usage on the host machine.

The delay will persist as long as data is being received and the number of bytes in the receive buffer is less than nBytes. The method checks the receive buffer every 10 ms, if no additional data is received within that time, it will read the data received so far and return to calling routine even if the delay time has not yet expired. This parameter only applies to connection-oriented sockets. :RecvFile( xFile, [nBytesToRecv], [nBytesPerRecv] ) → nBytesReceived | SOCKET_ERROR Read incoming data and save it into a file. For additional information on how data is read from the input queue, see :Recv above. Parameters: xFile The file where received data is saved can be specified as either a numeric handle as returned by FOpen() or FCreate(), or as a character string denoting the file name and path. NOTE: If a file handle is provided, then received data will be saved starting at the current file pointer offset. On return, the file will be left open and the file pointer will be positioned on the last byte written. If a file name is specified instead of a numeric handle, then the file will be closed. nBytesToRecv Number of bytes to read. The method completes when it has read the specified number of bytes, or when an error occurs, whichever occurs first. Set nBytesToRecv to zero or NIL in order to continue reading into file until socket is disconnected. nBytesPerRecv Data is read from the input queue in discrete blocks. This parameter specifies the number of bytes of data read per block. Set nBytesPerRecv to zero or NIL to select the default read size. This parameter is useful for message protocols that have limitations on the size of individual read requests. :RecvLine([cEOLMarker], [nMaxBytes]) → cReceived | NIL Read incoming data on a connection-oriented socket (eg. SOCK_STREAM) until cEOLMarker is reached or if specified; nMaxBytes have been read. If cEOLMarker is not supplied it defaults to CR+LF (Chr(13) + Chr(10)). See :Recv for additional information. :Send(cBuffer, [nFlag], [xToAddr], [nToPort], [nBytesToSend]) → nBytesSent | SOCKET_ERROR Send data to a specific destination or a connected peer. If the socket is unbound, unique values are assigned to the local association by the system, and the socket is marked as bound. The method returns an integer numeric value indicating the number of bytes transmitted, or SOCKET_ERROR if an error occurred. NOTE: The successful completion of :Send does not necessarily indicate that the data was successfully delivered to the remote peer.

For message-oriented sockets, care must be taken not to exceed the maximum packet size of the underlying provider, (see :MaxMessageSize). If the data is too long to pass atomically through the underlying protocol, :ErrorCode will be set to WSAEMSGSIZE, and no data is transmitted.

If no buffer space is available within the transport system to hold the data to be transmitted, :Send will block unless the socket has been placed in a nonblocking mode. On nonblocking, stream oriented sockets, the number of bytes written can be between 1 and the requested length, depending on buffer availability on both the client and server systems. Parameters: cBuffer This is the buffer containing the data to be transmitted. nFlag Specifies the way in which the call is made. The following options defined in Xb2NET.CH are available:
MSG_NORMAL - Read incoming data and remove it from the input queue (this is the default).
MSG_DONTROUTE - Specifies that the data should not be subject to routing.
MSG_OOB - Send out-of-band data (SOCK_STREAM only). xToAddr This parameter is only valid when used with connectionless, message-oriented sockets. It is ignored if :SockType is SOCK_STREAM, otherwise xToAddr can be any valid address in the socket's address family, including a broadcast address. However, to send to a broadcast address, :Broadcast(.t.) must be set first. Otherwise, :Send will fail with the :ErrorCode WSAEACCES. For TCP/IP, an application can send to any multicast address without becoming a group member. If a message-oriented socket has been previously connected to a specific address (using :Connect), specifying xToAddr will override the default destination address for this datagram only. The address can be specified either as a numeric address in network byte order, or as an IP address in form of a dotted octet string (eg. '127.0.0.1'). Default is INADDR_BROADCAST. nToPort This parameter is only valid when used with connectionless, message-oriented sockets. It is ignored if :SockType is SOCK_STREAM, otherwise it specifies the numeric port number on the remote computer to send to. Default is zero. nBytesToSend The number of bytes to send. If the parameter is NIL or not provided, the default is to send the entire contents of cBuffer. :SendFile(xFile, [nBytesToSend], [nBytesPerSend]) → nBytesSent | SOCKET_ERROR Transmit file data over a connected socket. The method returns an integer numeric value indicating the number of bytes transmitted, or SOCKET_ERROR if an error occurred. NOTE: The successful completion of a :SendFile does not necessarily indicate that the data was successfully delivered to the remote peer. Parameters: xFile The file to be transmitted can be specified as either a numeric handle as returned by FOpen() or FCreate(), or as a character string denoting the file name and path. NOTE: If a file handle is specified, then data will be transmitted beginning at the current file pointer offset. To transmit the entire file make sure that the file pointer is set to the beginning of the file. If a numeric file handle is provided, then it is the responsibility of the calling routine to close the file once the method returns. nBytesToSend Number of file bytes to transmit. The method completes when it has sent the specified number of bytes, or when an error occurs, whichever occurs first. Set nBytesToSend to zero or NIL in order to transmit the entire file. nBytesPerSend The file contents are transmitted in discrete blocks of data. This parameter specifies the number of bytes of data sent per block. Set nBytesPerSend to zero or NIL to select the default send size. This parameter is useful for message protocols that have limitations on the size of individual send requests. :Shutdown([nHow], [lShutdownClients]) → lSuccess This method is used on all types of sockets to disable reception and/or transmission of data. Note that :Shutdown does not close the socket. A socket can only be closed by executing the :Close or :Destroy methods. The method returns .T. when the shut down operation is successful, otherwise .F. is returned.

If the nHow parameter is set to SD_SEND, subsequent calls to :Send will be disallowed. If it is set to SD_RECEIVE (the default), subsequent calls to :Recv are disallowed. If it is set to SD_BOTH then both sends and receives are disabled.

If the socket is in a listening state and there are connected clients, the client sockets can be shut down by specifying .T. for lShutdownClients default is .F. :SSLShutdown() → self Send an SSL/TLS shutdown request to the remote peer and wait for an acknowledgement that the peer has shut down. If there is no SSL connection open on the socket, then the method will return immediately. :Close([lCloseClients]) → lSuccess Closes socket and releases allocated system resources. Any pending blocking, asynchronous calls issued by any thread in this process are canceled without posting any notification messages. If the socket is in a listening state and there are connected clients, the client sockets can also be closed by specifying .T. for lCloseClients, default is .F. The semantics of :Close are affected by the :LingerTimeout option, see :LingerTimeout for additional information. A socket that has been closed can later be reopened by using the :Open method. :Destroy([lDestroyClients]) → lSuccess This method will first execute a :Close and if successful, the class instance will be dereferenced from the class object list. If the socket is in a listening state and there are connected clients, the client socket objects can also be destroyed by specifying .T. for lDestroyClients, default is .F. Configuration :Broadcast([lSet]) → lSet Enable/disable transmission of broadcast messages on the socket. When lSet is not specified, the method will return the current setting. Default is .F. :Debug([lSet]) → lSet Enable/disable recording of debugging information. When lSet is not specified, the method will return the current setting. The mechanism for generating the debug information and the form it takes are dependant on the WinSock service provider and are beyond the scope of this manual. Default is .F. :KeepAlive([lSet]) → lSet Enable/disable use of "keep-alive" packets on TCP connections. When lSet is not specified, the method will return the current setting. Default is .F. :LingerTimeout([nSec]) → nSetting This method controls the action taken when unsent data is queued on a socket and a :Close or :Destroy is performed. The following types of behavior can be obtained:

nSec is specified as a negative value: Graceful shutdown, immediate return - allowing the shutdown sequence to complete in the background. Although this is the default behavior, the application has no way of knowing when (or whether) the graceful shutdown sequence actually completes.

nSec is specified as zero: Abortive shutdown sequence, immediate return from :Close. The socket's virtual circuit is reset immediately and any data queued on the socket is lost. Any :Recv call on the remote side of the circuit will fail with WSAECONNRESET.

nSec is specified as a positive value: Graceful shutdown, delaying return until either shutdown sequence completes or the specified nSec time interval elapses. If the time interval expires before the graceful shutdown sequence completes, an abortive shutdown sequence occurs, and :Close returns. A non-zero timeout interval should only be set on a blocking socket.

When nSec is not specified, the method will return the current setting. :OOBInLine([lSet]) → lSet Enable/disable the reception of out-of-band data in the normal data stream. When lSet is not specified, the method will return the current setting. Default is .F. :RecvBufferSize([nSize]) → nBytes Get/set buffer size for receives. When nSize is not specified, the method will return the current size of the receive buffer in bytes. :RecvTimeout([nMilliSec]) → nTimeout Get/set maximum number of millisecs to wait when receiving data from a remote connection (may not work with all stack implementations). This option can be set on any type of socket in any state. The default value is zero, which refers to an infinite timeout. Any other setting is the timeout, in milliseconds. It is valid to set the timeout to any value, but values less than 500 milliseconds (half a second) are interpreted to be 500 milliseconds. When nMilliSec is not specified, the method will return the current setting. :ReuseAddr([lSet]) → lSet By default, a socket cannot be bound to a local address that is already in use. Sometimes, however, it can be necessary to reuse an address in this way. Because every connection is uniquely identified by the combination of local and remote addresses, there is no problem with having two sockets bound to the same local address as long as the remote addresses are different. In order to allow the socket to be bound to an address that is already in use, the application should call this method by specifying lSet as .T. before issuing a :Bind call. Setting or resetting the option after the :Bind has no effect on this or any other socket. When lSet is not specified, the method will return the current setting. Default is .F. :Route([lSet]) → lSet Enable/disable routing; when disabled packets are sent directly to interface. When lSet is not specified, the method will return the current setting. Default is .T. (enable routing). :SendBufferSize([nSize]) → nBytes Get/set buffer size for sends. When nSize is not specified, the method will return the current size of the send buffer in bytes. :SendTimeout([nMilliSec]) → nTimeout Get/set maximum number of millisecs to wait when sending data to a remote connection (may not work with all stack implementations). This option can be set on any type of socket in any state. The default value is zero, which refers to an infinite timeout. Any other setting is the timeout, in milliseconds. It is valid to set the timeout to any value, but values less than 500 milliseconds (half a second) are interpreted to be 500 milliseconds. When nMilliSec is not specified, the method will return the current setting. :SetBlockingMode([lSet]) → lSet Enable/disable blocking mode on the socket. When enabled (which is the default), the process executing :Accept or sending/receiving data will wait for the operation to complete. If not specified lSet defaults to .T. :SetCallBack([xCallBack]) → self Register an object or codeblock to receive callback events. If a callback has already been registered, it can be cancelled by setting xCallBack to NIL.

When xCallBack is provided as an object, the object must be inherited from the Xbase++ XbpPartHandler class. In this case, the xbSocket class will place events of type xbeP_xbSocket into the Xbase++ event queue. These events can be read (asynchronously) from the event queue by using the standard Xbase++ function AppEvent(). For an example showing how to define asynchronous callbacks, please see: xbFTPClient:SetCallBack.

When xCallBack is provided as a codeblock, the user codeblock will be executed (synchronously) whenever an event occurs within the xbSocket instance.

Two message parameters are provided to the AppEvent() function / user codeblock. The first parameter will be an integer numeric status code defined in Xb2NET.CH with the prefix SOCK_ST_*, the second parameter will contain a reference to the socket object.

Example (synchronous callback): oSock:SetCallBack({|a,b|DisplayStatus(a,b)}) // codeblock executes synchronously

PROCEDURE DisplayStatus(nStatus, x)
  Static oXbp
  Local oWindow

  // create status CRT window if it does not exist
  if oXbp == nil
    oXbp := XbpCrt():new(,,{372,165},15,33,"STATUS")
    oXbp:autoFocus := .F.
    oXbp:create()
  endif

  // display status info in separate CRT window
  oWindow := SetAppWindow(oXbp)
  if valtype(x) == "O" .and. x:isDerivedFrom("xbSocket")
    ? nStatus, x:SendCount, x:RecvCount
  else
    ? nStatus, x
  endif
  DispOutAt(0,0,"StatusCode SendCount RecvCount", "gr+,w")
  SetAppWindow(oWindow)
  Return
:SetSSLContext([oSSLContext]) → self Attach an xbSSLContext object, oSSLContext to this socket in order to secure communications. The socket must be of type SOCK_STREAM and it must not be connected or in a listening state when the xbSSLContext object is attached. If oSSLContext is NIL or no parameter is supplied, then the present SSL/TLS connection (if there is one) will be shut down and its corresponding xbSSLContext will be detached from this socket. :TCPNoDelay([lSet]) → lSet Enable/disable use of Nagle algorithm for sends. The Nagle algorithm is disabled when lSet is .T. (and vice versa). The process involves buffering :Send data when there is unacknowledged data already "in flight" or buffering :Send data until a full-size packet can be sent. For most application protocols the Nagle Algorithm can deliver significant performance enhancements. However, in some cases this algorithm can impede performance, and :TCPNoDelay can be used to turn it off. These are applications where many small messages are sent, and the time delays between the messages are maintained. When lSet is NIL, the method returns the current setting. Status :ErrorMessage() → cErrorText Return error description of most recent WinSock error. :CatMark() → lNoOOBDataWaiting Check if out-of-band data is waiting to be read. This applies only to a stream oriented socket (eg. SOCK_STREAM) that has been configured for in-line reception of out-of-band data; see :OOBInLine. If no out-of-band data is waiting to be read, the operation returns .T. Otherwise, it returns .F., and the next :Recv or :RecvLine performed on the socket will retrieve some or all of the data preceding the "mark". The application should use :CatMark to determine whether any data remains. :GetCurrentCipher( [lAsString] ) → aCipherInfo | cCipherInfo If an SSL connection has been established, this method will return information about the cipher being used on the connection. The optional logical parameter lAsString will determine how the information will be returned.

(a) When lAsString is NIL or .F. a one dimensional array with 4 elements will be returned. The following array elements are defined in Xb2NET.CH:

CIPHER_NAME - cipher name as a string
CIPHER_VER - string indicating the SSL/TLS protocol version that first defined the cipher
CIPHER_BITS - number of secret bits used for cipher
CIPHER_ABITS - number of bits processed by the chosen algorithm

? The number of bits processed can be different from the secret bits. An export cipher like EXP-RC4-MD5 has only 40 secret bits. The algorithm does use the full 128 bits (which would be returned in CIPHER_ABITS), of which however 88 bits are fixed. The search space is hence only 40 bits.

Sample returned array: {"ECDHE-RSA-AES256-SHA", "TLSv1/SSLv3", 256, 256}

(b) When lAsString is .T., a text string is returned providing cipher information separated by one or more blanks in the following sequence:

1- Cipher Name
2- SSL/TLS Protocol version. Note that TLSv1.0 ciphers are flagged with SSLv3 since no new ciphers were added by TLSv1.1.
3- Kx=[key exchange] - Key exchange method. RSA (for export ciphers as RSA(512) or RSA(1024)), DH (for export ciphers as DH(512) or DH(1024)), DH/RSA, DH/DSS, Fortezza.
4- Au=[authentication] - Authentication method. RSA, DSS, DH, None. None is the representation of anonymous ciphers.
5- Enc=[symmetric encryption method] - Encryption method with number of secret bits. DES(40), DES(56), 3DES(168), RC4(40), RC4(56), RC4(64), RC4(128), RC2(40), RC2(56), RC2(128), IDEA(128), Fortezza, None.
6- Mac=[message authentication code] - Message digest: MD5, SHA1.
7- export flag. If the cipher is flagged exportable with respect to old US crypto regulations, the word "export" is printed.

Sample returned string: "ECDHE-RSA-AES256-SHA SSLv3 Kx=ECDH Au=RSA Enc=AES(256) Mac=SHA1" :GetReadCount() → nBytesAvailable Use to determine the amount of data pending in the network's input buffer that can be read from the socket. If the socket is stream oriented (eg. SOCK_STREAM), this method returns the amount of data that can be read in a single call to the :Recv method; this might not be the same as the total amount of data queued on the socket. If the socket message oriented (eg. SOCK_DGRAM), this method returns the size of the first datagram (message) queued on the socket. :GetSSLState() → nSSLState Returns the current state in the SSL connection establishment process. The return value will be an integer numeric status code defined in Xb2NET.CH with the prefix SSL_ST_* and SSL_CB_* :GetSSLStateString() → cSSLState Returns a string indicating the current state of the SSL object. Querying the state information is not very informative either before or after a connection has been established. It however can be of significant interest during the handshake. :isListening() → lListening Check if socket is in listening mode. :isConnected() → lConnected Check if a connected socket is still alive. :isSecure() → lSecureConnecton Check if there is a secure SSL/TLS connection open. :MaxMessageSize() → nBytes Maximum size of a message for message-oriented socket types (eg., SOCK_DGRAM). Has no meaning for stream oriented sockets. :RemoteName() → cHostName | NIL Return host name of remote machine or NIL if the remote host name cannot be resolved. :UpTime() → {nDays, nHrs, nMin, nSec} Returns a one dimensional array specifying amount of time socket has been open. The following array constants available in Xb2NET.CH provide access to the individual array elements:

UPTIME_DAY - number of days
UPTIME_HRS - number of hours
UPTIME_MIN - number of minutes
UPTIME_SEC - number of seconds Child/Parent Relation :AddClient(oSocket) → self Create a parent/child relation between this socket (the parent) and oSocket (the child). A list of all client sockets is available in the :ClientList ivar. :DelClient(oSocket) → self Remove parent/child relation between this socket and oSocket. A list of all client sockets is available in the :ClientList ivar. :SetParent([oParent]) → self Create or remove a parent/child relation between this socket (the child) and oParent (the parent). If oParent is not specified, the link is removed, otherwise a link is created. A reference to the parent socket is stored in the :Parent ivar.


xbSocket: object properties

:Handle readonly/numeric Numeric socket descriptor as used by WinSock. :SSLHandle readonly/numeric Numeric descriptor of SSL object as used by OpenSSL. :TryAlternateAF exported/logical When set to .T. and a :Connect or :Bind fails, the system will automatically retry the operation using an alternate address family. For example, if a client socket is configured to use AF_INET6 however a connection to a host cannot be established using IPv6, then the system will seamlessly switch to IPv4 and attempt the connection again. This property is disabled (.F.) by default. :AddrFamily readonly/numeric The socket's address family. #define constants: AF_* :SockType readonly/numeric The socket type. #define constants: SOCK_STREAM, SOCK_DGRAM, SOCK_RAW, SOCK_RDM, SOCK_SEQPACKET :Protocol readonly/numeric The protocol used. #define constants: IPPROTO_* :LocalAddr readonly/character The dotted-decimal (IPv4) or hexadecimal (IPv6) IP address of the local machine that the socket is bound to. :LocalPort readonly/numeric The numeric port number on the local machine that the socket is bound to. :RemoteAddr readonly/character The dotted-decimal (IPv4) or hexadecimal (IPv6) IP address of the remote machine that the socket is connected to. :RemotePort readonly/numeric The numeric port number on the remote machine that the socket is connected to. :BytesReceived readonly/numeric Number of bytes received by last :Recv or :RecvLine call. :BytesSent readonly/numeric Number of bytes transmitted by last :Send call. :RecvCount readonly/numeric A cumulative total of number of bytes received on this socket since it was opened. :SendCount readonly/numeric A cumulative total of number of bytes sent on this socket since it was opened. :ErrorCode exported/numeric Most recent result code returned by WinSock. :MinRecvRate exported/numeric Specifies the minimum allowable data transmission rate while receiving data from a connected peer. The size specified is in kilobytes per second. It can be used to prevent denial of service (DoS) attacks caused by clients that create many connections and send data to the server very slowly. :MinSendRate exported/numeric Specifies the minimum allowable data transmission rate while sending data to a connected peer. The size specified is in kilobytes per second. It can be used to prevent denial of service (DoS) attacks caused by clients that create many connections and read responses from the server very slowly. :onError exported/codeblock Provides the ability to optionally specify a codeblock that will be evaluated when a WinSock error occurs. When evaluated three parameters are passed to the codeblock (1) a reference to socket object responsible for the error, (2) the OpenSSL or WinSock error code number, and (3) a logical indicating if the error originated from the OpenSSL library (.T.) or from WinSock (.F.). Example:

oSocket:onError := {|oOwner,nErrCode,isSSL| xbErrorLog(oOwner,nErrCode,isSSL)} :onRecv exported/codeblock | NIL An optional codeblock that is evaluated immediately after data is received on the socket. The codeblock receives two parameters:

(1) A reference to the xbSocket object.
(2) The received content or NIL in case there is an error or the connection is terminated. :isEncoded exported/logical Provides the ability to automatically encode and decode data transmitted on the socket. When set to .T., all inbound data will be decoded (see :Decode) and all outbound data will be encoded (see :Encode). This is quite a powerful feature since it means that data can be transparently "massaged" before it is passed on. For example, using the following codeblocks, any datatype can be sent and received between Xbase++ applications. Send an array, receive an array; send a codeblock, receive a codeblock... you can imagine the possibilities.

oSocket:isEncoded := .T.
oSocket:Encode := {|xVal| Var2Bin(xVal)}
oSocket:Decode := {|cBuffer,nBytes| Bin2Var(Left(cBuffer,nBytes))}
:Encode exported/codeblock Optional codeblock that is automatically evaluated to encode outbound data when :isEncoded is .T. If no user codeblock is supplied but :isEncoded is .T. a default built-in encryption algorithm will be used. When evaluated two parameters are passed to the codeblock (1) a reference to the value being transmitted, (which may be any data type), and (2) if the value to be transmitted is a string, this parameter will contain the length of the string, otherwise it will be -1. See :isEncoded for more information. :Decode exported/codeblock Optional codeblock that is automatically evaluated to decode inbound data when :isEncoded is .T. If no user codeblock is supplied but :isEncoded is .T. a default built-in decryption algorithm will be used. When evaluated two parameters are passed to the codeblock (1) a text buffer of the data received, and (2) the number of bytes received. See :isEncoded for more information. :Parent readonly/object Reference to parent socket or NIL if this socket has no parent. :ClientList readonly/array A one dimensional array listing all active client sockets either created through this socket's :Accept method or :AddClient method. :DateStarted readonly/date Date socket opened. :TimeStarted readonly/numeric Time socket opened (seconds after midnight). :ThreadID readonly/numeric Xbase++ thread ID number where socket was created. :SSLContext readonly/object Reference to the xbSSLContext instance, or NIL if no SSL context has been assigned. :Cargo exported/any data type Used to attach additional information to the object as required by the programmer.


xbWebSocket     inherited from xbSocket

This class implements the WebSocket protocol as defined in RFC 6455. Instances of this class may be used in both client and server implementations.
! This class requires the OpenSSL library and an Xb2.NET SSL license!

xbWebSocket: class methods

:New([oServerSocket]) → self Creates a new instance of the xbWebSocket class. This class is inherited from xbSocket, which means that instances of this class have access to all methods and properties of its superclass. An instance of xbWebSocket may be used in either client-side or server-side roles. A server-side role is initiated by supplying the optional parameter oServerSocket in the init method. Whereas a client-side connection is established by calling the :Connect method. Parameters: oServerSocket This parameter is optional. It is used in a server-side implementation to accept a connection from an HTTP client requesting an upgrade to WebSocket. The parameter represents the xbSocket instance that has been accepted (and upgraded) by the HTTP server.

xbWebSocket: object methods

:Close( [nStatusCode], [cReason] ) → self Sends closing handshake to peer and then closes the socket connection. After the :close method is called, the underlying socket is no longer valid and the connection with the peer is terminated. Parameters: nStatusCode Optional integer numeric value in the range 1000-4999 indicating the reason for closing the connection. Standard WebSocket status codes are defined in Xb2NET.CH with prefix WS_STATUS_*. Status codes in the range 4000-4999 are reserved for private use. cReason Optional character string indicating the reason for closing the connection. :Connect( xURI, [aHTTPHeaders] ) → lSuccess Connect to a remote HTTP server and send a WebSocket upgrade request. If the connection and upgrade request is successful, the method returns .T. and the socket can then be used to exchange data between the remote peers. If an error occurs, the method returns .F. The cause of the error can be determined by inspecting values saved in the :ErrorCode and :ErrorMessage instance variables. Parameters: xURI The name or IP address of the remote HTTP server, including port, target resource path and query string (if any). If not specified the port defaults to 80 when using HTTP or 443 when using HTTPS. xURI may be specified as either a URL-encoded character string or an xbURI object, eg:

cURL := "ws://xb2.net/echo"
oSock := xbWebSocket():new()
if !oSock:Connect(cURL)
    MsgBox("Unable to connect to: " + cURL + chr(10) +;
      "Error:" + Str(oSock:ErrorCode) + " - " + oSock:ErrorMessage)
    Return
endif
oSock:send("hello")
MsgBox("recv:" + var2char(oSock:Recv()))

aHTTPHeaders Optional array of name/value pairs representing HTTP headers to be included in the HTTP upgrade request. If provided, the array must be in the following format:
{{cHeader1, cValue1}, {cHeader2, cValue2},... } :Ping( [cData], [nWaitForPong], [@cError] ) → lSuccess Send Ping control frame to remote peer. A Ping frame may serve either as a keepalive or as a means to verify that an endpoint is still responsive. The method returns .T. if the Ping frame was transmitted successfully and .F. otherwise. Upon receipt of a Ping frame, the endpoint must respond with a Pong frame. Parameters: cData Optional character string message to be sent in Ping frame. If not provided, cData defaults to a zero length string. Note that an endpoint must respond with the same message that was transmitted in the Ping frame. nWaitForPong This is an optional parameter which determines the maximum amount of time (in milliseconds) to wait for the peer to respond with a Pong frame. If the socket is in blocking mode (see :SetBlockingMode), then the actual minimum timeout value can not be lower than the socket's :RecvTimeout value. If the peer does not respond with a Pong frame within the allotted time, the method returns .F. and an appropriate error message is returned in the cError output parameter. When this parameter is NIL, the method does not wait for a Pong and returns immediately after sending the Ping frame. cError This is an optional output parameter that can be used to determine the reason for failure when a timeout value is supplied in the nWaitForPong parameter. This parameter must be passed by reference. If a Pong frame is not received within the timeout value, then the reason for failure will be returned as a character string in this parameter. :Pong( [cData] ) → lSuccess Send Pong frame to the endpoint. A Pong frame is sent in response to a Ping frame. If the Ping frame being replied to contains message data, then the same message data must be supplied in the cData parameter and echoed back in the Pong frame. The method returns .T. if the Pong was sent successfully and .F. otherwise.

Note: If :AutoPong is enabled (it is enabled by default), then the :Recv method will automatically respond with a Pong frame whenever a Ping frame is received. Therefore, under normal circumstances it should not be necessary to use this method. :Recv() → cData | NIL Receive a single data frame from connected peer. If a full data frame is available to be read, the method returns the message payload as a character string. Each call to :Recv will read only one data frame even though there may be multiple data frames queued in the receive buffer waiting to be read. If data was received, the :OpCode property will indicate the type of data frame received. If there is no incoming data available, the method returns a zero length string and :OpCode will be NIL.

The method returns NIL if the socket is disconnected or a network error occurs while reading data. The method will also return NIL when the incoming message payload is too large (see :MaxPayloadSize). When the incoming message exceeds :MaxPayloadSize, the WebSocket will be closed with a status code of 1009.

If a WS_OP_CLOSE frame is received, the :StatusCode property will indicate the reason for the close and :Recv will return a payload message if one was send by the peer in the close frame.

If :AutoPong is enabled (it is enabled by default), then :Recv will automatically respond with a Pong frame whenever a WS_OP_PING frame is received. If the peer included a payload message in the WS_OP_PING frame, then cData will contain this message. :Reset() → self Reinitialize object. :Send( cPayload, [nOpCode], [isFinalFrame] ) → nBytesSent | SOCKET_ERROR Send a data frame with a payload message to connected peer. The method returns an integer numeric value indicating the number of bytes transmitted, or SOCKET_ERROR if an error occurred. NOTE: The successful completion of :Send does not necessarily indicate that the data was successfully delivered to the remote peer. Parameters: cPayload A character string representing the message to be delivered to the remote peer. If not specified, the payload defaults to a zero length string. nOpCode Optional integer numeric value indicating the data frame type. The following codes defined in Xb2NET.CH are possible:

OpCodeDescription
WS_OP_CONT A data frame that is a continuation of the previous data frame where the payload type is the same as the previous frame.
WS_OP_TEXT (the default) A data frame containing UTF-8 encoded text.
WS_OP_BIN A data frame containing binary data.
WS_OP_CLOSE A control frame indicating the connection will be closed. Note: The :Close method will send the WS_OP_CLOSE frame and then close the underlying socket connection.
WS_OP_PING A Ping control frame. See the :Ping method for more information.
WS_OP_PONG A Pong control frame. See the :Pong method for more information.
isFinalFrame Optional logical parameter that is used with fragmented messages to indicate the last data frame of the message. If a value is not supplied,this parameter defaults to .T. indicating that the data frame is the final frame.

To split a large message into smaller chunks, set isFinalFrame to .F. and set nOpCode to either WS_OP_TEXT or WS_OP_BIN. In all subsequent frames, nOpCode must be set to WS_OP_CONT. On the very last frame set isFinalFrame to .T. Note that the control frames WS_OP_CLOSE, WS_OP_PING and WS_OP_PONG may not be fragmented.


xbWebSocket: object properties

:AutoPong exported/logical Controls whether the :Recv method will automatically reply to Ping control frames with a Pong. To disable this functionality, set :AutoPong to .F. (by default it is enabled). :DataReceived exported/character string Provides a reference to the payload message received in the most recent call to :Recv. If there was no incoming data available, the value will be NIL. :MaxPayloadSize exported/numeric Set a limit on the size of a payload (in bytes) that can be received from an endpoint in one data frame. If the data to be transmitted is larger than this value, the endpoint will need to fragment the message into multiple frames. The default value for this property is 999999 bytes. :OpCode exported/numeric Indicates the type of data frame received from endpoint in the most recent call to :Recv. If no data was received, :OpCode will be NIL, otherwise the following codes defined in Xb2NET.CH are possible:

OpCodeDescription
WS_OP_CONTContinuation data frame of a larger fragmented message. Check :isFinalFrame to determine if this is the last frame in the message.
WS_OP_TEXTData frame contains UTF-8 encoded text.
WS_OP_BINData frame contains binary data.
WS_OP_CLOSEControl frame indicating the connection will be closed by endpoint.
WS_OP_PINGPing control frame.
WS_OP_PONGPong control frame. Note that a Pong frame may be sent by an endpoint unsolicited.
:StatusCode exported/numeric When a connection is closed by an endpoint, the :StatusCode property will indicate the reason why the endpoint closed the connection. The code will be an integer numeric value in the range 1000-4999. Standard WebSocket status codes are defined in Xb2NET.CH with prefix WS_STATUS_*. :isClient exported/logical Indicates if the local endpoint is a client or server. The property will be .T. if the :Connect method was used to establish the WebSocket connection. :isFinalFrame exported/logical Indicates if the data frame received from endpoint in the most recent call to :Recv is the final frame. The following possibilities exist:

isFinalFrame OpCode Description
.T.WS_OP_TEXT, WS_OP_BINUnfragmented messages consisting of a single frame
.F.WS_OP_TEXT, WS_OP_BINFirst data frame in a fragmented message
.F.WS_OP_CONTA data frame in a fragmented message
.T.WS_OP_CONTFinal frame in a fragmented message


xbServer     inherited from xbSocket and Thread

This class implements a generic socket listener that spawns an xbSocketThread when a client connection is accepted.

xbServer: class methods

:New([xLocalAddr], [nPort], [oSSLContext], [cName], [nAddrFamily]) → self Creates a new instance of the xbServer class and allocates system resources to bind the newly created socket to a specific transport service provider. The xbServer class is inherited from xbSocket and Thread (part of Xbase++). An instance of this class will therefore have access to all methods and properties of its superclasses. For information on the Thread class, please consult your Xbase++ documentation. All parameters are optional. Parameters: xLocalAddr The local address can be specified either as a numeric address in network byte order, an IPv4 address in form of a dotted octet string (eg. '127.0.0.1'), or as an IPv6 address in the form of a 8 groups of hextets separated by colons (eg. '2001:db8::ff00:42:8329'). Note that IPv6 addresses may be abbreviated. For example, the loopback address, '0000:0000:0000:0000:0000:0000:0000:0001', may be shortened to '::1'. If an application does not care what local address is assigned, specify the constant value INADDR_ANY (the default and IPv4 use) or IN6ADDR_ANY (for use with IPv6). This allows the underlying service provider to use any appropriate network address. nPort This is the numeric port number on the local computer to bind the socket to. If not supplied, the default is 23 (or 992 when using an xbSSLContext) which are the standard port numbers for Telnet and TelnetS respectfully. oSSLContext In order to secure data transmission and possibly authenticate clients, an instance of xbSSLContext can be passed using this parameter. cName Optional descriptive name to associate with the thread instance. See Xbase++ documentation Thread:Name. nAddrFamily An address family, define constant AF_*. Defaults to AF_INET6 when xLocalAddr contains an IPv6 style numeric address, and AF_INET otherwise.


xbServer: class properties

:ServerName readonly/character Contains server name and version number, eg. Xb2.NET/3.2.21

xbServer: object methods

:ActiveConnections() → nConnectionsOpen Returns the total number of connections currently open. :SetBacklog([nBacklog]) → nBacklog Get/set the maximum length of the queue of pending connections. If this value is SOMAXCONN (the default), then the underlying service provider responsible for this socket will set the backlog to a maximum "reasonable" value. There is no standard provision to find out the actual backlog value however if nBacklog is not specified, the method will return the current backlog setting (which may not necessarily be the actual backlog value set by the service provider).

If the server is running and the socket is in a listening state, calls to :SetBacklog will update the current backlog for the socket. If there are more pending connections than the new backlog value, the excess pending connections will be reset and dropped. :Start() → lSuccess Start running the server in its own thread. If the server thread is started successfully, the method returns .T., otherwise it returns .F. Once started, the server will begin listening for incoming connections on the address and port specified when the xbServer object was instantiated. A new xbSocketThread object will be instantiated and bound to each accepted connection. It is the xbSocketThread object that is responsible for handling the actual communications with the client.

The server will continue running in its own thread and listening for incoming connections until it is terminated by calling the :Stop method. Once the server has stopped, it can be restarted by calling :Start. As long as the server thread is active, repeated calls to :Start are ignored. :Stop([nTimeOut]) → lSuccess Close server socket and signal server plus all connected clients to terminate. nTimeOut is an optional parameter specifying the maximum amount of time, in 1/100ths of a second, to wait for the xbServer thread (including all connected clients) to terminate. The default value of zero causes the current thread (where :Stop was called) to wait indefinitely until the xbServer thread and all connected clients have terminated. The method returns .F. if the server could not be terminated within the specified time interval, otherwise it returns .T.


xbServer: object properties

Status :ConnectCount exported/numeric Total number of connections accepted since server started. This is not the same as :ActiveConnections. :ThreadID readonly/numeric Numeric ID of thread. Configuration :MaxConnections exported/numeric | NIL Maximum allowable number of concurrent client connections. A value of NIL (the default) does not impose a limit on the number of concurrent client connections. See :onMaxConnect for additional information. :SleepTime exported/numeric This setting takes effect when the :MaxConnections condition is reached. It defines the amount of time in 1/100ths of a second to idle the xbServer thread before accepting a new connection. :WorkerClass exported/reference to class function This instance variable provides a reference to a client socket handler class function. By default :WorkerClass contains a reference to the xbSocketThread class function, however it can be used to define a custom client socket handler to be used instead of xbSocketThread. When instantiated, the init method of the worker class will receive two parameters: (1) a reference to the parent server object, and (2) a numeric handle of the newly created socket. If a custom class is used, it should be derived either from the xbSocket and Thread classes or from the xbSocketThread class.

Example: oServer:WorkerClass := MyClientHandler()

CLASS MyClientHandler FROM xbSocketThread
EXPORTED:
INLINE METHOD Init(oParent, nHandle)
  ::xbSocketThread:init(oParent, nHandle)
  // add your custom init code here
  Return self

// The :Execute method is where all the work is done, add your custom code here
INLINE METHOD Execute()
  Local cRecv := ::Recv()
  if ::BytesReceived > 0
    ::Send( cRecv ) // just echo back whatever we receive
  endif
  Return self

ENDCLASS
Event Handling :atEnd exported/character | codeblock | NIL Can be used to provide an optional code block or a character string containing the name of a globally visible function that will be executed before the thread terminates. This property will be inherited by worker threads. :onCertificateChange exported/codeblock | NIL This (optional) codeblock will be executed when an updated SSL/TLS certificate file is available. The codeblock must return a new xbSSLContext loading the updated certificate file.

Example: oServer:onCertificateChange := {|| MakeSSLContext()}

FUNCTION MakeSSLContext()
  Local oSSL

  oSSL := xbSSLContext():new( TLS_server_method )
  do case
  case ! oSSL:UseCertificateChainFile(".\SSL\MYCERT.PEM")
    cError := "Problem with certificate"
  case ! oSSL:UsePrivateKeyFile(".\SSL\MYKEY.PEM")
    cError := "Problem with private key"
  case ! oSSL:CheckPrivateKey()
    cError := "Private key does not match certificate public key!"
  case ! oSSL:LoadDHParams(".\SSL\DH2048.PEM")
    cError := "Problem loading DH params file"
  endcase

  if cError != NIL
    cError := "Unable to initialize SSL/TLS context - " + cError + CRLF + xbSSLGetErrorString()
    ErrorLog( cError )
    oSSL:destroy()
    Return NIL
  endif
Return oSSL
:onConnect exported/codeblock | NIL This is the codeblock that will be executed when a client connection is accepted. If :onConnect is NIL, then the server will simply echo back to the client all received data (this is the default behavior). For the server to do anything useful, a codeblock must be attached to this ivar. The purpose of this codeblock is to receive the client request, process as required and send back a response. The connected socket can be kept open as long as required or until the client disconnects.

It is important to note that the code encapsulated by the codeblock will be executed in a new xbSocketThread. This thread remains active as long as the socket connection is open. It may be terminated by closing the socket connection (from either the server or client sides) and exiting the procedure. The client socket will be automatically shut down and closed just before the thread terminates.

Example: oServer:onConnect := {||ServiceClient()}

PROCEDURE ServiceClient()
  Local cRecv, cSend
  Local oClient := ThreadObject()
  Local cTempFile := "~" + NTrim(oClient:Handle) + ".tmp"

  while (cRecv := oClient:RecvLine()) != NIL
    cSend := cRecv
    cRecv := StrTran(StrTran(cRecv,chr(10),""),chr(13),"")
    RunShell( "/C " + cRecv + " > " + cTempFile,,.f.,.t. )
    cSend += MemoRead(cTempFile)
    FErase(cTempFile)
    if oClient:Send( cSend ) < 0
      exit
    endif
  end
Return
:onMaxConnect exported/character | codeblock | NIL The :onMaxConnect ivar determines what happens when :ActiveConnections reaches :MaxConnections. The following options are possible:

NIL - do not accept any more connections until an existing client connection is closed.
STRING - accept new connection, receive request, send string contained in :onMaxConnect to client and immediately close connection.
CODEBLOCK - accept new connection, create new xbSocketThread object and execute codeblock contained in :onMaxConnect within this new thread.

Example: oServer:MaxConnections := 50
oServer:onMaxConnect := "Too many connections, please try later..."
// or
oServer:onMaxConnect := {||SendBusy()}

PROCEDURE SendBusy()
  Local oThread := ThreadObject()
  oThread:Recv()
  if oThread:BytesReceived > 0
    oThread:Send( "Too many connections, please try later...")
  endif
Return


xbHTTPServer     inherited from xbServer

This class implements an HTTP 1.1 listener that spawns an xbHTTPThread when a client connection is accepted.

xbHTTPServer: class methods

:New([xLocalAddr], [nPort], [oSSLContext], [cName], [nAddrFamily]) → self Creates a new instance of the xbHTTPServer class and allocates system resources to bind the newly created socket to a specific transport service provider. The xbHTTPServer class is inherited from xbServer which in turn is inherited from xbSocket and Thread. An instance of this class will therefore have access to all methods and properties of its superclasses. For information on the Thread class, please consult your Xbase++ documentation. All parameters are optional. Parameters: xLocalAddr The local address can be specified either as a numeric address in network byte order, an IPv4 address in form of a dotted octet string (eg. '127.0.0.1'), or as an IPv6 address in the form of a 8 groups of hextets separated by colons (eg. '2001:db8::ff00:42:8329'). Note that IPv6 addresses may be abbreviated. For example, the loopback address, '0000:0000:0000:0000:0000:0000:0000:0001', may be shortened to '::1'. If an application does not care what local address is assigned, specify the constant value INADDR_ANY (the default and IPv4 use) or IN6ADDR_ANY (for use with IPv6). This allows the underlying service provider to use any appropriate network address. nPort This is the numeric port number on the local computer to bind the socket to. If not supplied, the default is 80 (or 443 when using an xbSSLContext) which are the standard port numbers for HTTP and HTTPS respectfully. oSSLContext In order to secure data transmission and possibly authenticate clients, an instance of xbSSLContext can be passed using this parameter. cName Optional descriptive name to associate with the thread instance. See Xbase++ documentation Thread:Name. nAddrFamily An address family, define constant AF_*. Defaults to AF_INET6 when xLocalAddr contains an IPv6 style numeric address, and AF_INET otherwise.

xbHTTPServer: object methods

:GetRelativePath( cFullPath ) → cRelativePath Returns the file path relative to the root directory for HTTP server (:RootDir). If the two paths cannot be reconciled, the method returns a zero length string.

Example: oServer:RootDir(".\www_root")
? oServer:GetRelativePath("e:\website\www_root\prg\hello.prg")
// output: "prg\hello.prg"
:RootDir( [cPath] ) → cPath Get/set default root directory for HTTP server. If not specified, the default is the current path where the webserver application is running (not recommended).
! Never place private or sensitive data anywhere within the :RootDir (including sub-folders)!
! Using the default setting is discouraged because it exposes the application's folder for potential unauthorized access! :StatusText( nStatusCode ) → cStatusText Return a text message corresponding to an HTTP response status code. Please see xbHttpStatusText() for a listing of HTTP response status codes and associated text messages.


xbHTTPServer: object properties

Configuration :AllowDelete exported/logical When set to .T., client is permitted to delete a file on the HTTP server by using the DELETE method. The target file is specified in the URI request. This property is ignored when the :onDELETE ivar contains a codeblock. The default value is .F. :AllowTrace exported/logical When set to .T., client is permitted to submit HTTP TRACE requests. The default is .F., ie. the TRACE command is disabled. The HTTP TRACE command is used for testing and debugging. When an HTTP TRACE request is sent to a web server that supports it, that server will respond echoing the data that is passed to it, including any HTTP headers. It is recommended that TRACE be only supported in a test environment since it is theoretically possible for a client to use HTTP TRACE for cross-site-scripting attacks. :AllowUpload exported/logical When set to .T., client is permitted to upload a file to the HTTP server by using the PUT method. The target file is specified in the URI request, with the file contents contained within the body of the request. This property is ignored when the :onPUT ivar contains a codeblock. The default value is .F. :CacheControl exported/character Defines server-wide cache control policy for static files. If a value is provided, it will be used to add an HTTP "Cache-Control" header field to all static files (htm, css, js, jpg,...) requested by a client. This setting only applies to static files, dynamic requests are never cached. For additional information on the "Cache-Control" header field see RFC-2616, 14.9.

Examples: // allow content to be cached for up to 24 hrs
oServer:CacheControl := "max-age=86400"
// prevent saving of HTTP request & response in non-volatile storage medium.
oServer:CacheControl := "no-store"
:CompressedFilePrefix exported/character Specifies the file prefix to be used when saving temporary compressed versions of files found within :RootDir.

Web server files are automatically compressed as they are requested. In order to save CPU cycles for future requests, a copy of the compressed file is saved within the same directory using a hidden attribute and a unique file name prefix. When a compressed version already exists, the server will compare the timestamp with the original file to determine if the compressed version is stale. The default file name prefix used is "~", eg:

Original file: d:\www_root\index.htm
Temporary compressed version (hidden): d:\www_root\~index.htm :CompressHttp10 exported/logical This property enables or disables compression for requests containing an HTTP 1.0 version number.

HTTP 1.0, as described in RFC 1945, provides a minimal level of support for certain types of compression. However, some confusion exists around HTTP 1.0 compression, especially with regard to proxy servers. To minimize the chance of inappropriately returning a compressed file to a client that cannot decompress it, you can use this property to disable compression in questionable scenarios.

The default value of this property is .F., meaning that compression is disabled for HTTP 1.0 requests. :CompressLevel exported/numeric Sets the default compression level to be used when compressing HTTP content. Acceptable values are between 0 and 9, where 0 = no compression and 9 = highest compression. Although a higher compression level will result in smaller data, it will also result in higher CPU utilization. Best performance can be achieved by setting the compression level to 6 or 7. The default is 0 or no compression.

? Data compression is implemented by the open-source ZLIB.DLL library that uses the "deflate" method as documented in RFC-1950. :CompressTypes exported/character Specifies a list of HTTP content MIME types that will be automatically compressed when compression is enabled (:CompressLevel > 0). The default is: "text/html;text/xml;text/plain;text/sgml;text/rtf;text/vbscript;application/javascript;" :IndexFile exported/character | character array | NIL This is the default file that will be returned to the client when no resource is requested. A single value can be specified as a character string or multiple values as an array of character strings. When multiple values are specified, the server will search the root directory for the first match. The default is: {"default.htm", "default.html", "index.htm", "index.html", "main.htm", "main.html"}

Setting :IndexFile to NIL will cause all client requests with an empty URI path component to be routed to the :onGET codeblock. :MaxHeaderBytes exported/numeric Specifies the maximum size of the HTTP header accepted by the server before terminating the client connection. Default is 16,384 bytes. :MaxRequestLength exported/numeric Specifies the maximum size of the input stream. It can be used to prevent denial of service attacks caused by users who post large files to the server. The size specified is in kilobytes. See also: :MinSendRate and :MinRecvRate. :SessionCookies exported/logical Specify whether session cookies will be used for HTTP state management. The default value is .T. meaning that session cookies will be used for state management. Many browsers will return the same session ID to the HTTP server for browsing sessions opened in a new tab or even a new window. Sometimes this is desirable but often it may not be. In such a case, session cookies should be disabled by setting this property to .F. :SessionTag exported/character This is the tag name that will be used to track a session-state between the server and client. Each session is identified by an ID that must be communicated between the server and client with each request-response state. By default, an xbHTTPThread object will use cookies to maintain this session ID between states. However, this may not always work since a client may have cookie support turned off. In such cases, the session ID can be communicated between states by embedding the session ID in the URL (as a query parameter) or as a hidden form variable within an HTML page. Each instance of the HTTP server can have a different session tag identifier. The default is: _SID :SessionTimeout exported/numeric Inactive session timeout in minutes. An inactive client xbSession object will be maintained in memory for a minimum :SessionTimeout minutes. The default is 15 minutes. :SOAPParser exported/reference to class function This instance variable provides a reference to a SOAP parser class function. By default :SOAPParser contains a reference to the xbSOAPEnvelope class function, however it can be used to define a custom SOAP parser to be used instead of xbSOAPEnvelope. When instantiated, the init method of the SOAP parser will receive a single character string parameter containing the SOAP envelope. If a custom class is used, it should at minimum contain a GetVar method that returns the value of a SOAP parameter.

Example: oServer:SOAPParser := MySOAPParser()

CLASS MySOAPParser
EXPORTED:
INLINE METHOD init( cXMLString )
  // code to parse the XML SOAP envelope
  Return self

INLINE METHOD GetVar( cName )
  // code to return value of input parameter cName
  Return xValue

ENDCLASS
:TLog exported/object | NIL Provides a reference to the object that will be used for logging client requests. To enable transaction logging, set :TLog to an instance of the xbTLog class. To disable or pause logging temporarily, set :TLog to NIL.

Example: oTLog := xbTLog():new()
oTLog:SetDir(".\LogFiles")

oServer := xbHTTPServer():new()
oServer:TLog := oTLog
:WorkerClass exported/reference to class function This instance variable provides a reference to a client socket handler class function. By default :WorkerClass contains a reference to the xbHTTPThread class function, however it can be used to define a custom client socket handler to be used instead of xbHTTPThread. When instantiated, the init method of the worker class will receive two parameters: (1) a reference to the parent server object, and (2) a numeric handle of the newly created socket. If a custom class is used, it should be derived either from the xbSocket and Thread classes or from the xbHTTPThread class.

Example: oServer:WorkerClass := MyHTTPHandler()

CLASS MyHTTPHandler FROM xbHTTPThread
EXPORTED:
INLINE METHOD Init(oParent, nHandle)
  ::xbHTTPThread:init(oParent, nHandle)
  // add your custom init code here
  Return self

// The :Execute method is where all the work is done, add your custom code here
INLINE METHOD Execute()
  Local oRequest := ::HTTPRequest
  Local oResponse := ::HTTPResponse

  while oRequest:Recv()
    do case
    case oRequest:Command == "GET"
      // code to generate GET response
    case oRequest:Command == "POST"
      // code to generate POST response
    case oRequest:Command == "HEAD"
      // code to generate HEAD response
    otherwise
      // send command not implemented status code
      oResponse:StatusCode := 501
    endcase
    oResponse:Send()
    if !oRequest:KeepAlive
      // client doesn't want to keep connection open
      ::Close()
    endif
    oResponse:Reset() // reinitialize object
  end
  Return self

ENDCLASS
Event Handling :FilterRequest exported/codeblock | NIL When supplied, this optional codeblock will be executed right after an HTTP request is received and prior to a response being generated. A :FilterRequest codeblock can be used to easily spy on all HTTP requests and if desired, modify the request prior to it being processed by the default HTTP handler. If supplied, the codeblock must return a logical value. A return value of .F. indicates that the codeblock has generated a response and no additional processing is required (ie. the request will not be processed by the default HTTP handler). A return value of .T. tells the default HTTP handler to process the request as usual. When evaluated, the codeblock will receive one parameter; a reference to the connected xbHTTPThread object.

Example 1: oServer:FilterRequest := {|o|FilterRequest(o)}

FUNCTION FilterRequest(oClient)
  if "windows" $ Lower(oClient:HTTPRequest:Path())
    // don't allow access to system folder
    oClient:HTTPResponse:StatusCode := 403
    oClient:HTTPResponse:ContentType("text/plain")
    oClient:HTTPResponse:Content := "The POLICE has been dispatched!"
    Return .F.
  endif
Return .T.

Example 2: The following function shows how to use :FilterRequest to do virtual hosting. It assumes that the hosted websites are organized as follows:
/www_root/website1/...
/www_root/website2/...
/www_root/website3/...
etc...


For example if the 3 websites hosted are sqlexpress.com, xb2.net and mail.xb2.net, then the directory structure will be as follows:
/www_root/sqlexpress.com/...
/www_root/xb2.net/...
/www_root/mail.xb2.net/...

oServer:RootDir("/www_root")
oServer:FilterRequest := {|o|VirtualHosting(o)}

FUNCTION VirtualHosting(oClient)
  Local i
  Local cHost := Lower(oClient:HTTPRequest:Host())
  Local cPath := oClient:HTTPRequest:Path()

  // strip out port numbers
  if (i := At(':',cHost)) > 0
    cHost := Left(cHost,i-1)
  endif

  // modify requested path
  if cPath $ "/\" .or. Empty(cPath)
    cPath := "/index.htm"
  endif
  cPath := "/" + cHost + cPath
  oClient:HTTPRequest:Path(cPath)
Return .T.

Example 3: Process Microsoft and Android connectivity checks on your own server. Modify your local hosts file to point the following host names to your own HTTP server:
connectivitycheck.android.com, connectivitycheck.gstatic.com, msftncsi.com, dns.msftncsi.com, www.msftncsi.com, msftconnecttest.com, www.msftconnecttest.com

oServer:FilterRequest := {|o|FilterRequest(o)}

FUNCTION FilterRequest(oClient)
  Local cPath := oClient:HTTPRequest:Path()
  if !empty(cPath)
    cPath := lower(cPath)
    if "/generate_204" $ cPath // Android
      oClient:HttpResponse:StatusCode := 204
      oClient:NoLog := .t.
      Return .F.
    elseif "/connecttest.txt" $ cPath // Microsoft
      oClient:HttpResponse:ContentType := "text/plain"
      oClient:HttpResponse:content := "Microsoft Connect Test"
      oClient:HttpResponse:CacheControl("no-store, max-age=0")
      oClient:NoLog := .t.
      Return .F.
    elseif "/ncsi.txt" $ cPath // Microsoft (old format)
      oClient:HttpResponse:ContentType := "text/plain"
      oClient:HttpResponse:content := "Microsoft NCSI"
      oClient:HttpResponse:CacheControl("no-store, max-age=0")
      oClient:NoLog := .t.
      Return .F.
    endif
  endif
Return .T.

Example 4: Set up a reverse proxy by relaying HTTP requests to a different server. See xbHTTPReverseProxy() for sample code. :onDELETE exported/codeblock | NIL This is an optional codeblock that will be executed when a DELETE request is received. By default DELETE requests are rejected unless :AllowDelete is set to .T. or a custom codeblock is assigned to the :onDELETE ivar. When evaluated, the codeblock will receive one parameter; a reference to the connected xbHTTPThread object.

Example: oServer:onDELETE := {|o|DeleteFile(o)}

PROCEDURE DeleteFile( oClient )
  Local cRootDir := oClient:Parent:RootDir()
  Local cFile := oClient:HTTPRequest:Path

  cFile := cRootDir + iif(Left(cPath,1)=="/", SubStr(cPath,2), cPath)
  oClient:HTTPResponse:ContentType("text/plain")
  if FErase(cFile) == 0
    oClient:HTTPResponse:Content := "File deleted"
  else
    oClient:HTTPResponse:Content := "Unable to delete file"
  endif
Return
:onGET exported/codeblock | NIL This is an optional codeblock that may be used to define a custom user function for processing dynamic requests instead of using the default built-in behaviour. HTTP requests that fall under this category include; (a) requests with a URI query component ( http://example.com/hello?key=1234 ), (b) requests containing parentheses ( http://example.com/hello() ), and (c) requests with an empty URI path component and no :IndexFile defined. If a dynamic request is received, and :onGET is set to NIL, then the server will reply with a 404 status code. When evaluated, the supplied codeblock will receive one parameter; a reference to the connected xbHTTPThread object. :onHTTPError exported/codeblock | NIL This is an optional codeblock that will be executed when a runtime error occurs while processing the HTTP request. If no custom codeblock is supplied, the default behavior is to log the error and return to the client a description of the error including callstack information. If a codeblock is supplied and a runtime error occurs within the connected client's xbHTTPThread, the codeblock will be evaluated with one parameter passed; a reference to the Xbase++ Error object. The function evaluated within the supplied codeblock must terminate with a Break(). If a character string is passed to the Break() function (as in the example below), then this string will be transmitted to the client. Alternatively, if an error object is passed, then the HTTP server will generate a corresponding reply.

Example: oServer:onHTTPError := {|o|HTTPError(o)}

PROCEDURE HTTPError( oError )
  Local oClient := ThreadObject()
  Local cCRLF := chr(10)+chr(13)
  Local cResponse

  oClient:HTTPResponse:ContentType("text/plain")
  cResponse := "An error occurred in my Xbase++ web server:" + cCRLF +;
    iif(ValType(oError:subSystem) == "C", oError:subSystem, "???" ) + "/" +;
    iif(ValType(oError:subCode) == "N", Str(oError:subCode), "???" ) + cCRLF +;
    iif(ValType(oError:description) == "C", oError:description, "" )
  Break( cResponse )
Return
:onInvalidCommand exported/codeblock | NIL This is an optional codeblock that will be evaluated when a non-supported method is requested by the client. If no custom codeblock is supplied, the default behavior is to reply with an HTTP 501 status code. When evaluated, the supplied codeblock will receive one parameter; a reference to the connected xbHTTPThread object.

Example: oServer:onInvalidCommand := {|o|MethodNotSupported(o)}

PROCEDURE MethodNotSupported( oClient )
  Local oResp := oClient:HTTPResponse
  oResp:StatusCode := 501
  oResp:ContentType := "text/plain"
  oResp:Content := "The requested method is not supported!"
Return
:onLog exported/codeblock | NIL An optional codeblock that will be evaluated immediately after a client request is completed and just before the transaction is to be logged. If supplied, the codeblock must return a logical value. A return value of .F. indicates an entry should not be added to the log file for this transaction. A return value of .T. indicates to proceed as usual; ie. if logging is enabled (see :TLog), then the transaction will be logged.

This codeblock can therefore be used to filter what gets logged to the transaction log file and/or to perform custom logging. When evaluated, the supplied codeblock will receive one parameter; a reference to the connected xbHTTPThread object.

Example: oServer:onLog := {|o|OnLog(o)}

FUNCTION OnLog( oClient )
  if oClient:InetNtoA(oClient:RemoteAddr) == "127.0.0.1"
    // don't log requests originating from localhost
    Return .F.
  endif
Return .T.
:onNotFound exported/codeblock | NIL This is an optional codeblock that will be evaluated when a requested resource is not found. If no custom codeblock is supplied, the default behavior is to reply with an HTTP 404 status code. When evaluated, the supplied codeblock will receive one parameter; a reference to the connected xbHTTPThread object.

Example: oServer:onNotFound := {|o|FileNotFound(o)}

PROCEDURE FileNotFound( oClient )
  Local oReq := oClient:HTTPRequest
  Local oResp := oClient:HTTPResponse

  if oReq:Path == "/~5" .or. oReq:Path == "\~5"
    // redirect user to the new location
    oResp:Location := "http://www.SomeOtherLocation.com"
    oResp:StatusCode := 301
  else
    oResp:StatusCode := 404
    oResp:ContentType := "text/plain"
    oResp:Content := "The requested file is not found!"
  endif
Return
:onPOST exported/codeblock | NIL This is an optional codeblock that may be used to define a custom user function for processing HTTP POST requests. It can also be set to NIL in order to reject all POST requests. When set to NIL, the server will reply with a 501 status code when an HTTP POST request is received. By default, a built-in function is used to automatically process POST requests. When evaluated, the supplied codeblock will receive one parameter; a reference to the connected xbHTTPThread object. :onPUT exported/codeblock | NIL This is an optional codeblock that will be executed when a PUT request is received. By default PUT requests are rejected unless :AllowUpload is set to .T. or a custom codeblock is assigned to the :onPUT ivar. When evaluated, the codeblock will receive one parameter; a reference to the connected xbHTTPThread object. See :onDELETE for an example. :onSend exported/codeblock | NIL An optional codeblock that is evaluated just before HTTP content is sent to a client. The codeblock receives two parameters:

(1) A reference to the current xbHTTPThread object.
(2) If the content is using "chunked" transfer encoding, the 2'nd parameter will include the chunked content, otherwise it will be NIL. :onSessionClose exported/codeblock | NIL An optional codeblock that will be executed just before a client xbSession object is closed. When executed, one parameter is passed to the codeblock; a reference to the array containing the terminated session's data. :onSOAP exported/codeblock | NIL This is an optional codeblock that may be used to define a custom user function for processing SOAP requests. If a SOAP request is received, and :onSOAP is NIL, then the :onPOST codeblock will be evaluated. If that is also not defined, then the server will reply with a 501 status code. By default, a built-in function is used to automatically process SOAP requests. When evaluated, the supplied codeblock will receive one parameter; a reference to the connected xbHTTPThread object.

Example: oServer:onSOAP := {|o| MySOAPHandler(o)}

PROCEDURE MySOAPHandler( oClient )
  Local cAction, oSOAPReq, oSOAPResp

  // :HTTPRequest:Content contains an xbSOAPEnvelope instance
  oSOAPReq := oClient:HTTPRequest:Content
  // this is the action requested by the client
  cAction := oSOAPReq:Action
  // create another SOAP envelope object where we will write our response
  oSOAPResp := xbSOAPEnvelope():new()
  // tack on the word "Response" to the reply envelope action, eg. "GetDateTimeResponse"
  oSOAPResp:Action := cAction + "Response"
 
  do case
  case cAction == "GetDateTime"
      oSOAPResp:SetVar("Date", Date())
      oSOAPResp:SetVar("Time", Time())
  case cAction == "SQLExecute"
      if Empty(oSOAPReq:GetVar("SQLStatement"))
        // the parameter is missing - send back an appropriate fault response.
        oSOAPResp:SetFault("Client", "SQLStatement parameter is missing")
      else
        nResult := DefaultSQLConnection():Execute( oSOAPReq:GetVar("SQLStatement") )
        oSOAPResp:SetVar("Result", nResult)
      endif
  otherwise
      // requested method is not available - send back a fault response.
      oSOAPResp:SetFault("Client", "Client request " + cAction + " not available")
  endcase

  // attach the SOAP response envelope to the HTTP response object
  // the Xb2.NET HTTP server will take care of the rest
  oClient:HTTPResponse:Content := oSOAPResp
Return
:onWebSocket exported/codeblock | NIL This is an optional codeblock that may be used to define a custom user function for processing WebSocket upgrade requests. It can also be set to NIL in order to disable WebSocket support entirely. When set to NIL, the server will reply with a 501 status code when a WebSocket upgrade request is received. If a custom user function is supplied, the function must return a logical value where .T. indicates that the websocket upgrade request has been accepted and .F. indicates that the upgrade request has been rejected. By default, a built-in function is used to handle WebSocket upgrade requests. When evaluated, the supplied codeblock will receive one parameter; a reference to the connected xbHTTPThread object.


xbSocketThread     inherited from xbSocket and Thread

This is the client thread that is spawned by xbServer when a connection with a peer is accepted. This "worker" thread will handle the request and send a response back to the connected client.

xbSocketThread: class methods

:New([nAddrFamily], [nSocketType], [nProtocol], [oSSLContext], [cName]) → self, or;
:New(oParent, [nHandle],,, [cName]) → self
Creates a new instance of the xbSocketThread class and allocates system resources to bind the newly created socket to a specific transport service provider. The xbSocketThread class is inherited from xbSocket and Thread (part of Xbase++). An instance of this class will therefore have access to all methods and properties of its superclasses. For information on the Thread class, please consult your Xbase++ documentation. For additional information on parameters, please see xbSocket:New(). All parameters are optional. cName Optional descriptive name to associate with the thread instance. See Xbase++ documentation Thread:Name.

xbSocketThread: object methods

:Start([cFuncName|bCodeBlock], [xParamList,...] ) → lSuccess Starts the thread and executes the function cFuncName or evaluates the code block bCodeBlock within this thread. The parameters xParamList are passed on to the function or codeblock, respectively. If the thread is started successfully, the method returns .T., otherwise it returns .F.

Once started the xbSocketThread will continue executing the code encapsulated by the specified function or codeblock until the socket is either disconnected by the remote host or, the thread is terminated by calling the :Stop method. Once the thread has stopped, it can be restarted by calling :Start. As long as the thread is active, repeated calls to :Start are ignored.

If neither cFuncName or bCodeBlock are supplied, then the default behavior is to simply echo back to the connected peer all received data. The following is an example of a server type socket thread that implements two commands "GET TIME" and "GET DATE":

Example: oSocket:Start("ServiceClient", oSocket)

PROCEDURE ServiceClient( oSocket )
  Local cRecv, cSend

  while (cRecv := oSocket:RecvLine()) != NIL
    cRecv := Upper(Left(cRecv,8))
    do case
    case cRecv == "GET TIME"
      cSend := Time()
    case cRecv == "GET DATE"
      cSend := DToS(Date())
    otherwise
      cSend := cRecv + " invalid command"
    endcase
    if oSocket:Send( cSend ) < 0
      exit
    endif
  end
Return
:Stop([nTimeOut]) → lSuccess Close socket and signal socket thread to terminate. nTimeOut is an optional parameter specifying the maximum amount of time, in 1/100ths of a second, to wait for the xbSocketThread thread to terminate. The default value of zero causes the current thread (where :Stop was called) to wait indefinitely until the xbSocketThread thread has terminated. The method returns .F. if the thread could not be terminated within the specified time interval, otherwise it returns .T.


xbSocketThread: object properties

:ThreadID readonly/numeric Numeric ID of thread.


xbHTTPThread     inherited from xbSocket and Thread

This is the client thread that is spawned by xbHTTPServer when a connection is accepted from a user agent (a browser). This "worker" thread is responsible for handling the client request and generating an appropriate xbHTTPResponse that will be sent back to the client. Typically, there is no need to instantiate this class in your code since it is automatically instantiated by the xbHTTPServer when a client connection is accepted.

xbHTTPThread: class methods

:New([nAddrFamily], [nSocketType], [nProtocol], [oSSLContext], [cName]) → self, or;
:New(oParent, [nHandle],,, [cName]) → self
Creates a new instance of the xbHTTPThread class and allocates system resources to bind the newly created socket to a specific transport service provider. The xbHTTPThread class is inherited from xbSocket and Thread (part of Xbase++). An instance of this class will therefore have access to all methods and properties of its superclasses. For information on the Thread class, please consult your Xbase++ documentation. For additional information on parameters, please see xbSocket:New(). All parameters are optional. cName Optional descriptive name to associate with the thread instance. See Xbase++ documentation Thread:Name.

xbHTTPThread: object methods

Life Cycle :Start([cFuncName|bCodeBlock], [xParamList,...] ) → lSuccess Starts the HTTP server thread. If the thread is started successfully, the method returns .T., otherwise it returns .F. Once started the xbHTTPThread will continue running until the socket is either disconnected by the remote host or, the thread is terminated by calling the :Stop method. Once the thread has stopped, it can be restarted by calling :Start. As long as the thread is active, repeated calls to :Start are ignored. :Stop([nTimeOut]) → lSuccess Close socket and signal socket thread to terminate. nTimeOut is an optional parameter specifying the maximum amount of time, in 1/100ths of a second, to wait for the xbHTTPThread thread to terminate. The default value of zero causes the current thread (where :Stop was called) to wait indefinitely until the xbHTTPThread thread has terminated. The method returns .F. if the thread could not be terminated within the specified time interval, otherwise it returns .T. Send Reply :NotFound() → nBytesSent | SOCKET_ERROR Send default HTTP 404 error message to client. :Send([cBuffer], [nFlag], [xToAddr], [nToPort]) → nBytesSent | SOCKET_ERROR Transmit data provided in cBuffer to connected client. If cBuffer is NIL or not specified, the method will send the data contained in the :HTTPResponse object (the other parameters are ignored). In most cases, there is no need to call this method since it will be called automatically by the xbHTTPThread object. For a detailed explanation of all parameters, see xbSocket:Send() :SendBusy() → self Send default server busy response to client and close connection. :SendError(xError, [nStatusCode]) → self Send error message to client and close connection. xError can be either a string or an Xbase++ error object. The second parameter, nStatusCode is an optional numeric value that can be used to set the HTTP status code returned to the connected client. If not specified, the value defaults to 500. Please see xbHttpStatusText() for a description of HTTP response status codes. :SendFile(cFile) → nBytesSent | SOCKET_ERROR This method transmits a file to the client. The file path must be relative to the directory where the HTTP server application is running. If cFile is not found, then an HTTP 404 status code will be sent instead. State Management

Session or state management involves saving persistent data across multiple HTTP requests. The automatic session management performed by the xbHTTPServer class relies on one "session" cookie containing a session ID which is passed to the client. Please note that session cookies are not permanent, they are removed from the client's browser cache when the last browser window (within the same process) is closed.

Automatic session management using cookies is simple to implement since it requires no additional coding by the programmer. However if cookie support is turned off on the client side, then the session ID will be lost. To overcome this problem, some additional code will need to be added to the web application to keep track of the session ID. This is fairly easy to implement but unfortunately it cannot be done automatically by Xb2.NET. To keep track of the session ID without using cookies do this:

    1. Make sure to open a session at the start of each request. Sessions are opened by using one of the following methods:
      ThreadObject():OpenSession()
      ThreadObject():NewSession()
      ThreadObject():SetCargo()
    2. Get the session ID by using ThreadObject():GetSessionHandle()
    3. Add a variable with the name "_SID" and a value returned by :GetSessionHandle() to each URL query hyperlink that points back to the server. It is only necessary to embed the _SID variable into hyperlinks that will result in a dynamic function being executed on the web server.
    4. Add a hidden variable with the name "_SID" and a value returned by :GetSessionHandle() to each form that will be posted back to the server.
      ! Using POST variables is the preferred method of sending back the session ID because the data will not be logged by intermediary proxies and session ID's will not be exposed by clients forwarding the data to external websites in the HTTP referer header.

Example: PROCEDURE WEB_Test1()
  Local cID
  Local oClient := ThreadObject()
  if oClient:GetCargo("message") == NIL
    oClient:SetCargo("message", "Session start time:" + time())
  endif
  cID := oClient:GetSessionHandle()
  oClient:HTTPResponse:Content := "<html><body><a href=Test2?_SID=" + cID + ">Click here</a></body></html>"
  Return

PROCEDURE WEB_Test2()
  Local oClient := ThreadObject()
  oClient:HTTPResponse:Content := "<html><body>" + oClient:GetCargo("message") + "</body></html>"
  Return

To use a different variable name (other than "_SID"), then set xbHTTPServer:SessionTag to the new name, eg:

oMyHTTPServer:SessionTag := "RANDOM" :OpenSession() → self Open existing client session or create a new one if none exists. Session data is stored in server memory until the session is either closed using :CloseSession or the session times out (see xbHTTPServer:SessionTimeout). ? Calling :GetCargo or :SetCargo automatically opens a session. :NewSession([lCloseExisting]) → self Create brand new session. The optional logical parameter lCloseExisting can be set to .F. (false) in order to leave a current existing session open while creating a brand new session.

If not provided, the default value for lCloseExisting is .T. (true), meaning that the client's current session will be closed prior to creating a new session. This is equivalent to calling :CloseSession() followed by :OpenSession().

Warning: Setting lCloseExisting to .F. (false) will leave an existing session open, while opening a new one. Since sessions are maintained in memory and are not closed until a predetermined time of inactivity has elapsed, this setting has the potential of consuming more memory than normally required. If this functionality is indeed required, it is suggested that the xbHTTPServer:SessionTimeout be reduced. :CloseSession() → self Close session and release any state variables maintained in memory by the xbSession class for this client. :GetSessionHandle() → cSessionID | NIL Returns client session ID as a string or NIL if there is no session currently open for this client. :GetCargo([cName]) → xValue | aVarList | NIL Retrieve a named state variable previously saved with :SetCargo. If a parameter is not supplied or if cName is NIL, then the method will return an array of all name/value pairs saved in the current xbSession object. Note, this method will open a new session if none exists. :SetCargo([xName], [xValue]) → xPreviousValue | aPreviousVarList Store the value xValue using a symbolic character name xName until the session is closed. This method is quite flexible and can be used is several ways:

When xName and xValue are both NIL then delete all state variables (session is not closed)
When xValue is NIL, state variable with the name xName is deleted
When xName is an array, replace all name/value pairs with passed array
Otherwise add/replace value

This method will open a new session if none exists. Data :GetCookie([cName]) → cValue | aCookieList | NIL This method is a shortcut to xbHTTPThread:HTTPRequest:GetCookie(). Please see the xbHTTPRequest class for more information. :SetCookie([cName],[cValue],[dExpiry],[cPath],[cDomain],[lSecure],[cSameSite],[lHttpOnly]) → cPreviousValue | aPrevCookieList This method is a shortcut to xbHTTPThread:HTTPResponse:SetCookie(). Please see the xbHTTPResponse class for more information. :GetVar([cName],[nSource]) → cValue | aVarList | NIL Retrieve a named parameter contained within the HTTP request. If cName is NIL, then the method will return an array of name/value pairs transmitted by the client as URL query parameters.

Named parameters can be transmitted by the client as a query within the URL, eg: (http://ca.finance.yahoo.com/q?s=NT.TO&d=c&k=c4&t=1d) or as form variables within the body of the request. The optional nSource parameter can be used to specify where to retrieve the value from. If not specified the parameter will first be searched within the URL query then within the form (if available). The method will return the first value found matching the name cName or NIL if the parameter is not found. The following Xb2NET.CH define constant are provided for this purpose:

VAR_QUERY - search within URL query parameter list
VAR_CONTENT - search within the body of the HTTP request.
VAR_ANY - first search the URL query, then within the body of the HTTP request.

xbHTTPThread: object properties

:HTTPRequest readonly/object Reference to xbHTTPRequest object. This object encapsulates the client request that was sent to the HTTP server. :HTTPResponse readonly/object Reference to xbHTTPResponse object. This object encapsulates the server response that will be sent to the client. :isSOAP readonly/logical This instance variable will be .T. when the request contains a SOAP Action. In all other cases its value will be .F. :NoLog exported/logical Used to temporarily disable HTTP server logging. This can be useful in preventing unwanted information from filling up the server log. The value of this instance variable is reset to .F. on each new HTTP request. If it is set to .T. within the user function, then no data will be logged when the request is completed. :RootDir Inherits value from :Parent:RootDir but may be changed in a xbHTTPServer:FilterRequest to simplify serving files from different drives/folders. :Session exported/object Reference to xbSession object currently active for the connected client. If no session exists, the value will be NIL.


xbHTTPMessage     abstract class

This is an abstract class that provides a common foundation for the xbHTTPRequest and xbHTTPResponse classes.

xbHTTPMessage: object methods

:Reset([oSocket]) → self Reinitialize object. :GetHeader([cName]) → cValue | aHeaderList | NIL This is a generic method for retrieving HTTP header fields. If cName is NIL, then the method will return an array of name/value pairs representing all header fields. :SetHeader([cName], [cValue]) → cPreviousValue | aPreviousHeaderList This is a generic method for setting HTTP header fields. This method can be used is several ways:

When cName and cValue are both NIL then delete all headers.
When cValue is NIL, header parameter with the name cName is deleted.
When cName is an array, replace all headers with passed array.
Otherwise add/replace value
:GetCookie([cName]) → cValue | aCookieList | NIL Retrieve the value of a cookie with the name cName. If a parameter is not supplied or if cName is NIL, then the method will return an array of name/value pairs representing all cookies. :ClearContent() Clear the :Content buffer and remove all content related header fields. :GetContentAsString() Retrieve the HTTP message content as a character string. :ParseHeader( cHeader ) Parse message header. This is done automatically when a message is received using :Recv(). :AsString() → cHTTPMessage Encode header and content suitable for HTTP transport and return as character string. :Send() → nBytesSent | SOCKET_ERROR Encode header and content for HTTP transport and transmit to connected peer. :SendChunk([cData], [cExtension]) → nBytesSent | SOCKET_ERROR Transmit a chunk of data to connected peer using "chunked" transfer encoding. Sending data as chunks allows dynamically produced content to be transferred to the recipient incrementally. In order to use this method, the message header must have the TransferEncoding field set to "chunked". The message header is transmitted first using :Send(), followed by the individual chunks of data. When no more data remains, a final empty chunk must be sent to indicate the end of content. cData is a character string representing the chunk of data to be transmitted, and cExtension is a character string used to attach additional attributes and/or to indicate that an encoding transformation has been applied to the chunk. Both parameters are optional.

Example: PROCEDURE WEB_SendChunks()
  Local i, oResponse := ThreadObject():HTTPResponse

  // add a transfer-encoding header field and set it to "chunked"
  oResponse:TransferEncoding('chunked')
  // send the message header
  oResponse:Send()
  // send first chunk of content
  oResponse:SendChunk('<html><head><title>Sending Chunks</title></head><body>')

  for i := 1 to 10
    oResponse:SendChunk('<p>This is chunk #' + Str(i))
  next

  oResponse:SendChunk('<p>All done</body></html>')
  // send an empty chunk to signal end of content
  oResponse:SendChunk()
Return
:Recv([xFile]) → lSuccess Read message transmitted by remote peer and parse message header from content. The method returns .T. if data was successfully received.

The optional parameter xFile determines how the HTTP message content is saved. If xFile is provided, then the content will be saved in a file, otherwise it will be saved in the instance variable :Content.

The file where received data is saved can be specified as either a numeric handle as returned by FOpen() or FCreate(), or as a character string denoting the file name and path. NOTE: If a file handle is provided, then received data will be saved starting at the current file pointer offset. On return, the file will be left open and the file pointer will be positioned on the last byte written. If a file name is specified instead of a numeric handle, then the file will be closed.


xbHTTPMessage: object properties

:BytesReceived exported/numeric Number of bytes received by last :Recv call. :BytesSent exported/numeric Number of bytes transmitted by last :Send call. :Cargo exported/any data type Used to attach additional information to the object as required by the programmer. :Content exported/character or object Message content. Can be a character string or an object. :CompressLevel exported/numeric Sets the default compression level to be used when compressing HTTP content. Acceptable values are between 0 and 9, where 0 = no compression and 9 = highest compression. Although a higher compression level will result in smaller data, it will also result in higher CPU utilization. Best performance can be achieved by setting the compression level to 6 or 7. The default is 0 or no compression.

? Data compression is implemented by the open-source ZLIB.DLL library that uses the "deflate" method as documented in RFC-1950. :CompressTypes exported/character Specifies a list of HTTP content MIME types that will be automatically compressed when compression is enabled (:CompressLevel > 0). The default is: "text/html;text/xml;text/plain;text/sgml;text/rtf;text/vbscript;application/x-javascript;" :HTTPVersion exported/character The HTTP protocol version of the message, eg. "1.1" :MaxHeaderBytes exported/numeric Specifies the maximum acceptable size of the received HTTP header. Default is 65,536 bytes. :Message exported/character Complete HTTP header as a character string. :Socket exported/object Reference to the connected xbSocket object. Depending on the context, the peer can be either the server or the client. :StartLine exported/character First line in HTTP message. Header fields (access/assign methods) :CacheControl exported access-assign method/character Get/set the "Cache-Control" header field. This general-header field is used to control the caching mechanisms along the message route. It can be used to prevent caches from adversely interfering with the request or response. See RFC-2616, 14.9. :Connection exported access-assign method/character Get/set the "Connection" header field. This general-header field allows the sender to specify options that are desired for that particular connection. It can be used with HTTP 1.1 to keep persistent connections. See RFC-2616, 14.10. :ContentEncoding exported access-assign method/character Get/set the "Content-Encoding" header field. This header field applies to the message content and is is used as a modifier to the media-type. When present, its value indicates what additional content codings have been applied to the entity-body, and thus what decoding mechanisms must be applied in order to obtain the media-type referenced by the Content-Type header field. See RFC-2616, 14.11. :ContentLanguage exported access-assign method/character Get/set the "Content-Language" header field. This header field applies to the message content and is used to describe the natural language(s) of the intended audience for the enclosed entity. Note that this might not be equivalent to all the languages used within the entity-body. See RFC-2616, 14.12. :ContentLength exported access-assign method/numeric Get/set the "Content-Length" header field. This header field indicates the size of the message content sent to the recipient. See RFC-2616, 14.13. :ContentLocation exported access-assign method/character Get/set the "Content-Location" header field. This header field may be used to supply the location for the entity enclosed in the message when that entity is accessible from a location separate from the requested resource's URI. See RFC-2616, 14.14. :ContentMD5 exported access-assign method/character Get/set the "Content-MD5" header field. This header field is used for the purpose of providing an end-to-end message integrity check of the content. See RFC-2616, 14.15. :ContentRange exported access-assign method/character Get/set the "Content-Range" header field. This header field is sent with a partial entity-body to specify where in the full entity-body the partial body should be applied. See RFC-2616, 14.16. :ContentType exported access-assign method/character Get/set the "Content-Type" header field. This header field indicates the media type of the message content sent to the recipient or, in the case of the HEAD command, the media type that would have been sent had the request been a GET. See RFC-2616, 14.17. :KeepAlive exported access-assign method/logical Get/set the "Connection" header field. When .T. it indicates that the sender requests a persistent connection. :LastModified exported access-assign method/character Get/set the "Last-Modified" header field. This header field is used to indicate the date and time at which the message content was last modified. See RFC-2616, 14.29. :Pragma exported access-assign method/character Get/set the "Pragma" header field. This header field is used to include implementation-specific directives that might apply to any recipient along the message path. See RFC-2616, 14.32. :ProxyConnection exported access-assign method/character Get/set the "Proxy-Connection" header field. This header field is only used in HTTP/1.0. It has been superseded by the "Connection" header field in HTTP/1.1 :SecWebSocketProtocol exported access-assign method/character Get/set the "Sec-WebSocket-Protocol" header field. This header field is used in the WebSocket opening handshake. It is sent from the client to the server and back from the server to the client to confirm the subprotocol of the connection. This enables scripts to both select a subprotocol and be sure that the server agreed to serve that subprotocol. See RFC-6455. :SecWebSocketVersion exported access-assign method/character Get/set the "Sec-WebSocket-Version" header field. This header field is used in the WebSocket opening handshake. It is sent from the client to the server to indicate the protocol version of the connection. This enables servers to correctly interpret the opening handshake and subsequent data being sent from the data, and close the connection if the server cannot interpret that data in a safe manner. This header field is also sent from the server to the client on WebSocket handshake error, when the version received from the client does not match a version understood by the server. In such a case, the header field includes the protocol version(s) supported by the server. See RFC-6455. :Trailer exported access-assign method/character Get/set the "Trailer" header field. This is a general header field whose value indicates that the given set of header fields is present in the trailer of a message encoded with chunked transfer-coding. See RFC-2616, 14.40. :TransferEncoding exported access-assign method/character Get/set the "Transfer-Encoding" header field. This is a general header field indicating what (if any) type of transformation has been applied to the message body in order to safely transfer it between the sender and the recipient. This differs from the content-coding in that the transfer-coding is a property of the message, not of the entity. See RFC-2616, 14.41. :Upgrade exported access-assign method/character Get/set the "Upgrade" header field. This is a general header field that allows the client to specify what additional communication protocols it supports and would like to use if the server finds it appropriate to switch protocols. It may also be used by the server to enforce an upgrade by sending a "426 upgrade required" response. The client can then send a new request with the appropriate upgrade headers. See RFC-2616, 14.42 and RFC-2817. :Via exported access-assign method/character Get/set the "Via" header field. This is a general header field that indicates the intermediate protocols and recipients between the client and server on requests, and between the server and client on responses. See RFC-2616, 14.45. :Warning exported access-assign method/character Get/set the "Warning" header field. This is a general header field that is used to carry additional information about the status or transformation of a message which might not be reflected in the message. See RFC-2616, 14.46.


xbHTTPRequest     inherited from xbHTTPMessage and xbURI

This class encapsulates an HTTP request. It can be used on the client side to compose and send a request to an HTTP server, and on the server side it is used to receive and parse the HTTP request sent by the client.

xbHTTPRequest: class methods

:New([oSocket]) → self Creates a new instance of the xbHTTPRequest class. The optional parameter oSocket is a reference to an xbSocket object that must be supplied in order to use the :Send and/or :Recv methods.

xbHTTPRequest: object methods

:SetCookie([cName],[cValue]) → cPreviousValue | aPrevCookieList This method is used on the client side to return a previously saved cookie value back to the HTTP server. An HTTP server will request that a cookie be stored on the client side by using the xbHTTPResponse:SetCookie method. Cookies are typically used by HTTP servers to store state information on the client side. This method can be used is several ways:

When cName and cValue are both NIL then remove all cookies from internal array.
When cValue is NIL, then remove the cookie with name cName from internal array.
When cName is an array, replace all cookie name/value pairs with passed array.
Otherwise add or replace a cookie value.


xbHTTPRequest: object properties

:Command exported/character This is the HTTP method requested, eg: GET, HEAD, POST, PUT, DELETE, TRACE, CONNECT :isSOAP readonly/logical This instance variable will be .T. when the received request contains a SOAP Action. In all other cases its value will be .F. :isWebSocket readonly/logical This instance variable will be .T. when the received request contains a WebSocket opening handshake. In all other cases its value will be .F. Header fields (access/assign methods) :Accept exported access-assign method/character Get/set the "Accept" header field. This header field can be used by the client to specify certain media types which are acceptable for the response. See RFC-2616, 14.1. :AcceptCharset exported access-assign method/character Get/set the "Accept-Charset" header field. This header field allows a client to specify what character sets is is capable of understanding. See RFC-2616, 14.2. :AcceptEncoding exported access-assign method/character Get/set the "Accept-Encoding" header field. This request header field is similar to :Accept, but restricts the content codings that are acceptable in the response. See RFC-2616, 14.3. :AcceptLanguage exported access-assign method/character Get/set the "Accept-Language" header field. This request header field is similar to :Accept, but restricts the set of natural languages that are preferred in the response. See RFC-2616, 14.4. Language tags are defined in RFC-1766. :Authorization exported access-assign method/character Get/set the "Authorization" header field. It is used by a client to authenticate itself with a server. The field is usually, but not necessarily, included with the request after receiving a 401 response. The Authorization field value consists of credentials containing the authentication information of the client for the realm of the resource being requested. See RFC-2616, 14.8. :Expect exported access-assign method/character Get/set the "Expect" header field. This header field is used to indicate that particular server behaviors are required by the client. A "100-continue" token can be used by a client sending a request message with a request body to determine if the server is willing to accept the request (based on the request headers) before the client sends the request body. In some cases, it might either be inappropriate or highly inefficient for the client to send the body if the server will reject the message without looking at the body. See RFC-2616, 14.20. :ForwardedFor exported access-assign method/character Get/set the "X-Forwarded-For" header field. :Host exported access-assign method/character Get/set the "Host" header field. The Host request-header field specifies the HTTP host and port number of the resource being requested, as obtained from the original URI given by the user or referring resource. The :Host is equivalent to the xbURI:Authority portion of a URI. See RFC-2616, 14.23. :IfMatch exported access-assign method/character Get/set the "If-Match" header field. This header field is used to make an HTTP command conditional. As an example it can be used by clients to efficiently update cached information with a minimum amount of transaction overhead. See RFC-2616, 14.24. :IfModifiedSince exported access-assign method/character Get/set the "If-Modified-Since" header field. This header field is used to make an HTTP command conditional. If the requested variant has not been modified since the time specified in this field, an entity will not be returned from the server; instead, a 304 (not modified) response will be returned without any message-body. See RFC-2616, 14.25. :IfNoneMatch exported access-assign method/character Get/set the "If-None-Match" header field. See RFC-2616, 14.26. :IfRange exported access-assign method/character Get/set the "If-Range" header field. See RFC-2616, 14.27. :IfUnmodifiedSince exported access-assign method/character Get/set the "If-Unmodified-Since" header field. See RFC-2616, 14.28. :MaxForwards exported access-assign method/character Get/set the "Max-Forwards" header field. See RFC-2616, 14.31. :Origin exported access-assign method/character Get/set the "Origin" header field. See RFC-6454. :ProxyAuthorization exported access-assign method/character Get/set the "Proxy-Authorization" header field. This request header field is used by a client to identify itself to a proxy which requires authentication. The field is usually, but not necessarily, included with the request after receiving a 407 response. The :ProxyAuthorization field value consists of credentials containing the authentication information of the client for the proxy and/or realm of the resource being requested. See RFC-2616, 14.34. :Range exported access-assign method/character Get/set the "Range" header field. See RFC-2616, 14.35. :Referrer exported access-assign method/character Get/set the "Referer" header field. This request-header field allows the client to specify, for the server's benefit, the address (URI) of the resource from which the Request-URI was obtained. See RFC-2616, 14.36. :SecWebSocketKey exported access-assign method/character Get/set the "Sec-WebSocket-Key" header field. This header field is used in the WebSocket opening handshake. It is sent from the client to the server to provide part of the information used by the server to prove that it received a valid WebSocket opening handshake. This helps ensure that the server does not accept connections from non-WebSocket clients. See RFC-6455. :SOAPAction exported access-assign method/character Get/set the "SOAPAction" header field. Most HTTP servers that also provide SOAP services use this request header field to differentiate between a SOAP request and a normal web request. In most cases the content of the header field is not important, but as a general rule it should be the same as the SOAP method requested. :TE exported access-assign method/character Get/set the "TE" header field. See RFC-2616, 14.39. :UserAgent exported access-assign method/character Get/set the "User-Agent" header field. This header field contains information about the user agent (client) originating the request. It is used for statistical purposes, the tracing of protocol violations, and automated recognition of user agents for the sake of tailoring responses to avoid particular user agent limitations. See RFC-2616, 14.43. :UserEmail exported access-assign method/character Get/set the "From" header field. See RFC-2616, 14.22.


xbHTTPResponse     inherited from xbHTTPMessage

This class encapsulates an HTTP response. It can be used on the server side to compose and send an HTTP response to a connected client, and on the client side to receive and parse the HTTP response that was sent by the server.

xbHTTPResponse: class methods

:New([oSocket]) → self Creates a new instance of the xbHTTPResponse class. The optional parameter oSocket is a reference to an xbSocket object that must be supplied in order to use the :Send and/or :Recv methods.

xbHTTPResponse: object methods

:SetCookie([cName],[cValue],[dExpiry],[cPath],[cDomain],[lSecure],[cSameSite],[lHttpOnly]) → cPreviousValue | aPrevCookieList This method is used on the server side to store a cookie value on the client side. Cookies are typically used by HTTP servers to store state information on the client side. This method can be used is several ways:

When cName and cValue are both NIL then remove all cookies from internal array.
When cValue is NIL, then remove the cookie with name cName from internal array.
When cName is an array, replace all cookie name/value pairs with passed array.
Otherwise add or replace a cookie value.
Parameters: cName The name of the cookie. cValue A character string representing the cookie data to be saved in the browser's cache. dExpiry The expiration date of the cookie. If an expiration date is not set, the cookie expires after the Internet session ends. Otherwise, the cookie is persisted in the browser's cache until the expiration date. To delete a persistent cookie from the browser's cache, set dExpiry to a date in the past, eg:
oResponse:SetCookie("mycookie","",stod("19900101"))
cPath Setting the path, is optional and can be used to specify a subset of the URLs for which the cookie is valid. If a path is specified, the cookie is considered valid for any requests that match that path. For example, if the specified path is /example, requests with the paths /examplecode and /example/code.htm would match. If no path is specified, the path is assumed to be the path of the resource associated with the SetCookie header. cDomain Specifying the domain name, is optional for persistent cookies and is used to indicate the end of the domain for which the cookie is valid. Session cookies that specify a domain are rejected. If the specified domain name ending matches the request, the cookie tries to match the path to determine if the cookie should be sent. For example, if the domain name ending is .microsoft.com, requests to home.microsoft.com and support.microsoft.com would be checked to see if the specified pattern matches the request. The domain name must have at least two or three periods in it to prevent cookies from being set for widely used domain name endings, such as .com, .edu, and co.jp. Allowable domain names would be similar to .microsoft.com, .someschool.edu, and .someserver.co.jp. Only hosts within the specified domain can set a cookie for a domain. lSecure The cookie can be marked as secure so that it will only be sent to HTTPS servers. If lSecure is not specified or is set .F., a cookie is considered safe to be sent in the clear over unsecured channels. cSameSite This attribute allows you to declare if the cookie should be restricted to a first-party or same-site context. The following values are possible:

"Strict" - Cookies will only be sent in a first-party context and not be sent along with requests initiated by third party websites. This is the default setting providing the best security / privacy.
"Lax"   - Cookies are not sent on normal cross-site subrequests (eg. to load images or frames into a third party site), but are sent when a user is navigating to the origin site (ie. when following a link).
"None"   - Cookies will be sent in all contexts - in responses to both first-party and cross-site requests.
lHttpOnly When set to .T., the cookie will be inaccessible to the JavaScript Document.cookie API and will only be sent to the server. Cookies that persist in server-side sessions don't need to be available to JavaScript and should have the HttpOnly attribute. This helps mitigate cross-site scripting (XSS) attacks.


xbHTTPResponse: object properties

:StatusCode exported/numeric The StatusCode is a 3-digit integer result code of the attempt to understand and satisfy the request. The first digit defines the class of response while the remaining two digits are not categorized. There are 5 values for the first digit:

1xx: Informational - Request received, continuing process
2xx: Success - The action was successfully received, understood, and accepted
3xx: Redirection - Further action must be taken to complete the request
4xx: Client Error - The request contains bad syntax or cannot be fulfilled
5xx: Server Error - The server failed to fulfill an apparently valid request
:StatusText exported/character This is a short textual description of the :StatusCode. Please see xbHttpStatusText() for a listing of HTTP response status codes and associated text messages. Header fields (access/assign methods) :AcceptRanges exported access-assign method/character Get/set the "Accept-Ranges" header field. See RFC-2616, 14.5. :Age exported access-assign method/character Get/set the "Age" header field. This response-header field conveys the sender's estimate of the amount of time in integer seconds since the response was generated at the origin server. See RFC-2616, 14.6. :Allow exported access-assign method/character Get/set the "Allow" header field. This field lists the set of methods supported by the resource identified by the Request-URI. The purpose is to inform the recipient of commands that are supported by the resource. See RFC-2616, 14.7. :ETag Get/set the "ETag" header field. See RFC-2616, 14.19. :Expires exported access-assign method/character Get/set the "Expires" header field. This header field gives the date/time after which the message content is considered stale. See RFC-2616, 14.21. :Location exported access-assign method/character Get/set the "Location" header field. It is used to redirect the client to a location other than the Request-URI for completion of the request. For 201 (Created) responses, the Location is that of the new resource which was created by the request. For 3xx responses, the location should indicate the server's preferred URI for automatic redirection to the resource. The field value consists of a single absolute URI. See RFC-2616, 14.30. :ProxyAuthenticate exported access-assign method/character Get/set the "Proxy-Authenticate" header field. See RFC-2616, 14.33. :Refresh exported access-assign method/character Get/set the "Refresh" header field. Although this header field is not part of RFC-2616, it is supported by most browsers. By including this header field in a HTTP response, a client can be triggered to automatically fetch information from a server. This is often referred to as "client pull".

Examples: // refresh page after 60 seconds
oClient:HTTPResponse:Refresh("60")

// display page then after 3 seconds display Login.htm
oClient:HTTPResponse:Refresh("3; URL=Login.htm")

// display page then after 10 seconds redirect user to www.mysite.com
oClient:HTTPResponse:Refresh("10; URL=http://www.mysite.com")
:RetryAfter exported access-assign method/character Get/set the "RetryAfter" header field. This response-header field can be used with a 503 (Service Unavailable) response to indicate how long the service is expected to be unavailable. It may also be used with any 3xx (Redirection) response to indicate the minimum time the client is asked wait before issuing the redirected request. The value of this field can be either an HTTP-date as returned by xbGMTDate or an integer number of seconds after the time of the response. See RFC-2616, 14.37. :SecWebsocketAccept exported access-assign method/character Get/set the "Sec-WebSocket-Accept" header field. This header field is used in the WebSocket opening handshake. It is sent from the server to the client to confirm that the server is willing to initiate the WebSocket connection. See RFC-6455. :Server exported access-assign method/character Get/set the "Server" header field. This header field contains information about the software used by the origin server to handle the request. See RFC-2616, 14.38. :Vary exported access-assign method/character Get/set the "Vary" header field. See RFC-2616, 14.44. :WWWAuthenticate exported access-assign method/character Get/set the "WWW-Authenticate" header field. See RFC-2616, 14.47.


xbHTTPClient

This class provides a higher level interface for developing HTTP client applications. xbHTTPClient is also the base class for xbSOAPEnvelope and xbXMLDocument.

xbHTTPClient: class methods

:New() → self Create a new instance of the xbHTTPClient class. :DefaultSSLContext(oSSLContext) → self Designate an default xbSSLContext object, oSSLContext to be used for securing connections with remote servers. A programmer may override the default SSL context at the object level by using the :SetSSLContext() method.

xbHTTPClient: object methods

:Reset() → self Reinitialize object.
! If there is a persistent host connection open, the connection will not be closed when :Reset() is called. :Destroy() → self Clean up resources allocated by the client. This method must be called when a persistent connection is used and the instance is no longer needed. :Erase() → self Remove payload data from memory, erase any associated payload file(s) from disk and reinitialize object. :Execute(xURI, [cCommand], [xPostContent], [aHTTPHeaders], [xRecvFile]) → oHTTPResponse | NIL Send a request to a remote HTTP server and receive response. If successful, the method returns a reference to an xbHTTPResponse instance containing the deserialized response returned by the remote HTTP server. If an error occurs, the method returns NIL. The cause of the error can be determined by inspecting values saved in the :ErrorCode, :ErrorMessage and :ErrorSource instance variables. By default, if an error occurs when attempting to establish a connection, the system will automatically retry connecting using the alternate address family (AF_INET / AF_INET6). This behaviour can be disabled by setting :TryAlternateAF to .F. Parameters: xURI The name or IP address of the remote HTTP server, including port, target resource path and query string (if any). If not specified the port defaults to 80 when using HTTP or 443 when using HTTPS. xURI may be specified as either a URL-encoded character string or an xbURI object, eg:

// option 1: using URL-encoded character string
oHttp := xbHTTPClient():new()
oHttp:Execute("http://xb2.net/login?uid=smith&pwd=%26123%2B%2B")

// option 2: using xbURI object
oURI := xbURI():new()
oURI:Scheme := "http"
oURI:Authority := "xb2.net"
oURI:Path := "/login"
oURI:SetVar("uid","smith")
oURI:SetVar("pwd","&123++") // note special chars in value
oHttp := xbHTTPClient():new()
oHttp:Execute(oURI)
cCommand Optional character string specifying the HTTP method (eg. "GET", "HEAD", "POST", "PUT",...) requested. If not directly specified, cCommand defaults to "GET" if the xPostContent parameter is empty otherwise the default is "POST". xPostContent Optional character string or object providing the HTTP request content for transmission to remote server. If an object is provided instead of a character string, then the object must have a :AsString() method and :MimeType property. The object's :AsString method must return the HTTP content encoded as a character string. aHTTPHeaders Optional array of name/value pairs representing HTTP headers to be included in the request. If provided, the array must be in the following format:
{{cHeader1, cValue1}, {cHeader2, cValue2},... } xRecvFile The optional parameter xRecvFile determines how the HTTP message content is saved. If xRecvFile is provided, then the content will be saved in a file, otherwise it will be saved in the instance variable :HTTPResponse:Content.

The file where received data is saved can be specified as either a numeric handle as returned by FOpen() or FCreate(), or as a character string denoting the file name and path. NOTE: If a file handle is provided, then received data will be saved starting at the current file pointer offset. On return, the file pointer will be positioned on the last byte written to the file. If a file name is specified instead of a numeric file handle, then the file will be closed.

Example: oHttp := xbHTTPClient():new()
oHttp:Transport := VIA_WININET
oForm := xbForm():new()
oForm:SetVar("username", "indigo")
oForm:SetVar("password", "74Y5aU")
aHeaders := {{"Accept-Charset", "ISO-8859-1, US-ASCII"}, {"Cache-Control", "private"}}
oResp := oHttp:Execute("https://www.sterlingwebforms.com/webforms/scripts/default.asp?DisplayLang=English","POST",oForm, aHeaders)
if oResp == NIL
    MsgBox("Error:" + str(oHttp:ErrorCode) + chr(10) + oHttp:ErrorMessage)
else
    DispHtml(oResp:Content)
endif
:ErrorMessage() → cErrorText Return error description of most recent WinSock or WinInet error. :GetPayload() → oPayload Perform any required payload composition and return a reference to the :Payload property. :KeepAlive( lSet ) → lKeepAlive Specify .T. to create a persistent connection to a host. A persistent connection is useful when one of more methods must be executed multiple times on the same host. Once the connection is no longer required, the :Destroy() method must be called to release system resources that were allocated by the persistent connection.

Example: oHttp := xbHTTPClient():new()
oHttp:SetProxy("192.168.0.1", 8888, "robin", "batmobile1" )
// create a persistent connection since we will be
// executing multiple times on same server

oHttp:KeepAlive(.t.)
while inkey(10) != K_ESC
    oResp := oHttp:Execute("http://investdb.theglobeandmail.com/invest/investSQL/gx.stock_today?pi_symbol=ibm-n")
    DispHtml(oResp:Content)
end
// close persistent connection and cleanup resources
oHttp:Destroy()
:RecvTimeout([nMilliSec]) → nTimeout Set maximum number of millisecs to wait when receiving data from the HTTP server. The default value is zero, which refers to an infinite timeout. Any other setting is the timeout, in milliseconds. It is valid to set the timeout to any value, but values less than 500 milliseconds (half a second) are interpreted to be 500 milliseconds. When nMilliSec is not specified, the method will return the current setting. :SendTimeout([nMilliSec]) → nTimeout Set maximum number of millisecs to wait when sending data to HTTP server. The default value is zero, which refers to an infinite timeout. Any other setting is the timeout, in milliseconds. It is valid to set the timeout to any value, but values less than 500 milliseconds (half a second) are interpreted to be 500 milliseconds. When nMilliSec is not specified, the method will return the current setting. :SetAuthorization(cUserID, [cPassword]) → self This method is used to supply the user ID and password for 'basic' authentication required by some HTTP servers. :SetCallBack([xCallBack]) → self Register an object or codeblock to receive callback events. If a callback has already been registered, it can be cancelled by setting xCallBack to NIL.

For more information, please see: xbSocket:SetCallBack. :SetProxy(cProxyHost, [nProxyPort], [cUserID], [cPassword]) → self Call this method to set the proxy used to connect to the HTTP server. Parameters: cProxyHost The name or IP address of the proxy server. cProxyPort The port number used to connect to the proxy server. If not specified, the default is 80, or 443 when an SSL context is defined. cUserID The user ID for logging into the proxy server (if required). cPassword The password for logging into the proxy server (if required). :SetSSLContext([oSSLContext]) → self Designate an xbSSLContext object, oSSLContext to be used for secure communications with the peer. If oSSLContext is NIL or no parameter is supplied, then a current SSL/TLS connection (if there is one) will be shut down and its corresponding xbSSLContext will be detached from this xbHTTPClient.

NOTE: The :Execute() method will automatically create a secure connection when the target URL includes an HTTPS scheme. It is only necessary to call this method when specific SSL/TLS properties need to be set (eg. client certificate, CA lists, cypher suites,...) and :Transport is set to VIA_SOCKETS (the default). :TryAlternateAF([lSet]) → lTryAlternateAF Determines is the system will automatically retry a failed connection using the alternate address family (AF_INET / AF_INET6). For example, if :AddrFamily is set to AF_INET6 however an IPv6 connection cannot be made, then the system will seamlessly switch to IPv4 and attempt the connection again. By default, this property is enabled (.T.).


xbHTTPClient: object properties

:AddrFamily exported/numeric An address family, define constant AF_*. Defaults to AF_INET6 when the remote host name contains an IPv6 style numeric address, and AF_INET otherwise. :Cargo exported/any data type Used to attach additional information to the object as required by the programmer. :CertKeyword exported/character Specifies the search string to be used for locating a client certificate in the Windows system certificate store. The first certificate containing the specified string (case insensitive) within its subject field is used. This property only applies when :Transport is set to VIA_WININET. When using the default transport method VIA_SOCKETS, a client certificate is specified by using :SetSSLContext to attach an xbSSLContext object. :CertUseDefault exported/logical When set to .T., the system will automatically send the first matching client certificate (from Windows system certificate store) when remote HTTP server requests SSL/TLS client authentication. This property only applies when :Transport is set to VIA_WININET. When using the default transport method VIA_SOCKETS, a client certificate is specified by using :SetSSLContext to attach an xbSSLContext object. :ErrorCode exported/numeric The WinSock or WinInet error code number. :ErrorSource exported/character Additional debugging information about the last error. :HTTPResponse readonly/object Reference to xbHTTPResponse object representing response returned by the remote HTTP server. :HTTPVersion exported/character The HTTP protocol version of the request, eg. "1.1" or "1.0". The default is "1.1" :MimeType exported/character The MIME encoding type of the HTTP request content. By default it is set to "text/plain". :onRequest exported/codeblock | NIL An optional codeblock that is evaluated just before the HTTP request is sent out. When evaluated, the codeblock receives a single parameter; a reference to the xbHTTPRequest object that will be sent to the server. Example:

bLog := {|o| xbSaveToFile(o:AsString(), "HttpClient.log")}
oHttp := xbHTTPClient():New()
oHttp:onRequest := bLog
oHttp:onResponse := bLog

oResp := oHttp:Execute(...)
:onResponse exported/codeblock | NIL An optional codeblock that is evaluated immediately after the HTTP response is received and parsed. When evaluated, the codeblock receives a single parameter; a reference to the parsed xbHTTPResponse object. See example above (:onRequest): :Payload exported/object Provides a reference to the xbPayload instance. One or more attachments may be combined to form a single payload by using :Payload:Add(), example:

oReq := xbHTTPClient():new()
aFiles := Directory("d:\photos\*.jpg")

// attach the files
for i := 1 to len(aFiles)
    oReq:Payload:Add("d:\photos\" + aFiles[i,F_NAME], PL_DATA_FILE, nil, nil, aFiles[i,F_NAME])
next
// transmit payload to HTTP server
oResp := oReq:Execute("https://www.fotostore.net/upload?uid=R034657")
if oResp == NIL
    MsgBox("Error trying to send request to HTTP server!" + chr(10) +;
      "Error code:" + str(oReq:ErrorCode) + chr(10) + oReq:ErrorMessage )
    Return .f.
endif

? "HTTP server response:"
? oResp:Content
:Transport exported/numeric Specifies the transport medium that will be used to deliver the HTTP request. The following options are available: VIA_SOCKETS (the default), and VIA_WININET. The default method uses the low level WinSock library to communicate with the HTTP server directly whereas VIA_WININET uses the higher level WinInet library.

Using WinInet can be useful when it is desirable to use the client machine's preconfigured Internet Explorer settings such as proxy server, security settings and client certificates. When using VIA_WININET, secure SSL/TLS connections will use the Microsoft security provider instead of OpenSSL. :SecurityFlags exported/numeric Optional SSL/TLS security flags to use when :Transport is set to VIA_WININET. The following constants, defined in Xb2NET.CH, provide a list of security flags that can be used. Individual flags can be added together to achieve the desired security behaviour:

SECURITY_FLAG_IGNORE_REVOCATION - Ignores certificate revocation problems.
SECURITY_FLAG_IGNORE_UNKNOWN_CA - Ignores unknown certificate authority problems.
SECURITY_FLAG_IGNORE_WRONG_USAGE - Ignores incorrect usage problems.
SECURITY_FLAG_IGNORE_CERT_CN_INVALID - Ignores errors where the certificate common name (host name field) is incorrect.
SECURITY_FLAG_IGNORE_CERT_DATE_INVALID - Ignores errors where the SSL/TLS certificate date that was received from the server is bad or the certificate has expired.
SECURITY_FLAG_IGNORE_REDIRECT_TO_HTTPS - Ignores errors where the application is moving from a non-SSL/TLS to an SSL/TLS connection because of a redirect.
SECURITY_FLAG_IGNORE_REDIRECT_TO_HTTP - Ignores error where the application is moving from an SSL/TLS to an non-SSL/TLS connection because of a redirect.
:SSLContext readonly/object Reference to the xbSSLContext instance, or NIL if no SSL context has been assigned.


xbXMLDocument     inherited from xbHTTPClient

This class provides a simplified means for generating XML requests and parsing XML responses.

xbXMLDocument: class methods

:New([cXML]) → self Create a new instance of the xbXMLDocument class and optionally parse the XML document cXML.

xbXMLDocument: object methods

:AddPayload( cName, xData, [nDataType], [cType], [nTypeType], [cID], [cOptions], [nPos], [cXMLAttrib] ) → cID Attach a payload. The payload can be a disk file, a character string, an object containing an :AsString() method, or any Xbase++ variable. The method returns a character string representing the payload identifier. Parameters: cName The XML parameter name. xData The payload to attach. nDataType Optional numeric parameter indicating the data type of xData. If not provided, the payload data type will be inferred from the valtype of xData. If supplied, nDataType must be set to one of the following constants defined in Xb2NET.CH:

PL_DATA_NONE
There is no data. Attach an empty record.
PL_DATA_STRING
A literal character string.
PL_DATA_FILE
A disk file. In this case, xData can be specified as either a character string indicating the file name (including path) or a numeric file handle as returned by FOpen().
PL_DATA_OBJECT
An object having a :AsString() method and :MimeType property. The object's :AsString method is called during serialization with the result encoded as one payload record. A single parameter representing the payload ID is passed to the :AsString method when evaluated. The advantage of using an object vs. a literal character string is that the object may return dynamic content. A second advantage is better memory utilization in the case of multiple payloads. Assuming that the object generates some large content dynamically, system memory is utilized only when the specific payload record is serialized.
PL_DATA_CB
A codeblock whose return value is encoded as one payload record. A single parameter representing the payload ID is passed to the codeblock during serialization. if nTypeType is set to PL_TYPE_XBASE, then the return value of the codeblock may be any Xbase++ data type. Otherwise, the return value must be a literal character string. The advantage of using a codeblock vs. a literal character string is that a codeblock may return dynamic content. Another advantage is better memory utilization in the case of multiple payloads. If the codeblock generates some large content dynamically, system memory is utilized only when the specific payload record is serialized.
PL_DATA_XBASE
Xbase++ variable of any data type (object, codeblock, array, number, string, date, etc...). When received by another Xb2.NET application, the payload data is converted back into the same native Xbase++ data type. Use this type only when the payload recipient is another Xb2.NET application! cType An optional character string specifying the payload content type. This is either a MIME type or a URI reference. Examples:
"http://schemas.xmlsoap.org/soap/envelope/" (a URI reference)
"text/xml" (a MIME media-type) nTypeType Optional numeric parameter indicating the type of cType parameter. The default is PL_TYPE_UNKNOWN. If supplied, nTypeType must be set to one of the following constants defined in Xb2NET.CH:

PL_TYPE_MIME
cType is a MIME media-type, eg: "audio/mpeg"
PL_TYPE_URI
cType is an absolute URI. URIs can be used for message types that are not expected to be registered as media types or that do not map well onto the media type mechanism, eg: http://schemas.xmlsoap.org/rp/
PL_TYPE_UNKNOWN
The type is not known. This is the default.
PL_TYPE_NONE
There is no data. Attach an empty record.
PL_TYPE_XBASE
xData contains an Xbase++ value of any data type (object, codeblock, array, number, string, date, etc...). When received by another Xb2.NET application, the payload data is converted back into the same native Xbase++ data type. Use this type only when the payload recipient is another Xb2.NET application! cID Optional character string specifying a payload identifier. If not provided, a unique system generated ID will be used instead. This is the same ID value returned by the :AddPayload() method. cOptions Optional character string providing additional payload information that may be useful to the receiver. nPos Optional integer numeric value specifying the position of this payload relative to previously attached payloads. If not specified, the payload is appended to the previous payloads. To make this the first payload item, set nPos to 1. cXMLAttrib Optional character string allowing special XML tag attributes to be included with this XML parameter. :AddVar(cName, xValue, [cXMLAttrib]) Add a new variable cName, value xValue and optional XML attribute cXMLAttrib to the XML document. Unlike :SetVar, this method does not check if another element with name cName already exists in the XML document. It is therefore possible to add multiple elements with the same name. :AsString( [lRefresh] ) → cXML Serialize object into XML document. The optional parameter lRefresh, when set to .T. will force re-serialization of the object. :Execute(xURI, [cXMLStream], [aHTTPHeaders], [xRecvFile]) → oXMLReply | oHTTPResponse | NIL Send an XML request to a remote HTTP server and receive response. If successful, the method returns a reference to either an xbHTTPResponse instance or an xbXMLDocument instance providing the deserialized response returned by the remote HTTP server. If an error occurs, the method returns NIL. The cause of the error can be determined by inspecting values saved in the :ErrorCode, :ErrorMessage and :ErrorSource instance variables.

The method returns an xbHTTPResponse rather that an xbXMLDocument instance under the following conditions: (1) Response content is directed to a file (xRecvFile parameter is provided), or (2) :DeserializeResponse property is set ot .F. Parameters: xURI The name or IP address of the remote HTTP server, including port, target resource path and query string (if any). If not specified the port defaults to 80 when using HTTP or 443 when using HTTPS. xURI may be specified as either a URL-encoded character string or an xbURI object. Please see xbHTTPClient:Execute for an example.: cXMLStream An optional parameter that can be used to provide a pre-serialized XML document which will be transmitted to the server as is. Since the serialized envelope is already provided, it it not necessary to use :SetVar or :AddVar to define the XML document. aHTTPHeaders Optional array of name/value pairs representing HTTP headers to be included in the request. If provided, the array must be in the following format:
{{cHeader1, cValue1}, {cHeader2, cValue2},... } xRecvFile The optional parameter xRecvFile determines how the response content is saved. If xRecvFile is provided, then the content will be saved in a file, otherwise it will be saved in the instance variable :HTTPResponse:Content.

The file where received data is saved can be specified as either a numeric handle as returned by FOpen() or FCreate(), or as a character string denoting the file name and path. NOTE: If a file handle is provided, then received data will be saved starting at the current file pointer offset. On return, the file pointer will be positioned on the last byte written to the file. If a file name is specified instead of a numeric file handle, then the file will be closed.

If this parameter is provided, then the response sent by the HTTP server will not be deserialized. In this case the :Execute method will return a reference to an xbHTTPResponse object.

Example: oXml := xbXMLDocument():new()
oReq := xbComplexType():new("FDXRateRequest")
oXml:AddVar("FDXRateRequest", oReq)

oHeader := xbComplexType():New("RequestHeader")
oHeader:AddVar("CustomerTransactionIdentifier", xbCreateGuid())
oHeader:AddVar("AccountNumber", "1273092")
oHeader:AddVar("MeterNumber", "74821")
oHeader:AddVar("CarrierCode", "FDXE")

oReq:AddVar("RequestHeader", oHeader)
oReq:AddVar("ShipDate", date())
oReq:AddVar("DropoffType", "REGULARPICKUP")
oReq:AddVar("Service", "PRIORITYOVERNIGHT")
oReq:AddVar("Packaging", "YOURPACKAGING")
oReq:AddVar("WeightUnits", "LBS")
oReq:AddVar("Weight", 10.0)
oReq:AddVar("OriginAddress", FdxAddress("OriginAddress", "TX", 73301, "US"))
oReq:AddVar("DestinationAddress", FdxAddress("DestinationAddress", "TN", 37115, "US"))
oReq:AddVar("Dimensions", FdxDimensions(100,35,20,"CM"))
oReq:AddVar("PackageCount", 1)

oResponse := oXml:Execute("https://gateway.fedex.com")
if oResponse == NIL
    ? "Error:", oXml:ErrorCode
    ? oXml:ErrorSource
    ? oXml:ErrorMessage
else
    ? "NetCharges:", oResponse:GetVar({"EstimatedCharges","DiscountedCharges","NetCharge"})
endif
:GetVar([acName]) → xValue | aVarList | NIL Retrieve a XML element by name. The parameter acName can be used in three ways:

If cName is NIL, then the method will return an array listing all XML tags as name/value pairs.

If the parameter is a simple string, then the top-level XML document is scanned for an element with the provided name. If none is found, the method returns NIL, otherwise the method returns the element's contents.

If the parameter is an array of strings representing a search path, then the XML document is searched using the provided path. If there is no match, the method returns NIL, otherwise the final element's contents are returned.

Example: TEXT INTO cXmlDoc TRIMMED
<?xml version="1.0" ?>
<FDXRateReply xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <EstimatedCharges>
        <RateScale>01552</RateScale>
        <RateZone>5</RateZone>
        <CurrencyCode>USD</CurrencyCode>
        <BilledWeight>10.0</BilledWeight>
        <DiscountedCharges>
            <BaseCharge>47.75</BaseCharge>
            <TotalDiscount>0.00</TotalDiscount>
            <Surcharges>
                <Fuel>2.63</Fuel>
                <Other>0.00</Other>
            </Surcharges>
            <TotalSurcharge>2.63</TotalSurcharge>
            <NetCharge>50.38</NetCharge>
            <TotalRebate>0.00</TotalRebate>
        </DiscountedCharges>
    </EstimatedCharges>
</FDXRateReply>
ENDTEXT

oXml := xbXMLDocument():new(cXmlDoc)
? oXml:GetVar()
// output: {{FDXRateReply, xbComplexType, xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"}}
? oXml:GetVar("FDXRateReply")
// output: xbComplexType
? oXml:GetVar("EstimatedCharges")
// output: NIL
? oXml:GetVar({"FDXRateReply","EstimatedCharges","DiscountedCharges","NetCharge"})
// output: 50.38
:GetVarAttrib(cName) → cAttribute | NIL Retrieve a XML element's attributes. If the cName does not exist, the method returns NIL. :Parse(cXML) → self Parse the XML document cXML. Once parsed, elements can be accessed using :GetVar. :SetVar([xName], [xValue], [cXMLAttrib]) → xPreviousValue | aPreviousVarList Assign the value xValue to the parameter xName. This method and can be used is several ways:

When xName and xValue are both NIL then delete all XML elements
When xValue is NIL, then remove the element xName
When xName is an array, replace all XML elements with the passed array of name/value pairs
Otherwise add or replace the value of an individual element xName.

The optional parameter cXMLAttrib allows custom attributes to be included within the XML element.

Examples: // this is the default when using XML_BINDING_ENCODED format:
// <age xsi:type="xs:int">35</age>

oSoap:SetVar("age",35)

// remove attribute:
// <age >35</age>

oSoap:SetVar("age",35,'')

// add your own attribute:
// <age s0="tinyint">35</age>

oSoap:SetVar("age",35,'s0="tinyint"')
:SetXML(cXML) → self Assigns the XML document cXML to the object. The method is similar to :Parse but much faster, since the XML document is actually NOT parsed. Consequently, :GetVar cannot be used to access elements within the document. This method is useful when sending a preformatted document.


xbXMLDocument: object properties

:CharacterEncoding exported/character The character encoding format used within XML document. Character encodings can be specified directly either within the XML header (using :CharacterEncoding) or within the HTTP content-type header (using :MimeType). If both properties are used to provide the character encoding format, they should match.

Example: oXml:CharacterEncoding := "iso-8859-1"

/* produces an XML document with following header */
<?xml version="1.0" encoding="iso-8859-1" ?>
:DeserializeResponse exported/logical Determines whether the content returned by the remote HTTP server is parsed into an XML array. The default behaviour is to parse the response, however this can be disabled by setting this property to .F. When disabled, the :Execute method will return a reference to an xbHTTPResponse object rather than a reference to a response xbXMLDocument instance. :MimeType exported/character The MIME encoding type. By default it is set to "text/xml".

NOTE: If not explicitly specified, some HTTP servers will assume that the XML document is encoded using the UTF-8 charset. A conversion problem will result on the remote server when the XML document contains ASCII characters > 127. This problem can be eliminated by specifying the codepage directly using the :MimeType property.

Example: oXml := xbXMLDocument():new()
oXml:MimeType := "text/xml; charset=windows-1252"
oXml:SetVar(...)
oXml:Execute(...)
:SerializationFormat exported/numeric Determines how data is serialized in the XML document for transport. The following options are possible:

XML_BINDING_ENCODED
Embed data type attributes within the XML document.
XML_BINDING_LITERAL (the default)
Do NOT include data type attributes within the XML document. This serialization format results in smaller XML documents.
:XMLArray exported/array A reference to the root element containing an array of the parsed XML document.


xbSOAPEnvelope     inherited from xbHTTPClient

SOAP (Simple Object Access Protocol) provides a simple and lightweight mechanism for exchanging structured and typed information between peers in a decentralized, distributed environment using XML. SOAP is an open standard developed by the W3C that can be used in a distributed environment to execute platform and application independent remote procedure calls (RPC).

xbSOAPEnvelope: class methods

:New([cSOAPEnvelope]) → self Create a new instance of the xbSOAPEnvelope class and optionally parse the SOAP envelope cSOAPEnvelope in order to retrieve the action and attached parameters.

xbSOAPEnvelope: object methods

:AddNameSpace(cNameSpace) → self Add an XML namespace to the SOAP envelope tag. The method can be called repeatedly to add additional namespaces.

Example: oSoap:AddNameSpace('s0="https://www.lifeline.nl/schemas/vz33/"')
/* will produce the following SOAP Envelope tag (the elements in blue are the standard namespaces) */

<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:enc="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:s0="https://www.lifeline.nl/schemas/vz33/"
env:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
:AddPayload( cName, xData, [nDataType], [cType], [nTypeType], [cID], [cOptions], [nPos], [cXMLAttrib] ) → cID Attach a payload. The payload can be a disk file, a character string, an object containing an :AsString() method, or any Xbase++ variable. The method returns a character string representing the payload identifier. Parameters: cName The SOAP parameter name. xData The payload to attach. nDataType Optional numeric parameter indicating the data type of xData. If not provided, the payload data type will be inferred from the valtype of xData. If supplied, nDataType must be set to one of the following constants defined in Xb2NET.CH:

PL_DATA_NONE
There is no data. Attach an empty record.
PL_DATA_STRING
A literal character string.
PL_DATA_FILE
A disk file. In this case, xData can be specified as either a character string indicating the file name (including path) or a numeric file handle as returned by FOpen().
PL_DATA_OBJECT
An object having a :AsString() method and :MimeType property. The object's :AsString method is called during serialization with the result encoded as one payload record. A single parameter representing the payload ID is passed to the :AsString method when evaluated. The advantage of using an object vs. a literal character string is that the object may return dynamic content. A second advantage is better memory utilization in the case of multiple payloads. Assuming that the object generates some large content dynamically, system memory is utilized only when the specific payload record is serialized.
PL_DATA_CB
A codeblock whose return value is encoded as one payload record. A single parameter representing the payload ID is passed to the codeblock during serialization. if nTypeType is set to PL_TYPE_XBASE, then the return value of the codeblock may be any Xbase++ data type. Otherwise, the return value must be a literal character string. The advantage of using a codeblock vs. a literal character string is that a codeblock may return dynamic content. Another advantage is better memory utilization in the case of multiple payloads. If the codeblock generates some large content dynamically, system memory is utilized only when the specific payload record is serialized.
PL_DATA_XBASE
Xbase++ variable of any data type (object, codeblock, array, number, string, date, etc...). When received by another Xb2.NET application, the payload data is converted back into the same native Xbase++ data type. Use this type only when the payload recipient is another Xb2.NET application! cType An optional character string specifying the payload content type. This is either a MIME type or a URI reference. Examples:
"http://schemas.xmlsoap.org/soap/envelope/" (a URI reference)
"text/xml" (a MIME media-type) nTypeType Optional numeric parameter indicating the type of cType parameter. The default is PL_TYPE_UNKNOWN. If supplied, nTypeType must be set to one of the following constants defined in Xb2NET.CH:

PL_TYPE_MIME
cType is a MIME media-type, eg: "audio/mpeg"
PL_TYPE_URI
cType is an absolute URI. URIs can be used for message types that are not expected to be registered as media types or that do not map well onto the media type mechanism, eg: http://schemas.xmlsoap.org/rp/
PL_TYPE_UNKNOWN
The type is not known. This is the default.
PL_TYPE_NONE
There is no data. Attach an empty record.
PL_TYPE_XBASE
xData contains an Xbase++ value of any data type (object, codeblock, array, number, string, date, etc...). When received by another Xb2.NET application, the payload data is converted back into the same native Xbase++ data type. Use this type only when the payload recipient is another Xb2.NET application! cID Optional character string specifying a payload identifier. If not provided, a unique system generated ID will be used instead. This is the same ID value returned by the :AddPayload() method. cOptions Optional character string providing additional payload information that may be useful to the receiver. nPos Optional integer numeric value specifying the position of this payload relative to previously attached payloads. If not specified, the payload is appended to the previous payloads. To make this the first payload item, set nPos to 1. cXMLAttrib Optional character string allowing special XML tag attributes to be included with this SOAP parameter. :AddVar(cName, xValue, [cXMLAttrib]) Add a new variable cName, value xValue and optional XML attribute cXMLAttrib to the SOAP body. This method does not check if an element with name cName already exists in the SOAP body like :SetVar. It is therefore possible to add multiple elements with the same name. :AsString( [lRefresh] ) → cSOAPEnvelope Serialize object into an XML SOAP envelope. The optional parameter lRefresh, when set to .T. will force re-serialization of the object. :GetVar([acName]) → xValue | aVarList | NIL Retrieve a SOAP parameter by name. The parameter acName can be used in three ways:

If cName is NIL, then the method will return an array listing all SOAP parameters as name/value pairs.

If the parameter is a simple string, then the top-level XML document is scanned for an element with the provided name. If none is found, the method returns NIL, otherwise the method returns the element's contents.

If the SOAP envelope contains a hierarchy of complex data types, then an array of strings representing a search path can be supplied for acName. If there is no match, the method returns NIL, otherwise the final element's value is returned.

Example: see: xbXMLDocument:GetVar()
:GetVarAttrib(cName) → cAttribute | NIL Retrieve a SOAP parameter's XML attributes. If the cName does not exist, the method returns NIL. :Parse(cSOAPEnvelope) → self Parse the SOAP envelope cSOAPEnvelope in order to retrieve the action and attached parameters. Once parsed, the attached parameters can be accessed using :GetVar. :SetFault([cFaultCode],[cFaultString],[cFaultActor],[cDetailCode],[cDetailString]) → cFaultEnvelope Generate a SOAP fault envelope. Calling this method will clear the action and all parameters. Parameters: cFaultCode A character string that is intended for use by software to provide an algorithmic mechanism for identifying the fault. The following is the set of faultcodes defined by the "http://schemas.xmlsoap.org/soap/envelope/" namespace: VersionMismatch, MustUnderstand, Client, Server. If not specified, the default is "Server". cFaultString A string intended to provide a human readable explanation of the fault. It should provide some information explaining the nature of the fault. If not specified, the default is "Server Error". cFaultActor A URI character string providing information about who caused the fault to happen within the message path. cDetailCode A character string that can be used used to provide an application specific error code related to the body of the SOAP message. The detailcode is intended for use by software to provide an algorithmic mechanism for identifying the fault. cDetailString A character string that can be used to provide application specific error information related to the body of the SOAP message. The detailstring is intended to provide a human readable explanation of the fault. :SetStyle([nMessageStyle], [nSerializationFormat]) → self This method sets the formatting style of the SOAP envelope. All parameters are optional. Parameters: nMessageStyle Determines whether message is formatted using RPC or document style. The following options are possible:

SOAP_STYLE_RPC (the default)
RPC style implies that the SOAP Body contains an element with the name of the method or remote procedure being invoked. This element in turn contains an element for each parameter of that procedure.

SOAP_STYLE_DOCUMENT
Document style implies that the SOAP Body contains one or more child elements called parts. There are no SOAP formatting rules for what the Body contains; it contains whatever the sender and the receiver agree upon.

nSerializationFormat Determines how data is serialized in the SOAP envelope for transport. The following options are possible:

SOAP_BINDING_ENCODED
Uses the SOAP encoding rules defined in section 5 of SOAP 1.1. When using this format, data type information is embedded within the SOAP envelope for each parameter. This is the default when SOAP_STYLE_RPC is selected.

SOAP_BINDING_LITERAL
Data is serialized according to a schema. In practice, this schema is usually expressed using W3C XML Schema. When using this format, data type information and XML attributes are NOT embedded within the SOAP envelope resulting in smaller envelopes. This is the default when SOAP_STYLE_DOCUMENT is selected. :SetVar([xName], [xValue], [cXMLAttrib]) → xPreviousValue | aPreviousVarList Assign the value xValue to the parameter xName. This method and can be used is several ways:

When xName and xValue are both NIL then delete all SOAP parameters
When xValue is NIL, then remove the parameter xName
When xName is an array, replace all SOAP parameters with the passed array of name/value pairs
Otherwise add or replace the value of an individual parameter xName.

The optional parameter cXMLAttrib allows custom XML tag attributes to be included with the SOAP parameter.

Examples: // this is the default when using SOAP_BINDING_ENCODED format:
// <age xsi:type="xs:int">35</age>

oSoap:SetVar("age",35)

// remove attribute:
// <age >35</age>

oSoap:SetVar("age",35,'')

// add your own attribute:
// <age s0="tinyint">35</age>

oSoap:SetVar("age",35,'s0="tinyint"')
:SetXML(cSOAPEnvelope) → self Assigns the XML envelope cSOAPEnvelope to the object. The method is similar to :Parse but much faster, since the XML document is actually NOT parsed. Consequently, :GetVar cannot be used to access elements within the document. This method is useful when sending a preformatted document. Client-Side Only Methods (see additional methods in parent xbHTTPClient class) :Execute(xURI, [cMethod], [cSOAPAction], [cXMLStream], [xRecvFile]) → oSOAPReply | oHTTPResponse | NIL Execute a method on a remote SOAP server. The method returns an xbSOAPEnvelope object that will contain data returned by the remote SOAP server, or a fault if the method failed to execute.

The method returns an xbHTTPResponse rather that an xbSOAPEnvelope instance under the following conditions: (1) Response content is directed to a file (xRecvFile parameter is provided), or (2) :DeserializeResponse property is set ot .F.

Parameters: xURI The name or IP address of the remote SOAP server, including port, target resource path and query string (if any). If not specified the port defaults to 80 when using HTTP or 443 when using HTTPS. xURI may be specified as either a URL-encoded character string or an xbURI object. Please see xbHTTPClient:Execute for an example.: cMethod The requested action to execute on the server. If not specified cMethod defaults to :Action, in which case :Action must not be blank. cSOAPAction An optional parameter that will set the SOAPAction header field in the HTTP request. If not specified cSOAPAction defaults to cMethod. Some SOAP servers may require a specific SOAPAction header field to be specified. cXMLStream An optional parameter that can be used to provide a pre-serialized XML SOAP envelope which will be transmitted to the server as is. Since the serialized envelope is already provided, it it not necessary to use :SetVar, :SetStyle, :AddNameSpace, and :NameSpace to define the SOAP message. xRecvFile The optional parameter xRecvFile determines how the response content is saved. If xRecvFile is provided, then the content will be saved in a file (useful if the response is very large), otherwise it will be saved in the instance variable :HTTPResponse:Content.

The file where received data is saved can be specified as either a numeric handle as returned by FOpen() or FCreate(), or as a character string denoting the file name and path. NOTE: If a file handle is provided, then received data will be saved starting at the current file pointer offset. On return, the file pointer will be positioned on the last byte written to the file. If a file name is specified instead of a numeric file handle, then the file will be closed.

If this parameter is provided, then the response sent by the HTTP server will not be parsed. In this case the :Execute method will return a reference to an xbHTTPResponse object.

Example: oAgent := xbSOAPEnvelope():new()

oAgent:NameSpace := "urn:xmethods-CurrencyExchange"
oAgent:SetVar("Country1", "USA" )
oAgent:SetVar("Country2", "EURO")

// Execute request
oResult := oAgent:Execute("http://services.xmethods.net:80/soap", "getRate")
// Print exchange rate
? oResult:GetVar("Result")


xbSOAPEnvelope: object properties

:Action exported/character The name of the SOAP action or method contained within the Body of the SOAP envelope. All SOAP envelopes must have an action defined. :ActionNode exported/array A reference to the array containing the method or action node within the :XMLArray array. :CharacterEncoding exported/character The character encoding format used within XML document. Character encodings can be specified directly either within the XML header (using :CharacterEncoding) or within the HTTP content-type header (using :MimeType). If both properties are used to provide the character encoding format, they should match.

Example: oSoap:CharacterEncoding := "iso-8859-1"

/* produces a SOAP Envelope with following XML header */
<?xml version="1.0" encoding="iso-8859-1" ?>
:DeserializeResponse exported/logical Determines whether the content returned by the remote HTTP server is parsed and returned as a SOAP object. The default behaviour is to parse the response, however this can be disabled by setting this property to .F. When disabled, the :Execute method will return a reference to an xbHTTPResponse object rather than a reference to a response xbSOAPEnvelope instance. :Header exported/character The SOAP envelope header. The Header is an optional element that may be present in a SOAP message. If present, the element is the first immediate child element of a SOAP envelope (it is not part of the SOAP Body). Eg:

oSoap:Header := '<AuthHeader xmlns="http://ups.com/ShippingServer"><AuthToken>xYu0r28v6</AuthToken></AuthHeader>' :HeaderNode exported/array A reference to the array containing the Header node within the :XMLArray array. :MessageStyle exported/numeric Determines whether message is formatted using RPC or document style. The following options are possible:

SOAP_STYLE_RPC (the default)
RPC style implies that the SOAP Body contains an element with the name of the method or remote procedure being invoked. This element in turn contains an element for each parameter of that procedure.

SOAP_STYLE_DOCUMENT
Document style implies that the SOAP Body contains one or more child elements called parts. There are no SOAP formatting rules for what the Body contains; it contains whatever the sender and the receiver agree upon. :MimeType exported/character The MIME encoding type. By default it is set to "text/xml".

NOTE: If not explicitly specified, some SOAP servers (eg. Microsoft ASP .NET server) will assume that the XML SOAP message is encoded using the UTF-8 charset. A conversion problem will result on the remote server when the SOAP data contains ASCII characters > 127. This problem can be eliminated by specifying the codepage directly using the :MimeType property.

Example: oSoap := xbSOAPEnvelope():new()
oSoap:MimeType := "text/xml; charset=windows-1252"
oSoap:SetVar(...)
oSoap:Execute(...)
:NameSpace exported/character This is the namespace of the SOAP method. Some SOAP servers require a particular namespace to be specified when executing a method. The default is "http://xb2.net/soap". :Version exported/character The SOAP specification version number used to generate SOAP message structures and message exchange patterns. Among other things, this property determines the message MIME encoding type and document namespaces used within the SOAP envelope. Two versions are supported: "1.1" and "1.2". The default is "1.1". :XMLArray exported/array A reference to the root element containing an array of the parsed XML SOAP envelope.


xbComplexType

The xbComplexType class is used to represent complex data structures. Data structures can be nested, and may contain any other type, including an array. Instances of xbComplexType are typically used by the xbSOAPEnvelope and xbXMLDocument classes to serialize and deserialize complex data structures.

xbComplexType: class methods

:New([cName], [xAttrib], [oPayload]) → self Create a new instance of the xbComplexType class. Parameters: cName The name of the complex type. If not supplied, the default is "Struct". xAttrib Optional attribute associated with the complex type. When the complex type is used in a a SOAP envelope, xAttrib must be a character string that represents the complex type's XML attributes. oPayload This parameter is optional, if supplied it provides a reference to an xbPayload object to be used by :AddPayload().

Example: // set carton dimensions
oDim := xbComplexType():new("Dimensions")
oDim:SetVar("Length", nLen)
oDim:SetVar("Width" , nWidth)
oDim:SetVar("Height", nHeight)
oDim:SetVar("Units" , cUnits)

// define carton
oCarton := xbComplexType():New("carton")
oCarton:SetVar("Dimensions", oDim)
oCarton:SetVar("orderNumber", cHostOrder)
oCarton:SetVar("amount", nPrice)
oCarton:SetVar("weight", nWeight)
oCarton:SetVar("printerAddress", cTargetPrinter)
oCarton:SetVar("toteId", cTotLabel)

// call shipping system to rate package
oSoap := xbSOAPEnvelope():New()
oSoap:MimeType := "text/xml; charset=windows-1252"
oSoap:SetStyle(SOAP_STYLE_DOCUMENT)
oSoap:NameSpace := "http://www.xyzco.com/webservices/"
oSoap:SetVar("carton", oCarton)

oRet := oSoap:Execute("http://192.168.2.23","rateCarton","http://www.xyzco.com/webservices/rateCarton")
lSuccess := oRet:GetVar("rateCartonResult") == "1"

xbComplexType: object methods

:AddPayload( cName, xData, [nDataType], [cType], [nTypeType], [cID], [cOptions], [nPos], [cXMLAttrib] ) → cID Attach a payload. The payload can be a disk file, a character string, an object containing an :AsString() method, or any Xbase++ variable. The method returns a character string representing the payload identifier.

! An error will be raised if this method is used prior to providing a reference to the target xbPayload object. The target xbPayload object may be specified as a parameter to the object init method, or assigned to the :Payload instance variable. Parameters: cName The XML parameter name. xData The payload to attach. nDataType Optional numeric parameter indicating the data type of xData. If not provided, the payload data type will be inferred from the valtype of xData. If supplied, nDataType must be set to one of the following constants defined in Xb2NET.CH:

PL_DATA_NONE
There is no data. Attach an empty record.
PL_DATA_STRING
A literal character string.
PL_DATA_FILE
A disk file. In this case, xData can be specified as either a character string indicating the file name (including path) or a numeric file handle as returned by FOpen().
PL_DATA_OBJECT
An object having a :AsString() method and :MimeType property. The object's :AsString method is called during serialization with the result encoded as one payload record. A single parameter representing the payload ID is passed to the :AsString method when evaluated. The advantage of using an object vs. a literal character string is that the object may return dynamic content. A second advantage is better memory utilization in the case of multiple payloads. Assuming that the object generates some large content dynamically, system memory is utilized only when the specific payload record is serialized.
PL_DATA_CB
A codeblock whose return value is encoded as one payload record. A single parameter representing the payload ID is passed to the codeblock during serialization. if nTypeType is set to PL_TYPE_XBASE, then the return value of the codeblock may be any Xbase++ data type. Otherwise, the return value must be a literal character string. The advantage of using a codeblock vs. a literal character string is that a codeblock may return dynamic content. Another advantage is better memory utilization in the case of multiple payloads. If the codeblock generates some large content dynamically, system memory is utilized only when the specific payload record is serialized.
PL_DATA_XBASE
Xbase++ variable of any data type (object, codeblock, array, number, string, date, etc...). When received by another Xb2.NET application, the payload data is converted back into the same native Xbase++ data type. Use this type only when the payload recipient is another Xb2.NET application! cType An optional character string specifying the payload content type. This is either a MIME type or a URI reference. Examples:
"http://schemas.xmlsoap.org/soap/envelope/" (a URI reference)
"text/xml" (a MIME media-type) nTypeType Optional numeric parameter indicating the type of cType parameter. The default is PL_TYPE_UNKNOWN. If supplied, nTypeType must be set to one of the following constants defined in Xb2NET.CH:

PL_TYPE_MIME
cType is a MIME media-type, eg: "audio/mpeg"
PL_TYPE_URI
cType is an absolute URI. URIs can be used for message types that are not expected to be registered as media types or that do not map well onto the media type mechanism, eg: http://schemas.xmlsoap.org/rp/
PL_TYPE_UNKNOWN
The type is not known. This is the default.
PL_TYPE_NONE
There is no data. Attach an empty record.
PL_TYPE_XBASE
xData contains an Xbase++ value of any data type (object, codeblock, array, number, string, date, etc...). When received by another Xb2.NET application, the payload data is converted back into the same native Xbase++ data type. Use this type only when the payload recipient is another Xb2.NET application! cID Optional character string specifying a payload identifier. If not provided, a unique system generated ID will be used instead. This is the same ID value returned by the :AddPayload() method. cOptions Optional character string providing additional payload information that may be useful to the receiver. nPos Optional integer numeric value specifying the position of this payload relative to previously attached payloads. If not specified, the payload is appended to the previous payloads. To make this the first payload item, set nPos to 1. cXMLAttrib Optional character string allowing special XML tag attributes to be included with this XML parameter.

Example: // initialize SOAP envelope object
oSoap := xbSOAPEnvelope():new()
oSoap:SetStyle(SOAP_STYLE_DOCUMENT)
oSoap:Payload:SetFormat(PAYLOAD_MTOM)
// create "request" structure and provide reference to SOAP payload
oReq := xbComplexType():New()
oReq:Payload := oSoap:Payload
oReq:AddVar("EmailAddress", "test@gmail.com")
oReq:AddVar("FileName", "upload.txt")
oReq:AddPayload("FileData", "c:\upload\upload.txt", PL_DATA_FILE)
// add "request" structure to SOAP envelope
oSoap:AddVar("Request", oReq)
oResult := oSoap:Execute("http://live.xb2.net","EchoAll")
:AddVar(cName, xValue, [xAttrib]) Add a new variable xName, value xValue and optional attribute xAttrib to the data structure. This method does not check if the element with name cName already exists in the structure. It is therefore possible to add multiple elements with the same name. :GetVar([acName]) → xValue | aVarList | NIL Search the data structure and retrieve the first element's value matching acName. The parameter acName can be used in three ways:

If cName is NIL, then the method will return an array listing all elements as subarrays of {cName, xValue, xAttrib}.

If the parameter is a simple string, then the data structure is scanned for an element with the provided name. If none is found, the method returns NIL, otherwise the method returns the element's contents.

If the data structure contains a hierarchy of complex data types, then an array of strings representing a search path can be supplied for acName. If there is no match, the method returns NIL, otherwise the final element's value is returned.

Example: see: xbXMLDocument:GetVar()
:GetVarAttrib(cName) → cAttribute | NIL Retrieve an element's attribute. If the cName does not exist, the method returns NIL. :Reset([cName], [xAttrib]) → self Reinitialize object. For parameter information see :New(). :SetVar([xName], [xValue], [xAttrib]) → xPreviousValue | aPreviousVarList Assign the value xValue and optional attribute xAttrib to the first element with name xName. This method and can be used is several ways:

When xName and xValue are both NIL then empty the data structure.
When xValue is NIL, then delete the first element with name xName.
When xName is an array; replace the entire data structure with the passed array of {cName, xValue, xAttrib} elements.
Otherwise add or replace the value of an individual element xName.


xbComplexType: object properties

:Attrib exported/any data type Optional attribute associated with the complex type. When the complex type is used in a SOAP envelope, :Attrib must be a character string that represents the complex type's XML attributes. :Cargo exported/any data type Used to attach additional information to the object as required by the programmer. :Name exported/character The name of the complex type. :Payload exported/object Provides a reference to an optional xbPayload object. :VarList exported/array The data structure represented as an array of elements with the following format:
{{cName1, xValue1, xAttrib1}, {cName2, xValue2, xAttrib2},... }


xbForm

A Form is typically used by a client application in conjunction with an HTTP-POST method to send data to the server. It consists of name=value pairs encoded so that the form can be reliably disassembled into its individual components at the server end.

xbForm: class methods

:New([cEncodedFormString]) → self Create a new instance of the xbForm class and optionally parse an encoded form cEncodedFormString in order to retrieve the attached variables and data.

Example: oHttp := xbHTTPClient():new()
oHttp:Transport := VIA_WININET
oForm := xbForm():new()
oForm:SetVar("Action", "VIEW")
oForm:SetVar("FormID", cDocumentID)
oResp := oHttp:Execute("https://www.sterlingwebforms.com/webforms/scripts/inbox.asp",,oForm)
if oResp == NIL
    MsgBox("Error:" + str(oHttp:ErrorCode) + chr(10) + oHttp:ErrorMessage)
else
    DispHtml(oResp:Content)
endif

xbForm: object methods

:AsString() → cEncodedFormString Encode the form variables and data suitable for safe HTTP transport. :GetVar([cName]) → xValue | aVarList | NIL Retrieve a form variable. If cName is NIL, then the method will return an array listing all form variables as name/value pairs. :Parse(cEncodedFormString) → self Parse an encoded form cEncodedFormString, to separate the attached variables which can later be accessed using :GetVar. :Reset() → self Reinitialize object. :SetVar([xName], [cValue]) → xPreviousValue | aPreviousVarList Assign the value cValue to the form variable xName. This method and can be used is several ways:

When xName and cValue are both NIL then delete all form variables
When cValue is NIL, then remove the form variable xName
When xName is an array, replace all form variables with the passed array of name/value pairs
Otherwise add or replace the value of an individual form variable xName.


xbForm: object properties

:Cargo exported/any data type Used to attach additional information to the object as required by the programmer. :MimeType exported/character The MIME encoding type. It is set to: "application/x-www-form-urlencoded"


xbFTPClient

FTP (File Transfer Protocol) client provides methods for managing directories and files on a remote FTP or FTPS server. The class is fully compliant with RFC-959, RFC-2228 and RFC-4217. It provides support for AUTH TLS, AUTH SSL and Implicit SSL connections for control and data connections.

xbFTPClient: class methods

:New([oSSLContext]) → self Create a new instance of the xbFTPClient class. The optional parameter oSSLContext can be set to an instance of the xbSSLContext class in order to make the connection secure.

NOTE: The :Connect method will automatically create a secure connection when the target URL includes an FTPS scheme. The oSSLContext parameter is only needed when specific SSL/TLS properties need to be set (eg. client certificate, CA lists, cypher suites,...).

Example: oFtp := xbFTPClient():new()

if ! oFtp:Connect("ftps://thebatcave.com:1939")
  MsgBox("Failed to connect to FTP server!")
  Return
endif

if oFtp:Login("batman", "6otHam825")
  oFtp:GetFile("thejoker.doc")
else
  MsgBox("Login failed!")
endif

oFtp:Destroy()

xbFTPClient: object methods

Configuration / Life Cycle :Connect(xHostAddress, [nPort]) → lSuccess Establish connection with FTP server. The method returns .T. if the connection was successfully established.

By default, if an error occurs when attempting to establish a connection, the system will automatically retry connecting using the alternate address family (AF_INET / AF_INET6). This behaviour can be disabled by setting :TryAlternateAF to .F. Parameters: xHostAddress The address of the remote FTP server. It can be specified either as a numeric address in network byte order, an IP address in form of a dotted octet string (eg. '127.0.0.1') or a host name. In addition, the host, port and scheme (ftp or ftps) can be combined in standard URL format, eg: ftp://undergroundgarage.org:21. nPort The numeric port number of the remote FTP server. If not directly specified, the default port is 21 for FTP and 990 for FTPS when :ImplicitSSL is set to .T. :Close() → self Logout from FTP server and close all connections. :Destroy() → self Logout from FTP server, close all connections and release any system resources used by object. :RecvTimeout([nMilliSec]) → nTimeout Set maximum number of millisecs to wait when receiving data from the FTP server. The default value is zero, which refers to an infinite timeout. Any other setting is the timeout, in milliseconds. It is valid to set the timeout to any value, but values less than 500 milliseconds (half a second) are interpreted to be 500 milliseconds. When nMilliSec is not specified, the method will return the current setting. :SendTimeout([nMilliSec]) → nTimeout Set maximum number of millisecs to wait when sending data to FTP server. The default value is zero, which refers to an infinite timeout. Any other setting is the timeout, in milliseconds. It is valid to set the timeout to any value, but values less than 500 milliseconds (half a second) are interpreted to be 500 milliseconds. When nMilliSec is not specified, the method will return the current setting. :TryAlternateAF([lSet]) → lTryAlternateAF Determines is the system will automatically retry a failed connection using the alternate address family (AF_INET / AF_INET6). For example, if :AddrFamily is set to AF_INET6 however an IPv6 connection cannot be made, then the system will seamlessly switch to IPv4 and attempt the connection again. By default, this property is enabled (.T.). :SetCallBack([xCallBack]) → self Register an object or codeblock to receive callback events. If a callback has already been registered, it can be cancelled by setting xCallBack to NIL.

When xCallBack is provided as an object, the object must be inherited from the Xbase++ XbpPartHandler class. In this case, the xbFTPClient class will place events of type xbeP_xbFTPClient into the Xbase++ event queue. These events can be read (asynchronously) from the event queue by using the standard Xbase++ function AppEvent().

When xCallBack is provided as a codeblock, the user codeblock will be executed (synchronously) whenever an event occurs within the xbFTPClient instance. Example:

oFtp:SetCallBack( {|a,b|qout(a,b)} ) // codeblock executes synchronously

Two message parameters are provided to the AppEvent() function / user codeblock. The first parameter will be an integer numeric status code defined in Xb2NET.CH with the prefix FTP_ST_* or FTP_ERR_*, the second parameter will be a character string providing details of the event.

Example (asynchronous callback): oDlg := XbpDialog():New(AppDeskTop(), AppDeskTop(), {50,50}, {600,400})
oDlg:Title := "FTP Status"
oDlg:create()

oMLE := XbpMLE():new()
oMLE:WordWrap := .f.
oMLE:Editable := .f.
oMLE:Create(oDlg:drawingArea,,{0,0}, oDlg:drawingArea:CurrentSize())

// the file upload is executed in a separate thread
oFtpThread := Thread():New()
oFtpThread:Start("UploadFile", cServer, cUserID, cPassword, cFileName, oMLE)

nEvent := 0
while nEvent != xbeP_Close
    nEvent := AppEvent(@mp1, @mp2, @oXbp)
    if nEvent == xbeP_xbFTPClient
        // display FTP event in dialog window
        cText := var2char(mp1) + " " + var2char(mp2) + CRLF
        oMLE:Insert( Len(oMLE:GetData())+1, cText )
    else
        oXbp:handleEvent( nEvent, mp1, mp2 )
    endif
end

FUNCTION UploadFile(cServer, cUserID, cPassword, cFileName, xCallBack)
  Local oFtp, lSuccess
 
  oFtp := xbFTPClient():new()
  oFtp:SetCallBack(xCallBack)

  lSuccess := oFtp:Connect(cServer) ;
    .and. oFtp:Login(cUserID, cPassword) ;
    .and. oFtp:PutFile(cFileName)

  oFtp:Destroy()
  Return lSuccess
:SetDataPort([cIPAddress], [nPort]) → self Allows the programmer to explicitly specify the client's IP address when using standard data transfer (when :PassiveMode is .F.). This may be useful in cases where the server does not support passive mode and the FTP client is behind a router-based firewall.

If the client is behind a router-based firewall, then the router must be configured to forward incoming connections on nPort to the client. If nPort is not specified or is set to 0 (zero), then the router must be configured to forward to the client all incoming connections on ports 1024 to 5000.

To clear a previously specified data port, call SetDataPort with no parameters, eg:
oFtp:SetDataPort()
Parameters: cIPAddress A character string representing the FTP client's IP address. This address must be visible to the FTP server. nPort The numeric port number where the FTP client will be listening for a data connection. If not directly specified, the default value is 0 (zero), indicating that the client will choose a free port between 1024 and 5000.

Example: oFtp := xbFTPClient():new()
oFtp:SetDataPort("207.17.4.88", 5900)
:SetSSLContext([oSSLContext]) → self Designate an xbSSLContext object, oSSLContext to be used for secure communications with the FTP server. If oSSLContext is NIL or no parameter is supplied, then a current SSL/TLS connection (if there is one) will be shut down and its corresponding xbSSLContext will be detached from this xbFTPClient.

NOTE: The :Connect() method will automatically create a secure connection when the target URL includes an FTPS scheme. It is only necessary to call this method when specific SSL/TLS properties need to be set (eg. client certificate, CA lists, cypher suites,...). :SSLConnect([oSSLContext]) → lSuccess Initiate a SSL/TLS handshake with a connected FTP server. The client must already be connected to the server prior to calling this method. Under normal circumstances, it is not necessary to call this method for creating a secure connection since the :Connect method will do this automatically when either the target URL contains an FTPS scheme or an SSLContext is provided via :SetSSLContext.

Note that an FTP server will reset state information for a connected client after calling this method. For example, if the client was already logged in, it will be necessary to log in again.

oSSLContext is an optional parameter than can be set to an instance of the xbSSLContext class. This is only necessary if specific SSL/TLS properties need to be set, such as a client certificate, CA lists, cypher suites, etc.

The method will return .T. if an SSL/TLS connection has been successfully established with the FTP server. Otherwise, the method returns .F. FTP Control :CreateDirectory(cPath) → lSuccess Create a new directory on the FTP server. cPath is a character string that contains the name of the directory to create. The method returns .T. if successful, or .F. otherwise. :DeleteDirectory(cPath) → lSuccess Remove a directory path with the name cPath from the FTP server. The method returns .T. if the directory path was successfully deleted, or .F. otherwise. :DeleteFile(cFileName) → lSuccess Remove a file with the name cFileName from the FTP server. The method returns .T. if the file was successfully deleted, or .F. otherwise. :Directory([cPath],[cCommand]) → aDir | NIL Returns array of directory path information or NIL if an error occurs. The directory listing is returned as a one dimensional array of character strings with each array element representing one directory entry with file name, attributes and date/time information. The parameter cCommand may be used to specify the FTP command used to retrieve the directory listing, eg: 'LIST' (default), 'MLSD', 'NLSD'. :GetCurrentDirectory() → cPath | NIL Return the current directory path as a string or NIL if an error returns. :GetFile(cRemoteFile, [xLocalFile], [cDataType], [lAppend]) → lSuccess Download a file cRemoteFile from FTP server and save it locally with the name xLocalFile. The method returns .T. if the file was successfully retrieved. Parameters: cRemoteFile A character string name of the remote FTP server file to download. xLocalFile The file where received data is saved can be specified as either a numeric handle as returned by FOpen() or FCreate(), or as a character string denoting the file name and path. NOTE: If a file handle is provided, then received data will be written starting at the current file pointer offset (regardless of the value of lAppend). On return, the file will be left open and the file pointer will be positioned on the last byte written. If a file name is specified instead of a numeric handle, then the file will be closed. If xLocalFile is not provided, it defaults to cRemoteFile. cDataType By default, data will be received in binary mode. However, if the FTP server does not support binary transfer mode, then cDataType can be set to "A" to request data transfer in ASCII mode. Other data types supported by FTP include "I" for image (or binary), "E" for EBCDIC, and "L n" for local byte size (where n is the byte size). For additional information, please see the TYPE command in RFC959. lAppend An optional logical parameter that can be set to .T. in order to append received data to xLocalFile. When this parameter is NIL or .F., then any existing data will be overwritten. :GetResponse([nEventCode]) → lSuccess Get response message from FTP server. This method is used in conjunction with the :SendCommand() to fetch the FTP server's response. The method returns .T. if a response was received from the FTP server, and .F. otherwise. The received response string and corresponding three-digit status code are stored in the :Response and :ResponseCode instance variables. :Login([cUserID], [cPassword], [cAccount]) → lSuccess Login to FTP server. All parameters are optional character strings. If not supplied, the default cUserID is "anonymous", cPassword is a zero-length string and cAccount is "nul". :PutFile(xLocalFile, [cRemoteFile], [cDataType], [lAppend]) → lSuccess Upload a file xLocalFile to FTP server and store it under the name cRemoteFile. The method returns .T. if the file was successfully uploaded. Parameters: xLocalFile The file to be uploaded can be specified as either a numeric handle as returned by FOpen() or FCreate(), or as a character string denoting the file name and path. NOTE: If a file handle is specified, then data will be transmitted beginning at the current file pointer offset. To transmit the entire file make sure that the file pointer is set to the beginning of the file. If a numeric file handle is provided, then it is the responsibility of the calling routine to close the file once the method returns. cRemoteFile A character string name of the file on on the remote FTP server. If cRemoteFile is not provided, it defaults to xLocalFile. cDataType By default, data will be uploaded in binary mode. However, if the FTP server does not support binary transfer mode, then cDataType can be set to "A" to request data transfer in ASCII mode. Other data types supported by FTP include "I" for image (or binary), "E" for EBCDIC, and "L n" for local byte size (where n is the byte size). For additional information, please see the TYPE command in RFC959. lAppend An optional logical parameter that can be set to .T. in order to append transmitted data to cRemoteFile. When this parameter is NIL or .F., then the remote file if it exists, will be overwritten. :RenameFile(cFileName, cNewFileName) → lSuccess Rename a file stored on the FTP server. cFileName is the name of the file that will have its name changed on the remote server, and cNewFileName is the new name for the remote file. The method returns .T. if the file was successfully renamed. :SendCommand(cCommand) → lSuccess Send a command to FTP server. The method returns .T. if the command was successfully transmitted to the FTP server, and .F. otherwise. This method is provided as a means of executing special FTP commands not implemented by this class.

Example: oFtp:SendCommand("DELE index.htm")
oFtp:GetResponse()
? oFtp:Response
:SetCurrentDirectory([cPath]) → lSuccess Change to a different working directory on the FTP server. cPath is the name of the directory to change to on the remote system, if it is set to NIL, the working directory will be set to the parent directory. The method returns .T. if the working directory was successfully changed.


xbFTPClient: object properties

:Abort exported/logical Can be set to .T. in order to abort a data transfer that is currently in progress. The abort signal can be set from an external thread or from a callback codeblock specified in :SetCallBack(). :AddrFamily exported/numeric An address family, define constant AF_*. Defaults to AF_INET6 when the remote host name contains an IPv6 style numeric address, and AF_INET otherwise. :BytesTransferred exported/numeric Current number of bytes transferred. This property is continually updated while data transfer is in progress. :Cargo exported/any data type Used to attach additional information to the object as required by the programmer. :ElapsedTime readonly/numeric Number of seconds elapsed since start of data transfer. :ErrorCode exported/numeric Most recent FTP or WinSock error code. FTP error codes are defined in Xb2NET.CH with the prefix FTP_ERR_*. :ImplicitSSL exported/logical Determines how an SSL/TLS connection is established.

When set to .T., the :Connect method will automatically perform SSL/TLS negotiation during the connect phase (for control and all data connections). Although port 990 is registered with the IANA for this purpose, this method is not favoured by the IETF and is therefore not supported by many FTP servers.

The default value for this property is .F. meaning that as long as the FTP server supports it, an SSL/TLS secure connection can be negotiated any time after a normal connection is established. :PassiveMode exported/logical Determines whether the client or server initiates the data connection.

Normally, when a client connects to an FTP site, the server establishes the data connection back the client. However, if the server allows passive transfers, the client can establish the data connection. The default value for this property is .F., meaning that the client will wait for the server to establish a data connection.

? Passive mode may be required for clients who are behind some types of router-based firewalls or behind a gateway requiring passive transfers. :RecvBufferSize exported/numeric Specifies the buffer size to be used by the data socket for file downloads. The default value is defined by the function xbTcpWindowSize. :Response readonly/character The reply sent by remote FTP server in response to last command. :ResponseCode readonly/character A three-digit status code returned by remote FTP server in response to last command. :SecureDataChannel exported/logical Controls security level on the data connection.

When set to .T. (the default) and a secure control channel is established with the FTP server, then data channels will also be secured. Note that a FTP server need not necessarily support secure data connections even though it does support secure control connections. :SendBufferSize exported/numeric Specifies the buffer size to be used by the data socket for file uploads. The default value is defined by the function xbTcpWindowSize. :SSLContext readonly/object Reference to the xbSSLContext instance or NIL if no SSL context has been assigned. :SSLSessionReuse exported/logical Allows SSL/TLS session resumption on the data connection by reusing the same session as the control connection.

When set to .T. (the default) and a secure connection is required to the FTP server, the data connection will use the same SSL/TLS session as the control channel. This prevents session stealing attacks on the FTP server because both the data and control connections have the same session. Any mismatch in sessions indicates a potential attack. :Host readonly/character The host name or IP address of remote FTP server. :Port readonly/numeric The socket port number of remote FTP server.


xbJSON

This class provides methods for creating, parsing and modifying JSON strings.

xbJSON: class methods

:New( [cJSON] ) → self Create a new instance of the xbJSON class and optionally parse the JSON string cJSON.

xbJSON: object methods

:AddVar( cName, xValue ) → self Add a new variable cName with value xValue to the JSON object.

Example: oJ := xbJSON():new()
oJ:AddVar("sku","B00004YVB4")
oJ:AddVar("name","Victorinox Swiss Army Tinker Pocket Knife")
oJ:AddVar("price",28.59)

// create array to hold inventory locations
aData := {}
oStock := xbJSON():new()
oStock:AddVar("location","A1402A1")
oStock:AddVar("qty",44)
AAdd(aData, oStock)

oStock := xbJSON():new()
oStock:AddVar("location","B0524E2")
oStock:AddVar("qty",288)
AAdd(aData, oStock)

oJ:AddVar("inventory", aData)

? oJ:AsString()

/* output */
{"sku":"B00004YVB4","name":"Victorinox Swiss Army Tinker Pocket Knife","price":28.59,"inventory":[{"location":"A1402A1","qty":44},{"location":"B0524E2","qty":288}]}
:AsString() → cJSON Serialize object into JSON string. :GetVar( [xFind] ) → xValue | aVarList | NIL Retrieve a JSON element by name or index position. To find elements within a multi-level nested JSON structure, an array of search values must be provided (see example below). If the xFind parameter is not supplied the method returns the entire :VarList array. If the searched property is not found, the method returns NIL and the instance variable :Found will be .F.

! JSON elements can be null, so a NIL return value does not necessarily mean that the item was not found!

Example: TEXT INTO cTest TRIMMED
{
  "first_name" : "Bob",
  "last_name" : "Smith",
  "address" : [
    {
      "apt" : null,
      "number" : 32,
      "street" : "Cherry Blvd",
      "city" : "Albany",
      "state" : "NY",
      "zip" : "69381",
      "country" : "US" },
    {
      "apt" : 314,
      "number" : 140,
      "street" : "Townsgate Court",
      "city" : "Toronto",
      "state" : "ON",
      "zip" : "M5A 1E6",
      "country" : "CA" }
  ],
  "payment_methods" : {
    "paypal" : "b.smith@aol.com",
    "credit" : { "number":4583628404041741, "exp":"17/09" } }
}
ENDTEXT

oJ := xbJSON():new( cTest )
? oJ:GetVar("first_name"), oJ:found
? oJ:GetVar(2), oJ:found
? oJ:GetVar("paypal"), oJ:found
? oJ:GetVar({"payment_methods","paypal"}), oJ:found
? oJ:GetVar({"address",2,"city"}), oJ:found
? oJ:GetVar({3,2,6}), oJ:found
? oJ:GetVar({3,2,"zip"}), oJ:found
? oJ:GetVar({3,2,99}), oJ:found
? oJ:GetVar()

/* output */
Bob Y
Smith Y
NIL N
b.smith@aol.com Y
Toronto Y
M5A 1E6 Y
M5A 1E6 Y
NIL N
{{first_name, Bob}, {last_name, Smith}, {address, {xbJSON, xbJSON}}, {payment_methods, xbJSON}}
:Reset( [cJSON] ) → self Reinitialize the object and optionally parse the new JSON string cJSON. :SetVar( xFind, [xValue] ) → xOldValue | NIL Modify a JSON element by name or index position. This method works similar to :GetVar(), with the addition that if the element is found, its value will be changed to xValue. If found, the method returns the element's previous value. Otherwise, NIL is returned and the instance variable :Found will be .F.

Example: Using the cTest JSON string from the :GetVar() example above:

oJ := xbJSON():new( cTest )
? oJ:SetVar("first_name","Bobby"), oJ:found
? oJ:GetVar("first_name")
?
? oJ:SetVar({"payment_methods","credit","exp"},"20/09"), oJ:found
? oJ:GetVar({"payment_methods","credit","exp"})
?
// delete 2nd address
? aAddr := oJ:GetVar("address")
? oJ:SetVar("address", ASize(aAddr,1)), oJ:found
?
? oJ:GetVar()
?
? oJ:AsString()

/* output */
Bob Y
Bobby

17/09 Y
20/09

{xbJSON, xbJSON}
{xbJSON} Y

{{first_name, Bobby}, {last_name, Smith}, {address, {xbJSON}}, {payment_methods, xbJSON}}

{"first_name":"Bobby","last_name":"Smith","address":[{"apt":null,"number":32,"street":"Cherry Blvd","city":"Albany","state":"NY","zip":"69381","country":"US"}],"payment_methods":{"paypal":"b.smith@aol.com","credit":{"number":4583628402741745,"exp":"20/09"}}}


xbJSON: object properties

:Cargo exported/any data type Used to attach additional information to the object as required by the programmer. :Found exported/logical Indicates if the last call to :GetVar() or :SetVar() successfully located the JSON property that was searched. :MimeType exported/character The MIME encoding type. The default value is "application/json". :VarList exported/array An array of JSON name/value pairs in the following format: {{cName1, xVal1}, {cName2, xVal2}, ... }


xbPayload

Provides methods for serializing and deserializing attachments of any size (files, character strings, objects or any Xbase++ data) for transmission between an HTTP client and server. This class is also used by the xbSOAPEnvelope class for sending SOAP attachments.

xbPayload: class methods

:New() → self Create a new instance of the xbPayload class.

Example: FUNCTION ShipRequest()
Local oConn, oSock, oPL, cChunk, oData, cSQL, cRet

oSock := xbSocket():New()
if ! oSock:Connect("192.168.2.10",2002)
    oSock:destroy()
    Return .f.
endif

oPL := xbPayload():New()
// specify requested function in payload
oPL:Add("ShipOrders",PL_DATA_STRING,"http://xb2.net/payload/",PL_TYPE_URI)
// attach SQL resultset
cSQL := "SELECT * FROM Orders WHERE Completed=1 AND Shipped=0"
oConn := SQLConnection():new()
oConn:driverConnect(nil,"DSN=Sales;UID=shipping;PWD=99",SQL_DRIVER_NOPROMPT)
oData := oConn:DataSet(cSQL)
oData:Execute() // fetch data
oConn:Destroy() // close database connection
oPL:Add(oData,PL_DATA_XBASE,nil,nil,nil,cSQL)
// attach invoices as PDF documents (documents are generated dynamically during transmission)
while ! oData:Eof()
    oPL:Add({|cID|GenerateInvoice(cID)},,"application/pdf",PL_TYPE_MIME,oData:FieldGet("OrderID"))
    oData:Skip()
end

// transmit data
oPL:ClearState()
while (cChunk := oPL:Serialize()) != NIL
    if oSock:Send(cChunk) == SOCKET_ERROR
        oPL:ClearState()
        oSock:destroy()
        Return .f.
    endif
end
// all data sent, wait for response
cRet := oSock:RecvLine()
oSock:destroy()
Return cRet == "SUCCESS"

xbPayload: object methods

:Add( xData, [nDataType], [cType], [nTypeType], [cID], [cOptions], [nPos] ) → cID Attach a payload. The payload can be a disk file, a character string, an object containing an :AsString() method, or any Xbase++ variable. The method returns a character string representing the payload identifier. Parameters: xData The payload to attach. nDataType Optional numeric parameter indicating the data type of xData. If not provided, the payload data type will be inferred from the valtype of xData. If supplied, nDataType must be set to one of the following constants defined in Xb2NET.CH:

PL_DATA_NONE
There is no data. Attach an empty record.
PL_DATA_STRING
A literal character string.
PL_DATA_FILE
A disk file. In this case, xData can be specified as either a character string indicating the file name (including path) or a numeric file handle as returned by FOpen().
PL_DATA_OBJECT
An object having a :AsString() method and :MimeType property. The object's :AsString method is called during serialization with the result encoded as one payload record. A single parameter representing the payload ID is passed to the :AsString method when evaluated. The advantage of using an object vs. a literal character string is that the object may return dynamic content. A second advantage is better memory utilization in the case of multiple payloads. Assuming that the object generates some large content dynamically, system memory is utilized only when the specific payload record is serialized.
PL_DATA_CB
A codeblock whose return value is encoded as one payload record. A single parameter representing the payload ID is passed to the codeblock during serialization. if nTypeType is set to PL_TYPE_XBASE, then the return value of the codeblock may be any Xbase++ data type. Otherwise, the return value must be a literal character string. The advantage of using a codeblock vs. a literal character string is that a codeblock may return dynamic content. Another advantage is better memory utilization in the case of multiple payloads. If the codeblock generates some large content dynamically, system memory is utilized only when the specific payload record is serialized.
PL_DATA_XBASE
Xbase++ variable of any data type (object, codeblock, array, number, string, date, etc...). When received by another Xb2.NET application, the payload data is converted back into the same native Xbase++ data type. Use this type only when the payload recipient is another Xb2.NET application! cType An optional character string specifying the payload content type. This is either a MIME type or a URI reference. Examples:
"http://schemas.xmlsoap.org/soap/envelope/" (a URI reference)
"text/xml" (a MIME media-type) nTypeType Optional numeric parameter indicating the type of cType parameter. The default is PL_TYPE_UNKNOWN. If supplied, nTypeType must be set to one of the following constants defined in Xb2NET.CH:

PL_TYPE_MIME
cType is a MIME media-type, eg: "audio/mpeg"
PL_TYPE_URI
cType is an absolute URI. URIs can be used for message types that are not expected to be registered as media types or that do not map well onto the media type mechanism, eg: http://schemas.xmlsoap.org/rp/
PL_TYPE_UNKNOWN
The type is not known. This is the default.
PL_TYPE_NONE
There is no data. Attach an empty record.
PL_TYPE_XBASE
xData contains an Xbase++ value of any data type (object, codeblock, array, number, string, date, etc...). When received by another Xb2.NET application, the payload data is converted back into the same native Xbase++ data type. Use this type only when the payload recipient is another Xb2.NET application! cID Optional character string specifying a payload identifier. If not provided, a unique system generated ID will be used instead. This is the same ID value returned by the :Add() method. cOptions Optional character string providing additional payload information that may be useful to the receiver. nPos Optional integer numeric value specifying the position of this payload relative to previously attached payloads. If not specified, the payload is appended to the previous payloads. To make this the first payload item, set nPos to 1. :AsString() → cSerializedPayload Serialize the payloads as a single character string.

Warning: If the attachments are large, it is possible that this method will consume more memory than is available on the host system. Use, :Serialize() instead to process the payloads in smaller chunks. :ClearState() → self Reset serialization and deserialization state. :Deserialize( cBuffer, [nBytes] ) → nBytes Deserialize a payload stream. As the payload stream is sequentially parsed, references to the payloads are saved in the :List property. :Erase() → self Remove payload data from memory and erase any associated file(s) from disk. :GetPayload(xID) → xPayload, or;
:GetVar(xID) → xPayload
Retrieve a payload item by ID. The parameter xID represents the payload identifier and can be provided as a numeric or a character string. A numeric value corresponds to an index within the :List array of payloads. A character string corresponds to the PL_ID value of the desired payload.

The method returns NIL if the desired payload cannot be found. Otherwise the data type of the return value depends on the payload that was transmitted by the remote peer. For example, if the remote peer transmits a codeblock, the returned value will be a codeblock.

A data file transmitted by a remote peer may be returned as either a simple character string or as an xbStream object. Generally, if the file is larger than one :ChunkSize, then it will be saved to disk and an xbStream object will be returned providing a reference to the saved disk file. :Reset() → self Reinitialize object and clear payload list. :Serialize() → cPayloadChunk | NIL Serialize the payloads in successive chunks. The method returns NIL once all data has been serialized. :SetFormat(nFormat) → self Set payload serialization format. The parameter nFormat is an integer numeric value that specifies the serialization format using a symbolic constant with prefix PAYLOAD_*. The table below provides currently supported payload formats including associated MIME Content-Types and specification reference:

nFormatMIME Content-TypeReference
PAYLOAD_DIMEapplication/dime IETF Internet-Draft. Reference: draft-nielsen-dime-02. June 17, 2002; expires December 2002
PAYLOAD_MP_MIXEDmultipart/mixedRFC 2046, Section 5.1.3
PAYLOAD_MP_FORMDATAmultipart/form-dataRFC 2388
PAYLOAD_MP_RELATEDmultipart/relatedRFC 2387
PAYLOAD_XOPmultipart/related; type="application/xop+xml"; startinfo="text/xml"http://www.w3.org/TR/xop10/
PAYLOAD_MTOMmultipart/related; type="application/xop+xml"; startinfo="application/soap+xml"http://www.w3.org/TR/soap12-mtom/


xbPayload: object properties

:ChunkSize exported/numeric The maximum chunk size used for serializing files. The default value is 128 KB.

Normally, HTTP payloads are transmitted using chunked transfer encoding. Some servers however may not support this. To disable HTTP chunked transfer encoding, set :ChunkSize to NIL.
! By setting this property to NIL, the entire payload will be serialized in memory prior to transmission. This may not be desirable if the payload is very large! :Format readonly/numeric The payload serialization format. To change the serialization format, use :SetFormat() method. :List exported/array Provides a reference to a two dimensional array containing information about the payloads. The array columns can be identified using the following symbolic constants defined in Xb2NET.CH:

PL_ID
A character string containing the payload ID.
PL_DATA
The payload data; character string, object or file name.
PL_DATA_T
An integer indicating the data type of PL_DATA. The value is a reference to the symbolic constants with prefix PL_DATA_*.
PL_TYPE
A character string specifying the media-type or absolute-URI of payload.
PL_TYPE_T
An integer indicating the data type of PL_TYPE. The value is a reference to the symbolic constants with prefix PL_TYPE_*.
PL_OPTIONS
Character string providing optional information used by parser.
:MimeType exported/character The MIME encoding type. The default value is "application/dime".


xbSSLContext

Provides a context for implementing secure network communications using the OpenSSL library. An SSL context holds various data longer-lived than single SSL connections, such as SSL configuration options, certificate(s) and private key(s). It also manages a cache of SSL sessions for server-side sockets in order to speed up repeated connections from the same client. Once initialized, an xbSSLContext object can be attached to an xbSocket, xbServer, xbHTTPServer or xbSOAPEnvelope instance to provide secure communications. For more information about SSL/TLS, see the following document: SSL/TLS Frequently Asked Questions.

Initialization of an xbSSLContext object involves the following tasks:

Example: // define SSL context
oSSL := xbSSLContext():new( TLS_server_method )

oSSL:SetOptions(SSL_OP_CIPHER_SERVER_PREFERENCE) // use the server's cipher ordering preference, rather than the client's
oSSL:SetOptions(SSL_OP_ALL) // enable workarounds for various bugs present in other SSL implementations
oSSL:SetOptions(SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION) // disallow session resumption on renegotiation

// No request for a certificate is sent. Any certificate received will be verified but will not terminate the handshake in a failure.
oSSL:SetVerify(SSL_VERIFY_NONE)

// load cipher list, certificate, private key and DH parameters
do case
case !oSSL:SetCipherList("HIGH:-AES128:!LOW:!EXP:!CAMELLIA:!PSK:!SRP:!3DES:!DES:!MD5:!aNULL")
   cError := "Problem with cipher list"
case !oSSL:UseCertificateChainFile("MYCERT.PEM")
   cError := "Problem with certificate"
case !oSSL:UsePrivateKeyFile("MYKEY.PEM")
   cError := "Problem with private key"
case !oSSL:CheckPrivateKey()
   cError := "Private key does not match certificate public key!"
case !oSSL:LoadDHParams("DH2048.PEM")
   cError := "Problem loading DH params file"
endcase

// if no error then start HTTPS server, otherwise display message
if cError == NIL
   // attach SSL context to HTTP server instance and start server
   oHTTPS := xbHTTPServer():new(INADDR_ANY, 443, oSSL)
   oHTTPS:start()
else
   MsgBox("Unable to start HTTPS server - " + cError + chr(10) + xbSSLGetErrorString())
   oSSL:destroy()
endif

xbSSLContext: class methods

:New([nConnectMethod]) → self Creates a new instance of the xbSSLContext class that provides the framework to establish SSL/TLS enabled connections. The optional parameter, nConnectMethod is used to define the protocol to use when establishing a secure connection with a peer. Connection methods are provided for generic (client and server) use, server only, and client only use. The following constants, defined in Xb2NET.CH, can be used to specify the nConnectMethod type to use (the default is TLS_method):

TCP connection-oriented sockets (SOCK_STREAM)

UDP datagram sockets (SOCK_DGRAM)

! Instantiating the xbSSLContext class allocates system resources that must later be released by calling :Destroy() once the object is no longer needed. A runtime error is raised if the security provider cannot be successfully initialized.

xbSSLContext: class properties

:Version readonly/array An array of OpenSSL library version information with following elements:

SSLEAY_VERSION - The OpenSSL library version number and release date, eg: "OpenSSL 3.0.7 1 Nov 2022"
SSLEAY_CFLAGS - The compiler flags set for the compilation process in the form [compiler: ...] if available or [compiler: information not available] otherwise.
SSLEAY_BUILT_ON - The date of the build process in the form [built on: ...] if available or [built on: date not available] otherwise.
SSLEAY_PLATFORM - The target of the library build in the form [platform: ...] if available or [platform: information not available] otherwise.
SSLEAY_DIR - The default OpenSSL directory in the form [OPENSSLDIR: "..."] if available or [OPENSSLDIR: N/A] otherwise.

xbSSLContext: object methods

Life Cycle :Destroy() → self Release system resources that have been allocated by this xbSSLContext instance. SSL/TLS Options :GenerateRSAKey([nKeyLength]) → lSuccess Generate a temporary RSA key for use by the SSL context. nKeyLength is an optional parameter that specifies the size of the key to be generated in bits and must be a multiple of 16. The default is 1024-bits. If successful, the method returns .T. :LoadDHParams(cFileName) → lSuccess Load the file with the Diffie-Hellman (DH) parameters to be used for ephemeral keying. If successful, the method returns .T.

Ephemeral keying involves generating temporary session keys in such a way that only the two parties involved in the communication can obtain them. After the session is complete, and both parties destroy the session keys, the only way to decrypt the communication is to break the session keys themselves. This feature is known as forward secrecy because breaking session keys is much more difficult than obtaining the server's private key. Furthermore, in order to decrypt all communication one must break the session keys for each individual conversation.

With forward secrecy, if an attacker gets a hold of the server's private key, it will not be able to decrypt past communications. The private key is only used to sign the DH handshake, which does not reveal the session key. DH ensures that session keys never leave the client or server and therefore cannot be intercepted by a MITM.

! Ephemeral keying requires the TLS server to designate appropriate 'parameters' consisting of a suitably-large prime and a corresponding element called a 'generator'. Since generating large primes is computationally intensive, these parameters can be generated off-line and stored in a file. It is strongly recommended that each server use its own unique DH parameters!

The following command uses the OPENSSL.EXE command line utility to generate a 2048-bit DH parameter file called "dh2048.pem":

openssl dhparam -out dh2048.pem 2048
:SetECDHCurve([nCurveName]) → lSuccess Load Elliptic Curve to be used for Diffie-Hellman ephemeral keying. The optional parameter nCurveName is an integer numeric value corresponding to an elliptic curve name defined in Xb2NET.CH with the prefix NID_X9_62*, NID_secp*, NID_sect*, NID_wap_wsg_idm* and NID_uacurve*

? By default, the xbSSLContext will automatically select the most appropriate curve to be used for ECDH temporary key exchange. Therefore, calling this method is not neccesary unless the programmer wishes to set a specific elliptic curve used for ephemeral keying. If the curve is loaded successfully, the method returns .T.

Please see section under LoadDHParams() for additional information concerning ephemeral keying and forward secrecy. :SetCipherList([cCipherList]) → lSuccess A cipher suite is a set of algorithms that SSL/TLS uses to secure a connection. A variety of algorithms and cipher suites are provided by OpenSSL, however when designing secure applications, it is essential that algorithms having known security vulnerabilities not be allowed. This method is used to set the preference and order of ciphers when negotiating connections for SSL and TLSv1.2 (and below).

!Due to major differences between the way ciphersuites for TLSv1.2 (and below) and ciphersuites for TLSv1.3 work, they are configured differently. For TLSv1.3, ciphersuites may be configured using the :SetCipherSuites() method. Changing the TLSv1.2 and below cipher list has no impact on the TLSv1.3 ciphersuite configuration!

The list of ciphers is specified by a specially formatted string, cCipherList containing a colon-delimited list of algorithms or alias tags:
OpenSSL Cipher Specification Tags
Tag Description
Key Exchange Algorithm:
kRSA, RSARSA key exchange
kDHrDiffie-Hellman key exchange and certificates signed by CAs with RSA keys
kDHdDiffie-Hellman key exchange and certificates signed by CAs with DSS keys
kDHCombination of kDHr + kDHd
kEDHEphemeral (temp key) Diffie-Hellman key exchange
kECDHrECDH cert, signed with RSA keys
kECDHeECDH cert, signed with ECDSA keys
kECDHCombination of kECDHr + kECDHe
kEECDHEphemeral Elliptic Curve Diffie-Hellman
kSRPSecure Remote Password (SRP) key exchange
kPSKPre-shared key
DH All ciphers using Diffie-Hellman (DH) key exchange, including anonymous, ephemeral and fixed DH
ADHAll anonymous DH cipher suites, not including the ECDH suites (insecure)
EDHAll non-anonymous ciphers using ephemeral DH key exchange, not including the ECDH suites
ECDHAll ciphers using Elliptic Curve Diffie-Hellman (ECDH) key exchange, including anonymous, ephemeral and fixed ECDH
AECDHAll anonymous ECDH cipher suites (insecure)
EECDHAll non-anonymous ciphers using ephemeral ECDH key exchange
Authentication Algorithm:
aDHCipher suites using DH authentication (the certificates carry DH keys)
aDSS, DSSCipher suites using DSS authentication (the certificates carry DSS keys)
aECDHCipher suites using ECDH authentication (the certificates carry ECDH keys)
aECDSA, ECDSACipher suites using ECDSA authentication (the certificates carry ECDSA keys)
aNULLThe cipher suites offering no authentication. This is currently the anonymous DH algorithm and SRP. These cipher suites are vulnerable to a "man in the middle" attack and so their use is normally discouraged.
aRSARSA authentication (the certificates carry RSS keys)
PSKCipher suites using Pre-Shared Key authentication
SRPCipher suites using Secure Remote Password (SRP) authentication
Cipher Encoding Algorithm:
eNULL, NULLAll ciphers using no encryption. Because these offer no encryption at all and are a security risk they are disabled unless explicitly included.
AES128AES 128-bit block cipher with 128-bit key size
AES256AES 128-bit block cipher with 256-bit key size
AESAES 128-bit block cipher with 128 or 256-bit key size
AESGCMAES in Galois Counter Mode (GCM) - only supported in TLSv1.2
CAMELLIA128CAMELLIA 128-bit block cipher with 128-bit key size
CAMELLIA256CAMELLIA 128-bit block cipher with 256-bit key size
CAMELLIACAMELLIA 128-bit block cipher with 128 or 256-bit key size
DESDES encryption (not including triple-DES) using 64-bit block size and 56-bit key size (obsolete and insecure)
3DESTriple-DES encryption using 64-bit block size
IDEAIDEA 64-bit block cipher with 128-bit key size
SEEDSEED 128-bit block cipher with 128-bit key size
RC2RC2 64-bit block cipher with a variable size key (obsolete and insecure)
RC4RC4 stream cipher (insecure)
MAC Digest Algorithm:
MD5MD5 hash function (128 bit - obsolete and insecure)
SHA1, SHASHA hash function (160 bit)
SHA256SHA hash function (256 bit)
SHA384SHA hash function (384 bit)
Aliases:
ALLAll ciphers suites except the eNULL ciphers which must be explicitly enabled
LOWAll ciphers with 64 or 56 bit encryption, but excluding export cipher suites
MEDIUMAll ciphers with 128 bit encryption
HIGHAll ciphers with greater than 128 bit encryption, and some cipher suites with 128-bit keys
EXP, EXPORTAll export ciphers, including 40 and 56 bit algorithms
TLSv1.2, TLSv1, SSLv3TLS v1.2, TLS v1.0 or SSL v3.0 cipher suites respectively (there are no ciphersuites specific to TLSv1.1)
Special Keywords:
@STRENGTHsort the list of ciphers by their strength (key size) in order of highest to lowest. It should be specified last on the list.
These tags can be joined together into a colon-delimited string to specify the order of ciphers that will be used when negotiating an SSL/TLS connection. To simplify this, there are also aliases (SSLv3, EXP, LOW, MEDIUM, HIGH) for certain groups of ciphers. These tags can be joined together with prefixes to form the cCipherList. Available prefixes are:
Prefix   Description
add cipher to list
+add ciphers to list and pull them to current location in list
-remove cipher from list (can be added later again)
!remove cipher from list completely (can not be added later again)
If not supplied, the default value for cCipherList is "ALL:!ADH:!LOW:!EXP:!MD5:!eNULL:@STRENGTH"

? The OPENSSL.EXE command line utility can be used as a test tool to determine the appropriate cipherlist. It will convert OpenSSL cipher lists into ordered SSL cipher preference lists. To do this, type the following in a command prompt window:

    openssl ciphers -v [cipherlist]

where [cipherlist] is the cipher list specification, eg:
    openssl ciphers -v "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH"
:SetCipherSuites([cCipherSuites]) → lSuccess This method defines the set of acceptable cipher suites used when negotiating TLS v1.3 connections. The list of ciphers is specified by a specially formatted string, cCipherSuites containing a colon-delimited list of algorithms (ordered by preference). If no list is provided, it defaults to: "TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256"
List of TLS v1.3 cipher suites
TLS_AES_256_GCM_SHA384
TLS_CHACHA20_POLY1305_SHA256
TLS_AES_128_GCM_SHA256
TLS_AES_128_CCM_8_SHA256
TLS_AES_128_CCM_SHA256
:SetOptions(nOptions) → nNewOptions This method is used to provide fine-grained control over the SSL/TLS connections spawned from this context. It affects the (external) protocol behavior of the SSL library. Changes to a SSL context do not affect already created SSL connections.

The parameter nOptions is a set of SSL_OP_* flags that can be combined by summing individual flags together. Once an option is set, it cannot be cleared. This method only adds the options presented to the set of options already contained in this context. The method returns the new set of options. The following bug workaround options are available:
Option Name SSL_OP_ALL Description
SSL_OP_CRYPTOPRO_TLSEXT_BUG Adds a ServerHello TLSEXT when using a GOST cipher.
SSL_OP_DONT_INSERT_EMPTY_FRAGMENTSDisables a countermeasure against a SSL 3.0/TLS 1.0 protocol vulnerability affecting CBC ciphers, which cannot be handled by some broken (Microsoft) SSL implementations.
SSL_OP_LEGACY_SERVER_CONNECTAllow legacy insecure renegotiation between OpenSSL and unpatched servers only.
SSL_OP_TLSEXT_PADDINGAdds a padding extension to ensure the ClientHello size is never between 256 and 511 bytes in length.
SSL_OP_SAFARI_ECDHE_ECDSA_BUGDon't prefer ECDHE-ECDSA ciphers when the client appears to be Safari on OS X. OS X 10.8...10.8.3 has broken support for ECDHE-ECDSA ciphers.
SSL_OP_ALLAll of the above bug workarounds. It is usually safe to use SSL_OP_ALL to enable the bug workaround options if compatibility with somewhat broken implementations is desired.
SSL_OP_ALLOW_NO_DHE_KEXIn TLSv1.3 allow a non-(EC)DHE-based key exchange mode.
SSL_OP_CIPHER_SERVER_PREFERENCESet on servers to choose the cipher according to the server's preferences.
SSL_OP_NO_COMPRESSIONDon't use compression even if supported.
SSL_OP_NO_SSLv2Do not use the SSLv2 protocol (deprecated - SSLv2 is disabled by default).
SSL_OP_NO_SSLv3Do not use the SSLv3 protocol.
SSL_OP_NO_TLSv1Do not use the TLSv1 protocol.
SSL_OP_NO_TLSv1_1Do not use the TLSv1.1 protocol.
SSL_OP_NO_TLSv1_2Do not use the TLSv1.2 protocol.
SSL_OP_NO_TLSv1_3Do not use the TLSv1.3 protocol.
SSL_OP_NO_RENEGOTIATION Disallow all renegotiation.
SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATIONWhen performing renegotiation as a server, always start a new session (i.e., session resumption requests are only accepted in the initial handshake). This option is not needed for clients.
SSL_OP_SINGLE_DH_USEAlways create a new key when using temporary/ephemeral DH parameters. As of OpenSSL 1.0.2f single-DH key use is always on, and this option does nothing.
SSL_OP_SINGLE_ECDH_USEDo not reuse a ECDH key for different SSL sessions. As of OpenSSL 1.1.0 single-ECDH key use is always on, and this option does nothing.
SSL_OP_TLS_ROLLBACK_BUGAllow a client to specify SSLv3.0 in the pre-master secret even if TLSv1.0 was specified in the ClientHello.
Certificate Management :CheckPrivateKey() → lSuccess Verify that the private key agrees with the corresponding public key in the loaded certificate. Both the certificate and private key must have already been loaded prior to calling this method. The method returns TRUE if successful. The following are the most likely causes of errors (check the error stack by calling xbSSLGetLastError() to find out the reason):

:isCertificateFileStale() → lChanged Method returns .T. when a new version of a previously loaded certificate file is available. :SetDefaultPassword(cPassword) → self Set the password that will be used to access data in a private key file that is in PEM (base64 encoded) format. Other items in PEM formatting (certificates) can also be encrypted, it is however not usual, as certificate information is considered public. :UseCertificateFile(cFileName, [nType]) → lSuccess Loads the first certificate stored in file cFileName into memory. The formatting type of the certificate file can be specified in the second parameter nType. Two types of file formats are supported; SSL_FILETYPE_PEM (the default) and SSL_FILETYPE_ASN1. Files of type SSL_FILETYPE_ASN1 (also known as DER, binary encoding) can only contain one certificate or private key. Files of type SSL_FILETYPE_PEM can contain more than one item.

The method returns TRUE if successful. The following are the most likely causes of errors:

If a chain of certificates is required rather than just one certificate, then use the :UseCertificateChainFile() method instead. :UseCertificateChainFile(cFile) → lSuccess Read a file that contains the certificate in PEM (base64 encoded) format, possibly followed by a sequence of CA certificates that should be sent to the peer in the certificate message. The certificates must be sorted starting with the certificate for your application, followed by intermediate CA certificates if applicable, and ending at the highest level (root) CA. The method returns TRUE if successful. The following are the most likely causes of errors:

The entire list of certificates is passed to the remote node during the SSL/TLS handshake. If only one certificate is needed rather than a chain of certificates, then it is better to use the :UseCertificateFile() method instead. :UsePKCS12File(cPfxFile, cPassPhrase, [lAddExtraChainCerts]) → lSuccess The PKCS#12 (aka PFX key storage) standard specifies a format for secure transportation of user identity information. This can be any sort of information, including certificates, passwords, and even portable keys. Many applications, including commonly used web browsers use PKCS#12 formatted credentials. Parameters: cPfxFile A character string containing the name (including path) of the PKCS#12 formatted file. If exported from Microsoft Internet Explorer, this file will typically have a .PFX extension. cPassPhrase A character string containing the password phrase under which the file was protected. lAddExtraChainCerts This is an optional logical parameter that determines whether additional certificates contained within the PKCS#12 file are added to the certificate chain. The default is to discard any additional certificates, however by setting this parameter to TRUE, any additional certificates contained within the file will be added to the certificate chain. :UsePrivateKeyFile(cFileName) → lSuccess Add the first private key found in file cFileName to the context object. The private key file must be in PEM (base64 encoded) format. If it is encrypted, then the password must be specified by calling :SetDefaultPassword() prior to calling this method

The method returns TRUE if successful. The following are the most likely causes of errors (check the error stack by calling xbSSLGetLastError() to find out the reason):

Peer Authentication :LoadVerifyLocations([cCAFileName], [cCAPathName]) → lSuccess Verifying a certificate's authenticity requires that the verifying agent have a list of Certification Authorities (CAs) that it trusts. This method is used to provide the application with such a list in order for it to verify the peer. Parameters: cCAFileName The name of the file containing CA certificates in PEM (base64 encoded) format. More than one CA certificate may be present in the file. cCAPathName The name of a directory containing CA certificates in PEM (base64 encoded) format. Each file in the directory must contain only a single CA certificate and the files must be named by the subject name's hash and an extension of ".0". If more than one CA certificate with the same name hash value exist, the extension must be different (e.g. 9d66eef0.0, 9d66eef0.1 etc).

The method must be called with either the first or second parameter as NIL, but not both. An important difference between file and directory storage is the time when the certificates get loaded. With a flat file, the file is parsed and certificates loaded during the call to this method. However, with a directory, certificates are read only when needed, that is during the verification phase that occurs during the SSL/TLS handshake.

The method returns TRUE if successful. It may fail if both parameters are NIL or processing at one of the locations specified failed. Check the error stack by calling xbSSLGetLastError() to find out the reason. :SetVerify(nVerifyType) → self This method is used to control how certificates and requests are handled during a SSL/TLS handshake. The parameter nVerifyType is used to specify the type of verification to perform on the peer's certificate. The following flags are provided for this purpose:

:SetVerifyDepth(nDepth) → self This method is used to set the maximum allowable depth for peer authentication. In other words, it limits the number of certificates that will be verified in order to ensure the chain is trusted. For example, if the depth was set to 4 and 6 certificates are present in the chain to reach the trusted certificate, the verification would fail because the required depth would be too great. Setting the depth to zero allows chains of unlimited length to be used. The default depth limit is 9, allowing for the peer certificate and additional 9 CA certificates. :GetVerifyDepth() → nDepth Returns the verification depth limit currently set in this SSL context as an integer numeric value. If no limit has been explicitly set, -1 is returned and the default value will be used.


xbSSLContext: object properties

:Cargo exported/any data type Used to attach additional information to the object as required by the programmer. :ConnectMethod readonly/numeric Reference to TLS_* connect method used at object initialization. :Handle readonly/numeric Numeric context descriptor as used by OpenSSL. :SNI exported/logical This property is used for client-side SNI (Server Name Indication). It determines whether the host name is transmitted to a server prior to initiating the SSL/TLS handshake. By default, client-side SNI is enabled. The client will transmit the host name of the server it wishes to connect to before a secure connection is established. This allows a server supporting multiple host names to respond with an appropriate certificate. The host name is derived from the connection URI when the host is not provided in dotted-decimal IP format. To disable this functionality, set this property to .F.


xbSession

This class simplifies session management by providing the ability of saving persistent data across multiple HTTP requests. The data managed by a session is stored in memory and will therefore only persist as long as the application is active. See state management for additional information on managing sessions within an xbHTTPServer.

xbSession: class methods

:New() → self Creates a new instance of the xbSession class. :ActiveSessions() → nActiveSessionCount Return a count of the number of currently active sessions. :GetOpenSessions() → aSessionList Returns a list of currently active sessions. The value returned is a one-dimensional array where each element contains a reference to an xbSession object. :KeepAlive(cHandle) → lSuccess Find the session with the given session handle cHandle and reset its idle time to zero in order to make it look active. The method returns .T. if the session was found and updated, otherwise it returns .F. :Open(cHandle) → oSession Find the session with the given cHandle session handle and return a reference to it. If a session with this handle does not exist, then a new session is created. :RestoreSessions([cFileName]) → lSuccess Restore session data that was previously saved using :SaveSessions. If not specified, cFileName defaults to "xb2session.bin". The method returns .T. if session data was successfully restored. :SaveSessions([cFileName]) → lSuccess Create a snapshot of all session data and save it to a file. If not specified, cFileName defaults to "xb2session.bin". Session data may later be restored by using the class method :RestoreSessions. The method returns .T. if session data was successfully saved. :SweepSessions(nMaxIdleTime, [bOnDelete]) → nDeleted Remove sessions (including data stored by those sessions) that have been idle for more than nMaxIdleTime minutes. An optional codeblock bOnDelete can be provided which will be executed once for each session that is deleted from memory. When executed, one parameter is passed to the codeblock; a reference to the array containing the terminated session's data. The method returns a count of the number of expired sessions which have been purged.

xbSession: class properties

:LastSweep exported/numeric The time in seconds after midnight when the last :SweepSessions was performed. :MaxSessions exported/numeric Maximum number of concurrent session objects maintained in memory. The default value is 500, but this can be changed at any time.

xbSession: object methods

:Close([bOnDelete]) → self Remove this session from the session manager and release all data maintained by it. An optional codeblock bOnDelete can be provided which will be executed just before the session data is deleted from memory. When executed, one parameter is passed to the codeblock; a reference to the array containing this session's data. :GetCargo([cName]) → xValue | aVarList | NIL, or
:GetVar([cName]) → xValue | aVarList | NIL
Retrieve a named state variable previously saved with :SetCargo. If a parameter is not supplied or if cName is NIL, then the method will return an array of all name/value pairs saved in the current session object. :SetCargo([xName], [xValue]) → xPreviousValue | aPreviousVarList, or
:SetVar([xName], [xValue]) → xPreviousValue | aPreviousVarList
Store the value xValue using a symbolic character name xName until the session is closed. This method is quite flexible and can be used is several ways:

When xName and xValue are both NIL then delete all state variables (session is not closed)
When xValue is NIL, state variable with the name xName is deleted
When xName is an array, replace all name/value pairs with passed array
Otherwise add/replace value
:MinutesIdle() → nMinutesIdle Returns the number of minutes that this session has been idle. :UpTime() → {nDays, nHrs, nMin, nSec} Returns a one dimensional array specifying amount of time the session has been open. The following array constants available in Xb2NET.CH provide access to the individual array elements:

UPTIME_DAY - number of days
UPTIME_HRS - number of hours
UPTIME_MIN - number of minutes
UPTIME_SEC - number of seconds


xbSession: object properties

:Cargo exported/any data type Used to attach additional information to the object as required by the programmer. :Handle exported/character a unique character string representing the session ID. :DateStarted readonly/date Date session was created. :TimeStarted readonly/numeric Time session was created (seconds after midnight).


xbStream

Provides generic methods for reading and writing to data stream files.

xbStream: class methods

:New(xFile) → self Create a new instance of the xbStream class. The parameter xFile provides a reference to the target data stream file. It may be specified as a character string containing the name of the target file with drive and path information, or as an integer numeric value providing the operating system file handle of an open data stream file.

Note: If a file handle is provided instead of a file name, then :Read() and :Write() will commence at current file pointer offset. In addition, when the object is initialized with a file handle, the :Close() method may not be used to close the file, it must be closed by the calling routine.

xbStream: object methods

:AsString() → cString Return contents of entire data stream as a character string.

Warning: If the data stream is very large, it is possible that this method will consume more memory than is available on the host system. Use, :Read() instead to process the stream in smaller chunks. :Close() → lSuccess Close the underlying data file containing data stream. The method returns .T. (true) when the underlying data file was closed successfully, otherwise it returns .F. (false).

Note: The underlying file will only be closed if it was originally opened via the :Open() or :Create() methods. If the data file was opened externally such that the xbStream object was initialized by providing a file handle, then it may not be closed via this method. :Create([nAttribute]) → nHandle | -1 Create a data stream file referenced in the :Name property and open it for write access. If the xbStream object was initialized by providing a file handle, so that the target file name is unknown, then a new file will not be created. The optional nAttribute parameter is an integer numeric value which sets the access mode for the file. If supplied, nAttribute must be set to one of the following constants defined in FILEIO.CH:

FC_NORMAL - Creates file with read and write access (the default).
FC_READONLY - Creates file with read access.
FC_HIDDEN - Creates hidden file.
FC_SYSTEM - Creates system file.

The method returns an integer numeric value representing the file handle provided by the operating system. If the file could not be created, then the method returns -1. The nature of the error can be determined by calling the standard Xbase++ function FError(). :Erase() → lSuccess Close and delete the underlying data file containing data stream. The method returns .T. (true) when the underlying data file was deleted successfully, otherwise it returns .F. (false).

Note: The underlying file will only be deleted if it was originally opened via the :Open() or :Create() methods. If the data file was opened externally such that the xbStream object was initialized by providing a file handle, then it may not be erased via this method. :GetName() → cFileName | NIL Returns disk file name (excluding drive and path information) containing data stream. The method will return NIL if the file name is unknown. The complete file name with drive and path information is stored in the :Name ivar. :GetSize() → nSize Returns total size in bytes of data stream file. :Open([nMode]) → nHandle | -1 Open the data stream file referenced by the :Name property. The target file may also be opened externally and manipulated using xbStream methods by supplying a file handle to the init method. If opened externally, the file must also be closed externally.

The optional nMode parameter is an integer numeric value that provides the mode for data access. If not supplied, the file is opened in "read-only" and "shared" mode. Symbolic constants providing possible values for nMode are defined in FILEIO.CH with prefix FO_*. For additional information, please consult the Xbase++ documentation for function FOpen().

The method returns an integer numeric value representing the file handle provided by the operating system. If the file could not be opened, then the method returns -1. The nature of the error can be determined by calling the standard Xbase++ function FError(). :Read(@cBuffer, [nBytes]) → nBytesRead Read nBytes from data stream into cBuffer, a pre-sized character string that is passed by reference. The parameter nBytes is an optional integer numeric value that determines the number of bytes to read. If it is supplied it must be smaller than or equal to the size of cBuffer. If not provided, nBytes defaults to the size of cBuffer.

The method returns the actual number of bytes that were read from the data stream. The return value should be the same as nBytes. If it is less than nBytes then either an error occurred or the end of the data stream has been reached. The nature of the error can be determined by calling the standard Xbase++ function FError(). :Write(cBuffer, [nBytes]) → nBytesWritten Write a character string from cBuffer into the data stream. nBytes is an optional integer numeric value that determines the number of characters written into the data stream from cBuffer. If nBytes is not provided, the entire contents of cBuffer are written to the data stream.

The method returns an integer numeric value indicating the number of bytes actually written into the data stream. A return value that is less than nBytes indicates that an error occurred during the write operation. The nature of the error can be determined by calling the standard Xbase++ function FError().


xbStream: object properties

:BytesRead readonly/numeric A cumulative total of number of bytes read from the data stream. :BytesWritten readonly/numeric A cumulative total of number of bytes written to the data stream. :Cargo exported/any data type Used to attach additional information to the object as required by the programmer. :Handle exported/numeric An integer numeric value representing the file handle provided by the operating system for the open data stream. :MimeType exported/character The MIME encoding type of the data stream. :Name exported/character The data stream disk file name including drive and path. If the xbStream object was initialized by providing a target file handle, then the name of the underlying file will be unknown. :Options exported/character A character string providing optional information about the data stream. For example, if the data stream was transmitted as a MIME payload, then this property may include information such as content description, encoding information and content disposition.


xbTLog

Class for logging client requests using Extended Log File Format (W3C Working Draft WD-logfile-960323). This log format is compatible with Microsoft Internet Information Server (IIS) and is supported by many third party web log analyzers. The Microsoft LogParser Tool may be used to generate visual charts and reports from the raw log files.

xbTLog: class methods

:New([cSoftware], [nTimePeriod], [nFields], [cFilePrefix]) → self Create a new instance of the xbTLog class. All parameters are optional. Parameters: cSoftware On optional character string that is used to identify the software which generated the log. If not provided, the value of xbHTTPServer():ServerName will be used instead. nTimePeriod Optional numeric value specifying the time period when a new log file is created. The following options are possible:

TLOG_HOURLY - Log files are created hourly
TLOG_DAILY - Log files are created daily starting with the first entry that occurs after midnight.
TLOG_WEEKLY - Log files are created weekly starting with the first entry that occurs after midnight Saturday.
TLOG_MONTHLY - Log files are created monthly starting with the first entry that occurs after midnight of the last day of the month.
TLOG_UNLIMITED - Data is always appended to the same log file.

If not specified the default is TLOG_DAILY. For more information see :TimePeriod in the object properties section below. nFields Optional set of bitmap flags specifying the information to be recorded in each log entry. The flags are defined in Xb2NET.CH with the prefix EXLOG_* and can be added together to define the set of fields to be recorded. For more information see :Fields in the object properties section below.

If not specified, nFields defaults to:
EXLOG_TIME + EXLOG_C_IP + EXLOG_CS_METHOD + EXLOG_CS_URI_STEM + EXLOG_CS_URI_QUERY + EXLOG_SC_STATUS + EXLOG_SC_BYTES + EXLOG_CS_BYTES + EXLOG_TIME_TAKEN + EXLOG_CS_VERSION + EXLOG_CS_REFERRER + EXLOG_SC_WIN32_STATUS + EXLOG_MEM_HANDLES cFilePrefix Optional character string providing the log file name prefix. If not specified the file name prefix defaults to "trans".

Example: oTLog := xbTLog():new()
oTLog:SetDir(".\LogFiles")
oTLog:TimePeriod := TLOG_MONTHLY
oTLog:Fields := EXLOG_DATE + EXLOG_TIME + EXLOG_C_IP + EXLOG_CS_METHOD + EXLOG_CS_URI_STEM + EXLOG_CS_URI_QUERY + EXLOG_SC_STATUS

oServer := xbHTTPServer():new()
oServer:TLog := oTLog
oServer:RootDir := ".\www_root"
oServer:IndexFile := "index.htm"
oServer:start()


xbTLog: object methods

:Close() → self Close current log file. Note that calling this method does not terminate logging, the log file will be reopened by the :Write() method. To pause logging, use the :Stop() method. :SetDir(cPath) → cPath Set the directory path where the log files will be written. If the specified directory path does not exist, it will be created. :Start() → self Restart logging after it has been disabled with the :Stop() method. :Stop() → self Disable logging and close current log file. Logging can be restarted by using the :Start() method. :Write(cString) → nErrorCode Write a pre-formatted log entry into the log file. cString is a character string containing the log entry record to be written. It must be properly formatted as per W3C Working Draft WD-logfile-960323 and correspond to the :Fields property.

The method returns zero if successful. Otherwise, an integer numeric OS error code is returned.


xbTLog: object properties

:Cargo exported/any data type Used to attach additional information to the object as required by the programmer. :Fields exported/numeric Set of bitmap flags specifying the information to be recorded in each log entry. The following bitmap constants defined in Xb2NET.CH provide the available list of fields. These can be added together to define the set of fields to be recorded in each log entry:

EXLOG_DATE - Date of activity.
EXLOG_TIME - Time of activity.
EXLOG_C_IP - IP address of client who accessed the server.
EXLOG_CS_USERNAME - Name of authenticated user who accessed the server.
EXLOG_S_SITENAME - HTTP server appname.
EXLOG_S_COMPUTERNAME - Name of server on which the log entry was generated.
EXLOG_S_IP - IP address of server on which the log entry was generated.
EXLOG_S_PORT - Server port number the client connected to.
EXLOG_CS_METHOD - The action client was trying to perform (eg. GET, POST, etc...).
EXLOG_CS_URI_STEM - The resource accessed (eg. index.htm).
EXLOG_CS_URI_QUERY - The query, if any, the client was trying to perform.
EXLOG_SC_STATUS - The response status of the action.
EXLOG_SC_WIN32_STATUS - The response status of the action as a win32 error code.
EXLOG_SC_BYTES - Number of bytes sent by the server.
EXLOG_CS_BYTES - Number of bytes received by the server.
EXLOG_TIME_TAKEN - Duration of time, in milliseconds, that the action consumed.
EXLOG_CS_VERSION - The protocol version that the client used (eg. HTTP/1.1).
EXLOG_CS_HOST - The HTTP 'host' header field.
EXLOG_CS_USER_AGENT - The HTTP browser used by the client.
EXLOG_CS_COOKIE - The content of a HTTP cookie received, if any.
EXLOG_CS_REFERRER - The previous HTTP site visited by the user, if it provided a link to the current site.
EXLOG_MEM_HANDLES - Number of Xbase++ memory handles currently in use by the HTTP server process.
:FilePrefix exported/character The log file name prefix. :isActive readonly/logical A logical flag indicating if logging is enabled. The status of this flag is controlled by the :Start() and :Stop() methods. :LogDir readonly/character The directory path where log files are written. :Software exported/character A character string that is used to identify the software which generated the log. :TimePeriod exported/numeric Specifies the time period when a new log file is created. The following options, defined in Xb2NET.CH, are possible:


xbURI

A Uniform Resource Identifier (URI) is a compact string of characters for identifying an abstract or physical resource. This class provides methods for parsing a URI into its individual components as well as methods for combining these individual components into an encoded string safe for transport. A URI consists of the following components (some of which may not be present is all URI's):

[scheme]://[authority][path]?[query]#[fragment]

xbURI: class methods

:New([cURIString]) → self Creates a new instance of the xbURI class and optionally parses a URI string cURIString into its individual components. If passed, the cURIString must be in URL encoded format in order to parse correctly.

xbURI: object methods

:AsString([lResourceOnly]) → cEncodedURIString Combine the URI components and encode the result suitable for HTTP transport.

An optional logical parameter lResourceOnly, can be set to .T. in order to return only the "resource" portion of the URI. A URI resource consists of the path, query and fragment portions only, eg:
/physics/letters/quantum.htm?uid=maxwell#qed

If the parameter lResourceOnly is NIL or .F., then the full URI will be returned. :GetVar([cName]) → xValue | aVarList | NIL Retrieve a URI query parameter. If cName is NIL, then the method will return an array listing all query parameters as name/value pairs. :Parse(cURIString) → self Parse the URI string cURIString into its individual components. The specified URI string must be in URL encoded format in order to parse correctly. :Reset() → self Reinitialize object. :SetVar([xName], [cValue]) → xPreviousValue | aPreviousVarList Assign the value cValue to the query parameter xName. This method and can be used is several ways:

When xName and cValue are both NIL then delete all query parameters
When cValue is NIL, then remove the query parameter xName
When xName is an array, replace all query parameters with the passed array of name/value pairs
Otherwise add or replace a query parameter value


xbURI: object properties

:Cargo exported/any data type Used to attach additional information to the object as required by the programmer. :isAbsolute exported/logical Indicates if URI path is absolute (.T.) or relative (.F.). Absolute URI paths include a scheme component. :isQuery exported/logical Indicates if URI contains a query component. This property can be set to .T. to append a query marker (the question mark '?' character) to the final URI even though no query component exists. The presence of the query marker can be significant on some HTTP servers. :Scheme exported access-assign method/character This is the name of the scheme being used. Some examples are:
http, ftp, gopher, mailto, news, telnet :Authority exported access-assign method/character The authority component is the top hierarchical element in the URI that is typically defined by a server, eg:
www.sqlexpress.net, atlas.gc.ca, cgi.ebay.ca :Path exported access-assign method/character The path component identifies the target resource within the scope of the Authority (or Scheme if there is no Authority), eg:
/, /english/facts/index.html, /aw-cgi/eBayISAPI.dll :Query exported access-assign method/character The query component is a string of information to be interpreted by the target resource. It is separated from the target resource by a question mark (?) character. The :GetVar and :SetVar methods can be used to get and set individual parameters within the query. The following is an example of a query component:
UID=1836743&ITEM=XE342&QTY=3 :Fragment exported access-assign method/character A URI fragment is used to provide additional retrieval information to the client after the target resource has been successfully loaded. Technically, a fragment is not really a part of the URI, but is is often used in conjunction with a URI. It is separated from the URI by a crosshatch (#) character, eg:
http://www.sqlexpress.net/download.htm#sqlexpress