圈圈套圈圈(3)

如何监听普通请求.
测试引用:
http://www.cnblogs.com/ference/p/4014210.html

2017/09/30 15:03:51 request url: <http://localhost:10011/login>
2017/09/30 15:03:51 request url path: </login>
2017/09/30 15:03:51 request for <localhost:10011> from <127.0.0.1:47038>
2017/09/30 15:03:51 request body is <username=cartman&password=poder>
2017/09/30 15:03:51 
2017/09/30 15:03:51 response: localhost:10011 -> text/plain
2017/09/30 15:03:51 response status -> 200 OK
2017/09/30 15:03:51 response status code -> 200
2017/09/30 15:03:51 response body -> logon
2017/09/30 15:03:51 response content-length -> 5
2017/09/30 15:03:51 

对Resquest操作

    proxy.OnRequest().DoFunc(func(req *http.Request, ctx *goproxy.ProxyCtx) (*http.Request, *http.Response) {
        log.Printf("request url: <%v>", req.URL)
        log.Printf("request url path: <%v>", req.URL.Path)
        log.Printf("request for <%v> from <%v>", req.URL.Host, req.RemoteAddr)

        // Attempt 1: // It will drain the Body. Fails.
        // bytes, _ := io.ioutil.ReadAll(req.Body)

        // Attempt 2: // Fails. GetBody is nil
        // body, _ := req.GetBody()         // call to nil func
        // bytes, _ := ioutil.ReadAll(body) // instead of req.Body

        // Attempt 3:
        if req.Body != nil {
            body, _ := ioutil.ReadAll(req.Body)
            req.Body = &FakeReadCloser{bytes.NewReader(body)}
            //log.Printf("request body is <%v>", string(body))
        }
        log.Println()

        return req, nil
    })

从req中取出body. 不过这个对象读完了之后需要还原. 所以用了一个Faker类. (主要实现ReadCloser)

type ReadCloser struct {
    Reader
    Closer
}

实现很简单:


type FakeReadCloser struct {
    io.Reader
}

func (FakeReadCloser) Close() error {
    return nil
}

使用的时候再套上一个bytes.Reader.(至于FakeReadCloser是否是指针, 都可以. 暂不纠结)

对Response操作
proxy.OnResponse().DoFunc(func(resp *http.Response, ctx *goproxy.ProxyCtx) *http.Response {
        if ctx != nil && ctx.Req != nil && resp != nil && resp.Header != nil {
            log.Println("response:", ctx.Req.Host, "->", resp.Header.Get("Content-Type"))
        }
        if resp.Body != nil {
            body, _ := ioutil.ReadAll(resp.Body)
            log.Println("response status ->", resp.Status)          //string
            log.Println("response status code ->", resp.StatusCode) // int
            //log.Println("response body ->", string(body))
            log.Println("response content-length ->", resp.ContentLength)
            resp.Body = &FakeReadCloser{bytes.NewReader(body)}

            log.Println()
        }

        return resp
    })

不需要其他設置. 即可完成監聽.


測試用js

'use strict';

const http = require('http');
const querystring = require('querystring');

const ProxyHost = "localhost";
const ProxyPort = 8080;

const TargetHost = "localhost";
const TargetPort = 10011;

//~ por ejemplo:
//~    name=eric&passwd=secret

function getResDo(cb) {
    return (res) => {
        res.setEncoding('utf8');
        let rs = '';
        res.on('data', (chunk) => {
            rs += `${chunk}`;
        });
        res.on('end', () => {
            //console.log("response is %s", resJson);
            //console.log(res.headers);
            //console.log("====");
            //console.log(res.headers.cookie);// undefined
            //console.log(res.headers['set-cookie']); // an array
            //console.log("Is an array: %s", Array.isArray(res.headers['set-cookie']));
            cb(res, rs);
        });
    };
}

function parseCookies(res) {
    let list = {};
    let ra = res.headers['set-cookie'];
    //~ not every response get a `set-cookie`
    if (ra) {
        ra.forEach((rc) => {
            rc && rc.split(';').forEach((cookie) => {
                let parts = cookie.split('=');
                list[parts.shift().trim()] = parts.join('=');
            });
        });
    }
    return list;
}

function packCookie(opts) {
    let ar = [];
    for (let k in opts) {
        ar.push(`${k}=${opts[k]}`);
    }
    return ar.join("; ");
}

function makeLoginOptions(dataToPost) {
    return {
        hostname: ProxyHost,
        port: ProxyPort,
        path: `http://${TargetHost}:${TargetPort}/login`,
        method: 'POST',
        headers: {
            'Content-Type': 'application/x-www-form-urlencoded',
            'Content-Length': dataToPost.length,
        }
    };
}

function doLogin() {
    return new Promise((resolve, reject) => {
        let postdata = querystring.stringify({
            username: 'cartman',
            password: 'poder'
        });
        let req = http.request(makeLoginOptions(postdata), getResDo((res, rs) => {
            resolve({
                cookie:parseCookies(res),
                response:rs
            });
        }));
        req.end(postdata);
    });
}

doLogin().then((rs) => {
    let cookie = rs.cookie;
    let response = rs.response;
    console.log("before moving to next:\n%s", JSON.stringify(cookie, null, 4));
    console.log("response: %s", response);
});

在這種簡單模式下163和csdn都可以代.
git也能穿.(之前git不能穿的原因是OnResponse中訪問resp的異常)
So far.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值