第 1 章 - HTTP 和 HTTPS 的简介

超文本传输协议 (Hypertext Transfer Protocol, HTTP) 是设计用于在 Web 上传输内容的协议。 HTTP 是一种简单协议,它利用可靠的传输控制协议 (Transmission Control Protocol, TCP) 服务来执行其内容传输功能。 因此,HTTP 是高度可靠的内容传输协议。 HTTP 是最常用的应用程序协议之一。 Web 上的所有操作都使用 HTTP 协议。

HTTPS 是 HTTP 协议的安全版本,它使用传输层安全性 (Transport Layer Security, TLS) 来实现 HTTP,以确保基础 TCP 连接的安全。 除了设置 TLS 所需的其他配置以外,HTTPS 基本上与目前使用的 HTTP 完全相同。

常规 HTTP 要求

若要正常运行,NetX Web HTTP 包需要安装 NetX Duo(5.10 或更高版本)。 此外,必须创建一个 IP 实例,并且必须在该 IP 实例上启用 TCP。 如需 HTTPS 支持,还必须安装 NetX Secure TLS(5.11 或更高版本)(参阅下一节)。 第 2 章的“小型示例系统”一节中的演示文件将演示如何执行此操作。

NetX Web HTTP 包的 HTTP 客户端部分没有其他要求。

NetX Web HTTP 包的 HTTP 服务器部分有几个附加要求。 首先,它需要具备 TCP 已知端口 80 的完全访问权限,以便处理所有客户端 HTTP 请求(此端口可由应用程序更改为任何其他有效的 TCP 端口)。 HTTP 服务器还设计用于与 FileX 嵌入式文件系统配合使用。 如果 FileX 不可用,用户可以将使用的 FileX 部分移植到他们自己的环境中。 本指南后面的部分将对此进行讨论。

HTTPS 要求

若要 HTTPS 正常运行,NetX Web HTTP 包要求既安装 NetX Duo(5.10 或更高版本)又NetX Secure TLS(5.11 或更高版本)。 此外,必须创建 IP 实例,并在与 TLS 配合使用的相同 IP 实例上启用 TCP。 需要使用适当的加密例程和受信任的 CA 证书初始化 TLS 会话,并且必须为远程服务器主机在 TLS 握手期间提供的证书分配空间。 第 2 章的“小型示例 HTTPS 系统”一节中的演示文件将演示如何执行此操作。

NetX Web HTTP 包的 HTTPS 客户端部分没有其他要求。

NetX Web HTTP 包的 HTTPS 服务器部分有几个附加要求。 首先,它需要具备 TCP 已知端口 443 的完全访问权限,以便处理所有客户端 HTTPS 请求(和明文 HTTP 一样,此端口可由应用程序进行更改)。 其次,需要使用适当的加密例程和服务器身份证书(或预共享密钥)初始化 TLS 会话。 HTTPS 服务器还设计为与 FileX 嵌入式文件系统配合使用。 如果 FileX 不可用,用户可以将使用的 FileX 部分移植到他们自己的环境中。 本指南后面的部分将讨论 FileX 的用法。

有关 TLS 的配置选项的详细信息,请参阅 NetX Secure 文档。

除非另有说明,否则本文档介绍的所有 HTTP 功能也适用于 HTTPS。

HTTP 和 HTTPS 的限制

NetX Web HTTP 实现 HTTP 1.1 标准。 但是,存在以下限制:

  1. 不支持请求流水线处理
  2. HTTP 服务器支持基本身份验证和 MD5 摘要式身份验证,但不支持 MD5-sess 身份验证。 目前,HTTP 客户端仅支持基本身份验证。 对 HTTPS 使用 TLS 时,仍可以使用 HTTP 身份验证。
  3. 不支持内容压缩。
  4. 不支持 TRACE、OPTIONS 和 CONNECT 请求。
  5. 与 HTTP 服务器或客户端关联的数据包池必须足够大以容纳完整的 HTTP 标头。
  6. HTTP 客户端服务仅用于内容传输,此包中未提供任何显示实用工具。

HTTP URL(资源名称)

HTTP 协议设计用于在 Web 上传输内容。 请求的内容由统一资源定位器 (URL) 指定。 这是每个 HTTP 请求的主要组件。 URL 始终以“/”字符开头,通常与 HTTP 服务器上的文件相对应。 常见的 HTTP 文件扩展名如下所示:

  • .htm(或 .html ):超文本标记语言 (Hypertext Markup Language, HTML)
  • .txt:ASCII 纯文本
  • .gif:二进制 GIF 图像
  • .xbm:二进制 Xbitmap 图像

HTTP 客户端请求

