前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >golang源码分析之:go-mitmproxy

golang源码分析之:go-mitmproxy

作者头像
golangLeetcode
发布于 2024-07-06 00:21:32
发布于 2024-07-06 00:21:32
41100
代码可运行
举报
运行总次数:0
代码可运行

日常开发中,我们除了使用charles、finder抓包外,也可以使用mitmproxy抓包,并且它还提供二次开发能力。在学习mitmproxy之前,我们先学习下他的go版本的精简实现github.com/lqqyt2423/go-mitmproxy/cmd/go-mitmproxy

目前只支持http代理和https代理,不支持websocket和透明代理,这是比mitmproxy弱的地方,它提供了11个hook点,我们可以根据需求,通过addon的方式来定义和添加自己的hook点实现自定义抓包,它的11个hook点定义如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
type Addon interface {
  // 一个客户端已经连接到了mitmproxy。请注意,一个连接可能对应多个HTTP请求。
  ClientConnected(*ClientConn)

  // 一个客户端连接已关闭(由我们或客户端关闭)。
  ClientDisconnected(*ClientConn)

  // mitmproxy 已连接到服务器。
  ServerConnected(*ConnContext)

  // 服务器连接已关闭(由我们或服务器关闭)。
  ServerDisconnected(*ConnContext)

  // 与服务器的TLS握手已成功完成。
  TlsEstablishedServer(*ConnContext)

  // HTTP请求头已成功读取。此时,请求体为空。
  Requestheaders(*Flow)

  // 完整的HTTP请求已被读取。
  Request(*Flow)

  // HTTP响应头已成功读取。此时,响应体为空。
  Responseheaders(*Flow)

  // 完整的HTTP响应已被读取。
  Response(*Flow)

  // 流式请求体修改器
  StreamRequestModifier(*Flow, io.Reader) io.Reader

  // 流式响应体修改器
  StreamResponseModifier(*Flow, io.Reader) io.Reader
}

下面我们开始分析下它的源码,入口函数位于cmd/go-mitmproxy/main.go,里面定义了Config结构体,每一个field代表了一个抓包工具的可选项:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
type Config struct {
version bool // show go-mitmproxy version


Addr         string   // proxy listen addr
WebAddr      string   // web interface listen addr
SslInsecure  bool     // not verify upstream server SSL/TLS certificates.
IgnoreHosts  []string // a list of ignore hosts
AllowHosts   []string // a list of allow hosts
CertPath     string   // path of generate cert files
Debug        int      // debug mode: 1 - print debug log, 2 - show debug from
Dump         string   // dump filename
DumpLevel    int      // dump level: 0 - header, 1 - header + body
Upstream     string   // upstream proxy
UpstreamCert bool     // Connect to upstream server to look up certificate details. Default: True
MapRemote    string   // map remote config filename
MapLocal     string   // map local config filename


filename string // read config from the filename
}

它的main函数里核心包括了下面四步:

1,初始化proxy

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
p, err := proxy.NewProxy(opts)

代理结构体的定义位于proxy/proxy.go

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
type Proxy struct {
Opts    *Options
Version string
Addons  []Addon


entry           *entry
attacker        *attacker
shouldIntercept func(req *http.Request) bool              // req is received by proxy.server
upstreamProxy   func(req *http.Request) (*url.URL, error) // req is received by proxy.server, not client request
}

初始化proxy的时候,会设置对应的entry和attacker

2,设置本地和远程拦截策略,也就是根据规则匹配对应的host,并做出是否代理的决策

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
p.SetShouldInterceptRule(func(req *http.Request) bool {
return !helper.MatchHost(req.Host, config.IgnoreHosts)
})
p.SetShouldInterceptRule(func(req *http.Request) bool {
return helper.MatchHost(req.Host, config.AllowHosts)
})

在proxy上绑定这个拦截规则

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func (proxy *Proxy) SetShouldInterceptRule(rule func(req *http.Request) bool) {
proxy.shouldIntercept = rule
}

mapremote和maplocal的具体实现如下:

