Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[5.1]Fix bug #5548 #5587

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
150 changes: 81 additions & 69 deletions core-tests/src/network/client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -217,34 +217,26 @@ TEST(client, shutdown_all) {
}

#ifdef SW_USE_OPENSSL
TEST(client, ssl_1) {
int ret;

TEST(client, ssl_1) {
bool connected = false;
bool closed = false;
swoole::String buf(65536);
String buf(65536);

swoole_event_init(SW_EVENTLOOP_WAIT_EXIT);

Client client(SW_SOCK_TCP, true);
client.enable_ssl_encrypt();
client.onConnect = [&connected](Client *cli) {
connected = true;
cli->send(cli,
SW_STRL("GET / HTTP/1.1\r\n"
"Host: www.baidu.com\r\n"
"Connection: close\r\n"
"User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/51.0.2704.106 Safari/537.36"
"\r\n\r\n"),
0);
cli->send(cli, SW_STRL(TEST_REQUEST_BAIDU), 0);
};

client.onError = [](Client *cli) {};
client.onClose = [&closed](Client *cli) { closed = true; };
client.onReceive = [&buf](Client *cli, const char *data, size_t length) { buf.append(data, length); };
ret = client.connect(&client, "www.baidu.com", 443, -1, 0);
ASSERT_EQ(ret, 0);

ASSERT_EQ(client.connect(&client, TEST_DOMAIN_BAIDU, 443, -1, 0), 0);

swoole_event_wait();

Expand All @@ -253,89 +245,109 @@ TEST(client, ssl_1) {
ASSERT_TRUE(buf.contains("Baidu"));
}


TEST(client, http_proxy) {
int ret;
static void proxy_async_test(Client &client, bool https) {
swoole_event_init(SW_EVENTLOOP_WAIT_EXIT);

bool connected = false;
bool closed = false;
swoole::String buf(65536);

swoole_event_init(SW_EVENTLOOP_WAIT_EXIT);
String buf(65536);

Client client(SW_SOCK_TCP, true);
client.enable_ssl_encrypt();
client.http_proxy = new HttpProxy();
client.http_proxy->proxy_host = std::string(TEST_HTTP_PROXY_HOST);
client.http_proxy->proxy_port = TEST_HTTP_PROXY_PORT;
if (https) {
client.enable_ssl_encrypt();
}

client.onConnect = [&connected](Client *cli) {
connected = true;
cli->send(cli,
SW_STRL("GET / HTTP/1.1\r\n"
"Host: www.baidu.com\r\n"
"Connection: close\r\n"
"User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/51.0.2704.106 Safari/537.36"
"\r\n\r\n"),
0);
cli->send(cli, SW_STRL(TEST_REQUEST_BAIDU), 0);
};

client.onError = [](Client *cli) {};
client.onClose = [&closed](Client *cli) { closed = true; };
client.onReceive = [&buf](Client *cli, const char *data, size_t length) { buf.append(data, length); };
ret = client.connect(&client, "www.baidu.com", 443, -1, 0);
ASSERT_EQ(ret, 0);

ASSERT_EQ(client.connect(&client, TEST_DOMAIN_BAIDU, https ? 443 : 80, -1, 0), 0);

swoole_event_wait();

ASSERT_TRUE(connected);
ASSERT_TRUE(closed);
ASSERT_TRUE(buf.contains("Baidu"));
ASSERT_TRUE(buf.contains("www.baidu.com"));
}

TEST(client, socks5_proxy) {
int ret;
static void proxy_sync_test(Client &client, bool https) {
String buf(65536);
if (https) {
client.enable_ssl_encrypt();
}

ASSERT_EQ(client.connect(&client, TEST_DOMAIN_BAIDU, https ? 443 : 80, -1, 0), 0);
ASSERT_GT(client.send(&client, SW_STRL(TEST_REQUEST_BAIDU), 0), 0);

while (true) {
char rbuf[4096];
auto nr = client.recv(&client, rbuf, sizeof(rbuf), 0);
if (nr <= 0) {
break;
}
buf.append(rbuf, nr);
}

ASSERT_TRUE(buf.contains("www.baidu.com"));
}

bool connected = false;
bool closed = false;
swoole::String buf(65536);
static void proxy_set_socks5_proxy(Client &client) {
client.socks5_proxy = create_socks5_proxy();
}

swoole_event_init(SW_EVENTLOOP_WAIT_EXIT);
static void proxy_set_http_proxy(Client &client) {
client.http_proxy = create_http_proxy();
}

TEST(client, https_get_async_with_http_proxy) {
Client client(SW_SOCK_TCP, true);
client.enable_ssl_encrypt();
proxy_set_http_proxy(client);
proxy_async_test(client, true);
}

client.socks5_proxy = new Socks5Proxy();
client.socks5_proxy->host = std::string("127.0.0.1");
client.socks5_proxy->port = 1080;
client.socks5_proxy->dns_tunnel = 1;
client.socks5_proxy->method = 0x02;
client.socks5_proxy->username = std::string("user");
client.socks5_proxy->password = std::string("password");
TEST(client, https_get_async_with_socks5_proxy) {
Client client(SW_SOCK_TCP, true);
proxy_set_socks5_proxy(client);
proxy_async_test(client, true);
}

client.onConnect = [&connected](Client *cli) {
connected = true;
cli->send(cli,
SW_STRL("GET / HTTP/1.1\r\n"
"Host: www.baidu.com\r\n"
"Connection: close\r\n"
"User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/51.0.2704.106 Safari/537.36"
"\r\n\r\n"),
0);
};
TEST(client, https_get_sync_with_http_proxy) {
Client client(SW_SOCK_TCP, false);
proxy_set_http_proxy(client);
proxy_sync_test(client, true);
}

client.onError = [](Client *cli) {};
client.onClose = [&closed](Client *cli) { closed = true; };
client.onReceive = [&buf](Client *cli, const char *data, size_t length) { buf.append(data, length); };
ret = client.connect(&client, "www.baidu.com", 443, -1, 0);
ASSERT_EQ(ret, 0);
TEST(client, https_get_sync_with_socks5_proxy) {
Client client(SW_SOCK_TCP, false);
proxy_set_socks5_proxy(client);
proxy_sync_test(client, true);
}

swoole_event_wait();
TEST(client, http_get_async_with_http_proxy) {
Client client(SW_SOCK_TCP, true);
proxy_set_http_proxy(client);
proxy_async_test(client, false);
}

ASSERT_TRUE(connected);
ASSERT_TRUE(closed);
ASSERT_TRUE(buf.contains("Baidu"));
TEST(client, http_get_async_with_socks5_proxy) {
Client client(SW_SOCK_TCP, true);
proxy_set_socks5_proxy(client);
proxy_async_test(client, false);
}

TEST(client, http_get_sync_with_http_proxy) {
Client client(SW_SOCK_TCP, false);
proxy_set_http_proxy(client);
proxy_sync_test(client, false);
}

TEST(client, http_get_sync_with_socks5_proxy) {
Client client(SW_SOCK_TCP, false);
proxy_set_socks5_proxy(client);
proxy_sync_test(client, false);
}
#endif
49 changes: 36 additions & 13 deletions include/swoole_async.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@

#include <vector>
#include <string>
#include <mutex>
#include <atomic>

#ifndef O_DIRECT
#define O_DIRECT 040000
Expand All @@ -34,18 +32,22 @@ enum AsyncFlag {
SW_AIO_EOF = 1u << 2,
};

struct AsyncRequest {
virtual ~AsyncRequest() = default;
};

struct AsyncEvent {
size_t task_id;
uint8_t canceled;
int error;
/**
* input & output
*/
void *data;
std::shared_ptr<AsyncRequest> data;
/**
* output
*/
ssize_t retval;
int error;
/**
* internal use only
*/
Expand All @@ -60,28 +62,52 @@ struct AsyncEvent {
}
};

struct GethostbynameRequest {
const char *name;
struct GethostbynameRequest : public AsyncRequest {
std::string name;
int family;
char *addr;
size_t addr_len;

GethostbynameRequest(const char *_name, int _family) : name(_name), family(_family) {
GethostbynameRequest(std::string _name, int _family) : name(std::move(_name)), family(_family) {
addr_len = _family == AF_INET6 ? INET6_ADDRSTRLEN : INET_ADDRSTRLEN;
addr = new char[addr_len];
}

~GethostbynameRequest() {
~GethostbynameRequest() override {
delete[] addr;
}
};

struct GetaddrinfoRequest : public AsyncRequest {
std::string hostname;
std::string service;
int family;
int socktype;
int protocol;
int error;
std::vector<struct sockaddr_in6> results;
int count;

void parse_result(std::vector<std::string> &retval);

GetaddrinfoRequest(std::string _hostname, int _family, int _socktype, int _protocol, std::string _service)
: hostname(std::move(_hostname)),
service(std::move(_service)) {
family =_family;
socktype =_socktype;
protocol =_protocol;
count = 0;
error = 0;
}

~GetaddrinfoRequest() override = default;
};

class AsyncThreads {
public:
bool schedule = false;
size_t task_num = 0;
Pipe *pipe = nullptr;
async::ThreadPool *pool = nullptr;
std::shared_ptr<async::ThreadPool> pool;
network::Socket *read_socket = nullptr;
network::Socket *write_socket = nullptr;

Expand All @@ -97,9 +123,6 @@ class AsyncThreads {
void notify_one();

static int callback(Reactor *reactor, Event *event);

private:
std::mutex init_lock;
};

namespace async {
Expand Down
27 changes: 19 additions & 8 deletions include/swoole_client.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@
#include "swoole_protocol.h"
#include "swoole_proxy.h"

#define SW_HTTPS_PROXY_HANDSHAKE_RESPONSE "HTTP/1.1 200 Connection established"

namespace swoole {
namespace network {

Expand Down Expand Up @@ -105,12 +103,12 @@ class Client {
std::shared_ptr<SSLContext> ssl_context = nullptr;
#endif

std::function<void (Client *cli)> onConnect = nullptr;
std::function<void (Client *cli)> onError = nullptr;
std::function<void (Client *cli, const char *, size_t)> onReceive = nullptr;
std::function<void (Client *cli)> onClose = nullptr;
std::function<void (Client *cli)> onBufferFull = nullptr;
std::function<void (Client *cli)> onBufferEmpty = nullptr;
std::function<void(Client *cli)> onConnect = nullptr;
std::function<void(Client *cli)> onError = nullptr;
std::function<void(Client *cli, const char *, size_t)> onReceive = nullptr;
std::function<void(Client *cli)> onClose = nullptr;
std::function<void(Client *cli)> onBufferFull = nullptr;
std::function<void(Client *cli)> onBufferEmpty = nullptr;

int (*connect)(Client *cli, const char *host, int port, double _timeout, int sock_flag) = nullptr;
ssize_t (*send)(Client *cli, const char *data, size_t length, int flags) = nullptr;
Expand All @@ -131,6 +129,19 @@ class Client {
return socket;
}

SocketType get_socket_type() {
return socket->socket_type;
}

const std::string *get_http_proxy_host_name() {
#ifdef SW_USE_OPENSSL
if (ssl_context && !ssl_context->tls_host_name.empty()) {
return &ssl_context->tls_host_name;
}
#endif
return &http_proxy->target_host;
}

int sleep();
int wakeup();
int shutdown(int __how);
Expand Down
13 changes: 12 additions & 1 deletion include/swoole_proxy.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,14 @@
#include <cstdint>

#define SW_SOCKS5_VERSION_CODE 0x05
#define SW_HTTP_PROXY_CHECK_MESSAGE 0
#define SW_HTTP_PROXY_HANDSHAKE_RESPONSE "HTTP/1.1 200 Connection established\r\n"

#define SW_HTTP_PROXY_FMT \
"CONNECT %.*s:%d HTTP/1.1\r\n" \
"Host: %.*s:%d\r\n" \
"User-Agent: Swoole/" SWOOLE_VERSION "\r\n" \
"Proxy-Connection: Keep-Alive\r\n"

enum swHttpProxyState {
SW_HTTP_PROXY_STATE_WAIT = 0,
Expand All @@ -40,6 +48,8 @@ enum swSocks5Method {
};

namespace swoole {
class String;

struct HttpProxy {
uint8_t state;
uint8_t dont_handshake;
Expand All @@ -49,9 +59,10 @@ struct HttpProxy {
std::string password;
std::string target_host;
int target_port;
char buf[512];

std::string get_auth_str();
size_t pack(String *send_buffer, const std::string *host_name);
bool handshake(String *recv_buffer);
};

struct Socks5Proxy {
Expand Down
Loading
Loading