仓颉编程语言扩展库 API

仓颉编程语言扩展库(stdx)包含若干包,提供相关功能。

标准库为开发者提供了最通用的 API,而扩展库则专注于某一领域。如 compress 包提供压缩与解压缩能力,crypto 包提供加解密相关能力,net 包则专注于提供高效的网络协议解析和网络通信能力。

说明:

目前,官方提供的扩展库不随仓颉编译器、工具链一起发布,需要用户单独下载。

包列表

stdx 含若干包,提供了丰富的扩展功能:

包名功能
aspectCJaspectCJ 包提供 Cangjie 中面向切面编程(Aspect Oriented Programming, AOP)相关的能力。
compress.zlibcompress 包提供压缩解压功能。
crypto.cryptocrypto 包提供安全加密能力。
crypto.digestdigest 包提供常用的消息摘要算法。
crypto.keyskeys 包提供非对称加密和签名算法。
crypto.x509x509 包提供处理数字证书功能。
encoding.base64base 包提供字符串的 Base64 编码及解码。
encoding.hexhex 包提供字符串的 Hex 编码及解码。
encoding.jsonjson 包用于对 json 数据的处理,实现 String, JsonValue, DataModel 之间的相互转换。
encoding.json.streamjson.stream 包主要用于仓颉对象和 JSON 数据流之间的互相转换。
encoding.urlurl 包提供了 URL 相关的能力,包括解析 URL 的各个组件,对 URL 进行编解码,合并 URL 或路径等。 。
fuzzfuzz 包为开发者提供基于覆盖率反馈的仓颉 fuzz 引擎及对应的接口,开发者可以编写代码对 API 进行测试。
loglog 包提供了日志记录相关的能力。
loggerlogger 包提供文本格式和 JSON 格式日志打印功能。
net.httphttp 包提供 HTTP/1.1,HTTP/2,WebSocket 协议的 server、client 端实现。
net.tlstls 包用于进行安全加密的网络通信,提供创建 TLS 服务器、基于协议进行 TLS 握手、收发加密数据、恢复 TLS 会话等能力。
serializationserialization 包提供了序列化和反序列化能力。
unittest.dataunittest 模块提供了单元测试扩展能力。

使用指导

仓颉编程语言扩展库 stdx 二进制包包含静态(static)和 动态 (dynamic) 两部分,请按需引用。

二进制产物结构

二进制包解压出来的目录包含 dynamic 和 static 两个目录:

dynamic/stdx 是动态产物,包含动态文件、cjo、bc 文件。

static/stdx 是静态产物,包含静态文件、cjo、bc 文件。

包依赖

导入库名依赖包
import stdx.aspectCJ.*stdx.aspectCJ
import stdx.compress.zlip.*stdx.compress.zlib
import stdx.crypto.crypto.*stdx.crypto.crypto、stdx.crypto.digest
import stdx.crypto.digest.*stdx.crypto.digest
import stdx.crypto.keys.*stdx.crypto.keys、stdx.crypto.x509、stdx.encoding.hex、stdx.encoding.base64、stdx.crypto.crypto、stdx.crypto.digest
import stdx.crypto.x509.*stdx.crypto.x509、stdx.encoding.hex、stdx.encoding.base64、stdx.crypto.crypto、stdx.crypto.digest
import stdx.encoding.hex.*stdx.encoding.hex
import stdx.encoding.base64.*stdx.encoding.base64
import stdx.encoding.json.*stdx.encoding.json、stdx.serialization.serialization
import stdx.encoding.json.stream.*stdx.encoding.json.stream
import stdx.encoding.url.*stdx.encoding.url
import stdx.log.*stdx.log
import stdx.logger.*stdx.logger
import stdx.serialization.serialization.*stdx.serialization.serialization
import stdx.fuzz.fuzz.*stdx.fuzz.fuzz
import stdx.net.http .*stdx.net.http、stdx.net.tls、stdx.logger、stdx.log、stdx.encoding.url、stdx.encoding.json.stream、stdx.crypto.x509 、stdx.encoding.hex、stdx.encoding.base64、stdx.crypto.crypto、stdx.crypto.digest
import stdx.net.tls.*stdx.net.tls、stdx.crypto.x509、stdx.encoding.hex、stdx.encoding.base64、stdx.crypto.crypto、stdx.crypto.digest
import stdx.unittest.data.*stdx.encoding.json、stdx.serialization.serialization

代码中导入上述包,用 cjc 命令去编译代码,需要严格按照上述包的依赖的顺序去链接。 如果是用 cjpm 则无需关注。

如果使用静态库,在导入 crypto 和 net 库时,由于需要依赖系统符号,所以 Windows 操作系统 需要额外添加 -lcrypt32Linux 操作系统 需要额外添加 -ldl

cjc 使用命令示例

cjc 的介绍和编译请查看 cjc 编译选项章节

import stdx.aspectCJ.*
import stdx.compress.zlib.*
import stdx.crypto.crypto.*
import stdx.crypto.digest.*
import stdx.crypto.keys.*
import stdx.crypto.x509.*
import stdx.encoding.hex.*
import stdx.encoding.base64.*
import stdx.encoding.json.*
import stdx.encoding.url.*
import stdx.encoding.json.stream.*
import stdx.net.tls.*
import stdx.net.http.*
import stdx.log.*
import stdx.logger.*
import stdx.serialization.serialization.*
main() {
    0
}

Linux 和 mac 的编译命令:

$ cjc main.cj -L $CANGJIE_STDX_PATH -lstdx.aspectCJ -lstdx.encoding.json -lstdx.serialization.serialization -lstdx.net.http -lstdx.net.tls -lstdx.logger -lstdx.log -lstdx.encoding.url -lstdx.encoding.json.stream -lstdx.crypto.keys -lstdx.crypto.x509 -lstdx.encoding.hex -lstdx.encoding.base64 -lstdx.crypto.crypto -lstdx.crypto.digest  -lstdx.compress.zlib -lstdx.compress -ldl --import-path $CANGJIE_STDX_PATH -o main.out

windows 编译命令:

$ cjc main.cj -L $CANGJIE_STDX_PATH -lstdx.aspectCJ -lstdx.encoding.json -lstdx.serialization.serialization -lstdx.net.http -lstdx.net.tls -lstdx.logger -lstdx.log -lstdx.encoding.url -lstdx.encoding.json.stream -lstdx.crypto.keys -lstdx.crypto.x509 -lstdx.encoding.hex -lstdx.encoding.base64 -lstdx.crypto.crypto -lstdx.crypto.digest  -lstdx.compress.zlib -lstdx.compress -lcrypt32 --import-path $CANGJIE_STDX_PATH -o main.out

CANGJIE_STDX_PATH 是设置的 stdx 路径。

运行前 Linux 操作系统需要在 LD_LIBRARY_PATH 中设置扩展库的路径,Windows 操作系统需要在 PATH 中设置扩展库的路径,macOS 操作系统需要在 DYLD_LIBRARY_PATH 中设置扩展库的路径。

cjpm 使用示例

cjpm 的介绍和使用请查看 cjpm 手册。

cjpm.toml 增加如下配置:

[target.x86_64-unknown-linux-gnu]
  [target.x86_64-unknown-linux-gnu.bin-dependencies]
    path-option = ["${CANGJIE_STDX_PATH}"]

上面配置中 x86_64-unknown-linux-gnu 这是表示的系统架构信息,需要通过 cjc -v 获取。并替换成自己获取的系统信息。 CANGJIE_STDX_PATH 是设置的 stdx 路径。

stdx.aspectCJ

功能介绍

stdx.aspectCJ 包提供了 Cangjie 中面向切面编程(Aspect Oriented Programming, AOP)的相关注解,配合 libcollect-aspects 和 libwave-aspects 两个编译插件使用,可以对函数进行前后插桩以及替换实现。

API 列表

类名功能
InsertAtEntry一个注解类,提供一种切面能力。在注解所指定方法的入口,织入对被注解标注的函数的调用。
InsertAtExit一个注解类,提供一种切面能力。在注解所指定方法的退出点,织入对被注解标注的函数的调用。
ReplaceFuncBody一个注解类,提供一种切面能力。将注解所指定方法的方法体,替换为对被注解标注的函数的调用。

规格和使用

规格

标注范围:

  • 注解暂不支持标注在泛型函数上,也不支持织入泛型函数;
  • 注解只允许标注在 public 函数上;
  • 注解可以标注在全局函数上,支持:
    • 织入另一个全局函数,
    • 织入另一个实例成员函数,
    • 织入另一个静态成员函数;
  • 注解可以标注在静态成员函数上,支持:
    • 织入另一个全局函数,
    • 织入另一个实例成员函数,
    • 织入另一个静态成员函数;
  • 注解可以标注在实例成员函数上,支持:
    • 织入同类型的其它实例成员函数。

全局变量定义约束:

  • 定义了切面的包中,只允许定义基本类型(整型、浮点、Rune、Bool)字面值的全局变量,否则编译报错;若需要使用超规格的全局变量,需要将其定义在另外的包再导入使用,以避免在编译后可能产生的循环依赖;

形参约束:

  • 被标注 @InsertAtEntry/@InsertAtExit 的函数,其返回类型只能是 Unit;
  • 被标注 @ReplaceFuncBody 的函数,其返回类型应和被织入的函数的返回类型相同;
  • 被标注 @InsertAtEntry/@InsertAtExit/@ReplaceFuncBody 的函数如果没有形参,那么其织入后总是被无参调用 ;
  • 被标注 @InsertAtEntry/@InsertAtExit/@ReplaceFuncBody 的函数如果有形参,其形参列表应和被织入函数的源码形参列表相同,此外:
    • 特别地,如果被织入的函数是实例成员函数,那么需要将 this 参数显式地写在形参中;
    • 对于被标注 @ReplaceFuncBody 的函数,需要额外添加一个形参,形参的类型和被织入的函数相同,该形参表示被织入函数原始版本的闭包。

使用

要实现 AOP 的完整功能,除了使用上述的注解类来定义切面,还需要两个编译插件:

  • libcollect-aspects.so(.dll/.dylib)
  • libwave-aspects.so(.dll/.dylib)

这两个编译插件以动态库的形式在 stdx.aspectCJ 中提供,不同平台提供不同版本。

应先使用 libcollect-aspects,在编译时收集所有切面、连接点信息;再使用 libwave-aspects 进行二次编译,把之前收集的切面织入到连接点。

class InsertAtEntry

public class InsertAtEntry {
    public const init(packageName!: String, className!: String, methodName!: String, isStatic!: Bool, funcTypeStr!: String, recursive!: Bool)
}

功能:在注解所指定方法的入口,织入对被注解标注的函数的调用。注解所指定的方法和被注解标注的函数,需满足规格限制

const init(String, String, String, Bool, String, Bool)

public const init(packageName!: String, className!: String, methodName!: String, isStatic!: Bool, funcTypeStr!: String, recursive!: Bool)

功能:创建 InsertAtEntry 对象。

参数:

  • packageName: String - 被织入的函数的所属包名,如 "default", "std.core";
  • className: String - 如果被织入的函数是成员函数,则为函数所属类名;如果被织入的函数是全局函数,则为空;
  • methodName: String - 被织入的函数名称,如 "foo";
  • isStatic: Bool - 被织入的函数是否为静态成员函数;
  • funcTypeStr: String - 被织入的函数的类型字符串,不包括空格。对于自定义类型,类型定义所在的包名不可省略,且和类型名之间使用 . 分隔。不需要包括隐式的 this 形参的类型。如 "(Int64,std.core.Object)->Unit";
  • recursive: Bool - 当被织入的函数是成员函数时,表示是否对子类里的函数 override 版本也做织入;否则该字段应填 false。

class InsertAtExit

public class InsertAtExit {
    public const init(packageName!: String, className!: String, methodName!: String, isStatic!: Bool, funcTypeStr!: String, recursive!: Bool)
}

功能:在注解所指定方法的退出点,织入对被注解标注的函数的调用。注解所指定的方法和被注解标注的函数,需满足规格限制

const init(String, String, String, Bool, String, Bool)

public const init(packageName!: String, className!: String, methodName!: String, isStatic!: Bool, funcTypeStr!: String, recursive!: Bool)

功能:创建 InsertAtExit 对象。

参数:

  • packageName: String - 被织入的函数的所属包名,如 "default", "std.core";
  • className: String - 如果被织入的函数是成员函数,则为函数所属类名;如果被织入的函数是全局函数,则为空;
  • methodName: String - 被织入的函数名称,如 "foo";
  • isStatic: Bool - 被织入的函数是否为静态成员函数;
  • funcTypeStr: String - 被织入的函数的类型字符串,不包括空格。对于自定义类型,类型定义所在的包名不可省略,且和类型名之间使用 . 分隔。不需要包括隐式的 this 形参的类型。如 "(Int64,std.core.Object)->Unit";
  • recursive: Bool - 当被织入的函数是成员函数时,表示是否对子类里的函数 override 版本也做织入;否则该字段应填 false。

class ReplaceFuncBody

public class ReplaceFuncBody {
    public const init(packageName!: String, className!: String, methodName!: String, isStatic!: Bool, recursive!: Bool)
}

功能:将注解所指定方法的方法体,替换为对被注解标注的函数的调用。注解所指定的方法和被注解标注的函数,需满足规格限制

const init(String, String, String, Bool, Bool)

public const init(packageName!: String, className!: String, methodName!: String, isStatic!: Bool, recursive!: Bool)

功能:创建 ReplaceFuncBody 对象。

参数:

  • packageName: String - 被织入的函数的所属包名,如 "default", "std.core";
  • className: String - 如果被织入的函数是成员函数,则为函数所属类名;如果被织入的函数是全局函数,则为空;
  • methodName: String - 被织入的函数名称,如 "foo";
  • isStatic: Bool - 被织入的函数是否为静态成员函数;
  • recursive: Bool - 当被织入的函数是成员函数时,表示是否对子类里的函数 override 版本也做织入;否则该字段应填 false。

AOP 开发示例

下面是使用 @InsertAtEntry 完成在指定函数入口插桩的示例代码:

package AOP_demo1

import stdx.aspectCJ.*
import std.time.DateTime

@InsertAtEntry[packageName: "AOP_demo1", className: "", methodName: "printCurrentTime", isStatic: false, funcTypeStr: "()->Unit", recursive: false]
public func printCurrentTimeImpl() {
    println("----- ${DateTime.now()} -----")
}

public func printCurrentTime() {
    println("hi")
    println("bye")
}

main() {
    printCurrentTime()
    0
}

linux 平台编译命令:

cjc aop_demo1.cj --plugin=libcollect-aspects.so -o main	// 第一次编译,收集切面
cjc aop_demo1.cj --plugin=libwave-aspects.so -o main	// 第二次编译,织入切面

运行结果可能如下:

----- 2025-06-03T00:00:18.994507-07:00 -----
hi
bye

下面是使用 @InsertAtExit 完成在指定函数退出前插桩的示例代码:

package AOP_demo2

import stdx.aspectCJ.*
import std.time.DateTime

@InsertAtExit[packageName: "AOP_demo1", className: "", methodName: "printCurrentTime", isStatic: false, funcTypeStr: "()->std.core:String", recursive: false]
public func printCurrentTimeImpl() {
    println("----- ${DateTime.now()} -----")
}

public func printCurrentTime() {
    println("hi")
    println("bye")
    "done"
}

main() {
    println(printCurrentTime())
    0
}

linux 平台编译命令:

cjc aop_demo2.cj --plugin=libcollect-aspects.so -o main	// 第一次编译,收集切面
cjc aop_demo2.cj --plugin=libwave-aspects.so -o main	// 第二次编译,织入切面

运行结果可能如下:

hi
bye
----- 2025-06-03T00:04:59.996469-07:00 -----
done

下面是使用 @ReplaceFuncBody 完成替换指定函数函数体的示例代码:

package AOP_demo2

import stdx.aspectCJ.*
import std.time.DateTime

@ReplaceFuncBody[packageName: "AOP_demo1", className: "", methodName: "printCurrentTime", isStatic: false, recursive: false]
public func printCurrentTimeImpl(original: (String)->String) {
    println("----- ${DateTime.now()} -----")
    println(original("abc"))
    println("----- end -----")
    "def"
}

public func printCurrentTime(x: String): String {
    println(x)
    "456"
}

main() {
    println(printCurrentTime("123"))
    0
}

linux 平台编译命令:

cjc aop_demo2.cj --plugin=libcollect-aspects.so -o main	// 第一次编译,收集切面
cjc aop_demo2.cj --plugin=libwave-aspects.so -o main	// 第二次编译,织入切面

运行结果可能如下:

----- 2025-06-03T00:04:59.996469-07:00 -----
abc
456
----- end -----
def

stdx.compress.zlib

功能介绍

compress 提供压缩解压功能。

压缩是指用更少的比特表示数据,以便更高效地存储和传输数据。在实际应用中,压缩广泛应用于文件压缩、网页压缩、数据库备份等。

压缩功能的实现依赖于压缩算法,主流的压缩算法有 deflate、lz77、lzw 等,这些算法可以将数据中的冗余信息去除或者替换成更紧凑的表示形式,从而实现数据压缩的目的。目前使用自研的 deflate 算法。

基于 deflate 压缩算法,给压缩后数据加上首部和尾部,可封装成不同格式的压缩文件,如 deflate-raw(无封装)、gzip、zip、png 等。其中 zip 可用于多个文件的压缩和打包,gzip 仅包含一个压缩文件。目前支持的数据格式有 deflate-raw 和 gzip,暂不支持文件打包功能。

此外,支持设置压缩级别,更高的压缩级别对应着更高的压缩率和更慢的压缩速度,反之,更低的压缩级别对应着更低的压缩率和更快的压缩速度。

特别地,zlib 指的是压缩功能的一个实现库,zlib 包实现了 deflate 算法,并支持 deflate-raw 和 gzip 压缩格式。

本包使用自研 deflate 算法,支持 deflate-raw 和 gzip 数据格式,支持快速、默认、高压缩率三种压缩等级,压缩速度依次下降,压缩率依次提升。

本包提供流式压缩和解压功能,即支持从输入流读取数据,将其压缩或解压,并写入字节数组,或从字节数组中读取数据,将其压缩或解压,并写入输出流。

说明:

本包暂不支持文件打包功能。

API 列表

类名功能
CompressInputStream压缩输入流。
CompressOutputStream压缩输出流。
DecompressInputStream解压输入流。
DecompressOutputStream解压输出流。

枚举

枚举名功能
CompressLevel压缩等级。
WrapType压缩数据格式。

异常类

异常类名功能
ZlibExceptionzlib 包的异常类。

class CompressInputStream

public class CompressInputStream <: InputStream {
    public init(inputStream: InputStream, wrap!: WrapType = DeflateFormat, compressLevel!: CompressLevel = DefaultCompression, bufLen!: Int64 = 512)
}

功能:压缩输入流。

可将 CompressInputStream 实例通过构造函数绑定到任意 InputStream 类型输入流,通过循环调用 read(outBuf: Array) 函数,将该输入流中的数据压缩,并将压缩后的数据输出到传入的字节数组。

父类型:

  • InputStream

init(InputStream, WrapType, CompressLevel, Int64)

public init(inputStream: InputStream, wrap!: WrapType = DeflateFormat, compressLevel!: CompressLevel = DefaultCompression, bufLen!: Int64 = 512)

功能:构造一个压缩输入流。

需绑定一个输入流,可设置压缩数据格式、压缩等级、内部缓冲区大小(每次从输入流中读取多少数据进行压缩)。

参数:

  • inputStream: InputStream - 待压缩的输入流。
  • wrap!: WrapType - 压缩数据格式,默认值为 DeflateFormat
  • compressLevel!: CompressLevel - 压缩等级,默认值为 DefaultCompression
  • bufLen!: Int64 - 输入流缓冲区的大小,取值范围为 (0, Int64.Max],默认 512 字节。

异常:

  • ZlibException - 当 bufLen 小于等于 0,输入流分配内存失败,或压缩资源初始化失败,抛出异常。

func close()

public func close(): Unit

功能:关闭压缩输入流。

当前 CompressInputStream 实例使用完毕后必须调用此函数来释放其所占内存资源,以免造成内存泄漏。调用该函数前需确保 read 函数已返回 0,否则可能导致绑定的 InputStream 并未被全部压缩。

异常:

  • ZlibException - 如果释放压缩资源失败,抛出异常。

func read(Array<Byte>)

public func read(outBuf: Array<Byte>): Int64

功能:从绑定的输入流中读取数据并压缩,压缩后数据放入指定的字节数组中。

参数:

  • outBuf: Array<Byte> - 用来存放压缩后数据的缓冲区。

返回值:

  • Int64 - 如果压缩成功,返回压缩后字节数,如果绑定的输入流中数据已经全部压缩完成,或者该压缩输入流被关闭,返回 0。

异常:

  • ZlibException - 当 outBuf 为空,或压缩数据失败,抛出异常。

示例:

import stdx.compress.zlib.*
import std.fs.*
import std.io.*

main(): Unit {
    let arr1 = "Hello, World!Hello, World!Hello, World!Hello, World!Hello, World!".toArray()
    let byteBuffer = ByteBuffer(arr1)
    let bufferedInputStream = BufferedInputStream(byteBuffer)
    var compressInputStream: CompressInputStream = CompressInputStream(bufferedInputStream)
    var arr: Array<Byte> = Array<Byte>(1024, repeat: 0)
    println(arr1.size)
    var len = compressInputStream.read(arr)
    println(len)
    compressInputStream.close()
}

运行结果:

65
17

class CompressOutputStream

public class CompressOutputStream <: OutputStream {
    public init(outputStream: OutputStream, wrap!: WrapType = DeflateFormat, compressLevel!: CompressLevel = DefaultCompression, bufLen!: Int64 = 512)
}

功能:压缩输出流。

可将 CompressOutputStream 实例通过构造函数绑定到任意 OutputStream 类型输出流,调用 write(inBuf: Array) 函数读取、压缩指定字节数组中的数据,并将压缩后的数据输出到绑定的输出流。

父类型:

  • OutputStream

init(OutputStream, WrapType, CompressLevel, Int64)

public init(outputStream: OutputStream, wrap!: WrapType = DeflateFormat, compressLevel!: CompressLevel = DefaultCompression, bufLen!: Int64 = 512)

功能:构造一个压缩输出流,需绑定一个输出流,可设置压缩数据类型、压缩等级、内部缓冲区大小(每得到多少压缩后数据往输出流写出)。

参数:

  • outputStream: OutputStream - 绑定的输出流,压缩后数据将写入该输出流。
  • wrap!: WrapType - 压缩数据格式,默认值为 DeflateFormat
  • compressLevel!: CompressLevel - 压缩等级,默认值为 DefaultCompression
  • bufLen!: Int64 - 输出流缓冲区的大小,取值范围为 (0, Int64.Max],默认 512 字节。

异常:

  • ZlibException - 如果 bufLen 小于等于 0,输出流分配内存失败,或压缩资源初始化失败,抛出异常。

func close()

public func close(): Unit

功能:关闭当前压缩输出流实例。

关闭时,将写入剩余压缩数据(包括缓冲区中数据,以及压缩尾部信息),并释放其所占内存资源。当前压缩输出流使用完毕后必须调用此函数来释放其所占内存资源,以免造成内存泄漏。在调用 close 函数前,绑定的输出流里已写入的数据并不是一段完整的压缩数据,调用 close 函数后,才会把剩余压缩数据写入绑定的输出流,使其完整。

异常:

  • ZlibException - 如果当前压缩输出流已经被关闭,或释放压缩资源失败,抛出异常。

func flush()

public func flush(): Unit

功能:刷新压缩输出流。将内部缓冲区里已压缩的数据刷出并写入绑定的输出流,然后刷新绑定的输出流。

异常:

  • ZlibException - 如果当前压缩输出流已经被关闭,抛出异常。

func write(Array<Byte>)

public func write(inBuf: Array<Byte>): Unit

功能:将指定字节数组中的数据进行压缩,并写入输出流,当数据全部压缩完成并写入输出流,函数返回。

参数:

  • inBuf: Array<Byte> - 待压缩的字节数组。

异常:

  • ZlibException - 如果当前压缩输出流已经被关闭,或压缩数据失败,抛出异常。

示例:

import stdx.compress.zlib.*
import std.io.*

main(): Unit {
    var byteBuffer = ByteBuffer()
    var compressOutputStream: CompressOutputStream = CompressOutputStream(byteBuffer,bufLen:39)

    var arr = "Hello, World!Hello, World!Hello, World!".toArray()

    /* 将字节数组压缩后写入压缩输出流的缓冲区 */
    compressOutputStream.write(arr)

    /* 将内部缓冲区里已压缩的数据刷出并写入绑定的输出流,然后刷新绑定的输出流 */
    compressOutputStream.flush()
    
    /* 关闭压缩输出流 */
    compressOutputStream.close()
}

class DecompressInputStream

public class DecompressInputStream <: InputStream {
    public init(inputStream: InputStream, wrap!: WrapType = DeflateFormat, bufLen!: Int64 = 512)
}

功能:解压输入流。

可将 DecompressInputStream 实例通过构造函数绑定到任意 InputStream 输入流,通过循环调用 read(outBuf: Array) 函数读取、解压输入流中的数据,并将解压后数据输出到指定字节数组。

父类型:

  • InputStream

init(InputStream, WrapType, Int64)

public init(inputStream: InputStream, wrap!: WrapType = DeflateFormat, bufLen!: Int64 = 512)

功能:构造一个解压输入流。

需绑定一个输入流,可设置待解压数据格式、内部缓冲区大小(每次从输入流中读取多少数据进行解压)。

参数:

  • inputStream: InputStream - 待压缩的输入流。
  • wrap!: WrapType - 待解压数据格式,默认值为 DeflateFormat
  • bufLen!: Int64 - 输入流缓冲区的大小,取值范围为 (0, Int64.Max],默认 512 字节。

异常:

  • ZlibException - 如果 bufLen 小于等于 0,输入流分配内存失败,或待解压资源初始化失败,抛出异常。

func close()

public func close(): Unit

功能:关闭解压输入流。

当前 DecompressInputStream 实例使用完毕后必须调用此函数来释放其所占内存资源,以免造成内存泄漏。调用该函数前需确保 read 函数已返回 0,否则可能导致绑定的 InputStream 并未被全部解压。

异常:

  • ZlibException - 如果释放解压资源失败,抛出异常。

func read(Array<Byte>)

public func read(outBuf: Array<Byte>): Int64

功能:从绑定的输入流中读取数据并解压,解压后数据放入指定的字节数组中。

参数:

  • outBuf: Array<Byte> - 用来存放解压后数据的缓冲区。

返回值:

  • Int64 - 如果解压成功,返回解压后字节数,如果绑定的输入流中数据已经全部解压完成,或者该解压输入流被关闭,返回 0。

异常:

  • ZlibException - 当 outBuf 为空,或解压数据失败,抛出异常。

示例:

import stdx.compress.zlib.*
import std.fs.*
import std.io.*

main(): Unit {
    let arr1 = "Hello, World!Hello, World!Hello, World!Hello, World!Hello, World!".toArray()

    /* 使用压缩输入流进行数据压缩 */
    let byteBuffer = ByteBuffer(arr1)
    var compressInputStream: CompressInputStream = CompressInputStream(byteBuffer)
    var arr2: Array<Byte> = Array<Byte>(1024, repeat: 0)
    /* 原始数据长度 */
    println(arr1.size)
    var len1 = compressInputStream.read(arr2)
    /* 压缩后的数据长度 */
    println(len1)

    /* 使用解压缩输入流进行数据解压 */
    var decompressInputStream: DecompressInputStream = DecompressInputStream(ByteBuffer(arr2[..len1]))
    var arr3: Array<Byte> = Array<Byte>(1024, repeat: 0)
    var len2 = decompressInputStream.read(arr3)
    println(String.fromUtf8(arr3[..len2]))

    /* 关闭输入流 */
    compressInputStream.close()
    decompressInputStream.close()
}

运行结果:

65
17
Hello, World!Hello, World!Hello, World!Hello, World!Hello, World!

class DecompressOutputStream

public class DecompressOutputStream <: OutputStream {
    public init(outputStream: OutputStream, wrap!: WrapType = DeflateFormat, bufLen!: Int64 = 512)
}

功能:解压输出流。

可将 DecompressOutputStream 实例通过构造函数绑定到指定的 OutputStream 类型输出流,通过调用 write(inBuf: Array) 函数读取、解压指定字节数组中的数据,并将解压后数据输出到绑定的输出流中。

父类型:

  • OutputStream

init(OutputStream, WrapType, Int64)

public init(outputStream: OutputStream, wrap!: WrapType = DeflateFormat, bufLen!: Int64 = 512)

功能:构造一个解压输出流。

需绑定一个输出流,可设置压缩数据类型、压缩等级、内部缓冲区大小(解压后数据会存入内部缓冲区,缓冲区存满后再写到输出流)。

参数:

  • outputStream: OutputStream - 绑定的输出流,解压后数据将写入该输出流。
  • wrap!: WrapType - 待解压数据格式,默认值为 DeflateFormat
  • bufLen!: Int64 - 输出流缓冲区的大小,取值范围为 (0, Int64.Max],默认 512 字节。

异常:

  • ZlibException - 如果 bufLen 小于等于 0,输出流分配内存失败,或解压资源初始化失败,抛出异常。

func close()

public func close(): Unit

功能:关闭当前解压输出流实例。

关闭时,将写入剩余解压后数据,并释放其所占内存资源。当前压缩输出流使用完毕后必须调用此函数来释放其所占内存资源,以免造成内存泄漏。如果之前 write 函数已处理的压缩数据不完整,调用 close 函数时会因为解压数据不全而抛出异常。

异常:

  • ZlibException - 如果当前压缩输出流已经被关闭,通过 write 函数传入的待解压数据不完整,或释放压缩资源失败,抛出异常。

func flush()

public func flush(): Unit

功能:刷新解压输出流。将内部缓冲区里已解压的数据写入绑定的输出流,然后刷新绑定的输出流。

异常:

  • ZlibException - 如果当前解压输出流已经被关闭,抛出异常。

func write(Array<Byte>)

public func write(inBuf: Array<Byte>): Unit

功能:将指定字节数组中的数据进行解压,并写入输出流,当数据全部解压完成并写入输出流,函数返回。

参数:

  • inBuf: Array<Byte> - 待解压的字节数组。

异常:

  • ZlibException - 如果当前解压输出流已经被关闭,或解压数据失败,抛出异常。

示例:

import stdx.compress.zlib.*
import std.fs.*
import std.io.*

main(): Unit {
    let arr1 = "Hello, World!Hello, World!Hello, World!Hello, World!Hello, World!".toArray()

    /* 使用压缩输入流进行数据压缩 */
    let byteBuffer = ByteBuffer(arr1)
    var compressInputStream: CompressInputStream = CompressInputStream(byteBuffer)
    var arr2: Array<Byte> = Array<Byte>(1024, repeat: 0)
    /* 原始数据长度 */
    println(arr1.size)
    var len1 = compressInputStream.read(arr2)
    /* 压缩后的数据长度 */
    println(len1)

    /* 使用解压缩输出流进行数据解压后,将数据写入文件,文件的内容为原始数据 */
    var file = File("./file.text", ReadWrite)
    var decompressOutputStream: DecompressOutputStream = DecompressOutputStream(file)
    decompressOutputStream.write(arr2[..len1])
    decompressOutputStream.flush()

    /* 关闭输入流和输出流 */
    compressInputStream.close()
    decompressOutputStream.close()
    file.close()
}

运行结果:

65
17

枚举

enum CompressLevel

public enum CompressLevel {
    | BestCompression
    | BestSpeed
    | DefaultCompression
}

功能:压缩等级。

压缩等级决定了压缩率和压缩速度,目前支持三种压缩等级,压缩率由小到大,压缩速度由快到慢依次为:BestSpeed、DefaultCompression、BestCompression。

BestCompression

BestCompression

功能:构造一个压缩率优先的压缩等级枚举实例,表示压缩率最高,压缩速度相对降低。

BestSpeed

BestSpeed

功能:构造一个压缩速度优先的压缩等级枚举实例,表示压缩速度最快,压缩率相对较低。

DefaultCompression

DefaultCompression

功能:构造一个压缩等级枚举实例,表示默认压缩等级。

enum WrapType

public enum WrapType {
    | DeflateFormat
    | GzipFormat
}

功能:压缩数据格式。

目前支持 DeflateFormat 和 GzipFormat 两种格式。

DeflateFormat

DeflateFormat

功能:构造一个表示 Deflate 压缩数据格式的枚举实例。

GzipFormat

GzipFormat

功能:构造一个表示 Gzip 压缩数据格式的枚举实例。

异常类

class ZlibException

public class ZlibException <: Exception {
    public init(message: String)
}

功能:zlib 包的异常类。

父类型:

  • Exception

init(String)

public init(message: String)

功能:根据异常信息创建 ZlibException 实例。

参数:

  • message: String - 异常提示信息。

Deflate 格式数据的压缩和解压

示例:

import stdx.compress.zlib.*
import std.fs.*

main() {
    var arr: Array<Byte> = Array<Byte>(1024 * 1024, {i => UInt8(i % 256)})
    File.writeTo("./zlib1.txt", arr)

    if (compressFile("./zlib1.txt", "./zlib_copmressed1.zlib") <= 0) {
        println("Failed to compress file!")
    }

    if (decompressFile("./zlib_copmressed1.zlib", "./zlib_decopmressed1.txt") != arr.size) {
        println("Failed to decompress file!")
    }

    if (compareFile("./zlib1.txt", "./zlib_decopmressed1.txt")) {
        println("success")
    } else {
        println("failed")
    }

    remove("./zlib1.txt")
    remove("./zlib_copmressed1.zlib")
    remove("./zlib_decopmressed1.txt")
    return 0
}

func compressFile(srcFileName: String, destFileName: String): Int64 {
    var count: Int64 = 0
    var srcFile: File = File(srcFileName, Read)
    var destFile: File = File(destFileName, Write)

    var tempBuf: Array<UInt8> = Array<UInt8>(1024, repeat: 0)
    var compressOutputStream: CompressOutputStream = CompressOutputStream(destFile, wrap: DeflateFormat)
    while (true) {
        var readNum = srcFile.read(tempBuf)
        if (readNum > 0) {
            compressOutputStream.write(tempBuf.slice(0, readNum).toArray())
            count += readNum
        } else {
            break
        }
    }
    compressOutputStream.flush()
    compressOutputStream.close()

    srcFile.close()
    destFile.close()
    return count
}

func decompressFile(srcFileName: String, destFileName: String): Int64 {
    var count: Int64 = 0
    var srcFile: File = File(srcFileName, Read)
    var destFile: File = File(destFileName, Write)

    var tempBuf: Array<UInt8> = Array<UInt8>(1024, repeat: 0)
    var decompressInputStream: DecompressInputStream = DecompressInputStream(srcFile, wrap: DeflateFormat)
    while (true) {
        var readNum = decompressInputStream.read(tempBuf)
        if (readNum <= 0) {
            break
        }
        destFile.write(tempBuf.slice(0, readNum).toArray())
        count += readNum
    }
    decompressInputStream.close()

    srcFile.close()
    destFile.close()
    return count
}

func compareFile(fileName1: String, fileName2: String): Bool {
    return File.readFrom(fileName1) == File.readFrom(fileName2)
}

运行结果:

success

Gzip 格式数据的压缩和解压

示例:

import stdx.compress.zlib.*
import std.fs.*

main() {
    var arr: Array<Byte> = Array<Byte>(1024 * 1024, {i => UInt8(i % 256)})
    File.writeTo("./zlib.txt", arr)

    if (compressFile("./zlib.txt", "./zlib_copmressed.zlib") <= 0) {
        println("Failed to compress file!")
    }

    if (decompressFile("./zlib_copmressed.zlib", "./zlib_decopmressed.txt") != arr.size) {
        println("Failed to decompress file!")
    }

    if (compareFile("./zlib.txt", "./zlib_decopmressed.txt")) {
        println("success")
    } else {
        println("failed")
    }

    remove("./zlib.txt")
    remove("./zlib_copmressed.zlib")
    remove("./zlib_decopmressed.txt")
    return 0
}

func compressFile(srcFileName: String, destFileName: String): Int64 {
    var count: Int64 = 0
    var srcFile: File = File(srcFileName, Read)
    var destFile: File = File(destFileName, Write)

    var tempBuf: Array<UInt8> = Array<UInt8>(1024, repeat: 0)
    var compressOutputStream: CompressOutputStream = CompressOutputStream(destFile, wrap: GzipFormat, bufLen: 10000)
    while (true) {
        var readNum = srcFile.read(tempBuf)
        if (readNum > 0) {
            compressOutputStream.write(tempBuf.slice(0, readNum).toArray())
            count += readNum
        } else {
            break
        }
    }
    compressOutputStream.flush()
    compressOutputStream.close()

    srcFile.close()
    destFile.close()
    return count
}

func decompressFile(srcFileName: String, destFileName: String): Int64 {
    var count: Int64 = 0
    var srcFile: File = File(srcFileName, Read)
    var destFile: File = File(destFileName, Write)

    var tempBuf: Array<UInt8> = Array<UInt8>(1024, repeat: 0)
    var decompressInputStream: DecompressInputStream = DecompressInputStream(srcFile, wrap: GzipFormat, bufLen: 10000)
    while (true) {
        var readNum = decompressInputStream.read(tempBuf)
        if (readNum <= 0) {
            break
        }
        destFile.write(tempBuf.slice(0, readNum).toArray())
        count += readNum
    }
    decompressInputStream.close()

    srcFile.close()
    destFile.close()
    return count
}

func compareFile(fileName1: String, fileName2: String): Bool {
    return File.readFrom(fileName1) == File.readFrom(fileName2)
}

运行结果:

success

stdx.crypto.crypto

功能介绍

crypto 包提供安全随机数功能和提供国密 SM4 对称加解密。

使用本包需要外部依赖 OpenSSL 3 的 crypto 动态库文件,故使用前需安装相关工具。

  • 对于 Linux 操作系统,可参考以下方式:

    • 如果系统的包管理工具支持安装 OpenSSL 3 开发工具包,可通过这个方式安装,并确保系统安装目录下含有 libcrypto.so 和 libcrypto.so.3 这两个动态库文件,例如 Ubuntu 22.04 系统上可使用 sudo apt install libssl-dev 命令安装 libssl-dev 工具包;
    • 如果无法通过上面的方式安装,可自行下载 OpenSSL 3.x.x 源码编译安装软件包,并确保安装目录下含有 libcrypto.so 和 libcrypto.so.3 这两个动态库文件,然后可选择下面任意一种方式来保证系统链接器可以找到这些文件:
      • 在系统未安装 OpenSSL 的场景,安装时选择直接安装到系统路径下;
      • 安装在自定义目录的场景,将这些文件所在目录设置到环境变量 LD_LIBRARY_PATH 以及 LIBRARY_PATH 中。
  • 对于 Windows 操作系统,可按照以下步骤:

    • 自行下载 OpenSSL 3.x.x 源码编译安装 x64 架构软件包或者自行下载安装第三方预编译的供开发人员使用的 OpenSSL 3.x.x 软件包;
    • 确保安装目录下含有 libcrypto.dll.a(或 libcrypto.lib)、libcrypto-3-x64.dll 这两个库文件;
    • 将 libcrypto.dll.a(或 libcrypto.lib) 所在的目录路径设置到环境变量 LIBRARY_PATH 中,将 libcrypto-3-x64.dll 所在的目录路径设置到环境变量 PATH 中。
  • 对于 macOS 操作系统,可参考以下方式:

    • 使用 brew install openssl@3 安装,并确保系统安装目录下含有 libcrypto.dylib 和 libcrypto.3.dylib 这两个动态库文件;
    • 如果无法通过上面的方式安装,可自行下载 OpenSSL 3.x.x 源码编译安装软件包,并确保安装目录下含有 libcrypto.dylib 和 libcrypto.3.dylib 这两个动态库文件,然后可选择下面任意一种方式来保证系统链接器可以找到这些文件:
      • 在系统未安装 OpenSSL 的场景,安装时选择直接安装到系统路径下;
      • 安装在自定义目录的场景,将这些文件所在目录设置到环境变量 DYLD_LIBRARY_PATH 以及 LIBRARY_PATH 中。

说明:

如果未安装 OpenSSL 3 软件包或者安装低版本的软件包,程序可能无法使用并抛出相关异常 SecureRandomException:Can not load openssl library or function xxx。

API 列表

类名功能
SecureRandom安全随机数。
SM4提供国密SM4对称加解密。

结构体

结构体名功能
OperationMode对称加解密算法的工作模式。
PaddingMode对称加解密算法的工填充模式。

异常类

异常类名功能
SecureRandomException安全随机数异常类。

class SecureRandom

public class SecureRandom {
    public init(priv!: Bool = false)
}

功能:用于生成加密安全的伪随机数。

和 Random 相比,主要有三个方面不同:

  • 随机数种子: Random 使用系统时钟作为默认的种子,时间戳一样,结果就相同;SecureRandom 使用操作系统或者硬件提供的随机数种子,生成的是真随机数。

  • 随机数生成: Random 使用了梅森旋转伪随机生成器;SecureRandom 则使用了 openssl 库提供的 MD5 等随机算法,使用熵源生成真随机数;如果硬件支持,还可以使用硬件随机数生成器来生成安全性更强的随机数。

  • 安全性: Random 不能用于加密安全的应用或者隐私数据的保护,可以使用 SecureRandom

使用示例见 SecureRandom 使用

init(Bool)

public init(priv!: Bool = false)

功能:创建 SecureRandom 实例,可指定是否使用更加安全的加密安全伪随机生成器,加密安全伪随机生成器可用于会话密钥和证书私钥等加密场景。

参数:

  • priv!: Bool - 设置为 true 表示使用加密安全伪随机生成器。

func nextBits(UInt64)

public func nextBits(bits: UInt64): UInt64

功能:生成一个指定位长的随机整数。

参数:

  • bits: UInt64 - 要生成的随机数的位数,取值范围 (0, 64]。

返回值:

  • UInt64 - 生成的用户指定位长的随机数。

异常:

  • IllegalArgumentException - 如果 bits 等于 0,或大于 64,超过所能截取的 UInt64 长度,则抛出异常。
  • SecureRandomException - 当生成器不能正确生成随机数或生成随机数失败时,抛出异常。

func nextBool()

public func nextBool(): Bool

功能:获取一个随机的 Bool 类型实例。

返回值:

  • Bool - 一个随机的 Bool 类型实例。

异常:

  • SecureRandomException - 当生成器不能正确生成随机数或生成随机数失败时,抛出异常。

func nextBytes(Array<Byte>)

public func nextBytes(bytes: Array<Byte>): Unit

功能:生成随机数替换入参数组中的每个元素。

参数:

  • bytes: Array<Byte> - 被替换的数组。

异常:

  • SecureRandomException - 当生成器不能正确生成随机数或生成随机数失败时,抛出异常。

func nextBytes(Int32)

public func nextBytes(length: Int32): Array<Byte>

功能:获取一个指定长度的随机字节的数组。

参数:

  • length: Int32 - 要生成的随机字节数组的长度。

返回值:

  • Array<Byte> - 一个随机字节数组。

异常:

  • IllegalArgumentException - 当参数 length 小于等于 0,抛出异常。
  • SecureRandomException - 当生成器不能正确生成随机数或生成随机数失败时,抛出异常。

func nextFloat16()

public func nextFloat16(): Float16

功能:获取一个 Float16 类型且在区间 [0.0, 1.0) 内的随机数。

返回值:

  • Float16 - 一个 Float16 类型的随机数。

异常:

  • SecureRandomException - 当生成器不能正确生成随机数或生成随机数失败时,抛出异常。

func nextFloat32()

public func nextFloat32(): Float32

功能:获取一个 Float32 类型且在区间 [0.0, 1.0) 内的随机数。

返回值:

  • Float32 - 一个 Float32 类型的随机数。

异常:

  • SecureRandomException - 当生成器不能正确生成随机数或生成随机数失败时,抛出异常。

func nextFloat64()

public func nextFloat64(): Float64

功能:获取一个 Float64 类型且在区间 [0.0, 1.0) 内的随机数。

返回值:

  • Float64 - 一个 Float64 类型的随机数。

异常:

  • SecureRandomException - 当生成器不能正确生成随机数或生成随机数失败时,抛出异常。

func nextGaussianFloat16(Float16, Float16)

public func nextGaussianFloat16(mean!: Float16 = 0.0, sigma!: Float16 = 1.0): Float16

功能:默认获取一个 Float16 类型且符合均值为 0.0 标准差为 1.0 的高斯分布的随机数,其中均值是期望值,可解释为位置参数,决定了分布的位置,标准差可解释为尺度参数,决定了分布的幅度。

参数:

  • mean!: Float16 - 均值。
  • sigma!: Float16 - 标准差。

返回值:

  • Float16 - 一个 Float16 类型的随机数。

异常:

  • SecureRandomException - 当生成器不能正确生成随机数或生成随机数失败时,抛出异常。

func nextGaussianFloat32(Float32, Float32)

public func nextGaussianFloat32(mean!: Float32 = 0.0, sigma!: Float32 = 1.0): Float32

功能:默认获取一个 Float32 类型且符合均值为 0.0 标准差为 1.0 的高斯分布的随机数,其中均值是期望值,可解释为位置参数,决定了分布的位置,标准差可解释为尺度参数,决定了分布的幅度。

参数:

  • mean!: Float32 - 均值。
  • sigma!: Float32 - 标准差。

返回值:

  • Float32 - 一个 Float32 类型的随机数。

异常:

  • SecureRandomException - 当生成器不能正确生成随机数或生成随机数失败时,抛出异常。

func nextGaussianFloat64(Float64, Float64)

public func nextGaussianFloat64(mean!: Float64 = 0.0, sigma!: Float64 = 1.0): Float64

功能:默认获取一个 Float64 类型且符合均值为 0.0 标准差为 1.0 的高斯分布的随机数,其中均值是期望值,可解释为位置参数,决定了分布的位置,标准差可解释为尺度参数,决定了分布的幅度。

参数:

  • mean!: Float64 - 均值。
  • sigma!: Float64 - 标准差。

返回值:

  • Float64 - 一个 Float64 类型的随机数。

异常:

  • SecureRandomException - 当生成器不能正确生成随机数或生成随机数失败时,抛出异常。

func nextInt16()

public func nextInt16(): Int16

功能:获取一个 Int16 类型的随机数。

返回值:

  • Int16 - 一个 Int16 类型的随机数。

异常:

  • SecureRandomException - 当生成器不能正确生成随机数或生成随机数失败时,抛出异常。

func nextInt32()

public func nextInt32(): Int32

功能:获取一个 Int32 类型的随机数。

返回值:

  • Int32 - 一个 Int32 类型的随机数。

异常:

  • SecureRandomException - 当生成器不能正确生成随机数或生成随机数失败时,抛出异常。

func nextInt16(Int16)

public func nextInt16(max: Int16): Int16

功能:获取一个 Int16 类型且在区间 [0, max) 内的随机数。

参数:

  • max: Int16 - 区间最大值。

返回值:

  • Int16 - 一个 Int16 类型的随机数。

异常:

  • IllegalArgumentException - 当 max 为非正数时,抛出异常。
  • SecureRandomException - 当生成器不能正确生成随机数或生成随机数失败时,抛出异常。

func nextInt32(Int32)

public func nextInt32(max: Int32): Int32

功能:获取一个 Int32 类型且在区间 [0, max) 内的随机数。

参数:

  • max: Int32 - 区间最大值。

返回值:

  • Int32 - 一个 Int32 类型的随机数。

异常:

  • IllegalArgumentException - 当 max 为非正数时,抛出异常。
  • SecureRandomException - 当生成器不能正确生成随机数或生成随机数失败时,抛出异常。

func nextInt64()

public func nextInt64(): Int64

功能:获取一个 Int64 类型的随机数。

返回值:

  • Int64 - 一个 Int64 类型的随机数。

异常:

  • SecureRandomException - 当生成器不能正确生成随机数或生成随机数失败时,抛出异常。

func nextInt64(Int64)

public func nextInt64(max: Int64): Int64

功能:获取一个 Int64 类型且在区间 [0, max) 内的随机数。

参数:

  • max: Int64 - 区间最大值。

返回值:

  • Int64 - 一个 Int64 类型的随机数。

异常:

  • IllegalArgumentException - 当 max 为非正数时,抛出异常。
  • SecureRandomException - 当生成器不能正确生成随机数或生成随机数失败时,抛出异常。

func nextInt8()

public func nextInt8(): Int8

功能:获取一个 Int8 类型的随机数。

返回值:

  • Int8 - 一个 Int8 类型的随机数。

异常:

  • SecureRandomException - 当生成器不能正确生成随机数或生成随机数失败时,抛出异常。

func nextInt8(Int8)

public func nextInt8(max: Int8): Int8

功能:获取一个 Int8 类型且在区间 [0, max) 内的随机数。

参数:

  • max: Int8 - 区间最大值。

返回值:

  • Int8 - 一个 Int8 类型的随机数。

异常:

  • IllegalArgumentException - 当 max 为非正数时,抛出异常。
  • SecureRandomException - 当生成器不能正确生成随机数或生成随机数失败时,抛出异常。

func nextUInt16()

public func nextUInt16(): UInt16

功能:获取一个 UInt16 类型的随机数。

返回值:

  • UInt16 - 一个 UInt16 类型的随机数。

异常:

  • SecureRandomException - 当生成器不能正确生成随机数或生成随机数失败时,抛出异常。

func nextUInt16(UInt16)

public func nextUInt16(max: UInt16): UInt16

功能:获取一个 UInt16 类型且在区间 [0, max) 内的随机数。

参数:

  • max: UInt16 - 区间最大值。

返回值:

  • UInt16 - 一个 UInt16 类型的随机数。

异常:

  • IllegalArgumentException - 当 max 为 0 时,抛出异常。
  • SecureRandomException - 当生成器不能正确生成随机数或生成随机数失败时,抛出异常。

func nextUInt32()

public func nextUInt32(): UInt32

功能:获取一个 UInt32 类型的随机数。

返回值:

  • UInt32 - 一个 UInt32 类型的随机数。

异常:

  • SecureRandomException - 当生成器不能正确生成随机数或生成随机数失败时,抛出异常。

func nextUInt32(UInt32)

public func nextUInt32(max: UInt32): UInt32

功能:获取一个 UInt32 类型且在区间 [0, max) 内的随机数。

参数:

  • max: UInt32 - 区间最大值。

返回值:

  • UInt32 - 一个 UInt32 类型的随机数。

异常:

  • IllegalArgumentException - 当 max 为 0 时,抛出异常。
  • SecureRandomException - 当生成器不能正确生成随机数或生成随机数失败时,抛出异常。

func nextUInt64()

public func nextUInt64(): UInt64

功能:获取一个 UInt64 类型的随机数。

返回值:

  • UInt64 - 一个 UInt64 类型的随机数。

异常:

  • SecureRandomException - 当生成器不能正确生成随机数或生成随机数失败时,抛出异常。

func nextUInt64(UInt64)

public func nextUInt64(max: UInt64): UInt64

功能:获取一个 UInt64 类型且在区间 [0, max) 内的随机数。

参数:

  • max: UInt64 - 区间最大值。

返回值:

  • UInt64 - 一个 UInt64 类型的随机数。

异常:

  • IllegalArgumentException - 当 max 为 0 时,抛出异常。
  • SecureRandomException - 当生成器不能正确生成随机数或生成随机数失败时,抛出异常。

func nextUInt8()

public func nextUInt8(): UInt8

功能:获取一个 UInt8 类型的随机数。

返回值:

  • UInt8 - 一个 UInt8 类型的随机数。

异常:

  • SecureRandomException - 当生成器不能正确生成随机数或生成随机数失败时,抛出异常。

func nextUInt8(UInt8)

public func nextUInt8(max: UInt8): UInt8

功能:获取一个 UInt8 类型且在区间 [0, max) 内的随机数。

参数:

  • max: UInt8 - 区间最大值。

返回值:

  • UInt8 - 一个 UInt8 类型的随机数。

异常:

  • IllegalArgumentException - 当 max 为 0 时,抛出异常。
  • SecureRandomException - 当生成器不能正确生成随机数或生成随机数失败时,抛出异常。

class SM4

public class SM4 <: BlockCipher {
    public init(
        optMode: OperationMode,
        key: Array<Byte>,
        iv!: Array<Byte> = Array<Byte>(),
        paddingMode!: PaddingMode = PaddingMode.PKCS7Padding,
        aad!: Array<Byte> = Array<Byte>(),
        tagSize!: Int64 = 16
    )
}

功能:提供国密SM4对称加解密。

目前 SM4 支持 的加解密工作模式由 OperationMode 定义,目前支持 ECB、CBC、OFB、CFB、CTR、GCM模式。

不同的工作模式可能对应的加解密实现不同,安全性也不同。需要选择和场景适配的加解密工作模式。

iv 初始化向量在 GCM 模式下可以设置推荐长度是12字节,在 CBC、OFB、CFB、CTR 模式下 iv 长度是16字节,在 ECB 模式下 iv 可以不设置。

paddingMode 填充模式模式由 PaddingMode 定义, 目前支持 NoPadding 非填充、PKCS7Padding PKCS7填充。默认是 PKCS7 填充。

paddingMode 设置对ECB 和 CBC 有效,ECB 和 CBC 分组加解密需要分组长度等于 blockSize。会根据填充模式进行填充。 paddingMode 设置对 OFB、CFB、CTR、GCM 工作模式无效,这些工作模式均无需填充。

如果选择 NoPadding 模式,即不填充。则在 ECB 和 CBC 工作模式下用户需要对数据是否可以分组负责,如果数据不能分组,或者最后一组数据长度不足 blockSize 则会报错。

aad 附加数据,仅在 GCM 模式下使用,由用户填充,参与摘要计算,默认为空。

tagSize 设置摘要长度,仅在 GCM 模式下使用,默认值为 SM4_GCM_TAG_SIZE 16字节,最小不能低于12字节,最大不能超过16字节。

如果是 GCM 工作模式。加密结果的后 tagSize 字节是摘要数据。

使用示例见 SM4 使用

注意:

GCM 模式需要 OpenSSL 3.2 或者以上版本。

父类型:

  • BlockCipher

init(OperationMode, Array<Byte>, Array<Byte>, PaddingMode, Array<Byte>, Int64)

    public init(
        optMode: OperationMode,
        key: Array<Byte>,
        iv!: Array<Byte> = Array<Byte>(),
        paddingMode!: PaddingMode = PaddingMode.PKCS7Padding,
        aad!: Array<Byte> = Array<Byte>(),
        tagSize!: Int64 = 16
    )

功能:创建 SM4 实例,可指定在不同工作模式下参数。

参数:

  • optMode: OperationMode - 设置加解密工作模式。
  • key: Array<Byte> - 密钥,长度为16字节。
  • iv!: Array<Byte> - 初始化向量。
  • paddingMode!: PaddingMode - 设置填充模式。
  • aad!: Array<Byte> - 设置附加数据。
  • tagSize!: Int64 - 设置摘要长度。

异常:

prop aad

public prop aad: Array<Byte>

功能:附加数据。

类型:Array<Byte>

prop algorithm

public prop algorithm: String

功能:获取分组加解密算法的算法名称。

类型:String

prop blockSize

public prop blockSize: Int64

功能:分组长度,单位字节。

类型:Int64

prop keySize

public prop keySize: Int64

功能:密钥长度。

类型:Int64

prop key

public prop key: Array<Byte>

功能:密钥。

类型:Array<Byte>

prop optMode

public prop optMode: OperationMode

功能:工作模式。

类型:OperationMode

prop paddingMode

public prop paddingMode: PaddingMode

功能:填充模式。

类型:PaddingMode

prop iv

public prop iv: Array<Byte>

功能:初始化向量。

类型:Array<Byte>

prop ivSize

public prop ivSize: Int64

功能:初始化向量长度。

类型:Int64

prop tagSize

public prop tagSize: Int64

功能:摘要长度。

类型:Int64

func encrypt(Array<Byte>)

public func encrypt(input: Array<Byte>): Array<Byte>

功能:加密一段数据数据。

参数:

  • input: Array<Byte> - 输入字节序列。

返回值:

  • Array<Byte> - 加密后的结果。

异常:

func encrypt(Array<Byte>, Array<Byte>)

public func encrypt(input: Array<Byte>, to!: Array<Byte>): Int64

功能:加密一段数据数据,指定输出数组长度会影响加解密结果。一般而言选填充模式,指定的密文数组长度不能小于明文数组长度加上一个 blockSize。

参数:

  • input: Array<Byte> - 待进行加密的数据。
  • to!: Array<Byte> - 输出数组。

返回值:

  • Int64 - 输出长度。

异常:

  • CryptoException - 加密失败,抛出异常。
  • IllegalArgumentException - 当 to 的 size = 0 时,抛出异常。

func encrypt(InputStream, OutputStream)

public func encrypt(input: InputStream, output: OutputStream)

功能:对输入流进行加密,一般如果数据过大无法一次对其加密,可以对数据流进行加密。

参数:

  • input:InputStream - 待加密的输入数据流。
  • output: OutputStream - 解密后的输出数据流。

异常:

func decrypt(Array<Byte>)

public func decrypt(input: Array<Byte>): Array<Byte>

功能:解密一段数据数据。

参数:

  • input: Array<Byte> - 输入字节序列。

返回值:

  • Array<Byte> - 解密后的结果。

异常:

func decrypt(Array<Byte>, Array<Byte>)

public func decrypt(input: Array<Byte>,  to!: Array<Byte>): Int64

功能:解密一段数据数据,指定输出数组长度会影响加解密结果。一般而言,指定的明文数组长度不能小于密文数组长度减去一个 blockSize。

参数:

  • input: Array<Byte> - 待进行解密的数据。
  • to!: Array<Byte> - 输出数组。

返回值:

  • Int64 - 输出长度。

异常:

  • CryptoException - 解密失败,抛出异常。
  • IllegalArgumentException - 当 to 的 size = 0 时,抛出异常。

func decrypt(InputStream, OutputStream)

public func decrypt(input: InputStream, output: OutputStream)

功能:对输入流进行解密,一般如果数据过大无法一次对其解密,可以对数据流进行解密。

参数:

  • input:InputStream - 待解密的输入数据流。
  • output: OutputStream - 解密后的输出数据流。

异常:

结构体

struct OperationMode

public struct OperationMode <: ToString & Equatable<OperationMode> {
    public static let ECB
    public static let CBC
    public static let OFB
    public static let CFB
    public static let CTR
    public static let GCM
    public let mode: String
}

功能: 对称加解密算法的工作模式。

父类型:

static let ECB

public static let ECB

功能:Electronic CodeBook(单子密码本)工作模式, ECB 初始值是 OperationMode("ECB")。

类型:OperationMode

static let CBC

public static let CBC

功能:Cipher Block Chaining(密码分组链接)工作模式,CBC 初始值是 OperationMode("CBC")。

类型:OperationMode

static let OFB

public static let OFB

功能:Output FeedBack(输出反馈)工作模式,OFB 初始值是 OperationMode("OFB")。

类型:OperationMode

static let CFB

public static let CFB

功能:Output FeedBack(密文反馈)工作模式,CFB 初始值是 OperationMode("CFB")。

类型:OperationMode

static let CTR

public static let CTR

功能:CounTeR(计数器)工作模式,CTR 初始值是 OperationMode("CTR")。

类型:OperationMode

static let GCM

public static let GCM

功能:Galois Counter(伽罗瓦计数器)工作模式,GCM 初始值是 OperationMode("GCM")。

类型:OperationMode

let mode

public let mode: String

功能:operation 分组加解密的工作模式,目前支持 ECB、CBC CFB OFB CTR GCM。

类型:String

func toString()

public override func toString(): String

功能:获取工作模式字符串。

返回值:

  • String - 工作模式字符串。

func ==(OperationMode)

public operator override func ==(other: OperationMode): Bool

功能:工作模式比较是否相同。

参数:

返回值:

  • Bool - true 相同,false 不相同。

func !=(OperationMode)

public operator override func !=(other: OperationMode): Bool

功能:工作模式比较是否不相同。

参数:

返回值:

  • Bool - true 不相同,false 相同。

struct PaddingMode

public struct PaddingMode <: Equatable<PaddingMode> {
    public static let NoPadding: PaddingMode
    public static let PKCS7Padding: PaddingMode
    public let paddingType: Int64
}

功能: 对称加解密算法的填充模式。

父类型:

static let NoPadding

public static let NoPadding: PaddingMode

功能:不填充,NoPadding 初始值是 PaddingMode(0)。

类型:PaddingMode

static let PKCS7Padding

public static let PKCS7Padding: PaddingMode

功能:采用PKCS7协议填充,PKCS7Padding 初始值是 PaddingMode(1)。

类型:PaddingMode

let paddingType

public let paddingType: Int64

功能:分组加解密填充方式,目前支持非填充和 pkcs7 填充。

类型:Int64

func ==(PaddingMode)

public operator override func ==(other: PaddingMode): Bool

功能:填充模式比较是否相同。

参数:

返回值:

  • Bool - true 相同,false 不相同。

func !=(PaddingMode)

public operator override func !=(other: PaddingMode): Bool

功能:工作模式比较是否不相同。

参数:

返回值:

  • Bool - true 不相同,false 相同。

异常类

class SecureRandomException

public class SecureRandomException <: Exception {
    public init()
    public init(message: String)
}

功能:crypto 包安全随机数的异常类。

父类型:

  • Exception

init()

public init()

功能:创建默认的 SecureRandomException 实例,异常提示消息为空。

init(String)

public init(message: String)

功能:根据异常信息创建 SecureRandomException 实例。

参数:

  • message: String - 异常提示信息。

SecureRandom 使用

Random 创建随机数对象。

示例:

import stdx.crypto.crypto.*

main() {
    let r = SecureRandom()
    for (_ in 0..10) {
        let flip = r.nextBool()
        println(flip)
    }
    return 0
}

运行结果:

说明

可能出现的运行结果如下(true/false 的选择是随机的)。

false
true
false
false
false
true
true
false
false
true

SM4 使用

SM4 加解密数据。

示例:

import stdx.crypto.crypto.*
import stdx.encoding.hex.fromHexString

main() {
    var plains = "hello cangjie!"
    var key = "1234567890123456"
    var iv = "1234567890123456"
    var sm4 = SM4(OperationMode.CBC, key.toArray(), iv: iv.toArray())
    var enRe = sm4.encrypt(plains.toArray())
    var dd = sm4.decrypt(enRe)
    println(String.fromUtf8(dd))
}

运行结果:

hello cangjie!

stdx.crypto.digest

功能介绍

digest 包提供常用的消息摘要算法,包括 MD5、SHA1、SHA224、SHA256、SHA384、SHA512、HMAC、SM3等。

使用本包需要外部依赖 OpenSSL 3 的 crypto 动态库文件,故使用前需安装相关工具。

  • 对于 Linux 操作系统,可参考以下方式:

    • 如果系统的包管理工具支持安装 OpenSSL 3 开发工具包,可通过这个方式安装,并确保系统安装目录下含有 libcrypto.so 和 libcrypto.so.3 这两个动态库文件,例如 Ubuntu 22.04 系统上可使用 sudo apt install libssl-dev 命令安装 libssl-dev 工具包;
    • 如果无法通过上面的方式安装,可自行下载 OpenSSL 3.x.x 源码编译安装软件包,并确保安装目录下含有 libcrypto.so 和 libcrypto.so.3 这两个动态库文件,然后可选择下面任意一种方式来保证系统链接器可以找到这些文件:
      • 在系统未安装 OpenSSL 的场景,安装时选择直接安装到系统路径下;
      • 安装在自定义目录的场景,将这些文件所在目录设置到环境变量 LD_LIBRARY_PATH 以及 LIBRARY_PATH 中。
  • 对于 Windows 操作系统,可按照以下步骤:

    • 自行下载 OpenSSL 3.x.x 源码编译安装 x64 架构软件包或者自行下载安装第三方预编译的供开发人员使用的 OpenSSL 3.x.x 软件包;
    • 确保安装目录下含有 libcrypto.dll.a(或 libcrypto.lib)、libcrypto-3-x64.dll 这两个库文件;
    • 将 libcrypto.dll.a(或 libcrypto.lib)所在的目录路径设置到环境变量 LIBRARY_PATH 中,将 libcrypto-3-x64.dll 所在的目录路径设置到环境变量 PATH 中。
  • 对于 macOS 操作系统,可参考以下方式:

    • 使用 brew install openssl@3 安装,并确保系统安装目录下含有 libcrypto.dylib 和 libcrypto.3.dylib 这两个动态库文件;
    • 如果无法通过上面的方式安装,可自行下载 OpenSSL 3.x.x 源码编译安装软件包,并确保安装目录下含有 libcrypto.dylib 和 libcrypto.3.dylib 这两个动态库文件,然后可选择下面任意一种方式来保证系统链接器可以找到这些文件:
      • 在系统未安装 OpenSSL 的场景,安装时选择直接安装到系统路径下;
      • 安装在自定义目录的场景,将这些文件所在目录设置到环境变量 DYLD_LIBRARY_PATH 以及 LIBRARY_PATH 中。

说明:

如果未安装 OpenSSL 3 软件包或者安装低版本的软件包,程序可能无法使用并抛出相关异常 CryptoException:Can not load openssl library or function xxx。

API 列表

类名功能
HMACHMAC摘要算法。
MD5MD5摘要算法。
SHA1SHA1摘要算法。
SHA224SHA224摘要算法。
SHA256SHA256摘要算法。
SHA384SHA384摘要算法。
SHA512SHA512摘要算法。
SM3SM3摘要算法。

结构体

结构体名功能
HashType摘要算法类型。

异常类

异常类名功能
CryptoExceptioncrypto 包的异常类。

class HMAC

public class HMAC <: Digest {
    public init(key: Array<Byte>, digest: () -> Digest)
    public init(key: Array<Byte>, algorithm: HashType)
}

功能:提供 HMAC 算法的实现。目前支持的摘要算法包括 MD5、SHA1、SHA224、SHA256、SHA384、SHA512、SM3。

父类型:

  • Digest

prop algorithm

public prop algorithm: String

功能:HMAC 所选 Hash 算法的算法名称。

类型:String

prop blockSize

public prop blockSize: Int64

功能:HMAC 所选 Hash 算法信息块长度,单位字节。

类型:Int64

prop size

public prop size: Int64

功能:HMAC 所选 Hash 算法的摘要信息长度,单位字节。

类型:Int64

init(Array<Byte>, () -> Digest)

public init(key: Array<Byte>, digest: () -> Digest)

功能:构造函数,创建 HMAC 对象。

参数:

  • key: Array<Byte> - 密钥,建议该参数不小于所选Hash算法摘要的长度。
  • digest: () -> Digest - hash 算法。

异常:

init(Array<Byte>, HashType)

public init(key: Array<Byte>, algorithm: HashType)

功能:构造函数,创建 HMAC 对象。

参数:

  • key: Array<Byte> - 密钥,建议该参数不小于所选Hash算法摘要的长度。
  • algorithm: HashType - hash 算法。

异常:

static func equal(Array<Byte>, Array<Byte>)

public static func equal(mac1: Array<Byte>, mac2: Array<Byte>): Bool

功能:比较两个信息摘要是否相等,且不泄露比较时间,即比较不采用传统短路原则,从而防止 timing attack 类型的攻击。

参数:

  • mac1: Array<Byte> - 需要比较的信息摘要序列。
  • mac2: Array<Byte> - 需要比较的信息摘要序列。

返回值:

  • Bool - 信息摘要是否相同, true 相同, false 不相同。

func finish()

public func finish(): Array<Byte>

功能:返回生成的信息摘要值,注意调用 finish 后不可以再进行摘要计算,如重新计算需要 reset 重置上下文。

返回值:

  • Array<Byte> - 生成的信息摘要字节序列。

异常:

  • CryptoException - 未重置上下文再次调用 finish 进行摘要计算,抛此异常。

func finish(Array<Byte>)

public func finish(to!: Array<Byte>): Unit

功能:获取生成的信息摘要值,注意调用 finish 后不可以再进行摘要计算,如重新计算需要 reset 重置上下文。

参数:

  • to!: Array<Byte> - 目标数组。

异常:

  • CryptoException - 未重置上下文再次调用 finish 进行摘要计算或者指定输出数组大小不等于摘要算法信息长度,抛此异常。

func reset()

public func reset(): Unit

功能:重置 HMAC 对象到初始状态,清理 HMAC 上下文。

异常:

func write(Array<Byte>)

public func write(buffer: Array<Byte>): Unit 

功能:使用给定的 buffer 更新 HMAC 对象,在调用 finish 前可以多次更新。

参数:

  • buffer: Array<Byte> - 需要追加的字节序列。

异常:

  • CryptoException - 当 buffer 为空、finish 已经调用生成信息摘要场景,抛此异常。

class MD5

public class MD5 <: Digest {
    public init()
}

功能:提供 MD5 算法的实现接口。使用示例见 MD5 算法示例

父类型:

  • Digest

prop algorithm

public prop algorithm: String

功能:MD5 摘要算法的算法名称。

类型:String

prop blockSize

public prop blockSize: Int64

功能:MD5 信息块长度,单位字节。

类型:Int64

prop size

public prop size: Int64

功能:MD5 摘要信息长度,单位字节。

类型:Int64

init()

public init()

功能:无参构造函数,创建 MD5 对象。

func finish()

public func finish(): Array<Byte>

功能:返回生成的 MD5 值,注意调用 finish 后 MD5 上下文会发生改变,finish 后不可以再进行摘要计算,如重新计算需要 reset 重置上下文。

返回值:

  • Array<Byte> - 生成的 MD5 字节序列。

异常:

  • CryptoException - 未重置上下文再次调用 finish 进行摘要计算,抛此异常。

func finish(Array<Byte>)

public func finish(to!: Array<Byte>): Unit

功能:获取生成的信息摘要值,注意调用 finish 后不可以再进行摘要计算,如重新计算需要 reset 重置上下文。

参数:

  • to!: Array<Byte> - 目标数组。

异常:

  • CryptoException - 未重置上下文再次调用 finish 进行摘要计算或者指定输出数组大小不等于摘要算法信息长度,抛此异常。

func reset()

public func reset(): Unit

功能:重置 MD5 对象到初始状态,清理 MD5 上下文。

func write(Array<Byte>)

public func write(buffer: Array<Byte>): Unit

功能:使用给定的 buffer 更新 MD5 对象,在调用 finish 前可以多次更新。

参数:

  • buffer: Array<Byte> - 输入字节序列。

异常:

  • CryptoException - 已经调用 finish 进行摘要计算后未重置上下文,抛此异常。

class SHA1

public class SHA1 <: Digest {
    public init()
}

功能:提供 SHA1 算法的实现接口。使用示例见 SHA1 算法示例

父类型:

  • Digest

prop algorithm

public prop algorithm: String

功能:SHA1 摘要算法的算法名称。

类型:String

prop blockSize

public prop blockSize: Int64

功能:SHA1 信息块长度,单位字节。

类型:Int64

prop size

public prop size: Int64

功能:SHA1 摘要信息长度,单位字节。

类型:Int64

init()

public init()

功能:无参构造函数,创建 SHA1 对象。

func finish()

public func finish(): Array<Byte>

功能:返回生成的 SHA1 值,注意调用 finish 后 SHA1 上下文会发生改变,finish 后不可以再进行摘要计算,如重新计算需要 reset 重置上下文。

返回值:

  • Array<Byte> - 生成的 SHA1 字节序列。

异常:

  • CryptoException - 未重置上下文再次调用 finish 进行摘要计算,抛此异常。

func finish(Array<Byte>)

public func finish(to!: Array<Byte>): Unit

功能:获取生成的信息摘要值,注意调用 finish 后不可以再进行摘要计算,如重新计算需要 reset 重置上下文。

参数:

  • to!: Array<Byte> - 目标数组。

异常:

  • CryptoException - 未重置上下文再次调用 finish 进行摘要计算或者指定输出数组大小不等于摘要算法信息长度,抛此异常。

func reset()

public func reset(): Unit

功能:重置 SHA1 对象到初始状态,清理 SHA1 上下文。

func write(Array<Byte>)

public func write(buffer: Array<Byte>): Unit

功能:使用给定的 buffer 更新 SHA1 对象,在调用 finish 前可以多次更新。

参数:

  • buffer: Array<Byte> - 输入字节序列。

异常:

  • CryptoException - 已经调用 finish 进行摘要计算后未重置上下文,抛此异常。

class SHA224

public class SHA224 <: Digest {
    public init()
}

功能:提供 SHA224 算法的实现接口。使用示例见 SHA224 算法示例

父类型:

  • Digest

prop algorithm

public prop algorithm: String

功能:SHA224 摘要算法的算法名称。

类型:String

prop blockSize

public prop blockSize: Int64

功能:SHA224 信息块长度,单位字节。

类型:Int64

prop size

public prop size: Int64

功能:SHA224 摘要信息长度,单位字节。

类型:Int64

init()

public init()

功能:无参构造函数,创建 SHA224 对象。

func finish()

public func finish(): Array<Byte>

功能:返回生成的 SHA224 值,注意调用 finish 后 SHA224 上下文会发生改变,finish 后不可以再进行摘要计算,如重新计算需要 reset 重置上下文。

返回值:

  • Array<Byte> - 生成的 SHA224 字节序列。

异常:

  • CryptoException - 未重置上下文再次调用 finish 进行摘要计算,抛此异常。

func finish(Array<Byte>)

public func finish(to!: Array<Byte>): Unit

功能:获取生成的信息摘要值,注意调用 finish 后不可以再进行摘要计算,如重新计算需要 reset 重置上下文。

参数:

  • to!: Array<Byte> - 目标数组。

异常:

  • CryptoException - 未重置上下文再次调用 finish 进行摘要计算或者指定输出数组大小不等于摘要算法信息长度,抛此异常。

func reset()

public func reset(): Unit

功能:重置 SHA224 对象到初始状态,清理 SHA224 上下文。

func write(Array<Byte>)

public func write(buffer: Array<Byte>): Unit

功能:使用给定的 buffer 更新 SHA224 对象,在调用 finish 前可以多次更新。

参数:

  • buffer: Array<Byte> - 输入字节序列。

异常:

  • CryptoException - 已经调用 finish 进行摘要计算后未重置上下文,抛此异常。

class SHA256

public class SHA256 <: Digest {
    public init()
}

功能:提供 SHA256 算法的实现接口。使用示例见 SHA256 算法示例

父类型:

  • Digest

prop algorithm

public prop algorithm: String

功能:SHA256 摘要算法的算法名称。

类型:String

prop blockSize

public prop blockSize: Int64

功能:SHA256 信息块长度,单位字节。

类型:Int64

prop size

public prop size: Int64

功能:SHA256 摘要信息长度,单位字节。

类型:Int64

init()

public init()

功能:无参构造函数,创建 SHA256 对象。

func finish()

public func finish(): Array<Byte>

功能:返回生成的 SHA256 值,注意调用 finish 后 SHA256 上下文会发生改变,finish 后不可以再进行摘要计算,如重新计算需要 reset 重置上下文。

返回值:

  • Array<Byte> - 生成的 SHA256 字节序列。

异常:

  • CryptoException - 未重置上下文再次调用 finish 进行摘要计算,抛此异常。

func finish(Array<Byte>)

public func finish(to!: Array<Byte>): Unit

功能:获取生成的信息摘要值,注意调用 finish 后不可以再进行摘要计算,如重新计算需要 reset 重置上下文。

参数:

  • to!: Array<Byte> - 目标数组。

异常:

  • CryptoException - 未重置上下文再次调用 finish 进行摘要计算或者指定输出数组大小不等于摘要算法信息长度,抛此异常。

func reset()

public func reset(): Unit

功能:重置 SHA256 对象到初始状态,清理 SHA256 上下文。

func write(Array<Byte>)

public func write(buffer: Array<Byte>): Unit

功能:使用给定的 buffer 更新 SHA256 对象,在调用 finish 前可以多次更新。

参数:

  • buffer: Array<Byte> - 输入字节序列。

异常:

  • CryptoException - 已经调用 finish 进行摘要计算后未重置上下文,抛此异常。

class SHA384

public class SHA384 <: Digest {
    public init()
}

功能:提供 SHA384 算法的实现接口。使用示例见 SHA384 算法示例

父类型:

  • Digest

prop algorithm

public prop algorithm: String

功能:SHA384 摘要算法的算法名称。

类型:String

prop blockSize

public prop blockSize: Int64

功能:SHA384 信息块长度,单位字节。

类型:Int64

prop size

public prop size: Int64

功能:SHA384 摘要信息长度,单位字节。

类型:Int64

init()

public init()

功能:无参构造函数,创建 SHA384 对象。

func finish()

public func finish(): Array<Byte>

功能:返回生成的 SHA384 值,注意调用 finish 后 SHA384 上下文会发生改变,finish 后不可以再进行摘要计算,如重新计算需要 reset 重置上下文。

返回值:

  • Array<Byte> - 生成的 SHA384 字节序列。

异常:

  • CryptoException - 未重置上下文再次调用 finish 进行摘要计算,抛此异常。

func finish(Array<Byte>)

public func finish(to!: Array<Byte>): Unit

功能:获取生成的信息摘要值,注意调用 finish 后不可以再进行摘要计算,如重新计算需要 reset 重置上下文。

参数:

  • to!: Array<Byte> - 目标数组。

异常:

  • CryptoException - 未重置上下文再次调用 finish 进行摘要计算或者指定输出数组大小不等于摘要算法信息长度,抛此异常。

func reset()

public func reset(): Unit

功能:重置 SHA384 对象到初始状态,清理 SHA384 上下文。

func write(Array<Byte>)

public func write(buffer: Array<Byte>): Unit

功能:使用给定的 buffer 更新 SHA384 对象,在调用 finish 前可以多次更新。

参数:

  • buffer: Array<Byte> - 输入字节序列。

异常:

  • CryptoException - 已经调用 finish 进行摘要计算后未重置上下文,抛此异常。

class SHA512

public class SHA512 <: Digest {
    public init()
}

功能:提供 SHA512 算法的实现接口。使用示例见 SHA512 算法示例

父类型:

  • Digest

prop algorithm

public prop algorithm: String

功能:SHA512 摘要算法的算法名称。

类型:String

prop blockSize

public prop blockSize: Int64

功能:SHA512 信息块长度,单位字节。

类型:Int64

prop size

public prop size: Int64

功能:SHA512 摘要信息长度,单位字节。

类型:Int64

init()

public init()

功能:无参构造函数,创建 SHA512 对象。

func finish()

public func finish(): Array<Byte>

功能:返回生成的 SHA512 值,注意调用 finish 后 SHA512 上下文会发生改变,finish 后不可以再进行摘要计算,如重新计算需要 reset 重置上下文。

返回值:

  • Array<Byte> - 生成的 SHA512 字节序列。

异常:

  • CryptoException - 未重置上下文再次调用 finish 进行摘要计算,抛此异常。

func finish(Array<Byte>)

public func finish(to!: Array<Byte>): Unit

功能:获取生成的信息摘要值,注意调用 finish 后不可以再进行摘要计算,如重新计算需要 reset 重置上下文。

参数:

  • to!: Array<Byte> - 目标数组。

异常:

  • CryptoException - 未重置上下文再次调用 finish 进行摘要计算或者指定输出数组大小不等于摘要算法信息长度,抛此异常。

func reset()

public func reset(): Unit

功能:重置 SHA512 对象到初始状态,清理 SHA512 上下文。

func write(Array<Byte>)

public func write(buffer: Array<Byte>): Unit

功能:使用给定的 buffer 更新 SHA512 对象,在调用 finish 前可以多次更新。

参数:

  • buffer: Array<Byte> - 输入字节序列。

异常:

  • CryptoException - 已经调用 finish 进行摘要计算后未重置上下文,抛此异常。

class SM3

public class SM3 <: Digest {
    public init()
}

功能:提供 SM3 算法的实现接口。使用示例见 SM3 算法示例

父类型:

  • Digest

prop algorithm

public prop algorithm: String

功能:SM3 摘要算法的算法名称。

类型:String

prop blockSize

public prop blockSize: Int64

功能:SM3 信息块长度,单位字节。

类型:Int64

prop size

public prop size: Int64

功能:SM3 摘要信息长度,单位字节。

类型:Int64

init()

public init()

功能:无参构造函数,创建 SM3 对象。

func finish()

public func finish(): Array<Byte>

功能:返回生成的 SM3 值,注意调用 finish 后 SM3 上下文会发生改变,finish 后不可以再进行摘要计算,如重新计算需要 reset 重置上下文。

返回值:

  • Array<Byte> - 生成的 SM3 字节序列。

异常:

  • CryptoException - 未重置上下文再次调用 finish 进行摘要计算,抛此异常。

func finish(Array<Byte>)

public func finish(to!: Array<Byte>): Unit

功能:获取生成的信息摘要值,注意调用 finish 后不可以再进行摘要计算,如重新计算需要 reset 重置上下文。

参数:

  • to!: Array<Byte> - 目标数组。

异常:

  • CryptoException - 未重置上下文再次调用 finish 进行摘要计算或者指定输出数组大小不等于摘要算法信息长度,抛此异常。

func reset()

public func reset(): Unit

功能:重置 SM3 对象到初始状态,清理 SM3 上下文。

func write(Array<Byte>)

public func write(buffer: Array<Byte>): Unit

功能:使用给定的 buffer 更新 SM3 对象,在调用 finish 前可以多次更新。

参数:

  • buffer: Array<Byte> - 输入字节序列。

异常:

  • CryptoException - 已经调用 finish 进行摘要计算后未重置上下文,抛此异常。

结构体

struct HashType

public struct HashType <: ToString & Equatable<HashType>

功能: 此类为 Hash 算法类别结构体,MD5SHA1SHA224SHA256SHA384SHA512均为常用摘要算法。

父类型:

prop MD5

public static prop MD5: HashType

功能:返回 MD5 类型。

类型:HashType

prop SHA1

public static prop SHA1: HashType

功能:返回 SHA1 类型。

类型:HashType

prop SHA224

public static prop SHA224: HashType

功能:返回 SHA224 类型。

类型:HashType

prop SHA256

public static prop SHA256: HashType

功能:返回 SHA256 类型。

类型:HashType

prop SHA384

public static prop SHA384: HashType

功能:返回 SHA384 类型。

类型:HashType

prop SHA512

public static prop SHA512: HashType

功能:返回 SHA512 类型。

类型:HashType

prop SM3

public static prop SM3: HashType

功能:返回 SM3 类型。

类型:HashType

func toString()

public func toString(): String

功能:获取 Hash 算法名称。

返回值:

  • String - Hash 算法名称。

operator func ==(HashType)

public operator override func ==(other: HashType): Bool

功能:判断两 HashType 是否引用同一实例。

参数:

  • other: HashType - 对比的 HashType。

返回值:

  • Bool - 相同返回 true;否则,返回 false

operator func !=(HashType)

public operator override func !=(other: HashType): Bool

功能:判断两 HashType 是否引用不同实例。

参数:

  • other: HashType - 对比的 HashType。

返回值:

  • Bool - 不相同返回 true;否则,返回 false

异常类

class CryptoException

public class CryptoException <: Exception {
    public init()
    public init(message: String)
}

功能:此类为摘要和加解密出现错误时抛出的异常。

父类型:

  • Exception

init()

public init()

功能:无参构造函数,构造CryptoException异常。

init(String)

public init(message: String)

功能:根据异常信息构造 CryptoException 异常类对象。

参数:

  • message: String - 异常信息。

digest 使用

MD5 算法示例

调用 MD5 成员函数

示例:

import stdx.crypto.digest.*
import std.convert.*
import std.crypto.digest.*
import stdx.encoding.hex.*

main() {
    var str: String = "helloworld"
    var md5Instance = MD5()
    md5Instance.write(str.toArray())
    var md: Array<Byte> = md5Instance.finish()
    var result: String = toHexString(md)
    println(result)
    return 0
}

运行结果:

fc5e038d38a57032085441e7fe7010b0

SHA1 算法示例

调用 SHA1 成员函数

示例:

import stdx.crypto.digest.*
import std.convert.*
import std.crypto.digest.*
import stdx.encoding.hex.*

main() {
    var str: String = "helloworld"
    var sha1Instance = SHA1()
    sha1Instance.write(str.toArray())
    var md: Array<Byte> = sha1Instance.finish()
    var result: String = toHexString(md)
    println(result)
    return 0
}

运行结果:

6adfb183a4a2c94a2f92dab5ade762a47889a5a1

SHA224 算法示例

调用 SHA224 成员函数

示例:

import stdx.crypto.digest.*
import std.convert.*
import std.crypto.digest.*
import stdx.encoding.hex.*

main() {
    var str: String = "helloworld"
    var sha224Instance = SHA224()
    sha224Instance.write(str.toArray())
    var md: Array<Byte> = sha224Instance.finish()
    var result: String = toHexString(md)
    println(result)
    return 0
}

运行结果:

b033d770602994efa135c5248af300d81567ad5b59cec4bccbf15bcc

SHA256 算法示例

调用 SHA256 成员函数

示例:

import stdx.crypto.digest.*
import std.convert.*
import std.crypto.digest.*
import stdx.encoding.hex.*

main() {
    var str: String = "helloworld"
    var sha256Instance = SHA256()
    sha256Instance.write(str.toArray())
    var md: Array<Byte> = sha256Instance.finish()
    var result: String = toHexString(md)
    println(result)
    return 0
}

运行结果:

936a185caaa266bb9cbe981e9e05cb78cd732b0b3280eb944412bb6f8f8f07af

SHA384 算法示例

调用 SHA384 成员函数

示例:

import stdx.crypto.digest.*
import std.convert.*
import std.crypto.digest.*
import stdx.encoding.hex.*

main() {
    var str: String = "helloworld"
    var sha384Instance = SHA384()
    sha384Instance.write(str.toArray())
    var md: Array<Byte> = sha384Instance.finish()
    var result: String = toHexString(md)
    println(result)
    return 0
}

运行结果:

97982a5b1414b9078103a1c008c4e3526c27b41cdbcf80790560a40f2a9bf2ed4427ab1428789915ed4b3dc07c454bd9

SHA512 算法示例

调用 SHA512 成员函数

示例:

import stdx.crypto.digest.*
import std.convert.*
import std.crypto.digest.*
import stdx.encoding.hex.*

main() {
    var str: String = "helloworld"
    var sha512Instance = SHA512()
    sha512Instance.write(str.toArray())
    var md: Array<Byte> = sha512Instance.finish()
    var result: String = toHexString(md)
    println(result)
    return 0
}

运行结果:

1594244d52f2d8c12b142bb61f47bc2eaf503d6d9ca8480cae9fcf112f66e4967dc5e8fa98285e36db8af1b8ffa8b84cb15e0fbcf836c3deb803c13f37659a60

HMAC 算法示例

说明

目前只支持HMAC-SHA512。

调用 HMAC-SHA512 成员函数

示例:

import stdx.crypto.digest.*
import stdx.encoding.hex.*

main() {
    var algorithm: HashType = HashType.SHA512
    var key: Array<UInt8> = "cangjie".toArray()
    var data1: Array<UInt8> = "123".toArray()
    var data2: Array<UInt8> = "456".toArray()
    var data3: Array<UInt8> = "789".toArray()
    var data4: Array<UInt8> = "123456789".toArray()
    var hmac = HMAC(key, algorithm)
    hmac.write(data1)
    hmac.write(data2)
    hmac.write(data3)
    var md1: Array<Byte> = hmac.finish()
    var result1: String = toHexString(md1)
    println(result1)

    hmac.reset()
    hmac.write(data4)
    var md2: Array<Byte> = hmac.finish()
    var result2: String = toHexString(md2)
    println(result2)
    println(HMAC.equal(md1, md2))
    return 0
}

运行结果:

2bafeb53b60a119d38793a886c7744f5027d7eaa3702351e75e4ff9bf255e3ce296bf41f80adda2861e81bd8efc52219df821852d84a17fb625e3965ebf2fdd9
2bafeb53b60a119d38793a886c7744f5027d7eaa3702351e75e4ff9bf255e3ce296bf41f80adda2861e81bd8efc52219df821852d84a17fb625e3965ebf2fdd9
true

SM3 算法示例

调用 SM3 成员函数

示例:

import stdx.crypto.digest.*
import std.convert.*
import std.crypto.digest.*
import stdx.encoding.hex.*

main() {
    var str: String = "helloworld"
    var sm3Instance = SM3()
    sm3Instance.write(str.toArray())
    var md: Array<Byte> = sm3Instance.finish()
    var result: String = toHexString(md)
    println(result)
    return 0
}

运行结果:

c70c5f73da4e8b8b73478af54241469566f6497e16c053a03a0170fa00078283

stdx.crypto.keys

功能介绍

keys 包提供非对称加密和签名算法,包括 RSA 和 SM2 非对称加密算法以及 ECDSA 签名算法。

使用本包需要外部依赖 OpenSSL 3 的 crypto 动态库文件,故使用前需安装相关工具。

  • 对于 Linux 操作系统,可参考以下方式:

    • 如果系统的包管理工具支持安装 OpenSSL 3 开发工具包,可通过这个方式安装,并确保系统安装目录下含有 libcrypto.so 和 libcrypto.so.3 这两个动态库文件,例如 Ubuntu 22.04 系统上可使用 sudo apt install libssl-dev 命令安装 libssl-dev 工具包;
    • 如果无法通过上面的方式安装,可自行下载 OpenSSL 3.x.x 源码编译安装软件包,并确保安装目录下含有 libcrypto.so 和 libcrypto.so.3 这两个动态库文件,然后可选择下面任意一种方式来保证系统链接器可以找到这些文件:
      • 在系统未安装 OpenSSL 的场景,安装时选择直接安装到系统路径下;
      • 安装在自定义目录的场景,将这些文件所在目录设置到环境变量 LD_LIBRARY_PATH 以及 LIBRARY_PATH 中。
  • 对于 Windows 操作系统,可按照以下步骤:

    • 自行下载 OpenSSL 3.x.x 源码编译安装 x64 架构软件包或者自行下载安装第三方预编译的供开发人员使用的 OpenSSL 3.x.x 软件包;
    • 确保安装目录下含有 libcrypto.dll.a(或 libcrypto.lib)、libcrypto-3-x64.dll 这两个库文件;
    • 将 libcrypto.dll.a(或 libcrypto.lib)所在的目录路径设置到环境变量 LIBRARY_PATH 中,将 libcrypto-3-x64.dll 所在的目录路径设置到环境变量 PATH 中。
  • 对于 macOS 操作系统,可参考以下方式:

    • 使用 brew install openssl@3 安装,并确保系统安装目录下含有 libcrypto.dylib 和 libcrypto.3.dylib 这两个动态库文件;
    • 如果无法通过上面的方式安装,可自行下载 OpenSSL 3.x.x 源码编译安装软件包,并确保安装目录下含有 libcrypto.dylib 和 libcrypto.3.dylib 这两个动态库文件,然后可选择下面任意一种方式来保证系统链接器可以找到这些文件:
      • 在系统未安装 OpenSSL 的场景,安装时选择直接安装到系统路径下;
      • 安装在自定义目录的场景,将这些文件所在目录设置到环境变量 DYLD_LIBRARY_PATH 以及 LIBRARY_PATH 中。

说明:

如果未安装 OpenSSL 3 软件包或者安装低版本的软件包,程序可能无法使用并抛出相关异常 CryptoException:Can not load openssl library or function xxx。

API 列表

类名功能
ECDSAPrivateKeyECDSA私钥类。
ECDSAPublicKeyECDSA公钥类。
RSAPrivateKeyRSA私钥类。
RSAPublicKeyRSA公钥类。
SM2PrivateKeySM2私钥类。
SM2PublicKeySM2公钥类。

枚举

枚举名功能
Curve枚举类型 Curve 用于选择生成 ECDSA 密钥时使用的椭圆曲线类型。
PadOption用于设置 RSA 的填充模式。

结构体

结构体名功能
OAEPOption最优非对称加密填充。
PSSOption概率签名方案。

class ECDSAPrivateKey

public class ECDSAPrivateKey <: PrivateKey {
    public init(curve: Curve)
}

功能:ECDSA 私钥类,提供生成 ECDSA 私钥能力,ECDSA 的私钥支持签名操作,同时支持 PEM 和 DER 格式的编码解码。使用示例见 ECDSA 密钥示例

父类型:

init(Curve)

public init(curve: Curve)

功能:init 初始化生成私钥。

参数:

  • curve: Curve - 椭圆曲线类型。

异常:

static func decodeDer(DerBlob)

public static func decodeDer(blob: DerBlob): ECDSAPrivateKey

功能:将私钥从 DER 格式解码。

参数:

  • blob: DerBlob - 二进制格式的私钥对象。

返回值:

异常:

static func decodeDer(DerBlob, ?String)

public static func decodeDer(blob: DerBlob, password!: ?String): ECDSAPrivateKey

功能:将加密的私钥从 DER 格式解码。

参数:

  • blob: DerBlob - 二进制格式的私钥对象。
  • password!: ?String - 解密私钥需要提供的密码,密码为 None 时则不解密。

返回值:

异常:

  • CryptoException - 解码失败、解密失败或者参数密码为空字符串,抛出异常。

static func decodeFromPem(String)

public static func decodeFromPem(text: String): ECDSAPrivateKey

功能:将私钥从 PEM 格式解码。

参数:

  • text: String - PEM 格式的私钥字符流。

返回值:

异常:

  • CryptoException - 解码失败、字符流不符合 PEM 格式或文件头不符合私钥头标准时,抛出异常。

static func decodeFromPem(String, ?String)

public static func decodeFromPem(text: String, password!: ?String): ECDSAPrivateKey

功能:将私钥从PEM 格式解码。

参数:

  • text: String - PEM 格式的私钥字符流。
  • password!: ?String - 解密私钥需要提供的密码,密码为 None 时则不解密。

返回值:

异常:

  • CryptoException - 解码失败、解密失败、参数密码为空字符串、字符流不符合 PEM 格式或文件头不符合私钥头标准时,抛出异常。

func encodeToDer()

public override func encodeToDer(): DerBlob

功能:将私钥编码为 DER 格式。

返回值:

  • DerBlob - 编码后的 Der 格式私钥。

异常:

func encodeToDer(?String)

public func encodeToDer(password!: ?String): DerBlob

功能:使用 AES-256-CBC 加密私钥,将私钥编码为 DER 格式。

参数:

  • password!: ?String - 加密私钥需要提供的密码,密码为 None 时则不加密。

返回值:

  • DerBlob - 编码后的 DER 格式私钥。

异常:

  • CryptoException - 编码失败、加密失败或者参数密码为空字符串,抛出异常。

func encodeToPem()

public override func encodeToPem(): PemEntry

功能:将私钥编码为 PEM 格式。

返回值:

  • PemEntry - 私钥 PEM 格式的对象。

异常:

func sign(Array<Byte>)

public func sign(digest: Array<Byte>): Array<Byte>

功能:sign 对数据的摘要结果进行签名。

参数:

  • digest: Array<Byte> - 数据的摘要结果。

返回值:

  • Array<Byte> - 签名后的数据。

异常:

func toString

public override func toString(): String

功能:输出私钥种类。

返回值:

  • String - 密钥类别描述。

class ECDSAPublicKey

public class ECDSAPublicKey <: PublicKey {
    public init(pri: ECDSAPrivateKey)
}

功能:ECDSA 公钥类,提供生成 ECDSA 公钥能力,ECDSA 公钥支持验证签名操作,支持 PEM 和 DER 格式的编码解码。使用示例见 ECDSA 密钥示例

父类型:

init(ECDSAPrivateKey)

public init(pri: ECDSAPrivateKey)

功能:init 初始化公钥,从私钥中获取对应的公钥。

参数:

异常:

static func decodeDer(DerBlob)

public static func decodeDer(blob: DerBlob): ECDSAPublicKey

功能:将公钥从 DER 格式解码。

参数:

  • blob: DerBlob - 二进制格式的公钥对象。

返回值:

异常:

static func decodeFromPem(String)

public static func decodeFromPem(text: String): ECDSAPublicKey

功能:将公钥从 PEM 格式解码。

参数:

  • text: String - PEM 格式的公钥字符流。

返回值:

异常:

  • CryptoException - 解码失败、字符流不符合 PEM 格式或文件头不符合公钥头标准时,抛出异常。

func encodeToDer()

public override func encodeToDer(): DerBlob

功能:将公钥编码为 DER 格式。

返回值:

  • DerBlob - 编码后的 Der 格式公钥。

异常:

func encodeToPem()

public override func encodeToPem(): PemEntry

功能:将公钥编码为 PEM 格式。

返回值:

异常:

func toString

public override func toString(): String

功能:输出公钥种类。

返回值:

  • String - 密钥类别描述。

func verify(Array<Byte>, Array<Byte>)

public func verify(digest: Array<Byte>, sig: Array<Byte>): Bool

功能:verify 验证签名结果。

参数:

  • digest: Array<Byte> - 数据的摘要结果。
  • sig: Array<Byte> - 数据的签名结果。

返回值:

  • Bool - 返回 true 表示验证成功,false 失败。

class RSAPrivateKey

public class RSAPrivateKey <: PrivateKey{
    public init(bits: Int32)
    public init(bits: Int32, e: BigInt)
}

功能:RSA 私钥类,提供生成 RSA 私钥能力,RSA 私钥支持签名和解密操作,支持 PEM 和 DER 格式的编码解码,符合 PKCS1 标准。使用示例见 RSA 密钥示例

父类型:

init(Int32)

public init(bits: Int32)

功能:init 初始化生成私钥,公钥指数默认值为 65537,业界推荐。公钥指数e的大小直接影响了RSA算法的安全性和加密效率。通常情况下,e的值越小,加密速度越快,但安全性越低。

参数:

  • bits: Int32 - 密钥长度,需要大于等于 512 位,并且小于等于 16384 位。

异常:

  • CryptoException - 密钥长度不符合要求或初始化失败,抛出异常。

init(Int32, BigInt)

public init(bits: Int32, e: BigInt)

功能:init 初始化生成私钥,允许用户指定公共指数。

参数:

  • bits: Int32 - 密钥长度,需要大于等于 512 位,并且小于等于 16384 位,推荐使用的密钥长度不小于 3072 位。
  • e: BigInt - 公钥公共指数,范围是 [3, 2^256-1] 的奇数。

异常:

  • CryptoException - 密钥长度不符合要求、公钥公共指数值不符合要求或初始化失败,抛出异常。

static func decodeDer(DerBlob)

public static func decodeDer(blob: DerBlob): RSAPrivateKey

功能:将私钥从 DER 格式解码。

参数:

  • blob: DerBlob - 二进制格式的私钥对象。

返回值:

异常:

static func decodeDer(DerBlob, ?String)

public static func decodeDer(blob: DerBlob, password!: ?String): RSAPrivateKey

功能:将加密的私钥从 DER 格式解码。

参数:

  • blob: DerBlob - 二进制格式的私钥对象。
  • password!: ?String - 解密私钥需要提供的密码,密码为 None 时则不解密。

返回值:

异常:

  • CryptoException - 解码失败、解密失败或者参数密码为空字符串,抛出异常。

static func decodeFromPem(String)

public static func decodeFromPem(text: String): RSAPrivateKey

功能:将私钥从 PEM 格式解码。

参数:

  • text: String - PEM 格式的私钥字符流。

返回值:

异常:

  • CryptoException - 解码失败、解密失败、字符流不符合 PEM 格式或文件头不符合私钥头标准时,抛出异常。

static func decodeFromPem(String, ?String)

public static func decodeFromPem(text: String, password!: ?String): RSAPrivateKey

功能:将私钥从 PEM 格式解码。

参数:

  • text: String - PEM 格式的私钥字符流。
  • password!: ?String - 解密私钥需要提供的密码,密码为 None 时则不解密。

返回值:

异常:

  • CryptoException - 解码失败、解密失败、参数密码为空字符串、字符流不符合 PEM 格式或文件头不符合私钥头标准时,抛出异常。

func decrypt(InputStream, OutputStream, PadOption)

public func decrypt(input: InputStream, output: OutputStream, padType!: PadOption): Unit

功能:decrypt 解密出原始数据。

参数:

  • input: InputStream - 加密的数据。
  • output: OutputStream - 解密后的数据。
  • padType!: PadOption - 填充模式,可以选择 PKCS1 或 OAEP 模式,不支持 PSS 模式,在对安全场景要求较高的情况下,推荐使用 OAEP 填充模式。

异常:

  • CryptoException - 设置填充模式失败或解密失败,抛出异常。

func encodeToDer()

public override func encodeToDer(): DerBlob

功能:将私钥编码为 DER 格式。

返回值:

  • DerBlob - 编码后的 DER 格式私钥。

异常:

func encodeToDer(?String)

public func encodeToDer(password!: ?String): DerBlob

功能:使用 AES-256-CBC 加密私钥,将私钥编码为 DER 格式。

参数:

  • password!: ?String - 加密私钥需要提供的密码,密码为 None 时则不加密。

返回值:

  • DerBlob - 编码后的 DER 格式私钥。

异常:

  • CryptoException - 编码失败、加密失败或者参数密码为空字符串,抛出异常。

func encodeToPem()

public override func encodeToPem(): PemEntry

功能:将私钥编码为 PEM 格式。

返回值:

  • PemEntry - 私钥 PEM 格式的对象。

异常:

func sign(Digest, Array<Byte>, PadOption)

public func sign(hash: Digest, digest: Array<Byte>, padType!: PadOption): Array<Byte>

功能:对数据的摘要结果进行签名。

参数:

  • hash: Digest - 摘要方法,获取 digest 结果使用的摘要方法。
  • digest: Array<Byte> - 数据的摘要结果。
  • padType!: PadOption - 填充模式,可以选择 PKCS1 或 PSS 模式,不支持 OAEP 模式,在对安全场景要求较高的情况下,推荐使用 PSS 填充模式。

返回值:

  • Array<Byte> - 签名后的数据。

异常:

  • CryptoException - 设置摘要方法失败、设置填充模式失败或签名失败,抛出异常。

func toString()

public override func toString(): String

功能:输出私钥种类。

返回值:

  • String - 密钥类别描述。

class RSAPublicKey

public class RSAPublicKey <: PublicKey {
    public init(pri: RSAPrivateKey)
}

功能:RSA 公钥类,提供生成 RSA 公钥能力,RSA 公钥支持验证签名和加密操作,支持 PEM 和 DER 格式的编码解码。使用示例见 RSA 密钥示例

父类型:

init(RSAPrivateKey)

public init(pri: RSAPrivateKey)

功能:init 初始化公钥,从私钥中获取对应的公钥。

参数:

异常:

static func decodeDer(DerBlob)

public static func decodeDer(blob: DerBlob): RSAPublicKey

功能:将公钥从 DER 格式解码。

参数:

  • blob: DerBlob - 二进制格式的公钥对象。

返回值:

异常:

static func decodeFromPem(String)

public static func decodeFromPem(text: String): RSAPublicKey

功能:将公钥从PEM 格式解码。

参数:

  • text: String - PEM 格式的公钥字符流。

返回值:

异常:

  • CryptoException - 解码失败、字符流不符合 PEM 格式或文件头不符合公钥头标准时,抛出异常。

func encodeToDer()

public override func encodeToDer(): DerBlob

功能:将公钥编码为 DER 格式。

返回值:

  • DerBlob - 编码后的 Der 格式公钥。

异常:

func encodeToPem()

public override func encodeToPem(): PemEntry

功能:将公钥编码为 PEM 格式。

返回值:

异常:

func encrypt(InputStream, OutputStream, PadOption)

public func encrypt(input: InputStream, output: OutputStream, padType!: PadOption): Unit

功能:encrypt 给一段数据进行加密。

参数:

  • input: InputStream - 需要加密的数据。
  • output: OutputStream - 加密后的数据。
  • padType!: PadOption - 填充模式,可以选择 PKCS1 或 OAEP 模式,不支持 PSS 模式,在对安全场景要求较高的情况下,推荐使用 OAEP 填充模式。

异常:

  • CryptoException - 设置填充模式失败或加密失败,抛出异常。

func toString()

public override func toString(): String

功能:输出公钥种类。

返回值:

  • String - 密钥类别描述。

func verify(Digest, Array<Byte>, Array<Byte>, PadOption)

public func verify(hash: Digest, digest: Array<Byte>, sig: Array<Byte>, padType!: PadOption): Bool

功能:verify 验证签名结果。

参数:

  • hash: Digest - 摘要方法,获取 digest 结果使用的摘要方法。
  • digest: Array<Byte> - 数据的摘要结果。
  • sig: Array<Byte> - 数据的签名结果。
  • padType!: PadOption - 填充模式,可以选择 PKCS1 或 PSS 模式,不支持 OAEP 模式,在对安全场景要求较高的情况下,推荐使用 PSS 填充模式。

返回值:

  • Bool - 返回 true 表示验证成功,false 失败。

异常:

  • CryptoException - 设置填充模式失败或验证失败,抛出异常。

class SM2PrivateKey

public class SM2PrivateKey <: PrivateKey {
    public init()
}

功能:SM2 私钥类,提供生成 SM2 私钥能力,SM2 私钥支持签名和解密操作,支持 PEM 和 DER 格式的编码解码,符合 PKCS1 标准。使用示例见 SM2 密钥示例

父类型:

init()

public init()

功能:init 初始化生成私钥。

异常:

static func decodeDer(DerBlob)

public static func decodeDer(blob: DerBlob): SM2PrivateKey

功能:将私钥从 DER 格式解码。

参数:

  • blob: DerBlob - 二进制格式的私钥对象。

返回值:

异常:

static func decodeDer(DerBlob, ?String)

public static func decodeDer(blob: DerBlob, password!: ?String): SM2PrivateKey

功能:将加密的私钥从 DER 格式解码。

参数:

  • blob: DerBlob - 二进制格式的私钥对象。
  • password!: ?String - 解密私钥需要提供的密码,密码为 None 时则不解密。

返回值:

异常:

  • CryptoException - 解码失败、解密失败或者参数密码为空字符串,抛出异常。

static func decodeFromPem(String)

public static func decodeFromPem(text: String): SM2PrivateKey

功能:将私钥从 PEM 格式解码。

参数:

  • text: String - PEM 格式的私钥字符流。

返回值:

异常:

  • CryptoException - 解码失败、解密失败、字符流不符合 PEM 格式或文件头不符合私钥头标准时,抛出异常。

static func decodeFromPem(String, ?String)

public static func decodeFromPem(text: String, password!: ?String): SM2PrivateKey

功能:将私钥从 PEM 格式解码。

参数:

  • text: String - PEM 格式的私钥字符流。
  • password!: ?String - 解密私钥需要提供的密码,密码为 None 时则不解密。

返回值:

异常:

  • CryptoException - 解码失败、解密失败、参数密码为空字符串、字符流不符合 PEM 格式或文件头不符合私钥头标准时,抛出异常。

func decrypt(Array<Byte>)

public func decrypt(input: Array<Byte>): Array<Byte>

功能:decrypt 解密出原始数据,待解密密文需要遵循 ASN.1 编码规则。

参数:

  • input: Array<Byte> - 加密的数据。

返回值:

  • Array<Byte> - 解密后的数据。

异常:

func encodeToDer()

public func encodeToDer(): DerBlob

功能:将私钥编码为 DER 格式。

返回值:

  • DerBlob - 编码后的 DER 格式私钥。

异常:

func encodeToDer(?String)

public func encodeToDer(password!: ?String): DerBlob

功能:使用 AES-256-CBC 加密私钥,将私钥编码为 DER 格式。

参数:

  • password!: ?String - 加密私钥需要提供的密码,密码为 None 时则不加密。

返回值:

  • DerBlob - 编码后的 DER 格式公钥。

异常:

  • CryptoException - 编码失败、加密失败或者参数密码为空字符串,抛出异常。

func encodeToPem(?String)

public func encodeToPem(password!: ?String): PemEntry 

功能:将加密的私钥编码为 PEM 格式。

参数:

  • password!: ?String - 加密私钥需要提供的密码,密码为 None 时则不加密。

返回值:

  • PemEntry - 私钥 PEM 格式的对象。

异常:

  • CryptoException - 编码失败、加密失败或者参数密码为空字符串,抛出异常。

func encodeToPem()

public func encodeToPem(): PemEntry

功能:将私钥编码为 PEM 格式。

返回值:

  • PemEntry - 私钥 PEM 格式的对象。

异常:

func sign(Array<Byte>)

public func sign(data: Array<Byte>): Array<Byte>

功能:sign 对数据进行签名,SM2 采用SM3数据摘要算法。

参数:

  • data: Array<Byte> - 数据。

返回值:

  • Array<Byte> - 签名后的数据。

异常:

func toString

public override func toString(): String

功能:输出私钥种类。

返回值:

  • String - 密钥类别描述。

class SM2PublicKey

public class SM2PublicKey <: PublicKey {
    public init(pri: SM2PrivateKey)
}

功能:SM2 公钥类,提供生成 SM2 公钥能力,SM2 公钥支持验证签名和加密操作,支持 PEM 和 DER 格式的编码解码。使用示例见 SM2 密钥示例

父类型:

init(SM2PrivateKey)

public init(pri: SM2PrivateKey)

功能:init 初始化公钥,从私钥中获取对应的公钥。

参数:

异常:

static func decodeDer(DerBlob)

public static func decodeDer(blob: DerBlob): SM2PublicKey

功能:将公钥从 DER 格式解码。

参数:

  • blob: DerBlob - 二进制格式的公钥对象。

返回值:

异常:

static func decodeFromPem(String)

public static func decodeFromPem(text: String): SM2PublicKey

功能:将公钥从PEM 格式解码。

参数:

  • text: String - PEM 格式的公钥字符流。

返回值:

异常:

  • CryptoException - 解码失败、字符流不符合 PEM 格式或文件头不符合公钥头标准时,抛出异常。

func encodeToDer()

public func encodeToDer(): DerBlob

功能:将公钥编码为 DER 格式。

返回值:

  • DerBlob - 编码后的 Der 格式公钥。

异常:

func encodeToPem()

public func encodeToPem(): PemEntry

功能:将公钥编码为 PEM 格式。

返回值:

异常:

func encrypt(Array<Byte>)

public func encrypt(input: Array<Byte>): Array<Byte> 

功能:encrypt 给一段数据进行加密,输出密文遵循 ASN.1 编码规则。

参数:

  • input: Array<Byte> - 需要加密的数据。

返回值:

  • Array<Byte> - 加密后的数据。

异常:

func toString()

public override func toString(): String

功能:输出公钥种类。

返回值:

  • String - 密钥类别描述。

func verify(Array<Byte>, Array<Byte>)

public func verify(data: Array<Byte>, sig: Array<Byte>): Bool

功能:verify 验证签名结果。

参数:

  • data: Array<Byte> - 数据。
  • sig: Array<Byte> - 数据的签名结果。

返回值:

  • Bool - 返回 true 表示验证成功,false 失败。

异常:

  • CryptoException - 设置填充模式失败或验证失败,抛出异常。

枚举

enum Curve

public enum Curve {
    | P224 | P256 | P384 | P521 | BP256 | BP320 | BP384 | BP512
}

功能:枚举类型 Curve 用于选择生成 ECDSA 密钥时使用的椭圆曲线类型。

椭圆曲线是一种数学曲线,常用于加密算法中的密钥生成。在密码学中,椭圆曲线密码算法是一种基于椭圆曲线的公钥密码算法。它的基本思想是利用椭圆曲线上的点集构成一个计算困难性,来实现公钥密码的安全性。

Curve 枚举类型支持 NIST P-224,NIST P-256,NIST P-384,NIST P-521,Brainpool P-256,Brainpool P-320,Brainpool P-384,Brainpool P-512 八种椭圆曲线。

  • NIST P-224:基于椭圆曲线的加密算法,使用224位的素数作为模数,安全性较高,适用于轻量级应用。

  • NIST P-256:基于椭圆曲线的加密算法,使用256位的素数作为模数,安全性较高,适用于中等级应用。

  • NIST P-384:基于椭圆曲线的加密算法,使用384位的素数作为模数,安全性非常高,适用于高级别应用。

  • NIST P-521:基于椭圆曲线的加密算法,使用521位的素数作为模数,安全性非常高,适用于极高级别应用。

  • Brainpool P-256:基于椭圆曲线的加密算法,使用256位的素数作为模数,安全性较高,但比NIST P-256更快。

  • Brainpool P-320:基于椭圆曲线的加密算法,使用320位的素数作为模数,安全性非常高,但比NIST P-384更快。

  • Brainpool P-384:基于椭圆曲线的加密算法,使用384位的素数作为模数,安全性非常高,但比NIST P-384更快。

  • Brainpool P-512:基于椭圆曲线的加密算法,使用512位的素数作为模数,安全性非常高,但比NIST P-521更快

BP256

BP256

功能:使用 Brainpool P-256 椭圆曲线初始化 Curve 实例。

BP320

BP320

功能:使用 Brainpool P-320 椭圆曲线初始化 Curve 实例。

BP384

BP384

功能:使用 Brainpool P-384 椭圆曲线初始化 Curve 实例。

BP512

BP512

功能:使用 Brainpool P-512 椭圆曲线初始化 Curve 实例。

P224

P224

功能:使用 NIST P-224 椭圆曲线初始化 Curve 实例。

P256

P256

功能:使用 NIST P-256 椭圆曲线初始化 Curve 实例。

P384

P384

功能:使用 NIST P-384 椭圆曲线初始化 Curve 实例。

P521

P521

功能:使用 NIST P-521 椭圆曲线初始化 Curve 实例。

enum PadOption

public enum PadOption {
    | OAEP(OAEPOption) | PSS(PSSOption) | PKCS1
}

功能:用于设置 RSA 的填充模式。

RSA 有三种常用的填充模式:

OAEP 为最优非对称加密填充,只能用于加密解密; PSS 为概率签名方案,只能用于签名和验证; PKCS1 是一种普通的填充模式,用于填充数据长度,可以用于加密、解密、签名和验证。 RSA 的 PKCS1 填充模式是在早期的 PKCS #1 v1.5 规范中定义的填充模式,当前对使用 PKCS1 填充模式的攻击较为成熟,容易被攻击者解密或伪造签名,建议采用 PKCS #1 v2 版本中更加安全的 PSS 或 OAEP 填充模式。

OAEP(OAEPOption)

OAEP(OAEPOption)

功能:使用最优非对称加密初始化 PadOption 实例。

PKCS1

PKCS1

功能:使用 PKCS #1 公钥密码学标准初始化 PadOption 实例。

PSS(PSSOption)

PSS(PSSOption)

功能:使用概率签名方案初始化 PadOption 实例。

结构体

struct OAEPOption

public struct OAEPOption {
    public init(hash: Digest, mgfHash: Digest, label!: String = "")
}

功能:此结构体为 OAEP 填充模式需要设置的参数。

init(Digest, Digest, String)

public init(hash: Digest, mgfHash: Digest, label!: String = "")

功能:初始化 OAEP 填充参数。

参数:

  • hash: Digest - 摘要方法,用于对 label 进行摘要。
  • mgfHash: Digest - 摘要方法,用于设置 MGF1 函数中的摘要方法。
  • label!: String - label 是可选参数,默认为空字符串,可以通过设置 label 来区分不同的加密操作。

struct PSSOption

public struct PSSOption {
    public init(saltLen: Int32)
}

功能: 此结构体为 PSS 填充模式需要设置的参数。

init(Int32)

public init(saltLen: Int32)

功能:初始化 PSS 填充参数。

参数:

  • saltLen: Int32 - 随机盐长度,长度应大于等于 0,小于等于(RSA 长度 - 摘要长度 - 2),长度单位为字节,长度过长会导致签名失败。

异常:

keys 使用

RSA 密钥示例

生成 rsa 公钥及私钥,并使用公钥的 OAEP 填充模式加密,用私钥的 OAEP 填充模式解密

示例:

import stdx.crypto.keys.*
import stdx.crypto.digest.*
import std.io.*
import std.crypto.digest.*

main() {
    var rsaPri = RSAPrivateKey(2048)
    var rsaPub = RSAPublicKey(rsaPri)

    var str: String = "hello world, hello cangjie"
    var bas1 = ByteBuffer()
    var bas2 = ByteBuffer()
    var bas3 = ByteBuffer()
    bas1.write(str.toArray())

    var encOpt = OAEPOption(SHA1(), SHA256())
    rsaPub.encrypt(bas1, bas2, padType: OAEP(encOpt))
    var encOpt2 = OAEPOption(SHA1(), SHA256())
    rsaPri.decrypt(bas2, bas3, padType: OAEP(encOpt2))

    var buf = Array<Byte>(str.size, repeat: 0)
    bas3.read(buf)
    if (str.toArray() == buf) {
        println("success")
    } else {
        println("fail")
    }
}

运行结果:

success

从文件中读取 rsa 公钥和私钥,并使用私钥的 PKCS1 填充模式签名,用公钥的 PKCS1 填充模式验证签名结果

说明: >

  • 需要自行准备公私钥文件。

示例:

import stdx.crypto.keys.*
import stdx.crypto.digest.*
import std.crypto.digest.*
import std.fs.*
import std.io.*
 
main() {
    var pemPri = String.fromUtf8(readToEnd(File("./files/rsaPri.pem", Read)))
    var rsaPri = RSAPrivateKey.decodeFromPem(pemPri)
 
    var pemPub = String.fromUtf8(readToEnd(File("./files/rsaPub.pem", Read)))
    var rsaPub = RSAPublicKey.decodeFromPem(pemPub)
 
    var str: String = "helloworld"
    var sha512Instance = SHA512()
    sha512Instance.write(str.toArray())
    var md: Array<Byte> = sha512Instance.finish()
 
    var sig = rsaPri.sign(sha512Instance, md, padType: PKCS1)
    if (rsaPub.verify(sha512Instance, md, sig, padType: PKCS1)){
        println("verify successful")
    }
}

运行结果:

verify successful

ECDSA 密钥示例

生成 ECDSA 公钥及私钥,并使用私钥签名,公钥验证签名结果

示例:

import stdx.crypto.keys.*
import stdx.crypto.digest.*
import std.convert.*
import std.crypto.digest.*

main() {
    var ecPri = ECDSAPrivateKey(P224)
    var ecPub = ECDSAPublicKey(ecPri)

    var str: String = "helloworld"
    var sha512Instance = SHA512()
    sha512Instance.write(str.toArray())
    var md: Array<Byte> = sha512Instance.finish()

    var sig = ecPri.sign(md)
    if (ecPub.verify(md, sig)) {
        println("verify successful")
    }
}

运行结果:

verify successful

SM2 密钥示例

生成 SM2 公钥及私钥,并使用私钥签名,公钥验证签名结果

示例:

import stdx.crypto.keys.*
import stdx.crypto.digest.*
import std.convert.*
import std.crypto.digest.*
import std.fs.*
import std.io.*

main(): Unit {
    /* 无参生成公钥私钥 */
    let sm2PrivateKey = SM2PrivateKey()
    let sm2PublicKey = SM2PublicKey(sm2PrivateKey)

    /* 公钥和私钥导出 */
    let priPem = sm2PrivateKey.encodeToPem()
    let file1: File = File("./sm2Pri.pem", Write)
    file1.write(priPem.encode().toArray())
    file1.close()

    let pubPem = sm2PublicKey.encodeToPem()
    let file2: File = File("./sm2Pub.pem", Write)
    file2.write(pubPem.encode().toArray())
    file2.close()

    /* 公钥加密,私钥解密 */
    let str: String = "helloworld"
    let encresult = sm2PublicKey.encrypt(str.toArray())
    let decresult = sm2PrivateKey.decrypt(encresult)
    println(String.fromUtf8(decresult))

    /* 私钥签名,公钥验证 */
    let strSig: String = "helloworld"
    let sigRe = sm2PrivateKey.sign(strSig.toArray())
    let verifyre = sm2PublicKey.verify(strSig.toArray(), sigRe)
    println(verifyre)

    /* 私钥公钥导入 */
    let pemPri = String.fromUtf8(readToEnd(File("./sm2Pri.pem", Read)))
    let sm2PrivateKeyNew = SM2PrivateKey.decodeFromPem(pemPri)
    println(sm2PrivateKeyNew)
    let pemPub = String.fromUtf8(readToEnd(File("./sm2Pub.pem", Read)))
    let sm2PublicKeyNew = SM2PublicKey.decodeFromPem(pemPub)
    println(sm2PublicKeyNew)
}

运行结果:

helloworld
true
SM2 PRIVATE KEY
SM2 PUBLIC KEY

stdx.crypto.x509

功能介绍

x509 包提供处理数字证书功能,提供包括解析和序列化 X509 证书、验证证书、创建自签名证书、创建和验证证书链等主要功能。

使用本包需要外部依赖 OpenSSL 3 的 crypto 动态库文件,故使用前需安装相关工具。

  • 对于 Linux 操作系统,可参考以下方式:

    • 如果系统的包管理工具支持安装 OpenSSL 3 开发工具包,可通过这个方式安装,并确保系统安装目录下含有 libcrypto.so 和 libcrypto.so.3 这两个动态库文件,例如 Ubuntu 22.04 系统上可使用 sudo apt install libssl-dev 命令安装 libssl-dev 工具包;
    • 如果无法通过上面的方式安装,可自行下载 OpenSSL 3.x.x 源码编译安装软件包,并确保安装目录下含有 libcrypto.so 和 libcrypto.so.3 这两个动态库文件,然后可选择下面任意一种方式来保证系统链接器可以找到这些文件:
      • 在系统未安装 OpenSSL 的场景,安装时选择直接安装到系统路径下;
      • 安装在自定义目录的场景,将这些文件所在目录设置到环境变量 LD_LIBRARY_PATH 以及 LIBRARY_PATH 中。
  • 对于 Windows 操作系统,可按照以下步骤:

    • 自行下载 OpenSSL 3.x.x 源码编译安装 x64 架构软件包或者自行下载安装第三方预编译的供开发人员使用的 OpenSSL 3.x.x 软件包;
    • 确保安装目录下含有 libcrypto.dll.a(或 libcrypto.lib)、libcrypto-3-x64.dll 这两个库文件;
    • 将 libcrypto.dll.a(或 libcrypto.lib) 所在的目录路径设置到环境变量 LIBRARY_PATH 中,将 libcrypto-3-x64.dll 所在的目录路径设置到环境变量 PATH 中。
  • 对于 macOS 操作系统,可参考以下方式:

    • 使用 brew install openssl@3 安装,并确保系统安装目录下含有 libcrypto.dylib 和 libcrypto.3.dylib 这两个动态库文件;
    • 如果无法通过上面的方式安装,可自行下载 OpenSSL 3.x.x 源码编译安装软件包,并确保安装目录下含有 libcrypto.dylib 和 libcrypto.3.dylib 这两个动态库文件,然后可选择下面任意一种方式来保证系统链接器可以找到这些文件:
      • 在系统未安装 OpenSSL 的场景,安装时选择直接安装到系统路径下;
      • 安装在自定义目录的场景,将这些文件所在目录设置到环境变量 DYLD_LIBRARY_PATH 以及 LIBRARY_PATH 中。

说明:

如果未安装 OpenSSL 3 软件包或者安装低版本的软件包,程序可能无法使用并抛出相关异常 X509Exception: Can not load openssl library or function xxx。

API 列表

类型别名

类型别名功能
IPx509 用 Array<Byte> 来记录 IP。

接口

接口名功能
DHParamters提供 DH 密钥接口。
Key提供密钥接口。
PrivateKey提供私钥接口。
PublicKey提供公钥接口。

类名功能
X509CertificateX509 数字证书是一种用于加密通信的数字证书。
X509CertificateRequest数字证书签名请求。
X509Name证书实体可辨识名称。

枚举

枚举名功能
PublicKeyAlgorithm数字证书中包含的公钥信息。
SignatureAlgorithm证书签名算法。

结构体

结构体名功能
DerBlobCrypto 支持配置二进制证书流。
ExtKeyUsage数字证书扩展字段。
KeyUsage数字证书扩展字段中通常会包含携带公钥的用法说明。
PemPem 结构体。
PemEntryPEM 文本格式。
SerialNumber数字证书的序列号。
Signature数字证书的签名。
VerifyOption校验选项。
X509CertificateInfo证书信息。
X509CertificateRequestInfo证书请求信息。

异常类

异常类名功能
X509Exceptionx509 包的异常类。

类型别名

type IP

public type IP = Array<Byte>

功能:x509包用 Array<Byte> 来记录 IP

接口

interface DHParamters

public interface DHParamters <: Key {
    override func encodeToPem(): PemEntry
    static func decodeDer(blob: DerBlob): DHParamters
    static func decodeFromPem(text: String): DHParamters
}

功能:提供 DH 参数接口。

父类型:

static func decodeDer(DerBlob)

static func decodeDer(blob: DerBlob): DHParamters

功能:将 DH 密钥参数从 DER 格式解码。

说明:

  • DH(Diffie-Hellman)密钥交换协议是一种确保共享KEY安全穿越不安全网络的方法。
  • DER 和 PEM 是两种常见的编码格式。

参数:

  • blob: DerBlob - DER 格式的 DH 密钥参数对象。

返回值:

  • DHParamters - 由 DER 格式解码出的 DH 密钥参数。

异常:

  • X509Exception - 当 DER 格式的 DH 密钥参数内容不正确,无法解析时抛出异常。

static func decodeFromPem(String)

static func decodeFromPem(text: String): DHParamters

功能:将 DH 密钥参数从 PEM 格式解码。

说明:

PEM 是用 ASCLL(BASE64)编码的证书。

参数:

  • text: String - PEM 格式的 DH 密钥参数字符流。

返回值:

  • DHParamters - 由 PEM 格式解码出的 DH 密钥参数。

异常:

  • X509Exception - 字符流不符合 PEM 格式时,或文件头不符合 DH 密钥参数头标准 ("-----BEGIN DH PARAMETERS-----")时抛出异常。

func encodeToPem()

override func encodeToPem(): PemEntry

功能:将 DH 密钥参数编码为 PEM 格式。

返回值:

  • PemEntry - DH 密钥参数数据 PEM 格式编码生成的对象。

interface Key

public interface Key <: ToString {
    func encodeToDer(): DerBlob
    func encodeToPem(): PemEntry
    static func decodeDer(encoded: DerBlob): Key
    static func decodeFromPem(text: String): Key
}

功能:提供密钥接口。 公钥用于签名验证或加密,私钥用于签名或解密,公钥和私钥必须相互匹配并形成一对。 该类为密钥类,无具体实现,供 PrivateKey/PublicKey 及用户扩展接口。

父类型:

  • ToString

static func decodeDer(DerBlob)

static func decodeDer(encoded: DerBlob): Key

功能:将密钥从 DER 格式解码。

参数:

  • encoded: DerBlob - DER 格式的对象。

返回值:

  • Key - 由 DER 格式解码出的密钥。

异常:

  • X509Exception - 当 DER 格式的私钥内容不正确,无法解析时抛出异常。

static func decodeFromPem(String)

static func decodeFromPem(text: String): Key

功能:将密钥从 PEM 格式解码。

参数:

  • text: String - PEM 格式的字符流。

返回值:

  • Key - 由 PEM 格式解码出的密钥。

func encodeToDer()

func encodeToDer(): DerBlob

功能:将密钥编码为 DER 格式。

返回值:

  • DerBlob - 密钥数据 DER 格式编码生成的对象。

func encodeToPem()

func encodeToPem(): PemEntry

功能:将密钥编码为 PEM 格式。

返回值:

  • PemEntry - 密钥数据 PEM 格式编码生成的对象。

interface PrivateKey

public interface PrivateKey <: Key {
    static func decodeDer(blob: DerBlob): PrivateKey
    static func decodeFromPem(text: String): PrivateKey
    static func decodeDer(blob: DerBlob, password!: ?String): PrivateKey
    static func decodeFromPem(text: String, password!: ?String): PrivateKey
    func encodeToDer(password!: ?String): DerBlob
    override func encodeToPem(): PemEntry
    func encodeToPem(password!: ?String): PemEntry
}

功能:提供私钥接口。

父类型:

static func decodeDer(DerBlob)

static func decodeDer(blob: DerBlob): PrivateKey

功能:将私钥从 DER 格式解码。

参数:

  • blob: DerBlob - DER 格式的私钥对象。

返回值:

  • PrivateKey - 由 DER 格式解码出的私钥。

异常:

  • X509Exception - 当 DER 格式的私钥内容不正确,无法解析时抛出异常。

static func decodeDer(DerBlob, ?String)

static func decodeDer(blob: DerBlob, password!: ?String): PrivateKey 

功能:将 DER 格式的私钥解密解码成 PrivateKey 对象,密码为 None 时则不解密。

参数:

  • blob: DerBlob - DER 格式的私钥。
  • password!: ?String - 解密密码。

返回值:

异常:

  • X509Exception - 解密解码失败,或者 password 为空字符串。

static func decodeFromPem(String)

static func decodeFromPem(text: String): PrivateKey

功能:将私钥从 PEM 格式解码。

参数:

  • text: String - PEM 格式的私钥字符流。

返回值:

  • PrivateKey - 由 PEM 格式解码出的私钥。

异常:

  • X509Exception - 字符流不符合 PEM 格式时,或文件头不符合公钥头标准时抛出异常。

static func decodeFromPem(String, ?String)

static func decodeFromPem(text: String, password!: ?String): PrivateKey 

功能:将 PEM 格式的私钥解密解码成 PrivateKey 对象,密码为 None 时则不解密。

参数:

  • text: String - PEM 格式的私钥。
  • password!: ?String - 解密密码。

返回值:

异常:

  • X509Exception - 解密解码失败,或者 password 为空字符串。

func encodeToDer(?String)

func encodeToDer(password!: ?String): DerBlob

功能:将私钥加密编码成 DER 格式,密码为 None 时则不加密。

参数:

  • password!: ?String - 加密密码。

返回值:

  • DerBlob - 加密后的 DER 格式的私钥。

异常:

  • X509Exception - 加密失败,或者 password 为空字符串。

func encodeToPem()

override func encodeToPem(): PemEntry

功能:将私钥编码成 PEM 格式。

返回值:

  • PemEntry - 编码后的 PEM 格式的私钥。

异常:

func encodeToPem(?String)

func encodeToPem(password!: ?String): PemEntry

功能:将私钥加密编码成 PEM 格式,密码为 None 时则不加密。

参数:

  • password!: ?String - 加密密码。

返回值:

  • PemEntry - 加密后的 PEM 格式的私钥。

异常:

  • X509Exception - 加密失败,或者 password 为空字符串。

interface PublicKey

public interface PublicKey <: Key {
    override func encodeToPem(): PemEntry
    static func decodeDer(blob: DerBlob): PublicKey
    static func decodeFromPem(text: String): PublicKey
}

功能:公钥接口。

父类型:

static func decodeDer(DerBlob)

static func decodeDer(blob: DerBlob): PublicKey

功能:将公钥从 DER 格式解码。

参数:

  • blob: DerBlob - DER 格式的公钥对象。

返回值:

  • PublicKey - 由 DER 格式解码出的公钥。

异常:

  • X509Exception - 当 DER 格式的公钥内容不正确,无法解析时抛出异常。

static func decodeFromPem(String)

static func decodeFromPem(text: String): PublicKey

功能:将公钥从 PEM 格式解码。

参数:

  • text: String - PEM 格式的公钥字符流。

返回值:

  • PublicKey - 由 PEM 格式解码出的公钥。

异常:

  • X509Exception - 字符流不符合 PEM 格式时,或文件头不符合公钥头标准时抛出异常。

func encodeToPem()

override func encodeToPem(): PemEntry

功能:将公钥编码为 PEM 格式。

返回值:

  • PemEntry - 公钥数据 PEM 格式编码生成的对象。

x509 包

class X509Certificate

public class X509Certificate <: Equatable<X509Certificate> & Hashable & ToString {
    public init(
        certificateInfo: X509CertificateInfo,
        parent!: X509Certificate,
        publicKey!: PublicKey,
        privateKey!: PrivateKey,
        signatureAlgorithm!: ?SignatureAlgorithm = None
    )
}

功能:X509 数字证书是一种用于加密通信的数字证书,它是公钥基础设施(PKI)的核心组件之一。X509 数字证书包含了一个实体的公钥和身份信息,用于验证该实体的身份和确保通信的安全性。

父类型:

prop dnsNames

public prop dnsNames: Array<String>

功能:解析数字证书备选名称中的域名。

类型:Array<String>

prop emailAddresses

public prop emailAddresses: Array<String>

功能:解析数字证书备选名称中的 email 地址。

类型:Array<String>

prop extKeyUsage

public prop extKeyUsage: ExtKeyUsage

功能:解析数字证书中的扩展密钥用法。

类型:ExtKeyUsage

prop issuer

public prop issuer: X509Name

功能:解析数字证书的颁发者信息。

类型:X509Name

prop IPAddresses

public prop IPAddresses: Array<IP>

功能:解析数字证书备选名称中的 IP 地址。

类型:Array<IP>

prop keyUsage

public prop keyUsage: KeyUsage

功能:解析数字证书中的密钥用法。

类型:KeyUsage

prop notAfter

public prop notAfter: DateTime

功能:解析数字证书的有效期截止时间。

类型:DateTime

prop notBefore

public prop notBefore: DateTime

功能:解析数字证书的有效期开始时间。

类型:DateTime

prop publicKey

public prop publicKey: PublicKey

功能:解析数字证书的公钥。

类型:PublicKey

prop publicKeyAlgorithm

public prop publicKeyAlgorithm: PublicKeyAlgorithm

功能:解析数字证书的公钥算法。

类型:PublicKeyAlgorithm

prop serialNumber

public prop serialNumber: SerialNumber

功能:解析数字证书的序列号。

类型:SerialNumber

prop signature

public prop signature: Signature

功能:解析数字证书的签名。

类型:Signature

prop signatureAlgorithm

public prop signatureAlgorithm: SignatureAlgorithm

功能:解析数字证书的签名算法。

类型:SignatureAlgorithm

prop subject

public prop subject: X509Name

功能:解析数字证书的使用者信息。

类型:X509Name

init(X509CertificateInfo, X509Certificate, PublicKey, PrivateKey, ?SignatureAlgorithm)

public init(
    certificateInfo: X509CertificateInfo,
    parent!: X509Certificate,
    publicKey!: PublicKey,
    privateKey!: PrivateKey,
    signatureAlgorithm!: ?SignatureAlgorithm = None
)

功能:创建数字证书对象。

参数:

  • certificateInfo: X509CertificateInfo - 数字证书配置信息。
  • parent!: X509Certificate - 颁发者证书。
  • publicKey!: PublicKey - 申请人公钥,仅支持 RSA、ECDSA 和 DSA 公钥。
  • privateKey!: PrivateKey - 颁发者私钥,仅支持 RSA、ECDSA 和 DSA 私钥。
  • signatureAlgorithm!: ?SignatureAlgorithm - 证书签名算法,默认值为 None,使用默认值时默认的摘要类型是 SHA256

异常:

  • X509Exception - 公钥或私钥类型不支持、私钥类型和证书签名算法中的私钥类型不匹配或数字证书信息设置失败时,抛出异常。

static func decodeFromDer(DerBlob)

public static func decodeFromDer(der: DerBlob): X509Certificate

功能:将 DER 格式的数字证书解码。

参数:

  • der: DerBlob - DER 格式的二进制数据。

返回值:

异常:

  • X509Exception - 数据为空时,或数据不是有效的数字证书 DER 格式时抛出异常。

static func decodeFromPem(String)

public static func decodeFromPem(pem: String): Array<X509Certificate>

功能:将数字证书从 PEM 格式解码。

参数:

  • pem: String - PEM 格式的数字证书字符流。

返回值:

异常:

  • X509Exception - 字符流不符合 PEM 格式时,或文件头不符合数字证书头标准时抛出异常。

func encodeToDer()

public func encodeToDer(): DerBlob

功能:将数字证书编码成 Der 格式。

返回值:

  • DerBlob - 编码后的 Der 格式的数字证书。

func encodeToPem()

public func encodeToPem(): PemEntry

功能:将数字证书编码成 PEM 格式。

返回值:

  • PemEntry - 编码后的 PEM 格式的数字证书。

func hashCode()

public override func hashCode(): Int64

功能:返回证书哈希值。

返回值:

  • Int64 - 对证书对象进行哈希计算后得到的结果。

static func systemRootCerts()

public static func systemRootCerts(): Array<X509Certificate>

功能:返回操作系统的根证书,支持 Linux,MacOS 和 Windows 平台。

返回值:

func toString()

public override func toString(): String

功能:生成证书名称字符串,包含证书的使用者信息、有效期以及颁发者信息。

返回值:

  • String - 证书名称字符串。

func verify(VerifyOption)

public func verify(verifyOption: VerifyOption): Bool

功能:根据验证选项验证当前证书的有效性。

验证优先级:

  1. 优先验证有效期;
  2. 可选验证 DNS 域名;
  3. 最后根据根证书和中间证书验证其有效性。

参数:

返回值:

  • Bool - 证书有效返回 true,否则返回 false。

异常:

  • X509Exception - 检验过程中失败,比如内存分配异常等内部错误,则抛出异常。

operator func !=(X509Certificate)

public override operator func !=(other: X509Certificate): Bool

功能:判不等。

参数:

返回值:

  • Bool - 若证书不同,返回 true;否则,返回 false。

operator func ==(X509Certificate)

public override operator func ==(other: X509Certificate): Bool

功能:判等。

参数:

返回值:

  • Bool - 若证书相同,返回 true;否则,返回 false。

class X509CertificateRequest

public class X509CertificateRequest <: Hashable & ToString {
    public init(
        privateKey: PrivateKey,
        certificateRequestInfo!: ?X509CertificateRequestInfo = None,
        signatureAlgorithm!: ?SignatureAlgorithm = None
    )
}

功能:数字证书签名请求。

父类型:

  • Hashable
  • ToString

prop IPAddresses

public prop IPAddresses: Array<IP>

功能:解析数字证书签名请求备选名称中的 IP 地址。

类型:Array<IP>

prop dnsNames

public prop dnsNames: Array<String>

功能:解析数字证书签名请求备选名称中的域名。

类型:Array<String>

prop emailAddresses

public prop emailAddresses: Array<String>

功能:解析数字证书签名请求备选名称中的 email 地址。

类型:Array<String>

prop publicKey

public prop publicKey: PublicKey

功能:解析数字证书签名请求的公钥。

类型:PublicKey

prop publicKeyAlgorithm

public prop publicKeyAlgorithm: PublicKeyAlgorithm

功能:解析数字证书签名请求的公钥算法。

类型:PublicKeyAlgorithm

prop signature

public prop signature: Signature

功能:解析数字证书签名请求的签名。

类型:Signature

prop signatureAlgorithm

public prop signatureAlgorithm: SignatureAlgorithm

功能:解析数字证书签名请求的签名算法。

类型:SignatureAlgorithm

prop subject

public prop subject: X509Name

功能:解析数字证书签名请求的使用者信息。

类型:X509Name

init(PrivateKey, ?X509CertificateRequestInfo, ?SignatureAlgorithm)

public init(
    privateKey: PrivateKey,
    certificateRequestInfo!: ?X509CertificateRequestInfo = None,
    signatureAlgorithm!: ?SignatureAlgorithm = None
)

功能:创建数字证书签名请求对象。

参数:

  • privateKey: PrivateKey - 私钥,仅支持 RSA、ECDSA 和 DSA 私钥。
  • certificateRequestInfo!: ?X509CertificateRequestInfo - 数字证书签名信息,默认值为 None。
  • signatureAlgorithm!: ?SignatureAlgorithm - 证书签名算法,默认值为 None,使用默认值时默认的摘要类型是 SHA256

异常:

  • X509Exception - 私钥类型不支持、私钥类型和证书签名算法中的私钥类型不匹配或数字证书签名信息设置失败时,抛出异常。

static func decodeFromDer(DerBlob)

public static func decodeFromDer(der: DerBlob): X509CertificateRequest

功能:将 DER 格式的数字证书签名请求解码。

参数:

  • der: DerBlob - DER 格式的二进制数据。

返回值:

异常:

  • X509Exception - 数据为空时,或数据不是有效的数字证书签名请求 DER 格式时抛出异常。

static func decodeFromPem(String)

public static func decodeFromPem(pem: String): Array<X509CertificateRequest>

功能:将数字证书签名请求从 PEM 格式解码。

参数:

  • pem: String - PEM 格式的数字证书签名请求字符流。

返回值:

异常:

  • X509Exception - 字符流不符合 PEM 格式时,或文件头不符合数字证书签名请求头标准时抛出异常。

func encodeToDer()

public func encodeToDer(): DerBlob

功能:将数字证书签名请求编码成 Der 格式。

返回值:

  • DerBlob - 编码后的 Der 格式的数字证书签名请求。

func encodeToPem()

public func encodeToPem(): PemEntry

功能:将数字证书签名请求编码成 PEM 格式。

返回值:

  • PemEntry - 编码后的 PEM 格式的数字证书签名请求。

func hashCode()

public override func hashCode(): Int64

功能:返回证书签名请求哈希值。

返回值:

  • Int64 - 对证书签名请求对象进行哈希计算后得到的结果。

func toString()

public override func toString(): String

功能:生成证书签名请求名称字符串,包含证书签名请求的使用者信息。

返回值:

  • String - 证书签名请求名称字符串。

class X509Name

public class X509Name <: ToString {
    public init(
        countryName!: ?String = None,
        provinceName!: ?String = None,
        localityName!: ?String = None,
        organizationName!: ?String = None,
        organizationalUnitName!: ?String = None,
        commonName!: ?String = None,
        email!: ?String = None
    )
}

功能:证书实体可辨识名称(Distinguished Name)是数字证书中的一个重要组成部分,作用是确保证书的持有者身份的真实性和可信度,同时也是数字证书验证的重要依据之一。

X509Name 通常包含证书实体的国家或地区名称(Country Name)、州或省名称(State or Province Name)、城市名称(Locality Name)、组织名称(Organization Name)、组织单位名称(Organizational Unit Name)、通用名称(Common Name)。有时也会包含 email 地址。

父类型:

  • ToString

prop commonName

public prop commonName: ?String

功能:返回证书实体的通用名称。

类型:?String

prop countryName

public prop countryName: ?String

功能:返回证书实体的国家或地区名称。

类型:?String

prop email

public prop email: ?String

功能:返回证书实体的 email 地址。

类型:?String

prop localityName

public prop localityName: ?String

功能:返回证书实体的城市名称。

类型:?String

prop organizationName

public prop organizationName: ?String

功能:返回证书实体的组织名称。

类型:?String

prop organizationalUnitName

public prop organizationalUnitName: ?String

功能:返回证书实体的组织单位名称。

类型:?String

prop provinceName

public prop provinceName: ?String

功能:返回证书实体的州或省名称。

类型:?String

init(?String, ?String, ?String, ?String, ?String, ?String, ?String)

    public init(
        countryName!: ?String = None,
        provinceName!: ?String = None,
        localityName!: ?String = None,
        organizationName!: ?String = None,
        organizationalUnitName!: ?String = None,
        commonName!: ?String = None,
        email!: ?String = None
    )

功能:构造 X509Name 对象。

参数:

  • countryName!: ?String - 国家或地区名称,默认值为 None。
  • provinceName!: ?String - 州或省名称,默认值为 None。
  • localityName!: ?String - 城市名称,默认值为 None。
  • organizationName!: ?String - 组织名称,默认值为 None。
  • organizationalUnitName!: ?String - 组织单位名称,默认值为 None。
  • commonName!: ?String - 通用名称,默认值为 None。
  • email!: ?String - email 地址,默认值为 None。

异常:

  • X509Exception - 设置证书实体可辨识名称时失败,比如内存分配异常等内部错误,则抛出异常。

func toString()

public override func toString(): String

功能:生成证书实体名称字符串。

返回值:

  • String - 证书实体名称字符串,包含实体名称中存在的字段信息。

枚举

enum PublicKeyAlgorithm

public enum PublicKeyAlgorithm <: Equatable<PublicKeyAlgorithm> & ToString {
    RSA | DSA | ECDSA | UnknownPublicKeyAlgorithm
}

功能:数字证书中包含的公钥信息,目前支持的种类有:RSA、DSA、ECDSA。

父类型:

DSA

DSA

功能:DSA 公钥算法。

ECDSA

ECDSA

功能:ECDSA 公钥算法。

RSA

RSA

功能:RSA 公钥算法。

UnknownPublicKeyAlgorithm

UnknownPublicKeyAlgorithm

功能:未知公钥算法。

func toString()

public override func toString(): String

功能:生成证书携带的公钥算法名称字符串。

返回值:

  • String - 证书携带的公钥算法名称字符串。

operator func !=(PublicKeyAlgorithm)

public override operator func !=(other: PublicKeyAlgorithm): Bool

功能:判不等。

参数:

返回值:

  • Bool - 若公钥算法不同,返回 true;否则,返回 false。

operator func ==(PublicKeyAlgorithm)

public override operator func ==(other: PublicKeyAlgorithm): Bool

功能:判等。

参数:

返回值:

  • Bool - 若公钥算法相同,返回 true;否则,返回 false。

enum SignatureAlgorithm

public enum SignatureAlgorithm <: Equatable<SignatureAlgorithm> & ToString {
    | MD2WithRSA | MD5WithRSA | SHA1WithRSA | SHA256WithRSA | SHA384WithRSA
    | SHA512WithRSA | DSAWithSHA1 | DSAWithSHA256 | ECDSAWithSHA1 | ECDSAWithSHA256
    | ECDSAWithSHA384 | ECDSAWithSHA512 | UnknownSignatureAlgorithm
}

功能:证书签名算法(Signature Algorithm)是用于数字证书签名的算法,它是一种将数字证书中的公钥和其他信息进行加密的算法,以确保数字证书的完整性和真实性。

目前支持签名算法的种类包括:MD2WithRSA 、MD5WithRSA 、SHA1WithRSA 、SHA256WithRSA 、SHA384WithRSA、SHA512WithRSA、DSAWithSHA1、DSAWithSHA256、ECDSAWithSHA1、ECDSAWithSHA256、ECDSAWithSHA384 和 ECDSAWithSHA512。

父类型:

DSAWithSHA1

DSAWithSHA1

功能:DSAwithSHA1 签名算法。

DSAWithSHA256

DSAWithSHA256

功能:DSAwithSHA256 签名算法。

ECDSAWithSHA1

ECDSAWithSHA1

功能:ECDSAwithSHA1 签名算法。

ECDSAWithSHA256

ECDSAWithSHA256

功能:ECDSAwithSHA256 签名算法。

ECDSAWithSHA384

ECDSAWithSHA384

功能:ECDSAwithSHA384 签名算法。

ECDSAWithSHA512

ECDSAWithSHA512

功能:ECDSAwithSHA512 签名算法。

MD2WithRSA

MD2WithRSA

功能:MD2withRSA 签名算法。

MD5WithRSA

MD5WithRSA

功能:MD5withRSA 签名算法。

SHA1WithRSA

SHA1WithRSA

功能:SHA1withRSA签名算法。

SHA256WithRSA

SHA256WithRSA

功能:SHA256withRSA 签名算法。

SHA384WithRSA

SHA384WithRSA

功能:SHA384withRSA 签名算法。

SHA512WithRSA

SHA512WithRSA

功能:SHA512withRSA 签名算法。

UnknownSignatureAlgorithm

UnknownSignatureAlgorithm

功能:未知签名算法。

func toString()

public override func toString(): String

功能:生成证书签名算法名称字符串。

返回值:

  • String - 证书签名算法名称字符串。

operator func != (SignatureAlgorithm)

public override operator func !=(other: SignatureAlgorithm): Bool

功能:判不等。

参数:

返回值:

  • Bool - 若签名算法不同,返回 true;否则,返回 false。

operator func == (SignatureAlgorithm)

public override operator func ==(other: SignatureAlgorithm): Bool

功能:判等。

参数:

返回值:

  • Bool - 若签名算法相同,返回 true;否则,返回 false。

结构体

struct DerBlob

public struct DerBlob <: Equatable<DerBlob> & Hashable {
    public init(content: Array<Byte>)
}

功能:Crypto 支持配置二进制证书流,用户读取二进制证书数据并创建 DerBlob 对象后可将其解析成 X509Certificate / X509CertificateRequest / PublicKey / PrivateKey 对象。

父类型:

prop body

public prop body: Array<Byte>

功能:DerBlob 对象中的字符序列。

类型:Array<Byte>

prop size

public prop size: Int64

功能:DerBlob 对象中字符序列的大小。

类型:Int64

init(Array<Byte>)

public init(content: Array<Byte>)

功能:构造 DerBlob 对象。

参数:

  • content: Array<Byte> - 二进制字符序列。

func hashCode()

public override func hashCode(): Int64

功能:返回 DerBlob 对象哈希值。

返回值:

  • Int64 - 对 DerBlob 对象进行哈希计算后得到的结果。

operator func !=(DerBlob)

public override operator func !=(other: DerBlob): Bool

功能:判不等。

参数:

返回值:

  • Bool - 若对象不同,返回 true;否则,返回 false。

operator func ==(DerBlob)

public override operator func ==(other: DerBlob): Bool

功能:判等。

参数:

返回值:

  • Bool - 若对象相同,返回 true;否则,返回 false。

struct ExtKeyUsage

public struct ExtKeyUsage <: ToString {
    public static let AnyKey = 0u16
    public static let ServerAuth = 1u16
    public static let ClientAuth = 2u16
    public static let EmailProtection = 3u16
    public static let CodeSigning = 4u16
    public static let OCSPSigning = 5u16
    public static let TimeStamping = 6u16
    public init(keys: Array<UInt16>)
}

功能:数字证书扩展字段中通常会包含携带扩展密钥用法说明,目前支持的用途有:ServerAuth、ClientAuth、EmailProtection、CodeSigning、OCSPSigning、TimeStamping。

父类型:

  • ToString

static let AnyKey

public static let AnyKey = 0u16

功能:表示应用于任意用途。

类型:UInt16

static let ClientAuth

public static let ClientAuth = 2u16

功能:表示用于 SSL 的客户端验证。

类型:UInt16

static let CodeSigning

public static let CodeSigning = 4u16

功能:表示用于代码签名。

类型:UInt16

static let EmailProtection

public static let EmailProtection = 3u16

功能:表示用于电子邮件的加解密、签名等。

类型:UInt16

static let OCSPSigning

public static let OCSPSigning = 5u16

功能:用于对 OCSP 响应包进行签名。

类型:UInt16

static let ServerAuth

public static let ServerAuth = 1u16

功能:表示用于 SSL 的服务端验证。

类型:UInt16

static let TimeStamping

public static let TimeStamping = 6u16

功能:用于将对象摘要值与时间绑定。

类型:UInt16

init(Array<UInt16>)

public init(keys: Array<UInt16>)

功能:构造指定用途的扩展密钥用法,需要注意同一个密钥可以有多种用途。

参数:

  • keys: Array<UInt16> - 密钥。

func toString()

public override func toString(): String

功能:生成扩展密钥用途字符串。

返回值:

  • String - 证书扩展密钥用途字符串。

struct KeyUsage

public struct KeyUsage <: ToString {
    public static let DigitalSignature = 0x0080u16
    public static let NonRepudiation = 0x0040u16
    public static let KeyEncipherment = 0x0020u16
    public static let DataEncipherment = 0x0010u16
    public static let KeyAgreement = 0x0008u16
    public static let CertSign = 0x0004u16
    public static let CRLSign = 0x0002u16
    public static let EncipherOnly = 0x0001u16
    public static let DecipherOnly = 0x0100u16
    public init(keys: UInt16)
}

功能:数字证书扩展字段中通常会包含携带公钥的用法说明,目前支持的用途有:DigitalSignature、NonRepudiation、KeyEncipherment、DataEncipherment、KeyAgreement、CertSign、CRLSign、EncipherOnly、DecipherOnly。

父类型:

  • ToString

static let CRLSign

public static let CRLSign = 0x0002u16

功能:表示私钥可用于对 CRL 签名,而公钥可用于验证 CRL 签名。

类型:UInt16

static let CertSign

public static let CertSign = 0x0004u16

功能:表示私钥用于证书签名,而公钥用于验证证书签名,专用于 CA 证书。

类型:UInt16

static let DataEncipherment

public static let DataEncipherment = 0x0010u16

功能:表示公钥用于直接加密数据。

类型:UInt16

static let DecipherOnly

public static let DecipherOnly = 0x0100u16

功能:表示证书中的公钥在密钥协商过程中,仅仅用于解密计算,配合 key Agreement 使用才有意义。

类型:UInt16

static let DigitalSignature

public static let DigitalSignature = 0x0080u16

功能:表示私钥可以用于除了签发证书、签发 CRL 和非否认性服务的各种数字签名操作,而公钥用来验证这些签名。

类型:UInt16

static let EncipherOnly

public static let EncipherOnly = 0x0001u16

功能:表示证书中的公钥在密钥协商过程中,仅仅用于加密计算,配合 key Agreement 使用才有意义。

类型:UInt16

static let KeyAgreement

public static let KeyAgreement = 0x0008u16

功能:表示密钥用于密钥协商。

类型:UInt16

static let KeyEncipherment

public static let KeyEncipherment = 0x0020u16

功能:表示密钥用来加密传输其他的密钥。

类型:UInt16

static let NonRepudiation

public static let NonRepudiation = 0x0040u16

功能:表示私钥可以用于进行非否认性服务中的签名,而公钥用来验证签名。

类型:UInt16

init(UInt16)

public init(keys: UInt16)

功能:构造指定用途的扩展密钥用法,需要注意同一个密钥可以有多种用途。

参数:

  • keys: UInt16 - 密钥的用法,建议使用本结构中所提供的密钥用法变量通过按位或的方式传入参数。

func toString()

public override func toString(): String

功能:生成密钥用途字符串。

返回值:

  • String - 证书密钥用途字符串。

struct Pem

public struct Pem <: Collection<PemEntry> & ToString {
    public Pem(private let items: Array<PemEntry>)
}

功能:结构体 Pem 为条目序列,可以包含多个 PemEntry

父类型:

prop size

public override prop size: Int64

功能:条目序列的数量。

类型:Int64

Pem(Array<PemEntry>)

public Pem(private let items: Array<PemEntry>)

功能:构造 Pem 对象。

参数:

static func decode(String)

public static func decode(text: String): Pem

功能:将 PEM 文本解码为条目序列。

参数:

  • text: String - PEM 字符串。

返回值:

  • Pem - PEM 条目序列。

异常:

  • X509Exception - 数据为空时,或解码失败抛出异常。

func encode()

public func encode(): String

功能:返回PEM格式的字符串。行结束符将根据当前操作系统生成。

返回值:

  • String - PEM 格式的字符串。

func isEmpty()

public override func isEmpty(): Bool

功能:判断 PEM 文本解码为条目序列是否为空。

返回值:

  • Bool - PEM 文本解码为条目序列为空返回 true;否则,返回 false。

func iterator()

public override func iterator(): Iterator<PemEntry>

功能:生成 PEM 文本解码为条目序列的迭代器。

返回值:

  • Iterator<PemEntry> - PEM 文本解码为条目序列的迭代器。

func toString()

public override func toString(): String

功能:返回一个字符串,字符串内容是包含每个条目序列的标签。

返回值:

  • String - 包含每个条目序列的标签的字符串。

struct PemEntry

public struct PemEntry <: ToString {
    public static let LABEL_CERTIFICATE = "CERTIFICATE"
    public static let LABEL_X509_CRL = "X509 CRL"
    public static let LABEL_CERTIFICATE_REQUEST = "CERTIFICATE REQUEST"
    public static let LABEL_PRIVATE_KEY = "PRIVATE KEY"
    public static let LABEL_EC_PRIVATE_KEY = "EC PRIVATE KEY"
    public static let LABEL_ENCRYPTED_PRIVATE_KEY = "ENCRYPTED PRIVATE KEY"
    public static let LABEL_RSA_PRIVATE_KEY = "RSA PRIVATE KEY"
    public static let LABEL_SM2_PRIVATE_KEY = "SM2 PRIVATE KEY"
    public static let LABEL_PUBLIC_KEY = "PUBLIC KEY"
    public static let LABEL_EC_PARAMETERS = "EC PARAMETERS"
    public static let LABEL_DH_PARAMETERS = "DH PARAMETERS"
    public PemEntry(
        public let label: String,
        public let headers: Array<(String, String)>,
        public let body: ?DerBlob
    )
    public init(label: String, body: DerBlob)
}

功能:PEM 文本格式经常用于存储证书和密钥,PEM 编码结构包含以下几个部分:

第一行是 “-----BEGIN”,标签和 “-----” 组成的utf8编码的字符串; 中间是正文,是实际二进制内容经过 base64 编码得到的可打印字符串,详细的PEM编码规范可参考 RFC 7468; 最后一行是 “-----END”,标签和 “-----” 组成的 utf8 编码的字符串,详见 RFC 1421。 在旧版的 PEM 编码标准中在第一行和正文之间还包含条目头。

为了支持不同的用户场景,我们提供了 PemEntryPem 类型,PemEntry 用于存储单个PEM 基础结构。

父类型:

  • ToString

static let LABEL_CERTIFICATE

public static let LABEL_CERTIFICATE = "CERTIFICATE"

功能:记录条目类型为证书。

类型:String

static let LABEL_CERTIFICATE_REQUEST

public static let LABEL_CERTIFICATE_REQUEST = "CERTIFICATE REQUEST"

功能:记录条目类型为证书签名请求。

类型:String

static let LABEL_DH_PARAMETERS

public static let LABEL_DH_PARAMETERS = "DH PARAMETERS"

功能:记录条目类型为 DH 密钥参数。

类型:String

static let LABEL_EC_PARAMETERS

public static let LABEL_EC_PARAMETERS = "EC PARAMETERS"

功能:记录条目类型为椭圆曲线参数。

类型:String

static let LABEL_EC_PRIVATE_KEY

public static let LABEL_EC_PRIVATE_KEY = "EC PRIVATE KEY"

功能:记录条目类型为椭圆曲线私钥。

类型:String

static let LABEL_ENCRYPTED_PRIVATE_KEY

public static let LABEL_ENCRYPTED_PRIVATE_KEY = "ENCRYPTED PRIVATE KEY"

功能:记录条目类型为 PKCS #8 标准加密的私钥。

类型:String

static let LABEL_PRIVATE_KEY

public static let LABEL_PRIVATE_KEY = "PRIVATE KEY"

功能:记录条目类型为 PKCS #8 标准未加密的私钥。

类型:String

static let LABEL_PUBLIC_KEY

public static let LABEL_PUBLIC_KEY = "PUBLIC KEY"

功能:记录条目类型为公钥。

类型:String

static let LABEL_RSA_PRIVATE_KEY

public static let LABEL_RSA_PRIVATE_KEY = "RSA PRIVATE KEY"

功能:记录条目类型为 RSA 私钥。

类型:String

static let LABEL_SM2_PRIVATE_KEY

public static let LABEL_SM2_PRIVATE_KEY = "SM2 PRIVATE KEY"

功能:记录条目类型为 SM2 私钥。

类型:String

static let LABEL_X509_CRL

public static let LABEL_X509_CRL = "X509 CRL"

功能:记录条目类型为证书吊销列表。

类型:String

PemEntry(String, Array<(String, String)>, ?DerBlob)

public PemEntry(
    public let label: String,
    public let headers: Array<(String, String)>,
    public let body: ?DerBlob
)

功能:构造 PemEntry 对象。

参数:

  • label: String - 标签。

  • headers: Array<(String, String)> - 条目头。

  • body: ?DerBlob - 二进制内容。

let body

public let body: ?DerBlob

功能:PemEntry 实例的二进制内容。

类型:?DerBlob

let headers

public let headers: Array<(String, String)>

功能:PemEntry 实例的条目头。

类型:Array<(String, String)>

let label

public let label: String

功能:PemEntry 实例的标签。

类型:String

init(String, DerBlob)

public init(label: String, body: DerBlob)

功能:构造 PemEntry 对象。

参数:

  • label: String - 标签
  • body: DerBlob - 二进制内容

func encode()

public func encode(): String

功能:返回PEM格式的字符串。行结束符将根据当前操作系统生成。

返回值:

  • String - PEM 格式的字符串。

func header(String)

public func header(name: String): Iterator<String>

功能:通过条目头名称,找到对应条目内容。

参数:

  • name: String - 条目头名称。

返回值:

  • Iterator<String> - 条目头名称对应内容的迭代器。

func toString()

public override func toString(): String

功能:返回 PEM 对象的标签和二进制内容的长度。

返回值:

  • String - PEM 对象的标签和二进制内容的长度。

struct SerialNumber

public struct SerialNumber <: Equatable<SerialNumber> & Hashable & ToString {
    public init(length!: UInt8 = 16)
}

功能: 结构体 SerialNumber 为数字证书的序列号,是数字证书中的一个唯一标识符,用于标识数字证书的唯一性。根据规范,证书序列号的长度不应超过 20 字节。详见rfc5280

父类型:

init(UInt8)

public init(length!: UInt8 = 16)

功能:生成指定长度的随机序列号。

参数:

  • length!: UInt8 - 序列号长度,单位为字节,类型为 UInt8,默认值为 16。

异常:

  • X509Exception - length 等于 0 或大于 20 时,抛出异常。

func hashCode()

public override func hashCode(): Int64

功能:返回证书序列号哈希值。

返回值:

  • Int64 - 对证书序列号对象进行哈希计算后得到的结果。

func toString()

public override func toString(): String

功能:生成证书序列号字符串,格式为 16 进制。

返回值:

  • String - 证书序列号字符串。

operator func !=(SerialNumber)

public override operator func !=(other: SerialNumber): Bool

功能:判不等。

参数:

  • other: SerialNumber - 被比较的证书序列号对象。

返回值:

  • Bool - 若序列号不同,返回 true;否则,返回 false。

operator func ==(SerialNumber)

public override operator func ==(other: SerialNumber): Bool

功能:判等。

参数:

  • other: SerialNumber - 被比较的证书序列号对象。

返回值:

  • Bool - 若序列号相同,返回 true;否则,返回 false。

struct Signature

public struct Signature <: Equatable<Signature> & Hashable {
}

功能:数字证书的签名,用来验证身份的正确性。

父类型:

prop signatureValue

public prop signatureValue: DerBlob

功能:返回证书签名的二进制。

类型:DerBlob

func hashCode()

public override func hashCode(): Int64

功能:返回证书签名哈希值。

返回值:

  • Int64 - 对证书签名对象进行哈希计算后得到的结果。

operator func !=(Signature)

public override operator func !=(other: Signature): Bool

功能:判不等。

参数:

  • other: Signature - 被比较的证书签名。

返回值:

  • Bool - 若证书签名不同,返回 true;否则,返回 false。

operator func ==(Signature)

public override operator func ==(other: Signature): Bool

功能:判等。

参数:

  • other: Signature - 被比较的证书签名。

返回值:

  • Bool - 若证书签名相同,返回 true;否则,返回 false。

struct VerifyOption

public struct VerifyOption {
    public var time: DateTime = DateTime.now()
    public var dnsName: String = ""
    public var roots: Array<X509Certificate> = X509Certificate.systemRootCerts()
    public var intermediates: Array<X509Certificate> = Array<X509Certificate>()
}

功能:用于为 x509 证书验证函数 verify 提供配置选项。

var dnsName

public var dnsName: String = ""

功能:校验域名,默认为空,只有设置域名时才会进行此处校验。

类型:String

var intermediates

public var intermediates: Array<X509Certificate> = Array<X509Certificate>()

功能:中间证书链,默认为空。

类型:Array<X509Certificate>

var roots

public var roots: Array<X509Certificate> = X509Certificate.systemRootCerts()

功能:根证书链,默认为系统根证书链。

类型:Array<X509Certificate>

var time

public var time: DateTime = DateTime.now()

功能:校验时间,默认为创建选项的时间。

类型:DateTime

struct X509CertificateInfo

public struct X509CertificateInfo {
    public var serialNumber: SerialNumber
    public var notBefore: DateTime
    public var notAfter: DateTime
    public var subject: ?X509Name
    public var dnsNames: Array<String>
    public var emailAddresses: Array<String>
    public var IPAddresses: Array<IP>
    public var keyUsage: ?KeyUsage
    public var extKeyUsage: ?ExtKeyUsage

    public init(
        serialNumber!: ?SerialNumber = None,
        notBefore!: ?DateTime = None,
        notAfter!: ?DateTime = None,
        subject!: ?X509Name = None,
        dnsNames!: Array<String> = Array<String>(),
        emailAddresses!: Array<String> = Array<String>(),
        IPAddresses!: Array<IP> = Array<IP>(),
        keyUsage!: ?KeyUsage = None,
        extKeyUsage!: ?ExtKeyUsage = None
    )
}

功能:X509CertificateInfo 结构包含了证书信息,包括证书序列号、有效期、实体可辨识名称、域名、email 地址、IP 地址、密钥用法和扩展密钥用法。

var IPAddresses

public var IPAddresses: Array<IP>

功能:记录证书的 IP 地址。

类型:Array<IP>

var dnsNames

public var dnsNames: Array<String>

功能:记录证书的 DNS 域名。

类型:Array<String>

var emailAddresses

public var emailAddresses: Array<String>

功能:记录证书的 email 地址。

类型:Array<String>

var extKeyUsage

public var extKeyUsage: ?ExtKeyUsage

功能:记录证书的扩展密钥用法。

类型:?ExtKeyUsage

var keyUsage

public var keyUsage: ?KeyUsage

功能:记录证书的密钥用法。

类型:?KeyUsage

var notAfter

public var notAfter: DateTime

功能:记录证书有效期的结束日期。

类型:DateTime

var notBefore

public var notBefore: DateTime

功能:记录证书有效期的起始日期。

类型:DateTime

var serialNumber

public var serialNumber: SerialNumber

功能:记录证书的序列号。

类型:SerialNumber

var subject

public var subject: ?X509Name

功能:记录证书实体可辨识名称。

类型:?X509Name

init(?SerialNumber, ?DateTime, ?DateTime, ?X509Name, Array<String>, Array<String>, Array<IP>, ?KeyUsage, ?ExtKeyUsage)

public init(
    serialNumber!: ?SerialNumber = None,
    notBefore!: ?DateTime = None,
    notAfter!: ?DateTime = None,
    subject!: ?X509Name = None,
    dnsNames!: Array<String> = Array<String>(),
    emailAddresses!: Array<String> = Array<String>(),
    IPAddresses!: Array<IP> = Array<IP>(),
    keyUsage!: ?KeyUsage = None,
    extKeyUsage!: ?ExtKeyUsage = None
)

功能:构造 X509CertificateInfo 对象。

参数:

  • serialNumber!: ?SerialNumber - 数字证书序列号,默认值为 None,使用默认值时默认的序列号长度为 128 比特。
  • notBefore!: ?DateTime - 数字证书有效期开始时间,默认值为 None,使用默认值时默认的时间为 X509CertificateInfo 创建的时间。
  • notAfter!: ?DateTime - 数字证书有效期截止时间,默认值为 None,使用默认值时默认的时间为 notBefore 往后 1 年的时间。
  • subject!: ?X509Name - 数字证书使用者信息,默认值为 None。
  • dnsNames!: Array<String> - 域名列表,需要用户保证输入域名的有效性,默认值为空的字符串数组。
  • emailAddresses!: Array<String> - email 地址列表,需要用户保证输入 email 的有效性,默认值为空的字符串数组。
  • IPAddresses!: Array<IP> - IP 地址列表,默认值为空的 IP 数组。
  • keyUsage!: ?KeyUsage - 密钥用法,默认值为 None。
  • extKeyUsage!: ?ExtKeyUsage - 扩展密钥用法,默认值为 None。

异常:

  • X509Exception - 输入的 IP 地址列表中包含无效的 IP 地址,则抛出异常。

struct X509CertificateRequestInfo

public struct X509CertificateRequestInfo {
    public var subject: ?X509Name
    public var dnsNames: Array<String>
    public var emailAddresses: Array<String>
    public var IPAddresses: Array<IP>
 
    public init(
        subject!: ?X509Name = None,
        dnsNames!: Array<String> = Array<String>(),
        emailAddresses!: Array<String> = Array<String>(),
        IPAddresses!: Array<IP> = Array<IP>()
    )
}

功能: X509CertificateRequestInfo 结构包含了证书请求信息,包括证书实体可辨识名称、域名、email 地址和 IP 地址。

var IPAddresses

public var IPAddresses: Array<IP>

功能:记录证书签名请求的 IP 地址。

类型:Array<IP>

var dnsNames

public var dnsNames: Array<String>

功能:记录证书签名请求的 DNS 域名。

类型:Array<String>

var emailAddresses

public var emailAddresses: Array<String>

功能:记录证书签名请求的 email 地址。

类型:Array<String>

var subject

public var subject: ?X509Name

功能:记录证书签名请求的实体可辨识名称。

init(?X509Name, Array<String>, Array<String>, Array<IP>)

public init(
    subject!: ?X509Name = None,
    dnsNames!: Array<String> = Array<String>(),
    emailAddresses!: Array<String> = Array<String>(),
    IPAddresses!: Array<IP> = Array<IP>()
)

功能:构造 X509CertificateRequestInfo 对象。

参数:

  • subject!: ?X509Name - 数字证书的使用者信息,默认值为 None。
  • dnsNames!: Array<String> - 域名列表,需要用户保证输入域名的有效性,默认值为空的字符串数组。
  • emailAddresses!: Array<String> - email 地址列表,需要用户保证输入 email 的有效性,默认值为空的字符串数组。
  • IPAddresses!: Array<IP> - IP 地址列表,默认值为空的 IP 数组。

异常:

  • X509Exception - 输入的 IP 地址列表中包含无效的 IP 地址,则抛出异常。

异常类

class X509Exception

public class X509Exception <: Exception {
    public init()
    public init(message: String)
}

功能:此异常为 X509 包抛出的异常类型。

父类型:

  • Exception

init()

public init()

功能:构造 X509Exception 对象。

init(String)

public init(message: String)

功能:构造 X509Exception 对象。

参数:

  • message: String - 异常的信息。

x509 使用

读取、解析证书

说明:

需要自行准备证书文件。

示例:

import std.fs.File
import stdx.crypto.x509.*

let readPath = "./files/root_rsa.cer"

main() {
    /* 读取本地证书*/
    let pem = String.fromUtf8(File.readFrom(readPath))
    let certificates = X509Certificate.decodeFromPem(pem)

    /* 解析证书中的必选字段 */
    let cert = certificates[0]
    println(cert)
    println("Serial Number: ${cert.serialNumber}")
    println("Issuer: ${cert.issuer}")
    println("NotBefore: ${cert.notBefore}")
    println("NotAfter: ${cert.notAfter}")
    println(cert.signatureAlgorithm)
    let signature = cert.signature
    println(signature.hashCode())
    println(cert.publicKeyAlgorithm)
    let pubKey = cert.publicKey
    println(pubKey.encodeToPem().encode())

    /* 解析证书中的扩展字段 */
    println("DNSNames: ${cert.dnsNames}")
    println("EmailAddresses: ${cert.emailAddresses}")
    println("IPAddresses: ${cert.IPAddresses}")
    println("KeyUsage: ${cert.keyUsage}")
    println("ExtKeyUsage: ${cert.extKeyUsage}")

    /* 解析证书使用者的可辨识名称 */
    println("Subject: ${cert.subject}")

    return 0
}

读取、验证证书

说明:

需要自行准备证书文件。

示例:

import std.fs.File
import stdx.crypto.x509.*
import std.time.DateTime

let prefixPath = "./files/"
let certFile = "servers.crt"
let rootFile = "roots.crt"
let middleFile = "middles.crt"

func getX509Cert(path: String) {
    let pem = String.fromUtf8(File.readFrom(path))
    X509Certificate.decodeFromPem(pem)
}

func testVerifyByTime(cert: X509Certificate, roots: Array<X509Certificate>, middles: Array<X509Certificate>) {
    var opt = VerifyOption()
    opt.roots = roots
    opt.intermediates = middles
    cert.verify(opt)
    println("Verify result: ${cert.verify(opt)}")
    opt.time = DateTime.of(year: 2023, month: 7, dayOfMonth: 1)
    println("Verify result:: ${cert.verify(opt)}")
}

func testVerifyByDNS(cert: X509Certificate) {
    var opt = VerifyOption()
    opt.dnsName = "www.example.com"
    println("cert DNS names: ${cert.dnsNames}")
    let res = cert.verify(opt)
    println("Verify result: ${res}")
}

/**
 * The relation of certs.
 *    root[0]         root[1]
 *    /      \            |
 *  mid[0]  mid[1]    mid[2]
 *   |                  |
 *  server[0]         server[1]
 */
func testVerify(cert: X509Certificate, roots: Array<X509Certificate>, middles: Array<X509Certificate>) {
    var opt = VerifyOption()
    opt.roots = roots
    opt.intermediates = middles
    let res = cert.verify(opt)
    println("Verify result: ${res}")
}

main() {
    /* 两个服务端证书 */
    let certs = getX509Cert(prefixPath + certFile)
    /* 两个根证书 */
    let roots = getX509Cert(prefixPath + rootFile)
    /* 三个中间证书 */
    let middles = getX509Cert(prefixPath + middleFile)
    /* 验证有效期 */
    testVerifyByTime(certs[0], [roots[0]], [middles[0]])
    /* 验证 DNS 域名 */
    testVerifyByDNS(certs[0])

    /* 根据根证书和中间证书验证其有效性 */
    /* cert0 <- root0: false */
    testVerify(certs[0], [roots[0]], [])
    /* cert0 <- middle0 <- root0: true */
    testVerify(certs[0], [roots[0]], [middles[0]])
    /* cert0 <- (middle0, middle1, middle2) <- (root0, root1) : true */
    testVerify(certs[0], roots, middles)
    /* cert1 <- middle0 <- root0: false */
    testVerify(certs[1], [roots[0]], [middles[0]])
    /* cert1 <- middle2 <- root1: true */
    testVerify(certs[1], [roots[1]], [middles[2]])
    /* cert1 <- (middle0, middle1, middle2) <- (root0, root1) : true */
    testVerify(certs[1], roots, middles)
    return 0
}

创建、解析证书

说明:

需要自行准备根证书文件。

示例:

import std.fs.*
import stdx.crypto.x509.*
import std.time.*
import std.io.*

main() {
    let x509Name = X509Name(
        countryName: "CN",
        provinceName: "beijing",
        localityName: "haidian",
        organizationName: "organization",
        organizationalUnitName: "organization unit",
        commonName: "x509",
        email: "test@email.com"
    )
    let serialNumber = SerialNumber(length: 20)
    let startTime: DateTime = DateTime.now()
    let endTime: DateTime = startTime.addYears(1)
    let ip1: IP = [8, 8, 8, 8]
    let ip2: IP = [0, 1, 0, 1, 0, 1, 0, 1, 0, 8, 0, 8, 0, 8, 0, 8]
    let parentCertPem = String.fromUtf8(readToEnd(File("./certificate.pem", Read)))
    let parentCert = X509Certificate.decodeFromPem(parentCertPem)[0]
    let parentKeyPem = String.fromUtf8(readToEnd(File("./rsa_private_key.pem", Read)))
    let parentPrivateKey = PrivateKey.decodeFromPem(parentKeyPem)
    let usrKeyPem = String.fromUtf8(readToEnd(File("./ecdsa_public_key.pem", Read)))
    let usrPublicKey = PublicKey.decodeFromPem(usrKeyPem)

    let certInfo = X509CertificateInfo(serialNumber: serialNumber, notBefore: startTime, notAfter: endTime,
        subject: x509Name, dnsNames: ["b.com"], IPAddresses: [ip1, ip2]);
    let cert = X509Certificate(certInfo, parent: parentCert, publicKey: usrPublicKey, privateKey: parentPrivateKey)

    println(cert)
    println("Serial Number: ${cert.serialNumber}")
    println("Issuer: ${cert.issuer}")
    println("Subject: ${cert.subject}")
    println("NotBefore: ${cert.notBefore}")
    println("NotAfter: ${cert.notAfter}")
    println(cert.signatureAlgorithm)
    println("DNSNames: ${cert.dnsNames}")
    println("IPAddresses: ${cert.IPAddresses}")

    return 0
}

创建、解析证书签名请求

说明:

需要自行准备私钥等文件。

示例:

import std.fs.*
import std.io.*
import stdx.crypto.x509.*

main() {
    let x509Name = X509Name(
        countryName: "CN",
        provinceName: "beijing",
        localityName: "haidian",
        organizationName: "organization",
        organizationalUnitName: "organization unit",
        commonName: "x509",
        email: "test@email.com"
    )
    let ip1: IP = [8, 8, 8, 8]
    let ip2: IP = [0, 1, 0, 1, 0, 1, 0, 1, 0, 8, 0, 8, 0, 8, 0, 8]
    let rsaPem = String.fromUtf8(readToEnd(File("./rsa_private_key.pem", Read)))
    let rsa = PrivateKey.decodeFromPem(rsaPem)

    let csrInfo = X509CertificateRequestInfo(subject: x509Name, dnsNames: ["b.com"], IPAddresses: [ip1, ip2]);
    let csr = X509CertificateRequest(rsa, certificateRequestInfo: csrInfo, signatureAlgorithm: SHA256WithRSA)

    println("Subject: ${csr.subject.toString()}")
    println("IPAddresses: ${csr.IPAddresses}")
    println("dnsNames: ${csr.dnsNames}")

    return 0
}

stdx.encoding.base64

功能介绍

base 包提供字符串的 Base64 编码及解码。

Base64 编码能够将二进制数据转换成仅由 64 个可打印的字符(A-Z、a-z、0-9、+、/)组成的文本格式,这使得二进制数据能够在文本环境中安全传输和存储。

API 列表

函数

函数名功能
fromBase64String(String)用于 Base64 编码的字符串的解码。
toBase64String(Array<Byte>)用于将字符数组转换成 Base64 编码的字符串。

函数

func fromBase64String(String)

public func fromBase64String(data: String): Option<Array<Byte>>

功能:此函数用于 Base64 编码的字符串的解码。

参数:

  • data: String - 要解码的 Base64 编码的字符串。

返回值:

  • Option<Array<Byte>> - 输入空字符串会返回 Option<Array<Byte>>.Some(Array<Byte>()),解码失败会返回 Option<Array<Byte>>.None。

func toBase64String(Array<Byte>)

public func toBase64String(data: Array<Byte>): String

功能:此函数用于将 Byte 数组转换成 Base64 编码的字符串。

参数:

  • data: Array<Byte> - 要编码的 Byte 数组。

返回值:

  • String - 返回编码后的字符串。

Byte 数组和 Base64 互转

示例:

import stdx.encoding.base64.*

main(): Int64 {
    var arr: Array<Byte> = [77, 97, 110]
    var str = toBase64String(arr)
    print("${str},")
    var opArr: Option<Array<Byte>> = fromBase64String(str)
    var arr2: Array<Byte> = match (opArr) {
        case Some(s) => s
        case None => Array<Byte>()
    }
    for (i in 0..arr2.size) {
        print("${arr2[i]},")
    }
    return 0
}

运行结果:

TWFu,77,97,110,

stdx.encoding.hex

功能介绍

hex 包提供字符串的 Hex 编码及解码。

Hex 编码(也称为十六进制编码)是一种将数据转换为十六进制表示形式的编码方法。Hex 编码使用 16 个字符来表示数据,这 16 个字符分别是 0-9 的数字和 A-F 的字母(不区分大小写,即 a-f 和 A-F 是等价的)。

API 列表

函数

函数名功能
fromHexString(String)用于 Hex 编码的字符串的解码。
toHexString(Array<Byte>)用于将字符数组转换成 Hex 编码的字符串。

函数

func fromHexString(String)

public func fromHexString(data: String): Option<Array<Byte>>

功能:此函数用于 Hex 编码的字符串的解码。

参数:

  • data: String - 要解码的 Hex 编码的字符串。

返回值:

  • Option<Array<Byte>> - 输入空字符串会返回 Option<Array<Byte>>.Some(Array<Byte>()),解码失败会返回 Option<Array<Byte>>.None。

func toHexString(Array<Byte>)

public func toHexString(data: Array<Byte>): String

功能:此函数用于将 Byte 数组转换成 Hex 编码的字符串。

参数:

  • data: Array<Byte> - 要编码的 Byte 数组。

返回值:

  • String - 返回编码后的字符串。

Byte 数组和 Hex 互转

示例:

import stdx.encoding.hex.*

main(): Int64 {
    var arr: Array<Byte> = [65, 66, 94, 97]
    var str = toHexString(arr)
    print("${str},")
    var opArr: Option<Array<Byte>> = fromHexString(str)
    var arr2: Array<Byte> = match (opArr) {
        case Some(s) => s
        case None => Array<Byte>()
    }
    for (i in 0..arr2.size) {
        print("${arr2[i]},")
    }
    return 0
}

运行结果:

41425e61,65,66,94,97,

stdx.encoding.json

功能介绍

json 包用于对 JSON 数据的处理,实现 String, JsonValue, DataModel 之间的相互转换。

JsonValue 是对 JSON 数据格式的封装,包括 object, array, string, number, true, false 和 null。

DataModel 详细信息可参考:serialization 包文档

JSON 语法规则可参考:介绍 JSON

JSON 数据转换标准可参考:ECMA-404 The JSON Data Interchange Standard

API 列表

接口

接口名功能
ToJson用于实现 JsonValue 和 DataModel 的相互转换。

类名功能
JsonArray创建空 JsonArray。
JsonBool将指定的 Bool 类型实例封装成 JsonBool 实例。
JsonFloat将指定的 Float64 类型实例封装成 JsonFloat 实例。
JsonInt将指定的 Int64 类型实例封装成 JsonInt 实例。
JsonNull将 JsonNull 转换为字符串。
JsonObject创建空 JsonObject。
JsonString将指定的 String 类型实例封装成 JsonString 实例。
JsonValue此类为 JSON 数据层, 主要用于 JsonValue 和 String 数据之间的互相转换。

枚举

枚举名功能
JsonKind表示 JsonValue 的具体类型。

异常类

异常类名功能
JsonException用于 JsonValue 类型使用时出现异常的场景。

接口

interface ToJson

public interface ToJson {
    static func fromJson(jv: JsonValue): DataModel
    func toJson(): JsonValue
}

功能:用于实现 JsonValueDataModel 的相互转换。

static func fromJson(JsonValue)

static func fromJson(jv: JsonValue): DataModel

功能:将 JsonValue 转化为对象 DataModel

参数:

返回值:

func toJson()

func toJson(): JsonValue

功能:将自身转化为 JsonValue

返回值:

异常:

extend DataModel <: ToJson

extend DataModel <: ToJson

功能:为 DataModel 类型实现 ToJson 接口。

父类型:

static func fromJson(JsonValue)

public static func fromJson(jv: JsonValue): DataModel

功能:将 JsonValue 转化为对象 DataModel

参数:

返回值:

func toJson()

public func toJson(): JsonValue

功能:将自身转化为 JsonValue

返回值:

异常:

class JsonArray

public class JsonArray <: JsonValue {
    public init()
    public init(list: ArrayList<JsonValue>)
    public init(list: Array<JsonValue>)
}

功能:此类为 JsonValue 实现子类,主要用于封装数组类型的 JSON 数据。

父类型:

示例:

使用示例见 JsonArray 使用示例

init()

public init()

功能:创建空 JsonArray

init(ArrayList<JsonValue>)

public init(list: ArrayList<JsonValue>)

功能:将指定的 ArrayList 类型实例封装成 JsonArray 实例。

参数:

init(Array<JsonValue>)

public init(list: Array<JsonValue>)

功能:将指定的 Array 类型实例封装成 JsonArray 实例。

参数:

func add(JsonValue)

public func add(jv: JsonValue): JsonArray

功能:向 JsonArray 中加入 JsonValue 数据。

参数:

返回值:

func get(Int64)

public func get(index: Int64): Option<JsonValue>

功能:获取 JsonArray 中指定索引的 JsonValue,并用 Option<JsonValue> 封装。

参数:

  • index: Int64 - 指定的索引。

返回值:

func getItems()

public func getItems(): ArrayList<JsonValue>

功能:获取 JsonArray 中的 items 数据。

返回值:

func kind()

public func kind(): JsonKind

功能:返回当前 JsonArray 所属的 JsonKind 类型(JsArray)。

返回值:

func size()

public func size(): Int64

功能:获取 JsonArrayJsonValue 的数量。

返回值:

func toJsonString()

public func toJsonString(): String

功能:将 JsonArray 转换为 JSON 格式的 (带有空格换行符) 的字符串。

返回值:

  • String - 转换后的 JSON 格式字符串。

func toJsonString(Int64, Bool, String)

public func toJsonString(depth: Int64, bracketInNewLine!: Bool = false, indent!: String = "  "): String

功能:将 JsonArray 转换为 JSON 格式的字符串。该函数将指定初始的缩进深度、第一个括号后是否换行以及缩进字符串。

参数:

  • depth: Int64 - 指定的缩进深度。
  • bracketInNewLine!: Bool - 第一个括号是否换行,如果为 true,第一个括号将另起一行并且按照指定的深度缩进。
  • indent!: String - 指定的缩进字符串,缩进字符串中只允许空格和制表符的组合,默认为两个空格。

返回值:

  • String - 转换后的 JSON 格式字符串。

异常:

  • IllegalArgumentException - 如果 depth 为负数,或 indent 中存在 ' ' 和 '\t' 以外的字符,则抛出异常。

func toString()

public func toString(): String

功能:将 JsonString 转换为字符串。

返回值:

  • String - 转换后的字符串。

operator func [](Int64)

public operator func [](index: Int64): JsonValue

功能:获取 JsonArray 中指定索引的 JsonValue

参数:

  • index: Int64 - 指定的索引。

返回值:

异常:

class JsonBool

public class JsonBool <: JsonValue {
    public init(bv: Bool)
}

功能:此类为 JsonValue 实现子类,主要用于封装 true 或者 false 的 JSON 数据。

父类型:

init(Bool)

public init(bv: Bool)

功能:将指定的 Bool 类型实例封装成 JsonBool 实例。

func getValue()

public func getValue(): Bool

功能:获取 JsonBool 中 value 的实际值。

返回值:

  • Bool - value 的实际值。

func kind()

public func kind(): JsonKind

功能:返回当前 JsonBool 所属的 JsonKind 类型(JsBool)。

返回值:

func toJsonString()

public func toJsonString(): String

功能:将 JsonBool 转换为 JSON 格式的 (带有空格换行符) 字符串。

返回值:

  • String - 转换后的 JSON 格式字符串。

func toString()

public func toString(): String

功能:将 JsonBool 转换为字符串。

返回值:

  • String - 转换后的字符串。

class JsonFloat

public class JsonFloat <: JsonValue {
    public init(fv: Float64)
    public init(v: Int64)
}

功能:此类为 JsonValue 实现子类,主要用于封装浮点类型的 JSON 数据。

父类型:

init(Float64)

public init(fv: Float64)

功能:将指定的 Float64 类型实例封装成 JsonFloat 实例。

参数:

  • fv: Float64 - Float64 类型。

init(Int64)

public init(v: Int64)

功能:将指定的 Int64 类型实例封装成 JsonFloat 实例。

参数:

  • v: Int64 - Int64 类型。

func getValue()

public func getValue(): Float64

功能:获取 JsonFloat 中 value 的实际值。

返回值:

  • Float64 - value 的实际值。

func kind()

public func kind(): JsonKind

功能:返回当前 JsonFloat 所属的 JsonKind 类型(JsFloat)。

返回值:

func toJsonString()

public func toJsonString(): String

功能:将 JsonFloat 转换为 JSON 格式的 (带有空格换行符) 字符串。

返回值:

  • String - 转换后的 JSON 格式字符串。

func toString()

public func toString(): String

功能:将 JsonFloat 转换为字符串。

返回值:

  • String - 转换后的字符串。

class JsonInt

public class JsonInt <: JsonValue {
    public init(iv: Int64)
}

功能:此类为 JsonValue 实现子类,主要用于封装整数类型的 JSON 数据。

父类型:

init(Int64)

public init(iv: Int64)

功能:将指定的 Int64 类型实例封装成 JsonInt 实例。

参数:

  • iv: Int64 - 用于创建 JsonInt 的 Int64。

func getValue()

public func getValue(): Int64

功能:获取 JsonInt 中 value 的实际值。

返回值:

  • Int64 - value 的实际值。

func kind()

public func kind(): JsonKind

功能:返回当前 JsonInt 所属的 JsonKind 类型(JsInt)。

返回值:

func toJsonString()

public func toJsonString(): String

功能:将 JsonInt 转换为 JSON 格式的 (带有空格换行符) 字符串。

返回值:

  • String - 转换后的 JSON 格式字符串。

func toString()

public func toString(): String

功能:将 JsonInt 转换为字符串。

返回值:

  • String - 转换后的字符串。

class JsonNull

public class JsonNull <: JsonValue

功能:此类为 JsonValue 实现子类,主要用于封装 null 的 JSON 数据。

父类型:

func kind()

public func kind(): JsonKind

功能:返回当前 JsonNull 所属的 JsonKind 类型(JsNull)。

返回值:

func toJsonString()

public func toJsonString(): String

功能:将 JsonNull 转换为 JSON 格式的 (带有空格换行符) 字符串。

返回值:

  • String - 转换后的 JSON 格式字符串。

func toString()

public func toString(): String

功能:将 JsonNull 转换为字符串。

返回值:

  • String - 转换后的字符串。

class JsonObject

public class JsonObject <: JsonValue {
    public init()
    public init(map: HashMap<String, JsonValue>)
}

功能:此类为 JsonValue 实现子类,主要用于封装 object 类型的 JSON 数据。

父类型:

init()

public init()

功能:创建空 JsonObject

init(HashMap<String, JsonValue>)

public init(map: HashMap<String, JsonValue>)

功能:将指定的 HashMap 类型实例封装成 JsonObject 实例。

func containsKey(String)

public func containsKey(key: String): Bool

功能:判断 JsonObject 中是否存在 key。

参数:

  • key: String - 指定的 key。

返回值:

  • Bool - 存在返回 true,不存在返回 false。

func get(String)

public func get(key: String): Option<JsonValue>

功能:获取 JsonObject 中 key 对应的 JsonValue,并用 Option<JsonValue> 封装。

参数:

  • key: String - 指定的 key。

返回值:

func getFields()

public func getFields(): HashMap<String, JsonValue>

功能:获取 JsonObject 中的 fields 数据。

返回值:

func kind()

public func kind(): JsonKind

功能:返回当前 JsonObject 所属的 JsonKind 类型(JsObject)。

返回值:

func put(String, JsonValue)

public func put(key: String, v: JsonValue): Unit

功能:向 JsonObject 中加入 key-JsonValue 数据。

参数:

func size()

public func size(): Int64

功能:获取 JsonObject 中 fields 存入 string-JsonValue 的数量。

返回值:

func toJsonString()

public func toJsonString(): String

功能:将 JsonObject 转换为 JSON 格式的 (带有空格换行符) 字符串。

返回值:

  • String - 转换后的 JSON 格式字符串。

func toJsonString(Int64, Bool, String)

public func toJsonString(depth: Int64, bracketInNewLine!: Bool = false, indent!: String = "  "): String

功能:将 JsonObject 转换为 Json格式的字符串。该函数将指定初始的缩进深度、第一个括号后是否换行以及缩进字符串。

参数:

  • depth: Int64 - 缩进深度。
  • bracketInNewLine!: Bool - 第一个括号是否换行,如果为 true,第一个括号将另起一行并且按照指定的深度缩进。
  • indent!: String - 指定的缩进字符串,缩进字符串中只允许空格和制表符的组合,默认为两个空格。

返回值:

  • String - 转换后的 JSON 格式字符串。

异常:

  • IllegalArgumentException - 如果 depth 为负数,或 indent 中存在 ' ' 和 '\t' 以外的字符,则抛出异常。

func toString()

public func toString(): String

功能:将 JsonObject 转换为字符串。

返回值:

  • String - 转换后的字符串。

operator func [](String)

public operator func [](key: String): JsonValue

功能:获取 JsonObject 中 key 对应的 JsonValue

参数:

  • key: String - 指定的 key。

返回值:

异常:

class JsonString

public class JsonString <: JsonValue {
    public init(sv: String)
}

功能:此类为 JsonValue 实现子类,主要用于封装字符串类型的 JSON 数据。

父类型:

init(String)

public init(sv: String)

功能:将指定的 String 类型实例封装成 JsonString 实例。

func getValue()

public func getValue(): String

功能:获取 JsonString 中 value 的实际值。

返回值:

  • String - value 的实际值。

func kind()

public func kind(): JsonKind

功能:返回当前 JsonString 所属的 JsonKind 类型(JsString)。

返回值:

func toJsonString()

public func toJsonString(): String

功能:将 JsonString 转换为 JSON 格式的 (带有空格换行符) 字符串。

返回值:

  • String - 转换后的 JSON 格式字符串。

func toString()

public func toString(): String

功能:将 JsonString 转换为字符串。

返回值:

  • String - 转换后的字符串。

class JsonValue

sealed abstract class JsonValue <: ToString

功能:此类为 JSON 数据层,主要用于 JsonValue 和 String 数据之间的互相转换。

抽象类 JsonValue 提供了 String 类型和具体的 JSON 类型相互转换的接口,以及具体的 JSON 类型判断功能。

父类型:

  • ToString

示例:

使用示例见JsonValue 和 String 互相转换

static func fromStr(String)

public static func fromStr(s: String): JsonValue

功能:将字符串数据解析为 JsonValue。对于整数,支持前导 '0b','0o','0x'(不区分大小写),分别表示二进制,八进制和十六进制。字符串解析失败时将打印错误字符及其行数和列数,其中列数从错误字符所在行的非空格字符起开始计算。

JSON 在解析 String 转换为 JsonValue 时,转义字符 \ 之后只能对应 JSON 支持的转义字符(b、f、n、r、t、u、\、"、/),其中 \u 的格式为:\uXXXX,X 为十六进制数,例:\u0041 代表字符 'A'。

参数:

  • s: String - 传入字符串,暂不支持 "?" 和特殊字符。

返回值:

异常:

  • JsonException - 如果内存分配失败,或解析字符串出错,抛出异常。

示例:

import stdx.encoding.json.*

main() {
    println(JsonString("\b | \f | \n | \r | \t | A | \\ | \" | /").toString())
    println(JsonValue.fromStr("\"\\b\"").toString())
    println(JsonValue.fromStr("\"\\f\"").toString())
    println(JsonValue.fromStr("\"\\n\"").toString())
    println(JsonValue.fromStr("\"\\r\"").toString())
    println(JsonValue.fromStr("\"\\t\"").toString())
    println(JsonValue.fromStr("\"\\u0041\"").toString())
    println(JsonValue.fromStr("\"\\\\\"").toString())
    println(JsonValue.fromStr("\"\\\"\"").toString())
    println(JsonValue.fromStr("\"\\/\"").toString())
}

运行结果如下:

"\b | \f | \n | \r | \t | A | \\ | \" | /"
"\b"
"\f"
"\n"
"\r"
"\t"
"A"
"\\"
"\""
"/"

func asArray()

public func asArray(): JsonArray

功能:将 JsonValue 转换为 JsonArray 格式。

返回值:

异常:

func asBool()

public func asBool(): JsonBool

功能:将 JsonValue 转换为 JsonBool 格式。

返回值:

异常:

func asFloat()

public func asFloat(): JsonFloat

功能:将 JsonValue 转换为 JsonFloat 格式。

返回值:

异常:

func asInt()

public func asInt(): JsonInt

功能:将 JsonValue 转换为 JsonInt 格式。

返回值:

异常:

func asNull()

public func asNull(): JsonNull

功能:将 JsonValue 转换为 JsonNull 格式。

返回值:

异常:

func asObject()

public func asObject(): JsonObject

功能:将 JsonValue 转换为 JsonObject 格式。

返回值:

异常:

func asString()

public func asString(): JsonString

功能:将 JsonValue 转换为 JsonString 格式。

返回值:

异常:

func kind()

public func kind(): JsonKind

功能:返回当前 JsonValue 所属的 JsonKind 类型。

返回值:

func toJsonString()

public func toJsonString(): String

功能:将 JsonValue 转换为 JSON 格式的 (带有空格换行符) 字符串。

返回值:

  • String - 转换后的 JSON 格式字符串。

func toString()

public func toString(): String

功能:将 JsonValue 转换为字符串。

返回值:

  • String - 转换后的字符串。

枚举

enum JsonKind

public enum JsonKind {
    | JsNull
    | JsBool
    | JsInt
    | JsFloat
    | JsString
    | JsArray
    | JsObject
}

功能:表示 JsonValue 的具体类型。

JsArray

JsArray

功能:表示 JSON 类型中的数组类型。

JsBool

JsBool

功能:表示 true 或者 false 类型。

JsFloat

JsFloat

功能:表示值为浮点数的 number 类型。

JsInt

JsInt

功能:表示值为整数的 number 类型。

JsNull

JsNull

功能:表示 null 类型。

JsObject

JsObject

功能:表述 JSON 类型中的对象类型。

JsString

JsString

功能:表示 string 类型。

异常

class JsonException

public class JsonException <: Exception {
    public init()
    public init(message: String)
}

功能:JSON 包的异常类,用于 JsonValue 类型使用时出现异常的场景。

父类型:

  • Exception

init()

public init()

功能:构造一个不包含任何异常提示信息的 JsonException 实例。

init(String)

public init(message: String)

功能:根据指定的异常提示信息构造 JsonException 实例。

参数:

  • message: String - 指定的异常提示信息。

JsonArray 使用示例

下面是 JsonArray 使用示例,该示例构造了一个 JsonArray 对象,并往其中添加了一些 JsonValue,最后以两种格式打印了该 JsonArray 对象。

示例:

import stdx.encoding.json.*
import std.collection.*

main() {
    var a: JsonValue = JsonNull()
    var b: JsonValue = JsonBool(true)
    var c: JsonValue = JsonBool(false)
    var d: JsonValue = JsonInt(7363)
    var e: JsonValue = JsonFloat(736423.546)
    var list: ArrayList<JsonValue> = ArrayList<JsonValue>()
    var list2: ArrayList<JsonValue> = ArrayList<JsonValue>()
    var map = JsonObject()
    var map1 = JsonObject()
    map1.put("a", JsonString("jjjjjj"))
    map1.put("b", b)
    map1.put("c", JsonString("hhhhh"))
    list2.add(b)
    list2.add(JsonInt(3333333))
    list2.add(map1)
    list2.add(JsonString("sdfghgfasd"))
    list.add(b)
    list.add(a)
    list.add(map)
    list.add(c)
    list.add(JsonArray(list2))
    list.add(d)
    list.add(JsonString("ddddddd"))
    list.add(e)
    var result: JsonValue = JsonArray(list)
    println("func toString result is:")
    println(result.toString())
    println("func toJsonString result is:")
    println(result.toJsonString())
}

运行结果:

func toString result is:
[true,null,{},false,[true,3333333,{"a":"jjjjjj","b":true,"c":"hhhhh"},"sdfghgfasd"],7363,"ddddddd",736423.546]
func toJsonString result is:
[
  true,
  null,
  {},
  false,
  [
    true,
    3333333,
    {
      "a": "jjjjjj",
      "b": true,
      "c": "hhhhh"
    },
    "sdfghgfasd"
  ],
  7363,
  "ddddddd",
  736423.546
]

JsonValue 和 String 互相转换

下面是 JsonValue 和 String 互相转换的示例,该示例使用 JsonValue.fromStr 将一个 JSON 字符串转换为 JsonValue,随后以两种格式打印了该 JsonValue 对象。

示例:

import stdx.encoding.json.*

main() {
    var str = ##"[true,"kjjjke\"eed",{"sdfd":"ggggg","eeeee":[341,false,{"nnnn":55.87}]},3422,22.341,false,[22,22.22,true,"ddd"],43]"##
    var jv: JsonValue = JsonValue.fromStr(str)
    var res = jv.toString()
    var prettyres = jv.toJsonString()
    println(res)
    println(prettyres)
}

运行结果:

[true,"kjjjke\"eed",{"sdfd":"ggggg","eeeee":[341,false,{"nnnn":55.87}]},3422,22.341,false,[22,22.22,true,"ddd"],43]
[
  true,
  "kjjjke\"eed",
  {
    "sdfd": "ggggg",
    "eeeee": [
      341,
      false,
      {
        "nnnn": 55.87
      }
    ]
  },
  3422,
  22.341,
  false,
  [
    22,
    22.22,
    true,
    "ddd"
  ],
  43
]

JsonValue 与 DataModel 的转换

下面是 JSON 字符串与自定义类型间的转换的示例,该用例为 Person 类型实现了 Serializable 接口,随后进行了从 JSON 字符串到自定义类型的转换和从自定义类型到 JSON 字符串的转换。

示例:

import stdx.serialization.serialization.*
import stdx.encoding.json.*

class Person <: Serializable<Person> {
    var name: String = ""
    var age: Int64 = 0
    var loc: Option<Location> = Option<Location>.None

    public func serialize(): DataModel {
        return DataModelStruct()
            .add(field<String>("name", name))
            .add(field<Int64>("age", age))
            .add(field<Option<Location>>("loc", loc))
    }

    public static func deserialize(dm: DataModel): Person {
        var dms = match (dm) {
            case data: DataModelStruct => data
            case _ => throw Exception("this data is not DataModelStruct")
        }
        var result = Person()
        result.name = String.deserialize(dms.get("name"))
        result.age = Int64.deserialize(dms.get("age"))
        result.loc = Option<Location>.deserialize(dms.get("loc"))
        return result
    }
}

class Location <: Serializable<Location> {
    var country: String = ""
    var province: String = ""

    public func serialize(): DataModel {
        return DataModelStruct().add(field<String>("country", country)).add(field<String>("province", province))
    }

    public static func deserialize(dm: DataModel): Location {
        var dms = match (dm) {
            case data: DataModelStruct => data
            case _ => throw Exception("this data is not DataModelStruct")
        }
        var result = Location()
        result.country = String.deserialize(dms.get("country"))
        result.province = String.deserialize(dms.get("province"))
        return result
    }
}

main() {
    var js = ##"{
    "name": "A",
    "age": 30,
    "loc": {
        "country": "China",
        "province": "Beijing"
    }
}"##

    /* 实现从 JSON 字符串到自定义类型的转换 */
    var jv = JsonValue.fromStr(js)
    var dm = DataModel.fromJson(jv)
    var A = Person.deserialize(dm)
    println("name == ${A.name}")
    println("age == ${A.age}")
    println("country == ${A.loc.getOrThrow().country}")
    println("province == ${A.loc.getOrThrow().province}")
    println("====================")

    /* 实现从自定义类型到 JSON 字符串的转换 */
    dm = A.serialize()
    var jo = dm.toJson().asObject()
    println(jo.toJsonString())
}

运行结果:

name == A
age == 30
country == China
province == Beijing
====================
{
  "name": "A",
  "age": 30,
  "loc": {
    "country": "China",
    "province": "Beijing"
  }
}

stdx.encoding.json.stream

功能介绍

json.stream 包主要用于仓颉对象和 JSON 数据流之间的互相转换。

本包提供了 JsonWriter 和 JsonReader 类,JsonWriter 用于提供仓颉对象转 JSON 数据流的序列化能力;JsonReader 用于提供 JSON 数据流转仓颉对象的反序列化能力。

当前实现中支持和 JSON 数据流互转的类型有:

  • 基础数据类型:String、Int8、Int16、Int32、Int64、Float16、Float32、Float64、UInt8、UInt16、UInt32、UInt64。

  • 集合类型:Array<T>、ArrayList<T>、HashMap<String, T>。

  • 其它类型:Option<T>、BigInt、Decimal。

API 列表

接口

接口名功能
JsonDeserializable<T>此接口用于实现从 JsonReader 中读取一个仓颉对象。
JsonSerializable为类型提供序列化到 JSON 数据流的接口。

类名功能
JsonReader此类提供 JSON 数据流转仓颉对象的反序列化能力。
JsonWriter构造函数,构造一个将数据写入 out 的实例。

枚举

枚举名功能
JsonToken表示 JSON 编码的字符串中的结构、名称或者值类型。

结构体

结构体名功能
WriteConfig用于表示 JsonWriter 的序列化格式配置。

接口

interface JsonDeserializable<T>

public interface JsonDeserializable<T> {
    static func fromJson(r: JsonReader): T
}

功能:此接口用于实现从 JsonReader 中读取一个仓颉对象。

支持的对象类型包括:

  • 基本数据类型:整数类型、浮点类型、布尔类型、字符串类型。

  • Collection 类型:Array、ArrayList、HashMap、Option。

  • BigInt、Decimal 类型。

  • DateTime 类型。

static func fromJson(JsonReader)

static func fromJson(r: JsonReader): T

功能:从参数 r 指定的 JsonReader 实例中读取一个 T 类型对象。

参数:

返回值:

  • T - T 类型的实例。

异常:

  • IllegalStateException - 如果输入流的 JSON 数据不符合格式,抛出异常。

extend BigInt <: JsonDeserializable<BigInt>

extend BigInt <: JsonDeserializable<BigInt>

功能:为 BigInt 类型实现 JsonDeserializable 接口。

父类型:

static func fromJson(JsonReader)

public static func fromJson(r: JsonReader): BigInt

功能:从 JsonReader 中读取一个 BigInt。

参数:

返回值:

  • BigInt - BigInt 类型的实例。

extend Bool <: JsonDeserializable<Bool>

extend Bool <: JsonDeserializable<Bool>

功能:为 Bool 类型实现 JsonDeserializable 接口。

父类型:

static func fromJson(JsonReader)

public static func fromJson(r: JsonReader): Bool

功能:从 JsonReader 中读取一个 Bool。

参数:

返回值:

  • Bool - Bool 类型的实例。

extend DateTime <: JsonDeserializable<DateTime>

extend DateTime <: JsonDeserializable<DateTime>

功能:为 DateTime 类型实现 JsonDeserializable 接口。

父类型:

static func fromJson(JsonReader)

public static func fromJson(r: JsonReader): DateTime

功能:从 JsonReader 中读取一个 DateTime 实例。

该函数将会把读取到的字符串按照 RFC3339 的规范解析,可包含小数秒格式,函数的行为参考DateTime的func parse(String)。

参数:

返回值:

  • DateTime - DateTime 类型的实例。

异常:

  • TimeParseException - 无法正常解析时,抛出异常。

extend Decimal <: JsonDeserializable<Decimal>

extend Decimal <: JsonDeserializable<Decimal>

功能:为 Decimal 类型实现 JsonDeserializable 接口。

父类型:

static func fromJson(JsonReader)

public static func fromJson(r: JsonReader): Decimal

功能:从 JsonReader 中读取一个 Decimal。

参数:

返回值:

  • Decimal - Decimal 类型的实例。

extend Float16 <: JsonDeserializable<Float16>

extend Float16 <: JsonDeserializable<Float16>

功能:为 Float16 类型实现 JsonDeserializable 接口。

父类型:

static func fromJson(JsonReader)

public static func fromJson(r: JsonReader): Float16

功能:从 JsonReader 中读取一个 Float16。

参数:

返回值:

  • Float16 - Float16 类型的实例。

异常:

  • OverflowException - 读取的数据超过范围时,抛出异常。

extend Float32 <: JsonDeserializable<Float32>

extend Float32 <: JsonDeserializable<Float32>

功能:为 Float32 类型实现 JsonDeserializable 接口。

父类型:

static func fromJson(JsonReader)

public static func fromJson(r: JsonReader): Float32

功能:从 JsonReader 中读取一个 Float32。

参数:

返回值:

  • Float32 - Float32 类型的实例。

异常:

  • OverflowException - 读取的数据超过范围时,抛出异常。

extend Float64 <: JsonDeserializable<Float64>

extend Float64 <: JsonDeserializable<Float64>

功能:为 Float64 类型实现 JsonDeserializable 接口。

父类型:

static func fromJson(JsonReader)

public static func fromJson(r: JsonReader): Float64

功能:从 JsonReader 中读取一个 Float64。

参数:

返回值:

  • Float64 - Float64 类型的实例。

异常:

  • OverflowException - 读取的数据超过范围时,抛出异常。

extend String <: JsonDeserializable<String>

extend String <: JsonDeserializable<String>

功能:为 String 类型实现 JsonDeserializable 接口。

父类型:

static func fromJson(JsonReader)

public static func fromJson(r: JsonReader): String

功能:从 JsonReader 中读取一个 String。

根据下一个 JsonToken 的不同,String 的反序列化结果将会不同:

  • 当下一个 JsonTokenJsonString 时, 反序列化过程会按照标准ECMA-404 The JSON Data Interchange Standard对读到的 String 进行转义。
  • 当下一个 JsonTokenJsonNumber JsonBool JsonNull 其中一个时,将会读取下一个 value 字段的原始字符串并返回。
  • 当下一个 JsonToken 是其它类型时,调用此接口会抛异常。

参数:

返回值:

  • String - String 类型的实例。

extend Int16 <: JsonDeserializable<Int16>

extend Int16 <: JsonDeserializable<Int16>

功能:为 Int16 类型实现 JsonDeserializable 接口。

父类型:

static func fromJson(JsonReader)

public static func fromJson(r: JsonReader): Int16

功能:从 JsonReader 中读取一个 Int16。

参数:

返回值:

  • Int16 - Int16 类型的实例。

异常:

  • OverflowException - 读取的数据超过范围时,抛出异常。

extend Int32 <: JsonDeserializable<Int32>

extend Int32 <: JsonDeserializable<Int32>

功能:为 Int32 类型实现 JsonDeserializable 接口。

父类型:

static func fromJson(JsonReader)

public static func fromJson(r: JsonReader): Int32

功能:从 JsonReader 中读取一个 Int32。

参数:

返回值:

  • Int32 - Int32 类型的实例。

异常:

  • OverflowException - 读取的数据超过范围时,抛出异常。

extend Int64 <: JsonDeserializable<Int64>

extend Int64 <: JsonDeserializable<Int64>

功能:为 Int64 类型实现 JsonDeserializable 接口。

父类型:

static func fromJson(JsonReader)

public static func fromJson(r: JsonReader): Int64

功能:从 JsonReader 中读取一个 Int64。

参数:

返回值:

  • Int64 - Int64 类型的实例。

异常:

  • OverflowException - 读取的数据超过范围时,抛出异常。

extend Int8 <: JsonDeserializable<Int8>

extend Int8 <: JsonDeserializable<Int8>

功能:为 Int8 类型实现 JsonDeserializable 接口。

父类型:

static func fromJson(JsonReader)

public static func fromJson(r: JsonReader): Int8

功能:从 JsonReader 中读取一个 Int8。

参数:

返回值:

  • Int8 - Int8 类型的实例。

异常:

  • OverflowException - 读取的数据超过范围时,抛出异常。

extend IntNative <: JsonDeserializable<IntNative>

extend IntNative <: JsonDeserializable<IntNative>

功能:为 IntNative 类型实现 JsonDeserializable 接口。

父类型:

static func fromJson(JsonReader)

public static func fromJson(r: JsonReader): IntNative

功能:从 JsonReader 中读取一个 IntNative。

参数:

返回值:

  • IntNative - IntNative 类型的实例。

异常:

  • OverflowException - 读取的数据超过范围时,抛出异常。

extend UInt16 <: JsonDeserializable<UInt16>

extend UInt16 <: JsonDeserializable<UInt16>

功能:为 UInt16 类型实现 JsonDeserializable 接口。

父类型:

static func fromJson(JsonReader)

public static func fromJson(r: JsonReader): UInt16

功能:从 JsonReader 中读取一个 UInt16。

参数:

返回值:

  • UInt16 - UInt16 类型的实例。

异常:

  • OverflowException - 读取的数据超过范围时,抛出异常。

extend UInt32 <: JsonDeserializable<UInt32>

extend UInt32 <: JsonDeserializable<UInt32>

功能:为 UInt32 类型实现 JsonDeserializable 接口。

父类型:

static func fromJson(JsonReader)

public static func fromJson(r: JsonReader): UInt32

功能:从 JsonReader 中读取一个 UInt32。

参数:

返回值:

  • UInt32 - UInt32 类型的实例。

异常:

  • OverflowException - 读取的数据超过范围时,抛出异常。

extend UInt64 <: JsonDeserializable<UInt64 >

extend UInt64 <: JsonDeserializable<UInt64>

功能:为 UInt64 类型实现 JsonDeserializable 接口。

父类型:

static func fromJson(JsonReader)

public static func fromJson(r: JsonReader): UInt64

功能:从 JsonReader 中读取一个 UInt64。

参数:

返回值:

  • UInt64 - UInt64 类型的实例。

异常:

  • OverflowException - 读取的数据超过范围时,抛出异常。

extend UInt8 <: JsonDeserializable<UInt8>

extend UInt8 <: JsonDeserializable<UInt8>

功能:为 UInt8 类型实现 JsonDeserializable 接口。

父类型:

static func fromJson(JsonReader)

public static func fromJson(r: JsonReader): UInt8

功能:从 JsonReader 中读取一个 UInt8。

参数:

返回值:

  • UInt8 - UInt8 类型的实例。

异常:

  • OverflowException - 读取的数据超过范围时,抛出异常。

extend UIntNative <: JsonDeserializable<UIntNative>

extend UIntNative <: JsonDeserializable<UIntNative>

功能:为 UIntNative 类型实现 JsonDeserializable 接口。

父类型:

static func fromJson(JsonReader)

public static func fromJson(r: JsonReader): UIntNative

功能:从 JsonReader 中读取一个 UIntNative。

参数:

返回值:

  • UIntNative - UIntNative 类型的实例。

异常:

  • OverflowException - 读取的数据超过范围时,抛出异常。

extend<T> Array<T> <: JsonDeserializable<Array<T>> where T <: JsonDeserializable<T>

extend<T> Array<T> <: JsonDeserializable<Array<T>> where T <: JsonDeserializable<T>

功能:为 Array<T> 类型实现 JsonDeserializable 接口。

父类型:

static func fromJson(JsonReader)

public static func fromJson(r: JsonReader): Array<T>

功能:从 JsonReader 中读取一个 Array。

参数:

返回值:

  • Array<T> - Array 类型的实例。

extend<T> ArrayList<T> <: JsonDeserializable<ArrayList<T>> where T <: JsonDeserializable<T>

extend<T> ArrayList<T> <: JsonDeserializable<ArrayList<T>> where T <: JsonDeserializable<T>

功能:为 ArrayList 类型实现 JsonDeserializable 接口。

父类型:

static func fromJson(JsonReader)

public static func fromJson(r: JsonReader): ArrayList<T>

功能:从 JsonReader 中读取一个 ArrayList。

参数:

返回值:

  • ArrayList <T> - ArrayList 类型的实例。

extend<T> Option <T> <: JsonDeserializable<Option<T>> where T <: JsonDeserializable<T>

extend<T> Option<T> <: JsonDeserializable<Option<T>> where T <: JsonDeserializable<T>

功能:为 Option 类型实现 JsonDeserializable 接口。

父类型:

static func fromJson(JsonReader)

public static func fromJson(r: JsonReader): Option<T>

功能:从 JsonReader 中读取一个Option。

参数:

返回值:

  • Option<T> - Option 类型的实例。

extend<T> HashMap<String, T> <: JsonDeserializable<HashMap<String, T>> where T <: JsonDeserializable<T>

extend<T> HashMap<String, T> <: JsonDeserializable<HashMap<String, T>> where T <: JsonDeserializable<T>

功能:为 HashMap 类型实现 JsonDeserializable 接口。

父类型:

static func fromJson(JsonReader)

public static func fromJson(r: JsonReader): HashMap<String, T>

功能:从 JsonReader 中读取一个 HashMap。

参数:

返回值:

  • HashMap<String, T> - HashMap<String, T> 类型的实例。

interface JsonSerializable

public interface JsonSerializable {
    func toJson(w: JsonWriter): Unit
}

功能:为类型提供序列化到 JSON 数据流的接口。

JsonWriter 搭配使用,JsonWriter 可以将实现了 JsonSerializable 接口的类型写入到 Stream 中。

func toJson(JsonWriter)

func toJson(w: JsonWriter): Unit

功能:将实现了 JsonSerializable 接口的类型写入参数 w 指定的 JsonWriter 实例中。

参数:

extend BigInt <: JsonSerializable

extend BigInt <: JsonSerializable

功能:为 BigInt 类型提供序列化到 JSON 数据流的接口。

父类型:

func toJson(JsonWriter)

public func toJson(w: JsonWriter): Unit

功能:将 BigInt 类型写入参数 w 指定的 JsonWriter 实例中。

参数:

extend Bool <: JsonSerializable

extend Bool <: JsonSerializable

功能:为 Bool 类型提供序列化到 JSON 数据流的接口。

父类型:

func toJson(JsonWriter)

public func toJson(w: JsonWriter): Unit

功能:将 Bool 类型写入参数 w 指定的 JsonWriter 实例中。

参数:

extend DateTime <: JsonSerializable

extend DateTime <: JsonSerializable

功能:为 DateTime 类型实现 JsonSerializable 接口。

父类型:

func toJson(JsonWriter)

public func toJson(w: JsonWriter): Unit

功能:提供 DateTime 类型序列化到流的功能。

该接口的功能与 JsonWriterwriteConfig中的属性 dateTimeFormat有关联,将会把 DateTime 按照dateTimeFormat中的格式输出到目标流中,可以通过修改dateTimeFormat实现不同的格式控制。

参数:

extend Decimal <: JsonSerializable

extend Decimal <: JsonSerializable

功能:为 Decimal 类型提供序列化到 JSON 数据流的接口。

父类型:

func toJson(JsonWriter)

public func toJson(w: JsonWriter): Unit

功能:将 Decimal 类型写入参数 w 指定的 JsonWriter 实例中。

参数:

extend Float16 <: JsonSerializable

extend Float16 <: JsonSerializable

功能:为 Float16 类型提供序列化到 JSON 数据流的接口。

父类型:

func toJson(JsonWriter)

public func toJson(w: JsonWriter): Unit

功能:将 Float16 类型写入参数 w 指定的 JsonWriter 实例中。

参数:

extend Float32 <: JsonSerializable

extend Float32 <: JsonSerializable

功能:为 Float32 类型提供序列化到 JSON 数据流的接口。

父类型:

func toJson(JsonWriter)

public func toJson(w: JsonWriter): Unit

功能:将 Float32 类型写入参数 w 指定的 JsonWriter 实例中。

参数:

extend Float64 <: JsonSerializable

extend Float64 <: JsonSerializable

功能:为 Float64 类型提供序列化到 JSON 数据流的接口。

父类型:

func toJson(JsonWriter)

public func toJson(w: JsonWriter): Unit

功能:将 Float64 类型写入参数 w 指定的 JsonWriter 实例中。

参数:

extend String <: JsonSerializable

extend String <: JsonSerializable

功能:为 String 类型提供序列化到 JSON 数据流的接口。

父类型:

func toJson(JsonWriter)

public func toJson(w: JsonWriter): Unit

功能:将 String 类型写入参数 w 指定的 JsonWriter 实例中。写入的String

参数:

extend Int16 <: JsonSerializable

extend Int16 <: JsonSerializable

功能:为 Int16 类型提供序列化到 JSON 数据流的接口。

父类型:

func toJson(JsonWriter)

public func toJson(w: JsonWriter): Unit

功能:将 Int16 类型写入参数 w 指定的 JsonWriter 实例中。

参数:

extend Int32 <: JsonSerializable

extend Int32 <: JsonSerializable

功能:为 Int32 类型提供序列化到 JSON 数据流的接口。

父类型:

func toJson(JsonWriter)

public func toJson(w: JsonWriter): Unit

功能:将 Int32 类型写入参数 w 指定的 JsonWriter 实例中。

参数:

extend Int64 <: JsonSerializable

extend Int64 <: JsonSerializable

功能:为 Int64 类型提供序列化到 JSON 数据流的接口。

父类型:

func toJson(JsonWriter)

public func toJson(w: JsonWriter): Unit

功能:将 Int64 类型写入参数 w 指定的 JsonWriter 实例中。

参数:

extend Int8 <: JsonSerializable

extend Int8 <: JsonSerializable

功能:为 Int8 类型提供序列化到 JSON 数据流的接口。

父类型:

func toJson(JsonWriter)

public func toJson(w: JsonWriter): Unit

功能:将 Int8 类型写入参数 w 指定的 JsonWriter 实例中。

参数:

extend IntNative <: JsonSerializable

extend IntNative <: JsonSerializable

功能:为 IntNative 类型提供序列化到 JSON 数据流的接口。

父类型:

func toJson(JsonWriter)

public func toJson(w: JsonWriter): Unit

功能:将 IntNative 类型写入参数 w 指定的 JsonWriter 实例中。

参数:

extend UInt16 <: JsonSerializable

extend UInt16 <: JsonSerializable

功能:为 UInt16 类型提供序列化到 JSON 数据流的接口。

父类型:

func toJson(JsonWriter)

public func toJson(w: JsonWriter): Unit

功能:将 UInt16 类型写入参数 w 指定的 JsonWriter 实例中。

参数:

extend UInt32 <: JsonSerializable

extend UInt32 <: JsonSerializable

功能:为 UInt32 类型提供序列化到 JSON 数据流的接口。

父类型:

func toJson(JsonWriter)

public func toJson(w: JsonWriter): Unit

功能:将 UInt32 类型写入参数 w 指定的 JsonWriter 实例中。

参数:

extend UInt64 <: JsonSerializable

extend UInt64 <: JsonSerializable

功能:为 UInt64 类型提供序列化到 JSON 数据流的接口。

父类型:

func toJson(JsonWriter)

public func toJson(w: JsonWriter): Unit

功能:将 UInt64 类型写入参数 w 指定的 JsonWriter 实例中。

参数:

extend UInt8 <: JsonSerializable

extend UInt8 <: JsonSerializable

功能:为 UInt8 类型提供序列化到 JSON 数据流的接口。

父类型:

func toJson(JsonWriter)

public func toJson(w: JsonWriter): Unit

功能:将 UInt8 类型写入参数 w 指定的 JsonWriter 实例中。

参数:

extend UIntNative <: JsonSerializable

extend UIntNative <: JsonSerializable

功能:为 UIntNative 类型提供序列化到 JSON 数据流的接口。

父类型:

func toJson(JsonWriter)

public func toJson(w: JsonWriter): Unit

功能:将 UIntNative 类型写入参数 w 指定的 JsonWriter 实例中。

参数:

extend<T> Array<T> <: JsonSerializable where T <: JsonSerializable

extend<T> Array<T> <: JsonSerializable where T <: JsonSerializable

功能:为 Array<T> 类型提供序列化到 JSON 数据流的接口。

父类型:

func toJson(JsonWriter)

public func toJson(w: JsonWriter): Unit

功能:将 Array<T> 类型写入参数 w 指定的 JsonWriter 实例中。

参数:

extend<T> ArrayList<T> <: JsonSerializable where T <: JsonSerializable

extend<T> ArrayList<T> <: JsonSerializable where T <: JsonSerializable

功能:为 ArrayList<T> 类型提供序列化到 JSON 数据流的接口。

父类型:

func toJson(JsonWriter)

public func toJson(w: JsonWriter): Unit

功能:将 ArrayList<T> 类型写入参数 w 指定的 JsonWriter 实例中。

参数:

extend<T> Option<T> <: JsonSerializable where T <: JsonSerializable

extend<T> Option<T> <: JsonSerializable where T <: JsonSerializable

功能:为 Option<T> 类型提供序列化到 JSON 数据流的接口。

父类型:

func toJson(JsonWriter)

public func toJson(w: JsonWriter): Unit

功能:将 Option<T> 类型写入参数 w 指定的 JsonWriter 实例中。

参数:

extend<V> HashMap<String, V> <: JsonSerializable where V <: JsonSerializable

extend<V> HashMap<String, V> <: JsonSerializable where V <: JsonSerializable

功能:为 HashMap<String, T> 类型提供序列化到 JSON 数据流的接口。

父类型:

func toJson(JsonWriter)

public func toJson(w: JsonWriter): Unit

功能:将 HashMap<String, T> 类型写入参数 w 指定的 JsonWriter 实例中。

参数:

class JsonReader

public class JsonReader {
    public init(inputStream: InputStream)
}

功能:此类提供 JSON 数据流转仓颉对象的反序列化能力。

使用示例见使用 Json Stream 进行反序列化

init(InputStream)

public init(inputStream: InputStream)

功能:根据输入流创建一个 JsonReaderJsonReader 从输入流中读取数据时,将跳过非 JsonString 中的空字符('\0', '\t', '\n', '\r')。

参数:

  • inputStream: InputStream - 输入的 JSON 数据流。

func endArray()

public func endArray(): Unit

功能:从输入流的当前位置跳过空白字符后消耗一个 ']' 字符,endArray 必须有一个 startArray 与之对应。

异常:

  • IllegalStateException - 如果输入流的 JSON 数据不符合格式,抛出异常。

func endObject()

public func endObject(): Unit

功能:从输入流的当前位置跳过空白字符后消耗一个 '}' 字符,endObject 必须有一个 startObject 与之对应。

异常:

  • IllegalStateException - 如果输入流的 JSON 数据不符合格式,抛出异常。

func peek()

public func peek(): Option<JsonToken>

功能:获取输入流的下一个 JsonToken 的类型,不保证下一个 JsonToken 的格式一定正确。

例:如果输入流中的下一个字符为 't',获取的 JsonToken 将为 JsonToken.Bool,但调用 readValue<Bool>() 不一定成功。

返回值:

  • Option<JsonToken> - 获取到的下一个 JsonToken 的类型,如果到了输入流的结尾返回 None。

异常:

  • IllegalStateException - 如果输入流的下一个字符不在以下范围内:(n, t, f, ", 0~9, -, {, }, [, ])。

func readName()

public func readName(): String

功能:从输入流的当前位置读取一个 name。

返回值:

  • String - 读取出的 name 值。

异常:

  • IllegalStateException - 如果输入流的 JSON 数据不符合格式,抛出异常。

func readValue<T>() where T <: JsonDeserializable<T>

public func readValue<T>(): T where T <: JsonDeserializable<T>

功能:从输入流的当前位置读取一个 value。

注意:

当泛型 T 是 String 类型时,根据下一个 JsonToken 的不同,该函数的返回值将会不同:

返回值:

  • T - 读取出的 value 值。

异常:

  • IllegalStateException - 如果输入流的 JSON 数据不符合格式,抛出异常。

func readValueBytes()

public func readValueBytes(): Array<Byte>

功能:读取输入流的下一组原始数据(字节数组),不进行转义等操作。

说明:

readValueBytes 的规则如下:

  • 如果 next token 是 value,则读取这个 value 的所有原始字节,直到读取到代表结束的符号,如 ',' '}' ']'。

  • 如果 next token 是 Name,读取 (name + value) 这一个组合的原始字节数组。

  • 如果 next token 是 BeginArray,读取 Array 内的内的所有原始字节。

  • 如果 next token 是 BeginObject,读取 Object 内的内的所有原始字节。

  • 如果 next token 是 EndArray 或者 EndObject 或者 None,不做任何操作,返回空的数组,再次执行 peek() 仍返回 EndArray 或者 EndObject 或者 None。

返回值:

  • Array<Byte> - 下一组数据对应的原始字节数据。

异常:

  • IllegalStateException - 如果输入流的 JSON 数据不符合格式,抛出异常。

func skip()

public func skip(): Unit

功能:从输入流的当前位置跳过一组数据。

说明:

Skip 的规则如下:

  • 如果 next token 是 value,跳过这个 value, 跳过 value 时不检查该 value 格式是否正确。

  • 如果 next token 是 Name,跳过 (name + value) 这一个组合。

  • 如果 next token 是 BeginArray,跳过这个 array。

  • 如果 next token 是 BeginObject,跳过这个 object。

  • 如果 next token 是 EndArray 或者 EndObject 或者 None,不做任何操作,peek 仍返回 EndArray 或者 EndObject 或者 None。

异常:

  • IllegalStateException - 如果输入流的 JSON 数据不符合格式,抛出异常。

func startArray()

public func startArray(): Unit

功能:从输入流的当前位置跳过空白字符后消耗一个 '[' 字符。

异常:

  • IllegalStateException - 如果输入流的 JSON 数据不符合格式,抛出异常。

func startObject()

public func startObject(): Unit

功能:从输入流的当前位置跳过空白字符后消耗一个 '{' 字符。

异常:

  • IllegalStateException - 如果输入流的 JSON 数据不符合格式,抛出异常。

class JsonWriter

public class JsonWriter {
    public var writeConfig = WriteConfig.compact
    public init(out: OutputStream)
}

功能:JsonWriter 提供了将仓颉对象序列化到 OutputStream 的能力。

JsonWriter 需要和 interface JsonSerializable 搭配使用,JsonWriter 可以通过 writeValue 来将实现了 JsonSerializable 接口的类型写入到 Stream 中。

注意:

JsonWriter 中使用缓存来减少写入 Stream 时的 IO 次数,在结束使用 JsonWriter 之前需要调用 flush 函数来确保缓存中的数据全部写入 Stream。

示例:

使用示例见使用 Json Stream 进行序列化

var writeConfig

public var writeConfig = WriteConfig.compact

功能:序列化格式配置。详见 WriteConfig

init(OutputStream)

public init(out: OutputStream)

功能:构造函数,构造一个将数据写入 out 的实例。

参数:

  • out: OutputStream - 目标流

func endArray()

public func endArray(): Unit

功能:结束序列化当前的 JSON 数组。

异常:

  • IllegalStateException - 当前 writer 没有匹配的 startArray 时。

func endObject()

public func endObject(): Unit

功能:结束序列化当前的 JSON object。

异常:

  • IllegalStateException - 当前 writer 的状态不应该结束一个 JSON object 时。

func flush()

public func flush(): Unit

功能:将缓存中的数据写入 out,并且调用 out 的 flush 方法。

func jsonValue(String)

public func jsonValue(value: String): JsonWriter

功能: 将符合JSON value规范的原始字符串写入stream。

注意:

此函数不会对值 value 进行转义,也不会为入参添加双引号。如果使用者能够保证输入的值 value 符合数据转换标准ECMA-404 The JSON Data Interchange Standard, 建议使用该函数。

返回值:

异常:

  • IllegalStateException - 当前 writer 的状态不应该写入 value 时。

func startArray()

public func startArray(): Unit

功能:开始序列化一个新的 JSON 数组,每一个 startArray 都必须有一个 endArray 对应。

异常:

  • IllegalStateException - 当前 writer 的状态不应该写入 JSON array 时。

func startObject()

public func startObject(): Unit

功能:开始序列化一个新的 JSON object,每一个 startObject 都必须有一个 endObject 对应。

异常:

  • IllegalStateException - 当前 writer 的状态不应该写入 JSON object 时。

func writeName(String)

public func writeName(name: String): JsonWriter

功能:在 object 结构中写入 name。

返回值:

异常:

  • IllegalStateException - 当前 JsonWriter 的状态不应写入参数 name 指定字符串时。

func writeNullValue()

public func writeNullValue(): JsonWriter

功能:向流中写入 JSON value null。

返回值:

异常:

  • IllegalStateException - 当前 writer 的状态不应该写入 value 时

func writeValue<T>(T) where T <: JsonSerializable

public func writeValue<T>(v: T): JsonWriter where T <: JsonSerializable

功能:将实现了 JsonSerializable 接口的类型写入到 Stream 中。该接口会调用泛型 T 的 toJson 方法向输出流中写入数据。

json.stream 包已经为基础类型 Int64、UInt64、Float64、Bool、String类型扩展实现了 JsonSerializable, 并且为 Collection 类型 Array、ArrayList和 HashMap 扩展实现了 JsonSerializable

返回值:

异常:

  • IllegalStateException - 当前 writer 的状态不应该写入 value 时。

枚举

enum JsonToken

public enum JsonToken <: Equatable<JsonToken> & Hashable{
    | JsonNull
    | JsonBool
    | JsonNumber
    | JsonString
    | BeginArray
    | EndArray
    | BeginObject
    | EndObject
    | Name
}

功能:表示 JSON 编码的字符串中的结构、名称或者值类型。

JsonToken 通常和 JsonReader.peek()搭配使用,通过对返回值的判断来决定具体的处理方式。

父类型:

BeginArray

BeginArray

功能:表示 JSON 中 array 的开始。如果 JsonReader.peek() 返回的是该类型,可以使用 JsonReader.startArray() 读取。

BeginObject

BeginObject

功能:表示 JSON 中 object 的开始。如果 JsonReader.peek() 返回的是该类型,可以使用 JsonReader.startObject() 读取。

EndArray

EndArray

功能:表示 JSON 中 array 的结束。如果 JsonReader.peek() 返回的是该类型,可以使用 JsonReader.endArray() 读取。

EndObject

EndObject

功能:表示 JSON 中 object 的结束。如果 JsonReader.peek() 返回的是该类型,可以使用 JsonReader.endObject() 读取。

JsonBool

JsonBool

功能:表示 JSON 的 bool 类型。如果 JsonReader.peek() 返回的是该类型,可以使用 JsonReader.readValue<Bool>() 读取。

JsonNull

JsonNull

功能:表示 JSON 的 null 类型。如果 JsonReader.peek() 返回的是该类型,可以使用 JsonReader.readValue<Option<T>>() 读取。

JsonNumber

JsonNumber

功能:表示 JSON 的 number 类型。如果 JsonReader.peek() 返回的是该类型,可以使用 JsonReader.readValue<Float64>() 读取。

JsonString

JsonString

功能:表示 JSON 的 string 类型。如果 JsonReader.peek() 返回的是该类型,可以使用 JsonReader.readValue<String>() 读取。

Name

Name

功能:表示 object 中的 name。如果 JsonReader.peek() 返回的是该类型,可以使用 JsonReader.readName() 读取。

func hashCode()

public func hashCode(): Int64

功能:获取 JsonToken 对象的 hashCode 值。

返回值:

  • Int64 - hashCode 值。

operator func !=(JsonToken)

public operator func !=(that: JsonToken): Bool

功能:判不等。

参数:

返回值:

  • Bool - 当前实例与 that 不相等返回 true,否则返回 false

operator func ==(JsonToken)

public operator func ==(that: JsonToken): Bool

功能:判等。

参数:

返回值:

  • Bool - 当前实例与 that 相等返回 true,否则返回 false

结构体

struct WriteConfig

public struct WriteConfig {
    public static let compact: WriteConfig
    public static let pretty: WriteConfig
}

功能:用于表示 JsonWriter 的序列化格式配置。

示例:

使用示例见 WriteConfig 使用示例

static let compact

public static let compact: WriteConfig

功能:提供紧凑的序列化格式。

说明:

compact 的各属性值为:

  • newline: "",空字符串。
  • indent: "",空字符串。
  • useSpaceAfterSeparators: false。
  • htmlSafe: false。
  • dateTimeFormat: DateTimeFormat.RFC3339。

类型:WriteConfig

示例:

{"Name":"zhangsan","Age":18,"Scores":[88.8,99.9],"Class":{"Name":"Class A","Students Number":33}}

static let pretty

public static let pretty: WriteConfig

功能:提供整洁的序列化格式。

说明:

pretty 的各属性值为:

  • newline: "\n"。
  • indent: "    ",包含4个空格的字符串。
  • useSpaceAfterSeparators: true。
  • htmlSafe: false。
  • dateTimeFormat: DateTimeFormat.RFC3339。

类型:WriteConfig

示例:

{
    "Name": "zhangsan",
    "Age": 18,
    "Scores": [
        88.8,
        99.9
    ],
    "Class": {
        "Name": "Class A",
        "Students Number": 33
    }
}

prop dateTimeFormat

public mut prop dateTimeFormat: String

功能:用于序列化 DateTime 类型时的格式控制,功能与 DateTime 的 func toString(DateTimeFormat) 一致。

类型:String

prop htmlSafe

public mut prop htmlSafe: Bool

功能:用于表示是否转义 HTML 字符 <>&='

该值为 true 时,会将 HTML 字符转义为对应的 Unicode 编码的字符串。

该选项只对 json value 中的字符串字面量有效。

类型:Bool

prop indent

public mut prop indent: String

功能:用于表示序列化时每个缩进级别填入的缩进字符串。取值应匹配正则 ^[ \t]*$

当上述的换行起作用时,该值会作为换行后的填充符。

类型:String

异常:

  • IllegalArgumentException - 设置的字符串包含 ' ' 或者 '\t' 以外的字符。

prop newline

public mut prop newline: String

功能:用于表示序列化时填入的换行符。取值应匹配正则 ^[\r\n]*$

当该值不为空字符串且合法时,JsonWriter 调用 startObject 和 startArray 操作、插入元素、以及它们的结束操作会产生新的换行。

当该值为空字符串时,不会触发换行。

类型:String

异常:

  • IllegalArgumentException - 设置的字符串包含 '\r' 或者 '\n' 以外的字符。

prop useSpaceAfterSeparators

public mut prop useSpaceAfterSeparators: Bool

功能:用于表示序列化时在 ':' 和 ',' 后是否加一个空格。

该值为 true 时,每插入一个 field name 或者 array 元素后会自动写入一个空格。

该选项只对 json Object 中的 field 以及 json Array 中的元素有效。

类型:Bool

使用 Json Stream 进行反序列化

示例:

import stdx.encoding.json.stream.*
import std.io.*
import std.collection.*

class A <: JsonDeserializable<A> {
    var key1: Option<String> = None
    var key2: Bool = false
    var key3: Float64 = 0.0
    var key4: String = ""
    var key5: Array<Int64> = Array<Int64>()
    var key6: HashMap<String, String> = HashMap<String, String>()

    public static func fromJson(r: JsonReader): A {
        var res = A()
        while (let Some(v) <- r.peek()) {
            match (v) {
                case BeginObject =>
                    r.startObject()
                    while (r.peek() != EndObject) {
                        let n = r.readName()
                        match (n) {
                            case "key1" => res.key1 = r.readValue<Option<String>>()
                            case "key2" => res.key2 = r.readValue<Bool>()
                            case "key3" => res.key3 = r.readValue<Float64>()
                            case "key4" => res.key4 = r.readValue<String>()
                            case "key5" => res.key5 = r.readValue<Array<Int64>>()
                            case "key6" => res.key6 = r.readValue<HashMap<String, String>>()
                            case _ => ()
                        }
                    }
                    r.endObject()
                    break
                case _ => throw Exception()
            }
        }
        return res
    }

    func toString(): String {
        return "${key1}\n${key2}\n${key3}\n${key4}\n${key5}\n${key6}"
    }
}

main() {
    let jsonStr = ##"{"key1": null, "key2": true, "key3": 123.456, "key4": "string", "key5": [123, 456], "key6": {"key7": " ", "key8": "\\a"}}"##
    var bas = ByteBuffer()
    unsafe { bas.write(jsonStr.rawData()) }
    var reader = JsonReader(bas)
    var obj = A.fromJson(reader)
    println(obj.toString())
}

运行结果:

None
true
123.456000
string
[123, 456]
[(key7,  ), (key8, \a)]

使用 Json Stream 进行序列化

示例:

import stdx.encoding.json.stream.*
import std.io.{ByteBuffer, readToEnd}

class Image <: JsonSerializable {
    var width: Int64
    var height: Int64
    var title: String
    var ids: Array<Int64>

    public init() {
        width = 0
        height = 0
        title = ""
        ids = Array<Int64>()
    }

    public func toJson(w: JsonWriter): Unit {
        w.startObject()
        w.writeName("Width").writeValue(width)
        w.writeName("Height").writeValue(height)
        w.writeName("Title").writeValue(title)
        w.writeName("Ids").writeValue<Array<Int64>>(ids)
        w.endObject()
    }
}

main() {
    let image = Image()
    image.width = 800
    image.height = 600
    image.title = "View from 15th Floor"
    image.ids = [116, 943, 234, 38793]

    let stream = ByteBuffer()
    let writer = JsonWriter(stream)

    /* 将图片序列化 */
    writer.writeValue(image)
    writer.flush()
    println(String.fromUtf8(readToEnd(stream)))
}

运行结果:

{"Width":800,"Height":600,"Title":"View from 15th Floor","Ids":[116,943,234,38793]}

WriteConfig 使用示例

示例:

import stdx.encoding.json.stream.{JsonWriter, WriteConfig, JsonSerializable}
import std.io.ByteBuffer

main() {
    /* 构造 JsonWriter */
    let buffer = ByteBuffer()
    let writer = JsonWriter(buffer)

    /* 设置 JSON 写格式配置 */
    let fmtCfg = WriteConfig.pretty
    writer.writeConfig = fmtCfg

    /* 写 JSON  */
    writer.writeValue(MyObj())

    /* 打印 JSON 序列化字符串 */
    println(String.fromUtf8(buffer.bytes()))
}

class MyObj <: JsonSerializable {
    public func toJson(w: JsonWriter): Unit {
        w.startObject()
        w.writeName("Name").writeValue("zhangsan")
        w.writeName("Age").writeValue(18)
        w.writeName("Scores").writeValue([88.8, 99.9])
        w.writeName("Class")
        w.startObject()
        w.writeName("Name").writeValue("Class A")
        w.writeName("Students Number").writeValue(33)
        w.endObject()
        w.endObject()
        w.flush()
    }
}

运行结果:

{
    "Name": "zhangsan",
    "Age": 18,
    "Scores": [
        88.8,
        99.9
    ],
    "Class": {
        "Name": "Class A",
        "Students Number": 33
    }
}

stdx.encoding.url

功能介绍

url 包提供了 URL 相关的能力,包括解析 URL 的各个组件,对 URL 进行编解码,合并 URL 或路径等。

URL(Uniform Resource Locator)是统一资源定位符的缩写,它是用来标识互联网上资源位置的一种地址。通常包含协议、主机名、路径和查询参数等信息,其中协议是指访问资源所使用的协议(如 HTTP、FTP 等),主机名是指资源所在的服务器的域名或 IP 地址,路径是指资源所在的具体位置,查询参数是指用于传递参数的字符串。URL 是互联网上标识资源的唯一方式,通过 URL 可以访问网页、图片、视频等各种类型的资源。

URL 一般是以下格式:

scheme://host[:port]/path[?query][#fragment]

其中:

  • scheme:协议,例如 httphttpsftp 等;
  • host:主机名或 IP 地址;
  • port:端口号,可选,默认为协议默认端口;
  • path:资源路径,例如 /index.html/blog/post/123 等;
  • query:查询参数,例如 ?page=2&sort=desc 等,可选;
  • fragment:文档片段标识符,例如 #section-1,可选。

例如,网址 https://www.example.com/blog/post/123?page=2&sort=desc#section-1 的 URL 格式为:

  • scheme: https
  • host: www.example.com
  • path: /blog/post/123
  • query: ?page=2&sort=desc
  • fragment: #section-1

URL 编码的原因和基本过程:

URL 编码是将 URL 中的非 ASCII 字符转换为一种可读性更好的 ASCII 字符的过程。这是因为 URL 中只允许包含 ASCII 字符,而非 ASCII 字符可能会导致 URL 解析错误或传输失败。

URL 编码的基本过程如下:

  1. 将 URL 字符串转换为字节数组。
  2. 对于每个非 ASCII 字符,将其转换为 UTF-8 编码的字节序列。
  3. 对于每个字节,将其转换为两个十六进制数字。
  4. 在每个十六进制数字前添加一个百分号(%)。
  5. 将所有编码后的字符连接起来形成编码后的 URL 字符串。

例如,将字符串“你好,世界!”进行 URL 编码,结果为“%E4%BD%A0%E5%A5%BD%EF%BC%8C%E4%B8%96%E7%95%8C%EF%BC%81”。

API 列表

类名功能
FormForm 以 key-value 键值对形式存储 http 请求的参数,同一个 key 可以对应多个 value,value 以数组形式存储。
URL该类提供解析 URL 的函数以及其他相关函数。
UserInfoUserInfo 表示 URL 中用户名和密码信息。

异常类

异常类名功能
UrlSyntaxExceptionurl 解析异常类。

class Form

public class Form {
    public init()
    public init(queryComponent: String)
}

功能:Form 以 key-value 键值对形式存储 http 请求的表单信息,通常为请求 URL 中的 query 部分。

同一个 key 可以对应多个 value,value 以数组形式存储。& 符号分隔多个键值对;= 分隔的左侧作为 key 值,右侧作为 value 值(没有 = 或者 value 为空,均是允许的)。使用示例见 Form 的构造使用

init()

public init()

功能:构造一个默认的 Form 实例。

init(String)

public init(queryComponent: String)

功能:根据 URL 编码的查询字符串,即 URL 实例的 query 部分构造 Form 实例。

解析 URL 编码的查询字符串,得到若干键值对,并将其添加到新构造的 Form 实例中。

参数:

  • queryComponent: String - URL 的 query 组件部分的字符串,但是不包括组件前面的 ? 符号。

异常:

  • IllegalArgumentException - 当URL 字符串中包含不符合 utf8 编码规则的字节时,抛出异常。
  • UrlSyntaxException - 当 URL 字符串中包含非法转义字符时,抛出异常。

func add(String, String)

public func add(key: String, value: String): Unit

功能:新增 key-value 映射,如果 key 已存在,则将 value 添加到原来 value 数组的最后面。

参数:

  • key: String - 指定键,可以是新增的。
  • value: String - 将该值添加到指定键对应的值数组中。

func clone()

public func clone(): Form

功能:克隆 Form

返回值:

  • Form - 克隆得到的新 Form 实例。

func get(String)

public func get(key: String): Option<String>

功能:根据 key 获取第一个对应的 value 值。

举例:

  • 当 query 组件部分是 a=b 时,form.get("a")获得 Some(b)
  • 当 query 组件部分是 a= 时,form.get("a")获得 Some()
  • 当 query 组件部分是 a 时,form.get("a")获得 Some()
  • 当 query 组件部分是 a 时,form.get("c")获得 None

参数:

  • key: String - 指定键。

返回值:

  • Option<String> - 根据指定键获取的第一个值,用 Option<String> 类型表示。

func getAll(String)

public func getAll(key: String): ArrayList<String>

功能:根据指定的键(key)获取该键(key)对应的所有 value 值。

参数:

  • key: String - 用户指定的键(key),用于获取对应的 value 值。

返回值:

  • ArrayList<String> - 根据指定键(key)获取的全部 value 值对应的数组。当指定键(key)不存在时,返回空数组。

func isEmpty()

public func isEmpty(): Bool

功能:判断 Form 是否为空。

返回值:

  • Bool - 如果为空,则返回 true;否则,返回 false。

func remove(String)

public func remove(key: String): Unit

功能:删除 key 及其对应 value。

参数:

  • key: String - 需要删除的键。

func set(String, String)

public func set(key: String, value: String): Unit

功能:重置指定 key 对应的 value。

参数:

  • key: String - 指定键。
  • value: String - 将指定键的值设置为 value。

func toEncodeString()

public func toEncodeString(): String

功能:对表单中的键值对进行编码,编码采用百分号编码。

未保留字符不会被编码,空格将编码为 '+'。

说明:

RFC 3986 协议中对未保留字符定义如下: unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"

返回值:

  • String - 编码后的字符串。

class URL

public class URL <: ToString {
    public init(scheme!: String, hostName!: String, path!: String)
}

功能:该类提供解析 URL 的函数以及其他相关函数。

字符串中被百分号%编码的内容会被解码,保存在相应的组件之中,而初始值保存在相应的 raw 属性之中。URL 中的用户名和密码部分(如果存在的话)也会按照 RFC 3986 协议的说明被解析。

注意:

RFC 3986 明确说明在任何场景下,明文保存用户信息存在被泄露风险,所以建议不要在 URL 中明文保存用户信息。

父类型:

  • ToString

prop fragment

public prop fragment: ?String

功能:获取解码后的锚点组件,用字符串表示。

类型:?String

prop host

public prop host: String

功能:获取解码后的主机名和端口部分,用字符串表示。

类型:String

prop hostName

public prop hostName: String

功能:获取解码后的主机名,用字符串表示。

类型:String

prop opaque

public prop opaque: String

功能:获取 URL 中未被解析的部分,用字符串表示。

类型:String

示例:

import stdx.encoding.url.*

main () {
    let url = URL.parse("https:\\\\/example.com/foo/bar") // '\' 不是协议规定的分割符,无法被解析。
    println("url.scheme=${url.scheme}")
    println("url.host=${url.host}")
    println("url.opaque=${url.opaque}")
}

运行结果:

url.scheme=https
url.host=
url.opaque=\\/example.com/foo/bar

prop path

public prop path: String

功能:获取解码后的路径,用字符串表示。

类型:String

prop port

public prop port: String

功能:获取端口号,用字符串表示,空字符串表示无端口号。

类型:String

prop query

public prop query: ?String

功能:获取解码后的查询组件,用字符串表示。

类型:?String

prop queryForm

public prop queryForm: Form

功能:获取解码后的查询组件,用 Form 实例表示。

类型:Form

prop rawFragment

public prop rawFragment: ?String

功能:获取解码前的锚点组件,用字符串表示。

类型:?String

prop rawPath

public prop rawPath: String

功能:获取解码前的路径,用字符串表示。

类型:String

prop rawQuery

public prop rawQuery: ?String

功能:获取解码前的查询组件,用字符串表示。

类型:?String

prop rawUserInfo

public prop rawUserInfo: UserInfo

功能:获取解码前的用户名和密码信息,用 UserInfo 实例表示。

类型:UserInfo

prop scheme

public prop scheme: String

功能:获取 URL 中协议部分,用字符串表示。

类型:String

prop userInfo

public prop userInfo: UserInfo

功能:获取解码后的用户名和密码信息,用 UserInfo 实例表示。

类型:UserInfo

init(String, String, String)

public init(scheme!: String, hostName!: String, path!: String)

功能:构造一个 URL 实例。

构造实例时需要满足要求:

  • 拥有主机名 hostName 时,需要有协议 scheme。
  • 不能只存在协议 scheme。
  • 存在协议和路径的情况下,路径 path 必须是绝对路径。

参数:

  • scheme!: String - 协议类型。
  • hostName!: String - 不包含端口号的主机名。
  • path!: String - 请求资源的路径。

异常:

static func mergePaths(String, String)

public static func mergePaths(basePath: String, refPath: String): String

功能:合并两个路径。

合并规则:将引用路径 refPath 追加到基础路径 basePath 的最后一段。如果 refPath 是绝对路径,结果就是 refPath 原本的值。如果 refPath 不是绝对路径,则将自身拼接至 basePath 最后一个 / 后,所有结果最终都会进行标准化(路径中的.字符,..字符,以及多个连续的 / 字符都会被优化)。具体行为可以参照下面示例。更详细行为参考 RFC 3986 协议。

如需合并 URL 请使用 resolveURL

例如:

  • /a/b/c 合并 /d 输出 /d
  • /a/b/c 合并 d 输出 /a/b/d
  • /a/b/ 合并 d/e/../f 输出 /a/b/d/f
  • /a/b/c/ 合并 ./../../g 输出 /a/g

参数:

  • basePath: String - 基础路径。
  • refPath: String - 引用路径。

返回值:

  • String - 合并且标准化后的路径。

static func parse(String)

public static func parse(rawUrl: String): URL

功能:将原始 URL 字符串解析成 URL 对象。

这个函数会将 URL 按照组件分解,然后分别进行解码并存储在相应的组件属性中,而 rawXXX (此处泛指前缀是 raw 的 URL 属性)属性部分存储的是原始值,不做编解码处理。

使用示例请参见URL 解析函数 parse 的使用

注意:

该函数可以解析 URL 中的用户名和密码(如果存在),这是符合 RFC 3986 协议的解析功能的,但是 RFC 3986 也明确指出,任何场景下,明文保存用户信息存在被泄露风险,所以建议不要在 URL 中明文保存用户信息。

参数:

  • rawUrl: String - URL 字符串。

返回值:

  • URL - 解析字符串得到的 URL 实例。

异常:

  • UrlSyntaxException - 当 URL 字符串中包含非法字符时,抛出异常。
  • IllegalArgumentException - 当被编码的字符不符合 UTF-8 的字节序列规则时,抛出异常。

func isAbsoluteURL()

public func isAbsoluteURL(): Bool

功能:判断 URL 是否为绝对 URL(scheme 存在时,URL 是绝对 URL)。

返回值:

  • Bool - scheme 存在时返回 true,不存在时返回 false。

func replace(Option<String>, Option<String>, Option<String>, Option<String>, Option<String>, Option<String>, Option<String>)

public func replace(scheme!: Option<String> = None, userInfo!: Option<String> = None,
 hostName!: Option<String> = None, port!: Option<String> = None, path!: Option<String> = None, 
 query!: Option<String> = None, fragment!: Option<String> = None): URL

功能:替换 URL 对象的各组件,并且返回一个新的 URL 对象。

替换时需要满足以下要求:

  • 方案 scheme 为空时,主机名必须为空。
  • 主机名为空时,用户信息或端口号必须为空。
  • 方案 scheme 不为空时,主机名和路径不能同时为空。
  • 方案 scheme 不为空时,路径必须是绝对路径。
  • 任意组件均为合法字符。

参数:

  • scheme!: Option<String> - 协议组件。
  • userInfo!: Option<String> - 用户信息。
  • hostName!: Option<String> - 主机名。
  • port!: Option<String> - 端口号。
  • path!: Option<String> - 资源路径。
  • query!: Option<String> - 查询组件。
  • fragment!: Option<String> - 锚点组件。

返回值:

异常:

func resolveURL(URL)

public func resolveURL(ref: URL): URL

功能:以当前 URL 实例为基础 URL,以传入的 URL 为参考 URL,根据 RFC 3986 协议生成一个新的 URL 实例。

例如:http://a/b/c/d;p?q 为基础 URL,以下 = 左边为参考 URL,右边为生成的新 URL

更多详细的 URL 生成规则,请参见 RFC 3968 协议。

参数:

  • ref: URL - 参考 URL 对象。

返回值:

func toString()

public func toString(): String

功能:获取当前 URL 实例的字符串值。

会把 hostName 编码,其余部分取 rawXXX (此处泛指前缀是 raw 的 URL 属性)属性值,按照 URL 组件构成顺序进行拼接而获得该函数返回值。

返回值:

  • String - 当前 URL 实例的字符串值。

class UserInfo

public class UserInfo <: ToString {
    public init()
    public init(userName: String)
    public init(userName: String, passWord: String)
    public init(userName: String, passWord: Option<String>)
}

功能:UserInfo 表示 URL 中用户名和密码信息。

注意:

RFC 3986 明确指出,任何场景下,明文保存用户信息存在被泄露风险,所以建议不要在 URL 中明文保存用户信息。

父类型:

  • ToString

init()

public init()

功能:创建 UserInfo 实例。

init(String)

public init(userName: String)

功能:根据用户名创建 UserInfo 实例。

参数:

  • userName: String - 用户名。

init(String, Option<String>)

public init(userName: String, passWord: Option<String>)

功能:根据用户名和密码创建 UserInfo 实例。 参数:

  • userName: String - 用户名。
  • passWord: Option<String> - 密码,用 Option<String> 类型表示。

init(String, String)

public init(userName: String, passWord: String)

功能:根据用户名和密码创建 UserInfo 实例。 参数:

  • userName: String - 用户名。
  • passWord: String - 密码。

func password()

public func password(): Option<String>

功能:获取密码信息。

注意:

RFC 3986 明确指出,任何场景下,明文保存用户信息存在被泄露风险,所以建议不要在 URL 中明文保存用户信息。

返回值:

  • Option<String> - 将密码以 Option<String> 形式返回。

func toString()

public func toString(): String

功能:将当前 UserInfo 实例转换为字符串。

返回值:

  • String - 当前 UserInfo 实例的字符串表示。

func username()

public func username(): String

功能:获取用户名信息。

返回值:

  • String - 字符串类型的用户名。

异常类

class UrlSyntaxException

public class UrlSyntaxException <: Exception {
    public init(reason: String)
    public init(input: String, reason: String)
    public init(input: String, reason: String, pos: String)
}

功能:URL 解析异常类。

父类型:

  • Exception

init(String)

public init(reason: String)

功能:根据错误原因构造 UrlSyntaxException 实例。

参数:

  • reason: String - 解析错误的原因。

init(String, String)

public init(input: String, reason: String)

功能:根据 URL 及错误原因构造 UrlSyntaxException 实例。

参数:

  • input: String - 原生 URL 或其片段。
  • reason: String - 解析错误的原因。

init(String, String, String)

public init(input: String, reason: String, pos: String)

功能:根据 URL 字符串,错误原因以及解析失败的部分,构造 UrlSyntaxException 实例。

参数:

  • input: String - 原生 URL 或其片段。
  • reason: String - 解析错误的原因。
  • pos: String - 给定 URL 字符串中解析失败的部分。

Form 的构造使用

Form 的构造与其函数 get 的使用

创建 Form 类,并通过 get 获取 key 对应映射的 value。示例中使用 Form 类的函数 get 获取指定 key = 1 的 value 值 2 。

示例:

import stdx.encoding.url.*

main(): Int64 {
    var s = Form("1=2&2=3&1=2&&")
    print(s.get("1").getOrThrow())
    return 0
}

运行结果:

2

Form 的构造与重复 key 情况下函数 get 的使用

创建 Form 类,并通过 get 获取 key 对应映射的 value。示例中使用 Form 类的函数 get 获取指定 key = 1 的第一个 value 值 %6AD。value 中的 %6A 被解码为 j,因此得到 value 值 jD 。

示例:

import stdx.encoding.url.*

main(): Int64 {
    var s = Form("2=3&1=%6AD&1=2")
    /* 对于 %6A 解码成 j,重复的 key 调用 get 获取第一个 value 值 jD */
    print(s.get("1").getOrThrow())
    return 0
}

运行结果如下:

jD

Form 的构造与其他函数使用

分别调用 add,set,clone,打印输出前后变化。

示例:

import stdx.encoding.url.*

main(): Int64 {
    var f = Form()
    
    /* 给键 k 增加值 v1 和 v2 */
    f.add("k", "v1")
    f.add("k", "v2")

    /* 调用 get 方法时,获取的是第一个值 */
    println(f.get("k").getOrThrow())

    /* 设定键 k 的值为 v */
    f.set("k", "v")
    println(f.get("k").getOrThrow())
    let clone_f = f.clone()

    /* 给克隆出来的 clone_f 增加键值对 */
    clone_f.add("k1", "v1")

    /* 通过 get 获得值 v1 */
    println(clone_f.get("k1").getOrThrow())

    /* 原来的 f 并没有键 k1,所以值是给的默认值 kkk */
    println(f.get("k1") ?? "kkk")
    return 0
}

运行结果如下:

v1
v
v1
kkk

URL 解析函数 parse 的使用

使用 parse 函数解析 URL 字符串,生成 URL 对象。示例中对一个地址进行了解析并获得了 URL 对象,并且打印该对象的各个属性。

示例:

import stdx.encoding.url.*

main(): Int64 {
    /* 调用 URL 静态函数 parse 解析网址获得名为 url 的对象 */
    var url = URL.parse(
        "http://www.example.com:80/path%E4%BB%93%E9%A2%89?key=value%E4%BB%93%E9%A2%89#%E4%BD%A0%E5%A5%BD")

    /* 打印 url 的组件属性 */
    println("url.scheme = ${url.scheme}")
    println("url.opaque = ${url.opaque}")
    println("url.userInfo = ${url.userInfo}")
    println("url.rawUserInfo = ${url.rawUserInfo}")
    println("url.host = ${url.host}")
    println("url.hostName = ${url.hostName}")
    println("url.port = ${url.port}")
    println("url.path = ${url.path}")
    println("url.rawPath = ${url.rawPath}")
    println("url.query = ${url.query.getOrThrow()}")
    println("url.rawQuery = ${url.rawQuery.getOrThrow()}")
    println("url.fragment = ${url.fragment.getOrThrow()}")
    println("url.rawfragment = ${url.rawFragment.getOrThrow()}")
    println("url = ${url}")
    return 0
}

运行结果:

url.scheme = http
url.opaque =
url.userInfo =
url.rawUserInfo =
url.host = www.example.com:80
url.hostName = www.example.com
url.port = 80
url.path = /path仓颉
url.rawPath = /path%E4%BB%93%E9%A2%89
url.query = key=value仓颉
url.rawQuery = key=value%E4%BB%93%E9%A2%89
url.fragment = 你好
url.rawfragment = %E4%BD%A0%E5%A5%BD
url = http://www.example.com:80/path%E4%BB%93%E9%A2%89?key=value%E4%BB%93%E9%A2%89#%E4%BD%A0%E5%A5%BD

stdx.fuzz.fuzz

功能介绍

Fuzz 技术是一种自动化软件测试方法,旨在发现软件中的漏洞和错误。它通过持续输入随机的或经过变异的测试用例来执行软件程序,并根据程序的覆盖率信息来指导测试的方向。

fuzz 包为开发者提供基于覆盖率反馈的仓颉 fuzz 引擎及对应的接口,开发者可以编写代码对 API 进行测试。当前支持通过传入 fuzz 引擎变异的字节流 (Array<UInt8>) 或符合仓颉的标准数据类型(FuzzDataProvider)进行 fuzz 测试。

使用此包需要配合覆盖率反馈插桩(SanitizerCoverage)功能使用,需要开发者对 fuzz 测试有一定的了解,初学者建议先学习 C 语言的 Fuzz 工具 libFuzzer

使用本包需要外部依赖 LLVM 套件 compiler-rt 提供的 libclang_rt.fuzzer_no_main.a 静态库,当前支持 Linux 以及 macOS,不支持 Windows。

通常使用包管理工具即可完成安装,例如 Ubuntu 22.04 系统上可使用 sudo apt install clang 进行安装,安装后可以在 clang -print-runtime-dir 指向的目录下找到对应的 libclang_rt.fuzzer_no_main.a 文件,例如 /usr/lib/llvm-14/lib/clang/14.0.0/lib/linux/libclang_rt.fuzzer_no_main-x86_64.a,将来在链接时会用到它。

API 列表

类名功能
FuzzerFuzzer 类提供了 fuzz 工具的创建。
FuzzerBuilder此类用于 Fuzzer 类的构建。
FuzzDataProviderFuzzDataProvider 是一个工具类,目的是将变异数据的字节流转化为标准的仓颉基本数据。
DebugDataProvider此类继承了 FuzzDataProvider 类型,额外增加了调试信息。

异常类

异常类名功能
ExhaustedException此异常为转换数据时,剩余数据不足以转换时抛出的异常。

常量&变量

let FUZZ_VERSION

public let FUZZ_VERSION = "1.0.0"

功能:Fuzz 版本。

类型:String

class DebugDataProvider

public class DebugDataProvider <: FuzzDataProvider

功能:此类继承了 FuzzDataProvider 类型,额外增加了调试信息。

父类型:

func consumeAll()

public override func consumeAll(): Array<UInt8>

功能:将所有数据转换成 UInt8 类型数组。

返回值:

  • Array<UInt8> - UInt8 类型数组。

func consumeAllAsAscii()

public override func consumeAllAsAscii(): String

功能:将所有数据转换成 Ascii String 类型。

返回值:

  • String - Ascii String 类型实例。

func consumeAllAsString()

public override func consumeAllAsString(): String

功能:将所有数据转换成 utf8 String 类型。

返回值:

  • String - utf8 String 类型实例。

func consumeAsciiString(Int64)

public override func consumeAsciiString(maxLength: Int64): String

功能:将数据转换成 Ascii String 类型实例。

参数:

  • maxLength: Int64 - String 类型的最大长度。

返回值:

  • String - String 类型实例。

异常:

  • IllegalArgumentException - 如果 maxLength 为负数,则抛出异常。

func consumeBool()

public override func consumeBool(): Bool

功能:将数据转换成 Bool 类型实例。

返回值:

  • Bool - Bool 类型实例。

func consumeBools(Int64)

public override func consumeBools(count: Int64): Array<Bool>

功能:将指定数量的数据转换成 Bool 类型数组。

参数:

  • count: Int64 - 指定转换的数据量。

返回值:

  • Array<Bool> - Bool 类型数组。

异常:

  • IllegalArgumentException - 如果 count 为负数,则抛出异常。

func consumeByte()

public override func consumeByte(): Byte

功能:将数据转换成 Byte 类型实例。

返回值:

  • Byte - Byte 类型实例。

func consumeBytes(Int64)

public override func consumeBytes(count: Int64): Array<Byte>

功能:将指定数量的数据转换成 Byte 类型数组。

参数:

  • count: Int64 - 指定转换的数据量。

返回值:

  • Array<Byte> - Byte 类型数组。

异常:

  • IllegalArgumentException - 如果 count 为负数,则抛出异常。

func consumeFloat32()

public override func consumeFloat32(): Float32

功能:将数据转换成 Float32 类型实例。

返回值:

  • Float32 - Float32 类型实例。

func consumeFloat64()

public override func consumeFloat64(): Float64

功能:将数据转换成 Float64 类型实例。

返回值:

  • Float64 - Float64 类型实例。

func consumeInt16()

public override func consumeInt16(): Int16

功能:将数据转换成 Int16 类型实例。

返回值:

  • Int16 - Int16 类型实例。

func consumeInt16s(Int64)

public override func consumeInt16s(count: Int64): Array<Int16>

功能:将指定数量的数据转换成 Int16 类型数组。

参数:

  • count: Int64 - 指定转换的数据量。

返回值:

  • Array<Int16> - Int16 类型数组。

异常:

  • IllegalArgumentException - 如果 count 为负数,则抛出异常。

func consumeInt32()

public override func consumeInt32(): Int32

功能:将数据转换成 Int32 类型实例。

返回值:

  • Int32 - Int32 类型实例。

func consumeInt32s(Int64)

public override func consumeInt32s(count: Int64): Array<Int32>

功能:将指定数量的数据转换成 Int32 类型数组。

参数:

  • count: Int64 - 指定转换的数据量。

返回值:

  • Array<Int32> - Int32 类型数组。

异常:

  • IllegalArgumentException - 如果 count 为负数,则抛出异常。

func consumeInt64()

public override func consumeInt64(): Int64

功能:将数据转换成 Int64 类型实例。

返回值:

  • Int64 - Int64 类型实例。

func consumeInt64s(Int64)

public override func consumeInt64s(count: Int64): Array<Int64>

功能:将指定数量的数据转换成 Int64 类型数组。

参数:

  • count: Int64 - 指定转换的数据量。

返回值:

  • Array<Int64> - Int64 类型数组。

异常:

  • IllegalArgumentException - 如果 count 为负数,则抛出异常。

func consumeInt8()

public override func consumeInt8(): Int8

功能:将数据转换成 Int8 类型实例。

返回值:

  • Int8 - Int8 类型实例。

func consumeInt8s(Int64)

public override func consumeInt8s(count: Int64): Array<Int8>

功能:将指定数量的数据转换成 Int8 类型数组。

参数:

  • count: Int64 - 指定转换的数据量。

返回值:

  • Array<Int8> - Int8 类型数组。

异常:

  • IllegalArgumentException - 如果 count 为负数,则抛出异常。

func consumeRune()

public override func consumeRune(): Rune

功能:将数据转换成 Rune 类型实例。

返回值:

  • Rune - Rune 类型实例。

func consumeString(Int64)

public override func consumeString(maxLength: Int64): String

功能:将数据转换成 utf8 String 类型实例。

参数:

  • maxLength: Int64 - String 类型的最大长度。

返回值:

  • String - String 类型实例。

异常:

  • IllegalArgumentException - 如果 maxLength 为负数,则抛出异常。

func consumeUInt16()

public override func consumeUInt16(): UInt16

功能:将数据转换成 UInt16 类型实例。

返回值:

  • UInt16 - UInt16 类型实例。

func consumeUInt16s(Int64)

public override func consumeUInt16s(count: Int64): Array<UInt16>

功能:将指定数量的数据转换成 UInt16 类型数组。

参数:

  • count: Int64 - 指定转换的数据量。

返回值:

  • Array<UInt16> - UInt16 类型数组。

异常:

  • IllegalArgumentException - 如果 count 为负数,则抛出异常。

func consumeUInt32()

public override func consumeUInt32(): UInt32

功能:将数据转换成 UInt32 类型实例。

返回值:

  • UInt32 - UInt32 类型实例。

func consumeUInt32s(Int64)

public override func consumeUInt32s(count: Int64): Array<UInt32>

功能:将指定数量的数据转换成 UInt32 类型数组。

参数:

  • count: Int64 - 指定转换的数据量。

返回值:

  • Array<UInt32> - UInt32 类型数组。

异常:

  • IllegalArgumentException - 如果 count 为负数,则抛出异常。

func consumeUInt64()

public override func consumeUInt64(): UInt64

功能:将数据转换成 UInt64 类型实例。

返回值:

  • UInt64 - UInt64 类型实例。

func consumeUInt64s(Int64)

public override func consumeUInt64s(count: Int64): Array<UInt64>

功能:将指定数量的数据转换成 UInt64 类型数组。

参数:

  • count: Int64 - 指定转换的数据量。

返回值:

  • Array<UInt64> - UInt64 类型数组。

异常:

  • IllegalArgumentException - 如果 count 为负数,则抛出异常。

func consumeUInt8()

public override func consumeUInt8(): UInt8

功能:将数据转换成 UInt8 类型实例。

返回值:

  • UInt8 - UInt8 类型实例。

func consumeUInt8s(Int64)

public override func consumeUInt8s(count: Int64): Array<UInt8>

功能:将指定数量的数据转换成 UInt8 类型数组。

参数:

  • count: Int64 - 指定转换的数据量。

返回值:

  • Array<UInt8> - UInt8 类型数组。

异常:

  • IllegalArgumentException - 如果 count 为负数,则抛出异常。

func wrap(FuzzDataProvider)

public static func wrap(dp: FuzzDataProvider): DebugDataProvider

功能:根据 FuzzDataProvider 实例创建 DebugDataProvider 实例。

参数:

返回值:

class Fuzzer

public class Fuzzer {
    public init(targetFunction: (Array<UInt8>) -> Int32)
    public init(targetFunction: (Array<UInt8>) -> Int32, args: Array<String>)
    public init(targetFunction: (FuzzDataProvider) -> Int32)
    public init(targetFunction: (FuzzDataProvider) -> Int32, args: Array<String>)
}

功能:Fuzzer 类提供了 fuzz 工具的创建。用户提供需要进行 fuzz 测试的函数 targetFunction,以及设置特定的 fuzz 运行参数 args 比如 fuzz 执行次数、初始种子、生成数据最大长度等,可创建相应类型的 Fuzzer

init((Array<UInt8>) -> Int32)

public init(targetFunction: (Array<UInt8>) -> Int32)

功能:根据以 UInt8 数组为参数,以 Int32 为返回值的目标函数,创建 Fuzzer 实例。

参数:

  • targetFunction: (Array<UInt8>) ->Int32 - 以 UInt8 数组为参数,以 Int32 为返回值的目标函数。

init((Array<UInt8>) -> Int32, Array<String>)

public init(targetFunction: (Array<UInt8>) -> Int32, args: Array<String>)

功能:根据以 UInt8 数组为参数,以 Int32 为返回值的目标函数,以及 Fuzz 运行参数,创建 Fuzzer 实例。

参数:

  • targetFunction: (Array<UInt8>) ->Int32 - 以 UInt8 数组为参数,以 Int32 为返回值的目标函数。
  • args: Array<String> - Fuzz 运行参数。

init((FuzzDataProvider) -> Int32)

public init(targetFunction: (FuzzDataProvider) -> Int32)

功能:根据以 FuzzDataProvider 为参数,以 Int32 为返回值的目标函数,创建 Fuzzer 实例。

参数:

init((FuzzDataProvider) -> Int32, Array<String>)

public init(targetFunction: (FuzzDataProvider) -> Int32, args: Array<String>)

功能:根据以 FuzzDataProvider 为参数,以 Int32 为返回值的目标函数,以及 Fuzz 运行参数,创建 Fuzzer 实例。

参数:

  • targetFunction: (FuzzDataProvider) ->Int32 - 以 FuzzDataProvider 为参数,以 Int32 为返回值的目标函数。
  • args: Array<String> - Fuzz 运行参数。

func disableDebugDataProvider()

public func disableDebugDataProvider(): Unit

功能:关闭调试信息打印功能,当 FuzzDataProvider.consumeXXX 被调用时,返回值将不被打印到 stdout

func disableFakeCoverage()

public func disableFakeCoverage(): Unit

功能:关闭调用 enableFakeCoverage 对 Fuzz 的影响。

func enableDebugDataProvider()

public func enableDebugDataProvider(): Unit

功能:启用调试信息打印功能,当 FuzzDataProvider.consumeXXX 被调用时,返回值将被打印到 stdout。该功能默认为关闭。

func enableFakeCoverage()

public func enableFakeCoverage(): Unit

功能:创建一块虚假的覆盖率反馈区域,保持 Fuzz 持续进行。在 FuzzDataProvider 模式下,前几轮运行时可能由于数据不足而导致没有覆盖率,libfuzzer 会退出。该功能默认为关闭。

func getArgs()

public func getArgs(): Array<String>

功能:获取 Fuzz 运行参数。

返回值:

  • Array<String> - 当前 Fuzz 运行参数。

func setArgs(Array<String>)

public func setArgs(args: Array<String>): Unit

功能:设置 Fuzz 运行参数。

参数:

  • args: Array<String> - Fuzz 运行参数。

func setTargetFunction((Array<UInt8>) -> Int32)

public func setTargetFunction(targetFunction: (Array<UInt8>) -> Int32): Unit

功能:设置 Fuzz 目标函数。

参数:

  • targetFunction: (Array<UInt8>) ->Int32 - 以 UInt8 数组为参数,以 Int32 为返回值的目标函数。

func setTargetFunction((FuzzDataProvider) -> Int32)

public func setTargetFunction(targetFunction: (FuzzDataProvider) -> Int32): Unit

功能:设置 Fuzz 目标函数。

参数:

func startFuzz()

public func startFuzz(): Unit

功能:执行 Fuzz。

class FuzzerBuilder

public class FuzzerBuilder {
    public init(targetFunction: (Array<UInt8>) -> Int32)
    public init(targetFunction: (FuzzDataProvider) -> Int32)
}

功能:此类用于 Fuzzer 类的构建。

init((Array<UInt8>) -> Int32)

public init(targetFunction: (Array<UInt8>) -> Int32)

功能:根据以 UInt8 数组为参数,以 Int32 为返回值的目标函数,创建 FuzzerBuilder 实例。

参数:

  • targetFunction: (Array<UInt8>) ->Int32 - 以 UInt8 数组为参数,以 Int32 为返回值的目标函数。

init((FuzzDataProvider) -> Int32)

public init(targetFunction: (FuzzDataProvider) -> Int32)

功能:根据以 FuzzDataProvider 为参数,以 Int32 为返回值的目标函数,创建 FuzzerBuilder 实例。

参数:

func build()

public func build(): Fuzzer

功能:生成一个 Fuzzer 实例。

返回值:

func setArgs(Array<String>)

public func setArgs(args: Array<String>): FuzzerBuilder

功能:设置 Fuzz 运行参数。

参数:

  • args: Array<String> - Fuzz 运行参数。

返回值:

func setTargetFunction((Array<UInt8>) -> Int32)

public func setTargetFunction(targetFunction: (Array<UInt8>) -> Int32): FuzzerBuilder

功能:设置 Fuzz 目标函数。

参数:

  • targetFunction: (Array<UInt8>) ->Int32 - 以 UInt8 数组为参数,以 Int32 为返回值的目标函数。

返回值:

func setTargetFunction((FuzzDataProvider) -> Int32)

public func setTargetFunction(targetFunction: (FuzzDataProvider) -> Int32): FuzzerBuilder

功能:设置 Fuzz 目标函数。

参数:

返回值:

class FuzzDataProvider

public open class FuzzDataProvider {
    public let data: Array<UInt8>
    public var remainingBytes: Int64
    public var offset: Int64
}

功能:FuzzDataProvider 是一个工具类,目的是将变异数据的字节流转化为标准的仓颉基本数据。

当前支持的数据结构如下:

目标类型API说明
BoolconsumeBool()获取 1 个 Bool,变异数据长度不足时,抛出 ExhaustedException
Array<Bool>consumeBools(count: Int64)获取 N 个 Bool,变异数据长度不足时,抛出 ExhaustedException
ByteconsumeByte()获取 1 个 Byte,变异数据长度不足时,抛出 ExhaustedException
Array<Byte>consumeBytes(count: Int64)获取 N 个 Byte,变异数据长度不足时,抛出 ExhaustedException
UInt8consumeUInt8()获取 1 个 UInt8,变异数据长度不足时,抛出 ExhaustedException
UInt16consumeUInt16()获取 1 个 UInt16,变异数据长度不足时,抛出 ExhaustedException
UInt32consumeUInt32()获取 1 个 UInt32,变异数据长度不足时,抛出 ExhaustedException
UInt64consumeUInt64()获取 1 个 UInt64,变异数据长度不足时,抛出 ExhaustedException
Int8consumeInt8()获取 1 个 Int8,变异数据长度不足时,抛出 ExhaustedException
Int16consumeInt16()获取 1 个 Int16,变异数据长度不足时,抛出 ExhaustedException
Int32consumeInt32()获取 1 个 Int32,变异数据长度不足时,抛出 ExhaustedException
Int64consumeInt64()获取 1 个 Int64,变异数据长度不足时,抛出 ExhaustedException
Float32consumeFloat32()获取 1 个 Float32,变异数据长度不足时,抛出 ExhaustedException
Float64consumeFloat64()获取 1 个 Float64,变异数据长度不足时,抛出 ExhaustedException
Array<UInt8>consumeUInt8s(count: Int64)获取 N 个 UInt8,变异数据长度不足时,抛出 ExhaustedException
Array<UInt16>consumeUInt16s(count: Int64)获取 N 个 UInt16,变异数据长度不足时,抛出 ExhaustedException
Array<UInt32>consumeUInt32s(count: Int64)获取 N 个 UInt32,变异数据长度不足时,抛出 ExhaustedException
Array<UInt64>consumeUInt64s(count: Int64)获取 N 个 UInt64,变异数据长度不足时,抛出 ExhaustedException
Array<Int8>consumeInt8s(count: Int64)获取 N 个 Int8,变异数据长度不足时,抛出 ExhaustedException
Array<Int16>consumeInt16s(count: Int64)获取 N 个 Int16,变异数据长度不足时,抛出 ExhaustedException
Array<Int32>consumeInt32s(count: Int64)获取 N 个 Int32,变异数据长度不足时,抛出 ExhaustedException
Array<Int64>consumeInt64s(count: Int64)获取 N 个 Int64,变异数据长度不足时,抛出 ExhaustedException
RuneconsumeRune()获取 1 个 Rune,变异数据长度不足时,抛出 ExhaustedException
StringconsumeAsciiString(maxLength: Int64)获取 1 个纯 ASCII 的 String,长度为 0 到 maxLength,可以为 0。
StringconsumeString(maxLength: Int64)获取 1 个 UTF8 String,长度为 0 到 maxLength,可以为 0。
Array<UInt8>consumeAll()FuzzDataProvider 中的剩余内容全部转化为字节数组。
StringconsumeAllAsAscii()FuzzDataProvider 中的剩余内容全部转化为纯 ASCII 的 String。
StringconsumeAllAsString()FuzzDataProvider 中的剩余内容全部转化为 UTF8 String,末尾多余的字符不会被消耗。

在数据长度不足时,调用上述大部分虽然会抛出 ExhaustedException,但编写 fuzz 函数时通常并不需要对它进行处理,ExhaustedException 默认会被 fuzz 框架捕获,告诉 libfuzzer 该次运行无效,请继续下一轮变异。随着执行时间的变长,变异数据也会逐渐变长,直到满足 FuzzDataProvider 的需求。

如果达到了 max_len 仍无法满足 FuzzDataProvider 的需求,则进程退出,请修改 fuzz 测试用例(推荐) 或 增大 max_len(不推荐)。

let data

public let data: Array<UInt8>

功能:变异数据。

类型:Array<UInt8>

var offset

public var offset: Int64

功能:已转化的字节数。

类型:Int64

var remainingBytes

public var remainingBytes: Int64

功能:剩余字节数。

类型:Int64

func consumeAll()

public open func consumeAll(): Array<UInt8>

功能:将所有数据转换成 UInt8 类型数组。

返回值:

  • Array<UInt8> - UInt8 类型数组。

func consumeAllAsAscii()

public open func consumeAllAsAscii(): String

功能:将所有数据转换成 Ascii String 类型。

返回值:

  • String - Ascii String 类型实例。

func consumeAllAsString()

public open func consumeAllAsString(): String

功能:将所有数据转换成 utf8 String 类型。

返回值:

  • String - utf8 String 类型实例。

func consumeAsciiString(Int64)

public open func consumeAsciiString(maxLength: Int64): String

功能:将数据转换成 Ascii String 类型实例。

参数:

  • maxLength: Int64 - String 类型的最大长度。

返回值:

  • String - String 类型实例。

异常:

  • IllegalArgumentException - 如果 maxLength 为负数,则抛出异常。

func consumeBool()

public open func consumeBool(): Bool

功能:将数据转换成 Bool 类型实例。

返回值:

  • Bool - Bool 类型实例。

func consumeBools(Int64)

public open func consumeBools(count: Int64): Array<Bool>

功能:将指定数量的数据转换成 Bool 类型数组。

参数:

  • count: Int64 - 指定转换的数据量。

返回值:

  • Array<Bool> - Bool 类型数组。

异常:

  • IllegalArgumentException - 如果 count 为负数,则抛出异常。

func consumeByte()

public open func consumeByte(): Byte

功能:将数据转换成 Byte 类型实例。

返回值:

  • Byte - Byte 类型实例。

func consumeBytes(Int64)

public open func consumeBytes(count: Int64): Array<Byte>

功能:将指定数量的数据转换成 Byte 类型数组。

参数:

  • count: Int64 - 指定转换的数据量。

返回值:

  • Array<Byte> - Byte 类型数组。

异常:

  • IllegalArgumentException - 如果 count 为负数,则抛出异常。

func consumeFloat32()

public open func consumeFloat32(): Float32

功能:将数据转换成 Float32 类型实例。

返回值:

  • Float32 - Float32 类型实例。

func consumeFloat64()

public open func consumeFloat64(): Float64

功能:将数据转换成 Float64 类型实例。

返回值:

  • Float64 - Float64 类型实例。

func consumeInt16()

public open func consumeInt16(): Int16

功能:将数据转换成 Int16 类型实例。

返回值:

  • Int16 - Int16 类型实例。

异常:

  • IllegalArgumentException - 如果 count 为负数,则抛出异常。

func consumeInt16s(Int64)

public open func consumeInt16s(count: Int64): Array<Int16>

功能:将指定数量的数据转换成 Int16 类型数组。

参数:

  • count: Int64 - 指定转换的数据量。

返回值:

  • Array<Int16> - Int16 类型数组。

func consumeInt32()

public open func consumeInt32(): Int32

功能:将数据转换成 Int32 类型实例。

返回值:

  • Int32 - Int32 类型实例。

func consumeInt32s(Int64)

public open func consumeInt32s(count: Int64): Array<Int32>

功能:将指定数量的数据转换成 Int32 类型数组。

参数:

  • count: Int64 - 指定转换的数据量。

返回值:

  • Array<Int32> - Int32 类型数组。

异常:

  • IllegalArgumentException - 如果 count 为负数,则抛出异常。

func consumeInt64()

public open func consumeInt64(): Int64

功能:将数据转换成 Int64 类型实例。

返回值:

  • Int64 - Int64 类型实例。

func consumeInt64s(Int64)

public open func consumeInt64s(count: Int64): Array<Int64>

功能:将指定数量的数据转换成 Int64 类型数组。

参数:

  • count: Int64 - 指定转换的数据量。

返回值:

  • Array<Int64> - Int64 类型数组。

异常:

  • IllegalArgumentException - 如果 count 为负数,则抛出异常。

func consumeInt8()

public open func consumeInt8(): Int8

功能:将数据转换成 Int8 类型实例。

返回值:

  • Int8 - Int8 类型实例。

func consumeInt8s(Int64)

public open func consumeInt8s(count: Int64): Array<Int8>

功能:将指定数量的数据转换成 Int8 类型数组。

参数:

  • count: Int64 - 指定转换的数据量。

返回值:

  • Array<Int8> - Int8 类型数组。

异常:

  • IllegalArgumentException - 如果 count 为负数,则抛出异常。

func consumeRune()

public open func consumeRune(): Rune

功能:将数据转换成 Rune 类型实例。

返回值:

  • Rune - Rune 类型实例。

func consumeString(Int64)

public open func consumeString(maxLength: Int64): String

功能:将数据转换成 utf8 String 类型实例。

参数:

  • maxLength: Int64 - String 类型的最大长度。

返回值:

  • String - String 类型实例。

异常:

  • IllegalArgumentException - 如果 maxLength 为负数,则抛出异常。

func consumeUInt16()

public open func consumeUInt16(): UInt16

功能:将数据转换成 UInt16 类型实例。

返回值:

  • UInt16 - UInt16 类型实例。

func consumeUInt16s(Int64)

public open func consumeUInt16s(count: Int64): Array<UInt16>

功能:将指定数量的数据转换成 UInt16 类型数组。

参数:

  • count: Int64 - 指定转换的数据量。

返回值:

  • Array<UInt16> - UInt16 类型数组。

异常:

  • IllegalArgumentException - 如果 count 为负数,则抛出异常。

func consumeUInt32()

public open func consumeUInt32(): UInt32

功能:将数据转换成 UInt32 类型实例。

返回值:

  • UInt32 - UInt32 类型实例。

func consumeUInt32s(Int64)

public open func consumeUInt32s(count: Int64): Array<UInt32>

功能:将指定数量的数据转换成 UInt32 类型数组。

参数:

  • count: Int64 - 指定转换的数据量。

返回值:

  • Array<UInt32> - UInt32 类型数组。

异常:

  • IllegalArgumentException - 如果 count 为负数,则抛出异常。

func consumeUInt64()

public open func consumeUInt64(): UInt64

功能:将数据转换成 UInt64 类型实例。

返回值:

  • UInt64 - UInt64 类型实例。

func consumeUInt64s(Int64)

public open func consumeUInt64s(count: Int64): Array<UInt64>

功能:将指定数量的数据转换成 UInt64 类型数组。

参数:

  • count: Int64 - 指定转换的数据量。

返回值:

  • Array<UInt64> - UInt64 类型数组。

异常:

  • IllegalArgumentException - 如果 count 为负数,则抛出异常。

func consumeUInt8()

public open func consumeUInt8(): UInt8

功能:将数据转换成 UInt8 类型实例。

返回值:

  • UInt8 - UInt8 类型实例。

func consumeUInt8s(Int64)

public open func consumeUInt8s(count: Int64): Array<UInt8>

功能:将指定数量的数据转换成 UInt8 类型数组。

参数:

  • count: Int64 - 指定转换的数据量。

返回值:

  • Array<UInt8> - UInt8 类型数组。

异常:

  • IllegalArgumentException - 如果 count 为负数,则抛出异常。

static func withCangjieData(Array<UInt8>)

public static func withCangjieData(data: Array<UInt8>): FuzzDataProvider

功能:使用 Array<UInt8> 类型的数据生成 FuzzDataProvider 类型实例。

参数:

  • data: Array<UInt8> - 输入的外部数据。

返回值:

static func withNativeData(CPointer<UInt8>, Int64)

public static unsafe func withNativeData(data: CPointer<UInt8>, length: Int64): FuzzDataProvider

功能:使用 C 指针数据生成 FuzzDataProvider 类型实例。

参数:

  • data: CPointer<UInt8> - 输入的外部数据。
  • length: Int64 - 数据长度。

返回值:

异常类

class ExhaustedException

public class ExhaustedException <: Exception {
    public init()
    public init(message: String)
}

功能:此异常为转换数据时,剩余数据不足以转换时抛出的异常。

父类型:

  • Exception

init()

public init()

功能:创建 ExhaustedException 实例。

init(String)

public init(message: String)

功能:创建 ExhaustedException 实例。

参数:

  • message: String - 异常提示信息。

测试猜测字符功能

  • 编写被测 API,当且仅当输入数组长度是 8、内容是 "Cangjie!" 对应的 ASCII 时抛出异常,纯随机的情况下最差需要 264 次猜测才会触发异常。
  • 创建 Fuzzer 并且调用待测 API,进入主流程。
// 导入依赖的类
import stdx.fuzz.fuzz.Fuzzer

main() {
    // 创建Fuzzer并启动fuzz流程
    Fuzzer(api).startFuzz()
    return 0
}


// 被测函数,在满足特定条件会抛出异常,该异常会被 Fuzzer 捕获
public func api(data: Array<UInt8>): Int32 {
    if (data.size == 8 && data[0] == b'C' && data[1] == b'a' && data[2] == b'n' && data[3] == b'g' && data[4] == b'j' &&
        data[5] == b'i' && data[6] == b'e' && data[7] == b'!') {
        throw Exception("TRAP")
    }
    return 0
}

下方的命令中的 CANGJIE_STDX_PATH 指向存放 stdx 系列的路径,例如 "./static/stdx"

Linux 的编译命令是:cjc fuzz_main.cj -L $CANGJIE_STDX_PATH -lstdx.fuzz.fuzz --import-path $CANGJIE_STDX_PATH --link-options="--whole-archive $CANGJIE_HOME/lib/linux_x86_64_llvm/libclang_rt.fuzzer_no_main.a -no-whole-archive -lstdc++" --sanitizer-coverage-inline-8bit-counters

macOS 的编译命令是:cjc fuzz_main.cj -L $CANGJIE_STDX_PATH -lstdx.fuzz.fuzz --import-path $CANGJIE_STDX_PATH --link-options="$CANGJIE_HOME/lib/linux_x86_64_llvm/libclang_rt.fuzzer_no_main.a -lc++" --sanitizer-coverage-inline-8bit-counters

释义:

  • link-options 是链接时选项,fuzz 库本身依赖符号 LLVMFuzzerRunDriver,该符号需要开发者自行解决。
    • 仓颉语言在 $CANGJIE_HOME/lib/linux_x86_64_llvm/libclang_rt.fuzzer_no_main.a 存放一份 修改过 的 libfuzzer,对标准的 libfuzzer 进行了增强,见 实验性特性-覆盖率信息打印
    • 可以使用 find $(clang -print-runtime-dir) -name "libclang_rt.fuzzer_no_main*.a" 寻找本地安装好的静态库文件。
  • 向 Linux 编译需要使用 whole-archive libfuzzer.a 是因为 cjc 调用 ld 后端时,从左到右顺序是 libfuzzer.alibcangjie-fuzz-fuzz.a、 libc 等基础库,该顺序会导致 libcangjie-fuzz-fuzz.a 依赖的 LLVMFuzzerRunDriver 符号未被找到。解决方案有:
    • libfuzzer.a 放到 libcangjie-fuzz-fuzz.a 后面;
    • 使用 whole-archive libfuzzer.a 来规避符号找不到的问题。
  • -lstdc++ (Linux) / -lc++ (macOS) 用于链接 libfuzzer 依赖的 std 库。
  • --sanitizer-coverage-inline-8bit-counterscjc 的编译选项,它会对当前 package 执行覆盖率反馈插桩,详见 cjc 编译器使用手册。
    • 其他高级的参数有:--sanitizer-coverage-trace-compares(提高Fuzz变异的效率)、--sanitizer-coverage-pc-table(Fuzz结束后打印覆盖率信息)。

注意:

如果您使用的Linux系统版本较低,可能出现GLIBC版本过低的链接器报错,请在 link-options 参数中添加 -lpthread 来解决此问题。

libfuzzer 体验类似,可以直接运行,数秒后(取决于 CPU 性能)可获得 crash,且输入的数据是 "Cangjie!"

运行结果如下:

$ ./main
INFO: Seed: 246468919
INFO: Loaded 1 modules   (15 inline 8-bit counters): 15 [0x55bb7c76dcb0, 0x55bb7c76dcbf),
INFO: -max_len is not provided; libFuzzer will not generate inputs larger than 4096 bytes
INFO: A corpus is not provided, starting from an empty corpus
#2      INITED ft: 4 corp: 1/1b exec/s: 0 rss: 28Mb
#420    NEW    ft: 5 corp: 2/9b lim: 8 exec/s: 0 rss: 28Mb L: 8/8 MS: 3 CrossOver-InsertByte-InsertRepeatedBytes-
#1323   NEW    ft: 6 corp: 3/17b lim: 14 exec/s: 0 rss: 28Mb L: 8/8 MS: 3 InsertByte-InsertByte-CrossOver-
#131072 pulse  ft: 6 corp: 3/17b lim: 1300 exec/s: 65536 rss: 35Mb
#262144 pulse  ft: 6 corp: 3/17b lim: 2600 exec/s: 65536 rss: 41Mb
#295225 NEW    ft: 7 corp: 4/25b lim: 2930 exec/s: 73806 rss: 43Mb L: 8/8 MS: 2 ShuffleBytes-ChangeByte-
#514006 NEW    ft: 8 corp: 5/33b lim: 4096 exec/s: 73429 rss: 53Mb L: 8/8 MS: 1 ChangeByte-
#524288 pulse  ft: 8 corp: 5/33b lim: 4096 exec/s: 74898 rss: 53Mb
#1048576        pulse  ft: 8 corp: 5/33b lim: 4096 exec/s: 61680 rss: 78Mb
#1064377        NEW    ft: 9 corp: 6/41b lim: 4096 exec/s: 62610 rss: 79Mb L: 8/8 MS: 1 ChangeByte-
#1287268        NEW    ft: 10 corp: 7/49b lim: 4096 exec/s: 61298 rss: 90Mb L: 8/8 MS: 1 ChangeByte-
#2097152        pulse  ft: 10 corp: 7/49b lim: 4096 exec/s: 59918 rss: 128Mb
#2875430        NEW    ft: 11 corp: 8/57b lim: 4096 exec/s: 61179 rss: 165Mb L: 8/8 MS: 2 ChangeBinInt-ChangeByte-
#4194304        pulse  ft: 11 corp: 8/57b lim: 4096 exec/s: 59918 rss: 227Mb
#4208258        NEW    ft: 12 corp: 9/65b lim: 4096 exec/s: 60117 rss: 228Mb L: 8/8 MS: 3 CrossOver-CrossOver-ChangeBit-
[WARNING]: Detect uncatched exception, maybe caused by bugs, exit now
An exception has occurred:
Exception: TRAP
         at default.api(std/core::Array<...>)(/data/Cangjie/fuzz_main.cj:14)
         at _ZN7default3apiER_ZN8std$core5ArrayIhE_cc_wrapper(/data/Cangjie/fuzz_main.cj:0)
         at libfuzzerCallback(fuzz/fuzz/callback.cj:20)
[INFO]: data is: [67, 97, 110, 103, 106, 105, 101, 33]
[INFO]: data base64: Q2FuZ2ppZSE=
crash file will stored with libfuzzer
==899957== ERROR: libFuzzer: fuzz target exited
SUMMARY: libFuzzer: fuzz target exited
MS: 1 ChangeByte-; base unit: 7d8b0108ce76a937161065eafcde95bbf3d47dbf
0x43,0x61,0x6e,0x67,0x6a,0x69,0x65,0x21,
Cangjie!
artifact_prefix='./'; Test unit written to ./crash-555e7af32a2ceb585cdd9ce810c4804e65d41cea
Base64: Q2FuZ2ppZSE=

使用 DataProvider 功能进行测试

除了使用字节流对 API 进行测试的方法之外,fuzz 包提供了 FuzzDataProvider 类,用于更友好地从变异的数据源产生仓颉的标准数据类型,方便对 API 进行测试。

public func api2(dp: FuzzDataProvider): Int32 {
    if(dp.consumeBool() && dp.consumeByte() == b'A' && dp.consumeuint32() == 0xdeadbeef){
        throw Exception("TRAP")
    }
    return 0
}

此案例中,开启 --sanitizer-coverage-trace-compares 可有效提高 fuzz 效率。

DataProvider 模式下,无法直观地判断各个 API 返回值分别是什么,因此提供了 Fuzzer.enableDebugDataProvider() 和 DebugDataProvider,在 startFuzz 前调用 enableDebugDataProvider() 即可令本次 fuzz 每次调用 consumeXXX 时打印日志。

例如,上文代码触发异常后,添加 enableDebugDataProvider 重新编译,效果如下。

import stdx.fuzz.fuzz.*

main() {
    let fuzzer = Fuzzer(api2)
    fuzzer.enableDebugDataProvider()
    fuzzer.startFuzz()
    return 0
}

运行结果如下:

./main crash-d7ece8e77ff25769a5d55eb8d3093d4bace78e1b
Running: crash-d7ece8e77ff25769a5d55eb8d3093d4bace78e1b
[DEBUG] consumeBool return true
[DEBUG] consumeByte return 65
[DEBUG] consumeUInt32 return 3735928559
[WARNING]: Detect uncatched exception, maybe caused by bugs, exit now
An exception has occurred:
Exception: TRAP
         at default.api2(fuzz/fuzz::FuzzDataProvider)(/tmp/test.cj:12)
         at _ZN7default4api2EC_ZN9fuzz$fuzz16FuzzDataProviderE_cc_wrapper(/tmp/test.cj:0)
         at libfuzzerCallback(fuzz/fuzz/callback.cj:0)
[INFO]: data is: [191, 65, 239, 190, 173, 222]

使用 FakeCoverage 避免 DataProvider 模式下 Fuzz 异常终止

在链接了 libfuzzer <= 14 的情况下,且处于 DataProvider 模式下,遇到了类似如下的错误,可能需要阅读此章节:

ERROR: no interesting inputs were found. Is the code instrumented for coverage? Exiting.

libfuzzer 15 起,修复了该 feature,即使初始化时拒绝了输入,也不会停止执行。

注意:请确认被测试的库确实被插入了覆盖率反馈,因为在没有覆盖率反馈插桩的情况下,也会出现该错误!

当前 fuzz 后端对接到了 libfuzzer,而 libfuzzer 在启动时会先输入空字节流、再输入仅包含一个 '\n' 的字节流对待测函数进行试探,在两轮结束后检测覆盖率是否新增。在 DataProvider 模式下,如果先消耗数据,再调用待测库的 API,会导致消耗数据时长度不足而提前返回,从而 libfuzzer 认为覆盖率信息为零。

例如下方代码,会触发该错误

触发的代码:

// main.cj
import stdx.fuzz.fuzz.*

main() {
    let f = Fuzzer(api)
    f.disableFakeCoverage()
    f.startFuzz()
    return 0
}

// fuzz_target.cj, with sancov
public func api(dp: FuzzDataProvider): Int32 {
    if (dp.consumeBool() && dp.consumeBool()) {
        throw Exception("TRAP!")
    }
    return 0
}

运行结果如下:

...
ERROR: no interesting inputs were found. Is the code instrumented for coverage? Exiting.
...

因此,需要使用 Fake Coverage 创建虚假的覆盖率信息,让 libfuzzer 在初始化期间认为待测模块确实被插桩,等到 DataProvider 收集到足够数据后,再进行有效的 fuzz 测试。该模式被称为 Fake Coverage 模式。

将上文的 disableFakeCoverage() 替换为 enableFakeCoverage() 即可继续运行,最终触发 TRAP。

此外,除了使用 Fake Coverage 模式,还可以在测试用例中主动调用待测函数的某些不重要的API来将覆盖率信息传递给 libfuzzer,也能起到让 fuzz 继续下去的作用。

// main.cj
import stdx.fuzz.fuzz.*

main() {
    let f = Fuzzer(api)
    f.enableFakeCoverage()
    f.startFuzz()
    return 0
}

// fuzz_target.cj, with sancov
public func api(dp: FuzzDataProvider): Int32 {
    if (dp.consumeBool() && dp.consumeBool()) {
        throw Exception("TRAP!")
    }
    return 0
}

运行结果如下:

INFO: Running with entropic power schedule (0xFF, 100).
INFO: Seed: 3187548846
INFO: Loaded 2 modules   (8 inline 8-bit counters): 7 [0x55bf83ea8790, 0x55bf83ea8797), 1 [0x55bf83e97b00, 0x55bf83e97b01),
INFO: -max_len is not provided; libFuzzer will not generate inputs larger than 4096 bytes
INFO: A corpus is not provided, starting from an empty corpus
#2      INITED ft: 5 corp: 1/1b exec/s: 0 rss: 33Mb
#9      NEW    ft: 6 corp: 2/2b lim: 4 exec/s: 0 rss: 33Mb L: 1/1 MS: 2 CopyPart-ChangeByte-
[WARNING]: Detect uncatched exception, maybe caused by bugs, exit now
An exception has occurred:
Exception: TRAP!
...
...

打印 fuzz 使用方法

可以使用 -help=1 打印帮助,-seed=246468919 指定随机数的种子。

运行结果如下:

$ ./main -help=1                                                                                                                                                                                        exit 130
Usage:
To run fuzzing pass 0 or more directories.
program_name [-flag1=val1 [-flag2=val2 ...] ] [dir1 [dir2 ...] ]
To run individual tests without fuzzing pass 1 or more files:
program_name [-flag1=val1 [-flag2=val2 ...] ] file1 [file2 ...]

实验性特性-覆盖率信息打印

仓颉 fuzzer 支持使用 -print_coverage=1 作为启动参数运行 fuzzer,用于统计各函数的测试情况,该特性在持续完善中,只与输出覆盖率报告有关,不影响 fuzz 过程。

由于该功能需要对 libfuzzer 进行侵入式修改,使用该功能需要链接仓颉自带的 libfuzzer,路径是:$CANGJIE_HOME/lib/{linux_x86_64_llvm, linux_aarch64_llvm}/libclang_rt-fuzzer_no_main.a。

编译时需要同时启用--sanitizer-coverage-inline-8bit-counters--sanitizer-coverage-pc-table

C 语言 libfuzzer 输出举例

./a.out -print_coverage=1
COVERAGE:
COVERED_FUNC: hits: 5 edges: 6/8 LLVMFuzzerTestOneInput /tmp/test.cpp:5
  UNCOVERED_PC: /tmp/test.cpp:6
  UNCOVERED_PC: /tmp/test.cpp:9

仓颉语言 cj-fuzz 输出举例

./main -print_coverage=1 -runs=100
Done 100 runs in 0 second(s)
COVERAGE:
COVERED_FUNC: hits: 1 edges: 3/12 ttt <unknown cj filename>:<unknown cj line number>
  UNCOVERED_PC: <unknown cj filename>:<unknown cj line number>
  UNCOVERED_PC: <unknown cj filename>:<unknown cj line number>
  UNCOVERED_PC: <unknown cj filename>:<unknown cj line number>
  UNCOVERED_PC: <unknown cj filename>:<unknown cj line number>
  UNCOVERED_PC: <unknown cj filename>:<unknown cj line number>
  UNCOVERED_PC: <unknown cj filename>:<unknown cj line number>
  UNCOVERED_PC: <unknown cj filename>:<unknown cj line number>
  UNCOVERED_PC: <unknown cj filename>:<unknown cj line number>
  UNCOVERED_PC: <unknown cj filename>:<unknown cj line number>
UNCOVERED_FUNC: hits: 0 edges: 0/2 main <unknown cj filename>:<unknown cj line number>
COVERED_FUNC: hits: 1 edges: 1/1 ttt_cc_wrapper <unknown cj filename>:<unknown cj line number>

栈回溯缺失的处理方案

当前在启动 fuzz 时默认会有这三条 WARNING,因为当前 cj-fuzz 没有对它们进行实现。

WARNING: Failed to find function "__sanitizer_acquire_crash_state".
WARNING: Failed to find function "__sanitizer_print_stack_trace".
WARNING: Failed to find function "__sanitizer_set_death_callback".

在 fuzz 过程中,可能会因为以下 3 种情况而结束 fuzz 流程:

  1. 抛出异常
  2. 超时
  3. 在 C 代码中 crash

其中“抛出异常”的情况,fuzz 框架对异常进行捕获后会打印栈回溯,不会造成栈回溯缺失的现象。

“超时”和“在 C 代码中 crash”实际是在 native 代码中触发了 SIGNAL,不属于仓颉异常,因此会造成栈回溯的缺失。

libfuzzer 会尝试使用 __sanitizer_acquire_crash_state__sanitizer_print_stack_trace__sanitizer_set_death_callback 等函数处理异常情况,其中 __sanitizer_print_stack_trace 会打印栈回溯,目前成熟的实现在 llvm compiler-rt 中的 asan 等模块中。

因此,建议的解决方案是在链接时额外加入如下的静态库文件和链接选项,释义如下:

/usr/lib/llvm-14/lib/clang/14.0.0/lib/linux/libclang_rt.asan-x86_64.a -lgcc_s --eh-frame-hdr

  • /usr/lib/llvm-14/lib/clang/14.0.0/lib/linux/libclang_rt.asan-x86_64.a 因为该 .a 文件实现了 __sanitizer_print_stack_trace,出于方便就直接用它;
  • -lgcc_s 栈回溯依赖 gcc_s;
  • --eh-frame-hdr ld 链接时生成 eh_frame_hdr 节,帮助完成栈回溯。

可选的环境变量:ASAN_SYMBOLIZER_PATH=$CANGJIE_HOME/third_party/llvm/bin/llvm-symbolizer,可能在某些情况下有用。

最终会得到两套栈回溯,一套是 Exception.printStackTrace,一套是 __sanitizer_print_stack_trace,内容如下:

[WARNING]: Detect uncatched exception, maybe caused by bugs, exit now
An exception has occurred:
Exception: TRAP!
         at default.ttt(std/core::Array<...>)(/data/cangjie/libs/fuzz/ci_fuzzer0.cj:11)
         at _ZN7default3tttER_ZN8std$core5ArrayIhE_cc_wrapper(/data/cangjie/libs/fuzz/ci_fuzzer0.cj:0)
         at libfuzzerCallback(/data/cangjie/libs/fuzz/fuzz/callback.cj:34)
[INFO]: data is: [0, 202, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255]
[INFO]: crash file will stored with libfuzzer
==425243== ERROR: libFuzzer: fuzz target exited
    #0 0x563a233fadf1 in __sanitizer_print_stack_trace (/data/cangjie/libs/fuzz/main+0x280df1)
    #1 0x563a2337c0b8 in fuzzer::PrintStackTrace() (/data/cangjie/libs/fuzz/main+0x2020b8)
    #2 0x563a2338726c in fuzzer::Fuzzer::ExitCallback() (/data/cangjie/libs/fuzz/main+0x20d26c)
    #3 0x7f485cf36494 in __run_exit_handlers stdlib/exit.c:113:8
    #4 0x7f485cf3660f in exit stdlib/exit.c:143:3
    #5 0x563a23224e68 in libfuzzerCallback$real /data/cangjie/libs/fuzz/fuzz/callback.cj:62:18
    #6 0x7f485d22718b in CJ_MCC_N2CStub (/data/cangjie/output/runtime/lib/linux_x86_64_llvm/libcangjie-runtime.so+0x2718b)
    #7 0x563a2322fc26 in libfuzzerCallback /data/cangjie/libs/fuzz/fuzz/callback.cj:20
    #8 0x563a23387883 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) (/data/cangjie/libs/fuzz/main+0x20d883)
    #9 0x563a2338a3f9 in fuzzer::Fuzzer::RunOne(unsigned char const*, unsigned long, bool, fuzzer::InputInfo*, bool, bool*) (/data/cangjie/libs/fuzz/main+0x2103f9)
    #10 0x563a23387e49 in fuzzer::Fuzzer::MutateAndTestOne() (/data/cangjie/libs/fuzz/main+0x20de49)
    #11 0x563a2338a2b5 in fuzzer::Fuzzer::Loop(std::vector<fuzzer::SizedFile, std::allocator<fuzzer::SizedFile>>&) (/data/cangjie/libs/fuzz/main+0x2102b5)
    #12 0x563a23377a12 in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) (/data/cangjie/libs/fuzz/main+0x1fda12)
    #13 0x563a231ad2b6 in fuzz_fake$fuzz::Fuzzer::startFuzz() /data/cangjie/libs/fuzz/fuzz/fuzzer.cj:200:13
    #14 0x563a23405fad in default::main() /data/cangjie/libs/fuzz/ci_fuzzer0.cj:5:5
    #15 0x563a23405fe7 in user.main /data/cangjie/libs/fuzz/<stdin>
    #16 0x563a234060e1 in cj_entry$ (/data/cangjie/libs/fuzz/main+0x28c0e1)
    #17 0x7f485d227220  (/data/cangjie/output/runtime/lib/linux_x86_64_llvm/libcangjie-runtime.so+0x27220)
    #18 0x7f485d223898  (/data/cangjie/output/runtime/lib/linux_x86_64_llvm/libcangjie-runtime.so+0x23898)
    #19 0x7f485d2607b9 in CJ_CJThreadEntry (/data/cangjie/output/runtime/lib/linux_x86_64_llvm/libcangjie-runtime.so+0x607b9)

stdx.log

功能介绍

log 包提供了一个单一的日志API,它抽象了实际的日志实现。

API 列表

函数

函数名功能
getGlobalLogger(Array<Attr>)获取全局Logger对象。
setGlobalLogger(Logger)设置全局Logger对象。

类型别名

类型别名功能
Attr日志消息的键值对类型,是 (String, LogValue) 的类型别名。

接口

接口名功能
LogValue为仓颉数据类型提供序列化到日志输出目标的接口。

类名功能
Logger此抽象类提供基础的日志打印和管理功能。
LogRecord日志消息的“负载”。
LogWriterLogWriter 提供了将仓颉数据类型序列化到日志输出目标的能力。
NoopLoggerLogger 的 NO-OP(无操作)实现。

结构体

结构体名功能
LogLevelLogLevel 为日志级别结构体。

异常类

异常类名功能
LogException用于处理 log 相关的异常。

类型别名

type Attr

public type Attr = (String, LogValue)

功能:日志消息的键值对类型,是 (String, LogValue) 的类型别名。

函数

func getGlobalLogger(Array<Attr>)

public func getGlobalLogger(attrs: Array<Attr>): Logger

功能:获取 Logger 对象。

如果未传入 attrs 参数,那么获取的是同一个 Logger 对象,传入了 attrs 参数,则创建一个包含指定的属性的 Logger 对象副本。

参数:

  • attrs: Array<Attr> - 日志数据键值对属性,获取的 Logger 对象会包含这些属性。

返回值:

func setGlobalLogger(Logger)

public func setGlobalLogger(logger: Logger): Unit

功能:设置全局 Logger 对象。

注意,这个函数在程序的生命周期中只应该被调用一次。对 setGlobalLogger 的调用完成之前发生的任何日志事件都将被忽略。

此函数通常不需要手动调用。日志实现提供者应提供包含了调用本方法的的初始化方法。

参数:

接口

interface LogValue

public interface LogValue {
    func writeTo(w: LogWriter): Unit
}

功能:为类型提供序列化到日志输出目标的接口。

LogWriter 搭配使用, LogWriter 可以通过 writeValue 将实现了 LogValue 接口的类型写入到日志输出目标中。

func writeTo(LogWriter)

func writeTo(w: LogWriter): Unit

功能:将实现了 LogValue 接口的类型写入参数 w 指定的 LogWriter 实例中。

参数:

extend Bool <: LogValue

extend Bool <: LogValue

功能:为 Bool 类型实现 LogValue 接口。

父类型:

func writeTo(LogWriter)

public func writeTo(w: LogWriter): Unit

功能:提供 Bool 类型序列化到流的功能。

参数:

extend Exception <: LogValue

extend Exception <: LogValue

功能:为 Exception 类型实现 LogValue 接口。

父类型:

func writeTo(LogWriter)

public func writeTo(w: LogWriter): Unit

功能:提供 Exception 类型序列化到流的功能。

参数:

extend Int64 <: LogValue

extend Int64 <: LogValue

功能:为 Int64 类型实现 LogValue 接口。

父类型:

func writeTo(LogWriter)

public func writeTo(w: LogWriter): Unit

功能:提供 Int64 类型序列化到流的功能。

参数:

extend Float64 <: LogValue

extend Float64 <: LogValue

功能:为 Float64 类型实现 LogValue 接口。

父类型:

func writeTo(LogWriter)

public func writeTo(w: LogWriter): Unit

功能:提供 Float64 类型序列化到流的功能。

参数:

extend String <: LogValue

extend String <: LogValue

功能:为 String 类型实现 LogValue 接口。

父类型:

func writeTo(LogWriter)

public func writeTo(w: LogWriter): Unit

功能:提供 String 类型序列化到流的功能。

参数:

extend DateTime <: LogValue

extend DateTime <: LogValue

功能:为 DateTime 类型实现 LogValue 接口。

父类型:

func writeTo(LogWriter)

public func writeTo(w: LogWriter): Unit

功能:提供 DateTime 类型序列化到流的功能。

参数:

extend Duration <: LogValue

extend Duration <: LogValue

功能:为 Duration 类型实现 LogValue 接口。

父类型:

func writeTo(LogWriter)

public func writeTo(w: LogWriter): Unit

功能:提供 Duration 类型序列化到流的功能。

参数:

extend<T> Array<T> <: LogValue where T <: LogValue

extend<T> Array<T> <: LogValue where T <: LogValue

功能:为 Array<T> 类型实现 LogValue 接口。

父类型:

func writeTo(LogWriter)

public func writeTo(w: LogWriter): Unit

功能:提供 Array<T> 类型序列化到流的功能。

参数:

extend<V> HashMap<String, V> <: LogValue where V <: LogValue

extend<V> HashMap<String, V> <: LogValue where V <: LogValue

功能:为 HashMap<K, V> 类型实现 LogValue 接口。

父类型:

func writeTo(LogWriter)

public func writeTo(w: LogWriter): Unit

功能:提供 HashMap<K, V> 类型序列化到流的功能。

参数:

extend<V> TreeMap<String, V> <: LogValue where V <: LogValue

extend<V> TreeMap<String, V> <: LogValue where V <: LogValue

功能:为 TreeMap<K, V> 类型实现 LogValue 接口。

父类型:

func writeTo(LogWriter)

public func writeTo(w: LogWriter): Unit

功能:提供 TreeMap<K, V> 类型序列化到流的功能。

参数:

extend<T> Option<T> <: LogValue where T <: LogValue

extend<T> Option<T> <: LogValue where T <: LogValue

功能:为 Option<T> 类型实现 LogValue 接口。

父类型:

func writeTo(LogWriter)

public func writeTo(w: LogWriter): Unit

功能:提供 Option<T> 类型序列化到流的功能。

参数:

class Logger

public abstract class Logger <: Resource {
}

功能:此抽象类提供基础的日志打印和管理功能。

父类型:

  • Resource

prop level

public mut open prop level: LogLevel

功能:获取和修改日志打印级别。

类型:LogLevel

func debug(String, Array<Attr>)

public func debug(message: String, attrs: Array<Attr>): Unit

功能:打印 DEBUG 级别的日志的便捷函数。

参数:

  • message: String - 日志消息。
  • attrs: Array<Attr> - 日志数据键值对。

func debug(() -> String, Array<Attr>)

public func debug(message: () -> String, attrs: Array<Attr>): Unit

功能:打印 DEBUG 级别的日志的便捷函数。

参数:

  • message: () -> String - 日志消息。
  • attrs: Array<Attr> - 日志数据键值对。

func enabled(LogLevel)

public func enabled(level: LogLevel): Bool

功能:确定是否记录指定日志级别的日志消息。

这个函数允许调用者提前判断日志是否会被丢弃,以避免耗时的日志消息参数计算。

参数:

返回值:

  • Bool - 如果指定的日志级别处于使能状态,则返回 true;否则,返回 false

func error(String, Array<Attr>)

public func error(message: String, attrs: Array<Attr>): Unit

功能:打印 ERROR 级别的日志的便捷函数。

参数:

  • message: String - 日志消息。
  • attrs: Array<Attr> - 日志数据键值对。

func error(() -> String, Array<Attr>)

public func error(message: () -> String, attrs: Array<Attr>): Unit

功能:打印 ERROR 级别的日志的便捷函数。

参数:

  • message: () -> String - 日志消息。
  • attrs: Array<Attr> - 日志数据键值对。

func fatal(String, Array<Attr>)

public func fatal(message: String, attrs: Array<Attr>): Unit

功能:打印 FATAL 级别的日志的便捷函数。

参数:

  • message: String - 日志消息。
  • attrs: Array<Attr> - 日志数据键值对。

func fatal(() -> String, Array<Attr>)

public func fatal(message: () -> String, attrs: Array<Attr>): Unit

功能:打印 FATAL 级别的日志的便捷函数。

参数:

  • message: () -> String - 日志消息。
  • attrs: Array<Attr> - 日志数据键值对。

func info(String, Array<Attr>)

public func info(message: String, attrs: Array<Attr>): Unit

功能:打印 INFO 级别的日志的便捷函数。

参数:

  • message: String - 日志消息。
  • attrs: Array<Attr> - 日志数据键值对。

func info(() -> String, Array<Attr>)

public func info(message: () -> String, attrs: Array<Attr>): Unit

功能:打印 INFO 级别的日志的便捷函数。

参数:

  • message: () -> String - 日志消息。
  • attrs: Array<Attr> - 日志数据键值对。

func log(LogLevel, String, Array<Attr>)

public open func log(level: LogLevel, message: String, attrs: Array<Attr>): Unit

功能:打印日志的通用函数,需指定日志级别。

参数:

  • level: LogLevel - 日志级别。
  • message: String - 日志消息。
  • attrs: Array<Attr> - 日志数据键值对。

func log(LogLevel, () -> String, Array<Attr>)

public open func log(level: LogLevel, message: () -> String, attrs: Array<Attr>): Unit

功能:打印日志的通用函数,需指定日志级别。

参数:

  • level: LogLevel - 日志级别。
  • message: () -> String - 日志消息。
  • attrs: Array<Attr> - 日志数据键值对。

func log(LogRecord)

public open func log(record: LogRecord): Unit

功能:打印日志的通用函数。

参数:

func trace(String, Array<Attr>)

public func trace(message: String, attrs: Array<Attr>): Unit

功能:打印 TRACE 级别的日志的便捷函数。

参数:

  • message: String - 日志消息。
  • attrs: Array<Attr> - 日志数据键值对。

func trace(() -> String, Array<Attr>)

public func trace(message: () -> String, attrs: Array<Attr>): Unit

功能:打印 TRACE 级别的日志的便捷函数。

参数:

  • message: () -> String - 日志消息。
  • attrs: Array<Attr> - 日志数据键值对。

func warn(String, Array<Attr>)

public func warn(message: String, attrs: Array<Attr>): Unit

功能:打印 WARN 级别的日志的便捷函数。

参数:

  • message: String - 日志消息。
  • attrs: Array<Attr> - 日志数据键值对。

func warn(() -> String, Array<Attr>)

public func warn(message: () -> String, attrs: Array<Attr>): Unit

功能:打印 WARN 级别的日志的便捷函数。

参数:

  • message: () -> String - 日志消息。
  • attrs: Array<Attr> - 日志数据键值对。

func withAttrs(Array<Attr>)

public open func withAttrs(attrs: Array<Attr>): Logger

功能:创建当前对象的副本,新的副本会包含指定的属性。

参数:

  • attrs: Array<Attr> - 日志数据键值对属性。

返回值:

class LogRecord

public class LogRecord {
    public init(time: DateTime, level: LogLevel, msg: String, attrs: Array<Attr>)
}

功能:日志消息的“负载”。

记录结构作为参数传递给 Logger 类的 log方法。日志提供者处理这些结构以显示日志消息。记录是由日志对象自动创建,因此日志用户看不到。

init(DateTime, LogLevel, String, Array<Attr>)

public init(time: DateTime, level: LogLevel, msg: String, attrs: Array<Attr>)

功能:创建一个 LogRecord 实例,指定时间戳,日志打印级别,日志消息和日志数据键值对。

参数:

  • time: DateTime - 记录日志时的时间戳
  • level: LogLevel - 日志级别。
  • msg: String - 日志消息。
  • attrs: Array<Attr> - 日志数据键值对。

prop attrs

public mut prop attrs: Array<Attr>

功能:获取或设置日志数据键值对。

类型:Array<Attr>

prop level

public prop level: LogLevel

功能:获取日志打印级别,只有级别小于等于该值的日志会被打印。

类型:LogLevel

prop message

public mut prop message: String

功能:获取或设置日志消息。

类型:String

prop time

public prop time: DateTime

功能:获取日志打印时的时间戳。

类型:DateTime

func clone()

public func clone(): LogRecord

功能:创建当前对象的副本。

返回值:

class LogWriter

public abstract class LogWriter {
}

功能:LogWriter 提供了将仓颉对象序列化成日志输出目标的能力。

LogWriter 需要和 interface LogValue 搭配使用,LogWriter 可以通过 writeValue 系列方法来将实现了 LogValue 接口的类型写入到日志输出目标中。

func endArray()

public func endArray(): Unit

功能:结束序列化当前的 LogValue 数组。

异常:

  • IllegalStateException - 当前 writer 没有匹配的 startArray 时。

func endObject()

public func endObject(): Unit

功能:结束序列化当前的 LogValue object。

异常:

  • IllegalStateException - 当前 writer 的状态不应该结束一个 LogValue object 时。

func startArray()

public func startArray(): Unit

功能:开始序列化一个新的 LogValue 数组,每一个 startArray 都必须有一个 endArray 对应。

异常:

  • IllegalStateException - 当前 writer 的状态不应该写入 LogValue array 时。

func startObject()

public func startObject(): Unit

功能:开始序列化一个新的 LogValue object,每一个 startObject 都必须有一个 endObject 对应。

异常:

  • IllegalStateException - 当前 writer 的状态不应该写入 LogValue object 时。

func writeBool(Bool)

public func writeBool(v: Bool): Unit

功能:向日志输出目标中写入 Bool 值。

参数:

  • v: Bool - 待写入的 Bool 值。

异常:

  • IllegalStateException - 当前 writer 的状态不应该写入 value 时。

func writeFloat(Float64)

public func writeFloat(v: Float64): Unit

功能:向日志输出目标中写入 Float64 值。

参数:

  • v: Float64 - 待写入的 Float64 值。

异常:

  • IllegalStateException - 当前 writer 的状态不应该写入 value 时。

func writeDateTime(DateTime)

public func writeDateTime(v: DateTime): Unit

功能:向日志输出目标中写入 DateTime 值。

参数:

  • v: DateTime - 待写入的 DateTime 值。

异常:

  • IllegalStateException - 当前 writer 的状态不应该写入 value 时。

func writeDuration(Duration)

public func writeDuration(v: Duration): Unit

功能:向日志输出目标中写入 Duration 值。

参数:

  • v: Duration - 待写入的 Duration 值。

异常:

  • IllegalStateException - 当前 writer 的状态不应该写入 value 时。

func writeException(Exception)

public func writeException(v: Exception): Unit

功能:向日志输出目标中写入 Exception 值。

参数:

  • v: Exception - 待写入的 Exception 值。

异常:

  • IllegalStateException - 当前 writer 的状态不应该写入 value 时,抛出该异常。

func writeInt(Int64)

public func writeInt(v: Int64): Unit

功能:向日志输出目标中写入 Int64 值。

参数:

  • v: Int64 - 待写入的 Int64 值。

异常:

  • IllegalStateException - 当前 writer 的状态不应该写入 value 时。

func writeKey(String)

public func writeKey(v: String): Unit

功能:向日志输出目标中写入 name。

参数:

  • v: String - 待写入的 Key 值。

异常:

  • IllegalStateException - 当前 writer 的状态不应写入参数 name 指定字符串时。

func writeNone()

public func writeNone(): Unit

功能:向日志输出目标中写入 None,具体写成什么格式由 Logger 的提供者自行决定。

异常:

  • IllegalStateException - 当前 writer 的状态不应该写入 value 时。

func writeString(String)

public func writeString(v: String): Unit

功能:向日志输出目标中写入 String 值。

参数:

  • v: String - 待写入的 String 值。

异常:

  • IllegalStateException - 当前 writer 的状态不应该写入 value 时。

func writeValue(LogValue)

public func writeValue(v: LogValue): Unit

功能:将实现了 LogValue 接口的类型写入到日志输出目标中。该接口会调用 LogValuewriteTo 方法向日志输出目标中写入数据。

log 包已经为基础类型 Int64、Float64、Bool、String 类型扩展实现了 LogValue,并且为 DateTime、Duration、 Collection 类型 Array、HashMap 和 TreeMap 以及 Option<T> 扩展实现了 LogValue

参数:

异常:

  • IllegalStateException - 当前 writer 的状态不应该写入 value 时。

class NoopLogger

public class NoopLogger <: Logger {
    public init()
}

功能:Logger 的 NO-OP(无操作)实现,会丢弃所有的日志。

父类型:

init()

public init()

功能:创建一个 NoopLogger 实例。

prop level

public mut prop level: LogLevel

功能:永远只能获取到 OFF 日志打印级别,设置日志打印级别不会生效。

类型:LogLevel

func close()

public func close(): Unit

功能:NOOP 实现。

func isClosed()

public func isClosed(): Bool

功能:NOOP 实现。

返回值:

  • Bool。

func log(LogLevel, String, Array<Attr>)

public func log(level: LogLevel, message: String, attrs: Array<Attr>): Unit

功能:NOOP 实现。

参数:

  • level: LogLevel - 日志级别。
  • message: String - 日志消息。
  • attrs: Array<Attr> - 日志数据键值对。

func log(LogLevel, () -> String, Array<Attr>)

public func log(level: LogLevel, message: () -> String, attrs: Array<Attr>): Unit

功能:NOOP 实现。

参数:

  • level: LogLevel - 日志级别。
  • message: () -> String - 日志消息。
  • attrs: Array<Attr> - 日志数据键值对。

func log(LogRecord)

public func log(record: LogRecord): Unit

功能:NOOP 实现。

参数:

func withAttrs(Array<Attr>)

public func withAttrs(attrs: Array<Attr>): Logger

功能:NOOP 实现。

参数:

  • attrs: Array<Attr> - 日志数据键值对。

返回值:

结构体

struct LogLevel

public struct LogLevel <: ToString & Comparable<LogLevel> {
    public static const OFF = LogLevel("OFF", 0x7FFF_FFFF)
    public static const FATAL = LogLevel("FATAL", 6000)
    public static const ERROR = LogLevel("ERROR", 5000)
    public static const WARN = LogLevel("WARN", 4000)
    public static const INFO = LogLevel("INFO", 3000)
    public static const DEBUG = LogLevel("DEBUG", 2000)
    public static const TRACE = LogLevel("TRACE", 1000)
    public static const ALL = LogLevel("ALL", -0x8000_0000)
    public let name: String
    public let value: Int32
    public const init(name: String, value: Int32)
}

功能:LogLevel 为日志级别结构体。

定义了日志打印的七个级别,级别从低到高分别为 OFFFATALERRORWARNINFODEBUGTRACEALL

我们期望只有级别小于等于指定打印级别的日志条目会被打印到输出流中。

父类型:

let name

public let name: String

功能:日志级别名。

let value

public let value: Int32

功能:日志级别值。

init(String, Int32)

public const init(name: String, value: Int32)

功能:常量构造函数,创建 LogLevel 对象。

参数:

  • name: String - 日志级别名。
  • value: Int32 - 日志级别值。

static const ALL

public static const ALL = LogLevel("ALL", -0x8000_0000)

功能:获取一个日志打印级别的静态常量实例,等级为所有。

static const DEBUG

public static const DEBUG = LogLevel("DEBUG", 2000)

功能:获取一个日志打印级别的静态常量实例,等级为调试。

static const ERROR

public static const ERROR = LogLevel("ERROR", 5000)

功能:获取一个日志打印级别的静态常量实例,等级为错误。

static const FATAL

public static const FATAL = LogLevel("FATAL", 6000)

功能:获取一个日志打印级别的静态常量实例,等级为严重错误。

static const INFO

public static const INFO = LogLevel("INFO", 3000)

功能:获取一个日志打印级别的静态常量实例,等级为通知。

static const OFF

public static const OFF = LogLevel("OFF", 0x7FFF_FFFF)

功能:获取一个日志打印级别的静态常量实例,等级为禁用。

static const TRACE

public static const TRACE = LogLevel("TRACE", 1000)

功能:获取一个日志打印级别的静态常量实例,等级为跟踪。

static const WARN

public static const WARN = LogLevel("WARN", 4000)

功能:获取一个日志打印级别的静态常量实例,等级为警告。

func compare(LogLevel)

public func compare(rhs: LogLevel): Ordering

功能:判断当前 LogLevel 类型实例与参数指向的 LogLevel 类型实例的大小关系。

参数:

  • rhs: LogLevel - 待与当前实例比较的另一个实例。

返回值:

  • Ordering - 如果大于,返回 Ordering.GT,如果等于,返回 Ordering.EQ,如果小于,返回 Ordering.LT。

func toString()

public func toString(): String

功能:获取日志级别对应的名称。

返回值:

  • String - 当前的日志级别的名称。

operator func ==(LogLevel)

public operator func ==(rhs: LogLevel): Bool

功能:比较日志级别高低。

参数:

  • rhs: LogLevel - 将当前日志级别和 target 进行比较。

返回值:

  • Bool - 如果当前日志级别等于 target,返回 true,否则返回 false

operator func !=(LogLevel)

public operator func !=(rhs: LogLevel): Bool

功能:比较日志级别高低。

参数:

  • rhs: LogLevel - 将当前日志级别和 target 进行比较。

返回值:

  • Bool - 如果当前日志级别不等于 target,返回 true,否则返回 false

operator func >=(LogLevel)

public operator func >=(rhs: LogLevel): Bool

功能:比较日志级别高低。

参数:

  • rhs: LogLevel - 将当前日志级别和 target 进行比较。

返回值:

  • Bool - 如果当前日志级别大于等于 target,返回 true,否则返回 false

operator func <=(LogLevel)

public operator func <=(rhs: LogLevel): Bool

功能:比较日志级别高低。

参数:

  • rhs: LogLevel - 将当前日志级别和 target 进行比较。

返回值:

  • Bool - 如果当前日志级别小于等于 target,返回 true,否则返回 false

operator func >(LogLevel)

public operator func >(rhs: LogLevel): Bool

功能:比较日志级别高低。

参数:

  • rhs: LogLevel - 将当前日志级别和 target 进行比较。

返回值:

  • Bool - 如果当前日志级别大于 target,返回 true,否则返回 false

operator func <(LogLevel)

public operator func <(rhs: LogLevel): Bool

功能:比较日志级别高低。

参数:

  • rhs: LogLevel - 将当前日志级别和 target 进行比较。

返回值:

  • Bool - 如果当前日志级别小于 target,返回 true,否则返回 false

异常类

class LogException

public open class LogException <: Exception {
    public init()
    public init(message: String)
}

功能:用于处理 log 相关的异常。

父类型:

  • Exception

init()

public init()

功能:无参构造函数。

init(String)

public init(message: String)

功能:根据异常信息创建 LogException 实例。

参数:

  • message: String - 异常信息。

日志打印示例

库开发场景记录日志

下面是开发仓颉库时,打印日志的示例。

代码如下:

import stdx.log.*
import stdx.logger.*
import std.env.*

public class PGConnection {
    let objId: Int64 = 1
    let logger = getGlobalLogger(("name", "PGConnection"))

    public func close(): Unit {
        logger.trace("driver conn closed", ("id", objId))
    }
}

main ():Unit {
    let tl = SimpleLogger(getStdOut())
    tl.level = LogLevel.TRACE
    setGlobalLogger(tl)
    var conn = PGConnection()
    conn.close()
}

运行结果可能如下:

2024-11-21T20:16:43.33200773+08:00 TRACE driver conn closed name="PGConnection" id=1

应用程序开发场景日志打印

下面是 自定义 PasswordFilter 和 TextLogger 日志打印示例。

代码如下:

import std.time.*
import std.io.{OutputStream, ByteBuffer, BufferedOutputStream}
import std.env.*
import std.fs.*
import std.collection.{ArrayList, Map, HashMap}
import std.collection.concurrent.*
import std.sync.AtomicBool
import std.time.DateTime
import stdx.log.*

public class PasswordFilter <: Logger {
    var _level = LogLevel.INFO
    let processor: Logger
    public init(logger: Logger) {
        processor = logger
    }
    public mut prop level: LogLevel {
        get() {
            _level
        }
        set(v) {
            _level = v
        }
    }
    public func withAttrs(attrs: Array<Attr>): Logger {
        this
    }
    // log
    public func log(level: LogLevel, message: String, attrs: Array<Attr>): Unit {
        let record: LogRecord = LogRecord(DateTime.now(), level, message, attrs)
        log(record)
    }
    // lazy
    public func log(level: LogLevel, message: () -> String, attrs: Array<Attr>): Unit {
        let record: LogRecord = LogRecord(DateTime.now(), level, message(), attrs)
        log(record)
    }
    // 根据键值对的名字过滤,将密码值换成 "***"
    public func log(record: LogRecord): Unit {
        var attrs = record.attrs.clone()
        for (i in 0..attrs.size) {
            var attr = attrs[i]
            if (attr[0] == "password") {
                attrs[i] = (attr[0], "***")
            }
        }
        let r = LogRecord(record.time, record.level, record.message, attrs)
        processor.log(r)
    }
    public func isClosed(): Bool {
        false
    }
    public func close(): Unit {
    }
}

main() {
    let o = ByteBuffer()
    let tl = TextLogger(getStdOut())
    tl.level = LogLevel.TRACE
    let l = PasswordFilter(tl)
    setGlobalLogger(l)
    let logger = getGlobalLogger([("name", "main")])
    let user = User()
    // 普通记录信息日志
    logger.info("Hello, World!", ("k1", [[1, 4], [2, 5], [3]]), ("password", "v22222"))
    // 记录诊断日志,如果 DEBUG 级别未开启,直接返回,几乎无cost
    logger.debug("Logging in user ${user.name} with birthday ${user.birthdayCalendar}")

    // lazy 方式记录耗时日志数据
    logger.log(LogLevel.ERROR, "long-running operation msg", ("k1", 100), ("k2", user.birthdayCalendar),
        ("oper", ToStringWrapper({=> "Some long-running operation returned"})))

    logger.log(LogLevel.ERROR, "long-running operation msg", ("sourcePackage", @sourcePackage()),
        ("sourceFile", @sourceFile()), ("sourceLine", @sourceLine()), ("birthdayCalendar", user.birthdayCalendar),
        ("oper", ToStringWrapper({=> "Some long-running operation returned"})))

    let m = HashMap<String, String>()
    m.add("k1", "1")
    m.add("k2", "2")
    m.add("k3", "3")
    logger.trace({=> "Some long-running operation returned"}, ("k1", m))
    let m2 = HashMap<String, LogValue>()
    m2.add("g1", m)

    // 如果TRACE 级别没有开启,那么lambda表达式不会被执行
    logger.trace({=> "Some long-running operation returned"}, ("k2", m2))

    // Console.stdOut.write(o.bytes())
    // Console.stdOut.flush()
}

public class User {
    public prop name: String {
        get() {
            "foo"
        }
    }
    public prop birthdayCalendar: DateTime {
        get() {
            DateTime.now()
        }
    }
}

public class ToStringWrapper <: ToString & LogValue {
    let _fn: () -> String
    public init(fn: () -> String) {
        _fn = fn
    }
    public func toString(): String {
        return _fn()
    }
    public func writeTo(w: LogWriter): Unit {
        w.writeValue(_fn())
    }
}

func expensiveOperation(): String {
    for (_ in 0..1000000) {
        unsafe {
            let b = LibC.malloc<Byte>(count: 1000)
            LibC.free(b)
        }
    }
    "Some long-running operation returned"
}

public class TextLogger <: Logger {
    let w: TextLogWriter
    let opts = HashMap<String, String>()
    let _closed = AtomicBool(false)
    let queue = ConcurrentLinkedQueue<LogRecord>()
    let bo: BufferedOutputStream<OutputStream>
    let _attrs = ArrayList<Attr>()
    var _level = LogLevel.INFO
    public init(output: OutputStream) {
        bo = BufferedOutputStream<OutputStream>(output)
        w = TextLogWriter(bo)
    }

    public mut prop level: LogLevel {
        get() {
            _level
        }
        set(v) {
            _level = v
        }
    }
    public func withAttrs(attrs: Array<Attr>): Logger {
        if (attrs.size > 0) {
            let nl = TextLogger(w.out)
            nl._attrs.add(all: attrs)
            return nl
        }
        return this
    }
    // log
    public func log(level: LogLevel, message: String, attrs: Array<Attr>): Unit {
        if (this.enabled(level)) {
            let record: LogRecord = LogRecord(DateTime.now(), level, message, attrs)
            log(record)
        }
    }
    // lazy
    public func log(level: LogLevel, message: () -> String, attrs: Array<Attr>): Unit {
        if (this.enabled(level)) {
            let record: LogRecord = LogRecord(DateTime.now(), level, message(), attrs)
            log(record)
        }
    }
    public func log(record: LogRecord): Unit {
        // write time
        w.writeKey("time")
        w.writeValue(record.time)
        w.writeString(" ")
        // write level
        w.writeKey("level")
        w.writeString(record.level.toString())
        w.writeString(" ")
        // write message
        w.writeKey("msg")
        w.writeValue(record.message)
        w.writeString(" ")
        // write source

        // write attrs
        for (i in 0..record.attrs.size) {
            let attr = record.attrs[i]
            w.writeKey(attr[0])
            w.writeValue(attr[1])
            if (i < record.attrs.size - 1) {
                w.writeString(" ")
            }
        }
        w.writeString("\n")
        bo.flush()
    }
    public func isClosed(): Bool {
        _closed.load()
    }
    public func close(): Unit {
        if (isClosed()) {
            return
        }
        _closed.store(true)
    }
}

class TextLogWriter <: LogWriter {
    var out: OutputStream
    init(out: OutputStream) {
        this.out = out
    }
    public func writeNone(): Unit {
        out.write("None".toArray())
    }
    public func writeInt(v: Int64): Unit {
        out.write(v.toString().toArray())
    }
    public func writeUInt(v: UInt64): Unit {
        out.write(v.toString().toArray())
    }
    public func writeBool(v: Bool): Unit {
        out.write(v.toString().toArray())
    }
    public func writeFloat(v: Float64): Unit {
        out.write(v.toString().toArray())
    }
    public func writeString(v: String): Unit {
        out.write(v.toArray())
    }
    public func writeDateTime(v: DateTime): Unit {
        out.write(v.toString().toArray())
    }
    public func writeDuration(v: Duration): Unit {
        out.write(v.toString().toArray())
    }
    public func writeException(v: Exception): Unit {
        out.write(v.toString().toArray())
    }
    public func writeKey(v: String): Unit {
        out.write(v.toString().toArray())
        out.write("=".toArray())
    }
    public func writeValue(v: LogValue): Unit {
        match (v) {
            case vv: String =>
                out.write("\"".toArray())
                out.write(vv.toArray())
                out.write("\"".toArray())
            case vv: ToString =>
                out.write("\"".toArray())
                out.write(vv.toString().toArray())
                out.write("\"".toArray())
            case _ =>
                out.write("\"".toArray())
                v.writeTo(this)
                out.write("\"".toArray())
        }
    }
    public func startArray(): Unit {
        out.write("[".toArray())
    }
    public func endArray(): Unit {
        out.write("]".toArray())
    }
    public func startObject(): Unit {
        out.write("{".toArray())
    }
    public func endObject(): Unit {
        out.write("}".toArray())
    }
}

运行结果可能如下:

time="2024-06-17T14:10:07.1861349Z" level=INFO msg="Hello, World!" k1="[[1, 4], [2, 5], [3]]" password="***"
time="2024-06-17T14:10:07.1864929Z" level=DEBUG msg="Logging in user foo with birthday 2024-06-17T14:10:07.1864802Z"
time="2024-06-17T14:10:07.1869579Z" level=ERROR msg="long-running operation msg" k1="100" k2="2024-06-17T14:10:07.186957Z" oper="Some long-running operation returned"
time="2024-06-17T14:10:07.18742Z" level=ERROR msg="long-running operation msg" sourcePackage="log" sourceFile="main.cj" sourceLine="77" birthdayCalendar="2024-06-17T14:10:07.1874188Z" oper="Some long-running operation returned"
time="2024-06-17T14:10:07.1879195Z" level=TRACE msg="Some long-running operation returned" k1="[(k1, 1), (k2, 2), (k3, 3)]"
time="2024-06-17T14:10:07.1881599Z" level=TRACE msg="Some long-running operation returned" k2="{g1="[(k1, 1), (k2, 2), (k3, 3)]"}"

stdx.logger

功能介绍

logger 包提供文本格式和 JSON 格式日志打印功能。

API 列表

类名功能
JsonLogger输出 JSON 格式的 Logger 类实现。
SimpleLogger输出传统文本格式的 Logger 类实现。
TextLogger输出文本 KV 格式的 Logger 类实现。

class JsonLogger

public class JsonLogger <: Logger {
    public init(output: OutputStream)
}

功能:此类实现了输出 JSON 格式的日志打印功能,形如 {"time":"2024-07-27T11:51:59+08:00","level":"INFO","msg":"foo","name":"bar"}

父类型:

init(OutputStream)

public init(output: OutputStream)

功能:创建 JsonLogger 对象。

参数:

  • output: OutputStream - 绑定的输出流,日志格式化后将写入该输出流。

prop level

public mut prop level: LogLevel

功能:获取和修改日志打印级别。

类型:LogLevel

func close()

public func close(): Unit

功能:关闭 Logger。

func isClosed()

public func isClosed(): Bool

功能:判断当前 Logger 是否关闭。

返回值:

  • Bool - 是否关闭。

func log(LogRecord)

public func log(record: LogRecord): Unit

功能:打印日志的通用函数。

参数:

func withAttrs(Array<Attr>)

public func withAttrs(attrs: Array<Attr>): Logger

功能:创建当前对象的副本,新的副本会包含指定的属性。

参数:

  • attrs: Array<Attr> - 日志数据键值对属性。

返回值:

class SimpleLogger

public class SimpleLogger <: Logger {
    public init(output: OutputStream)
}

功能:此类实现了输出文本格式的日志打印功能,形如 2024-07-27T11:50:47.6616733+08:00 INFO foo name="bar"

父类型:

init(OutputStream)

public init(output: OutputStream)

功能:创建 SimpleLogger 对象。

参数:

  • output: OutputStream - 绑定的输出流,日志格式化后将写入该输出流。

prop level

public mut prop level: LogLevel

功能:获取和修改日志打印级别。

类型:LogLevel

func close()

public func close(): Unit

功能:关闭 Logger。

func isClosed()

public func isClosed(): Bool

功能:判断当前 Logger 是否关闭。

返回值:

  • Bool - 是否关闭。

func log(LogRecord)

public func log(record: LogRecord): Unit

功能:打印日志的通用函数。

参数:

func withAttrs(Array<Attr>)

public func withAttrs(attrs: Array<Attr>): Logger

功能:创建当前对象的副本,新的副本会包含指定的属性。

参数:

  • attrs: Array<Attr> - 日志数据键值对属性。

返回值:

class TextLogger

public class TextLogger <: Logger {
    public init(output: OutputStream)
}

功能:此类实现了输出文本格式的日志打印功能,形如 time=2024-07-27T11:52:40.3226881+08:00 level="INFO" msg="foo" name="bar"

父类型:

init(OutputStream)

public init(output: OutputStream)

功能:创建 TextLogger 对象。

参数:

  • output: OutputStream - 绑定的输出流,日志格式化后将写入该输出流。

prop level

public mut prop level: LogLevel

功能:获取和修改日志打印级别。

类型:LogLevel

func close()

public func close(): Unit

功能:关闭 Logger。

func isClosed()

public func isClosed(): Bool

功能:判断当前 Logger 是否关闭。

返回值:

  • Bool - 是否关闭。

func log(LogRecord)

public func log(record: LogRecord): Unit

功能:打印日志的通用函数。

参数:

func withAttrs(Array<Attr>)

public func withAttrs(attrs: Array<Attr>): Logger

功能:创建当前对象的副本,新的副本会包含指定的属性。

参数:

  • attrs: Array<Attr> - 日志数据键值对属性。

返回值:

日志打印示例

下面是使用 JsonLogger 日志打印示例代码:

import std.time.*
import std.io.{OutputStream, ByteBuffer, BufferedOutputStream}
import std.env.*
import std.fs.*
import std.collection.{HashMap, ArrayList}
import stdx.encoding.json.stream.*
import stdx.log.*
import stdx.logger.*

main() {
    let o = ByteBuffer()
    let bo = BufferedOutputStream<OutputStream>(getStdOut())
    let tl = JsonLogger(bo)
    tl.level = LogLevel.TRACE
    setGlobalLogger(tl)
    let logger = getGlobalLogger([("name", "main")])
    let futs = ArrayList<Future<Unit>>()

    for (_ in 0..1) {
        let f = spawn {
            =>
            logger.info("abc", ("age", 2))
            let user = User()
            // 记录诊断日志,如果 DEBUG 级别未开启,直接返回,几乎无cost
            logger.debug("Logging in user ${user.name} with birthday ${user.birthdayCalendar}")
            // 普通记录信息日志
            logger.info("Hello, World!", ("k1", [[1, 4], [2, 5], [3]]), ("password", "v22222"))

            // lazy 方式记录耗时日志数据
            logger.log(LogLevel.ERROR, "long-running operation msg", ("k1", 100), ("k2", user.birthdayCalendar),
                ("oper", ToStringWrapper({=> "Some long-running operation returned"})))

            logger.log(LogLevel.ERROR, "long-running operation msg", ("sourcePackage", @sourcePackage()),
                ("sourceFile", @sourceFile()), ("sourceLine", @sourceLine()), ("birthdayCalendar", user.birthdayCalendar),
                ("oper", ToStringWrapper({=> "Some long-running operation returned"})))

            let m = HashMap<String, String>()
            m.add("k1", "1\n")
            m.add("k2", "2")
            m.add("k3", "3")
            logger.trace({=> "Some long-running operation returned"}, ("m1", m))
            let m2 = HashMap<String, LogValue>()
            m2.add("g1", m)
            m2.add("k1", [["1", "4 s"], ["2", "5"], ["3"]])

            // 如果TRACE 级别没有开启,那么lambda表达式不会被执行
            logger.trace({=> "Some long-running operation returned"}, ("m2", m2))
        }
        futs.add(f)
    }

    for (f in futs) {
        f.get()
    }

    logger.close()
}

public class User {
    public prop name: String {
        get() {
            "foo"
        }
    }
    public prop birthdayCalendar: DateTime {
        get() {
            DateTime.now()
        }
    }
}

public class ToStringWrapper <: ToString & LogValue {
    let _fn: () -> String
    public init(fn: () -> String) {
        _fn = fn
    }
    public func toString(): String {
        return _fn()
    }
    public func writeTo(w: LogWriter): Unit {
        w.writeValue(_fn())
    }
}

func expensiveOperation(): String {
    for (_ in 0..1000000) {
        unsafe {
            let b = LibC.malloc<Byte>(count: 1000)
            LibC.free(b)
        }
    }
    "Some long-running operation returned"
}

运行结果如下:

{"time":"2024-07-18T07:57:45Z","level":"INFO","msg":"abc","name":"main","age":2}
{"time":"2024-07-18T07:57:45Z","level":"DEBUG","msg":"Logging in user foo with birthday 2024-07-18T07:57:45.9912185Z","name":"main"}
{"time":"2024-07-18T07:57:45Z","level":"INFO","msg":"Hello, World!","name":"main","k1":[[1,4],[2,5],[3]],"password":"v22222"}
{"time":"2024-07-18T07:57:45Z","level":"ERROR","msg":"long-running operation msg","name":"main","k1":100,"k2":"2024-07-18T07:57:45Z","oper":"Some long-running operation returned"}
{"time":"2024-07-18T07:57:45Z","level":"ERROR","msg":"long-running operation msg","name":"main","sourcePackage":"mylog","sourceFile":"main.cj","sourceLine":52,"birthdayCalendar":"2024-07-18T07:57:45Z","oper":"Some long-running operation returned"}
{"time":"2024-07-18T07:57:45Z","level":"TRACE","msg":"Some long-running operation returned","name":"main","m1":{"k1":"1\n","k2":"2","k3":"3"}}
{"time":"2024-07-18T07:57:45Z","level":"TRACE","msg":"Some long-running operation returned","name":"main","m2":{"g1":{"k1":"1\n","k2":"2","k3":"3"},"k1":[["1","4 s"],["2","5"],["3"]]}}

下面是使用 SimpleLogger 日志打印示例代码:

import std.time.*
import std.io.{OutputStream, ByteBuffer, BufferedOutputStream}
import std.env.*
import std.fs.*
import std.collection.{HashMap, ArrayList}
import stdx.log.*
import stdx.logger.*

main() {
    let o = ByteBuffer()
    let bo = BufferedOutputStream<OutputStream>(getStdOut())
    let tl = SimpleLogger(bo)
    tl.level = LogLevel.TRACE
    setGlobalLogger(tl)
    let logger = getGlobalLogger([("name", "main")])
    let futs = ArrayList<Future<Unit>>()

    // let f = File("log/a.log", Append)
    // let h = TextHandler(f)
    for (_ in 0..1) {
        let f = spawn {
            =>
            logger.info("abc", ("age", 2))
            let user = User()
            // 记录诊断日志,如果 DEBUG 级别未开启,直接返回,几乎无cost
            logger.debug("Logging in user ${user.name} with birthday ${user.birthdayCalendar}")
            // 普通记录信息日志
            logger.info("Hello, World!", ("k1", [[1, 4], [2, 5], [3]]), ("password", "v22222"))

            // lazy 方式记录耗时日志数据
            logger.log(LogLevel.ERROR, "long-running operation msg", ("k1", 100), ("k2", user.birthdayCalendar),
                ("oper", ToStringWrapper({=> "Some long-running operation returned"})))

            logger.log(LogLevel.ERROR, "long-running operation msg", ("sourcePackage", @sourcePackage()),
                ("sourceFile", @sourceFile()), ("sourceLine", @sourceLine()), ("birthdayCalendar", user.birthdayCalendar),
                ("oper", ToStringWrapper({=> "Some long-running operation returned"})))

            let m = HashMap<String, String>()
            m.add("k1", "1\n")
            m.add("k2", "2")
            m.add("k3", "3")
            logger.trace({=> "Some long-running operation returned"}, ("m1", m))
            let m2 = HashMap<String, LogValue>()
            m2.add("g1", m)
            m2.add("k1", [["1", "4 s"], ["2", "5"], ["3"]])

            // 如果TRACE 级别没有开启,那么lambda表达式不会被执行
            logger.trace({=> "Some long-running operation returned"}, ("m2", m2))
        }
        futs.add(f)
    }

    for (f in futs) {
        f.get()
    }

    logger.close()
}

public class User {
    public prop name: String {
        get() {
            "foo"
        }
    }
    public prop birthdayCalendar: DateTime {
        get() {
            DateTime.now()
        }
    }
}

public class ToStringWrapper <: ToString & LogValue {
    let _fn: () -> String
    public init(fn: () -> String) {
        _fn = fn
    }
    public func toString(): String {
        return _fn()
    }
    public func writeTo(w: LogWriter): Unit {
        w.writeValue(_fn())
    }
}

func expensiveOperation(): String {
    for (_ in 0..1000000) {
        unsafe {
            let b = LibC.malloc<Byte>(count: 1000)
            LibC.free(b)
        }
    }
    "Some long-running operation returned"
}

运行结果如下:

2025-04-15T15:06:54.7371418+08:00 INFO abc name="main" age=2
2025-04-15T15:06:54.737251+08:00 DEBUG Logging in user foo with birthday 2025-04-15T15:06:54.7372416+08:00 name="main"
2025-04-15T15:06:54.7376041+08:00 INFO Hello, World! name="main" k1=[[1,4],[2,5],[3]] password="v22222"
2025-04-15T15:06:54.7379054+08:00 ERROR long-running operation msg name="main" k1=100 k2=2025-04-15T15:06:54.7379047+08:00 oper="Some long-running operation returned"
2025-04-15T15:06:54.7381296+08:00 ERROR long-running operation msg name="main" sourcePackage="mylog" sourceFile="main.cj" sourceLine=37 birthdayCalendar=2025-04-15T15:06:54.7381291+08:00 oper="Some long-running operation returned"
2025-04-15T15:06:54.7385818+08:00 TRACE Some long-running operation returned name="main" m1={k1:"1\n",k2:"2",k3:"3"}
2025-04-15T15:06:54.7387716+08:00 TRACE Some long-running operation returned name="main" m2={g1:{k1:"1\n",k2:"2",k3:"3"},k1:[["1","4 s"],["2","5"],["3"]]}

下面是使用 TextLogger 日志打印示例代码:

import std.time.*
import std.io.{OutputStream, ByteBuffer, BufferedOutputStream}
import std.env.*
import std.fs.*
import std.collection.{HashMap, ArrayList}
import stdx.log.*
import stdx.logger.*

main() {
    let o = ByteBuffer()
    let bo = BufferedOutputStream<OutputStream>(getStdOut())
    let tl = TextLogger(bo)
    tl.level = LogLevel.TRACE
    setGlobalLogger(tl)
    let logger = getGlobalLogger([("name", "main")])
    let futs = ArrayList<Future<Unit>>()

    // let f = File("log/a.log", Append)
    // let h = TextHandler(f)
    for (_ in 0..1) {
        let f = spawn {
            =>
            logger.info("abc", ("age", 2))
            let user = User()
            // 记录诊断日志,如果 DEBUG 级别未开启,直接返回,几乎无cost
            logger.debug("Logging in user ${user.name} with birthday ${user.birthdayCalendar}")
            // 普通记录信息日志
            logger.info("Hello, World!", ("k1", [[1, 4], [2, 5], [3]]), ("password", "v22222"))

            // lazy 方式记录耗时日志数据
            logger.log(LogLevel.ERROR, "long-running operation msg", ("k1", 100), ("k2", user.birthdayCalendar),
                ("oper", ToStringWrapper({=> "Some long-running operation returned"})))

            logger.log(LogLevel.ERROR, "long-running operation msg", ("sourcePackage", @sourcePackage()),
                ("sourceFile", @sourceFile()), ("sourceLine", @sourceLine()), ("birthdayCalendar", user.birthdayCalendar),
                ("oper", ToStringWrapper({=> "Some long-running operation returned"})))

            let m = HashMap<String, String>()
            m.add("k1", "1\n")
            m.add("k2", "2")
            m.add("k3", "3")
            logger.trace({=> "Some long-running operation returned"}, ("m1", m))
            let m2 = HashMap<String, LogValue>()
            m2.add("g1", m)
            m2.add("k1", [["1", "4 s"], ["2", "5"], ["3"]])

            // 如果TRACE 级别没有开启,那么lambda表达式不会被执行
            logger.trace({=> "Some long-running operation returned"}, ("m2", m2))
        }
        futs.add(f)
    }

    for (f in futs) {
        f.get()
    }

    logger.close()
}

public class User {
    public prop name: String {
        get() {
            "foo"
        }
    }
    public prop birthdayCalendar: DateTime {
        get() {
            DateTime.now()
        }
    }
}

public class ToStringWrapper <: ToString & LogValue {
    let _fn: () -> String
    public init(fn: () -> String) {
        _fn = fn
    }
    public func toString(): String {
        return _fn()
    }
    public func writeTo(w: LogWriter): Unit {
        w.writeValue(_fn())
    }
}

func expensiveOperation(): String {
    for (_ in 0..1000000) {
        unsafe {
            let b = LibC.malloc<Byte>(count: 1000)
            LibC.free(b)
        }
    }
    "Some long-running operation returned"
}

运行结果如下:

time=2025-04-15T15:18:09.2186361+08:00 level="INFO" msg="abc" name="main" age=2
time=2025-04-15T15:18:09.2187444+08:00 level="DEBUG" msg="Logging in user foo with birthday 2025-04-15T15:18:09.2187408+08:00" name="main"
time=2025-04-15T15:18:09.2191009+08:00 level="INFO" msg="Hello, World!" name="main" k1=[[1,4],[2,5],[3]] password="v22222"
time=2025-04-15T15:18:09.2193242+08:00 level="ERROR" msg="long-running operation msg" name="main" k1=100 k2=2025-04-15T15:18:09.2193236+08:00 oper="Some long-running operation returned"    
time=2025-04-15T15:18:09.2194668+08:00 level="ERROR" msg="long-running operation msg" name="main" sourcePackage="mylog" sourceFile="main.cj" sourceLine=37 birthdayCalendar=2025-04-15T15:18:09.2194663+08:00 oper="Some long-running operation returned"
time=2025-04-15T15:18:09.2197682+08:00 level="TRACE" msg="Some long-running operation returned" name="main" m1={k1:"1\n",k2:"2",k3:"3"}
time=2025-04-15T15:18:09.2200024+08:00 level="TRACE" msg="Some long-running operation returned" name="main" m2={g1:{k1:"1\n",k2:"2",k3:"3"},k1:[["1","4 s"],["2","5"],["3"]]}

stdx.net.http

功能介绍

http 包提供 HTTP/1.1、HTTP/2 和 WebSocket 协议的 server、client 端实现。

关于协议的详细内容可参考 RFC 91109112911392187541 等。

使用本包需要外部依赖 OpenSSL 3sslcrypto 动态库文件,故使用前需安装相关工具:

  • 对于 Linux 操作系统,可参考以下方式:
    • 如果系统的包管理工具支持安装 OpenSSL 3 开发工具包,可通过这个方式安装,并确保系统安装目录下含有 libssl.solibssl.so.3libcrypto.solibcrypto.so.3 这些动态库文件,例如 Ubuntu 22.04 系统上可使用 sudo apt install libssl-dev 命令安装 libssl-dev 工具包;
    • 如果无法通过上面的方式安装,可自行下载 OpenSSL 3.x.x 源码编译安装软件包,并确保安装目录下含有 libssl.solibssl.so.3libcrypto.solibcrypto.so.3 这些动态库文件,然后可选择下面任意一种方式来保证系统链接器可以找到这些文件:
      • 在系统未安装 OpenSSL 的场景,安装时选择直接安装到系统路径下;
      • 安装在自定义目录的场景,将这些文件所在目录设置到环境变量 LD_LIBRARY_PATH 以及 LIBRARY_PATH 中。
  • 对于 Windows 操作系统,可按照以下步骤:
    • 自行下载 OpenSSL 3.x.x 源码编译安装 x64 架构软件包或者自行下载安装第三方预编译的供开发人员使用的 OpenSSL 3.x.x 软件包;
    • 确保安装目录下含有 libssl.dll.a(或 libssl.lib)、libssl-3-x64.dlllibcrypto.dll.a(或 libcrypto.lib)、libcrypto-3-x64.dll 这些库文件;
    • libssl.dll.a(或 libssl.lib)、libcrypto.dll.a(或 libcrypto.lib)所在的目录路径设置到环境变量 LIBRARY_PATH 中,将 libssl-3-x64.dlllibcrypto-3-x64.dll 所在的目录路径设置到环境变量 PATH 中。
  • 对于 macOS 操作系统,可参考以下方式:
    • 使用 brew install openssl@3 安装,并确保系统安装目录下含有 libcrypto.dyliblibcrypto.3.dylib 这两个动态库文件;
    • 如果无法通过上面的方式安装,可自行下载 OpenSSL 3.x.x 源码编译安装软件包,并确保安装目录下含有 libcrypto.dyliblibcrypto.3.dylib 这两个动态库文件,然后可选择下面任意一种方式来保证系统链接器可以找到这些文件:
      • 在系统未安装 OpenSSL 的场景,安装时选择直接安装到系统路径下;
      • 安装在自定义目录的场景,将这些文件所在目录设置到环境变量 DYLD_LIBRARY_PATH 以及 LIBRARY_PATH 中。

如果未安装 OpenSSL 3软件包或者安装低版本的软件包,程序可能无法使用并抛出 TLS 相关异常。

http

用户可以选择 http 协议的版本,如 HTTP/1.1、HTTP/2。http 包的多数 API 并不区分这两种协议版本,只有当用户用到某个版本的特有功能时,才需要做这种区分,如 HTTP/1.1 中的 chunked 的 transfer-encoding,HTTP/2 中的 server push。

http 库默认使用 HTTP/1.1 版本。当开发者需要使用 HTTP/2 协议时,需要为 Client/Server 配置 tls,并且设置 alpn 的值为 h2;不支持 HTTP/1.1 通过 Upgrade: h2c 协议升级的方式升级到 HTTP/2。

如果创建 HTTP/2 连接握手失败,Client/Server 会自动将协议退回 HTTP/1.1。

  • 用户通过 ClientBuilder 构建一个 Client 实例,构建过程可以指定多个参数,如 httpProxy、logger、cookieJar、是否自动 redirect、连接池大小等。

  • 用户通过 ServerBuilder 构建一个 Server 实例,构建过程可以指定多个参数,如 addr、port、logger、distributor 等。

用户如果需要自己设置 Logger,需要保证它是线程安全的。

Client、Server 的大多数参数在构建后便不允许修改,如果想要更改,用户需要重新构建一个新的 Client 或 Server 实例;如果该参数支持动态修改,本实现会提供显式的功能,如 Server 端 cert、CA 的热更新。

  • 通过 Client 实例,用户可以发送 http request、接收 http response。

  • 通过 Server 实例,用户可以配置 request 转发处理器,启动 http server。在 server handler 中,用户可以通过 HttpContext 获取 client 发来的 request 的详细信息,构造发送给 client 的 response。 Server 端根据 Client 端请求,创建对应的 ProtocolService 实例,同一个 Server 实例可同时支持两种协议:HTTP/1.1、HTTP/2。

  • 在 client 端,用户通过 HttpRequestBuilder 构造 request,构建过程可以指定多个参数,如 method、url、version、headers、body、trailers 等等;构建之后的request 不允许再进行修改。

  • 在 server 端,用户通过 HttpResponseBuilder 构造 response,构建过程可以指定多个参数,如 status、headers、body、trailers 等等;构建之后的 response 不允许再进行修改。

另外,本实现提供一些工具类,方便用户构造一些常用 response,如 RedirectHandler 构造 redirect response,NotFoundHandler 构造 404 response。

WebSocket

本实现为 WebSocket 提供 sub-protocol 协商,包括基础的 frame 解码、读取、消息发送、frame 编码、ping、pong、关闭等功能。

用户通过 WebSocket.upgradeFromClient 从一个 HTTP/1.1 或 HTTP/2 Client 实例升级到 WebSocket 协议,之后通过返回的 WebSocket 实例进行 WebSocket 通讯。

用户在一个 server 端的 handler 中,通过 WebSocket.upgradeFromServer 从 HTTP/1.1 或 HTTP/2 协议升级到 WebSocket 协议,之后通过返回的 WebSocket 实例进行 WebSocket 通讯。

按照协议,HTTP/1.1 中,升级后的 WebSocket 连接是建立在 tcp/tls 连接之上;HTTP/2 中,升级后的 WebSocket 连接是建立在 HTTP/2 connection 的一个 stream 之上。HTTP/1.1 中,close 最终会直接关闭 tcp/tls 连接;HTTP/2 中,close 只会关闭 connection 上的一个 stream。

API 列表

函数

函数名功能
handleError(HttpContext, UInt16)便捷的 Http 请求处理函数,用于回复错误请求。
notFound(HttpContext)便捷的 Http 请求处理函数,用于回复 404 响应。
upgrade(HttpContext)在 handler 内获取 StreamingSocket,可用于支持协议升级和处理 CONNECT 请求。

接口

接口名功能
CookieJarClient 用来管理 Cookie 的工具。
HttpRequestDistributorHttp request 分发器接口,将一个 request 按照 url 中的 path 分发给对应的 HttpRequestHandler 处理。
HttpRequestHandlerHttp request 处理器。
ProtocolServiceFactoryHttp 服务实例工厂,用于生成 ProtocolService 实例。

类名功能
ClientClient 类,用户可以通过 Client 实例发送 HTTP/1.1 或 HTTP/2 请求。
ClientBuilder用于 Client 实例的构建,Client 没有公开的构造函数,用户只能通过 ClientBuilder 得到 Client 实例。ClientBuilder 文档中未明确说明支持版本的配置,在 HTTP/1.1 与 HTTP/2 都会生效。
CookieHTTP 本身是无状态的,server 为了知道 client 的状态,提供个性化的服务,便可以通过 Cookie 来维护一个有状态的会话。
FileHandler用于处理文件下载或者文件上传。
FuncHandlerHttpRequestHandler 接口包装类,把单个函数包装成 HttpRequestHandler。
HttpContextHttp 请求上下文,作为 HttpRequestHandler.handle 函数的参数在服务端使用。
HttpHeaders用于表示 Http 报文中的 header 和 trailer,定义了相关增、删、改、查操作。
HttpRequestHttp 请求类。
HttpRequestBuilderHttpRequestBuilder 类用于构造 HttpRequest 实例。
HttpResponseHttp 响应类。
HttpResponseBuilder用于构造 HttpResponse 实例。
HttpResponsePusherHTTP/2 服务器推送。
HttpResponseWriterHTTP response消息体 Writer,支持用户控制消息体的发送过程。
NotFoundHandler便捷的 Http 请求处理器,404 Not Found 处理器。
OptionsHandler便捷的 Http 处理器,用于处理 OPTIONS 请求。固定返回 "Allow: OPTIONS,GET,HEAD,POST,PUT,DELETE" 响应头。
ProtocolServiceHttp协议服务实例,为单个客户端连接提供 Http 服务,包括对客户端 request 报文的解析、 request 的分发处理、 response 的发送等。
RedirectHandler便捷的 Http 处理器,用于回复重定向响应。
Server提供 HTTP 服务的 Server 类。
ServerBuilder提供 Server 实例构建器。
WebSocket提供 WebSocket 服务的相关类,提供 WebSocket 连接的读、写、关闭等函数。用户通过 upgradeFrom 函数以获取 WebSocket 连接。
WebSocketFrameWebSocket 用于读的基本单元。

枚举

枚举名功能
FileHandlerType用于设置 FileHandler 是上传还是下载模式。
Protocol定义 HTTP 协议类型枚举。
WebSocketFrameType定义 WebSocketFrame 的枚举类型。

结构体

结构体名功能
HttpStatusCode用来表示网页服务器超文本传输协议响应状态的 3 位数字代码。
ServicePoolConfigHttp Server 协程池配置。
TransportConfig传输层配置类,服务器建立连接使用的传输层配置。

异常类

异常类名功能
ConnectionExceptionHttp 的tcp连接异常类。
CoroutinePoolRejectExceptionHttp 的协程池拒绝请求处理异常类。
HttpExceptionHttp 的通用异常类。
HttpStatusExceptionHttp 的响应状态异常类。
HttpTimeoutExceptionHttp 的超时异常类。
WebSocketExceptionWebSocket 的通用异常类。

函数

func handleError(HttpContext, UInt16)

public func handleError(ctx: HttpContext, code: UInt16): Unit

功能:便捷的 Http 请求处理函数,用于回复错误请求。

参数:

  • ctx: HttpContext - Http 请求上下文。
  • code: UInt16 - Http 响应码。

func notFound(HttpContext)

public func notFound(ctx: HttpContext): Unit

功能:便捷的 Http 请求处理函数,用于回复 404 响应。

参数:

func upgrade(HttpContext)

public func upgrade(ctx: HttpContext): StreamingSocket

功能:在 handler 内获取 StreamingSocket,可用于支持协议升级和处理 CONNECT 请求。

  • 调用该函数时,将首先根据 ctx.responseBuilder 发送响应,仅发送状态码和响应头。
  • 调用该函数时,将把 ctx.request.body 置空,后续无法通过 body.read(...) 读数据,未读完的 body 数据将留存在返回的 StreamingSocket 中。

参数:

返回值:

  • StreamingSocket - 底层连接(对于 HTTP/2 是一个 stream),可用于后续读写。

异常:

  • HttpException - 获取底层连接(对于 HTTP/2 是一个 stream)失败。

接口

interface CookieJar

public interface CookieJar {
    prop isHttp: Bool
    prop rejectPublicSuffixes: ArrayList<String>
    static func createDefaultCookieJar(rejectPublicSuffixes: ArrayList<String>, isHttp: Bool): CookieJar
    static func parseSetCookieHeader(response: HttpResponse): ArrayList<Cookie>
    static func toCookieString(cookies: ArrayList<Cookie>): String
    func clear(): Unit
    func getCookies(url: URL): ArrayList<Cookie>
    func removeCookies(domain: String): Unit
    func storeCookies(url: URL, cookies: ArrayList<Cookie>): Unit
}

功能:CookieJarClient 用来管理 Cookie 的工具。

其有两个静态函数:

如果 Client 配置了 CookieJar,那么 Cookie 的解析收发都是自动的。

说明

prop isHttp

prop isHttp: Bool

功能:该 CookieJar 是否用于 HTTP 协议。

  • 若 isHttp 为 true, 则只会存储来自于 HTTP 协议的 Cookie
  • 若 isHttp 为 false, 则只会存储来自非 HTTP 协议的 Cookie,且不会存储发送设置了 httpOnly 的 Cookie

类型:Bool

prop rejectPublicSuffixes

prop rejectPublicSuffixes: ArrayList<String>

功能:获取 public suffixes 配置,该配置是一个 domain 黑名单,会拒绝 domain 值为 public suffixes 的 Cookie

说明:

如果该 Cookie 来自于与 domain 相同的 host,黑名单就不会生效。

类型:ArrayList<String>

static func createDefaultCookieJar(ArrayList<String>, Bool)

static func createDefaultCookieJar(rejectPublicSuffixes: ArrayList<String>, isHttp: Bool): CookieJar

功能:构建默认的管理 CookieCookieJar 实例。

默认的 CookieJar 的管理要求参考 RFC 6265 5.3.

参数:

  • rejectPublicSuffixes: ArrayList<String> - 用户配置的 public suffixes,Cookie 管理为了安全会拒绝 domain 值为 public suffixes 的 cookie(除非该 Cookie 来自于与 domain 相同的 host),public suffixes 见 PUBLIC SUFFIX LIST
  • isHttp: Bool - 该 CookieJar 是否用于 HTTP 协议,isHttp 为 true 则只会存储来自于 HTTP 协议的 Cookie

返回值:

static func parseSetCookieHeader(HttpResponse)

static func parseSetCookieHeader(response: HttpResponse): ArrayList<Cookie>

功能:解析 response 中的 Set-Cookie header。

该函数解析 response 中的 Set-Cookie header,并返回解析出的 ArrayList<Cookie>,解析 Set-Cookie header 的具体规则见 RFC 6265 5.2.

参数:

返回值:

  • ArrayList<Cookie> - 从 response 中解析出的 ArrayList<Cookie> 数组。

static func toCookieString(ArrayList<Cookie>)

static func toCookieString(cookies: ArrayList<Cookie>): String

功能:将 ArrayList<Cookie> 转成字符串,用于 Cookie header。

该函数会将传入的 ArrayList<Cookie> 数组转成协议规定的 Cookie header 的字符串形式,见 RFC 6265 5.4.4.

参数:

  • cookies: ArrayList<Cookie> - 所需转成 Cookie header 字符串的 ArrayList<Cookie>。

返回值:

  • String - 用于 Cookie header 的字符串。

func clear()

func clear(): Unit

功能:清除全部 Cookie

默认实现 CookieJarImpl 会清除 CookieJar 中的所有 Cookie

func getCookies(URL)

func getCookies(url: URL): ArrayList<Cookie>

功能:从 CookieJar 中取出 ArrayList<Cookie>。

默认实现 cookieJarImpl 的取 ArrayList<Cookie> 函数的具体要求见 RFC 6265 5.4.,对取出的 ArrayList<Cookie> 调用 toCookieString 可以将取出的 ArrayList<Cookie> 转成 Cookie header 的 value 字符串。

参数:

  • url: URL - 所要取出 ArrayList<Cookie> 的 url。

返回值:

func removeCookies(String)

func removeCookies(domain: String): Unit

功能:从 CookieJar 中移除某个 domain 的 Cookie

说明:

默认实现 CookieJarImpl 的移除某个 domain 的 Cookie 只会移除特定 domain 的 Cookie,domain 的 subdomain 的 Cookie 并不会移除。

参数:

  • domain: String - 所要移除 Cookie 的域名。

异常:

  • IllegalArgumentException - 如果传入的 domain 为空字符串或者非法,则抛出该异常,合法的 domain 规则见 Cookie 的参数文档。

func storeCookies(URL, ArrayList<Cookie>)

func storeCookies(url: URL, cookies: ArrayList<Cookie>): Unit

功能:将 ArrayList<Cookie> 存进 CookieJar

如果往 CookieJar 中存 Cookie 时超过了上限(3000 条),那么至少清除 CookieJar 中 1000 条 Cookie 再往里存储。清除 CookieJarCookie 的优先级见 RFC 6265 5.3.12.

Cookie按如下顺序清除:

  • 过期的 Cookie
  • 相同 domain 中超过 50 条以上的部分;
  • 所有 Cookie具有相同优先级的 Cookie 则优先删除 last-access 属性更早的。

参数:

  • url: URL - 产生该 Cookie 的 url。
  • cookies: ArrayList<Cookie> - 需要存储的 ArrayList<Cookie>。

interface HttpRequestDistributor

public interface HttpRequestDistributor {
    func register(path: String, handler: HttpRequestHandler): Unit
    func register(path: String, handler: (HttpContext) -> Unit): Unit
    func distribute(path: String): HttpRequestHandler
}

功能:Http request 分发器接口,将一个 request 按照 url 中的 path 分发给对应的 HttpRequestHandler 处理。

说明:

本实现提供一个默认的 HttpRequestDistributor,该 distributor 非线程安全。 默认实现提供仓颉标准库中 HTTP/1.1、HTTP/2 的 ProtocolService 实例。 且只能在启动 server 前 register,启动后再次 register,结果未定义。 如果用户希望在启动 server 后还能够 register,需要自己提供一个线程安全的 HttpRequestDistributor 实现。

func distribute(String)

func distribute(path: String): HttpRequestHandler

功能:分发请求处理器,未找到对应请求处理器时,将返回 NotFoundHandler 以返回 404 状态码。

参数:

  • path: String - 请求路径。

返回值:

func register(String, (HttpContext) -> Unit)

func register(path: String, handler: (HttpContext) -> Unit): Unit

功能:注册请求处理器。

参数:

  • path: String - 请求路径。
  • handler: (HttpContext) ->Unit - 请求处理函数。

异常:

func register(String, HttpRequestHandler)

func register(path: String, handler: HttpRequestHandler): Unit

功能:注册请求处理器。

参数:

异常:

interface HttpRequestHandler

public interface HttpRequestHandler {
    func handle(ctx: HttpContext): Unit
}

功能:Http request 处理器。

http server 端通过 handler 处理来自客户端的 http request;在 handler 中用户可以获取 http request 的详细信息,包括 header、body;在 handler 中,用户可以构造 http response,包括 header、body,并且可以直接发送 response 给客户端,也可交由 server 发送。

用户在构建 http server 时,需手动通过 server 的 HttpRequestDistributor 注册一个或多个 handler,当一个客户端 http request 被接收,distributor 按照 request 中 url 的 path 分发给对应的 handler 处理。

注意:

应用程序应注意 DNS 重绑定攻击,即在 handler 的处理逻辑中对 request 中的 Host 请求头的值进行合法性校验,校验该值是否为此应用程序所认可的权威主机名。

func handle(HttpContext)

func handle(ctx: HttpContext): Unit

功能:处理 Http 请求。

参数:

interface ProtocolServiceFactory

public interface ProtocolServiceFactory {
    func create(protocol: Protocol, socket: StreamingSocket): ProtocolService
}

功能:Http 服务实例工厂,用于生成 ProtocolService 实例。

ServerBuilder 提供默认的实现。默认实现提供仓颉标准库中 HTTP/1.1、HTTP/2 的 ProtocolService 实例。

func create(Protocol, StreamingSocket)

func create(protocol: Protocol, socket: StreamingSocket): ProtocolService

功能:根据协议创建协议服务实例。

参数:

返回值:

  • ProtocolService - 协议服务实例。

class Client

public class Client

功能:发送 Http request、随时关闭等。用户可以通过 Client 实例发送 HTTP/1.1 或 HTTP/2 请求。

说明:

Client 文档中未明确说明支持版本的配置,在 HTTP/1.1 与 HTTP/2 都会生效。

prop autoRedirect

public prop autoRedirect: Bool

功能:客户端是否会自动进行重定向,304 状态码默认不重定向。

类型:Bool

prop connector

public prop connector: (SocketAddress) -> StreamingSocket

功能:客户端调用此函数获取到服务器的连接。

类型:(SocketAddress) -> StreamingSocket

prop cookieJar

public prop cookieJar: ?CookieJar

功能:用于存储客户端所有 Cookie,如果配置为 None,则不会启用 Cookie

类型:?CookieJar

prop enablePush

public prop enablePush: Bool

功能:客户端 HTTP/2 是否支持服务器推送,默认值为 true。

类型:Bool

prop headerTableSize

public prop headerTableSize: UInt32

功能:获取客户端 HTTP/2 Hpack 动态表的初始值,默认值为 4096。

类型:UInt32

prop httpProxy

public prop httpProxy: String

功能:获取客户端 http 代理,默认使用系统环境变量 http_proxy 的值,用字符串表示,格式为:"http://host:port",例如:"http://192.168.1.1:80"

类型:String

prop httpsProxy

public prop httpsProxy: String

功能:获取客户端 https 代理,默认使用系统环境变量 https_proxy 的值,用字符串表示,格式为:"http://host:port",例如:"http://192.168.1.1:443"

类型:String

prop initialWindowSize

public prop initialWindowSize: UInt32

功能:获取客户端 HTTP/2 流控窗口初始值,默认值为 65535 ,取值范围为 0 至 2^31 - 1。

类型:UInt32

prop logger

public prop logger: Logger

功能:获取客户端日志记录器,设置 logger.level 将立即生效,记录器应该是线程安全的。

类型:Logger

prop maxConcurrentStreams

public prop maxConcurrentStreams: UInt32

功能:获取客户端 HTTP/2 初始最大并发流数量,默认值为 2^31 - 1。

类型:UInt32

prop maxFrameSize

public prop maxFrameSize: UInt32

功能:获取客户端 HTTP/2 初始最大帧大小。默认值为 16384. 取值范围为 2^14 至 2^24 - 1。

类型:UInt32

prop maxHeaderListSize

public prop maxHeaderListSize: UInt32

功能:获取客户端支持的 HTTP/2 最大头部(Header)大小。这个大小指的是响应头部中所有头部字段(Header Field)的最大允许长度之和,其中包括所有字段名称(name)的长度、字段值(value)的长度以及每个字段自动添加的伪头开销(通常每个字段会有32字节的开销,这包括了 HTTP/2 协议本身为头部字段添加的伪头部信息)。默认情况下,这个最大长度被设置为 UInt32.Max。

类型:UInt32

prop poolSize

public prop poolSize: Int64

功能:配置 HTTP/1.1 客户端使用的连接池的大小,亦可表示对同一个主机(host:port)同时存在的连接数的最大值。

类型:Int64

prop readTimeout

public prop readTimeout: Duration

功能:获取客户端设定的读取整个响应的超时时间,默认值为 15 秒。

类型:Duration

prop writeTimeout

public prop writeTimeout: Duration

功能:获取客户端设定的写请求的超时时间,默认值为 15 秒。

类型:Duration

func close()

public func close(): Unit

功能:关闭客户端建立的所有连接,调用后不能继续发送请求。

func connect(String, HttpHeaders, Protocol)

public func connect(url: String, header!: HttpHeaders = HttpHeaders(), version!: Protocol = HTTP1_1): (HttpResponse, ?StreamingSocket)

功能:发送 CONNECT 请求与服务器建立隧道,返回建连成功后的连接,连接由用户负责关闭。服务器返回 2xx 表示建连成功,否则建连失败(不支持自动重定向,3xx 也视为失败)。

参数:

  • url: String - 请求的 url。
  • header!: HttpHeaders - 请求头,默认为空请求头。
  • version!: Protocol - 请求的协议,默认为 HTTP1_1

返回值:

  • (HttpResponse, ?StreamingSocket) - 返回元组类型,其中 HttpResponse 实例表示服务器返回的响应体,Option<StreamingSocket> 实例表示请求成功时返回 headers 之后连接。

异常:

  • UrlSyntaxException - 当参数 url 不符合 URL 解析规范时,抛出异常。
  • IllegalArgumentException - 当被编码的字符不符合 UTF-8 的字节序列规则时,抛出异常。
  • 其余同 func send。

func delete(String)

public func delete(url: String): HttpResponse

功能:请求方法为 DELETE 的便捷请求函数。

参数:

  • url: String - 请求的 url。

返回值:

异常:

  • UrlSyntaxException - 当参数 url 不符合 URL 解析规范时,抛出异常。
  • IllegalArgumentException - 当被编码的字符不符合 UTF-8 的字节序列规则时,抛出异常。
  • 其余同 func send。

func get(String)

public func get(url: String): HttpResponse

功能:请求方法为 GET 的便捷请求函数。

参数:

  • url: String - 请求的 url。

返回值:

异常:

  • UrlSyntaxException - 当参数 url 不符合 URL 解析规范时,抛出异常。
  • IllegalArgumentException - 当被编码的字符不符合 UTF-8 的字节序列规则时,抛出异常。
  • 其余同 func send。

func getTlsConfig()

public func getTlsConfig(): ?TlsClientConfig

功能:获取客户端设定的 TLS 层配置。

返回值:

  • ?TlsClientConfig - 客户端设定的 TLS 层配置,如果没有设置则返回 None。

func head(String)

public func head(url: String): HttpResponse

功能:请求方法为 HEAD 的便捷请求函数。

参数:

  • url: String - 请求的 url。

返回值:

异常:

  • UrlSyntaxException - 当参数 url 不符合 URL 解析规范时,抛出异常。
  • IllegalArgumentException - 当被编码的字符不符合 UTF-8 的字节序列规则时,抛出异常。
  • 其余同 func send。

func options(String)

public func options(url: String): HttpResponse

功能:请求方法为 OPTIONS 的便捷请求函数。

参数:

  • url: String - 请求的 url。

返回值:

异常:

  • UrlSyntaxException - 当参数 url 不符合 URL 解析规范时,抛出异常。
  • IllegalArgumentException - 当被编码的字符不符合 UTF-8 的字节序列规则时,抛出异常。
  • 其余同 func send。

func post(String, Array<UInt8>)

public func post(url: String, body: Array<UInt8>): HttpResponse

功能:请求方法为 POST 的便捷请求函数。

参数:

  • url: String - 请求的 url。
  • body: Array<UInt8> - 请求体。

返回值:

异常:

  • UrlSyntaxException - 当参数 url 不符合 URL 解析规范时,抛出异常。
  • IllegalArgumentException - 当被编码的字符不符合 UTF-8 的字节序列规则时,抛出异常。
  • 其余同 func send。

func post(String, InputStream)

public func post(url: String, body: InputStream): HttpResponse

功能:请求方法为 POST 的便捷请求函数。

参数:

  • url: String - 请求的 url。
  • body: InputStream - 请求体。

返回值:

异常:

  • UrlSyntaxException - 当参数 url 不符合 URL 解析规范时,抛出异常。
  • IllegalArgumentException - 当被编码的字符不符合 UTF-8 的字节序列规则时,抛出异常。
  • 其余同 func send。

func post(String, String)

public func post(url: String, body: String): HttpResponse

功能:请求方法为 POST 的便捷请求函数。

参数:

  • url: String - 请求的 url。
  • body: String - 请求体。

返回值:

异常:

  • UrlSyntaxException - 当参数 url 不符合 URL 解析规范时,抛出异常。
  • IllegalArgumentException - 当被编码的字符不符合 UTF-8 的字节序列规则时,抛出异常。
  • 其余同 func send。

func put(String, Array<UInt8>)

public func put(url: String, body: Array<UInt8>): HttpResponse

功能:请求方法为 PUT 的便捷请求函数。

参数:

  • url: String - 请求的 url。
  • body: Array<UInt8> - 请求体。

返回值:

异常:

  • UrlSyntaxException - 当参数 url 不符合 URL 解析规范时,抛出异常。
  • IllegalArgumentException - 当被编码的字符不符合 UTF-8 的字节序列规则时,抛出异常。
  • 其余同 func send。

func put(String, InputStream)

public func put(url: String, body: InputStream): HttpResponse

功能:请求方法为 PUT 的便捷请求函数。

参数:

  • url: String - 请求的 url。
  • body: InputStream - 请求体。

返回值:

异常:

  • UrlSyntaxException - 当参数 url 不符合 URL 解析规范时,抛出异常。
  • IllegalArgumentException - 当被编码的字符不符合 UTF-8 的字节序列规则时,抛出异常。
  • 其余同 func send。

func put(String, String)

public func put(url: String, body: String): HttpResponse

功能:请求方法为 PUT 的便捷请求函数。

参数:

  • url: String - 请求的 url。
  • body: String - 请求体。

返回值:

异常:

  • UrlSyntaxException - 当参数 url 不符合 URL 解析规范时,抛出异常。
  • IllegalArgumentException - 当被编码的字符不符合 UTF-8 的字节序列规则时,抛出异常。
  • 其余同 func send。

func send(HttpRequest)

public func send(req: HttpRequest): HttpResponse

功能:通用请求函数,发送 HttpRequest 到 url 中的服务器,接收 HttpResponse

注意:

  • 对于 HTTP/1.1,如果请求中有 body 要发,那么需要保证 Content-Length 和 Transfer-Encoding: chunked 必有且只有一个,以 chunked 形式发时,每段 chunk 最大为 8192 字节;如果用户发送的 body 为自己实现的 InputStream 类,则需要自己保证 Content-Length和 Transfer-Encoding: chunked 设置且只设置了一个;如果用户采用默认的 body 发送,Content-Length 和 Transfer-Encoding: chunked 都缺失时,我们会为其补上 Content-Length header,值为 body.size;
  • 用户如果设置了 Content-Length,则需要保证其正确性:如果所发 body 的内容大于等于 Content-Length 的值,我们会发送长度为 Content-Length 值的数据;如果所发 body 的内容小于 Content-Length 的值,此时如果 body 是默认的 body,则会抛出 HttpException,如果 body是用户自己实现的 InputStream 类,其行为便无法保证(可能会造成服务器端的读 request 超时或者客户端的收 response 超时);
  • 升级函数通过 WebSocket 的 upgradeFromClient 或 Clientupgrade 接口发出,调用 client 的其他函数发送 upgrade 请求会抛出异常;
  • 协议规定 TRACE 请求无法携带内容,故用户发送带有 body 的 TRACE 请求时会抛出异常;
  • HTTP/1.1 默认对同一个服务器的连接数不超过 10 个。response 的 body 需要用户调用 body.read(buf: Array<Byte>) 函数去读。body 被读完后,连接才能被客户端对象复用,否则请求相同的服务器也会新建连接。新建连接时如果连接数超出限制则会抛出 HttpException
  • body.read 函数将 body 读完之后返回 0,如果读的时候连接断开会抛出 ConnectionException
  • HTTP/1.1 的升级请求如果收到 101 响应,则表示切换协议,此连接便不归 client 管理;
  • 下文的快捷请求函数的注意点与 send 相同。

参数:

返回值:

异常:

func upgrade(HttpRequest)

public func upgrade(req: HttpRequest): (HttpResponse, ?StreamingSocket)

功能:发送请求并升级协议,用户设置请求头,返回升级后的连接(如果升级成功),连接由用户负责关闭。

说明:

  • 服务器返回 101 表示升级成功,获取到了 StreamingSocket;
  • 必选请求头:
    • Upgrade: protocol-name ["/" protocol-version];
    • Connection: Upgrade (在请求头包含 Upgrade 字段时会自动添加);
  • 不支持 HTTP/1.0、HTTP/2;
  • 不支持 HTTP/1.1 CONNECT 方法的 HttpRequest

参数:

返回值:

  • (HttpResponse,?StreamingSocket) - 返回一个元组,HttpResponse 实例表示服务器返回的响应,?StreamingSocket 实例表示获取的底层连接,升级失败时为 None。

异常:

  • HttpException -
    • 请求报文或响应报文不符合协议;
    • 请求报文不含 Upgrade 头;
    • 发送 CONNECT 请求;
    • 发送带 body 的 TRACE 请求;
  • SocketException,ConnectionException - Socket 连接出现异常或被关闭;
  • SocketTimeoutException - Socket 连接超时;
  • TlsException - Tls 连接建立失败或通信异常。

class ClientBuilder

public class ClientBuilder {
    public init()
}

功能:用于 Client 实例的构建,Client 没有公开的构造函数,用户只能通过 ClientBuilder 得到 Client 实例。ClientBuilder 文档中未明确说明支持版本的配置,在 HTTP/1.1 与 HTTP/2 都会生效。

说明:

该类提供了一系列配置参数的函数,配置完成后调用 build 函数构造出 Client 实例。配置函数中说明了参数的取值范围,但配置函数本身不做参数合法性校验,build 时统一进行校验。

init()

public init()

功能:创建新的 ClientBuilder 实例。

func autoRedirect(Bool)

public func autoRedirect(auto: Bool): ClientBuilder

功能:配置客户端是否会自动进行重定向。重定向会请求 Location 头的资源,协议规定,Location 只能包含一个 URI 引用Location = URI-reference,详见 RFC 9110 10.2.2.。304 状态码默认不重定向。

参数:

  • auto: Bool - 默认值为 true,即开启自动重定向。

返回值:

func build()

public func build(): Client

功能:构造 Client 实例。

此处会对各参数的值进行检查,如果取值非法,将抛出异常。各参数的取值范围详见设置参数相关的函数。

返回值:

异常:

  • IllegalArgumentException - 配置项有非法参数时抛出此异常。

func connector((SocketAddress)->StreamingSocket)

public func connector(c: (SocketAddress) -> StreamingSocket): ClientBuilder

功能:客户端调用此函数获取到服务器的连接。

参数:

  • c: (SocketAddress) ->StreamingSocket - 入参为 SocketAddress 实例,返回值类型为 StreamingSocket 的函数类型。

返回值:

func cookieJar(?CookieJar)

public func cookieJar(cookieJar: ?CookieJar): ClientBuilder

功能:用于存储客户端所有 Cookie

参数:

返回值:

func enablePush(Bool)

public func enablePush(enable: Bool): ClientBuilder

功能:配置客户端 HTTP/2 是否支持服务器推送。

参数:

  • enable: Bool - 默认值 true。

返回值:

func headerTableSize(UInt32)

public func headerTableSize(size: UInt32): ClientBuilder

功能:配置客户端 HTTP/2 Hpack 动态表初始值。

参数:

  • size: UInt32 - 默认值 4096。

返回值:

func httpProxy(String)

public func httpProxy(addr: String): ClientBuilder

功能:设置客户端 http 代理,默认使用系统环境变量 http_proxy 的值。

参数:

  • addr: String - 格式为:"http://host:port",例如:"http://192.168.1.1:80"

返回值:

func httpsProxy(String)

public func httpsProxy(addr: String): ClientBuilder

功能:设置客户端 https 代理,默认使用系统环境变量 https_proxy 的值。

参数:

  • addr: String - 格式为:"http://host:port",例如:"http://192.168.1.1:443"

返回值:

func initialWindowSize(UInt32)

public func initialWindowSize(size: UInt32): ClientBuilder

功能:配置客户端 HTTP/2 流控窗口初始值。

参数:

  • size: UInt32 - 默认值 65535 , 取值范围为 0 至 2^31 - 1。

返回值:

func logger(Logger)

public func logger(logger: Logger): ClientBuilder

功能:设定客户端的 logger,默认 logger 级别为 INFO,logger 内容将写入 Console.stdout。

参数:

  • logger: Logger - 需要是线程安全的,默认使用内置线程安全 logger。

返回值:

func maxConcurrentStreams(UInt32)

public func maxConcurrentStreams(size: UInt32): ClientBuilder

功能:配置客户端 HTTP/2 初始最大并发流数量。

参数:

  • size: UInt32 - 默认值为 2^31 - 1。

返回值:

func maxFrameSize(UInt32)

public func maxFrameSize(size: UInt32): ClientBuilder

功能:配置客户端 HTTP/2 初始最大帧大小。

参数:

  • size: UInt32 - 默认值为 16384。取值范围为 2^14 至 2^24 - 1。

返回值:

func maxHeaderListSize(UInt32)

public func maxHeaderListSize(size: UInt32): ClientBuilder

功能:获取客户端支持的 HTTP/2 最大头部(Header)大小。这个大小指的是响应头部中所有头部字段(Header Field)的最大允许长度之和,其中包括所有字段名称(name)的长度、字段值(value)的长度以及每个字段自动添加的伪头开销(通常每个字段会有 32 字节的开销,这包括了 HTTP/2 协议本身为头部字段添加的伪头部信息)。默认情况下,这个最大长度被设置为 UInt32.Max。

参数:

  • size: UInt32 - 客户端接收的 HTTP/2 响应 headers 最大长度。

返回值:

func noProxy()

public func noProxy(): ClientBuilder

功能:调用此函数后,客户端不使用任何代理。

返回值:

func poolSize(Int64)

public func poolSize(size: Int64): ClientBuilder

功能:配置 HTTP/1.1 客户端使用的连接池的大小,亦可表示对同一个主机(host:port)同时存在的连接数的最大值。

参数:

  • size: Int64 - 默认 10,poolSize 需要大于 0。

返回值:

异常:

  • HttpException - 如果传参小于等于 0,则会抛出该异常。

func readTimeout(Duration)

public func readTimeout(timeout: Duration): ClientBuilder

功能:设定客户端读取一个响应的最大时长。

参数:

  • timeout: Duration - 默认 15s,Duration.Max 代表不限制,如果传入负的 Duration 将被替换为 Duration.Zero。

返回值:

func tlsConfig(TlsClientConfig)

public func tlsConfig(config: TlsClientConfig): ClientBuilder

功能:设置 TLS 层配置,默认不对其进行设置。

参数:

  • config: TlsClientConfig - 设定支持 tls 客户端需要的配置信息。

返回值:

func writeTimeout(Duration)

public func writeTimeout(timeout: Duration): ClientBuilder

功能:设定客户端发送一个请求的最大时长。

参数:

  • timeout: Duration - 默认 15 秒,Duration.Max 代表不限制,如果传入负的 Duration 将被替换为 Duration.Zero。

返回值:

public class Cookie {
    public init(name: String, value: String, expires!: ?DateTime = None, maxAge!: ?Int64 = None,
        domain!: String = "", path!: String = "", secure!: Bool = false, httpOnly!: Bool = false)
}

功能:HTTP 本身是无状态的,server 为了知道 client 的状态,提供个性化的服务,便可以通过 Cookie 来维护一个有状态的会话。

说明:

  • 用户首次访问某站点时,server 通过 Set-Cookie header 将 name/value 对,以及 attribute-value 传给用户代理;用户代理随后对该站点的请求中便可以将 name/value 加入到 Cookie header 中;
  • Cookie 类提供了构建 Cookie 对象,并将 Cookie 对象转成 Set-Cookie header 值的函数,提供了获取 Cookie 对象各属性值的函数;
  • Cookie 的各个属性的要求和作用见 RFC 6265
  • 下文中 cookie-name,cookie-value,expires-av 等名字采用 RFC 6265 中的术语,详情请见协议。

prop cookieName

public prop cookieName: String

功能:获取 Cookie 对象的 cookie-name 值。

类型:String

prop cookieValue

public prop cookieValue: String

功能:获取 Cookie 对象的 cookie-value 值。

类型:String

prop domain

public prop domain: String

功能:获取 Cookie 对象的 domain-av 值。

类型:String

prop expires

public prop expires: ?DateTime

功能:获取 Cookie 对象的 expires-av 值。

类型:?DateTime

prop httpOnly

public prop httpOnly: Bool

功能:获取 Cookie 对象的 httpOnly-av 值。

类型:Bool

prop maxAge

public prop maxAge: ?Int64

功能:获取 Cookie 对象的 max-age-av 值。

类型:?Int64

prop others

public prop others: ArrayList<String>

功能:获取未被解析的属性。

类型:ArrayList<String>

prop path

public prop path: String

功能:获取 Cookie 对象的 path-av 值。

类型:String

prop secure

public prop secure: Bool

功能:获取 Cookie 对象的 secure-av 值。

类型:Bool

init(String, String, ?DateTime, ?Int64, String, String, Bool, Bool)

public init(name: String, value: String, expires!: ?DateTime = None, maxAge!: ?Int64 = None,
    domain!: String = "", path!: String = "", secure!: Bool = false, httpOnly!: Bool = false)

功能:提供 Cookie 对象的公开构造器说明:该构造器会检查传入的各项属性是否满足协议要求,如果不满足则会产生 IllegalArgumentException。具体要求见 RFC 6265 4.1.1.

注意:

Cookie 各属性中只有 cookie-name,cookie-value 是必需的,必须传入 name,value 参数,但 value 参数可以传入空字符串。

参数:

  • name: String - cookie-name 属性。

    name         = token 
    token        = 1*tchar
    tchar        = "!" / "#" / "$" / "%" / "&" / "'" / "*"
                   / "+" / "-" / "." / "^" / "_" / "`" / "|" / "~"
                   / DIGIT / ALPHA
    
  • value: String - cookie-value 属性。

    value        = *cookie-octet / ( DQUOTE *cookie-octet DQUOTE )
    cookie-octet = %x21 / %x23-2B / %x2D-3A / %x3C-5B / %x5D-7E
                ; US-ASCII characters excluding CTLs,
                ; whitespace DQUOTE, comma, semicolon,
                ; and backslash
    
  • expires!: ?DateTime - 设置 Cookie 的过期时间,默认为 None,时间必须在 1601 年之后。

  • maxAge!: ?Int64 - Cookie 的最大生命周期,默认为 None,如果 Cookie 既有 expires 属性,也有 maxAge,则表示该 Cookie 只维护到会话结束(维护到 Client 关闭之前,Client 关闭之后设置了过期的 Cookie 也不再维护)。

    max-age-av     = "Max-Age=" non-zero-digit *DIGIT
    non-zero-digit = %x31-39
                    ; digits 1 through 9
    DIGIT          = %x30-39
                    ; digits 0 through 9
    
  • domain!: String - 默认为空字符串,表示该收到该 Cookie 的客户端只会发送该 Cookie 给原始服务器。如果设置了合法的 domain,则收到该 Cookie 的客户端只会发送该 Cookie 给所有该 domain 的子域(且满足其他属性条件要求才会发)。

    domain          = <subdomain> | " "
    <subdomain>   ::= <label> | <subdomain> "." <label>
    <label>       ::= <letter> [ [ <ldh-str> ] <let-dig> ]
    <ldh-str>     ::= <let-dig-hyp> | <let-dig-hyp> <ldh-str>
    <let-dig-hyp> ::= <let-dig> | "-"
    <let-dig>     ::= <letter> | <digit>
    <letter>      ::= any one of the 52 alphabetic characters A through Z in upper case and a through z in lower case
    <digit>       ::= any one of the ten digits 0 through 9
    RFC 1035 2.3.1.
    而 RFC 1123 2.1. 放松了对 label 首字符必须是 letter 的限制
    因此,对 domain 的要求为:
    1、总长度小于等于 255,由若干个 label 组成
    2、label 与 label 之间通过 "." 分隔,每个 label 长度小于等于 63
    3、label 的开头和结尾必须是数字或者字母,label 的中间字符必须是数字、字母或者 "-"
    
  • path!: String - 默认为空字符串,客户端会根据 url 计算出默认的 path 属性,见 RFC 6265 5.1.4.。 收到该 Cookie 的客户端只会发送该 Cookie 给所有该 path 的子目录(且满足其他属性条件要求才会发)。

    path            = <any RUNE except CTLs or ";">
    RUNE            = <any [USASCII] character>
    CTLs            = <controls>
    
  • secure!: Bool - 默认为 false,如果设置为 true,该 Cookie 只会在安全协议请求中发送。

  • httpOnly!: Bool - 默认为 false,如果设置为 true,该 Cookie 只会在 HTTP 协议请求中发送。

异常:

  • IllegalArgumentException - 传入的参数不符合协议要求时抛出异常。

func toSetCookieString()

public func toSetCookieString(): String

功能:提供将 Cookie 转成字符串形式的函数,方便 server 设置 Set-Cookie header。

注意:

  • Cookie 各属性(包含 name,value)在对象创建时就被检查了,因此 toSetCookieString() 函数不会产生异常;
  • Cookie 必需的属性是 cookie-pair 即 cookie-name "=" cookie-value,cookie-value 可以为空字符串,toSetCookieString() 函数只会将设置过的属性写入字符串,即只有 "cookie-name=" 是必有的,其余部分是否存在取决于是否设置。

返回值:

  • String - 字符串对象,用于设置 Set-Cookie header。

class FileHandler

public class FileHandler <: HttpRequestHandler {
    public init(path: String, handlerType!: FileHandlerType = DownLoad, bufferSize!: Int64 = 64 * 1024)
}

功能:用于处理文件下载或者文件上传。

文件下载:

  • 构造 FileHandler 时需要传入待下载文件的路径,目前一个 FileHandler 只能处理一个文件的下载;
  • 下载文件只能使用 GET 请求,其他请求返回 400 状态码;
  • 文件如果不存在,将返回 404 状态码。

文件上传:

  • 构造 FileHandler 时需要传入一个存在的目录路径,上传到服务端的文件将保存在这个目录中;
  • 上传文件时只能使用 POST 请求,其他请求返回 400 状态码;
  • 上传数据的 http 报文必须是 multipart/form-data 格式的,Content-Type 头字段的值为 multipart/form-data; boundary=----XXXXX
  • 上传文件的文件名存放在 form-data 数据报文中,报文数据格式为 Content-Disposition: form-data; name="xxx"; filename="xxxx",文件名是 filename 字段的值;
  • 目前 form-data 中必须包含 filename 字段;
  • 如果请求报文不正确,将返回 400 状态码;
  • 如果出现其他异常,例如文件处理异常,将返回 500 状态码。

父类型:

init(String, FileHandlerType, Int64)

public init(path: String, handlerType!: FileHandlerType = DownLoad, bufferSize!: Int64 = 64 * 1024)

功能:FileHandler 的构造函数。

参数:

  • path: String - FileHandler 构造时需要传入的文件或者目录路径字符串,上传模式中只能传入存在的目录路径;路径中存在../时,用户需要确认标准化后的绝对路径是期望传入的路径。
  • handlerType!: FileHandlerType - 构造 FileHandler 时指定当前 FileHandler 的工作模式,默认为 DownLoad 下载模式。
  • bufferSize!: Int64 - 内部从网络读取或者写入的缓冲区大小,默认值为 64*1024(64k),若小于 4096,则使用 4096 作为缓冲区大小。

异常:

  • HttpException - 当 path 不存在时,抛出异常。
  • IllegalArgumentException - 参数错误时抛出异常,如 path 为空或者包含空字符串等。

func handle(HttpContext)

public func handle(ctx: HttpContext): Unit

功能:根据请求对响应数据进行处理。

参数:

class FuncHandler

public class FuncHandler <: HttpRequestHandler {
    public FuncHandler(let handler: (HttpContext) -> Unit)
}

功能:HttpRequestHandler 接口包装类,把单个函数包装成 HttpRequestHandler

父类型:

FuncHandler((HttpContext) -> Unit)

public FuncHandler(let handler: (HttpContext) -> Unit)

功能:FuncHandler 的构造函数。

参数:

  • handler: (HttpContext) -> Unit - 是调用 handle 的处理函数。

func handle(HttpContext)

public func handle(ctx: HttpContext): Unit

功能:处理 Http 请求。

参数:

class HttpContext

public class HttpContext

功能:Http 请求上下文,作为 HttpRequestHandler.handle 函数的参数在服务端使用。

prop clientCertificate

public prop clientCertificate: ?Array<X509Certificate>

功能:获取 Http 客户端证书。

类型:?Array<X509Certificate>

prop request

public prop request: HttpRequest

功能:获取 Http 请求。

类型:HttpRequest

prop responseBuilder

public prop responseBuilder: HttpResponseBuilder

功能:获取 Http 响应构建器。

类型:HttpResponseBuilder

class HttpHeaders

public class HttpHeaders <: Iterable<(String, Collection<String>)>

功能:此类用于表示 Http 报文中的 header 和 trailer,定义了相关增、删、改、查操作。

说明:

  • header 和 trailer 为键值映射集,由若干 field-line 组成,每一个 field-line 包含一个键 (field -name) 和若干值 (field-value)。
  • field-name 由 token 字符组成,不区分大小写,在该类中将转为小写保存。
  • field-value 由 vchar,SP 和 HTAB 组成,vchar 表示可见的 US-ASCII 字符,不得包含前后空格,不得为空值。
  • 详见 rfc 9110

示例:

Example-Field: Foo, Bar
key: Example-Field, value: Foo, Bar
field-name = token
token = 1*tchar
tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*"
/ "+" / "-" / "." / "^" / "_" / "`" / "|" / "~"
/ DIGIT / ALPHA
; any VCHAR, except delimiters

父类型:

  • Iterable<(String, Collection<String>)>

func add(String, String)

public func add(name: String, value: String): Unit

功能:添加指定键值对。如果 name 已经存在,将在其对应的值列表中添加 value;如果 name 不存在,则添加 name 字段及其值 value。

参数:

异常:

  • HttpException - 如果传入的 name/value 包含不合法元素,将抛出此异常。

func del(String)

public func del(name: String): Unit

功能:删除指定 name 对应的键值对。

参数:

  • name: String - 删除的字段名称。

func get(String)

public func get(name: String): Collection<String>

功能:获取指定 name 对应的 value 值。

参数:

  • name: String - 字段名称,不区分大小写。

返回值:

  • Collection<String> - name 对应的 value 集合,如果指定 name 不存在,返回空集合。

func getFirst(String)

public func getFirst(name: String): ?String

功能:获取指定 name 对应的第一个 value 值。

参数:

  • name: String - 字段名称,不区分大小写。

返回值:

  • ?String - name 对应的第一个 value 值,如果指定 name 不存在,返回 None。

func isEmpty()

public func isEmpty(): Bool

功能:判断当前实例是否为空,即没有任何键值对。

返回值:

  • Bool - 如果当前实例为空,返回 true,否则返回 false。

func iterator()

public func iterator(): Iterator<(String, Collection<String>)>

功能:获取迭代器,可用于遍历所有键值对。

返回值:

  • Iterator<(String, Collection<String>)> - 该键值集的迭代器。

func set(String, String)

public func set(name: String, value: String): Unit

功能:设置指定键值对。如果 name 已经存在,传入的 value 将会覆盖之前的值。

参数:

异常:

  • HttpException - 如果传入的 name/values 包含不合法元素,将抛出此异常。

class HttpRequest

public class HttpRequest <: ToString

功能:此类为 Http 请求类。

客户端发送请求时,需要构造一个 HttpRequest 实例,再编码成字节报文发出。

服务端处理请求时,需要把收到的请求解析成 HttpRequest 实例,并传给 handler 处理函数。

父类型:

  • ToString

prop body

public prop body: InputStream

功能:获取 body。

注意:

  • body 不支持并发读取;
  • 默认 InputStream 实现类的 read 函数不支持多次读取。

类型:InputStream

prop bodySize

public prop bodySize: Option<Int64>

功能:获取请求 body 长度。

  • 如果未设置 body,则 bodySize 为 Some(0);
  • 如果 body 长度已知,即通过 Array<UInt8> 或 String 传入 body,或传入的 InputStream 有确定的 length (length >= 0),则 bodySize 为 Some(Int64);
  • 如果 body 长度未知,即通过用户自定义的 InputStream 实例传入 body 且 InputStream 实例没有确定的 length (length < 0),则 bodySize 为 None。

类型:Option<Int64>

prop close

public prop close: Bool

功能:表示该请求 header 是否包含 Connection: close

  • 对于服务端,close 为 true 表示处理完该请求应该关闭连接。
  • 对于客户端,close 为 true 表示如果收到响应后服务端未关闭连接,客户端应主动关闭连接。

类型:Bool

prop form

public prop form: Form

功能:获取请求中的表单信息。

  • 如果请求方法为 POST,PUT,PATCH,且 content-type 包含 application/x-www-form-urlencoded,获取请求 body 部分,用 form 格式解析;
  • 如果请求方法不为 POST,PUT,PATCH,获取请求 url 中 query 部分。

注意:

  • 如果用该接口读取了 body,body 已被消费完,后续将无法通过 body.read 读取 body;
  • 如果 form 不符合 Form 格式,抛 UrlSyntaxException 异常。

类型:Form

prop headers

public prop headers: HttpHeaders

功能:获取 headers,headers 详述见 HttpHeaders 类,获取后,可通过调用 HttpHeaders 实例成员函数,修改该请求的 headers。

类型:HttpHeaders

prop method

public prop method: String

功能:获取 method,如 "GET", "POST",request 实例的 method 无法修改。

类型:String

prop readTimeout

public prop readTimeout: ?Duration

功能:表示该请求的请求级读超时时间。None 表示没有设置;Some(Duration) 表示设置了读超时时间。

类型:?Duration

prop remoteAddr

public prop remoteAddr: String

功能:用于服务端,获取对端地址,即客户端地址,格式为 ip: port,用户无法设置,自定义的 request 对象调用该属性返回 "",服务端 handler 中调用该属性返回客户端地址。

类型:String

prop trailers

public prop trailers: HttpHeaders

功能:获取 trailers,trailers 详述见 HttpHeaders 类,获取后,可通过调用 HttpHeaders 实例成员函数,修改该请求的 trailers。

类型:HttpHeaders

prop url

public prop url: URL

功能:获取 url,表示客户端访问的 url。

类型:URL

prop version

public prop version: Protocol

功能:获取 http 版本,如 HTTP1_1 和 HTTP2_0,request 实例的 version 无法修改。

类型:Protocol

prop writeTimeout

public prop writeTimeout: ?Duration

功能:表示该请求的请求级写超时时间,None 表示没有设置;Some(Duration) 表示设置了写超时时间。

类型:?Duration

func toString()

public override func toString(): String

功能:把请求转换为字符串,包括 start line,headers,body size,trailers。 例如:"GET /path HTTP/1.1\r\nhost: www.example.com\r\n\r\nbody size: 5\r\nbar: foo\r\n"

返回值:

  • String - 请求的字符串表示。

class HttpRequestBuilder

public class HttpRequestBuilder {
    public init()
    public init(request: HttpRequest)
}

功能:HttpRequestBuilder 类用于构造 HttpRequest 实例。

init()

public init()

功能:构造一个新 HttpRequestBuilder

init(HttpRequest)

public init(request: HttpRequest)

功能: 通过 request 构造一个具有 request 属性的 HttpRequestBuilder。由于 body 成员是一个 InputStream,对原始的 request 的 body 的操作会影响到复制得到的 HttpRequest 的 body。HttpRequestBuilder 的 headers 和 trailers 是入参 request 的深拷贝。其余元素都是入参 request 的浅拷贝(因为是不可变对象,无需深拷贝)。

参数:

func addHeaders(HttpHeaders)

public func addHeaders(headers: HttpHeaders): HttpRequestBuilder

功能:向请求 header 添加参数 HttpHeaders 中的键值对。

参数:

返回值:

func addTrailers(HttpHeaders)

public func addTrailers(trailers: HttpHeaders): HttpRequestBuilder

功能:向请求 trailer 添加参数 HttpHeaders 中的键值对。

参数:

返回值:

func body(Array<UInt8>)

public func body(body: Array<UInt8>): HttpRequestBuilder

功能:设置请求 body。如果已经设置过,调用该函数将替换原 body。

参数:

  • body: Array<UInt8> - 字节数组形式的请求体。

返回值:

func body(InputStream)

public func body(body: InputStream): HttpRequestBuilder

功能:设置请求 body。如果已经设置过,调用该函数将替换原 body。

参数:

  • body: InputStream - 流形式的请求体。

返回值:

func body(String)

public func body(body: String): HttpRequestBuilder

功能:设置请求 body,如果已经设置过,调用该函数将替换原 body调用该函数设置请求 body,则 body 将以内置的 InputStream 实现类表示,其大小已知。

参数:

  • body: String - 字符串形式的请求体。

返回值:

func build()

public func build(): HttpRequest

功能:根据 HttpRequestBuilder 实例生成一个 HttpRequest 实例。

返回值:

func connect()

public func connect(): HttpRequestBuilder

功能:构造 method 为 "CONNECT" 的请求的便捷函数。

返回值:

func delete()

public func delete(): HttpRequestBuilder

功能:构造 method 为 "DELETE" 的请求的便捷函数。

返回值:

func get()

public func get(): HttpRequestBuilder

功能:构造 method 为 "GET" 的请求的便捷函数。

返回值:

func head()

public func head(): HttpRequestBuilder

功能:构造 method 为 "HEAD" 的请求的便捷函数。

返回值:

func header(String, String)

public func header(name: String, value: String): HttpRequestBuilder

功能:向请求 header 添加指定键值对,规则同 HttpHeaders 类的 add 函数。

参数:

  • name: String - 请求头的 key。
  • value: String - 请求头的 value。

返回值:

异常:

  • HttpException - 如果传入的 name 或 value 包含不合法元素,将抛出此异常。

func method(String)

public func method(method: String): HttpRequestBuilder

功能:设置请求 method,默认请求 method 为 "GET"。

参数:

  • method: String - 请求方法,必须由 token 字符组成,如果传入空字符串,method 值将自动设置为 "GET"。

返回值:

异常:

func options()

public func options(): HttpRequestBuilder

功能:构造 method 为 "OPTIONS" 的请求的便捷函数。

返回值:

func post()

public func post(): HttpRequestBuilder

功能:构造 method 为 "POST" 的请求的便捷函数。

返回值:

func priority(Int64, Bool)

public func priority(urg: Int64, inc: Bool): HttpRequestBuilder

功能:设置 priority 头的便捷函数,调用此函数后,将生成 priority 头,形如:"priority: urgency=x, i"。如果通过设置请求头的函数设置了 priority 字段,调用此函数无效。如果多次调用此函数,以最后一次为准。

参数:

  • urg: Int64 - 表示请求优先级,取值范围为 [0, 7],0 表示最高优先级。
  • inc: Bool - 表示请求是否需要增量处理,为 true 表示希望服务器并发处理与之同 urg 同 inc 的请求,为 false 表示不希望服务器并发处理。

返回值:

异常:

  • HttpException - 当参数 urg 取值非法,即不在 [0, 7] 范围内时,抛出异常。

func put()

public func put(): HttpRequestBuilder

功能:构造 method 为 "PUT" 的请求的便捷函数。

返回值:

func readTimeout(Duration)

public func readTimeout(timeout: Duration): HttpRequestBuilder

功能:设置此请求的读超时时间。如果传入的 Duration 为负,则会自动转为 0。如果用户设置了此读超时时间,那么该请求的读超时以此为准;如果用户没有设置,那么该请求的读超时以 Client 为准。

参数:

  • timeout: Duration - 用户设置的此请求的读超时时间。

返回值:

func setHeaders(HttpHeaders)

public func setHeaders(headers: HttpHeaders): HttpRequestBuilder

功能:设置请求 header,如果已经设置过,调用该函数将替换原 header。

参数:

返回值:

func setTrailers(HttpHeaders)

public func setTrailers(trailers: HttpHeaders): HttpRequestBuilder

功能:设置请求 trailer,如果已经设置过,调用该函数将替换原 trailer。

参数:

返回值:

func trace()

public func trace(): HttpRequestBuilder

功能:构造 method 为 "TRACE" 的请求的便捷函数。

返回值:

func trailer(String, String)

public func trailer(name: String, value: String): HttpRequestBuilder

功能:向请求 trailer 添加指定键值对,规则同 HttpHeaders 类的 add 函数。

参数:

  • name: String - 请求头的 key。
  • value: String - 请求头的 value。

返回值:

异常:

  • HttpException - 如果传入的 name 或 value 包含不合法元素,将抛出此异常。

func url(String)

public func url(rawUrl: String): HttpRequestBuilder

功能:设置请求 url,默认 url 为空的 URL 对象。

参数:

  • rawUrl: String - 待解析成 url 对象的字符串,该字符串格式详见 URL.parse 函数。

返回值:

异常:

  • IllegalArgumentException - 当被编码的字符不符合 UTF8 的字节序列规则时,抛出异常。
  • UrlSyntaxException - 当传入字符串不符合 URL 格式时,抛出异常。

func url(URL)

public func url(url: URL): HttpRequestBuilder

功能:设置请求 url,默认 url 为空的 URL 对象,即 URL.parse("")。

参数:

  • url: URL - URL 对象。

返回值:

func version(Protocol)

public func version(version: Protocol): HttpRequestBuilder

功能:设置请求的 http 协议版本,默认为 UnknownProtocol(""),客户端会根据 tls 配置自动选择协议。

参数:

返回值:

func writeTimeout(Duration)

public func writeTimeout(timeout: Duration): HttpRequestBuilder

功能:设置此请求的写超时时间。如果传入的 Duration 为负,则会自动转为 0。如果用户设置了此写超时时间,那么该请求的写超时以此为准;如果用户没有设置,那么该请求的写超时以 Client 为准。

参数:

  • timeout: Duration - 用户设置的此请求的写超时时间。

返回值:

class HttpResponse

public class HttpResponse <: ToString

功能:Http 响应类。

此类定义了 http 中响应 Response 的相关接口,客户端用该类读取服务端返回的响应。

父类型:

  • ToString

prop body

public prop body: InputStream

功能:获取 body。

注意:

  • body 不支持并发读取;
  • 默认 InputStream 实现类的 read 函数不支持多次读取。

类型:InputStream

prop bodySize

public prop bodySize: Option<Int64>

功能:获取响应 body 长度。

  • 如果未设置 body,则 bodySize 为 Some(0);
  • 如果 body 长度已知,即通过 Array<UInt8> 或 String 传入 body,或传入的 InputStream 有确定的 length (length >= 0),则 bodySize 为 Some(Int64);
  • 如果 body 长度未知,即通过用户自定义的 InputStream 实例传入 body 且 InputStream 实例没有确定的 length (length < 0),则 bodySize 为 None。

类型:Option<Int64>

prop close

public prop close: Bool

功能:表示该响应 header 是否包含 Connection: close。

对于服务端,close 为 true 表示处理完该请求应该关闭连接;

对于客户端,close 为 true 表示如果收到响应后服务端未关闭连接,客户端应主动关闭连接。

类型:Bool

prop headers

public prop headers: HttpHeaders

功能:获取 headers,headers 详述见 HttpHeaders 类,获取后,可通过调用 HttpHeaders 实例成员函数,修改该请求的 headers。

类型:HttpHeaders

prop request

public prop request: Option<HttpRequest>

功能:获取该响应对应的请求,默认为 None。

类型:Option<HttpRequest>

prop status

public prop status: UInt16

功能:获取响应的状态码,默认值为 200。状态码由 100~599 的三位数字组成,状态码所反映的具体信息可参考 RFC 9110

类型:UInt16

prop trailers

public prop trailers: HttpHeaders

功能:获取 trailers,trailers 详述见 HttpHeaders 类,获取后,可通过调用 HttpHeaders 实例成员函数,修改该请求的 trailers。

类型:HttpHeaders

prop version

public prop version: Protocol

功能:获取响应的协议版本,默认值为 HTTP1_1

类型:Protocol

func toString()

public override func toString(): String

功能:把响应转换为字符串,包括 status-line,headers,body size, trailers。

例如:HTTP/1.1 200 OK\r\ncontent-length: 5\r\n\r\nbody size: 5\r\nbar: foo\r\n。

返回值:

  • String - 响应的字符串表示。

extend HttpResponse

extend HttpResponse

功能:为 HttpResonse 扩展 HTTP/2.0 特有的方法。

func getPush()

public func getPush(): Option<ArrayList<HttpResponse>>

功能:获取服务器推送的响应,返回 None 代表未开启服务器推送功能,返回空 ArrayList 代表无服务器推送的响应。

返回值:

  • Option<ArrayList<HttpResponse>> - 服务器推送的响应列表。

class HttpResponseBuilder

public class HttpResponseBuilder {
    public init()
}

功能:用于构造 HttpResponse 实例。

init()

public init()

功能:构造一个新 HttpResponseBuilder

func addHeaders(HttpHeaders)

public func addHeaders(headers: HttpHeaders): HttpResponseBuilder

功能:向响应 header 添加参数 HttpHeaders 中的键值对。

参数:

返回值:

func addTrailers(HttpHeaders)

public func addTrailers(trailers: HttpHeaders): HttpResponseBuilder

功能:向响应 trailer 添加参数 HttpHeaders 中的键值对。

参数:

返回值:

func body(Array<UInt8>)

public func body(body: Array<UInt8>): HttpResponseBuilder

功能:设置响应 body,如果已经设置过,调用该函数将替换原 body。

参数:

  • body: Array<UInt8> - 字节数组形式的响应体。

返回值:

func body(InputStream)

public func body(body: InputStream): HttpResponseBuilder

功能:设置响应 body,如果已经设置过,调用该函数将替换原 body调用该函数设置请求 body。

参数:

  • body: InputStream - 流形式的响应体。

返回值:

func body(String)

public func body(body: String): HttpResponseBuilder

功能:设置响应 body,如果已经设置过,调用该函数将替换原 body调用该函数设置请求 body。

参数:

  • body: String - 字符串形式的响应体。

返回值:

func build()

public func build(): HttpResponse

功能:根据 HttpResponseBuilder 实例生成一个 HttpResponse 实例。

返回值:

func header(String, String)

public func header(name: String, value: String): HttpResponseBuilder

功能:向响应 header 添加指定键值对,规则同 HttpHeaders 类的 add 函数。

参数:

  • name: String - 响应头的 key。
  • value: String - 响应头的 value。

返回值:

异常:

  • HttpException - 如果传入的 name 或 value 包含不合法元素,将抛出此异常。

func request(HttpRequest)

public func request(request: HttpRequest): HttpResponseBuilder

功能:设置响应对应的请求。

参数:

返回值:

func setHeaders(HttpHeaders)

public func setHeaders(headers: HttpHeaders): HttpResponseBuilder

功能:设置响应 header,如果已经设置过,调用该函数将替换原 header。

参数:

返回值:

func setTrailers(HttpHeaders)

public func setTrailers(trailers: HttpHeaders): HttpResponseBuilder

功能:设置响应 trailer,如果已经设置过,调用该函数将替换原 trailer。

参数:

返回值:

func status(UInt16)

public func status(status: UInt16): HttpResponseBuilder

功能:设置 http 响应状态码。

参数:

  • status: UInt16 - 传入的状态码的值。

返回值:

异常:

  • HttpException - 如果设置响应状态码不在 100~599 这个区间内,则抛出此异常。

func trailer(String, String)

public func trailer(name: String, value: String): HttpResponseBuilder

功能:向响应 trailer 添加指定键值对,规则同 HttpHeaders 类的 add 函数。

参数:

  • name: String - 响应头的 key。
  • value: String - 响应头的 value。

返回值:

异常:

  • HttpException - 如果传入的 name 或 value 包含不合法元素,将抛出此异常。

func version(Protocol)

public func version(version: Protocol): HttpResponseBuilder

功能:设置 http 响应协议版本。

参数:

返回值:

class HttpResponsePusher

public class HttpResponsePusher

功能:HTTP/2 服务器推送。

说明:

如果服务器收到请求后,认为客户端后续还需要某些关联资源,可以将其提前推送到客户端; 服务端推送包括推送请求和推送响应; 启用服务端推送需要先调用 push 函数发送推送请求,并向服务器注册该请求对应的 handler,用以生成推送响应; 客户端可设置拒绝服务端推送; 不允许嵌套推送,即不允许在推送请求对应的 handler 中再次推送。嵌套推送情况下,服务端将不执行推送,并打印日志进行提示。

static func getPusher(HttpContext)

public static func getPusher(ctx: HttpContext): ?HttpResponsePusher

功能:获取 HttpResponsePusher 实例,如果客户端拒绝推送,将返回 None。

参数:

返回值:

func push(String, String, HttpHeaders)

public func push(path: String, method: String, header: HttpHeaders): Unit

功能:向客户端发送推送请求,path 为请求地址,method 为请求方法,header 为请求头。

参数:

  • path: String - 推送的请求地址。
  • method: String - 推送的请求方法。
  • header: HttpHeaders - 推送的请求头。

class HttpResponseWriter

public class HttpResponseWriter {
    public HttpResponseWriter(let ctx: HttpContext)
}

功能:HTTP response 消息体 Writer,支持用户控制消息体的发送过程。

说明:

第一次调用 write 函数时,将立即发送 header 和通过参数传入的 body,此后每次调用 write,发送通过参数传入的 body。 对于 HTTP/1.1,如果设置了 transfer-encoding: chunked,用户每调用一次 write,将发送一个 chunk。 对于 HTTP/2,用户每调用一次 write,将把指定数据封装并发出。

HttpResponseWriter(HttpContext)

public HttpResponseWriter(let ctx: HttpContext)

功能:构造一个 HttpResponseWriter 实例。

参数:

func write(Array<Byte>)

public func write(buf: Array<Byte>): Unit

功能:发送 buf 中数据到客户端。

参数:

  • buf: Array<Byte> - 要发送的数据。

异常:

class NotFoundHandler

public class NotFoundHandler <: HttpRequestHandler

功能:便捷的 Http 请求处理器,404 Not Found 处理器。

父类型:

func handle(HttpContext)

public func handle(ctx: HttpContext): Unit

功能:处理 Http 请求,回复 404 响应。

参数:

class OptionsHandler

public class OptionsHandler <: HttpRequestHandler

功能:便捷的 Http 处理器,用于处理 OPTIONS 请求。固定返回 "Allow: OPTIONS,GET,HEAD,POST,PUT,DELETE" 响应头。

父类型:

func handle(HttpContext)

public func handle(ctx: HttpContext): Unit

功能:处理 Http OPTIONS 请求。

参数:

class ProtocolService

public abstract class ProtocolService

功能:Http 协议服务实例,为单个客户端连接提供 Http 服务,包括对客户端 request 报文的解析、 request 的分发处理、 response 的发送等。

prop server

open protected mut prop server: Server

功能:返回 Server 实例,提供默认实现,设置为绑定的 Server 实例

func serve()

protected func serve(): Unit

功能:处理来自客户端连接的请求,不提供默认实现。

func closeGracefully()

open protected func closeGracefully(): Unit

功能:优雅关闭连接,提供默认实现,无任何行为。

func close()

open protected func close(): Unit

功能:强制关闭连接,提供默认实现,无任何行为。

class RedirectHandler

public class RedirectHandler <: HttpRequestHandler {
    public init(url: String, code: UInt16)
}

功能:便捷的 Http 处理器,用于回复重定向响应。

父类型:

init(String, UInt16)

public init(url: String, code: UInt16)

功能:RedirectHandler 的构造函数。

参数:

  • url: String - 重定向响应中 Location 头部的 url。
  • code: UInt16 - 重定向响应的响应码。

异常:

  • HttpException - url 为空或响应码不是除 304 以外的 3XX 状态码时抛出异常。

func handle(HttpContext)

public func handle(ctx: HttpContext): Unit

功能:处理 Http 请求,回复重定向响应。

参数:

class Server

public class Server

功能:提供 HTTP 服务的 Server 类。

说明:

  • 启动服务,在指定地址及端口等待用户连接、服务用户的 http request;
  • 关闭服务,包括关闭所有已有连接;
  • 提供注册处理 http request 的 handler 的机制,根据注册信息分发 request 到相应的 handler;
  • 提供 tls 证书热机制;
  • 提供 shutdown 回调机制;
  • 通过 Logger.level 开启、关闭日志打印,包括按照用户要求打印相应级别的日志;
  • Server 文档中未明确说明支持版本的配置,在 HTTP/1.1 与 HTTP/2 都会生效。

prop addr

public prop addr: String

功能:获取服务端监听地址。

类型:String

prop distributor

public prop distributor: HttpRequestDistributor

功能:获取请求分发器,请求分发器会根据 url 将请求分发给对应的 handler。

类型:HttpRequestDistributor

prop enableConnectProtocol

public prop enableConnectProtocol: Bool

功能:HTTP/2 专用,用来限制对端发送的报文是否支持通过 connect 方法升级协议,true 表示支持。

类型:Bool

prop headerTableSize

public prop headerTableSize: UInt32

功能:获取服务端 HTTP/2 Hpack 动态表的初始值,默认值为 4096。

类型:UInt32

prop httpKeepAliveTimeout

public prop httpKeepAliveTimeout: Duration

功能:HTTP/1.1 专用,获取服务器设定的保持长连接的超时时间。

类型:Duration

prop initialWindowSize

public prop initialWindowSize: UInt32

功能:HTTP/2 专用,用来限制对端发送的报文stream 初始流量窗口大小。默认值为 65535 ,取值范围为 0 至 2^31 - 1。

类型:UInt32

prop listener

public prop listener: ServerSocket

功能:获取服务器绑定 socket。

类型:ServerSocket

prop logger

public prop logger: Logger

功能:获取服务器日志记录器,设置 logger.level 将立即生效,记录器应该是线程安全的。

类型:Logger

prop maxConcurrentStreams

public prop maxConcurrentStreams: UInt32

功能:HTTP/2 专用,用来限制连接同时处理的最大请求数量。

类型:UInt32

prop maxFrameSize

public prop maxFrameSize: UInt32

功能:HTTP/2 专用,用来限制对端发送的报文一个帧的最大长度。默认值为 16384. 取值范围为 2^14 至 2^24 - 1。

类型:UInt32

prop maxHeaderListSize

public prop maxHeaderListSize: UInt32

功能:获取客户端支持的 HTTP/2 最大头部(Header)大小。这个大小指的是响应头部中所有头部字段(Header Field)的最大允许长度之和,其中包括所有字段名称(name)的长度、字段值(value)的长度以及每个字段自动添加的伪头开销(通常每个字段会有32字节的开销,这包括了HTTP/2协议本身为头部字段添加的伪头部信息)。默认情况下,这个最大长度被设置为 UInt32.Max。

类型:UInt32

prop maxRequestBodySize

public prop maxRequestBodySize: Int64

功能:获取服务器设定的读取请求的请求体最大值,仅对于 HTTP/1.1 且未设置 "Transfer-Encoding: chunked" 的请求生效。

类型:Int64

prop maxRequestHeaderSize

public prop maxRequestHeaderSize: Int64

功能:获取服务器设定的读取请求的请求头最大值。仅对 HTTP/1.1 生效,HTTP/2 中有专门的配置 maxHeaderListSize。

类型:Int64

prop port

public prop port: UInt16

功能:获取服务端监听端口。

类型:UInt16

prop protocolServiceFactory

public prop protocolServiceFactory: ProtocolServiceFactory

功能:获取协议服务工厂,服务协议工厂会生成每个协议所需的服务实例。

类型:ProtocolServiceFactory

prop readHeaderTimeout

public prop readHeaderTimeout: Duration

功能:获取服务器设定的读取请求头的超时时间。

类型:Duration

prop readTimeout

public prop readTimeout: Duration

功能:获取服务器设定的读取整个请求的超时时间。

类型:Duration

prop servicePoolConfig

public prop servicePoolConfig: ServicePoolConfig

功能:获取协程池配置实例。

类型:ServicePoolConfig

prop transportConfig

public prop transportConfig: TransportConfig

功能:获取服务器设定的传输层配置。

类型:TransportConfig

prop writeTimeout

public prop writeTimeout: Duration

功能:获取服务器设定的写响应的超时时间。

类型:Duration

func afterBind(() -> Unit)

public func afterBind(f: ()-> Unit): Unit

功能:注册服务器启动时的回调函数,服务内部 ServerSocket 实例 bind 之后,accept 之前将调用该函数。重复调用将覆盖之前注册的函数。

参数:

  • f: () -> Unit - 回调函数,入参为空,返回值为 Unit 类型。

func close()

public func close(): Unit

功能:关闭服务器,服务器关闭后将不再对请求进行读取与处理,重复关闭将只有第一次生效(包括 close 和 closeGracefully)。

func closeGracefully()

public func closeGracefully(): Unit

功能:关闭服务器,服务器关闭后将不再对请求进行读取,当前正在进行处理的服务器待处理结束后进行关闭。

func getTlsConfig()

public func getTlsConfig(): ?TlsServerConfig

功能:获取服务器设定的 TLS 层配置。

返回值:

  • ?TlsServerConfig - 服务端设定的 TLS 层配置,如果没有设置则返回 None。

func onShutdown(() -> Unit)

public func onShutdown(f: () -> Unit): Unit

功能:注册服务器关闭时的回调函数,服务器关闭时将调用该回调函数,重复调用将覆盖之前注册的函数。

参数:

  • f: () -> Unit - 回调函数,入参为空,返回值为 Unit 类型。

func serve()

public func serve(): Unit

功能:启动服务端进程,不支持重复启动。

h1 request 检查和处理:

  • request-line 不符合 RFC 9112 中 request-line = method SP request-target SP HTTP-version 的规则,将会返回 400 响应;
  • method 由 tokens 组成,且大小写敏感;request-target 为能够被解析的 url;HTTP-version 为 HTTP/1.0 或 HTTP/1.1 ,否则将会返回 400 响应;
  • headers name 和 value 需符合特定规则,详见 HttpHeaders 类说明,否则返回 400 响应;
  • 当 headers 的大小超出 server 设定的 maxRequestHeaderSize 时将自动返回 431 响应;
  • headers 中必须包含 "host" 请求头,且值唯一,否则返回 400 响应headers 中不允许同时存在 "content-length" 与 "transfer-encoding" 请求头,否则返回 400 响应;
  • 请求头 "transfer-encoding" 的 value 经过 "," 分割后最后一个 value 必须为 "chunked",且之前的 value 不允许存在 "chunked",否则返回 400 响应;
  • 请求头 "content-length" 其 value 必须能解析为 Int64 类型,且不能为负值,否则返回 400 响应,当其 value 值超出 server 设定maxRequestBodySize,将返回 413 响应;
  • headers 中若不存在 "content-length" 和 "transfer-encoding: chunked" 时默认不存在 body;
  • 请求头 "trailer" 中,value 不允许存在 "transfer-encoding","trailer","content-length";
  • 请求头 "expect" 中,value 中存在非 "100-continue" 的值,将会返回 417 响应;
  • HTTP/1.0 默认短连接,若想保持长连接需要包含请求头 "connection: keep-alive" 与 "keep-alive: timeout = XX, max = XX",将会自动保持 timeout 时长的连接。HTTP/1.1 默认长连接,当解析 request 失败则关闭连接;
  • 仅允许在 chunked 模式下存在 trailer,且 trailer 中条目的 name 必须被包含在 "trailer" 请求头中,否则将自动删除。

h1 response 检查和处理:

  • 若用户不对 response 进行配置,将会自动返回 200 响应;
  • 若接收到的 request 包含请求头 "connection: close" 而配置 response 未添加响应头 "connection" 或响应头 "connection" 的 value 不包含 "close",将自动添加 "connection: close",若接收到的 request 不包含请求头 "connection: close" 且响应头不存在 "connection: keep-alive",将会自动添加;
  • 如果 headers 包含逐跳响应头:"proxy-connection","keep-alive","te","transfer-encoding","upgrade",将会在响应头 "connection" 自动添加这些头作为 value;
  • 将自动添加 "date" 响应头,用户提供的 "date" 将被忽略;
  • 若请求方法为 "HEAD" 或响应状态码为 "1XX\204\304",body将配置为空;
  • 若已知提供 body 的长度时,将会与响应头 "content-length" 进行比较,若不存在响应头 "content-length",将自动添加此响应头,其 value 值为 body 长度。若响应头 "content-length" 长度大于 body 长度,将会在 handler 中抛出 HttpException,若小于 body 长度,将对 body 进行截断处理,发送的 body 长度将为 "content-length" 的值;
  • response 中 "set-cookie" header 将分条发送,其他 headers 同名条目将合成一条发送;
  • 在处理包含请求头:"expect: 100-continue" 的 request 时,在调用 request 的 body.read() 时将会自动发送状态码为 100 的响应给客户端。不允许用户主动发送状态码为 100 的 response,若进行发送则被认定为服务器异常。

启用 h2 服务:tlsConfig 中 supportedAlpnProtocols 需包含 "h2",此后如果 tls 层 alpn 协商结果为 h2,则启用 h2 服务。

h2 request 检查和处理:

  • headers name 和 value 需符合特定规则,详见 HttpHeaders 类说明,此外 name 不能包含大写字符,否则发送 RST 帧关闭流,即无法保证返回响应;
  • trailers name 和 value 需符合同样规则,否则关闭流;
  • headers 不能包含 "connection","transfer-encoding","keep-alive","upgrade","proxy-connection",否则关闭流;
  • 如果有 "te" header,其值只能为 "trailers",否则关闭流;
  • 如果有 "host" header 和 ":authority" pseudo header,"host" 值必须与 ":authority" 一致,否则关闭流;
  • 如果有 "content-length" header,需符合 "content-length" 每个值都能解析为 Int64 类型,且如果有多个值,必须相等,否则关闭流;
  • 如果有 "content-length" header,且有 body 大小,则 content-length 值与 body 大小必须相等,否则关闭流;
  • 如果有 "trailer" header,其值不能包含 "transfer-encoding","trailer","content-length",否则关闭流;
  • 仅在升级 WebSocket 场景下支持 CONNECT 方法,否则关闭流;
  • pseudo headers 中,必须包含 ":method"、":scheme"、":path",其中 ":method" 值必须由 tokens 字符组成,":scheme" 值必须为 "https",":path" 不能为空,否则关闭流;
  • trailer 中条目的 name 必须被包含在 "trailer" 头中,否则将自动删除;
  • request headers 大小不能超过 maxHeaderListSize,否则关闭连接。

h2 response 检查和处理:

  • 如果 HEAD 请求的响应包含 body,将自动删除;
  • 将自动添加 "date" field,用户提供的 "date" 将被忽略;
  • 如果 headers 包含 "connection","transfer-encoding","keep-alive","upgrade","proxy-connection",将自动删除;
  • response 中 "set-cookie" header 将分条发送,其他 headers 同名条目将合成一条发送;
  • 如果 headers 包含 "content-length",且 method 不为 "HEAD","content-length" 将被删除;
  • 如果 method 为 "HEAD",则:
    • headers 包含 "content-length",但 "content-length" 不合法(无法被解析为 Int64 值,或包含多个不同值),如果用户调用 HttpResponseWriter 类的 write 函数,将抛出 HttpException,如果用户 handler 已经结束,将打印日志;
    • headers 包含 "content-length",同时 response.body.length 不为 -1,"content-length" 值与 body.length 不符,同 6.1 处理;
    • headers 包含 "content-length",同时 response.body.length 为 -1,或 body.length 与 "content-length" 值一致,则保留 "content-length" header;
  • trailer 中条目必须被包含在 "trailer" 头中,否则将自动删除;
  • 如果 handler 中抛出异常,且用户未调用 write 发送部分响应,将返回 500 响应。如果用户已经调用 write 发送部分响应,将发送 RST 帧关闭 stream。

h2 server 发完 response 之后,如果 stream 状态不是 CLOSED,会发送带 NO_ERROR 错误码的 RST 帧关闭 stream,避免已经处理完毕的 stream 继续占用服务器资源。

h2 流量控制:

  • connection 流量窗口初始值为 65535,每次收到 DATA 帧将返回一个 connection 层面的 WINDOW-UPDATE,发送 DATA 时,如果 connection 流量窗口值为负数,将阻塞至其变为正数;
  • stream 流量窗口初始值可由用户设置,默认值为 65535,每次收到 DATA 帧将返回一个 stream 层面的 WINDOW-UPDATE,发送 DATA 时,如果 stream 流量窗口值为负数,将阻塞至其变为正数。

h2 请求优先级:

  • 支持按 urgency 处理请求,h2 服务默认并发处理请求,当并发资源不足时,请求将按 urgency 处理,优先级高的请求优先处理。

默认 ProtocolServiceFactory 协议选择:

  • 如果连接是 tcp,使用 HTTP/1.1 server;
  • 如果连接是 tls,根据 alpn 协商结果确定 http 协议版本,如果协商结果为 "http/1.0","http/1.1" 或 "",使用 HTTP/1.1 server,如果协商结果为 "h2",使用 HTTP/2 server,否则不处理此次请求,打印日志关连接。

异常:

  • SocketException - 当端口监听失败时,抛出异常。

func updateCA(Array<X509Certificate>)

public func updateCA(newCa: Array<X509Certificate>): Unit

功能:对 CA 证书进行热更新。

参数:

异常:

  • IllegalArgumentException - 参数包含空字符时抛出异常。
  • HttpException - 服务端未配置 tlsConfig时抛出异常。

func updateCA(String)

public func updateCA(newCaFile: String): Unit

功能:对 CA 证书进行热更新。

参数:

  • newCaFile: String - CA证书文件。

异常:

  • IllegalArgumentException - 参数包含空字符时抛出异常。
  • HttpException - 服务端未配置 tlsConfig时抛出异常。

func updateCert(Array<X509Certificate>, PrivateKey)

public func updateCert(certChain: Array<X509Certificate>, certKey: PrivateKey): Unit

功能:对 TLS 证书进行热更新。

参数:

异常:

func updateCert(String, String)

public func updateCert(certificateChainFile: String, privateKeyFile: String): Unit

功能:对 TLS 证书进行热更新。

参数:

  • certificateChainFile: String - 证书链文件。
  • privateKeyFile: String - 证书匹配的私钥文件。

异常:

  • IllegalArgumentException - 参数包含空字符时抛出异常。
  • HttpException - 服务端未配置 tlsConfig时抛出异常。

class ServerBuilder

public class ServerBuilder {
    public init()
}

功能:提供 Server 实例构建器。

支持通过如下参数构造一个 Http Server

  • 地址、端口;
  • 线程安全的 logger;
  • HttpRequestDistributor,用于注册 handler、分发 request;
  • HTTP/2 的 settings;
  • shutdown 回调;
  • transport:listener、连接及其配置;
  • protocol service:http 协议解析服务;

除地址端口、shutdown 回调外,均提供默认实现,用户在构造 server 过程中可不指定其他构建参数。 ServerBuilder 文档中未明确说明支持版本的配置,在 HTTP/1.1 与 HTTP/2 都会生效。

说明:

该类提供了一系列配置参数的函数,配置完成后调用 build 函数构造出 Server 实例。配置函数中说明了参数的取值范围,但配置函数本身不做参数合法性校验,build 时统一进行校验。

init()

public init()

功能:创建 ServerBuilder 实例。

func addr(String)

public func addr(addr: String): ServerBuilder

功能:设置服务端监听地址,若 listener 被设定,此值被忽略。

格式需符合 IPAddress 中相关规定。

参数:

  • addr: String - 地址值。

返回值:

func afterBind(()->Unit)

public func afterBind(f: ()->Unit): ServerBuilder

功能:注册服务器启动时的回调函数,服务内部 ServerSocket 实例 bind 之后,accept 之前将调用该函数。重复调用将覆盖之前注册的函数。

参数:

  • f: () ->Unit - 回调函数,入参为空,返回值为 Unit 类型。

返回值:

func build()

public func build(): Server

功能:根据设置的参数构建 Server 实例。

此处会对各参数的值进行检查,如果取值非法,将抛出异常。各参数的取值范围详见设置参数相关的函数。

返回值:

异常:

  • IllegalArgumentException - 当设置的参数非法时,抛出异常。
  • IllegalFormatException 格式错误时,抛出异常。

func distributor(HttpRequestDistributor)

public func distributor(distributor: HttpRequestDistributor): ServerBuilder

功能:设置请求分发器,请求分发器会根据 url 将请求分发给对应的 handler。不设置时使用默认请求分发器。

参数:

返回值:

func enableConnectProtocol(Bool)

public func enableConnectProtocol(flag: Bool): ServerBuilder

功能:HTTP/2 专用,设置本端是否接收 CONNECT 请求,默认 false。

参数:

  • flag: Bool - 本端是否接收 CONNECT 请求。

返回值:

func headerTableSize(UInt32)

public func headerTableSize(size: UInt32): ServerBuilder

功能:设置服务端 HTTP/2 Hpack 动态表的初始值,默认值为 4096。

参数:

  • size: UInt32 - 本端对响应头编码时使用的最大 table size

返回值:

func httpKeepAliveTimeout(Duration)

public func httpKeepAliveTimeout(timeout: Duration): ServerBuilder

功能:HTTP/1.1 专用,设定服务端连接保活时长,该时长内客户端未再次发送请求,服务端将关闭长连接,默认不进行限制。

参数:

  • timeout: Duration - 设定保持长连接的超时时间,如果传入负的 Duration 将被替换为 Duration.Zero。

返回值:

func initialWindowSize(UInt32)

public func initialWindowSize(size: UInt32): ServerBuilder

功能:HTTP/2 专用,设置当前服务器上每个流的接收报文的初始流量窗口大小,默认值为 65535。取值范围为 0 至 2^31 - 1。

参数:

  • size: UInt32 - 本端一个 stream 上接收报文的初始流量窗口大小。

返回值:

func listener(ServerSocket)

public func listener(listener: ServerSocket): ServerBuilder

功能:服务端调用此函数对指定 socket 进行绑定监听。

参数:

  • listener: ServerSocket - 所绑定的socket。

返回值:

func logger(Logger)

public func logger(logger: Logger): ServerBuilder

功能:设定服务器的 logger,默认 logger 级别为 INFO,logger 内容将写入 Console.stdout。

参数:

  • logger: Logger - 需要是线程安全的,默认使用内置线程安全 logger。

返回值:

func maxConcurrentStreams(UInt32)

public func maxConcurrentStreams(size: UInt32): ServerBuilder

功能:HTTP/2 专用,设置本端同时处理的最大请求数量,限制对端并发发送请求的数量,默认值为 100。

参数:

  • size: UInt32 - 本端同时处理的最大请求数量。

返回值:

func maxFrameSize(UInt32)

public func maxFrameSize(size: UInt32): ServerBuilder

功能:HTTP/2 专用,设置本端接收的一个帧的最大长度,用来限制对端发送帧的长度,默认值为 16384. 取值范围为 2^14 至 2^24 - 1。

参数:

  • size: UInt32 - 本端接收的一个帧的最大长度。

返回值:

func maxHeaderListSize(UInt32)

public func maxHeaderListSize(size: UInt32): ServerBuilder

功能:获取客户端支持的 HTTP/2 最大头部(Header)大小。这个大小指的是响应头部中所有头部字段(Header Field)的最大允许长度之和,其中包括所有字段名称(name)的长度、字段值(value)的长度以及每个字段自动添加的伪头开销(通常每个字段会有32字节的开销,这包括了 HTTP/2 协议本身为头部字段添加的伪头部信息)。默认情况下,这个最大长度被设置为 UInt32.Max。

参数:

  • size: UInt32 - 本端接收的报文头最大长度。

返回值:

func maxRequestBodySize(Int64)

public func maxRequestBodySize(size: Int64): ServerBuilder

功能:设置服务端允许客户端发送单个请求的请求体最大长度,请求体长度超过该值时,将返回状态码为 413 的响应。默认值为 2M。仅对于 HTTP/1.1 且未设置 "Transfer-Encoding: chunked" 的请求生效。

参数:

  • size: Int64 - 设定允许接收请求的请求体大小最大值,值为 0 代表不作限制。

返回值:

异常:

  • IllegalArgumentException - 当入参size < 0时,抛出异常。

func maxRequestHeaderSize(Int64)

public func maxRequestHeaderSize(size: Int64): ServerBuilder

功能:设定服务端允许客户端发送单个请求的请求头最大长度,请求头长度超过该值时,将返回状态码为 431 的响应;仅对 HTTP/1.1 生效,HTTP/2 中有专门的配置 maxHeaderListSize。

参数:

  • size: Int64 - 设定允许接收请求的请求头大小最大值,值为 0 代表不作限制。

返回值:

异常:

  • IllegalArgumentException - 当入参size < 0时,抛出异常。

func onShutdown(() -> Unit)

public func onShutdown(f: () -> Unit): ServerBuilder

功能:注册服务器关闭时的回调函数,服务器关闭时将调用该回调函数,重复调用将覆盖之前注册的函数。

参数:

  • f: () ->Unit - 回调函数,入参为空,返回值为 Unit 类型。

返回值:

func port(UInt16)

public func port(port: UInt16): ServerBuilder

功能:设置服务端监听端口,若 listener 被设定,此值被忽略。

参数:

  • port: UInt16 - 端口值。

返回值:

func protocolServiceFactory(ProtocolServiceFactory)

public func protocolServiceFactory(factory: ProtocolServiceFactory): ServerBuilder

功能:设置协议服务工厂,服务协议工厂会生成每个协议所需的服务实例,不设置时使用默认工厂。

参数:

返回值:

func readHeaderTimeout(Duration)

public func readHeaderTimeout(timeout: Duration): ServerBuilder

功能:设定服务端读取客户端发送一个请求的请求头最大时长,超过该时长将不再进行读取并关闭连接,默认不进行限制。

参数:

  • timeout: Duration - 设定的读请求头超时时间,如果传入负的 Duration 将被替换为 Duration.Zero。

返回值:

func readTimeout(Duration)

public func readTimeout(timeout: Duration): ServerBuilder

功能:设定服务端读取一个请求的最大时长,超过该时长将不再进行读取并关闭连接,默认不进行限制。

参数:

  • timeout: Duration - 设定读请求的超时时间,如果传入时间为负值将被替换为 Duration.Zero。

返回值:

func servicePoolConfig(ServicePoolConfig)

public func servicePoolConfig(cfg: ServicePoolConfig): ServerBuilder

功能:服务过程中使用的协程池相关设置,具体说明见 ServicePoolConfig 结构体。

参数:

返回值:

func tlsConfig(TlsServerConfig)

public func tlsConfig(config: TlsServerConfig): ServerBuilder

功能:设置 TLS 层配置,默认不对其进行设置。

参数:

  • config: TlsServerConfig - 设定支持 tls 服务所需要的配置信息。

返回值:

func transportConfig(TransportConfig)

public func transportConfig(config: TransportConfig): ServerBuilder

功能:设置传输层配置,默认配置详见 TransportConfig 结构体说明。

参数:

返回值:

func writeTimeout(Duration)

public func writeTimeout(timeout: Duration): ServerBuilder

功能:设定服务端发送一个响应的最大时长,超过该时长将不再进行写入并关闭连接,默认不进行限制。

参数:

  • timeout: Duration - 设定写响应的超时时间,如果传入时间为负值将被替换为 Duration.Zero。

返回值:

class WebSocket

public class WebSocket

功能:提供 WebSocket 服务的相关类,提供 WebSocket 连接的读、写、关闭等函数。用户通过 upgradeFrom 函数以获取 WebSocket 连接。

  • 调用 read() 读取一个 WebSocketFrame,用户可通过 WebSocketFrame.frameType 来知晓帧的类型,通过 WebSocketFrame.fin 来知晓是否是分段帧。
  • 调用 write(frameType: WebSocketFrameType, byteArray: Array<UInt8>),传入 message 的类型和 message 的 byte 来发送 WebSocket 信息,如果写的是控制帧,则不会分段发送,如果写的是数据帧(Text、Binary),则会将 message 按底层 buffer 的大小分段(分成多个 fragment)发送。

详细说明见下文接口说明,接口行为以 RFC 6455 为准。

prop logger

public prop logger: Logger

功能:日志记录器。

类型:Logger

prop subProtocol

public prop subProtocol: String

功能:获取与对端协商到的 subProtocol,协商时,客户端提供一个按偏好排名的 subProtocols 列表,服务器从中选取一个或零个子协议。

类型:String

static func upgradeFromClient(Client, URL, Protocol, ArrayList<String>, HttpHeaders)

public static func upgradeFromClient(client: Client, url: URL,
 version!: Protocol = HTTP1_1,
 subProtocols!: ArrayList<String> = ArrayList<String>(), 
 headers!: HttpHeaders = HttpHeaders()): (WebSocket, HttpHeaders)

功能:提供客户端升级到 WebSocket 协议的函数。

说明:

客户端的升级流程为:传入 client 对象,url 对象,构建升级请求,请求服务器后验证其响应,如果握手成功,则返回 WebSocket 对象用于 WebSocket 通讯,并返回 101 响应头的 HttpHeaders 对象给用户。暂不支持 extensions。如果子协议协商成功,用户可通过调用返回的 WebSocket 的 subProtocol 查看子协议。

参数:

  • client: Client - 用于请求的 client 对象。
  • url: URL - 用于请求的 url 对象,WebSocket 升级时要注意 url 的 scheme 为 ws 或 wss。
  • version!: Protocol - 创建 socket 使用的 HTTP 版本,只支持 HTTP1_1HTTP2_0WebSocket 升级。
  • subProtocols!: ArrayList<String> - 用户配置的子协议列表,按偏好排名,默认为空。若用户配置了,则会随着升级请求发送给服务器。
  • headers!: HttpHeaders - 需要随着升级请求一同发送的非升级必要头,如 cookie 等。

返回值:

  • (WebSocket, HttpHeaders) - 升级成功,则返回 WebSocket 对象用于通讯和 101 响应的头。

异常:

  • SocketException - 底层连接错误时抛出异常。
  • HttpException - 握手时 HTTP 请求过程中出现错误时抛出异常。
  • WebSocketException - 升级失败,升级响应验证不通过时抛出异常。

static func upgradeFromServer(HttpContext, ArrayList<String>, ArrayList<String>, (HttpRequest) -> HttpHeaders)

public static func upgradeFromServer(ctx: HttpContext, subProtocols!: ArrayList<String> = ArrayList<String>(), 
                                        origins!: ArrayList<String> = ArrayList<String>(), 
                                        userFunc!:(HttpRequest) -> HttpHeaders = {_: HttpRequest => HttpHeaders()}): WebSocket

功能:提供服务端升级到 WebSocket 协议的函数,通常在 handler 中使用。

服务端升级的流程为:收到客户端发来的升级请求,验证请求,如果验证通过,则回复 101 响应并返回 WebSocket 对象用于 WebSocket 通讯。

  • 用户通过 subProtocols,origins 参数来配置其支持的 subprotocol 和 origin 白名单,subProtocols如果不设置,则表示不支持子协议,origins 如果不设置,则表示接受所有 origin 的握手请求;
  • 用户通过 userFunc 来自定义处理升级请求的行为,如处理 cookie 等,传入的 userFunc 要求返回一个 HttpHeaders 对象,其会通过 101 响应回给客户端(升级失败的请求则不会);
  • 暂不支持 WebSocket 的 extensions,因此如果握手过程中出现 extensions 协商则会抛 WebSocketException
  • 只支持 HTTP1_1 和 HTTP2_0 向 WebSocket 升级。

参数:

  • ctx: HttpContext - Http 请求上下文,将传入给 handler 的直接传给 upgradeFromServer 即可。
  • subProtocols!: ArrayList<String> - 用户配置的子协议列表,默认值为空,表示不支持。如果用户配置了,则会选取升级请求中最靠前的作为升级后的 WebSocket 的子协议,用户可通过调用返回的 WebSocket 的 subProtocol 查看子协议。
  • origins!: ArrayList<String> - 用户配置的同意握手的 origin 的白名单,如果不配置,则同意来自所有 origin 的握手,如果配置了,则只接受来自配置 origin 的握手。
  • userFunc!: (HttpRequest) ->HttpHeaders - 用户配置的自定义处理升级请求的函数,该函数返回一个 HttpHeaders

返回值:

func closeConn()

public func closeConn(): Unit

功能:提供关闭底层 WebSocket 连接的函数。

说明:

直接关闭底层连接。正常的关闭流程需要遵循协议规定的握手流程,即先发送 Close 帧给对端,并等待对端回应的 Close 帧。握手流程结束后方可关闭底层连接。

func read()

public func read(): WebSocketFrame

功能:从连接中读取一个帧,如果连接上数据未就绪会阻塞,非线程安全(即对同一个 WebSocket 对象不支持多线程读)。

read 函数返回一个 WebSocketFrame 对象,用户可以调用 WebSocketFrame 的 frameType,fin 属性确定其帧类型和是否是分段帧调用。通过 WebSocketFrame 的 payload 函数得到原始二进制数据数组:Array<UInt8>

  • 分段帧的首帧为 fin == false,frameType == TextWebFrame 或 BinaryWebFrame中间帧 fin == false,frameType == ContinuationWebFrame尾帧 fin == true, frameType == ContinuationWebFrame;
  • 非分段帧为 fin == true, frameType != ContinuationWebFrame。

注意:

  • 数据帧(Text,Binary)可以分段,用户需要多次调用 read 将所有分段帧读完(以下称为接收到完整的 message),再将分段帧的 payload 按接收序拼接Text 帧的 payload 为 UTF-8 编码,用户在接收到完整的 message 后,调用 String.fromUtf8函数将拼接后的 payload 转成字符串Binary 帧的 payload 的意义由使用其的应用确定,用户在接收到完整的 message 后,将拼接后的 payload 传给上层应用;
  • 控制帧(Close,Ping,Pong)不可分段;
  • 控制帧本身不可分段,但其可以穿插在分段的数据帧之间。分段的数据帧之间不可出现其他数据帧,如果用户收到穿插的分段数据帧,则需要当作错误处理;
  • 客户端收到 masked 帧,服务器收到 unmasked 帧,断开底层连接并抛出异常;
  • rsv1、rsv2、rsv3 位被设置(暂不支持 extensions,因此 rsv 位必须为 0),断开底层连接并抛出异常;
  • 收到无法理解的帧类型(只支持 Continuation,Text,Binary,Close,Ping,Pong),断开底层连接并抛出异常;
  • 收到分段或 payload 长度大于 125 bytes 的控制帧(Close,Ping,Pong),断开底层连接并抛出异常;
  • 收到 payload 长度大于 20M 的帧,断开底层连接并抛出异常;
  • closeConn 关闭连接后继续调用读,抛出异常。

返回值:

异常:

  • SocketException - 底层连接错误。
  • WebSocketException - 收到不符合协议规定的帧,此时会给对端发送 Close 帧说明错误信息,并断开底层连接。
  • ConnectionException - 从连接中读数据时对端已关闭连接抛此异常。

func write(WebSocketFrameType, Array<UInt8>, Int64)

public func write(frameType: WebSocketFrameType, byteArray: Array<UInt8>, frameSize!: Int64 = FRAMESIZE): Unit

功能:发送数据,非线程安全(即对同一个 WebSocket 对象不支持多线程写)。

注意:

write 函数将数据以 WebSocket 帧的形式发送给对端;

  • 如果发送数据帧(Text,Binary),传入的 byteArray 如果大于 frameSize (默认 4 * 1024 bytes),我们会将其分成小于等于 frameSize 的 payload 以分段帧的形式发送,否则不分段;
  • 如果发送控制帧(Close,Ping,Pong),传入的 byteArray 的大小需要小于等于 125 bytes,Close 帧的前两个字节为状态码,可用的状态码见 RFC 6455 7.4. Status Codes协议规定,Close 帧发送之后,禁止再发送数据帧,如果发送则会抛出异常;
  • 用户需要自己保证其传入的 byteArray 符合协议,如 Text 帧的 payload 需要是 UTF-8 编码,如果数据帧设置了 frameSize,那么需要大于 0,否则抛出异常;
  • 发送数据帧时,frameSize 小于等于 0,抛出异常;
  • 用户发送控制帧时,传入的数据大于 125 bytes,抛出异常;
  • 用户传入非 Text,Binary,Close,Ping,Pong 类型的帧类型,抛出异常;
  • 发送 Close 帧时传入非法的状态码,或 reason 数据超过 123 bytes,抛出异常;
  • 发送完 Close 帧后继续发送数据帧,抛出异常;
  • closeConn 关闭连接后调用写,抛出异常。

参数:

  • frameType: WebSocketFrameType - 所需发送的帧的类型。
  • byteArray: Array<UInt8> - 所需发送的帧的 payload(二进制形式)。
  • frameSize!: Int64 - 分段帧的大小,默认为 4 * 1024 bytes,frameSize 不会对控制帧生效(控制帧设置了无效)。

异常:

  • SocketException - 底层连接错误时抛出异常。
  • WebSocketException - 传入非法的帧类型,或者数据时抛出异常。

func writeCloseFrame(?UInt16, String)

public func writeCloseFrame(status!: ?UInt16 = None, reason!: String = ""): Unit

功能:发送 Close 帧。

注意:

协议规定,Close 帧发送之后,禁止再发送数据帧。如果用户不设置 status,那么 reason 不会被发送(即有 reason 必有 status);控制帧的 payload 不超过 125 bytes,Close 帧的前两个 bytes 为 status,因此 reason 不能超过 123 bytes,closeConn 关闭连接后调用写,抛出异常。

参数:

  • status!: ?UInt16 - 发送的 Close 帧的状态码,默认为 None,表示不发送状态码和 reason。
  • reason!: String - 关闭连接的说明,默认为空字符串,发送时会转成 UTF-8,不保证可读,debug 用。

异常:

  • WebSocketException - 传入非法的状态码,或 reason 数据超过 123 bytes时抛出异常。

func writePingFrame(Array<UInt8>)

public func writePingFrame(byteArray: Array<UInt8>): Unit

功能:提供发送 Ping 帧的快捷函数,closeConn 关闭连接后调用写,抛出异常。

参数:

  • byteArray: Array<UInt8> - 所需发送的帧的 payload(二进制形式)。

异常:

  • SocketException - 底层连接错误时抛出异常。
  • WebSocketException - 传入的数据大于 125 bytes,抛出异常。

func writePongFrame(Array<UInt8>)

public func writePongFrame(byteArray: Array<UInt8>): Unit

功能:提供发送 Pong 帧的快捷函数,closeConn 关闭连接后调用写,抛出异常。

参数:

  • byteArray: Array<UInt8> - 所需发送的帧的 payload(二进制形式)。

异常:

  • SocketException - 底层连接错误时抛出异常。
  • WebSocketException - 传入的数据大于 125 bytes,抛出异常。

class WebSocketFrame

public class WebSocketFrame

功能:WebSocket 用于读的基本单元。

WebSocketFrame 提供了三个属性,其中 fin 和 frameType 共同说明了帧是否分段和帧的类型。payload 为帧的载荷。

  • 分段帧的首帧为 fin == false,frameType == TextWebFrame 或 BinaryWebFrame;
  • 中间帧 fin == false,frameType == ContinuationWebFrame;
  • 尾帧 fin == true, frameType == ContinuationWebFrame;
  • 非分段帧为 fin == true, frameType != ContinuationWebFrame;
  • 用户仅能通过 WebSocket 对象的 read 函数得到 WebSocketFrame。数据帧可分段,如果用户收到分段帧,则需要多次调用 read 函数直到收到完整的 message,并将所有分段的 payload 按接收顺序拼接。

注意:

由于控制帧可以穿插在分段帧之间,用户在拼接分段帧的 payload 时需要单独处理控制帧。分段帧之间仅可穿插控制帧,如果用户在分段帧之间接收到其他数据帧,则需要当作错误处理。

prop fin

public prop fin: Bool

功能:获取 WebSocketFrame 的 fin 属性,fin 与 frameType 共同说明了帧是否分段和帧的类型。

类型:Bool

prop frameType

public prop frameType: WebSocketFrameType

功能:获取 WebSocketFrame 的帧类型,fin 与 frameType 共同说明了帧是否分段和帧的类型。

类型:WebSocketFrameType

prop payload

public prop payload: Array<UInt8>

功能:获取 WebSocketFrame 的帧载荷。如果是分段数据帧,用户需要在接收到完整的 message 后,将所有分段的 payload 按接收序拼接。

类型:Array<UInt8>

枚举

enum FileHandlerType

public enum FileHandlerType {
    | DownLoad
    | UpLoad
}

功能:用于设置 FileHandler 是上传还是下载模式。

DownLoad

DownLoad

功能:设置 FileHandler 为下载模式。

UpLoad

UpLoad

功能:设置 FileHandler 为上传模式。

enum Protocol

public enum Protocol <: Equatable<Protocol> & ToString {
    | HTTP1_0
    | HTTP1_1
    | HTTP2_0
    | UnknownProtocol(String)
}

功能:定义 HTTP 协议类型枚举。

父类型:

HTTP1_0

HTTP1_0

功能:定义 1.0 版本 HTTP 协议。

HTTP1_1

HTTP1_1

功能:定义 1.1 版本 HTTP 协议。

HTTP2_0

HTTP2_0

功能:定义 2.0 版本 HTTP 协议。

UnknownProtocol(String)

UnknownProtocol(String)

功能:定义未知 HTTP 协议。

func toString()

public override func toString(): String

功能:获取 Http 协议版本字符串。

返回值:

  • String - Http 协议版本字符串。

operator func != (Protocol)

public override operator func != (that: Protocol): Bool

功能:判断枚举值是否不相等。

参数:

  • that: Protocol - 被比较的枚举值。

返回值:

  • Bool - 当前实例与 that 不等,返回 true;否则返回 false

operator func == (Protocol)

public override operator func == (that: Protocol): Bool

功能:判断枚举值是否相等。

参数:

  • that: Protocol - 被比较的枚举值。

返回值:

  • Bool - 当前实例与 that 相等,返回 true;否则返回 false

enum WebSocketFrameType

public enum WebSocketFrameType <: Equatable<WebSocketFrameType> & ToString {
    | ContinuationWebFrame
    | TextWebFrame
    | BinaryWebFrame
    | CloseWebFrame
    | PingWebFrame
    | PongWebFrame
    | UnknownWebFrame
}

功能:定义 WebSocketFrame 的枚举类型。

父类型:

ContinuationWebFrame

ContinuationWebFrame

功能:定义 websocket 协议中的未结束的分片帧。

TextWebFrame

TextWebFrame

功能:定义 websocket 协议中的文本帧。

BinaryWebFrame

BinaryWebFrame

功能:定义 websocket 协议中的数据帧。

CloseWebFrame

CloseWebFrame

功能:定义 websocket 协议中的关闭帧。

PingWebFrame

PingWebFrame

功能:定义 websocket 协议中的心跳帧。

PongWebFrame

PongWebFrame

功能:定义 websocket 协议中的心跳帧。

UnknownWebFrame

UnknownWebFrame

功能:定义 websocket 协议中的未知类型帧。

func toString()

public override func toString(): String

功能:获取 WebSocket 帧类型字符串。

返回值:

operator func != (WebSocketFrameType)

public override operator func != (that: WebSocketFrameType): Bool

功能:判断枚举值是否不相等。

参数:

返回值:

  • Bool - 当前实例与 that 不等返回 true,否则返回 false

operator func == (WebSocketFrameType)

public override operator func == (that: WebSocketFrameType): Bool

功能:判断枚举值是否相等。

参数:

返回值:

  • Bool - 当前实例与 that 相等返回 true,否则返回 false

结构体

struct HttpStatusCode

public struct HttpStatusCode {
    public static const STATUS_CONTINUE: UInt16 =                        100
    public static const STATUS_SWITCHING_PROTOCOLS: UInt16 =             101
    public static const STATUS_PROCESSING: UInt16 =                      102
    public static const STATUS_EARLY_HINTS: UInt16 =                     103
 
    public static const STATUS_OK: UInt16 =                              200
    public static const STATUS_CREATED: UInt16 =                         201
    public static const STATUS_ACCEPTED: UInt16 =                        202
    public static const STATUS_NON_AUTHORITATIVE_INFO: UInt16 =          203
    public static const STATUS_NO_CONTENT: UInt16 =                      204
    public static const STATUS_RESET_CONTENT: UInt16 =                   205
    public static const STATUS_PARTIAL_CONTENT: UInt16 =                 206
    public static const STATUS_MULTI_STATUS: UInt16 =                    207
    public static const STATUS_ALREADY_REPORTED: UInt16 =                208
    public static const STATUS_IM_USED: UInt16 =                         226
 
    public static const STATUS_MULTIPLE_CHOICES: UInt16 =                300
    public static const STATUS_MOVED_PERMANENTLY: UInt16 =               301
    public static const STATUS_FOUND: UInt16 =                           302
    public static const STATUS_SEE_OTHER: UInt16 =                       303
    public static const STATUS_NOT_MODIFIED: UInt16 =                    304
    public static const STATUS_USE_PROXY: UInt16 =                       305
    public static const STATUS_TEMPORARY_REDIRECT: UInt16 =              307
    public static const STATUS_PERMANENT_REDIRECT: UInt16 =              308
 
    public static const STATUS_BAD_REQUEST: UInt16 =                     400
    public static const STATUS_UNAUTHORIZED: UInt16 =                    401
    public static const STATUS_PAYMENT_REQUIRED: UInt16 =                402
    public static const STATUS_FORBIDDEN: UInt16 =                       403
    public static const STATUS_NOT_FOUND: UInt16 =                       404
    public static const STATUS_METHOD_NOT_ALLOWED: UInt16 =              405
    public static const STATUS_NOT_ACCEPTABLE: UInt16 =                  406
    public static const STATUS_PROXY_AUTH_REQUIRED: UInt16 =             407
    public static const STATUS_REQUEST_TIMEOUT: UInt16 =                 408
    public static const STATUS_CONFLICT: UInt16 =                        409
    public static const STATUS_GONE: UInt16 =                            410
    public static const STATUS_LENGTH_REQUIRED: UInt16 =                 411
    public static const STATUS_PRECONDITION_FAILED: UInt16 =             412
    public static const STATUS_REQUEST_CONTENT_TOO_LARGE: UInt16 =       413
    public static const STATUS_REQUEST_URI_TOO_LONG: UInt16 =            414
    public static const STATUS_UNSUPPORTED_MEDIA_TYPE: UInt16 =          415
    public static const STATUS_REQUESTED_RANGE_NOT_SATISFIABLE: UInt16 = 416
    public static const STATUS_EXPECTATION_FAILED: UInt16 =              417
    public static const STATUS_TEAPOT: UInt16 =                          418
    public static const STATUS_MISDIRECTED_REQUEST: UInt16 =             421
    public static const STATUS_UNPROCESSABLE_ENTITY: UInt16 =            422
    public static const STATUS_LOCKED: UInt16 =                          423
    public static const STATUS_FAILED_DEPENDENCY: UInt16 =               424
    public static const STATUS_TOO_EARLY: UInt16 =                       425
    public static const STATUS_UPGRADE_REQUIRED: UInt16 =                426
    public static const STATUS_PRECONDITION_REQUIRED: UInt16 =           428
    public static const STATUS_TOO_MANY_REQUESTS: UInt16 =               429
    public static const STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE: UInt16 = 431
    public static const STATUS_UNAVAILABLE_FOR_LEGAL_REASONS: UInt16 =   451
 
    public static const STATUS_INTERNAL_SERVER_ERROR: UInt16 =           500
    public static const STATUS_NOT_IMPLEMENTED: UInt16 =                 501
    public static const STATUS_BAD_GATEWAY: UInt16 =                     502
    public static const STATUS_SERVICE_UNAVAILABLE: UInt16 =             503
    public static const STATUS_GATEWAY_TIMEOUT: UInt16 =                 504
    public static const STATUS_HTTP_VERSION_NOT_SUPPORTED: UInt16 =      505
    public static const STATUS_VARIANT_ALSO_NEGOTIATES: UInt16 =         506
    public static const STATUS_INSUFFICIENT_STORAGE: UInt16 =            507
    public static const STATUS_LOOP_DETECTED: UInt16 =                   508
    public static const STATUS_NOT_EXTENDED: UInt16 =                    510
    public static const STATUS_NETWORK_AUTHENTICATION_REQUIRED: UInt16 = 511
}

功能:用来表示网页服务器超文本传输协议响应状态的 3 位数字代码。

状态码由 RFC 9110 规范定义,并得到 RFC2518、RFC 3229、RFC 4918、RFC 5842、RFC 7168 与 RFC 8297 等规范扩展。

所有状态码的第一个数字代表了响应的五种状态之一:

  • 状态代码的 1xx(信息)指示在完成请求的操作并发送最终响应之前通信连接状态或请求进度的临时响应。
  • 状态代码的 2xx(成功)指示客户端的请求已成功接收、理解和接受。
  • 状态代码的 3xx(重定向)指示用户代理需要采取进一步的操作才能完成请求。
  • 状态代码的 4xx(客户端错误)指示客户端似乎出错。
  • 状态代码的 5xx(服务器错误)指示服务器意识到它出错或无法执行请求的方法。

static const STATUS_ACCEPTED

public static const STATUS_ACCEPTED: UInt16 = 202

功能:服务器已接受请求,但尚未处理。

类型:Int64

static const STATUS_ALREADY_REPORTED

public static const STATUS_ALREADY_REPORTED: UInt16 = 208

功能:消息体将是一个 XML 消息。

类型:Int64

static const STATUS_BAD_GATEWAY

public static const STATUS_BAD_GATEWAY: UInt16 = 502

功能:作为网关或者代理工作的服务器尝试执行请求时,从上游服务器接收到无效的响应。

类型:Int64

static const STATUS_BAD_REQUEST

public static const STATUS_BAD_REQUEST: UInt16 = 400

功能:语义有误,当前请求无法被服务器理解;或请求参数有误。

类型:Int64

static const STATUS_CONFLICT

public static const STATUS_CONFLICT: UInt16 = 409

功能:由于和被请求的资源的当前状态之间存在冲突,请求无法完成。

类型:Int64

static const STATUS_CONTINUE

public static const STATUS_CONTINUE: UInt16 = 100

功能:这个临时响应是用来通知客户端它的部分请求已经被服务器接收,且仍未被拒绝。

类型:Int64

说明:

客户端应当继续发送请求的剩余部分,或者如果请求已经完成,忽略这个响应。 服务器必须在请求完成后向客户端发送一个最终响应。

static const STATUS_CREATED

public static const STATUS_CREATED: UInt16 = 201

功能:请求已经被实现,而且有一个新的资源已经依据请求的需要而建立,且其 URI 已经随 Location 头信息返回。

类型:Int64

static const STATUS_EARLY_HINTS

public static const STATUS_EARLY_HINTS: UInt16 = 103

功能:提前预加载 (css、js) 文档。

类型:Int64

static const STATUS_EXPECTATION_FAILED

public static const STATUS_EXPECTATION_FAILED: UInt16 = 417

功能:服务器无法满足 Expect 的请求头信息。

类型:Int64

static const STATUS_FAILED_DEPENDENCY

public static const STATUS_FAILED_DEPENDENCY: UInt16 = 424

功能:由于之前的某个请求发生的错误,导致当前请求失败。

类型:Int64

static const STATUS_FORBIDDEN

public static const STATUS_FORBIDDEN: UInt16 = 403

功能:服务器已经理解请求,但是拒绝执行。

类型:Int64

static const STATUS_FOUND

public static const STATUS_FOUND: UInt16 = 302

功能:临时移动。

类型:Int64

说明:

请求的资源已被临时的移动到新 URI,客户端应当继续向原有地址发送以后的请求。

static const STATUS_GATEWAY_TIMEOUT

public static const STATUS_GATEWAY_TIMEOUT: UInt16 = 504

功能:从上游服务器(URI 标识出的服务器,例如 HTTP、FTP、LDAP)或者辅助服务器(例如 DNS)收到响应超时。

类型:Int64

static const STATUS_GONE

public static const STATUS_GONE: UInt16 = 410

功能:被请求的资源在服务器上已经不再可用,而且没有任何已知的转发地址。

类型:Int64

static const STATUS_HTTP_VERSION_NOT_SUPPORTED

public static const STATUS_HTTP_VERSION_NOT_SUPPORTED: UInt16 = 505

功能:服务器不支持,或者拒绝支持在请求中使用的 HTTP 版本。

类型:Int64

static const STATUS_IM_USED

public static const STATUS_IM_USED: UInt16 = 226

功能:服务器已完成对资源的请求,并且响应是应用于当前实例的一个或多个实例操作的结果的表示。

类型:Int64

static const STATUS_INSUFFICIENT_STORAGE

public static const STATUS_INSUFFICIENT_STORAGE: UInt16 = 507

功能:服务器无法存储完成请求所必须的内容。

类型:Int64

static const STATUS_INTERNAL_SERVER_ERROR

public static const STATUS_INTERNAL_SERVER_ERROR: UInt16 = 500

功能:服务器遇到了一个未曾预料的状况,导致了它无法完成对请求的处理。

类型:Int64

static const STATUS_LENGTH_REQUIRED

public static const STATUS_LENGTH_REQUIRED: UInt16 = 411

功能:服务器拒绝在没有定义 Content-Length 头的情况下接受请求。

类型:Int64

static const STATUS_LOCKED

public static const STATUS_LOCKED: UInt16 = 423

功能:当前资源被锁定。

类型:Int64

static const STATUS_LOOP_DETECTED

public static const STATUS_LOOP_DETECTED: UInt16 = 508

功能:服务器在处理请求时检测到无限递归。

类型:Int64

static const STATUS_METHOD_NOT_ALLOWED

public static const STATUS_METHOD_NOT_ALLOWED: UInt16 = 405

功能:请求行中指定的请求函数不能被用于请求响应的资源。

类型:Int64

static const STATUS_MISDIRECTED_REQUEST

public static const STATUS_MISDIRECTED_REQUEST: UInt16 = 421

功能:请求被指向到无法生成响应的服务器。

类型:Int64

static const STATUS_MOVED_PERMANENTLY

public static const STATUS_MOVED_PERMANENTLY: UInt16 = 301

功能:永久移动。

类型:Int64

说明:

请求的资源已被永久的移动到新 URI,返回信息会包括新的 URI,浏览器会自动定向到新 URI。

static const STATUS_MULTIPLE_CHOICES

public static const STATUS_MULTIPLE_CHOICES: UInt16 = 300

功能:被请求的资源有一系列可供选择的回馈信息,每个都有自己特定的地址和浏览器驱动的商议信息。

类型:Int64

说明:

用户或浏览器能够自行选择一个首选的地址进行重定向。

static const STATUS_MULTI_STATUS

public static const STATUS_MULTI_STATUS: UInt16 = 207

功能:DAV 绑定的成员已经在(多状态)响应之前的部分被列举,且未被再次包含。

类型:Int64

static const STATUS_NETWORK_AUTHENTICATION_REQUIRED

public static const STATUS_NETWORK_AUTHENTICATION_REQUIRED: UInt16 = 511

功能:要求网络认证。

类型:Int64

static const STATUS_NON_AUTHORITATIVE_INFO

public static const STATUS_NON_AUTHORITATIVE_INFO: UInt16 = 203

功能:服务器已成功处理了请求。

类型:Int64

说明:

返回的实体头部元信息不是在原始服务器上有效的确定集合,而是来自本地或者第三方的拷贝。

static const STATUS_NOT_ACCEPTABLE

public static const STATUS_NOT_ACCEPTABLE: UInt16 = 406

功能:请求的资源的内容特性无法满足请求头中的条件,因而无法生成响应实体。

类型:Int64

static const STATUS_NOT_EXTENDED

public static const STATUS_NOT_EXTENDED: UInt16 = 510

功能:获取资源所需要的策略并没有被满足。

类型:Int64

static const STATUS_NOT_FOUND

public static const STATUS_NOT_FOUND: UInt16 = 404

功能:请求失败,请求所希望得到的资源未被在服务器上发现。

类型:Int64

static const STATUS_NOT_IMPLEMENTED

public static const STATUS_NOT_IMPLEMENTED: UInt16 = 501

功能:服务器不支持当前请求所需要的某个功能。

类型:Int64

static const STATUS_NOT_MODIFIED

public static const STATUS_NOT_MODIFIED: UInt16 = 304

功能:请求的资源未修改,服务器返回此状态码时,不会返回任何资源。

类型:Int64

说明:

客户端通常会缓存访问过的资源,通过提供一个头信息指出客户端希望只返回在指定日期之后修改的资源。

static const STATUS_NO_CONTENT

public static const STATUS_NO_CONTENT: UInt16 = 204

功能:服务器成功处理,但未返回内容。

类型:Int64

static const STATUS_OK

public static const STATUS_OK: UInt16 = 200

功能:请求已经成功,请求所希望的响应头或数据体将随此响应返回。

类型:Int64

static const STATUS_PARTIAL_CONTENT

public static const STATUS_PARTIAL_CONTENT: UInt16 = 206

功能:服务器已经成功处理了部分 GET 请求。

类型:Int64

static const STATUS_PAYMENT_REQUIRED

public static const STATUS_PAYMENT_REQUIRED: UInt16 = 402

功能:为了将来可能的需求而预留的状态码。

类型:Int64

static const STATUS_PERMANENT_REDIRECT

public static const STATUS_PERMANENT_REDIRECT: UInt16 = 308

功能:请求和所有将来的请求应该使用另一个 URI。

类型:Int64

static const STATUS_PRECONDITION_FAILED

public static const STATUS_PRECONDITION_FAILED: UInt16 = 412

功能:服务器在验证在请求的头字段中给出先决条件时,没能满足其中的一个或多个。

类型:Int64

static const STATUS_PRECONDITION_REQUIRED

public static const STATUS_PRECONDITION_REQUIRED: UInt16 = 428

功能:客户端发送 HTTP 请求时,必须要满足的一些预设条件。

类型:Int64

static const STATUS_PROCESSING

public static const STATUS_PROCESSING: UInt16 = 102

功能:处理将被继续执行。

类型:Int64

static const STATUS_PROXY_AUTH_REQUIRED

public static const STATUS_PROXY_AUTH_REQUIRED: UInt16 = 407

功能:必须在代理服务器上进行身份验证。

类型:Int64

static const STATUS_REQUESTED_RANGE_NOT_SATISFIABLE

public static const STATUS_REQUESTED_RANGE_NOT_SATISFIABLE: UInt16 = 416

功能:客户端请求的范围无效。

类型:Int64

说明:

请求中包含了 Range 请求头,并且 Range 中指定的任何数据范围都与当前资源的可用范围不重合; 同时请求中又没有定义 If-Range 请求头。

static const STATUS_REQUEST_CONTENT_TOO_LARGE

public static const STATUS_REQUEST_CONTENT_TOO_LARGE: UInt16 = 413

功能:请求提交的实体数据大小超过了服务器愿意或者能够处理的范围。

类型:Int64

static const STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE

public static const STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE: UInt16 = 431

功能:请求头字段太大。

类型:Int64

static const STATUS_REQUEST_TIMEOUT

public static const STATUS_REQUEST_TIMEOUT: UInt16 = 408

功能:请求超时。客户端没有在服务器预备等待的时间内完成一个请求的发送。

类型:Int64

static const STATUS_REQUEST_URI_TOO_LONG

public static const STATUS_REQUEST_URI_TOO_LONG: UInt16 = 414

功能:求的 URI 长度超过了服务器能够解释的长度。

类型:Int64

static const STATUS_RESET_CONTENT

public static const STATUS_RESET_CONTENT: UInt16 = 205

功能:服务器成功处理了请求,且没有返回任何内容,希望请求者重置文档视图。

类型:Int64

static const STATUS_SEE_OTHER

public static const STATUS_SEE_OTHER: UInt16 = 303

功能:对应当前请求的响应可以在另一个 URL 上被找到,而且客户端应当采用 GET 的方式访问那个资源。

类型:Int64

static const STATUS_SERVICE_UNAVAILABLE

public static const STATUS_SERVICE_UNAVAILABLE: UInt16 = 503

功能:临时的服务器维护或者过载。

类型:Int64

static const STATUS_SWITCHING_PROTOCOLS

public static const STATUS_SWITCHING_PROTOCOLS: UInt16 = 101

功能:服务器已经理解了客户端的请求,并将通过 Upgrade 消息头通知客户端采用不同的协议来完成这个请求。

类型:Int64

说明:

在发送完这个响应最后的空行后,服务器将会切换到在 Upgrade 消息头中定义的那些协议。

static const STATUS_TEAPOT

public static const STATUS_TEAPOT: UInt16 = 418

功能:服务端无法处理请求,一个愚弄客户端的状态码,被称为“我是茶壶”错误码,不应被认真对待。

类型:Int64

static const STATUS_TEMPORARY_REDIRECT

public static const STATUS_TEMPORARY_REDIRECT: UInt16 = 307

功能:临时重定向。

类型:Int64

static const STATUS_TOO_EARLY

public static const STATUS_TOO_EARLY: UInt16 = 425

功能:服务器不愿意冒风险来处理该请求。

类型:Int64

static const STATUS_TOO_MANY_REQUESTS

public static const STATUS_TOO_MANY_REQUESTS: UInt16 = 429

功能:请求过多。

类型:Int64

static const STATUS_UNAUTHORIZED

public static const STATUS_UNAUTHORIZED: UInt16 = 401

功能:当前请求需要用户验证。

类型:Int64

public static const STATUS_UNAVAILABLE_FOR_LEGAL_REASONS: UInt16 = 451

功能:该请求因法律原因不可用。

类型:Int64

static const STATUS_UNPROCESSABLE_ENTITY

public static const STATUS_UNPROCESSABLE_ENTITY: UInt16 = 422

功能:请求格式正确,但是由于含有语义错误,无法响应。

类型:Int64

static const STATUS_UNSUPPORTED_MEDIA_TYPE

public static const STATUS_UNSUPPORTED_MEDIA_TYPE: UInt16 = 415

功能:服务器无法处理请求附带的媒体格式。

类型:Int64

说明:

对于当前请求的函数和所请求的资源,请求中提交的实体并不是服务器中所支持的格式。

static const STATUS_UPGRADE_REQUIRED

public static const STATUS_UPGRADE_REQUIRED: UInt16 = 426

功能:服务器拒绝处理客户端使用当前协议发送的请求,但是可以接受其使用升级后的协议发送的请求。

类型:Int64

static const STATUS_USE_PROXY

public static const STATUS_USE_PROXY: UInt16 = 305

功能:使用代理,所请求的资源必须通过代理访问。

类型:Int64

static const STATUS_VARIANT_ALSO_NEGOTIATES

public static const STATUS_VARIANT_ALSO_NEGOTIATES: UInt16 = 506

功能:服务器存在内部配置错误。

类型:Int64

struct ServicePoolConfig

public struct ServicePoolConfig {
    public let capacity: Int64
    public let queueCapacity: Int64
    public let preheat: Int64
    public init(capacity!: Int64 = 10 ** 4, queueCapacity!: Int64 = 10 ** 4, preheat!: Int64 = 0)
}

功能:Http Server 协程池配置。

说明:

HTTP/1.1 Server 每次收到一个请求,将从协程池取出一个协程进行处理,如果任务等待队列已满,将拒绝服务该次请求,并断开连接。 HTTP/2 Server 处理过程中会从协程池取出若干协程进行处理,如果任务等待队列已满,将阻塞直至有协程空闲。

let capacity

public let capacity: Int64

功能:获取协程池容量。

类型:Int64

let preheat

public let preheat: Int64

功能:获取服务启动时预先启动的协程数量。

类型:Int64

let queueCapacity

public let queueCapacity: Int64

功能:获取缓冲区等待任务的最大数量。

类型:Int64

init(Int64, Int64, Int64)

public init(
    capacity!: Int64 = 10 ** 4,
    queueCapacity!: Int64 = 10 ** 4,
    preheat!: Int64 = 0
)

功能:构造一个 ServicePoolConfig 实例。

参数:

  • capacity!: Int64 - 协程池容量,默认值为 10000。
  • queueCapacity!: Int64 - 缓冲区等待任务的最大数量,默认值为 10000。
  • preheat!: Int64 - 服务启动时预先启动的协程数量,默认值为 0。

异常:

  • IllegalArgumentException - 当参数 capacity/queueCapacity/preheat 小于 0,或参数 preheat 大于 capacity。

struct TransportConfig

public struct TransportConfig

功能:传输层配置类,服务器建立连接使用的传输层配置。

prop keepAliveConfig

public mut prop keepAliveConfig: SocketKeepAliveConfig

功能:设定和读取传输层连接的消息保活配置,默认配置空闲时间为 45s,发送探测报文的时间间隔为 5s,在连接被认为无效之前发送的探测报文数 5 次,实际时间粒度可能因操作系统而异。

类型:SocketKeepAliveConfig

prop readBufferSize

public mut prop readBufferSize: ?Int64

功能:设定和读取传输层连接的读缓冲区大小,默认值为 None ,若设置的值小于 0,将在服务器进行服务建立连接后抛出 IllegalArgumentException。

说明:

使用默认值时,实际的缓冲区大小将由操作系统决定。

类型:?Int64

prop readTimeout

public mut prop readTimeout: Duration

功能:设定和读取传输层连接的读超时时间,如果设置的时间小于 0 将置为 0,默认值为 Duration.Max。

类型:Duration

prop writeBufferSize

public mut prop writeBufferSize: ?Int64

功能:设定和读取传输层连接的写缓冲区大小,默认值为 None ,若设置的值小于 0,将在服务器进行服务建立连接后抛出 IllegalArgumentException。

说明:

使用默认值时,实际的缓冲区大小将由操作系统决定。

类型:?Int64

prop writeTimeout

public mut prop writeTimeout: Duration

功能:设定和读取传输层连接的写超时时间,如果设置的时间小于 0 将置为 0,默认值为 Duration.Max。

类型:Duration

异常类

class ConnectionException

public class ConnectionException <: IOException {
    public init(message: String)
}

功能:Http 的tcp连接异常类。

父类型:

  • IOException

init(String)

public init(message: String)

功能:创建 ConnectionException 实例。

参数:

  • message: String - 异常提示信息。

class CoroutinePoolRejectException

public class CoroutinePoolRejectException <: Exception {
    public init(message: String)
}

功能:Http 的协程池拒绝请求处理异常类。

父类型:

  • Exception

init(String)

public init(message: String)

功能:创建 CoroutinePoolRejectException 实例。

参数:

  • message: String - 异常提示信息。

class HttpException

public class HttpException <: Exception {
    public init(message: String)
}

功能:Http 的通用异常类。

父类型:

  • Exception

init(String)

public init(message: String)

功能:创建 HttpException 实例。

参数:

  • message: String - 异常提示信息。

class HttpStatusException

public class HttpStatusException <: Exception {
    public init(statusCode: UInt16, message: String)
}

功能:Http 的响应状态异常类。

父类型:

  • Exception

init(UInt16, String)

public init(statusCode: UInt16, message: String)

功能:创建 HttpStatusException 实例。

参数:

  • statusCode: UInt16 - 状态码。
  • message: String - 异常提示信息。

class HttpTimeoutException

public class HttpTimeoutException <: Exception {
    public init(message: String)
}

功能:Http 的超时异常类。

父类型:

  • Exception

init(String)

public init(message: String)

功能:创建 HttpTimeoutException 实例。

参数:

  • message: String - 异常提示信息。

class WebSocketException

public class WebSocketException <: Exception {
    public init(message: String)
}

功能:WebSocket 的通用异常类。

父类型:

  • Exception

init(String)

public init(message: String)

功能:创建 WebSocketException 实例。

参数:

  • message: String - 异常提示信息。

client

Hello World

示例:

import stdx.net.http.*

main () {
    // 1. 构建 client 实例
    let client = ClientBuilder().build()
    // 2. 发送 request
    let rsp = client.get("http://example.com/hello")
    // 3. 读取response
    println(rsp)
    // 4. 关闭连接
    client.close()
}

运行结果:

HTTP/1.1 200 OK
accept-ranges: bytes
age: 258597
cache-control: max-age=604800
content-type: text/html
date: Wed, 05 Jun 2024 02:19:26 GMT
etag: "3147526947"
expires: Wed, 12 Jun 2024 02:19:26 GMT
last-modified: Thu, 17 Oct 2019 07:18:26 GMT
server: ECAcc (lac/55A4)
vary: Accept-Encoding
x-cache: HIT
content-length: 1256
connection: close

body size: 1256

自定义 client 网络配置

示例:

import std.net.{TcpSocket, SocketAddress}
import std.convert.Parsable
import std.fs.*
import stdx.net.tls.*
import stdx.crypto.x509.X509Certificate
import stdx.net.http.*
import std.io.*

// 该程序需要用户配置存在且合法的文件路径才能执行
main() {
    // 1. 自定义配置
    // tls 配置
    var tlsConfig = TlsClientConfig()
    let pem = String.fromUtf8(readToEnd(File("/rootCerPath", Read)))
    tlsConfig.verifyMode = CustomCA(X509Certificate.decodeFromPem(pem))
    tlsConfig.alpnProtocolsList = ["h2"]
    let TcpSocketConnector = {
        sa: SocketAddress =>
        let socket = TcpSocket(sa)
        socket.connect()
        return socket
    }
    // 2. 构建 client 实例
    let client = ClientBuilder().tlsConfig(tlsConfig).enablePush(false).connector(TcpSocketConnector).build()
    // 3. 发送 request
    let rsp = client.get("https://example.com/hello")
    // 4. 读取 response
    let buf = Array<UInt8>(1024, repeat: 0)
    let len = rsp.body.read(buf)
    println(String.fromUtf8(buf.slice(0, len)))
    // 5. 关闭连接
    client.close()
}

request中的 chunked 与 trailer

示例:

import std.io.*
import std.fs.*
import stdx.net.http.*

func checksum(chunk: Array<UInt8>): Int64 {
    var sum = 0
    for (i in chunk) {
        if (i == b'\n') {
            sum += 1
        }
    }
    return sum / 2
}

// 该程序需要用户配置存在且合法的文件路径才能执行
main() {
    // 1. 构建 client 实例
    let client = ClientBuilder().build()
    var requestBuilder = HttpRequestBuilder()
    let file = File("./res.jpg", Read)
    let sum = checksum(readToEnd(file))
    let req = requestBuilder
        .method("PUT")
        .url("https://example.com/src/")
        .header("Transfer-Encoding", "chunked")
        .header("Trailer", "checksum")
        .body(FileBody("./res.jpg"))
        .trailer("checksum", sum.toString())
        .build()
    let rsp = client.send(req)
    println(rsp)
    client.close()
}

class FileBody <: InputStream {
    var file: File
    init(path: String) {
        file = File(path, Read)
    }
    public func read(buf: Array<UInt8>): Int64 {
        file.read(buf)
    }
}

配置代理

示例:

import stdx.net.http.*

main() {
    // 1. 构建 client 实例
    let client = ClientBuilder().httpProxy("http://192.168.0.1:8080").build()
    // 2. 发送 request,所有 request 都会被发送至 192.168.0.1 地址的 8080 端口,而不是 example.com
    let rsp = client.get("http://example.com/hello")
    // 3. 读取 response
    println(rsp)
    // 4. 关闭连接
    client.close()
}

cookie

Client

示例:

import stdx.net.http.*
import stdx.encoding.url.*
import std.net.*
import std.time.*
import std.sync.*

main() {
    // 1、启动socket服务器
    let serverSocket = TcpServerSocket(bindAt: 0)
    serverSocket.bind()
    let fut = spawn {
        serverPacketCapture(serverSocket)
    }
    sleep(Duration.millisecond * 10)
    // 客户端一般从 response 中的 Set-Cookie header 中读取 cookie,并将其存入 cookieJar 中,
    // 下次发起 request时,将其放在 request 的 Cookie header 中发送
    // 2、启动客户端
    let client = ClientBuilder().build()
    let port = (serverSocket.localAddress as IPSocketAddress)?.port ?? throw Exception("Port not found.")
    var u = URL.parse("http://127.0.0.1:${port}/a/b/c")
    var r = HttpRequestBuilder()
                        .url(u)
                        .build()
    // 3、发送request
    client.send(r)
    sleep(Duration.second * 2)
    r = HttpRequestBuilder()
                        .url(u)
                        .build()
    // 4、发送新 request,从 CookieJar 中取出 cookie,并转成 Cookie header 中的值
    // 此时 cookie 2=2 已经过期,因此只发送 1=1 cookie
    client.send(r)
    // 5、关闭客户端
    client.close()
    fut.get()
    serverSocket.close()
}

func serverPacketCapture(serverSocket: TcpServerSocket) {
    let buf = Array<UInt8>(500, repeat: 0)
    let server = serverSocket.accept()
    var i = server.read(buf)
    println(String.fromUtf8(buf[..i]))
    // GET /a/b/c HTTP/1.1
    // host: 127.0.0.1:44649
    // user-agent: CANGJIEUSERAGENT_1_1
    // connection: keep-alive
    // content-length: 0
    //
    // 过期时间为 4 秒的 cookie1
    let cookie1 = Cookie("1", "1", maxAge: 4, domain: "127.0.0.1", path: "/a/b/")
    let setCookie1 = cookie1.toSetCookieString()
    // 过期时间为 2 秒的 cookie2
    let cookie2 = Cookie("2", "2", maxAge: 2, path: "/a/")
    let setCookie2 = cookie2.toSetCookieString()
    // 服务器发送 Set-Cookie 头,客户端解析并将其存进 CookieJar 中
    server.write("HTTP/1.1 204 ok\r\nSet-Cookie: ${setCookie1}\r\nSet-Cookie: ${setCookie2}\r\nConnection: close\r\n\r\n".toArray())

    let server2 = serverSocket.accept()
    i = server2.read(buf)
    // 接收客户端的带 cookie 的请求
    println(String.fromUtf8(buf[..i]))
    // GET /a/b/c HTTP/1.1
    // host: 127.0.0.1:34857
    // cookie: 1=1
    // user-agent: CANGJIEUSERAGENT_1_1
    // connection: keep-alive
    // content-length: 0
    //
    server2.write("HTTP/1.1 204 ok\r\nConnection: close\r\n\r\n".toArray())
    server2.close()
}

运行结果:

GET /a/b/c HTTP/1.1
host: 127.0.0.1:37359
user-agent: CANGJIEUSERAGENT_1_1
connection: keep-alive
content-length: 0


GET /a/b/c HTTP/1.1
host: 127.0.0.1:37359
cookie: 1=1
user-agent: CANGJIEUSERAGENT_1_1
connection: keep-alive
content-length: 0

Server

示例:

import stdx.net.http.*

main () {
    // 服务器设置 cookie 时将 cookie 放在 Set-Cookie header 中发给客户端
    // 1. 构建 Server 实例
    let server = ServerBuilder()
                       .addr("127.0.0.1")
                       .port(8080)
                       .build()
    // 2. 注册 HttpRequestHandler
    server.distributor.register("/index", {httpContext =>
        let cookie = Cookie("name", "value")
        httpContext.responseBuilder.header("Set-Cookie", cookie.toSetCookieString()).body("Hello 仓颉!")
    })
    // 3. 启动服务
    server.serve()
}

log

示例:

import stdx.log.*
import stdx.net.http.*

main() {
    // 1. 构建 Server 实例
    let server = ServerBuilder().addr("127.0.0.1").port(8080).build()
    // 2. 注册 HttpRequestHandler
    server.distributor.register("/index", {
        httpContext => httpContext.responseBuilder.body("Hello 仓颉!")
    })
    // 3. 开启日志
    server.logger.level = LogLevel.DEBUG
    // client 端通过 client.logger.level = DEBUG 开启
    // 4. 启动服务
    server.serve()
}

运行结果:

2024/01/25 17:23:54.344205 DEBUG Logger [Server#serve] bindAndListen(127.0.0.1, 8080)

server

Hello 仓颉

示例:

import stdx.net.http.ServerBuilder

main() {
    // 1. 构建 Server 实例
    let server = ServerBuilder().addr("127.0.0.1").port(8080).build()
    // 2. 注册 HttpRequestHandler
    server.distributor.register("/index", {
        httpContext => httpContext.responseBuilder.body("Hello 仓颉!")
    })
    // 3. 启动服务
    server.serve()
}

通过 request distributor注册处理器

示例:

import stdx.net.http.{ServerBuilder, HttpRequestHandler, FuncHandler}

main() {
    // 1. 构建 Server 实例
    let server = ServerBuilder().addr("127.0.0.1").port(8080).build()
    var a: HttpRequestHandler = FuncHandler({
        httpContext => httpContext.responseBuilder.body("index")
    })
    var b: HttpRequestHandler = FuncHandler({
        httpContext => httpContext.responseBuilder.body("id")
    })
    var c: HttpRequestHandler = FuncHandler({
        httpContext => httpContext.responseBuilder.body("help")
    })
    server.distributor.register("/index", a)
    server.distributor.register("/id", b)
    server.distributor.register("/help", c)
    // 2. 启动服务
    server.serve()
}

自定义 request distributor与处理器

示例:

import stdx.net.http.*
import std.collection.HashMap

class NaiveDistributor <: HttpRequestDistributor {
    let map = HashMap<String, HttpRequestHandler>()
    public func register(path: String, handler: HttpRequestHandler): Unit {
        map.add(path, handler)
    }

    public func distribute(path: String): HttpRequestHandler {
        if (path == "/index") {
            return PageHandler()
        }
        return NotFoundHandler()
    }
}

// 返回一个简单的 HTML 页面
class PageHandler <: HttpRequestHandler {
    public func handle(httpContext: HttpContext): Unit {
        httpContext.responseBuilder.body("<html></html>")
    }
}

main() {
    // 1. 构建 Server 实例并自定义分发器
    let server = ServerBuilder().addr("127.0.0.1").port(8080).distributor(NaiveDistributor()).build()
    // 2. 启动服务
    server.serve()
}

自定义 server 网络配置

示例:

import std.io.*
import std.fs.*
import stdx.net.tls.*
import stdx.crypto.x509.{X509Certificate, PrivateKey}
import stdx.net.http.*

//该程序需要用户配置存在且合法的文件路径才能执行
main() {
    // 1. 自定义配置
    // tcp 配置
    var transportCfg = TransportConfig()
    transportCfg.readBufferSize = 8192
    // tls 配置,需要传入配套的证书与私钥文件路径
    let pem0 = String.fromUtf8(readToEnd(File("/certPath", Read)))
    let pem02 = String.fromUtf8(readToEnd(File("/keyPath", Read)))
    var tlsConfig = TlsServerConfig(X509Certificate.decodeFromPem(pem0), PrivateKey.decodeFromPem(pem02))
    tlsConfig.supportedAlpnProtocols = ["h2"]
    // 2. 构建 Server 实例
    let server = ServerBuilder()
        .addr("127.0.0.1")
        .port(8080)
        .transportConfig(transportCfg)
        .tlsConfig(tlsConfig)
        .headerTableSize(10 * 1024)
        .maxRequestHeaderSize(1024 * 1024)
        .build()
    // 3. 注册 HttpRequestHandler
    server.distributor.register("/index", {
        httpContext => httpContext.responseBuilder.body("Hello 仓颉!")
    })
    // 4. 启动服务
    server.serve()
}

response中的 chunked与trailer

示例:

import stdx.net.http.*
import std.io.*
import std.collection.HashMap

func checksum(chunk: Array<UInt8>): Int64 {
    var sum = 0
    for (i in chunk) {
        if (i == UInt8(UInt32(r'\n'))) {
            sum += 1
        }
    }
    return sum / 2
}

main() {
    // 1. 构建 Server 实例
    let server = ServerBuilder().addr("127.0.0.1").port(8080).build()
    // 2. 注册 HttpRequestHandler
    server
        .distributor
        .register(
            "/index",
            {
                httpContext =>
                let responseBuilder = httpContext.responseBuilder
                responseBuilder.header("transfer-encoding", "chunked")
                responseBuilder.header("trailer", "checkSum")
                let writer = HttpResponseWriter(httpContext)
                var sum = 0
                for (_ in 0..10) {
                    let chunk = Array<UInt8>(10, repeat: 0)
                    sum += checksum(chunk)
                    writer.write(chunk)
                }
                // handler 结束后发送
                responseBuilder.trailer("checkSum", "${sum}")
            }
        )
    // 3. 启动服务
    server.serve()
}

处理重定向 request

示例:

import stdx.net.http.*

main() {
    // 1. 构建 Server 实例
    let server = ServerBuilder().addr("127.0.0.1").port(8080).build()
    // 2. 注册 HttpRequestHandler
    server.distributor.register("/redirecta", RedirectHandler("/movedsource", 308))
    server.distributor.register("/redirectb", RedirectHandler("http://www.example.com", 308))
    // 3. 启动服务
    server.serve()
}

tls 证书热加载

示例:

import std.io.*
import std.fs.*
import stdx.net.tls.*
import stdx.crypto.x509.{X509Certificate, PrivateKey}
import stdx.net.http.*

//该程序需要用户配置存在且合法的文件路径才能执行
main() {
    // 1. tls 配置
    let pem0 = String.fromUtf8(readToEnd(File("/certPath", Read)))
    let pem02 = String.fromUtf8(readToEnd(File("/keyPath", Read)))
    var tlsConfig = TlsServerConfig(X509Certificate.decodeFromPem(pem0), PrivateKey.decodeFromPem(pem02))
    tlsConfig.supportedAlpnProtocols = ["http/1.1"]
    let pem = String.fromUtf8(readToEnd(File("/rootCerPath", Read)))
    tlsConfig.verifyMode = CustomCA(X509Certificate.decodeFromPem(pem))
    // 2. 构建 Server 实例,并启动服务
    let server = ServerBuilder().addr("127.0.0.1").port(8080).tlsConfig(tlsConfig).build()
    spawn {
        server.serve()
    }
    // 3. 更新 tls 证书和私钥,之后收到的 request 将使用新的证书和私钥
    server.updateCert("/newCerPath", "/newKeyPath")
    // 4. 更新 CA ,双向认证时使用,之后收到的 request 将使用新的 CA
    server.updateCA("/newRootCerPath")
}

server push

仅用于 HTTP/2

client:

示例:

import std.io.*
import std.fs.*
import std.collection.ArrayList
import stdx.net.tls.*
import stdx.crypto.x509.X509Certificate
import stdx.net.http.*

//该程序需要用户配置存在且合法的文件路径才能执行
main() {
    // 1. tls 配置
    var tlsConfig = TlsClientConfig()
    let pem = String.fromUtf8(readToEnd(File("/rootCerPath", Read)))
    tlsConfig.verifyMode = CustomCA(X509Certificate.decodeFromPem(pem))
    tlsConfig.alpnProtocolsList = ["h2"]
    // 2. 构建 Client 实例
    let client = ClientBuilder().tlsConfig(tlsConfig).build()
    // 3. 发送 request ,接收 response
    let response = client.get("https://example.com/index.html")
    // 4. 收 pushResponse ,此例中相当于 client.get("http://example.com/picture.png") 的 response
    let pushResponses: Option<ArrayList<HttpResponse>> = response.getPush()
    client.close()
}

server:

示例:

import std.io.*
import std.fs.*
import stdx.net.tls.*
import stdx.crypto.x509.{X509Certificate, PrivateKey}
import stdx.net.http.*

// 该程序需要用户配置存在且合法的文件路径才能执行
main() {
    // 1. tls 配置
    let pem0 = String.fromUtf8(readToEnd(File("/certPath", Read)))
    let pem02 = String.fromUtf8(readToEnd(File("/keyPath", Read)))
    var tlsConfig = TlsServerConfig(X509Certificate.decodeFromPem(pem0), PrivateKey.decodeFromPem(pem02))
    tlsConfig.supportedAlpnProtocols = ["h2"]
    // 2. 构建 Server 实例
    let server = ServerBuilder().addr("127.0.0.1").port(8080).tlsConfig(tlsConfig).build()
    // 3. 注册原 request 的 handler
    server
        .distributor
        .register(
            "/index.html",
            {
                httpContext =>
                let pusher = HttpResponsePusher.getPusher(httpContext)
                match (pusher) {
                    case Some(pusher) => pusher.push("/picture.png", "GET", httpContext.request.headers)
                    case None => ()
                }
            }
        )
    // 4. 注册 pushRequest 的 handler
    server.distributor.register("/picture.png", {
        httpContext => httpContext.responseBuilder.body("picture.png")
    })
    // 4. 启动服务
    server.serve()
}

webSocket

示例:

import stdx.net.http.*
import stdx.encoding.url.*
import std.time.*
import std.sync.*
import std.collection.*
import stdx.log.*

let server = ServerBuilder().addr("127.0.0.1").port(0).build()

main() {
    // 1 启动服务器
    spawn {startServer()}
    sleep(Duration.millisecond * 200)

    let client = ClientBuilder().build()
    let u = URL.parse("ws://127.0.0.1:${server.port}/webSocket")

    let subProtocol = ArrayList<String>(["foo1", "bar1"])
    let headers = HttpHeaders()
    headers.add("test", "echo")

    // 2 完成 WebSocket 握手,获取 WebSocket 实例
    let websocket: WebSocket
    let respHeaders: HttpHeaders
    (websocket, respHeaders) = WebSocket.upgradeFromClient(client, u, subProtocols: subProtocol, headers: headers)
    client.close()

    println("subProtocol: ${websocket.subProtocol}")
    println(respHeaders.getFirst("rsp") ?? "")

    // 3 消息收发
    // 发送 hello
    websocket.write(TextWebFrame, "hello".toArray())
    // 接收消息
    let data = ArrayList<UInt8>()
    var frame = websocket.read()
    while (true) {
        match (frame.frameType) {
            case ContinuationWebFrame =>
                data.add(all: frame.payload)
                if (frame.fin) {
                    break
                }
            case TextWebFrame | BinaryWebFrame =>
                if (!data.isEmpty()) {
                    throw Exception("invalid frame")
                }
                data.add(all: frame.payload)
                if (frame.fin) {
                    break
                }
            case CloseWebFrame =>
                websocket.write(CloseWebFrame, frame.payload)
                break
            case PingWebFrame => websocket.writePongFrame(frame.payload)
            case _ => ()
        }
        frame = websocket.read()
    }
    println("data size: ${data.size}")
    println("last item: ${String.fromUtf8(data.toArray()[4096])}")

    // 4 关闭 websocket,
    // 收发 CloseFrame
    websocket.writeCloseFrame(status: 1000)
    let websocketFrame = websocket.read()
    println("close frame type: ${websocketFrame.frameType}")
    println("close frame payload: ${websocketFrame.payload}")

    // 关闭底层连接
    websocket.closeConn()

    server.close()
}

func startServer() {
    // 1 注册 handler
    server.distributor.register("/webSocket", handler1)
    server.logger.level = LogLevel.OFF
    server.serve()
}

// server:
func handler1(ctx: HttpContext): Unit {
    // 2 完成 websocket 握手,获取 websocket 实例
    let websocketServer = WebSocket.upgradeFromServer(
        ctx,
        subProtocols: ArrayList<String>(["foo", "bar", "foo1"]),
        userFunc: {
            request: HttpRequest =>
            let value = request.headers.getFirst("test") ?? ""
            let headers = HttpHeaders()
            headers.add("rsp", value)
            headers
        }
    )
    // 3 消息收发
    // 接收 hello
    let data = ArrayList<UInt8>()
    var frame = websocketServer.read()
    while (true) {
        match (frame.frameType) {
            case ContinuationWebFrame =>
                data.add(all: frame.payload)
                if (frame.fin) {
                    break
                }
            case TextWebFrame | BinaryWebFrame =>
                if (!data.isEmpty()) {
                    throw Exception("invalid frame")
                }
                data.add(all: frame.payload)
                if (frame.fin) {
                    break
                }
            case CloseWebFrame =>
                websocketServer.write(CloseWebFrame, frame.payload)
                break
            case PingWebFrame => websocketServer.writePongFrame(frame.payload)
            case _ => ()
        }
        frame = websocketServer.read()
    }
    println("data: ${String.fromUtf8(data.toArray())}")

    // 发 4097 个 a
    websocketServer.write(TextWebFrame, Array<UInt8>(4097, repeat: 97))

    // 4 关闭 websocket,
    // 收发 CloseFrame
    let websocketFrame = websocketServer.read()
    println("close frame type: ${websocketFrame.frameType}")
    println("close frame payload: ${websocketFrame.payload}")
    websocketServer.write(CloseWebFrame, websocketFrame.payload)
    // 关闭底层连接
    websocketServer.closeConn()
}

运行结果:

subProtocol: foo1
echo
data: hello
data size: 4097
last item: a
close frame type: CloseWebFrame
close frame payload: [3, 232]
close frame type: CloseWebFrame
close frame payload: [3, 232]

stdx.net.tls

功能介绍

tls 包用于进行安全加密的网络通信,提供创建 TLS 服务器、基于协议进行 TLS 握手、收发加密数据、恢复 TLS 会话等能力。

本包支持TLS 1.2 及 TLS 1.3 传输层安全协议通信。

使用本包需要外部依赖 OpenSSL 3sslcrypto 动态库文件,故使用前需安装相关工具:

  • 对于 Linux 操作系统,可参考以下方式:
    • 如果系统的包管理工具支持安装 OpenSSL 3 开发工具包,可通过这个方式安装,并确保系统安装目录下含有 libssl.solibssl.so.3libcrypto.solibcrypto.so.3 这些动态库文件,例如 Ubuntu 22.04 系统上可使用 sudo apt install libssl-dev 命令安装 libssl-dev 工具包;
    • 如果无法通过上面的方式安装,可自行下载 OpenSSL 3.x.x 源码编译安装软件包,并确保安装目录下含有 libssl.solibssl.so.3libcrypto.solibcrypto.so.3 这些动态库文件,然后可选择下面任意一种方式来保证系统链接器可以找到这些文件:
      • 在系统未安装 OpenSSL 的场景,安装时选择直接安装到系统路径下;
      • 安装在自定义目录的场景,将这些文件所在目录设置到环境变量 LD_LIBRARY_PATH 以及 LIBRARY_PATH 中。
  • 对于 Windows 操作系统,可按照以下步骤:
    • 自行下载 OpenSSL 3.x.x 源码编译安装 x64 架构软件包或者自行下载安装第三方预编译的供开发人员使用的 OpenSSL 3.x.x 软件包;
    • 确保安装目录下含有 libssl.dll.a(或 libssl.lib)、libssl-3-x64.dlllibcrypto.dll.a(或 libcrypto.lib)、libcrypto-3-x64.dll 这些库文件;
    • libssl.dll.a(或 libssl.lib)、libcrypto.dll.a(或 libcrypto.lib)所在的目录路径设置到环境变量 LIBRARY_PATH 中,将 libssl-3-x64.dlllibcrypto-3-x64.dll 所在的目录路径设置到环境变量 PATH 中。
  • 对于 macOS 操作系统,可参考以下方式:
    • 使用 brew install openssl@3 安装,并确保系统安装目录下含有 libcrypto.dyliblibcrypto.3.dylib 这两个动态库文件;
    • 如果无法通过上面的方式安装,可自行下载 OpenSSL 3.x.x 源码编译安装软件包,并确保安装目录下含有 libcrypto.dyliblibcrypto.3.dylib 这两个动态库文件,然后可选择下面任意一种方式来保证系统链接器可以找到这些文件:
      • 在系统未安装 OpenSSL 的场景,安装时选择直接安装到系统路径下;
      • 安装在自定义目录的场景,将这些文件所在目录设置到环境变量 DYLD_LIBRARY_PATH 以及 LIBRARY_PATH 中。

注意:

如果未安装OpenSSL 3软件包或者安装低版本的软件包,程序可能无法使用并抛出相关异常 TlsException: Can not load openssl library or function xxx.。

API 列表

类名功能
TlsSessionContext服务端启用 session 特性恢复会话,存储 session 用于对客户端进行验证类型。
TlsSocket用于在客户端及服务端间创建加密传输通道。

枚举

枚举名功能
CertificateVerifyMode证书认证模式。
SignatureAlgorithm签名算法类型,签名算法用于确保传输数据的身份验证、完整性和真实性。
SignatureSchemeType加密算法类型,用于保护网络通信的安全性和隐私性。
SignatureType签名算法类型,用于认证真实性。
TlsClientIdentificationMode服务端对客户端证书的认证模式。
TlsVersionTLS 协议版本。

结构体

结构体名功能
CipherSuiteTLS 中的密码套件。
TlsClientConfig客户端配置。
TlsServerConfig服务端配置。
TlsSession当客户端 TLS 握手成功后,将会生成一个会话,当连接因一些原因丢失后,客户端可以通过这个会话 id 复用此次会话,省略握手流程。

异常类

类名功能
TlsExceptionTLS 处理出现错误时抛出的异常类型。

class TlsSessionContext

public class TlsSessionContext <: Equatable<TlsSessionContext> & ToString

功能:该类表示 TLS 会话上下文,给客户端提供信息,确保客户端所连接的服务端仍为相同实例,用于连接复用时,验证客户端合法性。

说明:

当客户端尝试恢复会话时,双方都必须确保他们正在恢复与合法对端的会话。

父类型:

static func fromName(String)

public static func fromName(name: String): TlsSessionContext

功能:通过名称创建 TlsSessionContext 实例。

通过 TlsSessionContext 保存的名称获取 TlsSessionContext 对象。该名称用于区分 TLS 服务器,因此客户端依赖此名称来避免意外,尝试恢复与错误的服务器的连接。这里不一定使用加密安全名称,因为底层实现可以完成这项工作。从此函数返回的具有相同名称的两个 TlsSessionContext 可能不相等,并且不保证可替换。尽管它们是从相同的名称创建的,因此服务器实例应该在整个生命周期内创建一个 TlsSessionContext ,并且在每次 TlsSocket.server() 调用中使用它。

参数:

  • name: String - 会话上下文名称。

返回值:

func toString()

public override func toString(): String

功能:生成会话上下文名称字符串。

返回值:

operator func !=(TlsSessionContext)

public override operator func !=(other: TlsSessionContext)

功能:判断两 TlsSessionContext 实例名称是否不同。

参数:

返回值:

operator func ==(TlsSessionContext)

public override operator func ==(other: TlsSessionContext)

功能:判断两 TlsSessionContext 实例名称是否相同。

参数:

返回值:

class TlsSocket

public class TlsSocket <: StreamingSocket & ToString & Equatable<TlsSocket> & Hashable

功能:TlsSocket 用于在客户端及服务端间创建加密传输通道。

父类型:

  • StreamingSocket
  • ToString
  • Equatable<TlsSocket>
  • Hashable

prop alpnProtocolName

public prop alpnProtocolName: ?String

功能:读取协商到的应用层协议名称。

类型:?String

异常:

  • TlsException - 当套接字未完成 TLS 握手或本端 TLS 套接字已关闭时,抛出异常。
  • IllegalMemoryException - 当内存申请失败时,抛出异常。

prop cipherSuite

public prop cipherSuite: CipherSuite

功能:握手后协商到的加密套。

说明:

密码套件包含加密算法、用于消息认证的散列函数、密钥交换算法。

类型:CipherSuite

异常:

  • TlsException - 当套接字未完成 TLS 握手或本端 TLS 套接字已关闭时,抛出异常。

prop clientCertificate

public prop clientCertificate: ?Array<X509Certificate>

功能:客户端提供的客户端证书。在客户端获取时为本端证书,在服务端获取时为对端证书。

注意:

获取对端证书时,如果对端没有发送证书,该接口可能获取失败,返回 None。详见 peerCertificate

类型:?Array<X509Certificate>

异常:

  • TlsException - 当套接字未完成 TLS 握手或本端 TLS 套接字已关闭时,抛出异常。

prop domain

public prop domain: ?String

功能:读取协商到的服务端主机名称。

  • TlsException - 当套接字未完成 TLS 握手或本端 TLS 套接字已关闭时,抛出异常。

类型:?String

prop localAddress

public override prop localAddress: SocketAddress

功能:读取 TlsSocket 的本地地址。

类型:SocketAddress

异常:

  • SocketException - 本端建连的底层 TCP 套接字关闭,抛出异常。
  • TlsException - 本端配置为 TLS 的套接字已关闭时,抛出异常。

prop peerCertificate

public prop peerCertificate: ?Array<X509Certificate>

功能:获取对端证书。在客户端获取时同 serverCertificate,在服务端获取时同 clientCertificate

注意:

  • 如果握手时没有要求对端发送证书,此处将无法获取对端证书,返回 None。

  • 通过 session 机制恢复连接时,双方都不发送证书,该接口行为如下:

    • 在服务端,如果被恢复的原始连接建立时获取了对端证书,服务端将缓存对端证书,并在此处获取到缓存的证书;
    • 在客户端,不缓存原始连接的对端证书,此处将无法获取对端证书,返回 None。

类型:?Array<X509Certificate>

异常:

  • TlsException - 当套接字未完成 TLS 握手或本端 TLS 套接字已关闭时,抛出异常。

prop readTimeout

public override mut prop readTimeout: ?Duration

功能:读写 TlsSocket 的读超时时间。

类型:?Duration

异常:

  • SocketException - 本端建连的底层 TCP 套接字关闭,抛出异常。
  • TlsException - 本端配置为 TLS 的套接字已关闭时,抛出异常。
  • IllegalArgumentException - 设定的读超时时间为负值时,抛出异常。

prop remoteAddress

public override prop remoteAddress: SocketAddress

功能:读取 TlsSocket 的远端地址。

类型:SocketAddress

异常:

  • SocketException - 本端建连的底层 TCP 套接字关闭,抛出异常。
  • TlsException - 本端配置为 TLS 的套接字已关闭时,抛出异常。

prop serverCertificate

public prop serverCertificate: Array<X509Certificate>

功能:服务器证书链由服务器提供或在服务器配置中预先配置。在服务端获取时为本端证书,在客户端获取时为对端证书。

注意:

获取对端证书时,如果对端没有发送证书,该接口可能获取失败,返回 None。详见 peerCertificate

类型:Array<X509Certificate>

异常:

  • TlsException - 当套接字未完成 TLS 握手或本端 TLS 套接字已关闭时,抛出异常。

prop session

public prop session: ?TlsSession

功能:读取 TLS 会话 id , 客户端会在握手成功后捕获当前会话的 id ,可使用该 id 重用该会话,省去 TLS 建立连接时间。连接建立未成功时,返回 None

说明:

服务端不做捕获因此始终为 None。

类型:?TlsSession

异常:

  • TlsException - 当套接字未完成 TLS 握手,抛出异常。

prop socket

public prop socket: StreamingSocket

功能:TlsSocket 创建所使用的 StreamingSocket。

类型:StreamingSocket

异常:

  • TlsException - 本端配置为 TLS 套接字已关闭时,抛出异常。

prop tlsVersion

public prop tlsVersion: TlsVersion

功能:读取协商到的 TLS 版本。

类型:TlsVersion

异常:

  • TlsException - 当套接字未完成 TLS 握手或本端 TLS 套接字已关闭时,抛出异常。

prop writeTimeout

public override mut prop writeTimeout: ?Duration

功能:读写 TlsSocket 的写超时时间。

类型:?Duration

异常:

  • SocketException - 本端建连的底层 TCP 套接字关闭,抛出异常。
  • TlsException - 本端配置为 TLS 的套接字已关闭时,抛出异常。
  • IllegalArgumentException - 设定的写超时时间为负值时,抛出异常。

static func client(StreamingSocket, ?TlsSession, TlsClientConfig)

public static func client(
    socket: StreamingSocket,
    session!: ?TlsSession = None,
    clientConfig!: TlsClientConfig = TlsClientConfig()
): TlsSocket

功能:根据传入的 StreamingSocket 实例创建指定地址的客户端 TLS 套接字,该套接字可用于客户端 TLS 握手及会话。

参数:

  • socket: StreamingSocket - 已连接到服务端的客户端 TCP 套接字。
  • session!: ?TlsSession - TLS 会话 id,若存在可用的 TLS 会话, 则可通过该 id 恢复历史 TLS 会话,省去 TLS 建立连接时间,但使用该会话依然可能协商失败。默认为 None
  • clientConfig!: TlsClientConfig - 客户端配置,默认为 TlsClientConfig()。

返回值:

static func server(StreamingSocket, ?TlsSessionContext, TlsServerConfig)

public static func server(
    socket: StreamingSocket,
    sessionContext!: ?TlsSessionContext = None,
    serverConfig!: TlsServerConfig
): TlsSocket

功能:根据传入的 StreamingSocket 实例创建指定地址的服务端 TLS 套接字,该套接字可用于服务端 TLS 握手及会话。

参数:

  • socket: StreamingSocket - TCP 连接建立完成后接受到套接字。
  • sessionContext!: ?TlsSessionContext - TLS 会话 id, 若存在可用的 TLS 会话, 则可通过该 id 恢复历史 TLS 会话,省去 TLS 建立连接时间,但使用该会话依然可能协商失败。默认为 None。
  • serverConfig!: TlsServerConfig - 服务端配置,默认为 TlsServerConfig()。

返回值:

func close()

public func close(): Unit

功能:关闭套接字。

异常:

  • SocketException - 底层连接无法关闭时,抛出异常。

func handshake(?Duration)

public func handshake(timeout!: ?Duration = None): Unit

功能:TLS 握手。不支持重新协商握手,因此只能被调用一次。调用对象可以为客户端或者服务端的 TlsSocket

参数:

  • timeout!: ?Duration - 握手超时时间,默认为 None 不对超时时间进行设置,此时采用默认 30s 的超时时间。

异常:

  • SocketException - 本端建连的底层 TCP 套接字关闭,抛出异常。
  • SocketTimeoutException - 底层 TCP 套接字连接超时时,抛出异常。
  • TlsException - 当握手已经开始或者已经结束,抛出异常或当握手阶段出现系统错误时,抛出异常。
  • IllegalArgumentException - 设定的握手超时时间为负值时,抛出异常。

func hashCode()

public override func hashCode(): Int64

功能:返回 TLS 套接字对象的哈希值。

返回值:

  • Int64 - 对 TLS 套接字对象进行哈希计算后得到的结果。

func isClosed()

public func isClosed(): Bool

功能:返回套接字是否关闭的状态。

返回值:

  • Bool - 连接断开返回 true;否则,返回 false。

func read(Array<Byte>)

public override func read(buffer: Array<Byte>): Int64

功能:TlsSocket 读取数据。

参数:

  • buffer: Array<Byte> - 存储读取到的数据内容的数组。

返回值:

  • Int64 - 读取到的数据内容字节数。

异常:

  • SocketException - 本端建连的底层 TCP 套接字关闭,抛出异常。
  • TlsException - 当 buffer 为空,或者 TlsSocket 未连接,或读取数据出现系统错误等。

func toString()

public func toString(): String

功能:套接字的字符串表示,字符串内容为当前套接字状态。

说明:

例如:当前套接字处于可开始进行握手状态时,该接口将返回字符串 "TlsSocket(TcpSocket(${本端地址} -> ${对端地址}), ready for handshake)"

返回值:

  • String - 该 TLS 连接字符串。

func write(Array<Byte>)

public func write(buffer: Array<Byte>): Unit

功能:TlsSocket 发送数据。

参数:

  • buffer: Array<Byte> - 存储将要发送的数据内容数组。

异常:

  • SocketException - 本端建连的底层 TCP 套接字关闭,抛出异常。
  • TlsException - 当套接字已关闭,或者 TlsSocket 未连接,或写入数据出现系统错误等。

operator func !=(TlsSocket)

public override operator func !=(other: TlsSocket)

功能:判断两 TlsSocket 是否引用不同实例。

参数:

  • other: TlsSocket - 对比的 TLS 套接字。

返回值:

  • Unit - 对比的套接字不同返回 true;否则,返回 false

operator func ==(TlsSocket)

public override operator func ==(other: TlsSocket)

功能:判断两 TlsSocket 是否引用同一实例。

参数:

  • other: TlsSocket - 对比的 TLS 套接字。

返回值:

  • Unit - 对比的套接字相同返回 true;否则,返回 false

枚举

enum CertificateVerifyMode

public enum CertificateVerifyMode {
    | CustomCA(Array<X509Certificate>)
    | Default
    | TrustAll
}

功能:对证书验证的处理模式。

说明:

CustomCA 模式可使用用户配置的证书地址,适用于用户证书无法设置为系统证书的场景。
证书认证模式,TCP 连接建立成功后,客户端和服务端可交换证书,Default 模式使用系统证书。
在开发测试阶段,可使用 TrustAll 模式,该模式表示本端不作对对端证书的校验。此模式本端信任任意建立连接对象,一般仅在开发测试阶段使用。

CustomCA(Array<X509Certificate>)

CustomCA(Array<X509Certificate>)

功能:表示根据提供的 CA 列表进行验证。

Default

Default

功能:表示默认验证模式,根据系统 CA 验证证书。

TrustAll

TrustAll

功能:表示信任所有证书。

enum SignatureAlgorithm

public enum SignatureAlgorithm <: ToString & Equatable<SignatureAlgorithm> {
    | SignatureAndHashAlgorithm(SignatureType, HashType)
    | SignatureScheme(SignatureSchemeType)
}

功能:签名算法类型,签名算法用于确保传输数据的身份验证、完整性和真实性。

父类型:

SignatureAndHashAlgorithm(SignatureType, HashType)

SignatureAndHashAlgorithm(SignatureType, HashType)

功能:表明哪个签名和哈希算法对会被用于数字签名,自 TLS 1.2 及以后版本,包含签名和哈希算法类型。

SignatureScheme(SignatureSchemeType)

SignatureScheme(SignatureSchemeType)

功能:签名方案,自 TLS 1.3 及以后版本,业界更为推荐的指定签名算法的方式。

func toString()

public func toString():String

功能:转换签名算法的字符串表示。

返回值:

  • String - 签名算法名称。

operator func !=(SignatureAlgorithm)

public operator func !=(other: SignatureAlgorithm) : Bool

功能:判断签名算法类型是否不同。

参数:

返回值:

  • Bool - 不相同返回 true;否则,返回 false

operator func ==(SignatureAlgorithm)

public operator func ==(other: SignatureAlgorithm) : Bool

功能:判断签名算法类型是否相同。

参数:

返回值:

  • Bool - 相同返回 true;否则,返回 false

enum SignatureSchemeType

public enum SignatureSchemeType <: ToString & Equatable<SignatureSchemeType> {
    | RSA_PKCS1_SHA256
    | RSA_PKCS1_SHA384
    | RSA_PKCS1_SHA512
    | ECDSA_SECP256R1_SHA256
    | ECDSA_SECP384R1_SHA384
    | ECDSA_SECP521R1_SHA512
    | RSA_PSS_RSAE_SHA256
    | RSA_PSS_RSAE_SHA384
    | RSA_PSS_RSAE_SHA512
    | ED25519
    | ED448
    | RSA_PSS_PSS_SHA256
    | RSA_PSS_PSS_SHA384
    | RSA_PSS_PSS_SHA512
}

功能:加密算法类型,用于保护网络通信的安全性和隐私性。

父类型:

ECDSA_SECP256R1_SHA256

ECDSA_SECP256R1_SHA256

功能:创建一个 ECDSA_SECP256R1_SHA256 类型的枚举实例,表示加密算法类型使用 ECDSA_SECP256R1_SHA256

ECDSA_SECP384R1_SHA384

ECDSA_SECP384R1_SHA384

功能:创建一个 ECDSA_SECP384R1_SHA384 类型的枚举实例,表示加密算法类型使用 ECDSA_SECP384R1_SHA384

ECDSA_SECP521R1_SHA512

ECDSA_SECP521R1_SHA512

功能:创建一个 ECDSA_SECP521R1_SHA512 类型的枚举实例,表示加密算法类型使用 ECDSA_SECP521R1_SHA512

ED25519

ED25519

功能:创建一个 ED25519 类型的枚举实例,表示加密算法类型使用 ED25519。

ED448

ED448

功能:创建一个 ED448 类型的枚举实例,表示加密算法类型使用 ED448。

RSA_PKCS1_SHA256

RSA_PKCS1_SHA256

功能:创建一个 RSA_PKCS1_SHA256 类型的枚举实例,表示加密算法类型使用 RSA_PKCS1_SHA256

RSA_PKCS1_SHA384

RSA_PKCS1_SHA384

功能:创建一个 RSA_PKCS1_SHA384 类型的枚举实例,表示加密算法类型使用 RSA_PKCS1_SHA384

RSA_PKCS1_SHA512

RSA_PKCS1_SHA512

功能:创建一个 RSA_PKCS1_SHA512 类型的枚举实例,表示加密算法类型使用 RSA_PKCS1_SHA512

RSA_PSS_PSS_SHA256

RSA_PSS_PSS_SHA256

功能:创建一个 RSA_PSS_PSS_SHA256 类型的枚举实例,表示加密算法类型使用 RSA_PSS_PSS_SHA256

RSA_PSS_PSS_SHA384

RSA_PSS_PSS_SHA384

功能:创建一个 RSA_PSS_PSS_SHA384 类型的枚举实例,表示加密算法类型使用 RSA_PSS_PSS_SHA384

RSA_PSS_PSS_SHA512

RSA_PSS_PSS_SHA512

功能:创建一个 RSA_PSS_PSS_SHA512 类型的枚举实例,表示加密算法类型使用 RSA_PSS_PSS_SHA512

RSA_PSS_RSAE_SHA256

RSA_PSS_RSAE_SHA256

功能:创建一个 RSA_PSS_RSAE_SHA256 类型的枚举实例,表示加密算法类型使用 RSA_PSS_RSAE_SHA256

RSA_PSS_RSAE_SHA384

RSA_PSS_RSAE_SHA384

功能:创建一个 RSA_PSS_RSAE_SHA384 类型的枚举实例,表示加密算法类型使用 RSA_PSS_RSAE_SHA384

RSA_PSS_RSAE_SHA512

RSA_PSS_RSAE_SHA512

功能:创建一个 RSA_PSS_RSAE_SHA512 类型的枚举实例,表示加密算法类型使用 RSA_PSS_RSAE_SHA384

func toString()

public func toString(): String

功能:加密算法类型的字符串表示。

RSA_PKCS1_SHA256 的字符串表示为 "rsa_pkcs1_sha256"。

返回值:

  • String - 加密算法类型的字符串表示。

operator func !=(SignatureSchemeType)

public operator func !=(other: SignatureSchemeType): Bool

功能:判断两者是否为不同加密算法类型。

参数:

返回值:

  • Bool - 不相同返回 true;否则,返回 false。

operator func ==(SignatureSchemeType)

public operator func ==(other: SignatureSchemeType): Bool

功能:判断两者是否为同一加密算法类型。

参数:

返回值:

  • Bool - 相同返回 true;否则,返回 false。

enum SignatureType

public enum SignatureType <: ToString & Equatable<SignatureType> {
    | DSA
    | ECDSA
    | RSA
}

功能:签名算法类型,用于认证真实性。参见 RFC5246 7.4.1.4.1 章节。

父类型:

DSA

DSA

功能:创建一个 DSA 类型的枚举实例,表示采用数字签名算法。

ECDSA

ECDSA

功能:创建一个 ECDSA 类型的枚举实例,表示采用椭圆曲线数字签名算法。

RSA

RSA

功能:创建一个 RSA 类型的枚举实例,表示采用 RSA 加密算法。

func toString()

public func toString(): String

功能:转换为签名算法的字符串表示。

返回值:

  • String - 签名算法的名称。

operator func !=(SignatureType)

public operator func !=(other: SignatureType) : Bool

功能:判断两者是否为不同的签名算法。

参数:

返回值:

  • Bool - 不相同返回 true;否则,返回 false

operator func ==(SignatureType)

public operator func ==(other: SignatureType) : Bool

功能:判断两者是否为相同的签名算法。

参数:

返回值:

  • Bool - 相同返回 true;否则,返回 false

enum TlsClientIdentificationMode

public enum TlsClientIdentificationMode {
    | Disabled
    | Optional
    | Required
}

功能:服务端对客户端证书的认证模式。

Disabled

Disabled

功能:表示服务端不校验客户端证书,客户端可以不发送证书和公钥,即单向认证。

Optional

Optional

功能:表示服务端校验客户端证书,但客户端可以不提供证书及公钥,不提供时则单向认证,提供时则为双向认证。

Required

Required

功能:表示服务端校验客户端证书,并且要求客户端必须提供证书和公钥,即双向认证。

enum TlsVersion

public enum TlsVersion <: ToString {
    | V1_2
    | V1_3
    | Unknown
}

功能:TLS 协议版本

父类型:

  • ToString

Unknown

Unknown

功能:表示未知协议版本。

V1_2

V1_2

功能:表示 TLS 1.2。

V1_3

V1_3

功能:表示 TLS 1.3。

func toString()

public override func toString(): String

功能:返回当前 TlsVersion 的字符串表示。

返回值:

  • String - 当前 TlsVersion 的字符串表示。

结构体

struct CipherSuite

public struct CipherSuite <: ToString & Equatable<CipherSuite>

功能:TLS 中的密码套件。

父类型:

static prop allSupported

public static prop allSupported: Array<CipherSuite>

功能:返回所有支持的密码套件。

返回值:存放密码套件的数组。

类型:Array<CipherSuite>

func toString()

public func toString(): String

功能:返回密码套件名称。

返回值:

  • String - 密码套件名称。

operator func !=(CipherSuite)

public operator func !=(that: CipherSuite): Bool

功能:判断两个密码套件是否不等。

参数:

  • that: CipherSuite - 被比较的密码套件对象。

返回值:

  • Bool - 若不等,则返回 true;反之,返回 false

operator func ==(CipherSuite)

public operator func ==(that: CipherSuite): Bool

功能:判断两个密码套件是否相等。

参数:

  • that: CipherSuite - 被比较的密码套件对象。

返回值:

  • Bool - 若相等,则返回 true;反之,返回 false

struct TlsClientConfig

public struct TlsClientConfig {
    public var keylogCallback: ?(TlsSocket, String) -> Unit = None
    public var verifyMode: CertificateVerifyMode = CertificateVerifyMode.Default
    public init()
}

功能:客户端配置。

var keylogCallback

public var keylogCallback: ?(TlsSocket, String) -> Unit = None

功能:握手过程的回调函数,提供 TLS 初始秘钥数据,用于调试和解密记录使用。

类型:?(TlsSocket, String) -> Unit

var verifyMode

public var verifyMode: CertificateVerifyMode = CertificateVerifyMode.Default

功能:设置或获取证书认证模式,默认为 Default

类型:CertificateVerifyMode

prop alpnProtocolsList

public mut prop alpnProtocolsList: Array<String>

功能:要求的应用层协议名称。若列表为空,则客户将不协商应用层协议。

类型:Array<String>

异常:

  • IllegalArgumentException - 列表元素有 '\0' 字符时,抛出异常。

prop cipherSuitesV1_2

public mut prop cipherSuitesV1_2: ?Array<String>

功能:基于 TLS 1.2 协议下的加密套。

类型:?Array<String>

异常:

  • IllegalArgumentException - 列表元素有 '\0' 字符时,抛出异常。

prop cipherSuitesV1_3

public mut prop cipherSuitesV1_3: ?Array<String>

功能:基于 TLS 1.3 协议下的加密套。

类型:?Array<String>

异常:

  • IllegalArgumentException - 列表元素有 '\0' 字符时,抛出异常。

prop clientCertificate

public mut prop clientCertificate: ?(Array<X509Certificate>, PrivateKey)

功能:客户端证书和私钥。

类型:?(Array<X509Certificate>, PrivateKey)

prop domain

public mut prop domain: ?String

功能:读写要求的服务端主机地址 (SNI), None 表示不要求。

类型:?String

异常:

  • IllegalArgumentException - 参数有 '\0' 字符时,抛出异常。

prop maxVersion

public mut prop maxVersion: TlsVersion

功能:支持的 TLS 最大的版本。

注意:

当仅设置 maxVersion 而未设置 minVersion ,或设置的 maxVersion 低于 minVersion ,将会在握手阶段抛出 TlsException

类型:TlsVersion

prop minVersion

public mut prop minVersion: TlsVersion

功能:支持的 TLS 最小的版本。

注意:

当仅设置 minVersion 而未设置 maxVersion ,或设置的 minVersion 高于 maxVersion ,将会在握手阶段抛出 TlsException

类型:TlsVersion

prop securityLevel

public mut prop securityLevel: Int32

功能:指定客户端的安全级别,默认值为2,可选参数值在 0-5 内,参数值含义参见 openssl-SSL_CTX_set_security_level 说明。

类型:Int32

prop signatureAlgorithms

public mut prop signatureAlgorithms: ?Array<SignatureAlgorithm>

功能:指定保序的签名和哈希算法。在值为 None 或者列表为空时,客户端会使用默认的列表。指定列表后,客户端可能不会发送不合适的签名算法。 参见 RFC5246 7.4.1.4.1 (TLS 1.2) 章节, RFC8446 4.2.3. (TLS 1.3) 章节。

类型:?Array<SignatureAlgorithm>

init()

public init()

功能:构造 TlsClientConfig

struct TlsServerConfig

public struct TlsServerConfig {
    public var clientIdentityRequired: TlsClientIdentificationMode = Disabled
    public var keylogCallback: ?(TlsSocket, String) -> Unit = None
    public var verifyMode: CertificateVerifyMode = CertificateVerifyMode.Default
    public init(certChain: Array<X509Certificate>, certKey: PrivateKey)
}

功能:服务端配置。

var clientIdentityRequired

public var clientIdentityRequired: TlsClientIdentificationMode = Disabled

功能:设置或获取服务端要求客户端的认证模式,默认不要求客户端认证服务端证书,也不要求客户端发送本端证书。

类型:TlsClientIdentificationMode

var keylogCallback

public var keylogCallback: ?(TlsSocket, String) -> Unit = None

功能:握手过程的回调函数,提供 TLS 初始秘钥数据,用于调试和解密记录使用。

类型:?(TlsSocket, String) -> Unit

var verifyMode

public var verifyMode: CertificateVerifyMode = CertificateVerifyMode.Default

功能:设置或获取认证模式,默认认证系统证书。

类型:CertificateVerifyMode

prop cipherSuitesV1_2

public mut prop cipherSuitesV1_2: Array<String>

功能:基于 TLS 1.2 协议下的加密套。

类型:Array<String>

异常:

  • IllegalArgumentException - 列表元素有 '\0' 字符时,抛出异常。

prop cipherSuitesV1_3

public mut prop cipherSuitesV1_3: Array<String>

功能:基于 TLS 1.3 协议下的加密套。

类型:Array<String>

异常:

  • IllegalArgumentException - 列表元素有 '\0' 字符时,抛出异常。

prop dhParameters

public mut prop dhParameters: ?DHParamters

功能:指定服务端的 DH 密钥参数,默认为 None, 默认情况下使用 openssl 自动生成的参数值。

类型:?DHParamters

prop maxVersion

public mut prop maxVersion: TlsVersion

功能:支持的最大 TLS 版本。

注意:

当仅设置 maxVersion 而未设置 minVersion ,或设置的 maxVersion 低于 minVersion ,将会在握手阶段抛出 TlsException

类型:TlsVersion

prop minVersion

public mut prop minVersion: TlsVersion

功能:支持的最小 TLS 版本。

注意:

当仅设置 minVersion 而未设置 maxVersion ,或设置的 minVersion 高于 maxVersion ,将会在握手阶段抛出 TlsException

类型:TlsVersion

prop securityLevel

public mut prop securityLevel: Int32

功能:指定服务端的安全级别,默认值为2,可选参数值在 [0,5] 内,参数值含义参见 openssl-SSL_CTX_set_security_level 说明。 功能:指定服务端的安全级别,默认值为2,可选参数值在 0-5 内,参数值含义参见 openssl-SSL_CTX_set_security_level 说明。

类型:Int32

异常:

  • IllegalArgumentException - 当配置值不在 0-5 范围内时,抛出异常。

prop serverCertificate(Array<X509Certificate>, PrivateKey)

public mut prop serverCertificate: (Array<X509Certificate>, PrivateKey)

功能:服务端证书和对应的私钥文件。

类型:(Array<X509Certificate>, PrivateKey)

prop supportedAlpnProtocols

public mut prop supportedAlpnProtocols: Array<String>

功能:应用层协商协议,若客户端尝试协商该协议,服务端将与选取其中相交的协议名称。若客户端未尝试协商协议,则该配置将被忽略。

类型:Array<String>

异常:

  • IllegalArgumentException - 列表元素有 '\0' 字符时,抛出异常。

init(Array<X509Certificate>, PrivateKey)

public init(certChain: Array<X509Certificate>, certKey: PrivateKey)

功能:构造 TlsServerConfig 对象。

参数:

struct TlsSession

public struct TlsSession <: Equatable<TlsSession> & ToString & Hashable

功能:此结构体表示已建立的客户端会话。此结构体实例用户不可创建,其内部结构对用户不可见。

当客户端 TLS 握手成功后,将会生成一个会话,当连接因一些原因丢失后,客户端可以通过这个会话 id 复用此次会话,省略握手流程。

父类型:

func hashCode()

public override func hashCode(): Int64

功能:生成会话 id 哈希值。

返回值:

  • Int64 - 会话 id 哈希值。

func toString()

public override func toString(): String

功能:生成会话 id 字符串。

返回值:

operator func !=(TlsSession)

public override operator func !=(other: TlsSession)

功能:判断会话 id 是否不同。

参数:

返回值:

  • Unit - 若会话对象不同,返回 true;否则,返回 false

operator func ==(TlsSession)

public override operator func ==(other: TlsSession)

功能:判断会话 id 是否相同。

参数:

返回值:

  • Unit - 若会话对象相同,返回 true;否则,返回 false

异常类

class TlsException

public class TlsException <: Exception {
    public init()
    public init(message: String)
}

功能:TLS 处理出现错误时抛出的异常。

父类型:

  • Exception

init()

public init()

功能:创建 TlsException 实例,异常提示消息为空。

init(String)

public init(message: String)

功能:根据异常信息创建 TlsException 实例。

参数:

  • message: String - 异常信息。

服务端证书及公钥在一份文件中

说明:

需要自行准备证书文件。

示例:

import std.io.*
import std.{fs.*, collection.*}
import stdx.net.tls.*
import stdx.crypto.x509.{X509Certificate, PrivateKey, Pem, PemEntry, DerBlob}

let certificatePath = "/etc/myserver/cert-and-key.pem"

func parsePem(text: String): (Array<X509Certificate>, PrivateKey) {
    let pem = Pem.decode(text)
    let chain = pem |> filter<PemEntry> {entry => entry.label == PemEntry.LABEL_CERTIFICATE} |>
        map<PemEntry, X509Certificate> {entry => X509Certificate.decodeFromDer(entry.body ?? DerBlob())} |> collectArray

    let key = (pem |> filter<PemEntry> {entry => entry.label == PemEntry.LABEL_PRIVATE_KEY} |>
        map<PemEntry, PrivateKey> {entry => PrivateKey.decodeDer(entry.body ?? DerBlob())} |> first) ?? throw Exception(
        "No private key found in the PEM file")

    if (chain.isEmpty()) {
        throw Exception("No certificates found in the PEM file")
    }

    return (chain, key)
}

func readTextFromFile(path: String): String {
    var fileString = ""
    try (file = File(path, Read)) {
        fileString = String.fromUtf8(readToEnd(file))
        ()
    }
    fileString
}

main() {
    // 对证书及私钥进行解析
    let pem = readTextFromFile(certificatePath)

    let (certificate, privateKey) = parsePem(pem)

    var _ = TlsServerConfig(certificate, privateKey)

    // 进行 https 服务,请参阅其他服务器示例
}

客户端示例

示例:

import std.net.TcpSocket
import stdx.crypto.x509.{X509Certificate, PrivateKey}
import stdx.net.tls.*

main() {
    var config = TlsClientConfig()
    config.verifyMode = TrustAll
    config.alpnProtocolsList = ["h2"]

    // 用于恢复会话
    var lastSession: ?TlsSession = None
    // 重新连接环路
    while (true) {
        try (socket = TcpSocket("127.0.0.1", 8443)) {
            // 首先进行 TCP 连接
            socket.connect()
            try (tls = TlsSocket.client(socket, clientConfig: config, session: lastSession)) {
                try {
                    tls.handshake()
                    // 如果成功协商下一次重新连接,将记住会话
                    lastSession = tls.session
                } catch (e: Exception) {
                    // 如果协商失败,将删除会话
                    lastSession = None
                    throw e
                }
                // tls 实例已完成
                tls.write("Hello, peer! Let's discuss our personal secrets.\n".toArray())
            }
        } catch (e: Exception) {
            println("client connection failed ${e}, retrying...")
        }
    }
}

证书热更新

示例:

import std.net.StreamingSocket
import stdx.crypto.x509.{X509Certificate, PrivateKey}
import stdx.net.tls.*

class MyServer {
    private var currentConfig: TlsServerConfig

    init(initialConfig: TlsServerConfig) {
        currentConfig = initialConfig
    }

    // 更改带有密钥的证书只会影响新的连接
    public mut prop certificate: (Array<X509Certificate>, PrivateKey) {
        get() {
            currentConfig.serverCertificate
        }
        set(newCertificate) {
            currentConfig.serverCertificate = newCertificate
        }
    }

    public func onAcceptedConnection(client: StreamingSocket) {
        try (tls = TlsSocket.server(client, serverConfig: currentConfig)) {
            tls.handshake()
        }
    }
}

main() {}

服务端示例

说明:

需要自行准备证书文件。

示例:

import std.io.*
import std.fs.{File, OpenMode}
import std.net.{TcpServerSocket, TcpSocket}
import stdx.crypto.x509.{X509Certificate, PrivateKey}
import stdx.net.tls.*

// 证书及私钥路径,用户需自备
let certificatePath = "./files/apiserver.crt"
let certificateKeyPath = "./files/apiserver.key"

main() {
    // 对证书以及私钥进行解析
    let pem = readTextFromFile(certificatePath)
    let keyText = readTextFromFile(certificateKeyPath)

    let certificate = X509Certificate.decodeFromPem(pem)
    let privateKey = PrivateKey.decodeFromPem(keyText)

    let config = TlsServerConfig(certificate, privateKey)

    // 可选:允许恢复 TLS 会话
    let sessions = TlsSessionContext.fromName("my-server")

    try (server = TcpServerSocket(bindAt: 8443)) {
        server.bind()

        server.acceptLoop {
            clientSocket => try (tls = TlsSocket.server(clientSocket, serverConfig: config, sessionContext: sessions)) {
                tls.handshake()
                let buffer = Array<Byte>(100, repeat: 0)
                tls.read(buffer)
                println(buffer)
            }
        }
    }
}

extend TcpServerSocket {
    func acceptLoop(handler: (TcpSocket) -> Unit) {
        while (true) {
            let client = accept()
            spawn {
                try {
                    handler(client)
                } finally {
                    client.close()
                }
            }
        }
    }
}

func readTextFromFile(path: String): String {
    var str = ""
    try (file = File(path, Read)) {
        str = String.fromUtf8(readToEnd(file))
    }
    str
}

stdx.serialization.serialization

功能介绍

serialization 包提供了序列化和反序列化的能力。

序列化(serialization)是指将数据结构或对象状态转换成可取用格式(例如存成文件形式,存于缓冲,或经由网络中发送),以留待后续在相同或另一台计算机环境中,能恢复原先状态的过程。相对地,从一系列字节提取数据结构的反向操作,即反序列化(deserialization)。

用户定义的类型,可以通过实现 Serializable 接口,来支持序列化和反序列化。

API列表

函数

函数名功能
field<T>(String, T)用于将一组数据 namedata 封装到 Field 对象中。

接口

接口名功能
Serializable用于规范序列化。

类名功能
DataModel中间数据层。
DataModelBool此类为 DataModel 的子类,实现对 Bool 类型数据的封装。
DataModelFloat此类为 DataModel 的子类,实现对 Float64 类型数据的封装。
DataModelInt此类为 DataModel 的子类,实现对 Int64 类型数据的封装。
DataModelNull此类为 DataModel 的子类,实现对 Null 类型数据的封装。
DataModelSeq此类为 DataModel 的子类,实现对 ArrayList<DataModel> 类型数据的封装。
DataModelString此类为 DataModel 的子类,实现对 String 类型数据的封装。
DataModelStruct此类为 DataModel 的子类,用来实现 class 对象到 DataModel 的转换。
Field用于存储 DataModelStruct 的元素。

异常类

异常类名功能
DataModelExceptionDataModel 的异常类。

函数

func field<T>(String, T) where T <: Serializable<T>

public func field<T>(name: String, data: T) : Field where T <: Serializable<T>

功能:此函数用于将一组数据 namedata 封装到 Field 对象中。处理一组数据 namedata,将 data 序列化为 DataModel 类型,并将二者封装到 Field 对象中。

参数:

  • name: String - String 类型,name 字段为 "" 时行为与为其它字符串时一致。
  • data: T - T 类型,T 类型必须实现 Serializable<T> 接口。

返回值:

  • Field - 封装了 namedataField 对象。

接口

interface Serializable

public interface Serializable<T> {
    func serialize(): DataModel
    static func deserialize(dm: DataModel): T
}

功能:用于规范序列化。

static func deserialize(DataModel)

static func deserialize(dm: DataModel): T

功能:将 DataModel 反序列化为对象。

说明:

支持实现 Serializable 的类型包括:

  • 基本数据类型:整数类型、浮点类型、布尔类型、字符类型、字符串类型。
  • Collection 类型:Array、ArrayList、HashSet、HashMap、Option。
  • 用户自定义的实现了 Serializable<T> 的类型。

参数:

  • dm: DataModel - 待反序列化的数据。

返回值:

  • T - 反序列化的对象。

异常:

  • DataModelException - 当 dm 的类型不支持反序列化到 T 类型时,抛出异常。

func serialize()

func serialize(): DataModel

功能:将自身序列化为 DataModel

返回值:

extend<T> Array<T> <: Serializable<Array<T>> where T <: Serializable<T>

extend<T> Array<T> <: Serializable<Array<T>> where T <: Serializable<T>

功能:为 Array<T> 类型实现 Serializable<Array<T>> 接口。

父类型:

static func deserialize(DataModel)

static public func deserialize(dm: DataModel): Array<T>

功能:将 DataModel 反序列化为 Array<T>。

参数:

返回值:

  • Array<T> - 反序列化后的 Array<T>。

异常:

func serialize()

public func serialize(): DataModel

功能:将 Array<T> 序列化为 DataModelSeq

返回值:

extend<T> ArrayList<T> <: Serializable<ArrayList<T>> where T <: Serializable<T>

extend<T> ArrayList<T> <: Serializable<ArrayList<T>> where T <: Serializable<T>

功能:为 ArrayList<T> 类型实现 Serializable<ArrayList<T>> 接口。

父类型:

static func deserialize(DataModel)

static public func deserialize(dm: DataModel): ArrayList<T>

功能:将 DataModel 反序列化为 ArrayList<T>。

参数:

返回值:

  • ArrayList<T> - 反序列化后的 ArrayList<T>。

异常:

func serialize()

public func serialize(): DataModel

功能:将 ArrayList<T> 序列化为 DataModelSeq

返回值:

extend Bool <: Serializable

extend Bool <: Serializable<Bool>

功能:为 Bool 类型实现 Serializable 接口。

父类型:

static func deserialize(DataModel)

static public func deserialize(dm: DataModel): Bool

功能:将 DataModel 反序列化为 Bool。

参数:

返回值:

  • Bool - 反序列化后的 Bool。

异常:

func serialize()

public func serialize(): DataModel

功能:将 Bool 序列化为 DataModelBool

返回值:

extend Float16 <: Serializable

extend Float16 <: Serializable<Float16>

功能:为 Float16 类型实现 Serializable 接口。

父类型:

static func deserialize(DataModel)

static public func deserialize(dm: DataModel): Float16

功能:将 DataModel 反序列化为 Float16。

参数:

返回值:

  • Float16 - 反序列化后的 Float16。

异常:

func serialize()

public func serialize(): DataModel

功能:将 Float16 序列化为 DataModelFloat

返回值:

extend Float32 <: Serializable

extend Float32 <: Serializable<Float32>

功能:为 Float32 类型实现 Serializable 接口。

父类型:

static func deserialize(DataModel)

static public func deserialize(dm: DataModel): Float32

功能:将 DataModel 反序列化为 Float32。

参数:

返回值:

  • Float32 - 反序列化后的 Float32。

异常:

func serialize()

public func serialize(): DataModel

功能:将 Float32 序列化为 DataModelFloat

返回值:

extend Float64 <: Serializable

extend Float64 <: Serializable<Float64>

功能:为 Float64 类型实现 Serializable 接口。

父类型:

static func deserialize(DataModel)

static public func deserialize(dm: DataModel): Float64

功能:将 DataModel 反序列化为 Float64。

参数:

返回值:

  • Float64 - 反序列化后的 Float64。

异常:

func serialize()

public func serialize(): DataModel

功能:将 Float64 序列化为 DataModelFloat

返回值:

extend<K, V> HashMap<K, V> <: Serializable<HashMap<K, V>> where K <: Serializable<K> & Hashable & Equatable<K>, V <: Serializable<V>

extend<K, V> HashMap<K, V> <: Serializable<HashMap<K, V>> where K <: Serializable<K> & Hashable & Equatable<K>, V <: Serializable<V>

功能:为 HashMap<K, V> 类型实现 Serializable<HashMap<K, V>> 接口。

父类型:

static func deserialize(DataModel)

static public func deserialize(dm: DataModel): HashMap<K, V>

功能:将 DataModel 反序列化为 HashMap<K, V>。

参数:

返回值:

  • HashMap<K, V> - 反序列化后的 HashMap<K, V>。

异常:

func serialize()

public func serialize(): DataModel

功能:将 HashMap<K, V> 序列化为 DataModelSeq

返回值:

异常:

  • DataModelException - 当前 HashMap 实例中的 Key 不是 String 类型时,抛出异常。

extend<T> HashSet<T> <: Serializable<HashSet<T>> where T <: Serializable<T> & Hashable & Equatable<T>

extend<T> HashSet<T> <: Serializable<HashSet<T>> where T <: Serializable<T> & Hashable & Equatable<T>

功能:为 HashSet<T> 类型实现 Serializable<HashSet<T>> 接口。

父类型:

static func deserialize(DataModel)

static public func deserialize(dm: DataModel): HashSet<T>

功能:将 DataModel 反序列化为 HashSet<T>。

参数:

返回值:

  • HashSet<T> - 反序列化后的 HashSet<T>。

异常:

func serialize()

public func serialize(): DataModel

功能:将 HashSet<T> 序列化为 DataModelSeq

返回值:

extend Int16 <: Serializable

extend Int16 <: Serializable<Int16>

功能:为 Int16 类型实现 Serializable 接口。

父类型:

static func deserialize(DataModel)

static public func deserialize(dm: DataModel): Int16

功能:将 DataModel 反序列化为 Int16。

参数:

返回值:

  • Int16 - 反序列化后的 Int16。

异常:

func serialize()

public func serialize(): DataModel

功能:将 Int16 序列化为 DataModelInt

返回值:

extend Int32 <: Serializable

extend Int32 <: Serializable<Int32>

功能:为 Int32 类型实现 Serializable 接口。

父类型:

static func deserialize(DataModel)

static public func deserialize(dm: DataModel): Int32

功能:将 DataModel 反序列化为 Int32。

参数:

返回值:

  • Int32 - 反序列化后的 Int32。

异常:

func serialize()

public func serialize(): DataModel

功能:将 Int32 序列化为 DataModelInt

返回值:

extend Int64 <: Serializable

extend Int64 <: Serializable<Int64>

功能:为 Int64 类型实现 Serializable 接口。

父类型:

static func deserialize(DataModel)

static public func deserialize(dm: DataModel): Int64

功能:将 DataModel 反序列化为 Int64。

参数:

返回值:

  • Int64 - 反序列化后的 Int64。

异常:

func serialize()

public func serialize(): DataModel

功能:将 Int64 序列化为 DataModelInt

返回值:

extend Int8 <: Serializable

extend Int8 <: Serializable<Int8>

功能:为 Int8 类型实现 Serializable 接口。

父类型:

static func deserialize(DataModel)

static public func deserialize(dm: DataModel): Int8

功能:将 DataModel 反序列化为 Int8。

参数:

返回值:

  • Int8 - 反序列化后的 Int8。

异常:

func serialize()

public func serialize(): DataModel

功能:将 Int8 序列化为 DataModelInt

返回值:

extend<T> Option<T> <: Serializable<Option<T>> where T <: Serializable<T>

extend<T> Option<T> <: Serializable<Option<T>> where T <: Serializable<T>

功能:为 Option<T> 类型实现 Serializable<Option<T>> 接口。

父类型:

static func deserialize(DataModel)

static public func deserialize(dm: DataModel): Option<T>

功能:将 DataModel 反序列化为 Option<T>。

参数:

返回值:

  • Option<T> - 反序列化后的 Option<T>。

异常:

  • DataModelException - 当 dm 的类型不支持反序列化到 T 类型时,抛出异常。

func serialize()

public func serialize(): DataModel

功能:将 Option<T> 中的 T 序列化为 DataModel

返回值:

extend Rune <: Serializable

extend Rune <: Serializable<Rune>

功能:为 Rune 类型实现 Serializable 接口。

父类型:

static func deserialize(DataModel)

static public func deserialize(dm: DataModel): Rune

功能:将 DataModel 反序列化为 Rune。

参数:

返回值:

  • Rune - 反序列化后的字符。

异常:

func serialize()

public func serialize(): DataModel

功能:将 Rune 序列化为 DataModelString

返回值:

extend String <: Serializable

extend String <: Serializable<String>

功能:为 String 类型实现 Serializable 接口。

父类型:

static func deserialize(DataModel)

static public func deserialize(dm: DataModel): String

功能:将 DataModel 反序列化为 String。

参数:

返回值:

  • String - 反序列化后的 String。

异常:

func serialize()

public func serialize(): DataModel

功能:将 String 序列化为 DataModelString

返回值:

extend UInt16 <: Serializable

extend UInt16 <: Serializable<UInt16>

功能:为 UInt16 类型实现 Serializable 接口。

父类型:

static func deserialize(DataModel)

static public func deserialize(dm: DataModel): UInt16

功能:将 DataModel 反序列化为 UInt16。

参数:

返回值:

  • UInt16 - 反序列化后的 UInt16。

异常:

func serialize()

public func serialize(): DataModel

功能:将 UInt16 序列化为 DataModelInt

返回值:

extend UInt32 <: Serializable

extend UInt32 <: Serializable<UInt32>

功能:为 UInt32 类型实现 Serializable 接口。

父类型:

static func deserialize(DataModel)

static public func deserialize(dm: DataModel): UInt32

功能:将 DataModel 反序列化为 UInt32。

参数:

返回值:

  • UInt32 - 反序列化后的 UInt32。

异常:

func serialize()

public func serialize(): DataModel

功能:将 UInt32 序列化为 DataModelInt

返回值:

extend UInt64 <: Serializable

extend UInt64 <: Serializable<UInt64>

功能:为 UInt64 类型实现 Serializable 接口。

父类型:

static func deserialize(DataModel)

static public func deserialize(dm: DataModel): UInt64

功能:将 DataModel 反序列化为 UInt64。

参数:

返回值:

  • UInt64 - 反序列化后的 UInt64。

异常:

func serialize()

public func serialize(): DataModel

功能:将 UInt64 序列化为 DataModelInt

返回值:

extend UInt8 <: Serializable

extend UInt8 <: Serializable<UInt8>

功能:为 UInt8 类型实现 Serializable 接口。

父类型:

static func deserialize(DataModel)

static public func deserialize(dm: DataModel): UInt8

功能:将 DataModel 反序列化为 UInt8。

参数:

返回值:

  • UInt8 - 反序列化后的 UInt8。

异常:

func serialize()

public func serialize(): DataModel

功能:将 UInt8 序列化为 DataModelInt

返回值:

class DataModel

public abstract class DataModel

功能:此类为中间数据层。

class DataModelBool

public class DataModelBool <: DataModel {
    public init(bv: Bool)
}

功能:此类为 DataModel 的子类,实现对 Bool 类型数据的封装。

父类型:

init(Bool)

public init(bv: Bool)

功能:构造一个具有初始数据的 DataModelBool 实例。

参数:

  • bv: Bool - 传入的 Bool 类型的数据。

func getValue()

public func getValue(): Bool

功能:获取 DataModelBool 中的数据。

返回值:

class DataModelFloat

public class DataModelFloat <: DataModel {
    public init(fv: Float64)
    public init(v: Int64)
}

功能:此类为 DataModel 的子类,实现对 Float64 类型数据的封装。

父类型:

init(Float64)

public init(fv: Float64)

功能:构造一个具有初始数据的 DataModelFloat 实例。

参数:

  • fv: Float64 - 传入的 Float64 类型的数据。

init(Int64)

public init(v: Int64)

功能:构造一个具有初始数据的 DataModelFloat 实例。

参数:

  • v: Int64 - 传入的 Int64 类型的数据。

func getValue()

public func getValue(): Float64

功能:获取 DataModelFloat 中的数据。

返回值:

class DataModelInt

public class DataModelInt <: DataModel {
    public init(iv: Int64)
}

功能:此类为 DataModel 的子类,实现对 Int64 类型数据的封装。

父类型:

init(Int64)

public init(iv: Int64)

功能:构造一个具有初始数据的 DataModelInt 实例。

参数:

  • iv: Int64 - 传入的 Int64 类型的数据。

func getValue()

public func getValue(): Int64

功能:获取 DataModelInt 中的数据。

返回值:

  • Int64 - DataModelInt 中类型为 Int64 的 value 数值。

class DataModelNull

public class DataModelNull <: DataModel

功能:此类为 DataModel 的子类,实现对 Null 类型数据的封装。

父类型:

class DataModelSeq

public class DataModelSeq <: DataModel {
    public init()
    public init(list: ArrayList<DataModel>)
}

功能:此类为 DataModel 的子类,实现对 ArrayList<DataModel> 类型数据的封装。

父类型:

init()

public init()

功能:构造一个参数为空的 DataModelSeq 实例。其中的数据默认为空的 ArrayList<DataModel>。

init(ArrayList<DataModel>)

public init(list: ArrayList<DataModel>)

功能:构造一个具有初始数据的 DataModelSeq 实例。

参数:

func add(DataModel)

public func add(dm: DataModel)

功能:在 DataModelSeq 末尾增加一个 DataModel 数据。

参数:

func getItems()

public func getItems(): ArrayList<DataModel>

功能:获取 DataModelSeq 中的数据。

返回值:

class DataModelString

public class DataModelString <: DataModel {
    public init(sv: String)
}

功能:此类为 DataModel 的子类,实现对 String 类型数据的封装。

父类型:

init(String)

public init(sv: String)

功能:构造一个具有初始数据的 DataModelString

参数:

  • sv: String - 传入的 String 类型。

func getValue()

public func getValue(): String

功能:获取 DataModelString 中的数据。

返回值:

class DataModelStruct

public class DataModelStruct <: DataModel {
    public init()
    public init(list: ArrayList<Field>)
}

功能:此类为 DataModel 的子类,用来实现 class 对象到 DataModel 的转换。

父类型:

init()

public init()

功能:构造一个空参的 DataModelStructfields 默认为空的 ArrayList<Field>。

init(ArrayList<Field>)

public init(list: ArrayList<Field>)

功能:构造一个具有初始数据的 DataModelStruct

参数:

  • list: ArrayList<Field> - 传入的 ArrayList<Field> 类型的数据。

func add(Field)

public func add(fie: Field): DataModelStruct

功能:添加数据 fieDataModelStruct 中。

参数:

返回值:

func get(String)

public func get(key: String): DataModel

功能:获取 key 对应的数据。

参数:

  • key: String - 传入的 String 类型。

返回值:

func getFields()

public func getFields(): ArrayList<Field>

功能:获取 DataModelStruct 的数据集合。

返回值:

  • ArrayList<Field> - 类型为 ArrayList<Field> 的数据集合。

class Field

public class Field {
    public init(name: String, data: DataModel)
}

功能:用于存储 DataModelStruct 的元素。

init(String, DataModel)

public init(name: String, data: DataModel)

功能:Field 的构造函数。

参数:

  • name: String - name 字段值,name 字段为 "" 时行为与为其它字符串时一致。
  • data: DataModel - data 字段值。

func getData()

public func getData(): DataModel

功能:获取 data 字段。

返回值:

func getName()

public func getName(): String

功能:获取 name 字段。

返回值:

  • String - 获取到的 name 字段,类型为 String。

异常类

class DataModelException

public class DataModelException <: Exception {
    public init()
    public init(message: String)
}

功能:DataModel 的异常类。

父类型:

  • Exception

init()

public init()

功能:创建 DataModelException 实例。

init(String)

public init(message: String)

功能:根据异常信息创建 DataModelException 实例。

参数:

  • message: String - 异常信息提示字符串。

class 序列化和反序列化

import stdx.serialization.serialization.*
import std.math.*
import stdx.encoding.json.*

/* 通过实现 Serializable 接口,来实现对自定义类型的序列化和反序列化功能 */
class Abc <: Serializable<Abc> {
    var name: String = "Abcde"
    var age: Int64 = 555
    var loc: Option<Location> = Option<Location>.None

    /* 实现 Serializable 接口的序列化方法 */
    public func serialize(): DataModel {
        return DataModelStruct().add(field<String>("name", name)).add(field<Int64>("age", age)).add(field<Option<Location>>("loc", loc))
    }

    /* 实现反序列化方法 */
    public static func deserialize(dm: DataModel): Abc {
        let dms = match (dm) {
            case data: DataModelStruct => data
            case _ => throw Exception("this data is not DataModelStruct")
        }
        let result = Abc()
        result.name = String.deserialize(dms.get("name"))
        result.age = Int64.deserialize(dms.get("age"))
        result.loc = Option<Location>.deserialize(dms.get("loc"))
        return result
    }
}

class Location <: Serializable<Location> {
    var time: Int64 = 666
    var heheh: Rune = 'T'

    /* 实现 Serializable 接口的序列化方法 */
    public func serialize(): DataModel {
        return DataModelStruct().add(field<Int64>("time", time)).add(field<Rune>("heheh", heheh))
    }

    /* 实现反序列化方法 */
    public static func deserialize(dm: DataModel): Location {
        let dms = match (dm) {
            case data: DataModelStruct => data
            case _ => throw Exception("this data is not DataModelStruct")
        }
        let result = Location()
        result.time = Int64.deserialize(dms.get("time"))
        result.heheh = Rune.deserialize(dms.get("heheh"))
        return result
    }
}

main(): Unit {
    let dd = Abc()
    let aa: JsonValue = dd.serialize().toJson()
    let bb: JsonObject = (aa as JsonObject).getOrThrow()
    let v1 = (bb.get("name").getOrThrow() as JsonString).getOrThrow()
    let v2 = (bb.get("age").getOrThrow() as JsonInt).getOrThrow()
    let v3 = bb.get("loc").getOrThrow()
    println(v1.getValue())
    println(v2.getValue())
    println(v3.toString())
    println("===========")
    let aaa = ##"{"age": 123, "loc": { "heheh": "H", "time": 45 }, "name": "zhangsan"}"##
    let bbb = JsonValue.fromStr(aaa)
    let ccc = (bbb as JsonObject).getOrThrow()
    let v4 = (ccc.get("name").getOrThrow() as JsonString).getOrThrow()
    let v5 = (ccc.get("age").getOrThrow() as JsonInt).getOrThrow()
    let v6 = (ccc.get("loc").getOrThrow() as JsonObject).getOrThrow()
    let v7 = (v6.get("time").getOrThrow() as JsonInt).getOrThrow()
    let v8 = (v6.get("heheh").getOrThrow() as JsonString).getOrThrow()
    println(v4.getValue())
    println(v5.getValue())
    println(v7.getValue())
    println(v8.getValue())
}

运行结果如下:

Abcde
555
null
===========
zhangsan
123
45
H

HashSet 和 HashMap 序列化

import std.collection.*
import stdx.serialization.serialization.*
import stdx.encoding.json.*

main(): Unit {
    let s: HashSet<Values> = HashSet<Values>([Values(3), Values(5), Values(7)])
    let seris: DataModel = s.serialize()
    println(seris.toJson().toJsonString())
    println("===========")
    let m: HashMap<String, Values> = HashMap<String, Values>([("1", Values(3)), ("2", Values(6)), ("3", Values(9))])
    let serim: DataModel = m.serialize()
    print(serim.toJson().toJsonString())
}

class Values <: Hashable & Equatable<Values> & Serializable<Values> {
    var m_data: Int64

    init(m_data: Int64) {
        this.m_data = m_data
    }

    public func hashCode(): Int64 {
        return this.m_data
    }

    public operator func ==(right: Values): Bool {
        let a = (this.m_data == right.m_data)
        if (a) { return true } else { return false }
    }

    public operator func !=(right: Values): Bool {
        let a = (this.m_data != right.m_data)
        if (a) { return true } else { return false }
    }

    /* 实现 Serializable 接口的序列化方法 */
    public func serialize(): DataModel {
        return DataModelStruct().add(field<Int64>("m_data", m_data))
    }

    /* 实现反序列化方法 */
    public static func deserialize(dm: DataModel): Values {
        let dms: DataModelStruct = match (dm) {
            case data: DataModelStruct => data
            case _ => throw Exception("this data is not DataModelStruct")
        }
        let result = Values(0)
        result.m_data = Int64.deserialize(dms.get("m_data"))
        return result
    }
}

运行结果如下:

[
  {
    "m_data": 3
  },
  {
    "m_data": 5
  },
  {
    "m_data": 7
  }
]
===========
{
  "1": {
    "m_data": 3
  },
  "2": {
    "m_data": 6
  },
  "3": {
    "m_data": 9
  }
}

stdx.unittest.data

功能介绍

unittest.data 库用于在编写仓颉项目单元测试代码时提供输入序列化格式的测试数据的能力,当前支持 json/csv/tsv 等格式。

标准测试能力可参考标准库 API 文档。

API 列表

函数

函数名功能
csv<T>(String, Rune, Rune, Rune, Option<Rune>, Option<Array<String>>, Array<UInt64>, Array<UInt64>, Bool)该函数可从 csv 文件中读取类型 T 的数据值,其中 T 必须可被序列化。该函数的返回值是参数化测试的一种参数源。
json<T>(String)该函数可从 JSON 文件中读取类型 T 的数据值,其中 T 必须可被序列化。该函数的返回值是参数化测试的一种参数源。
tsv<T>(String, Rune, Rune, Option<Rune>, Option<Array<String>>, Array<UInt64>, Array<UInt64>, Bool)该函数可从 tsv 文件中读取类型 T 的数据值,其中 T 必须可被序列化。该函数的返回值是参数化测试的一种参数源。

类名功能
CsvStrategyDataStrategy 对 CSV 数据格式的序列化实现。
JsonStrategyDataStrategy 对 JSON 数据格式的序列化实现。
SerializableProvider获取序列化数据 DataProvider 接口的实现。

函数

func csv<T>(String, Rune, Rune, Rune, Option<Rune>, Option<Array<String>>, Array<UInt64>, Array<UInt64>, Bool) where T <: Serializable<T>

public func csv<T>(
 fileName: String,
 delimiter!: Rune = ',',
 quoteChar!: Rune = '"',
 escapeChar!: Rune = '"',
 commentChar!: Option<Rune> = None,
 header!: Option<Array<String>> = None,
 skipRows!: Array<UInt64> = [],
 skipColumns!: Array<UInt64> = [],
 skipEmptyLines!: Bool = false
): CsvStrategy<T> where T <: Serializable<T>

功能:该函数可从 csv 文件中读取类型 T 的数据值,其中 T 必须可被序列化。该函数的返回值是参数化测试的一种参数源。

参数:

  • fileName: String - CSV 格式的文件地址,可为相对地址,不限制后缀名。
  • delimiter!: Rune - 一行中作为元素分隔符的符号。默认值为 , (逗号)。
  • quoteChar!: Rune - 括住元素的符号。默认值为 " (双引号)。
  • escapeChar!: Rune :转义括住元素的符号。默认值为 " (双引号)。
  • commentChar!: Option<Rune> - 注释符号,跳过一行。必须在一行的最左侧。默认值是 None (不存在注释符号)。
  • header!: Option<Array<String>> - 提供一种方式覆盖第一行。
    • 当 header 被指定时,文件的第一行将被作为数据行,指定的 header 将被使用。
    • 当 header 被指定,同时第一行通过指定 skipRows 被跳过时,第一行将被忽略,指定的 header 将被使用。
    • 当 header 未被指定时,即值为 None 时,文件的第一行将被作为表头。此为默认值。
  • skipRows!: Array<UInt64> - 指定需被跳过的数据行号,行号从 0 开始。默认值为空数组 []
  • skipColumns!: Array<UInt64> - 指定需被跳过的数据列号,列号从 0 开始。当有数据列被跳过,并且用户指定了自定义的 header 时,该 header 将按照跳过后的实际数据列对应。默认值为空数据 []
  • skipEmptyLines!: Bool - 指定是否需要跳过空行。默认值为 false

返回值:

  • CsvStrategy<T> 对象,T 可被序列化,数据值从 CSV 文件中读取。

异常:

  • IllegalStateException - 如果 CSV 数据的结构不正确,则抛出该异常。

func json<T>(String) where T <: Serializable<T>

public func json<T>(fileName: String): JsonStrategy<T> where T <: Serializable<T>

功能:该函数可从 JSON 文件中读取类型 T 的数据值,其中 T 必须可被序列化。该函数的返回值是参数化测试的一种参数源。

参数:

  • fileName: String - JSON 格式的文件地址,可为相对地址。

返回值:

  • JsonStrategy<T> - T 可被序列化,数据值从 JSON 文件中读取。

示例:

@Test[user in json("users.json")]
func test_user_age(user: User): Unit {
    @Expect(user.age, 100)
}

json 文件示例:

[
    {
        "age": 100
    },
    {
        "age": 100
    }
]

创建一种被用作测试函数参数的类,该类实现接口 Serializable

import stdx.serialization.serialization.*
import std.convert.*
class User <: Serializable<User> {
    User(let age: Int64) {}

    public func serialize(): DataModel {
        DataModelStruct()
          .add(Field("age", DataModelInt(age)))
    }

    public static func deserialize(dm: DataModel): User {
        if (let Some(dms) <- (dm as DataModelStruct)) {
          if (let Some(age) <- (dms.get("age") as DataModelInt)) {
            return User(age.getValue())
          }
        }

        throw Exception("Can't deserialize user.")
    }
}

任何实现 Serializable 的类型都可以用作参数类型,包括默认值:

@Test[user in json("numbers.json")]
func test(value: Int64)
@Test[user in json("names.json")]
func test(name: String)

func tsv<T>(String, Rune, Rune, Option<Rune>, Option<Array<String>>, Array<UInt64>, Array<UInt64>, Bool) where T <: Serializable<T>

public func tsv<T>(
    fileName: String,
    quoteChar!: Rune = '"',
    escapeChar!: Rune = '"',
    commentChar!: Option<Rune> = None,
    header!: Option<Array<String>> = None,
    skipRows!: Array<UInt64> = [],
    skipColumns!: Array<UInt64> = [],
    skipEmptyLines!: Bool = false
): CsvStrategy<T> where T <: Serializable<T>

功能:该函数可从 tsv 文件中读取类型 T 的数据值,其中 T 必须可被序列化。该函数的返回值是参数化测试的一种参数源。

参数:

  • fileName: String - TSV 格式的文件地址,可为相对地址,不限制后缀名。
  • quoteChar!: Rune - 括住元素的符号。默认值为 " (双引号)。
  • escapeChar!: Rune - 转义括住元素的符号。默认值为 " (双引号)。
  • commentChar!: Option<Rune> - 注释符号,跳过一行。必须在一行的最左侧。默认值是 None (不存在注释符号)。
  • header!: Option<Array<String>> - 提供一种方式覆盖第一行。
    • 当 header 被指定时,文件的第一行将被作为数据行,指定的 header 将被使用。
    • 当 header 被指定,同时第一行通过指定 skipRows 被跳过时,第一行将被忽略,指定的 header 将被使用。
    • 当 header 未被指定时,即值为 None 时,文件的第一行(跳过后的实际数据)将被作为表头。此为默认值。
  • skipRows!: Array<UInt64> - 指定需被跳过的数据行号,行号从 0 开始。默认值为空数组 []
  • skipColumns!: Array<UInt64> - 指定需被跳过的数据列号,列号从 0 开始。当有数据列被跳过,并且用户指定了自定义的 header 时,该 header 将按照跳过后的实际数据列对应。默认值为空数据 []
  • skipEmptyLines!: Bool - 指定是否需要跳过空行。默认值为 false

返回值:

  • CsvStrategy<T> - T 可被序列化,数据值从 TSV 文件中读取。

异常:

  • IllegalStateException - 如果 TSV 数据的结构不正确,则抛出该异常。

示例:

在单元测试中,可以通过传入 csv/tsv 文件地址进行参数化测试。

CSV 文件每一行的数据应当被表示成一个 Serializable<T> 对象,它的成员名是文件每一列头的值,成员值是 DataModelString 类型的对应列号上的值。

举例来说,有一个 testdata.csv 文件,具有如下内容:

username,age
Alex Great,21
Donald Sweet,28

有几种方式可以序列化上述数据:

  1. 将数据表示为 HashMap<String, String> 类型。

    具体示例为:

    import std.collection.HashMap
    import std.unittest.*
    import std.unittest.testmacro.*
    
    @Test[user in csv("testdata.csv")]
    func testUser(user: HashMap<String, String>) {
        @Assert(user["username"] == "Alex Great" || user["username"] == "Donald Sweet")
        @Assert(user["age"] == "21" || user["age"] == "28")
    }
    
  2. 将数据表示为 Serializable<T> 类型数据,其 String 类型的数据可被反序列化为 DataModelStruct 格式对象。

具体示例为:

import serialization.serialization.*
import std.convert.*
import std.unittest.*
import std.unittest.testmacro.*

public class User <: Serializable<User> {
    public User(let name: String, let age: UInt32) {}

    public func serialize(): DataModel {
        let dms = DataModelStruct()
        dms.add(Field("username", DataModelString(name)))
        dms.add(Field("age", DataModelString(age.toString())))
        return dms
    }

    static public func deserialize(dm: DataModel): User {
        var data: DataModelStruct = match (dm) {
            case dms: DataModelStruct => dms
            case _ => throw DataModelException("this data is not DataModelStruct")
        }

        let name = String.deserialize(data.get("username"))
        let age = String.deserialize(data.get("age"))
        return User(name, UInt32.parse(age))
    }
}

@Test[user in csv("testdata.csv")]
func testUser(user: User) {
   @Assert(user.name == "Alex Great" || user.name == "Donald Sweet")
   @Assert(user.age == 21 || user.age == 28)
}

class CsvStrategy

public class CsvStrategy<T> <: DataStrategy<T> where T <: Serializable<T> {}

功能:DataStrategy 对 CSV 数据格式的序列化实现。

父类型:

  • DataStrategy<T>

func provider(Configuration)

public override func provider(configuration: Configuration): SerializableProvider<T>

功能:生成序列化数据迭代器。

参数:

  • configuration: Configuration - 数据配置信息。

返回值:

class JsonStrategy

public class JsonStrategy<T> <: DataStrategy<T> where T <: Serializable<T> {}

功能:DataStrategy 对 JSON 数据格式的序列化实现。

父类型:

  • DataStrategy<T>

func provider(Configuration)

public override func provider(configuration: Configuration): SerializableProvider<T>

功能:生成序列化数据迭代器。

参数:

  • configuration: Configuration - 数据配置信息。

返回值:

  • SerializableProvider<T> - 序列化迭代器对象。

class SerializableProvider

public class SerializableProvider<T> <: DataProvider<T> where T <: Serializable<T> {}

功能:获取序列化数据 DataProvider 接口的实现。

父类型:

  • DataProvider<T>

prop isInfinite

public prop isInfinite: Bool

功能:是否生成无限的数据。

Bool。

func provide()

public override func provide(): Iterable<T> 

功能:获取数据迭代器。

返回值:

  • Iterable<T> - 数据迭代器。