You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@trafficserver.apache.org by Manjesh Nilange <ma...@yahoo-inc.com> on 2010/07/21 23:58:30 UTC

C++ wrapper for some API sections

Hi all,

I started working on a C++ wrapper for some of the API functions to make
some of the data structures easier to use. What I did was basically wrap
the pointers and types so that they can be automatically
released/destroyed. I abandoned working on this as I have other things
on my place. However, if others see value in what it currently provides
or wish to enhance and improve it, I'll check it in. I'm attaching the
wrapper and an example source file to show the benefits (reduced code
and automatic cleanup). The wrapper is just a proof of concept and has
some caveats and limitations, but it compiles and works fine. 

- Manjesh


RE: C++ wrapper for some API sections

Posted by Manjesh Nilange <ma...@yahoo-inc.com>.
Does anybody want to own the Jira ticket? I'm not planning to work on
this.

Also, boost is used for 'noncopyable', not to wrap pointers. If we don't
want to use boost, this can be replaced trivially.

- Manjesh


> -----Original Message-----
> From: Mladen Turk [mailto:mturk@apache.org]
> Sent: Thursday, July 22, 2010 3:45 AM
> To: dev@trafficserver.apache.org
> Subject: Re: C++ wrapper for some API sections
> 
> On 07/22/2010 12:09 AM, Manjesh Nilange wrote:
> > The attachments are missing (even though my sent folder email says
the
> > attachments were part of it). I'm just going to copy-paste the two
files
> > in the email.
> >
> 
> Why don't create the JIRA issue (the usual way)
> and attach the code in there.
> I doubt anyone will take a look otherwise.
> 
> And BTW, introducing multi-megabyte boost just to wrap
> few pointer will fire my -1 immediately.
> 
> 
> Regards
> --
> ^TM

Re: C++ wrapper for some API sections

Posted by Mladen Turk <mt...@apache.org>.
On 07/22/2010 12:09 AM, Manjesh Nilange wrote:
> The attachments are missing (even though my sent folder email says the
> attachments were part of it). I'm just going to copy-paste the two files
> in the email.
>

Why don't create the JIRA issue (the usual way)
and attach the code in there.
I doubt anyone will take a look otherwise.

And BTW, introducing multi-megabyte boost just to wrap
few pointer will fire my -1 immediately.


Regards
-- 
^TM

RE: C++ wrapper for some API sections

Posted by Manjesh Nilange <ma...@yahoo-inc.com>.
The attachments are missing (even though my sent folder email says the
attachments were part of it). I'm just going to copy-paste the two files
in the email.

 

Example code:

 

void

usingCxxApi(INKHttpTxn txnp) {

  HttpTransaction txn(txnp);

  HttpRequest client_req;

  if (!txn.getClientReq(client_req)) {

    INKError("[%s] Error while retrieving client request",
__FUNCTION__);

    return;

  }

  Url url;

  if (client_req.getUrl(url)) {

    MString query;

    if (url.getQuery(query)) {

      INKDebug(DEBUG_TAG, "[%s] Got query [%.*s]", __FUNCTION__,
query.size(), query.data());

    }

  }

  HttpHeaderFieldIterator field_iter;

  for (client_req.getHeaderFieldIterator(field_iter); field_iter.good();
field_iter.next()) {

    MString name;

    if (field_iter->getName(name) && name.size()) {

      HttpHeaderValueIterator value_iter;

      for (field_iter->getValueIterator(value_iter); value_iter.good();
value_iter.next()) {

        INKDebug(DEBUG_TAG, "[%s] Examining header field [%.*s] with
value [%.*s]",

                 name.size(), name.data(), value_iter->size(),
value_iter->data());

        }

      }

    }

  }

}

 

void

