unsigned int constructHeaders(request_rec *r, DirConfig *config,
		vector<StaticString> &requestData, DirectoryMapper &mapper,
		string &output)
	{
		const char *baseURI = mapper.getBaseURI();
		
		/*
		 * Apache unescapes URI's before passing them to Phusion Passenger,
		 * but backend processes expect the escaped version.
		 * http://code.google.com/p/phusion-passenger/issues/detail?id=404
		 */
		size_t uriLen = strlen(r->uri);
		unsigned int escaped = escapeUri(NULL, (const unsigned char *) r->uri, uriLen);
		char escapedUri[uriLen + 2 * escaped + 1];
		escapeUri((unsigned char *) escapedUri, (const unsigned char *) r->uri, uriLen);
		escapedUri[uriLen + 2 * escaped] = '\0';
		
		
		// Set standard CGI variables.
		#ifdef AP_GET_SERVER_VERSION_DEPRECATED
			addHeader(output, "SERVER_SOFTWARE", ap_get_server_banner());
		#else
			addHeader(output, "SERVER_SOFTWARE", ap_get_server_version());
		#endif
		addHeader(output, "SERVER_PROTOCOL", r->protocol);
		addHeader(output, "SERVER_NAME",     ap_get_server_name(r));
		addHeader(output, "SERVER_ADMIN",    r->server->server_admin);
		addHeader(output, "SERVER_ADDR",     r->connection->local_ip);
		addHeader(output, "SERVER_PORT",     apr_psprintf(r->pool, "%u", ap_get_server_port(r)));
		#if HTTP_VERSION(AP_SERVER_MAJORVERSION_NUMBER, AP_SERVER_MINORVERSION_NUMBER) >= 2004
			addHeader(output, "REMOTE_ADDR", r->connection->client_ip);
			addHeader(output, "REMOTE_PORT", apr_psprintf(r->pool, "%d", r->connection->client_addr->port));
		#else
			addHeader(output, "REMOTE_ADDR", r->connection->remote_ip);
			addHeader(output, "REMOTE_PORT", apr_psprintf(r->pool, "%d", r->connection->remote_addr->port));
		#endif
		addHeader(output, "REMOTE_USER",     r->user);
		addHeader(output, "REQUEST_METHOD",  r->method);
		addHeader(output, "QUERY_STRING",    r->args ? r->args : "");
		addHeader(output, "HTTPS",           lookupEnv(r, "HTTPS"));
		addHeader(output, "CONTENT_TYPE",    lookupHeader(r, "Content-type"));
		addHeader(output, "DOCUMENT_ROOT",   ap_document_root(r));
		
		if (config->allowsEncodedSlashes()) {
			/*
			 * Apache decodes encoded slashes in r->uri, so we must use r->unparsed_uri
			 * if we are to support encoded slashes. However mod_rewrite doesn't change
			 * r->unparsed_uri, so the user must make a choice between mod_rewrite
			 * support or encoded slashes support. Sucks. :-(
			 *
			 * http://code.google.com/p/phusion-passenger/issues/detail?id=113
			 * http://code.google.com/p/phusion-passenger/issues/detail?id=230
			 */
			addHeader(output, "REQUEST_URI", r->unparsed_uri);
		} else {
			const char *request_uri;
			if (r->args != NULL) {
				request_uri = apr_pstrcat(r->pool, escapedUri, "?", r->args, (char *) NULL);
			} else {
				request_uri = escapedUri;
			}
			addHeader(output, "REQUEST_URI", request_uri);
		}
		
		if (baseURI == NULL) {
			addHeader(output, "SCRIPT_NAME", "");
			addHeader(output, "PATH_INFO", escapedUri);
		} else {
			addHeader(output, "SCRIPT_NAME", baseURI);
			addHeader(output, "PATH_INFO", escapedUri + strlen(baseURI));
		}
		
		// Set HTTP headers.
		const apr_array_header_t *hdrs_arr;
		apr_table_entry_t *hdrs;
		int i;
		
		hdrs_arr = apr_table_elts(r->headers_in);
		hdrs = (apr_table_entry_t *) hdrs_arr->elts;
		for (i = 0; i < hdrs_arr->nelts; ++i) {
			if (hdrs[i].key) {
				addHeader(output, httpToEnv(r->pool, hdrs[i].key), hdrs[i].val);
			}
		}
		
		// Add other environment variables.
		const apr_array_header_t *env_arr;
		apr_table_entry_t *env;
		
		env_arr = apr_table_elts(r->subprocess_env);
		env = (apr_table_entry_t*) env_arr->elts;
		for (i = 0; i < env_arr->nelts; ++i) {
			addHeader(output, env[i].key, env[i].val);
		}
		
		// Phusion Passenger options.
		addHeader(output, "PASSENGER_STATUS_LINE", "false");
		addHeader(output, "PASSENGER_APP_ROOT", mapper.getAppRoot());
		addHeader(output, "PASSENGER_APP_GROUP_NAME", config->getAppGroupName(mapper.getAppRoot()));
		addHeader(output, "PASSENGER_RUBY", config->ruby ? config->ruby : serverConfig.defaultRuby);
		addHeader(output, "PASSENGER_PYTHON", config->python);
		addHeader(output, "PASSENGER_ENV", config->getEnvironment());
		addHeader(output, "PASSENGER_SPAWN_METHOD", config->getSpawnMethodString());
		addHeader(output, "PASSENGER_USER", config->getUser());
		addHeader(output, "PASSENGER_GROUP", config->getGroup());
		addHeader(output, "PASSENGER_APP_TYPE", mapper.getApplicationTypeName());
		addHeader(output, "PASSENGER_MIN_INSTANCES",
			apr_psprintf(r->pool, "%ld", config->getMinInstances()));
		addHeader(output, "PASSENGER_MAX_PRELOADER_IDLE_TIME",
			apr_psprintf(r->pool, "%ld", config->maxPreloaderIdleTime));
		addHeader(output, "PASSENGER_DEBUGGER", "false");
		addHeader(output, "PASSENGER_SHOW_VERSION_IN_HEADER", "true");
		addHeader(output, "PASSENGER_MAX_REQUESTS",
			apr_psprintf(r->pool, "%ld", config->getMaxRequests()));
		addHeader(output, "PASSENGER_STAT_THROTTLE_RATE",
			apr_psprintf(r->pool, "%ld", config->getStatThrottleRate()));
		addHeader(output, "PASSENGER_RESTART_DIR", config->getRestartDir());
		addHeader(output, "PASSENGER_FRIENDLY_ERROR_PAGES",
			config->showFriendlyErrorPages() ? "true" : "false");
		if (config->useUnionStation() && !config->unionStationKey.empty()) {
			addHeader(output, "UNION_STATION_SUPPORT", "true");
			addHeader(output, "UNION_STATION_KEY", config->unionStationKey);
			if (!config->unionStationFilters.empty()) {
				addHeader(output, "UNION_STATION_FILTERS",
					config->getUnionStationFilterString());
			}
		}
		
		/*********************/
		/*********************/
		
		requestData.push_back(output);
		return output.size();
	}