1 /* ****************************************************************
3 * Copyright 2016 Samsung Electronics All Rights Reserved.
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 #include "CoapHttpHandler.h"
22 #include "oic_malloc.h"
23 #include "oic_string.h"
26 #include "ocpayload.h"
27 #include "uarraylist.h"
28 #include "CoapHttpParser.h"
29 #include "CoapHttpMap.h"
30 #if defined (__TIZENRT__)
31 #include <apps/netutils/cJSON.h>
36 #define TAG "CHPHandler"
38 #define CHP_RESOURCE_TYPE_NAME "core.chp"
39 #define CHP_RESOURCE_INTF_NAME "oc.mi.def"
42 * CoAP request tracking.
43 * This structure is used to hold CoAP request information
48 OCRequestHandle requestHandle;
52 * Pointer to handle of the newly created proxy resource.
54 static OCResourceHandle g_proxyHandle = NULL;
55 static int g_isCHProxyInitialized = false;
58 * Function to hand over CoAP request handling to Proxy.
60 OCStackResult CHPHandleOCFRequest(const OCEntityHandlerRequest* requestInfo,
61 const char* proxyUri);
64 * Entity handler to receive requests from csdk.
66 OCEntityHandlerResult CHPEntityHandler(OCEntityHandlerFlag flag,
67 OCEntityHandlerRequest* entityHandlerRequest,
69 bool CHPIsInitialized()
71 return g_isCHProxyInitialized;
74 OCStackResult CHPInitialize(bool secure)
76 OIC_LOG_V(DEBUG, TAG, "%s IN", __func__);
77 if (g_isCHProxyInitialized)
79 OIC_LOG(DEBUG, TAG, "CH Proxy already initialized");
83 OCStackResult result = CHPParserInitialize();
84 if (OC_STACK_OK != result)
86 OIC_LOG_V(ERROR, TAG, "Parser initialization failed[%d]", result);
90 result = OCSetProxyURI(OC_RSRVD_PROXY_URI);
91 if (OC_STACK_OK != result)
93 OIC_LOG_V(ERROR, TAG, "Setting proxy uri failed[%d]", result);
98 uint8_t prop = OC_ACTIVE | OC_DISCOVERABLE | OC_SLOW;
103 result = OCCreateResource(&g_proxyHandle,
104 CHP_RESOURCE_TYPE_NAME,
105 CHP_RESOURCE_INTF_NAME,
111 if (OC_STACK_OK != result)
113 OIC_LOG_V(ERROR, TAG, "Create resource for proxy failed[%d]", result);
114 CHPParserTerminate();
118 g_isCHProxyInitialized = true;
119 OIC_LOG_V(DEBUG, TAG, "%s OUT", __func__);
123 OCStackResult CHPTerminate()
125 OIC_LOG_V(DEBUG, TAG, "%s IN", __func__);
126 OCStackResult result = CHPParserTerminate();
127 if (OC_STACK_OK != result)
129 OIC_LOG_V(ERROR, TAG, "Parser termination failed[%d]", result);
132 result = OCDeleteResource(g_proxyHandle);
133 if (OC_STACK_OK != result)
135 OIC_LOG_V(ERROR, TAG, "Delete resource for proxy failed[%d]", result);
138 g_proxyHandle = NULL;
139 g_isCHProxyInitialized = false;
141 OIC_LOG_V(DEBUG, TAG, "%s OUT", __func__);
144 static void CHPGetProxyURI(OCHeaderOption* options, uint8_t *numOptions, char* uri,
147 OIC_LOG_V(DEBUG, TAG, "%s IN", __func__);
148 if (!uri || uriLength <= 0)
150 OIC_LOG (INFO, TAG, "Invalid uri buffer");
154 if (!options || !numOptions || 0 == *numOptions)
156 OIC_LOG (INFO, TAG, "No options present");
160 for (int count = 0; count < *numOptions; count++)
162 if (options[count].protocolID == OC_COAP_ID &&
163 options[count].optionID == COAP_OPTION_PROXY_URI)
165 OIC_LOG(DEBUG, TAG, "Proxy URI is present");
166 // Extract proxy-uri and delete it from headeroptions.
167 OICStrcpy(uri, uriLength, (char *)options[count].optionData);
168 for (int fwd = count; fwd < *numOptions-1; fwd++)
170 options[count] = options[count+1];
177 OIC_LOG_V(DEBUG, TAG, "%s OUT", __func__);
181 // TODO: Will be moved to OCProxyPayload
182 static OCRepPayload* CHPGetDiscoveryPayload()
184 OCRepPayload* payload = OCRepPayloadCreate();
187 OIC_LOG(ERROR, TAG, PCF("Failed to create Payload"));
191 OCRepPayloadSetUri(payload, OC_RSRVD_PROXY_URI);
192 OCRepPayloadSetPropString(payload, OC_RSRVD_DEVICE_ID, OCGetServerInstanceIDString());
196 OCEntityHandlerResult CHPEntityHandler(OCEntityHandlerFlag flag,
197 OCEntityHandlerRequest* entityHandlerRequest,
200 OIC_LOG(INFO, TAG, "Proxy request received");
201 UNUSED(callbackParam);
203 if (!g_isCHProxyInitialized)
205 OIC_LOG (ERROR, TAG, "Proxy not initialized");
206 return OC_EH_INTERNAL_SERVER_ERROR;
209 if (!entityHandlerRequest)
211 OIC_LOG (ERROR, TAG, "Invalid request pointer");
215 if (flag & OC_OBSERVE_FLAG)
217 OIC_LOG_V (ERROR, TAG, "Proxy is not observable");
218 return OC_EH_BAD_REQ;
220 else if (flag & OC_REQUEST_FLAG)
223 * A proxy can handle two type of requests:
224 * 1. Discovery request in which case proxy-uri option will not be present.
225 * 2. Request for HTTP resource with proxy-uri option.
227 char proxyUri[MAX_HEADER_OPTION_DATA_LENGTH] = {'\0'};
228 CHPGetProxyURI(entityHandlerRequest->rcvdVendorSpecificHeaderOptions,
229 &(entityHandlerRequest->numRcvdVendorSpecificHeaderOptions),
230 proxyUri, sizeof(proxyUri));
232 if (proxyUri[0] != '\0')
234 // A request for HTTP resource. Response will be sent asynchronously
235 if (OC_STACK_OK == CHPHandleOCFRequest(entityHandlerRequest,
243 OCEntityHandlerResult ehResult = OC_EH_ERROR;
244 switch (entityHandlerRequest->method)
247 case OC_REST_DISCOVER:
249 // Generate discovery payload
250 OIC_LOG (INFO, TAG, "Discovery request from client");
252 OCEntityHandlerResponse response =
253 { .requestHandle = entityHandlerRequest->requestHandle,
254 .resourceHandle = entityHandlerRequest->resource,
255 .ehResult = ehResult};
257 response.payload = (OCPayload *)CHPGetDiscoveryPayload();
258 // Indicate that response is NOT in a persistent buffer
259 response.persistentBufferFlag = 0;
262 if (OCDoResponse(&response) != OC_STACK_OK)
264 OIC_LOG(ERROR, TAG, "Error sending response");
265 ehResult = OC_EH_ERROR;
268 OCPayloadDestroy(response.payload);
272 // Other methods are not supported
273 OIC_LOG (INFO, TAG, "Invalid method from client");
274 ehResult = OC_EH_METHOD_NOT_ALLOWED;
284 void CHPHandleHttpResponse(const HttpResponse_t *httpResponse, void *context)
286 OIC_LOG_V(DEBUG, TAG, "%s IN", __func__);
287 if (!httpResponse || !context)
289 OIC_LOG(ERROR, TAG, "Invalid arguements");
293 CHPRequest_t *ctxt = (CHPRequest_t *)context;
294 OCEntityHandlerResponse response = { .requestHandle = ctxt->requestHandle,
295 .resourceHandle = g_proxyHandle};
296 response.persistentBufferFlag = 0;
298 OCStackResult result = CHPGetOCCode(httpResponse->status, ctxt->method,
300 if (OC_STACK_OK != result)
302 OIC_LOG_V(ERROR, TAG, "%s failed[%d]", __func__, result);
303 response.ehResult = OC_EH_INTERNAL_SERVER_ERROR;
304 if (OCDoResponse(&response) != OC_STACK_OK)
306 OIC_LOG(ERROR, TAG, "Error sending response");
312 // ctxt not required now.
315 if (httpResponse->dataFormat[0] != '\0')
317 OCPayloadFormat format = CHPGetOCContentType(httpResponse->dataFormat);
321 OIC_LOG(DEBUG, TAG, "Payload format is CBOR");
322 result = OCParsePayload(&response.payload, PAYLOAD_TYPE_REPRESENTATION,
323 httpResponse->payload, httpResponse->payloadLength);
324 if (result != OC_STACK_OK)
326 OIC_LOG(ERROR, TAG, "Error parsing payload");
327 response.ehResult = OC_EH_INTERNAL_SERVER_ERROR;
328 if (OCDoResponse(&response) != OC_STACK_OK)
330 OIC_LOG(ERROR, TAG, "Error sending response");
336 OIC_LOG(DEBUG, TAG, "Payload format is JSON");
337 cJSON *payloadJson = cJSON_Parse((char *)httpResponse->payload);
340 OIC_LOG(ERROR, TAG, "Unable to parse json response");
341 response.ehResult = OC_EH_INTERNAL_SERVER_ERROR;
342 if (OCDoResponse(&response) != OC_STACK_OK)
344 OIC_LOG(ERROR, TAG, "Error sending response");
348 OCRepPayload* payloadCbor = OCRepPayloadCreate();
351 response.ehResult = OC_EH_INTERNAL_SERVER_ERROR;
352 if (OCDoResponse(&response) != OC_STACK_OK)
354 OIC_LOG(ERROR, TAG, "Error sending response");
356 cJSON_Delete(payloadJson);
360 CHPJsonToRepPayload(payloadJson, payloadCbor);
361 response.payload = (OCPayload *)payloadCbor;
362 cJSON_Delete(payloadJson);
365 OIC_LOG(ERROR, TAG, "Payload format is not supported");
366 response.ehResult = OC_EH_INTERNAL_SERVER_ERROR;
367 if (OCDoResponse(&response) != OC_STACK_OK)
369 OIC_LOG(ERROR, TAG, "Error sending response");
374 // Header Options parsing
375 response.numSendVendorSpecificHeaderOptions = 0;
376 OCHeaderOption *optionsPointer = response.sendVendorSpecificHeaderOptions;
378 uint8_t tempOptionNumber = u_arraylist_length(httpResponse->headerOptions);
379 for (int numOptions = 0; numOptions < tempOptionNumber &&
380 response.numSendVendorSpecificHeaderOptions < MAX_HEADER_OPTIONS;
383 HttpHeaderOption_t *httpOption = u_arraylist_get(httpResponse->headerOptions, numOptions);
384 result = CHPGetOCOption(httpOption, optionsPointer);
385 if (OC_STACK_OK != result)
387 OIC_LOG_V(ERROR, TAG, "CHPGetCoAPOption failed[%d][%d]", result,
388 response.numSendVendorSpecificHeaderOptions);
392 response.numSendVendorSpecificHeaderOptions++;
396 if (OCDoResponse(&response) != OC_STACK_OK)
398 OIC_LOG(ERROR, TAG, "Error sending response");
401 //OICFree(coapResponseInfo.info.payload);
402 OIC_LOG_V(DEBUG, TAG, "%s OUT", __func__);
405 OCStackResult CHPHandleOCFRequest(const OCEntityHandlerRequest* requestInfo,
406 const char* proxyUri)
408 OIC_LOG_V(DEBUG, TAG, "%s IN", __func__);
410 HttpRequest_t httpRequest = { .httpMajor = 1,
413 OCEntityHandlerResponse response = { .requestHandle = requestInfo->requestHandle,
414 .resourceHandle = requestInfo->resource};
415 OCStackResult result = CHPGetHttpMethod(requestInfo->method, &httpRequest.method);
416 if (OC_STACK_OK != result)
418 OIC_LOG(ERROR, TAG, "Method not found in HTTP");
419 response.ehResult = OC_EH_BAD_REQ;
420 if (OCDoResponse(&response) != OC_STACK_OK)
422 OIC_LOG(ERROR, TAG, "Error sending response");
425 return OC_STACK_ERROR;
428 uint8_t vendorOptions = requestInfo->numRcvdVendorSpecificHeaderOptions;
431 httpRequest.headerOptions = u_arraylist_create();
432 for (int option = 0; option < vendorOptions; option++)
434 HttpHeaderOption_t *httpOption = NULL;
435 result = CHPGetHttpOption(requestInfo->rcvdVendorSpecificHeaderOptions + option,
437 if (OC_STACK_OK != result || NULL == httpOption )
439 OIC_LOG_V(ERROR, TAG, "CHPGetHttpOption failed [%d]", result);
442 u_arraylist_add(httpRequest.headerOptions, (void *)httpOption);
446 OICStrcpy(httpRequest.resourceUri, sizeof(httpRequest.resourceUri), proxyUri);
448 if (requestInfo->payload && requestInfo->payload->type == PAYLOAD_TYPE_REPRESENTATION)
450 // Conversion from cbor to json.
451 cJSON *payloadJson = CHPRepPayloadToJson((OCRepPayload *)requestInfo->payload);
454 response.ehResult = OC_EH_BAD_REQ;
455 if (OCDoResponse(&response) != OC_STACK_OK)
457 OIC_LOG(ERROR, TAG, "Error sending response");
460 return OC_STACK_ERROR;
463 httpRequest.payload = (void *)cJSON_Print(payloadJson);
464 httpRequest.payloadLength = strlen(httpRequest.payload);
465 OICStrcpy(httpRequest.payloadFormat, sizeof(httpRequest.payloadFormat),
467 cJSON_Delete(payloadJson);
470 OICStrcpy(httpRequest.acceptFormat, sizeof(httpRequest.acceptFormat),
472 CHPRequest_t *chpRequest = (CHPRequest_t *)OICCalloc(1, sizeof(CHPRequest_t));
475 OIC_LOG(ERROR, TAG, "Calloc failed");
476 response.ehResult = OC_EH_INTERNAL_SERVER_ERROR;
477 if (OCDoResponse(&response) != OC_STACK_OK)
479 OIC_LOG(ERROR, TAG, "Error sending response");
482 OICFree(httpRequest.payload);
483 u_arraylist_destroy(httpRequest.headerOptions);
484 return OC_STACK_NO_MEMORY;
487 chpRequest->requestHandle = requestInfo->requestHandle;
488 chpRequest->method = requestInfo->method;
490 result = CHPPostHttpRequest(&httpRequest, CHPHandleHttpResponse,
492 if (OC_STACK_OK != result)
494 OIC_LOG_V(ERROR, TAG, "CHPPostHttpRequest failed[%d]", result);
497 case OC_STACK_INVALID_URI:
498 response.ehResult = OC_EH_BAD_REQ;
501 response.ehResult = OC_EH_INTERNAL_SERVER_ERROR;
504 if (OCDoResponse(&response) != OC_STACK_OK)
506 OIC_LOG(ERROR, TAG, "Error sending response");
509 OICFree(httpRequest.payload);
511 u_arraylist_destroy(httpRequest.headerOptions);
512 return OC_STACK_ERROR;
515 if (!httpRequest.payloadCached)
517 // Free only if parser has not cached it.
518 OICFree(httpRequest.payload);
520 u_arraylist_destroy(httpRequest.headerOptions);
521 OIC_LOG_V(DEBUG, TAG, "%s OUT", __func__);