深入理解ngx_http_proxy_connect_module模块(下)

目录

  • 5. 源码分析
    • 5.1 模块的初始化代码
    • 5.2 请求入口点函数分析
      • 5.2.1 ngx_http_proxy_connect_post_read_handler
      • 5.2.2 ngx_http_proxy_connect_handler
    • 5.3 域名解析回调
    • 5.4 向上游服务器发起连接
      • 5.4.1 ngx_http_proxy_connect_process_connect
      • 5.4.2 ngx_http_proxy_connect_write_upstream
    • 5.5 连接建立后向客户端发送CONNECT请求的响应
    • 5.6 数据隧道透传
      • 5.6.1 上下游连接的读写回调函数
      • 5.6.1 ngx_http_proxy_connect_tunnel
    • 5.7 关闭会话
  • 6. 总结

对于模块的配置指令和内置变量的相关信息可以查看上半部分:深入理解ngx_http_proxy_connect_module模块(上)

5. 源码分析

  废话不多说,直接进入源码环节。

5.1 模块的初始化代码

static ngx_http_module_t  ngx_http_proxy_connect_module_ctx = {ngx_http_proxy_connect_add_variables,   /* preconfiguration */ngx_http_proxy_connect_init,            /* postconfiguration */NULL,                                   /* create main configuration */NULL,                                   /* init main configuration */NULL,                                   /* create server configuration */NULL,                                   /* merge server configuration */ngx_http_proxy_connect_create_loc_conf, /* create location configuration */ngx_http_proxy_connect_merge_loc_conf   /* merge location configuration */
};

  本模块设置了preconfiguration回调,用来在nginx框架中添加第4节列出的变量;本模块又设置了postconfiguration回调,用来设置回调钩子函数。ngx_http_proxy_connect_init代码如下:

static ngx_int_t
ngx_http_proxy_connect_init(ngx_conf_t *cf)
{ngx_http_core_main_conf_t  *cmcf;ngx_http_handler_pt        *h;cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);h = ngx_array_push(&cmcf->phases[NGX_HTTP_POST_READ_PHASE].handlers);if (h == NULL) {return NGX_ERROR;}*h = ngx_http_proxy_connect_post_read_handler;return NGX_OK;
}

  ngx_http_proxy_connect_init代码非常简单,就是在NGX_HTTP_POST_READ_PHASE阶段设置一个回调函数ngx_http_proxy_connect_post_read_handler, NGX_HTTP_POST_READ_PHASE阶段是nginx 异步http处理框架收到客户端的http请求包后的第一个处理阶段。

  然后再看一下proxy_connect配置指令的代码,如下:

static char *
ngx_http_proxy_connect(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{ngx_http_core_loc_conf_t            *clcf;ngx_http_proxy_connect_loc_conf_t   *pclcf;clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);clcf->handler = ngx_http_proxy_connect_handler;pclcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_proxy_connect_module);pclcf->accept_connect = 1;return NGX_CONF_OK;
}

   也是非常简单,就是设置一个NGX_HTTP_CONTENT_PHASE阶段的回调函数,以便在这个阶段来接管connect请求的处理逻辑。

5.2 请求入口点函数分析

5.2.1 ngx_http_proxy_connect_post_read_handler

  ngx_http_proxy_connect_post_read_handler函数在NGX_HTTP_POST_READ_PHASE阶段被回调,如果发现当前的是CONNECT请求,则判断是否开启了proxy_connect,如果没有开启,则返回NGX_HTTP_NOT_ALLOWED,反之,则对当前的请求设置一个ngx_http_proxy_connect_ctx_t上下文,源码如下:

