blob: cad0be4fa24a5b1904ecadd2342d6d40cc0a24a3 [file] [log] [blame]
rtc@google.comded22402009-10-26 22:36:21 +00001# Copyright (c) 2009 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5from xml.dom import minidom
6
7import os
8import web
9
10# TODO(rtc): This is redundant with devserver.py. Move this code to a
11# common location.
12app_id = "87efface-864d-49a5-9bb3-4b050a7c227a"
13root_dir = "/usr/local/google/home/rtc/chromeos/trunk/src"
14scripts_dir = "%s/scripts" % root_dir
15app_dir = os.popen("pwd").read().strip()
16static_dir = "%s/static" % app_dir
17
18# Basic functionality of handling ChromeOS autoupdate pings
19# and building/serving update images.
20# TODO(rtc): Clean this code up and write some tests.
21
22def GetUpdatePayload(hash, size, url, id):
23 payload = """<?xml version="1.0" encoding="UTF-8"?>
24 <gupdate xmlns="http://www.google.com/update2/response" protocol="2.0">
25 <app appid="{%s}" status="ok">
26 <ping status="ok"/>
27 <updatecheck
28 codebase="%s"
29 hash="%s"
30 needsadmin="false"
31 size="%s"
32 status="ok"/>
33 </app>
34 </gupdate>
35 """
36 return payload % (id, url, hash, size)
37
38def GetNoUpdatePayload(id):
39 payload = """<?xml version="1.0" encoding="UTF-8"?>
40 <gupdate xmlns="http://www.google.com/update2/response" protocol="2.0">
41 <app appid="{%s}" status="ok">
42 <ping status="ok"/>
43 <updatecheck status="noupdate"/>
44 </app>
45 </gupdate>
46 """
47 return payload % id
48
49def GetLatestImagePath():
50 cmd = "%s/get_latest_image.sh" % scripts_dir
51 return os.popen(cmd).read().strip()
52
53def GetLatestVersion(latest_image_path):
54 latest_version = latest_image_path.split('/')[-1]
55 return latest_version.split('-')[0]
56
57def CanUpdate(client_version, latest_version):
58 """
59 Returns true iff the latest_version is greater than the client_version.
60 """
61 client_tokens = client_version.split('.')
62 latest_tokens = latest_version.split('.')
63 web.debug("client version %s latest version %s" % (client_version, latest_version))
64 for i in range(0,4):
65 if int(latest_tokens[i]) == int(client_tokens[i]):
66 continue
67 return int(latest_tokens[i]) > int(client_tokens[i])
68 return False
69
70def BuildUpdateImage(image_path):
71 image_file = "%s/rootfs.image" % image_path
72 web.debug("checking image file %s/update.gz" % image_path)
73 if not os.path.exists("%s/update.gz" % image_path):
74 mkupdate = "%s/mk_memento_images.sh %s" % (scripts_dir, image_file)
75 web.debug(mkupdate)
76 err = os.system(mkupdate)
77 if err != 0:
78 web.debug("failed to create update image")
79 return False
80
81 web.debug("Found an image, copying it to static")
82 err = os.system("cp %s/update.gz %s" % (image_path, static_dir))
83 if err != 0:
84 web.debug("Unable to move update.gz from %s to %s" % (image_path, static_dir))
85 return False
86 return True
87
88def GetSize(update_path):
89 return os.path.getsize(update_path)
90
91def GetHash(update_path):
92 cmd = "cat %s | openssl sha1 -binary | openssl base64 | tr \'\\n\' \' \';" % update_path
93 web.debug(cmd)
94 return os.popen(cmd).read()
95
96def HandleUpdatePing(data):
97 update_dom = minidom.parseString(data)
98 root = update_dom.firstChild
99 query = root.getElementsByTagName("o:app")[0]
100 client_version = query.attributes['version'].value
101 latest_image_path = GetLatestImagePath();
102 latest_version = GetLatestVersion(latest_image_path);
103 if not CanUpdate(client_version, latest_version):
104 web.debug("no update")
105 return GetNoUpdatePayload(app_id)
106
107 web.debug("update found %s " % latest_version)
108 ok = BuildUpdateImage(latest_image_path)
109 if ok != True:
110 web.debug("Failed to build an update image")
111 return GetNoUpdatePayload(app_id)
112
113 hash = GetHash("%s/update.gz" % static_dir)
114 size = GetSize("%s/update.gz" % static_dir)
115 hostname = web.ctx.host
116 url = "http://%s/static/update.gz" % hostname
117 return GetUpdatePayload(hash, size, url, app_id)
118