From 0bf15a769499e4f999ffafa47a9a5ef0023ac3de Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Wed, 21 Nov 2012 22:10:35 +0900 Subject: [PATCH] Rename --client-mode as --client and add --client-proxy With --client-proxy option, shrpx makes sure that the request path is an absolute URI, otherwise it will return 400 status code. --- src/shrpx.cc | 54 +++++++++++++++++++++++-------------- src/shrpx_config.cc | 11 +++++--- src/shrpx_config.h | 6 ++++- src/shrpx_https_upstream.cc | 18 ++++++++++++- 4 files changed, 64 insertions(+), 25 deletions(-) diff --git a/src/shrpx.cc b/src/shrpx.cc index 89451d26..0d165a71 100644 --- a/src/shrpx.cc +++ b/src/shrpx.cc @@ -351,6 +351,9 @@ void fill_default_config() mod_config()->backlog = 256; mod_config()->ciphers = 0; + + mod_config()->client_proxy = false; + mod_config()->client = false; mod_config()->client_mode = false; } } // namespace @@ -358,12 +361,9 @@ void fill_default_config() namespace { void print_usage(std::ostream& out) { - out << "Usage: shrpx [-Dhs] [-b ] [-f ] [-n ]\n" - << " [-c ] [-L ] [OPTIONS...]\n" - << " \n" - << "\n" - << " shrpx --client-mode [-Dh] [-b ] [-f ]\n" - << " [-n ] [-c ] [-L ] [OPTIONS...]\n" + out << "Usage: shrpx [-Dh] [-s|--client|-p] [-b ]\n" + << " [-f ] [-n ] [-c ] [-L ]\n" + << " [OPTIONS...] \n" << "\n" << "A reverse proxy for SPDY/HTTPS.\n" << std::endl; @@ -401,6 +401,14 @@ void print_help(std::ostream& out) << " -D, --daemon Run in a background. If -D is used, the\n" << " current working directory is changed to '/'.\n" << " -s, --spdy-proxy SSL/SPDY proxy mode.\n" + << " --client Instead of accepting SPDY/HTTPS connection,\n" + << " accept HTTP connection and communicate with\n" + << " backend server in SPDY. To use shrpx as\n" + << " a forward proxy, use -p option instead.\n" + << " -p, --client-proxy Like --client option, but it also requires\n" + << " the request path from frontend must be\n" + << " an absolute URI, suitable for use as a\n" + << " forward proxy." << " --add-x-forwarded-for\n" << " Append X-Forwarded-For header field to the\n" << " downstream request.\n" @@ -451,10 +459,6 @@ void print_help(std::ostream& out) << get_config()->backlog << "\n" << " --ciphers= Set allowed cipher list. The format of the\n" << " string is described in OpenSSL ciphers(1).\n" - << " --client-mode Instead of accepting SPDY/HTTPS connection,\n" - << " accept HTTP connection and communicate with\n" - << " backend server in SPDY. This is for testing\n" - << " purpose.\n" << " -h, --help Print this help.\n" << std::endl; } @@ -477,6 +481,7 @@ int main(int argc, char **argv) {"log-level", required_argument, 0, 'L' }, {"daemon", no_argument, 0, 'D' }, {"spdy-proxy", no_argument, 0, 's' }, + {"client-proxy", no_argument, 0, 'p' }, {"add-x-forwarded-for", no_argument, &flag, 1 }, {"frontend-spdy-read-timeout", required_argument, &flag, 2 }, {"frontend-read-timeout", required_argument, &flag, 3 }, @@ -493,12 +498,12 @@ int main(int argc, char **argv) {"syslog-facility", required_argument, &flag, 14 }, {"backlog", required_argument, &flag, 15 }, {"ciphers", required_argument, &flag, 16 }, - {"client-mode", no_argument, &flag, 17 }, + {"client", no_argument, &flag, 17 }, {"help", no_argument, 0, 'h' }, {0, 0, 0, 0 } }; int option_index = 0; - int c = getopt_long(argc, argv, "DL:sb:c:f:n:h", long_options, + int c = getopt_long(argc, argv, "DL:sb:c:f:n:hp", long_options, &option_index); if(c == -1) { break; @@ -529,6 +534,9 @@ int main(int argc, char **argv) case 's': cmdcfgs.push_back(std::make_pair(SHRPX_OPT_SPDY_PROXY, "yes")); break; + case 'p': + cmdcfgs.push_back(std::make_pair(SHRPX_OPT_CLIENT_PROXY, "yes")); + break; case '?': exit(EXIT_FAILURE); case 0: @@ -603,8 +611,8 @@ int main(int argc, char **argv) cmdcfgs.push_back(std::make_pair(SHRPX_OPT_CIPHERS, optarg)); break; case 17: - // --client-mode - cmdcfgs.push_back(std::make_pair(SHRPX_OPT_CLIENT_MODE, "yes")); + // --client + cmdcfgs.push_back(std::make_pair(SHRPX_OPT_CLIENT, "yes")); break; default: break; @@ -637,6 +645,18 @@ int main(int argc, char **argv) } } + int mode = get_config()->spdy_proxy | + (get_config()->client_proxy << 1) | (get_config()->client << 2); + if(mode != 0 && mode != 1 && mode != 2 && mode != 4) { + LOG(FATAL) << "--spdy-proxy, --client-proxy and --client cannot be used " + << "at the same time."; + exit(EXIT_FAILURE); + } + + if(get_config()->client || get_config()->client_proxy) { + mod_config()->client_mode = true; + } + if(!get_config()->client_mode) { if(!get_config()->private_key_file || !get_config()->cert_file) { print_usage(std::cerr); @@ -645,12 +665,6 @@ int main(int argc, char **argv) } } - if(get_config()->spdy_proxy && get_config()->client_mode) { - LOG(FATAL) << "--spdy-proxy and --client-mode cannot be used " - << "at the same time."; - exit(EXIT_FAILURE); - } - char hostport[NI_MAXHOST+16]; bool downstream_ipv6_addr = is_ipv6_numeric_addr(get_config()->downstream_host); diff --git a/src/shrpx_config.cc b/src/shrpx_config.cc index dd285e65..0035a526 100644 --- a/src/shrpx_config.cc +++ b/src/shrpx_config.cc @@ -51,6 +51,7 @@ SHRPX_OPT_SPDY_MAX_CONCURRENT_STREAMS[] = "spdy-max-concurrent-streams"; const char SHRPX_OPT_LOG_LEVEL[] = "log-level"; const char SHRPX_OPT_DAEMON[] = "daemon"; const char SHRPX_OPT_SPDY_PROXY[] = "spdy-proxy"; +const char SHRPX_OPT_CLIENT_PROXY[] = "client-proxy"; const char SHRPX_OPT_ADD_X_FORWARDED_FOR[] = "add-x-forwarded-for"; const char SHRPX_OPT_FRONTEND_SPDY_READ_TIMEOUT[] = "frontend-spdy-read-timeout"; @@ -68,7 +69,7 @@ const char SHRPX_OPT_SYSLOG[] = "syslog"; const char SHRPX_OPT_SYSLOG_FACILITY[] = "syslog-facility"; const char SHRPX_OPT_BACKLOG[] = "backlog"; const char SHRPX_OPT_CIPHERS[] = "ciphers"; -const char SHRPX_OPT_CLIENT_MODE[] = "client-mode"; +const char SHRPX_OPT_CLIENT[] = "client"; Config::Config() : verbose(false), @@ -86,6 +87,7 @@ Config::Config() num_worker(0), spdy_max_concurrent_streams(0), spdy_proxy(false), + client_proxy(false), add_x_forwarded_for(false), accesslog(false), spdy_upstream_window_bits(0), @@ -98,6 +100,7 @@ Config::Config() use_syslog(false), backlog(0), ciphers(0), + client(false), client_mode(false) {} @@ -189,6 +192,8 @@ int parse_config(const char *opt, const char *optarg) mod_config()->daemon = util::strieq(optarg, "yes"); } else if(util::strieq(opt, SHRPX_OPT_SPDY_PROXY)) { mod_config()->spdy_proxy = util::strieq(optarg, "yes"); + } else if(util::strieq(opt, SHRPX_OPT_CLIENT_PROXY)) { + mod_config()->client_proxy = util::strieq(optarg, "yes"); } else if(util::strieq(opt, SHRPX_OPT_ADD_X_FORWARDED_FOR)) { mod_config()->add_x_forwarded_for = util::strieq(optarg, "yes"); } else if(util::strieq(opt, SHRPX_OPT_FRONTEND_SPDY_READ_TIMEOUT)) { @@ -248,8 +253,8 @@ int parse_config(const char *opt, const char *optarg) mod_config()->backlog = strtol(optarg, 0, 10); } else if(util::strieq(opt, SHRPX_OPT_CIPHERS)) { set_config_str(&mod_config()->ciphers, optarg); - } else if(util::strieq(opt, SHRPX_OPT_CLIENT_MODE)) { - mod_config()->client_mode = util::strieq(optarg, "yes"); + } else if(util::strieq(opt, SHRPX_OPT_CLIENT)) { + mod_config()->client = util::strieq(optarg, "yes"); } else if(util::strieq(opt, "conf")) { LOG(WARNING) << "conf is ignored"; } else { diff --git a/src/shrpx_config.h b/src/shrpx_config.h index 1ba9a19f..5eb1934a 100644 --- a/src/shrpx_config.h +++ b/src/shrpx_config.h @@ -45,6 +45,7 @@ extern const char SHRPX_OPT_SPDY_MAX_CONCURRENT_STREAMS[]; extern const char SHRPX_OPT_LOG_LEVEL[]; extern const char SHRPX_OPT_DAEMON[]; extern const char SHRPX_OPT_SPDY_PROXY[]; +extern const char SHRPX_OPT_CLIENT_PROXY[]; extern const char SHRPX_OPT_ADD_X_FORWARDED_FOR[]; extern const char SHRPX_OPT_FRONTEND_SPDY_READ_TIMEOUT[]; extern const char SHRPX_OPT_FRONTEND_READ_TIMEOUT[]; @@ -60,7 +61,7 @@ extern const char SHRPX_OPT_SYSLOG[]; extern const char SHRPX_OPT_SYSLOG_FACILITY[]; extern const char SHRPX_OPT_BACKLOG[]; extern const char SHRPX_OPT_CIPHERS[]; -extern const char SHRPX_OPT_CLIENT_MODE[]; +extern const char SHRPX_OPT_CLIENT[]; union sockaddr_union { sockaddr sa; @@ -92,6 +93,7 @@ struct Config { size_t num_worker; size_t spdy_max_concurrent_streams; bool spdy_proxy; + bool client_proxy; bool add_x_forwarded_for; bool accesslog; size_t spdy_upstream_window_bits; @@ -105,6 +107,8 @@ struct Config { bool use_syslog; int backlog; char *ciphers; + bool client; + // true if --client or --client-proxy are enabled. bool client_mode; Config(); }; diff --git a/src/shrpx_https_upstream.cc b/src/shrpx_https_upstream.cc index d6c3a50c..651e9e9a 100644 --- a/src/shrpx_https_upstream.cc +++ b/src/shrpx_https_upstream.cc @@ -126,6 +126,7 @@ int htp_hdr_valcb(http_parser *htp, const char *data, size_t len) namespace { int htp_hdrs_completecb(http_parser *htp) { + int rv; HttpsUpstream *upstream; upstream = reinterpret_cast(htp->data); if(ENABLE_LOG) { @@ -139,6 +140,21 @@ int htp_hdrs_completecb(http_parser *htp) downstream->set_request_connection_close(!http_should_keep_alive(htp)); + if(get_config()->client_proxy && + downstream->get_request_method() != "CONNECT") { + // Make sure that request path is an absolute URI. + http_parser_url u; + const char *url = downstream->get_request_path().c_str(); + memset(&u, 0, sizeof(u)); + rv = http_parser_parse_url(url, + downstream->get_request_path().size(), + 0, &u); + if(rv != 0 || !(u.field_set & (1 << UF_SCHEMA))) { + // Expect to respond with 400 bad request + return -1; + } + } + DownstreamConnection *dconn; dconn = upstream->get_client_handler()->get_downstream_connection(); @@ -151,7 +167,7 @@ int htp_hdrs_completecb(http_parser *htp) } } - int rv = dconn->attach_downstream(downstream); + rv = dconn->attach_downstream(downstream); if(rv != 0) { downstream->set_request_state(Downstream::CONNECT_FAIL); downstream->set_downstream_connection(0);