Check parsing response from cjson
[platform/upstream/iotivity.git] / service / coap-http-proxy / src / CoapHttpHandler.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 "CoapHttpHandler.h"
22 #include "oic_malloc.h"
23 #include "oic_string.h"
24 #include "logger.h"
25 #include "pdu.h"
26 #include "ocpayload.h"
27 #include "uarraylist.h"
28 #include "CoapHttpParser.h"
29 #include "CoapHttpMap.h"
30 #include "cJSON.h"
31
32 #define TAG "CHPHandler"
33
34 #define CHP_RESOURCE_TYPE_NAME "core.chp"
35 #define CHP_RESOURCE_INTF_NAME "oc.mi.def"
36
37 /**
38  * CoAP request tracking.
39  * This structure is used to hold CoAP request information
40  */
41 typedef struct
42 {
43     OCMethod method;
44     OCRequestHandle requestHandle;
45 } CHPRequest_t;
46
47 /**
48  * Pointer to handle of the newly created proxy resource.
49  */
50 static OCResourceHandle g_proxyHandle = NULL;
51 static int g_isCHProxyInitialized = false;
52
53 /**
54  * Function to hand over CoAP request handling to Proxy.
55  */
56 OCStackResult CHPHandleOCFRequest(const OCEntityHandlerRequest* requestInfo,
57                                    const char* proxyUri);
58
59 /**
60  * Entity handler to receive requests from csdk.
61  */
62 OCEntityHandlerResult CHPEntityHandler(OCEntityHandlerFlag flag,
63                                        OCEntityHandlerRequest* entityHandlerRequest,
64                                        void* callbackParam);
65 bool CHPIsInitialized()
66 {
67     return g_isCHProxyInitialized;
68 }
69
70 OCStackResult CHPInitialize()
71 {
72     OIC_LOG(DEBUG, TAG, "CHPInitialize IN");
73     if (g_isCHProxyInitialized)
74     {
75         OIC_LOG(DEBUG, TAG, "CH Proxy already initialized");
76         return OC_STACK_OK;
77     }
78
79     OCStackResult result = CHPParserInitialize();
80     if (OC_STACK_OK != result)
81     {
82         OIC_LOG_V(ERROR, TAG, "Parser initialization failed[%d]", result);
83         return result;
84     }
85
86     result = OCSetProxyURI(OC_RSRVD_PROXY_URI);
87     if (OC_STACK_OK != result)
88     {
89         OIC_LOG_V(ERROR, TAG, "Setting proxy uri failed[%d]", result);
90         CHPParserTerminate();
91         return result;
92     }
93
94     result = OCCreateResource(&g_proxyHandle,
95                                CHP_RESOURCE_TYPE_NAME,
96                                CHP_RESOURCE_INTF_NAME,
97                                OC_RSRVD_PROXY_URI,
98                                CHPEntityHandler,
99                                NULL,
100                                OC_ACTIVE | OC_DISCOVERABLE | OC_SLOW);
101
102     if (OC_STACK_OK != result)
103     {
104         OIC_LOG_V(ERROR, TAG, "Create resource for proxy failed[%d]", result);
105         CHPParserTerminate();
106         return result;
107     }
108
109     g_isCHProxyInitialized = true;
110     OIC_LOG(DEBUG, TAG, "CHPInitialize OUT");
111     return OC_STACK_OK;
112 }
113
114 OCStackResult CHPTerminate()
115 {
116     OIC_LOG(DEBUG, TAG, "CHPTerminate IN");
117     OCStackResult result = CHPParserTerminate();
118     if (OC_STACK_OK != result)
119     {
120         OIC_LOG_V(ERROR, TAG, "Parser termination failed[%d]", result);
121     }
122
123     result = OCDeleteResource(g_proxyHandle);
124     if (OC_STACK_OK != result)
125     {
126         OIC_LOG_V(ERROR, TAG, "Delete resource for proxy failed[%d]", result);
127     }
128
129     g_proxyHandle = NULL;
130     g_isCHProxyInitialized = false;
131     return result;
132     OIC_LOG(DEBUG, TAG, "CHPTerminate OUT");
133 }
134
135 static void CHPGetProxyURI(OCHeaderOption* options, uint8_t *numOptions, char* uri,
136                            size_t uriLength)
137 {
138     OIC_LOG(DEBUG, TAG, "CHPGetProxyURI IN");
139     if (!uri || uriLength <= 0)
140     {
141         OIC_LOG (INFO, TAG, "Invalid uri buffer");
142         return;
143     }
144
145     if (!options || !numOptions || 0 == *numOptions)
146     {
147         OIC_LOG (INFO, TAG, "No options present");
148         return;
149     }
150
151     for (int count = 0; count < *numOptions; count++)
152     {
153         if (options[count].protocolID == OC_COAP_ID &&
154                 options[count].optionID == COAP_OPTION_PROXY_URI)
155         {
156             OIC_LOG(DEBUG, TAG, "Proxy URI is present");
157             // Extract proxy-uri and delete it from headeroptions.
158             OICStrcpy(uri, uriLength, (char *)options[count].optionData);
159             for (int fwd = count; fwd < *numOptions-1; fwd++)
160             {
161                 options[count] = options[count+1];
162             }
163             *numOptions -= 1;
164             return;
165         }
166     }
167
168     OIC_LOG(DEBUG, TAG, "CHPGetProxyURI OUT");
169     return;
170 }
171
172 // TODO: Will be moved to OCProxyPayload
173 static OCRepPayload* CHPGetDiscoveryPayload()
174 {
175     OCRepPayload* payload = OCRepPayloadCreate();
176     if (!payload)
177     {
178         OIC_LOG(ERROR, TAG, PCF("Failed to create Payload"));
179         return NULL;
180     }
181
182     OCRepPayloadSetUri(payload, OC_RSRVD_PROXY_URI);
183     OCRepPayloadSetPropString(payload, OC_RSRVD_DEVICE_ID, OCGetServerInstanceIDString());
184     return payload;
185 }
186
187 OCEntityHandlerResult CHPEntityHandler(OCEntityHandlerFlag flag,
188                                        OCEntityHandlerRequest* entityHandlerRequest,
189                                        void* callbackParam)
190 {
191     OIC_LOG_V(INFO, TAG, "Proxy request received");
192     UNUSED(callbackParam);
193
194     if (!g_isCHProxyInitialized)
195     {
196         OIC_LOG (ERROR, TAG, "Proxy not initialized");
197         return OC_EH_INTERNAL_SERVER_ERROR;
198     }
199
200     if (!entityHandlerRequest)
201     {
202         OIC_LOG (ERROR, TAG, "Invalid request pointer");
203         return OC_EH_ERROR;
204     }
205
206     if (flag & OC_OBSERVE_FLAG)
207     {
208         OIC_LOG_V (ERROR, TAG, "Proxy is not observable");
209         return OC_EH_BAD_REQ;
210     }
211     else if (flag & OC_REQUEST_FLAG)
212     {
213         /*
214          *  A proxy can handle two type of requests:
215          *  1. Discovery request in which case proxy-uri option will not be present.
216          *  2. Request for HTTP resource with proxy-uri option.
217          */
218         char proxyUri[MAX_HEADER_OPTION_DATA_LENGTH] = {'\0'};
219         CHPGetProxyURI(entityHandlerRequest->rcvdVendorSpecificHeaderOptions,
220                        &(entityHandlerRequest->numRcvdVendorSpecificHeaderOptions),
221                        proxyUri, sizeof(proxyUri));
222
223         if (proxyUri[0] != '\0')
224         {
225             // A request for HTTP resource. Response will be sent asynchronously
226             if (OC_STACK_OK == CHPHandleOCFRequest(entityHandlerRequest,
227                                                    proxyUri) )
228             {
229                 return OC_EH_SLOW;
230             }
231         }
232         else
233         {
234             OCEntityHandlerResult ehResult = OC_EH_ERROR;
235             switch (entityHandlerRequest->method)
236             {
237                 case OC_REST_GET:
238                 case OC_REST_DISCOVER:
239                 {
240                     // Generate discovery payload
241                     OIC_LOG (INFO, TAG, "Discovery request from client");
242                     ehResult = OC_EH_OK;
243                     OCEntityHandlerResponse response =
244                                 { .requestHandle = entityHandlerRequest->requestHandle,
245                                   .resourceHandle = entityHandlerRequest->resource,
246                                   .ehResult = ehResult};
247
248                     response.payload = (OCPayload *)CHPGetDiscoveryPayload();
249                     // Indicate that response is NOT in a persistent buffer
250                     response.persistentBufferFlag = 0;
251
252                     // Send the response
253                     if (OCDoResponse(&response) != OC_STACK_OK)
254                     {
255                         OIC_LOG(ERROR, TAG, "Error sending response");
256                         ehResult = OC_EH_ERROR;
257                     }
258
259                     OCPayloadDestroy(response.payload);
260                     break;
261                 }
262                 default:
263                     // Other methods are not supported
264                     OIC_LOG (INFO, TAG, "Invalid method from client");
265                     ehResult = OC_EH_METHOD_NOT_ALLOWED;
266                     break;
267             }
268             return ehResult;
269         }
270     }
271
272     return OC_EH_ERROR;
273 }
274
275 void CHPHandleHttpResponse(const HttpResponse_t *httpResponse, void *context)
276 {
277     OIC_LOG(DEBUG, TAG, "CHPHandleHttpResponse IN");
278     if (!httpResponse || !context)
279     {
280         OIC_LOG(ERROR, TAG, "Invalid arguements");
281         return;
282     }
283
284     CHPRequest_t *ctxt = (CHPRequest_t *)context;
285     OCEntityHandlerResponse response = { .requestHandle = ctxt->requestHandle,
286                                          .resourceHandle = g_proxyHandle};
287     response.persistentBufferFlag = 0;
288
289     OCStackResult result = CHPGetOCCode(httpResponse->status, ctxt->method,
290                                         &response.ehResult);
291     if (OC_STACK_OK != result)
292     {
293         OIC_LOG_V(ERROR, TAG, "%s failed[%d]", __func__, result);
294         response.ehResult = OC_EH_INTERNAL_SERVER_ERROR;
295         if (OCDoResponse(&response) != OC_STACK_OK)
296         {
297             OIC_LOG(ERROR, TAG, "Error sending response");
298         }
299         OICFree(ctxt);
300         return;
301     }
302
303     // ctxt not required now.
304     OICFree(ctxt);
305
306     if (httpResponse->dataFormat[0] != '\0')
307     {
308         OCPayloadFormat format = CHPGetOCContentType(httpResponse->dataFormat);
309         switch (format)
310         {
311             case OC_FORMAT_CBOR:
312                 OIC_LOG(DEBUG, TAG, "Payload format is CBOR");
313                 result = OCParsePayload(&response.payload, PAYLOAD_TYPE_REPRESENTATION,
314                                         httpResponse->payload, httpResponse->payloadLength);
315                 if (result != OC_STACK_OK)
316                 {
317                     OIC_LOG(ERROR, TAG, "Error parsing payload");
318                     response.ehResult = OC_EH_INTERNAL_SERVER_ERROR;
319                     if (OCDoResponse(&response) != OC_STACK_OK)
320                     {
321                         OIC_LOG(ERROR, TAG, "Error sending response");
322                     }
323                     return;
324                 }
325                 break;
326             case OC_FORMAT_JSON:
327                 OIC_LOG(DEBUG, TAG, "Payload format is JSON");
328                 cJSON *payloadJson = cJSON_Parse((char *)httpResponse->payload);
329                 if (!payloadJson)
330                 {
331                     OIC_LOG(ERROR, TAG, "Unable to parse json response");
332                     response.ehResult = OC_EH_INTERNAL_SERVER_ERROR;
333                     if (OCDoResponse(&response) != OC_STACK_OK)
334                     {
335                         OIC_LOG(ERROR, TAG, "Error sending response");
336                     }
337                     return;
338                 }
339                 OCRepPayload* payloadCbor = OCRepPayloadCreate();
340                 if (!payloadCbor)
341                 {
342                     response.ehResult = OC_EH_INTERNAL_SERVER_ERROR;
343                     if (OCDoResponse(&response) != OC_STACK_OK)
344                     {
345                         OIC_LOG(ERROR, TAG, "Error sending response");
346                     }
347                     cJSON_Delete(payloadJson);
348                     return;
349                 }
350
351                 CHPJsonToRepPayload(payloadJson, payloadCbor);
352                 response.payload = (OCPayload *)payloadCbor;
353                 cJSON_Delete(payloadJson);
354                 break;
355             default:
356                 OIC_LOG(ERROR, TAG, "Payload format is not supported");
357                 response.ehResult = OC_EH_INTERNAL_SERVER_ERROR;
358                 if (OCDoResponse(&response) != OC_STACK_OK)
359                 {
360                     OIC_LOG(ERROR, TAG, "Error sending response");
361                 }
362                 return;
363         }
364     }
365     // Header Options parsing
366     response.numSendVendorSpecificHeaderOptions = 0;
367     OCHeaderOption *optionsPointer = response.sendVendorSpecificHeaderOptions;
368
369     uint8_t tempOptionNumber = u_arraylist_length(httpResponse->headerOptions);
370     for (int numOptions = 0; numOptions < tempOptionNumber &&
371                              response.numSendVendorSpecificHeaderOptions < MAX_HEADER_OPTIONS;
372                              numOptions++)
373     {
374         HttpHeaderOption_t *httpOption = u_arraylist_get(httpResponse->headerOptions, numOptions);
375         result = CHPGetOCOption(httpOption, optionsPointer);
376         if (OC_STACK_OK != result)
377         {
378             OIC_LOG_V(ERROR, TAG, "CHPGetCoAPOption failed[%d][%d]", result,
379                                                 response.numSendVendorSpecificHeaderOptions);
380             continue;
381         }
382
383         response.numSendVendorSpecificHeaderOptions++;
384         optionsPointer += 1;
385     }
386
387     if (OCDoResponse(&response) != OC_STACK_OK)
388     {
389         OIC_LOG(ERROR, TAG, "Error sending response");
390     }
391
392     //OICFree(coapResponseInfo.info.payload);
393     OIC_LOG(DEBUG, TAG, "CHPHandleHttpResponse OUT");
394 }
395
396 OCStackResult CHPHandleOCFRequest(const OCEntityHandlerRequest* requestInfo,
397                                    const char* proxyUri)
398 {
399     OIC_LOG_V(DEBUG, TAG, "%s IN", __func__);
400
401     HttpRequest_t httpRequest = { .httpMajor = 1,
402                                   .httpMinor = 1};
403
404     OCEntityHandlerResponse response = { .requestHandle = requestInfo->requestHandle,
405                                          .resourceHandle = requestInfo->resource};
406     OCStackResult result = CHPGetHttpMethod(requestInfo->method, &httpRequest.method);
407     if (OC_STACK_OK != result)
408     {
409         OIC_LOG(ERROR, TAG, "Method not found in HTTP");
410         response.ehResult = OC_EH_BAD_REQ;
411         if (OCDoResponse(&response) != OC_STACK_OK)
412         {
413             OIC_LOG(ERROR, TAG, "Error sending response");
414         }
415
416         return OC_STACK_ERROR;
417     }
418
419     uint8_t vendorOptions = requestInfo->numRcvdVendorSpecificHeaderOptions;
420     if (vendorOptions)
421     {
422         httpRequest.headerOptions = u_arraylist_create();
423         for (int option = 0; option < vendorOptions; option++)
424         {
425             HttpHeaderOption_t *httpOption = NULL;
426             result = CHPGetHttpOption(requestInfo->rcvdVendorSpecificHeaderOptions + option,
427                                       &httpOption);
428             if (OC_STACK_OK != result || NULL == httpOption )
429             {
430                 OIC_LOG_V(ERROR, TAG, "CHPGetHttpOption failed [%d]", result);
431                 continue;
432             }
433             u_arraylist_add(httpRequest.headerOptions, (void *)httpOption);
434         }
435     }
436
437     OICStrcpy(httpRequest.resourceUri, sizeof(httpRequest.resourceUri), proxyUri);
438
439     if (requestInfo->payload && requestInfo->payload->type == PAYLOAD_TYPE_REPRESENTATION)
440     {
441         // Conversion from cbor to json.
442         cJSON *payloadJson = CHPRepPayloadToJson((OCRepPayload *)requestInfo->payload);
443         if (!payloadJson)
444         {
445             response.ehResult = OC_EH_BAD_REQ;
446             if (OCDoResponse(&response) != OC_STACK_OK)
447             {
448                 OIC_LOG(ERROR, TAG, "Error sending response");
449             }
450
451             return OC_STACK_ERROR;
452
453         }
454         httpRequest.payload = (void *)cJSON_Print(payloadJson);
455         httpRequest.payloadLength = strlen(httpRequest.payload);
456         OICStrcpy(httpRequest.payloadFormat, sizeof(httpRequest.payloadFormat),
457                   CBOR_CONTENT_TYPE);
458         cJSON_Delete(payloadJson);
459     }
460
461     OICStrcpy(httpRequest.acceptFormat, sizeof(httpRequest.acceptFormat),
462               ACCEPT_MEDIA_TYPE);
463     CHPRequest_t *chpRequest = (CHPRequest_t *)OICCalloc(1, sizeof(CHPRequest_t));
464     if (!chpRequest)
465     {
466         OIC_LOG(ERROR, TAG, "Calloc failed");
467         response.ehResult = OC_EH_INTERNAL_SERVER_ERROR;
468         if (OCDoResponse(&response) != OC_STACK_OK)
469         {
470             OIC_LOG(ERROR, TAG, "Error sending response");
471         }
472
473         OICFree(httpRequest.payload);
474         u_arraylist_destroy(httpRequest.headerOptions);
475         return OC_STACK_NO_MEMORY;
476     }
477
478     chpRequest->requestHandle = requestInfo->requestHandle;
479     chpRequest->method = requestInfo->method;
480
481     result = CHPPostHttpRequest(&httpRequest, CHPHandleHttpResponse,
482                                 (void *)chpRequest);
483     if (OC_STACK_OK != result)
484     {
485         OIC_LOG_V(ERROR, TAG, "CHPPostHttpRequest failed[%d]", result);
486         switch (result)
487         {
488             case OC_STACK_INVALID_URI:
489                 response.ehResult = OC_EH_BAD_REQ;
490                 break;
491             default:
492                 response.ehResult = OC_EH_INTERNAL_SERVER_ERROR;
493         }
494
495         if (OCDoResponse(&response) != OC_STACK_OK)
496         {
497             OIC_LOG(ERROR, TAG, "Error sending response");
498         }
499
500         OICFree(httpRequest.payload);
501         OICFree(chpRequest);
502         u_arraylist_destroy(httpRequest.headerOptions);
503         return OC_STACK_ERROR;
504     }
505
506     if (!httpRequest.payloadCached)
507     {
508         // Free only if parser has not cached it.
509         OICFree(httpRequest.payload);
510     }
511     u_arraylist_destroy(httpRequest.headerOptions);
512     OIC_LOG_V(DEBUG, TAG, "%s OUT", __func__);
513     return OC_STACK_OK;
514 }