/ Check-in [35dd8b0148]
DEMO | DOWNLOAD | DEPLOY | SEARCH
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Release "2.6.1". WebSocket: add support for .shtml server-side-include.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:35dd8b01480eda7e2eec1317e33c8d0586598746
User & Date: pmacdona 2018-11-18 22:26:45
Context
2018-11-28
03:22
Release "2.6.2". Pre switch to new docs. Fix File.realpath check-in: 70ea852cb1 user: pmacdona tags: trunk
2018-11-18
22:26
Release "2.6.1". WebSocket: add support for .shtml server-side-include. check-in: 35dd8b0148 user: pmacdona tags: trunk
2018-11-02
13:24
Fix utf bug in String.map check-in: e53e49a18d user: pmacdona tags: trunk
Changes

Changes to Make.jsi.

36
37
38
39
40
41
42

43
44
45
46
47
48
49
..
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
...
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
    XCPREFIX='',
    //PROGLDFLAGS += USERLIB+' ',
    SHLEXT='.so',
    ZIPDIR='zipdir',
    PROGBINMIN = './jsimin',
    PROGBINA   = PROGRAM+'_'+EXEEXT,
    PROGBIN    = PROGRAM+EXEEXT,

    JSI_PKG_DIRS=BUILDDIR+'/lib,'+PREFIX+'/lib/jsi';

eval($.readConf(MAKECONF));

// Global vars.
$.YACC    = 'bison -v';
$.LDFLAGS = '-lm ';
................................................................................

if (TARGET == 'win')
    JSI__REGEX=1;


if (JSI__REGEX) {
    $.CFLAGS += '-Iregex ';
    $.CFILES += 'regex/regcomp.c  regex/regerror.c  regex/regexec.c regex/tre-mem.c ';
    //HFILES += 'regex/regex.h regex/tre.h ';
}

if (LINKSTATIC)
    PROGLDFLAGS += '-static ';


................................................................................
    if (JSI__GNUREADLINE)
        PROGLDFLAGS += '-lreadline -lncurses ';
}

MINIZDIR='miniz';
if (JSI__MINIZ) {
    CFILES += MINIZDIR+'/miniz.c ';
    CFLAGS += '-I'+PWD+'/'+MINIZDIR+' ';
} else if (!WIN)
    PROGLDFLAGS += '-lz ';

//PROGLDFLAGS += USERLIB+' ';
$.LDFLAGS += PROGLDFLAGS+' ';
$.CFLAGS  += COPTS+PROGFLAGS;
OBJS    = CFILES.map(['.c','.o']) + EFILES.map(['.c','.o']);







>







 







|







 







|







36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
..
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
...
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
    XCPREFIX='',
    //PROGLDFLAGS += USERLIB+' ',
    SHLEXT='.so',
    ZIPDIR='zipdir',
    PROGBINMIN = './jsimin',
    PROGBINA   = PROGRAM+'_'+EXEEXT,
    PROGBIN    = PROGRAM+EXEEXT,
    PWD=File.pwd(),
    JSI_PKG_DIRS=BUILDDIR+'/lib,'+PREFIX+'/lib/jsi';

eval($.readConf(MAKECONF));

// Global vars.
$.YACC    = 'bison -v';
$.LDFLAGS = '-lm ';
................................................................................

if (TARGET == 'win')
    JSI__REGEX=1;


if (JSI__REGEX) {
    $.CFLAGS += '-Iregex ';
    CFILES += 'regex/regcomp.c  regex/regerror.c  regex/regexec.c regex/tre-mem.c ';
    //HFILES += 'regex/regex.h regex/tre.h ';
}

if (LINKSTATIC)
    PROGLDFLAGS += '-static ';


................................................................................
    if (JSI__GNUREADLINE)
        PROGLDFLAGS += '-lreadline -lncurses ';
}

MINIZDIR='miniz';
if (JSI__MINIZ) {
    CFILES += MINIZDIR+'/miniz.c ';
    $.CFLAGS += '-I'+PWD+'/'+MINIZDIR+' ';
} else if (!WIN)
    PROGLDFLAGS += '-lz ';

//PROGLDFLAGS += USERLIB+' ';
$.LDFLAGS += PROGLDFLAGS+' ';
$.CFLAGS  += COPTS+PROGFLAGS;
OBJS    = CFILES.map(['.c','.o']) + EFILES.map(['.c','.o']);

Changes to Makefile.

395
396
397
398
399
400
401
402
403
404
405
406
407
408
409

stubs:
	(cd src && ../$(PROGBIN) ../tools/mkstubs.jsi)

ref:
	./$(PROGBIN) tools/mkproto.jsi > tools/protos.jsi
	$(MAKE) -C www
	$(MAKE) -C html

release: stubs ref src/jsi.c src/jsiOne.c

printconf:
	@echo $(EXPECT_CONFIG_VER)

test:







|







395
396
397
398
399
400
401
402
403
404
405
406
407
408
409

stubs:
	(cd src && ../$(PROGBIN) ../tools/mkstubs.jsi)

ref:
	./$(PROGBIN) tools/mkproto.jsi > tools/protos.jsi
	$(MAKE) -C www
#	$(MAKE) -C html

release: stubs ref src/jsi.c src/jsiOne.c

printconf:
	@echo $(EXPECT_CONFIG_VER)

test:

Changes to lib/Jsi_DebugUI/Jsi_DebugUI.jsi.

711
712
713
714
715
716
717


718
719
720
721
722
723
724
            rootdir     :self.rootdir, 
            onRecv      :webRecv, 
            onCloseLast :webCloseLast, 
            debug       :self.wsdebug,
            extHandlers :true,      // Sets up preprocess handlers for .htmli, .cssi, and .jsi files
            urlPrefix   :'/DebugUI'
        };


        for (i in defws)
            if (self.wsopts[i] === undefined)
                self.wsopts[i] = defws[i];
        
        self.ws = new WebSocket(self.wsopts);
        self.wsopts.port = self.ws.conf('port');
                    







>
>







711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
            rootdir     :self.rootdir, 
            onRecv      :webRecv, 
            onCloseLast :webCloseLast, 
            debug       :self.wsdebug,
            extHandlers :true,      // Sets up preprocess handlers for .htmli, .cssi, and .jsi files
            urlPrefix   :'/DebugUI'
        };
        if (self.local)
            defws.noCompress = true;
        for (i in defws)
            if (self.wsopts[i] === undefined)
                self.wsopts[i] = defws[i];
        
        self.ws = new WebSocket(self.wsopts);
        self.wsopts.port = self.ws.conf('port');
                    

Changes to lib/Jsi_Make.jsi.

182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
...
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
                printf("%*s%S <== TARGET(%S,%S)\n", sublevel*2+4, ' ', m, dst, src);
            if (!m)
                un++;
        }
        return (un !== cnt);
    }

    function fileDirty(target, src) {
        if (!File.exists(target))
            return true;
        return File.mtime(target)<File.mtime(src);
    }
    
    // Return true if dirty.
    function makeTarget(target:string|null, tdeps:string, level=0) {
................................................................................
        debugger;
        puts("Making target: "+tsrc);
        if (!makeTarget(null, tsrc))
            printf("Nothing to do for target '%S'\n", tsrc);
        return 0;
    }
    
    Jsi_Opts(that, options, opts);

    that.makePPLine=makePPLine;
    that.makePushDep=makePushDep;
    that.readDepends=readDepends;
    that.readConf=readConf;
    that.run=run;
    that.which=which;







|







 







|







182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
...
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
                printf("%*s%S <== TARGET(%S,%S)\n", sublevel*2+4, ' ', m, dst, src);
            if (!m)
                un++;
        }
        return (un !== cnt);
    }

    function fileDirty(target:string, src:string) {
        if (!File.exists(target))
            return true;
        return File.mtime(target)<File.mtime(src);
    }
    
    // Return true if dirty.
    function makeTarget(target:string|null, tdeps:string, level=0) {
................................................................................
        debugger;
        puts("Making target: "+tsrc);
        if (!makeTarget(null, tsrc))
            printf("Nothing to do for target '%S'\n", tsrc);
        return 0;
    }
    
    parseOpts(that, options, opts);

    that.makePPLine=makePPLine;
    that.makePushDep=makePushDep;
    that.readDepends=readDepends;
    that.readConf=readConf;
    that.run=run;
    that.which=which;

Changes to lib/Jsi_Markdeep.jsi.

1
2
3
4
5



6
7
8
9
10
11
12
13
14
15
16
17


18
19



20





21
22



23

24
25
26
27
28
29
30
#!/usr/bin/env jsish

function Jsi_Markdeep(files:array|string=null, conf:object=undefined):string|object
{
    var options = { // Add markdeep pre/post tags to input.



        root        :'',        // Url root
        title       :''         // Page title
    };
    var self = {
    };
    parseOpts(self, options, conf);
        
    function parse(files:array) {
        var rc = '';
        for (var i in files) {
            var curFile = files[i];
            var s = File.read(curFile);


            rc += s;
        }



        if (rc.indexOf('<!-- Markdeep: -->')<0)





            rc = '<!-- Markdeep: --><style class="fallback">body{visibility:hidden;}</style>'
                + rc + '<script src="markdeep.min.js"></script>'



                + '<script>window.alreadyProcessedMarkdeep||(document.body.style.visibility="visible")</script>';

        return rc;
    }
    if (typeof(files) === 'string')
        files = [files];
    if (files && files.length)
        return parse(files);
        





>
>
>








|



>
>


>
>
>
|
>
>
>
>
>
|
<
>
>
>

>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

35
36
37
38
39
40
41
42
43
44
45
46
#!/usr/bin/env jsish

function Jsi_Markdeep(files:array|string=null, conf:object=undefined):string|object
{
    var options = { // Add markdeep pre/post tags to input.
        dumpScript  :'',        // Enable dump.
        prefix      :'',        // String to prefix.
        suffix      :'',        // String to suffix.
        root        :'',        // Url root
        title       :''         // Page title
    };
    var self = {
    };
    parseOpts(self, options, conf);
        
    function parse(files:array) {
        var rc = self.prefix;
        for (var i in files) {
            var curFile = files[i];
            var s = File.read(curFile);
            if (rc === '' && self.title === '')
                self.title = File.rootname(File.tail(curFile));
            rc += s;
        }
        var title = '';
        if (self.title !== '')
            title = '<title>'+self.title+'</title>';
        var marker = '<!-- Markdeep: -->',
            add = '';
        if (self.dumpScript !== '')
            add += '<script src="'+self.dumpScript+'"></script>';
        if (rc.indexOf(marker)<0)
            rc = title+'<link rel="stylesheet" href="jsistyle.css" type="text/css" media="screen" />\n'
                + marker + '<style class="fallback">body{visibility:hidden;}</style>\n'

                + '<script>window.markdeepOptions={tocStyle:"medium"}</script>\n'
                + rc
                + add
                + '<script>window.alreadyProcessedMarkdeep||(document.body.style.visibility="visible")</script>';
        rc += self.suffix;
        return rc;
    }
    if (typeof(files) === 'string')
        files = [files];
    if (files && files.length)
        return parse(files);
        

Changes to lib/Jsi_SqliteUI/Jsi_SqliteUI.jsi.

11
12
13
14
15
16
17

18
19
20
21
22
23
24
...
591
592
593
594
595
596
597


598
599
600
601
602
603
604
        Debug       :false,             // LogDebug output.
        Trace       :false,             // LogTrace output.
        closeTimeout:5000,              // Time til exit after close of final client websocket (ms).
        browser     :'',                // Browser program to use.
        dump        :false,             // Dump database.
        foreignkey  :true,              // Enable foreign key constraints.
        integrity   :true,              // Do integrity check on startup.

        local       :true,              // Web server is to listen only on localhost.
        noCheck     :false,             // Disable typechecking.
        noGui       :false,             // Disable starting local browser.
        noUpdate    :false,             // Caller will provide update calls.
        noIO        :false,             // Disable disk io operations, other than to db.
        port        :0,                 // Port, or zero to let OS choose.
        readonly    :false,             // Databases are opened readonly.
................................................................................
            onOpen:WsOpen,
            onCloseLast:CloseLast,
            debug:self.wsdebug,
            extHandlers:true,
            urlRedirect:self.urlPrefix+'/html/main.htmli',
            urlPrefix:'/SqliteUI'
        };


        if (self.server) {
            self.closeTimeout = 0;
            self.noGui = true;
        }
        self.cleanup = cleanup;
        /* Open websockets on first available port. */
        var i, emsg = '';







>







 







>
>







11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
...
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
        Debug       :false,             // LogDebug output.
        Trace       :false,             // LogTrace output.
        closeTimeout:5000,              // Time til exit after close of final client websocket (ms).
        browser     :'',                // Browser program to use.
        dump        :false,             // Dump database.
        foreignkey  :true,              // Enable foreign key constraints.
        integrity   :true,              // Do integrity check on startup.
        isDemo      :false,             // Demo mode to disable certain features.
        local       :true,              // Web server is to listen only on localhost.
        noCheck     :false,             // Disable typechecking.
        noGui       :false,             // Disable starting local browser.
        noUpdate    :false,             // Caller will provide update calls.
        noIO        :false,             // Disable disk io operations, other than to db.
        port        :0,                 // Port, or zero to let OS choose.
        readonly    :false,             // Databases are opened readonly.
................................................................................
            onOpen:WsOpen,
            onCloseLast:CloseLast,
            debug:self.wsdebug,
            extHandlers:true,
            urlRedirect:self.urlPrefix+'/html/main.htmli',
            urlPrefix:'/SqliteUI'
        };
        if (self.local)
            self.wsopts.noCompress = true;
        if (self.server) {
            self.closeTimeout = 0;
            self.noGui = true;
        }
        self.cleanup = cleanup;
        /* Open websockets on first available port. */
        var i, emsg = '';

Changes to lib/Jsi_Websrv.jsi.

123
124
125
126
127
128
129

130
131
132
133
134
135
136
137
138
139
140

141
142
143
144
145
146
147
148
149
150
151
152
153
154




155
156
157
158
159
160
161
162

163
164
165
166
167
168
169
...
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
...
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
...
358
359
360
361
362
363
364


365
366
367
368
369
370
371
...
385
386
387
388
389
390
391


392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
    
    function WsRecv(ws:userobj, id:number, data:string)
    {
        var msg;
        LogDebug("SERVER GOT: "+ id +": "+data);
        var dat;
        if (self.onRecv) {

            dat = JSON.parse(data);
            var ret = self.onRecv(ws, id, dat);
            if (ret) {
                if (typeof(ret) !== 'array' )
                    return WsSend(id, dat.cmd, ret);
                if (ret.length !== 2) throw('array size != 2: '+ret.toString());
                WsSend(id, ret[0], ret[1]);
            }
            return;
        }
        try {

            dat = JSON.parse(data);
            LogDebug("JSON: "+dat.toString());
            switch (dat.cmd) {
                case 'init':
                    msg = InitData(id);
                    LogTrace("MSG:", msg);
                    WsSend(id, 'init', msg);
                    break;
                case 'run':
                    var app = dat.data;
                    require(app);
                    var rv = runModule(app, []);
                    WsSend(id, 'run', rv);
                    break;




                case 'process':     WsSend(id, 'process'); break;
                case 'exit':        DoExit(); break;
                    
                default: LogDebug("unknown cmd:", dat.cmd); break;
            }
        } catch (e) {
          LogDebug("ERROR: "+e);
        }

    }

    function WsUpload(ws:userobj, id:number, filename:string, data:string, startpos:number, complete:boolean)
    {
        LogDebug('QUERY:', self.ws.query(id));
        LogDebug('HDRS:', self.ws.header(id));
        LogDebug('POS='+startpos+' FN='+filename+' DATA:', data);
................................................................................
                return;
            }
        }
        self.done = 1;
    }
    
    function main() {
        var urlarg;
        if (typeof args === 'string')
            args = [args];
        urlarg = args[0];
        args.shift();
        if (urlarg) {
            var fext = File.extension(urlarg);
            var zexts = ['.zip', '.sqlar', '.fossil'];
................................................................................
                self.rootdir = File.dirname(self.url);
            var rlen = self.rootdir.length;
            if (self.url.substr(0, rlen) === self.rootdir)
                self.url = self.url.substr(rlen);
        }
        if (!self.rootdir)
            self.rootdir = '.';
        if (!self.server && !self.pageStr && (!self.url || !File.isfile(self.rootdir+'/'+self.url)))
            throw("url file empty or not found: "+self.url);
        
        // Provide default values for websocket.
        var wo = self.wsopts = {
            local:self.local,
            debug:self.wsdebug,
            extHandler:true,
................................................................................
            onRecv:WsRecv,
            onUpload:WsUpload,
            onFilter:WsFilter,
            port:self.port,
            rootdir:self.rootdir,
            urlPrefix:self.urlPrefix
        };


        if (self.server) {
            self.noGui = true;
            if (self.timeout !== options.timeout)
                self.timeout = 0;
        }
        switch (self.mode) {
            case 'admin':
................................................................................
            wo.onGet=WebGetString;
        }
        if (self.useridPass != '') {
            wo.useridPass = self.useridPass;
            if (self.useridPass === ':') // Exercise onAuth callback.
                wo.onAuth = WsAuth;
        }


        for (var i in self.wsOpts)
            wo[i] = self.wsOpts[i];

        OpenWebsock();
        
        var nargs = null;
       // if (self.noCheck)
       //     nargs = '{noCheck:true}';
       // self.ws.handler('.htmli', 'Jsi_Htmlpp', null);  // Associate .htmli with Web Pre-Processor (for. <? ... ?> tags).
       // self.ws.handler('.jsi',   'Jsi_Jspp',   nargs); // Associate .jsi with Pre-Processor for types.
       // self.ws.handler('.cssi',  'Jsi_Csspp',  null);  // Associate .cssi with Pre-Processor for css.
        LogDebug("Listening on port: "+self.port);
        
        if (!self.noGui && self.url && self.url.length) {
            OpenBrowser(self.url, self.anchor, self.query);
        }

        if (self.noWait) {







>











>

<












>
>
>
>



|


|

>







 







|







 







|







 







>
>







 







>
>



|
<
<
<
<
<
<
<







123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143

144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
...
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
...
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
...
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
...
393
394
395
396
397
398
399
400
401
402
403
404
405







406
407
408
409
410
411
412
    
    function WsRecv(ws:userobj, id:number, data:string)
    {
        var msg;
        LogDebug("SERVER GOT: "+ id +": "+data);
        var dat;
        if (self.onRecv) {
            LogDebug('Self');
            dat = JSON.parse(data);
            var ret = self.onRecv(ws, id, dat);
            if (ret) {
                if (typeof(ret) !== 'array' )
                    return WsSend(id, dat.cmd, ret);
                if (ret.length !== 2) throw('array size != 2: '+ret.toString());
                WsSend(id, ret[0], ret[1]);
            }
            return;
        }
        try {
            LogDebug("JSON: "+data.length);
            dat = JSON.parse(data);

            switch (dat.cmd) {
                case 'init':
                    msg = InitData(id);
                    LogTrace("MSG:", msg);
                    WsSend(id, 'init', msg);
                    break;
                case 'run':
                    var app = dat.data;
                    require(app);
                    var rv = runModule(app, []);
                    WsSend(id, 'run', rv);
                    break;
                case 'save': 
                    var file = File.tail(dat.url)+'.save';
                    File.write(file, dat.data);
                    break;
                case 'process':     WsSend(id, 'process'); break;
                case 'exit':        DoExit(); break;
                    
                default: LogWarn("unknown cmd:", dat.cmd); break;
            }
        } catch (e) {
          LogWarn("ERROR: "+e);
        }
        LogDebug("Done");
    }

    function WsUpload(ws:userobj, id:number, filename:string, data:string, startpos:number, complete:boolean)
    {
        LogDebug('QUERY:', self.ws.query(id));
        LogDebug('HDRS:', self.ws.header(id));
        LogDebug('POS='+startpos+' FN='+filename+' DATA:', data);
................................................................................
                return;
            }
        }
        self.done = 1;
    }
    
    function main() {
        var urlarg, urlOrig = self.url;
        if (typeof args === 'string')
            args = [args];
        urlarg = args[0];
        args.shift();
        if (urlarg) {
            var fext = File.extension(urlarg);
            var zexts = ['.zip', '.sqlar', '.fossil'];
................................................................................
                self.rootdir = File.dirname(self.url);
            var rlen = self.rootdir.length;
            if (self.url.substr(0, rlen) === self.rootdir)
                self.url = self.url.substr(rlen);
        }
        if (!self.rootdir)
            self.rootdir = '.';
        if (!self.server && !self.pageStr && urlOrig=='' && (!self.url || !File.isfile(self.rootdir+'/'+self.url)))
            throw("url file empty or not found: "+self.url);
        
        // Provide default values for websocket.
        var wo = self.wsopts = {
            local:self.local,
            debug:self.wsdebug,
            extHandler:true,
................................................................................
            onRecv:WsRecv,
            onUpload:WsUpload,
            onFilter:WsFilter,
            port:self.port,
            rootdir:self.rootdir,
            urlPrefix:self.urlPrefix
        };
        if (self.local)
            wo.noCompress = true;
        if (self.server) {
            self.noGui = true;
            if (self.timeout !== options.timeout)
                self.timeout = 0;
        }
        switch (self.mode) {
            case 'admin':
................................................................................
            wo.onGet=WebGetString;
        }
        if (self.useridPass != '') {
            wo.useridPass = self.useridPass;
            if (self.useridPass === ':') // Exercise onAuth callback.
                wo.onAuth = WsAuth;
        }
        if (typeof self.wsOpts === 'string')
            self.wsOpts = JSON.parse(self.wsOpts, false);
        for (var i in self.wsOpts)
            wo[i] = self.wsOpts[i];

        OpenWebsock();        







        LogDebug("Listening on port: "+self.port);
        
        if (!self.noGui && self.url && self.url.length) {
            OpenBrowser(self.url, self.anchor, self.query);
        }

        if (self.noWait) {

Changes to lib/templates/WebApp.jsi.

3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
..
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
..
92
93
94
95
96
97
98


99
100


101
102
103
104
105
106
107
require('WebSocket');

function WebApp(args:array|string=void, conf:object=void) {
    
    var self = { done:false };
    var options = { // A  WebSocket server module
        file        :'html/main.htmli', // Source file.
        local       :true,      // Connection listens only on localhost.
        port        :0,             // Port number for server.
        quiet       :false,         // No info messages.
        rootdir     :'',            // Root directory
        server      :false,         // Just the server: do not open a browser.
        useridPass  :'',            // USER:PASS for web GUI.
        wsdebug     :0,             // WebSockets debug level.
        wsOpts      :{}             // WebSockets options.
................................................................................
        } else if (self.rootdir === '')
            self.rootdir=File.realpath(File.dirname(req.loadFile));

        if (!File.exists(self.rootdir+'/'+self.file))
            throw('file not found: '+self.file);

        var wsopts = {
            local:self.local,
            rootdir     :self.rootdir, 
            port        :self.port,
            debug       :self.wsdebug,
            onFilter    :onFilter,
            onCloseLast :onCloseLast,
            onRecv      :onRecv,
            onOpen      :onOpen,
................................................................................
            urlPrefix   :'/'+mod
            //onAuth      :onAuth,
            //onGet       :onGet,
            //onUnknown   :onUnknown,
            //onUpload    :onUpload,
            //getRegex    :/^\/admin/,
        };


        if (self.useridPass !== '')
            wsopts.useridPass = self.useridPass;


        for (var i in self.wsOpts)
            wsopts[i] = self.wsOpts[i];
        LogDebug("Starting:", conf, wsopts);
        debugger;
        self.ws = new WebSocket( wsopts );
        if (!self.port)
            self.port = self.ws.conf('port');







|







 







|







 







>
>


>
>







3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
..
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
..
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
require('WebSocket');

function WebApp(args:array|string=void, conf:object=void) {
    
    var self = { done:false };
    var options = { // A  WebSocket server module
        file        :'html/main.htmli', // Source file.
        local       :true,          // Connection listens only on localhost.
        port        :0,             // Port number for server.
        quiet       :false,         // No info messages.
        rootdir     :'',            // Root directory
        server      :false,         // Just the server: do not open a browser.
        useridPass  :'',            // USER:PASS for web GUI.
        wsdebug     :0,             // WebSockets debug level.
        wsOpts      :{}             // WebSockets options.
................................................................................
        } else if (self.rootdir === '')
            self.rootdir=File.realpath(File.dirname(req.loadFile));

        if (!File.exists(self.rootdir+'/'+self.file))
            throw('file not found: '+self.file);

        var wsopts = {
            local       :self.local,
            rootdir     :self.rootdir, 
            port        :self.port,
            debug       :self.wsdebug,
            onFilter    :onFilter,
            onCloseLast :onCloseLast,
            onRecv      :onRecv,
            onOpen      :onOpen,
................................................................................
            urlPrefix   :'/'+mod
            //onAuth      :onAuth,
            //onGet       :onGet,
            //onUnknown   :onUnknown,
            //onUpload    :onUpload,
            //getRegex    :/^\/admin/,
        };
        if (self.local)
            wsopts.noCompress = true;
        if (self.useridPass !== '')
            wsopts.useridPass = self.useridPass;
        if (typeof self.wsOpts === 'string')
            self.wsOpts = JSON.parse(self.wsOpts, false);
        for (var i in self.wsOpts)
            wsopts[i] = self.wsOpts[i];
        LogDebug("Starting:", conf, wsopts);
        debugger;
        self.ws = new WebSocket( wsopts );
        if (!self.port)
            self.port = self.ws.conf('port');

Changes to lib/web/jsiweb.js.

132
133
134
135
136
137
138














139
140
141
142
143
                    case Array: return "array"; 
                    case RegExp: return "regexp";
                    case Object: return "object";
                    default: return "userobj";
                }
            default: return "any";
        }














    }
};

