router_local_http.sh 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. #!/bin/sh
  2. set -eu
  3. SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
  4. APP_DIR=$(CDPATH= cd -- "$SCRIPT_DIR/.." && pwd)
  5. CONFIG_PATH=${1:-"$APP_DIR/router_local.conf"}
  6. if [ ! -r "$CONFIG_PATH" ]; then
  7. echo "[router-http] config not found: $CONFIG_PATH" >&2
  8. exit 1
  9. fi
  10. # shellcheck disable=SC1090
  11. . "$CONFIG_PATH"
  12. RUNTIME_DIR=${RUNTIME_DIR:-"$APP_DIR/cfip_runtime"}
  13. VALUE_TEXT_FILE=${VALUE_TEXT_FILE:-"current_ip.txt"}
  14. VALUE_JSON_FILE=${VALUE_JSON_FILE:-"current_ip.json"}
  15. STATE_FILE=${STATE_FILE:-"state.json"}
  16. EXPORT_VARS_FILE=${EXPORT_VARS_FILE:-"substore_vars.json"}
  17. HTTP_PORT=${HTTP_PORT:-8080}
  18. TEXT_PATH="$RUNTIME_DIR/$VALUE_TEXT_FILE"
  19. JSON_PATH="$RUNTIME_DIR/$VALUE_JSON_FILE"
  20. STATE_PATH="$RUNTIME_DIR/$STATE_FILE"
  21. EXPORT_PATH="$RUNTIME_DIR/$EXPORT_VARS_FILE"
  22. TMP_BASE=${TMPDIR:-/tmp}
  23. nc_listen() {
  24. if nc -h 2>&1 | grep -qi 'busybox'; then
  25. nc -l -p "$HTTP_PORT"
  26. else
  27. nc -l "$HTTP_PORT"
  28. fi
  29. }
  30. serve_once() {
  31. req_fifo="$TMP_BASE/router_http_req.$$"
  32. resp_fifo="$TMP_BASE/router_http_resp.$$"
  33. rm -f "$req_fifo" "$resp_fifo"
  34. mkfifo "$req_fifo" "$resp_fifo"
  35. cat "$resp_fifo" | nc_listen > "$req_fifo" 2>/dev/null &
  36. nc_pid=$!
  37. sleep 1
  38. if ! kill -0 "$nc_pid" 2>/dev/null; then
  39. rm -f "$req_fifo" "$resp_fifo"
  40. echo "[router-http] nc listen failed on port $HTTP_PORT" >&2
  41. return 1
  42. fi
  43. exec 3<"$req_fifo"
  44. exec 4>"$resp_fifo"
  45. if ! IFS= read -r request_line <&3; then
  46. exec 3<&-
  47. exec 4>&-
  48. wait "$nc_pid" 2>/dev/null || true
  49. rm -f "$req_fifo" "$resp_fifo"
  50. return 0
  51. fi
  52. while IFS= read -r header_line <&3; do
  53. [ "$header_line" = "$(printf '\r')" ] && break
  54. [ -z "$header_line" ] && break
  55. done
  56. request_path=$(printf '%s' "$request_line" | awk '{print $2}')
  57. status_line="HTTP/1.1 200 OK\r"
  58. content_type="text/plain; charset=utf-8"
  59. file_path="$TEXT_PATH"
  60. case "$request_path" in
  61. /|/current_ip.txt|"/$VALUE_TEXT_FILE")
  62. content_type="text/plain; charset=utf-8"
  63. file_path="$TEXT_PATH"
  64. ;;
  65. /current_ip.json|"/$VALUE_JSON_FILE")
  66. content_type="application/json; charset=utf-8"
  67. file_path="$JSON_PATH"
  68. ;;
  69. /state.json|"/$STATE_FILE")
  70. content_type="application/json; charset=utf-8"
  71. file_path="$STATE_PATH"
  72. ;;
  73. /substore_vars.json|"/$EXPORT_VARS_FILE")
  74. content_type="application/json; charset=utf-8"
  75. file_path="$EXPORT_PATH"
  76. ;;
  77. *)
  78. status_line="HTTP/1.1 404 Not Found\r"
  79. file_path=""
  80. ;;
  81. esac
  82. if [ -n "$file_path" ] && [ -f "$file_path" ]; then
  83. content_length=$(wc -c < "$file_path" | tr -d ' ')
  84. printf '%b\n' "$status_line" >&4
  85. printf 'Content-Type: %s\r\n' "$content_type" >&4
  86. printf 'Content-Length: %s\r\n' "$content_length" >&4
  87. printf 'Connection: close\r\n' >&4
  88. printf '\r\n' >&4
  89. cat "$file_path" >&4
  90. else
  91. body='not found'
  92. printf '%b\n' "$status_line" >&4
  93. printf 'Content-Type: text/plain; charset=utf-8\r\n' >&4
  94. printf 'Content-Length: %s\r\n' "$(printf '%s' "$body" | wc -c | tr -d ' ')" >&4
  95. printf 'Connection: close\r\n' >&4
  96. printf '\r\n' >&4
  97. printf '%s' "$body" >&4
  98. fi
  99. exec 3<&-
  100. exec 4>&-
  101. wait "$nc_pid" 2>/dev/null || true
  102. rm -f "$req_fifo" "$resp_fifo"
  103. }
  104. echo "[router-http] listening on 0.0.0.0:$HTTP_PORT"
  105. while true; do
  106. if ! serve_once; then
  107. exit 1
  108. fi
  109. done