static ngx_int_t
ngx_http_proxy_connect_post_read_handler(ngx_http_request_t *r)
{ngx_http_proxy_connect_ctx_t      *ctx;ngx_http_proxy_connect_loc_conf_t *pclcf;if (r->method == NGX_HTTP_CONNECT) {pclcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_connect_module);if (!pclcf->accept_connect) {ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,"proxy_connect: client sent connect method");return NGX_HTTP_NOT_ALLOWED;}/* init ctx */ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_proxy_connect_ctx_t));if (ctx == NULL) {return NGX_ERROR;}ctx->buf.pos = (u_char *) NGX_HTTP_PROXY_CONNECT_ESTABLISTHED;ctx->buf.last = ctx->buf.pos +sizeof(NGX_HTTP_PROXY_CONNECT_ESTABLISTHED) - 1;ctx->buf.memory = 1;ctx->connect_timeout = pclcf->connect_timeout;ctx->send_timeout = pclcf->send_timeout;ctx->data_timeout = pclcf->data_timeout;ngx_http_set_ctx(r, ctx, ngx_http_proxy_connect_module);}/* 返回NGX_DECLINED表示如果本阶段有其他的模块,就继续执行这些模块的回调函数。return NGX_DECLINED;
}

5.2.2 ngx_http_proxy_connect_handler

  nginx在经过以上ngx_http_proxy_connect_post_read_handler处理后,正常情况下都会会进入到NGX_HTTP_CONTENT_PHASE阶段,在这时就会回调ngx_http_proxy_connect_handler进行处理,源码如下:

static ngx_int_t
ngx_http_proxy_connect_handler(ngx_http_request_t *r)
{ngx_url_t                            url;ngx_int_t                            rc;ngx_resolver_ctx_t                  *rctx, temp;ngx_http_core_loc_conf_t            *clcf;ngx_http_proxy_connect_ctx_t        *ctx;ngx_http_proxy_connect_upstream_t   *u;ngx_http_proxy_connect_loc_conf_t   *plcf;plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_connect_module);/* 如果不是CONNECT请求或者配置中没有开启proxy_connect, 则本模块直接放弃处理 */if (r->method != NGX_HTTP_CONNECT || !plcf->accept_connect) {return NGX_DECLINED;}/* 判断客户端请求的端口是否在允许的范围内,如果不在范围内,则本模块直接放弃处理 */rc = ngx_http_proxy_connect_allow_handler(r, plcf);if (rc != NGX_OK) {return rc;}/* 获取在ngx_http_proxy_connect_post_read_handler设置的上下文信息 */ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_connect_module);;if (ngx_http_proxy_connect_upstream_create(r, ctx) != NGX_OK) {return NGX_HTTP_INTERNAL_SERVER_ERROR;}u = ctx->u;u->conf = plcf;ngx_memzero(&url, sizeof(ngx_url_t));/* 如果在配置文件中设置了proxy_connect_address,则根据设置的值作为连接上游服务器的地址 */if (plcf->address) {if (ngx_http_complex_value(r, plcf->address, &url.url) != NGX_OK) {return NGX_HTTP_INTERNAL_SERVER_ERROR;}if (url.url.len == 0 || url.url.data == NULL) {url.url.len = r->connect_host.len;url.url.data = r->connect_host.data;}} else {/* 没有设置proxy_connect_address,则用CONNECT请求头中的url地址中的host部分作为上游服务器的地址 */url.url.len = r->connect_host.len;url.url.data = r->connect_host.data;}/* 设置待连接上游服务器的端口 */url.default_port = r->connect_port_n;url.no_resolve = 1;ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,"proxy_connect: connect handler: parse url: %V" , &url.url);if (ngx_parse_url(r->pool, &url) != NGX_OK) {if (url.err) {ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,"proxy_connect: %s in connect host \"%V\"",url.err, &url.url);return NGX_HTTP_FORBIDDEN;}return NGX_HTTP_INTERNAL_SERVER_ERROR;}/* 将当前请求的read和write的i/o事件处理回调函数进行设置,因为当前暂时还不需要处理读写操作,只是用来进行连接是否中断的检测 */r->read_event_handler = ngx_http_proxy_connect_rd_check_broken_connection;r->write_event_handler = ngx_http_proxy_connect_wr_check_broken_connection;/* NOTE:*   We use only one address in u->resolved,*   and u->resolved.host is "<address:port>" format.*  u->resolved用来存放最终向上游服务器连接的ip+端口的地址。*/u->resolved = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_resolved_t));if (u->resolved == NULL) {return NGX_HTTP_INTERNAL_SERVER_ERROR;}/* rc = NGX_DECLINED */if (url.addrs) {/* 如果url.addrs中已经有目标地址,则用第一个地址来设置u->resolved */ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,"proxy_connect: upstream address given directly");u->resolved->sockaddr = url.addrs[0].sockaddr;u->resolved->socklen = url.addrs[0].socklen;
#if defined(nginx_version) && nginx_version >= 1011007u->resolved->name = url.addrs[0].name;
#endifu->resolved->naddrs = 1;}u->resolved->host = url.host;u->resolved->port = (in_port_t) (url.no_port ? r->connect_port_n : url.port);u->resolved->no_port = url.no_port;if (u->resolved->sockaddr) {/* 目标地址已经设置好了,接下去就不需要进行域名解析直接进行连接了 */rc = ngx_http_proxy_connect_sock_ntop(r, u);if (rc != NGX_OK) {return rc;}/* 当前的ngx_http_request_t的引用计数+1 */r->main->count++;/*  向上游服务器发起TCP连接请求 */ngx_http_proxy_connect_process_connect(r, u);return NGX_DONE;}/* 因为将连接的上游服务器是域名形式提供的,因此需要先通过域名解析后方可以发起连接 */ngx_str_t *host = &url.host;clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);temp.name = *host;/* 设置请求上游服务器的开始时间 */u->start_time = ngx_current_msec;u->state.resolve_time = (ngx_msec_t) -1

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

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

