1 // Copyright (c) 2006, 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 // Disable exception handler warnings.
31 #pragma warning( disable : 4530 )
32 
33 #include <errno.h>
34 
35 #include "client/windows/sender/crash_report_sender.h"
36 #include "common/windows/http_upload.h"
37 
38 #if _MSC_VER < 1400  // MSVC 2005/8
39 // Older MSVC doesn't have fscanf_s, but they are compatible as long as
40 // we don't use the string conversions (%s/%c/%S/%C).
41 #define fscanf_s fscanf
42 #endif
43 
44 namespace google_breakpad {
45 
46 static const char kCheckpointSignature[] = "GBP1\n";
47 
CrashReportSender(const wstring & checkpoint_file)48 CrashReportSender::CrashReportSender(const wstring &checkpoint_file)
49     : checkpoint_file_(checkpoint_file),
50       max_reports_per_day_(-1),
51       last_sent_date_(-1),
52       reports_sent_(0) {
53   FILE *fd;
54   if (OpenCheckpointFile(L"r", &fd) == 0) {
55     ReadCheckpoint(fd);
56     fclose(fd);
57   }
58 }
59 
SendCrashReport(const wstring & url,const map<wstring,wstring> & parameters,const wstring & dump_file_name,wstring * report_code)60 ReportResult CrashReportSender::SendCrashReport(
61     const wstring &url, const map<wstring, wstring> &parameters,
62     const wstring &dump_file_name, wstring *report_code) {
63   int today = GetCurrentDate();
64   if (today == last_sent_date_ &&
65       max_reports_per_day_ != -1 &&
66       reports_sent_ >= max_reports_per_day_) {
67     return RESULT_THROTTLED;
68   }
69 
70   int http_response = 0;
71   bool result = HTTPUpload::SendRequest(
72     url, parameters, dump_file_name, L"upload_file_minidump", NULL, report_code,
73     &http_response);
74 
75   if (result) {
76     ReportSent(today);
77     return RESULT_SUCCEEDED;
78   } else if (http_response == 400) {  // TODO: update if/when the server
79                                       //       switches to a different code
80     return RESULT_REJECTED;
81   } else {
82     return RESULT_FAILED;
83   }
84 }
85 
ReadCheckpoint(FILE * fd)86 void CrashReportSender::ReadCheckpoint(FILE *fd) {
87   char buf[128];
88   if (!fgets(buf, sizeof(buf), fd) ||
89       strcmp(buf, kCheckpointSignature) != 0) {
90     return;
91   }
92 
93   if (fscanf_s(fd, "%d\n", &last_sent_date_) != 1) {
94     last_sent_date_ = -1;
95     return;
96   }
97   if (fscanf_s(fd, "%d\n", &reports_sent_) != 1) {
98     reports_sent_ = 0;
99     return;
100   }
101 }
102 
ReportSent(int today)103 void CrashReportSender::ReportSent(int today) {
104   // Update the report stats
105   if (today != last_sent_date_) {
106     last_sent_date_ = today;
107     reports_sent_ = 0;
108   }
109   ++reports_sent_;
110 
111   // Update the checkpoint file
112   FILE *fd;
113   if (OpenCheckpointFile(L"w", &fd) == 0) {
114     fputs(kCheckpointSignature, fd);
115     fprintf(fd, "%d\n", last_sent_date_);
116     fprintf(fd, "%d\n", reports_sent_);
117     fclose(fd);
118   }
119 }
120 
GetCurrentDate() const121 int CrashReportSender::GetCurrentDate() const {
122   SYSTEMTIME system_time;
123   GetSystemTime(&system_time);
124   return (system_time.wYear * 10000) + (system_time.wMonth * 100) +
125       system_time.wDay;
126 }
127 
OpenCheckpointFile(const wchar_t * mode,FILE ** fd)128 int CrashReportSender::OpenCheckpointFile(const wchar_t *mode, FILE **fd) {
129   if (checkpoint_file_.empty()) {
130     return ENOENT;
131   }
132 #if _MSC_VER >= 1400  // MSVC 2005/8
133   return _wfopen_s(fd, checkpoint_file_.c_str(), mode);
134 #else
135   *fd = _wfopen(checkpoint_file_.c_str(), mode);
136   if (*fd == NULL) {
137     return errno;
138   }
139   return 0;
140 #endif
141 }
142 
143 }  // namespace google_breakpad
144