On 22/11/2013 8:20 a.m., Alex Rousskov wrote:
> On 11/18/2013 05:13 AM, Amos Jeffries wrote:
>> On 16/10/2013 7:12 a.m., Alex Rousskov wrote:
>>> On 10/11/2013 11:03 PM, Amos Jeffries wrote:
>>>> On 10/10/2013 10:12 p.m., Amos Jeffries wrote:
>>>>> Replace String class internals with an SBuf.
>>> FWIW, you made the review process more time consuming and less accurate
>>> [for me] by moving implementation from .cc and .cci into .h. As you
>>> know, bzr does not track such changes well. I only found a bug or two,
>>> but I am not confident the move did not hide more problems from me.
>>
>> Okay, undone that moving now. The attached patch is more easily comparible.
> 
> Thank you. I am using the patch from your recent posting on the same thread.
> 
> 
>> -    String(char const *);
>> +    explicit String(char const *);
> 
> Most of the non-String.* changes in the patch are due to this change.
> Most of those changes are not in a performance-sensitive code. And many
> are due to some _other_ code using char* types. Furthermore:
> 
>>      String &operator =(char const *);
> 
> The above operator is inconsistent with an explicit char* constructor.
> If you do not allow implicit construction, you should not allow
> assignment either because it is just one more form of an implicit char*
> conversion.
> 
> Please consider postponing adding "explicit" to the old constructor
> (which is unrelated to the patch scope AFAICT) until more stuff is
> converted to SBuf.
> 
> 
> The above comment does not apply to the explicit SBuf constructor. I am
> not sure "explicit" is warranted there, but I do not have enough
> ammunition to object to it: My overall motivation here is to make the
> eventual transition to SBuf smoother. Explicit constructors for an
> essentially temporary String class hurt that goal: We are forced to add
> String() wrappers first and then will be forced to remove them when the
> String class is gone...
> 
> 
>>> * Manipulation of defined_ in the assignment operator is questionable
>>> because it differs from similar manipulation in the constructor. If the
>>> code is correct, a comment explaining the difference is warranted.
>>
>> Done. Both use size()>0 now.
> 
> There is still a difference with:
> 
>> +String::String(char const *aString) :
>> +        buf_(aString),
>> +        defined_(aString != NULL)
> 
> Above, defined_ for "" is true. In the new SBuf constructor, defined_
> for "" is false.  If the code is correct, a comment explaining the
> difference is warranted.
> 
> 
>> +    if (str) {
>> +        append(str);
>> +        // XXX: empty string "" sent to append means no change,
> 
> The comment is misleading a bit: Appending an empty string sets defined_
> to true in the patched code because patched String::append() sets
> defined_ to true unconditionally.
> 
> 
>>  char const *
>>  String::termedBuf() const
>>  {
>> -    return buf_;
>> +    if (!defined()) return NULL;
> 
> Since an empty String could have been defined() in the unpatched code, I
> suggest relaxing this to always return c_str(), even for undefined
> Strings. I think it will be safer this way, but you should double check
> that I did not miss any cases where it would break something.
> 

I've gone through the non-String code use of String::defined() and tried
to find other ways of avoiding the defined()/NULL testing for ambiguous
cases of String/SBuf differences.

If you can check this attached patch is okay for merge to trunk we can
drop the nasty defined_ tracking the conversion patch has to do.

Amos

=== modified file 'src/HttpHdrCc.h'
--- src/HttpHdrCc.h     2013-03-26 10:33:10 +0000
+++ src/HttpHdrCc.h     2013-11-22 14:52:28 +0000
@@ -61,53 +61,53 @@
             min_fresh(MIN_FRESH_UNKNOWN) {}
 
     /// reset data-members to default state
     void clear();
 
     /// parse a header-string and fill in appropriate values.
     bool parse(const String & s);
 
     //manipulation for Cache-Control: public header
     bool hasPublic() const {return isSet(CC_PUBLIC);}
     bool Public() const {return isSet(CC_PUBLIC);}
     void Public(bool v) {setMask(CC_PUBLIC,v);}
     void clearPublic() {setMask(CC_PUBLIC,false);}
 
     //manipulation for Cache-Control: private header
     bool hasPrivate() const {return isSet(CC_PRIVATE);}
     const String &Private() const {return private_;}
     void Private(String &v) {
         setMask(CC_PRIVATE,true);
         // uses append for multi-line headers
-        if (private_.defined())
+        if (private_.size() > 0)
             private_.append(",");
         private_.append(v);
     }
     void clearPrivate() {setMask(CC_PRIVATE,false); private_.clean();}
 
     //manipulation for Cache-Control: no-cache header
     bool hasNoCache() const {return isSet(CC_NO_CACHE);}
     const String &noCache() const {return no_cache;}
     void noCache(String &v) {
         setMask(CC_NO_CACHE,true);
         // uses append for multi-line headers
-        if (no_cache.defined())
+        if (no_cache.size() > 0)
             no_cache.append(",");
         no_cache.append(v);
     }
     void clearNoCache() {setMask(CC_NO_CACHE,false); no_cache.clean();}
 
     //manipulation for Cache-Control: no-store header
     bool hasNoStore() const {return isSet(CC_NO_STORE);}
     bool noStore() const {return isSet(CC_NO_STORE);}
     void noStore(bool v) {setMask(CC_NO_STORE,v);}
     void clearNoStore() {setMask(CC_NO_STORE,false);}
 
     //manipulation for Cache-Control: no-transform header
     bool hasNoTransform() const {return isSet(CC_NO_TRANSFORM);}
     bool noTransform() const {return isSet(CC_NO_TRANSFORM);}
     void noTransform(bool v) {setMask(CC_NO_TRANSFORM,v);}
     void clearNoTransform() {setMask(CC_NO_TRANSFORM,false);}
 
     //manipulation for Cache-Control: must-revalidate header
     bool hasMustRevalidate() const {return isSet(CC_MUST_REVALIDATE);}
     bool mustRevalidate() const {return isSet(CC_MUST_REVALIDATE);}

=== modified file 'src/HttpHeaderTools.cc'
--- src/HttpHeaderTools.cc      2013-10-25 00:13:46 +0000
+++ src/HttpHeaderTools.cc      2013-11-22 14:55:11 +0000
@@ -277,41 +277,41 @@
         }
         end = pos;
         while (end < (start+len) && *end != '\\' && *end != '\"' && (unsigned 
char)*end > 0x1F && *end != 0x7F)
             ++end;
         if (((unsigned char)*end <= 0x1F && *end != '\r' && *end != '\n') || 
*end == 0x7F) {
             debugs(66, 2, HERE << "failed to parse a quoted-string header 
field with CTL octet " << (start-pos)
                    << " bytes into '" << start << "'");
             val->clean();
             return 0;
         }
         val->append(pos, end-pos);
         pos = end;
     }
 
     if (*pos != '\"') {
         debugs(66, 2, HERE << "failed to parse a quoted-string header field 
which did not end with \" ");
         val->clean();
         return 0;
     }
     /* Make sure it's defined even if empty "" */