notUsingCxxApi(INKHttpTxn txnp) {

  INKMBuffer req_bufp;

  INKMLoc req_hdr_loc;

  if (INKHttpTxnClientReqGet(txnp, &req_bufp, &req_hdr_loc) == 0) {

    INKError("[%s] Error while retrieving client request",
__FUNCTION__);

    return;

  }

  INKMLoc url_loc = INKHttpHdrUrlGet(req_bufp, req_hdr_loc);

  if (url_loc && (url_loc != INK_ERROR_PTR)) {

    int query_len;

    const char *query = INKUrlHttpQueryGet(req_bufp, url_loc,
&query_len);

    if (query && (query != INK_ERROR_PTR)) {

      INKDebug(DEBUG_TAG, "[%s] Got query [%.*s]", __FUNCTION__,
query._len, query);

      INKHandleStringRelease(req_bufp, url_loc, query);

    }

    INKHandleMLocRelease(req_bufp, req_hdr_loc, url_loc);

  }

  INKMLoc field_loc = INKMimeHdrFieldGet(req_bufp, req_hdr_loc, 0);

  while (field_loc && (field_loc != INK_ERROR_PTR)) {

    INKMLoc next_field_loc;

    const char *name;

    int name_len;

    name = INKMimeHdrFieldNameGet(req_bufp, req_hdr_loc, field_loc,
&name_len);

    if (name && (name != INK_ERROR_PTR)) {

      int n_values;

      n_values = INKMimeHdrFieldValuesCount(req_bufp, req_hdr_loc,
field_loc);

      if (n_values && (n_values != INK_ERROR)) {

        const char *value;

        int value_len;

        for (int i = 0; i < n_values; ++i) {

          if (INKMimeHdrFieldValueStringGet(req_bufp, req_hdr_loc,
field_loc, i,

                                            &value, &value_len) ==
INK_SUCCESS) {

            if (value) {

              INKDebug(DEBUG_TAG, "[%s] Examining header field [%.*s]
with value [%.*s]",

                       name_len, name, value_len, value);

            }

            INKHandleStringRelease(req_bufp, field_loc, value);

          }

        }

      }

      INKHandleStringRelease(req_bufp, field_loc, name);

    }

    next_field_loc = INKMimeHdrFieldNext(req_bufp, req_hdr_loc,
field_loc);

    INKHandleMLocRelease(req_bufp, req_hdr_loc, field_loc);

    field_loc = next_field_loc;

  }

  INKHandleMLocRelease(req_bufp, INK_NULL_MLOC, req_hdr_loc);

}

 

 

 

And the actual wrapper:

 

 

 

 

 

#ifndef _TS_API_CXX_H

 

#define _TS_API_CXX_H

 

#include <boost/noncopyable.hpp>

 

#include "InkAPI.h"

 

namespace Ts {

 

  class MString : boost::noncopyable {

  public:

    MString() : _data(0), _size(0), _type(MLOC_DEPENDENT), _loc(0) { };

    const char *data() const { return _data; }

    int size() const { return _size; }

    operator const char *() const { return _data; };

    void clear() {

      if (_type == MLOC_DEPENDENT) {

        if (_loc) {

          INKHandleStringRelease(_buf, _loc, _data);

          _loc = 0;

        }

      } else {

        if (_data) {

          INKfree(const_cast<char *>(_data));

        }

      }

      _size = 0;

    }

    ~MString() { clear(); }

  private:

    const char *_data;

    int _size;

    enum Type { MLOC_DEPENDENT, HEAP_DEPENDENT };

    Type _type;

    INKMBuffer _buf;

    INKMLoc _loc;

    void _set(INKMBuffer buf, INKMLoc loc) {

      _buf = buf;

      _loc = loc;

      _type = MLOC_DEPENDENT;

    }

    void _set(const char *ptr) {

      _data = ptr;

      _size = _data ? strlen(_data) : 0;

      _type = HEAP_DEPENDENT;

    }

    friend class Url;

    friend class HttpHeaderField;

    friend class HttpHeaderValueIterator;

