Implemented rest query parser and added unit test for the parser's API.
Also added code to handle query in Doxm resource.
Change-Id: Id3dc6c171d9faa25a44849b316eaa54171a997a6
Signed-off-by: Shilpa Sodani <shilpa.a.sodani@intel.com>
Signed-off-by: Sachin Agrawal <sachin.agrawal@intel.com>
Reviewed-on: https://gerrit.iotivity.org/gerrit/1216
Tested-by: jenkins-iotivity <jenkins-iotivity@opendaylight.org>
######################################################################
libocsrm_env.PrependUnique(CPPPATH = [
'../../../extlibs/cjson/',
+# '../../../extlibs/tinydtls/',
'../logger/include',
'../ocrandom/include',
'../stack/include',
OCSRM_SRC + 'policyengine.c',
OCSRM_SRC + 'psinterface.c',
OCSRM_SRC + 'srmresourcestrings.c',
+ OCSRM_SRC + 'srmutility.c',
OCSRM_SRC + 'base64.c'
]
extern const char * PRE_PROVISIONED_DEVICE_PIN;
extern const char * PRE_PROVISIONED_STRONG_CREDENTIAL;
+extern const char * OIC_SEC_TRUE;
+extern const char * OIC_SEC_FALSE;
+
+extern const char * OIC_SEC_REST_QUERY_SEPARATOR;
+extern char OIC_SEC_REST_QUERY_DELIMETER;
+
#endif //IOTVT_SRM_RSRC_STRINGS_H
#define IOTVT_SRM_UTILITY_H
#include "ocstack.h"
-#include "uthash.h"
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+#include "uri.h"
+#ifdef __cplusplus
+}
+#endif
+
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
+
+typedef struct OicParseQueryIter OicParseQueryIter_t;
+
+/**
+ * @brief OicRestQueryIter data structure is used for book-keeping
+ * sub-REST query's attribute's and value's, starting location &
+ * length between calls to GetNextQuery(). This struct needs
+ * to be first initialized with ParseQueryIterInit().
+ *
+ */
+struct OicParseQueryIter
+{
+ unsigned char * attrPos; /**<stating location of attribute */
+ size_t attrLen; /**<length of the attribute */
+ unsigned char * valPos; /**<starting location of value*/
+ size_t valLen; /**<length of the value*/
+ coap_parse_iterator_t pi; /**<coap struct for tokenizing the query*/
+};
+
/**
* @def VERIFY_SUCCESS
* @brief Macro to verify success of operation.
#define VERIFY_NON_NULL(tag, arg, logLevel) { if (NULL == (arg)) \
{ OC_LOG((logLevel), tag, PCF(#arg " is NULL")); goto exit; } }
+/**
+ * This method initializes the OicParseQueryIter_t struct
+ *
+ *@param query - REST query, to be parsed
+ *@param parseIter - OicParseQueryIter_t struct, to be initialized
+ *
+ */
+void ParseQueryIterInit(unsigned char * query, OicParseQueryIter_t * parseIter);
+
+
+/**
+ * This method fills the OicParseQueryIter_t struct with next REST query's
+ * attribute's and value's information
+ *
+ *@param parseIter - OicParseQueryIter_t struct, has next query's attribute's & value's info
+ *
+ * @retval
+ * OicParseQueryIter_t * - has parsed query info
+ * NULL - has no query to parse
+ */
+OicParseQueryIter_t * GetNextQuery(OicParseQueryIter_t * parseIter);
#ifdef __cplusplus
}
*/
static SPResult findResource(unsigned short timeout)
{
- static char DOXM_OWNED_FALSE_MULTICAST_QUERY[] = "/oic/sec/doxm?Owned=\"FALSE\"";
+ static char DOXM_OWNED_FALSE_MULTICAST_QUERY[] = "/oic/sec/doxm?Owned=FALSE";
CAResult_t res = CAGenerateToken(&gToken, CA_MAX_TOKEN_LEN);
if (CA_STATUS_OK != res)
{
#include "credresource.h"
#include "ocserverrequest.h"
#include "srmutility.h"
-#include "uthash.h"
#include <stdlib.h>
#include <string.h>
return bRet;
}
+static bool ValidateQuery(unsigned char * query)
+{
+ // Send doxm resource data if the state of doxm resource
+ // matches with the query parameters.
+ // else send doxm resource data as NULL
+ // TODO Remove this check and rely on Policy Engine
+ // and Provisioning Mode to enforce provisioning-state
+ // access rules. Eventually, the PE and PM code will
+ // not send a request to the /doxm Entity Handler at all
+ // if it should not respond.
+ OC_LOG (INFO, TAG, PCF("In ValidateQuery"));
+ if(NULL == gDoxm)
+ {
+ return false;
+ }
+
+ OicParseQueryIter_t parseIter = {};
+
+ ParseQueryIterInit(query, &parseIter);
+
+ while(GetNextQuery(&parseIter))
+ {
+ if(strncasecmp((char *)parseIter.attrPos, OIC_JSON_OWNED_NAME, parseIter.attrLen) == 0)
+ {
+ if((strncasecmp((char *)parseIter.valPos, OIC_SEC_TRUE, parseIter.valLen) == 0) &&
+ (gDoxm->owned))
+ {
+ return true;
+ }
+ else if((strncasecmp((char *)parseIter.valPos, OIC_SEC_FALSE, parseIter.valLen) == 0)
+ && (!gDoxm->owned))
+ {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
static OCEntityHandlerResult HandleDoxmGetRequest (const OCEntityHandlerRequest * ehRequest)
{
- // Convert Doxm data into JSON for transmission
- char* jsonStr = BinToDoxmJSON(gDoxm);
+ char* jsonStr = NULL;
+ OCEntityHandlerResult ehRet = OC_EH_OK;
+
+ OC_LOG (INFO, TAG, PCF("Doxm EntityHandle processing GET request"));
+
+ //Checking if Get request is a query.
+ if(ehRequest->query)
+ {
+ OC_LOG (INFO, TAG, PCF("HandleDoxmGetRequest processing query"));
+ if(!ValidateQuery((unsigned char *)ehRequest->query))
+ {
+ ehRet = OC_EH_ERROR;
+ }
+ }
/*
- * A device should 'always' have a default Doxm. Therefore,
- * jsonStr should never be NULL.
+ * For GET or Valid Query request return doxm resource json payload.
+ * For non-valid query return NULL json payload.
+ * A device will 'always' have a default Doxm, so BinToDoxmJSON will
+ * return valid doxm resource json.
*/
- OCEntityHandlerResult ehRet = (jsonStr ? OC_EH_OK : OC_EH_ERROR);
+
+ jsonStr = (ehRet == OC_EH_OK) ? BinToDoxmJSON(gDoxm) : NULL;
// Send response payload to request originator
if(OC_STACK_OK != SendSRMResponse(ehRequest, ehRet, jsonStr))
{
- OC_LOG (ERROR, TAG, PCF("SendSRMResponse failed in HandlePstatGetRequest"));
+ OC_LOG (ERROR, TAG, PCF("SendSRMResponse failed in HandleDoxmGetRequest"));
}
OICFree(jsonStr);
static OCEntityHandlerResult HandleDoxmPutRequest (const OCEntityHandlerRequest * ehRequest)
{
+ OC_LOG (INFO, TAG, PCF("Doxm EntityHandle processing PUT request"));
OCEntityHandlerResult ehRet = OC_EH_ERROR;
OicUuid_t emptyOwner = {};
*/
if ((false == gDoxm->owned) && (false == newDoxm->owned))
{
+ OC_LOG (INFO, TAG, PCF("Doxm EntityHandle enabling AnonECDHCipherSuite"));
#ifdef __WITH_DTLS__
ehRet = (CAEnableAnonECDHCipherSuite(true) == CA_STATUS_OK) ? OC_EH_OK : OC_EH_ERROR;
#endif //__WITH_DTLS__
uint8_t ownerPSK[OWNER_PSK_LENGTH_128] = {};
//Generating OwnerPSK
+ OC_LOG (INFO, TAG, PCF("Doxm EntityHandle generating OwnerPSK"));
pskRet = CAGenerateOwnerPSK(&request->addressInfo,
request->connectivityType,
(uint8_t*) OXM_JUST_WORKS, strlen(OXM_JUST_WORKS),
sizeof(base64Buff), &outLen);
VERIFY_SUCCESS(TAG, b64Ret == B64_OK, ERROR);
+ OC_LOG (INFO, TAG, PCF("Doxm EntityHandle generating Credential"));
OicSecCred_t *cred = GenerateCredential(&newDoxm->owner, SYMMETRIC_PAIR_WISE_KEY,
NULL, base64Buff, ownLen, &newDoxm->owner);
VERIFY_NON_NULL(TAG, cred, ERROR);
OCStackResult SendSRMResponse(const OCEntityHandlerRequest *ehRequest,
OCEntityHandlerResult ehRet, const char *rspPayload)
{
+ OC_LOG (INFO, TAG, PCF("SRM sending SRM response"));
OCEntityHandlerResponse response = {};
if (ehRequest)
{
const char * OXM_PRE_PROVISIONED_DEVICE_PIN = "oic.sec.doxm.ppdp";
const char * OXM_PRE_PROVISIONED_STRONG_CREDENTIAL = "oic.sec.doxm.ppsc";
+const char * OIC_SEC_TRUE = "true";
+const char * OIC_SEC_FALSE = "false";
+
+const char * OIC_SEC_REST_QUERY_SEPARATOR = "&";
+char OIC_SEC_REST_QUERY_DELIMETER = '=';
--- /dev/null
+//******************************************************************
+//
+// Copyright 2015 Intel Mobile Communications GmbH All Rights Reserved.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+//
+// Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+#define _POSIX_C_SOURCE 200112L
+#include <string.h>
+
+#include "srmutility.h"
+#include "srmresourcestrings.h"
+#include "logger.h"
+
+#define TAG PCF("SRM-UTILITY")
+
+/**
+ * This method initializes the OicParseQueryIter_t struct
+ *
+ *@param query - REST query, to be parsed
+ *@param parseIter - OicParseQueryIter_t struct, to be initialized
+ *
+ */
+void ParseQueryIterInit(unsigned char * query, OicParseQueryIter_t * parseIter)
+{
+ OC_LOG (INFO, TAG, PCF("Initializing coap iterator"));
+ if((NULL == query) || (NULL == parseIter))
+ return;
+
+ parseIter->attrPos = NULL;
+ parseIter->attrLen = 0;
+ parseIter->valPos = NULL;
+ parseIter->valLen = 0;
+ coap_parse_iterator_init(query, strlen((char *)query),
+ (unsigned char *)OIC_SEC_REST_QUERY_SEPARATOR, (unsigned char *) "", 0, &parseIter->pi);
+}
+
+
+/**
+ * This method fills the OicParseQueryIter_t struct with next REST query's
+ * attribute's and value's information
+ *
+ *@param parseIter - OicParseQueryIter_t struct, has next query's attribute's & value's info
+ *
+ * @retval
+ * OicParseQueryIter_t * - has parsed query info
+ * NULL - has no query to parse
+ */
+OicParseQueryIter_t * GetNextQuery(OicParseQueryIter_t * parseIter)
+{
+ OC_LOG (INFO, TAG, PCF("Getting Next Query"));
+ if(NULL == parseIter)
+ return NULL;
+
+ unsigned char * qrySeg = NULL;
+ char * delimPos;
+
+ //Get the next query. Querys are separated by OIC_SEC_REST_QUERY_SEPARATOR
+ qrySeg = coap_parse_next(&parseIter->pi);
+
+ if(qrySeg)
+ {
+ delimPos = strchr((char *)qrySeg, OIC_SEC_REST_QUERY_DELIMETER);
+ if(delimPos)
+ {
+ parseIter->attrPos = parseIter->pi.pos;
+ parseIter->attrLen = (unsigned char *)delimPos - parseIter->pi.pos;
+ parseIter->valPos = (unsigned char *)delimPos + 1;
+ parseIter->valLen = &qrySeg[parseIter->pi.segment_length] - parseIter->valPos;
+ return parseIter;
+ }
+ }
+ return NULL;
+}
'../../connectivity/inc',
'../../connectivity/api',
'../../connectivity/external/inc',
+ '../../connectivity/lib/libcoap-4.1.1',
'../include',
'../include/internal',
'../../logger/include',
'../../../oc_logger/include',
'../../../../extlibs/gtest/gtest-1.7.0/include',
'../../../../extlibs/cjson/',
+# '../../../../extlibs/tinydtls/',
'../include'
])
srmtest_env.AppendUnique(CXXFLAGS = ['-std=c++0x', '-Wall', '-pthread'])
'policyengine.cpp',
'securityresourcemanager.cpp',
'credentialresource.cpp',
+ 'srmutility.cpp',
'base64tests.cpp'])
Alias("test", [unittest])
void InitSecDoxmInstance(OicSecDoxm_t * doxm);
OCEntityHandlerResult HandleDoxmPostRequest (const OCEntityHandlerRequest * ehRequest);
void DeleteDoxmBinData(OicSecDoxm_t* doxm);
+OCEntityHandlerResult HandleDoxmGetRequest (const OCEntityHandlerRequest * ehRequest);
#ifdef __cplusplus
}
#endif
EXPECT_EQ(OC_EH_ERROR, DoxmEntityHandler(OCEntityHandlerFlag::OC_OBSERVE_FLAG, &req));
}
+TEST(DoxmEntityHandlerTest, DoxmEntityHandlerValidRequest)
+{
+ EXPECT_EQ(OC_STACK_INVALID_PARAM, InitDoxmResource());
+ char query[] = "oxm=0&owned=false&owner=owner1";
+ OCEntityHandlerRequest req = {};
+ req.method = OC_REST_GET;
+ req.query = (char*)OICMalloc(strlen(query) + 1);
+ strcpy((char *)req.query, query);
+ EXPECT_EQ(OC_EH_ERROR, DoxmEntityHandler(OCEntityHandlerFlag::OC_REQUEST_FLAG, &req));
+
+ OICFree(req.query);
+}
+
//BinToDoxmJSON Tests
TEST(BinToDoxmJSONTest, BinToDoxmJSONNullDoxm)
{
EXPECT_TRUE(doxm == NULL);
}
-//GetDoxmResourceData Test
-TEST(DoxmGetResourceDataTest, GetDoxmResourceData)
-{
- EXPECT_TRUE(NULL == GetDoxmResourceData());
-}
#if 0
+//HandleDoxmPostRequest Test
TEST(HandleDoxmPostRequestTest, HandleDoxmPostRequestValidInput)
{
OCEntityHandlerRequest ehRequest = {};
--- /dev/null
+// Copyright 2015 Intel Mobile Communications GmbH All Rights Reserved.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+//
+// Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+#include "gtest/gtest.h"
+#include "ocstack.h"
+#include "srmutility.h"
+
+
+//ParseRestQuery Tests
+TEST(ParseRestQueryTest, ParseRestQueryEmpty)
+{
+ unsigned char query[] = "";
+ OicParseQueryIter_t parseIter = {};
+ ParseQueryIterInit(query, &parseIter);
+ EXPECT_EQ(NULL, GetNextQuery(&parseIter));
+}
+
+TEST(ParseRestQueryTest, ParseSingleRestQuery)
+{
+ char attr[10], val[10];
+ unsigned char query[] = "owned=false";
+
+ OicParseQueryIter_t parseIter = {};
+ ParseQueryIterInit(query, &parseIter);
+ EXPECT_NE((OicParseQueryIter_t *)NULL, GetNextQuery(&parseIter));
+
+ strncpy(attr, (char *)parseIter.attrPos, parseIter.attrLen);
+ strncpy(val, (char *)parseIter.valPos, parseIter.valLen);
+ attr[parseIter.attrLen] = '\0';
+ val[parseIter.valLen] = '\0';
+ printf("\nAttribute: %s value: %s\n\n", attr, val);
+
+}
+
+TEST(ParseRestQueryTest, ParseRestMultipleQuery)
+{
+ char attr[10], val[10];
+ unsigned char query[] = "oxm=0&owned=true&owner=owner1";
+
+ OicParseQueryIter_t parseIter = {};
+ ParseQueryIterInit(query, &parseIter);
+ printf("\n");
+ while(GetNextQuery(&parseIter))
+ {
+ EXPECT_NE(0, parseIter.pi.segment_length);
+
+ strncpy(attr, (char *)parseIter.attrPos, parseIter.attrLen);
+ strncpy(val, (char *)parseIter.valPos, parseIter.valLen);
+ attr[parseIter.attrLen] = '\0';
+ val[parseIter.valLen] = '\0';
+ printf("Attribute: %s value: %s\n", attr, val);
+
+ }
+ printf("\n");
+}
+