streamToString(readStream, async htmlDoc => {
								let jsonml = htmlToJsonML(htmlDoc);
								// MongoDB doesn't accept periods in keys, so we replace them with
								// `˙`s when storing them in the database.
								jsonml = replaceInKeys(jsonml, '.', '˙');
								let snapshot = {
									type: 'http://sharejs.org/types/JSONv0',
									data: jsonml
								};
								const userPermissions = await permissionManager
									.getUserPermissionsFromSnapshot(req.user.username, req.user.provider,
										snapshot);
								// If user doesn't have write permissions to the docuemnt, add them if
								// the user is logged in, otherwise just delete all permissions on the
								// new document.
								if (!userPermissions.includes('w')) {
									if (req.user.username === 'anonymous' && req.user.provider === '') {
										snapshot = permissionManager.clearPermissionsFromSnapshot(snapshot);
									} else {
										snapshot = await permissionManager
											.addPermissionsToSnapshot(req.user.username, req.user.provider,
												'rw', snapshot);
									}
								}
								documentManager.createNewDocument({
									webstrateId, snapshot
								}, function(err, _webstrateId) {
									if (err) {
										console.error(err);
										return reject(err);
									}
									createdWebstrate = true;
								});
							});
	}, async function(err, snapshot) {
		if (err) {
			console.error(err);
			return res.status(409).send(String(err));
		}

		req.user.permissions = await permissionManager.getUserPermissionsFromSnapshot(req.user.username,
			req.user.provider, snapshot);

		// If the webstrate doesn't exist, write permissions are required to create it.
		if (!snapshot.type && !req.user.permissions.includes('w')) {
			return res.status(403).send('Insufficient permissions.');
		}

		// If the webstrate does exist, read permissions are required to access it (or any of its
		// assets).
		if (!req.user.permissions.includes('r')) {
			return res.status(403).send('Insufficient permissions.');
		}

		// Set CORS header on a response, assuming the requesting host is allowed it.
		setCorsHeaders(req, res, snapshot);

		// Requesting an asset.
		if (req.assetName) {
			try {
				const asset = await assetManager.getAsset({
					webstrateId: req.webstrateId,
					assetName: req.assetName,
					version: snapshot.v
				});

				if (!asset) {
					return res.status(404).send(`Asset "${req.assetName}" not found.`);
				}

				if ('dir' in req.query) {
					const zipStructure = await getZipStructure(asset.fileName);
					res.json(zipStructure);
					return;
				}

				if (req.assetPath) {
					return yauzl.open(APP_PATH + '/uploads/' + asset.fileName, { lazyEntries: true },
						(err, zipFile) => {
							if (err) {
								return res.status(400).send(`"${req.assetName}" is not a valid ZIP file.`);
							}
							zipFile.on('entry', async entry => {
								if (req.assetPath !== entry.fileName) {
									return zipFile.readEntry();
								}

								// If requested file is a directory, list directory files.
								if (entry.fileName.endsWith('/')) {
									const zipStructure = await getZipStructure(asset.fileName);
									const filteredZipStructure = zipStructure.filter(path =>
										path.startsWith(entry.fileName));
									return res.json(filteredZipStructure);
								}

								zipFile.openReadStream(entry, (err, readStream) => {
									res.type(mime.lookup(entry.fileName) || 'text/plain');
									// Getting this from a ZIP might be a little heavy, so we cache it for a year,
									// even though the ZIP asset could in fact get overwritten.
									res.setHeader('Cache-Control', 'public, max-age=31557600');
									readStream.pipe(res);
								});
							});
							zipFile.readEntry();

							zipFile.once('end', async () => {
								res.status(404).send(`File "${req.assetPath}" not found in asset ` +
									`"${req.assetName}".\n`);
							});
						});
				}

				// `/<webstrateId>/<asset>` may not always refer to the same asset, but to optimize rapid
				// requests, we set a maxAge anyway. If the requested asset includes a specific version,
				// it'll always refer to the same thing, allowing us to set a longer maxAge.
				var maxAge = req.version ? '1y' : (config.maxAge || '1m');
				res.type(asset.mimeType);
				return res.sendFile(APP_PATH + '/uploads/' + asset.fileName, { maxAge });
			} catch (error) {
				console.error(error);
				return res.status(409).send(String(err));
			}
		}

		// Requesting current document version number by calling `/<id>?v` or `/<id>?version`.
		if ('v' in req.query || 'version' in req.query) {
			return serveVersion(req, res, snapshot);
		}

		// Requesting a list of operations by calling `/<id>?ops`.
		if ('ops' in req.query) {
			return serveOps(req, res);
		}

		// Requesting a list of tags by calling `/<id>?tags`.
		if ('tags' in req.query) {
			return serveTags(req, res);
		}

		// Requesting a list of assets by calling `/<id>?assets`.
		if ('assets' in req.query) {
			return serveAssets(req, res);
		}

		// Requesting a JsonML version of the webstrate by calling `/<id>?json`.
		if ('json' in req.query) {
			if (!snapshot.type) {
				return res.status(404).send('Document doesn\'t exist.');
			}

			return serveJsonMLWebstrate(req, res, snapshot);
		}

		// Requesting a raw version of the webstrate (i.e. a server-generated HTML file) by calling
		// `/<id>?raw`.
		if ('raw' in req.query) {
			if (!snapshot.type) {
				return res.status(404).send('Document doesn\'t exist.');
			}

			return serveRawWebstrate(req, res, snapshot);
		}

		if ('dl' in req.query) {
			if (!snapshot.type) {
				return res.status(404).send('Document doesn\'t exist.');
			}

			return serveCompressedWebstrate(req, res, snapshot);
		}

		if ('tokens' in req.query) {
			return serveTokenList(req, res);
		}

		// Requesting a copy of the webstrate.
		if ('copy' in req.query) {
			var defaultPermissions = permissionManager.getDefaultPermissions(req.user.username,
				req.user.provider);

			// If a user is required to be logged in (through loggedInToCreateWebstrates) to create a
			// webstrate, we also require them to be logged in to copy a webstrate.
			if (!permissionManager.userIsAllowedToCreateWebstrate(req.user)) {
				let err = 'Must be logged in to copy a webstrate.';
				if (Array.isArray(config.loggedInToCreateWebstrates)) {
					const allowedProviders = config.loggedInToCreateWebstrates.join(' or ');
					err =  `Must be logged in with ${allowedProviders} to copy a webstrate.`;
				}
				return res.status(403).send(err);
			}

			// If the user has no default write permissions, they're not allowed to create documents.
			if (!defaultPermissions.includes('w')) {
				return res.status(403).send('Write permissions are required to create a new document.');
			}

			return copyWebstrate(req, res, snapshot);
		}

		// Requesting to restore document to a previous version or tag by calling:
		// `/<id>/?restore=<version|tag>`.
		if ('restore' in req.query) {
			if (!req.user.permissions.includes('w')) {
				return res.status(403).send('Write permissions are required to restore a document.');
			}

			// If the document contains a user with admin permissions, only admins can restore the
			// document.
			if (!req.user.permissions.includes('a') &&
				await permissionManager.webstrateHasAdmin(req.webstrateId)) {
				return res.status(403).send('Admin permissions are required to restore this document.');
			}

			return restoreWebstrate(req, res, snapshot);
		}

		if ('delete' in req.query) {
			// If a user is required to be logged in (through loggedInToCreateWebstrates) to create a
			// webstrate, we also require them to be logged in to delete a webstrate.
			if (!permissionManager.userIsAllowedToCreateWebstrate(req.user)) {
				let err = 'Must be logged in to delete a webstrate.';
				if (Array.isArray(config.loggedInToCreateWebstrates)) {
					const allowedProviders = config.loggedInToCreateWebstrates.join(' or ');
					err =  `Must be logged in with ${allowedProviders} to delete a webstrate.`;
				}
				return res.status(403).send(err);
			}

			if (!req.user.permissions.includes('w')) {
				return res.status(403).send('Write permissions are required to delete a document.');
			}

			// If the document contains a user with admin permissions, only admins can delete the
			// document.
			if (!req.user.permissions.includes('a') &&
				await permissionManager.webstrateHasAdmin(req.webstrateId)) {
				return res.status(403).send('Admin permissions are required to delete this document.');
			}

			return deleteWebstrate(req, res);
		}

		// We don't need to check for "static" in req.query, because this happens on the client side.

		return serveWebstrate(req, res);
	});