diff --git a/src/slic3r/Utils/CrealityPrint.cpp b/src/slic3r/Utils/CrealityPrint.cpp index 1df8c72d4b..d745e9f77d 100644 --- a/src/slic3r/Utils/CrealityPrint.cpp +++ b/src/slic3r/Utils/CrealityPrint.cpp @@ -185,7 +185,7 @@ std::string CrealityPrint::safe_filename(const std::string &filename) const void CrealityPrint::start_print(const std::string &filename) const { try { - std::string host = m_host; + std::string host = Http::get_host_from_url(m_host); auto const port = "9999"; json j2 = { diff --git a/src/slic3r/Utils/ElegooLink.cpp b/src/slic3r/Utils/ElegooLink.cpp index 46e593c926..95aee7f048 100644 --- a/src/slic3r/Utils/ElegooLink.cpp +++ b/src/slic3r/Utils/ElegooLink.cpp @@ -122,77 +122,6 @@ namespace Slic3r { } } - std::string get_host_from_url(const std::string& url_in) - { - std::string url = url_in; - // add http:// if there is no scheme - size_t double_slash = url.find("//"); - if (double_slash == std::string::npos) - url = "http://" + url; - std::string out = url; - CURLU* hurl = curl_url(); - if (hurl) { - // Parse the input URL. - CURLUcode rc = curl_url_set(hurl, CURLUPART_URL, url.c_str(), 0); - if (rc == CURLUE_OK) { - // Replace the address. - char* host; - rc = curl_url_get(hurl, CURLUPART_HOST, &host, 0); - if (rc == CURLUE_OK) { - char* port; - rc = curl_url_get(hurl, CURLUPART_PORT, &port, 0); - if (rc == CURLUE_OK && port != nullptr) { - out = std::string(host) + ":" + port; - curl_free(port); - } else { - out = host; - curl_free(host); - } - } - else - BOOST_LOG_TRIVIAL(error) << "ElegooLink get_host_from_url: failed to get host form URL " << url; - } - else - BOOST_LOG_TRIVIAL(error) << "ElegooLink get_host_from_url: failed to parse URL " << url; - curl_url_cleanup(hurl); - } - else - BOOST_LOG_TRIVIAL(error) << "ElegooLink get_host_from_url: failed to allocate curl_url"; - return out; - } - - std::string get_host_from_url_no_port(const std::string& url_in) - { - std::string url = url_in; - // add http:// if there is no scheme - size_t double_slash = url.find("//"); - if (double_slash == std::string::npos) - url = "http://" + url; - std::string out = url; - CURLU* hurl = curl_url(); - if (hurl) { - // Parse the input URL. - CURLUcode rc = curl_url_set(hurl, CURLUPART_URL, url.c_str(), 0); - if (rc == CURLUE_OK) { - // Replace the address. - char* host; - rc = curl_url_get(hurl, CURLUPART_HOST, &host, 0); - if (rc == CURLUE_OK) { - out = host; - curl_free(host); - } - else - BOOST_LOG_TRIVIAL(error) << "ElegooLink get_host_from_url: failed to get host form URL " << url; - } - else - BOOST_LOG_TRIVIAL(error) << "ElegooLink get_host_from_url: failed to parse URL " << url; - curl_url_cleanup(hurl); - } - else - BOOST_LOG_TRIVIAL(error) << "ElegooLink get_host_from_url: failed to allocate curl_url"; - return out; - } - #ifdef WIN32 // Workaround for Windows 10/11 mDNS resolve issue, where two mDNS resolves in succession fail. std::string substitute_host(const std::string& orig_addr, std::string sub_addr) @@ -337,7 +266,7 @@ namespace Slic3r { std::replace(web_path.begin(), web_path.end(), '\\', '/'); web_path = "file://" + web_path; web_path += "?access_code=" + get_cc2_token(config->opt_string("printhost_apikey")); - web_path += "&ip=" + get_host_from_url(host) + "&id=elegoo_123456"; + web_path += "&ip=" + Http::get_host_header_value(host) + "&id=elegoo_123456"; const std::string lang = GUI::wxGetApp().current_language_code_safe().utf8_string(); if (!lang.empty()) @@ -503,7 +432,6 @@ namespace Slic3r { // Msg contains ip string. auto url = substitute_host(make_url(""), GUI::into_u8(msg)); msg.Clear(); - std::string host = get_host_from_url(m_host); auto http = Http::get(url); // std::move(url)); // "Host" header is necessary here. We have resolved IP address and subsituted it into "url" variable. // And when creating Http object above, libcurl automatically includes "Host" header from address it got. @@ -511,7 +439,7 @@ namespace Slic3r { // Not changing the host would work on the most cases (where there is 1 service on 1 hostname) but would break when f.e. reverse // proxy is used (issue #9734). Also when allow_ip_resolve = 0, this is not needed, but it should not break anything if it stays. // https://www.rfc-editor.org/rfc/rfc7230#section-5.4 - http.header("Host", host); + http.header("Host", Http::get_host_header_value(m_host)); set_auth(http); http.on_error([&](std::string body, std::string error, unsigned status) { BOOST_LOG_TRIVIAL(error) << boost::format("%1%: Error getting version at %2% : %3%, HTTP %4%, body: `%5%`") % name % url % @@ -555,11 +483,10 @@ namespace Slic3r { bool res = true; const auto token = cc2_token(); auto url = substitute_host(make_cc2_info_url(), GUI::into_u8(msg)); - std::string host_header = get_host_from_url(m_host); auto http = Http::get(url); msg.Clear(); - http.header("Host", host_header); + http.header("Host", Http::get_host_header_value(m_host)); http.header("X-Token", token); http.header("Accept", "application/json"); http.on_error([&](std::string body, std::string error, unsigned status) { @@ -618,7 +545,7 @@ namespace Slic3r { std::string url = substitute_host(make_cc2_upload_url(), resolved_addr.to_string()); info_fn(L"resolve", boost::nowide::widen(url)); - return loopUploadCC2(url, get_host_from_url(m_host), std::move(upload_data), prorgess_fn, error_fn, info_fn); + return loopUploadCC2(url, Http::get_host_header_value(m_host), std::move(upload_data), prorgess_fn, error_fn, info_fn); } wxString legacy_msg = GUI::from_u8(resolved_addr.to_string()); @@ -664,7 +591,7 @@ namespace Slic3r { } #endif // _WIN32 - return loopUploadCC2(url, get_host_from_url(m_host), std::move(upload_data), prorgess_fn, error_fn, info_fn); + return loopUploadCC2(url, Http::get_host_header_value(m_host), std::move(upload_data), prorgess_fn, error_fn, info_fn); } wxString legacy_msg; @@ -803,8 +730,7 @@ namespace Slic3r { // on the most cases (where there is 1 service on 1 hostname) but would break when f.e. reverse proxy is used (issue #9734). Also // when allow_ip_resolve = 0, this is not needed, but it should not break anything if it stays. // https://www.rfc-editor.org/rfc/rfc7230#section-5.4 - std::string host = get_host_from_url(m_host); - http.header("Host", host); + http.header("Host", Http::get_host_header_value(m_host)); http.header("Accept", "application/json, text/plain, */*"); #endif // _WIN32 set_auth(http); @@ -835,7 +761,7 @@ namespace Slic3r { if (res) { if (upload_data.post_action == PrintHostPostUploadAction::StartPrint) { // connect to websocket, since the upload is successful, the file will be printed - std::string wsUrl = get_host_from_url_no_port(m_host); + std::string wsUrl = Http::get_host_from_url(m_host); WebSocketClient client; try { client.connect(wsUrl, "3030", "/websocket"); @@ -1016,7 +942,7 @@ namespace Slic3r { #ifndef WIN32 return upload_inner_with_host(std::move(upload_data), prorgess_fn, error_fn, info_fn); #else - std::string host = get_host_from_url_no_port(m_host); + std::string host = Http::get_host_from_url(m_host); // decide what to do based on m_host - resolve hostname or upload to ip std::vector resolved_addr; diff --git a/src/slic3r/Utils/Http.cpp b/src/slic3r/Utils/Http.cpp index 4f5227167c..f1ff056d10 100644 --- a/src/slic3r/Utils/Http.cpp +++ b/src/slic3r/Utils/Http.cpp @@ -978,6 +978,51 @@ std::string Http::get_filename_from_url(const std::string &url) return path_url.substr(start_pos + 1, path_url.length() - start_pos - 1); } +std::string Http::get_host_from_url(const std::string &url_in, std::string *port) +{ + std::string url = url_in; + if (url.find("//") == std::string::npos) + url = "http://" + url; + + if (port) + port->clear(); + std::string out = url_in; + CURLU *hurl = curl_url(); + if (hurl) { + CURLUcode rc = curl_url_set(hurl, CURLUPART_URL, url.c_str(), 0); + if (rc == CURLUE_OK) { + char *host; + rc = curl_url_get(hurl, CURLUPART_HOST, &host, 0); + if (rc == CURLUE_OK) { + out = host; + curl_free(host); + if (port) { + char *pstr; + rc = curl_url_get(hurl, CURLUPART_PORT, &pstr, 0); + if (rc == CURLUE_OK && pstr) { + *port = pstr; + curl_free(pstr); + } + } + } else + BOOST_LOG_TRIVIAL(error) << "Http::get_host_from_url: failed to get host from URL " << url; + } else + BOOST_LOG_TRIVIAL(error) << "Http::get_host_from_url: failed to parse URL " << url; + curl_url_cleanup(hurl); + } else + BOOST_LOG_TRIVIAL(error) << "Http::get_host_from_url: failed to allocate curl_url"; + return out; +} + +std::string Http::get_host_header_value(const std::string &url) +{ + std::string port; + std::string host = get_host_from_url(url, &port); + if (!port.empty()) + host += ":" + port; + return host; +} + std::ostream& operator<<(std::ostream &os, const Http::Progress &progress) { os << "Http::Progress(" diff --git a/src/slic3r/Utils/Http.hpp b/src/slic3r/Utils/Http.hpp index 4b6967a454..a44a95e605 100644 --- a/src/slic3r/Utils/Http.hpp +++ b/src/slic3r/Utils/Http.hpp @@ -204,6 +204,8 @@ public: static std::string url_decode(const std::string &str); static std::string get_filename_from_url(const std::string &url); + static std::string get_host_from_url(const std::string &url, std::string *port = nullptr); + static std::string get_host_header_value(const std::string &url); private: Http(const std::string &url); diff --git a/src/slic3r/Utils/OctoPrint.cpp b/src/slic3r/Utils/OctoPrint.cpp index 68a28afbf7..ece2680a73 100644 --- a/src/slic3r/Utils/OctoPrint.cpp +++ b/src/slic3r/Utils/OctoPrint.cpp @@ -33,45 +33,6 @@ namespace Slic3r { namespace { #ifdef WIN32 -std::string get_host_from_url(const std::string& url_in) -{ - std::string url = url_in; - // add http:// if there is no scheme - size_t double_slash = url.find("//"); - if (double_slash == std::string::npos) - url = "http://" + url; - std::string out = url; - CURLU* hurl = curl_url(); - if (hurl) { - // Parse the input URL. - CURLUcode rc = curl_url_set(hurl, CURLUPART_URL, url.c_str(), 0); - if (rc == CURLUE_OK) { - // Replace the address. - char* host; - rc = curl_url_get(hurl, CURLUPART_HOST, &host, 0); - if (rc == CURLUE_OK) { - char* port; - rc = curl_url_get(hurl, CURLUPART_PORT, &port, 0); - if (rc == CURLUE_OK && port != nullptr) { - out = std::string(host) + ":" + port; - curl_free(port); - } else { - out = host; - curl_free(host); - } - } - else - BOOST_LOG_TRIVIAL(error) << "OctoPrint get_host_from_url: failed to get host form URL " << url; - } - else - BOOST_LOG_TRIVIAL(error) << "OctoPrint get_host_from_url: failed to parse URL " << url; - curl_url_cleanup(hurl); - } - else - BOOST_LOG_TRIVIAL(error) << "OctoPrint get_host_from_url: failed to allocate curl_url"; - return out; -} - // Workaround for Windows 10/11 mDNS resolve issue, where two mDNS resolves in succession fail. std::string substitute_host(const std::string& orig_addr, std::string sub_addr) { @@ -186,7 +147,6 @@ bool OctoPrint::test_with_resolved_ip(wxString &msg) const BOOST_LOG_TRIVIAL(info) << boost::format("%1%: Get version at: %2%") % name % url; - std::string host = get_host_from_url(m_host); auto http = Http::get(url);//std::move(url)); // "Host" header is necessary here. We have resolved IP address and subsituted it into "url" variable. // And when creating Http object above, libcurl automatically includes "Host" header from address it got. @@ -194,7 +154,7 @@ bool OctoPrint::test_with_resolved_ip(wxString &msg) const // Not changing the host would work on the most cases (where there is 1 service on 1 hostname) but would break when f.e. reverse proxy is used (issue #9734). // Also when allow_ip_resolve = 0, this is not needed, but it should not break anything if it stays. // https://www.rfc-editor.org/rfc/rfc7230#section-5.4 - http.header("Host", host); + http.header("Host", Http::get_host_header_value(m_host)); set_auth(http); http .on_error([&](std::string body, std::string error, unsigned status) { @@ -306,7 +266,7 @@ bool OctoPrint::upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, Erro #ifndef WIN32 return upload_inner_with_host(std::move(upload_data), prorgess_fn, error_fn, info_fn); #else - std::string host = get_host_from_url(m_host); + std::string host = Http::get_host_from_url(m_host); // decide what to do based on m_host - resolve hostname or upload to ip std::vector resolved_addr; @@ -393,14 +353,13 @@ bool OctoPrint::upload_inner_with_resolved_ip(PrintHostUpload upload_data, Progr % upload_parent_path.string() % (upload_data.post_action == PrintHostPostUploadAction::StartPrint ? "true" : "false"); - std::string host = get_host_from_url(m_host); auto http = Http::post(url);//std::move(url)); // "Host" header is necessary here. We have resolved IP address and subsituted it into "url" variable. // And when creating Http object above, libcurl automatically includes "Host" header from address it got. // Thus "Host" is set to the resolved IP instead of host filled by user. We need to change it back. // Not changing the host would work on the most cases (where there is 1 service on 1 hostname) but would break when f.e. reverse proxy is used (issue #9734). // https://www.rfc-editor.org/rfc/rfc7230#section-5.4 - http.header("Host", host); + http.header("Host", Http::get_host_header_value(m_host)); set_auth(http); http.form_add("print", upload_data.post_action == PrintHostPostUploadAction::StartPrint ? "true" : "false") .form_add("path", upload_parent_path.string()) // XXX: slashes on windows ??? @@ -486,8 +445,7 @@ bool OctoPrint::upload_inner_with_host(PrintHostUpload upload_data, ProgressFn p // Not changing the host would work on the most cases (where there is 1 service on 1 hostname) but would break when f.e. reverse proxy is used (issue #9734). // Also when allow_ip_resolve = 0, this is not needed, but it should not break anything if it stays. // https://www.rfc-editor.org/rfc/rfc7230#section-5.4 - std::string host = get_host_from_url(m_host); - http.header("Host", host); + http.header("Host", Http::get_host_header_value(m_host)); #endif // _WIN32 set_auth(http); http.form_add("print", upload_data.post_action == PrintHostPostUploadAction::StartPrint ? "true" : "false") @@ -884,7 +842,6 @@ bool PrusaLink::test_with_resolved_ip_and_method_check(wxString& msg, bool& use_ BOOST_LOG_TRIVIAL(info) << boost::format("%1%: Get version at: %2%") % name % url; - std::string host = get_host_from_url(m_host); auto http = Http::get(url);//std::move(url)); // "Host" header is necessary here. We have resolved IP address and subsituted it into "url" variable. // And when creating Http object above, libcurl automatically includes "Host" header from address it got. @@ -892,7 +849,7 @@ bool PrusaLink::test_with_resolved_ip_and_method_check(wxString& msg, bool& use_ // Not changing the host would work on the most cases (where there is 1 service on 1 hostname) but would break when f.e. reverse proxy is used (issue #9734). // Also when allow_ip_resolve = 0, this is not needed, but it should not break anything if it stays. // https://www.rfc-editor.org/rfc/rfc7230#section-5.4 - http.header("Host", host); + http.header("Host", Http::get_host_header_value(m_host)); set_auth(http); http .on_error([&](std::string body, std::string error, unsigned status) { @@ -1053,8 +1010,7 @@ bool PrusaLink::put_inner(PrintHostUpload upload_data, std::string url, const st // Thus "Host" is set to the resolved IP instead of host filled by user. We need to change it back. // Not changing the host would work on the most cases (where there is 1 service on 1 hostname) but would break when f.e. reverse proxy is used (issue #9734). // https://www.rfc-editor.org/rfc/rfc7230#section-5.4 - std::string host = get_host_from_url(m_host); - http.header("Host", host); + http.header("Host", Http::get_host_header_value(m_host)); #endif // _WIN32 set_auth(http); // This is ugly, but works. There was an error at PrusaLink side that accepts any string at Print-After-Upload as true, thus False was also triggering print after upload. @@ -1103,8 +1059,7 @@ bool PrusaLink::post_inner(PrintHostUpload upload_data, std::string url, const s // Thus "Host" is set to the resolved IP instead of host filled by user. We need to change it back. // Not changing the host would work on the most cases (where there is 1 service on 1 hostname) but would break when f.e. reverse proxy is used (issue #9734). // https://www.rfc-editor.org/rfc/rfc7230#section-5.4 - std::string host = get_host_from_url(m_host); - http.header("Host", host); + http.header("Host", Http::get_host_header_value(m_host)); #endif // _WIN32 set_auth(http); set_http_post_header_args(http, upload_data.post_action);