Skip to content

Commit ce71e79

Browse files
committed
Initial implementation of javascript-proxy-headers
Extensions for JavaScript HTTP libraries to support sending and receiving custom proxy headers during HTTPS CONNECT tunneling. Core implementation: - ProxyHeadersAgent: Custom https.Agent with proxy header support - CONNECT request/response parser - Utility functions for proxy URL handling Library extensions: - axios: createProxyAxios() factory function - node-fetch: proxyFetch() wrapper - got: createProxyGot() factory function - undici: request() with proxy header support - superagent: proxyPlugin() middleware Documentation: - LIBRARY_RESEARCH.md: Analysis of 15+ JavaScript HTTP libraries - IMPLEMENTATION_PRIORITY.md: Detailed implementation plan - README.md: Usage examples for all supported libraries Made-with: Cursor
0 parents  commit ce71e79

16 files changed

Lines changed: 2082 additions & 0 deletions

.gitignore

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Dependencies
2+
node_modules/
3+
4+
# Build output
5+
dist/
6+
7+
# Logs
8+
*.log
9+
npm-debug.log*
10+
11+
# OS files
12+
.DS_Store
13+
Thumbs.db
14+
15+
# IDE
16+
.idea/
17+
.vscode/
18+
*.swp
19+
*.swo
20+
21+
# Test coverage
22+
coverage/
23+
24+
# Environment
25+
.env
26+
.env.local

IMPLEMENTATION_PRIORITY.md

