go语言解析HTTP包生成代码发送HTTP数据包

Posted 念秋

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了go语言解析HTTP包生成代码发送HTTP数据包相关的知识,希望对你有一定的参考价值。

输入是从fiddler捕获的HTTP数据包

GET https://bbs.kanxue.com/ HTTP/1.1
Host: bbs.kanxue.com
Connection: keep-alive
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Sec-Fetch-Site: none
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
sec-ch-ua: "Not.A/Brand";v="8", "Chromium";v="114", "Google Chrome";v="114"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9

运行程序以后,粘贴上面的内容,然后回车即可。

需要注意的是,有的请求没有body部分,所以需要多一个回车。

package main

import (
	"bufio"
	"bytes"
	"fmt"
	"log"
	"net/url"
	"os"
	"strings"
	"text/template"
)

type Request struct 
	Method string
	URL    string
	//Headers []struct 
	//	Key   string
	//	Value string
	//
	Headers map[string]string
	Body    string
	Proxy   string


func main() 
	reader := bufio.NewReader(os.Stdin)

	// 读取并解析起始行
	startLine, _ := reader.ReadString(\'\\n\')
	method, reqURL, _ := parseStartLine(startLine)

	// 读取并解析Header部分
	headers := make(map[string]string)
	for 
		line, _ := reader.ReadString(\'\\n\')
		if line == "\\r\\n" 
			break
		
		key, value := parseHeader(line)
		headers[key] = value
	
	delete(headers, "Content-Length")

	// 读取Body部分
	body, _ := reader.ReadString(\'\\n\')
	//fmt.Println("Body: ", body)

	// 输出解析结果
	//fmt.Println("RequestMethod: ", method)
	//fmt.Println("RequestURL: ", reqURL)
	//fmt.Println("Headers: ", headers)
	//fmt.Println("Body: ", body)

	data := &Request
		Method:  method,
		URL:     reqURL,
		Headers: headers,
		Body:    body,
		Proxy:   "http://127.0.0.1:7788",
	
	generate(data)


func replace(input, from, to string) string 
	return strings.Replace(input, from, to, -1)


func generate(data *Request) 
	// 从内存中获取数据,构造结构体

	funcMap := template.FuncMap"replace": replace
	// 定义模板
	t := template.Must(template.New("codeTemplate").Funcs(funcMap).Parse(`
package main

import (
        "bytes"
        "fmt"
        "io/ioutil"
        "net/http"
        "net/url"
)

func main() 
        // 请求方法
        method := ".Method"
        urls := ".URL"
        
        // 请求头
        headers := map[string]string
                range $key, $value :=.Headers"$key": "replace $value "\\"" "\\\\\\""",
                end
        
        
        // 请求 body
        body := ` + "`.Body`" + `
        
        // 设置代理
        proxyStr := ".Proxy"
        proxyURL, err := url.Parse(proxyStr)
        if err != nil 
                fmt.Println("Error parsing proxy URL:", err)
                return
        
        
        // 创建 HTTP 客户端
        client := &http.ClientTransport: &http.TransportProxy: http.ProxyURL(proxyURL)

        // 创建 HTTP 请求
        req, err := http.NewRequest(method, urls, bytes.NewBuffer([]byte(body)))
        if err != nil 
                fmt.Println("Error creating HTTP request:", err)
                return
        

        // 添加 HTTP 请求头
        for key, value := range headers 
                req.Header.Set(key, value)
        

        // 发送 HTTP 请求
        resp, err := client.Do(req)
        if err != nil 
                fmt.Println("Error sending HTTP request:", err)
                return
        
        defer resp.Body.Close()

        // 读取 HTTP 响应体
        respBody, err := ioutil.ReadAll(resp.Body)
        if err != nil 
                fmt.Println("Error reading HTTP response body:", err)
                return
        

        // 输出 HTTP 响应体
        fmt.Println(string(respBody))

`))

	// 渲染模板
	var buf bytes.Buffer
	if err := t.Execute(&buf, data); err != nil 
		log.Fatalf("Failed to render template: %v", err)
	

	// 将 Go 语言代码写入文件
	file, err := os.Create("http_request.go")
	if err != nil 
		log.Fatalf("Failed to create file: %v", err)
	
	defer file.Close()
	if _, err := file.Write(buf.Bytes()); err != nil 
		log.Fatalf("Failed to write file: %v", err)
	
	fmt.Println("Go 语言程序生成成功,请通过 go run 命令运行 http_request.go 程序。")


// 解析HTTP请求起始行
func parseStartLine(startLine string) (string, string, error) 
	// 移除行尾的回车换行符
	startLine = strings.TrimSpace(startLine)

	parts := strings.Split(startLine, " ")
	if len(parts) != 3 
		return "", "", fmt.Errorf("Invalid Start Line: %s", startLine)
	

	reqURL, err := url.Parse(parts[1])
	if err != nil 
		return "", "", err
	

	return parts[0], reqURL.String(), nil


// 解析HTTP请求Header部分
func parseHeader(line string) (string, string) 
	parts := strings.SplitN(line, ":", 2)
	if len(parts) != 2 
		return "", ""
	

	key := strings.TrimSpace(parts[0])
	value := strings.TrimSpace(parts[1])

	return key, value


以上是关于go语言解析HTTP包生成代码发送HTTP数据包的主要内容,如果未能解决你的问题,请参考以下文章

go语言标准库之http/template

Go http包执行流程

从HTTP协议到GO语言的net/http包,到搭建一个简单的WEB

Go语言http包简易入门

Go Http包解析:为什么需要response.Body.Close()

pcap抓包分析包问题