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
34 #ifdef WITH_GROUPACTION
38 #define TAG PCF("occollection")
40 #define NUM_PARAM_IN_QUERY 2
42 static OCStackResult CheckRTParamSupport(const OCResource* resource, const char* rtPtr)
44 OCResourceType* rTPointer = resource->rsrcType;
47 if( strcmp (rTPointer->resourcetypename, rtPtr) == 0)
50 rTPointer = rTPointer->next;
52 return OC_STACK_ERROR;
55 static OCStackResult CheckIFParamSupport(const OCResource* resource, const char* ifPtr)
57 OCResourceInterface* iFPointer = resource->rsrcInterface;
60 if( strcmp (iFPointer->name, ifPtr) == 0)
63 iFPointer = iFPointer->next;
65 return OC_STACK_ERROR;
69 ValidateQuery (const unsigned char *query, OCResourceHandle resource,
70 OCStackIfTypes *ifParam, char **rtParam)
72 uint8_t numFields = 0, numParam;
74 //TODO: Query and URL validation is being done for virtual resource case
75 // using ValidateUrlQuery function. We should be able to merge it with this
77 OC_LOG(INFO, TAG, PCF("Entering ValidateQuery"));
80 return OC_STACK_ERROR;
84 // Query string is empty
85 OC_LOG_V(INFO, TAG, PCF("Empty query string, use default IF and RT"));
86 *ifParam = STACK_IF_DEFAULT;
87 *rtParam = (char *) OCGetResourceTypeName (resource, 0);
91 // Break the query string to validate it and determine IF and RT parameters
92 // Validate there are atmost 2 parameters in string and that one is 'if' and other 'rt'
93 char *endStr, *ifPtr = NULL, *rtPtr = NULL;
94 char *token = strtok_r ((char *)query, "&", &endStr);
96 // External loop breaks query string into fields using the & separator
101 char *innerToken = strtok_r (token, "=", &endToken);
104 // Internal loop parses the field to extract values (parameters) assigned to each field
105 while (innerToken != NULL)
108 if (strcmp (innerToken, OC_RSRVD_INTERFACE) == 0)
110 // Determine the value of IF parameter
111 innerToken = strtok_r (NULL, "=", &endToken);
113 } else if (strcmp (innerToken, OC_RSRVD_RESOURCE_TYPE) == 0) {
114 // Determine the value of RT parameter
115 innerToken = strtok_r (NULL, "=", &endToken);
118 innerToken = strtok_r (NULL, "=", &endToken);
123 // Query parameter should be of the form if=<string>. String should not have & or =
124 return OC_STACK_INVALID_QUERY;
126 token = strtok_r (NULL, "&", &endStr);
128 if (numFields > NUM_PARAM_IN_QUERY)
130 // M1 release supports one IF value, one RT value and no other params
131 return OC_STACK_INVALID_QUERY;
136 if(CheckIFParamSupport((OCResource *)resource, ifPtr) != OC_STACK_OK)
138 return OC_STACK_INVALID_QUERY;
140 if (strcmp (ifPtr, OC_RSRVD_INTERFACE_DEFAULT) == 0)
142 *ifParam = STACK_IF_DEFAULT;
144 else if (strcmp (ifPtr, OC_RSRVD_INTERFACE_LL) == 0)
146 *ifParam = STACK_IF_LL;
148 else if (strcmp (ifPtr, OC_RSRVD_INTERFACE_BATCH) == 0)
150 *ifParam = STACK_IF_BATCH;
152 else if(strcmp (ifPtr, OC_RSRVD_INTERFACE_GROUP) == 0)
154 *ifParam = STACK_IF_GROUP;
158 return OC_STACK_ERROR;
163 // IF not specified in query, use default IF
164 *ifParam = STACK_IF_DEFAULT;
169 if (CheckRTParamSupport((OCResource *)resource, rtPtr) == OC_STACK_OK)
175 return OC_STACK_INVALID_QUERY;
180 // RT not specified in query. Use the first resource type for the resource as default.
181 *rtParam = (char *) OCGetResourceTypeName (resource, 0);
183 OC_LOG_V(INFO, TAG, "Query params: IF = %d, RT = %s", *ifParam, *rtParam);
189 static OCStackResult BuildRootResourceJSON(OCResource *resource,
190 unsigned char * bufferPtr, uint16_t *remaining)
192 OCStackResult ret = OC_STACK_ERROR;
197 OC_LOG(INFO, TAG, PCF("Entering BuildRootResourceJSON"));
198 resObj = cJSON_CreateObject();
202 cJSON_AddItemToObject (resObj, OC_RSRVD_HREF, cJSON_CreateString(resource->uri));
204 jsonStr = cJSON_PrintUnformatted (resObj);
205 jsonLen = strlen(jsonStr);
206 if (jsonLen < *remaining)
208 strcpy((char*) bufferPtr, jsonStr);
209 *remaining -= jsonLen;
210 bufferPtr += jsonLen;
214 cJSON_Delete (resObj);
222 HandleLinkedListInterface(OCEntityHandlerRequest *ehRequest,
223 uint8_t filterOn, char *filterValue)
225 OCStackResult ret = OC_STACK_ERROR;
226 unsigned char jsonbuffer[MAX_RESPONSE_LENGTH] = {0};
227 size_t jsonbufferLength = 0;
228 uint16_t remaining = 0;
229 unsigned char * ptr = NULL;
230 OCResource * collResource = (OCResource *) ehRequest->resource;
233 remaining = MAX_RESPONSE_LENGTH;
235 ret = BuildRootResourceJSON(collResource, ptr, &remaining);
236 ptr += strlen((char*)ptr);
238 if (ret == OC_STACK_OK && remaining >= (sizeof(OC_JSON_SEPARATOR) + 1))
240 *ptr = OC_JSON_SEPARATOR;
246 ret = OC_STACK_ERROR;
250 if (ret == OC_STACK_OK)
252 for (int i = 0; i < MAX_CONTAINED_RESOURCES; i++)
254 OCResource* temp = collResource->rsrcResources[i];
257 ret = BuildVirtualResourceResponse(temp, filterOn, filterValue, (char*)ptr, &remaining);
258 if (ret != OC_STACK_OK)
262 ptr += strlen((char*)ptr);
263 if (collResource->rsrcResources[i+1] && remaining > sizeof(OC_JSON_SEPARATOR))
265 *ptr = OC_JSON_SEPARATOR;
278 jsonbufferLength = strlen((const char *)jsonbuffer);
279 if(ret == OC_STACK_OK && jsonbufferLength)
281 OCEntityHandlerResponse response = {0};
282 response.ehResult = OC_EH_OK;
283 response.payload = jsonbuffer;
284 response.payloadSize = jsonbufferLength + 1;
285 response.persistentBufferFlag = 0;
286 response.requestHandle = (OCRequestHandle) ehRequest->requestHandle;
287 response.resourceHandle = (OCResourceHandle) collResource;
288 ret = OCDoResponse(&response);
294 HandleBatchInterface(OCEntityHandlerRequest *ehRequest)
296 OCStackResult stackRet = OC_STACK_ERROR;
297 OCEntityHandlerResult ehResult = OC_EH_ERROR;
298 unsigned char jsonbuffer[MAX_RESPONSE_LENGTH] = {0};
299 size_t jsonbufferLength = 0;
300 uint16_t remaining = 0;
301 unsigned char * ptr = NULL;
302 OCResource * collResource = (OCResource *) ehRequest->resource;
305 remaining = MAX_RESPONSE_LENGTH;
307 stackRet = BuildRootResourceJSON(collResource, ptr, &remaining);
308 ptr += strlen((char*)ptr);
311 jsonbufferLength = strlen((const char *)jsonbuffer);
314 OCEntityHandlerResponse response = {0};
315 response.ehResult = OC_EH_OK;
316 response.payload = jsonbuffer;
317 response.payloadSize = jsonbufferLength + 1;
318 response.persistentBufferFlag = 0;
319 response.requestHandle = (OCRequestHandle) ehRequest->requestHandle;
320 response.resourceHandle = (OCResourceHandle) collResource;
321 stackRet = OCDoResponse(&response);
324 if (stackRet == OC_STACK_OK)
326 for (int i = 0; i < MAX_CONTAINED_RESOURCES; i++)
328 OCResource* temp = collResource->rsrcResources[i];
331 // Note that all entity handlers called through a collection
332 // will get the same pointer to ehRequest, the only difference
333 // is ehRequest->resource
334 ehRequest->resource = (OCResourceHandle) temp;
336 ehResult = temp->entityHandler(OC_REQUEST_FLAG, ehRequest);
338 // The default collection handler is returning as OK
339 if(stackRet != OC_STACK_SLOW_RESOURCE)
341 stackRet = OC_STACK_OK;
343 // if a single resource is slow, then entire response will be treated
345 if(ehResult == OC_EH_SLOW)
347 OC_LOG(INFO, TAG, PCF("This is a slow resource"));
348 ((OCServerRequest *)ehRequest->requestHandle)->slowFlag = 1;
349 stackRet = EntityHandlerCodeToOCStackCode(ehResult);
357 ehRequest->resource = (OCResourceHandle) collResource;
362 uint8_t GetNumOfResourcesInCollection (OCResource *resource)
365 for (int i = 0; i < MAX_CONTAINED_RESOURCES; i++)
367 if (resource->rsrcResources[i])
376 OCStackResult DefaultCollectionEntityHandler (OCEntityHandlerFlag flag,
377 OCEntityHandlerRequest *ehRequest)
379 OCStackResult result = OC_STACK_ERROR;
380 OCStackIfTypes ifQueryParam = STACK_IF_INVALID;
381 char *rtQueryParam = NULL;
383 OC_LOG_V(INFO, TAG, "DefaultCollectionEntityHandler with query %s", ehRequest->query);
385 if (flag != OC_REQUEST_FLAG)
386 return OC_STACK_ERROR;
388 result = ValidateQuery ((const unsigned char *)ehRequest->query,
389 ehRequest->resource, &ifQueryParam, &rtQueryParam);
391 if (result != OC_STACK_OK)
395 if(!((ehRequest->method == OC_REST_GET) ||
396 (ehRequest->method == OC_REST_PUT) ||
397 (ehRequest->method == OC_REST_POST)))
398 return OC_STACK_ERROR;
400 if (ehRequest->method == OC_REST_GET)
402 switch (ifQueryParam)
404 case STACK_IF_DEFAULT:
405 // Get attributes of collection resource and properties of contined resource
406 // M1 release does not support attributes for collection resource, so the GET
407 // operation is same as the GET on LL interface.
408 OC_LOG(INFO, TAG, PCF("STACK_IF_DEFAULT"));
409 return HandleLinkedListInterface(ehRequest, STACK_RES_DISCOVERY_NOFILTER, NULL);
412 OC_LOG(INFO, TAG, PCF("STACK_IF_LL"));
413 return HandleLinkedListInterface(ehRequest, STACK_RES_DISCOVERY_NOFILTER, NULL);
416 OC_LOG(INFO, TAG, PCF("STACK_IF_BATCH"));
417 ((OCServerRequest *)ehRequest->requestHandle)->ehResponseHandler = HandleAggregateResponse;
418 ((OCServerRequest *)ehRequest->requestHandle)->numResponses =
419 GetNumOfResourcesInCollection((OCResource *)ehRequest->resource) + 1;
420 return HandleBatchInterface(ehRequest);
421 #ifdef WITH_GROUPACTION
423 return BuildCollectionGroupActionJSONResponse(OC_REST_GET/*flag*/, (OCResource *)ehRequest->resource,
425 #endif // WITH_GROUPACTION
427 return OC_STACK_ERROR;
429 } else if (ehRequest->method == OC_REST_PUT) {
430 switch (ifQueryParam)
432 case STACK_IF_DEFAULT:
433 // M1 release does not support PUT on default interface
434 return OC_STACK_ERROR;
437 // LL interface only supports GET
438 return OC_STACK_ERROR;
441 ((OCServerRequest *)ehRequest->requestHandle)->ehResponseHandler = HandleAggregateResponse;
442 ((OCServerRequest *)ehRequest->requestHandle)->numResponses =
443 GetNumOfResourcesInCollection((OCResource *)ehRequest->resource) + 1;
444 return HandleBatchInterface(ehRequest);
447 #ifdef WITH_GROUPACTION
450 OC_LOG_V(INFO, TAG, "IF_COLLECTION PUT with request ::\n%s\n ", ehRequest->reqJSONPayload);
451 printf("PUT ::\n%s\n", ehRequest->reqJSONPayload);
452 return BuildCollectionGroupActionJSONResponse(OC_REST_PUT/*flag*/, (OCResource *)ehRequest->resource, ehRequest);
454 #endif // WITH_GROUPACTION
456 return OC_STACK_ERROR;
459 #ifdef WITH_GROUPACTION
460 else if(ehRequest->method == OC_REST_POST) {
466 OC_LOG_V(INFO, TAG, "IF_COLLECTION POST with request :: \n%s\n ", ehRequest->reqJSONPayload);
467 printf("POST ::\n%s\n", ehRequest->reqJSONPayload);
468 return BuildCollectionGroupActionJSONResponse(OC_REST_POST/*flag*/, (OCResource *)ehRequest->resource, ehRequest);
471 return OC_STACK_ERROR;
474 #endif // WITH_GROUPACTION