mirror of
https://github.com/lush2020/edgetunnel.git
synced 2026-03-21 00:42:43 +08:00
delete custom code for bypass
This commit is contained in:
48
.github/workflows/build-client.yml
vendored
48
.github/workflows/build-client.yml
vendored
@@ -1,48 +0,0 @@
|
||||
name: build client
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Use Node.js 18
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 18.x
|
||||
cache: 'npm'
|
||||
- run: npm ci
|
||||
- name: pkg edge tunnel client
|
||||
run: npx nx run edge-bypass-client:pkg
|
||||
- name: copy config file
|
||||
run: cp dist/apps/edge-bypass-client/assets/config.json dist/pkg/edge-tunnel-client
|
||||
- name: linux arm64 package
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: edgetunnel-linux-arm64
|
||||
path: |
|
||||
dist/pkg/edge-tunnel-client/edgetunnel-linux-arm64
|
||||
dist/pkg/edge-tunnel-client/config.json
|
||||
- name: linux x64 package
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: edgetunnel-linux-x64
|
||||
path: |
|
||||
dist/pkg/edge-tunnel-client/edgetunnel-linux-x64
|
||||
dist/pkg/edge-tunnel-client/config.json
|
||||
- name: macos x64 package
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: edgetunnel-macos-x64
|
||||
path: |
|
||||
dist/pkg/edge-tunnel-client/edgetunnel-macos-x64
|
||||
dist/pkg/edge-tunnel-client/config.json
|
||||
- name: win x64 package
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: edgetunnel-win-x64
|
||||
path: |
|
||||
dist/pkg/edge-tunnel-client/edgetunnel-win-x64.exe
|
||||
dist/pkg/edge-tunnel-client/config.json
|
||||
37
.github/workflows/release.yml
vendored
37
.github/workflows/release.yml
vendored
@@ -1,37 +0,0 @@
|
||||
name: release
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Use Node.js 18
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 18.x
|
||||
cache: 'npm'
|
||||
- run: npm ci
|
||||
- name: pkg edge tunnel client
|
||||
run: npx nx run edge-bypass-client:pkg
|
||||
- name: copy config file
|
||||
run: cp dist/apps/edge-bypass-client/assets/config.json dist/pkg/edge-tunnel-client
|
||||
- name: zip edgetunnel-linux-arm64
|
||||
run: zip -j edgetunnel-linux-arm64-${{github.run_number}}.zip dist/pkg/edge-tunnel-client/edgetunnel-linux-arm64 dist/pkg/edge-tunnel-client/config.json
|
||||
- name: zip edgetunnel-linux-x64
|
||||
run: zip -j edgetunnel-linux-x64-${{github.run_number}}.zip dist/pkg/edge-tunnel-client/edgetunnel-linux-x64 dist/pkg/edge-tunnel-client/config.json
|
||||
- name: zip edgetunnel-macos-x64
|
||||
run: zip -j edgetunnel-macos-x64-${{github.run_number}}.zip dist/pkg/edge-tunnel-client/edgetunnel-macos-x64 dist/pkg/edge-tunnel-client/config.json
|
||||
- name: zip edgetunnel-win-x64
|
||||
run: zip -j edgetunnel-win-x64-${{github.run_number}}.zip dist/pkg/edge-tunnel-client/edgetunnel-win-x64.exe dist/pkg/edge-tunnel-client/config.json
|
||||
- name: Upload release files
|
||||
uses: svenstaro/upload-release-action@v2
|
||||
if: github.event_name == 'release'
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file_glob: true
|
||||
file: edgetunnel*.zip
|
||||
tag: ${{ github.ref }}
|
||||
@@ -1,21 +0,0 @@
|
||||
{
|
||||
"name": "deno-bypass",
|
||||
"$schema": "../../node_modules/nx/schemas/project-schema.json",
|
||||
"sourceRoot": "apps/deno-bypass/src",
|
||||
"projectType": "application",
|
||||
"targets": {
|
||||
"run": {
|
||||
"executor": "nx:run-commands",
|
||||
"options": {
|
||||
"command": "deno run --allow-net --allow-env --allow-write apps/deno-bypass/src/bypass.ts "
|
||||
}
|
||||
},
|
||||
"serve": {
|
||||
"executor": "nx:run-commands",
|
||||
"options": {
|
||||
"command": "deno run --allow-net --allow-write --allow-env --watch apps/deno-bypass/src/bypass.ts "
|
||||
}
|
||||
}
|
||||
},
|
||||
"tags": []
|
||||
}
|
||||
@@ -1,83 +0,0 @@
|
||||
import { serve } from 'https://deno.land/std@0.167.0/http/server.ts';
|
||||
import { buildRawHttp500, isVaildateReq } from './helper.ts';
|
||||
const userID = Deno.env.get('UUID');
|
||||
|
||||
const handler = async (request: Request): Promise<Response> => {
|
||||
console.log('--------start--------');
|
||||
try {
|
||||
const headers = request.headers;
|
||||
const serverAddress = headers.get('x-host') || '';
|
||||
const remotePort = headers.get('x-port') || 443;
|
||||
const isHttp = headers.get('x-http') === 'true';
|
||||
const uuid = request.headers.get('x-uuid');
|
||||
|
||||
if (!serverAddress || !remotePort || !userID) {
|
||||
return new Response(
|
||||
`Version 0.0.1-2022/12/04!!
|
||||
${userID ? 'has UUID env' : 'no UUID env'}
|
||||
感谢 deno deploy 严肃对待 web standard。支持 HTTP request & response streaming。
|
||||
`,
|
||||
{
|
||||
status: 200,
|
||||
headers: {},
|
||||
}
|
||||
);
|
||||
}
|
||||
if (uuid !== userID) {
|
||||
return new Response(buildRawHttp500('Do not send right UUID!'), {
|
||||
status: 403,
|
||||
headers: {},
|
||||
});
|
||||
}
|
||||
|
||||
if (!isVaildateReq(request)) {
|
||||
return new Response(
|
||||
buildRawHttp500(
|
||||
'request is not vaild due to lcoalip or request body is null'
|
||||
),
|
||||
{
|
||||
status: 500,
|
||||
headers: {},
|
||||
}
|
||||
);
|
||||
}
|
||||
console.log(
|
||||
`want to proxy to server address ${serverAddress}, and port ${remotePort}`
|
||||
);
|
||||
|
||||
const connection = await Deno.connect({
|
||||
port: Number(remotePort),
|
||||
hostname: serverAddress,
|
||||
});
|
||||
|
||||
// const proxyResp = request.body?.pipeThrough(connection);
|
||||
// 1. request.body readablestream end casue socket to be end, this will casue socket send FIN package early
|
||||
// and casue deno can't get TCP pcakge.
|
||||
// 2. current soluction for this, let proxy client wait for few ms and then end readablestream
|
||||
// 3. this is only inpact HTTP proxy not https
|
||||
let readablestreamRsp = connection.readable;
|
||||
if (isHttp) {
|
||||
// if is http, we need wait for request read, or we can warpper into async function
|
||||
for await (let chunk of request.body || []) {
|
||||
// console.log(new TextDecoder().decode(chunk));
|
||||
connection.write(chunk);
|
||||
}
|
||||
readablestreamRsp = connection.readable;
|
||||
} else {
|
||||
readablestreamRsp = request.body!.pipeThrough(connection);
|
||||
}
|
||||
|
||||
return new Response(readablestreamRsp, {
|
||||
status: 200,
|
||||
headers: {},
|
||||
});
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
return new Response(buildRawHttp500('has error'), {
|
||||
status: 500,
|
||||
headers: {},
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
serve(handler, { port: 8888, hostname: '[::]' });
|
||||
@@ -1,48 +0,0 @@
|
||||
const EOL = '\n';
|
||||
function isPrivateIP(ip: string) {
|
||||
if (ip === 'localhost') {
|
||||
return true;
|
||||
}
|
||||
const parts = ip.split('.');
|
||||
return (
|
||||
parts[0] === '10' ||
|
||||
(parts[0] === '172' &&
|
||||
parseInt(parts[1], 10) >= 16 &&
|
||||
parseInt(parts[1], 10) <= 31) ||
|
||||
(parts[0] === '192' && parts[1] === '168')
|
||||
);
|
||||
}
|
||||
|
||||
function buildRawHttp500(message: string) {
|
||||
const body = new TextEncoder().encode(`${message}`);
|
||||
return new ReadableStream({
|
||||
start(controller) {
|
||||
controller.enqueue(
|
||||
new TextEncoder().encode(`HTTP/1.1 500 Internal Server Error${EOL}`)
|
||||
);
|
||||
controller.enqueue(
|
||||
new TextEncoder().encode(`content-length: ${body.length}${EOL}`)
|
||||
);
|
||||
controller.enqueue(
|
||||
new TextEncoder().encode(
|
||||
`content-type: text/plain;charset=UTF-8${EOL}${EOL}`
|
||||
)
|
||||
);
|
||||
controller.enqueue(body);
|
||||
controller.close();
|
||||
},
|
||||
cancel() {},
|
||||
});
|
||||
}
|
||||
|
||||
function isVaildateReq(request: Request) {
|
||||
const serverAddress = request.headers.get('x-host') || '';
|
||||
let isVaild = true;
|
||||
if (isPrivateIP(serverAddress) || !request.body) {
|
||||
console.log('lcoal ip or request.body is null');
|
||||
isVaild = false;
|
||||
}
|
||||
return isVaild;
|
||||
}
|
||||
|
||||
export { isPrivateIP, buildRawHttp500, isVaildateReq };
|
||||
@@ -1,70 +0,0 @@
|
||||
import { serve } from 'https://deno.land/std@0.167.0/http/server.ts';
|
||||
|
||||
const userID = Deno.env.get('UUID') || '***REMOVED******';
|
||||
|
||||
const handler = async (request: Request): Promise<Response> => {
|
||||
const headers = request.headers;
|
||||
const serverAddress = headers.get('x-host') || '';
|
||||
const remotePort = headers.get('x-port') || 443;
|
||||
const uuid = headers.get('x-uuid');
|
||||
|
||||
if (!serverAddress || !remotePort || !userID) {
|
||||
return new Response(
|
||||
`Version 0.0.1-2022/12/04!!
|
||||
${userID ? 'has UUID env' : 'no UUID env'}
|
||||
感谢 deno deploy 严肃对待 web standard。支持 HTTP request & response streaming。
|
||||
`,
|
||||
{
|
||||
status: 200,
|
||||
headers: {},
|
||||
}
|
||||
);
|
||||
}
|
||||
console.log(
|
||||
`want to proxy to server address ${serverAddress}, and port ${remotePort}`
|
||||
);
|
||||
|
||||
if (uuid !== userID) {
|
||||
return new Response('Do not send right UUID!', {
|
||||
status: 403,
|
||||
headers: {},
|
||||
});
|
||||
}
|
||||
const connection = await Deno.connect({
|
||||
port: Number(remotePort),
|
||||
hostname: serverAddress,
|
||||
});
|
||||
const result = request.body?.pipeThrough(
|
||||
new TransformStream({
|
||||
transform(chunk, controller) {
|
||||
console.log('-- transform--');
|
||||
controller.enqueue(chunk);
|
||||
},
|
||||
})
|
||||
);
|
||||
const proxyResp = result?.pipeThrough(connection);
|
||||
for await (let chunk of connection.readable) {
|
||||
console.log('-------', new TextDecoder().decode(chunk));
|
||||
}
|
||||
// let timer: number | undefined = undefined;
|
||||
// const body = new ReadableStream({
|
||||
// start(controller) {
|
||||
// timer = setInterval(() => {
|
||||
// const message = `It is ${new Date().toISOString()}\n`;
|
||||
// controller.enqueue(new TextEncoder().encode(message));
|
||||
// }, 1000);
|
||||
// },
|
||||
// pull(chunk) {},
|
||||
// cancel() {
|
||||
// if (timer !== undefined) {
|
||||
// clearInterval(timer);
|
||||
// }
|
||||
// },
|
||||
// });
|
||||
return new Response('111', {
|
||||
status: 200,
|
||||
headers: {},
|
||||
});
|
||||
};
|
||||
|
||||
serve(handler, { port: 8080, hostname: '0.0.0.0' });
|
||||
@@ -1,14 +0,0 @@
|
||||
// (async () => {
|
||||
// try {
|
||||
// for await (let chunk of request.body || []) {
|
||||
// // console.log(new TextDecoder().decode(chunk));
|
||||
// connection.write(chunk);
|
||||
// }
|
||||
// } catch (error) {
|
||||
// console.log(error);
|
||||
// return new Response('has error', {
|
||||
// status: 500,
|
||||
// headers: {},
|
||||
// });
|
||||
// }
|
||||
// })();
|
||||
@@ -1,39 +0,0 @@
|
||||
import { serve } from 'https://deno.land/std@0.167.0/http/server.ts';
|
||||
|
||||
console.log('Current Deno version', Deno.version.deno);
|
||||
|
||||
const handler = async (request: Request): Promise<Response> => {
|
||||
const connection = await Deno.connect({
|
||||
port: 80,
|
||||
hostname: 'www.baidu.com',
|
||||
});
|
||||
const body2 = new ReadableStream({
|
||||
start(controller) {
|
||||
controller.enqueue(new TextEncoder().encode('GET / HTTP/1.1\r\n'));
|
||||
controller.enqueue(new TextEncoder().encode('Host: www.baidu.com\r\n'));
|
||||
controller.enqueue(
|
||||
new TextEncoder().encode('User-Agent: curl/7.83.1\r\n')
|
||||
);
|
||||
controller.enqueue(new TextEncoder().encode('Accept: */*\r\n\r\n'));
|
||||
controller.close();
|
||||
},
|
||||
cancel() {},
|
||||
});
|
||||
|
||||
// for await (const chunk of body2) {
|
||||
// console.log('11', new TextDecoder().decode(chunk));
|
||||
// }
|
||||
const proxyResp = body2?.pipeThrough(connection);
|
||||
|
||||
for await (const chunk of proxyResp) {
|
||||
console.log('11', new TextDecoder().decode(chunk));
|
||||
}
|
||||
return new Response('111', {
|
||||
status: 200,
|
||||
headers: {
|
||||
'x-ray': 'xxxx',
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
serve(handler, { port: 8080, hostname: '0.0.0.0' });
|
||||
@@ -1,18 +0,0 @@
|
||||
{
|
||||
"extends": ["../../.eslintrc.json"],
|
||||
"ignorePatterns": ["!**/*"],
|
||||
"overrides": [
|
||||
{
|
||||
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
|
||||
"rules": {}
|
||||
},
|
||||
{
|
||||
"files": ["*.ts", "*.tsx"],
|
||||
"rules": {}
|
||||
},
|
||||
{
|
||||
"files": ["*.js", "*.jsx"],
|
||||
"rules": {}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
/* eslint-disable */
|
||||
export default {
|
||||
displayName: 'edge-bypass-client',
|
||||
preset: '../../jest.preset.js',
|
||||
globals: {
|
||||
'ts-jest': {
|
||||
tsconfig: '<rootDir>/tsconfig.spec.json',
|
||||
},
|
||||
},
|
||||
testEnvironment: 'node',
|
||||
transform: {
|
||||
'^.+\\.[tj]s$': 'ts-jest',
|
||||
},
|
||||
moduleFileExtensions: ['ts', 'js', 'html'],
|
||||
coverageDirectory: '../../coverage/apps/edge-bypass-client',
|
||||
};
|
||||
@@ -1,79 +0,0 @@
|
||||
{
|
||||
"name": "edge-bypass-client",
|
||||
"$schema": "../../node_modules/nx/schemas/project-schema.json",
|
||||
"sourceRoot": "apps/edge-bypass-client/src",
|
||||
"projectType": "application",
|
||||
"targets": {
|
||||
"build": {
|
||||
"executor": "@nrwl/webpack:webpack",
|
||||
"outputs": ["{options.outputPath}"],
|
||||
"options": {
|
||||
"target": "node",
|
||||
"compiler": "tsc",
|
||||
"outputPath": "dist/apps/edge-bypass-client",
|
||||
"main": "apps/edge-bypass-client/src/main.ts",
|
||||
"tsConfig": "apps/edge-bypass-client/tsconfig.app.json",
|
||||
"assets": ["apps/edge-bypass-client/src/assets"]
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"optimization": true,
|
||||
"extractLicenses": true,
|
||||
"inspect": false,
|
||||
"fileReplacements": [
|
||||
{
|
||||
"replace": "apps/edge-bypass-client/src/environments/environment.ts",
|
||||
"with": "apps/edge-bypass-client/src/environments/environment.prod.ts"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"serve": {
|
||||
"executor": "@nrwl/js:node",
|
||||
"options": {
|
||||
"buildTarget": "edge-bypass-client:build",
|
||||
"args": [
|
||||
"run",
|
||||
"--config",
|
||||
"./apps/edge-bypass-client/src/assets/config-local.json"
|
||||
]
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"buildTarget": "edge-bypass-client:build:production"
|
||||
}
|
||||
}
|
||||
},
|
||||
"pkg": {
|
||||
"executor": "nx:run-commands",
|
||||
"options": {
|
||||
"command": "npx pkg dist/apps/edge-bypass-client/main.js --targets linux,linux-arm64,macos,win --compress GZip --output dist/pkg/edge-tunnel-client/edgetunnel"
|
||||
},
|
||||
"dependsOn": ["build"]
|
||||
},
|
||||
"pkg-local": {
|
||||
"executor": "nx:run-commands",
|
||||
"options": {
|
||||
"command": "npx pkg dist/apps/edge-bypass-client/main.js --targets win --compress GZip --output dist/pkg/edge-tunnel-client/edgetunnel"
|
||||
},
|
||||
"dependsOn": ["build"]
|
||||
},
|
||||
"lint": {
|
||||
"executor": "@nrwl/linter:eslint",
|
||||
"outputs": ["{options.outputFile}"],
|
||||
"options": {
|
||||
"lintFilePatterns": ["apps/edge-bypass-client/**/*.ts"]
|
||||
}
|
||||
},
|
||||
"test": {
|
||||
"executor": "@nrwl/jest:jest",
|
||||
"outputs": ["{workspaceRoot}/coverage/{projectRoot}"],
|
||||
"options": {
|
||||
"jestConfig": "apps/edge-bypass-client/jest.config.ts",
|
||||
"passWithNoTests": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"tags": []
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"port": "",
|
||||
"address": "",
|
||||
"uuid": "",
|
||||
"logLevel": "DEBUG"
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
export const environment = {
|
||||
production: true,
|
||||
};
|
||||
@@ -1,3 +0,0 @@
|
||||
export const environment = {
|
||||
production: false,
|
||||
};
|
||||
@@ -1,60 +0,0 @@
|
||||
import { Command } from 'commander';
|
||||
import { writeFileSync, existsSync, readFileSync } from 'fs';
|
||||
import { exit } from 'node:process';
|
||||
import { env } from 'process';
|
||||
let config: {
|
||||
port: string;
|
||||
address: string;
|
||||
uuid: string;
|
||||
logLevel: string;
|
||||
} = null;
|
||||
const program = new Command();
|
||||
program.option('-v').action((options) => {
|
||||
console.log(options);
|
||||
exit();
|
||||
});
|
||||
program
|
||||
.command('run')
|
||||
.description('launch local http proxy for edge pass')
|
||||
.option(
|
||||
'--config <config>',
|
||||
'address of remote proxy, etc https://***.deno.dev/'
|
||||
)
|
||||
.option(
|
||||
'--address <address>',
|
||||
'address of remote proxy, etc https://***.deno.dev/'
|
||||
)
|
||||
.option('--port <port>', 'local port of http proxy proxy')
|
||||
.option('--uuid <uuid>', 'uuid')
|
||||
.option('--save', 'if this is pass, will save to config.json')
|
||||
.action((options) => {
|
||||
console.log(__dirname);
|
||||
console.log(process.cwd());
|
||||
if (options.config) {
|
||||
if (existsSync(options.config)) {
|
||||
const content = readFileSync(options.config, {
|
||||
encoding: 'utf-8',
|
||||
});
|
||||
config = JSON.parse(content);
|
||||
return;
|
||||
} else {
|
||||
console.error('config not exsit!');
|
||||
exit();
|
||||
}
|
||||
}
|
||||
config = options;
|
||||
if (config.address && config.port && config.uuid) {
|
||||
if (options.save) {
|
||||
writeFileSync('./config.json', JSON.stringify(options), {
|
||||
encoding: 'utf-8',
|
||||
});
|
||||
}
|
||||
} else {
|
||||
console.error('need pass all args!');
|
||||
exit();
|
||||
}
|
||||
});
|
||||
program.parse();
|
||||
env.NODE_ENV = env.NODE_ENV || 'production';
|
||||
|
||||
export { config };
|
||||
@@ -1,94 +0,0 @@
|
||||
import { IncomingMessage } from 'http';
|
||||
import * as os from 'os';
|
||||
import * as url from 'node:url';
|
||||
import { config } from './cmd';
|
||||
|
||||
async function* concatStreams(readables: any[]) {
|
||||
for (const readable of readables) {
|
||||
for await (const chunk of readable) {
|
||||
yield chunk;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// POST http://zizi.press/test11.ttt?test1=66 HTTP/1.1
|
||||
// Host: zizi.press
|
||||
// User-Agent: curl/7.83.1
|
||||
// Connection: Keep-Alive
|
||||
// Content-Type: application/json
|
||||
// Accept: application/json
|
||||
// Content-Length: 16
|
||||
|
||||
// {"tool": "curl"}
|
||||
|
||||
//-------------------------------------
|
||||
// GET http://zizi.press/test11.ttt?test1=66 HTTP/1.1
|
||||
// Host: zizi.press
|
||||
// User-Agent: curl/7.83.1
|
||||
// Accept: */*
|
||||
// Connection: Keep-Alive
|
||||
|
||||
function rawHTTPHeader(req: IncomingMessage) {
|
||||
const reqUrl = url.parse(req.url);
|
||||
const headers = Object.entries(req.headers)
|
||||
.map(([key, value]) => {
|
||||
return `${key}:${value}`;
|
||||
})
|
||||
.join(os.EOL);
|
||||
const raw = `${req.method} ${reqUrl.path} HTTP/${req.httpVersion}${os.EOL}${headers}${os.EOL}${os.EOL}`;
|
||||
return raw;
|
||||
}
|
||||
|
||||
function rawHTTPPackage(req: IncomingMessage) {
|
||||
const rawHttpHeader = rawHTTPHeader(req);
|
||||
return concatStreams([[rawHttpHeader], req]);
|
||||
}
|
||||
|
||||
async function* deplay(ms) {
|
||||
yield await new Promise((res, reject) => {
|
||||
setTimeout(() => res(''), ms);
|
||||
});
|
||||
}
|
||||
|
||||
// delay few ms for
|
||||
// // request.body readablestream end casue socket to be end, this will casue socket send FIN package early
|
||||
// and casue deno can't get TCP pcakge.
|
||||
function rawHTTPPackageWithDelay(req: IncomingMessage) {
|
||||
const rawHttpHeader = rawHTTPHeader(req);
|
||||
return concatStreams([[rawHttpHeader], req, deplay(500)]);
|
||||
}
|
||||
|
||||
function errorHandler() {
|
||||
process
|
||||
.on('unhandledRejection', (reason, p) => {
|
||||
console.error(reason, 'Unhandled Rejection at Promise', p);
|
||||
})
|
||||
.on('uncaughtException', (err) => {
|
||||
console.error(err, 'Uncaught Exception thrown');
|
||||
// should exit node.js, but anyway
|
||||
// process.exit(1);
|
||||
});
|
||||
}
|
||||
|
||||
function loghelper(...args) {
|
||||
let logs = args;
|
||||
if (config.logLevel?.toUpperCase() !== 'DEBUG') {
|
||||
logs = args.map((item) => {
|
||||
if (item instanceof Error) {
|
||||
return `${item.message}`;
|
||||
} else {
|
||||
return item;
|
||||
}
|
||||
});
|
||||
}
|
||||
console.log('', ...logs);
|
||||
}
|
||||
|
||||
export {
|
||||
concatStreams,
|
||||
rawHTTPPackage,
|
||||
rawHTTPHeader,
|
||||
rawHTTPPackageWithDelay,
|
||||
errorHandler,
|
||||
loghelper,
|
||||
};
|
||||
@@ -1,158 +0,0 @@
|
||||
import { createServer } from 'node:http';
|
||||
import { pipeline, Readable } from 'node:stream';
|
||||
import { config } from './lib/cmd';
|
||||
import * as url from 'node:url';
|
||||
import * as undici from 'undici';
|
||||
import {
|
||||
concatStreams,
|
||||
rawHTTPPackage,
|
||||
errorHandler,
|
||||
loghelper,
|
||||
} from './lib/helper';
|
||||
|
||||
errorHandler();
|
||||
|
||||
const isLocal = process.env.DEBUG === 'true';
|
||||
const httpProxyServer = createServer(async (req, resp) => {
|
||||
const reqUrl = url.parse(req.url);
|
||||
const clientSocketLoggerInfo = `[proxy to ${req.url}](http)`;
|
||||
try {
|
||||
loghelper(`${clientSocketLoggerInfo} Client use HTTP/${req.httpVersion}`);
|
||||
// make call to edge http server
|
||||
// 1. forward all package remote, socket over http body
|
||||
const fromClientReq = Readable.from(rawHTTPPackage(req)).on(
|
||||
'error',
|
||||
(error) => {
|
||||
loghelper(
|
||||
`${clientSocketLoggerInfo} client socket to remote http body has error`,
|
||||
error
|
||||
);
|
||||
req.destroy();
|
||||
}
|
||||
);
|
||||
const { body, headers, statusCode, trailers } = await undici.request(
|
||||
config.address,
|
||||
{
|
||||
headers: {
|
||||
'x-host': reqUrl.hostname,
|
||||
'x-port': reqUrl.port || '80',
|
||||
'x-uuid': config.uuid,
|
||||
'x-http': 'true',
|
||||
},
|
||||
method: 'POST',
|
||||
body: fromClientReq,
|
||||
}
|
||||
);
|
||||
loghelper(
|
||||
`${clientSocketLoggerInfo} remote server return ${statusCode} Connected To Proxy`
|
||||
);
|
||||
// 2. forward remote reponse body to clientSocket
|
||||
for await (const chunk of body) {
|
||||
if (isLocal) {
|
||||
loghelper(chunk.toString());
|
||||
}
|
||||
req.socket.write(chunk);
|
||||
// resp.write(chunk);
|
||||
}
|
||||
// resp.end();
|
||||
body.on('error', (err) => {
|
||||
loghelper(
|
||||
`${clientSocketLoggerInfo} remote server response body has error`,
|
||||
err
|
||||
);
|
||||
req.destroy();
|
||||
});
|
||||
} catch (error) {
|
||||
req.destroy();
|
||||
req.socket?.end();
|
||||
loghelper(`${clientSocketLoggerInfo} has error `, error);
|
||||
}
|
||||
});
|
||||
|
||||
// handle https website
|
||||
httpProxyServer.on('connect', async (req, clientSocket, head) => {
|
||||
const reqUrl = url.parse('https://' + req.url);
|
||||
const clientSocketLoggerInfo = `[proxy to ${req.url}]`;
|
||||
let fromClientSocket = null;
|
||||
try {
|
||||
loghelper(
|
||||
`${clientSocketLoggerInfo} Client use HTTP/${
|
||||
req.httpVersion
|
||||
} Connected To Proxy, head on connect is ${head.toString() || 'empty'}`
|
||||
);
|
||||
// We need only the data once, the starting packet, per http proxy spec
|
||||
clientSocket.write(
|
||||
`HTTP/${req.httpVersion} 200 Connection Established\r\n\r\n`
|
||||
);
|
||||
|
||||
// loghelper(config);
|
||||
// make call to edge http server
|
||||
// 1. forward all package remote, socket over http body
|
||||
fromClientSocket = Readable.from(concatStreams([head, clientSocket]));
|
||||
const { body, headers, statusCode, trailers } = await undici.request(
|
||||
config.address,
|
||||
{
|
||||
headers: {
|
||||
'x-host': reqUrl.hostname,
|
||||
'x-port': reqUrl.port,
|
||||
'x-uuid': config.uuid,
|
||||
// "Content-Type": "text/plain",
|
||||
},
|
||||
method: 'POST',
|
||||
body: fromClientSocket,
|
||||
}
|
||||
);
|
||||
fromClientSocket.on('error', (error) => {
|
||||
loghelper(
|
||||
`${clientSocketLoggerInfo} client socket to remote http body has error`,
|
||||
error
|
||||
);
|
||||
//
|
||||
fromClientSocket.push(null);
|
||||
clientSocket.destroy();
|
||||
});
|
||||
loghelper(`${clientSocketLoggerInfo} remote server return ${statusCode}`);
|
||||
// 2. forward remote reponse body to clientSocket
|
||||
for await (const chunk of body) {
|
||||
clientSocket.write(chunk);
|
||||
}
|
||||
|
||||
body.on('error', (err) => {
|
||||
loghelper(
|
||||
`${clientSocketLoggerInfo} remote response body has error`,
|
||||
err
|
||||
);
|
||||
fromClientSocket.push(null);
|
||||
clientSocket.destroy();
|
||||
});
|
||||
clientSocket.on('error', (e) => {
|
||||
body?.destroy();
|
||||
fromClientSocket.push(null);
|
||||
clientSocket.end();
|
||||
loghelper(`${clientSocketLoggerInfo} clientSocket has error: ` + e);
|
||||
});
|
||||
clientSocket.on('end', () => {
|
||||
loghelper(`${clientSocketLoggerInfo} has done and end.`);
|
||||
});
|
||||
} catch (error) {
|
||||
fromClientSocket?.push(null);
|
||||
clientSocket.end();
|
||||
loghelper(`${clientSocketLoggerInfo} has error `, error);
|
||||
}
|
||||
});
|
||||
|
||||
httpProxyServer.on('error', (err) => {
|
||||
loghelper('SERVER ERROR', err);
|
||||
});
|
||||
httpProxyServer.on('clientError', (err, clientSocket) => {
|
||||
loghelper('client error: ' + err);
|
||||
clientSocket.end('HTTP/1.1 400 Bad Request\r\n\r\n');
|
||||
});
|
||||
|
||||
httpProxyServer.on('close', () => {
|
||||
loghelper('Server close');
|
||||
});
|
||||
|
||||
httpProxyServer.listen(Number(config.port), () => {
|
||||
loghelper('Server runnig at http://localhost:' + config.port);
|
||||
});
|
||||
@@ -1,152 +0,0 @@
|
||||
import { createServer } from 'node:http';
|
||||
import { pipeline, Readable } from 'node:stream';
|
||||
import { config } from '../lib/cmd';
|
||||
import * as url from 'node:url';
|
||||
import * as undici from 'undici';
|
||||
import {
|
||||
concatStreams,
|
||||
rawHTTPHeader,
|
||||
rawHTTPPackage,
|
||||
rawHTTPPackageWithDelay,
|
||||
} from '../lib/helper';
|
||||
|
||||
const isLocal = process.env.env === 'LOCAL';
|
||||
const httpProxyServer = createServer(async (req, resp) => {
|
||||
const reqUrl = url.parse(req.url || '');
|
||||
const clientSocketLoggerInfo = `[proxy to ${req.url}](http)`;
|
||||
try {
|
||||
console.log(`${clientSocketLoggerInfo} Client use HTTP/${req.httpVersion}`);
|
||||
|
||||
// for await (const chunk of req.socket) {
|
||||
// console.log(chunk.toString());
|
||||
// }
|
||||
|
||||
// make call to edge http server
|
||||
// 1. forward all package remote, socket over http body
|
||||
const { body, headers, statusCode, trailers } = await undici.request(
|
||||
config.address,
|
||||
{
|
||||
headers: {
|
||||
'x-host': reqUrl.hostname,
|
||||
'x-port': reqUrl.port || '80',
|
||||
'x-uuid': config.uuid,
|
||||
'x-http': 'true',
|
||||
} as any,
|
||||
method: 'POST',
|
||||
// append few ms for body
|
||||
// body: Readable.from(rawHTTPPackageWithDelay(req)),
|
||||
body: Readable.from(rawHTTPPackage(req)),
|
||||
}
|
||||
);
|
||||
console.log(
|
||||
`${clientSocketLoggerInfo} remote server return ${statusCode} Connected To Proxy`
|
||||
);
|
||||
// 2. forward remote reponse body to clientSocket
|
||||
for await (const chunk of body) {
|
||||
if (isLocal) {
|
||||
console.log(chunk.toString());
|
||||
}
|
||||
req.socket.write(chunk);
|
||||
}
|
||||
body.on('error', (err) => {
|
||||
console.log(
|
||||
`${clientSocketLoggerInfo} remote server response body has error`,
|
||||
err
|
||||
);
|
||||
});
|
||||
// issue with pipeline
|
||||
// https://stackoverflow.com/questions/55959479/error-err-stream-premature-close-premature-close-in-node-pipeline-stream
|
||||
// pipeline(body, req.socket, (error) => {
|
||||
// console.log(
|
||||
// `${clientSocketLoggerInfo} remote server to clientSocket has error: ` +
|
||||
// error
|
||||
// );
|
||||
// req.socket.end();
|
||||
// req.socket.destroy();
|
||||
// });
|
||||
} catch (error) {
|
||||
req.socket.end();
|
||||
req.socket.destroy();
|
||||
console.log(`${clientSocketLoggerInfo} has error `, error);
|
||||
}
|
||||
});
|
||||
|
||||
// handle https website
|
||||
httpProxyServer.on('connect', async (req, clientSocket, head) => {
|
||||
const reqUrl = url.parse('https://' + req.url);
|
||||
const clientSocketLoggerInfo = `[proxy to ${req.url}]`;
|
||||
try {
|
||||
console.log(
|
||||
`${clientSocketLoggerInfo} Client use HTTP/${
|
||||
req.httpVersion
|
||||
} Connected To Proxy, head on connect is ${head.toString() || 'empty'}`
|
||||
);
|
||||
// We need only the data once, the starting packet, per http proxy spec
|
||||
clientSocket.write(
|
||||
`HTTP/${req.httpVersion} 200 Connection Established\r\n\r\n`
|
||||
);
|
||||
|
||||
// console.log(config);
|
||||
// make call to edge http server
|
||||
// 1. forward all package remote, socket over http body
|
||||
const { body, headers, statusCode, trailers } = await undici.request(
|
||||
config.address,
|
||||
{
|
||||
headers: {
|
||||
'x-host': reqUrl.hostname,
|
||||
'x-port': reqUrl.port,
|
||||
'x-uuid': config.uuid,
|
||||
// "Content-Type": "text/plain",
|
||||
} as any,
|
||||
method: 'POST',
|
||||
body: Readable.from(concatStreams([head, clientSocket])),
|
||||
}
|
||||
);
|
||||
console.log(`${clientSocketLoggerInfo} remote server return ${statusCode}`);
|
||||
// 2. forward remote reponse body to clientSocket
|
||||
// 2. forward remote reponse body to clientSocket
|
||||
for await (const chunk of body) {
|
||||
clientSocket.write(chunk);
|
||||
}
|
||||
body.on('error', (err) => {
|
||||
console.log(`${clientSocketLoggerInfo} body error`, err);
|
||||
});
|
||||
// pipeline(body, clientSocket, (error) => {
|
||||
// console.log(
|
||||
// `${clientSocketLoggerInfo} remote server to clientSocket has error: `,
|
||||
// error
|
||||
// );
|
||||
// body?.destroy();
|
||||
// clientSocket.destroy();
|
||||
// });
|
||||
clientSocket.on('error', (e) => {
|
||||
body?.destroy();
|
||||
clientSocket.destroy();
|
||||
console.log(`${clientSocketLoggerInfo} clientSocket has error: ` + e);
|
||||
});
|
||||
clientSocket.on('end', () => {
|
||||
console.log(`${clientSocketLoggerInfo} has done and end.`);
|
||||
});
|
||||
} catch (error) {
|
||||
clientSocket.destroy();
|
||||
console.log(`${clientSocketLoggerInfo} has error `, error);
|
||||
}
|
||||
});
|
||||
|
||||
httpProxyServer.on('error', (err) => {
|
||||
console.log('SERVER ERROR');
|
||||
console.log(err);
|
||||
throw err;
|
||||
});
|
||||
httpProxyServer.on('clientError', (err, clientSocket) => {
|
||||
console.log('client error: ' + err);
|
||||
clientSocket.end('HTTP/1.1 400 Bad Request\r\n\r\n');
|
||||
});
|
||||
|
||||
httpProxyServer.on('close', () => {
|
||||
console.log('Server close');
|
||||
});
|
||||
|
||||
httpProxyServer.listen(Number(config.port), () => {
|
||||
console.log('Server runnig at http://localhost:' + config.port);
|
||||
});
|
||||
@@ -1,31 +0,0 @@
|
||||
import * as undici from 'undici';
|
||||
import { pipeline, Readable, Writable } from 'node:stream';
|
||||
|
||||
pipeline(
|
||||
new Readable({
|
||||
read() {
|
||||
this.push(Buffer.from('undici'));
|
||||
this.push(null);
|
||||
},
|
||||
}),
|
||||
undici.pipeline(
|
||||
'http://localhost:1082',
|
||||
{
|
||||
method: 'POST',
|
||||
},
|
||||
({ statusCode, headers, body }) => {
|
||||
console.log(`response received ${statusCode}`);
|
||||
console.log('headers', headers);
|
||||
console.log('headers', body);
|
||||
return body;
|
||||
}
|
||||
),
|
||||
// new Writable({
|
||||
// write(chunk) {
|
||||
// console.log(chunk.toString());
|
||||
// },
|
||||
// }),
|
||||
(error) => {
|
||||
console.log(error);
|
||||
}
|
||||
);
|
||||
@@ -1,15 +0,0 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../dist/out-tsc",
|
||||
"module": "commonjs",
|
||||
"types": ["node"]
|
||||
},
|
||||
"exclude": [
|
||||
"jest.config.ts",
|
||||
"**/*.spec.ts",
|
||||
"**/*.test.ts",
|
||||
"**/test-demo/*.ts"
|
||||
],
|
||||
"include": ["**/*.ts"]
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"module": "NodeNext",
|
||||
"target": "ES2022"
|
||||
},
|
||||
"files": [],
|
||||
"include": [],
|
||||
"references": [
|
||||
{
|
||||
"path": "./tsconfig.app.json"
|
||||
},
|
||||
{
|
||||
"path": "./tsconfig.spec.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../dist/out-tsc",
|
||||
"module": "commonjs",
|
||||
"types": ["jest", "node"]
|
||||
},
|
||||
"include": ["jest.config.ts", "**/*.test.ts", "**/*.spec.ts", "**/*.d.ts"]
|
||||
}
|
||||
Reference in New Issue
Block a user