diff --git a/uppsrc/Core/Http.cpp b/uppsrc/Core/Http.cpp index 7ee928c8a..2bdb11ff6 100644 --- a/uppsrc/Core/Http.cpp +++ b/uppsrc/Core/Http.cpp @@ -23,7 +23,7 @@ void HttpRequest::Init() ssl_proxy_port = 0; max_header_size = 1000000; max_content_size = 10000000; - max_redirects = 5; + max_redirects = 10; max_retries = 3; force_digest = false; std_headers = true; @@ -323,6 +323,7 @@ bool HttpRequest::Do() void HttpRequest::Start() { + LLOG("HTTP START"); Close(); ClearError(); gzip = false; @@ -371,6 +372,7 @@ void HttpRequest::Dns() void HttpRequest::StartConnect() { + LLOG("HTTP StartConnect"); if(!Connect(addrinfo)) return; if(ssl && ssl_proxy_host.GetCount()) { @@ -408,6 +410,7 @@ void HttpRequest::ProcessSSLProxyResponse() void HttpRequest::AfterConnect() { + LLOG("HTTP AfterConnect"); if(ssl && !StartSSL()) return; if(ssl) @@ -437,8 +440,11 @@ void HttpRequest::StartRequest() url << "http://" << host_port << Nvl(path, "/"); if(!IsNull(proxy_host) && !ssl) data << url; - else - data << Nvl(path, "/"); + else { + if(*path != '/') + data << '/'; + data << path; + } data << " HTTP/1.1\r\n"; if(std_headers) { data << "URL: " << url << "\r\n" @@ -665,7 +671,7 @@ void HttpRequest::Finish() if(status_code >= 300 && status_code < 400) { String url = GetRedirectUrl(); if(url.GetCount() && redirect_count++ < max_redirects) { - LLOG("HTTP redirect " << url); + LLOG("--- HTTP redirect " << url); Url(url); CopyCookies(); Start(); @@ -678,6 +684,7 @@ void HttpRequest::Finish() String HttpRequest::Execute() { + New(); while(Do()) LLOG("HTTP Execute: " << GetPhaseName()); return IsSuccess() ? GetContent() : String::GetVoid(); diff --git a/uppsrc/Core/SSL/Socket.cpp b/uppsrc/Core/SSL/Socket.cpp index ceedf7f6e..fc8000916 100644 --- a/uppsrc/Core/SSL/Socket.cpp +++ b/uppsrc/Core/SSL/Socket.cpp @@ -1,206 +1,212 @@ -#include "SSL.h" - -#define LLOG(x) // DLOG(x) - -NAMESPACE_UPP - -struct TcpSocket::SSLImp : TcpSocket::SSL { - virtual bool Start(); - virtual bool Wait(dword flags, int end_time); - virtual int Send(const void *buffer, int maxlen); - virtual int Recv(void *buffer, int maxlen); - virtual void Close(); - virtual dword Handshake(); - - TcpSocket& socket; - SslContext context; - ::SSL *ssl; - SslCertificate cert; - - int GetErrorCode(int res); - String GetErrorText(int code); - void SetSSLError(const char *context); - void SetSSLResError(const char *context, int res); - bool IsAgain(int res) const; - - SSLImp(TcpSocket& socket) : socket(socket) { ssl = NULL; } - ~SSLImp(); -}; - -TcpSocket::SSL *TcpSocket::CreateSSLImp(TcpSocket& socket) -{ - return new TcpSocket::SSLImp(socket); -} - -void InitCreateSSL() -{ - TcpSocket::CreateSSL = TcpSocket::CreateSSLImp; -} - -INITBLOCK { - InitCreateSSL(); -} - -TcpSocket::SSLImp::~SSLImp() -{ - if(ssl) - SSL_free(ssl); -} - -void TcpSocket::SSLImp::SetSSLError(const char *context) -{ - int code; - String text = SslGetLastError(code); - socket.SetSockError(context, code, text); -} - -const char *TcpSocketErrorDesc(int code); - -int TcpSocket::SSLImp::GetErrorCode(int res) -{ - return SSL_get_error(ssl, res); -} - -String TcpSocket::SSLImp::GetErrorText(int code) -{ - String out; - switch(code) { -#define SSLERR(c) case c: out = #c; break; - SSLERR(SSL_ERROR_NONE) - SSLERR(SSL_ERROR_SSL) - SSLERR(SSL_ERROR_WANT_READ) - SSLERR(SSL_ERROR_WANT_WRITE) - SSLERR(SSL_ERROR_WANT_X509_LOOKUP) - SSLERR(SSL_ERROR_SYSCALL) - SSLERR(SSL_ERROR_ZERO_RETURN) - SSLERR(SSL_ERROR_WANT_CONNECT) -#ifdef PLATFORM_WIN32 - SSLERR(SSL_ERROR_WANT_ACCEPT) -#endif - default: out = "unknown code"; break; - } - return out; -} - -void TcpSocket::SSLImp::SetSSLResError(const char *context, int res) -{ - int code = GetErrorCode(res); - if(code == SSL_ERROR_SYSCALL) { - socket.SetSockError(context); - return; - } - socket.SetSockError(context, code, GetErrorText(code)); -} - -bool TcpSocket::SSLImp::IsAgain(int res) const -{ - res = SSL_get_error(ssl, res); - return res == SSL_ERROR_WANT_READ || - res == SSL_ERROR_WANT_WRITE || - res == SSL_ERROR_WANT_CONNECT || - res == SSL_ERROR_WANT_ACCEPT; -} - -bool TcpSocket::SSLImp::Start() -{ - LLOG("SSL Start"); - - if(!context.Create(const_cast(SSLv3_client_method()))) { - SetSSLError("Start: SSL context."); - return false; - } - if(socket.cert.GetCount()) - context.UseCertificate(socket.cert, socket.pkey, socket.asn1); - if(!(ssl = SSL_new(context))) { - SetSSLError("Start: SSL_new"); - return false; - } - if(!SSL_set_fd(ssl, socket.GetSOCKET())) { - SetSSLError("Start: SSL_set_fd"); - return false; - } - return Handshake(); -} - -dword TcpSocket::SSLImp::Handshake() -{ - int res; - if(socket.mode == ACCEPT) - res = SSL_accept(ssl); - else - if(socket.mode == CONNECT) - res = SSL_connect(ssl); - else - return 0; - if(res <= 0) { - int code = GetErrorCode(res); - if(code == SSL_ERROR_WANT_READ) - return WAIT_READ; - if(code == SSL_ERROR_WANT_WRITE) - return WAIT_WRITE; - SetSSLResError("SSL handshake", res); - return 0; - } - socket.mode = SSL_CONNECTED; - cert.Set(SSL_get_peer_certificate(ssl)); - SSLInfo& f = socket.sslinfo.Create(); - f.cipher = SSL_get_cipher(ssl); - if(!cert.IsEmpty()) { - f.cert_avail = true; - f.cert_subject = cert.GetSubjectName(); - f.cert_issuer = cert.GetIssuerName(); - f.cert_serial = cert.GetSerialNumber(); - f.cert_notbefore = cert.GetNotBefore(); - f.cert_notafter = cert.GetNotAfter(); - f.cert_version = cert.GetVersion(); - f.cert_verified = SSL_get_verify_result(ssl) == X509_V_OK; - } - return 0; -} - -bool TcpSocket::SSLImp::Wait(dword flags, int end_time) -{ - LLOG("SSL Wait"); - if((flags & WAIT_READ) && SSL_pending(ssl) > 0) - return true; - return socket.RawWait(flags, end_time); -} - -int TcpSocket::SSLImp::Send(const void *buffer, int maxlen) -{ - LLOG("SSL Send " << maxlen); - int res = SSL_write(ssl, (const char *)buffer, maxlen); - if(res > 0) - return res; - if(res == 0) - socket.is_eof = true; - else - if(!IsAgain(res)) - SetSSLResError("SSL_write", res); - return 0; -} - -int TcpSocket::SSLImp::Recv(void *buffer, int maxlen) -{ - LLOG("SSL Recv " << maxlen); - int res = SSL_read(ssl, (char *)buffer, maxlen); - if(res > 0) - return res; - if(res == 0) - socket.is_eof = true; - else - if(!IsAgain(res)) - SetSSLResError("SSL_read", res); - return 0; -} - -void TcpSocket::SSLImp::Close() -{ - LLOG("SSL Close"); - SSL_shutdown(ssl); - socket.RawClose(); - SSL_free(ssl); - ssl = NULL; -} - -END_UPP_NAMESPACE +#include "SSL.h" + +#define LLOG(x) // DLOG(x) + +NAMESPACE_UPP + +struct TcpSocket::SSLImp : TcpSocket::SSL { + virtual bool Start(); + virtual bool Wait(dword flags, int end_time); + virtual int Send(const void *buffer, int maxlen); + virtual int Recv(void *buffer, int maxlen); + virtual void Close(); + virtual dword Handshake(); + + TcpSocket& socket; + SslContext context; + ::SSL *ssl; + SslCertificate cert; + + int GetErrorCode(int res); + String GetErrorText(int code); + void SetSSLError(const char *context); + void SetSSLResError(const char *context, int res); + bool IsAgain(int res) const; + + SSLImp(TcpSocket& socket) : socket(socket) { ssl = NULL; LLOG("SSLImp(" << socket.GetSOCKET() << ")"); } + ~SSLImp(); +}; + +TcpSocket::SSL *TcpSocket::CreateSSLImp(TcpSocket& socket) +{ + return new TcpSocket::SSLImp(socket); +} + +void InitCreateSSL() +{ + TcpSocket::CreateSSL = TcpSocket::CreateSSLImp; +} + +INITBLOCK { + InitCreateSSL(); +} + +TcpSocket::SSLImp::~SSLImp() +{ + if(ssl) + SSL_free(ssl); +} + +void TcpSocket::SSLImp::SetSSLError(const char *context) +{ + int code; + String text = SslGetLastError(code); + socket.SetSockError(context, code, text); +} + +const char *TcpSocketErrorDesc(int code); + +int TcpSocket::SSLImp::GetErrorCode(int res) +{ + return SSL_get_error(ssl, res); +} + +String TcpSocket::SSLImp::GetErrorText(int code) +{ + String out; + switch(code) { +#define SSLERR(c) case c: out = #c; break; + SSLERR(SSL_ERROR_NONE) + SSLERR(SSL_ERROR_SSL) + SSLERR(SSL_ERROR_WANT_READ) + SSLERR(SSL_ERROR_WANT_WRITE) + SSLERR(SSL_ERROR_WANT_X509_LOOKUP) + SSLERR(SSL_ERROR_SYSCALL) + SSLERR(SSL_ERROR_ZERO_RETURN) + SSLERR(SSL_ERROR_WANT_CONNECT) +#ifdef PLATFORM_WIN32 + SSLERR(SSL_ERROR_WANT_ACCEPT) +#endif + default: out = "unknown code"; break; + } + return out; +} + +void TcpSocket::SSLImp::SetSSLResError(const char *context, int res) +{ + int code = GetErrorCode(res); + if(code == SSL_ERROR_SYSCALL) { + socket.SetSockError(context); + return; + } + socket.SetSockError(context, code, GetErrorText(code)); +} + +bool TcpSocket::SSLImp::IsAgain(int res) const +{ + res = SSL_get_error(ssl, res); + return res == SSL_ERROR_WANT_READ || + res == SSL_ERROR_WANT_WRITE || + res == SSL_ERROR_WANT_CONNECT || + res == SSL_ERROR_WANT_ACCEPT; +} + +bool TcpSocket::SSLImp::Start() +{ + LLOG("SSL Start"); + + ERR_clear_error(); + if(!context.Create(const_cast(SSLv3_client_method()))) { + SetSSLError("Start: SSL context."); + return false; + } + if(socket.cert.GetCount()) + context.UseCertificate(socket.cert, socket.pkey, socket.asn1); + if(!(ssl = SSL_new(context))) { + SetSSLError("Start: SSL_new"); + return false; + } + if(!SSL_set_fd(ssl, socket.GetSOCKET())) { + SetSSLError("Start: SSL_set_fd"); + return false; + } + return Handshake(); +} + +dword TcpSocket::SSLImp::Handshake() +{ + int res; + ERR_clear_error(); + if(socket.mode == ACCEPT) + res = SSL_accept(ssl); + else + if(socket.mode == CONNECT) + res = SSL_connect(ssl); + else + return 0; + if(res <= 0) { + int code = GetErrorCode(res); + if(code == SSL_ERROR_WANT_READ) + return WAIT_READ; + if(code == SSL_ERROR_WANT_WRITE) + return WAIT_WRITE; + if(code == SSL_ERROR_SYSCALL && socket.GetErrorCode() == WSAENOTCONN) + return WAIT_WRITE; + SetSSLResError("SSL handshake", res); + return 0; + } + socket.mode = SSL_CONNECTED; + cert.Set(SSL_get_peer_certificate(ssl)); + SSLInfo& f = socket.sslinfo.Create(); + f.cipher = SSL_get_cipher(ssl); + if(!cert.IsEmpty()) { + f.cert_avail = true; + f.cert_subject = cert.GetSubjectName(); + f.cert_issuer = cert.GetIssuerName(); + f.cert_serial = cert.GetSerialNumber(); + f.cert_notbefore = cert.GetNotBefore(); + f.cert_notafter = cert.GetNotAfter(); + f.cert_version = cert.GetVersion(); + f.cert_verified = SSL_get_verify_result(ssl) == X509_V_OK; + } + return 0; +} + +bool TcpSocket::SSLImp::Wait(dword flags, int end_time) +{ + LLOG("SSL Wait"); + if((flags & WAIT_READ) && SSL_pending(ssl) > 0) + return true; + return socket.RawWait(flags, end_time); +} + +int TcpSocket::SSLImp::Send(const void *buffer, int maxlen) +{ + LLOG("SSL Send " << maxlen); + ERR_clear_error(); + int res = SSL_write(ssl, (const char *)buffer, maxlen); + if(res > 0) + return res; + if(res == 0) + socket.is_eof = true; + else + if(!IsAgain(res)) + SetSSLResError("SSL_write", res); + return 0; +} + +int TcpSocket::SSLImp::Recv(void *buffer, int maxlen) +{ + LLOG("SSL Recv " << maxlen); + ERR_clear_error(); + int res = SSL_read(ssl, (char *)buffer, maxlen); + if(res > 0) + return res; + if(res == 0) + socket.is_eof = true; + else + if(!IsAgain(res)) + SetSSLResError("SSL_read", res); + return 0; +} + +void TcpSocket::SSLImp::Close() +{ + LLOG("SSL Close"); + SSL_shutdown(ssl); + socket.RawClose(); + SSL_free(ssl); + ssl = NULL; +} + +END_UPP_NAMESPACE diff --git a/uppsrc/Core/Socket.cpp b/uppsrc/Core/Socket.cpp index 5568879ff..805385e1c 100644 --- a/uppsrc/Core/Socket.cpp +++ b/uppsrc/Core/Socket.cpp @@ -434,7 +434,7 @@ bool TcpSocket::RawConnect(addrinfo *rp) bool TcpSocket::Connect(IpAddrInfo& info) { - LLOG("TCP Connect addrinfo"); + LLOG("Connect addrinfo"); Init(); Reset(); addrinfo *result = info.GetResult(); @@ -443,7 +443,7 @@ bool TcpSocket::Connect(IpAddrInfo& info) bool TcpSocket::Connect(const char *host, int port) { - LLOG("TCP Connect(" << host << ':' << port << ')'); + LLOG("Connect(" << host << ':' << port << ')'); Init(); Reset(); @@ -457,7 +457,7 @@ bool TcpSocket::Connect(const char *host, int port) void TcpSocket::RawClose() { - LLOG("TCP close " << (int)socket); + LLOG("close " << (int)socket); if(socket != INVALID_SOCKET) { int res; #if defined(PLATFORM_WIN32) @@ -800,7 +800,7 @@ void TcpSocket::SetSockError(const char *context, int code, const char *errdesc) errordesc << "socket(" << (int)socket << ") / "; errordesc << context << ": " << errdesc; is_error = true; - LLOG("TCP ERROR " << errordesc); + LLOG("ERROR " << errordesc); } void TcpSocket::SetSockError(const char *context, const char *errdesc) diff --git a/uppsrc/Core/src.tpp/HttpRequest$en-us.tpp b/uppsrc/Core/src.tpp/HttpRequest$en-us.tpp index 3edf275d3..628652ae9 100644 --- a/uppsrc/Core/src.tpp/HttpRequest$en-us.tpp +++ b/uppsrc/Core/src.tpp/HttpRequest$en-us.tpp @@ -52,7 +52,7 @@ axContentSize]([@(0.0.255) int]_[*@3 m])&] [s5;:HttpRequest`:`:MaxRedirect`(int`): [_^HttpRequest^ HttpRequest][@(0.0.255) `&]_[* MaxR edirect]([@(0.0.255) int]_[*@3 n])&] [s2;%% Specifies the maximum number of redirections (code 3xx) (default -is 5). Returns `*this.&] +is 10). Returns `*this.&] [s3;%% &] [s4;%% &] [s5;:HttpRequest`:`:MaxRetries`(int`): [_^HttpRequest^ HttpRequest][@(0.0.255) `&]_[* MaxRe