第 2 章 - HTTP 和 HTTPS 的安装和使用

本章介绍与安装、设置和使用 NetX Web HTTP 组件相关的各种问题。

产品分发

可在 https://github.com/azure-rtos/netxduo 上获取用于 NetX 的 HTTP。 此包包含三个源文件、两个包含文件,以及一个包含此文档的文件,如下所示:

  • nx_web_http_common.h:NetX Web HTTP 的常用头文件
  • nx_web_http_client.h:用于 NetX Web 的 HTTP 客户端的头文件
  • nx_web_http_server.h:用于 NetX Web 的 HTTP 服务器的头文件
  • nx_web_http_client.c:用于 NetX Web 的 HTTP 客户端的 C 源文件
  • nx_web_http_server.c:用于 NetX Web 的 HTTP 服务器的 C 源文件
  • nx_tcpserver.c:用于多个 TCP 套接字的 C 源文件
  • nx_tcpserver.h:用于定义 HTTPS 服务器符号的头文件
  • nx_md5.c:MD5 摘要算法
  • filex_stub.h:存根文件(如果 FileX 不存在)
  • nx_web_http.pdf:用于 NetX Web 的 HTTP 的说明
  • demo_netx_web_http.c:NetX Web HTTP 演示

HTTP 安装

若要使用 NetX Web HTTP,应将之前提到的全部分发文件复制到已安装 NetX Duo 的同一个目录。 例如,如果 NetX Duo 安装在目录“\threadx\arm7\green”中,NetX Web HTTP 客户端应用程序的 nx_web_http_client.h 和 nx_web_http_client.c 以及 NetX Web HTTP 服务器应用程序的 nx_web_http_server.h、nx_web_http_server.c、nx_tcpserver.c 和 nx_tcpserver.h 也应在此目录中。对于客户端和服务器应用程序,nx_web_http_common.h 也必须在此目录中。如果正在使用摘要式身份验证,还应将 nx_md5.c 复制到此目录中。 对于演示的“RAM 驱动程序”应用程序,应将 HTTP 客户端和服务器文件复制到相同的目录中。

如果使用 TLS,则应该有一个包含 TLS 源文件的单独的 NetX Secure 目录。

使用 HTTP

NetX Web HTTP 的使用非常简单。 基本上,应用程序代码必须在包含 tx_api.h、fx_api.h 和 nx_api.h 后,包含 nx_web_http_client.h 和/或 nx_web_http_server.h(系统会自动包含 nx_web_http_common.h)。 借助这些头文件,应用程序将能够分别使用 ThreadX、FileX 和 NetX Duo。 如需 HTTPS 支持,则必须在包含 nx_secure_tls.h 文件后包含上述头文件,以便提供 TLS 支持。

如果应用程序代码包含 HTTP 头文件,就能够执行本指南中后续内容指定的 HTTP 函数调用。 应用程序还必须在生成过程中链接 nx_web_http_client.c(用于 HTTP(S) 客户端)、nx_web_http_server.c 和 nx_tcpserver.c(用于 HTTP(S) 服务器)以及 nx_md5.c(用于摘要式身份验证)。 这些文件的编译方式必须与其他应用程序文件相同,并且其对象格式必须与应用程序的文件链接起来。 这就是使用 NetX Web HTTP 所需的全部内容。

注意

如果在生成过程中未指定 NX_WEB_HTTP_DIGEST_ENABLE,则无需将 md5.c 文件添加到应用程序中。 同样,如果不需要 HTTP 客户端功能,则可忽略 nx_web_http_client.c 文件,如果不需要 HTTP 服务器功能,则可忽略 nx_web_http_server.c。

除非为了启用 HTTPS(而不是只使用纯文本 HTTP)而定义了 NX_WEB_HTTPS_ENABLE,否则不需要在生成过程中包含 NetX Secure TLS。

由于 HTTP 采用 NetX TCP 服务,因此在使用 HTTP 之前,必须通过 nx_tcp_enable() 调用启用 TCP。

