Merge from Chromium at DEPS revision r202854

This commit was generated by merge_to_master.py.

Change-Id: Idca323f71ef844a9e04f454d4f070b1e398f2deb
diff --git a/ppapi/api/extensions/dev/ppb_ext_socket_dev.idl b/ppapi/api/extensions/dev/ppb_ext_socket_dev.idl
index 10051d7..9b0fc7b 100644
--- a/ppapi/api/extensions/dev/ppb_ext_socket_dev.idl
+++ b/ppapi/api/extensions/dev/ppb_ext_socket_dev.idl
@@ -9,7 +9,8 @@
  */
 
 label Chrome {
-  M28 = 0.1
+  M28 = 0.1,
+  M29 = 0.2
 };
 
 /**
@@ -414,4 +415,128 @@
       [in] PP_Instance instance,
       [out] PP_Ext_Socket_NetworkInterface_Dev_Array result,
       [in] PP_CompletionCallback callback);
+
+  /**
+   * Joins the multicast group and starts to receive packets from that group.
+   * The socket must be of UDP type and must be bound to a local port before
+   * calling this method.
+   *
+   * @param[in] instance A <code>PP_Instance</code>.
+   * @param[in] socket_id An integer <code>PP_Var</code>. The socket ID.
+   * @param[in] address A string <code>PP_Var</code>. The group address to join.
+   * Domain names are not supported.
+   * @param[out] result An integer <code>PP_Var</code>.
+   * @param[in] callback A <code>PP_CompletionCallback</code> to be called
+   * upon completion.
+   *
+   * @return An error code from <code>pp_errors.h</code>.
+   */
+  [version=0.2]
+  int32_t JoinGroup(
+      [in] PP_Instance instance,
+      [in] PP_Var socket_id,
+      [in] PP_Var address,
+      [out] PP_Var result,
+      [in] PP_CompletionCallback callback);
+
+  /**
+   * Leaves the multicast group previously joined using <code>JoinGroup</code>.
+   * It's not necessary to leave the multicast group before destroying the
+   * socket or exiting. This is automatically called by the OS.
+   *
+   * Leaving the group will prevent the router from sending multicast datagrams
+   * to the local host, presuming no other process on the host is still joined
+   * to the group.
+   *
+   * @param[in] instance A <code>PP_Instance</code>.
+   * @param[in] socket_id An integer <code>PP_Var</code>. The socket ID.
+   * @param[in] address A string <code>PP_Var</code>. The group address to
+   * leave. Domain names are not supported.
+   * @param[out] result An integer <code>PP_Var</code>.
+   * @param[in] callback A <code>PP_CompletionCallback</code> to be called
+   * upon completion.
+   *
+   * @return An error code from <code>pp_errors.h</code>.
+   */
+  [version=0.2]
+  int32_t LeaveGroup(
+      [in] PP_Instance instance,
+      [in] PP_Var socket_id,
+      [in] PP_Var address,
+      [out] PP_Var result,
+      [in] PP_CompletionCallback callback);
+
+  /**
+   * Sets the time-to-live of multicast packets sent to the multicast group.
+   *
+   * Calling this method does not require multicast permissions.
+   *
+   * @param[in] instance A <code>PP_Instance</code>.
+   * @param[in] socket_id An integer <code>PP_Var</code>. The socket ID.
+   * @param[in] ttl An integer <code>PP_Var</code>. The time-to-live value.
+   * @param[out] result An integer <code>PP_Var</code>.
+   * @param[in] callback A <code>PP_CompletionCallback</code> to be called
+   * upon completion.
+   *
+   * @return An error code from <code>pp_errors.h</code>.
+   */
+  [version=0.2]
+  int32_t SetMulticastTimeToLive(
+      [in] PP_Instance instance,
+      [in] PP_Var socket_id,
+      [in] PP_Var ttl,
+      [out] PP_Var result,
+      [in] PP_CompletionCallback callback);
+
+  /**
+   * Sets whether multicast packets sent from the host to the multicast group
+   * will be looped back to the host.
+   *
+   * Note: the behavior of <code>SetMulticastLoopbackMode</code> is slightly
+   * different between Windows and Unix-like systems. The inconsistency
+   * happens only when there is more than one application on the same host
+   * joined to the same multicast group while having different settings on
+   * multicast loopback mode. On Windows, the applications with loopback off
+   * will not RECEIVE the loopback packets; while on Unix-like systems, the
+   * applications with loopback off will not SEND the loopback packets to
+   * other applications on the same host. See MSDN: http://goo.gl/6vqbj
+   *
+   * Calling this method does not require multicast permissions.
+   *
+   * @param[in] instance A <code>PP_Instance</code>.
+   * @param[in] socket_id An integer <code>PP_Var</code>. The socket ID.
+   * @param[in] enabled A boolean <code>PP_Var</code>. Indicates whether to
+   * enable loopback mode.
+   * @param[out] result An integer <code>PP_Var</code>.
+   * @param[in] callback A <code>PP_CompletionCallback</code> to be called
+   * upon completion.
+   *
+   * @return An error code from <code>pp_errors.h</code>.
+   */
+  [version=0.2]
+  int32_t SetMulticastLoopbackMode(
+      [in] PP_Instance instance,
+      [in] PP_Var socket_id,
+      [in] PP_Var enabled,
+      [out] PP_Var result,
+      [in] PP_CompletionCallback callback);
+
+  /**
+   * Gets the multicast group addresses the socket is currently joined to.
+   *
+   * @param[in] instance A <code>PP_Instance</code>.
+   * @param[in] socket_id An integer <code>PP_Var</code>. The socket ID.
+   * @param[out] groups An array <code>PP_Var</code> of string
+   * <code>PP_Var</code>s.
+   * @param[in] callback A <code>PP_CompletionCallback</code> to be called
+   * upon completion.
+   *
+   * @return An error code from <code>pp_errors.h</code>.
+   */
+  [version=0.2]
+  int32_t GetJoinedGroups(
+      [in] PP_Instance instance,
+      [in] PP_Var socket_id,
+      [out] PP_Var groups,
+      [in] PP_CompletionCallback callback);
 };
diff --git a/ppapi/api/ppb_file_ref.idl b/ppapi/api/ppb_file_ref.idl
index e783027..8e4b81d 100644
--- a/ppapi/api/ppb_file_ref.idl
+++ b/ppapi/api/ppb_file_ref.idl
@@ -107,9 +107,9 @@
    * if ancestor directories are not needed.
    *
    * @return An int32_t containing an error code from <code>pp_errors.h</code>.
-   * Fails if the directory already exists or if ancestor directories do not
-   * exist and <code>make_ancestors</code> was not passed as
-   * <code>PP_TRUE</code>.
+   * Succeeds if the directory already exists. Fails if ancestor directories
+   * do not exist and <code>make_ancestors</code> was passed as
+   * <code>PP_FALSE</code>.
    */
   int32_t MakeDirectory([in] PP_Resource directory_ref,
                         [in] PP_Bool make_ancestors,
diff --git a/ppapi/api/ppb_messaging.idl b/ppapi/api/ppb_messaging.idl
index 7c9a7ae..647f7f6 100644
--- a/ppapi/api/ppb_messaging.idl
+++ b/ppapi/api/ppb_messaging.idl
@@ -30,9 +30,14 @@
    * of a module.
    * @param[in] message A <code>PP_Var</code> containing the data to be sent to
    * JavaScript.
-   * Message can have a numeric, boolean, or string value; arrays and
-   * dictionaries are not yet supported. Ref-counted var types are copied, and
-   * are therefore not shared between the module instance and the browser.
+   * <code>message</code> can be any <code>PP_Var</code> type except
+   * <code>PP_VARTYPE_OBJECT</code>. Array/Dictionary types are supported from
+   * Chrome M29 onward. All var types are copied when passing them to
+   * JavaScript.
+   *
+   * When passing array or dictionary <code>PP_Var</code>s, the entire reference
+   * graph will be converted and transferred, including reference cycles if they
+   * exist.
    *
    * Listeners for message events in JavaScript code will receive an object
    * conforming to the HTML 5 <code>MessageEvent</code> interface.
diff --git a/ppapi/api/ppp_instance.idl b/ppapi/api/ppp_instance.idl
index a5026ae..f178b7a 100644
--- a/ppapi/api/ppp_instance.idl
+++ b/ppapi/api/ppp_instance.idl
@@ -207,7 +207,7 @@
 
   /**
    * HandleDocumentLoad() is called after initialize for a full-frame
-   * module that was instantiated based on the MIME type of a DOMWindow
+   * instance that was instantiated based on the MIME type of a DOMWindow
    * navigation. This situation only applies to modules that are pre-registered
    * to handle certain MIME types. If you haven't specifically registered to
    * handle a MIME type or aren't positive this applies to you, your
@@ -230,7 +230,8 @@
    * @param[in] url_loader An open <code>PPB_URLLoader</code> instance.
    *
    * @return <code>PP_TRUE</code> if the data was handled,
-   * <code>PP_FALSE</code> otherwise.
+   * <code>PP_FALSE</code> otherwise.  If you return false, the load will be
+   * canceled for you.
    */
   PP_Bool HandleDocumentLoad(
       /* A PP_Instance identifying one instance of a module. */
diff --git a/ppapi/api/ppp_messaging.idl b/ppapi/api/ppp_messaging.idl
index 19bd71f..150f771 100644
--- a/ppapi/api/ppp_messaging.idl
+++ b/ppapi/api/ppp_messaging.idl
@@ -29,9 +29,17 @@
    *
    * @param[in] instance A <code>PP_Instance</code> identifying one instance
    * of a module.
-   * @param[in] message A <code>PP_Var</code> containing the data to be sent
-   * to JavaScript. Message can have an int32_t, double, bool, or string value
-   * (objects are not supported).
+   * @param[in] message A <code>PP_Var</code> which has been converted from a
+   * JavaScript value. JavaScript array/object types are supported from Chrome
+   * M29 onward. All JavaScript values are copied when passing them to the
+   * plugin.
+   *
+   * When converting JavaScript arrays, any object properties whose name
+   * is not an array index are ignored. When passing arrays and objects, the
+   * entire reference graph will be converted and transferred, including
+   * reference cycles if they exist. Since <code>PP_Var</code>s are ref-counted,
+   * the author of the plugin must take care if they expect to receive vars with
+   * cycles. Cycles must be manually broken to correctly release the vars.
    *
    * The following JavaScript code invokes <code>HandleMessage</code>, passing
    * the module instance on which it was invoked, with <code>message</code>
diff --git a/ppapi/api/private/ppb_flash_device_id.idl b/ppapi/api/private/ppb_flash_device_id.idl
index 1fa4986..16b0d3d 100644
--- a/ppapi/api/private/ppb_flash_device_id.idl
+++ b/ppapi/api/private/ppb_flash_device_id.idl
@@ -7,12 +7,13 @@
  * This file contains the <code>PPB_Flash_DeviceID</code> interface.
  */
 
-[generate_thunk]
-
 label Chrome {
-  M21 = 1.0
+  M21 = 1.0,
+  M29 = 1.1
 };
 
+// TODO(raymes): This is deprecated by the PPB_Flash_DRM interface. Remove this
+// interface after a few versions of Chrome have passed.
 interface PPB_Flash_DeviceID {
   PP_Resource Create([in] PP_Instance instance);
 
@@ -21,6 +22,7 @@
    * string in |*id| and will call the completion callback. On failure the
    * given var will be PP_VARTYPE_UNDEFINED.
    */
+  [version=1.0, deprecate=1.1]
   int32_t GetDeviceID([in] PP_Resource device_id,
                       [out] PP_Var id,
                       [in] PP_CompletionCallback callback);
diff --git a/ppapi/api/private/ppb_flash_drm.idl b/ppapi/api/private/ppb_flash_drm.idl
new file mode 100644
index 0000000..8438114
--- /dev/null
+++ b/ppapi/api/private/ppb_flash_drm.idl
@@ -0,0 +1,35 @@
+/* Copyright (c) 2012 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/**
+ * This file contains the <code>PPB_Flash_DRM</code> interface.
+ */
+
+[generate_thunk]
+
+label Chrome {
+  M29 = 1.0
+};
+
+/**
+ * A resource for performing Flash DRM-related operations.
+ */
+interface PPB_Flash_DRM {
+  /**
+   * Creates a PPB_Flash_DRM resource for performing DRM-related operations in
+   * Flash.
+   */
+  PP_Resource Create([in] PP_Instance instance);
+
+  /**
+   * Asynchronously computes the device ID. When available, it will place the
+   * string in |*id| and will call the completion callback. On failure the
+   * given var will be PP_VARTYPE_UNDEFINED.
+   */
+  int32_t GetDeviceID([in] PP_Resource drm,
+                      [out] PP_Var id,
+                      [in] PP_CompletionCallback callback);
+};
+
diff --git a/ppapi/api/private/ppb_nacl_private.idl b/ppapi/api/private/ppb_nacl_private.idl
index b1f47ce..c871178 100644
--- a/ppapi/api/private/ppb_nacl_private.idl
+++ b/ppapi/api/private/ppb_nacl_private.idl
@@ -34,12 +34,6 @@
   PP_NACL_MANIFEST_MISSING_ARCH = 0
 };
 
-struct PP_NaClExecutableMetadata {
-  /** File path of NaCl executable. This is created by the OpenNaClExecutableFd
-   *  function. It is the caller's responsiblity to release it. */
-  PP_Var file_path;
-};
-
 /* PPB_NaCl_Private */
 interface PPB_NaCl_Private {
   /* Launches NaCl's sel_ldr process.  Returns PP_NACL_OK on success and
@@ -129,5 +123,6 @@
    */
   PP_FileHandle OpenNaClExecutable([in] PP_Instance instance,
                                    [in] str_t file_url,
-                                   [out] PP_NaClExecutableMetadata metadata);
+                                   [out] uint64_t file_token_lo,
+                                   [out] uint64_t file_token_hi);
 };
diff --git a/ppapi/api/private/ppb_tcp_server_socket_private.idl b/ppapi/api/private/ppb_tcp_server_socket_private.idl
index f04635c..a9130cc 100644
--- a/ppapi/api/private/ppb_tcp_server_socket_private.idl
+++ b/ppapi/api/private/ppb_tcp_server_socket_private.idl
@@ -8,7 +8,8 @@
  */
 
 label Chrome {
-  M18 = 0.1
+  M18 = 0.1,
+  M28 = 0.2
 };
 
 /**
@@ -53,6 +54,15 @@
                  [in] PP_CompletionCallback callback);
 
   /**
+   * Returns the current address to which the socket is bound, in the
+   * buffer pointed to by |addr|. This method can be called only after
+   * successful Listen() call and before StopListening() call.
+   */
+  [version=0.2]
+  int32_t GetLocalAddress([in] PP_Resource tcp_server_socket,
+                          [out] PP_NetAddress_Private addr);
+
+  /**
    * Cancels all pending callbacks reporting PP_ERROR_ABORTED and
    * closes the socket. Note: this method is implicitly called when
    * server socket is destroyed.
diff --git a/ppapi/c/extensions/dev/ppb_ext_socket_dev.h b/ppapi/c/extensions/dev/ppb_ext_socket_dev.h
index b24e129..61bddd1 100644
--- a/ppapi/c/extensions/dev/ppb_ext_socket_dev.h
+++ b/ppapi/c/extensions/dev/ppb_ext_socket_dev.h
@@ -4,7 +4,7 @@
  */
 
 /* From extensions/dev/ppb_ext_socket_dev.idl,
- *   modified Tue Apr 02 16:04:00 2013.
+ *   modified Tue May 21 16:00:11 2013.
  */
 
 #ifndef PPAPI_C_EXTENSIONS_DEV_PPB_EXT_SOCKET_DEV_H_
@@ -18,7 +18,8 @@
 #include "ppapi/c/pp_var.h"
 
 #define PPB_EXT_SOCKET_DEV_INTERFACE_0_1 "PPB_Ext_Socket(Dev);0.1"
-#define PPB_EXT_SOCKET_DEV_INTERFACE PPB_EXT_SOCKET_DEV_INTERFACE_0_1
+#define PPB_EXT_SOCKET_DEV_INTERFACE_0_2 "PPB_Ext_Socket(Dev);0.2"
+#define PPB_EXT_SOCKET_DEV_INTERFACE PPB_EXT_SOCKET_DEV_INTERFACE_0_2
 
 /**
  * @file
@@ -137,7 +138,7 @@
  * @addtogroup Interfaces
  * @{
  */
-struct PPB_Ext_Socket_Dev_0_1 {
+struct PPB_Ext_Socket_Dev_0_2 {
   /**
    * Creates a socket of the specified type that will connect to the specified
    * remote machine.
@@ -409,9 +410,191 @@
   int32_t (*GetNetworkList)(PP_Instance instance,
                             PP_Ext_Socket_NetworkInterface_Dev_Array* result,
                             struct PP_CompletionCallback callback);
+  /**
+   * Joins the multicast group and starts to receive packets from that group.
+   * The socket must be of UDP type and must be bound to a local port before
+   * calling this method.
+   *
+   * @param[in] instance A <code>PP_Instance</code>.
+   * @param[in] socket_id An integer <code>PP_Var</code>. The socket ID.
+   * @param[in] address A string <code>PP_Var</code>. The group address to join.
+   * Domain names are not supported.
+   * @param[out] result An integer <code>PP_Var</code>.
+   * @param[in] callback A <code>PP_CompletionCallback</code> to be called
+   * upon completion.
+   *
+   * @return An error code from <code>pp_errors.h</code>.
+   */
+  int32_t (*JoinGroup)(PP_Instance instance,
+                       struct PP_Var socket_id,
+                       struct PP_Var address,
+                       struct PP_Var* result,
+                       struct PP_CompletionCallback callback);
+  /**
+   * Leaves the multicast group previously joined using <code>JoinGroup</code>.
+   * It's not necessary to leave the multicast group before destroying the
+   * socket or exiting. This is automatically called by the OS.
+   *
+   * Leaving the group will prevent the router from sending multicast datagrams
+   * to the local host, presuming no other process on the host is still joined
+   * to the group.
+   *
+   * @param[in] instance A <code>PP_Instance</code>.
+   * @param[in] socket_id An integer <code>PP_Var</code>. The socket ID.
+   * @param[in] address A string <code>PP_Var</code>. The group address to
+   * leave. Domain names are not supported.
+   * @param[out] result An integer <code>PP_Var</code>.
+   * @param[in] callback A <code>PP_CompletionCallback</code> to be called
+   * upon completion.
+   *
+   * @return An error code from <code>pp_errors.h</code>.
+   */
+  int32_t (*LeaveGroup)(PP_Instance instance,
+                        struct PP_Var socket_id,
+                        struct PP_Var address,
+                        struct PP_Var* result,
+                        struct PP_CompletionCallback callback);
+  /**
+   * Sets the time-to-live of multicast packets sent to the multicast group.
+   *
+   * Calling this method does not require multicast permissions.
+   *
+   * @param[in] instance A <code>PP_Instance</code>.
+   * @param[in] socket_id An integer <code>PP_Var</code>. The socket ID.
+   * @param[in] ttl An integer <code>PP_Var</code>. The time-to-live value.
+   * @param[out] result An integer <code>PP_Var</code>.
+   * @param[in] callback A <code>PP_CompletionCallback</code> to be called
+   * upon completion.
+   *
+   * @return An error code from <code>pp_errors.h</code>.
+   */
+  int32_t (*SetMulticastTimeToLive)(PP_Instance instance,
+                                    struct PP_Var socket_id,
+                                    struct PP_Var ttl,
+                                    struct PP_Var* result,
+                                    struct PP_CompletionCallback callback);
+  /**
+   * Sets whether multicast packets sent from the host to the multicast group
+   * will be looped back to the host.
+   *
+   * Note: the behavior of <code>SetMulticastLoopbackMode</code> is slightly
+   * different between Windows and Unix-like systems. The inconsistency
+   * happens only when there is more than one application on the same host
+   * joined to the same multicast group while having different settings on
+   * multicast loopback mode. On Windows, the applications with loopback off
+   * will not RECEIVE the loopback packets; while on Unix-like systems, the
+   * applications with loopback off will not SEND the loopback packets to
+   * other applications on the same host. See MSDN: http://goo.gl/6vqbj
+   *
+   * Calling this method does not require multicast permissions.
+   *
+   * @param[in] instance A <code>PP_Instance</code>.
+   * @param[in] socket_id An integer <code>PP_Var</code>. The socket ID.
+   * @param[in] enabled A boolean <code>PP_Var</code>. Indicates whether to
+   * enable loopback mode.
+   * @param[out] result An integer <code>PP_Var</code>.
+   * @param[in] callback A <code>PP_CompletionCallback</code> to be called
+   * upon completion.
+   *
+   * @return An error code from <code>pp_errors.h</code>.
+   */
+  int32_t (*SetMulticastLoopbackMode)(PP_Instance instance,
+                                      struct PP_Var socket_id,
+                                      struct PP_Var enabled,
+                                      struct PP_Var* result,
+                                      struct PP_CompletionCallback callback);
+  /**
+   * Gets the multicast group addresses the socket is currently joined to.
+   *
+   * @param[in] instance A <code>PP_Instance</code>.
+   * @param[in] socket_id An integer <code>PP_Var</code>. The socket ID.
+   * @param[out] groups An array <code>PP_Var</code> of string
+   * <code>PP_Var</code>s.
+   * @param[in] callback A <code>PP_CompletionCallback</code> to be called
+   * upon completion.
+   *
+   * @return An error code from <code>pp_errors.h</code>.
+   */
+  int32_t (*GetJoinedGroups)(PP_Instance instance,
+                             struct PP_Var socket_id,
+                             struct PP_Var* groups,
+                             struct PP_CompletionCallback callback);
 };
 
-typedef struct PPB_Ext_Socket_Dev_0_1 PPB_Ext_Socket_Dev;
+typedef struct PPB_Ext_Socket_Dev_0_2 PPB_Ext_Socket_Dev;
+
+struct PPB_Ext_Socket_Dev_0_1 {
+  int32_t (*Create)(PP_Instance instance,
+                    PP_Ext_Socket_SocketType_Dev type,
+                    PP_Ext_Socket_CreateOptions_Dev options,
+                    PP_Ext_Socket_CreateInfo_Dev* create_info,
+                    struct PP_CompletionCallback callback);
+  void (*Destroy)(PP_Instance instance, struct PP_Var socket_id);
+  int32_t (*Connect)(PP_Instance instance,
+                     struct PP_Var socket_id,
+                     struct PP_Var hostname,
+                     struct PP_Var port,
+                     struct PP_Var* result,
+                     struct PP_CompletionCallback callback);
+  int32_t (*Bind)(PP_Instance instance,
+                  struct PP_Var socket_id,
+                  struct PP_Var address,
+                  struct PP_Var port,
+                  struct PP_Var* result,
+                  struct PP_CompletionCallback callback);
+  void (*Disconnect)(PP_Instance instance, struct PP_Var socket_id);
+  int32_t (*Read)(PP_Instance instance,
+                  struct PP_Var socket_id,
+                  struct PP_Var buffer_size,
+                  PP_Ext_Socket_ReadInfo_Dev* read_info,
+                  struct PP_CompletionCallback callback);
+  int32_t (*Write)(PP_Instance instance,
+                   struct PP_Var socket_id,
+                   struct PP_Var data,
+                   PP_Ext_Socket_WriteInfo_Dev* write_info,
+                   struct PP_CompletionCallback callback);
+  int32_t (*RecvFrom)(PP_Instance instance,
+                      struct PP_Var socket_id,
+                      struct PP_Var buffer_size,
+                      PP_Ext_Socket_RecvFromInfo_Dev* recv_from_info,
+                      struct PP_CompletionCallback callback);
+  int32_t (*SendTo)(PP_Instance instance,
+                    struct PP_Var socket_id,
+                    struct PP_Var data,
+                    struct PP_Var address,
+                    struct PP_Var port,
+                    PP_Ext_Socket_WriteInfo_Dev* write_info,
+                    struct PP_CompletionCallback callback);
+  int32_t (*Listen)(PP_Instance instance,
+                    struct PP_Var socket_id,
+                    struct PP_Var address,
+                    struct PP_Var port,
+                    struct PP_Var backlog,
+                    struct PP_Var* result,
+                    struct PP_CompletionCallback callback);
+  int32_t (*Accept)(PP_Instance instance,
+                    struct PP_Var socket_id,
+                    PP_Ext_Socket_AcceptInfo_Dev* accept_info,
+                    struct PP_CompletionCallback callback);
+  int32_t (*SetKeepAlive)(PP_Instance instance,
+                          struct PP_Var socket_id,
+                          struct PP_Var enable,
+                          struct PP_Var delay,
+                          struct PP_Var* result,
+                          struct PP_CompletionCallback callback);
+  int32_t (*SetNoDelay)(PP_Instance instance,
+                        struct PP_Var socket_id,
+                        struct PP_Var no_delay,
+                        struct PP_Var* result,
+                        struct PP_CompletionCallback callback);
+  int32_t (*GetInfo)(PP_Instance instance,
+                     struct PP_Var socket_id,
+                     PP_Ext_Socket_SocketInfo_Dev* result,
+                     struct PP_CompletionCallback callback);
+  int32_t (*GetNetworkList)(PP_Instance instance,
+                            PP_Ext_Socket_NetworkInterface_Dev_Array* result,
+                            struct PP_CompletionCallback callback);
+};
 /**
  * @}
  */
diff --git a/ppapi/c/pp_macros.h b/ppapi/c/pp_macros.h
index 6179380..c56d95b 100644
--- a/ppapi/c/pp_macros.h
+++ b/ppapi/c/pp_macros.h
@@ -3,13 +3,13 @@
  * found in the LICENSE file.
  */
 
-/* From pp_macros.idl modified Tue Mar 19 12:29:49 2013. */
+/* From pp_macros.idl modified Thu Mar 14 13:24:42 2013. */
 
 #ifndef PPAPI_C_PP_MACROS_H_
 #define PPAPI_C_PP_MACROS_H_
 
 
-#define PPAPI_RELEASE 28
+#define PPAPI_RELEASE 29
 
 /**
  * @file
diff --git a/ppapi/c/ppb_file_ref.h b/ppapi/c/ppb_file_ref.h
index 951c30d..0f35e2c 100644
--- a/ppapi/c/ppb_file_ref.h
+++ b/ppapi/c/ppb_file_ref.h
@@ -3,7 +3,7 @@
  * found in the LICENSE file.
  */
 
-/* From ppb_file_ref.idl modified Thu May  2 16:22:57 2013. */
+/* From ppb_file_ref.idl modified Wed May 22 15:08:49 2013. */
 
 #ifndef PPAPI_C_PPB_FILE_REF_H_
 #define PPAPI_C_PPB_FILE_REF_H_
@@ -122,9 +122,9 @@
    * if ancestor directories are not needed.
    *
    * @return An int32_t containing an error code from <code>pp_errors.h</code>.
-   * Fails if the directory already exists or if ancestor directories do not
-   * exist and <code>make_ancestors</code> was not passed as
-   * <code>PP_TRUE</code>.
+   * Succeeds if the directory already exists. Fails if ancestor directories
+   * do not exist and <code>make_ancestors</code> was passed as
+   * <code>PP_FALSE</code>.
    */
   int32_t (*MakeDirectory)(PP_Resource directory_ref,
                            PP_Bool make_ancestors,
diff --git a/ppapi/c/ppb_messaging.h b/ppapi/c/ppb_messaging.h
index 31ed0a7..404a11c 100644
--- a/ppapi/c/ppb_messaging.h
+++ b/ppapi/c/ppb_messaging.h
@@ -3,7 +3,7 @@
  * found in the LICENSE file.
  */
 
-/* From ppb_messaging.idl modified Thu Apr 26 13:16:11 2012. */
+/* From ppb_messaging.idl modified Mon May 20 15:31:07 2013. */
 
 #ifndef PPAPI_C_PPB_MESSAGING_H_
 #define PPAPI_C_PPB_MESSAGING_H_
@@ -44,9 +44,14 @@
    * of a module.
    * @param[in] message A <code>PP_Var</code> containing the data to be sent to
    * JavaScript.
-   * Message can have a numeric, boolean, or string value; arrays and
-   * dictionaries are not yet supported. Ref-counted var types are copied, and
-   * are therefore not shared between the module instance and the browser.
+   * <code>message</code> can be any <code>PP_Var</code> type except
+   * <code>PP_VARTYPE_OBJECT</code>. Array/Dictionary types are supported from
+   * Chrome M29 onward. All var types are copied when passing them to
+   * JavaScript.
+   *
+   * When passing array or dictionary <code>PP_Var</code>s, the entire reference
+   * graph will be converted and transferred, including reference cycles if they
+   * exist.
    *
    * Listeners for message events in JavaScript code will receive an object
    * conforming to the HTML 5 <code>MessageEvent</code> interface.
diff --git a/ppapi/c/ppp_instance.h b/ppapi/c/ppp_instance.h
index bdc2883..d2641f9 100644
--- a/ppapi/c/ppp_instance.h
+++ b/ppapi/c/ppp_instance.h
@@ -3,7 +3,7 @@
  * found in the LICENSE file.
  */
 
-/* From ppp_instance.idl modified Thu Jun 28 15:08:39 2012. */
+/* From ppp_instance.idl modified Thu Apr 25 13:07:47 2013. */
 
 #ifndef PPAPI_C_PPP_INSTANCE_H_
 #define PPAPI_C_PPP_INSTANCE_H_
@@ -146,7 +146,7 @@
   void (*DidChangeFocus)(PP_Instance instance, PP_Bool has_focus);
   /**
    * HandleDocumentLoad() is called after initialize for a full-frame
-   * module that was instantiated based on the MIME type of a DOMWindow
+   * instance that was instantiated based on the MIME type of a DOMWindow
    * navigation. This situation only applies to modules that are pre-registered
    * to handle certain MIME types. If you haven't specifically registered to
    * handle a MIME type or aren't positive this applies to you, your
@@ -169,7 +169,8 @@
    * @param[in] url_loader An open <code>PPB_URLLoader</code> instance.
    *
    * @return <code>PP_TRUE</code> if the data was handled,
-   * <code>PP_FALSE</code> otherwise.
+   * <code>PP_FALSE</code> otherwise.  If you return false, the load will be
+   * canceled for you.
    */
   PP_Bool (*HandleDocumentLoad)(PP_Instance instance, PP_Resource url_loader);
 };
diff --git a/ppapi/c/ppp_messaging.h b/ppapi/c/ppp_messaging.h
index 1448bb1..b2e1f3c 100644
--- a/ppapi/c/ppp_messaging.h
+++ b/ppapi/c/ppp_messaging.h
@@ -3,7 +3,7 @@
  * found in the LICENSE file.
  */
 
-/* From ppp_messaging.idl modified Wed Jan 25 11:41:09 2012. */
+/* From ppp_messaging.idl modified Tue May 21 09:01:17 2013. */
 
 #ifndef PPAPI_C_PPP_MESSAGING_H_
 #define PPAPI_C_PPP_MESSAGING_H_
@@ -45,9 +45,17 @@
    *
    * @param[in] instance A <code>PP_Instance</code> identifying one instance
    * of a module.
-   * @param[in] message A <code>PP_Var</code> containing the data to be sent
-   * to JavaScript. Message can have an int32_t, double, bool, or string value
-   * (objects are not supported).
+   * @param[in] message A <code>PP_Var</code> which has been converted from a
+   * JavaScript value. JavaScript array/object types are supported from Chrome
+   * M29 onward. All JavaScript values are copied when passing them to the
+   * plugin.
+   *
+   * When converting JavaScript arrays, any object properties whose name
+   * is not an array index are ignored. When passing arrays and objects, the
+   * entire reference graph will be converted and transferred, including
+   * reference cycles if they exist. Since <code>PP_Var</code>s are ref-counted,
+   * the author of the plugin must take care if they expect to receive vars with
+   * cycles. Cycles must be manually broken to correctly release the vars.
    *
    * The following JavaScript code invokes <code>HandleMessage</code>, passing
    * the module instance on which it was invoked, with <code>message</code>
diff --git a/ppapi/c/private/ppb_flash_device_id.h b/ppapi/c/private/ppb_flash_device_id.h
index 33d1ba7..17660fb 100644
--- a/ppapi/c/private/ppb_flash_device_id.h
+++ b/ppapi/c/private/ppb_flash_device_id.h
@@ -3,7 +3,7 @@
  * found in the LICENSE file.
  */
 
-/* From private/ppb_flash_device_id.idl modified Fri Jun  1 15:21:17 2012. */
+/* From private/ppb_flash_device_id.idl modified Tue May 14 10:55:27 2013. */
 
 #ifndef PPAPI_C_PRIVATE_PPB_FLASH_DEVICE_ID_H_
 #define PPAPI_C_PRIVATE_PPB_FLASH_DEVICE_ID_H_
@@ -29,6 +29,8 @@
  * @addtogroup Interfaces
  * @{
  */
+/* TODO(raymes): This is deprecated by the PPB_Flash_DRM interface. Remove this
+ * interface after a few versions of Chrome have passed. */
 struct PPB_Flash_DeviceID_1_0 {
   PP_Resource (*Create)(PP_Instance instance);
   /**
diff --git a/ppapi/c/private/ppb_flash_drm.h b/ppapi/c/private/ppb_flash_drm.h
new file mode 100644
index 0000000..ed41593
--- /dev/null
+++ b/ppapi/c/private/ppb_flash_drm.h
@@ -0,0 +1,57 @@
+/* Copyright (c) 2012 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/* From private/ppb_flash_drm.idl modified Tue May 21 09:34:07 2013. */
+
+#ifndef PPAPI_C_PRIVATE_PPB_FLASH_DRM_H_
+#define PPAPI_C_PRIVATE_PPB_FLASH_DRM_H_
+
+#include "ppapi/c/pp_bool.h"
+#include "ppapi/c/pp_completion_callback.h"
+#include "ppapi/c/pp_instance.h"
+#include "ppapi/c/pp_macros.h"
+#include "ppapi/c/pp_resource.h"
+#include "ppapi/c/pp_stdint.h"
+#include "ppapi/c/pp_var.h"
+
+#define PPB_FLASH_DRM_INTERFACE_1_0 "PPB_Flash_DRM;1.0"
+#define PPB_FLASH_DRM_INTERFACE PPB_FLASH_DRM_INTERFACE_1_0
+
+/**
+ * @file
+ * This file contains the <code>PPB_Flash_DRM</code> interface.
+ */
+
+
+/**
+ * @addtogroup Interfaces
+ * @{
+ */
+/**
+ * A resource for performing Flash DRM-related operations.
+ */
+struct PPB_Flash_DRM_1_0 {
+  /**
+   * Creates a PPB_Flash_DRM resource for performing DRM-related operations in
+   * Flash.
+   */
+  PP_Resource (*Create)(PP_Instance instance);
+  /**
+   * Asynchronously computes the device ID. When available, it will place the
+   * string in |*id| and will call the completion callback. On failure the
+   * given var will be PP_VARTYPE_UNDEFINED.
+   */
+  int32_t (*GetDeviceID)(PP_Resource drm,
+                         struct PP_Var* id,
+                         struct PP_CompletionCallback callback);
+};
+
+typedef struct PPB_Flash_DRM_1_0 PPB_Flash_DRM;
+/**
+ * @}
+ */
+
+#endif  /* PPAPI_C_PRIVATE_PPB_FLASH_DRM_H_ */
+
diff --git a/ppapi/c/private/ppb_nacl_private.h b/ppapi/c/private/ppb_nacl_private.h
index 8e40fd8..72b62e9 100644
--- a/ppapi/c/private/ppb_nacl_private.h
+++ b/ppapi/c/private/ppb_nacl_private.h
@@ -3,7 +3,7 @@
  * found in the LICENSE file.
  */
 
-/* From private/ppb_nacl_private.idl modified Mon Apr 22 22:25:20 2013. */
+/* From private/ppb_nacl_private.idl modified Fri May 17 13:21:13 2013. */
 
 #ifndef PPAPI_C_PRIVATE_PPB_NACL_PRIVATE_H_
 #define PPAPI_C_PRIVATE_PPB_NACL_PRIVATE_H_
@@ -12,7 +12,6 @@
 #include "ppapi/c/pp_instance.h"
 #include "ppapi/c/pp_macros.h"
 #include "ppapi/c/pp_stdint.h"
-#include "ppapi/c/pp_var.h"
 
 #define PPB_NACL_PRIVATE_INTERFACE_1_0 "PPB_NaCl_Private;1.0"
 #define PPB_NACL_PRIVATE_INTERFACE PPB_NACL_PRIVATE_INTERFACE_1_0
@@ -57,19 +56,6 @@
  */
 
 /**
- * @addtogroup Structs
- * @{
- */
-struct PP_NaClExecutableMetadata {
-  /** File path of NaCl executable. This is created by the OpenNaClExecutableFd
-   *  function. It is the caller's responsiblity to release it. */
-  struct PP_Var file_path;
-};
-/**
- * @}
- */
-
-/**
  * @addtogroup Interfaces
  * @{
  */
@@ -149,10 +135,10 @@
    * corresponding to the file URL and returns a file descriptor, or an invalid
    * handle on failure. |metadata| is left unchanged on failure.
    */
-  PP_FileHandle (*OpenNaClExecutable)(
-      PP_Instance instance,
-      const char* file_url,
-      struct PP_NaClExecutableMetadata* metadata);
+  PP_FileHandle (*OpenNaClExecutable)(PP_Instance instance,
+                                      const char* file_url,
+                                      uint64_t* file_token_lo,
+                                      uint64_t* file_token_hi);
 };
 
 typedef struct PPB_NaCl_Private_1_0 PPB_NaCl_Private;
diff --git a/ppapi/c/private/ppb_proxy_private.h b/ppapi/c/private/ppb_proxy_private.h
index eac3f57..b185c2c 100644
--- a/ppapi/c/private/ppb_proxy_private.h
+++ b/ppapi/c/private/ppb_proxy_private.h
@@ -10,7 +10,7 @@
 #include "ppapi/c/pp_module.h"
 #include "ppapi/c/pp_resource.h"
 
-#define PPB_PROXY_PRIVATE_INTERFACE "PPB_Proxy_Private;5"
+#define PPB_PROXY_PRIVATE_INTERFACE "PPB_Proxy_Private;6"
 
 // Exposes functions needed by the out-of-process proxy to call into the
 // renderer PPAPI implementation.
@@ -34,11 +34,6 @@
       PP_Module module,
       PP_Bool (*is_seen)(PP_Module, PP_Instance));
 
-  // Returns the number of bytes synchronously readable out of the URLLoader's
-  // buffer. Returns 0 on failure or if the url loader doesn't have any data
-  // now.
-  int32_t (*GetURLLoaderBufferedBytes)(PP_Resource url_loader);
-
   // Allows adding additional refcounts to the PluginModule that owns the
   // proxy dispatcher (and all interface proxies). For every AddRef call
   // there must be a corresponding release call.
diff --git a/ppapi/c/private/ppb_tcp_server_socket_private.h b/ppapi/c/private/ppb_tcp_server_socket_private.h
index f019519..7de387b 100644
--- a/ppapi/c/private/ppb_tcp_server_socket_private.h
+++ b/ppapi/c/private/ppb_tcp_server_socket_private.h
@@ -4,7 +4,7 @@
  */
 
 /* From private/ppb_tcp_server_socket_private.idl,
- *   modified Thu Mar 28 10:31:11 2013.
+ *   modified Mon May 20 12:45:38 2013.
  */
 
 #ifndef PPAPI_C_PRIVATE_PPB_TCP_SERVER_SOCKET_PRIVATE_H_
@@ -20,8 +20,10 @@
 
 #define PPB_TCPSERVERSOCKET_PRIVATE_INTERFACE_0_1 \
     "PPB_TCPServerSocket_Private;0.1"
+#define PPB_TCPSERVERSOCKET_PRIVATE_INTERFACE_0_2 \
+    "PPB_TCPServerSocket_Private;0.2"
 #define PPB_TCPSERVERSOCKET_PRIVATE_INTERFACE \
-    PPB_TCPSERVERSOCKET_PRIVATE_INTERFACE_0_1
+    PPB_TCPSERVERSOCKET_PRIVATE_INTERFACE_0_2
 
 /**
  * @file
@@ -37,7 +39,7 @@
  * The <code>PPB_TCPServerSocket_Private</code> interface provides TCP
  * server socket operations.
  */
-struct PPB_TCPServerSocket_Private_0_1 {
+struct PPB_TCPServerSocket_Private_0_2 {
   /**
    * Allocates a TCP server socket resource.
    */
@@ -71,6 +73,13 @@
                     PP_Resource* tcp_socket,
                     struct PP_CompletionCallback callback);
   /**
+   * Returns the current address to which the socket is bound, in the
+   * buffer pointed to by |addr|. This method can be called only after
+   * successful Listen() call and before StopListening() call.
+   */
+  int32_t (*GetLocalAddress)(PP_Resource tcp_server_socket,
+                             struct PP_NetAddress_Private* addr);
+  /**
    * Cancels all pending callbacks reporting PP_ERROR_ABORTED and
    * closes the socket. Note: this method is implicitly called when
    * server socket is destroyed.
@@ -78,7 +87,20 @@
   void (*StopListening)(PP_Resource tcp_server_socket);
 };
 
-typedef struct PPB_TCPServerSocket_Private_0_1 PPB_TCPServerSocket_Private;
+typedef struct PPB_TCPServerSocket_Private_0_2 PPB_TCPServerSocket_Private;
+
+struct PPB_TCPServerSocket_Private_0_1 {
+  PP_Resource (*Create)(PP_Instance instance);
+  PP_Bool (*IsTCPServerSocket)(PP_Resource resource);
+  int32_t (*Listen)(PP_Resource tcp_server_socket,
+                    const struct PP_NetAddress_Private* addr,
+                    int32_t backlog,
+                    struct PP_CompletionCallback callback);
+  int32_t (*Accept)(PP_Resource tcp_server_socket,
+                    PP_Resource* tcp_socket,
+                    struct PP_CompletionCallback callback);
+  void (*StopListening)(PP_Resource tcp_server_socket);
+};
 /**
  * @}
  */
diff --git a/ppapi/cpp/extensions/dev/socket_dev.cc b/ppapi/cpp/extensions/dev/socket_dev.cc
index fb493ba..558f01e 100644
--- a/ppapi/cpp/extensions/dev/socket_dev.cc
+++ b/ppapi/cpp/extensions/dev/socket_dev.cc
@@ -14,8 +14,8 @@
 
 namespace {
 
-template <> const char* interface_name<PPB_Ext_Socket_Dev_0_1>() {
-  return PPB_EXT_SOCKET_DEV_INTERFACE_0_1;
+template <> const char* interface_name<PPB_Ext_Socket_Dev_0_2>() {
+  return PPB_EXT_SOCKET_DEV_INTERFACE_0_2;
 }
 
 }  // namespace
@@ -317,13 +317,13 @@
 int32_t Socket_Dev::Create(const SocketType_Dev& type,
                            const Optional<CreateOptions_Dev>& options,
                            const CreateCallback& callback) {
-  if (!has_interface<PPB_Ext_Socket_Dev_0_1>())
+  if (!has_interface<PPB_Ext_Socket_Dev_0_2>())
     return callback.MayForce(PP_ERROR_NOINTERFACE);
 
   internal::ToVarConverter<SocketType_Dev> type_var(type);
   internal::ToVarConverter<Optional<CreateOptions_Dev> > options_var(options);
 
-  return get_interface<PPB_Ext_Socket_Dev_0_1>()->Create(
+  return get_interface<PPB_Ext_Socket_Dev_0_2>()->Create(
       instance_.pp_instance(),
       type_var.pp_var(),
       options_var.pp_var(),
@@ -332,12 +332,12 @@
 }
 
 void Socket_Dev::Destroy(int32_t socket_id) {
-  if (!has_interface<PPB_Ext_Socket_Dev_0_1>())
+  if (!has_interface<PPB_Ext_Socket_Dev_0_2>())
     return;
 
   internal::ToVarConverter<int32_t> socket_id_var(socket_id);
 
-  return get_interface<PPB_Ext_Socket_Dev_0_1>()->Destroy(
+  return get_interface<PPB_Ext_Socket_Dev_0_2>()->Destroy(
       instance_.pp_instance(),
       socket_id_var.pp_var());
 }
@@ -346,14 +346,14 @@
                             const std::string& hostname,
                             int32_t port,
                             const ConnectCallback& callback) {
-  if (!has_interface<PPB_Ext_Socket_Dev_0_1>())
+  if (!has_interface<PPB_Ext_Socket_Dev_0_2>())
     return callback.MayForce(PP_ERROR_NOINTERFACE);
 
   internal::ToVarConverter<int32_t> socket_id_var(socket_id);
   internal::ToVarConverter<std::string> hostname_var(hostname);
   internal::ToVarConverter<int32_t> port_var(port);
 
-  return get_interface<PPB_Ext_Socket_Dev_0_1>()->Connect(
+  return get_interface<PPB_Ext_Socket_Dev_0_2>()->Connect(
       instance_.pp_instance(),
       socket_id_var.pp_var(),
       hostname_var.pp_var(),
@@ -366,14 +366,14 @@
                          const std::string& address,
                          int32_t port,
                          const BindCallback& callback) {
-  if (!has_interface<PPB_Ext_Socket_Dev_0_1>())
+  if (!has_interface<PPB_Ext_Socket_Dev_0_2>())
     return callback.MayForce(PP_ERROR_NOINTERFACE);
 
   internal::ToVarConverter<int32_t> socket_id_var(socket_id);
   internal::ToVarConverter<std::string> address_var(address);
   internal::ToVarConverter<int32_t> port_var(port);
 
-  return get_interface<PPB_Ext_Socket_Dev_0_1>()->Bind(
+  return get_interface<PPB_Ext_Socket_Dev_0_2>()->Bind(
       instance_.pp_instance(),
       socket_id_var.pp_var(),
       address_var.pp_var(),
@@ -383,12 +383,12 @@
 }
 
 void Socket_Dev::Disconnect(int32_t socket_id) {
-  if (!has_interface<PPB_Ext_Socket_Dev_0_1>())
+  if (!has_interface<PPB_Ext_Socket_Dev_0_2>())
     return;
 
   internal::ToVarConverter<int32_t> socket_id_var(socket_id);
 
-  return get_interface<PPB_Ext_Socket_Dev_0_1>()->Disconnect(
+  return get_interface<PPB_Ext_Socket_Dev_0_2>()->Disconnect(
       instance_.pp_instance(),
       socket_id_var.pp_var());
 }
@@ -396,13 +396,13 @@
 int32_t Socket_Dev::Read(int32_t socket_id,
                          const Optional<int32_t>& buffer_size,
                          const ReadCallback& callback) {
-  if (!has_interface<PPB_Ext_Socket_Dev_0_1>())
+  if (!has_interface<PPB_Ext_Socket_Dev_0_2>())
     return callback.MayForce(PP_ERROR_NOINTERFACE);
 
   internal::ToVarConverter<int32_t> socket_id_var(socket_id);
   internal::ToVarConverter<Optional<int32_t> > buffer_size_var(buffer_size);
 
-  return get_interface<PPB_Ext_Socket_Dev_0_1>()->Read(
+  return get_interface<PPB_Ext_Socket_Dev_0_2>()->Read(
       instance_.pp_instance(),
       socket_id_var.pp_var(),
       buffer_size_var.pp_var(),
@@ -413,13 +413,13 @@
 int32_t Socket_Dev::Write(int32_t socket_id,
                           const VarArrayBuffer& data,
                           const WriteCallback& callback) {
-  if (!has_interface<PPB_Ext_Socket_Dev_0_1>())
+  if (!has_interface<PPB_Ext_Socket_Dev_0_2>())
     return callback.MayForce(PP_ERROR_NOINTERFACE);
 
   internal::ToVarConverter<int32_t> socket_id_var(socket_id);
   internal::ToVarConverter<Var> data_var(data);
 
-  return get_interface<PPB_Ext_Socket_Dev_0_1>()->Write(
+  return get_interface<PPB_Ext_Socket_Dev_0_2>()->Write(
       instance_.pp_instance(),
       socket_id_var.pp_var(),
       data_var.pp_var(),
@@ -430,13 +430,13 @@
 int32_t Socket_Dev::RecvFrom(int32_t socket_id,
                              const Optional<int32_t>& buffer_size,
                              const RecvFromCallback& callback) {
-  if (!has_interface<PPB_Ext_Socket_Dev_0_1>())
+  if (!has_interface<PPB_Ext_Socket_Dev_0_2>())
     return callback.MayForce(PP_ERROR_NOINTERFACE);
 
   internal::ToVarConverter<int32_t> socket_id_var(socket_id);
   internal::ToVarConverter<Optional<int32_t> > buffer_size_var(buffer_size);
 
-  return get_interface<PPB_Ext_Socket_Dev_0_1>()->RecvFrom(
+  return get_interface<PPB_Ext_Socket_Dev_0_2>()->RecvFrom(
       instance_.pp_instance(),
       socket_id_var.pp_var(),
       buffer_size_var.pp_var(),
@@ -449,7 +449,7 @@
                            const std::string& address,
                            int32_t port,
                            const SendToCallback& callback) {
-  if (!has_interface<PPB_Ext_Socket_Dev_0_1>())
+  if (!has_interface<PPB_Ext_Socket_Dev_0_2>())
     return callback.MayForce(PP_ERROR_NOINTERFACE);
 
   internal::ToVarConverter<int32_t> socket_id_var(socket_id);
@@ -457,7 +457,7 @@
   internal::ToVarConverter<std::string> address_var(address);
   internal::ToVarConverter<int32_t> port_var(port);
 
-  return get_interface<PPB_Ext_Socket_Dev_0_1>()->SendTo(
+  return get_interface<PPB_Ext_Socket_Dev_0_2>()->SendTo(
       instance_.pp_instance(),
       socket_id_var.pp_var(),
       data_var.pp_var(),
@@ -472,7 +472,7 @@
                            int32_t port,
                            const Optional<int32_t>& backlog,
                            const ListenCallback& callback) {
-  if (!has_interface<PPB_Ext_Socket_Dev_0_1>())
+  if (!has_interface<PPB_Ext_Socket_Dev_0_2>())
     return callback.MayForce(PP_ERROR_NOINTERFACE);
 
   internal::ToVarConverter<int32_t> socket_id_var(socket_id);
@@ -480,7 +480,7 @@
   internal::ToVarConverter<int32_t> port_var(port);
   internal::ToVarConverter<Optional<int32_t> > backlog_var(backlog);
 
-  return get_interface<PPB_Ext_Socket_Dev_0_1>()->Listen(
+  return get_interface<PPB_Ext_Socket_Dev_0_2>()->Listen(
       instance_.pp_instance(),
       socket_id_var.pp_var(),
       address_var.pp_var(),
@@ -492,12 +492,12 @@
 
 int32_t Socket_Dev::Accept(int32_t socket_id,
                            const AcceptCallback& callback) {
-  if (!has_interface<PPB_Ext_Socket_Dev_0_1>())
+  if (!has_interface<PPB_Ext_Socket_Dev_0_2>())
     return callback.MayForce(PP_ERROR_NOINTERFACE);
 
   internal::ToVarConverter<int32_t> socket_id_var(socket_id);
 
-  return get_interface<PPB_Ext_Socket_Dev_0_1>()->Accept(
+  return get_interface<PPB_Ext_Socket_Dev_0_2>()->Accept(
       instance_.pp_instance(),
       socket_id_var.pp_var(),
       callback.output(),
@@ -508,14 +508,14 @@
                                  bool enable,
                                  const Optional<int32_t>& delay,
                                  const SetKeepAliveCallback& callback) {
-  if (!has_interface<PPB_Ext_Socket_Dev_0_1>())
+  if (!has_interface<PPB_Ext_Socket_Dev_0_2>())
     return callback.MayForce(PP_ERROR_NOINTERFACE);
 
   internal::ToVarConverter<int32_t> socket_id_var(socket_id);
   internal::ToVarConverter<bool> enable_var(enable);
   internal::ToVarConverter<Optional<int32_t> > delay_var(delay);
 
-  return get_interface<PPB_Ext_Socket_Dev_0_1>()->SetKeepAlive(
+  return get_interface<PPB_Ext_Socket_Dev_0_2>()->SetKeepAlive(
       instance_.pp_instance(),
       socket_id_var.pp_var(),
       enable_var.pp_var(),
@@ -527,13 +527,13 @@
 int32_t Socket_Dev::SetNoDelay(int32_t socket_id,
                                bool no_delay,
                                const SetNoDelayCallback& callback) {
-  if (!has_interface<PPB_Ext_Socket_Dev_0_1>())
+  if (!has_interface<PPB_Ext_Socket_Dev_0_2>())
     return callback.MayForce(PP_ERROR_NOINTERFACE);
 
   internal::ToVarConverter<int32_t> socket_id_var(socket_id);
   internal::ToVarConverter<bool> no_delay_var(no_delay);
 
-  return get_interface<PPB_Ext_Socket_Dev_0_1>()->SetNoDelay(
+  return get_interface<PPB_Ext_Socket_Dev_0_2>()->SetNoDelay(
       instance_.pp_instance(),
       socket_id_var.pp_var(),
       no_delay_var.pp_var(),
@@ -543,12 +543,12 @@
 
 int32_t Socket_Dev::GetInfo(int32_t socket_id,
                             const GetInfoCallback& callback) {
-  if (!has_interface<PPB_Ext_Socket_Dev_0_1>())
+  if (!has_interface<PPB_Ext_Socket_Dev_0_2>())
     return callback.MayForce(PP_ERROR_NOINTERFACE);
 
   internal::ToVarConverter<int32_t> socket_id_var(socket_id);
 
-  return get_interface<PPB_Ext_Socket_Dev_0_1>()->GetInfo(
+  return get_interface<PPB_Ext_Socket_Dev_0_2>()->GetInfo(
       instance_.pp_instance(),
       socket_id_var.pp_var(),
       callback.output(),
@@ -556,15 +556,99 @@
 }
 
 int32_t Socket_Dev::GetNetworkList(const GetNetworkListCallback& callback) {
-  if (!has_interface<PPB_Ext_Socket_Dev_0_1>())
+  if (!has_interface<PPB_Ext_Socket_Dev_0_2>())
     return callback.MayForce(PP_ERROR_NOINTERFACE);
 
-  return get_interface<PPB_Ext_Socket_Dev_0_1>()->GetNetworkList(
+  return get_interface<PPB_Ext_Socket_Dev_0_2>()->GetNetworkList(
       instance_.pp_instance(),
       callback.output(),
       callback.pp_completion_callback());
 }
 
+int32_t Socket_Dev::JoinGroup(int32_t socket_id,
+                              const std::string& address,
+                              const JoinGroupCallback& callback) {
+  if (!has_interface<PPB_Ext_Socket_Dev_0_2>())
+    return callback.MayForce(PP_ERROR_NOINTERFACE);
+
+  internal::ToVarConverter<int32_t> socket_id_var(socket_id);
+  internal::ToVarConverter<std::string> address_var(address);
+
+  return get_interface<PPB_Ext_Socket_Dev_0_2>()->JoinGroup(
+      instance_.pp_instance(),
+      socket_id_var.pp_var(),
+      address_var.pp_var(),
+      callback.output(),
+      callback.pp_completion_callback());
+}
+
+int32_t Socket_Dev::LeaveGroup(int32_t socket_id,
+                               const std::string& address,
+                               const LeaveGroupCallback& callback) {
+  if (!has_interface<PPB_Ext_Socket_Dev_0_2>())
+    return callback.MayForce(PP_ERROR_NOINTERFACE);
+
+  internal::ToVarConverter<int32_t> socket_id_var(socket_id);
+  internal::ToVarConverter<std::string> address_var(address);
+
+  return get_interface<PPB_Ext_Socket_Dev_0_2>()->LeaveGroup(
+      instance_.pp_instance(),
+      socket_id_var.pp_var(),
+      address_var.pp_var(),
+      callback.output(),
+      callback.pp_completion_callback());
+}
+
+int32_t Socket_Dev::SetMulticastTimeToLive(
+    int32_t socket_id,
+    int32_t ttl,
+    const SetMulticastTimeToLiveCallback& callback) {
+  if (!has_interface<PPB_Ext_Socket_Dev_0_2>())
+    return callback.MayForce(PP_ERROR_NOINTERFACE);
+
+  internal::ToVarConverter<int32_t> socket_id_var(socket_id);
+  internal::ToVarConverter<int32_t> ttl_var(ttl);
+
+  return get_interface<PPB_Ext_Socket_Dev_0_2>()->SetMulticastTimeToLive(
+      instance_.pp_instance(),
+      socket_id_var.pp_var(),
+      ttl_var.pp_var(),
+      callback.output(),
+      callback.pp_completion_callback());
+}
+
+int32_t Socket_Dev::SetMulticastLoopbackMode(
+    int32_t socket_id,
+    bool enabled,
+    const SetMulticastLoopbackModeCallback& callback) {
+  if (!has_interface<PPB_Ext_Socket_Dev_0_2>())
+    return callback.MayForce(PP_ERROR_NOINTERFACE);
+
+  internal::ToVarConverter<int32_t> socket_id_var(socket_id);
+  internal::ToVarConverter<bool> enabled_var(enabled);
+
+  return get_interface<PPB_Ext_Socket_Dev_0_2>()->SetMulticastLoopbackMode(
+      instance_.pp_instance(),
+      socket_id_var.pp_var(),
+      enabled_var.pp_var(),
+      callback.output(),
+      callback.pp_completion_callback());
+}
+
+int32_t Socket_Dev::GetJoinedGroups(int32_t socket_id,
+                                    const GetJoinedGroupsCallback& callback) {
+  if (!has_interface<PPB_Ext_Socket_Dev_0_2>())
+    return callback.MayForce(PP_ERROR_NOINTERFACE);
+
+  internal::ToVarConverter<int32_t> socket_id_var(socket_id);
+
+  return get_interface<PPB_Ext_Socket_Dev_0_2>()->GetJoinedGroups(
+      instance_.pp_instance(),
+      socket_id_var.pp_var(),
+      callback.output(),
+      callback.pp_completion_callback());
+}
+
 }  // namespace socket
 }  // namespace ext
 }  // namespace pp
diff --git a/ppapi/cpp/extensions/dev/socket_dev.h b/ppapi/cpp/extensions/dev/socket_dev.h
index c51b6cc..95e78d3 100644
--- a/ppapi/cpp/extensions/dev/socket_dev.h
+++ b/ppapi/cpp/extensions/dev/socket_dev.h
@@ -250,6 +250,35 @@
       GetNetworkListCallback;
   int32_t GetNetworkList(const GetNetworkListCallback& callback);
 
+  typedef ExtCompletionCallbackWithOutput<int32_t> JoinGroupCallback;
+  int32_t JoinGroup(int32_t socket_id,
+                    const std::string& address,
+                    const JoinGroupCallback& callback);
+
+  typedef ExtCompletionCallbackWithOutput<int32_t> LeaveGroupCallback;
+  int32_t LeaveGroup(int32_t socket_id,
+                     const std::string& address,
+                     const LeaveGroupCallback& callback);
+
+  typedef ExtCompletionCallbackWithOutput<int32_t>
+      SetMulticastTimeToLiveCallback;
+  int32_t SetMulticastTimeToLive(
+      int32_t socket_id,
+      int32_t ttl,
+      const SetMulticastTimeToLiveCallback& callback);
+
+  typedef ExtCompletionCallbackWithOutput<int32_t>
+      SetMulticastLoopbackModeCallback;
+  int32_t SetMulticastLoopbackMode(
+      int32_t socket_id,
+      bool enabled,
+      const SetMulticastLoopbackModeCallback& callback);
+
+  typedef ExtCompletionCallbackWithOutput<std::vector<std::string> >
+      GetJoinedGroupsCallback;
+  int32_t GetJoinedGroups(int32_t socket_id,
+                          const GetJoinedGroupsCallback& callback);
+
  private:
   InstanceHandle instance_;
 };
diff --git a/ppapi/cpp/file_ref.h b/ppapi/cpp/file_ref.h
index 8b008ac..d229c5f 100644
--- a/ppapi/cpp/file_ref.h
+++ b/ppapi/cpp/file_ref.h
@@ -96,7 +96,9 @@
   /// completion of MakeDirectory().
   ///
   /// @return An int32_t containing an error code from <code>pp_errors.h</code>.
-  /// Fails if the directory already exists.
+  /// Succeeds if the directory already exists. Fails if ancestor
+  /// directortories do not exist (see MakeDirectoryIncludingAncestors for the
+  /// alternative).
   int32_t MakeDirectory(const CompletionCallback& cc);
 
   /// MakeDirectoryIncludingAncestors() makes a new directory in the file
@@ -107,7 +109,7 @@
   /// completion of MakeDirectoryIncludingAncestors().
   ///
   /// @return An int32_t containing an error code from <code>pp_errors.h</code>.
-  /// Fails if the directory already exists.
+  /// Succeeds if the directory already exists.
   int32_t MakeDirectoryIncludingAncestors(const CompletionCallback& cc);
 
   /// Touch() Updates time stamps for a file.  You must have write access to the
diff --git a/ppapi/cpp/private/flash_drm.cc b/ppapi/cpp/private/flash_drm.cc
new file mode 100644
index 0000000..7307445
--- /dev/null
+++ b/ppapi/cpp/private/flash_drm.cc
@@ -0,0 +1,58 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ppapi/cpp/private/flash_drm.h"
+
+#include "ppapi/c/pp_errors.h"
+#include "ppapi/c/private/ppb_flash_device_id.h"
+#include "ppapi/c/private/ppb_flash_drm.h"
+#include "ppapi/cpp/module_impl.h"
+
+namespace pp {
+
+namespace {
+
+template <> const char* interface_name<PPB_Flash_DRM_1_0>() {
+  return PPB_FLASH_DRM_INTERFACE_1_0;
+}
+
+template <> const char* interface_name<PPB_Flash_DeviceID_1_0>() {
+  return PPB_FLASH_DEVICEID_INTERFACE_1_0;
+}
+
+}  // namespace
+
+namespace flash {
+
+DRM::DRM() {
+}
+
+DRM::DRM(const InstanceHandle& instance) : Resource() {
+  if (has_interface<PPB_Flash_DRM_1_0>()) {
+    PassRefFromConstructor(get_interface<PPB_Flash_DRM_1_0>()->Create(
+        instance.pp_instance()));
+  } else if (has_interface<PPB_Flash_DeviceID_1_0>()) {
+    PassRefFromConstructor(get_interface<PPB_Flash_DeviceID_1_0>()->Create(
+        instance.pp_instance()));
+  }
+}
+
+int32_t DRM::GetDeviceID(const CompletionCallbackWithOutput<Var>& callback) {
+  if (has_interface<PPB_Flash_DRM_1_0>()) {
+    return get_interface<PPB_Flash_DRM_1_0>()->GetDeviceID(
+        pp_resource(),
+        callback.output(),
+        callback.pp_completion_callback());
+  }
+  if (has_interface<PPB_Flash_DeviceID_1_0>()) {
+    return get_interface<PPB_Flash_DeviceID_1_0>()->GetDeviceID(
+        pp_resource(),
+        callback.output(),
+        callback.pp_completion_callback());
+  }
+  return callback.MayForce(PP_ERROR_NOINTERFACE);
+}
+
+}  // namespace flash
+}  // namespace pp
diff --git a/ppapi/cpp/private/flash_drm.h b/ppapi/cpp/private/flash_drm.h
new file mode 100644
index 0000000..49e37c2
--- /dev/null
+++ b/ppapi/cpp/private/flash_drm.h
@@ -0,0 +1,26 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef PPAPI_CPP_PRIVATE_FLASH_DRM_H_
+#define PPAPI_CPP_PRIVATE_FLASH_DRM_H_
+
+#include "ppapi/cpp/completion_callback.h"
+#include "ppapi/cpp/resource.h"
+
+namespace pp {
+namespace flash {
+
+class DRM : public Resource {
+ public:
+  DRM();
+  explicit DRM(const InstanceHandle& instance);
+
+  // On success, returns a string var.
+  int32_t GetDeviceID(const CompletionCallbackWithOutput<Var>& callback);
+};
+
+}  // namespace flash
+}  // namespace pp
+
+#endif  // PPAPI_CPP_PRIVATE_FLASH_DRM_H_
diff --git a/ppapi/cpp/private/tcp_server_socket_private.cc b/ppapi/cpp/private/tcp_server_socket_private.cc
index 5f315bf..50adcc1 100644
--- a/ppapi/cpp/private/tcp_server_socket_private.cc
+++ b/ppapi/cpp/private/tcp_server_socket_private.cc
@@ -14,46 +14,78 @@
 
 namespace {
 
-template <> const char* interface_name<PPB_TCPServerSocket_Private>() {
-  return PPB_TCPSERVERSOCKET_PRIVATE_INTERFACE;
+template <> const char* interface_name<PPB_TCPServerSocket_Private_0_2>() {
+  return PPB_TCPSERVERSOCKET_PRIVATE_INTERFACE_0_2;
+}
+
+template <> const char* interface_name<PPB_TCPServerSocket_Private_0_1>() {
+  return PPB_TCPSERVERSOCKET_PRIVATE_INTERFACE_0_1;
 }
 
 }  // namespace
 
 TCPServerSocketPrivate::TCPServerSocketPrivate(const InstanceHandle& instance) {
-  if (has_interface<PPB_TCPServerSocket_Private>()) {
-    PassRefFromConstructor(get_interface<PPB_TCPServerSocket_Private>()->Create(
-        instance.pp_instance()));
+  if (has_interface<PPB_TCPServerSocket_Private_0_2>()) {
+    PassRefFromConstructor(
+        get_interface<PPB_TCPServerSocket_Private_0_2>()->Create(
+            instance.pp_instance()));
+  } else if (has_interface<PPB_TCPServerSocket_Private_0_1>()) {
+    PassRefFromConstructor(
+        get_interface<PPB_TCPServerSocket_Private_0_1>()->Create(
+            instance.pp_instance()));
   }
 }
 
 // static
 bool TCPServerSocketPrivate::IsAvailable() {
-  return has_interface<PPB_TCPServerSocket_Private>();
+  return has_interface<PPB_TCPServerSocket_Private_0_2>() ||
+      has_interface<PPB_TCPServerSocket_Private_0_1>();
 }
 
 int32_t TCPServerSocketPrivate::Listen(const PP_NetAddress_Private* addr,
                                        int32_t backlog,
                                        const CompletionCallback& callback) {
-  if (!has_interface<PPB_TCPServerSocket_Private>())
-    return callback.MayForce(PP_ERROR_NOINTERFACE);
-  return get_interface<PPB_TCPServerSocket_Private>()->Listen(
-      pp_resource(), addr, backlog, callback.pp_completion_callback());
+  if (has_interface<PPB_TCPServerSocket_Private_0_2>()) {
+    return get_interface<PPB_TCPServerSocket_Private_0_2>()->Listen(
+        pp_resource(), addr, backlog, callback.pp_completion_callback());
+  }
+  if (has_interface<PPB_TCPServerSocket_Private_0_1>()) {
+    return get_interface<PPB_TCPServerSocket_Private_0_1>()->Listen(
+        pp_resource(), addr, backlog, callback.pp_completion_callback());
+  }
+  return callback.MayForce(PP_ERROR_NOINTERFACE);
 }
 
 int32_t TCPServerSocketPrivate::Accept(PP_Resource* tcp_socket,
                                        const CompletionCallback& callback) {
-  if (!has_interface<PPB_TCPServerSocket_Private>())
-    return callback.MayForce(PP_ERROR_NOINTERFACE);
-  return get_interface<PPB_TCPServerSocket_Private>()->Accept(
-      pp_resource(), tcp_socket, callback.pp_completion_callback());
+  if (has_interface<PPB_TCPServerSocket_Private_0_2>()) {
+    return get_interface<PPB_TCPServerSocket_Private_0_2>()->Accept(
+        pp_resource(), tcp_socket, callback.pp_completion_callback());
+  }
+  if (has_interface<PPB_TCPServerSocket_Private_0_1>()) {
+    return get_interface<PPB_TCPServerSocket_Private_0_1>()->Accept(
+        pp_resource(), tcp_socket, callback.pp_completion_callback());
+  }
+  return callback.MayForce(PP_ERROR_NOINTERFACE);
+}
+
+int32_t TCPServerSocketPrivate::GetLocalAddress(PP_NetAddress_Private* addr) {
+  if (has_interface<PPB_TCPServerSocket_Private_0_2>()) {
+    return get_interface<PPB_TCPServerSocket_Private_0_2>()->GetLocalAddress(
+        pp_resource(), addr);
+  }
+  return PP_ERROR_NOINTERFACE;
 }
 
 void TCPServerSocketPrivate::StopListening() {
-  if (!has_interface<PPB_TCPServerSocket_Private>())
-    return;
-  return get_interface<PPB_TCPServerSocket_Private>()->StopListening(
-      pp_resource());
+  if (has_interface<PPB_TCPServerSocket_Private_0_2>()) {
+    return get_interface<PPB_TCPServerSocket_Private_0_2>()->StopListening(
+        pp_resource());
+  }
+  if (has_interface<PPB_TCPServerSocket_Private_0_1>()) {
+    return get_interface<PPB_TCPServerSocket_Private_0_1>()->StopListening(
+        pp_resource());
+  }
 }
 
 }  // namespace pp
diff --git a/ppapi/cpp/private/tcp_server_socket_private.h b/ppapi/cpp/private/tcp_server_socket_private.h
index 3d40cea..d6a1942 100644
--- a/ppapi/cpp/private/tcp_server_socket_private.h
+++ b/ppapi/cpp/private/tcp_server_socket_private.h
@@ -30,6 +30,7 @@
   // |callback| is called or StopListening method is called.
   int32_t Accept(PP_Resource* socket,
                  const CompletionCallback& callback);
+  int32_t GetLocalAddress(PP_NetAddress_Private* addr);
   void StopListening();
 };
 
diff --git a/ppapi/examples/video_effects/video_effects.cc b/ppapi/examples/video_effects/video_effects.cc
new file mode 100644
index 0000000..101ba9c
--- /dev/null
+++ b/ppapi/examples/video_effects/video_effects.cc
@@ -0,0 +1,179 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <string.h>
+#include <iterator>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include "ppapi/c/pp_errors.h"
+#include "ppapi/cpp/instance.h"
+#include "ppapi/cpp/message_loop.h"
+#include "ppapi/cpp/module.h"
+#include "ppapi/cpp/private/video_destination_private.h"
+#include "ppapi/cpp/private/video_frame_private.h"
+#include "ppapi/cpp/private/video_source_private.h"
+#include "ppapi/cpp/var.h"
+#include "ppapi/utility/completion_callback_factory.h"
+
+// When compiling natively on Windows, PostMessage can be #define-d to
+// something else.
+#ifdef PostMessage
+#undef PostMessage
+#endif
+
+namespace {
+
+// Helper functions
+std::vector<std::string> SplitStringBySpace(const std::string& str) {
+  std::istringstream buf(str);
+  std::istream_iterator<std::string> begin(buf), end;
+  std::vector<std::string> tokens(begin, end);
+  return tokens;
+}
+
+// This object is the global object representing this plugin library as long
+// as it is loaded.
+class VEDemoModule : public pp::Module {
+ public:
+  VEDemoModule() : pp::Module() {}
+  virtual ~VEDemoModule() {}
+
+  virtual pp::Instance* CreateInstance(PP_Instance instance);
+};
+
+class VEDemoInstance : public pp::Instance {
+ public:
+  VEDemoInstance(PP_Instance instance, pp::Module* module);
+  virtual ~VEDemoInstance();
+
+  // pp::Instance implementation (see PPP_Instance).
+  virtual void HandleMessage(const pp::Var& message_data);
+
+ private:
+  void DestinationOpenDone(int32_t result, const std::string& src_url);
+  void SourceOpenDone(int32_t result);
+  void GetFrameDone(int32_t result, pp::VideoFrame_Private video_frame);
+  void KickoffEffect(int32_t result);
+  pp::VideoSource_Private video_source_;
+  pp::VideoDestination_Private video_destination_;
+  bool effect_on_;
+  pp::CompletionCallbackFactory<VEDemoInstance> factory_;
+  pp::MessageLoop message_loop_;
+};
+
+VEDemoInstance::VEDemoInstance(PP_Instance instance, pp::Module* module)
+    : pp::Instance(instance),
+      video_source_(this),
+      video_destination_(this),
+      effect_on_(false),
+      message_loop_(pp::MessageLoop::GetCurrent()) {
+  factory_.Initialize(this);
+}
+
+VEDemoInstance::~VEDemoInstance() {
+  video_source_.Close();
+  video_destination_.Close();
+}
+
+void VEDemoInstance::HandleMessage(const pp::Var& message_data) {
+  if (message_data.is_string()) {
+    std::vector<std::string> messages;
+    messages = SplitStringBySpace(message_data.AsString());
+    if (messages.empty()) {
+      PostMessage(pp::Var("Ignored empty message."));
+      return;
+    }
+    if (messages[0] == "registerStream") {
+      if (messages.size() < 3) {
+        PostMessage(pp::Var("Got 'registerStream' with incorrect parameters."));
+        return;
+      }
+      // Open destination stream for write.
+      video_destination_.Open(
+          messages[2],
+          factory_.NewCallback(&VEDemoInstance::DestinationOpenDone,
+                               messages[1]));
+    } else if (messages[0] == "effectOn") {
+      effect_on_ = true;
+      PostMessage(pp::Var("Effect ON."));
+    } else if (messages[0] == "effectOff") {
+      effect_on_ = false;
+      PostMessage(pp::Var("Effect OFF."));
+    }
+  }
+}
+
+void VEDemoInstance::DestinationOpenDone(int32_t result,
+                                         const std::string& src_url) {
+  if (result != PP_OK) {
+    PostMessage(pp::Var("Failed to open destination stream."));
+    return;
+  }
+  // Open source stream for read.
+  video_source_.Open(src_url,
+                     factory_.NewCallback(&VEDemoInstance::SourceOpenDone));
+}
+
+void VEDemoInstance::SourceOpenDone(int32_t result) {
+  if (result != PP_OK) {
+    PostMessage(pp::Var("Failed to open source stream."));
+    return;
+  }
+  // Done with the stream register.
+  PostMessage(pp::Var("DoneRegistering"));
+
+  // Kick off the processing loop.
+  message_loop_.PostWork(factory_.NewCallback(&VEDemoInstance::KickoffEffect));
+}
+
+void VEDemoInstance::GetFrameDone(int32_t result,
+                                  pp::VideoFrame_Private video_frame) {
+  if (result != PP_OK) {
+    PostMessage(pp::Var("Failed to get frame."));
+    return;
+  }
+
+  // Apply the effect to the received frame.
+  if (effect_on_) {
+    pp::ImageData image_data = video_frame.image_data();
+    pp::Size size = image_data.size();
+    std::vector<uint8_t> tmp_row(image_data.stride());
+    uint8_t* image = static_cast<uint8_t*>(image_data.data());
+    for (int i = 0; i < size.height() / 2; ++i) {
+      uint8_t* top = image + i * image_data.stride();
+      uint8_t* bottom = image + (size.height() - 1 - i) * image_data.stride();
+      memcpy(&tmp_row[0], top, image_data.stride());
+      memcpy(top, bottom, image_data.stride());
+      memcpy(bottom, &tmp_row[0], image_data.stride());
+    }
+  }
+
+  // Put frame back to destination stream
+  video_destination_.PutFrame(video_frame);
+
+  // Trigger for the next frame.
+  message_loop_.PostWork(factory_.NewCallback(&VEDemoInstance::KickoffEffect));
+}
+
+void VEDemoInstance::KickoffEffect(int32_t /* result */) {
+  // Get the frame from the source stream.
+  video_source_.GetFrame(
+      factory_.NewCallbackWithOutput<pp::VideoFrame_Private>(
+          &VEDemoInstance::GetFrameDone));
+}
+
+pp::Instance* VEDemoModule::CreateInstance(PP_Instance instance) {
+  return new VEDemoInstance(instance, this);
+}
+
+}  // anonymous namespace
+
+namespace pp {
+// Factory function for your specialization of the Module object.
+Module* CreateModule() {
+  return new VEDemoModule();
+}
+}  // namespace pp
diff --git a/ppapi/examples/video_effects/video_effects.html b/ppapi/examples/video_effects/video_effects.html
new file mode 100644
index 0000000..82d813f
--- /dev/null
+++ b/ppapi/examples/video_effects/video_effects.html
@@ -0,0 +1,208 @@
+<!DOCTYPE html>
+<html>
+  <!--
+  Copyright (c) 2013 The Chromium Authors. All rights reserved.
+  Use of this source code is governed by a BSD-style license that can be
+  found in the LICENSE file.
+  -->
+<head>
+<title>Video Effects Demo</title>
+<style>
+video {
+  border:5px solid black;
+  width:480px;
+  height:360px;
+}
+button {
+  font: 18px sans-serif;
+  padding: 8px;
+}
+textarea {
+  font-family: monospace;
+  margin: 2px;
+  width:480px;
+  height:640px;
+}
+</style>
+</head>
+<body>
+<table>
+<tr>
+<td><video id="vidlocal" autoplay></video></td>
+<td><video id="vidprocessedlocal" autoplay></video></td>
+<td><video id="vidremote" autoplay></video></td>
+</tr>
+<tr>
+<td>Local Media Stream</td>
+<td>Local Media Stream After Effect</td>
+<td>Remote Media Stream</td>
+</tr>
+<tr>
+</table>
+<br>
+<button id="startButton" onclick="start()">Start</button>
+<button id="toggleEffectButton" onclick="toggleEffect()">Enable Effect</button>
+<button id="callButton" onclick="call()">Call</button>
+<button id="hangupButton" onclick="hangup()">Hang Up</button>
+<br>
+<embed id="plugin" type="application/x-ppapi-example-video-effects"
+    width="320" height="240"/>
+
+<script>
+var RTCPeerConnection = webkitRTCPeerConnection;
+var getUserMedia = navigator.webkitGetUserMedia.bind(navigator);
+var attachMediaStream = function(element, stream) {
+  element.src = webkitURL.createObjectURL(stream);
+};
+var startButton = document.getElementById('startButton');
+var toggleEffectButton = document.getElementById('toggleEffectButton');
+var callButton = document.getElementById('callButton');
+var hangupButton = document.getElementById('hangupButton');
+
+callButton.disabled = true;
+hangupButton.disabled = true;
+toggleEffectButton.disabled = true;
+var pc1 = null;
+var pc2 = null;
+var localstream = null;
+var processedLocalstream = null;
+var effectsPlugin = null;
+var effectsEnabled = false;
+
+function trace(text) {
+  // This function is used for logging.
+  if (text[text.length - 1] == '\n') {
+    text = text.substring(0, text.length - 1);
+  }
+  console.log((performance.now() / 1000).toFixed(3) + ": " + text);
+}
+
+function gotStream(stream){
+  trace("Received local stream");
+  // Call the polyfill wrapper to attach the media stream to this element.
+  attachMediaStream(vidlocal, stream);
+  localstream = stream;
+  callButton.disabled = false;
+  initEffect();
+}
+
+function start() {
+  trace("Requesting local stream");
+  startButton.disabled = true;
+  // Call into getUserMedia via the polyfill (adapter.js).
+  getUserMedia({audio:false, video:true},
+                gotStream, function() {});
+}  
+
+function onRegisterStreamDone() {
+  vidprocessedlocal.src = webkitURL.createObjectURL(processedLocalstream);
+  toggleEffectButton.disabled = false;
+}
+
+function HandleMessage(message_event) {
+  if (message_event.data) {
+    if (message_event.data == 'DoneRegistering') {
+      onRegisterStreamDone();
+    } else {
+      trace(message_event.data);
+    }
+  }
+}
+
+function initEffect() {
+  var url = webkitURL.createObjectURL(localstream);
+  processedLocalstream = new webkitMediaStream([]);
+  var processedStreamUrl = webkitURL.createObjectURL(processedLocalstream);
+  effectsPlugin.postMessage(
+      'registerStream' + ' ' + url + ' ' + processedStreamUrl);
+}
+
+function toggleEffect() {
+  effectsEnabled = !effectsEnabled;
+  if (effectsEnabled) {
+    toggleEffectButton.innerHTML = 'Disable Effect';
+    effectsPlugin.postMessage('effectOn');
+  } else {
+    toggleEffectButton.innerHTML = 'Enable Effect';
+    effectsPlugin.postMessage('effectOff');
+  }
+}
+    
+function call() {
+  callButton.disabled = true;
+  hangupButton.disabled = false;
+  trace("Starting call");
+  var servers = null;
+  pc1 = new RTCPeerConnection(servers);
+  trace("Created local peer connection object pc1");
+  pc1.onicecandidate = iceCallback1; 
+  pc2 = new RTCPeerConnection(servers);
+  trace("Created remote peer connection object pc2");
+  pc2.onicecandidate = iceCallback2;
+  pc2.onaddstream = gotRemoteStream; 
+
+  pc1.addStream(processedLocalstream);
+  trace("Adding Local Stream to peer connection");
+  
+  pc1.createOffer(gotDescription1);
+}
+
+function gotDescription1(desc){
+  pc1.setLocalDescription(desc);
+  trace("Offer from pc1 \n" + desc.sdp);
+  pc2.setRemoteDescription(desc);
+  // Since the "remote" side has no media stream we need
+  // to pass in the right constraints in order for it to
+  // accept the incoming offer of audio and video.
+  var sdpConstraints = {'mandatory': {
+                        'OfferToReceiveAudio':true, 
+                        'OfferToReceiveVideo':true }};
+  pc2.createAnswer(gotDescription2, null, sdpConstraints);
+}
+
+function gotDescription2(desc){
+  pc2.setLocalDescription(desc);
+  trace("Answer from pc2 \n" + desc.sdp);
+  pc1.setRemoteDescription(desc);
+}
+
+function hangup() {
+  trace("Ending call");
+  pc1.close(); 
+  pc2.close();
+  pc1 = null;
+  pc2 = null;
+  hangupButton.disabled = true;
+  callButton.disabled = false;
+}
+
+function gotRemoteStream(e){
+  vidremote.src = webkitURL.createObjectURL(e.stream);
+  trace("Received remote stream");
+}
+
+function iceCallback1(event){
+  if (event.candidate) {
+    pc2.addIceCandidate(new RTCIceCandidate(event.candidate));
+    trace("Local ICE candidate: \n" + event.candidate.candidate);
+  }
+}
+      
+function iceCallback2(event){
+  if (event.candidate) {
+    pc1.addIceCandidate(new RTCIceCandidate(event.candidate));
+    trace("Remote ICE candidate: \n " + event.candidate.candidate);
+  }
+}
+
+function InitializePlugin() {
+  effectsPlugin = document.getElementById('plugin');
+  effectsPlugin.addEventListener('message', HandleMessage, false);
+}
+
+document.addEventListener('DOMContentLoaded', InitializePlugin, false);
+</script>
+</body>
+</html>
+
+
diff --git a/ppapi/generators/idl_c_header.py b/ppapi/generators/idl_c_header.py
index 4ad27ba..ee2f256 100755
--- a/ppapi/generators/idl_c_header.py
+++ b/ppapi/generators/idl_c_header.py
@@ -167,12 +167,40 @@
                           'See http://crbug.com/233439' %
                           (t.GetName(), node.GetName()))
 
+
+def CheckPassByValue(filenode, releases):
+  """Checks that new pass-by-value structs are not introduced.
+
+  See http://crbug.com/233439 for details.
+  """
+  cgen = CGen()
+  # DO NOT add any more entries to this whitelist.
+  # http://crbug.com/233439
+  type_whitelist = ['PP_ArrayOutput', 'PP_CompletionCallback',
+                    'PP_Ext_EventListener', 'PP_FloatPoint',
+                    'PP_Graphics3DTrustedState', 'PP_Point', 'PP_TouchPoint',
+                    'PP_Var']
+  nodes_to_check = filenode.GetListOf('Struct')
+  nodes_to_check.extend(filenode.GetListOf('Union'))
+  for node in nodes_to_check:
+    if node.GetName() in type_whitelist:
+      continue
+    build_list = node.GetUniqueReleases(releases)
+    if node.GetProperty('passByValue'):
+      raise Exception('%s is a new passByValue struct or union. '
+                      'See http://crbug.com/233439' % node.GetName())
+    if node.GetProperty('returnByValue'):
+      raise Exception('%s is a new returnByValue struct or union. '
+                      'See http://crbug.com/233439' % node.GetName())
+
+
 class HGen(GeneratorByFile):
   def __init__(self):
     Generator.__init__(self, 'C Header', 'cgen', 'Generate the C headers.')
 
   def GenerateFile(self, filenode, releases, options):
     CheckTypedefs(filenode, releases)
+    CheckPassByValue(filenode, releases)
     savename = GetHeaderFromNode(filenode, GetOption('dstroot'))
     my_min, my_max = filenode.GetMinMax(releases)
     if my_min > releases[-1] or my_max < releases[0]:
diff --git a/ppapi/generators/idl_outfile.py b/ppapi/generators/idl_outfile.py
index 538267f..61b678c 100755
--- a/ppapi/generators/idl_outfile.py
+++ b/ppapi/generators/idl_outfile.py
@@ -95,6 +95,7 @@
     filename = os.path.realpath(self.filename)
     self.open = False
     outtext = ''.join(self.outlist)
+    oldtext = ''
 
     if not self.always_write:
       if os.path.isfile(filename):
diff --git a/ppapi/generators/idl_thunk.py b/ppapi/generators/idl_thunk.py
index 9121cb0..1bb0de0 100755
--- a/ppapi/generators/idl_thunk.py
+++ b/ppapi/generators/idl_thunk.py
@@ -536,10 +536,11 @@
         for child in members:
           rtype, name, arrays, args = cgen.GetComponents(
               child, build, 'return')
-          if not _IsNewestMember(child, members, releases):
-            version = node.GetVersion(build).replace('.', '_')
-            name += '_' + version
           if child.InReleases([build]):
+            if not _IsNewestMember(child, members, releases):
+              version = child.GetVersion(
+                  child.first_release[build]).replace('.', '_')
+              name += '_' + version
             generated_functions.append(name)
         out.Write(',\n'.join(['  &%s' % f for f in generated_functions]))
         out.Write('\n};\n\n')
@@ -574,11 +575,11 @@
   idldir = os.path.join(idldir, 'test_thunk', '*.idl')
   filenames = glob.glob(idldir)
   ast = ParseFiles(filenames)
-  if tgen.GenerateRange(ast, ['M13', 'M14'], {}):
-    print "Golden file for M13-M14 failed."
+  if tgen.GenerateRange(ast, ['M13', 'M14', 'M15'], {}):
+    print "Golden file for M13-M15 failed."
     failed = 1
   else:
-    print "Golden file for M13-M14 passed."
+    print "Golden file for M13-M15 passed."
 
   return failed
 
diff --git a/ppapi/generators/test_thunk/simple.idl b/ppapi/generators/test_thunk/simple.idl
index 30beace..c4ce7b9 100644
--- a/ppapi/generators/test_thunk/simple.idl
+++ b/ppapi/generators/test_thunk/simple.idl
@@ -11,7 +11,8 @@
 
 label Chrome {
   M13 = 0.5,
-  M14 = 1.0
+  M14 = 1.0,
+  M15 = 1.5
 };
 
 interface PPB_Simple {
@@ -24,6 +25,10 @@
 
   uint32_t DoUint32Instance([in] PP_Instance instance);
 
+  [version=1.5]
+  uint32_t DoUint32Instance([in] PP_Instance instance,
+                            [in] PP_Resource resource);
+
   uint32_t DoUint32Resource([in] PP_Resource instance);
 
   [report_errors=False]
diff --git a/ppapi/generators/test_thunk/simple_thunk.cc b/ppapi/generators/test_thunk/simple_thunk.cc
index e6418f0..8fc2ba2 100644
--- a/ppapi/generators/test_thunk/simple_thunk.cc
+++ b/ppapi/generators/test_thunk/simple_thunk.cc
@@ -19,6 +19,7 @@
 namespace {
 
 PP_Resource Create(PP_Instance instance) {
+  VLOG(4) << "PPB_Simple::Create()";
   EnterResourceCreation enter(instance);
   if (enter.failed())
     return 0;
@@ -26,24 +27,37 @@
 }
 
 PP_Bool IsSimple(PP_Resource resource) {
+  VLOG(4) << "PPB_Simple::IsSimple()";
   EnterResource<PPB_Simple_API> enter(resource, false);
   return PP_FromBool(enter.succeeded());
 }
 
 void PostMessage(PP_Instance instance, PP_Var message) {
+  VLOG(4) << "PPB_Simple::PostMessage()";
   EnterInstance enter(instance);
-  if (enter.succeeded())
-    enter.functions()->PostMessage(instance, message);
+  if (enter.failed())
+    return;
+  enter.functions()->PostMessage(instance, message);
 }
 
-uint32_t DoUint32Instance(PP_Instance instance) {
+uint32_t DoUint32Instance_0_5(PP_Instance instance) {
+  VLOG(4) << "PPB_Simple::DoUint32Instance()";
   EnterInstance enter(instance);
   if (enter.failed())
     return 0;
-  return enter.functions()->DoUint32Instance(instance);
+  return enter.functions()->DoUint32Instance0_5(instance);
+}
+
+uint32_t DoUint32Instance(PP_Instance instance, PP_Resource resource) {
+  VLOG(4) << "PPB_Simple::DoUint32Instance()";
+  EnterInstance enter(instance);
+  if (enter.failed())
+    return 0;
+  return enter.functions()->DoUint32Instance(instance, resource);
 }
 
 uint32_t DoUint32Resource(PP_Resource instance) {
+  VLOG(4) << "PPB_Simple::DoUint32Resource()";
   EnterResource<PPB_Simple_API> enter(instance, true);
   if (enter.failed())
     return 0;
@@ -51,6 +65,7 @@
 }
 
 uint32_t DoUint32ResourceNoErrors(PP_Resource instance) {
+  VLOG(4) << "PPB_Simple::DoUint32ResourceNoErrors()";
   EnterResource<PPB_Simple_API> enter(instance, false);
   if (enter.failed())
     return 0;
@@ -58,6 +73,7 @@
 }
 
 int32_t OnFailure12(PP_Instance instance) {
+  VLOG(4) << "PPB_Simple::OnFailure12()";
   EnterInstance enter(instance);
   if (enter.failed())
     return 12;
@@ -68,18 +84,27 @@
   &Create,
   &IsSimple,
   &PostMessage,
-  &DoUint32Instance,
+  &DoUint32Instance_0_5,
   &DoUint32Resource,
-  &DoUint32ResourceNoErrors,
+  &DoUint32ResourceNoErrors
 };
 
 const PPB_Simple_1_0 g_ppb_simple_thunk_1_0 = {
   &Create,
   &IsSimple,
+  &DoUint32Instance_0_5,
+  &DoUint32Resource,
+  &DoUint32ResourceNoErrors,
+  &OnFailure12
+};
+
+const PPB_Simple_1_5 g_ppb_simple_thunk_1_5 = {
+  &Create,
+  &IsSimple,
   &DoUint32Instance,
   &DoUint32Resource,
   &DoUint32ResourceNoErrors,
-  &OnFailure12,
+  &OnFailure12
 };
 
 }  // namespace
@@ -92,5 +117,9 @@
   return &g_ppb_simple_thunk_1_0;
 }
 
+const PPB_Simple_1_5* GetPPB_Simple_1_5_Thunk() {
+  return &g_ppb_simple_thunk_1_5;
+}
+
 }  // namespace thunk
 }  // namespace ppapi
diff --git a/ppapi/lib/gl/include/GLES2/gl2ext.h b/ppapi/lib/gl/include/GLES2/gl2ext.h
index 8effd30..ce2cbf0 100644
--- a/ppapi/lib/gl/include/GLES2/gl2ext.h
+++ b/ppapi/lib/gl/include/GLES2/gl2ext.h
@@ -1748,7 +1748,8 @@
 #ifdef GL_GLEXT_PROTOTYPES
 #define glResizeCHROMIUM GLES2_GET_FUN(ResizeCHROMIUM)
 #if !defined(GLES2_USE_CPP_BINDINGS)
-GL_APICALL void GL_APIENTRY glResizeCHROMIUM (GLuint width, GLuint height);
+GL_APICALL void GL_APIENTRY glResizeCHROMIUM (
+    GLuint width, GLuint height, GLfloat scale_factor);
 #endif
 #else
 typedef void (GL_APIENTRYP PFNGLRESIZECHROMIUM) (GLuint width, GLuint height);
diff --git a/ppapi/native_client/src/trusted/plugin/file_downloader.cc b/ppapi/native_client/src/trusted/plugin/file_downloader.cc
index ce7fe30..1708124 100644
--- a/ppapi/native_client/src/trusted/plugin/file_downloader.cc
+++ b/ppapi/native_client/src/trusted/plugin/file_downloader.cc
@@ -5,6 +5,7 @@
 #include "native_client/src/trusted/plugin/file_downloader.h"
 
 #include <stdio.h>
+#include <string.h>
 #include <string>
 
 #include "native_client/src/include/portability_io.h"
@@ -21,8 +22,17 @@
 #include "ppapi/cpp/url_response_info.h"
 
 namespace {
+
 const int32_t kExtensionUrlRequestStatusOk = 200;
 const int32_t kDataUriRequestStatusOk = 0;
+
+struct NaClFileInfo NoFileInfo() {
+  struct NaClFileInfo info;
+  memset(&info, 0, sizeof(info));
+  info.desc = -1;
+  return info;
+}
+
 }
 
 namespace plugin {
@@ -145,7 +155,8 @@
 }
 
 void FileDownloader::OpenFast(const nacl::string& url,
-                              PP_FileHandle file_handle) {
+                              PP_FileHandle file_handle,
+                              uint64_t file_token_lo, uint64_t file_token_hi) {
   PLUGIN_PRINTF(("FileDownloader::OpenFast (url=%s)\n", url.c_str()));
   CHECK(instance_ != NULL);
   open_time_ = NaClGetTimeOfDayMicroseconds();
@@ -154,9 +165,12 @@
   url_ = url;
   mode_ = DOWNLOAD_NONE;
   file_handle_ = file_handle;
+  file_token_.lo = file_token_lo;
+  file_token_.hi = file_token_hi;
 }
 
-int32_t FileDownloader::GetPOSIXFileDescriptor() {
+struct NaClFileInfo FileDownloader::GetFileInfo() {
+  struct NaClFileInfo info = NoFileInfo();
   int32_t file_desc = NACL_NO_FILE_DESC;
   if (not_streaming() && file_handle_ != PP_kInvalidFileHandle) {
 #if NACL_WINDOWS
@@ -165,13 +179,14 @@
 #else
     file_desc = file_handle_;
 #endif
+    info.file_token = file_token_;
   } else {
     if (!streaming_to_file()) {
-      return NACL_NO_FILE_DESC;
+      return NoFileInfo();
     }
     // Use the trusted interface to get the file descriptor.
     if (file_io_trusted_interface_ == NULL) {
-      return NACL_NO_FILE_DESC;
+      return NoFileInfo();
     }
     file_desc = file_io_trusted_interface_->GetOSFileDescriptor(
         file_reader_.pp_resource());
@@ -183,12 +198,13 @@
   if (posix_desc == -1) {
     // Close the Windows HANDLE if it can't be converted.
     CloseHandle(reinterpret_cast<HANDLE>(file_desc));
-    return NACL_NO_FILE_DESC;
+    return NoFileInfo();
   }
   file_desc = posix_desc;
 #endif
 
-  return file_desc;
+  info.desc = file_desc;
+  return info;
 }
 
 int64_t FileDownloader::TimeSinceOpenMilliseconds() const {
diff --git a/ppapi/native_client/src/trusted/plugin/file_downloader.h b/ppapi/native_client/src/trusted/plugin/file_downloader.h
index a60c837..7d87930 100644
--- a/ppapi/native_client/src/trusted/plugin/file_downloader.h
+++ b/ppapi/native_client/src/trusted/plugin/file_downloader.h
@@ -10,6 +10,7 @@
 #include "native_client/src/include/nacl_macros.h"
 #include "native_client/src/include/nacl_string.h"
 #include "native_client/src/trusted/plugin/callback_source.h"
+#include "native_client/src/trusted/validator/nacl_file_info.h"
 #include "ppapi/c/private/pp_file_handle.h"
 #include "ppapi/c/trusted/ppb_file_io_trusted.h"
 #include "ppapi/c/trusted/ppb_url_loader_trusted.h"
@@ -85,14 +86,16 @@
                   StreamCallbackSource* stream_callback_source);
 
   // Bypasses downloading and takes a handle to the open file. To get the fd,
-  // call GetPOSIXFileDescriptor().
-  void OpenFast(const nacl::string& url, PP_FileHandle file_handle);
+  // call GetFileInfo().
+  void OpenFast(const nacl::string& url, PP_FileHandle file_handle,
+                uint64_t file_token_lo, uint64_t file_token_hi);
 
+  // Return a structure describing the file opened, including a file desc.
   // If downloading and opening succeeded, this returns a valid read-only
   // POSIX file descriptor.  On failure, the return value is an invalid
   // descriptor.  The file descriptor is owned by this instance, so the
   // delegate does not have to close it.
-  int32_t GetPOSIXFileDescriptor();
+  struct NaClFileInfo GetFileInfo();
 
   // Returns the time delta between the call to Open() and this function.
   int64_t TimeSinceOpenMilliseconds() const;
@@ -160,6 +163,7 @@
   pp::CompletionCallback file_open_notify_callback_;
   pp::FileIO file_reader_;
   PP_FileHandle file_handle_;
+  struct NaClFileToken file_token_;
   const PPB_FileIOTrusted* file_io_trusted_interface_;
   const PPB_URLLoaderTrusted* url_loader_trusted_interface_;
   pp::URLLoader url_loader_;
diff --git a/ppapi/native_client/src/trusted/plugin/file_utils.cc b/ppapi/native_client/src/trusted/plugin/file_utils.cc
new file mode 100644
index 0000000..50600a2
--- /dev/null
+++ b/ppapi/native_client/src/trusted/plugin/file_utils.cc
@@ -0,0 +1,77 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Some common file utilities for plugin code.
+
+#include "native_client/src/trusted/plugin/file_utils.h"
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include "native_client/src/include/nacl_scoped_ptr.h"
+#include "native_client/src/include/portability_io.h"
+#include "native_client/src/include/portability_string.h"
+
+
+namespace plugin {
+namespace file_utils {
+
+StatusCode SlurpFile(int32_t fd,
+                     nacl::string& out_buf,
+                     size_t max_size_to_read) {
+  struct stat stat_buf;
+  if (fstat(fd, &stat_buf) != 0) {
+    CLOSE(fd);
+    return PLUGIN_FILE_ERROR_STAT;
+  }
+
+  // Figure out how large a buffer we need to slurp the whole file (with a
+  // '\0' at the end).
+  size_t bytes_to_read = static_cast<size_t>(stat_buf.st_size);
+  if (bytes_to_read > max_size_to_read - 1) {
+    CLOSE(fd);
+    return PLUGIN_FILE_ERROR_FILE_TOO_LARGE;
+  }
+
+  FILE* input_file = fdopen(fd, "rb");
+  if (!input_file) {
+    CLOSE(fd);
+    return PLUGIN_FILE_ERROR_OPEN;
+  }
+  // From here on, closing input_file will automatically close fd.
+
+  nacl::scoped_array<char> buffer(new char[bytes_to_read + 1]);
+  if (buffer == NULL) {
+    fclose(input_file);
+    return PLUGIN_FILE_ERROR_MEM_ALLOC;
+  }
+
+  size_t total_bytes_read = 0;
+  while (bytes_to_read > 0) {
+    size_t bytes_this_read = fread(&buffer[total_bytes_read],
+                                   sizeof(char),
+                                   bytes_to_read,
+                                   input_file);
+    if (bytes_this_read < bytes_to_read && (feof(input_file) ||
+                                            ferror(input_file))) {
+      fclose(input_file);
+      return PLUGIN_FILE_ERROR_READ;
+    }
+    total_bytes_read += bytes_this_read;
+    bytes_to_read -= bytes_this_read;
+  }
+
+  fclose(input_file);
+  buffer[total_bytes_read] = '\0';
+  out_buf = buffer.get();
+  return PLUGIN_FILE_SUCCESS;
+}
+
+}  // namespace file_utils
+}  // namespace plugin
+
diff --git a/ppapi/native_client/src/trusted/plugin/file_utils.h b/ppapi/native_client/src/trusted/plugin/file_utils.h
new file mode 100644
index 0000000..223bf66
--- /dev/null
+++ b/ppapi/native_client/src/trusted/plugin/file_utils.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Some common file utilities for plugin code.
+
+#ifndef NATIVE_CLIENT_SRC_TRUSTED_PLUGIN_FILE_UTILS_H_
+#define NATIVE_CLIENT_SRC_TRUSTED_PLUGIN_FILE_UTILS_H_
+
+#include "native_client/src/include/nacl_string.h"
+#include "native_client/src/include/portability_io.h"
+#include "ppapi/c/pp_stdint.h"
+
+namespace plugin {
+namespace file_utils {
+
+enum StatusCode {
+  PLUGIN_FILE_SUCCESS = 0,
+  PLUGIN_FILE_ERROR_MEM_ALLOC = 1,
+  PLUGIN_FILE_ERROR_OPEN = 2,
+  PLUGIN_FILE_ERROR_FILE_TOO_LARGE = 3,
+  PLUGIN_FILE_ERROR_STAT = 4,
+  PLUGIN_FILE_ERROR_READ = 5
+};
+
+// Slurp the whole contents of the given file (|fd| - open file descriptor) into
+// |out_buf|. |max_size_to_read| is the maximal allowed size of the file.
+// If the file turns out to be larger, an error is returned. In any case,
+// |fd| is closed.
+StatusCode SlurpFile(int32_t fd,
+                     nacl::string& out_buf,
+                     size_t max_size_to_read = (1 << 20));
+
+}  // namespace file_utils
+}  // namespace plugin
+
+#endif  // NATIVE_CLIENT_SRC_TRUSTED_PLUGIN_FILE_UTILS_H_
+
diff --git a/ppapi/native_client/src/trusted/plugin/plugin.cc b/ppapi/native_client/src/trusted/plugin/plugin.cc
index de70eaf..cd5dfbf 100644
--- a/ppapi/native_client/src/trusted/plugin/plugin.cc
+++ b/ppapi/native_client/src/trusted/plugin/plugin.cc
@@ -9,11 +9,6 @@
 
 #include "native_client/src/trusted/plugin/plugin.h"
 
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
 #include <sys/stat.h>
 #include <sys/types.h>
 
@@ -32,6 +27,7 @@
 #include "native_client/src/shared/platform/nacl_check.h"
 #include "native_client/src/trusted/desc/nacl_desc_wrapper.h"
 #include "native_client/src/trusted/nonnacl_util/sel_ldr_launcher.h"
+#include "native_client/src/trusted/plugin/file_utils.h"
 #include "native_client/src/trusted/plugin/json_manifest.h"
 #include "native_client/src/trusted/plugin/nacl_entry_points.h"
 #include "native_client/src/trusted/plugin/nacl_subprocess.h"
@@ -806,16 +802,16 @@
 void Plugin::NexeFileDidOpen(int32_t pp_error) {
   PLUGIN_PRINTF(("Plugin::NexeFileDidOpen (pp_error=%"NACL_PRId32")\n",
                  pp_error));
-  int32_t file_desc = nexe_downloader_.GetPOSIXFileDescriptor();
+  struct NaClFileInfo info = nexe_downloader_.GetFileInfo();
   PLUGIN_PRINTF(("Plugin::NexeFileDidOpen (file_desc=%"NACL_PRId32")\n",
-                 file_desc));
+                 info.desc));
   HistogramHTTPStatusCode(
       is_installed_ ?
           "NaCl.HttpStatusCodeClass.Nexe.InstalledApp" :
           "NaCl.HttpStatusCodeClass.Nexe.NotInstalledApp",
       nexe_downloader_.status_code());
   ErrorInfo error_info;
-  if (pp_error != PP_OK || file_desc == NACL_NO_FILE_DESC) {
+  if (pp_error != PP_OK || info.desc == NACL_NO_FILE_DESC) {
     if (pp_error == PP_ERROR_ABORTED) {
       ReportLoadAbort();
     } else if (pp_error == PP_ERROR_NOACCESS) {
@@ -828,7 +824,7 @@
     }
     return;
   }
-  int32_t file_desc_ok_to_close = DUP(file_desc);
+  int32_t file_desc_ok_to_close = DUP(info.desc);
   if (file_desc_ok_to_close == NACL_NO_FILE_DESC) {
     error_info.SetReport(ERROR_NEXE_FH_DUP,
                          "could not duplicate loaded file handle.");
@@ -1087,10 +1083,10 @@
   // The manifest file was successfully opened.  Set the src property on the
   // plugin now, so that the full url is available to error handlers.
   set_manifest_url(nexe_downloader_.url());
-  int32_t file_desc = nexe_downloader_.GetPOSIXFileDescriptor();
+  struct NaClFileInfo info = nexe_downloader_.GetFileInfo();
   PLUGIN_PRINTF(("Plugin::NaClManifestFileDidOpen (file_desc=%"
-                 NACL_PRId32")\n", file_desc));
-  if (pp_error != PP_OK || file_desc == NACL_NO_FILE_DESC) {
+                 NACL_PRId32")\n", info.desc));
+  if (pp_error != PP_OK || info.desc == NACL_NO_FILE_DESC) {
     if (pp_error == PP_ERROR_ABORTED) {
       ReportLoadAbort();
     } else if (pp_error == PP_ERROR_NOACCESS) {
@@ -1104,75 +1100,44 @@
     }
     return;
   }
-  // Duplicate the file descriptor in order to create a FILE stream with it
-  // that can later be closed without closing the original descriptor.  The
-  // browser will take care of the original descriptor.
-  int dup_file_desc = DUP(file_desc);
-  struct stat stat_buf;
-  if (0 != fstat(dup_file_desc, &stat_buf)) {
-    CLOSE(dup_file_desc);
-    error_info.SetReport(ERROR_MANIFEST_STAT,
-                         "could not stat manifest file.");
-    ReportLoadError(error_info);
-    return;
-  }
-  size_t bytes_to_read = static_cast<size_t>(stat_buf.st_size);
-  if (bytes_to_read > kNaClManifestMaxFileBytes) {
-    CLOSE(dup_file_desc);
-    error_info.SetReport(ERROR_MANIFEST_TOO_LARGE,
-                         "manifest file too large.");
-    ReportLoadError(error_info);
-    return;
-  }
-  FILE* json_file = fdopen(dup_file_desc, "rb");
-  PLUGIN_PRINTF(("Plugin::NaClManifestFileDidOpen "
-                 "(dup_file_desc=%"NACL_PRId32", json_file=%p)\n",
-                 dup_file_desc, static_cast<void*>(json_file)));
-  if (json_file == NULL) {
-    CLOSE(dup_file_desc);
-    error_info.SetReport(ERROR_MANIFEST_OPEN,
-                         "could not open manifest file.");
-    ReportLoadError(error_info);
-    return;
-  }
-  nacl::scoped_array<char> json_buffer(new char[bytes_to_read + 1]);
-  if (json_buffer == NULL) {
-    fclose(json_file);
-    error_info.SetReport(ERROR_MANIFEST_MEMORY_ALLOC,
-                         "could not allocate manifest memory.");
-    ReportLoadError(error_info);
-    return;
-  }
-  // json_buffer could hold a large enough buffer that the system might need
-  // multiple reads to fill it, so iterate through reads.
-  size_t total_bytes_read = 0;
-  while (0 < bytes_to_read) {
-    size_t bytes_this_read = fread(&json_buffer[total_bytes_read],
-                                   sizeof(char),
-                                   bytes_to_read,
-                                   json_file);
-    if (bytes_this_read < bytes_to_read &&
-        (feof(json_file) || ferror(json_file))) {
-      PLUGIN_PRINTF(("Plugin::NaClManifestFileDidOpen failed: "
-                     "total_bytes_read=%"NACL_PRIuS" "
-                     "bytes_to_read=%"NACL_PRIuS"\n",
-                     total_bytes_read, bytes_to_read));
-      fclose(json_file);
-      error_info.SetReport(ERROR_MANIFEST_READ,
-                           "could not read manifest file.");
-      ReportLoadError(error_info);
-      return;
-    }
-    total_bytes_read += bytes_this_read;
-    bytes_to_read -= bytes_this_read;
-  }
-  // Once the bytes are read, the FILE is no longer needed, so close it.  This
-  // allows for early returns without leaking the |json_file| FILE object.
-  fclose(json_file);
-  // No need to close |file_desc|, that is handled by |nexe_downloader_|.
-  json_buffer[total_bytes_read] = '\0';  // Force null termination.
+  // SlurpFile closes the file descriptor after reading (or on error).
+  // Duplicate our file descriptor since it will be handled by the browser.
+  int dup_file_desc = DUP(info.desc);
+  nacl::string json_buffer;
+  file_utils::StatusCode status = file_utils::SlurpFile(
+      dup_file_desc, json_buffer, kNaClManifestMaxFileBytes);
 
-  ProcessNaClManifest(json_buffer.get());
+  if (status != file_utils::PLUGIN_FILE_SUCCESS) {
+    switch (status) {
+      case file_utils::PLUGIN_FILE_SUCCESS:
+        CHECK(0);
+        break;
+      case file_utils::PLUGIN_FILE_ERROR_MEM_ALLOC:
+        error_info.SetReport(ERROR_MANIFEST_MEMORY_ALLOC,
+                             "could not allocate manifest memory.");
+        break;
+      case file_utils::PLUGIN_FILE_ERROR_OPEN:
+        error_info.SetReport(ERROR_MANIFEST_OPEN,
+                             "could not open manifest file.");
+        break;
+      case file_utils::PLUGIN_FILE_ERROR_FILE_TOO_LARGE:
+        error_info.SetReport(ERROR_MANIFEST_TOO_LARGE,
+                             "manifest file too large.");
+        break;
+      case file_utils::PLUGIN_FILE_ERROR_STAT:
+        error_info.SetReport(ERROR_MANIFEST_STAT,
+                             "could not stat manifest file.");
+        break;
+      case file_utils::PLUGIN_FILE_ERROR_READ:
+        error_info.SetReport(ERROR_MANIFEST_READ,
+                             "could not read manifest file.");
+        break;
+    }
+    ReportLoadError(error_info);
+    return;
+  }
+
+  ProcessNaClManifest(json_buffer);
 }
 
 void Plugin::ProcessNaClManifest(const nacl::string& manifest_json) {
@@ -1309,28 +1274,32 @@
                  static_cast<void*>(url_downloader)));
   url_downloaders_.erase(url_downloader);
   nacl::scoped_ptr<FileDownloader> scoped_url_downloader(url_downloader);
-  int32_t file_desc = scoped_url_downloader->GetPOSIXFileDescriptor();
+  struct NaClFileInfo info = scoped_url_downloader->GetFileInfo();
 
   if (pp_error != PP_OK) {
     PP_RunCompletionCallback(&callback, pp_error);
-  } else if (file_desc > NACL_NO_FILE_DESC) {
-    url_fd_map_[url_downloader->url_to_open()] = file_desc;
+  } else if (info.desc > NACL_NO_FILE_DESC) {
+    url_file_info_map_[url_downloader->url_to_open()] = info;
     PP_RunCompletionCallback(&callback, PP_OK);
   } else {
     PP_RunCompletionCallback(&callback, PP_ERROR_FAILED);
   }
 }
 
-int32_t Plugin::GetPOSIXFileDesc(const nacl::string& url) {
-  PLUGIN_PRINTF(("Plugin::GetFileDesc (url=%s)\n", url.c_str()));
-  int32_t file_desc_ok_to_close = NACL_NO_FILE_DESC;
-  std::map<nacl::string, int32_t>::iterator it = url_fd_map_.find(url);
-  if (it != url_fd_map_.end())
-    file_desc_ok_to_close = DUP(it->second);
-  return file_desc_ok_to_close;
+struct NaClFileInfo Plugin::GetFileInfo(const nacl::string& url) {
+  struct NaClFileInfo info;
+  memset(&info, 0, sizeof(info));
+  std::map<nacl::string, struct NaClFileInfo>::iterator it =
+      url_file_info_map_.find(url);
+  if (it != url_file_info_map_.end()) {
+    info = it->second;
+    info.desc = DUP(info.desc);
+  } else {
+    info.desc = -1;
+  }
+  return info;
 }
 
-
 bool Plugin::StreamAsFile(const nacl::string& url,
                           PP_CompletionCallback callback) {
   PLUGIN_PRINTF(("Plugin::StreamAsFile (url='%s')\n", url.c_str()));
@@ -1609,25 +1578,18 @@
   if (!DocumentCanRequest(url))
     return false;
 
-  PP_NaClExecutableMetadata file_metadata;
+  uint64_t file_token_lo = 0;
+  uint64_t file_token_hi = 0;
   PP_FileHandle file_handle =
       nacl_interface()->OpenNaClExecutable(pp_instance(),
                                            url.c_str(),
-                                           &file_metadata);
+                                           &file_token_lo, &file_token_hi);
   // We shouldn't hit this if the file URL is in an installed app.
   if (file_handle == PP_kInvalidFileHandle)
     return false;
 
-  // Release the PP_Var in the metadata struct.
-  pp::Module* module = pp::Module::Get();
-  const PPB_Var* var_interface =
-      static_cast<const PPB_Var*>(
-          module->GetBrowserInterface(PPB_VAR_INTERFACE));
-  var_interface->Release(file_metadata.file_path);
-
   // FileDownloader takes ownership of the file handle.
-  // TODO(bbudge) Consume metadata once we have the final format.
-  downloader->OpenFast(url, file_handle);
+  downloader->OpenFast(url, file_handle, file_token_lo, file_token_hi);
   return true;
 }
 
diff --git a/ppapi/native_client/src/trusted/plugin/plugin.gypi b/ppapi/native_client/src/trusted/plugin/plugin.gypi
index 4532f2f..756ebce 100644
--- a/ppapi/native_client/src/trusted/plugin/plugin.gypi
+++ b/ppapi/native_client/src/trusted/plugin/plugin.gypi
@@ -7,6 +7,7 @@
     'chromium_code': 1,  # Use higher warning level.
     'common_sources': [
       'file_downloader.cc',
+      'file_utils.cc',
       'json_manifest.cc',
       'local_temp_file.cc',
       'module_ppapi.cc',
diff --git a/ppapi/native_client/src/trusted/plugin/plugin.h b/ppapi/native_client/src/trusted/plugin/plugin.h
index 37bcfdd..eecddc6 100644
--- a/ppapi/native_client/src/trusted/plugin/plugin.h
+++ b/ppapi/native_client/src/trusted/plugin/plugin.h
@@ -24,6 +24,7 @@
 #include "native_client/src/trusted/plugin/pnacl_coordinator.h"
 #include "native_client/src/trusted/plugin/service_runtime.h"
 #include "native_client/src/trusted/plugin/utility.h"
+#include "native_client/src/trusted/validator/nacl_file_info.h"
 
 #include "ppapi/c/private/ppb_nacl_private.h"
 #include "ppapi/cpp/private/var_private.h"
@@ -252,9 +253,11 @@
   // corresponding to the url body is recorded for further lookup.
   bool StreamAsFile(const nacl::string& url,
                     PP_CompletionCallback pp_callback);
-  // Returns an open POSIX file descriptor retrieved by StreamAsFile()
-  // or NACL_NO_FILE_DESC. The caller must take ownership of the descriptor.
-  int32_t GetPOSIXFileDesc(const nacl::string& url);
+
+  // Returns rich information for a file retrieved by StreamAsFile(). This info
+  // contains a file descriptor. The caller must take ownership of this
+  // descriptor.
+  struct NaClFileInfo GetFileInfo(const nacl::string& url);
 
   // A helper function that gets the scheme type for |url|. Uses URLUtil_Dev
   // interface which this class has as a member.
@@ -475,7 +478,7 @@
   std::set<FileDownloader*> url_downloaders_;
   // Keep track of file descriptors opened by StreamAsFile().
   // These are owned by the browser.
-  std::map<nacl::string, int32_t> url_fd_map_;
+  std::map<nacl::string, struct NaClFileInfo> url_file_info_map_;
 
   // Pending progress events.
   std::queue<ProgressEvent*> progress_events_;
diff --git a/ppapi/native_client/src/trusted/plugin/pnacl_coordinator.cc b/ppapi/native_client/src/trusted/plugin/pnacl_coordinator.cc
index 836b086..613abd4 100644
--- a/ppapi/native_client/src/trusted/plugin/pnacl_coordinator.cc
+++ b/ppapi/native_client/src/trusted/plugin/pnacl_coordinator.cc
@@ -90,9 +90,11 @@
                             "key did not start with files/");
       return false;
     }
-    // Append what follows files to the pnacl URL prefix.
+    // Resolve the full URL to the file. Provide it with a platform-specific
+    // prefix.
     nacl::string key_basename = key.substr(kFilesPrefix.length());
-    return ResolveURL(key_basename, full_url, error_info);
+    return ResolveURL(PnaclUrls::PrependPlatformPrefix(key_basename),
+                      full_url, error_info);
   }
 
  private:
@@ -237,44 +239,20 @@
                  reinterpret_cast<const void*>(coordinator->manifest_.get()),
                  coordinator->off_the_record_));
 
-  // Load llc and ld.
-  std::vector<nacl::string> resource_urls;
-  resource_urls.push_back(PnaclUrls::GetLlcUrl());
-  resource_urls.push_back(PnaclUrls::GetLdUrl());
-  pp::CompletionCallback resources_cb =
-      coordinator->callback_factory_.NewCallback(
-          &PnaclCoordinator::ResourcesDidLoad);
+  // Loading resources (e.g. llc and ld nexes) is done with PnaclResources.
   coordinator->resources_.reset(
       new PnaclResources(plugin,
                          coordinator,
-                         coordinator->manifest_.get(),
-                         resource_urls,
-                         resources_cb));
+                         coordinator->manifest_.get()));
   CHECK(coordinator->resources_ != NULL);
-  coordinator->resources_->StartLoad();
-  // ResourcesDidLoad will be invoked when all resources have been received.
-  return coordinator;
-}
 
-int32_t PnaclCoordinator::GetLoadedFileDesc(int32_t pp_error,
-                                            const nacl::string& url,
-                                            const nacl::string& component) {
-  PLUGIN_PRINTF(("PnaclCoordinator::GetLoadedFileDesc (pp_error=%"
-                 NACL_PRId32", url=%s, component=%s)\n", pp_error,
-                 url.c_str(), component.c_str()));
-  ErrorInfo error_info;
-  int32_t file_desc_ok_to_close = plugin_->GetPOSIXFileDesc(url);
-  if (pp_error != PP_OK || file_desc_ok_to_close == NACL_NO_FILE_DESC) {
-    if (pp_error == PP_ERROR_ABORTED) {
-      plugin_->ReportLoadAbort();
-    } else {
-      ReportPpapiError(ERROR_PNACL_RESOURCE_FETCH,
-                       pp_error,
-                       component + " load failed.");
-    }
-    return NACL_NO_FILE_DESC;
-  }
-  return file_desc_ok_to_close;
+  // The first step of loading resources: read the resource info file.
+  pp::CompletionCallback resource_info_read_cb =
+      coordinator->callback_factory_.NewCallback(
+          &PnaclCoordinator::ResourceInfoWasRead);
+  coordinator->resources_->ReadResourceInfo(PnaclUrls::GetResourceInfoUrl(),
+                                            resource_info_read_cb);
+  return coordinator;
 }
 
 PnaclCoordinator::PnaclCoordinator(
@@ -670,6 +648,15 @@
   translate_notify_callback_.Run(pp_error);
 }
 
+void PnaclCoordinator::ResourceInfoWasRead(int32_t pp_error) {
+  PLUGIN_PRINTF(("PluginCoordinator::ResourceInfoWasRead (pp_error=%"
+                NACL_PRId32")\n", pp_error));
+  // Second step of loading resources: call StartLoad.
+  pp::CompletionCallback resources_cb =
+      callback_factory_.NewCallback(&PnaclCoordinator::ResourcesDidLoad);
+  resources_->StartLoad(resources_cb);
+}
+
 void PnaclCoordinator::ResourcesDidLoad(int32_t pp_error) {
   PLUGIN_PRINTF(("PnaclCoordinator::ResourcesDidLoad (pp_error=%"
                  NACL_PRId32")\n", pp_error));
diff --git a/ppapi/native_client/src/trusted/plugin/pnacl_coordinator.h b/ppapi/native_client/src/trusted/plugin/pnacl_coordinator.h
index 194171b..d6ee015 100644
--- a/ppapi/native_client/src/trusted/plugin/pnacl_coordinator.h
+++ b/ppapi/native_client/src/trusted/plugin/pnacl_coordinator.h
@@ -109,13 +109,6 @@
   // BitcodeToNative has completed (and the finish_callback called).
   nacl::DescWrapper* ReleaseTranslatedFD() { return translated_fd_.release(); }
 
-  // Looks up a file descriptor for an url that was already downloaded.
-  // This is used for getting the descriptor for llc and ld nexes as well
-  // as the libraries and object files used by the linker.
-  int32_t GetLoadedFileDesc(int32_t pp_error,
-                            const nacl::string& url,
-                            const nacl::string& component);
-
   // Run |translate_notify_callback_| with an error condition that is not
   // PPAPI specific.  Also set ErrorInfo report.
   void ReportNonPpapiError(PluginErrorCode err, const nacl::string& message);
@@ -165,8 +158,10 @@
                    const PnaclOptions& pnacl_options,
                    const pp::CompletionCallback& translate_notify_callback);
 
+  // Callback for when the resource info JSON file has been read.
+  void ResourceInfoWasRead(int32_t pp_error);
+
   // Callback for when llc and ld have been downloaded.
-  // This is the first callback invoked in response to BitcodeToNative.
   void ResourcesDidLoad(int32_t pp_error);
 
   // Callbacks for temporary file related stages.
diff --git a/ppapi/native_client/src/trusted/plugin/pnacl_resources.cc b/ppapi/native_client/src/trusted/plugin/pnacl_resources.cc
index af2944f..119d53a 100644
--- a/ppapi/native_client/src/trusted/plugin/pnacl_resources.cc
+++ b/ppapi/native_client/src/trusted/plugin/pnacl_resources.cc
@@ -7,22 +7,29 @@
 #include "native_client/src/include/portability_io.h"
 #include "native_client/src/shared/platform/nacl_check.h"
 #include "native_client/src/trusted/desc/nacl_desc_wrapper.h"
+#include "native_client/src/trusted/plugin/file_utils.h"
 #include "native_client/src/trusted/plugin/manifest.h"
 #include "native_client/src/trusted/plugin/plugin.h"
 #include "native_client/src/trusted/plugin/pnacl_coordinator.h"
 #include "native_client/src/trusted/plugin/utility.h"
-
 #include "ppapi/c/pp_errors.h"
+#include "third_party/jsoncpp/source/include/json/reader.h"
+#include "third_party/jsoncpp/source/include/json/value.h"
 
 namespace plugin {
 
-static const char kPnaclComponentScheme[] =
-    "pnacl-component://";
-const char PnaclUrls::kLlcUrl[] = "llc.nexe";
-const char PnaclUrls::kLdUrl[] = "ld.nexe";
+static const char kPnaclComponentScheme[] = "pnacl-component://";
+const char PnaclUrls::kResourceInfoUrl[] = "pnacl.json";
+
+const char PnaclResources::kDefaultLlcName[] = "llc.nexe";
+const char PnaclResources::kDefaultLdName[] = "ld.nexe";
 
 nacl::string PnaclUrls::GetBaseUrl() {
-  return nacl::string(kPnaclComponentScheme) + GetSandboxISA() + "/";
+  return nacl::string(kPnaclComponentScheme);
+}
+
+nacl::string PnaclUrls::PrependPlatformPrefix(const nacl::string& url) {
+  return nacl::string(GetSandboxISA()) + "/" + url;
 }
 
 // Determine if a URL is for a pnacl-component file, or if it is some other
@@ -92,22 +99,118 @@
   return resource_wrappers_[url];
 }
 
-void PnaclResources::StartLoad() {
+void PnaclResources::ReadResourceInfo(
+    const nacl::string& resource_info_url,
+    const pp::CompletionCallback& resource_info_read_cb) {
+  PLUGIN_PRINTF(("PnaclResources::ReadResourceInfo\n"));
+
+  nacl::string full_url;
+  ErrorInfo error_info;
+  if (!manifest_->ResolveURL(resource_info_url, &full_url, &error_info)) {
+    ReadResourceInfoError(nacl::string("failed to resolve ") +
+                          resource_info_url + ": " +
+                          error_info.message() + ".");
+    return;
+  }
+  PLUGIN_PRINTF(("Resolved resources info url: %s\n", full_url.c_str()));
+  nacl::string resource_info_filename =
+    PnaclUrls::PnaclComponentURLToFilename(full_url);
+
+  PLUGIN_PRINTF(("Pnacl-converted resources info url: %s\n",
+                 resource_info_filename.c_str()));
+
+  int32_t fd = GetPnaclFD(plugin_, resource_info_filename.c_str());
+  if (fd < 0) {
+    ReadResourceInfoError(
+        nacl::string("PnaclResources::ReadResourceInfo failed for: ") +
+        resource_info_filename);
+    return;
+  }
+
+  nacl::string json_buffer;
+  file_utils::StatusCode status = file_utils::SlurpFile(fd, json_buffer);
+  if (status != file_utils::PLUGIN_FILE_SUCCESS) {
+    ReadResourceInfoError(
+        nacl::string("PnaclResources::ReadResourceInfo reading "
+                     "failed for: ") + resource_info_filename);
+    return;
+  }
+
+  // Finally, we have the resource info JSON data in json_buffer.
+  PLUGIN_PRINTF(("Resource info JSON data:\n%s\n", json_buffer.c_str()));
+  nacl::string error_message;
+  if (!ParseResourceInfo(json_buffer, error_message)) {
+    ReadResourceInfoError(nacl::string("Parsing resource info failed: ") +
+                          error_message + "\n");
+    return;
+  }
+
+  // Done. Queue the completion callback.
+  pp::Core* core = pp::Module::Get()->core();
+  core->CallOnMainThread(0, resource_info_read_cb, PP_OK);
+}
+
+void PnaclResources::ReadResourceInfoError(const nacl::string& msg) {
+  coordinator_->ReportNonPpapiError(ERROR_PNACL_RESOURCE_FETCH, msg);
+}
+
+bool PnaclResources::ParseResourceInfo(const nacl::string& buf,
+                                       nacl::string& errmsg) {
+  // Expect the JSON file to contain a top-level object (dictionary).
+  Json::Reader json_reader;
+  Json::Value json_data;
+  if (!json_reader.parse(buf, json_data)) {
+    errmsg = nacl::string("JSON parse error: ") +
+             json_reader.getFormatedErrorMessages();
+    return false;
+  }
+
+  if (!json_data.isObject()) {
+    errmsg = nacl::string("Malformed JSON dictionary");
+    return false;
+  }
+
+  if (json_data.isMember("pnacl-llc-name")) {
+    Json::Value json_name = json_data["pnacl-llc-name"];
+    if (json_name.isString()) {
+      llc_tool_name = json_name.asString();
+      PLUGIN_PRINTF(("Set llc_tool_name=%s\n", llc_tool_name.c_str()));
+    }
+  }
+
+  if (json_data.isMember("pnacl-ld-name")) {
+    Json::Value json_name = json_data["pnacl-ld-name"];
+    if (json_name.isString()) {
+      ld_tool_name = json_name.asString();
+      PLUGIN_PRINTF(("Set ld_tool_name=%s\n", ld_tool_name.c_str()));
+    }
+  }
+
+  return true;
+}
+
+void PnaclResources::StartLoad(
+    const pp::CompletionCallback& all_loaded_callback) {
   PLUGIN_PRINTF(("PnaclResources::StartLoad\n"));
 
-  CHECK(resource_urls_.size() > 0);
+  std::vector<nacl::string> resource_urls;
+  resource_urls.push_back(GetLlcUrl());
+  resource_urls.push_back(GetLdUrl());
+
   PLUGIN_PRINTF(("PnaclResources::StartLoad -- local install of PNaCl.\n"));
   // Do a blocking load of each of the resources.
   int32_t result = PP_OK;
-  for (size_t i = 0; i < resource_urls_.size(); ++i) {
-    const nacl::string& url = resource_urls_[i];
+  for (size_t i = 0; i < resource_urls.size(); ++i) {
+    const nacl::string& url_with_platform_prefix =
+      PnaclUrls::PrependPlatformPrefix(resource_urls[i]);
     nacl::string full_url;
     ErrorInfo error_info;
-    if (!manifest_->ResolveURL(resource_urls_[i], &full_url, &error_info)) {
+    if (!manifest_->ResolveURL(url_with_platform_prefix, &full_url,
+                               &error_info)) {
       coordinator_->ReportNonPpapiError(
           ERROR_PNACL_RESOURCE_FETCH,
           nacl::string("failed to resolve ") +
-          url + ": " +
+          url_with_platform_prefix + ": " +
           error_info.message() + ".");
       break;
     }
@@ -117,18 +220,18 @@
     if (fd < 0) {
       coordinator_->ReportNonPpapiError(
           ERROR_PNACL_RESOURCE_FETCH,
-          nacl::string("PnaclLocalResources::StartLoad failed for: ") +
+          nacl::string("PnaclResources::StartLoad failed for: ") +
           filename + " (PNaCl not installed?  Check chrome://nacl)");
       result = PP_ERROR_FILENOTFOUND;
       break;
     } else {
-      resource_wrappers_[url] =
+      resource_wrappers_[resource_urls[i]] =
           plugin_->wrapper_factory()->MakeFileDesc(fd, O_RDONLY);
     }
   }
   // We're done!  Queue the callback.
   pp::Core* core = pp::Module::Get()->core();
-  core->CallOnMainThread(0, all_loaded_callback_, result);
+  core->CallOnMainThread(0, all_loaded_callback, result);
 }
 
 }  // namespace plugin
diff --git a/ppapi/native_client/src/trusted/plugin/pnacl_resources.h b/ppapi/native_client/src/trusted/plugin/pnacl_resources.h
index 54e6399..10dbd35 100644
--- a/ppapi/native_client/src/trusted/plugin/pnacl_resources.h
+++ b/ppapi/native_client/src/trusted/plugin/pnacl_resources.h
@@ -26,15 +26,23 @@
 // Constants for loading LLC and LD.
 class PnaclUrls {
  public:
+  // Get the base URL prefix for Pnacl resources (without platform prefix).
   static nacl::string GetBaseUrl();
+
+  // Return {platform_prefix}/url
+  static nacl::string PrependPlatformPrefix(const nacl::string& url);
+
   static bool IsPnaclComponent(const nacl::string& full_url);
   static nacl::string PnaclComponentURLToFilename(
       const nacl::string& full_url);
-  static const nacl::string GetLlcUrl() { return nacl::string(kLlcUrl); }
-  static const nacl::string GetLdUrl() { return nacl::string(kLdUrl); }
+
+  // Get the URL for the resource info JSON file that contains information
+  // about loadable resources.
+  static const nacl::string GetResourceInfoUrl() {
+    return nacl::string(kResourceInfoUrl);
+  }
  private:
-  static const char kLlcUrl[];
-  static const char kLdUrl[];
+  static const char kResourceInfoUrl[];
 };
 
 // Loads a list of resources, providing a way to get file descriptors for
@@ -44,20 +52,35 @@
  public:
   PnaclResources(Plugin* plugin,
                  PnaclCoordinator* coordinator,
-                 const Manifest* manifest,
-                 const std::vector<nacl::string>& resource_urls,
-                 const pp::CompletionCallback& all_loaded_callback)
+                 const Manifest* manifest)
       : plugin_(plugin),
         coordinator_(coordinator),
         manifest_(manifest),
-        resource_urls_(resource_urls),
-        all_loaded_callback_(all_loaded_callback) {
+        llc_tool_name(kDefaultLlcName),
+        ld_tool_name(kDefaultLdName) {
   }
   virtual ~PnaclResources();
 
-  // Start loading the resources.  After construction, this is the first step.
-  virtual void StartLoad();
-  // Get file descs by name. Only valid after all_loaded_callback_ has been run.
+  // Read the resource info JSON file.  This is the first step after
+  // construction; it has to be completed before StartLoad is called.
+  virtual void ReadResourceInfo(
+      const nacl::string& resource_info_url,
+      const pp::CompletionCallback& resource_info_read_cb);
+
+  // Start loading the resources.
+  virtual void StartLoad(
+      const pp::CompletionCallback& all_loaded_callback);
+
+  const nacl::string& GetLlcUrl() {
+    return llc_tool_name;
+  }
+
+  const nacl::string& GetLdUrl() {
+    return ld_tool_name;
+  }
+
+  // Get file descs by name. Only valid after StartLoad's completion callback
+  // fired.
   nacl::DescWrapper* WrapperForUrl(const nacl::string& url);
 
   static int32_t GetPnaclFD(Plugin* plugin, const char* filename);
@@ -71,13 +94,28 @@
   PnaclCoordinator* coordinator_;
   // The manifest for looking up resource URLs.
   const Manifest* manifest_;
-  // The list of resource URLs (relative to resource_base_url_) to load.
-  std::vector<nacl::string> resource_urls_;
-  // Callback to be invoked when all resources can be guaranteed available.
-  pp::CompletionCallback all_loaded_callback_;
   // The descriptor wrappers for the downloaded URLs.  Only valid
   // once all_loaded_callback_ has been invoked.
   std::map<nacl::string, nacl::DescWrapper*> resource_wrappers_;
+
+  // The names of the llc and ld nexes are read from the resource info file.
+  // These are default values if the resource file does not contain the names.
+  // TODO(eliben): this should be eventually removed, once all nacl deps
+  // propagate - the names should always exist in the resource info JSON file.
+  static const char kDefaultLlcName[];
+  static const char kDefaultLdName[];
+
+  // Tool names for llc and ld; read from the resource info file.
+  nacl::string llc_tool_name;
+  nacl::string ld_tool_name;
+
+  // Parses resource info json data in |buf|.  Returns true if successful.
+  // Otherwise returns false and places an error message in |errmsg|.
+  bool ParseResourceInfo(const nacl::string& buf, nacl::string& errmsg);
+
+  // Convenience function for reporting an error while reading the resource
+  // info file.
+  void ReadResourceInfoError(const nacl::string& msg);
 };
 
 }  // namespace plugin;
diff --git a/ppapi/native_client/src/trusted/plugin/pnacl_translate_thread.cc b/ppapi/native_client/src/trusted/plugin/pnacl_translate_thread.cc
index e035ce1..7b1a680 100644
--- a/ppapi/native_client/src/trusted/plugin/pnacl_translate_thread.cc
+++ b/ppapi/native_client/src/trusted/plugin/pnacl_translate_thread.cc
@@ -135,7 +135,7 @@
     nacl::MutexLocker ml(&subprocess_mu_);
     int64_t llc_start_time = NaClGetTimeOfDayMicroseconds();
     llc_subprocess_.reset(
-      StartSubprocess(PnaclUrls::GetLlcUrl(), manifest_, &error_info));
+      StartSubprocess(resources_->GetLlcUrl(), manifest_, &error_info));
     if (llc_subprocess_ == NULL) {
       TranslateFailed(ERROR_PNACL_LLC_SETUP,
                       "Compile process could not be created: " +
@@ -278,7 +278,7 @@
     nacl::MutexLocker ml(&subprocess_mu_);
     int64_t ld_start_time = NaClGetTimeOfDayMicroseconds();
     ld_subprocess_.reset(
-      StartSubprocess(PnaclUrls::GetLdUrl(), manifest_, &error_info));
+      StartSubprocess(resources_->GetLdUrl(), manifest_, &error_info));
     if (ld_subprocess_ == NULL) {
       TranslateFailed(ERROR_PNACL_LD_SETUP,
                       "Link process could not be created: " +
diff --git a/ppapi/native_client/src/trusted/plugin/service_runtime.cc b/ppapi/native_client/src/trusted/plugin/service_runtime.cc
index ba21a49..6c44bc4 100644
--- a/ppapi/native_client/src/trusted/plugin/service_runtime.cc
+++ b/ppapi/native_client/src/trusted/plugin/service_runtime.cc
@@ -46,11 +46,10 @@
 #include "native_client/src/trusted/plugin/pnacl_resources.h"
 #include "native_client/src/trusted/plugin/sel_ldr_launcher_chrome.h"
 #include "native_client/src/trusted/plugin/srpc_client.h"
-
-#include "native_client/src/trusted/weak_ref/call_on_main_thread.h"
-
 #include "native_client/src/trusted/service_runtime/nacl_error_code.h"
 #include "native_client/src/trusted/service_runtime/include/sys/nacl_imc_api.h"
+#include "native_client/src/trusted/validator/nacl_file_info.h"
+#include "native_client/src/trusted/weak_ref/call_on_main_thread.h"
 
 #include "ppapi/c/pp_errors.h"
 #include "ppapi/c/trusted/ppb_file_io_trusted.h"
@@ -172,11 +171,15 @@
 // and invoke StreamAsFile with a completion callback that invokes
 // GetPOSIXFileDesc.
 bool PluginReverseInterface::OpenManifestEntry(nacl::string url_key,
-                                               int32_t* out_desc) {
+                                               struct NaClFileInfo* info) {
   ErrorInfo error_info;
   bool op_complete = false;  // NB: mu_ and cv_ also controls access to this!
+  // The to_open object is owned by the weak ref callback. Because this function
+  // waits for the callback to finish, the to_open object will be deallocated on
+  // the main thread before this function can return. The pointers it contains
+  // to stack variables will not leak.
   OpenManifestEntryResource* to_open =
-      new OpenManifestEntryResource(url_key, out_desc,
+      new OpenManifestEntryResource(url_key, info,
                                     &error_info, &op_complete);
   CHECK(to_open != NULL);
   NaClLog(4, "PluginReverseInterface::OpenManifestEntry: %s\n",
@@ -228,8 +231,8 @@
   NaClLog(4,
           "PluginReverseInterface::OpenManifestEntry:"
           " *out_desc = %d\n",
-          *out_desc);
-  if (*out_desc == -1) {
+          info->desc);
+  if (info->desc == -1) {
     // TODO(bsy,ncbray): what else should we do with the error?  This
     // is a runtime error that may simply be a programming error in
     // the untrusted code, or it may be something else wrong w/ the
@@ -267,7 +270,7 @@
     // up requesting thread -- we are done.
     nacl::MutexLocker take(&mu_);
     *p->op_complete_ptr = true;  // done...
-    *p->out_desc = -1;       // but failed.
+    p->file_info->desc = -1;  // but failed.
     NaClXCondVarBroadcast(&cv_);
     return;
   }
@@ -294,7 +297,7 @@
                 "StreamAsFile failed\n");
         nacl::MutexLocker take(&mu_);
         *p->op_complete_ptr = true;  // done...
-        *p->out_desc = -1;       // but failed.
+        p->file_info->desc = -1;       // but failed.
         p->error_info->SetReport(ERROR_MANIFEST_OPEN,
                                  "ServiceRuntime: StreamAsFile failed");
         NaClXCondVarBroadcast(&cv_);
@@ -321,7 +324,9 @@
       }
       nacl::MutexLocker take(&mu_);
       *p->op_complete_ptr = true;  // done!
-      *p->out_desc = fd;
+      // TODO(ncbray): enable the fast loading and validation paths for this
+      // type of file.
+      p->file_info->desc = fd;
       NaClXCondVarBroadcast(&cv_);
       NaClLog(4,
               "OpenManifestEntry_MainThreadContinuation: GetPnaclFd okay\n");
@@ -347,7 +352,7 @@
     } else {
       nacl::MutexLocker take(&mu_);
       *p->op_complete_ptr = true;  // done...
-      *p->out_desc = -1;       // but failed.
+      p->file_info->desc = -1;  // but failed.
       p->error_info->SetReport(ERROR_PNACL_NOT_ENABLED,
                                "ServiceRuntime: GetPnaclFd failed -- pnacl not "
                                "enabled with --enable-pnacl.");
@@ -366,16 +371,17 @@
 
   nacl::MutexLocker take(&mu_);
   if (result == PP_OK) {
-    NaClLog(4, "StreamAsFile_MainThreadContinuation: GetPOSIXFileDesc(%s)\n",
+    NaClLog(4, "StreamAsFile_MainThreadContinuation: GetFileInfo(%s)\n",
             p->url.c_str());
-    *p->out_desc = plugin_->GetPOSIXFileDesc(p->url);
+    *p->file_info = plugin_->GetFileInfo(p->url);
+
     NaClLog(4,
             "StreamAsFile_MainThreadContinuation: PP_OK, desc %d\n",
-            *p->out_desc);
+            p->file_info->desc);
   } else {
     NaClLog(4,
             "StreamAsFile_MainThreadContinuation: !PP_OK, setting desc -1\n");
-    *p->out_desc = -1;
+    p->file_info->desc = -1;
     p->error_info->SetReport(ERROR_MANIFEST_OPEN,
                              "Plugin StreamAsFile failed at callback");
   }
@@ -397,16 +403,16 @@
     // accepts NaClDescs we can avoid this downcast.
     NaClDesc* desc = pnacl_coordinator_->ReleaseTranslatedFD()->desc();
     struct NaClDescIoDesc* ndiodp = (struct NaClDescIoDesc*)desc;
-    *p->out_desc = ndiodp->hd->d;
+    p->file_info->desc = ndiodp->hd->d;
     pnacl_coordinator_.reset(NULL);
     NaClLog(4,
             "BitcodeTranslate_MainThreadContinuation: PP_OK, desc %d\n",
-            *p->out_desc);
+            p->file_info->desc);
   } else {
     NaClLog(4,
             "BitcodeTranslate_MainThreadContinuation: !PP_OK, "
             "setting desc -1\n");
-    *p->out_desc = -1;
+    p->file_info->desc = -1;
     // Error should have been reported by pnacl coordinator.
     NaClLog(LOG_ERROR, "PluginReverseInterface::BitcodeTranslate error.\n");
   }
diff --git a/ppapi/native_client/src/trusted/plugin/service_runtime.h b/ppapi/native_client/src/trusted/plugin/service_runtime.h
index a7eca38..6c6bced 100644
--- a/ppapi/native_client/src/trusted/plugin/service_runtime.h
+++ b/ppapi/native_client/src/trusted/plugin/service_runtime.h
@@ -27,6 +27,8 @@
 #include "ppapi/c/trusted/ppb_file_io_trusted.h"
 #include "ppapi/cpp/completion_callback.h"
 
+struct NaClFileInfo;
+
 namespace nacl {
 class DescWrapper;
 }  // namespace
@@ -63,15 +65,15 @@
 struct OpenManifestEntryResource {
  public:
   OpenManifestEntryResource(const std::string& target_url,
-                            int32_t* descp,
+                            struct NaClFileInfo* finfo,
                             ErrorInfo* infop,
                             bool* op_complete)
       : url(target_url),
-        out_desc(descp),
+        file_info(finfo),
         error_info(infop),
         op_complete_ptr(op_complete) {}
   std::string url;
-  int32_t* out_desc;
+  struct NaClFileInfo* file_info;
   ErrorInfo* error_info;
   bool* op_complete_ptr;
 };
@@ -152,7 +154,8 @@
 
   virtual bool EnumerateManifestKeys(std::set<nacl::string>* out_keys);
 
-  virtual bool OpenManifestEntry(nacl::string url_key, int32_t* out_desc);
+  virtual bool OpenManifestEntry(nacl::string url_key,
+                                 struct NaClFileInfo *info);
 
   virtual bool CloseManifestEntry(int32_t desc);
 
diff --git a/ppapi/native_client/src/untrusted/pnacl_irt_shim/pnacl_shim.c b/ppapi/native_client/src/untrusted/pnacl_irt_shim/pnacl_shim.c
index fe06f54..cc3644c 100644
--- a/ppapi/native_client/src/untrusted/pnacl_irt_shim/pnacl_shim.c
+++ b/ppapi/native_client/src/untrusted/pnacl_irt_shim/pnacl_shim.c
@@ -83,6 +83,7 @@
 #include "ppapi/c/private/ppb_flash.h"
 #include "ppapi/c/private/ppb_flash_clipboard.h"
 #include "ppapi/c/private/ppb_flash_device_id.h"
+#include "ppapi/c/private/ppb_flash_drm.h"
 #include "ppapi/c/private/ppb_flash_font_file.h"
 #include "ppapi/c/private/ppb_flash_fullscreen.h"
 #include "ppapi/c/private/ppb_flash_menu.h"
@@ -245,6 +246,7 @@
 static struct __PnaclWrapperInfo Pnacl_WrapperInfo_PPB_Flash_Clipboard_4_0;
 static struct __PnaclWrapperInfo Pnacl_WrapperInfo_PPB_Flash_Clipboard_5_0;
 static struct __PnaclWrapperInfo Pnacl_WrapperInfo_PPB_Flash_DeviceID_1_0;
+static struct __PnaclWrapperInfo Pnacl_WrapperInfo_PPB_Flash_DRM_1_0;
 static struct __PnaclWrapperInfo Pnacl_WrapperInfo_PPB_Flash_FontFile_0_1;
 static struct __PnaclWrapperInfo Pnacl_WrapperInfo_PPB_FlashFullscreen_0_1;
 static struct __PnaclWrapperInfo Pnacl_WrapperInfo_PPB_FlashFullscreen_1_0;
@@ -262,6 +264,7 @@
 static struct __PnaclWrapperInfo Pnacl_WrapperInfo_PPB_NetworkMonitor_Private_0_2;
 static struct __PnaclWrapperInfo Pnacl_WrapperInfo_PPB_Talk_Private_1_0;
 static struct __PnaclWrapperInfo Pnacl_WrapperInfo_PPB_TCPServerSocket_Private_0_1;
+static struct __PnaclWrapperInfo Pnacl_WrapperInfo_PPB_TCPServerSocket_Private_0_2;
 static struct __PnaclWrapperInfo Pnacl_WrapperInfo_PPB_TCPSocket_Private_0_3;
 static struct __PnaclWrapperInfo Pnacl_WrapperInfo_PPB_TCPSocket_Private_0_4;
 static struct __PnaclWrapperInfo Pnacl_WrapperInfo_PPB_TCPSocket_Private_0_5;
@@ -280,6 +283,7 @@
 static struct __PnaclWrapperInfo Pnacl_WrapperInfo_PPB_Ext_Alarms_Dev_0_1;
 static struct __PnaclWrapperInfo Pnacl_WrapperInfo_PPB_Ext_Events_Dev_0_1;
 static struct __PnaclWrapperInfo Pnacl_WrapperInfo_PPB_Ext_Socket_Dev_0_1;
+static struct __PnaclWrapperInfo Pnacl_WrapperInfo_PPB_Ext_Socket_Dev_0_2;
 /* END Declarations for all Wrapper Infos. */
 
 /* Not generating wrapper methods for PPB_Audio_1_0 */
@@ -2683,6 +2687,20 @@
 
 /* End wrapper methods for PPB_Flash_DeviceID_1_0 */
 
+/* Begin wrapper methods for PPB_Flash_DRM_1_0 */
+
+static PP_Resource Pnacl_M29_PPB_Flash_DRM_Create(PP_Instance instance) {
+  const struct PPB_Flash_DRM_1_0 *iface = Pnacl_WrapperInfo_PPB_Flash_DRM_1_0.real_iface;
+  return iface->Create(instance);
+}
+
+static int32_t Pnacl_M29_PPB_Flash_DRM_GetDeviceID(PP_Resource drm, struct PP_Var* id, struct PP_CompletionCallback* callback) {
+  const struct PPB_Flash_DRM_1_0 *iface = Pnacl_WrapperInfo_PPB_Flash_DRM_1_0.real_iface;
+  return iface->GetDeviceID(drm, id, *callback);
+}
+
+/* End wrapper methods for PPB_Flash_DRM_1_0 */
+
 /* Not generating wrapper methods for PPB_Flash_FontFile_0_1 */
 
 /* Not generating wrapper methods for PPB_FlashFullscreen_0_1 */
@@ -2990,6 +3008,40 @@
 
 /* End wrapper methods for PPB_TCPServerSocket_Private_0_1 */
 
+/* Begin wrapper methods for PPB_TCPServerSocket_Private_0_2 */
+
+static PP_Resource Pnacl_M28_PPB_TCPServerSocket_Private_Create(PP_Instance instance) {
+  const struct PPB_TCPServerSocket_Private_0_2 *iface = Pnacl_WrapperInfo_PPB_TCPServerSocket_Private_0_2.real_iface;
+  return iface->Create(instance);
+}
+
+static PP_Bool Pnacl_M28_PPB_TCPServerSocket_Private_IsTCPServerSocket(PP_Resource resource) {
+  const struct PPB_TCPServerSocket_Private_0_2 *iface = Pnacl_WrapperInfo_PPB_TCPServerSocket_Private_0_2.real_iface;
+  return iface->IsTCPServerSocket(resource);
+}
+
+static int32_t Pnacl_M28_PPB_TCPServerSocket_Private_Listen(PP_Resource tcp_server_socket, const struct PP_NetAddress_Private* addr, int32_t backlog, struct PP_CompletionCallback* callback) {
+  const struct PPB_TCPServerSocket_Private_0_2 *iface = Pnacl_WrapperInfo_PPB_TCPServerSocket_Private_0_2.real_iface;
+  return iface->Listen(tcp_server_socket, addr, backlog, *callback);
+}
+
+static int32_t Pnacl_M28_PPB_TCPServerSocket_Private_Accept(PP_Resource tcp_server_socket, PP_Resource* tcp_socket, struct PP_CompletionCallback* callback) {
+  const struct PPB_TCPServerSocket_Private_0_2 *iface = Pnacl_WrapperInfo_PPB_TCPServerSocket_Private_0_2.real_iface;
+  return iface->Accept(tcp_server_socket, tcp_socket, *callback);
+}
+
+static int32_t Pnacl_M28_PPB_TCPServerSocket_Private_GetLocalAddress(PP_Resource tcp_server_socket, struct PP_NetAddress_Private* addr) {
+  const struct PPB_TCPServerSocket_Private_0_2 *iface = Pnacl_WrapperInfo_PPB_TCPServerSocket_Private_0_2.real_iface;
+  return iface->GetLocalAddress(tcp_server_socket, addr);
+}
+
+static void Pnacl_M28_PPB_TCPServerSocket_Private_StopListening(PP_Resource tcp_server_socket) {
+  const struct PPB_TCPServerSocket_Private_0_2 *iface = Pnacl_WrapperInfo_PPB_TCPServerSocket_Private_0_2.real_iface;
+  iface->StopListening(tcp_server_socket);
+}
+
+/* End wrapper methods for PPB_TCPServerSocket_Private_0_2 */
+
 /* Begin wrapper methods for PPB_TCPSocket_Private_0_3 */
 
 static PP_Resource Pnacl_M17_PPB_TCPSocket_Private_Create(PP_Instance instance) {
@@ -3618,6 +3670,110 @@
 
 /* End wrapper methods for PPB_Ext_Socket_Dev_0_1 */
 
+/* Begin wrapper methods for PPB_Ext_Socket_Dev_0_2 */
+
+static int32_t Pnacl_M29_PPB_Ext_Socket_Dev_Create(PP_Instance instance, PP_Ext_Socket_SocketType_Dev type, PP_Ext_Socket_CreateOptions_Dev options, PP_Ext_Socket_CreateInfo_Dev* create_info, struct PP_CompletionCallback* callback) {
+  const struct PPB_Ext_Socket_Dev_0_2 *iface = Pnacl_WrapperInfo_PPB_Ext_Socket_Dev_0_2.real_iface;
+  return iface->Create(instance, type, options, create_info, *callback);
+}
+
+static void Pnacl_M29_PPB_Ext_Socket_Dev_Destroy(PP_Instance instance, struct PP_Var* socket_id) {
+  const struct PPB_Ext_Socket_Dev_0_2 *iface = Pnacl_WrapperInfo_PPB_Ext_Socket_Dev_0_2.real_iface;
+  iface->Destroy(instance, *socket_id);
+}
+
+static int32_t Pnacl_M29_PPB_Ext_Socket_Dev_Connect(PP_Instance instance, struct PP_Var* socket_id, struct PP_Var* hostname, struct PP_Var* port, struct PP_Var* result, struct PP_CompletionCallback* callback) {
+  const struct PPB_Ext_Socket_Dev_0_2 *iface = Pnacl_WrapperInfo_PPB_Ext_Socket_Dev_0_2.real_iface;
+  return iface->Connect(instance, *socket_id, *hostname, *port, result, *callback);
+}
+
+static int32_t Pnacl_M29_PPB_Ext_Socket_Dev_Bind(PP_Instance instance, struct PP_Var* socket_id, struct PP_Var* address, struct PP_Var* port, struct PP_Var* result, struct PP_CompletionCallback* callback) {
+  const struct PPB_Ext_Socket_Dev_0_2 *iface = Pnacl_WrapperInfo_PPB_Ext_Socket_Dev_0_2.real_iface;
+  return iface->Bind(instance, *socket_id, *address, *port, result, *callback);
+}
+
+static void Pnacl_M29_PPB_Ext_Socket_Dev_Disconnect(PP_Instance instance, struct PP_Var* socket_id) {
+  const struct PPB_Ext_Socket_Dev_0_2 *iface = Pnacl_WrapperInfo_PPB_Ext_Socket_Dev_0_2.real_iface;
+  iface->Disconnect(instance, *socket_id);
+}
+
+static int32_t Pnacl_M29_PPB_Ext_Socket_Dev_Read(PP_Instance instance, struct PP_Var* socket_id, struct PP_Var* buffer_size, PP_Ext_Socket_ReadInfo_Dev* read_info, struct PP_CompletionCallback* callback) {
+  const struct PPB_Ext_Socket_Dev_0_2 *iface = Pnacl_WrapperInfo_PPB_Ext_Socket_Dev_0_2.real_iface;
+  return iface->Read(instance, *socket_id, *buffer_size, read_info, *callback);
+}
+
+static int32_t Pnacl_M29_PPB_Ext_Socket_Dev_Write(PP_Instance instance, struct PP_Var* socket_id, struct PP_Var* data, PP_Ext_Socket_WriteInfo_Dev* write_info, struct PP_CompletionCallback* callback) {
+  const struct PPB_Ext_Socket_Dev_0_2 *iface = Pnacl_WrapperInfo_PPB_Ext_Socket_Dev_0_2.real_iface;
+  return iface->Write(instance, *socket_id, *data, write_info, *callback);
+}
+
+static int32_t Pnacl_M29_PPB_Ext_Socket_Dev_RecvFrom(PP_Instance instance, struct PP_Var* socket_id, struct PP_Var* buffer_size, PP_Ext_Socket_RecvFromInfo_Dev* recv_from_info, struct PP_CompletionCallback* callback) {
+  const struct PPB_Ext_Socket_Dev_0_2 *iface = Pnacl_WrapperInfo_PPB_Ext_Socket_Dev_0_2.real_iface;
+  return iface->RecvFrom(instance, *socket_id, *buffer_size, recv_from_info, *callback);
+}
+
+static int32_t Pnacl_M29_PPB_Ext_Socket_Dev_SendTo(PP_Instance instance, struct PP_Var* socket_id, struct PP_Var* data, struct PP_Var* address, struct PP_Var* port, PP_Ext_Socket_WriteInfo_Dev* write_info, struct PP_CompletionCallback* callback) {
+  const struct PPB_Ext_Socket_Dev_0_2 *iface = Pnacl_WrapperInfo_PPB_Ext_Socket_Dev_0_2.real_iface;
+  return iface->SendTo(instance, *socket_id, *data, *address, *port, write_info, *callback);
+}
+
+static int32_t Pnacl_M29_PPB_Ext_Socket_Dev_Listen(PP_Instance instance, struct PP_Var* socket_id, struct PP_Var* address, struct PP_Var* port, struct PP_Var* backlog, struct PP_Var* result, struct PP_CompletionCallback* callback) {
+  const struct PPB_Ext_Socket_Dev_0_2 *iface = Pnacl_WrapperInfo_PPB_Ext_Socket_Dev_0_2.real_iface;
+  return iface->Listen(instance, *socket_id, *address, *port, *backlog, result, *callback);
+}
+
+static int32_t Pnacl_M29_PPB_Ext_Socket_Dev_Accept(PP_Instance instance, struct PP_Var* socket_id, PP_Ext_Socket_AcceptInfo_Dev* accept_info, struct PP_CompletionCallback* callback) {
+  const struct PPB_Ext_Socket_Dev_0_2 *iface = Pnacl_WrapperInfo_PPB_Ext_Socket_Dev_0_2.real_iface;
+  return iface->Accept(instance, *socket_id, accept_info, *callback);
+}
+
+static int32_t Pnacl_M29_PPB_Ext_Socket_Dev_SetKeepAlive(PP_Instance instance, struct PP_Var* socket_id, struct PP_Var* enable, struct PP_Var* delay, struct PP_Var* result, struct PP_CompletionCallback* callback) {
+  const struct PPB_Ext_Socket_Dev_0_2 *iface = Pnacl_WrapperInfo_PPB_Ext_Socket_Dev_0_2.real_iface;
+  return iface->SetKeepAlive(instance, *socket_id, *enable, *delay, result, *callback);
+}
+
+static int32_t Pnacl_M29_PPB_Ext_Socket_Dev_SetNoDelay(PP_Instance instance, struct PP_Var* socket_id, struct PP_Var* no_delay, struct PP_Var* result, struct PP_CompletionCallback* callback) {
+  const struct PPB_Ext_Socket_Dev_0_2 *iface = Pnacl_WrapperInfo_PPB_Ext_Socket_Dev_0_2.real_iface;
+  return iface->SetNoDelay(instance, *socket_id, *no_delay, result, *callback);
+}
+
+static int32_t Pnacl_M29_PPB_Ext_Socket_Dev_GetInfo(PP_Instance instance, struct PP_Var* socket_id, PP_Ext_Socket_SocketInfo_Dev* result, struct PP_CompletionCallback* callback) {
+  const struct PPB_Ext_Socket_Dev_0_2 *iface = Pnacl_WrapperInfo_PPB_Ext_Socket_Dev_0_2.real_iface;
+  return iface->GetInfo(instance, *socket_id, result, *callback);
+}
+
+static int32_t Pnacl_M29_PPB_Ext_Socket_Dev_GetNetworkList(PP_Instance instance, PP_Ext_Socket_NetworkInterface_Dev_Array* result, struct PP_CompletionCallback* callback) {
+  const struct PPB_Ext_Socket_Dev_0_2 *iface = Pnacl_WrapperInfo_PPB_Ext_Socket_Dev_0_2.real_iface;
+  return iface->GetNetworkList(instance, result, *callback);
+}
+
+static int32_t Pnacl_M29_PPB_Ext_Socket_Dev_JoinGroup(PP_Instance instance, struct PP_Var* socket_id, struct PP_Var* address, struct PP_Var* result, struct PP_CompletionCallback* callback) {
+  const struct PPB_Ext_Socket_Dev_0_2 *iface = Pnacl_WrapperInfo_PPB_Ext_Socket_Dev_0_2.real_iface;
+  return iface->JoinGroup(instance, *socket_id, *address, result, *callback);
+}
+
+static int32_t Pnacl_M29_PPB_Ext_Socket_Dev_LeaveGroup(PP_Instance instance, struct PP_Var* socket_id, struct PP_Var* address, struct PP_Var* result, struct PP_CompletionCallback* callback) {
+  const struct PPB_Ext_Socket_Dev_0_2 *iface = Pnacl_WrapperInfo_PPB_Ext_Socket_Dev_0_2.real_iface;
+  return iface->LeaveGroup(instance, *socket_id, *address, result, *callback);
+}
+
+static int32_t Pnacl_M29_PPB_Ext_Socket_Dev_SetMulticastTimeToLive(PP_Instance instance, struct PP_Var* socket_id, struct PP_Var* ttl, struct PP_Var* result, struct PP_CompletionCallback* callback) {
+  const struct PPB_Ext_Socket_Dev_0_2 *iface = Pnacl_WrapperInfo_PPB_Ext_Socket_Dev_0_2.real_iface;
+  return iface->SetMulticastTimeToLive(instance, *socket_id, *ttl, result, *callback);
+}
+
+static int32_t Pnacl_M29_PPB_Ext_Socket_Dev_SetMulticastLoopbackMode(PP_Instance instance, struct PP_Var* socket_id, struct PP_Var* enabled, struct PP_Var* result, struct PP_CompletionCallback* callback) {
+  const struct PPB_Ext_Socket_Dev_0_2 *iface = Pnacl_WrapperInfo_PPB_Ext_Socket_Dev_0_2.real_iface;
+  return iface->SetMulticastLoopbackMode(instance, *socket_id, *enabled, result, *callback);
+}
+
+static int32_t Pnacl_M29_PPB_Ext_Socket_Dev_GetJoinedGroups(PP_Instance instance, struct PP_Var* socket_id, struct PP_Var* groups, struct PP_CompletionCallback* callback) {
+  const struct PPB_Ext_Socket_Dev_0_2 *iface = Pnacl_WrapperInfo_PPB_Ext_Socket_Dev_0_2.real_iface;
+  return iface->GetJoinedGroups(instance, *socket_id, groups, *callback);
+}
+
+/* End wrapper methods for PPB_Ext_Socket_Dev_0_2 */
+
 /* Not generating wrapper interface for PPB_Audio_1_0 */
 
 /* Not generating wrapper interface for PPB_AudioConfig_1_0 */
@@ -4319,6 +4475,11 @@
     .GetDeviceID = (int32_t (*)(PP_Resource device_id, struct PP_Var* id, struct PP_CompletionCallback callback))&Pnacl_M21_PPB_Flash_DeviceID_GetDeviceID
 };
 
+struct PPB_Flash_DRM_1_0 Pnacl_Wrappers_PPB_Flash_DRM_1_0 = {
+    .Create = (PP_Resource (*)(PP_Instance instance))&Pnacl_M29_PPB_Flash_DRM_Create,
+    .GetDeviceID = (int32_t (*)(PP_Resource drm, struct PP_Var* id, struct PP_CompletionCallback callback))&Pnacl_M29_PPB_Flash_DRM_GetDeviceID
+};
+
 /* Not generating wrapper interface for PPB_Flash_FontFile_0_1 */
 
 /* Not generating wrapper interface for PPB_FlashFullscreen_0_1 */
@@ -4413,6 +4574,15 @@
     .StopListening = (void (*)(PP_Resource tcp_server_socket))&Pnacl_M18_PPB_TCPServerSocket_Private_StopListening
 };
 
+struct PPB_TCPServerSocket_Private_0_2 Pnacl_Wrappers_PPB_TCPServerSocket_Private_0_2 = {
+    .Create = (PP_Resource (*)(PP_Instance instance))&Pnacl_M28_PPB_TCPServerSocket_Private_Create,
+    .IsTCPServerSocket = (PP_Bool (*)(PP_Resource resource))&Pnacl_M28_PPB_TCPServerSocket_Private_IsTCPServerSocket,
+    .Listen = (int32_t (*)(PP_Resource tcp_server_socket, const struct PP_NetAddress_Private* addr, int32_t backlog, struct PP_CompletionCallback callback))&Pnacl_M28_PPB_TCPServerSocket_Private_Listen,
+    .Accept = (int32_t (*)(PP_Resource tcp_server_socket, PP_Resource* tcp_socket, struct PP_CompletionCallback callback))&Pnacl_M28_PPB_TCPServerSocket_Private_Accept,
+    .GetLocalAddress = (int32_t (*)(PP_Resource tcp_server_socket, struct PP_NetAddress_Private* addr))&Pnacl_M28_PPB_TCPServerSocket_Private_GetLocalAddress,
+    .StopListening = (void (*)(PP_Resource tcp_server_socket))&Pnacl_M28_PPB_TCPServerSocket_Private_StopListening
+};
+
 struct PPB_TCPSocket_Private_0_3 Pnacl_Wrappers_PPB_TCPSocket_Private_0_3 = {
     .Create = (PP_Resource (*)(PP_Instance instance))&Pnacl_M17_PPB_TCPSocket_Private_Create,
     .IsTCPSocket = (PP_Bool (*)(PP_Resource resource))&Pnacl_M17_PPB_TCPSocket_Private_IsTCPSocket,
@@ -4572,6 +4742,29 @@
     .GetNetworkList = (int32_t (*)(PP_Instance instance, PP_Ext_Socket_NetworkInterface_Dev_Array* result, struct PP_CompletionCallback callback))&Pnacl_M28_PPB_Ext_Socket_Dev_GetNetworkList
 };
 
+struct PPB_Ext_Socket_Dev_0_2 Pnacl_Wrappers_PPB_Ext_Socket_Dev_0_2 = {
+    .Create = (int32_t (*)(PP_Instance instance, PP_Ext_Socket_SocketType_Dev type, PP_Ext_Socket_CreateOptions_Dev options, PP_Ext_Socket_CreateInfo_Dev* create_info, struct PP_CompletionCallback callback))&Pnacl_M29_PPB_Ext_Socket_Dev_Create,
+    .Destroy = (void (*)(PP_Instance instance, struct PP_Var socket_id))&Pnacl_M29_PPB_Ext_Socket_Dev_Destroy,
+    .Connect = (int32_t (*)(PP_Instance instance, struct PP_Var socket_id, struct PP_Var hostname, struct PP_Var port, struct PP_Var* result, struct PP_CompletionCallback callback))&Pnacl_M29_PPB_Ext_Socket_Dev_Connect,
+    .Bind = (int32_t (*)(PP_Instance instance, struct PP_Var socket_id, struct PP_Var address, struct PP_Var port, struct PP_Var* result, struct PP_CompletionCallback callback))&Pnacl_M29_PPB_Ext_Socket_Dev_Bind,
+    .Disconnect = (void (*)(PP_Instance instance, struct PP_Var socket_id))&Pnacl_M29_PPB_Ext_Socket_Dev_Disconnect,
+    .Read = (int32_t (*)(PP_Instance instance, struct PP_Var socket_id, struct PP_Var buffer_size, PP_Ext_Socket_ReadInfo_Dev* read_info, struct PP_CompletionCallback callback))&Pnacl_M29_PPB_Ext_Socket_Dev_Read,
+    .Write = (int32_t (*)(PP_Instance instance, struct PP_Var socket_id, struct PP_Var data, PP_Ext_Socket_WriteInfo_Dev* write_info, struct PP_CompletionCallback callback))&Pnacl_M29_PPB_Ext_Socket_Dev_Write,
+    .RecvFrom = (int32_t (*)(PP_Instance instance, struct PP_Var socket_id, struct PP_Var buffer_size, PP_Ext_Socket_RecvFromInfo_Dev* recv_from_info, struct PP_CompletionCallback callback))&Pnacl_M29_PPB_Ext_Socket_Dev_RecvFrom,
+    .SendTo = (int32_t (*)(PP_Instance instance, struct PP_Var socket_id, struct PP_Var data, struct PP_Var address, struct PP_Var port, PP_Ext_Socket_WriteInfo_Dev* write_info, struct PP_CompletionCallback callback))&Pnacl_M29_PPB_Ext_Socket_Dev_SendTo,
+    .Listen = (int32_t (*)(PP_Instance instance, struct PP_Var socket_id, struct PP_Var address, struct PP_Var port, struct PP_Var backlog, struct PP_Var* result, struct PP_CompletionCallback callback))&Pnacl_M29_PPB_Ext_Socket_Dev_Listen,
+    .Accept = (int32_t (*)(PP_Instance instance, struct PP_Var socket_id, PP_Ext_Socket_AcceptInfo_Dev* accept_info, struct PP_CompletionCallback callback))&Pnacl_M29_PPB_Ext_Socket_Dev_Accept,
+    .SetKeepAlive = (int32_t (*)(PP_Instance instance, struct PP_Var socket_id, struct PP_Var enable, struct PP_Var delay, struct PP_Var* result, struct PP_CompletionCallback callback))&Pnacl_M29_PPB_Ext_Socket_Dev_SetKeepAlive,
+    .SetNoDelay = (int32_t (*)(PP_Instance instance, struct PP_Var socket_id, struct PP_Var no_delay, struct PP_Var* result, struct PP_CompletionCallback callback))&Pnacl_M29_PPB_Ext_Socket_Dev_SetNoDelay,
+    .GetInfo = (int32_t (*)(PP_Instance instance, struct PP_Var socket_id, PP_Ext_Socket_SocketInfo_Dev* result, struct PP_CompletionCallback callback))&Pnacl_M29_PPB_Ext_Socket_Dev_GetInfo,
+    .GetNetworkList = (int32_t (*)(PP_Instance instance, PP_Ext_Socket_NetworkInterface_Dev_Array* result, struct PP_CompletionCallback callback))&Pnacl_M29_PPB_Ext_Socket_Dev_GetNetworkList,
+    .JoinGroup = (int32_t (*)(PP_Instance instance, struct PP_Var socket_id, struct PP_Var address, struct PP_Var* result, struct PP_CompletionCallback callback))&Pnacl_M29_PPB_Ext_Socket_Dev_JoinGroup,
+    .LeaveGroup = (int32_t (*)(PP_Instance instance, struct PP_Var socket_id, struct PP_Var address, struct PP_Var* result, struct PP_CompletionCallback callback))&Pnacl_M29_PPB_Ext_Socket_Dev_LeaveGroup,
+    .SetMulticastTimeToLive = (int32_t (*)(PP_Instance instance, struct PP_Var socket_id, struct PP_Var ttl, struct PP_Var* result, struct PP_CompletionCallback callback))&Pnacl_M29_PPB_Ext_Socket_Dev_SetMulticastTimeToLive,
+    .SetMulticastLoopbackMode = (int32_t (*)(PP_Instance instance, struct PP_Var socket_id, struct PP_Var enabled, struct PP_Var* result, struct PP_CompletionCallback callback))&Pnacl_M29_PPB_Ext_Socket_Dev_SetMulticastLoopbackMode,
+    .GetJoinedGroups = (int32_t (*)(PP_Instance instance, struct PP_Var socket_id, struct PP_Var* groups, struct PP_CompletionCallback callback))&Pnacl_M29_PPB_Ext_Socket_Dev_GetJoinedGroups
+};
+
 static struct __PnaclWrapperInfo Pnacl_WrapperInfo_PPB_Audio_1_0 = {
   .iface_macro = PPB_AUDIO_INTERFACE_1_0,
   .wrapped_iface = NULL /* Still need slot for real_iface */,
@@ -5256,6 +5449,12 @@
   .real_iface = NULL
 };
 
+static struct __PnaclWrapperInfo Pnacl_WrapperInfo_PPB_Flash_DRM_1_0 = {
+  .iface_macro = PPB_FLASH_DRM_INTERFACE_1_0,
+  .wrapped_iface = (void *) &Pnacl_Wrappers_PPB_Flash_DRM_1_0,
+  .real_iface = NULL
+};
+
 static struct __PnaclWrapperInfo Pnacl_WrapperInfo_PPB_Flash_FontFile_0_1 = {
   .iface_macro = PPB_FLASH_FONTFILE_INTERFACE_0_1,
   .wrapped_iface = NULL /* Still need slot for real_iface */,
@@ -5358,6 +5557,12 @@
   .real_iface = NULL
 };
 
+static struct __PnaclWrapperInfo Pnacl_WrapperInfo_PPB_TCPServerSocket_Private_0_2 = {
+  .iface_macro = PPB_TCPSERVERSOCKET_PRIVATE_INTERFACE_0_2,
+  .wrapped_iface = (void *) &Pnacl_Wrappers_PPB_TCPServerSocket_Private_0_2,
+  .real_iface = NULL
+};
+
 static struct __PnaclWrapperInfo Pnacl_WrapperInfo_PPB_TCPSocket_Private_0_3 = {
   .iface_macro = PPB_TCPSOCKET_PRIVATE_INTERFACE_0_3,
   .wrapped_iface = (void *) &Pnacl_Wrappers_PPB_TCPSocket_Private_0_3,
@@ -5466,6 +5671,12 @@
   .real_iface = NULL
 };
 
+static struct __PnaclWrapperInfo Pnacl_WrapperInfo_PPB_Ext_Socket_Dev_0_2 = {
+  .iface_macro = PPB_EXT_SOCKET_DEV_INTERFACE_0_2,
+  .wrapped_iface = (void *) &Pnacl_Wrappers_PPB_Ext_Socket_Dev_0_2,
+  .real_iface = NULL
+};
+
 static struct __PnaclWrapperInfo *s_ppb_wrappers[] = {
   &Pnacl_WrapperInfo_PPB_Audio_1_0,
   &Pnacl_WrapperInfo_PPB_AudioConfig_1_0,
@@ -5563,6 +5774,7 @@
   &Pnacl_WrapperInfo_PPB_Flash_Clipboard_4_0,
   &Pnacl_WrapperInfo_PPB_Flash_Clipboard_5_0,
   &Pnacl_WrapperInfo_PPB_Flash_DeviceID_1_0,
+  &Pnacl_WrapperInfo_PPB_Flash_DRM_1_0,
   &Pnacl_WrapperInfo_PPB_Flash_FontFile_0_1,
   &Pnacl_WrapperInfo_PPB_FlashFullscreen_0_1,
   &Pnacl_WrapperInfo_PPB_FlashFullscreen_1_0,
@@ -5580,6 +5792,7 @@
   &Pnacl_WrapperInfo_PPB_NetworkMonitor_Private_0_2,
   &Pnacl_WrapperInfo_PPB_Talk_Private_1_0,
   &Pnacl_WrapperInfo_PPB_TCPServerSocket_Private_0_1,
+  &Pnacl_WrapperInfo_PPB_TCPServerSocket_Private_0_2,
   &Pnacl_WrapperInfo_PPB_TCPSocket_Private_0_3,
   &Pnacl_WrapperInfo_PPB_TCPSocket_Private_0_4,
   &Pnacl_WrapperInfo_PPB_TCPSocket_Private_0_5,
@@ -5593,6 +5806,7 @@
   &Pnacl_WrapperInfo_PPB_Ext_Alarms_Dev_0_1,
   &Pnacl_WrapperInfo_PPB_Ext_Events_Dev_0_1,
   &Pnacl_WrapperInfo_PPB_Ext_Socket_Dev_0_1,
+  &Pnacl_WrapperInfo_PPB_Ext_Socket_Dev_0_2,
   NULL
 };
 
diff --git a/ppapi/native_client/src/untrusted/pnacl_support_extension/pnacl_component_crx_gen.py b/ppapi/native_client/src/untrusted/pnacl_support_extension/pnacl_component_crx_gen.py
index ee65a17..18a5ba0 100755
--- a/ppapi/native_client/src/untrusted/pnacl_support_extension/pnacl_component_crx_gen.py
+++ b/ppapi/native_client/src/untrusted/pnacl_support_extension/pnacl_component_crx_gen.py
@@ -361,7 +361,7 @@
                                    [],
                                    False)
   CRXGen.RunCRXGen(options.chrome_path, ext_dir)
-  shutil.copy2(J(tempdir, 'dummy_extension.pem'),
+  shutil.copy(J(tempdir, 'dummy_extension.pem'),
                PnaclDirs.OutputDir())
   shutil.rmtree(tempdir)
   logging.info('\n<<< Fresh key is now in %s/dummy_extension.pem >>>\n' %
@@ -392,7 +392,7 @@
   if arch in lib_overrides:
     for override in lib_overrides[arch]:
       logging.info('Copying override %s to %s' % (override, target_dir))
-      shutil.copy2(override, target_dir)
+      shutil.copy(override, target_dir)
 
   # Skip the CRX generation if we are only building the unpacked version
   # for commandline testing.
@@ -507,7 +507,7 @@
       assert (f == os.path.basename(f))
       full_name = J(root, f)
       target_name = UseWhitelistedChars(f, arch)
-      shutil.copy2(full_name, J(dest_dir, target_name))
+      shutil.copy(full_name, J(dest_dir, target_name))
 
 
 def BuildArchForInstaller(version_quad, arch, lib_overrides, options):
@@ -532,7 +532,7 @@
     for override in lib_overrides[arch]:
       override_base = os.path.basename(override)
       target_name = UseWhitelistedChars(override_base, arch)
-      shutil.copy2(override, J(target_dir, target_name))
+      shutil.copy(override, J(target_dir, target_name))
 
 
 def BuildInstallerStyle(version_quad, lib_overrides, options):
diff --git a/ppapi/native_client/src/untrusted/pnacl_support_extension/pnacl_info_template.json b/ppapi/native_client/src/untrusted/pnacl_support_extension/pnacl_info_template.json
index 380fc6b..0aa66e9 100644
--- a/ppapi/native_client/src/untrusted/pnacl_support_extension/pnacl_info_template.json
+++ b/ppapi/native_client/src/untrusted/pnacl_support_extension/pnacl_info_template.json
@@ -1,4 +1,6 @@
 {
   "abi-version": "%(abi-version)s",
-  "pnacl-arch": "%(arch)s"
+  "pnacl-arch": "%(arch)s",
+  "pnacl-llc-name": "llc.nexe",
+  "pnacl-ld-name": "ld.nexe"
 }
diff --git a/ppapi/ppapi_c.target.darwin-arm.mk b/ppapi/ppapi_c.target.darwin-arm.mk
index 80ac9ba..82e28e6 100644
--- a/ppapi/ppapi_c.target.darwin-arm.mk
+++ b/ppapi/ppapi_c.target.darwin-arm.mk
@@ -66,6 +66,7 @@
 	'-DNO_TCMALLOC' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
+	'-DENABLE_DOUBLE_RESOURCE_LOAD_TIMING' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_GPU=1' \
@@ -87,9 +88,9 @@
 
 # Include paths placed before CFLAGS/CPPFLAGS
 LOCAL_C_INCLUDES := \
-	$(GYP_ABS_ANDROID_TOP_DIR)/frameworks/wilhelm/include \
-	$(GYP_ABS_ANDROID_TOP_DIR)/bionic \
-	$(GYP_ABS_ANDROID_TOP_DIR)/external/stlport/stlport
+	$(PWD)/frameworks/wilhelm/include \
+	$(PWD)/bionic \
+	$(PWD)/external/stlport/stlport
 
 LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES)
 
diff --git a/ppapi/ppapi_c.target.darwin-x86.mk b/ppapi/ppapi_c.target.darwin-x86.mk
index 1ab465e..c1ffb4d 100644
--- a/ppapi/ppapi_c.target.darwin-x86.mk
+++ b/ppapi/ppapi_c.target.darwin-x86.mk
@@ -68,6 +68,7 @@
 	'-DNO_TCMALLOC' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
+	'-DENABLE_DOUBLE_RESOURCE_LOAD_TIMING' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_GPU=1' \
@@ -89,9 +90,9 @@
 
 # Include paths placed before CFLAGS/CPPFLAGS
 LOCAL_C_INCLUDES := \
-	$(GYP_ABS_ANDROID_TOP_DIR)/frameworks/wilhelm/include \
-	$(GYP_ABS_ANDROID_TOP_DIR)/bionic \
-	$(GYP_ABS_ANDROID_TOP_DIR)/external/stlport/stlport
+	$(PWD)/frameworks/wilhelm/include \
+	$(PWD)/bionic \
+	$(PWD)/external/stlport/stlport
 
 LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES)
 
diff --git a/ppapi/ppapi_c.target.linux-arm.mk b/ppapi/ppapi_c.target.linux-arm.mk
index 80ac9ba..82e28e6 100644
--- a/ppapi/ppapi_c.target.linux-arm.mk
+++ b/ppapi/ppapi_c.target.linux-arm.mk
@@ -66,6 +66,7 @@
 	'-DNO_TCMALLOC' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
+	'-DENABLE_DOUBLE_RESOURCE_LOAD_TIMING' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_GPU=1' \
@@ -87,9 +88,9 @@
 
 # Include paths placed before CFLAGS/CPPFLAGS
 LOCAL_C_INCLUDES := \
-	$(GYP_ABS_ANDROID_TOP_DIR)/frameworks/wilhelm/include \
-	$(GYP_ABS_ANDROID_TOP_DIR)/bionic \
-	$(GYP_ABS_ANDROID_TOP_DIR)/external/stlport/stlport
+	$(PWD)/frameworks/wilhelm/include \
+	$(PWD)/bionic \
+	$(PWD)/external/stlport/stlport
 
 LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES)
 
diff --git a/ppapi/ppapi_c.target.linux-x86.mk b/ppapi/ppapi_c.target.linux-x86.mk
index 1ab465e..c1ffb4d 100644
--- a/ppapi/ppapi_c.target.linux-x86.mk
+++ b/ppapi/ppapi_c.target.linux-x86.mk
@@ -68,6 +68,7 @@
 	'-DNO_TCMALLOC' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
+	'-DENABLE_DOUBLE_RESOURCE_LOAD_TIMING' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_GPU=1' \
@@ -89,9 +90,9 @@
 
 # Include paths placed before CFLAGS/CPPFLAGS
 LOCAL_C_INCLUDES := \
-	$(GYP_ABS_ANDROID_TOP_DIR)/frameworks/wilhelm/include \
-	$(GYP_ABS_ANDROID_TOP_DIR)/bionic \
-	$(GYP_ABS_ANDROID_TOP_DIR)/external/stlport/stlport
+	$(PWD)/frameworks/wilhelm/include \
+	$(PWD)/bionic \
+	$(PWD)/external/stlport/stlport
 
 LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES)
 
diff --git a/ppapi/ppapi_proxy.gypi b/ppapi/ppapi_proxy.gypi
index 242f899..f426cbe 100644
--- a/ppapi/ppapi_proxy.gypi
+++ b/ppapi/ppapi_proxy.gypi
@@ -43,8 +43,8 @@
           'proxy/file_chooser_resource.h',
           'proxy/flash_clipboard_resource.cc',
           'proxy/flash_clipboard_resource.h',
-          'proxy/flash_device_id_resource.cc',
-          'proxy/flash_device_id_resource.h',
+          'proxy/flash_drm_resource.cc',
+          'proxy/flash_drm_resource.h',
           'proxy/flash_file_resource.cc',
           'proxy/flash_file_resource.h',
           'proxy/flash_font_file_resource.cc',
@@ -125,8 +125,6 @@
           'proxy/ppb_tcp_socket_private_proxy.h',
           'proxy/ppb_testing_proxy.cc',
           'proxy/ppb_testing_proxy.h',
-          'proxy/ppb_url_loader_proxy.cc',
-          'proxy/ppb_url_loader_proxy.h',
           'proxy/ppb_var_deprecated_proxy.cc',
           'proxy/ppb_var_deprecated_proxy.h',
           'proxy/ppb_video_decoder_proxy.cc',
@@ -176,6 +174,8 @@
           'proxy/truetype_font_singleton_resource.h',
           'proxy/udp_socket_private_resource.cc',
           'proxy/udp_socket_private_resource.h',
+          'proxy/url_loader_resource.cc',
+          'proxy/url_loader_resource.h',
           'proxy/url_request_info_resource.cc',
           'proxy/url_request_info_resource.h',
           'proxy/url_response_info_resource.cc',
@@ -205,7 +205,7 @@
               'proxy/browser_font_singleton_resource.cc',
               'proxy/device_enumeration_resource_helper.cc',
               'proxy/flash_clipboard_resource.cc',
-              'proxy/flash_device_id_resource.cc',
+              'proxy/flash_drm_resource.cc',
               'proxy/flash_file_resource.cc',
               'proxy/flash_font_file_resource.cc',
               'proxy/flash_fullscreen_resource.cc',
diff --git a/ppapi/ppapi_shared.gypi b/ppapi/ppapi_shared.gypi
index 0d2e478..5f6ad46 100644
--- a/ppapi/ppapi_shared.gypi
+++ b/ppapi/ppapi_shared.gypi
@@ -112,6 +112,7 @@
           'shared_impl/var_value_conversions.h',
           # TODO(viettrungluu): Split these out; it won't be used in NaCl.
           'shared_impl/private/net_address_private_impl.cc',
+          'shared_impl/private/net_address_private_impl_constants.cc',
           'shared_impl/private/net_address_private_impl.h',
 
           'shared_impl/private/ppb_char_set_shared.cc',
@@ -164,8 +165,9 @@
           'thunk/ppb_find_dev_thunk.cc',
           'thunk/ppb_flash_clipboard_api.h',
           'thunk/ppb_flash_clipboard_thunk.cc',
-          'thunk/ppb_flash_device_id_api.h',
           'thunk/ppb_flash_device_id_thunk.cc',
+          'thunk/ppb_flash_drm_api.h',
+          'thunk/ppb_flash_drm_thunk.cc',
           'thunk/ppb_flash_file_fileref_thunk.cc',
           'thunk/ppb_flash_file_modulelocal_thunk.cc',
           'thunk/ppb_flash_font_file_api.h',
@@ -284,6 +286,7 @@
               'thunk/ppb_file_io_trusted_thunk.cc',
               'thunk/ppb_flash_clipboard_thunk.cc',
               'thunk/ppb_flash_device_id_thunk.cc',
+              'thunk/ppb_flash_drm_thunk.cc',
               'thunk/ppb_flash_file_fileref_thunk.cc',
               'thunk/ppb_flash_file_modulelocal_thunk.cc',
               'thunk/ppb_flash_font_file_thunk.cc',
diff --git a/ppapi/ppapi_shared.target.darwin-arm.mk b/ppapi/ppapi_shared.target.darwin-arm.mk
index b2457c1..0fba5fa 100644
--- a/ppapi/ppapi_shared.target.darwin-arm.mk
+++ b/ppapi/ppapi_shared.target.darwin-arm.mk
@@ -77,6 +77,7 @@
 	ppapi/shared_impl/var_tracker.cc \
 	ppapi/shared_impl/var_value_conversions.cc \
 	ppapi/shared_impl/private/net_address_private_impl.cc \
+	ppapi/shared_impl/private/net_address_private_impl_constants.cc \
 	ppapi/shared_impl/private/ppb_char_set_shared.cc \
 	ppapi/shared_impl/private/ppb_tcp_server_socket_shared.cc \
 	ppapi/shared_impl/private/ppb_x509_certificate_private_shared.cc \
@@ -108,6 +109,7 @@
 	ppapi/thunk/ppb_find_dev_thunk.cc \
 	ppapi/thunk/ppb_flash_clipboard_thunk.cc \
 	ppapi/thunk/ppb_flash_device_id_thunk.cc \
+	ppapi/thunk/ppb_flash_drm_thunk.cc \
 	ppapi/thunk/ppb_flash_file_fileref_thunk.cc \
 	ppapi/thunk/ppb_flash_file_modulelocal_thunk.cc \
 	ppapi/thunk/ppb_flash_font_file_thunk.cc \
@@ -204,6 +206,7 @@
 	'-DNO_TCMALLOC' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
+	'-DENABLE_DOUBLE_RESOURCE_LOAD_TIMING' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_GPU=1' \
@@ -259,11 +262,11 @@
 	$(LOCAL_PATH)/third_party/npapi \
 	$(LOCAL_PATH)/third_party/npapi/bindings \
 	$(LOCAL_PATH)/v8/include \
-	$(GYP_ABS_ANDROID_TOP_DIR)/external/icu4c/common \
-	$(GYP_ABS_ANDROID_TOP_DIR)/external/icu4c/i18n \
-	$(GYP_ABS_ANDROID_TOP_DIR)/frameworks/wilhelm/include \
-	$(GYP_ABS_ANDROID_TOP_DIR)/bionic \
-	$(GYP_ABS_ANDROID_TOP_DIR)/external/stlport/stlport
+	$(PWD)/external/icu4c/common \
+	$(PWD)/external/icu4c/i18n \
+	$(PWD)/frameworks/wilhelm/include \
+	$(PWD)/bionic \
+	$(PWD)/external/stlport/stlport
 
 LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES)
 
diff --git a/ppapi/ppapi_shared.target.darwin-x86.mk b/ppapi/ppapi_shared.target.darwin-x86.mk
index 5268cf1..2696f0b 100644
--- a/ppapi/ppapi_shared.target.darwin-x86.mk
+++ b/ppapi/ppapi_shared.target.darwin-x86.mk
@@ -77,6 +77,7 @@
 	ppapi/shared_impl/var_tracker.cc \
 	ppapi/shared_impl/var_value_conversions.cc \
 	ppapi/shared_impl/private/net_address_private_impl.cc \
+	ppapi/shared_impl/private/net_address_private_impl_constants.cc \
 	ppapi/shared_impl/private/ppb_char_set_shared.cc \
 	ppapi/shared_impl/private/ppb_tcp_server_socket_shared.cc \
 	ppapi/shared_impl/private/ppb_x509_certificate_private_shared.cc \
@@ -108,6 +109,7 @@
 	ppapi/thunk/ppb_find_dev_thunk.cc \
 	ppapi/thunk/ppb_flash_clipboard_thunk.cc \
 	ppapi/thunk/ppb_flash_device_id_thunk.cc \
+	ppapi/thunk/ppb_flash_drm_thunk.cc \
 	ppapi/thunk/ppb_flash_file_fileref_thunk.cc \
 	ppapi/thunk/ppb_flash_file_modulelocal_thunk.cc \
 	ppapi/thunk/ppb_flash_font_file_thunk.cc \
@@ -206,6 +208,7 @@
 	'-DNO_TCMALLOC' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
+	'-DENABLE_DOUBLE_RESOURCE_LOAD_TIMING' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_GPU=1' \
@@ -261,11 +264,11 @@
 	$(LOCAL_PATH)/third_party/npapi \
 	$(LOCAL_PATH)/third_party/npapi/bindings \
 	$(LOCAL_PATH)/v8/include \
-	$(GYP_ABS_ANDROID_TOP_DIR)/external/icu4c/common \
-	$(GYP_ABS_ANDROID_TOP_DIR)/external/icu4c/i18n \
-	$(GYP_ABS_ANDROID_TOP_DIR)/frameworks/wilhelm/include \
-	$(GYP_ABS_ANDROID_TOP_DIR)/bionic \
-	$(GYP_ABS_ANDROID_TOP_DIR)/external/stlport/stlport
+	$(PWD)/external/icu4c/common \
+	$(PWD)/external/icu4c/i18n \
+	$(PWD)/frameworks/wilhelm/include \
+	$(PWD)/bionic \
+	$(PWD)/external/stlport/stlport
 
 LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES)
 
diff --git a/ppapi/ppapi_shared.target.linux-arm.mk b/ppapi/ppapi_shared.target.linux-arm.mk
index b2457c1..0fba5fa 100644
--- a/ppapi/ppapi_shared.target.linux-arm.mk
+++ b/ppapi/ppapi_shared.target.linux-arm.mk
@@ -77,6 +77,7 @@
 	ppapi/shared_impl/var_tracker.cc \
 	ppapi/shared_impl/var_value_conversions.cc \
 	ppapi/shared_impl/private/net_address_private_impl.cc \
+	ppapi/shared_impl/private/net_address_private_impl_constants.cc \
 	ppapi/shared_impl/private/ppb_char_set_shared.cc \
 	ppapi/shared_impl/private/ppb_tcp_server_socket_shared.cc \
 	ppapi/shared_impl/private/ppb_x509_certificate_private_shared.cc \
@@ -108,6 +109,7 @@
 	ppapi/thunk/ppb_find_dev_thunk.cc \
 	ppapi/thunk/ppb_flash_clipboard_thunk.cc \
 	ppapi/thunk/ppb_flash_device_id_thunk.cc \
+	ppapi/thunk/ppb_flash_drm_thunk.cc \
 	ppapi/thunk/ppb_flash_file_fileref_thunk.cc \
 	ppapi/thunk/ppb_flash_file_modulelocal_thunk.cc \
 	ppapi/thunk/ppb_flash_font_file_thunk.cc \
@@ -204,6 +206,7 @@
 	'-DNO_TCMALLOC' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
+	'-DENABLE_DOUBLE_RESOURCE_LOAD_TIMING' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_GPU=1' \
@@ -259,11 +262,11 @@
 	$(LOCAL_PATH)/third_party/npapi \
 	$(LOCAL_PATH)/third_party/npapi/bindings \
 	$(LOCAL_PATH)/v8/include \
-	$(GYP_ABS_ANDROID_TOP_DIR)/external/icu4c/common \
-	$(GYP_ABS_ANDROID_TOP_DIR)/external/icu4c/i18n \
-	$(GYP_ABS_ANDROID_TOP_DIR)/frameworks/wilhelm/include \
-	$(GYP_ABS_ANDROID_TOP_DIR)/bionic \
-	$(GYP_ABS_ANDROID_TOP_DIR)/external/stlport/stlport
+	$(PWD)/external/icu4c/common \
+	$(PWD)/external/icu4c/i18n \
+	$(PWD)/frameworks/wilhelm/include \
+	$(PWD)/bionic \
+	$(PWD)/external/stlport/stlport
 
 LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES)
 
diff --git a/ppapi/ppapi_shared.target.linux-x86.mk b/ppapi/ppapi_shared.target.linux-x86.mk
index 5268cf1..2696f0b 100644
--- a/ppapi/ppapi_shared.target.linux-x86.mk
+++ b/ppapi/ppapi_shared.target.linux-x86.mk
@@ -77,6 +77,7 @@
 	ppapi/shared_impl/var_tracker.cc \
 	ppapi/shared_impl/var_value_conversions.cc \
 	ppapi/shared_impl/private/net_address_private_impl.cc \
+	ppapi/shared_impl/private/net_address_private_impl_constants.cc \
 	ppapi/shared_impl/private/ppb_char_set_shared.cc \
 	ppapi/shared_impl/private/ppb_tcp_server_socket_shared.cc \
 	ppapi/shared_impl/private/ppb_x509_certificate_private_shared.cc \
@@ -108,6 +109,7 @@
 	ppapi/thunk/ppb_find_dev_thunk.cc \
 	ppapi/thunk/ppb_flash_clipboard_thunk.cc \
 	ppapi/thunk/ppb_flash_device_id_thunk.cc \
+	ppapi/thunk/ppb_flash_drm_thunk.cc \
 	ppapi/thunk/ppb_flash_file_fileref_thunk.cc \
 	ppapi/thunk/ppb_flash_file_modulelocal_thunk.cc \
 	ppapi/thunk/ppb_flash_font_file_thunk.cc \
@@ -206,6 +208,7 @@
 	'-DNO_TCMALLOC' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
+	'-DENABLE_DOUBLE_RESOURCE_LOAD_TIMING' \
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_GPU=1' \
@@ -261,11 +264,11 @@
 	$(LOCAL_PATH)/third_party/npapi \
 	$(LOCAL_PATH)/third_party/npapi/bindings \
 	$(LOCAL_PATH)/v8/include \
-	$(GYP_ABS_ANDROID_TOP_DIR)/external/icu4c/common \
-	$(GYP_ABS_ANDROID_TOP_DIR)/external/icu4c/i18n \
-	$(GYP_ABS_ANDROID_TOP_DIR)/frameworks/wilhelm/include \
-	$(GYP_ABS_ANDROID_TOP_DIR)/bionic \
-	$(GYP_ABS_ANDROID_TOP_DIR)/external/stlport/stlport
+	$(PWD)/external/icu4c/common \
+	$(PWD)/external/icu4c/i18n \
+	$(PWD)/frameworks/wilhelm/include \
+	$(PWD)/bionic \
+	$(PWD)/external/stlport/stlport
 
 LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES)
 
diff --git a/ppapi/ppapi_sources.gypi b/ppapi/ppapi_sources.gypi
index 7ea5549..950b628 100644
--- a/ppapi/ppapi_sources.gypi
+++ b/ppapi/ppapi_sources.gypi
@@ -285,6 +285,8 @@
       'cpp/private/flash_clipboard.h',
       'cpp/private/flash_device_id.cc',
       'cpp/private/flash_device_id.h',
+      'cpp/private/flash_drm.cc',
+      'cpp/private/flash_drm.h',
       'cpp/private/flash_file.cc',
       'cpp/private/flash_file.h',
       'cpp/private/flash_font_file.cc',
@@ -497,8 +499,8 @@
       'tests/test_flash.h',
       'tests/test_flash_clipboard.cc',
       'tests/test_flash_clipboard.h',
-      'tests/test_flash_device_id.cc',
-      'tests/test_flash_device_id.h',
+      'tests/test_flash_drm.cc',
+      'tests/test_flash_drm.h',
       'tests/test_flash_file.cc',
       'tests/test_flash_file.h',
       'tests/test_flash_fullscreen.cc',
diff --git a/ppapi/ppapi_tests.gypi b/ppapi/ppapi_tests.gypi
index ffd577f..0d17f37 100644
--- a/ppapi/ppapi_tests.gypi
+++ b/ppapi/ppapi_tests.gypi
@@ -101,6 +101,8 @@
         'proxy/resource_message_test_sink.h',
         'shared_impl/test_globals.cc',
         'shared_impl/test_globals.h',
+        'shared_impl/unittest_utils.cc',
+        'shared_impl/unittest_utils.h',
       ],
     },
 
@@ -121,6 +123,14 @@
         'proxy/ppapi_perftests.cc',
         'proxy/ppp_messaging_proxy_perftest.cc',
       ],
+      'conditions': [
+        # See http://crbug.com/162998#c4 for why this is needed.
+        ['OS=="linux" and linux_use_tcmalloc==1', {
+          'dependencies': [
+            '../base/allocator/allocator.gyp:allocator',
+          ],
+        }],
+      ],
     },
     {
       'target_name': 'ppapi_unittests',
@@ -461,6 +471,16 @@
       ],
     },
     {
+      'target_name': 'ppapi_example_video_effects',
+      'dependencies': [
+        'ppapi_example_skeleton',
+        'ppapi.gyp:ppapi_cpp',
+      ],
+      'sources': [
+        'examples/video_effects/video_effects.cc',
+      ],
+    },
+    {
       'target_name': 'ppapi_example_enumerate_devices',
       'dependencies': [
         'ppapi_example_skeleton',
diff --git a/ppapi/proxy/extensions_common_resource.cc b/ppapi/proxy/extensions_common_resource.cc
index 0393b12..40d03f9 100644
--- a/ppapi/proxy/extensions_common_resource.cc
+++ b/ppapi/proxy/extensions_common_resource.cc
@@ -109,21 +109,26 @@
     return;
 
   int32_t result = params.result();
-  if (result == PP_OK) {
-    // If the size doesn't match, something must be really wrong.
-    CHECK_EQ(output_args.size(), output.GetSize());
 
-    std::vector<PP_Var> output_vars;
-    if (CreateVarVectorFromListValue(output, &output_vars)) {
-      DCHECK_EQ(output_args.size(), output_vars.size());
-      std::vector<PP_Var>::const_iterator src_iter = output_vars.begin();
-      std::vector<PP_Var*>::const_iterator dest_iter = output_args.begin();
-      for (; src_iter != output_vars.end() && dest_iter != output_args.end();
-           ++src_iter, ++dest_iter) {
-        **dest_iter = *src_iter;
-      }
-    } else {
-      result = PP_ERROR_FAILED;
+  // If the size doesn't match, something must be really wrong.
+  CHECK_EQ(output_args.size(), output.GetSize());
+
+  std::vector<PP_Var> output_vars;
+  if (CreateVarVectorFromListValue(output, &output_vars)) {
+    DCHECK_EQ(output_args.size(), output_vars.size());
+    std::vector<PP_Var>::const_iterator src_iter = output_vars.begin();
+    std::vector<PP_Var*>::const_iterator dest_iter = output_args.begin();
+    for (; src_iter != output_vars.end() && dest_iter != output_args.end();
+         ++src_iter, ++dest_iter) {
+      **dest_iter = *src_iter;
+    }
+  } else {
+    NOTREACHED();
+    result = PP_ERROR_FAILED;
+    for (std::vector<PP_Var*>::const_iterator dest_iter = output_args.begin();
+         dest_iter != output_args.end();
+         ++dest_iter) {
+      **dest_iter = PP_MakeUndefined();
     }
   }
 
diff --git a/ppapi/proxy/flash_device_id_resource.cc b/ppapi/proxy/flash_device_id_resource.cc
deleted file mode 100644
index 493ebda..0000000
--- a/ppapi/proxy/flash_device_id_resource.cc
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ppapi/proxy/flash_device_id_resource.h"
-
-#include "base/bind.h"
-#include "ppapi/c/pp_errors.h"
-#include "ppapi/proxy/dispatch_reply_message.h"
-#include "ppapi/proxy/ppapi_messages.h"
-#include "ppapi/shared_impl/var.h"
-
-namespace ppapi {
-namespace proxy {
-
-FlashDeviceIDResource::FlashDeviceIDResource(Connection connection,
-                                             PP_Instance instance)
-    : PluginResource(connection, instance),
-      dest_(NULL) {
-  SendCreate(BROWSER, PpapiHostMsg_FlashDeviceID_Create());
-}
-
-FlashDeviceIDResource::~FlashDeviceIDResource() {
-}
-
-thunk::PPB_Flash_DeviceID_API*
-FlashDeviceIDResource::AsPPB_Flash_DeviceID_API() {
-  return this;
-}
-
-int32_t FlashDeviceIDResource::GetDeviceID(
-    PP_Var* id,
-    scoped_refptr<TrackedCallback> callback) {
-  if (TrackedCallback::IsPending(callback_))
-    return PP_ERROR_INPROGRESS;
-  if (!id)
-    return PP_ERROR_BADARGUMENT;
-
-  dest_ = id;
-  callback_ = callback;
-
-  Call<PpapiPluginMsg_FlashDeviceID_GetDeviceIDReply>(
-      BROWSER,
-      PpapiHostMsg_FlashDeviceID_GetDeviceID(),
-      base::Bind(&FlashDeviceIDResource::OnPluginMsgGetDeviceIDReply, this));
-  return PP_OK_COMPLETIONPENDING;
-}
-
-void FlashDeviceIDResource::OnPluginMsgGetDeviceIDReply(
-    const ResourceMessageReplyParams& params,
-    const std::string& id) {
-  if (params.result() == PP_OK)
-    *dest_ = StringVar::StringToPPVar(id);
-  else
-    *dest_ = PP_MakeUndefined();
-  dest_ = NULL;
-  callback_->Run(params.result());
-}
-
-}  // namespace proxy
-}  // namespace ppapi
diff --git a/ppapi/proxy/flash_device_id_resource.h b/ppapi/proxy/flash_device_id_resource.h
deleted file mode 100644
index 19c9e63..0000000
--- a/ppapi/proxy/flash_device_id_resource.h
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef PPAPI_PROXY_FLASH_DEVICE_ID_RESOURCE_H_
-#define PPAPI_PROXY_FLASH_DEVICE_ID_RESOURCE_H_
-
-#include "ppapi/proxy/plugin_resource.h"
-#include "ppapi/proxy/ppapi_proxy_export.h"
-#include "ppapi/shared_impl/tracked_callback.h"
-#include "ppapi/thunk/ppb_flash_device_id_api.h"
-
-namespace ppapi {
-namespace proxy {
-
-class FlashDeviceIDResource
-    : public PluginResource,
-      public thunk::PPB_Flash_DeviceID_API {
- public:
-  FlashDeviceIDResource(Connection connection,
-                        PP_Instance instance);
-  virtual ~FlashDeviceIDResource();
-
-  // Resource override.
-  virtual thunk::PPB_Flash_DeviceID_API* AsPPB_Flash_DeviceID_API() OVERRIDE;
-
-  // PPB_Flash_DeviceID_API implementation.
-  virtual int32_t GetDeviceID(PP_Var* id,
-                              scoped_refptr<TrackedCallback> callback) OVERRIDE;
-
- private:
-  // IPC message handler.
-  void OnPluginMsgGetDeviceIDReply(const ResourceMessageReplyParams& params,
-                                   const std::string& id);
-
-  // Non-null when a callback is pending.
-  PP_Var* dest_;
-
-  scoped_refptr<TrackedCallback> callback_;
-
-  DISALLOW_COPY_AND_ASSIGN(FlashDeviceIDResource);
-};
-
-}  // namespace proxy
-}  // namespace ppapi
-
-#endif  // PPAPI_PROXY_FLASH_DEVICE_ID_RESOURCE_H_
diff --git a/ppapi/proxy/flash_drm_resource.cc b/ppapi/proxy/flash_drm_resource.cc
new file mode 100644
index 0000000..c066b65
--- /dev/null
+++ b/ppapi/proxy/flash_drm_resource.cc
@@ -0,0 +1,57 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ppapi/proxy/flash_drm_resource.h"
+
+#include "base/bind.h"
+#include "ppapi/c/pp_errors.h"
+#include "ppapi/proxy/dispatch_reply_message.h"
+#include "ppapi/proxy/ppapi_messages.h"
+#include "ppapi/shared_impl/var.h"
+
+namespace ppapi {
+namespace proxy {
+
+FlashDRMResource::FlashDRMResource(Connection connection,
+                                   PP_Instance instance)
+    : PluginResource(connection, instance) {
+  SendCreate(BROWSER, PpapiHostMsg_FlashDRM_Create());
+}
+
+FlashDRMResource::~FlashDRMResource() {
+}
+
+thunk::PPB_Flash_DRM_API* FlashDRMResource::AsPPB_Flash_DRM_API() {
+  return this;
+}
+
+int32_t FlashDRMResource::GetDeviceID(PP_Var* id,
+                                      scoped_refptr<TrackedCallback> callback) {
+  if (!id)
+    return PP_ERROR_BADARGUMENT;
+
+  *id = PP_MakeUndefined();
+
+  Call<PpapiPluginMsg_FlashDRM_GetDeviceIDReply>(
+      BROWSER,
+      PpapiHostMsg_FlashDRM_GetDeviceID(),
+      base::Bind(&FlashDRMResource::OnPluginMsgGetDeviceIDReply, this,
+      id, callback));
+  return PP_OK_COMPLETIONPENDING;
+}
+
+void FlashDRMResource::OnPluginMsgGetDeviceIDReply(
+    PP_Var* dest,
+    scoped_refptr<TrackedCallback> callback,
+    const ResourceMessageReplyParams& params,
+    const std::string& id) {
+  if (TrackedCallback::IsPending(callback)) {
+    if (params.result() == PP_OK)
+      *dest = StringVar::StringToPPVar(id);
+    callback->Run(params.result());
+  }
+}
+
+}  // namespace proxy
+}  // namespace ppapi
diff --git a/ppapi/proxy/flash_drm_resource.h b/ppapi/proxy/flash_drm_resource.h
new file mode 100644
index 0000000..d85db0c
--- /dev/null
+++ b/ppapi/proxy/flash_drm_resource.h
@@ -0,0 +1,43 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef PPAPI_PROXY_FLASH_DRM_RESOURCE_H_
+#define PPAPI_PROXY_FLASH_DRM_RESOURCE_H_
+
+#include "ppapi/proxy/plugin_resource.h"
+#include "ppapi/proxy/ppapi_proxy_export.h"
+#include "ppapi/shared_impl/tracked_callback.h"
+#include "ppapi/thunk/ppb_flash_drm_api.h"
+
+namespace ppapi {
+namespace proxy {
+
+class FlashDRMResource
+    : public PluginResource,
+      public thunk::PPB_Flash_DRM_API {
+ public:
+  FlashDRMResource(Connection connection,
+                   PP_Instance instance);
+  virtual ~FlashDRMResource();
+
+  // Resource override.
+  virtual thunk::PPB_Flash_DRM_API* AsPPB_Flash_DRM_API() OVERRIDE;
+
+  // PPB_Flash_DRM_API implementation.
+  virtual int32_t GetDeviceID(PP_Var* id,
+                              scoped_refptr<TrackedCallback> callback) OVERRIDE;
+
+ private:
+  void OnPluginMsgGetDeviceIDReply(PP_Var* dest,
+                                   scoped_refptr<TrackedCallback> callback,
+                                   const ResourceMessageReplyParams& params,
+                                   const std::string& id);
+
+  DISALLOW_COPY_AND_ASSIGN(FlashDRMResource);
+};
+
+}  // namespace proxy
+}  // namespace ppapi
+
+#endif  // PPAPI_PROXY_FLASH_DRM_RESOURCE_H_
diff --git a/ppapi/proxy/interface_list.cc b/ppapi/proxy/interface_list.cc
index 4bd8b40..e97359e 100644
--- a/ppapi/proxy/interface_list.cc
+++ b/ppapi/proxy/interface_list.cc
@@ -67,6 +67,7 @@
 #include "ppapi/c/private/ppb_flash_fullscreen.h"
 #include "ppapi/c/private/ppb_flash.h"
 #include "ppapi/c/private/ppb_flash_device_id.h"
+#include "ppapi/c/private/ppb_flash_drm.h"
 #include "ppapi/c/private/ppb_flash_menu.h"
 #include "ppapi/c/private/ppb_flash_message_loop.h"
 #include "ppapi/c/private/ppb_flash_print.h"
@@ -104,7 +105,6 @@
 #include "ppapi/proxy/ppb_tcp_server_socket_private_proxy.h"
 #include "ppapi/proxy/ppb_tcp_socket_private_proxy.h"
 #include "ppapi/proxy/ppb_testing_proxy.h"
-#include "ppapi/proxy/ppb_url_loader_proxy.h"
 #include "ppapi/proxy/ppb_var_deprecated_proxy.h"
 #include "ppapi/proxy/ppb_video_decoder_proxy.h"
 #include "ppapi/proxy/ppb_x509_certificate_private_proxy.h"
@@ -244,7 +244,6 @@
   // Do not add more stuff here, they should be added to interface_list*.h
   // TODO(brettw) remove these.
   AddPPB(PPB_Instance_Proxy::GetInfoPrivate(), PERMISSION_PRIVATE);
-  AddPPB(PPB_URLLoader_Proxy::GetTrustedInfo(), PERMISSION_PRIVATE);
   AddPPB(PPB_Var_Deprecated_Proxy::GetInfo(), PERMISSION_DEV);
 
   // TODO(tomfinegan): Figure out where to put these once we refactor things
diff --git a/ppapi/proxy/pdf_resource.cc b/ppapi/proxy/pdf_resource.cc
index a5b5d8c..07d3430 100644
--- a/ppapi/proxy/pdf_resource.cc
+++ b/ppapi/proxy/pdf_resource.cc
@@ -167,30 +167,28 @@
     return 0;
 
   HostResource resource;
-  std::string image_data_desc;
+  PP_ImageDataDesc image_desc;
   int fd;
   if (!UnpackMessage<PpapiPluginMsg_PDF_GetResourceImageReply>(
-      reply, &resource, &image_data_desc, &fd)) {
+      reply, &resource, &image_desc, &fd)) {
     return 0;
   }
 
-  if (resource.is_null() || image_data_desc.size() != sizeof(PP_ImageDataDesc))
+  if (resource.is_null())
     return 0;
-
-  // We serialize the PP_ImageDataDesc just by copying to a string.
-  PP_ImageDataDesc desc;
-  memcpy(&desc, image_data_desc.data(), sizeof(PP_ImageDataDesc));
+  if (!PPB_ImageData_Shared::IsImageDataDescValid(image_desc))
+    return 0;
 
 #if defined(OS_ANDROID)
   // This is compiled into android for tests only.
   return 0;
-#elif defined(OS_WIN) || defined(OS_MACOSX)
+#elif defined(TOOLKIT_GTK)
+  return (new ImageData(resource, image_desc, fd))->GetReference();
+#elif defined(OS_LINUX) || defined(OS_WIN) || defined(OS_MACOSX)
   base::SharedMemoryHandle handle;
   if (!reply_params.TakeSharedMemoryHandleAtIndex(0, &handle))
     return 0;
-  return (new ImageData(resource, desc, handle))->GetReference();
-#elif defined(OS_LINUX)
-  return (new ImageData(resource, desc, fd))->GetReference();
+  return (new ImageData(resource, image_desc, handle))->GetReference();
 #else
 #error Not implemented.
 #endif
diff --git a/ppapi/proxy/pdf_resource_unittest.cc b/ppapi/proxy/pdf_resource_unittest.cc
index fa79f00..cad6907 100644
--- a/ppapi/proxy/pdf_resource_unittest.cc
+++ b/ppapi/proxy/pdf_resource_unittest.cc
@@ -166,12 +166,9 @@
       { 5, 10 },
       20,
   };
-  std::string image_data_desc;
-  image_data_desc.resize(sizeof(PP_ImageDataDesc));
-  memcpy(&image_data_desc[0], &expected_desc, sizeof(PP_ImageDataDesc));
   SerializedHandle serialized_handle(SerializedHandle::SHARED_MEMORY);
   PpapiPluginMsg_PDF_GetResourceImageReply reply_msg(expected_resource,
-                                                     image_data_desc,
+                                                     expected_desc,
                                                      0);
   ResourceSyncCallHandler handler(
       &sink(),
diff --git a/ppapi/proxy/plugin_resource.h b/ppapi/proxy/plugin_resource.h
index 1535278..9448326 100644
--- a/ppapi/proxy/plugin_resource.h
+++ b/ppapi/proxy/plugin_resource.h
@@ -131,6 +131,8 @@
                           IPC::Message* reply_msg,
                           ResourceMessageReplyParams* reply_params);
 
+  const Connection& connection() { return connection_; }
+
  private:
   IPC::Sender* GetSender(Destination dest) {
     return dest == RENDERER ? connection_.renderer_sender :
diff --git a/ppapi/proxy/ppapi_messages.h b/ppapi/proxy/ppapi_messages.h
index 622cfb3..14312dc 100644
--- a/ppapi/proxy/ppapi_messages.h
+++ b/ppapi/proxy/ppapi_messages.h
@@ -45,6 +45,7 @@
 #include "ppapi/c/private/ppb_tcp_socket_private.h"
 #include "ppapi/c/private/ppb_udp_socket_private.h"
 #include "ppapi/c/private/ppp_flash_browser_operations.h"
+#include "ppapi/c/private/ppb_flash_drm.h"
 #include "ppapi/proxy/host_resolver_private_resource.h"
 #include "ppapi/proxy/ppapi_param_traits.h"
 #include "ppapi/proxy/ppapi_proxy_export.h"
@@ -589,10 +590,10 @@
 IPC_MESSAGE_ROUTED2(PpapiMsg_PPPInstance_DidChangeFocus,
                     PP_Instance /* instance */,
                     PP_Bool /* has_focus */)
-IPC_SYNC_MESSAGE_ROUTED2_1(PpapiMsg_PPPInstance_HandleDocumentLoad,
-                           PP_Instance /* instance */,
-                           ppapi::HostResource /* url_loader */,
-                           PP_Bool /* result */)
+IPC_MESSAGE_ROUTED3(PpapiMsg_PPPInstance_HandleDocumentLoad,
+    PP_Instance /* instance */,
+    int /* pending_loader_host_id */,
+    ppapi::URLResponseInfoData /* response */)
 
 // PPP_Messaging.
 IPC_MESSAGE_ROUTED2(PpapiMsg_PPPMessaging_HandleMessage,
@@ -631,19 +632,6 @@
                    PP_Instance /* instance */,
                    uint32_t /* desired_number_of_characters */)
 
-// PPB_URLLoader
-// (Messages from browser to plugin to notify it of changes in state.)
-//
-// NOTE: The ReadResponseBody_Ack message is a custom generated message
-// with the following fields appended:
-//   ppapi::HostResource
-//   response data (array of bytes stored via WriteData)
-//   int result
-//
-IPC_MESSAGE_ROUTED0(PpapiMsg_PPBURLLoader_ReadResponseBody_Ack)
-IPC_MESSAGE_ROUTED2(PpapiMsg_PPBURLLoader_CallbackComplete,
-                    ppapi::HostResource /* loader */,
-                    int32_t /* result */)
 #if !defined(OS_NACL) && !defined(NACL_WIN64)
 // PPB_Broker.
 IPC_MESSAGE_ROUTED3(
@@ -722,11 +710,6 @@
                     uint32 /* socket_id */,
                     bool /* succeeded */)
 
-// PPB_URLLoader_Trusted
-IPC_MESSAGE_ROUTED1(
-    PpapiMsg_PPBURLLoader_UpdateProgress,
-    ppapi::proxy::PPBURLLoader_UpdateProgress_Params /* params */)
-
 // PPB_TCPServerSocket_Private.
 
 // |socket_resource| should not be used as Resource in browser. The
@@ -737,10 +720,11 @@
 // initialized (if needed) but Listen call is failed.
 // |status| == PP_OK means that socket is correctly initialized (if
 // needed) and Listen call succeeds.
-IPC_MESSAGE_ROUTED4(PpapiMsg_PPBTCPServerSocket_ListenACK,
+IPC_MESSAGE_ROUTED5(PpapiMsg_PPBTCPServerSocket_ListenACK,
                     uint32 /* plugin_dispatcher_id */,
                     PP_Resource /* socket_resource */,
                     uint32 /* socket_id */,
+                    PP_NetAddress_Private /* local_addr */,
                     int32_t /* status */)
 IPC_MESSAGE_ROUTED5(PpapiMsg_PPBTCPServerSocket_AcceptACK,
                     uint32 /* plugin_dispatcher_id */,
@@ -1002,30 +986,6 @@
                     uint32_t /* caret */,
                     uint32_t /* anchor */)
 
-// PPB_URLLoader.
-IPC_SYNC_MESSAGE_ROUTED1_1(PpapiHostMsg_PPBURLLoader_Create,
-                           PP_Instance /* instance */,
-                           ppapi::HostResource /* result */)
-IPC_MESSAGE_ROUTED2(PpapiHostMsg_PPBURLLoader_Open,
-                    ppapi::HostResource /* loader */,
-                    ppapi::URLRequestInfoData /* request_data */)
-IPC_MESSAGE_ROUTED1(PpapiHostMsg_PPBURLLoader_FollowRedirect,
-                    ppapi::HostResource /* loader */)
-IPC_SYNC_MESSAGE_ROUTED1_2(
-    PpapiHostMsg_PPBURLLoader_GetResponseInfo,
-    ppapi::HostResource /* loader */,
-    bool /* success */,
-    ppapi::URLResponseInfoData /* result */)
-IPC_MESSAGE_ROUTED2(PpapiHostMsg_PPBURLLoader_ReadResponseBody,
-                    ppapi::HostResource /* loader */,
-                    int32_t /* bytes_to_read */)
-IPC_MESSAGE_ROUTED1(PpapiHostMsg_PPBURLLoader_FinishStreamingToFile,
-                    ppapi::HostResource /* loader */)
-IPC_MESSAGE_ROUTED1(PpapiHostMsg_PPBURLLoader_Close,
-                    ppapi::HostResource /* loader */)
-IPC_MESSAGE_ROUTED1(PpapiHostMsg_PPBURLLoader_GrantUniversalAccess,
-                    ppapi::HostResource /* loader */)
-
 // PPB_Var.
 IPC_SYNC_MESSAGE_ROUTED1_1(PpapiHostMsg_PPBVar_AddRefObject,
                            int64 /* object_id */,
@@ -1426,10 +1386,13 @@
 IPC_MESSAGE_CONTROL1(PpapiHostMsg_FileSystem_InitIsolatedFileSystem,
                      std::string /* fsid */)
 
-// Flash device ID.
-IPC_MESSAGE_CONTROL0(PpapiHostMsg_FlashDeviceID_Create)
-IPC_MESSAGE_CONTROL0(PpapiHostMsg_FlashDeviceID_GetDeviceID)
-IPC_MESSAGE_CONTROL1(PpapiPluginMsg_FlashDeviceID_GetDeviceIDReply,
+// Flash DRM ------------------------------------------------------------------
+IPC_MESSAGE_CONTROL0(PpapiHostMsg_FlashDRM_Create)
+
+// Requests the device ID.
+IPC_MESSAGE_CONTROL0(PpapiHostMsg_FlashDRM_GetDeviceID)
+// Reply for GetDeviceID which includes the device ID as a string.
+IPC_MESSAGE_CONTROL1(PpapiPluginMsg_FlashDRM_GetDeviceIDReply,
                      std::string /* id */)
 
 // Gamepad.
@@ -1511,7 +1474,63 @@
 IPC_MESSAGE_CONTROL1(PpapiPluginMsg_Printing_GetDefaultPrintSettingsReply,
                      PP_PrintSettings_Dev /* print_settings */)
 
+// URLLoader ------------------------------------------------------------------
+
+IPC_MESSAGE_CONTROL0(PpapiHostMsg_URLLoader_Create)
+
+// These messages correspond to PPAPI calls and all should get a
+// CallbackComplete message.
+IPC_MESSAGE_CONTROL1(PpapiHostMsg_URLLoader_Open,
+                     ppapi::URLRequestInfoData /* request_data */)
+
+// The plugin can tell the host to defer a load to hold off on sending more
+// data because the buffer in the plugin is full. When defers_loading is set to
+// false, data streaming will resume.
+//
+// When auditing redirects (no auto follow) the load will be automatically
+// deferred each time we get a redirect. The plugin will reset this to false
+// by sending this message when it wants to continue following the redirect.
+//
+// When streaming data, the host may still send more data after this call (for
+// example, it could already be in-flight at the time of this request).
+IPC_MESSAGE_CONTROL1(PpapiHostMsg_URLLoader_SetDeferLoading,
+                     bool /* defers_loading */)
+
+// Closes the URLLoader. There is no reply.
+IPC_MESSAGE_CONTROL0(PpapiHostMsg_URLLoader_Close)
+
+// Requests that cross-site restrictions be ignored. The plugin must have
+// the private permission set. Otherwise this message will be ignored by the
+// renderer. There is no reply.
+IPC_MESSAGE_CONTROL0(PpapiHostMsg_URLLoader_GrantUniversalAccess)
+
+// Push notification that a response is available.
+IPC_MESSAGE_CONTROL1(PpapiPluginMsg_URLLoader_ReceivedResponse,
+                     ppapi::URLResponseInfoData /* response */)
+
+// Push notification with load data from the renderer. It is a custom generated
+// message with the response data (array of bytes stored via WriteData)
+// appended.
+IPC_MESSAGE_CONTROL0(PpapiPluginMsg_URLLoader_SendData)
+
+// Push notification indicating that all data has been sent, either via
+// SendData or by streaming it to a file. Note that since this is a push
+// notification, we don't use the result field of the ResourceMessageReply.
+IPC_MESSAGE_CONTROL1(PpapiPluginMsg_URLLoader_FinishedLoading,
+                     int32_t /* result */)
+
+// Push notification from the renderer to the plugin to tell it about download
+// and upload progress. This will only be sent if the plugin has requested
+// progress updates, and only the fields requested by the plugin will be
+// valid.
+IPC_MESSAGE_CONTROL4(PpapiPluginMsg_URLLoader_UpdateProgress,
+                     int64_t /* bytes_sent */,
+                     int64_t /* total_bytes_to_be_sent */,
+                     int64_t /* bytes_received */,
+                     int64_t /* total_bytes_to_be_received */)
+
 // Shared memory ---------------------------------------------------------------
+
 // Creates shared memory on the host side, returning a handle to the shared
 // memory on the plugin and keeping the memory mapped in on the host.
 // We return a "host handle_id" that can be mapped back to the
@@ -1522,7 +1541,8 @@
                             int /* host_handle_id */,
                             ppapi::proxy::SerializedHandle /* plugin_handle */)
 
-// WebSocket ------------------------------------------------------------------
+// WebSocket -------------------------------------------------------------------
+
 IPC_MESSAGE_CONTROL0(PpapiHostMsg_WebSocket_Create)
 
 // Establishes the connection to a server. This message requires
@@ -1811,14 +1831,13 @@
                      PP_ResourceImage /* image_id */,
                      float /* scale */)
 // Reply for PpapiHostMsg_PDF_GetResourceImage containing the host resource id
-// of the image and a string (representing a PP_ImageDataDesc) containing the
-// properties of the image. Also carries a shared memory handle pointing to the
-// memory containg the image. On linux, the handle is transmitted in this
-// message as |fd|. This is due to the unfortunate way that ImageHandles are
-// defined for use with PPB_ImageData.
+// of the image and a PP_ImageDataDesc which describes the image. Also carries
+// a shared memory handle pointing to the memory containg the image. On linux,
+// the handle is transmitted in this message as |fd|. This is due to the
+// unfortunate way that ImageHandles are defined for use with PPB_ImageData.
 IPC_MESSAGE_CONTROL3(PpapiPluginMsg_PDF_GetResourceImageReply,
                      ppapi::HostResource /* resource_id */,
-                     std::string /* image_data_desc */,
+                     PP_ImageDataDesc /* image_data_desc */,
                      int /* fd */)
 
 // VideoCapture_Dev, plugin -> host
diff --git a/ppapi/proxy/ppapi_proxy_test.cc b/ppapi/proxy/ppapi_proxy_test.cc
index 19f41bb..2df72cc 100644
--- a/ppapi/proxy/ppapi_proxy_test.cc
+++ b/ppapi/proxy/ppapi_proxy_test.cc
@@ -41,11 +41,6 @@
   // worry about Instance uniqueness in tests, so we can ignore the call.
 }
 
-int32_t GetURLLoaderBufferedBytes(PP_Resource url_loader) {
-  NOTREACHED();
-  return 0;
-}
-
 void AddRefModule(PP_Module module) {}
 void ReleaseModule(PP_Module module) {}
 PP_Bool IsInModuleDestructor(PP_Module module) { return PP_FALSE; }
@@ -54,7 +49,6 @@
   &PluginCrashed,
   &GetInstanceForResource,
   &SetReserveInstanceIDCallback,
-  &GetURLLoaderBufferedBytes,
   &AddRefModule,
   &ReleaseModule,
   &IsInModuleDestructor
diff --git a/ppapi/proxy/ppb_image_data_proxy.cc b/ppapi/proxy/ppb_image_data_proxy.cc
index 40fddf4..999ab81 100644
--- a/ppapi/proxy/ppb_image_data_proxy.cc
+++ b/ppapi/proxy/ppb_image_data_proxy.cc
@@ -430,20 +430,20 @@
 ImageHandle ImageData::NullHandle() {
 #if defined(OS_WIN)
   return NULL;
-#elif defined(OS_MACOSX) || defined(OS_ANDROID)
-  return ImageHandle();
-#else
+#elif defined(TOOLKIT_GTK)
   return 0;
+#else
+  return ImageHandle();
 #endif
 }
 
 ImageHandle ImageData::HandleFromInt(int32_t i) {
 #if defined(OS_WIN)
     return reinterpret_cast<ImageHandle>(i);
-#elif defined(OS_MACOSX) || defined(OS_ANDROID)
-    return ImageHandle(i, false);
-#else
+#elif defined(TOOLKIT_GTK)
     return static_cast<ImageHandle>(i);
+#else
+    return ImageHandle(i, false);
 #endif
 }
 #endif  // !defined(OS_NACL)
@@ -566,14 +566,14 @@
 #if defined(OS_WIN)
   *image_handle = dispatcher->ShareHandleWithRemote(
       reinterpret_cast<HANDLE>(static_cast<intptr_t>(local_fd)), false);
-#elif defined(OS_MACOSX) || defined(OS_ANDROID)
-  *image_handle = dispatcher->ShareHandleWithRemote(local_fd, false);
-#elif defined(OS_POSIX)
+#elif defined(TOOLKIT_GTK)
   // On X Windows, a non-nacl handle is a SysV shared memory key.
   if (is_nacl_plugin)
     *image_handle = dispatcher->ShareHandleWithRemote(local_fd, false);
   else
     *image_handle = IPC::PlatformFileForTransit(local_fd, false);
+#elif defined(OS_POSIX)
+  *image_handle = dispatcher->ShareHandleWithRemote(local_fd, false);
 #else
   #error Not implemented.
 #endif
@@ -602,11 +602,11 @@
   if (resource) {
     image_data_desc->resize(sizeof(PP_ImageDataDesc));
     memcpy(&(*image_data_desc)[0], &desc, sizeof(PP_ImageDataDesc));
-#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_ANDROID)
-    *result_image_handle = image_handle;
-#else
+#if defined(TOOLKIT_GTK)
     // On X Windows ImageHandle is a SysV shared memory key.
     *result_image_handle = image_handle.fd;
+#else
+    *result_image_handle = image_handle;
 #endif
   } else {
     image_data_desc->clear();
diff --git a/ppapi/proxy/ppb_tcp_server_socket_private_proxy.cc b/ppapi/proxy/ppb_tcp_server_socket_private_proxy.cc
index e577a6b..f895aac 100644
--- a/ppapi/proxy/ppb_tcp_server_socket_private_proxy.cc
+++ b/ppapi/proxy/ppb_tcp_server_socket_private_proxy.cc
@@ -158,15 +158,16 @@
     uint32 plugin_dispatcher_id,
     PP_Resource socket_resource,
     uint32 socket_id,
+    const PP_NetAddress_Private& local_addr,
     int32_t status) {
- thunk::EnterResourceNoLock<thunk::PPB_TCPServerSocket_Private_API>
+  thunk::EnterResourceNoLock<thunk::PPB_TCPServerSocket_Private_API>
      enter(socket_resource, true);
   if (enter.succeeded()) {
     PPB_TCPServerSocket_Shared* server_socket =
         static_cast<PPB_TCPServerSocket_Shared*>(enter.object());
     if (status == PP_OK)
       id_to_server_socket_[socket_id] = server_socket;
-    server_socket->OnListenCompleted(socket_id, status);
+    server_socket->OnListenCompleted(socket_id, local_addr, status);
   } else if (socket_id != 0 && status == PP_OK) {
     IPC::Message* msg =
         new PpapiHostMsg_PPBTCPServerSocket_Destroy(socket_id);
diff --git a/ppapi/proxy/ppb_tcp_server_socket_private_proxy.h b/ppapi/proxy/ppb_tcp_server_socket_private_proxy.h
index e2e644f..3fd985e 100644
--- a/ppapi/proxy/ppb_tcp_server_socket_private_proxy.h
+++ b/ppapi/proxy/ppb_tcp_server_socket_private_proxy.h
@@ -41,6 +41,7 @@
   void OnMsgListenACK(uint32 plugin_dispatcher_id,
                       PP_Resource socket_resource,
                       uint32 socket_id,
+                      const PP_NetAddress_Private& local_addr,
                       int32_t status);
   void OnMsgAcceptACK(uint32 plugin_dispatcher_id,
                       uint32 server_socket_id,
diff --git a/ppapi/proxy/ppb_url_loader_proxy.cc b/ppapi/proxy/ppb_url_loader_proxy.cc
deleted file mode 100644
index 425b61f..0000000
--- a/ppapi/proxy/ppb_url_loader_proxy.cc
+++ /dev/null
@@ -1,652 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ppapi/proxy/ppb_url_loader_proxy.h"
-
-#include <algorithm>
-#include <deque>
-#include <vector>
-
-#include "base/bind.h"
-#include "base/logging.h"
-#include "build/build_config.h"
-#include "ppapi/c/pp_completion_callback.h"
-#include "ppapi/c/pp_errors.h"
-#include "ppapi/c/pp_resource.h"
-#include "ppapi/c/ppb_url_loader.h"
-#include "ppapi/c/private/ppb_proxy_private.h"
-#include "ppapi/c/trusted/ppb_url_loader_trusted.h"
-#include "ppapi/proxy/enter_proxy.h"
-#include "ppapi/proxy/host_dispatcher.h"
-#include "ppapi/proxy/plugin_dispatcher.h"
-#include "ppapi/proxy/plugin_resource_tracker.h"
-#include "ppapi/proxy/ppapi_messages.h"
-#include "ppapi/proxy/ppb_file_ref_proxy.h"
-#include "ppapi/shared_impl/scoped_pp_resource.h"
-#include "ppapi/shared_impl/tracked_callback.h"
-#include "ppapi/thunk/enter.h"
-#include "ppapi/thunk/ppb_url_loader_api.h"
-#include "ppapi/thunk/ppb_url_request_info_api.h"
-#include "ppapi/thunk/resource_creation_api.h"
-#include "ppapi/thunk/thunk.h"
-
-#if defined(OS_LINUX)
-#include <sys/shm.h>
-#endif
-
-using ppapi::thunk::EnterResourceNoLock;
-using ppapi::thunk::PPB_URLLoader_API;
-using ppapi::thunk::ResourceCreationAPI;
-
-namespace ppapi {
-namespace proxy {
-
-namespace {
-
-// The maximum size we'll read into the plugin without being explicitly
-// asked for a larger buffer.
-const int32_t kMaxReadBufferSize = 16777216;  // 16MB
-
-#if !defined(OS_NACL)
-// Called in the renderer when the byte counts have changed. We send a message
-// to the plugin to synchronize its counts so it can respond to status polls
-// from the plugin.
-void UpdateResourceLoadStatus(PP_Instance pp_instance,
-                              PP_Resource pp_resource,
-                              int64 bytes_sent,
-                              int64 total_bytes_to_be_sent,
-                              int64 bytes_received,
-                              int64 total_bytes_to_be_received) {
-  Dispatcher* dispatcher = HostDispatcher::GetForInstance(pp_instance);
-  if (!dispatcher)
-    return;
-
-  PPBURLLoader_UpdateProgress_Params params;
-  params.instance = pp_instance;
-  params.resource.SetHostResource(pp_instance, pp_resource);
-  params.bytes_sent = bytes_sent;
-  params.total_bytes_to_be_sent = total_bytes_to_be_sent;
-  params.bytes_received = bytes_received;
-  params.total_bytes_to_be_received = total_bytes_to_be_received;
-  dispatcher->Send(new PpapiMsg_PPBURLLoader_UpdateProgress(
-      API_ID_PPB_URL_LOADER, params));
-}
-#endif  // !defined(OS_NACL)
-
-InterfaceProxy* CreateURLLoaderProxy(Dispatcher* dispatcher) {
-  return new PPB_URLLoader_Proxy(dispatcher);
-}
-
-}  // namespace
-
-// URLLoader -------------------------------------------------------------------
-
-class URLLoader : public Resource, public PPB_URLLoader_API {
- public:
-  URLLoader(const HostResource& resource);
-  virtual ~URLLoader();
-
-  // Resource overrides.
-  virtual PPB_URLLoader_API* AsPPB_URLLoader_API() OVERRIDE;
-
-  // PPB_URLLoader_API implementation.
-  virtual int32_t Open(PP_Resource request_id,
-                       scoped_refptr<TrackedCallback> callback) OVERRIDE;
-  virtual int32_t Open(const URLRequestInfoData& data,
-                       int requestor_pid,
-                       scoped_refptr<TrackedCallback> callback) OVERRIDE;
-  virtual int32_t FollowRedirect(
-      scoped_refptr<TrackedCallback> callback) OVERRIDE;
-  virtual PP_Bool GetUploadProgress(int64_t* bytes_sent,
-                                    int64_t* total_bytes_to_be_sent) OVERRIDE;
-  virtual PP_Bool GetDownloadProgress(
-      int64_t* bytes_received,
-      int64_t* total_bytes_to_be_received) OVERRIDE;
-  virtual PP_Resource GetResponseInfo() OVERRIDE;
-  virtual int32_t ReadResponseBody(
-      void* buffer,
-      int32_t bytes_to_read,
-      scoped_refptr<TrackedCallback> callback) OVERRIDE;
-  virtual int32_t FinishStreamingToFile(
-      scoped_refptr<TrackedCallback> callback) OVERRIDE;
-  virtual void Close() OVERRIDE;
-  virtual void GrantUniversalAccess() OVERRIDE;
-  virtual void RegisterStatusCallback(
-      PP_URLLoaderTrusted_StatusCallback cb) OVERRIDE;
-  virtual bool GetResponseInfoData(URLResponseInfoData* data) OVERRIDE;
-
-  // Called when the browser has new up/download progress to report.
-  void UpdateProgress(const PPBURLLoader_UpdateProgress_Params& params);
-
-  // Called when the browser responds to our ReadResponseBody request.
-  void ReadResponseBodyAck(int32_t result, const char* data);
-
-  // Called when any callback other than the read callback has been executed.
-  void CallbackComplete(int32_t result);
-
- private:
-  // Reads the give bytes out of the buffer_, placing them in the given output
-  // buffer, and removes the bytes from the buffer.
-  //
-  // The size must be not more than the current size of the buffer.
-  void PopBuffer(void* output_buffer, int32_t output_size);
-
-  PluginDispatcher* GetDispatcher() const {
-    return PluginDispatcher::GetForResource(this);
-  }
-
-  // Initialized to -1. Will be set to nonnegative values by the UpdateProgress
-  // message when the values are known.
-  int64_t bytes_sent_;
-  int64_t total_bytes_to_be_sent_;
-  int64_t bytes_received_;
-  int64_t total_bytes_to_be_received_;
-
-  // Current completion callback for the current phase of loading. We have only
-  // one thing (open, follow redirect, read, etc.) outstanding at once.
-  scoped_refptr<TrackedCallback> current_callback_;
-
-  // When an asynchronous read is pending, this will contain the buffer to put
-  // the data. The current_callback_ will identify the read callback.
-  void* current_read_buffer_;
-  int32_t current_read_buffer_size_;
-
-  // A buffer of all the data that's been sent to us from the host that we
-  // have yet to send out to the plugin.
-  std::deque<char> buffer_;
-
-  // Cached copy of the response info. When nonzero, we're holding a reference
-  // to this resource.
-  PP_Resource response_info_;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(URLLoader);
-};
-
-URLLoader::URLLoader(const HostResource& resource)
-    : Resource(OBJECT_IS_PROXY, resource),
-      bytes_sent_(-1),
-      total_bytes_to_be_sent_(-1),
-      bytes_received_(-1),
-      total_bytes_to_be_received_(-1),
-      current_read_buffer_(NULL),
-      current_read_buffer_size_(0),
-      response_info_(0) {
-}
-
-URLLoader::~URLLoader() {
-  if (response_info_)
-    PpapiGlobals::Get()->GetResourceTracker()->ReleaseResource(response_info_);
-}
-
-PPB_URLLoader_API* URLLoader::AsPPB_URLLoader_API() {
-  return this;
-}
-
-int32_t URLLoader::Open(PP_Resource request_id,
-                        scoped_refptr<TrackedCallback> callback) {
-  EnterResourceNoLock<thunk::PPB_URLRequestInfo_API> enter(request_id, true);
-  if (enter.failed()) {
-    Log(PP_LOGLEVEL_ERROR, "PPB_URLLoader.Open: The URL you're requesting is "
-        " on a different security origin than your plugin. To request "
-        " cross-origin resources, see "
-        " PP_URLREQUESTPROPERTY_ALLOWCROSSORIGINREQUESTS.");
-    return PP_ERROR_BADRESOURCE;
-  }
-  return Open(enter.object()->GetData(), 0, callback);
-}
-
-int32_t URLLoader::Open(const URLRequestInfoData& data,
-                        int requestor_pid,
-                        scoped_refptr<TrackedCallback> callback) {
-  DCHECK_EQ(0, requestor_pid);  // Used in-process only.
-
-  if (TrackedCallback::IsPending(current_callback_))
-    return PP_ERROR_INPROGRESS;
-
-  current_callback_ = callback;
-
-  GetDispatcher()->Send(new PpapiHostMsg_PPBURLLoader_Open(
-      API_ID_PPB_URL_LOADER, host_resource(), data));
-  return PP_OK_COMPLETIONPENDING;
-}
-
-int32_t URLLoader::FollowRedirect(scoped_refptr<TrackedCallback> callback) {
-  if (TrackedCallback::IsPending(current_callback_))
-    return PP_ERROR_INPROGRESS;
-
-  current_callback_ = callback;
-
-  GetDispatcher()->Send(new PpapiHostMsg_PPBURLLoader_FollowRedirect(
-      API_ID_PPB_URL_LOADER, host_resource()));
-  return PP_OK_COMPLETIONPENDING;
-}
-
-PP_Bool URLLoader::GetUploadProgress(int64_t* bytes_sent,
-                                     int64_t* total_bytes_to_be_sent) {
-  if (bytes_sent_ == -1) {
-    *bytes_sent = 0;
-    *total_bytes_to_be_sent = 0;
-    return PP_FALSE;
-  }
-  *bytes_sent = bytes_sent_;
-  *total_bytes_to_be_sent = total_bytes_to_be_sent_;
-  return PP_TRUE;
-}
-
-PP_Bool URLLoader::GetDownloadProgress(
-    int64_t* bytes_received,
-    int64_t* total_bytes_to_be_received) {
-  if (bytes_received_ == -1) {
-    *bytes_received = 0;
-    *total_bytes_to_be_received = 0;
-    return PP_FALSE;
-  }
-  *bytes_received = bytes_received_;
-  *total_bytes_to_be_received = total_bytes_to_be_received_;
-  return PP_TRUE;
-}
-
-PP_Resource URLLoader::GetResponseInfo() {
-  if (!response_info_) {
-    bool success = false;
-    URLResponseInfoData data;
-    GetDispatcher()->Send(new PpapiHostMsg_PPBURLLoader_GetResponseInfo(
-        API_ID_PPB_URL_LOADER, host_resource(), &success, &data));
-    if (!success)
-      return 0;
-
-    // Create a proxy resource for the the file ref host resource if needed.
-    PP_Resource body_as_file_ref = 0;
-    if (!data.body_as_file_ref.resource.is_null()) {
-      body_as_file_ref =
-          PPB_FileRef_Proxy::DeserializeFileRef(data.body_as_file_ref);
-    }
-
-    // Assumes ownership of body_as_file_ref.
-    thunk::EnterResourceCreationNoLock enter(pp_instance());
-    response_info_ = enter.functions()->CreateURLResponseInfo(
-        pp_instance(), data, body_as_file_ref);
-  }
-
-  // The caller expects to get a ref, and we want to keep holding ours.
-  PpapiGlobals::Get()->GetResourceTracker()->AddRefResource(response_info_);
-  return response_info_;
-}
-
-int32_t URLLoader::ReadResponseBody(void* buffer,
-                                    int32_t bytes_to_read,
-                                    scoped_refptr<TrackedCallback> callback) {
-  if (!buffer || bytes_to_read <= 0)
-    return PP_ERROR_BADARGUMENT;  // Must specify an output buffer.
-  if (TrackedCallback::IsPending(current_callback_))
-    return PP_ERROR_INPROGRESS;  // Can only have one request pending.
-
-  if (buffer_.size()) {
-    // Special case: we've already buffered some data that we can synchronously
-    // return to the caller. Do so without making IPCs.
-    int32_t bytes_to_return =
-        std::min(bytes_to_read, static_cast<int32_t>(buffer_.size()));
-    PopBuffer(buffer, bytes_to_return);
-    return bytes_to_return;
-  }
-
-  current_callback_ = callback;
-  current_read_buffer_ = buffer;
-  current_read_buffer_size_ = bytes_to_read;
-
-  GetDispatcher()->Send(new PpapiHostMsg_PPBURLLoader_ReadResponseBody(
-      API_ID_PPB_URL_LOADER, host_resource(), bytes_to_read));
-  return PP_OK_COMPLETIONPENDING;
-}
-
-int32_t URLLoader::FinishStreamingToFile(
-    scoped_refptr<TrackedCallback> callback) {
-  if (TrackedCallback::IsPending(current_callback_))
-    return PP_ERROR_INPROGRESS;
-
-  current_callback_ = callback;
-
-  GetDispatcher()->Send(new PpapiHostMsg_PPBURLLoader_FinishStreamingToFile(
-      API_ID_PPB_URL_LOADER, host_resource()));
-  return PP_OK_COMPLETIONPENDING;
-}
-
-void URLLoader::Close() {
-  GetDispatcher()->Send(new PpapiHostMsg_PPBURLLoader_Close(
-      API_ID_PPB_URL_LOADER, host_resource()));
-}
-
-void URLLoader::GrantUniversalAccess() {
-  GetDispatcher()->Send(
-      new PpapiHostMsg_PPBURLLoader_GrantUniversalAccess(
-          API_ID_PPB_URL_LOADER, host_resource()));
-}
-
-void URLLoader::RegisterStatusCallback(
-    PP_URLLoaderTrusted_StatusCallback cb) {
-  // Not implemented in the proxied version, this is for implementing the
-  // proxy itself in the host.
-}
-
-bool URLLoader::GetResponseInfoData(URLResponseInfoData* data) {
-  // Not implemented in the proxied version, this is for implementing the
-  // proxy itself in the host.
-  return false;
-}
-
-void URLLoader::UpdateProgress(
-    const PPBURLLoader_UpdateProgress_Params& params) {
-  bytes_sent_ = params.bytes_sent;
-  total_bytes_to_be_sent_ = params.total_bytes_to_be_sent;
-  bytes_received_ = params.bytes_received;
-  total_bytes_to_be_received_ = params.total_bytes_to_be_received;
-}
-
-void URLLoader::ReadResponseBodyAck(int32 result, const char* data) {
-  if (!TrackedCallback::IsPending(current_callback_) || !current_read_buffer_) {
-    NOTREACHED();
-    return;
-  }
-
-  if (result >= 0) {
-    DCHECK_EQ(0U, buffer_.size());
-
-    int32_t bytes_to_return = std::min(current_read_buffer_size_, result);
-    std::copy(data,
-              data + bytes_to_return,
-              static_cast<char*>(current_read_buffer_));
-
-    if (result > bytes_to_return) {
-      // Save what remains to be copied when ReadResponseBody is called again.
-      buffer_.insert(buffer_.end(),
-                     data + bytes_to_return,
-                     data + result);
-    }
-
-    result = bytes_to_return;
-  }
-
-  current_callback_->Run(result);
-}
-
-void URLLoader::CallbackComplete(int32_t result) {
-  current_callback_->Run(result);
-}
-
-void URLLoader::PopBuffer(void* output_buffer, int32_t output_size) {
-  CHECK(output_size <= static_cast<int32_t>(buffer_.size()));
-  std::copy(buffer_.begin(),
-            buffer_.begin() + output_size,
-            static_cast<char*>(output_buffer));
-  buffer_.erase(buffer_.begin(),
-                buffer_.begin() + output_size);
-}
-
-// PPB_URLLoader_Proxy ---------------------------------------------------------
-
-PPB_URLLoader_Proxy::PPB_URLLoader_Proxy(Dispatcher* dispatcher)
-    : InterfaceProxy(dispatcher),
-      callback_factory_(this) {
-}
-
-PPB_URLLoader_Proxy::~PPB_URLLoader_Proxy() {
-}
-
-// static
-PP_Resource PPB_URLLoader_Proxy::TrackPluginResource(
-    const HostResource& url_loader_resource) {
-  return (new URLLoader(url_loader_resource))->GetReference();
-}
-
-// static
-const InterfaceProxy::Info* PPB_URLLoader_Proxy::GetTrustedInfo() {
-  static const Info info = {
-    thunk::GetPPB_URLLoaderTrusted_0_3_Thunk(),
-    PPB_URLLOADERTRUSTED_INTERFACE_0_3,
-    API_ID_NONE,  // URL_LOADER is the canonical one.
-    false,
-    &CreateURLLoaderProxy
-  };
-  return &info;
-}
-
-// static
-PP_Resource PPB_URLLoader_Proxy::CreateProxyResource(PP_Instance pp_instance) {
-  PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(pp_instance);
-  if (!dispatcher)
-    return 0;
-
-  HostResource result;
-  dispatcher->Send(new PpapiHostMsg_PPBURLLoader_Create(
-      API_ID_PPB_URL_LOADER, pp_instance, &result));
-  if (result.is_null())
-    return 0;
-  return PPB_URLLoader_Proxy::TrackPluginResource(result);
-}
-
-bool PPB_URLLoader_Proxy::OnMessageReceived(const IPC::Message& msg) {
-  bool handled = true;
-  IPC_BEGIN_MESSAGE_MAP(PPB_URLLoader_Proxy, msg)
-#if !defined(OS_NACL)
-    IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBURLLoader_Create,
-                        OnMsgCreate)
-    IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBURLLoader_Open,
-                        OnMsgOpen)
-    IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBURLLoader_FollowRedirect,
-                        OnMsgFollowRedirect)
-    IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBURLLoader_GetResponseInfo,
-                        OnMsgGetResponseInfo)
-    IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBURLLoader_ReadResponseBody,
-                        OnMsgReadResponseBody)
-    IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBURLLoader_FinishStreamingToFile,
-                        OnMsgFinishStreamingToFile)
-    IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBURLLoader_Close,
-                        OnMsgClose)
-    IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBURLLoader_GrantUniversalAccess,
-                        OnMsgGrantUniversalAccess)
-#endif  // !defined(OS_NACL)
-
-    IPC_MESSAGE_HANDLER(PpapiMsg_PPBURLLoader_UpdateProgress,
-                        OnMsgUpdateProgress)
-    IPC_MESSAGE_HANDLER(PpapiMsg_PPBURLLoader_ReadResponseBody_Ack,
-                        OnMsgReadResponseBodyAck)
-    IPC_MESSAGE_HANDLER(PpapiMsg_PPBURLLoader_CallbackComplete,
-                        OnMsgCallbackComplete)
-    IPC_MESSAGE_UNHANDLED(handled = false)
-  IPC_END_MESSAGE_MAP()
-  // TODO(brettw) handle bad messages!
-  return handled;
-}
-
-#if !defined(OS_NACL)
-void PPB_URLLoader_Proxy::PrepareURLLoaderForSendingToPlugin(
-    PP_Resource resource) {
-  // So the plugin can query load status, we need to register our status
-  // callback before sending any URLLoader to the plugin.
-  EnterResourceNoLock<PPB_URLLoader_API> enter(resource, false);
-  if (enter.succeeded())
-    enter.object()->RegisterStatusCallback(&UpdateResourceLoadStatus);
-  else
-    NOTREACHED();  // Only called internally, resource should be valid.
-}
-
-void PPB_URLLoader_Proxy::OnMsgCreate(PP_Instance instance,
-                                      HostResource* result) {
-  thunk::EnterResourceCreation enter(instance);
-  if (enter.succeeded()) {
-    result->SetHostResource(instance,
-                            enter.functions()->CreateURLLoader(instance));
-    PrepareURLLoaderForSendingToPlugin(result->host_resource());
-  }
-}
-
-void PPB_URLLoader_Proxy::OnMsgOpen(const HostResource& loader,
-                                    const URLRequestInfoData& data) {
-  int peer_pid = dispatcher()->channel()->peer_pid();
-
-  EnterHostFromHostResourceForceCallback<PPB_URLLoader_API> enter(
-      loader, callback_factory_, &PPB_URLLoader_Proxy::OnCallback, loader);
-  enter.SetResult(enter.object()->Open(data, peer_pid, enter.callback()));
-  // TODO(brettw) bug 73236 register for the status callbacks.
-}
-
-void PPB_URLLoader_Proxy::OnMsgFollowRedirect(
-    const HostResource& loader) {
-  EnterHostFromHostResourceForceCallback<PPB_URLLoader_API> enter(
-      loader, callback_factory_, &PPB_URLLoader_Proxy::OnCallback, loader);
-  if (enter.succeeded())
-    enter.SetResult(enter.object()->FollowRedirect(enter.callback()));
-}
-
-void PPB_URLLoader_Proxy::OnMsgGetResponseInfo(const HostResource& loader,
-                                               bool* success,
-                                               URLResponseInfoData* result) {
-  EnterHostFromHostResource<PPB_URLLoader_API> enter(loader);
-  if (enter.succeeded())
-    *success = enter.object()->GetResponseInfoData(result);
-  else
-    *success = false;
-}
-
-void PPB_URLLoader_Proxy::OnMsgReadResponseBody(
-    const HostResource& loader,
-    int32_t bytes_to_read) {
-  // The plugin could be sending us malicious messages, don't accept negative
-  // sizes.
-  if (bytes_to_read < 0) {
-    // TODO(brettw) kill plugin.
-    bytes_to_read = 0;
-  }
-
-  // Read more than requested if there are bytes available for synchronous
-  // reading. This prevents us from getting too far behind due to IPC message
-  // latency. Any extra data will get buffered in the plugin.
-  int32_t synchronously_available_bytes =
-      static_cast<HostDispatcher*>(dispatcher())->ppb_proxy()->
-          GetURLLoaderBufferedBytes(loader.host_resource());
-  if (bytes_to_read < kMaxReadBufferSize) {
-    // Grow the amount to read so we read ahead synchronously, if possible.
-    bytes_to_read =
-        std::max(bytes_to_read,
-                 std::min(synchronously_available_bytes, kMaxReadBufferSize));
-  }
-
-  // This heap object will get deleted by the callback handler.
-  // TODO(brettw) this will be leaked if the plugin closes the resource!
-  // (Also including the plugin unloading and having the resource implicitly
-  // destroyed. Depending on the cleanup ordering, we may not need the weak
-  // pointer here.)
-  IPC::Message* message =
-      new PpapiMsg_PPBURLLoader_ReadResponseBody_Ack(API_ID_PPB_URL_LOADER);
-  IPC::ParamTraits<HostResource>::Write(message, loader);
-
-  char* ptr = message->BeginWriteData(bytes_to_read);
-  if (!ptr) {
-    // TODO(brettw) have a way to check for out-of-memory.
-  }
-
-  EnterHostFromHostResourceForceCallback<PPB_URLLoader_API> enter(
-      loader, callback_factory_, &PPB_URLLoader_Proxy::OnReadCallback, message);
-  if (enter.succeeded()) {
-    enter.SetResult(enter.object()->ReadResponseBody(ptr, bytes_to_read,
-                                                     enter.callback()));
-  }
-}
-
-void PPB_URLLoader_Proxy::OnMsgFinishStreamingToFile(
-    const HostResource& loader) {
-  EnterHostFromHostResourceForceCallback<PPB_URLLoader_API> enter(
-      loader, callback_factory_, &PPB_URLLoader_Proxy::OnCallback, loader);
-  if (enter.succeeded())
-    enter.SetResult(enter.object()->FinishStreamingToFile(enter.callback()));;
-}
-
-void PPB_URLLoader_Proxy::OnMsgClose(const HostResource& loader) {
-  EnterHostFromHostResource<PPB_URLLoader_API> enter(loader);
-  if (enter.succeeded())
-    enter.object()->Close();
-}
-
-void PPB_URLLoader_Proxy::OnMsgGrantUniversalAccess(
-    const HostResource& loader) {
-  EnterHostFromHostResource<PPB_URLLoader_API> enter(loader);
-  if (enter.succeeded())
-    enter.object()->GrantUniversalAccess();
-}
-#endif  // !defined(OS_NACL)
-
-// Called in the Plugin.
-void PPB_URLLoader_Proxy::OnMsgUpdateProgress(
-    const PPBURLLoader_UpdateProgress_Params& params) {
-  EnterPluginFromHostResource<PPB_URLLoader_API> enter(params.resource);
-  if (enter.succeeded())
-    static_cast<URLLoader*>(enter.object())->UpdateProgress(params);
-}
-
-// Called in the Plugin.
-void PPB_URLLoader_Proxy::OnMsgReadResponseBodyAck(
-    const IPC::Message& message) {
-  PickleIterator iter(message);
-
-  HostResource host_resource;
-  if (!IPC::ParamTraits<HostResource>::Read(&message, &iter, &host_resource)) {
-    NOTREACHED() << "Expecting HostResource";
-    return;
-  }
-
-  const char* data;
-  int data_len;
-  if (!iter.ReadData(&data, &data_len)) {
-    NOTREACHED() << "Expecting data";
-    return;
-  }
-
-  int result;
-  if (!iter.ReadInt(&result)) {
-    NOTREACHED() << "Expecting result";
-    return;
-  }
-
-  if (result >= 0 && result != data_len) {
-    NOTREACHED() << "Data size mismatch";
-    return;
-  }
-
-  EnterPluginFromHostResource<PPB_URLLoader_API> enter(host_resource);
-  if (enter.succeeded())
-    static_cast<URLLoader*>(enter.object())->ReadResponseBodyAck(result, data);
-}
-
-// Called in the plugin.
-void PPB_URLLoader_Proxy::OnMsgCallbackComplete(
-    const HostResource& host_resource,
-    int32_t result) {
-  EnterPluginFromHostResource<PPB_URLLoader_API> enter(host_resource);
-  if (enter.succeeded())
-    static_cast<URLLoader*>(enter.object())->CallbackComplete(result);
-}
-
-#if !defined(OS_NACL)
-void PPB_URLLoader_Proxy::OnReadCallback(int32_t result,
-                                         IPC::Message* message) {
-  int32_t bytes_read = 0;
-  if (result > 0)
-    bytes_read = result;  // Positive results indicate bytes read.
-
-  message->TrimWriteData(bytes_read);
-  message->WriteInt(result);
-
-  dispatcher()->Send(message);
-}
-
-void PPB_URLLoader_Proxy::OnCallback(int32_t result,
-                                     const HostResource& resource) {
-  dispatcher()->Send(new PpapiMsg_PPBURLLoader_CallbackComplete(
-      API_ID_PPB_URL_LOADER, resource, result));
-}
-#endif  // !defined(OS_NACL)
-
-}  // namespace proxy
-}  // namespace ppapi
diff --git a/ppapi/proxy/ppb_url_loader_proxy.h b/ppapi/proxy/ppb_url_loader_proxy.h
deleted file mode 100644
index f4c5bc5..0000000
--- a/ppapi/proxy/ppb_url_loader_proxy.h
+++ /dev/null
@@ -1,92 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef PPAPI_PPB_URL_LOADER_PROXY_H_
-#define PPAPI_PPB_URL_LOADER_PROXY_H_
-
-#include "ppapi/c/pp_completion_callback.h"
-#include "ppapi/c/pp_instance.h"
-#include "ppapi/c/pp_module.h"
-#include "ppapi/c/pp_resource.h"
-#include "ppapi/c/pp_size.h"
-#include "ppapi/c/pp_var.h"
-#include "ppapi/c/ppb_url_loader.h"
-#include "ppapi/c/trusted/ppb_url_loader_trusted.h"
-#include "ppapi/proxy/interface_proxy.h"
-#include "ppapi/proxy/proxy_completion_callback_factory.h"
-#include "ppapi/shared_impl/host_resource.h"
-#include "ppapi/utility/completion_callback_factory.h"
-
-namespace ppapi {
-
-struct URLRequestInfoData;
-struct URLResponseInfoData;
-
-namespace proxy {
-
-struct PPBURLLoader_UpdateProgress_Params;
-
-class PPB_URLLoader_Proxy : public InterfaceProxy {
- public:
-  PPB_URLLoader_Proxy(Dispatcher* dispatcher);
-  virtual ~PPB_URLLoader_Proxy();
-
-  static const Info* GetTrustedInfo();
-
-  static PP_Resource CreateProxyResource(PP_Instance instance);
-
-  // URLLoader objects are normally allocated by the Create function, but
-  // they are also provided to PPP_Instance.OnMsgHandleDocumentLoad. This
-  // function allows the proxy for DocumentLoad to create the correct plugin
-  // proxied info for the given browser-supplied URLLoader resource ID.
-  static PP_Resource TrackPluginResource(
-      const HostResource& url_loader_resource);
-
-  // InterfaceProxy implementation.
-  virtual bool OnMessageReceived(const IPC::Message& msg);
-
-  // URLLoader objects are sent from places other than just URLLoader.Create,
-  // in particular when doing a full-frame plugin. This function does the
-  // necessary setup in the host before the resource is sent. Call this any
-  // time you're sending a new URLLoader that the plugin hasn't seen yet.
-  void PrepareURLLoaderForSendingToPlugin(PP_Resource resource);
-
-  static const ApiID kApiID = API_ID_PPB_URL_LOADER;
-
- private:
-  // Plugin->renderer message handlers.
-  void OnMsgCreate(PP_Instance instance,
-                   HostResource* result);
-  void OnMsgOpen(const HostResource& loader,
-                 const URLRequestInfoData& data);
-  void OnMsgFollowRedirect(const HostResource& loader);
-  void OnMsgGetResponseInfo(const HostResource& loader,
-                            bool* success,
-                            URLResponseInfoData* result);
-  void OnMsgReadResponseBody(const HostResource& loader,
-                             int32_t bytes_to_read);
-  void OnMsgFinishStreamingToFile(const HostResource& loader);
-  void OnMsgClose(const HostResource& loader);
-  void OnMsgGrantUniversalAccess(const HostResource& loader);
-
-  // Renderer->plugin message handlers.
-  void OnMsgUpdateProgress(
-      const PPBURLLoader_UpdateProgress_Params& params);
-  void OnMsgReadResponseBodyAck(const IPC::Message& message);
-  void OnMsgCallbackComplete(const HostResource& host_resource, int32_t result);
-
-  // Handles callbacks for read complete messages. Takes ownership of the
-  // message pointer.
-  void OnReadCallback(int32_t result, IPC::Message* message);
-
-  // Handles callback for everything but reads.
-  void OnCallback(int32_t result, const HostResource& resource);
-
-  ProxyCompletionCallbackFactory<PPB_URLLoader_Proxy> callback_factory_;
-};
-
-}  // namespace proxy
-}  // namespace ppapi
-
-#endif  // PPAPI_PPB_URL_LOADER_PROXY_H_
diff --git a/ppapi/proxy/ppp_instance_proxy.cc b/ppapi/proxy/ppp_instance_proxy.cc
index eb1d4e4..a7a0699 100644
--- a/ppapi/proxy/ppp_instance_proxy.cc
+++ b/ppapi/proxy/ppp_instance_proxy.cc
@@ -13,11 +13,14 @@
 #include "ppapi/c/ppp_instance.h"
 #include "ppapi/proxy/host_dispatcher.h"
 #include "ppapi/proxy/plugin_dispatcher.h"
+#include "ppapi/proxy/plugin_globals.h"
+#include "ppapi/proxy/plugin_proxy_delegate.h"
 #include "ppapi/proxy/plugin_resource_tracker.h"
 #include "ppapi/proxy/ppapi_messages.h"
-#include "ppapi/proxy/ppb_url_loader_proxy.h"
+#include "ppapi/proxy/url_loader_resource.h"
 #include "ppapi/shared_impl/ppapi_globals.h"
 #include "ppapi/shared_impl/ppb_view_shared.h"
+#include "ppapi/shared_impl/resource_tracker.h"
 #include "ppapi/shared_impl/scoped_pp_resource.h"
 #include "ppapi/thunk/enter.h"
 #include "ppapi/thunk/ppb_flash_fullscreen_api.h"
@@ -83,36 +86,11 @@
                                               instance, has_focus));
 }
 
-PP_Bool HandleDocumentLoad(PP_Instance instance,
-                           PP_Resource url_loader) {
-  PP_Bool result = PP_FALSE;
-  HostDispatcher* dispatcher = HostDispatcher::GetForInstance(instance);
-
-  // Set up the URLLoader for proxying.
-
-  PPB_URLLoader_Proxy* url_loader_proxy = static_cast<PPB_URLLoader_Proxy*>(
-      dispatcher->GetInterfaceProxy(API_ID_PPB_URL_LOADER));
-  url_loader_proxy->PrepareURLLoaderForSendingToPlugin(url_loader);
-
-  // PluginResourceTracker in the plugin process assumes that resources that it
-  // tracks have been addrefed on behalf of the plugin at the renderer side. So
-  // we explicitly do it for |url_loader| here.
-  //
-  // Please also see comments in PPP_Instance_Proxy::OnMsgHandleDocumentLoad()
-  // about releasing of this extra reference.
-  const PPB_Core* core = reinterpret_cast<const PPB_Core*>(
-      dispatcher->local_get_interface()(PPB_CORE_INTERFACE));
-  if (!core) {
-    NOTREACHED();
-    return PP_FALSE;
-  }
-  core->AddRefResource(url_loader);
-
-  HostResource serialized_loader;
-  serialized_loader.SetHostResource(instance, url_loader);
-  dispatcher->Send(new PpapiMsg_PPPInstance_HandleDocumentLoad(
-      API_ID_PPP_INSTANCE, instance, serialized_loader, &result));
-  return result;
+PP_Bool HandleDocumentLoad(PP_Instance instance, PP_Resource url_loader) {
+  // This should never get called. Out-of-process document loads are handled
+  // specially.
+  NOTREACHED();
+  return PP_FALSE;
 }
 
 static const PPP_Instance_1_1 instance_interface = {
@@ -253,19 +231,25 @@
 
 void PPP_Instance_Proxy::OnPluginMsgHandleDocumentLoad(
     PP_Instance instance,
-    const HostResource& url_loader,
-    PP_Bool* result) {
-  PP_Resource plugin_loader =
-      PPB_URLLoader_Proxy::TrackPluginResource(url_loader);
-  *result = combined_interface_->HandleDocumentLoad(instance, plugin_loader);
+    int pending_loader_host_id,
+    const URLResponseInfoData& data) {
+  PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance);
+  if (!dispatcher)
+    return;
+  Connection connection(PluginGlobals::Get()->GetBrowserSender(),
+                        dispatcher);
 
-  // This balances the one reference that TrackPluginResource() initialized it
-  // with. The plugin will normally take an additional reference which will keep
-  // the resource alive in the plugin (and the one reference in the renderer
-  // representing all plugin references).
-  // Once all references at the plugin side are released, the renderer side will
-  // be notified and release the reference added in HandleDocumentLoad() above.
-  PpapiGlobals::Get()->GetResourceTracker()->ReleaseResource(plugin_loader);
+  scoped_refptr<URLLoaderResource> loader_resource(
+      new URLLoaderResource(connection, instance,
+                            pending_loader_host_id, data));
+
+  PP_Resource loader_pp_resource = loader_resource->GetReference();
+  if (!combined_interface_->HandleDocumentLoad(instance, loader_pp_resource))
+    loader_resource->Close();
+  // We don't pass a ref into the plugin, if it wants one, it will have taken
+  // an additional one.
+  PpapiGlobals::Get()->GetResourceTracker()->ReleaseResource(
+      loader_pp_resource);
 }
 
 }  // namespace proxy
diff --git a/ppapi/proxy/ppp_instance_proxy.h b/ppapi/proxy/ppp_instance_proxy.h
index 1b599d0..85ae55c 100644
--- a/ppapi/proxy/ppp_instance_proxy.h
+++ b/ppapi/proxy/ppp_instance_proxy.h
@@ -20,6 +20,7 @@
 
 namespace ppapi {
 
+struct URLResponseInfoData;
 struct ViewData;
 
 namespace proxy {
@@ -50,8 +51,9 @@
                                 PP_Bool flash_fullscreen);
   void OnPluginMsgDidChangeFocus(PP_Instance instance, PP_Bool has_focus);
   void OnPluginMsgHandleDocumentLoad(PP_Instance instance,
-                                     const HostResource& url_loader,
-                                     PP_Bool* result);
+                                     int pending_loader_host_id,
+                                     const URLResponseInfoData& data);
+
   scoped_ptr<PPP_Instance_Combined> combined_interface_;
 };
 
diff --git a/ppapi/proxy/raw_var_data_unittest.cc b/ppapi/proxy/raw_var_data_unittest.cc
index 8a00d21..2b134af 100644
--- a/ppapi/proxy/raw_var_data_unittest.cc
+++ b/ppapi/proxy/raw_var_data_unittest.cc
@@ -4,8 +4,6 @@
 
 #include "ppapi/proxy/raw_var_data.h"
 
-#include <cmath>
-
 #include "base/logging.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
@@ -18,6 +16,7 @@
 #include "ppapi/shared_impl/proxy_lock.h"
 #include "ppapi/shared_impl/scoped_pp_var.h"
 #include "ppapi/shared_impl/test_globals.h"
+#include "ppapi/shared_impl/unittest_utils.h"
 #include "ppapi/shared_impl/var.h"
 #include "ppapi/shared_impl/var_tracker.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -45,153 +44,6 @@
   TestGlobals globals_;
 };
 
-// Compares two vars for equality. When two vars are found to be equal, an entry
-// is inserted into |visited_map| with (expected id, actual id). When comparing
-// two PP_Vars that have a graph of references, this avoids following reference
-// cycles. It also ensures that a var with ID x in the graph is always equal
-// to a var with ID y. This guarantees that the topology of the two graphs
-// being compared is identical.
-bool Equals(const PP_Var& expected,
-            const PP_Var& actual,
-            base::hash_map<int64_t, int64_t>* visited_map) {
-  if (expected.type != actual.type) {
-    LOG(ERROR) << "expected type: " << expected.type <<
-        " actual type: " << actual.type;
-    return false;
-  }
-  if (VarTracker::IsVarTypeRefcounted(expected.type)) {
-    base::hash_map<int64_t, int64_t>::iterator it =
-        visited_map->find(expected.value.as_id);
-    if (it != visited_map->end()) {
-      if (it->second != actual.value.as_id) {
-        LOG(ERROR) << "expected id: " << it->second << " actual id: " <<
-            actual.value.as_id;
-        return false;
-      } else {
-        return true;
-      }
-    } else {
-      (*visited_map)[expected.value.as_id] = actual.value.as_id;
-    }
-  }
-  switch (expected.type) {
-    case PP_VARTYPE_UNDEFINED:
-      return true;
-    case PP_VARTYPE_NULL:
-      return true;
-    case PP_VARTYPE_BOOL:
-      if (expected.value.as_bool != actual.value.as_bool) {
-        LOG(ERROR) << "expected: " << expected.value.as_bool << " actual: " <<
-            actual.value.as_bool;
-        return false;
-      }
-      return true;
-    case PP_VARTYPE_INT32:
-      if (expected.value.as_int != actual.value.as_int) {
-        LOG(ERROR) << "expected: " << expected.value.as_int << " actual: " <<
-            actual.value.as_int;
-        return false;
-      }
-      return true;
-    case PP_VARTYPE_DOUBLE:
-      if (fabs(expected.value.as_double - actual.value.as_double) > 1.0e-4) {
-        LOG(ERROR) << "expected: " << expected.value.as_double <<
-            " actual: " << actual.value.as_double;
-        return false;
-      }
-      return true;
-    case PP_VARTYPE_OBJECT:
-      if (expected.value.as_id != actual.value.as_id) {
-        LOG(ERROR) << "expected: " << expected.value.as_id << " actual: " <<
-            actual.value.as_id;
-        return false;
-      }
-      return true;
-    case PP_VARTYPE_STRING: {
-      StringVar* expected_var = StringVar::FromPPVar(expected);
-      StringVar* actual_var = StringVar::FromPPVar(actual);
-      DCHECK(expected_var && actual_var);
-      if (expected_var->value() != actual_var->value()) {
-        LOG(ERROR) << "expected: " << expected_var->value() << " actual: " <<
-            actual_var->value();
-        return false;
-      }
-      return true;
-    }
-    case PP_VARTYPE_ARRAY_BUFFER: {
-      ArrayBufferVar* expected_var = ArrayBufferVar::FromPPVar(expected);
-      ArrayBufferVar* actual_var = ArrayBufferVar::FromPPVar(actual);
-      DCHECK(expected_var && actual_var);
-      if (expected_var->ByteLength() != actual_var->ByteLength()) {
-        LOG(ERROR) << "expected: " << expected_var->ByteLength() <<
-            " actual: " << actual_var->ByteLength();
-        return false;
-      }
-      if (memcmp(expected_var->Map(), actual_var->Map(),
-                 expected_var->ByteLength()) != 0) {
-        LOG(ERROR) << "expected array buffer does not match actual.";
-        return false;
-      }
-      return true;
-    }
-    case PP_VARTYPE_ARRAY: {
-      ArrayVar* expected_var = ArrayVar::FromPPVar(expected);
-      ArrayVar* actual_var = ArrayVar::FromPPVar(actual);
-      DCHECK(expected_var && actual_var);
-      if (expected_var->elements().size() != actual_var->elements().size()) {
-        LOG(ERROR) << "expected: " << expected_var->elements().size() <<
-            " actual: " << actual_var->elements().size();
-        return false;
-      }
-      for (size_t i = 0; i < expected_var->elements().size(); ++i) {
-        if (!Equals(expected_var->elements()[i].get(),
-                    actual_var->elements()[i].get(),
-                    visited_map)) {
-          return false;
-        }
-      }
-      return true;
-    }
-    case PP_VARTYPE_DICTIONARY: {
-      DictionaryVar* expected_var = DictionaryVar::FromPPVar(expected);
-      DictionaryVar* actual_var = DictionaryVar::FromPPVar(actual);
-      DCHECK(expected_var && actual_var);
-      if (expected_var->key_value_map().size() !=
-          actual_var->key_value_map().size()) {
-        LOG(ERROR) << "expected: " << expected_var->key_value_map().size() <<
-            " actual: " << actual_var->key_value_map().size();
-        return false;
-      }
-      DictionaryVar::KeyValueMap::const_iterator expected_iter =
-          expected_var->key_value_map().begin();
-      DictionaryVar::KeyValueMap::const_iterator actual_iter =
-          actual_var->key_value_map().begin();
-      for ( ; expected_iter != expected_var->key_value_map().end();
-           ++expected_iter, ++actual_iter) {
-        if (expected_iter->first != actual_iter->first) {
-          LOG(ERROR) << "expected: " << expected_iter->first <<
-              " actual: " << actual_iter->first;
-          return false;
-        }
-        if (!Equals(expected_iter->second.get(),
-                    actual_iter->second.get(),
-                    visited_map)) {
-          return false;
-        }
-      }
-      return true;
-    }
-  }
-  NOTREACHED();
-  return false;
-}
-
-bool Equals(const PP_Var& expected,
-            const PP_Var& actual) {
-  base::hash_map<int64_t, int64_t> visited_map;
-  return Equals(expected, actual, &visited_map);
-}
-
 PP_Var WriteAndRead(const PP_Var& var) {
   PP_Instance dummy_instance = 1234;
   scoped_ptr<RawVarDataGraph> expected_data(RawVarDataGraph::Create(
@@ -207,7 +59,7 @@
 bool WriteReadAndCompare(const PP_Var& var) {
   ScopedPPVar expected(ScopedPPVar::PassRef(), var);
   ScopedPPVar actual(ScopedPPVar::PassRef(), WriteAndRead(expected.get()));
-  return Equals(expected.get(), actual.get());
+  return TestEqual(expected.get(), actual.get());
 }
 
 }  // namespace
@@ -310,7 +162,7 @@
   dictionary->SetWithStringKey("10", release_array.get());
   ScopedPPVar result = ScopedPPVar(ScopedPPVar::PassRef(),
                                    WriteAndRead(release_dictionary.get()));
-  EXPECT_TRUE(Equals(release_dictionary.get(), result.get()));
+  EXPECT_TRUE(TestEqual(release_dictionary.get(), result.get()));
   // Break the cycle.
   // TODO(raymes): We need some better machinery for releasing vars with
   // cycles. Remove the code below once we have that.
@@ -322,7 +174,7 @@
   array->Set(index, release_array.get());
   result = ScopedPPVar(ScopedPPVar::PassRef(),
                        WriteAndRead(release_array.get()));
-  EXPECT_TRUE(Equals(release_array.get(), result.get()));
+  EXPECT_TRUE(TestEqual(release_array.get(), result.get()));
   // Break the self reference.
   array->Set(index, PP_MakeUndefined());
   ArrayVar* result_array = ArrayVar::FromPPVar(result.get());
diff --git a/ppapi/proxy/resource_creation_proxy.cc b/ppapi/proxy/resource_creation_proxy.cc
index 8bbe862..b15f23d 100644
--- a/ppapi/proxy/resource_creation_proxy.cc
+++ b/ppapi/proxy/resource_creation_proxy.cc
@@ -14,7 +14,7 @@
 #include "ppapi/proxy/file_chooser_resource.h"
 #include "ppapi/proxy/file_io_resource.h"
 #include "ppapi/proxy/file_system_resource.h"
-#include "ppapi/proxy/flash_device_id_resource.h"
+#include "ppapi/proxy/flash_drm_resource.h"
 #include "ppapi/proxy/flash_font_file_resource.h"
 #include "ppapi/proxy/flash_menu_resource.h"
 #include "ppapi/proxy/graphics_2d_resource.h"
@@ -33,13 +33,13 @@
 #include "ppapi/proxy/ppb_network_monitor_private_proxy.h"
 #include "ppapi/proxy/ppb_tcp_server_socket_private_proxy.h"
 #include "ppapi/proxy/ppb_tcp_socket_private_proxy.h"
-#include "ppapi/proxy/ppb_url_loader_proxy.h"
 #include "ppapi/proxy/ppb_video_decoder_proxy.h"
 #include "ppapi/proxy/ppb_x509_certificate_private_proxy.h"
 #include "ppapi/proxy/printing_resource.h"
 #include "ppapi/proxy/talk_resource.h"
 #include "ppapi/proxy/truetype_font_resource.h"
 #include "ppapi/proxy/udp_socket_private_resource.h"
+#include "ppapi/proxy/url_loader_resource.h"
 #include "ppapi/proxy/url_request_info_resource.h"
 #include "ppapi/proxy/url_response_info_resource.h"
 #include "ppapi/proxy/video_capture_resource.h"
@@ -82,6 +82,11 @@
   return PPB_FileRef_Proxy::CreateProxyResource(instance, file_system, path);
 }
 
+PP_Resource ResourceCreationProxy::CreateFileRef(
+    const PPB_FileRef_CreateInfo& create_info) {
+  return PPB_FileRef_Proxy::DeserializeFileRef(create_info);
+}
+
 PP_Resource ResourceCreationProxy::CreateFileSystem(
     PP_Instance instance,
     PP_FileSystemType type) {
@@ -166,7 +171,7 @@
 }
 
 PP_Resource ResourceCreationProxy::CreateURLLoader(PP_Instance instance) {
-  return PPB_URLLoader_Proxy::CreateProxyResource(instance);
+    return (new URLLoaderResource(GetConnection(), instance))->GetReference();
 }
 
 PP_Resource ResourceCreationProxy::CreateURLRequestInfo(
@@ -341,8 +346,8 @@
   return PPB_Buffer_Proxy::CreateProxyResource(instance, size);
 }
 
-PP_Resource ResourceCreationProxy::CreateFlashDeviceID(PP_Instance instance) {
-  return (new FlashDeviceIDResource(GetConnection(), instance))->GetReference();
+PP_Resource ResourceCreationProxy::CreateFlashDRM(PP_Instance instance) {
+  return (new FlashDRMResource(GetConnection(), instance))->GetReference();
 }
 
 PP_Resource ResourceCreationProxy::CreateFlashFontFile(
diff --git a/ppapi/proxy/resource_creation_proxy.h b/ppapi/proxy/resource_creation_proxy.h
index 0597c11..2d23f55 100644
--- a/ppapi/proxy/resource_creation_proxy.h
+++ b/ppapi/proxy/resource_creation_proxy.h
@@ -41,6 +41,8 @@
   virtual PP_Resource CreateFileRef(PP_Instance instance,
                                     PP_Resource file_system,
                                     const char* path) OVERRIDE;
+  virtual PP_Resource CreateFileRef(
+      const PPB_FileRef_CreateInfo& create_info) OVERRIDE;
   virtual PP_Resource CreateFileSystem(PP_Instance instance,
                                        PP_FileSystemType type) OVERRIDE;
   virtual PP_Resource CreateIsolatedFileSystem(
@@ -147,7 +149,7 @@
       const PP_BrowserFont_Trusted_Description* description) OVERRIDE;
   virtual PP_Resource CreateBuffer(PP_Instance instance,
                                    uint32_t size) OVERRIDE;
-  virtual PP_Resource CreateFlashDeviceID(PP_Instance instance) OVERRIDE;
+  virtual PP_Resource CreateFlashDRM(PP_Instance instance) OVERRIDE;
   virtual PP_Resource CreateFlashFontFile(
       PP_Instance instance,
       const PP_BrowserFont_Trusted_Description* description,
diff --git a/ppapi/proxy/serialized_structs.h b/ppapi/proxy/serialized_structs.h
index 2b403b4..835142b 100644
--- a/ppapi/proxy/serialized_structs.h
+++ b/ppapi/proxy/serialized_structs.h
@@ -120,11 +120,11 @@
 // TODO(raymes): Make ImageHandle compatible with SerializedHandle.
 #if defined(OS_WIN)
 typedef HANDLE ImageHandle;
-#elif defined(OS_MACOSX) || defined(OS_ANDROID)
-typedef base::SharedMemoryHandle ImageHandle;
-#else
-// On X Windows this is a SysV shared memory key.
+#elif defined(TOOLKIT_GTK)
+// On legacy X Windows this is a SysV shared memory key.
 typedef int ImageHandle;
+#else
+typedef base::SharedMemoryHandle ImageHandle;
 #endif
 
 }  // namespace proxy
diff --git a/ppapi/proxy/url_loader_resource.cc b/ppapi/proxy/url_loader_resource.cc
new file mode 100644
index 0000000..5ee8d95
--- /dev/null
+++ b/ppapi/proxy/url_loader_resource.cc
@@ -0,0 +1,392 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ppapi/proxy/url_loader_resource.h"
+
+#include "base/logging.h"
+#include "ppapi/c/pp_completion_callback.h"
+#include "ppapi/c/pp_errors.h"
+#include "ppapi/c/ppb_url_loader.h"
+#include "ppapi/proxy/dispatch_reply_message.h"
+#include "ppapi/proxy/ppapi_messages.h"
+#include "ppapi/proxy/ppb_file_ref_proxy.h"
+#include "ppapi/proxy/url_request_info_resource.h"
+#include "ppapi/proxy/url_response_info_resource.h"
+#include "ppapi/shared_impl/ppapi_globals.h"
+#include "ppapi/shared_impl/url_response_info_data.h"
+#include "ppapi/thunk/enter.h"
+#include "ppapi/thunk/resource_creation_api.h"
+
+using ppapi::thunk::EnterResourceNoLock;
+using ppapi::thunk::PPB_URLLoader_API;
+using ppapi::thunk::PPB_URLRequestInfo_API;
+
+#ifdef _MSC_VER
+// Do not warn about use of std::copy with raw pointers.
+#pragma warning(disable : 4996)
+#endif
+
+namespace ppapi {
+namespace proxy {
+
+URLLoaderResource::URLLoaderResource(Connection connection,
+                                     PP_Instance instance)
+    : PluginResource(connection, instance),
+      mode_(MODE_WAITING_TO_OPEN),
+      status_callback_(NULL),
+      bytes_sent_(0),
+      total_bytes_to_be_sent_(-1),
+      bytes_received_(0),
+      total_bytes_to_be_received_(-1),
+      user_buffer_(NULL),
+      user_buffer_size_(0),
+      done_status_(PP_OK_COMPLETIONPENDING),
+      is_streaming_to_file_(false),
+      is_asynchronous_load_suspended_(false) {
+  SendCreate(RENDERER, PpapiHostMsg_URLLoader_Create());
+}
+
+URLLoaderResource::URLLoaderResource(Connection connection,
+                                     PP_Instance instance,
+                                     int pending_main_document_loader_id,
+                                     const ppapi::URLResponseInfoData& data)
+    : PluginResource(connection, instance),
+      mode_(MODE_OPENING),
+      status_callback_(NULL),
+      bytes_sent_(0),
+      total_bytes_to_be_sent_(-1),
+      bytes_received_(0),
+      total_bytes_to_be_received_(-1),
+      user_buffer_(NULL),
+      user_buffer_size_(0),
+      done_status_(PP_OK_COMPLETIONPENDING),
+      is_streaming_to_file_(false),
+      is_asynchronous_load_suspended_(false) {
+  AttachToPendingHost(RENDERER, pending_main_document_loader_id);
+  SaveResponseInfo(data);
+}
+
+URLLoaderResource::~URLLoaderResource() {
+}
+
+PPB_URLLoader_API* URLLoaderResource::AsPPB_URLLoader_API() {
+  return this;
+}
+
+int32_t URLLoaderResource::Open(PP_Resource request_id,
+                                scoped_refptr<TrackedCallback> callback) {
+  EnterResourceNoLock<PPB_URLRequestInfo_API> enter_request(request_id, true);
+  if (enter_request.failed()) {
+    Log(PP_LOGLEVEL_ERROR,
+        "PPB_URLLoader.Open: invalid request resource ID. (Hint to C++ wrapper"
+        " users: use the ResourceRequest constructor that takes an instance or"
+        " else the request will be null.)");
+    return PP_ERROR_BADARGUMENT;
+  }
+  return Open(enter_request.object()->GetData(), 0, callback);
+}
+
+int32_t URLLoaderResource::Open(
+    const ::ppapi::URLRequestInfoData& request_data,
+    int requestor_pid,
+    scoped_refptr<TrackedCallback> callback) {
+  int32_t rv = ValidateCallback(callback);
+  if (rv != PP_OK)
+    return rv;
+  if (mode_ != MODE_WAITING_TO_OPEN)
+    return PP_ERROR_INPROGRESS;
+
+  request_data_ = request_data;
+
+  mode_ = MODE_OPENING;
+  is_asynchronous_load_suspended_ = false;
+
+  RegisterCallback(callback);
+  Post(RENDERER, PpapiHostMsg_URLLoader_Open(request_data));
+  return PP_OK_COMPLETIONPENDING;
+}
+
+int32_t URLLoaderResource::FollowRedirect(
+    scoped_refptr<TrackedCallback> callback) {
+  int32_t rv = ValidateCallback(callback);
+  if (rv != PP_OK)
+    return rv;
+  if (mode_ != MODE_OPENING)
+    return PP_ERROR_INPROGRESS;
+
+  SetDefersLoading(false);  // Allow the redirect to continue.
+  RegisterCallback(callback);
+  return PP_OK_COMPLETIONPENDING;
+}
+
+PP_Bool URLLoaderResource::GetUploadProgress(int64_t* bytes_sent,
+                                              int64_t* total_bytes_to_be_sent) {
+  if (!request_data_.record_upload_progress) {
+    *bytes_sent = 0;
+    *total_bytes_to_be_sent = 0;
+    return PP_FALSE;
+  }
+  *bytes_sent = bytes_sent_;
+  *total_bytes_to_be_sent = total_bytes_to_be_sent_;
+  return PP_TRUE;
+}
+
+PP_Bool URLLoaderResource::GetDownloadProgress(
+    int64_t* bytes_received,
+    int64_t* total_bytes_to_be_received) {
+  if (!request_data_.record_download_progress) {
+    *bytes_received = 0;
+    *total_bytes_to_be_received = 0;
+    return PP_FALSE;
+  }
+  *bytes_received = bytes_received_;
+  *total_bytes_to_be_received = total_bytes_to_be_received_;
+  return PP_TRUE;
+}
+
+PP_Resource URLLoaderResource::GetResponseInfo() {
+  if (response_info_.get())
+    return response_info_->GetReference();
+  return 0;
+}
+
+int32_t URLLoaderResource::ReadResponseBody(
+    void* buffer,
+    int32_t bytes_to_read,
+    scoped_refptr<TrackedCallback> callback) {
+  int32_t rv = ValidateCallback(callback);
+  if (rv != PP_OK)
+    return rv;
+  if (!response_info_.get() ||
+      !response_info_->data().body_as_file_ref.resource.is_null())
+    return PP_ERROR_FAILED;
+  if (bytes_to_read <= 0 || !buffer)
+    return PP_ERROR_BADARGUMENT;
+
+  user_buffer_ = static_cast<char*>(buffer);
+  user_buffer_size_ = bytes_to_read;
+
+  if (!buffer_.empty())
+    return FillUserBuffer();
+
+  // We may have already reached EOF.
+  if (done_status_ != PP_OK_COMPLETIONPENDING) {
+    user_buffer_ = NULL;
+    user_buffer_size_ = 0;
+    return done_status_;
+  }
+
+  RegisterCallback(callback);
+  return PP_OK_COMPLETIONPENDING;
+}
+
+int32_t URLLoaderResource::FinishStreamingToFile(
+    scoped_refptr<TrackedCallback> callback) {
+  int32_t rv = ValidateCallback(callback);
+  if (rv != PP_OK)
+    return rv;
+  if (!response_info_.get() ||
+      response_info_->data().body_as_file_ref.resource.is_null())
+    return PP_ERROR_FAILED;
+
+  // We may have already reached EOF.
+  if (done_status_ != PP_OK_COMPLETIONPENDING)
+    return done_status_;
+
+  is_streaming_to_file_ = true;
+  if (is_asynchronous_load_suspended_)
+    SetDefersLoading(false);
+
+  // Wait for didFinishLoading / didFail.
+  RegisterCallback(callback);
+  return PP_OK_COMPLETIONPENDING;
+}
+
+void URLLoaderResource::Close() {
+  mode_ = MODE_LOAD_COMPLETE;
+  done_status_ = PP_ERROR_ABORTED;
+
+  Post(RENDERER, PpapiHostMsg_URLLoader_Close());
+
+  // Abort the callbacks, the plugin doesn't want to be called back after this.
+  // TODO(brettw) this should fix bug 69457, mark it fixed. ============
+  if (TrackedCallback::IsPending(pending_callback_))
+    pending_callback_->PostAbort();
+}
+
+void URLLoaderResource::GrantUniversalAccess() {
+  Post(RENDERER, PpapiHostMsg_URLLoader_GrantUniversalAccess());
+}
+
+void URLLoaderResource::RegisterStatusCallback(
+    PP_URLLoaderTrusted_StatusCallback callback) {
+  status_callback_ = callback;
+}
+
+void URLLoaderResource::OnReplyReceived(
+    const ResourceMessageReplyParams& params,
+    const IPC::Message& msg) {
+  IPC_BEGIN_MESSAGE_MAP(URLLoaderResource, msg)
+    case PpapiPluginMsg_URLLoader_SendData::ID:
+      // Special message, manually dispatch since we don't want the automatic
+      // unpickling.
+      OnPluginMsgSendData(params, msg);
+      break;
+
+    PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL(
+        PpapiPluginMsg_URLLoader_ReceivedResponse,
+        OnPluginMsgReceivedResponse)
+    PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL(
+        PpapiPluginMsg_URLLoader_FinishedLoading,
+        OnPluginMsgFinishedLoading)
+    PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL(
+        PpapiPluginMsg_URLLoader_UpdateProgress,
+        OnPluginMsgUpdateProgress)
+  IPC_END_MESSAGE_MAP()
+}
+
+void URLLoaderResource::OnPluginMsgReceivedResponse(
+    const ResourceMessageReplyParams& params,
+    const URLResponseInfoData& data) {
+  SaveResponseInfo(data);
+  RunCallback(PP_OK);
+}
+
+void URLLoaderResource::OnPluginMsgSendData(
+    const ResourceMessageReplyParams& params,
+    const IPC::Message& message) {
+  PickleIterator iter(message);
+  const char* data;
+  int data_length;
+  if (!iter.ReadData(&data, &data_length)) {
+    NOTREACHED() << "Expecting data";
+    return;
+  }
+
+  mode_ = MODE_STREAMING_DATA;
+  buffer_.insert(buffer_.end(), data, data + data_length);
+
+  // To avoid letting the network stack download an entire stream all at once,
+  // defer loading when we have enough buffer.
+  // Check for this before we run the callback, even though that could move
+  // data out of the buffer. Doing anything after the callback is unsafe.
+  DCHECK(request_data_.prefetch_buffer_lower_threshold <
+         request_data_.prefetch_buffer_upper_threshold);
+  if (!is_streaming_to_file_ &&
+      !is_asynchronous_load_suspended_ &&
+      (buffer_.size() >= static_cast<size_t>(
+          request_data_.prefetch_buffer_upper_threshold))) {
+    DVLOG(1) << "Suspending async load - buffer size: " << buffer_.size();
+    SetDefersLoading(true);
+  }
+
+  if (user_buffer_)
+    RunCallback(FillUserBuffer());
+  else
+    DCHECK(!TrackedCallback::IsPending(pending_callback_));
+}
+
+void URLLoaderResource::OnPluginMsgFinishedLoading(
+    const ResourceMessageReplyParams& params,
+    int32_t result) {
+  mode_ = MODE_LOAD_COMPLETE;
+  done_status_ = result;
+  user_buffer_ = NULL;
+  user_buffer_size_ = 0;
+
+  // If the client hasn't called any function that takes a callback since
+  // the initial call to Open, or called ReadResponseBody and got a
+  // synchronous return, then the callback will be NULL.
+  if (TrackedCallback::IsPending(pending_callback_))
+    RunCallback(done_status_);
+}
+
+void URLLoaderResource::OnPluginMsgUpdateProgress(
+    const ResourceMessageReplyParams& params,
+    int64_t bytes_sent,
+    int64_t total_bytes_to_be_sent,
+    int64_t bytes_received,
+    int64_t total_bytes_to_be_received) {
+  bytes_sent_ = bytes_sent;
+  total_bytes_to_be_sent_ = total_bytes_to_be_sent;
+  bytes_received_ = bytes_received;
+  total_bytes_to_be_received_ = total_bytes_to_be_received;
+
+  if (status_callback_)
+    status_callback_(pp_instance(), pp_resource(),
+                     bytes_sent_, total_bytes_to_be_sent_,
+                     bytes_received_, total_bytes_to_be_received_);
+}
+
+void URLLoaderResource::SetDefersLoading(bool defers_loading) {
+  Post(RENDERER, PpapiHostMsg_URLLoader_SetDeferLoading(defers_loading));
+}
+
+int32_t URLLoaderResource::ValidateCallback(
+    scoped_refptr<TrackedCallback> callback) {
+  DCHECK(callback);
+  if (TrackedCallback::IsPending(pending_callback_))
+    return PP_ERROR_INPROGRESS;
+  return PP_OK;
+}
+
+void URLLoaderResource::RegisterCallback(
+    scoped_refptr<TrackedCallback> callback) {
+  DCHECK(!TrackedCallback::IsPending(pending_callback_));
+  pending_callback_ = callback;
+}
+
+void URLLoaderResource::RunCallback(int32_t result) {
+  // This may be null when this is a main document loader.
+  if (!pending_callback_.get())
+    return;
+
+  // If |user_buffer_| was set as part of registering a callback, the paths
+  // which trigger that callack must have cleared it since the callback is now
+  // free to delete it.
+  DCHECK(!user_buffer_);
+
+  // As a second line of defense, clear the |user_buffer_| in case the
+  // callbacks get called in an unexpected order.
+  user_buffer_ = NULL;
+  user_buffer_size_ = 0;
+  pending_callback_->Run(result);
+}
+
+void URLLoaderResource::SaveResponseInfo(const URLResponseInfoData& data) {
+  // Create a proxy resource for the the file ref host resource if needed.
+  PP_Resource body_as_file_ref = 0;
+  if (!data.body_as_file_ref.resource.is_null()) {
+    thunk::EnterResourceCreationNoLock enter(pp_instance());
+    body_as_file_ref =
+        enter.functions()->CreateFileRef(data.body_as_file_ref);
+  }
+  response_info_ = new URLResponseInfoResource(
+      connection(), pp_instance(), data, body_as_file_ref);
+}
+
+size_t URLLoaderResource::FillUserBuffer() {
+  DCHECK(user_buffer_);
+  DCHECK(user_buffer_size_);
+
+  size_t bytes_to_copy = std::min(buffer_.size(), user_buffer_size_);
+  std::copy(buffer_.begin(), buffer_.begin() + bytes_to_copy, user_buffer_);
+  buffer_.erase(buffer_.begin(), buffer_.begin() + bytes_to_copy);
+
+  // If the buffer is getting too empty, resume asynchronous loading.
+  if (is_asynchronous_load_suspended_ &&
+      buffer_.size() <= static_cast<size_t>(
+          request_data_.prefetch_buffer_lower_threshold)) {
+    DVLOG(1) << "Resuming async load - buffer size: " << buffer_.size();
+    SetDefersLoading(false);
+  }
+
+  // Reset for next time.
+  user_buffer_ = NULL;
+  user_buffer_size_ = 0;
+  return bytes_to_copy;
+}
+
+}  // namespace proxy
+}  // namespace ppapi
\ No newline at end of file
diff --git a/ppapi/proxy/url_loader_resource.h b/ppapi/proxy/url_loader_resource.h
new file mode 100644
index 0000000..685ccfe
--- /dev/null
+++ b/ppapi/proxy/url_loader_resource.h
@@ -0,0 +1,146 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef PPAPI_PROXY_URL_LOADER_RESOURCE_H_
+#define PPAPI_PROXY_URL_LOADER_RESOURCE_H_
+
+#include <deque>
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "ppapi/c/trusted/ppb_url_loader_trusted.h"
+#include "ppapi/proxy/plugin_resource.h"
+#include "ppapi/proxy/ppapi_proxy_export.h"
+#include "ppapi/shared_impl/url_request_info_data.h"
+#include "ppapi/thunk/ppb_url_loader_api.h"
+
+namespace ppapi {
+namespace proxy {
+
+class URLResponseInfoResource;
+
+class PPAPI_PROXY_EXPORT URLLoaderResource
+    : public PluginResource,
+      public NON_EXPORTED_BASE(thunk::PPB_URLLoader_API) {
+ public:
+  // Constructor for plugin-initiated loads.
+  URLLoaderResource(Connection connection,
+                    PP_Instance instance);
+
+  // Constructor for renderer-initiated (document) loads. The loader ID is the
+  // pending host ID for the already-created host in the renderer, and the
+  // response data is the response for the already-opened connection.
+  URLLoaderResource(Connection connection,
+                    PP_Instance instance,
+                    int pending_main_document_loader_id,
+                    const URLResponseInfoData& data);
+
+  virtual ~URLLoaderResource();
+
+  // Resource override.
+  thunk::PPB_URLLoader_API* AsPPB_URLLoader_API() OVERRIDE;
+
+  // PPB_URLLoader_API implementation.
+  virtual int32_t Open(PP_Resource request_id,
+                       scoped_refptr<TrackedCallback> callback) OVERRIDE;
+  virtual int32_t Open(const URLRequestInfoData& data,
+                       int requestor_pid,
+                       scoped_refptr<TrackedCallback> callback) OVERRIDE;
+  virtual int32_t FollowRedirect(
+      scoped_refptr<TrackedCallback> callback) OVERRIDE;
+  virtual PP_Bool GetUploadProgress(int64_t* bytes_sent,
+                                    int64_t* total_bytes_to_be_sent) OVERRIDE;
+  virtual PP_Bool GetDownloadProgress(
+      int64_t* bytes_received,
+      int64_t* total_bytes_to_be_received) OVERRIDE;
+  virtual PP_Resource GetResponseInfo() OVERRIDE;
+  virtual int32_t ReadResponseBody(
+      void* buffer,
+      int32_t bytes_to_read,
+      scoped_refptr<TrackedCallback> callback) OVERRIDE;
+  virtual int32_t FinishStreamingToFile(
+      scoped_refptr<TrackedCallback> callback) OVERRIDE;
+  virtual void Close() OVERRIDE;
+  virtual void GrantUniversalAccess() OVERRIDE;
+  virtual void RegisterStatusCallback(
+      PP_URLLoaderTrusted_StatusCallback callback) OVERRIDE;
+
+  // PluginResource implementation.
+  virtual void OnReplyReceived(const ResourceMessageReplyParams& params,
+                               const IPC::Message& msg) OVERRIDE;
+
+ private:
+  enum Mode {
+    // The plugin has not called Open() yet.
+    MODE_WAITING_TO_OPEN,
+
+    // The plugin is waiting for the Open() or FollowRedirect callback.
+    MODE_OPENING,
+
+    // We've started to receive data and may receive more.
+    MODE_STREAMING_DATA,
+
+    // All data has been streamed or there was an error.
+    MODE_LOAD_COMPLETE
+  };
+
+  // IPC message handlers.
+  void OnPluginMsgReceivedResponse(const ResourceMessageReplyParams& params,
+                                   const URLResponseInfoData& data);
+  void OnPluginMsgSendData(const ResourceMessageReplyParams& params,
+                           const IPC::Message& message);
+  void OnPluginMsgFinishedLoading(const ResourceMessageReplyParams& params,
+                                  int32_t result);
+  void OnPluginMsgUpdateProgress(const ResourceMessageReplyParams& params,
+                                 int64_t bytes_sent,
+                                 int64_t total_bytes_to_be_sent,
+                                 int64_t bytes_received,
+                                 int64_t total_bytes_to_be_received);
+
+  // Sends the defers loading message to the renderer to block or unblock the
+  // load.
+  void SetDefersLoading(bool defers_loading);
+
+  int32_t ValidateCallback(scoped_refptr<TrackedCallback> callback);
+
+  // Sets up |callback| as the pending callback. This should only be called once
+  // it is certain that |PP_OK_COMPLETIONPENDING| will be returned.
+  void RegisterCallback(scoped_refptr<TrackedCallback> callback);
+
+  void RunCallback(int32_t result);
+
+  // Saves the given response info to response_info_, handling file refs if
+  // necessary. This does not issue any callbacks.
+  void SaveResponseInfo(const URLResponseInfoData& data);
+
+  size_t FillUserBuffer();
+
+  Mode mode_;
+  URLRequestInfoData request_data_;
+
+  scoped_refptr<TrackedCallback> pending_callback_;
+
+  PP_URLLoaderTrusted_StatusCallback status_callback_;
+
+  std::deque<char> buffer_;
+  int64_t bytes_sent_;
+  int64_t total_bytes_to_be_sent_;
+  int64_t bytes_received_;
+  int64_t total_bytes_to_be_received_;
+  char* user_buffer_;
+  size_t user_buffer_size_;
+  int32_t done_status_;
+  bool is_streaming_to_file_;
+  bool is_asynchronous_load_suspended_;
+
+  // The response info if we've received it.
+  scoped_refptr<URLResponseInfoResource> response_info_;
+
+  DISALLOW_COPY_AND_ASSIGN(URLLoaderResource);
+};
+
+}  // namespace proxy
+}  // namespace ppapi
+
+#endif  // PPAPI_PROXY_URL_LOADER_RESOURCE_H_
\ No newline at end of file
diff --git a/ppapi/proxy/url_response_info_resource.h b/ppapi/proxy/url_response_info_resource.h
index f05b32c..dfb1f8f 100644
--- a/ppapi/proxy/url_response_info_resource.h
+++ b/ppapi/proxy/url_response_info_resource.h
@@ -37,6 +37,8 @@
   virtual PP_Var GetProperty(PP_URLResponseProperty property) OVERRIDE;
   virtual PP_Resource GetBodyAsFileRef() OVERRIDE;
 
+  const URLResponseInfoData& data() const { return data_; }
+
  private:
   URLResponseInfoData data_;
 
diff --git a/ppapi/proxy/video_source_resource.cc b/ppapi/proxy/video_source_resource.cc
index 218d883..3bce63d 100644
--- a/ppapi/proxy/video_source_resource.cc
+++ b/ppapi/proxy/video_source_resource.cc
@@ -103,20 +103,21 @@
   // The callback may have been aborted by Close().
   if (TrackedCallback::IsPending(get_frame_callback_)) {
     int32_t result = reply_params.result();
-    if (result == PP_OK) {
+    if (result == PP_OK &&
+        PPB_ImageData_Shared::IsImageDataDescValid(image_desc)) {
       frame->timestamp = timestamp;
 
 #if defined(OS_ANDROID)
       frame->image_data = 0;
-#elif defined(OS_WIN) || defined(OS_MACOSX)
+#elif defined(TOOLKIT_GTK)
+      frame->image_data =
+          (new ImageData(image_data, image_desc, fd))->GetReference();
+#elif defined(OS_LINUX) || defined(OS_WIN) || defined(OS_MACOSX)
       base::SharedMemoryHandle handle;
       if (!reply_params.TakeSharedMemoryHandleAtIndex(0, &handle))
         frame->image_data = 0;
       frame->image_data =
           (new ImageData(image_data, image_desc, handle))->GetReference();
-#elif defined(OS_LINUX)
-      frame->image_data =
-          (new ImageData(image_data, image_desc, fd))->GetReference();
 #else
 #error Not implemented.
 #endif
diff --git a/ppapi/shared_impl/api_id.h b/ppapi/shared_impl/api_id.h
index 00706bf..16955aa 100644
--- a/ppapi/shared_impl/api_id.h
+++ b/ppapi/shared_impl/api_id.h
@@ -45,7 +45,6 @@
   API_ID_PPB_TESTING,
   API_ID_PPB_TEXT_INPUT,
   API_ID_PPB_UDPSOCKET_PRIVATE,
-  API_ID_PPB_URL_LOADER,
   API_ID_PPB_URL_RESPONSE_INFO,
   API_ID_PPB_VAR_ARRAY_BUFFER,
   API_ID_PPB_VAR_DEPRECATED,
diff --git a/ppapi/shared_impl/ppapi_globals.cc b/ppapi/shared_impl/ppapi_globals.cc
index 9f4aaa3..f5166c3 100644
--- a/ppapi/shared_impl/ppapi_globals.cc
+++ b/ppapi/shared_impl/ppapi_globals.cc
@@ -18,29 +18,38 @@
     tls_ppapi_globals_for_test = LAZY_INSTANCE_INITIALIZER;
 }  // namespace
 
-PpapiGlobals* PpapiGlobals::ppapi_globals_ = NULL;
+PpapiGlobals* ppapi_globals = NULL;
 
 PpapiGlobals::PpapiGlobals() {
-  DCHECK(!ppapi_globals_);
-  ppapi_globals_ = this;
+  DCHECK(!ppapi_globals);
+  ppapi_globals = this;
   main_loop_proxy_ = base::MessageLoopProxy::current();
 }
 
 PpapiGlobals::PpapiGlobals(PerThreadForTest) {
-  DCHECK(!ppapi_globals_);
+  DCHECK(!ppapi_globals);
   main_loop_proxy_ = base::MessageLoopProxy::current();
 }
 
 PpapiGlobals::~PpapiGlobals() {
-  DCHECK(ppapi_globals_ == this || !ppapi_globals_);
-  ppapi_globals_ = NULL;
+  DCHECK(ppapi_globals == this || !ppapi_globals);
+  ppapi_globals = NULL;
+}
+
+//Static Getter for the global singleton.
+PpapiGlobals* PpapiGlobals::Get() {
+  if (ppapi_globals)
+    return ppapi_globals;
+  // In unit tests, the following might be valid (see
+  // SetPpapiGlobalsOnThreadForTest). Normally, this will just return NULL.
+  return GetThreadLocalPointer();
 }
 
 // static
 void PpapiGlobals::SetPpapiGlobalsOnThreadForTest(PpapiGlobals* ptr) {
   // If we're using a per-thread PpapiGlobals, we should not have a global one.
   // If we allowed it, it would always over-ride the "test" versions.
-  DCHECK(!ppapi_globals_);
+  DCHECK(!ppapi_globals);
   tls_ppapi_globals_for_test.Pointer()->Set(ptr);
 }
 
diff --git a/ppapi/shared_impl/ppapi_globals.h b/ppapi/shared_impl/ppapi_globals.h
index d226c7f..4c094c1 100644
--- a/ppapi/shared_impl/ppapi_globals.h
+++ b/ppapi/shared_impl/ppapi_globals.h
@@ -49,13 +49,7 @@
   virtual ~PpapiGlobals();
 
   // Getter for the global singleton.
-  inline static PpapiGlobals* Get() {
-    if (ppapi_globals_)
-      return ppapi_globals_;
-    // In unit tests, the following might be valid (see
-    // SetPpapiGlobalsOnThreadForTest). Normally, this will just return NULL.
-    return GetThreadLocalPointer();
-  }
+  static PpapiGlobals* Get();
 
   // This allows us to set a given PpapiGlobals object as the PpapiGlobals for
   // a given thread. After setting the PpapiGlobals for a thread, Get() will
@@ -137,8 +131,6 @@
   // threads to have distinct "globals".
   static PpapiGlobals* GetThreadLocalPointer();
 
-  static PpapiGlobals* ppapi_globals_;
-
   scoped_refptr<base::MessageLoopProxy> main_loop_proxy_;
 
   DISALLOW_COPY_AND_ASSIGN(PpapiGlobals);
diff --git a/ppapi/shared_impl/ppb_audio_config_shared.cc b/ppapi/shared_impl/ppb_audio_config_shared.cc
index 25f356d..8af3c99 100644
--- a/ppapi/shared_impl/ppb_audio_config_shared.cc
+++ b/ppapi/shared_impl/ppb_audio_config_shared.cc
@@ -8,6 +8,14 @@
 
 namespace ppapi {
 
+// Rounds up requested_size to the nearest multiple of minimum_size.
+static uint32_t CalculateMultipleOfSampleFrameCount(uint32_t minimum_size,
+                                                    uint32_t requested_size) {
+  const uint32_t multiple = (requested_size + minimum_size - 1) / minimum_size;
+  return std::min(minimum_size * multiple,
+                  static_cast<uint32_t>(PP_AUDIOMAXSAMPLEFRAMECOUNT));
+}
+
 PPB_AudioConfig_Shared::PPB_AudioConfig_Shared(ResourceObjectType type,
                                                PP_Instance instance)
     : Resource(type, instance),
@@ -62,31 +70,57 @@
   if (sample_frame_count < PP_AUDIOMINSAMPLEFRAMECOUNT)
     sample_frame_count = PP_AUDIOMINSAMPLEFRAMECOUNT;
 
+  // If hardware information isn't available we're connected to a fake audio
+  // output stream on the browser side, so we can use whatever sample count the
+  // client wants.
+  if (!hardware_sample_frame_count || !hardware_sample_rate)
+    return sample_frame_count;
+
+  // Note: All the values below were determined through experimentation to
+  // minimize jitter and back-to-back callbacks from the browser.  Please take
+  // care when modifying these values as they impact a large number of users.
+  // TODO(dalecurtis): Land jitter test and add documentation for updating this.
+
   // If client is using same sample rate as audio hardware, then recommend a
   // multiple of the audio hardware's sample frame count.
-  if (hardware_sample_rate == sample_rate && hardware_sample_frame_count > 0) {
-    // Round up input sample_frame_count to nearest multiple.
-    uint32_t multiple = (sample_frame_count + hardware_sample_frame_count - 1) /
-        hardware_sample_frame_count;
-    uint32_t recommendation = hardware_sample_frame_count * multiple;
-    if (recommendation > PP_AUDIOMAXSAMPLEFRAMECOUNT)
-      recommendation = PP_AUDIOMAXSAMPLEFRAMECOUNT;
-    return recommendation;
+  if (hardware_sample_rate == sample_rate) {
+    return CalculateMultipleOfSampleFrameCount(
+        hardware_sample_frame_count, sample_frame_count);
   }
 
-  // Otherwise, recommend a conservative 50ms buffer based on sample rate.
-  const uint32_t kDefault50msAt44100kHz = 2205;
-  const uint32_t kDefault50msAt48000kHz = 2400;
-  switch (sample_rate) {
-    case PP_AUDIOSAMPLERATE_44100:
-      return kDefault50msAt44100kHz;
-    case PP_AUDIOSAMPLERATE_48000:
-      return kDefault50msAt48000kHz;
-    case PP_AUDIOSAMPLERATE_NONE:
-      return 0;
+  // Should track the value reported by XP and ALSA backends.
+  const uint32_t kHighLatencySampleFrameCount = 2048;
+
+  // If the hardware requires a high latency buffer or we're at a low sample
+  // rate w/ a buffer that's larger than 10ms, choose the nearest multiple of
+  // the high latency sample frame count.  An example of too low and too large
+  // is 16kHz and a sample frame count greater than 160 frames.
+  if (hardware_sample_frame_count >= kHighLatencySampleFrameCount ||
+      (hardware_sample_rate < 44100 &&
+       hardware_sample_frame_count > hardware_sample_rate / 100u)) {
+    return CalculateMultipleOfSampleFrameCount(
+        sample_frame_count,
+        std::max(kHighLatencySampleFrameCount, hardware_sample_frame_count));
   }
-  // Unable to make a recommendation.
-  return 0;
+
+  // All low latency clients should be able to handle a 512 frame buffer with
+  // resampling from 44.1kHz and 48kHz to higher sample rates.
+  // TODO(dalecurtis): We may need to investigate making the callback thread
+  // high priority to handle buffers at the absolute minimum w/o glitching.
+  const uint32_t kLowLatencySampleFrameCount = 512;
+
+  // Special case for 48kHz -> 44.1kHz and buffer sizes greater than 10ms.  In
+  // testing most buffer sizes > 10ms led to glitching, so we choose a size we
+  // know won't cause jitter.
+  int min_sample_frame_count = kLowLatencySampleFrameCount;
+  if (hardware_sample_rate == 44100 && sample_rate == 48000 &&
+      hardware_sample_frame_count > hardware_sample_rate / 100u) {
+    min_sample_frame_count = std::max(
+        2 * kLowLatencySampleFrameCount, hardware_sample_frame_count);
+  }
+
+  return CalculateMultipleOfSampleFrameCount(
+      min_sample_frame_count, sample_frame_count);
 }
 
 // static
@@ -116,6 +150,8 @@
                                   uint32_t sample_frame_count) {
   // TODO(brettw): Currently we don't actually check what the hardware
   // supports, so just allow sample rates of the "guaranteed working" ones.
+  // TODO(dalecurtis): If sample rates are added RecommendSampleFrameCount_1_1()
+  // must be updated to account for the new rates.
   if (sample_rate != PP_AUDIOSAMPLERATE_44100 &&
       sample_rate != PP_AUDIOSAMPLERATE_48000)
     return false;
diff --git a/ppapi/shared_impl/ppb_graphics_3d_shared.cc b/ppapi/shared_impl/ppb_graphics_3d_shared.cc
index e480e0c..4960db5 100644
--- a/ppapi/shared_impl/ppb_graphics_3d_shared.cc
+++ b/ppapi/shared_impl/ppb_graphics_3d_shared.cc
@@ -51,7 +51,7 @@
     return PP_ERROR_BADARGUMENT;
 
   ScopedNoLocking already_locked(this);
-  gles2_impl()->ResizeCHROMIUM(width, height);
+  gles2_impl()->ResizeCHROMIUM(width, height, 1.f);
   // TODO(alokp): Check if resize succeeded and return appropriate error code.
   return PP_OK;
 }
@@ -129,7 +129,9 @@
       share_gles2 ? share_gles2->share_group() : NULL,
       transfer_buffer_.get(),
       false,
-      true));
+      true,
+      NULL  // Do not use GpuMemoryBuffers.
+      ));
 
   if (!gles2_impl_->Initialize(
       transfer_buffer_size,
diff --git a/ppapi/shared_impl/ppb_image_data_shared.cc b/ppapi/shared_impl/ppb_image_data_shared.cc
index 4201a1e..4001d6f 100644
--- a/ppapi/shared_impl/ppb_image_data_shared.cc
+++ b/ppapi/shared_impl/ppb_image_data_shared.cc
@@ -42,4 +42,13 @@
                      format == PP_IMAGEDATAFORMAT_RGBA_PREMUL);
 }
 
+// static
+PP_Bool PPB_ImageData_Shared::IsImageDataDescValid(
+    const PP_ImageDataDesc& desc) {
+  return PP_FromBool(IsImageDataFormatSupported(desc.format) &&
+                     desc.size.width > 0 &&
+                     desc.size.height > 0 &&
+                     desc.stride > 0);
+}
+
 }  // namespace ppapi
diff --git a/ppapi/shared_impl/ppb_image_data_shared.h b/ppapi/shared_impl/ppb_image_data_shared.h
index 0f1f4bb..45cd875 100644
--- a/ppapi/shared_impl/ppb_image_data_shared.h
+++ b/ppapi/shared_impl/ppb_image_data_shared.h
@@ -24,6 +24,7 @@
  public:
   static PP_ImageDataFormat GetNativeImageDataFormat();
   static PP_Bool IsImageDataFormatSupported(PP_ImageDataFormat format);
+  static PP_Bool IsImageDataDescValid(const PP_ImageDataDesc& desc);
 };
 
 }  // namespace ppapi
diff --git a/ppapi/shared_impl/private/net_address_private_impl.cc b/ppapi/shared_impl/private/net_address_private_impl.cc
index 87a929f..6cd87b8 100644
--- a/ppapi/shared_impl/private/net_address_private_impl.cc
+++ b/ppapi/shared_impl/private/net_address_private_impl.cc
@@ -395,8 +395,6 @@
 
 // For the NaCl target, all we need are the API functions and the thunk.
 #if !defined(OS_NACL)
-// static
-const PP_NetAddress_Private NetAddressPrivateImpl::kInvalidNetAddress = { 0 };
 
 // static
 bool NetAddressPrivateImpl::ValidateNetAddress(
diff --git a/ppapi/shared_impl/private/net_address_private_impl_constants.cc b/ppapi/shared_impl/private/net_address_private_impl_constants.cc
new file mode 100644
index 0000000..44cc4d3
--- /dev/null
+++ b/ppapi/shared_impl/private/net_address_private_impl_constants.cc
@@ -0,0 +1,16 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ppapi/shared_impl/private/net_address_private_impl.h"
+
+#include "ppapi/c/private/ppb_net_address_private.h"
+
+namespace ppapi {
+
+#if !defined(OS_NACL)
+// static
+const PP_NetAddress_Private NetAddressPrivateImpl::kInvalidNetAddress = { 0 };
+#endif  // !defined(OS_NACL)
+
+}  // namespace ppapi
diff --git a/ppapi/shared_impl/private/ppb_tcp_server_socket_shared.cc b/ppapi/shared_impl/private/ppb_tcp_server_socket_shared.cc
index f816c62..11add89 100644
--- a/ppapi/shared_impl/private/ppb_tcp_server_socket_shared.cc
+++ b/ppapi/shared_impl/private/ppb_tcp_server_socket_shared.cc
@@ -5,15 +5,18 @@
 #include "ppapi/shared_impl/private/ppb_tcp_server_socket_shared.h"
 
 #include <cstddef>
+#include <cstring>
 
 #include "base/logging.h"
 #include "ppapi/c/pp_errors.h"
+#include "ppapi/shared_impl/private/net_address_private_impl.h"
 
 namespace ppapi {
 
 PPB_TCPServerSocket_Shared::PPB_TCPServerSocket_Shared(PP_Instance instance)
     : Resource(OBJECT_IS_IMPL, instance),
       socket_id_(0),
+      local_addr_(),
       state_(BEFORE_LISTENING),
       tcp_socket_buffer_(NULL) {
 }
@@ -22,6 +25,7 @@
     const HostResource& resource)
     : Resource(OBJECT_IS_PROXY, resource),
       socket_id_(0),
+      local_addr_(),
       state_(BEFORE_LISTENING),
       tcp_socket_buffer_(NULL) {
 }
@@ -69,6 +73,16 @@
   return PP_OK_COMPLETIONPENDING;
 }
 
+int32_t PPB_TCPServerSocket_Shared::GetLocalAddress(
+    PP_NetAddress_Private* addr) {
+  if (!addr)
+    return PP_ERROR_BADARGUMENT;
+  if (state_ != LISTENING)
+    return PP_ERROR_FAILED;
+  *addr = local_addr_;
+  return PP_OK;
+}
+
 void PPB_TCPServerSocket_Shared::StopListening() {
   if (state_ == CLOSED)
     return;
@@ -85,8 +99,10 @@
   tcp_socket_buffer_ = NULL;
 }
 
-void PPB_TCPServerSocket_Shared::OnListenCompleted(uint32 socket_id,
-                                                   int32_t status) {
+void PPB_TCPServerSocket_Shared::OnListenCompleted(
+    uint32 socket_id,
+    const PP_NetAddress_Private& local_addr,
+    int32_t status) {
   if (state_ != BEFORE_LISTENING ||
       !TrackedCallback::IsPending(listen_callback_)) {
     NOTREACHED();
@@ -95,6 +111,7 @@
 
   if (status == PP_OK) {
     socket_id_ = socket_id;
+    local_addr_ = local_addr;
     state_ = LISTENING;
   }
 
diff --git a/ppapi/shared_impl/private/ppb_tcp_server_socket_shared.h b/ppapi/shared_impl/private/ppb_tcp_server_socket_shared.h
index 03c22ab..29d14a2 100644
--- a/ppapi/shared_impl/private/ppb_tcp_server_socket_shared.h
+++ b/ppapi/shared_impl/private/ppb_tcp_server_socket_shared.h
@@ -38,9 +38,12 @@
                          scoped_refptr<TrackedCallback> callback) OVERRIDE;
   virtual int32_t Accept(PP_Resource* tcp_socket,
                          scoped_refptr<TrackedCallback> callback) OVERRIDE;
+  virtual int32_t GetLocalAddress(PP_NetAddress_Private* addr) OVERRIDE;
   virtual void StopListening() OVERRIDE;
 
-  void OnListenCompleted(uint32 socket_id, int32_t status);
+  void OnListenCompleted(uint32 socket_id,
+                         const PP_NetAddress_Private& local_addr,
+                         int32_t status);
   virtual void OnAcceptCompleted(bool succeeded,
                                  uint32 accepted_socket_id,
                                  const PP_NetAddress_Private& local_addr,
@@ -65,6 +68,7 @@
   };
 
   uint32 socket_id_;
+  PP_NetAddress_Private local_addr_;
   State state_;
 
   scoped_refptr<TrackedCallback> listen_callback_;
diff --git a/ppapi/shared_impl/resource.cc b/ppapi/shared_impl/resource.cc
index 2c40961..4fb9a47 100644
--- a/ppapi/shared_impl/resource.cc
+++ b/ppapi/shared_impl/resource.cc
@@ -75,6 +75,7 @@
 }
 
 void Resource::Log(PP_LogLevel level, const std::string& message) {
+printf("Log:%s\n", message.c_str());
   PpapiGlobals::Get()->LogWithSource(pp_instance(), level, std::string(),
                                      message);
 }
diff --git a/ppapi/shared_impl/resource.h b/ppapi/shared_impl/resource.h
index 50513fd..4c5dc35 100644
--- a/ppapi/shared_impl/resource.h
+++ b/ppapi/shared_impl/resource.h
@@ -37,7 +37,7 @@
   F(PPB_FileSystem_API) \
   F(PPB_Find_API) \
   F(PPB_Flash_Clipboard_API) \
-  F(PPB_Flash_DeviceID_API) \
+  F(PPB_Flash_DRM_API) \
   F(PPB_Flash_File_API) \
   F(PPB_Flash_FontFile_API) \
   F(PPB_Flash_Fullscreen_API) \
diff --git a/ppapi/shared_impl/unittest_utils.cc b/ppapi/shared_impl/unittest_utils.cc
new file mode 100644
index 0000000..2c32b30
--- /dev/null
+++ b/ppapi/shared_impl/unittest_utils.cc
@@ -0,0 +1,166 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ppapi/shared_impl/unittest_utils.h"
+
+#include <cmath>
+
+#include "base/hash_tables.h"
+#include "base/logging.h"
+#include "ppapi/shared_impl/array_var.h"
+#include "ppapi/shared_impl/dictionary_var.h"
+#include "ppapi/shared_impl/var.h"
+#include "ppapi/shared_impl/var_tracker.h"
+
+namespace ppapi {
+
+namespace {
+
+// When two vars x and y are found to be equal, an entry is inserted into
+// |visited_map| with (x.value.as_id, y.value.as_id). This allows reference
+// cycles to be avoided. It also allows us to associate nodes in |expected| with
+// nodes in |actual| and check whether the graphs have equivalent topology.
+bool Equals(const PP_Var& expected,
+            const PP_Var& actual,
+            base::hash_map<int64_t, int64_t>* visited_map) {
+  if (expected.type != actual.type) {
+    LOG(ERROR) << "expected type: " << expected.type <<
+        " actual type: " << actual.type;
+    return false;
+  }
+  if (VarTracker::IsVarTypeRefcounted(expected.type)) {
+    base::hash_map<int64_t, int64_t>::iterator it =
+        visited_map->find(expected.value.as_id);
+    if (it != visited_map->end()) {
+      if (it->second != actual.value.as_id) {
+        LOG(ERROR) << "expected id: " << it->second << " actual id: " <<
+            actual.value.as_id;
+        return false;
+      } else {
+        return true;
+      }
+    } else {
+      (*visited_map)[expected.value.as_id] = actual.value.as_id;
+    }
+  }
+  switch (expected.type) {
+    case PP_VARTYPE_UNDEFINED:
+      return true;
+    case PP_VARTYPE_NULL:
+      return true;
+    case PP_VARTYPE_BOOL:
+      if (expected.value.as_bool != actual.value.as_bool) {
+        LOG(ERROR) << "expected: " << expected.value.as_bool << " actual: " <<
+            actual.value.as_bool;
+        return false;
+      }
+      return true;
+    case PP_VARTYPE_INT32:
+      if (expected.value.as_int != actual.value.as_int) {
+        LOG(ERROR) << "expected: " << expected.value.as_int << " actual: " <<
+            actual.value.as_int;
+        return false;
+      }
+      return true;
+    case PP_VARTYPE_DOUBLE:
+      if (fabs(expected.value.as_double - actual.value.as_double) > 1.0e-4) {
+        LOG(ERROR) << "expected: " << expected.value.as_double <<
+            " actual: " << actual.value.as_double;
+        return false;
+      }
+      return true;
+    case PP_VARTYPE_OBJECT:
+      if (expected.value.as_id != actual.value.as_id) {
+        LOG(ERROR) << "expected: " << expected.value.as_id << " actual: " <<
+            actual.value.as_id;
+        return false;
+      }
+      return true;
+    case PP_VARTYPE_STRING: {
+      StringVar* expected_var = StringVar::FromPPVar(expected);
+      StringVar* actual_var = StringVar::FromPPVar(actual);
+      DCHECK(expected_var && actual_var);
+      if (expected_var->value() != actual_var->value()) {
+        LOG(ERROR) << "expected: " << expected_var->value() << " actual: " <<
+            actual_var->value();
+        return false;
+      }
+      return true;
+    }
+    case PP_VARTYPE_ARRAY_BUFFER: {
+      ArrayBufferVar* expected_var = ArrayBufferVar::FromPPVar(expected);
+      ArrayBufferVar* actual_var = ArrayBufferVar::FromPPVar(actual);
+      DCHECK(expected_var && actual_var);
+      if (expected_var->ByteLength() != actual_var->ByteLength()) {
+        LOG(ERROR) << "expected: " << expected_var->ByteLength() <<
+            " actual: " << actual_var->ByteLength();
+        return false;
+      }
+      if (memcmp(expected_var->Map(), actual_var->Map(),
+                 expected_var->ByteLength()) != 0) {
+        LOG(ERROR) << "expected array buffer does not match actual.";
+        return false;
+      }
+      return true;
+    }
+    case PP_VARTYPE_ARRAY: {
+      ArrayVar* expected_var = ArrayVar::FromPPVar(expected);
+      ArrayVar* actual_var = ArrayVar::FromPPVar(actual);
+      DCHECK(expected_var && actual_var);
+      if (expected_var->elements().size() != actual_var->elements().size()) {
+        LOG(ERROR) << "expected: " << expected_var->elements().size() <<
+            " actual: " << actual_var->elements().size();
+        return false;
+      }
+      for (size_t i = 0; i < expected_var->elements().size(); ++i) {
+        if (!Equals(expected_var->elements()[i].get(),
+                    actual_var->elements()[i].get(),
+                    visited_map)) {
+          return false;
+        }
+      }
+      return true;
+    }
+    case PP_VARTYPE_DICTIONARY: {
+      DictionaryVar* expected_var = DictionaryVar::FromPPVar(expected);
+      DictionaryVar* actual_var = DictionaryVar::FromPPVar(actual);
+      DCHECK(expected_var && actual_var);
+      if (expected_var->key_value_map().size() !=
+          actual_var->key_value_map().size()) {
+        LOG(ERROR) << "expected: " << expected_var->key_value_map().size() <<
+            " actual: " << actual_var->key_value_map().size();
+        return false;
+      }
+      DictionaryVar::KeyValueMap::const_iterator expected_iter =
+          expected_var->key_value_map().begin();
+      DictionaryVar::KeyValueMap::const_iterator actual_iter =
+          actual_var->key_value_map().begin();
+      for ( ; expected_iter != expected_var->key_value_map().end();
+           ++expected_iter, ++actual_iter) {
+        if (expected_iter->first != actual_iter->first) {
+          LOG(ERROR) << "expected: " << expected_iter->first <<
+              " actual: " << actual_iter->first;
+          return false;
+        }
+        if (!Equals(expected_iter->second.get(),
+                    actual_iter->second.get(),
+                    visited_map)) {
+          return false;
+        }
+      }
+      return true;
+    }
+  }
+  NOTREACHED();
+  return false;
+}
+
+}  // namespace
+
+bool TestEqual(const PP_Var& expected, const PP_Var& actual) {
+  base::hash_map<int64_t, int64_t> visited_map;
+  return Equals(expected, actual, &visited_map);
+}
+
+}  // namespace ppapi
diff --git a/ppapi/shared_impl/unittest_utils.h b/ppapi/shared_impl/unittest_utils.h
new file mode 100644
index 0000000..e07d8a8
--- /dev/null
+++ b/ppapi/shared_impl/unittest_utils.h
@@ -0,0 +1,19 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef PPAPI_SHARED_IMPL_UNITTEST_UTILS_H_
+#define PPAPI_SHARED_IMPL_UNITTEST_UTILS_H_
+
+#include "ppapi/c/pp_var.h"
+
+namespace ppapi {
+
+// Compares two vars for equality. This is a deep comparison (the entire graph
+// is traversed recursively). The function guarantees that the topology of the
+// two PP_Var graphs being compared is identical, including graphs with cycles.
+bool TestEqual(const PP_Var& expected, const PP_Var& actual);
+
+}  // namespace ppapi
+
+#endif  // PPAPI_SHARED_IMPL_UNITTEST_UTILS_H_
diff --git a/ppapi/tests/test_flash_device_id.cc b/ppapi/tests/test_flash_device_id.cc
deleted file mode 100644
index a4e20b2..0000000
--- a/ppapi/tests/test_flash_device_id.cc
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ppapi/tests/test_flash_device_id.h"
-
-#include "ppapi/c/pp_macros.h"
-#include "ppapi/c/private/ppb_flash_device_id.h"
-#include "ppapi/cpp/instance.h"
-#include "ppapi/cpp/module.h"
-#include "ppapi/cpp/private/flash_device_id.h"
-#include "ppapi/cpp/var.h"
-#include "ppapi/tests/testing_instance.h"
-
-REGISTER_TEST_CASE(FlashDeviceID);
-
-using pp::flash::DeviceID;
-using pp::Var;
-
-TestFlashDeviceID::TestFlashDeviceID(TestingInstance* instance)
-    : TestCase(instance),
-      PP_ALLOW_THIS_IN_INITIALIZER_LIST(callback_factory_(this)) {
-}
-
-void TestFlashDeviceID::RunTests(const std::string& filter) {
-  RUN_TEST(GetDeviceID, filter);
-}
-
-std::string TestFlashDeviceID::TestGetDeviceID() {
-  DeviceID device_id(instance_);
-  TestCompletionCallbackWithOutput<Var> output_callback(
-      instance_->pp_instance());
-  int32_t rv = device_id.GetDeviceID(output_callback.GetCallback());
-  output_callback.WaitForResult(rv);
-  ASSERT_TRUE(output_callback.result() == PP_OK);
-  Var result = output_callback.output();
-  ASSERT_TRUE(result.is_string());
-  std::string id = result.AsString();
-  ASSERT_FALSE(id.empty());
-
-  PASS();
-}
diff --git a/ppapi/tests/test_flash_device_id.h b/ppapi/tests/test_flash_device_id.h
deleted file mode 100644
index 10e50bf..0000000
--- a/ppapi/tests/test_flash_device_id.h
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef PAPPI_TESTS_TEST_FLASH_DEVICE_ID_H_
-#define PAPPI_TESTS_TEST_FLASH_DEVICE_ID_H_
-
-#include <string>
-
-#include "ppapi/tests/test_case.h"
-#include "ppapi/utility/completion_callback_factory.h"
-
-class TestFlashDeviceID : public TestCase {
- public:
-  explicit TestFlashDeviceID(TestingInstance* instance);
-
-  // TestCase implementation.
-  virtual void RunTests(const std::string& filter);
-
- private:
-  std::string TestGetDeviceID();
-
-  pp::CompletionCallbackFactory<TestFlashDeviceID> callback_factory_;
-};
-
-#endif  // PAPPI_TESTS_TEST_FLASH_DEVICE_ID_H_
diff --git a/ppapi/tests/test_flash_drm.cc b/ppapi/tests/test_flash_drm.cc
new file mode 100644
index 0000000..94b6f26
--- /dev/null
+++ b/ppapi/tests/test_flash_drm.cc
@@ -0,0 +1,61 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ppapi/tests/test_flash_drm.h"
+
+#include "ppapi/c/pp_macros.h"
+#include "ppapi/c/private/ppb_flash_drm.h"
+#include "ppapi/cpp/instance.h"
+#include "ppapi/cpp/module.h"
+#include "ppapi/cpp/private/flash_device_id.h"
+#include "ppapi/cpp/private/flash_drm.h"
+#include "ppapi/cpp/var.h"
+#include "ppapi/tests/testing_instance.h"
+
+REGISTER_TEST_CASE(FlashDRM);
+
+using pp::flash::DeviceID;
+using pp::flash::DRM;
+using pp::Var;
+
+TestFlashDRM::TestFlashDRM(TestingInstance* instance)
+    : TestCase(instance),
+      PP_ALLOW_THIS_IN_INITIALIZER_LIST(callback_factory_(this)) {
+}
+
+void TestFlashDRM::RunTests(const std::string& filter) {
+  RUN_TEST(GetDeviceID, filter);
+}
+
+std::string TestFlashDRM::TestGetDeviceID() {
+  // Test the old C++ wrapper.
+  // TODO(raymes): Remove this once Flash switches APIs.
+  {
+    DeviceID device_id(instance_);
+    TestCompletionCallbackWithOutput<Var> output_callback(
+        instance_->pp_instance());
+    int32_t rv = device_id.GetDeviceID(output_callback.GetCallback());
+    output_callback.WaitForResult(rv);
+    ASSERT_TRUE(output_callback.result() == PP_OK);
+    Var result = output_callback.output();
+    ASSERT_TRUE(result.is_string());
+    std::string id = result.AsString();
+    ASSERT_FALSE(id.empty());
+  }
+
+  {
+    DRM drm(instance_);
+    TestCompletionCallbackWithOutput<Var> output_callback(
+        instance_->pp_instance());
+    int32_t rv = drm.GetDeviceID(output_callback.GetCallback());
+    output_callback.WaitForResult(rv);
+    ASSERT_TRUE(output_callback.result() == PP_OK);
+    Var result = output_callback.output();
+    ASSERT_TRUE(result.is_string());
+    std::string id = result.AsString();
+    ASSERT_FALSE(id.empty());
+  }
+
+  PASS();
+}
diff --git a/ppapi/tests/test_flash_drm.h b/ppapi/tests/test_flash_drm.h
new file mode 100644
index 0000000..964a80e
--- /dev/null
+++ b/ppapi/tests/test_flash_drm.h
@@ -0,0 +1,26 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef PAPPI_TESTS_TEST_FLASH_DRM_H_
+#define PAPPI_TESTS_TEST_FLASH_DRM_H_
+
+#include <string>
+
+#include "ppapi/tests/test_case.h"
+#include "ppapi/utility/completion_callback_factory.h"
+
+class TestFlashDRM : public TestCase {
+ public:
+  explicit TestFlashDRM(TestingInstance* instance);
+
+  // TestCase implementation.
+  virtual void RunTests(const std::string& filter);
+
+ private:
+  std::string TestGetDeviceID();
+
+  pp::CompletionCallbackFactory<TestFlashDRM> callback_factory_;
+};
+
+#endif  // PAPPI_TESTS_TEST_FLASH_DRM_H_
diff --git a/ppapi/tests/test_post_message.cc b/ppapi/tests/test_post_message.cc
index 39102e1..8c67ee5 100644
--- a/ppapi/tests/test_post_message.cc
+++ b/ppapi/tests/test_post_message.cc
@@ -5,6 +5,7 @@
 #include "ppapi/tests/test_post_message.h"
 
 #include <algorithm>
+#include <map>
 #include <sstream>
 
 #include "ppapi/c/dev/ppb_testing_dev.h"
@@ -58,6 +59,64 @@
   delete arg;
 }
 
+// TODO(raymes): Consider putting something like this into pp::Var.
+bool VarsEqual(const pp::Var& expected,
+               const pp::Var& actual,
+               std::map<int64_t, int64_t>* visited_ids) {
+  if (expected.pp_var().type != actual.pp_var().type) {
+    if (!expected.is_number() && !actual.is_number())
+      return false;
+  }
+  // TODO(raymes): Implement a pp::Var::IsRefCounted() function.
+  if (expected.pp_var().type > PP_VARTYPE_DOUBLE) {
+    std::map<int64_t, int64_t>::const_iterator it =
+        visited_ids->find(expected.pp_var().value.as_id);
+    if (it != visited_ids->end()) {
+      if (it->second == actual.pp_var().value.as_id)
+        return true;
+      return false;
+    }
+    (*visited_ids)[expected.pp_var().value.as_id] = actual.pp_var().value.as_id;
+  }
+
+  if (expected.is_number()) {
+    return fabs(expected.AsDouble() - actual.AsDouble()) < 1.0e-4;
+  } else if (expected.is_array()) {
+    pp::VarArray_Dev expected_array(expected);
+    pp::VarArray_Dev actual_array(actual);
+    if (expected_array.GetLength() != actual_array.GetLength())
+      return false;
+    for (uint32_t i = 0; i < expected_array.GetLength(); ++i) {
+      if (!VarsEqual(expected_array.Get(i), actual_array.Get(i), visited_ids))
+        return false;
+    }
+    return true;
+  } else if (expected.is_dictionary()) {
+    pp::VarDictionary_Dev expected_dict(expected);
+    pp::VarDictionary_Dev actual_dict(actual);
+    if (expected_dict.GetKeys().GetLength() !=
+        actual_dict.GetKeys().GetLength()) {
+      return false;
+    }
+    for (uint32_t i = 0; i < expected_dict.GetKeys().GetLength(); ++i) {
+      pp::Var key = expected_dict.GetKeys().Get(i);
+      if (actual_dict.HasKey(key) == PP_FALSE)
+        return false;
+      if (!VarsEqual(expected_dict.Get(key), actual_dict.Get(key), visited_ids))
+        return false;
+    }
+    return true;
+  } else {
+    return expected == actual;
+  }
+}
+
+bool VarsEqual(const pp::Var& expected,
+               const pp::Var& actual) {
+  std::map<int64_t, int64_t> visited_ids;
+  return VarsEqual(expected, actual, &visited_ids);
+}
+
 class ScopedArrayBufferSizeSetter {
  public:
   ScopedArrayBufferSizeSetter(const PPB_Testing_Dev* interface,
@@ -135,6 +194,9 @@
   RUN_TEST(SendInInit, filter);
   RUN_TEST(SendingData, filter);
   RUN_TEST(SendingArrayBuffer, filter);
+  RUN_TEST(SendingArray, filter);
+  RUN_TEST(SendingDictionary, filter);
+  RUN_TEST(SendingComplexVar, filter);
   RUN_TEST(MessageEvent, filter);
   RUN_TEST(NoHandler, filter);
   RUN_TEST(ExtraParam, filter);
@@ -199,6 +261,27 @@
   return message_data_.size() - message_size_before;
 }
 
+std::string TestPostMessage::CheckMessageProperties(
+    const pp::Var& test_data,
+    const std::vector<std::string>& properties_to_check) {
+  typedef std::vector<std::string>::const_iterator Iterator;
+  for (Iterator iter = properties_to_check.begin();
+       iter != properties_to_check.end();
+       ++iter) {
+    ASSERT_TRUE(AddEchoingListener(*iter));
+    message_data_.clear();
+    instance_->PostMessage(test_data);
+    ASSERT_EQ(message_data_.size(), 0);
+    ASSERT_EQ(WaitForMessages(), 1);
+    ASSERT_TRUE(message_data_.back().is_bool());
+    if (!message_data_.back().AsBool())
+      return std::string("Failed: ") + *iter;
+    ASSERT_TRUE(message_data_.back().AsBool());
+    ASSERT_TRUE(ClearListeners());
+  }
+  PASS();
+}
+
 std::string TestPostMessage::TestSendInInit() {
   ASSERT_EQ(WaitForMessages(), 1);
   // This test assumes Init already sent a message.
@@ -317,20 +400,8 @@
       std::string expected_byte("(message_event.data.byteLength-1)%256");
       properties_to_check.push_back(received_byte + " == " + expected_byte);
     }
-    for (std::vector<std::string>::iterator iter = properties_to_check.begin();
-         iter != properties_to_check.end();
-         ++iter) {
-      ASSERT_TRUE(AddEchoingListener(*iter));
-      message_data_.clear();
-      instance_->PostMessage(test_data);
-      ASSERT_EQ(message_data_.size(), 0);
-      ASSERT_EQ(WaitForMessages(), 1);
-      ASSERT_TRUE(message_data_.back().is_bool());
-      if (!message_data_.back().AsBool())
-        return std::string("Failed: ") + *iter + ", size: " + kSizeAsString;
-      ASSERT_TRUE(message_data_.back().AsBool());
-      ASSERT_TRUE(ClearListeners());
-    }
+    ASSERT_SUBTEST_SUCCESS(CheckMessageProperties(test_data,
+                                                  properties_to_check));
 
     // Set up the JavaScript message event listener to echo the data part of the
     // message event back to us.
@@ -360,6 +431,148 @@
   PASS();
 }
 
+std::string TestPostMessage::TestSendingArray() {
+  // Clean up after previous tests. This also swallows the message sent by Init
+  // if we didn't run the 'SendInInit' test. All tests other than 'SendInInit'
+  // should start with these.
+  WaitForMessages();
+  ASSERT_TRUE(ClearListeners());
+
+  pp::VarArray_Dev array;
+  array.Set(0, pp::Var(kTestBool));
+  array.Set(1, pp::Var(kTestString));
+  // Purposely leave index 2 empty.
+  array.Set(3, pp::Var(kTestInt));
+  array.Set(4, pp::Var(kTestDouble));
+
+  std::stringstream ss;
+  ss << array.GetLength();
+  std::string length_as_string(ss.str());
+
+  // Have the listener test some properties of the Array.
+  std::vector<std::string> properties_to_check;
+  properties_to_check.push_back(
+      "message_event.data.constructor.name === 'Array'");
+  properties_to_check.push_back(
+      std::string("message_event.data.length === ") + length_as_string);
+  ASSERT_SUBTEST_SUCCESS(CheckMessageProperties(array, properties_to_check));
+
+  // Set up the JavaScript message event listener to echo the data part of the
+  // message event back to us.
+  ASSERT_TRUE(AddEchoingListener("message_event.data"));
+  message_data_.clear();
+  instance_->PostMessage(array);
+  // PostMessage is asynchronous, so we should not receive a response yet.
+  ASSERT_EQ(message_data_.size(), 0);
+  ASSERT_EQ(WaitForMessages(), 1);
+  ASSERT_TRUE(message_data_.back().is_array());
+  ASSERT_TRUE(VarsEqual(array, message_data_.back()));
+
+  message_data_.clear();
+  ASSERT_TRUE(ClearListeners());
+
+  PASS();
+}
+
+std::string TestPostMessage::TestSendingDictionary() {
+  // Clean up after previous tests. This also swallows the message sent by Init
+  // if we didn't run the 'SendInInit' test. All tests other than 'SendInInit'
+  // should start with these.
+  WaitForMessages();
+  ASSERT_TRUE(ClearListeners());
+
+  pp::VarDictionary_Dev dictionary;
+  dictionary.Set(pp::Var("foo"), pp::Var(kTestBool));
+  dictionary.Set(pp::Var("bar"), pp::Var(kTestString));
+  dictionary.Set(pp::Var("abc"), pp::Var(kTestInt));
+  dictionary.Set(pp::Var("def"), pp::Var());
+
+  std::stringstream ss;
+  ss << dictionary.GetKeys().GetLength();
+  std::string length_as_string(ss.str());
+
+  // Have the listener test some properties of the Dictionary.
+  std::vector<std::string> properties_to_check;
+  properties_to_check.push_back(
+      "message_event.data.constructor.name === 'Object'");
+  properties_to_check.push_back(
+      std::string("Object.keys(message_event.data).length === ") +
+      length_as_string);
+  ASSERT_SUBTEST_SUCCESS(CheckMessageProperties(dictionary,
+                                                properties_to_check));
+
+  // Set up the JavaScript message event listener to echo the data part of the
+  // message event back to us.
+  ASSERT_TRUE(AddEchoingListener("message_event.data"));
+  message_data_.clear();
+  instance_->PostMessage(dictionary);
+  // PostMessage is asynchronous, so we should not receive a response yet.
+  ASSERT_EQ(message_data_.size(), 0);
+  ASSERT_EQ(WaitForMessages(), 1);
+  ASSERT_TRUE(message_data_.back().is_dictionary());
+  ASSERT_TRUE(VarsEqual(dictionary, message_data_.back()));
+
+  message_data_.clear();
+  ASSERT_TRUE(ClearListeners());
+
+  PASS();
+}
+
+std::string TestPostMessage::TestSendingComplexVar() {
+  // Clean up after previous tests. This also swallows the message sent by Init
+  // if we didn't run the 'SendInInit' test. All tests other than 'SendInInit'
+  // should start with these.
+  WaitForMessages();
+  ASSERT_TRUE(ClearListeners());
+
+  pp::Var string(kTestString);
+  pp::VarDictionary_Dev dictionary;
+  dictionary.Set(pp::Var("foo"), pp::Var(kTestBool));
+  dictionary.Set(pp::Var("bar"), string);
+  dictionary.Set(pp::Var("abc"), pp::Var(kTestInt));
+  dictionary.Set(pp::Var("def"), pp::Var());
+  dictionary.Set(pp::Var("dictionary"), dictionary);  // Self-reference.
+
+  // Reference to array.
+  pp::VarArray_Dev array;
+  array.Set(0, pp::Var(kTestBool));
+  array.Set(1, string);
+  // Purposely leave index 2 empty (which will place an undefined var there).
+  array.Set(3, pp::Var(kTestInt));
+  array.Set(4, pp::Var(kTestDouble));
+
+  dictionary.Set(pp::Var("array-ref1"), array);
+  dictionary.Set(pp::Var("array-ref2"), array);
+
+  // Set up a (dictionary -> array -> dictionary) cycle.
+  pp::VarArray_Dev array2;
+  array2.Set(0, dictionary);
+  dictionary.Set(pp::Var("array2"), array2);
+
+  // Set up the JavaScript message event listener to echo the data part of the
+  // message event back to us.
+  ASSERT_TRUE(AddEchoingListener("message_event.data"));
+  message_data_.clear();
+  instance_->PostMessage(dictionary);
+  // PostMessage is asynchronous, so we should not receive a response yet.
+  ASSERT_EQ(message_data_.size(), 0);
+  ASSERT_EQ(WaitForMessages(), 1);
+  ASSERT_TRUE(message_data_.back().is_dictionary());
+  pp::VarDictionary_Dev result(message_data_.back());
+  ASSERT_TRUE(VarsEqual(dictionary, message_data_.back()));
+
+  // Break the cycles.
+  dictionary.Delete(pp::Var("dictionary"));
+  dictionary.Delete(pp::Var("array2"));
+  result.Delete(pp::Var("dictionary"));
+  result.Delete(pp::Var("array2"));
+
+  message_data_.clear();
+  ASSERT_TRUE(ClearListeners());
+
+  PASS();
+}
+
 std::string TestPostMessage::TestMessageEvent() {
   // Set up the JavaScript message event listener to pass us some values from
   // the MessageEvent and make sure they match our expectations.
diff --git a/ppapi/tests/test_post_message.h b/ppapi/tests/test_post_message.h
index 8ba3e4e..3ea69e8 100644
--- a/ppapi/tests/test_post_message.h
+++ b/ppapi/tests/test_post_message.h
@@ -43,6 +43,12 @@
   // at the time of invocation.
   int WaitForMessages();
 
+  // Verifies that the given javascript assertions are true of the message
+  // (|test_data|) passed via PostMessage().
+  std::string CheckMessageProperties(
+      const pp::Var& test_data,
+      const std::vector<std::string>& properties_to_check);
+
   // Test that we can send a message from Instance::Init. Note the actual
   // message is sent in TestPostMessage::Init, and this test simply makes sure
   // we got it.
@@ -55,6 +61,15 @@
   // Test sending ArrayBuffer vars in both directions.
   std::string TestSendingArrayBuffer();
 
+  // Test sending Array vars in both directions.
+  std::string TestSendingArray();
+
+  // Test sending Dictionary vars in both directions.
+  std::string TestSendingDictionary();
+
+  // Test sending a complex var with references and cycles in both directions.
+  std::string TestSendingComplexVar();
+
   // Test the MessageEvent object that JavaScript received to make sure it is
   // of the right type and has all the expected fields.
   std::string TestMessageEvent();
diff --git a/ppapi/tests/test_tcp_server_socket_private.cc b/ppapi/tests/test_tcp_server_socket_private.cc
index 47e3020..880515d 100644
--- a/ppapi/tests/test_tcp_server_socket_private.cc
+++ b/ppapi/tests/test_tcp_server_socket_private.cc
@@ -4,6 +4,7 @@
 
 #include "ppapi/tests/test_tcp_server_socket_private.h"
 
+#include <cstdio>
 #include <vector>
 
 #include "ppapi/cpp/pass_ref.h"
@@ -132,25 +133,16 @@
     int32_t backlog) {
   PP_NetAddress_Private base_address;
   ASSERT_SUBTEST_SUCCESS(GetLocalAddress(&base_address));
-
-  // TODO (ygorshenin): find more efficient way to select available
-  // ports.
-  bool is_free_port_found = false;
-  for (uint16_t port = kPortScanFrom; port < kPortScanTo; ++port) {
-    if (!NetAddressPrivate::ReplacePort(base_address, port, address))
-      return ReportError("PPB_NetAddress_Private::ReplacePort", 0);
-
-    TestCompletionCallback callback(instance_->pp_instance(), callback_type());
-    callback.WaitForResult(
-        socket->Listen(address, backlog, callback.GetCallback()));
-    CHECK_CALLBACK_BEHAVIOR(callback);
-    if (callback.result() == PP_OK) {
-      is_free_port_found = true;
-      break;
-    }
-  }
-
-  ASSERT_TRUE(is_free_port_found);
+  if (!NetAddressPrivate::ReplacePort(base_address, 0, address))
+    return ReportError("PPB_NetAddress_Private::ReplacePort", 0);
+  TestCompletionCallback callback(instance_->pp_instance(), callback_type());
+  callback.WaitForResult(
+      socket->Listen(address, backlog, callback.GetCallback()));
+  CHECK_CALLBACK_BEHAVIOR(callback);
+  ASSERT_EQ(PP_OK, callback.result());
+  int32_t rv = socket->GetLocalAddress(address);
+  ASSERT_EQ(PP_OK, rv);
+  ASSERT_TRUE(NetAddressPrivate::GetPort(*address) != 0);
   PASS();
 }
 
@@ -158,14 +150,12 @@
   static const int kBacklog = 2;
 
   TCPServerSocketPrivate server_socket(instance_);
-
   PP_NetAddress_Private address;
   ASSERT_SUBTEST_SUCCESS(SyncListen(&server_socket, &address, kBacklog));
 
   // We can't use a blocking callback for Accept, because it will wait forever
   // for the client to connect, since the client connects after.
-  TestCompletionCallback accept_callback(instance_->pp_instance(),
-                                         PP_REQUIRED);
+  TestCompletionCallback accept_callback(instance_->pp_instance(), PP_REQUIRED);
   // We need to make sure there's a message loop to run accept_callback on.
   pp::MessageLoop current_thread_loop(pp::MessageLoop::GetCurrent());
   if (current_thread_loop.is_null() && testing_interface_->IsOutOfProcess()) {
@@ -209,7 +199,6 @@
   static const size_t kBacklog = 5;
 
   TCPServerSocketPrivate server_socket(instance_);
-
   PP_NetAddress_Private address;
   ASSERT_SUBTEST_SUCCESS(SyncListen(&server_socket, &address, 2 * kBacklog));
 
diff --git a/ppapi/tests/test_tcp_server_socket_private_disallowed.cc b/ppapi/tests/test_tcp_server_socket_private_disallowed.cc
index 8c89a3a..99aceb1 100644
--- a/ppapi/tests/test_tcp_server_socket_private_disallowed.cc
+++ b/ppapi/tests/test_tcp_server_socket_private_disallowed.cc
@@ -62,22 +62,17 @@
   ASSERT_TRUE(socket != 0);
   ASSERT_TRUE(tcp_server_socket_private_interface_->IsTCPServerSocket(socket));
 
-  PP_NetAddress_Private base_address, current_address;
+  PP_NetAddress_Private base_address, address;
   pp::NetAddressPrivate::GetAnyAddress(false, &base_address);
-
-  for (uint16_t port = kPortScanFrom; port < kPortScanTo; ++port) {
-    ASSERT_TRUE(pp::NetAddressPrivate::ReplacePort(base_address,
-                                                   port,
-                                                   &current_address));
-    TestCompletionCallback callback(instance_->pp_instance(), callback_type());
-    callback.WaitForResult(tcp_server_socket_private_interface_->Listen(
-        socket,
-        &current_address,
-        1,
-        callback.GetCallback().pp_completion_callback()));
-    CHECK_CALLBACK_BEHAVIOR(callback);
-    ASSERT_NE(PP_OK, callback.result());
-  }
-
+  ASSERT_TRUE(pp::NetAddressPrivate::ReplacePort(
+      base_address, 0, &address));
+  TestCompletionCallback callback(instance_->pp_instance());
+  callback.WaitForResult(tcp_server_socket_private_interface_->Listen(
+      socket,
+      &address,
+      1,
+      callback.GetCallback().pp_completion_callback()));
+  CHECK_CALLBACK_BEHAVIOR(callback);
+  ASSERT_NE(PP_OK, callback.result());
   PASS();
 }
diff --git a/ppapi/tests/test_url_loader.cc b/ppapi/tests/test_url_loader.cc
index 0978f0e..d3602d3 100644
--- a/ppapi/tests/test_url_loader.cc
+++ b/ppapi/tests/test_url_loader.cc
@@ -800,7 +800,6 @@
       event.Wait();
     }
   }
-
   // The loader should now have the data and have finished successfully.
   std::string body;
   std::string error = ReadEntireResponseBody(&loader, &body);
diff --git a/ppapi/thunk/interfaces_legacy.h b/ppapi/thunk/interfaces_legacy.h
new file mode 100644
index 0000000..9d03bbe
--- /dev/null
+++ b/ppapi/thunk/interfaces_legacy.h
@@ -0,0 +1,51 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+#ifndef LEGACY_IFACE
+#define LEGACY_IFACE(iface_str, function_name)
+#endif
+
+LEGACY_IFACE(PPB_AUDIO_TRUSTED_INTERFACE_0_6,
+             ::ppapi::thunk::GetPPB_AudioTrusted_0_6_Thunk())
+LEGACY_IFACE(PPB_BUFFER_TRUSTED_INTERFACE_0_1,
+             ::ppapi::thunk::GetPPB_BufferTrusted_0_1_Thunk())
+LEGACY_IFACE(PPB_GRAPHICS_3D_TRUSTED_INTERFACE_1_0,
+             ::ppapi::thunk::GetPPB_Graphics3DTrusted_1_0_Thunk())
+LEGACY_IFACE(PPB_IMAGEDATA_TRUSTED_INTERFACE_0_4,
+             ::ppapi::thunk::GetPPB_ImageDataTrusted_0_4_Thunk())
+LEGACY_IFACE(PPB_INPUT_EVENT_INTERFACE_1_0,
+             ::ppapi::thunk::GetPPB_InputEvent_1_0_Thunk())
+LEGACY_IFACE(PPB_INSTANCE_PRIVATE_INTERFACE_0_1,
+             ::ppapi::thunk::GetPPB_Instance_Private_0_1_Thunk())
+LEGACY_IFACE(PPB_CORE_INTERFACE_1_0, &core_interface)
+LEGACY_IFACE(PPB_GPUBLACKLIST_PRIVATE_INTERFACE,
+             PPB_GpuBlacklist_Private_Impl::GetInterface())
+LEGACY_IFACE(PPB_OPENGLES2_INTERFACE,
+             ::ppapi::PPB_OpenGLES2_Shared::GetInterface())
+LEGACY_IFACE(PPB_OPENGLES2_INSTANCEDARRAYS_INTERFACE,
+             ::ppapi::PPB_OpenGLES2_Shared::GetInstancedArraysInterface())
+LEGACY_IFACE(PPB_OPENGLES2_FRAMEBUFFERBLIT_INTERFACE,
+             ::ppapi::PPB_OpenGLES2_Shared::GetFramebufferBlitInterface())
+LEGACY_IFACE(
+    PPB_OPENGLES2_FRAMEBUFFERMULTISAMPLE_INTERFACE,
+    ::ppapi::PPB_OpenGLES2_Shared::GetFramebufferMultisampleInterface())
+LEGACY_IFACE(PPB_OPENGLES2_CHROMIUMENABLEFEATURE_INTERFACE,
+             ::ppapi::PPB_OpenGLES2_Shared::GetChromiumEnableFeatureInterface())
+LEGACY_IFACE(PPB_OPENGLES2_CHROMIUMMAPSUB_INTERFACE,
+             ::ppapi::PPB_OpenGLES2_Shared::GetChromiumMapSubInterface())
+LEGACY_IFACE(PPB_OPENGLES2_CHROMIUMMAPSUB_DEV_INTERFACE_1_0,
+             ::ppapi::PPB_OpenGLES2_Shared::GetChromiumMapSubInterface())
+LEGACY_IFACE(PPB_OPENGLES2_QUERY_INTERFACE,
+             ::ppapi::PPB_OpenGLES2_Shared::GetQueryInterface())
+LEGACY_IFACE(PPB_PROXY_PRIVATE_INTERFACE, PPB_Proxy_Impl::GetInterface())
+LEGACY_IFACE(PPB_UMA_PRIVATE_INTERFACE, PPB_UMA_Private_Impl::GetInterface())
+LEGACY_IFACE(PPB_VAR_DEPRECATED_INTERFACE,
+             PPB_Var_Deprecated_Impl::GetVarDeprecatedInterface())
+LEGACY_IFACE(PPB_VAR_INTERFACE_1_0,
+             ::ppapi::PPB_Var_Shared::GetVarInterface1_0())
+LEGACY_IFACE(PPB_VAR_INTERFACE_1_1,
+             ::ppapi::PPB_Var_Shared::GetVarInterface1_1())
+LEGACY_IFACE(PPB_VAR_ARRAY_BUFFER_INTERFACE_1_0,
+             ::ppapi::PPB_Var_Shared::GetVarArrayBufferInterface1_0())
+
+
diff --git a/ppapi/thunk/interfaces_ppb_private.h b/ppapi/thunk/interfaces_ppb_private.h
index 94dd53f..6bc431d 100644
--- a/ppapi/thunk/interfaces_ppb_private.h
+++ b/ppapi/thunk/interfaces_ppb_private.h
@@ -47,6 +47,9 @@
 // This uses the FileIO API which is declared in the public stable file.
 PROXIED_IFACE(NoAPIName, PPB_FILEIOTRUSTED_INTERFACE_0_4, PPB_FileIOTrusted_0_4)
 
+PROXIED_IFACE(NoAPIName, PPB_URLLOADERTRUSTED_INTERFACE_0_3,
+              PPB_URLLoaderTrusted_0_3)
+
 PROXIED_IFACE(NoAPIName, PPB_VIDEODESTINATION_PRIVATE_INTERFACE_0_1,
               PPB_VideoDestination_Private_0_1)
 PROXIED_IFACE(NoAPIName, PPB_VIDEOSOURCE_PRIVATE_INTERFACE_0_1,
diff --git a/ppapi/thunk/interfaces_ppb_private_flash.h b/ppapi/thunk/interfaces_ppb_private_flash.h
index a020a3a..21d9c27 100644
--- a/ppapi/thunk/interfaces_ppb_private_flash.h
+++ b/ppapi/thunk/interfaces_ppb_private_flash.h
@@ -37,6 +37,9 @@
 PROXIED_IFACE(NoAPIName,
               PPB_FLASH_DEVICEID_INTERFACE_1_0,
               PPB_Flash_DeviceID_1_0)
+PROXIED_IFACE(NoAPIName,
+              PPB_FLASH_DRM_INTERFACE_1_0,
+              PPB_Flash_DRM_1_0)
 
 PROXIED_IFACE(NoAPIName,
               PPB_FLASH_FONTFILE_INTERFACE_0_1,
diff --git a/ppapi/thunk/interfaces_ppb_private_no_permissions.h b/ppapi/thunk/interfaces_ppb_private_no_permissions.h
index 138ce9c..dca6289 100644
--- a/ppapi/thunk/interfaces_ppb_private_no_permissions.h
+++ b/ppapi/thunk/interfaces_ppb_private_no_permissions.h
@@ -19,6 +19,9 @@
 PROXIED_IFACE(PPB_TCPServerSocket_Private,
               PPB_TCPSERVERSOCKET_PRIVATE_INTERFACE_0_1,
               PPB_TCPServerSocket_Private_0_1)
+PROXIED_IFACE(PPB_TCPServerSocket_Private,
+              PPB_TCPSERVERSOCKET_PRIVATE_INTERFACE_0_2,
+              PPB_TCPServerSocket_Private_0_2)
 PROXIED_IFACE(PPB_TCPSocket_Private, PPB_TCPSOCKET_PRIVATE_INTERFACE_0_3,
               PPB_TCPSocket_Private_0_3)
 PROXIED_IFACE(PPB_TCPSocket_Private, PPB_TCPSOCKET_PRIVATE_INTERFACE_0_4,
diff --git a/ppapi/thunk/interfaces_ppb_public_dev.h b/ppapi/thunk/interfaces_ppb_public_dev.h
index 707e0e5..ea8fccb 100644
--- a/ppapi/thunk/interfaces_ppb_public_dev.h
+++ b/ppapi/thunk/interfaces_ppb_public_dev.h
@@ -16,6 +16,8 @@
               PPB_Ext_Alarms_Dev_0_1)
 PROXIED_IFACE(NoAPIName, PPB_EXT_SOCKET_DEV_INTERFACE_0_1,
               PPB_Ext_Socket_Dev_0_1)
+PROXIED_IFACE(NoAPIName, PPB_EXT_SOCKET_DEV_INTERFACE_0_2,
+              PPB_Ext_Socket_Dev_0_2)
 PROXIED_IFACE(NoAPIName, PPB_FILECHOOSER_DEV_INTERFACE_0_5,
               PPB_FileChooser_Dev_0_5)
 PROXIED_IFACE(NoAPIName, PPB_FILECHOOSER_DEV_INTERFACE_0_6,
diff --git a/ppapi/thunk/interfaces_ppb_public_stable.h b/ppapi/thunk/interfaces_ppb_public_stable.h
index 14b539f..ddfe2ca 100644
--- a/ppapi/thunk/interfaces_ppb_public_stable.h
+++ b/ppapi/thunk/interfaces_ppb_public_stable.h
@@ -23,7 +23,6 @@
 PROXIED_API(PPB_Graphics3D)
 PROXIED_API(PPB_ImageData)
 PROXIED_API(PPB_Instance)
-PROXIED_API(PPB_URLLoader)
 
 // AudioConfig isn't proxied in the normal way, we have only local classes and
 // serialize it to a struct when we need it on the host side.
@@ -73,7 +72,7 @@
 PROXIED_IFACE(PPB_Instance, PPB_MESSAGING_INTERFACE_1_0, PPB_Messaging_1_0)
 PROXIED_IFACE(PPB_Instance, PPB_MOUSECURSOR_INTERFACE_1_0, PPB_MouseCursor_1_0)
 PROXIED_IFACE(PPB_Instance, PPB_MOUSELOCK_INTERFACE_1_0, PPB_MouseLock_1_0)
-PROXIED_IFACE(PPB_URLLoader, PPB_URLLOADER_INTERFACE_1_0, PPB_URLLoader_1_0)
+PROXIED_IFACE(NoAPIName, PPB_URLLOADER_INTERFACE_1_0, PPB_URLLoader_1_0)
 PROXIED_IFACE(NoAPIName, PPB_URLREQUESTINFO_INTERFACE_1_0,
               PPB_URLRequestInfo_1_0)
 PROXIED_IFACE(NoAPIName, PPB_URLRESPONSEINFO_INTERFACE_1_0,
diff --git a/ppapi/thunk/ppb_ext_socket_thunk.cc b/ppapi/thunk/ppb_ext_socket_thunk.cc
index e4134c7..e0afd66 100644
--- a/ppapi/thunk/ppb_ext_socket_thunk.cc
+++ b/ppapi/thunk/ppb_ext_socket_thunk.cc
@@ -15,9 +15,6 @@
 
 namespace {
 
-// TODO(yzshen): The socket API should directly communicate with the browser
-// process, instead of going by way of the renderer process.
-
 int32_t Create(PP_Instance instance,
                PP_Ext_Socket_SocketType_Dev type,
                PP_Ext_Socket_CreateOptions_Dev options,
@@ -32,7 +29,7 @@
   input_args.push_back(type);
   input_args.push_back(options);
   output_args.push_back(create_info);
-  return enter.SetResult(enter.functions()->CallRenderer(
+  return enter.SetResult(enter.functions()->CallBrowser(
       "socket.create", input_args, output_args, enter.callback()));
 }
 
@@ -43,7 +40,7 @@
 
   std::vector<PP_Var> args;
   args.push_back(socket_id);
-  enter.functions()->PostRenderer("socket.destroy", args);
+  enter.functions()->PostBrowser("socket.destroy", args);
 }
 
 int32_t Connect(PP_Instance instance,
@@ -62,7 +59,7 @@
   input_args.push_back(hostname);
   input_args.push_back(port);
   output_args.push_back(result);
-  return enter.SetResult(enter.functions()->CallRenderer(
+  return enter.SetResult(enter.functions()->CallBrowser(
       "socket.connect", input_args, output_args, enter.callback()));
 }
 
@@ -82,7 +79,7 @@
   input_args.push_back(address);
   input_args.push_back(port);
   output_args.push_back(result);
-  return enter.SetResult(enter.functions()->CallRenderer(
+  return enter.SetResult(enter.functions()->CallBrowser(
       "socket.bind", input_args, output_args, enter.callback()));
 }
 
@@ -93,7 +90,7 @@
 
   std::vector<PP_Var> args;
   args.push_back(socket_id);
-  enter.functions()->PostRenderer("socket.disconnect", args);
+  enter.functions()->PostBrowser("socket.disconnect", args);
 }
 
 int32_t Read(PP_Instance instance,
@@ -110,7 +107,7 @@
   input_args.push_back(socket_id);
   input_args.push_back(buffer_size);
   output_args.push_back(read_info);
-  return enter.SetResult(enter.functions()->CallRenderer(
+  return enter.SetResult(enter.functions()->CallBrowser(
       "socket.read", input_args, output_args, enter.callback()));
 }
 
@@ -128,7 +125,7 @@
   input_args.push_back(socket_id);
   input_args.push_back(data);
   output_args.push_back(write_info);
-  return enter.SetResult(enter.functions()->CallRenderer(
+  return enter.SetResult(enter.functions()->CallBrowser(
       "socket.write", input_args, output_args, enter.callback()));
 }
 
@@ -146,7 +143,7 @@
   input_args.push_back(socket_id);
   input_args.push_back(buffer_size);
   output_args.push_back(recv_from_info);
-  return enter.SetResult(enter.functions()->CallRenderer(
+  return enter.SetResult(enter.functions()->CallBrowser(
       "socket.recvFrom", input_args, output_args, enter.callback()));
 }
 
@@ -168,7 +165,7 @@
   input_args.push_back(address);
   input_args.push_back(port);
   output_args.push_back(write_info);
-  return enter.SetResult(enter.functions()->CallRenderer(
+  return enter.SetResult(enter.functions()->CallBrowser(
       "socket.sendTo", input_args, output_args, enter.callback()));
 }
 
@@ -190,7 +187,7 @@
   input_args.push_back(port);
   input_args.push_back(backlog);
   output_args.push_back(result);
-  return enter.SetResult(enter.functions()->CallRenderer(
+  return enter.SetResult(enter.functions()->CallBrowser(
       "socket.listen", input_args, output_args, enter.callback()));
 }
 
@@ -206,7 +203,7 @@
   std::vector<PP_Var*> output_args;
   input_args.push_back(socket_id);
   output_args.push_back(accept_info);
-  return enter.SetResult(enter.functions()->CallRenderer(
+  return enter.SetResult(enter.functions()->CallBrowser(
       "socket.accept", input_args, output_args, enter.callback()));
 }
 
@@ -226,7 +223,7 @@
   input_args.push_back(enable);
   input_args.push_back(delay);
   output_args.push_back(result);
-  return enter.SetResult(enter.functions()->CallRenderer(
+  return enter.SetResult(enter.functions()->CallBrowser(
       "socket.setKeepAlive", input_args, output_args, enter.callback()));
 }
 
@@ -244,7 +241,7 @@
   input_args.push_back(socket_id);
   input_args.push_back(no_delay);
   output_args.push_back(result);
-  return enter.SetResult(enter.functions()->CallRenderer(
+  return enter.SetResult(enter.functions()->CallBrowser(
       "socket.setNoDelay", input_args, output_args, enter.callback()));
 }
 
@@ -260,7 +257,7 @@
   std::vector<PP_Var*> output_args;
   input_args.push_back(socket_id);
   output_args.push_back(result);
-  return enter.SetResult(enter.functions()->CallRenderer(
+  return enter.SetResult(enter.functions()->CallBrowser(
       "socket.getInfo", input_args, output_args, enter.callback()));
 }
 
@@ -274,10 +271,100 @@
   std::vector<PP_Var> input_args;
   std::vector<PP_Var*> output_args;
   output_args.push_back(result);
-  return enter.SetResult(enter.functions()->CallRenderer(
+  return enter.SetResult(enter.functions()->CallBrowser(
       "socket.getNetworkList", input_args, output_args, enter.callback()));
 }
 
+int32_t JoinGroup(PP_Instance instance,
+                  PP_Var socket_id,
+                  PP_Var address,
+                  PP_Var* result,
+                  PP_CompletionCallback callback) {
+  EnterInstanceAPI<ExtensionsCommon_API> enter(instance, callback);
+  if (enter.failed())
+    return enter.retval();
+
+  std::vector<PP_Var> input_args;
+  std::vector<PP_Var*> output_args;
+  input_args.push_back(socket_id);
+  input_args.push_back(address);
+  output_args.push_back(result);
+  return enter.SetResult(enter.functions()->CallBrowser(
+      "socket.joinGroup", input_args, output_args, enter.callback()));
+}
+
+int32_t LeaveGroup(PP_Instance instance,
+                   PP_Var socket_id,
+                   PP_Var address,
+                   PP_Var* result,
+                   PP_CompletionCallback callback) {
+  EnterInstanceAPI<ExtensionsCommon_API> enter(instance, callback);
+  if (enter.failed())
+    return enter.retval();
+
+  std::vector<PP_Var> input_args;
+  std::vector<PP_Var*> output_args;
+  input_args.push_back(socket_id);
+  input_args.push_back(address);
+  output_args.push_back(result);
+  return enter.SetResult(enter.functions()->CallBrowser(
+      "socket.leaveGroup", input_args, output_args, enter.callback()));
+}
+
+int32_t SetMulticastTimeToLive(PP_Instance instance,
+                               PP_Var socket_id,
+                               PP_Var ttl,
+                               PP_Var* result,
+                               PP_CompletionCallback callback) {
+  EnterInstanceAPI<ExtensionsCommon_API> enter(instance, callback);
+  if (enter.failed())
+    return enter.retval();
+
+  std::vector<PP_Var> input_args;
+  std::vector<PP_Var*> output_args;
+  input_args.push_back(socket_id);
+  input_args.push_back(ttl);
+  output_args.push_back(result);
+  return enter.SetResult(enter.functions()->CallBrowser(
+      "socket.setMulticastTimeToLive", input_args, output_args,
+      enter.callback()));
+}
+
+int32_t SetMulticastLoopbackMode(PP_Instance instance,
+                                 PP_Var socket_id,
+                                 PP_Var enabled,
+                                 PP_Var* result,
+                                 PP_CompletionCallback callback) {
+  EnterInstanceAPI<ExtensionsCommon_API> enter(instance, callback);
+  if (enter.failed())
+    return enter.retval();
+
+  std::vector<PP_Var> input_args;
+  std::vector<PP_Var*> output_args;
+  input_args.push_back(socket_id);
+  input_args.push_back(enabled);
+  output_args.push_back(result);
+  return enter.SetResult(enter.functions()->CallBrowser(
+      "socket.setMulticastLoopbackMode", input_args, output_args,
+      enter.callback()));
+}
+
+int32_t GetJoinedGroups(PP_Instance instance,
+                        PP_Var socket_id,
+                        PP_Var* groups,
+                        PP_CompletionCallback callback) {
+  EnterInstanceAPI<ExtensionsCommon_API> enter(instance, callback);
+  if (enter.failed())
+    return enter.retval();
+
+  std::vector<PP_Var> input_args;
+  std::vector<PP_Var*> output_args;
+  input_args.push_back(socket_id);
+  output_args.push_back(groups);
+  return enter.SetResult(enter.functions()->CallBrowser(
+      "socket.getJoinedGroups", input_args, output_args, enter.callback()));
+}
+
 const PPB_Ext_Socket_Dev_0_1 g_ppb_ext_socket_dev_0_1_thunk = {
   &Create,
   &Destroy,
@@ -296,11 +383,37 @@
   &GetNetworkList
 };
 
+const PPB_Ext_Socket_Dev_0_2 g_ppb_ext_socket_dev_0_2_thunk = {
+  &Create,
+  &Destroy,
+  &Connect,
+  &Bind,
+  &Disconnect,
+  &Read,
+  &Write,
+  &RecvFrom,
+  &SendTo,
+  &Listen,
+  &Accept,
+  &SetKeepAlive,
+  &SetNoDelay,
+  &GetInfo,
+  &GetNetworkList,
+  &JoinGroup,
+  &LeaveGroup,
+  &SetMulticastTimeToLive,
+  &SetMulticastLoopbackMode,
+  &GetJoinedGroups
+};
 }  // namespace
 
 const PPB_Ext_Socket_Dev_0_1* GetPPB_Ext_Socket_Dev_0_1_Thunk() {
   return &g_ppb_ext_socket_dev_0_1_thunk;
 }
 
+const PPB_Ext_Socket_Dev_0_2* GetPPB_Ext_Socket_Dev_0_2_Thunk() {
+  return &g_ppb_ext_socket_dev_0_2_thunk;
+}
+
 }  // namespace thunk
 }  // namespace ppapi
diff --git a/ppapi/thunk/ppb_flash_device_id_thunk.cc b/ppapi/thunk/ppb_flash_device_id_thunk.cc
index 595fdc7..43432a0 100644
--- a/ppapi/thunk/ppb_flash_device_id_thunk.cc
+++ b/ppapi/thunk/ppb_flash_device_id_thunk.cc
@@ -9,7 +9,7 @@
 #include "ppapi/c/private/ppb_flash_device_id.h"
 #include "ppapi/shared_impl/tracked_callback.h"
 #include "ppapi/thunk/enter.h"
-#include "ppapi/thunk/ppb_flash_device_id_api.h"
+#include "ppapi/thunk/ppb_flash_drm_api.h"
 #include "ppapi/thunk/ppb_instance_api.h"
 #include "ppapi/thunk/resource_creation_api.h"
 #include "ppapi/thunk/thunk.h"
@@ -24,14 +24,14 @@
   EnterResourceCreation enter(instance);
   if (enter.failed())
     return 0;
-  return enter.functions()->CreateFlashDeviceID(instance);
+  return enter.functions()->CreateFlashDRM(instance);
 }
 
 int32_t GetDeviceID(PP_Resource device_id,
                     struct PP_Var* id,
                     struct PP_CompletionCallback callback) {
   VLOG(4) << "PPB_Flash_DeviceID::GetDeviceID()";
-  EnterResource<PPB_Flash_DeviceID_API> enter(device_id, callback, true);
+  EnterResource<PPB_Flash_DRM_API> enter(device_id, callback, true);
   if (enter.failed())
     return enter.retval();
   return enter.SetResult(enter.object()->GetDeviceID(id, enter.callback()));
diff --git a/ppapi/thunk/ppb_flash_device_id_api.h b/ppapi/thunk/ppb_flash_drm_api.h
similarity index 79%
rename from ppapi/thunk/ppb_flash_device_id_api.h
rename to ppapi/thunk/ppb_flash_drm_api.h
index cbd1bf5..28d91be 100644
--- a/ppapi/thunk/ppb_flash_device_id_api.h
+++ b/ppapi/thunk/ppb_flash_drm_api.h
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include "base/memory/ref_counted.h"
+#include "ppapi/c/private/ppb_flash_drm.h"
 #include "ppapi/thunk/ppapi_thunk_export.h"
 
 namespace ppapi {
@@ -11,9 +12,9 @@
 
 namespace thunk {
 
-class PPAPI_THUNK_EXPORT PPB_Flash_DeviceID_API {
+class PPAPI_THUNK_EXPORT PPB_Flash_DRM_API {
  public:
-  virtual ~PPB_Flash_DeviceID_API() {}
+  virtual ~PPB_Flash_DRM_API() {}
 
   virtual int32_t GetDeviceID(PP_Var* id,
                               scoped_refptr<TrackedCallback> callback) = 0;
diff --git a/ppapi/thunk/ppb_flash_drm_thunk.cc b/ppapi/thunk/ppb_flash_drm_thunk.cc
new file mode 100644
index 0000000..5d1176d
--- /dev/null
+++ b/ppapi/thunk/ppb_flash_drm_thunk.cc
@@ -0,0 +1,52 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// From private/ppb_flash_drm.idl modified Mon May 20 13:45:09 2013.
+
+#include "ppapi/c/pp_completion_callback.h"
+#include "ppapi/c/pp_errors.h"
+#include "ppapi/c/private/ppb_flash_drm.h"
+#include "ppapi/shared_impl/tracked_callback.h"
+#include "ppapi/thunk/enter.h"
+#include "ppapi/thunk/ppb_flash_drm_api.h"
+#include "ppapi/thunk/ppb_instance_api.h"
+#include "ppapi/thunk/resource_creation_api.h"
+#include "ppapi/thunk/thunk.h"
+
+namespace ppapi {
+namespace thunk {
+
+namespace {
+
+PP_Resource Create(PP_Instance instance) {
+  VLOG(4) << "PPB_Flash_DRM::Create()";
+  EnterResourceCreation enter(instance);
+  if (enter.failed())
+    return 0;
+  return enter.functions()->CreateFlashDRM(instance);
+}
+
+int32_t GetDeviceID(PP_Resource drm,
+                    struct PP_Var* id,
+                    struct PP_CompletionCallback callback) {
+  VLOG(4) << "PPB_Flash_DRM::GetDeviceID()";
+  EnterResource<PPB_Flash_DRM_API> enter(drm, callback, true);
+  if (enter.failed())
+    return enter.retval();
+  return enter.SetResult(enter.object()->GetDeviceID(id, enter.callback()));
+}
+
+const PPB_Flash_DRM_1_0 g_ppb_flash_drm_thunk_1_0 = {
+  &Create,
+  &GetDeviceID
+};
+
+}  // namespace
+
+const PPB_Flash_DRM_1_0* GetPPB_Flash_DRM_1_0_Thunk() {
+  return &g_ppb_flash_drm_thunk_1_0;
+}
+
+}  // namespace thunk
+}  // namespace ppapi
diff --git a/ppapi/thunk/ppb_tcp_server_socket_private_api.h b/ppapi/thunk/ppb_tcp_server_socket_private_api.h
index 8563bef..0ca23d1 100644
--- a/ppapi/thunk/ppb_tcp_server_socket_private_api.h
+++ b/ppapi/thunk/ppb_tcp_server_socket_private_api.h
@@ -24,6 +24,7 @@
                          scoped_refptr<TrackedCallback> callback) = 0;
   virtual int32_t Accept(PP_Resource* tcp_socket,
                          scoped_refptr<TrackedCallback> callback) = 0;
+  virtual int32_t GetLocalAddress(PP_NetAddress_Private* addr) = 0;
   virtual void StopListening() = 0;
 };
 
diff --git a/ppapi/thunk/ppb_tcp_server_socket_private_thunk.cc b/ppapi/thunk/ppb_tcp_server_socket_private_thunk.cc
index a9fcb14..bbfe16d 100644
--- a/ppapi/thunk/ppb_tcp_server_socket_private_thunk.cc
+++ b/ppapi/thunk/ppb_tcp_server_socket_private_thunk.cc
@@ -49,13 +49,21 @@
   return enter.SetResult(enter.object()->Accept(tcp_socket, enter.callback()));
 }
 
+int32_t GetLocalAddress(PP_Resource tcp_server_socket,
+                        PP_NetAddress_Private* addr) {
+  EnterTCPServer enter(tcp_server_socket, true);
+  if (enter.failed())
+    return PP_ERROR_BADRESOURCE;
+  return enter.object()->GetLocalAddress(addr);
+}
+
 void StopListening(PP_Resource tcp_server_socket) {
   EnterTCPServer enter(tcp_server_socket, true);
   if (enter.succeeded())
     enter.object()->StopListening();
 }
 
-const PPB_TCPServerSocket_Private g_ppb_tcp_server_socket_thunk = {
+const PPB_TCPServerSocket_Private_0_1 g_ppb_tcp_server_socket_thunk_0_1 = {
   Create,
   IsTCPServerSocket,
   Listen,
@@ -63,10 +71,25 @@
   StopListening
 };
 
+const PPB_TCPServerSocket_Private_0_2 g_ppb_tcp_server_socket_thunk_0_2 = {
+  Create,
+  IsTCPServerSocket,
+  Listen,
+  Accept,
+  GetLocalAddress,
+  StopListening,
+};
+
 }  // namespace
 
-const PPB_TCPServerSocket_Private* GetPPB_TCPServerSocket_Private_0_1_Thunk() {
-  return &g_ppb_tcp_server_socket_thunk;
+const PPB_TCPServerSocket_Private_0_1*
+GetPPB_TCPServerSocket_Private_0_1_Thunk() {
+  return &g_ppb_tcp_server_socket_thunk_0_1;
+}
+
+const PPB_TCPServerSocket_Private_0_2*
+GetPPB_TCPServerSocket_Private_0_2_Thunk() {
+  return &g_ppb_tcp_server_socket_thunk_0_2;
 }
 
 }  // namespace thunk
diff --git a/ppapi/thunk/ppb_url_loader_api.h b/ppapi/thunk/ppb_url_loader_api.h
index 00d4690..df9b6aa 100644
--- a/ppapi/thunk/ppb_url_loader_api.h
+++ b/ppapi/thunk/ppb_url_loader_api.h
@@ -49,14 +49,6 @@
   virtual void GrantUniversalAccess() = 0;
   virtual void RegisterStatusCallback(
       PP_URLLoaderTrusted_StatusCallback cb) = 0;
-
-  // Internal function. This will fill in the given response info data and
-  // return true on sucesss. If the dowbload was to a file, there will be one
-  // plugin reference transferred to the caller. On failure, returns false.
-  //
-  // If body_as_file_ref is non-zero, this will transfer one plugin reference
-  // to that object to the caller.
-  virtual bool GetResponseInfoData(URLResponseInfoData* data) = 0;
 };
 
 }  // namespace thunk
diff --git a/ppapi/thunk/resource_creation_api.h b/ppapi/thunk/resource_creation_api.h
index cd7e348..c441249 100644
--- a/ppapi/thunk/resource_creation_api.h
+++ b/ppapi/thunk/resource_creation_api.h
@@ -29,6 +29,7 @@
 
 namespace ppapi {
 
+struct PPB_FileRef_CreateInfo;
 struct URLRequestInfoData;
 struct URLResponseInfoData;
 
@@ -47,6 +48,12 @@
   virtual PP_Resource CreateFileRef(PP_Instance instance,
                                     PP_Resource file_system,
                                     const char* path) = 0;
+  // Like the above version but takes a serialized file ref. The resource
+  // in the serialized file ref is passed into this, which takes ownership of
+  // the reference. In the proxy, the return value will be a plugin resource.
+  // In the impl, the return value will be the same resource ID.
+  virtual PP_Resource CreateFileRef(
+      const PPB_FileRef_CreateInfo& serialized) = 0;
   virtual PP_Resource CreateFileSystem(PP_Instance instance,
                                        PP_FileSystemType type) = 0;
   virtual PP_Resource CreateIsolatedFileSystem(PP_Instance instance,
@@ -153,7 +160,7 @@
       PP_Instance instance,
       const PP_BrowserFont_Trusted_Description* description) = 0;
   virtual PP_Resource CreateBuffer(PP_Instance instance, uint32_t size) = 0;
-  virtual PP_Resource CreateFlashDeviceID(PP_Instance instance) = 0;
+  virtual PP_Resource CreateFlashDRM(PP_Instance instance) = 0;
   virtual PP_Resource CreateFlashFontFile(
       PP_Instance instance,
       const PP_BrowserFont_Trusted_Description* description,
diff --git a/ppapi/thunk/thunk.h b/ppapi/thunk/thunk.h
index 2b074ff..2e31d2a 100644
--- a/ppapi/thunk/thunk.h
+++ b/ppapi/thunk/thunk.h
@@ -10,7 +10,6 @@
 #include "ppapi/c/trusted/ppb_buffer_trusted.h"
 #include "ppapi/c/trusted/ppb_graphics_3d_trusted.h"
 #include "ppapi/c/trusted/ppb_image_data_trusted.h"
-#include "ppapi/c/trusted/ppb_url_loader_trusted.h"
 #include "ppapi/thunk/ppapi_thunk_export.h"
 
 // Declares a getter for the interface thunk of the form:
@@ -50,8 +49,6 @@
     GetPPB_ImageDataTrusted_0_4_Thunk();
 PPAPI_THUNK_EXPORT const PPB_Instance_Private_0_1*
     GetPPB_Instance_Private_0_1_Thunk();
-PPAPI_THUNK_EXPORT const PPB_URLLoaderTrusted_0_3*
-    GetPPB_URLLoaderTrusted_0_3_Thunk();
 
 }  // namespace thunk
 }  // namespace ppapi