mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge latest green inbound changeset and mozilla-central
This commit is contained in:
commit
d9879cd4ec
@ -1,4 +1,4 @@
|
||||
{
|
||||
"revision": "47d1ef9819810cecf9ce8cdcfd7f211530e43668",
|
||||
"revision": "4cdfe9307db3882da00e49361aa2f6788c9efe54",
|
||||
"repo_path": "/integration/gaia-central"
|
||||
}
|
||||
|
@ -24,9 +24,17 @@ let WebrtcIndicator = {
|
||||
fillPopup: function (aPopup) {
|
||||
this._menuitemData = new WeakMap;
|
||||
for (let streamData of this.UIModule.activeStreams) {
|
||||
let pageURI = Services.io.newURI(streamData.uri, null, null);
|
||||
let menuitem = document.createElement("menuitem");
|
||||
menuitem.setAttribute("label", streamData.uri);
|
||||
menuitem.setAttribute("class", "menuitem-iconic");
|
||||
menuitem.setAttribute("label", streamData.browser.contentTitle || streamData.uri);
|
||||
menuitem.setAttribute("tooltiptext", streamData.uri);
|
||||
PlacesUtils.favicons.getFaviconURLForPage(pageURI, function (aURI) {
|
||||
if (aURI) {
|
||||
let iconURL = PlacesUtils.favicons.getFaviconLinkForIcon(aURI).spec;
|
||||
menuitem.setAttribute("image", iconURL);
|
||||
}
|
||||
});
|
||||
|
||||
this._menuitemData.set(menuitem, streamData);
|
||||
|
||||
|
@ -94,6 +94,7 @@ function cleanup() {
|
||||
Services.obs.removeObserver(obs_DESTROYING, DESTROYING);
|
||||
Services.obs.removeObserver(obs_BEFORE_DESTROYED, BEFORE_DESTROYED);
|
||||
Services.obs.removeObserver(obs_DESTROYED, DESTROYED);
|
||||
Services.obs.removeObserver(obs_STARTUP, STARTUP);
|
||||
|
||||
gBrowser.removeCurrentTab();
|
||||
finish();
|
||||
|
@ -118,6 +118,7 @@ function cleanup() {
|
||||
Services.obs.removeObserver(tab_DESTROYING, DESTROYING);
|
||||
Services.obs.removeObserver(tab_SHOWN, SHOWN);
|
||||
Services.obs.removeObserver(tab_HIDDEN, HIDDEN);
|
||||
Services.obs.removeObserver(tab_STARTUP, STARTUP);
|
||||
|
||||
gBrowser.tabContainer.removeEventListener("TabSelect", tabSelect);
|
||||
gBrowser.removeCurrentTab();
|
||||
|
@ -282,13 +282,6 @@ public:
|
||||
uint16_t ReadyState();
|
||||
|
||||
// request
|
||||
void Open(const nsACString& aMethod, const nsAString& aUrl, ErrorResult& aRv)
|
||||
{
|
||||
Open(aMethod, aUrl, true,
|
||||
mozilla::dom::Optional<nsAString>(),
|
||||
mozilla::dom::Optional<nsAString>(),
|
||||
aRv);
|
||||
}
|
||||
void Open(const nsACString& aMethod, const nsAString& aUrl, bool aAsync,
|
||||
const mozilla::dom::Optional<nsAString>& aUser,
|
||||
const mozilla::dom::Optional<nsAString>& aPassword,
|
||||
|
@ -27,15 +27,11 @@ function checkDoc(title, expectedtitle, normalizedtitle) {
|
||||
is(doc.doctype.internalSubset, null, "internalSubset should be null!");
|
||||
isElement(doc.documentElement, "html");
|
||||
isElement(doc.documentElement.firstChild, "head");
|
||||
if (title !== undefined) {
|
||||
is(doc.documentElement.firstChild.childNodes.length, 1);
|
||||
isElement(doc.documentElement.firstChild.firstChild, "title");
|
||||
// Doesn't always work out in WebKit.
|
||||
ok(doc.documentElement.firstChild.firstChild.firstChild, "Need a text node.");
|
||||
is(doc.documentElement.firstChild.firstChild.firstChild.data, expectedtitle);
|
||||
} else {
|
||||
is(doc.documentElement.firstChild.childNodes.length, 0);
|
||||
}
|
||||
is(doc.documentElement.firstChild.childNodes.length, 1);
|
||||
isElement(doc.documentElement.firstChild.firstChild, "title");
|
||||
// Doesn't always work out in WebKit.
|
||||
ok(doc.documentElement.firstChild.firstChild.firstChild, "Need a text node.");
|
||||
is(doc.documentElement.firstChild.firstChild.firstChild.data, expectedtitle);
|
||||
isElement(doc.documentElement.lastChild, "body");
|
||||
is(doc.documentElement.lastChild.childNodes.length, 0);
|
||||
((!title || title.indexOf("\f") === -1) ? is : todo_is)
|
||||
@ -45,7 +41,7 @@ function checkDoc(title, expectedtitle, normalizedtitle) {
|
||||
}
|
||||
checkDoc("", "", "");
|
||||
checkDoc(null, "null", "null");
|
||||
checkDoc(undefined, "", "");
|
||||
checkDoc(undefined, "undefined", "undefined");
|
||||
checkDoc("foo bar baz", "foo bar baz", "foo bar baz");
|
||||
checkDoc("foo\t\tbar baz", "foo\t\tbar baz", "foo bar baz");
|
||||
checkDoc("foo\n\nbar baz", "foo\n\nbar baz", "foo bar baz");
|
||||
|
@ -447,6 +447,8 @@ public:
|
||||
virtual bool IsDormantNeeded() { return false; }
|
||||
// Release media resources they should be released in dormant state
|
||||
virtual void ReleaseMediaResources() {};
|
||||
// Release the decoder during shutdown
|
||||
virtual void ReleaseDecoder() {};
|
||||
|
||||
// Resets all state related to decoding, emptying all buffers etc.
|
||||
virtual nsresult ResetDecode();
|
||||
|
@ -320,7 +320,13 @@ public:
|
||||
void SetFragmentEndTime(int64_t aEndTime);
|
||||
|
||||
// Drop reference to decoder. Only called during shutdown dance.
|
||||
void ReleaseDecoder() { mDecoder = nullptr; }
|
||||
void ReleaseDecoder() {
|
||||
MOZ_ASSERT(mReader);
|
||||
if (mReader) {
|
||||
mReader->ReleaseDecoder();
|
||||
}
|
||||
mDecoder = nullptr;
|
||||
}
|
||||
|
||||
// Called when a "MozAudioAvailable" event listener is added to the media
|
||||
// element. Called on the main thread.
|
||||
|
@ -69,6 +69,13 @@ void MediaOmxReader::ReleaseMediaResources()
|
||||
}
|
||||
}
|
||||
|
||||
void MediaOmxReader::ReleaseDecoder()
|
||||
{
|
||||
if (mOmxDecoder.get()) {
|
||||
mOmxDecoder->ReleaseDecoder();
|
||||
}
|
||||
}
|
||||
|
||||
nsresult MediaOmxReader::ReadMetadata(MediaInfo* aInfo,
|
||||
MetadataTags** aTags)
|
||||
{
|
||||
|
@ -62,6 +62,8 @@ public:
|
||||
virtual bool IsDormantNeeded();
|
||||
virtual void ReleaseMediaResources();
|
||||
|
||||
virtual void ReleaseDecoder() MOZ_OVERRIDE;
|
||||
|
||||
virtual nsresult ReadMetadata(MediaInfo* aInfo,
|
||||
MetadataTags** aTags);
|
||||
virtual nsresult Seek(int64_t aTime, int64_t aStartTime, int64_t aEndTime, int64_t aCurrentTime);
|
||||
|
@ -62,8 +62,8 @@ private:
|
||||
};
|
||||
|
||||
// When loading an MP3 stream from a file, we need to parse the file's
|
||||
// content to find its duration. Reading files of 100 Mib or more can
|
||||
// delay the player app noticably, so the file os read and decoded in
|
||||
// content to find its duration. Reading files of 100 MiB or more can
|
||||
// delay the player app noticably, so the file is read and decoded in
|
||||
// smaller chunks.
|
||||
//
|
||||
// We first read on the decode thread, but parsing must be done on the
|
||||
@ -79,7 +79,9 @@ private:
|
||||
class OmxDecoderNotifyDataArrivedRunnable : public nsRunnable
|
||||
{
|
||||
public:
|
||||
OmxDecoderNotifyDataArrivedRunnable(android::OmxDecoder* aOmxDecoder, const char* aBuffer, uint64_t aLength, int64_t aOffset, uint64_t aFullLength)
|
||||
OmxDecoderNotifyDataArrivedRunnable(android::OmxDecoder* aOmxDecoder,
|
||||
const char* aBuffer, uint64_t aLength,
|
||||
int64_t aOffset, uint64_t aFullLength)
|
||||
: mOmxDecoder(aOmxDecoder),
|
||||
mBuffer(aBuffer),
|
||||
mLength(aLength),
|
||||
@ -96,24 +98,7 @@ public:
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
|
||||
|
||||
const char* buffer = mBuffer.get();
|
||||
|
||||
while (mLength) {
|
||||
uint32_t length = std::min<uint64_t>(mLength, UINT32_MAX);
|
||||
mOmxDecoder->NotifyDataArrived(mBuffer.get(), mLength, mOffset);
|
||||
|
||||
buffer += length;
|
||||
mLength -= length;
|
||||
mOffset += length;
|
||||
}
|
||||
|
||||
if (mOffset < mFullLength) {
|
||||
// We cannot read data in the main thread because it
|
||||
// might block for too long. Instead we post an IO task
|
||||
// to the IO thread if there is more data available.
|
||||
XRE_GetIOMessageLoop()->PostTask(FROM_HERE, new OmxDecoderProcessCachedDataTask(mOmxDecoder.get(), mOffset));
|
||||
}
|
||||
|
||||
NotifyDataArrived();
|
||||
Completed();
|
||||
|
||||
return NS_OK;
|
||||
@ -130,6 +115,32 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
void NotifyDataArrived()
|
||||
{
|
||||
const char* buffer = mBuffer.get();
|
||||
|
||||
while (mLength) {
|
||||
uint32_t length = std::min<uint64_t>(mLength, UINT32_MAX);
|
||||
bool success = mOmxDecoder->NotifyDataArrived(buffer, mLength,
|
||||
mOffset);
|
||||
if (!success) {
|
||||
return;
|
||||
}
|
||||
|
||||
buffer += length;
|
||||
mLength -= length;
|
||||
mOffset += length;
|
||||
}
|
||||
|
||||
if (mOffset < mFullLength) {
|
||||
// We cannot read data in the main thread because it
|
||||
// might block for too long. Instead we post an IO task
|
||||
// to the IO thread if there is more data available.
|
||||
XRE_GetIOMessageLoop()->PostTask(FROM_HERE,
|
||||
new OmxDecoderProcessCachedDataTask(mOmxDecoder.get(), mOffset));
|
||||
}
|
||||
}
|
||||
|
||||
// Call this function at the end of Run() to notify waiting
|
||||
// threads.
|
||||
void Completed()
|
||||
@ -400,7 +411,7 @@ bool OmxDecoder::TryLoad() {
|
||||
const char* audioMime;
|
||||
sp<MetaData> meta = mAudioTrack->getFormat();
|
||||
|
||||
if (meta->findCString(kKeyMIMEType, &audioMime) && !strcasecmp(audioMime, AUDIO_MP3)) {
|
||||
if (mIsMp3) {
|
||||
// Feed MP3 parser with cached data. Local files will be fully
|
||||
// cached already, network streams will update with sucessive
|
||||
// calls to NotifyDataArrived.
|
||||
@ -628,10 +639,15 @@ bool OmxDecoder::SetAudioFormat() {
|
||||
return true;
|
||||
}
|
||||
|
||||
void OmxDecoder::NotifyDataArrived(const char* aBuffer, uint32_t aLength, int64_t aOffset)
|
||||
void OmxDecoder::ReleaseDecoder()
|
||||
{
|
||||
if (!mAudioTrack.get() || !mIsMp3 || !mMP3FrameParser.IsMP3()) {
|
||||
return;
|
||||
mDecoder = nullptr;
|
||||
}
|
||||
|
||||
bool OmxDecoder::NotifyDataArrived(const char* aBuffer, uint32_t aLength, int64_t aOffset)
|
||||
{
|
||||
if (!mAudioTrack.get() || !mIsMp3 || !mMP3FrameParser.IsMP3() || !mDecoder) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mMP3FrameParser.Parse(aBuffer, aLength, aOffset);
|
||||
@ -645,6 +661,8 @@ void OmxDecoder::NotifyDataArrived(const char* aBuffer, uint32_t aLength, int64_
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
mDecoder->UpdateEstimatedMediaDuration(mDurationUs);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void OmxDecoder::ReleaseVideoBuffer() {
|
||||
|
@ -181,7 +181,9 @@ public:
|
||||
bool SetVideoFormat();
|
||||
bool SetAudioFormat();
|
||||
|
||||
void NotifyDataArrived(const char* aBuffer, uint32_t aLength, int64_t aOffset);
|
||||
void ReleaseDecoder();
|
||||
|
||||
bool NotifyDataArrived(const char* aBuffer, uint32_t aLength, int64_t aOffset);
|
||||
|
||||
void GetDuration(int64_t *durationUs) {
|
||||
*durationUs = mDurationUs;
|
||||
|
@ -998,34 +998,8 @@ nsXBLPrototypeBinding::Read(nsIObjectInputStream* aStream,
|
||||
previousHandler = handler;
|
||||
} while (1);
|
||||
|
||||
if (mBinding) {
|
||||
while (true) {
|
||||
XBLBindingSerializeDetails type;
|
||||
rv = aStream->Read8(&type);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (type != XBLBinding_Serialize_Attribute) {
|
||||
break;
|
||||
}
|
||||
|
||||
int32_t attrNamespace;
|
||||
rv = ReadNamespace(aStream, attrNamespace);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsAutoString attrName, attrValue;
|
||||
rv = aStream->ReadString(attrName);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = aStream->ReadString(attrValue);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIAtom> atomName = do_GetAtom(attrName);
|
||||
mBinding->SetAttr(attrNamespace, atomName, attrValue, false);
|
||||
}
|
||||
}
|
||||
|
||||
// Finally, read in the resources.
|
||||
while (true) {
|
||||
do {
|
||||
XBLBindingSerializeDetails type;
|
||||
rv = aStream->Read8(&type);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
@ -1042,7 +1016,7 @@ nsXBLPrototypeBinding::Read(nsIObjectInputStream* aStream,
|
||||
|
||||
AddResource(type == XBLBinding_Serialize_Stylesheet ? nsGkAtoms::stylesheet :
|
||||
nsGkAtoms::image, src);
|
||||
}
|
||||
} while (1);
|
||||
|
||||
if (isFirstBinding) {
|
||||
aDocInfo->SetFirstPrototypeBinding(this);
|
||||
@ -1152,30 +1126,6 @@ nsXBLPrototypeBinding::Write(nsIObjectOutputStream* aStream)
|
||||
aStream->Write8(XBLBinding_Serialize_NoMoreItems);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (mBinding) {
|
||||
uint32_t attributes = mBinding->GetAttrCount();
|
||||
nsAutoString attrValue;
|
||||
for (uint32_t i = 0; i < attributes; ++i) {
|
||||
const nsAttrName* attr = mBinding->GetAttrNameAt(i);
|
||||
nsDependentAtomString attrName = attr->Atom();
|
||||
mBinding->GetAttr(attr->NamespaceID(), attr->Atom(), attrValue);
|
||||
rv = aStream->Write8(XBLBinding_Serialize_Attribute);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = WriteNamespace(aStream, attr->NamespaceID());
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = aStream->WriteWStringZ(attrName.get());
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = aStream->WriteWStringZ(attrValue.get());
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
}
|
||||
|
||||
aStream->Write8(XBLBinding_Serialize_NoMoreItems);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Write out the resources
|
||||
if (mResources) {
|
||||
rv = mResources->Write(aStream);
|
||||
|
@ -15,7 +15,7 @@ typedef uint8_t XBLBindingSerializeDetails;
|
||||
|
||||
// A version number to ensure we don't load cached data in a different
|
||||
// file format.
|
||||
#define XBLBinding_Serialize_Version 0x00000003
|
||||
#define XBLBinding_Serialize_Version 0x00000002
|
||||
|
||||
// Set for the first binding in a document
|
||||
#define XBLBinding_Serialize_IsFirstBinding 1
|
||||
@ -45,7 +45,6 @@ typedef uint8_t XBLBindingSerializeDetails;
|
||||
#define XBLBinding_Serialize_Handler 8
|
||||
#define XBLBinding_Serialize_Image 9
|
||||
#define XBLBinding_Serialize_Stylesheet 10
|
||||
#define XBLBinding_Serialize_Attribute 0xA
|
||||
#define XBLBinding_Serialize_Mask 0x0F
|
||||
#define XBLBinding_Serialize_ReadOnly 0x80
|
||||
|
||||
|
@ -703,8 +703,13 @@ AudioChannelService::Observe(nsISupports* aSubject, const char* aTopic, const PR
|
||||
audioManager->SetAudioChannelVolume(AUDIO_CHANNEL_ALARM, index);
|
||||
} else if (keyStr.EqualsLiteral("audio.volume.telephony")) {
|
||||
audioManager->SetAudioChannelVolume(AUDIO_CHANNEL_TELEPHONY, index);
|
||||
} else {
|
||||
MOZ_ASSUME_UNREACHABLE("unexpected audio channel for volume control");
|
||||
} else if (!keyStr.EqualsLiteral("audio.volume.bt_sco")) {
|
||||
// bt_sco is not a valid audio channel so we manipulate it in
|
||||
// AudioManager.cpp. And the others should not be used.
|
||||
// We didn't use MOZ_ASSUME_UNREACHABLE here because any web content who
|
||||
// has permission of mozSettings can set any names then it can be easy to
|
||||
// crash the B2G.
|
||||
NS_WARNING("unexpected audio channel for volume control");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -2714,7 +2714,8 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
|
||||
# A helper function for wrapping up the template body for
|
||||
# possibly-nullable objecty stuff
|
||||
def wrapObjectTemplate(templateBody, type, codeToSetNull, failureCode=None):
|
||||
if isNullOrUndefined and type.nullable():
|
||||
if isNullOrUndefined:
|
||||
assert type.nullable()
|
||||
# Just ignore templateBody and set ourselves to null.
|
||||
# Note that we don't have to worry about default values
|
||||
# here either, since we already examined this value.
|
||||
@ -3331,6 +3332,9 @@ for (uint32_t i = 0; i < length; ++i) {
|
||||
"Default": "eStringify",
|
||||
"EmptyString": "eEmpty",
|
||||
"Null": "eNull",
|
||||
# For Missing it doesn't matter what we use here, since we'll never
|
||||
# call ConvertJSValueToString on undefined in that case.
|
||||
"Missing": "eStringify"
|
||||
}
|
||||
if type.nullable():
|
||||
# For nullable strings null becomes a null string.
|
||||
@ -3850,8 +3854,11 @@ class CGArgumentConverter(CGThing):
|
||||
"args[${index}]"
|
||||
).substitute(replacer)
|
||||
self.replacementVariables["mutableVal"] = self.replacementVariables["val"]
|
||||
haveValueCheck = string.Template(
|
||||
"args.hasDefined(${index})").substitute(replacer)
|
||||
if argument.treatUndefinedAs == "Missing":
|
||||
haveValueCheck = "args.hasDefined(${index})"
|
||||
else:
|
||||
haveValueCheck = "${index} < args.length()"
|
||||
haveValueCheck = string.Template(haveValueCheck).substitute(replacer)
|
||||
self.replacementVariables["haveValue"] = haveValueCheck
|
||||
self.descriptorProvider = descriptorProvider
|
||||
if self.argument.optional and not self.argument.defaultValue:
|
||||
@ -4992,6 +4999,15 @@ class CGMethodCall(CGThing):
|
||||
CGWrapper(CGIndenter(CGGeneric(code)), pre="\n", post="\n"))
|
||||
return
|
||||
|
||||
# We don't handle [TreatUndefinedAs=Missing] arguments in overload
|
||||
# resolution yet.
|
||||
for (_, sigArgs) in signatures:
|
||||
for arg in sigArgs:
|
||||
if arg.treatUndefinedAs == "Missing":
|
||||
raise TypeError("No support for [TreatUndefinedAs=Missing] "
|
||||
"handling in overload resolution yet: %s" %
|
||||
arg.location)
|
||||
|
||||
# Need to find the right overload
|
||||
maxArgCount = method.maxArgCount
|
||||
allowedArgCounts = method.allowedArgCounts
|
||||
@ -5081,30 +5097,22 @@ class CGMethodCall(CGThing):
|
||||
else:
|
||||
failureCode = None
|
||||
type = distinguishingType(signature)
|
||||
# The argument at index distinguishingIndex can't possibly be
|
||||
# unset here, because we've already checked that argc is large
|
||||
# enough that we can examine this argument. But note that we
|
||||
# still want to claim that optional arguments are optional, in
|
||||
# case undefined was passed in.
|
||||
argIsOptional = (distinguishingArgument(signature).optional and
|
||||
not distinguishingArgument(signature).defaultValue)
|
||||
# The argument at index distinguishingIndex can't possibly
|
||||
# be unset here, because we've already checked that argc is
|
||||
# large enough that we can examine this argument.
|
||||
testCode = instantiateJSToNativeConversion(
|
||||
getJSToNativeConversionInfo(type, descriptor,
|
||||
failureCode=failureCode,
|
||||
isDefinitelyObject=isDefinitelyObject,
|
||||
isNullOrUndefined=isNullOrUndefined,
|
||||
isOptional=argIsOptional,
|
||||
sourceDescription=(argDesc % (distinguishingIndex + 1))),
|
||||
{
|
||||
"declName" : "arg%d" % distinguishingIndex,
|
||||
"holderName" : ("arg%d" % distinguishingIndex) + "_holder",
|
||||
"val" : distinguishingArg,
|
||||
"mutableVal" : distinguishingArg,
|
||||
"obj" : "obj",
|
||||
"haveValue": "args.hasDefined(%d)" % distinguishingIndex
|
||||
},
|
||||
checkForValue=argIsOptional
|
||||
)
|
||||
"obj" : "obj"
|
||||
})
|
||||
caseBody.append(CGIndenter(testCode, indent));
|
||||
# If we got this far, we know we unwrapped to the right
|
||||
# C++ type, so just do the call. Start conversion with
|
||||
@ -5114,76 +5122,24 @@ class CGMethodCall(CGThing):
|
||||
getPerSignatureCall(signature, distinguishingIndex + 1),
|
||||
indent))
|
||||
|
||||
def hasConditionalConversion(type):
|
||||
"""
|
||||
Return whether the argument conversion for this type will be
|
||||
conditional on the type of incoming JS value. For example, for
|
||||
interface types the conversion is conditional on the incoming
|
||||
value being isObject().
|
||||
|
||||
For the types for which this returns false, we do not have to
|
||||
output extra isUndefined() or isNullOrUndefined() cases, because
|
||||
null/undefined values will just fall through into our
|
||||
unconditional conversion.
|
||||
"""
|
||||
if type.isString() or type.isEnum():
|
||||
return False
|
||||
if type.isBoolean():
|
||||
distinguishingTypes = (distinguishingType(s) for s in
|
||||
possibleSignatures)
|
||||
return any(t.isString() or t.isEnum() or t.isNumeric()
|
||||
for t in distinguishingTypes)
|
||||
if type.isNumeric():
|
||||
distinguishingTypes = (distinguishingType(s) for s in
|
||||
possibleSignatures)
|
||||
return any(t.isString() or t.isEnum()
|
||||
for t in distinguishingTypes)
|
||||
return True
|
||||
|
||||
def needsNullOrUndefinedCase(type):
|
||||
"""
|
||||
Return true if the type needs a special isNullOrUndefined() case
|
||||
"""
|
||||
return ((type.nullable() and
|
||||
hasConditionalConversion(type)) or
|
||||
type.isDictionary())
|
||||
|
||||
# First check for undefined and optional distinguishing arguments
|
||||
# and output a special branch for that case. Note that we don't
|
||||
# use distinguishingArgument here because we actualy want to
|
||||
# exclude variadic arguments. Also note that we skip this check if
|
||||
# we plan to output a isNullOrUndefined() special case for this
|
||||
# argument anyway, since that will subsume our isUndefined() check.
|
||||
# This is safe, because there can be at most one nullable
|
||||
# distinguishing argument, so if we're it we'll definitely get
|
||||
# picked up by the nullable handling. Also, we can skip this check
|
||||
# if the argument has an unconditional conversion later on.
|
||||
undefSigs = [s for s in possibleSignatures if
|
||||
distinguishingIndex < len(s[1]) and
|
||||
s[1][distinguishingIndex].optional and
|
||||
hasConditionalConversion(s[1][distinguishingIndex].type) and
|
||||
not needsNullOrUndefinedCase(s[1][distinguishingIndex].type)]
|
||||
# Can't have multiple signatures with an optional argument at the
|
||||
# same index.
|
||||
assert len(undefSigs) < 2
|
||||
if len(undefSigs) > 0:
|
||||
caseBody.append(CGGeneric("if (%s.isUndefined()) {" %
|
||||
distinguishingArg))
|
||||
tryCall(undefSigs[0], 2, isNullOrUndefined=True)
|
||||
caseBody.append(CGGeneric("}"))
|
||||
|
||||
# Next, check for null or undefined. That means looking for
|
||||
# First check for null or undefined. That means looking for
|
||||
# nullable arguments at the distinguishing index and outputting a
|
||||
# separate branch for them. But if the nullable argument has an
|
||||
# unconditional conversion, we don't need to do that. The reason
|
||||
# separate branch for them. But if the nullable argument is a
|
||||
# primitive, string, or enum, we don't need to do that. The reason
|
||||
# for that is that at most one argument at the distinguishing index
|
||||
# is nullable (since two nullable arguments are not
|
||||
# distinguishable), and null/undefined values will always fall
|
||||
# through to the unconditional conversion we have, if any, since
|
||||
# they will fail whatever the conditions on the input value are for
|
||||
# our other conversions.
|
||||
# distinguishable), and all the argument types other than
|
||||
# primitive/string/enum end up inside isObject() checks. So if our
|
||||
# nullable is a primitive/string/enum it's safe to not output the
|
||||
# extra branch: we'll fall through to conversion for those types,
|
||||
# which correctly handles null as needed, because isObject() will be
|
||||
# false for null and undefined.
|
||||
nullOrUndefSigs = [s for s in possibleSignatures
|
||||
if needsNullOrUndefinedCase(distinguishingType(s))]
|
||||
if ((distinguishingType(s).nullable() and not
|
||||
distinguishingType(s).isString() and not
|
||||
distinguishingType(s).isEnum() and not
|
||||
distinguishingType(s).isPrimitive()) or
|
||||
distinguishingType(s).isDictionary())]
|
||||
# Can't have multiple nullable types here
|
||||
assert len(nullOrUndefSigs) < 2
|
||||
if len(nullOrUndefSigs) > 0:
|
||||
|
@ -81,6 +81,11 @@ public:
|
||||
return !Equals(aOtherNullable);
|
||||
}
|
||||
|
||||
operator bool() const
|
||||
{
|
||||
return !mIsNull;
|
||||
}
|
||||
|
||||
// Make it possible to use a const Nullable of an array type with other
|
||||
// array types.
|
||||
template<typename U>
|
||||
|
@ -401,7 +401,12 @@ class IDLObjectWithIdentifier(IDLObject):
|
||||
if isDictionaryMember:
|
||||
raise WebIDLError("[TreatUndefinedAs] is not allowed for "
|
||||
"dictionary members", [self.location])
|
||||
if value == 'Null':
|
||||
if value == 'Missing':
|
||||
if not isOptional:
|
||||
raise WebIDLError("[TreatUndefinedAs=Missing] is only "
|
||||
"allowed on optional arguments",
|
||||
[self.location])
|
||||
elif value == 'Null':
|
||||
if not self.type.isDOMString():
|
||||
raise WebIDLError("[TreatUndefinedAs=Null] is only "
|
||||
"allowed on arguments or "
|
||||
@ -421,8 +426,8 @@ class IDLObjectWithIdentifier(IDLObject):
|
||||
[self.location])
|
||||
else:
|
||||
raise WebIDLError("[TreatUndefinedAs] must take the "
|
||||
"identifiers EmptyString or Null",
|
||||
[self.location])
|
||||
"identifiers EmptyString or Null or "
|
||||
"Missing", [self.location])
|
||||
self.treatUndefinedAs = value
|
||||
else:
|
||||
unhandledAttrs.append(attr)
|
||||
@ -3138,12 +3143,15 @@ class IDLMethod(IDLInterfaceMember, IDLScope):
|
||||
|
||||
def finish(self, scope):
|
||||
for overload in self._overloads:
|
||||
inOptionalArguments = False
|
||||
variadicArgument = None
|
||||
|
||||
arguments = overload.arguments
|
||||
for (idx, argument) in enumerate(arguments):
|
||||
if not argument.isComplete():
|
||||
argument.complete(scope)
|
||||
if argument.isComplete():
|
||||
continue
|
||||
|
||||
argument.complete(scope)
|
||||
assert argument.type.isComplete()
|
||||
|
||||
if (argument.type.isDictionary() or
|
||||
@ -3153,7 +3161,7 @@ class IDLMethod(IDLInterfaceMember, IDLScope):
|
||||
# end of the list or followed by optional arguments must be
|
||||
# optional.
|
||||
if (not argument.optional and
|
||||
all(arg.optional for arg in arguments[idx+1:])):
|
||||
(idx == len(arguments) - 1 or arguments[idx+1].optional)):
|
||||
raise WebIDLError("Dictionary argument or union "
|
||||
"argument containing a dictionary "
|
||||
"not followed by a required argument "
|
||||
@ -3171,6 +3179,13 @@ class IDLMethod(IDLInterfaceMember, IDLScope):
|
||||
if variadicArgument:
|
||||
raise WebIDLError("Variadic argument is not last argument",
|
||||
[variadicArgument.location])
|
||||
# Once we see an optional argument, there can't be any non-optional
|
||||
# arguments.
|
||||
if inOptionalArguments and not argument.optional:
|
||||
raise WebIDLError("Non-optional argument after optional "
|
||||
"arguments",
|
||||
[argument.location])
|
||||
inOptionalArguments = argument.optional
|
||||
if argument.variadic:
|
||||
variadicArgument = argument
|
||||
|
||||
@ -3215,7 +3230,7 @@ class IDLMethod(IDLInterfaceMember, IDLScope):
|
||||
return [overload for overload in self._overloads if
|
||||
len(overload.arguments) == argc or
|
||||
(len(overload.arguments) > argc and
|
||||
all(arg.optional for arg in overload.arguments[argc:])) or
|
||||
overload.arguments[argc].optional) or
|
||||
(len(overload.arguments) < argc and
|
||||
len(overload.arguments) > 0 and
|
||||
overload.arguments[-1].variadic)]
|
||||
@ -4045,6 +4060,21 @@ class Parser(Tokenizer):
|
||||
raise WebIDLError("stringifier must have DOMString return type",
|
||||
[self.getLocation(p, 2)])
|
||||
|
||||
inOptionalArguments = False
|
||||
variadicArgument = False
|
||||
for argument in arguments:
|
||||
# Only the last argument can be variadic
|
||||
if variadicArgument:
|
||||
raise WebIDLError("Only the last argument can be variadic",
|
||||
[variadicArgument.location])
|
||||
# Once we see an optional argument, there can't be any non-optional
|
||||
# arguments.
|
||||
if inOptionalArguments and not argument.optional:
|
||||
raise WebIDLError("Cannot have a non-optional argument following an optional argument",
|
||||
[argument.location])
|
||||
inOptionalArguments = argument.optional
|
||||
variadicArgument = argument if argument.variadic else None
|
||||
|
||||
# identifier might be None. This is only permitted for special methods.
|
||||
if not identifier:
|
||||
if not getter and not setter and not creator and \
|
||||
|
@ -171,23 +171,6 @@ def WebIDLTest(parser, harness):
|
||||
|
||||
harness.ok(threw, "Dictionary arg followed by optional arg must be optional")
|
||||
|
||||
parser = parser.reset()
|
||||
threw = False
|
||||
try:
|
||||
parser.parse("""
|
||||
dictionary A {
|
||||
};
|
||||
interface X {
|
||||
void doFoo(A arg1, optional long arg2, long arg3);
|
||||
};
|
||||
""")
|
||||
results = parser.finish()
|
||||
except:
|
||||
threw = True
|
||||
|
||||
harness.ok(not threw,
|
||||
"Dictionary arg followed by non-optional arg doesn't have to be optional")
|
||||
|
||||
parser = parser.reset()
|
||||
threw = False
|
||||
try:
|
||||
|
@ -11,9 +11,9 @@ def WebIDLTest(parser, harness):
|
||||
except:
|
||||
threw = True
|
||||
|
||||
harness.ok(not threw,
|
||||
"Should not have thrown on non-optional argument following "
|
||||
"optional argument.")
|
||||
harness.ok(threw,
|
||||
"Should have thrown on non-optional argument following optional "
|
||||
"argument.")
|
||||
|
||||
parser = parser.reset()
|
||||
parser.parse("""
|
||||
|
@ -11,8 +11,6 @@ def WebIDLTest(parser, harness):
|
||||
void withVariadics(long... numbers);
|
||||
void withVariadics(TestOverloads iface);
|
||||
void withVariadics(long num, TestOverloads iface);
|
||||
void optionalTest();
|
||||
void optionalTest(optional long num1, long num2);
|
||||
};
|
||||
""")
|
||||
|
||||
@ -25,7 +23,7 @@ def WebIDLTest(parser, harness):
|
||||
"Should be an IDLInterface")
|
||||
harness.check(iface.identifier.QName(), "::TestOverloads", "Interface has the right QName")
|
||||
harness.check(iface.identifier.name, "TestOverloads", "Interface has the right name")
|
||||
harness.check(len(iface.members), 4, "Expect %s members" % 4)
|
||||
harness.check(len(iface.members), 3, "Expect %s members" % 3)
|
||||
|
||||
member = iface.members[0]
|
||||
harness.check(member.identifier.QName(), "::TestOverloads::basic", "Method has the right QName")
|
||||
@ -50,11 +48,3 @@ def WebIDLTest(parser, harness):
|
||||
harness.check(argument.identifier.QName(), "::TestOverloads::basic::arg1", "Argument has the right QName")
|
||||
harness.check(argument.identifier.name, "arg1", "Argument has the right name")
|
||||
harness.check(str(argument.type), "Long", "Argument has the right type")
|
||||
|
||||
member = iface.members[3]
|
||||
harness.check(len(member.overloadsForArgCount(0)), 1,
|
||||
"Only one overload for no args")
|
||||
harness.check(len(member.overloadsForArgCount(1)), 0,
|
||||
"No overloads for one arg")
|
||||
harness.check(len(member.overloadsForArgCount(2)), 1,
|
||||
"Only one overload for two args")
|
||||
|
@ -1,62 +1,51 @@
|
||||
def WebIDLTest(parser, harness):
|
||||
threw = False
|
||||
try:
|
||||
parser.parse("""
|
||||
results = parser.parse("""
|
||||
interface VariadicConstraints1 {
|
||||
void foo(byte... arg1, byte arg2);
|
||||
};
|
||||
""")
|
||||
results = parser.finish()
|
||||
|
||||
except:
|
||||
threw = True
|
||||
|
||||
harness.ok(threw,
|
||||
"Should have thrown on variadic argument followed by required "
|
||||
"argument.")
|
||||
harness.ok(threw, "Should have thrown.")
|
||||
|
||||
parser = parser.reset()
|
||||
threw = False
|
||||
try:
|
||||
parser.parse("""
|
||||
results = parser.parse("""
|
||||
interface VariadicConstraints2 {
|
||||
void foo(byte... arg1, optional byte arg2);
|
||||
};
|
||||
""")
|
||||
results = parser.finish();
|
||||
|
||||
except:
|
||||
threw = True
|
||||
|
||||
harness.ok(threw,
|
||||
"Should have thrown on variadic argument followed by optional "
|
||||
"argument.")
|
||||
harness.ok(threw, "Should have thrown.")
|
||||
|
||||
parser = parser.reset()
|
||||
threw = False
|
||||
try:
|
||||
parser.parse("""
|
||||
results = parser.parse("""
|
||||
interface VariadicConstraints3 {
|
||||
void foo(optional byte... arg1);
|
||||
};
|
||||
""")
|
||||
results = parser.finish()
|
||||
|
||||
except:
|
||||
threw = True
|
||||
|
||||
harness.ok(threw,
|
||||
"Should have thrown on variadic argument explicitly flagged as "
|
||||
"optional.")
|
||||
harness.ok(threw, "Should have thrown.")
|
||||
|
||||
parser = parser.reset()
|
||||
threw = False
|
||||
try:
|
||||
parser.parse("""
|
||||
results = parser.parse("""
|
||||
interface VariadicConstraints4 {
|
||||
void foo(byte... arg1 = 0);
|
||||
};
|
||||
""")
|
||||
results = parser.finish()
|
||||
|
||||
except:
|
||||
threw = True
|
||||
|
||||
|
@ -162,9 +162,9 @@ public:
|
||||
void PassByte(int8_t);
|
||||
int8_t ReceiveByte();
|
||||
void PassOptionalByte(const Optional<int8_t>&);
|
||||
void PassOptionalByteBeforeRequired(const Optional<int8_t>&, int8_t);
|
||||
void PassOptionalUndefinedMissingByte(const Optional<int8_t>&);
|
||||
void PassOptionalByteWithDefault(int8_t);
|
||||
void PassOptionalByteWithDefaultBeforeRequired(int8_t, int8_t);
|
||||
void PassOptionalUndefinedMissingByteWithDefault(int8_t);
|
||||
void PassNullableByte(const Nullable<int8_t>&);
|
||||
void PassOptionalNullableByte(const Optional< Nullable<int8_t> >&);
|
||||
void PassVariadicByte(const Sequence<int8_t>&);
|
||||
@ -411,7 +411,9 @@ public:
|
||||
void PassString(const nsAString&);
|
||||
void PassNullableString(const nsAString&);
|
||||
void PassOptionalString(const Optional<nsAString>&);
|
||||
void PassOptionalUndefinedMissingString(const Optional<nsAString>&);
|
||||
void PassOptionalStringWithDefaultValue(const nsAString&);
|
||||
void PassOptionalUndefinedMissingStringWithDefaultValue(const nsAString&);
|
||||
void PassOptionalNullableString(const Optional<nsAString>&);
|
||||
void PassOptionalNullableStringWithDefaultValue(const nsAString&);
|
||||
void PassVariadicString(const Sequence<nsString>&);
|
||||
@ -630,22 +632,6 @@ public:
|
||||
void Overload7(const nsCString&);
|
||||
void Overload8(int32_t);
|
||||
void Overload8(TestInterface&);
|
||||
void Overload9(const Nullable<int32_t>&);
|
||||
void Overload9(const nsAString&);
|
||||
void Overload10(const Nullable<int32_t>&);
|
||||
void Overload10(JSContext*, JS::Handle<JSObject*>);
|
||||
void Overload11(int32_t);
|
||||
void Overload11(const nsAString&);
|
||||
void Overload12(int32_t);
|
||||
void Overload12(const Nullable<bool>&);
|
||||
void Overload13(const Nullable<int32_t>&);
|
||||
void Overload13(bool);
|
||||
void Overload14(const Optional<int32_t>&);
|
||||
void Overload14(TestInterface&);
|
||||
void Overload15(int32_t);
|
||||
void Overload15(const Optional<NonNull<TestInterface> >&);
|
||||
void Overload16(int32_t);
|
||||
void Overload16(const Optional<TestInterface*>&);
|
||||
|
||||
// Variadic handling
|
||||
void PassVariadicThirdArg(const nsAString&, int32_t,
|
||||
|
@ -118,9 +118,9 @@ interface TestInterface {
|
||||
void passByte(byte arg);
|
||||
byte receiveByte();
|
||||
void passOptionalByte(optional byte arg);
|
||||
void passOptionalByteBeforeRequired(optional byte arg1, byte arg2);
|
||||
void passOptionalUndefinedMissingByte([TreatUndefinedAs=Missing] optional byte arg);
|
||||
void passOptionalByteWithDefault(optional byte arg = 0);
|
||||
void passOptionalByteWithDefaultBeforeRequired(optional byte arg1 = 0, byte arg2);
|
||||
void passOptionalUndefinedMissingByteWithDefault([TreatUndefinedAs=Missing] optional byte arg = 0);
|
||||
void passNullableByte(byte? arg);
|
||||
void passOptionalNullableByte(optional byte? arg);
|
||||
void passVariadicByte(byte... arg);
|
||||
@ -365,7 +365,9 @@ interface TestInterface {
|
||||
void passString(DOMString arg);
|
||||
void passNullableString(DOMString? arg);
|
||||
void passOptionalString(optional DOMString arg);
|
||||
void passOptionalUndefinedMissingString([TreatUndefinedAs=Missing] optional DOMString arg);
|
||||
void passOptionalStringWithDefaultValue(optional DOMString arg = "abc");
|
||||
void passOptionalUndefinedMissingStringWithDefaultValue([TreatUndefinedAs=Missing] optional DOMString arg = "abc");
|
||||
void passOptionalNullableString(optional DOMString? arg);
|
||||
void passOptionalNullableStringWithDefaultValue(optional DOMString? arg = null);
|
||||
void passVariadicString(DOMString... arg);
|
||||
@ -579,22 +581,6 @@ interface TestInterface {
|
||||
void overload7(ByteString arg);
|
||||
void overload8(long arg);
|
||||
void overload8(TestInterface arg);
|
||||
void overload9(long? arg);
|
||||
void overload9(DOMString arg);
|
||||
void overload10(long? arg);
|
||||
void overload10(object arg);
|
||||
void overload11(long arg);
|
||||
void overload11(DOMString? arg);
|
||||
void overload12(long arg);
|
||||
void overload12(boolean? arg);
|
||||
void overload13(long? arg);
|
||||
void overload13(boolean arg);
|
||||
void overload14(optional long arg);
|
||||
void overload14(TestInterface arg);
|
||||
void overload15(long arg);
|
||||
void overload15(optional TestInterface arg);
|
||||
void overload16(long arg);
|
||||
void overload16(optional TestInterface? arg);
|
||||
|
||||
// Variadic handling
|
||||
void passVariadicThirdArg(DOMString arg1, long arg2, TestInterface... arg3);
|
||||
|
@ -23,9 +23,9 @@ interface TestExampleInterface {
|
||||
void passByte(byte arg);
|
||||
byte receiveByte();
|
||||
void passOptionalByte(optional byte arg);
|
||||
void passOptionalByteBeforeRequired(optional byte arg1, byte arg2);
|
||||
void passOptionalUndefinedMissingByte([TreatUndefinedAs=Missing] optional byte arg);
|
||||
void passOptionalByteWithDefault(optional byte arg = 0);
|
||||
void passOptionalByteWithDefaultBeforeRequired(optional byte arg1 = 0, byte arg2);
|
||||
void passOptionalUndefinedMissingByteWithDefault([TreatUndefinedAs=Missing] optional byte arg = 0);
|
||||
void passNullableByte(byte? arg);
|
||||
void passOptionalNullableByte(optional byte? arg);
|
||||
void passVariadicByte(byte... arg);
|
||||
@ -263,7 +263,9 @@ interface TestExampleInterface {
|
||||
void passString(DOMString arg);
|
||||
void passNullableString(DOMString? arg);
|
||||
void passOptionalString(optional DOMString arg);
|
||||
void passOptionalUndefinedMissingString([TreatUndefinedAs=Missing] optional DOMString arg);
|
||||
void passOptionalStringWithDefaultValue(optional DOMString arg = "abc");
|
||||
void passOptionalUndefinedMissingStringWithDefaultValue([TreatUndefinedAs=Missing] optional DOMString arg = "abc");
|
||||
void passOptionalNullableString(optional DOMString? arg);
|
||||
void passOptionalNullableStringWithDefaultValue(optional DOMString? arg = null);
|
||||
void passVariadicString(DOMString... arg);
|
||||
@ -476,22 +478,6 @@ interface TestExampleInterface {
|
||||
void overload7(ByteString arg);
|
||||
void overload8(long arg);
|
||||
void overload8(TestInterface arg);
|
||||
void overload9(long? arg);
|
||||
void overload9(DOMString arg);
|
||||
void overload10(long? arg);
|
||||
void overload10(object arg);
|
||||
void overload11(long arg);
|
||||
void overload11(DOMString? arg);
|
||||
void overload12(long arg);
|
||||
void overload12(boolean? arg);
|
||||
void overload13(long? arg);
|
||||
void overload13(boolean arg);
|
||||
void overload14(optional long arg);
|
||||
void overload14(TestInterface arg);
|
||||
void overload15(long arg);
|
||||
void overload15(optional TestInterface arg);
|
||||
void overload16(long arg);
|
||||
void overload16(optional TestInterface? arg);
|
||||
|
||||
// Variadic handling
|
||||
void passVariadicThirdArg(DOMString arg1, long arg2, TestInterface... arg3);
|
||||
|
@ -35,9 +35,9 @@ interface TestJSImplInterface {
|
||||
void passByte(byte arg);
|
||||
byte receiveByte();
|
||||
void passOptionalByte(optional byte arg);
|
||||
void passOptionalByteBeforeRequired(optional byte arg1, byte arg2);
|
||||
void passOptionalUndefinedMissingByte([TreatUndefinedAs=Missing] optional byte arg);
|
||||
void passOptionalByteWithDefault(optional byte arg = 0);
|
||||
void passOptionalByteWithDefaultBeforeRequired(optional byte arg1 = 0, byte arg2);
|
||||
void passOptionalUndefinedMissingByteWithDefault([TreatUndefinedAs=Missing] optional byte arg = 0);
|
||||
void passNullableByte(byte? arg);
|
||||
void passOptionalNullableByte(optional byte? arg);
|
||||
void passVariadicByte(byte... arg);
|
||||
@ -285,7 +285,9 @@ interface TestJSImplInterface {
|
||||
void passString(DOMString arg);
|
||||
void passNullableString(DOMString? arg);
|
||||
void passOptionalString(optional DOMString arg);
|
||||
void passOptionalUndefinedMissingString([TreatUndefinedAs=Missing] optional DOMString arg);
|
||||
void passOptionalStringWithDefaultValue(optional DOMString arg = "abc");
|
||||
void passOptionalUndefinedMissingStringWithDefaultValue([TreatUndefinedAs=Missing] optional DOMString arg = "abc");
|
||||
void passOptionalNullableString(optional DOMString? arg);
|
||||
void passOptionalNullableStringWithDefaultValue(optional DOMString? arg = null);
|
||||
void passVariadicString(DOMString... arg);
|
||||
@ -504,22 +506,6 @@ interface TestJSImplInterface {
|
||||
void overload7(ByteString arg);
|
||||
void overload8(long arg);
|
||||
void overload8(TestJSImplInterface arg);
|
||||
void overload9(long? arg);
|
||||
void overload9(DOMString arg);
|
||||
void overload10(long? arg);
|
||||
void overload10(object arg);
|
||||
void overload11(long arg);
|
||||
void overload11(DOMString? arg);
|
||||
void overload12(long arg);
|
||||
void overload12(boolean? arg);
|
||||
void overload13(long? arg);
|
||||
void overload13(boolean arg);
|
||||
void overload14(optional long arg);
|
||||
void overload14(TestInterface arg);
|
||||
void overload15(long arg);
|
||||
void overload15(optional TestInterface arg);
|
||||
void overload16(long arg);
|
||||
void overload16(optional TestInterface? arg);
|
||||
|
||||
// Variadic handling
|
||||
void passVariadicThirdArg(DOMString arg1, long arg2, TestJSImplInterface... arg3);
|
||||
|
@ -989,18 +989,11 @@ BluetoothHfpManager::Connect(const nsAString& aDeviceAddress,
|
||||
return;
|
||||
}
|
||||
|
||||
mNeedsUpdatingSdpRecords = true;
|
||||
mIsHandsfree = !IS_HEADSET(aController->GetCod());
|
||||
|
||||
nsString uuid;
|
||||
if (mIsHandsfree) {
|
||||
BluetoothUuidHelper::GetString(BluetoothServiceClass::HANDSFREE, uuid);
|
||||
} else {
|
||||
BluetoothUuidHelper::GetString(BluetoothServiceClass::HEADSET, uuid);
|
||||
}
|
||||
BluetoothUuidHelper::GetString(BluetoothServiceClass::HANDSFREE, uuid);
|
||||
|
||||
if (NS_FAILED(bs->GetServiceChannel(aDeviceAddress, uuid, this))) {
|
||||
aController->OnConnect(NS_LITERAL_STRING(ERR_SERVICE_CHANNEL_NOT_FOUND));
|
||||
aController->OnConnect(NS_LITERAL_STRING(ERR_NO_AVAILABLE_RESOURCE));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1509,25 +1502,9 @@ BluetoothHfpManager::OnSocketDisconnect(BluetoothSocket* aSocket)
|
||||
void
|
||||
BluetoothHfpManager::OnUpdateSdpRecords(const nsAString& aDeviceAddress)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(!aDeviceAddress.IsEmpty());
|
||||
MOZ_ASSERT(mRunnable);
|
||||
|
||||
BluetoothService* bs = BluetoothService::Get();
|
||||
NS_ENSURE_TRUE_VOID(bs);
|
||||
|
||||
nsString uuid;
|
||||
if (mIsHandsfree) {
|
||||
BluetoothUuidHelper::GetString(BluetoothServiceClass::HANDSFREE, uuid);
|
||||
} else {
|
||||
BluetoothUuidHelper::GetString(BluetoothServiceClass::HEADSET, uuid);
|
||||
}
|
||||
|
||||
// Since we have updated SDP records of the target device, we should
|
||||
// try to get the channel of target service again.
|
||||
if (NS_FAILED(bs->GetServiceChannel(aDeviceAddress, uuid, this))) {
|
||||
OnConnect(NS_LITERAL_STRING(ERR_SERVICE_CHANNEL_NOT_FOUND));
|
||||
}
|
||||
// UpdateSdpRecord() is not called so this callback function should not
|
||||
// be invoked.
|
||||
MOZ_ASSUME_UNREACHABLE("UpdateSdpRecords() should be called somewhere");
|
||||
}
|
||||
|
||||
void
|
||||
@ -1541,14 +1518,17 @@ BluetoothHfpManager::OnGetServiceChannel(const nsAString& aDeviceAddress,
|
||||
BluetoothService* bs = BluetoothService::Get();
|
||||
NS_ENSURE_TRUE_VOID(bs);
|
||||
|
||||
BluetoothValue v;
|
||||
|
||||
if (aChannel < 0) {
|
||||
if (mNeedsUpdatingSdpRecords) {
|
||||
mNeedsUpdatingSdpRecords = false;
|
||||
bs->UpdateSdpRecords(aDeviceAddress, this);
|
||||
} else {
|
||||
// If we can't find Handsfree server channel number on the remote device,
|
||||
// try to create HSP connection instead.
|
||||
nsString hspUuid;
|
||||
BluetoothUuidHelper::GetString(BluetoothServiceClass::HEADSET, hspUuid);
|
||||
|
||||
if (aServiceUuid.Equals(hspUuid)) {
|
||||
OnConnect(NS_LITERAL_STRING(ERR_SERVICE_CHANNEL_NOT_FOUND));
|
||||
} else if (NS_FAILED(bs->GetServiceChannel(aDeviceAddress,
|
||||
hspUuid, this))) {
|
||||
OnConnect(NS_LITERAL_STRING(ERR_NO_AVAILABLE_RESOURCE));
|
||||
}
|
||||
|
||||
return;
|
||||
|
@ -147,8 +147,6 @@ private:
|
||||
int mNetworkSelectionMode;
|
||||
bool mReceiveVgsFlag;
|
||||
bool mDialingRequestProcessed;
|
||||
bool mIsHandsfree;
|
||||
bool mNeedsUpdatingSdpRecords;
|
||||
nsString mDeviceAddress;
|
||||
nsString mMsisdn;
|
||||
nsString mOperatorName;
|
||||
|
@ -46,11 +46,6 @@ BEGIN_BLUETOOTH_NAMESPACE
|
||||
// Major device class = 0xA, Peripheral
|
||||
#define IS_PERIPHERAL(cod) (GET_MAJOR_DEVICE_CLASS(cod) == 0xa)
|
||||
|
||||
// Major device class = 0x4, Audio/Video
|
||||
// Minor device class = 0x1, Wearable Headset device
|
||||
#define IS_HEADSET(cod) ((GET_MAJOR_DEVICE_CLASS(cod) == 0x4) && \
|
||||
(GET_MINOR_DEVICE_CLASS(cod) == 0x1))
|
||||
|
||||
class BluetoothProfileManagerBase;
|
||||
class BluetoothReplyRunnable;
|
||||
typedef void (*BluetoothProfileControllerCallback)();
|
||||
|
@ -18,21 +18,17 @@ function checkDoc(title, expectedtitle, normalizedtitle) {
|
||||
assert_equals(doc.doctype.systemId, "")
|
||||
assert_equals(doc.documentElement.localName, "html")
|
||||
assert_equals(doc.documentElement.firstChild.localName, "head")
|
||||
if (title !== undefined) {
|
||||
assert_equals(doc.documentElement.firstChild.childNodes.length, 1)
|
||||
assert_equals(doc.documentElement.firstChild.firstChild.localName, "title")
|
||||
assert_equals(doc.documentElement.firstChild.firstChild.firstChild.data,
|
||||
expectedtitle)
|
||||
} else {
|
||||
assert_equals(doc.documentElement.firstChild.childNodes.length, 0)
|
||||
}
|
||||
assert_equals(doc.documentElement.firstChild.childNodes.length, 1)
|
||||
assert_equals(doc.documentElement.firstChild.firstChild.localName, "title")
|
||||
assert_equals(doc.documentElement.firstChild.firstChild.firstChild.data,
|
||||
expectedtitle)
|
||||
assert_equals(doc.documentElement.lastChild.localName, "body")
|
||||
assert_equals(doc.documentElement.lastChild.childNodes.length, 0)
|
||||
})
|
||||
}
|
||||
checkDoc("", "", "")
|
||||
checkDoc(null, "null", "null")
|
||||
checkDoc(undefined, "", "")
|
||||
checkDoc(undefined, "undefined", "undefined")
|
||||
checkDoc("foo bar baz", "foo bar baz", "foo bar baz")
|
||||
checkDoc("foo\t\tbar baz", "foo\t\tbar baz", "foo bar baz")
|
||||
checkDoc("foo\n\nbar baz", "foo\n\nbar baz", "foo bar baz")
|
||||
|
@ -12,7 +12,7 @@ function checkDoc(title, expectedtitle, normalizedtitle) {
|
||||
}
|
||||
checkDoc("", "", "")
|
||||
checkDoc(null, "null", "null")
|
||||
checkDoc(undefined, "", "")
|
||||
checkDoc(undefined, "undefined", "undefined")
|
||||
checkDoc("foo bar baz", "foo bar baz", "foo bar baz")
|
||||
checkDoc("foo\t\tbar baz", "foo\t\tbar baz", "foo bar baz")
|
||||
checkDoc("foo\n\nbar baz", "foo\n\nbar baz", "foo bar baz")
|
||||
|
@ -2802,7 +2802,7 @@ QuotaManager::FindSynchronizedOp(const nsACString& aPattern,
|
||||
for (uint32_t index = 0; index < mSynchronizedOps.Length(); index++) {
|
||||
const nsAutoPtr<SynchronizedOp>& currentOp = mSynchronizedOps[index];
|
||||
if (PatternMatchesOrigin(aPattern, currentOp->mOriginOrPattern) &&
|
||||
(currentOp->mPersistenceType.IsNull() ||
|
||||
(!currentOp->mPersistenceType ||
|
||||
currentOp->mPersistenceType == aPersistenceType) &&
|
||||
(!currentOp->mId || currentOp->mId == aId)) {
|
||||
return currentOp;
|
||||
@ -3067,7 +3067,7 @@ QuotaManager::CollectOriginsForEviction(uint64_t aMinSizeToBeFreed,
|
||||
uint32_t index;
|
||||
for (index = 0; index < mSynchronizedOps.Length(); index++) {
|
||||
nsAutoPtr<SynchronizedOp>& op = mSynchronizedOps[index];
|
||||
if (op->mPersistenceType.IsNull() ||
|
||||
if (!op->mPersistenceType ||
|
||||
op->mPersistenceType.Value() == PERSISTENCE_TYPE_TEMPORARY) {
|
||||
if (op->mOriginOrPattern.IsPattern() &&
|
||||
!originCollection.ContainsPattern(op->mOriginOrPattern)) {
|
||||
@ -3078,7 +3078,7 @@ QuotaManager::CollectOriginsForEviction(uint64_t aMinSizeToBeFreed,
|
||||
|
||||
for (index = 0; index < mSynchronizedOps.Length(); index++) {
|
||||
nsAutoPtr<SynchronizedOp>& op = mSynchronizedOps[index];
|
||||
if (op->mPersistenceType.IsNull() ||
|
||||
if (!op->mPersistenceType ||
|
||||
op->mPersistenceType.Value() == PERSISTENCE_TYPE_TEMPORARY) {
|
||||
if (op->mOriginOrPattern.IsOrigin() &&
|
||||
!originCollection.ContainsOrigin(op->mOriginOrPattern)) {
|
||||
|
@ -138,7 +138,8 @@ public:
|
||||
static_cast<AudioManager *>(audioManager.get())->SetStreamVolumeIndex(
|
||||
AUDIO_STREAM_BLUETOOTH_SCO, volIndex);
|
||||
} else {
|
||||
MOZ_ASSUME_UNREACHABLE("unexpected audio channel for volume control");
|
||||
MOZ_ASSUME_UNREACHABLE("unexpected audio channel for initializing "
|
||||
"volume control");
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
@ -314,7 +315,7 @@ AudioManager::Observe(nsISupports* aSubject,
|
||||
return NS_OK;
|
||||
}
|
||||
nsDependentJSString keyStr;
|
||||
if (!keyStr.init(cx, jsKey) || keyStr.EqualsLiteral("audio.volume.bt_sco")) {
|
||||
if (!keyStr.init(cx, jsKey) || !keyStr.EqualsLiteral("audio.volume.bt_sco")) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -31,6 +31,7 @@
|
||||
#include "AudioManager.h"
|
||||
#endif
|
||||
#include "mozilla/ipc/Ril.h"
|
||||
#include "mozilla/ipc/KeyStore.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "nsCxPusher.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
@ -341,6 +342,8 @@ SystemWorkerManager::Init()
|
||||
return rv;
|
||||
}
|
||||
|
||||
InitKeyStore(cx);
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
InitAutoMounter();
|
||||
InitializeTimeZoneSettingObserver();
|
||||
@ -545,6 +548,13 @@ SystemWorkerManager::InitWifi(JSContext *cx)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
SystemWorkerManager::InitKeyStore(JSContext *cx)
|
||||
{
|
||||
mKeyStore = new KeyStore();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS3(SystemWorkerManager,
|
||||
nsIObserver,
|
||||
nsIInterfaceRequestor,
|
||||
|
@ -35,6 +35,7 @@ namespace mozilla {
|
||||
namespace ipc {
|
||||
class RilConsumer;
|
||||
class UnixSocketRawData;
|
||||
class KeyStore;
|
||||
}
|
||||
|
||||
namespace dom {
|
||||
@ -70,6 +71,7 @@ private:
|
||||
nsresult InitNetd(JSContext *cx);
|
||||
#endif
|
||||
nsresult InitWifi(JSContext *cx);
|
||||
nsresult InitKeyStore(JSContext *cx);
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
nsCOMPtr<nsIWorkerHolder> mNetdWorker;
|
||||
@ -77,6 +79,7 @@ private:
|
||||
nsCOMPtr<nsIWorkerHolder> mWifiWorker;
|
||||
|
||||
nsTArray<nsRefPtr<ipc::RilConsumer> > mRilConsumers;
|
||||
nsRefPtr<ipc::KeyStore> mKeyStore;
|
||||
|
||||
bool mShutdown;
|
||||
};
|
||||
|
@ -7,3 +7,4 @@ qemu = true
|
||||
disabled = Bug 808783
|
||||
[test_fakevolume.js]
|
||||
[test_ril_code_quality.py]
|
||||
[test_screen_state.js]
|
||||
|
@ -74,7 +74,7 @@ interface CanvasRenderingContext2D {
|
||||
|
||||
// path API (see also CanvasPathMethods)
|
||||
void beginPath();
|
||||
void fill(optional CanvasWindingRule winding = "nonzero");
|
||||
void fill([TreatUndefinedAs=Missing] optional CanvasWindingRule winding = "nonzero");
|
||||
// NOT IMPLEMENTED void fill(Path path);
|
||||
void stroke();
|
||||
// NOT IMPLEMENTED void stroke(Path path);
|
||||
@ -84,10 +84,10 @@ interface CanvasRenderingContext2D {
|
||||
// NOT IMPLEMENTED boolean drawCustomFocusRing(Path path, Element element);
|
||||
// NOT IMPLEMENTED void scrollPathIntoView();
|
||||
// NOT IMPLEMENTED void scrollPathIntoView(Path path);
|
||||
void clip(optional CanvasWindingRule winding = "nonzero");
|
||||
void clip([TreatUndefinedAs=Missing] optional CanvasWindingRule winding = "nonzero");
|
||||
// NOT IMPLEMENTED void clip(Path path);
|
||||
// NOT IMPLEMENTED void resetClip();
|
||||
boolean isPointInPath(unrestricted double x, unrestricted double y, optional CanvasWindingRule winding = "nonzero");
|
||||
boolean isPointInPath(unrestricted double x, unrestricted double y, [TreatUndefinedAs=Missing] optional CanvasWindingRule winding = "nonzero");
|
||||
// NOT IMPLEMENTED boolean isPointInPath(Path path, unrestricted double x, unrestricted double y);
|
||||
boolean isPointInStroke(double x, double y);
|
||||
|
||||
|
@ -28,9 +28,9 @@ interface Promise {
|
||||
static Promise reject(any value);
|
||||
|
||||
[Creator]
|
||||
Promise then(optional AnyCallback fulfillCallback,
|
||||
optional AnyCallback rejectCallback);
|
||||
Promise then([TreatUndefinedAs=Missing] optional AnyCallback fulfillCallback,
|
||||
[TreatUndefinedAs=Missing] optional AnyCallback rejectCallback);
|
||||
|
||||
[Creator]
|
||||
Promise catch(optional AnyCallback rejectCallback);
|
||||
Promise catch([TreatUndefinedAs=Missing] optional AnyCallback rejectCallback);
|
||||
};
|
||||
|
@ -71,9 +71,7 @@ interface XMLHttpRequest : XMLHttpRequestEventTarget {
|
||||
|
||||
// request
|
||||
[Throws]
|
||||
void open(ByteString method, DOMString url);
|
||||
[Throws]
|
||||
void open(ByteString method, DOMString url, boolean async,
|
||||
void open(ByteString method, DOMString url, optional boolean async = true,
|
||||
optional DOMString? user, optional DOMString? password);
|
||||
[Throws]
|
||||
void setRequestHeader(ByteString header, ByteString value);
|
||||
|
@ -121,11 +121,6 @@ public:
|
||||
return mStateData.mReadyState;
|
||||
}
|
||||
|
||||
void Open(const nsACString& aMethod, const nsAString& aUrl, ErrorResult& aRv)
|
||||
{
|
||||
Open(aMethod, aUrl, true, Optional<nsAString>(),
|
||||
Optional<nsAString>(), aRv);
|
||||
}
|
||||
void
|
||||
Open(const nsACString& aMethod, const nsAString& aUrl, bool aAsync,
|
||||
const Optional<nsAString>& aUser, const Optional<nsAString>& aPassword,
|
||||
|
381
ipc/keystore/KeyStore.cpp
Normal file
381
ipc/keystore/KeyStore.cpp
Normal file
@ -0,0 +1,381 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* vim: set sw=4 ts=8 et ft=cpp: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#undef LOG
|
||||
#if defined(MOZ_WIDGET_GONK)
|
||||
#include <android/log.h>
|
||||
#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "Gonk", args)
|
||||
#else
|
||||
#define LOG(args...) printf(args);
|
||||
#endif
|
||||
|
||||
#include "KeyStore.h"
|
||||
#include "jsfriendapi.h"
|
||||
#include "MainThreadUtils.h" // For NS_IsMainThread.
|
||||
|
||||
#include "plbase64.h"
|
||||
#include "certdb.h"
|
||||
|
||||
using namespace mozilla::ipc;
|
||||
|
||||
namespace mozilla {
|
||||
namespace ipc {
|
||||
|
||||
static const char* KEYSTORE_SOCKET_NAME = "keystore";
|
||||
static const char* KEYSTORE_SOCKET_PATH = "/dev/socket/keystore";
|
||||
|
||||
int
|
||||
KeyStoreConnector::Create()
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
|
||||
int fd;
|
||||
|
||||
unlink(KEYSTORE_SOCKET_PATH);
|
||||
|
||||
fd = socket(AF_LOCAL, SOCK_STREAM, 0);
|
||||
|
||||
if (fd < 0) {
|
||||
NS_WARNING("Could not open keystore socket!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Allow access of wpa_supplicant(different user, differnt group)
|
||||
chmod(KEYSTORE_SOCKET_PATH, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
bool
|
||||
KeyStoreConnector::CreateAddr(bool aIsServer,
|
||||
socklen_t& aAddrSize,
|
||||
sockaddr_any& aAddr,
|
||||
const char* aAddress)
|
||||
{
|
||||
// Keystore socket must be server
|
||||
MOZ_ASSERT(aIsServer);
|
||||
|
||||
aAddr.un.sun_family = AF_LOCAL;
|
||||
if(strlen(KEYSTORE_SOCKET_PATH) > sizeof(aAddr.un.sun_path)) {
|
||||
NS_WARNING("Address too long for socket struct!");
|
||||
return false;
|
||||
}
|
||||
strcpy((char*)&aAddr.un.sun_path, KEYSTORE_SOCKET_PATH);
|
||||
aAddrSize = strlen(KEYSTORE_SOCKET_PATH) + offsetof(struct sockaddr_un, sun_path) + 1;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
KeyStoreConnector::SetUp(int aFd)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
KeyStoreConnector::GetSocketAddr(const sockaddr_any& aAddr,
|
||||
nsAString& aAddrStr)
|
||||
{
|
||||
// Unused.
|
||||
MOZ_CRASH("This should never be called!");
|
||||
}
|
||||
|
||||
static char *
|
||||
get_cert_db_filename(void *arg, int vers)
|
||||
{
|
||||
static char keystoreDbPath[] = "/data/misc/wifi/keystore";
|
||||
return keystoreDbPath;
|
||||
}
|
||||
|
||||
KeyStore::KeyStore()
|
||||
{
|
||||
// Initial NSS
|
||||
certdb = CERT_GetDefaultCertDB();
|
||||
|
||||
Listen();
|
||||
}
|
||||
|
||||
void
|
||||
KeyStore::Shutdown()
|
||||
{
|
||||
mShutdown = true;
|
||||
CloseSocket();
|
||||
}
|
||||
|
||||
void
|
||||
KeyStore::Listen()
|
||||
{
|
||||
ListenSocket(new KeyStoreConnector());
|
||||
|
||||
ResetHandlerInfo();
|
||||
}
|
||||
|
||||
void
|
||||
KeyStore::ResetHandlerInfo()
|
||||
{
|
||||
mHandlerInfo.state = STATE_IDLE;
|
||||
mHandlerInfo.command = 0;
|
||||
mHandlerInfo.paramCount = 0;
|
||||
mHandlerInfo.commandPattern = NULL;
|
||||
for (int i = 0; i < MAX_PARAM; i++) {
|
||||
mHandlerInfo.param[i].length = 0;
|
||||
memset(mHandlerInfo.param[i].data, 0, VALUE_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
KeyStore::CheckSize(UnixSocketRawData *aMessage, size_t aExpectSize)
|
||||
{
|
||||
return (aMessage->mSize - aMessage->mCurrentWriteOffset >= aExpectSize) ?
|
||||
true : false;
|
||||
}
|
||||
|
||||
bool
|
||||
KeyStore::ReadCommand(UnixSocketRawData *aMessage)
|
||||
{
|
||||
if (mHandlerInfo.state != STATE_IDLE) {
|
||||
NS_WARNING("Wrong state in ReadCommand()!");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!CheckSize(aMessage, 1)) {
|
||||
NS_WARNING("Data size error in ReadCommand()!");
|
||||
return false;
|
||||
}
|
||||
|
||||
mHandlerInfo.command = aMessage->mData[aMessage->mCurrentWriteOffset];
|
||||
aMessage->mCurrentWriteOffset++;
|
||||
|
||||
// Find corrsponding command pattern
|
||||
const struct ProtocolCommand *command = commands;
|
||||
while (command->command && command->command != mHandlerInfo.command) {
|
||||
command++;
|
||||
}
|
||||
|
||||
if (!command->command) {
|
||||
NS_WARNING("Unsupported command!");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get command pattern.
|
||||
mHandlerInfo.commandPattern = command;
|
||||
if (command->paramNum) {
|
||||
// Read command parameter if needed.
|
||||
mHandlerInfo.state = STATE_READ_PARAM_LEN;
|
||||
} else {
|
||||
mHandlerInfo.state = STATE_PROCESSING;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
KeyStore::ReadLength(UnixSocketRawData *aMessage)
|
||||
{
|
||||
if (mHandlerInfo.state != STATE_READ_PARAM_LEN) {
|
||||
NS_WARNING("Wrong state in ReadLength()!");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!CheckSize(aMessage, 2)) {
|
||||
NS_WARNING("Data size error in ReadLength()!");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read length of command parameter.
|
||||
unsigned short dataLength;
|
||||
memcpy(&dataLength, &aMessage->mData[aMessage->mCurrentWriteOffset], 2);
|
||||
aMessage->mCurrentWriteOffset += 2;
|
||||
mHandlerInfo.param[mHandlerInfo.paramCount].length = ntohs(dataLength);
|
||||
|
||||
mHandlerInfo.state = STATE_READ_PARAM_DATA;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
KeyStore::ReadData(UnixSocketRawData *aMessage)
|
||||
{
|
||||
if (mHandlerInfo.state != STATE_READ_PARAM_DATA) {
|
||||
NS_WARNING("Wrong state in ReadData()!");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!CheckSize(aMessage, mHandlerInfo.param[mHandlerInfo.paramCount].length)) {
|
||||
NS_WARNING("Data size error in ReadData()!");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read command parameter.
|
||||
memcpy(mHandlerInfo.param[mHandlerInfo.paramCount].data,
|
||||
&aMessage->mData[aMessage->mCurrentWriteOffset],
|
||||
mHandlerInfo.param[mHandlerInfo.paramCount].length);
|
||||
aMessage->mCurrentWriteOffset += mHandlerInfo.param[mHandlerInfo.paramCount].length;
|
||||
mHandlerInfo.paramCount++;
|
||||
|
||||
if (mHandlerInfo.paramCount == mHandlerInfo.commandPattern->paramNum) {
|
||||
mHandlerInfo.state = STATE_PROCESSING;
|
||||
} else {
|
||||
mHandlerInfo.state = STATE_READ_PARAM_LEN;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Transform base64 certification data into DER format
|
||||
void
|
||||
KeyStore::FormatCaData(const uint8_t *aCaData, int aCaDataLength,
|
||||
const char *aName, const uint8_t **aFormatData,
|
||||
int &aFormatDataLength)
|
||||
{
|
||||
int bufSize = strlen(CA_BEGIN) + strlen(CA_END) + strlen(CA_TAILER) * 2 +
|
||||
strlen(aName) * 2 + aCaDataLength + aCaDataLength/CA_LINE_SIZE + 2;
|
||||
char *buf = (char *)malloc(bufSize);
|
||||
|
||||
aFormatDataLength = bufSize;
|
||||
*aFormatData = (const uint8_t *)buf;
|
||||
|
||||
char *ptr = buf;
|
||||
int len;
|
||||
|
||||
// Create DER header.
|
||||
len = snprintf(ptr, bufSize, "%s%s%s", CA_BEGIN, aName, CA_TAILER);
|
||||
ptr += len;
|
||||
bufSize -= len;
|
||||
|
||||
// Split base64 data in lines.
|
||||
int copySize;
|
||||
while (aCaDataLength > 0) {
|
||||
copySize = (aCaDataLength > CA_LINE_SIZE) ? CA_LINE_SIZE : aCaDataLength;
|
||||
|
||||
memcpy(ptr, aCaData, copySize);
|
||||
ptr += copySize;
|
||||
aCaData += copySize;
|
||||
aCaDataLength -= copySize;
|
||||
bufSize -= copySize;
|
||||
|
||||
*ptr = '\n';
|
||||
ptr++;
|
||||
bufSize--;
|
||||
}
|
||||
|
||||
// Create DEA tailer.
|
||||
snprintf(ptr, bufSize, "%s%s%s", CA_END, aName, CA_TAILER);
|
||||
}
|
||||
|
||||
// Status response
|
||||
void
|
||||
KeyStore::SendResponse(ResponseCode aResponse)
|
||||
{
|
||||
if (aResponse == NO_RESPONSE)
|
||||
return;
|
||||
|
||||
uint8_t response = (uint8_t)aResponse;
|
||||
UnixSocketRawData* data = new UnixSocketRawData((const void *)&response, 1);
|
||||
SendSocketData(data);
|
||||
}
|
||||
|
||||
// Data response
|
||||
void
|
||||
KeyStore::SendData(const uint8_t *aData, int aLength)
|
||||
{
|
||||
unsigned short dataLength = htons(aLength);
|
||||
|
||||
UnixSocketRawData* length = new UnixSocketRawData((const void *)&dataLength, 2);
|
||||
SendSocketData(length);
|
||||
|
||||
UnixSocketRawData* data = new UnixSocketRawData((const void *)aData, aLength);
|
||||
SendSocketData(data);
|
||||
}
|
||||
|
||||
void
|
||||
KeyStore::ReceiveSocketData(nsAutoPtr<UnixSocketRawData>& aMessage)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
bool success = true;
|
||||
while (aMessage->mCurrentWriteOffset < aMessage->mSize ||
|
||||
mHandlerInfo.state == STATE_PROCESSING) {
|
||||
switch (mHandlerInfo.state) {
|
||||
case STATE_IDLE:
|
||||
success = ReadCommand(aMessage);
|
||||
break;
|
||||
case STATE_READ_PARAM_LEN:
|
||||
success = ReadLength(aMessage);
|
||||
break;
|
||||
case STATE_READ_PARAM_DATA:
|
||||
success = ReadData(aMessage);
|
||||
break;
|
||||
case STATE_PROCESSING:
|
||||
success = false;
|
||||
if (mHandlerInfo.command == 'g') {
|
||||
// Get CA
|
||||
const uint8_t *certData;
|
||||
int certDataLength;
|
||||
const char *certName = (const char *)mHandlerInfo.param[0].data;
|
||||
|
||||
// Get cert from NSS by name
|
||||
CERTCertificate *cert = CERT_FindCertByNickname(certdb, certName);
|
||||
if (!cert) {
|
||||
break;
|
||||
}
|
||||
|
||||
char *certDER = PL_Base64Encode((const char *)cert->derCert.data,
|
||||
cert->derCert.len, nullptr);
|
||||
if (!certDER) {
|
||||
break;
|
||||
}
|
||||
|
||||
FormatCaData((const uint8_t *)certDER, strlen(certDER), "CERTIFICATE",
|
||||
&certData, certDataLength);
|
||||
PL_strfree(certDER);
|
||||
|
||||
SendResponse(SUCCESS);
|
||||
SendData(certData, certDataLength);
|
||||
success = true;
|
||||
|
||||
free((void *)certData);
|
||||
}
|
||||
|
||||
ResetHandlerInfo();
|
||||
break;
|
||||
}
|
||||
|
||||
if (!success) {
|
||||
SendResponse(PROTOCOL_ERROR);
|
||||
ResetHandlerInfo();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
KeyStore::OnConnectSuccess()
|
||||
{
|
||||
mShutdown = false;
|
||||
}
|
||||
|
||||
void
|
||||
KeyStore::OnConnectError()
|
||||
{
|
||||
if (!mShutdown) {
|
||||
Listen();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
KeyStore::OnDisconnect()
|
||||
{
|
||||
if (!mShutdown) {
|
||||
Listen();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ipc
|
||||
} // namespace mozilla
|
131
ipc/keystore/KeyStore.h
Normal file
131
ipc/keystore/KeyStore.h
Normal file
@ -0,0 +1,131 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set sw=2 ts=8 et ft=cpp: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_ipc_KeyStore_h
|
||||
#define mozilla_ipc_KeyStore_h 1
|
||||
|
||||
#include "mozilla/ipc/UnixSocket.h"
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
|
||||
#include "cert.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace ipc {
|
||||
|
||||
enum ResponseCode {
|
||||
SUCCESS = 1,
|
||||
LOCKED = 2,
|
||||
UNINITIALIZED = 3,
|
||||
SYSTEM_ERROR = 4,
|
||||
PROTOCOL_ERROR = 5,
|
||||
PERMISSION_DENIED = 6,
|
||||
KEY_NOT_FOUND = 7,
|
||||
VALUE_CORRUPTED = 8,
|
||||
UNDEFINED_ACTION = 9,
|
||||
WRONG_PASSWORD_0 = 10,
|
||||
WRONG_PASSWORD_1 = 11,
|
||||
WRONG_PASSWORD_2 = 12,
|
||||
WRONG_PASSWORD_3 = 13, // MAX_RETRY = 4
|
||||
NO_RESPONSE
|
||||
};
|
||||
|
||||
static const int MAX_PARAM = 2;
|
||||
static const int KEY_SIZE = ((NAME_MAX - 15) / 2);
|
||||
static const int VALUE_SIZE = 32768;
|
||||
static const int PASSWORD_SIZE = VALUE_SIZE;
|
||||
|
||||
static const char *CA_BEGIN = "-----BEGIN ",
|
||||
*CA_END = "-----END ",
|
||||
*CA_TAILER = "-----\n";
|
||||
static const int CA_LINE_SIZE = 64;
|
||||
|
||||
struct ProtocolCommand {
|
||||
int8_t command;
|
||||
int paramNum;
|
||||
};
|
||||
|
||||
static const struct ProtocolCommand commands[] = {
|
||||
{'g', 1}, // Get CA, command "g CERT_NAME"
|
||||
{ 0, 0}
|
||||
};
|
||||
|
||||
struct ProtocolParam{
|
||||
uint length;
|
||||
int8_t data[VALUE_SIZE];
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
STATE_IDLE,
|
||||
STATE_READ_PARAM_LEN,
|
||||
STATE_READ_PARAM_DATA,
|
||||
STATE_PROCESSING
|
||||
} ProtocolHandlerState;
|
||||
|
||||
class KeyStoreConnector : public mozilla::ipc::UnixSocketConnector
|
||||
{
|
||||
public:
|
||||
KeyStoreConnector()
|
||||
{}
|
||||
|
||||
virtual ~KeyStoreConnector()
|
||||
{}
|
||||
|
||||
virtual int Create();
|
||||
virtual bool CreateAddr(bool aIsServer,
|
||||
socklen_t& aAddrSize,
|
||||
sockaddr_any& aAddr,
|
||||
const char* aAddress);
|
||||
virtual bool SetUp(int aFd);
|
||||
virtual void GetSocketAddr(const sockaddr_any& aAddr,
|
||||
nsAString& aAddrStr);
|
||||
};
|
||||
|
||||
class KeyStore : public mozilla::ipc::UnixSocketConsumer
|
||||
{
|
||||
public:
|
||||
KeyStore();
|
||||
virtual ~KeyStore() {}
|
||||
|
||||
void Shutdown();
|
||||
|
||||
private:
|
||||
virtual void ReceiveSocketData(nsAutoPtr<UnixSocketRawData>& aMessage);
|
||||
|
||||
virtual void OnConnectSuccess();
|
||||
virtual void OnConnectError();
|
||||
virtual void OnDisconnect();
|
||||
|
||||
private:
|
||||
struct {
|
||||
ProtocolHandlerState state;
|
||||
uint8_t command;
|
||||
struct ProtocolParam param[MAX_PARAM];
|
||||
int paramCount;
|
||||
const struct ProtocolCommand *commandPattern;
|
||||
} mHandlerInfo;
|
||||
void ResetHandlerInfo();
|
||||
void Listen();
|
||||
|
||||
void FormatCaData(const uint8_t *caData, int caDataLength, const char *name,
|
||||
const uint8_t **formatData, int &formatDataLength);
|
||||
|
||||
bool CheckSize(UnixSocketRawData *aMessage, size_t aExpectSize);
|
||||
bool ReadCommand(UnixSocketRawData *aMessage);
|
||||
bool ReadLength(UnixSocketRawData *aMessage);
|
||||
bool ReadData(UnixSocketRawData *aMessage);
|
||||
void SendResponse(ResponseCode response);
|
||||
void SendData(const uint8_t *data, int length);
|
||||
|
||||
bool mShutdown;
|
||||
|
||||
CERTCertDBHandle *certdb;
|
||||
};
|
||||
|
||||
} // namespace ipc
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_ipc_KeyStore_h
|
7
ipc/keystore/Makefile.in
Normal file
7
ipc/keystore/Makefile.in
Normal file
@ -0,0 +1,7 @@
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
EXPORT_LIBRARY = 1
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
include $(topsrcdir)/ipc/chromium/chromium-config.mk
|
21
ipc/keystore/moz.build
Normal file
21
ipc/keystore/moz.build
Normal file
@ -0,0 +1,21 @@
|
||||
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
MODULE = 'ipc'
|
||||
|
||||
EXPORTS.mozilla.ipc += [
|
||||
'KeyStore.h'
|
||||
]
|
||||
|
||||
CPP_SOURCES += [
|
||||
'KeyStore.cpp'
|
||||
]
|
||||
|
||||
FAIL_ON_WARNINGS = True
|
||||
|
||||
LIBXUL_LIBRARY = True
|
||||
|
||||
LIBRARY_NAME = 'mozkeystore_s'
|
@ -18,7 +18,7 @@ if CONFIG['MOZ_B2G_BT']:
|
||||
DIRS += ['dbus']
|
||||
|
||||
if CONFIG['MOZ_B2G_RIL'] or CONFIG['MOZ_B2G_BT']:
|
||||
DIRS += ['unixsocket']
|
||||
DIRS += ['unixsocket', 'keystore']
|
||||
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
|
||||
DIRS += ['netd']
|
||||
|
@ -52,7 +52,7 @@ function run_test()
|
||||
// Test sync XHR sending
|
||||
cu.evalInSandbox('var createXHR = ' + createXHR.toString(), sb);
|
||||
var res = cu.evalInSandbox('var sync = createXHR("4444/simple"); sync.send(null); sync', sb);
|
||||
do_check_true(checkResults(res));
|
||||
checkResults(res);
|
||||
|
||||
// negative test sync XHR sending (to ensure that the xhr do not have chrome caps, see bug 779821)
|
||||
try {
|
||||
|
@ -97,7 +97,7 @@ endif
|
||||
endif #}
|
||||
|
||||
ifneq ($(strip $(MOZ_B2G_RIL)$(MOZ_B2G_BT)),) #{
|
||||
STATIC_LIBS += mozipcunixsocket_s
|
||||
STATIC_LIBS += mozipcunixsocket_s mozkeystore_s
|
||||
endif #}
|
||||
|
||||
ifeq (gonk,$(MOZ_WIDGET_TOOLKIT))
|
||||
|
Loading…
Reference in New Issue
Block a user