You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by ti...@apache.org on 2015/06/10 02:31:16 UTC
cordova-lib git commit: CB-9127 Implements cordova-serve module.
Repository: cordova-lib
Updated Branches:
refs/heads/master c3485e214 -> b5068a943
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-lib/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-lib/commit/b5068a94
Tree: http://git-wip-us.apache.org/repos/asf/cordova-lib/tree/b5068a94
Diff: http://git-wip-us.apache.org/repos/asf/cordova-lib/diff/b5068a94
Branch: refs/heads/master
Commit: b5068a94337f6a974611d2d46b8395f50762a356
Parents: c3485e2
Author: Tim Barham <ti...@microsoft.com>
Authored: Fri Jun 5 12:05:52 2015 -0700
Committer: Tim Barham <ti...@microsoft.com>
Committed: Tue Jun 9 17:27:33 2015 -0700
----------------------------------------------------------------------
cordova-serve/.jshintrc | 11 +++
cordova-serve/README.md | 142 +++++++++++++++++++++++++++++++++++++
cordova-serve/RELEASENOTES.md | 22 ++++++
cordova-serve/package.json | 38 ++++++++++
cordova-serve/serve.js | 25 +++++++
cordova-serve/src/browser.js | 100 ++++++++++++++++++++++++++
cordova-serve/src/exec.js | 46 ++++++++++++
cordova-serve/src/platform.js | 59 +++++++++++++++
cordova-serve/src/server.js | 141 ++++++++++++++++++++++++++++++++++++
cordova-serve/src/stream.js | 72 +++++++++++++++++++
cordova-serve/src/util.js | 104 +++++++++++++++++++++++++++
11 files changed, 760 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/b5068a94/cordova-serve/.jshintrc
----------------------------------------------------------------------
diff --git a/cordova-serve/.jshintrc b/cordova-serve/.jshintrc
new file mode 100644
index 0000000..6997763
--- /dev/null
+++ b/cordova-serve/.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-lib/blob/b5068a94/cordova-serve/README.md
----------------------------------------------------------------------
diff --git a/cordova-serve/README.md b/cordova-serve/README.md
new file mode 100644
index 0000000..58cc810
--- /dev/null
+++ b/cordova-serve/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-lib/blob/b5068a94/cordova-serve/RELEASENOTES.md
----------------------------------------------------------------------
diff --git a/cordova-serve/RELEASENOTES.md b/cordova-serve/RELEASENOTES.md
new file mode 100644
index 0000000..4464930
--- /dev/null
+++ b/cordova-serve/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-lib/blob/b5068a94/cordova-serve/package.json
----------------------------------------------------------------------
diff --git a/cordova-serve/package.json b/cordova-serve/package.json
new file mode 100644
index 0000000..8257d58
--- /dev/null
+++ b/cordova-serve/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-lib/blob/b5068a94/cordova-serve/serve.js
----------------------------------------------------------------------
diff --git a/cordova-serve/serve.js b/cordova-serve/serve.js
new file mode 100644
index 0000000..b477a7a
--- /dev/null
+++ b/cordova-serve/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-lib/blob/b5068a94/cordova-serve/src/browser.js
----------------------------------------------------------------------
diff --git a/cordova-serve/src/browser.js b/cordova-serve/src/browser.js
new file mode 100644
index 0000000..5b3b40e
--- /dev/null
+++ b/cordova-serve/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-lib/blob/b5068a94/cordova-serve/src/exec.js
----------------------------------------------------------------------
diff --git a/cordova-serve/src/exec.js b/cordova-serve/src/exec.js
new file mode 100644
index 0000000..d1c02a4
--- /dev/null
+++ b/cordova-serve/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-lib/blob/b5068a94/cordova-serve/src/platform.js
----------------------------------------------------------------------
diff --git a/cordova-serve/src/platform.js b/cordova-serve/src/platform.js
new file mode 100644
index 0000000..12b169b
--- /dev/null
+++ b/cordova-serve/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-lib/blob/b5068a94/cordova-serve/src/server.js
----------------------------------------------------------------------
diff --git a/cordova-serve/src/server.js b/cordova-serve/src/server.js
new file mode 100644
index 0000000..eafacc1
--- /dev/null
+++ b/cordova-serve/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-lib/blob/b5068a94/cordova-serve/src/stream.js
----------------------------------------------------------------------
diff --git a/cordova-serve/src/stream.js b/cordova-serve/src/stream.js
new file mode 100644
index 0000000..b16de62
--- /dev/null
+++ b/cordova-serve/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-lib/blob/b5068a94/cordova-serve/src/util.js
----------------------------------------------------------------------
diff --git a/cordova-serve/src/util.js b/cordova-serve/src/util.js
new file mode 100644
index 0000000..8fb076b
--- /dev/null
+++ b/cordova-serve/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