-    if (!val->defined())
+    if (!val->termedBuf())
         val->limitInit("", 0);
     return 1;
 }
 
 /**
  * Checks the anonymizer (header_access) configuration.
  *
  * \retval 0    Header is explicitly blocked for removal
  * \retval 1    Header is explicitly allowed
  * \retval 1    Header has been replaced, the current version can be used.
  * \retval 1    Header has no access controls to test
  */
 static int
 httpHdrMangle(HttpHeaderEntry * e, HttpRequest * request, int req_or_rep)
 {
     int retval;
 
     /* check with anonymizer tables */
     HeaderManglers *hms = NULL;
     assert(e);

=== modified file 'src/SquidString.h'
--- src/SquidString.h   2013-10-04 13:55:21 +0000
+++ src/SquidString.h   2013-11-22 15:04:22 +0000
@@ -55,48 +55,40 @@
     typedef size_t size_type; //storage size intentionally unspecified
     const static size_type npos = std::string::npos;
 
     String &operator =(char const *);
     String &operator =(String const &);
     bool operator ==(String const &) const;
     bool operator !=(String const &) const;
 
     /**
      * Retrieve a single character in the string.
      \param pos        Position of character to retrieve.
      */
     _SQUID_INLINE_ char operator [](unsigned int pos) const;
 
     _SQUID_INLINE_ size_type size() const;
     /// variant of size() suited to be used for printf-alikes.
     /// throws when size() > MAXINT
     int psize() const;
 
     /**
-     * \retval true the String has some contents
-     */
-    _SQUID_INLINE_ bool defined() const;
-    /**
-     * \retval true the String does not hold any contents
-     */
-    _SQUID_INLINE_ bool undefined() const;
-    /**
      * Returns a raw pointer to the underlying backing store. The caller has 
been
      * verified not to make any assumptions about null-termination
      */
     _SQUID_INLINE_ char const * rawBuf() const;
     /**
      * Returns a raw pointer to the underlying backing store.
      * The caller requires it to be null-terminated.
      */
     _SQUID_INLINE_ char const * termedBuf() const;
     void limitInit(const char *str, int len); // TODO: rename to assign()
     void clean();
     void reset(char const *str);
     void append(char const *buf, int len);
     void append(char const *buf);
     void append(char const);
     void append(String const &);
     void absorb(String &old);
     const char * pos(char const *aString) const;
     const char * pos(char const ch) const;
     ///offset from string start of the first occurrence of ch
@@ -104,40 +96,43 @@
     size_type find(char const ch) const;
     size_type find(char const *aString) const;
     const char * rpos(char const ch) const;
     size_type rfind(char const ch) const;
     _SQUID_INLINE_ int cmp(char const *) const;
     _SQUID_INLINE_ int cmp(char const *, size_type count) const;
     _SQUID_INLINE_ int cmp(String const &) const;
     _SQUID_INLINE_ int caseCmp(char const *) const;
     _SQUID_INLINE_ int caseCmp(char const *, size_type count) const;
     _SQUID_INLINE_ int caseCmp(String const &) const;
 
     String substr(size_type from, size_type to) const;
 
     _SQUID_INLINE_ void cut(size_type newLength);
 
 private:
     void allocAndFill(const char *str, int len);
     void allocBuffer(size_type sz);
     void setBuffer(char *buf, size_type sz);
 
+    bool defined() const {return buf_!=NULL;}
+    bool undefined() const {return !defined();}
+
     _SQUID_INLINE_ bool nilCmp(bool, bool, int &) const;
 
     /* never reference these directly! */
     size_type size_; /* buffer size; 64K limit */
 
     size_type len_;  /* current length  */
 
     char *buf_;
 
     _SQUID_INLINE_ void set(char const *loc, char const ch);
     _SQUID_INLINE_ void cutPointer(char const *loc);
 
 };
 
 _SQUID_INLINE_ std::ostream & operator<<(std::ostream& os, String const 
&aString);
 
 _SQUID_INLINE_ bool operator<(const String &a, const String &b);
 
 #if _USE_INLINE_
 #include "String.cci"

=== modified file 'src/String.cci'
--- src/String.cci      2012-09-22 01:28:35 +0000
+++ src/String.cci      2013-11-22 15:01:15 +0000
@@ -36,50 +36,40 @@
 #include <stdint.h>
 #else /* HAVE_STDINT_H */
 #ifndef INT_MAX
 #define INT_MAX 1<<31 //hack but a safe bet
 #endif /* INT_MAX */
 #endif /* HAVE_STDINT_H */
 
 String::String() : size_(0), len_(0), buf_(NULL)
 {
 #if DEBUGSTRINGS
     StringRegistry::Instance().add(this);
 #endif
 }
 
 String::size_type
 String::size() const
 {
     return len_;
 }
 
-bool String::defined() const
-{
-    return buf_!=NULL;
-}
-
-bool String::undefined() const
-{
-    return buf_==NULL;
-}
-
 char const *
 String::rawBuf() const
 {
     return buf_;
 }
 
 char const *
 String::termedBuf() const
 {
     return buf_;
 }
 
 char
 String::operator [](unsigned int aPos) const
 {
     assert(aPos < size_);
 
     return buf_[aPos];
 }
 

