From f18b58763b3005e2e82bd46f65bec83341924e90 Mon Sep 17 00:00:00 2001 From: Nick Martin Date: Wed, 15 Aug 2012 21:51:29 -0700 Subject: [PATCH 1/7] Initial absolute-url package. --- app/lib/bundler.js | 1 + app/meteor/run.js | 33 ++++++++++++++----------- app/server/server.js | 28 ++++++++++++++------- packages/absolute-url/package.js | 16 ++++++++++++ packages/absolute-url/url_common.js | 28 +++++++++++++++++++++ packages/absolute-url/url_server.js | 2 ++ packages/absolute-url/url_tests.js | 29 ++++++++++++++++++++++ packages/livedata/server_convenience.js | 4 +++ 8 files changed, 117 insertions(+), 24 deletions(-) create mode 100644 packages/absolute-url/package.js create mode 100644 packages/absolute-url/url_common.js create mode 100644 packages/absolute-url/url_server.js create mode 100644 packages/absolute-url/url_tests.js diff --git a/app/lib/bundler.js b/app/lib/bundler.js index b4d832cbc2..c622c8b96b 100644 --- a/app/lib/bundler.js +++ b/app/lib/bundler.js @@ -577,6 +577,7 @@ _.extend(Bundle.prototype, { "\n" + " $ npm install fibers\n" + " $ export MONGO_URL='mongodb://user:password@host:port/databasename'\n" + +" $ export ROOT_URL='http://example.com'\n" + " $ node main.js\n" + "\n" + "Use the PORT environment variable to set the port where the\n" + diff --git a/app/meteor/run.js b/app/meteor/run.js index 26c21bafd5..b8bef237d0 100644 --- a/app/meteor/run.js +++ b/app/meteor/run.js @@ -168,14 +168,15 @@ var log_to_clients = function (msg) { ////////// Launch server process ////////// -var start_server = function (bundle_path, port, mongo_url, +var start_server = function (bundle_path, outer_port, inner_port, mongo_url, on_exit_callback, on_listen_callback) { // environment var env = {}; for (var k in process.env) env[k] = process.env[k]; - env.PORT = port; + env.PORT = inner_port; env.MONGO_URL = mongo_url; + env.ROOT_URL = 'http://localhost:' + outer_port; var proc = spawn(process.execPath, [path.join(bundle_path, 'main.js'), '--keepalive'], @@ -544,19 +545,21 @@ exports.run = function (app_dir, bundle_opts, port) { start_watching(); Status.running = true; - server_handle = start_server(bundle_path, inner_port, mongo_url, function () { - // on server exit - Status.running = false; - Status.listening = false; - Status.soft_crashed(); - if (!Status.crashing) - restart_server(); - }, function () { - // on listen - Status.listening = true; - _.each(request_queue, function (f) { f(); }); - request_queue = []; - }); + server_handle = start_server( + bundle_path, outer_port, inner_port, mongo_url, + function () { + // on server exit + Status.running = false; + Status.listening = false; + Status.soft_crashed(); + if (!Status.crashing) + restart_server(); + }, function () { + // on listen + Status.listening = true; + _.each(request_queue, function (f) { f(); }); + request_queue = []; + }); // launch test bundle and server if needed. diff --git a/app/server/server.js b/app/server/server.js index 8738ccb9d9..56a965d41d 100644 --- a/app/server/server.js +++ b/app/server/server.js @@ -50,9 +50,16 @@ var supported_browser = function (user_agent) { // add any runtime configuration options needed to app_html var runtime_config = function (app_html) { var insert = ''; - if (process.env.DEFAULT_DDP_ENDPOINT) - insert += "__meteor_runtime_config__.DEFAULT_DDP_ENDPOINT = '" + - process.env.DEFAULT_DDP_ENDPOINT + "';"; + if (typeof __meteor_runtime_config__ === 'undefined') + return app_html; + + _.each(__meteor_runtime_config__, function (value, key) { + insert += "__meteor_runtime_config__." + + key + + " = '" + + value.replace(/'/g, '\\\'').replace(/\n/g, '\\n') + + "';\n"; + }); app_html = app_html.replace("// ##RUNTIME_CONFIG##", insert); @@ -75,12 +82,6 @@ var run = function () { app.use(gzippo.staticGzip(static_cacheable_path, {clientMaxAge: 1000 * 60 * 60 * 24 * 365})); app.use(gzippo.staticGzip(path.join(bundle_dir, 'static'))); - var app_html = fs.readFileSync(path.join(bundle_dir, 'app.html'), 'utf8'); - var unsupported_html = fs.readFileSync(path.join(bundle_dir, 'unsupported.html')); - - app_html = runtime_config(app_html); - - // read bundle config file var info_raw = fs.readFileSync(path.join(bundle_dir, 'app.json'), 'utf8'); @@ -88,6 +89,7 @@ var run = function () { // start up app __meteor_bootstrap__ = {require: require, startup_hooks: [], app: app}; + __meteor_runtime_config__ = {}; Fiber(function () { // (put in a fiber to let Meteor.db operations happen during loading) @@ -112,6 +114,14 @@ var run = function () { require('vm').runInThisContext(code, filename, true); }); + + // Actually serve HTML. This happens after user code, so that + // packages can insert connect middlewares. + var app_html = fs.readFileSync(path.join(bundle_dir, 'app.html'), 'utf8'); + var unsupported_html = fs.readFileSync(path.join(bundle_dir, 'unsupported.html')); + + app_html = runtime_config(app_html); + app.use(function (req, res) { // prevent favicon.ico and robots.txt from returning app_html if (_.indexOf(['/favicon.ico', '/robots.txt'], req.url) !== -1) { diff --git a/packages/absolute-url/package.js b/packages/absolute-url/package.js new file mode 100644 index 0000000000..189fc9e0fb --- /dev/null +++ b/packages/absolute-url/package.js @@ -0,0 +1,16 @@ +Package.describe({ + summary: "Generate absolute URLs to the application", + internal: true +}); + +Package.on_use(function (api) { + api.add_files('url_server.js', 'server'); + api.add_files('url_common.js', ['client', 'server']); +}); + +Package.on_test(function (api) { + api.use('absolute-url', ['client', 'server']); + api.use('tinytest'); + + api.add_files('url_tests.js', ['client', 'server']); +}); diff --git a/packages/absolute-url/url_common.js b/packages/absolute-url/url_common.js new file mode 100644 index 0000000000..483f265f84 --- /dev/null +++ b/packages/absolute-url/url_common.js @@ -0,0 +1,28 @@ +(function () { + + Meteor.absoluteUrl = function (path, options) { + // merge options with defaults + options = _.extend({}, Meteor.absoluteUrl.defaultOptions, options || {}); + + var url = options.rootUrl; + if (!url) + throw new Error("Must pass options.rootUrl or set ROOT_URL in the server environment"); + + if (!/\/$/.test(url)) // !endsWith(url, '/') + url += '/'; + + if (path) + url += path; + + if (options.secure && /^http:/.test(url)) // startsWith(url, 'http:') + url = url.replace(/^http:/, 'https:'); + + return url; + }; + + // allow later packages to override default options + Meteor.absoluteUrl.defaultOptions = { }; + if (__meteor_runtime_config__ && __meteor_runtime_config__.ROOT_URL) + Meteor.absoluteUrl.defaultOptions.rootUrl = __meteor_runtime_config__.ROOT_URL; + +})(); diff --git a/packages/absolute-url/url_server.js b/packages/absolute-url/url_server.js new file mode 100644 index 0000000000..1c672cf044 --- /dev/null +++ b/packages/absolute-url/url_server.js @@ -0,0 +1,2 @@ +if (process.env.ROOT_URL) + __meteor_runtime_config__.ROOT_URL = process.env.ROOT_URL; diff --git a/packages/absolute-url/url_tests.js b/packages/absolute-url/url_tests.js new file mode 100644 index 0000000000..6aebfd0bf1 --- /dev/null +++ b/packages/absolute-url/url_tests.js @@ -0,0 +1,29 @@ +Tinytest.add("absolute-url - basics", function(test) { + + test.equal(Meteor.absoluteUrl(undefined, {rootUrl: 'http://asdf.com'}), + 'http://asdf.com/'); + test.equal(Meteor.absoluteUrl(undefined, {rootUrl: 'http://asdf.com/'}), + 'http://asdf.com/'); + + test.equal(Meteor.absoluteUrl('foo', {rootUrl: 'http://asdf.com/'}), + 'http://asdf.com/foo'); + test.equal(Meteor.absoluteUrl('/foo', {rootUrl: 'http://asdf.com'}), + 'http://asdf.com//foo'); + + test.equal(Meteor.absoluteUrl('foo', {rootUrl: 'http://asdf.com', + secure: true}), + 'https://asdf.com/foo'); + test.equal(Meteor.absoluteUrl('foo', {rootUrl: 'https://asdf.com', + secure: true}), + 'https://asdf.com/foo'); + test.equal(Meteor.absoluteUrl('foo', {rootUrl: 'https://asdf.com', + secure: false}), + 'https://asdf.com/foo'); +}); + + +Tinytest.add("absolute-url - environment", function(test) { + // make sure our test runner set the runtime configuration, and this + // propagates to the client. + test.isTrue(/^http/.test(__meteor_runtime_config__.ROOT_URL)); +}); diff --git a/packages/livedata/server_convenience.js b/packages/livedata/server_convenience.js index a3470b39dc..547181ab66 100644 --- a/packages/livedata/server_convenience.js +++ b/packages/livedata/server_convenience.js @@ -1,3 +1,7 @@ +if (process.env.DEFAULT_DDP_ENDPOINT) + __meteor_runtime_config__.DEFAULT_DDP_ENDPOINT = process.env.DEFAULT_DDP_ENDPOINT; + + _.extend(Meteor, { default_server: new Meteor._LivedataServer, From e9956ee8e8cb7e7957cc6061ea9fdca7380d478f Mon Sep 17 00:00:00 2001 From: Nick Martin Date: Wed, 15 Aug 2012 22:30:15 -0700 Subject: [PATCH 2/7] Integrate force-ssl and absolute-url. Now when you add force-ssl, secure defaults to true in absolute-url. --- packages/absolute-url/url_common.js | 7 ++++++- packages/absolute-url/url_tests.js | 15 +++++++++++++++ packages/force-ssl/force_ssl_common.js | 1 + packages/force-ssl/package.js | 7 +++++++ 4 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 packages/force-ssl/force_ssl_common.js diff --git a/packages/absolute-url/url_common.js b/packages/absolute-url/url_common.js index 483f265f84..d1b123aa92 100644 --- a/packages/absolute-url/url_common.js +++ b/packages/absolute-url/url_common.js @@ -14,7 +14,12 @@ if (path) url += path; - if (options.secure && /^http:/.test(url)) // startsWith(url, 'http:') + // turn http to http if secure option is set, and we're not talking + // to localhost. + if (options.secure && + /^http:/.test(url) && // startsWith('http:') + !/http:\/\/localhost[:\/]/.test(url) && // doesn't match localhost + !/http:\/\/127\.0\.0\.1[:\/]/.test(url)) // or 127.0.0.1 url = url.replace(/^http:/, 'https:'); return url; diff --git a/packages/absolute-url/url_tests.js b/packages/absolute-url/url_tests.js index 6aebfd0bf1..e2e595180d 100644 --- a/packages/absolute-url/url_tests.js +++ b/packages/absolute-url/url_tests.js @@ -19,6 +19,21 @@ Tinytest.add("absolute-url - basics", function(test) { test.equal(Meteor.absoluteUrl('foo', {rootUrl: 'https://asdf.com', secure: false}), 'https://asdf.com/foo'); + + test.equal(Meteor.absoluteUrl('foo', {rootUrl: 'http://localhost', + secure: true}), + 'http://localhost/foo'); + test.equal(Meteor.absoluteUrl('foo', {rootUrl: 'http://localhost:3000', + secure: true}), + 'http://localhost:3000/foo'); + test.equal(Meteor.absoluteUrl('foo', {rootUrl: 'https://localhost:3000', + secure: true}), + 'https://localhost:3000/foo'); + test.equal(Meteor.absoluteUrl('foo', {rootUrl: 'http://127.0.0.1:3000', + secure: true}), + 'http://127.0.0.1:3000/foo'); + + }); diff --git a/packages/force-ssl/force_ssl_common.js b/packages/force-ssl/force_ssl_common.js new file mode 100644 index 0000000000..00b121f8b4 --- /dev/null +++ b/packages/force-ssl/force_ssl_common.js @@ -0,0 +1 @@ +_.extend(Meteor.absoluteUrl.defaultOptions, {secure: true}); diff --git a/packages/force-ssl/package.js b/packages/force-ssl/package.js index 451e1795f9..90b5037578 100644 --- a/packages/force-ssl/package.js +++ b/packages/force-ssl/package.js @@ -7,6 +7,13 @@ Package.on_use(function (api) { // make sure we come after livedata, so we load after the sockjs // server has been instantiated. api.use('livedata', 'server'); + + // we don't really depend on absolute-url, but we do modify its + // behavior. If there were a way to say "if the other package is + // loaded, make sure we come after it", we should do that here. + api.use('absolute-url', ['client', 'server']); + + api.add_files('force_ssl_common.js', ['client', 'server']); api.add_files('force_ssl_server.js', 'server'); // Another thing we could do is add a force_ssl_client.js file that From b3ada2cf4f25f26964fbca0e47466f603b24c447 Mon Sep 17 00:00:00 2001 From: Nick Martin Date: Wed, 15 Aug 2012 23:26:39 -0700 Subject: [PATCH 3/7] Document absolute-url package. --- docs/client/docs.js | 1 + docs/client/packages.html | 1 + docs/client/packages/absolute-url.html | 15 +++++++++++++++ docs/client/packages/absolute-url.js | 24 ++++++++++++++++++++++++ packages/absolute-url/package.js | 3 +-- 5 files changed, 42 insertions(+), 2 deletions(-) create mode 100644 docs/client/packages/absolute-url.html create mode 100644 docs/client/packages/absolute-url.js diff --git a/docs/client/docs.js b/docs/client/docs.js index c79d83b199..c7dc28497e 100644 --- a/docs/client/docs.js +++ b/docs/client/docs.js @@ -186,6 +186,7 @@ var toc = [ ], "Packages", [ [ + "absolute-url", "amplify", "backbone", "bootstrap", diff --git a/docs/client/packages.html b/docs/client/packages.html index 1c12157077..51eddc0373 100644 --- a/docs/client/packages.html +++ b/docs/client/packages.html @@ -16,6 +16,7 @@ and removed with: $ meteor remove +{{> pkg_absolute_url}} {{> pkg_amplify}} {{> pkg_backbone}} {{> pkg_bootstrap}} diff --git a/docs/client/packages/absolute-url.html b/docs/client/packages/absolute-url.html new file mode 100644 index 0000000000..19a0401e63 --- /dev/null +++ b/docs/client/packages/absolute-url.html @@ -0,0 +1,15 @@ + diff --git a/docs/client/packages/absolute-url.js b/docs/client/packages/absolute-url.js new file mode 100644 index 0000000000..4c81df2da4 --- /dev/null +++ b/docs/client/packages/absolute-url.js @@ -0,0 +1,24 @@ +Template.pkg_absolute_url.absoluteUrl = { + id: "meteor_absoluteUrl", + name: "Meteor.absoluteUrl(path, [options])", + locus: "Anywhere", + descr: ["Generate an absolute URL to the application."], + args: [ + {name: "path", + type: "String", + descr: 'A path to append to the root URL. Do not include a leading "`/`".' + } + ], + options: [ + {name: "secure", + type: "Boolean", + descr: "Create an HTTPS URL." + }, + {name: "rootUrl", + type: "String", + descr: "Override the default ROOT_URL from the server environment. For example: \"`http://foo.example.com`\"" + } + ] + +}; + diff --git a/packages/absolute-url/package.js b/packages/absolute-url/package.js index 189fc9e0fb..bc6331b4a7 100644 --- a/packages/absolute-url/package.js +++ b/packages/absolute-url/package.js @@ -1,6 +1,5 @@ Package.describe({ - summary: "Generate absolute URLs to the application", - internal: true + summary: "Generate absolute URLs to the application" }); Package.on_use(function (api) { From 4e68bdd0e9b44ae2ecb1b60f0294a079f1bb60b1 Mon Sep 17 00:00:00 2001 From: David Glasser Date: Thu, 16 Aug 2012 19:44:31 -0700 Subject: [PATCH 4/7] dev_bundle 0.1.7: packages needed for email branch --- admin/generate-dev-bundle.sh | 5 ++++- meteor | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/admin/generate-dev-bundle.sh b/admin/generate-dev-bundle.sh index 78663532f2..34ec6feb03 100755 --- a/admin/generate-dev-bundle.sh +++ b/admin/generate-dev-bundle.sh @@ -2,7 +2,7 @@ set -e -BUNDLE_VERSION=0.1.6 +BUNDLE_VERSION=0.1.7 UNAME=$(uname) ARCH=$(uname -m) @@ -143,6 +143,9 @@ npm install fibers@0.6.5 npm install useragent@1.0.6 npm install request@2.9.202 npm install http-proxy@0.8.0 +npm install simplesmtp@0.1.19 +npm install mailcomposer@0.1.15 +npm install stream-buffers@0.2.3 # unused, but kept in bundle for compatibility for a while. npm install connect-gzip@0.1.5 diff --git a/meteor b/meteor index 6d12ecc158..4381110127 100755 --- a/meteor +++ b/meteor @@ -1,6 +1,6 @@ #!/bin/bash -BUNDLE_VERSION=0.1.6 +BUNDLE_VERSION=0.1.7 # OS Check. Put here because here is where we download the precompiled # bundles that are arch specific. From 1df6b74ada92a7c4cfa0f398486893d2b07d7148 Mon Sep 17 00:00:00 2001 From: Nick Martin Date: Thu, 16 Aug 2012 21:16:31 -0700 Subject: [PATCH 5/7] Feedback from review. --- app/lib/app.html.in | 1 - app/server/server.js | 16 ++++++---------- docs/client/packages/absolute-url.js | 4 ++-- packages/absolute-url/package.js | 4 +++- packages/absolute-url/url_common.js | 9 +++++++-- packages/absolute-url/url_tests.js | 18 +++++++++--------- 6 files changed, 27 insertions(+), 25 deletions(-) diff --git a/app/lib/app.html.in b/app/lib/app.html.in index 0149601a24..3694303c2c 100644 --- a/app/lib/app.html.in +++ b/app/lib/app.html.in @@ -5,7 +5,6 @@ {{/each}} diff --git a/app/server/server.js b/app/server/server.js index 56a965d41d..df50c844da 100644 --- a/app/server/server.js +++ b/app/server/server.js @@ -53,15 +53,10 @@ var runtime_config = function (app_html) { if (typeof __meteor_runtime_config__ === 'undefined') return app_html; - _.each(__meteor_runtime_config__, function (value, key) { - insert += "__meteor_runtime_config__." - + key - + " = '" - + value.replace(/'/g, '\\\'').replace(/\n/g, '\\n') - + "';\n"; - }); - - app_html = app_html.replace("// ##RUNTIME_CONFIG##", insert); + app_html = app_html.replace( + "// ##RUNTIME_CONFIG##", + "__meteor_runtime_config__ = " + + JSON.stringify(__meteor_runtime_config__) + ";"); return app_html; }; @@ -116,7 +111,8 @@ var run = function () { // Actually serve HTML. This happens after user code, so that - // packages can insert connect middlewares. + // packages can insert connect middlewares and update + // __meteor_runtime_config__ var app_html = fs.readFileSync(path.join(bundle_dir, 'app.html'), 'utf8'); var unsupported_html = fs.readFileSync(path.join(bundle_dir, 'unsupported.html')); diff --git a/docs/client/packages/absolute-url.js b/docs/client/packages/absolute-url.js index 4c81df2da4..7a4ba1d036 100644 --- a/docs/client/packages/absolute-url.js +++ b/docs/client/packages/absolute-url.js @@ -1,8 +1,8 @@ Template.pkg_absolute_url.absoluteUrl = { id: "meteor_absoluteUrl", - name: "Meteor.absoluteUrl(path, [options])", + name: "Meteor.absoluteUrl([path], [options])", locus: "Anywhere", - descr: ["Generate an absolute URL to the application."], + descr: ["Generate an absolute URL pointing to the application."], args: [ {name: "path", type: "String", diff --git a/packages/absolute-url/package.js b/packages/absolute-url/package.js index bc6331b4a7..796cba69b8 100644 --- a/packages/absolute-url/package.js +++ b/packages/absolute-url/package.js @@ -1,8 +1,10 @@ Package.describe({ - summary: "Generate absolute URLs to the application" + summary: "Generate absolute URLs pointing to the application" }); Package.on_use(function (api) { + // note server before common. usually it is the other way around, but + // in this case server must load first. api.add_files('url_server.js', 'server'); api.add_files('url_common.js', ['client', 'server']); }); diff --git a/packages/absolute-url/url_common.js b/packages/absolute-url/url_common.js index d1b123aa92..4c65f71170 100644 --- a/packages/absolute-url/url_common.js +++ b/packages/absolute-url/url_common.js @@ -1,6 +1,11 @@ (function () { Meteor.absoluteUrl = function (path, options) { + // path is optional + if (!options && typeof path === 'object') { + options = path; + path = undefined; + } // merge options with defaults options = _.extend({}, Meteor.absoluteUrl.defaultOptions, options || {}); @@ -8,7 +13,7 @@ if (!url) throw new Error("Must pass options.rootUrl or set ROOT_URL in the server environment"); - if (!/\/$/.test(url)) // !endsWith(url, '/') + if (!/\/$/.test(url)) // url ends with '/' url += '/'; if (path) @@ -17,7 +22,7 @@ // turn http to http if secure option is set, and we're not talking // to localhost. if (options.secure && - /^http:/.test(url) && // startsWith('http:') + /^http:/.test(url) && // url starts with 'http:' !/http:\/\/localhost[:\/]/.test(url) && // doesn't match localhost !/http:\/\/127\.0\.0\.1[:\/]/.test(url)) // or 127.0.0.1 url = url.replace(/^http:/, 'https:'); diff --git a/packages/absolute-url/url_tests.js b/packages/absolute-url/url_tests.js index e2e595180d..97ab03e40b 100644 --- a/packages/absolute-url/url_tests.js +++ b/packages/absolute-url/url_tests.js @@ -1,5 +1,7 @@ Tinytest.add("absolute-url - basics", function(test) { + test.equal(Meteor.absoluteUrl({rootUrl: 'http://asdf.com'}), + 'http://asdf.com/'); test.equal(Meteor.absoluteUrl(undefined, {rootUrl: 'http://asdf.com'}), 'http://asdf.com/'); test.equal(Meteor.absoluteUrl(undefined, {rootUrl: 'http://asdf.com/'}), @@ -11,29 +13,27 @@ Tinytest.add("absolute-url - basics", function(test) { 'http://asdf.com//foo'); test.equal(Meteor.absoluteUrl('foo', {rootUrl: 'http://asdf.com', - secure: true}), + secure: true}), 'https://asdf.com/foo'); test.equal(Meteor.absoluteUrl('foo', {rootUrl: 'https://asdf.com', - secure: true}), + secure: true}), 'https://asdf.com/foo'); test.equal(Meteor.absoluteUrl('foo', {rootUrl: 'https://asdf.com', - secure: false}), + secure: false}), 'https://asdf.com/foo'); test.equal(Meteor.absoluteUrl('foo', {rootUrl: 'http://localhost', - secure: true}), + secure: true}), 'http://localhost/foo'); test.equal(Meteor.absoluteUrl('foo', {rootUrl: 'http://localhost:3000', - secure: true}), + secure: true}), 'http://localhost:3000/foo'); test.equal(Meteor.absoluteUrl('foo', {rootUrl: 'https://localhost:3000', - secure: true}), + secure: true}), 'https://localhost:3000/foo'); test.equal(Meteor.absoluteUrl('foo', {rootUrl: 'http://127.0.0.1:3000', - secure: true}), + secure: true}), 'http://127.0.0.1:3000/foo'); - - }); From f7afc0b5f318b69bd6484d120f14a00b44dbd8d8 Mon Sep 17 00:00:00 2001 From: Nick Martin Date: Thu, 16 Aug 2012 21:52:14 -0700 Subject: [PATCH 6/7] Test hash fragments also. --- packages/absolute-url/url_tests.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/absolute-url/url_tests.js b/packages/absolute-url/url_tests.js index 97ab03e40b..6548dfc7ab 100644 --- a/packages/absolute-url/url_tests.js +++ b/packages/absolute-url/url_tests.js @@ -11,6 +11,8 @@ Tinytest.add("absolute-url - basics", function(test) { 'http://asdf.com/foo'); test.equal(Meteor.absoluteUrl('/foo', {rootUrl: 'http://asdf.com'}), 'http://asdf.com//foo'); + test.equal(Meteor.absoluteUrl('#foo', {rootUrl: 'http://asdf.com'}), + 'http://asdf.com/#foo'); test.equal(Meteor.absoluteUrl('foo', {rootUrl: 'http://asdf.com', secure: true}), From eae1e2b21365cbdd06e208fa81f7d16df5af7c0d Mon Sep 17 00:00:00 2001 From: David Glasser Date: Fri, 17 Aug 2012 13:50:14 -0700 Subject: [PATCH 7/7] meteor run: Don't miss LISTENING if there's other stuff on stdout --- app/meteor/run.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/app/meteor/run.js b/app/meteor/run.js index 26c21bafd5..7b9810037f 100644 --- a/app/meteor/run.js +++ b/app/meteor/run.js @@ -187,12 +187,13 @@ var start_server = function (bundle_path, port, mongo_url, proc.stdout.on('data', function (data) { if (!data) return; + var originalLength = data.length; // string must match server.js - if (data.match(/^LISTENING\s*$/)) { + data = data.replace(/^LISTENING\s*(?:\n|$)/m, ''); + if (data.length != originalLength) on_listen_callback && on_listen_callback(); - } else { + if (data) log_to_clients({stdout: data}); - } }); proc.stderr.setEncoding('utf8');