wmproxy

wmproxy已用Rust实现http/https代理, socks5代理, 反向代理, 静态文件服务器,四层TCP/UDP转发,七层负载均衡,内网穿透,后续将实现websocket代理等,会将实现过程分享出来,感兴趣的可以一起造个轮子

项目地址

国内: https://gitee.com/tickbh/wmproxy

github: https://github.com/tickbh/wmproxy

旅程路线

  大家好,我是这趟旅程的导游,可以叫我导游,我为大家来介绍HTTP的组装之旅。

  大家好,我是这趟旅程的乘客,可以叫我小H,出来玩实在太开心了

旅行开端

首先导游带我来了码头,说是我接一位神秘的来客

  我问:“这个神秘的来客有什么来头?”

  导游答:“这个神秘的来客,名字叫socket,这码头能正常的运营有一半的功劳是他的存在,等下他来了我们要赶紧麻溜的接待。”

  只见远处来了一艘轮船正在缓缓的驶来,他看起来好壮观。

  导游这时候急忙的说:“他马上就停靠进来了,这边码头的工人马上就会将他的货卸下了,去晚了就看不到全过程了。”

  我们就立即来到了停靠点,只见有一套完善的流程正在对接着这一切,我想这是这码头能繁荣的原因吧,高效!

  socket说:“这些东西是http大神要的东西,你们把它们按照指定的顺序转交给他,他会安排如何处理的!”

旅行中转

接下来运送集装箱的过程又会碰到什么有趣的事呢?

  我们跟随着运送车队前行,只见http大神安排了查验数据,但奇怪的是他只检查前面的一辆车,后面的就数一数就放行了。

  于是我就好奇的问:“为什么前面一辆车要检查,后面的车就数一数都不用拿出来检查?”

  http大神就笑着说:“我检查前面的车,因为我不知道这些车装了什么东西,第一辆车带有车队的信息,我就通过他来知道这趟车的内容是什么了。下面我跟你说下这辆车带的信息。”

