devserver: return correct IsDelta value in Omaha response

The devserver now uses the newly introduced update_payload module to
actually parse payload files and determine whether they are delta/full
with certainty. This fix includes both locally and remotely served
files. Also fixes a potential problem with remote file attribute
fetching.

BUG=chromium-os:37688
TEST=(1) update response contains correct IsDelta value; (2)
api/fileinfo correctly returns is_delta value.
CQ-DEPEND=I8f426f55d2ee7fb0fa265ae4d5ad84f3c68ca702

Change-Id: I7258d81a66a5c763cc62f6800965fe1a57a0008e
Reviewed-on: https://gerrit.chromium.org/gerrit/43537
Reviewed-by: Gilad Arnold <garnold@chromium.org>
Tested-by: Gilad Arnold <garnold@chromium.org>
Commit-Queue: Gilad Arnold <garnold@chromium.org>
diff --git a/autoupdate.py b/autoupdate.py
index 1f71ef4..31003e8 100644
--- a/autoupdate.py
+++ b/autoupdate.py
@@ -5,16 +5,24 @@
 import json
 import os
 import subprocess
+import sys
 import time
 import urllib2
 import urlparse
 
 import cherrypy
 
+# Allow importing from dev/host/lib when running from source tree.
+lib_dir = os.path.join(os.path.dirname(__file__), 'host', 'lib')
+if os.path.exists(lib_dir) and os.path.isdir(lib_dir):
+  sys.path.insert(1, lib_dir)
+
 from build_util import BuildObject
 import autoupdate_lib
 import common_util
 import log_util
+# pylint: disable=F0401
+import update_payload
 
 
 # Module-local log function.
@@ -277,16 +285,15 @@
     return image_name
 
   @staticmethod
-  def _IsDeltaFormatFile(filename):
+  def IsDeltaFormatFile(filename):
     try:
-      file_handle = open(filename, 'r')
-      delta_magic = 'CrAU'
-      magic = file_handle.read(len(delta_magic))
-      return magic == delta_magic
-    except IOError:
-      # For unit tests, we may not have real files, so it's ok to
-      # ignore these IOErrors. In any case, this value is not being
-      # used in update_engine at all as of now.
+      with open(filename) as payload_file:
+        payload = update_payload.Payload(payload_file)
+        payload.Init()
+        return payload.IsDelta()
+    except (IOError, update_payload.PayloadError):
+      # For unit tests we may not have real files, so it's ok to ignore these
+      # errors.
       return False
 
   def GenerateUpdateFile(self, src_image, image_path, output_dir):
@@ -432,12 +439,10 @@
     # Generation complete, copy if requested.
     if self.copy_to_static_root:
       # The final results exist directly in static
-      update_payload = os.path.join(static_image_dir,
-                                    UPDATE_FILE)
-      stateful_payload = os.path.join(static_image_dir,
-                                      STATEFUL_FILE)
+      cros_update_payload = os.path.join(static_image_dir, UPDATE_FILE)
+      stateful_payload = os.path.join(static_image_dir, STATEFUL_FILE)
       metadata_file = os.path.join(static_image_dir, METADATA_FILE)
-      common_util.CopyFile(cache_update_payload, update_payload)
+      common_util.CopyFile(cache_update_payload, cros_update_payload)
       common_util.CopyFile(cache_stateful_payload, stateful_payload)
       common_util.CopyFile(cache_metadata_file, metadata_file)
       return None
@@ -565,9 +570,6 @@
       if not metadata_obj:
         raise AutoupdateError('Failed to obtain remote payload info')
 
-      if not metadata_obj.is_delta_format:
-        metadata_obj.is_delta_format = ('_mton' in url) or ('_nton' in url)
-
       return metadata_obj
     except IOError as e:
       raise AutoupdateError('Failed to obtain remote payload info: %s', e)
@@ -593,7 +595,7 @@
       sha1 = common_util.GetFileSha1(filename)
       sha256 = common_util.GetFileSha256(filename)
       size = common_util.GetFileSize(filename)
-      is_delta_format = self._IsDeltaFormatFile(filename)
+      is_delta_format = self.IsDeltaFormatFile(filename)
       metadata_obj = UpdateMetadata(sha1, sha256, size, is_delta_format)
       Autoupdate._StoreMetadataToFile(payload_dir, metadata_obj)
 
diff --git a/devserver.py b/devserver.py
index 6621e53..8378b76 100755
--- a/devserver.py
+++ b/devserver.py
@@ -300,9 +300,16 @@
       file_sha256 = common_util.GetFileSha256(file_path)
     except os.error, e:
       raise DevServerError('failed to get info for file %s: %s' %
-                           (file_path, str(e)))
-    return json.dumps(
-        {'size': file_size, 'sha1': file_sha1, 'sha256': file_sha256})
+                           (file_path, e))
+
+    is_delta = autoupdate.Autoupdate.IsDeltaFormatFile(file_path)
+
+    return json.dumps({
+        autoupdate.Autoupdate.SIZE_ATTR: file_size,
+        autoupdate.Autoupdate.SHA1_ATTR: file_sha1,
+        autoupdate.Autoupdate.SHA256_ATTR: file_sha256,
+        autoupdate.Autoupdate.ISDELTA_ATTR: is_delta
+    })
 
 
 class DevServerRoot(object):
diff --git a/host/__init__.py b/host/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/host/__init__.py