Development of CoAP-HTTP Proxy
[platform/upstream/iotivity.git] / service / coap-http-proxy / src / CoapHttpMap.c
1 /* ****************************************************************
2  *
3  * Copyright 2016 Samsung Electronics 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 #include "CoapHttpMap.h"
22 #include <string.h>
23 #include "oic_malloc.h"
24 #include "oic_string.h"
25 #include "logger.h"
26 #include "ocstack.h"
27 #include "pdu.h"
28 #include "ocpayload.h"
29
30 #define TAG "CHPMap"
31
32 int CHPGetOptionID(const char *httpOptionName)
33 {
34     if (!httpOptionName)
35     {
36         OIC_LOG(ERROR, TAG, "HTTP option name is NULL");
37         return 0;
38     }
39
40     OICStringToLower((char *)httpOptionName);
41     if (0 == strcmp(httpOptionName, HTTP_OPTION_CACHE_CONTROL) ||
42         0 == strcmp(httpOptionName, HTTP_OPTION_EXPIRES))
43     {
44         return COAP_OPTION_MAXAGE;
45     }
46     else if (0 == strcmp(httpOptionName, HTTP_OPTION_IF_MATCH))
47     {
48         return COAP_OPTION_IF_MATCH;
49     }
50     else if (0 == strcmp(httpOptionName, HTTP_OPTION_IF_NONE_MATCH))
51     {
52         return COAP_OPTION_IF_NONE_MATCH;
53     }
54     else if (0 == strcmp(httpOptionName, HTTP_OPTION_ETAG))
55     {
56         return COAP_OPTION_ETAG;
57     }
58     else
59     {
60         OIC_LOG_V(ERROR, TAG, "No Mapping found for %s", httpOptionName);
61     }
62
63     return 0;
64 }
65
66 OCStackResult CHPGetOCCode(const HttpResponseResult_t httpCode, const OCMethod method,
67                             OCEntityHandlerResult *ocfCode)
68 {
69     OIC_LOG_V(DEBUG, TAG, "%s IN", __func__);
70     OIC_LOG_V(DEBUG, TAG, "Http Code is %d", httpCode);
71
72     switch (httpCode)
73     {
74         case CHP_SUCCESS:
75             if (OC_REST_GET == method)
76             {
77                 *ocfCode = OC_EH_CONTENT;
78             }
79             else if (OC_REST_DELETE == method)
80             {
81                 *ocfCode = OC_EH_RESOURCE_DELETED;
82             }
83             else
84             {
85                 *ocfCode = OC_EH_CHANGED;
86             }
87             break;
88         case CHP_NO_CONTENT:
89             if (OC_REST_DELETE == method)
90             {
91                 *ocfCode = OC_EH_RESOURCE_DELETED;
92             }
93             else
94             {
95                 *ocfCode = OC_EH_CHANGED;
96             }
97             break;
98         case CHP_CREATED:
99             *ocfCode = OC_EH_RESOURCE_CREATED;
100             break;
101         case CHP_NOT_MODIFIED:
102             *ocfCode = OC_EH_VALID;
103             break;
104         case CHP_BAD_REQ:
105         case CHP_REQUEST_URI_TOO_LARGE:
106             *ocfCode = OC_EH_BAD_REQ;
107             break;
108         case CHP_BAD_GATEWAY:
109         case CHP_VERSION_NOT_SUPPORTED:
110             *ocfCode = OC_EH_BAD_GATEWAY;
111             break;
112         case CHP_UNAUTHORIZED_REQ:
113         case CHP_FORBIDDEN_REQ:
114         case CHP_NOT_FOUND:
115         case CHP_NOT_ACCEPTABLE:
116         case CHP_REQUEST_ENTITY_TOO_LARGE:
117         case CHP_UNSUPPORTED_MEDIA_TYPE:
118         case CHP_INTERNAL_SERVER_ERROR:
119         case CHP_NOT_IMPLEMENTED:
120         case CHP_SERVICE_UNAVAILABLE:
121         case CHP_GATEWAY_TIMEOUT:
122             *ocfCode = httpCode;
123             break;
124         default:
125             OIC_LOG_V(ERROR, TAG, "HTTP Response code[%d] is not matching the OCF Response code",
126                       httpCode);
127             return OC_STACK_ERROR;
128     }
129
130     OIC_LOG_V(DEBUG, TAG, "%s OUT", __func__);
131     return OC_STACK_OK;
132 }
133
134 OCStackResult CHPGetOCOption(const HttpHeaderOption_t *httpOption, OCHeaderOption *ocfOption)
135 {
136     OIC_LOG(DEBUG, TAG, "CHPGetCoAPOption IN");
137     if (!httpOption)
138     {
139         OIC_LOG(ERROR, TAG, "HTTP option is Null");
140         return OC_STACK_INVALID_PARAM;
141     }
142
143     ocfOption->optionID = CHPGetOptionID(httpOption->optionName);
144     if (!ocfOption->optionID)
145     {
146         OIC_LOG(INFO, TAG, "No match for HTTP option found");
147         return OC_STACK_INVALID_OPTION;
148     }
149
150     ocfOption->protocolID = OC_COAP_ID;
151     ocfOption->optionLength = httpOption->optionLength < sizeof(ocfOption->optionData) ?
152                                 httpOption->optionLength : sizeof(ocfOption->optionData);
153     memcpy(ocfOption->optionData,  httpOption->optionData, ocfOption->optionLength);
154
155     OIC_LOG(DEBUG, TAG, "CHPGetCoAPOption OUT");
156     return OC_STACK_OK;
157 }
158
159 OCPayloadFormat CHPGetOCContentType(const char *httpContentType)
160 {
161     OIC_LOG_V(DEBUG, TAG, "%s IN", __func__);
162
163     OICStringToLower((char *)httpContentType);
164     if (strstr(httpContentType, CBOR_CONTENT_TYPE))
165     {
166         return OC_FORMAT_CBOR;
167     }
168     else if (strstr(httpContentType, JSON_CONTENT_TYPE))
169     {
170         return OC_FORMAT_JSON;
171     }
172
173     OIC_LOG_V(DEBUG, TAG, "%s OUT", __func__);
174     return OC_FORMAT_UNSUPPORTED;
175 }
176
177 OCStackResult CHPGetHttpMethod(const OCMethod method, HttpMethod_t *httpMethod)
178 {
179     OIC_LOG_V(DEBUG, TAG, "%s IN", __func__);
180
181     switch (method)
182     {
183         case OC_REST_GET:
184             *httpMethod = CHP_GET;
185             break;
186         case OC_REST_PUT:
187             *httpMethod = CHP_PUT;
188             break;
189         case OC_REST_POST:
190             *httpMethod = CHP_POST;
191             break;
192         case OC_REST_DELETE:
193             *httpMethod = CHP_DELETE;
194             break;
195         default:
196             *httpMethod = CHP_INVALID;
197             OIC_LOG_V(ERROR, TAG, "Unknown method type %d", method);
198             return OC_STACK_INVALID_METHOD;
199     }
200
201     OIC_LOG_V(DEBUG, TAG, "%s OUT", __func__);
202     return OC_STACK_OK;
203 }
204
205 OCStackResult CHPGetHttpOption(const OCHeaderOption* option, HttpHeaderOption_t** httpOption)
206 {
207     OIC_LOG_V(DEBUG, TAG, "%s IN", __func__);
208     if (!option)
209     {
210         OIC_LOG(ERROR, TAG, "option is NULL");
211         return OC_STACK_INVALID_PARAM;
212     }
213
214     *httpOption = (HttpHeaderOption_t *)OICCalloc(1, sizeof(HttpHeaderOption_t));
215     if (NULL == *httpOption)
216     {
217         OIC_LOG(ERROR, TAG, "Memory allocation failed");
218         return OC_STACK_NO_MEMORY;
219     }
220
221     switch (option->optionID)
222     {
223         case COAP_OPTION_ACCEPT:
224             OICStrcpy((*httpOption)->optionName, sizeof((*httpOption)->optionName),
225                       HTTP_OPTION_ACCEPT);
226             break;
227         case COAP_OPTION_IF_MATCH:
228             OICStrcpy((*httpOption)->optionName, sizeof((*httpOption)->optionName),
229                       HTTP_OPTION_IF_MATCH);
230             break;
231         case COAP_OPTION_IF_NONE_MATCH:
232             OICStrcpy((*httpOption)->optionName, sizeof((*httpOption)->optionName),
233                       HTTP_OPTION_IF_NONE_MATCH);
234             break;
235         case COAP_OPTION_ETAG:
236             OICStrcpy((*httpOption)->optionName, sizeof((*httpOption)->optionName),
237                       HTTP_OPTION_ETAG);
238             break;
239         case COAP_OPTION_CONTENT_TYPE:
240             OICStrcpy((*httpOption)->optionName, sizeof((*httpOption)->optionName),
241                       HTTP_OPTION_CONTENT_TYPE);
242             break;
243         default:
244             OIC_LOG_V(INFO, TAG, "No Matching found for the ID %d", option->optionID);
245     }
246
247     if ('\0' == (*httpOption)->optionName[0])
248     {
249         OIC_LOG(ERROR, TAG, "No matching is found");
250         OICFree(*httpOption);
251         return OC_STACK_INVALID_OPTION;
252     }
253
254     (*httpOption)->optionLength = option->optionLength < sizeof((*httpOption)->optionData) ?
255                                       option->optionLength : sizeof((*httpOption)->optionData);
256     memcpy((*httpOption)->optionData, option->optionData, (*httpOption)->optionLength);
257
258     OIC_LOG_V(DEBUG, TAG, "%s OUT", __func__);
259     return OC_STACK_OK;
260 }
261
262 void CHPJsonToRepPayload(cJSON* rootJSon, OCRepPayload* payload)
263 {
264     cJSON* dataJson = rootJSon->child;
265     while (dataJson)
266     {
267         switch (dataJson->type)
268         {
269             case cJSON_String:
270                 OCRepPayloadSetPropString(payload, dataJson->string, dataJson->valuestring);
271                 break;
272             case cJSON_Number:
273                 if (dataJson->valueint == dataJson->valuedouble)
274                 {
275                     OCRepPayloadSetPropInt(payload, dataJson->string, dataJson->valueint);
276                 }
277                 else
278                 {
279                     OCRepPayloadSetPropDouble(payload, dataJson->string, dataJson->valuedouble);
280                 }
281                 break;
282             case cJSON_False:
283                 OCRepPayloadSetPropBool(payload, dataJson->string, false);
284                 break;
285             case cJSON_True:
286                 OCRepPayloadSetPropBool(payload, dataJson->string, true);
287                 break;
288             case cJSON_Object:
289             {
290                 OCRepPayload* childPayload = OCRepPayloadCreate();
291                 CHPJsonToRepPayload(dataJson,childPayload);
292                 OCRepPayloadSetPropObject(payload, dataJson->string,childPayload );
293                 break;
294             }
295             case cJSON_Array:
296             {
297                 int size = cJSON_GetArraySize(dataJson);
298                 size_t dimensions[MAX_REP_ARRAY_DEPTH];
299                 dimensions[0] = size;
300                 dimensions[1] = dimensions[2] = 0;
301
302                 int i = 0;
303                 int type = cJSON_IsReference;
304                 int numType = 0;    // int:1, double:2
305                 const int intType = 1;
306                 const int doubleType = 2;
307
308                 int64_t intArray[size];
309                 double doubleArray[size];
310                 char* strArray[size];
311                 OCRepPayload* objPayloadArray[size];
312
313                 for (; i < size ; ++i)
314                 {
315                     cJSON* subitem = cJSON_GetArrayItem(dataJson, i);
316                     if (subitem == NULL)
317                     {
318                         continue;
319                     }
320
321                     if ((type != cJSON_IsReference) && (type != subitem->type))
322                     {
323                         continue;
324                     }
325                     else
326                     {
327                         type = subitem->type;
328                         switch (type)
329                         {
330                             case cJSON_Number:
331                                 if (subitem->valueint == subitem->valuedouble)
332                                 {
333                                     numType = intType;
334                                     intArray[i] = (int64_t) subitem->valueint;
335                                 }
336                                 else
337                                 {
338                                     numType = doubleType;
339                                     doubleArray[i] = subitem->valuedouble;
340                                 }
341                                 break;
342                             case cJSON_String:
343                                 strArray[i] = subitem->valuestring;
344                                 break;
345                             case cJSON_Object:
346                                 objPayloadArray[i] = OCRepPayloadCreate();
347                                 CHPJsonToRepPayload(subitem,objPayloadArray[i]);
348                                 break;
349                             default:
350                                 OIC_LOG(ERROR, TAG, "wrong ArrayType in JsonToRepPayload()");
351                                 break;
352                         }
353                     }
354                 }
355
356                 switch (type)
357                 {
358                     case cJSON_Number:
359                     if (numType == intType)
360                     {
361                         OCRepPayloadSetIntArray(payload, dataJson->string,(const int64_t*)intArray,
362                                                 dimensions);
363                     }
364                     else if (numType == doubleType)
365                     {
366                         OCRepPayloadSetDoubleArray(payload, dataJson->string,
367                                                    (const double*)doubleArray,
368                                                    dimensions);
369                     }
370                     break;
371                     case cJSON_String:
372                         OCRepPayloadSetStringArray(payload, dataJson->string,
373                                                    (const char**)strArray,
374                                                    dimensions);
375                     break;
376                     case cJSON_Object:
377                         OCRepPayloadSetPropObjectArray(payload, dataJson->string,
378                                                        (const OCRepPayload**)objPayloadArray,
379                                                        dimensions);
380                         break;
381                   default:
382                         OIC_LOG(ERROR, TAG, "wrong ArrayType in JsonToRepPayload()");
383                         break;
384                 }
385                 break;
386             }
387         }
388         dataJson = dataJson->next;
389     }
390 }
391
392 cJSON* CHPRepPayloadToJson(OCRepPayload* repData)
393 {
394     cJSON *outJson = cJSON_CreateObject();
395     if (outJson == NULL)
396     {
397         return NULL;
398     }
399
400     OCRepPayloadValue* val = repData->values;
401     while (val)
402     {
403         switch (val->type)
404         {
405             case OCREP_PROP_NULL:
406                 break;
407             case OCREP_PROP_INT:
408                 OIC_LOG_V(DEBUG, TAG, "%s(int):%d", val->name, (int)val->i);
409                 cJSON_AddNumberToObject(outJson,val->name,(int)val->i);
410                 break;
411             case OCREP_PROP_DOUBLE:
412                 OIC_LOG_V(DEBUG, TAG, "%s(double):%f", val->name, val->d);
413                 cJSON_AddNumberToObject(outJson,val->name,val->d);
414                 break;
415             case OCREP_PROP_BOOL:
416                 OIC_LOG_V(DEBUG, TAG, "%s(bool):%s", val->name, val->b ? "true" : "false");
417                 cJSON_AddBoolToObject(outJson,val->name,val->b);
418                 break;
419             case OCREP_PROP_STRING:
420                 OIC_LOG_V(DEBUG, TAG, "%s(string):%s", val->name, val->str);
421                 cJSON_AddStringToObject(outJson,val->name,val->str);
422                 break;
423             case OCREP_PROP_OBJECT:
424             {
425                 cJSON *objJson = CHPRepPayloadToJson(val->obj);
426                 if (objJson != NULL)
427                 {
428                     cJSON_AddItemToObject(outJson,val->name,objJson);
429                 }
430                 break;
431             }
432             case OCREP_PROP_ARRAY:
433             {
434                 unsigned int i = 0;
435                 int arraySize = (int)val->arr.dimensions[0];
436                 switch (val->arr.type)
437                 {
438                     case OCREP_PROP_INT:
439                         OIC_LOG_V(DEBUG, TAG, "%s(int array)", val->name);
440                         if (arraySize > 0)
441                         {
442                             int castVal[val->arr.dimensions[0]];
443                             for (i = 0 ; i < (unsigned int)arraySize ; i++)
444                             {
445                                 castVal[i] = (int)val->arr.iArray[i];
446                             }
447                             cJSON *array = cJSON_CreateIntArray(castVal,arraySize);
448                             if (array != NULL)
449                             {
450                                 cJSON_AddItemToObject(outJson,val->name,array);
451                             }
452                         }
453                         break;
454                     case OCREP_PROP_DOUBLE:
455                         OIC_LOG_V(DEBUG, TAG, "%s(double array)", val->name);
456                         if (arraySize > 0)
457                         {
458                             cJSON *array = cJSON_CreateDoubleArray(val->arr.dArray,arraySize);
459                             if (array != NULL)
460                             {
461                                 cJSON_AddItemToObject(outJson,val->name,array);
462                             }
463                         }
464                         break;
465                     case OCREP_PROP_STRING:
466                         OIC_LOG_V(DEBUG, TAG, "%s(string array)", val->name);
467                         if (arraySize > 0)
468                         {
469                             cJSON *array = cJSON_CreateStringArray((const char**)val->arr.strArray,
470                                                                    arraySize);
471                             if (array != NULL)
472                             {
473                                 cJSON_AddItemToObject(outJson,val->name,array);
474                             }
475                         }
476                         break;
477                     case OCREP_PROP_OBJECT:
478                         if (arraySize > 0)
479                         {
480                             cJSON *arrayJson = cJSON_CreateArray();
481                             for (i = 0 ; i < (unsigned int)arraySize ; i++)
482                             {
483                                 cJSON *objJson = CHPRepPayloadToJson(val->arr.objArray[i]);
484                                 if (objJson != NULL && arrayJson != NULL)
485                                 {
486                                     cJSON_AddItemToArray(arrayJson, objJson);
487                                 }
488                             }
489                             if (arrayJson != NULL)
490                             {
491                                 cJSON_AddItemToObject(outJson,val->name,arrayJson);
492                             }
493                         }
494                         break;
495                     case OCREP_PROP_BOOL:
496                         //TODO : Not support - cJSON_CreateBoolArray
497                         break;
498                     default:
499                         OIC_LOG_V(ERROR, TAG, "Unknown/unsupported array type: %s", val->name);
500                         break;
501                 }
502                 break;
503             }
504             default:
505                 OIC_LOG_V(ERROR, TAG, "Unknown type: %s", val->name);
506                 break;
507         }
508         val = val->next;
509     }
510
511     if( repData->values != NULL)
512     {
513         return outJson;
514     }
515     else
516     {
517         cJSON_Delete(outJson);
518         return NULL;
519     }
520 }