From 9227cc114a9a167855ca7a9ad9fc1364f01e3263 Mon Sep 17 00:00:00 2001 From: fgenesis Date: Fri, 2 Oct 2015 17:44:54 +0200 Subject: [PATCH] Fix HTTP->HTTPS redirect, local redirect, and some other issues. Accept untrusted certs for now. --- main.cpp | 11 +++++-- minihttp.cpp | 83 ++++++++++++++++++++++++++++++++++++---------------- minihttp.h | 1 + 3 files changed, 67 insertions(+), 28 deletions(-) diff --git a/main.cpp b/main.cpp index b48be73..bded52d 100644 --- a/main.cpp +++ b/main.cpp @@ -24,7 +24,7 @@ protected: { puts("_OnOpen()"); 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(); } @@ -45,6 +45,12 @@ protected: int main(int argc, char *argv[]) { + if(argc != 2) + { + puts("URL plz!"); + return 1; + } + #ifdef SIGPIPE // On *NIX systems, don't signal writing to a closed socket. 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://example.com"); // Queue another one //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; diff --git a/minihttp.cpp b/minihttp.cpp index 6695747..2afba5b 100644 --- a/minihttp.cpp +++ b/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: // 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 *sl = strstr(p, "//"); unsigned int offs = 0; - bool ssl = false; 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) + { + useSSL = false; offs = 7; + } else if(strncmp(p, "https://", 8) == 0) { - ssl = true; + useSSL = true; offs = 8; } else @@ -253,7 +259,6 @@ bool SplitURI(const std::string& uri, std::string& host, std::string& file, int& port = atoi(host.c_str() + colon); host.erase(port); } - useSSL = ssl; return true; } @@ -316,9 +321,6 @@ TcpSocket::~TcpSocket() close(); if(_inbuf) free(_inbuf); -#ifdef MINIHTTP_USE_POLARSSL - shutdownSSL(); -#endif } bool TcpSocket::isOpen(void) @@ -339,6 +341,7 @@ void TcpSocket::close(void) if(_sslctx) ((SSLCtx*)_sslctx)->reset(); net_close(_s); + shutdownSSL(); #else # ifdef _WIN32 ::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_bio(&ctx->ssl, net_recv, ps, net_send, ps); + traceprint("SSL handshake now...\n"); int err; while( (err = ssl_handshake(&ctx->ssl)) ) { @@ -445,7 +449,7 @@ static bool _openSSL(void *ps, SSLCtx *ctx) return false; } } - + traceprint("SSL handshake done\n"); return true; } #endif @@ -475,6 +479,7 @@ bool TcpSocket::open(const char *host /* = NULL */, unsigned int port /* = 0 */) return false; } + traceprint("TcpSocket::open(): host = [%s], port = %d\n", host, port); assert(!SOCKETVALID(_s)); @@ -500,11 +505,14 @@ bool TcpSocket::open(const char *host /* = NULL */, unsigned int port /* = 0 */) #ifdef MINIHTTP_USE_POLARSSL if(_sslctx) + { + traceprint("TcpSocket::open(): SSL requested...\n"); if(!_openSSL(&_s, (SSLCtx*)_sslctx)) { close(); return false; } + } #endif _OnOpen(); @@ -581,7 +589,7 @@ SSLResult TcpSocket::verifySSL() r |= SSLR_CERT_FUTURE; // More than just this? - if(res != BADCERT_SKIP_VERIFY) + if(res & (BADCERT_SKIP_VERIFY | SSLR_CERT_NOT_TRUSTED)) r |= SSLR_FAIL; } @@ -589,7 +597,11 @@ SSLResult TcpSocket::verifySSL() } #else // MINIHTTP_USE_POLARSSL 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; } #endif @@ -812,7 +824,7 @@ bool HttpSocket::Download(const std::string& url, const char *extraRequest /*= req.user = user; if(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 req.host = _curRequest.host; if(req.port < 0) @@ -822,6 +834,32 @@ bool HttpSocket::Download(const std::string& url, const char *extraRequest /*= 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 */) { Request req(what, _host, _lastport, user); @@ -929,7 +967,11 @@ bool HttpSocket::_OpenRequest(const Request& req) if(req.useSSL && !hasSSL()) { 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)) return false; @@ -1041,7 +1083,9 @@ void HttpSocket::_ParseHeaderFields(const char *s, size_t size) ++val; std::string key(s, colon - s); 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; } } @@ -1088,10 +1132,7 @@ bool HttpSocket::_HandleStatus() case 308: if(_followRedir) if(const char *loc = Hdr("location")) - { - traceprint("Following HTTP redirect to: %s\n", loc); _Redirect(loc, forceGET); - } return false; 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 { switch(_status) diff --git a/minihttp.h b/minihttp.h index b5f5113..6a7b698 100644 --- a/minihttp.h +++ b/minihttp.h @@ -145,6 +145,7 @@ struct Request 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) {} + std::string protocol; std::string host; std::string header; // set by socket std::string resource;