| Index: chrome/renderer/resources/extensions/certificate_provider_custom_bindings.js | 
| diff --git a/chrome/renderer/resources/extensions/certificate_provider_custom_bindings.js b/chrome/renderer/resources/extensions/certificate_provider_custom_bindings.js | 
| new file mode 100644 | 
| index 0000000000000000000000000000000000000000..6089677b2a8f6e7a1db4bbc2c091e46f0e3105fc | 
| --- /dev/null | 
| +++ b/chrome/renderer/resources/extensions/certificate_provider_custom_bindings.js | 
| @@ -0,0 +1,81 @@ | 
| +// Copyright 2015 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. | 
| + | 
| +var binding = require('binding').Binding.create('certificateProvider'); | 
| +var certificateProviderInternal = require('binding').Binding.create( | 
| +    'certificateProviderInternal').generate(); | 
| +var eventBindings = require('event_bindings'); | 
| + | 
| +var certificateProviderSchema = | 
| +    requireNative('schema_registry').GetSchema('certificateProvider') | 
| +var utils = require('utils'); | 
| +var validate = require('schemaUtils').validate; | 
| + | 
| +// Custom bindings for chrome.certificateProvider API. | 
| +// The bindings are used to implement callbacks for the API events. Internally | 
| +// each event is passed a requestId argument used to identify the callback | 
| +// associated with the event. This argument is massaged out from the event | 
| +// arguments before dispatching the event to consumers. A callback is appended | 
| +// to the event arguments. The callback wraps an appropriate | 
| +// chrome.certificateProviderInternal API function that is used to report the | 
| +// event result from the extension. The function is passed the requestId and | 
| +// values provided by the extension. It validates that the values provided by | 
| +// the extension match chrome.certificateProvider event callback schemas. It | 
| +// also ensures that a callback is run at most once. In case there is an | 
| +// exception during event dispatching, the chrome.certificateProviderInternal | 
| +// function is called with a default error value. | 
| + | 
| +// Handles a chrome.certificateProvider event as described in the file comment. | 
| +// |eventName|: The event name. The first argument of the event must be a | 
| +//     request id. | 
| +// |internalReportFunc|: The function that should be called to report results in | 
| +//     reply to an event. The first argument of the function must be the request | 
| +//     id that was received with the event. | 
| +function handleEvent(eventName, internalReportFunc) { | 
| +  var eventSchema = | 
| +      utils.lookup(certificateProviderSchema.events, 'name', eventName); | 
| +  var callbackSchema = utils.lookup(eventSchema.parameters, 'type', 'function'); | 
| + | 
| +  eventBindings.registerArgumentMassager( | 
| +      'certificateProvider.' + eventName, | 
| +      function(args, dispatch) { | 
| +        var responded = false; | 
| + | 
| +        // Function provided to the extension as the event callback argument. | 
| +        // The extension calls this to report results in reply to the event. | 
| +        // It throws an exception if called more than once and if the provided | 
| +        // results don't match the callback schema. | 
| +        var reportFunc = function(reportArg1, reportArg2) { | 
| +          if (responded) { | 
| +            throw new Error( | 
| +                'Event callback must not be called more than once.'); | 
| +          } | 
| + | 
| +          var reportArgs = [reportArg1]; | 
| +          if (reportArg2 !== undefined) | 
| +            reportArgs.push(reportArg2); | 
| +          var finalArgs = []; | 
| +          try { | 
| +            // Validates that the results reported by the extension matche the | 
| +            // callback schema of the event. Throws an exception in case of an | 
| +            // error. | 
| +            validate(reportArgs, callbackSchema.parameters); | 
| +            finalArgs = reportArgs; | 
| +          } finally { | 
| +            responded = true; | 
| +            internalReportFunc.apply( | 
| +                null, [args[0] /* requestId */].concat(finalArgs)); | 
| +          } | 
| +        }; | 
| +        dispatch(args.slice(1).concat(reportFunc)); | 
| +      }); | 
| +} | 
| + | 
| +handleEvent('onCertificatesRequested', | 
| +            certificateProviderInternal.reportCertificates); | 
| + | 
| +handleEvent('onSignDigestRequested', | 
| +            certificateProviderInternal.reportSignature); | 
| + | 
| +exports.binding = binding.generate(); | 
|  |