Removed execute permissions from non-executable files.
[platform/upstream/iotivity.git] / resource / csdk / stack / src / occollection.c
1 //******************************************************************
2 //
3 // Copyright 2014 Intel Mobile Communications GmbH All Rights Reserved.
4 //
5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
6 //
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
10 //
11 //      http://www.apache.org/licenses/LICENSE-2.0
12 //
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.
18 //
19 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
20
21 #define _POSIX_C_SOURCE 200112L
22 #include <string.h>
23 #include "ocstack.h"
24 #include "ocstackinternal.h"
25 #include "ocresourcehandler.h"
26 #include "logger.h"
27 #include "debug.h"
28 #include "cJSON.h"
29 /// Module Name
30 #include <stdio.h>
31
32 #define WITH_GROUPACTION 1
33
34 #ifdef WITH_GROUPACTION
35 #include "oicgroup.h"
36 #endif
37
38 #define TAG PCF("occollection")
39
40 #define NUM_PARAM_IN_QUERY  2
41
42 static OCStackResult CheckRTParamSupport(const OCResource* resource, const char* rtPtr)
43 {
44     OCResourceType* rTPointer = resource->rsrcType;
45     while (rTPointer)
46     {
47         if( strcmp (rTPointer->resourcetypename, rtPtr) == 0)
48             return OC_STACK_OK;
49
50         rTPointer = rTPointer->next;
51     }
52     return OC_STACK_ERROR;
53 }
54
55 static OCStackResult CheckIFParamSupport(const OCResource* resource, const char* ifPtr)
56 {
57     OCResourceInterface* iFPointer = resource->rsrcInterface;
58     while (iFPointer)
59     {
60         if( strcmp (iFPointer->name, ifPtr) == 0)
61              return OC_STACK_OK;
62
63         iFPointer = iFPointer->next;
64     }
65     return OC_STACK_ERROR;
66 }
67
68 static OCStackResult
69 ValidateQuery (const unsigned char *query, OCResourceHandle resource,
70                              OCStackIfTypes *ifParam, char **rtParam)
71 {
72     uint8_t numFields = 0, numParam;
73
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
76     // function.
77     OC_LOG(INFO, TAG, PCF("Entering ValidateQuery"));
78
79     if (!query)
80         return OC_STACK_ERROR;
81
82     if (!(*query))
83     {
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);
88         return OC_STACK_OK;
89     }
90
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);
95
96     // External loop breaks query string into fields using the & separator
97     while (token != NULL)
98     {
99         numFields++;
100         char *endToken;
101         char *innerToken = strtok_r (token, "=", &endToken);
102         numParam = 0;
103
104         // Internal loop parses the field to extract values (parameters) assigned to each field
105         while (innerToken != NULL)
106         {
107             numParam++;
108             if (strcmp (innerToken, OC_RSRVD_INTERFACE) == 0)
109             {
110                 // Determine the value of IF parameter
111                 innerToken = strtok_r (NULL, "=", &endToken);
112                 ifPtr = innerToken;
113             } else if (strcmp (innerToken, OC_RSRVD_RESOURCE_TYPE) == 0) {
114                 // Determine the value of RT parameter
115                 innerToken = strtok_r (NULL, "=", &endToken);
116                 rtPtr = innerToken;
117             } else {
118                 innerToken = strtok_r (NULL, "=", &endToken);
119             }
120         }
121         if (numParam != 2)
122         {
123             // Query parameter should be of the form if=<string>. String should not have & or =
124             return OC_STACK_INVALID_QUERY;
125         }
126         token = strtok_r (NULL, "&", &endStr);
127     }
128     if (numFields > NUM_PARAM_IN_QUERY)
129     {
130         // M1 release supports one IF value, one RT value and no other params
131         return OC_STACK_INVALID_QUERY;
132     }
133
134     if (ifPtr)
135     {
136         if(CheckIFParamSupport((OCResource *)resource, ifPtr) != OC_STACK_OK)
137         {
138             return OC_STACK_INVALID_QUERY;
139         }
140         if (strcmp (ifPtr, OC_RSRVD_INTERFACE_DEFAULT) == 0)
141         {
142             *ifParam = STACK_IF_DEFAULT;
143         }
144         else if (strcmp (ifPtr, OC_RSRVD_INTERFACE_LL) == 0)
145         {
146             *ifParam = STACK_IF_LL;
147         }
148         else if (strcmp (ifPtr, OC_RSRVD_INTERFACE_BATCH) == 0)
149         {
150             *ifParam = STACK_IF_BATCH;
151         }
152         else if(strcmp (ifPtr, OC_RSRVD_INTERFACE_GROUP) == 0)
153         {
154             *ifParam = STACK_IF_GROUP;
155         }
156         else
157         {
158             return OC_STACK_ERROR;
159         }
160     }
161     else
162     {
163         // IF not specified in query, use default IF
164         *ifParam = STACK_IF_DEFAULT;
165     }
166
167     if (rtPtr)
168     {
169         if (CheckRTParamSupport((OCResource *)resource, rtPtr) == OC_STACK_OK)
170         {
171             *rtParam = rtPtr;
172         }
173         else
174         {
175             return OC_STACK_INVALID_QUERY;
176         }
177     }
178     else
179     {
180         // RT not specified in query. Use the first resource type for the resource as default.
181         *rtParam = (char *) OCGetResourceTypeName (resource, 0);
182     }
183     OC_LOG_V(INFO, TAG, "Query params: IF = %d, RT = %s", *ifParam, *rtParam);
184
185     return OC_STACK_OK;
186 }
187
188
189 static OCStackResult BuildRootResourceJSON(OCResource *resource,
190         unsigned char * bufferPtr, uint16_t *remaining)
191 {
192     OCStackResult ret = OC_STACK_ERROR;
193     cJSON *resObj;
194     char *jsonStr;
195     uint16_t jsonLen;
196
197     OC_LOG(INFO, TAG, PCF("Entering BuildRootResourceJSON"));
198     resObj = cJSON_CreateObject();
199
200     if (resource)
201     {
202         cJSON_AddItemToObject (resObj, OC_RSRVD_HREF, cJSON_CreateString(resource->uri));
203     }
204     jsonStr = cJSON_PrintUnformatted (resObj);
205     jsonLen = strlen(jsonStr);
206     if (jsonLen < *remaining)
207     {
208         strcpy((char*) bufferPtr, jsonStr);
209         *remaining -= jsonLen;
210         bufferPtr += jsonLen;
211         ret = OC_STACK_OK;
212     }
213
214     cJSON_Delete (resObj);
215     free (jsonStr);
216
217     return ret;
218 }
219
220
221 static OCStackResult
222 HandleLinkedListInterface(OCEntityHandlerRequest *ehRequest,
223                        uint8_t filterOn, char *filterValue)
224 {
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;
231
232     ptr = jsonbuffer;
233     remaining = MAX_RESPONSE_LENGTH;
234
235     ret = BuildRootResourceJSON(collResource, ptr, &remaining);
236     ptr += strlen((char*)ptr);
237
238     if (ret == OC_STACK_OK && remaining >= (sizeof(OC_JSON_SEPARATOR) + 1))
239     {
240         *ptr = OC_JSON_SEPARATOR;
241         ptr++;
242         remaining--;
243     }
244     else
245     {
246         ret = OC_STACK_ERROR;
247     }
248     *(ptr + 1) = '\0';
249
250     if (ret == OC_STACK_OK)
251     {
252         for  (int i = 0; i < MAX_CONTAINED_RESOURCES; i++)
253         {
254             OCResource* temp = collResource->rsrcResources[i];
255             if (temp)
256             {
257                 ret = BuildVirtualResourceResponse(temp, filterOn, filterValue, (char*)ptr, &remaining);
258                 if (ret != OC_STACK_OK)
259                 {
260                     break;
261                 }
262                 ptr += strlen((char*)ptr);
263                 if (collResource->rsrcResources[i+1] && remaining > sizeof(OC_JSON_SEPARATOR))
264                 {
265                     *ptr = OC_JSON_SEPARATOR;
266                     ptr++;
267                     remaining--;
268                 }
269                 *(ptr + 1) = '\0';
270             }
271             else
272             {
273                 break;
274             }
275         }
276     }
277
278     jsonbufferLength = strlen((const char *)jsonbuffer);
279     if(ret == OC_STACK_OK && jsonbufferLength)
280     {
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);
289     }
290     return ret;
291 }
292
293 static OCStackResult
294 HandleBatchInterface(OCEntityHandlerRequest *ehRequest)
295 {
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;
303
304     ptr = jsonbuffer;
305     remaining = MAX_RESPONSE_LENGTH;
306
307     stackRet = BuildRootResourceJSON(collResource, ptr, &remaining);
308     ptr += strlen((char*)ptr);
309     *(ptr + 1) = '\0';
310
311     jsonbufferLength = strlen((const char *)jsonbuffer);
312     if(jsonbufferLength)
313     {
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);
322     }
323
324     if (stackRet == OC_STACK_OK)
325     {
326         for  (int i = 0; i < MAX_CONTAINED_RESOURCES; i++)
327         {
328             OCResource* temp = collResource->rsrcResources[i];
329             if (temp)
330             {
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;
335
336                 ehResult = temp->entityHandler(OC_REQUEST_FLAG, ehRequest);
337
338                 // The default collection handler is returning as OK
339                 if(stackRet != OC_STACK_SLOW_RESOURCE)
340                 {
341                     stackRet = OC_STACK_OK;
342                 }
343                 // if a single resource is slow, then entire response will be treated
344                 // as slow response
345                 if(ehResult == OC_EH_SLOW)
346                 {
347                     OC_LOG(INFO, TAG, PCF("This is a slow resource"));
348                     ((OCServerRequest *)ehRequest->requestHandle)->slowFlag = 1;
349                     stackRet = EntityHandlerCodeToOCStackCode(ehResult);
350                 }
351             }
352             else
353             {
354                 break;
355             }
356         }
357         ehRequest->resource = (OCResourceHandle) collResource;
358     }
359     return stackRet;
360 }
361
362 uint8_t GetNumOfResourcesInCollection (OCResource *resource)
363 {
364     uint8_t num = 0;
365     for (int i = 0; i < MAX_CONTAINED_RESOURCES; i++)
366     {
367         if (resource->rsrcResources[i])
368         {
369             num++;
370         }
371     }
372     return num;
373 }
374
375
376 OCStackResult DefaultCollectionEntityHandler (OCEntityHandlerFlag flag,
377                                               OCEntityHandlerRequest *ehRequest)
378 {
379     OCStackResult result = OC_STACK_ERROR;
380     OCStackIfTypes ifQueryParam = STACK_IF_INVALID;
381     char *rtQueryParam = NULL;
382
383     OC_LOG_V(INFO, TAG, "DefaultCollectionEntityHandler with query %s", ehRequest->query);
384
385     if (flag != OC_REQUEST_FLAG)
386         return OC_STACK_ERROR;
387
388     result = ValidateQuery ((const unsigned char *)ehRequest->query,
389                             ehRequest->resource, &ifQueryParam, &rtQueryParam);
390
391     if (result != OC_STACK_OK)
392         return result;
393
394   
395     if(!((ehRequest->method == OC_REST_GET) || 
396         (ehRequest->method == OC_REST_PUT) ||
397         (ehRequest->method == OC_REST_POST)))
398         return OC_STACK_ERROR;
399
400     if (ehRequest->method == OC_REST_GET)
401     {
402         switch (ifQueryParam)
403         {
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);
410
411             case STACK_IF_LL:
412                 OC_LOG(INFO, TAG, PCF("STACK_IF_LL"));
413                 return HandleLinkedListInterface(ehRequest, STACK_RES_DISCOVERY_NOFILTER, NULL);
414
415             case STACK_IF_BATCH:
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
422             case STACK_IF_GROUP:
423                 return BuildCollectionGroupActionJSONResponse(OC_REST_GET/*flag*/, (OCResource *)ehRequest->resource,
424                                  ehRequest);
425 #endif  // WITH_GROUPACTION
426             default:
427                 return OC_STACK_ERROR;
428         }
429     } else if (ehRequest->method == OC_REST_PUT) {
430         switch (ifQueryParam)
431         {
432             case STACK_IF_DEFAULT:
433                 // M1 release does not support PUT on default interface
434                 return OC_STACK_ERROR;
435
436             case STACK_IF_LL:
437                 // LL interface only supports GET
438                 return OC_STACK_ERROR;
439
440             case STACK_IF_BATCH:
441                 ((OCServerRequest *)ehRequest->requestHandle)->ehResponseHandler = HandleAggregateResponse;
442                 ((OCServerRequest *)ehRequest->requestHandle)->numResponses =
443                         GetNumOfResourcesInCollection((OCResource *)ehRequest->resource) + 1;
444                 return HandleBatchInterface(ehRequest);
445
446
447 #ifdef WITH_GROUPACTION
448             case STACK_IF_GROUP:
449             {
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);
453             }
454 #endif // WITH_GROUPACTION
455             default:
456                 return OC_STACK_ERROR;
457         }
458     }
459 #ifdef WITH_GROUPACTION
460     else if(ehRequest->method == OC_REST_POST) {
461
462         switch(ifQueryParam)
463         {
464             case STACK_IF_GROUP:
465             {
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);
469             }
470             default:
471                 return OC_STACK_ERROR;
472         }
473     }
474 #endif // WITH_GROUPACTION
475     return result;
476 }
477