POST /report HTTP/1.1\r\n
Content-Type: application/x-www-form-urlencoded; charset=UTF-8\r\n
Accept: */*\r\n
Accept-Language: zh-CN,zh-Hans;q=0.9\r\n
Accept-Encoding: gzip, deflate, br\r\n
Host: www.wm-proxy.com\r\n
Origin: https://www.wm-proxy.com\r\n
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.1 Safari/605.1.15\r\n
Referer: https://www.wm-proxy.com/\r\n
Content-Length: 218\r\n
Connection: keep-alive\r\n
\r\n

  通过这第一辆车的信息,我就知道了他要找的是叫/report的,他用POST的方法去敲他家的门,他可以接受Accept-Language: zh-CN,zh-Hans;q=0.9这种格式的语言,接受Accept-Encoding: gzip, deflate, br这三种格式的压缩,及后面还带着218的数据,在他访问结束的时候不要立刻关闭Connection: keep-alive他可能还有话没说完,叫我再等等,然后通过\r\n\r\n表示他没有其它信息了。

  我惊叹的答到:“原来这车上隐藏了这么多的信息吖,那接下来他们会遇到什么?”

  http大神说:“我现在知道了他们的全部信息了,我现在会把这些车队组装成Request<RecvStream>的结构体,等下你看到那边的一扇扇门了没有,那个叫中间件。”

  我来到这门前:“这怎么有两个门呢?他们等下走哪个门呢?”

  http大神说:“他们这些门,都是有统一的规格的,他们需要按照我的规格来建这些门,左边是进的process_request,右边是出的process_response,要严格的按照这流程来,要不然会出错哦。下面我给你说下他这个门有哪些注意的”

#[async_trait]
pub trait Middleware: Send + Sync {
async fn process_request(&mut self, request: &mut RecvRequest) -> ProtResult<()>;
async fn process_response(&mut self, request: &mut RecvRequest, response: &mut RecvResponse) -> ProtResult<()>;
}

  他们按照这规格建起各种各样的门,他们可以规定进门后要怎么处理我组装的这个车队RecvRequest,比如要把车队变成红色之类等操作或者记录下有多少个车队经过等,这样我就可以不会显得臃肿,但是我的能力却是大大的提升了起来。

  我表示羡慕到:“原来这种方式强大可以变得这么优雅。那通过这些门后会有什么好玩的?”

旅程终点

过了中间件的门,我们就来到了这旅程的终点。我们来到了一个大广场,广场上有个神奇的装置,看起来像传送门。

  我就很好奇的问:“这传送门看起来的有点高级,这边角好像和刚才那门有点像,难道也是要遵循你的规则?”

  http大神回答:“观察力不错哦,这传送门也是同样的道理哦,因为我也不知道他们要把这个数据拿来干什么,所以我就弄了个传送门,让他们把数据加工好后再给我咯,我的要求就是建传送门必须要按以下格式”

#[async_trait]
pub trait OperateTrait {
async fn operate(&mut self, req: &mut RecvRequest) -> ProtResult<RecvResponse>;
}

  “他们必须返回给我一个RecvResponse或者一个错误,我等下好告诉socket要运送哪些东西回去。你看,从传送门里出来了一个对象Ok(RecvResponse),那我们接下来把这个对象带回去。这对象类似这样子的内容:”

HTTP/1.1 200 OK\r\n
Content-Encoding: deflate\r\n
Date: Wed, 22 Nov 2023 11:30:23 GMT\r\n
Content-Type: application/json;charset=UTF-8\r\n
Content-Length: 31\r\n
Connection: keep-alive\r\n
Access-Control-Allow-Origin: *\r\n
\r\n

旅程返程

得到了正在的返回结果,我们就马不停蹄的往回走了

  我们又回到了中间件的门,但是此时是从另一侧的门回来,上面标注着process_response,我想这应该是处理我们刚刚从传送门回来的对象吧,这也是逻辑严密的结构。

async fn process_response(&mut self, request: &mut RecvRequest, response: &mut RecvResponse) -> ProtResult<()>;

  经过了中间件的门,对象Ok(RecvResponse)被重新粉刷了蓝色,也做了标记,我们就把他带到了socket的面前。

  socket说:“你们回来的真快,这才过去了不到10ms,把我要的东西带过来了吗?”

  http大神说:“都在这了,顺序不要乱了哦,他们可是被暗中标记过了,乱了的话,等下就还原不回来了。”

  于是socket就把这些数据带回去了,看着这船来船往的码头,我就感慨到,原来他们都已经预处理好各种情况的应对了,难怪看起来那么的井井有条。只见HTTP大神给了例子:

use std::{env, error::Error, time::Duration};
use async_trait::async_trait; use tokio::{net::TcpListener};
use webparse::{Response};
use wenmeng::{self, ProtResult, Server, RecvRequest, RecvResponse, OperateTrait, Middleware}; struct Operate;
#[async_trait]
impl OperateTrait for Operate {
async fn operate(&mut self, req: &mut RecvRequest) -> ProtResult<RecvResponse> {
tokio::time::sleep(Duration::new(1, 1)).await;
let response = Response::builder()
.version(req.version().clone())
.body("Hello World\r\n".to_string())?;
Ok(response.into_type())
}
} struct HelloMiddleware;
#[async_trait]
impl Middleware for HelloMiddleware {
async fn process_request(&mut self, request: &mut RecvRequest) -> ProtResult<()> {
println!("hello request {}", request.url());
Ok(())
} async fn process_response(&mut self, _request: &mut RecvRequest, response: &mut RecvResponse) -> ProtResult<()> {
println!("hello response {}", response.status());
Ok(())
}
} #[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
env_logger::init();
let addr = env::args()
.nth(1)
.unwrap_or_else(|| "0.0.0.0:8080".to_string());
let server = TcpListener::bind(&addr).await?;
println!("Listening on: {}", addr);
loop {
let (stream, addr) = server.accept().await?;
tokio::spawn(async move {
let mut server = Server::new(stream, Some(addr));
server.middle(HelloMiddleware);
let operate = Operate;
let e = server.incoming(operate).await;
println!("close server ==== addr = {:?} e = {:?}", addr, e);
});
}
}

小结

在http的处理过程中,还有其它的好玩的东西,需要注意的东西,这次我们介绍了中间件及回调处理的小小见闻。以下是一个小demo

点击 [关注][在看][点赞] 是对作者最大的支持

30. 干货系列从零用Rust编写正反向代理,HTTP的组装之旅(中间件)的更多相关文章

  1. Spring Boot干货系列:(七)默认日志框架配置

    Spring Boot干货系列:(七)默认日志框架配置 原创 2017-04-05 嘟嘟MD 嘟爷java超神学堂 前言 今天来介绍下Spring Boot如何配置日志logback,我刚学习的时候, ...

  2. (转)Spring Boot干货系列:(七)默认日志logback配置解析

    转:http://tengj.top/2017/04/05/springboot7/ 前言 今天来介绍下Spring Boot如何配置日志logback,我刚学习的时候,是带着下面几个问题来查资料的, ...

  3. (转)Spring Boot干货系列:(四)开发Web应用之Thymeleaf篇

    转:http://tengj.top/2017/03/13/springboot4/ 前言 Web开发是我们平时开发中至关重要的,这里就来介绍一下Spring Boot对Web开发的支持. 正文 Sp ...

  4. 【转】Spring Boot干货系列:(一)优雅的入门篇

    转自Spring Boot干货系列:(一)优雅的入门篇 前言 Spring一直是很火的一个开源框架,在过去的一段时间里,Spring Boot在社区中热度一直很高,所以决定花时间来了解和学习,为自己做 ...

  5. 【转】Spring Boot干货系列:常用属性汇总

    转自Spring Boot干货系列:常用属性汇总 附录A.常用应用程序属性 摘自:http://docs.spring.io/spring-boot/docs/current/reference/ht ...

  6. Spring Boot干货系列:(八)数据存储篇-SQL关系型数据库之JdbcTemplate的使用

    Spring Boot干货系列:(八)数据存储篇-SQL关系型数据库之JdbcTemplate的使用 原创 2017-04-13 嘟嘟MD 嘟爷java超神学堂 前言 前面几章介绍了一些基础,但都是静 ...

  7. Spring Boot干货系列:(五)开发Web应用JSP篇

    Spring Boot干货系列:(五)开发Web应用JSP篇 原创 2017-04-05 嘟嘟MD 嘟爷java超神学堂 前言 上一篇介绍了Spring Boot中使用Thymeleaf模板引擎,今天 ...

  8. Spring Boot干货系列:(四)Thymeleaf篇

    Spring Boot干货系列:(四)Thymeleaf篇 原创 2017-04-05 嘟嘟MD 嘟爷java超神学堂 前言 Web开发是我们平时开发中至关重要的,这里就来介绍一下Spring Boo ...

  9. Spring Boot干货系列:(一)优雅的入门篇

    Spring Boot干货系列:(一)优雅的入门篇 2017-02-26 嘟嘟MD 嘟爷java超神学堂   前言 Spring一直是很火的一个开源框架,在过去的一段时间里,Spring Boot在社 ...

  10. Spring Boot干货系列:(十二)Spring Boot使用单元测试(转)

    前言这次来介绍下Spring Boot中对单元测试的整合使用,本篇会通过以下4点来介绍,基本满足日常需求 Service层单元测试 Controller层单元测试 新断言assertThat使用 单元 ...

随机推荐

  1. JavaWeb和MVC三层架构

    JavaWeb 概述 网站发布和部署一定要依托技术语言吗: 不一定,一个网站可以直接发布和部署,因为因为浏览器能够识别网页只需要两样东西,网络和静态页面,还有一个装在他们的容器,比如 nginx. 静 ...

  2. C#.NET 国密SM2 加密解密 与JAVA互通 ver:20230805

    C#.NET 国密SM2 加密解密 与JAVA互通 ver:20230805 .NET 环境:.NET6 控制台程序(.net core). JAVA 环境:JAVA8,带maven 的JAVA控制台 ...

  3. C#/.NET/.NET Core优秀项目和框架每周精选(坑已挖,欢迎大家踊跃提交PR或者Issues中留言)

    前言 注意:排名不分先后,都是十分优秀的开源项目和框架,每周定期更新分享(欢迎关注公众号:追逐时光者,第一时间获取每周精选分享资讯). 每周精选优秀的C#/.NET/.NET Core项目和框架,帮助 ...

  4. [loki]轻量级日志聚合系统loki快速入门

    前言 简述:loki是由grafana开源的日志聚合系统,相较于ELK.EFK更轻量. loki特性: 不对日志进行全文索引.通过存储压缩非结构化日志和仅索引元数据,Loki 操作起来会更简单,更省成 ...

  5. Nginx 文件名逻辑漏洞(CVE-2013-4547)(Vulhub)

    Nginx 文件名逻辑漏洞(CVE-2013-4547)(Vulhub) 漏洞简介 在Nginx 0.8.41 ~ 1.4.3 / 1.5.0 ~ 1.5.7版本中存在错误解析用户请求的url信息,从 ...

  6. 【全新重构发布】iNeuOS工业互联网操作系统 V5 版本

    iNeuOS工业互联网操作系统历经迭代27个版本,老版本截止更新V4.1版本:历时一年多时间,现在正式发布全新V5版本,V5版本与V4.1老版本不完全兼容. 发布V5版本后,iNeuOS工业互联网操作 ...

  7. 【路由器】小米 WR30U 解锁并刷机

    本文主要记录个人对小米 WR30U 路由器的解锁和刷机过程,整体步骤与 一般安装流程 类似,但是由于 WR30U 的解锁 ssh 和刷机的过程中有一些细节需要注意,因此记录一下 解锁 ssh 环境准备 ...

  8. Linux 内核设备驱动程序的IO寄存器访问 (下)

    Linux 内核设备驱动程序通过 devm_regmap_init_mmio() 等函数获得 struct regmap 结构对象,该对象包含可用于访问设备寄存器的全部信息,包括定义访问操作如何执行的 ...

  9. 4.go语言复合类型简述

    目录 1. 本章前瞻 2.来自leetcode的例题 描述 分析 题解 3. 复合类型新版本的变化 3.1 string和[]byte的高效转化 3.2 内置函数clear 4. 复合类型概述 4.1 ...

  10. Ubuntu SVN服务端安装方法

    Ubuntu SVN服务端安装方法:https://blog.csdn.net/sm_wang/article/details/78656120https://www.cnblogs.com/myme ...