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"
38 #include "payload_logging.h"
43 #define WITH_GROUPACTION 1
47 #define TAG "OIC_RI_COLLECTION"
49 #define NUM_PARAM_IN_QUERY 2 // The expected number of parameters in a query
50 #define NUM_FIELDS_IN_QUERY 2 // The expected number of fields in a query
52 #include "platform_features.h"
54 static OCStackResult CheckRTParamSupport(const OCResource* resource, const char* rtPtr)
56 if (!resource || !rtPtr)
58 return OC_STACK_INVALID_PARAM;
61 OCResourceType* rTPointer = resource->rsrcType;
64 if (strcmp(rTPointer->resourcetypename, rtPtr) == 0)
69 rTPointer = rTPointer->next;
71 return OC_STACK_ERROR;
74 static OCStackResult CheckIFParamSupport(const OCResource* resource, const char* ifPtr)
76 if (!resource || !ifPtr)
78 return OC_STACK_INVALID_PARAM;
81 OCResourceInterface* iFPointer = resource->rsrcInterface;
84 if (strcmp(iFPointer->name, ifPtr) == 0)
89 iFPointer = iFPointer->next;
91 return OC_STACK_ERROR;
95 ValidateQuery (const char *query, OCResourceHandle resource,
96 OCStackIfTypes *ifParam, char **rtParam)
98 uint8_t numFields = 0;
101 //TODO: Query and URL validation is being done for virtual resource case
102 // using ValidateUrlQuery function. We should be able to merge it with this
104 OIC_LOG(INFO, TAG, "Entering ValidateQuery");
108 return OC_STACK_ERROR;
111 if (!ifParam || !rtParam)
113 return OC_STACK_INVALID_PARAM;
118 // Query string is empty
119 OIC_LOG(INFO, TAG, "Empty query string, use default IF and RT");
120 *ifParam = STACK_IF_DEFAULT;
121 *rtParam = (char *) OCGetResourceTypeName (resource, 0);
125 // Break the query string to validate it and determine IF and RT parameters
126 // Validate there are atmost 2 parameters in string and that one is 'if' and other 'rt'
127 // separated by token '&' or ';'. Stack will accept both the versions.
129 char *endStr, *ifPtr = NULL, *rtPtr = NULL;
130 char *token = strtok_r ((char *)query, OC_QUERY_SEPARATOR , &endStr);
132 // External loop breaks query string into fields using the & separator
133 while (token != NULL)
137 char *innerToken = strtok_r (token, "=", &endToken);
140 // Internal loop parses the field to extract values (parameters) assigned to each field
141 while (innerToken != NULL)
144 if (strncmp (innerToken, OC_RSRVD_INTERFACE, sizeof(OC_RSRVD_INTERFACE)) == 0)
146 // Determine the value of IF parameter
147 innerToken = strtok_r (NULL, "=", &endToken);
150 else if (strcmp (innerToken, OC_RSRVD_RESOURCE_TYPE) == 0)
152 // Determine the value of RT parameter
153 innerToken = strtok_r (NULL, "=", &endToken);
158 innerToken = strtok_r (NULL, "=", &endToken);
161 if (numParam != NUM_PARAM_IN_QUERY)
163 // Query parameter should be of the form if=<string>. String should not have & or =
164 return OC_STACK_INVALID_QUERY;
166 token = strtok_r (NULL, OC_QUERY_SEPARATOR, &endStr);
169 if (numFields > NUM_FIELDS_IN_QUERY)
171 // current release supports one IF value, one RT value and no other params
172 return OC_STACK_INVALID_QUERY;
177 if (CheckIFParamSupport((OCResource *)resource, ifPtr) != OC_STACK_OK)
179 return OC_STACK_INVALID_QUERY;
181 if (strcmp (ifPtr, OC_RSRVD_INTERFACE_DEFAULT) == 0)
183 *ifParam = STACK_IF_DEFAULT;
185 else if (strcmp (ifPtr, OC_RSRVD_INTERFACE_LL) == 0)
187 *ifParam = STACK_IF_LL;
189 else if (strcmp (ifPtr, OC_RSRVD_INTERFACE_BATCH) == 0)
191 *ifParam = STACK_IF_BATCH;
193 else if (strcmp (ifPtr, OC_RSRVD_INTERFACE_GROUP) == 0)
195 *ifParam = STACK_IF_GROUP;
199 return OC_STACK_ERROR;
204 // IF not specified in query, use default IF
205 *ifParam = STACK_IF_DEFAULT;
210 if (CheckRTParamSupport((OCResource *)resource, rtPtr) == OC_STACK_OK)
216 return OC_STACK_INVALID_QUERY;
221 // RT not specified in query. Use the first resource type for the resource as default.
222 *rtParam = (char *) OCGetResourceTypeName (resource, 0);
224 OIC_LOG_V(INFO, TAG, "Query params: IF = %d, RT = %s", *ifParam, *rtParam);
230 HandleLinkedListInterface(OCEntityHandlerRequest *ehRequest,
238 return OC_STACK_INVALID_PARAM;
241 OCResource *collResource = (OCResource *)ehRequest->resource;
242 OCChildResource *tempChildResource = NULL;
243 OCRepPayload* payload = NULL;
247 return OC_STACK_INVALID_PARAM;
250 OCStackResult ret = BuildResponseRepresentation(collResource, &payload);
251 if (ret == OC_STACK_OK)
253 tempChildResource = collResource->rsrcChildResourcesHead;
254 while (tempChildResource && ret == OC_STACK_OK)
256 OCResource* temp = tempChildResource->rsrcResource;
259 //TODO : Add resource type filtering once collections
260 // start supporting queries.
261 ret = BuildResponseRepresentation(temp, &payload);
264 tempChildResource = tempChildResource->next;
268 if (ret == OC_STACK_OK)
270 OCEntityHandlerResponse response = {0};
271 response.ehResult = OC_EH_OK;
272 response.payload = (OCPayload*)payload;
273 response.persistentBufferFlag = 0;
274 response.requestHandle = (OCRequestHandle) ehRequest->requestHandle;
275 response.resourceHandle = (OCResourceHandle) collResource;
276 ret = OCDoResponse(&response);
279 OCRepPayloadDestroy(payload);
284 HandleBatchInterface(OCEntityHandlerRequest *ehRequest)
288 return OC_STACK_INVALID_PARAM;
291 OCResource * collResource = (OCResource *) ehRequest->resource;
293 OCRepPayload* payload = OCRepPayloadCreate();
296 return OC_STACK_NO_MEMORY;
301 OCRepPayloadSetUri(payload, collResource->uri);
304 OCEntityHandlerResponse response = {0};
305 response.ehResult = OC_EH_OK;
306 response.payload = (OCPayload*)payload;
307 response.persistentBufferFlag = 0;
308 response.requestHandle = (OCRequestHandle) ehRequest->requestHandle;
309 response.resourceHandle = (OCResourceHandle) collResource;
310 OCStackResult stackRet = OCDoResponse(&response);
312 if (stackRet == OC_STACK_OK)
314 OCChildResource *tempChildResource = (collResource) ? collResource->rsrcChildResourcesHead
316 while(tempChildResource)
318 OCResource* tempRsrcResource = tempChildResource->rsrcResource;
320 if (tempRsrcResource)
322 // Note that all entity handlers called through a collection
323 // will get the same pointer to ehRequest, the only difference
324 // is ehRequest->resource
325 ehRequest->resource = (OCResourceHandle) tempRsrcResource;
327 OCEntityHandlerResult ehResult = tempRsrcResource->entityHandler(OC_REQUEST_FLAG,
328 ehRequest, tempRsrcResource->entityHandlerCallbackParam);
330 // The default collection handler is returning as OK
331 if (stackRet != OC_STACK_SLOW_RESOURCE)
333 stackRet = OC_STACK_OK;
335 // if a single resource is slow, then entire response will be treated
337 if (ehResult == OC_EH_SLOW)
339 OIC_LOG(INFO, TAG, "This is a slow resource");
340 ((OCServerRequest *)ehRequest->requestHandle)->slowFlag = 1;
341 stackRet = EntityHandlerCodeToOCStackCode(ehResult);
349 tempChildResource = tempChildResource->next;
353 ehRequest->resource = (OCResourceHandle) collResource;
358 uint8_t GetNumOfResourcesInCollection (OCResource *resource)
363 OCChildResource *tempChildResource = NULL;
365 tempChildResource = resource->rsrcChildResourcesHead;
367 while(tempChildResource)
370 tempChildResource = tempChildResource->next;
382 OCStackResult DefaultCollectionEntityHandler (OCEntityHandlerFlag flag,
383 OCEntityHandlerRequest *ehRequest)
385 if (!ehRequest || !ehRequest->query)
387 return OC_STACK_INVALID_PARAM;
390 OIC_LOG_V(INFO, TAG, "DefaultCollectionEntityHandler with query %s", ehRequest->query);
392 if (flag != OC_REQUEST_FLAG)
394 return OC_STACK_ERROR;
397 OCStackIfTypes ifQueryParam = STACK_IF_INVALID;
398 char *rtQueryParam = NULL;
399 OCStackResult result = ValidateQuery (ehRequest->query,
400 ehRequest->resource, &ifQueryParam, &rtQueryParam);
402 if (result != OC_STACK_OK)
407 switch (ehRequest->method)
410 switch (ifQueryParam)
412 case STACK_IF_DEFAULT:
413 // Get attributes of collection resource and properties of contained resources
414 // M1 release does not support attributes for collection resource, so the GET
415 // operation is same as the GET on LL interface.
416 OIC_LOG(INFO, TAG, "STACK_IF_DEFAULT");
417 return HandleLinkedListInterface(ehRequest, STACK_RES_DISCOVERY_NOFILTER, NULL);
420 OIC_LOG(INFO, TAG, "STACK_IF_LL");
421 return HandleLinkedListInterface(ehRequest, STACK_RES_DISCOVERY_NOFILTER, NULL);
424 OIC_LOG(INFO, TAG, "STACK_IF_BATCH");
425 ((OCServerRequest *)ehRequest->requestHandle)->ehResponseHandler =
426 HandleAggregateResponse;
428 ((OCServerRequest *)ehRequest->requestHandle)->numResponses =
429 GetNumOfResourcesInCollection((OCResource *)ehRequest->resource) + 1;
431 return HandleBatchInterface(ehRequest);
434 return BuildCollectionGroupActionCBORResponse(OC_REST_GET/*flag*/,
435 (OCResource *) ehRequest->resource, ehRequest);
438 return OC_STACK_ERROR;
442 switch (ifQueryParam)
444 case STACK_IF_DEFAULT:
445 // M1 release does not support PUT on default interface
446 return OC_STACK_ERROR;
449 // LL interface only supports GET
450 return OC_STACK_ERROR;
453 ((OCServerRequest *)ehRequest->requestHandle)->ehResponseHandler =
454 HandleAggregateResponse;
455 ((OCServerRequest *)ehRequest->requestHandle)->numResponses =
456 GetNumOfResourcesInCollection((OCResource *)ehRequest->resource) + 1;
457 return HandleBatchInterface(ehRequest);
460 OIC_LOG(INFO, TAG, "IF_COLLECTION PUT with request ::\n");
461 OIC_LOG_PAYLOAD(INFO, ehRequest->payload);
462 return BuildCollectionGroupActionCBORResponse(OC_REST_PUT/*flag*/,
463 (OCResource *) ehRequest->resource, ehRequest);
466 return OC_STACK_ERROR;
470 switch (ifQueryParam)
472 case STACK_IF_DEFAULT:
473 // M1 release does not support POST on default interface
474 return OC_STACK_ERROR;
477 // LL interface only supports GET
478 return OC_STACK_ERROR;
481 ((OCServerRequest *)ehRequest->requestHandle)->ehResponseHandler =
482 HandleAggregateResponse;
483 ((OCServerRequest *)ehRequest->requestHandle)->numResponses =
484 GetNumOfResourcesInCollection((OCResource *)ehRequest->resource) + 1;
485 return HandleBatchInterface(ehRequest);
488 OIC_LOG(INFO, TAG, "IF_COLLECTION POST with request ::\n");
489 OIC_LOG_PAYLOAD(INFO, ehRequest->payload);
490 return BuildCollectionGroupActionCBORResponse(OC_REST_POST/*flag*/,
491 (OCResource *) ehRequest->resource, ehRequest);
494 return OC_STACK_ERROR;
498 // TODO implement DELETE accordingly to the desired behavior
499 return OC_STACK_ERROR;
502 return OC_STACK_ERROR;