使 go http 客户端与非标准的 http 服务器一起工作
making go http client work with non-standard http servers
Shoutcast 服务器基本上使用 http,但有一个重要区别:它们使用 ICY 200 OK
而不是 HTTP/1.1 200 OK
来响应 GET
请求。
Go 不会有任何障碍,正确地失败并显示错误 malformed HTTP version "ICY"
。
但是我想让事情正常进行,并且想知道最好的方法是什么。到目前为止我的想法:
- 使用自定义 http.Transport.Proxy 将
ICY
更改为 HTTP/1.1
in-flight
- 做同样事情的进程外代理
- 重载
http.ParseHTTPVersion
(但golang没有函数重载)
- 复制整个http包,只是为了修改
ParseHTTPVersion
数字 1. 似乎最吸引人,但我不知道如何尊重 http "scope" 并实际修改给定 http 版本上的所有响应。这是http.Transport.Proxy
可以处理的事情吗?
任何人都可以给我任何指示吗?
我通过创建一个 returns 包装连接的自定义 Dial 函数来实现此功能。我的包装程序拦截了连接上的第一次读取,并将 ICY 替换为 HTTP/1.1。不是超级健壮,但证明了这个概念:
package main
import (
"fmt"
"net"
"net/http"
)
type IcyConnWrapper struct {
net.Conn
haveReadAny bool
}
func (i *IcyConnWrapper) Read(b []byte) (int, error) {
if i.haveReadAny {
return i.Conn.Read(b)
}
i.haveReadAny = true
//bounds checking ommitted. There are a few ways this can go wrong.
//always check array sizes and returned n.
n, err := i.Conn.Read(b[:3])
if err != nil {
return n, err
}
if string(b[:3]) == "ICY" {
//write Correct http response into buffer
copy(b, []byte("HTTP/1.1"))
return 8, nil
}
return n, nil
}
func main() {
tr := &http.Transport{
Dial: func(network, a string) (net.Conn, error) {
realConn, err := net.Dial(network, a)
if err != nil {
return nil, err
}
return &IcyConnWrapper{Conn: realConn}, nil
},
}
client := &http.Client{Transport: tr}
http.DefaultClient = client
resp, err := http.Get("http://178.33.230.189:8100") //random url I found on the internet
fmt.Println(err)
fmt.Println(resp.StatusCode)
}
Shoutcast 服务器基本上使用 http,但有一个重要区别:它们使用 ICY 200 OK
而不是 HTTP/1.1 200 OK
来响应 GET
请求。
Go 不会有任何障碍,正确地失败并显示错误 malformed HTTP version "ICY"
。
但是我想让事情正常进行,并且想知道最好的方法是什么。到目前为止我的想法:
- 使用自定义 http.Transport.Proxy 将
ICY
更改为HTTP/1.1
in-flight - 做同样事情的进程外代理
- 重载
http.ParseHTTPVersion
(但golang没有函数重载) - 复制整个http包,只是为了修改
ParseHTTPVersion
数字 1. 似乎最吸引人,但我不知道如何尊重 http "scope" 并实际修改给定 http 版本上的所有响应。这是http.Transport.Proxy
可以处理的事情吗?
任何人都可以给我任何指示吗?
我通过创建一个 returns 包装连接的自定义 Dial 函数来实现此功能。我的包装程序拦截了连接上的第一次读取,并将 ICY 替换为 HTTP/1.1。不是超级健壮,但证明了这个概念:
package main
import (
"fmt"
"net"
"net/http"
)
type IcyConnWrapper struct {
net.Conn
haveReadAny bool
}
func (i *IcyConnWrapper) Read(b []byte) (int, error) {
if i.haveReadAny {
return i.Conn.Read(b)
}
i.haveReadAny = true
//bounds checking ommitted. There are a few ways this can go wrong.
//always check array sizes and returned n.
n, err := i.Conn.Read(b[:3])
if err != nil {
return n, err
}
if string(b[:3]) == "ICY" {
//write Correct http response into buffer
copy(b, []byte("HTTP/1.1"))
return 8, nil
}
return n, nil
}
func main() {
tr := &http.Transport{
Dial: func(network, a string) (net.Conn, error) {
realConn, err := net.Dial(network, a)
if err != nil {
return nil, err
}
return &IcyConnWrapper{Conn: realConn}, nil
},
}
client := &http.Client{Transport: tr}
http.DefaultClient = client
resp, err := http.Get("http://178.33.230.189:8100") //random url I found on the internet
fmt.Println(err)
fmt.Println(resp.StatusCode)
}