1*9712c20fSFrederick Mayle // Copyright 2006 Google LLC 2*9712c20fSFrederick Mayle // 3*9712c20fSFrederick Mayle // Redistribution and use in source and binary forms, with or without 4*9712c20fSFrederick Mayle // modification, are permitted provided that the following conditions are 5*9712c20fSFrederick Mayle // met: 6*9712c20fSFrederick Mayle // 7*9712c20fSFrederick Mayle // * Redistributions of source code must retain the above copyright 8*9712c20fSFrederick Mayle // notice, this list of conditions and the following disclaimer. 9*9712c20fSFrederick Mayle // * Redistributions in binary form must reproduce the above 10*9712c20fSFrederick Mayle // copyright notice, this list of conditions and the following disclaimer 11*9712c20fSFrederick Mayle // in the documentation and/or other materials provided with the 12*9712c20fSFrederick Mayle // distribution. 13*9712c20fSFrederick Mayle // * Neither the name of Google LLC nor the names of its 14*9712c20fSFrederick Mayle // contributors may be used to endorse or promote products derived from 15*9712c20fSFrederick Mayle // this software without specific prior written permission. 16*9712c20fSFrederick Mayle // 17*9712c20fSFrederick Mayle // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18*9712c20fSFrederick Mayle // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19*9712c20fSFrederick Mayle // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20*9712c20fSFrederick Mayle // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21*9712c20fSFrederick Mayle // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22*9712c20fSFrederick Mayle // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23*9712c20fSFrederick Mayle // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24*9712c20fSFrederick Mayle // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25*9712c20fSFrederick Mayle // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26*9712c20fSFrederick Mayle // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27*9712c20fSFrederick Mayle // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28*9712c20fSFrederick Mayle 29*9712c20fSFrederick Mayle #ifdef HAVE_CONFIG_H 30*9712c20fSFrederick Mayle #include <config.h> // Must come first 31*9712c20fSFrederick Mayle #endif 32*9712c20fSFrederick Mayle 33*9712c20fSFrederick Mayle #include <assert.h> 34*9712c20fSFrederick Mayle 35*9712c20fSFrederick Mayle // Disable exception handler warnings. 36*9712c20fSFrederick Mayle #pragma warning(disable:4530) 37*9712c20fSFrederick Mayle 38*9712c20fSFrederick Mayle #include <fstream> 39*9712c20fSFrederick Mayle #include <vector> 40*9712c20fSFrederick Mayle 41*9712c20fSFrederick Mayle #include "common/windows/string_utils-inl.h" 42*9712c20fSFrederick Mayle 43*9712c20fSFrederick Mayle #include "common/windows/http_upload.h" 44*9712c20fSFrederick Mayle 45*9712c20fSFrederick Mayle namespace { 46*9712c20fSFrederick Mayle using std::string; 47*9712c20fSFrederick Mayle using std::wstring; 48*9712c20fSFrederick Mayle using std::map; 49*9712c20fSFrederick Mayle using std::vector; 50*9712c20fSFrederick Mayle using std::ifstream; 51*9712c20fSFrederick Mayle using std::ios; 52*9712c20fSFrederick Mayle 53*9712c20fSFrederick Mayle const wchar_t kUserAgent[] = L"Breakpad/1.0 (Windows)"; 54*9712c20fSFrederick Mayle 55*9712c20fSFrederick Mayle // Helper class which closes an internet handle when it goes away 56*9712c20fSFrederick Mayle class AutoInternetHandle { 57*9712c20fSFrederick Mayle public: AutoInternetHandle(HINTERNET handle)58*9712c20fSFrederick Mayle explicit AutoInternetHandle(HINTERNET handle) : handle_(handle) {} ~AutoInternetHandle()59*9712c20fSFrederick Mayle ~AutoInternetHandle() { 60*9712c20fSFrederick Mayle if (handle_) { 61*9712c20fSFrederick Mayle InternetCloseHandle(handle_); 62*9712c20fSFrederick Mayle } 63*9712c20fSFrederick Mayle } 64*9712c20fSFrederick Mayle get()65*9712c20fSFrederick Mayle HINTERNET get() { return handle_; } 66*9712c20fSFrederick Mayle 67*9712c20fSFrederick Mayle private: 68*9712c20fSFrederick Mayle HINTERNET handle_; 69*9712c20fSFrederick Mayle }; 70*9712c20fSFrederick Mayle UTF8ToWide(const string & utf8)71*9712c20fSFrederick Mayle wstring UTF8ToWide(const string& utf8) { 72*9712c20fSFrederick Mayle if (utf8.length() == 0) { 73*9712c20fSFrederick Mayle return wstring(); 74*9712c20fSFrederick Mayle } 75*9712c20fSFrederick Mayle 76*9712c20fSFrederick Mayle // compute the length of the buffer we'll need 77*9712c20fSFrederick Mayle int charcount = MultiByteToWideChar(CP_UTF8, 0, utf8.c_str(), -1, NULL, 0); 78*9712c20fSFrederick Mayle 79*9712c20fSFrederick Mayle if (charcount == 0) { 80*9712c20fSFrederick Mayle return wstring(); 81*9712c20fSFrederick Mayle } 82*9712c20fSFrederick Mayle 83*9712c20fSFrederick Mayle // convert 84*9712c20fSFrederick Mayle wchar_t* buf = new wchar_t[charcount]; 85*9712c20fSFrederick Mayle MultiByteToWideChar(CP_UTF8, 0, utf8.c_str(), -1, buf, charcount); 86*9712c20fSFrederick Mayle wstring result(buf); 87*9712c20fSFrederick Mayle delete[] buf; 88*9712c20fSFrederick Mayle return result; 89*9712c20fSFrederick Mayle } 90*9712c20fSFrederick Mayle WideToMBCP(const wstring & wide,unsigned int cp)91*9712c20fSFrederick Mayle string WideToMBCP(const wstring& wide, unsigned int cp) { 92*9712c20fSFrederick Mayle if (wide.length() == 0) { 93*9712c20fSFrederick Mayle return string(); 94*9712c20fSFrederick Mayle } 95*9712c20fSFrederick Mayle 96*9712c20fSFrederick Mayle // compute the length of the buffer we'll need 97*9712c20fSFrederick Mayle int charcount = WideCharToMultiByte(cp, 0, wide.c_str(), -1, 98*9712c20fSFrederick Mayle NULL, 0, NULL, NULL); 99*9712c20fSFrederick Mayle if (charcount == 0) { 100*9712c20fSFrederick Mayle return string(); 101*9712c20fSFrederick Mayle } 102*9712c20fSFrederick Mayle 103*9712c20fSFrederick Mayle // convert 104*9712c20fSFrederick Mayle char *buf = new char[charcount]; 105*9712c20fSFrederick Mayle WideCharToMultiByte(cp, 0, wide.c_str(), -1, buf, charcount, 106*9712c20fSFrederick Mayle NULL, NULL); 107*9712c20fSFrederick Mayle 108*9712c20fSFrederick Mayle string result(buf); 109*9712c20fSFrederick Mayle delete[] buf; 110*9712c20fSFrederick Mayle return result; 111*9712c20fSFrederick Mayle } 112*9712c20fSFrederick Mayle GetFileContents(const wstring & filename,vector<char> * contents)113*9712c20fSFrederick Mayle bool GetFileContents(const wstring& filename, vector<char>* contents) { 114*9712c20fSFrederick Mayle bool rv = false; 115*9712c20fSFrederick Mayle // The "open" method on pre-MSVC8 ifstream implementations doesn't accept a 116*9712c20fSFrederick Mayle // wchar_t* filename, so use _wfopen directly in that case. For VC8 and 117*9712c20fSFrederick Mayle // later, _wfopen has been deprecated in favor of _wfopen_s, which does 118*9712c20fSFrederick Mayle // not exist in earlier versions, so let the ifstream open the file itself. 119*9712c20fSFrederick Mayle // GCC doesn't support wide file name and opening on FILE* requires ugly 120*9712c20fSFrederick Mayle // hacks, so fallback to multi byte file. 121*9712c20fSFrederick Mayle #ifdef _MSC_VER 122*9712c20fSFrederick Mayle ifstream file; 123*9712c20fSFrederick Mayle file.open(filename.c_str(), ios::binary); 124*9712c20fSFrederick Mayle #else // GCC 125*9712c20fSFrederick Mayle ifstream file(WideToMBCP(filename, CP_ACP).c_str(), ios::binary); 126*9712c20fSFrederick Mayle #endif // _MSC_VER >= 1400 127*9712c20fSFrederick Mayle if (file.is_open()) { 128*9712c20fSFrederick Mayle file.seekg(0, ios::end); 129*9712c20fSFrederick Mayle std::streamoff length = file.tellg(); 130*9712c20fSFrederick Mayle // Check for loss of data when converting lenght from std::streamoff into 131*9712c20fSFrederick Mayle // std::vector<char>::size_type 132*9712c20fSFrederick Mayle std::vector<char>::size_type vector_size = 133*9712c20fSFrederick Mayle static_cast<std::vector<char>::size_type>(length); 134*9712c20fSFrederick Mayle if (static_cast<std::streamoff>(vector_size) == length) { 135*9712c20fSFrederick Mayle contents->resize(vector_size); 136*9712c20fSFrederick Mayle if (length != 0) { 137*9712c20fSFrederick Mayle file.seekg(0, ios::beg); 138*9712c20fSFrederick Mayle file.read(&((*contents)[0]), length); 139*9712c20fSFrederick Mayle } 140*9712c20fSFrederick Mayle rv = true; 141*9712c20fSFrederick Mayle } 142*9712c20fSFrederick Mayle file.close(); 143*9712c20fSFrederick Mayle } 144*9712c20fSFrederick Mayle return rv; 145*9712c20fSFrederick Mayle } 146*9712c20fSFrederick Mayle CheckParameters(const map<wstring,wstring> & parameters)147*9712c20fSFrederick Mayle bool CheckParameters(const map<wstring, wstring>& parameters) { 148*9712c20fSFrederick Mayle for (map<wstring, wstring>::const_iterator pos = parameters.begin(); 149*9712c20fSFrederick Mayle pos != parameters.end(); ++pos) { 150*9712c20fSFrederick Mayle const wstring& str = pos->first; 151*9712c20fSFrederick Mayle if (str.size() == 0) { 152*9712c20fSFrederick Mayle return false; // disallow empty parameter names 153*9712c20fSFrederick Mayle } 154*9712c20fSFrederick Mayle for (unsigned int i = 0; i < str.size(); ++i) { 155*9712c20fSFrederick Mayle wchar_t c = str[i]; 156*9712c20fSFrederick Mayle if (c < 32 || c == '"' || c > 127) { 157*9712c20fSFrederick Mayle return false; 158*9712c20fSFrederick Mayle } 159*9712c20fSFrederick Mayle } 160*9712c20fSFrederick Mayle } 161*9712c20fSFrederick Mayle return true; 162*9712c20fSFrederick Mayle } 163*9712c20fSFrederick Mayle 164*9712c20fSFrederick Mayle // Converts a UTF16 string to UTF8. WideToUTF8(const wstring & wide)165*9712c20fSFrederick Mayle string WideToUTF8(const wstring& wide) { 166*9712c20fSFrederick Mayle return WideToMBCP(wide, CP_UTF8); 167*9712c20fSFrederick Mayle } 168*9712c20fSFrederick Mayle ReadResponse(HINTERNET request,wstring * response)169*9712c20fSFrederick Mayle bool ReadResponse(HINTERNET request, wstring *response) { 170*9712c20fSFrederick Mayle bool has_content_length_header = false; 171*9712c20fSFrederick Mayle wchar_t content_length[32]; 172*9712c20fSFrederick Mayle DWORD content_length_size = sizeof(content_length); 173*9712c20fSFrederick Mayle DWORD claimed_size = 0; 174*9712c20fSFrederick Mayle string response_body; 175*9712c20fSFrederick Mayle 176*9712c20fSFrederick Mayle if (HttpQueryInfo(request, HTTP_QUERY_CONTENT_LENGTH, 177*9712c20fSFrederick Mayle static_cast<LPVOID>(&content_length), 178*9712c20fSFrederick Mayle &content_length_size, 0)) { 179*9712c20fSFrederick Mayle has_content_length_header = true; 180*9712c20fSFrederick Mayle claimed_size = wcstol(content_length, NULL, 10); 181*9712c20fSFrederick Mayle response_body.reserve(claimed_size); 182*9712c20fSFrederick Mayle } 183*9712c20fSFrederick Mayle 184*9712c20fSFrederick Mayle DWORD bytes_available; 185*9712c20fSFrederick Mayle DWORD total_read = 0; 186*9712c20fSFrederick Mayle BOOL return_code; 187*9712c20fSFrederick Mayle 188*9712c20fSFrederick Mayle while (((return_code = InternetQueryDataAvailable(request, &bytes_available, 189*9712c20fSFrederick Mayle 0, 0)) != 0) && bytes_available > 0) { 190*9712c20fSFrederick Mayle vector<char> response_buffer(bytes_available); 191*9712c20fSFrederick Mayle DWORD size_read; 192*9712c20fSFrederick Mayle 193*9712c20fSFrederick Mayle return_code = InternetReadFile(request, 194*9712c20fSFrederick Mayle &response_buffer[0], 195*9712c20fSFrederick Mayle bytes_available, &size_read); 196*9712c20fSFrederick Mayle 197*9712c20fSFrederick Mayle if (return_code && size_read > 0) { 198*9712c20fSFrederick Mayle total_read += size_read; 199*9712c20fSFrederick Mayle response_body.append(&response_buffer[0], size_read); 200*9712c20fSFrederick Mayle } 201*9712c20fSFrederick Mayle else { 202*9712c20fSFrederick Mayle break; 203*9712c20fSFrederick Mayle } 204*9712c20fSFrederick Mayle } 205*9712c20fSFrederick Mayle 206*9712c20fSFrederick Mayle bool succeeded = return_code && (!has_content_length_header || 207*9712c20fSFrederick Mayle (total_read == claimed_size)); 208*9712c20fSFrederick Mayle if (succeeded && response) { 209*9712c20fSFrederick Mayle *response = UTF8ToWide(response_body); 210*9712c20fSFrederick Mayle } 211*9712c20fSFrederick Mayle 212*9712c20fSFrederick Mayle return succeeded; 213*9712c20fSFrederick Mayle } 214*9712c20fSFrederick Mayle SendRequestInner(const wstring & url,const wstring & http_method,const wstring & content_type_header,const string & request_body,int * timeout_ms,wstring * response_body,int * response_code)215*9712c20fSFrederick Mayle bool SendRequestInner( 216*9712c20fSFrederick Mayle const wstring& url, 217*9712c20fSFrederick Mayle const wstring& http_method, 218*9712c20fSFrederick Mayle const wstring& content_type_header, 219*9712c20fSFrederick Mayle const string& request_body, 220*9712c20fSFrederick Mayle int* timeout_ms, 221*9712c20fSFrederick Mayle wstring* response_body, 222*9712c20fSFrederick Mayle int* response_code) { 223*9712c20fSFrederick Mayle if (response_code) { 224*9712c20fSFrederick Mayle *response_code = 0; 225*9712c20fSFrederick Mayle } 226*9712c20fSFrederick Mayle 227*9712c20fSFrederick Mayle // Break up the URL and make sure we can handle it 228*9712c20fSFrederick Mayle wchar_t scheme[16], host[256], path[1024]; 229*9712c20fSFrederick Mayle URL_COMPONENTS components; 230*9712c20fSFrederick Mayle memset(&components, 0, sizeof(components)); 231*9712c20fSFrederick Mayle components.dwStructSize = sizeof(components); 232*9712c20fSFrederick Mayle components.lpszScheme = scheme; 233*9712c20fSFrederick Mayle components.dwSchemeLength = sizeof(scheme) / sizeof(scheme[0]); 234*9712c20fSFrederick Mayle components.lpszHostName = host; 235*9712c20fSFrederick Mayle components.dwHostNameLength = sizeof(host) / sizeof(host[0]); 236*9712c20fSFrederick Mayle components.lpszUrlPath = path; 237*9712c20fSFrederick Mayle components.dwUrlPathLength = sizeof(path) / sizeof(path[0]); 238*9712c20fSFrederick Mayle if (!InternetCrackUrl(url.c_str(), static_cast<DWORD>(url.size()), 239*9712c20fSFrederick Mayle 0, &components)) { 240*9712c20fSFrederick Mayle DWORD err = GetLastError(); 241*9712c20fSFrederick Mayle wprintf(L"%d\n", err); 242*9712c20fSFrederick Mayle return false; 243*9712c20fSFrederick Mayle } 244*9712c20fSFrederick Mayle bool secure = false; 245*9712c20fSFrederick Mayle if (wcscmp(scheme, L"https") == 0) { 246*9712c20fSFrederick Mayle secure = true; 247*9712c20fSFrederick Mayle } 248*9712c20fSFrederick Mayle else if (wcscmp(scheme, L"http") != 0) { 249*9712c20fSFrederick Mayle return false; 250*9712c20fSFrederick Mayle } 251*9712c20fSFrederick Mayle 252*9712c20fSFrederick Mayle AutoInternetHandle internet(InternetOpen(kUserAgent, 253*9712c20fSFrederick Mayle INTERNET_OPEN_TYPE_PRECONFIG, 254*9712c20fSFrederick Mayle NULL, // proxy name 255*9712c20fSFrederick Mayle NULL, // proxy bypass 256*9712c20fSFrederick Mayle 0)); // flags 257*9712c20fSFrederick Mayle if (!internet.get()) { 258*9712c20fSFrederick Mayle return false; 259*9712c20fSFrederick Mayle } 260*9712c20fSFrederick Mayle 261*9712c20fSFrederick Mayle AutoInternetHandle connection(InternetConnect(internet.get(), 262*9712c20fSFrederick Mayle host, 263*9712c20fSFrederick Mayle components.nPort, 264*9712c20fSFrederick Mayle NULL, // user name 265*9712c20fSFrederick Mayle NULL, // password 266*9712c20fSFrederick Mayle INTERNET_SERVICE_HTTP, 267*9712c20fSFrederick Mayle 0, // flags 268*9712c20fSFrederick Mayle 0)); // context 269*9712c20fSFrederick Mayle if (!connection.get()) { 270*9712c20fSFrederick Mayle return false; 271*9712c20fSFrederick Mayle } 272*9712c20fSFrederick Mayle 273*9712c20fSFrederick Mayle DWORD http_open_flags = secure ? INTERNET_FLAG_SECURE : 0; 274*9712c20fSFrederick Mayle http_open_flags |= INTERNET_FLAG_NO_COOKIES; 275*9712c20fSFrederick Mayle AutoInternetHandle request(HttpOpenRequest(connection.get(), 276*9712c20fSFrederick Mayle http_method.c_str(), 277*9712c20fSFrederick Mayle path, 278*9712c20fSFrederick Mayle NULL, // version 279*9712c20fSFrederick Mayle NULL, // referer 280*9712c20fSFrederick Mayle NULL, // agent type 281*9712c20fSFrederick Mayle http_open_flags, 282*9712c20fSFrederick Mayle 0)); // context 283*9712c20fSFrederick Mayle if (!request.get()) { 284*9712c20fSFrederick Mayle return false; 285*9712c20fSFrederick Mayle } 286*9712c20fSFrederick Mayle 287*9712c20fSFrederick Mayle if (!content_type_header.empty()) { 288*9712c20fSFrederick Mayle HttpAddRequestHeaders(request.get(), 289*9712c20fSFrederick Mayle content_type_header.c_str(), 290*9712c20fSFrederick Mayle static_cast<DWORD>(-1), 291*9712c20fSFrederick Mayle HTTP_ADDREQ_FLAG_ADD); 292*9712c20fSFrederick Mayle } 293*9712c20fSFrederick Mayle 294*9712c20fSFrederick Mayle if (timeout_ms) { 295*9712c20fSFrederick Mayle if (!InternetSetOption(request.get(), 296*9712c20fSFrederick Mayle INTERNET_OPTION_SEND_TIMEOUT, 297*9712c20fSFrederick Mayle timeout_ms, 298*9712c20fSFrederick Mayle sizeof(*timeout_ms))) { 299*9712c20fSFrederick Mayle fwprintf(stderr, L"Could not unset send timeout, continuing...\n"); 300*9712c20fSFrederick Mayle } 301*9712c20fSFrederick Mayle 302*9712c20fSFrederick Mayle if (!InternetSetOption(request.get(), 303*9712c20fSFrederick Mayle INTERNET_OPTION_RECEIVE_TIMEOUT, 304*9712c20fSFrederick Mayle timeout_ms, 305*9712c20fSFrederick Mayle sizeof(*timeout_ms))) { 306*9712c20fSFrederick Mayle fwprintf(stderr, L"Could not unset receive timeout, continuing...\n"); 307*9712c20fSFrederick Mayle } 308*9712c20fSFrederick Mayle } 309*9712c20fSFrederick Mayle 310*9712c20fSFrederick Mayle if (!HttpSendRequest(request.get(), NULL, 0, 311*9712c20fSFrederick Mayle const_cast<char*>(request_body.data()), 312*9712c20fSFrederick Mayle static_cast<DWORD>(request_body.size()))) { 313*9712c20fSFrederick Mayle return false; 314*9712c20fSFrederick Mayle } 315*9712c20fSFrederick Mayle 316*9712c20fSFrederick Mayle // The server indicates a successful upload with HTTP status 200. 317*9712c20fSFrederick Mayle wchar_t http_status[4]; 318*9712c20fSFrederick Mayle DWORD http_status_size = sizeof(http_status); 319*9712c20fSFrederick Mayle if (!HttpQueryInfo(request.get(), HTTP_QUERY_STATUS_CODE, 320*9712c20fSFrederick Mayle static_cast<LPVOID>(&http_status), &http_status_size, 321*9712c20fSFrederick Mayle 0)) { 322*9712c20fSFrederick Mayle return false; 323*9712c20fSFrederick Mayle } 324*9712c20fSFrederick Mayle 325*9712c20fSFrederick Mayle int http_response = wcstol(http_status, NULL, 10); 326*9712c20fSFrederick Mayle if (response_code) { 327*9712c20fSFrederick Mayle *response_code = http_response; 328*9712c20fSFrederick Mayle } 329*9712c20fSFrederick Mayle 330*9712c20fSFrederick Mayle bool result = (http_response == 200); 331*9712c20fSFrederick Mayle 332*9712c20fSFrederick Mayle if (result) { 333*9712c20fSFrederick Mayle result = ReadResponse(request.get(), response_body); 334*9712c20fSFrederick Mayle } 335*9712c20fSFrederick Mayle 336*9712c20fSFrederick Mayle return result; 337*9712c20fSFrederick Mayle } 338*9712c20fSFrederick Mayle GenerateMultipartBoundary()339*9712c20fSFrederick Mayle wstring GenerateMultipartBoundary() { 340*9712c20fSFrederick Mayle // The boundary has 27 '-' characters followed by 16 hex digits 341*9712c20fSFrederick Mayle static const wchar_t kBoundaryPrefix[] = L"---------------------------"; 342*9712c20fSFrederick Mayle static const int kBoundaryLength = 27 + 16 + 1; 343*9712c20fSFrederick Mayle 344*9712c20fSFrederick Mayle // Generate some random numbers to fill out the boundary 345*9712c20fSFrederick Mayle int r0 = rand(); 346*9712c20fSFrederick Mayle int r1 = rand(); 347*9712c20fSFrederick Mayle 348*9712c20fSFrederick Mayle wchar_t temp[kBoundaryLength]; 349*9712c20fSFrederick Mayle swprintf(temp, kBoundaryLength, L"%s%08X%08X", kBoundaryPrefix, r0, r1); 350*9712c20fSFrederick Mayle 351*9712c20fSFrederick Mayle // remove when VC++7.1 is no longer supported 352*9712c20fSFrederick Mayle temp[kBoundaryLength - 1] = L'\0'; 353*9712c20fSFrederick Mayle 354*9712c20fSFrederick Mayle return wstring(temp); 355*9712c20fSFrederick Mayle } 356*9712c20fSFrederick Mayle GenerateMultipartPostRequestHeader(const wstring & boundary)357*9712c20fSFrederick Mayle wstring GenerateMultipartPostRequestHeader(const wstring& boundary) { 358*9712c20fSFrederick Mayle wstring header = L"Content-Type: multipart/form-data; boundary="; 359*9712c20fSFrederick Mayle header += boundary; 360*9712c20fSFrederick Mayle return header; 361*9712c20fSFrederick Mayle } 362*9712c20fSFrederick Mayle AppendFileToRequestBody(const wstring & file_part_name,const wstring & filename,string * request_body,bool set_content_type=true)363*9712c20fSFrederick Mayle bool AppendFileToRequestBody(const wstring& file_part_name, 364*9712c20fSFrederick Mayle const wstring& filename, 365*9712c20fSFrederick Mayle string* request_body, 366*9712c20fSFrederick Mayle bool set_content_type = true) { 367*9712c20fSFrederick Mayle string file_part_name_utf8 = WideToUTF8(file_part_name); 368*9712c20fSFrederick Mayle if (file_part_name_utf8.empty()) { 369*9712c20fSFrederick Mayle return false; 370*9712c20fSFrederick Mayle } 371*9712c20fSFrederick Mayle 372*9712c20fSFrederick Mayle string filename_utf8 = WideToUTF8(filename); 373*9712c20fSFrederick Mayle if (filename_utf8.empty()) { 374*9712c20fSFrederick Mayle return false; 375*9712c20fSFrederick Mayle } 376*9712c20fSFrederick Mayle 377*9712c20fSFrederick Mayle if (set_content_type) { 378*9712c20fSFrederick Mayle request_body->append( 379*9712c20fSFrederick Mayle "Content-Disposition: form-data; " 380*9712c20fSFrederick Mayle "name=\"" + 381*9712c20fSFrederick Mayle file_part_name_utf8 + 382*9712c20fSFrederick Mayle "\"; " 383*9712c20fSFrederick Mayle "filename=\"" + 384*9712c20fSFrederick Mayle filename_utf8 + "\"\r\n"); 385*9712c20fSFrederick Mayle request_body->append("Content-Type: application/octet-stream\r\n"); 386*9712c20fSFrederick Mayle request_body->append("\r\n"); 387*9712c20fSFrederick Mayle } 388*9712c20fSFrederick Mayle 389*9712c20fSFrederick Mayle vector<char> contents; 390*9712c20fSFrederick Mayle if (!GetFileContents(filename, &contents)) { 391*9712c20fSFrederick Mayle return false; 392*9712c20fSFrederick Mayle } 393*9712c20fSFrederick Mayle 394*9712c20fSFrederick Mayle if (!contents.empty()) { 395*9712c20fSFrederick Mayle request_body->append(&(contents[0]), contents.size()); 396*9712c20fSFrederick Mayle } 397*9712c20fSFrederick Mayle 398*9712c20fSFrederick Mayle return true; 399*9712c20fSFrederick Mayle } 400*9712c20fSFrederick Mayle GenerateRequestBody(const map<wstring,wstring> & parameters,const map<wstring,wstring> & files,const wstring & boundary,string * request_body)401*9712c20fSFrederick Mayle bool GenerateRequestBody(const map<wstring, wstring>& parameters, 402*9712c20fSFrederick Mayle const map<wstring, wstring>& files, 403*9712c20fSFrederick Mayle const wstring& boundary, 404*9712c20fSFrederick Mayle string *request_body) { 405*9712c20fSFrederick Mayle string boundary_str = WideToUTF8(boundary); 406*9712c20fSFrederick Mayle if (boundary_str.empty()) { 407*9712c20fSFrederick Mayle return false; 408*9712c20fSFrederick Mayle } 409*9712c20fSFrederick Mayle 410*9712c20fSFrederick Mayle request_body->clear(); 411*9712c20fSFrederick Mayle 412*9712c20fSFrederick Mayle // Append each of the parameter pairs as a form-data part 413*9712c20fSFrederick Mayle for (map<wstring, wstring>::const_iterator pos = parameters.begin(); 414*9712c20fSFrederick Mayle pos != parameters.end(); ++pos) { 415*9712c20fSFrederick Mayle request_body->append("--" + boundary_str + "\r\n"); 416*9712c20fSFrederick Mayle request_body->append("Content-Disposition: form-data; name=\"" + 417*9712c20fSFrederick Mayle WideToUTF8(pos->first) + "\"\r\n\r\n" + 418*9712c20fSFrederick Mayle WideToUTF8(pos->second) + "\r\n"); 419*9712c20fSFrederick Mayle } 420*9712c20fSFrederick Mayle 421*9712c20fSFrederick Mayle // Now append each upload file as a binary (octet-stream) part 422*9712c20fSFrederick Mayle for (map<wstring, wstring>::const_iterator pos = files.begin(); 423*9712c20fSFrederick Mayle pos != files.end(); ++pos) { 424*9712c20fSFrederick Mayle request_body->append("--" + boundary_str + "\r\n"); 425*9712c20fSFrederick Mayle 426*9712c20fSFrederick Mayle if (!AppendFileToRequestBody(pos->first, pos->second, request_body)) { 427*9712c20fSFrederick Mayle return false; 428*9712c20fSFrederick Mayle } 429*9712c20fSFrederick Mayle } 430*9712c20fSFrederick Mayle request_body->append("--" + boundary_str + "--\r\n"); 431*9712c20fSFrederick Mayle return true; 432*9712c20fSFrederick Mayle } 433*9712c20fSFrederick Mayle } 434*9712c20fSFrederick Mayle 435*9712c20fSFrederick Mayle namespace google_breakpad { SendPutRequest(const wstring & url,const wstring & path,int * timeout_ms,wstring * response_body,int * response_code)436*9712c20fSFrederick Mayle bool HTTPUpload::SendPutRequest( 437*9712c20fSFrederick Mayle const wstring& url, 438*9712c20fSFrederick Mayle const wstring& path, 439*9712c20fSFrederick Mayle int* timeout_ms, 440*9712c20fSFrederick Mayle wstring* response_body, 441*9712c20fSFrederick Mayle int* response_code) { 442*9712c20fSFrederick Mayle string request_body; 443*9712c20fSFrederick Mayle // Turn off content-type in the body. If content-type is set then binary 444*9712c20fSFrederick Mayle // files uploaded to GCS end up with the it prepended to the file 445*9712c20fSFrederick Mayle // contents. 446*9712c20fSFrederick Mayle if (!AppendFileToRequestBody(L"symbol_file", path, &request_body, 447*9712c20fSFrederick Mayle /*set_content_type=*/false)) { 448*9712c20fSFrederick Mayle return false; 449*9712c20fSFrederick Mayle } 450*9712c20fSFrederick Mayle 451*9712c20fSFrederick Mayle return SendRequestInner( 452*9712c20fSFrederick Mayle url, 453*9712c20fSFrederick Mayle L"PUT", 454*9712c20fSFrederick Mayle L"", 455*9712c20fSFrederick Mayle request_body, 456*9712c20fSFrederick Mayle timeout_ms, 457*9712c20fSFrederick Mayle response_body, 458*9712c20fSFrederick Mayle response_code); 459*9712c20fSFrederick Mayle } 460*9712c20fSFrederick Mayle SendGetRequest(const wstring & url,int * timeout_ms,wstring * response_body,int * response_code)461*9712c20fSFrederick Mayle bool HTTPUpload::SendGetRequest( 462*9712c20fSFrederick Mayle const wstring& url, 463*9712c20fSFrederick Mayle int* timeout_ms, 464*9712c20fSFrederick Mayle wstring* response_body, 465*9712c20fSFrederick Mayle int* response_code) { 466*9712c20fSFrederick Mayle return SendRequestInner( 467*9712c20fSFrederick Mayle url, 468*9712c20fSFrederick Mayle L"GET", 469*9712c20fSFrederick Mayle L"", 470*9712c20fSFrederick Mayle "", 471*9712c20fSFrederick Mayle timeout_ms, 472*9712c20fSFrederick Mayle response_body, 473*9712c20fSFrederick Mayle response_code); 474*9712c20fSFrederick Mayle } 475*9712c20fSFrederick Mayle SendMultipartPostRequest(const wstring & url,const map<wstring,wstring> & parameters,const map<wstring,wstring> & files,int * timeout_ms,wstring * response_body,int * response_code)476*9712c20fSFrederick Mayle bool HTTPUpload::SendMultipartPostRequest( 477*9712c20fSFrederick Mayle const wstring& url, 478*9712c20fSFrederick Mayle const map<wstring, wstring>& parameters, 479*9712c20fSFrederick Mayle const map<wstring, wstring>& files, 480*9712c20fSFrederick Mayle int* timeout_ms, 481*9712c20fSFrederick Mayle wstring* response_body, 482*9712c20fSFrederick Mayle int* response_code) { 483*9712c20fSFrederick Mayle // TODO(bryner): support non-ASCII parameter names 484*9712c20fSFrederick Mayle if (!CheckParameters(parameters)) { 485*9712c20fSFrederick Mayle return false; 486*9712c20fSFrederick Mayle } 487*9712c20fSFrederick Mayle 488*9712c20fSFrederick Mayle wstring boundary = GenerateMultipartBoundary(); 489*9712c20fSFrederick Mayle wstring content_type_header = GenerateMultipartPostRequestHeader(boundary); 490*9712c20fSFrederick Mayle 491*9712c20fSFrederick Mayle string request_body; 492*9712c20fSFrederick Mayle if (!GenerateRequestBody(parameters, files, boundary, &request_body)) { 493*9712c20fSFrederick Mayle return false; 494*9712c20fSFrederick Mayle } 495*9712c20fSFrederick Mayle 496*9712c20fSFrederick Mayle return SendRequestInner( 497*9712c20fSFrederick Mayle url, 498*9712c20fSFrederick Mayle L"POST", 499*9712c20fSFrederick Mayle content_type_header, 500*9712c20fSFrederick Mayle request_body, 501*9712c20fSFrederick Mayle timeout_ms, 502*9712c20fSFrederick Mayle response_body, 503*9712c20fSFrederick Mayle response_code); 504*9712c20fSFrederick Mayle } 505*9712c20fSFrederick Mayle SendSimplePostRequest(const wstring & url,const wstring & body,const wstring & content_type,int * timeout_ms,wstring * response_body,int * response_code)506*9712c20fSFrederick Mayle bool HTTPUpload::SendSimplePostRequest( 507*9712c20fSFrederick Mayle const wstring& url, 508*9712c20fSFrederick Mayle const wstring& body, 509*9712c20fSFrederick Mayle const wstring& content_type, 510*9712c20fSFrederick Mayle int *timeout_ms, 511*9712c20fSFrederick Mayle wstring *response_body, 512*9712c20fSFrederick Mayle int *response_code) { 513*9712c20fSFrederick Mayle return SendRequestInner( 514*9712c20fSFrederick Mayle url, 515*9712c20fSFrederick Mayle L"POST", 516*9712c20fSFrederick Mayle content_type, 517*9712c20fSFrederick Mayle WideToUTF8(body), 518*9712c20fSFrederick Mayle timeout_ms, 519*9712c20fSFrederick Mayle response_body, 520*9712c20fSFrederick Mayle response_code); 521*9712c20fSFrederick Mayle } 522*9712c20fSFrederick Mayle } // namespace google_breakpad 523