go - 在 Go 中解析来自文本文件的 HTTP 请求和响应

标签 go

给定以下文件,其中包含 HTTP 请求和 HTTP 响应的 HTTP 管道流。

我如何将这个文件解析到我的变量中?

type Connection struct{
   Request *http.Request
   Response *http.Response
}
stream := make([]Connection, 0)

原始文件:

GET /ubuntu/dists/trusty/InRelease HTTP/1.1
Host: archive.ubuntu.com
Cache-Control: max-age=0
Accept: text/*
User-Agent: Debian APT-HTTP/1.3 (1.0.1ubuntu2)

HTTP/1.1 404 Not Found
Date: Thu, 26 Nov 2015 18:26:36 GMT
Server: Apache/2.2.22 (Ubuntu)
Vary: Accept-Encoding
Content-Length: 311
Content-Type: text/html; charset=iso-8859-1

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>404 Not Found</title>
</head><body>
<h1>Not Found</h1>
<p>The requested URL /ubuntu/dists/trusty/InRelease was not found on this server.</p>
<hr>
<address>Apache/2.2.22 (Ubuntu) Server at archive.ubuntu.com Port 80</address>
</body></html>
GET /ubuntu/dists/trusty-updates/InRelease HTTP/1.1
Host: archive.ubuntu.com
Cache-Control: max-age=0
Accept: text/*
User-Agent: Debian APT-HTTP/1.3 (1.0.1ubuntu2)

HTTP/1.1 200 OK
Date: Thu, 26 Nov 2015 18:26:37 GMT
Server: Apache/2.2.22 (Ubuntu)
Last-Modified: Thu, 26 Nov 2015 18:03:00 GMT
ETag: "fbb7-5257562a5fd00"
Accept-Ranges: bytes
Content-Length: 64439
Cache-Control: max-age=382, proxy-revalidate
Expires: Thu, 26 Nov 2015 18:33:00 GMT

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512

Origin: Ubuntu
Label: Ubuntu
Suite: trusty-updates
Version: 14.04
Codename: trusty
[... truncated by author]

我知道有 http.ReadRequest .回应呢?感谢任何想法/反馈/想法。

最佳答案

其实很简单:

package main

import (
    "bufio"
    "bytes"
    "fmt"
    "io"
    "io/ioutil"
    "log"
    "net/http"
    "net/http/httputil"
    "os"
)

type Connection struct {
    Request  *http.Request
    Response *http.Response
}

func ReadHTTPFromFile(r io.Reader) ([]Connection, error) {
    buf := bufio.NewReader(r)
    stream := make([]Connection, 0)

    for {
        req, err := http.ReadRequest(buf)
        if err == io.EOF {
            break
        }
        if err != nil {
            return stream, err
        }

        resp, err := http.ReadResponse(buf, req)
        if err != nil {
            return stream, err
        }

        //save response body
        b := new(bytes.Buffer)
        io.Copy(b, resp.Body)
        resp.Body.Close()
        resp.Body = ioutil.NopCloser(b)

        stream = append(stream, Connection{Request: req, Response: resp})
    }
    return stream, nil

}
func main() {
    f, err := os.Open("/tmp/test.http")
    if err != nil {
        log.Fatal(err)
    }
    defer f.Close()
    stream, err := ReadHTTPFromFile(f)
    if err != nil {
        log.Fatalln(err)
    }
    for _, c := range stream {
        b, err := httputil.DumpRequest(c.Request, true)
        if err != nil {
            log.Fatal(err)
        }
        fmt.Println(string(b))
        b, err = httputil.DumpResponse(c.Response, true)
        if err != nil {
            log.Fatal(err)
        }
        fmt.Println(string(b))
    }
}

一些注意事项:

  • http.ReadRequesthttp.ReadResponse
  • http.ReadRequesthttp.ReadResponse 可以在同一个 bufio.Reader 上反复调用,直到 EOF 它将“正常工作”
    • “正常工作”取决于 Content-Length header 的存在和正确,因此读取正文会将 Reader 置于下一个请求/响应的开头
    • Read the code准确了解什么有效,什么无效
  • resp.Body 必须根据文档关闭,所以我们必须将它复制到另一个缓冲区以保留它
  • 使用您的示例数据(修改 Content-Length 以匹配您的截断),此代码将输出与给定相同的请求和响应
  • httputil.DumpRequesthttputil.DumpResponse 不一定会以与输入文件相同的顺序转储 HTTP header ,因此不要期望 差异 完美

关于go - 在 Go 中解析来自文本文件的 HTTP 请求和响应,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33963467/

相关文章:

types - 在 Go 中,如何为具有字符串基类型的类型创建 "constructor"?

go - 在Go中跨字节编码20位数字

go - 用miniredis模拟redis服务器失败

json - 将字节数组设置为 json.RawMessage

Git repo inside git repo, 由 go get 创建 - convert to submodule

dictionary - 将 map 用于其具有用户定义类型的设置属性

http - 不在 net/http golang 中处理 GET

go - 无法 `syscall.Kill()` 一个守护进程

go - 如何在结构中使用带有私有(private)变量的go-amino库

optimization - 优化Go文件读取程序