mirror of
https://github.com/dalbodeule/hop-gate.git
synced 2025-12-08 04:45:43 +09:00
[feat](server): add 504 Gateway Timeout support and enhance buffer handling
- Introduced `StatusGatewayTimeout` (504) for server-side timeouts between HopGate and backend. - Implemented 504 error page with multilingual support. - Enhanced `bufio.Reader` usage in JSON decoding to prevent "dtls: buffer too small" errors for large payloads. - Applied request handling improvements for control domain and timeout scenarios.
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package dtls
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
@@ -61,7 +62,16 @@ func PerformServerHandshake(
|
||||
}
|
||||
|
||||
var req handshakeRequest
|
||||
if err := json.NewDecoder(sess).Decode(&req); err != nil {
|
||||
// NOTE: pion/dtls 는 application plaintext 를 Caller's buffer 에 복호화하므로,
|
||||
// JSON 디코더가 사용하는 버퍼 크기가 너무 작으면 "dtls: buffer too small" 이 발생할 수 있습니다.
|
||||
// 이를 피하기 위해 충분히 큰 bufio.Reader(예: 64KiB)를 사용합니다. (ko)
|
||||
// pion/dtls decrypts application data into the buffer provided by the caller.
|
||||
// To avoid "dtls: buffer too small" errors when JSON payloads are larger than
|
||||
// the default decoder buffer, we wrap the session in a bufio.Reader with a
|
||||
// sufficiently large size (e.g. 64KiB). (en)
|
||||
dec := json.NewDecoder(bufio.NewReaderSize(sess, 64*1024))
|
||||
|
||||
if err := dec.Decode(&req); err != nil {
|
||||
log.Error("failed to read handshake request", logging.Fields{
|
||||
"error": err.Error(),
|
||||
})
|
||||
@@ -151,7 +161,11 @@ func PerformClientHandshake(
|
||||
}
|
||||
|
||||
var resp handshakeResponse
|
||||
if err := json.NewDecoder(sess).Decode(&resp); err != nil {
|
||||
// 클라이언트 측에서도 동일하게 큰 버퍼를 사용해 "buffer too small" 오류를 방지합니다. (ko)
|
||||
// Use the same larger buffer on the client side as well. (en)
|
||||
dec := json.NewDecoder(bufio.NewReaderSize(sess, 64*1024))
|
||||
|
||||
if err := dec.Decode(&resp); err != nil {
|
||||
log.Error("failed to read handshake response", logging.Fields{
|
||||
"error": err.Error(),
|
||||
})
|
||||
|
||||
@@ -14,6 +14,11 @@ import (
|
||||
// TLS/DTLS 핸드셰이크 실패를 나타내는 HTTP 스타일 상태 코드입니다. (예: 525)
|
||||
const StatusTLSHandshakeFailed = 525
|
||||
|
||||
// StatusGatewayTimeout is an HTTP-style status code representing
|
||||
// a gateway timeout between HopGate and the backend (similar to 504).
|
||||
// HopGate 와 백엔드 간 요청이 너무 오래 걸려 타임아웃된 경우를 나타내는 상태 코드입니다. (예: 504)
|
||||
const StatusGatewayTimeout = http.StatusGatewayTimeout
|
||||
|
||||
//go:embed templates/*.html
|
||||
var embeddedTemplatesFS embed.FS
|
||||
|
||||
|
||||
32
internal/errorpages/templates/504.html
Normal file
32
internal/errorpages/templates/504.html
Normal file
@@ -0,0 +1,32 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>504 Gateway Timeout - HopGate</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="stylesheet" href="/__hopgate_assets__/errors.css">
|
||||
</head>
|
||||
<body class="min-h-screen bg-slate-950 text-slate-50 flex items-center justify-center px-4">
|
||||
<div class="w-full max-w-xl text-center">
|
||||
<div class="items-center justify-center gap-3 mb-8 flex flex-col">
|
||||
<img src="/__hopgate_assets__/hop-gate.png" alt="HopGate" class="h-8 w-[240px] opacity-90" />
|
||||
<h2 class="text-md font-medium tracking-[0.25em] uppercase text-slate-400">HopGate</h2>
|
||||
</div>
|
||||
|
||||
<div class="inline-flex items-baseline gap-4 mb-4">
|
||||
<span class="text-6xl md:text-7xl font-extrabold tracking-[0.25em] text-amber-200">504</span>
|
||||
<span class="text-lg md:text-xl font-semibold text-slate-100">Gateway Timeout</span>
|
||||
</div>
|
||||
|
||||
<p class="text-sm md:text-base text-slate-300 leading-relaxed">
|
||||
The request to the backend service took too long and was timed out by HopGate.<br>
|
||||
백엔드 서비스로의 요청이 너무 오래 걸려 HopGate 에서 타임아웃 처리되었습니다.
|
||||
</p>
|
||||
|
||||
<div class="mt-8 text-xs md:text-sm text-slate-500">
|
||||
This may happen when the origin is overloaded or responding very slowly.<br>
|
||||
원본 서버가 과부하 상태이거나 응답이 매우 느린 경우에 발생할 수 있습니다.
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,6 +1,7 @@
|
||||
package proxy
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
@@ -61,7 +62,14 @@ func (p *ClientProxy) StartLoop(ctx context.Context, sess dtls.Session) error {
|
||||
}
|
||||
log := p.Logger
|
||||
|
||||
dec := json.NewDecoder(sess)
|
||||
// NOTE: pion/dtls 는 복호화된 애플리케이션 데이터를 호출자가 제공한 버퍼에 채워 넣습니다.
|
||||
// 기본 JSON 디코더 버퍼(수백 바이트 수준)만 사용하면 큰 HTTP 바디/Envelope 에서
|
||||
// "dtls: buffer too small" 오류가 날 수 있으므로, 여기서는 여유 있는 버퍼(64KiB)를 사용합니다. (ko)
|
||||
// NOTE: pion/dtls decrypts application data into the buffer provided by the caller.
|
||||
// Using only the default JSON decoder buffer (a few hundred bytes) can trigger
|
||||
// "dtls: buffer too small" for large HTTP bodies/envelopes, so we wrap the
|
||||
// session with a reasonably large bufio.Reader (64KiB). (en)
|
||||
dec := json.NewDecoder(bufio.NewReaderSize(sess, 64*1024))
|
||||
enc := json.NewEncoder(sess)
|
||||
|
||||
for {
|
||||
|
||||
Reference in New Issue
Block a user