相关文章

欧盟发布关于网络安全、通信网络弹性的综合风险评估报告:具有战略意义的十大网络安全风险场景

在欧盟委员会和欧盟网络安全局 ENISA 的支持下&#xff0c;欧盟成员国近日发布了一份报告&#xff0c;详细介绍了欧洲通信基础设施和网络的网络安全和弹性。 该报告概述了对欧盟具有战略意义的十种风险情景。 1、 擦除器/勒索软件攻击 2、 供应链攻击 3、 攻击托管服务、托…

HarmonyOS—使用数据模型和连接器

Serverless低代码开发平台是一个可视化的平台&#xff0c; 打通了HarmonyOS云侧与端侧能力&#xff0c;能够轻松实现HMS Core、AGC Serverless能力调用。其中&#xff0c;数据模型和连接器是两大主要元素。开发者在使用DevEco Studio的低代码功能进行开发时&#xff0c;可以使用…

Redis有哪些原子命令?

SET key value [NX|XX]&#xff1a;将键key设置为指定的字符串value&#xff0c;如果键不存在&#xff0c;则创建&#xff0c;如果键已经存在&#xff0c;则覆盖原有值。可选参数NX表示仅在键不存在时设置值&#xff0c;XX表示仅在键已存在时设置值。 GETSET key value&#x…

给生成出来的a链接或其他dom节点添加点击事件

