ESP WebSocket Client
====================

Overview
--------
The ESP WebSocket client is an implementation of `WebSocket protocol client <https://tools.ietf.org/html/rfc6455>`_ for {IDF_TARGET_NAME}

Features
--------
   * Supports WebSocket over TCP, TLS with mbedtls
   * Easy to setup with URI
   * Multiple instances (Multiple clients in one application)

Configuration
-------------
URI
^^^

-  Supports ``ws``, ``wss`` schemes
-  WebSocket samples:

   -  ``ws://echo.websocket.org``: WebSocket over TCP, default port 80
   -  ``wss://echo.websocket.org``: WebSocket over SSL, default port 443

Minimal configurations:

.. code:: c

    const esp_websocket_client_config_t ws_cfg = {
        .uri = "ws://echo.websocket.org",
    };

The WebSocket client supports the use of both path and query in the URI. Sample:

.. code:: c

    const esp_websocket_client_config_t ws_cfg = {
        .uri = "ws://echo.websocket.org/connectionhandler?id=104",
    };


If there are any options related to the URI in
:cpp:type:`esp_websocket_client_config_t`, the option defined by the URI will be
overridden. Sample:

.. code:: c

    const esp_websocket_client_config_t ws_cfg = {
        .uri = "ws://echo.websocket.org:123",
        .port = 4567,
    };
    //WebSocket client will connect to websocket.org using port 4567

TLS
^^^

Configuration:

.. code:: c

    const esp_websocket_client_config_t ws_cfg = {
        .uri = "wss://echo.websocket.org",
        .cert_pem = (const char *)websocket_org_pem_start,
    };

.. note:: If you want to verify the server, then you need to provide a certificate in PEM format, and provide to ``cert_pem`` in :cpp:type:`websocket_client_config_t`. If no certficate is provided then the TLS connection will default to not requiring verification.

PEM certificate for this example could be extracted from an openssl `s_client` command connecting to websocket.org.
In case a host operating system has `openssl` and `sed` packages installed, one could execute the following command to download and save the root or intermediate root certificate to a file (Note for Windows users: Both Linux like environment or Windows native packages may be used). ::

    echo "" | openssl s_client -showcerts -connect websocket.org:443 \
        | sed -n "1,/Root/d; /BEGIN/,/END/p" \
        | openssl x509 -outform PEM \
        > websocket_org.pem

This command will extract the second certificate in the chain and save it as a pem-file.

Mutual TLS with DS Peripheral
"""""""""""""""""""""""""""""

To leverage the Digital Signature (DS) peripheral on supported targets, use `esp_secure_cert_mgr <https://github.com/espressif/esp_secure_cert_mgr/>`_ to flash an encrypted client certificate. In your project, add the dependency: ::

    idf.py add-dependency esp_secure_cert_mgr

Set ``client_cert`` and ``client_ds_data`` in the config struct:

.. code:: c

    char *client_cert = NULL;
    uint32_t client_cert_len = 0;
    esp_err_t err = esp_secure_cert_get_device_cert(&client_cert, &client_cert_len);
    assert(err == ESP_OK);

    esp_ds_data_ctx_t *ds_data = esp_secure_cert_get_ds_ctx();
    assert(ds_data != NULL);

    esp_websocket_client_config_t config = {
        .uri = "wss://echo.websocket.org",
        .cert_pem = (const char *)websocket_org_pem_start,
        .client_cert = client_cert,
        .client_ds_data = ds_data,
    };

.. note:: ``client_cert`` provided by `esp_secure_cert_mgr` is a null-terminated PEM; so ``client_cert_len`` (DER format) should not be set.

Subprotocol
^^^^^^^^^^^

The subprotocol field in the config struct can be used to request a subprotocol

.. code:: c

    const esp_websocket_client_config_t ws_cfg = {
        .uri = "ws://websocket.org",
        .subprotocol = "soap",
    };

.. note:: The client is indifferent to the subprotocol field in the server response and will accept the connection no matter what the server replies.

For more options on :cpp:type:`esp_websocket_client_config_t`, please refer to API reference below

Events
------
* `WEBSOCKET_EVENT_BEGIN`: The client thread is running.
* `WEBSOCKET_EVENT_BEFORE_CONNECT`: The client is about to connect.
* `WEBSOCKET_EVENT_CONNECTED`: The client has successfully established a connection to the server. The client is now ready to send and receive data. Contains no event data.
* `WEBSOCKET_EVENT_DATA`: The client has successfully received and parsed a WebSocket frame. The event data contains a pointer to the payload data, the length of the payload data as well as the opcode of the received frame. A message may be fragmented into multiple events if the length exceeds the buffer size. This event will also be posted for non-payload frames, e.g. pong or connection close frames.
* `WEBSOCKET_EVENT_ERROR`: The client has experienced an error. Examples include transport write or read failures.
* `WEBSOCKET_EVENT_DISCONNECTED`: The client has aborted the connection due to the transport layer failing to read data, e.g. because the server is unavailable. Contains no event data.
* `WEBSOCKET_EVENT_CLOSED`: The connection has been closed cleanly.
* `WEBSOCKET_EVENT_FINISH`: The client thread is about to exit.

If the client handle is needed in the event handler it can be accessed through the pointer passed to the event handler:

.. code:: c

    esp_websocket_client_handle_t client = (esp_websocket_client_handle_t)handler_args;


Limitations and Known Issues
----------------------------
* The client is able to request the use of a subprotocol from the server during the handshake, but does not do any subprotocol related checks on the response from the server.

Application Example
-------------------
A simple WebSocket example that uses esp_websocket_client to establish a websocket connection and send/receive data with the `websocket.org <https://websocket.org>`_ server can be found here: `example <https://github.com/espressif/esp-protocols/tree/master/components/esp_websocket_client/examples>`_

Sending Text Data
^^^^^^^^^^^^^^^^^
The WebSocket client supports sending data as a text data frame, which informs the application layer that the payload data is text data encoded as UTF-8. Example:

.. code:: cpp

    esp_websocket_client_send_text(client, data, len, portMAX_DELAY);


API Reference
-------------

.. include-build-file:: inc/esp_websocket_client.inc