将 HTTPS 与 NetX Secure TLS 配合使用时,必须在调用 HTTPS 例程之前使用 nx_secure_tls_initialize() 初始化 TLS。

小型示例系统

下面的图 1.1 介绍了如何使用 NetX Web HTTP 的示例。

注意

此示例仅用于演示目的,不保证能够按原样编译和运行。

如需获取将在本机 Express Logic 环境中正确生成的演示源代码文件,请参阅 NetX Duo HTTPS 发行版代码分发。  另请注意,这些演示特意采用非常简单的设计,因为它们旨在向新用户介绍 HTTPS 和/或 NetX Duo HTTPS 应用程序。

在此示例中,HTTP 包含介绍的文件 nx_web_http_client.h 和 nx_web_http_server.h(netx_web_http_common.h 自动附带)。 接下来,系统将在“tx_application_define”中创建 HTTP 服务器。 请注意,HTTP 服务器控制块“Server”之前已定义为全局变量。 创建成功后,系统会启动 HTTPS 服务器。 然后创建 HTTPS 客户端。 该客户端写入文件,然后读回文件。

注意

NX_WEB_HTTPS_ENABLE 在此系统上定义。

/* This is a small demo of HTTPS on the high-performance NetX Duo TCP/IP stack.
   This demo relies on ThreadX, NetX Duo, and FileX to show an HTML
   transfer from the client and then back from the server.  */

#include  "tx_api.h"
#include  "fx_api.h"
#include  "nx_api.h"
#include  “nx_crypto.h”
#include  “nx_secure_tls_api.h”
#include  “nx_secure_x509.h”
#include  "nx_web_http_client.h"
#include  "nx_web_http_server.h"
#define    DEMO_STACK_SIZE         4096


/* Define the ThreadX and NetX object control blocks...  */

TX_THREAD               thread_0;
TX_THREAD               thread_1;
NX_PACKET_POOL          pool_0;
NX_PACKET_POOL          pool_1;
NX_IP                   ip_0;
NX_IP                   ip_1;
FX_MEDIA                ram_disk;

/* Define HTTP objects.  */

NX_WEB_HTTP_SERVER      my_server;
NX_WEB_HTTP_CLIENT      my_client;

/* Define the counters used in the demo application...  */

ULONG                   error_counter;


/* Define the RAM disk memory.  */

UCHAR                   ram_disk_memory[32000];

/* Include cryptographic routines for TLS. */
extern const NX_SECURE_TLS_CRYPTO nx_crypto_tls_ciphers;

/* Define TLS data for HTTPS. */
CHAR crypto_metadata[8928 * NX_WEB_HTTP_SESSION_MAX];
UCHAR tls_packet_buffer[16500];

/* NX_WEB_HTTP_SERVER_SESSION_MAX defaults to 2 in nx_web_http_server.h */
UCHAR server_tls_packet_buffer[16500 * NX_WEB_HTTP_SERVER_SESSION_MAX];

/* Define certificate containers. The server certificate is used to identify the NetX
   Web HTTPS server and the trusted certificate is used by the client to verify the
   server’s identity certificate.  */
NX_SECURE_X509_CERT server_certificate;
NX_SECURE_X509_CERT trusted_certificate;

/* Remote certificates need both an NX_SECURE_X509_CERT container and an associated
   buffer. The number of certificates depends on the remote host, but usually at least
   two certificates will be sent – the identity certificate for the host and the
   certificate that issued the identity certificate. */
NX_SECURE_X509_CERT remote_certificate, remote_issuer;

UCHAR remote_cert_buffer[2000];
UCHAR remote_issuer_buffer[2000];

/* Certificate information for server and client (see NetX Secure TLS reference on X.509
    certificates for more information). Arrays are populated with binary versions Of
    certificates and keys and the corresponding “len” variables are assigned the lengths
    of that data. Trusted certificates do not need a private key. */
const UCHAR server_cert_der[] = { … };
const UINT  server_cert_derlen = … ;
const UCHAR server_cert_key_der[] = { … };
const UINT  server_cert_key_derlen = … ;

