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 #define _POSIX_C_SOURCE 200112L
24 #include "ocstackinternal.h"
25 #include "ocresourcehandler.h"
32 #define WITH_GROUPACTION 1
36 #define TAG PCF("occollection")
38 #define NUM_PARAM_IN_QUERY 2
40 static OCStackResult CheckRTParamSupport(const OCResource* resource, const char* rtPtr)
42 OCResourceType* rTPointer = resource->rsrcType;
45 if( strcmp (rTPointer->resourcetypename, rtPtr) == 0)
48 rTPointer = rTPointer->next;
50 return OC_STACK_ERROR;
53 static OCStackResult CheckIFParamSupport(const OCResource* resource, const char* ifPtr)
55 OCResourceInterface* iFPointer = resource->rsrcInterface;
58 if( strcmp (iFPointer->name, ifPtr) == 0)
61 iFPointer = iFPointer->next;
63 return OC_STACK_ERROR;
67 ValidateQuery (const unsigned char *query, OCResourceHandle resource,
68 OCStackIfTypes *ifParam, char **rtParam)
70 uint8_t numFields = 0, numParam;
72 //TODO: Query and URL validation is being done for virtual resource case
73 // using ValidateUrlQuery function. We should be able to merge it with this
75 OC_LOG(INFO, TAG, PCF("Entering ValidateQuery"));
78 return OC_STACK_ERROR;
82 // Query string is empty
83 OC_LOG_V(INFO, TAG, PCF("Empty query string, use default IF and RT"));
84 *ifParam = STACK_IF_DEFAULT;
85 *rtParam = (char *) OCGetResourceTypeName (resource, 0);
89 // Break the query string to validate it and determine IF and RT parameters
90 // Validate there are atmost 2 parameters in string and that one is 'if' and other 'rt'
91 char *endStr, *ifPtr = NULL, *rtPtr = NULL;
92 char *token = strtok_r ((char *)query, "&", &endStr);
94 // External loop breaks query string into fields using the & separator
99 char *innerToken = strtok_r (token, "=", &endToken);
102 // Internal loop parses the field to extract values (parameters) assigned to each field
103 while (innerToken != NULL)
106 if (strcmp (innerToken, OC_RSRVD_INTERFACE) == 0)
108 // Determine the value of IF parameter
109 innerToken = strtok_r (NULL, "=", &endToken);
111 } else if (strcmp (innerToken, OC_RSRVD_RESOURCE_TYPE) == 0) {
112 // Determine the value of RT parameter
113 innerToken = strtok_r (NULL, "=", &endToken);
116 innerToken = strtok_r (NULL, "=", &endToken);
121 // Query parameter should be of the form if=<string>. String should not have & or =
122 return OC_STACK_INVALID_QUERY;
124 token = strtok_r (NULL, "&", &endStr);
126 if (numFields > NUM_PARAM_IN_QUERY)
128 // M1 release supports one IF value, one RT value and no other params
129 return OC_STACK_INVALID_QUERY;
134 if(CheckIFParamSupport((OCResource *)resource, ifPtr) != OC_STACK_OK)
136 return OC_STACK_INVALID_QUERY;
138 if (strcmp (ifPtr, OC_RSRVD_INTERFACE_DEFAULT) == 0)
140 *ifParam = STACK_IF_DEFAULT;
142 else if (strcmp (ifPtr, OC_RSRVD_INTERFACE_LL) == 0)
144 *ifParam = STACK_IF_LL;
146 else if (strcmp (ifPtr, OC_RSRVD_INTERFACE_BATCH) == 0)
148 *ifParam = STACK_IF_BATCH;
150 else if(strcmp (ifPtr, OC_RSRVD_INTERFACE_GROUP) == 0)
152 *ifParam = STACK_IF_GROUP;
156 return OC_STACK_ERROR;
161 // IF not specified in query, use default IF
162 *ifParam = STACK_IF_DEFAULT;
167 if (CheckRTParamSupport((OCResource *)resource, rtPtr) == OC_STACK_OK)
173 return OC_STACK_INVALID_QUERY;
178 // RT not specified in query. Use the first resource type for the resource as default.
179 *rtParam = (char *) OCGetResourceTypeName (resource, 0);
181 OC_LOG_V(INFO, TAG, "Query params: IF = %d, RT = %s", *ifParam, *rtParam);
187 static OCStackResult BuildRootResourceJSON(OCResource *resource,
188 unsigned char * bufferPtr, uint16_t *remaining)
190 OCStackResult ret = OC_STACK_ERROR;
195 OC_LOG(INFO, TAG, PCF("Entering BuildRootResourceJSON"));
196 resObj = cJSON_CreateObject();
200 cJSON_AddItemToObject (resObj, OC_RSRVD_HREF, cJSON_CreateString(resource->uri));
202 jsonStr = cJSON_PrintUnformatted (resObj);
203 jsonLen = strlen(jsonStr);
204 if (jsonLen < *remaining)
206 strcpy((char*) bufferPtr, jsonStr);
207 *remaining -= jsonLen;
208 bufferPtr += jsonLen;
212 cJSON_Delete (resObj);
220 HandleLinkedListInterface(OCEntityHandlerRequest *ehRequest,
221 uint8_t filterOn, char *filterValue)
223 OCStackResult ret = OC_STACK_ERROR;
224 unsigned char jsonbuffer[MAX_RESPONSE_LENGTH] = {0};
225 size_t jsonbufferLength = 0;
226 uint16_t remaining = 0;
227 unsigned char * ptr = NULL;
228 OCResource * collResource = (OCResource *) ehRequest->resource;
231 remaining = MAX_RESPONSE_LENGTH;
233 ret = BuildRootResourceJSON(collResource, ptr, &remaining);
234 ptr += strlen((char*)ptr);
236 if (ret == OC_STACK_OK && remaining >= (sizeof(OC_JSON_SEPARATOR) + 1))
238 *ptr = OC_JSON_SEPARATOR;
244 ret = OC_STACK_ERROR;
248 if (ret == OC_STACK_OK)
250 for (int i = 0; i < MAX_CONTAINED_RESOURCES; i++)
252 OCResource* temp = collResource->rsrcResources[i];
256 //TODO : Update needed here to get correct connectivity type
257 //from ServerRequest data structure
258 ret = BuildVirtualResourceResponse(temp, filterOn, filterValue,
259 (char*)ptr, &remaining, CA_WIFI );
261 ret = BuildVirtualResourceResponse(temp, filterOn, filterValue,
262 (char*)ptr, &remaining);
264 if (ret != OC_STACK_OK)
268 ptr += strlen((char*)ptr);
269 if (collResource->rsrcResources[i+1] && remaining > sizeof(OC_JSON_SEPARATOR))
271 *ptr = OC_JSON_SEPARATOR;
284 jsonbufferLength = strlen((const char *)jsonbuffer);
285 if(ret == OC_STACK_OK && jsonbufferLength)
287 OCEntityHandlerResponse response = {0};
288 response.ehResult = OC_EH_OK;
289 response.payload = jsonbuffer;
290 response.payloadSize = jsonbufferLength + 1;
291 response.persistentBufferFlag = 0;
292 response.requestHandle = (OCRequestHandle) ehRequest->requestHandle;
293 response.resourceHandle = (OCResourceHandle) collResource;
294 ret = OCDoResponse(&response);
300 HandleBatchInterface(OCEntityHandlerRequest *ehRequest)
302 OCStackResult stackRet = OC_STACK_ERROR;
303 OCEntityHandlerResult ehResult = OC_EH_ERROR;
304 unsigned char jsonbuffer[MAX_RESPONSE_LENGTH] = {0};
305 size_t jsonbufferLength = 0;
306 uint16_t remaining = 0;
307 unsigned char * ptr = NULL;
308 OCResource * collResource = (OCResource *) ehRequest->resource;
311 remaining = MAX_RESPONSE_LENGTH;
313 stackRet = BuildRootResourceJSON(collResource, ptr, &remaining);
314 ptr += strlen((char*)ptr);
317 jsonbufferLength = strlen((const char *)jsonbuffer);
320 OCEntityHandlerResponse response = {0};
321 response.ehResult = OC_EH_OK;
322 response.payload = jsonbuffer;
323 response.payloadSize = jsonbufferLength + 1;
324 response.persistentBufferFlag = 0;
325 response.requestHandle = (OCRequestHandle) ehRequest->requestHandle;
326 response.resourceHandle = (OCResourceHandle) collResource;
327 stackRet = OCDoResponse(&response);
330 if (stackRet == OC_STACK_OK)
332 for (int i = 0; i < MAX_CONTAINED_RESOURCES; i++)
334 OCResource* temp = collResource->rsrcResources[i];
337 // Note that all entity handlers called through a collection
338 // will get the same pointer to ehRequest, the only difference
339 // is ehRequest->resource
340 ehRequest->resource = (OCResourceHandle) temp;
342 ehResult = temp->entityHandler(OC_REQUEST_FLAG, ehRequest);
344 // The default collection handler is returning as OK
345 if(stackRet != OC_STACK_SLOW_RESOURCE)
347 stackRet = OC_STACK_OK;
349 // if a single resource is slow, then entire response will be treated
351 if(ehResult == OC_EH_SLOW)
353 OC_LOG(INFO, TAG, PCF("This is a slow resource"));
354 ((OCServerRequest *)ehRequest->requestHandle)->slowFlag = 1;
355 stackRet = EntityHandlerCodeToOCStackCode(ehResult);
363 ehRequest->resource = (OCResourceHandle) collResource;
368 uint8_t GetNumOfResourcesInCollection (OCResource *resource)
371 for (int i = 0; i < MAX_CONTAINED_RESOURCES; i++)
373 if (resource->rsrcResources[i])
382 OCStackResult DefaultCollectionEntityHandler (OCEntityHandlerFlag flag,
383 OCEntityHandlerRequest *ehRequest)
385 OCStackResult result = OC_STACK_ERROR;
386 OCStackIfTypes ifQueryParam = STACK_IF_INVALID;
387 char *rtQueryParam = NULL;
389 OC_LOG_V(INFO, TAG, "DefaultCollectionEntityHandler with query %s", ehRequest->query);
391 if (flag != OC_REQUEST_FLAG)
392 return OC_STACK_ERROR;
394 result = ValidateQuery ((const unsigned char *)ehRequest->query,
395 ehRequest->resource, &ifQueryParam, &rtQueryParam);
397 if (result != OC_STACK_OK)
401 if(!((ehRequest->method == OC_REST_GET) ||
402 (ehRequest->method == OC_REST_PUT) ||
403 (ehRequest->method == OC_REST_POST)))
404 return OC_STACK_ERROR;
406 if (ehRequest->method == OC_REST_GET)
408 switch (ifQueryParam)
410 case STACK_IF_DEFAULT:
411 // Get attributes of collection resource and properties of contined resource
412 // M1 release does not support attributes for collection resource, so the GET
413 // operation is same as the GET on LL interface.
414 OC_LOG(INFO, TAG, PCF("STACK_IF_DEFAULT"));
415 return HandleLinkedListInterface(ehRequest, STACK_RES_DISCOVERY_NOFILTER, NULL);
418 OC_LOG(INFO, TAG, PCF("STACK_IF_LL"));
419 return HandleLinkedListInterface(ehRequest, STACK_RES_DISCOVERY_NOFILTER, NULL);
422 OC_LOG(INFO, TAG, PCF("STACK_IF_BATCH"));
423 ((OCServerRequest *)ehRequest->requestHandle)->ehResponseHandler = HandleAggregateResponse;
424 ((OCServerRequest *)ehRequest->requestHandle)->numResponses =
425 GetNumOfResourcesInCollection((OCResource *)ehRequest->resource) + 1;
426 return HandleBatchInterface(ehRequest);
428 return BuildCollectionGroupActionJSONResponse(OC_REST_GET/*flag*/,
429 (OCResource *) ehRequest->resource, ehRequest);
431 return OC_STACK_ERROR;
433 } else if (ehRequest->method == OC_REST_PUT) {
434 switch (ifQueryParam)
436 case STACK_IF_DEFAULT:
437 // M1 release does not support PUT on default interface
438 return OC_STACK_ERROR;
441 // LL interface only supports GET
442 return OC_STACK_ERROR;
445 ((OCServerRequest *)ehRequest->requestHandle)->ehResponseHandler = HandleAggregateResponse;
446 ((OCServerRequest *)ehRequest->requestHandle)->numResponses =
447 GetNumOfResourcesInCollection((OCResource *)ehRequest->resource) + 1;
448 return HandleBatchInterface(ehRequest);
452 OC_LOG_V(INFO, TAG, "IF_COLLECTION PUT with request ::\n%s\n ",
453 ehRequest->reqJSONPayload);
454 return BuildCollectionGroupActionJSONResponse(OC_REST_PUT/*flag*/,
455 (OCResource *) ehRequest->resource, ehRequest);
458 return OC_STACK_ERROR;
461 else if (ehRequest->method == OC_REST_POST)
464 switch (ifQueryParam)
468 OC_LOG_V(INFO, TAG, "IF_COLLECTION POST with request :: \n%s\n ",
469 ehRequest->reqJSONPayload);
470 return BuildCollectionGroupActionJSONResponse(OC_REST_POST/*flag*/,
471 (OCResource *) ehRequest->resource, ehRequest);
474 return OC_STACK_ERROR;