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"
30 #define TAG PCF("occollection")
32 #define NUM_PARAM_IN_QUERY 2
34 static OCStackResult CheckRTParamSupport(const OCResource* resource, const char* rtPtr)
36 OCResourceType* rTPointer = resource->rsrcType;
39 if( strcmp (rTPointer->resourcetypename, rtPtr) == 0)
42 rTPointer = rTPointer->next;
44 return OC_STACK_ERROR;
47 static OCStackResult CheckIFParamSupport(const OCResource* resource, const char* ifPtr)
49 OCResourceInterface* iFPointer = resource->rsrcInterface;
52 if( strcmp (iFPointer->name, ifPtr) == 0)
55 iFPointer = iFPointer->next;
57 return OC_STACK_ERROR;
61 ValidateQuery (const unsigned char *query, OCResourceHandle resource,
62 OCStackIfTypes *ifParam, char **rtParam)
64 uint8_t numFields = 0, numParam;
66 //TODO: Query and URL validation is being done for virtual resource case
67 // using ValidateUrlQuery function. We should be able to merge it with this
69 OC_LOG(INFO, TAG, PCF("Entering ValidateQuery"));
72 return OC_STACK_ERROR;
76 // Query string is empty
77 OC_LOG_V(INFO, TAG, PCF("Empty query string, use default IF and RT"));
78 *ifParam = STACK_IF_DEFAULT;
79 *rtParam = (char *) OCGetResourceTypeName (resource, 0);
83 // Break the query string to validate it and determine IF and RT parameters
84 // Validate there are atmost 2 parameters in string and that one is 'if' and other 'rt'
85 char *endStr, *ifPtr = NULL, *rtPtr = NULL;
86 char *token = strtok_r ((char *)query, "&", &endStr);
88 // External loop breaks query string into fields using the & separator
93 char *innerToken = strtok_r (token, "=", &endToken);
96 // Internal loop parses the field to extract values (parameters) assigned to each field
97 while (innerToken != NULL)
100 if (strcmp (innerToken, OC_RSRVD_INTERFACE) == 0)
102 // Determine the value of IF parameter
103 innerToken = strtok_r (NULL, "=", &endToken);
105 } else if (strcmp (innerToken, OC_RSRVD_RESOURCE_TYPE) == 0) {
106 // Determine the value of RT parameter
107 innerToken = strtok_r (NULL, "=", &endToken);
110 innerToken = strtok_r (NULL, "=", &endToken);
115 // Query parameter should be of the form if=<string>. String should not have & or =
116 return OC_STACK_INVALID_QUERY;
118 token = strtok_r (NULL, "&", &endStr);
120 if (numFields > NUM_PARAM_IN_QUERY)
122 // M1 release supports one IF value, one RT value and no other params
123 return OC_STACK_INVALID_QUERY;
128 if(CheckIFParamSupport((OCResource *)resource, ifPtr) != OC_STACK_OK)
130 return OC_STACK_INVALID_QUERY;
132 if (strcmp (ifPtr, OC_RSRVD_INTERFACE_DEFAULT) == 0)
134 *ifParam = STACK_IF_DEFAULT;
136 else if (strcmp (ifPtr, OC_RSRVD_INTERFACE_LL) == 0)
138 *ifParam = STACK_IF_LL;
140 else if (strcmp (ifPtr, OC_RSRVD_INTERFACE_BATCH) == 0)
142 *ifParam = STACK_IF_BATCH;
146 return OC_STACK_ERROR;
151 // IF not specified in query, use default IF
152 *ifParam = STACK_IF_DEFAULT;
157 if (CheckRTParamSupport((OCResource *)resource, rtPtr) == OC_STACK_OK)
163 return OC_STACK_INVALID_QUERY;
168 // RT not specified in query. Use the first resource type for the resource as default.
169 *rtParam = (char *) OCGetResourceTypeName (resource, 0);
171 OC_LOG_V(INFO, TAG, "Query params: IF = %d, RT = %s", *ifParam, *rtParam);
177 static OCStackResult BuildRootResourceJSON(OCResource *resource,
178 unsigned char * bufferPtr, uint16_t *remaining)
180 OCStackResult ret = OC_STACK_ERROR;
185 OC_LOG(INFO, TAG, PCF("Entering BuildRootResourceJSON"));
186 resObj = cJSON_CreateObject();
190 cJSON_AddItemToObject (resObj, OC_RSRVD_HREF, cJSON_CreateString(resource->uri));
192 jsonStr = cJSON_PrintUnformatted (resObj);
193 jsonLen = strlen(jsonStr);
194 if (jsonLen < *remaining)
196 strcpy((char*) bufferPtr, jsonStr);
197 *remaining -= jsonLen;
198 bufferPtr += jsonLen;
202 cJSON_Delete (resObj);
210 HandleLinkedListInterface(OCEntityHandlerRequest *ehRequest,
211 uint8_t filterOn, char *filterValue)
213 OCStackResult ret = OC_STACK_ERROR;
214 unsigned char jsonbuffer[MAX_RESPONSE_LENGTH] = {0};
215 size_t jsonbufferLength = 0;
216 uint16_t remaining = 0;
217 unsigned char * ptr = NULL;
218 OCResource * collResource = (OCResource *) ehRequest->resource;
221 remaining = MAX_RESPONSE_LENGTH;
223 ret = BuildRootResourceJSON(collResource, ptr, &remaining);
224 ptr += strlen((char*)ptr);
226 if (ret == OC_STACK_OK && remaining >= (sizeof(OC_JSON_SEPARATOR) + 1))
228 *ptr = OC_JSON_SEPARATOR;
234 ret = OC_STACK_ERROR;
238 if (ret == OC_STACK_OK)
240 for (int i = 0; i < MAX_CONTAINED_RESOURCES; i++)
242 OCResource* temp = collResource->rsrcResources[i];
245 ret = BuildVirtualResourceResponse(temp, filterOn, filterValue, (char*)ptr, &remaining);
246 if (ret != OC_STACK_OK)
250 ptr += strlen((char*)ptr);
251 if (collResource->rsrcResources[i+1] && remaining > sizeof(OC_JSON_SEPARATOR))
253 *ptr = OC_JSON_SEPARATOR;
266 jsonbufferLength = strlen((const char *)jsonbuffer);
267 if(ret == OC_STACK_OK && jsonbufferLength)
269 OCEntityHandlerResponse response = {0};
270 response.ehResult = OC_EH_OK;
271 response.payload = jsonbuffer;
272 response.payloadSize = jsonbufferLength + 1;
273 response.persistentBufferFlag = 0;
274 response.requestHandle = (OCRequestHandle) ehRequest->requestHandle;
275 response.resourceHandle = (OCResourceHandle) collResource;
276 ret = OCDoResponse(&response);
282 HandleBatchInterface(OCEntityHandlerRequest *ehRequest)
284 OCStackResult stackRet = OC_STACK_ERROR;
285 OCEntityHandlerResult ehResult = OC_EH_ERROR;
286 unsigned char jsonbuffer[MAX_RESPONSE_LENGTH] = {0};
287 size_t jsonbufferLength = 0;
288 uint16_t remaining = 0;
289 unsigned char * ptr = NULL;
290 OCResource * collResource = (OCResource *) ehRequest->resource;
293 remaining = MAX_RESPONSE_LENGTH;
295 stackRet = BuildRootResourceJSON(collResource, ptr, &remaining);
296 ptr += strlen((char*)ptr);
299 jsonbufferLength = strlen((const char *)jsonbuffer);
302 OCEntityHandlerResponse response = {0};
303 response.ehResult = OC_EH_OK;
304 response.payload = jsonbuffer;
305 response.payloadSize = jsonbufferLength + 1;
306 response.persistentBufferFlag = 0;
307 response.requestHandle = (OCRequestHandle) ehRequest->requestHandle;
308 response.resourceHandle = (OCResourceHandle) collResource;
309 stackRet = OCDoResponse(&response);
312 if (stackRet == OC_STACK_OK)
314 for (int i = 0; i < MAX_CONTAINED_RESOURCES; i++)
316 OCResource* temp = collResource->rsrcResources[i];
319 // Note that all entity handlers called through a collection
320 // will get the same pointer to ehRequest, the only difference
321 // is ehRequest->resource
322 ehRequest->resource = (OCResourceHandle) temp;
324 ehResult = temp->entityHandler(OC_REQUEST_FLAG, ehRequest);
326 // The default collection handler is returning as OK
327 if(stackRet != OC_STACK_SLOW_RESOURCE)
329 stackRet = OC_STACK_OK;
331 // if a single resource is slow, then entire response will be treated
333 if(ehResult == OC_EH_SLOW)
335 OC_LOG(INFO, TAG, PCF("This is a slow resource"));
336 ((OCServerRequest *)ehRequest->requestHandle)->slowFlag = 1;
337 stackRet = EntityHandlerCodeToOCStackCode(ehResult);
345 ehRequest->resource = (OCResourceHandle) collResource;
350 uint8_t GetNumOfResourcesInCollection (OCResource *resource)
353 for (int i = 0; i < MAX_CONTAINED_RESOURCES; i++)
355 if (resource->rsrcResources[i])
364 OCStackResult DefaultCollectionEntityHandler (OCEntityHandlerFlag flag,
365 OCEntityHandlerRequest *ehRequest)
367 OCStackResult result = OC_STACK_ERROR;
368 OCStackIfTypes ifQueryParam = STACK_IF_INVALID;
369 char *rtQueryParam = NULL;
371 OC_LOG_V(INFO, TAG, "DefaultCollectionEntityHandler with query %s", ehRequest->query);
373 if (flag != OC_REQUEST_FLAG)
374 return OC_STACK_ERROR;
376 result = ValidateQuery ((const unsigned char *)ehRequest->query,
377 ehRequest->resource, &ifQueryParam, &rtQueryParam);
379 if (result != OC_STACK_OK)
382 if ((ehRequest->method != OC_REST_GET) &&
383 (ehRequest->method != OC_REST_PUT))
384 return OC_STACK_ERROR;
386 if (ehRequest->method == OC_REST_GET)
388 switch (ifQueryParam)
390 case STACK_IF_DEFAULT:
391 // Get attributes of collection resource and properties of contined resource
392 // M1 release does not support attributes for collection resource, so the GET
393 // operation is same as the GET on LL interface.
394 OC_LOG(INFO, TAG, PCF("STACK_IF_DEFAULT"));
395 return HandleLinkedListInterface(ehRequest, STACK_RES_DISCOVERY_NOFILTER, NULL);
398 OC_LOG(INFO, TAG, PCF("STACK_IF_LL"));
399 return HandleLinkedListInterface(ehRequest, STACK_RES_DISCOVERY_NOFILTER, NULL);
402 OC_LOG(INFO, TAG, PCF("STACK_IF_BATCH"));
403 ((OCServerRequest *)ehRequest->requestHandle)->ehResponseHandler = HandleAggregateResponse;
404 ((OCServerRequest *)ehRequest->requestHandle)->numResponses =
405 GetNumOfResourcesInCollection((OCResource *)ehRequest->resource) + 1;
406 return HandleBatchInterface(ehRequest);
409 return OC_STACK_ERROR;
411 } else if (ehRequest->method == OC_REST_PUT) {
412 switch (ifQueryParam)
414 case STACK_IF_DEFAULT:
415 // M1 release does not support PUT on default interface
416 return OC_STACK_ERROR;
419 // LL interface only supports GET
420 return OC_STACK_ERROR;
423 ((OCServerRequest *)ehRequest->requestHandle)->ehResponseHandler = HandleAggregateResponse;
424 ((OCServerRequest *)ehRequest->requestHandle)->numResponses =
425 GetNumOfResourcesInCollection((OCResource *)ehRequest->resource) + 1;
426 return HandleBatchInterface(ehRequest);
429 return OC_STACK_ERROR;