mirror of
https://github.com/sogou/workflow.git
synced 2026-02-08 01:33:17 +08:00
HttpTask support auth when has userinfo (#1554)
* HttpTask support auth when has userinfo * clear auth when redirect to other host * HttpProxyTask support auth when has userinfo * remove one StringUtil::url_decode as requested in #1554
This commit is contained in:
@@ -39,6 +39,23 @@ using namespace protocol;
|
||||
|
||||
/**********Client**********/
|
||||
|
||||
static int __encode_auth(const char *p, std::string& auth)
|
||||
{
|
||||
size_t len = strlen(p);
|
||||
size_t base64_len = (len + 2) / 3 * 4;
|
||||
char *base64 = (char *)malloc(base64_len + 1);
|
||||
|
||||
if (!base64)
|
||||
return -1;
|
||||
|
||||
EVP_EncodeBlock((unsigned char *)base64, (const unsigned char *)p, len);
|
||||
auth.append("Basic ");
|
||||
auth.append(base64, base64_len);
|
||||
|
||||
free(base64);
|
||||
return 0;
|
||||
}
|
||||
|
||||
class ComplexHttpTask : public WFComplexClientTask<HttpRequest, HttpResponse>
|
||||
{
|
||||
public:
|
||||
@@ -64,8 +81,9 @@ protected:
|
||||
virtual bool finish_once();
|
||||
|
||||
protected:
|
||||
bool need_redirect(ParsedURI& uri);
|
||||
bool redirect_url(HttpResponse *client_resp, ParsedURI& uri);
|
||||
bool need_redirect(const ParsedURI& uri, ParsedURI& new_uri);
|
||||
bool redirect_url(HttpResponse *client_resp,
|
||||
const ParsedURI& uri, ParsedURI& new_uri);
|
||||
void set_empty_request();
|
||||
void check_response();
|
||||
|
||||
@@ -184,6 +202,10 @@ void ComplexHttpTask::set_empty_request()
|
||||
|
||||
client_req->set_request_uri("/");
|
||||
cursor.find_and_erase(&header);
|
||||
|
||||
header.name = "Authorization";
|
||||
header.name_len = strlen("Authorization");
|
||||
cursor.find_and_erase(&header);
|
||||
}
|
||||
|
||||
void ComplexHttpTask::init_failed()
|
||||
@@ -206,7 +228,6 @@ bool ComplexHttpTask::init_success()
|
||||
{
|
||||
this->state = WFT_STATE_TASK_ERROR;
|
||||
this->error = WFT_ERR_URI_SCHEME_INVALID;
|
||||
this->set_empty_request();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -253,10 +274,29 @@ bool ComplexHttpTask::init_success()
|
||||
this->WFComplexClientTask::set_transport_type(is_ssl ? TT_TCP_SSL : TT_TCP);
|
||||
client_req->set_request_uri(request_uri.c_str());
|
||||
client_req->set_header_pair("Host", header_host.c_str());
|
||||
|
||||
if (uri_.userinfo && uri_.userinfo[0])
|
||||
{
|
||||
std::string userinfo(uri_.userinfo);
|
||||
std::string http_auth;
|
||||
|
||||
StringUtil::url_decode(userinfo);
|
||||
|
||||
if (__encode_auth(userinfo.c_str(), http_auth) < 0)
|
||||
{
|
||||
this->state = WFT_STATE_SYS_ERROR;
|
||||
this->error = errno;
|
||||
return false;
|
||||
}
|
||||
|
||||
client_req->set_header_pair("Authorization", http_auth.c_str());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ComplexHttpTask::redirect_url(HttpResponse *client_resp, ParsedURI& uri)
|
||||
bool ComplexHttpTask::redirect_url(HttpResponse *client_resp,
|
||||
const ParsedURI& uri, ParsedURI& new_uri)
|
||||
{
|
||||
if (redirect_count_ < redirect_max_)
|
||||
{
|
||||
@@ -284,14 +324,14 @@ bool ComplexHttpTask::redirect_url(HttpResponse *client_resp, ParsedURI& uri)
|
||||
url = uri.scheme + (':' + url);
|
||||
}
|
||||
|
||||
URIParser::parse(url, uri);
|
||||
URIParser::parse(url, new_uri);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ComplexHttpTask::need_redirect(ParsedURI& uri)
|
||||
bool ComplexHttpTask::need_redirect(const ParsedURI& uri, ParsedURI& new_uri)
|
||||
{
|
||||
HttpRequest *client_req = this->get_req();
|
||||
HttpResponse *client_resp = this->get_resp();
|
||||
@@ -308,7 +348,7 @@ bool ComplexHttpTask::need_redirect(ParsedURI& uri)
|
||||
case 301:
|
||||
case 302:
|
||||
case 303:
|
||||
if (redirect_url(client_resp, uri))
|
||||
if (redirect_url(client_resp, uri, new_uri))
|
||||
{
|
||||
if (strcasecmp(method, HttpMethodGet) != 0 &&
|
||||
strcasecmp(method, HttpMethodHead) != 0)
|
||||
@@ -323,7 +363,7 @@ bool ComplexHttpTask::need_redirect(ParsedURI& uri)
|
||||
|
||||
case 307:
|
||||
case 308:
|
||||
if (redirect_url(client_resp, uri))
|
||||
if (redirect_url(client_resp, uri, new_uri))
|
||||
return true;
|
||||
else
|
||||
break;
|
||||
@@ -359,8 +399,31 @@ bool ComplexHttpTask::finish_once()
|
||||
|
||||
if (this->state == WFT_STATE_SUCCESS)
|
||||
{
|
||||
if (this->need_redirect(uri_))
|
||||
this->set_redirect(uri_);
|
||||
ParsedURI new_uri;
|
||||
if (this->need_redirect(uri_, new_uri))
|
||||
{
|
||||
if (uri_.userinfo && strcasecmp(uri_.host, new_uri.host) == 0)
|
||||
{
|
||||
if (!new_uri.userinfo)
|
||||
{
|
||||
new_uri.userinfo = uri_.userinfo;
|
||||
uri_.userinfo = NULL;
|
||||
}
|
||||
}
|
||||
else if (uri_.userinfo)
|
||||
{
|
||||
HttpRequest *client_req = this->get_req();
|
||||
HttpHeaderCursor cursor(client_req);
|
||||
struct HttpMessageHeader header = {
|
||||
.name = "Authorization",
|
||||
.name_len = strlen("Authorization")
|
||||
};
|
||||
|
||||
cursor.find_and_erase(&header);
|
||||
}
|
||||
|
||||
this->set_redirect(new_uri);
|
||||
}
|
||||
else if (this->state != WFT_STATE_SUCCESS)
|
||||
this->disable_retry();
|
||||
}
|
||||
@@ -370,23 +433,6 @@ bool ComplexHttpTask::finish_once()
|
||||
|
||||
/*******Proxy Client*******/
|
||||
|
||||
static int __encode_auth(const char *p, std::string& auth)
|
||||
{
|
||||
size_t len = strlen(p);
|
||||
size_t base64_len = (len + 2) / 3 * 4;
|
||||
char *base64 = (char *)malloc(base64_len + 1);
|
||||
|
||||
if (!base64)
|
||||
return -1;
|
||||
|
||||
EVP_EncodeBlock((unsigned char *)base64, (const unsigned char *)p, len);
|
||||
auth.append("Basic ");
|
||||
auth.append(base64, base64_len);
|
||||
|
||||
free(base64);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static SSL *__create_ssl(SSL_CTX *ssl_ctx)
|
||||
{
|
||||
BIO *wbio;
|
||||
@@ -635,7 +681,6 @@ bool ComplexHttpProxyTask::init_success()
|
||||
{
|
||||
this->state = WFT_STATE_TASK_ERROR;
|
||||
this->error = WFT_ERR_URI_SCHEME_INVALID;
|
||||
this->set_empty_request();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -653,17 +698,6 @@ bool ComplexHttpProxyTask::init_success()
|
||||
else
|
||||
user_port = is_ssl_ ? 443 : 80;
|
||||
|
||||
if (uri_.userinfo && uri_.userinfo[0])
|
||||
{
|
||||
proxy_auth_.clear();
|
||||
if (__encode_auth(uri_.userinfo, proxy_auth_) < 0)
|
||||
{
|
||||
this->state = WFT_STATE_SYS_ERROR;
|
||||
this->error = errno;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
std::string info("http-proxy|remote:");
|
||||
info += is_ssl_ ? "https://" : "http://";
|
||||
info += user_uri_.host;
|
||||
@@ -672,8 +706,24 @@ bool ComplexHttpProxyTask::init_success()
|
||||
info += user_uri_.port;
|
||||
else
|
||||
info += is_ssl_ ? "443" : "80";
|
||||
info += "|auth:";
|
||||
info += proxy_auth_;
|
||||
|
||||
if (uri_.userinfo && uri_.userinfo[0])
|
||||
{
|
||||
std::string userinfo(uri_.userinfo);
|
||||
|
||||
StringUtil::url_decode(userinfo);
|
||||
proxy_auth_.clear();
|
||||
|
||||
if (__encode_auth(userinfo.c_str(), proxy_auth_) < 0)
|
||||
{
|
||||
this->state = WFT_STATE_SYS_ERROR;
|
||||
this->error = errno;
|
||||
return false;
|
||||
}
|
||||
|
||||
info += "|auth:";
|
||||
info += proxy_auth_;
|
||||
}
|
||||
|
||||
this->WFComplexClientTask::set_info(info);
|
||||
|
||||
@@ -704,6 +754,24 @@ bool ComplexHttpProxyTask::init_success()
|
||||
client_req->set_request_uri(request_uri.c_str());
|
||||
client_req->set_header_pair("Host", header_host.c_str());
|
||||
this->WFComplexClientTask::set_transport_type(TT_TCP);
|
||||
|
||||
if (user_uri_.userinfo && user_uri_.userinfo[0])
|
||||
{
|
||||
std::string userinfo(user_uri_.userinfo);
|
||||
std::string http_auth;
|
||||
|
||||
StringUtil::url_decode(userinfo);
|
||||
|
||||
if (__encode_auth(userinfo.c_str(), http_auth) < 0)
|
||||
{
|
||||
this->state = WFT_STATE_SYS_ERROR;
|
||||
this->error = errno;
|
||||
return false;
|
||||
}
|
||||
|
||||
client_req->set_header_pair("Authorization", http_auth.c_str());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -732,8 +800,33 @@ bool ComplexHttpProxyTask::finish_once()
|
||||
|
||||
if (this->state == WFT_STATE_SUCCESS)
|
||||
{
|
||||
if (this->need_redirect(user_uri_))
|
||||
ParsedURI new_uri;
|
||||
if (this->need_redirect(user_uri_, new_uri))
|
||||
{
|
||||
if (user_uri_.userinfo &&
|
||||
strcasecmp(user_uri_.host, new_uri.host) == 0)
|
||||
{
|
||||
if (!new_uri.userinfo)
|
||||
{
|
||||
new_uri.userinfo = user_uri_.userinfo;
|
||||
user_uri_.userinfo = NULL;
|
||||
}
|
||||
}
|
||||
else if (user_uri_.userinfo)
|
||||
{
|
||||
HttpRequest *client_req = this->get_req();
|
||||
HttpHeaderCursor cursor(client_req);
|
||||
struct HttpMessageHeader header = {
|
||||
.name = "Authorization",
|
||||
.name_len = strlen("Authorization")
|
||||
};
|
||||
|
||||
cursor.find_and_erase(&header);
|
||||
}
|
||||
|
||||
user_uri_ = std::move(new_uri);
|
||||
this->set_redirect(uri_);
|
||||
}
|
||||
else if (this->state != WFT_STATE_SUCCESS)
|
||||
this->disable_retry();
|
||||
}
|
||||
|
||||
@@ -49,20 +49,17 @@ static inline char __itoh(int n)
|
||||
return n + '0';
|
||||
}
|
||||
|
||||
size_t StringUtil::url_decode(char *str, size_t len)
|
||||
static size_t __url_decode(char *str)
|
||||
{
|
||||
char *dest = str;
|
||||
char *data = str;
|
||||
|
||||
while (len--)
|
||||
while (*data)
|
||||
{
|
||||
if (*data == '%' && len >= 2
|
||||
&& isxdigit(*(data + 1))
|
||||
&& isxdigit(*(data + 2)))
|
||||
if (*data == '%' && isxdigit(data[1]) && isxdigit(data[2]))
|
||||
{
|
||||
*dest = __htoi((unsigned char *)data + 1);
|
||||
data += 2;
|
||||
len -= 2;
|
||||
}
|
||||
else if (*data == '+')
|
||||
*dest = ' ';
|
||||
@@ -82,25 +79,25 @@ void StringUtil::url_decode(std::string& str)
|
||||
if (str.empty())
|
||||
return;
|
||||
|
||||
size_t sz = url_decode(const_cast<char *>(str.c_str()), str.size());
|
||||
size_t sz = __url_decode(const_cast<char *>(str.c_str()));
|
||||
|
||||
str.resize(sz);
|
||||
}
|
||||
|
||||
std::string StringUtil::url_encode(const std::string& str)
|
||||
{
|
||||
std::string res;
|
||||
const char *cur = str.c_str();
|
||||
const char *ed = cur + str.size();
|
||||
std::string res;
|
||||
|
||||
while (cur < ed)
|
||||
{
|
||||
if (*cur == ' ')
|
||||
res += '+';
|
||||
else if (isalnum(*cur) || *cur == '-' || *cur == '_' || *cur == '.'
|
||||
|| *cur == '!' || *cur == '~' || *cur == '*' || *cur == '\''
|
||||
|| *cur == '(' || *cur == ')' || *cur == ':' || *cur == '/'
|
||||
|| *cur == '@' || *cur == '?' || *cur == '#' || *cur == '&')
|
||||
else if (isalnum(*cur) || *cur == '-' || *cur == '_' || *cur == '.' ||
|
||||
*cur == '!' || *cur == '~' || *cur == '*' || *cur == '\'' ||
|
||||
*cur == '(' || *cur == ')' || *cur == ':' || *cur == '/' ||
|
||||
*cur == '@' || *cur == '?' || *cur == '#' || *cur == '&')
|
||||
res += *cur;
|
||||
else
|
||||
{
|
||||
@@ -117,17 +114,17 @@ std::string StringUtil::url_encode(const std::string& str)
|
||||
|
||||
std::string StringUtil::url_encode_component(const std::string& str)
|
||||
{
|
||||
std::string res;
|
||||
const char *cur = str.c_str();
|
||||
const char *ed = cur + str.size();
|
||||
std::string res;
|
||||
|
||||
while (cur < ed)
|
||||
{
|
||||
if (*cur == ' ')
|
||||
res += '+';
|
||||
else if (isalnum(*cur) || *cur == '-' || *cur == '_' || *cur == '.'
|
||||
|| *cur == '!' || *cur == '~' || *cur == '*' || *cur == '\''
|
||||
|| *cur == '(' || *cur == ')')
|
||||
else if (isalnum(*cur) || *cur == '-' || *cur == '_' || *cur == '.' ||
|
||||
*cur == '!' || *cur == '~' || *cur == '*' || *cur == '\'' ||
|
||||
*cur == '(' || *cur == ')')
|
||||
res += *cur;
|
||||
else
|
||||
{
|
||||
@@ -144,10 +141,10 @@ std::string StringUtil::url_encode_component(const std::string& str)
|
||||
|
||||
std::vector<std::string> StringUtil::split(const std::string& str, char sep)
|
||||
{
|
||||
std::vector<std::string> res;
|
||||
std::string::const_iterator start = str.begin();
|
||||
std::string::const_iterator end = str.end();
|
||||
std::string::const_iterator next = find(start, end, sep);
|
||||
std::vector<std::string> res;
|
||||
|
||||
while (next != end)
|
||||
{
|
||||
|
||||
@@ -31,7 +31,6 @@
|
||||
class StringUtil
|
||||
{
|
||||
public:
|
||||
static size_t url_decode(char *str, size_t len);
|
||||
static void url_decode(std::string& str);
|
||||
static std::string url_encode(const std::string& str);
|
||||
static std::string url_encode_component(const std::string& str);
|
||||
|
||||
Reference in New Issue
Block a user