xref: /aosp_15_r20/external/google-breakpad/src/common/linux/symbol_collector_client.cc (revision 9712c20fc9bbfbac4935993a2ca0b3958c5adad2)
1 // Copyright 2019 Google LLC
2 //
3 // Redistribution and use in source and binary forms, with or without
4 // modification, are permitted provided that the following conditions are
5 // met:
6 //
7 //     * Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 //     * Redistributions in binary form must reproduce the above
10 // copyright notice, this list of conditions and the following disclaimer
11 // in the documentation and/or other materials provided with the
12 // distribution.
13 //     * Neither the name of Google LLC nor the names of its
14 // contributors may be used to endorse or promote products derived from
15 // this software without specific prior written permission.
16 //
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 
29 #ifdef HAVE_CONFIG_H
30 #include <config.h>  // Must come first
31 #endif
32 
33 #include "common/linux/symbol_collector_client.h"
34 
35 #include <stdio.h>
36 
37 #include <iostream>
38 #include <regex>
39 
40 #include "common/linux/libcurl_wrapper.h"
41 
42 namespace google_breakpad {
43 namespace sym_upload {
44 
45 // static
CreateUploadUrl(LibcurlWrapper * libcurl_wrapper,const string & api_url,const string & api_key,UploadUrlResponse * uploadUrlResponse)46 bool SymbolCollectorClient::CreateUploadUrl(
47     LibcurlWrapper* libcurl_wrapper,
48     const string& api_url,
49     const string& api_key,
50     UploadUrlResponse* uploadUrlResponse) {
51   string header, response;
52   long response_code;
53 
54   string url = api_url + "/v1/uploads:create";
55   if (!api_key.empty()) {
56     url += "?key=" + api_key;
57   }
58 
59   if (!libcurl_wrapper->SendSimplePostRequest(url,
60                                               /*body=*/"",
61                                               /*content_type=*/"",
62                                               &response_code,
63                                               &header,
64                                               &response)) {
65     printf("Failed to create upload url.\n");
66     printf("Response code: %ld\n", response_code);
67     printf("Response:\n");
68     printf("%s\n", response.c_str());
69     return false;
70   }
71 
72   // Note camel-case rather than underscores.
73   std::regex upload_url_regex("\"uploadUrl\": \"([^\"]+)\"");
74   std::regex upload_key_regex("\"uploadKey\": \"([^\"]+)\"");
75 
76   std::smatch upload_url_match;
77   if (!std::regex_search(response, upload_url_match, upload_url_regex) ||
78       upload_url_match.size() != 2) {
79     printf("Failed to parse create url response.");
80     printf("Response:\n");
81     printf("%s\n", response.c_str());
82     return false;
83   }
84   string upload_url = upload_url_match[1].str();
85 
86   std::smatch upload_key_match;
87   if (!std::regex_search(response, upload_key_match, upload_key_regex) ||
88       upload_key_match.size() != 2) {
89     printf("Failed to parse create url response.");
90     printf("Response:\n");
91     printf("%s\n", response.c_str());
92     return false;
93   }
94   string upload_key = upload_key_match[1].str();
95 
96   uploadUrlResponse->upload_url = upload_url;
97   uploadUrlResponse->upload_key = upload_key;
98   return true;
99 }
100 
101 // static
CompleteUpload(LibcurlWrapper * libcurl_wrapper,const string & api_url,const string & api_key,const string & upload_key,const string & debug_file,const string & debug_id,const string & type)102 CompleteUploadResult SymbolCollectorClient::CompleteUpload(
103     LibcurlWrapper* libcurl_wrapper,
104     const string& api_url,
105     const string& api_key,
106     const string& upload_key,
107     const string& debug_file,
108     const string& debug_id,
109     const string& type) {
110   string header, response;
111   long response_code;
112 
113   string url = api_url + "/v1/uploads/" + upload_key + ":complete";
114   if (!api_key.empty()) {
115     url += "?key=" + api_key;
116   }
117   string body =
118       "{ symbol_id: {"
119       "debug_file: \"" + debug_file + "\", "
120       "debug_id: \"" + debug_id + "\" }, "
121       "symbol_upload_type: \"" + type + "\" }";
122 
123   if (!libcurl_wrapper->SendSimplePostRequest(url,
124                                               body,
125                                               "application/son",
126                                               &response_code,
127                                               &header,
128                                               &response)) {
129     printf("Failed to complete upload.\n");
130     printf("Response code: %ld\n", response_code);
131     printf("Response:\n");
132     printf("%s\n", response.c_str());
133     return CompleteUploadResult::Error;
134   }
135 
136   std::regex result_regex("\"result\": \"([^\"]+)\"");
137   std::smatch result_match;
138   if (!std::regex_search(response, result_match, result_regex) ||
139       result_match.size() != 2) {
140     printf("Failed to parse complete upload response.");
141     printf("Response:\n");
142     printf("%s\n", response.c_str());
143     return CompleteUploadResult::Error;
144   }
145   string result = result_match[1].str();
146 
147   if (result.compare("DUPLICATE_DATA") == 0) {
148     return CompleteUploadResult::DuplicateData;
149   }
150 
151   return CompleteUploadResult::Ok;
152 }
153 
154 // static
CheckSymbolStatus(LibcurlWrapper * libcurl_wrapper,const string & api_url,const string & api_key,const string & debug_file,const string & debug_id)155 SymbolStatus SymbolCollectorClient::CheckSymbolStatus(
156     LibcurlWrapper* libcurl_wrapper,
157     const string& api_url,
158     const string& api_key,
159     const string& debug_file,
160     const string& debug_id) {
161   string header, response;
162   long response_code;
163   string url = api_url +
164                "/v1/symbols/" + debug_file + "/" + debug_id + ":checkStatus";
165   if (!api_key.empty()) {
166     url += "?key=" + api_key;
167   }
168 
169   if (!libcurl_wrapper->SendGetRequest(
170       url,
171       &response_code,
172       &header,
173       &response)) {
174     printf("Failed to check symbol status, error message.\n");
175     printf("Response code: %ld\n", response_code);
176     printf("Response:\n");
177     printf("%s\n", response.c_str());
178     return SymbolStatus::Unknown;
179   }
180 
181   std::regex status_regex("\"status\": \"([^\"]+)\"");
182   std::smatch status_match;
183   if (!std::regex_search(response, status_match, status_regex) ||
184       status_match.size() != 2) {
185     printf("Failed to parse check symbol status response.");
186     printf("Response:\n");
187     printf("%s\n", response.c_str());
188     return SymbolStatus::Unknown;
189   }
190   string status = status_match[1].str();
191 
192   return (status.compare("FOUND") == 0) ?
193       SymbolStatus::Found :
194       SymbolStatus::Missing;
195 }
196 
197 }  // namespace sym_upload
198 }  // namespace google_breakpad
199