Back to index

nordugrid-arc-nox  1.1.0~rc6
Public Member Functions | Protected Member Functions | Protected Attributes | Static Protected Attributes
Arc::MCC_HTTP_Service Class Reference

This class implements MCC to processes HTTP request. More...

#include <MCCHTTP.h>

Inheritance diagram for Arc::MCC_HTTP_Service:
Inheritance graph
[legend]
Collaboration diagram for Arc::MCC_HTTP_Service:
Collaboration graph
[legend]

List of all members.

Public Member Functions

 MCC_HTTP_Service (Config *cfg)
virtual ~MCC_HTTP_Service (void)
virtual MCC_Status process (Message &, Message &)
 Dummy Message processing method.
virtual void Next (MCCInterface *next, const std::string &label="")
 Add reference to next MCC in chain.
virtual void AddSecHandler (Config *cfg, ArcSec::SecHandler *sechandler, const std::string &label="")
 Add security components/handlers to this MCC.
virtual void Unlink ()
 Removing all links.

Protected Member Functions

MCCInterfaceNext (const std::string &label="")
bool ProcessSecHandlers (Message &message, const std::string &label="") const
 Executes security handlers of specified queue.

Protected Attributes

std::map< std::string,
MCCInterface * > 
next_
 Set of labeled "next" components.
std::map< std::string,
std::list< ArcSec::SecHandler * > > 
sechandlers_
 Set of labeled authentication and authorization handlers.

Static Protected Attributes

static Logger logger
 A logger for MCCs.

Detailed Description

This class implements MCC to processes HTTP request.

On input payload with PayloadStreamInterface is expected. HTTP message is read from stream ans it's body is converted into PayloadRaw and passed to next MCC. Returned payload of PayloadRawInterface type is treated as body part of returning PayloadHTTP. Generated HTTP response is sent though stream passed in input payload. During processing of request/input message following attributes are generated: HTTP:METHOD - HTTP method e.g. GET, PUT, POST, etc. HTTP:ENDPOINT - URL taken from HTTP request ENDPOINT - global attribute equal to HTTP:ENDPOINT HTTP:RANGESTART - start of requested byte range HTTP:RANGEEND - end of requested byte range (inclusive) HTTP:name - all 'name' attributes of HTTP header. Attributes of response message of HTTP:name type are translated into HTTP header with corresponding 'name's.

Definition at line 38 of file MCCHTTP.h.


Constructor & Destructor Documentation

Definition at line 131 of file MCCHTTP.cpp.

                                             :MCC_HTTP(cfg) {
}

Definition at line 134 of file MCCHTTP.cpp.

                                        {
}

Member Function Documentation

void Arc::MCC::AddSecHandler ( Config cfg,
ArcSec::SecHandler sechandler,
const std::string &  label = "" 
) [virtual, inherited]

Add security components/handlers to this MCC.

Security handlers are stacked into a few queues with each queue identified by its label. The queue labelled 'incoming' is executed for every 'request' message after the message is processed by the MCC on the service side and before processing on the client side. The queue labelled 'outgoing' is run for response message before it is processed by MCC algorithms on the service side and after processing on the client side. Those labels are just a matter of agreement and some MCCs may implement different queues executed at various message processing steps.

Definition at line 35 of file MCC.cpp.

                                {
    if (sechandler) {
      sechandlers_[label].push_back(sechandler);
      // need polishing to put the SecHandlerFactory->getinstance here
      XMLNode cn = (*cfg)["SecHandler"];
      Config cfg_(cn);
    }
  }

Here is the caller graph for this function:

MCCInterface * Arc::MCC::Next ( const std::string &  label = "") [protected, inherited]

Definition at line 22 of file MCC.cpp.

                                                {
    std::map<std::string, MCCInterface *>::iterator n = next_.find(label);
    if (n == next_.end())
      return NULL;
    return n->second;
  }

Here is the caller graph for this function:

void Arc::MCC::Next ( MCCInterface next,
const std::string &  label = "" 
) [virtual, inherited]

Add reference to next MCC in chain.

This method is called by Loader for every potentially labeled link to next component which implements MCCInterface. If next is NULL corresponding link is removed.

Reimplemented in Arc::MCC_TLS_Client, Arc::Plexer, and Arc::MCC_GSI_Client.

Definition at line 15 of file MCC.cpp.

                                                           {
    if (next == NULL)
      next_.erase(label);
    else
      next_[label] = next;
  }

Dummy Message processing method.

Just a placeholder.

Reimplemented from Arc::MCC.

