ARI: REST over Websocket

This commit adds the ability to make ARI REST requests over the same
websocket used to receive events.

For full details on how to use the new capability, visit...

https://docs.asterisk.org/Configuration/Interfaces/Asterisk-REST-Interface-ARI/ARI-REST-over-WebSocket/

Changes:

* Added utilities to http.c:
  * ast_get_http_method_from_string().
  * ast_http_parse_post_form().
* Added utilities to json.c:
  * ast_json_nvp_array_to_ast_variables().
  * ast_variables_to_json_nvp_array().
* Added definitions for new events to carry REST responses.
* Created res/ari/ari_websocket_requests.c to house the new request handlers.
* Moved non-event specific code out of res/ari/resource_events.c into
  res/ari/ari_websockets.c
* Refactored res/res_ari.c to move non-http code out of ast_ari_callback()
  (which is http specific) and into ast_ari_invoke() so it can be shared
  between both the http and websocket transports.

UpgradeNote: This commit adds the ability to make ARI REST requests over the same
websocket used to receive events.
See https://docs.asterisk.org/Configuration/Interfaces/Asterisk-REST-Interface-ARI/ARI-REST-over-WebSocket/

(cherry picked from commit 1442c17141)
This commit is contained in:
George Joseph
2025-03-12 15:58:51 -06:00
committed by Asterisk Development Team
parent 68d9a69be3
commit 2a55f064f3
20 changed files with 2154 additions and 1300 deletions

View File

@@ -200,7 +200,8 @@
"TextMessageReceived",
"ChannelConnectedLine",
"PeerStatusChange",
"ChannelTransfer"
"ChannelTransfer",
"RESTResponse"
]
},
"ContactInfo": {
@@ -1039,6 +1040,125 @@
"description": "Value of the parameter"
}
}
},
"RESTHeader": {
"id": "RESTHeader",
"description": "REST over Websocket header",
"properties": {
"name": {
"type": "string",
"description": "Header name",
"required": true
},
"value": {
"required": true,
"type": "string",
"description": "Header value"
}
}
},
"RESTQueryStringParameter": {
"id": "RESTQueryStringParameter",
"description": "REST over Websocket Query String Parameter",
"properties": {
"name": {
"type": "string",
"description": "Parameter name",
"required": true
},
"value": {
"required": true,
"type": "string",
"description": "Parameter value"
}
}
},
"RESTRequest": {
"id": "RESTRequest",
"description": "REST over Websocket Request.",
"properties": {
"type": {
"type": "string",
"description": "Message type. Must be 'RESTRequest'",
"required": true
},
"transaction_id": {
"type": "string",
"description": "Opaque transaction id. Can be any valid string. Will be returned in any response to this request.",
"required": true
},
"request_id": {
"type": "string",
"description": "Opaque request id. Can be any valid string. Will be returned in any response to this request.",
"required": true
},
"method": {
"required": true,
"type": "string",
"description": "HTTP method (GET, PUT, POST, DELETE, etc.)"
},
"uri": {
"required": true,
"type": "string",
"description": "Resource URI with optional query string parameters."
},
"content_type": {
"required": false,
"type": "string",
"description": "The Content-Type of the message body."
},
"query_strings": {
"required": false,
"type": "List[RESTQueryStringParameter]",
"description": "Request query string parameters."
},
"message_body": {
"required": false,
"type": "string",
"description": "Request message body. Only content types application/json and application/x-www-form-urlencoded are supported."
}
}
},
"RESTResponse": {
"id": "RESTResponse",
"description": "REST over Websocket Response.",
"properties": {
"transaction_id": {
"type": "string",
"description": "Opaque transaction id. Will be whatever was specified on the original request.",
"required": true
},
"request_id": {
"type": "string",
"description": "Opaque request id. Will be whatever was specified on the original request.",
"required": true
},
"status_code": {
"required": true,
"type": "int",
"description": "HTTP status code"
},
"reason_phrase": {
"required": true,
"type": "string",
"description": "HTTP reason phrase"
},
"uri": {
"required": true,
"type": "string",
"description": "Original request resource URI"
},
"content_type": {
"required": false,
"type": "string",
"description": "The Content-Type of the message body."
},
"message_body": {
"required": false,
"type": "string",
"description": "Response message body"
}
}
}
}
}