HTTP 采用简单的机制来请求 Web 内容。 在已知的 TCP 端口 80(使用 HTTPS 时是端口 443)上成功建立连接后,客户端会发出一组标准 HTTP 命令。 下面是一些基本的 HTTP 命令:

  • GET resource HTTP/1.1:获取指定的资源
  • POST resource HTTP/1.1:获取指定的资源并将附加的输入传递到 HTTP 服务器
  • HEAD resource HTTP/1.1:与 GET 类似,但 HTTP 服务器不会返回任何内容
  • PUT resource HTTP/1.1:在 HTTP 服务器上放置资源
  • DELETE resource HTTP/1.1:删除服务器上的资源

这些 ASCII 命令由 Web 浏览器和 NetX Web HTTP 客户端服务在内部生成,用于通过 HTTP 服务器执行 HTTP 操作。

请注意,HTTP 客户端应用程序应使用端口80,如果使用 HTTPS,则应使用端口 443。 客户端和服务器 HTTP API 都将此端口作为参数,为了方便起见,系统还定义了以下宏:NX_WEB_HTTP_SERVER_PORT(端口 80)和 NX_WEB_HTTPS_SERVER_PORT(端口 443)。 还可以使用 nx_web_http_client_set_connect_port() 服务在运行时更改 HTTP 服务器端口。 有关此服务的更多详细信息,请参阅第 4 章。

HTTP 服务器响应

HTTP 服务器还使用同一个已知的 TCP 端口 80(使用 HTTPS 时是端口 443)发送客户端命令响应。 HTTP 服务器处理客户端命令之后,会返回 ASCII 响应字符串,其中包含 3 位数状态代码。 HTTP 客户端软件使用数值响应来确定操作是成功还是失败。 下面列出了对客户端命令的各种 HTTP 服务器响应:

  • 200:请求成功
  • 400:请求的格式不正确
  • 401:未经授权的请求,客户端需要发送身份验证
  • 404:找不到请求中的指定资源
  • 500:内部 HTTP 服务器错误
  • 501:HTTP 服务器未实现该请求
  • 502:服务不可用

例如,当放置文件“test.htm”的客户端请求成功时,响应消息为“HTTP/1.1 200 OK”。

HTTP 通信

如前所述,HTTP 服务器使用已知的 TCP 端口 80(使用 HTTPS 时是端口 443)来处理客户端请求。 HTTP 客户端可能会将任何可用的 TCP 端口用于传出连接。 HTTP 事件的一般顺序如下:

HTTP GET 请求:

  1. 客户端发起与服务器端口 80(使用 HTTPS 时是端口 443)的 TCP 连接。
  2. 如果正在使用 HTTPS,建立 TCP 连接后,即会执行 TLS 握手来对服务器进行身份验证,并建立一个安全通道。
  3. 客户端发送“GET resource HTTP/1.1”请求(以及其他标头信息)。
  4. 服务器生成“HTTP/1.1 200 OK”消息和附加信息,后面紧跟资源内容(如果有)。
  5. 服务器断开与客户端的连接(如果正在使用 HTTPS,则会关闭 TLS)。
  6. 客户端断开与套接字的连接(TLS 在服务器发出断开连接警报后关闭)。

HTTP PUT 请求:

  1. 客户端发起与服务器端口 80(或端口 443)的 TCP 连接。
  2. 如果正在使用 HTTPS,建立 TCP 连接后,即会执行 TLS 握手来对服务器进行身份验证,并建立一个安全通道。
  3. 客户端发送“PUT resource HTTP/1.1”请求以及其他标头信息,后跟资源内容。
  4. 服务器生成“HTTP/1.1 200 OK”消息和附加信息,后面紧跟资源内容。
  5. 服务器断开连接。
  6. 客户端断开连接。

注意

如前所述,对于使用备用端口连接到客户端的 Web 服务器,HTTP 客户端可在运行时使用 nx_web_http_client_set_connect_port() 将默认连接端口(80 或 443)更改为其他端口。

HTTP 身份验证

HTTP 身份验证是可选的,并非所有 Web 请求都需要。 有两种形式的身份验证,即基本身份验证和摘要式身份验证 。 基本身份验证相当于许多协议中的名称和密码身份验证。 在 HTTP 基本身份验证中,名称和密码采用 base64 格式进行连接和编码。 基本身份验证的主要缺点是,名称和密码会在请求中公开传输。 这样,名称和密码容易被盗用。 摘要式身份验证从不在请求中传输名称和密码,因此解决了这个问题。 相反,此身份验证使用某种算法根据名称、密码和其他信息派生一个 128 位的摘要。 NetX Web HTTP 服务器支持标准 MD5 摘要算法。

