mirror of
https://github.com/DeNNiiInc/Website-Stress-Test.git
synced 2026-04-17 12:36:00 +00:00
Incorporated BCT branding
This commit is contained in:
390
README.md
Normal file
390
README.md
Normal file
@@ -0,0 +1,390 @@
|
|||||||
|
# Website Stress Testing Tool - Enhanced Edition
|
||||||
|
|
||||||
|
A professional stress testing application that simulates realistic traffic patterns to test production websites with support for 1-5000 concurrent users. Now with **Website Crawler** for realistic user simulation!
|
||||||
|
|
||||||
|
## 🚀 Features
|
||||||
|
|
||||||
|
### Core Testing
|
||||||
|
- **Concurrent Users**: Simulate 1-5000 users simultaneously
|
||||||
|
- **Traffic Patterns**: Steady, Burst, Ramp-Up, and Random patterns
|
||||||
|
- **🕷️ Website Crawler**: NEW! Randomly navigate through website links like real users
|
||||||
|
- **Real-Time Monitoring**: Live statistics and interactive charts
|
||||||
|
- **CORS Proxy**: Bypass browser CORS restrictions with user agent rotation
|
||||||
|
|
||||||
|
### Advanced Metrics
|
||||||
|
- **Percentile Analysis**: P50, P95, and P99 response times
|
||||||
|
- **Error Categorization**: Track 4xx, 5xx, timeout, and network errors separately
|
||||||
|
- **Bandwidth Tracking**: Monitor total data sent and received
|
||||||
|
- **Request History**: Live log of last 100 requests with filtering
|
||||||
|
|
||||||
|
### User Experience
|
||||||
|
- **🌓 Theme Toggle**: Switch between dark and light modes
|
||||||
|
- **⚡ Test Presets**: Quick-load configurations (Light, Medium, Heavy, Spike)
|
||||||
|
- **💾 Save Configurations**: Save and reload custom test setups
|
||||||
|
- **⌨️ Keyboard Shortcuts**: S=Start, P=Pause, X=Stop
|
||||||
|
- **📱 Mobile Responsive**: Works great on all devices
|
||||||
|
- **Export Results**: JSON and CSV export functionality
|
||||||
|
|
||||||
|
### Premium UI
|
||||||
|
- Modern dark/light theme with glassmorphism effects
|
||||||
|
- Real-time charts with Chart.js
|
||||||
|
- Smooth animations and transitions
|
||||||
|
- Professional color-coded statistics
|
||||||
|
|
||||||
|
## 📋 Prerequisites
|
||||||
|
|
||||||
|
- **Node.js** (v14 or higher) - Required for the CORS proxy server
|
||||||
|
- **Modern Web Browser** (Chrome, Firefox, Edge, Safari)
|
||||||
|
|
||||||
|
## 🛠️ Setup Instructions
|
||||||
|
|
||||||
|
### Step 1: Install Node.js
|
||||||
|
|
||||||
|
If you don't have Node.js installed:
|
||||||
|
|
||||||
|
**Windows:**
|
||||||
|
```powershell
|
||||||
|
# Using Chocolatey
|
||||||
|
choco install nodejs
|
||||||
|
|
||||||
|
# Or download from: https://nodejs.org/
|
||||||
|
```
|
||||||
|
|
||||||
|
**macOS:**
|
||||||
|
```bash
|
||||||
|
# Using Homebrew
|
||||||
|
brew install node
|
||||||
|
```
|
||||||
|
|
||||||
|
**Linux:**
|
||||||
|
```bash
|
||||||
|
# Ubuntu/Debian
|
||||||
|
sudo apt install nodejs npm
|
||||||
|
|
||||||
|
# Fedora
|
||||||
|
sudo dnf install nodejs
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 2: Start the CORS Proxy Server
|
||||||
|
|
||||||
|
The proxy server is required to bypass CORS restrictions when testing production websites.
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
# Navigate to the project directory
|
||||||
|
cd "C:\Users\DM\OneDrive - BCT\BCT-YT - Documents\Project-Files\HomeLoan\HTML\StressTest"
|
||||||
|
|
||||||
|
# Start the proxy server
|
||||||
|
node proxy-server.js
|
||||||
|
```
|
||||||
|
|
||||||
|
You should see:
|
||||||
|
```
|
||||||
|
╔════════════════════════════════════════════════════════════╗
|
||||||
|
║ CORS Proxy Server for Stress Testing Tool ║
|
||||||
|
╚════════════════════════════════════════════════════════════╝
|
||||||
|
|
||||||
|
✅ Server running on: http://localhost:3000
|
||||||
|
✅ Max connections: 5000
|
||||||
|
✅ Request timeout: 30000ms
|
||||||
|
```
|
||||||
|
|
||||||
|
**Keep this terminal window open** while using the stress testing tool.
|
||||||
|
|
||||||
|
### Step 3: Open the Stress Testing Tool
|
||||||
|
|
||||||
|
Open `index.html` in your web browser:
|
||||||
|
|
||||||
|
**Option A: Double-click** the `index.html` file
|
||||||
|
|
||||||
|
**Option B: Use a local web server** (recommended)
|
||||||
|
```powershell
|
||||||
|
# In a NEW terminal window (keep proxy running in the first)
|
||||||
|
python -m http.server 8080
|
||||||
|
|
||||||
|
# Then open: http://localhost:8080
|
||||||
|
```
|
||||||
|
|
||||||
|
## 📖 Usage Guide
|
||||||
|
|
||||||
|
### Quick Start with Presets
|
||||||
|
|
||||||
|
1. **Select a Preset**: Choose from Light, Medium, Heavy, or Spike test
|
||||||
|
2. **Enter Target URL**: `https://example.com`
|
||||||
|
3. **Click "Start Test"**: Watch real-time metrics
|
||||||
|
4. **Review Results**: Scroll down after test completes
|
||||||
|
|
||||||
|
### Basic Test
|
||||||
|
|
||||||
|
1. **Enter Target URL**: `https://beyondcloud.solutions/tag/guides/`
|
||||||
|
2. **Set Concurrent Users**: Use the slider (1-5000)
|
||||||
|
3. **Set Duration**: Test duration in seconds (10-600)
|
||||||
|
4. **Select Traffic Pattern**:
|
||||||
|
- **Steady**: Constant requests per second
|
||||||
|
- **Burst**: Traffic spikes at intervals
|
||||||
|
- **Ramp-Up**: Gradual increase in load
|
||||||
|
- **Random**: Realistic user behavior
|
||||||
|
5. **Click "Start Test"**
|
||||||
|
6. **Monitor Live Statistics**: Watch real-time metrics and charts
|
||||||
|
7. **Stop or Wait**: Click "Stop" or let it complete
|
||||||
|
8. **Review Results**: Scroll down to see detailed metrics
|
||||||
|
9. **Export** (optional): Download results as JSON or CSV
|
||||||
|
|
||||||
|
### 🕷️ Crawler Mode (NEW!)
|
||||||
|
|
||||||
|
Simulate real users by randomly navigating through website links:
|
||||||
|
|
||||||
|
1. **Enable Crawler Mode**: Check the "Enable Crawler Mode" checkbox
|
||||||
|
2. **Set Crawl Depth**: How many page hops per user (1-5)
|
||||||
|
3. **Set Links Per Page**: Maximum links to extract (1-50)
|
||||||
|
4. **Start Test**: Users will randomly click links and navigate the site
|
||||||
|
5. **Monitor**: Watch the Request History to see different URLs being visited
|
||||||
|
|
||||||
|
**How it works:**
|
||||||
|
- Extracts links from HTML responses
|
||||||
|
- Randomly selects links from the same domain
|
||||||
|
- Simulates realistic browsing behavior
|
||||||
|
- Tracks unique URLs visited
|
||||||
|
|
||||||
|
### Advanced Options
|
||||||
|
|
||||||
|
Click "Advanced Options" to configure:
|
||||||
|
|
||||||
|
- **HTTP Method**: GET, POST, PUT, DELETE, PATCH
|
||||||
|
- **Custom Headers**: Add authentication, content-type, etc.
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"Authorization": "Bearer your-token",
|
||||||
|
"Content-Type": "application/json"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- **Request Body**: For POST/PUT requests
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"key": "value"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- **Think Time**: Delay between requests (0-5000ms)
|
||||||
|
|
||||||
|
### Keyboard Shortcuts
|
||||||
|
|
||||||
|
- **S**: Start test
|
||||||
|
- **P**: Pause/Resume test
|
||||||
|
- **X**: Stop test
|
||||||
|
|
||||||
|
### Theme Toggle
|
||||||
|
|
||||||
|
Click the **🌓 Theme** button in the header to switch between dark and light modes. Your preference is saved automatically.
|
||||||
|
|
||||||
|
### Save & Load Configurations
|
||||||
|
|
||||||
|
1. **Configure your test** with desired settings
|
||||||
|
2. **Click "💾 Save Current Config"**
|
||||||
|
3. **Enter a name** for your configuration
|
||||||
|
4. **Reload page** to see it in the presets dropdown
|
||||||
|
5. **Select saved config** to quickly load those settings
|
||||||
|
|
||||||
|
## 📊 Understanding Results
|
||||||
|
|
||||||
|
### Key Metrics
|
||||||
|
|
||||||
|
- **Total Requests**: Number of HTTP requests sent
|
||||||
|
- **Success Rate**: Percentage of successful responses (2xx, 3xx)
|
||||||
|
- **Requests per Second (RPS)**: Average throughput
|
||||||
|
- **Response Time**: Min, Max, Average, P50, P95, P99
|
||||||
|
- **Failed Requests**: Number of errors or timeouts
|
||||||
|
- **Bandwidth**: Total data sent and received
|
||||||
|
|
||||||
|
### Percentiles (NEW!)
|
||||||
|
|
||||||
|
- **P50 (Median)**: 50% of requests were faster than this
|
||||||
|
- **P95**: 95% of requests were faster than this (good for SLAs)
|
||||||
|
- **P99**: 99% of requests were faster than this (catches outliers)
|
||||||
|
|
||||||
|
### Error Breakdown (NEW!)
|
||||||
|
|
||||||
|
- **4xx Errors**: Client errors (bad request, not found, etc.)
|
||||||
|
- **5xx Errors**: Server errors (internal server error, etc.)
|
||||||
|
- **Timeout Errors**: Requests that exceeded timeout limit
|
||||||
|
- **Network Errors**: Connection failures, DNS errors, etc.
|
||||||
|
|
||||||
|
### Charts
|
||||||
|
|
||||||
|
- **RPS Chart**: Shows request rate over time
|
||||||
|
- **Response Time Chart**: Shows latency trends
|
||||||
|
- **User Load vs Error Rate**: Correlates user count with error percentage
|
||||||
|
|
||||||
|
### Request History (NEW!)
|
||||||
|
|
||||||
|
- Live table showing last 100 requests
|
||||||
|
- Color-coded by success/failure
|
||||||
|
- Shows URL, status code, and response time
|
||||||
|
- Auto-scrolls with new requests
|
||||||
|
|
||||||
|
## 🔧 Configuration
|
||||||
|
|
||||||
|
### Changing the Proxy URL
|
||||||
|
|
||||||
|
If you deploy the proxy server to a different location, update the proxy URL in `script.js`:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
this.config = {
|
||||||
|
// ... other config
|
||||||
|
proxyUrl: 'http://your-server:3000' // Change this
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### Deploying to Production
|
||||||
|
|
||||||
|
When hosting on a web server:
|
||||||
|
|
||||||
|
1. **Update proxy server** `allowedOrigins` in `proxy-server.js`:
|
||||||
|
```javascript
|
||||||
|
const CONFIG = {
|
||||||
|
allowedOrigins: 'https://your-domain.com', // Not '*'
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Deploy both files**:
|
||||||
|
- Frontend: `index.html`, `styles.css`, `script.js`
|
||||||
|
- Backend: `proxy-server.js`, `package.json`
|
||||||
|
|
||||||
|
3. **Run proxy server** on your hosting:
|
||||||
|
```bash
|
||||||
|
npm start
|
||||||
|
# or
|
||||||
|
node proxy-server.js
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🎯 Testing Your Website
|
||||||
|
|
||||||
|
### Example: Testing with Crawler Mode
|
||||||
|
|
||||||
|
1. Start proxy server: `node proxy-server.js`
|
||||||
|
2. Open `index.html` in browser
|
||||||
|
3. Enter URL: `https://beyondcloud.solutions`
|
||||||
|
4. Enable Crawler Mode ✅
|
||||||
|
5. Set crawl depth: 2
|
||||||
|
6. Set users: 50
|
||||||
|
7. Set duration: 60 seconds
|
||||||
|
8. Select pattern: Random
|
||||||
|
9. Click "Start Test"
|
||||||
|
10. Watch Request History to see different pages being visited
|
||||||
|
11. Monitor results
|
||||||
|
|
||||||
|
## ⚠️ Important Notes
|
||||||
|
|
||||||
|
### Browser Limitations
|
||||||
|
|
||||||
|
- This tool runs in the browser, which has connection limits
|
||||||
|
- For very high loads (1000+ users), consider server-side tools:
|
||||||
|
- Apache JMeter
|
||||||
|
- k6
|
||||||
|
- Artillery
|
||||||
|
- Gatling
|
||||||
|
|
||||||
|
### CORS Proxy Security
|
||||||
|
|
||||||
|
- **Development**: The proxy allows all origins (`*`)
|
||||||
|
- **Production**: Update `allowedOrigins` to your specific domain
|
||||||
|
- **Never** expose an open proxy to the internet
|
||||||
|
|
||||||
|
### Responsible Testing
|
||||||
|
|
||||||
|
- **Only test websites you own** or have permission to test
|
||||||
|
- **Start with low user counts** to avoid overwhelming servers
|
||||||
|
- **Monitor your target server** during tests
|
||||||
|
- **Be aware** that aggressive testing may trigger rate limiting or security measures
|
||||||
|
- **Crawler mode** generates more requests - use responsibly
|
||||||
|
|
||||||
|
## 🐛 Troubleshooting
|
||||||
|
|
||||||
|
### "All requests are failing"
|
||||||
|
|
||||||
|
**Problem**: CORS proxy not running
|
||||||
|
|
||||||
|
**Solution**: Start the proxy server:
|
||||||
|
```powershell
|
||||||
|
node proxy-server.js
|
||||||
|
```
|
||||||
|
|
||||||
|
### "Connection refused" errors
|
||||||
|
|
||||||
|
**Problem**: Proxy server not accessible
|
||||||
|
|
||||||
|
**Solutions**:
|
||||||
|
1. Check proxy is running on port 3000
|
||||||
|
2. Verify firewall isn't blocking port 3000
|
||||||
|
3. Check `proxyUrl` in `script.js` matches your setup
|
||||||
|
|
||||||
|
### "Request timeout" errors
|
||||||
|
|
||||||
|
**Problem**: Target server is slow or unreachable
|
||||||
|
|
||||||
|
**Solutions**:
|
||||||
|
1. Increase timeout in `proxy-server.js` (line 16)
|
||||||
|
2. Reduce concurrent users
|
||||||
|
3. Increase think time
|
||||||
|
4. Check target URL is accessible
|
||||||
|
|
||||||
|
### Crawler not finding links
|
||||||
|
|
||||||
|
**Problem**: Website uses JavaScript to render links
|
||||||
|
|
||||||
|
**Solutions**:
|
||||||
|
1. Crawler only works with server-rendered HTML
|
||||||
|
2. Try disabling crawler mode for JavaScript-heavy sites
|
||||||
|
3. Consider using headless browser tools for SPA testing
|
||||||
|
|
||||||
|
## 📁 File Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
StressTest/
|
||||||
|
├── index.html # Main application UI (enhanced)
|
||||||
|
├── styles.css # Premium design system (dark/light theme)
|
||||||
|
├── script.js # Frontend logic (with crawler)
|
||||||
|
├── proxy-server.js # CORS proxy backend (enhanced)
|
||||||
|
├── package.json # Node.js configuration
|
||||||
|
└── README.md # This file
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🆕 What's New in Enhanced Edition
|
||||||
|
|
||||||
|
### Version 2.0 Features
|
||||||
|
|
||||||
|
✨ **Website Crawler**: Simulate real user navigation
|
||||||
|
📊 **Percentile Metrics**: P50, P95, P99 response times
|
||||||
|
🔍 **Error Categorization**: Detailed error breakdown
|
||||||
|
📈 **Bandwidth Tracking**: Monitor data usage
|
||||||
|
📝 **Request History**: Live log of recent requests
|
||||||
|
⚡ **Test Presets**: Quick-load common scenarios
|
||||||
|
💾 **Save Configurations**: Persist custom setups
|
||||||
|
🌓 **Theme Toggle**: Dark and light modes
|
||||||
|
⌨️ **Keyboard Shortcuts**: Quick controls
|
||||||
|
🎨 **Enhanced UI**: Improved mobile responsiveness
|
||||||
|
🔄 **User Agent Rotation**: More realistic traffic simulation
|
||||||
|
|
||||||
|
## 🔒 Security Considerations
|
||||||
|
|
||||||
|
1. **Proxy Server**: Restrict `allowedOrigins` in production
|
||||||
|
2. **Rate Limiting**: Consider adding rate limits to the proxy
|
||||||
|
3. **Authentication**: Add auth if exposing publicly
|
||||||
|
4. **Monitoring**: Log requests for security auditing
|
||||||
|
5. **Crawler Mode**: Be mindful of the additional load it generates
|
||||||
|
|
||||||
|
## 📝 License
|
||||||
|
|
||||||
|
MIT License - Feel free to modify and use as needed.
|
||||||
|
|
||||||
|
## 🤝 Support
|
||||||
|
|
||||||
|
For issues or questions:
|
||||||
|
1. Check this README
|
||||||
|
2. Review the browser console for errors
|
||||||
|
3. Check proxy server logs
|
||||||
|
4. Verify target website is accessible
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Happy Stress Testing! 🚀**
|
||||||
|
|
||||||
|
*Enhanced with Website Crawler & Advanced Metrics*
|
||||||
396
index.html
Normal file
396
index.html
Normal file
@@ -0,0 +1,396 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<meta name="description"
|
||||||
|
content="Professional stress testing tool for simulating realistic traffic to production websites">
|
||||||
|
<title>Beyond Cloud Technology - Website Stress Test</title>
|
||||||
|
<link rel="icon" type="image/png" href="Logo.png">
|
||||||
|
<link rel="stylesheet" href="styles.css">
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js"></script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<!-- Header -->
|
||||||
|
<header class="header">
|
||||||
|
<div class="header-content">
|
||||||
|
<h1 class="title">
|
||||||
|
<img src="Logo.png" alt="BCT Logo" class="title-icon">
|
||||||
|
Beyond Cloud Technology - Website Stress Test
|
||||||
|
</h1>
|
||||||
|
<p class="subtitle">Simulate realistic traffic patterns to test your production websites</p>
|
||||||
|
<a href="https://www.youtube.com/@beyondcloudtechnology" target="_blank" rel="noopener noreferrer"
|
||||||
|
class="youtube-link">
|
||||||
|
<svg class="youtube-icon" viewBox="0 0 24 24" fill="currentColor">
|
||||||
|
<path
|
||||||
|
d="M23.498 6.186a3.016 3.016 0 0 0-2.122-2.136C19.505 3.545 12 3.545 12 3.545s-7.505 0-9.377.505A3.017 3.017 0 0 0 .502 6.186C0 8.07 0 12 0 12s0 3.93.502 5.814a3.016 3.016 0 0 0 2.122 2.136c1.871.505 9.376.505 9.376.505s7.505 0 9.377-.505a3.015 3.015 0 0 0 2.122-2.136C24 15.93 24 12 24 12s0-3.93-.502-5.814zM9.545 15.568V8.432L15.818 12l-6.273 3.568z" />
|
||||||
|
</svg>
|
||||||
|
Watch on YouTube @beyondcloudtechnology
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="header-controls">
|
||||||
|
<button type="button" class="btn btn-secondary btn-sm" id="themeToggle" title="Toggle Theme">
|
||||||
|
🌓 Theme
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<!-- Test Presets -->
|
||||||
|
<div class="panel full-width">
|
||||||
|
<div class="panel-header">
|
||||||
|
<div class="panel-icon">⚡</div>
|
||||||
|
<h2 class="panel-title">Quick Start</h2>
|
||||||
|
</div>
|
||||||
|
<div class="preset-controls">
|
||||||
|
<select id="presetSelect" class="form-select">
|
||||||
|
<option value="">Select a preset...</option>
|
||||||
|
<option value="light">🟢 Light Load (10 users, 30s)</option>
|
||||||
|
<option value="medium">🟡 Medium Load (100 users, 60s)</option>
|
||||||
|
<option value="heavy">🔴 Heavy Load (500 users, 120s)</option>
|
||||||
|
<option value="spike">💥 Spike Test (200 users, burst)</option>
|
||||||
|
</select>
|
||||||
|
<button type="button" class="btn btn-secondary" id="saveConfigBtn">💾 Save Current Config</button>
|
||||||
|
</div>
|
||||||
|
<div class="keyboard-shortcuts">
|
||||||
|
<small><strong>Keyboard Shortcuts:</strong> S = Start | P = Pause/Resume | X = Stop</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Main Grid -->
|
||||||
|
<div class="main-grid">
|
||||||
|
<!-- Configuration Panel -->
|
||||||
|
<div class="panel">
|
||||||
|
<div class="panel-header">
|
||||||
|
<div class="panel-icon">⚙️</div>
|
||||||
|
<h2 class="panel-title">Configuration</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<form id="configForm">
|
||||||
|
<!-- Target URL -->
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="form-label" for="targetUrl">Target URL</label>
|
||||||
|
<input type="url" id="targetUrl" class="form-input" placeholder="https://example.com" required>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Number of Users -->
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="form-label" for="userCount">
|
||||||
|
Concurrent Users
|
||||||
|
<span class="range-value" id="userCountValue">100</span>
|
||||||
|
</label>
|
||||||
|
<input type="range" id="userCount" class="form-range" min="1" max="5000" value="100">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Test Duration -->
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="form-label" for="duration">
|
||||||
|
Duration (seconds)
|
||||||
|
<span class="range-value" id="durationValue">60</span>
|
||||||
|
</label>
|
||||||
|
<input type="range" id="duration" class="form-range" min="10" max="600" value="60" step="10">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Traffic Pattern -->
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="form-label" for="trafficPattern">Traffic Pattern</label>
|
||||||
|
<select id="trafficPattern" class="form-select">
|
||||||
|
<option value="steady">Steady Load (Constant RPS)</option>
|
||||||
|
<option value="burst">Burst Mode (Traffic Spikes)</option>
|
||||||
|
<option value="rampup">Ramp-Up (Gradual Increase)</option>
|
||||||
|
<option value="random">Random (Realistic Users)</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Crawler Mode -->
|
||||||
|
<div class="form-group crawler-section">
|
||||||
|
<label class="checkbox-label">
|
||||||
|
<input type="checkbox" id="crawlerEnabled" class="form-checkbox">
|
||||||
|
<span>🕷️ Enable Crawler Mode (Simulate Real Users)</span>
|
||||||
|
</label>
|
||||||
|
<small class="help-text">Randomly navigate through website links like real users</small>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Crawler Settings (shown when enabled) -->
|
||||||
|
<div class="crawler-settings" id="crawlerSettings" style="display: none;">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="form-label" for="crawlDepth">
|
||||||
|
Crawl Depth
|
||||||
|
<span class="range-value" id="crawlDepthValue">2</span>
|
||||||
|
</label>
|
||||||
|
<input type="range" id="crawlDepth" class="form-range" min="1" max="5" value="2">
|
||||||
|
<small class="help-text">Maximum number of page hops per user</small>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="form-label" for="linksPerPage">
|
||||||
|
Links Per Page
|
||||||
|
<span class="range-value" id="linksPerPageValue">10</span>
|
||||||
|
</label>
|
||||||
|
<input type="range" id="linksPerPage" class="form-range" min="1" max="50" value="10">
|
||||||
|
<small class="help-text">Maximum links to extract from each page</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Advanced Options Accordion -->
|
||||||
|
<div class="accordion">
|
||||||
|
<button type="button" class="accordion-header" id="advancedToggle">
|
||||||
|
<span>Advanced Options</span>
|
||||||
|
<span class="accordion-icon">▼</span>
|
||||||
|
</button>
|
||||||
|
<div class="accordion-content" id="advancedContent">
|
||||||
|
<!-- HTTP Method -->
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="form-label" for="httpMethod">HTTP Method</label>
|
||||||
|
<select id="httpMethod" class="form-select">
|
||||||
|
<option value="GET">GET</option>
|
||||||
|
<option value="POST">POST</option>
|
||||||
|
<option value="PUT">PUT</option>
|
||||||
|
<option value="DELETE">DELETE</option>
|
||||||
|
<option value="PATCH">PATCH</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Request Headers -->
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="form-label" for="customHeaders">Custom Headers (JSON)</label>
|
||||||
|
<textarea id="customHeaders" class="form-textarea"
|
||||||
|
placeholder='{"Authorization": "Bearer token", "Content-Type": "application/json"}'></textarea>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Request Body -->
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="form-label" for="requestBody">Request Body (JSON)</label>
|
||||||
|
<textarea id="requestBody" class="form-textarea"
|
||||||
|
placeholder='{"key": "value"}'></textarea>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Think Time -->
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="form-label" for="thinkTime">
|
||||||
|
Think Time (ms)
|
||||||
|
<span class="range-value" id="thinkTimeValue">1000</span>
|
||||||
|
</label>
|
||||||
|
<input type="range" id="thinkTime" class="form-range" min="0" max="5000" value="1000"
|
||||||
|
step="100">
|
||||||
|
<small class="help-text">Delay between requests per user</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Control Panel -->
|
||||||
|
<div class="panel">
|
||||||
|
<div class="panel-header">
|
||||||
|
<div class="panel-icon">🎮</div>
|
||||||
|
<h2 class="panel-title">Control Panel</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Status Badge -->
|
||||||
|
<div class="text-center mb-3">
|
||||||
|
<span class="status-badge status-idle" id="statusBadge">Idle</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Progress Bar -->
|
||||||
|
<div class="progress-container">
|
||||||
|
<div class="progress-bar" id="progressBar" style="width: 0%"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Control Buttons -->
|
||||||
|
<div class="btn-group mt-4">
|
||||||
|
<button type="button" class="btn btn-success" id="startBtn">▶️ Start Test</button>
|
||||||
|
<button type="button" class="btn btn-warning" id="pauseBtn" disabled>⏸️ Pause</button>
|
||||||
|
<button type="button" class="btn btn-danger" id="stopBtn" disabled>⏹️ Stop</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Quick Stats -->
|
||||||
|
<div class="stats-grid mt-4">
|
||||||
|
<div class="stat-card">
|
||||||
|
<div class="stat-label">Elapsed Time</div>
|
||||||
|
<div class="stat-value" id="elapsedTime">0s</div>
|
||||||
|
</div>
|
||||||
|
<div class="stat-card">
|
||||||
|
<div class="stat-label">Remaining</div>
|
||||||
|
<div class="stat-value" id="remainingTime">0s</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Live Statistics -->
|
||||||
|
<div class="panel full-width">
|
||||||
|
<div class="panel-header">
|
||||||
|
<div class="panel-icon">📊</div>
|
||||||
|
<h2 class="panel-title">Live Statistics</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="stats-grid">
|
||||||
|
<div class="stat-card">
|
||||||
|
<div class="stat-label">Active Users</div>
|
||||||
|
<div class="stat-value info" id="activeUsers">0</div>
|
||||||
|
</div>
|
||||||
|
<div class="stat-card">
|
||||||
|
<div class="stat-label">Total Requests</div>
|
||||||
|
<div class="stat-value" id="totalRequests">0</div>
|
||||||
|
</div>
|
||||||
|
<div class="stat-card">
|
||||||
|
<div class="stat-label">Requests/Sec</div>
|
||||||
|
<div class="stat-value info" id="requestsPerSec">0</div>
|
||||||
|
</div>
|
||||||
|
<div class="stat-card">
|
||||||
|
<div class="stat-label">Success Rate</div>
|
||||||
|
<div class="stat-value success" id="successRate">0%</div>
|
||||||
|
</div>
|
||||||
|
<div class="stat-card">
|
||||||
|
<div class="stat-label">Failed Requests</div>
|
||||||
|
<div class="stat-value danger" id="failedRequests">0</div>
|
||||||
|
</div>
|
||||||
|
<div class="stat-card">
|
||||||
|
<div class="stat-label">Avg Response Time</div>
|
||||||
|
<div class="stat-value warning" id="avgResponseTime">0ms</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Percentile Metrics -->
|
||||||
|
<div class="panel-section mt-4">
|
||||||
|
<h3 class="section-title">Response Time Percentiles</h3>
|
||||||
|
<div class="stats-grid">
|
||||||
|
<div class="stat-card">
|
||||||
|
<div class="stat-label">P50 (Median)</div>
|
||||||
|
<div class="stat-value info" id="p50ResponseTime">0ms</div>
|
||||||
|
</div>
|
||||||
|
<div class="stat-card">
|
||||||
|
<div class="stat-label">P95</div>
|
||||||
|
<div class="stat-value warning" id="p95ResponseTime">0ms</div>
|
||||||
|
</div>
|
||||||
|
<div class="stat-card">
|
||||||
|
<div class="stat-label">P99</div>
|
||||||
|
<div class="stat-value danger" id="p99ResponseTime">0ms</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Error Breakdown -->
|
||||||
|
<div class="panel-section mt-4">
|
||||||
|
<h3 class="section-title">Error Breakdown</h3>
|
||||||
|
<div class="stats-grid">
|
||||||
|
<div class="stat-card">
|
||||||
|
<div class="stat-label">4xx Errors</div>
|
||||||
|
<div class="stat-value warning" id="errors4xx">0</div>
|
||||||
|
</div>
|
||||||
|
<div class="stat-card">
|
||||||
|
<div class="stat-label">5xx Errors</div>
|
||||||
|
<div class="stat-value danger" id="errors5xx">0</div>
|
||||||
|
</div>
|
||||||
|
<div class="stat-card">
|
||||||
|
<div class="stat-label">Timeout Errors</div>
|
||||||
|
<div class="stat-value danger" id="errorsTimeout">0</div>
|
||||||
|
</div>
|
||||||
|
<div class="stat-card">
|
||||||
|
<div class="stat-label">Network Errors</div>
|
||||||
|
<div class="stat-value danger" id="errorsNetwork">0</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Bandwidth -->
|
||||||
|
<div class="panel-section mt-4">
|
||||||
|
<h3 class="section-title">Bandwidth Usage</h3>
|
||||||
|
<div class="stat-card-large">
|
||||||
|
<div class="stat-label">Total Bandwidth</div>
|
||||||
|
<div class="stat-value info" id="totalBandwidth">0 B</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Charts -->
|
||||||
|
<div class="main-grid mt-4">
|
||||||
|
<div class="chart-container">
|
||||||
|
<canvas id="rpsChart"></canvas>
|
||||||
|
</div>
|
||||||
|
<div class="chart-container">
|
||||||
|
<canvas id="responseTimeChart"></canvas>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- User/Error Correlation Chart (Full Width) -->
|
||||||
|
<div class="chart-container" style="height: 350px; margin-top: var(--spacing-lg);">
|
||||||
|
<canvas id="userErrorChart"></canvas>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Request History Log -->
|
||||||
|
<div class="panel full-width">
|
||||||
|
<div class="panel-header">
|
||||||
|
<div class="panel-icon">📝</div>
|
||||||
|
<h2 class="panel-title">Request History (Last 100)</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="request-history-container">
|
||||||
|
<table class="request-history-table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Time</th>
|
||||||
|
<th>URL</th>
|
||||||
|
<th>Status</th>
|
||||||
|
<th>Response Time</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="requestHistoryBody">
|
||||||
|
<!-- Populated dynamically -->
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Results Panel -->
|
||||||
|
<div class="panel full-width" id="resultsPanel" style="display: none;">
|
||||||
|
<div class="panel-header">
|
||||||
|
<div class="panel-icon">📈</div>
|
||||||
|
<h2 class="panel-title">Test Results</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="btn-group mb-3">
|
||||||
|
<button type="button" class="btn btn-primary" id="exportJsonBtn">💾 Export as JSON</button>
|
||||||
|
<button type="button" class="btn btn-primary" id="exportCsvBtn">📄 Export as CSV</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<table class="results-table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Metric</th>
|
||||||
|
<th>Value</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="resultsTableBody">
|
||||||
|
<!-- Results will be populated here -->
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<div id="detailedResults" class="mt-4"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<footer class="footer">
|
||||||
|
<p>© 2025 Beyond Cloud Technology. All rights reserved.</p>
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
<script src="script.js"></script>
|
||||||
|
<script>
|
||||||
|
// Show/hide crawler settings based on checkbox
|
||||||
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
const crawlerCheckbox = document.getElementById('crawlerEnabled');
|
||||||
|
const crawlerSettings = document.getElementById('crawlerSettings');
|
||||||
|
|
||||||
|
if (crawlerCheckbox && crawlerSettings) {
|
||||||
|
crawlerCheckbox.addEventListener('change', (e) => {
|
||||||
|
crawlerSettings.style.display = e.target.checked ? 'block' : 'none';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
17
package.json
Normal file
17
package.json
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"name": "stress-testing-tool",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "Website stress testing tool with CORS proxy",
|
||||||
|
"main": "proxy-server.js",
|
||||||
|
"scripts": {
|
||||||
|
"start": "node proxy-server.js",
|
||||||
|
"proxy": "node proxy-server.js"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"stress-testing",
|
||||||
|
"load-testing",
|
||||||
|
"cors-proxy"
|
||||||
|
],
|
||||||
|
"author": "",
|
||||||
|
"license": "MIT"
|
||||||
|
}
|
||||||
242
proxy-server.js
Normal file
242
proxy-server.js
Normal file
@@ -0,0 +1,242 @@
|
|||||||
|
// ===================================
|
||||||
|
// CORS PROXY SERVER
|
||||||
|
// ===================================
|
||||||
|
// This proxy server allows the stress testing tool to test
|
||||||
|
// production websites without CORS restrictions.
|
||||||
|
|
||||||
|
const http = require('http');
|
||||||
|
const https = require('https');
|
||||||
|
const url = require('url');
|
||||||
|
|
||||||
|
const PORT = 3000;
|
||||||
|
|
||||||
|
// Configuration
|
||||||
|
const CONFIG = {
|
||||||
|
// Maximum request timeout (30 seconds)
|
||||||
|
timeout: 30000,
|
||||||
|
|
||||||
|
// Allowed origins (restrict to your stress testing tool's domain)
|
||||||
|
// Use '*' for development, specific domain for production
|
||||||
|
allowedOrigins: '*',
|
||||||
|
|
||||||
|
// Maximum concurrent connections
|
||||||
|
maxConnections: 5000,
|
||||||
|
|
||||||
|
// User agents for rotation
|
||||||
|
userAgents: [
|
||||||
|
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
|
||||||
|
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
|
||||||
|
'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:121.0) Gecko/20100101 Firefox/121.0',
|
||||||
|
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.1 Safari/605.1.15',
|
||||||
|
'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get random user agent
|
||||||
|
function getRandomUserAgent() {
|
||||||
|
return CONFIG.userAgents[Math.floor(Math.random() * CONFIG.userAgents.length)];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the proxy server
|
||||||
|
const server = http.createServer((req, res) => {
|
||||||
|
// Handle CORS preflight requests
|
||||||
|
if (req.method === 'OPTIONS') {
|
||||||
|
handleCORS(res);
|
||||||
|
res.writeHead(200);
|
||||||
|
res.end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only allow POST requests to the proxy
|
||||||
|
if (req.method !== 'POST') {
|
||||||
|
res.writeHead(405, { 'Content-Type': 'application/json' });
|
||||||
|
res.end(JSON.stringify({ error: 'Method not allowed. Use POST.' }));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse request body
|
||||||
|
let body = '';
|
||||||
|
req.on('data', chunk => {
|
||||||
|
body += chunk.toString();
|
||||||
|
});
|
||||||
|
|
||||||
|
req.on('end', () => {
|
||||||
|
try {
|
||||||
|
const proxyRequest = JSON.parse(body);
|
||||||
|
handleProxyRequest(proxyRequest, res);
|
||||||
|
} catch (error) {
|
||||||
|
res.writeHead(400, { 'Content-Type': 'application/json' });
|
||||||
|
res.end(JSON.stringify({
|
||||||
|
error: 'Invalid JSON',
|
||||||
|
message: error.message
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Handle the actual proxy request
|
||||||
|
function handleProxyRequest(proxyRequest, clientRes) {
|
||||||
|
const { targetUrl, method = 'GET', headers = {}, body = null } = proxyRequest;
|
||||||
|
|
||||||
|
// Validate target URL
|
||||||
|
if (!targetUrl) {
|
||||||
|
clientRes.writeHead(400, { 'Content-Type': 'application/json' });
|
||||||
|
clientRes.end(JSON.stringify({ error: 'targetUrl is required' }));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let parsedUrl;
|
||||||
|
try {
|
||||||
|
parsedUrl = new URL(targetUrl);
|
||||||
|
} catch (error) {
|
||||||
|
clientRes.writeHead(400, { 'Content-Type': 'application/json' });
|
||||||
|
clientRes.end(JSON.stringify({ error: 'Invalid URL' }));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine if we need http or https
|
||||||
|
const protocol = parsedUrl.protocol === 'https:' ? https : http;
|
||||||
|
|
||||||
|
// Prepare request options with random user agent
|
||||||
|
const options = {
|
||||||
|
hostname: parsedUrl.hostname,
|
||||||
|
port: parsedUrl.port,
|
||||||
|
path: parsedUrl.pathname + parsedUrl.search,
|
||||||
|
method: method,
|
||||||
|
headers: {
|
||||||
|
...headers,
|
||||||
|
'User-Agent': getRandomUserAgent(),
|
||||||
|
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
|
||||||
|
'Accept-Language': 'en-US,en;q=0.5',
|
||||||
|
'Accept-Encoding': 'gzip, deflate, br',
|
||||||
|
'DNT': '1',
|
||||||
|
'Connection': 'keep-alive',
|
||||||
|
'Upgrade-Insecure-Requests': '1'
|
||||||
|
},
|
||||||
|
timeout: CONFIG.timeout
|
||||||
|
};
|
||||||
|
|
||||||
|
const startTime = Date.now();
|
||||||
|
|
||||||
|
// Make the request to the target server
|
||||||
|
const proxyReq = protocol.request(options, (proxyRes) => {
|
||||||
|
const responseTime = Date.now() - startTime;
|
||||||
|
|
||||||
|
// Collect response data
|
||||||
|
let responseData = '';
|
||||||
|
let responseSize = 0;
|
||||||
|
const maxBodySize = 500000; // 500KB limit for crawler
|
||||||
|
|
||||||
|
proxyRes.on('data', chunk => {
|
||||||
|
responseSize += chunk.length;
|
||||||
|
// Only collect body if under size limit (for crawler)
|
||||||
|
if (responseSize < maxBodySize) {
|
||||||
|
responseData += chunk.toString();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
proxyRes.on('end', () => {
|
||||||
|
// Send response back to client with CORS headers
|
||||||
|
handleCORS(clientRes);
|
||||||
|
clientRes.writeHead(200, { 'Content-Type': 'application/json' });
|
||||||
|
|
||||||
|
clientRes.end(JSON.stringify({
|
||||||
|
success: true,
|
||||||
|
statusCode: proxyRes.statusCode,
|
||||||
|
statusMessage: proxyRes.statusMessage,
|
||||||
|
responseTime: responseTime,
|
||||||
|
headers: proxyRes.headers,
|
||||||
|
body: responseData, // Full body for crawler link extraction
|
||||||
|
bodySize: responseSize
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Handle request errors
|
||||||
|
proxyReq.on('error', (error) => {
|
||||||
|
const responseTime = Date.now() - startTime;
|
||||||
|
|
||||||
|
handleCORS(clientRes);
|
||||||
|
clientRes.writeHead(200, { 'Content-Type': 'application/json' });
|
||||||
|
|
||||||
|
clientRes.end(JSON.stringify({
|
||||||
|
success: false,
|
||||||
|
error: error.message,
|
||||||
|
responseTime: responseTime,
|
||||||
|
statusCode: 0
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
|
||||||
|
// Handle timeout
|
||||||
|
proxyReq.on('timeout', () => {
|
||||||
|
proxyReq.destroy();
|
||||||
|
const responseTime = Date.now() - startTime;
|
||||||
|
|
||||||
|
handleCORS(clientRes);
|
||||||
|
clientRes.writeHead(200, { 'Content-Type': 'application/json' });
|
||||||
|
|
||||||
|
clientRes.end(JSON.stringify({
|
||||||
|
success: false,
|
||||||
|
error: 'Request timeout',
|
||||||
|
responseTime: responseTime,
|
||||||
|
statusCode: 0
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
|
||||||
|
// Send request body if present
|
||||||
|
if (body && method !== 'GET' && method !== 'HEAD') {
|
||||||
|
proxyReq.write(typeof body === 'string' ? body : JSON.stringify(body));
|
||||||
|
}
|
||||||
|
|
||||||
|
proxyReq.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add CORS headers to response
|
||||||
|
function handleCORS(res) {
|
||||||
|
res.setHeader('Access-Control-Allow-Origin', CONFIG.allowedOrigins);
|
||||||
|
res.setHeader('Access-Control-Allow-Methods', 'POST, OPTIONS');
|
||||||
|
res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start the server
|
||||||
|
server.listen(PORT, () => {
|
||||||
|
console.log(`
|
||||||
|
╔════════════════════════════════════════════════════════════╗
|
||||||
|
║ CORS Proxy Server for Stress Testing Tool ║
|
||||||
|
╚════════════════════════════════════════════════════════════╝
|
||||||
|
|
||||||
|
✅ Server running on: http://localhost:${PORT}
|
||||||
|
✅ Max connections: ${CONFIG.maxConnections}
|
||||||
|
✅ Request timeout: ${CONFIG.timeout}ms
|
||||||
|
|
||||||
|
📝 Usage:
|
||||||
|
POST to http://localhost:${PORT} with JSON body:
|
||||||
|
{
|
||||||
|
"targetUrl": "https://example.com",
|
||||||
|
"method": "GET",
|
||||||
|
"headers": {},
|
||||||
|
"body": null
|
||||||
|
}
|
||||||
|
|
||||||
|
🔒 Security Note:
|
||||||
|
For production, update CONFIG.allowedOrigins to your
|
||||||
|
stress testing tool's domain (not '*')
|
||||||
|
|
||||||
|
Press Ctrl+C to stop the server
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Handle server errors
|
||||||
|
server.on('error', (error) => {
|
||||||
|
console.error('❌ Server error:', error.message);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Graceful shutdown
|
||||||
|
process.on('SIGINT', () => {
|
||||||
|
console.log('\n\n🛑 Shutting down proxy server...');
|
||||||
|
server.close(() => {
|
||||||
|
console.log('✅ Server closed');
|
||||||
|
process.exit(0);
|
||||||
|
});
|
||||||
|
});
|
||||||
1046
styles.css
Normal file
1046
styles.css
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user