HTTPS oldal szöveges tartalom lekérdezés BOOST C++ segítségével

HTTPS oldal szöveges tartalom lekérdezés BOOST C++ segítségével
2020-11-26T17:50:47+01:00
2020-12-07T20:33:36+01:00
2022-10-15T21:16:38+02:00
Relative
Sziasztok!

Visual Studio 2015-ben írtam egy DLL file-t, ami HTTP lekérdezést hajt végre, annak szöveges tartalmát nyeri ki egy ostringstream file-ba (ostringstream_content). BOOST eljárással működik. Maga a programkód érdemi része egyszerű. Így néz ki:

#include <boost/asio.hpp> #include <iostream> #include <istream> #include <ostream> using boost::asio::ip::tcp; std::ostringstream ostringstream_content; const char* url[2] = { "www.domaincim.com", "/alkonyvtar/" }; int GetPageContent2(const char* argv[]) { try { boost::asio::io_service io_service; tcp::resolver resolver(io_service); tcp::resolver::query query(argv[0], "http"); tcp::resolver::iterator endpoint_iterator = resolver.resolve(query); tcp::resolver::iterator end; tcp::socket socket(io_service); boost::system::error_code error = boost::asio::error::host_not_found; while (error && endpoint_iterator != end) { socket.close(); socket.connect(*endpoint_iterator++, error); } if (error) throw boost::system::system_error(error); boost::asio::streambuf request; std::ostream request_stream(&request); request_stream << "GET " << argv[1] << " HTTP/1.1\r\n"; request_stream << "Host: " << argv[0] << "\r\n"; request_stream << "Accept: */*\r\n"; request_stream << "Cache-Control: no-cache\r\n"; request_stream << "Connection: close\r\n\r\n"; boost::asio::write(socket, request); boost::asio::streambuf response; boost::asio::read_until(socket, response, "\r\n"); // Read until EOF, writing data to output as we go. while (boost::asio::read(socket, response, boost::asio::transfer_at_least(1), error)) /*std::cout*/ ostringstream_content << &response; if (error != boost::asio::error::eof) throw boost::system::system_error(error); } catch (std::exception& e) { std::cout << "Exception: " << e.what() << "\n"; } return 0; }
Teljesen jól működik. Viszont HTTPS tartalmakkal nem boldogul. Hibaüzenetet kapok, hogy SSL lekérdezést használjak. Ezzel kapcsolatban szeretném a segítségeteket kérni, hogy hogyan lehet átalakítani úgy a kódot, hogy a HTTPS tartalmakat kezelje.

Maradni szeretnék a BOOST használatánál, mert az a környezet, ahol alkalmazom, elég kényes. Ezzel viszont már tudom, hogy nincs gond.
Neten nézelődtem megoldás után, de nem találtam olyat, amit használni tudtam volna. Ez valószínűleg a C++ tudásom hiányosságából fakad. Nem vagyok benne elég jártas.

Előre is köszönöm a segítséget!