=== modified file 'src/acl/HttpHeaderData.cc'
--- src/acl/HttpHeaderData.cc   2013-10-31 19:13:17 +0000
+++ src/acl/HttpHeaderData.cc   2013-11-22 14:41:12 +0000
@@ -58,47 +58,42 @@
 }
 
 bool
 ACLHTTPHeaderData::match(HttpHeader* hdr)
 {
     if (hdr == NULL)
         return false;
 
     debugs(28, 3, "aclHeaderData::match: checking '" << hdrName << "'");
 
     String value;
     if (hdrId != HDR_BAD_HDR) {
         if (!hdr->has(hdrId))
             return false;
         value = hdr->getStrOrList(hdrId);
     } else {
         if (!hdr->getByNameIfPresent(hdrName.termedBuf(), value))
             return false;
     }
 
-    // By now, we know the header is present, but:
-    // HttpHeader::get*() return an undefined String for empty header values;
-    // String::termedBuf() returns NULL for undefined Strings; and
-    // ACLRegexData::match() always fails on NULL strings.
-    // This makes it possible to detect an empty header value using regex:
-    const char *cvalue = value.defined() ? value.termedBuf() : "";
-    return regex_rule->match(cvalue);
+    const SBuf cvalue(value);
+    return regex_rule->match(cvalue.c_str());
 }
 
 wordlist *
 ACLHTTPHeaderData::dump()
 {
     wordlist *W = NULL;
     wordlistAdd(&W, hdrName.termedBuf());
     wordlist * regex_dump = regex_rule->dump();
     wordlistAddWl(&W, regex_dump);
     wordlistDestroy(&regex_dump);
     return W;
 }
 
 void
 ACLHTTPHeaderData::parse()
 {
     char* t = strtokFile();
     assert (t != NULL);
     hdrName = t;
     hdrId = httpHeaderIdByNameDef(hdrName.rawBuf(), hdrName.size());

=== modified file 'src/adaptation/ecap/MessageRep.cc'
--- src/adaptation/ecap/MessageRep.cc   2013-10-25 00:13:46 +0000
+++ src/adaptation/ecap/MessageRep.cc   2013-11-22 14:39:07 +0000
@@ -22,41 +22,41 @@
 {
 }
 
 bool
 Adaptation::Ecap::HeaderRep::hasAny(const Name &name) const
 {
     const http_hdr_type squidId = TranslateHeaderId(name);
     // XXX: optimize to remove getByName: we do not need the value here
     return squidId == HDR_OTHER ?
            theHeader.getByName(name.image().c_str()).size() > 0:
            (bool)theHeader.has(squidId);
 }
 
 Adaptation::Ecap::HeaderRep::Value
 Adaptation::Ecap::HeaderRep::value(const Name &name) const
 {
     const http_hdr_type squidId = TranslateHeaderId(name);
     const String value = squidId == HDR_OTHER ?
                          theHeader.getByName(name.image().c_str()) :
                          theHeader.getStrOrList(squidId);
-    return value.defined() ?
+    return value.size() > 0 ?
            Value::FromTempString(value.termedBuf()) : Value();
 }
 
 void
 Adaptation::Ecap::HeaderRep::add(const Name &name, const Value &value)
 {
     const http_hdr_type squidId = TranslateHeaderId(name); // HDR_OTHER OK
     HttpHeaderEntry *e = new HttpHeaderEntry(squidId, name.image().c_str(),
             value.toString().c_str());
     theHeader.addEntry(e);
 
     if (squidId == HDR_CONTENT_LENGTH)
         theMessage.content_length = theHeader.getInt64(HDR_CONTENT_LENGTH);
 }
 
 void
 Adaptation::Ecap::HeaderRep::removeAny(const Name &name)
 {
     const http_hdr_type squidId = TranslateHeaderId(name);
     if (squidId == HDR_OTHER)

=== modified file 'src/adaptation/ecap/XactionRep.cc'
--- src/adaptation/ecap/XactionRep.cc   2013-10-25 00:13:46 +0000
+++ src/adaptation/ecap/XactionRep.cc   2013-11-22 15:22:04 +0000
@@ -126,41 +126,41 @@
             client_addr = request->client_addr;
         if (!client_addr.isAnyAddr() && !client_addr.isNoAddr()) {
             char ntoabuf[MAX_IPSTRLEN] = "";
             client_addr.toStr(ntoabuf,MAX_IPSTRLEN);
             return libecap::Area::FromTempBuffer(ntoabuf, strlen(ntoabuf));
         }
     }
     return libecap::Area();
 }
 
 const libecap::Area
 Adaptation::Ecap::XactionRep::usernameValue() const
 {
 #if USE_AUTH
     const HttpRequest *request = dynamic_cast<const HttpRequest*>(theCauseRep ?
                                  theCauseRep->raw().header : 
theVirginRep.raw().header);
     Must(request);
     if (request->auth_user_request != NULL) {
         if (char const *name = request->auth_user_request->username())
             return libecap::Area::FromTempBuffer(name, strlen(name));
-        else if (request->extacl_user.defined() && request->extacl_user.size())
+        else if (request->extacl_user.size() > 0)
             return libecap::Area::FromTempBuffer(request->extacl_user.rawBuf(),
                                                  request->extacl_user.size());
     }
 #endif
     return libecap::Area();
 }
 
 const libecap::Area
 Adaptation::Ecap::XactionRep::masterxSharedValue(const libecap::Name &name) 