addon/mapremote.go

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
if err := helper.NewStructFromFile(filename, &mapRemote); err != nil {
if err := mapRemote.validate(); err != nil {
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
type MapRemote struct {
proxy.BaseAddon
Items  []*mapRemoteItem
Enable bool
}

addon/maplocal.go

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
if err := helper.NewStructFromFile(filename, &mapLocal); err != nil {
if err := mapLocal.validate(); err != nil {
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
type MapLocal struct {
proxy.BaseAddon
Items  []*mapLocalItem
Enable bool
}

3,添加hook点,也就是addon

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
p.AddAddon(proxy.NewUpstreamCertAddon(false))
p.AddAddon(&proxy.LogAddon{})
p.AddAddon(web.NewWebAddon(config.WebAddr))
mapRemote, err := addon.NewMapRemoteFromFile(config.MapRemote)
p.AddAddon(mapRemote)
mapLocal, err := addon.NewMapLocalFromFile(config.MapLocal)
p.AddAddon(mapLocal)
dumper := addon.NewDumperWithFilename(config.Dump, config.DumpLevel)
p.AddAddon(dumper)

添加hook点就是把拦截点append到数组里就行了

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func (proxy *Proxy) AddAddon(addon Addon) {

proxy.Addons = append(proxy.Addons, addon)

}

proxy/addon.go中对hook点进行了约定,也就是说用户可以在这11个hook点上随意定义hook插件

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
type Addon interface {
// A client has connected to mitmproxy. Note that a connection can correspond to multiple HTTP requests.
ClientConnected(*ClientConn)


// A client connection has been closed (either by us or the client).
ClientDisconnected(*ClientConn)


// Mitmproxy has connected to a server.
ServerConnected(*ConnContext)


// A server connection has been closed (either by us or the server).
ServerDisconnected(*ConnContext)


// The TLS handshake with the server has been completed successfully.
TlsEstablishedServer(*ConnContext)


// HTTP request headers were successfully read. At this point, the body is empty.
Requestheaders(*Flow)


// The full HTTP request has been read.
Request(*Flow)


// HTTP response headers were successfully read. At this point, the body is empty.
Responseheaders(*Flow)


// The full HTTP response has been read.
Response(*Flow)


// Stream request body modifier
StreamRequestModifier(*Flow, io.Reader) io.Reader


// Stream response body modifier
StreamResponseModifier(*Flow, io.Reader) io.Reader


// onAccessProxyServer
AccessProxyServer(req *http.Request, res http.ResponseWriter)
}

同时也定义了一个基础插件和两个最常用的插件实现

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
type BaseAddon struct{}
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
type LogAddon struct {
BaseAddon
}
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
type UpstreamCertAddon struct {
BaseAddon
UpstreamCert bool // Connect to upstream server to look up certificate details.
}
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func NewUpstreamCertAddon(upstreamCert bool) *UpstreamCertAddon {
return &UpstreamCertAddon{UpstreamCert: upstreamCert}
}

一些其他的addon定义如下:

web/web.go里定义了webAddOn

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
type WebAddon struct {
proxy.BaseAddon


server   *http.Server
upgrader *websocket.Upgrader


conns   []*concurrentConn
connsMu sync.RWMutex


flowMessageState map[*proxy.Flow]messageType
flowMu           sync.Mutex
}

实现了一个简单的httpserver,通过websocket将抓包结果发送到web前端,我们可以通过网页查看抓包结果

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
web := &WebAddon{
flowMessageState: make(map[*proxy.Flow]messageType),
}
web.upgrader = &websocket.Upgrader{
serverMux := new(http.ServeMux)
serverMux.HandleFunc("/echo", web.echo)


fsys, err := fs.Sub(assets, "client/build")
serverMux.Handle("/", http.FileServer(http.FS(fsys)))


web.server = &http.Server{Addr: addr, Handler: serverMux}
web.conns = make([]*concurrentConn, 0)
err := web.server.ListenAndServe()

addon/dumper.go 定义了Dumper将抓包结果保存到文件里

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
out, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
return NewDumper(out, level)
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
type Dumper struct {
proxy.BaseAddon
out   io.Writer
level int // 0: header 1: header + body
}

4,启动代理

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
log.Fatal(p.Start())

启动proxy的时候分别会启动两个协程,一个是entry,一个是attacker

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func (proxy *Proxy) Start() error {
  go func() {
  if err := proxy.attacker.start(); err != nil {
  return proxy.entry.start()

4.1首先看下entry协程

它的定义位于 proxy/entry.go,它代表了代理server,本质上就是一个http/https服务器

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
type entry struct {
proxy  *Proxy
server *http.Server
}
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func newEntry(proxy *Proxy) *entry {
e := &entry{proxy: proxy}
e.server = &http.Server{
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func (e *entry) start() error {
ln, err := net.Listen("tcp", addr)
pln := &wrapListener{
Listener: ln,
proxy:    e.proxy,
}
return e.server.Serve(pln)

重点看下ServeHTTP函数,每当有拦截到来的时候先处理hook,然后初始化attacker的连接,并调用对应的attack方法

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func (e *entry) ServeHTTP(res http.ResponseWriter, req *http.Request) {
if req.Method == "CONNECT" {
e.handleConnect(res, req)
// trigger addon event Responseheaders
for _, addon := range e.proxy.Addons {
addon.Responseheaders(f)
}
for _, addon := range proxy.Addons {
addon.AccessProxyServer(req, res)
}
proxy.attacker.initHttpDialFn(req)
proxy.attacker.attack(res, req)

处理连接的时候,会进行请求的拷贝,也就是entry收到的请求到accacker的请求,以及attacker响应到entry的响应

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func (e *entry) handleConnect(res http.ResponseWriter, req *http.Request) {
e.directTransfer(res, req, f)
e.httpsDialFirstAttack(res, req, f)
e.httpsDialLazyAttack(res, req, f)

具体拷贝方法定义位于

proxy/helper.go

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func transfer(log *log.Entry, server, client io.ReadWriteCloser) {
go func() {
_, err := io.Copy(server, client)
go func() {
_, err := io.Copy(client, server)

拷贝完请求之后就需要向真是上游发起请求

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func (e *entry) httpsDialLazyAttack(res http.ResponseWriter, req *http.Request, f *Flow) {
  cconn, err := e.establishConnection(res, f)
  peek, err := cconn.(*wrapClientConn).Peek(3)
  conn, err := proxy.attacker.httpsDial(req.Context(), req)
  transfer(log, conn, cconn)
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func (e *entry) httpsDialFirstAttack(res http.ResponseWriter, req *http.Request, f *Flow) {
conn, err := proxy.attacker.httpsDial(req.Context(), req)
cconn, err := e.establishConnection(res, f)
peek, err := cconn.(*wrapClientConn).Peek(3)
if !helper.IsTls(peek) {
// todo: http, ws
transfer(log, conn, cconn)
// is tls
f.ConnContext.ClientConn.Tls = true
proxy.attacker.httpsTlsDial(req.Context(), cconn, conn)

每一次代理请求被定义为一个flow,其代码实现位于:proxy/flow.go

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func newFlow() *Flow {
return &Flow{Id:   uuid.NewV4(),
done: make(chan struct{}),}
}

4.2 接下来看下attacker的协程

其代码位于proxy/attacker.go ,创建attacker的时候需要创建一个ca也就是一个自签名的证书,方便被代理的服务使用(代理https时候)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
ca, err := newCa(proxy.Opts)
a := &attacker{
proxy: proxy,
ca:    ca,
client: &http.Client{
Transport: &http.Transport
a.server = &http.Server{
Handler: a,
ConnContext:
a.h2Server = &http2.Server{
MaxConcurrentStreams: 100, // todo: wait for remote server setting
NewWriteScheduler:    func() http2.WriteScheduler { return http2.NewPriorityWriteScheduler(nil) },
}
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func newCa(opts *Options) (cert.CA, error) {
newCaFunc := opts.NewCaFunc
if newCaFunc != nil {
return newCaFunc()
}
return cert.NewSelfSignCA(opts.CaRootPath)
}

在它的start方法里启动了代理服务

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func (a *attacker) start() error {
return a.server.Serve(a.listener)
}

代理连接是在初始化函数里定义的

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func (a *attacker) initHttpDialFn(req *http.Request) {
connCtx.dialFn = func(ctx context.Context) error {
addr := helper.CanonicalAddr(req.URL)
c, err := a.proxy.getUpstreamConn(ctx, req)
if err := a.serverTlsHandshake(ctx, connCtx); err != nil {
serverConn := newServerConn()
serverConn.Conn = cw
serverConn.Address = addr
serverConn.client = &http.Client{
Transport: &http.Transport{
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
return cw, nil
},

attack方法是代理逻辑的核心

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func (a *attacker) attack(res http.ResponseWriter, req *http.Request) {
reply := func(response *Response, body io.Reader) {
res.Header().Add(key, v)
_, err := io.Copy(res, body)
_, err := io.Copy(res, response.BodyReader)
_, err := res.Write(response.Body)
proxyReq, err := http.NewRequestWithContext(proxyReqCtx, f.Request.Method, f.Request.URL.String(), reqBody)

proxyReq.Header.Add(key, v)
proxyRes, err = a.client.Do(proxyReq)
if err := f.ConnContext.dialFn(req.Context()); err != nil {
proxyRes, err = f.ConnContext.ServerConn.client.Do(proxyReq)
reply(f.Response, resBody)

对于https代理,需要发起tls连接

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func (a *attacker) httpsTlsDial(ctx context.Context, cconn net.Conn, conn net.Conn) {
clientTlsConn := tls.Server(cconn, &tls.Config{
SessionTicketsDisabled: true, // 设置此值为 true ,确保每次都会调用下面的 GetConfigForClient 方法
GetConfigForClient: func(chi *tls.ClientHelloInfo) (*tls.Config, error) {
c, err := a.ca.GetCert(chi.ServerName)
go func() {
if err := clientTlsConn.HandshakeContext(ctx); err != nil {
if err := a.serverTlsHandshake(ctx, connCtx); err != nil {
// will go to attacker.ServeHTTP
a.serveConn(clientTlsConn, connCtx)
func newCa(opts *Options) (cert.CA, error) {
newCaFunc := opts.NewCaFunc
if newCaFunc != nil {
return newCaFunc()
}
return cert.NewSelfSignCA(opts.CaRootPath)
}
// send clientHello to server, server handshake
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func (a *attacker) serverTlsHandshake(ctx context.Context, connCtx *ConnContext) error {
serverTlsConfig := &tls.Config{
serverTlsConn := tls.Client(serverConn.Conn, serverTlsConfig)
if err := serverTlsConn.HandshakeContext(ctx); err != nil {
serverTlsState := serverTlsConn.ConnectionState()
serverConn.tlsState = &serverTlsState
serverConn.client = &http.Client{
Transport: &http.Transport{

自认证证书逻辑位于cert/self_sign_ca.go,创建证书的逻辑如下

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
storePath, err := getStorePath(path)
ca := &SelfSignCA{
StorePath: storePath,
cache:     lru.New(100),
group:     new(singleflight.Group),
}
if err := ca.load(); err != nil {
key, err := x509.ParsePKCS8PrivateKey(keyDERBlock.Bytes)
x509Cert, err := x509.ParseCertificate(certDERBlock.Bytes)
if err := ca.create(); err != nil {

证书的名字

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func (ca *SelfSignCA) caFile() string {
return filepath.Join(ca.StorePath, "mitmproxy-ca.pem")
}
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func (ca *SelfSignCA) create() error {
key, cert, err := createCert()
key, err := rsa.GenerateKey(rand.Reader, 2048)
template := &x509.Certificate{
certBytes, err := x509.CreateCertificate
cert, err := x509.ParseCertificate
return ca.saveCert()
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-06-30,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 golang算法架构leetcode技术php 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
golang 源码阅读之会议系统ion part II
golang 源码阅读之会议系统ion part I介绍了ion的系统架构和islb的代码,本篇将继续介绍ion的其他几个核心模块:
golangLeetcode
2022/08/03
3851
K8s源码分析(20)-client go组件之request和result
上一篇文章里,我们主要介绍了 kubernetes 世界中 client go 这个基础组件,它的主要职责是负责与 API server 进行通讯交互。其中负责资源调度的 kube-scheduler 组件,负责资源管理的 controller manager 组件,以及负责 pod 生命周期的 kublet 组件,负责网络管理的 kube-proxy 组件都会依赖于这个组件。而该组件在通讯的时候又依赖于 request 对象,并且得到相应的 result 对象,在本篇文章里我们主要来介绍 request 和 result 对象。
TA码字
2022/10/30
3060
K8s源码分析(20)-client go组件之request和result
python mitmproxy 文档
1、顾名思义,mitmproxy 就是用于 MITM 的 proxy,MITM 即[中间人攻击],用于中间人攻击的代理首先会向正常的代理一样转发请求,保障服务端与客户端的通信,其次,会适时的查、记录其截获的数据,或篡改数据,引发服务端或客户端特定的行为。 2、不同于 fiddler 或 wireshark 等抓包工具,mitmproxy 不仅可以截获请求帮助开发者查看、分析,更可以通过自定义脚本进行二次开发。举例来说,利用 fiddler 可以过滤出浏览器对某个特定 url 的请求,并查看、分析其数据,但实现不了高度定制化的需求,类似于:“截获对浏览器对该 url 的请求,将返回内容置空,并将真实的返回内容存到某个数据库,出现异常时发出邮件通知”。而对于 mitmproxy,这样的需求可以通过载入自定义 python 脚本轻松实现。 3、但 mitmproxy 并不会真的对无辜的人发起中间人攻击,由于 mitmproxy 工作在 HTTP 层,而当前 HTTPS 的普及让客户端拥有了检测并规避中间人攻击的能力,所以要让 mitmproxy 能够正常工作,必须要让客户端(APP 或浏览器)主动信任 mitmproxy 的 SSL 证书,或忽略证书异常,这也就意味着 APP 或浏览器是属于开发者本人的——显而易见,这不是在做黑产,而是在做开发或测试。 4、那这样的工具有什么实际意义呢?据我所知目前比较广泛的应用是做仿真爬虫,即利用手机模拟器、无头浏览器来爬取 APP 或网站的数据,mitmproxy 作为代理可以拦截、存储爬虫获取到的数据,或修改数据调整爬虫的行为。 事实上,以上说的仅是 mitmproxy 以正向代理模式工作的情况,通过调整配置,mitmproxy 还可以作为透明代理、反向代理、上游代理、SOCKS 代理等,但这些工作模式针对 mitmproxy 来说似乎不大常用,故本文仅讨论正向代理模式。 5、python脚本不要小于3.6 6、安装完后,mitmdump 是命令行工具,mitmweb是一个web界面。
用户5760343
2022/05/14
1.2K0
python mitmproxy 文档
golang源码分析:分布式链路追踪
在上一节搭完分布式追踪的采集展示链路后,这一节开始分析分析分布式链路追踪的核心源码。我们知道分布式追踪的原理是通过traceId串联调用链路上的所有服务和日志,每个服务都有一个自己的spanId,每一次rpc调用都需要生成一个子spanId,通过父子spanID的对应关系,构建一个有向无环图实现分布式追踪的。因此在业务代码的接入过程中需要实现如下功能,父子span关系的构建,父子span关系的传递(包括context内部传递和rpc服务之间的传递有可能跨协议比如http和grpc协议之间传递),rpc日志的采样,上报等等。每一个厂商都有自己的实现,opentrace定义了统一的标准接口,我们按照标准实现即可。在业务代码中实现包括四步:
golangLeetcode
2022/12/17
8340
golang源码分析:分布式链路追踪
kratos源码分析系列(6)
直接获取当前节点:selector/node/direct/direct.go
golangLeetcode
2023/09/06
5840
kratos源码分析系列(6)
golang源码分析:httptest
httptest是golang官方源码自带的测试包,它可以非常方便获取http请求结构体,http返回值结构体,以及在本地启动一个loopback的server,方便我们做单测。对于go的web应用程序中往往需要与其他系统进行交互, 比如通过http访问其他系统, 此时就需要一种方法用于打桩来模拟Web服务端和客户端,httptest包即Go语言针对Web应用提供的解决方案。
golangLeetcode
2023/09/06
3430
golang源码分析:httptest
python mitmproxy事件流程
class Events: # HTTP lifecycle def http_connect(self, flow: mitmproxy.http.HTTPFlow): """ An HTTP CONNECT request was received. Setting a non 2xx response on the flow will return the response to the client abort the connection. CONNECT requests and r
用户5760343
2022/05/13
5960
golang 源码分析(17):cobra docker
然后创建DockerCli对象,DockerCli对象在cli/cli.go里声明。
golangLeetcode
2022/08/02
5370
go进阶-GO创建web服务+websocket详解
go提供了一系列用于创建web服务器的标准,而非常简单。只需要调用net/http包中的ListenAndServe函数并传入网络地址和负责处理的处理器就ok了。net/http库实现了整套的http服务中的客户端、服务端接口,可以基于此轻松的发起HTTP请求或者对外提供HTTP服务。
黄规速
2024/05/24
2.5K0
go进阶-GO创建web服务+websocket详解
Golang(十二)TLS 相关知识(三)理解并模拟简单代理
0. 前言 前面的介绍我们理解了数字签名等知识,同时学习了 OpenSSL 生成私钥和证书并验证 之前提过我们基于 BitTorrent 协议开发了一个 docker 镜像分发加速插件 中间涉及到了配置 docker 的代理 下面我们简单介绍下 Golang 的 http.transport 配置了网络代理后的网络行为并编写一个简单的代理转发,加深理解代理转发行为 1. http.Transport 配置代理 http 代理配置代码如下: func TLSTransport(caFile string)
西凉风雷
2022/11/23
6930
Golang(十二)TLS 相关知识(三)理解并模拟简单代理
Golang源码深入-Go1.15.6发起http请求流程-2
上一篇文章我们讲到go client的大概实现的大概思路,整理了相关client.go的核心源码,详情请翻阅:Golang源码深入-Go1.15.6发起http请求流程-1。笔者这一篇分享一下transport.go相关核心的代码,整理相关核心的技术点,希望读者多交流学习。
公众号-利志分享
2022/04/25
7440
Golang源码深入-Go1.15.6发起http请求流程-2
golang源码分析:爬虫colly(part II)
这里紧接着golang源码分析:爬虫colly(part I)继续讲解,我们看下colly最核心的文件colly.go
golangLeetcode
2022/08/02
2830
Golang测试技术
本篇文章内容来源于Golang核心开发组成员Andrew Gerrand在Google I/O 2014的一次主题分享“Testing Techniques”,即介绍使用Golang开发 时会使用到的测试技术(主要针对单元测试),包括基本技术、高级技术(并发测试、mock/fake、竞争条件测试、并发测试、内/外部测 试、vet工具等)等,感觉总结的很全面,这里整理记录下来,希望能给大家带来帮助。原Slide访问需要自己搭梯子。另外这里也要吐槽一 下:Golang官方站的slide都是以一种特有的golan
李海彬
2018/03/27
9190
golang源码分析:将域名解析代理到自定义域名服务器
开发过程中,好多域名是内网域名,直接改/etc/host是一个选择,但是如果不及时改回去,在切换环境的时候会给我们排查问题带来很大干扰,如果能够实现一个代理,在运行的时候走指定代理服务器,代理服务器内部将域名解析发送到自定义的域名服务器上,如果自定义域名服务器解析不了,再走默认的域名服务器,是不是很爽?
golangLeetcode
2022/12/17
1.5K0
golang 源码分析:mc,minio-go
对象存储服务(Object Storage Service,OSS)是一种海量、安全、低成本、高可靠的云存储服务,适合存放任意类型的文件。容量和处理能力弹性扩展,多种存储类型供选择,全面优化存储成本。Minio 除了直接作为对象存储使用,还可以作为云上对象存储服务的网关层,无缝对接到 Amazon S3、MicroSoft Azure。 在学习minio的源码之前,先阅读下minio的客户端mc和golang sdk minio-go
golangLeetcode
2022/08/03
1.5K0
golang的http与twirp源码分析
在ListenAndServe方法中,使用Handler构建一个Server对象,最终调用其Server方法
歪歪梯
2020/06/19
6950
详解golang net之transport
关于golang http transport的讲解,网上有很多文章进行了解读,但都比较粗,很多代码实现并没有讲清楚。故给出更加详细的实现说明。整体看下来细节实现层面还是比较难懂的。
charlieroro
2020/03/24
4.5K0
docker源码分析-Client创建与命令执行
一直在研究docker,最近被人问到docker到底是怎么工作的却不是太清楚,在网上偶然看到一本讲docker源码的电子书,花了整晚看了下,终于对docker的实现细节比较清楚了。但这本电子书讲的是1.2版本时的docker源码,跟最新的1.12版本相比差别还是挺大的,在这本书里讲到的源码与最新源码已经对应不上了。因此我计划写一份针对1.12版本的docker源码分析。 docker的总体架构 这部分基本没有太大的变化,我觉得可以直接参照1.2版本的总体架构,就不重复分析了。见这里。 Client创建与命令
jeremyxu
2018/05/10
1.3K0
package http
要管理代理、TLS配置、keep-alive、压缩和其他设置,创建一个Transport:
李海彬
2018/07/26
4K0
package http
面试官:net/http库知道吗?能说说优缺点吗?
哈喽,大家后,我是asong;这几天看了一下Go语言标准库net/http的源码,所以就来分享一下我的学习心得;为什么会突然想看http标准库呢?因为在面试的时候面试官问我你知道Go语言的net/http库吗?他有什么有缺点吗?因为我没有看过这部分源码,所以一首凉凉送给我;
Golang梦工厂
2022/12/08
8540
面试官:net/http库知道吗?能说说优缺点吗?
相关推荐
golang 源码阅读之会议系统ion part II
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档