Relative
Mutasd a teljes hozzászólást!
Libcurl és openssl a barátaid.
Mutasd a teljes hozzászólást!

  • Ha mindenképp boost::asio, akkor használhatod az SSL modulját, legalább is a gugli megtalálta nekem a dokumentációját. Azért készülj fel, hogy ez nem egy-két sor átírása lesz, mert az SSL még olyan finomságokat rárak a sima TCP kapcsolatra, mint titkosítási algoritmusok és tanúsítványok. (Nem csak arra való, hogy titkosítsa a kapcsolatot, hanem annak az ellenőrzésére is, hogy tényleg azzal kommunikálsz, akihez csatlakozni próbáltál.)
    Mutasd a teljes hozzászólást!
  • Igen - ettől tartok én is -, hogy ez nem olyan egyszerű, mint ahogy elsőre képzeltem.
    Mutasd a teljes hozzászólást!
  • Régebben próbálkoztam már Libcurl-lel, de valamiért nem működött. Mindenesetre újra megpróbálom.

    Kicsit megakasztott a Libcurl telepítése. Lehet, hogy újratelepítem az egész Visual Studio-t, mert fogalmam sincs, mi a gond....
    Mutasd a teljes hozzászólást!
    Csatolt állomány
  • Hol akadtál el a csaboka által küldött linkkel?
    Boost hivatalos oldalán vannak doksik példákkal.

    Boost::Beast környékén is szétnézhetsz.
    Mutasd a teljes hozzászólást!
  • Csaboka csak megerősített abban, hogy a BOOST ASIO nem egyszerű terep. A neten példák után keresve próbálkoztam az alábbi kóddal:

    #include <boost/asio.hpp> #include <iostream> #include <istream> #include <ostream> #include <boost/regex.hpp> #include <boost/asio/ssl.hpp> namespace ssl = boost::asio::ssl; using tcp = boost::asio::ip::tcp; using ssl_socket = ssl::stream<tcp::socket>; bool verify_certificate(bool /*preverified*/, boost::asio::ssl::verify_context& /*ctx*/) { /* char subject_name[256]; X509* cert = X509_STORE_CTX_get_current_cert(ctx.native_handle()); X509_NAME_oneline(X509_get_subject_name(cert), subject_name, 256); std::cout << "Verifying:\n" << subject_name << std::endl;*/ return true; } int GetPageContent3(const char* argv[]) { std::string url = "https://www.domaincim.com:443/auth/fuck/"; std::string json = "{ "hello" : "world" }"; std::string protocol, domain, port, path; boost::regex ex("(http|https)://([^/ :]+):?([^/ ]*)(/?[^ #?]*)\x3f?([^ #]*)#?([^ ]*)"); boost::cmatch what; if (regex_match(url.c_str(), what, ex)) { protocol = std::string(what[1].first, what[1].second); domain = std::string(what[2].first, what[2].second); port = std::string(what[3].first, what[3].second); path = std::string(what[4].first, what[4].second); } std::cout << "protocol: " << protocol << "\n"; std::cout << "domain: " << domain << "\n"; std::cout << "port: " << port << "\n"; std::cout << "path: " << path << "\n"; // Get a list of endpoints corresponding to the server name. boost::asio::io_service io_service; boost::asio::ssl::context ctx(ssl::context::sslv23); ctx.set_default_verify_paths(); ctx.set_options(boost::asio::ssl::context::default_workarounds | boost::asio::ssl::context::verify_none); ssl_socket socket(io_service, ctx); tcp::resolver resolver(io_service); tcp::resolver::query query(domain.c_str(), port.c_str()); tcp::resolver::iterator endpoint_iterator = resolver.resolve(query); socket.set_verify_mode(boost::asio::ssl::context::verify_none); // Try each endpoint until we successfully establish a connection. socket.set_verify_callback(verify_certificate); std::cout << "Connecting... " << std::flush; boost::asio::connect(socket.lowest_layer(), endpoint_iterator); std::cout << "Connected to " << socket.lowest_layer().remote_endpoint() << "\n"; socket.handshake(ssl_socket::client); socket.lowest_layer().set_option(tcp::no_delay(true)); // Form the request. We specify the "Connection: close" header so that the // server will close the socket after transmitting the response. This will // allow us to treat all data up until the EOF as the content. boost::asio::streambuf request; std::ostream request_stream(&request); request_stream << "GET " << path << " HTTP/1.1\r\n"; request_stream << "Host:" << domain << ":" << port << "\r\n"; request_stream << "User-Agent: C/1.0\r\n"; request_stream << "Accept: */*\r\n"; request_stream << "Connection: close\r\n\r\n"; int a = boost::asio::write(socket, request); std::cout << a << " byte sent\n"; std::vector<char> response(10 * 1024); boost::system::error_code ec; auto bytes_received = boost::asio::read(socket, boost::asio::buffer(response), boost::asio::transfer_all(), ec); ostringstream_content << &response; }
    Akkor adtam fel, miután telepítettem hozzá az OpenSSL-t és már önmagában az "#include boost/asio/ssl.hpp;" sor olyan hibaüzeneteket adott, amit nem tudtam értelmezni.

    Tudom, hogy alapvetően az én ismereteim hiányosak. De ez a C++ nekem néha olyan nyakatekertnek tűnik. Az is érhetetlen számomra, hogy a Visual Studio 2019-es verziójának telepítője miért 27 GB méretű. És akkor önmagában még használhatatlan is - számomra -, mert mindenhez külön modulokat kell telepítgetni (BOOST, Libcurl, OpenSSL, MySQL Connector stb). BOOST is például három és fél giga. Mi van?? Ok, tudom, hogy én vagyok hülye hozzá, de gyakorlatilag pár száz soros egyszerűnek tűnő feladatokat végrehajtó kódokat szeretnék csak készíteni... És elnézést a hisztiért, biztosan tudom, mindennek jó oka van. Na de azért mégis...
    Mutasd a teljes hozzászólást!
  • Ha csak a feladat gyors megoldása a cél, akkor szerintem használd a 'curl' exe-t, vagy akármilyen más ehhez hasonló kliens programot.

    Ezt a programot akár boost::Process segítségével is megtudod hívni megfelelően felparaméterezve és akkor nem kell neked C++-ban implementálnod.
    Ezzel sokat megspórolsz, ha nem megy kényelmesen külső 3rd party dolgok importálása a projektedbe, mert így nem kell se openssl, se libcurl függőséggel szívnod.

    Legegyszerűbb talán, ha készítesz egy külön scriptet, ami meghívja először a curl-t az generálja a letöltött állományt, majd meghívod a C++ programod ami értelmezi a letöltött dolgokat. Itt a C++ program felteszi, hogy a letöltött adatok már elérhetőek a specifikált helyen. (Esetleg pipe-olod egymásba őket)

    Amennyiben nem a C++ gyakorlása, boost::asio megértése a cél, akkor ezek sokkal egyszerűbb és járhatóbb út, rövidtávú cél orientáltabb..
    Mutasd a teljes hozzászólást!
  • Köszönöm mindenkinek a tanácsokat, segítséget.

    Végül Libcurl-lel sikerült megoldanom a tartalomlekérdezést.
    Mutasd a teljes hozzászólást!
  • Maradni szeretnék a BOOST használatánál, mert az a környezet, ahol alkalmazom, elég kényes

    Szóval akkor ez nem annyira fontos. Jó lett volna ezt az elején tisztázni.
    Mutasd a teljes hozzászólást!
  • Az elején nem voltam tisztában mindennel. Boost-os megoldás biztosan működött volna abban a környezetben, ahova készült a program. Libcurl-lel viszont éppen ellenkező tapasztalataim voltak.
    Mutasd a teljes hozzászólást!
Tetszett amit olvastál? Szeretnél a jövőben is értesülni a hasonló érdekességekről?
abcd