{"name":"Arma 3: WebAPI","title":"Arma 3: WebAPI","type":"topic","url":"https://community.bistudio.com/wiki/Arma_3:_WebAPI","revid":379581,"updated":"2026-11-02T17:05:20Z","aliases":[],"markdown":"WebAPI allows to use HTTP, Websocket and other REST APIs.\n\nAll web requests return handles, these behave like a Promise.\nIt can be waited on to receive the first result or failure (note special behavior for Websockets which have multiple results).\n\nThese handles are not Serializable, they behave like Control/Display references.\nWhen loading a savegame all stored handles will be null, and they cannot be transferred over network.\n\nNote that all HTTP Requests (including Websockets connection establish) are checked using a CORS Preflight check.\n\nThe API provides a pre-defined domain named \"armaserver\" which points to the Server the player is playing on.\n\n```\nhttp://armaserver:8080/test\n```\n\nwill send the request to the server, using the same address that the player used to connect to the server (note this will fail if player joined via Steam Datagram relay (ugh)).\nIn singleplayer and on the server, this points to localhost.\n\n#### Initiating Requests\n\nCommand syntax is:\n\n```sqf\nprivate _handle = webRequest HASHMAP;\n```\n\nThe structure of the HashMap depends on the request type.\n\n```cpp\n{\n    type: STRING, // \"http\"|\"websocket\"|\"mdns\"|\"send\"|\"close\"|\"flush\"\n\n    // \"http\"/\"websocket\"/\"mdns\" only\n    callbackContext: ANY // Context passed to all internal callbacks as _thisArgs\n\n    // \"http\"/\"mdns\" only\n    onCompleted: CODE // Function called with params [\"_request\", \"_result\"]. On success or failure.\n\n    // \"http\"/\"websocket\" only. For websocket these are only used for initial connection establishment\n    url: STRING,        // URL to connect to, must be http/https for \"http\" type, or ws/wss for \"websocket\" type\n    origin: STRING,        // Optional. Identifier of sender, like \"ACEMOD\" or \"arma://ACEMOD\", will be passed as \"Origin\" in preflight request\n    headers: HASHMAP<STRING, STRING>, // Optional. Extra headers to add to the request. Note the list of not allowed headers.\n    verifySSL: BOOL,    // Optional, Default true. verify SSL/TLS certificate for https/wss connections\n    debug: BOOL,        // Optional default false. Print verbose debug logging into RPT, only available if the -debug commandline parameter is set\n\n    // \"http\" only\n    method: STRING, // Optional, default GET. \"GET\"|\"POST\"|\"PUT\"|\"DELETE\"|\"CUSTOM\"|...\n    postData: STRING, // Data to send as body of request, only valid with \"POST\"/\"CUSTOM\" methods\n\n    // \"websocket\" only\n    onWebsocketEstablished: CODE,    // Function called once Websocket connection is established and ready to send/receive data.\n                                    // params [\"_request\", \"_data\"].\n                                    // Returns the headers and result the server returned to the CONNECT invocation\n\n    onWebsocketLost: CODE,            // Function called when initial connection failed, or connection was lost.\n                                    // params [\"_request\", \"_data\"].\n                                    // _data contains error message.\n\n    onWebsocketDataReceived: CODE,    // Function called with params [\"_request\", \"_data\"].\n                                    // _data is a string containing the TEXT content that was transmitted.\n\n    // \"send\"/\"close\" only\n    connection: HANDLE, // Handle to a websocket session\n\n    // \"send\" only\n    data: STRING, // Data to send over the websocket connection\n\n    // \"close\" only\n    statusCode: SCALAR,    // Optional, default 1000. Websocket status code to send in close message.\n                        // See https://www.rfc-editor.org/info/rfc6455/#section-5.5.1\n    reason: STRING // Optional, message to send with close command to the server\n}\n```\n\n- All callbacks are called in Unscheduled Environment.\n- The \"http\", \"websocket\", \"mdns\" types establish new requests.\n- The \"send\", \"info\", \"close\" types are used on established connections.\n\n##### HTTP\n\nEnforces that Origin header is set (and cannot be overwritten by headers parameter).\nThe Origin is always `arma://`-prefixed. The default Origin is `arma://null`\nAutomatically passes an `Accept-Encoding` header specifying deflate, gzip, br, zstd\nAutomatically sets the `User-Agent` header to \"BIGameEngine/2.22.154051\" (The current game version)\n\nThe following headers are blocked and cannot be set:\n\n- Sec-*\n- Proxy-*\n- Host\n- Accept-Encoding\n- Content-Length\n- User-Agent\n- Origin\n- Cookie\n- Cookie2\n- Connection\n- Keep-Alive\n- Proxy-Authorization\n- Proxy-Authenticate\n- TE\n- Trailer\n- Transfer-Encoding\n- Via\n- Upgrade\n- Expect\n- Referer\n\n```sqf\nspawn {\n    private _handle = webRequest #{\n        \"type\": \"http\",\n        //\"method\": \"GET\", \"GET\" is default\n        \"origin\": \"test\",\n        \"url\": \"https://myip.wtf/text\"\n    };\n    private _result = waitUntil _handle; // suspend until its ready\n    _result params [\"_request\", \"_result\"];\n    systemChat format [\"My IP is: %1\", _result get \"body\"];\n};\n```\n\nResults can be retrieved/awaited by either specifying the \"onCompleted\" callback, or using the returned _handle, which is a Promise.\n\nThe result structure depends on whether the request was successful or failed.\nSuccess means that the target webserver could be reached and returned a response, it might still be an error response returned by the server, for that check the httpCode.\n\nA successful request results in a HashMap of following structure:\n\n```cpp\n{\n    httpCode: SCALAR,                            // the numeric HTTP result code\n    body: STRING,                                // the Content returned by the request\n    responseHeaders: HASHMAP<STRING, STRING>,    // the headers provided in the response\n}\n```\n\nMaximum length of body is the same as maximum string length.\n\nA failed request results in a HashMap of following structure:\n\n```cpp\n{\n    error: STRING, // Error message explaining what failed\n}\n```\n\nFailed requests generally only happen on Internal errors, Preflight failures or Timeouts.\nNote that starting due to security reasons, some error messages are less detailed if the `-debug` command line parameter is not set.\n\nExample messages:\n\nWithout `-debug` parameter:\nAll Preflight failures: `{\"error\":\"Request error\"}`\n\nPreflight successful but server did not respond to actual request: `{\"error\":\"Operation timed out after 30003 milliseconds with 0 bytes received\"}`\n\nWith `-debug` parameter:\n\n```json\n{\"error\":\"Preflight failed: Reason: Did not find method in CORS header 'Access-Control-Allow-Methods'\"}\n```\n\n```json\n{\"error\":\"Preflight failed: Reason: CORS header 'Access-Control-Allow-Origin' missing\"}\n```\n\nDomain does not exist\n\n```json\n{\"error\":\"Preflight failed: Could not resolve host: doesnotexist.cim, CurlError: 6\"}\n```\n\nServer does not allow OPTIONS method, required for Preflight check\n\n```json\n{\"error\":\"Preflight failed: Reason: CORS request got result HTTP 405\"}\n```\n\n```json\n{\"error\":\"Operation timed out after 30003 milliseconds with 0 bytes received\"}\n```\n\nServer not reachable, so Preflight check also failed:\n\n```json\n{\"error\":\"Preflight failed: Connection timed out after 5000 milliseconds\"}\n```\n\nCertificate error:\n\n```json\n{\"error\":\"Preflight failed: Certificate validation failed\"}\n```\n\n##### Websocket\n\nFor the initial \"CONNECT\" request, the same limitations/requirements as the HTTP request apply.\nThe onWebsocketEstablished/onWebsocketLost eventhandler parameters also match what a HTTP request would be.\n\n```sqf\nprivate _handle = webRequest #{\n    \"type\": \"websocket\",\n    \"origin\": \"test\",\n    \"url\": \"wss://localhost:7082/websocket/relay\",\n    \"onWebsocketEstablished\": {\n        GResult = _this select 1;\n        systemChat str _this;\n    },\n    \"onWebsocketLost\": {\n        GResultLoss = _this select 1;\n        systemChat str _this;\n    },\n    \"onWebsocketDataReceived\": {\n        GLastMessage = _this select 1;\n        systemChat str _this;\n    },\n\n    \"callbackContext\": \"hello world context\",\n    \"verifySSL\": false\n};\n\nGHandle = _handle;\n```\n\nWebsockets need to use the callbacks.\nThe handle is also a Promise, but it will only be resolved once, on the first Established/Lost.\nAfter the connection is established, the handle cannot be used to receive data or notice Connection Loss events.\n\nUnlike HTTP Requests, the returned handle MUST be stored, once the Handle goes out of scope (and is not stored elsewhere), the connection is closed.\n\nThe max length of a websocket message is also the max SQF string length.\nWhen the server sends a larger message, the client will cut the connection with WS status 1009;\nthe message will not be forwarded to script and the `onWebsocketLost` callback will be called with an error message.\n\nNote that handling fragmented messages (one message split into multiple \"Continuation\" frames, which must be re-assembled by receiver) is inefficient.\nPrefer having messages in a large single frame instead.\n\nThere are currently no Websocket extensions supported by the engine.\nRFC 7692 may be supplied at a later point (ref https://github.com/curl/curl/discussions/16065)\n\nWhen the server closes the connection, the close status code and message, are forwarded inside the error message for onWebsocketLost.\n\nTo send a message:\n\n```sqf\nwebRequest #{\n    \"type\": \"send\",\n    \"connection\": _handle,\n    \"data\": \"Message to Send\"\n};\n```\n\nTo close the connection:\n\n```sqf\nwebRequest #{\n    \"type\": \"close\",\n    \"connection\": _handle,\n    \"statusCode\": SCALAR, // Optional, default 1000. Websocket status code to send in close message. See https://www.rfc-editor.org/info/rfc6455/#section-5.5.1\n    \"reason\": STRING // Optional, message to send with close command to the server\n};\n```\n\n##### mDNS\n\nA mutual DNS request will look up the name \"_arma3web._tcp.local\" on the local network. It can be used to find Arma web services that advertise themselves.\n\nThis can be used to find services that run on non-static port assignments.\n\nmDNS cannot error, it always results in Hashmap<SERVICE_RECORD> (That means a hashmap, of string:hashmap pairs)\nOne service can have multiple SRV records (multiple ports) but usually only have one.\nThe SRV records can have different hostnames, but usually only have one.\nThus the ADDR hashmap usually only has one entry.\n\nmDNS requests have a timeout of 10 seconds.\nThey wait for services to announce themselves, if within 10 seconds it did not receive a single announcement, it aborts. That means the result will be empty.\n\nSERVICE_RECORD\n\n```cpp\n{\n    SRV: Array<SRV_Record>,\n    TXT: Array<STRING>,\n    ADDR: Hashmap<STRING, Array<STRING>> // Network addresses, corresponding to the SRV records name\n}\n```\n\nSRV_RECORD:\n\n```cpp\n{\n    name: STRING,\n    priority: SCALAR,\n    weight: SCALAR,\n    port: SCALAR,\n}\n```\n\nExample:\n\n```json\n{\n    \"IAmAServiceName._arma3web._tcp.local\": {\n        \"TXT\": [\n            \"OhSoMany=Things\",\n            \"txtvers=1\"\n        ],\n        \"ADDR\": {\n            \"The service decides its hostname\": [\n                \"127.0.0.1\",\n                \"[::1]\"\n            ]\n        },\n        \"SRV\": [\n            {\n                \"priority\": 0,\n                \"port\": 1337,\n                \"name\": \"The service decides its hostname\",\n                \"weight\": 0\n            }\n        ]\n    },\n    \"ASPNetSample._arma3web._tcp.local\": {\n        \"TXT\": [\n            \"version=1.0\",\n            \"status=running\",\n            \"path=/api/v1\",\n            \"txtvers=1\"\n        ],\n        \"ADDR\": {\n            \"SecondaryService.local\": [\n                \"[::1]\"\n            ],\n            \"ASPNetSample_a3web.local\": [\n                \"172.18.144.1\",\n                \"192.168.73.1\",\n                \"172.18.48.1\",\n                \"192.168.11.1\",\n                \"172.22.208.1\",\n                \"172.27.160.1\",\n                \"172.23.16.1\"\n            ]\n        },\n        \"SRV\": [\n            {\n                \"priority\": 0,\n                \"port\": 1338,\n                \"name\": \"ASPNetSample_a3web.local\",\n                \"weight\": 0\n            },\n            {\n                \"priority\": 0,\n                \"port\": 7082,\n                \"name\": \"ASPNetSample_a3web.local\",\n                \"weight\": 0\n            }\n        ]\n    }\n}\n```\n\nSample for how to announce mDNS services (in C#): https://github.com/dedmen/ArmaWebRequestTests/blob/master/mDNSHostedService.cs\n\n#### Preflight\n\nEvery web request executes a CORS preflight request, to check if the Webserver allows us to request from it.\nSee https://developer.mozilla.org/en-US/docs/Glossary/Preflight_request\n\nThe preflight result is cached, cache expiry respects the \"Access-Control-Max-Age\" response header of the webserver.\nIf no such header is provided, the default is 60 seconds.\nThe maximum allowed age is 600 seconds (10 minutes), the minimum is 5 seconds.\nThe cache will also only store 64 URLs, and will evict the least recently used entry if full.\n\nIf a previously unknown METHOD is used on a known URL, a new preflight is sent, the allowed methods result is inserted into the cached entry and its expiry time is extended.\n\nThe Preflight \"Origin\" that must be allowed, is decided by the script issuing the request, but it uses a \"arma://\" protocol. Like \"arma://ACEMod\"\n\nThe returned \"Access-Control-Allow-Origin\" should either be \"arma://*\" (Note that \"*\" is not allowed) or exactly the same as the \"Origin\" request header.\n\nNote that the FULL URL, is the cache key for the preflight request, that means using query parameters in the URL, will create new Preflight requests. Thus it is highly discouraged too use query parameters, use POST or QUERY requests instead.\n\nAccess-Control-Request-Headers / Access-Control-Allow-Headers are not checked.\n\nIf `-debug` parameter is not set, there can be a maximum of 5 preflight failures (where the server actually replies, timeout or failing to reach the server does not count), after that the whole domain is blacklisted until game restart.\n\nThe preflight cache can be cleared, but only if `-debug` is set:\n\n```sqf\nwebRequest #{ type: \"flush\" };\n```","sections":[{"heading":null,"level":1,"markdown":"WebAPI allows to use HTTP, Websocket and other REST APIs.\n\nAll web requests return handles, these behave like a Promise.\nIt can be waited on to receive the first result or failure (note special behavior for Websockets which have multiple results).\n\nThese handles are not Serializable, they behave like Control/Display references.\nWhen loading a savegame all stored handles will be null, and they cannot be transferred over network.\n\nNote that all HTTP Requests (including Websockets connection establish) are checked using a CORS Preflight check.\n\nThe API provides a pre-defined domain named \"armaserver\" which points to the Server the player is playing on.\n\n```\nhttp://armaserver:8080/test\n```\n\nwill send the request to the server, using the same address that the player used to connect to the server (note this will fail if player joined via Steam Datagram relay (ugh)).\nIn singleplayer and on the server, this points to localhost."},{"heading":"Initiating Requests","level":4,"markdown":"Command syntax is:\n\n```sqf\nprivate _handle = webRequest HASHMAP;\n```\n\nThe structure of the HashMap depends on the request type.\n\n```cpp\n{\n    type: STRING, // \"http\"|\"websocket\"|\"mdns\"|\"send\"|\"close\"|\"flush\"\n\n    // \"http\"/\"websocket\"/\"mdns\" only\n    callbackContext: ANY // Context passed to all internal callbacks as _thisArgs\n\n    // \"http\"/\"mdns\" only\n    onCompleted: CODE // Function called with params [\"_request\", \"_result\"]. On success or failure.\n\n    // \"http\"/\"websocket\" only. For websocket these are only used for initial connection establishment\n    url: STRING,        // URL to connect to, must be http/https for \"http\" type, or ws/wss for \"websocket\" type\n    origin: STRING,        // Optional. Identifier of sender, like \"ACEMOD\" or \"arma://ACEMOD\", will be passed as \"Origin\" in preflight request\n    headers: HASHMAP<STRING, STRING>, // Optional. Extra headers to add to the request. Note the list of not allowed headers.\n    verifySSL: BOOL,    // Optional, Default true. verify SSL/TLS certificate for https/wss connections\n    debug: BOOL,        // Optional default false. Print verbose debug logging into RPT, only available if the -debug commandline parameter is set\n\n    // \"http\" only\n    method: STRING, // Optional, default GET. \"GET\"|\"POST\"|\"PUT\"|\"DELETE\"|\"CUSTOM\"|...\n    postData: STRING, // Data to send as body of request, only valid with \"POST\"/\"CUSTOM\" methods\n\n    // \"websocket\" only\n    onWebsocketEstablished: CODE,    // Function called once Websocket connection is established and ready to send/receive data.\n                                    // params [\"_request\", \"_data\"].\n                                    // Returns the headers and result the server returned to the CONNECT invocation\n\n    onWebsocketLost: CODE,            // Function called when initial connection failed, or connection was lost.\n                                    // params [\"_request\", \"_data\"].\n                                    // _data contains error message.\n\n    onWebsocketDataReceived: CODE,    // Function called with params [\"_request\", \"_data\"].\n                                    // _data is a string containing the TEXT content that was transmitted.\n\n    // \"send\"/\"close\" only\n    connection: HANDLE, // Handle to a websocket session\n\n    // \"send\" only\n    data: STRING, // Data to send over the websocket connection\n\n    // \"close\" only\n    statusCode: SCALAR,    // Optional, default 1000. Websocket status code to send in close message.\n                        // See https://www.rfc-editor.org/info/rfc6455/#section-5.5.1\n    reason: STRING // Optional, message to send with close command to the server\n}\n```\n\n- All callbacks are called in Unscheduled Environment.\n- The \"http\", \"websocket\", \"mdns\" types establish new requests.\n- The \"send\", \"info\", \"close\" types are used on established connections."},{"heading":"HTTP","level":5,"markdown":"Enforces that Origin header is set (and cannot be overwritten by headers parameter).\nThe Origin is always `arma://`-prefixed. The default Origin is `arma://null`\nAutomatically passes an `Accept-Encoding` header specifying deflate, gzip, br, zstd\nAutomatically sets the `User-Agent` header to \"BIGameEngine/2.22.154051\" (The current game version)\n\nThe following headers are blocked and cannot be set:\n\n- Sec-*\n- Proxy-*\n- Host\n- Accept-Encoding\n- Content-Length\n- User-Agent\n- Origin\n- Cookie\n- Cookie2\n- Connection\n- Keep-Alive\n- Proxy-Authorization\n- Proxy-Authenticate\n- TE\n- Trailer\n- Transfer-Encoding\n- Via\n- Upgrade\n- Expect\n- Referer\n\n```sqf\nspawn {\n    private _handle = webRequest #{\n        \"type\": \"http\",\n        //\"method\": \"GET\", \"GET\" is default\n        \"origin\": \"test\",\n        \"url\": \"https://myip.wtf/text\"\n    };\n    private _result = waitUntil _handle; // suspend until its ready\n    _result params [\"_request\", \"_result\"];\n    systemChat format [\"My IP is: %1\", _result get \"body\"];\n};\n```\n\nResults can be retrieved/awaited by either specifying the \"onCompleted\" callback, or using the returned _handle, which is a Promise.\n\nThe result structure depends on whether the request was successful or failed.\nSuccess means that the target webserver could be reached and returned a response, it might still be an error response returned by the server, for that check the httpCode.\n\nA successful request results in a HashMap of following structure:\n\n```cpp\n{\n    httpCode: SCALAR,                            // the numeric HTTP result code\n    body: STRING,                                // the Content returned by the request\n    responseHeaders: HASHMAP<STRING, STRING>,    // the headers provided in the response\n}\n```\n\nMaximum length of body is the same as maximum string length.\n\nA failed request results in a HashMap of following structure:\n\n```cpp\n{\n    error: STRING, // Error message explaining what failed\n}\n```\n\nFailed requests generally only happen on Internal errors, Preflight failures or Timeouts.\nNote that starting due to security reasons, some error messages are less detailed if the `-debug` command line parameter is not set.\n\nExample messages:\n\nWithout `-debug` parameter:\nAll Preflight failures: `{\"error\":\"Request error\"}`\n\nPreflight successful but server did not respond to actual request: `{\"error\":\"Operation timed out after 30003 milliseconds with 0 bytes received\"}`\n\nWith `-debug` parameter:\n\n```json\n{\"error\":\"Preflight failed: Reason: Did not find method in CORS header 'Access-Control-Allow-Methods'\"}\n```\n\n```json\n{\"error\":\"Preflight failed: Reason: CORS header 'Access-Control-Allow-Origin' missing\"}\n```\n\nDomain does not exist\n\n```json\n{\"error\":\"Preflight failed: Could not resolve host: doesnotexist.cim, CurlError: 6\"}\n```\n\nServer does not allow OPTIONS method, required for Preflight check\n\n```json\n{\"error\":\"Preflight failed: Reason: CORS request got result HTTP 405\"}\n```\n\n```json\n{\"error\":\"Operation timed out after 30003 milliseconds with 0 bytes received\"}\n```\n\nServer not reachable, so Preflight check also failed:\n\n```json\n{\"error\":\"Preflight failed: Connection timed out after 5000 milliseconds\"}\n```\n\nCertificate error:\n\n```json\n{\"error\":\"Preflight failed: Certificate validation failed\"}\n```"},{"heading":"Websocket","level":5,"markdown":"For the initial \"CONNECT\" request, the same limitations/requirements as the HTTP request apply.\nThe onWebsocketEstablished/onWebsocketLost eventhandler parameters also match what a HTTP request would be.\n\n```sqf\nprivate _handle = webRequest #{\n    \"type\": \"websocket\",\n    \"origin\": \"test\",\n    \"url\": \"wss://localhost:7082/websocket/relay\",\n    \"onWebsocketEstablished\": {\n        GResult = _this select 1;\n        systemChat str _this;\n    },\n    \"onWebsocketLost\": {\n        GResultLoss = _this select 1;\n        systemChat str _this;\n    },\n    \"onWebsocketDataReceived\": {\n        GLastMessage = _this select 1;\n        systemChat str _this;\n    },\n\n    \"callbackContext\": \"hello world context\",\n    \"verifySSL\": false\n};\n\nGHandle = _handle;\n```\n\nWebsockets need to use the callbacks.\nThe handle is also a Promise, but it will only be resolved once, on the first Established/Lost.\nAfter the connection is established, the handle cannot be used to receive data or notice Connection Loss events.\n\nUnlike HTTP Requests, the returned handle MUST be stored, once the Handle goes out of scope (and is not stored elsewhere), the connection is closed.\n\nThe max length of a websocket message is also the max SQF string length.\nWhen the server sends a larger message, the client will cut the connection with WS status 1009;\nthe message will not be forwarded to script and the `onWebsocketLost` callback will be called with an error message.\n\nNote that handling fragmented messages (one message split into multiple \"Continuation\" frames, which must be re-assembled by receiver) is inefficient.\nPrefer having messages in a large single frame instead.\n\nThere are currently no Websocket extensions supported by the engine.\nRFC 7692 may be supplied at a later point (ref https://github.com/curl/curl/discussions/16065)\n\nWhen the server closes the connection, the close status code and message, are forwarded inside the error message for onWebsocketLost.\n\nTo send a message:\n\n```sqf\nwebRequest #{\n    \"type\": \"send\",\n    \"connection\": _handle,\n    \"data\": \"Message to Send\"\n};\n```\n\nTo close the connection:\n\n```sqf\nwebRequest #{\n    \"type\": \"close\",\n    \"connection\": _handle,\n    \"statusCode\": SCALAR, // Optional, default 1000. Websocket status code to send in close message. See https://www.rfc-editor.org/info/rfc6455/#section-5.5.1\n    \"reason\": STRING // Optional, message to send with close command to the server\n};\n```"},{"heading":"mDNS","level":5,"markdown":"A mutual DNS request will look up the name \"_arma3web._tcp.local\" on the local network. It can be used to find Arma web services that advertise themselves.\n\nThis can be used to find services that run on non-static port assignments.\n\nmDNS cannot error, it always results in Hashmap<SERVICE_RECORD> (That means a hashmap, of string:hashmap pairs)\nOne service can have multiple SRV records (multiple ports) but usually only have one.\nThe SRV records can have different hostnames, but usually only have one.\nThus the ADDR hashmap usually only has one entry.\n\nmDNS requests have a timeout of 10 seconds.\nThey wait for services to announce themselves, if within 10 seconds it did not receive a single announcement, it aborts. That means the result will be empty.\n\nSERVICE_RECORD\n\n```cpp\n{\n    SRV: Array<SRV_Record>,\n    TXT: Array<STRING>,\n    ADDR: Hashmap<STRING, Array<STRING>> // Network addresses, corresponding to the SRV records name\n}\n```\n\nSRV_RECORD:\n\n```cpp\n{\n    name: STRING,\n    priority: SCALAR,\n    weight: SCALAR,\n    port: SCALAR,\n}\n```\n\nExample:\n\n```json\n{\n    \"IAmAServiceName._arma3web._tcp.local\": {\n        \"TXT\": [\n            \"OhSoMany=Things\",\n            \"txtvers=1\"\n        ],\n        \"ADDR\": {\n            \"The service decides its hostname\": [\n                \"127.0.0.1\",\n                \"[::1]\"\n            ]\n        },\n        \"SRV\": [\n            {\n                \"priority\": 0,\n                \"port\": 1337,\n                \"name\": \"The service decides its hostname\",\n                \"weight\": 0\n            }\n        ]\n    },\n    \"ASPNetSample._arma3web._tcp.local\": {\n        \"TXT\": [\n            \"version=1.0\",\n            \"status=running\",\n            \"path=/api/v1\",\n            \"txtvers=1\"\n        ],\n        \"ADDR\": {\n            \"SecondaryService.local\": [\n                \"[::1]\"\n            ],\n            \"ASPNetSample_a3web.local\": [\n                \"172.18.144.1\",\n                \"192.168.73.1\",\n                \"172.18.48.1\",\n                \"192.168.11.1\",\n                \"172.22.208.1\",\n                \"172.27.160.1\",\n                \"172.23.16.1\"\n            ]\n        },\n        \"SRV\": [\n            {\n                \"priority\": 0,\n                \"port\": 1338,\n                \"name\": \"ASPNetSample_a3web.local\",\n                \"weight\": 0\n            },\n            {\n                \"priority\": 0,\n                \"port\": 7082,\n                \"name\": \"ASPNetSample_a3web.local\",\n                \"weight\": 0\n            }\n        ]\n    }\n}\n```\n\nSample for how to announce mDNS services (in C#): https://github.com/dedmen/ArmaWebRequestTests/blob/master/mDNSHostedService.cs"},{"heading":"Preflight","level":4,"markdown":"Every web request executes a CORS preflight request, to check if the Webserver allows us to request from it.\nSee https://developer.mozilla.org/en-US/docs/Glossary/Preflight_request\n\nThe preflight result is cached, cache expiry respects the \"Access-Control-Max-Age\" response header of the webserver.\nIf no such header is provided, the default is 60 seconds.\nThe maximum allowed age is 600 seconds (10 minutes), the minimum is 5 seconds.\nThe cache will also only store 64 URLs, and will evict the least recently used entry if full.\n\nIf a previously unknown METHOD is used on a known URL, a new preflight is sent, the allowed methods result is inserted into the cached entry and its expiry time is extended.\n\nThe Preflight \"Origin\" that must be allowed, is decided by the script issuing the request, but it uses a \"arma://\" protocol. Like \"arma://ACEMod\"\n\nThe returned \"Access-Control-Allow-Origin\" should either be \"arma://*\" (Note that \"*\" is not allowed) or exactly the same as the \"Origin\" request header.\n\nNote that the FULL URL, is the cache key for the preflight request, that means using query parameters in the URL, will create new Preflight requests. Thus it is highly discouraged too use query parameters, use POST or QUERY requests instead.\n\nAccess-Control-Request-Headers / Access-Control-Allow-Headers are not checked.\n\nIf `-debug` parameter is not set, there can be a maximum of 5 preflight failures (where the server actually replies, timeout or failing to reach the server does not count), after that the whole domain is blacklisted until game restart.\n\nThe preflight cache can be cleared, but only if `-debug` is set:\n\n```sqf\nwebRequest #{ type: \"flush\" };\n```"}],"categories":[],"groups":["General"]}