void Controller::initializeUnionStation(Client *client, Request *req, RequestAnalysis &analysis) { if (analysis.unionStationSupport) { Options &options = req->options; ServerKit::HeaderTable &headers = req->secureHeaders; const LString *key = headers.lookup("!~UNION_STATION_KEY"); if (key == NULL || key->size == 0) { disconnectWithError(&client, "header !~UNION_STATION_KEY must be set."); return; } key = psg_lstr_make_contiguous(key, req->pool); const LString *filters = headers.lookup("!~UNION_STATION_FILTERS"); if (filters != NULL) { filters = psg_lstr_make_contiguous(filters, req->pool); } options.transaction = unionStationContext->newTransaction( options.getAppGroupName(), "requests", string(key->start->data, key->size), (filters != NULL) ? string(filters->start->data, filters->size) : string()); if (!options.transaction->isNull()) { options.analytics = true; options.unionStationKey = StaticString(key->start->data, key->size); } req->beginStopwatchLog(&req->stopwatchLogs.requestProcessing, "request processing"); req->logMessage(string("Request method: ") + http_method_str(req->method)); req->logMessage("URI: " + StaticString(req->path.start->data, req->path.size)); } }
void Controller::fillPoolOption(Request *req, StaticString &field, const HashedStaticString &name) { const LString *value = req->secureHeaders.lookup(name); if (value != NULL && value->size > 0) { value = psg_lstr_make_contiguous(value, req->pool); field = StaticString(value->start->data, value->size); } }
void Controller::fillPoolOptionSecToMsec(Request *req, unsigned int &field, const HashedStaticString &name) { const LString *value = req->secureHeaders.lookup(name); if (value != NULL && value->size > 0) { value = psg_lstr_make_contiguous(value, req->pool); field = stringToInt(StaticString(value->start->data, value->size)) * 1000; } }
void Controller::createNewPoolOptions(Client *client, Request *req, const HashedStaticString &appGroupName) { ServerKit::HeaderTable &secureHeaders = req->secureHeaders; Options &options = req->options; SKC_TRACE(client, 2, "Creating new pool options: app group name=" << appGroupName); options = Options(); const LString *scriptName = secureHeaders.lookup("!~SCRIPT_NAME"); const LString *appRoot = secureHeaders.lookup("!~PASSENGER_APP_ROOT"); if (scriptName == NULL || scriptName->size == 0) { if (appRoot == NULL || appRoot->size == 0) { const LString *documentRoot = secureHeaders.lookup("!~DOCUMENT_ROOT"); if (OXT_UNLIKELY(documentRoot == NULL || documentRoot->size == 0)) { disconnectWithError(&client, "client did not send a !~PASSENGER_APP_ROOT or a !~DOCUMENT_ROOT header"); return; } documentRoot = psg_lstr_make_contiguous(documentRoot, req->pool); appRoot = psg_lstr_create(req->pool, extractDirNameStatic(StaticString(documentRoot->start->data, documentRoot->size))); } else { appRoot = psg_lstr_make_contiguous(appRoot, req->pool); } options.appRoot = HashedStaticString(appRoot->start->data, appRoot->size); } else { if (appRoot == NULL || appRoot->size == 0) { const LString *documentRoot = secureHeaders.lookup("!~DOCUMENT_ROOT"); if (OXT_UNLIKELY(documentRoot == NULL || documentRoot->size == 0)) { disconnectWithError(&client, "client did not send a !~DOCUMENT_ROOT header"); return; } documentRoot = psg_lstr_null_terminate(documentRoot, req->pool); documentRoot = resolveSymlink(StaticString(documentRoot->start->data, documentRoot->size), req->pool); appRoot = psg_lstr_create(req->pool, extractDirNameStatic(StaticString(documentRoot->start->data, documentRoot->size))); } else { appRoot = psg_lstr_make_contiguous(appRoot, req->pool); } options.appRoot = HashedStaticString(appRoot->start->data, appRoot->size); scriptName = psg_lstr_make_contiguous(scriptName, req->pool); options.baseURI = StaticString(scriptName->start->data, scriptName->size); } fillPoolOptionsFromConfigCaches(options, req->pool, req->config); const LString *appType = secureHeaders.lookup("!~PASSENGER_APP_TYPE"); if (appType == NULL || appType->size == 0) { AppTypeDetector detector; PassengerAppType type = detector.checkAppRoot(options.appRoot); if (type == PAT_NONE || type == PAT_ERROR) { disconnectWithError(&client, "client did not send a recognized !~PASSENGER_APP_TYPE header"); return; } options.appType = getAppTypeName(type); } else { fillPoolOption(req, options.appType, "!~PASSENGER_APP_TYPE"); } options.appGroupName = appGroupName; fillPoolOption(req, options.appType, "!~PASSENGER_APP_TYPE"); fillPoolOption(req, options.environment, "!~PASSENGER_APP_ENV"); fillPoolOption(req, options.ruby, "!~PASSENGER_RUBY"); fillPoolOption(req, options.python, "!~PASSENGER_PYTHON"); fillPoolOption(req, options.nodejs, "!~PASSENGER_NODEJS"); fillPoolOption(req, options.meteorAppSettings, "!~PASSENGER_METEOR_APP_SETTINGS"); fillPoolOption(req, options.user, "!~PASSENGER_USER"); fillPoolOption(req, options.group, "!~PASSENGER_GROUP"); fillPoolOption(req, options.minProcesses, "!~PASSENGER_MIN_PROCESSES"); fillPoolOption(req, options.maxProcesses, "!~PASSENGER_MAX_PROCESSES"); fillPoolOption(req, options.spawnMethod, "!~PASSENGER_SPAWN_METHOD"); fillPoolOption(req, options.startCommand, "!~PASSENGER_START_COMMAND"); fillPoolOptionSecToMsec(req, options.startTimeout, "!~PASSENGER_START_TIMEOUT"); fillPoolOption(req, options.maxPreloaderIdleTime, "!~PASSENGER_MAX_PRELOADER_IDLE_TIME"); fillPoolOption(req, options.maxRequestQueueSize, "!~PASSENGER_MAX_REQUEST_QUEUE_SIZE"); fillPoolOption(req, options.abortWebsocketsOnProcessShutdown, "!~PASSENGER_ABORT_WEBSOCKETS_ON_PROCESS_SHUTDOWN"); fillPoolOption(req, options.forceMaxConcurrentRequestsPerProcess, "!~PASSENGER_FORCE_MAX_CONCURRENT_REQUESTS_PER_PROCESS"); fillPoolOption(req, options.restartDir, "!~PASSENGER_RESTART_DIR"); fillPoolOption(req, options.startupFile, "!~PASSENGER_STARTUP_FILE"); fillPoolOption(req, options.loadShellEnvvars, "!~PASSENGER_LOAD_SHELL_ENVVARS"); fillPoolOption(req, options.fileDescriptorUlimit, "!~PASSENGER_APP_FILE_DESCRIPTOR_ULIMIT"); fillPoolOption(req, options.raiseInternalError, "!~PASSENGER_RAISE_INTERNAL_ERROR"); fillPoolOption(req, options.lveMinUid, "!~PASSENGER_LVE_MIN_UID"); /******************/ boost::shared_ptr<Options> optionsCopy = boost::make_shared<Options>(options); optionsCopy->persist(options); optionsCopy->clearPerRequestFields(); optionsCopy->detachFromUnionStationTransaction(); poolOptionsCache.insert(options.getAppGroupName(), optionsCopy); }
unsigned int Controller::determineHeaderSizeForSessionProtocol(Request *req, SessionProtocolWorkingState &state, string delta_monotonic) { unsigned int dataSize = sizeof(boost::uint32_t); state.path = req->getPathWithoutQueryString(); state.hasBaseURI = req->options.baseURI != P_STATIC_STRING("/") && startsWith(state.path, req->options.baseURI); if (state.hasBaseURI) { state.path = state.path.substr(req->options.baseURI.size()); if (state.path.empty()) { state.path = P_STATIC_STRING("/"); } } state.queryString = req->getQueryString(); state.methodStr = StaticString(http_method_str(req->method)); state.remoteAddr = req->secureHeaders.lookup(REMOTE_ADDR); state.remotePort = req->secureHeaders.lookup(REMOTE_PORT); state.remoteUser = req->secureHeaders.lookup(REMOTE_USER); state.contentType = req->headers.lookup(HTTP_CONTENT_TYPE); if (req->hasBody()) { state.contentLength = req->headers.lookup(HTTP_CONTENT_LENGTH); } else { state.contentLength = NULL; } if (req->envvars != NULL) { size_t len = modp_b64_decode_len(req->envvars->size); state.environmentVariablesData = (char *) malloc(len); if (state.environmentVariablesData == NULL) { throw RuntimeException("Unable to allocate memory for base64 " "decoding of environment variables"); } len = modp_b64_decode(state.environmentVariablesData, req->envvars->start->data, req->envvars->size); if (len == (size_t) -1) { throw RuntimeException("Unable to base64 decode environment variables"); } state.environmentVariablesSize = len; } dataSize += sizeof("REQUEST_URI"); dataSize += req->path.size + 1; dataSize += sizeof("PATH_INFO"); dataSize += state.path.size() + 1; dataSize += sizeof("SCRIPT_NAME"); if (state.hasBaseURI) { dataSize += req->options.baseURI.size(); } else { dataSize += sizeof(""); } dataSize += sizeof("QUERY_STRING"); dataSize += state.queryString.size() + 1; dataSize += sizeof("REQUEST_METHOD"); dataSize += state.methodStr.size() + 1; if (req->host != NULL && req->host->size > 0) { const LString *host = psg_lstr_make_contiguous(req->host, req->pool); const char *sep = (const char *) memchr(host->start->data, ':', host->size); if (sep != NULL) { state.serverName = StaticString(host->start->data, sep - host->start->data); state.serverPort = StaticString(sep + 1, host->start->data + host->size - sep - 1); } else { state.serverName = StaticString(host->start->data, host->size); if (req->https) { state.serverPort = P_STATIC_STRING("443"); } else { state.serverPort = P_STATIC_STRING("80"); } } } else { state.serverName = defaultServerName; state.serverPort = defaultServerPort; } dataSize += sizeof("SERVER_NAME"); dataSize += state.serverName.size() + 1; dataSize += sizeof("SERVER_PORT"); dataSize += state.serverPort.size() + 1; dataSize += sizeof("SERVER_SOFTWARE"); dataSize += serverSoftware.size() + 1; dataSize += sizeof("SERVER_PROTOCOL"); dataSize += sizeof("HTTP/1.1"); dataSize += sizeof("REMOTE_ADDR"); if (state.remoteAddr != NULL) { dataSize += state.remoteAddr->size + 1; } else { dataSize += sizeof("127.0.0.1"); } dataSize += sizeof("REMOTE_PORT"); if (state.remotePort != NULL) { dataSize += state.remotePort->size + 1; } else { dataSize += sizeof("0"); } if (state.remoteUser != NULL) { dataSize += sizeof("REMOTE_USER"); dataSize += state.remoteUser->size + 1; } if (state.contentType != NULL) { dataSize += sizeof("CONTENT_TYPE"); dataSize += state.contentType->size + 1; } if (state.contentLength != NULL) { dataSize += sizeof("CONTENT_LENGTH"); dataSize += state.contentLength->size + 1; } dataSize += sizeof("PASSENGER_CONNECT_PASSWORD"); dataSize += ApplicationPool2::ApiKey::SIZE + 1; if (req->https) { dataSize += sizeof("HTTPS"); dataSize += sizeof("on"); } if (req->options.analytics) { dataSize += sizeof("PASSENGER_TXN_ID"); dataSize += req->options.transaction->getTxnId().size() + 1; dataSize += sizeof("PASSENGER_DELTA_MONOTONIC"); dataSize += delta_monotonic.size() + 1; } if (req->upgraded()) { dataSize += sizeof("HTTP_CONNECTION"); dataSize += sizeof("upgrade"); } ServerKit::HeaderTable::Iterator it(req->headers); while (*it != NULL) { dataSize += sizeof("HTTP_") - 1 + it->header->key.size + 1; dataSize += it->header->val.size + 1; it.next(); } if (state.environmentVariablesData != NULL) { dataSize += state.environmentVariablesSize; } return dataSize + 1; }