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:[email protected]]
> Sent: Wednesday, July 21, 2010 2:59 PM
> To: [email protected]
> 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