예제 #1
0
/* ****************************************************************************
*
* restInit - 
*
* FIXME P5: add vector of the accepted content-types, instead of the bool
*           See Issue #256
*/
void restInit
(
  RestService*        _restServiceV,
  IpVersion           _ipVersion,
  const char*         _bindAddress,
  unsigned short      _port,
  bool                _multitenant,
  unsigned int        _connectionMemory,
  unsigned int        _maxConnections,
  unsigned int        _mhdThreadPoolSize,
  const std::string&  _rushHost,
  unsigned short      _rushPort,
  const char*         _allowedOrigin,
  const char*         _httpsKey,
  const char*         _httpsCertificate,
  RestServeFunction   _serveFunction
)
{
  const char* key  = _httpsKey;
  const char* cert = _httpsCertificate;

  port             = _port;
  restServiceV     = _restServiceV;
  ipVersionUsed    = _ipVersion;
  serveFunction    = (_serveFunction != NULL)? _serveFunction : serve;  
  multitenant      = _multitenant;
  connMemory       = _connectionMemory;
  maxConns         = _maxConnections;
  threadPoolSize   = _mhdThreadPoolSize;
  rushHost         = _rushHost;
  rushPort         = _rushPort;

  strncpy(restAllowedOrigin, _allowedOrigin, sizeof(restAllowedOrigin));

  strncpy(bindIp, LOCAL_IP_V4, MAX_LEN_IP - 1);
  strncpy(bindIPv6, LOCAL_IP_V6, MAX_LEN_IP - 1);

  if (isIPv6(std::string(_bindAddress)))
  {
    strncpy(bindIPv6, _bindAddress, MAX_LEN_IP - 1);
  }
  else
  {
    strncpy(bindIp, _bindAddress, MAX_LEN_IP - 1);
  }

  // Starting REST interface
  int r;
  if ((r = restStart(_ipVersion, key, cert)) != 0)
  {
    fprintf(stderr, "restStart: error %d\n", r);
    orionExitFunction(1, "restStart: error");
  }
}
예제 #2
0
/* ****************************************************************************
*
* restInit - 
*
* FIXME P5: add vector of the accepted content-types, instead of the bool
*           argument _acceptTextXml that was added for iotAgent only.
*           See Issue #256
*/
void restInit
(
  RestService*        _restServiceV,
  IpVersion           _ipVersion,
  const char*         _bindAddress,
  unsigned short      _port,
  bool                _multitenant,
  const std::string&  _rushHost,
  unsigned short      _rushPort,
  const char*         _allowedOrigin,
  const char*         _httpsKey,
  const char*         _httpsCertificate,
  RestServeFunction   _serveFunction,
  bool                _acceptTextXml
)
{
  const char* key  = _httpsKey;
  const char* cert = _httpsCertificate;

  port          = _port;
  restServiceV  = _restServiceV;
  ipVersionUsed = _ipVersion;
  serveFunction = (_serveFunction != NULL)? _serveFunction : serve;
  acceptTextXml = _acceptTextXml;
  multitenant   = _multitenant;
  rushHost      = _rushHost;
  rushPort      = _rushPort;

  strncpy(restAllowedOrigin, _allowedOrigin, sizeof(restAllowedOrigin));

  strncpy(bindIp, LOCAL_IP_V4, MAX_LEN_IP - 1);
  strncpy(bindIPv6, LOCAL_IP_V6, MAX_LEN_IP - 1);

  if (isIPv6(std::string(_bindAddress)))
    strncpy(bindIPv6, _bindAddress, MAX_LEN_IP - 1);
  else
    strncpy(bindIp, _bindAddress, MAX_LEN_IP - 1);

  if ((_ipVersion == IPV4) || (_ipVersion == IPDUAL))
     strncpy(bindIp, bindIp, MAX_LEN_IP - 1);

  if ((_ipVersion == IPV6) || (_ipVersion == IPDUAL))
     strncpy(bindIPv6, bindIPv6, MAX_LEN_IP - 1);

  // Starting REST interface
  int r;
  if ((r = restStart(_ipVersion, key, cert)) != 0)
  {
    fprintf(stderr, "restStart: error %d\n", r);
    orionExitFunction(1, "restStart: error");
  }
}
예제 #3
0
/* ****************************************************************************
*
* compoundValueStart - 
*
* This function is called when the first compound node is encountered, so not
* only must the root be created, but also the first node of the compound tree
* must be taken care of. This is done by calling compoundValueMiddle.
*/
void compoundValueStart
(
    ConnectionInfo*     ciP,
    const std::string&  path,
    const std::string&  name,
    const std::string&  value,
    const std::string&  rest,
    orion::ValueType    type,
    bool                fatherIsVector
)
{
  ciP->inCompoundValue   = true;
  ciP->compoundValueP    = new orion::CompoundValueNode(orion::ValueTypeObject);
  ciP->compoundValueRoot = ciP->compoundValueP;

  LM_T(LmtCompoundValueContainer, ("Set current container to '%s' (%s)",
                                   ciP->compoundValueP->path.c_str(),
                                   ciP->compoundValueP->name.c_str()));


  if (fatherIsVector)
  {
    ciP->compoundValueP->valueType = orion::ValueTypeVector;
  }

  //
  // In the parsing routines, in all context attributes that can accept Compound values,
  // a pointer to the one where we are right now is saved in ParseData.
  //
  // If this pointer is not set, it is a fatal error and the broker dies, because of the
  // following LM_X, that does an exit
  // It is better to exit here and clearly see the error, than to continue and get strange
  // outputs that will be difficult to trace back to here.
  //
  if (ciP->parseDataP->lastContextAttribute == NULL)
    orionExitFunction(1, "No pointer to last ContextAttribute");

  ciP->compoundValueVector.push_back(ciP->compoundValueP);
  LM_T(LmtCompoundValueAdd, ("Created new toplevel element"));
  compoundValueMiddle(ciP, rest, name, value, type);
}
예제 #4
0
/* ****************************************************************************
*
* 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;
}
예제 #5
0
/* ****************************************************************************
*
* 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;
}