onMounted(() > {nextTick(() > {const domNodes document.querySelectorAll(a)console.log(domNodes)domNodes.forEach((item, index) > {item.addEventListener(click, async () > {// 点击文章后进行统计console.log(点击了节点&#xff01;, index)})})}) })q…

npm install的-S和-D的区别

在npm install参数中&#xff0c;-S代表 --save&#xff0c;-D标志--save-dev。 1、-S (--save) 用于将包添加到项目的 dependencies&#xff0c;表示这是在生产环境中运行时所需的依赖。例如&#xff1a;npm install package-name -S&#xff0c;这将把 package-name 添加到 …

express+mysql+vue,从零搭建一个商城管理系统5--用户注册

提示&#xff1a;学习express&#xff0c;搭建管理系统 文章目录 前言一、新建user表二、安装bcryptjs、MD5、body-parser三、修改config/db.js四、新建config/bcrypt.js五、新建models文件夹和models/user.js五、index.js引入使用body-parser六、修改routes/user.js七、启动项…

书生·浦语大模型全链路开源体系介绍

背景介绍 随着人工智能技术的迅猛发展&#xff0c;大模型技术已成为当今人工智能领域的热门话题。2022 年 11 月 30 日&#xff0c;美国 OpenAI 公司发布了 ChatGPT 通用型对话系统 并引发了全球 的极大关注&#xff0c;上线仅 60 天月活用户数便超过 1 亿&#xff0c;成为历史…

淘宝问大家植入广告

随着电子商务的迅猛发展&#xff0c;各大电商平台都在努力提升用户体验&#xff0c;打造更加互动和有趣的购物环境。淘宝作为中国最大的电商平台之一&#xff0c;其“问大家”功能作为社区互动的重要一环&#xff0c;不仅为买家提供了提问和分享经验的平台&#xff0c;也成为卖…

【实践总结】文件上传可能导致的DoS

通过CVE-2023-24998了解上传的可能隐患 Apache Commons FileUpload场景 条件1&#xff1a; &#xff08;影响版本&#xff09; <!-- Apache Commons FileUpload --><dependency><groupId>commons-fileupload</groupId><artifactId>commons-file…

【小沐学QT】QT学习之OpenGL开发笔记

文章目录 1、简介2、Qt QOpenGLWidget gl函数3、Qt QOpenGLWidget qt函数4、Qt QOpenGLWindow5、Qt glut6、Qt glfw结语 1、简介 Qt提供了与OpenGL实现集成的支持&#xff0c;使开发人员有机会在更传统的用户界面的同时显示硬件加速的3D图形。 Qt有两种主要的UI开发方…

【Azure 架构师学习笔记】-Azure Synapse -- Link for SQL 实时数据加载

本文属于【Azure 架构师学习笔记】系列。 本文属于【Azure Synapse】系列。 前言 Azure Synapse Link for SQL 可以提供从SQL Server或者Azure SQL中接近实时的数据加载。通过这个技术&#xff0c;使用SQL Server/Azure SQL中的新数据能够几乎实时地传送到Synapse&#xff08;…

音视频数字化(视频的数字化)

前面我们已经聊了音频的数字化【音视频数字化(音频数字化)】,并且介绍了音乐CD的那些事儿【音视频数字化(音乐CD)】。从原理上讲,视频的数字化与音频大致相仿,只是相对复杂。 目录 1、模拟视频 2、视频采集 2、压缩标准 1、模拟视频 在【音视频数字化(数字与模拟…

前端路由与后端路由的区别

聚沙成塔每天进步一点点 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 欢迎来到前端入门之旅&#xff01;感兴趣的可以订阅本专栏哦&#xff01;这个专栏是为那些对Web开发感兴趣、刚刚踏入前端领域的朋友们量身打造的。无论你是完全的新手还是有一些基础的开发…

react useContext 用法

1 创建createContext import React, { useContext, useEffect, useState } from react const GlobalContext React.createContext() 2 GlobalContext 作为提供者 export default function App(){ const [filmList,setfilmList] useState([]); const [info,setinfo] useS…

SQL注入漏洞解析--less-7

我们先看一下第七关 页面显示use outfile意思是利用文件上传来做 outfile是将检索到的数据&#xff0c;保存到服务器的文件内&#xff1a; 格式&#xff1a;select * into outfile "文件地址" 示例&#xff1a; mysql> select * into outfile f:/mysql/test/one f…

Vue源码系列讲解——实例方法篇【一】(数据相关方法)

目录 0. 前言 1. vm.$watch 1.1 用法回顾 1.2 内部原理 2. vm.$set 2.1 用法回顾 2.2 内部原理 3. vm.$delete 3.1 用法回顾 3.2 内部原理 0. 前言 与数据相关的实例方法有3个&#xff0c;分别是vm.$set、vm.$delete和vm.$watch。它们是在stateMixin函数中挂载到Vue原…

【OnlyOffice】 桌面应用编辑器,版本8.0已发布,PDF表单、RTL支持、Moodle集成、本地界面主题

ONLYOFFICE桌面编辑器v8.0是一款功能强大、易于使用的办公软件&#xff0c;适用于个人用户、企业团队和教育机构&#xff0c;帮助他们高效地处理文档工作并实现协作。无论是在Windows、macOS还是Linux平台上&#xff0c;ONLYOFFICE都能提供无缝的编辑和共享体验。 目录 ONLYOFF…

ESP32语音转文字齐护百度在线语音识别

一、导入(10分钟&#xff09; 学习目的 二、新授(70分钟) 1.预展示结果(5分钟) 2.本节课所用的软硬件(5分钟) 4.图形化块介绍(10分钟) 5.单个模块的简单使用(10分钟) 6.在线语音转换工具逻辑分析(10分钟) 7.在线语音转换工具分步实现(30分钟) 三、巩固练习(5分钟) 四、课堂小结…

腾讯云4核8G的云服务器性能水平?使用场景说明

腾讯云4核8G服务器适合做什么&#xff1f;搭建网站博客、企业官网、小程序、小游戏后端服务器、电商应用、云盘和图床等均可以&#xff0c;腾讯云4核8G服务器可以选择轻量应用服务器4核8G12M或云服务器CVM&#xff0c;轻量服务器和标准型CVM服务器性能是差不多的&#xff0c;轻…

【办公类-21-04】20240227单个word按“段落数”拆分多个Word(三级育婴师操作参考题目 有段落文字和表格 1拆13份)

作品展示 背景需求&#xff1a; 最近学育婴师&#xff0c;老师发了一套doc操作参考 但是老师是一节节授课的&#xff0c;每节都有视频&#xff0c;如果做在一个文档里&#xff0c;会很长很长&#xff0c;容易找不到。所以我需要里面的单独文字的docx。 以前的方法是 1、打开源…