/* * barrier -- mouse and keyboard sharing utility * Copyright (C) 2014-2016 Symless Ltd. * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file LICENSE that should have accompanied this file. * * This package is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "arch/win32/ArchInternetWindows.h" #include "arch/win32/XArchWindows.h" #include "arch/Arch.h" #include "base/String.h" #include "common/Version.h" #include #include #include struct WinINetUrl { std::string m_scheme; std::string m_host; std::string m_path; INTERNET_PORT m_port; DWORD m_flags; }; class WinINetRequest { public: WinINetRequest(const std::string& url); ~WinINetRequest(); std::string send(); void openSession(); void connect(); void openRequest(); private: HINTERNET m_session; HINTERNET m_connect; HINTERNET m_request; WinINetUrl m_url; bool m_used; }; // // ArchInternetWindows // std::string ArchInternetWindows::get(const std::string& url) { WinINetRequest request(url); return request.send(); } std::string ArchInternetWindows::urlEncode(const std::string& url) { TCHAR buffer[1024]; DWORD bufferSize = sizeof(buffer); if (UrlEscape(url.c_str(), buffer, &bufferSize, URL_ESCAPE_UNSAFE) != S_OK) { throw XArch(new XArchEvalWindows()); } std::string result(buffer); // the win32 url encoding functions are pretty useless (to us) and only // escape "unsafe" chars, but not + or =, so we need to replace these // manually (and probably many other chars). barrier::string::findReplaceAll(result, "+", "%2B"); barrier::string::findReplaceAll(result, "=", "%3D"); return result; } // // WinINetRequest // static WinINetUrl parseUrl(const std::string& url); WinINetRequest::WinINetRequest(const std::string& url) : m_session(NULL), m_connect(NULL), m_request(NULL), m_used(false), m_url(parseUrl(url)) { } WinINetRequest::~WinINetRequest() { if (m_request != NULL) { InternetCloseHandle(m_request); } if (m_connect != NULL) { InternetCloseHandle(m_connect); } if (m_session != NULL) { InternetCloseHandle(m_session); } } std::string WinINetRequest::send() { if (m_used) { throw XArch("class is one time use."); } m_used = true; openSession(); connect(); openRequest(); std::string headers("Content-Type: text/html"); if (!HttpSendRequest(m_request, headers.c_str(), (DWORD)headers.length(), NULL, NULL)) { throw XArch(new XArchEvalWindows()); } std::stringstream result; CHAR buffer[1025]; DWORD read = 0; while (InternetReadFile(m_request, buffer, sizeof(buffer) - 1, &read) && (read != 0)) { buffer[read] = 0; result << buffer; read = 0; } return result.str(); } void WinINetRequest::openSession() { std::stringstream userAgent; userAgent << "Barrier "; userAgent << kVersion; m_session = InternetOpen( userAgent.str().c_str(), INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, NULL); if (m_session == NULL) { throw XArch(new XArchEvalWindows()); } } void WinINetRequest::connect() { m_connect = InternetConnect( m_session, m_url.m_host.c_str(), m_url.m_port, NULL, NULL, INTERNET_SERVICE_HTTP, NULL, NULL); if (m_connect == NULL) { throw XArch(new XArchEvalWindows()); } } void WinINetRequest::openRequest() { m_request = HttpOpenRequest( m_connect, "GET", m_url.m_path.c_str(), HTTP_VERSION, NULL, NULL, m_url.m_flags, NULL); if (m_request == NULL) { throw XArch(new XArchEvalWindows()); } } // nb: i tried to use InternetCrackUrl here, but couldn't quite get that to // work. here's some (less robust) code to split the url into components. // this works fine with simple urls, but doesn't consider the full url spec. static WinINetUrl parseUrl(const std::string& url) { WinINetUrl parsed; size_t schemeEnd = url.find("://"); size_t hostEnd = url.find('/', schemeEnd + 3); parsed.m_scheme = url.substr(0, schemeEnd); parsed.m_host = url.substr(schemeEnd + 3, hostEnd - (schemeEnd + 3)); parsed.m_path = url.substr(hostEnd); parsed.m_port = INTERNET_DEFAULT_HTTP_PORT; parsed.m_flags = 0; if (parsed.m_scheme.find("https") != std::string::npos) { parsed.m_port = INTERNET_DEFAULT_HTTPS_PORT; parsed.m_flags = INTERNET_FLAG_SECURE; } return parsed; }