var Jsi = new __Jsi();








>
>
>
>
>
>
>
>
>
>
>
>
>
>





132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
                    case Array: return "array"; 
                    case RegExp: return "regexp";
                    case Object: return "object";
                    default: return "userobj";
                }
            default: return "any";
        }
    },
    
    SaveFile(filename, data, mime) {
        var blob = new Blob([data], {type: (mime?mime:'text/html')});
        if(window.navigator.msSaveOrOpenBlob) {
            window.navigator.msSaveBlob(blob, filename);
        } else {
            var elem = window.document.createElement('a');
            elem.href = window.URL.createObjectURL(blob);
            elem.download = filename;
            document.body.appendChild(elem);
            elem.click();
            document.body.removeChild(elem);
        }
    }
};

var Jsi = new __Jsi();

Changes to lib/web/markdeep.min.js.

cannot compute difference between binary files

Changes to src/jsi.c.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
...
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
...
459
460
461
462
463
464
465

466
467
468
469
470
471
472
...
626
627
628
629
630
631
632

633
634
635
636
637
638
639
.....
26574
26575
26576
26577
26578
26579
26580
26581
26582
26583
26584
26585
26586
26587
26588
.....
26618
26619
26620
26621
26622
26623
26624

26625
26626
26627
26628
26629
26630
26631
.....
36985
36986
36987
36988
36989
36990
36991















36992
36993
36994
36995
36996
36997
36998
.....
44007
44008
44009
44010
44011
44012
44013

44014

44015
44016
44017
44018
44019
44020
44021
.....
50430
50431
50432
50433
50434
50435
50436
50437
50438
50439
50440
50441
50442
50443
50444
.....
50578
50579
50580
50581
50582
50583
50584
50585
50586
50587
50588
50589
50590
50591
50592
.....
50598
50599
50600
50601
50602
50603
50604
50605
50606
50607
50608
50609
50610
50611
50612
.....
50621
50622
50623
50624
50625
50626
50627

50628
50629
50630
50631
50632
50633
50634
.....
51078
51079
51080
51081
51082
51083
51084
51085






































































51086
51087
51088
51089
51090
51091
51092
51093
51094
51095
51096
51097
51098
51099

51100
51101
51102
51103
51104
51105
51106
.....
51229
51230
51231
51232
51233
51234
51235
51236



51237
51238
51239
51240
51241
51242
51243
51244
51245
51246
51247
51248
51249
51250
51251
51252
51253
51254
51255
51256
51257
51258
51259
51260
51261
51262
51263
51264
51265
51266
51267

51268











51269





51270




51271
51272
51273
51274
51275
51276
51277
.....
51375
51376
51377
51378
51379
51380
51381
51382
51383
51384
51385
51386
51387
51388
51389
51390




51391
51392
51393
51394
51395
51396
51397
.....
51466
51467
51468
51469
51470
51471
51472
51473
51474
51475
51476
51477
51478
51479
51480
51481
51482
51483
51484
51485
51486
51487
51488




51489
51490
51491
51492
51493
51494
51495
51496
51497
51498
51499
51500
51501
51502
51503
51504
51505

51506
51507
51508
51509
51510
51511
51512
.....
52769
52770
52771
52772
52773
52774
52775

52776
52777
52778
52779
52780
52781
52782
.....
52794
52795
52796
52797
52798
52799
52800
52801
52802
52803
52804
52805
52806
52807
52808
52809
.....
52905
52906
52907
52908
52909
52910
52911
52912
52913
52914
52915
52916
52917
52918
52919
52920
52921
52922
.....
65106
65107
65108
65109
65110
65111
65112

65113
65114
65115
65116
65117
65118
65119
.....
65262
65263
65264
65265
65266
65267
65268



65269
65270
65271
65272
65273
65274
65275
65276

65277
65278
65279
65280
65281
65282
65283
65284
65285
65286
65287
/* jsi.h : External API header file for Jsi. */
#ifndef __JSI_H__
#define __JSI_H__

#define JSI_VERSION_MAJOR   2
#define JSI_VERSION_MINOR   6
#define JSI_VERSION_RELEASE 0

#define JSI_VERSION (JSI_VERSION_MAJOR + ((Jsi_Number)JSI_VERSION_MINOR/100.0) + ((Jsi_Number)JSI_VERSION_RELEASE/10000.0))

#ifndef JSI_EXTERN
#define JSI_EXTERN extern
#endif

................................................................................
JSI_EXTERN int Jsi_Strcmp(const char *str1, const char *str2); /*STUB = 26*/
JSI_EXTERN int Jsi_Strncmp(const char *str1, const char *str2, int n); /*STUB = 27*/
JSI_EXTERN int Jsi_Strncasecmp(const char *str1, const char *str2, int n); /*STUB = 28*/
JSI_EXTERN int Jsi_StrcmpDict(const char *str1, const char *str2, int nocase, int dict); /*STUB = 29*/
JSI_EXTERN char* Jsi_Strcpy(char *dst, const char *src); /*STUB = 30*/
JSI_EXTERN char* Jsi_Strncpy(char *dst, const char *src, int len); /*STUB = 31*/
JSI_EXTERN char* Jsi_Strdup(const char *n); /*STUB = 32*/
JSI_EXTERN char* Jsi_StrdupLen(const char *str, int len); /*STUB = 407*/ /*LAST*/
JSI_EXTERN char* Jsi_Strrchr(const char *str, int c); /*STUB = 33*/
JSI_EXTERN char* Jsi_Strstr(const char *str, const char *sub); /*STUB = 34*/
JSI_EXTERN char* Jsi_Strrstr(const char *str, const char *sub); /*STUB = 233*/ 
JSI_EXTERN int Jsi_ObjArraySizer(Jsi_Interp *interp, Jsi_Obj *obj, uint n); /*STUB = 35*/
JSI_EXTERN char* Jsi_Strchr(const char *str, int c); /*STUB = 36*/
JSI_EXTERN int Jsi_Strpos(const char *str, int start, const char *nid, int nocase); /*STUB = 37*/
JSI_EXTERN int Jsi_Strrpos(const char *str, int start, const char *nid, int nocase); /*STUB = 38*/
................................................................................

JSI_EXTERN Jsi_Value* Jsi_ValueNewNull(Jsi_Interp *interp); /*STUB = 100*/
JSI_EXTERN Jsi_Value* Jsi_ValueNewBoolean(Jsi_Interp *interp, int bval); /*STUB = 101*/
JSI_EXTERN Jsi_Value* Jsi_ValueNewNumber(Jsi_Interp *interp, Jsi_Number n); /*STUB = 102*/
JSI_EXTERN Jsi_Value* Jsi_ValueNewBlob(Jsi_Interp *interp, uchar *s, uint len); /*STUB = 103*/
JSI_EXTERN Jsi_Value* Jsi_ValueNewString(Jsi_Interp *interp, const char *s, int len); /*STUB = 104*/
JSI_EXTERN Jsi_Value* Jsi_ValueNewStringKey(Jsi_Interp *interp, const char *s); /*STUB = 105*/

JSI_EXTERN Jsi_Value* Jsi_ValueNewStringDup(Jsi_Interp *interp, const char *s); /*STUB = 106*/
JSI_EXTERN Jsi_Value* Jsi_ValueNewArray(Jsi_Interp *interp, const char **items, int count); /*STUB = 107*/
JSI_EXTERN Jsi_Value* Jsi_ValueNewObj(Jsi_Interp *interp, Jsi_Obj *o) ; /*STUB = 108*/
#define Jsi_ValueNewBlobString(interp, s) Jsi_ValueNewBlob(interp, (uchar*)s, Jsi_Strlen(s))

JSI_EXTERN Jsi_RC Jsi_GetStringFromValue(Jsi_Interp* interp, Jsi_Value *value, const char **s); /*STUB = 109*/
JSI_EXTERN Jsi_RC Jsi_GetNumberFromValue(Jsi_Interp* interp, Jsi_Value *value, Jsi_Number *n); /*STUB = 110*/
................................................................................
    Jsi_CHash_SHA3_384, Jsi_CHash_SHA3_512, Jsi_CHash_SHA3_256 } Jsi_CryptoHashType;

JSI_EXTERN Jsi_RC Jsi_Encrypt(Jsi_Interp *interp, Jsi_DString *inout, const char *key, uint keyLen, bool decrypt); /*STUB = 229*/
JSI_EXTERN Jsi_RC Jsi_CryptoHash(char *outbuf, const char *str, int len, Jsi_CryptoHashType type, uint strength, bool noHex, int *sizPtr); /*STUB = 230*/
JSI_EXTERN Jsi_RC Jsi_Base64(const char *str, int len, Jsi_DString *buf, bool decode); /*STUB = 231*/
JSI_EXTERN int Jsi_HexStr(const uchar *data, int len, Jsi_DString *dStr, bool decode); /*STUB = 232*/
JSI_EXTERN uint32_t Jsi_Crc32(uint32_t crc, const void *ptr, size_t buf_len); /*STUB = 234*/


JSI_EXTERN int Jsi_NumberIsInfinity(Jsi_Number a);  /*STUB = 235*/
JSI_EXTERN bool Jsi_NumberIsEqual(Jsi_Number n1, Jsi_Number n2);  /*STUB = 236*/
JSI_EXTERN bool Jsi_NumberIsFinite(Jsi_Number value);  /*STUB = 237*/
JSI_EXTERN bool Jsi_NumberIsInteger(Jsi_Number n);  /*STUB = 238*/
JSI_EXTERN bool Jsi_NumberIsNaN(Jsi_Number a);  /*STUB = 239*/
JSI_EXTERN bool Jsi_NumberIsNormal(Jsi_Number a);  /*STUB = 240*/
................................................................................
        return Jsi_LogError("expected even length array");
    if (argc>(skip+1) && Jsi_ValueGetBoolean(interp, Jsi_ValueArrayIndex(interp, args, skip+1), &nocase) != JSI_OK) 
        return Jsi_LogError("expected boolean");
    Jsi_DString dStr;
    Jsi_DSInit(&dStr);
    Jsi_Obj *obj = repVal->d.obj;
    p = source_str;
    for (j=0; j<(uint)source_len; j++, p++) {
        for (i=0; i<obj->arrCnt; i+=2) {
            if (!obj->arr[i]) continue;
            if (!obj->arr[i+1]) continue;
            const char *cp = Jsi_ValueToString(interp, obj->arr[i], &slen);
            int res = (nocase ? Jsi_Strncasecmp(cp, p, slen) : Jsi_Strncmp(cp, p, slen));
            if (!res) {
                replace_str = Jsi_ValueToString(interp, obj->arr[i+1], &replace_len);
................................................................................
    Jsi_Regex *re;
    const char *p;
    int maxArgs = 1;

    int offset = 0, n, j, opt_all = 0, num_matches = 0;
    /* Is a generic  String.replace if _this->d.obj is a function */
    ChkString(_this, funcPtr, source_str, &source_len, &bLen);

    if (!skip)
        strVal = _this;
    else
        strVal = Jsi_ValueArrayIndex(interp, args, 0);
    seq = Jsi_ValueArrayIndex(interp, args, skip);
    Jsi_Value *repVal = Jsi_ValueArrayIndex(interp, args, 1+skip);
    if (!Jsi_ValueIsFunction(interp, repVal))
................................................................................
    Jsi_Value *modv = Jsi_ValueArrayIndex(interp, args, 1);
    Jsi_Number fmod;
    if (Jsi_GetNumberFromValue(interp, modv, &fmod) != JSI_OK)
        return JSI_ERROR;
    SAFEACCESS(fname, 1)
    return (Jsi_Chmod(interp, fname, (unsigned int)fmod) == 0 ? JSI_OK : JSI_ERROR);
}
















static Jsi_RC FileReadCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this,
    Jsi_Value **ret, Jsi_Func *funcPtr) /* TODO limit. */
{   
    Jsi_Value *fname = Jsi_ValueArrayIndex(interp, args, 0);
    Jsi_Value *vmode = Jsi_ValueArrayIndex(interp, args, 1);
    const char *mode = (vmode ? Jsi_ValueString(interp, vmode, NULL) : NULL);
................................................................................
                ustart = m;
                ulen = e+l-1;
            }
        }
    }
#endif
    if (ulen>len) {

        fprintf(stderr, "TODO: fix utf substr\n");

        ulen = len;
    }
    Jsi_DSAppendLen(dStr, str+ustart, ulen);
    return Jsi_DSValue(dStr);
}

int Jsi_UtfIndexToOffset(const char *str, int index)
................................................................................
    jsi_wsStatData stats;
    char *iface;
    const char* urlPrefix, *urlRedirect;
    const char *localhostName;
    const char *clientName;
    const char *clientIP;
    const char *useridPass;
    const char *realm;
    struct lws_context *instCtx;
    Jsi_Value *getRegexp, *post;
    unsigned int oldus;
    int opts;
    int hasOpts;
    int debug;
    int maxConnects;
................................................................................
    JSI_OPT(DSTRING,    jsi_wsPss, url,         .help="Url for connection"),
    JSI_OPT_END(jsi_wsPss, .help="Per-connection options")
};

static Jsi_OptionSpec WSOptions[] =
{
    JSI_OPT(STRING, jsi_wsCmdObj, address,    .help="In client-mode the address to connect to (127.0.0.1)" ),
    JSI_OPT(INT,    jsi_wsCmdObj, bufferPwr2, .help="Tune the recv/send buffer: value is a power of 2 (0-20)"),
    JSI_OPT(BOOL,   jsi_wsCmdObj, client,     .help="Run in client mode", jsi_IIOF),
    JSI_OPT(STRKEY, jsi_wsCmdObj, clientHost, .help="Override host name for client"),
    JSI_OPT(STRKEY, jsi_wsCmdObj, clientOrigin,.help="Override client origin (origin)"),
    JSI_OPT(INT,    jsi_wsCmdObj, debug,      .help="Set debug level. Setting this to 512 will turn on max libwebsocket log levels"),
    JSI_OPT(BOOL,   jsi_wsCmdObj, echo,       .help="LogInfo outputs all websock Send/Recv messages"),
    JSI_OPT(STRKEY, jsi_wsCmdObj, formParams, .help="Comma seperated list of upload form param names ('text,send,file,upload')", jsi_IIRO),
    JSI_OPT(OBJ,    jsi_wsCmdObj, extArgs,    .help="Arguments for extension handlers", jsi_IIOF),
................................................................................
    JSI_OPT(BOOL,   jsi_wsCmdObj, local,      .help="Limit connections to localhost addresses on the 127 network"),
    JSI_OPT(STRKEY, jsi_wsCmdObj, localhostName,.help="Client name used by localhost connections ('localhost')"),
    JSI_OPT(INT,    jsi_wsCmdObj, maxConnects,.help="In server mode, max number of client connections accepted"),
    JSI_OPT(INT,    jsi_wsCmdObj, maxDownload,.help="Max size of file download"),
    JSI_OPT(INT,    jsi_wsCmdObj, maxUpload,  .help="Max size of file upload will accept"),
    JSI_OPT(OBJ,    jsi_wsCmdObj, mimeTypes,  .help="Object providing map of file extensions to mime types (eg. {txt:'text/plain', bb:'text/bb'})", jsi_IIOF),
    JSI_OPT(BOOL,   jsi_wsCmdObj, noConfig,   .help="Disable use of conf() to change options after options after create", jsi_IIOF),
    JSI_OPT(BOOL,   jsi_wsCmdObj, noCompress, .help="Disable per-message-deflate extension"),
    JSI_OPT(BOOL,   jsi_wsCmdObj, noUpdate,   .help="Disable update event-processing (eg. to exit)"),
    JSI_OPT(BOOL,   jsi_wsCmdObj, noWebsock,  .help="Serve html, but disallow websocket upgrade", jsi_IIOF),
    JSI_OPT(BOOL,   jsi_wsCmdObj, noWarn,     .help="Quietly ignore file related errors"),
    JSI_OPT(FUNC,   jsi_wsCmdObj, onAuth,     .help="Function to call for http basic authentication", .flags=0, .custom=0, .data=(void*)"ws:userobj, id:number, url:string, userpass:string"),
    JSI_OPT(FUNC,   jsi_wsCmdObj, onClose,    .help="Function to call when the websocket connection closes", .flags=0, .custom=0, .data=(void*)"ws:userobj|null, id:number"),
    JSI_OPT(FUNC,   jsi_wsCmdObj, onCloseLast,.help="Function to call when last websock connection closes. On object delete arg is null", .flags=0, .custom=0, .data=(void*)"ws:userobj|null"),
    JSI_OPT(FUNC,   jsi_wsCmdObj, onFilter,   .help="Function to call on a new connection: return false to kill connection", .flags=0, .custom=0, .data=(void*)"ws:userobj, id:number, url:string, ishttp:boolean"),
................................................................................
    JSI_OPT(STRKEY, jsi_wsCmdObj, realm,      .help="Realm for basic auth (jsish)", ),
    JSI_OPT(INT,    jsi_wsCmdObj, recvBufMax, .help="Size limit of a websocket message", jsi_IIOF),
    JSI_OPT(INT,    jsi_wsCmdObj, recvBufTimeout,.help="Timeout for recv of a websock msg", jsi_IIOF),
    JSI_OPT(BOOL,   jsi_wsCmdObj, redirMax,   .help="Temporarily disable redirects when see more than this in 10 minutes"),
    JSI_OPT(STRING, jsi_wsCmdObj, rootdir,    .help="Directory to serve html from (\".\")"),
    JSI_OPT(CUSTOM, jsi_wsCmdObj, stats,      .help="Statistical data", jsi_IIRO, .custom=Jsi_Opt_SwitchSuboption, .data=WPSStats),
    JSI_OPT(TIME_T, jsi_wsCmdObj, startTime,  .help="Time of websocket start", jsi_IIRO),

    JSI_OPT(STRKEY, jsi_wsCmdObj, urlPrefix,  .help="Prefix in url to strip from path; for reverse proxy"),
    JSI_OPT(STRKEY, jsi_wsCmdObj, urlRedirect,.help="Redirect when no url or / is given. Must match urlPrefix, if given"),
    JSI_OPT(BOOL,   jsi_wsCmdObj, use_ssl,    .help="Use https (for client)", jsi_IIOF),
    JSI_OPT(STRKEY, jsi_wsCmdObj, useridPass, .help="The USERID:PASSWORD to use for basic authentication"),
    JSI_OPT(OBJ,    jsi_wsCmdObj, version,    .help="WebSocket version info", jsi_IIRO),
    JSI_OPT_END(jsi_wsCmdObj, .help="Websocket options")
};
................................................................................
            if (n>0)
                Jsi_DSAppendLen(hStr, (char*)buffer, n);
            p = buffer;
        }
    }
    return true;
}







































































