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 if (httpResponse->dataFormat[0] != '\0')
308 OCPayloadFormat format = CHPGetOCContentType(httpResponse->dataFormat);
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)
317 OIC_LOG(ERROR, TAG, "Error parsing payload");
318 response.ehResult = OC_EH_INTERNAL_SERVER_ERROR;
319 if (OCDoResponse(&response) != OC_STACK_OK)
321 OIC_LOG(ERROR, TAG, "Error sending response");
327 OIC_LOG(DEBUG, TAG, "Payload format is JSON");
328 cJSON *payloadJson = cJSON_Parse((char *)httpResponse->payload);
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)
335 OIC_LOG(ERROR, TAG, "Error sending response");
339 OCRepPayload* payloadCbor = OCRepPayloadCreate();
342 response.ehResult = OC_EH_INTERNAL_SERVER_ERROR;
343 if (OCDoResponse(&response) != OC_STACK_OK)
345 OIC_LOG(ERROR, TAG, "Error sending response");
347 cJSON_Delete(payloadJson);
351 CHPJsonToRepPayload(payloadJson, payloadCbor);
352 response.payload = (OCPayload *)payloadCbor;
353 cJSON_Delete(payloadJson);
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)
360 OIC_LOG(ERROR, TAG, "Error sending response");
365 // Header Options parsing
366 response.numSendVendorSpecificHeaderOptions = 0;
367 OCHeaderOption *optionsPointer = response.sendVendorSpecificHeaderOptions;
369 uint8_t tempOptionNumber = u_arraylist_length(httpResponse->headerOptions);
370 for (int numOptions = 0; numOptions < tempOptionNumber &&
371 response.numSendVendorSpecificHeaderOptions < MAX_HEADER_OPTIONS;
374 HttpHeaderOption_t *httpOption = u_arraylist_get(httpResponse->headerOptions, numOptions);
375 result = CHPGetOCOption(httpOption, optionsPointer);
376 if (OC_STACK_OK != result)
378 OIC_LOG_V(ERROR, TAG, "CHPGetCoAPOption failed[%d][%d]", result,
379 response.numSendVendorSpecificHeaderOptions);
383 response.numSendVendorSpecificHeaderOptions++;
387 if (OCDoResponse(&response) != OC_STACK_OK)
389 OIC_LOG(ERROR, TAG, "Error sending response");
392 //OICFree(coapResponseInfo.info.payload);
393 OIC_LOG(DEBUG, TAG, "CHPHandleHttpResponse OUT");
396 OCStackResult CHPHandleOCFRequest(const OCEntityHandlerRequest* requestInfo,
397 const char* proxyUri)
399 OIC_LOG_V(DEBUG, TAG, "%s IN", __func__);
401 HttpRequest_t httpRequest = { .httpMajor = 1,
404 OCEntityHandlerResponse response = { .requestHandle = requestInfo->requestHandle,
405 .resourceHandle = requestInfo->resource};
406 OCStackResult result = CHPGetHttpMethod(requestInfo->method, &httpRequest.method);
407 if (OC_STACK_OK != result)
409 OIC_LOG(ERROR, TAG, "Method not found in HTTP");
410 response.ehResult = OC_EH_BAD_REQ;
411 if (OCDoResponse(&response) != OC_STACK_OK)
413 OIC_LOG(ERROR, TAG, "Error sending response");
416 return OC_STACK_ERROR;
419 uint8_t vendorOptions = requestInfo->numRcvdVendorSpecificHeaderOptions;
422 httpRequest.headerOptions = u_arraylist_create();
423 for (int option = 0; option < vendorOptions; option++)
425 HttpHeaderOption_t *httpOption = NULL;
426 result = CHPGetHttpOption(requestInfo->rcvdVendorSpecificHeaderOptions + option,
428 if (OC_STACK_OK != result || NULL == httpOption )
430 OIC_LOG_V(ERROR, TAG, "CHPGetHttpOption failed [%d]", result);
433 u_arraylist_add(httpRequest.headerOptions, (void *)httpOption);
437 OICStrcpy(httpRequest.resourceUri, sizeof(httpRequest.resourceUri), proxyUri);
439 if (requestInfo->payload && requestInfo->payload->type == PAYLOAD_TYPE_REPRESENTATION)
441 // Conversion from cbor to json.
442 cJSON *payloadJson = CHPRepPayloadToJson((OCRepPayload *)requestInfo->payload);
445 response.ehResult = OC_EH_BAD_REQ;
446 if (OCDoResponse(&response) != OC_STACK_OK)
448 OIC_LOG(ERROR, TAG, "Error sending response");
451 return OC_STACK_ERROR;
454 httpRequest.payload = (void *)cJSON_Print(payloadJson);
455 httpRequest.payloadLength = strlen(httpRequest.payload);
456 OICStrcpy(httpRequest.payloadFormat, sizeof(httpRequest.payloadFormat),
458 cJSON_Delete(payloadJson);
461 OICStrcpy(httpRequest.acceptFormat, sizeof(httpRequest.acceptFormat),
463 CHPRequest_t *chpRequest = (CHPRequest_t *)OICCalloc(1, sizeof(CHPRequest_t));
466 OIC_LOG(ERROR, TAG, "Calloc failed");
467 response.ehResult = OC_EH_INTERNAL_SERVER_ERROR;
468 if (OCDoResponse(&response) != OC_STACK_OK)
470 OIC_LOG(ERROR, TAG, "Error sending response");
473 OICFree(httpRequest.payload);
474 u_arraylist_destroy(httpRequest.headerOptions);
475 return OC_STACK_NO_MEMORY;
478 chpRequest->requestHandle = requestInfo->requestHandle;
479 chpRequest->method = requestInfo->method;
481 result = CHPPostHttpRequest(&httpRequest, CHPHandleHttpResponse,
483 if (OC_STACK_OK != result)
485 OIC_LOG_V(ERROR, TAG, "CHPPostHttpRequest failed[%d]", result);
488 case OC_STACK_INVALID_URI:
489 response.ehResult = OC_EH_BAD_REQ;
492 response.ehResult = OC_EH_INTERNAL_SERVER_ERROR;
495 if (OCDoResponse(&response) != OC_STACK_OK)
497 OIC_LOG(ERROR, TAG, "Error sending response");
500 OICFree(httpRequest.payload);
502 u_arraylist_destroy(httpRequest.headerOptions);
503 return OC_STACK_ERROR;
506 if (!httpRequest.payloadCached)
508 // Free only if parser has not cached it.
509 OICFree(httpRequest.payload);
511 u_arraylist_destroy(httpRequest.headerOptions);
512 OIC_LOG_V(DEBUG, TAG, "%s OUT", __func__);