1// Aseprite
2// Copyright (C) 2020 Igara Studio S.A.
3// Copyright (C) 2001-2018 David Capello
4//
5// This program is distributed under the terms of
6// the End-User License Agreement for Aseprite.
7
8#ifdef HAVE_CONFIG_H
9#include "config.h"
10#endif
11
12#include "updater/check_update.h"
13
14#include "base/convert_to.h"
15#include "base/debug.h"
16#include "net/http_headers.h"
17#include "net/http_request.h"
18#include "net/http_response.h"
19#include "tinyxml.h"
20#include "updater/user_agent.h"
21#include "ver/info.h"
22
23#include <iostream>
24#include <memory>
25#include <sstream>
26
27namespace updater {
28
29CheckUpdateResponse::CheckUpdateResponse()
30 : m_type(Unknown)
31 , m_waitDays(0.0)
32{
33}
34
35CheckUpdateResponse::CheckUpdateResponse(const CheckUpdateResponse& other)
36 : m_type(other.m_type)
37 , m_version(other.m_version)
38 , m_url(other.m_url)
39 , m_waitDays(0.0)
40{
41}
42
43CheckUpdateResponse::CheckUpdateResponse(const std::string& responseBody)
44 : m_type(Unknown)
45 , m_waitDays(0.0)
46{
47 TiXmlDocument doc;
48 doc.Parse(responseBody.c_str());
49
50 TiXmlHandle handle(&doc);
51 TiXmlElement* xmlUpdate = handle.FirstChild("update").ToElement();
52 if (!xmlUpdate) {
53 // TODO show error?
54 return;
55 }
56
57 const char* latest_attr = xmlUpdate->Attribute("latest");
58 const char* version_attr = xmlUpdate->Attribute("version");
59 const char* type_attr = xmlUpdate->Attribute("type");
60 const char* url_attr = xmlUpdate->Attribute("url");
61 const char* uuid_attr = xmlUpdate->Attribute("uuid");
62 const char* waitdays_attr = xmlUpdate->Attribute("waitdays");
63
64 if (latest_attr && strcmp(latest_attr, "1") == 0)
65 m_type = NoUpdate;
66
67 if (type_attr) {
68 if (strcmp(type_attr, "critical") == 0)
69 m_type = Critical;
70 else if (strcmp(type_attr, "major") == 0)
71 m_type = Major;
72 }
73
74 if (version_attr)
75 m_version = version_attr;
76
77 if (url_attr)
78 m_url = url_attr;
79
80 if (uuid_attr)
81 m_uuid = uuid_attr;
82
83 if (waitdays_attr)
84 m_waitDays = base::convert_to<double>(std::string(waitdays_attr));
85}
86
87class CheckUpdate::CheckUpdateImpl
88{
89public:
90 CheckUpdateImpl() { }
91 ~CheckUpdateImpl() { }
92
93 void abort()
94 {
95 if (m_request)
96 m_request->abort();
97 }
98
99 bool checkNewVersion(const Uuid& uuid, const std::string& extraParams, CheckUpdateDelegate* delegate)
100 {
101 std::string url = get_app_update_url();
102 if (!uuid.empty()) {
103 url += "&uuid=";
104 url += uuid;
105 }
106 if (!extraParams.empty()) {
107 url += "&";
108 url += extraParams;
109 }
110
111 m_request.reset(new net::HttpRequest(url));
112 net::HttpHeaders headers;
113 headers.setHeader("User-Agent", getUserAgent());
114 m_request->setHeaders(headers);
115
116 std::stringstream body;
117 net::HttpResponse response(&body);
118 if (m_request->send(response)) {
119 TRACE("Checking updates: %s (User-Agent: %s)\n", url.c_str(), getUserAgent().c_str());
120 TRACE("Response:\n--\n%s--\n", body.str().c_str());
121
122 CheckUpdateResponse data(body.str());
123 delegate->onResponse(data);
124 return true;
125 }
126 else
127 return false;
128 }
129
130private:
131 std::unique_ptr<net::HttpRequest> m_request;
132};
133
134CheckUpdate::CheckUpdate()
135 : m_impl(new CheckUpdateImpl)
136{
137}
138
139CheckUpdate::~CheckUpdate()
140{
141 delete m_impl;
142}
143
144void CheckUpdate::abort()
145{
146 m_impl->abort();
147}
148
149bool CheckUpdate::checkNewVersion(const Uuid& uuid, const std::string& extraParams, CheckUpdateDelegate* delegate)
150{
151 return m_impl->checkNewVersion(uuid, extraParams, delegate);
152}
153
154} // namespace updater
155