Ubuntu 下 nginx-1.24.0 源码分析 - ngx_sprintf_str 函数

ngx_sprintf_str 函数

ngx_sprintf_str 声明在 ngx_string.c 的开头

static u_char *ngx_sprintf_str(u_char *buf, u_char *last, u_char *src,size_t len, ngx_uint_t hexadecimal);

ngx_sprintf_str 实现在ngx_string.c中

static u_char *
ngx_sprintf_str(u_char *buf, u_char *last, u_char *src, size_t len,ngx_uint_t hexadecimal)
{static u_char   hex[] = "0123456789abcdef";static u_char   HEX[] = "0123456789ABCDEF";if (hexadecimal == 0) {if (len == (size_t) -1) {while (*src && buf < last) {*buf++ = *src++;}} else {len = ngx_min((size_t) (last - buf), len);buf = ngx_cpymem(buf, src, len);}} else if (hexadecimal == 1) {if (len == (size_t) -1) {while (*src && buf < last - 1) {*buf++ = hex[*src >> 4];*buf++ = hex[*src++ & 0xf];}} else {while (len-- && buf < last - 1) {*buf++ = hex[*src >> 4];*buf++ = hex[*src++ & 0xf];}}} else { /* hexadecimal == 2 */if (len == (size_t) -1) {while (*src && buf < last - 1) {*buf++ = HEX[*src >> 4];*buf++ = HEX[*src++ & 0xf];}} else {while (len-- && buf < last - 1) {*buf++ = HEX[*src >> 4];*buf++ = HEX[*src++ & 0xf];}}}return buf;
}

ngx_sprintf_str函数,它负责将数据按不同格式写入缓冲区

u_char *buf:目标缓冲区的起始位置,用来写入结果。

u_char *last:缓冲区的末尾指针(指向最后一个有效位置的下一个位置),防止越界。

u_char *src:源数据(比如要处理的字符串或二进制数据)。

size_t len:要处理的源数据长度。如果传(size_t)-1(即-1的无符号形态)(未指定长度),表示src是字符串,直到遇到\0结束。

ngx_uint_t hexadecimal:控制输出格式:0是普通字符串,1是小写十六进制,2是大写十六进制。

返回值指向最后一个有效位置的下一个位置,也是下一个可写入位置,方便用于进行链式操作


static u_char   hex[] = "0123456789abcdef";
static u_char   HEX[] = "0123456789ABCDEF";

这两个数组是十六进制转换的核心工具

就像密码本一样,把4位二进制数(0-15)翻译成对应的字符

hex[] 是小写字母版(a-f)

HEX[] 是大写字母版(A-F)

假设我们要转换字节0xAE(二进制10101110):

// 拆分高4位和低4位

高4位 = 0xA(1010) → hex[0xA] → 'a'

低4位 = 0xE(1110) → hex[0xE] → 'e'

