42 lines
3 KiB
TypeScript
42 lines
3 KiB
TypeScript
|
|
// origin เต็มของ request ที่เข้ามา — ใช้ประกอบ URL เต็มที่จะส่งกลับออกไปข้างนอก
|
||
|
|
// (deep link ของ N10 / manifest.xml ของ wordaddin) เพราะ request ที่เห็นฝั่ง app
|
||
|
|
// มักผ่าน reverse proxy หลัง (IIS ของทางศาล) จึงต้องดู header ของ proxy ก่อน
|
||
|
|
//
|
||
|
|
// ถอดมาจาก requestOrigin เดิมใน app/api/note/external/documents/route.ts
|
||
|
|
// (2026-10-16) ให้ route manifest ของ wordaddin ใช้ร่วม
|
||
|
|
|
||
|
|
/** origin เต็มของ request นี้: เชื่อ header ของ reverse proxy ก่อน
|
||
|
|
* (x-forwarded-proto / x-forwarded-host — proxy หลายชั้นส่งเป็น comma list
|
||
|
|
* ใช้ค่าแรก) แล้วค่อย fallback จาก host/protocol ของ request ตรง ๆ
|
||
|
|
*
|
||
|
|
* แล้วบังคับ https เมื่อโฮสต์ปลายทางไม่ใช่ localhost แต่ได้ proto เป็น http:
|
||
|
|
* hop ภายในหลัง proxy เป็น http ปกติ (อาจไม่มี x-forwarded-proto ให้ — Next
|
||
|
|
* server ก็ฉีด `x-forwarded-proto: http` ให้เองด้วย เชื่อ "ใครเป็นคนตั้ง" ไม่ได้)
|
||
|
|
* ส่วนผู้บริโภค URL พวกนี้ (Word สำหรับ manifest — รับ https เท่านั้น ยกเว้น
|
||
|
|
* localhost, browser สำหรับ deep link ของ N10) เข้าถึงโฮสต์จริงผ่าน https
|
||
|
|
* เสมอ — ค่า http://<โฮสต์ที่ไม่ใช่ localhost> ใช้ไม่ได้จริง จึงชี้ขาดจากตัว
|
||
|
|
* โฮสต์ปลายทางแทนการเดาว่า header มาจาก proxy หรือถูกฉีด */
|
||
|
|
export function requestOrigin(req: Request): string {
|
||
|
|
const url = new URL(req.url);
|
||
|
|
const host =
|
||
|
|
req.headers.get("x-forwarded-host")?.split(",")[0]?.trim() ??
|
||
|
|
req.headers.get("host") ??
|
||
|
|
url.host;
|
||
|
|
const forwardedProto =
|
||
|
|
req.headers.get("x-forwarded-proto")?.split(",")[0]?.trim() ??
|
||
|
|
url.protocol.replace(":", "");
|
||
|
|
// host อาจติด port มาด้วย (localhost:3000) — ถอดออกก่อนเทียบ (URL จัดการ
|
||
|
|
// IPv6 ในวงเล็บ [::1] ให้ด้วย เขียน split(":") เองจะพัง)
|
||
|
|
const hostname = (() => {
|
||
|
|
try {
|
||
|
|
return new URL(`http://${host}`).hostname;
|
||
|
|
} catch {
|
||
|
|
return host;
|
||
|
|
}
|
||
|
|
})();
|
||
|
|
const isLocal =
|
||
|
|
hostname === "localhost" || hostname === "127.0.0.1" || hostname === "[::1]" || hostname === "::1";
|
||
|
|
const proto = !isLocal && forwardedProto === "http" ? "https" : forwardedProto;
|
||
|
|
return `${proto}://${host}`;
|
||
|
|
}
|