// Handle http GET/POST
static int jsi_wsHttp(Jsi_Interp *interp, jsi_wsCmdObj *cmdPtr, struct lws *wsi, void *user,
    struct lws_context *context, const char* inPtr, Jsi_DString *tStr, jsi_wsPss *pss)
{
    const char *ext = NULL;
    unsigned char buffer[JSI_BUFSIZ];
    const char *mime = "text/html";
    time_t now = time(NULL);
    char buf[JSI_BUFSIZ];
    int rc = 0;
    buf[0] = 0;
    uchar *p = buffer, *end = &buffer[sizeof(buffer)-1];
    int n;
    Jsi_Value* fname = NULL;


    /* if a legal POST URL, let it continue and accept data */
    if (lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI))
        return 0;
    if (!pss)
        pss = jsi_wsgetPss(cmdPtr, wsi, user, 1, 1);
  
................................................................................
#endif

    snprintf(buf, sizeof(buf), "%s/%s", rootDir, inPtr);
    if (cmdPtr->debug>1)
        fprintf(stderr, "FILE: %s in %s | %s\n", buf, rootDir, Jsi_ValueString(interp, cmdPtr->rootdir, NULL));
    char extBuf[100];
    bool isgzip = 0;
    if (ext) {



        uint elen = Jsi_Strlen(ext);
        if (elen>3 && elen<(sizeof(extBuf)-10) && !Jsi_Strcmp(ext+elen-3,".gz")) {
            Jsi_Strcpy(extBuf, ext);
            extBuf[elen-3] = 0;
            char *ext2 = Jsi_Strrchr(extBuf, '.');
            if (ext2) {
                isgzip = 1;
                ext = ext2;
            }
        }
        Jsi_HashEntry *hPtr;

        if (Jsi_Strncasecmp(ext,".html", -1) == 0) mime = "text/html";
        else if (Jsi_Strncasecmp(ext,".js", -1) == 0) mime = "application/x-javascript";
        else if (Jsi_Strncasecmp(ext,".css", -1) == 0) mime = "text/css";
        else if (Jsi_Strncasecmp(ext,".htmli", -1) == 0) mime = "text/html";
        else if (Jsi_Strncasecmp(ext,".md", -1) == 0) mime = "text/html";
        else if (Jsi_Strncasecmp(ext,".jsi", -1) == 0) mime = "application/x-javascript";
        else if (Jsi_Strncasecmp(ext,".cssi", -1) == 0) mime = "text/css";
        else if (Jsi_Strncasecmp(ext,".png", -1) == 0) mime = "image/png";
        else if (Jsi_Strncasecmp(ext,".ico", -1) == 0) mime = "image/icon";
        else if (Jsi_Strncasecmp(ext,".gif", -1) == 0) mime = "image/gif";
        else if (Jsi_Strncasecmp(ext,".jpeg", -1) == 0) mime = "image/jpeg";
        else if (Jsi_Strncasecmp(ext,".jpg", -1) == 0) mime = "image/jpeg";
        else if (Jsi_Strncasecmp(ext,".svg", -1) == 0) mime = "image/svg+xml";
        else if (Jsi_Strncasecmp(ext,".json", -1) == 0) mime = "application/json";
        else if (Jsi_Strncasecmp(ext,".txt", -1) == 0) mime = "text/plain";
        else if (cmdPtr->mimeTypes) {
            /* Lookup mime type in mimeTypes object. */
            const char *nmime;
            Jsi_Value *mVal = Jsi_ValueObjLookup(interp, cmdPtr->mimeTypes, ext+1, 1);

            if (mVal && ((nmime = Jsi_ValueString(interp, mVal, NULL))))











                mime = nmime;





        }




        
        if ((hPtr = Jsi_HashEntryFind(cmdPtr->handlers, ext)) && !cmdPtr->deleted) {
            /* Use interprete html eg. using jsi_wpp preprocessor */
            Jsi_DString jStr = {};
            Jsi_Value *vrc = NULL;
            int hrc = 0, strLen, evrc, isalloc=0;
            char *vStr, *hstr = NULL;
................................................................................
            if (hrc<=0)
                return -1;
            return 1;
        }
    }
    if (!buf[0]) {
        if (cmdPtr->debug)
            fprintf(stderr, "Unknown file: %s\n", inPtr);
        return -1;
    }
    fname = Jsi_ValueNewStringDup(interp, buf);
    Jsi_IncrRefCount(interp, fname);
    
    Jsi_DString hStr = {};
    Jsi_StatBuf jsb;
    bool native = Jsi_FSNative(interp, fname);




    if ((native && Jsi_InterpSafe(interp) && Jsi_InterpAccess(interp, fname, JSI_INTACCESS_READ) != JSI_OK) ||
        (Jsi_Stat(interp, fname, &jsb) || jsb.st_size<=0)) {
nofile:
        if (cmdPtr->onUnknown || pss->onUnknown) {
            Jsi_Value *uk = (pss->onUnknown?pss->onUnknown:cmdPtr->onUnknown);
            Jsi_RC jrc = jsi_wsGetCmd(interp, cmdPtr, pss, wsi, inPtr, uk, NULL);
            if (jrc == JSI_ERROR)
................................................................................
        goto bail;
        
    if (pss->headers && !jsi_wsAddHeader(interp, cmdPtr, wsi, pss->headers, &hStr))
        goto bail;

    n = Jsi_DSLength(&hStr);
    
    if (native) {
        Jsi_DecrRefCount(interp, fname);

        int hrc = lws_serve_http_file(wsi, buf, mime, Jsi_DSValue(&hStr), Jsi_DSLength(&hStr));
        if (hrc<0) {
            if (cmdPtr->noWarn==0)
                fprintf(stderr, "can not serve file (%d): %s\n", hrc, buf);
            goto bail;
        } else if (hrc > 0 && lws_http_transaction_completed(wsi))
            goto bail;
    } else {
        // Need to read data for non-native files.
        Jsi_Channel chan = Jsi_Open(interp, fname, "rb");
        int n, sum = 0;

        if (!chan) {




            goto nofile;
        }
        Jsi_DString dStr = {};
        char sbuf[JSI_BUFSIZ];
        int hrc = jsi_wsServeHeader(pss, wsi, (int)jsb.st_size, 200, Jsi_DSValue(&hStr), mime, &dStr);
        if (hrc>=0) {
            while (sum < 10000000 && (n = Jsi_Read(interp, chan, sbuf, sizeof(sbuf))) > 0) {
                Jsi_DSAppendLen(&dStr, sbuf, n);
                sum += n;
            }
            char *str = Jsi_DSValue(&dStr);
            int strLen = Jsi_DSLength(&dStr);
            hrc = jsi_wswrite(pss, wsi, (unsigned char*)str, strLen, LWS_WRITE_HTTP);
        }
        Jsi_DecrRefCount(interp, fname);
        Jsi_Close(interp, chan);
        Jsi_DSFree(&dStr);

        if (hrc<0) {
            if (cmdPtr->noWarn==0)
                fprintf(stderr, "can not serve data (%d): %s\n", hrc, buf);
            goto bail;
        } else if (hrc > 0 && lws_http_transaction_completed(wsi))
            goto bail;

................................................................................
    cmdPtr->interp = interp;
    cmdPtr->ietf_version = -1;
    cmdPtr->bufferPwr2 = 0;
    cmdPtr->ws_gid = -1;
    cmdPtr->ws_uid = -1;
    cmdPtr->startTime = time(NULL);
    cmdPtr->hasOpts = 1;

    if ((arg != NULL && !Jsi_ValueIsNull(interp,arg))
        && Jsi_OptionsProcess(interp, WSOptions, cmdPtr, arg, 0) < 0) {
bail:
        jsi_wswebsocketObjFree(interp, cmdPtr);
        return JSI_ERROR;
    }
    if (cmdPtr->headers && (Jsi_ValueGetLength(interp, cmdPtr->headers)%2)) {
................................................................................
    cmdPtr->protocols[JWS_PROTOCOL_HTTP].name="http-only";
    cmdPtr->protocols[JWS_PROTOCOL_HTTP].callback=jsi_wscallback_http;
    cmdPtr->protocols[JWS_PROTOCOL_HTTP].per_session_data_size=sizeof(jsi_wsPss);
    cmdPtr->protocols[JWS_PROTOCOL_WEBSOCK].name=subprot;
    cmdPtr->protocols[JWS_PROTOCOL_WEBSOCK].callback=jsi_wscallback_websock;
    cmdPtr->protocols[JWS_PROTOCOL_WEBSOCK].per_session_data_size=sizeof(jsi_wsPss);

    if (cmdPtr->bufferPwr2 == 0 && !cmdPtr->noCompress)
        cmdPtr->bufferPwr2 = 12;
    if (cmdPtr->bufferPwr2>0) {
        if (cmdPtr->bufferPwr2>20) {
            Jsi_LogError("bufferPwr2 not in 0-20: %d", cmdPtr->bufferPwr2);
            goto bail;
        }
        cmdPtr->protocols[JWS_PROTOCOL_WEBSOCK].rx_buffer_size=(1<<cmdPtr->bufferPwr2);
    }
................................................................................

    Jsi_Obj *fobj = Jsi_ValueGetObj(interp, toacc);
    if ((cmdPtr->objId = Jsi_UserObjNew(interp, &websockobject, fobj, cmdPtr))<0) {
        goto bail;
    }
    cmdPtr->handlers = Jsi_HashNew(interp, JSI_KEYS_STRING, jsi_wsfreeHandlers);
    if (cmdPtr->extHandlers) {
        jsi_wsHandlerAdd(interp, cmdPtr, ".jsi",   "Jsi_Jspp",   jsi_wsStrValGet(cmdPtr, "jsi"), 1);
        jsi_wsHandlerAdd(interp, cmdPtr, ".htmli", "Jsi_Htmlpp", jsi_wsStrValGet(cmdPtr, "htmli"), 1);
        jsi_wsHandlerAdd(interp, cmdPtr, ".cssi",  "Jsi_Csspp",  jsi_wsStrValGet(cmdPtr, "cssi"), 1);
        jsi_wsHandlerAdd(interp, cmdPtr, ".md",    "Jsi_Markdeep", jsi_wsStrValGet(cmdPtr, "md"), 1);
    }
    cmdPtr->fobj = fobj;
#ifdef LWS_LIBRARY_VERSION_NUMBER
    Jsi_JSONParseFmt(interp, &cmdPtr->version, "{libVer:\"%s\", hdrVer:\"%s\", hdrNum:%d, pkgVer:%d}",
        (char *)lws_get_library_version(), LWS_LIBRARY_VERSION, LWS_LIBRARY_VERSION_NUMBER, jsi_WsPkgVersion); 
#endif
    return JSI_OK;
................................................................................
}

Jsi_RC jsi_evalStrFile(Jsi_Interp* interp, Jsi_Value *path, char *str, int flags, int level)
{
    Jsi_Channel tinput = NULL, input = Jsi_GetStdChannel(interp, 0);
    Jsi_Value *npath = path;
    Jsi_RC rc = JSI_ERROR;

    const char *ustr = NULL, *ostr = str;
    if (Jsi_MutexLock(interp, interp->Mutex) != JSI_OK)
        return rc;
    int oldSp, uskip = 0, fncOfs = 0;
    int oldef = interp->evalFlags;
    jsi_Pstate *oldps = interp->ps;
    const char *oldFile = interp->curFile;
................................................................................
        }
    }

    /* TODO: cleanup interp->framePtr->Sp stuff. */
    oldSp = interp->framePtr->Sp;
    // Evaluate code.
    rc = JSI_OK;



    ps = jsiNewParser(interp, str, input, 0);
    interp->evalFlags = flags;
    if (!ps)
        rc = JSI_ERROR;
    else {
        Jsi_ValueMakeUndef(interp, &interp->retValue);
        interp->ps = ps;
        Jsi_Value *retValue = interp->retValue;

        bool strict = (jsi_GetDirective(interp, ps->opcodes, "use strict")!=NULL);
        const char *cext;
        if (!strict && fname && ((cext=Jsi_Strstr(fname,".jsi"))) && !cext[4])
            strict = 1;
        if (strict) {
            interp->framePtr->strict = 1;
            if (interp->framePtr->level<=1)
                interp->strict = 1;
        }
        const char *curFile = interp->curFile;







|







 







|







 







>







 







>







 







|







 







>







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







>

>







 







|







 







|







 







|







 







>







 








>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>






|


|




>







 







|
>
>
>












<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
|

<

>
|
>
>
>
>
>
>
>
>
>
>
>
|
>
>
>
>
>
|
>
>
>
>







 







|








>
>
>
>







 







|











|
<
<
|
>
>
>
>

<
<
<
|

<
|
<
<
|

|


<

>







 







>







 







|
|







 







|
|
|
|







 







>







 







>
>
>








>
|
<
<
<







1
2
3
4
5
6
7
8
9
10
11
12
13
14
...
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
...
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
...
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
.....
26576
26577
26578
26579
26580
26581
26582
26583
26584
26585
26586
26587
26588
26589
26590
.....
26620
26621
26622
26623
26624
26625
26626
26627
26628
26629
26630
26631
26632
26633
26634
.....
36988
36989
36990
36991
36992
36993
36994
36995
36996
36997
36998
36999
37000
37001
37002
37003
37004
37005
37006
37007
37008
37009
37010
37011
37012
37013
37014
37015
37016
.....
44025
44026
44027
44028
44029
44030
44031
44032
44033
44034
44035
44036
44037
44038
44039
44040
44041
.....
50450
50451
50452
50453
50454
50455
50456
50457
50458
50459
50460
50461
50462
50463
50464
.....
50598
50599
50600
50601
50602
50603
50604
50605
50606
50607
50608
50609
50610
50611
50612
.....
50618
50619
50620
50621
50622
50623
50624
50625
50626
50627
50628
50629
50630
50631
50632
.....
50641
50642
50643
50644
50645
50646
50647
50648
50649
50650
50651
50652
50653
50654
50655
.....
51099
51100
51101
51102
51103
51104
51105
51106
51107
51108
51109
51110
51111
51112
51113
51114
51115
51116
51117
51118
51119
51120
51121
51122
51123
51124
51125
51126
51127
51128
51129
51130
51131
51132
51133
51134
51135
51136
51137
51138
51139
51140
51141
51142
51143
51144
51145
51146
51147
51148
51149
51150
51151
51152
51153
51154
51155
51156
51157
51158
51159
51160
51161
51162
51163
51164
51165
51166
51167
51168
51169
51170
51171
51172
51173
51174
51175
51176
51177
51178
51179
51180
51181
51182
51183
51184
51185
51186
51187
51188
51189
51190
51191
51192
51193
51194
51195
51196
51197
51198
.....
51321
51322
51323
51324
51325
51326
51327
51328
51329
51330
51331
51332
51333
51334
51335
51336
51337
51338
51339
51340
51341
51342
51343















51344
51345

51346
51347
51348
51349
51350
51351
51352
51353
51354
51355
51356
51357
51358
51359
51360
51361
51362
51363
51364
51365
51366
51367
51368
51369
51370
51371
51372
51373
51374
51375
51376
51377
.....
51475
51476
51477
51478
51479
51480
51481
51482
51483
51484
51485
51486
51487
51488
51489
51490
51491
51492
51493
51494
51495
51496
51497
51498
51499
51500
51501
.....
51570
51571
51572
51573
51574
51575
51576
51577
51578
51579
51580
51581
51582
51583
51584
51585
51586
51587
51588
51589


51590
51591
51592
51593
51594
51595



51596
51597

51598


51599
51600
51601
51602
51603

51604
51605
51606
51607
51608
51609
51610
51611
51612
.....
52869
52870
52871
52872
52873
52874
52875
52876
52877
52878
52879
52880
52881
52882
52883
.....
52895
52896
52897
52898
52899
52900
52901
52902
52903
52904
52905
52906
52907
52908
52909
52910
.....
53006
53007
53008
53009
53010
53011
53012
53013
53014
53015
53016
53017
53018
53019
53020
53021
53022
53023
.....
65207
65208
65209
65210
65211
65212
65213
65214
65215
65216
65217
65218
65219
65220
65221
.....
65364
65365
65366
65367
65368
65369
65370
65371
65372
65373
65374
65375
65376
65377
65378
65379
65380
65381
65382
65383



65384
65385
65386
65387
65388
65389
65390
/* jsi.h : External API header file for Jsi. */
#ifndef __JSI_H__
#define __JSI_H__

#define JSI_VERSION_MAJOR   2
#define JSI_VERSION_MINOR   6
#define JSI_VERSION_RELEASE 1

#define JSI_VERSION (JSI_VERSION_MAJOR + ((Jsi_Number)JSI_VERSION_MINOR/100.0) + ((Jsi_Number)JSI_VERSION_RELEASE/10000.0))

#ifndef JSI_EXTERN
#define JSI_EXTERN extern
#endif

................................................................................
JSI_EXTERN int Jsi_Strcmp(const char *str1, const char *str2); /*STUB = 26*/
JSI_EXTERN int Jsi_Strncmp(const char *str1, const char *str2, int n); /*STUB = 27*/
JSI_EXTERN int Jsi_Strncasecmp(const char *str1, const char *str2, int n); /*STUB = 28*/
JSI_EXTERN int Jsi_StrcmpDict(const char *str1, const char *str2, int nocase, int dict); /*STUB = 29*/
JSI_EXTERN char* Jsi_Strcpy(char *dst, const char *src); /*STUB = 30*/
JSI_EXTERN char* Jsi_Strncpy(char *dst, const char *src, int len); /*STUB = 31*/
JSI_EXTERN char* Jsi_Strdup(const char *n); /*STUB = 32*/
JSI_EXTERN char* Jsi_StrdupLen(const char *str, int len); /*STUB = 407*/
JSI_EXTERN char* Jsi_Strrchr(const char *str, int c); /*STUB = 33*/
JSI_EXTERN char* Jsi_Strstr(const char *str, const char *sub); /*STUB = 34*/
JSI_EXTERN char* Jsi_Strrstr(const char *str, const char *sub); /*STUB = 233*/ 
JSI_EXTERN int Jsi_ObjArraySizer(Jsi_Interp *interp, Jsi_Obj *obj, uint n); /*STUB = 35*/
JSI_EXTERN char* Jsi_Strchr(const char *str, int c); /*STUB = 36*/
JSI_EXTERN int Jsi_Strpos(const char *str, int start, const char *nid, int nocase); /*STUB = 37*/
JSI_EXTERN int Jsi_Strrpos(const char *str, int start, const char *nid, int nocase); /*STUB = 38*/
................................................................................

JSI_EXTERN Jsi_Value* Jsi_ValueNewNull(Jsi_Interp *interp); /*STUB = 100*/
JSI_EXTERN Jsi_Value* Jsi_ValueNewBoolean(Jsi_Interp *interp, int bval); /*STUB = 101*/
JSI_EXTERN Jsi_Value* Jsi_ValueNewNumber(Jsi_Interp *interp, Jsi_Number n); /*STUB = 102*/
JSI_EXTERN Jsi_Value* Jsi_ValueNewBlob(Jsi_Interp *interp, uchar *s, uint len); /*STUB = 103*/
JSI_EXTERN Jsi_Value* Jsi_ValueNewString(Jsi_Interp *interp, const char *s, int len); /*STUB = 104*/
JSI_EXTERN Jsi_Value* Jsi_ValueNewStringKey(Jsi_Interp *interp, const char *s); /*STUB = 105*/
JSI_EXTERN Jsi_Value* Jsi_ValueNewStringConst(Jsi_Interp *interp, const char *s, int len); /*STUB = 409*/ /*LAST*/
JSI_EXTERN Jsi_Value* Jsi_ValueNewStringDup(Jsi_Interp *interp, const char *s); /*STUB = 106*/
JSI_EXTERN Jsi_Value* Jsi_ValueNewArray(Jsi_Interp *interp, const char **items, int count); /*STUB = 107*/
JSI_EXTERN Jsi_Value* Jsi_ValueNewObj(Jsi_Interp *interp, Jsi_Obj *o) ; /*STUB = 108*/
#define Jsi_ValueNewBlobString(interp, s) Jsi_ValueNewBlob(interp, (uchar*)s, Jsi_Strlen(s))

JSI_EXTERN Jsi_RC Jsi_GetStringFromValue(Jsi_Interp* interp, Jsi_Value *value, const char **s); /*STUB = 109*/
JSI_EXTERN Jsi_RC Jsi_GetNumberFromValue(Jsi_Interp* interp, Jsi_Value *value, Jsi_Number *n); /*STUB = 110*/
................................................................................
    Jsi_CHash_SHA3_384, Jsi_CHash_SHA3_512, Jsi_CHash_SHA3_256 } Jsi_CryptoHashType;

JSI_EXTERN Jsi_RC Jsi_Encrypt(Jsi_Interp *interp, Jsi_DString *inout, const char *key, uint keyLen, bool decrypt); /*STUB = 229*/
JSI_EXTERN Jsi_RC Jsi_CryptoHash(char *outbuf, const char *str, int len, Jsi_CryptoHashType type, uint strength, bool noHex, int *sizPtr); /*STUB = 230*/
JSI_EXTERN Jsi_RC Jsi_Base64(const char *str, int len, Jsi_DString *buf, bool decode); /*STUB = 231*/
JSI_EXTERN int Jsi_HexStr(const uchar *data, int len, Jsi_DString *dStr, bool decode); /*STUB = 232*/
JSI_EXTERN uint32_t Jsi_Crc32(uint32_t crc, const void *ptr, size_t buf_len); /*STUB = 234*/
JSI_EXTERN Jsi_RC Jsi_FileRead(Jsi_Interp *interp, Jsi_Value *name, Jsi_DString *dStr); /*STUB = 408*/

JSI_EXTERN int Jsi_NumberIsInfinity(Jsi_Number a);  /*STUB = 235*/
JSI_EXTERN bool Jsi_NumberIsEqual(Jsi_Number n1, Jsi_Number n2);  /*STUB = 236*/
JSI_EXTERN bool Jsi_NumberIsFinite(Jsi_Number value);  /*STUB = 237*/
JSI_EXTERN bool Jsi_NumberIsInteger(Jsi_Number n);  /*STUB = 238*/
JSI_EXTERN bool Jsi_NumberIsNaN(Jsi_Number a);  /*STUB = 239*/
JSI_EXTERN bool Jsi_NumberIsNormal(Jsi_Number a);  /*STUB = 240*/
................................................................................
        return Jsi_LogError("expected even length array");
    if (argc>(skip+1) && Jsi_ValueGetBoolean(interp, Jsi_ValueArrayIndex(interp, args, skip+1), &nocase) != JSI_OK) 
        return Jsi_LogError("expected boolean");
    Jsi_DString dStr;
    Jsi_DSInit(&dStr);
    Jsi_Obj *obj = repVal->d.obj;
    p = source_str;
    for (j=0; j<(uint)bLen; j++, p++) {
        for (i=0; i<obj->arrCnt; i+=2) {
            if (!obj->arr[i]) continue;
            if (!obj->arr[i+1]) continue;
            const char *cp = Jsi_ValueToString(interp, obj->arr[i], &slen);
            int res = (nocase ? Jsi_Strncasecmp(cp, p, slen) : Jsi_Strncmp(cp, p, slen));
            if (!res) {
                replace_str = Jsi_ValueToString(interp, obj->arr[i+1], &replace_len);
................................................................................
    Jsi_Regex *re;
    const char *p;
    int maxArgs = 1;

    int offset = 0, n, j, opt_all = 0, num_matches = 0;
    /* Is a generic  String.replace if _this->d.obj is a function */
    ChkString(_this, funcPtr, source_str, &source_len, &bLen);
    source_len = bLen;
    if (!skip)
        strVal = _this;
    else
        strVal = Jsi_ValueArrayIndex(interp, args, 0);
    seq = Jsi_ValueArrayIndex(interp, args, skip);
    Jsi_Value *repVal = Jsi_ValueArrayIndex(interp, args, 1+skip);
    if (!Jsi_ValueIsFunction(interp, repVal))
................................................................................
    Jsi_Value *modv = Jsi_ValueArrayIndex(interp, args, 1);
    Jsi_Number fmod;
    if (Jsi_GetNumberFromValue(interp, modv, &fmod) != JSI_OK)
        return JSI_ERROR;
    SAFEACCESS(fname, 1)
    return (Jsi_Chmod(interp, fname, (unsigned int)fmod) == 0 ? JSI_OK : JSI_ERROR);
}

Jsi_RC Jsi_FileRead(Jsi_Interp *interp, Jsi_Value *name, Jsi_DString *dStr) {
    Jsi_RC rc = JSI_ERROR;
    Jsi_Channel chan = Jsi_Open(interp, name, "rb");
    int n, sum = 0;
    if (!chan)
        return rc;
    char buf[JSI_BUFSIZ];
    while (sum < MAX_LOOP_COUNT && (n = Jsi_Read(interp, chan, buf, sizeof(buf))) > 0) {
        Jsi_DSAppendLen(dStr, buf, n);
        sum += n;
    }
    Jsi_Close(interp, chan);
    return JSI_OK;
}

static Jsi_RC FileReadCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this,
    Jsi_Value **ret, Jsi_Func *funcPtr) /* TODO limit. */
{   
    Jsi_Value *fname = Jsi_ValueArrayIndex(interp, args, 0);
    Jsi_Value *vmode = Jsi_ValueArrayIndex(interp, args, 1);
    const char *mode = (vmode ? Jsi_ValueString(interp, vmode, NULL) : NULL);
................................................................................
                ustart = m;
                ulen = e+l-1;
            }
        }
    }
#endif
    if (ulen>len) {
#if JSI__MEMDEBUG
        fprintf(stderr, "TODO: fix utf substr\n");
#endif
        ulen = len;
    }
    Jsi_DSAppendLen(dStr, str+ustart, ulen);
    return Jsi_DSValue(dStr);
}