// 组合成"ae"


    if (hexadecimal == 0) {if (len == (size_t) -1) {while (*src && buf < last) {*buf++ = *src++;}} else {len = ngx_min((size_t) (last - buf), len);buf = ngx_cpymem(buf, src, len);}

当hexadecimal为0时,处理的是非十六进制情况,直接复制原始字节

2种情况:

if (len == (size_t) -1)

表示未指定长度

while (*src && buf < last)

未指定长度的情况下循环的两个终止条件:

1:*src 遇到 \0 (字符串结束标志)

2: buf 触达缓冲区末尾 last,防止溢出

*buf++ = *src++
逐字节复制字符,同时移动目标指针 buf 和源指针 src,继续进行下一个字符的处理

else 就是指定了长度的情况

len = ngx_min((size_t)(last - buf), len)

计算安全的复制长度,取「剩余缓冲区空间」和「用户指定长度」的较小值,防止溢出

ngx_min 的定义在 ngx_core.h:

#define ngx_min(val1, val2)  ((val1 > val2) ? (val2) : (val1))

buf = ngx_cpymem(buf, src, len)

内存复制函数(类似 memcpy),但返回值是目标地址末尾位置,直接更新 buf(指向最后一个有效位置的下一个位置


    } else if (hexadecimal == 1) {if (len == (size_t) -1) {while (*src && buf < last - 1) {*buf++ = hex[*src >> 4];*buf++ = hex[*src++ & 0xf];}} else {while (len-- && buf < last - 1) {*buf++ = hex[*src >> 4];*buf++ = hex[*src++ & 0xf];}}

else if (hexadecimal == 1)

进入小写十六进制模式,将每个字节拆解为两个十六进制字符(如 0xAB → 'a''b'

if (len == (size_t)-1)

表示未指定长度的情况下

while (*src && buf < last - 1)

终止条件 1:*src 遇到 \0

终止条件 2:缓冲区至少保留 2 字节空间

*buf++ = hex[*src >> 4]

取字节高 4 位(如 0xA0 → 0xA),查表 hex 得到字符('a'),存入buf 指向的位置,buf 加 1,指向下一个可写入位置

*buf++ = hex[*src++ & 0xf]
取低 4 位(如 0xA5 → 0x5),查表得到字符('5'),存入buf 指向的位置,buf 加 1,指向下一个可写入位置,同时移动 src 指针,指向下一个要处理的字符

else 

指定长度的情况下

while (len-- && buf < last - 1)
通过 len-- 控制循环次数,确保不超出指定长度

buf < last - 1 缓冲区至少保留 2 字节空间

之后操作同上


    } else { /* hexadecimal == 2 */if (len == (size_t) -1) {while (*src && buf < last - 1) {*buf++ = HEX[*src >> 4];*buf++ = HEX[*src++ & 0xf];}} else {while (len-- && buf < last - 1) {*buf++ = HEX[*src >> 4];*buf++ = HEX[*src++ & 0xf];}}}

处理 hexadecimal == 2 的情况,也就是将字节转成 大写十六进制字符串

逻辑同上

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/12869.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

spring基础总结

先修知识&#xff1a;依赖注入&#xff0c;反转控制&#xff0c;生命周期 IDEA快捷键 Ctrl Altm:提取方法&#xff0c;设置trycatch 通用快捷键&#xff1a; Ctrl F&#xff1a;在当前文件中查找文本。Ctrl R&#xff1a;在当前文件中替换文本。Ctrl Z&#xff1a;撤销…

MyBatis XML文件配置

目录 一、 配置连接字符串和MyBatis 二、书写持久层代码 2.1 添加Mapper接口 2.2 添加UserlnfoXMLMapper.xml 三、增删改查 3.1 、增&#xff08;Insert&#xff09; 3.2、删&#xff08;Delete) 3.3、改 (Update) 3.4、查 (Select) MyBatisXML的方式需要以下两步&am…

QT:对象树

1.概念 Qt 中的对象树是一种以树形结构组织 Qt 对象的方式。当创建一个QObject&#xff08;Qt 中大多数类的基类&#xff09;或其派生类的对象时&#xff0c;可以为其指定一个父对象&#xff08;parent&#xff09;。这个对象就会被添加到其父对象的子对象列表中&#xff0c;形…

设备通过国标GB28181接入EasyCVR,显示在线但视频无法播放的原因排查

安防监控EasyCVR平台支持多种视频源接入&#xff0c;包括但不限于IP摄像头、NVR、编码器、流媒体服务器等。平台采用高效的视频流接入技术&#xff0c;支持大规模视频流的并发接入&#xff0c;确保视频流的稳定性和流畅性。 有用户反馈&#xff0c;项目现场使用国标GB28181接入…

本地安装部署deepseek

在截图下载工具(地址不方便粘贴过不审核)复制安装程序链接下载模型管理工具ollama&#xff0c;下一步下一步&#xff0c;有需要也可以下载linux版的 githup&#xff1a;https://github.com/ollama/ollama/releases/tag/v0.5.7 安装程序&#xff1a;https://github.com/ollama…

熟练掌握Http协议

目录 基本概念请求数据Get请求方式和Post请求方式 响应数据响应状态码 基本概念 Http协议全称超文本传输协议(HyperText Transfer Protocol)&#xff0c;是网络通信中应用层的协议&#xff0c;规定了浏览器和web服务器数据传输的格式和规则 Http应用层协议具有以下特点&#…

在Mapbox GL JS中“line-pattern”的使用详解

在Mapbox GL JS中&#xff0c;line-pattern 是一种用于在地图上绘制带有图案的线条的样式属性。通过 line-pattern&#xff0c;你可以使用自定义的图像作为线条的图案&#xff0c;而不是使用纯色或渐变。 1. 基本概念 line-pattern: 该属性允许你指定一个图像作为线条的图案。…

QT:信号和槽

目录 1.概念 2.信号和槽的使用 2.1代码的方式使用 2.1.1.使用connect关联 2.2图形化界面的方式使用 2.2.1使用流程 2.2.2使用名字关联槽函数 3.自定义信号和槽函数 3.1自定义槽函数 3.2自定义信号 4.总结 1.概念 信号和槽是QT特有的一种机制&#xff0c;信号和槽都是…

【数据分析】豆瓣电影Top250的数据分析与Web网页可视化(numpy+pandas+matplotlib+flask)

豆瓣电影Top250的数据分析与Web网页可视化(numpy+pandas+matplotlib+flask) 豆瓣电影Top250官网:https://movie.douban.com/top250写在前面 实验目的:实现豆瓣电影Top250详情的数据分析与Web网页可视化。电脑系统:Windows使用软件:PyCharm、NavicatPython版本:Python 3.…

simpleQtLogger日志库的使用

simpleQtLogger日志库的使用 simpleQtLogger日志库的使用1. 使用2. 修改点控制台中文乱码修复qt6没有setCodec()修复void*强转数值修复打印日志级别修改 simpleQtLogger日志库的使用 B站上看到一个简单的qt日志库&#xff0c;这里记录一下它的使用。 但是我并不知道源码是谁写…

Linux中安装rabbitMQ

使用docker安装 Linux中还没有安装docker的可以看我之前的视频&#xff0c;先把docker安装了。 Docker的安装_docker version 25.0.1-CSDN博客 检查是否有docker docker -v 上传mq的tar包 我们把mq的tar包上传到我们的Linux服务器中&#xff0c;随后加载成docker的镜像。 加载…

PostgreSQL技术内幕24:定时任务调度插件pg_cron

文章目录 0.简介1.基础知识2.pg_cron安装使用方式2.1 安装pg_cron2.2 使用方式 3.实现原理3.1 启动过程3.2 任务添加和管理3.3 调度过程3.4 执行原理 0.简介 pg_cron是PostgreSQL中的一个简单的基于cron的任务调度插件&#xff0c;本文将从其基础知识&#xff08;Linux中Cron的…

【回溯+剪枝】找出所有子集的异或总和再求和 全排列Ⅱ

文章目录 1863. 找出所有子集的异或总和再求和解题思路&#xff1a;子集问题解法&#xff08;回溯 剪枝&#xff09;47. 全排列 II解题思路&#xff1a;排序 回溯 剪枝 1863. 找出所有子集的异或总和再求和 1863. 找出所有子集的异或总和再求和 一个数组的 异或总和 定义为…

每日一题洛谷P5721 【深基4.例6】数字直角三角形c++

#include<iostream> using namespace std; int main() {int n;cin >> n;int t 1;for (int i 0; i < n; i) {for (int j 0; j < n - i; j) {printf("%02d",t);t;}cout << endl;}return 0; }

Hackmyvm Blackhat

简介 难度&#xff1a;简单 靶机地址&#xff1a;https://hackmyvm.eu/machines/machine.php?vmBlackhat 参考wp&#xff1a;https://emvee-nl.github.io/posts/HackMyVM-Writeup-Blackhat/#privilege-escalation 环境 kali&#xff1a;192.168.194.9 靶机&#xff1a;192.…

【含文档+PPT+源码】基于Python爬虫二手房价格预测与可视化系统的设计与实现

项目介绍 本课程演示的是一款基于Python爬虫二手房价格预测与可视化系统&#xff0c;主要针对计算机相关专业的正在做毕设的学生与需要项目实战练习的 Java 学习者。 包含&#xff1a;项目源码、项目文档、数据库脚本、软件工具等所有资料 带你从零开始部署运行本套系统 该项…

《redis哨兵机制》

【redis哨兵机制导读】上一节介绍了redis主从同步的机制&#xff0c;但大家有没有想过一种场景&#xff0c;比如&#xff1a;主库突然挂了&#xff0c;那么按照读写分离的设计思想&#xff0c;此时redis集群只有从库才能提供读服务&#xff0c;那么写服务该如何提供&#xff0c…

用python实现进度条

前言 在Python中&#xff0c;可以使用多种方式实现进度条。以下是几种常见的进度条格式的实现方法&#xff1a; 1. 使用 tqdm 库 tqdm 是一个非常流行的库&#xff0c;可以轻松地在循环中显示进度条。 from tqdm import tqdm import time# 示例&#xff1a;简单的进度条 fo…

Mysql:数据库

Mysql 一、数据库概念&#xff1f;二、MySQL架构三、SQL语句分类四、数据库操作4.1 数据库创建4.2 数据库字符集和校验规则4.3 数据库修改4.4 数据库删除4.4 数据库备份和恢复其他 五、表操作5.1 创建表5.2 修改表5.3 删除表 六、表的增删改查6.1 Create(创建):数据新增1&#…

2024年12月 Scratch 图形化(二级)真题解析 中国电子学会全国青少年软件编程等级考试

202412 Scratch 图形化&#xff08;二级&#xff09;真题解析 中国电子学会全国青少年软件编程等级考试 一、单选题(共25题&#xff0c;共50分) 第 1 题 小猫初始位置和方向如下图所示&#xff0c;下面哪个选项能让小猫吃到老鼠&#xff1f;&#xff08; &#xff09; A. B. …