Lines changed: 272 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,272 @@
1+
# Implementation Priority & Plan
2+
3+
This document outlines the implementation plan for javascript-proxy-headers.
4+
5+
## Architecture Overview
6+
7+
```
8+
┌─────────────────────────────────────────────────────────────┐
9+
│ javascript-proxy-headers │
10+
├─────────────────────────────────────────────────────────────┤
11+
│ Library Wrappers (high-level, user-friendly APIs) │
12+
│ ┌─────────┐ ┌───────────┐ ┌─────┐ ┌────────┐ ┌──────────┐ │
13+
│ │ axios │ │node-fetch │ │ got │ │ undici │ │superagent│ │
14+
│ └────┬────┘ └─────┬─────┘ └──┬──┘ └────┬───┘ └────┬─────┘ │
15+
│ │ │ │ │ │ │
16+
│ └────────────┴────┬─────┴─────────┴──────────┘ │
17+
│ │ │
18+
│ ┌──────────────────────▼──────────────────────────────┐ │
19+
│ │ ProxyHeadersAgent (core) │ │
20+
│ │ - Manages CONNECT request with custom headers │ │
21+
│ │ - Captures CONNECT response headers │ │
22+
│ │ - Compatible with http.Agent interface │ │
23+
│ └─────────────────────────────────────────────────────┘ │
24+
└─────────────────────────────────────────────────────────────┘
25+
```
26+
27+
## Implementation Phases
28+
29+
### Phase 1: Core Agent (Week 1)
30+
**Goal:** Create `ProxyHeadersAgent` - the foundation for all library wrappers
31+
32+
**Files:**
33+
- `lib/core/proxy-headers-agent.js` - Main agent implementation
34+
- `lib/core/connect-parser.js` - HTTP CONNECT response parser
35+
- `lib/core/utils.js` - Shared utilities
36+
37+
**Features:**
38+
- [x] Parse proxy URL (host, port, auth)
39+
- [x] Send custom headers in CONNECT request
40+
- [x] Parse CONNECT response headers
41+
- [x] Support Basic auth
42+
- [x] Expose headers via callback or property
43+
- [x] Compatible with Node.js `http.Agent` interface
44+
45+
**API:**
46+
```javascript
47+
import { ProxyHeadersAgent } from 'javascript-proxy-headers';
48+
49+
const agent = new ProxyHeadersAgent('http://proxy:8080', {
50+
proxyHeaders: {
51+
'X-ProxyMesh-Country': 'US'
52+
}
53+
});
54+
55+
// After request, headers available on agent
56+
console.log(agent.lastProxyHeaders); // Map of response headers
57+
```
58+
59+
---
60+
61+
### Phase 2: Undici Extension (Week 1-2)
62+
**Goal:** Native undici support with cleanest API
63+
64+
**Files:**
65+
- `lib/undici-proxy.js`
66+
67+
**Features:**
68+
- [ ] Custom `ProxyAgent` subclass or wrapper
69+
- [ ] Support `proxyHeaders` option
70+
- [ ] Expose CONNECT response headers on response
71+
- [ ] Support async header callback
72+
73+
**API:**
74+
```javascript
75+
import { request } from 'javascript-proxy-headers/undici';
76+
77+
const { statusCode, headers, body, proxyHeaders } = await request(url, {
78+
proxy: 'http://proxy:8080',
79+
proxyHeaders: { 'X-ProxyMesh-Country': 'US' }
80+
});
81+
82+
console.log(proxyHeaders.get('x-proxymesh-ip'));
83+
```
84+
85+
---
86+
87+
### Phase 3: node-fetch Extension (Week 2)
88+
**Goal:** Drop-in fetch wrapper with proxy header support
89+
90+
**Files:**
91+
- `lib/node-fetch-proxy.js`
92+
93+
**Features:**
94+
- [ ] Wrapper function around fetch
95+
- [ ] Uses ProxyHeadersAgent internally
96+
- [ ] Extends Response to include proxyHeaders
97+
98+
**API:**
99+
```javascript
100+
import { proxyFetch } from 'javascript-proxy-headers/node-fetch';
101+
102+
const response = await proxyFetch(url, {
103+
proxy: 'http://proxy:8080',
104+
proxyHeaders: { 'X-ProxyMesh-Country': 'US' }
105+
});
106+
107+
console.log(response.proxyHeaders.get('x-proxymesh-ip'));
108+
```
109+
110+
---
111+
112+
### Phase 4: Axios Extension (Week 2-3)
113+
**Goal:** Axios adapter with proxy header support
114+
115+
**Files:**
116+
- `lib/axios-proxy.js`
117+
118+
**Features:**
119+
- [ ] Custom axios instance factory
120+
- [ ] Request interceptor for agent setup
121+
- [ ] Response interceptor to merge headers
122+
- [ ] Support both sync and async access
123+
124+
**API:**
125+
```javascript
126+
import { createProxyAxios } from 'javascript-proxy-headers/axios';
127+
128+
const client = createProxyAxios({
129+
proxy: 'http://proxy:8080',
130+
proxyHeaders: { 'X-ProxyMesh-Country': 'US' }
131+
});
132+
133+
const response = await client.get(url);
134+
console.log(response.headers['x-proxymesh-ip']); // Merged into response
135+
```
136+
137+
---
138+
139+
### Phase 5: Got Extension (Week 3)
140+
**Goal:** Got instance with proxy header support
141+
142+
**Files:**
143+
- `lib/got-proxy.js`
144+
145+
**Features:**
146+
- [ ] Use got.extend() for clean integration
147+
- [ ] Leverage got's hook system
148+
- [ ] Merge proxy headers into response
149+
150+
**API:**
151+
```javascript
152+
import { createProxyGot } from 'javascript-proxy-headers/got';
153+
154+
const client = createProxyGot({
155+
proxy: 'http://proxy:8080',
156+
proxyHeaders: { 'X-ProxyMesh-Country': 'US' }
157+
});
158+
159+
const response = await client(url);
160+
console.log(response.headers['x-proxymesh-ip']);
161+
```
162+
163+
---
164+
165+
### Phase 6: SuperAgent Extension (Week 3-4)
166+
**Goal:** SuperAgent plugin for proxy headers
167+
168+
**Files:**
169+
- `lib/superagent-proxy.js`
170+
171+
**Features:**
172+
- [ ] Plugin function for superagent
173+
- [ ] Chainable API
174+
175+
**API:**
176+
```javascript
177+
import superagent from 'superagent';
178+
import { proxyPlugin } from 'javascript-proxy-headers/superagent';
179+
180+
const response = await superagent
181+
.get(url)
182+
.use(proxyPlugin({
183+
proxy: 'http://proxy:8080',
184+
proxyHeaders: { 'X-ProxyMesh-Country': 'US' }
185+
}));
186+
187+
console.log(response.headers['x-proxymesh-ip']);
188+
```
189+
190+
---
191+
192+
## Technical Challenges
193+
194+
### 1. CONNECT Response Timing
195+
The CONNECT response is received before the TLS handshake. Need to:
196+
- Buffer the response
197+
- Parse headers before upgrading to TLS
198+
- Store headers for later retrieval
199+
200+
### 2. Connection Pooling
201+
When using keep-alive/connection pooling:
202+
- Each new CONNECT will have different proxy headers
203+
- Need to track which response corresponds to which request
204+
- Consider disabling pooling for simplicity initially
205+
206+
### 3. Async Header Access
207+
Proxy headers are available before the target response:
208+
- Option 1: Callback when CONNECT completes
209+
- Option 2: Property on agent, accessed after request
210+
- Option 3: Merge into final response headers
211+
212+
### 4. TypeScript Support
213+
- Provide `.d.ts` files for all modules
214+
- Extend existing library types properly
215+
216+
---
217+
218+
## File Structure
219+
220+
```
221+
javascript-proxy-headers/
222+
├── package.json
223+
├── README.md
224+
├── LIBRARY_RESEARCH.md
225+
├── IMPLEMENTATION_PRIORITY.md
226+
├── index.js # Main entry point
227+
├── lib/
228+
│ ├── core/
229+
│ │ ├── proxy-headers-agent.js
230+
│ │ ├── connect-parser.js
231+
│ │ └── utils.js
232+
│ ├── axios-proxy.js
233+
│ ├── node-fetch-proxy.js
234+
│ ├── got-proxy.js
235+
│ ├── undici-proxy.js
236+
│ └── superagent-proxy.js
237+
├── test/
238+
│ ├── run_tests.js
239+
│ ├── core.test.js
240+
│ ├── axios.test.js
241+
│ ├── node-fetch.test.js
242+
│ ├── got.test.js
243+
│ ├── undici.test.js
244+
│ └── superagent.test.js
245+
└── types/
246+
└── index.d.ts
247+
```
248+
249+
---
250+
251+
## Success Criteria
252+
253+
1. **Core Agent**: Can send headers in CONNECT, receive headers from response
254+
2. **All Libraries**: Consistent API pattern across all wrappers
255+
3. **Tests**: Each library tested with real proxy
256+
4. **Documentation**: Clear examples for each library
257+
5. **TypeScript**: Full type definitions
258+
259+
---
260+
261+
## Risks & Mitigations
262+
263+
| Risk | Mitigation |
264+
|------|------------|
265+
| Node.js internals change | Pin minimum Node version, test across versions |
266+
| Library API changes | Use peer dependencies with version ranges |
267+
| Connection pooling complexity | Start without pooling, add later |
268+
| Performance overhead | Benchmark against direct connections |
269+
270+
---
271+
272+
*Plan created: February 28, 2026*

0 commit comments

Comments
 (0)