{"version":3,"sources":["webapp/webapp_server.js"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;AAAA,8B;;AAEA,2B;AACA,+B;AACA,2B;AACA,+B;AACA,6B;AACA,mC;;AAEA,qC;AACA,yC;AACA,+B;;AAEA,0C;AACA,kC;;AAEA,kC;AACA,mC;;AAEA,Y;AACA,qB;;AAEA,8B;AACA,Y;AACA,yD;AACA,mB;AACA,G;AACA,E;;AAEA,mC;;AAEA,8B;AACA,2B;;AAEA,+C;AACA,kB;;AAEA,uB;;AAEA,gC;AACA,uC;AACA,wB;AACA,4B;AACA,E;;AAEA,4C;AACA,yD;AACA,E;;AAEA,yB;AACA,E;AACA,iE;AACA,kE;AACA,+C;AACA,E;AACA,wE;AACA,+D;AACA,sE;AACA,kE;AACA,W;AACA,E;AACA,kD;AACA,uE;AACA,E;AACA,uE;AACA,iE;AACA,gE;AACA,E;AACA,6D;AACA,qD;AACA,E;AACA,8E;AACA,8E;AACA,8E;AACA,sB;AACA,E;AACA,uE;AACA,qE;AACA,8C;AACA,E;AACA,mE;AACA,W;;;AAGA,yC;AACA,iC;AACA,8B;AACA,oC;AACA,4C;AACA,qE;AACA,G;AACA,wB;AACA,E;;AAEA,kD;AACA,oD;AACA,U;AACA,sC;AACA,4B;AACA,4B;AACA,2B;AACA,I;AACA,E;;AAEA,qD;AACA,kD;;AAEA,2C;AACA,U;AACA,wD;AACA,iC;AACA,I;AACA,E;;AAEA,8E;AACA,gF;AACA,4D;AACA,4B;AACA,4C;AACA,+B;AACA,oD;AACA,mC;AACA,4B;AACA,a;AACA,uC;AACA,oE;AACA,6C;AACA,K;AACA,4B;AACA,E;AACA,+C;AACA,gC;AACA,E;;AAEA,+B;AACA,6B;AACA,sD;AACA,iB;;AAEA,kE;AACA,kE;AACA,oE;AACA,oE;AACA,8D;AACA,kD;AACA,8B;AACA,iB;;AAEA,iE;AACA,gC;AACA,iB;;AAEA,wD;AACA,c;AACA,E;;;AAGA,sE;AACA,+D;AACA,E;AACA,mE;AACA,sE;AACA,E;AACA,oE;AACA,sD;AACA,oE;AACA,oE;AACA,6C;AACA,qD;AACA,E;AACA,4D;AACA,oE;AACA,oB;;AAEA,4B;AACA,8D;AACA,2C;AACA,8C;AACA,yE;AACA,I;;AAEA,+D;AACA,8C;AACA,wE;AACA,uB;AACA,8B;AACA,S;AACA,I;AACA,kE;AACA,8C;AACA,wE;AACA,uB;AACA,8B;AACA,S;AACA,I;AACA,mD;AACA,iC;AACA,0C;AACA,oB;;AAEA,+B;AACA,6D;AACA,uD;AACA,I;AACA,G;;;;AAIA,4E;AACA,wE;AACA,yE;AACA,6E;AACA,iC;AACA,gE;AACA,oE;AACA,sC;AACA,gF;AACA,kC;AACA,gD;AACA,sE;AACA,mD;AACA,mC;AACA,gC;AACA,yC;AACA,K;AACA,iE;AACA,E;;;AAGA,4C;AACA,8C;AACA,0B;AACA,gB;AACA,oB;AACA,2B;;AAEA,qE;AACA,+D;AACA,oE;AACA,qB;AACA,wE;AACA,6B;AACA,+C;;AAEA,kD;;AAEA,sE;AACA,mE;AACA,0D;AACA,gC;AACA,+C;AACA,mC;AACA,c;AACA,K;;AAEA,uC;AACA,mE;AACA,oC;AACA,O;AACA,G;AACA,sC;AACA,E;;AAEA,6D;AACA,iE;AACA,4E;AACA,8C;;AAEA,+B;AACA,uC;AACA,kD;AACA,I;;AAEA,kB;AACA,+B;AACA,0E;AACA,2E;AACA,uC;AACA,qB;AACA,U;AACA,uC;AACA,2D;AACA,G;;AAEA,wC;AACA,c;AACA,uC;AACA,sD;AACA,0B;AACA,kC;AACA,mC;AACA,yC;AACA,oB;AACA,iC;AACA,gC;AACA,c;AACA,W;AACA,U;AACA,gF;AACA,+E;AACA,gF;AACA,+E;AACA,+E;AACA,uD;AACA,4C;AACA,6D;AACA,gF;AACA,wC;AACA,qE;AACA,wC;AACA,O;AACA,yB;AACA,I;AACA,E;;AAEA,4E;AACA,wC;AACA,oE;AACA,wD;AACA,E;AACA,2C;AACA,wE;AACA,wD;;AAEA,gB;;AAEA,qD;AACA,qC;AACA,gF;AACA,oD;AACA,W;AACA,W;AACA,G;AACA,sD;AACA,O;AACA,4C;AACA,e;AACA,W;AACA,W;AACA,G;;AAEA,oC;AACA,wB;AACA,6D;AACA,O;AACA,iB;AACA,c;AACA,I;;AAEA,iD;AACA,iD;AACA,kD;AACA,mE;AACA,W;AACA,mD;AACA,yD;AACA,gD;AACA,W;AACA,G;;AAEA,sC;AACA,W;AACA,W;AACA,G;;AAEA,4E;AACA,2E;AACA,Y;;AAEA,mC;;AAEA,kE;AACA,8D;AACA,kC;AACA,I;AACA,6E;AACA,8E;AACA,kE;AACA,8E;AACA,0E;AACA,0E;AACA,gD;AACA,6B;AACA,mC;AACA,8B;;AAEA,0E;AACA,4E;AACA,4B;AACA,I;AACA,6E;AACA,0E;AACA,0B;AACA,gC;AACA,kE;AACA,qC;AACA,G;;AAEA,2B;AACA,2E;AACA,mC;AACA,6D;AACA,oC;AACA,qE;AACA,qE;AACA,4C;AACA,wD;AACA,K;AACA,G;;AAEA,qB;AACA,4B;AACA,c;AACA,U;AACA,gC;AACA,qB;AACA,2E;AACA,mC;AACA,sD;AACA,2B;AACA,kB;AACA,Q;AACA,oC;AACA,+D;AACA,2B;AACA,kB;AACA,Q;AACA,iB;AACA,G;AACA,E;;AAEA,2C;AACA,kE;AACA,gD;;AAEA,0E;AACA,yB;AACA,sC;AACA,iD;AACA,E;;AAEA,mC;AACA,2B;AACA,iD;;AAEA,4C;AACA,2D;AACA,I;;AAEA,sD;AACA,kC;AACA,uB;AACA,+D;AACA,8D;AACA,sE;AACA,+C;AACA,qD;AACA,sE;AACA,qD;AACA,oE;AACA,6D;;AAEA,4D;AACA,4D;;AAEA,kD;;AAEA,2C;AACA,0C;AACA,oD;AACA,kE;AACA,4D;AACA,wC;AACA,4C;AACA,8C;AACA,6B;AACA,c;;AAEA,iC;AACA,iF;AACA,2C;AACA,6E;AACA,mE;AACA,+B;AACA,gB;AACA,a;AACA,W;AACA,W;;AAEA,uB;AACA,6B;AACA,4E;AACA,2D;AACA,oE;AACA,U;;AAEA,8C;;AAEA,qE;AACA,mD;AACA,8D;AACA,2C;AACA,0B;AACA,sB;AACA,U;AACA,Q;;AAEA,W;AACA,sE;AACA,yD;AACA,oD;AACA,kD;AACA,W;;AAEA,8B;AACA,kD;AACA,mB;AACA,oE;AACA,wB;AACA,O;AACA,O;AACA,I;;AAEA,qD;AACA,2E;AACA,gF;AACA,4E;AACA,gF;AACA,iC;AACA,sB;AACA,iC;AACA,oE;AACA,uE;AACA,iE;AACA,wE;AACA,4D;AACA,oE;AACA,wD;AACA,8D;AACA,sE;AACA,qB;AACA,mE;AACA,iC;AACA,kD;AACA,gC;AACA,S;AACA,O;AACA,M;;AAEA,kC;AACA,kE;AACA,qC;AACA,sD;AACA,uC;AACA,6C;AACA,S;;AAEA,8C;AACA,+B;;AAEA,qD;AACA,uD;AACA,2C;AACA,kE;AACA,Q;AACA,O;AACA,I;;AAEA,yC;;AAEA,c;AACA,sB;;AAEA,iD;AACA,8B;;AAEA,wE;AACA,4C;AACA,qC;AACA,8B;;AAEA,2E;AACA,sB;AACA,oC;AACA,0C;AACA,a;AACA,a;AACA,K;AACA,uB;AACA,6B;AACA,c;AACA,K;;AAEA,6C;AACA,8C;AACA,oE;AACA,oD;AACA,gC;AACA,6E;AACA,+D;AACA,gF;AACA,4C;AACA,mF;AACA,6D;AACA,a;AACA,2E;AACA,a;AACA,4B;AACA,8B;AACA,qC;AACA,qB;AACA,Y;AACA,a;AACA,K;AACA,K;;AAEA,0E;AACA,6B;AACA,2B;;AAEA,0C;AACA,iD;AACA,qC;AACA,uB;AACA,wE;AACA,a;AACA,K;;AAEA,2E;AACA,kD;AACA,wC;AACA,iC;;AAEA,oC;AACA,+E;AACA,+E;AACA,mC;AACA,0C;AACA,6E;AACA,gB;AACA,a;AACA,K;AACA,gE;AACA,gC;AACA,K;;AAEA,qC;AACA,0B;AACA,oB;;AAEA,mB;AACA,iD;AACA,M;AACA,qB;AACA,sC;;AAEA,gD;;AAEA,wE;AACA,6E;AACA,gF;AACA,8D;AACA,0D;AACA,kC;AACA,8D;AACA,gB;AACA,uB;AACA,K;;AAEA,iD;AACA,wD;AACA,yC;AACA,6D;;AAEA,qE;AACA,mC;AACA,Y;AACA,+B;AACA,K;;AAEA,oB;AACA,S;AACA,qD;AACA,iB;AACA,gD;AACA,kC;AACA,gB;AACA,uB;AACA,K;;AAEA,gC;AACA,2B;AACA,c;AACA,qB;AACA,K;;AAEA,gE;AACA,+B;AACA,uB;AACA,c;AACA,K;;;AAGA,0C;AACA,gC;;AAEA,0E;AACA,+E;AACA,mC;AACA,8C;;AAEA,sE;AACA,gF;AACA,S;AACA,qE;;;AAGA,iB;AACA,oB;AACA,2C;AACA,2C;AACA,2B;AACA,mB;AACA,wC;AACA,mC;AACA,M;AACA,+B;AACA,+B;AACA,qC;AACA,U;AACA,Y;AACA,K;AACA,K;;AAEA,2E;AACA,gF;AACA,2B;AACA,0B;AACA,0C;;AAEA,+D;AACA,oD;AACA,mC;AACA,oC;AACA,6E;AACA,6C;AACA,0D;;AAEA,2C;AACA,kC;AACA,+C;;AAEA,qB;AACA,2C;AACA,kC;AACA,Q;;AAEA,oB;AACA,I;AACA,E;;;AAGA,kB;;;AAGA,gC;;AAEA,oD;AACA,8B;AACA,E;;AAEA,4D;AACA,+B;AACA,wC;AACA,E;;AAEA,2D;AACA,8B;AACA,wC;AACA,E;;AAEA,oE;AACA,wE;AACA,qE;AACA,sC;AACA,4B;AACA,mD;AACA,8D;AACA,E;;AAEA,qB;AACA,gD;AACA,wD","file":"/packages/webapp.js","sourcesContent":["////////// Requires //////////\n\nvar fs = Npm.require(\"fs\");\nvar http = Npm.require(\"http\");\nvar os = Npm.require(\"os\");\nvar path = Npm.require(\"path\");\nvar url = Npm.require(\"url\");\nvar crypto = Npm.require(\"crypto\");\n\nvar connect = Npm.require('connect');\nvar useragent = Npm.require('useragent');\nvar send = Npm.require('send');\n\nvar Future = Npm.require('fibers/future');\nvar Fiber = Npm.require('fibers');\n\nvar SHORT_SOCKET_TIMEOUT = 5*1000;\nvar LONG_SOCKET_TIMEOUT = 120*1000;\n\nWebApp = {};\nWebAppInternals = {};\n\nWebAppInternals.NpmModules = {\n connect: {\n version: Npm.require('connect/package.json').version,\n module: connect\n }\n};\n\nWebApp.defaultArch = 'web.browser';\n\n// XXX maps archs to manifests\nWebApp.clientPrograms = {};\n\n// XXX maps archs to program path on filesystem\nvar archPath = {};\n\nvar bundledJsCssPrefix;\n\nvar sha1 = function (contents) {\n var hash = crypto.createHash('sha1');\n hash.update(contents);\n return hash.digest('hex');\n};\n\nvar readUtf8FileSync = function (filename) {\n return Meteor.wrapAsync(fs.readFile)(filename, 'utf8');\n};\n\n// #BrowserIdentification\n//\n// We have multiple places that want to identify the browser: the\n// unsupported browser page, the appcache package, and, eventually\n// delivering browser polyfills only as needed.\n//\n// To avoid detecting the browser in multiple places ad-hoc, we create a\n// Meteor \"browser\" object. It uses but does not expose the npm\n// useragent module (we could choose a different mechanism to identify\n// the browser in the future if we wanted to). The browser object\n// contains\n//\n// * `name`: the name of the browser in camel case\n// * `major`, `minor`, `patch`: integers describing the browser version\n//\n// Also here is an early version of a Meteor `request` object, intended\n// to be a high-level description of the request without exposing\n// details of connect's low-level `req`. Currently it contains:\n//\n// * `browser`: browser identification object described above\n// * `url`: parsed url, including parsed query params\n//\n// As a temporary hack there is a `categorizeRequest` function on WebApp which\n// converts a connect `req` to a Meteor `request`. This can go away once smart\n// packages such as appcache are being passed a `request` object directly when\n// they serve content.\n//\n// This allows `request` to be used uniformly: it is passed to the html\n// attributes hook, and the appcache package can use it when deciding\n// whether to generate a 404 for the manifest.\n//\n// Real routing / server side rendering will probably refactor this\n// heavily.\n\n\n// e.g. \"Mobile Safari\" => \"mobileSafari\"\nvar camelCase = function (name) {\n var parts = name.split(' ');\n parts[0] = parts[0].toLowerCase();\n for (var i = 1; i < parts.length; ++i) {\n parts[i] = parts[i].charAt(0).toUpperCase() + parts[i].substr(1);\n }\n return parts.join('');\n};\n\nvar identifyBrowser = function (userAgentString) {\n var userAgent = useragent.lookup(userAgentString);\n return {\n name: camelCase(userAgent.family),\n major: +userAgent.major,\n minor: +userAgent.minor,\n patch: +userAgent.patch\n };\n};\n\n// XXX Refactor as part of implementing real routing.\nWebAppInternals.identifyBrowser = identifyBrowser;\n\nWebApp.categorizeRequest = function (req) {\n return {\n browser: identifyBrowser(req.headers['user-agent']),\n url: url.parse(req.url, true)\n };\n};\n\n// HTML attribute hooks: functions to be called to determine any attributes to\n// be added to the '' tag. Each function is passed a 'request' object (see\n// #BrowserIdentification) and should return null or object.\nvar htmlAttributeHooks = [];\nvar getHtmlAttributes = function (request) {\n var combinedAttributes = {};\n _.each(htmlAttributeHooks || [], function (hook) {\n var attributes = hook(request);\n if (attributes === null)\n return;\n if (typeof attributes !== 'object')\n throw Error(\"HTML attribute hook must return null or object\");\n _.extend(combinedAttributes, attributes);\n });\n return combinedAttributes;\n};\nWebApp.addHtmlAttributeHook = function (hook) {\n htmlAttributeHooks.push(hook);\n};\n\n// Serve app HTML for this URL?\nvar appUrl = function (url) {\n if (url === '/favicon.ico' || url === '/robots.txt')\n return false;\n\n // NOTE: app.manifest is not a web standard like favicon.ico and\n // robots.txt. It is a file name we have chosen to use for HTML5\n // appcache URLs. It is included here to prevent using an appcache\n // then removing it from poisoning an app permanently. Eventually,\n // once we have server side routing, this won't be needed as\n // unknown URLs with return a 404 automatically.\n if (url === '/app.manifest')\n return false;\n\n // Avoid serving app HTML for declared routes such as /sockjs/.\n if (RoutePolicy.classify(url))\n return false;\n\n // we currently return app HTML on all URLs by default\n return true;\n};\n\n\n// We need to calculate the client hash after all packages have loaded\n// to give them a chance to populate __meteor_runtime_config__.\n//\n// Calculating the hash during startup means that packages can only\n// populate __meteor_runtime_config__ during load, not during startup.\n//\n// Calculating instead it at the beginning of main after all startup\n// hooks had run would allow packages to also populate\n// __meteor_runtime_config__ during startup, but that's too late for\n// autoupdate because it needs to have the client hash at startup to\n// insert the auto update version itself into\n// __meteor_runtime_config__ to get it to the client.\n//\n// An alternative would be to give autoupdate a \"post-start,\n// pre-listen\" hook to allow it to insert the auto update version at\n// the right moment.\n\nMeteor.startup(function () {\n var calculateClientHash = WebAppHashing.calculateClientHash;\n WebApp.clientHash = function (archName) {\n archName = archName || WebApp.defaultArch;\n return calculateClientHash(WebApp.clientPrograms[archName].manifest);\n };\n\n WebApp.calculateClientHashRefreshable = function (archName) {\n archName = archName || WebApp.defaultArch;\n return calculateClientHash(WebApp.clientPrograms[archName].manifest,\n function (name) {\n return name === \"css\";\n });\n };\n WebApp.calculateClientHashNonRefreshable = function (archName) {\n archName = archName || WebApp.defaultArch;\n return calculateClientHash(WebApp.clientPrograms[archName].manifest,\n function (name) {\n return name !== \"css\";\n });\n };\n WebApp.calculateClientHashCordova = function () {\n var archName = 'web.cordova';\n if (! WebApp.clientPrograms[archName])\n return 'none';\n\n return calculateClientHash(\n WebApp.clientPrograms[archName].manifest, null, _.pick(\n __meteor_runtime_config__, 'PUBLIC_SETTINGS'));\n };\n});\n\n\n\n// When we have a request pending, we want the socket timeout to be long, to\n// give ourselves a while to serve it, and to allow sockjs long polls to\n// complete. On the other hand, we want to close idle sockets relatively\n// quickly, so that we can shut down relatively promptly but cleanly, without\n// cutting off anyone's response.\nWebApp._timeoutAdjustmentRequestCallback = function (req, res) {\n // this is really just req.socket.setTimeout(LONG_SOCKET_TIMEOUT);\n req.setTimeout(LONG_SOCKET_TIMEOUT);\n // Insert our new finish listener to run BEFORE the existing one which removes\n // the response from the socket.\n var finishListeners = res.listeners('finish');\n // XXX Apparently in Node 0.12 this event is now called 'prefinish'.\n // https://github.com/joyent/node/commit/7c9b6070\n res.removeAllListeners('finish');\n res.on('finish', function () {\n res.setTimeout(SHORT_SOCKET_TIMEOUT);\n });\n _.each(finishListeners, function (l) { res.on('finish', l); });\n};\n\n\n// Will be updated by main before we listen.\n// Map from client arch to boilerplate object.\n// Boilerplate object has:\n// - func: XXX\n// - baseData: XXX\nvar boilerplateByArch = {};\n\n// Given a request (as returned from `categorizeRequest`), return the\n// boilerplate HTML to serve for that request. Memoizes on HTML\n// attributes (used by, eg, appcache) and whether inline scripts are\n// currently allowed.\n// XXX so far this function is always called with arch === 'web.browser'\nvar memoizedBoilerplate = {};\nvar getBoilerplate = function (request, arch) {\n\n var htmlAttributes = getHtmlAttributes(request);\n\n // The only thing that changes from request to request (for now) are\n // the HTML attributes (used by, eg, appcache) and whether inline\n // scripts are allowed, so we can memoize based on that.\n var memHash = JSON.stringify({\n inlineScriptsAllowed: inlineScriptsAllowed,\n htmlAttributes: htmlAttributes,\n arch: arch\n });\n\n if (! memoizedBoilerplate[memHash]) {\n memoizedBoilerplate[memHash] = boilerplateByArch[arch].toHTML({\n htmlAttributes: htmlAttributes\n });\n }\n return memoizedBoilerplate[memHash];\n};\n\nWebAppInternals.generateBoilerplateInstance = function (arch,\n manifest,\n additionalOptions) {\n additionalOptions = additionalOptions || {};\n\n var runtimeConfig = _.extend(\n _.clone(__meteor_runtime_config__),\n additionalOptions.runtimeConfigOverrides || {}\n );\n\n var jsCssPrefix;\n if (arch === 'web.cordova') {\n // in cordova we serve assets up directly from disk so it doesn't make\n // sense to use the prefix (ordinarily something like a CDN) and go out\n // to the internet for those files.\n jsCssPrefix = '';\n } else {\n jsCssPrefix = bundledJsCssPrefix ||\n __meteor_runtime_config__.ROOT_URL_PATH_PREFIX || '';\n }\n\n return new Boilerplate(arch, manifest,\n _.extend({\n pathMapper: function (itemPath) {\n return path.join(archPath[arch], itemPath); },\n baseDataExtension: {\n additionalStaticJs: _.map(\n additionalStaticJs || [],\n function (contents, pathname) {\n return {\n pathname: pathname,\n contents: contents\n };\n }\n ),\n // Convert to a JSON string, then get rid of most weird characters, then\n // wrap in double quotes. (The outermost JSON.stringify really ought to\n // just be \"wrap in double quotes\" but we use it to be safe.) This might\n // end up inside a \", but normal {{spacebars}} escaping escapes too much! See\n // https://github.com/meteor/meteor/issues/3730\n meteorRuntimeConfig: JSON.stringify(\n encodeURIComponent(JSON.stringify(runtimeConfig))),\n rootUrlPathPrefix: __meteor_runtime_config__.ROOT_URL_PATH_PREFIX || '',\n bundledJsCssPrefix: jsCssPrefix,\n inlineScriptsAllowed: WebAppInternals.inlineScriptsAllowed(),\n inline: additionalOptions.inline\n }\n }, additionalOptions)\n );\n};\n\n// A mapping from url path to \"info\". Where \"info\" has the following fields:\n// - type: the type of file to be served\n// - cacheable: optionally, whether the file should be cached or not\n// - sourceMapUrl: optionally, the url of the source map\n//\n// Info also contains one of the following:\n// - content: the stringified content that should be served at this path\n// - absolutePath: the absolute path on disk to the file\n\nvar staticFiles;\n\n// Serve static files from the manifest or added with\n// `addStaticJs`. Exported for tests.\nWebAppInternals.staticFilesMiddleware = function (staticFiles, req, res, next) {\n if ('GET' != req.method && 'HEAD' != req.method) {\n next();\n return;\n }\n var pathname = connect.utils.parseUrl(req).pathname;\n try {\n pathname = decodeURIComponent(pathname);\n } catch (e) {\n next();\n return;\n }\n\n var serveStaticJs = function (s) {\n res.writeHead(200, {\n 'Content-type': 'application/javascript; charset=UTF-8'\n });\n res.write(s);\n res.end();\n };\n\n if (pathname === \"/meteor_runtime_config.js\" &&\n ! WebAppInternals.inlineScriptsAllowed()) {\n serveStaticJs(\"__meteor_runtime_config__ = \" +\n JSON.stringify(__meteor_runtime_config__) + \";\");\n return;\n } else if (_.has(additionalStaticJs, pathname) &&\n ! WebAppInternals.inlineScriptsAllowed()) {\n serveStaticJs(additionalStaticJs[pathname]);\n return;\n }\n\n if (!_.has(staticFiles, pathname)) {\n next();\n return;\n }\n\n // We don't need to call pause because, unlike 'static', once we call into\n // 'send' and yield to the event loop, we never call another handler with\n // 'next'.\n\n var info = staticFiles[pathname];\n\n // Cacheable files are files that should never change. Typically\n // named by their hash (eg meteor bundled js and css files).\n // We cache them ~forever (1yr).\n //\n // We cache non-cacheable files anyway. This isn't really correct, as users\n // can change the files and changes won't propagate immediately. However, if\n // we don't cache them, browsers will 'flicker' when rerendering\n // images. Eventually we will probably want to rewrite URLs of static assets\n // to include a query parameter to bust caches. That way we can both get\n // good caching behavior and allow users to change assets without delay.\n // https://github.com/meteor/meteor/issues/773\n var maxAge = info.cacheable\n ? 1000 * 60 * 60 * 24 * 365\n : 1000 * 60 * 60 * 24;\n\n // Set the X-SourceMap header, which current Chrome, FireFox, and Safari\n // understand. (The SourceMap header is slightly more spec-correct but FF\n // doesn't understand it.)\n //\n // You may also need to enable source maps in Chrome: open dev tools, click\n // the gear in the bottom right corner, and select \"enable source maps\".\n if (info.sourceMapUrl) {\n res.setHeader('X-SourceMap',\n __meteor_runtime_config__.ROOT_URL_PATH_PREFIX +\n info.sourceMapUrl);\n }\n\n if (info.type === \"js\") {\n res.setHeader(\"Content-Type\", \"application/javascript; charset=UTF-8\");\n } else if (info.type === \"css\") {\n res.setHeader(\"Content-Type\", \"text/css; charset=UTF-8\");\n } else if (info.type === \"json\") {\n res.setHeader(\"Content-Type\", \"application/json; charset=UTF-8\");\n // XXX if it is a manifest we are serving, set additional headers\n if (/\\/manifest.json$/.test(pathname)) {\n res.setHeader(\"Access-Control-Allow-Origin\", \"*\");\n }\n }\n\n if (info.content) {\n res.write(info.content);\n res.end();\n } else {\n send(req, info.absolutePath)\n .maxage(maxAge)\n .hidden(true) // if we specified a dotfile in the manifest, serve it\n .on('error', function (err) {\n Log.error(\"Error serving static file \" + err);\n res.writeHead(500);\n res.end();\n })\n .on('directory', function () {\n Log.error(\"Unexpected directory \" + info.absolutePath);\n res.writeHead(500);\n res.end();\n })\n .pipe(res);\n }\n};\n\nvar getUrlPrefixForArch = function (arch) {\n // XXX we rely on the fact that arch names don't contain slashes\n // in that case we would need to uri escape it\n\n // We add '__' to the beginning of non-standard archs to \"scope\" the url\n // to Meteor internals.\n return arch === WebApp.defaultArch ?\n '' : '/' + '__' + arch.replace(/^web\\./, '');\n};\n\nvar runWebAppServer = function () {\n var shuttingDown = false;\n var syncQueue = new Meteor._SynchronousQueue();\n\n var getItemPathname = function (itemUrl) {\n return decodeURIComponent(url.parse(itemUrl).pathname);\n };\n\n WebAppInternals.reloadClientPrograms = function () {\n syncQueue.runTask(function() {\n staticFiles = {};\n var generateClientProgram = function (clientPath, arch) {\n // read the control for the client we'll be serving up\n var clientJsonPath = path.join(__meteor_bootstrap__.serverDir,\n clientPath);\n var clientDir = path.dirname(clientJsonPath);\n var clientJson = JSON.parse(readUtf8FileSync(clientJsonPath));\n if (clientJson.format !== \"web-program-pre1\")\n throw new Error(\"Unsupported format for client assets: \" +\n JSON.stringify(clientJson.format));\n\n if (! clientJsonPath || ! clientDir || ! clientJson)\n throw new Error(\"Client config file not parsed.\");\n\n var urlPrefix = getUrlPrefixForArch(arch);\n\n var manifest = clientJson.manifest;\n _.each(manifest, function (item) {\n if (item.url && item.where === \"client\") {\n staticFiles[urlPrefix + getItemPathname(item.url)] = {\n absolutePath: path.join(clientDir, item.path),\n cacheable: item.cacheable,\n // Link from source to its map\n sourceMapUrl: item.sourceMapUrl,\n type: item.type\n };\n\n if (item.sourceMap) {\n // Serve the source map too, under the specified URL. We assume all\n // source maps are cacheable.\n staticFiles[urlPrefix + getItemPathname(item.sourceMapUrl)] = {\n absolutePath: path.join(clientDir, item.sourceMap),\n cacheable: true\n };\n }\n }\n });\n\n var program = {\n manifest: manifest,\n version: WebAppHashing.calculateClientHash(manifest, null, _.pick(\n __meteor_runtime_config__, 'PUBLIC_SETTINGS')),\n PUBLIC_SETTINGS: __meteor_runtime_config__.PUBLIC_SETTINGS\n };\n\n WebApp.clientPrograms[arch] = program;\n\n // Serve the program as a string at /foo//manifest.json\n // XXX change manifest.json -> program.json\n staticFiles[path.join(urlPrefix, 'manifest.json')] = {\n content: JSON.stringify(program),\n cacheable: true,\n type: \"json\"\n };\n };\n\n try {\n var clientPaths = __meteor_bootstrap__.configJson.clientPaths;\n _.each(clientPaths, function (clientPath, arch) {\n archPath[arch] = path.dirname(clientPath);\n generateClientProgram(clientPath, arch);\n });\n\n // Exported for tests.\n WebAppInternals.staticFiles = staticFiles;\n } catch (e) {\n Log.error(\"Error reloading the client program: \" + e.stack);\n process.exit(1);\n }\n });\n };\n\n WebAppInternals.generateBoilerplate = function () {\n // This boilerplate will be served to the mobile devices when used with\n // Meteor/Cordova for the Hot-Code Push and since the file will be served by\n // the device's server, it is important to set the DDP url to the actual\n // Meteor server accepting DDP connections and not the device's file server.\n var defaultOptionsForArch = {\n 'web.cordova': {\n runtimeConfigOverrides: {\n // XXX We use absoluteUrl() here so that we serve https://\n // URLs to cordova clients if force-ssl is in use. If we were\n // to use __meteor_runtime_config__.ROOT_URL instead of\n // absoluteUrl(), then Cordova clients would immediately get a\n // HCP setting their DDP_DEFAULT_CONNECTION_URL to\n // http://example.meteor.com. This breaks the app, because\n // force-ssl doesn't serve CORS headers on 302\n // redirects. (Plus it's undesirable to have clients\n // connecting to http://example.meteor.com when force-ssl is\n // in use.)\n DDP_DEFAULT_CONNECTION_URL: process.env.MOBILE_DDP_URL ||\n Meteor.absoluteUrl(),\n ROOT_URL: process.env.MOBILE_ROOT_URL ||\n Meteor.absoluteUrl()\n }\n }\n };\n\n syncQueue.runTask(function() {\n _.each(WebApp.clientPrograms, function (program, archName) {\n boilerplateByArch[archName] =\n WebAppInternals.generateBoilerplateInstance(\n archName, program.manifest,\n defaultOptionsForArch[archName]);\n });\n\n // Clear the memoized boilerplate cache.\n memoizedBoilerplate = {};\n\n // Configure CSS injection for the default arch\n // XXX implement the CSS injection for all archs?\n WebAppInternals.refreshableAssets = {\n allCss: boilerplateByArch[WebApp.defaultArch].baseData.css\n };\n });\n };\n\n WebAppInternals.reloadClientPrograms();\n\n // webserver\n var app = connect();\n\n // Auto-compress any json, javascript, or text.\n app.use(connect.compress());\n\n // Packages and apps can add handlers that run before any other Meteor\n // handlers via WebApp.rawConnectHandlers.\n var rawConnectHandlers = connect();\n app.use(rawConnectHandlers);\n\n // We're not a proxy; reject (without crashing) attempts to treat us like\n // one. (See #1212.)\n app.use(function(req, res, next) {\n if (RoutePolicy.isValidUrl(req.url)) {\n next();\n return;\n }\n res.writeHead(400);\n res.write(\"Not a proxy\");\n res.end();\n });\n\n // Strip off the path prefix, if it exists.\n app.use(function (request, response, next) {\n var pathPrefix = __meteor_runtime_config__.ROOT_URL_PATH_PREFIX;\n var url = Npm.require('url').parse(request.url);\n var pathname = url.pathname;\n // check if the path in the url starts with the path prefix (and the part\n // after the path prefix must start with a / if it exists.)\n if (pathPrefix && pathname.substring(0, pathPrefix.length) === pathPrefix &&\n (pathname.length == pathPrefix.length\n || pathname.substring(pathPrefix.length, pathPrefix.length + 1) === \"/\")) {\n request.url = request.url.substring(pathPrefix.length);\n next();\n } else if (pathname === \"/favicon.ico\" || pathname === \"/robots.txt\") {\n next();\n } else if (pathPrefix) {\n response.writeHead(404);\n response.write(\"Unknown path\");\n response.end();\n } else {\n next();\n }\n });\n\n // Parse the query string into res.query. Used by oauth_server, but it's\n // generally pretty handy..\n app.use(connect.query());\n\n // Serve static files from the manifest.\n // This is inspired by the 'static' middleware.\n app.use(function (req, res, next) {\n Fiber(function () {\n WebAppInternals.staticFilesMiddleware(staticFiles, req, res, next);\n }).run();\n });\n\n // Packages and apps can add handlers to this via WebApp.connectHandlers.\n // They are inserted before our default handler.\n var packageAndAppHandlers = connect();\n app.use(packageAndAppHandlers);\n\n var suppressConnectErrors = false;\n // connect knows it is an error handler because it has 4 arguments instead of\n // 3. go figure. (It is not smart enough to find such a thing if it's hidden\n // inside packageAndAppHandlers.)\n app.use(function (err, req, res, next) {\n if (!err || !suppressConnectErrors || !req.headers['x-suppress-error']) {\n next(err);\n return;\n }\n res.writeHead(err.status, { 'Content-Type': 'text/plain' });\n res.end(\"An error message\");\n });\n\n app.use(function (req, res, next) {\n if (! appUrl(req.url))\n return next();\n\n var headers = {\n 'Content-Type': 'text/html; charset=utf-8'\n };\n if (shuttingDown)\n headers['Connection'] = 'Close';\n\n var request = WebApp.categorizeRequest(req);\n\n if (request.url.query && request.url.query['meteor_css_resource']) {\n // In this case, we're requesting a CSS resource in the meteor-specific\n // way, but we don't have it. Serve a static css file that indicates that\n // we didn't have it, so we can detect that and refresh.\n headers['Content-Type'] = 'text/css; charset=utf-8';\n res.writeHead(200, headers);\n res.write(\".meteor-css-not-found-error { width: 0px;}\");\n res.end();\n return undefined;\n }\n\n // /packages/asdfsad ... /__cordova/dafsdf.js\n var pathname = connect.utils.parseUrl(req).pathname;\n var archKey = pathname.split('/')[1];\n var archKeyCleaned = 'web.' + archKey.replace(/^__/, '');\n\n if (! /^__/.test(archKey) || ! _.has(archPath, archKeyCleaned)) {\n archKey = WebApp.defaultArch;\n } else {\n archKey = archKeyCleaned;\n }\n\n var boilerplate;\n try {\n boilerplate = getBoilerplate(request, archKey);\n } catch (e) {\n Log.error(\"Error running template: \" + e);\n res.writeHead(500, headers);\n res.end();\n return undefined;\n }\n\n res.writeHead(200, headers);\n res.write(boilerplate);\n res.end();\n return undefined;\n });\n\n // Return 404 by default, if no other handlers serve this URL.\n app.use(function (req, res) {\n res.writeHead(404);\n res.end();\n });\n\n\n var httpServer = http.createServer(app);\n var onListeningCallbacks = [];\n\n // After 5 seconds w/o data on a socket, kill it. On the other hand, if\n // there's an outstanding request, give it a higher timeout instead (to avoid\n // killing long-polling requests)\n httpServer.setTimeout(SHORT_SOCKET_TIMEOUT);\n\n // Do this here, and then also in livedata/stream_server.js, because\n // stream_server.js kills all the current request handlers when installing its\n // own.\n httpServer.on('request', WebApp._timeoutAdjustmentRequestCallback);\n\n\n // start up app\n _.extend(WebApp, {\n connectHandlers: packageAndAppHandlers,\n rawConnectHandlers: rawConnectHandlers,\n httpServer: httpServer,\n // For testing.\n suppressConnectErrors: function () {\n suppressConnectErrors = true;\n },\n onListening: function (f) {\n if (onListeningCallbacks)\n onListeningCallbacks.push(f);\n else\n f();\n }\n });\n\n // Let the rest of the packages (and Meteor.startup hooks) insert connect\n // middlewares and update __meteor_runtime_config__, then keep going to set up\n // actually serving HTML.\n main = function (argv) {\n WebAppInternals.generateBoilerplate();\n\n // only start listening after all the startup code has run.\n var localPort = parseInt(process.env.PORT) || 0;\n var host = process.env.BIND_IP;\n var localIp = host || '0.0.0.0';\n httpServer.listen(localPort, localIp, Meteor.bindEnvironment(function() {\n if (process.env.METEOR_PRINT_ON_LISTEN)\n console.log(\"LISTENING\"); // must match run-app.js\n\n var callbacks = onListeningCallbacks;\n onListeningCallbacks = null;\n _.each(callbacks, function (x) { x(); });\n\n }, function (e) {\n console.error(\"Error listening:\", e);\n console.error(e && e.stack);\n }));\n\n return 'DAEMON';\n };\n};\n\n\nrunWebAppServer();\n\n\nvar inlineScriptsAllowed = true;\n\nWebAppInternals.inlineScriptsAllowed = function () {\n return inlineScriptsAllowed;\n};\n\nWebAppInternals.setInlineScriptsAllowed = function (value) {\n inlineScriptsAllowed = value;\n WebAppInternals.generateBoilerplate();\n};\n\nWebAppInternals.setBundledJsCssPrefix = function (prefix) {\n bundledJsCssPrefix = prefix;\n WebAppInternals.generateBoilerplate();\n};\n\n// Packages can call `WebAppInternals.addStaticJs` to specify static\n// JavaScript to be included in the app. This static JS will be inlined,\n// unless inline scripts have been disabled, in which case it will be\n// served under `/`.\nvar additionalStaticJs = {};\nWebAppInternals.addStaticJs = function (contents) {\n additionalStaticJs[\"/\" + sha1(contents) + \".js\"] = contents;\n};\n\n// Exported for tests\nWebAppInternals.getBoilerplate = getBoilerplate;\nWebAppInternals.additionalStaticJs = additionalStaticJs;\n"]}