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 "platform_features.h"
23 #include "oic_malloc.h"
24 #include "oic_string.h"
25 #include "experimental/logger.h"
27 #include "ocpayload.h"
28 #include "internal/ocpayloadcbor.h"
29 #include "uarraylist.h"
30 #include "CoapHttpParser.h"
31 #include "CoapHttpMap.h"
34 #define TAG "CHPHandler"
36 #define CHP_RESOURCE_TYPE_NAME "core.chp"
37 #define CHP_RESOURCE_INTF_NAME "oc.mi.def"
40 * CoAP request tracking.
41 * This structure is used to hold CoAP request information
46 OCRequestHandle requestHandle;
50 * Pointer to handle of the newly created proxy resource.
52 static OCResourceHandle g_proxyHandle = NULL;
53 static int g_isCHProxyInitialized = false;
56 * Function to hand over CoAP request handling to Proxy.
58 OCStackResult CHPHandleOCFRequest(const OCEntityHandlerRequest* requestInfo,
59 const char* proxyUri);
62 * Entity handler to receive requests from csdk.
64 OCEntityHandlerResult CHPEntityHandler(OCEntityHandlerFlag flag,
65 OCEntityHandlerRequest* entityHandlerRequest,
67 bool CHPIsInitialized(void)
69 return g_isCHProxyInitialized;
72 OCStackResult CHPInitialize(bool secure)
74 OIC_LOG_V(DEBUG, TAG, "%s IN", __func__);
75 if (g_isCHProxyInitialized)
77 OIC_LOG(DEBUG, TAG, "CH Proxy already initialized");
81 OCStackResult result = CHPParserInitialize();
82 if (OC_STACK_OK != result)
84 OIC_LOG_V(ERROR, TAG, "Parser initialization failed[%d]", result);
88 result = OCSetProxyURI(OC_RSRVD_PROXY_URI);
89 if (OC_STACK_OK != result)
91 OIC_LOG_V(ERROR, TAG, "Setting proxy uri failed[%d]", result);
96 uint8_t prop = OC_ACTIVE | OC_DISCOVERABLE | OC_SLOW;
101 result = OCCreateResource(&g_proxyHandle,
102 CHP_RESOURCE_TYPE_NAME,
103 CHP_RESOURCE_INTF_NAME,
109 if (OC_STACK_OK != result)
111 OIC_LOG_V(ERROR, TAG, "Create resource for proxy failed[%d]", result);
112 CHPParserTerminate();
116 g_isCHProxyInitialized = true;
117 OIC_LOG_V(DEBUG, TAG, "%s OUT", __func__);
121 OCStackResult CHPTerminate(void)
123 OIC_LOG_V(DEBUG, TAG, "%s IN", __func__);
125 if (!g_isCHProxyInitialized)
127 OIC_LOG(ERROR, TAG, "CH Proxy not initialized");
131 OCStackResult result = CHPParserTerminate();
132 if (OC_STACK_OK != result)
134 OIC_LOG_V(ERROR, TAG, "Parser termination failed[%d]", result);
137 result = OCDeleteResource(g_proxyHandle);
138 if (OC_STACK_OK != result)
140 OIC_LOG_V(ERROR, TAG, "Delete resource for proxy failed[%d]", result);
143 g_proxyHandle = NULL;
144 g_isCHProxyInitialized = false;
145 OIC_LOG_V(DEBUG, TAG, "%s OUT", __func__);
149 static void CHPGetProxyURI(OCHeaderOption* options, uint8_t *numOptions, char* uri,
152 OIC_LOG_V(DEBUG, TAG, "%s IN", __func__);
153 if (!uri || uriLength <= 0)
155 OIC_LOG (INFO, TAG, "Invalid uri buffer");
159 if (!options || !numOptions || 0 == *numOptions)
161 OIC_LOG (INFO, TAG, "No options present");
165 for (uint8_t count = 0; count < *numOptions; count++)
167 if (options[count].protocolID == OC_COAP_ID &&
168 options[count].optionID == COAP_OPTION_PROXY_URI)
170 OIC_LOG(DEBUG, TAG, "Proxy URI is present");
171 // Extract proxy-uri and delete it from headeroptions.
172 OICStrcpy(uri, uriLength, (char *)options[count].optionData);
173 for (uint8_t fwd = count; fwd < *numOptions - 1; fwd++)
175 options[count] = options[count + 1];
182 OIC_LOG_V(DEBUG, TAG, "%s OUT", __func__);
186 // TODO: Will be moved to OCProxyPayload
187 static OCRepPayload* CHPGetDiscoveryPayload(void)
189 OCRepPayload* payload = OCRepPayloadCreate();
192 OIC_LOG(ERROR, TAG, PCF("Failed to create Payload"));
196 OCRepPayloadSetUri(payload, OC_RSRVD_PROXY_URI);
197 OCRepPayloadSetPropString(payload, OC_RSRVD_DEVICE_ID, OCGetServerInstanceIDString());
201 OCEntityHandlerResult CHPEntityHandler(OCEntityHandlerFlag flag,
202 OCEntityHandlerRequest* entityHandlerRequest,
205 OIC_LOG(INFO, TAG, "Proxy request received");
206 OC_UNUSED(callbackParam);
208 if (!g_isCHProxyInitialized)
210 OIC_LOG (ERROR, TAG, "Proxy not initialized");
211 return OC_EH_INTERNAL_SERVER_ERROR;
214 if (!entityHandlerRequest)
216 OIC_LOG (ERROR, TAG, "Invalid request pointer");
220 if (flag & OC_OBSERVE_FLAG)
222 OIC_LOG_V (ERROR, TAG, "Proxy is not observable");
223 return OC_EH_BAD_REQ;
225 else if (flag & OC_REQUEST_FLAG)
228 * A proxy can handle two type of requests:
229 * 1. Discovery request in which case proxy-uri option will not be present.
230 * 2. Request for HTTP resource with proxy-uri option.
232 char proxyUri[MAX_HEADER_OPTION_DATA_LENGTH] = {'\0'};
233 CHPGetProxyURI(entityHandlerRequest->rcvdVendorSpecificHeaderOptions,
234 &(entityHandlerRequest->numRcvdVendorSpecificHeaderOptions),
235 proxyUri, sizeof(proxyUri));
237 if (proxyUri[0] != '\0')
239 // A request for HTTP resource. Response will be sent asynchronously
240 if (OC_STACK_OK == CHPHandleOCFRequest(entityHandlerRequest,
248 OCEntityHandlerResult ehResult = OC_EH_ERROR;
249 switch (entityHandlerRequest->method)
252 case OC_REST_DISCOVER:
254 // Generate discovery payload
255 OIC_LOG (INFO, TAG, "Discovery request from client");
257 OCEntityHandlerResponse response =
258 { .requestHandle = entityHandlerRequest->requestHandle,
259 .ehResult = ehResult};
261 response.payload = (OCPayload *)CHPGetDiscoveryPayload();
262 // Indicate that response is NOT in a persistent buffer
263 response.persistentBufferFlag = 0;
266 if (OCDoResponse(&response) != OC_STACK_OK)
268 OIC_LOG(ERROR, TAG, "Error sending response");
269 ehResult = OC_EH_ERROR;
272 OCPayloadDestroy(response.payload);
276 // Other methods are not supported
277 OIC_LOG (INFO, TAG, "Invalid method from client");
278 ehResult = OC_EH_METHOD_NOT_ALLOWED;
288 void CHPHandleHttpResponse(const HttpResponse_t *httpResponse, void *context)
290 OIC_LOG_V(DEBUG, TAG, "%s IN", __func__);
291 if (!httpResponse || !context)
293 OIC_LOG(ERROR, TAG, "Invalid arguements");
297 CHPRequest_t *ctxt = (CHPRequest_t *)context;
298 OCEntityHandlerResponse response = { .requestHandle = ctxt->requestHandle };
299 response.persistentBufferFlag = 0;
301 OCStackResult result = CHPGetOCCode(httpResponse->status, ctxt->method,
303 if (OC_STACK_OK != result)
305 OIC_LOG_V(ERROR, TAG, "%s failed[%d]", __func__, result);
306 response.ehResult = OC_EH_INTERNAL_SERVER_ERROR;
307 if (OCDoResponse(&response) != OC_STACK_OK)
309 OIC_LOG(ERROR, TAG, "Error sending response");
315 // ctxt not required now.
318 if (httpResponse->dataFormat[0] != '\0')
320 OCPayloadFormat format = CHPGetOCContentType(httpResponse->dataFormat);
324 OIC_LOG(DEBUG, TAG, "Payload format is CBOR");
325 result = OCParsePayload(&response.payload, OC_FORMAT_CBOR, PAYLOAD_TYPE_REPRESENTATION,
326 httpResponse->payload, httpResponse->payloadLength);
327 if (result != OC_STACK_OK)
329 OIC_LOG(ERROR, TAG, "Error parsing payload");
330 response.ehResult = OC_EH_INTERNAL_SERVER_ERROR;
331 if (OCDoResponse(&response) != OC_STACK_OK)
333 OIC_LOG(ERROR, TAG, "Error sending response");
339 OIC_LOG(DEBUG, TAG, "Payload format is JSON");
340 cJSON *payloadJson = cJSON_Parse((char *)httpResponse->payload);
343 OIC_LOG(ERROR, TAG, "Unable to parse json response");
344 response.ehResult = OC_EH_INTERNAL_SERVER_ERROR;
345 if (OCDoResponse(&response) != OC_STACK_OK)
347 OIC_LOG(ERROR, TAG, "Error sending response");
351 OCRepPayload* payloadCbor = OCRepPayloadCreate();
354 response.ehResult = OC_EH_INTERNAL_SERVER_ERROR;
355 if (OCDoResponse(&response) != OC_STACK_OK)
357 OIC_LOG(ERROR, TAG, "Error sending response");
359 cJSON_Delete(payloadJson);
363 CHPJsonToRepPayload(payloadJson, payloadCbor);
364 response.payload = (OCPayload *)payloadCbor;
365 cJSON_Delete(payloadJson);
368 OIC_LOG(ERROR, TAG, "Payload format is not supported");
369 response.ehResult = OC_EH_INTERNAL_SERVER_ERROR;
370 if (OCDoResponse(&response) != OC_STACK_OK)
372 OIC_LOG(ERROR, TAG, "Error sending response");
377 // Header Options parsing
378 response.numSendVendorSpecificHeaderOptions = 0;
379 OCHeaderOption *optionsPointer = response.sendVendorSpecificHeaderOptions;
381 size_t tempOptionNumber = u_arraylist_length(httpResponse->headerOptions);
382 for (size_t numOptions = 0; (numOptions < tempOptionNumber) &&
383 (response.numSendVendorSpecificHeaderOptions < MAX_HEADER_OPTIONS);
386 HttpHeaderOption_t *httpOption = u_arraylist_get(httpResponse->headerOptions, numOptions);
387 result = CHPGetOCOption(httpOption, optionsPointer);
388 if (OC_STACK_OK != result)
390 OIC_LOG_V(ERROR, TAG, "CHPGetCoAPOption failed[%d][%d]", result,
391 response.numSendVendorSpecificHeaderOptions);
395 response.numSendVendorSpecificHeaderOptions++;
399 if (OCDoResponse(&response) != OC_STACK_OK)
401 OIC_LOG(ERROR, TAG, "Error sending response");
404 //OICFree(coapResponseInfo.info.payload);
405 OIC_LOG_V(DEBUG, TAG, "%s OUT", __func__);
408 OCStackResult CHPHandleOCFRequest(const OCEntityHandlerRequest* requestInfo,
409 const char* proxyUri)
411 OIC_LOG_V(DEBUG, TAG, "%s IN", __func__);
413 HttpRequest_t httpRequest = { .httpMajor = 1,
416 OCEntityHandlerResponse response = { .requestHandle = requestInfo->requestHandle };
417 OCStackResult result = CHPGetHttpMethod(requestInfo->method, &httpRequest.method);
418 if (OC_STACK_OK != result)
420 OIC_LOG(ERROR, TAG, "Method not found in HTTP");
421 response.ehResult = OC_EH_BAD_REQ;
422 if (OCDoResponse(&response) != OC_STACK_OK)
424 OIC_LOG(ERROR, TAG, "Error sending response");
427 return OC_STACK_ERROR;
430 uint8_t vendorOptionsCount = requestInfo->numRcvdVendorSpecificHeaderOptions;
431 if (vendorOptionsCount)
433 httpRequest.headerOptions = u_arraylist_create();
434 for (uint8_t option = 0; option < vendorOptionsCount; option++)
436 HttpHeaderOption_t *httpOption = NULL;
437 result = CHPGetHttpOption(requestInfo->rcvdVendorSpecificHeaderOptions + option,
439 if (OC_STACK_OK != result || NULL == httpOption )
441 OIC_LOG_V(ERROR, TAG, "CHPGetHttpOption failed [%d]", result);
444 u_arraylist_add(httpRequest.headerOptions, (void *)httpOption);
448 OICStrcpy(httpRequest.resourceUri, sizeof(httpRequest.resourceUri), proxyUri);
450 if (requestInfo->payload && requestInfo->payload->type == PAYLOAD_TYPE_REPRESENTATION)
452 // Conversion from cbor to json.
453 cJSON *payloadJson = CHPRepPayloadToJson((OCRepPayload *)requestInfo->payload);
456 response.ehResult = OC_EH_BAD_REQ;
457 if (OCDoResponse(&response) != OC_STACK_OK)
459 OIC_LOG(ERROR, TAG, "Error sending response");
462 return OC_STACK_ERROR;
465 httpRequest.payload = (void *)cJSON_Print(payloadJson);
466 httpRequest.payloadLength = strlen(httpRequest.payload);
467 OICStrcpy(httpRequest.payloadFormat, sizeof(httpRequest.payloadFormat),
469 cJSON_Delete(payloadJson);
472 OICStrcpy(httpRequest.acceptFormat, sizeof(httpRequest.acceptFormat),
474 CHPRequest_t *chpRequest = (CHPRequest_t *)OICCalloc(1, sizeof(CHPRequest_t));
477 OIC_LOG(ERROR, TAG, "Calloc failed");
478 response.ehResult = OC_EH_INTERNAL_SERVER_ERROR;
479 if (OCDoResponse(&response) != OC_STACK_OK)
481 OIC_LOG(ERROR, TAG, "Error sending response");
484 OICFree(httpRequest.payload);
485 u_arraylist_destroy(httpRequest.headerOptions);
486 return OC_STACK_NO_MEMORY;
489 chpRequest->requestHandle = requestInfo->requestHandle;
490 chpRequest->method = requestInfo->method;
492 result = CHPPostHttpRequest(&httpRequest, CHPHandleHttpResponse,
494 if (OC_STACK_OK != result)
496 OIC_LOG_V(ERROR, TAG, "CHPPostHttpRequest failed[%d]", result);
499 case OC_STACK_INVALID_URI:
500 response.ehResult = OC_EH_BAD_REQ;
503 response.ehResult = OC_EH_INTERNAL_SERVER_ERROR;
506 if (OCDoResponse(&response) != OC_STACK_OK)
508 OIC_LOG(ERROR, TAG, "Error sending response");
511 OICFree(httpRequest.payload);
513 u_arraylist_destroy(httpRequest.headerOptions);
514 return OC_STACK_ERROR;
517 if (!httpRequest.payloadCached)
519 // Free only if parser has not cached it.
520 OICFree(httpRequest.payload);
522 u_arraylist_destroy(httpRequest.headerOptions);
523 OIC_LOG_V(DEBUG, TAG, "%s OUT", __func__);