@@ -107,6 +107,53 @@ const (
107107 destHostKey key = iota
108108)
109109
110+ // mapDialErrorToHTTPStatus maps common TCP/network error strings to appropriate HTTP status codes
111+ func mapDialErrorToHTTPStatus (errStr string ) int {
112+ // Convert to lowercase for case-insensitive matching
113+ errLower := strings .ToLower (errStr )
114+
115+ // Check each error pattern and return appropriate status code
116+ switch {
117+ // Timeouts - backend didn't respond in time -> 504 Gateway Timeout
118+ case strings .Contains (errLower , "i/o timeout" ),
119+ strings .Contains (errLower , "deadline exceeded" ),
120+ strings .Contains (errLower , "context deadline exceeded" ),
121+ strings .Contains (errLower , "timeout" ):
122+ return 504
123+
124+ // Resource exhaustion errors -> 503 Service Unavailable
125+ case strings .Contains (errLower , "too many open files" ),
126+ strings .Contains (errLower , "socket: too many open files" ):
127+ return 503
128+
129+ // Connection errors -> 502 Bad Gateway
130+ case strings .Contains (errLower , "connection refused" ),
131+ strings .Contains (errLower , "connection reset by peer" ),
132+ strings .Contains (errLower , "broken pipe" ),
133+ strings .Contains (errLower , "network is unreachable" ),
134+ strings .Contains (errLower , "no route to host" ),
135+ strings .Contains (errLower , "host is unreachable" ),
136+ strings .Contains (errLower , "network is down" ):
137+ return 502
138+
139+ // DNS resolution failures -> 502 Bad Gateway
140+ case strings .Contains (errLower , "no such host" ),
141+ strings .Contains (errLower , "name resolution" ),
142+ strings .Contains (errLower , "lookup" ) && strings .Contains (errLower , "no such host" ):
143+ return 502
144+
145+ // TLS/SSL errors -> 502 Bad Gateway
146+ case strings .Contains (errLower , "tls" ),
147+ strings .Contains (errLower , "ssl" ),
148+ strings .Contains (errLower , "certificate" ):
149+ return 502
150+
151+ // Default to 502 Bad Gateway for unknown proxy errors
152+ default :
153+ return 502
154+ }
155+ }
156+
110157func (c * ProxyClientConnection ) send (pkt * client.Packet ) error {
111158 defer func (start time.Time ) { metrics .Metrics .ObserveFrontendWriteLatency (time .Since (start )) }(time .Now ())
112159 if c .Mode == ModeGRPC {
@@ -121,11 +168,21 @@ func (c *ProxyClientConnection) send(pkt *client.Packet) error {
121168 _ , err := c .HTTP .Write (pkt .GetData ().Data )
122169 return err
123170 } else if pkt .Type == client .PacketType_DIAL_RSP {
124- if pkt .GetDialResponse ().Error != "" {
125- body := bytes .NewBufferString (pkt .GetDialResponse ().Error )
171+ dialErr := pkt .GetDialResponse ().Error
172+ if dialErr != "" {
173+ // // Map the error to appropriate HTTP status code
174+ statusCode := mapDialErrorToHTTPStatus (dialErr )
175+ statusText := http .StatusText (statusCode )
176+ body := bytes .NewBufferString (dialErr )
126177 t := http.Response {
127- StatusCode : 503 ,
178+ StatusCode : statusCode ,
179+ Status : fmt .Sprintf ("%d %s" , statusCode , statusText ),
128180 Body : io .NopCloser (body ),
181+ Header : http.Header {
182+ "Content-Type" : []string {"text/plain; charset=utf-8" },
183+ },
184+ Proto : "HTTP/1.1" ,
185+ ProtoMinor : 1 ,
129186 }
130187
131188 t .Write (c .HTTP )
0 commit comments