764 lines
25 KiB
Markdown
764 lines
25 KiB
Markdown
# SmartProxy Simplification Plan: Unify Action Types
|
|
|
|
## Summary
|
|
Complete removal of 'redirect', 'block', and 'static' action types, leaving only 'forward' and 'socket-handler'. All old code will be deleted entirely - no migration paths or backwards compatibility. Socket handlers will be enhanced to receive IRouteContext as a second parameter.
|
|
|
|
## Goal
|
|
Create a dramatically simpler SmartProxy with only two action types, where everything is either proxied (forward) or handled by custom code (socket-handler).
|
|
|
|
## Current State
|
|
```typescript
|
|
export type TRouteActionType = 'forward' | 'redirect' | 'block' | 'static' | 'socket-handler';
|
|
export type TSocketHandler = (socket: plugins.net.Socket) => void | Promise<void>;
|
|
```
|
|
|
|
## Target State
|
|
```typescript
|
|
export type TRouteActionType = 'forward' | 'socket-handler';
|
|
export type TSocketHandler = (socket: plugins.net.Socket, context: IRouteContext) => void | Promise<void>;
|
|
```
|
|
|
|
## Benefits
|
|
1. **Simpler API** - Only two action types to understand
|
|
2. **Unified handling** - Everything is either forwarding or custom socket handling
|
|
3. **More flexible** - Socket handlers can do anything the old types did and more
|
|
4. **Less code** - Remove specialized handlers and their dependencies
|
|
5. **Context aware** - Socket handlers get access to route context (domain, port, clientIp, etc.)
|
|
6. **Clean codebase** - No legacy code or migration paths
|
|
|
|
---
|
|
|
|
## Phase 1: Code to Remove
|
|
|
|
### 1.1 Action Type Handlers
|
|
- `RouteConnectionHandler.handleRedirectAction()`
|
|
- `RouteConnectionHandler.handleBlockAction()`
|
|
- `RouteConnectionHandler.handleStaticAction()`
|
|
|
|
### 1.2 Handler Classes
|
|
- `RedirectHandler` class (http-proxy/handlers/)
|
|
- `StaticHandler` class (http-proxy/handlers/)
|
|
|
|
### 1.3 Type Definitions
|
|
- 'redirect', 'block', 'static' from TRouteActionType
|
|
- IRouteRedirect interface
|
|
- IRouteStatic interface
|
|
- Related properties in IRouteAction
|
|
|
|
### 1.4 Helper Functions
|
|
- `createStaticFileRoute()`
|
|
- Any other helpers that create redirect/block/static routes
|
|
|
|
---
|
|
|
|
## Phase 2: Create Predefined Socket Handlers
|
|
|
|
### 2.1 Block Handler
|
|
```typescript
|
|
export const SocketHandlers = {
|
|
// ... existing handlers
|
|
|
|
/**
|
|
* Block connection immediately
|
|
*/
|
|
block: (message?: string) => (socket: plugins.net.Socket, context: IRouteContext) => {
|
|
// Can use context for logging or custom messages
|
|
const finalMessage = message || `Connection blocked from ${context.clientIp}`;
|
|
if (finalMessage) {
|
|
socket.write(finalMessage);
|
|
}
|
|
socket.end();
|
|
},
|
|
|
|
/**
|
|
* HTTP block response
|
|
*/
|
|
httpBlock: (statusCode: number = 403, message?: string) => (socket: plugins.net.Socket, context: IRouteContext) => {
|
|
// Can customize message based on context
|
|
const defaultMessage = `Access forbidden for ${context.domain || context.clientIp}`;
|
|
const finalMessage = message || defaultMessage;
|
|
|
|
const response = [
|
|
`HTTP/1.1 ${statusCode} ${finalMessage}`,
|
|
'Content-Type: text/plain',
|
|
`Content-Length: ${finalMessage.length}`,
|
|
'Connection: close',
|
|
'',
|
|
finalMessage
|
|
].join('\r\n');
|
|
|
|
socket.write(response);
|
|
socket.end();
|
|
}
|
|
};
|
|
```
|
|
|
|
### 2.2 Redirect Handler
|
|
```typescript
|
|
export const SocketHandlers = {
|
|
// ... existing handlers
|
|
|
|
/**
|
|
* HTTP redirect handler
|
|
*/
|
|
httpRedirect: (locationTemplate: string, statusCode: number = 301) => (socket: plugins.net.Socket, context: IRouteContext) => {
|
|
let buffer = '';
|
|
|
|
socket.once('data', (data) => {
|
|
buffer += data.toString();
|
|
|
|
// Parse HTTP request
|
|
const lines = buffer.split('\r\n');
|
|
const requestLine = lines[0];
|
|
const [method, path] = requestLine.split(' ');
|
|
|
|
// Use domain from context (more reliable than Host header)
|
|
const domain = context.domain || 'localhost';
|
|
const port = context.port;
|
|
|
|
// Replace placeholders in location using context
|
|
let finalLocation = locationTemplate
|
|
.replace('{domain}', domain)
|
|
.replace('{port}', String(port))
|
|
.replace('{path}', path)
|
|
.replace('{clientIp}', context.clientIp);
|
|
|
|
const message = `Redirecting to ${finalLocation}`;
|
|
const response = [
|
|
`HTTP/1.1 ${statusCode} ${statusCode === 301 ? 'Moved Permanently' : 'Found'}`,
|
|
`Location: ${finalLocation}`,
|
|
'Content-Type: text/plain',
|
|
`Content-Length: ${message.length}`,
|
|
'Connection: close',
|
|
'',
|
|
message
|
|
].join('\r\n');
|
|
|
|
socket.write(response);
|
|
socket.end();
|
|
});
|
|
}
|
|
};
|
|
```
|
|
|
|
### 2.3 Benefits of Context in Socket Handlers
|
|
With routeContext as a second parameter, socket handlers can:
|
|
- Access client IP for logging or rate limiting
|
|
- Use domain information for multi-tenant handling
|
|
- Check if connection is TLS and what version
|
|
- Access route name/ID for metrics
|
|
- Build more intelligent responses based on context
|
|
|
|
Example advanced handler:
|
|
```typescript
|
|
const rateLimitHandler = (maxRequests: number) => {
|
|
const ipCounts = new Map<string, number>();
|
|
|
|
return (socket: net.Socket, context: IRouteContext) => {
|
|
const count = (ipCounts.get(context.clientIp) || 0) + 1;
|
|
ipCounts.set(context.clientIp, count);
|
|
|
|
if (count > maxRequests) {
|
|
socket.write(`Rate limit exceeded for ${context.clientIp}\n`);
|
|
socket.end();
|
|
return;
|
|
}
|
|
|
|
// Process request...
|
|
};
|
|
};
|
|
```
|
|
|
|
---
|
|
|
|
## Phase 3: Update Helper Functions
|
|
|
|
### 3.1 Update createHttpToHttpsRedirect
|
|
```typescript
|
|
export function createHttpToHttpsRedirect(
|
|
domains: string | string[],
|
|
httpsPort: number = 443,
|
|
options: Partial<IRouteConfig> = {}
|
|
): IRouteConfig {
|
|
return {
|
|
name: options.name || `HTTP to HTTPS Redirect for ${Array.isArray(domains) ? domains.join(', ') : domains}`,
|
|
match: {
|
|
ports: options.match?.ports || 80,
|
|
domains
|
|
},
|
|
action: {
|
|
type: 'socket-handler',
|
|
socketHandler: SocketHandlers.httpRedirect(`https://{domain}:${httpsPort}{path}`, 301)
|
|
},
|
|
...options
|
|
};
|
|
}
|
|
```
|
|
|
|
### 3.2 Update createSocketHandlerRoute
|
|
```typescript
|
|
export function createSocketHandlerRoute(
|
|
domains: string | string[],
|
|
ports: TPortRange,
|
|
handler: TSocketHandler,
|
|
options: { name?: string; priority?: number; path?: string } = {}
|
|
): IRouteConfig {
|
|
return {
|
|
name: options.name || 'socket-handler-route',
|
|
priority: options.priority !== undefined ? options.priority : 50,
|
|
match: {
|
|
domains,
|
|
ports,
|
|
...(options.path && { path: options.path })
|
|
},
|
|
action: {
|
|
type: 'socket-handler',
|
|
socketHandler: handler
|
|
}
|
|
};
|
|
}
|
|
|
|
```
|
|
|
|
---
|
|
|
|
## Phase 4: Core Implementation Changes
|
|
|
|
### 4.1 Update Route Connection Handler
|
|
```typescript
|
|
// Remove these methods:
|
|
// - handleRedirectAction()
|
|
// - handleBlockAction()
|
|
// - handleStaticAction()
|
|
|
|
// Update switch statement to only have:
|
|
switch (route.action.type) {
|
|
case 'forward':
|
|
return this.handleForwardAction(socket, record, route, initialChunk);
|
|
|
|
case 'socket-handler':
|
|
this.handleSocketHandlerAction(socket, record, route, initialChunk);
|
|
return;
|
|
|
|
default:
|
|
logger.log('error', `Unknown action type '${(route.action as any).type}'`);
|
|
socket.end();
|
|
this.connectionManager.cleanupConnection(record, 'unknown_action');
|
|
}
|
|
```
|
|
|
|
### 4.2 Update Socket Handler to Pass Context
|
|
```typescript
|
|
private async handleSocketHandlerAction(
|
|
socket: plugins.net.Socket,
|
|
record: IConnectionRecord,
|
|
route: IRouteConfig,
|
|
initialChunk?: Buffer
|
|
): Promise<void> {
|
|
const connectionId = record.id;
|
|
|
|
// Create route context for the handler
|
|
const routeContext = this.createRouteContext({
|
|
connectionId: record.id,
|
|
port: record.localPort,
|
|
domain: record.lockedDomain,
|
|
clientIp: record.remoteIP,
|
|
serverIp: socket.localAddress || '',
|
|
isTls: record.isTLS || false,
|
|
tlsVersion: record.tlsVersion,
|
|
routeName: route.name,
|
|
routeId: route.id,
|
|
});
|
|
|
|
try {
|
|
// Call the handler with socket AND context
|
|
const result = route.action.socketHandler(socket, routeContext);
|
|
|
|
// Rest of implementation stays the same...
|
|
} catch (error) {
|
|
// Error handling...
|
|
}
|
|
}
|
|
```
|
|
|
|
### 4.3 Clean Up Imports and Exports
|
|
- Remove imports of deleted handler classes
|
|
- Update index.ts files to remove exports
|
|
- Clean up any unused imports
|
|
|
|
---
|
|
|
|
## Phase 5: Test Updates
|
|
|
|
### 5.1 Remove Old Tests
|
|
- Delete tests for redirect action type
|
|
- Delete tests for block action type
|
|
- Delete tests for static action type
|
|
|
|
### 5.2 Add New Socket Handler Tests
|
|
- Test block socket handler with context
|
|
- Test HTTP redirect socket handler with context
|
|
- Test that context is properly passed to all handlers
|
|
|
|
---
|
|
|
|
## Phase 6: Documentation Updates
|
|
|
|
### 6.1 Update README.md
|
|
- Remove documentation for redirect, block, static action types
|
|
- Document the two remaining action types: forward and socket-handler
|
|
- Add examples using socket handlers with context
|
|
|
|
### 6.2 Update Type Documentation
|
|
```typescript
|
|
/**
|
|
* Route action types
|
|
* - 'forward': Proxy the connection to a target host:port
|
|
* - 'socket-handler': Pass the socket to a custom handler function
|
|
*/
|
|
export type TRouteActionType = 'forward' | 'socket-handler';
|
|
|
|
/**
|
|
* Socket handler function
|
|
* @param socket - The incoming socket connection
|
|
* @param context - Route context with connection information
|
|
*/
|
|
export type TSocketHandler = (socket: net.Socket, context: IRouteContext) => void | Promise<void>;
|
|
```
|
|
|
|
### 6.3 Example Documentation
|
|
```typescript
|
|
// Example: Block connections from specific IPs
|
|
const ipBlocker = (socket: net.Socket, context: IRouteContext) => {
|
|
if (context.clientIp.startsWith('192.168.')) {
|
|
socket.write('Internal IPs not allowed\n');
|
|
socket.end();
|
|
return;
|
|
}
|
|
// Forward to backend...
|
|
};
|
|
|
|
// Example: Domain-based routing
|
|
const domainRouter = (socket: net.Socket, context: IRouteContext) => {
|
|
const backend = context.domain === 'api.example.com' ? 'api-server' : 'web-server';
|
|
// Forward to appropriate backend...
|
|
};
|
|
```
|
|
|
|
---
|
|
|
|
## Implementation Steps
|
|
|
|
1. **Update TSocketHandler type** (15 minutes)
|
|
- Add IRouteContext as second parameter
|
|
- Update type definition in route-types.ts
|
|
|
|
2. **Update socket handler implementation** (30 minutes)
|
|
- Create routeContext in handleSocketHandlerAction
|
|
- Pass context to socket handler function
|
|
- Update all existing socket handlers in route-helpers.ts
|
|
|
|
3. **Remove old action types** (30 minutes)
|
|
- Remove 'redirect', 'block', 'static' from TRouteActionType
|
|
- Remove IRouteRedirect, IRouteStatic interfaces
|
|
- Clean up IRouteAction interface
|
|
|
|
4. **Delete old handlers** (45 minutes)
|
|
- Delete handleRedirectAction, handleBlockAction, handleStaticAction methods
|
|
- Delete RedirectHandler and StaticHandler classes
|
|
- Remove imports and exports
|
|
|
|
5. **Update route connection handler** (30 minutes)
|
|
- Simplify switch statement to only handle 'forward' and 'socket-handler'
|
|
- Remove all references to deleted action types
|
|
|
|
6. **Create new socket handlers** (30 minutes)
|
|
- Implement SocketHandlers.block() with context
|
|
- Implement SocketHandlers.httpBlock() with context
|
|
- Implement SocketHandlers.httpRedirect() with context
|
|
|
|
7. **Update helper functions** (30 minutes)
|
|
- Update createHttpToHttpsRedirect to use socket handler
|
|
- Delete createStaticFileRoute entirely
|
|
- Update any other affected helpers
|
|
|
|
8. **Clean up tests** (1.5 hours)
|
|
- Delete all tests for removed action types
|
|
- Update socket handler tests to verify context parameter
|
|
- Add new tests for block/redirect socket handlers
|
|
|
|
9. **Update documentation** (30 minutes)
|
|
- Update README.md
|
|
- Update type documentation
|
|
- Add examples of context usage
|
|
|
|
**Total estimated time: ~5 hours**
|
|
|
|
---
|
|
|
|
## Considerations
|
|
|
|
### Benefits
|
|
- **Dramatically simpler API** - Only 2 action types instead of 5
|
|
- **Consistent handling model** - Everything is either forwarding or custom handling
|
|
- **More powerful** - Socket handlers with context can do much more than old static types
|
|
- **Less code to maintain** - Removing hundreds of lines of specialized handler code
|
|
- **Better extensibility** - Easy to add new socket handlers for any use case
|
|
- **Context awareness** - All handlers get full connection context
|
|
|
|
### Trade-offs
|
|
- Static file serving removed (users should use nginx/apache behind proxy)
|
|
- HTTP-specific logic (redirects) now in socket handlers (but more flexible)
|
|
- Slightly more verbose configuration for simple blocks/redirects
|
|
|
|
### Why This Approach
|
|
1. **Simplicity wins** - Two concepts are easier to understand than five
|
|
2. **Power through context** - Socket handlers with context are more capable
|
|
3. **Clean break** - No migration paths means cleaner code
|
|
4. **Future proof** - Easy to add new handlers without changing core
|
|
|
|
---
|
|
|
|
## Code Examples: Before and After
|
|
|
|
### Block Action
|
|
```typescript
|
|
// BEFORE
|
|
{
|
|
action: { type: 'block' }
|
|
}
|
|
|
|
// AFTER
|
|
{
|
|
action: {
|
|
type: 'socket-handler',
|
|
socketHandler: SocketHandlers.block()
|
|
}
|
|
}
|
|
```
|
|
|
|
### HTTP Redirect
|
|
```typescript
|
|
// BEFORE
|
|
{
|
|
action: {
|
|
type: 'redirect',
|
|
redirect: {
|
|
to: 'https://{domain}:443{path}',
|
|
status: 301
|
|
}
|
|
}
|
|
}
|
|
|
|
// AFTER
|
|
{
|
|
action: {
|
|
type: 'socket-handler',
|
|
socketHandler: SocketHandlers.httpRedirect('https://{domain}:443{path}', 301)
|
|
}
|
|
}
|
|
```
|
|
|
|
### Custom Handler with Context
|
|
```typescript
|
|
// NEW CAPABILITY - Access to full context
|
|
{
|
|
action: {
|
|
type: 'socket-handler',
|
|
socketHandler: (socket, context) => {
|
|
console.log(`Connection from ${context.clientIp} to ${context.domain}:${context.port}`);
|
|
// Custom handling based on context...
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Detailed Implementation Tasks
|
|
|
|
### Step 1: Update TSocketHandler Type (15 minutes)
|
|
- [x] Open `ts/proxies/smart-proxy/models/route-types.ts`
|
|
- [x] Find line 14: `export type TSocketHandler = (socket: plugins.net.Socket) => void | Promise<void>;`
|
|
- [x] Import IRouteContext at top of file: `import type { IRouteContext } from '../../../core/models/route-context.js';`
|
|
- [x] Update TSocketHandler to: `export type TSocketHandler = (socket: plugins.net.Socket, context: IRouteContext) => void | Promise<void>;`
|
|
- [x] Save file
|
|
|
|
### Step 2: Update Socket Handler Implementation (30 minutes)
|
|
- [x] Open `ts/proxies/smart-proxy/route-connection-handler.ts`
|
|
- [x] Find `handleSocketHandlerAction` method (around line 790)
|
|
- [x] Add route context creation after line 809:
|
|
```typescript
|
|
// Create route context for the handler
|
|
const routeContext = this.createRouteContext({
|
|
connectionId: record.id,
|
|
port: record.localPort,
|
|
domain: record.lockedDomain,
|
|
clientIp: record.remoteIP,
|
|
serverIp: socket.localAddress || '',
|
|
isTls: record.isTLS || false,
|
|
tlsVersion: record.tlsVersion,
|
|
routeName: route.name,
|
|
routeId: route.id,
|
|
});
|
|
```
|
|
- [x] Update line 812 from `const result = route.action.socketHandler(socket);`
|
|
- [x] To: `const result = route.action.socketHandler(socket, routeContext);`
|
|
- [x] Save file
|
|
|
|
### Step 3: Update Existing Socket Handlers in route-helpers.ts (20 minutes)
|
|
- [x] Open `ts/proxies/smart-proxy/utils/route-helpers.ts`
|
|
- [x] Update `echo` handler (line 856):
|
|
- From: `echo: (socket: plugins.net.Socket) => {`
|
|
- To: `echo: (socket: plugins.net.Socket, context: IRouteContext) => {`
|
|
- [x] Update `proxy` handler (line 864):
|
|
- From: `proxy: (targetHost: string, targetPort: number) => (socket: plugins.net.Socket) => {`
|
|
- To: `proxy: (targetHost: string, targetPort: number) => (socket: plugins.net.Socket, context: IRouteContext) => {`
|
|
- [x] Update `lineProtocol` handler (line 879):
|
|
- From: `lineProtocol: (handler: (line: string, socket: plugins.net.Socket) => void) => (socket: plugins.net.Socket) => {`
|
|
- To: `lineProtocol: (handler: (line: string, socket: plugins.net.Socket) => void) => (socket: plugins.net.Socket, context: IRouteContext) => {`
|
|
- [ ] Update `httpResponse` handler (line 896):
|
|
- From: `httpResponse: (statusCode: number, body: string) => (socket: plugins.net.Socket) => {`
|
|
- To: `httpResponse: (statusCode: number, body: string) => (socket: plugins.net.Socket, context: IRouteContext) => {`
|
|
- [ ] Save file
|
|
|
|
### Step 4: Remove Old Action Types from Type Definitions (15 minutes)
|
|
- [ ] Open `ts/proxies/smart-proxy/models/route-types.ts`
|
|
- [ ] Find line with TRouteActionType (around line 10)
|
|
- [ ] Change from: `export type TRouteActionType = 'forward' | 'redirect' | 'block' | 'static' | 'socket-handler';`
|
|
- [ ] To: `export type TRouteActionType = 'forward' | 'socket-handler';`
|
|
- [ ] Find and delete IRouteRedirect interface (around line 123-126)
|
|
- [ ] Find and delete IRouteStatic interface (if exists)
|
|
- [ ] Find IRouteAction interface
|
|
- [ ] Remove these properties:
|
|
- `redirect?: IRouteRedirect;`
|
|
- `static?: IRouteStatic;`
|
|
- [ ] Save file
|
|
|
|
### Step 5: Delete Handler Classes (15 minutes)
|
|
- [ ] Delete file: `ts/proxies/http-proxy/handlers/redirect-handler.ts`
|
|
- [ ] Delete file: `ts/proxies/http-proxy/handlers/static-handler.ts`
|
|
- [ ] Open `ts/proxies/http-proxy/handlers/index.ts`
|
|
- [ ] Delete all content (the file only exports RedirectHandler and StaticHandler)
|
|
- [ ] Save empty file or delete it
|
|
|
|
### Step 6: Remove Handler Methods from RouteConnectionHandler (30 minutes)
|
|
- [ ] Open `ts/proxies/smart-proxy/route-connection-handler.ts`
|
|
- [ ] Find and delete entire `handleRedirectAction` method (around line 723)
|
|
- [ ] Find and delete entire `handleBlockAction` method (around line 750)
|
|
- [ ] Find and delete entire `handleStaticAction` method (around line 773)
|
|
- [ ] Remove imports at top:
|
|
- `import { RedirectHandler, StaticHandler } from '../http-proxy/handlers/index.js';`
|
|
- [ ] Save file
|
|
|
|
### Step 7: Update Switch Statement (15 minutes)
|
|
- [ ] Still in `route-connection-handler.ts`
|
|
- [ ] Find switch statement (around line 388)
|
|
- [ ] Remove these cases:
|
|
- `case 'redirect': return this.handleRedirectAction(...)`
|
|
- `case 'block': return this.handleBlockAction(...)`
|
|
- `case 'static': this.handleStaticAction(...); return;`
|
|
- [ ] Verify only 'forward' and 'socket-handler' cases remain
|
|
- [ ] Save file
|
|
|
|
### Step 8: Add New Socket Handlers to route-helpers.ts (30 minutes)
|
|
- [ ] Open `ts/proxies/smart-proxy/utils/route-helpers.ts`
|
|
- [ ] Add import at top: `import type { IRouteContext } from '../../../core/models/route-context.js';`
|
|
- [ ] Add to SocketHandlers object:
|
|
```typescript
|
|
/**
|
|
* Block connection immediately
|
|
*/
|
|
block: (message?: string) => (socket: plugins.net.Socket, context: IRouteContext) => {
|
|
const finalMessage = message || `Connection blocked from ${context.clientIp}`;
|
|
if (finalMessage) {
|
|
socket.write(finalMessage);
|
|
}
|
|
socket.end();
|
|
},
|
|
|
|
/**
|
|
* HTTP block response
|
|
*/
|
|
httpBlock: (statusCode: number = 403, message?: string) => (socket: plugins.net.Socket, context: IRouteContext) => {
|
|
const defaultMessage = `Access forbidden for ${context.domain || context.clientIp}`;
|
|
const finalMessage = message || defaultMessage;
|
|
|
|
const response = [
|
|
`HTTP/1.1 ${statusCode} ${finalMessage}`,
|
|
'Content-Type: text/plain',
|
|
`Content-Length: ${finalMessage.length}`,
|
|
'Connection: close',
|
|
'',
|
|
finalMessage
|
|
].join('\r\n');
|
|
|
|
socket.write(response);
|
|
socket.end();
|
|
},
|
|
|
|
/**
|
|
* HTTP redirect handler
|
|
*/
|
|
httpRedirect: (locationTemplate: string, statusCode: number = 301) => (socket: plugins.net.Socket, context: IRouteContext) => {
|
|
let buffer = '';
|
|
|
|
socket.once('data', (data) => {
|
|
buffer += data.toString();
|
|
|
|
const lines = buffer.split('\r\n');
|
|
const requestLine = lines[0];
|
|
const [method, path] = requestLine.split(' ');
|
|
|
|
const domain = context.domain || 'localhost';
|
|
const port = context.port;
|
|
|
|
let finalLocation = locationTemplate
|
|
.replace('{domain}', domain)
|
|
.replace('{port}', String(port))
|
|
.replace('{path}', path)
|
|
.replace('{clientIp}', context.clientIp);
|
|
|
|
const message = `Redirecting to ${finalLocation}`;
|
|
const response = [
|
|
`HTTP/1.1 ${statusCode} ${statusCode === 301 ? 'Moved Permanently' : 'Found'}`,
|
|
`Location: ${finalLocation}`,
|
|
'Content-Type: text/plain',
|
|
`Content-Length: ${message.length}`,
|
|
'Connection: close',
|
|
'',
|
|
message
|
|
].join('\r\n');
|
|
|
|
socket.write(response);
|
|
socket.end();
|
|
});
|
|
}
|
|
```
|
|
- [x] Save file
|
|
|
|
### Step 9: Update Helper Functions (20 minutes)
|
|
- [x] Still in `route-helpers.ts`
|
|
- [x] Update `createHttpToHttpsRedirect` function (around line 109):
|
|
- Change the action to use socket handler:
|
|
```typescript
|
|
action: {
|
|
type: 'socket-handler',
|
|
socketHandler: SocketHandlers.httpRedirect(`https://{domain}:${httpsPort}{path}`, 301)
|
|
}
|
|
```
|
|
- [x] Delete entire `createStaticFileRoute` function (lines 277-322)
|
|
- [x] Save file
|
|
|
|
### Step 10: Update Test Files (1.5 hours)
|
|
#### 10.1 Update Socket Handler Tests
|
|
- [x] Open `test/test.socket-handler.ts`
|
|
- [x] Update all handler functions to accept context parameter
|
|
- [x] Open `test/test.socket-handler.simple.ts`
|
|
- [x] Update handler to accept context parameter
|
|
- [x] Open `test/test.socket-handler-race.ts`
|
|
- [x] Update handler to accept context parameter
|
|
|
|
#### 10.2 Find and Update/Delete Redirect Tests
|
|
- [x] Search for files containing `type: 'redirect'` in test directory
|
|
- [x] For each file:
|
|
- [x] If it's a redirect-specific test, delete the file
|
|
- [x] If it's a mixed test, update redirect actions to use socket handlers
|
|
- [x] Files to check:
|
|
- [x] `test/test.route-redirects.ts` - deleted entire file
|
|
- [x] `test/test.forwarding.ts` - update any redirect tests
|
|
- [x] `test/test.forwarding.examples.ts` - update any redirect tests
|
|
- [x] `test/test.route-config.ts` - update any redirect tests
|
|
|
|
#### 10.3 Find and Update/Delete Block Tests
|
|
- [x] Search for files containing `type: 'block'` in test directory
|
|
- [x] Update or delete as appropriate
|
|
|
|
#### 10.4 Find and Delete Static Tests
|
|
- [x] Search for files containing `type: 'static'` in test directory
|
|
- [x] Delete static-specific test files
|
|
- [x] Remove static tests from mixed test files
|
|
|
|
### Step 11: Clean Up Imports and Exports (20 minutes)
|
|
- [x] Open `ts/proxies/smart-proxy/utils/index.ts`
|
|
- [x] Ensure route-helpers.ts is exported
|
|
- [x] Remove any exports of deleted functions
|
|
- [x] Open `ts/index.ts`
|
|
- [x] Remove any exports of deleted types/interfaces
|
|
- [x] Search for any remaining imports of RedirectHandler or StaticHandler
|
|
- [x] Remove any found imports
|
|
|
|
### Step 12: Documentation Updates (30 minutes)
|
|
- [x] Update README.md:
|
|
- [x] Remove any mention of redirect, block, static action types
|
|
- [x] Add examples of socket handlers with context
|
|
- [x] Document the two action types: forward and socket-handler
|
|
- [x] Update any JSDoc comments in modified files
|
|
- [x] Add examples showing context usage
|
|
|
|
### Step 13: Final Verification (15 minutes)
|
|
- [x] Run build: `pnpm build`
|
|
- [x] Fix any compilation errors
|
|
- [x] Run tests: `pnpm test`
|
|
- [x] Fix any failing tests
|
|
- [x] Search codebase for any remaining references to:
|
|
- [x] 'redirect' action type
|
|
- [x] 'block' action type
|
|
- [x] 'static' action type
|
|
- [x] RedirectHandler
|
|
- [x] StaticHandler
|
|
- [x] IRouteRedirect
|
|
- [x] IRouteStatic
|
|
|
|
### Step 14: Test New Functionality (30 minutes)
|
|
- [x] Create test for block socket handler with context
|
|
- [x] Create test for httpBlock socket handler with context
|
|
- [x] Create test for httpRedirect socket handler with context
|
|
- [x] Verify context is properly passed in all scenarios
|
|
|
|
---
|
|
|
|
## Files to be Modified/Deleted
|
|
|
|
### Files to Modify:
|
|
1. `ts/proxies/smart-proxy/models/route-types.ts` - Update types
|
|
2. `ts/proxies/smart-proxy/route-connection-handler.ts` - Remove handlers, update switch
|
|
3. `ts/proxies/smart-proxy/utils/route-helpers.ts` - Update handlers, add new ones
|
|
4. `ts/proxies/http-proxy/handlers/index.ts` - Remove exports
|
|
5. Various test files - Update to use socket handlers
|
|
|
|
### Files to Delete:
|
|
1. `ts/proxies/http-proxy/handlers/redirect-handler.ts`
|
|
2. `ts/proxies/http-proxy/handlers/static-handler.ts`
|
|
3. `test/test.route-redirects.ts` (likely)
|
|
4. Any static-specific test files
|
|
|
|
### Test Files Requiring Updates (15 files found):
|
|
- test/test.acme-http01-challenge.ts
|
|
- test/test.logger-error-handling.ts
|
|
- test/test.port80-management.node.ts
|
|
- test/test.route-update-callback.node.ts
|
|
- test/test.acme-state-manager.node.ts
|
|
- test/test.acme-route-creation.ts
|
|
- test/test.forwarding.ts
|
|
- test/test.route-redirects.ts
|
|
- test/test.forwarding.examples.ts
|
|
- test/test.acme-simple.ts
|
|
- test/test.acme-http-challenge.ts
|
|
- test/test.certificate-provisioning.ts
|
|
- test/test.route-config.ts
|
|
- test/test.route-utils.ts
|
|
- test/test.certificate-simple.ts
|
|
|
|
---
|
|
|
|
## Success Criteria
|
|
- ✅ Only 'forward' and 'socket-handler' action types remain
|
|
- ✅ Socket handlers receive IRouteContext as second parameter
|
|
- ✅ All old handler code completely removed
|
|
- ✅ Redirect functionality works via context-aware socket handlers
|
|
- ✅ Block functionality works via context-aware socket handlers
|
|
- ✅ All tests updated and passing
|
|
- ✅ Documentation updated with new examples
|
|
- ✅ No performance regression
|
|
- ✅ Cleaner, simpler codebase |