int Jsi_UtfIndexToOffset(const char *str, int index)
................................................................................
    jsi_wsStatData stats;
    char *iface;
    const char* urlPrefix, *urlRedirect;
    const char *localhostName;
    const char *clientName;
    const char *clientIP;
    const char *useridPass;
    const char *realm, *templateFile;
    struct lws_context *instCtx;
    Jsi_Value *getRegexp, *post;
    unsigned int oldus;
    int opts;
    int hasOpts;
    int debug;
    int maxConnects;
................................................................................
    JSI_OPT(DSTRING,    jsi_wsPss, url,         .help="Url for connection"),
    JSI_OPT_END(jsi_wsPss, .help="Per-connection options")
};

static Jsi_OptionSpec WSOptions[] =
{
    JSI_OPT(STRING, jsi_wsCmdObj, address,    .help="In client-mode the address to connect to (127.0.0.1)" ),
    JSI_OPT(INT,    jsi_wsCmdObj, bufferPwr2, .help="Tune the recv/send buffer: value is a power of 2 in [0-20] (16)"),
    JSI_OPT(BOOL,   jsi_wsCmdObj, client,     .help="Run in client mode", jsi_IIOF),
    JSI_OPT(STRKEY, jsi_wsCmdObj, clientHost, .help="Override host name for client"),
    JSI_OPT(STRKEY, jsi_wsCmdObj, clientOrigin,.help="Override client origin (origin)"),
    JSI_OPT(INT,    jsi_wsCmdObj, debug,      .help="Set debug level. Setting this to 512 will turn on max libwebsocket log levels"),
    JSI_OPT(BOOL,   jsi_wsCmdObj, echo,       .help="LogInfo outputs all websock Send/Recv messages"),
    JSI_OPT(STRKEY, jsi_wsCmdObj, formParams, .help="Comma seperated list of upload form param names ('text,send,file,upload')", jsi_IIRO),
    JSI_OPT(OBJ,    jsi_wsCmdObj, extArgs,    .help="Arguments for extension handlers", jsi_IIOF),
................................................................................
    JSI_OPT(BOOL,   jsi_wsCmdObj, local,      .help="Limit connections to localhost addresses on the 127 network"),
    JSI_OPT(STRKEY, jsi_wsCmdObj, localhostName,.help="Client name used by localhost connections ('localhost')"),
    JSI_OPT(INT,    jsi_wsCmdObj, maxConnects,.help="In server mode, max number of client connections accepted"),
    JSI_OPT(INT,    jsi_wsCmdObj, maxDownload,.help="Max size of file download"),
    JSI_OPT(INT,    jsi_wsCmdObj, maxUpload,  .help="Max size of file upload will accept"),
    JSI_OPT(OBJ,    jsi_wsCmdObj, mimeTypes,  .help="Object providing map of file extensions to mime types (eg. {txt:'text/plain', bb:'text/bb'})", jsi_IIOF),
    JSI_OPT(BOOL,   jsi_wsCmdObj, noConfig,   .help="Disable use of conf() to change options after options after create", jsi_IIOF),
    JSI_OPT(BOOL,   jsi_wsCmdObj, noCompress, .help="Disable per-message-deflate extension which can truncate large msgs"),
    JSI_OPT(BOOL,   jsi_wsCmdObj, noUpdate,   .help="Disable update event-processing (eg. to exit)"),
    JSI_OPT(BOOL,   jsi_wsCmdObj, noWebsock,  .help="Serve html, but disallow websocket upgrade", jsi_IIOF),
    JSI_OPT(BOOL,   jsi_wsCmdObj, noWarn,     .help="Quietly ignore file related errors"),
    JSI_OPT(FUNC,   jsi_wsCmdObj, onAuth,     .help="Function to call for http basic authentication", .flags=0, .custom=0, .data=(void*)"ws:userobj, id:number, url:string, userpass:string"),
    JSI_OPT(FUNC,   jsi_wsCmdObj, onClose,    .help="Function to call when the websocket connection closes", .flags=0, .custom=0, .data=(void*)"ws:userobj|null, id:number"),
    JSI_OPT(FUNC,   jsi_wsCmdObj, onCloseLast,.help="Function to call when last websock connection closes. On object delete arg is null", .flags=0, .custom=0, .data=(void*)"ws:userobj|null"),
    JSI_OPT(FUNC,   jsi_wsCmdObj, onFilter,   .help="Function to call on a new connection: return false to kill connection", .flags=0, .custom=0, .data=(void*)"ws:userobj, id:number, url:string, ishttp:boolean"),
................................................................................
    JSI_OPT(STRKEY, jsi_wsCmdObj, realm,      .help="Realm for basic auth (jsish)", ),
    JSI_OPT(INT,    jsi_wsCmdObj, recvBufMax, .help="Size limit of a websocket message", jsi_IIOF),
    JSI_OPT(INT,    jsi_wsCmdObj, recvBufTimeout,.help="Timeout for recv of a websock msg", jsi_IIOF),
    JSI_OPT(BOOL,   jsi_wsCmdObj, redirMax,   .help="Temporarily disable redirects when see more than this in 10 minutes"),
    JSI_OPT(STRING, jsi_wsCmdObj, rootdir,    .help="Directory to serve html from (\".\")"),
    JSI_OPT(CUSTOM, jsi_wsCmdObj, stats,      .help="Statistical data", jsi_IIRO, .custom=Jsi_Opt_SwitchSuboption, .data=WPSStats),
    JSI_OPT(TIME_T, jsi_wsCmdObj, startTime,  .help="Time of websocket start", jsi_IIRO),
    JSI_OPT(STRKEY, jsi_wsCmdObj, templateFile,.help="File name for markdeep template (template.shtml)"),
    JSI_OPT(STRKEY, jsi_wsCmdObj, urlPrefix,  .help="Prefix in url to strip from path; for reverse proxy"),
    JSI_OPT(STRKEY, jsi_wsCmdObj, urlRedirect,.help="Redirect when no url or / is given. Must match urlPrefix, if given"),
    JSI_OPT(BOOL,   jsi_wsCmdObj, use_ssl,    .help="Use https (for client)", jsi_IIOF),
    JSI_OPT(STRKEY, jsi_wsCmdObj, useridPass, .help="The USERID:PASSWORD to use for basic authentication"),
    JSI_OPT(OBJ,    jsi_wsCmdObj, version,    .help="WebSocket version info", jsi_IIRO),
    JSI_OPT_END(jsi_wsCmdObj, .help="Websocket options")
};
................................................................................
            if (n>0)
                Jsi_DSAppendLen(hStr, (char*)buffer, n);
            p = buffer;
        }
    }
    return true;
}

static Jsi_RC jsi_wsTemplateFill(Jsi_Interp *interp, jsi_wsCmdObj *cmdPtr, Jsi_Value *fn, Jsi_DString *dStr,
    int lvl) {
    Jsi_Value *fval;
    Jsi_RC rc = JSI_OK;
    char *cp, *ce, pref[] = "<!--#include file=\"", suffix[] = "\"-->";
    int flen, plen = sizeof(pref)-1, slen = sizeof(suffix)-1;
    Jsi_DString tStr = {};
    const char *cs = "<!-- Markdeep: --><style class=\"fallback\">body{visibility:hidden;}</style>\n"
                "<script>window.markdeepOptions={tocStyle:\"medium\"}</script>\n"
                "<!--#include file=\"$inc\"-->\n"
                "<script src=\"markdeep.min.js\"></script>\n"
                "<script>window.alreadyProcessedMarkdeep||(document.body.style.visibility='visible')</script>";
    char *fs, *fname = Jsi_ValueString(interp, fn, &flen), *fend = fname;
    char fbuf[PATH_MAX];
    if (lvl>10)
        return JSI_ERROR;
    fs = Jsi_Strrchr(fname, '/');
    if (fs) {
        flen = fs-fname;
        fend = fs+1;
    }
    if (lvl>0) {
        rc = Jsi_FileRead(interp, fn, &tStr);
        cs = Jsi_DSValue(&tStr);
    } else {
        snprintf(fbuf, sizeof(fbuf), "%.*s%s", flen, fname, cmdPtr->templateFile);
        fval = Jsi_ValueNewStringConst(interp, fbuf, -1);
        Jsi_IncrRefCount(interp, fval);
        Jsi_StatBuf sb;
        int n = Jsi_Stat(interp, fval, &sb);
        if (!n && sb.st_size>0) {
            rc = Jsi_FileRead(interp, fval, &tStr);
            cs = Jsi_DSValue(&tStr);
        }
        Jsi_DecrRefCount(interp, fval);
    }
    
    while (rc == JSI_OK && cs) {
        char *ext = NULL;
        cp = Jsi_Strstr(cs, pref);
        if (!cp || !(ce=Jsi_Strstr(cp+plen, suffix))) {
            Jsi_DSAppend(dStr, cs, NULL);
            break;
        }
        Jsi_DSAppendLen(dStr, cs, cp-cs);
        if (cp[plen] == '$' && lvl == 0) {
            snprintf(fbuf, sizeof(fbuf), "%.*spages/%s.md", flen, fname, fend);
        } else {
            cp += plen;
            int elen = ce-cp;
            snprintf(fbuf, sizeof(fbuf), "%.*s/%.*s", flen, fname, elen, cp);
            ext = Jsi_Strrchr(fbuf, '.');
        }
        fval = Jsi_ValueNewStringConst(interp, fbuf, -1);
        Jsi_IncrRefCount(interp, fval);
        if (!ext || Jsi_Strcmp(ext, ".shtml"))
            rc = Jsi_FileRead(interp, fval, dStr);
        else
            rc = jsi_wsTemplateFill(interp, cmdPtr, fval, dStr, lvl+1);
        Jsi_DecrRefCount(interp, fval);
    
        cs = ce + slen;
        if (*cs == '\n')
            cs++;
    }
    Jsi_DSFree(&tStr);
    return rc;
    
}

// Handle http GET/POST
static int jsi_wsHttp(Jsi_Interp *interp, jsi_wsCmdObj *cmdPtr, struct lws *wsi, void *user,
    struct lws_context *context, const char* inPtr, Jsi_DString *tStr, jsi_wsPss *pss)
{
    const char *ext = NULL;
    unsigned char buffer[JSI_BUFSIZ];
    const char *mime = NULL;
    time_t now = time(NULL);
    char buf[JSI_BUFSIZ];
    int rc = 0, essi = 0;
    buf[0] = 0;
    uchar *p = buffer, *end = &buffer[sizeof(buffer)-1];
    int n;
    Jsi_Value* fname = NULL;
    bool isMdi = 0;

    /* if a legal POST URL, let it continue and accept data */
    if (lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI))
        return 0;
    if (!pss)
        pss = jsi_wsgetPss(cmdPtr, wsi, user, 1, 1);
  