    friend class HttpRequest;

  };

 

  class HttpHeaderValueIterator : boost::noncopyable {

  public:

    HttpHeaderValueIterator() : _curr_index(-1), _n_values(-1) { };

    bool good() { return (_curr_index < _n_values); };

    void next() {

      _curr_value.clear();

      ++_curr_index;

      if (_curr_index < _n_values) {

        if (INKMimeHdrFieldValueStringGet(_hdr_buf, _hdr_loc,
_field_loc,

                                          _curr_index,
&(_curr_value._data),

                                          &(_curr_value._size)) ==
INK_SUCCESS) {

          _curr_value._set(_hdr_buf, _field_loc);

        } else {

          _curr_index = _n_values = -1;

        }

      }

    }

    MString *operator ->() {

      return &(_curr_value);

    }

    MString &operator *() {

      return _curr_value;

    }

    void clear() {

      _curr_value.clear();

      _curr_index = _n_values = -1;

    }

    ~HttpHeaderValueIterator() { clear(); };

  private:

    INKMBuffer _hdr_buf;

    INKMLoc _hdr_loc;

    INKMLoc _field_loc;

    MString _curr_value;

    int _curr_index;

    int _n_values;

    void _set(INKMBuffer hdr_buf, INKMLoc hdr_loc, INKMLoc field_loc,
int n_values) {

      if (n_values) {

        _hdr_buf = hdr_buf;

        _hdr_loc = hdr_loc;

        _field_loc = field_loc;

        _n_values = n_values;

        next();

      }

    }

    friend class HttpHeaderField;

    friend class HttpMessage;

  };

 

  class HttpHeaderField : boost::noncopyable {

  public:

    HttpHeaderField() : _field_loc(0) { };

    bool getName(MString &name) {

      name.clear();

      if (_field_loc) {

        name._data = INKMimeHdrFieldNameGet(_hdr_buf, _hdr_loc,
_field_loc, &name._size);

        if (name._data && (name._data != INK_ERROR_PTR)) {

          name._set(_hdr_buf, _field_loc);

          return true;

        }

      }

      return false;

    }

    bool getValueIterator(HttpHeaderValueIterator &value_iter) {

      value_iter.clear();

      if (_field_loc) {

        int n_values = INKMimeHdrFieldValuesCount(_hdr_buf, _hdr_loc,
_field_loc);

        if (n_values != INK_ERROR) {

          value_iter._set(_hdr_buf, _hdr_loc, _field_loc, n_values);

          return true;

        }

      }

      return false;

    }

    void clear() {

      if (_field_loc) {

        INKHandleMLocRelease(_hdr_buf, _hdr_loc, _field_loc);

        _field_loc = 0;

      }

    }

    ~HttpHeaderField() { clear(); };

  private:

    INKMBuffer _hdr_buf;

    INKMLoc _hdr_loc;

    INKMLoc _field_loc;

    void _set(INKMBuffer hdr_buf, INKMLoc hdr_loc, INKMLoc field_loc) {

      _hdr_buf = hdr_buf;

      _hdr_loc = hdr_loc;

      _field_loc = field_loc;

    }

    void _set(INKMLoc field_loc) { _field_loc = field_loc; };

    void _destroy() {

      if (_field_loc) {

        INKMimeHdrFieldDestroy(_hdr_buf, _hdr_loc, _field_loc);

        clear();

      }

    }

    friend class HttpHeaderFieldIterator;

  };

 

  class HttpHeaderFieldIterator : boost::noncopyable {

  public:

    HttpHeaderFieldIterator() : _curr_index(-1), _good(false) { };

    bool good() { return _good; };

    void next() {

      if (_good) {

        ++_curr_index;

        _curr_field.clear();

        _field_loc = INKMimeHdrFieldGet(_hdr_buf, _hdr_loc,
_curr_index);

        if (_field_loc && (_field_loc != INK_ERROR_PTR)) {

          _curr_field._set(_field_loc);

        } else {

          _good = false;

        }

      }

    }

