1
- var express = require ( 'express' ) ;
2
- var proxy = require ( 'http-proxy-middleware' ) ;
3
- const zlib = require ( "zlib" )
4
- const fs = require ( "fs" )
1
+ const zlib = require ( 'zlib' )
5
2
const parse = require ( 'url-parse' )
6
3
const cookiejar = require ( 'cookiejar' )
7
4
const iconv = require ( 'iconv-lite' )
5
+ const pako = require ( 'pako' )
8
6
const { logSave, logGet, logClear} = require ( './logger' )
9
- const { CookieAccessInfo , CookieJar , Cookie } = cookiejar
7
+ const ProxyMiddleware = require ( 'http-proxy-middleware' )
10
8
11
9
function countUtf8Bytes ( s ) {
12
10
var b = 0 , i = 0 , c
13
11
for ( ; c = s . charCodeAt ( i ++ ) ; b += c >> 11 ?3 :c >> 7 ?2 :1 ) ;
14
12
return b
15
13
}
16
14
15
+ function uint8ArrayConcat ( arrays ) { // for cloudflare
16
+ // sum of individual array lengths
17
+ let totalLength = arrays . reduce ( ( acc , value ) => acc + value . length , 0 ) ;
18
+ if ( ! arrays . length ) return null ;
19
+
20
+ let result = new Uint8Array ( totalLength ) ;
21
+ // for each array - copy it over result
22
+ // next array is copied right after the previous one
23
+ let length = 0 ;
24
+ for ( let array of arrays ) {
25
+ result . set ( array , length ) ;
26
+ length += array . length ;
27
+ }
28
+
29
+ return result ;
30
+ }
31
+
17
32
var contentTypeIsText = ( headers ) => {
18
33
if ( ! headers [ "content-type" ] ||
19
34
headers [ "content-type" ] . indexOf ( 'text/' ) !== - 1 ||
@@ -62,7 +77,7 @@ var redirect2HomePage = function({res, httpprefix, serverName,} ) {
62
77
res . status ( 302 ) . send ( `` )
63
78
}
64
79
65
- let getHostFromReq = ( { req, serverName} ) => { //return target
80
+ let getHostFromReq = ( { req, serverName} ) => { // return target
66
81
// url: http://127.0.0.1:8011/https/www.youtube.com/xxx/xxx/...
67
82
let https_prefix = '/https/'
68
83
let http_prefix = '/http/'
@@ -116,7 +131,9 @@ let getHostFromReq = ({req, serverName}) => { //return target
116
131
}
117
132
} )
118
133
}
119
- if ( host === '' ) {
134
+ let localServeList = [ '/index.html' , '/' , '/favicon.png' ]
135
+ if ( host === '' ||
136
+ ( host === serverName && ! localServeList . includes ( req . url ) ) ) {
120
137
if ( originalHost !== '' ) {
121
138
httpType = originalHost . split ( '/' ) [ 0 ]
122
139
host = originalHost . split ( '/' ) [ 1 ]
@@ -127,12 +144,9 @@ let getHostFromReq = ({req, serverName}) => { //return target
127
144
return { host, httpType}
128
145
}
129
146
130
-
131
- let Proxy = ( { blockedSites, urlModify, httpprefix, serverName, port, cookieDomainRewrite, locationReplaceMap302, regReplaceMap, siteSpecificReplace, pathReplace} ) => {
132
- let stream = fs . createWriteStream ( "web-records.csv" , { flags :'a' } )
133
- let handleRespond = ( { req, res, body, gbFlag} ) => { // text file
134
- let myRe
135
- let { host, httpType} = getHostFromReq ( { req, serverName} )
147
+ let Proxy = ( { ProxyMiddleware, blockedSites, urlModify, httpprefix, serverName, port, cookieDomainRewrite, locationReplaceMap302, regReplaceMap, siteSpecificReplace, pathReplace} ) => {
148
+ // let stream = fs.createWriteStream("web-records.csv", {flags:'a'})
149
+ var locationMod302 = ( { res, serverName, httpprefix, host, httpType} ) => {
136
150
let location = res . getHeaders ( ) [ 'location' ]
137
151
if ( res . statusCode == '301' || res . statusCode == '302' || res . statusCode == '303' || res . statusCode == '307' || res . statusCode == '308' ) {
138
152
location = locationReplaceMap302 ( { location, serverName, httpprefix, host, httpType} )
@@ -141,9 +155,16 @@ let Proxy = ({blockedSites, urlModify, httpprefix, serverName, port, cookieDomai
141
155
res . setHeader ( 'location' , location )
142
156
} catch ( e ) {
143
157
logSave ( `error: ${ e } ` )
144
- return
158
+ return false
145
159
}
146
- // return
160
+ }
161
+ return true
162
+ }
163
+ let handleRespond = ( { req, res, body, gbFlag} ) => { // text file
164
+ let myRe
165
+ let { host, httpType} = getHostFromReq ( { req, serverName} )
166
+ if ( locationMod302 ( { res, serverName, httpprefix, host, httpType} ) === false ) {
167
+ return
147
168
}
148
169
// logSave(`HandleRespond(), req.url:${req.url}, req.headers:${JSON.stringify(req.headers)}`)
149
170
for ( let key in regReplaceMap ) {
@@ -190,15 +211,23 @@ let Proxy = ({blockedSites, urlModify, httpprefix, serverName, port, cookieDomai
190
211
}
191
212
res . statusCode = '302'
192
213
}
193
- logSave ( `6` )
194
- body = zlib . gzipSync ( body ) //19ms
214
+ logSave ( `5 after replacment,displayed string, body.length:${ body . length } ` )
215
+ // logSave(`5 after replacment,displayed string: ${body}`)
216
+ if ( process . env . cloudflare === 'true' ) { // in cloudflare environment
217
+ let enc = new TextEncoder ( )
218
+ body = enc . encode ( body )
219
+ logSave ( `6 cloudflare, after encoding, uint8array, body.length:${ body . length } ` ) // body is utf-8 uint8Array now
220
+ } else { //node environment
221
+ body = zlib . gzipSync ( body ) //body is Buffer
222
+ }
223
+ logSave ( `7` )
195
224
try {
196
225
res . setHeader ( 'content-encoding' , 'gzip' ) ;
197
226
logSave ( `handleRespond: res.statusCode:${ res . statusCode } , res.headers:${ JSON . stringify ( res . getHeaders ( ) ) } ` )
198
227
if ( req . headers [ 'debugflag' ] === 'true' ) {
199
228
res . removeHeader ( 'content-encoding' )
200
229
res . setHeader ( 'content-type' , 'text/plain' )
201
- body = logGet ( )
230
+ body = logGet ( )
202
231
}
203
232
res . end ( body ) ;
204
233
} catch ( e ) {
@@ -216,7 +245,7 @@ let Proxy = ({blockedSites, urlModify, httpprefix, serverName, port, cookieDomai
216
245
return target
217
246
}
218
247
219
- let p = proxy ( {
248
+ let p = ProxyMiddleware ( {
220
249
target : `https://www.google.com` ,
221
250
router,
222
251
/*
@@ -256,14 +285,18 @@ let Proxy = ({blockedSites, urlModify, httpprefix, serverName, port, cookieDomai
256
285
let bodyLength = 0
257
286
let endFlag = false
258
287
proxyRes . on ( 'data' , function ( data ) {
259
- // body = Buffer.concat([body, data]);
260
288
if ( endFlag === true ) {
261
289
return // don't have to push it to bodyList
262
290
}
263
- bodyLength += data . length
291
+ bodyLength += data . length // data is Uint8Array for cloueflare, and Buffer for node environment
264
292
bodyList . push ( data )
265
293
if ( bodyLength >= 2500000 && contentTypeIsText ( proxyRes . headers ) !== true ) {
266
- let body = Buffer . concat ( bodyList )
294
+ let body
295
+ if ( process . env . cloudflare === 'true' ) { // in node environment
296
+ body = uint8ArrayConcat ( bodyList ) // body is Uint8Array for cloueflare
297
+ } else {
298
+ body = Buffer . concat ( bodyList ) // body is Buffer for node environment
299
+ }
267
300
let fwdStr = req . headers [ 'X-Forwarded-For' ] || req . headers [ 'x-forwarded-for' ]
268
301
let contentType = proxyRes . headers [ 'content-type' ]
269
302
let contentLen = proxyRes . headers [ 'content-length' ]
@@ -280,32 +313,58 @@ let Proxy = ({blockedSites, urlModify, httpprefix, serverName, port, cookieDomai
280
313
if ( endFlag === true ) {
281
314
return
282
315
}
283
- let body = Buffer . concat ( bodyList )
316
+ console . log ( `on end 1, bodyList.length:${ bodyList . length } ` )
317
+ let body
318
+ if ( process . env . cloudflare === 'true' ) {
319
+ body = uint8ArrayConcat ( bodyList ) // body is Uint8Array
320
+ if ( ! body ) { // if body is null, end the stream.
321
+ locationMod302 ( { res, serverName, httpprefix, host, httpType} )
322
+ res . end ( body ) ;
323
+ return
324
+ }
325
+ } else { // in node environment
326
+ body = Buffer . concat ( bodyList ) // body is Buffer
327
+ }
328
+ console . log ( `on end 2, body.length:${ body . length } ` )
284
329
let gbFlag = false
285
330
if ( proxyRes . headers [ "content-encoding" ] === 'gzip' ||
286
331
proxyRes . headers [ "content-encoding" ] === 'br' ) { // gzip/br encoding
287
332
let gunzipped
288
333
try {
289
- if ( proxyRes . headers [ "content-encoding" ] === 'br' ) {
290
- gunzipped = zlib . brotliDecompressSync ( body )
291
- logSave ( `zlib.brotli...` )
292
- } else { //gzip
293
- gunzipped = zlib . gunzipSync ( body )
334
+ if ( process . env . cloudflare === 'true' ) { // in cloudflare environment
335
+ console . log ( 'cloudflare environment' )
336
+ gunzipped = body // in cloudflare, we have gzip
337
+ } else {
338
+ console . log ( 'node environment' )
339
+ if ( proxyRes . headers [ "content-encoding" ] === 'br' ) {
340
+ gunzipped = zlib . brotliDecompressSync ( body )
341
+ logSave ( `zlib.brotli...` )
342
+ } else { //gzip
343
+ gunzipped = zlib . gunzipSync ( body )
294
344
logSave ( `zlib.gunzip...` )
345
+ }
295
346
}
296
347
} catch ( e ) {
297
348
// res.status(404).send(`{"error": "${e}"}`)
349
+ console . log ( `error2:${ e } ` )
298
350
return
299
351
}
352
+ console . log ( `on end 3` )
300
353
if ( contentTypeIsText ( proxyRes . headers ) === true ) { //gzip and text
354
+ console . log ( `on end 4` )
301
355
if ( ! gunzipped ) {
302
356
// res.status(404).send(`{"error":"failed unzip"}`)
303
357
redirect2HomePage ( { res, httpprefix, serverName, } )
304
358
return
305
359
}
306
- logSave ( `utf-8 text... ` )
360
+ logSave ( `utf-8 text, gunzipped.length: ${ gunzipped . length } ` )
307
361
let originBody = gunzipped
308
- body = gunzipped . toString ( 'utf-8' ) ;
362
+ if ( process . env . cloudflare === 'true' ) { // in cloudflare environment
363
+ body = new TextDecoder ( ) . decode ( gunzipped ) // gunzipped.toString('utf-8');
364
+ logSave ( `after decode, displayed string, body.length:${ body . length } ` )
365
+ } else {
366
+ body = gunzipped . toString ( 'utf-8' )
367
+ }
309
368
let searchBody = body . slice ( 0 , 1000 )
310
369
if ( searchBody . indexOf ( '="text/html; charset=gb' ) !== - 1 ||
311
370
searchBody . indexOf ( ' charset="gb' ) !== - 1 ||
@@ -317,15 +376,16 @@ let Proxy = ({blockedSites, urlModify, httpprefix, serverName, port, cookieDomai
317
376
let fwdStr = req . headers [ 'X-Forwarded-For' ] || req . headers [ 'x-forwarded-for' ] || ''
318
377
if ( proxyRes . statusCode === 200 && proxyRes . headers [ "content-type" ] &&
319
378
proxyRes . headers [ "content-type" ] . indexOf ( 'text/html' ) !== - 1 ) {
320
- saveRecord ( { stream, fwdStr, req, host, pktLen :body . length } )
379
+ // saveRecord({stream, fwdStr, req, host, pktLen:body.length})
321
380
}
322
381
if ( proxyRes . statusCode === 200 && req . url . indexOf ( '/sw.js' ) !== - 1 ) {
323
382
// fetching sw.js
324
383
res . setHeader ( 'service-worker-allowed' , '/' )
325
384
}
326
- handleRespond ( { req, res, body, gbFlag} )
385
+ handleRespond ( { req, res, body, gbFlag} ) // body is a displayed string
327
386
} else { // gzip and non-text
328
387
// console.log(`2========>${logGet()}`)
388
+ console . log ( `on end 5` )
329
389
let fwdStr = req . headers [ 'X-Forwarded-For' ] || req . headers [ 'x-forwarded-for' ]
330
390
let contentType = proxyRes . headers [ 'content-type' ]
331
391
let contentLen = proxyRes . headers [ 'content-length' ]
@@ -340,7 +400,11 @@ let Proxy = ({blockedSites, urlModify, httpprefix, serverName, port, cookieDomai
340
400
contentTypeIsText ( proxyRes . headers ) === true ) { // text with non gzip encoding
341
401
logSave ( `utf-8 text...` )
342
402
let originBody = body
343
- body = body . toString ( 'utf-8' ) ;
403
+ if ( process . env . cloudflare === 'true' ) { // in cloudflare environment
404
+ body = new TextDecoder ( ) . decode ( body ) // Uint8Array(utf-8 arrayBuffer) toString('utf-8')
405
+ } else { // node environment
406
+ body = body . toString ( 'utf-8' ) ;
407
+ }
344
408
if ( body . indexOf ( '="text/html; charset=gb' ) !== - 1 ||
345
409
body . indexOf ( ' charset="gb' ) !== - 1 ||
346
410
body . indexOf ( '=\'text/html; charset=gb' ) !== - 1 ) {
@@ -355,16 +419,22 @@ let Proxy = ({blockedSites, urlModify, httpprefix, serverName, port, cookieDomai
355
419
let contentType = proxyRes . headers [ 'content-type' ]
356
420
let contentLen = proxyRes . headers [ 'content-length' ]
357
421
console . log ( `end,route:${ fwdStr } , content-type:${ contentType } ,length:${ bodyLength } , content-length:${ contentLen } , ${ host } ` )
358
- res . end ( body )
422
+ if ( process . env . cloudflare === 'true' ) { // in cloudflare environment
423
+ res . end ( Uint8Array . from ( body ) )
424
+ } else { // node environment
425
+ res . end ( body )
426
+ }
359
427
}
360
428
} )
361
429
const setCookieHeaders = proxyRes . headers [ 'set-cookie' ] || [ ]
430
+ console . log ( `1` )
362
431
let datestr = ''
363
432
if ( setCookieHeaders . length > 0 ) {
364
433
let date = new Date
365
434
date . setDate ( date . getDate ( ) + 1 ) // 一天之后过期
366
435
datestr = date . toUTCString ( )
367
436
}
437
+ console . log ( `2, setCookieHeaders:${ JSON . stringify ( setCookieHeaders ) } ` )
368
438
const modifiedSetCookieHeaders = setCookieHeaders
369
439
. map ( str => new cookiejar . Cookie ( str ) )
370
440
. map ( cookie => {
@@ -378,6 +448,7 @@ let Proxy = ({blockedSites, urlModify, httpprefix, serverName, port, cookieDomai
378
448
return cookie
379
449
} )
380
450
. map ( cookie => cookie . toString ( ) )
451
+ console . log ( `3` )
381
452
let cookie_originalHost = new cookiejar . Cookie ( )
382
453
cookie_originalHost . name = 'ORIGINALHOST'
383
454
cookie_originalHost . value = `${ httpType } /${ host } `
@@ -386,6 +457,7 @@ let Proxy = ({blockedSites, urlModify, httpprefix, serverName, port, cookieDomai
386
457
cookie_originalHost . path = `/`
387
458
cookie_originalHost . secure = false
388
459
modifiedSetCookieHeaders . push ( cookie_originalHost . toString ( ) )
460
+ console . log ( `4` )
389
461
proxyRes . headers [ 'set-cookie' ] = modifiedSetCookieHeaders
390
462
Object . keys ( proxyRes . headers ) . forEach ( function ( key ) {
391
463
if ( key === 'content-security-policy' ||
@@ -469,9 +541,11 @@ let Proxy = ({blockedSites, urlModify, httpprefix, serverName, port, cookieDomai
469
541
} )
470
542
proxyReq . setHeader ( 'Accept-Encoding' , 'gzip' )
471
543
proxyReq . setHeader ( 'referer' , host )
544
+ console . log ( `host=${ host } ` )
472
545
if ( host . indexOf ( 'youtube.com' ) !== - 1 ) {
473
- proxyReq . setHeader ( 'User-Agent' , `Opera/7.50 (Windows XP; U)` )
546
+ // proxyReq.setHeader('User-Agent', `Opera/7.50 (Windows XP; U)`)
474
547
// proxyReq.setHeader('User-Agent', `Opera/9.80 (Android 4.1.2; Linux; Opera Mobi/ADR-1305251841) Presto/2.11.355 Version/12.10`)
548
+ proxyReq . setHeader ( 'User-Agent' , `Mozilla/5.0 (Linux; Android 6.0.1; Lenovo-A6020l36 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.93 Mobile Safari/537.36` )
475
549
}
476
550
logSave ( `req host:${ host } , req.url:${ req . url } , proxyReq.query:${ proxyReq . query } proxyReq.path:${ proxyReq . path } , proxyReq.url:${ proxyReq . url } proxyReq headers:${ JSON . stringify ( proxyReq . getHeaders ( ) ) } ` )
477
551
if ( host === '' || ! host ) {
0 commit comments