................................................................................
#endif

    snprintf(buf, sizeof(buf), "%s/%s", rootDir, inPtr);
    if (cmdPtr->debug>1)
        fprintf(stderr, "FILE: %s in %s | %s\n", buf, rootDir, Jsi_ValueString(interp, cmdPtr->rootdir, NULL));
    char extBuf[100];
    bool isgzip = 0;
    if (!ext || !ext[1])
        mime = "text/html";
    else {
        const char *eext = ext+1;
        uint elen = Jsi_Strlen(ext);
        if (elen>3 && elen<(sizeof(extBuf)-10) && !Jsi_Strcmp(ext+elen-3,".gz")) {
            Jsi_Strcpy(extBuf, ext);
            extBuf[elen-3] = 0;
            char *ext2 = Jsi_Strrchr(extBuf, '.');
            if (ext2) {
                isgzip = 1;
                ext = ext2;
            }
        }
        Jsi_HashEntry *hPtr;
















        if (cmdPtr->mimeTypes) {
            /* Lookup mime type in mimeTypes object. */

            Jsi_Value *mVal = Jsi_ValueObjLookup(interp, cmdPtr->mimeTypes, ext+1, 1);
            if (mVal)
                mime = Jsi_ValueString(interp, mVal, NULL);
        }
        if (!mime) {
            static const char* mtypes[] = {
                "html", "text/html", "js", "application/x-javascript", 
                "css", "text/css", "png", "image/png", "ico", "image/icon",
                "gif", "image/gif", "jpeg", "image/jpeg", 
                "jpg", "image/jpeg", "svg", "image/svg+xml",
                "json", "application/json", "txt", "text/plain",
                "jsi", "application/x-javascript", "cssi", "text/css",  
                0, 0
            };
            mime = "text/html";
            int i;
            for (i=0; mtypes[i]; i+=2)
                if (tolower(*eext) == mtypes[i][0] && !Jsi_Strncasecmp(eext, mtypes[i], -1)) {
                    mime = mtypes[i+1];
                    break;
                }
        }
        
        if (!Jsi_Strncasecmp(eext,"shtml", -1))
            essi = 1;
        
        if ((hPtr = Jsi_HashEntryFind(cmdPtr->handlers, ext)) && !cmdPtr->deleted) {
            /* Use interprete html eg. using jsi_wpp preprocessor */
            Jsi_DString jStr = {};
            Jsi_Value *vrc = NULL;
            int hrc = 0, strLen, evrc, isalloc=0;
            char *vStr, *hstr = NULL;
................................................................................
            if (hrc<=0)
                return -1;
            return 1;
        }
    }
    if (!buf[0]) {
        if (cmdPtr->debug)
            fprintf(stderr, "empty file: %s\n", inPtr);
        return -1;
    }
    fname = Jsi_ValueNewStringDup(interp, buf);
    Jsi_IncrRefCount(interp, fname);
    
    Jsi_DString hStr = {};
    Jsi_StatBuf jsb;
    bool native = Jsi_FSNative(interp, fname);
    if (!ext || essi) {
        isMdi = 1;
        goto serve;
    }
    if ((native && Jsi_InterpSafe(interp) && Jsi_InterpAccess(interp, fname, JSI_INTACCESS_READ) != JSI_OK) ||
        (Jsi_Stat(interp, fname, &jsb) || jsb.st_size<=0)) {
nofile:
        if (cmdPtr->onUnknown || pss->onUnknown) {
            Jsi_Value *uk = (pss->onUnknown?pss->onUnknown:cmdPtr->onUnknown);
            Jsi_RC jrc = jsi_wsGetCmd(interp, cmdPtr, pss, wsi, inPtr, uk, NULL);
            if (jrc == JSI_ERROR)
................................................................................
        goto bail;
        
    if (pss->headers && !jsi_wsAddHeader(interp, cmdPtr, wsi, pss->headers, &hStr))
        goto bail;

    n = Jsi_DSLength(&hStr);
    
    if (native && !isMdi) {
        Jsi_DecrRefCount(interp, fname);

        int hrc = lws_serve_http_file(wsi, buf, mime, Jsi_DSValue(&hStr), Jsi_DSLength(&hStr));
        if (hrc<0) {
            if (cmdPtr->noWarn==0)
                fprintf(stderr, "can not serve file (%d): %s\n", hrc, buf);
            goto bail;
        } else if (hrc > 0 && lws_http_transaction_completed(wsi))
            goto bail;
    } else {
        // Need to read data for non-native files.
        Jsi_DString dStr = {}, fStr = {};


        if (isMdi)
            rc = jsi_wsTemplateFill(interp, cmdPtr, fname, &fStr, (essi?1:0));
        else
            rc = Jsi_FileRead(interp, fname, &fStr);
        if (rc != JSI_OK)
            goto nofile;



        int hrc = jsi_wsServeHeader(pss, wsi, (int)Jsi_DSLength(&fStr), 200, Jsi_DSValue(&hStr), mime, &dStr);
        if (hrc>=0) {

            Jsi_DSAppendLen(&dStr, Jsi_DSValue(&fStr), Jsi_DSLength(&fStr));


            char *strVal = Jsi_DSValue(&dStr);
            int strLen = Jsi_DSLength(&dStr);
            hrc = jsi_wswrite(pss, wsi, (unsigned char*)strVal, strLen, LWS_WRITE_HTTP);
        }
        Jsi_DecrRefCount(interp, fname);

        Jsi_DSFree(&dStr);
        Jsi_DSFree(&fStr);
        if (hrc<0) {
            if (cmdPtr->noWarn==0)
                fprintf(stderr, "can not serve data (%d): %s\n", hrc, buf);
            goto bail;
        } else if (hrc > 0 && lws_http_transaction_completed(wsi))
            goto bail;

................................................................................
    cmdPtr->interp = interp;
    cmdPtr->ietf_version = -1;
    cmdPtr->bufferPwr2 = 0;
    cmdPtr->ws_gid = -1;
    cmdPtr->ws_uid = -1;
    cmdPtr->startTime = time(NULL);
    cmdPtr->hasOpts = 1;
    cmdPtr->templateFile = "template.shtml";
    if ((arg != NULL && !Jsi_ValueIsNull(interp,arg))
        && Jsi_OptionsProcess(interp, WSOptions, cmdPtr, arg, 0) < 0) {
bail:
        jsi_wswebsocketObjFree(interp, cmdPtr);
        return JSI_ERROR;
    }
    if (cmdPtr->headers && (Jsi_ValueGetLength(interp, cmdPtr->headers)%2)) {
................................................................................
    cmdPtr->protocols[JWS_PROTOCOL_HTTP].name="http-only";
    cmdPtr->protocols[JWS_PROTOCOL_HTTP].callback=jsi_wscallback_http;
    cmdPtr->protocols[JWS_PROTOCOL_HTTP].per_session_data_size=sizeof(jsi_wsPss);
    cmdPtr->protocols[JWS_PROTOCOL_WEBSOCK].name=subprot;
    cmdPtr->protocols[JWS_PROTOCOL_WEBSOCK].callback=jsi_wscallback_websock;
    cmdPtr->protocols[JWS_PROTOCOL_WEBSOCK].per_session_data_size=sizeof(jsi_wsPss);

    if (cmdPtr->bufferPwr2 == 0)
        cmdPtr->bufferPwr2 = 16;
    if (cmdPtr->bufferPwr2>0) {
        if (cmdPtr->bufferPwr2>20) {
            Jsi_LogError("bufferPwr2 not in 0-20: %d", cmdPtr->bufferPwr2);
            goto bail;
        }
        cmdPtr->protocols[JWS_PROTOCOL_WEBSOCK].rx_buffer_size=(1<<cmdPtr->bufferPwr2);
    }
................................................................................

    Jsi_Obj *fobj = Jsi_ValueGetObj(interp, toacc);
    if ((cmdPtr->objId = Jsi_UserObjNew(interp, &websockobject, fobj, cmdPtr))<0) {
        goto bail;
    }
    cmdPtr->handlers = Jsi_HashNew(interp, JSI_KEYS_STRING, jsi_wsfreeHandlers);
    if (cmdPtr->extHandlers) {
        jsi_wsHandlerAdd(interp, cmdPtr, ".jsi",   "Jsi_Jspp",     jsi_wsStrValGet(cmdPtr, "jsi"),   1);
        jsi_wsHandlerAdd(interp, cmdPtr, ".htmli", "Jsi_Htmlpp",   jsi_wsStrValGet(cmdPtr, "htmli"), 1);
        jsi_wsHandlerAdd(interp, cmdPtr, ".cssi",  "Jsi_Csspp",    jsi_wsStrValGet(cmdPtr, "cssi"),  1);
        jsi_wsHandlerAdd(interp, cmdPtr, ".mdi",   "Jsi_Markdeep", jsi_wsStrValGet(cmdPtr, "mdi"),   1);
    }
    cmdPtr->fobj = fobj;
#ifdef LWS_LIBRARY_VERSION_NUMBER
    Jsi_JSONParseFmt(interp, &cmdPtr->version, "{libVer:\"%s\", hdrVer:\"%s\", hdrNum:%d, pkgVer:%d}",
        (char *)lws_get_library_version(), LWS_LIBRARY_VERSION, LWS_LIBRARY_VERSION_NUMBER, jsi_WsPkgVersion); 
#endif
    return JSI_OK;
................................................................................
}

Jsi_RC jsi_evalStrFile(Jsi_Interp* interp, Jsi_Value *path, char *str, int flags, int level)
{
    Jsi_Channel tinput = NULL, input = Jsi_GetStdChannel(interp, 0);
    Jsi_Value *npath = path;
    Jsi_RC rc = JSI_ERROR;
    bool strict = 0;
    const char *ustr = NULL, *ostr = str;
    if (Jsi_MutexLock(interp, interp->Mutex) != JSI_OK)
        return rc;
    int oldSp, uskip = 0, fncOfs = 0;
    int oldef = interp->evalFlags;
    jsi_Pstate *oldps = interp->ps;
    const char *oldFile = interp->curFile;
................................................................................
        }
    }

    /* TODO: cleanup interp->framePtr->Sp stuff. */
    oldSp = interp->framePtr->Sp;
    // Evaluate code.
    rc = JSI_OK;
    const char *cext;
    if (fname && ((cext=Jsi_Strstr(fname,".jsi"))) && !cext[4])
        strict = interp->framePtr->strict = 1;
    ps = jsiNewParser(interp, str, input, 0);
    interp->evalFlags = flags;
    if (!ps)
        rc = JSI_ERROR;
    else {
        Jsi_ValueMakeUndef(interp, &interp->retValue);
        interp->ps = ps;
        Jsi_Value *retValue = interp->retValue;
        if (!strict)
            strict = (jsi_GetDirective(interp, ps->opcodes, "use strict")!=NULL);



        if (strict) {
            interp->framePtr->strict = 1;
            if (interp->framePtr->level<=1)
                interp->strict = 1;
        }
        const char *curFile = interp->curFile;

Changes to src/jsi.h.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
...
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
...
459
460
461
462
463
464
465

466
467
468
469
470
471
472
...
626
627
628
629
630
631
632

633
634
635
636
637
638
639
/* jsi.h : External API header file for Jsi. */
#ifndef __JSI_H__
#define __JSI_H__

#define JSI_VERSION_MAJOR   2
#define JSI_VERSION_MINOR   6
#define JSI_VERSION_RELEASE 0

#define JSI_VERSION (JSI_VERSION_MAJOR + ((Jsi_Number)JSI_VERSION_MINOR/100.0) + ((Jsi_Number)JSI_VERSION_RELEASE/10000.0))

#ifndef JSI_EXTERN
#define JSI_EXTERN extern
#endif

................................................................................
JSI_EXTERN int Jsi_Strcmp(const char *str1, const char *str2); /*STUB = 26*/
JSI_EXTERN int Jsi_Strncmp(const char *str1, const char *str2, int n); /*STUB = 27*/
JSI_EXTERN int Jsi_Strncasecmp(const char *str1, const char *str2, int n); /*STUB = 28*/
JSI_EXTERN int Jsi_StrcmpDict(const char *str1, const char *str2, int nocase, int dict); /*STUB = 29*/
JSI_EXTERN char* Jsi_Strcpy(char *dst, const char *src); /*STUB = 30*/
JSI_EXTERN char* Jsi_Strncpy(char *dst, const char *src, int len); /*STUB = 31*/
JSI_EXTERN char* Jsi_Strdup(const char *n); /*STUB = 32*/
JSI_EXTERN char* Jsi_StrdupLen(const char *str, int len); /*STUB = 407*/ /*LAST*/
JSI_EXTERN char* Jsi_Strrchr(const char *str, int c); /*STUB = 33*/
JSI_EXTERN char* Jsi_Strstr(const char *str, const char *sub); /*STUB = 34*/
JSI_EXTERN char* Jsi_Strrstr(const char *str, const char *sub); /*STUB = 233*/ 
JSI_EXTERN int Jsi_ObjArraySizer(Jsi_Interp *interp, Jsi_Obj *obj, uint n); /*STUB = 35*/
JSI_EXTERN char* Jsi_Strchr(const char *str, int c); /*STUB = 36*/
JSI_EXTERN int Jsi_Strpos(const char *str, int start, const char *nid, int nocase); /*STUB = 37*/
JSI_EXTERN int Jsi_Strrpos(const char *str, int start, const char *nid, int nocase); /*STUB = 38*/
................................................................................

JSI_EXTERN Jsi_Value* Jsi_ValueNewNull(Jsi_Interp *interp); /*STUB = 100*/
JSI_EXTERN Jsi_Value* Jsi_ValueNewBoolean(Jsi_Interp *interp, int bval); /*STUB = 101*/
JSI_EXTERN Jsi_Value* Jsi_ValueNewNumber(Jsi_Interp *interp, Jsi_Number n); /*STUB = 102*/
JSI_EXTERN Jsi_Value* Jsi_ValueNewBlob(Jsi_Interp *interp, uchar *s, uint len); /*STUB = 103*/
JSI_EXTERN Jsi_Value* Jsi_ValueNewString(Jsi_Interp *interp, const char *s, int len); /*STUB = 104*/
JSI_EXTERN Jsi_Value* Jsi_ValueNewStringKey(Jsi_Interp *interp, const char *s); /*STUB = 105*/

JSI_EXTERN Jsi_Value* Jsi_ValueNewStringDup(Jsi_Interp *interp, const char *s); /*STUB = 106*/
JSI_EXTERN Jsi_Value* Jsi_ValueNewArray(Jsi_Interp *interp, const char **items, int count); /*STUB = 107*/
JSI_EXTERN Jsi_Value* Jsi_ValueNewObj(Jsi_Interp *interp, Jsi_Obj *o) ; /*STUB = 108*/
#define Jsi_ValueNewBlobString(interp, s) Jsi_ValueNewBlob(interp, (uchar*)s, Jsi_Strlen(s))

JSI_EXTERN Jsi_RC Jsi_GetStringFromValue(Jsi_Interp* interp, Jsi_Value *value, const char **s); /*STUB = 109*/
JSI_EXTERN Jsi_RC Jsi_GetNumberFromValue(Jsi_Interp* interp, Jsi_Value *value, Jsi_Number *n); /*STUB = 110*/
................................................................................
    Jsi_CHash_SHA3_384, Jsi_CHash_SHA3_512, Jsi_CHash_SHA3_256 } Jsi_CryptoHashType;

JSI_EXTERN Jsi_RC Jsi_Encrypt(Jsi_Interp *interp, Jsi_DString *inout, const char *key, uint keyLen, bool decrypt); /*STUB = 229*/
JSI_EXTERN Jsi_RC Jsi_CryptoHash(char *outbuf, const char *str, int len, Jsi_CryptoHashType type, uint strength, bool noHex, int *sizPtr); /*STUB = 230*/
JSI_EXTERN Jsi_RC Jsi_Base64(const char *str, int len, Jsi_DString *buf, bool decode); /*STUB = 231*/
JSI_EXTERN int Jsi_HexStr(const uchar *data, int len, Jsi_DString *dStr, bool decode); /*STUB = 232*/
JSI_EXTERN uint32_t Jsi_Crc32(uint32_t crc, const void *ptr, size_t buf_len); /*STUB = 234*/


JSI_EXTERN int Jsi_NumberIsInfinity(Jsi_Number a);  /*STUB = 235*/
JSI_EXTERN bool Jsi_NumberIsEqual(Jsi_Number n1, Jsi_Number n2);  /*STUB = 236*/
JSI_EXTERN bool Jsi_NumberIsFinite(Jsi_Number value);  /*STUB = 237*/
JSI_EXTERN bool Jsi_NumberIsInteger(Jsi_Number n);  /*STUB = 238*/
JSI_EXTERN bool Jsi_NumberIsNaN(Jsi_Number a);  /*STUB = 239*/
JSI_EXTERN bool Jsi_NumberIsNormal(Jsi_Number a);  /*STUB = 240*/






|







 







|







 







>







 







>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
...
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
...
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
...
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
/* jsi.h : External API header file for Jsi. */
#ifndef __JSI_H__
#define __JSI_H__

#define JSI_VERSION_MAJOR   2
#define JSI_VERSION_MINOR   6
#define JSI_VERSION_RELEASE 1

#define JSI_VERSION (JSI_VERSION_MAJOR + ((Jsi_Number)JSI_VERSION_MINOR/100.0) + ((Jsi_Number)JSI_VERSION_RELEASE/10000.0))

#ifndef JSI_EXTERN
#define JSI_EXTERN extern
#endif

................................................................................
JSI_EXTERN int Jsi_Strcmp(const char *str1, const char *str2); /*STUB = 26*/
JSI_EXTERN int Jsi_Strncmp(const char *str1, const char *str2, int n); /*STUB = 27*/
JSI_EXTERN int Jsi_Strncasecmp(const char *str1, const char *str2, int n); /*STUB = 28*/
JSI_EXTERN int Jsi_StrcmpDict(const char *str1, const char *str2, int nocase, int dict); /*STUB = 29*/
JSI_EXTERN char* Jsi_Strcpy(char *dst, const char *src); /*STUB = 30*/
JSI_EXTERN char* Jsi_Strncpy(char *dst, const char *src, int len); /*STUB = 31*/
JSI_EXTERN char* Jsi_Strdup(const char *n); /*STUB = 32*/
JSI_EXTERN char* Jsi_StrdupLen(const char *str, int len); /*STUB = 407*/
JSI_EXTERN char* Jsi_Strrchr(const char *str, int c); /*STUB = 33*/
JSI_EXTERN char* Jsi_Strstr(const char *str, const char *sub); /*STUB = 34*/
JSI_EXTERN char* Jsi_Strrstr(const char *str, const char *sub); /*STUB = 233*/ 
JSI_EXTERN int Jsi_ObjArraySizer(Jsi_Interp *interp, Jsi_Obj *obj, uint n); /*STUB = 35*/
JSI_EXTERN char* Jsi_Strchr(const char *str, int c); /*STUB = 36*/
JSI_EXTERN int Jsi_Strpos(const char *str, int start, const char *nid, int nocase); /*STUB = 37*/
JSI_EXTERN int Jsi_Strrpos(const char *str, int start, const char *nid, int nocase); /*STUB = 38*/
................................................................................

JSI_EXTERN Jsi_Value* Jsi_ValueNewNull(Jsi_Interp *interp); /*STUB = 100*/
JSI_EXTERN Jsi_Value* Jsi_ValueNewBoolean(Jsi_Interp *interp, int bval); /*STUB = 101*/
JSI_EXTERN Jsi_Value* Jsi_ValueNewNumber(Jsi_Interp *interp, Jsi_Number n); /*STUB = 102*/
JSI_EXTERN Jsi_Value* Jsi_ValueNewBlob(Jsi_Interp *interp, uchar *s, uint len); /*STUB = 103*/
JSI_EXTERN Jsi_Value* Jsi_ValueNewString(Jsi_Interp *interp, const char *s, int len); /*STUB = 104*/
JSI_EXTERN Jsi_Value* Jsi_ValueNewStringKey(Jsi_Interp *interp, const char *s); /*STUB = 105*/
JSI_EXTERN Jsi_Value* Jsi_ValueNewStringConst(Jsi_Interp *interp, const char *s, int len); /*STUB = 409*/ /*LAST*/
JSI_EXTERN Jsi_Value* Jsi_ValueNewStringDup(Jsi_Interp *interp, const char *s); /*STUB = 106*/
JSI_EXTERN Jsi_Value* Jsi_ValueNewArray(Jsi_Interp *interp, const char **items, int count); /*STUB = 107*/
JSI_EXTERN Jsi_Value* Jsi_ValueNewObj(Jsi_Interp *interp, Jsi_Obj *o) ; /*STUB = 108*/
#define Jsi_ValueNewBlobString(interp, s) Jsi_ValueNewBlob(interp, (uchar*)s, Jsi_Strlen(s))

JSI_EXTERN Jsi_RC Jsi_GetStringFromValue(Jsi_Interp* interp, Jsi_Value *value, const char **s); /*STUB = 109*/
JSI_EXTERN Jsi_RC Jsi_GetNumberFromValue(Jsi_Interp* interp, Jsi_Value *value, Jsi_Number *n); /*STUB = 110*/
................................................................................
    Jsi_CHash_SHA3_384, Jsi_CHash_SHA3_512, Jsi_CHash_SHA3_256 } Jsi_CryptoHashType;

JSI_EXTERN Jsi_RC Jsi_Encrypt(Jsi_Interp *interp, Jsi_DString *inout, const char *key, uint keyLen, bool decrypt); /*STUB = 229*/
JSI_EXTERN Jsi_RC Jsi_CryptoHash(char *outbuf, const char *str, int len, Jsi_CryptoHashType type, uint strength, bool noHex, int *sizPtr); /*STUB = 230*/
JSI_EXTERN Jsi_RC Jsi_Base64(const char *str, int len, Jsi_DString *buf, bool decode); /*STUB = 231*/
JSI_EXTERN int Jsi_HexStr(const uchar *data, int len, Jsi_DString *dStr, bool decode); /*STUB = 232*/
JSI_EXTERN uint32_t Jsi_Crc32(uint32_t crc, const void *ptr, size_t buf_len); /*STUB = 234*/
JSI_EXTERN Jsi_RC Jsi_FileRead(Jsi_Interp *interp, Jsi_Value *name, Jsi_DString *dStr); /*STUB = 408*/

JSI_EXTERN int Jsi_NumberIsInfinity(Jsi_Number a);  /*STUB = 235*/
JSI_EXTERN bool Jsi_NumberIsEqual(Jsi_Number n1, Jsi_Number n2);  /*STUB = 236*/
JSI_EXTERN bool Jsi_NumberIsFinite(Jsi_Number value);  /*STUB = 237*/
JSI_EXTERN bool Jsi_NumberIsInteger(Jsi_Number n);  /*STUB = 238*/
JSI_EXTERN bool Jsi_NumberIsNaN(Jsi_Number a);  /*STUB = 239*/
JSI_EXTERN bool Jsi_NumberIsNormal(Jsi_Number a);  /*STUB = 240*/

Changes to src/jsiEval.c.

2169
2170
2171
2172
2173
2174
2175

2176
2177
2178
2179
2180
2181
2182
....
2313
2314
2315
2316
2317
2318
2319



2320
2321
2322
2323
2324
2325
2326
2327

2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
    jsi_Pstate *oldps = interp->ps;
    const char *oldFile = interp->curFile;
    char *origFile = Jsi_ValueString(interp, path, NULL);
    const char *fname = origFile;
    char *oldDir = interp->curDir;
    char dirBuf[PATH_MAX];
    jsi_Pstate *ps = NULL;

    bool oldStrict = interp->framePtr->strict;
    jsi_FileInfo *fi = NULL;
    int exists = (flags&JSI_EVAL_EXISTS);
    int ignore = (flags&JSI_EVAL_ERRIGNORE);
    if (flags & JSI_EVAL_GLOBAL)
        level = 1;
    if (flags & JSI_EVAL_ISMAIN)
................................................................................
        }
    }

    /* TODO: cleanup interp->framePtr->Sp stuff. */
    oldSp = interp->framePtr->Sp;
    // Evaluate code.
    rc = JSI_OK;



    ps = jsiNewParser(interp, str, input, 0);
    interp->evalFlags = flags;
    if (!ps)
        rc = JSI_ERROR;
    else {
        Jsi_ValueMakeUndef(interp, &interp->retValue);
        interp->ps = ps;
        Jsi_Value *retValue = interp->retValue;

        bool strict = (jsi_GetDirective(interp, ps->opcodes, "use strict")!=NULL);
        const char *cext;
        if (!strict && fname && ((cext=Jsi_Strstr(fname,".jsi"))) && !cext[4])
            strict = 1;
        if (strict) {
            interp->framePtr->strict = 1;
            if (interp->framePtr->level<=1)
                interp->strict = 1;
        }
        const char *curFile = interp->curFile;








>







 







>
>
>








>
|
<
<
<







2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
....
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333



2334
2335
2336
2337
2338
2339
2340
    jsi_Pstate *oldps = interp->ps;
    const char *oldFile = interp->curFile;
    char *origFile = Jsi_ValueString(interp, path, NULL);
    const char *fname = origFile;
    char *oldDir = interp->curDir;
    char dirBuf[PATH_MAX];
    jsi_Pstate *ps = NULL;
    bool strict = 0;
    bool oldStrict = interp->framePtr->strict;
    jsi_FileInfo *fi = NULL;
    int exists = (flags&JSI_EVAL_EXISTS);
    int ignore = (flags&JSI_EVAL_ERRIGNORE);
    if (flags & JSI_EVAL_GLOBAL)
        level = 1;
    if (flags & JSI_EVAL_ISMAIN)
................................................................................
        }
    }

    /* TODO: cleanup interp->framePtr->Sp stuff. */
    oldSp = interp->framePtr->Sp;
    // Evaluate code.
    rc = JSI_OK;
    const char *cext;
    if (fname && ((cext=Jsi_Strstr(fname,".jsi"))) && !cext[4])
        strict = interp->framePtr->strict = 1;
    ps = jsiNewParser(interp, str, input, 0);
    interp->evalFlags = flags;
    if (!ps)
        rc = JSI_ERROR;
    else {
        Jsi_ValueMakeUndef(interp, &interp->retValue);
        interp->ps = ps;
        Jsi_Value *retValue = interp->retValue;
        if (!strict)
            strict = (jsi_GetDirective(interp, ps->opcodes, "use strict")!=NULL);



        if (strict) {
            interp->framePtr->strict = 1;
            if (interp->framePtr->level<=1)
                interp->strict = 1;
        }
        const char *curFile = interp->curFile;

Changes to src/jsiFileCmds.c.

341
342
343
344
345
346
347















348
349
350
351
352
353
354
    Jsi_Value *modv = Jsi_ValueArrayIndex(interp, args, 1);
    Jsi_Number fmod;
    if (Jsi_GetNumberFromValue(interp, modv, &fmod) != JSI_OK)
        return JSI_ERROR;
    SAFEACCESS(fname, 1)
    return (Jsi_Chmod(interp, fname, (unsigned int)fmod) == 0 ? JSI_OK : JSI_ERROR);
}
















