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