@@ -5,12 +5,14 @@ flags.defineString("db", "", "DB File path");
55flags . defineBoolean ( "readonly" , false , "Open the database for readonly" ) ;
66flags . defineNumber ( "port" , 2048 , "TCP Port to listen on" ) ;
77flags . defineMultiString ( "cors" , [ ] , "CORS URLs to allow requests from" ) ;
8+ flags . defineString ( "requestlimit" , "1mb" , "request body limit for HTTP POSTs" ) ;
89flags . parse ( ) ;
910
1011console . log ( "db" , "=" , flags . get ( "db" ) ) ;
1112console . log ( "readonly" , "=" , flags . get ( "readonly" ) ) ;
1213console . log ( "port" , "=" , flags . get ( "port" ) ) ;
1314console . log ( "cors" , "=" , flags . get ( "cors" ) . join ( ", " ) || "false" ) ;
15+ console . log ( "requestlimit" , "=" , flags . get ( "requestlimit" ) )
1416
1517const Database = require ( "better-sqlite3" ) ;
1618
@@ -19,7 +21,7 @@ const bodyParser = require("body-parser");
1921
2022const app = express ( ) ;
2123app . use ( require ( "compression" ) ( ) ) ;
22- app . use ( bodyParser . urlencoded ( { extended : false , limit : "1mb" } ) ) ;
24+ app . use ( bodyParser . urlencoded ( { extended : false , limit : flags . get ( "requestlimit" ) } ) ) ;
2325app . use ( bodyParser . json ( { limit : "1mb" } ) ) ;
2426app . use ( function ( req , res , next ) {
2527 req . connection . setTimeout ( 2 * 60 * 1000 ) ; // 2 minutes
@@ -45,35 +47,123 @@ if (flags.get("cors").length > 0) {
4547
4648function getSqlExecutor ( httpRequestFieldName ) {
4749 return function ( req , res ) {
50+
51+ let blobtype = req [ httpRequestFieldName ] . blobtype ;
52+ if ( blobtype == undefined || blobtype == null )
53+ {
54+ blobtype = "base64" ; //default http blob handling to base64 if blobtype queryparam/bodyparam is missing
55+ }
56+ if ( ( typeof blobtype ) != "string" )
57+ {
58+ res . status ( 400 ) ;
59+ res . send (
60+ `${ res . statusCode } : 'blobtype' element mandatory in http request ${ httpRequestFieldName } must be string value 'base64' or 'array'!\n`
61+ ) ;
62+ return ;
63+ }
64+ blobtype = blobtype . toLowerCase ( ) . trim ( ) ;
65+ if ( blobtype != "base64" && blobtype != "array" )
66+ {
67+ res . status ( 400 ) ;
68+ res . send (
69+ `${ res . statusCode } : 'blobtype' element mandatory in http request ${ httpRequestFieldName } must be string value 'base64' or 'array'!\n`
70+ ) ;
71+ return ;
72+ }
73+
4874 const sql = req [ httpRequestFieldName ] . sql ;
4975 let params = [ ] ;
5076 if ( httpRequestFieldName === "body" && req . is ( "application/json" ) ) {
5177 params = req [ httpRequestFieldName ] . params ;
5278 if ( params == undefined || params == null ) {
5379 params = [ ] ;
5480 }
55- }
56- if ( ! sql ) {
57- return res . send ( [ ] ) ;
58- }
5981
60- let db ;
61- try {
6282 if ( ! Array . isArray ( params ) ) {
6383 res . status ( 400 ) ;
6484 res . send (
65- `${ err . code } : 'params' element in http request body must be an array!\n`
85+ `${ res . statusCode } : 'params' element in http request body must be an array!\n`
6686 ) ;
6787 return ;
6888 }
89+
90+ if ( blobtype === "base64" ) {
91+ /**********************************************************************************
92+ Enumerate through sqlite parameters and if of them is a blob param
93+ then decode+convert that param to a buffer.
94+ - Base64 Blob parameter is structured as follows: {data: "base64data"},
95+ - Non-blob parameters are primitives. not objects (numeric,string,bool)
96+ ***********************************************************************************/
97+ for ( let i = 0 ; i < params . length ; i ++ ) {
98+ let param = params [ i ] ;
99+ //if the parameter is an object, assume it's a blob parameter
100+ if ( typeof param === 'object' && param !== null ) {
101+
102+ if ( param . hasOwnProperty ( "data" ) )
103+ {
104+ var data = param . data ;
105+ let buff = null ;
106+ if ( typeof Buffer . from === "function" ) {
107+ // Node 5.10+
108+ buff = Buffer . from ( data , 'base64' ) ;
109+ }
110+ else {
111+ // older Node versions, now deprecated
112+ buff = new Buffer ( data , 'base64' ) ;
113+ }
114+ params [ i ] = buff ;
115+ }
116+ }
117+ }
118+ }
119+ else if ( blobtype === "array" ) {
120+ /**********************************************************************************
121+ Enumerate through sqlite parameters and if of them is a blob param
122+ then convert the param to a buffer.
123+ - Array Blob parameter is structured as follows: {data: bytearray[]},
124+ - Non-blob parameters are primitives. not objects (numeric,string,bool)
125+ ***********************************************************************************/
126+ for ( let i = 0 ; i < params . length ; i ++ ) {
127+ let param = params [ i ] ;
128+ //if the parameter is an object, assume it's a blob parameter
129+ if ( typeof param === 'object' && param !== null ) {
130+ if ( param . hasOwnProperty ( "data" ) )
131+ {
132+ var data = param . data ;
133+ let buff = null ;
134+ if ( typeof Buffer . from === "function" ) {
135+ // Node 5.10+
136+ buff = Buffer . from ( data ) ;
137+ }
138+ else {
139+ // older Node versions, now deprecated
140+ buff = new Buffer ( data ) ;
141+ }
142+ params [ i ] = buff ;
143+ }
144+ }
145+ }
146+ }
147+ }
148+ if ( ! sql ) {
149+ return res . send ( [ ] ) ;
150+ }
151+
152+ let db ;
153+ try {
69154 const readonly = flags . get ( "readonly" ) ;
70155 db = new Database ( flags . get ( "db" ) , { readonly } ) ;
71156 if ( ! readonly ) {
72157 db . pragma ( "journal_mode = WAL" ) ;
73158 }
74159 } catch ( err ) {
75160 res . status ( 400 ) ;
76- res . send ( `${ err . code } : ${ err . message } \n` ) ;
161+ //precautionary check if err doesn't have a code member
162+ let errcode = res . statusCode ;
163+ if ( err . code ) {
164+ errcode = err . code ;
165+ }
166+ res . send ( `${ errcode } : ${ err . message } \n` ) ;
77167 db . close && db . close ( ) ;
78168 return ;
79169 }
@@ -95,6 +185,34 @@ function getSqlExecutor(httpRequestFieldName) {
95185 }
96186
97187 db . close ( ) ;
188+
189+ //if blobtype = base64, enumerate through the rows/fields and convert any buffer fields found to base64 string
190+ if ( blobtype == "base64" )
191+ {
192+ for ( let i = 0 ; i < rows . length ; i ++ ) {
193+ let row = rows [ i ] ;
194+
195+ //get field count for row
196+ let fieldcount = 0 ;
197+ for ( var prop in row ) {
198+ if ( Object . prototype . hasOwnProperty . call ( row , prop ) ) {
199+ fieldcount ++ ;
200+ }
201+ }
202+
203+ //enumerate through fields
204+ for ( let j = 0 ; j < fieldcount ; j ++ )
205+ {
206+ let fieldname = Object . keys ( row ) [ j ] ;
207+ let fielddata = row [ fieldname ] ;
208+ if ( Buffer . isBuffer ( fielddata ) ) {
209+ let base64data = fielddata . toString ( 'base64' ) ;
210+ rows [ i ] [ fieldname ] = base64data ;
211+ }
212+ }
213+ }
214+ }
215+
98216 res . send ( rows ) ;
99217 } ;
100218}
0 commit comments