static Jsi_RC FileReadCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this,
    Jsi_Value **ret, Jsi_Func *funcPtr) /* TODO limit. */
{   
    Jsi_Value *fname = Jsi_ValueArrayIndex(interp, args, 0);
    Jsi_Value *vmode = Jsi_ValueArrayIndex(interp, args, 1);
    const char *mode = (vmode ? Jsi_ValueString(interp, vmode, NULL) : NULL);







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
    Jsi_Value *modv = Jsi_ValueArrayIndex(interp, args, 1);
    Jsi_Number fmod;
    if (Jsi_GetNumberFromValue(interp, modv, &fmod) != JSI_OK)
        return JSI_ERROR;
    SAFEACCESS(fname, 1)
    return (Jsi_Chmod(interp, fname, (unsigned int)fmod) == 0 ? JSI_OK : JSI_ERROR);
}

Jsi_RC Jsi_FileRead(Jsi_Interp *interp, Jsi_Value *name, Jsi_DString *dStr) {
    Jsi_RC rc = JSI_ERROR;
    Jsi_Channel chan = Jsi_Open(interp, name, "rb");
    int n, sum = 0;
    if (!chan)
        return rc;
    char buf[JSI_BUFSIZ];
    while (sum < MAX_LOOP_COUNT && (n = Jsi_Read(interp, chan, buf, sizeof(buf))) > 0) {
        Jsi_DSAppendLen(dStr, buf, n);
        sum += n;
    }
    Jsi_Close(interp, chan);
    return JSI_OK;
}

static Jsi_RC FileReadCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this,
    Jsi_Value **ret, Jsi_Func *funcPtr) /* TODO limit. */
{   
    Jsi_Value *fname = Jsi_ValueArrayIndex(interp, args, 0);
    Jsi_Value *vmode = Jsi_ValueArrayIndex(interp, args, 1);
    const char *mode = (vmode ? Jsi_ValueString(interp, vmode, NULL) : NULL);

Changes to src/jsiStubs.h.

1
2
3
4
5
6
7
8
9
10
11
12
...
429
430
431
432
433
434
435


436
437
438
439
440
441
442
...
844
845
846
847
848
849
850


851
852
853
854
855
856
857
....
1255
1256
1257
1258
1259
1260
1261


1262
1263
1264
1265
#ifndef __JSI_STUBS_H__
#define __JSI_STUBS_H__
#include "jsi.h"

#define JSI_STUBS_MD5 "bd4e55a8383c3598c0344241217a1d53"

#undef JSI_EXTENSION_INI
#define JSI_EXTENSION_INI Jsi_Stubs *jsiStubsPtr = NULL;

#ifdef JSI__MUSL
#define JSI_STUBS_BLDFLAGS 1
#else
................................................................................
    Jsi_CDataDb*(*_Jsi_CDataLookup)(Jsi_Interp *interp, const char *name);
    Jsi_RC(*_Jsi_CDataRegister)(Jsi_Interp *interp, Jsi_CData_Static *statics);
    Jsi_RC(*_Jsi_CDataStructInit)(Jsi_Interp *interp, uchar* data, const char *sname);
    Jsi_RC(*_Jsi_DllLookup)(Jsi_Interp *interp, const char *module, const char *name, void **ptr);
    Jsi_RC(*_Jsi_LoadLibrary)(Jsi_Interp *interp, const char *pathName, bool noInit);
    Jsi_StructSpec*(*_Jsi_CDataStruct)(Jsi_Interp *interp, const char *name);
    char*(*_Jsi_StrdupLen)(const char *str, int len);


    void *endPtr;
} Jsi_Stubs;

extern Jsi_Stubs* jsiStubsPtr;

#define __JSI_STUBS_INIT__\
    JSI_STUBS_SIG,    "jsi",    sizeof(Jsi_Stubs),     JSI_STUBS_BLDFLAGS,    JSI_STUBS_MD5,    NULL,\
................................................................................
    Jsi_CDataLookup,\
    Jsi_CDataRegister,\
    Jsi_CDataStructInit,\
    Jsi_DllLookup,\
    Jsi_LoadLibrary,\
    Jsi_CDataStruct,\
    Jsi_StrdupLen,\


    NULL

#ifdef JSI_USE_STUBS

#define Jsi_InterpNew(n0) JSISTUBCALL(jsiStubsPtr, _Jsi_InterpNew(n0))
#define Jsi_InterpDelete(n0) JSISTUBCALL(jsiStubsPtr, _Jsi_InterpDelete(n0))
#define Jsi_InterpOnDelete(n0,n1,n2) JSISTUBCALL(jsiStubsPtr, _Jsi_InterpOnDelete(n0,n1,n2))
................................................................................
#define Jsi_CDataLookup(n0,n1) JSISTUBCALL(jsiStubsPtr, _Jsi_CDataLookup(n0,n1))
#define Jsi_CDataRegister(n0,n1) JSISTUBCALL(jsiStubsPtr, _Jsi_CDataRegister(n0,n1))
#define Jsi_CDataStructInit(n0,n1,n2) JSISTUBCALL(jsiStubsPtr, _Jsi_CDataStructInit(n0,n1,n2))
#define Jsi_DllLookup(n0,n1,n2,n3) JSISTUBCALL(jsiStubsPtr, _Jsi_DllLookup(n0,n1,n2,n3))
#define Jsi_LoadLibrary(n0,n1,n2) JSISTUBCALL(jsiStubsPtr, _Jsi_LoadLibrary(n0,n1,n2))
#define Jsi_CDataStruct(n0,n1) JSISTUBCALL(jsiStubsPtr, _Jsi_CDataStruct(n0,n1))
#define Jsi_StrdupLen(n0,n1) JSISTUBCALL(jsiStubsPtr, _Jsi_StrdupLen(n0,n1))



#endif

#endif




|







 







>
>







 







>
>







 







>
>




1
2
3
4
5
6
7
8
9
10
11
12
...
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
...
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
....
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
#ifndef __JSI_STUBS_H__
#define __JSI_STUBS_H__
#include "jsi.h"

#define JSI_STUBS_MD5 "37fc4b8060d88c7f408fceb123d7042a"

#undef JSI_EXTENSION_INI
#define JSI_EXTENSION_INI Jsi_Stubs *jsiStubsPtr = NULL;

#ifdef JSI__MUSL
#define JSI_STUBS_BLDFLAGS 1
#else
................................................................................
    Jsi_CDataDb*(*_Jsi_CDataLookup)(Jsi_Interp *interp, const char *name);
    Jsi_RC(*_Jsi_CDataRegister)(Jsi_Interp *interp, Jsi_CData_Static *statics);
    Jsi_RC(*_Jsi_CDataStructInit)(Jsi_Interp *interp, uchar* data, const char *sname);
    Jsi_RC(*_Jsi_DllLookup)(Jsi_Interp *interp, const char *module, const char *name, void **ptr);
    Jsi_RC(*_Jsi_LoadLibrary)(Jsi_Interp *interp, const char *pathName, bool noInit);
    Jsi_StructSpec*(*_Jsi_CDataStruct)(Jsi_Interp *interp, const char *name);
    char*(*_Jsi_StrdupLen)(const char *str, int len);
    Jsi_RC(*_Jsi_FileRead)(Jsi_Interp *interp, Jsi_Value *name, Jsi_DString *dStr);
    Jsi_Value*(*_Jsi_ValueNewStringConst)(Jsi_Interp *interp, const char *s, int len);
    void *endPtr;
} Jsi_Stubs;

extern Jsi_Stubs* jsiStubsPtr;

#define __JSI_STUBS_INIT__\
    JSI_STUBS_SIG,    "jsi",    sizeof(Jsi_Stubs),     JSI_STUBS_BLDFLAGS,    JSI_STUBS_MD5,    NULL,\
................................................................................
    Jsi_CDataLookup,\
    Jsi_CDataRegister,\
    Jsi_CDataStructInit,\
    Jsi_DllLookup,\
    Jsi_LoadLibrary,\
    Jsi_CDataStruct,\
    Jsi_StrdupLen,\
    Jsi_FileRead,\
    Jsi_ValueNewStringConst,\
    NULL

#ifdef JSI_USE_STUBS

#define Jsi_InterpNew(n0) JSISTUBCALL(jsiStubsPtr, _Jsi_InterpNew(n0))
#define Jsi_InterpDelete(n0) JSISTUBCALL(jsiStubsPtr, _Jsi_InterpDelete(n0))
#define Jsi_InterpOnDelete(n0,n1,n2) JSISTUBCALL(jsiStubsPtr, _Jsi_InterpOnDelete(n0,n1,n2))
................................................................................
#define Jsi_CDataLookup(n0,n1) JSISTUBCALL(jsiStubsPtr, _Jsi_CDataLookup(n0,n1))
#define Jsi_CDataRegister(n0,n1) JSISTUBCALL(jsiStubsPtr, _Jsi_CDataRegister(n0,n1))
#define Jsi_CDataStructInit(n0,n1,n2) JSISTUBCALL(jsiStubsPtr, _Jsi_CDataStructInit(n0,n1,n2))
#define Jsi_DllLookup(n0,n1,n2,n3) JSISTUBCALL(jsiStubsPtr, _Jsi_DllLookup(n0,n1,n2,n3))
#define Jsi_LoadLibrary(n0,n1,n2) JSISTUBCALL(jsiStubsPtr, _Jsi_LoadLibrary(n0,n1,n2))
#define Jsi_CDataStruct(n0,n1) JSISTUBCALL(jsiStubsPtr, _Jsi_CDataStruct(n0,n1))
#define Jsi_StrdupLen(n0,n1) JSISTUBCALL(jsiStubsPtr, _Jsi_StrdupLen(n0,n1))
#define Jsi_FileRead(n0,n1,n2) JSISTUBCALL(jsiStubsPtr, _Jsi_FileRead(n0,n1,n2))
#define Jsi_ValueNewStringConst(n0,n1,n2) JSISTUBCALL(jsiStubsPtr, _Jsi_ValueNewStringConst(n0,n1,n2))

#endif

#endif

Changes to src/jsiUtf8.c.

118
119
120
121
122
123
124

125

126
127
128
129
130
131
132
                ustart = m;
                ulen = e+l-1;
            }
        }
    }
#endif
    if (ulen>len) {

        fprintf(stderr, "TODO: fix utf substr\n");

        ulen = len;
    }
    Jsi_DSAppendLen(dStr, str+ustart, ulen);
    return Jsi_DSValue(dStr);
}

int Jsi_UtfIndexToOffset(const char *str, int index)







>

>







118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
                ustart = m;
                ulen = e+l-1;
            }
        }
    }
#endif
    if (ulen>len) {
#if JSI__MEMDEBUG
        fprintf(stderr, "TODO: fix utf substr\n");
#endif
        ulen = len;
    }
    Jsi_DSAppendLen(dStr, str+ustart, ulen);
    return Jsi_DSValue(dStr);
}

int Jsi_UtfIndexToOffset(const char *str, int index)

Changes to src/jsiWebSocket.c.

124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
...
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
...
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
...
315
316
317
318
319
320
321

322
323
324
325
326
327
328
...
772
773
774
775
776
777
778
779






































































780
781
782
783
784
785
786
787
788
789
790
791
792
793

794
795
796
797
798
799
800
...
923
924
925
926
927
928
929
930



931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961

962











963





964




965
966
967
968
969
970
971
....
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084




1085
1086
1087
1088
1089
1090
1091
....
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182




1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199

1200
1201
1202
1203
1204
1205
1206
....
2463
2464
2465
2466
2467
2468
2469

2470
2471
2472
2473
2474
2475
2476
....
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
....
2599
2600
2601
2602
2603
2604
2605
2606
2607
2608
2609
2610
2611
2612
2613
2614
2615
2616
    jsi_wsStatData stats;
    char *iface;
    const char* urlPrefix, *urlRedirect;
    const char *localhostName;
    const char *clientName;
    const char *clientIP;
    const char *useridPass;
    const char *realm;
    struct lws_context *instCtx;
    Jsi_Value *getRegexp, *post;
    unsigned int oldus;
    int opts;
    int hasOpts;
    int debug;
    int maxConnects;
................................................................................
    JSI_OPT(DSTRING,    jsi_wsPss, url,         .help="Url for connection"),
    JSI_OPT_END(jsi_wsPss, .help="Per-connection options")
};

static Jsi_OptionSpec WSOptions[] =
{
    JSI_OPT(STRING, jsi_wsCmdObj, address,    .help="In client-mode the address to connect to (127.0.0.1)" ),
    JSI_OPT(INT,    jsi_wsCmdObj, bufferPwr2, .help="Tune the recv/send buffer: value is a power of 2 (0-20)"),
    JSI_OPT(BOOL,   jsi_wsCmdObj, client,     .help="Run in client mode", jsi_IIOF),
    JSI_OPT(STRKEY, jsi_wsCmdObj, clientHost, .help="Override host name for client"),
    JSI_OPT(STRKEY, jsi_wsCmdObj, clientOrigin,.help="Override client origin (origin)"),
    JSI_OPT(INT,    jsi_wsCmdObj, debug,      .help="Set debug level. Setting this to 512 will turn on max libwebsocket log levels"),
    JSI_OPT(BOOL,   jsi_wsCmdObj, echo,       .help="LogInfo outputs all websock Send/Recv messages"),
    JSI_OPT(STRKEY, jsi_wsCmdObj, formParams, .help="Comma seperated list of upload form param names ('text,send,file,upload')", jsi_IIRO),
    JSI_OPT(OBJ,    jsi_wsCmdObj, extArgs,    .help="Arguments for extension handlers", jsi_IIOF),
................................................................................
    JSI_OPT(BOOL,   jsi_wsCmdObj, local,      .help="Limit connections to localhost addresses on the 127 network"),
    JSI_OPT(STRKEY, jsi_wsCmdObj, localhostName,.help="Client name used by localhost connections ('localhost')"),
    JSI_OPT(INT,    jsi_wsCmdObj, maxConnects,.help="In server mode, max number of client connections accepted"),
    JSI_OPT(INT,    jsi_wsCmdObj, maxDownload,.help="Max size of file download"),
    JSI_OPT(INT,    jsi_wsCmdObj, maxUpload,  .help="Max size of file upload will accept"),
    JSI_OPT(OBJ,    jsi_wsCmdObj, mimeTypes,  .help="Object providing map of file extensions to mime types (eg. {txt:'text/plain', bb:'text/bb'})", jsi_IIOF),
    JSI_OPT(BOOL,   jsi_wsCmdObj, noConfig,   .help="Disable use of conf() to change options after options after create", jsi_IIOF),
    JSI_OPT(BOOL,   jsi_wsCmdObj, noCompress, .help="Disable per-message-deflate extension"),
    JSI_OPT(BOOL,   jsi_wsCmdObj, noUpdate,   .help="Disable update event-processing (eg. to exit)"),
    JSI_OPT(BOOL,   jsi_wsCmdObj, noWebsock,  .help="Serve html, but disallow websocket upgrade", jsi_IIOF),
    JSI_OPT(BOOL,   jsi_wsCmdObj, noWarn,     .help="Quietly ignore file related errors"),
    JSI_OPT(FUNC,   jsi_wsCmdObj, onAuth,     .help="Function to call for http basic authentication", .flags=0, .custom=0, .data=(void*)"ws:userobj, id:number, url:string, userpass:string"),
    JSI_OPT(FUNC,   jsi_wsCmdObj, onClose,    .help="Function to call when the websocket connection closes", .flags=0, .custom=0, .data=(void*)"ws:userobj|null, id:number"),
    JSI_OPT(FUNC,   jsi_wsCmdObj, onCloseLast,.help="Function to call when last websock connection closes. On object delete arg is null", .flags=0, .custom=0, .data=(void*)"ws:userobj|null"),
    JSI_OPT(FUNC,   jsi_wsCmdObj, onFilter,   .help="Function to call on a new connection: return false to kill connection", .flags=0, .custom=0, .data=(void*)"ws:userobj, id:number, url:string, ishttp:boolean"),
................................................................................
    JSI_OPT(STRKEY, jsi_wsCmdObj, realm,      .help="Realm for basic auth (jsish)", ),
    JSI_OPT(INT,    jsi_wsCmdObj, recvBufMax, .help="Size limit of a websocket message", jsi_IIOF),
    JSI_OPT(INT,    jsi_wsCmdObj, recvBufTimeout,.help="Timeout for recv of a websock msg", jsi_IIOF),
    JSI_OPT(BOOL,   jsi_wsCmdObj, redirMax,   .help="Temporarily disable redirects when see more than this in 10 minutes"),
    JSI_OPT(STRING, jsi_wsCmdObj, rootdir,    .help="Directory to serve html from (\".\")"),
    JSI_OPT(CUSTOM, jsi_wsCmdObj, stats,      .help="Statistical data", jsi_IIRO, .custom=Jsi_Opt_SwitchSuboption, .data=WPSStats),
    JSI_OPT(TIME_T, jsi_wsCmdObj, startTime,  .help="Time of websocket start", jsi_IIRO),

    JSI_OPT(STRKEY, jsi_wsCmdObj, urlPrefix,  .help="Prefix in url to strip from path; for reverse proxy"),
    JSI_OPT(STRKEY, jsi_wsCmdObj, urlRedirect,.help="Redirect when no url or / is given. Must match urlPrefix, if given"),
    JSI_OPT(BOOL,   jsi_wsCmdObj, use_ssl,    .help="Use https (for client)", jsi_IIOF),
    JSI_OPT(STRKEY, jsi_wsCmdObj, useridPass, .help="The USERID:PASSWORD to use for basic authentication"),
    JSI_OPT(OBJ,    jsi_wsCmdObj, version,    .help="WebSocket version info", jsi_IIRO),
    JSI_OPT_END(jsi_wsCmdObj, .help="Websocket options")
};
................................................................................
            if (n>0)
                Jsi_DSAppendLen(hStr, (char*)buffer, n);
            p = buffer;
        }
    }
    return true;
}







































































// Handle http GET/POST
static int jsi_wsHttp(Jsi_Interp *interp, jsi_wsCmdObj *cmdPtr, struct lws *wsi, void *user,
    struct lws_context *context, const char* inPtr, Jsi_DString *tStr, jsi_wsPss *pss)
{
    const char *ext = NULL;
    unsigned char buffer[JSI_BUFSIZ];
    const char *mime = "text/html";
    time_t now = time(NULL);
    char buf[JSI_BUFSIZ];
    int rc = 0;
    buf[0] = 0;
    uchar *p = buffer, *end = &buffer[sizeof(buffer)-1];
    int n;
    Jsi_Value* fname = NULL;


    /* if a legal POST URL, let it continue and accept data */
    if (lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI))
        return 0;
    if (!pss)
        pss = jsi_wsgetPss(cmdPtr, wsi, user, 1, 1);
  
