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 "occollection"
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 static OCStackResult CheckRTParamSupport(const OCResource* resource, const char* rtPtr)
54 if(!resource || !rtPtr)
56 return OC_STACK_INVALID_PARAM;
59 OCResourceType* rTPointer = resource->rsrcType;
62 if( strcmp (rTPointer->resourcetypename, rtPtr) == 0)
67 rTPointer = rTPointer->next;
69 return OC_STACK_ERROR;
72 static OCStackResult CheckIFParamSupport(const OCResource* resource, const char* ifPtr)
74 if(!resource || !ifPtr)
76 return OC_STACK_INVALID_PARAM;
79 OCResourceInterface* iFPointer = resource->rsrcInterface;
82 if( strcmp (iFPointer->name, ifPtr) == 0)
87 iFPointer = iFPointer->next;
89 return OC_STACK_ERROR;
93 ValidateQuery (const char *query, OCResourceHandle resource,
94 OCStackIfTypes *ifParam, char **rtParam)
96 uint8_t numFields = 0;
99 //TODO: Query and URL validation is being done for virtual resource case
100 // using ValidateUrlQuery function. We should be able to merge it with this
102 OC_LOG(INFO, TAG, "Entering ValidateQuery");
106 return OC_STACK_ERROR;
109 if(!ifParam || !rtParam)
111 return OC_STACK_INVALID_PARAM;
116 // Query string is empty
117 OC_LOG(INFO, TAG, "Empty query string, use default IF and RT");
118 *ifParam = STACK_IF_DEFAULT;
119 *rtParam = (char *) OCGetResourceTypeName (resource, 0);
123 // Break the query string to validate it and determine IF and RT parameters
124 // Validate there are atmost 2 parameters in string and that one is 'if' and other 'rt'
125 // separated by token '&' or ';'. Stack will accept both the versions.
127 char *endStr, *ifPtr = NULL, *rtPtr = NULL;
128 char *token = strtok_r ((char *)query, OC_QUERY_SEPARATOR , &endStr);
130 // External loop breaks query string into fields using the & separator
131 while (token != NULL)
135 char *innerToken = strtok_r (token, "=", &endToken);
138 // Internal loop parses the field to extract values (parameters) assigned to each field
139 while (innerToken != NULL)
142 if (strncmp (innerToken, OC_RSRVD_INTERFACE, sizeof(OC_RSRVD_INTERFACE)) == 0)
144 // Determine the value of IF parameter
145 innerToken = strtok_r (NULL, "=", &endToken);
148 else if (strcmp (innerToken, OC_RSRVD_RESOURCE_TYPE) == 0)
150 // Determine the value of RT parameter
151 innerToken = strtok_r (NULL, "=", &endToken);
156 innerToken = strtok_r (NULL, "=", &endToken);
159 if (numParam != NUM_PARAM_IN_QUERY)
161 // Query parameter should be of the form if=<string>. String should not have & or =
162 return OC_STACK_INVALID_QUERY;
164 token = strtok_r (NULL, OC_QUERY_SEPARATOR, &endStr);
167 if (numFields > NUM_FIELDS_IN_QUERY)
169 // current release supports one IF value, one RT value and no other params
170 return OC_STACK_INVALID_QUERY;
175 if(CheckIFParamSupport((OCResource *)resource, ifPtr) != OC_STACK_OK)
177 return OC_STACK_INVALID_QUERY;
179 if (strcmp (ifPtr, OC_RSRVD_INTERFACE_DEFAULT) == 0)
181 *ifParam = STACK_IF_DEFAULT;
183 else if (strcmp (ifPtr, OC_RSRVD_INTERFACE_LL) == 0)
185 *ifParam = STACK_IF_LL;
187 else if (strcmp (ifPtr, OC_RSRVD_INTERFACE_BATCH) == 0)
189 *ifParam = STACK_IF_BATCH;
191 else if(strcmp (ifPtr, OC_RSRVD_INTERFACE_GROUP) == 0)
193 *ifParam = STACK_IF_GROUP;
197 return OC_STACK_ERROR;
202 // IF not specified in query, use default IF
203 *ifParam = STACK_IF_DEFAULT;
208 if (CheckRTParamSupport((OCResource *)resource, rtPtr) == OC_STACK_OK)
214 return OC_STACK_INVALID_QUERY;
219 // RT not specified in query. Use the first resource type for the resource as default.
220 *rtParam = (char *) OCGetResourceTypeName (resource, 0);
222 OC_LOG_V(INFO, TAG, "Query params: IF = %d, RT = %s", *ifParam, *rtParam);
228 HandleLinkedListInterface(OCEntityHandlerRequest *ehRequest,
236 return OC_STACK_INVALID_PARAM;
239 OCStackResult ret = OC_STACK_OK;
240 OCResource *collResource = (OCResource *)ehRequest->resource;
242 OCRepPayload* payload = NULL;
244 if(ret == OC_STACK_OK)
246 ret = BuildResponseRepresentation(collResource, &payload);
249 if (ret == OC_STACK_OK)
251 for (int i = 0; i < MAX_CONTAINED_RESOURCES && ret == OC_STACK_OK; i++)
253 OCResource* temp = collResource->rsrcResources[i];
256 //TODO : Add resource type filtering once collections
257 // start supporting queries.
258 ret = BuildResponseRepresentation(temp, &payload);
263 if(ret == OC_STACK_OK)
265 OCEntityHandlerResponse response = {0};
266 response.ehResult = OC_EH_OK;
267 response.payload = (OCPayload*)payload;
268 response.persistentBufferFlag = 0;
269 response.requestHandle = (OCRequestHandle) ehRequest->requestHandle;
270 response.resourceHandle = (OCResourceHandle) collResource;
271 ret = OCDoResponse(&response);
273 OCRepPayloadDestroy(payload);
278 HandleBatchInterface(OCEntityHandlerRequest *ehRequest)
282 return OC_STACK_INVALID_PARAM;
285 OCStackResult stackRet = OC_STACK_OK;
286 OCEntityHandlerResult ehResult = OC_EH_ERROR;
287 OCResource * collResource = (OCResource *) ehRequest->resource;
289 OCRepPayload* payload = OCRepPayloadCreate();
292 stackRet = OC_STACK_NO_MEMORY;
295 if(stackRet == OC_STACK_OK)
299 OCRepPayloadSetUri(payload, collResource->uri);
303 if(stackRet == OC_STACK_OK)
305 OCEntityHandlerResponse response = {0};
306 response.ehResult = OC_EH_OK;
307 response.payload = (OCPayload*)payload;
308 response.persistentBufferFlag = 0;
309 response.requestHandle = (OCRequestHandle) ehRequest->requestHandle;
310 response.resourceHandle = (OCResourceHandle) collResource;
311 stackRet = OCDoResponse(&response);
314 if (stackRet == OC_STACK_OK)
316 for (uint8_t i = 0; i < MAX_CONTAINED_RESOURCES; i++)
318 OCResource* temp = collResource->rsrcResources[i];
321 // Note that all entity handlers called through a collection
322 // will get the same pointer to ehRequest, the only difference
323 // is ehRequest->resource
324 ehRequest->resource = (OCResourceHandle) temp;
326 ehResult = temp->entityHandler(OC_REQUEST_FLAG, ehRequest,
327 temp->entityHandlerCallbackParam);
329 // The default collection handler is returning as OK
330 if(stackRet != OC_STACK_SLOW_RESOURCE)
332 stackRet = OC_STACK_OK;
334 // if a single resource is slow, then entire response will be treated
336 if(ehResult == OC_EH_SLOW)
338 OC_LOG(INFO, TAG, "This is a slow resource");
339 ((OCServerRequest *)ehRequest->requestHandle)->slowFlag = 1;
340 stackRet = EntityHandlerCodeToOCStackCode(ehResult);
348 ehRequest->resource = (OCResourceHandle) collResource;
353 uint8_t GetNumOfResourcesInCollection (OCResource *resource)
358 for (uint8_t i = 0; i < MAX_CONTAINED_RESOURCES; i++)
360 if (resource->rsrcResources[i])
374 OCStackResult DefaultCollectionEntityHandler (OCEntityHandlerFlag flag,
375 OCEntityHandlerRequest *ehRequest)
377 if(!ehRequest || !ehRequest->query)
379 return OC_STACK_INVALID_PARAM;
382 OCStackResult result = OC_STACK_ERROR;
383 OCStackIfTypes ifQueryParam = STACK_IF_INVALID;
384 char *rtQueryParam = NULL;
386 OC_LOG_V(INFO, TAG, "DefaultCollectionEntityHandler with query %s", ehRequest->query);
388 if (flag != OC_REQUEST_FLAG)
390 return OC_STACK_ERROR;
393 result = ValidateQuery (ehRequest->query,
394 ehRequest->resource, &ifQueryParam, &rtQueryParam);
396 if (result != OC_STACK_OK)
401 switch (ehRequest->method)
404 switch (ifQueryParam)
406 case STACK_IF_DEFAULT:
407 // Get attributes of collection resource and properties of contained resources
408 // M1 release does not support attributes for collection resource, so the GET
409 // operation is same as the GET on LL interface.
410 OC_LOG(INFO, TAG, "STACK_IF_DEFAULT");
411 return HandleLinkedListInterface(ehRequest, STACK_RES_DISCOVERY_NOFILTER, NULL);
414 OC_LOG(INFO, TAG, "STACK_IF_LL");
415 return HandleLinkedListInterface(ehRequest, STACK_RES_DISCOVERY_NOFILTER, NULL);
418 OC_LOG(INFO, TAG, "STACK_IF_BATCH");
419 ((OCServerRequest *)ehRequest->requestHandle)->ehResponseHandler =
420 HandleAggregateResponse;
422 ((OCServerRequest *)ehRequest->requestHandle)->numResponses =
423 GetNumOfResourcesInCollection((OCResource *)ehRequest->resource) + 1;
425 return HandleBatchInterface(ehRequest);
428 return BuildCollectionGroupActionCBORResponse(OC_REST_GET/*flag*/,
429 (OCResource *) ehRequest->resource, ehRequest);
432 return OC_STACK_ERROR;
436 switch (ifQueryParam)
438 case STACK_IF_DEFAULT:
439 // M1 release does not support PUT on default interface
440 return OC_STACK_ERROR;
443 // LL interface only supports GET
444 return OC_STACK_ERROR;
447 ((OCServerRequest *)ehRequest->requestHandle)->ehResponseHandler =
448 HandleAggregateResponse;
449 ((OCServerRequest *)ehRequest->requestHandle)->numResponses =
450 GetNumOfResourcesInCollection((OCResource *)ehRequest->resource) + 1;
451 return HandleBatchInterface(ehRequest);
454 OC_LOG(INFO, TAG, "IF_COLLECTION PUT with request ::\n");
455 OC_LOG_PAYLOAD(INFO, ehRequest->payload);
456 return BuildCollectionGroupActionCBORResponse(OC_REST_PUT/*flag*/,
457 (OCResource *) ehRequest->resource, ehRequest);
460 return OC_STACK_ERROR;
464 switch (ifQueryParam)
466 case STACK_IF_DEFAULT:
467 // M1 release does not support POST on default interface
468 return OC_STACK_ERROR;
471 // LL interface only supports GET
472 return OC_STACK_ERROR;
475 ((OCServerRequest *)ehRequest->requestHandle)->ehResponseHandler =
476 HandleAggregateResponse;
477 ((OCServerRequest *)ehRequest->requestHandle)->numResponses =
478 GetNumOfResourcesInCollection((OCResource *)ehRequest->resource) + 1;
479 return HandleBatchInterface(ehRequest);
482 OC_LOG(INFO, TAG, "IF_COLLECTION POST with request ::\n");
483 OC_LOG_PAYLOAD(INFO, ehRequest->payload);
484 return BuildCollectionGroupActionCBORResponse(OC_REST_POST/*flag*/,
485 (OCResource *) ehRequest->resource, ehRequest);
488 return OC_STACK_ERROR;
492 // TODO implement DELETE accordingly to the desired behavior
493 return OC_STACK_ERROR;
496 return OC_STACK_ERROR;