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