................................................................................
#endif

    snprintf(buf, sizeof(buf), "%s/%s", rootDir, inPtr);
    if (cmdPtr->debug>1)
        fprintf(stderr, "FILE: %s in %s | %s\n", buf, rootDir, Jsi_ValueString(interp, cmdPtr->rootdir, NULL));
    char extBuf[100];
    bool isgzip = 0;
    if (ext) {



        uint elen = Jsi_Strlen(ext);
        if (elen>3 && elen<(sizeof(extBuf)-10) && !Jsi_Strcmp(ext+elen-3,".gz")) {
            Jsi_Strcpy(extBuf, ext);
            extBuf[elen-3] = 0;
            char *ext2 = Jsi_Strrchr(extBuf, '.');
            if (ext2) {
                isgzip = 1;
                ext = ext2;
            }
        }
        Jsi_HashEntry *hPtr;

        if (Jsi_Strncasecmp(ext,".html", -1) == 0) mime = "text/html";
        else if (Jsi_Strncasecmp(ext,".js", -1) == 0) mime = "application/x-javascript";
        else if (Jsi_Strncasecmp(ext,".css", -1) == 0) mime = "text/css";
        else if (Jsi_Strncasecmp(ext,".htmli", -1) == 0) mime = "text/html";
        else if (Jsi_Strncasecmp(ext,".md", -1) == 0) mime = "text/html";
        else if (Jsi_Strncasecmp(ext,".jsi", -1) == 0) mime = "application/x-javascript";
        else if (Jsi_Strncasecmp(ext,".cssi", -1) == 0) mime = "text/css";
        else if (Jsi_Strncasecmp(ext,".png", -1) == 0) mime = "image/png";
        else if (Jsi_Strncasecmp(ext,".ico", -1) == 0) mime = "image/icon";
        else if (Jsi_Strncasecmp(ext,".gif", -1) == 0) mime = "image/gif";
        else if (Jsi_Strncasecmp(ext,".jpeg", -1) == 0) mime = "image/jpeg";
        else if (Jsi_Strncasecmp(ext,".jpg", -1) == 0) mime = "image/jpeg";
        else if (Jsi_Strncasecmp(ext,".svg", -1) == 0) mime = "image/svg+xml";
        else if (Jsi_Strncasecmp(ext,".json", -1) == 0) mime = "application/json";
        else if (Jsi_Strncasecmp(ext,".txt", -1) == 0) mime = "text/plain";
        else if (cmdPtr->mimeTypes) {
            /* Lookup mime type in mimeTypes object. */
            const char *nmime;
            Jsi_Value *mVal = Jsi_ValueObjLookup(interp, cmdPtr->mimeTypes, ext+1, 1);

            if (mVal && ((nmime = Jsi_ValueString(interp, mVal, NULL))))











                mime = nmime;





        }




        
        if ((hPtr = Jsi_HashEntryFind(cmdPtr->handlers, ext)) && !cmdPtr->deleted) {
            /* Use interprete html eg. using jsi_wpp preprocessor */
            Jsi_DString jStr = {};
            Jsi_Value *vrc = NULL;
            int hrc = 0, strLen, evrc, isalloc=0;
            char *vStr, *hstr = NULL;
................................................................................
            if (hrc<=0)
                return -1;
            return 1;
        }
    }
    if (!buf[0]) {
        if (cmdPtr->debug)
            fprintf(stderr, "Unknown file: %s\n", inPtr);
        return -1;
    }
    fname = Jsi_ValueNewStringDup(interp, buf);
    Jsi_IncrRefCount(interp, fname);
    
    Jsi_DString hStr = {};
    Jsi_StatBuf jsb;
    bool native = Jsi_FSNative(interp, fname);




    if ((native && Jsi_InterpSafe(interp) && Jsi_InterpAccess(interp, fname, JSI_INTACCESS_READ) != JSI_OK) ||
        (Jsi_Stat(interp, fname, &jsb) || jsb.st_size<=0)) {
nofile:
        if (cmdPtr->onUnknown || pss->onUnknown) {
            Jsi_Value *uk = (pss->onUnknown?pss->onUnknown:cmdPtr->onUnknown);
            Jsi_RC jrc = jsi_wsGetCmd(interp, cmdPtr, pss, wsi, inPtr, uk, NULL);
            if (jrc == JSI_ERROR)
................................................................................
        goto bail;
        
    if (pss->headers && !jsi_wsAddHeader(interp, cmdPtr, wsi, pss->headers, &hStr))
        goto bail;

    n = Jsi_DSLength(&hStr);
    
    if (native) {
        Jsi_DecrRefCount(interp, fname);

        int hrc = lws_serve_http_file(wsi, buf, mime, Jsi_DSValue(&hStr), Jsi_DSLength(&hStr));
        if (hrc<0) {
            if (cmdPtr->noWarn==0)
                fprintf(stderr, "can not serve file (%d): %s\n", hrc, buf);
            goto bail;
        } else if (hrc > 0 && lws_http_transaction_completed(wsi))
            goto bail;
    } else {
        // Need to read data for non-native files.
        Jsi_Channel chan = Jsi_Open(interp, fname, "rb");
        int n, sum = 0;

        if (!chan) {




            goto nofile;
        }
        Jsi_DString dStr = {};
        char sbuf[JSI_BUFSIZ];
        int hrc = jsi_wsServeHeader(pss, wsi, (int)jsb.st_size, 200, Jsi_DSValue(&hStr), mime, &dStr);
        if (hrc>=0) {
            while (sum < 10000000 && (n = Jsi_Read(interp, chan, sbuf, sizeof(sbuf))) > 0) {
                Jsi_DSAppendLen(&dStr, sbuf, n);
                sum += n;
            }
            char *str = Jsi_DSValue(&dStr);
            int strLen = Jsi_DSLength(&dStr);
            hrc = jsi_wswrite(pss, wsi, (unsigned char*)str, strLen, LWS_WRITE_HTTP);
        }
        Jsi_DecrRefCount(interp, fname);
        Jsi_Close(interp, chan);
        Jsi_DSFree(&dStr);

        if (hrc<0) {
            if (cmdPtr->noWarn==0)
                fprintf(stderr, "can not serve data (%d): %s\n", hrc, buf);
            goto bail;
        } else if (hrc > 0 && lws_http_transaction_completed(wsi))
            goto bail;

................................................................................
    cmdPtr->interp = interp;
    cmdPtr->ietf_version = -1;
    cmdPtr->bufferPwr2 = 0;
    cmdPtr->ws_gid = -1;
    cmdPtr->ws_uid = -1;
    cmdPtr->startTime = time(NULL);
    cmdPtr->hasOpts = 1;

    if ((arg != NULL && !Jsi_ValueIsNull(interp,arg))
        && Jsi_OptionsProcess(interp, WSOptions, cmdPtr, arg, 0) < 0) {
bail:
        jsi_wswebsocketObjFree(interp, cmdPtr);
        return JSI_ERROR;
    }
    if (cmdPtr->headers && (Jsi_ValueGetLength(interp, cmdPtr->headers)%2)) {
................................................................................
    cmdPtr->protocols[JWS_PROTOCOL_HTTP].name="http-only";
    cmdPtr->protocols[JWS_PROTOCOL_HTTP].callback=jsi_wscallback_http;
    cmdPtr->protocols[JWS_PROTOCOL_HTTP].per_session_data_size=sizeof(jsi_wsPss);
    cmdPtr->protocols[JWS_PROTOCOL_WEBSOCK].name=subprot;
    cmdPtr->protocols[JWS_PROTOCOL_WEBSOCK].callback=jsi_wscallback_websock;
    cmdPtr->protocols[JWS_PROTOCOL_WEBSOCK].per_session_data_size=sizeof(jsi_wsPss);

    if (cmdPtr->bufferPwr2 == 0 && !cmdPtr->noCompress)
        cmdPtr->bufferPwr2 = 12;
    if (cmdPtr->bufferPwr2>0) {
        if (cmdPtr->bufferPwr2>20) {
            Jsi_LogError("bufferPwr2 not in 0-20: %d", cmdPtr->bufferPwr2);
            goto bail;
        }
        cmdPtr->protocols[JWS_PROTOCOL_WEBSOCK].rx_buffer_size=(1<<cmdPtr->bufferPwr2);
    }
................................................................................

    Jsi_Obj *fobj = Jsi_ValueGetObj(interp, toacc);
    if ((cmdPtr->objId = Jsi_UserObjNew(interp, &websockobject, fobj, cmdPtr))<0) {
        goto bail;
    }
    cmdPtr->handlers = Jsi_HashNew(interp, JSI_KEYS_STRING, jsi_wsfreeHandlers);
    if (cmdPtr->extHandlers) {
        jsi_wsHandlerAdd(interp, cmdPtr, ".jsi",   "Jsi_Jspp",   jsi_wsStrValGet(cmdPtr, "jsi"), 1);
        jsi_wsHandlerAdd(interp, cmdPtr, ".htmli", "Jsi_Htmlpp", jsi_wsStrValGet(cmdPtr, "htmli"), 1);
        jsi_wsHandlerAdd(interp, cmdPtr, ".cssi",  "Jsi_Csspp",  jsi_wsStrValGet(cmdPtr, "cssi"), 1);
        jsi_wsHandlerAdd(interp, cmdPtr, ".md",    "Jsi_Markdeep", jsi_wsStrValGet(cmdPtr, "md"), 1);
    }
    cmdPtr->fobj = fobj;
#ifdef LWS_LIBRARY_VERSION_NUMBER
    Jsi_JSONParseFmt(interp, &cmdPtr->version, "{libVer:\"%s\", hdrVer:\"%s\", hdrNum:%d, pkgVer:%d}",
        (char *)lws_get_library_version(), LWS_LIBRARY_VERSION, LWS_LIBRARY_VERSION_NUMBER, jsi_WsPkgVersion); 
#endif
    return JSI_OK;







|







 







|







 







|







 







>







 








>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>






|


|




>







 







|
>
>
>












<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
|

<

>
|
>
>
>
>
>
>
>
>
>
>
>
|
>
>
>
>
>
|
>
>
>
>







 







|








>
>
>
>







 







|











|
<
<
|
>
>
>
>

<
<
<
|

<
|
<
<
|

|


<

>







 







>







 







|
|







 







|
|
|
|







124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
...
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
...
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
...
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
...
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
...
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017















1018
1019

1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
....
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
....
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263


1264
1265
1266
1267
1268
1269



1270
1271

1272


1273
1274
1275
1276
1277

1278
1279
1280
1281
1282
1283
1284
1285
1286
....
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
....
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
....
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
2692
2693
2694
2695
2696
2697
    jsi_wsStatData stats;
    char *iface;
    const char* urlPrefix, *urlRedirect;
    const char *localhostName;
    const char *clientName;
    const char *clientIP;
    const char *useridPass;
    const char *realm, *templateFile;
    struct lws_context *instCtx;
    Jsi_Value *getRegexp, *post;
    unsigned int oldus;
    int opts;
    int hasOpts;
    int debug;
    int maxConnects;
................................................................................
    JSI_OPT(DSTRING,    jsi_wsPss, url,         .help="Url for connection"),
    JSI_OPT_END(jsi_wsPss, .help="Per-connection options")
};

static Jsi_OptionSpec WSOptions[] =
{
    JSI_OPT(STRING, jsi_wsCmdObj, address,    .help="In client-mode the address to connect to (127.0.0.1)" ),
    JSI_OPT(INT,    jsi_wsCmdObj, bufferPwr2, .help="Tune the recv/send buffer: value is a power of 2 in [0-20] (16)"),
    JSI_OPT(BOOL,   jsi_wsCmdObj, client,     .help="Run in client mode", jsi_IIOF),
    JSI_OPT(STRKEY, jsi_wsCmdObj, clientHost, .help="Override host name for client"),
    JSI_OPT(STRKEY, jsi_wsCmdObj, clientOrigin,.help="Override client origin (origin)"),
    JSI_OPT(INT,    jsi_wsCmdObj, debug,      .help="Set debug level. Setting this to 512 will turn on max libwebsocket log levels"),
    JSI_OPT(BOOL,   jsi_wsCmdObj, echo,       .help="LogInfo outputs all websock Send/Recv messages"),
    JSI_OPT(STRKEY, jsi_wsCmdObj, formParams, .help="Comma seperated list of upload form param names ('text,send,file,upload')", jsi_IIRO),
    JSI_OPT(OBJ,    jsi_wsCmdObj, extArgs,    .help="Arguments for extension handlers", jsi_IIOF),
................................................................................
    JSI_OPT(BOOL,   jsi_wsCmdObj, local,      .help="Limit connections to localhost addresses on the 127 network"),
    JSI_OPT(STRKEY, jsi_wsCmdObj, localhostName,.help="Client name used by localhost connections ('localhost')"),
    JSI_OPT(INT,    jsi_wsCmdObj, maxConnects,.help="In server mode, max number of client connections accepted"),
    JSI_OPT(INT,    jsi_wsCmdObj, maxDownload,.help="Max size of file download"),
    JSI_OPT(INT,    jsi_wsCmdObj, maxUpload,  .help="Max size of file upload will accept"),
    JSI_OPT(OBJ,    jsi_wsCmdObj, mimeTypes,  .help="Object providing map of file extensions to mime types (eg. {txt:'text/plain', bb:'text/bb'})", jsi_IIOF),
    JSI_OPT(BOOL,   jsi_wsCmdObj, noConfig,   .help="Disable use of conf() to change options after options after create", jsi_IIOF),
    JSI_OPT(BOOL,   jsi_wsCmdObj, noCompress, .help="Disable per-message-deflate extension which can truncate large msgs"),
    JSI_OPT(BOOL,   jsi_wsCmdObj, noUpdate,   .help="Disable update event-processing (eg. to exit)"),
    JSI_OPT(BOOL,   jsi_wsCmdObj, noWebsock,  .help="Serve html, but disallow websocket upgrade", jsi_IIOF),
    JSI_OPT(BOOL,   jsi_wsCmdObj, noWarn,     .help="Quietly ignore file related errors"),
    JSI_OPT(FUNC,   jsi_wsCmdObj, onAuth,     .help="Function to call for http basic authentication", .flags=0, .custom=0, .data=(void*)"ws:userobj, id:number, url:string, userpass:string"),
    JSI_OPT(FUNC,   jsi_wsCmdObj, onClose,    .help="Function to call when the websocket connection closes", .flags=0, .custom=0, .data=(void*)"ws:userobj|null, id:number"),
    JSI_OPT(FUNC,   jsi_wsCmdObj, onCloseLast,.help="Function to call when last websock connection closes. On object delete arg is null", .flags=0, .custom=0, .data=(void*)"ws:userobj|null"),
    JSI_OPT(FUNC,   jsi_wsCmdObj, onFilter,   .help="Function to call on a new connection: return false to kill connection", .flags=0, .custom=0, .data=(void*)"ws:userobj, id:number, url:string, ishttp:boolean"),
................................................................................
    JSI_OPT(STRKEY, jsi_wsCmdObj, realm,      .help="Realm for basic auth (jsish)", ),
    JSI_OPT(INT,    jsi_wsCmdObj, recvBufMax, .help="Size limit of a websocket message", jsi_IIOF),
    JSI_OPT(INT,    jsi_wsCmdObj, recvBufTimeout,.help="Timeout for recv of a websock msg", jsi_IIOF),
    JSI_OPT(BOOL,   jsi_wsCmdObj, redirMax,   .help="Temporarily disable redirects when see more than this in 10 minutes"),
    JSI_OPT(STRING, jsi_wsCmdObj, rootdir,    .help="Directory to serve html from (\".\")"),
    JSI_OPT(CUSTOM, jsi_wsCmdObj, stats,      .help="Statistical data", jsi_IIRO, .custom=Jsi_Opt_SwitchSuboption, .data=WPSStats),
    JSI_OPT(TIME_T, jsi_wsCmdObj, startTime,  .help="Time of websocket start", jsi_IIRO),
    JSI_OPT(STRKEY, jsi_wsCmdObj, templateFile,.help="File name for markdeep template (template.shtml)"),
    JSI_OPT(STRKEY, jsi_wsCmdObj, urlPrefix,  .help="Prefix in url to strip from path; for reverse proxy"),
    JSI_OPT(STRKEY, jsi_wsCmdObj, urlRedirect,.help="Redirect when no url or / is given. Must match urlPrefix, if given"),
    JSI_OPT(BOOL,   jsi_wsCmdObj, use_ssl,    .help="Use https (for client)", jsi_IIOF),
    JSI_OPT(STRKEY, jsi_wsCmdObj, useridPass, .help="The USERID:PASSWORD to use for basic authentication"),
    JSI_OPT(OBJ,    jsi_wsCmdObj, version,    .help="WebSocket version info", jsi_IIRO),
    JSI_OPT_END(jsi_wsCmdObj, .help="Websocket options")
};
................................................................................
            if (n>0)
                Jsi_DSAppendLen(hStr, (char*)buffer, n);
            p = buffer;
        }
    }
    return true;
}

static Jsi_RC jsi_wsTemplateFill(Jsi_Interp *interp, jsi_wsCmdObj *cmdPtr, Jsi_Value *fn, Jsi_DString *dStr,
    int lvl) {
    Jsi_Value *fval;
    Jsi_RC rc = JSI_OK;
    char *cp, *ce, pref[] = "<!--#include file=\"", suffix[] = "\"-->";
    int flen, plen = sizeof(pref)-1, slen = sizeof(suffix)-1;
    Jsi_DString tStr = {};
    const char *cs = "<!-- Markdeep: --><style class=\"fallback\">body{visibility:hidden;}</style>\n"
                "<script>window.markdeepOptions={tocStyle:\"medium\"}</script>\n"
                "<!--#include file=\"$inc\"-->\n"
                "<script src=\"markdeep.min.js\"></script>\n"
                "<script>window.alreadyProcessedMarkdeep||(document.body.style.visibility='visible')</script>";
    char *fs, *fname = Jsi_ValueString(interp, fn, &flen), *fend = fname;
    char fbuf[PATH_MAX];
    if (lvl>10)
        return JSI_ERROR;
    fs = Jsi_Strrchr(fname, '/');
    if (fs) {
        flen = fs-fname;
        fend = fs+1;
    }
    if (lvl>0) {
        rc = Jsi_FileRead(interp, fn, &tStr);
        cs = Jsi_DSValue(&tStr);
    } else {
        snprintf(fbuf, sizeof(fbuf), "%.*s%s", flen, fname, cmdPtr->templateFile);
        fval = Jsi_ValueNewStringConst(interp, fbuf, -1);
        Jsi_IncrRefCount(interp, fval);
        Jsi_StatBuf sb;
        int n = Jsi_Stat(interp, fval, &sb);
        if (!n && sb.st_size>0) {
            rc = Jsi_FileRead(interp, fval, &tStr);
            cs = Jsi_DSValue(&tStr);
        }
        Jsi_DecrRefCount(interp, fval);
    }
    
    while (rc == JSI_OK && cs) {
        char *ext = NULL;
        cp = Jsi_Strstr(cs, pref);
        if (!cp || !(ce=Jsi_Strstr(cp+plen, suffix))) {
            Jsi_DSAppend(dStr, cs, NULL);
            break;
        }
        Jsi_DSAppendLen(dStr, cs, cp-cs);
        if (cp[plen] == '$' && lvl == 0) {
            snprintf(fbuf, sizeof(fbuf), "%.*spages/%s.md", flen, fname, fend);
        } else {
            cp += plen;
            int elen = ce-cp;
            snprintf(fbuf, sizeof(fbuf), "%.*s/%.*s", flen, fname, elen, cp);
            ext = Jsi_Strrchr(fbuf, '.');
        }
        fval = Jsi_ValueNewStringConst(interp, fbuf, -1);
        Jsi_IncrRefCount(interp, fval);
        if (!ext || Jsi_Strcmp(ext, ".shtml"))
            rc = Jsi_FileRead(interp, fval, dStr);
        else
            rc = jsi_wsTemplateFill(interp, cmdPtr, fval, dStr, lvl+1);
        Jsi_DecrRefCount(interp, fval);
    
        cs = ce + slen;
        if (*cs == '\n')
            cs++;
    }
    Jsi_DSFree(&tStr);
    return rc;
    
}

// Handle http GET/POST
static int jsi_wsHttp(Jsi_Interp *interp, jsi_wsCmdObj *cmdPtr, struct lws *wsi, void *user,
    struct lws_context *context, const char* inPtr, Jsi_DString *tStr, jsi_wsPss *pss)
{
    const char *ext = NULL;
    unsigned char buffer[JSI_BUFSIZ];
    const char *mime = NULL;
    time_t now = time(NULL);
    char buf[JSI_BUFSIZ];
    int rc = 0, essi = 0;
    buf[0] = 0;
    uchar *p = buffer, *end = &buffer[sizeof(buffer)-1];
    int n;
    Jsi_Value* fname = NULL;
    bool isMdi = 0;

    /* if a legal POST URL, let it continue and accept data */
    if (lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI))
        return 0;
    if (!pss)
        pss = jsi_wsgetPss(cmdPtr, wsi, user, 1, 1);
  