Definition at line 182 of file MCCHTTP.cpp.

                                                                   {
  // Extracting payload
  if(!inmsg.Payload()) return MCC_Status();
  PayloadStreamInterface* inpayload = NULL;
  try {
    inpayload = dynamic_cast<PayloadStreamInterface*>(inmsg.Payload());
  } catch(std::exception& e) { };
  if(!inpayload) return MCC_Status();
  // Converting stream payload to HTTP which also implements raw interface
  PayloadHTTP nextpayload(*inpayload);
  if(!nextpayload) {
    logger.msg(WARNING, "Cannot create http payload");
    return make_http_fault(logger,*inpayload,outmsg,HTTP_BAD_REQUEST);
  };
  if(nextpayload.Method() == "END") {
    return MCC_Status(SESSION_CLOSE);
  };
  bool keep_alive = nextpayload.KeepAlive();
  // Creating message to pass to next MCC and setting new payload.
  Message nextinmsg = inmsg;
  nextinmsg.Payload(&nextpayload);
  // Creating attributes
  // Endpoints must be URL-like so make sure HTTP path is
  // converted to HTTP URL
  std::string endpoint = nextpayload.Endpoint();
  {
    std::string::size_type p = endpoint.find("://");
    if(p == std::string::npos) {
      // TODO: Use Host attribute of HTTP
      std::string oendpoint = nextinmsg.Attributes()->get("ENDPOINT");
      p=oendpoint.find("://");
      if(p != std::string::npos) {
        oendpoint.erase(0,p+3);
      };
      // Assuming we have host:port here
      if(oendpoint.empty() ||
         (oendpoint[oendpoint.length()-1] != '/')) {
        if(endpoint[0] != '/') oendpoint+="/";
      };
      // TODO: HTTPS detection
      endpoint="http://"+oendpoint+endpoint;
    };
  };
  nextinmsg.Attributes()->set("ENDPOINT",endpoint);
  nextinmsg.Attributes()->set("HTTP:ENDPOINT",nextpayload.Endpoint());
  nextinmsg.Attributes()->set("HTTP:METHOD",nextpayload.Method());
  // Filling security attributes
  HTTPSecAttr* sattr = new HTTPSecAttr(nextpayload);
  nextinmsg.Auth()->set("HTTP",sattr);
  parse_http_range(nextpayload,nextinmsg);
  // Reason ?
  for(std::multimap<std::string,std::string>::const_iterator i =
      nextpayload.Attributes().begin();i!=nextpayload.Attributes().end();++i) {
    nextinmsg.Attributes()->add("HTTP:"+i->first,i->second);
  };
  if(!ProcessSecHandlers(nextinmsg,"incoming")) {
    return make_http_fault(logger,*inpayload,outmsg,HTTP_BAD_REQUEST); // Maybe not 400 ?
  };
  // Call next MCC
  MCCInterface* next = Next(nextpayload.Method());
  if(!next) {
    logger.msg(WARNING, "No next element in the chain");
    return make_http_fault(logger,*inpayload,outmsg,HTTP_NOT_FOUND);
  }
  Message nextoutmsg = outmsg; nextoutmsg.Payload(NULL);
  MCC_Status ret = next->process(nextinmsg,nextoutmsg);
  // Do checks and extract raw response
  if(!ret) {
    if(nextoutmsg.Payload()) delete nextoutmsg.Payload();
    logger.msg(WARNING, "next element of the chain returned error status");
    return make_http_fault(logger,*inpayload,outmsg,HTTP_INTERNAL_ERR);
  }
  if(!nextoutmsg.Payload()) {
    logger.msg(WARNING, "next element of the chain returned empty payload");
    return make_http_fault(logger,*inpayload,outmsg,HTTP_INTERNAL_ERR);
  }
  PayloadRawInterface* retpayload = NULL;
  PayloadStreamInterface* strpayload = NULL;
  try {
    retpayload = dynamic_cast<PayloadRawInterface*>(nextoutmsg.Payload());
  } catch(std::exception& e) { };
  if(!retpayload) try {
    strpayload = dynamic_cast<PayloadStreamInterface*>(nextoutmsg.Payload());
  } catch(std::exception& e) { };
  if((!retpayload) && (!strpayload)) {
    logger.msg(WARNING, "next element of the chain returned invalid/unsupported payload");
    delete nextoutmsg.Payload();
    return make_http_fault(logger,*inpayload,outmsg,HTTP_INTERNAL_ERR);
  };
  if(!ProcessSecHandlers(nextinmsg,"outgoing")) {
    delete nextoutmsg.Payload(); return make_http_fault(logger,*inpayload,outmsg,HTTP_BAD_REQUEST); // Maybe not 400 ?
  };
  // Create HTTP response from raw body content
  // Use stream payload of inmsg to send HTTP response
  int http_code = HTTP_OK;
  const char* http_resp = "OK";
  int l = 0;
/*
  if(retpayload) {
    if(retpayload->BufferPos(0) != 0) {
      http_code=HTTP_PARTIAL;
      http_resp="Partial content";
    } else {
      for(int i = 0;;++i) {
        if(retpayload->Buffer(i) == NULL) break;
        l=retpayload->BufferPos(i) + retpayload->BufferSize(i);
      };
      if(l != retpayload->Size()) {
        http_code=HTTP_PARTIAL;
        http_resp="Partial content";
      };
    };
  } else {
    if((strpayload->Pos() != 0) || (strpayload->Limit() != strpayload->Size())) {
      http_code=HTTP_PARTIAL;
      http_resp="Partial content";
    };
  };
*/
  PayloadHTTP* outpayload = new PayloadHTTP(http_code,http_resp,*inpayload);
  // Use attributes which higher level MCC may have produced for HTTP
  for(AttributeIterator i = nextoutmsg.Attributes()->getAll();i.hasMore();++i) {
    const char* key = i.key().c_str();
    if(strncmp("HTTP:",key,5) == 0) {
      key+=5;
      // TODO: check for special attributes: method, code, reason, endpoint, etc.
      outpayload->Attribute(std::string(key),*i);
    };
  };
  outpayload->KeepAlive(keep_alive);
  if(retpayload) {
    outpayload->Body(*retpayload);
  } else {
    outpayload->Body(*strpayload);
  }
  bool flush_r = outpayload->Flush();
  delete outpayload;
  outmsg = nextoutmsg;
  // Returning empty payload because response is already sent through Flush
  PayloadRaw* outpayload_e = new PayloadRaw;
  outmsg.Payload(outpayload_e);
  if(!flush_r) {
    // If flush failed then we can't know if anything HTTPish was 
    // already sent. Hence we are just making lower level close
    // connection.
    logger.msg(WARNING, "Error to flush output payload");
    return MCC_Status(SESSION_CLOSE);
  };
  if(!keep_alive) return MCC_Status(SESSION_CLOSE);
  return MCC_Status(STATUS_OK);
}

