Files
fivenode_go/app/bridge/bridge_cookie.prg
Charles KWON OhJun c72c2ff58d feat(bridge): port bridge_*.prg + wire HTTP↔bridge dispatcher
Pulls bridge_context.prg, bridge_request.prg, bridge_session.prg, and
bridge_cookie.prg from upstream fivenode into app/bridge/ so the
mod_harbour AP_* surface (AP_METHOD, AP_BODY, AP_ARGS, AP_USERIP,
AP_RPUTS, AP_JSONRESPONSE, AP_SETCONTENTTYPE, ctx_get, ctx_set, ...)
runs unchanged on top of fivenode_go's Go RTL.

bridge_main.prg deliberately omitted — its REQUEST sweep pulls in
TDrMySQL / hbct / hbcurl symbols fivenode_go neither has nor needs.
fivenode_go runs ahead-of-time with the Five compiler, so the
REQUEST trick that keeps fnb-runtime symbols alive isn't required.

One upstream patch was unavoidable: AP_RPUTS / AP_ECHO were variadic
(`( ... )`) and used PValue() to walk caller args. Five's PValue
returns the caller's LOCAL slot (not the actual variadic args, which
aren't copied into locals when declared params is 0), so the body
came back as "1" instead of the JSON payload. Collapsed both to a
single-argument form; every call site in fivenode_go already passes
exactly one value. Patched-out spots are marked with a TODO so we
can revert once Five gains real variadic PValue support.

app/bridge_server.prg ties it all together: starts httpserver on
:8090 with BRIDGEDISPATCH as the handler, hand-translates the Go
request hash into the ctx fields the AP_* layer reads, dispatches by
URL path (hard-coded /api/hello and /api/echo for now — file-name
dispatch lands in 1a.4), and assembles the response from the buffered
AP_* output + ctx_get("status") + ctx_get("headers_out").

Verified end-to-end:
  GET  /api/hello                       -> 200 JSON, method/ip echoed
  POST /api/echo?lang=ko (16-byte body) -> 200 JSON, body_parsed,
                                           query, user-agent
  GET  /api/nope                        -> 404 JSON

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-27 10:54:12 +09:00

110 lines
2.3 KiB
Plaintext

/*
* bridge_cookie.prg - FiveNode
*
* Copyright (c) 2026 Charles KWON ( Charles KWON Ohjun, charleskwonohjun@gmail.com )
* All rights reserved.
*/
// bridge_cookie.prg
// Cookie functions (6) - mod_harbourv2 100% compatible
FUNCTION fn_GetCookies( cKey )
LOCAL hCookies := _parse_cookies()
IF cKey == NIL
RETURN hCookies
ENDIF
IF hb_HHasKey( hCookies, cKey )
RETURN hCookies[ cKey ]
ENDIF
RETURN ""
FUNCTION AP_COOKIE_READ( cName )
RETURN fn_GetCookies( cName )
FUNCTION fn_SetCookie( cName, cValue, nSecs, cPath, cDomain, lHttps, lOnlyHttp )
LOCAL cCookie, aCookies
hb_default( @cPath, "/" )
hb_default( @lHttps, .F. )
hb_default( @lOnlyHttp, .F. )
cCookie := cName + "=" + cValue
IF nSecs != NIL
cCookie += "; Max-Age=" + hb_ntos( nSecs )
ENDIF
cCookie += "; Path=" + cPath
IF cDomain != NIL
cCookie += "; Domain=" + cDomain
ENDIF
IF lHttps
cCookie += "; Secure"
ENDIF
IF lOnlyHttp
cCookie += "; HttpOnly"
ENDIF
aCookies := ctx_get( "cookies_out", {} )
AAdd( aCookies, cCookie )
ctx_set( "cookies_out", aCookies )
RETURN NIL
FUNCTION AP_COOKIE_WRITE( cName, cValue, nExpire )
RETURN fn_SetCookie( cName, cValue, nExpire )
FUNCTION AP_COOKIE_REMOVE( cName )
RETURN fn_SetCookie( cName, "", 0 )
FUNCTION AP_COOKIE_CHECK_STRING( cString )
IF Empty( cString )
RETURN .F.
ENDIF
IF ";" $ cString .OR. Chr(13) $ cString .OR. Chr(10) $ cString
RETURN .F.
ENDIF
RETURN .T.
// ── Cookie parsing helper ──
STATIC FUNCTION _parse_cookies()
LOCAL hHeaders, cRaw, aParts, cPart, aPair
LOCAL hCookies := { => }
hHeaders := AP_HEADERSIN()
IF hb_HHasKey( hHeaders, "Cookie" )
cRaw := hHeaders[ "Cookie" ]
aParts := hb_ATokens( cRaw, ";" )
FOR EACH cPart IN aParts
cPart := AllTrim( cPart )
aPair := hb_ATokens( cPart, "=" )
IF Len( aPair ) >= 2
hCookies[ AllTrim( aPair[1] ) ] := AllTrim( aPair[2] )
ENDIF
NEXT
ENDIF
RETURN hCookies
// -- mod_harbour compatibility wrappers --
FUNCTION MH_GetCookies( cKey )
RETURN fn_GetCookies( cKey )
FUNCTION MH_SetCookie( cName, cValue, nSecs, cPath, cDomain, lHttps, lOnlyHttp )
RETURN fn_SetCookie( cName, cValue, nSecs, cPath, cDomain, lHttps, lOnlyHttp )