CodeVetter · Repo Unpack · Behavior traces
expressjs/express
Four flows carry essentially all of Express's behaviour: application construction, request dispatch, response emission, and view rendering. Each is short and traceable by name — the framework is only three or four stack frames deep before control reaches an external package. The traces below name functions in call order as they appear in `lib/`.
- STARTUP: `require('express')` → `index.js` → `lib/express.js` → user calls `createApplication()` → `mixin(app, EventEmitter.prototype)` → `mixin(app, proto)` → `Object.create(req/res)` → `app.init()` → `app.defaultConfiguration()` → settings seeded and the `'mount'` listener attached → `Object.defineProperty(this, 'router', getter)` installs the lazy router.
- STARTUP (server): `app.listen(...)` → `http.createServer(this)` → if the last arg is a function it is wrapped with `once()` and registered on the server's `'error'` event → `server.listen.apply(server, args)`; the returned value is the `http.Server`, not the app.
- ROUTE REGISTRATION: `app.get('/x', fn)` → generated method sees `arguments.length > 1` → `this.route(path)` → `this.router.route(path)` (first access instantiates `new Router`) → `route.get(fn)`.
- DISPATCH: socket → `app(req, res)` closure → `app.handle` → `finalhandler(...)` built → `res.setHeader('X-Powered-By')` → `req.res`/`res.req` cross-links → both prototypes swapped → `res.locals` ensured → `this.router.handle(req, res, done)` hands off to the external router package.
- PRIMARY ACTION (`res.send('hi')`): typeof-string branch sets charset via `setCharset` or `this.type('html')` → `app.get('etag fn')` → length computed and `Content-Length` set unless `Transfer-Encoding` present → `etagFn(chunk, encoding)` → `this.set('ETag')` → `if (req.fresh) this.status(304)` → header stripping for 204/304/205 → `this.end(chunk, encoding)` (or bare `end()` for HEAD).
- JSON PATH: `res.json(obj)` → reads `json escape`/`json replacer`/`json spaces` → `stringify()` → sets `Content-Type: application/json` only if unset → delegates to `res.send(body)`, which then re-enters the string branch and applies the charset.
- JSONP PATH: `res.jsonp` → `stringify()` → reads the callback from `req.query[app.get('jsonp callback name')]` → takes `callback[0]` if an array → strips everything outside `[^\[\]\w$.]` → sets `X-Content-Type-Options: nosniff` and `text/javascript` → escapes U+2028/U+2029 → wraps in the `/**/ typeof cb === 'function' && cb(...)` Rosetta-Flash mitigation → `res.send`.
- RENDER PATH: `res.render(view, opts)` → `opts._locals = res.locals` → default callback `(err, str) => err ? req.next(err) : self.send(str)` → `app.render(name, opts, done)` → locals merged → cache consulted → `new View(name, { defaultEngine, root, engines })` → `view.lookup()` → `View#resolve` → `tryStat` → `tryRender(view, opts, done)` → `View#render` → engine → `process.nextTick` → `res.send(html)`.
- ENGINE RESOLUTION: inside the `View` constructor, if `opts.engines[this.ext]` is missing, Express computes `mod = this.ext.slice(1)` and performs a dynamic `require(mod).__express`, throwing `Module "x" does not provide a view engine.` when that export is not a function.
- VIEW LOOKUP fallback: `View#resolve` first tries `<dir>/<file>` and, failing that, `<dir>/<basename>/index<ext>` — both via synchronous `fs.statSync` wrapped in `tryStat`.
- FILE TRANSFER: `res.sendFile` → argument validation (throws on missing/non-string path, and on a relative path with no `root`) → `encodeURI(path)` → `opts.etag = app.enabled('etag')` → `send(req, pathname, opts)` → `sendfile(res, file, opts, cb)` → listeners registered → `file.pipe(res)`; the `onfinish` handler uses `setImmediate` to distinguish a completed stream from an aborted one.
- DOWNLOAD: `res.download` → argument shuffling for the (filename|options|callback) overloads → `Content-Disposition` built from `basename(name || path)` → caller headers copied except `content-disposition` → `opts = Object.create(opts)` so user options stay on the prototype → `resolve(path)` when no `root` → `this.sendFile(fullPath, opts, done)`.
- REDIRECT: `res.redirect([status,] url)` → optional `depd` deprecation calls → `this.location(address)` runs `encodeUrl` and re-reads the header → `res.format({ text, html, default })` picks a body → `res.status(status)` → explicit `Content-Length` via `Buffer.byteLength` → `end()` (body skipped for HEAD).
- SUB-APP MOUNT: `app.use('/admin', subApp)` → duck-type check passes → `subApp.mountpath = '/admin'`, `subApp.parent = this` → `router.use(path, mounted_app)` → `subApp.emit('mount', this)` → the child's `'mount'` listener re-parents its `request`/`response`/`engines`/`settings` prototypes; at request time `mounted_app` restores `orig.request`/`orig.response` before calling `next`.
- ERROR EXIT: when no handler responds, control returns to the `done` built in `app.handle`; `finalhandler`'s `onerror` is bound to `logerror`, which `console.error`s unless `app.get('env') === 'test'`.