1+ 'use strict' ;
2+
3+ if ( process . env . STACKDRIVER_DEBUGGER === 'true' ) {
4+ require ( '@google-cloud/debug-agent' ) . start ( ) ;
5+ }
6+
7+ const request = require ( 'request' ) ;
8+ var url = require ( 'url' ) ;
9+
10+ const express = require ( 'express' ) ;
11+ const app = express ( ) ;
12+
13+ const basicAuthConnect = require ( 'basic-auth-connect' ) ;
14+
15+
16+ const { Storage} = require ( '@google-cloud/storage' ) ;
17+ const storage = new Storage ( ) ;
18+
19+
20+ // basic auth setting
21+ const basicAuth = basicAuthConnect ( process . env . BASIC_AUTH_NAME , process . env . BASIC_AUTH_PASSWORD ) ;
22+
23+ // bucket
24+ const bucket = storage . bucket ( process . env . BUCKET_NAME ) ;
25+
26+ // Google Cloud Storage generateSignedUrl Life time
27+ const GCS_URL_LIFETIME = parseInt ( process . env . GCS_URL_LIFETIME ) ;
28+
29+ //transfer option
30+ const TRANSFER_MODE = process . env . TRANSFER_MODE ;
31+ const ALLOW_DIRECT_LIST = JSON . parse ( process . env . ALLOW_DIRECT_LIST ) ;
32+ const ALLOW_REDIRECT_LIST = JSON . parse ( process . env . ALLOW_REDIRECT_LIST ) ;
33+
34+ // default page
35+ const DEFAULT_HTML = process . env . DEFAULT_PAGE ;
36+ // 404 page
37+ const NOT_FOUND_HTML = process . env . NOT_FOUND_PAGE ;
38+
39+
40+
41+
42+ // Constants
43+ const REDIRECT = 'REDIRECT' ;
44+ const SIGNEDURL = 'SIGNEDURL' ;
45+ const FILE_NOT_FOUND = 'FILE_NOT_FOUND' ;
46+
47+
48+
49+ /**
50+ * file exists check
51+ *
52+ * return bool true=file exist
53+ */
54+ async function checkFileExists ( filename ) {
55+
56+ const [ exists ] = await bucket
57+ . file ( filename )
58+ . exists ( )
59+ . catch ( err => {
60+ throw err ;
61+ } ) ;
62+
63+
64+ return exists ;
65+ }
66+
67+
68+ /**
69+ * Google Cloud Storage Generate Signerate URL
70+ *
71+ * @param {string } filepath
72+ * @return {string } Signerate URL
73+ */
74+ async function generateSignedUrl ( filepath ) {
75+
76+ const options = {
77+ action : 'read' ,
78+ expires : Date . now ( ) + GCS_URL_LIFETIME ,
79+ } ;
80+
81+ // Get a signed URL for the file
82+ const [ url ] = await bucket
83+ . file ( filepath )
84+ . getSignedUrl ( options ) ;
85+
86+
87+ return url ;
88+ }
89+
90+
91+ async function fileSearch ( url_parse ) {
92+
93+ let path_name = url_parse . pathname ;
94+
95+ if ( path_name . slice ( - 1 ) === '/' ) {
96+ path_name = path_name . slice ( 0 , - 1 ) ; // remove '/'
97+ }
98+
99+
100+ let is_file = false ; //file find flg
101+
102+ if ( path_name !== '' ) {
103+ is_file = await checkFileExists ( path_name ) ; //file check
104+ }
105+
106+
107+ if ( is_file === false ) { //file not found
108+
109+
110+ if ( await checkFileExists ( `${ path_name } /${ DEFAULT_HTML } ` ) ) { //check defalut html
111+ is_file = true ;
112+ path_name = `${ path_name } /${ DEFAULT_HTML } ` ;
113+ }
114+
115+
116+ if ( is_file === false ) { //defalut html not found
117+
118+ if ( await checkFileExists ( `/${ NOT_FOUND_HTML } ` ) ) { // check 404 html
119+ is_file = true ;
120+ path_name = `/${ NOT_FOUND_HTML } ` ;
121+ } else {
122+ return [ FILE_NOT_FOUND , '' ] ;
123+ }
124+ }
125+ }
126+
127+
128+ let file_signed_url = await generateSignedUrl ( path_name ) ;
129+
130+ if ( TRANSFER_MODE === 'ALL_DIRECT' ) {
131+
132+ return [ SIGNEDURL , file_signed_url ] ;
133+
134+ } else {
135+
136+ const file_split_ext = path_name . split ( '.' ) ;
137+ if ( file_split_ext . length > 0 ) {
138+ const file_ext = file_split_ext [ file_split_ext . length - 1 ] . toLowerCase ( ) ;
139+
140+ if ( TRANSFER_MODE === 'ALLOW_DIRECT' && ALLOW_DIRECT_LIST . indexOf ( file_ext ) >= 0 ) {
141+
142+ return [ SIGNEDURL , file_signed_url ] ; //target transfer files
143+
144+ } else if ( TRANSFER_MODE === 'ALLOW_REDIRECT' && ALLOW_REDIRECT_LIST . indexOf ( file_ext ) === - 1 ) {
145+
146+ return [ SIGNEDURL , file_signed_url ] ; //target transfer files
147+ }
148+ }
149+ }
150+
151+
152+
153+ //redirect path
154+ if ( url_parse . query ) { //check get param
155+ file_signed_url = file_signed_url + '?' + url_parse . query ;
156+ }
157+
158+ return [ REDIRECT , file_signed_url ] ;
159+ }
160+
161+
162+
163+
164+
165+ /**
166+ * helath check
167+ */
168+ app . get ( '/_ah/start' , ( req , res ) => {
169+
170+ res . send ( 'I am alive.' ) ;
171+
172+ } ) ;
173+
174+
175+
176+ /**
177+ * main url listener
178+ */
179+ app . get ( '/*' , basicAuth , ( req , res ) => {
180+
181+ const url_parse = url . parse ( req . url ) ;
182+
183+
184+ fileSearch ( url_parse ) . then ( result => {
185+
186+ const [ result_status , result_url ] = result ;
187+
188+ if ( result_status === REDIRECT ) {
189+
190+ res . redirect ( result_url ) ;
191+
192+ } else if ( result_status === SIGNEDURL ) {
193+
194+ const proxyRequestHeaders = Object . assign ( { } , req . headers ) ;
195+ for ( let key of [ 'host' , 'authorization' , 'cookie' ] ) {
196+ if ( key in proxyRequestHeaders ) {
197+ delete proxyRequestHeaders [ key ] ;
198+ }
199+ }
200+
201+ request ( {
202+ url : result_url ,
203+ method : req . method ,
204+ headers : proxyRequestHeaders ,
205+ } ) . pipe ( res ) ;
206+
207+ } else if ( result_status === FILE_NOT_FOUND ) {
208+
209+ res . status ( 404 ) . end ( '404 Not Found' ) ;
210+ } else {
211+ //It will never reach this code
212+ res . status ( 500 ) . end ( '500 Internal Server Error' ) ;
213+ }
214+
215+ } ) ;
216+
217+
218+ } ) ;
219+
220+
221+ /**
222+ * server start
223+ */
224+ const server = app . listen ( 8080 ) ;
0 commit comments