diff --git a/Cargo.lock b/Cargo.lock index bf98b1624..f79b19921 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -317,7 +317,7 @@ version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" dependencies = [ - "getrandom", + "getrandom 0.2.11", "once_cell", "tiny-keccak", ] @@ -512,12 +512,12 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.9" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +checksum = "cea14ef9355e3beab063703aa9dab15afd25f0667c341310c1e5274bb1d0da18" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -528,9 +528,9 @@ checksum = "d9435d864e017c3c6afeac1654189b06cdb491cf2ff73dbf0d73b0f292f42ff8" [[package]] name = "fastrand" -version = "2.1.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" [[package]] name = "filetime" @@ -596,10 +596,22 @@ dependencies = [ "cfg-if", "js-sys", "libc", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", "wasm-bindgen", ] +[[package]] +name = "getrandom" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasi 0.14.2+wasi-0.2.4", +] + [[package]] name = "half" version = "1.8.2" @@ -939,7 +951,7 @@ checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ "bitflags 2.9.0", "libc", - "redox_syscall 0.5.10", + "redox_syscall", ] [[package]] @@ -954,6 +966,12 @@ version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "969488b55f8ac402214f3f5fd243ebb7206cf82de60d3172994707a4bcc2b829" +[[package]] +name = "linux-raw-sys" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" + [[package]] name = "litemap" version = "0.7.4" @@ -1016,7 +1034,7 @@ dependencies = [ "hermit-abi", "libc", "log", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", "windows-sys 0.52.0", ] @@ -1105,9 +1123,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.18.0" +version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "oorandom" @@ -1321,6 +1339,7 @@ dependencies = [ "signal-hook", "slab", "socket2", + "tempfile", "test-log", "thiserror", "time", @@ -1337,6 +1356,12 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "r-efi" +version = "5.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" + [[package]] name = "rayon" version = "1.8.0" @@ -1357,15 +1382,6 @@ dependencies = [ "crossbeam-utils", ] -[[package]] -name = "redox_syscall" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" -dependencies = [ - "bitflags 1.3.2", -] - [[package]] name = "redox_syscall" version = "0.5.10" @@ -1412,7 +1428,7 @@ checksum = "ed9b823fa29b721a59671b41d6b06e66b29e0628e207e8b1c3ceeda701ec928d" dependencies = [ "cc", "cfg-if", - "getrandom", + "getrandom 0.2.11", "libc", "untrusted", "windows-sys 0.52.0", @@ -1467,6 +1483,19 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "rustix" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266" +dependencies = [ + "bitflags 2.9.0", + "errno", + "libc", + "linux-raw-sys 0.9.4", + "windows-sys 0.59.0", +] + [[package]] name = "rustls" version = "0.21.11" @@ -1733,15 +1762,15 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.9.0" +version = "3.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01ce4141aa927a6d1bd34a041795abd0db1cccba5d5f24b009f694bdf3a1f3fa" +checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1" dependencies = [ - "cfg-if", "fastrand", - "redox_syscall 0.4.1", - "rustix 0.38.28", - "windows-sys 0.52.0", + "getrandom 0.3.3", + "once_cell", + "rustix 1.0.7", + "windows-sys 0.59.0", ] [[package]] @@ -1974,6 +2003,15 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasi" +version = "0.14.2+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" +dependencies = [ + "wit-bindgen-rt", +] + [[package]] name = "wasm-bindgen" version = "0.2.92" @@ -2226,6 +2264,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "wit-bindgen-rt" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" +dependencies = [ + "bitflags 2.9.0", +] + [[package]] name = "write16" version = "1.0.0" diff --git a/Cargo.toml b/Cargo.toml index d5799052d..462dae1d7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -50,6 +50,7 @@ zmq = "0.9" [dev-dependencies] criterion = "0.5" env_logger = { version = "0.9", default-features = false } +tempfile = "3.20.0" test-log = "0.2" [build-dependencies] @@ -82,7 +83,7 @@ bench = false [[bin]] name = "pushpin-handler" -test = false +test = true bench = false [[bin]] diff --git a/build.rs b/build.rs index 370ee00fb..ce4c3c494 100644 --- a/build.rs +++ b/build.rs @@ -353,7 +353,11 @@ fn get_qt_lib_prefix(lib_dir: &Path, version_maj: u16) -> Result Result> { - let paths = ["/usr/local/include", "/usr/include"]; + let paths = [ + "/usr/local/include", + "/usr/include", + "/opt/homebrew/include", + ]; let version_filename = "boost/version.hpp"; for path in paths { diff --git a/log.txt b/log.txt new file mode 100644 index 000000000..e69de29bb diff --git a/src/bin/pushpin-handler.rs b/src/bin/pushpin-handler.rs index 7c816fc02..0562349e6 100644 --- a/src/bin/pushpin-handler.rs +++ b/src/bin/pushpin-handler.rs @@ -14,9 +14,10 @@ * limitations under the License. */ +use clap::Parser; use pushpin::core::call_c_main; +use pushpin::core::ccliargs::CCliArgs; use pushpin::import_cpp; -use std::env; use std::process::ExitCode; import_cpp! { @@ -24,5 +25,7 @@ import_cpp! { } fn main() -> ExitCode { - unsafe { ExitCode::from(call_c_main(handler_main, env::args_os())) } + let c_cli_args = CCliArgs::parse().verify(); + + unsafe { ExitCode::from(call_c_main(handler_main, c_cli_args.into_osstring_vec())) } } diff --git a/src/bin/pushpin-proxy.rs b/src/bin/pushpin-proxy.rs index 59ea3da22..790d85629 100644 --- a/src/bin/pushpin-proxy.rs +++ b/src/bin/pushpin-proxy.rs @@ -14,9 +14,10 @@ * limitations under the License. */ +use clap::Parser; use pushpin::core::call_c_main; +use pushpin::core::ccliargs::CCliArgs; use pushpin::import_cpp; -use std::env; use std::process::ExitCode; import_cpp! { @@ -24,5 +25,7 @@ import_cpp! { } fn main() -> ExitCode { - unsafe { ExitCode::from(call_c_main(proxy_main, env::args_os())) } + let c_cli_args = CCliArgs::parse().verify(); + + unsafe { ExitCode::from(call_c_main(proxy_main, c_cli_args.into_osstring_vec())) } } diff --git a/src/core/argsdata.cpp b/src/core/argsdata.cpp new file mode 100644 index 000000000..9381077b5 --- /dev/null +++ b/src/core/argsdata.cpp @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2015-2022 Fanout, Inc. + * Copyright (C) 2024-2025 Fastly, Inc. + * + * This file is part of Pushpin. + * + * $FANOUT_BEGIN_LICENSE:APACHE2$ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $FANOUT_END_LICENSE$ + */ + +#include "argsdata.h" +#include "settings.h" +#include "config.h" +#include "log.h" +#include +#include + + +Settings ArgsData::loadIntoSettings() +{ + Settings settings(configFile); + + if(!ipcPrefix.isEmpty()) + settings.setIpcPrefix(ipcPrefix); + + if(portOffset != -1) + settings.setPortOffset(portOffset); + + return settings; +} + +ArgsData::ArgsData(QStringList &extArgs) +{ + if(extArgs.isEmpty()) + { + log_error("Error processing arguments. Use --help for usage."); + throw std::exception(); + } + + configFile = extArgs[0]; + logFile = !extArgs[1].isEmpty() ? extArgs[1] : QString(); + logLevel = extArgs[2].toInt(); + ipcPrefix = extArgs[3]; + portOffset = !extArgs[4].isEmpty() ? extArgs[4].toInt() : -1; + routeLines = extArgs[5].isEmpty() ? QStringList() : extArgs[5].split(','); + quietCheck = extArgs[6] == "true" ? true : false; + + // Set the log level + if(logLevel != -1) + log_setOutputLevel(logLevel); + else + log_setOutputLevel(LOG_LEVEL_INFO); + + // Set the log file if specified + if(!logFile.isEmpty()) + { + if(!log_setFile(logFile)) + { + log_error("failed to open log file: %s", qPrintable(logFile)); + throw std::exception(); + } + } + + log_debug("starting..."); + + // QSettings doesn't inform us if the config file can't be opened, so do that ourselves + { + QFile file(configFile); + if(!file.open(QIODevice::ReadOnly)) + { + log_error("failed to open %s", qPrintable(configFile)); + throw std::exception(); + } + } +} \ No newline at end of file diff --git a/src/core/argsdata.h b/src/core/argsdata.h new file mode 100644 index 000000000..a5a8cdd34 --- /dev/null +++ b/src/core/argsdata.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2015-2022 Fanout, Inc. + * Copyright (C) 2024-2025 Fastly, Inc. + * + * This file is part of Pushpin. + * + * $FANOUT_BEGIN_LICENSE:APACHE2$ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $FANOUT_END_LICENSE$ + */ + +#include +#include +#include "settings.h" + +class ArgsData +{ + public: + QString configFile; + QString logFile; + int logLevel; + QString ipcPrefix; + int portOffset; + QStringList routeLines; + bool quietCheck; + + ArgsData(QStringList &extArgs); + + Settings loadIntoSettings(); +}; \ No newline at end of file diff --git a/src/core/ccliargs.rs b/src/core/ccliargs.rs new file mode 100644 index 000000000..d9e1b42e5 --- /dev/null +++ b/src/core/ccliargs.rs @@ -0,0 +1,200 @@ +/* + * Copyright (C) 2023 Fastly, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use crate::core::config::get_config_file; +use crate::core::version; +use clap::{arg, Parser}; +use std::env; +use std::ffi::OsString; +use std::path::PathBuf; + +// Struct to hold the command line arguments +#[derive(Parser, Debug)] +#[command( + name= "Pushpin Handler", + version = version(), + about = "Pushpin handler component." +)] +pub struct CCliArgs { + /// Set path to the configuration file + #[arg(short, long, value_name = "file")] + pub config_file: Option, + + /// Set path to the log file + #[arg(short = 'l', long, value_name = "file")] + pub log_file: Option, + + /// Set log level (0=error, 1=warn, 2=info, 3=debug, 4=trace) + #[arg(short = 'L', long, value_name = "x", default_value_t = 2, value_parser = clap::value_parser!(u32).range(1..=4))] + pub log_level: u32, + + /// Override ipc_prefix config option, which is used to add a prefix to all ZeroMQ IPC filenames + #[arg(long, value_name = "prefix")] + pub ipc_prefix: Option, + + /// Override port_offset config option, which is used to increment all ZeroMQ TCP ports and the HTTP control server port + #[arg(long, value_name = "offset", value_parser = clap::value_parser!(u32))] + pub port_offset: Option, + + /// Add routes (overrides routes file) + #[arg(long, value_name = "routes")] + pub routes: Option>, + + /// Log update checks in Zurl as debug level + #[arg(long, value_name = "quiet-check", default_value_t = false)] + pub quiet_check: bool, +} + +impl CCliArgs { + /// Verifies the command line arguments. + pub fn verify(mut self) -> Self { + let work_dir = env::current_dir().unwrap_or_default(); + let config_path: Option = self.config_file.as_ref().map(PathBuf::from); + + // Resolve the config file path using get_config_file + self.config_file = match get_config_file(&work_dir, config_path) { + Ok(path) => Some(path.to_string_lossy().to_string()), + Err(e) => { + eprintln!("error: failed to find configuration file: {}", e); + std::process::exit(1); + } + }; + + self + } + + pub fn into_osstring_vec(self) -> Vec { + self.into_iter() + .map(|(_, value)| OsString::from(value)) + .collect() + } +} + +impl IntoIterator for CCliArgs { + type Item = (String, String); + type IntoIter = std::vec::IntoIter; + + fn into_iter(self) -> Self::IntoIter { + let args: Vec<(String, String)> = vec![ + ( + "config-file".to_string(), + self.config_file.unwrap_or_default(), + ), + ("log-file".to_string(), self.log_file.unwrap_or_default()), + ("log-level".to_string(), self.log_level.to_string()), + ( + "ipc-prefix".to_string(), + self.ipc_prefix.unwrap_or_default(), + ), + ( + "port-offset".to_string(), + self.port_offset.map_or("".to_string(), |p| p.to_string()), + ), + ( + "routes".to_string(), + self.routes.map_or("".to_string(), |r| r.join(",")), + ), + ("quiet-check".to_string(), self.quiet_check.to_string()), + ]; + + args.into_iter() + } +} + +#[cfg(test)] +mod tests { + use super::*; + use tempfile::NamedTempFile; + + #[test] + fn test_ccli_args() { + // Create mock values + let file = NamedTempFile::new().unwrap(); + let config_test_file = file.path().to_str().unwrap().to_string(); + let expected_arg_count = 7; + + let args = CCliArgs { + config_file: Some(config_test_file.clone()), + log_file: Some("pushpin.log".to_string()), + log_level: 3, + ipc_prefix: Some("ipc".to_string()), + port_offset: Some(8080), + routes: Some(vec!["route1".to_string(), "route2".to_string()]), + quiet_check: true, + }; + + // Test verify() method + let verified_args = args.verify(); + assert_eq!(verified_args.config_file, Some(config_test_file.clone())); + assert_eq!(verified_args.log_file, Some("pushpin.log".to_string())); + assert_eq!(verified_args.log_level, 3); + assert_eq!(verified_args.ipc_prefix, Some("ipc".to_string())); + assert_eq!(verified_args.port_offset, Some(8080)); + assert_eq!( + verified_args.routes, + Some(vec!["route1".to_string(), "route2".to_string()]) + ); + assert_eq!(verified_args.quiet_check, true); + + // Test OsString conversion + let osstring_vec = verified_args.into_osstring_vec(); + assert_eq!(osstring_vec.len(), expected_arg_count); + assert_eq!(osstring_vec[0], OsString::from(config_test_file)); + assert_eq!(osstring_vec[1], OsString::from("pushpin.log")); + assert_eq!(osstring_vec[2], OsString::from("3")); + assert_eq!(osstring_vec[3], OsString::from("ipc")); + assert_eq!(osstring_vec[4], OsString::from("8080")); + assert_eq!(osstring_vec[5], OsString::from("route1,route2")); + assert_eq!(osstring_vec[6], OsString::from("true")); + + // Test with empty/default values + let empty_args = CCliArgs { + config_file: None, + log_file: None, + log_level: 2, + ipc_prefix: None, + port_offset: None, + routes: None, + quiet_check: false, + }; + + let verified_empty_args = empty_args.verify(); + let default_config_file = get_config_file(&env::current_dir().unwrap(), None) + .unwrap() + .to_string_lossy() + .to_string(); + assert_eq!( + verified_empty_args.config_file, + Some(default_config_file.clone()) + ); + assert_eq!(verified_empty_args.log_file, None); + assert_eq!(verified_empty_args.log_level, 2); + assert_eq!(verified_empty_args.ipc_prefix, None); + assert_eq!(verified_empty_args.port_offset, None); + assert_eq!(verified_empty_args.routes, None); + assert_eq!(verified_empty_args.quiet_check, false); + + let empty_osstring_vec = verified_empty_args.into_osstring_vec(); + assert_eq!(empty_osstring_vec.len(), expected_arg_count); + assert_eq!(empty_osstring_vec[0], OsString::from(default_config_file)); + assert_eq!(empty_osstring_vec[1], OsString::from("")); + assert_eq!(empty_osstring_vec[2], OsString::from("2")); + assert_eq!(empty_osstring_vec[3], OsString::from("")); + assert_eq!(empty_osstring_vec[4], OsString::from("")); + assert_eq!(empty_osstring_vec[5], OsString::from("")); + assert_eq!(empty_osstring_vec[6], OsString::from("false")); + } +} diff --git a/src/core/core.pri b/src/core/core.pri index cecc9e5d9..ad7befda8 100644 --- a/src/core/core.pri +++ b/src/core/core.pri @@ -81,10 +81,12 @@ HEADERS += \ $$PWD/simplehttpserver.h \ $$PWD/stats.h \ $$PWD/statsmanager.h \ - $$PWD/settings.h + $$PWD/settings.h \ + $$PWD/argsdata.h SOURCES += \ $$PWD/config.cpp \ + $$PWD/argsdata.cpp \ $$PWD/timerwheel.cpp \ $$PWD/jwt.cpp \ $$PWD/timer.cpp \ diff --git a/src/core/mod.rs b/src/core/mod.rs index 03aed3465..d60ada1e5 100644 --- a/src/core/mod.rs +++ b/src/core/mod.rs @@ -16,6 +16,7 @@ pub mod arena; pub mod buffer; +pub mod ccliargs; pub mod channel; pub mod config; pub mod defer; diff --git a/src/core/settings.cpp b/src/core/settings.cpp index f45fee29f..2ed5125ee 100644 --- a/src/core/settings.cpp +++ b/src/core/settings.cpp @@ -189,3 +189,10 @@ void Settings::setPortOffset(int x) { portOffset_ = x; } + +bool Settings::operator==(const Settings& other) const { + return ipcPrefix_ == other.ipcPrefix_ && + portOffset_ == other.portOffset_ && + libdir_ == other.libdir_ && + rundir_ == other.rundir_; +} \ No newline at end of file diff --git a/src/core/settings.h b/src/core/settings.h index 0caef610d..820e44eaf 100644 --- a/src/core/settings.h +++ b/src/core/settings.h @@ -41,6 +41,7 @@ class Settings void setIpcPrefix(const QString &s); void setPortOffset(int x); + bool operator==(const Settings& other) const; private: QSettings *main_; diff --git a/src/core/tests.pri b/src/core/tests.pri index 0adf1c63d..1ffb5f38a 100644 --- a/src/core/tests.pri +++ b/src/core/tests.pri @@ -6,3 +6,4 @@ SOURCES += \ $$PWD/tcpstreamtest.cpp \ $$PWD/unixstreamtest.cpp \ $$PWD/eventlooptest.cpp + diff --git a/src/handler/argstest.cpp b/src/handler/argstest.cpp new file mode 100644 index 000000000..e69de29bb diff --git a/src/handler/handlerapp.cpp b/src/handler/handlerapp.cpp index 7a7ee85bb..89a37827b 100644 --- a/src/handler/handlerapp.cpp +++ b/src/handler/handlerapp.cpp @@ -22,6 +22,7 @@ */ #include "handlerapp.h" +#include "argsdata.h" #include #include @@ -42,6 +43,7 @@ #include "settings.h" #include "handlerengine.h" #include "config.h" +#include #define DEFAULT_HTTP_MAX_HEADERS_SIZE 10000 #define DEFAULT_HTTP_MAX_BODY_SIZE 1000000 @@ -82,101 +84,6 @@ static QString firstSpec(const QString &s, int peerCount) return s; } -enum CommandLineParseResult -{ - CommandLineOk, - CommandLineError, - CommandLineVersionRequested, - CommandLineHelpRequested -}; - -class ArgsData -{ -public: - QString configFile; - QString logFile; - int logLevel; - QString ipcPrefix; - int portOffset; - - ArgsData() : - logLevel(-1), - portOffset(-1) - { - } -}; - -static CommandLineParseResult parseCommandLine(QCommandLineParser *parser, ArgsData *args, QString *errorMessage) -{ - parser->setSingleDashWordOptionMode(QCommandLineParser::ParseAsLongOptions); - const QCommandLineOption configFileOption("config", "Config file.", "file"); - parser->addOption(configFileOption); - const QCommandLineOption logFileOption("logfile", "File to log to.", "file"); - parser->addOption(logFileOption); - const QCommandLineOption logLevelOption("loglevel", "Log level (default: 2).", "x"); - parser->addOption(logLevelOption); - const QCommandLineOption verboseOption("verbose", "Verbose output. Same as --loglevel=3."); - parser->addOption(verboseOption); - const QCommandLineOption ipcPrefixOption("ipc-prefix", "Override ipc_prefix config option.", "prefix"); - parser->addOption(ipcPrefixOption); - const QCommandLineOption portOffsetOption("port-offset", "Override port_offset config option.", "offset"); - parser->addOption(portOffsetOption); - const QCommandLineOption helpOption = parser->addHelpOption(); - const QCommandLineOption versionOption = parser->addVersionOption(); - - if(!parser->parse(QCoreApplication::arguments())) - { - *errorMessage = parser->errorText(); - return CommandLineError; - } - - if(parser->isSet(versionOption)) - return CommandLineVersionRequested; - - if(parser->isSet(helpOption)) - return CommandLineHelpRequested; - - if(parser->isSet(configFileOption)) - args->configFile = parser->value(configFileOption); - - if(parser->isSet(logFileOption)) - args->logFile = parser->value(logFileOption); - - if(parser->isSet(logLevelOption)) - { - bool ok; - int x = parser->value(logLevelOption).toInt(&ok); - if(!ok || x < 0) - { - *errorMessage = "error: loglevel must be greater than or equal to 0"; - return CommandLineError; - } - - args->logLevel = x; - } - - if(parser->isSet(verboseOption)) - args->logLevel = 3; - - if(parser->isSet(ipcPrefixOption)) - args->ipcPrefix = parser->value(ipcPrefixOption); - - if(parser->isSet(portOffsetOption)) - { - bool ok; - int x = parser->value(portOffsetOption).toInt(&ok); - if(!ok || x < 0) - { - *errorMessage = "error: port-offset must be greater than or equal to 0"; - return CommandLineError; - } - - args->portOffset = x; - } - - return CommandLineOk; -} - class HandlerApp::Private { public: @@ -185,64 +92,9 @@ class HandlerApp::Private QCoreApplication::setApplicationName("pushpin-handler"); QCoreApplication::setApplicationVersion(Config::get().version); - QCommandLineParser parser; - parser.setApplicationDescription("Pushpin handler component."); - - ArgsData args; - QString errorMessage; - switch(parseCommandLine(&parser, &args, &errorMessage)) - { - case CommandLineOk: - break; - case CommandLineError: - fprintf(stderr, "%s\n\n%s", qPrintable(errorMessage), qPrintable(parser.helpText())); - return 1; - case CommandLineVersionRequested: - printf("%s %s\n", qPrintable(QCoreApplication::applicationName()), - qPrintable(QCoreApplication::applicationVersion())); - return 0; - case CommandLineHelpRequested: - parser.showHelp(); - Q_UNREACHABLE(); - } - - if(args.logLevel != -1) - log_setOutputLevel(args.logLevel); - else - log_setOutputLevel(LOG_LEVEL_INFO); - - if(!args.logFile.isEmpty()) - { - if(!log_setFile(args.logFile)) - { - log_error("failed to open log file: %s", qPrintable(args.logFile)); - return 1; - } - } - - log_debug("starting..."); - - QString configFile = args.configFile; - if(configFile.isEmpty()) - configFile = QDir(Config::get().configDir).filePath("pushpin.conf"); - - // QSettings doesn't inform us if the config file doesn't exist, so do that ourselves - { - QFile file(configFile); - if(!file.open(QIODevice::ReadOnly)) - { - log_error("failed to open %s, and --config not passed", qPrintable(configFile)); - return 1; - } - } - - Settings settings(configFile); - - if(!args.ipcPrefix.isEmpty()) - settings.setIpcPrefix(args.ipcPrefix); - - if(args.portOffset != -1) - settings.setPortOffset(args.portOffset); + QStringList extArgs = QCoreApplication::arguments(); + ArgsData args(extArgs); + Settings settings = args.loadIntoSettings(); QStringList services = settings.value("runner/services").toStringList(); @@ -496,4 +348,4 @@ HandlerApp::~HandlerApp() = default; int HandlerApp::run() { return Private::run(); -} +} \ No newline at end of file diff --git a/src/handler/handlerapp.h b/src/handler/handlerapp.h index f0b5d6205..d68994c80 100644 --- a/src/handler/handlerapp.h +++ b/src/handler/handlerapp.h @@ -23,6 +23,7 @@ #ifndef HANDLERAPP_H #define HANDLERAPP_H +#include "settings.h" class HandlerApp { diff --git a/src/handler/handlerargstest.cpp b/src/handler/handlerargstest.cpp new file mode 100644 index 000000000..7a7fa8c08 --- /dev/null +++ b/src/handler/handlerargstest.cpp @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2025 Fastly, Inc. + * + * This file is part of Pushpin. + * + * $FANOUT_BEGIN_LICENSE:APACHE2$ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $FANOUT_END_LICENSE$ + */ + + +#include "config.h" +#include "handlerapp.h" +#include "settings.h" +#include "test.h" +#include "argsdata.h" + +void handlerargstest() +{ + // Get file for example config + std::string configFile = "examples/config/pushpin.conf"; + + // Set up valid command line arguments + int argc = 7; + char * argv[] = { + (char *) configFile.c_str(), // configFile + (char *) "log.txt", // logFile + (char *) "2", // logLevel + (char *) "ipc:prefix", // ipcPrefix + (char *) "80", // portOffset + (char *) "route1,route2", // routeLines + (char *) "true", // quietCheck + }; + + // Set up QCoreApplication + QCoreApplication qapp(argc, argv); + HandlerApp app; + QStringList extArgs = qapp.arguments(); + + // Verify the arguments + TEST_ASSERT_EQ(extArgs[0], QString("examples/config/pushpin.conf")); + TEST_ASSERT_EQ(extArgs[1], QString("log.txt")); + TEST_ASSERT_EQ(extArgs[2], QString("2")); + TEST_ASSERT_EQ(extArgs[3], QString("ipc:prefix")); + TEST_ASSERT_EQ(extArgs[4], QString("80")); + TEST_ASSERT_EQ(extArgs[5], QString("route1,route2")); + TEST_ASSERT_EQ(extArgs[6], QString("true")); + + // Verify ArgsData parsing + ArgsData args(extArgs); + TEST_ASSERT_EQ(args.configFile, QString("examples/config/pushpin.conf")); + TEST_ASSERT_EQ(args.logFile, QString("log.txt")); + TEST_ASSERT_EQ(args.logLevel, 2); + TEST_ASSERT_EQ(args.ipcPrefix, QString("ipc:prefix")); + TEST_ASSERT_EQ(args.portOffset, 80); + TEST_ASSERT_EQ(args.routeLines, QStringList({"route1", "route2"})); + TEST_ASSERT_EQ(args.quietCheck, true); + + // Set up mock settings + Settings mock_settings(args.configFile); + if (!args.ipcPrefix.isEmpty()) + mock_settings.setIpcPrefix(args.ipcPrefix);; + if (args.portOffset != -1) + mock_settings.setPortOffset(args.portOffset); + + // Load settings from command line arguments + Settings settings = args.loadIntoSettings(); + + // Verify mock settings match the loaded settings + TEST_ASSERT_EQ(mock_settings, settings); + + // Change the port offset to a different value + mock_settings.setPortOffset(60); + + // Verify that the mock settings no longer match the loaded settings + TEST_ASSERT(!(mock_settings == settings)); + + // Set up valid empty command line arguments + int argc_empty = 7; + char * argv_empty[] = { + (char *) configFile.c_str(), // configFile + (char *) "", // logFile + (char *) "2", // logLevel + (char *) "", // ipcPrefix + (char *) "", // portOffset + (char *) "", // routeLines + (char *) "false", // quietCheck + }; + + // Set up QCoreApplication with empty arguments + QCoreApplication qapp_empty(argc_empty, argv_empty); + HandlerApp app_empty; + QStringList extArgs_empty = qapp_empty.arguments(); + + // Verify the arguments + TEST_ASSERT_EQ(extArgs_empty[0], QString("examples/config/pushpin.conf")); + TEST_ASSERT_EQ(extArgs_empty[1], QString("")); + TEST_ASSERT_EQ(extArgs_empty[2], QString("2")); + TEST_ASSERT_EQ(extArgs_empty[3], QString("")); + TEST_ASSERT_EQ(extArgs_empty[4], QString("")); + TEST_ASSERT_EQ(extArgs_empty[5], QString("")); + TEST_ASSERT_EQ(extArgs_empty[6], QString("false")); + + // Verify ArgsData parsing with empty arguments + ArgsData args_empty(extArgs_empty); + TEST_ASSERT_EQ(args_empty.configFile, QString("examples/config/pushpin.conf")); + TEST_ASSERT_EQ(args_empty.logFile, QString("")); + TEST_ASSERT_EQ(args_empty.logLevel, 2); + TEST_ASSERT_EQ(args_empty.ipcPrefix, QString("")); + TEST_ASSERT_EQ(args_empty.portOffset, -1); + TEST_ASSERT_EQ(args_empty.routeLines, QStringList()); + TEST_ASSERT_EQ(args_empty.quietCheck, false); + + // Load settings from empty command line arguments + Settings settings_empty = args_empty.loadIntoSettings(); + + // Set up mock settings + Settings mock_settings_empty(args_empty.configFile); + if (!args_empty.ipcPrefix.isEmpty()) + mock_settings_empty.setIpcPrefix(args_empty.ipcPrefix); + if (args_empty.portOffset != -1) + mock_settings_empty.setPortOffset(args_empty.portOffset); + + // Verify mock settings match the loaded settings + TEST_ASSERT_EQ(mock_settings_empty, settings_empty); +} + +extern "C" int handlerargs_test(ffi::TestException *out_ex) +{ + TEST_CATCH(handlerargstest()); + + return 0; +} \ No newline at end of file diff --git a/src/handler/mod.rs b/src/handler/mod.rs index 0553068c6..f49499cbe 100644 --- a/src/handler/mod.rs +++ b/src/handler/mod.rs @@ -54,6 +54,11 @@ mod tests { unsafe { ffi::handlerengine_test(out_ex) == 0 } } + fn handlerargs_test(out_ex: &mut TestException) -> bool { + // SAFETY: safe to call + unsafe { ffi::handlerargs_test(out_ex) == 0 } + } + #[test] fn filter() { run_serial(filter_test); @@ -88,4 +93,9 @@ mod tests { fn handlerengine() { run_serial(handlerengine_test); } + + #[test] + fn handlerargs() { + run_serial(handlerargs_test); + } } diff --git a/src/handler/tests.pri b/src/handler/tests.pri index 52a6ac7d8..5f4c0704c 100644 --- a/src/handler/tests.pri +++ b/src/handler/tests.pri @@ -5,4 +5,5 @@ SOURCES += \ $$PWD/idformattest.cpp \ $$PWD/publishformattest.cpp \ $$PWD/publishitemtest.cpp \ - $$PWD/handlerenginetest.cpp + $$PWD/handlerenginetest.cpp \ + $$PWD/handlerargstest.cpp \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 07b4515cf..9d7d64085 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -148,6 +148,8 @@ pub mod ffi { pub fn publishformat_test(out_ex: *mut TestException) -> libc::c_int; pub fn publishitem_test(out_ex: *mut TestException) -> libc::c_int; pub fn handlerengine_test(out_ex: *mut TestException) -> libc::c_int; + pub fn handlerargs_test(out_ex: *mut TestException) -> libc::c_int; + pub fn proxyargs_test(out_ex: *mut TestException) -> libc::c_int; pub fn template_test(out_ex: *mut TestException) -> libc::c_int; } } diff --git a/src/proxy/app.cpp b/src/proxy/app.cpp index fafc0cf44..424ebea29 100644 --- a/src/proxy/app.cpp +++ b/src/proxy/app.cpp @@ -22,6 +22,7 @@ */ #include "app.h" +#include "argsdata.h" #include #include @@ -44,6 +45,9 @@ #include "domainmap.h" #include "engine.h" #include "config.h" +#include +#include +#include static void trimlist(QStringList *list) { @@ -101,92 +105,6 @@ enum CommandLineParseResult CommandLineHelpRequested }; -class ArgsData -{ -public: - QString configFile; - QString logFile; - int logLevel; - QString ipcPrefix; - QStringList routeLines; - bool quietCheck; - - ArgsData() : - logLevel(-1), - quietCheck(false) - { - } -}; - -static CommandLineParseResult parseCommandLine(QCommandLineParser *parser, ArgsData *args, QString *errorMessage) -{ - parser->setSingleDashWordOptionMode(QCommandLineParser::ParseAsLongOptions); - const QCommandLineOption configFileOption("config", "Config file.", "file"); - parser->addOption(configFileOption); - const QCommandLineOption logFileOption("logfile", "File to log to.", "file"); - parser->addOption(logFileOption); - const QCommandLineOption logLevelOption("loglevel", "Log level (default: 2).", "x"); - parser->addOption(logLevelOption); - const QCommandLineOption verboseOption("verbose", "Verbose output. Same as --loglevel=3."); - parser->addOption(verboseOption); - const QCommandLineOption ipcPrefixOption("ipc-prefix", "Override ipc_prefix config option.", "prefix"); - parser->addOption(ipcPrefixOption); - const QCommandLineOption routeOption("route", "Add route (overrides routes file).", "line"); - parser->addOption(routeOption); - const QCommandLineOption quietCheckOption("quiet-check", "Log update checks in Zurl as debug level."); - parser->addOption(quietCheckOption); - const QCommandLineOption helpOption = parser->addHelpOption(); - const QCommandLineOption versionOption = parser->addVersionOption(); - - if(!parser->parse(QCoreApplication::arguments())) - { - *errorMessage = parser->errorText(); - return CommandLineError; - } - - if(parser->isSet(versionOption)) - return CommandLineVersionRequested; - - if(parser->isSet(helpOption)) - return CommandLineHelpRequested; - - if(parser->isSet(configFileOption)) - args->configFile = parser->value(configFileOption); - - if(parser->isSet(logFileOption)) - args->logFile = parser->value(logFileOption); - - if(parser->isSet(logLevelOption)) - { - bool ok; - int x = parser->value(logLevelOption).toInt(&ok); - if(!ok || x < 0) - { - *errorMessage = "error: loglevel must be greater than or equal to 0"; - return CommandLineError; - } - - args->logLevel = x; - } - - if(parser->isSet(verboseOption)) - args->logLevel = 3; - - if(parser->isSet(ipcPrefixOption)) - args->ipcPrefix = parser->value(ipcPrefixOption); - - if(parser->isSet(routeOption)) - { - foreach(const QString &r, parser->values(routeOption)) - args->routeLines += r; - } - - if(parser->isSet(quietCheckOption)) - args->quietCheck = true; - - return CommandLineOk; -} - class EngineWorker { public: @@ -396,64 +314,11 @@ class App::Private QCoreApplication::setApplicationName("pushpin-proxy"); QCoreApplication::setApplicationVersion(Config::get().version); - QCommandLineParser parser; - parser.setApplicationDescription("Pushpin proxy component."); - - ArgsData args; - QString errorMessage; - switch(parseCommandLine(&parser, &args, &errorMessage)) - { - case CommandLineOk: - break; - case CommandLineError: - fprintf(stderr, "%s\n\n%s", qPrintable(errorMessage), qPrintable(parser.helpText())); - return 1; - case CommandLineVersionRequested: - printf("%s %s\n", qPrintable(QCoreApplication::applicationName()), - qPrintable(QCoreApplication::applicationVersion())); - return 0; - case CommandLineHelpRequested: - parser.showHelp(); - Q_UNREACHABLE(); - } - - if(args.logLevel != -1) - log_setOutputLevel(args.logLevel); - else - log_setOutputLevel(LOG_LEVEL_INFO); - - if(!args.logFile.isEmpty()) - { - if(!log_setFile(args.logFile)) - { - log_error("failed to open log file: %s", qPrintable(args.logFile)); - return 1; - } - } - - log_debug("starting..."); - - QString configFile = args.configFile; - if(configFile.isEmpty()) - configFile = QDir(Config::get().configDir).filePath("pushpin.conf"); - - // QSettings doesn't inform us if the config file doesn't exist, so do that ourselves - { - QFile file(configFile); - if(!file.open(QIODevice::ReadOnly)) - { - log_error("failed to open %s, and --config not passed", qPrintable(configFile)); - return 1; - } - } - - QDir configDir = QFileInfo(configFile).absoluteDir(); - - Settings settings(configFile); - - if(!args.ipcPrefix.isEmpty()) - settings.setIpcPrefix(args.ipcPrefix); + QStringList extArgs = QCoreApplication::arguments(); + ArgsData args(extArgs); + Settings settings = args.loadIntoSettings(); + QDir configDir = QFileInfo(args.configFile).absoluteDir(); QStringList services = settings.value("runner/services").toStringList(); int workerCount = settings.value("proxy/workers", 1).toInt(); @@ -791,4 +656,4 @@ App::~App() = default; int App::run() { return Private::run(); -} +} \ No newline at end of file diff --git a/src/proxy/mod.rs b/src/proxy/mod.rs index d5b0815a4..65accc359 100644 --- a/src/proxy/mod.rs +++ b/src/proxy/mod.rs @@ -34,6 +34,11 @@ mod tests { unsafe { ffi::proxyengine_test(out_ex) == 0 } } + fn proxyargs_test(out_ex: &mut TestException) -> bool { + // SAFETY: safe to call + unsafe { ffi::proxyargs_test(out_ex) == 0 } + } + #[test] fn websocketoverhttp() { run_serial(websocketoverhttp_test); @@ -48,4 +53,9 @@ mod tests { fn proxyengine() { run_serial(proxyengine_test); } + + #[test] + fn proxyargs() { + run_serial(proxyargs_test); + } } diff --git a/src/proxy/proxyargstest.cpp b/src/proxy/proxyargstest.cpp new file mode 100644 index 000000000..845d6eebc --- /dev/null +++ b/src/proxy/proxyargstest.cpp @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2025 Fastly, Inc. + * + * This file is part of Pushpin. + * + * $FANOUT_BEGIN_LICENSE:APACHE2$ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $FANOUT_END_LICENSE$ + */ + + + #include "config.h" + #include "app.h" + #include "settings.h" + #include "test.h" + #include "argsdata.h" + + void proxyargstest() + { + // Get file for example config + std::string configFile = "examples/config/pushpin.conf"; + + // Set up valid command line arguments + int argc = 7; + char * argv[] = { + (char *) configFile.c_str(), // configFile + (char *) "log.txt", // logFile + (char *) "2", // logLevel + (char *) "ipc:prefix", // ipcPrefix + (char *) "80", // portOffset + (char *) "route1,route2", // routeLines + (char *) "true", // quietCheck + }; + + // Set up QCoreApplication + QCoreApplication qapp(argc, argv); + App app; + QStringList extArgs = qapp.arguments(); + + // Verify the arguments + TEST_ASSERT_EQ(extArgs[0], QString("examples/config/pushpin.conf")); + TEST_ASSERT_EQ(extArgs[1], QString("log.txt")); + TEST_ASSERT_EQ(extArgs[2], QString("2")); + TEST_ASSERT_EQ(extArgs[3], QString("ipc:prefix")); + TEST_ASSERT_EQ(extArgs[4], QString("80")); + TEST_ASSERT_EQ(extArgs[5], QString("route1,route2")); + TEST_ASSERT_EQ(extArgs[6], QString("true")); + + // Verify ArgsData parsing + ArgsData args(extArgs); + TEST_ASSERT_EQ(args.configFile, QString("examples/config/pushpin.conf")); + TEST_ASSERT_EQ(args.logFile, QString("log.txt")); + TEST_ASSERT_EQ(args.logLevel, 2); + TEST_ASSERT_EQ(args.ipcPrefix, QString("ipc:prefix")); + TEST_ASSERT_EQ(args.portOffset, 80); + TEST_ASSERT_EQ(args.routeLines, QStringList({"route1", "route2"})); + TEST_ASSERT_EQ(args.quietCheck, true); + + // Set up mock settings + Settings mock_settings(args.configFile); + if (!args.ipcPrefix.isEmpty()) + mock_settings.setIpcPrefix(args.ipcPrefix);; + if (args.portOffset != -1) + mock_settings.setPortOffset(args.portOffset); + + // Load settings from command line arguments + Settings settings = args.loadIntoSettings(); + + // Verify mock settings match the loaded settings + TEST_ASSERT_EQ(mock_settings, settings); + + // Change the port offset to a different value + mock_settings.setPortOffset(60); + + // Verify that the mock settings no longer match the loaded settings + TEST_ASSERT(!(mock_settings == settings)); + + // Set up valid empty command line arguments + int argc_empty = 7; + char * argv_empty[] = { + (char *) configFile.c_str(), // configFile + (char *) "", // logFile + (char *) "2", // logLevel + (char *) "", // ipcPrefix + (char *) "", // portOffset + (char *) "", // routeLines + (char *) "false", // quietCheck + }; + + // Set up QCoreApplication with empty arguments + QCoreApplication qapp_empty(argc_empty, argv_empty); + App app_empty; + QStringList extArgs_empty = qapp_empty.arguments(); + + // Verify the arguments + TEST_ASSERT_EQ(extArgs_empty[0], QString("examples/config/pushpin.conf")); + TEST_ASSERT_EQ(extArgs_empty[1], QString("")); + TEST_ASSERT_EQ(extArgs_empty[2], QString("2")); + TEST_ASSERT_EQ(extArgs_empty[3], QString("")); + TEST_ASSERT_EQ(extArgs_empty[4], QString("")); + TEST_ASSERT_EQ(extArgs_empty[5], QString("")); + TEST_ASSERT_EQ(extArgs_empty[6], QString("false")); + + // Verify ArgsData parsing with empty arguments + ArgsData args_empty(extArgs_empty); + TEST_ASSERT_EQ(args_empty.configFile, QString("examples/config/pushpin.conf")); + TEST_ASSERT_EQ(args_empty.logFile, QString("")); + TEST_ASSERT_EQ(args_empty.logLevel, 2); + TEST_ASSERT_EQ(args_empty.ipcPrefix, QString("")); + TEST_ASSERT_EQ(args_empty.portOffset, -1); + TEST_ASSERT_EQ(args_empty.routeLines, QStringList()); + TEST_ASSERT_EQ(args_empty.quietCheck, false); + + // Load settings from empty command line arguments + Settings settings_empty = args_empty.loadIntoSettings(); + + // Set up mock settings + Settings mock_settings_empty(args_empty.configFile); + if (!args_empty.ipcPrefix.isEmpty()) + mock_settings_empty.setIpcPrefix(args_empty.ipcPrefix); + if (args_empty.portOffset != -1) + mock_settings_empty.setPortOffset(args_empty.portOffset); + + // Verify mock settings match the loaded settings + TEST_ASSERT_EQ(mock_settings_empty, settings_empty); + } + + extern "C" int proxyargs_test(ffi::TestException *out_ex) + { + TEST_CATCH(proxyargstest()); + + return 0; + } \ No newline at end of file diff --git a/src/proxy/tests.pri b/src/proxy/tests.pri index a6738761f..4548550b8 100644 --- a/src/proxy/tests.pri +++ b/src/proxy/tests.pri @@ -1,4 +1,6 @@ SOURCES += \ $$PWD/websocketoverhttptest.cpp \ $$PWD/routesfiletest.cpp \ - $$PWD/proxyenginetest.cpp + $$PWD/proxyenginetest.cpp \ + $$PWD/proxyargstest.cpp + diff --git a/src/runner/pushpinproxyservice.cpp b/src/runner/pushpinproxyservice.cpp index 44ea50a2a..f40be6d6f 100644 --- a/src/runner/pushpinproxyservice.cpp +++ b/src/runner/pushpinproxyservice.cpp @@ -37,22 +37,22 @@ PushpinProxyService::PushpinProxyService( bool quietCheck) { args_ += binFile; - args_ += "--config=" + configFile; + args_ += "--config-file=" + configFile; if(!ipcPrefix.isEmpty()) args_ += "--ipc-prefix=" + ipcPrefix; if(!logDir.isEmpty()) { - args_ += "--logfile=" + QDir(logDir).filePath(filePrefix + "pushpin-proxy.log"); + args_ += "--log-file=" + QDir(logDir).filePath(filePrefix + "pushpin-proxy.log"); setStandardOutputFile(QProcess::nullDevice()); } if(logLevel >= 0) - args_ += "--loglevel=" + QString::number(logLevel); + args_ += "--log-level=" + QString::number(logLevel); foreach(const QString &route, routeLines) - args_ += "--route=" + route; + args_ += "--routes=" + route; if(quietCheck) args_ += "--quiet-check"; diff --git a/src/runner/service.rs b/src/runner/service.rs index bc1eddea4..81e9286fd 100644 --- a/src/runner/service.rs +++ b/src/runner/service.rs @@ -322,21 +322,26 @@ impl PushpinProxyService { let mut args: Vec = vec![]; let service_name = "proxy"; + // Proxy bin path args.push(settings.proxy_bin.display().to_string()); - args.push(format!("--config={}", settings.config_file.display())); + // Config file + args.push(format!("--config-file={}", settings.config_file.display())); + + // Ipc prefix if !settings.ipc_prefix.is_empty() { args.push(format!("--ipc-prefix={}", settings.ipc_prefix)); } + + // Log level let log_level = match settings.log_levels.get("proxy") { Some(&x) => x, None => settings.log_levels.get("default").unwrap().to_owned(), }; - args.push(format!("--loglevel={}", log_level)); + args.push(format!("--log-level={}", log_level)); - for route in settings.route_lines.clone() { - args.push(format!("--route={}", route)); - } + // Routes + args.push(format!("--routes={}", settings.route_lines.join(","))); Self { service: Service::new(String::from(service_name), log_level), @@ -361,20 +366,28 @@ impl PushpinHandlerService { let mut args: Vec = vec![]; let service_name = "handler"; + // Handler bin path args.push(settings.handler_bin.display().to_string()); - args.push(format!("--config={}", settings.config_file.display())); + // Config file + args.push(format!("--config-file={}", settings.config_file.display())); + + // Port offset if settings.port_offset > 0 { args.push(format!("--port-offset={}", settings.port_offset)); } + + // Ipc prefix if !settings.ipc_prefix.is_empty() { args.push(format!("--ipc-prefix={}", settings.ipc_prefix)); } + + // Log level let log_level = match settings.log_levels.get("handler") { Some(&x) => x, None => settings.log_levels.get("default").unwrap().to_owned(), }; - args.push(format!("--loglevel={}", log_level)); + args.push(format!("--log-level={}", log_level)); Self { service: Service::new(String::from(service_name), log_level),