/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is mozilla.org code. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 2001 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Vidur Apparao (vidur@netscape.com) (Original author) * John Bandhauer (jband@netscape.com) * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #include "wspprivate.h" #include "nsAutoPtr.h" #include "nsIWSDL.h" #include "nsIWSDLSOAPBinding.h" #include "nsISchema.h" #include "nsISOAPParameter.h" #include "nsISOAPHeaderBlock.h" #include "nsISOAPEncoding.h" #include "nsIComponentManager.h" #include "nsIVariant.h" #include "nsVoidArray.h" #define NS_SOAP_1_1_ENCODING_NAMESPACE \ "http://schemas.xmlsoap.org/soap/encoding/" #define NS_SOAP_1_2_ENCODING_NAMESPACE \ "http://www.w3.org/2001/09/soap-encoding" WSPProxy::WSPProxy() : mIID(nsnull) { } WSPProxy::~WSPProxy() { } NS_IMETHODIMP WSPProxy::Init(nsIWSDLPort* aPort, nsIInterfaceInfo* aPrimaryInterface, nsIInterfaceInfoManager* aInterfaceInfoManager, const nsAString& aQualifier, PRBool aIsAsync) { NS_ENSURE_ARG(aPort); NS_ENSURE_ARG(aPrimaryInterface); mPort = aPort; mPrimaryInterface = aPrimaryInterface; mInterfaceInfoManager = aInterfaceInfoManager; mPrimaryInterface->GetIIDShared(&mIID); mQualifier.Assign(aQualifier); mIsAsync = aIsAsync; nsresult rv; rv = InitStub(*mIID); if (NS_FAILED(rv)) return rv; mInterfaces = do_CreateInstance(NS_SCRIPTABLE_INTERFACES_CONTRACTID, &rv); if (!mInterfaces) { return rv; } rv = mInterfaces->SetManager(mInterfaceInfoManager); if (NS_FAILED(rv)) { return rv; } if (mIsAsync) { // Get the completion method info const nsXPTMethodInfo* listenerGetter; rv = mPrimaryInterface->GetMethodInfo(3, &listenerGetter); if (NS_FAILED(rv)) { return NS_ERROR_FAILURE; } const nsXPTParamInfo& listenerParam = listenerGetter->GetParam(0); const nsXPTType& type = listenerParam.GetType(); if (!type.IsInterfacePointer()) { return NS_ERROR_FAILURE; } rv = mPrimaryInterface->GetInfoForParam(3, &listenerParam, getter_AddRefs(mListenerInterfaceInfo)); if (NS_FAILED(rv)) { return rv; } } return NS_OK; } NS_METHOD WSPProxy::Create(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr) { NS_ENSURE_ARG_POINTER(aInstancePtr); NS_ENSURE_NO_AGGREGATION(outer); WSPProxy* proxy = new WSPProxy(); if (!proxy) { return NS_ERROR_OUT_OF_MEMORY; } NS_ADDREF(proxy); nsresult rv = proxy->QueryInterface(aIID, aInstancePtr); NS_RELEASE(proxy); return rv; } NS_IMPL_ADDREF(WSPProxy) NS_IMPL_RELEASE(WSPProxy) NS_IMETHODIMP WSPProxy::QueryInterface(REFNSIID aIID, void** aInstancePtr) { if (aIID.Equals(NS_GET_IID(nsISupports))) { *aInstancePtr = static_cast(this); NS_ADDREF_THIS(); return NS_OK; } if(mXPTCStub && mIID && aIID.Equals(*mIID)) { *aInstancePtr = mXPTCStub; NS_ADDREF_THIS(); return NS_OK; } else if (aIID.Equals(NS_GET_IID(nsIWebServiceProxy))) { *aInstancePtr = static_cast(this); NS_ADDREF_THIS(); return NS_OK; } else if (aIID.Equals(NS_GET_IID(nsIClassInfo))) { *aInstancePtr = static_cast(this); NS_ADDREF_THIS(); return NS_OK; } return NS_ERROR_NO_INTERFACE; } /////////////////////////////////////////////////// // // Implementation of nsXPTCStubBase methods // /////////////////////////////////////////////////// /** * Asynchronous processing : * 1-> WSPProxy::CallMethod * 2 -> WSPCallContext::CallAsync * 3 -> nsSOAPCall::AsyncInvoke * 4 -> nsXXXSOAPTransport::AsyncCall * 5 -> nsIXMLHttpRequest::Send, nsXXXSOAPTransportCompletion::AddEventListener * ---- asynchronous ---- * 6 -> nsXXXSOAPTransportCompletion::HandleEvent * 7 -> WSPCallContext::HandleResponse, * WSPCallContext::CallCompletionListener * 8 -> nsSOAPBlock::SetSchemaType, nsSOAPBlock::GetValue * 9 -> nsSOAPEncoding::Decode, nsDefaultSOAPDecode::Decode * 10 -> WSPProxy::CallCompleted */ NS_IMETHODIMP WSPProxy::CallMethod(PRUint16 methodIndex, const XPTMethodDescriptor* info, nsXPTCMiniVariant* params) { nsresult rv; nsCOMPtr cc; nsCOMPtr binding; if (methodIndex < 3) { NS_ERROR("WSPProxy: bad method index"); return NS_ERROR_FAILURE; } // The first method in the interface for async callers is the // one to set the async listener if (mIsAsync && (methodIndex == 3)) { nsISupports* listener = static_cast(params[0].val.p); mAsyncListener = listener; return NS_OK; } PRUint32 methodOffset; if (mIsAsync) { methodOffset = 4; } else { methodOffset = 3; } nsCOMPtr operation; rv = mPort->GetOperation(methodIndex - methodOffset, getter_AddRefs(operation)); if (NS_FAILED(rv)) { return rv; } nsCOMPtr input; rv = operation->GetInput(getter_AddRefs(input)); if (NS_FAILED(rv)) { return rv; } // Create the call instance nsCOMPtr call = do_CreateInstance(NS_SOAPCALL_CONTRACTID, &rv); if (NS_FAILED(rv)) { return rv; } nsCOMPtr encoding = do_CreateInstance(NS_SOAPENCODING_CONTRACTID, &rv); if (NS_FAILED(rv)) { return rv; } call->SetEncoding(encoding); // Get the method name and target object uri nsAutoString methodName, targetObjectURI; rv = operation->GetBinding(getter_AddRefs(binding)); if (NS_FAILED(rv)) { return rv; } nsCOMPtr operationBinding = do_QueryInterface(binding, &rv); if (NS_FAILED(rv)) { return rv; } nsAutoString soapAction; operationBinding->GetSoapAction(soapAction); call->SetActionURI(soapAction); PRUint16 style; operationBinding->GetStyle(&style); // If the style is RPC, find the method name and target object URI. // If it is document-style, these are both left blank. if (style == nsISOAPPortBinding::STYLE_RPC) { operation->GetName(methodName); rv = input->GetBinding(getter_AddRefs(binding)); if (NS_FAILED(rv)) { return rv; } nsCOMPtr messageBinding = do_QueryInterface(binding, &rv); if (NS_FAILED(rv)) { return rv; } messageBinding->GetNamespace(targetObjectURI); } // Set the transport URI rv = mPort->GetBinding(getter_AddRefs(binding)); if (NS_FAILED(rv)) { return rv; } nsCOMPtr portBinding = do_QueryInterface(binding, &rv); if (NS_FAILED(rv)) { return rv; } nsAutoString address; portBinding->GetAddress(address); rv = call->SetTransportURI(address); if (NS_FAILED(rv)) { return rv; } PRUint16 version; portBinding->GetSoapVersion(&version); if (version == nsISOAPMessage::VERSION_UNKNOWN) { version = nsISOAPMessage::VERSION_1_1; } // Set up the parameters to the call PRUint32 i, partCount; input->GetPartCount(&partCount); PRUint32 maxParamIndex = info->num_args - 1; // Iterate through the parts to figure out how many are // body vs. header blocks nsCOMPtr part; PRUint32 headerCount = 0, bodyCount = 0; for (i = 0; i < partCount; i++) { rv = input->GetPart(i, getter_AddRefs(part)); if (NS_FAILED(rv)) { return rv; } rv = part->GetBinding(getter_AddRefs(binding)); if (NS_FAILED(rv)) { return rv; } nsCOMPtr partBinding = do_QueryInterface(binding, &rv); if (NS_FAILED(rv)) { return rv; } PRUint16 location; partBinding->GetLocation(&location); if (location == nsISOAPPartBinding::LOCATION_HEADER) { headerCount++; } else if (location == nsISOAPPartBinding::LOCATION_BODY) { bodyCount++; } } // Allocate parameter and header blocks nsISOAPParameter** bodyBlocks = nsnull; if (bodyCount) { bodyBlocks = static_cast (nsMemory::Alloc(bodyCount * sizeof(nsISOAPParameter*))); if (!bodyBlocks) { return NS_ERROR_OUT_OF_MEMORY; } for (i = 0; i < bodyCount; i++) { rv = CallCreateInstance(NS_SOAPPARAMETER_CONTRACTID, &bodyBlocks[i]); if (NS_FAILED(rv)) { NS_FREE_XPCOM_ISUPPORTS_POINTER_ARRAY(i, bodyBlocks); return rv; } } } nsISOAPHeaderBlock** headerBlocks = nsnull; if (headerCount) { headerBlocks = static_cast (nsMemory::Alloc(headerCount * sizeof(nsISOAPHeaderBlock*))); if (!headerBlocks) { if (bodyBlocks) { NS_FREE_XPCOM_ISUPPORTS_POINTER_ARRAY(bodyCount, bodyBlocks); } return NS_ERROR_OUT_OF_MEMORY; } for (i = 0; i < headerCount; i++) { rv = CallCreateInstance(NS_SOAPHEADERBLOCK_CONTRACTID, &headerBlocks[i]); if (NS_FAILED(rv)) { if (bodyBlocks) { NS_FREE_XPCOM_ISUPPORTS_POINTER_ARRAY(bodyCount, bodyBlocks); } NS_FREE_XPCOM_ISUPPORTS_POINTER_ARRAY(i, headerBlocks); return rv; } } } // Now iterate through the parameters and set up the parameter blocks PRUint32 bodyEntry = 0, headerEntry = 0, paramIndex = 0; for (i = 0; i < partCount; paramIndex++, i++) { input->GetPart(i, getter_AddRefs(part)); part->GetBinding(getter_AddRefs(binding)); nsCOMPtr partBinding = do_QueryInterface(binding); PRUint16 location; partBinding->GetLocation(&location); nsCOMPtr block; if (location == nsISOAPPartBinding::LOCATION_HEADER) { block = do_QueryInterface(headerBlocks[headerEntry++]); } else if (location == nsISOAPPartBinding::LOCATION_BODY) { block = do_QueryInterface(bodyBlocks[bodyEntry++]); } if (!block) { rv = NS_ERROR_FAILURE; goto call_method_end; } // Get the name, namespaceURI and type of the block based on // information from the WSDL part. If the schema component // associated with the part is an element, these values come // from the schema description of the element. If it is a // type, then the values are gathered from elsewhere. nsCOMPtr schemaComponent; rv = part->GetSchemaComponent(getter_AddRefs(schemaComponent)); if (NS_FAILED(rv)) { goto call_method_end; } nsCOMPtr type; nsAutoString blockName, blockNamespace; nsCOMPtr element = do_QueryInterface(schemaComponent); if (element) { rv = element->GetType(getter_AddRefs(type)); if (NS_FAILED(rv)) { goto call_method_end; } element->GetName(blockName); element->GetTargetNamespace(blockNamespace); } else { type = do_QueryInterface(schemaComponent); nsAutoString paramName; part->GetName(paramName); blockName.Assign(paramName); partBinding->GetNamespace(blockNamespace); } block->SetName(blockName); block->SetNamespaceURI(blockNamespace); block->SetSchemaType(type); nsAutoString encodingStyle; PRUint16 use; partBinding->GetUse(&use); // XXX Need a way to specify that a block should not be // encoded. if (use == nsISOAPPartBinding::USE_ENCODED) { partBinding->GetEncodingStyle(encodingStyle); if (!encodingStyle.IsEmpty()) { nsCOMPtr partEncoding; encoding->GetAssociatedEncoding(encodingStyle, PR_FALSE, getter_AddRefs(partEncoding)); block->SetEncoding(partEncoding); } } // Look ahead in the param info array to see if the current part has to be // treated as an array. If so then get the array length from the current // param and increment the param index. PRUint32 arrayLength; if (paramIndex < maxParamIndex && nsXPTType(info->params[paramIndex + 1].type.prefix).IsArray()) { arrayLength = params[paramIndex++].val.u32; } else { arrayLength = 0; } NS_ASSERTION(paramIndex <= maxParamIndex, "WSDL/IInfo param count mismatch"); const nsXPTParamInfo& paramInfo = info->params[paramIndex]; nsCOMPtr value; rv = ParameterToVariant(mPrimaryInterface, methodIndex, ¶mInfo, params[paramIndex], arrayLength, getter_AddRefs(value)); if (NS_FAILED(rv)) { goto call_method_end; } block->SetValue(value); } // Encode the parameters to the call rv = call->Encode(version, methodName, targetObjectURI, headerCount, headerBlocks, bodyCount, bodyBlocks); if (NS_FAILED(rv)) { goto call_method_end; } WSPCallContext* ccInst; ccInst = new WSPCallContext(this, call, methodName, operation); if (!ccInst) { rv = NS_ERROR_OUT_OF_MEMORY; goto call_method_end; } cc = ccInst; if (mIsAsync) { PRUint8 pcount; pcount = info->num_args; // There has to be at least one parameter - the retval. if (pcount == 0) { rv = NS_ERROR_FAILURE; goto call_method_end; } #ifdef DEBUG // The last one should be the retval. const nsXPTParamInfo& retParamInfo = info->params[pcount - 1]; if (!retParamInfo.IsRetval()) { rv = NS_ERROR_FAILURE; goto call_method_end; } // It should be an interface pointer const nsXPTType& retType = retParamInfo.GetType(); if (!retType.IsInterfacePointer()) { rv = NS_ERROR_FAILURE; goto call_method_end; } #endif nsIWebServiceCallContext** retval = static_cast(params[pcount-1].val.p); if (!retval) { rv = NS_ERROR_FAILURE; goto call_method_end; } *retval = cc; NS_ADDREF(*retval); rv = ccInst->CallAsync(methodIndex, mAsyncListener); if (NS_FAILED(rv)) { goto call_method_end; } mPendingCalls.AppendObject(ccInst); } else { rv = ccInst->CallSync(methodIndex, params); } call_method_end: if (bodyBlocks) { NS_FREE_XPCOM_ISUPPORTS_POINTER_ARRAY(bodyCount, bodyBlocks); } if (headerBlocks) { NS_FREE_XPCOM_ISUPPORTS_POINTER_ARRAY(headerCount, headerBlocks); } return rv; } nsresult WSPProxy::ParameterToVariant(nsIInterfaceInfo* aInterfaceInfo, PRUint32 aMethodIndex, const nsXPTParamInfo* aParamInfo, nsXPTCMiniVariant aMiniVariant, PRUint32 aArrayLength, nsIVariant** aVariant) { nsXPTType type; nsresult rv = aInterfaceInfo->GetTypeForParam(aMethodIndex, aParamInfo, 0, &type); if (NS_FAILED(rv)) { return rv; } uint8 type_tag = type.TagPart(); nsCOMPtr iinfo; if (type.IsArray()) { nsXPTType arrayType; rv = aInterfaceInfo->GetTypeForParam(aMethodIndex, aParamInfo, 1, &arrayType); if (NS_FAILED(rv)) { return rv; } if (arrayType.IsInterfacePointer()) { rv = aInterfaceInfo->GetInfoForParam(aMethodIndex, aParamInfo, getter_AddRefs(iinfo)); if (NS_FAILED(rv)) { return rv; } } return ArrayXPTCMiniVariantToVariant(arrayType.TagPart(), aMiniVariant, aArrayLength, iinfo, aVariant); } // else if (type.IsInterfacePointer()) { rv = aInterfaceInfo->GetInfoForParam(aMethodIndex, aParamInfo, getter_AddRefs(iinfo)); if (NS_FAILED(rv)) { return rv; } } return XPTCMiniVariantToVariant(type_tag, aMiniVariant, iinfo, aVariant); } nsresult WSPProxy::WrapInPropertyBag(nsISupports* aInstance, nsIInterfaceInfo* aInterfaceInfo, nsIPropertyBag** aPropertyBag) { *aPropertyBag = nsnull; nsresult rv; nsCOMPtr wrapper = do_CreateInstance(NS_WEBSERVICECOMPLEXTYPEWRAPPER_CONTRACTID, &rv); if (NS_FAILED(rv)) { return rv; } rv = wrapper->Init(aInstance, aInterfaceInfo); if (NS_FAILED(rv)) { return rv; } return CallQueryInterface(wrapper, aPropertyBag); } nsresult WSPProxy::XPTCMiniVariantToVariant(uint8 aTypeTag, nsXPTCMiniVariant aResult, nsIInterfaceInfo* aInterfaceInfo, nsIVariant** aVariant) { nsresult rv; // If a variant is passed in, just return it as is. if (aTypeTag == nsXPTType::T_INTERFACE) { nsISupports* inst = (nsISupports*)aResult.val.p; nsCOMPtr instVar = do_QueryInterface(inst); if (instVar) { *aVariant = instVar; NS_ADDREF(*aVariant); return NS_OK; } } nsCOMPtr var = do_CreateInstance(NS_VARIANT_CONTRACTID, &rv); if (NS_FAILED(rv)) { return rv; } switch (aTypeTag) { case nsXPTType::T_I8: var->SetAsInt8(aResult.val.i8); break; case nsXPTType::T_I16: var->SetAsInt16(aResult.val.i16); break; case nsXPTType::T_I32: var->SetAsInt32(aResult.val.i32); break; case nsXPTType::T_I64: var->SetAsInt64(aResult.val.i64); break; case nsXPTType::T_U8: var->SetAsUint8(aResult.val.u8); break; case nsXPTType::T_U16: var->SetAsUint16(aResult.val.u16); break; case nsXPTType::T_U32: var->SetAsUint32(aResult.val.u32); break; case nsXPTType::T_U64: var->SetAsUint64(aResult.val.u64); break; case nsXPTType::T_FLOAT: var->SetAsFloat(aResult.val.f); break; case nsXPTType::T_DOUBLE: var->SetAsDouble(aResult.val.d); break; case nsXPTType::T_BOOL: var->SetAsBool(aResult.val.b); break; case nsXPTType::T_CHAR: var->SetAsChar(aResult.val.c); break; case nsXPTType::T_WCHAR: var->SetAsWChar(aResult.val.wc); break; case nsXPTType::T_CHAR_STR: var->SetAsString(static_cast(aResult.val.p)); break; case nsXPTType::T_WCHAR_STR: var->SetAsWString(static_cast(aResult.val.p)); break; case nsXPTType::T_DOMSTRING: case nsXPTType::T_ASTRING: var->SetAsAString(*((nsAString*)aResult.val.p)); break; case nsXPTType::T_INTERFACE: { nsISupports* instance = (nsISupports*)aResult.val.p; if (instance) { nsCOMPtr propBag; rv = WrapInPropertyBag(instance, aInterfaceInfo, getter_AddRefs(propBag)); if (NS_FAILED(rv)) { return rv; } var->SetAsInterface(NS_GET_IID(nsIPropertyBag), propBag); // AFAICT, there is no need to release the instance here // because the caller who owns the object should be releasing it. // NS_RELEASE(instance); } else { var->SetAsEmpty(); } break; } default: NS_ERROR("Bad attribute type for complex type interface"); rv = NS_ERROR_FAILURE; } *aVariant = var; NS_ADDREF(*aVariant); return rv; } nsresult WSPProxy::ArrayXPTCMiniVariantToVariant(uint8 aTypeTag, nsXPTCMiniVariant aResult, PRUint32 aLength, nsIInterfaceInfo* aInterfaceInfo, nsIVariant** aVariant) { nsresult rv; nsCOMPtr retvar = do_CreateInstance(NS_VARIANT_CONTRACTID, &rv); if (NS_FAILED(rv)) { return rv; } if (aLength) { PRUint32 i = 0; void* array = aResult.val.p; void* entries; nsISupports** entriesSup = nsnull; const nsIID* iid = nsnull; switch (aTypeTag) { case nsXPTType::T_I8: case nsXPTType::T_I16: case nsXPTType::T_I32: case nsXPTType::T_I64: case nsXPTType::T_U8: case nsXPTType::T_U16: case nsXPTType::T_U32: case nsXPTType::T_U64: case nsXPTType::T_FLOAT: case nsXPTType::T_DOUBLE: case nsXPTType::T_BOOL: case nsXPTType::T_CHAR: case nsXPTType::T_WCHAR: case nsXPTType::T_CHAR_STR: case nsXPTType::T_WCHAR_STR: entries = array; break; case nsXPTType::T_INTERFACE: { aInterfaceInfo->GetIIDShared(&iid); if (iid->Equals(NS_GET_IID(nsIVariant))) { entries = array; } else { entriesSup = (nsISupports**)nsMemory::Alloc(aLength * sizeof(nsISupports*)); if (!entriesSup) { return NS_ERROR_OUT_OF_MEMORY; } const nsIID& propbagIID = NS_GET_IID(nsIPropertyBag); iid = &propbagIID; entries = (void*)entriesSup; for(i = 0; i < aLength; i++) { nsISupports* instance = *((nsISupports**)array + i); nsISupports** outptr = entriesSup + i; if (instance) { nsCOMPtr propBag; rv = WrapInPropertyBag(instance, aInterfaceInfo, getter_AddRefs(propBag)); if (NS_FAILED(rv)) { break; } propBag->QueryInterface(NS_GET_IID(nsISupports), (void**)outptr); } else { *outptr = nsnull; } } } aTypeTag = nsXPTType::T_INTERFACE_IS; break; } default: NS_ERROR("Conversion of illegal array type"); return NS_ERROR_FAILURE; } if (NS_SUCCEEDED(rv)) { rv = retvar->SetAsArray(aTypeTag, iid, aLength, entries); } if (entriesSup) { NS_FREE_XPCOM_ISUPPORTS_POINTER_ARRAY(i, entriesSup); } } else { retvar->SetAsEmpty(); } if (NS_SUCCEEDED(rv)) { *aVariant = retvar; NS_ADDREF(*aVariant); } return rv; } nsresult WSPProxy::VariantToInParameter(nsIInterfaceInfo* aInterfaceInfo, PRUint32 aMethodIndex, const nsXPTParamInfo* aParamInfo, nsIVariant* aVariant, nsXPTCVariant* aXPTCVariant) { nsXPTType type; nsresult rv = aInterfaceInfo->GetTypeForParam(aMethodIndex, aParamInfo, 0, &type); if (NS_FAILED(rv)) { return rv; } uint8 type_tag = type.TagPart(); nsCOMPtr iinfo; if (type.IsArray()) { nsXPTType arrayType; rv = aInterfaceInfo->GetTypeForParam(aMethodIndex, aParamInfo, 1, &arrayType); if (NS_FAILED(rv)) { return rv; } if (arrayType.IsInterfacePointer()) { rv = aInterfaceInfo->GetInfoForParam(aMethodIndex, aParamInfo, getter_AddRefs(iinfo)); if (NS_FAILED(rv)) { return rv; } } aXPTCVariant[0].type = nsXPTType::T_U32; aXPTCVariant[1].type = nsXPTType::T_ARRAY; aXPTCVariant[1].SetValIsArray(); return VariantToArrayValue(arrayType.TagPart(), aXPTCVariant, aXPTCVariant+1, iinfo, aVariant); } // Set the param's type on the XPTCVariant because xptcinvoke's // invoke_copy_to_stack depends on it. This fixes bug 203434. aXPTCVariant->type = type; // else if (type.IsInterfacePointer()) { rv = aInterfaceInfo->GetInfoForParam(aMethodIndex, aParamInfo, getter_AddRefs(iinfo)); if (NS_FAILED(rv)) { return rv; } } if (type_tag == nsXPTType::T_DOMSTRING) { // T_DOMSTRING values are expected to be stored in an nsAString // object pointed to by the nsXPTCVariant... return VariantToValue(type_tag, aXPTCVariant->val.p, iinfo, aVariant); } // else // ... but other types are expected to be stored directly in the // variant itself. return VariantToValue(type_tag, &aXPTCVariant->val, iinfo, aVariant); } nsresult WSPProxy::VariantToOutParameter(nsIInterfaceInfo* aInterfaceInfo, PRUint32 aMethodIndex, const nsXPTParamInfo* aParamInfo, nsIVariant* aVariant, nsXPTCMiniVariant* aMiniVariant) { nsXPTType type; nsresult rv = aInterfaceInfo->GetTypeForParam(aMethodIndex, aParamInfo, 0, &type); if (NS_FAILED(rv)) { return rv; } uint8 type_tag = type.TagPart(); nsCOMPtr iinfo; if (type.IsArray()) { nsXPTType arrayType; rv = aInterfaceInfo->GetTypeForParam(aMethodIndex, aParamInfo, 1, &arrayType); if (NS_FAILED(rv)) { return rv; } if (arrayType.IsInterfacePointer()) { rv = aInterfaceInfo->GetInfoForParam(aMethodIndex, aParamInfo, getter_AddRefs(iinfo)); if (NS_FAILED(rv)) { return rv; } } return VariantToArrayValue(arrayType.TagPart(), aMiniVariant, aMiniVariant + 1, iinfo, aVariant); } // else if (type.IsInterfacePointer()) { rv = aInterfaceInfo->GetInfoForParam(aMethodIndex, aParamInfo, getter_AddRefs(iinfo)); if (NS_FAILED(rv)) { return rv; } } return VariantToValue(type_tag, aMiniVariant->val.p, iinfo, aVariant); } nsresult WSPProxy::WrapInComplexType(nsIPropertyBag* aPropertyBag, nsIInterfaceInfo* aInterfaceInfo, nsISupports** aComplexType) { *aComplexType = nsnull; nsRefPtr wrapper = new WSPPropertyBagWrapper(); if (!wrapper) { return NS_ERROR_OUT_OF_MEMORY; } nsresult rv = wrapper->Init(aPropertyBag, aInterfaceInfo); if (NS_FAILED(rv)) { return rv; } wrapper->QueryInterface(NS_GET_IID(nsISupports), (void**)aComplexType); return NS_OK; } nsresult WSPProxy::VariantToValue(uint8 aTypeTag, void* aValue, nsIInterfaceInfo* aInterfaceInfo, nsIVariant* aProperty) { nsresult rv = NS_OK; switch(aTypeTag) { case nsXPTType::T_I8: rv = aProperty->GetAsInt8((PRUint8*)aValue); break; case nsXPTType::T_I16: rv = aProperty->GetAsInt16((PRInt16*)aValue); break; case nsXPTType::T_I32: rv = aProperty->GetAsInt32((PRInt32*)aValue); break; case nsXPTType::T_I64: rv = aProperty->GetAsInt64((PRInt64*)aValue); break; case nsXPTType::T_U8: rv = aProperty->GetAsUint8((PRUint8*)aValue); break; case nsXPTType::T_U16: rv = aProperty->GetAsUint16((PRUint16*)aValue); break; case nsXPTType::T_U32: rv = aProperty->GetAsUint32((PRUint32*)aValue); break; case nsXPTType::T_U64: rv = aProperty->GetAsUint64((PRUint64*)aValue); break; case nsXPTType::T_FLOAT: rv = aProperty->GetAsFloat((float*)aValue); break; case nsXPTType::T_DOUBLE: rv = aProperty->GetAsDouble((double*)aValue); break; case nsXPTType::T_BOOL: rv = aProperty->GetAsBool((PRBool*)aValue); break; case nsXPTType::T_CHAR: rv = aProperty->GetAsChar((char*)aValue); break; case nsXPTType::T_WCHAR: rv = aProperty->GetAsWChar((PRUnichar*)aValue); break; case nsXPTType::T_CHAR_STR: rv = aProperty->GetAsString((char**)aValue); break; case nsXPTType::T_WCHAR_STR: rv = aProperty->GetAsWString((PRUnichar**)aValue); break; case nsXPTType::T_DOMSTRING: case nsXPTType::T_ASTRING: rv = aProperty->GetAsAString(*(nsAString*)aValue); break; case nsXPTType::T_INTERFACE: { const nsIID* iid; aInterfaceInfo->GetIIDShared(&iid); PRUint16 dataType; aProperty->GetDataType(&dataType); if (dataType == nsIDataType::VTYPE_EMPTY) { *(nsISupports**)aValue = nsnull; } else if (iid->Equals(NS_GET_IID(nsIVariant))) { *(nsIVariant**)aValue = aProperty; NS_ADDREF(*(nsIVariant**)aValue); } else { nsCOMPtr sup; rv = aProperty->GetAsISupports(getter_AddRefs(sup)); if (NS_FAILED(rv)) { return rv; } nsCOMPtr propBag = do_QueryInterface(sup, &rv); if (NS_FAILED(rv)) { return rv; } nsCOMPtr wrapper; rv = WrapInComplexType(propBag, aInterfaceInfo, getter_AddRefs(wrapper)); if (NS_FAILED(rv)) { return rv; } rv = wrapper->QueryInterface(*iid, (void**)aValue); } break; } default: NS_ERROR("Bad attribute type for complex type interface"); rv = NS_ERROR_FAILURE; } return rv; } nsresult WSPProxy::VariantToArrayValue(uint8 aTypeTag, nsXPTCMiniVariant* aResultSize, nsXPTCMiniVariant* aResultArray, nsIInterfaceInfo* aInterfaceInfo, nsIVariant* aProperty) { void* array; PRUint16 type; PRUint32 count; nsIID arrayIID; nsresult rv = aProperty->GetAsArray(&type, &arrayIID, &count, &array); if (NS_FAILED(rv)) { return rv; } aResultSize->val.u32 = count; switch (aTypeTag) { case nsXPTType::T_I8: case nsXPTType::T_U8: case nsXPTType::T_I16: case nsXPTType::T_U16: case nsXPTType::T_I32: case nsXPTType::T_U32: case nsXPTType::T_I64: case nsXPTType::T_U64: case nsXPTType::T_FLOAT: case nsXPTType::T_DOUBLE: case nsXPTType::T_BOOL: case nsXPTType::T_CHAR: case nsXPTType::T_WCHAR: case nsXPTType::T_CHAR_STR: case nsXPTType::T_WCHAR_STR: aResultArray->val.p = array; break; case nsXPTType::T_INTERFACE: case nsXPTType::T_INTERFACE_IS: { if (arrayIID.Equals(NS_GET_IID(nsIVariant))) { aResultArray->val.p = array; } else if (!arrayIID.Equals(NS_GET_IID(nsIPropertyBag))) { NS_ERROR("Array of complex types should be represented by property " "bags"); return NS_ERROR_FAILURE; } else { nsISupports** outptr = (nsISupports**)nsMemory::Alloc(count * sizeof(nsISupports*)); if (!outptr) { return NS_ERROR_OUT_OF_MEMORY; } nsISupports** arraySup = (nsISupports**)array; const nsIID* iid; aInterfaceInfo->GetIIDShared(&iid); PRUint32 i; for (i = 0; i < count; i++) { nsCOMPtr propBag(do_QueryInterface(arraySup[i])); if (!propBag) { *(outptr + i) = nsnull; } else { nsCOMPtr wrapper; rv = WrapInComplexType(propBag, aInterfaceInfo, getter_AddRefs(wrapper)); if (NS_FAILED(rv)) { NS_FREE_XPCOM_ISUPPORTS_POINTER_ARRAY(i, outptr); return rv; } rv = wrapper->QueryInterface(*iid, (void**)(outptr + i)); if (NS_FAILED(rv)) { NS_FREE_XPCOM_ISUPPORTS_POINTER_ARRAY(i, outptr); return rv; } } } aResultArray->val.p = outptr; } break; } default: NS_ERROR("Conversion of illegal array type"); return NS_ERROR_FAILURE; } return NS_OK; } /////////////////////////////////////////////////// // // Implementation of nsIWebServiceProxy // /////////////////////////////////////////////////// /* readonly attribute nsIWSDLPort port; */ NS_IMETHODIMP WSPProxy::GetPort(nsIWSDLPort * *aPort) { NS_ENSURE_ARG_POINTER(aPort); *aPort = mPort; NS_IF_ADDREF(*aPort); return NS_OK; } /* readonly attribute boolean isAsync; */ NS_IMETHODIMP WSPProxy::GetIsAsync(PRBool *aIsAsync) { NS_ENSURE_ARG_POINTER(aIsAsync); *aIsAsync = mIsAsync; return NS_OK; } /* readonly attribute AString qualifier; */ NS_IMETHODIMP WSPProxy::GetQualifier(nsAString & aQualifier) { aQualifier.Assign(mQualifier); return NS_OK; } /* readonly attribute nsISimpleEnumerator pendingCalls; */ NS_IMETHODIMP WSPProxy::GetPendingCalls(nsISimpleEnumerator * *aPendingCalls) { return NS_ERROR_NOT_IMPLEMENTED; } nsresult WSPProxy::GetInterfaceName(PRBool listener, char** retval) { if (!mPrimaryInterface) { return NS_ERROR_FAILURE; } const char* rawName; nsresult rv = mPrimaryInterface->GetNameShared(&rawName); if (NS_FAILED(rv)) { return rv; } nsCAutoString name; if (listener) { if (mIsAsync) { name.Assign(rawName, strlen(rawName) - (sizeof("Async")-1) ); } else { name.Assign(rawName); } name.Append("Listener"); } else { name.Assign(rawName); } *retval = (char*) nsMemory::Clone(name.get(), name.Length()+1); return *retval ? NS_OK : NS_ERROR_OUT_OF_MEMORY; } /* readonly attribute string primaryInterfaceName; */ NS_IMETHODIMP WSPProxy::GetPrimaryInterfaceName(char * *aPrimaryInterfaceName) { return GetInterfaceName(PR_FALSE, aPrimaryInterfaceName); } /* readonly attribute string primaryAsyncListenerInterfaceName; */ NS_IMETHODIMP WSPProxy::GetPrimaryAsyncListenerInterfaceName(char * *aPrimaryAsyncListenerInterfaceName) { return GetInterfaceName(PR_TRUE, aPrimaryAsyncListenerInterfaceName); } /* readonly attribute nsIScriptableInterfaces interfaces; */ NS_IMETHODIMP WSPProxy::GetInterfaces(nsIScriptableInterfaces * *aInterfaces) { *aInterfaces = mInterfaces; NS_IF_ADDREF(*aInterfaces); return NS_OK; } /////////////////////////////////////////////////// // // Implementation of nsIClassInfo // /////////////////////////////////////////////////// /* void getInterfaces (out PRUint32 count, [array, size_is (count), retval] out nsIIDPtr array); */ NS_IMETHODIMP WSPProxy::GetInterfaces(PRUint32 *count, nsIID * **array) { if (!mIID) { return NS_ERROR_NOT_INITIALIZED; } *count = 2; nsIID** iids = static_cast(nsMemory::Alloc(2 * sizeof(nsIID*))); if (!iids) { return NS_ERROR_OUT_OF_MEMORY; } iids[0] = static_cast(nsMemory::Clone(mIID, sizeof(nsIID))); if (NS_UNLIKELY(!iids[0])) { NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(0, iids); return NS_ERROR_OUT_OF_MEMORY; } const nsIID& wsiid = NS_GET_IID(nsIWebServiceProxy); iids[1] = static_cast(nsMemory::Clone(&wsiid, sizeof(nsIID))); if (NS_UNLIKELY(!iids[1])) { NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(1, iids); return NS_ERROR_OUT_OF_MEMORY; } *array = iids; return NS_OK; } /* nsISupports getHelperForLanguage (in PRUint32 language); */ NS_IMETHODIMP WSPProxy::GetHelperForLanguage(PRUint32 language, nsISupports **_retval) { *_retval = nsnull; return NS_OK; } /* readonly attribute string contractID; */ NS_IMETHODIMP WSPProxy::GetContractID(char * *aContractID) { *aContractID = nsnull; return NS_OK; } /* readonly attribute string classDescription; */ NS_IMETHODIMP WSPProxy::GetClassDescription(char * *aClassDescription) { *aClassDescription = nsnull; return NS_OK; } /* readonly attribute nsCIDPtr classID; */ NS_IMETHODIMP WSPProxy::GetClassID(nsCID * *aClassID) { *aClassID = nsnull; return NS_OK; } /* readonly attribute PRUint32 implementationLanguage; */ NS_IMETHODIMP WSPProxy::GetImplementationLanguage(PRUint32 *aImplementationLanguage) { *aImplementationLanguage = nsIProgrammingLanguage::CPLUSPLUS; return NS_OK; } /* readonly attribute PRUint32 flags; */ NS_IMETHODIMP WSPProxy::GetFlags(PRUint32 *aFlags) { *aFlags = nsIClassInfo::DOM_OBJECT; return NS_OK; } /* [notxpcom] readonly attribute nsCID classIDNoAlloc; */ NS_IMETHODIMP WSPProxy::GetClassIDNoAlloc(nsCID *aClassIDNoAlloc) { return NS_ERROR_NOT_AVAILABLE; } void WSPProxy::GetListenerInterfaceInfo(nsIInterfaceInfo** aInfo) { *aInfo = mListenerInterfaceInfo; NS_IF_ADDREF(*aInfo); } void WSPProxy::CallCompleted(WSPCallContext* aContext) { mPendingCalls.RemoveObject(aContext); }