    void destroy() {

      if (_good) {

        _curr_field._destroy();

        --_curr_index; // to offset the increment in next()

      }

    }

    HttpHeaderField *operator ->() {

      return &(_curr_field);

    }

    HttpHeaderField &operator *() {

      return _curr_field;

    }

    void clear() {

      _curr_field.clear();

      _good = false;

    }

    ~HttpHeaderFieldIterator() { clear(); }

  private:

    INKMBuffer _hdr_buf;

    INKMLoc _hdr_loc;

    INKMLoc _field_loc;

    HttpHeaderField _curr_field;

    int _curr_index;

    bool _good;

    void _set(INKMBuffer hdr_buf, INKMLoc hdr_loc, INKMLoc field_loc) {

      _hdr_buf = hdr_buf;

      _hdr_loc = hdr_loc;

      _field_loc = field_loc;

      _curr_field._set(hdr_buf, hdr_loc, _field_loc);

      _curr_index = 0;

      _good = true;

    }

    friend class HttpMessage;

  };

  

  class Url : boost::noncopyable {

  public:

    Url() : _url_loc(0) { }

    bool getQuery(MString &query) {

      query.clear();

      if (_url_loc) {

        query._data = INKUrlHttpQueryGet(_hdr_buf, _url_loc,
&(query._size));

        if (query._data && (query._data != INK_ERROR_PTR)) {

          query._set(_hdr_buf, _url_loc);

          return true;

        }

      }

      return false;

    }

    bool getString(MString &mstr) {

      mstr.clear();

      if (_url_loc) {

        const char *ptr = INKUrlStringGet(_hdr_buf, _url_loc, NULL);

        if (ptr && (ptr != INK_ERROR_PTR)) {

          mstr._set(ptr);

          return true;

        }

      }

      return false;

    }

    void clear() {

      if (_url_loc) {

        INKHandleMLocRelease(_hdr_buf, _hdr_loc, _url_loc);

        _url_loc = 0;

      }

    }

    ~Url() { clear(); }

  private:

    INKMBuffer _hdr_buf;

    INKMLoc _hdr_loc;

    INKMLoc _url_loc;

    void _set(INKMBuffer hdr_buf, INKMLoc hdr_loc, INKMLoc url_loc) {

      _hdr_buf = hdr_buf;

      _hdr_loc = hdr_loc;

      _url_loc = url_loc;

    }

    friend class HttpRequest;

  };

 

  class HttpMessage : boost::noncopyable {

  public:

    HttpMessage() : _buf(0), _loc(0) { };

    virtual void clear() {

      if (_buf) {

        INKHandleMLocRelease(_buf, INK_NULL_MLOC, _loc);

        _buf = 0;

        _loc = 0;

      }

    }

    virtual bool getHeaderFieldIterator(HttpHeaderFieldIterator
&field_iter) {

      field_iter.clear();

      if (_buf) {

        INKMLoc first_field = INKMimeHdrFieldGet(_buf, _loc, 0);

        if (first_field && (first_field != INK_ERROR_PTR)) {

          field_iter._set(_buf, _loc, first_field);

          return true;

        }

      }

      return false;

    }

    virtual bool addHeaderField(const char *name, int name_len, const
char *value, int value_len) {

      bool retval = false;

      if (_buf) {

        INKMLoc field_loc = INKMimeHdrFieldCreate(_buf, _loc);

        if (field_loc && (field_loc != INK_ERROR_PTR)) {

          if (INKMimeHdrFieldNameSet(_buf, _loc, field_loc, name,
name_len) == INK_SUCCESS) {

            if (INKMimeHdrFieldValueStringInsert(_buf, _loc, field_loc,
0, value, value_len) == INK_SUCCESS) {

              if (INKMimeHdrFieldAppend(_buf, _loc, field_loc) ==
INK_SUCCESS) {

                retval = true;

              }

            }

          }

          INKHandleMLocRelease(_buf, _loc, field_loc);

        }

      }

      return retval;

    }

