cordova-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ste...@apache.org
Subject [01/24] cordova-serve git commit: CB-9127 Implements cordova-serve module.
Date Tue, 06 Jun 2017 05:43:07 GMT
Repository: cordova-serve
Updated Branches:
  refs/heads/master [created] cfaf7d549


CB-9127 Implements cordova-serve module.

This takes code and functionality from cordova-browser and cordova-lib ('cordova serve' command)
and combines it in a single module. Most of the code is lifted directly from those two places.
Once this is checked in and we have a release, cordova-lib and cordova-browser can be updated
to use it.


Project: http://git-wip-us.apache.org/repos/asf/cordova-serve/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-serve/commit/674b245d
Tree: http://git-wip-us.apache.org/repos/asf/cordova-serve/tree/674b245d
Diff: http://git-wip-us.apache.org/repos/asf/cordova-serve/diff/674b245d

Branch: refs/heads/master
Commit: 674b245dff21c08c0bd27eb3c17c1f8059afc9eb
Parents: 
Author: Tim Barham <tim.barham@microsoft.com>
Authored: Fri Jun 5 12:05:52 2015 -0700
Committer: Tim Barham <tim.barham@microsoft.com>
Committed: Tue Jun 9 17:27:33 2015 -0700

----------------------------------------------------------------------
 .jshintrc       |  11 ++++
 README.md       | 142 +++++++++++++++++++++++++++++++++++++++++++++++++++
 RELEASENOTES.md |  22 ++++++++
 package.json    |  38 ++++++++++++++
 serve.js        |  25 +++++++++
 src/browser.js  | 100 ++++++++++++++++++++++++++++++++++++
 src/exec.js     |  46 +++++++++++++++++
 src/platform.js |  59 +++++++++++++++++++++
 src/server.js   | 141 ++++++++++++++++++++++++++++++++++++++++++++++++++
 src/stream.js   |  72 ++++++++++++++++++++++++++
 src/util.js     | 104 +++++++++++++++++++++++++++++++++++++
 11 files changed, 760 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-serve/blob/674b245d/.jshintrc
----------------------------------------------------------------------
diff --git a/.jshintrc b/.jshintrc
new file mode 100644
index 0000000..6997763
--- /dev/null
+++ b/.jshintrc
@@ -0,0 +1,11 @@
+{
+  "node": true,
+  "bitwise": true,
+  "undef": true,
+  "trailing": true,
+  "quotmark": true,
+  "indent": 4,
+  "unused": "vars",
+  "latedef": "nofunc",
+  "-W030": false
+}

