PageRenderTime 4ms CodeModel.GetById 673ms app.highlight 504ms RepoModel.GetById 670ms app.codeStats 0ms

/ext/common/agents/HelperAgent/OptionParser.h

http://github.com/FooBarWidget/passenger
C++ Header | 378 lines | 335 code | 12 blank | 31 comment | 104 complexity | 26f3d4d296bf529246bca5441b53d8bf MD5 | raw file
  1/*
  2 *  Phusion Passenger - https://www.phusionpassenger.com/
  3 *  Copyright (c) 2010-2015 Phusion
  4 *
  5 *  "Phusion Passenger" is a trademark of Hongli Lai & Ninh Bui.
  6 *
  7 *  Permission is hereby granted, free of charge, to any person obtaining a copy
  8 *  of this software and associated documentation files (the "Software"), to deal
  9 *  in the Software without restriction, including without limitation the rights
 10 *  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 11 *  copies of the Software, and to permit persons to whom the Software is
 12 *  furnished to do so, subject to the following conditions:
 13 *
 14 *  The above copyright notice and this permission notice shall be included in
 15 *  all copies or substantial portions of the Software.
 16 *
 17 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 18 *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 19 *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 20 *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 21 *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 22 *  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 23 *  THE SOFTWARE.
 24 */
 25#ifndef _PASSENGER_SERVER_OPTION_PARSER_H_
 26#define _PASSENGER_SERVER_OPTION_PARSER_H_
 27
 28#include <boost/thread.hpp>
 29#include <cstdio>
 30#include <cstdlib>
 31#include <Constants.h>
 32#include <Utils.h>
 33#include <Utils/VariantMap.h>
 34#include <Utils/OptionParsing.h>
 35#include <Utils/StrIntUtils.h>
 36
 37namespace Passenger {
 38
 39using namespace std;
 40
 41
 42inline void
 43serverUsage() {
 44	// ....|---------------Keep output within standard terminal width (80 chars)------------|
 45	printf("Usage: " AGENT_EXE " server <OPTIONS...> [APP DIRECTORY]\n");
 46	printf("Runs the " PROGRAM_NAME " standalone HTTP server agent.\n");
 47	printf("\n");
 48	printf("The server starts in single-app mode, unless --multi-app is specified. When\n");
 49	printf("in single-app mode, it serves the app at the current working directory, or the\n");
 50	printf("app specified by APP DIRECTORY.\n");
 51	printf("\n");
 52	printf("Required options:\n");
 53	printf("      --passenger-root PATH  The location to the " PROGRAM_NAME " source\n");
 54	printf("                             directory\n");
 55	printf("\n");
 56	printf("Socket options (optional):\n");
 57	printf("  -l, --listen ADDRESS      Listen on the given address. The address must be\n");
 58	printf("                            formatted as tcp://IP:PORT for TCP sockets, or\n");
 59	printf("                            unix:PATH for Unix domain sockets. You can specify\n");
 60	printf("                            this option multiple times (up to %u times) to\n",
 61		SERVER_KIT_MAX_SERVER_ENDPOINTS);
 62	printf("                            listen on multiple addresses. Default:\n");
 63	printf("                            " DEFAULT_HTTP_SERVER_LISTEN_ADDRESS "\n");
 64	printf("      --admin-listen ADDRESS\n");
 65	printf("                            Listen on the given address for admin commands.\n");
 66	printf("                            The same syntax and limitations as with --listen\n");
 67	printf("                            are applicable\n");
 68	printf("\n");
 69	printf("Daemon options (optional):\n");
 70	printf("      --pid-file PATH       Store the server's PID in the given file. The file\n");
 71	printf("                            is deleted on exit\n");
 72	printf("\n");
 73	printf("Security options (optional):\n");
 74	printf("      --multi-app-password-file PATH\n");
 75	printf("                            Password-protect access to the HTTP server\n");
 76	printf("                            (multi-app mode only)\n");
 77	printf("      --authorize [LEVEL]:USERNAME:PASSWORDFILE\n");
 78	printf("                            Enables authentication on the admin server, through\n");
 79	printf("                            the given admin account. LEVEL indicates the\n");
 80	printf("                            privilege level (see below). PASSWORDFILE must\n");
 81	printf("                            point to a file containing the password\n");
 82	printf("      --no-user-switching   Disables user switching support\n");
 83	printf("      --default-user NAME   Default user to start apps as, when user\n");
 84	printf("                            switching is enabled. Default: " DEFAULT_WEB_APP_USER "\n");
 85	printf("      --default-group NAME  Default group to start apps as, when user\n");
 86	printf("                            switching is disabled. Default: the default\n");
 87	printf("                            user's primary group\n");
 88	printf("\n");
 89	printf("Application serving options (optional):\n");
 90	printf("  -e, --environment NAME    Default framework environment name to use.\n");
 91	printf("                            Default: " DEFAULT_APP_ENV "\n");
 92	printf("      --app-type TYPE       The type of application you want to serve\n");
 93	printf("                            (single-app mode only)\n");
 94	printf("      --startup-file PATH   The path of the app's startup file, relative to\n");
 95	printf("                            the app root directory (single-app mode only)\n");
 96	printf("      --spawn-method NAME   Spawn method to use. Can either be 'smart' or\n");
 97	printf("                            'direct'. Default: %s\n", DEFAULT_SPAWN_METHOD);
 98	printf("      --load-shell-envvars  Load shell startup files before loading application\n");
 99	printf("      --concurrency-model   The concurrency model to use for the app, either\n");
100	printf("                            'process' or 'thread' (Enterprise only).\n");
101	printf("                            Default: " DEFAULT_CONCURRENCY_MODEL "\n");
102	printf("      --app-thread-count    The number of application threads to use when using\n");
103	printf("                            the 'thread' concurrency model (Enterprise only).\n");
104	printf("                            Default: %d\n", DEFAULT_APP_THREAD_COUNT);
105	printf("\n");
106	printf("      --multi-app           Enable multi-app mode\n");
107	printf("\n");
108	printf("      --force-friendly-error-pages\n");
109	printf("                            Force friendly error pages to be always on\n");
110	printf("      --disable-friendly-error-pages\n");
111	printf("                            Force friendly error pages to be always off\n");
112	printf("\n");
113	printf("      --ruby PATH           Default Ruby interpreter to use.\n");
114	printf("      --nodejs PATH         Default NodeJs interpreter to use.\n");
115	printf("      --python PATH         Default Python interpreter to use.\n");
116	printf("      --meteor-app-settings PATH\n");
117	printf("                            File with settings for a Meteor (non-bundled) app.\n");
118	printf("                            (passed to Meteor using --settings)\n");
119	printf("      --debugger            Enable Ruby debugger support (Enterprise only)\n");
120	printf("\n");
121	printf("      --rolling-restarts    Enable rolling restarts (Enterprise only)\n");
122	printf("      --resist-deployment-errors\n");
123	printf("                            Enable deployment error resistance (Enterprise only)\n");
124	printf("\n");
125	printf("Process management options (optional):\n");
126	printf("      --max-pool-size N     Maximum number of application processes.\n");
127	printf("                            Default: %d\n", DEFAULT_MAX_POOL_SIZE);
128	printf("      --pool-idle-time SECS\n");
129	printf("                            Maximum number of seconds an application process\n");
130	printf("                            may be idle. Default: %d\n", DEFAULT_POOL_IDLE_TIME);
131	printf("      --min-instances N     Minimum number of application processes. Default: 1\n");
132	printf("\n");
133	printf("Request handling options (optional):\n");
134	printf("      --max-request-time    Abort requests that take too much time (Enterprise\n");
135	printf("                            only)\n");
136	printf("      --sticky-sessions     Enable sticky sessions\n");
137	printf("      --sticky-sessions-cookie-name NAME\n");
138	printf("                            Cookie name to use for sticky sessions.\n");
139	printf("                            Default: " DEFAULT_STICKY_SESSIONS_COOKIE_NAME "\n");
140	printf("      --vary-turbocache-by-cookie NAME\n");
141	printf("                            Vary the turbocache by the cookie of the given name\n");
142	printf("      --disable-turbocaching\n");
143	printf("                            Disable turbocaching\n");
144	printf("\n");
145	printf("Other options (optional):\n");
146	printf("      --log-file PATH       Log to the given file.\n");
147	printf("      --log-level LEVEL     Logging level. Default: %d\n", DEFAULT_LOG_LEVEL);
148	printf("      --fd-log-file PATH    Log file descriptor activity to the given file.\n");
149	printf("      --stat-throttle-rate SECONDS\n");
150	printf("                            Throttle filesystem restart.txt checks to at most\n");
151	printf("                            once per given seconds. Default: %d\n", DEFAULT_STAT_THROTTLE_RATE);
152	printf("      --no-show-version-in-header\n");
153	printf("                            Do not show " PROGRAM_NAME " version number in\n");
154	printf("                            HTTP headers.\n");
155	printf("      --data-buffer-dir PATH\n");
156	printf("                            Directory to store data buffers in. Default:\n");
157	printf("                            %s\n", getSystemTempDir());
158	printf("      --no-graceful-exit    When exiting, exit immediately instead of waiting\n");
159	printf("                            for all connections to terminate\n");
160	printf("      --benchmark MODE      Enable benchmark mode. Available modes:\n");
161	printf("                            after_accept,before_checkout,after_checkout,\n");
162	printf("                            response_begin\n");
163	printf("      --disable-selfchecks  Disable various self-checks. This improves\n");
164	printf("                            performance, but might delay finding bugs in\n");
165	printf("                            " PROGRAM_NAME "\n");
166	printf("      --threads NUMBER      Number of threads to use for request handling.\n");
167	printf("                            Default: number of CPU cores (%d)\n",
168		boost::thread::hardware_concurrency());
169	printf("      --cpu-affine          Enable per-thread CPU affinity (Linux only)\n");
170	printf("  -h, --help                Show this help\n");
171	printf("\n");
172	printf("Admin account privilege levels (ordered from most to least privileges):\n");
173	printf("  readonly    Read-only access\n");
174	printf("  full        Full access (default)\n");
175}
176
177inline bool
178parseServerOption(int argc, const char *argv[], int &i, VariantMap &options) {
179	OptionParser p(serverUsage);
180
181	if (p.isValueFlag(argc, i, argv[i], '\0', "--passenger-root")) {
182		options.set("passenger_root", argv[i + 1]);
183		i += 2;
184	} else if (p.isValueFlag(argc, i, argv[i], 'l', "--listen")) {
185		if (getSocketAddressType(argv[i + 1]) != SAT_UNKNOWN) {
186			vector<string> addresses = options.getStrSet("server_addresses", false);
187			if (addresses.size() == SERVER_KIT_MAX_SERVER_ENDPOINTS) {
188				fprintf(stderr, "ERROR: you may specify up to %u --listen addresses.\n",
189					SERVER_KIT_MAX_SERVER_ENDPOINTS);
190				exit(1);
191			}
192			addresses.push_back(argv[i + 1]);
193			options.setStrSet("server_addresses", addresses);
194			i += 2;
195		} else {
196			fprintf(stderr, "ERROR: invalid address format for --listen. The address "
197				"must be formatted as tcp://IP:PORT for TCP sockets, or unix:PATH "
198				"for Unix domain sockets.\n");
199			exit(1);
200		}
201	} else if (p.isValueFlag(argc, i, argv[i], '\0', "--admin-listen")) {
202		if (getSocketAddressType(argv[i + 1]) != SAT_UNKNOWN) {
203			vector<string> addresses = options.getStrSet("server_admin_addresses",
204				false);
205			if (addresses.size() == SERVER_KIT_MAX_SERVER_ENDPOINTS) {
206				fprintf(stderr, "ERROR: you may specify up to %u --admin-listen addresses.\n",
207					SERVER_KIT_MAX_SERVER_ENDPOINTS);
208				exit(1);
209			}
210			addresses.push_back(argv[i + 1]);
211			options.setStrSet("server_admin_addresses", addresses);
212			i += 2;
213		} else {
214			fprintf(stderr, "ERROR: invalid address format for --admin-listen. The address "
215				"must be formatted as tcp://IP:PORT for TCP sockets, or unix:PATH "
216				"for Unix domain sockets.\n");
217			exit(1);
218		}
219	} else if (p.isValueFlag(argc, i, argv[i], '\0', "--pid-file")) {
220		options.set("server_pid_file", argv[i + 1]);
221		i += 2;
222	} else if (p.isValueFlag(argc, i, argv[i], '\0', "--authorize")) {
223		vector<string> args;
224		vector<string> authorizations = options.getStrSet("server_authorizations",
225				false);
226
227		split(argv[i + 1], ':', args);
228		if (args.size() < 2 || args.size() > 3) {
229			fprintf(stderr, "ERROR: invalid format for --authorize. The syntax "
230				"is \"[LEVEL:]USERNAME:PASSWORDFILE\".\n");
231			exit(1);
232		}
233
234		authorizations.push_back(argv[i + 1]);
235		options.setStrSet("server_authorizations", authorizations);
236		i += 2;
237	} else if (p.isFlag(argv[i], '\0', "--no-user-switching")) {
238		options.setBool("user_switching", false);
239		i++;
240	} else if (p.isValueFlag(argc, i, argv[i], '\0', "--default-user")) {
241		options.set("default_user", argv[i + 1]);
242		i += 2;
243	} else if (p.isValueFlag(argc, i, argv[i], '\0', "--default-group")) {
244		options.set("default_group", argv[i + 1]);
245		i += 2;
246	} else if (p.isValueFlag(argc, i, argv[i], '\0', "--max-pool-size")) {
247		options.setInt("max_pool_size", atoi(argv[i + 1]));
248		i += 2;
249	} else if (p.isValueFlag(argc, i, argv[i], '\0', "--pool-idle-time")) {
250		options.setInt("pool_idle_time", atoi(argv[i + 1]));
251		i += 2;
252	} else if (p.isValueFlag(argc, i, argv[i], '\0', "--min-instances")) {
253		options.setInt("min_instances", atoi(argv[i + 1]));
254		i += 2;
255	} else if (p.isValueFlag(argc, i, argv[i], 'e', "--environment")) {
256		options.set("environment", argv[i + 1]);
257		i += 2;
258	} else if (p.isValueFlag(argc, i, argv[i], '\0', "--app-type")) {
259		options.set("app_type", argv[i + 1]);
260		i += 2;
261	} else if (p.isValueFlag(argc, i, argv[i], '\0', "--startup-file")) {
262		options.set("startup_file", argv[i + 1]);
263		i += 2;
264	} else if (p.isValueFlag(argc, i, argv[i], '\0', "--spawn-method")) {
265		options.set("spawn_method", argv[i + 1]);
266		i += 2;
267	} else if (p.isFlag(argv[i], '\0', "--load-shell-envvars")) {
268		options.setBool("load_shell_envvars", true);
269		i++;
270	} else if (p.isValueFlag(argc, i, argv[i], '\0', "--concurrency-model")) {
271		options.set("concurrency_model", argv[i + 1]);
272		i += 2;
273	} else if (p.isValueFlag(argc, i, argv[i], '\0', "--app-thread-count")) {
274		options.setInt("app_thread_count", atoi(argv[i + 1]));
275		i += 2;
276	} else if (p.isFlag(argv[i], '\0', "--multi-app")) {
277		options.setBool("multi_app", true);
278		i++;
279	} else if (p.isFlag(argv[i], '\0', "--force-friendly-error-pages")) {
280		options.setBool("friendly_error_pages", true);
281		i++;
282	} else if (p.isFlag(argv[i], '\0', "--disable-friendly-error-pages")) {
283		options.setBool("friendly_error_pages", false);
284		i++;
285	} else if (p.isValueFlag(argc, i, argv[i], '\0', "--max-request-time")) {
286		options.setInt("max_request_time", atoi(argv[i + 1]));
287		i += 2;
288	} else if (p.isFlag(argv[i], '\0', "--sticky-sessions")) {
289		options.setBool("sticky_sessions", true);
290		i++;
291	} else if (p.isValueFlag(argc, i, argv[i], '\0', "--sticky-sessions-cookie-name")) {
292		options.set("sticky_sessions_cookie_name", argv[i + 1]);
293		i += 2;
294	} else if (p.isValueFlag(argc, i, argv[i], '\0', "--vary-turbocache-by-cookie")) {
295		options.set("vary_turbocache_by_cookie", argv[i + 1]);
296		i += 2;
297	} else if (p.isFlag(argv[i], '\0', "--disable-turbocaching")) {
298		options.setBool("turbocaching", false);
299		i++;
300	} else if (p.isValueFlag(argc, i, argv[i], '\0', "--ruby")) {
301		options.set("default_ruby", argv[i + 1]);
302		i += 2;
303	} else if (p.isValueFlag(argc, i, argv[i], '\0', "--nodejs")) {
304		options.set("default_nodejs", argv[i + 1]);
305		i += 2;
306	} else if (p.isValueFlag(argc, i, argv[i], '\0', "--python")) {
307		options.set("default_python", argv[i + 1]);
308		i += 2;
309	} else if (p.isValueFlag(argc, i, argv[i], '\0', "--meteor-app-settings")) {
310		options.set("meteor_app_settings", argv[i + 1]);
311		i += 2;
312	} else if (p.isFlag(argv[i], '\0', "--debugger")) {
313		options.setBool("debugger", true);
314		i++;
315	} else if (p.isFlag(argv[i], '\0', "--rolling-restarts")) {
316		options.setBool("rolling_restarts", true);
317		i++;
318	} else if (p.isFlag(argv[i], '\0', "--resist-deployment-errors")) {
319		options.setBool("resist_deployment_errors", true);
320		i++;
321	} else if (p.isValueFlag(argc, i, argv[i], '\0', "--log-level")) {
322		// We do not set log_level because, when this function is called from
323		// the Watchdog, we don't want to affect the Watchdog's own log level.
324		options.setInt("server_log_level", atoi(argv[i + 1]));
325		i += 2;
326	} else if (p.isValueFlag(argc, i, argv[i], '\0', "--log-file")) {
327		// We do not set log_file because, when this function is called from
328		// the Watchdog, we don't want to affect the Watchdog's own log file.
329		options.set("server_log_file", argv[i + 1]);
330		i += 2;
331	} else if (p.isValueFlag(argc, i, argv[i], '\0', "--fd-log-file")) {
332		// We do not set file_descriptor_log_file because, when this function is called from
333		// the Watchdog, we don't want to affect the Watchdog's own log file.
334		options.set("server_file_descriptor_log_file", argv[i + 1]);
335		i += 2;
336	} else if (p.isValueFlag(argc, i, argv[i], '\0', "--stat-throttle-rate")) {
337		options.setInt("stat_throttle_rate", atoi(argv[i + 1]));
338		i += 2;
339	} else if (p.isFlag(argv[i], '\0', "--no-show-version-in-header")) {
340		options.setBool("show_version_in_header", false);
341		i++;
342	} else if (p.isValueFlag(argc, i, argv[i], '\0', "--data-buffer-dir")) {
343		options.setInt("data_buffer_dir", atoi(argv[i + 1]));
344		i += 2;
345	} else if (p.isFlag(argv[i], '\0', "--no-graceful-exit")) {
346		options.setBool("server_graceful_exit", false);
347		i++;
348	} else if (p.isValueFlag(argc, i, argv[i], '\0', "--benchmark")) {
349		options.set("benchmark_mode", argv[i + 1]);
350		i += 2;
351	} else if (p.isFlag(argv[i], '\0', "--disable-selfchecks")) {
352		options.setBool("selfchecks", false);
353		i++;
354	} else if (p.isValueFlag(argc, i, argv[i], '\0', "--threads")) {
355		options.setInt("server_threads", atoi(argv[i + 1]));
356		i += 2;
357	} else if (p.isFlag(argv[i], '\0', "--cpu-affine")) {
358		options.setBool("server_cpu_affine", true);
359		i++;
360	} else if (!startsWith(argv[i], "-")) {
361		if (!options.has("app_root")) {
362			options.set("app_root", argv[i]);
363			i++;
364		} else {
365			fprintf(stderr, "ERROR: you may not pass multiple application directories. "
366				"Please type '%s server --help' for usage.\n", argv[0]);
367			exit(1);
368		}
369	} else {
370		return false;
371	}
372	return true;
373}
374
375
376} // namespace Passenger
377
378#endif /* _PASSENGER_SERVER_OPTION_PARSER_H_ */