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"
32 #define TAG "CHPHandler"
34 #define CHP_RESOURCE_TYPE_NAME "core.chp"
35 #define CHP_RESOURCE_INTF_NAME "oc.mi.def"
38 * CoAP request tracking.
39 * This structure is used to hold CoAP request information
44 OCRequestHandle requestHandle;
48 * Pointer to handle of the newly created proxy resource.
50 static OCResourceHandle g_proxyHandle = NULL;
51 static int g_isCHProxyInitialized = false;
54 * Function to hand over CoAP request handling to Proxy.
56 OCStackResult CHPHandleOCFRequest(const OCEntityHandlerRequest* requestInfo,
57 const char* proxyUri);
60 * Entity handler to receive requests from csdk.
62 OCEntityHandlerResult CHPEntityHandler(OCEntityHandlerFlag flag,
63 OCEntityHandlerRequest* entityHandlerRequest,
65 bool CHPIsInitialized()
67 return g_isCHProxyInitialized;
70 OCStackResult CHPInitialize(bool secure)
72 OIC_LOG_V(DEBUG, TAG, "%s IN", __func__);
73 if (g_isCHProxyInitialized)
75 OIC_LOG(DEBUG, TAG, "CH Proxy already initialized");
79 OCStackResult result = CHPParserInitialize();
80 if (OC_STACK_OK != result)
82 OIC_LOG_V(ERROR, TAG, "Parser initialization failed[%d]", result);
86 result = OCSetProxyURI(OC_RSRVD_PROXY_URI);
87 if (OC_STACK_OK != result)
89 OIC_LOG_V(ERROR, TAG, "Setting proxy uri failed[%d]", result);
94 uint8_t prop = OC_ACTIVE | OC_DISCOVERABLE | OC_SLOW;
99 result = OCCreateResource(&g_proxyHandle,
100 CHP_RESOURCE_TYPE_NAME,
101 CHP_RESOURCE_INTF_NAME,
107 if (OC_STACK_OK != result)
109 OIC_LOG_V(ERROR, TAG, "Create resource for proxy failed[%d]", result);
110 CHPParserTerminate();
114 g_isCHProxyInitialized = true;
115 OIC_LOG_V(DEBUG, TAG, "%s OUT", __func__);
119 OCStackResult CHPTerminate()
121 OIC_LOG_V(DEBUG, TAG, "%s IN", __func__);
122 OCStackResult result = CHPParserTerminate();
123 if (OC_STACK_OK != result)
125 OIC_LOG_V(ERROR, TAG, "Parser termination failed[%d]", result);
128 result = OCDeleteResource(g_proxyHandle);
129 if (OC_STACK_OK != result)
131 OIC_LOG_V(ERROR, TAG, "Delete resource for proxy failed[%d]", result);
134 g_proxyHandle = NULL;
135 g_isCHProxyInitialized = false;
137 OIC_LOG_V(DEBUG, TAG, "%s OUT", __func__);
140 static void CHPGetProxyURI(OCHeaderOption* options, uint8_t *numOptions, char* uri,
143 OIC_LOG_V(DEBUG, TAG, "%s IN", __func__);
144 if (!uri || uriLength <= 0)
146 OIC_LOG (INFO, TAG, "Invalid uri buffer");
150 if (!options || !numOptions || 0 == *numOptions)
152 OIC_LOG (INFO, TAG, "No options present");
156 for (int count = 0; count < *numOptions; count++)
158 if (options[count].protocolID == OC_COAP_ID &&
159 options[count].optionID == COAP_OPTION_PROXY_URI)
161 OIC_LOG(DEBUG, TAG, "Proxy URI is present");
162 // Extract proxy-uri and delete it from headeroptions.
163 OICStrcpy(uri, uriLength, (char *)options[count].optionData);
164 for (int fwd = count; fwd < *numOptions-1; fwd++)
166 options[count] = options[count+1];
173 OIC_LOG_V(DEBUG, TAG, "%s OUT", __func__);
177 // TODO: Will be moved to OCProxyPayload
178 static OCRepPayload* CHPGetDiscoveryPayload()
180 OCRepPayload* payload = OCRepPayloadCreate();
183 OIC_LOG(ERROR, TAG, PCF("Failed to create Payload"));
187 OCRepPayloadSetUri(payload, OC_RSRVD_PROXY_URI);
188 OCRepPayloadSetPropString(payload, OC_RSRVD_DEVICE_ID, OCGetServerInstanceIDString());
192 OCEntityHandlerResult CHPEntityHandler(OCEntityHandlerFlag flag,
193 OCEntityHandlerRequest* entityHandlerRequest,
196 OIC_LOG(INFO, TAG, "Proxy request received");
197 UNUSED(callbackParam);
199 if (!g_isCHProxyInitialized)
201 OIC_LOG (ERROR, TAG, "Proxy not initialized");
202 return OC_EH_INTERNAL_SERVER_ERROR;
205 if (!entityHandlerRequest)
207 OIC_LOG (ERROR, TAG, "Invalid request pointer");
211 if (flag & OC_OBSERVE_FLAG)
213 OIC_LOG_V (ERROR, TAG, "Proxy is not observable");
214 return OC_EH_BAD_REQ;
216 else if (flag & OC_REQUEST_FLAG)
219 * A proxy can handle two type of requests:
220 * 1. Discovery request in which case proxy-uri option will not be present.
221 * 2. Request for HTTP resource with proxy-uri option.
223 char proxyUri[MAX_HEADER_OPTION_DATA_LENGTH] = {'\0'};
224 CHPGetProxyURI(entityHandlerRequest->rcvdVendorSpecificHeaderOptions,
225 &(entityHandlerRequest->numRcvdVendorSpecificHeaderOptions),
226 proxyUri, sizeof(proxyUri));
228 if (proxyUri[0] != '\0')
230 // A request for HTTP resource. Response will be sent asynchronously
231 if (OC_STACK_OK == CHPHandleOCFRequest(entityHandlerRequest,
239 OCEntityHandlerResult ehResult = OC_EH_ERROR;
240 switch (entityHandlerRequest->method)
243 case OC_REST_DISCOVER:
245 // Generate discovery payload
246 OIC_LOG (INFO, TAG, "Discovery request from client");
248 OCEntityHandlerResponse response =
249 { .requestHandle = entityHandlerRequest->requestHandle,
250 .resourceHandle = entityHandlerRequest->resource,
251 .ehResult = ehResult};
253 response.payload = (OCPayload *)CHPGetDiscoveryPayload();
254 // Indicate that response is NOT in a persistent buffer
255 response.persistentBufferFlag = 0;
258 if (OCDoResponse(&response) != OC_STACK_OK)
260 OIC_LOG(ERROR, TAG, "Error sending response");
261 ehResult = OC_EH_ERROR;
264 OCPayloadDestroy(response.payload);
268 // Other methods are not supported
269 OIC_LOG (INFO, TAG, "Invalid method from client");
270 ehResult = OC_EH_METHOD_NOT_ALLOWED;
280 void CHPHandleHttpResponse(const HttpResponse_t *httpResponse, void *context)
282 OIC_LOG_V(DEBUG, TAG, "%s IN", __func__);
283 if (!httpResponse || !context)
285 OIC_LOG(ERROR, TAG, "Invalid arguements");
289 CHPRequest_t *ctxt = (CHPRequest_t *)context;
290 OCEntityHandlerResponse response = { .requestHandle = ctxt->requestHandle,
291 .resourceHandle = g_proxyHandle};
292 response.persistentBufferFlag = 0;
294 OCStackResult result = CHPGetOCCode(httpResponse->status, ctxt->method,
296 if (OC_STACK_OK != result)
298 OIC_LOG_V(ERROR, TAG, "%s failed[%d]", __func__, result);
299 response.ehResult = OC_EH_INTERNAL_SERVER_ERROR;
300 if (OCDoResponse(&response) != OC_STACK_OK)
302 OIC_LOG(ERROR, TAG, "Error sending response");
308 // ctxt not required now.
311 if (httpResponse->dataFormat[0] != '\0')
313 OCPayloadFormat format = CHPGetOCContentType(httpResponse->dataFormat);
317 OIC_LOG(DEBUG, TAG, "Payload format is CBOR");
318 result = OCParsePayload(&response.payload, PAYLOAD_TYPE_REPRESENTATION,
319 httpResponse->payload, httpResponse->payloadLength);
320 if (result != OC_STACK_OK)
322 OIC_LOG(ERROR, TAG, "Error parsing payload");
323 response.ehResult = OC_EH_INTERNAL_SERVER_ERROR;
324 if (OCDoResponse(&response) != OC_STACK_OK)
326 OIC_LOG(ERROR, TAG, "Error sending response");
332 OIC_LOG(DEBUG, TAG, "Payload format is JSON");
333 cJSON *payloadJson = cJSON_Parse((char *)httpResponse->payload);
336 OIC_LOG(ERROR, TAG, "Unable to parse json response");
337 response.ehResult = OC_EH_INTERNAL_SERVER_ERROR;
338 if (OCDoResponse(&response) != OC_STACK_OK)
340 OIC_LOG(ERROR, TAG, "Error sending response");
344 OCRepPayload* payloadCbor = OCRepPayloadCreate();
347 response.ehResult = OC_EH_INTERNAL_SERVER_ERROR;
348 if (OCDoResponse(&response) != OC_STACK_OK)
350 OIC_LOG(ERROR, TAG, "Error sending response");
352 cJSON_Delete(payloadJson);
356 CHPJsonToRepPayload(payloadJson, payloadCbor);
357 response.payload = (OCPayload *)payloadCbor;
358 cJSON_Delete(payloadJson);
361 OIC_LOG(ERROR, TAG, "Payload format is not supported");
362 response.ehResult = OC_EH_INTERNAL_SERVER_ERROR;
363 if (OCDoResponse(&response) != OC_STACK_OK)
365 OIC_LOG(ERROR, TAG, "Error sending response");
370 // Header Options parsing
371 response.numSendVendorSpecificHeaderOptions = 0;
372 OCHeaderOption *optionsPointer = response.sendVendorSpecificHeaderOptions;
374 uint8_t tempOptionNumber = u_arraylist_length(httpResponse->headerOptions);
375 for (int numOptions = 0; numOptions < tempOptionNumber &&
376 response.numSendVendorSpecificHeaderOptions < MAX_HEADER_OPTIONS;
379 HttpHeaderOption_t *httpOption = u_arraylist_get(httpResponse->headerOptions, numOptions);
380 result = CHPGetOCOption(httpOption, optionsPointer);
381 if (OC_STACK_OK != result)
383 OIC_LOG_V(ERROR, TAG, "CHPGetCoAPOption failed[%d][%d]", result,
384 response.numSendVendorSpecificHeaderOptions);
388 response.numSendVendorSpecificHeaderOptions++;
392 if (OCDoResponse(&response) != OC_STACK_OK)
394 OIC_LOG(ERROR, TAG, "Error sending response");
397 //OICFree(coapResponseInfo.info.payload);
398 OIC_LOG_V(DEBUG, TAG, "%s OUT", __func__);
401 OCStackResult CHPHandleOCFRequest(const OCEntityHandlerRequest* requestInfo,
402 const char* proxyUri)
404 OIC_LOG_V(DEBUG, TAG, "%s IN", __func__);
406 HttpRequest_t httpRequest = { .httpMajor = 1,
409 OCEntityHandlerResponse response = { .requestHandle = requestInfo->requestHandle,
410 .resourceHandle = requestInfo->resource};
411 OCStackResult result = CHPGetHttpMethod(requestInfo->method, &httpRequest.method);
412 if (OC_STACK_OK != result)
414 OIC_LOG(ERROR, TAG, "Method not found in HTTP");
415 response.ehResult = OC_EH_BAD_REQ;
416 if (OCDoResponse(&response) != OC_STACK_OK)
418 OIC_LOG(ERROR, TAG, "Error sending response");
421 return OC_STACK_ERROR;
424 uint8_t vendorOptions = requestInfo->numRcvdVendorSpecificHeaderOptions;
427 httpRequest.headerOptions = u_arraylist_create();
428 for (int option = 0; option < vendorOptions; option++)
430 HttpHeaderOption_t *httpOption = NULL;
431 result = CHPGetHttpOption(requestInfo->rcvdVendorSpecificHeaderOptions + option,
433 if (OC_STACK_OK != result || NULL == httpOption )
435 OIC_LOG_V(ERROR, TAG, "CHPGetHttpOption failed [%d]", result);
438 u_arraylist_add(httpRequest.headerOptions, (void *)httpOption);
442 OICStrcpy(httpRequest.resourceUri, sizeof(httpRequest.resourceUri), proxyUri);
444 if (requestInfo->payload && requestInfo->payload->type == PAYLOAD_TYPE_REPRESENTATION)
446 // Conversion from cbor to json.
447 cJSON *payloadJson = CHPRepPayloadToJson((OCRepPayload *)requestInfo->payload);
450 response.ehResult = OC_EH_BAD_REQ;
451 if (OCDoResponse(&response) != OC_STACK_OK)
453 OIC_LOG(ERROR, TAG, "Error sending response");
456 return OC_STACK_ERROR;
459 httpRequest.payload = (void *)cJSON_Print(payloadJson);
460 httpRequest.payloadLength = strlen(httpRequest.payload);
461 OICStrcpy(httpRequest.payloadFormat, sizeof(httpRequest.payloadFormat),
463 cJSON_Delete(payloadJson);
466 OICStrcpy(httpRequest.acceptFormat, sizeof(httpRequest.acceptFormat),
468 CHPRequest_t *chpRequest = (CHPRequest_t *)OICCalloc(1, sizeof(CHPRequest_t));
471 OIC_LOG(ERROR, TAG, "Calloc failed");
472 response.ehResult = OC_EH_INTERNAL_SERVER_ERROR;
473 if (OCDoResponse(&response) != OC_STACK_OK)
475 OIC_LOG(ERROR, TAG, "Error sending response");
478 OICFree(httpRequest.payload);
479 u_arraylist_destroy(httpRequest.headerOptions);
480 return OC_STACK_NO_MEMORY;
483 chpRequest->requestHandle = requestInfo->requestHandle;
484 chpRequest->method = requestInfo->method;
486 result = CHPPostHttpRequest(&httpRequest, CHPHandleHttpResponse,
488 if (OC_STACK_OK != result)
490 OIC_LOG_V(ERROR, TAG, "CHPPostHttpRequest failed[%d]", result);
493 case OC_STACK_INVALID_URI:
494 response.ehResult = OC_EH_BAD_REQ;
497 response.ehResult = OC_EH_INTERNAL_SERVER_ERROR;
500 if (OCDoResponse(&response) != OC_STACK_OK)
502 OIC_LOG(ERROR, TAG, "Error sending response");
505 OICFree(httpRequest.payload);
507 u_arraylist_destroy(httpRequest.headerOptions);
508 return OC_STACK_ERROR;
511 if (!httpRequest.payloadCached)
513 // Free only if parser has not cached it.
514 OICFree(httpRequest.payload);
516 u_arraylist_destroy(httpRequest.headerOptions);
517 OIC_LOG_V(DEBUG, TAG, "%s OUT", __func__);