const UCHAR trusted_cert_der[] = { … };
const UINT  trusted_cert_derlen = … ;


/* Define function prototypes.  */

void    thread_0_entry(ULONG thread_input);
VOID    _fx_ram_driver(FX_MEDIA *media_ptr) ;
void    _nx_ram_network_driver(struct NX_IP_DRIVER_STRUCT *driver_req);
UINT    authentication_check(NX_WEB_HTTP_SERVER *server_ptr, UINT request_type,
             CHAR *resource, CHAR **name, CHAR **password, CHAR **realm);
UINT tls_setup_callback(NX_WEB_HTTP_CLIENT *client_ptr,
   NX_SECURE_TLS_SESSION *tls_session);

/* Define the application's authentication check.  This is called by
   the HTTP server whenever a new request is received.  */
UINT  authentication_check(NX_WEB_HTTP_SERVER *server_ptr, UINT request_type,
            CHAR *resource, CHAR **name, CHAR **password, CHAR **realm)
{
    /* Just use a simple name, password, and realm for all
       requests and resources.  */
    *name =     "name";
    *password = "password";
    *realm =    "NetX Web HTTP demo";

    /* Request basic authentication.  */
    return(NX_WEB_HTTP_BASIC_AUTHENTICATE);
}

/* Define the TLS setup callback for HTTPS Client. This function is invoked when the
   HTTPS client is started – all TLS per-session initialization should go in here. */
UINT tls_setup_callback(NX_WEB_HTTP_CLIENT *client_ptr,
  NX_SECURE_TLS_SESSION *tls_session)
{
    UINT status;

    /* Initialize and create TLS session. */
    nx_secure_tls_session_create(tls_session, &nx_crypto_tls_ciphers,
        crypto_metadata, sizeof(crypto_metadata));

    /* Allocate space for packet reassembly. */
    nx_secure_tls_session_packet_buffer_set(tls_session, tls_packet_buffer,
        sizeof(tls_packet_buffer));


    /* Add a CA Certificate to our trusted store for verifying incoming server
        certificates. */
    nx_secure_x509_certificate_initialize(&trusted_certificate, trusted_cert_der,
        trusted_cert_der_len, NX_NULL, 0, NULL, 0,
        NX_SECURE_X509_KEY_TYPE_NONE);
    nx_secure_tls_trusted_certificate_add(tls_session, &trusted_certificate);

    /* Need to allocate space for the certificate coming in from the remote host. */
    nx_secure_tls_remote_certificate_allocate(tls_session, &remote_certificate,
        remote_cert_buffer, sizeof(remote_cert_buffer));
    nx_secure_tls_remote_certificate_allocate(tls_session,
        &remote_issuer, remote_issuer_buffer,
        sizeof(remote_issuer_buffer));

    return(NX_SUCCESS);
 }

/* Define main entry point.  */

 int main()
 {
     /* Enter the ThreadX kernel.  */
     tx_kernel_enter();
 }

/* Define what the initial system looks like.  */
void    tx_application_define(void *first_unused_memory)
{

    CHAR    *pointer;

    /* Setup the working pointer.  */
    pointer =  (CHAR *) first_unused_memory;

    /* Create the main thread.  */
    tx_thread_create(&thread_0, "thread 0", thread_0_entry, 0,
        pointer, DEMO_STACK_SIZE,
        2, 2, TX_NO_TIME_SLICE, TX_AUTO_START);
    pointer = pointer + DEMO_STACK_SIZE;

    /* Initialize the NetX system.  */
    nx_system_initialize();

    /* Create packet pool.  */
    nx_packet_pool_create(&pool_0, "NetX Packet Pool 0",
        600, pointer, 8192);
    pointer = pointer + 8192;

    /* Create an IP instance.  */
    nx_ip_create(&ip_0, "NetX IP Instance 0", IP_ADDRESS(1, 2, 3, 4),
        0xFFFFFF00UL, &pool_0, _nx_ram_network_driver,
        pointer, 4096, 1);
    pointer =  pointer + 4096;

    /* Create another packet pool. */
    nx_packet_pool_create(&pool_1, "NetX Packet Pool 1", 600, pointer, 8192);
    pointer = pointer + 8192;

    /* Create another IP instance.  */
    nx_ip_create(&ip_1, "NetX IP Instance 1", IP_ADDRESS(1, 2, 3, 5),
        0xFFFFFF00UL, &pool_1, _nx_ram_network_driver,
        pointer, 4096, 1);
    pointer = pointer + 4096;

    /* Enable ARP and supply ARP cache memory for IP Instance 0.  */
    nx_arp_enable(&ip_0, (void *) pointer, 1024);
    pointer = pointer + 1024;

    /* Enable ARP and supply ARP cache memory for IP Instance 1.  */
    nx_arp_enable(&ip_1, (void *) pointer, 1024);
    pointer = pointer + 1024;

    /* Enable TCP processing for both IP instances.  */
    nx_tcp_enable(&ip_0);
    nx_tcp_enable(&ip_1);

    /* Open the RAM disk.  */
    fx_media_open(&ram_disk, "RAM DISK",
        _fx_ram_driver, ram_disk_memory, pointer, 4096);
    pointer += 4096;

    /* Create the NetX Web HTTP Server.  */
    nx_web_http_server_create(&my_server, "My HTTP Server", &ip_1,
        NX_WEB_HTTPS_SERVER_PORT, &ram_disk,
        pointer, 4096, &pool_1, authentication_check, NX_NULL);
    pointer = pointer + 4096;

    /* The TLS server needs an identity certificate which is imported as a binary DER-
        encoded X.509 certificate and its associated private key (e.g. DER-encoded PKCS#1
        RSA private key). */
    nx_secure_x509_certificate_initialize(&server_certificate, server_cert_der,
        server_cert_der_len, NX_NULL, 0,
        server_cert_key_der, server_cert_key_der_len,
        NX_SECURE_X509_KEY_TYPE_RSA_PKCS1_DER);

    /* Setup TLS session data for the TCP server.
        This enables TLS and HTTPS for the server.  */
    nx_web_http_server_secure_configure(&my_server, &nx_crypto_tls_ciphers,
        crypto_metadata, sizeof(crypto_metadata), server_tls_packet_buffer,
        sizeof(server_tls_packet_buffer), &server_certificate, NX_NULL, 0,
        NX_NULL, 0, NX_NULL, 0);

    /* Start the HTTP Server.  */
    nx_web_http_server_start(&my_server);
}

/* Define the test thread.  */
void    thread_0_entry(ULONG thread_input)
{
    NX_PACKET   *my_packet;
    UINT        status;

    /* Create an HTTP client instance.  */
    status = nx_web_http_client_create(&my_client, "My Client", &ip_0, &pool_0, 600);

    /* Check status.  */
    if (status)
        error_counter++;

    /* Prepare to send the simple 103-byte HTML file to the Server over HTTPS.  */
    status = nx_web_http_client_put_secure_start(&my_client, IP_ADDRESS(1,2,3,5),
        NX_WEB_HTTPS_SERVER_PORT, "/test.htm", "name", "password", 103, tls_setup_callback, 50);

    /* Check status.  */
    if (status)
        error_counter++;

    /* Allocate a packet.  */
     tatus = nx_web_http_client_request_packet_allocate(&pool_0, &my_packet,
        NX_TCP_PACKET, NX_WAIT_FOREVER);

    /* Check status.  */
    if (status != NX_SUCCESS)
        return;

    /* Build a simple 103-byte HTML page.  */
    nx_packet_data_append(my_packet, "<HTML>\r\n", 8,
        &pool_0, NX_WAIT_FOREVER);
    nx_packet_data_append(my_packet,
        "<HEAD><TITLE>NetX HTTP Test</TITLE></HEAD>\r\n", 44,
        &pool_0, NX_WAIT_FOREVER);
    nx_packet_data_append(my_packet, "<BODY>\r\n", 8,
        &pool_0, NX_WAIT_FOREVER);
    nx_packet_data_append(my_packet, "<H1>NetX Test Page</H1>\r\n", 25,
        &pool_0, NX_WAIT_FOREVER);
    nx_packet_data_append(my_packet, "</BODY>\r\n", 9,
        &pool_0, NX_WAIT_FOREVER);
    nx_packet_data_append(my_packet, "</HTML>\r\n", 9,
        &pool_0, NX_WAIT_FOREVER);

    /* Complete the PUT by writing the total length.  */
    status =  nx_web_http_client_put_packet(&my_client, my_packet, 50);

    /* Check status.  */
    if (status)
        error_counter++;

    /* Now GET the file back!  */
    status =  nx_web_http_client_get_secure_start(&my_client, IP_ADDRESS(1,2,3,5),
        NX_WEB_HTTPS_SERVER_PORT, "/test.htm",
        "name", "password", tls_setup_callback, 50);
 
    /* Check status.  */
    if (status)
        error_counter++;

    /* Get a packet.  */
    status =  nx_web_http_client_response_body_get(&my_client, &my_packet, 20);

    /* Check for an error.  */
    if ((status) || (my_packet -> nx_packet_length != 103))
        error_counter++;

    /* Check to see if we have a packet.  */
    if (status == NX_SUCCESS)
    {

        /* Yes, release it!  */
        nx_packet_release(my_packet);
    }

    /* Make sure TLS shuts down properly. */
    nx_web_http_client_delete(&my_client);

    /* Flush the media.  */
    fx_media_flush(&ram_disk);
}

