Pharos Framework

← Back

Native Request/Response Parity Contract

This contract records the current shell/native drift surface for request parsing and native-owned response defaults.

The goal is not to claim the native listener and every compiled host are already backed by one implementation. The goal is to make the current boundary explicit so request parsing and fallback response behavior do not drift silently.

The current boundary should be treated as transitional rather than fundamental. Local and CI validation should increasingly exercise the native listener together with compiled-host behavior so drift trends toward zero.

Reference surface

Current native reference behavior lives in:

  • src/native_runtime/c/pharos_runtime.c
  • src/native_runtime/c/native_http_log.c
  • src/native_runtime/c/native_http_response.c
  • src/native_runtime/c/native_http_access_log.c
  • src/native_runtime/c/native_static_serve.c

Current shell/runtime compiled-host wrapper behavior lives in:

  • runtime/pharos_app_runtime_layer.sh

Key native functions/paths:

  • parse_http_request
  • native_send_text_response
  • http_status_line_from_response_native
  • http_status_code_from_response_native
  • higher-level fail-closed request paths in handle_app_or_runtime_request
  • static artifact response ownership in native_serve_static_file

Contract behaviors to preserve or explicitly revise

1. Request line parsing

The native listener should continue to parse and preserve:

  • HTTP method
  • request target/path
  • header/body boundary from either \r\n\r\n or \n\n

Shell/runtime listener wrappers should normalize an empty or missing extracted request target to / rather than forwarding an empty path deeper into the stack.

Malformed request lines currently fail closed.

Shell/runtime listener wrappers should also fail closed when a request line is malformed instead of treating the missing fields as an implied method/path.

2. Header normalization for forwarded app requests

The native listener should continue to forward headers as newline-separated key:value lines and preserve the current extraction posture for:

  • Content-Length
  • Content-Type
  • Cookie

Shell/runtime forwarding should preserve header values after the first : rather than truncating values that themselves contain additional colons.

For duplicate forwarded headers, the current parity rule should remain explicit:

  • the forwarded headers blob preserves duplicate lines in arrival order
  • scalar extracted request metadata (Cookie, Content-Type, Content-Length) uses the last matching header occurrence case-insensitively
  • if this policy changes later, it must change intentionally across both native and shell/runtime forwarding surfaces

3. Header block completion and partial-request handling

The current request parser boundary should remain fail-closed when the listener never receives a completed header block.

Shell/runtime listener wrappers should not continue request dispatch after EOF if they never observed the terminating blank header line.

4. Content-Length validation and body completeness

Content-Length handling should remain fail-closed at the request parser boundary.

Shell/runtime listeners should reject:

  • non-numeric Content-Length values
  • partial bodies that do not deliver the promised byte count

They should not silently treat malformed or truncated bodies as a valid empty request body.

5. Default request metadata

When request metadata is absent, current native behavior should remain explicit:

  • missing content type → application/x-www-form-urlencoded
  • missing cookie header → empty string
  • multipart detection comes from Content-Type containing multipart/form-data

6. Native-owned response shaping

When the native listener, static server, or native runtime orchestration owns the response directly, current defaults should remain explicit:

  • plain-text fallback responses
  • charset=utf-8
  • Connection: close
  • explicit Content-Length
  • extensionless /api/... artifact responses that are framework JSON surfaces should not silently degrade to application/octet-stream

7. Request body transport shaping

For forwarded compiled app requests, the shell/native boundary should keep the request body transport rule explicit:

  • non-multipart request bodies travel through --form
  • multipart request bodies travel through --body-file
  • when both are present at a compiled-host wrapper boundary, --body-file should take precedence over stale inline form text

8. Compiled app failure defaults

When the compiled app request path fails, current fail-closed behavior should remain explicit across native and shell/runtime forwarding surfaces:

  • child failure or empty response → 502 Bad Gateway
  • detail text may be preserved for request-error logging
  • native success path forwards child bytes unchanged rather than rewriting them
  • shell/runtime forwarding should not silently downgrade compiled-host execution failures into 500 Internal Server Error when the failure is at the app-host boundary

Allowed divergence rule

If shell/runtime helpers, compiled hosts, and the native listener intentionally diverge for one of these behaviors, that divergence must be:

  • documented explicitly
  • justified by runtime ownership or platform constraints
  • reflected in checked contracts/tests/docs

Silent request/response drift is out of contract.

Preferred convergence check path

Where the host can build a runnable native target, prefer:

scripts/check.sh native-compiled-flow

That command makes the combined path a first-class validation surface instead of a late packaging-only concern.