http.go 1.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. package vmess
  2. import (
  3. "bufio"
  4. "bytes"
  5. "errors"
  6. "fmt"
  7. "net"
  8. "net/http"
  9. "net/textproto"
  10. "github.com/metacubex/mihomo/common/utils"
  11. "github.com/metacubex/randv2"
  12. )
  13. type httpConn struct {
  14. net.Conn
  15. cfg *HTTPConfig
  16. reader *bufio.Reader
  17. whandshake bool
  18. }
  19. type HTTPConfig struct {
  20. Method string
  21. Host string
  22. Path []string
  23. Headers map[string][]string
  24. }
  25. // Read implements net.Conn.Read()
  26. func (hc *httpConn) Read(b []byte) (int, error) {
  27. if hc.reader != nil {
  28. n, err := hc.reader.Read(b)
  29. return n, err
  30. }
  31. reader := textproto.NewConn(hc.Conn)
  32. // First line: GET /index.html HTTP/1.0
  33. if _, err := reader.ReadLine(); err != nil {
  34. return 0, err
  35. }
  36. if _, err := reader.ReadMIMEHeader(); err != nil {
  37. return 0, err
  38. }
  39. hc.reader = reader.R
  40. return reader.R.Read(b)
  41. }
  42. // Write implements io.Writer.
  43. func (hc *httpConn) Write(b []byte) (int, error) {
  44. if hc.whandshake {
  45. return hc.Conn.Write(b)
  46. }
  47. if len(hc.cfg.Path) == 0 {
  48. return -1, errors.New("path is empty")
  49. }
  50. path := hc.cfg.Path[randv2.IntN(len(hc.cfg.Path))]
  51. host := hc.cfg.Host
  52. if header := hc.cfg.Headers["Host"]; len(header) != 0 {
  53. host = header[randv2.IntN(len(header))]
  54. }
  55. u := fmt.Sprintf("http://%s%s", net.JoinHostPort(host, "80"), path)
  56. req, err := http.NewRequest(utils.EmptyOr(hc.cfg.Method, http.MethodGet), u, bytes.NewBuffer(b))
  57. if err != nil {
  58. return 0, err
  59. }
  60. for key, list := range hc.cfg.Headers {
  61. req.Header.Set(key, list[randv2.IntN(len(list))])
  62. }
  63. req.ContentLength = int64(len(b))
  64. if err := req.Write(hc.Conn); err != nil {
  65. return 0, err
  66. }
  67. hc.whandshake = true
  68. return len(b), nil
  69. }
  70. func (hc *httpConn) Close() error {
  71. return hc.Conn.Close()
  72. }
  73. func StreamHTTPConn(conn net.Conn, cfg *HTTPConfig) net.Conn {
  74. return &httpConn{
  75. Conn: conn,
  76. cfg: cfg,
  77. }
  78. }