1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 | "use strict";
|
12 |
|
13 | var l = require('ergo-utils').log.module('ergo-api-view');
|
14 | var _ = require('ergo-utils')._;
|
15 | var fs = require('ergo-utils').fs.extend(require('fs-extra'));
|
16 | var watch_api = require('./watch');
|
17 | var Promise = require('bluebird')
|
18 | var http = require("http"),
|
19 | url = require("url"),
|
20 | path = require("path");
|
21 | var posix = path.posix;
|
22 |
|
23 |
|
24 | var _server = null;
|
25 | function _serveWeb(options, context) {
|
26 |
|
27 | options.web_root = context.getOutPath();
|
28 | options.uri_root = posix.join('/', options.uri_root || '', '/');
|
29 | options.port = options.port || 8181;
|
30 |
|
31 | if (_server && _server.listening)
|
32 | {
|
33 | l.logw("Re-initialising...")
|
34 | _server.options = options;
|
35 | return _server;
|
36 | }
|
37 |
|
38 | l.log('Serving web from: ' + options.web_root)
|
39 |
|
40 | _server = http.createServer(function(request, response) {
|
41 | var uri = url.parse(request.url).pathname;
|
42 |
|
43 |
|
44 | if (options.uri_root != '/') {
|
45 | var reluri = posix.relative(options.uri_root, uri);
|
46 | var newuri = posix.join('/', reluri);
|
47 | l.logd("uri '"+uri+"' => '"+reluri+"' => '"+newuri+"'");
|
48 |
|
49 | if (reluri.length==0 && newuri=='/' && uri.substr(-1)!='/') {
|
50 |
|
51 | l.logw("302. '"+uri+"' => '"+reluri+"' => '"+newuri+"' redirecting");
|
52 | response.writeHead(302, {"Location": "http://localhost:"+options.port+options.uri_root});
|
53 | response.end();
|
54 | return;
|
55 | }
|
56 |
|
57 | if (reluri.length>1 && reluri.substr(0,2)=='..' && uri.indexOf('favicon.ico')<0) {
|
58 | l.loge("403. '"+uri+"' => '"+reluri+"' => '"+newuri+"' becomes a path outside the document root");
|
59 | response.writeHead(403, {"Content-Type": "text/plain"});
|
60 | response.write("403 Forbidden\nWhen trying to open: '" + newuri + "'");
|
61 | response.end();
|
62 | return;
|
63 | }
|
64 |
|
65 | uri = newuri;
|
66 | }
|
67 |
|
68 | var filename = path.join(options.web_root, uri);
|
69 |
|
70 | fs.stat(filename, function(err, stats) {
|
71 | if(err) {
|
72 | l.loge("404. '"+filename+"'. Reason: " + err);
|
73 | response.writeHead(404, {"Content-Type": "text/plain"});
|
74 | response.write("404 Not Found\nWhen trying to open: '" + filename + "'");
|
75 | response.end();
|
76 | return;
|
77 | }
|
78 |
|
79 | if (stats.isDirectory())
|
80 | filename = path.join(filename,'index.html');
|
81 |
|
82 | fs.readFile(filename, "binary", function(err, file) {
|
83 | if(err) {
|
84 | l.loge("Failed to open '"+filename+"'. Reason: " + err);
|
85 | response.writeHead(500, {"Content-Type": "text/plain"});
|
86 | response.write(err + "\n");
|
87 | response.end();
|
88 | return;
|
89 | }
|
90 |
|
91 | response.writeHead(200);
|
92 | response.write(file, "binary");
|
93 | response.end();
|
94 | });
|
95 | });
|
96 | });
|
97 |
|
98 | _server.options = options;
|
99 | l.logd("Ready to start")
|
100 | _server.listen(parseInt(options.port, 10));
|
101 | l.log("Web server started at\n => http://localhost:" + options.port + options.uri_root + "\nPress Ctrl + C to shutdown...");
|
102 |
|
103 | return _server;
|
104 | }
|
105 |
|
106 |
|
107 |
|
108 |
|
109 | module.exports = function(options) {
|
110 | return Promise.try(function() {
|
111 | options = options || {};
|
112 | var context = require('./config').getContextSync(options.working_dir);
|
113 | context.mergeRuntimeOptions(options);
|
114 |
|
115 | if (_.isDefined(options['watch']))
|
116 | {
|
117 | watch_api.watch(options, context);
|
118 | l.logd("Watcher ready")
|
119 | }
|
120 | else if (_.isDefined(options['build']))
|
121 | {
|
122 | l.log("Building...")
|
123 | watch_api.build(options, context);
|
124 | }
|
125 | return _serveWeb(options, context);
|
126 | });
|
127 | } |
\ | No newline at end of file |