passenger 5.3.7 → 6.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG +14 -0
- data/build/agent.rb +4 -2
- data/build/support/cxx_dependency_map.rb +134 -0
- data/resources/templates/standalone/server.erb +1 -0
- data/src/agent/AgentMain.cpp +4 -0
- data/src/agent/Core/ApplicationPool/Group/StateInspection.cpp +1 -1
- data/src/agent/Core/ApplicationPool/Options.h +7 -7
- data/src/agent/Core/ApplicationPool/Process.h +3 -0
- data/src/agent/Core/Config.h +9 -2
- data/src/agent/Core/Controller/Config.h +27 -6
- data/src/agent/Core/Controller/InitRequest.cpp +12 -7
- data/src/agent/Core/Controller/InitializationAndShutdown.cpp +2 -0
- data/src/agent/Core/CoreMain.cpp +62 -33
- data/src/agent/Core/OptionParser.h +6 -0
- data/src/agent/Core/SpawningKit/Spawner.h +20 -5
- data/src/agent/Core/SpawningKit/UserSwitchingRules.h +13 -6
- data/src/agent/Core/TelemetryCollector.h +1 -0
- data/src/agent/FileReadHelper/FileReadHelperMain.cpp +198 -0
- data/src/agent/Watchdog/Config.h +1 -0
- data/src/apache2_module/ConfigGeneral/AutoGeneratedDefinitions.cpp +5 -0
- data/src/apache2_module/ConfigGeneral/AutoGeneratedSetterFuncs.cpp +15 -0
- data/src/apache2_module/DirConfig/AutoGeneratedCreateFunction.cpp +5 -0
- data/src/apache2_module/DirConfig/AutoGeneratedManifestGeneration.cpp +13 -0
- data/src/apache2_module/DirConfig/AutoGeneratedMergeFunction.cpp +7 -0
- data/src/apache2_module/DirConfig/AutoGeneratedStruct.h +13 -0
- data/src/apache2_module/DirectoryMapper.h +14 -3
- data/src/apache2_module/Hooks.cpp +15 -4
- data/src/cxx_supportlib/AppLocalConfigFileUtils.h +148 -0
- data/src/cxx_supportlib/AppTypeDetector/CBindings.cpp +12 -1
- data/src/cxx_supportlib/AppTypeDetector/CBindings.h +2 -0
- data/src/cxx_supportlib/AppTypeDetector/Detector.h +38 -4
- data/src/cxx_supportlib/Constants.h +1 -1
- data/src/nginx_module/ConfigGeneral/AutoGeneratedDefinitions.c +16 -0
- data/src/nginx_module/ConfigGeneral/AutoGeneratedManifestDefaultsInitialization.c +6 -0
- data/src/nginx_module/ConfigGeneral/AutoGeneratedSetterFuncs.c +12 -0
- data/src/nginx_module/Configuration.c +20 -0
- data/src/nginx_module/ContentHandler.c +301 -23
- data/src/nginx_module/ContentHandler.h +5 -0
- data/src/nginx_module/LocationConfig/AutoGeneratedCreateFunction.c +10 -0
- data/src/nginx_module/LocationConfig/AutoGeneratedManifestGeneration.c +27 -0
- data/src/nginx_module/LocationConfig/AutoGeneratedMergeFunction.c +3 -0
- data/src/nginx_module/LocationConfig/AutoGeneratedStruct.h +7 -0
- data/src/nginx_module/ngx_http_passenger_module.h +6 -1
- data/src/ruby_supportlib/phusion_passenger.rb +6 -5
- data/src/ruby_supportlib/phusion_passenger/apache2/config_options.rb +6 -0
- data/src/ruby_supportlib/phusion_passenger/nginx/config_options.rb +14 -0
- data/src/ruby_supportlib/phusion_passenger/standalone/app_finder.rb +1 -0
- data/src/ruby_supportlib/phusion_passenger/standalone/config_options_list.rb +11 -1
- data/src/ruby_supportlib/phusion_passenger/standalone/start_command/builtin_engine.rb +1 -0
- metadata +4 -2
@@ -0,0 +1,148 @@
|
|
1
|
+
/*
|
2
|
+
* Phusion Passenger - https://www.phusionpassenger.com/
|
3
|
+
* Copyright (c) 2018 Phusion Holding B.V.
|
4
|
+
*
|
5
|
+
* "Passenger", "Phusion Passenger" and "Union Station" are registered
|
6
|
+
* trademarks of Phusion Holding B.V.
|
7
|
+
*
|
8
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
9
|
+
* of this software and associated documentation files (the "Software"), to deal
|
10
|
+
* in the Software without restriction, including without limitation the rights
|
11
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
12
|
+
* copies of the Software, and to permit persons to whom the Software is
|
13
|
+
* furnished to do so, subject to the following conditions:
|
14
|
+
*
|
15
|
+
* The above copyright notice and this permission notice shall be included in
|
16
|
+
* all copies or substantial portions of the Software.
|
17
|
+
*
|
18
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
19
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
20
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
21
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
22
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
23
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
24
|
+
* THE SOFTWARE.
|
25
|
+
*/
|
26
|
+
#ifndef _PASSENGER_APP_LOCAL_CONFIG_FILE_UTILS_H_
|
27
|
+
#define _PASSENGER_APP_LOCAL_CONFIG_FILE_UTILS_H_
|
28
|
+
|
29
|
+
#include <oxt/system_calls.hpp>
|
30
|
+
#include <oxt/backtrace.hpp>
|
31
|
+
|
32
|
+
#include <cerrno>
|
33
|
+
#include <fcntl.h>
|
34
|
+
|
35
|
+
#include <jsoncpp/json.h>
|
36
|
+
|
37
|
+
#include <StaticString.h>
|
38
|
+
#include <Constants.h>
|
39
|
+
#include <Exceptions.h>
|
40
|
+
#include <IOTools/IOUtils.h>
|
41
|
+
#include <Utils/ScopeGuard.h>
|
42
|
+
|
43
|
+
namespace Passenger {
|
44
|
+
|
45
|
+
using namespace std;
|
46
|
+
|
47
|
+
|
48
|
+
struct AppLocalConfig {
|
49
|
+
string appStartCommand;
|
50
|
+
bool appSupportsKuriaProtocol;
|
51
|
+
|
52
|
+
AppLocalConfig()
|
53
|
+
: appSupportsKuriaProtocol(false)
|
54
|
+
{ }
|
55
|
+
};
|
56
|
+
|
57
|
+
|
58
|
+
inline AppLocalConfig
|
59
|
+
parseAppLocalConfigFile(const StaticString appRoot) {
|
60
|
+
TRACE_POINT();
|
61
|
+
string path = appRoot + "/Passengerfile.json";
|
62
|
+
|
63
|
+
// Reading from Passengerfile.json from a root process is unsafe
|
64
|
+
// because of symlink attacks and other kinds of attacks. See the
|
65
|
+
// comments for safeReadFile().
|
66
|
+
//
|
67
|
+
// We are unable to use safeReadFile() here because we do not
|
68
|
+
// control the safety of the directories leading up to appRoot.
|
69
|
+
//
|
70
|
+
// What we can do is preventing the contents of an arbitrary
|
71
|
+
// file read from leaking out. Therefore, our result struct
|
72
|
+
// only contains a limited number of fields, that are known
|
73
|
+
// not to contain sensitive information. We also don't propagate
|
74
|
+
// JSON parsing error messages, which may contain the content.
|
75
|
+
|
76
|
+
int fd = syscalls::open(path.c_str(), O_RDONLY | O_NONBLOCK);
|
77
|
+
if (fd == -1) {
|
78
|
+
if (errno == ENOENT) {
|
79
|
+
return AppLocalConfig();
|
80
|
+
} else {
|
81
|
+
int e = errno;
|
82
|
+
throw FileSystemException("Error opening '" + path
|
83
|
+
+ "' for reading", e, path);
|
84
|
+
}
|
85
|
+
}
|
86
|
+
|
87
|
+
UPDATE_TRACE_POINT();
|
88
|
+
FdGuard fdGuard(fd, __FILE__, __LINE__);
|
89
|
+
pair<string, bool> content;
|
90
|
+
try {
|
91
|
+
content = readAll(fd, 1024 * 512);
|
92
|
+
} catch (const SystemException &e) {
|
93
|
+
throw FileSystemException("Error reading from '" + path + "'",
|
94
|
+
e.code(), path);
|
95
|
+
}
|
96
|
+
if (!content.second) {
|
97
|
+
throw SecurityException("Error parsing " + path
|
98
|
+
+ ": file exceeds size limit of 512 KB");
|
99
|
+
}
|
100
|
+
fdGuard.runNow();
|
101
|
+
|
102
|
+
UPDATE_TRACE_POINT();
|
103
|
+
Json::Reader reader;
|
104
|
+
Json::Value config;
|
105
|
+
if (!reader.parse(content.first, config)) {
|
106
|
+
if (geteuid() == 0) {
|
107
|
+
throw RuntimeException("Error parsing " + path
|
108
|
+
+ " (error messages suppressed for security reasons)");
|
109
|
+
} else {
|
110
|
+
throw RuntimeException("Error parsing " + path + ": "
|
111
|
+
+ reader.getFormattedErrorMessages());
|
112
|
+
}
|
113
|
+
}
|
114
|
+
// We no longer need the raw data so free the memory.
|
115
|
+
content.first.resize(0);
|
116
|
+
|
117
|
+
|
118
|
+
UPDATE_TRACE_POINT();
|
119
|
+
AppLocalConfig result;
|
120
|
+
|
121
|
+
if (!config.isObject()) {
|
122
|
+
throw RuntimeException("Config file " + path
|
123
|
+
+ " is not valid: top-level JSON object expected");
|
124
|
+
}
|
125
|
+
if (config.isMember("app_start_command")) {
|
126
|
+
if (config["app_start_command"].isString()) {
|
127
|
+
result.appStartCommand = config["app_start_command"].asString();
|
128
|
+
} else {
|
129
|
+
throw RuntimeException("Config file " + path
|
130
|
+
+ " is not valid: key 'app_start_command' must be a boolean");
|
131
|
+
}
|
132
|
+
}
|
133
|
+
if (config.isMember("app_supports_kuria_protocol")) {
|
134
|
+
if (config["app_supports_kuria_protocol"].isBool()) {
|
135
|
+
result.appSupportsKuriaProtocol = config["app_supports_kuria_protocol"].asBool();
|
136
|
+
} else {
|
137
|
+
throw RuntimeException("Config file " + path
|
138
|
+
+ " is not valid: key 'app_supports_kuria_protocol' must be a boolean");
|
139
|
+
}
|
140
|
+
}
|
141
|
+
|
142
|
+
return result;
|
143
|
+
}
|
144
|
+
|
145
|
+
|
146
|
+
} // namespace Passenger
|
147
|
+
|
148
|
+
#endif /* _PASSENGER_APP_LOCAL_CONFIG_FILE_UTILS_H_ */
|
@@ -74,6 +74,17 @@ psg_app_type_detector_result_set_wrapper_registry_entry(PsgAppTypeDetectorResult
|
|
74
74
|
cxxResult->wrapperRegistryEntry = static_cast<const WrapperRegistry::Entry *>(entry);
|
75
75
|
}
|
76
76
|
|
77
|
+
const char *
|
78
|
+
psg_app_type_detector_result_get_app_start_command(const PsgAppTypeDetectorResult *result,
|
79
|
+
size_t *len)
|
80
|
+
{
|
81
|
+
const Detector::Result *cxxResult = static_cast<const Detector::Result *>(result);
|
82
|
+
if (len != NULL) {
|
83
|
+
*len = cxxResult->appStartCommand.size();
|
84
|
+
}
|
85
|
+
return cxxResult->appStartCommand.data();
|
86
|
+
}
|
87
|
+
|
77
88
|
|
78
89
|
PsgAppTypeDetector *
|
79
90
|
psg_app_type_detector_new(const PsgWrapperRegistry *registry,
|
@@ -81,7 +92,7 @@ psg_app_type_detector_new(const PsgWrapperRegistry *registry,
|
|
81
92
|
{
|
82
93
|
const Registry *cxxRegistry = static_cast<const Registry *>(registry);
|
83
94
|
try {
|
84
|
-
Detector *detector = new Detector(*cxxRegistry, NULL, NULL, throttleRate);
|
95
|
+
Detector *detector = new Detector(*cxxRegistry, NULL, NULL, throttleRate, NULL);
|
85
96
|
return static_cast<PsgAppTypeDetector *>(detector);
|
86
97
|
} catch (const std::bad_alloc &) {
|
87
98
|
return NULL;
|
@@ -46,6 +46,8 @@ const PsgWrapperRegistryEntry *psg_app_type_detector_result_get_wrapper_registry
|
|
46
46
|
const PsgAppTypeDetectorResult *result);
|
47
47
|
void psg_app_type_detector_result_set_wrapper_registry_entry(PsgAppTypeDetectorResult *result,
|
48
48
|
const PsgWrapperRegistryEntry *entry);
|
49
|
+
const char *psg_app_type_detector_result_get_app_start_command(const PsgAppTypeDetectorResult *result,
|
50
|
+
size_t *len);
|
49
51
|
|
50
52
|
|
51
53
|
typedef void PsgAppTypeDetector;
|
@@ -38,30 +38,35 @@
|
|
38
38
|
#include <string>
|
39
39
|
|
40
40
|
#include <Exceptions.h>
|
41
|
+
#include <AppLocalConfigFileUtils.h>
|
41
42
|
#include <WrapperRegistry/Registry.h>
|
42
43
|
#include <FileTools/PathManip.h>
|
43
44
|
#include <FileTools/FileManip.h>
|
45
|
+
#include <StrIntTools/StrIntUtils.h>
|
46
|
+
#include <DataStructures/StringKeyTable.h>
|
44
47
|
#include <Utils.h>
|
45
48
|
#include <Utils/CachedFileStat.hpp>
|
46
|
-
#include <StrIntTools/StrIntUtils.h>
|
47
49
|
|
48
50
|
namespace Passenger {
|
49
51
|
namespace AppTypeDetector {
|
50
52
|
|
51
53
|
using namespace std;
|
52
54
|
|
55
|
+
typedef AppLocalConfig* AppLocalConfigPtr;
|
56
|
+
typedef StringKeyTable<AppLocalConfig> AppLocalConfigMap;
|
53
57
|
|
54
58
|
class Detector {
|
55
59
|
public:
|
56
60
|
struct Result {
|
57
61
|
const WrapperRegistry::Entry *wrapperRegistryEntry;
|
62
|
+
string appStartCommand;
|
58
63
|
|
59
64
|
Result()
|
60
65
|
: wrapperRegistryEntry(NULL)
|
61
66
|
{ }
|
62
67
|
|
63
68
|
bool isNull() const {
|
64
|
-
return wrapperRegistryEntry == NULL;
|
69
|
+
return wrapperRegistryEntry == NULL && appStartCommand.empty();
|
65
70
|
}
|
66
71
|
};
|
67
72
|
|
@@ -71,6 +76,9 @@ private:
|
|
71
76
|
boost::mutex *cstatMutex;
|
72
77
|
unsigned int throttleRate;
|
73
78
|
bool ownsCstat;
|
79
|
+
AppLocalConfigMap appLocalConfigCache;
|
80
|
+
boost::mutex *configMutex;
|
81
|
+
StringKeyTable<time_t> appRootCheckTimes;
|
74
82
|
|
75
83
|
bool check(char *buf, const char *end, const StaticString &appRoot,
|
76
84
|
const StaticString &name)
|
@@ -88,15 +96,33 @@ private:
|
|
88
96
|
cstat, cstatMutex, throttleRate) != FT_NONEXISTANT;
|
89
97
|
}
|
90
98
|
|
99
|
+
AppLocalConfigPtr getAppLocalConfigFromCache(const StaticString &appRoot) {
|
100
|
+
boost::unique_lock<boost::mutex> l;
|
101
|
+
time_t currentTime = SystemTime::get();
|
102
|
+
if (configMutex != NULL) {
|
103
|
+
l = boost::unique_lock<boost::mutex>(*configMutex);
|
104
|
+
}
|
105
|
+
if (!appLocalConfigCache.contains(appRoot)
|
106
|
+
|| currentTime >= (appRootCheckTimes.lookupCopy(appRoot) + throttleRate)) {
|
107
|
+
AppLocalConfig config = parseAppLocalConfigFile(appRoot);
|
108
|
+
appLocalConfigCache.insert(appRoot, config);
|
109
|
+
appRootCheckTimes.insert(appRoot, currentTime);
|
110
|
+
}
|
111
|
+
AppLocalConfigPtr appLocalConfig;
|
112
|
+
appLocalConfigCache.lookup(appRoot, &appLocalConfig);
|
113
|
+
return appLocalConfig;
|
114
|
+
}
|
115
|
+
|
91
116
|
public:
|
92
117
|
Detector(const WrapperRegistry::Registry &_registry,
|
93
118
|
CachedFileStat *_cstat = NULL, boost::mutex *_cstatMutex = NULL,
|
94
|
-
unsigned int _throttleRate = 1)
|
119
|
+
unsigned int _throttleRate = 1, boost::mutex *_configMutex = NULL)
|
95
120
|
: registry(_registry),
|
96
121
|
cstat(_cstat),
|
97
122
|
cstatMutex(_cstatMutex),
|
98
123
|
throttleRate(_throttleRate),
|
99
|
-
ownsCstat(false)
|
124
|
+
ownsCstat(false),
|
125
|
+
configMutex(_configMutex)
|
100
126
|
{
|
101
127
|
assert(_registry.isFinalized());
|
102
128
|
if (_cstat == NULL) {
|
@@ -176,6 +202,14 @@ public:
|
|
176
202
|
char buf[PATH_MAX + 32];
|
177
203
|
const char *end = buf + sizeof(buf) - 1;
|
178
204
|
|
205
|
+
AppLocalConfigPtr appLocalConfig = getAppLocalConfigFromCache(appRoot);
|
206
|
+
|
207
|
+
if (!appLocalConfig->appStartCommand.empty()) {
|
208
|
+
Result result;
|
209
|
+
result.appStartCommand = appLocalConfig->appStartCommand;
|
210
|
+
return result;
|
211
|
+
}
|
212
|
+
|
179
213
|
WrapperRegistry::Registry::ConstIterator it(registry.getIterator());
|
180
214
|
while (*it != NULL) {
|
181
215
|
const WrapperRegistry::Entry &entry = it.getValue();
|
@@ -81,7 +81,7 @@
|
|
81
81
|
#define PASSENGER_API_VERSION_MAJOR 0
|
82
82
|
#define PASSENGER_API_VERSION_MINOR 3
|
83
83
|
#define PASSENGER_DEFAULT_USER "nobody"
|
84
|
-
#define PASSENGER_VERSION "
|
84
|
+
#define PASSENGER_VERSION "6.0.0"
|
85
85
|
#define POOL_HELPER_THREAD_STACK_SIZE 262144
|
86
86
|
#define PROCESS_SHUTDOWN_TIMEOUT 60
|
87
87
|
#define PROCESS_SHUTDOWN_TIMEOUT_DISPLAY "1 minute"
|
@@ -462,6 +462,14 @@
|
|
462
462
|
offsetof(passenger_loc_conf_t, autogenerated.startup_file),
|
463
463
|
NULL
|
464
464
|
},
|
465
|
+
{
|
466
|
+
ngx_string("passenger_app_start_command"),
|
467
|
+
NGX_HTTP_MAIN_CONF | NGX_HTTP_SRV_CONF | NGX_HTTP_LOC_CONF | NGX_HTTP_LIF_CONF | NGX_CONF_TAKE1,
|
468
|
+
passenger_conf_set_app_start_command,
|
469
|
+
NGX_HTTP_LOC_CONF_OFFSET,
|
470
|
+
offsetof(passenger_loc_conf_t, autogenerated.app_start_command),
|
471
|
+
NULL
|
472
|
+
},
|
465
473
|
{
|
466
474
|
ngx_string("passenger_restart_dir"),
|
467
475
|
NGX_HTTP_MAIN_CONF | NGX_HTTP_SRV_CONF | NGX_HTTP_LOC_CONF | NGX_HTTP_LIF_CONF | NGX_CONF_TAKE1,
|
@@ -606,6 +614,14 @@
|
|
606
614
|
offsetof(passenger_loc_conf_t, upstream_config.busy_buffers_size_conf),
|
607
615
|
NULL
|
608
616
|
},
|
617
|
+
{
|
618
|
+
ngx_string("passenger_request_buffering"),
|
619
|
+
NGX_HTTP_MAIN_CONF | NGX_HTTP_SRV_CONF | NGX_HTTP_LOC_CONF | NGX_HTTP_LIF_CONF | NGX_CONF_FLAG,
|
620
|
+
passenger_conf_set_request_buffering,
|
621
|
+
NGX_HTTP_LOC_CONF_OFFSET,
|
622
|
+
offsetof(passenger_loc_conf_t, upstream_config.request_buffering),
|
623
|
+
NULL
|
624
|
+
},
|
609
625
|
{
|
610
626
|
ngx_string("passenger_intercept_errors"),
|
611
627
|
NGX_HTTP_MAIN_CONF | NGX_HTTP_SRV_CONF | NGX_HTTP_LOC_CONF | NGX_HTTP_LIF_CONF | NGX_CONF_FLAG,
|
@@ -380,6 +380,12 @@ set_manifest_autogenerated_loc_conf_defaults(manifest_gen_ctx_t *ctx, PsgJsonVal
|
|
380
380
|
"8k|16k",
|
381
381
|
sizeof("8k|16k") - 1);
|
382
382
|
|
383
|
+
add_manifest_options_container_static_default_bool(ctx,
|
384
|
+
options_container,
|
385
|
+
"passenger_request_buffering",
|
386
|
+
sizeof("passenger_request_buffering") - 1,
|
387
|
+
1);
|
388
|
+
|
383
389
|
add_manifest_options_container_static_default_bool(ctx,
|
384
390
|
options_container,
|
385
391
|
"passenger_intercept_errors",
|
@@ -709,6 +709,18 @@ passenger_conf_set_startup_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
|
|
709
709
|
return ngx_conf_set_str_slot(cf, cmd, conf);
|
710
710
|
}
|
711
711
|
|
712
|
+
static char *
|
713
|
+
passenger_conf_set_app_start_command(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) {
|
714
|
+
passenger_loc_conf_t *passenger_conf = conf;
|
715
|
+
|
716
|
+
passenger_conf->autogenerated.app_start_command_explicitly_set = 1;
|
717
|
+
record_loc_conf_source_location(cf, passenger_conf,
|
718
|
+
&passenger_conf->autogenerated.app_start_command_source_file,
|
719
|
+
&passenger_conf->autogenerated.app_start_command_source_line);
|
720
|
+
|
721
|
+
return ngx_conf_set_str_slot(cf, cmd, conf);
|
722
|
+
}
|
723
|
+
|
712
724
|
static char *
|
713
725
|
passenger_conf_set_restart_dir(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) {
|
714
726
|
passenger_loc_conf_t *passenger_conf = conf;
|
@@ -207,6 +207,7 @@ passenger_create_loc_conf(ngx_conf_t *cf)
|
|
207
207
|
conf->upstream_config.next_upstream_tries = NGX_CONF_UNSET_UINT;
|
208
208
|
#endif
|
209
209
|
conf->upstream_config.buffering = NGX_CONF_UNSET;
|
210
|
+
conf->upstream_config.request_buffering = NGX_CONF_UNSET;
|
210
211
|
conf->upstream_config.ignore_client_abort = NGX_CONF_UNSET;
|
211
212
|
#if NGINX_VERSION_NUM >= 1007007
|
212
213
|
conf->upstream_config.force_ranges = NGX_CONF_UNSET;
|
@@ -429,6 +430,9 @@ passenger_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
|
|
429
430
|
ngx_conf_merge_value(conf->upstream_config.buffering,
|
430
431
|
prev->upstream_config.buffering, 0);
|
431
432
|
|
433
|
+
ngx_conf_merge_value(conf->upstream_config.request_buffering,
|
434
|
+
prev->upstream_config.request_buffering, 1);
|
435
|
+
|
432
436
|
ngx_conf_merge_value(conf->upstream_config.ignore_client_abort,
|
433
437
|
prev->upstream_config.ignore_client_abort, 0);
|
434
438
|
|
@@ -1141,6 +1145,22 @@ passenger_enabled(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
|
|
1141
1145
|
return NGX_CONF_OK;
|
1142
1146
|
}
|
1143
1147
|
|
1148
|
+
static char *
|
1149
|
+
passenger_conf_set_request_buffering(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) {
|
1150
|
+
#ifdef NGINX_NO_SEND_REQUEST_BODY_INFINITE_LOOP_BUG
|
1151
|
+
passenger_loc_conf_t *passenger_conf = conf;
|
1152
|
+
|
1153
|
+
passenger_conf->autogenerated.upstream_config_request_buffering_explicitly_set = 1;
|
1154
|
+
record_loc_conf_source_location(cf, passenger_conf,
|
1155
|
+
&passenger_conf->autogenerated.upstream_config_request_buffering_source_file,
|
1156
|
+
&passenger_conf->autogenerated.upstream_config_request_buffering_source_line);
|
1157
|
+
|
1158
|
+
return ngx_conf_set_flag_slot(cf, cmd, conf);
|
1159
|
+
#else
|
1160
|
+
return "config cannot be set in Nginx < 1.15.3 due to this bug: https://trac.nginx.org/nginx/ticket/1618";
|
1161
|
+
#endif /* NGINX_NO_SEND_REQUEST_BODY_INFINITE_LOOP_BUG */
|
1162
|
+
}
|
1163
|
+
|
1144
1164
|
static char *
|
1145
1165
|
rails_framework_spawner_idle_time(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
|
1146
1166
|
{
|
@@ -1,7 +1,7 @@
|
|
1
1
|
/*
|
2
2
|
* Copyright (C) Igor Sysoev
|
3
3
|
* Copyright (C) 2007 Manlio Perillo (manlio.perillo@gmail.com)
|
4
|
-
* Copyright (c) 2010-
|
4
|
+
* Copyright (c) 2010-2018 Phusion Holding B.V.
|
5
5
|
*
|
6
6
|
* Redistribution and use in source and binary forms, with or without
|
7
7
|
* modification, are permitted provided that the following conditions
|
@@ -331,6 +331,179 @@ header_is_transfer_encoding(ngx_str_t *key)
|
|
331
331
|
ngx_strncasecmp(key->data + 1, (u_char *) "ransfer-encodin", sizeof("ransfer-encodin") - 1) == 0;
|
332
332
|
}
|
333
333
|
|
334
|
+
/* Given an ngx_chain_t head and tail position, appends a new chain element at the end,
|
335
|
+
* updates the head (if necessary) and returns the new element.
|
336
|
+
*
|
337
|
+
* - The element is allocated from a freelist.
|
338
|
+
* - Ensures that the element contains a buffer of at least `size` bytes.
|
339
|
+
* - Sets the given tag on the buffer in the chain element.
|
340
|
+
*
|
341
|
+
* On error, returns NULL without modifying the given chain.
|
342
|
+
*/
|
343
|
+
static ngx_chain_t *
|
344
|
+
append_ngx_chain_element(ngx_pool_t *p, ngx_chain_t **head,
|
345
|
+
ngx_chain_t *tail, ngx_chain_t **freelist, ngx_buf_tag_t tag, size_t size)
|
346
|
+
{
|
347
|
+
ngx_chain_t *elem;
|
348
|
+
ngx_buf_t *buf;
|
349
|
+
|
350
|
+
elem = ngx_chain_get_free_buf(p, freelist);
|
351
|
+
if (elem == NULL) {
|
352
|
+
return NULL;
|
353
|
+
}
|
354
|
+
|
355
|
+
buf = elem->buf;
|
356
|
+
buf->tag = tag;
|
357
|
+
|
358
|
+
if (size > 0 && (buf->pos == NULL || buf->last == NULL
|
359
|
+
|| (size_t) ngx_buf_size(buf) < size))
|
360
|
+
{
|
361
|
+
ngx_memzero(buf, sizeof(ngx_buf_t));
|
362
|
+
|
363
|
+
buf->start = ngx_palloc(p, size);
|
364
|
+
if (buf->start == NULL) {
|
365
|
+
return NULL;
|
366
|
+
}
|
367
|
+
|
368
|
+
/*
|
369
|
+
* set by ngx_memzero():
|
370
|
+
*
|
371
|
+
* b->file_pos = 0;
|
372
|
+
* b->file_last = 0;
|
373
|
+
* b->file = NULL;
|
374
|
+
* b->shadow = NULL;
|
375
|
+
* b->tag = 0;
|
376
|
+
* and flags
|
377
|
+
*/
|
378
|
+
|
379
|
+
buf->pos = buf->start;
|
380
|
+
buf->last = buf->start;
|
381
|
+
buf->end = buf->last + size;
|
382
|
+
buf->temporary = 1;
|
383
|
+
}
|
384
|
+
|
385
|
+
if (*head == NULL) {
|
386
|
+
*head = elem;
|
387
|
+
} else {
|
388
|
+
tail->next = elem;
|
389
|
+
}
|
390
|
+
return elem;
|
391
|
+
}
|
392
|
+
|
393
|
+
/* Given a chain of buffers containing client body data,
|
394
|
+
* this filter wraps all that data into chunked encoding
|
395
|
+
* headers and footers.
|
396
|
+
*/
|
397
|
+
static ngx_int_t
|
398
|
+
body_rechunk_output_filter(void *data, ngx_chain_t *input)
|
399
|
+
{
|
400
|
+
ngx_http_request_t *r = data;
|
401
|
+
ngx_chain_t *output_head = NULL, *output_tail = NULL;
|
402
|
+
ngx_int_t body_eof_reached = 0;
|
403
|
+
ngx_int_t rc;
|
404
|
+
passenger_context_t *ctx;
|
405
|
+
|
406
|
+
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
407
|
+
PROGRAM_NAME " rechunk output filter");
|
408
|
+
|
409
|
+
ctx = ngx_http_get_module_ctx(r, ngx_http_passenger_module);
|
410
|
+
|
411
|
+
if (input == NULL) {
|
412
|
+
goto out;
|
413
|
+
}
|
414
|
+
|
415
|
+
if (!ctx->header_sent) {
|
416
|
+
/* The first buffer contains the request header, so pass it unmodified. */
|
417
|
+
ctx->header_sent = 1;
|
418
|
+
|
419
|
+
while (input != NULL) {
|
420
|
+
output_tail = append_ngx_chain_element(r->pool,
|
421
|
+
&output_head, output_tail, &ctx->free,
|
422
|
+
(ngx_buf_tag_t) &body_rechunk_output_filter,
|
423
|
+
0);
|
424
|
+
if (output_tail == NULL) {
|
425
|
+
return NGX_ERROR;
|
426
|
+
}
|
427
|
+
|
428
|
+
ngx_memcpy(output_tail->buf, input->buf, sizeof(ngx_buf_t));
|
429
|
+
|
430
|
+
body_eof_reached = input->buf->last_buf;
|
431
|
+
input = input->next;
|
432
|
+
}
|
433
|
+
} else {
|
434
|
+
while (input != NULL) {
|
435
|
+
/* Append chunked encoding size header */
|
436
|
+
output_tail = append_ngx_chain_element(r->pool,
|
437
|
+
&output_head, output_tail, &ctx->free,
|
438
|
+
(ngx_buf_tag_t) &body_rechunk_output_filter,
|
439
|
+
32);
|
440
|
+
if (output_tail == NULL) {
|
441
|
+
return NGX_ERROR;
|
442
|
+
}
|
443
|
+
|
444
|
+
output_tail->buf->last = ngx_sprintf(output_tail->buf->last, "%xO\r\n",
|
445
|
+
ngx_buf_size(input->buf));
|
446
|
+
|
447
|
+
|
448
|
+
/* Append chunked encoding payload */
|
449
|
+
output_tail = append_ngx_chain_element(r->pool,
|
450
|
+
&output_head, output_tail, &ctx->free,
|
451
|
+
(ngx_buf_tag_t) &body_rechunk_output_filter,
|
452
|
+
0);
|
453
|
+
if (output_tail == NULL) {
|
454
|
+
return NGX_ERROR;
|
455
|
+
}
|
456
|
+
|
457
|
+
ngx_memcpy(output_tail->buf, input->buf, sizeof(ngx_buf_t));
|
458
|
+
|
459
|
+
|
460
|
+
/* Append chunked encoding footer */
|
461
|
+
output_tail = append_ngx_chain_element(r->pool,
|
462
|
+
&output_head, output_tail, &ctx->free,
|
463
|
+
(ngx_buf_tag_t) &body_rechunk_output_filter,
|
464
|
+
2);
|
465
|
+
if (output_tail == NULL) {
|
466
|
+
return NGX_ERROR;
|
467
|
+
}
|
468
|
+
|
469
|
+
output_tail->buf->last = ngx_copy(output_tail->buf->last, "\r\n", 2);
|
470
|
+
|
471
|
+
|
472
|
+
body_eof_reached = input->buf->last_buf;
|
473
|
+
input = input->next;
|
474
|
+
}
|
475
|
+
}
|
476
|
+
|
477
|
+
if (body_eof_reached) {
|
478
|
+
/* Append final termination chunk. */
|
479
|
+
output_tail = append_ngx_chain_element(r->pool,
|
480
|
+
&output_head, output_tail, &ctx->free,
|
481
|
+
(ngx_buf_tag_t) &body_rechunk_output_filter,
|
482
|
+
5);
|
483
|
+
if (output_tail == NULL) {
|
484
|
+
return NGX_ERROR;
|
485
|
+
}
|
486
|
+
|
487
|
+
output_tail->buf->last = ngx_copy(output_tail->buf->last,
|
488
|
+
"0\r\n\r\n", 5);
|
489
|
+
}
|
490
|
+
|
491
|
+
out:
|
492
|
+
|
493
|
+
rc = ngx_chain_writer(&r->upstream->writer, output_head);
|
494
|
+
|
495
|
+
/*
|
496
|
+
* The previous ngx_chain_writer() call consumed some buffers.
|
497
|
+
* Find such consumped (empty) buffers in the output buffer list,
|
498
|
+
* and either free them or add them to the freelist depending on
|
499
|
+
* whether the buffer's tag matches ours.
|
500
|
+
*/
|
501
|
+
ngx_chain_update_chains(r->pool, &ctx->free, &ctx->busy, &output_head,
|
502
|
+
(ngx_buf_tag_t) &body_rechunk_output_filter);
|
503
|
+
|
504
|
+
return rc;
|
505
|
+
}
|
506
|
+
|
334
507
|
#define SET_NGX_STR(str, the_data) \
|
335
508
|
do { \
|
336
509
|
(str)->data = (u_char *) the_data; \
|
@@ -346,15 +519,25 @@ header_is_transfer_encoding(ngx_str_t *key)
|
|
346
519
|
typedef struct {
|
347
520
|
ngx_str_t method; /* Includes trailing space */
|
348
521
|
ngx_str_t app_type;
|
522
|
+
ngx_str_t app_start_command;
|
349
523
|
ngx_str_t escaped_uri;
|
350
|
-
ngx_str_t content_length;
|
524
|
+
ngx_str_t content_length; /* Only used if !r->request_body_no_buffering */
|
351
525
|
ngx_str_t core_password;
|
352
526
|
ngx_str_t remote_port;
|
353
527
|
} buffer_construction_state;
|
354
528
|
|
529
|
+
/* prepare_request_buffer_construction() and construct_request_buffer() are
|
530
|
+
* used to create an HTTP request header buffer to be sent to the Core Controller.
|
531
|
+
*
|
532
|
+
* construct_request_buffer() is actually called twice: the first time in "no-op" mode to
|
533
|
+
* calculate how many bytes it must allocate, and the second time to actually create the
|
534
|
+
* buffer. For efficiency reasons, as much preparation work as possible is split into
|
535
|
+
* the prepare_request_buffer_construction() function so that the two construct_request_buffer()
|
536
|
+
* calls don't have to perform that work twice.
|
537
|
+
*/
|
355
538
|
static ngx_int_t
|
356
|
-
prepare_request_buffer_construction(ngx_http_request_t *r,
|
357
|
-
buffer_construction_state *state)
|
539
|
+
prepare_request_buffer_construction(ngx_http_request_t *r, passenger_loc_conf_t *slcf,
|
540
|
+
passenger_context_t *context, buffer_construction_state *state)
|
358
541
|
{
|
359
542
|
unsigned int len;
|
360
543
|
ngx_uint_t port;
|
@@ -364,6 +547,7 @@ prepare_request_buffer_construction(ngx_http_request_t *r, passenger_context_t *
|
|
364
547
|
#endif
|
365
548
|
const PsgWrapperRegistryEntry *wrapper_registry_entry;
|
366
549
|
|
550
|
+
/* Construct HTTP method string, including trailing space. */
|
367
551
|
switch (r->method) {
|
368
552
|
case NGX_HTTP_GET:
|
369
553
|
SET_NGX_STR(&state->method, "GET ");
|
@@ -415,10 +599,28 @@ prepare_request_buffer_construction(ngx_http_request_t *r, passenger_context_t *
|
|
415
599
|
break;
|
416
600
|
}
|
417
601
|
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
602
|
+
if (slcf->autogenerated.app_start_command.data != NULL) {
|
603
|
+
/* The config specified that this is either a generic app or a Kuria app. */
|
604
|
+
state->app_type.data = NULL;
|
605
|
+
state->app_type.len = 0;
|
606
|
+
state->app_start_command = slcf->autogenerated.app_start_command;
|
607
|
+
} else {
|
608
|
+
wrapper_registry_entry = psg_app_type_detector_result_get_wrapper_registry_entry(
|
609
|
+
context->detector_result);
|
610
|
+
if (wrapper_registry_entry != NULL) {
|
611
|
+
/* This is an auto-supported app. */
|
612
|
+
state->app_type.data = (u_char *) psg_wrapper_registry_entry_get_language(wrapper_registry_entry,
|
613
|
+
&state->app_type.len);
|
614
|
+
state->app_start_command.data = NULL;
|
615
|
+
state->app_start_command.len = 0;
|
616
|
+
} else {
|
617
|
+
/* This has been autodetected to be a generic app or a Kuria app. */
|
618
|
+
state->app_type.data = NULL;
|
619
|
+
state->app_type.len = 0;
|
620
|
+
state->app_start_command.data = (u_char *) psg_app_type_detector_result_get_app_start_command(
|
621
|
+
context->detector_result, &state->app_start_command.len);
|
622
|
+
}
|
623
|
+
}
|
422
624
|
|
423
625
|
/*
|
424
626
|
* Nginx unescapes URI's before passing them to Phusion Passenger,
|
@@ -446,7 +648,7 @@ prepare_request_buffer_construction(ngx_http_request_t *r, passenger_context_t *
|
|
446
648
|
NGX_ESCAPE_URI);
|
447
649
|
}
|
448
650
|
|
449
|
-
if (r->headers_in.chunked) {
|
651
|
+
if (r->headers_in.chunked && !r->request_body_no_buffering) {
|
450
652
|
/* If the request body is chunked, then Nginx sets r->headers_in.content_length_n
|
451
653
|
* but does not set r->headers_in.headers, so we add this header ourselves.
|
452
654
|
*/
|
@@ -495,6 +697,7 @@ prepare_request_buffer_construction(ngx_http_request_t *r, passenger_context_t *
|
|
495
697
|
return NGX_OK;
|
496
698
|
}
|
497
699
|
|
700
|
+
/* See comment for prepare_request_buffer_construction() */
|
498
701
|
static ngx_uint_t
|
499
702
|
construct_request_buffer(ngx_http_request_t *r, passenger_loc_conf_t *slcf,
|
500
703
|
passenger_context_t *context, buffer_construction_state *state, ngx_buf_t *b)
|
@@ -554,7 +757,7 @@ construct_request_buffer(ngx_http_request_t *r, passenger_loc_conf_t *slcf,
|
|
554
757
|
|
555
758
|
if (ngx_hash_find(&slcf->headers_set_hash, header[i].hash,
|
556
759
|
header[i].lowcase_key, header[i].key.len)
|
557
|
-
|| header_is_transfer_encoding(&header[i].key))
|
760
|
+
|| (!r->request_body_no_buffering && header_is_transfer_encoding(&header[i].key)))
|
558
761
|
{
|
559
762
|
continue;
|
560
763
|
}
|
@@ -568,7 +771,7 @@ construct_request_buffer(ngx_http_request_t *r, passenger_loc_conf_t *slcf,
|
|
568
771
|
total_size += header[i].key.len + header[i].value.len + 4;
|
569
772
|
}
|
570
773
|
|
571
|
-
if (r->headers_in.chunked) {
|
774
|
+
if (r->headers_in.chunked && !r->request_body_no_buffering) {
|
572
775
|
PUSH_STATIC_STR("Content-Length: ");
|
573
776
|
if (b != NULL) {
|
574
777
|
b->last = ngx_copy(b->last, state->content_length.data,
|
@@ -756,13 +959,23 @@ construct_request_buffer(ngx_http_request_t *r, passenger_loc_conf_t *slcf,
|
|
756
959
|
PUSH_STATIC_STR("\r\n");
|
757
960
|
}
|
758
961
|
|
759
|
-
|
760
|
-
|
761
|
-
|
762
|
-
state->app_type.
|
962
|
+
if (state->app_type.len > 0) {
|
963
|
+
PUSH_STATIC_STR("!~PASSENGER_APP_TYPE: ");
|
964
|
+
if (b != NULL) {
|
965
|
+
b->last = ngx_copy(b->last, state->app_type.data,
|
966
|
+
state->app_type.len);
|
967
|
+
}
|
968
|
+
total_size += state->app_type.len;
|
969
|
+
PUSH_STATIC_STR("\r\n");
|
970
|
+
} else {
|
971
|
+
PUSH_STATIC_STR("!~PASSENGER_APP_START_COMMAND: ");
|
972
|
+
if (b != NULL) {
|
973
|
+
b->last = ngx_copy(b->last, state->app_start_command.data,
|
974
|
+
state->app_start_command.len);
|
975
|
+
}
|
976
|
+
total_size += state->app_start_command.len;
|
977
|
+
PUSH_STATIC_STR("\r\n");
|
763
978
|
}
|
764
|
-
total_size += state->app_type.len;
|
765
|
-
PUSH_STATIC_STR("\r\n");
|
766
979
|
|
767
980
|
if (b != NULL) {
|
768
981
|
b->last = ngx_copy(b->last, slcf->options_cache.data, slcf->options_cache.len);
|
@@ -816,7 +1029,7 @@ create_request(ngx_http_request_t *r)
|
|
816
1029
|
|
817
1030
|
/* Construct and pass request headers */
|
818
1031
|
|
819
|
-
if (prepare_request_buffer_construction(r, context, &state) != NGX_OK) {
|
1032
|
+
if (prepare_request_buffer_construction(r, slcf, context, &state) != NGX_OK) {
|
820
1033
|
return NGX_ERROR;
|
821
1034
|
}
|
822
1035
|
request_size = construct_request_buffer(r, slcf, context, &state, NULL);
|
@@ -825,20 +1038,45 @@ create_request(ngx_http_request_t *r)
|
|
825
1038
|
if (b == NULL) {
|
826
1039
|
return NGX_ERROR;
|
827
1040
|
}
|
1041
|
+
construct_request_buffer(r, slcf, context, &state, b);
|
1042
|
+
|
828
1043
|
cl = ngx_alloc_chain_link(r->pool);
|
829
1044
|
if (cl == NULL) {
|
830
1045
|
return NGX_ERROR;
|
831
1046
|
}
|
832
1047
|
cl->buf = b;
|
833
1048
|
|
834
|
-
construct_request_buffer(r, slcf, context, &state, b);
|
835
1049
|
|
836
|
-
/* Pass request body
|
1050
|
+
/* Pass already received request body buffers. Make sure they come
|
1051
|
+
* after the request header buffer we just constructed.
|
1052
|
+
*/
|
837
1053
|
|
838
1054
|
body = r->upstream->request_bufs;
|
839
1055
|
r->upstream->request_bufs = cl;
|
840
1056
|
|
841
1057
|
while (body) {
|
1058
|
+
if (r->headers_in.chunked && r->request_body_no_buffering) {
|
1059
|
+
/* If Transfer-Encoding is chunked, then Nginx dechunks the body.
|
1060
|
+
* If at the same time request body buffering is disabled, then
|
1061
|
+
* we pass the Transfer-Encoding header to the Passenger Core,
|
1062
|
+
* and thus we also need to ensure we rechunk the body.
|
1063
|
+
*/
|
1064
|
+
b = ngx_create_temp_buf(r->pool, 32);
|
1065
|
+
if (b == NULL) {
|
1066
|
+
return NGX_ERROR;
|
1067
|
+
}
|
1068
|
+
|
1069
|
+
b->last = ngx_sprintf(b->last, "%xO\r\n",
|
1070
|
+
ngx_buf_size(body->buf));
|
1071
|
+
cl->next = ngx_alloc_chain_link(r->pool);
|
1072
|
+
if (cl->next == NULL) {
|
1073
|
+
return NGX_ERROR;
|
1074
|
+
}
|
1075
|
+
|
1076
|
+
cl = cl->next;
|
1077
|
+
cl->buf = b;
|
1078
|
+
}
|
1079
|
+
|
842
1080
|
b = ngx_alloc_buf(r->pool);
|
843
1081
|
if (b == NULL) {
|
844
1082
|
return NGX_ERROR;
|
@@ -850,15 +1088,41 @@ create_request(ngx_http_request_t *r)
|
|
850
1088
|
if (cl->next == NULL) {
|
851
1089
|
return NGX_ERROR;
|
852
1090
|
}
|
853
|
-
|
854
1091
|
cl = cl->next;
|
855
1092
|
cl->buf = b;
|
856
1093
|
|
857
1094
|
body = body->next;
|
1095
|
+
|
1096
|
+
if (r->headers_in.chunked && r->request_body_no_buffering) {
|
1097
|
+
b = ngx_create_temp_buf(r->pool, 2);
|
1098
|
+
if (b == NULL) {
|
1099
|
+
return NGX_ERROR;
|
1100
|
+
}
|
1101
|
+
|
1102
|
+
b->last = ngx_copy(b->last, "\r\n", 2);
|
1103
|
+
cl->next = ngx_alloc_chain_link(r->pool);
|
1104
|
+
if (cl->next == NULL) {
|
1105
|
+
return NGX_ERROR;
|
1106
|
+
}
|
1107
|
+
|
1108
|
+
cl = cl->next;
|
1109
|
+
cl->buf = b;
|
1110
|
+
}
|
858
1111
|
}
|
1112
|
+
|
859
1113
|
b->flush = 1;
|
860
1114
|
cl->next = NULL;
|
861
1115
|
|
1116
|
+
/* Again, if Transfer-Encoding is chunked, then Nginx dechunks the body.
|
1117
|
+
* Here we install an output filter to make sure that the request body parts
|
1118
|
+
* that will be received in the future, will also be rechunked when passed
|
1119
|
+
* to the Passenger Core.
|
1120
|
+
*/
|
1121
|
+
if (r->headers_in.chunked && r->request_body_no_buffering) {
|
1122
|
+
r->upstream->output.output_filter = body_rechunk_output_filter;
|
1123
|
+
r->upstream->output.filter_ctx = r;
|
1124
|
+
}
|
1125
|
+
|
862
1126
|
return NGX_OK;
|
863
1127
|
}
|
864
1128
|
|
@@ -1467,7 +1731,15 @@ passenger_content_handler(ngx_http_request_t *r)
|
|
1467
1731
|
detector_result_cleanup->handler = cleanup_detector_result;
|
1468
1732
|
detector_result_cleanup->data = context->detector_result;
|
1469
1733
|
|
1470
|
-
|
1734
|
+
/* If `app_start_command` is set, then it means the config specified that it is
|
1735
|
+
* either a generic app or a Kuria app.
|
1736
|
+
*/
|
1737
|
+
if (slcf->autogenerated.app_start_command.data == NULL
|
1738
|
+
&& slcf->autogenerated.app_type.data == NULL)
|
1739
|
+
{
|
1740
|
+
/* If neither `app_start_command` nor `app_type` are set, then
|
1741
|
+
* autodetect what kind of app this is.
|
1742
|
+
*/
|
1471
1743
|
pp_error_init(&error);
|
1472
1744
|
if (slcf->autogenerated.app_root.data == NULL) {
|
1473
1745
|
psg_app_type_detector_check_document_root(
|
@@ -1502,7 +1774,11 @@ passenger_content_handler(ngx_http_request_t *r)
|
|
1502
1774
|
pp_error_destroy(&error);
|
1503
1775
|
return NGX_HTTP_INTERNAL_SERVER_ERROR;
|
1504
1776
|
}
|
1505
|
-
} else {
|
1777
|
+
} else if (slcf->autogenerated.app_start_command.data == NULL) {
|
1778
|
+
/* If `app_start_command` is not set but `app_type` is, then
|
1779
|
+
* verify whether the given `app_type` value is supported
|
1780
|
+
* and resolve aliases.
|
1781
|
+
*/
|
1506
1782
|
wrapper_registry_entry = psg_wrapper_registry_lookup(psg_wrapper_registry,
|
1507
1783
|
(const char *) slcf->autogenerated.app_type.data,
|
1508
1784
|
slcf->autogenerated.app_type.len);
|
@@ -1547,6 +1823,8 @@ passenger_content_handler(ngx_http_request_t *r)
|
|
1547
1823
|
u->pipe->input_filter = ngx_event_pipe_copy_input_filter;
|
1548
1824
|
u->pipe->input_ctx = r;
|
1549
1825
|
|
1826
|
+
r->request_body_no_buffering = !slcf->upstream_config.request_buffering;
|
1827
|
+
|
1550
1828
|
rc = ngx_http_read_client_request_body(r, ngx_http_upstream_init);
|
1551
1829
|
|
1552
1830
|
fix_peer_address(r);
|