--------------------- PatchSet 136 Date: 2002/11/07 11:14:24 Author: rbcollins Branch: esi Tag: (none) Log: more incrementals, and convert to true refcounted implementation Members: include/RefCount.h:1.1->1.1.4.1 src/ESI.cc:1.1.2.37->1.1.2.38 src/ESIElement.h:1.1.2.2->1.1.2.3 --- /dev/null Wed Feb 14 12:13:05 2007 +++ squid3/include/RefCount.h Wed Feb 14 12:13:53 2007 @@ -0,0 +1,90 @@ + +/* + * $Id: RefCount.h,v 1.1.4.1 2002/11/07 11:14:24 rbcollins Exp $ + * + * DEBUG: section xx Refcount allocator + * AUTHOR: Robert Collins + * + * SQUID Web Proxy Cache http://www.squid-cache.org/ + * ---------------------------------------------------------- + * + * Squid is the result of efforts by numerous individuals from + * the Internet community; see the CONTRIBUTORS file for full + * details. Many organizations have provided support for Squid's + * development; see the SPONSORS file for full details. Squid is + * Copyrighted (C) 2001 by the Regents of the University of + * California; see the COPYRIGHT file for full details. Squid + * incorporates software developed and/or copyrighted by other + * sources; see the CREDITS file for full details. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. + * + */ + +#ifndef _SQUID_REFCOUNT_H_ +#define _SQUID_REFCOUNT_H_ + +template +class RefCount { +public: + RefCount () : p_ (NULL) {} + RefCount (C *p) : p_(p) { if (p_) ++p_->count_; } + ~RefCount() + { + dereference(); + } + RefCount (const RefCount &p) : p_(p.p_) + { + reference (p); + } + RefCount& operator = (const RefCount& p) + { + // DO NOT CHANGE THE ORDER HERE!!! + // This preserves semantics on self assignment + reference(p); + dereference(); + p_ = p.p_; + return *this; + } + C * operator-> () {return p_; } + C & operator * () {return *p_; } + C * getRaw() {return p_; } + bool operator == (const RefCount& p) const + { + return p.p_ == p_; + } +private: + void dereference() + { + if (p_ && --p_->count_ == 0) p_->deleteSelf(); + } + void reference (const RefCount& p) + { + if (p.p_) ++p.p_->count_; + } + C *p_; + +}; + +struct RefCountable +{ + RefCountable():count_(0){} + virtual ~RefCountable(){} + virtual void deleteSelf() = 0; + /* Not private, to allow class hierarchies */ + unsigned count_; +}; + +#endif /* _SQUID_REFCOUNT_H_ */ Index: squid3/src/ESI.cc =================================================================== RCS file: /cvsroot/squid-sf//squid3/src/ESI.cc,v retrieving revision 1.1.2.37 retrieving revision 1.1.2.38 diff -u -r1.1.2.37 -r1.1.2.38 --- squid3/src/ESI.cc 4 Nov 2002 13:04:04 -0000 1.1.2.37 +++ squid3/src/ESI.cc 7 Nov 2002 11:14:24 -0000 1.1.2.38 @@ -1,6 +1,6 @@ /* - * $Id: ESI.cc,v 1.1.2.37 2002/11/04 13:04:04 rbcollins Exp $ + * $Id: ESI.cc,v 1.1.2.38 2002/11/07 11:14:24 rbcollins Exp $ * * DEBUG: section 86 ESI processing * AUTHOR: Robert Collins @@ -143,6 +143,7 @@ }; CBDATA_TYPE (esiVarState); FREE esiVarStateFree; + char const *esiVarState::esiUserOs[]= { "WIN", "MAC", @@ -153,7 +154,6 @@ extern int esiExpressionEval (char const *); - typedef enum { ESI_KICK_FAILED, ESI_KICK_PENDING, @@ -184,14 +184,14 @@ void *operator new (size_t byteCount); void operator delete (void *address); void deleteSelf(); - + ~esiComment(); esiComment(); - void render(esiSegment *); + void render(esiSegment *); +private: + static MemPool *pool; }; -CBDATA_TYPE (esiComment); -static FREE esiCommentFree; -static ESIElement * esiCommentNew(void); +MemPool * esiComment::pool = NULL; /* esiLiteral */ struct esiLiteral : public ESIElement{ @@ -201,6 +201,8 @@ esiLiteral(esiSegment *); esiLiteral(esiContext *, const XML_Char *s, int len); + ~esiLiteral(); + void render(esiSegment *); esiProcessResult_t process (int dovars); /* optimise copies away later */ @@ -209,10 +211,10 @@ int donevars:1; } flags; esiVarState *varState; +private: + static MemPool *pool; }; -CBDATA_TYPE (esiLiteral); -static FREE esiLiteralFree; -static ESIElement * esiLiteralNew(esiContext *, const XML_Char *s, int len); +MemPool *esiLiteral::pool = NULL; /* esiSequence */ class esiSequence : public ESIElement{ @@ -221,13 +223,16 @@ void operator delete (void *address); void deleteSelf(); - esiSequence(esiTreeParent *); + esiSequence(esiTreeParentPtr); + ~esiSequence(); + void render(esiSegment *); - bool addElement (ESIElement *); + bool addElement (ESIElementPtr); esiProcessResult_t process (int dovars); - void provideData (esiSegment *, ESIElement *); + void provideData (esiSegment *, ESIElementPtr); + bool mayFail () const; - ESIElement ** elements; /* unprocessed or rendered nodes */ + ESIElementPtr * elements; /* unprocessed or rendered nodes */ int allocedcount; size_t allocedsize; int elementcount; @@ -235,13 +240,13 @@ struct { int dovars:1; /* for esiVar */ } flags; -protected: - static FREE Free; private: - esiTreeParent *parent; - int elementIndex (ESIElement *anElement) const; + static MemPool *Pool; + esiTreeParentPtr parent; + int elementIndex (ESIElementPtr anElement) const; + bool mayFail_; }; -CBDATA_TYPE (esiSequence); +MemPool *esiSequence::Pool = NULL; /* esiInclude */ struct esiInclude : public ESIElement{ @@ -249,7 +254,8 @@ void operator delete (void *address); void deleteSelf(); - esiInclude(int attributes, const char **attr, esiContext *); + esiInclude(esiTreeParentPtr, int attributes, const char **attr, esiContext *); + ~esiInclude(); void render(esiSegment *); esiProcessResult_t process (int dovars); void subRequestDone (esiStreamContext *, bool); @@ -264,10 +270,13 @@ esiSegment *altcontent; esiContext *context; char *srcurl, *alturl; +private: + static MemPool *Pool; + esiTreeParentPtr parent; + void start(); + bool started; }; -CBDATA_TYPE (esiInclude); -static FREE esiIncludeFree; -static ESIElement * esiIncludeNew (int attributes, const char **attr, esiContext *); +MemPool *esiInclude::Pool = NULL; /* esiRemove */ class esiRemove : public ESIElement { @@ -278,7 +287,7 @@ esiRemove(); void render(esiSegment *); - bool addElement (ESIElement *); + bool addElement (ESIElementPtr); }; CBDATA_TYPE (esiRemove); static FREE esiRemoveFree; @@ -286,21 +295,19 @@ /* esiAttempt */ struct esiAttempt : public esiSequence{ - void *operator new (size_t byteCount); - void operator delete (void *address); +// void *operator new (size_t byteCount); +// void operator delete (void *address); void deleteSelf(); - esiAttempt(esiTreeParent *aParent) : esiSequence (aParent) {} + esiAttempt(esiTreeParentPtr aParent) : esiSequence (aParent) {} }; -CBDATA_TYPE(esiAttempt); /* esiExcept */ struct esiExcept : public esiSequence{ - void *operator new (size_t byteCount); - void operator delete (void *address); +// void *operator new (size_t byteCount); +// void operator delete (void *address); void deleteSelf(); - esiExcept(esiTreeParent *aParent) : esiSequence (aParent) {} + esiExcept(esiTreeParentPtr aParent) : esiSequence (aParent) {} }; -CBDATA_TYPE(esiExcept); /* esiTry */ struct esiTry : public ESIElement{ @@ -308,14 +315,16 @@ void operator delete (void *address); void deleteSelf(); - esiTry(esiTreeParent *aParent); + esiTry(esiTreeParentPtr aParent); + ~esiTry(); + void render(esiSegment *); - bool addElement (ESIElement *); + bool addElement (ESIElementPtr); esiProcessResult_t process (int dovars); - void provideData (esiSegment *data, ESIElement *source); + void provideData (esiSegment *data, ESIElementPtr source); - ESIElement *attempt; - ESIElement *except; + ESIElementPtr attempt; + ESIElementPtr except; struct { int attemptok:1; /* the attempt branch process correctly */ int exceptok:1; /* likewise */ @@ -323,22 +332,21 @@ int exceptfailed:1; /* the except branch failed */ } flags; private: - esiTreeParent *parent; + static MemPool *Pool; + esiTreeParentPtr parent; esiSegment* exceptbuffer; }; -CBDATA_TYPE (esiTry); -static FREE esiTryFree; +MemPool *esiTry::Pool = NULL; /* esiVar */ struct esiVar:public esiSequence{ - void *operator new (size_t byteCount); - void operator delete (void *address); +// void *operator new (size_t byteCount); +// void operator delete (void *address); void deleteSelf(); - esiVar(esiTreeParent *aParent) : esiSequence (aParent) { + esiVar(esiTreeParentPtr aParent) : esiSequence (aParent) { flags.dovars = 1; } }; -CBDATA_TYPE(esiVar); /* esiChoose */ struct esiChoose : public ESIElement { @@ -346,24 +354,26 @@ void operator delete (void *address); void deleteSelf(); - esiChoose(esiTreeParent *); + esiChoose(esiTreeParentPtr); + ~esiChoose(); + void render(esiSegment *); - bool addElement (ESIElement *); + bool addElement (ESIElementPtr); esiProcessResult_t process (int dovars); - void provideData (esiSegment *data, ESIElement *source); + void provideData (esiSegment *data, ESIElementPtr source); - ESIElement ** elements; /* unprocessed nodes */ + ESIElementPtr * elements; /* unprocessed nodes */ int allocedcount; size_t allocedsize; int elementcount; int chosenelement; - ESIElement *otherwise; + ESIElementPtr otherwise; private: - esiTreeParent *parent; + static MemPool *Pool; + esiTreeParentPtr parent; }; -CBDATA_TYPE (esiChoose); -static FREE esiChooseFree; +MemPool *esiChoose::Pool = NULL; /* esiWhen */ struct esiWhen : public esiSequence @@ -371,33 +381,33 @@ void *operator new (size_t byteCount); void operator delete (void *address); void deleteSelf(); - esiWhen(esiTreeParent *aParent) : esiSequence (aParent) {} + esiWhen(esiTreeParentPtr aParent, int attributes, const char **attr, esiVarState *); bool testsTrue() const { return testValue;} void setTestResult(bool aBool) {testValue = aBool;} private: + static MemPool *Pool; bool testValue; }; -CBDATA_TYPE (esiWhen); -static ESIElement *esiWhenNew(esiTreeParent *aParent, int attributes, const char **attr, esiVarState *); +MemPool *esiWhen::Pool = NULL; /* esiOtherwise */ struct esiOtherwise : public esiSequence{ - void *operator new (size_t byteCount); - void operator delete (void *address); +// void *operator new (size_t byteCount); +// void operator delete (void *address); void deleteSelf(); - esiOtherwise(esiTreeParent *aParent) : esiSequence (aParent) {} + esiOtherwise(esiTreeParentPtr aParent) : esiSequence (aParent) {} }; -CBDATA_TYPE(esiOtherwise); /* esiContext */ struct esiContext : public esiTreeParent { void *operator new (size_t byteCount); void operator delete (void *address); void deleteSelf(); + esiContext() {} /* when esi processing completes */ - void provideData(esiSegment *, ESIElement *source); + void provideData(esiSegment *, ESIElementPtr source); clientStreamNode *thisNode; /* our stream node */ clientHttpRequest *http; /* the request we are processing. HMM: cbdataReferencing this will result @@ -434,16 +444,16 @@ off_t readpos; /* the logical position we are reading from */ off_t pos; /* the logical position of outbound_offset in the data stream */ struct _parserState{ - ESIElement *stack[10]; /* a stack of esi elements that are open */ + ESIElementPtr stack[10]; /* a stack of esi elements that are open */ int stackdepth; /* self explanatory */ XML_Parser p; /* our parser */ - ESIElement *top(); + ESIElementPtr top(); } parserState; /* todo factor this off somewhere else; */ esiVarState *varState; - ESIElement *tree; + ESIElementPtr tree; static void Free(void *); - esiKick_t kick (); + esiKick_t kick (); private: void fail (); void freeResources(); @@ -454,9 +464,10 @@ CBDATA_TYPE(esiContext); +typedef RefCount esiIncludePtr; struct _esiStreamContext { int finished; - esiInclude *include; + esiIncludePtr include; esiSegment localbuffer; esiSegment *buffer; }; @@ -469,7 +480,7 @@ static esiProcessResult_t esiProcess (esiContext *); /* esiStreamContext */ static FREE esiStreamContextFree; -static esiStreamContext *esiStreamContextNew (esiInclude *); +static esiStreamContext *esiStreamContextNew (esiIncludePtr); /* other */ static CSCB esiBufferRecipient; @@ -503,10 +514,10 @@ delete this; } - void -esiContext::provideData (esiSegment *theData, ESIElement *source) +esiContext::provideData (esiSegment *theData, ESIElementPtr source) { + debug (86,5)("esiContext::provideData: %p %p %p\n",this, theData, source.getRaw()); assert (source == tree); if (!outbound) { outbound = theData; @@ -514,6 +525,7 @@ } else outboundtail->next = theData; fixupOutboundTail(); + send(); } void @@ -560,7 +572,7 @@ } /* Render if we can to get maximal sent data */ - assert (tree || flags.error); + assert (tree.getRaw() || flags.error); if (!outbound) outbound = outboundtail = new esiSegment; @@ -728,69 +740,84 @@ trimBlanks(); if (!flags.clientwantsdata) { - debug (86,5)("esiSend: Client does not want data - not sending anything\n"); + debug (86,5)("esiContext::send: Client does not want data - not sending anything\n"); + return 0; + } + + if (tree.getRaw() && tree->mayFail()) { + debug (86, 5)("esiContext::send: Tree may fail. Not sending.\n"); + return 0; + } + else flags.oktosend = 1; + +#if 0 + if (!flags.oktosend) { + + fatal("esiContext::send: Not OK to send.\n"); return 0; } +#endif - if (flags.oktosend && (rep || (outbound && + if (!(rep || (outbound && outbound->len && (outbound_offset <= outbound->len)))) { - /* Yes! Send it without asking for more upstream */ - /* memcopying because the client provided the buffer */ - /* TODO: skip data until pos == next->readoff; */ - clientStreamNode *next; - size_t len = 0; - assert (thisNode->data == this); - next = thisNode->next(); - cbdataReference (this); - if (outbound) - len = next->readBuffer.length < (outbound->len - outbound_offset) ? - next->readBuffer.length : (outbound->len - outbound_offset); - /* prevent corruption on range requests, even though we don't support them yet */ - assert (pos == next->readBuffer.offset); - /* We must send data or a reply */ - assert (len != 0 || rep != NULL); - if (len) { - xmemcpy (next->readBuffer.data, &outbound->buf[outbound_offset], len); - if (len + outbound_offset == outbound->len) { - esiSegment *temp = outbound->next; - /* remove the used buffer */ - outbound_offset = 0; - cbdataFree (outbound); - outbound = temp; - } - pos += len; - if (!outbound) - outboundtail = NULL; - /* trim leading empty buffers ? */ - while (outbound && outbound->next && !outbound->len) { - esiSegment *temp = outbound->next; - cbdataFree (outbound); - outbound = temp; - } - } - flags.clientwantsdata = 0; - debug (86,5)("esiSend: Client no longer wants data \n"); - /* Deal with re-entrancy */ - HttpReply *temprep = rep; - rep = NULL; /* freed downstream */ - if (temprep && varState) - varState->buildVary (temprep); - { - StoreIOBuffer tempBuffer = EMPTYIOBUFFER; - tempBuffer.length = len; - tempBuffer.offset = pos - len; - tempBuffer.data = next->readBuffer.data; - clientStreamCallback (thisNode, http, temprep, tempBuffer); - } - if (len == 0) - len = 1; /* tell the caller we sent something (because we sent headers */ - esiContext *temp = this; - cbdataReferenceDone (temp); - debug (86,5)("esiSend returning %d\n",len); - return len; + debug (86,5)("esiContext::send: Nothing to send.\n"); + return 0; } - debug (86,5)("esiSend returning 0\n"); - return 0; + debug (86,5)("esiContext::send: Sending something...\n"); + /* Yes! Send it without asking for more upstream */ + /* memcopying because the client provided the buffer */ + /* TODO: skip data until pos == next->readoff; */ + clientStreamNode *next; + size_t len = 0; + assert (thisNode->data == this); + next = thisNode->next(); + cbdataReference (this); + if (outbound) + len = next->readBuffer.length < (outbound->len - outbound_offset) ? + next->readBuffer.length : (outbound->len - outbound_offset); + /* prevent corruption on range requests, even though we don't support them yet */ + assert (pos == next->readBuffer.offset); + /* We must send data or a reply */ + assert (len != 0 || rep != NULL); + if (len) { + xmemcpy (next->readBuffer.data, &outbound->buf[outbound_offset], len); + if (len + outbound_offset == outbound->len) { + esiSegment *temp = outbound->next; + /* remove the used buffer */ + outbound_offset = 0; + cbdataFree (outbound); + outbound = temp; + } + pos += len; + if (!outbound) + outboundtail = NULL; + /* trim leading empty buffers ? */ + while (outbound && outbound->next && !outbound->len) { + esiSegment *temp = outbound->next; + cbdataFree (outbound); + outbound = temp; + } + } + flags.clientwantsdata = 0; + debug (86,5)("esiSend: Client no longer wants data \n"); + /* Deal with re-entrancy */ + HttpReply *temprep = rep; + rep = NULL; /* freed downstream */ + if (temprep && varState) + varState->buildVary (temprep); + { + StoreIOBuffer tempBuffer = EMPTYIOBUFFER; + tempBuffer.length = len; + tempBuffer.offset = pos - len; + tempBuffer.data = next->readBuffer.data; + clientStreamCallback (thisNode, http, temprep, tempBuffer); + } + if (len == 0) + len = 1; /* tell the caller we sent something (because we sent headers */ + esiContext *temp = this; + cbdataReferenceDone (temp); + debug (86,5)("esiSend returning %d\n",len); + return len; } /* Detach event from a client Stream */ @@ -1033,7 +1060,7 @@ return ESI_ELEMENT_NONE; } -ESIElement * +ESIElementPtr esiContext::_parserState::top() { return stack[stackdepth-1]; @@ -1100,12 +1127,12 @@ break; case ESI_ELEMENT_COMMENT: /* Put on the stack to allow skipping of 'invalid' markup */ - element = esiCommentNew (); + element = new esiComment (); esiAddStackElement (context, element); break; case ESI_ELEMENT_INCLUDE: /* Put on the stack to allow skipping of 'invalid' markup */ - element = esiIncludeNew (specifiedattcount, attr, context); + element = new esiInclude (context->parserState.top().getRaw(), specifiedattcount, attr, context); esiAddStackElement (context, element); break; case ESI_ELEMENT_REMOVE: @@ -1115,37 +1142,37 @@ break; case ESI_ELEMENT_TRY: /* Put on the stack to allow skipping of 'invalid' markup */ - element = new esiTry (context->parserState.top()); + element = new esiTry (context->parserState.top().getRaw()); esiAddStackElement (context, element); break; case ESI_ELEMENT_ATTEMPT: /* Put on the stack to allow skipping of 'invalid' markup */ - element = new esiAttempt (context->parserState.top()); + element = new esiAttempt (context->parserState.top().getRaw()); esiAddStackElement (context, element); break; case ESI_ELEMENT_EXCEPT: /* Put on the stack to allow skipping of 'invalid' markup */ - element = new esiExcept (context->parserState.top()); + element = new esiExcept (context->parserState.top().getRaw()); esiAddStackElement (context, element); break; case ESI_ELEMENT_VARS: /* Put on the stack to allow skipping of 'invalid' markup */ - element = new esiVar (context->parserState.top()); + element = new esiVar (context->parserState.top().getRaw()); esiAddStackElement (context, element); break; case ESI_ELEMENT_CHOOSE: /* Put on the stack to allow skipping of 'invalid' markup */ - element = new esiChoose (context->parserState.top()); + element = new esiChoose (context->parserState.top().getRaw()); esiAddStackElement (context, element); break; case ESI_ELEMENT_WHEN: /* Put on the stack to allow skipping of 'invalid' markup */ - element = esiWhenNew (context->parserState.top(), specifiedattcount, attr, context->varState); + element = new esiWhen (context->parserState.top().getRaw(), specifiedattcount, attr, context->varState); esiAddStackElement (context, element); break; case ESI_ELEMENT_OTHERWISE: /* Put on the stack to allow skipping of 'invalid' markup */ - element = new esiOtherwise (context->parserState.top()); + element = new esiOtherwise (context->parserState.top().getRaw()); esiAddStackElement (context, element); break; } @@ -1261,15 +1288,13 @@ esiAddLiteral (esiContext *context, const XML_Char *s, int len) { /* handle any skipped data */ - ESIElement *element; assert (len); debug (86,5)("literal length is %d\n", len); /* give a literal to the current element */ assert (context->parserState.stackdepth <11); - element = esiLiteralNew (context, s, len); + ESIElementPtr element (new esiLiteral (context, s, len)); if (!context->parserState.top()->addElement(element)) { debug (86,1)("esiProcess: failed to add esi node, probable error in ESI template\n"); - cbdataFree (element); return -1; } return 0; @@ -1293,7 +1318,7 @@ if (!context->parserState.stackdepth) { debug (86,5)("empty parser stack, inserting the top level node\n"); - assert (context->tree); + assert (context->tree.getRaw()); context->parserState.stack[context->parserState.stackdepth++] = context->tree; } @@ -1408,8 +1433,7 @@ httpReplyDestroy (rep); rep = NULL; } - if (tree) - cbdataFree (tree); + tree = NULL; if (flags.parserinited) { XML_ParserFree (parserState.p); flags.parserinited = 0; @@ -1526,7 +1550,6 @@ if (rep->sline.status != HTTP_OK) { httpReplyDestroy(rep); rep = NULL; - assert (cbdataReferenceValid (esiStream->include)); esiStream->include->subRequestDone (esiStream, false); esiStream->finished = 1; cbdataReferenceDone (esiStream); @@ -1563,7 +1586,6 @@ if (rep == NULL && recievedData.data == NULL && recievedData.length == 0) { /* TODO: get stream status to test the entry for aborts */ debug (86,5)("Finished reading upstream data in subrequest\n"); - assert (cbdataReferenceValid (esiStream->include)); esiStream->include->subRequestDone (esiStream, true); esiStream->finished = 1; cbdataReferenceDone (esiStream); @@ -1577,7 +1599,6 @@ if (clientHttpRequestStatus(-1, http)) { /* TODO: Does thisNode if block leak htto ? */ esiStreamContext *temp = esiStream; - assert (cbdataReferenceValid (esiStream->include)); esiStream->include->subRequestDone (esiStream, false); esiStream->finished = 1; cbdataReferenceDone (esiStream); @@ -1588,7 +1609,6 @@ case STREAM_UNPLANNED_COMPLETE: /* fallthru ok */ case STREAM_COMPLETE: /* ok */ debug (86,1)("ESI subrequest finished OK\n"); - assert (cbdataReferenceValid (esiStream->include)); esiStream->include->subRequestDone (esiStream, true); esiStream->finished = 1; cbdataReferenceDone (esiStream); @@ -1596,7 +1616,6 @@ return; case STREAM_FAILED: debug (86,1)("ESI subrequest failed transfer\n"); - assert (cbdataReferenceValid (esiStream->include)); esiStream->include->subRequestDone (esiStream, false); esiStream->finished = 1; cbdataReferenceDone (esiStream); @@ -1632,18 +1651,18 @@ { esiStreamContext *esiStream = (esiStreamContext *)data; assert (esiStream); - cbdataReferenceDone (esiStream->include); + esiStream->include = NULL; esiSegmentFreeList (&esiStream->localbuffer.next); debug (86,5)("Freeing stream context\n"); } esiStreamContext * -esiStreamContextNew (esiInclude *include) +esiStreamContextNew (esiIncludePtr include) { esiStreamContext *rv = NULL; CBDATA_INIT_TYPE_FREECB(esiStreamContext, esiStreamContextFree); rv = cbdataAlloc(esiStreamContext); - rv->include = cbdataReference (include); + rv->include = include; return rv; } @@ -1651,33 +1670,24 @@ /* Implementation of ESIElements */ /* esiComment */ -void -esiCommentFree (void *data) +esiComment::~esiComment() { - esiComment *thisNode = (esiComment *)data; - debug (86,5)("esiCommentFree %p\n", thisNode); -} - -ESIElement * -esiCommentNew () -{ - return new esiComment; + debug (86,5)("esiComment::~esiComment %p\n", this); } void * esiComment::operator new(size_t byteCount) { assert (byteCount == sizeof (esiComment)); - void *rv; - CBDATA_INIT_TYPE_FREECB(esiComment, esiCommentFree); - rv = (void *)cbdataAlloc (esiComment); - return rv; + if (!pool) + pool = memPoolCreate ("esiComment", sizeof (esiComment)); + return memPoolAlloc(pool); } void esiComment::operator delete (void *address) { - cbdataFree ((esiComment *)address); + memPoolFree (pool, address); } void @@ -1702,16 +1712,15 @@ esiLiteral::operator new(size_t byteCount) { assert (byteCount == sizeof (esiLiteral)); - void *rv; - CBDATA_INIT_TYPE_FREECB(esiLiteral, esiLiteralFree); - rv = (void *)cbdataAlloc (esiLiteral); - return rv; + if (!pool) + pool = memPoolCreate ("esiLiteral", sizeof (esiLiteral)); + return memPoolAlloc (pool); } void esiLiteral::operator delete (void *address) { - cbdataFree ((esiLiteral *)address); + memPoolFree (pool, address); } void @@ -1720,23 +1729,15 @@ delete this; } -void -esiLiteralFree (void *data) +esiLiteral::~esiLiteral() { - esiLiteral *thisNode = (esiLiteral *)data; - debug (86, 5) ("esiLiteralFree %p\n", thisNode); - esiSegmentFreeList (&thisNode->buffer); - cbdataReferenceDone (thisNode->varState); + debug (86, 5) ("esiLiteral::~esiLiteral: %p\n", this); + esiSegmentFreeList (&buffer); + cbdataReferenceDone (varState); } /* precondition: the buffer chain has at least start + length bytes of data */ -ESIElement * -esiLiteralNew (esiContext *context, const XML_Char *s, int length) -{ - return new esiLiteral(context, s, length); -} - esiLiteral::esiLiteral(esiSegment *aSegment) { buffer = aSegment; @@ -1808,42 +1809,44 @@ delete this; } -void -esiSequence::Free (void *data) +esiSequence::~esiSequence () { - esiSequence *thisNode = (esiSequence *)data; int i; - debug (86,5)("esiSequence::Free %p\n", thisNode); - for (i = 0; i < thisNode->elementcount; ++i) { - cbdataFree(thisNode->elements[i]); + debug (86,5)("esiSequence::~esiSequence %p\n", this); + for (i = 0; i < elementcount; ++i) { + elements[i] = NULL; } - if (thisNode->elements) - memFreeBuf (thisNode->allocedsize, thisNode->elements); - cbdataReferenceDone (thisNode->parent); + if (elements) + memFreeBuf (allocedsize, elements); } void * esiSequence::operator new(size_t byteCount) { assert (byteCount == sizeof (esiSequence)); - void *rv; - CBDATA_INIT_TYPE_FREECB(esiSequence, esiSequence::Free); - rv = (void *)cbdataAlloc (esiSequence); - return rv; + if (!Pool) + Pool = memPoolCreate ("esiSequence", sizeof (esiSequence)); + return memPoolAlloc (Pool); } void esiSequence::operator delete (void *address) { - cbdataFree ((esiSequence *)address); + memPoolFree (Pool, address); } -esiSequence::esiSequence(esiTreeParent *aParent) : parent (cbdataReference(aParent)) +esiSequence::esiSequence(esiTreeParentPtr aParent) : parent (aParent), mayFail_(true) { elements = NULL; } +bool +esiSequence::mayFail () const +{ + return mayFail_; +} + void esiSequence::render(esiSegment *output) { @@ -1858,10 +1861,10 @@ /* FIXME: pass a esiSegment ** ? */ while (output->next) output = output->next; - cbdataFree (elements[i]); + elements[i] = NULL; } if (processedcount) { - xmemmove (elements, &elements[processedcount], (elementcount - processedcount) * sizeof (ESIElement *)); + xmemmove (elements, &elements[processedcount], (elementcount - processedcount) * sizeof (ESIElementPtr)); } elementcount -= processedcount; processedcount = 0; @@ -1869,8 +1872,9 @@ } void -esiSequence::provideData (esiSegment *data, ESIElement *source) +esiSequence::provideData (esiSegment *data, ESIElementPtr source) { + debug (86,5) ("esiSequence::provideData %p %p %p\n", this, data, source.getRaw()); /* when data is provided, the element *must* be completed */ /* XXX: when the callback model is complete, * we can introduce 'finished'. And then this rule can be @@ -1880,35 +1884,36 @@ int index = elementIndex (source); assert (index >= 0); /* remove the current node */ - cbdataFree (elements[index]); + elements[index] = NULL; /* create a literal */ esiLiteral *temp = new esiLiteral (data); /* insert the literal */ elements[index] = temp; /* XXX: TODO push any pushable data upwards */ + /* fail() not done */ + assert (process (flags.dovars) != ESI_PROCESS_FAILED); } bool -esiSequence::addElement (ESIElement *element) +esiSequence::addElement (ESIElementPtr element) { /* add an element to the output list */ /* Some elements require specific parents */ - if (dynamic_cast(element) || - dynamic_cast(element)) { + if (dynamic_cast(element.getRaw()) || + dynamic_cast(element.getRaw())) { debug (86,0)("esiSequenceAdd: misparented Attempt or Except element (section 3.4)\n"); return false; } /* Tie literals together for efficiency */ - if (elementcount && dynamic_cast(element) && - dynamic_cast(elements[elementcount - 1])) { - debug (86,5)("esiSequenceAdd: tying Literals %p and %p together\n", elements[elementcount - 1], - element); - esiSegmentTransferList (&((esiLiteral *)element)->buffer, - &((esiLiteral *)elements[elementcount - 1])->buffer); - cbdataFree (element); + if (elementcount && dynamic_cast(element.getRaw()) && + dynamic_cast(elements[elementcount - 1].getRaw())) { + debug (86,5)("esiSequenceAdd: tying Literals %p and %p together\n", elements[elementcount - 1].getRaw(), + element.getRaw()); + esiSegmentTransferList (&((esiLiteral *)element.getRaw())->buffer, + &((esiLiteral *)elements[elementcount - 1].getRaw())->buffer); return true; } - elements = (ESIElement **)memReallocBuf (elements, ++elementcount * sizeof (ESIElement *), + elements = (ESIElementPtr*)memReallocBuf (elements, ++elementcount * sizeof (ESIElementPtr), &allocedsize); assert (elements); allocedcount = elementcount; @@ -1918,7 +1923,7 @@ } int -esiSequence::elementIndex(ESIElement *anElement) const +esiSequence::elementIndex(ESIElementPtr anElement) const { for (int i = 0; i < elementcount; ++i) if (elements[i] == anElement) @@ -1929,6 +1934,7 @@ esiProcessResult_t esiSequence::process (int dovars) { + debug (86,5)("esiSequence::process: Processing %p with%s variable processing\n", this, (dovars || flags.dovars) ? "" : "out"); /* process as much of the list as we can, stopping only on * faliures */ @@ -1937,9 +1943,11 @@ if (flags.dovars) dovars = 1; for (i = processedcount; i < elementcount; ++i) { + debug (86,5)("esiSequence::process %p about to process element[%d] %p\n", this, i, elements[i].getRaw()); switch (elements[i]->process(dovars)){ case ESI_PROCESS_COMPLETE: - debug (86,5)("esiSequenceProcess: element Processed OK\n"); + debug (86,5)("esiSequenceProcess: %p element %p Processed OK\n", + this, elements[i].getRaw()); if (i == processedcount) /* another completely ready */ ++processedcount; @@ -1961,8 +1969,12 @@ } } assert (rv != ESI_PROCESS_COMPLETE || processedcount == elementcount); + if (rv == ESI_PROCESS_COMPLETE || rv == ESI_PROCESS_PENDING_MAYFAIL) + { + mayFail_ = false; + } - if (processedcount == elementcount || dynamic_cast(parent)) { + if (processedcount == elementcount || dynamic_cast(parent.getRaw())) { /* provide incremental data outside of the composite */ esiSegment *temp = new esiSegment; render (temp); @@ -1972,36 +1984,34 @@ esiSegmentFreeList (&temp); } + debug (86,5)("esiSequence::process: %p completed\n", this); return rv; } /* esiInclude */ -void -esiIncludeFree (void *data) +esiInclude::~esiInclude() { - esiInclude *thisNode = (esiInclude *)data; - debug (86,5)("esiIncludeFree %p\n", thisNode); - esiSegmentFreeList (&thisNode->srccontent); - esiSegmentFreeList (&thisNode->altcontent); - cbdataReferenceDone (thisNode->context); - safe_free (thisNode->srcurl); - safe_free (thisNode->alturl); + debug (86,5)("esiInclude::Free %p\n", this); + esiSegmentFreeList (&srccontent); + esiSegmentFreeList (&altcontent); + cbdataReferenceDone (context); + safe_free (srcurl); + safe_free (alturl); } void * esiInclude::operator new(size_t byteCount) { assert (byteCount == sizeof (esiInclude)); - void *rv; - CBDATA_INIT_TYPE_FREECB(esiInclude, esiIncludeFree); - rv = (void *)cbdataAlloc (esiInclude); - return rv; + if (!Pool) + Pool = memPoolCreate ("esiInclude", sizeof (esiInclude)); + return memPoolAlloc(Pool); } void esiInclude::operator delete (void *address) { - cbdataFree ((esiInclude *)address); + memPoolFree (Pool, address); } void @@ -2033,13 +2043,7 @@ httpHeaderClean (&tempheaders); } -ESIElement * -esiIncludeNew (int attrcount, char const **attr, esiContext *context) -{ - return new esiInclude (attrcount, attr, context); -} - -esiInclude::esiInclude (int attrcount, char const **attr, esiContext *aContext) +esiInclude::esiInclude (esiTreeParentPtr aParent, int attrcount, char const **attr, esiContext *aContext) : parent (aParent), started (false) { int i; assert (aContext); @@ -2076,6 +2080,16 @@ } } context = cbdataReference(aContext); +} + +void +esiInclude::start() +{ + /* prevent freeing ourselves */ + esiIncludePtr foo(this); + if (started) + return; + started = true; if (src) { esiIncludeStart (src, srcurl, context->varState); /* eaten by the request */ @@ -2116,6 +2130,7 @@ esiProcessResult_t esiInclude::process (int dovars) { + start(); debug (86, 5)("esiIncludeRender: Processing include %p\n", this); if (flags.failed) { if (flags.onerrorcontinue) @@ -2193,7 +2208,14 @@ /* Kick ESI Processor */ debug (86,5)("esiInclude %p SubRequest %p completed, kicking processor , status %s\n", this, stream, flags.finished ? "OK" : "FAILED"); assert (context); - context->kick(); + if (!flags.failed) { + parent->provideData (srccontent ? srccontent:altcontent,this); + if (srccontent) + srccontent = NULL; + else + altcontent = NULL; + } else + context->kick(); } } @@ -2246,40 +2268,34 @@ /* Accept non-ESI children */ bool -esiRemove::addElement (ESIElement *element) +esiRemove::addElement (ESIElementPtr element) { - if (!dynamic_cast(element)) { + if (!dynamic_cast(element.getRaw())) { debug (86,5)("esiRemoveAdd: Failed for %p\n",this); return false; } - cbdataFree (element); return true; } /* esiTry */ -void -esiTryFree (void *data) +esiTry::~esiTry() { - esiTry *thisNode = (esiTry *)data; - debug (86,5)("esiTryFree %p\n", thisNode); - cbdataFree (thisNode->attempt); - cbdataFree (thisNode->except); + debug (86,5)("esiTry::~esiTry %p\n", this); } void * esiTry::operator new(size_t byteCount) { assert (byteCount == sizeof (esiTry)); - void *rv; - CBDATA_INIT_TYPE_FREECB(esiTry, esiTryFree); - rv = (void *)cbdataAlloc (esiTry); - return rv; + if (!Pool) + Pool = memPoolCreate ("esiTry", sizeof(esiTry)); + return memPoolAlloc (Pool); } void esiTry::operator delete (void *address) { - cbdataFree ((esiTry *)address); + memPoolFree (Pool, address); } void @@ -2288,7 +2304,7 @@ delete this; } -esiTry::esiTry(esiTreeParent *aParent) : parent (aParent) , exceptbuffer(NULL) +esiTry::esiTry(esiTreeParentPtr aParent) : parent (aParent) , exceptbuffer(NULL) { } @@ -2297,8 +2313,8 @@ { /* Try renders from it's children */ assert (this); - assert (attempt); - assert (except); + assert (attempt.getRaw()); + assert (except.getRaw()); debug (86, 5)("esiTryRender: Rendering Try %p\n", this); if (flags.attemptok) { attempt->render(output); @@ -2313,32 +2329,31 @@ /* Accept attempt and except only */ bool -esiTry::addElement(ESIElement *element) +esiTry::addElement(ESIElementPtr element) { - debug (86,5)("esiTryAdd: Try %p adding element %p\n",this, element); - if (dynamic_cast(element)) { + debug (86,5)("esiTryAdd: Try %p adding element %p\n",this, element.getRaw()); + if (dynamic_cast(element.getRaw())) { /* Swallow whitespace */ - debug (86,5)("esiTryAdd: Try %p skipping whitespace %p\n",this, element); - cbdataFree (element); + debug (86,5)("esiTryAdd: Try %p skipping whitespace %p\n",this, element.getRaw()); return true; } - if (dynamic_cast(element)) { - if (attempt) { + if (dynamic_cast(element.getRaw())) { + if (attempt.getRaw()) { debug (86,1)("esiTryAdd: Failed for %p - try allready has an attempt node (section 3.4)\n",this); return false; } attempt = element; return true; } - if (dynamic_cast(element)) { - if (except) { + if (dynamic_cast(element.getRaw())) { + if (except.getRaw()) { debug (86,1)("esiTryAdd: Failed for %p - try already has an except node (section 3.4)\n",this); return false; } except = element; return true; } - debug (86,1)("esiTryAdd: Failed to add element %p to try %p, incorrect element type (see section 3.4)\n", element, this); + debug (86,1)("esiTryAdd: Failed to add element %p to try %p, incorrect element type (see section 3.4)\n", element.getRaw(), this); return false; } @@ -2347,11 +2362,11 @@ { esiProcessResult_t rv = ESI_PROCESS_PENDING_MAYFAIL; assert (this); - if (!attempt) { + if (!attempt.getRaw()) { debug (86,0)("esiTryProcess: Try has no attempt element - ESI template is invalid (section 3.4)\n"); return ESI_PROCESS_FAILED; } - if (!except) { + if (!except.getRaw()) { debug (86,0)("esiTryProcess: Try has no except element - ESI template is invalid (section 3.4)\n"); return ESI_PROCESS_FAILED; } @@ -2407,7 +2422,7 @@ } void -esiTry::provideData (esiSegment *data, ESIElement *source) +esiTry::provideData (esiSegment *data, ESIElementPtr source) { if (source == attempt) { flags.attemptok = 1; @@ -2426,14 +2441,12 @@ /* esiAttempt */ +#if 0 void * esiAttempt::operator new(size_t byteCount) { assert (byteCount == sizeof (esiAttempt)); - void *rv; - CBDATA_INIT_TYPE_FREECB(esiAttempt, esiSequence::Free); - rv = (void *)cbdataAlloc (esiAttempt); - return rv; + } void @@ -2441,7 +2454,7 @@ { cbdataFree ((esiAttempt *)address); } - +#endif void esiAttempt::deleteSelf() { @@ -2449,6 +2462,7 @@ } /* esiExcept */ +#if 0 void * esiExcept::operator new(size_t byteCount) { @@ -2464,7 +2478,7 @@ { cbdataFree ((esiExcept *)address); } - +#endif void esiExcept::deleteSelf() { @@ -2472,6 +2486,7 @@ } /* esiVar */ +#if 0 void * esiVar::operator new(size_t byteCount) { @@ -2487,6 +2502,7 @@ { cbdataFree ((esiVar *)address); } +#endif void esiVar::deleteSelf() @@ -3047,35 +3063,30 @@ } /* esiChoose */ -void -esiChooseFree (void *data) +esiChoose::~esiChoose() { - esiChoose *thisNode = (esiChoose *)data; int i; - debug (86,5)("esiChooseFree %p\n", thisNode); - for (i = 0; i < thisNode->elementcount; ++i) { - cbdataFree(thisNode->elements[i]); - } - if (thisNode->elements) - memFreeBuf (thisNode->allocedsize, thisNode->elements); - if (thisNode->otherwise) - cbdataFree (thisNode->otherwise); + debug (86,5)("esiChoose::~esiChoose %p\n", this); + for (i = 0; i < elementcount; ++i) { + elements[i] = NULL; + } + if (elements) + memFreeBuf (allocedsize, elements); } void * esiChoose::operator new(size_t byteCount) { assert (byteCount == sizeof (esiChoose)); - void *rv; - CBDATA_INIT_TYPE_FREECB(esiChoose, esiChooseFree); - rv = (void *)cbdataAlloc (esiChoose); - return rv; + if (!Pool) + Pool = memPoolCreate ("esiChoose", sizeof(esiChoose)); + return memPoolAlloc (Pool); } void esiChoose::operator delete (void *address) { - cbdataFree ((esiChoose *)address); + memPoolFree (Pool, address); } void @@ -3084,7 +3095,7 @@ delete this; } -esiChoose::esiChoose(esiTreeParent *aParent) : parent (aParent) +esiChoose::esiChoose(esiTreeParentPtr aParent) : parent (aParent) { elements = NULL; chosenelement = -1; @@ -3095,38 +3106,37 @@ { /* append all processed elements, and trim processed and rendered elements */ assert (output->next == NULL); - assert (elementcount || otherwise); + assert (elementcount || otherwise.getRaw()); debug (86,5)("esiChooseRender: rendering\n"); if (chosenelement >= 0) elements[chosenelement]->render(output); - else if (otherwise) + else if (otherwise.getRaw()) otherwise->render(output); } bool -esiChoose::addElement(ESIElement *element) +esiChoose::addElement(ESIElementPtr element) { /* add an element to the output list */ - if (dynamic_cast(element)) { + if (dynamic_cast(element.getRaw())) { /* Swallow whitespace */ - debug (86,5)("esiChooseAdd: Choose %p skipping whitespace %p\n",this, element); - cbdataFree (element); + debug (86,5)("esiChooseAdd: Choose %p skipping whitespace %p\n",this, element.getRaw()); return true; } /* Some elements require specific parents */ - if (!(dynamic_cast(element) || dynamic_cast(element))) { + if (!(dynamic_cast(element.getRaw()) || dynamic_cast(element.getRaw()))) { debug (86,0)("esiChooseAdd: invalid child node for esi:choose (section 3.3)\n"); return false; } - if (dynamic_cast(element)) { - if (otherwise) { + if (dynamic_cast(element.getRaw())) { + if (otherwise.getRaw()) { debug (86,0)("esiChooseAdd: only one otherwise node allowed for esi:choose (section 3.3)\n"); return false; } otherwise = element; } else { - elements = (ESIElement **)memReallocBuf (elements, ++elementcount * sizeof (ESIElement *), + elements = (ESIElementPtr *)memReallocBuf (elements, ++elementcount * sizeof (ESIElementPtr), &allocedsize); assert (elements); allocedcount = elementcount; @@ -3134,7 +3144,7 @@ debug (86,3)("esiChooseAdd: Added a new element, elements = %d\n", elementcount); if (chosenelement == -1) - if (((esiWhen *)element)->testsTrue()) { + if ((dynamic_cast(element.getRaw()))->testsTrue()) { chosenelement = elementcount - 1; debug (86,3)("esiChooseAdd: Chose element %d\n", elementcount); } @@ -3153,20 +3163,20 @@ return ESI_PROCESS_FAILED; else if (chosenelement >= 0) { return elements[chosenelement]->process(dovars); - } else if (otherwise) + } else if (otherwise.getRaw()) return otherwise->process(dovars); else return ESI_PROCESS_COMPLETE; } void -esiChoose::provideData (esiSegment *data, ESIElement *source) +esiChoose::provideData (esiSegment *data, ESIElementPtr source) { if (!elementcount) fatal ("invalid callback = no when clause\n"); if (chosenelement >= 0) assert (source == elements[chosenelement]); - else if (otherwise) + else if (otherwise.getRaw()) assert (source == otherwise); else fatal ("esiChoose::provideData: invalid callback - no elements chosen\n"); @@ -3178,16 +3188,15 @@ esiWhen::operator new(size_t byteCount) { assert (byteCount == sizeof (esiWhen)); - void *rv; - CBDATA_INIT_TYPE_FREECB(esiWhen, esiSequence::Free); - rv = (void *)cbdataAlloc (esiWhen); - return rv; + if (!Pool) + Pool = memPoolCreate("esiWhen", sizeof(esiWhen)); + return memPoolAlloc(Pool); } void esiWhen::operator delete (void *address) { - cbdataFree ((esiWhen *)address); + memPoolFree(Pool, address); } void @@ -3196,10 +3205,8 @@ delete this; } -ESIElement * -esiWhenNew (esiTreeParent *aParent, int attrcount, const char **attr,esiVarState *varState) +esiWhen::esiWhen (esiTreeParentPtr aParent, int attrcount, const char **attr,esiVarState *varState) : esiSequence (aParent) { - esiWhen *rv = new esiWhen (aParent); char const *expression = NULL; int i; @@ -3218,17 +3225,17 @@ } /* No expression ? default is not matching */ if (!expression) - return (ESIElement *)rv; + return; varState->feedData(expression, strlen (expression)); /* expression is not our buffer */ expression = varState->extractChar (); - rv->setTestResult(esiExpressionEval (expression)); + setTestResult(esiExpressionEval (expression)); safe_free (expression); - return (ESIElement *)rv; } /* esiOtherwise */ +#if 0 void * esiOtherwise::operator new(size_t byteCount) { @@ -3244,6 +3251,7 @@ { cbdataFree ((esiOtherwise *)address); } +#endif void esiOtherwise::deleteSelf() Index: squid3/src/ESIElement.h =================================================================== RCS file: /cvsroot/squid-sf//squid3/src/ESIElement.h,v retrieving revision 1.1.2.2 retrieving revision 1.1.2.3 diff -u -r1.1.2.2 -r1.1.2.3 --- squid3/src/ESIElement.h 4 Nov 2002 10:42:16 -0000 1.1.2.2 +++ squid3/src/ESIElement.h 7 Nov 2002 11:14:24 -0000 1.1.2.3 @@ -1,5 +1,5 @@ /* - * $Id: ESIElement.h,v 1.1.2.2 2002/11/04 10:42:16 rbcollins Exp $ + * $Id: ESIElement.h,v 1.1.2.3 2002/11/07 11:14:24 rbcollins Exp $ * * * SQUID Web Proxy Cache http://www.squid-cache.org/ @@ -33,6 +33,8 @@ #ifndef SQUID_ESIELEMENT_H #define SQUID_ESIELEMENT_H +#include "RefCount.h" + class esiSegment; typedef enum { ESI_PROCESS_COMPLETE, @@ -42,8 +44,9 @@ } esiProcessResult_t; class ESIElement; -struct esiTreeParent { - virtual void provideData (esiSegment *data, ESIElement *source) +typedef RefCount ESIElementPtr; +struct esiTreeParent : public RefCountable { + virtual void provideData (esiSegment *data, ESIElementPtr source) { /* make abstract when all functionality complete */ assert (0); @@ -51,8 +54,10 @@ virtual ~esiTreeParent(){} }; +typedef RefCount esiTreeParentPtr; + struct ESIElement : public esiTreeParent { - virtual bool addElement(ESIElement *) { + virtual bool addElement(ESIElementPtr) { /* Don't accept children */ debug (86,5)("ESIElement::addElement: Failed for %p\n",this); return false; @@ -64,6 +69,10 @@ return ESI_PROCESS_COMPLETE; } virtual void deleteSelf() = 0; + + virtual bool mayFail() const { + return true; + } }; #endif /* SQUID_ESIELEMENT_H */