图 1.1 与 NetX 和 NetX Secure TLS 配合使用的 HTTPS 示例

配置选项

有多个配置选项用于生成用于 NetX 的 HTTP。 下面是所有选项的列表,其中包含每个选项的详细说明: 此处列出了默认值,但可以在包含 nx_web_http_client 和 nx_web_http_server 之前重新定义这些值:

  • NX_DISABLE_ERROR_CHECKING:如果定义此选项,则会删除基本的 HTTP 错误检查。 此选项通常在应用程序完成调试后使用。
  • NX_WEB_HTTP_DIGEST_ENABLE:如果定义此选项,则在 HTTPS 服务器上启用使用 MD5 摘要进行身份验证。 默认情况下未定义此选项。
  • NX_WEB_HTTP_SERVER_PRIORITY:HTTPS 服务器线程的优先级。 默认情况下,此值定义为 16,表示将优先级指定为 16。
  • NX_WEB_HTTP_NO_FILEX:如果定义此选项,则可为 FileX 依赖项提供存根。 如果定义此选项,无需进行任何更改,HTTPS 客户端即可正常工作。 HTTPS 服务器需要修改,或者用户必须创建几个 FileX 服务才能正常工作。
  • NX_WEB_HTTP_TYPE_OF_SERVICE:HTTPS TCP 请求所需的服务类型。 默认情况下,此值定义为 NX_IP_NORMAL,用于表示正常的 IP 数据包服务。
  • NX_WEB_HTTP_SERVER_THREAD_TIME_SLICE:在暂停相同优先级的线程之前允许服务器线程运行的计时器计时周期数。 默认值为 2。 请注意,此选项已弃用。
  • NX_FTP_FRAGMENT_OPTION:为 HTTP TCP 请求启用分段。 默认情况下,使用此值 NX_DONT_FRAGMENT 会禁用 HTTP TCP 分段。
  • NX_WEB_HTTP_SERVER_WINDOW_SIZE:服务器套接字窗口大小。 默认情况下,此值为 2048 个字节。
  • NX_WEB_HTTP_TIME_TO_LIVE:指定数据包在被丢弃之前可通过的路由器数量。 默认值设置为 0x80。
  • NX_WEB_HTTP_SERVER_TIMEOUT:指定内部服务将暂停的 ThreadX 时钟周期数。 默认值设置为 10 秒 (10 * NX_IP_PERIODIC_RATE)。
  • NX_WEB_HTTP_SERVER_TIMEOUT_ACCEPT:指定内部服务在内部 nx_tcp_server_socket_accept() 调用中将挂起的 ThreadX 时钟周期数。 默认值设置为 (10 * NX_IP_PERIODIC_RATE)。
  • NX_WEB_HTTP_SERVER_TIMEOUT_DISCONNECT:指定内部服务在内部 nx_tcp_socket_disconnect() 调用中将挂起的 ThreadX 时钟周期数。 默认值设置为 10 秒 (10 * NX_IP_PERIODIC_RATE)。
  • NX_WEB_HTTP_SERVER_TIMEOUT_RECEIVE:指定内部服务在内部 nx_tcp_socket_receive() 调用中将挂起的 ThreadX 时钟周期数。 默认值设置为 10 秒 (10 * NX_IP_PERIODIC_RATE)。
  • NX_WEB_HTTP_SERVER_TIMEOUT_SEND:指定内部服务在内部 nx_tcp_socket_send() 调用中将挂起的 ThreadX 时钟周期数。 默认值设置为 10 秒 (10 * NX_IP_PERIODIC_RATE)。
  • NX_WEB_HTTP_MAX_HEADER_FIELD:指定 HTTP 标头字段的最大大小。默认值为 256。
  • NX_WEB_HTTP_MULTIPART_ENABLE******:如果已定义,则允许 HTTPS 服务器支持多部分 HTTP 请求。 **
  • NX_WEB_HTTP_SERVER_MAX_PENDING:指定可以排队等待 HTTPS 服务器的连接数。 默认值设置为最大服务器会话数的两倍。
  • NX_WEB_HTTP_MAX_RESOURCE:指定客户端提供的“资源名称”中允许包含的字节数。 默认值设置为 40。
  • NX_WEB_HTTP_MAX_NAME:指定客户端提供的“用户名”中允许包含的字节数。 默认值设置为 20。
  • NX_WEB_HTTP_MAX_PASSWORD:指定客户端提供的“密码”中允许包含的字节数。 默认值设置为 20。
  • NX_WEB_HTTP_SERVER_SESSION_MAX:指定 HTTP 或 HTTPS 服务器的并行会话数。 系统为每个会话分配了 TCP 套接字和 TLS 会话(如果启用了 HTTPS)。 默认值设置为 2。
  • NX_WEB_HTTPS_ENABLE:如果已定义此宏,则会启用 TLS 和 HTTPS。 如果只需要明文 HTTP,请保留未定义状态以释放资源。 默认情况下,系统未定义此宏。
  • NX_WEB_HTTPS_KEEPALIVE_DISABLE:如果已定义此宏,则会禁用 HTTP“保持活动状态”功能。 默认情况下,系统未定义此宏。
  • NX_WEB_HTTP_SERVER_MIN_PACKET_SIZE:指定在创建服务器时指定的池中的数据包的最小大小。 为了确保完整的 HTTP 标头可以包含在一个数据包中,需要提供最小大小。 默认值设置为 600。
  • NX_WEB_HTTP_CLIENT_MIN_PACKET_SIZE:指定在创建客户端时指定的池中的数据包的最小大小。 为了确保完整的 HTTP 标头可以包含在一个数据包中,需要提供最小大小。 默认值设置为 600。
  • NX_WEB_HTTP_SERVER_RETRY_SECONDS:设置服务器套接字重新传输超时值(以秒为单位)。 默认值设置为 2。
  • NX_WEB_HTTP_ SERVER_RETRY_MAX:这会设置服务器套接字上的最大重新传输次数。 默认值设置为 10。
  • NX_WEB_HTTP_ SERVER_RETRY_SHIFT:此值用于设置下一个重新传输超时值。 系统将当前超时值乘以到目前为止的重新传输次数,再按套接字超时移位值进行移位。 默认值设置为 1,可将超时值加倍。
  • NX_WEB_HTTP_SERVER_RETRY_TRANSMIT_QUEUE_DEPTH:这会指定可在服务器套接字重新传输队列中排队的最大数据包数量。 如果排队的数据包数量达到此数量,则无法再发送更多数据包,除非释放一个或多个排队的数据包。 默认值设置为 20。