2020-03-31 16:07:21 +08:00
|
|
|
package vmess
|
|
|
|
|
|
|
|
import (
|
2021-03-18 17:11:10 +08:00
|
|
|
"bufio"
|
2020-03-31 16:07:21 +08:00
|
|
|
"bytes"
|
2024-03-26 14:19:33 +08:00
|
|
|
"errors"
|
2020-03-31 16:07:21 +08:00
|
|
|
"fmt"
|
|
|
|
"net"
|
|
|
|
"net/http"
|
|
|
|
"net/textproto"
|
2023-03-06 18:10:14 +08:00
|
|
|
|
2023-11-09 08:47:44 +08:00
|
|
|
"github.com/metacubex/mihomo/common/utils"
|
2023-10-16 09:16:36 +08:00
|
|
|
|
2023-03-06 18:10:14 +08:00
|
|
|
"github.com/zhangyunhao116/fastrand"
|
2020-03-31 16:07:21 +08:00
|
|
|
)
|
|
|
|
|
|
|
|
type httpConn struct {
|
|
|
|
net.Conn
|
|
|
|
cfg *HTTPConfig
|
2021-03-18 17:11:10 +08:00
|
|
|
reader *bufio.Reader
|
2020-03-31 16:07:21 +08:00
|
|
|
whandshake bool
|
|
|
|
}
|
|
|
|
|
|
|
|
type HTTPConfig struct {
|
|
|
|
Method string
|
|
|
|
Host string
|
|
|
|
Path []string
|
|
|
|
Headers map[string][]string
|
|
|
|
}
|
|
|
|
|
|
|
|
// Read implements net.Conn.Read()
|
|
|
|
func (hc *httpConn) Read(b []byte) (int, error) {
|
2021-03-18 17:11:10 +08:00
|
|
|
if hc.reader != nil {
|
|
|
|
n, err := hc.reader.Read(b)
|
2020-03-31 16:07:21 +08:00
|
|
|
return n, err
|
|
|
|
}
|
|
|
|
|
|
|
|
reader := textproto.NewConn(hc.Conn)
|
|
|
|
// First line: GET /index.html HTTP/1.0
|
|
|
|
if _, err := reader.ReadLine(); err != nil {
|
|
|
|
return 0, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if _, err := reader.ReadMIMEHeader(); err != nil {
|
|
|
|
return 0, err
|
|
|
|
}
|
|
|
|
|
2021-03-18 17:11:10 +08:00
|
|
|
hc.reader = reader.R
|
|
|
|
return reader.R.Read(b)
|
2020-03-31 16:07:21 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Write implements io.Writer.
|
|
|
|
func (hc *httpConn) Write(b []byte) (int, error) {
|
|
|
|
if hc.whandshake {
|
|
|
|
return hc.Conn.Write(b)
|
|
|
|
}
|
|
|
|
|
2024-03-26 14:19:33 +08:00
|
|
|
if len(hc.cfg.Path) == 0 {
|
|
|
|
return -1, errors.New("path is empty")
|
|
|
|
}
|
|
|
|
|
2023-03-06 18:10:14 +08:00
|
|
|
path := hc.cfg.Path[fastrand.Intn(len(hc.cfg.Path))]
|
2021-05-16 20:05:41 +08:00
|
|
|
host := hc.cfg.Host
|
|
|
|
if header := hc.cfg.Headers["Host"]; len(header) != 0 {
|
2023-03-06 18:10:14 +08:00
|
|
|
host = header[fastrand.Intn(len(header))]
|
2021-05-16 20:05:41 +08:00
|
|
|
}
|
|
|
|
|
2024-02-26 14:05:06 +08:00
|
|
|
u := fmt.Sprintf("http://%s%s", net.JoinHostPort(host, "80"), path)
|
2024-05-15 13:53:18 +08:00
|
|
|
req, err := http.NewRequest(utils.EmptyOr(hc.cfg.Method, http.MethodGet), u, bytes.NewBuffer(b))
|
|
|
|
if err != nil {
|
|
|
|
return 0, err
|
|
|
|
}
|
2020-03-31 16:07:21 +08:00
|
|
|
for key, list := range hc.cfg.Headers {
|
2023-03-06 18:10:14 +08:00
|
|
|
req.Header.Set(key, list[fastrand.Intn(len(list))])
|
2020-03-31 16:07:21 +08:00
|
|
|
}
|
|
|
|
req.ContentLength = int64(len(b))
|
|
|
|
if err := req.Write(hc.Conn); err != nil {
|
|
|
|
return 0, err
|
|
|
|
}
|
|
|
|
hc.whandshake = true
|
|
|
|
return len(b), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (hc *httpConn) Close() error {
|
|
|
|
return hc.Conn.Close()
|
|
|
|
}
|
|
|
|
|
|
|
|
func StreamHTTPConn(conn net.Conn, cfg *HTTPConfig) net.Conn {
|
|
|
|
return &httpConn{
|
|
|
|
Conn: conn,
|
|
|
|
cfg: cfg,
|
|
|
|
}
|
|
|
|
}
|