1 //******************************************************************
3 // Copyright 2014 Intel Mobile Communications GmbH All Rights Reserved.
5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
7 // Licensed under the Apache License, Version 2.0 (the "License");
8 // you may not use this file except in compliance with the License.
9 // You may obtain a copy of the License at
11 // http://www.apache.org/licenses/LICENSE-2.0
13 // Unless required by applicable law or agreed to in writing, software
14 // distributed under the License is distributed on an "AS IS" BASIS,
15 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 // See the License for the specific language governing permissions and
17 // limitations under the License.
19 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
21 // Defining _POSIX_C_SOURCE macro with 200112L (or greater) as value
22 // causes header files to expose definitions
23 // corresponding to the POSIX.1-2001 base
24 // specification (excluding the XSI extension).
25 // For POSIX.1-2001 base specification,
26 // Refer http://pubs.opengroup.org/onlinepubs/009695399/
27 #define _POSIX_C_SOURCE 200112L
28 #include "occollection.h"
31 #include "ocstackinternal.h"
32 #include "ocresourcehandler.h"
35 #include "oic_malloc.h"
36 #include "oic_string.h"
37 #include "ocpayload.h"
42 #define WITH_GROUPACTION 1
46 #define TAG PCF("occollection")
48 #define NUM_PARAM_IN_QUERY 2 // The expected number of parameters in a query
49 #define NUM_FIELDS_IN_QUERY 2 // The expected number of fields in a query
51 static OCStackResult CheckRTParamSupport(const OCResource* resource, const char* rtPtr)
53 if(!resource || !rtPtr)
55 return OC_STACK_INVALID_PARAM;
58 OCResourceType* rTPointer = resource->rsrcType;
61 if( strcmp (rTPointer->resourcetypename, rtPtr) == 0)
66 rTPointer = rTPointer->next;
68 return OC_STACK_ERROR;
71 static OCStackResult CheckIFParamSupport(const OCResource* resource, const char* ifPtr)
73 if(!resource || !ifPtr)
75 return OC_STACK_INVALID_PARAM;
78 OCResourceInterface* iFPointer = resource->rsrcInterface;
81 if( strcmp (iFPointer->name, ifPtr) == 0)
86 iFPointer = iFPointer->next;
88 return OC_STACK_ERROR;
92 ValidateQuery (const char *query, OCResourceHandle resource,
93 OCStackIfTypes *ifParam, char **rtParam)
95 uint8_t numFields = 0;
98 //TODO: Query and URL validation is being done for virtual resource case
99 // using ValidateUrlQuery function. We should be able to merge it with this
101 OC_LOG(INFO, TAG, PCF("Entering ValidateQuery"));
104 return OC_STACK_ERROR;
106 if(!ifParam || !rtParam)
108 return OC_STACK_INVALID_PARAM;
113 // Query string is empty
114 OC_LOG_V(INFO, TAG, PCF("Empty query string, use default IF and RT"));
115 *ifParam = STACK_IF_DEFAULT;
116 *rtParam = (char *) OCGetResourceTypeName (resource, 0);
120 // Break the query string to validate it and determine IF and RT parameters
121 // Validate there are atmost 2 parameters in string and that one is 'if' and other 'rt'
122 // separated by token '&' or ';'. Stack will accept both the versions.
124 char *endStr, *ifPtr = NULL, *rtPtr = NULL;
125 char *token = strtok_r ((char *)query, OC_QUERY_SEPARATOR , &endStr);
127 // External loop breaks query string into fields using the & separator
128 while (token != NULL)
132 char *innerToken = strtok_r (token, "=", &endToken);
135 // Internal loop parses the field to extract values (parameters) assigned to each field
136 while (innerToken != NULL)
139 if (strncmp (innerToken, OC_RSRVD_INTERFACE, sizeof(OC_RSRVD_INTERFACE)) == 0)
141 // Determine the value of IF parameter
142 innerToken = strtok_r (NULL, "=", &endToken);
145 else if (strcmp (innerToken, OC_RSRVD_RESOURCE_TYPE) == 0)
147 // Determine the value of RT parameter
148 innerToken = strtok_r (NULL, "=", &endToken);
153 innerToken = strtok_r (NULL, "=", &endToken);
156 if (numParam != NUM_PARAM_IN_QUERY)
158 // Query parameter should be of the form if=<string>. String should not have & or =
159 return OC_STACK_INVALID_QUERY;
161 token = strtok_r (NULL, OC_QUERY_SEPARATOR, &endStr);
163 if (numFields > NUM_FIELDS_IN_QUERY)
165 // current release supports one IF value, one RT value and no other params
166 return OC_STACK_INVALID_QUERY;
171 if(CheckIFParamSupport((OCResource *)resource, ifPtr) != OC_STACK_OK)
173 return OC_STACK_INVALID_QUERY;
175 if (strcmp (ifPtr, OC_RSRVD_INTERFACE_DEFAULT) == 0)
177 *ifParam = STACK_IF_DEFAULT;
179 else if (strcmp (ifPtr, OC_RSRVD_INTERFACE_LL) == 0)
181 *ifParam = STACK_IF_LL;
183 else if (strcmp (ifPtr, OC_RSRVD_INTERFACE_BATCH) == 0)
185 *ifParam = STACK_IF_BATCH;
187 else if(strcmp (ifPtr, OC_RSRVD_INTERFACE_GROUP) == 0)
189 *ifParam = STACK_IF_GROUP;
193 return OC_STACK_ERROR;
198 // IF not specified in query, use default IF
199 *ifParam = STACK_IF_DEFAULT;
204 if (CheckRTParamSupport((OCResource *)resource, rtPtr) == OC_STACK_OK)
210 return OC_STACK_INVALID_QUERY;
215 // RT not specified in query. Use the first resource type for the resource as default.
216 *rtParam = (char *) OCGetResourceTypeName (resource, 0);
218 OC_LOG_V(INFO, TAG, "Query params: IF = %d, RT = %s", *ifParam, *rtParam);
224 HandleLinkedListInterface(OCEntityHandlerRequest *ehRequest, uint8_t filterOn, char *filterValue)
228 return OC_STACK_INVALID_PARAM;
231 OCStackResult ret = OC_STACK_OK;
232 OCResource *collResource = (OCResource *)ehRequest->resource;
234 OCRepPayload* payload = NULL;
236 if(ret == OC_STACK_OK)
238 ret = BuildResponseRepresentation(collResource, &payload);
241 if (ret == OC_STACK_OK)
243 for (int i = 0; i < MAX_CONTAINED_RESOURCES && ret == OC_STACK_OK; i++)
245 OCResource* temp = collResource->rsrcResources[i];
248 //TODO : Add resource type filtering once collections
249 // start supporting queries.
250 ret = BuildResponseRepresentation(temp, &payload);
255 if(ret == OC_STACK_OK)
257 OCEntityHandlerResponse response = {};
258 response.ehResult = OC_EH_OK;
259 response.payload = (OCPayload*)payload;
260 response.persistentBufferFlag = 0;
261 response.requestHandle = (OCRequestHandle) ehRequest->requestHandle;
262 response.resourceHandle = (OCResourceHandle) collResource;
263 ret = OCDoResponse(&response);
265 OCRepPayloadDestroy(payload);
270 HandleBatchInterface(OCEntityHandlerRequest *ehRequest)
272 OCStackResult stackRet = OC_STACK_OK;
273 OCEntityHandlerResult ehResult = OC_EH_ERROR;
274 OCResource * collResource = (OCResource *) ehRequest->resource;
276 OCRepPayload* payload = OCRepPayloadCreate();
279 stackRet = OC_STACK_NO_MEMORY;
282 if(stackRet == OC_STACK_OK)
284 OCRepPayloadSetUri(payload, collResource->uri);
287 if(stackRet == OC_STACK_OK)
289 OCEntityHandlerResponse response = {};
290 response.ehResult = OC_EH_OK;
291 response.payload = (OCPayload*)payload;
292 response.persistentBufferFlag = 0;
293 response.requestHandle = (OCRequestHandle) ehRequest->requestHandle;
294 response.resourceHandle = (OCResourceHandle) collResource;
295 stackRet = OCDoResponse(&response);
298 if (stackRet == OC_STACK_OK)
300 for (int i = 0; i < MAX_CONTAINED_RESOURCES; i++)
302 OCResource* temp = collResource->rsrcResources[i];
305 // Note that all entity handlers called through a collection
306 // will get the same pointer to ehRequest, the only difference
307 // is ehRequest->resource
308 ehRequest->resource = (OCResourceHandle) temp;
310 ehResult = temp->entityHandler(OC_REQUEST_FLAG, ehRequest,
311 temp->entityHandlerCallbackParam);
313 // The default collection handler is returning as OK
314 if(stackRet != OC_STACK_SLOW_RESOURCE)
316 stackRet = OC_STACK_OK;
318 // if a single resource is slow, then entire response will be treated
320 if(ehResult == OC_EH_SLOW)
322 OC_LOG(INFO, TAG, PCF("This is a slow resource"));
323 ((OCServerRequest *)ehRequest->requestHandle)->slowFlag = 1;
324 stackRet = EntityHandlerCodeToOCStackCode(ehResult);
332 ehRequest->resource = (OCResourceHandle) collResource;
337 uint8_t GetNumOfResourcesInCollection (OCResource *resource)
342 for (int i = 0; i < MAX_CONTAINED_RESOURCES; i++)
344 if (resource->rsrcResources[i])
358 OCStackResult DefaultCollectionEntityHandler (OCEntityHandlerFlag flag,
359 OCEntityHandlerRequest *ehRequest)
361 if(!ehRequest || !ehRequest->query)
363 return OC_STACK_INVALID_PARAM;
366 OCStackResult result = OC_STACK_ERROR;
367 OCStackIfTypes ifQueryParam = STACK_IF_INVALID;
368 char *rtQueryParam = NULL;
370 OC_LOG_V(INFO, TAG, "DefaultCollectionEntityHandler with query %s", ehRequest->query);
372 if (flag != OC_REQUEST_FLAG)
374 return OC_STACK_ERROR;
377 result = ValidateQuery (ehRequest->query,
378 ehRequest->resource, &ifQueryParam, &rtQueryParam);
380 if (result != OC_STACK_OK)
385 if(!((ehRequest->method == OC_REST_GET) ||
386 (ehRequest->method == OC_REST_PUT) ||
387 (ehRequest->method == OC_REST_POST)))
389 return OC_STACK_ERROR;
392 if (ehRequest->method == OC_REST_GET)
394 switch (ifQueryParam)
396 case STACK_IF_DEFAULT:
397 // Get attributes of collection resource and properties of contined resource
398 // M1 release does not support attributes for collection resource, so the GET
399 // operation is same as the GET on LL interface.
400 OC_LOG(INFO, TAG, PCF("STACK_IF_DEFAULT"));
401 return HandleLinkedListInterface(ehRequest, STACK_RES_DISCOVERY_NOFILTER, NULL);
404 OC_LOG(INFO, TAG, PCF("STACK_IF_LL"));
405 return HandleLinkedListInterface(ehRequest, STACK_RES_DISCOVERY_NOFILTER, NULL);
408 OC_LOG(INFO, TAG, PCF("STACK_IF_BATCH"));
409 ((OCServerRequest *)ehRequest->requestHandle)->ehResponseHandler =
410 HandleAggregateResponse;
412 ((OCServerRequest *)ehRequest->requestHandle)->numResponses =
413 GetNumOfResourcesInCollection((OCResource *)ehRequest->resource) + 1;
415 return HandleBatchInterface(ehRequest);
418 return BuildCollectionGroupActionJSONResponse(OC_REST_GET/*flag*/,
419 (OCResource *) ehRequest->resource, ehRequest);
421 return OC_STACK_ERROR;
424 else if (ehRequest->method == OC_REST_PUT)
426 switch (ifQueryParam)
428 case STACK_IF_DEFAULT:
429 // M1 release does not support PUT on default interface
430 return OC_STACK_ERROR;
433 // LL interface only supports GET
434 return OC_STACK_ERROR;
437 ((OCServerRequest *)ehRequest->requestHandle)->ehResponseHandler =
438 HandleAggregateResponse;
439 ((OCServerRequest *)ehRequest->requestHandle)->numResponses =
440 GetNumOfResourcesInCollection((OCResource *)ehRequest->resource) + 1;
441 return HandleBatchInterface(ehRequest);
445 OC_LOG(INFO, TAG, PCF("IF_COLLECTION PUT with request ::\n"));
446 OC_LOG_PAYLOAD(INFO, TAG, ehRequest->payload);
447 return BuildCollectionGroupActionJSONResponse(OC_REST_PUT/*flag*/,
448 (OCResource *) ehRequest->resource, ehRequest);
451 return OC_STACK_ERROR;
454 else if (ehRequest->method == OC_REST_POST)
457 switch (ifQueryParam)
461 OC_LOG(INFO, TAG, PCF("IF_COLLECTION POST with request ::\n"));
462 OC_LOG_PAYLOAD(INFO, TAG, ehRequest->payload);
463 return BuildCollectionGroupActionJSONResponse(OC_REST_POST/*flag*/,
464 (OCResource *) ehRequest->resource, ehRequest);
467 return OC_STACK_ERROR;
470 else if (ehRequest->method == OC_REST_POST)
473 if(ifQueryParam == STACK_IF_GROUP)
475 OC_LOG(INFO, TAG, PCF("IF_COLLECTION POST with request ::\n"));
476 OC_LOG_PAYLOAD(INFO, TAG, ehRequest->payload);
477 return BuildCollectionGroupActionJSONResponse(OC_REST_POST/*flag*/,
478 (OCResource *) ehRequest->resource, ehRequest);
482 return OC_STACK_ERROR;