shprx: Add --backend-http-proxy-uri option
Specify proxy URI in the form http://[USER:PASS]PROXY:PORT. USER and PASS are optional and if they exist they must be properly percent-encoded. This proxy is used when the backend connection is SPDY. First, make a CONNECT request to the proxy and it connects to the backend on behalf of shrpx. This forms tunnel. After that, shrpx performs SSL/TLS handshake with the downstream through the tunnel. The timeouts when connecting and making CONNECT request can be specified by --backend-read-timeout and --backend-write-timeout options.
This commit is contained in:
parent
9ba19df813
commit
cb8b8050b5
|
@ -0,0 +1,179 @@
|
||||||
|
/*
|
||||||
|
* Spdylay - SPDY Library
|
||||||
|
*
|
||||||
|
* Copyright (c) 2013 Tatsuhiro Tsujikawa
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
* a copy of this software and associated documentation files (the
|
||||||
|
* "Software"), to deal in the Software without restriction, including
|
||||||
|
* without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
* permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
* the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#ifndef BASE64_H
|
||||||
|
#define BASE64_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace spdylay {
|
||||||
|
|
||||||
|
namespace base64 {
|
||||||
|
|
||||||
|
template<typename InputIterator>
|
||||||
|
std::string encode(InputIterator first, InputIterator last)
|
||||||
|
{
|
||||||
|
static const char CHAR_TABLE[] = {
|
||||||
|
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
|
||||||
|
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
|
||||||
|
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
|
||||||
|
'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
|
||||||
|
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
|
||||||
|
'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
|
||||||
|
'w', 'x', 'y', 'z', '0', '1', '2', '3',
|
||||||
|
'4', '5', '6', '7', '8', '9', '+', '/',
|
||||||
|
};
|
||||||
|
std::string res;
|
||||||
|
size_t len = last-first;
|
||||||
|
if(len == 0) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
size_t r = len%3;
|
||||||
|
InputIterator j = last-r;
|
||||||
|
char temp[4];
|
||||||
|
while(first != j) {
|
||||||
|
int n = static_cast<unsigned char>(*first++) << 16;
|
||||||
|
n += static_cast<unsigned char>(*first++) << 8;
|
||||||
|
n += static_cast<unsigned char>(*first++);
|
||||||
|
temp[0] = CHAR_TABLE[n >> 18];
|
||||||
|
temp[1] = CHAR_TABLE[(n >> 12) & 0x3fu];
|
||||||
|
temp[2] = CHAR_TABLE[(n >> 6) & 0x3fu];
|
||||||
|
temp[3] = CHAR_TABLE[n & 0x3fu];
|
||||||
|
res.append(temp, sizeof(temp));
|
||||||
|
}
|
||||||
|
if(r == 2) {
|
||||||
|
int n = static_cast<unsigned char>(*first++) << 16;
|
||||||
|
n += static_cast<unsigned char>(*first++) << 8;
|
||||||
|
temp[0] = CHAR_TABLE[n >> 18];
|
||||||
|
temp[1] = CHAR_TABLE[(n >> 12) & 0x3fu];
|
||||||
|
temp[2] = CHAR_TABLE[(n >> 6) & 0x3fu];
|
||||||
|
temp[3] = '=';
|
||||||
|
res.append(temp, sizeof(temp));
|
||||||
|
} else if(r == 1) {
|
||||||
|
int n = static_cast<unsigned char>(*first++) << 16;
|
||||||
|
temp[0] = CHAR_TABLE[n >> 18];
|
||||||
|
temp[1] = CHAR_TABLE[(n >> 12) & 0x3fu];
|
||||||
|
temp[2] = '=';
|
||||||
|
temp[3] = '=';
|
||||||
|
res.append(temp, sizeof(temp));
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename InputIterator>
|
||||||
|
InputIterator getNext
|
||||||
|
(InputIterator first,
|
||||||
|
InputIterator last,
|
||||||
|
const int* tbl)
|
||||||
|
{
|
||||||
|
for(; first != last; ++first) {
|
||||||
|
if(tbl[static_cast<size_t>(*first)] != -1 || *first == '=') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return first;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename InputIterator>
|
||||||
|
std::string decode(InputIterator first, InputIterator last)
|
||||||
|
{
|
||||||
|
static const int INDEX_TABLE[] = {
|
||||||
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||||
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||||
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
|
||||||
|
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
|
||||||
|
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
|
||||||
|
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
|
||||||
|
-1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
|
||||||
|
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
|
||||||
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||||
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||||
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||||
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||||
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||||
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||||
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||||
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
|
||||||
|
};
|
||||||
|
std::string res;
|
||||||
|
InputIterator k[4];
|
||||||
|
int eq = 0;
|
||||||
|
for(; first != last;) {
|
||||||
|
for(int i = 1; i <= 4; ++i) {
|
||||||
|
k[i-1] = getNext(first, last, INDEX_TABLE);
|
||||||
|
if(k[i-1] == last) {
|
||||||
|
// If i == 1, input may look like this: "TWFu\n" (i.e.,
|
||||||
|
// garbage at the end)
|
||||||
|
if(i != 1) {
|
||||||
|
res.clear();
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
} else if(*k[i-1] == '=' && eq == 0) {
|
||||||
|
eq = i;
|
||||||
|
}
|
||||||
|
first = k[i-1]+1;
|
||||||
|
}
|
||||||
|
if(eq) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
int n = (INDEX_TABLE[static_cast<unsigned char>(*k[0])] << 18)+
|
||||||
|
(INDEX_TABLE[static_cast<unsigned char>(*k[1])] << 12)+
|
||||||
|
(INDEX_TABLE[static_cast<unsigned char>(*k[2])] << 6)+
|
||||||
|
INDEX_TABLE[static_cast<unsigned char>(*k[3])];
|
||||||
|
res += n >> 16;
|
||||||
|
res += n >> 8 & 0xffu;
|
||||||
|
res += n & 0xffu;
|
||||||
|
}
|
||||||
|
if(eq) {
|
||||||
|
if(eq <= 2) {
|
||||||
|
res.clear();
|
||||||
|
return res;
|
||||||
|
} else {
|
||||||
|
for(int i = eq; i <= 4; ++i) {
|
||||||
|
if(*k[i-1] != '=') {
|
||||||
|
res.clear();
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(eq == 3) {
|
||||||
|
int n = (INDEX_TABLE[static_cast<unsigned char>(*k[0])] << 18)+
|
||||||
|
(INDEX_TABLE[static_cast<unsigned char>(*k[1])] << 12);
|
||||||
|
res += n >> 16;
|
||||||
|
} else if(eq == 4) {
|
||||||
|
int n = (INDEX_TABLE[static_cast<unsigned char>(*k[0])] << 18)+
|
||||||
|
(INDEX_TABLE[static_cast<unsigned char>(*k[1])] << 12)+
|
||||||
|
(INDEX_TABLE[static_cast<unsigned char>(*k[2])] << 6);
|
||||||
|
res += n >> 16;
|
||||||
|
res += n >> 8 & 0xffu;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace base64
|
||||||
|
|
||||||
|
} // namespace spdylay
|
||||||
|
|
||||||
|
#endif // BASE64_H
|
100
src/shrpx.cc
100
src/shrpx.cc
|
@ -73,32 +73,28 @@ bool is_ipv6_numeric_addr(const char *host)
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
int cache_downstream_host_address()
|
int resolve_hostname(sockaddr_union *addr, size_t *addrlen,
|
||||||
|
const char *hostname, uint16_t port, int family)
|
||||||
{
|
{
|
||||||
addrinfo hints;
|
addrinfo hints;
|
||||||
int rv;
|
int rv;
|
||||||
char service[10];
|
char service[10];
|
||||||
|
|
||||||
snprintf(service, sizeof(service), "%u", get_config()->downstream_port);
|
snprintf(service, sizeof(service), "%u", port);
|
||||||
memset(&hints, 0, sizeof(addrinfo));
|
memset(&hints, 0, sizeof(addrinfo));
|
||||||
|
|
||||||
if(get_config()->backend_ipv4) {
|
hints.ai_family = family;
|
||||||
hints.ai_family = AF_INET;
|
|
||||||
} else if(get_config()->backend_ipv6) {
|
|
||||||
hints.ai_family = AF_INET6;
|
|
||||||
} else {
|
|
||||||
hints.ai_family = AF_UNSPEC;
|
|
||||||
}
|
|
||||||
hints.ai_socktype = SOCK_STREAM;
|
hints.ai_socktype = SOCK_STREAM;
|
||||||
#ifdef AI_ADDRCONFIG
|
#ifdef AI_ADDRCONFIG
|
||||||
hints.ai_flags |= AI_ADDRCONFIG;
|
hints.ai_flags |= AI_ADDRCONFIG;
|
||||||
#endif // AI_ADDRCONFIG
|
#endif // AI_ADDRCONFIG
|
||||||
addrinfo *res;
|
addrinfo *res;
|
||||||
|
|
||||||
rv = getaddrinfo(get_config()->downstream_host, service, &hints, &res);
|
rv = getaddrinfo(hostname, service, &hints, &res);
|
||||||
if(rv != 0) {
|
if(rv != 0) {
|
||||||
LOG(FATAL) << "Unable to get downstream address: " << gai_strerror(rv);
|
LOG(FATAL) << "Unable to resolve address for " << hostname
|
||||||
DIE();
|
<< ": " << gai_strerror(rv);
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
char host[NI_MAXHOST];
|
char host[NI_MAXHOST];
|
||||||
|
@ -106,17 +102,16 @@ int cache_downstream_host_address()
|
||||||
0, 0, NI_NUMERICHOST);
|
0, 0, NI_NUMERICHOST);
|
||||||
if(rv == 0) {
|
if(rv == 0) {
|
||||||
if(LOG_ENABLED(INFO)) {
|
if(LOG_ENABLED(INFO)) {
|
||||||
LOG(INFO) << "Using first returned address for downstream "
|
LOG(INFO) << "Address resolution for " << hostname << " succeeded: "
|
||||||
<< host
|
<< host;
|
||||||
<< ", port "
|
|
||||||
<< get_config()->downstream_port;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
LOG(FATAL) << gai_strerror(rv);
|
LOG(FATAL) << "Address resolution for " << hostname << " failed: "
|
||||||
DIE();
|
<< gai_strerror(rv);
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
memcpy(&mod_config()->downstream_addr, res->ai_addr, res->ai_addrlen);
|
memcpy(addr, res->ai_addr, res->ai_addrlen);
|
||||||
mod_config()->downstream_addrlen = res->ai_addrlen;
|
*addrlen = res->ai_addrlen;
|
||||||
freeaddrinfo(res);
|
freeaddrinfo(res);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -386,6 +381,10 @@ void fill_default_config()
|
||||||
mod_config()->backend_ipv6 = false;
|
mod_config()->backend_ipv6 = false;
|
||||||
mod_config()->tty = isatty(fileno(stderr));
|
mod_config()->tty = isatty(fileno(stderr));
|
||||||
mod_config()->cert_tree = 0;
|
mod_config()->cert_tree = 0;
|
||||||
|
mod_config()->downstream_http_proxy_userinfo = 0;
|
||||||
|
mod_config()->downstream_http_proxy_host = 0;
|
||||||
|
mod_config()->downstream_http_proxy_port = 0;
|
||||||
|
mod_config()->downstream_http_proxy_addrlen = 0;
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
@ -470,6 +469,20 @@ void print_help(std::ostream& out)
|
||||||
<< " Specify keep-alive timeout for backend\n"
|
<< " Specify keep-alive timeout for backend\n"
|
||||||
<< " connection. Default: "
|
<< " connection. Default: "
|
||||||
<< get_config()->downstream_idle_read_timeout.tv_sec << "\n"
|
<< get_config()->downstream_idle_read_timeout.tv_sec << "\n"
|
||||||
|
<< " --backend-http-proxy-uri=<URI>\n"
|
||||||
|
<< " Specify proxy URI in the form\n"
|
||||||
|
<< " http://[USER:PASS]PROXY:PORT. USER and PASS\n"
|
||||||
|
<< " are optional and if they exist they must be\n"
|
||||||
|
<< " properly percent-encoded. This proxy is used\n"
|
||||||
|
<< " when the backend connection is SPDY. First,\n"
|
||||||
|
<< " make a CONNECT request to the proxy and\n"
|
||||||
|
<< " it connects to the backend on behalf of\n"
|
||||||
|
<< " shrpx. This forms tunnel. After that, shrpx\n"
|
||||||
|
<< " performs SSL/TLS handshake with the\n"
|
||||||
|
<< " downstream through the tunnel. The timeouts\n"
|
||||||
|
<< " when connecting and making CONNECT request\n"
|
||||||
|
<< " can be specified by --backend-read-timeout\n"
|
||||||
|
<< " and --backend-write-timeout options.\n"
|
||||||
<< "\n"
|
<< "\n"
|
||||||
<< " SSL/TLS:\n"
|
<< " SSL/TLS:\n"
|
||||||
<< " --ciphers=<SUITE> Set allowed cipher list. The format of the\n"
|
<< " --ciphers=<SUITE> Set allowed cipher list. The format of the\n"
|
||||||
|
@ -602,6 +615,7 @@ int main(int argc, char **argv)
|
||||||
{"no-via", no_argument, &flag, 23},
|
{"no-via", no_argument, &flag, 23},
|
||||||
{"subcert", required_argument, &flag, 24},
|
{"subcert", required_argument, &flag, 24},
|
||||||
{"spdy-bridge", no_argument, &flag, 25},
|
{"spdy-bridge", no_argument, &flag, 25},
|
||||||
|
{"backend-http-proxy-uri", required_argument, &flag, 26},
|
||||||
{0, 0, 0, 0 }
|
{0, 0, 0, 0 }
|
||||||
};
|
};
|
||||||
int option_index = 0;
|
int option_index = 0;
|
||||||
|
@ -756,6 +770,11 @@ int main(int argc, char **argv)
|
||||||
// --spdy-bridge
|
// --spdy-bridge
|
||||||
cmdcfgs.push_back(std::make_pair(SHRPX_OPT_SPDY_BRIDGE, "yes"));
|
cmdcfgs.push_back(std::make_pair(SHRPX_OPT_SPDY_BRIDGE, "yes"));
|
||||||
break;
|
break;
|
||||||
|
case 26:
|
||||||
|
// --backend-http-proxy-uri
|
||||||
|
cmdcfgs.push_back(std::make_pair(SHRPX_OPT_BACKEND_HTTP_PROXY_URI,
|
||||||
|
optarg));
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -822,24 +841,39 @@ int main(int argc, char **argv)
|
||||||
char hostport[NI_MAXHOST+16];
|
char hostport[NI_MAXHOST+16];
|
||||||
bool downstream_ipv6_addr =
|
bool downstream_ipv6_addr =
|
||||||
is_ipv6_numeric_addr(get_config()->downstream_host);
|
is_ipv6_numeric_addr(get_config()->downstream_host);
|
||||||
if(get_config()->downstream_port == 80) {
|
snprintf(hostport, sizeof(hostport), "%s%s%s:%u",
|
||||||
snprintf(hostport, sizeof(hostport), "%s%s%s",
|
downstream_ipv6_addr ? "[" : "",
|
||||||
downstream_ipv6_addr ? "[" : "",
|
get_config()->downstream_host,
|
||||||
get_config()->downstream_host,
|
downstream_ipv6_addr ? "]" : "",
|
||||||
downstream_ipv6_addr ? "]" : "");
|
get_config()->downstream_port);
|
||||||
} else {
|
|
||||||
snprintf(hostport, sizeof(hostport), "%s%s%s:%u",
|
|
||||||
downstream_ipv6_addr ? "[" : "",
|
|
||||||
get_config()->downstream_host,
|
|
||||||
downstream_ipv6_addr ? "]" : "",
|
|
||||||
get_config()->downstream_port);
|
|
||||||
}
|
|
||||||
set_config_str(&mod_config()->downstream_hostport, hostport);
|
set_config_str(&mod_config()->downstream_hostport, hostport);
|
||||||
|
|
||||||
if(cache_downstream_host_address() == -1) {
|
if(LOG_ENABLED(INFO)) {
|
||||||
|
LOG(INFO) << "Resolving backend address";
|
||||||
|
}
|
||||||
|
if(resolve_hostname(&mod_config()->downstream_addr,
|
||||||
|
&mod_config()->downstream_addrlen,
|
||||||
|
get_config()->downstream_host,
|
||||||
|
get_config()->downstream_port,
|
||||||
|
get_config()->backend_ipv4 ? AF_INET :
|
||||||
|
(get_config()->backend_ipv6 ?
|
||||||
|
AF_INET6 : AF_UNSPEC)) == -1) {
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(get_config()->downstream_http_proxy_host) {
|
||||||
|
if(LOG_ENABLED(INFO)) {
|
||||||
|
LOG(INFO) << "Resolving backend http proxy address";
|
||||||
|
}
|
||||||
|
if(resolve_hostname(&mod_config()->downstream_http_proxy_addr,
|
||||||
|
&mod_config()->downstream_http_proxy_addrlen,
|
||||||
|
get_config()->downstream_http_proxy_host,
|
||||||
|
get_config()->downstream_http_proxy_port,
|
||||||
|
AF_UNSPEC) == -1) {
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(get_config()->syslog) {
|
if(get_config()->syslog) {
|
||||||
openlog("shrpx", LOG_NDELAY | LOG_NOWAIT | LOG_PID,
|
openlog("shrpx", LOG_NDELAY | LOG_NOWAIT | LOG_PID,
|
||||||
get_config()->syslog_facility);
|
get_config()->syslog_facility);
|
||||||
|
|
|
@ -38,6 +38,7 @@
|
||||||
|
|
||||||
#include "shrpx_log.h"
|
#include "shrpx_log.h"
|
||||||
#include "shrpx_ssl.h"
|
#include "shrpx_ssl.h"
|
||||||
|
#include "shrpx_http.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
using namespace spdylay;
|
using namespace spdylay;
|
||||||
|
@ -83,6 +84,7 @@ const char SHRPX_OPT_INSECURE[] = "insecure";
|
||||||
const char SHRPX_OPT_CACERT[] = "cacert";
|
const char SHRPX_OPT_CACERT[] = "cacert";
|
||||||
const char SHRPX_OPT_BACKEND_IPV4[] = "backend-ipv4";
|
const char SHRPX_OPT_BACKEND_IPV4[] = "backend-ipv4";
|
||||||
const char SHRPX_OPT_BACKEND_IPV6[] = "backend-ipv6";
|
const char SHRPX_OPT_BACKEND_IPV6[] = "backend-ipv6";
|
||||||
|
const char SHRPX_OPT_BACKEND_HTTP_PROXY_URI[] = "backend-http-proxy-uri";
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
Config *config = 0;
|
Config *config = 0;
|
||||||
|
@ -317,6 +319,36 @@ int parse_config(const char *opt, const char *optarg)
|
||||||
mod_config()->backend_ipv4 = util::strieq(optarg, "yes");
|
mod_config()->backend_ipv4 = util::strieq(optarg, "yes");
|
||||||
} else if(util::strieq(opt, SHRPX_OPT_BACKEND_IPV6)) {
|
} else if(util::strieq(opt, SHRPX_OPT_BACKEND_IPV6)) {
|
||||||
mod_config()->backend_ipv6 = util::strieq(optarg, "yes");
|
mod_config()->backend_ipv6 = util::strieq(optarg, "yes");
|
||||||
|
} else if(util::strieq(opt, SHRPX_OPT_BACKEND_HTTP_PROXY_URI)) {
|
||||||
|
// parse URI and get hostname, port and optionally userinfo.
|
||||||
|
http_parser_url u;
|
||||||
|
memset(&u, 0, sizeof(u));
|
||||||
|
int rv = http_parser_parse_url(optarg, strlen(optarg), 0, &u);
|
||||||
|
if(rv == 0) {
|
||||||
|
std::string val;
|
||||||
|
if(u.field_set & UF_USERINFO) {
|
||||||
|
http::copy_url_component(val, &u, UF_USERINFO, optarg);
|
||||||
|
val = util::percentDecode(val.begin(), val.end());
|
||||||
|
set_config_str(&mod_config()->downstream_http_proxy_userinfo,
|
||||||
|
val.c_str());
|
||||||
|
}
|
||||||
|
if(u.field_set & UF_HOST) {
|
||||||
|
http::copy_url_component(val, &u, UF_HOST, optarg);
|
||||||
|
set_config_str(&mod_config()->downstream_http_proxy_host, val.c_str());
|
||||||
|
} else {
|
||||||
|
LOG(ERROR) << "backend-http-proxy-uri does not contain hostname";
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if(u.field_set & UF_PORT) {
|
||||||
|
mod_config()->downstream_http_proxy_port = u.port;
|
||||||
|
} else {
|
||||||
|
LOG(ERROR) << "backend-http-proxy-uri does not contain port";
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LOG(ERROR) << "Could not parse backend-http-proxy-uri";
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
} else if(util::strieq(opt, "conf")) {
|
} else if(util::strieq(opt, "conf")) {
|
||||||
LOG(WARNING) << "conf is ignored";
|
LOG(WARNING) << "conf is ignored";
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -79,6 +79,7 @@ extern const char SHRPX_OPT_INSECURE[];
|
||||||
extern const char SHRPX_OPT_CACERT[];
|
extern const char SHRPX_OPT_CACERT[];
|
||||||
extern const char SHRPX_OPT_BACKEND_IPV4[];
|
extern const char SHRPX_OPT_BACKEND_IPV4[];
|
||||||
extern const char SHRPX_OPT_BACKEND_IPV6[];
|
extern const char SHRPX_OPT_BACKEND_IPV6[];
|
||||||
|
extern const char SHRPX_OPT_BACKEND_HTTP_PROXY_URI[];
|
||||||
|
|
||||||
union sockaddr_union {
|
union sockaddr_union {
|
||||||
sockaddr sa;
|
sockaddr sa;
|
||||||
|
@ -139,6 +140,16 @@ struct Config {
|
||||||
bool backend_ipv6;
|
bool backend_ipv6;
|
||||||
// true if stderr refers to a terminal.
|
// true if stderr refers to a terminal.
|
||||||
bool tty;
|
bool tty;
|
||||||
|
// userinfo in http proxy URI, not percent-encoded form
|
||||||
|
char *downstream_http_proxy_userinfo;
|
||||||
|
// host in http proxy URI
|
||||||
|
char *downstream_http_proxy_host;
|
||||||
|
// port in http proxy URI
|
||||||
|
uint16_t downstream_http_proxy_port;
|
||||||
|
// binary form of http proxy host and port
|
||||||
|
sockaddr_union downstream_http_proxy_addr;
|
||||||
|
// actual size of downstream_http_proxy_addr
|
||||||
|
size_t downstream_http_proxy_addrlen;
|
||||||
};
|
};
|
||||||
|
|
||||||
const Config* get_config();
|
const Config* get_config();
|
||||||
|
|
|
@ -153,6 +153,14 @@ std::string colorizeHeaders(const char *hdrs)
|
||||||
return nhdrs;
|
return nhdrs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void copy_url_component(std::string& dest, http_parser_url *u, int field,
|
||||||
|
const char* url)
|
||||||
|
{
|
||||||
|
if(u->field_set & (1 << field)) {
|
||||||
|
dest.assign(url+u->field_data[field].off, u->field_data[field].len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace http
|
} // namespace http
|
||||||
|
|
||||||
} // namespace shrpx
|
} // namespace shrpx
|
||||||
|
|
|
@ -27,6 +27,8 @@
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include "http-parser/http_parser.h"
|
||||||
|
|
||||||
namespace shrpx {
|
namespace shrpx {
|
||||||
|
|
||||||
namespace http {
|
namespace http {
|
||||||
|
@ -42,6 +44,12 @@ void capitalize(std::string& s, size_t offset);
|
||||||
// Adds ANSI color codes to HTTP headers |hdrs|.
|
// Adds ANSI color codes to HTTP headers |hdrs|.
|
||||||
std::string colorizeHeaders(const char *hdrs);
|
std::string colorizeHeaders(const char *hdrs);
|
||||||
|
|
||||||
|
// Copies the |field| component value from |u| and |url| to the
|
||||||
|
// |dest|. If |u| does not have |field|, then this function does
|
||||||
|
// nothing.
|
||||||
|
void copy_url_component(std::string& dest, http_parser_url *u, int field,
|
||||||
|
const char* url);
|
||||||
|
|
||||||
} // namespace http
|
} // namespace http
|
||||||
|
|
||||||
} // namespace shrpx
|
} // namespace shrpx
|
||||||
|
|
|
@ -201,16 +201,6 @@ ssize_t spdy_data_read_callback(spdylay_session *session,
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
namespace {
|
|
||||||
void copy_url_component(std::string& dest, http_parser_url *u, int field,
|
|
||||||
const char* url)
|
|
||||||
{
|
|
||||||
if(u->field_set & (1 << field)) {
|
|
||||||
dest.assign(url+u->field_data[field].off, u->field_data[field].len);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
int SpdyDownstreamConnection::push_request_headers()
|
int SpdyDownstreamConnection::push_request_headers()
|
||||||
{
|
{
|
||||||
int rv;
|
int rv;
|
||||||
|
@ -243,9 +233,9 @@ int SpdyDownstreamConnection::push_request_headers()
|
||||||
downstream_->get_request_path().size(),
|
downstream_->get_request_path().size(),
|
||||||
0, &u);
|
0, &u);
|
||||||
if(rv == 0) {
|
if(rv == 0) {
|
||||||
copy_url_component(scheme, &u, UF_SCHEMA, url);
|
http::copy_url_component(scheme, &u, UF_SCHEMA, url);
|
||||||
copy_url_component(path, &u, UF_PATH, url);
|
http::copy_url_component(path, &u, UF_PATH, url);
|
||||||
copy_url_component(query, &u, UF_QUERY, url);
|
http::copy_url_component(query, &u, UF_QUERY, url);
|
||||||
if(path.empty()) {
|
if(path.empty()) {
|
||||||
path = "/";
|
path = "/";
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,6 +40,7 @@
|
||||||
#include "shrpx_client_handler.h"
|
#include "shrpx_client_handler.h"
|
||||||
#include "shrpx_ssl.h"
|
#include "shrpx_ssl.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
#include "base64.h"
|
||||||
|
|
||||||
using namespace spdylay;
|
using namespace spdylay;
|
||||||
|
|
||||||
|
@ -49,13 +50,15 @@ SpdySession::SpdySession(event_base *evbase, SSL_CTX *ssl_ctx)
|
||||||
: evbase_(evbase),
|
: evbase_(evbase),
|
||||||
ssl_ctx_(ssl_ctx),
|
ssl_ctx_(ssl_ctx),
|
||||||
ssl_(0),
|
ssl_(0),
|
||||||
|
fd_(-1),
|
||||||
session_(0),
|
session_(0),
|
||||||
bev_(0),
|
bev_(0),
|
||||||
state_(DISCONNECTED),
|
state_(DISCONNECTED),
|
||||||
notified_(false),
|
notified_(false),
|
||||||
wrbev_(0),
|
wrbev_(0),
|
||||||
rdbev_(0),
|
rdbev_(0),
|
||||||
flow_control_(false)
|
flow_control_(false),
|
||||||
|
proxy_htp_(0)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
SpdySession::~SpdySession()
|
SpdySession::~SpdySession()
|
||||||
|
@ -71,9 +74,7 @@ int SpdySession::disconnect()
|
||||||
spdylay_session_del(session_);
|
spdylay_session_del(session_);
|
||||||
session_ = 0;
|
session_ = 0;
|
||||||
|
|
||||||
int fd = -1;
|
|
||||||
if(ssl_) {
|
if(ssl_) {
|
||||||
fd = SSL_get_fd(ssl_);
|
|
||||||
SSL_shutdown(ssl_);
|
SSL_shutdown(ssl_);
|
||||||
}
|
}
|
||||||
if(bev_) {
|
if(bev_) {
|
||||||
|
@ -86,9 +87,15 @@ int SpdySession::disconnect()
|
||||||
}
|
}
|
||||||
ssl_ = 0;
|
ssl_ = 0;
|
||||||
|
|
||||||
if(fd != -1) {
|
if(fd_ != -1) {
|
||||||
shutdown(fd, SHUT_WR);
|
shutdown(fd_, SHUT_WR);
|
||||||
close(fd);
|
close(fd_);
|
||||||
|
fd_ = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(proxy_htp_) {
|
||||||
|
delete proxy_htp_;
|
||||||
|
proxy_htp_ = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
notified_ = false;
|
notified_ = false;
|
||||||
|
@ -227,7 +234,7 @@ void eventcb(bufferevent *bev, short events, void *ptr)
|
||||||
if(LOG_ENABLED(INFO)) {
|
if(LOG_ENABLED(INFO)) {
|
||||||
SSLOG(INFO, spdy) << "Connection established";
|
SSLOG(INFO, spdy) << "Connection established";
|
||||||
}
|
}
|
||||||
spdy->connected();
|
spdy->set_state(SpdySession::CONNECTED);
|
||||||
if((!get_config()->insecure && spdy->check_cert() != 0) ||
|
if((!get_config()->insecure && spdy->check_cert() != 0) ||
|
||||||
spdy->on_connect() != 0) {
|
spdy->on_connect() != 0) {
|
||||||
spdy->disconnect();
|
spdy->disconnect();
|
||||||
|
@ -258,6 +265,75 @@ void eventcb(bufferevent *bev, short events, void *ptr)
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
void proxy_readcb(bufferevent *bev, void *ptr)
|
||||||
|
{
|
||||||
|
SpdySession *spdy = reinterpret_cast<SpdySession*>(ptr);
|
||||||
|
if(spdy->on_read_proxy() == 0) {
|
||||||
|
switch(spdy->get_state()) {
|
||||||
|
case SpdySession::PROXY_CONNECTED:
|
||||||
|
// The current bufferevent is no longer necessary, so delete it
|
||||||
|
// here.
|
||||||
|
spdy->free_bev();
|
||||||
|
// Initiate SSL/TLS handshake through established tunnel.
|
||||||
|
spdy->initiate_connection();
|
||||||
|
break;
|
||||||
|
case SpdySession::PROXY_FAILED:
|
||||||
|
spdy->disconnect();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
spdy->disconnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
void proxy_eventcb(bufferevent *bev, short events, void *ptr)
|
||||||
|
{
|
||||||
|
SpdySession *spdy = reinterpret_cast<SpdySession*>(ptr);
|
||||||
|
if(events & BEV_EVENT_CONNECTED) {
|
||||||
|
if(LOG_ENABLED(INFO)) {
|
||||||
|
SSLOG(INFO, spdy) << "Connected to the proxy";
|
||||||
|
}
|
||||||
|
std::string req = "CONNECT ";
|
||||||
|
req += get_config()->downstream_hostport;
|
||||||
|
req += " HTTP/1.1\r\nHost: ";
|
||||||
|
req += get_config()->downstream_host;
|
||||||
|
req += "\r\n";
|
||||||
|
if(get_config()->downstream_http_proxy_userinfo) {
|
||||||
|
req += "Proxy-Authorization: Basic ";
|
||||||
|
size_t len = strlen(get_config()->downstream_http_proxy_userinfo);
|
||||||
|
req += base64::encode(get_config()->downstream_http_proxy_userinfo,
|
||||||
|
get_config()->downstream_http_proxy_userinfo+len);
|
||||||
|
req += "\r\n";
|
||||||
|
}
|
||||||
|
req += "\r\n";
|
||||||
|
if(LOG_ENABLED(INFO)) {
|
||||||
|
SSLOG(INFO, spdy) << "HTTP proxy request headers\n" << req;
|
||||||
|
}
|
||||||
|
if(bufferevent_write(bev, req.c_str(), req.size()) != 0) {
|
||||||
|
SSLOG(ERROR, spdy) << "bufferevent_write() failed";
|
||||||
|
spdy->disconnect();
|
||||||
|
}
|
||||||
|
} else if(events & BEV_EVENT_EOF) {
|
||||||
|
if(LOG_ENABLED(INFO)) {
|
||||||
|
SSLOG(INFO, spdy) << "Proxy EOF";
|
||||||
|
}
|
||||||
|
spdy->disconnect();
|
||||||
|
} else if(events & (BEV_EVENT_ERROR | BEV_EVENT_TIMEOUT)) {
|
||||||
|
if(LOG_ENABLED(INFO)) {
|
||||||
|
if(events & BEV_EVENT_ERROR) {
|
||||||
|
SSLOG(INFO, spdy) << "Network error";
|
||||||
|
} else {
|
||||||
|
SSLOG(INFO, spdy) << "Timeout";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
spdy->disconnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
int SpdySession::check_cert()
|
int SpdySession::check_cert()
|
||||||
{
|
{
|
||||||
return ssl::check_cert(ssl_);
|
return ssl::check_cert(ssl_);
|
||||||
|
@ -266,51 +342,138 @@ int SpdySession::check_cert()
|
||||||
int SpdySession::initiate_connection()
|
int SpdySession::initiate_connection()
|
||||||
{
|
{
|
||||||
int rv;
|
int rv;
|
||||||
assert(state_ == DISCONNECTED);
|
if(get_config()->downstream_http_proxy_host && state_ == DISCONNECTED) {
|
||||||
if(LOG_ENABLED(INFO)) {
|
if(LOG_ENABLED(INFO)) {
|
||||||
SSLOG(INFO, this) << "Connecting to downstream server";
|
SSLOG(INFO, this) << "Connecting to the proxy "
|
||||||
|
<< get_config()->downstream_http_proxy_host << ":"
|
||||||
|
<< get_config()->downstream_http_proxy_port;
|
||||||
|
}
|
||||||
|
bev_ = bufferevent_socket_new(evbase_, -1, BEV_OPT_DEFER_CALLBACKS);
|
||||||
|
bufferevent_enable(bev_, EV_READ);
|
||||||
|
bufferevent_set_timeouts(bev_, &get_config()->downstream_read_timeout,
|
||||||
|
&get_config()->downstream_write_timeout);
|
||||||
|
|
||||||
|
// No need to set writecb because we write the request when
|
||||||
|
// connected at once.
|
||||||
|
bufferevent_setcb(bev_, proxy_readcb, 0, proxy_eventcb, this);
|
||||||
|
rv = bufferevent_socket_connect
|
||||||
|
(bev_,
|
||||||
|
const_cast<sockaddr*>(&get_config()->downstream_http_proxy_addr.sa),
|
||||||
|
get_config()->downstream_http_proxy_addrlen);
|
||||||
|
if(rv != 0) {
|
||||||
|
SSLOG(ERROR, this) << "Failed to connect to the proxy "
|
||||||
|
<< get_config()->downstream_http_proxy_host << ":"
|
||||||
|
<< get_config()->downstream_http_proxy_port;
|
||||||
|
bufferevent_free(bev_);
|
||||||
|
bev_ = 0;
|
||||||
|
return SHRPX_ERR_NETWORK;
|
||||||
|
}
|
||||||
|
proxy_htp_ = new http_parser();
|
||||||
|
http_parser_init(proxy_htp_, HTTP_RESPONSE);
|
||||||
|
proxy_htp_->data = this;
|
||||||
|
|
||||||
|
state_ = PROXY_CONNECTING;
|
||||||
|
} else if(state_ == DISCONNECTED || state_ == PROXY_CONNECTED) {
|
||||||
|
if(LOG_ENABLED(INFO)) {
|
||||||
|
SSLOG(INFO, this) << "Connecting to downstream server";
|
||||||
|
}
|
||||||
|
|
||||||
|
ssl_ = SSL_new(ssl_ctx_);
|
||||||
|
if(!ssl_) {
|
||||||
|
SSLOG(ERROR, this) << "SSL_new() failed: "
|
||||||
|
<< ERR_error_string(ERR_get_error(), NULL);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!ssl::numeric_host(get_config()->downstream_host)) {
|
||||||
|
// TLS extensions: SNI. There is no documentation about the return
|
||||||
|
// code for this function (actually this is macro wrapping SSL_ctrl
|
||||||
|
// at the time of this writing).
|
||||||
|
SSL_set_tlsext_host_name(ssl_, get_config()->downstream_host);
|
||||||
|
}
|
||||||
|
// If state_ == PROXY_CONNECTED, we has connected to the proxy
|
||||||
|
// using fd_ and tunnel has been established.
|
||||||
|
bev_ = bufferevent_openssl_socket_new(evbase_, fd_, ssl_,
|
||||||
|
BUFFEREVENT_SSL_CONNECTING,
|
||||||
|
BEV_OPT_DEFER_CALLBACKS);
|
||||||
|
rv = bufferevent_socket_connect
|
||||||
|
(bev_,
|
||||||
|
// TODO maybe not thread-safe?
|
||||||
|
const_cast<sockaddr*>(&get_config()->downstream_addr.sa),
|
||||||
|
get_config()->downstream_addrlen);
|
||||||
|
if(rv != 0) {
|
||||||
|
bufferevent_free(bev_);
|
||||||
|
bev_ = 0;
|
||||||
|
return SHRPX_ERR_NETWORK;
|
||||||
|
}
|
||||||
|
|
||||||
|
bufferevent_setwatermark(bev_, EV_READ, 0, SHRPX_READ_WARTER_MARK);
|
||||||
|
bufferevent_enable(bev_, EV_READ);
|
||||||
|
bufferevent_setcb(bev_, readcb, writecb, eventcb, this);
|
||||||
|
// No timeout for SPDY session
|
||||||
|
|
||||||
|
state_ = CONNECTING;
|
||||||
|
} else {
|
||||||
|
// Unreachable
|
||||||
|
DIE();
|
||||||
}
|
}
|
||||||
|
|
||||||
ssl_ = SSL_new(ssl_ctx_);
|
|
||||||
if(!ssl_) {
|
|
||||||
SSLOG(ERROR, this) << "SSL_new() failed: "
|
|
||||||
<< ERR_error_string(ERR_get_error(), NULL);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!ssl::numeric_host(get_config()->downstream_host)) {
|
|
||||||
// TLS extensions: SNI. There is no documentation about the return
|
|
||||||
// code for this function (actually this is macro wrapping SSL_ctrl
|
|
||||||
// at the time of this writing).
|
|
||||||
SSL_set_tlsext_host_name(ssl_, get_config()->downstream_host);
|
|
||||||
}
|
|
||||||
|
|
||||||
bev_ = bufferevent_openssl_socket_new(evbase_, -1, ssl_,
|
|
||||||
BUFFEREVENT_SSL_CONNECTING,
|
|
||||||
BEV_OPT_DEFER_CALLBACKS);
|
|
||||||
rv = bufferevent_socket_connect
|
|
||||||
(bev_,
|
|
||||||
// TODO maybe not thread-safe?
|
|
||||||
const_cast<sockaddr*>(&get_config()->downstream_addr.sa),
|
|
||||||
get_config()->downstream_addrlen);
|
|
||||||
if(rv != 0) {
|
|
||||||
bufferevent_free(bev_);
|
|
||||||
bev_ = 0;
|
|
||||||
return SHRPX_ERR_NETWORK;
|
|
||||||
}
|
|
||||||
|
|
||||||
bufferevent_setwatermark(bev_, EV_READ, 0, SHRPX_READ_WARTER_MARK);
|
|
||||||
bufferevent_enable(bev_, EV_READ);
|
|
||||||
bufferevent_setcb(bev_, readcb, writecb, eventcb, this);
|
|
||||||
// No timeout for SPDY session
|
|
||||||
|
|
||||||
state_ = CONNECTING;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpdySession::connected()
|
void SpdySession::free_bev()
|
||||||
{
|
{
|
||||||
state_ = CONNECTED;
|
bufferevent_free(bev_);
|
||||||
|
bev_ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
int htp_hdrs_completecb(http_parser *htp)
|
||||||
|
{
|
||||||
|
SpdySession *spdy;
|
||||||
|
spdy = reinterpret_cast<SpdySession*>(htp->data);
|
||||||
|
// We just check status code here
|
||||||
|
if(htp->status_code == 200) {
|
||||||
|
if(LOG_ENABLED(INFO)) {
|
||||||
|
SSLOG(INFO, spdy) << "Tunneling success";
|
||||||
|
}
|
||||||
|
spdy->set_state(SpdySession::PROXY_CONNECTED);
|
||||||
|
} else {
|
||||||
|
SSLOG(WARNING, spdy) << "Tunneling failed";
|
||||||
|
spdy->set_state(SpdySession::PROXY_FAILED);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
http_parser_settings htp_hooks = {
|
||||||
|
0, /*http_cb on_message_begin;*/
|
||||||
|
0, /*http_data_cb on_url;*/
|
||||||
|
0, /*http_cb on_status_complete */
|
||||||
|
0, /*http_data_cb on_header_field;*/
|
||||||
|
0, /*http_data_cb on_header_value;*/
|
||||||
|
htp_hdrs_completecb, /*http_cb on_headers_complete;*/
|
||||||
|
0, /*http_data_cb on_body;*/
|
||||||
|
0 /*http_cb on_message_complete;*/
|
||||||
|
};
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
int SpdySession::on_read_proxy()
|
||||||
|
{
|
||||||
|
evbuffer *input = bufferevent_get_input(bev_);
|
||||||
|
unsigned char *mem = evbuffer_pullup(input, -1);
|
||||||
|
|
||||||
|
size_t nread = http_parser_execute(proxy_htp_, &htp_hooks,
|
||||||
|
reinterpret_cast<const char*>(mem),
|
||||||
|
evbuffer_get_length(input));
|
||||||
|
|
||||||
|
evbuffer_drain(input, nread);
|
||||||
|
http_errno htperr = HTTP_PARSER_ERRNO(proxy_htp_);
|
||||||
|
if(htperr == HPE_OK) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpdySession::add_downstream_connection(SpdyDownstreamConnection *dconn)
|
void SpdySession::add_downstream_connection(SpdyDownstreamConnection *dconn)
|
||||||
|
@ -928,4 +1091,9 @@ int SpdySession::get_state() const
|
||||||
return state_;
|
return state_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SpdySession::set_state(int state)
|
||||||
|
{
|
||||||
|
state_ = state;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace shrpx
|
} // namespace shrpx
|
||||||
|
|
|
@ -36,6 +36,8 @@
|
||||||
|
|
||||||
#include <spdylay/spdylay.h>
|
#include <spdylay/spdylay.h>
|
||||||
|
|
||||||
|
#include "http-parser/http_parser.h"
|
||||||
|
|
||||||
namespace shrpx {
|
namespace shrpx {
|
||||||
|
|
||||||
class SpdyDownstreamConnection;
|
class SpdyDownstreamConnection;
|
||||||
|
@ -55,7 +57,6 @@ public:
|
||||||
|
|
||||||
int disconnect();
|
int disconnect();
|
||||||
int initiate_connection();
|
int initiate_connection();
|
||||||
void connected();
|
|
||||||
|
|
||||||
void add_downstream_connection(SpdyDownstreamConnection *dconn);
|
void add_downstream_connection(SpdyDownstreamConnection *dconn);
|
||||||
void remove_downstream_connection(SpdyDownstreamConnection *dconn);
|
void remove_downstream_connection(SpdyDownstreamConnection *dconn);
|
||||||
|
@ -83,22 +84,36 @@ public:
|
||||||
int on_write();
|
int on_write();
|
||||||
int send();
|
int send();
|
||||||
|
|
||||||
|
int on_read_proxy();
|
||||||
|
|
||||||
void clear_notify();
|
void clear_notify();
|
||||||
void notify();
|
void notify();
|
||||||
|
|
||||||
bufferevent* get_bev() const;
|
bufferevent* get_bev() const;
|
||||||
|
void free_bev();
|
||||||
|
|
||||||
int get_state() const;
|
int get_state() const;
|
||||||
|
void set_state(int state);
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
|
// Disconnected
|
||||||
DISCONNECTED,
|
DISCONNECTED,
|
||||||
|
// Connecting proxy and making CONNECT request
|
||||||
|
PROXY_CONNECTING,
|
||||||
|
// Tunnel is established with proxy
|
||||||
|
PROXY_CONNECTED,
|
||||||
|
// Establishing tunnel is failed
|
||||||
|
PROXY_FAILED,
|
||||||
|
// Connecting to downstream and/or performing SSL/TLS handshake
|
||||||
CONNECTING,
|
CONNECTING,
|
||||||
|
// Connected to downstream
|
||||||
CONNECTED
|
CONNECTED
|
||||||
};
|
};
|
||||||
private:
|
private:
|
||||||
event_base *evbase_;
|
event_base *evbase_;
|
||||||
SSL_CTX *ssl_ctx_;
|
SSL_CTX *ssl_ctx_;
|
||||||
SSL *ssl_;
|
SSL *ssl_;
|
||||||
|
int fd_;
|
||||||
spdylay_session *session_;
|
spdylay_session *session_;
|
||||||
bufferevent *bev_;
|
bufferevent *bev_;
|
||||||
std::set<SpdyDownstreamConnection*> dconns_;
|
std::set<SpdyDownstreamConnection*> dconns_;
|
||||||
|
@ -108,6 +123,8 @@ private:
|
||||||
bufferevent *wrbev_;
|
bufferevent *wrbev_;
|
||||||
bufferevent *rdbev_;
|
bufferevent *rdbev_;
|
||||||
bool flow_control_;
|
bool flow_control_;
|
||||||
|
// Used to parse the response from HTTP proxy
|
||||||
|
http_parser *proxy_htp_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace shrpx
|
} // namespace shrpx
|
||||||
|
|
Loading…
Reference in New Issue