const
 {
     const HttpRequest *request = dynamic_cast<const HttpRequest*>(theCauseRep ?
                                  theCauseRep->raw().header : 
theVirginRep.raw().header);
     Must(request);
     if (name.known()) { // must check to avoid empty names matching unset cfg
         Adaptation::History::Pointer ah = request->adaptHistory(false);
         if (ah != NULL) {
             String name, value;
             if (ah->getXxRecord(name, value))
                 return libecap::Area::FromTempBuffer(value.rawBuf(), 
value.size());
         }

=== modified file 'src/adaptation/icap/ModXact.cc'
--- src/adaptation/icap/ModXact.cc      2013-11-11 12:09:44 +0000
+++ src/adaptation/icap/ModXact.cc      2013-11-22 14:37:06 +0000
@@ -1335,41 +1335,41 @@
     const Adaptation::ServiceConfig &s = service().cfg();
     buf.Printf("%s " SQUIDSTRINGPH " ICAP/1.0\r\n", s.methodStr(), 
SQUIDSTRINGPRINT(s.uri));
     buf.Printf("Host: " SQUIDSTRINGPH ":%d\r\n", SQUIDSTRINGPRINT(s.host), 
s.port);
     buf.Printf("Date: %s\r\n", mkrfc1123(squid_curtime));
 
     if (!TheConfig.reuse_connections)
         buf.Printf("Connection: close\r\n");
 
     const HttpRequest *request = &virginRequest();
 
     // we must forward "Proxy-Authenticate" and "Proxy-Authorization"
     // as ICAP headers.
     if (virgin.header->header.has(HDR_PROXY_AUTHENTICATE)) {
         String vh=virgin.header->header.getByName("Proxy-Authenticate");
         buf.Printf("Proxy-Authenticate: " SQUIDSTRINGPH 
"\r\n",SQUIDSTRINGPRINT(vh));
     }
 
     if (virgin.header->header.has(HDR_PROXY_AUTHORIZATION)) {
         String vh=virgin.header->header.getByName("Proxy-Authorization");
         buf.Printf("Proxy-Authorization: " SQUIDSTRINGPH "\r\n", 
SQUIDSTRINGPRINT(vh));
-    } else if (request->extacl_user.defined() && request->extacl_user.size() 
&& request->extacl_passwd.defined() && request->extacl_passwd.size()) {
+    } else if (request->extacl_user.size() > 0 && 
request->extacl_passwd.size() > 0) {
         char loginbuf[256];
         snprintf(loginbuf, sizeof(loginbuf), SQUIDSTRINGPH ":" SQUIDSTRINGPH,
                  SQUIDSTRINGPRINT(request->extacl_user),
                  SQUIDSTRINGPRINT(request->extacl_passwd));
         buf.Printf("Proxy-Authorization: Basic %s\r\n", 
old_base64_encode(loginbuf));
     }
 
     // share the cross-transactional database records if needed
     if (Adaptation::Config::masterx_shared_name) {
         Adaptation::History::Pointer ah = request->adaptHistory(false);
         if (ah != NULL) {
             String name, value;
             if (ah->getXxRecord(name, value)) {
                 buf.Printf(SQUIDSTRINGPH ": " SQUIDSTRINGPH "\r\n",
                            SQUIDSTRINGPRINT(name), SQUIDSTRINGPRINT(value));
             }
         }
     }
 
     buf.Printf("Encapsulated: ");
@@ -1492,41 +1492,41 @@
     else if (allow204out)
         allowHeader = "Allow: 204\r\n";
     else if (allow206)
         allowHeader = "Allow: 206\r\n";
 
     if (allowHeader) { // may be nil if only allow204in is true
         buf.append(allowHeader, strlen(allowHeader));
         debugs(93,5, HERE << "Will write " << allowHeader);
     }
 }
 
 void Adaptation::Icap::ModXact::makeUsernameHeader(const HttpRequest *request, 
MemBuf &buf)
 {
 #if USE_AUTH
     if (request->auth_user_request != NULL) {
         char const *name = request->auth_user_request->username();
         if (name) {
             const char *value = TheConfig.client_username_encode ? 
old_base64_encode(name) : name;
             buf.Printf("%s: %s\r\n", TheConfig.client_username_header, value);
         }
-    } else if (request->extacl_user.defined() && request->extacl_user.size()) {
+    } else if (request->extacl_user.size() > 0) {
         const char *value = TheConfig.client_username_encode ? 
old_base64_encode(request->extacl_user.termedBuf()) : 
request->extacl_user.termedBuf();
         buf.Printf("%s: %s\r\n", TheConfig.client_username_header, value);
     }
 #endif
 }
 
 void Adaptation::Icap::ModXact::encapsulateHead(MemBuf &icapBuf, const char 
*section, MemBuf &httpBuf, const HttpMsg *head)
 {
     // update ICAP header
     icapBuf.Printf("%s=%d, ", section, (int) httpBuf.contentSize());
 
     // begin cloning
     HttpMsg::Pointer headClone;
 
     if (const HttpRequest* old_request = dynamic_cast<const 
HttpRequest*>(head)) {
         HttpRequest::Pointer new_request(new HttpRequest);
         Must(old_request->canonical);
         urlParse(old_request->method, old_request->canonical, 
new_request.getRaw());
         new_request->http_ver = old_request->http_ver;
         headClone = new_request.getRaw();

=== modified file 'src/client_side.cc'
--- src/client_side.cc  2013-11-11 12:09:44 +0000
+++ src/client_side.cc  2013-11-22 14:51:16 +0000
@@ -3772,41 +3772,41 @@
     } else {
         Ssl::CrtdMessage reply_message(Ssl::CrtdMessage::REPLY);
         if (reply_message.parse(reply.other().content(), 
reply.other().contentSize()) != Ssl::CrtdMessage::OK) {
             debugs(33, 5, HERE << "Reply from ssl_crtd for " << 
sslConnectHostOrIp << " is incorrect");
         } else {
             if (reply.result != HelperReply::Okay) {
                 debugs(33, 5, HERE << "Certificate for " << sslConnectHostOrIp 
<< " cannot be generated. ssl_crtd response: " << reply_message.getBody());
             } else {
                 debugs(33, 5, HERE << "Certificate for " << sslConnectHostOrIp 
<< " was successfully recieved from ssl_crtd");
                 SSL_CTX *ctx = 
Ssl::generateSslContextUsingPkeyAndCertFromMemory(reply_message.getBody().c_str(),
 *port);
                 getSslContextDone(ctx, true);
                 return;
             }
         }
     }
     getSslContextDone(NULL);
 }
 
 void ConnStateData::buildSslCertGenerationParams(Ssl::CertificateProperties 
&certProperties)
 {
-    certProperties.commonName =  sslCommonName.defined() ? 
sslCommonName.termedBuf() : sslConnectHostOrIp.termedBuf();
+    certProperties.commonName =  sslCommonName.size() > 0 ? 
sslCommonName.termedBuf() : sslConnectHostOrIp.termedBuf();
 
     // fake certificate adaptation requires bump-server-first mode
     if (!sslServerBump) {
         assert(port->signingCert.get());
         certProperties.signWithX509.resetAndLock(port->signingCert.get());
         if (port->signPkey.get())
             certProperties.signWithPkey.resetAndLock(port->signPkey.get());
         certProperties.signAlgorithm = Ssl::algSignTrusted;
         return;
     }
 
     // In case of an error while connecting to the secure server, use a fake
     // trusted certificate, with no mimicked fields and no adaptation
     // algorithms. There is nothing we can mimic so we want to minimize the
     // number of warnings the user will have to see to get to the error page.
     assert(sslServerBump->entry);
     if (sslServerBump->entry->isEmpty()) {
         if (X509 *mimicCert = sslServerBump->serverCert.get())
             certProperties.mimicCert.resetAndLock(mimicCert);
 
@@ -3867,41 +3867,41 @@
         assert(port->signingCert.get());
         certProperties.signWithX509.resetAndLock(port->signingCert.get());
 
         if (port->signPkey.get())
             certProperties.signWithPkey.resetAndLock(port->signPkey.get());
     }
     signAlgorithm = certProperties.signAlgorithm;
 }
 
 void
 ConnStateData::getSslContextStart()
 {
     assert(areAllContextsForThisConnection());
     freeAllContexts();
     /* careful: freeAllContexts() above frees request, host, etc. */
 
     if (port->generateHostCertificates) {
         Ssl::CertificateProperties certProperties;
         buildSslCertGenerationParams(certProperties);
         sslBumpCertKey = certProperties.dbKey().c_str();
-        assert(sslBumpCertKey.defined() && sslBumpCertKey[0] != '\0');
+        assert(sslBumpCertKey.size() > 0 && sslBumpCertKey[0] != '\0');
 
         debugs(33, 5, HERE << "Finding SSL certificate for " << sslBumpCertKey 
<< " in cache");
         Ssl::LocalContextStorage & 
ssl_ctx_cache(Ssl::TheGlobalContextStorage.getLocalStorage(port->s));
         SSL_CTX * dynCtx = NULL;
         Ssl::SSL_CTX_Pointer *cachedCtx = 
ssl_ctx_cache.get(sslBumpCertKey.termedBuf());
         if (cachedCtx && (dynCtx = cachedCtx->get())) {
             debugs(33, 5, HERE << "SSL certificate for " << sslBumpCertKey << 
" have found in cache");
             if (Ssl::verifySslCertificate(dynCtx, certProperties)) {
                 debugs(33, 5, HERE << "Cached SSL certificate for " << 
sslBumpCertKey << " is valid");
                 getSslContextDone(dynCtx);
                 return;
             } else {
                 debugs(33, 5, HERE << "Cached SSL certificate for " << 
sslBumpCertKey << " is out of date. Delete this certificate from cache");
                 ssl_ctx_cache.del(sslBumpCertKey.termedBuf());
             }
         } else {
             debugs(33, 5, HERE << "SSL certificate for " << sslBumpCertKey << 
" haven't found in cache");
         }
 
 #if USE_SSL_CRTD
@@ -3934,41 +3934,41 @@
 ConnStateData::getSslContextDone(SSL_CTX * sslContext, bool isNew)
 {
     // Try to add generated ssl context to storage.
     if (port->generateHostCertificates && isNew) {
 
         if (signAlgorithm == Ssl::algSignTrusted) {
             // Add signing certificate to the certificates chain
             X509 *cert = port->signingCert.get();
             if (SSL_CTX_add_extra_chain_cert(sslContext, cert)) {
                 // increase the certificate lock
                 CRYPTO_add(&(cert->references),1,CRYPTO_LOCK_X509);
             } else {
                 const int ssl_error = ERR_get_error();
                 debugs(33, DBG_IMPORTANT, "WARNING: can not add signing 
certificate to SSL context chain: " << ERR_error_string(ssl_error, NULL));
             }
             Ssl::addChainToSslContext(sslContext, port->certsToChain.get());
         }
         //else it is self-signed or untrusted do not attrach any certificate
 
         Ssl::LocalContextStorage & 
ssl_ctx_cache(Ssl::TheGlobalContextStorage.getLocalStorage(port->s));
-        assert(sslBumpCertKey.defined() && sslBumpCertKey[0] != '\0');
+        assert(sslBumpCertKey.size() > 0 && sslBumpCertKey[0] != '\0');
         if (sslContext) {
             if (!ssl_ctx_cache.add(sslBumpCertKey.termedBuf(), new 
Ssl::SSL_CTX_Pointer(sslContext))) {
                 // If it is not in storage delete after using. Else storage 
deleted it.
                 fd_table[clientConnection->fd].dynamicSslContext = sslContext;
             }
         } else {
             debugs(33, 2, HERE << "Failed to generate SSL cert for " << 
sslConnectHostOrIp);
         }
     }
 
     // If generated ssl context = NULL, try to use static ssl context.
     if (!sslContext) {
         if (!port->staticSslContext) {
             debugs(83, DBG_IMPORTANT, "Closing SSL " << 
clientConnection->remote << " as lacking SSL context");
             clientConnection->close();
             return;
         } else {
             debugs(33, 5, HERE << "Using static ssl context.");
             sslContext = port->staticSslContext.get();
         }

=== modified file 'src/errorpage.cc'
--- src/errorpage.cc    2013-10-25 00:13:46 +0000
+++ src/errorpage.cc    2013-11-22 14:51:57 +0000
@@ -822,41 +822,41 @@
         break;
 
     case 'B':
         if (building_deny_info_url) break;
         p = request ? ftpUrlWith2f(request) : "[no URL]";
         break;
 
     case 'c':
         if (building_deny_info_url) break;
         p = errorPageName(type);
         break;
 
     case 'D':
         if (!allowRecursion)
             p = "%D";  // if recursion is not allowed, do not convert
 #if USE_SSL
         // currently only SSL error details implemented
         else if (detail) {
             detail->useRequest(request);
             const String &errDetail = detail->toString();
-            if (errDetail.defined()) {
+            if (errDetail.size() > 0) {
                 MemBuf *detail_mb  = ConvertText(errDetail.termedBuf(), false);
                 mb.append(detail_mb->content(), detail_mb->contentSize());
                 delete detail_mb;
                 do_quote = 0;
             }
         }
 #endif
         if (!mb.contentSize())
             mb.Printf("[No Error Detail]");
         break;
 
     case 'e':
         mb.Printf("%d", xerrno);
         break;
 
     case 'E':
         if (xerrno)
             mb.Printf("(%d) %s", xerrno, strerror(xerrno));
         else
             mb.Printf("[No Error]");

=== modified file 'src/http.cc'
--- src/http.cc 2013-11-18 15:55:05 +0000
+++ src/http.cc 2013-11-22 15:18:38 +0000
@@ -345,41 +345,41 @@
     // NP: reverse-proxy traffic our parent server has instructed us never to 
cache
     if (surrogateNoStore) {
         debugs(22, 3, HERE << "NO because Surrogate-Control:no-store");
         return 0;
     }
 
     // RFC 2616: HTTP/1.1 Cache-Control conditions
     if (!ignoreCacheControl) {
         // XXX: check to see if the request headers alone were enough to 
prevent caching earlier
         // (ie no-store request header) no need to check those all again here 
if so.
         // for now we are not reliably doing that so we waste CPU re-checking 
request CC
 
         // RFC 2616 section 14.9.2 - MUST NOT cache any response with request 
CC:no-store
         if (request && request->cache_control && 
request->cache_control->noStore() &&
                 !REFRESH_OVERRIDE(ignore_no_store)) {
             debugs(22, 3, HERE << "NO because client request 
Cache-Control:no-store");
             return 0;
         }
 
         // NP: request CC:no-cache only means cache READ is forbidden. STORE 
is permitted.
-        if (rep->cache_control && rep->cache_control->hasNoCache() && 
rep->cache_control->noCache().defined()) {
+        if (rep->cache_control && rep->cache_control->hasNoCache() && 
rep->cache_control->noCache().size() > 0) {
             /* TODO: we are allowed to cache when no-cache= has parameters.
              * Provided we strip away any of the listed headers unless they 
are revalidated
              * successfully (ie, must revalidate AND these headers are 
prohibited on stale replies).
              * That is a bit tricky for squid right now so we avoid caching 
entirely.
              */
             debugs(22, 3, HERE << "NO because server reply 
Cache-Control:no-cache has parameters");
             return 0;
         }
 
         // NP: request CC:private is undefined. We ignore.
         // NP: other request CC flags are limiters on HIT/MISS. We don't care 
about here.
 
         // RFC 2616 section 14.9.2 - MUST NOT cache any response with 
CC:no-store
         if (rep->cache_control && rep->cache_control->noStore() &&
                 !REFRESH_OVERRIDE(ignore_no_store)) {
             debugs(22, 3, HERE << "NO because server reply 
Cache-Control:no-store");
             return 0;
         }
 
         // RFC 2616 section 14.9.1 - MUST NOT cache any response with 
CC:private in a shared cache like Squid.
@@ -410,41 +410,41 @@
             debugs(22, 3, HERE << "NO because Authenticated and ignoring 
Cache-Control");
             return 0;
         }
 
         bool mayStore = false;
         // HTTPbis pt6 section 3.2: a response CC:public is present
         if (rep->cache_control->Public()) {
             debugs(22, 3, HERE << "Authenticated but server reply 
Cache-Control:public");
             mayStore = true;
 
             // HTTPbis pt6 section 3.2: a response CC:must-revalidate is 
present
         } else if (rep->cache_control->mustRevalidate() && 
!REFRESH_OVERRIDE(ignore_must_revalidate)) {
             debugs(22, 3, HERE << "Authenticated but server reply 
Cache-Control:public");
             mayStore = true;
 
 #if USE_HTTP_VIOLATIONS
             // NP: given the must-revalidate exception we should also be able 
to exempt no-cache.
             // HTTPbis WG verdict on this is that it is omitted from the spec 
due to being 'unexpected' by
             // some. The caching+revalidate is not exactly unsafe though with 
Squids interpretation of no-cache
             // (without parameters) as equivalent to must-revalidate in the 
reply.
-        } else if (rep->cache_control->hasNoCache() && 
!rep->cache_control->noCache().defined() && 
!REFRESH_OVERRIDE(ignore_must_revalidate)) {
+        } else if (rep->cache_control->hasNoCache() && 
rep->cache_control->noCache().size() > 0 && 
!REFRESH_OVERRIDE(ignore_must_revalidate)) {
             debugs(22, 3, HERE << "Authenticated but server reply 
Cache-Control:no-cache (equivalent to must-revalidate)");
             mayStore = true;
 #endif
 
             // HTTPbis pt6 section 3.2: a response CC:s-maxage is present
         } else if (rep->cache_control->sMaxAge()) {
             debugs(22, 3, HERE << "Authenticated but server reply 
Cache-Control:s-maxage");
             mayStore = true;
         }
 
         if (!mayStore) {
             debugs(22, 3, HERE << "NO because Authenticated transaction");
             return 0;
         }
 
         // NP: response CC:no-cache is equivalent to 
CC:must-revalidate,max-age=0. We MAY cache, and do so.
         // NP: other request CC flags are limiters on HIT/MISS/REFRESH. We 
don't care about here.
     }
 
     /* HACK: The "multipart/x-mixed-replace" content type is used for
@@ -1689,41 +1689,41 @@
                                       StoreEntry * entry,
                                       const AccessLogEntryPointer &al,
                                       HttpHeader * hdr_out,
                                       const HttpStateFlags &flags)
 {
     /* building buffer for complex strings */
 #define BBUF_SZ (MAX_URL+32)
     LOCAL_ARRAY(char, bbuf, BBUF_SZ);
     LOCAL_ARRAY(char, ntoabuf, MAX_IPSTRLEN);
     const HttpHeader *hdr_in = &request->header;
     const HttpHeaderEntry *e = NULL;
     HttpHeaderPos pos = HttpHeaderInitPos;
     assert (hdr_out->owner == hoRequest);
 
     /* use our IMS header if the cached entry has Last-Modified time */
     if (request->lastmod > -1)
         hdr_out->putTime(HDR_IF_MODIFIED_SINCE, request->lastmod);
 
     // Add our own If-None-Match field if the cached entry has a strong ETag.
     // copyOneHeaderFromClientsideRequestToUpstreamRequest() adds client ones.
-    if (request->etag.defined()) {
+    if (request->etag.size() > 0) {
         hdr_out->addEntry(new HttpHeaderEntry(HDR_IF_NONE_MATCH, NULL,
                                               request->etag.termedBuf()));
     }
 
     bool we_do_ranges = decideIfWeDoRanges (request);
 
     String strConnection (hdr_in->getList(HDR_CONNECTION));
 
     while ((e = hdr_in->getEntry(&pos)))
         copyOneHeaderFromClientsideRequestToUpstreamRequest(e, strConnection, 
request, hdr_out, we_do_ranges, flags);
 
     /* Abstraction break: We should interpret multipart/byterange responses
      * into offset-length data, and this works around our inability to do so.
      */
     if (!we_do_ranges && request->multipartRangeRequest()) {
         /* don't cache the result */
         request->flags.cachable = false;
         /* pretend it's not a range request */
         delete request->range;
         request->range = NULL;

=== modified file 'src/redirect.cc'
--- src/redirect.cc     2013-10-26 15:56:57 +0000
+++ src/redirect.cc     2013-11-22 14:37:53 +0000
@@ -242,42 +242,41 @@
     Http::StatusCode status;
     char claddr[MAX_IPSTRLEN];
     char myaddr[MAX_IPSTRLEN];
 
     /** TODO: create a standalone method to initialize
      * the RedirectStateData for all the helpers.
      */
     RedirectStateData *r = new RedirectStateData(http->uri);
     if (conn != NULL)
         r->client_addr = conn->log_addr;
     else
         r->client_addr.setNoAddr();
     r->client_ident = NULL;
 #if USE_AUTH
     if (http->request->auth_user_request != NULL) {
         r->client_ident = http->request->auth_user_request->username();
         debugs(61, 5, HERE << "auth-user=" << 
(r->client_ident?r->client_ident:"NULL"));
     }
 #endif
 
-    // HttpRequest initializes with null_string. So we must check both 
defined() and size()
-    if (!r->client_ident && http->request->extacl_user.defined() && 
http->request->extacl_user.size()) {
+    if (!r->client_ident && http->request->extacl_user.size() > 0) {
         r->client_ident = http->request->extacl_user.termedBuf();
         debugs(61, 5, HERE << "acl-user=" << 
(r->client_ident?r->client_ident:"NULL"));
     }
 
     if (!r->client_ident && conn != NULL && conn->clientConnection != NULL && 
conn->clientConnection->rfc931[0]) {
         r->client_ident = conn->clientConnection->rfc931;
         debugs(61, 5, HERE << "ident-user=" << 
(r->client_ident?r->client_ident:"NULL"));
     }
 
 #if USE_SSL
 
     if (!r->client_ident && conn != NULL && 
Comm::IsConnOpen(conn->clientConnection)) {
         r->client_ident = 
sslGetUserEmail(fd_table[conn->clientConnection->fd].ssl);
         debugs(61, 5, HERE << "ssl-user=" << 
(r->client_ident?r->client_ident:"NULL"));
     }
 #endif
 
     if (!r->client_ident)
         r->client_ident = dash_str;
 

=== modified file 'src/ssl/ErrorDetail.cc'
--- src/ssl/ErrorDetail.cc      2013-11-07 10:46:14 +0000
+++ src/ssl/ErrorDetail.cc      2013-11-22 14:53:40 +0000
@@ -387,41 +387,41 @@
 /**
  * The subject of the current certification in text form
  */
 const char  *Ssl::ErrorDetail::subject() const
 {
     if (!broken_cert)
         return "[Not available]";
 
     static char tmpBuffer[256]; // A temporary buffer
     X509_NAME_oneline(X509_get_subject_name(broken_cert.get()), tmpBuffer,
                       sizeof(tmpBuffer));
     return tmpBuffer;
 }
 
 // helper function to be used with Ssl::matchX509CommonNames
 static int copy_cn(void *check_data,  ASN1_STRING *cn_data)
 {
     String *str = (String *)check_data;
     if (!str) // no data? abort
         return 0;
-    if (str->defined())
+    if (str->size() > 0)
         str->append(", ");
     str->append((const char *)cn_data->data, cn_data->length);
     return 1;
 }
 
 /**
  * The list with certificates cn and alternate names
  */
 const char *Ssl::ErrorDetail::cn() const
 {
     if (!broken_cert)
         return "[Not available]";
 
     static String tmpStr;  ///< A temporary string buffer
     tmpStr.clean();
     Ssl::matchX509CommonNames(broken_cert.get(), &tmpStr, copy_cn);
     return tmpStr.termedBuf();
 }
 
 /**
@@ -484,41 +484,41 @@
         snprintf(tmpBuffer, 64, "%d", (int)error_no);
         err = tmpBuffer;
     }
     return err;
 }
 
 /**
  * A short description of the error_no
  */
 const char *Ssl::ErrorDetail::err_descr() const
 {
     if (error_no == SSL_ERROR_NONE)
         return "[No Error]";
     if (const char *err = detailEntry.descr.termedBuf())
         return err;
     return "[Not available]";
 }
 
 const char *Ssl::ErrorDetail::err_lib_error() const
 {
-    if (errReason.defined())
+    if (errReason.size() > 0)
         return errReason.termedBuf();
     else if (lib_error_no != SSL_ERROR_NONE)
         return ERR_error_string(lib_error_no, NULL);
     else
         return "[No Error]";
 }
 
 /**
  * Converts the code to a string value. Supported formating codes are:
  *
  * Error meta information:
  * %err_name: The name of a high-level SSL error (e.g., X509_V_ERR_*)
  * %ssl_error_descr: A short description of the SSL error
  * %ssl_lib_error: human-readable low-level error string by 
ERR_error_string(3SSL)
  *
  * Certificate information extracted from broken (not necessarily peer!) cert
  * %ssl_cn: The comma-separated list of common and alternate names
  * %ssl_subject: The certificate subject
  * %ssl_ca_name: The certificate issuer name
  * %ssl_notbefore: The certificate "not before" field
@@ -557,41 +557,41 @@
         s = detailEntry.detail.termedBuf();
 
     if (!s)
         s = SslErrorDetailDefaultStr;
 
     assert(s);
     while ((p = strchr(s, '%'))) {
         errDetailStr.append(s, p - s);
         code_len = convert(++p, &t);
         if (code_len)
             errDetailStr.append(t);
         else
             errDetailStr.append("%");
         s = p + code_len;
     }
     errDetailStr.append(s, strlen(s));
 }
 
 const String &Ssl::ErrorDetail::toString() const
 {
-    if (!errDetailStr.defined())
+    if (errDetailStr.size() == 0)
         buildDetail();
     return errDetailStr;
 }
 
 Ssl::ErrorDetail::ErrorDetail( Ssl::ssl_error_t err_no, X509 *cert, X509 
*broken, const char *aReason): error_no (err_no), lib_error_no(SSL_ERROR_NONE), 
errReason(aReason)
 {
     if (cert)
         peer_cert.resetAndLock(cert);
 
     if (broken)
         broken_cert.resetAndLock(broken);
     else
         broken_cert.resetAndLock(cert);
 
     detailEntry.error_no = SSL_ERROR_NONE;
 }
 
 Ssl::ErrorDetail::ErrorDetail(Ssl::ErrorDetail const &anErrDetail)
 {
     error_no = anErrDetail.error_no;

=== modified file 'src/ssl/ErrorDetailManager.cc'
--- src/ssl/ErrorDetailManager.cc       2013-11-07 10:46:14 +0000
+++ src/ssl/ErrorDetailManager.cc       2013-11-22 15:00:34 +0000
@@ -213,44 +213,43 @@
             const String errorName = parser.getByName("name");
             if (!errorName.size()) {
                 debugs(83, DBG_IMPORTANT, HERE <<
                        "WARNING! invalid or no error detail name on:" << s);
                 return false;
             }
 
             Ssl::ssl_error_t ssl_error = 
Ssl::GetErrorCode(errorName.termedBuf());
             if (ssl_error != SSL_ERROR_NONE) {
 
                 if (theDetails->getErrorDetail(ssl_error)) {
                     debugs(83, DBG_IMPORTANT, HERE <<
                            "WARNING! duplicate entry: " << errorName);
                     return false;
                 }
 
                 ErrorDetailEntry &entry = theDetails->theList[ssl_error];
                 entry.error_no = ssl_error;
                 entry.name = errorName;
                 String tmp = parser.getByName("detail");
-                httpHeaderParseQuotedString(tmp.termedBuf(), tmp.size(), 
&entry.detail);
+                int detailsParseOk = 
httpHeaderParseQuotedString(tmp.termedBuf(), tmp.size(), &entry.detail);
                 tmp = parser.getByName("descr");
-                httpHeaderParseQuotedString(tmp.termedBuf(), tmp.size(), 
&entry.descr);
-                bool parseOK = entry.descr.defined() && entry.detail.defined();
+                int descrParseOk = 
httpHeaderParseQuotedString(tmp.termedBuf(), tmp.size(), &entry.descr);
 
-                if (!parseOK) {
+                if (!detailsParseOk || !descrParseOk) {
                     debugs(83, DBG_IMPORTANT, HERE <<
                            "WARNING! missing important field for detail error: 
" <<  errorName);
                     return false;
                 }
 
             } else if (!Ssl::ErrorIsOptional(errorName.termedBuf())) {
                 debugs(83, DBG_IMPORTANT, HERE <<
                        "WARNING! invalid error detail name: " << errorName);
                 return false;
             }
 
         }// else {only spaces and black lines; just ignore}
 
         buf.consume(size);
     }
     debugs(83, 9, HERE << " Remain size: " << buf.contentSize() << " Content: 
" << buf.content());
     return true;
 }

=== modified file 'src/stat.cc'
--- src/stat.cc 2013-10-25 00:13:46 +0000
+++ src/stat.cc 2013-11-22 14:56:52 +0000
@@ -2033,41 +2033,41 @@
             storeAppendPrintf(s, "\tnrequests: %d\n",
                               conn->nrequests);
         }
 
         storeAppendPrintf(s, "uri %s\n", http->uri);
         storeAppendPrintf(s, "logType %s\n", LogTags_str[http->logType]);
         storeAppendPrintf(s, "out.offset %ld, out.size %lu\n",
                           (long int) http->out.offset, (unsigned long int) 
http->out.size);
         storeAppendPrintf(s, "req_sz %ld\n", (long int) http->req_sz);
         e = http->storeEntry();
         storeAppendPrintf(s, "entry %p/%s\n", e, e ? e->getMD5Text() : "N/A");
         storeAppendPrintf(s, "start %ld.%06d (%f seconds ago)\n",
                           (long int) http->start_time.tv_sec,
                           (int) http->start_time.tv_usec,
                           tvSubDsec(http->start_time, current_time));
 #if USE_AUTH
         if (http->request->auth_user_request != NULL)
             p = http->request->auth_user_request->username();
         else
 #endif
-            if (http->request->extacl_user.defined()) {
+            if (http->request->extacl_user.size() > 0) {
                 p = http->request->extacl_user.termedBuf();
             }
 
         if (!p && conn != NULL && conn->clientConnection->rfc931[0])
             p = conn->clientConnection->rfc931;
 
 #if USE_SSL
 
         if (!p && conn != NULL && Comm::IsConnOpen(conn->clientConnection))
             p = sslGetUserEmail(fd_table[conn->clientConnection->fd].ssl);
 
 #endif
 
         if (!p)
             p = dash_str;
 
         storeAppendPrintf(s, "username %s\n", p);
 
 #if USE_DELAY_POOLS
         storeAppendPrintf(s, "delay_pool %d\n", 
DelayId::DelayClient(http).pool());

=== modified file 'src/store.cc'
--- src/store.cc        2013-10-25 00:13:46 +0000
+++ src/store.cc        2013-11-22 14:57:10 +0000
@@ -771,41 +771,41 @@
         // TODO: storeGetPublic() calls below may create unlocked entries.
         // We should add/use storeHas() API or lock/unlock those entries.
         if (mem_obj->vary_headers && !storeGetPublic(mem_obj->url, 
mem_obj->method)) {
             /* Create "vary" base object */
             String vary;
             StoreEntry *pe = storeCreateEntry(mem_obj->url, mem_obj->log_url, 
request->flags, request->method);
             /* We are allowed to do this typecast */
             HttpReply *rep = new HttpReply;
             rep->setHeaders(Http::scOkay, "Internal marker object", 
"x-squid-internal/vary", -1, -1, squid_curtime + 100000);
             vary = mem_obj->getReply()->header.getList(HDR_VARY);
 
             if (vary.size()) {
                 /* Again, we own this structure layout */
                 rep->header.putStr(HDR_VARY, vary.termedBuf());
                 vary.clean();
             }
 
 #if X_ACCELERATOR_VARY
             vary = mem_obj->getReply()->header.getList(HDR_X_ACCELERATOR_VARY);
 
-            if (vary.defined()) {
+            if (vary.size() > 0) {
                 /* Again, we own this structure layout */
                 rep->header.putStr(HDR_X_ACCELERATOR_VARY, vary.termedBuf());
                 vary.clean();
             }
 
 #endif
             pe->replaceHttpReply(rep);
 
             pe->timestampsSet();
 
             pe->makePublic();
 
             pe->complete();
 
             pe->unlock();
         }
 
         newkey = storeKeyPublicByRequest(mem_obj->request);
     } else
         newkey = storeKeyPublic(mem_obj->url, mem_obj->method);

Reply via email to