Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 34 additions & 1 deletion proxy/http/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package http

import (
"bufio"
"bytes"
"context"
"encoding/base64"
"io"
Expand Down Expand Up @@ -275,7 +276,7 @@ func (s *Server) handlePlainHTTP(ctx context.Context, request *http.Request, wri

responseDone := func() error {
responseReader := bufio.NewReaderSize(&buf.BufferedReader{Reader: link.Reader}, buf.Size)
response, err := http.ReadResponse(responseReader, request)
response, err := readResponseAndHandle100Continue(responseReader, request, writer)
if err == nil {
http_proto.RemoveHopByHopHeaders(response.Header)
if response.ContentLength >= 0 {
Expand Down Expand Up @@ -319,6 +320,38 @@ func (s *Server) handlePlainHTTP(ctx context.Context, request *http.Request, wri
return result
}

// Sometimes, server might send 1xx response to client
// it should not be processed by http proxy handler, just forward it to client
func readResponseAndHandle100Continue(r *bufio.Reader, req *http.Request, writer io.Writer) (*http.Response, error) {
// have a little look of response
peekBytes, err := r.Peek(56)
if err == nil || err == bufio.ErrBufferFull {
str := string(peekBytes)
ResponseLine := strings.Split(str, "\r\n")[0]
_, status, _ := strings.Cut(ResponseLine, " ")
// only handle 1xx response
if strings.HasPrefix(status, "1") {
ResponseHeader1xx := []byte{}
// read until \r\n\r\n (end of http response header)
for {
data, err := r.ReadSlice('\n')
if err != nil {
return nil, newError("failed to read http 1xx response").Base(err).AtError()
}
ResponseHeader1xx = append(ResponseHeader1xx, data...)
if bytes.Equal(ResponseHeader1xx[len(ResponseHeader1xx)-4:], []byte{'\r', '\n', '\r', '\n'}) {
break
}
if len(ResponseHeader1xx) > 1024 {
return nil, newError("too big http 1xx response").AtError()
}
}
writer.Write(ResponseHeader1xx)
}
}
return http.ReadResponse(r, req)
}

func init() {
common.Must(common.RegisterConfig((*ServerConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
return NewServer(ctx, config.(*ServerConfig))
Expand Down
Loading