Documentation ¶
Overview ¶
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文档里提及的 代码实现, 我们不予支持。
Index ¶
- Constants
- Variables
- func AllHeadersIn(template map[string][]string, realh http.Header) (ok bool, firstNotMatchKey string)
- func CanonicalizeHeaderKey(k []byte)
- func GetNginx400Response() string
- func GetNginx403Response() string
- func GetNginx404Response() string
- func GetNginxResponse(template string) string
- func GetNginxWeekdayStr(t *time.Time) string
- func HasFallbackType(ftype, b byte) bool
- func SetDefaultNginxHeader(rw http.ResponseWriter)
- func SetNginx400Response(rw http.ResponseWriter)
- func SetNginx403Response(rw http.ResponseWriter)
- func TrimHeaders(m map[string][]string) (result map[string][]string)
- type ClassicFallback
- type Fallback
- type FallbackConditionSet
- func (fcs *FallbackConditionSet) GetAllSubSets() (rs []FallbackConditionSet)
- func (fcs *FallbackConditionSet) GetSub(subType byte) (r FallbackConditionSet)
- func (fcs *FallbackConditionSet) GetType() (r byte)
- func (fcs FallbackConditionSet) TestAllSubSets(allsupportedTypeMask byte, theMap map[FallbackConditionSet]*FallbackResult) *FallbackResult
- type FallbackConf
- type FallbackMeta
- type FallbackResult
- type H1RequestParser
- type HeaderConn
- type HeaderPreset
- func (h *HeaderPreset) AssignDefaultValue()
- func (h *HeaderPreset) Prepare()
- func (h *HeaderPreset) ReadRequest(underlay io.Reader) (rp H1RequestParser, leftBuf *bytes.Buffer, err error)
- func (h *HeaderPreset) ReadResponse(underlay io.Reader) (leftBuf *bytes.Buffer, err error)
- func (h *HeaderPreset) WriteRequest(underlay io.Writer, payload []byte) error
- func (h *HeaderPreset) WriteResponse(underlay io.Writer, payload []byte) error
- type RawHeader
- type RejectConn
- type RequestErr
- type RequestHeader
- type ResponseHeader
Constants ¶
const ( FallBack_default byte = 1 << iota //default 其实也是path,只不过path是通配符。 Fallback_path Fallback_alpn Fallback_sni )
const ( Fail_tooShort = iota + 1 Fail_not_for_h2c Fail_method_len_wrong Fail_unexpected_proxy Fail_space_index_wrong Fail_is_11proxy_butNot_11 Fail_no_slash Fail_earlyLinefeed Fail_firstline_less_than_10 )
const ( Err403response = "HTTP/1.1 403 Forbidden\r\nConnection: close\r\nCache-Control: max-age=3600, public\r\nContent-Length: 0\r\n\r\n" 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 XForwardStr = "X-Forwarded-For" )
const ( //符合 nginx返回的时间格式,且符合 golang对时间格式字符串的 "123456"的约定 的字符串。 Nginx_timeFormatStr = "02 Jan 2006 15:04:05 MST" Nginx400_html = "" /* 171-byte string literal not displayed */ // real nginx response,to generate it, echo xx | nc 127.0.0.1 80 > response Err400response_nginx = "HTTP/1.1 400 Bad Request\r\nServer: nginx/1.21.5\r\nDate: Sat, 02 Jan 2006 15:04:05 MST\r\nContent-Type: text/html\r\nConnection: close\r\n\r\n" + Nginx400_html // real nginx response,to generate it, curl -iv --raw 127.0.0.1/not_exist_path > response Err404response_nginx = "" /* 406-byte string literal not displayed */ Nginx403_html = "" /* 185-byte string literal not displayed */ /* real nginx response, to generate it, set nginx config like: location / { return 403; } */ Err403response_nginx = "HTTP/1.1 403 Forbidden\r\nServer: nginx/1.21.5\r\nDate: Sat, 02 Jan 2006 15:04:05 MST\r\nContent-Type: text/html\r\nContent-Length: 169\r\nConnection: keep-alive\r\n\r\n" + Nginx403_html )
const Fail_no_endMark = -12
const (
Fallback_none = 0
)
const MaxParseUrlLen = 3000
也许有 ws 的 earlydata放在 query请求里的情况; 虽然本作不支持这种earlydata, 但是也要认定这是合法的请求。
Variables ¶
var ( HeaderENDING_bytes = []byte(HeaderENDING) ErrNotHTTP_Request = utils.InvalidDataErr("not http request") Err400response_golang string )
var ErrShouldFallback = errors.New("will fallback")
Functions ¶
func AllHeadersIn ¶ added in v1.2.0
func AllHeadersIn(template map[string][]string, realh http.Header) (ok bool, firstNotMatchKey string)
all values in template is given by real
func CanonicalizeHeaderKey ¶ added in v1.2.1
func CanonicalizeHeaderKey(k []byte)
Algorithm below is like standard textproto/CanonicalMIMEHeaderKey, except that it operates with slice of bytes and modifies it inplace without copying. copied from gobwas/ws
func GetNginx400Response ¶ added in v1.2.4
func GetNginx400Response() string
Get real a 400 response that looks like it comes from nginx.
func GetNginx403Response ¶ added in v1.2.4
func GetNginx403Response() string
Get real a 403 response that looks like it comes from nginx.
func GetNginx404Response ¶ added in v1.2.4
func GetNginx404Response() string
Get real a 404 response that looks like it comes from nginx.
func GetNginxResponse ¶ added in v1.2.4
Get real a response that looks like it comes from nginx.
func GetNginxWeekdayStr ¶ added in v1.2.4
func HasFallbackType ¶
判断 Fallback.SupportType 返回的 数值 是否具有特定的Fallback类型
func SetDefaultNginxHeader ¶ added in v1.2.4
func SetDefaultNginxHeader(rw http.ResponseWriter)
func SetNginx400Response ¶ added in v1.2.4
func SetNginx400Response(rw http.ResponseWriter)
mimic GetNginx400Response()
func SetNginx403Response ¶ added in v1.2.4
func SetNginx403Response(rw http.ResponseWriter)
Types ¶
type ClassicFallback ¶
type ClassicFallback struct { Default *FallbackResult Map map[string]map[FallbackConditionSet]*FallbackResult //第一层key为 inTag,若为 "" 则表示 来自所有inServer 的 都会被匹配 // contains filtered or unexported fields }
实现 Fallback,支持 path, alpn, sni 分流。
内部 map 我们使用通用的集合办法, 而不是多层map嵌套;
虽然目前就三个fallback类型,但是谁知道以后会加几个?所以这样更通用.
目前3种fallback性能是没问题的,不过如果 fallback继续增加的话, 最差情况下集合的子集总数会急剧上升,导致最差情况下性能不如多重 map;不过一般没人会给出那种配置. TODO: 预先计算所有的子集,这样就不用每次匹配都算一遍
func NewClassicFallback ¶
func NewClassicFallback() *ClassicFallback
func NewClassicFallbackFromConfList ¶
func NewClassicFallbackFromConfList(fcl []*FallbackConf) *ClassicFallback
func (*ClassicFallback) GetFallback ¶
func (cfb *ClassicFallback) GetFallback(fromServerTag string, ftype byte, ss ...string) *FallbackResult
GetFallback 使用给出的 ftype mask 和 对应参数 来试图匹配到 回落地址. ss 必须按 FallBack_* 类型 从小到大顺序排列
func (*ClassicFallback) InsertFallbackConditionSet ¶
func (cfb *ClassicFallback) InsertFallbackConditionSet(condition FallbackConditionSet, forServerTags []string, addr netLayer.Addr, xver int)
func (*ClassicFallback) SupportType ¶
func (cfb *ClassicFallback) SupportType() byte
type Fallback ¶
type Fallback interface { GetFallback(ftype byte, params ...string) *FallbackResult SupportType() byte //参考Fallback_开头的常量。如果支持多个,则返回它们 按位与 的结果 }
实现 Fallback. 这里的fallback只与http协议有关,所以只能按path,alpn 和 sni 进行分类
type FallbackConditionSet ¶
func (*FallbackConditionSet) GetAllSubSets ¶
func (fcs *FallbackConditionSet) GetAllSubSets() (rs []FallbackConditionSet)
返回不包括自己的所有子集
func (*FallbackConditionSet) GetSub ¶
func (fcs *FallbackConditionSet) GetSub(subType byte) (r FallbackConditionSet)
func (*FallbackConditionSet) GetType ¶
func (fcs *FallbackConditionSet) GetType() (r byte)
func (FallbackConditionSet) TestAllSubSets ¶
func (fcs FallbackConditionSet) TestAllSubSets(allsupportedTypeMask byte, theMap map[FallbackConditionSet]*FallbackResult) *FallbackResult
TestAllSubSets 传入一个map, 对fcs自己以及其所有子集依次测试, 看是否有匹配的。 对比 GetAllSubSets 内存占用较大, 而本方法开销则小很多, 因为1是复用内存, 2是匹配到就会返回,一般不会到遍历全部子集.
type FallbackConf ¶
type FallbackConf struct { //可选 FromTag []string `toml:"from" json:"from"` //which inServer triggered this fallback Xver int `toml:"xver" json:"xver"` //use PROXY protocol or not, and which version //必填。 //see netLayer.NewAddrFromAny for details about "any" addr. // // 约定,如果该项是字符串 且 开头为@,则我们认为它给出的是 tag 名称,要将其替换为 实际 该tag的 listen 的地址。 Dest any `toml:"dest" json:"dest"` Path string `toml:"path" json:"path"` Sni string `toml:"sni" json:"sni"` Alpn []string `toml:"alpn" json:"alpn"` }
type FallbackMeta ¶ added in v1.2.0
type FallbackMeta struct { net.Conn H1RequestBuf *bytes.Buffer Path string Method string IsH2 bool Reason string H2Request *http.Request }
http level fallback metadata
type FallbackResult ¶ added in v1.2.0
func (*FallbackResult) GetFallback ¶ added in v1.2.0
func (r *FallbackResult) GetFallback(ftype byte, _ ...string) *FallbackResult
func (FallbackResult) SupportType ¶ added in v1.2.0
func (FallbackResult) SupportType() byte
type H1RequestParser ¶ added in v1.2.0
type H1RequestParser struct { Version string Path string Method string WholeRequestBuf *bytes.Buffer Failreason int //为0表示没错误 Headers []RawHeader }
H1RequestParser被用于 预读一个链接,判断该连接是否是有效的http请求, 并将Version,Path,Method 记录在结构中.
只能过滤 http 0.9, 1.0 和 1.1. 无法过滤h2和h3.
func (*H1RequestParser) ReadAndParse ¶ added in v1.2.0
func (rhr *H1RequestParser) ReadAndParse(r io.Reader) error
尝试读取数据并解析HTTP请求, 解析的 数据会存入 RequestParser 结构中. 如果读取错误,会返回该错误; 如果读到的不是HTTP请求,返回 的err 的 errors.Is(err,ErrNotHTTP_Request) == true;
该函数有个小问题,就是如果一次Read是短Read(可能是网络原因),没读完整个http头部,则仍然会认为是错误
func (*H1RequestParser) ReadAndParse_2 ¶ added in v1.2.4
func (rhr *H1RequestParser) ReadAndParse_2(r net.Conn) error
第一次没读完后,再读一遍
type HeaderConn ¶
type HeaderPreset ¶
type HeaderPreset struct { Request *RequestHeader `toml:"request"` Response *ResponseHeader `toml:"response"` Strict bool `toml:"strict"` NoResponseHeaderWhenGotHttpResponse bool `toml:"no_resp_h_c"` //用于读取 回落到 真实http服务器的情况,此时我们就不用自定义的响应,而是用 真实服务器的响应。no_resp_h_c 意思是 no response header conditional }
http 头 预设, 分客户端的request 和 服务端的 response这两部分.
func (*HeaderPreset) AssignDefaultValue ¶
func (h *HeaderPreset) AssignDefaultValue()
默认值保持与v2ray的配置相同
func (*HeaderPreset) ReadRequest ¶
func (h *HeaderPreset) ReadRequest(underlay io.Reader) (rp H1RequestParser, leftBuf *bytes.Buffer, err error)
func (*HeaderPreset) ReadResponse ¶
func (*HeaderPreset) WriteRequest ¶
func (h *HeaderPreset) WriteRequest(underlay io.Writer, payload []byte) error
func (*HeaderPreset) WriteResponse ¶
func (h *HeaderPreset) WriteResponse(underlay io.Writer, payload []byte) error
type RejectConn ¶ added in v1.2.4
type RejectConn struct {
http.ResponseWriter
}
implements netLayer.RejectConn
func (RejectConn) RejectBehaviorDefined ¶ added in v1.2.4
func (RejectConn) RejectBehaviorDefined() bool
type RequestErr ¶
func (*RequestErr) Error ¶
func (e *RequestErr) Error() string
func (*RequestErr) Is ¶ added in v1.2.0
func (e *RequestErr) Is(err error) bool