コード例 #1
0
ファイル: jsonRequest.cpp プロジェクト: jesuspg/fiware-orion
/* ****************************************************************************
*
* jsonTreat - 
*/
std::string jsonTreat(const char* content, ConnectionInfo* ciP, ParseData* parseDataP, RequestType request, std::string payloadWord, JsonRequest** reqPP)
{
  std::string   res   = "OK";
  JsonRequest*  reqP  = jsonRequestGet(request, ciP->method);

  LM_T(LmtParse, ("Treating a JSON request: '%s'", content));

  ciP->parseDataP = parseDataP;

  if (reqP == NULL)
  {
    std::string errorReply = restErrorReplyGet(ciP, ciP->outFormat, "", requestType(request), SccBadRequest,
                                               std::string("Sorry, no request treating object found for RequestType '") + requestType(request) + "'");

    LM_RE(errorReply, ("Sorry, no request treating object found for RequestType %d (%s)", request, requestType(request)));
  }

  if (reqPP != NULL)
    *reqPP = reqP;

  LM_T(LmtParse, ("Treating '%s' request", reqP->keyword.c_str()));

  reqP->init(parseDataP);

  try
  {
    res = jsonParse(ciP, content, reqP->keyword, reqP->parseVector, parseDataP);
    if (ciP->inCompoundValue == true)
      orion::compoundValueEnd(ciP, parseDataP);
    if ((lmTraceIsSet(LmtCompoundValueShow)) && (ciP->compoundValueP != NULL))
      ciP->compoundValueP->shortShow("after parse: ");
  }
  catch (std::exception &e)
  {
    std::string errorReply  = restErrorReplyGet(ciP, ciP->outFormat, "", reqP->keyword, SccBadRequest, std::string("JSON Parse Error: ") + e.what());
    LM_E(("JSON Parse Error: '%s'", e.what()));
    LM_RE(errorReply, (res.c_str()));
  }

  if (res != "OK")
  {
    LM_E(("JSON parse error: %s", res.c_str()));
    ciP->httpStatusCode = SccBadRequest;

    std::string answer = restErrorReplyGet(ciP, ciP->outFormat, "", payloadWord, ciP->httpStatusCode, res);
    return answer; 
  }

  reqP->present(parseDataP);

  LM_T(LmtParseCheck, ("Calling check for JSON parsed tree (%s)", ciP->payloadWord));
  res = reqP->check(parseDataP, ciP);
  reqP->present(parseDataP);

  return res;
}
コード例 #2
0
ファイル: rest.cpp プロジェクト: LeonanCarvalho/fiware-orion
/* ****************************************************************************
*
* contentTypeCheck -
*
* NOTE
*   Any failure about Content-Type is an error in the HTTP layer (not exclusively NGSI)
*   so we don't want to use the default 200
*
* NOTE
*   In version 1 of the protocol, we admit ONLY application/json
*   In version 2 of the protocol, we admit ONLY application/json and text/plain
*/
static int contentTypeCheck(ConnectionInfo* ciP)
{
  //
  // Five cases:
  //   1. If there is no payload, the Content-Type is not interesting
  //   2. Payload present but no Content-Type 
  //   3. Content-Type present but not supported
  //   4. API version 2 and not 'application/json' || text/plain
  //


  // Case 1
  if (ciP->httpHeaders.contentLength == 0)
  {
    return 0;
  }


  // Case 2
  if (ciP->httpHeaders.contentType == "")
  {
    std::string details = "Content-Type header not used, default application/octet-stream is not supported";
    ciP->httpStatusCode = SccUnsupportedMediaType;
    ciP->answer = restErrorReplyGet(ciP, "", "OrionError", SccUnsupportedMediaType, details);
    ciP->httpStatusCode = SccUnsupportedMediaType;

    return 1;
  }

  // Case 3
  if ((ciP->apiVersion == "v1") && (ciP->httpHeaders.contentType != "application/json"))
  {
    std::string details = std::string("not supported content type: ") + ciP->httpHeaders.contentType;
    ciP->httpStatusCode = SccUnsupportedMediaType;
    ciP->answer = restErrorReplyGet(ciP, "", "OrionError", SccUnsupportedMediaType, details);
    ciP->httpStatusCode = SccUnsupportedMediaType;
    return 1;
  }


  // Case 4
  if ((ciP->apiVersion == "v2") && (ciP->httpHeaders.contentType != "application/json") && (ciP->httpHeaders.contentType != "text/plain"))
  {
    std::string details = std::string("not supported content type: ") + ciP->httpHeaders.contentType;
    ciP->httpStatusCode = SccUnsupportedMediaType;
    ciP->answer = restErrorReplyGet(ciP, "", "OrionError", SccUnsupportedMediaType, details);
    ciP->httpStatusCode = SccUnsupportedMediaType;
    return 1;
  }

  return 0;
}
コード例 #3
0
/* ****************************************************************************
*
* putAvailabilitySubscriptionConvOp - 
*/
std::string putAvailabilitySubscriptionConvOp
(
  ConnectionInfo*            ciP,
  int                        components,
  std::vector<std::string>&  compV,
  ParseData*                 parseDataP
)
{
  std::string                                    subscriptionId  = (compV[0] == "v1")? compV[3] : compV[2];
  UpdateContextAvailabilitySubscriptionRequest*  ucasP           = &parseDataP->ucas.res;

  if (subscriptionId != ucasP->subscriptionId.get())
  {
    std::string out;

    out = restErrorReplyGet(ciP,
                            ciP->outFormat,
                            "",
                            "updateContextAvailabilitySubscription",
                            SccBadRequest,
                            std::string("unmatching subscriptionId URI/payload: /") +
                            subscriptionId + "/ vs /" + ucasP->subscriptionId.get() + "/");
    return out;
  }

  return postUpdateContextAvailabilitySubscription(ciP, components, compV, parseDataP);
}
コード例 #4
0
/* ****************************************************************************
*
* putSubscriptionConvOp - 
*/
std::string putSubscriptionConvOp
(
  ConnectionInfo*            ciP,
  int                        components,
  std::vector<std::string>&  compV,
  ParseData*                 parseDataP
)
{
  std::string                        subscriptionId = compV[2];
  UpdateContextSubscriptionRequest*  ucsrP          = &parseDataP->ucsr.res;

  if (subscriptionId != ucsrP->subscriptionId.get())
  {
    std::string out;

    out = restErrorReplyGet(ciP,
                            ciP->outFormat,
                            "",
                            "updateContextSubscription",
                            SccBadRequest,
                            std::string("unmatching subscriptionId URI/payload: '") +
                            subscriptionId + "' vs '" + ucsrP->subscriptionId.get() + "'");

    return out;
  }

  return postUpdateContextSubscription(ciP, components, compV, parseDataP);
}
コード例 #5
0
/* ****************************************************************************
*
* badNgsi10Request - 
*/
std::string badNgsi10Request(ConnectionInfo* ciP, int components, std::vector<std::string>& compV, ParseData* parseDataP)
{
  std::string answer;

  answer = restErrorReplyGet(ciP, ciP->outFormat, "", ciP->payloadWord, SccBadRequest, std::string("ngsi10 service '") + ciP->url +"' not found");

  return answer;
}
コード例 #6
0
ファイル: rest.cpp プロジェクト: agallegoc/fiware-orion
/* ****************************************************************************
*
* contentTypeCheck -
*
* NOTE
*   Any failure about Content-Type is an error in the HTTP layer (not exclusively NGSI)
*   so we don't want to use the default 200
*/
static int contentTypeCheck(ConnectionInfo* ciP)
{
  std::string details = "";

  //
  // Four cases:
  //   1. If there is no payload, the Content-Type is not interesting
  //   2. Payload present but no Content-Type 
  //   3. text/xml used and acceptTextXml is setto true (iotAgent only)
  //   4. Content-Type present but not supported

  // Case 1
  if (ciP->httpHeaders.contentLength == 0)
    return 0;

  // Case 2
  if (ciP->httpHeaders.contentType == "")
  {
    std::string details = "Content-Type header not used, default application/octet-stream is not supported";
    ciP->httpStatusCode = SccUnsupportedMediaType;
    ciP->answer = restErrorReplyGet(ciP, ciP->outFormat, "", "OrionError", SccUnsupportedMediaType, details);
    ciP->httpStatusCode = SccUnsupportedMediaType;
    return 1;
  }

  // Case 3
  if ((acceptTextXml == true) && (ciP->httpHeaders.contentType == "text/xml"))
    return 0;

  // Case 4
  if ((ciP->httpHeaders.contentType != "application/xml") && (ciP->httpHeaders.contentType != "application/json"))
  {
    std::string details = std::string("not supported content type: ") + ciP->httpHeaders.contentType;
    ciP->httpStatusCode = SccUnsupportedMediaType;
    ciP->answer = restErrorReplyGet(ciP, ciP->outFormat, "", "OrionError", SccUnsupportedMediaType, details);
    ciP->httpStatusCode = SccUnsupportedMediaType;
    return 1;
  }

  return 0;
}
コード例 #7
0
/* ****************************************************************************
*
* badNgsi10Request - 
*/
std::string badNgsi10Request
(
  ConnectionInfo*            ciP,
  int                        components,
  std::vector<std::string>&  compV,
  ParseData*                 parseDataP
)
{
  std::string answer;
  std::string details = std::string("service '") + ciP->url + "' not found";

  alarmMgr.badInput(clientIp, details);
  restErrorReplyGet(ciP, SccBadRequest, "service not found", &answer);

  return answer;
}
コード例 #8
0
ファイル: rest.cpp プロジェクト: LeonanCarvalho/fiware-orion
/* ****************************************************************************
*
* outMimeTypeCheck - 
*/
static int outMimeTypeCheck(ConnectionInfo* ciP)
{
  ciP->outMimeType  = wantedOutputSupported(ciP->apiVersion, ciP->httpHeaders.accept, &ciP->charset);
  if (ciP->outMimeType == NOMIMETYPE)
  {
    /* This is actually an error in the HTTP layer (not exclusively NGSI) so we don't want to use the default 200 */
    ciP->httpStatusCode = SccNotAcceptable;
    ciP->answer = restErrorReplyGet(ciP,
                                    "",
                                    "OrionError",
                                    SccNotAcceptable,
                                    std::string("acceptable MIME types: application/json. Accept header in request: ") + ciP->httpHeaders.accept);

    ciP->outMimeType    = JSON; // We use JSON as default mimeType
    ciP->httpStatusCode = SccNotAcceptable;

    return 1;
  }

  return 0;
}
コード例 #9
0
ファイル: rest.cpp プロジェクト: AlvaroVega/fiware-orion
/* ****************************************************************************
*
* outFormatCheck - 
*/
static int outFormatCheck(ConnectionInfo* ciP)
{
  ciP->outFormat  = wantedOutputSupported(ciP->httpHeaders.accept, &ciP->charset);
  if (ciP->outFormat == NOFORMAT)
  {
    /* This is actually an error in the HTTP layer (not exclusively NGSI) so we don't want to use the default 200 */
    ciP->httpStatusCode = SccNotAcceptable;
    ciP->answer = restErrorReplyGet(ciP,
                                    XML,
                                    "",
                                    "OrionError",
                                    SccNotAcceptable,
                                    std::string("acceptable MIME types: application/xml, application/json. Accept header in request: ") + ciP->httpHeaders.accept);

    ciP->outFormat      = XML; // We use XML as default format
    ciP->httpStatusCode = SccNotAcceptable;

    return 1;
  }

  return 0;
}
コード例 #10
0
ファイル: rest.cpp プロジェクト: AlvaroVega/fiware-orion
/* ****************************************************************************
*
* connectionTreat - 
*
* This is the MHD_AccessHandlerCallback function for MHD_start_daemon
* This function returns:
* o MHD_YES  if the connection was handled successfully
* o MHD_NO   if the socket must be closed due to a serious error
*
* - This function is called once when the headers are read and the ciP is created.
* - Then it is called for data payload and once all the payload an acknowledgement
*   must be done, setting *upload_data_size to ZERO.
* - The last call is made with *upload_data_size == 0 and now is when the connection
*   is open to send responses.
*
* Call 1: *con_cls == NULL
* Call 2: *con_cls != NULL  AND  *upload_data_size != 0
* Call 3: *con_cls != NULL  AND  *upload_data_size == 0
*/
static int connectionTreat
(
   void*            cls,
   MHD_Connection*  connection,
   const char*      url,
   const char*      method,
   const char*      version,
   const char*      upload_data,
   size_t*          upload_data_size,
   void**           con_cls
)
{
  ConnectionInfo*        ciP         = (ConnectionInfo*) *con_cls;
  size_t                 dataLen     = *upload_data_size;

  // 1. First call - setup ConnectionInfo and get/check HTTP headers
  if (ciP == NULL)
  {
    //
    // IP Address and port of caller
    //
    char            ip[32];
    unsigned short  port = 0;

    const union MHD_ConnectionInfo* mciP = MHD_get_connection_info(connection, MHD_CONNECTION_INFO_CLIENT_ADDRESS);
    if (mciP != NULL)
    {
      port = (mciP->client_addr->sa_data[0] << 8) + mciP->client_addr->sa_data[1];
      snprintf(ip, sizeof(ip), "%d.%d.%d.%d", mciP->client_addr->sa_data[2]  & 0xFF, mciP->client_addr->sa_data[3]  & 0xFF, mciP->client_addr->sa_data[4] & 0xFF, mciP->client_addr->sa_data[5] & 0xFF);
    }
    else
    {
      port = 0;
      snprintf(ip, sizeof(ip), "IP unknown");
    }



    //
    // ConnectionInfo
    //
    if ((ciP = new ConnectionInfo(url, method, version, connection)) == NULL)
    {
      LM_E(("Runtime Error (error allocating ConnectionInfo)"));
      return MHD_NO;
    }

    *con_cls = (void*) ciP; // Pointer to ConnectionInfo for subsequent calls
    ciP->port = port;
    ciP->ip   = ip;
    
    //
    // Transaction starts here
    //
    LM_TRANSACTION_START("from", ip, port, url);  // Incoming REST request starts



    //
    // URI parameters
    // 
    ciP->uriParam[URI_PARAM_NOTIFY_FORMAT]      = DEFAULT_PARAM_NOTIFY_FORMAT;
    ciP->uriParam[URI_PARAM_PAGINATION_OFFSET]  = DEFAULT_PAGINATION_OFFSET;
    ciP->uriParam[URI_PARAM_PAGINATION_LIMIT]   = DEFAULT_PAGINATION_LIMIT;
    ciP->uriParam[URI_PARAM_PAGINATION_DETAILS] = DEFAULT_PAGINATION_DETAILS;
    
    MHD_get_connection_values(connection, MHD_GET_ARGUMENT_KIND, uriArgumentGet, ciP);
    if (ciP->httpStatusCode != SccOk)
    {
      LM_W(("Bad Input (error in URI parameters)"));
      restReply(ciP, ciP->answer);
      return MHD_YES;
    }
    LM_T(LmtUriParams, ("notifyFormat: '%s'", ciP->uriParam[URI_PARAM_NOTIFY_FORMAT].c_str()));

    MHD_get_connection_values(connection, MHD_HEADER_KIND, httpHeaderGet, &ciP->httpHeaders);
    
    char tenant[128];
    ciP->tenantFromHttpHeader = strToLower(tenant, ciP->httpHeaders.tenant.c_str(), sizeof(tenant));
    LM_T(LmtTenant, ("HTTP tenant: '%s'", ciP->httpHeaders.tenant.c_str()));
    ciP->outFormat            = wantedOutputSupported(ciP->httpHeaders.accept, &ciP->charset);
    if (ciP->outFormat == NOFORMAT)
      ciP->outFormat = XML; // XML is default output format

    ciP->servicePath = ciP->httpHeaders.servicePath;
    if (servicePathSplit(ciP) != 0)
    {
      LM_W(("Bad Input (error in ServicePath http-header)"));
      restReply(ciP, ciP->answer);
    }

    if (contentTypeCheck(ciP) != 0)
    {
      LM_W(("Bad Input (invalid mime-type in Content-Type http-header)"));
      restReply(ciP, ciP->answer);
    }
    else if (outFormatCheck(ciP) != 0)
    {
      LM_W(("Bad Input (invalid mime-type in Accept http-header)"));
      restReply(ciP, ciP->answer);
    }
    else
      ciP->inFormat = formatParse(ciP->httpHeaders.contentType, NULL);

    // Set default mime-type for notifications
    if (ciP->uriParam[URI_PARAM_NOTIFY_FORMAT] == "")
    {
      if (ciP->outFormat == XML)
        ciP->uriParam[URI_PARAM_NOTIFY_FORMAT] = "XML";
      else if (ciP->outFormat == JSON)
        ciP->uriParam[URI_PARAM_NOTIFY_FORMAT] = "JSON";
      else
        ciP->uriParam[URI_PARAM_NOTIFY_FORMAT] = "XML";

      LM_T(LmtUriParams, ("'default' value for notifyFormat (ciP->outFormat == %d)): '%s'", ciP->outFormat, ciP->uriParam[URI_PARAM_NOTIFY_FORMAT].c_str()));
    }

    return MHD_YES;
  }


  //
  // 2. Data gathering calls
  //
  // 2-1. Data gathering calls, just wait
  // 2-2. Last data gathering call, acknowledge the receipt of data
  //
  if (dataLen != 0)
  {
    if (dataLen == ciP->httpHeaders.contentLength)
    {
      if (ciP->httpHeaders.contentLength <= PAYLOAD_MAX_SIZE)
      {
        if (ciP->httpHeaders.contentLength > STATIC_BUFFER_SIZE)
          ciP->payload = (char*) malloc(ciP->httpHeaders.contentLength + 1);
        else
          ciP->payload = static_buffer;

        ciP->payloadSize = dataLen;
        memcpy(ciP->payload, upload_data, dataLen);
        ciP->payload[dataLen] = 0;
      }
      else
      {
        char details[256];
        snprintf(details, sizeof(details), "payload size: %d, max size supported: %d", ciP->httpHeaders.contentLength, PAYLOAD_MAX_SIZE);

        ciP->answer         = restErrorReplyGet(ciP, ciP->outFormat, "", ciP->url, SccRequestEntityTooLarge, details);
        ciP->httpStatusCode = SccRequestEntityTooLarge;
      }

      // All payload received, acknowledge!
      *upload_data_size = 0;
    }
    else
      LM_T(LmtPartialPayload, ("Got %d of payload of %d bytes", dataLen, ciP->httpHeaders.contentLength));

    return MHD_YES;
  }


  // 3. Finally, serve the request (unless an error has occurred)
  if (((ciP->verb == POST) || (ciP->verb == PUT)) && (ciP->httpHeaders.contentLength == 0) && (strncasecmp(ciP->url.c_str(), "/log/", 5) != 0))
  {
    std::string errorMsg = restErrorReplyGet(ciP, ciP->outFormat, "", url, SccLengthRequired, "Zero/No Content-Length in PUT/POST request");
    ciP->httpStatusCode = SccLengthRequired;
    restReply(ciP, errorMsg);
  }
  else if (ciP->answer != "")
    restReply(ciP, ciP->answer);
  else
    serveFunction(ciP);

  return MHD_YES;
}
コード例 #11
0
ファイル: xmlRequest.cpp プロジェクト: dmartr/fiware-orion
/* ****************************************************************************
*
* xmlTreat -
*/
std::string xmlTreat
(
  const char*      content,
  ConnectionInfo*  ciP,
  ParseData*       parseDataP,
  RequestType      request,
  std::string      payloadWord,
  XmlRequest**     reqPP,
  std::string*     errorMsgP
)
{
  xml_document<>  doc;
  char*           xmlPayload = (char*) content;

  //
  // If the payload is empty, the XML parsing library does an assert
  // and the broker dies.
  // Therefore, this check here is important, to avoid death.
  // 
  // 'OK' is returned as there is no error to send a request without payload.
  //
  if ((content == NULL) || (*content == 0))
  {
    return "OK";
  }

  try
  {
    doc.parse<0>(xmlPayload);
  }
  catch (parse_error& e)
  {
    std::string errorReply = restErrorReplyGet(ciP, ciP->outFormat, "", "unknown", SccBadRequest, "XML Parse Error");
    LM_W(("Bad Input ('%s', '%s')", content, e.what()));

    if (errorMsgP)
    {
      *errorMsgP = std::string("XML parse error exception: ") + e.what();
    }

    return errorReply;
  }
  catch (...)
  {
    std::string errorReply = restErrorReplyGet(ciP, ciP->outFormat, "", "unknown", SccBadRequest, "XML Parse Error");
    LM_W(("Bad Input (%s)", content));

    if (errorMsgP)
    {
      *errorMsgP = std::string("XML parse generic exception");
    }

    return errorReply;
  }

  xml_node<>*   father = doc.first_node();
  XmlRequest*   reqP   = xmlRequestGet(request, ciP->method);

  ciP->parseDataP = parseDataP;

  if (father == NULL)
  {
    std::string errorReply = restErrorReplyGet(ciP, ciP->outFormat, "", "unknown", SccBadRequest, "XML Parse Error");
    LM_W(("Bad Input (XML parse error)"));
    if (errorMsgP)
    {
      *errorMsgP = std::string("XML parse error: invalid XML input");
    }

    return errorReply;
  }

  if (reqP == NULL)
  {
    std::string errorReply =
      restErrorReplyGet(
        ciP,
        ciP->outFormat,
        "",
        requestType(request),
        SccBadRequest,
        std::string("Sorry, no request treating object found for RequestType /") +
        requestType(request) + "/, method /" + ciP->method + "/");

    LM_W(("Bad Input (no request treating object found for RequestType %d (%s), method %s)",
          request,
          requestType(request),
          ciP->method.c_str()));

    LM_W(("Bad Input (no request treating object found for RequestType %d (%s), method %s)",
          request, requestType(request), ciP->method.c_str()));

    if (errorMsgP)
    {
      *errorMsgP = std::string("Unable to treat ") + requestType(request) + " requests";
    }

    return errorReply;
  }


  if (reqPP != NULL)
  {
    *reqPP = reqP;
  }

  //
  // Checking that the payload matches the URL
  //
  if (((ciP->verb == POST) || (ciP->verb == PUT)) && (payloadWord.length() != 0))
  {
    std::string  errorReply;
    char*        payloadStart = (char*) content;

    // Skip '<?xml version="1.0" encoding="UTF-8"?> ' ?
    if (strncmp(payloadStart, "<?xml", 5) == 0)
    {
      ++payloadStart;
      payloadStart = strstr(payloadStart, "<");
    }

    // Skip '<'
    if (*payloadStart == '<')
    {
       ++payloadStart;
    }

    if (strncasecmp(payloadWord.c_str(), payloadStart, payloadWord.length()) != 0)
    {
      errorReply  = restErrorReplyGet(ciP,
                                      ciP->outFormat,
                                      "",
                                      reqP->keyword,
                                      SccBadRequest,
                                      std::string("Expected /") + payloadWord +
                                        "/ payload, got /" + payloadStart + "/");

      LM_W(("Bad Input (invalid  payload: wanted: '%s', got '%s')", payloadWord.c_str(), payloadStart));

      if (errorMsgP)
      {
        *errorMsgP = std::string("Bad Input (invalid payload, expecting '") +
          payloadWord + "', got '" + payloadStart + "')";
      }

      return errorReply;
    }
  }

  if (reqP->init == NULL)  // No payload treating function
  {
    return "OK";
  }

  reqP->init(parseDataP);
  ciP->httpStatusCode = SccOk;
  xmlParse(ciP, NULL, father, "", "", reqP->parseVector, parseDataP, errorMsgP);
  if (ciP->httpStatusCode != SccOk)
  {
    LM_W(("Bad Input (XML parse error)"));

    return restErrorReplyGet(ciP, ciP->outFormat, "", payloadWord, ciP->httpStatusCode, ciP->answer);
  }

  LM_T(LmtParseCheck, ("Calling check for XML parsed tree (%s)", ciP->payloadWord));
  std::string check = reqP->check(parseDataP, ciP);
  if (check != "OK")
  {
    LM_W(("Bad Input (%s: %s)", reqP->keyword.c_str(), check.c_str()));

    if (errorMsgP)
    {
      *errorMsgP = std::string("Bad Input: ") + check;
    }
  }

  reqP->present(parseDataP);

  if (check != "OK")
  {
    if (errorMsgP)
    {
      *errorMsgP = std::string("Bad Input: ") + check;
    }
  }

  return check;
}
コード例 #12
0
ファイル: RestService.cpp プロジェクト: Findeton/fiware-orion
/* ****************************************************************************
*
* restService - 
*/
std::string restService(ConnectionInfo* ciP, RestService* serviceV)
{
  std::vector<std::string>  compV;
  int                       components;
  JsonRequest*              jsonReqP   = NULL;
  ParseData                 parseData;
  JsonDelayedRelease        jsonRelease;

  if ((ciP->url.length() == 0) || ((ciP->url.length() == 1) && (ciP->url.c_str()[0] == '/')))
  {
    OrionError  error(SccBadRequest, "The Orion Context Broker is a REST service, not a 'web page'");
    std::string response = error.render(ciP, "");

    alarmMgr.badInput(clientIp, "The Orion Context Broker is a REST service, not a 'web page'");
    restReply(ciP, response);

    return std::string("Empty URL");
  }

  ciP->httpStatusCode = SccOk;

  components = stringSplit(ciP->url, '/', compV);

  for (unsigned int ix = 0; serviceV[ix].treat != NULL; ++ix)
  {
    if ((serviceV[ix].components != 0) && (serviceV[ix].components != components))
    {
      continue;
    }

    if ((ciP->method != serviceV[ix].verb) && (serviceV[ix].verb != "*"))
    {
      continue;
    }

    strncpy(ciP->payloadWord, serviceV[ix].payloadWord.c_str(), sizeof(ciP->payloadWord));
    bool match = true;
    for (int compNo = 0; compNo < components; ++compNo)
    {
      if (serviceV[ix].compV[compNo] == "*")
      {
        continue;
      }

      if (strcasecmp(serviceV[ix].compV[compNo].c_str(), compV[compNo].c_str()) != 0)
      {
        match = false;
        break;
      }
    }

    if (match == false)
    {
      continue;
    }

    if ((ciP->payload != NULL) && (ciP->payloadSize != 0) && (ciP->payload[0] != 0) && (serviceV[ix].verb != "*"))
    {
      std::string response;

      LM_T(LmtParsedPayload, ("Parsing payload for URL '%s', method '%s', service vector index: %d", ciP->url.c_str(), ciP->method.c_str(), ix));
      ciP->parseDataP = &parseData;
      LM_T(LmtPayload, ("Parsing payload '%s'", ciP->payload));
      response = payloadParse(ciP, &parseData, &serviceV[ix], &jsonReqP, &jsonRelease, compV);
      LM_T(LmtParsedPayload, ("payloadParse returns '%s'", response.c_str()));

      if (response != "OK")
      {
        alarmMgr.badInput(clientIp, response);
        restReply(ciP, response);

        if (jsonReqP != NULL)
        {
          jsonReqP->release(&parseData);
        }

        if (ciP->apiVersion == "v2")
        {
          delayedRelease(&jsonRelease);
        }

        compV.clear();
        return response;
      }
    }

    LM_T(LmtService, ("Treating service %s %s", serviceV[ix].verb.c_str(), ciP->url.c_str())); // Sacred - used in 'heavyTest'
    if (ciP->payloadSize == 0)
    {
      ciP->inFormat = NOFORMAT;
    }
    statisticsUpdate(serviceV[ix].request, ciP->inFormat);

    // Tenant to connectionInfo
    ciP->tenant = ciP->tenantFromHttpHeader;
    lmTransactionSetService(ciP->tenant.c_str());

    //
    // A tenant string must not be longer than 50 characters and may only contain
    // underscores and alphanumeric characters.
    //
    std::string result;
    if ((ciP->tenant != "") && ((result = tenantCheck(ciP->tenant)) != "OK"))
    {
      OrionError  error(SccBadRequest, result);

      std::string  response = error.render(ciP, "");

      alarmMgr.badInput(clientIp, result);

      if (ciP->apiVersion != "v1")
      {
        ciP->httpStatusCode = SccBadRequest;  // FIXME P9:  OK for all versions?
      }

      restReply(ciP, response);

      if (jsonReqP != NULL)
      {
        jsonReqP->release(&parseData);
      }

      if (ciP->apiVersion == "v2")
      {
        delayedRelease(&jsonRelease);
      }

      compV.clear();
        
      return response;
    }

    LM_T(LmtTenant, ("tenant: '%s'", ciP->tenant.c_str()));
    commonFilters(ciP, &parseData, &serviceV[ix]);
    scopeFilter(ciP, &parseData, &serviceV[ix]);


    //
    // If we have gotten this far the Input is OK.
    // Except for all the badVerb/badRequest, etc.
    // A common factor for all these 'services' is that the verb is '*'
    //
    // So, the 'Bad Input' alarm is cleared for this client.
    //
    if (serviceV[ix].verb != "*")
    {
      alarmMgr.badInputReset(clientIp);
    }

    std::string response = serviceV[ix].treat(ciP, components, compV, &parseData);

    filterRelease(&parseData, serviceV[ix].request);   

    if (jsonReqP != NULL)
    {
      jsonReqP->release(&parseData);
    }

    if (ciP->apiVersion == "v2")
    {
      delayedRelease(&jsonRelease);
    }

    compV.clear();

    if (response == "DIE")
    {
      orionExitFunction(0, "Received a 'DIE' request on REST interface");
    }

    restReply(ciP, response);
    return response;
  }

  std::string details = std::string("service '") + ciP->url + "' not recognized";
  alarmMgr.badInput(clientIp, details);

  ciP->httpStatusCode = SccBadRequest;
  std::string answer = restErrorReplyGet(ciP, "", ciP->payloadWord, SccBadRequest, std::string("unrecognized request"));
  restReply(ciP, answer);

  compV.clear();
  return answer;
}
コード例 #13
0
ファイル: RestService.cpp プロジェクト: d0ugal/fiware-orion
/* ****************************************************************************
*
* restService -
*/
std::string restService(ConnectionInfo* ciP, RestService* serviceV)
{
    std::vector<std::string>  compV;
    int                       components;
    XmlRequest*               reqP       = NULL;
    JsonRequest*              jsonReqP   = NULL;
    ParseData                 parseData;

    if ((ciP->url.length() == 0) || ((ciP->url.length() == 1) && (ciP->url.c_str()[0] == '/')))
    {
        OrionError  error(SccBadRequest, "The Orion Context Broker is a REST service, not a 'web page'");
        std::string response = error.render(ciP->outFormat, "");

        LM_W(("Bad Input (The Orion Context Broker is a REST service, not a 'web page')"));
        restReply(ciP, response);

        return std::string("Empty URL");
    }

    ciP->httpStatusCode = SccOk;

    components = stringSplit(ciP->url, '/', compV);

    for (unsigned int ix = 0; serviceV[ix].treat != NULL; ++ix)
    {
        if ((serviceV[ix].components != 0) && (serviceV[ix].components != components))
        {
            continue;
        }

        if ((ciP->method != serviceV[ix].verb) && (serviceV[ix].verb != "*"))
        {
            continue;
        }

        strncpy(ciP->payloadWord, serviceV[ix].payloadWord.c_str(), sizeof(ciP->payloadWord));
        bool match = true;
        for (int compNo = 0; compNo < components; ++compNo)
        {
            if (serviceV[ix].compV[compNo] == "*")
            {
                continue;
            }

            if (strcasecmp(serviceV[ix].compV[compNo].c_str(), compV[compNo].c_str()) != 0)
            {
                match = false;
                break;
            }
        }

        if (match == false)
        {
            continue;
        }

        if ((ciP->payload != NULL) && (ciP->payloadSize != 0) && (ciP->payload[0] != 0) && (serviceV[ix].verb != "*"))
        {
            std::string response;

            LM_T(LmtParsedPayload, ("Parsing payload for URL '%s', method '%s', service vector index: %d", ciP->url.c_str(), ciP->method.c_str(), ix));
            ciP->parseDataP = &parseData;
            response = payloadParse(ciP, &parseData, &serviceV[ix], &reqP, &jsonReqP);
            LM_T(LmtParsedPayload, ("payloadParse returns '%s'", response.c_str()));

            if (response != "OK")
            {
                restReply(ciP, response);

                if (reqP != NULL)
                {
                    reqP->release(&parseData);
                }
                if (jsonReqP != NULL)
                {
                    jsonReqP->release(&parseData);
                }

                compV.clear();
                return response;
            }
        }

        LM_T(LmtService, ("Treating service %s %s", serviceV[ix].verb.c_str(), ciP->url.c_str())); // Sacred - used in 'heavyTest'
        statisticsUpdate(serviceV[ix].request, ciP->inFormat);

        // Tenant to connectionInfo
        ciP->tenant = ciP->tenantFromHttpHeader;

        //
        // A tenant string must not be longer than 50 characters and may only contain
        // underscores and alphanumeric characters.
        //
        std::string result;
        if ((ciP->tenant != "") && ((result = tenantCheck(ciP->tenant)) != "OK"))
        {
            OrionError  error(SccBadRequest,
                              "tenant name not accepted - a tenant string must not be longer than " MAX_TENANT_NAME_LEN_STRING " characters"
                              " and may only contain underscores and alphanumeric characters");

            std::string  response = error.render(ciP->outFormat, "");

            LM_W(("Bad Input (%s)", error.details.c_str()));
            restReply(ciP, response);

            if (reqP != NULL)
            {
                reqP->release(&parseData);
            }

            if (jsonReqP != NULL)
            {
                jsonReqP->release(&parseData);
            }

            compV.clear();

            return response;
        }

        LM_T(LmtTenant, ("tenant: '%s'", ciP->tenant.c_str()));
        commonFilters(ciP, &parseData, &serviceV[ix]);
        scopeFilter(ciP, &parseData, &serviceV[ix]);
        std::string response = serviceV[ix].treat(ciP, components, compV, &parseData);
        filterRelease(&parseData, serviceV[ix].request);

        if (reqP != NULL)
        {
            reqP->release(&parseData);
        }

        if (jsonReqP != NULL)
        {
            jsonReqP->release(&parseData);
        }

        compV.clear();

        if (response == "DIE")
        {
            orionExitFunction(0, "Received a 'DIE' request on REST interface");
        }

        restReply(ciP, response);
        return response;
    }

    LM_W(("Bad Input (service '%s' not recognized)", ciP->url.c_str()));
    ciP->httpStatusCode = SccBadRequest;
    std::string answer = restErrorReplyGet(ciP, ciP->outFormat, "", ciP->payloadWord, SccBadRequest, std::string("unrecognized request"));
    restReply(ciP, answer);

    compV.clear();
    return answer;
}
/* ****************************************************************************
*
* postAttributeValueInstanceWithTypeAndId - 
*
* POST /ngsi10/contextEntities/type/{type}/id/{id}/attributes/{attributeName}/{valueID}
*
* Payload: UpdateContextAttributeRequest
*/
std::string postAttributeValueInstanceWithTypeAndId
(
  ConnectionInfo*            ciP,
  int                        components,
  std::vector<std::string>&  compV,
  ParseData*                 parseDataP
)
{
  UpdateContextRequest            request;
  UpdateContextResponse           response;
  std::string                     entityType    = compV[3];
  std::string                     entityId      = compV[5];
  std::string                     attributeName = compV[7];
  std::string                     valueId       = compV[8];
  UpdateContextAttributeRequest*  upcarP        = &parseDataP->upcar.res;
  bool                            idFound       = false;

  //
  // Any metadata ID in the payload?
  //
  // If so, the value must be equal to the {valueID} of the URL
  //
  for (unsigned int ix = 0; ix < upcarP->metadataVector.size(); ++ix)
  {
    Metadata* mP = upcarP->metadataVector.get(ix);

    if (mP->name == "ID")
    {
      if (mP->value != valueId)
      {
        std::string out;

        out = restErrorReplyGet(ciP,
                                ciP->outFormat,
                                "", "StatusCode",
                                SccBadRequest,
                                std::string("unmatching metadata ID value URI/payload: '") +
                                  valueId + "' vs '" + mP->value + "'");
        return out;
      }
      else
      {
        idFound = true;
      }
    }
  }


  ContextAttribute*               attributeP    = new ContextAttribute(attributeName, "", upcarP->contextValue);
  ContextElement*                 ceP           = new ContextElement();

  // Copy the metadata vector of the input payload
  attributeP->metadataVector.fill((MetadataVector*) &upcarP->metadataVector);

  // If no "ID" metadata was in the payload, add it
  if (idFound == false)
  {
    Metadata* mP = new Metadata("ID", "", valueId);
    attributeP->metadataVector.push_back(mP);
  }

  // Filling the rest of the structure for mongoUpdateContext
  ceP->entityId.fill(entityId, entityType, "false");
  ceP->attributeDomainName.set("");
  ceP->contextAttributeVector.push_back(attributeP);
  request.contextElementVector.push_back(ceP);
  request.updateActionType.set("APPEND");

  response.errorCode.code = SccNone;
  ciP->httpStatusCode = mongoUpdateContext(&request, &response, ciP->tenant, ciP->servicePathV, ciP->uriParam);

  StatusCode statusCode;
  if (response.contextElementResponseVector.size() == 0)
  {
    statusCode.fill(SccContextElementNotFound,
                    std::string("Entity-Attribute pair: '") + entityId + "-" + attributeName + "'");
  }
  else if (response.contextElementResponseVector.size() == 1)
  {
    ContextElementResponse* cerP = response.contextElementResponseVector.get(0);

    if (response.errorCode.code != SccNone)
    {
      statusCode.fill(&response.errorCode);
    }
    else if (cerP->statusCode.code != SccNone)
    {
      statusCode.fill(&cerP->statusCode);
    }
    else
    {
      statusCode.fill(SccOk);
    }
  }
  else
  {
    statusCode.fill(SccReceiverInternalError,
                    "More than one response from postAttributeValueInstanceWithTypeAndId::mongoUpdateContext");
  }

  request.release();
  return statusCode.render(ciP->outFormat, "", false, false);
}
コード例 #15
0
ファイル: rest.cpp プロジェクト: agallegoc/fiware-orion
/* ****************************************************************************
*
* connectionTreat - 
*
* This is the MHD_AccessHandlerCallback function for MHD_start_daemon
* This function returns:
* o MHD_YES  if the connection was handled successfully
* o MHD_NO   if the socket must be closed due to a serious error
*
* - This function is called once when the headers are read and the ciP is created.
* - Then it is called for data payload and once all the payload an acknowledgement
*   must be done, setting *upload_data_size to ZERO.
* - The last call is made with *upload_data_size == 0 and now is when the connection
*   is open to send responses.
*
* Call 1: *con_cls == NULL
* Call 2: *con_cls != NULL  AND  *upload_data_size != 0
* Call 3: *con_cls != NULL  AND  *upload_data_size == 0
*/
static int connectionTreat
(
   void*            cls,
   MHD_Connection*  connection,
   const char*      url,
   const char*      method,
   const char*      version,
   const char*      upload_data,
   size_t*          upload_data_size,
   void**           con_cls
)
{
  ConnectionInfo* ciP      = (ConnectionInfo*) *con_cls;
  size_t          dataLen  = *upload_data_size;

  // 1. First call - setup ConnectionInfo and get/check HTTP headers
  if (ciP == NULL)
  {
    if ((ciP = new ConnectionInfo(url, method, version, connection)) == NULL)
      LM_RE(MHD_NO, ("Error allocating ConnectionInfo"));
        
    *con_cls = (void*) ciP; // Pointer to ConnectionInfo for subsequent calls

    MHD_get_connection_values(connection, MHD_HEADER_KIND, httpHeaderGet, &ciP->httpHeaders);

    ciP->outFormat  = wantedOutputSupported(ciP->httpHeaders.accept, &ciP->charset);
    if (ciP->outFormat == NOFORMAT)
      ciP->outFormat = XML; // XML is default output format

    if (contentTypeCheck(ciP) != 0)
    {
      LM_W(("Error in Content-Type"));
      restReply(ciP, ciP->answer);
    }
    else if (outFormatCheck(ciP) != 0)
    {
      LM_W(("Bad Accepted Out-Format (in Accept header)"));
      restReply(ciP, ciP->answer);
    }
    else
      ciP->inFormat = formatParse(ciP->httpHeaders.contentType, NULL);

    return MHD_YES;
  }


  //
  // 2. Data gathering calls
  //
  // 2-1. Data gathering calls, just wait
  // 2-2. Last data gathering call, acknowledge the receipt of data
  //
  if (dataLen != 0)
  {
    if (dataLen == ciP->httpHeaders.contentLength)
    {
      if (ciP->httpHeaders.contentLength <= PAYLOAD_MAX_SIZE)
      {
        if (ciP->httpHeaders.contentLength > STATIC_BUFFER_SIZE)
          ciP->payload = (char*) malloc(ciP->httpHeaders.contentLength);
        else
          ciP->payload = static_buffer;

        ciP->payloadSize = dataLen;
        memcpy(ciP->payload, upload_data, dataLen);
        ciP->payload[dataLen] = 0;
      }
      else
      {
        char details[256];
        snprintf(details, sizeof(details), "payload size: %d, max size supported: %d", ciP->httpHeaders.contentLength, PAYLOAD_MAX_SIZE);

        ciP->answer         = restErrorReplyGet(ciP, ciP->outFormat, "", ciP->url, SccRequestEntityTooLarge, details);
        ciP->httpStatusCode = SccRequestEntityTooLarge;
      }

      // All payload received, acknowledge!
      *upload_data_size = 0;
    }
    else
      LM_T(LmtPartialPayload, ("Got %d of payload of %d bytes", dataLen, ciP->httpHeaders.contentLength));

    return MHD_YES;
  }


  // 3. Finally, serve the request (unless an error has occurred)
  if (((ciP->verb == POST) || (ciP->verb == PUT)) && (ciP->httpHeaders.contentLength == 0))
  {
    std::string errorMsg = restErrorReplyGet(ciP, ciP->outFormat, "", url, SccLengthRequired, "Zero/No Content-Length in PUT/POST request");
    ciP->httpStatusCode = SccLengthRequired;
    restReply(ciP, errorMsg);
  }
  else if (ciP->answer != "")
    restReply(ciP, ciP->answer);
  else
    serveFunction(ciP);

  return MHD_YES;
}
コード例 #16
0
/* ****************************************************************************
*
* restErrorReplyGet -
*/
TEST(restReply, restErrorReplyGet)
{
    const char* rcrOutfile01   = "ngsi9.restReply.registerContext01.ok.valid.xml";
    const char* rcrOutfile02   = "ngsi9.restReply.registerContext02.ok.valid.xml";
    const char* dcarOutfile01  = "ngsi9.restReply.discovery01.ok.valid.xml";
    const char* dcarOutfile02  = "ngsi9.restReply.discovery02.ok.valid.xml";
    const char* scarOutfile01  = "ngsi9.restReply.subscribeContextAvailability01.ok.valid.xml";
    const char* scarOutfile02  = "ngsi9.restReply.subscribeContextAvailability02.ok.valid.xml";
    const char* ucasOutfile01  = "ngsi9.restReply.updateContextAvailabilitySubscription01.ok.valid.xml";
    const char* ucasOutfile02  = "ngsi9.restReply.updateContextAvailabilitySubscription02.ok.valid.xml";
    const char* ucarOutfile01  = "ngsi9.restReply.unsubscribeContextAvailability01.ok.valid.xml";
    const char* ucarOutfile02  = "ngsi9.restReply.unsubscribeContextAvailability02.ok.valid.xml";
    const char* ncarOutfile01  = "ngsi9.restReply.notifyContextAvailabilityRequest01.ok.valid.xml";
    const char* ncarOutfile02  = "ngsi9.restReply.notifyContextAvailabilityRequest02.ok.valid.xml";
    const char* qcrOutfile01   = "ngsi10.restReply.queryContextResponse01.ok.valid.xml";
    const char* qcrOutfile02   = "ngsi10.restReply.queryContextResponse02.ok.valid.xml";
    const char* scrOutfile01   = "ngsi10.restReply.subscribeContextResponse01.ok.valid.xml";
    const char* scrOutfile02   = "ngsi10.restReply.subscribeContextResponse02.ok.valid.xml";
    const char* ucsOutfile01   = "ngsi10.restReply.updateContextSubscriptionResponse01.ok.valid.xml";
    const char* ucsOutfile02   = "ngsi10.restReply.updateContextSubscriptionResponse02.ok.valid.xml";
    const char* uscrOutfile01  = "ngsi10.restReply.unsubscribeContextResponse01.ok.valid.xml";
    const char* uscrOutfile02  = "ngsi10.restReply.unsubscribeContextResponse02.ok.valid.xml";
    const char* ucrOutfile01   = "ngsi10.restReply.updateContextResponse01.ok.valid.xml";
    const char* ucrOutfile02   = "ngsi10.restReply.updateContextResponse02.ok.valid.xml";
    const char* ncrOutfile01   = "ngsi10.restReply.notifyContextResponse01.ok.valid.xml";
    const char* ncrOutfile02   = "ngsi10.restReply.notifyContextResponse02.ok.valid.xml";

    std::string rcr1 = "registerContext";
    std::string rcr2 = "/ngsi9/registerContext";
    std::string rcr3 = "/NGSI9/registerContext";
    std::string rcr4 = "registerContextRequest";

    std::string dcar1 = "discoverContextAvailability";
    std::string dcar2 = "/ngsi9/discoverContextAvailability";
    std::string dcar3 = "/NGSI9/discoverContextAvailability";
    std::string dcar4 = "discoverContextAvailabilityRequest";

    std::string scar1 = "subscribeContextAvailability";
    std::string scar2 = "/ngsi9/subscribeContextAvailability";
    std::string scar3 = "/NGSI9/subscribeContextAvailability";
    std::string scar4 = "subscribeContextAvailabilityRequest";

    std::string ucas1 = "updateContextAvailabilitySubscription";
    std::string ucas2 = "/ngsi9/updateContextAvailabilitySubscription";
    std::string ucas3 = "/NGSI9/updateContextAvailabilitySubscription";
    std::string ucas4 = "updateContextAvailabilitySubscriptionRequest";

    std::string ucar1 = "unsubscribeContextAvailability";
    std::string ucar2 = "/ngsi9/unsubscribeContextAvailability";
    std::string ucar3 = "/NGSI9/unsubscribeContextAvailability";
    std::string ucar4 = "unsubscribeContextAvailabilityRequest";

    std::string ncar1 = "notifyContextAvailability";
    std::string ncar2 = "/ngsi9/notifyContextAvailability";
    std::string ncar3 = "/NGSI9/notifyContextAvailability";
    std::string ncar4 = "notifyContextAvailabilityRequest";

    std::string qcr1 = "queryContext";
    std::string qcr2 = "/ngsi10/queryContext";
    std::string qcr3 = "/NGSI10/queryContext";
    std::string qcr4 = "queryContextRequest";

    std::string scr1 = "subscribeContext";
    std::string scr2 = "/ngsi10/subscribeContext";
    std::string scr3 = "/NGSI10/subscribeContext";
    std::string scr4 = "subscribeContextRequest";

    std::string ucs1 = "updateContextSubscription";
    std::string ucs2 = "/ngsi10/updateContextSubscription";
    std::string ucs3 = "/NGSI10/updateContextSubscription";
    std::string ucs4 = "updateContextSubscriptionRequest";

    std::string uscr1 = "unsubscribeContext";
    std::string uscr2 = "/ngsi10/unsubscribeContext";
    std::string uscr3 = "/NGSI10/unsubscribeContext";
    std::string uscr4 = "unsubscribeContextRequest";

    std::string ucr1 = "updateContext";
    std::string ucr2 = "/ngsi10/updateContext";
    std::string ucr3 = "/NGSI10/updateContext";
    std::string ucr4 = "updateContextRequest";

    std::string ncr1 = "notifyContext";
    std::string ncr2 = "/ngsi10/notifyContext";
    std::string ncr3 = "/NGSI10/notifyContext";
    std::string ncr4 = "notifyContextRequest";

    std::string     out;
    ConnectionInfo  ci("/ngsi/test", "POST", "1.1");

    utInit();

    EXPECT_EQ("OK", testDataFromFile(expectedBuf, sizeof(expectedBuf), rcrOutfile01)) << "Error getting test data from '" << rcrOutfile01 << "'";
    out = restErrorReplyGet(&ci, XML, "", rcr1, SccOk, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());
    out = restErrorReplyGet(&ci, XML, "", rcr2, SccOk, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());
    out = restErrorReplyGet(&ci, XML, "", rcr3, SccOk, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());
    out = restErrorReplyGet(&ci, XML, "", rcr4, SccOk, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());

    EXPECT_EQ("OK", testDataFromFile(expectedBuf, sizeof(expectedBuf), rcrOutfile02)) << "Error getting test data from '" << rcrOutfile02 << "'";
    out = restErrorReplyGet(&ci, XML, "", rcr1, SccBadRequest, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());
    out = restErrorReplyGet(&ci, XML, "", rcr2, SccBadRequest, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());
    out = restErrorReplyGet(&ci, XML, "", rcr3, SccBadRequest, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());
    out = restErrorReplyGet(&ci, XML, "", rcr4, SccBadRequest, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());


    EXPECT_EQ("OK", testDataFromFile(expectedBuf, sizeof(expectedBuf), dcarOutfile01)) << "Error getting test data from '" << dcarOutfile01 << "'";
    out = restErrorReplyGet(&ci, XML, "", dcar1, SccOk, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());
    out = restErrorReplyGet(&ci, XML, "", dcar2, SccOk, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());
    out = restErrorReplyGet(&ci, XML, "", dcar3, SccOk, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());
    out = restErrorReplyGet(&ci, XML, "", dcar4, SccOk, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());

    EXPECT_EQ("OK", testDataFromFile(expectedBuf, sizeof(expectedBuf), dcarOutfile02)) << "Error getting test data from '" << dcarOutfile02 << "'";
    out = restErrorReplyGet(&ci, XML, "", dcar1, SccBadRequest, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());
    out = restErrorReplyGet(&ci, XML, "", dcar2, SccBadRequest, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());
    out = restErrorReplyGet(&ci, XML, "", dcar3, SccBadRequest, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());
    out = restErrorReplyGet(&ci, XML, "", dcar4, SccBadRequest, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());


    EXPECT_EQ("OK", testDataFromFile(expectedBuf, sizeof(expectedBuf), scarOutfile01)) << "Error getting test data from '" << scarOutfile01 << "'";
    out = restErrorReplyGet(&ci, XML, "", scar1, SccOk, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());
    out = restErrorReplyGet(&ci, XML, "", scar2, SccOk, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());
    out = restErrorReplyGet(&ci, XML, "", scar3, SccOk, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());
    out = restErrorReplyGet(&ci, XML, "", scar4, SccOk, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());

    EXPECT_EQ("OK", testDataFromFile(expectedBuf, sizeof(expectedBuf), scarOutfile02)) << "Error getting test data from '" << scarOutfile02 << "'";
    out = restErrorReplyGet(&ci, XML, "", scar1, SccBadRequest, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());
    out = restErrorReplyGet(&ci, XML, "", scar2, SccBadRequest, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());
    out = restErrorReplyGet(&ci, XML, "", scar3, SccBadRequest, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());
    out = restErrorReplyGet(&ci, XML, "", scar4, SccBadRequest, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());


    EXPECT_EQ("OK", testDataFromFile(expectedBuf, sizeof(expectedBuf), ucasOutfile01)) << "Error getting test data from '" << ucasOutfile01 << "'";
    out = restErrorReplyGet(&ci, XML, "", ucas1, SccOk, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());
    out = restErrorReplyGet(&ci, XML, "", ucas2, SccOk, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());
    out = restErrorReplyGet(&ci, XML, "", ucas3, SccOk, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());
    out = restErrorReplyGet(&ci, XML, "", ucas4, SccOk, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());

    EXPECT_EQ("OK", testDataFromFile(expectedBuf, sizeof(expectedBuf), ucasOutfile02)) << "Error getting test data from '" << ucasOutfile02 << "'";
    out = restErrorReplyGet(&ci, XML, "", ucas1, SccBadRequest, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());
    out = restErrorReplyGet(&ci, XML, "", ucas2, SccBadRequest, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());
    out = restErrorReplyGet(&ci, XML, "", ucas3, SccBadRequest, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());
    out = restErrorReplyGet(&ci, XML, "", ucas4, SccBadRequest, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());


    EXPECT_EQ("OK", testDataFromFile(expectedBuf, sizeof(expectedBuf), ucarOutfile01)) << "Error getting test data from '" << ucarOutfile01 << "'";
    out = restErrorReplyGet(&ci, XML, "", ucar1, SccOk, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());
    out = restErrorReplyGet(&ci, XML, "", ucar2, SccOk, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());
    out = restErrorReplyGet(&ci, XML, "", ucar3, SccOk, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());
    out = restErrorReplyGet(&ci, XML, "", ucar4, SccOk, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());

    EXPECT_EQ("OK", testDataFromFile(expectedBuf, sizeof(expectedBuf), ucarOutfile02)) << "Error getting test data from '" << ucarOutfile02 << "'";
    out = restErrorReplyGet(&ci, XML, "", ucar1, SccBadRequest, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());
    out = restErrorReplyGet(&ci, XML, "", ucar2, SccBadRequest, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());
    out = restErrorReplyGet(&ci, XML, "", ucar3, SccBadRequest, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());
    out = restErrorReplyGet(&ci, XML, "", ucar4, SccBadRequest, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());


    EXPECT_EQ("OK", testDataFromFile(expectedBuf, sizeof(expectedBuf), ncarOutfile01)) << "Error getting test data from '" << ncarOutfile01 << "'";
    out = restErrorReplyGet(&ci, XML, "", ncar1, SccOk, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());
    out = restErrorReplyGet(&ci, XML, "", ncar2, SccOk, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());
    out = restErrorReplyGet(&ci, XML, "", ncar3, SccOk, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());
    out = restErrorReplyGet(&ci, XML, "", ncar4, SccOk, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());

    EXPECT_EQ("OK", testDataFromFile(expectedBuf, sizeof(expectedBuf), ncarOutfile02)) << "Error getting test data from '" << ncarOutfile02 << "'";
    out = restErrorReplyGet(&ci, XML, "", ncar1, SccBadRequest, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());
    out = restErrorReplyGet(&ci, XML, "", ncar2, SccBadRequest, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());
    out = restErrorReplyGet(&ci, XML, "", ncar3, SccBadRequest, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());
    out = restErrorReplyGet(&ci, XML, "", ncar4, SccBadRequest, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());


    EXPECT_EQ("OK", testDataFromFile(expectedBuf, sizeof(expectedBuf), qcrOutfile01)) << "Error getting test data from '" << qcrOutfile01 << "'";
    out = restErrorReplyGet(&ci, XML, "", qcr1, SccOk, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());
    out = restErrorReplyGet(&ci, XML, "", qcr2, SccOk, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());
    out = restErrorReplyGet(&ci, XML, "", qcr3, SccOk, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());
    out = restErrorReplyGet(&ci, XML, "", qcr4, SccOk, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());

    EXPECT_EQ("OK", testDataFromFile(expectedBuf, sizeof(expectedBuf), qcrOutfile02)) << "Error getting test data from '" << qcrOutfile02 << "'";
    out = restErrorReplyGet(&ci, XML, "", qcr1, SccBadRequest, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());
    out = restErrorReplyGet(&ci, XML, "", qcr2, SccBadRequest, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());
    out = restErrorReplyGet(&ci, XML, "", qcr3, SccBadRequest, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());
    out = restErrorReplyGet(&ci, XML, "", qcr4, SccBadRequest, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());


    EXPECT_EQ("OK", testDataFromFile(expectedBuf, sizeof(expectedBuf), scrOutfile01)) << "Error getting test data from '" << scrOutfile01 << "'";
    out = restErrorReplyGet(&ci, XML, "", scr1, SccOk, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());
    out = restErrorReplyGet(&ci, XML, "", scr2, SccOk, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());
    out = restErrorReplyGet(&ci, XML, "", scr3, SccOk, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());
    out = restErrorReplyGet(&ci, XML, "", scr4, SccOk, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());

    EXPECT_EQ("OK", testDataFromFile(expectedBuf, sizeof(expectedBuf), scrOutfile02)) << "Error getting test data from '" << scrOutfile02 << "'";
    out = restErrorReplyGet(&ci, XML, "", scr1, SccBadRequest, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());
    out = restErrorReplyGet(&ci, XML, "", scr2, SccBadRequest, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());
    out = restErrorReplyGet(&ci, XML, "", scr3, SccBadRequest, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());
    out = restErrorReplyGet(&ci, XML, "", scr4, SccBadRequest, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());


    EXPECT_EQ("OK", testDataFromFile(expectedBuf, sizeof(expectedBuf), ucsOutfile01)) << "Error getting test data from '" << ucsOutfile01 << "'";
    out = restErrorReplyGet(&ci, XML, "", ucs1, SccOk, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());
    out = restErrorReplyGet(&ci, XML, "", ucs2, SccOk, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());
    out = restErrorReplyGet(&ci, XML, "", ucs3, SccOk, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());
    out = restErrorReplyGet(&ci, XML, "", ucs4, SccOk, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());

    EXPECT_EQ("OK", testDataFromFile(expectedBuf, sizeof(expectedBuf), ucsOutfile02)) << "Error getting test data from '" << ucsOutfile02 << "'";
    out = restErrorReplyGet(&ci, XML, "", ucs1, SccBadRequest, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());
    out = restErrorReplyGet(&ci, XML, "", ucs2, SccBadRequest, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());
    out = restErrorReplyGet(&ci, XML, "", ucs3, SccBadRequest, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());
    out = restErrorReplyGet(&ci, XML, "", ucs4, SccBadRequest, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());


    EXPECT_EQ("OK", testDataFromFile(expectedBuf, sizeof(expectedBuf), uscrOutfile01)) << "Error getting test data from '" << uscrOutfile01 << "'";
    out = restErrorReplyGet(&ci, XML, "", uscr1, SccOk, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());
    out = restErrorReplyGet(&ci, XML, "", uscr2, SccOk, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());
    out = restErrorReplyGet(&ci, XML, "", uscr3, SccOk, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());
    out = restErrorReplyGet(&ci, XML, "", uscr4, SccOk, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());

    EXPECT_EQ("OK", testDataFromFile(expectedBuf, sizeof(expectedBuf), uscrOutfile02)) << "Error getting test data from '" << uscrOutfile02 << "'";
    out = restErrorReplyGet(&ci, XML, "", uscr1, SccBadRequest, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());
    out = restErrorReplyGet(&ci, XML, "", uscr2, SccBadRequest, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());
    out = restErrorReplyGet(&ci, XML, "", uscr3, SccBadRequest, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());
    out = restErrorReplyGet(&ci, XML, "", uscr4, SccBadRequest, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());


    EXPECT_EQ("OK", testDataFromFile(expectedBuf, sizeof(expectedBuf), ucrOutfile01)) << "Error getting test data from '" << ucrOutfile01 << "'";
    out = restErrorReplyGet(&ci, XML, "", ucr1, SccOk, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());
    out = restErrorReplyGet(&ci, XML, "", ucr2, SccOk, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());
    out = restErrorReplyGet(&ci, XML, "", ucr3, SccOk, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());
    out = restErrorReplyGet(&ci, XML, "", ucr4, SccOk, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());

    EXPECT_EQ("OK", testDataFromFile(expectedBuf, sizeof(expectedBuf), ucrOutfile02)) << "Error getting test data from '" << ucrOutfile02 << "'";
    out = restErrorReplyGet(&ci, XML, "", ucr1, SccBadRequest, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());
    out = restErrorReplyGet(&ci, XML, "", ucr2, SccBadRequest, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());
    out = restErrorReplyGet(&ci, XML, "", ucr3, SccBadRequest, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());
    out = restErrorReplyGet(&ci, XML, "", ucr4, SccBadRequest, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());


    EXPECT_EQ("OK", testDataFromFile(expectedBuf, sizeof(expectedBuf), ncrOutfile01)) << "Error getting test data from '" << ncrOutfile01 << "'";
    out = restErrorReplyGet(&ci, XML, "", ncr1, SccOk, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());
    out = restErrorReplyGet(&ci, XML, "", ncr2, SccOk, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());
    out = restErrorReplyGet(&ci, XML, "", ncr3, SccOk, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());
    out = restErrorReplyGet(&ci, XML, "", ncr4, SccOk, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());

    EXPECT_EQ("OK", testDataFromFile(expectedBuf, sizeof(expectedBuf), ncrOutfile02)) << "Error getting test data from '" << ncrOutfile02 << "'";
    out = restErrorReplyGet(&ci, XML, "", ncr1, SccBadRequest, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());
    out = restErrorReplyGet(&ci, XML, "", ncr2, SccBadRequest, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());
    out = restErrorReplyGet(&ci, XML, "", ncr3, SccBadRequest, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());
    out = restErrorReplyGet(&ci, XML, "", ncr4, SccBadRequest, "detail");
    EXPECT_STREQ(expectedBuf, out.c_str());

    utExit();
}
コード例 #17
0
ファイル: rest.cpp プロジェクト: LeonanCarvalho/fiware-orion
static int connectionTreat
(
   void*            cls,
   MHD_Connection*  connection,
   const char*      url,
   const char*      method,
   const char*      version,
   const char*      upload_data,
   size_t*          upload_data_size,
   void**           con_cls
)
{
  ConnectionInfo*        ciP         = (ConnectionInfo*) *con_cls;
  size_t                 dataLen     = *upload_data_size;

  // 1. First call - setup ConnectionInfo and get/check HTTP headers
  if (ciP == NULL)
  {
    //
    // First thing to do on a new connection, set correlator to N/A.
    // After reading HTTP headers, the correlator id either changes due to encountering a 
    // Fiware-Correlator HTTP Header, or, if no HTTP header with Fiware-Correlator is found,
    // a new correlator is generated.
    //
    correlatorIdSet("N/A");

    //
    // IP Address and port of caller
    //
    char            ip[32];
    unsigned short  port = 0;

    const union MHD_ConnectionInfo* mciP = MHD_get_connection_info(connection, MHD_CONNECTION_INFO_CLIENT_ADDRESS);

    if (mciP != NULL)
    {
      struct sockaddr* addr = (struct sockaddr*) mciP->client_addr;

      port = (addr->sa_data[0] << 8) + addr->sa_data[1];
      snprintf(ip, sizeof(ip), "%d.%d.%d.%d",
               addr->sa_data[2] & 0xFF,
               addr->sa_data[3] & 0xFF,
               addr->sa_data[4] & 0xFF,
               addr->sa_data[5] & 0xFF);
      snprintf(clientIp, sizeof(clientIp), "%s", ip);
    }
    else
    {
      port = 0;
      snprintf(ip, sizeof(ip), "IP unknown");
    }


    //
    // Reset time measuring?
    //
    if (timingStatistics)
    {
      memset(&threadLastTimeStat, 0, sizeof(threadLastTimeStat));
    }


    //
    // ConnectionInfo
    //
    // FIXME P1: ConnectionInfo could be a thread variable (like the static_buffer),
    // as long as it is properly cleaned up between calls.
    // We would save the call to new/free for each and every request.
    // Once we *really* look to scratch some efficiency, this change should be made.
    //
    // Also, is ciP->ip really used?
    //
    if ((ciP = new ConnectionInfo(url, method, version, connection)) == NULL)
    {
      LM_E(("Runtime Error (error allocating ConnectionInfo)"));
      return MHD_NO;
    }

    if (timingStatistics)
    {
      clock_gettime(CLOCK_REALTIME, &ciP->reqStartTime);
    }

    LM_T(LmtRequest, (""));
    // WARNING: This log message below is crucial for the correct function of the Behave tests - CANNOT BE REMOVED
    LM_T(LmtRequest, ("--------------------- Serving request %s %s -----------------", method, url));
    *con_cls     = (void*) ciP; // Pointer to ConnectionInfo for subsequent calls
    ciP->port    = port;
    ciP->ip      = ip;
    ciP->callNo  = reqNo;

    ++reqNo;


    //
    // URI parameters
    //
    // FIXME P1: We might not want to do all these assignments, they are not used in all requests ...
    //           Once we *really* look to scratch some efficiency, this change should be made.
    //     
    ciP->uriParam[URI_PARAM_PAGINATION_OFFSET]  = DEFAULT_PAGINATION_OFFSET;
    ciP->uriParam[URI_PARAM_PAGINATION_LIMIT]   = DEFAULT_PAGINATION_LIMIT;
    ciP->uriParam[URI_PARAM_PAGINATION_DETAILS] = DEFAULT_PAGINATION_DETAILS;
    
    MHD_get_connection_values(connection, MHD_HEADER_KIND, httpHeaderGet, &ciP->httpHeaders);

    char correlator[CORRELATOR_ID_SIZE + 1];
    if (ciP->httpHeaders.correlator == "")
    {
      correlatorGenerate(correlator);
      ciP->httpHeaders.correlator = correlator;
    }

    correlatorIdSet(ciP->httpHeaders.correlator.c_str());

    ciP->httpHeader.push_back("Fiware-Correlator");
    ciP->httpHeaderValue.push_back(ciP->httpHeaders.correlator);

    //
    // Transaction starts here
    //
    lmTransactionStart("from", ip, port, url);  // Incoming REST request starts


    /* X-Forwared-For (used by a potential proxy on top of Orion) overrides ip */
    if (ciP->httpHeaders.xforwardedFor == "")
    {
      lmTransactionSetFrom(ip);
    }
    else
    {
      lmTransactionSetFrom(ciP->httpHeaders.xforwardedFor.c_str());
    }

    ciP->apiVersion = apiVersionGet(ciP->url.c_str());

    char tenant[SERVICE_NAME_MAX_LEN + 1];
    ciP->tenantFromHttpHeader = strToLower(tenant, ciP->httpHeaders.tenant.c_str(), sizeof(tenant));
    ciP->outMimeType          = wantedOutputSupported(ciP->apiVersion, ciP->httpHeaders.accept, &ciP->charset);
    if (ciP->outMimeType == NOMIMETYPE)
    {
      ciP->outMimeType = JSON; // JSON is default output mimeType
    }

    MHD_get_connection_values(connection, MHD_GET_ARGUMENT_KIND, uriArgumentGet, ciP);

    return MHD_YES;
  }


  //
  // 2. Data gathering calls
  //
  // 2-1. Data gathering calls, just wait
  // 2-2. Last data gathering call, acknowledge the receipt of data
  //
  if (dataLen != 0)
  {
    //
    // If the HTTP header says the request is bigger than our PAYLOAD_MAX_SIZE,
    // just silently "eat" the entire message
    //
    if (ciP->httpHeaders.contentLength > PAYLOAD_MAX_SIZE)
    {
      *upload_data_size = 0;
      return MHD_YES;
    }

    //
    // First call with payload - use the thread variable "static_buffer" if possible,
    // otherwise allocate a bigger buffer
    //
    // FIXME P1: This could be done in "Part I" instead, saving an "if" for each "Part II" call
    //           Once we *really* look to scratch some efficiency, this change should be made.
    //
    if (ciP->payloadSize == 0)  // First call with payload
    {
      if (ciP->httpHeaders.contentLength > STATIC_BUFFER_SIZE)
      {
        ciP->payload = (char*) malloc(ciP->httpHeaders.contentLength + 1);
      }
      else
      {
        ciP->payload = static_buffer;
      }
    }

    // Copy the chunk
    LM_T(LmtPartialPayload, ("Got %d of payload of %d bytes", dataLen, ciP->httpHeaders.contentLength));
    memcpy(&ciP->payload[ciP->payloadSize], upload_data, dataLen);
    
    // Add to the size of the accumulated read buffer
    ciP->payloadSize += *upload_data_size;

    // Zero-terminate the payload
    ciP->payload[ciP->payloadSize] = 0;

    // Acknowledge the data and return
    *upload_data_size = 0;
    return MHD_YES;
  }


  //
  // 3. Finally, serve the request (unless an error has occurred)
  // 
  // URL and headers checks are delayed to the "third" MHD call, as no 
  // errors can be sent before all the request has been read
  //
  if (urlCheck(ciP, ciP->url) == false)
  {
    alarmMgr.badInput(clientIp, "error in URI path");
    restReply(ciP, ciP->answer);
  }

  ciP->servicePath = ciP->httpHeaders.servicePath;
  lmTransactionSetSubservice(ciP->servicePath.c_str());

  if (servicePathSplit(ciP) != 0)
  {
    alarmMgr.badInput(clientIp, "error in ServicePath http-header");
    restReply(ciP, ciP->answer);
  }

  if (contentTypeCheck(ciP) != 0)
  {
    alarmMgr.badInput(clientIp, "invalid mime-type in Content-Type http-header");
    restReply(ciP, ciP->answer);
  }
  else if (outMimeTypeCheck(ciP) != 0)
  {
    alarmMgr.badInput(clientIp, "invalid mime-type in Accept http-header");
    restReply(ciP, ciP->answer);
  }
  else
  {
    ciP->inMimeType = mimeTypeParse(ciP->httpHeaders.contentType, NULL);
  }

  if (ciP->httpStatusCode != SccOk)
  {
    alarmMgr.badInput(clientIp, "error in URI parameters");
    restReply(ciP, ciP->answer);
    return MHD_YES;
  }  

  //
  // Here, if the incoming request was too big, return error about it
  //
  if (ciP->httpHeaders.contentLength > PAYLOAD_MAX_SIZE)
  {
    char details[256];
    snprintf(details, sizeof(details), "payload size: %d, max size supported: %d", ciP->httpHeaders.contentLength, PAYLOAD_MAX_SIZE);

    alarmMgr.badInput(clientIp, details);

    ciP->answer         = restErrorReplyGet(ciP, "", ciP->url, SccRequestEntityTooLarge, details);
    ciP->httpStatusCode = SccRequestEntityTooLarge;
  }

  //
  // Requests of verb POST, PUT or PATCH are considered erroneous if no payload is present - with two exceptions.
  //
  // - Old log requests  (URL contains '/log/')
  // - New log requests  (URL is exactly '/admin/log')
  //
  if (((ciP->verb == POST) || (ciP->verb == PUT) || (ciP->verb == PATCH )) && 
      (ciP->httpHeaders.contentLength == 0) && 
      ((strncasecmp(ciP->url.c_str(), "/log/", 5) != 0) && (strncasecmp(ciP->url.c_str(), "/admin/log", 10) != 0)))
  {
    std::string errorMsg = restErrorReplyGet(ciP, "", url, SccContentLengthRequired, "Zero/No Content-Length in PUT/POST/PATCH request");

    ciP->httpStatusCode  = SccContentLengthRequired;
    restReply(ciP, errorMsg);
    alarmMgr.badInput(clientIp, errorMsg);
  }
  else if (ciP->answer != "")
  {
    alarmMgr.badInput(clientIp, ciP->answer);
    restReply(ciP, ciP->answer);
  }
  else
  {
    serveFunction(ciP);
  }

  return MHD_YES;
}