1 #ifdef HAVE_CONFIG_H 2 #include <config.h> // Must come first 3 #endif 4 5 #include "common/windows/symbol_collector_client.h" 6 7 #include <stdio.h> 8 9 #include <regex> 10 11 #include "common/windows/http_upload.h" 12 13 namespace google_breakpad { 14 15 // static CreateUploadUrl(wstring & api_url,wstring & api_key,int * timeout_ms,UploadUrlResponse * uploadUrlResponse)16 bool SymbolCollectorClient::CreateUploadUrl( 17 wstring& api_url, 18 wstring& api_key, 19 int* timeout_ms, 20 UploadUrlResponse *uploadUrlResponse) { 21 wstring url = api_url + 22 L"/v1/uploads:create" 23 L"?key=" + api_key; 24 wstring response; 25 int response_code; 26 27 if (!HTTPUpload::SendSimplePostRequest( 28 url, 29 L"", 30 L"", 31 timeout_ms, 32 &response, 33 &response_code)) { 34 wprintf(L"Failed to create upload url.\n"); 35 wprintf(L"Response code: %ld\n", response_code); 36 wprintf(L"Response:\n"); 37 wprintf(L"%s\n", response.c_str()); 38 return false; 39 } 40 41 // Note camel-case rather than underscores. 42 std::wregex upload_url_regex(L"\"uploadUrl\": \"([^\"]+)\""); 43 std::wregex upload_key_regex(L"\"uploadKey\": \"([^\"]+)\""); 44 45 std::wsmatch upload_url_match; 46 if (!std::regex_search(response, upload_url_match, upload_url_regex) || 47 upload_url_match.size() != 2) { 48 wprintf(L"Failed to parse create url response."); 49 wprintf(L"Response:\n"); 50 wprintf(L"%s\n", response.c_str()); 51 return false; 52 } 53 wstring upload_url = upload_url_match[1].str(); 54 55 std::wsmatch upload_key_match; 56 if (!std::regex_search(response, upload_key_match, upload_key_regex) || 57 upload_key_match.size() != 2) { 58 wprintf(L"Failed to parse create url response."); 59 wprintf(L"Response:\n"); 60 wprintf(L"%s\n", response.c_str()); 61 return false; 62 } 63 wstring upload_key = upload_key_match[1].str(); 64 65 uploadUrlResponse->upload_url = upload_url; 66 uploadUrlResponse->upload_key = upload_key; 67 return true; 68 } 69 70 // static CompleteUpload(wstring & api_url,wstring & api_key,int * timeout_ms,const wstring & upload_key,const wstring & debug_file,const wstring & debug_id,const wstring & type,const wstring & product_name)71 CompleteUploadResult SymbolCollectorClient::CompleteUpload( 72 wstring& api_url, 73 wstring& api_key, 74 int* timeout_ms, 75 const wstring& upload_key, 76 const wstring& debug_file, 77 const wstring& debug_id, 78 const wstring& type, 79 const wstring& product_name) { 80 wstring url = api_url + 81 L"/v1/uploads/" + upload_key + L":complete" 82 L"?key=" + api_key; 83 wstring body = 84 L"{ symbol_id: {" 85 L"debug_file: \"" + 86 debug_file + 87 L"\", " 88 L"debug_id: \"" + 89 debug_id + 90 L"\" " 91 L"}, "; 92 if (!product_name.empty()) { 93 body += 94 L"metadata: {" 95 L"product_name: \"" + 96 product_name + 97 L"\"" 98 L"},"; 99 } 100 body += L"symbol_upload_type: \"" + type + 101 L"\", " 102 L"use_async_processing: true }"; 103 wstring response; 104 int response_code; 105 106 if (!HTTPUpload::SendSimplePostRequest( 107 url, 108 body, 109 L"application/json", 110 timeout_ms, 111 &response, 112 &response_code)) { 113 wprintf(L"Failed to complete upload.\n"); 114 wprintf(L"Response code: %ld\n", response_code); 115 wprintf(L"Response:\n"); 116 wprintf(L"%s\n", response.c_str()); 117 return CompleteUploadResult::Error; 118 } 119 120 std::wregex result_regex(L"\"result\": \"([^\"]+)\""); 121 std::wsmatch result_match; 122 if (!std::regex_search(response, result_match, result_regex) || 123 result_match.size() != 2) { 124 wprintf(L"Failed to parse complete upload response."); 125 wprintf(L"Response:\n"); 126 wprintf(L"%s\n", response.c_str()); 127 return CompleteUploadResult::Error; 128 } 129 wstring result = result_match[1].str(); 130 131 if (result.compare(L"DUPLICATE_DATA") == 0) { 132 return CompleteUploadResult::DuplicateData; 133 } 134 135 return CompleteUploadResult::Ok; 136 } 137 138 // static CheckSymbolStatus(wstring & api_url,wstring & api_key,int * timeout_ms,const wstring & debug_file,const wstring & debug_id)139 SymbolStatus SymbolCollectorClient::CheckSymbolStatus( 140 wstring& api_url, 141 wstring& api_key, 142 int* timeout_ms, 143 const wstring& debug_file, 144 const wstring& debug_id) { 145 wstring response; 146 int response_code; 147 wstring url = api_url + 148 L"/v1/symbols/" + debug_file + L"/" + debug_id + L":checkStatus" 149 L"?key=" + api_key; 150 151 if (!HTTPUpload::SendGetRequest( 152 url, 153 timeout_ms, 154 &response, 155 &response_code)) { 156 wprintf(L"Failed to check symbol status.\n"); 157 wprintf(L"Response code: %ld\n", response_code); 158 wprintf(L"Response:\n"); 159 wprintf(L"%s\n", response.c_str()); 160 return SymbolStatus::Unknown; 161 } 162 163 std::wregex status_regex(L"\"status\": \"([^\"]+)\""); 164 std::wsmatch status_match; 165 if (!std::regex_search(response, status_match, status_regex) || 166 status_match.size() != 2) { 167 wprintf(L"Failed to parse check symbol status response."); 168 wprintf(L"Response:\n"); 169 wprintf(L"%s\n", response.c_str()); 170 return SymbolStatus::Unknown; 171 } 172 wstring status = status_match[1].str(); 173 174 return (status.compare(L"FOUND") == 0) ? 175 SymbolStatus::Found : 176 SymbolStatus::Missing; 177 } 178 179 } // namespace google_breakpad