Files
v2ray_simple/httpLayer/httpLayer.go
e1732a364fed 3e7e779920 修订代码; 完善ws; 令Pool使用指针,而不是slice
令 websocket在path访问正确但是不是ws连接时,也进行回落,而不是返回一个错误

将 GetH1RequestMethod_and_PATH_from_Bytes 改名为 ParseH1Request, 且支持 读取header

同时新增了 RawHeader 结构 用于 上述目的。httpLayer还添加了 CanonicalizeHeaderKey 方法。

令Pool使用指针 后,测速从 3200左右上升至3800左右,也不知道是不是这个优化导致的。如果是的话,那也太猛了。
2022-05-07 09:51:45 +08:00

155 lines
3.7 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
Package httpLayer provides methods for parsing and sending http request and response.
Fallback 由 本包 处理. 因为回落的目标只可能是http服务器.
http头 格式 可以参考:
https://datatracker.ietf.org/doc/html/rfc2616#section-4
https://datatracker.ietf.org/doc/html/rfc2616#section-5
V2ray 兼容性
http头我们希望能够完全兼容 v2ray的行为。
观察v2ray的实现在没有header时还会添加一个 Date 这个v2ray的文档里没提
v2ray文档: https://www.v2fly.org/config/transport/tcp.html#noneheaderobject
相关 v2ray代码: https://github.com/v2fly/v2ray-core/tree/master/transport/internet/headers/http/http.go
我们虽然宣称兼容 v2ray但在对于这种 不在 v2ray文档里提及的 代码实现, 我们不予支持。
*/
package httpLayer
import (
"bytes"
"errors"
"io"
"net"
"strings"
"github.com/e1732a364fed/v2ray_simple/utils"
"net/http"
"net/http/httptest"
)
var Err404response = `HTTP/1.1 404 Not Found\r\nContent-Type: text/html
Connection: keep-alive\r\n404 Not Found\r\n`
const Err403response = `HTTP/1.1 403 Forbidden
Connection: close
Cache-Control: max-age=3600, public
Content-Length: 0
`
const (
H11_Str = "http/1.1"
H2_Str = "h2"
CRLF = "\r\n"
//参考 https://datatracker.ietf.org/doc/html/rfc2616#section-4.1
//
//http头的尾部. 每个header末尾都有一个 crlf, 整个头部结尾还有一个crlf, 所以是两个.
HeaderENDING = CRLF + CRLF
//我们不使用v2ray的8k的最大header长度限制因为这反倒会探测出特殊性。http标准是最大1MB。
)
var (
HeaderENDING_bytes = []byte(HeaderENDING)
ErrNotHTTP_Request = errors.New("not http request")
)
func init() {
//使用 httptest 包 来完美重现 golang的http包的 notfound, 可以随golang具体实现而同步变化
req := httptest.NewRequest("GET", "http://exam.com/", nil)
w := httptest.NewRecorder()
http.NotFound(w, req)
buf := &bytes.Buffer{}
w.Result().Write(buf)
Err404response = buf.String()
}
type RequestErr struct {
Path string
Method string
}
func (e *RequestErr) Is(err error) bool {
if err == nil {
return false
}
if re, ok := err.(*RequestErr); ok && re != nil {
return (e.Path == re.Path && e.Method == re.Path)
}
if err == utils.ErrInvalidData {
return true
}
return false
}
func (e *RequestErr) Error() string {
var sb strings.Builder
sb.WriteString("InvaidRequest ")
sb.WriteString(e.Method)
sb.WriteString(",")
sb.WriteString(e.Path)
return sb.String()
}
// H1RequestParser被用于 预读一个链接判断该连接是否是有效的http请求,
// 并将VersionPathMethod 记录在结构中.
//
// 只能过滤 http 0.9, 1.0 和 1.1. 无法过滤h2和h3.
type H1RequestParser struct {
Version string
Path string
Method string
WholeRequestBuf *bytes.Buffer
Failreason int //为0表示没错误
Headers []RawHeader
}
// 尝试读取数据并解析HTTP请求, 解析道道 数据会存入 RequestParser 结构中.
//如果读取错误,会返回该错误; 如果读到的不是HTTP请求返回 ErrNotHTTP_Request;
func (rhr *H1RequestParser) ReadAndParse(r io.Reader) error {
bs := utils.GetPacket()
n, e := r.Read(bs)
if e != nil {
return e
}
data := bs[:n]
buf := bytes.NewBuffer(data)
rhr.WholeRequestBuf = buf
rhr.Version, rhr.Method, rhr.Path, rhr.Headers, rhr.Failreason = ParseH1Request(data, false)
if rhr.Failreason != 0 {
return utils.ErrInErr{ErrDesc: "httpLayer ReadAndParse failed", ErrDetail: ErrNotHTTP_Request, Data: rhr.Failreason}
}
return nil
}
// http level fallback metadata
type FallbackMeta struct {
net.Conn
H1RequestBuf *bytes.Buffer
Path string
Method string
IsH2 bool
H2Request *http.Request
}