何时需要身份验证? 请求的资源是否需要身份验证由 HTTP 服务器决定。 如果需要身份验证,并且客户端请求不包含适当的身份验证,服务器会向客户端发送“HTTP/1.1 401 Unauthorized”响应和所需的身份验证类型。 因此,客户端需要构建具有适当身份验证的新请求。

使用 HTTPS 时,HTTPS 服务器仍可使用 HTTP 身份验证。 在这种情况下,系统将采用 TLS 对所有 HTTP 流量加密,因此使用 HTTP 基本身份验证不会带来安全风险。 也可以使用摘要式身份验证,但与基于 TLS 的基本身份验证相比,这种验证方式并未显著提高安全性。

HTTP 身份验证回调

如前所述,HTTP 身份验证是可选的,并非所有 Web 传输都需要。 此外,身份验证通常与资源相关。 访问服务器上的某些资源需要身份验证,而访问其他资源则不需要。 使用 NetX Web HTTP 服务器包,应用程序可以(通过 nx_web_http_server_create 调用)指定身份验证回调例程,该例程在开始处理每个 HTTP 客户端请求时调用。

回调例程可向 NetX Web HTTP 服务器提供与资源关联的用户名、密码和领域字符串,并返回必要的身份验证类型。 如果资源不需要身份验证,身份验证回调应返回 NX_WEB_HTTP_DONT_AUTHENTICATE 的值。 如果指定的资源需要基本身份验证,此例程应返回 NX_WEB_HTTP_BASIC_AUTHENTICATE。 最后,如果需要 MD5 摘要式身份验证,回调例程应返回 NX_WEB_HTTP_DIGEST_AUTHENTICATE。 如果 HTTP 服务器提供的所有资源都不需要身份验证,则不需要回调,并且可以向 HTTP 服务器 create 调用提供空指针。

应用程序身份验证回调例程的格式很简单,定义如下:

UINT nx_web_http_server_authentication_check(NX_WEB_HTTP_SERVER *server_ptr,
    UINT request_type, CHAR *resource,
    CHAR **name, CHAR **password,
    CHAR **realm);

输入参数定义如下:

  • request_type - 指定 HTTP 客户端请求,有效请求定义为:
    • NX_WEB_HTTP_SERVER_GET_REQUEST
    • NX_WEB_HTTP_SERVER_POST_REQUEST
    • NX_WEB_HTTP_SERVER_HEAD_REQUEST
    • NX_WEB_HTTP_SERVER_PUT_REQUEST
    • NX_WEB_HTTP_SERVER_DELETE_REQUEST
  • resource - 请求的特定资源。
  • name - 指向所需用户名的指针。
  • password - 指向所需密码的指针。
  • realm - 指向此身份验证领域的指针。

身份验证例程的返回值指定了是否需要身份验证。 如果身份验证回调例程返回 NX_WEB_HTTP_DONT_AUTHENTICATE,则不使用 name 指针、password 指针和 realm 指针。 否则,HTTP 服务器开发人员必须确保 nx_web_http_server.h 中定义的 NX_WEB_HTTP_MAX_USERNAME 和 NX_WEB_HTTP_MAX_PASSWORD 足够大,以便容纳身份验证回调中指定的用户名和密码。 这些参数的默认大小均为 20 个字符。

用于验证用户名/密码是否无效的 HTTP 回调

如果 HTTP 服务器收到的客户端请求中的用户名和密码组合无效,则会调用 NetX Web HTTP 服务器中用于验证用户名/密码是否无效的可选回调。 如果 HTTP 服务器应用程序向 HTTP 服务器注册了回调,则会在 nx_web_http_server_get_process()、nx_web_http_server_put_process() 或 nx_web_http_server_delete_process() 中的基本身份验证或摘要式身份验证失败时调用该回调。

为了向 HTTP 服务器注册回调,系统为 NetX Web HTTP 服务器定义了以下服务。

UINT nx_web_http_server_invalid_userpassword_notify_set(
    NX_WEB_HTTP_SERVER *http_server_ptr,
    UINT (*invalid_username_password_callback)
        (CHAR *resource, ULONG *client_nx_address,
        UINT request_type));

请求类型定义如下:

  • NX_WEB_HTTP_SERVER_GET_REQUEST
  • NX_WEB_HTTP_SERVER_POST_REQUEST
  • NX_WEB_HTTP_SERVER_HEAD_REQUEST
  • NX_WEB_HTTP_SERVER_PUT_REQUEST
  • NX_WEB_HTTP_SERVER_DELETE_REQUEST

用于插入 GMT 日期标头的 HTTP 回调

