|
#!/bin/bash
|
|
|
|
# Test script for verifying proxy routing behavior
|
|
# Ensures /dashboard and /api/stats are always handled internally
|
|
|
|
PORT=8080
|
|
TEST_UPSTREAM_PORT=3000
|
|
|
|
echo "=== Proxy Routing Test Suite ==="
|
|
echo "================================"
|
|
|
|
# Start a simple upstream server that logs all requests
|
|
echo "Starting test upstream server on port $TEST_UPSTREAM_PORT..."
|
|
cat > test_upstream.py << 'EOF'
|
|
from http.server import HTTPServer, BaseHTTPRequestHandler
|
|
import json
|
|
import datetime
|
|
|
|
class TestHandler(BaseHTTPRequestHandler):
|
|
def do_GET(self):
|
|
print(f"[{datetime.datetime.now()}] UPSTREAM RECEIVED: {self.command} {self.path}")
|
|
if self.path == "/dashboard" or self.path == "/api/stats":
|
|
print("ERROR: Internal route leaked to upstream!")
|
|
self.send_response(200)
|
|
self.send_header('Content-Type', 'application/json')
|
|
self.end_headers()
|
|
response = {"upstream": "response", "path": self.path}
|
|
self.wfile.write(json.dumps(response).encode())
|
|
|
|
def do_POST(self):
|
|
self.do_GET()
|
|
|
|
def log_message(self, format, *args):
|
|
return # Suppress default logging
|
|
|
|
if __name__ == "__main__":
|
|
server = HTTPServer(('localhost', 3000), TestHandler)
|
|
print("Test upstream server running on port 3000")
|
|
server.serve_forever()
|
|
EOF
|
|
|
|
python3 test_upstream.py &
|
|
UPSTREAM_PID=$!
|
|
sleep 2
|
|
|
|
# Start the proxy with debug mode
|
|
echo "Starting proxy server..."
|
|
DEBUG=1 ./rproxy proxy_config.json &
|
|
PROXY_PID=$!
|
|
sleep 3
|
|
|
|
echo ""
|
|
echo "=== Test 1: Direct dashboard access ==="
|
|
echo "Request: GET /dashboard"
|
|
response=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:$PORT/dashboard)
|
|
if [ "$response" = "200" ]; then
|
|
echo "✓ Dashboard served correctly (HTTP $response)"
|
|
else
|
|
echo "✗ Dashboard failed (HTTP $response)"
|
|
fi
|
|
|
|
echo ""
|
|
echo "=== Test 2: Direct API stats access ==="
|
|
echo "Request: GET /api/stats"
|
|
response=$(curl -s http://localhost:$PORT/api/stats | jq -r '.current' 2>/dev/null)
|
|
if [ ! -z "$response" ]; then
|
|
echo "✓ API stats served correctly"
|
|
else
|
|
echo "✗ API stats failed"
|
|
fi
|
|
|
|
echo ""
|
|
echo "=== Test 3: Multiple requests on same connection (keep-alive) ==="
|
|
echo "Testing pipeline: /api/stats -> /test -> /dashboard -> /another"
|
|
cat > test_requests.txt << 'EOF'
|
|
GET /api/stats HTTP/1.1
|
|
Host: localhost
|
|
Connection: keep-alive
|
|
|
|
GET /test HTTP/1.1
|
|
Host: localhost
|
|
Connection: keep-alive
|
|
|
|
GET /dashboard HTTP/1.1
|
|
Host: localhost
|
|
Connection: keep-alive
|
|
|
|
GET /another HTTP/1.1
|
|
Host: localhost
|
|
Connection: close
|
|
|
|
EOF
|
|
|
|
# Send pipelined requests
|
|
(cat test_requests.txt; sleep 1) | nc localhost $PORT > test_response.txt 2>&1
|
|
|
|
# Check if internal routes were handled correctly
|
|
if grep -q "cpu_percent" test_response.txt && grep -q "Reverse Proxy Monitor" test_response.txt; then
|
|
echo "✓ Internal routes handled correctly in pipeline"
|
|
else
|
|
echo "✗ Internal routes not handled correctly in pipeline"
|
|
fi
|
|
|
|
echo ""
|
|
echo "=== Test 4: Concurrent connections ==="
|
|
echo "Sending 10 concurrent requests to different endpoints..."
|
|
|
|
# Background requests
|
|
for i in {1..3}; do
|
|
curl -s http://localhost:$PORT/dashboard > /dev/null &
|
|
done
|
|
for i in {1..3}; do
|
|
curl -s http://localhost:$PORT/api/stats > /dev/null &
|
|
done
|
|
for i in {1..4}; do
|
|
curl -s http://localhost:$PORT/test$i > /dev/null &
|
|
done
|
|
|
|
wait
|
|
|
|
echo "✓ Concurrent requests completed"
|
|
|
|
echo ""
|
|
echo "=== Test 5: Rapid sequential requests ==="
|
|
echo "Sending rapid requests to verify state management..."
|
|
|
|
success=0
|
|
failed=0
|
|
|
|
for i in {1..20}; do
|
|
# Alternate between internal and forwarded routes
|
|
if [ $((i % 3)) -eq 0 ]; then
|
|
response=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:$PORT/dashboard)
|
|
if [ "$response" = "200" ]; then
|
|
((success++))
|
|
else
|
|
((failed++))
|
|
echo " ✗ Dashboard request $i failed (HTTP $response)"
|
|
fi
|
|
elif [ $((i % 3)) -eq 1 ]; then
|
|
response=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:$PORT/api/stats)
|
|
if [ "$response" = "200" ]; then
|
|
((success++))
|
|
else
|
|
((failed++))
|
|
echo " ✗ API stats request $i failed (HTTP $response)"
|
|
fi
|
|
else
|
|
response=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:$PORT/test$i)
|
|
if [ "$response" = "200" ]; then
|
|
((success++))
|
|
else
|
|
((failed++))
|
|
fi
|
|
fi
|
|
done
|
|
|
|
echo "Results: $success successful, $failed failed"
|
|
if [ $failed -eq 0 ]; then
|
|
echo "✓ All rapid requests handled correctly"
|
|
else
|
|
echo "✗ Some requests failed"
|
|
fi
|
|
|
|
echo ""
|
|
echo "=== Test 6: WebSocket upgrade after regular request ==="
|
|
echo "Testing state reset after WebSocket..."
|
|
|
|
# First a normal request
|
|
curl -s http://localhost:$PORT/api/stats > /dev/null
|
|
echo "✓ Normal request sent"
|
|
|
|
# Then attempt WebSocket (will fail but tests state handling)
|
|
curl -s -H "Upgrade: websocket" -H "Connection: upgrade" http://localhost:$PORT/ws 2>/dev/null
|
|
echo "✓ WebSocket attempt sent"
|
|
|
|
# Then another normal request to internal route
|
|
response=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:$PORT/dashboard)
|
|
if [ "$response" = "200" ]; then
|
|
echo "✓ Dashboard works after WebSocket attempt"
|
|
else
|
|
echo "✗ Dashboard failed after WebSocket attempt (HTTP $response)"
|
|
fi
|
|
|
|
echo ""
|
|
echo "=== Checking upstream server logs ==="
|
|
echo "Verifying no internal routes leaked to upstream..."
|
|
sleep 1
|
|
|
|
# The upstream server prints errors if it receives internal routes
|
|
# Check proxy debug logs for routing decisions
|
|
echo ""
|
|
echo "Recent routing decisions from proxy logs:"
|
|
echo "(Last 10 routing log entries)"
|
|
echo "----------------------------------------"
|
|
|
|
# Kill the servers
|
|
kill $PROXY_PID 2>/dev/null
|
|
kill $UPSTREAM_PID 2>/dev/null
|
|
|
|
# Clean up
|
|
rm -f test_upstream.py test_requests.txt test_response.txt
|
|
|
|
echo ""
|
|
echo "=== Test Complete ==="
|
|
echo "If you see any 'ERROR: Internal route leaked to upstream!' messages above,"
|
|
echo "the routing issue is NOT fixed. Otherwise, the fix is working correctly." |