mirror of
https://github.com/Fishwaldo/minihttp.git
synced 2025-03-15 19:41:27 +00:00
Fix HTTP->HTTPS redirect, local redirect, and some other issues. Accept untrusted certs for now.
This commit is contained in:
parent
8dd0c35416
commit
9227cc114a
3 changed files with 67 additions and 28 deletions
11
main.cpp
11
main.cpp
|
@ -24,7 +24,7 @@ protected:
|
||||||
{
|
{
|
||||||
puts("_OnOpen()");
|
puts("_OnOpen()");
|
||||||
minihttp::SSLResult sr = verifySSL();
|
minihttp::SSLResult sr = verifySSL();
|
||||||
printf("SSL status flags (0 is good): 0x%x\n", sr);
|
printf("SSL status flags: 0x%x (fail: %d)\n", sr, sr & minihttp::SSLR_FAIL);
|
||||||
minihttp::HttpSocket::_OnOpen();
|
minihttp::HttpSocket::_OnOpen();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,6 +45,12 @@ protected:
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
|
if(argc != 2)
|
||||||
|
{
|
||||||
|
puts("URL plz!");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef SIGPIPE
|
#ifdef SIGPIPE
|
||||||
// On *NIX systems, don't signal writing to a closed socket.
|
// On *NIX systems, don't signal writing to a closed socket.
|
||||||
signal(SIGPIPE, SIG_IGN);
|
signal(SIGPIPE, SIG_IGN);
|
||||||
|
@ -61,7 +67,8 @@ int main(int argc, char *argv[])
|
||||||
//ht->Download("http://www.ietf.org/rfc/rfc2616.txt");
|
//ht->Download("http://www.ietf.org/rfc/rfc2616.txt");
|
||||||
//ht->Download("http://example.com"); // Queue another one
|
//ht->Download("http://example.com"); // Queue another one
|
||||||
//ht->Download("https://example.com"); // SSL connection
|
//ht->Download("https://example.com"); // SSL connection
|
||||||
ht->Download("raw.githubusercontent.com/fgenesis/minihttp/master/minihttp.h"); // transparent HTTP -> HTTPS redirection
|
//ht->Download("raw.githubusercontent.com/fgenesis/minihttp/master/minihttp.h"); // transparent HTTP -> HTTPS redirection
|
||||||
|
ht->Download(argv[1]);
|
||||||
|
|
||||||
minihttp::SocketSet ss;
|
minihttp::SocketSet ss;
|
||||||
|
|
||||||
|
|
83
minihttp.cpp
83
minihttp.cpp
|
@ -213,19 +213,25 @@ static bool _Resolve(const char *host, unsigned int port, struct sockaddr_in *ad
|
||||||
// FIXME: this does currently not handle links like:
|
// FIXME: this does currently not handle links like:
|
||||||
// http://example.com/index.html#pos
|
// http://example.com/index.html#pos
|
||||||
|
|
||||||
bool SplitURI(const std::string& uri, std::string& host, std::string& file, int& port, bool& useSSL)
|
bool SplitURI(const std::string& uri, std::string& protocol, std::string& host, std::string& file, int& port, bool& useSSL)
|
||||||
{
|
{
|
||||||
const char *p = uri.c_str();
|
const char *p = uri.c_str();
|
||||||
const char *sl = strstr(p, "//");
|
const char *sl = strstr(p, "//");
|
||||||
unsigned int offs = 0;
|
unsigned int offs = 0;
|
||||||
bool ssl = false;
|
|
||||||
if(sl)
|
if(sl)
|
||||||
{
|
{
|
||||||
|
size_t colon = uri.find(':');
|
||||||
|
size_t firstslash = uri.find('/');
|
||||||
|
if(colon < firstslash)
|
||||||
|
protocol = uri.substr(0, colon);
|
||||||
if(strncmp(p, "http://", 7) == 0)
|
if(strncmp(p, "http://", 7) == 0)
|
||||||
|
{
|
||||||
|
useSSL = false;
|
||||||
offs = 7;
|
offs = 7;
|
||||||
|
}
|
||||||
else if(strncmp(p, "https://", 8) == 0)
|
else if(strncmp(p, "https://", 8) == 0)
|
||||||
{
|
{
|
||||||
ssl = true;
|
useSSL = true;
|
||||||
offs = 8;
|
offs = 8;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -253,7 +259,6 @@ bool SplitURI(const std::string& uri, std::string& host, std::string& file, int&
|
||||||
port = atoi(host.c_str() + colon);
|
port = atoi(host.c_str() + colon);
|
||||||
host.erase(port);
|
host.erase(port);
|
||||||
}
|
}
|
||||||
useSSL = ssl;
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -316,9 +321,6 @@ TcpSocket::~TcpSocket()
|
||||||
close();
|
close();
|
||||||
if(_inbuf)
|
if(_inbuf)
|
||||||
free(_inbuf);
|
free(_inbuf);
|
||||||
#ifdef MINIHTTP_USE_POLARSSL
|
|
||||||
shutdownSSL();
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TcpSocket::isOpen(void)
|
bool TcpSocket::isOpen(void)
|
||||||
|
@ -339,6 +341,7 @@ void TcpSocket::close(void)
|
||||||
if(_sslctx)
|
if(_sslctx)
|
||||||
((SSLCtx*)_sslctx)->reset();
|
((SSLCtx*)_sslctx)->reset();
|
||||||
net_close(_s);
|
net_close(_s);
|
||||||
|
shutdownSSL();
|
||||||
#else
|
#else
|
||||||
# ifdef _WIN32
|
# ifdef _WIN32
|
||||||
::closesocket((SOCKET)_s);
|
::closesocket((SOCKET)_s);
|
||||||
|
@ -436,6 +439,7 @@ static bool _openSSL(void *ps, SSLCtx *ctx)
|
||||||
//ssl_set_ciphersuites( &ctx->ssl, ssl_default_ciphersuites); // FIXME
|
//ssl_set_ciphersuites( &ctx->ssl, ssl_default_ciphersuites); // FIXME
|
||||||
ssl_set_bio(&ctx->ssl, net_recv, ps, net_send, ps);
|
ssl_set_bio(&ctx->ssl, net_recv, ps, net_send, ps);
|
||||||
|
|
||||||
|
traceprint("SSL handshake now...\n");
|
||||||
int err;
|
int err;
|
||||||
while( (err = ssl_handshake(&ctx->ssl)) )
|
while( (err = ssl_handshake(&ctx->ssl)) )
|
||||||
{
|
{
|
||||||
|
@ -445,7 +449,7 @@ static bool _openSSL(void *ps, SSLCtx *ctx)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
traceprint("SSL handshake done\n");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -475,6 +479,7 @@ bool TcpSocket::open(const char *host /* = NULL */, unsigned int port /* = 0 */)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
traceprint("TcpSocket::open(): host = [%s], port = %d\n", host, port);
|
||||||
|
|
||||||
assert(!SOCKETVALID(_s));
|
assert(!SOCKETVALID(_s));
|
||||||
|
|
||||||
|
@ -500,11 +505,14 @@ bool TcpSocket::open(const char *host /* = NULL */, unsigned int port /* = 0 */)
|
||||||
|
|
||||||
#ifdef MINIHTTP_USE_POLARSSL
|
#ifdef MINIHTTP_USE_POLARSSL
|
||||||
if(_sslctx)
|
if(_sslctx)
|
||||||
|
{
|
||||||
|
traceprint("TcpSocket::open(): SSL requested...\n");
|
||||||
if(!_openSSL(&_s, (SSLCtx*)_sslctx))
|
if(!_openSSL(&_s, (SSLCtx*)_sslctx))
|
||||||
{
|
{
|
||||||
close();
|
close();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
_OnOpen();
|
_OnOpen();
|
||||||
|
@ -581,7 +589,7 @@ SSLResult TcpSocket::verifySSL()
|
||||||
r |= SSLR_CERT_FUTURE;
|
r |= SSLR_CERT_FUTURE;
|
||||||
|
|
||||||
// More than just this?
|
// More than just this?
|
||||||
if(res != BADCERT_SKIP_VERIFY)
|
if(res & (BADCERT_SKIP_VERIFY | SSLR_CERT_NOT_TRUSTED))
|
||||||
r |= SSLR_FAIL;
|
r |= SSLR_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -589,7 +597,11 @@ SSLResult TcpSocket::verifySSL()
|
||||||
}
|
}
|
||||||
#else // MINIHTTP_USE_POLARSSL
|
#else // MINIHTTP_USE_POLARSSL
|
||||||
void TcpSocket::shutdownSSL() {}
|
void TcpSocket::shutdownSSL() {}
|
||||||
bool TcpSocket::initSSL(const char *certs) { return false; }
|
bool TcpSocket::initSSL(const char *certs)
|
||||||
|
{
|
||||||
|
traceprint("initSSL: Compiled without SSL support!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
SSLResult TcpSocket::verifySSL() { return SSLR_NO_SSL; }
|
SSLResult TcpSocket::verifySSL() { return SSLR_NO_SSL; }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -812,7 +824,7 @@ bool HttpSocket::Download(const std::string& url, const char *extraRequest /*=
|
||||||
req.user = user;
|
req.user = user;
|
||||||
if(post)
|
if(post)
|
||||||
req.post = *post;
|
req.post = *post;
|
||||||
SplitURI(url, req.host, req.resource, req.port, req.useSSL);
|
SplitURI(url, req.protocol, req.host, req.resource, req.port, req.useSSL);
|
||||||
if(IsRedirecting() && req.host.empty()) // if we're following a redirection to the same host, the server is likely to omit its hostname
|
if(IsRedirecting() && req.host.empty()) // if we're following a redirection to the same host, the server is likely to omit its hostname
|
||||||
req.host = _curRequest.host;
|
req.host = _curRequest.host;
|
||||||
if(req.port < 0)
|
if(req.port < 0)
|
||||||
|
@ -822,6 +834,32 @@ bool HttpSocket::Download(const std::string& url, const char *extraRequest /*=
|
||||||
return SendRequest(req, false);
|
return SendRequest(req, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool HttpSocket::_Redirect(std::string loc, bool forceGET)
|
||||||
|
{
|
||||||
|
traceprint("Following HTTP redirect to: %s\n", loc.c_str());
|
||||||
|
if(loc.empty())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Request req;
|
||||||
|
req.user = _curRequest.user;
|
||||||
|
req.useSSL = _curRequest.useSSL;
|
||||||
|
if(!forceGET)
|
||||||
|
req.post = _curRequest.post;
|
||||||
|
SplitURI(loc, req.protocol, req.host, req.resource, req.port, req.useSSL);
|
||||||
|
if(req.protocol.empty()) // assume local resource
|
||||||
|
{
|
||||||
|
req.host = _curRequest.host;
|
||||||
|
req.resource = loc;
|
||||||
|
}
|
||||||
|
if(req.host.empty())
|
||||||
|
req.host = _curRequest.host;
|
||||||
|
if(req.port < 0)
|
||||||
|
req.port = _curRequest.port;
|
||||||
|
req.extraGetHeaders = _curRequest.extraGetHeaders;
|
||||||
|
return SendRequest(req, false);
|
||||||
|
}
|
||||||
|
|
||||||
bool HttpSocket::SendRequest(const std::string what, const char *extraRequest /*= NULL*/, void *user /* = NULL */)
|
bool HttpSocket::SendRequest(const std::string what, const char *extraRequest /*= NULL*/, void *user /* = NULL */)
|
||||||
{
|
{
|
||||||
Request req(what, _host, _lastport, user);
|
Request req(what, _host, _lastport, user);
|
||||||
|
@ -929,7 +967,11 @@ bool HttpSocket::_OpenRequest(const Request& req)
|
||||||
if(req.useSSL && !hasSSL())
|
if(req.useSSL && !hasSSL())
|
||||||
{
|
{
|
||||||
traceprint("HttpSocket::_OpenRequest(): Is an SSL connection, but SSL was not inited, doing that now\n");
|
traceprint("HttpSocket::_OpenRequest(): Is an SSL connection, but SSL was not inited, doing that now\n");
|
||||||
initSSL(NULL); // FIXME: supply cert list?
|
if(!initSSL(NULL)) // FIXME: supply cert list?
|
||||||
|
{
|
||||||
|
traceprint("FAILED to init SSL");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if(!open(req.host.c_str(), req.port))
|
if(!open(req.host.c_str(), req.port))
|
||||||
return false;
|
return false;
|
||||||
|
@ -1041,7 +1083,9 @@ void HttpSocket::_ParseHeaderFields(const char *s, size_t size)
|
||||||
++val;
|
++val;
|
||||||
std::string key(s, colon - s);
|
std::string key(s, colon - s);
|
||||||
strToLower(key);
|
strToLower(key);
|
||||||
_hdrs[key] = std::string(val, valEnd - val);
|
std::string valstr(val, valEnd - val);
|
||||||
|
_hdrs[key] = valstr;
|
||||||
|
traceprint("HDR: %s: %s\n", key.c_str(), valstr.c_str());
|
||||||
s = valEnd;
|
s = valEnd;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1088,10 +1132,7 @@ bool HttpSocket::_HandleStatus()
|
||||||
case 308:
|
case 308:
|
||||||
if(_followRedir)
|
if(_followRedir)
|
||||||
if(const char *loc = Hdr("location"))
|
if(const char *loc = Hdr("location"))
|
||||||
{
|
|
||||||
traceprint("Following HTTP redirect to: %s\n", loc);
|
|
||||||
_Redirect(loc, forceGET);
|
_Redirect(loc, forceGET);
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -1099,16 +1140,6 @@ bool HttpSocket::_HandleStatus()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HttpSocket::_Redirect(std::string loc, bool forceGET)
|
|
||||||
{
|
|
||||||
if(loc.empty())
|
|
||||||
return false;
|
|
||||||
// treat non-full URLs as local paths (browsers do it the same way)
|
|
||||||
if(loc.size() && !strchr(loc.c_str(), ':') && loc[0] != '/')
|
|
||||||
loc = '/' + loc;
|
|
||||||
return Download(loc, _curRequest.extraGetHeaders.c_str(), _curRequest.user, forceGET ? NULL : &_curRequest.post);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HttpSocket::IsRedirecting() const
|
bool HttpSocket::IsRedirecting() const
|
||||||
{
|
{
|
||||||
switch(_status)
|
switch(_status)
|
||||||
|
|
|
@ -145,6 +145,7 @@ struct Request
|
||||||
Request(const std::string& h, const std::string& res, int p = 80, void *u = NULL)
|
Request(const std::string& h, const std::string& res, int p = 80, void *u = NULL)
|
||||||
: host(h), resource(res), port(80), user(u), useSSL(false) {}
|
: host(h), resource(res), port(80), user(u), useSSL(false) {}
|
||||||
|
|
||||||
|
std::string protocol;
|
||||||
std::string host;
|
std::string host;
|
||||||
std::string header; // set by socket
|
std::string header; // set by socket
|
||||||
std::string resource;
|
std::string resource;
|
||||||
|
|
Loading…
Add table
Reference in a new issue