Fix XHTTP
This commit is contained in:
+33
-48
@@ -144,13 +144,13 @@ func (ib *nativeInbound) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
if !ib.xhttpHostAllowed(r.Host) {
|
if !ib.xhttpHostAllowed(r.Host) {
|
||||||
xrayLogf("native xray: xhttp reject inbound=%q reason=host method=%s path=%q host=%q want=%q remote=%s", ib.tag, r.Method, r.URL.RequestURI(), r.Host, ib.xhttpHost, r.RemoteAddr)
|
xrayLogf("native xray: xhttp reject inbound=%q reason=host method=%s path=%q host=%q want=%q remote=%s", ib.tag, r.Method, r.URL.RequestURI(), r.Host, ib.xhttpHost, r.RemoteAddr)
|
||||||
xhttpBadRequest(w)
|
w.WriteHeader(http.StatusNotFound)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
base, ok := ib.matchXHTTPPath(r.URL.Path)
|
base, ok := ib.matchXHTTPPath(r.URL.Path)
|
||||||
if !ok {
|
if !ok {
|
||||||
xrayLogf("native xray: xhttp reject inbound=%q reason=path method=%s path=%q want=%q host=%q remote=%s", ib.tag, r.Method, r.URL.RequestURI(), ib.path, r.Host, r.RemoteAddr)
|
xrayLogf("native xray: xhttp reject inbound=%q reason=path method=%s path=%q want=%q host=%q remote=%s", ib.tag, r.Method, r.URL.RequestURI(), ib.path, r.Host, r.RemoteAddr)
|
||||||
xhttpBadRequest(w)
|
w.WriteHeader(http.StatusNotFound)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -164,45 +164,39 @@ func (ib *nativeInbound) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||||||
mode := ib.normalizedXHTTPMode()
|
mode := ib.normalizedXHTTPMode()
|
||||||
xrayTracef("native xray: xhttp request inbound=%q method=%s proto=%s path=%q host=%q session=%q seq=%q len=%d mode=%s remote=%s", ib.tag, r.Method, r.Proto, r.URL.RequestURI(), r.Host, sessionID, seqStr, r.ContentLength, mode, r.RemoteAddr)
|
xrayTracef("native xray: xhttp request inbound=%q method=%s proto=%s path=%q host=%q session=%q seq=%q len=%d mode=%s remote=%s", ib.tag, r.Method, r.Proto, r.URL.RequestURI(), r.Host, sessionID, seqStr, r.ContentLength, mode, r.RemoteAddr)
|
||||||
|
|
||||||
// Xray's SplitHTTP treats GET with a sequence id as an uplink packet, not as
|
// Routing mirrors xray-core splithttp hub.go ServeHTTP exactly.
|
||||||
// stream-down. Some clients use this when the upload payload is carried in
|
if sessionID == "" && mode != "" && mode != "auto" && mode != "stream-one" && mode != "stream-up" {
|
||||||
// headers/cookies instead of the body. The previous native handler always
|
http.Error(w, "stream-one mode is not allowed", http.StatusBadRequest)
|
||||||
// treated GET as download and dropped those packets, so normal sites such as
|
return
|
||||||
// fast.com could authenticate but then stall with no upstream data.
|
}
|
||||||
if r.Method == http.MethodGet && sessionID != "" && seqStr != "" {
|
|
||||||
|
// GET carries uplink data only when it has a sequence id; every other method
|
||||||
|
// (POST/PUT/PATCH) is always an uplink request.
|
||||||
|
isUplinkRequest := true
|
||||||
|
if r.Method == http.MethodGet {
|
||||||
|
isUplinkRequest = seqStr != ""
|
||||||
|
}
|
||||||
|
|
||||||
|
if isUplinkRequest && sessionID != "" { // stream-up, packet-up
|
||||||
sess := ib.upsertXHTTPSession(w, sessionID)
|
sess := ib.upsertXHTTPSession(w, sessionID)
|
||||||
if sess == nil {
|
if sess == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if seqStr == "" {
|
||||||
|
ib.handleXHTTPStreamUpload(w, r, sess)
|
||||||
|
return
|
||||||
|
}
|
||||||
ib.handleXHTTPPacketUpload(w, r, sess, seqStr)
|
ib.handleXHTTPPacketUpload(w, r, sess, seqStr)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if r.Method == http.MethodGet || r.Method == http.MethodHead {
|
if r.Method == http.MethodGet || sessionID == "" { // stream-down, stream-one
|
||||||
if sessionID == "" {
|
if sessionID != "" {
|
||||||
// Do not look like a fake web site. A plain browser request is not an
|
sess := ib.upsertXHTTPSession(w, sessionID)
|
||||||
// XHTTP stream. External Xray normally answers this kind of access as a
|
if sess == nil {
|
||||||
// bad request because the required XHTTP metadata/padding is missing.
|
return
|
||||||
xhttpBadRequest(w)
|
}
|
||||||
return
|
ib.handleXHTTPDownload(w, r, sess, sessionID)
|
||||||
}
|
|
||||||
sess := ib.upsertXHTTPSession(w, sessionID)
|
|
||||||
if sess == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
ib.handleXHTTPDownload(w, r, sess, sessionID)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if !isXHTTPUploadMethod(r.Method) {
|
|
||||||
w.Header().Set("Allow", "GET, POST, PUT, PATCH, OPTIONS")
|
|
||||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if sessionID == "" {
|
|
||||||
if mode != "auto" && mode != "stream-one" && mode != "stream-up" {
|
|
||||||
http.Error(w, "xhttp stream-one mode is not allowed", http.StatusBadRequest)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if r.Body == nil || (r.ContentLength == 0 && len(r.TransferEncoding) == 0) {
|
if r.Body == nil || (r.ContentLength == 0 && len(r.TransferEncoding) == 0) {
|
||||||
@@ -213,15 +207,8 @@ func (ib *nativeInbound) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
sess := ib.upsertXHTTPSession(w, sessionID)
|
w.Header().Set("Allow", "GET, POST, PUT, PATCH, OPTIONS")
|
||||||
if sess == nil {
|
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||||
return
|
|
||||||
}
|
|
||||||
if seqStr == "" {
|
|
||||||
ib.handleXHTTPStreamUpload(w, r, sess)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
ib.handleXHTTPPacketUpload(w, r, sess, seqStr)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func xhttpBadRequest(w http.ResponseWriter) {
|
func xhttpBadRequest(w http.ResponseWriter) {
|
||||||
@@ -332,16 +319,14 @@ func (ib *nativeInbound) extractXHTTPMeta(r *http.Request, base string) (session
|
|||||||
sessionKey := firstNonEmpty(ib.xhttpSessionKey, defaultXHTTPMetaKey(sessionPlacement, true))
|
sessionKey := firstNonEmpty(ib.xhttpSessionKey, defaultXHTTPMetaKey(sessionPlacement, true))
|
||||||
seqKey := firstNonEmpty(ib.xhttpSeqKey, defaultXHTTPMetaKey(seqPlacement, false))
|
seqKey := firstNonEmpty(ib.xhttpSeqKey, defaultXHTTPMetaKey(seqPlacement, false))
|
||||||
|
|
||||||
|
// Matches xray-core ExtractMetaFromRequest: split the path suffix after the
|
||||||
|
// base directly, without trimming empty segments, so segment indices line up
|
||||||
|
// exactly with what the client produced via appendToPath.
|
||||||
var parts []string
|
var parts []string
|
||||||
pathPart := 0
|
pathPart := 0
|
||||||
if sessionPlacement == xhttpPlacementPath || seqPlacement == xhttpPlacementPath {
|
if sessionPlacement == xhttpPlacementPath || seqPlacement == xhttpPlacementPath {
|
||||||
rest := ""
|
|
||||||
if strings.HasPrefix(r.URL.Path, base) {
|
if strings.HasPrefix(r.URL.Path, base) {
|
||||||
rest = r.URL.Path[len(base):]
|
parts = strings.Split(r.URL.Path[len(base):], "/")
|
||||||
}
|
|
||||||
rest = strings.Trim(rest, "/")
|
|
||||||
if rest != "" {
|
|
||||||
parts = strings.Split(rest, "/")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user