v2ray-core icon indicating copy to clipboard operation
v2ray-core copied to clipboard

`Expect: 100-continue` is not proper handled in http proxy

Open yyjdelete opened this issue 9 months ago • 1 comments

Reproduce with V2Ray 5.29.3 (V2Fly, a community-driven edition of V2Ray.) Custom (go1.23.7 windows/amd64)

The same as https://github.com/XTLS/Xray-core/issues/4545

I notice this when use http_proxy with git and GCM try to do OAUTH2 with an local instance of gitea(auth will never complete) Not sure, but maybe simple remove Expect: 100-continue from proxy/http/server.go and don't send it to server make it works(allow client to fallback as if the server not support 100-continue)

The http stream look like the below in the case(add <- to all response lines for better view), the http_proxy will only forward the first HTTP/1.1 100 Continue but not the latter HTTP/1.1 400 Bad Request( or 200 or others in really instance)

POST /login/oauth/access_token HTTP/1.1
Host: 127.0.0.1:3000
User-Agent: curl/8.12.1
Accept: */*
Content-Type: application/x-www-form-urlencoded
Content-Length: 2097152
Expect: 100-continue


<-HTTP/1.1 100 Continue


{req_body}
<-HTTP/1.1 400 Bad Request
<-Cache-Control: max-age=0, private, must-revalidate, no-transform
<-Content-Type: application/json;charset=utf-8
<-Set-Cookie: ...
<-Set-Cookie: ...
<-X-Frame-Options: SAMEORIGIN
<-Date: ...
<-Content-Length: 122
<-
<-{resp_body}
<-

REPRODUCE

It can easily be reproduce with curl and an local instance of gitea 127.0.0.1->freedom, 127.0.0.1:8888->http inbound, no server required gitea can be simple run gitea and do an first time init(http://127.0.0.1:3000/) with sqlite, and test with the below code It can also be done with git bash for windows

# generate an file >= 1M and not too large to triggle `100-continue` with curl, but not too large as it may triggle CONN RST
# without http_proxy 
$ export http_proxy=
$ dd if=/dev/random of=/tmp/temp.dat bs=1M count=2
$ curl -X POST "http://127.0.0.1:3000/login/oauth/access_token" -H "Content-Type: application/x-www-form-urlencoded" -T /tmp/temp.dat
{"error":"unsupported_grant_type","error_description":"Only refresh_token or authorization_code grant type is supported"}
# with http_proxy 
$ export http_proxy=http://127.0.0.1:8888/
$ curl -X POST "http://127.0.0.1:3000/login/oauth/access_token" -H "Content-Type: application/x-www-form-urlencoded" -T /tmp/temp.dat
# no response and timeout after 1 min
curl: (52) Empty reply from server

yyjdelete avatar Mar 25 '25 05:03 yyjdelete

For each request, we need to keep reading HTTP responses in a loop, forward all 1xx informational responses, and break the loop when we see a non-1xx response. See https://github.com/database64128/shadowsocks-go/blob/main/httpproxy/server.go as an example of how this can be implemented.

database64128 avatar Mar 25 '25 07:03 database64128