/ src / common / windows / symbol_collector_client.cc
symbol_collector_client.cc
  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
 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
 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
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