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:manj...@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