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()
72 OIC_LOG(DEBUG, TAG, "CHPInitialize IN");
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 result = OCCreateResource(&g_proxyHandle,
95 CHP_RESOURCE_TYPE_NAME,
96 CHP_RESOURCE_INTF_NAME,
100 OC_ACTIVE | OC_DISCOVERABLE | OC_SLOW);
102 if (OC_STACK_OK != result)
104 OIC_LOG_V(ERROR, TAG, "Create resource for proxy failed[%d]", result);
105 CHPParserTerminate();
109 g_isCHProxyInitialized = true;
110 OIC_LOG(DEBUG, TAG, "CHPInitialize OUT");
114 OCStackResult CHPTerminate()
116 OIC_LOG(DEBUG, TAG, "CHPTerminate IN");
117 OCStackResult result = CHPParserTerminate();
118 if (OC_STACK_OK != result)
120 OIC_LOG_V(ERROR, TAG, "Parser termination failed[%d]", result);
123 result = OCDeleteResource(g_proxyHandle);
124 if (OC_STACK_OK != result)
126 OIC_LOG_V(ERROR, TAG, "Delete resource for proxy failed[%d]", result);
129 g_proxyHandle = NULL;
130 g_isCHProxyInitialized = false;
132 OIC_LOG(DEBUG, TAG, "CHPTerminate OUT");
135 static void CHPGetProxyURI(OCHeaderOption* options, uint8_t *numOptions, char* uri,
138 OIC_LOG(DEBUG, TAG, "CHPGetProxyURI IN");
139 if(!uri || uriLength <= 0)
141 OIC_LOG (INFO, TAG, "Invalid uri buffer");
145 if (!options || !numOptions || 0 == *numOptions)
147 OIC_LOG (INFO, TAG, "No options present");
151 for (int count = 0; count < *numOptions; count++)
153 if (options[count].protocolID == OC_COAP_ID &&
154 options[count].optionID == COAP_OPTION_PROXY_URI)
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++)
161 options[count] = options[count+1];
168 OIC_LOG(DEBUG, TAG, "CHPGetProxyURI OUT");
172 // TODO: Will be moved to OCProxyPayload
173 static OCRepPayload* CHPGetDiscoveryPayload()
175 OCRepPayload* payload = OCRepPayloadCreate();
178 OIC_LOG(ERROR, TAG, PCF("Failed to create Payload"));
182 OCRepPayloadSetUri(payload, OC_RSRVD_PROXY_URI);
183 OCRepPayloadSetPropString(payload, OC_RSRVD_DEVICE_ID, OCGetServerInstanceIDString());
187 OCEntityHandlerResult CHPEntityHandler(OCEntityHandlerFlag flag,
188 OCEntityHandlerRequest* entityHandlerRequest,
191 OIC_LOG_V(INFO, TAG, "Proxy request received");
192 UNUSED(callbackParam);
194 if(!g_isCHProxyInitialized)
196 OIC_LOG (ERROR, TAG, "Proxy not initialized");
197 return OC_EH_INTERNAL_SERVER_ERROR;
200 if (!entityHandlerRequest)
202 OIC_LOG (ERROR, TAG, "Invalid request pointer");
206 if(flag & OC_OBSERVE_FLAG)
208 OIC_LOG_V (ERROR, TAG, "Proxy is not observable");
209 return OC_EH_BAD_REQ;
211 else if (flag & OC_REQUEST_FLAG)
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.
218 char proxyUri[MAX_HEADER_OPTION_DATA_LENGTH] = {'\0'};
219 CHPGetProxyURI(entityHandlerRequest->rcvdVendorSpecificHeaderOptions,
220 &(entityHandlerRequest->numRcvdVendorSpecificHeaderOptions),
221 proxyUri, sizeof(proxyUri));
223 if(proxyUri[0] != '\0')
225 // A request for HTTP resource. Response will be sent asynchronously
226 if(OC_STACK_OK == CHPHandleOCFRequest(entityHandlerRequest,
234 OCEntityHandlerResult ehResult = OC_EH_ERROR;
235 switch (entityHandlerRequest->method)
238 case OC_REST_DISCOVER:
240 // Generate discovery payload
241 OIC_LOG (INFO, TAG, "Discovery request from client");
243 OCEntityHandlerResponse response =
244 { .requestHandle = entityHandlerRequest->requestHandle,
245 .resourceHandle = entityHandlerRequest->resource,
246 .ehResult = ehResult};
248 response.payload = (OCPayload *)CHPGetDiscoveryPayload();
249 // Indicate that response is NOT in a persistent buffer
250 response.persistentBufferFlag = 0;
253 if (OCDoResponse(&response) != OC_STACK_OK)
255 OIC_LOG(ERROR, TAG, "Error sending response");
256 ehResult = OC_EH_ERROR;
259 OCPayloadDestroy(response.payload);
263 // Other methods are not supported
264 OIC_LOG (INFO, TAG, "Invalid method from client");
265 ehResult = OC_EH_METHOD_NOT_ALLOWED;
275 void CHPHandleHttpResponse(const HttpResponse_t *httpResponse, void *context)
277 OIC_LOG(DEBUG, TAG, "CHPHandleHttpResponse IN");
278 if (!httpResponse || !context)
280 OIC_LOG(ERROR, TAG, "Invalid arguements");
284 CHPRequest_t *ctxt = (CHPRequest_t *)context;
285 OCEntityHandlerResponse response = { .requestHandle = ctxt->requestHandle,
286 .resourceHandle = g_proxyHandle};
287 response.persistentBufferFlag = 0;
289 OCStackResult result = CHPGetOCCode(httpResponse->status, ctxt->method,
291 if (OC_STACK_OK != result)
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)
297 OIC_LOG(ERROR, TAG, "Error sending response");
303 // ctxt not required now.
306 OCPayloadFormat format = CHPGetOCContentType(httpResponse->dataFormat);
310 OIC_LOG(DEBUG, TAG, "Payload format is CBOR");
311 result = OCParsePayload(&response.payload, PAYLOAD_TYPE_REPRESENTATION,
312 httpResponse->payload, httpResponse->payloadLength);
313 if(result != OC_STACK_OK)
315 OIC_LOG(ERROR, TAG, "Error parsing payload");
316 response.ehResult = OC_EH_INTERNAL_SERVER_ERROR;
317 if (OCDoResponse(&response) != OC_STACK_OK)
319 OIC_LOG(ERROR, TAG, "Error sending response");
325 OIC_LOG(DEBUG, TAG, "Payload format is JSON");
326 cJSON *payloadJson = cJSON_Parse((char *)httpResponse->payload);
327 OCRepPayload* payloadCbor = OCRepPayloadCreate();
330 response.ehResult = OC_EH_INTERNAL_SERVER_ERROR;
331 if (OCDoResponse(&response) != OC_STACK_OK)
333 OIC_LOG(ERROR, TAG, "Error sending response");
335 cJSON_Delete(payloadJson);
339 CHPJsonToRepPayload(payloadJson, payloadCbor);
340 response.payload = (OCPayload *)payloadCbor;
341 cJSON_Delete(payloadJson);
344 OIC_LOG(ERROR, TAG, "Payload format is not supported");
345 response.ehResult = OC_EH_INTERNAL_SERVER_ERROR;
346 if (OCDoResponse(&response) != OC_STACK_OK)
348 OIC_LOG(ERROR, TAG, "Error sending response");
353 // Header Options parsing
354 response.numSendVendorSpecificHeaderOptions = 0;
355 OCHeaderOption *optionsPointer = response.sendVendorSpecificHeaderOptions;
357 uint8_t tempOptionNumber = u_arraylist_length(httpResponse->headerOptions);
358 for (int numOptions = 0; numOptions < tempOptionNumber &&
359 response.numSendVendorSpecificHeaderOptions < MAX_HEADER_OPTIONS;
362 HttpHeaderOption_t *httpOption = u_arraylist_get(httpResponse->headerOptions, numOptions);
363 result = CHPGetOCOption(httpOption, optionsPointer);
364 if (OC_STACK_OK != result)
366 OIC_LOG_V(ERROR, TAG, "CHPGetCoAPOption failed[%d][%d]", result,
367 response.numSendVendorSpecificHeaderOptions);
371 response.numSendVendorSpecificHeaderOptions++;
375 if (OCDoResponse(&response) != OC_STACK_OK)
377 OIC_LOG(ERROR, TAG, "Error sending response");
380 //OICFree(coapResponseInfo.info.payload);
381 OIC_LOG(DEBUG, TAG, "CHPHandleHttpResponse OUT");
384 OCStackResult CHPHandleOCFRequest(const OCEntityHandlerRequest* requestInfo,
385 const char* proxyUri)
387 OIC_LOG_V(DEBUG, TAG, "%s IN", __func__);
389 HttpRequest_t httpRequest = { .httpMajor = 1,
392 OCEntityHandlerResponse response = { .requestHandle = requestInfo->requestHandle,
393 .resourceHandle = requestInfo->resource};
394 OCStackResult result = CHPGetHttpMethod(requestInfo->method, &httpRequest.method);
395 if (OC_STACK_OK != result)
397 OIC_LOG(ERROR, TAG, "Method not found in HTTP");
398 response.ehResult = OC_EH_BAD_REQ;
399 if (OCDoResponse(&response) != OC_STACK_OK)
401 OIC_LOG(ERROR, TAG, "Error sending response");
404 return OC_STACK_ERROR;
407 uint8_t vendorOptions = requestInfo->numRcvdVendorSpecificHeaderOptions;
410 httpRequest.headerOptions = u_arraylist_create();
411 for (int option = 0; option < vendorOptions; option++)
413 HttpHeaderOption_t *httpOption = NULL;
414 result = CHPGetHttpOption(requestInfo->rcvdVendorSpecificHeaderOptions + option,
416 if (OC_STACK_OK != result || NULL == httpOption )
418 OIC_LOG_V(ERROR, TAG, "CHPGetHttpOption failed [%d]", result);
421 u_arraylist_add(httpRequest.headerOptions, (void *)httpOption);
425 OICStrcpy(httpRequest.resourceUri, sizeof(httpRequest.resourceUri), proxyUri);
427 if (requestInfo->payload && requestInfo->payload->type == PAYLOAD_TYPE_REPRESENTATION)
429 // Conversion from cbor to json.
430 cJSON *payloadJson = CHPRepPayloadToJson((OCRepPayload *)requestInfo->payload);
433 response.ehResult = OC_EH_BAD_REQ;
434 if (OCDoResponse(&response) != OC_STACK_OK)
436 OIC_LOG(ERROR, TAG, "Error sending response");
439 return OC_STACK_ERROR;
442 httpRequest.payload = (void *)cJSON_Print(payloadJson);
443 httpRequest.payloadLength = strlen(httpRequest.payload);
444 OICStrcpy(httpRequest.payloadFormat, sizeof(httpRequest.payloadFormat),
446 cJSON_Delete(payloadJson);
449 OICStrcpy(httpRequest.acceptFormat, sizeof(httpRequest.acceptFormat),
451 CHPRequest_t *chpRequest = (CHPRequest_t *)OICCalloc(1, sizeof(CHPRequest_t));
454 OIC_LOG(ERROR, TAG, "Calloc failed");
455 response.ehResult = OC_EH_INTERNAL_SERVER_ERROR;
456 if (OCDoResponse(&response) != OC_STACK_OK)
458 OIC_LOG(ERROR, TAG, "Error sending response");
461 OICFree(httpRequest.payload);
462 u_arraylist_destroy(httpRequest.headerOptions);
463 return OC_STACK_NO_MEMORY;
466 chpRequest->requestHandle = requestInfo->requestHandle;
467 chpRequest->method = requestInfo->method;
469 result = CHPPostHttpRequest(&httpRequest, CHPHandleHttpResponse,
471 if (OC_STACK_OK != result)
473 OIC_LOG_V(ERROR, TAG, "CHPPostHttpRequest failed[%d]", result);
476 case OC_STACK_INVALID_URI:
477 response.ehResult = OC_EH_BAD_REQ;
480 response.ehResult = OC_EH_INTERNAL_SERVER_ERROR;
483 if (OCDoResponse(&response) != OC_STACK_OK)
485 OIC_LOG(ERROR, TAG, "Error sending response");
488 OICFree(httpRequest.payload);
490 u_arraylist_destroy(httpRequest.headerOptions);
491 return OC_STACK_ERROR;
494 if(!httpRequest.payloadCached)
496 // Free only if parser has not cached it.
497 OICFree(httpRequest.payload);
499 u_arraylist_destroy(httpRequest.headerOptions);
500 OIC_LOG_V(DEBUG, TAG, "%s OUT", __func__);