http://git-wip-us.apache.org/repos/asf/cordova-serve/blob/674b245d/README.md
----------------------------------------------------------------------
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..58cc810
--- /dev/null
+++ b/README.md
@@ -0,0 +1,142 @@
+This module can be used to serve up a Cordova application in the browser. It has no command-line,
but rather is intended
+to be called using the following API:
+
+``` js
+var serve = require('cordova-serve');
+serve.launchServer(opts);
+serve.servePlatform(platform, opts);
+serve.launchBrowser(ops);
+serve.sendStream(filePath, request, response[, readStream][, noCache]);
+```
+
+## launchServer()
+
+``` js
+launchServer(opts);
+```
+
+Launches a server with the specified options. Parameters:
+
+* **opts**: Options, as described below.
+
+## servePlatform()
+
+``` js
+servePlatform(platform, opts);
+```
+
+Launches a server that serves up any Cordova platform (e.g. `browser`, `android` etc) from
the current project.
+Parameters:
+
+* **opts**: Options, as described below. Note that for `servePlatform()`, the `root` value
should be a Cordova project's
+  root folder, or any folder within it - `servePlatform()` will replace it with the platform's
`www_dir` folder. If this
+  value is not specified, the *cwd* will be used.
+
+## launchBrowser()
+
+``` js
+launchBrowser(opts);
+```
+
+Launches a browser window pointing to the specified URL. The single parameter is an options
object that supports the
+following values (both optional):
+
+* **url**: The URL to open in the browser.
+* **target**: The name of the browser to launch. Can be any of the following: `chrome`, `chromium`,
`firefox`, `ie`,
+  `opera`, `safari`. If no browser is specified, 
+
+## sendStream()
+
+``` js
+sendStream(filePath, request, response[, readStream][, noCache]);
+```
+
+The server uses this method to stream files, and it is provided as a convenience method you
can use if you are
+customizing the stream by specifying `opts.streamHandler`. Parameters:
+
+* **filePath**: The absolute path to the file to be served (which will have been passed to
your `streamHandler`).
+* **request**: The request object (which will have been passed to your `streamHandler`).
+* **response**: The response object (which will have been passed to your `streamHandler`).
+* **readStream**: (optional) A custom read stream, if required.
+* **noCache**: (optional) If true, browser caching will be disabled for this file (by setting
response header
+  Cache-Control will be set to 'no-cache')
+
+## The *opts* Options Object
+The opts object passed to `launchServer()` and `servePlatform()` supports the following values
(all optional):
+
+* **root**: The file path on the local file system that is used as the root for the server,
for default mapping of URL
+  path to local file system path.   
+* **port**: The port for the server. Note that if this port is already in use, it will be
incremented until a free port
+  is found.
+* **urlPathProcessor**: An optional method to handle special case URLs - `cordova-serve`
will by default
+  treat the URL as relative to the platform's `www_dir`, but will first call this method,
if provided, to support
+  custom handling.
+* **streamHandler**: An optional custom stream handler - `cordova-serve` will by default
stream files using
+  `sendStream()`, described above, which just streams files, but will first call this method,
if provided, to
+  support custom streaming. This method is described in more detail below.
+* **serverExtender**: This method is called as soon as the server is created, so that the
caller can do
+  additional things with the server (like attach to certain events, for example). This method
is described in more
+  detail below.
+
+## urlPathProcessor()
+Provide this method if you need to do custom processing of URL paths. That is, custom mapping
of URL path to local file path. 
+The signature of this method is as follows:
+
+``` js
+urlPathProcessor(urlPath, request, response, do302, do404)
+```
+
+Parameters:
+
+* **urlPath**: The URL path to process. It is the value of `url.parse(request.url).pathname`.
+* **request**: The server request object.
+* **response**: The server response object.
+* **do302**: A helper method to do a 302 HTTP response (redirection). It takes a single parameter
- the URL to redirect to.
+* **do404**: A helper method to do a 404 HTTP response (not found).
+
+Return value:
+
+Broadly, there are three possible actions you can take in your `urlPathProcessor` handler:
+
+1. You completely handle the request (presumably by doing some sort of response and ultimately
calling `response.end()`.
+   In this scenario, you should return `null`. 
+2. You have mapped the URL path to a custom local file path. In this scenario, you should
return `{filePath: <value>}`,
+   where `<value>` is the local file path.
+3. You have determined you don't need to do any custom processing and will let cordova-serve
to its default mapping. In
+   this scenario, you should return `{filePath: null}`.
+
+## streamHandler()
+Provide this method if you wish to perform custom stream handling. The signature of this
method is as follows:
+
+``` js
+streamHandler(filePath, request, response)
+```
+
+Parameters:
+
+* **filePath**: This is the path to the local file that will be streamed. It might be the
value you returned from
+  urlPathProcessor(), in which case it doesn't necessarily have to reference an actual file:
it might just be an
+  identifier string that your custom stream handler will recognize. If you are going to end
up calling `sendStream()`,
+  it is useful if even a fake file name has a file extension, as that is used for mime type
lookup.
+* **request**: The server request object.
+* **response**: The serve response object.
+
+Return value:
+
+Return `true` if you have handled the stream request, otherwise `false`.
+
+## serverExtender()
+
+If you provide this method, it will be called as soon as the server is created. It allows
you to attach additional
+functionality to the server, such has event handlers, web sockets etc.  The signature of
this method is as follows:
+
+``` js
+serverExtender(server, root)
+```
+
+Parameters:
+
+* **server**: A reference to the server (the result of calling `http.createServer()`).
+* **root**: The file path on the local file system that is used as the root for the server
(if it was provided), for
+  default mapping of URL path to local file system path.
+

http://git-wip-us.apache.org/repos/asf/cordova-serve/blob/674b245d/RELEASENOTES.md
----------------------------------------------------------------------
diff --git a/RELEASENOTES.md b/RELEASENOTES.md
new file mode 100644
index 0000000..4464930
--- /dev/null
+++ b/RELEASENOTES.md
@@ -0,0 +1,22 @@
+<!--
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+#  KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+-->
+# Cordova-serve Release Notes
+

http://git-wip-us.apache.org/repos/asf/cordova-serve/blob/674b245d/package.json
----------------------------------------------------------------------
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..8257d58
--- /dev/null
+++ b/package.json
@@ -0,0 +1,38 @@
+{
+  "name": "cordova-serve",
+  "version": "0.1.2-dev",
+  "description": "Apache Cordova server support for cordova-lib and cordova-browser.",
+  "main": "serve.js",
+  "repository": {
+    "type": "git",
+    "url": "git://git-wip-us.apache.org/repos/asf/cordova-lib.git"
+  },
+  "keywords": [
+    "cordova",
+    "server",
+    "apache"
+  ],
+  "author": "Apache Software Foundation",
+  "license": "Apache version 2.0",
+  "bugs": {
+    "url": "https://issues.apache.org/jira/browse/CB",
+    "email": "dev@cordova.apache.org"
+  },
+  "dependencies": {
+    "combined-stream": "^1.0.3",
+    "d8": "^0.4.4",
+    "mime": "^1.2.11",
+    "q": "^1.4.1",
+    "shelljs": "^0.4.0"
+  },
+  "devDependencies": {
+    "jshint": "^2.8.0"
+  },
+  "scripts": {
+    "jshint": "node node_modules/jshint/bin/jshint src"
+  },
+  "engines": {
+    "node": ">= 0.12.0",
+    "npm": ">= 2.5.1"
+  }
+}

http://git-wip-us.apache.org/repos/asf/cordova-serve/blob/674b245d/serve.js
----------------------------------------------------------------------
diff --git a/serve.js b/serve.js
new file mode 100644
index 0000000..b477a7a
--- /dev/null
+++ b/serve.js
@@ -0,0 +1,25 @@
+/**
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ 'License'); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ 'AS IS' BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+module.exports = {
+    sendStream: require('./src/stream'),
+    servePlatform: require('./src/platform'),
+    launchServer: require('./src/server'),
+    launchBrowser: require('./src/browser')
+};

http://git-wip-us.apache.org/repos/asf/cordova-serve/blob/674b245d/src/browser.js
----------------------------------------------------------------------
diff --git a/src/browser.js b/src/browser.js
new file mode 100644
index 0000000..5b3b40e
--- /dev/null
+++ b/src/browser.js
@@ -0,0 +1,100 @@
+/**
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+var exec = require('./exec'),
+    Q = require('q');
+
+/**
+ * Launches the specified browser with the given URL.
+ * Based on https://github.com/domenic/opener
+ * @param {{target: ?string, url: ?string, dataDir: ?string}} opts - parameters:
+ *   target - the target browser - ie, chrome, safari, opera, firefox or chromium
+ *   url - the url to open in the browser
+ *   dataDir - a data dir to provide to Chrome (can be used to force it to open in a new
window)
+ * @return {Q} Promise to launch the specified browser
+ */
+module.exports = function (opts) {
+    //target, url, dataDir
+    var target = opts.target || 'chrome';
+    var url = opts.url || '';
+
+    return getBrowser(target, opts.dataDir).then(function (browser) {
+        var args;
+        switch (process.platform) {
+            case 'darwin':
+                args = ['open'];
+                if (target == 'chrome') {
+                    // Chrome needs to be launched in a new window. Other browsers, particularly,
opera does not work with this.        
+                    args.push('-n');
+                }
+                args.push('-a', browser);
+                break;
+            case 'win32':
+                // On Windows, we really want to use the "start" command. But, the rules
regarding arguments with spaces, and 
+                // escaping them with quotes, can get really arcane. So the easiest way to
deal with this is to pass off the 
+                // responsibility to "cmd /c", which has that logic built in. 
+                // 
+                // Furthermore, if "cmd /c" double-quoted the first parameter, then "start"
will interpret it as a window title, 
+                // so we need to add a dummy empty-string window title: http://stackoverflow.com/a/154090/3191

+                args = ['cmd /c start ""', browser];
+                break;
+            case 'linux':
+                // if a browser is specified, launch it with the url as argument
+                // otherwise, use xdg-open.
+                args = [browser];
+                break;
+        }
+        args.push(url);
+        var command = args.join(' ');
+        console.log('Executing command: ' + command);
+        return exec(command);
+    });
+};
+
+function getBrowser(target, dataDir) {
+    dataDir = dataDir || 'temp_chrome_user_data_dir_for_cordova';
+
+    var chromeArgs = ' --user-data-dir=/tmp/' + dataDir;
+    var browsers = {
+        'win32': {
+            'ie': 'iexplore',
+            'chrome': 'chrome --user-data-dir=%TEMP%\\' + dataDir,
+            'safari': 'safari',
+            'opera': 'opera',
+            'firefox': 'firefox'
+        },
+        'darwin': {
+            'chrome': '"Google Chrome" --args' + chromeArgs,
+            'safari': 'safari',
+            'firefox': 'firefox',
+            'opera': 'opera'
+        },
+        'linux' : {
+            'chrome': 'google-chrome' + chromeArgs ,
+            'chromium': 'chromium-browser' + chromeArgs,
+            'firefox': 'firefox',
+            'opera': 'opera'
+        }
+    };
+    target = target.toLowerCase();
+    if (target in browsers[process.platform]) {
+        return Q(browsers[process.platform][target]);
+    }
+    return Q.reject('Browser target not supported: ' + target);
+}

http://git-wip-us.apache.org/repos/asf/cordova-serve/blob/674b245d/src/exec.js
----------------------------------------------------------------------
diff --git a/src/exec.js b/src/exec.js
new file mode 100644
index 0000000..d1c02a4
--- /dev/null
+++ b/src/exec.js
@@ -0,0 +1,46 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+var child_process = require('child_process'),
+    Q             = require('q');
+
+/**
+ * Executes the command specified.
+ * @param  {string} cmd Command to execute
+ * @param  {[string]}  opt_cwd Current working directory
+ * @return {Q} promise a promise that either resolves with the stdout, or rejects with an
error message and the stderr.
+ */
+module.exports = function (cmd, opt_cwd) {
+    var d = Q.defer();
+    try {
+        child_process.exec(cmd, {cwd: opt_cwd, maxBuffer: 1024000}, function (err, stdout,
stderr) {
+            if (err) {
+                d.reject(new Error('Error executing "' + cmd + '": ' + stderr));
+            }
+            else {
+                d.resolve(stdout);
+            }
+        });
+    } catch (e) {
+        console.error('error caught: ' + e);
+        d.reject(e);
+    }
+    return d.promise;
+};
+

http://git-wip-us.apache.org/repos/asf/cordova-serve/blob/674b245d/src/platform.js
----------------------------------------------------------------------
diff --git a/src/platform.js b/src/platform.js
new file mode 100644
index 0000000..12b169b
--- /dev/null
+++ b/src/platform.js
@@ -0,0 +1,59 @@
+/**
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+var server = require('./server'),
+    fs     = require('fs'),
+    Q      = require('q'),
+    util   = require('./util');
+
+/**
+ * Launches a server where the root points to the specified platform in a Cordova project.
+ * @param {string} platform - Cordova platform to serve.
+ * @param {{root: ?string, port: ?number, urlPathProcessor: ?function, streamHandler: ?function,
serverExtender: ?function}} opts
+ *   root - cordova project directory, or any directory within it. If not specified, cwd
is used. This will be modified to point to the platform's www_dir.
+ *   All other values are passed unaltered to launchServer().
+ * @returns {*|promise}
+ */
+module.exports = function (platform, opts) {
+    return Q().then(function () {
+        if (!platform) {
+            throw new Error('A platform must be specified');
+        }
+
+        opts = opts || {};
+        opts.root = util.getPlatformWwwRoot(findProjectRoot(opts.root), platform);
+        if (!fs.existsSync(opts.root)) {
+            throw new Error('Project does not include the specified platform: ' + platform);
+        }
+
+        return server(opts);
+    });
+};
+
+function findProjectRoot(path) {
+    var projectRoot = util.cordovaProjectRoot(path);
+    if (!projectRoot) {
+        if (!path) {
+            throw new Error('Current directory does not appear to be in a Cordova project.');
+        } else {
+            throw new Error('Directory "' + path + '" does not appear to be in a Cordova
project.');
+        }
+    }
+    return projectRoot;
+}

http://git-wip-us.apache.org/repos/asf/cordova-serve/blob/674b245d/src/server.js
----------------------------------------------------------------------
diff --git a/src/server.js b/src/server.js
new file mode 100644
index 0000000..eafacc1
--- /dev/null
+++ b/src/server.js
@@ -0,0 +1,141 @@
+/**
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+var fs     = require('fs'),
+    http   = require('http'),
+    url    = require('url'),
+    path   = require('path'),
+    Q      = require('q'),
+    stream = require('./stream');
+
+/**
+ * @desc Launches a server with the specified options and optional custom handlers.
+ * @param {{root: ?string, port: ?number, urlPathHandler: ?function, streamHandler: ?function,
serverExtender: ?function}} opts
+ *     urlPathHandler(urlPath, request, response, do302, do404, serveFile) - an optional
method to provide custom handling for
+ *         processing URLs and serving up the resulting data. Can serve up the data itself
using response.write(), or determine
+ *         a custom local file path and call serveFile to serve it up, or do no processing
and call serveFile with no params to
+ *         treat urlPath as relative to the root.
+ *     streamHandler(filePath, request, response) - an optional custom stream handler, to
stream whatever you want. If not
+ *         provided, the file referenced by filePath will be streamed. Return true if the
file is handled.
+ *     serverExtender(server, root) - if provided, is called as soon as server is created
so caller can attached to events etc.
+ * @returns {*|promise}
+ */
+module.exports = function (opts) {
+    var deferred = Q.defer();
+
+    opts = opts || {};
+    var root = opts.root;
+    var port = opts.port || 8000;
+
+    var server = http.createServer(function (request, response) {
+        function do404() {
+            console.log('404 ' + request.url);
+            response.writeHead(404, {'Content-Type': 'text/plain'});
+            response.write('404 Not Found\n');
+            response.end();
+        }
+
+        function do302(where) {
+            console.log('302 ' + request.url);
+            response.setHeader('Location', where);
+            response.writeHead(302, {'Content-Type': 'text/plain'});
+            response.end();
+        }
+
+        function do304() {
+            console.log('304 ' + request.url);
+            response.writeHead(304, {'Content-Type': 'text/plain'});
+            response.end();
+        }
+
+        function isFileChanged(path) {
+            var mtime = fs.statSync(path).mtime,
+                itime = request.headers['if-modified-since'];
+            return !itime || new Date(mtime) > new Date(itime);
+        }
+
+        var urlPath = url.parse(request.url).pathname;
+
+        if (opts.urlPathHandler) {
+            opts.urlPathHandler(urlPath, request, response, do302, do404, serveFile);
+        } else {
+            serveFile();
+        }
+
+        function serveFile(filePath) {
+            if (!filePath) {
+                if (!root) {
+                    throw new Error('No server root directory HAS BEEN specified!');
+                }
+                filePath = path.join(root, urlPath);
+            }
+
+            fs.exists(filePath, function (exists) {
+                if (!exists) {
+                    do404();
+                    return;
+                }
+                if (fs.statSync(filePath).isDirectory()) {
+                    var index = path.join(filePath, 'index.html');
+                    if (fs.existsSync(index)) {
+                        filePath = index;
+                    }
+                }
+                if (fs.statSync(filePath).isDirectory()) {
+                    if (!/\/$/.test(urlPath)) {
+                        do302(request.url + '/');
+                        return;
+                    }
+                    console.log('200 ' + request.url);
+                    response.writeHead(200, {'Content-Type': 'text/html'});
+                    response.write('<html><head><title>Directory listing
of ' + urlPath + '</title></head>');
+                    response.write('<h3>Items in this directory</h3>');
+                    response.write('<ul>');
+                    fs.readdirSync(filePath).forEach(function (file) {
+                        response.write('<li><a href="' + file + '">' + file +
'</a></li>\n');
+                    });
+
+                    response.write('</ul>');
+                    response.end();
+                } else if (!isFileChanged(filePath)) {
+                    do304();
+                } else {
+                    var streamHandler = opts.streamHandler || stream;
+                    streamHandler(filePath, request, response);
+                }
+            });
+        }
+    }).on('listening', function () {
+        console.log('Static file server running on port ' + port + ' (i.e. http://localhost:'
+ port + ')\nCTRL + C to shut down');
+        deferred.resolve({server: server, port: port});
+    }).on('error', function (e) {
+        if (e && e.toString().indexOf('EADDRINUSE') !== -1) {
+            port++;
+            server.listen(port);
+        } else {
+            deferred.reject(e);
+        }
+    }).listen(port);
+
+    if (opts.serverExtender) {
+        opts.serverExtender(server, root);
+    }
+
+    return deferred.promise;
+};

http://git-wip-us.apache.org/repos/asf/cordova-serve/blob/674b245d/src/stream.js
----------------------------------------------------------------------
diff --git a/src/stream.js b/src/stream.js
new file mode 100644
index 0000000..b16de62
--- /dev/null
+++ b/src/stream.js
@@ -0,0 +1,72 @@
+/**
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+var fs = require('fs'),
+    mime = require('mime'),
+    zlib = require('zlib');
+
+// d8 is a date parsing and formatting micro-framework
+// Used only for RFC 2822 formatting
+require('d8');
+require('d8/locale/en-US');
+
+/**
+ * Streams a file
+ * @param {string} filePath - the file to stream (if a readStream is provided, this can be
a dummy file name to provide mime type)
+ * @param {http.IncomingMessage} request - request object provided by request event.
+ * @param {http.ServerResponse} response - response object provided by request event.
+ * @param {ReadStream} [readStream] - an optional read stream (for custom handling).
+ * @param {boolean} [noCache] - if true, response header Cache-Control will be set to 'no-cache'.
+ * @returns {ReadStream} - the provided ReadStream, otherwise one created for the specified
file.
+ */
+module.exports = function (filePath, request, response, readStream, noCache) {
+    if ((typeof readStream) === 'boolean') {
+        noCache = readStream;
+        readStream = null;
+    }
+
+    var mimeType = mime.lookup(filePath);
+    var respHeaders = {
+        'Content-Type': mimeType
+    };
+
+    if (!readStream) {
+        readStream = fs.createReadStream(filePath);
+    }
+
+    var acceptEncoding = request.headers['accept-encoding'] || '';
+    if (acceptEncoding.match(/\bgzip\b/)) {
+        console.log('gzip');
+        respHeaders['content-encoding'] = 'gzip';
+        readStream = readStream.pipe(zlib.createGzip());
+    } else if (acceptEncoding.match(/\bdeflate\b/)) {
+        console.log('deflate');
+        respHeaders['content-encoding'] = 'deflate';
+        readStream = readStream.pipe(zlib.createDeflate());
+    }
+
+    respHeaders['Last-Modified'] = new Date(fs.statSync(filePath).mtime).format('r');
+    if (noCache) {
+        respHeaders['Cache-Control'] = 'no-cache';
+    }
+    console.log('200 ' + request.url + ' (' + filePath + ')');
+    response.writeHead(200, respHeaders);
+    readStream.pipe(response);
+    return readStream;
+};

http://git-wip-us.apache.org/repos/asf/cordova-serve/blob/674b245d/src/util.js
----------------------------------------------------------------------
diff --git a/src/util.js b/src/util.js
new file mode 100644
index 0000000..8fb076b
--- /dev/null
+++ b/src/util.js
@@ -0,0 +1,104 @@
+/**
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+var fs   = require('fs'),
+    path = require('path');
+
+// Some helpful utility stuff copied from cordova-lib. This is a bit nicer than taking a
dependency on cordova-lib just
+// to get this minimal stuff. Hopefully we won't need the platform stuff (finding platform
www_dir) once it is moved
+// into the actual platform.
+
+var platforms = {
+    amazon_fireos: {www_dir: 'assets/www'},
+    android: {www_dir: 'assets/www'},
+    blackberry10: {www_dir: 'www'},
+    browser: {www_dir: 'www'},
+    firefoxos: {www_dir: 'www'},
+    ios: {www_dir: 'www'},
+    ubuntu: {www_dir: 'www'},
+    windows: {www_dir: 'www'},
+    wp8: {www_dir: 'www'}
+};
+
+/**
+ * @desc Look for a Cordova project's root directory, starting at the specified directory
(or CWD if none specified).
+ * @param {string=} dir - the directory to start from (we check this directory then work
up), or CWD if none specified.
+ * @returns {string} - the Cordova project's root directory, or null if not found.
+ */
+function cordovaProjectRoot(dir) {
+    if (!dir) {
+        // Prefer PWD over cwd so that symlinked dirs within your PWD work correctly.
+        var pwd = process.env.PWD;
+        var cwd = process.cwd();
+        if (pwd && pwd != cwd && pwd != 'undefined') {
+            return cordovaProjectRoot(pwd) || cordovaProjectRoot(cwd);
+        }
+        return cordovaProjectRoot(cwd);
+    }
+
+    var bestReturnValueSoFar = null;
+    for (var i = 0; i < 1000; ++i) {
+        var result = isRootDir(dir);
+        if (result === 2) {
+            return dir;
+        }
+        if (result === 1) {
+            bestReturnValueSoFar = dir;
+        }
+        var parentDir = path.normalize(path.join(dir, '..'));
+        // Detect fs root.
+        if (parentDir == dir) {
+            return bestReturnValueSoFar;
+        }
+        dir = parentDir;
+    }
+    return null;
+}
+
+function getPlatformWwwRoot(cordovaProjectRoot, platformName) {
+    var platform = platforms[platformName];
+    if (!platform) {
+        throw new Error ('Unrecognized platform: ' + platformName);
+    }
+    return path.join(cordovaProjectRoot, 'platforms', platformName, platform.www_dir);
+}
+
+function isRootDir(dir) {
+    if (fs.existsSync(path.join(dir, 'www'))) {
+        if (fs.existsSync(path.join(dir, 'config.xml'))) {
+            // For sure is.
+            if (fs.existsSync(path.join(dir, 'platforms'))) {
+                return 2;
+            } else {
+                return 1;
+            }
+        }
+        // Might be (or may be under platforms/).
+        if (fs.existsSync(path.join(dir, 'www', 'config.xml'))) {
+            return 1;
+        }
+    }
+    return 0;
+}
+
+module.exports = {
+    cordovaProjectRoot: cordovaProjectRoot,
+    getPlatformWwwRoot: getPlatformWwwRoot,
+    platforms: platforms
+};


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@cordova.apache.org
For additional commands, e-mail: commits-help@cordova.apache.org


Mime
View raw message