1//
2// Copyright (C) 2012 The Android Open Source Project
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8//      http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15//
16
17#ifndef UPDATE_ENGINE_OMAHA_REQUEST_ACTION_H_
18#define UPDATE_ENGINE_OMAHA_REQUEST_ACTION_H_
19
20#include <fcntl.h>
21#include <sys/stat.h>
22#include <sys/types.h>
23
24#include <memory>
25#include <string>
26#include <vector>
27
28#include <gtest/gtest_prod.h>  // for FRIEND_TEST
29
30#include <brillo/secure_blob.h>
31#include <curl/curl.h>
32
33#include "update_engine/common/action.h"
34#include "update_engine/common/http_fetcher.h"
35#include "update_engine/omaha_response.h"
36#include "update_engine/system_state.h"
37
38// The Omaha Request action makes a request to Omaha and can output
39// the response on the output ActionPipe.
40
41namespace chromeos_update_engine {
42
43// Encodes XML entities in a given string. Input must be ASCII-7 valid. If
44// the input is invalid, the default value is used instead.
45std::string XmlEncodeWithDefault(const std::string& input,
46                                 const std::string& default_value);
47
48// Escapes text so it can be included as character data and attribute
49// values. The |input| string must be valid ASCII-7, no UTF-8 supported.
50// Returns whether the |input| was valid and escaped properly in |output|.
51bool XmlEncode(const std::string& input, std::string* output);
52
53// This struct encapsulates the Omaha event information. For a
54// complete list of defined event types and results, see
55// http://code.google.com/p/omaha/wiki/ServerProtocol#event
56struct OmahaEvent {
57  // The Type values correspond to EVENT_TYPE values of Omaha.
58  enum Type {
59    kTypeUnknown = 0,
60    kTypeDownloadComplete = 1,
61    kTypeInstallComplete = 2,
62    kTypeUpdateComplete = 3,
63    kTypeUpdateDownloadStarted = 13,
64    kTypeUpdateDownloadFinished = 14,
65    // Chromium OS reserved type sent after the first reboot following an update
66    // completed.
67    kTypeRebootedAfterUpdate = 54,
68  };
69
70  // The Result values correspond to EVENT_RESULT values of Omaha.
71  enum Result {
72    kResultError = 0,
73    kResultSuccess = 1,
74    kResultUpdateDeferred = 9,  // When we ignore/defer updates due to policy.
75  };
76
77  OmahaEvent()
78      : type(kTypeUnknown),
79        result(kResultError),
80        error_code(ErrorCode::kError) {}
81  explicit OmahaEvent(Type in_type)
82      : type(in_type),
83        result(kResultSuccess),
84        error_code(ErrorCode::kSuccess) {}
85  OmahaEvent(Type in_type, Result in_result, ErrorCode in_error_code)
86      : type(in_type),
87        result(in_result),
88        error_code(in_error_code) {}
89
90  Type type;
91  Result result;
92  ErrorCode error_code;
93};
94
95class NoneType;
96class OmahaRequestAction;
97class OmahaRequestParams;
98class PrefsInterface;
99
100// This struct is declared in the .cc file.
101struct OmahaParserData;
102
103template<>
104class ActionTraits<OmahaRequestAction> {
105 public:
106  // Takes parameters on the input pipe.
107  typedef NoneType InputObjectType;
108  // On UpdateCheck success, puts the Omaha response on output. Event
109  // requests do not have an output pipe.
110  typedef OmahaResponse OutputObjectType;
111};
112
113class OmahaRequestAction : public Action<OmahaRequestAction>,
114                           public HttpFetcherDelegate {
115 public:
116  static const int kNeverPinged = -1;
117  static const int kPingTimeJump = -2;
118  // We choose this value of 10 as a heuristic for a work day in trying
119  // each URL, assuming we check roughly every 45 mins. This is a good time to
120  // wait - neither too long nor too little - so we don't give up the preferred
121  // URLs that appear earlier in list too quickly before moving on to the
122  // fallback ones.
123  static const int kDefaultMaxFailureCountPerUrl = 10;
124
125  // These are the possible outcome upon checking whether we satisfied
126  // the wall-clock-based-wait.
127  enum WallClockWaitResult {
128    kWallClockWaitNotSatisfied,
129    kWallClockWaitDoneButUpdateCheckWaitRequired,
130    kWallClockWaitDoneAndUpdateCheckWaitNotRequired,
131  };
132
133  // The ctor takes in all the parameters that will be used for making
134  // the request to Omaha. For some of them we have constants that
135  // should be used.
136  //
137  // Takes ownership of the passed in HttpFetcher. Useful for testing.
138  //
139  // Takes ownership of the passed in OmahaEvent. If |event| is null,
140  // this is an UpdateCheck request, otherwise it's an Event request.
141  // Event requests always succeed.
142  //
143  // A good calling pattern is:
144  // OmahaRequestAction(..., new OmahaEvent(...), new WhateverHttpFetcher);
145  // or
146  // OmahaRequestAction(..., nullptr, new WhateverHttpFetcher);
147  OmahaRequestAction(SystemState* system_state,
148                     OmahaEvent* event,
149                     std::unique_ptr<HttpFetcher> http_fetcher,
150                     bool ping_only);
151  ~OmahaRequestAction() override;
152  typedef ActionTraits<OmahaRequestAction>::InputObjectType InputObjectType;
153  typedef ActionTraits<OmahaRequestAction>::OutputObjectType OutputObjectType;
154  void PerformAction() override;
155  void TerminateProcessing() override;
156  void ActionCompleted(ErrorCode code) override;
157
158  int GetHTTPResponseCode() { return http_fetcher_->http_response_code(); }
159
160  // Debugging/logging
161  static std::string StaticType() { return "OmahaRequestAction"; }
162  std::string Type() const override { return StaticType(); }
163
164  // Delegate methods (see http_fetcher.h)
165  void ReceivedBytes(HttpFetcher *fetcher,
166                     const void* bytes, size_t length) override;
167
168  void TransferComplete(HttpFetcher *fetcher, bool successful) override;
169
170  // Returns true if this is an Event request, false if it's an UpdateCheck.
171  bool IsEvent() const { return event_.get() != nullptr; }
172
173 private:
174  FRIEND_TEST(OmahaRequestActionTest, GetInstallDateWhenNoPrefsNorOOBE);
175  FRIEND_TEST(OmahaRequestActionTest,
176              GetInstallDateWhenOOBECompletedWithInvalidDate);
177  FRIEND_TEST(OmahaRequestActionTest,
178              GetInstallDateWhenOOBECompletedWithValidDate);
179  FRIEND_TEST(OmahaRequestActionTest,
180              GetInstallDateWhenOOBECompletedDateChanges);
181
182  // Enumeration used in PersistInstallDate().
183  enum InstallDateProvisioningSource {
184    kProvisionedFromOmahaResponse,
185    kProvisionedFromOOBEMarker,
186
187    // kProvisionedMax is the count of the number of enums above. Add
188    // any new enums above this line only.
189    kProvisionedMax
190  };
191
192  // Gets the install date, expressed as the number of PST8PDT
193  // calendar weeks since January 1st 2007, times seven. Returns -1 if
194  // unknown. See http://crbug.com/336838 for details about this value.
195  static int GetInstallDate(SystemState* system_state);
196
197  // Parses the Omaha Response in |doc| and sets the
198  // |install_date_days| field of |output_object| to the value of the
199  // elapsed_days attribute of the daystart element. Returns True if
200  // the value was set, False if it wasn't found.
201  static bool ParseInstallDate(OmahaParserData* parser_data,
202                               OmahaResponse* output_object);
203
204  // Returns True if the kPrefsInstallDateDays state variable is set,
205  // False otherwise.
206  static bool HasInstallDate(SystemState *system_state);
207
208  // Writes |install_date_days| into the kPrefsInstallDateDays state
209  // variable and emits an UMA stat for the |source| used. Returns
210  // True if the value was written, False if an error occurred.
211  static bool PersistInstallDate(SystemState *system_state,
212                                 int install_date_days,
213                                 InstallDateProvisioningSource source);
214
215  // Persist the new cohort* value received in the XML file in the |prefs_key|
216  // preference file. If the |new_value| is empty, the currently stored value
217  // will be deleted. Don't call this function with an empty |new_value| if the
218  // value was not set in the XML, since that would delete the stored value.
219  bool PersistCohortData(const std::string& prefs_key,
220                         const std::string& new_value);
221
222  // If this is an update check request, initializes
223  // |ping_active_days_| and |ping_roll_call_days_| to values that may
224  // be sent as pings to Omaha.
225  void InitPingDays();
226
227  // Based on the persistent preference store values, calculates the
228  // number of days since the last ping sent for |key|.
229  int CalculatePingDays(const std::string& key);
230
231  // Returns whether we have "active_days" or "roll_call_days" ping values to
232  // send to Omaha and thus we should include them in the response.
233  bool ShouldPing() const;
234
235  // Returns true if the download of a new update should be deferred.
236  // False if the update can be downloaded.
237  bool ShouldDeferDownload(OmahaResponse* output_object);
238
239  // Returns true if the basic wall-clock-based waiting period has been
240  // satisfied based on the scattering policy setting. False otherwise.
241  // If true, it also indicates whether the additional update-check-count-based
242  // waiting period also needs to be satisfied before the download can begin.
243  WallClockWaitResult IsWallClockBasedWaitingSatisfied(
244      OmahaResponse* output_object);
245
246  // Returns true if the update-check-count-based waiting period has been
247  // satisfied. False otherwise.
248  bool IsUpdateCheckCountBasedWaitingSatisfied();
249
250  // Parses the response from Omaha that's available in |doc| using the other
251  // helper methods below and populates the |output_object| with the relevant
252  // values. Returns true if we should continue the parsing.  False otherwise,
253  // in which case it sets any error code using |completer|.
254  bool ParseResponse(OmahaParserData* parser_data,
255                     OmahaResponse* output_object,
256                     ScopedActionCompleter* completer);
257
258  // Parses the status property in the given update_check_node and populates
259  // |output_object| if valid. Returns true if we should continue the parsing.
260  // False otherwise, in which case it sets any error code using |completer|.
261  bool ParseStatus(OmahaParserData* parser_data,
262                   OmahaResponse* output_object,
263                   ScopedActionCompleter* completer);
264
265  // Parses the URL nodes in the given XML document and populates
266  // |output_object| if valid. Returns true if we should continue the parsing.
267  // False otherwise, in which case it sets any error code using |completer|.
268  bool ParseUrls(OmahaParserData* parser_data,
269                 OmahaResponse* output_object,
270                 ScopedActionCompleter* completer);
271
272  // Parses the package node in the given XML document and populates
273  // |output_object| if valid. Returns true if we should continue the parsing.
274  // False otherwise, in which case it sets any error code using |completer|.
275  bool ParsePackage(OmahaParserData* parser_data,
276                    OmahaResponse* output_object,
277                    ScopedActionCompleter* completer);
278
279  // Parses the other parameters in the given XML document and populates
280  // |output_object| if valid. Returns true if we should continue the parsing.
281  // False otherwise, in which case it sets any error code using |completer|.
282  bool ParseParams(OmahaParserData* parser_data,
283                   OmahaResponse* output_object,
284                   ScopedActionCompleter* completer);
285
286  // Called by TransferComplete() to complete processing, either
287  // asynchronously after looking up resources via p2p or directly.
288  void CompleteProcessing();
289
290  // Helper to asynchronously look up payload on the LAN.
291  void LookupPayloadViaP2P(const OmahaResponse& response);
292
293  // Callback used by LookupPayloadViaP2P().
294  void OnLookupPayloadViaP2PCompleted(const std::string& url);
295
296  // Returns true if the current update should be ignored.
297  bool ShouldIgnoreUpdate(const OmahaResponse& response) const;
298
299  // Returns true if updates are allowed over the current type of connection.
300  // False otherwise.
301  bool IsUpdateAllowedOverCurrentConnection() const;
302
303  // Global system context.
304  SystemState* system_state_;
305
306  // Contains state that is relevant in the processing of the Omaha request.
307  OmahaRequestParams* params_;
308
309  // Pointer to the OmahaEvent info. This is an UpdateCheck request if null.
310  std::unique_ptr<OmahaEvent> event_;
311
312  // pointer to the HttpFetcher that does the http work
313  std::unique_ptr<HttpFetcher> http_fetcher_;
314
315  // If true, only include the <ping> element in the request.
316  bool ping_only_;
317
318  // Stores the response from the omaha server
319  brillo::Blob response_buffer_;
320
321  // Initialized by InitPingDays to values that may be sent to Omaha
322  // as part of a ping message. Note that only positive values and -1
323  // are sent to Omaha.
324  int ping_active_days_;
325  int ping_roll_call_days_;
326
327  DISALLOW_COPY_AND_ASSIGN(OmahaRequestAction);
328};
329
330}  // namespace chromeos_update_engine
331
332#endif  // UPDATE_ENGINE_OMAHA_REQUEST_ACTION_H_
333