NetX Web HTTP 服务器提供用于在其响应消息中插入日期标头的可选回调。 当 HTTP 服务器响应 put 或 get 请求时,将调用此回调。

为了向 HTTP 服务器注册 GMT 日期回调,系统定义了以下服务:

UINT nx_web_http_server_gmt_callback_set(
    NX_WEB_HTTP_SERVER *server_ptr,
    VOID (*gmt_get)(NX_WEB_HTTP_SERVER_DATE *date);

NX_WEB_HTTP_SERVER_DATE 数据类型定义如下:

typedef struct NX_WEB_HTTP_SERVER_DATE_STRUCT
{
    USHORT nx_web_http_server_year; /* Year */
    UCHAR nx_web_http_server_month; /* Month */
    UCHAR nx_web_http_server_day; /* Day */
    UCHAR nx_web_http_server_hour; /* Hour */
    UCHAR nx_web_http_server_minute; /* Minute */
    UCHAR nx_web_http_server_second; /* Second */
    UCHAR nx_web_http_server_weekday; /* Weekday */
} NX_WEB_HTTP_SERVER_DATE;

用于获取缓存信息的 HTTP 回调

HTTP 服务器提供用于从 HTTP 应用程序请求特定资源的最长期限和日期的回调。 此信息用于确定 HTTP 服务器是否在对客户端 Get 请求的响应中发送整页。 如果在客户端请求中找不到“If-Modified-Since”,或者它与用于获取缓存的回调所返回的“Last-Modified”日期不匹配,则会发送整页。

为了向 HTTP 服务器注册此回调,系统定义了以下服务:

UINT nx_web_http_server_cache_info_callback_set(
    NX_WEB_HTTP_SERVER *server_ptr,
    UINT (*cache_info_get)
    (CHAR *, UINT *, NX_WEB_HTTP_SERVER_DATE *));

HTTP 分块传输编码支持

如果无法在发送 HTTP 消息之前确定消息总长度,则可使用分块传输编码功能,将消息作为一系列不带“Content-Length”标头字段的区块发送。 所有 HTTP 请求和响应消息都支持此功能。 接收方应支持此功能,并通过内部逻辑采用透明的方式处理区块标头。 发送方必须分别通过客户端和服务器调用 API nx_web_http_client_request_chunked_set 和 nx_web_http_server_response_chunked_set。

UINT nx_web_http_client_request_chunked_set(NX_WEB_HTTP_CLIENT *client_ptr,
    UINT chunk_size,
    NX_PACKET *packet_ptr);

UINT nx_web_http_server_response_chunked_set(NX_WEB_HTTP_SERVER *server_ptr,
    UINT chunk_size,
    NX_PACKET *packet_ptr);

有关这些服务的更多详细信息,请参阅第 3 章“HTTP 服务说明”中的说明。

HTTP 多部分支持

多用途 Internet 邮件扩展 (MIME) 最初适用于 SMTP 协议,但现已适用于 HTTP。 MIME 允许同一消息中包含混合的消息类型(例如,图像/jpg 和文本/纯文本)。 NetX Web HTTP 服务器提供了一些服务,用于确定来自客户端的包含 MIME 的 HTTP 消息中的内容类型。 若要启用 HTTP 多部分支持,并使用这些服务,必须定义配置选项 NX_WEB_HTTP_MULTIPART_ENABLE。

UINT nx_web_http_server_get_entity_header(NX_WEB_HTTP_SERVER *server_ptr,
    NX_PACKET **packet_pptr,
    UCHAR *entity_header_buffer,
    ULONG buffer_size);

UINT nx_web_http_server_get_entity_content(NX_WEB_HTTP_SERVER *server_ptr,
    NX_PACKET **packet_pptr,
    ULONG *available_offset,
    ULONG *available_length);

有关使用这些服务的更多详细信息,请参阅第 3 章“HTTP 服务说明”中的说明。

HTTP 多线程支持

用户可以同时从多个线程调用 NetX Web HTTP 客户端服务。 但在同一个线程中,对特定 HTTP 客户端实例的读取或写入请求应按顺序发出。

如果使用 HTTPS,则可从多个线程调用 NetX Web HTTP 客户端服务,但由于基础 TLS 功能增加了复杂性,因此每个线程都应该有一个独立的 HTTP 客户端实例(NX_WEB_HTTP_CLIENT 控制结构)。

HTTP RFC

NetX Web HTTP 符合 RFC1945“超文本传输协议 1.0”、RFC 2616“超文本传输协议 – HTTP/1.1”、RFC 2581“TCP 拥塞控制”、RFC 1122“Internet 主机要求”和相关的 RFC。

对于 HTTPS,NetX Web HTTP 符合 RFC 2818“HTTP over TLS”。