................................................................................
#endif

    snprintf(buf, sizeof(buf), "%s/%s", rootDir, inPtr);
    if (cmdPtr->debug>1)
        fprintf(stderr, "FILE: %s in %s | %s\n", buf, rootDir, Jsi_ValueString(interp, cmdPtr->rootdir, NULL));
    char extBuf[100];
    bool isgzip = 0;
    if (!ext || !ext[1])
        mime = "text/html";
    else {
        const char *eext = ext+1;
        uint elen = Jsi_Strlen(ext);
        if (elen>3 && elen<(sizeof(extBuf)-10) && !Jsi_Strcmp(ext+elen-3,".gz")) {
            Jsi_Strcpy(extBuf, ext);
            extBuf[elen-3] = 0;
            char *ext2 = Jsi_Strrchr(extBuf, '.');
            if (ext2) {
                isgzip = 1;
                ext = ext2;
            }
        }
        Jsi_HashEntry *hPtr;
















        if (cmdPtr->mimeTypes) {
            /* Lookup mime type in mimeTypes object. */

            Jsi_Value *mVal = Jsi_ValueObjLookup(interp, cmdPtr->mimeTypes, ext+1, 1);
            if (mVal)
                mime = Jsi_ValueString(interp, mVal, NULL);
        }
        if (!mime) {
            static const char* mtypes[] = {
                "html", "text/html", "js", "application/x-javascript", 
                "css", "text/css", "png", "image/png", "ico", "image/icon",
                "gif", "image/gif", "jpeg", "image/jpeg", 
                "jpg", "image/jpeg", "svg", "image/svg+xml",
                "json", "application/json", "txt", "text/plain",
                "jsi", "application/x-javascript", "cssi", "text/css",  
                0, 0
            };
            mime = "text/html";
            int i;
            for (i=0; mtypes[i]; i+=2)
                if (tolower(*eext) == mtypes[i][0] && !Jsi_Strncasecmp(eext, mtypes[i], -1)) {
                    mime = mtypes[i+1];
                    break;
                }
        }
        
        if (!Jsi_Strncasecmp(eext,"shtml", -1))
            essi = 1;
        
        if ((hPtr = Jsi_HashEntryFind(cmdPtr->handlers, ext)) && !cmdPtr->deleted) {
            /* Use interprete html eg. using jsi_wpp preprocessor */
            Jsi_DString jStr = {};
            Jsi_Value *vrc = NULL;
            int hrc = 0, strLen, evrc, isalloc=0;
            char *vStr, *hstr = NULL;
................................................................................
            if (hrc<=0)
                return -1;
            return 1;
        }
    }
    if (!buf[0]) {
        if (cmdPtr->debug)
            fprintf(stderr, "empty file: %s\n", inPtr);
        return -1;
    }
    fname = Jsi_ValueNewStringDup(interp, buf);
    Jsi_IncrRefCount(interp, fname);
    
    Jsi_DString hStr = {};
    Jsi_StatBuf jsb;
    bool native = Jsi_FSNative(interp, fname);
    if (!ext || essi) {
        isMdi = 1;
        goto serve;
    }
    if ((native && Jsi_InterpSafe(interp) && Jsi_InterpAccess(interp, fname, JSI_INTACCESS_READ) != JSI_OK) ||
        (Jsi_Stat(interp, fname, &jsb) || jsb.st_size<=0)) {
nofile:
        if (cmdPtr->onUnknown || pss->onUnknown) {
            Jsi_Value *uk = (pss->onUnknown?pss->onUnknown:cmdPtr->onUnknown);
            Jsi_RC jrc = jsi_wsGetCmd(interp, cmdPtr, pss, wsi, inPtr, uk, NULL);
            if (jrc == JSI_ERROR)
................................................................................
        goto bail;
        
    if (pss->headers && !jsi_wsAddHeader(interp, cmdPtr, wsi, pss->headers, &hStr))
        goto bail;

    n = Jsi_DSLength(&hStr);
    
    if (native && !isMdi) {
        Jsi_DecrRefCount(interp, fname);

        int hrc = lws_serve_http_file(wsi, buf, mime, Jsi_DSValue(&hStr), Jsi_DSLength(&hStr));
        if (hrc<0) {
            if (cmdPtr->noWarn==0)
                fprintf(stderr, "can not serve file (%d): %s\n", hrc, buf);
            goto bail;
        } else if (hrc > 0 && lws_http_transaction_completed(wsi))
            goto bail;
    } else {
        // Need to read data for non-native files.
        Jsi_DString dStr = {}, fStr = {};


        if (isMdi)
            rc = jsi_wsTemplateFill(interp, cmdPtr, fname, &fStr, (essi?1:0));
        else
            rc = Jsi_FileRead(interp, fname, &fStr);
        if (rc != JSI_OK)
            goto nofile;



        int hrc = jsi_wsServeHeader(pss, wsi, (int)Jsi_DSLength(&fStr), 200, Jsi_DSValue(&hStr), mime, &dStr);
        if (hrc>=0) {

            Jsi_DSAppendLen(&dStr, Jsi_DSValue(&fStr), Jsi_DSLength(&fStr));


            char *strVal = Jsi_DSValue(&dStr);
            int strLen = Jsi_DSLength(&dStr);
            hrc = jsi_wswrite(pss, wsi, (unsigned char*)strVal, strLen, LWS_WRITE_HTTP);
        }
        Jsi_DecrRefCount(interp, fname);

        Jsi_DSFree(&dStr);
        Jsi_DSFree(&fStr);
        if (hrc<0) {
            if (cmdPtr->noWarn==0)
                fprintf(stderr, "can not serve data (%d): %s\n", hrc, buf);
            goto bail;
        } else if (hrc > 0 && lws_http_transaction_completed(wsi))
            goto bail;

................................................................................
    cmdPtr->interp = interp;
    cmdPtr->ietf_version = -1;
    cmdPtr->bufferPwr2 = 0;
    cmdPtr->ws_gid = -1;
    cmdPtr->ws_uid = -1;
    cmdPtr->startTime = time(NULL);
    cmdPtr->hasOpts = 1;
    cmdPtr->templateFile = "template.shtml";
    if ((arg != NULL && !Jsi_ValueIsNull(interp,arg))
        && Jsi_OptionsProcess(interp, WSOptions, cmdPtr, arg, 0) < 0) {
bail:
        jsi_wswebsocketObjFree(interp, cmdPtr);
        return JSI_ERROR;
    }
    if (cmdPtr->headers && (Jsi_ValueGetLength(interp, cmdPtr->headers)%2)) {
................................................................................
    cmdPtr->protocols[JWS_PROTOCOL_HTTP].name="http-only";
    cmdPtr->protocols[JWS_PROTOCOL_HTTP].callback=jsi_wscallback_http;
    cmdPtr->protocols[JWS_PROTOCOL_HTTP].per_session_data_size=sizeof(jsi_wsPss);
    cmdPtr->protocols[JWS_PROTOCOL_WEBSOCK].name=subprot;
    cmdPtr->protocols[JWS_PROTOCOL_WEBSOCK].callback=jsi_wscallback_websock;
    cmdPtr->protocols[JWS_PROTOCOL_WEBSOCK].per_session_data_size=sizeof(jsi_wsPss);

    if (cmdPtr->bufferPwr2 == 0)
        cmdPtr->bufferPwr2 = 16;
    if (cmdPtr->bufferPwr2>0) {
        if (cmdPtr->bufferPwr2>20) {
            Jsi_LogError("bufferPwr2 not in 0-20: %d", cmdPtr->bufferPwr2);
            goto bail;
        }
        cmdPtr->protocols[JWS_PROTOCOL_WEBSOCK].rx_buffer_size=(1<<cmdPtr->bufferPwr2);
    }
................................................................................

    Jsi_Obj *fobj = Jsi_ValueGetObj(interp, toacc);
    if ((cmdPtr->objId = Jsi_UserObjNew(interp, &websockobject, fobj, cmdPtr))<0) {
        goto bail;
    }
    cmdPtr->handlers = Jsi_HashNew(interp, JSI_KEYS_STRING, jsi_wsfreeHandlers);
    if (cmdPtr->extHandlers) {
        jsi_wsHandlerAdd(interp, cmdPtr, ".jsi",   "Jsi_Jspp",     jsi_wsStrValGet(cmdPtr, "jsi"),   1);
        jsi_wsHandlerAdd(interp, cmdPtr, ".htmli", "Jsi_Htmlpp",   jsi_wsStrValGet(cmdPtr, "htmli"), 1);
        jsi_wsHandlerAdd(interp, cmdPtr, ".cssi",  "Jsi_Csspp",    jsi_wsStrValGet(cmdPtr, "cssi"),  1);
        jsi_wsHandlerAdd(interp, cmdPtr, ".mdi",   "Jsi_Markdeep", jsi_wsStrValGet(cmdPtr, "mdi"),   1);
    }
    cmdPtr->fobj = fobj;
#ifdef LWS_LIBRARY_VERSION_NUMBER
    Jsi_JSONParseFmt(interp, &cmdPtr->version, "{libVer:\"%s\", hdrVer:\"%s\", hdrNum:%d, pkgVer:%d}",
        (char *)lws_get_library_version(), LWS_LIBRARY_VERSION, LWS_LIBRARY_VERSION_NUMBER, jsi_WsPkgVersion); 
#endif
    return JSI_OK;

Changes to tools/protos.jsi.

1
2
3
4
5
6
7
8
//JSI Command Prototypes: version 2.6.0
throw("NOT EXECUTABLE: USE FILE IN GEANY EDITOR FOR CMD LINE COMPLETION + GOTO TAG");

var Array = function(cmd,args) {};
Array.prototype.concat = function(...):array {};
Array.prototype.every = function(callback:function):any {};
Array.prototype.fill = function(value:any, start:number=0, end:number=-1):array {};
Array.prototype.filter = function(callback:function, this:object=void):array {};
|







1
2
3
4
5
6
7
8
//JSI Command Prototypes: version 2.6.1
throw("NOT EXECUTABLE: USE FILE IN GEANY EDITOR FOR CMD LINE COMPLETION + GOTO TAG");

var Array = function(cmd,args) {};
Array.prototype.concat = function(...):array {};
Array.prototype.every = function(callback:function):any {};
Array.prototype.fill = function(value:any, start:number=0, end:number=-1):array {};
Array.prototype.filter = function(callback:function, this:object=void):array {};

Changes to www/reference.wiki.

1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
....
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
....
1635
1636
1637
1638
1639
1640
1641

1642
1643
1644
1645
1646
1647
1648

<a name="new WebSocketOptions"></a>
<a name="WebSocket.confOptions"></a>
<h2>Options for "new WebSocket"</h2>
<table border="1" class="optstbl table">
<tr><th>Option</th> <th>Type</th> <th>Description</th><th>Flags</th></tr>
<tr><td>address</td><td><i>STRING</i></td><td>In client-mode the address to connect to (127.0.0.1).</td><td><i></i></td></tr>
<tr><td>bufferPwr2</td><td><i>INT</i></td><td>Tune the recv/send buffer: value is a power of 2 (0-20).</td><td><i></i></td></tr>
<tr><td>client</td><td><i>BOOL</i></td><td>Run in client mode.</td><td><i>initOnly</i></td></tr>
<tr><td>clientHost</td><td><i>STRKEY</i></td><td>Override host name for client.</td><td><i></i></td></tr>
<tr><td>clientOrigin</td><td><i>STRKEY</i></td><td>Override client origin (origin).</td><td><i></i></td></tr>
<tr><td>debug</td><td><i>INT</i></td><td>Set debug level. Setting this to 512 will turn on max libwebsocket log levels.</td><td><i></i></td></tr>
<tr><td>echo</td><td><i>BOOL</i></td><td>LogInfo outputs all websock Send/Recv messages.</td><td><i></i></td></tr>
<tr><td>formParams</td><td><i>STRKEY</i></td><td>Comma seperated list of upload form param names ('text,send,file,upload').</td><td><i>readOnly</i></td></tr>
<tr><td>extArgs</td><td><i>OBJ</i></td><td>Arguments for extension handlers.</td><td><i>initOnly</i></td></tr>
................................................................................
<tr><td>local</td><td><i>BOOL</i></td><td>Limit connections to localhost addresses on the 127 network.</td><td><i></i></td></tr>
<tr><td>localhostName</td><td><i>STRKEY</i></td><td>Client name used by localhost connections ('localhost').</td><td><i></i></td></tr>
<tr><td>maxConnects</td><td><i>INT</i></td><td>In server mode, max number of client connections accepted.</td><td><i></i></td></tr>
<tr><td>maxDownload</td><td><i>INT</i></td><td>Max size of file download.</td><td><i></i></td></tr>
<tr><td>maxUpload</td><td><i>INT</i></td><td>Max size of file upload will accept.</td><td><i></i></td></tr>
<tr><td>mimeTypes</td><td><i>OBJ</i></td><td>Object providing map of file extensions to mime types (eg. {txt:'text/plain', bb:'text/bb'}).</td><td><i>initOnly</i></td></tr>
<tr><td>noConfig</td><td><i>BOOL</i></td><td>Disable use of conf() to change options after options after create.</td><td><i>initOnly</i></td></tr>
<tr><td>noCompress</td><td><i>BOOL</i></td><td>Disable per-message-deflate extension.</td><td><i></i></td></tr>
<tr><td>noUpdate</td><td><i>BOOL</i></td><td>Disable update event-processing (eg. to exit).</td><td><i></i></td></tr>
<tr><td>noWebsock</td><td><i>BOOL</i></td><td>Serve html, but disallow websocket upgrade.</td><td><i>initOnly</i></td></tr>
<tr><td>noWarn</td><td><i>BOOL</i></td><td>Quietly ignore file related errors.</td><td><i></i></td></tr>
<tr><td>onAuth</td><td><i>FUNC</i></td><td>Function to call for http basic authentication. @function(ws:userobj, id:number, url:string, userpass:string)</td><td><i></i></td></tr>
<tr><td>onClose</td><td><i>FUNC</i></td><td>Function to call when the websocket connection closes. @function(ws:userobj|null, id:number)</td><td><i></i></td></tr>
<tr><td>onCloseLast</td><td><i>FUNC</i></td><td>Function to call when last websock connection closes. On object delete arg is null. @function(ws:userobj|null)</td><td><i></i></td></tr>
<tr><td>onFilter</td><td><i>FUNC</i></td><td>Function to call on a new connection: return false to kill connection. @function(ws:userobj, id:number, url:string, ishttp:boolean)</td><td><i></i></td></tr>
................................................................................
<tr><td>realm</td><td><i>STRKEY</i></td><td>Realm for basic auth (jsish).</td><td><i></i></td></tr>
<tr><td>recvBufMax</td><td><i>INT</i></td><td>Size limit of a websocket message.</td><td><i>initOnly</i></td></tr>
<tr><td>recvBufTimeout</td><td><i>INT</i></td><td>Timeout for recv of a websock msg.</td><td><i>initOnly</i></td></tr>
<tr><td>redirMax</td><td><i>BOOL</i></td><td>Temporarily disable redirects when see more than this in 10 minutes.</td><td><i></i></td></tr>
<tr><td>rootdir</td><td><i>STRING</i></td><td>Directory to serve html from (".").</td><td><i></i></td></tr>
<tr><td>stats</td><td><i><a href='#statsOptions'>options</a></i></td><td>Statistical data.</td><td><i>readOnly</i></td></tr>
<tr><td>startTime</td><td><i>TIME_T</i></td><td>Time of websocket start.</td><td><i>readOnly</i></td></tr>

<tr><td>urlPrefix</td><td><i>STRKEY</i></td><td>Prefix in url to strip from path; for reverse proxy.</td><td><i></i></td></tr>
<tr><td>urlRedirect</td><td><i>STRKEY</i></td><td>Redirect when no url or / is given. Must match urlPrefix, if given.</td><td><i></i></td></tr>
<tr><td>use_ssl</td><td><i>BOOL</i></td><td>Use https (for client).</td><td><i>initOnly</i></td></tr>
<tr><td>useridPass</td><td><i>STRKEY</i></td><td>The USERID:PASSWORD to use for basic authentication.</td><td><i></i></td></tr>
<tr><td>version</td><td><i>OBJ</i></td><td>WebSocket version info.</td><td><i>readOnly</i></td></tr>
</table>








|







 







|







 







>







1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
....
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
....
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649

<a name="new WebSocketOptions"></a>
<a name="WebSocket.confOptions"></a>
<h2>Options for "new WebSocket"</h2>
<table border="1" class="optstbl table">
<tr><th>Option</th> <th>Type</th> <th>Description</th><th>Flags</th></tr>
<tr><td>address</td><td><i>STRING</i></td><td>In client-mode the address to connect to (127.0.0.1).</td><td><i></i></td></tr>
<tr><td>bufferPwr2</td><td><i>INT</i></td><td>Tune the recv/send buffer: value is a power of 2 in [0-20] (16).</td><td><i></i></td></tr>
<tr><td>client</td><td><i>BOOL</i></td><td>Run in client mode.</td><td><i>initOnly</i></td></tr>
<tr><td>clientHost</td><td><i>STRKEY</i></td><td>Override host name for client.</td><td><i></i></td></tr>
<tr><td>clientOrigin</td><td><i>STRKEY</i></td><td>Override client origin (origin).</td><td><i></i></td></tr>
<tr><td>debug</td><td><i>INT</i></td><td>Set debug level. Setting this to 512 will turn on max libwebsocket log levels.</td><td><i></i></td></tr>
<tr><td>echo</td><td><i>BOOL</i></td><td>LogInfo outputs all websock Send/Recv messages.</td><td><i></i></td></tr>
<tr><td>formParams</td><td><i>STRKEY</i></td><td>Comma seperated list of upload form param names ('text,send,file,upload').</td><td><i>readOnly</i></td></tr>
<tr><td>extArgs</td><td><i>OBJ</i></td><td>Arguments for extension handlers.</td><td><i>initOnly</i></td></tr>
................................................................................
<tr><td>local</td><td><i>BOOL</i></td><td>Limit connections to localhost addresses on the 127 network.</td><td><i></i></td></tr>
<tr><td>localhostName</td><td><i>STRKEY</i></td><td>Client name used by localhost connections ('localhost').</td><td><i></i></td></tr>
<tr><td>maxConnects</td><td><i>INT</i></td><td>In server mode, max number of client connections accepted.</td><td><i></i></td></tr>
<tr><td>maxDownload</td><td><i>INT</i></td><td>Max size of file download.</td><td><i></i></td></tr>
<tr><td>maxUpload</td><td><i>INT</i></td><td>Max size of file upload will accept.</td><td><i></i></td></tr>
<tr><td>mimeTypes</td><td><i>OBJ</i></td><td>Object providing map of file extensions to mime types (eg. {txt:'text/plain', bb:'text/bb'}).</td><td><i>initOnly</i></td></tr>
<tr><td>noConfig</td><td><i>BOOL</i></td><td>Disable use of conf() to change options after options after create.</td><td><i>initOnly</i></td></tr>
<tr><td>noCompress</td><td><i>BOOL</i></td><td>Disable per-message-deflate extension which can truncate large msgs.</td><td><i></i></td></tr>
<tr><td>noUpdate</td><td><i>BOOL</i></td><td>Disable update event-processing (eg. to exit).</td><td><i></i></td></tr>
<tr><td>noWebsock</td><td><i>BOOL</i></td><td>Serve html, but disallow websocket upgrade.</td><td><i>initOnly</i></td></tr>
<tr><td>noWarn</td><td><i>BOOL</i></td><td>Quietly ignore file related errors.</td><td><i></i></td></tr>
<tr><td>onAuth</td><td><i>FUNC</i></td><td>Function to call for http basic authentication. @function(ws:userobj, id:number, url:string, userpass:string)</td><td><i></i></td></tr>
<tr><td>onClose</td><td><i>FUNC</i></td><td>Function to call when the websocket connection closes. @function(ws:userobj|null, id:number)</td><td><i></i></td></tr>
<tr><td>onCloseLast</td><td><i>FUNC</i></td><td>Function to call when last websock connection closes. On object delete arg is null. @function(ws:userobj|null)</td><td><i></i></td></tr>
<tr><td>onFilter</td><td><i>FUNC</i></td><td>Function to call on a new connection: return false to kill connection. @function(ws:userobj, id:number, url:string, ishttp:boolean)</td><td><i></i></td></tr>
................................................................................
<tr><td>realm</td><td><i>STRKEY</i></td><td>Realm for basic auth (jsish).</td><td><i></i></td></tr>
<tr><td>recvBufMax</td><td><i>INT</i></td><td>Size limit of a websocket message.</td><td><i>initOnly</i></td></tr>
<tr><td>recvBufTimeout</td><td><i>INT</i></td><td>Timeout for recv of a websock msg.</td><td><i>initOnly</i></td></tr>
<tr><td>redirMax</td><td><i>BOOL</i></td><td>Temporarily disable redirects when see more than this in 10 minutes.</td><td><i></i></td></tr>
<tr><td>rootdir</td><td><i>STRING</i></td><td>Directory to serve html from (".").</td><td><i></i></td></tr>
<tr><td>stats</td><td><i><a href='#statsOptions'>options</a></i></td><td>Statistical data.</td><td><i>readOnly</i></td></tr>
<tr><td>startTime</td><td><i>TIME_T</i></td><td>Time of websocket start.</td><td><i>readOnly</i></td></tr>
<tr><td>templateFile</td><td><i>STRKEY</i></td><td>File name for markdeep template (template.shtml).</td><td><i></i></td></tr>
<tr><td>urlPrefix</td><td><i>STRKEY</i></td><td>Prefix in url to strip from path; for reverse proxy.</td><td><i></i></td></tr>
<tr><td>urlRedirect</td><td><i>STRKEY</i></td><td>Redirect when no url or / is given. Must match urlPrefix, if given.</td><td><i></i></td></tr>
<tr><td>use_ssl</td><td><i>BOOL</i></td><td>Use https (for client).</td><td><i>initOnly</i></td></tr>
<tr><td>useridPass</td><td><i>STRKEY</i></td><td>The USERID:PASSWORD to use for basic authentication.</td><td><i></i></td></tr>
<tr><td>version</td><td><i>OBJ</i></td><td>WebSocket version info.</td><td><i>readOnly</i></td></tr>
</table>