    virtual bool isHeaderPresent(const char *name, int name_len, const
char *value = 0, int value_len = 0) {

      bool retval = false;

      if (_buf) {

        INKMLoc field_loc = INKMimeHdrFieldFind(_buf, _loc, name,
name_len);

        if (field_loc && (field_loc != INK_ERROR_PTR)) {

          if (value && value_len) {

            int n_values = INKMimeHdrFieldValuesCount(_buf, _loc,
field_loc);

            if (n_values != INK_ERROR) {

              HttpHeaderValueIterator value_iter;

              value_iter._set(_buf, _loc, field_loc, n_values);

              for (; value_iter.good(); value_iter.next()) {

                if ((value_iter->size() == value_len) &&
(strncasecmp(value_iter->data(), value, value_len) == 0)) {

                  retval = true;

                  break;

                }

              }

            }

          } else {

            retval = true;

          }

          INKHandleMLocRelease(_buf, _loc, field_loc);

        }

      }

      return retval;

    }

    virtual ~HttpMessage() { clear(); };

  protected:

    INKMBuffer _buf;

    INKMLoc _loc;

  };

 

  class HttpRequest : public HttpMessage {

  public:

    bool getUrl(Url &url) {

      url.clear();

      if (_buf) {

        INKMLoc url_loc = INKHttpHdrUrlGet(_buf, _loc);

        if (url_loc && (url_loc != INK_ERROR_PTR)) {

          url._set(_buf, _loc, url_loc);

          return true;

        }

      }

      return false;

    }

    bool getMethod(MString &method) {

      method.clear();

      if (_buf) {

        method._data = INKHttpHdrMethodGet(_buf, _loc, &method._size);

        if (method._data && (method._data != INK_ERROR_PTR)) {

          method._set(_buf, _loc);

          return true;

        }

      }

      return false;

    }

  private:

    friend class HttpTransaction;

  };

 

  class HttpResponse : public HttpMessage {

  public:

  private:

    friend class HttpTransaction;

  };

 

  class HttpTransaction : boost::noncopyable {

  public:

    HttpTransaction(INKHttpTxn txnp) : _txnp(txnp) { };

    bool getClientReq(HttpRequest &req) {

      req.clear();

      return (INKHttpTxnClientReqGet(_txnp, &req._buf, &req._loc) == 1);

    }

    bool getServerResp(HttpResponse &resp) {

      resp.clear();

      return (INKHttpTxnServerRespGet(_txnp, &resp._buf, &resp._loc) ==
1);

    }

    bool getClientResp(HttpResponse &resp) {

      resp.clear();

      return (INKHttpTxnClientRespGet(_txnp, &resp._buf, &resp._loc) ==
1);

    }

  private:

    INKHttpTxn _txnp;

  };

 

};

 

#endif

 

 

 

 

> -----Original Message-----

> From: Manjesh Nilange [mailto:manjesh@yahoo-inc.com]

> Sent: Wednesday, July 21, 2010 2:59 PM

> To: dev@trafficserver.apache.org

> Subject: C++ wrapper for some API sections

> 

> Hi all,

> 

> I started working on a C++ wrapper for some of the API functions to
make

> some of the data structures easier to use. What I did was basically
wrap

> the pointers and types so that they can be automatically

> released/destroyed. I abandoned working on this as I have other things

> on my place. However, if others see value in what it currently
provides

> or wish to enhance and improve it, I'll check it in. I'm attaching the

> wrapper and an example source file to show the benefits (reduced code

> and automatic cleanup). The wrapper is just a proof of concept and has

> some caveats and limitations, but it compiles and works fine.

> 

> - Manjesh