Here is the call graph for this function:

bool Arc::MCC::ProcessSecHandlers ( Message message,
const std::string &  label = "" 
) const [protected, inherited]

Executes security handlers of specified queue.

Returns true if the message is authorized for further processing or if there are no security handlers which implement authorization functionality. This is a convenience method and has to be called by the implemention of the MCC.

Definition at line 45 of file MCC.cpp.

                                           {
    // Each MCC/Service can define security handler queues in the configuration
    // file, the queues have labels specified in handlers configuration 'event'
    // attribute.
    // Security handlers in one queue are called sequentially.
    // Each one should be configured carefully, because there can be some
    // relationship between them (e.g. authentication should be put in front
    // of authorization).
    // The SecHandler::Handle() only returns true/false with true meaning that
    // handler processed message successfuly. If SecHandler implements
    // authorization functionality, it returns false if message is disallowed
    // and true otherwise.
    // If any SecHandler in the handler chain produces some information which
    // will be used by some following handler, the information should be
    // stored in the attributes of message (e.g. the Identity extracted from
    // authentication will be used by authorization to make access control
    // decision).
    std::map<std::string, std::list<ArcSec::SecHandler *> >::const_iterator q =
      sechandlers_.find(label);
    if (q == sechandlers_.end()) {
      logger.msg(DEBUG,
     "No security processing/check requested for '%s'", label);
      return true;
    }
    for (std::list<ArcSec::SecHandler *>::const_iterator h = q->second.begin();
         h != q->second.end(); ++h) {
      const ArcSec::SecHandler *handler = *h;
      if (!handler)
        continue; // Shouldn't happen. Just a sanity check.
      if (!(handler->Handle(&message))) {
        logger.msg(INFO, "Security processing/check failed");
        return false;
      }
    }
    logger.msg(DEBUG, "Security processing/check passed");
    return true;
  }

Here is the call graph for this function:

Here is the caller graph for this function:

void Arc::MCC::Unlink ( ) [virtual, inherited]

Removing all links.

Useful for destroying chains.

Definition at line 29 of file MCC.cpp.

                   {
    for (std::map<std::string, MCCInterface *>::iterator n = next_.begin();
         n != next_.end(); n = next_.begin())
      next_.erase(n);
  }

Here is the caller graph for this function:


Member Data Documentation

Arc::Logger Arc::MCC_HTTP::logger [static, protected, inherited]

A logger for MCCs.

A logger intended to be the parent of loggers in the different MCCs.

Reimplemented from Arc::MCC.

Definition at line 17 of file MCCHTTP.h.

std::map<std::string, MCCInterface *> Arc::MCC::next_ [protected, inherited]

Set of labeled "next" components.

Each implemented MCC must call process() method of corresponding MCCInterface from this set in own process() method.

Definition at line 50 of file MCC.h.

std::map<std::string, std::list<ArcSec::SecHandler *> > Arc::MCC::sechandlers_ [protected, inherited]

Set of labeled authentication and authorization handlers.

MCC calls sequence of handlers at specific point depending on associated identifier. In most aces those are "in" and "out" for incoming and outgoing messages correspondingly.

Definition at line 57 of file MCC.h.


The documentation for this class was generated from the following files: