=== modified file 'configure.ac'
--- configure.ac	2012-10-12 12:25:08 +0000
+++ configure.ac	2012-10-16 06:15:53 +0000
@@ -3565,6 +3565,7 @@
 	src/esi/Makefile \
 	src/eui/Makefile \
 	src/format/Makefile \
+	src/http/Makefile \
 	src/icmp/Makefile \
 	src/ident/Makefile \
 	src/ip/Makefile \

=== modified file 'src/AccessLogEntry.h'
--- src/AccessLogEntry.h	2012-09-21 14:57:30 +0000
+++ src/AccessLogEntry.h	2012-10-09 04:39:01 +0000
@@ -81,7 +81,7 @@
     {
 
     public:
-        HttpDetails() : method(METHOD_NONE), code(0), content_type(NULL),
+        HttpDetails() : method(Http::METHOD_NONE), code(0), content_type(NULL),
                 timedout(false), aborted(false) {}
 
         HttpRequestMethod method;

=== modified file 'src/HttpReply.cc'
--- src/HttpReply.cc	2012-09-25 15:36:18 +0000
+++ src/HttpReply.cc	2012-10-09 04:39:01 +0000
@@ -428,7 +428,7 @@
 {
     if (sline.version.major < 1)
         return -1;
-    else if (method.id() == METHOD_HEAD)
+    else if (method.id() == Http::METHOD_HEAD)
         return 0;
     else if (sline.status == HTTP_OK)
         (void) 0;		/* common case, continue */
@@ -532,7 +532,7 @@
 {
     bool expectBody = true;
 
-    if (req_method == METHOD_HEAD)
+    if (req_method == Http::METHOD_HEAD)
         expectBody = false;
     else if (sline.status == HTTP_NO_CONTENT)
         expectBody = false;

=== modified file 'src/HttpRequest.cc'
--- src/HttpRequest.cc	2012-09-25 15:36:18 +0000
+++ src/HttpRequest.cc	2012-10-09 04:39:01 +0000
@@ -87,7 +87,7 @@
 void
 HttpRequest::init()
 {
-    method = METHOD_NONE;
+    method = Http::METHOD_NONE;
     protocol = AnyP::PROTO_NONE;
     urlpath = NULL;
     login[0] = '\0';
@@ -293,7 +293,7 @@
     }
 
     /* See if the request buffer starts with a known HTTP request method. */
-    if (HttpRequestMethod(buf->content(),NULL) == METHOD_NONE) {
+    if (HttpRequestMethod(buf->content(),NULL) == Http::METHOD_NONE) {
         debugs(73, 3, "HttpRequest::sanityCheckStartLine: did not find HTTP request method");
         *error = HTTP_INVALID_HEADER;
         return false;
@@ -308,7 +308,7 @@
     const char *t = start + strcspn(start, w_space);
     method = HttpRequestMethod(start, t);
 
-    if (method == METHOD_NONE)
+    if (method == Http::METHOD_NONE)
         return false;
 
     start = t + strspn(t, w_space);
@@ -568,15 +568,15 @@
 HttpRequest *
 HttpRequest::CreateFromUrl(char * url)
 {
-    return urlParse(METHOD_GET, url, NULL);
+    return urlParse(Http::METHOD_GET, url, NULL);
 }
 
-/*
+/**
  * Are responses to this request possible cacheable ?
  * If false then no matter what the response must not be cached.
  */
 bool
-HttpRequest::cacheable() const
+HttpRequest::maybeCacheable()
 {
     // Intercepted request with Host: header which cannot be trusted.
     // Because it failed verification, or someone bypassed the security tests
@@ -585,26 +585,28 @@
     if (!flags.hostVerified && (flags.intercepted || flags.spoofClientIp))
         return false;
 
-    if (protocol == AnyP::PROTO_HTTP)
-        return httpCachable(method);
-
-    /*
-     * The below looks questionable: what non HTTP protocols use connect,
-     * trace, put and post? RC
-     */
-
-    if (!method.isCacheble())
-        return false;
-
-    /*
-     * XXX POST may be cached sometimes.. ignored
-     * for now
-     */
-    if (protocol == AnyP::PROTO_GOPHER)
-        return gopherCachable(this);
-
-    if (protocol == AnyP::PROTO_CACHE_OBJECT)
-        return false;
+    switch(protocol)
+    {
+    case AnyP::PROTO_HTTP:
+        if (!method.respMaybeCacheable())
+            return false;
+
+        // XXX: this would seem the correct place to detect request cache-controls
+        //      no-store, private and related which block cacheability
+        break;
+
+    case AnyP::PROTO_GOPHER:
+        if (!gopherCachable(this))
+            return false;
+        break;
+
+    case AnyP::PROTO_CACHE_OBJECT:
+        return false;
+
+    //case AnyP::PROTO_FTP:
+    default:
+        break;
+    }
 
     return true;
 }

=== modified file 'src/HttpRequest.h'
--- src/HttpRequest.h	2012-10-04 09:14:06 +0000
+++ src/HttpRequest.h	2012-10-09 04:39:01 +0000
@@ -82,8 +82,10 @@
 
     virtual HttpRequest *clone() const;
 
-    /* are responses to this request potentially cachable */
-    bool cacheable() const;
+    /// Whether response to this request is potentially cachable
+    /// \retval false  Not cacheable.
+    /// \retval true   Possibly cacheable. Response factors will determine.
+    bool maybeCacheable();
 
     bool conditional() const; ///< has at least one recognized If-* header
 

=== modified file 'src/HttpRequestMethod.cc'
--- src/HttpRequestMethod.cc	2012-09-01 14:38:36 +0000
+++ src/HttpRequestMethod.cc	2012-10-09 04:41:25 +0000
@@ -1,89 +1,25 @@
-
 /*
  * DEBUG: section 73    HTTP Request
- * AUTHOR: Duane Wessels
- *
- * 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.
- *
- * Copyright (c) 2003, Robert Collins <robertc@squid-cache.org>
  */
 
 #include "squid.h"
 #include "HttpRequestMethod.h"
 #include "wordlist.h"
 
-const char* HttpRequestMethod::RequestMethodStr[] = {
-    "NONE",
-    "GET",
-    "POST",
-    "PUT",
-    "HEAD",
-    "CONNECT",
-    "TRACE",
-    "PURGE",
-    "OPTIONS",
-    "DELETE",
-    "PROPFIND",
-    "PROPPATCH",
-    "MKCOL",
-    "COPY",
-    "MOVE",
-    "LOCK",
-    "UNLOCK",
-    "BMOVE",
-    "BDELETE",
-    "BPROPFIND",
-    "BPROPPATCH",
-    "BCOPY",
-    "SEARCH",
-    "SUBSCRIBE",
-    "UNSUBSCRIBE",
-    "POLL",
-    "REPORT",
-    "MKACTIVITY",
-    "CHECKOUT",
-    "MERGE",
-    "ERROR"
-};
-
-static
-_method_t &operator++ (_method_t &aMethod)
+static Http::MethodType &
+operator++ (Http::MethodType &aMethod)
 {
     int tmp = (int)aMethod;
-    aMethod = (_method_t)(++tmp);
+    aMethod = (Http::MethodType)(++tmp);
     return aMethod;
 }
 
-/*
+/**
  * Construct a HttpRequestMethod from a NULL terminated string such as "GET"
  * or from a range of chars, * such as "GET" from "GETFOOBARBAZ"
  * (pass in pointer to G and pointer to F.)
  */
-HttpRequestMethod::HttpRequestMethod(char const *begin, char const *end) : theMethod (METHOD_NONE)
+HttpRequestMethod::HttpRequestMethod(char const *begin, char const *end) : theMethod (Http::METHOD_NONE)
 {
     if (begin == NULL)
         return;
@@ -106,73 +42,26 @@
         end = begin + strcspn(begin, w_space);
 
     if (end == begin) {
-        theMethod = METHOD_NONE;
+        theMethod = Http::METHOD_NONE;
         return;
     }
 
-    for (++theMethod; theMethod < METHOD_ENUM_END; ++theMethod) {
-        if (0 == strncasecmp(begin, RequestMethodStr[theMethod], end-begin)) {
+    for (++theMethod; theMethod < Http::METHOD_ENUM_END; ++theMethod) {
+        if (0 == strncasecmp(begin, Http::MethodType_str[theMethod], end-begin)) {
             return;
         }
     }
 
     // if method not found and method string is not null then it is other method
-    theMethod = METHOD_OTHER;
+    theMethod = Http::METHOD_OTHER;
     theImage.limitInit(begin,end-begin);
 }
 
-/** \todo AYJ: this _should_ be obsolete. Since all such methods fit nicely into METHOD_OTHER now. */
-void
-HttpRequestMethod::AddExtension(const char *mstr)
-{
-#if 0 /* obsolete now that we have METHOD_OTHER always enabled */
-    _method_t method = METHOD_NONE;
-
-    for (++method; method < METHOD_ENUM_END; ++method) {
-        if (0 == strcmp(mstr, RequestMethodStr[method])) {
-            debugs(23, 2, "Extension method '" << mstr << "' already exists");
-            return;
-        }
-
-        if (0 != strncmp("%EXT", RequestMethodStr[method], 4))
-            continue;
-
-        /* Don't free statically allocated "%EXTnn" string */
-        RequestMethodStr[method] = xstrdup(mstr);
-
-        debugs(23, DBG_IMPORTANT, "Extension method '" << mstr << "' added, enum=" << method);
-
-        return;
-    }
-
-    debugs(23, DBG_IMPORTANT, "WARNING: Could not add new extension method '" << mstr << "' due to lack of array space");
-#endif
-}
-
-void
-HttpRequestMethod::Configure(SquidConfig &cfg)
-{
-#if 0 /* extension methods obsolete now that we have METHOD_OTHER always enabled */
-    wordlist *w = cfg.ext_methods;
-
-    while (w) {
-        char *s;
-
-        for (s = w->key; *s; ++s)
-            *s = xtoupper(*s);
-
-        AddExtension(w->key);
-
-        w = w->next;
-    }
-#endif
-}
-
 char const*
 HttpRequestMethod::image() const
 {
-    if (METHOD_OTHER != theMethod) {
-        return RequestMethodStr[theMethod];
+    if (Http::METHOD_OTHER != theMethod) {
+        return Http::MethodType_str[theMethod];
     } else {
         if (theImage.size()>0) {
             return theImage.termedBuf();
@@ -183,60 +72,163 @@
 }
 
 bool
-HttpRequestMethod::isCacheble() const
-{
-    // TODO: optimize the lookup with a precomputed flags array
-    // XXX: the list seems wrong; e.g., Is METHOD_DELETE really cachable?
-    // see also http.cc::httpCachable()
-
-    if (theMethod == METHOD_CONNECT)
-        return false;
-
-    if (theMethod == METHOD_TRACE)
-        return false;
-
-    if (theMethod == METHOD_PUT)
-        return false;
-
-    if (theMethod == METHOD_POST)
-        return false;
-
-    if (theMethod == METHOD_OTHER)
-        return false;
-
-    return true;
-}
-
-bool
-HttpRequestMethod::purgesOthers() const
-{
-    // TODO: optimize the lookup with a precomputed flags array
-
+HttpRequestMethod::isHttpSafe() const
+{
+    // Only a few methods are defined as safe. All others are "unsafe"
+
+    // NOTE:
+    // All known RFCs which register methods are listed in comments.
+    // if there is one not listed which defines methods, it needs 
+    // checking and adding. If only to say it is known to define none.
+
+    switch(theMethod)
+    {
+        // RFC 2068 - none
+
+        // RFC 2616 section 9.1.1
+    case Http::METHOD_GET:
+    case Http::METHOD_HEAD:
+    case Http::METHOD_OPTIONS:
+
+        // RFC 3253 section 3.6
+    case Http::METHOD_REPORT:
+
+        // RFC 3648 - none
+        // RFC 3744 - none
+        // RFC 4437 - none
+        // RFC 4791 - none
+
+        // RFC 4918 section 9.1
+    case Http::METHOD_PROPFIND:
+
+        // RFC 5323 section 2
+    case Http::METHOD_SEARCH:
+
+        // RFC 5789 - none
+        // RFC 5842 - none
+
+        return true;
+
+    default:
+        return false;
+    }
+}
+
+bool
+HttpRequestMethod::isIdempotent() const
+{
+    // Only a few methods are defined as idempotent.
+
+    // NOTE:
+    // All known RFCs which register methods are listed in comments.
+    // if there is one not listed which defines methods, it needs 
+    // checking and adding. If only to say it is known to define none.
+
+    switch(theMethod)
+    {
+        // RFC 2068 - TODO check LINK/UNLINK definition
+
+        // RFC 2616 section 9.1.2
+    case Http::METHOD_GET:
+    case Http::METHOD_HEAD:
+    case Http::METHOD_PUT:
+    case Http::METHOD_DELETE:
+    case Http::METHOD_OPTIONS:
+    case Http::METHOD_TRACE:
+
+        // RFC 3253 - TODO check
+        // RFC 3648 - TODO check
+        // RFC 3744 - TODO check
+        // RFC 4437 - TODO check
+        // RFC 4791 - TODO check
+
+        // RFC 4918 section 9
+    case Http::METHOD_PROPFIND:
+    case Http::METHOD_PROPPATCH:
+    case Http::METHOD_MKCOL:
+    case Http::METHOD_COPY:
+    case Http::METHOD_MOVE:
+    case Http::METHOD_UNLOCK:
+
+        // RFC 5323 - TODO check
+        // RFC 5789 - TODO check
+        // RFC 5842 - TODO check
+
+        return true;
+
+    default:
+        return false;
+    }
+}
+
+bool
+HttpRequestMethod::respMaybeCacheable() const
+{
+    // Only a few methods are defined as cacheable.
+    // All other methods from the below RFC are "MUST NOT cache"
+    switch(theMethod)
+    {
+        // RFC 2616 section 9
+    case Http::METHOD_GET:
+    case Http::METHOD_HEAD:
+        return true;
+#if WHEN_POST_CACHE_SUPPORTED
+    case Http::METHOD_POST: // Special case.
+        // RFC 2616 specifies POST as possibly cacheable
+        // However, Squid does not implement the required checks yet
+        return true;
+#endif
+
+        // RFC 4918 section 9
+#if WHEN_PROPFIND_CACHE_SUPPORTED
+    case Http::METHOD_PROPFIND: // Special case.
+        // RFC 4918 specifies PROPFIND as possibly cacheable
+        // However, Squid does not implement the required checks yet
+        return true;
+#endif
+
+        // RFC 5323 section 2 - defines no cacheable methods
+
+        // RFC 3253
+#if WHEN_CC_NOCACHE_DOES_REVALIDATES_IS_CONFIRMED
+    case Http::METHOD_CHECKOUT:
+    case Http::METHOD_CHECKIN:
+    case Http::METHOD_UNCHECKOUT:
+    case Http::METHOD_MKWORKSPACE:
+    case Http::METHOD_VERSION_CONTROL:
+    case Http::METHOD_UPDATE:
+    case Http::METHOD_LABEL:
+    case Http::METHOD_MERGE:
+    case Http::METHOD_BASELINE_CONTROL:
+    case Http::METHOD_MKACTIVITY:
+        // RFC 3253 defines these methods using "MUST include Cache-Control: no-cache".
+        //
+        // XXX: follow RFC 2616 definition of "no-cache" meaning "MAY cache, always revalidate"
+        // XXX: or treat as unregistered/undefined methods ??
+        // However, Squid may not implement the required revalidation checks yet
+        return ??;
+#endif
+
+        // Special Squid method tokens are not cacheable.
+        // RFC 2616 defines all unregistered or unspecified methods as non-cacheable
+        // until such time as an RFC defines them cacheable.
+    default:
+        return false;
+    }
+}
+
+bool
+HttpRequestMethod::shouldInvalidate() const
+{
     switch (theMethod) {
-        /* common sense suggests purging is not required? */
-    case METHOD_GET:     // XXX: but we do purge HEAD on successful GET
-    case METHOD_HEAD:
-    case METHOD_NONE:
-    case METHOD_CONNECT:
-    case METHOD_TRACE:
-    case METHOD_OPTIONS:
-    case METHOD_PROPFIND:
-    case METHOD_BPROPFIND:
-    case METHOD_COPY:
-    case METHOD_BCOPY:
-    case METHOD_LOCK:
-    case METHOD_UNLOCK:
-    case METHOD_SEARCH:
-        return false;
-
-        /* purging mandated by RFC 2616 */
-    case METHOD_POST:
-    case METHOD_PUT:
-    case METHOD_DELETE:
+        /* RFC 2616 section 13.10 - "MUST invalidate" */
+    case Http::METHOD_POST:
+    case Http::METHOD_PUT:
+    case Http::METHOD_DELETE:
         return true;
 
-        /* purging suggested by common sense */
-    case METHOD_PURGE:
+        /* Squid extension to force invalidation */
+    case Http::METHOD_PURGE:
         return true;
 
         /*
@@ -245,10 +237,37 @@
          * understand SHOULD invalidate any entities referred to by the
          * Request-URI.
          */
-    case METHOD_OTHER:
-    default:
-        return true;
-    }
-
-    return true; // not reached, but just in case
+    case Http::METHOD_OTHER:
+        return true;
+
+    default:
+        // Methods which are known but not required to invalidate.
+        return false;
+    }
+}
+
+bool
+HttpRequestMethod::purgesOthers() const
+{
+    if (shouldInvalidate())
+        return true;
+
+    switch (theMethod) {
+        /* common sense suggests purging is not required? */
+    case Http::METHOD_GET:     // XXX: but we do purge HEAD on successful GET
+    case Http::METHOD_HEAD:
+    case Http::METHOD_NONE:
+    case Http::METHOD_CONNECT:
+    case Http::METHOD_TRACE:
+    case Http::METHOD_OPTIONS:
+    case Http::METHOD_PROPFIND:
+    case Http::METHOD_COPY:
+    case Http::METHOD_LOCK:
+    case Http::METHOD_UNLOCK:
+    case Http::METHOD_SEARCH:
+        return false;
+
+    default:
+        return true;
+    }
 }

=== modified file 'src/HttpRequestMethod.h'
--- src/HttpRequestMethod.h	2012-09-23 09:04:21 +0000
+++ src/HttpRequestMethod.h	2012-10-09 04:41:42 +0000
@@ -1,94 +1,29 @@
-/*
- *
- * 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_HTTPREQUESTMETHOD_H
 #define SQUID_HTTPREQUESTMETHOD_H
 
+#include "http/MethodType.h"
+#include "SquidString.h"
 #include "SquidString.h"
 
 class SquidConfig;
 
 #include <iosfwd>
 
-enum _method_t {
-    METHOD_NONE,		/* 000 */
-    METHOD_GET,			/* 001 */
-    METHOD_POST,		/* 010 */
-    METHOD_PUT,			/* 011 */
-    METHOD_HEAD,		/* 100 */
-    METHOD_CONNECT,		/* 101 */
-    METHOD_TRACE,		/* 110 */
-    METHOD_PURGE,		/* 111 */
-    METHOD_OPTIONS,
-    METHOD_DELETE,		/* RFC2616 section 9.7 */
-    METHOD_PROPFIND,
-    METHOD_PROPPATCH,
-    METHOD_MKCOL,
-    METHOD_COPY,
-    METHOD_MOVE,
-    METHOD_LOCK,
-    METHOD_UNLOCK,
-    METHOD_BMOVE,
-    METHOD_BDELETE,
-    METHOD_BPROPFIND,
-    METHOD_BPROPPATCH,
-    METHOD_BCOPY,
-    METHOD_SEARCH,
-    METHOD_SUBSCRIBE,
-    METHOD_UNSUBSCRIBE,
-    METHOD_POLL,
-    METHOD_REPORT,
-    METHOD_MKACTIVITY,
-    METHOD_CHECKOUT,
-    METHOD_MERGE,
-    METHOD_OTHER,
-    METHOD_ENUM_END  // MUST be last, (yuck) this is used as an array-initialization index constant!
-};
-
 /**
  * This class represents an HTTP Request METHOD
  * - i.e. PUT, POST, GET etc.
  * It has a runtime extension facility to allow it to
  * efficiently support new methods
- \ingroup POD
  */
 class HttpRequestMethod
 {
 
 public:
-    static void AddExtension(const char *methodString);
-    static void Configure(SquidConfig &Config);
-
-    HttpRequestMethod() : theMethod(METHOD_NONE), theImage() {}
-
-    HttpRequestMethod(_method_t const aMethod) : theMethod(aMethod), theImage() {}
+//    static void Configure(SquidConfig &Config);
+
+    HttpRequestMethod() : theMethod(Http::METHOD_NONE), theImage() {}
+
+    HttpRequestMethod(Http::MethodType const aMethod) : theMethod(aMethod), theImage() {}
 
     /**
      \param begin    string to convert to request method.
@@ -104,19 +39,19 @@
         return *this;
     }
 
-    HttpRequestMethod & operator = (_method_t const aMethod) {
+    HttpRequestMethod & operator = (Http::MethodType const aMethod) {
         theMethod = aMethod;
         theImage.clean();
         return *this;
     }
 
-    bool operator == (_method_t const & aMethod) const { return theMethod == aMethod; }
+    bool operator == (Http::MethodType const & aMethod) const { return theMethod == aMethod; }
     bool operator == (HttpRequestMethod const & aMethod) const {
         return theMethod == aMethod.theMethod &&
-               (theMethod != METHOD_OTHER || theImage == aMethod.theImage);
+               (theMethod != Http::METHOD_OTHER || theImage == aMethod.theImage);
     }
 
-    bool operator != (_method_t const & aMethod) const { return theMethod != aMethod; }
+    bool operator != (Http::MethodType const & aMethod) const { return theMethod != aMethod; }
     bool operator != (HttpRequestMethod const & aMethod) const {
         return !operator==(aMethod);
     }
@@ -125,30 +60,62 @@
     HttpRequestMethod& operator++() {
         // TODO: when this operator is used in more than one place,
         // replace it with HttpRequestMethods::Iterator API
-        // XXX: this interface can create METHOD_OTHER without an image
-        assert(theMethod < METHOD_ENUM_END);
-        theMethod = (_method_t)(1 + (int)theMethod);
+        // XXX: this interface can create Http::METHOD_OTHER without an image
+        assert(theMethod < Http::METHOD_ENUM_END);
+        theMethod = (Http::MethodType)(1 + (int)theMethod);
         return *this;
     }
 
     /** Get an ID representation of the method.
-     \retval METHOD_NONE   the method is unset
-     \retval METHOD_OTHER  the method is not recognized and has no unique ID
-     \retval *             the method is on of the recognized HTTP methods.
+     * \retval Http::METHOD_NONE   the method is unset
+     * \retval Http::METHOD_OTHER  the method is not recognized and has no unique ID
+     * \retval *                   the method is on of the recognized HTTP methods.
      */
-    _method_t id() const { return theMethod; }
+    Http::MethodType id() const { return theMethod; }
 
     /** Get a char string representation of the method. */
     char const * image() const;
 
-    bool isCacheble() const;
+    /// Whether this method is defined as a "safe" in HTTP/1.1
+    /// see RFC 2616 section 9.1.1
+    bool isHttpSafe() const;
+
+    /// Whether this method is defined as "idempotent" in HTTP/1.1
+    /// see RFC 2616 section 9.1.2
+    bool isIdempotent() const;
+
+    /** Whether responses to this method MAY be cached.
+     * \retval false  Not cacheable.
+     * \retval true   Possibly cacheable. Other details will determine.
+     */
+    bool respMaybeCacheable() const;
+
+    /** Whether this method SHOULD (or MUST) invalidate existing cached entries.
+     * Invalidation is always determined by the response
+     *
+     * RFC 2616 defines invalidate as either immediate purge
+     * or delayed explicit revalidate all stored copies on next use.
+     *
+     * \retval true   SHOULD invalidate. Response details can raise this to a MUST.
+     * \retval false  Other details will determine. Method is not a factor.
+     */
+    bool shouldInvalidate() const;
+
+    /* Whether this method invalidates existing cached entries.
+     * Kept for backward-compatibility. This is the old 2.x-3.2 invalidation behaviour.
+     *
+     * NOTE:
+     *    purgesOthers differs from shouldInvalidate() in that purgesOthers() returns
+     *    true on any methods the MAY invalidate (Squid opts to do so).
+     *    shouldInvalidate() only returns true on methods which SHOULD invalidate.
+     */
     bool purgesOthers() const;
 
 private:
     static const char *RequestMethodStr[];
 
-    _method_t theMethod; ///< Method type
-    String theImage;     ///< Used for store METHOD_OTHER only
+    Http::MethodType theMethod; ///< Method type
+    String theImage;     ///< Used for storing the Http::METHOD_OTHER only. A copy of the parsed method text.
 };
 
 inline std::ostream &
@@ -159,7 +126,7 @@
 }
 
 inline const char*
-RequestMethodStr(const _method_t m)
+RequestMethodStr(const Http::MethodType m)
 {
     return HttpRequestMethod(m).image();
 }

=== modified file 'src/Makefile.am'
--- src/Makefile.am	2012-10-13 21:31:34 +0000
+++ src/Makefile.am	2012-10-16 06:15:53 +0000
@@ -43,8 +43,8 @@
 endif
 DIST_SUBDIRS += auth
 
-SUBDIRS	+= ip icmp ident log ipc mgr
-DIST_SUBDIRS += ip icmp ident log ipc mgr
+SUBDIRS	+= http ip icmp ident log ipc mgr
+DIST_SUBDIRS += http ip icmp ident log ipc mgr
 
 if ENABLE_SSL
 SUBDIRS += ssl
@@ -628,6 +628,7 @@
 	anyp/libanyp.la \
 	comm/libcomm.la \
 	eui/libeui.la \
+	http/libsquid-http.la \
 	icmp/libicmp.la icmp/libicmp-core.la \
 	log/liblog.la \
 	format/libformat.la \
@@ -1324,6 +1325,7 @@
 nodist_tests_testACLMaxUserIP_SOURCES= \
 	$(TESTSOURCES)
 tests_testACLMaxUserIP_LDADD= \
+	http/libsquid-http.la \
 	$(AUTH_ACL_LIBS) \
 	ident/libident.la \
 	acl/libacls.la \
@@ -1569,6 +1571,7 @@
 	$(DISKIO_GEN_SOURCE)
 # comm.cc only requires comm/libcomm.la until fdc_table is dead.
 tests_testCacheManager_LDADD = \
+	http/libsquid-http.la \
 	$(AUTH_ACL_LIBS) \
 	ident/libident.la \
 	acl/libacls.la \
@@ -1746,6 +1749,7 @@
 	SquidMath.h \
 	swap_log_op.cc
 tests_testDiskIO_LDADD = \
+	http/libsquid-http.la \
 	SquidConfig.o \
 	CommCalls.o \
 	DnsLookupDetails.o \
@@ -1986,6 +1990,7 @@
 	$(BUILT_SOURCES) \
 	$(DISKIO_GEN_SOURCE)
 tests_testEvent_LDADD = \
+	http/libsquid-http.la \
 	$(AUTH_ACL_LIBS) \
 	ident/libident.la \
 	acl/libacls.la \
@@ -2228,6 +2233,7 @@
 	$(BUILT_SOURCES) \
 	$(DISKIO_GEN_SOURCE)
 tests_testEventLoop_LDADD = \
+	http/libsquid-http.la \
 	$(AUTH_ACL_LIBS) \
 	ident/libident.la \
 	acl/libacls.la \
@@ -2464,6 +2470,7 @@
 	$(BUILT_SOURCES) \
 	$(DISKIO_GEN_SOURCE)
 tests_test_http_range_LDADD = \
+	http/libsquid-http.la \
 	$(AUTH_ACL_LIBS) \
 	ident/libident.la \
 	acl/libacls.la \
@@ -2530,6 +2537,7 @@
 nodist_tests_testHttpParser_SOURCES = \
 	$(TESTSOURCES)
 tests_testHttpParser_LDADD= \
+	http/libsquid-http.la \
 	SquidConfig.o \
 	base/libbase.la \
 	ip/libip.la \
@@ -2757,6 +2765,7 @@
 	comm/libcomm.la \
 	log/liblog.la \
 	format/libformat.la \
+	http/libsquid-http.la \
 	$(REPL_OBJS) \
 	$(ADAPTATION_LIBS) \
 	$(ESI_LIBS) \
@@ -2916,6 +2925,7 @@
 	swap_log_op.cc
 
 tests_testStore_LDADD= \
+	http/libsquid-http.la \
 	$(AUTH_ACL_LIBS) \
 	ident/libident.la \
 	acl/libacls.la \
@@ -3138,6 +3148,7 @@
 	SquidMath.h \
 	swap_log_op.cc
 tests_testUfs_LDADD = \
+	http/libsquid-http.la \
 	CommCalls.o \
 	DnsLookupDetails.o \
 	$(AUTH_ACL_LIBS) \
@@ -3299,6 +3310,7 @@
 	SquidMath.h \
 	$(TESTSOURCES)
 tests_testRock_LDADD = \
+	http/libsquid-http.la \
 	libsquid.la \
 	comm/libcomm.la \
 	anyp/libanyp.la \
@@ -3838,6 +3850,7 @@
 nodist_tests_testURL_SOURCES = \
 	$(BUILT_SOURCES)
 tests_testURL_LDADD = \
+	http/libsquid-http.la \
 	anyp/libanyp.la \
 	$(AUTH_ACL_LIBS) \
 	ident/libident.la \

=== modified file 'src/acl/Asn.cc'
--- src/acl/Asn.cc	2012-09-19 17:16:56 +0000
+++ src/acl/Asn.cc	2012-10-09 04:42:22 +0000
@@ -248,8 +248,8 @@
     assert(NULL != req);
     asState->request = HTTPMSGLOCK(req);
 
-    if ((e = storeGetPublic(asres, METHOD_GET)) == NULL) {
-        e = storeCreateEntry(asres, asres, RequestFlags(), METHOD_GET);
+    if ((e = storeGetPublic(asres, Http::METHOD_GET)) == NULL) {
+        e = storeCreateEntry(asres, asres, RequestFlags(), Http::METHOD_GET);
         asState->sc = storeClientListAdd(e, asState);
         FwdState::fwdStart(Comm::ConnectionPointer(), e, asState->request);
     } else {

=== modified file 'src/adaptation/ecap/MessageRep.cc'
--- src/adaptation/ecap/MessageRep.cc	2012-08-31 16:57:39 +0000
+++ src/adaptation/ecap/MessageRep.cc	2012-10-09 04:39:01 +0000
@@ -227,7 +227,7 @@
         const int id = aMethod.hostId();
         Must(METHOD_NONE < id && id < METHOD_ENUM_END);
         Must(id != METHOD_OTHER);
-        theMessage.method = HttpRequestMethod(static_cast<_method_t>(id));
+        theMessage.method = HttpRequestMethod(static_cast<Http::MethodType>(id));
     } else {
         const std::string &image = aMethod.image();
         theMessage.method = HttpRequestMethod(image.data(),

=== modified file 'src/adaptation/icap/ModXact.cc'
--- src/adaptation/icap/ModXact.cc	2012-08-31 16:57:39 +0000
+++ src/adaptation/icap/ModXact.cc	2012-10-09 04:39:01 +0000
@@ -1746,12 +1746,12 @@
     else if (HttpRequest *req = dynamic_cast<HttpRequest*>(msg))
         method = req->method;
     else
-        method = METHOD_NONE;
+        method = Http::METHOD_NONE;
 
     int64_t size;
     // expectingBody returns true for zero-sized bodies, but we will not
     // get a pipe for that body, so we treat the message as bodyless
-    if (method != METHOD_NONE && msg->expectingBody(method, size) && size) {
+    if (method != Http::METHOD_NONE && msg->expectingBody(method, size) && size) {
         debugs(93, 6, HERE << "expects virgin body from " <<
                virgin.body_pipe << "; size: " << size);
 

=== modified file 'src/auth/digest/UserRequest.cc'
--- src/auth/digest/UserRequest.cc	2012-08-31 16:57:39 +0000
+++ src/auth/digest/UserRequest.cc	2012-10-09 04:39:01 +0000
@@ -104,7 +104,7 @@
             return;
         }
 
-        if (static_cast<Auth::Digest::Config*>(Auth::Config::Find("digest"))->PostWorkaround && request->method != METHOD_GET) {
+        if (static_cast<Auth::Digest::Config*>(Auth::Config::Find("digest"))->PostWorkaround && request->method != Http::METHOD_GET) {
             /* Ugly workaround for certain very broken browsers using the
              * wrong method to calculate the request-digest on POST request.
              * This should be deleted once Digest authentication becomes more
@@ -113,7 +113,7 @@
              */
             DigestCalcResponse(SESSIONKEY, authenticateDigestNonceNonceb64(digest_request->nonce),
                                digest_request->nc, digest_request->cnonce, digest_request->qop,
-                               RequestMethodStr(METHOD_GET), digest_request->uri, HA2, Response);
+                               RequestMethodStr(Http::METHOD_GET), digest_request->uri, HA2, Response);
 
             if (strcasecmp(digest_request->response, Response)) {
                 auth_user->credentials(Auth::Failed);

=== modified file 'src/cache_cf.cc'
--- src/cache_cf.cc	2012-10-20 08:01:32 +0000
+++ src/cache_cf.cc	2012-10-26 00:34:40 +0000
@@ -913,7 +913,6 @@
         Config2.effectiveGroupID = grp->gr_gid;
     }
 
-    HttpRequestMethod::Configure(Config);
 #if USE_SSL
 
     debugs(3, DBG_IMPORTANT, "Initializing https proxy context");

=== modified file 'src/client_side.cc'
--- src/client_side.cc	2012-10-05 07:26:35 +0000
+++ src/client_side.cc	2012-10-09 04:42:44 +0000
@@ -858,9 +858,9 @@
 {
     switch (r->method.id()) {
 
-    case METHOD_GET:
+    case Http::METHOD_GET:
 
-    case METHOD_HEAD:
+    case Http::METHOD_HEAD:
         /* We do not want to see a request entity on GET/HEAD requests */
         return (r->content_length <= 0 || Config.onoff.request_entities);
 
@@ -2149,7 +2149,7 @@
     int r;
 
     /* pre-set these values to make aborting simpler */
-    *method_p = METHOD_NONE;
+    *method_p = Http::METHOD_NONE;
 
     /* NP: don't be tempted to move this down or remove again.
      * It's the only DDoS protection old-String has against long URL */
@@ -2211,7 +2211,7 @@
     *method_p = HttpRequestMethod(&hp->buf[hp->req.m_start], &hp->buf[hp->req.m_end]+1);
 
     /* deny CONNECT via accelerated ports */
-    if (*method_p == METHOD_CONNECT && csd && csd->port && csd->port->accel) {
+    if (*method_p == Http::METHOD_CONNECT && csd && csd->port && csd->port->accel) {
         debugs(33, DBG_IMPORTANT, "WARNING: CONNECT method received on " << csd->port->protocol << " Accelerator port " << csd->port->s.GetPort() );
         /* XXX need a way to say "this many character length string" */
         debugs(33, DBG_IMPORTANT, "WARNING: for request: " << hp->buf);
@@ -2219,7 +2219,7 @@
         return parseHttpRequestAbort(csd, "error:method-not-allowed");
     }
 
-    if (*method_p == METHOD_NONE) {
+    if (*method_p == Http::METHOD_NONE) {
         /* XXX need a way to say "this many character length string" */
         debugs(33, DBG_IMPORTANT, "clientParseRequestMethod: Unsupported method in request '" << hp->buf << "'");
         hp->request_parse_status = HTTP_METHOD_NOT_ALLOWED;
@@ -2445,7 +2445,7 @@
     clientReplyContext *repContext = dynamic_cast<clientReplyContext *>(node->data.getRaw());
     assert (repContext);
     repContext->setReplyToError(ERR_TOO_BIG,
-                                HTTP_BAD_REQUEST, METHOD_NONE, NULL,
+                                HTTP_BAD_REQUEST, Http::METHOD_NONE, NULL,
                                 clientConnection->remote, NULL, NULL, NULL);
     context->registerWithConn();
     context->pullData();
@@ -2713,7 +2713,7 @@
         unsupportedTe = te.size() && te != "identity";
     } // else implied identity coding
 
-    mustReplyToOptions = (method == METHOD_OPTIONS) &&
+    mustReplyToOptions = (method == Http::METHOD_OPTIONS) &&
                          (request->header.getInt64(HDR_MAX_FORWARDS) == 0);
     if (!urlCheckRequest(request) || mustReplyToOptions || unsupportedTe) {
         clientStreamNode *node = context->getClientReplyContext();
@@ -2760,7 +2760,7 @@
     clientSetKeepaliveFlag(http);
 
     // Let tunneling code be fully responsible for CONNECT requests
-    if (http->request->method == METHOD_CONNECT) {
+    if (http->request->method == Http::METHOD_CONNECT) {
         context->mayUseConnection(true);
         conn->flags.readMore = false;
     }
@@ -2788,7 +2788,7 @@
             assert (repContext);
             conn->quitAfterError(request);
             repContext->setReplyToError(ERR_TOO_BIG,
-                                        HTTP_REQUEST_ENTITY_TOO_LARGE, METHOD_NONE, NULL,
+                                        HTTP_REQUEST_ENTITY_TOO_LARGE, Http::METHOD_NONE, NULL,
                                         conn->clientConnection->remote, http->request, NULL, NULL);
             assert(context->http->out.offset == 0);
             context->pullData();
@@ -3216,7 +3216,7 @@
         clientReplyContext *repContext = dynamic_cast<clientReplyContext *>(node->data.getRaw());
         assert (repContext);
         repContext->setReplyToError(ERR_LIFETIME_EXP,
-                                    HTTP_REQUEST_TIMEOUT, METHOD_NONE, "N/A", &CachePeer.sin_addr,
+                                    HTTP_REQUEST_TIMEOUT, Http::METHOD_NONE, "N/A", &CachePeer.sin_addr,
                                     NULL, NULL, NULL);
         /* No requests can be outstanded */
         assert(chr == NULL);

=== modified file 'src/client_side_reply.cc'
--- src/client_side_reply.cc	2012-10-04 09:14:06 +0000
+++ src/client_side_reply.cc	2012-10-09 04:39:01 +0000
@@ -534,7 +534,7 @@
         return;
     }
 
-    if (r->method == METHOD_PURGE) {
+    if (r->method == Http::METHOD_PURGE) {
         removeClientStoreReference(&sc, http);
         e = NULL;
         purgeRequest();
@@ -635,13 +635,13 @@
     }
 
     /** Check if its a PURGE request to be actioned. */
-    if (r->method == METHOD_PURGE) {
+    if (r->method == Http::METHOD_PURGE) {
         purgeRequest();
         return;
     }
 
     /** Check if its an 'OTHER' request. Purge all cached entries if so and continue. */
-    if (r->method == METHOD_OTHER) {
+    if (r->method == Http::METHOD_OTHER) {
         purgeAllCached();
     }
 
@@ -779,7 +779,7 @@
 
     // TODO: can we use purgeAllCached() here instead of doing the
     // getPublicByRequestMethod() dance?
-    StoreEntry::getPublicByRequestMethod(this, http->request, METHOD_GET);
+    StoreEntry::getPublicByRequestMethod(this, http->request, Http::METHOD_GET);
 }
 
 // Purges all entries with a given url
@@ -795,13 +795,13 @@
     bool get_or_head_sent = false;
 #endif
 
-    for (HttpRequestMethod m(METHOD_NONE); m != METHOD_ENUM_END; ++m) {
-        if (m.isCacheble()) {
+    for (HttpRequestMethod m(Http::METHOD_NONE); m != Http::METHOD_ENUM_END; ++m) {
+        if (m.respMaybeCacheable()) {
             if (StoreEntry *entry = storeGetPublic(url, m)) {
                 debugs(88, 5, "purging " << RequestMethodStr(m) << ' ' << url);
 #if USE_HTCP
                 neighborsHtcpClear(entry, url, req, m, HTCP_CLR_INVALIDATION);
-                if (m == METHOD_GET || m == METHOD_HEAD) {
+                if (m == Http::METHOD_GET || m == Http::METHOD_HEAD) {
                     get_or_head_sent = true;
                 }
 #endif
@@ -812,7 +812,7 @@
 
 #if USE_HTCP
     if (!get_or_head_sent) {
-        neighborsHtcpClear(NULL, url, req, HttpRequestMethod(METHOD_GET), HTCP_CLR_INVALIDATION);
+        neighborsHtcpClear(NULL, url, req, HttpRequestMethod(Http::METHOD_GET), HTCP_CLR_INVALIDATION);
     }
 #endif
 }
@@ -844,7 +844,7 @@
 {
     if (newEntry->isNull()) {
         lookingforstore = 2;
-        StoreEntry::getPublicByRequestMethod(this, http->request, METHOD_HEAD);
+        StoreEntry::getPublicByRequestMethod(this, http->request, Http::METHOD_HEAD);
     } else
         purgeFoundObject (newEntry);
 }
@@ -923,7 +923,7 @@
 {
     http->logType = LOG_TCP_MISS;
     lookingforstore = 3;
-    StoreEntry::getPublicByRequestMethod(this,http->request, METHOD_GET);
+    StoreEntry::getPublicByRequestMethod(this,http->request, Http::METHOD_GET);
 }
 
 void
@@ -937,14 +937,14 @@
         /* Release the cached URI */
         debugs(88, 4, "clientPurgeRequest: GET '" << newEntry->url() << "'" );
 #if USE_HTCP
-        neighborsHtcpClear(newEntry, NULL, http->request, HttpRequestMethod(METHOD_GET), HTCP_CLR_PURGE);
+        neighborsHtcpClear(newEntry, NULL, http->request, HttpRequestMethod(Http::METHOD_GET), HTCP_CLR_PURGE);
 #endif
         newEntry->release();
         purgeStatus = HTTP_OK;
     }
 
     lookingforstore = 4;
-    StoreEntry::getPublicByRequestMethod(this, http->request, METHOD_HEAD);
+    StoreEntry::getPublicByRequestMethod(this, http->request, Http::METHOD_HEAD);
 }
 
 void
@@ -953,7 +953,7 @@
     if (newEntry && !newEntry->isNull()) {
         debugs(88, 4, "clientPurgeRequest: HEAD '" << newEntry->url() << "'" );
 #if USE_HTCP
-        neighborsHtcpClear(newEntry, NULL, http->request, HttpRequestMethod(METHOD_HEAD), HTCP_CLR_PURGE);
+        neighborsHtcpClear(newEntry, NULL, http->request, HttpRequestMethod(Http::METHOD_HEAD), HTCP_CLR_PURGE);
 #endif
         newEntry->release();
         purgeStatus = HTTP_OK;
@@ -963,23 +963,23 @@
 
     if (http->request->vary_headers
             && !strstr(http->request->vary_headers, "=")) {
-        StoreEntry *entry = storeGetPublic(urlCanonical(http->request), METHOD_GET);
+        StoreEntry *entry = storeGetPublic(urlCanonical(http->request), Http::METHOD_GET);
 
         if (entry) {
             debugs(88, 4, "clientPurgeRequest: Vary GET '" << entry->url() << "'" );
 #if USE_HTCP
-            neighborsHtcpClear(entry, NULL, http->request, HttpRequestMethod(METHOD_GET), HTCP_CLR_PURGE);
+            neighborsHtcpClear(entry, NULL, http->request, HttpRequestMethod(Http::METHOD_GET), HTCP_CLR_PURGE);
 #endif
             entry->release();
             purgeStatus = HTTP_OK;
         }
 
-        entry = storeGetPublic(urlCanonical(http->request), METHOD_HEAD);
+        entry = storeGetPublic(urlCanonical(http->request), Http::METHOD_HEAD);
 
         if (entry) {
             debugs(88, 4, "clientPurgeRequest: Vary HEAD '" << entry->url() << "'" );
 #if USE_HTCP
-            neighborsHtcpClear(entry, NULL, http->request, HttpRequestMethod(METHOD_HEAD), HTCP_CLR_PURGE);
+            neighborsHtcpClear(entry, NULL, http->request, HttpRequestMethod(Http::METHOD_HEAD), HTCP_CLR_PURGE);
 #endif
             entry->release();
             purgeStatus = HTTP_OK;
@@ -1697,14 +1697,14 @@
         return;
     }
 
-    if (context->http->request->method == METHOD_PURGE) {
+    if (context->http->request->method == Http::METHOD_PURGE) {
         context->purgeRequest();
         return;
     }
 
     // OPTIONS with Max-Forwards:0 handled in clientProcessRequest()
 
-    if (context->http->request->method == METHOD_TRACE) {
+    if (context->http->request->method == Http::METHOD_TRACE) {
         if (context->http->request->header.getInt64(HDR_MAX_FORWARDS) == 0) {
             context->traceReply(aNode);
             return;
@@ -1908,8 +1908,8 @@
 void
 clientReplyContext::sendNotModifiedOrPreconditionFailedError()
 {
-    if (http->request->method == METHOD_GET ||
-            http->request->method == METHOD_HEAD)
+    if (http->request->method == Http::METHOD_GET ||
+            http->request->method == Http::METHOD_HEAD)
         sendNotModified();
     else
         sendPreconditionFailedError();
@@ -2015,7 +2015,7 @@
 
 #endif
 
-    if (http->request->method == METHOD_HEAD) {
+    if (http->request->method == Http::METHOD_HEAD) {
         /* do not forward body for HEAD replies */
         body_size = 0;
         http->flags.done_copying = 1;

=== modified file 'src/client_side_request.cc'
--- src/client_side_request.cc	2012-10-17 00:14:09 +0000
+++ src/client_side_request.cc	2012-10-26 00:34:40 +0000
@@ -581,7 +581,7 @@
 {
     // IP address validation for Host: failed. Admin wants to ignore them.
     // NP: we do not yet handle CONNECT tunnels well, so ignore for them
-    if (!Config.onoff.hostStrictVerify && http->request->method != METHOD_CONNECT) {
+    if (!Config.onoff.hostStrictVerify && http->request->method != Http::METHOD_CONNECT) {
         debugs(85, 3, "SECURITY ALERT: Host header forgery detected on " << http->getConn()->clientConnection <<
                " (" << A << " does not match " << B << ") on URL: " << urlCanonical(http->request));
 
@@ -691,7 +691,7 @@
         // Verify forward-proxy requested URL domain matches the Host: header
         debugs(85, 3, HERE << "FAIL on validate URL port " << http->request->port << " matches Host: port " << portStr);
         hostHeaderVerifyFailed("URL port", portStr);
-    } else if (!portStr && http->request->method != METHOD_CONNECT && http->request->port != urlDefaultPort(http->request->protocol)) {
+    } else if (!portStr && http->request->method != Http::METHOD_CONNECT && http->request->port != urlDefaultPort(http->request->protocol)) {
         // Verify forward-proxy requested URL domain matches the Host: header
         // Special case: we don't have a default-port to check for CONNECT. Assume URL is correct.
         debugs(85, 3, HERE << "FAIL on validate URL port " << http->request->port << " matches Host: default port " << urlDefaultPort(http->request->protocol));
@@ -942,10 +942,10 @@
     if (request->flags.auth)
         return 0;
 
-    if (method == METHOD_TRACE)
+    if (method == Http::METHOD_TRACE)
         return 1;
 
-    if (method != METHOD_GET)
+    if (method != Http::METHOD_GET)
         return 0;
 
     /* scan hierarchy_stoplist */
@@ -957,7 +957,7 @@
         return 0;
 
     if (request->protocol == AnyP::PROTO_HTTP)
-        return httpCachable(method);
+        return method.respMaybeCacheable();
 
     if (request->protocol == AnyP::PROTO_GOPHER)
         return gopherCachable(request);
@@ -1077,7 +1077,7 @@
         }
     }
 
-    if (request->method == METHOD_OTHER) {
+    if (request->method == Http::METHOD_OTHER) {
         no_cache=true;
     }
 
@@ -1095,7 +1095,7 @@
     }
 
     /* ignore range header in non-GETs or non-HEADs */
-    if (request->method == METHOD_GET || request->method == METHOD_HEAD) {
+    if (request->method == Http::METHOD_GET || request->method == Http::METHOD_HEAD) {
         // XXX: initialize if we got here without HttpRequest::parseHeader()
         if (!request->range)
             request->range = req_hdr->getRange();
@@ -1166,7 +1166,7 @@
 
 #endif
 
-    request->flags.cachable = http->request->cacheable();
+    request->flags.cachable = http->request->maybeCacheable();
 
     if (clientHierarchical(http))
         request->flags.hierarchical = 1;
@@ -1308,7 +1308,7 @@
     // Bumping here can only start with a CONNECT request on a bumping port
     // (bumping of intercepted SSL conns is decided before we get 1st request).
     // We also do not bump redirected CONNECT requests.
-    if (http->request->method != METHOD_CONNECT || http->redirect.status ||
+    if (http->request->method != Http::METHOD_CONNECT || http->redirect.status ||
             !Config.accessList.ssl_bump || !http->getConn()->port->sslBump) {
         http->al->ssl.bumpMode = Ssl::bumpEnd; // SslBump does not apply; log -
         debugs(85, 5, HERE << "cannot SslBump this request");
@@ -1369,7 +1369,7 @@
 {
     debugs(85, 4, "clientProcessRequest: " << RequestMethodStr(request->method) << " '" << uri << "'");
 
-    if (request->method == METHOD_CONNECT && !redirect.status) {
+    if (request->method == Http::METHOD_CONNECT && !redirect.status) {
 #if USE_SSL
         if (sslBumpNeeded()) {
             sslBumpStart();

=== modified file 'src/errorpage.cc'
--- src/errorpage.cc	2012-09-19 17:16:56 +0000
+++ src/errorpage.cc	2012-10-09 04:39:01 +0000
@@ -1167,7 +1167,7 @@
             status = httpStatus;
         else {
             // Use 307 for HTTP/1.1 non-GET/HEAD requests.
-            if (request->method != METHOD_GET && request->method != METHOD_HEAD && request->http_ver >= HttpVersion(1,1))
+            if (request->method != Http::METHOD_GET && request->method != Http::METHOD_HEAD && request->http_ver >= HttpVersion(1,1))
                 status = HTTP_TEMPORARY_REDIRECT;
         }
 

=== modified file 'src/esi/Include.cc'
--- src/esi/Include.cc	2012-09-01 14:38:36 +0000
+++ src/esi/Include.cc	2012-10-09 04:39:01 +0000
@@ -334,10 +334,9 @@
     /* tempUrl is eaten by the request */
     char const *tempUrl = vars->extractChar ();
 
-    debugs(86, 5, "ESIIncludeStart: Starting subrequest with url '" << tempUrl <<
-           "'");
+    debugs(86, 5, "ESIIncludeStart: Starting subrequest with url '" << tempUrl << "'");
 
-    if (clientBeginRequest(METHOD_GET, tempUrl, esiBufferRecipient, esiBufferDetach, stream.getRaw(), &tempheaders, stream->localbuffer->buf, HTTP_REQBUF_SZ)) {
+    if (clientBeginRequest(Http::METHOD_GET, tempUrl, esiBufferRecipient, esiBufferDetach, stream.getRaw(), &tempheaders, stream->localbuffer->buf, HTTP_REQBUF_SZ)) {
         debugs(86, DBG_CRITICAL, "starting new ESI subrequest failed");
     }
 

=== modified file 'src/forward.cc'
--- src/forward.cc	2012-10-03 07:34:10 +0000
+++ src/forward.cc	2012-10-09 04:43:22 +0000
@@ -563,29 +563,14 @@
 bool
 FwdState::checkRetriable()
 {
-    /* RFC2616 9.1 Safe and Idempotent Methods */
-    switch (request->method.id()) {
-        /* 9.1.1 Safe Methods */
-
-    case METHOD_GET:
-
-    case METHOD_HEAD:
-        /* 9.1.2 Idempotent Methods */
-
-    case METHOD_PUT:
-
-    case METHOD_DELETE:
-
-    case METHOD_OPTIONS:
-
-    case METHOD_TRACE:
-        break;
-
-    default:
+    // Optimize: A compliant proxy may retry PUTs, but Squid lacks the [rather
+    // complicated] code required to protect the PUT request body from being
+    // nibbled during the first try. Thus, Squid cannot retry some PUTs today.
+    if (request->body_pipe != NULL)
         return false;
-    }
 
-    return true;
+    // RFC2616 9.1 Safe and Idempotent Methods
+    return (request->method.isHttpSafe() || request->method.isIdempotent());
 }
 
 void

=== modified file 'src/ftp.cc'
--- src/ftp.cc	2012-10-10 17:06:38 +0000
+++ src/ftp.cc	2012-10-11 06:19:35 +0000
@@ -507,7 +507,7 @@
     AsyncCall::Pointer closer = JobCallback(9, 5, Dialer, this, FtpStateData::ctrlClosed);
     ctrl.opened(conn, closer);
 
-    if (request->method == METHOD_PUT)
+    if (request->method == Http::METHOD_PUT)
         flags.put = 1;
 }
 
@@ -1336,7 +1336,7 @@
 {
     debugs(9, 3, HERE << "FtpStateData::processReplyBody starting.");
 
-    if (request->method == METHOD_HEAD && (flags.isdir || theSize != -1)) {
+    if (request->method == Http::METHOD_HEAD && (flags.isdir || theSize != -1)) {
         serverComplete();
         return;
     }
@@ -2537,7 +2537,7 @@
 
     /** \par
       * Checks for 'HEAD' method request and passes off for special handling by FtpStateData::processHeadResponse(). */
-    if (ftpState->request->method == METHOD_HEAD && (ftpState->flags.isdir || ftpState->theSize != -1)) {
+    if (ftpState->request->method == Http::METHOD_HEAD && (ftpState->flags.isdir || ftpState->theSize != -1)) {
         ftpState->processHeadResponse(); // may call serverComplete
         return;
     }

=== modified file 'src/htcp.cc'
--- src/htcp.cc	2012-09-22 14:21:59 +0000
+++ src/htcp.cc	2012-10-09 04:39:01 +0000
@@ -748,7 +748,7 @@
      */
     method = HttpRequestMethod(s->method, NULL);
 
-    s->request = HttpRequest::CreateFromUrlAndMethod(s->uri, method == METHOD_NONE ? HttpRequestMethod(METHOD_GET) : method);
+    s->request = HttpRequest::CreateFromUrlAndMethod(s->uri, method == Http::METHOD_NONE ? HttpRequestMethod(Http::METHOD_GET) : method);
 
     if (s->request)
         HTTPMSGLOCK(s->request);

=== added directory 'src/http'
=== modified file 'src/http.cc'
--- src/http.cc	2012-10-20 08:01:32 +0000
+++ src/http.cc	2012-10-26 00:34:40 +0000
@@ -176,19 +176,6 @@
     mustStop("HttpStateData::httpStateConnClosed");
 }
 
-int
-httpCachable(const HttpRequestMethod& method)
-{
-    /* GET and HEAD are cachable. Others are not. */
-
-    // TODO: replase to HttpRequestMethod::isCachable() ?
-    if (method != METHOD_GET && method != METHOD_HEAD)
-        return 0;
-
-    /* else cachable */
-    return 1;
-}
-
 void
 HttpStateData::httpTimeout(const CommTimeoutCbParams &params)
 {
@@ -283,14 +270,14 @@
      * changed.
      */
     if (e->mem_obj->request)
-        pe = storeGetPublicByRequestMethod(e->mem_obj->request, METHOD_HEAD);
+        pe = storeGetPublicByRequestMethod(e->mem_obj->request, Http::METHOD_HEAD);
     else
-        pe = storeGetPublic(e->mem_obj->url, METHOD_HEAD);
+        pe = storeGetPublic(e->mem_obj->url, Http::METHOD_HEAD);
 
     if (pe != NULL) {
         assert(e != pe);
 #if USE_HTCP
-        neighborsHtcpClear(e, NULL, e->mem_obj->request, HttpRequestMethod(METHOD_HEAD), HTCP_CLR_INVALIDATION);
+        neighborsHtcpClear(e, NULL, e->mem_obj->request, HttpRequestMethod(Http::METHOD_HEAD), HTCP_CLR_INVALIDATION);
 #endif
         pe->release();
     }
@@ -1952,7 +1939,7 @@
     case HDR_MAX_FORWARDS:
         /** \par Max-Forwards:
          * pass only on TRACE or OPTIONS requests */
-        if (request->method == METHOD_TRACE || request->method == METHOD_OPTIONS) {
+        if (request->method == Http::METHOD_TRACE || request->method == Http::METHOD_OPTIONS) {
             const int64_t hops = e->getInt64();
 
             if (hops > 0)

=== added file 'src/http/Makefile.am'
--- src/http/Makefile.am	1970-01-01 00:00:00 +0000
+++ src/http/Makefile.am	2012-02-22 05:54:32 +0000
@@ -0,0 +1,14 @@
+include $(top_srcdir)/src/Common.am
+include $(top_srcdir)/src/TestHeaders.am
+
+noinst_LTLIBRARIES = libsquid-http.la
+
+libsquid_http_la_SOURCES = \
+	MethodType.cc \
+	MethodType.h
+
+MethodType.cc: MethodType.h $(top_srcdir)/src/mk-string-arrays.awk
+	($(AWK) -f $(top_srcdir)/src/mk-string-arrays.awk < $(srcdir)/MethodType.h | sed -e 's%METHOD_%%' | \
+		sed -e 's%_C%-C%' >$@) || ($(RM) -f $@ && exit 1)
+
+CLEANFILES += MethodType.cc

=== added file 'src/http/MethodType.h'
--- src/http/MethodType.h	1970-01-01 00:00:00 +0000
+++ src/http/MethodType.h	2012-07-03 02:09:07 +0000
@@ -0,0 +1,94 @@
+#ifndef SQUID_SRC_HTTP_METHODTYPE_H
+#define SQUID_SRC_HTTP_METHODTYPE_H
+
+namespace Http
+{
+
+// see IANA registry: 
+// also: https://datatracker.ietf.org/doc/draft-ietf-httpbis-method-registrations
+typedef enum _method_t {
+    METHOD_NONE = 0,
+
+#if NO_SPECIAL_HANDLING
+    // RFC 2068
+    METHOD_LINK,
+    METHOD_UNLINK,
+#endif
+
+    // RFC 2616 (HTTP)
+    METHOD_GET,
+    METHOD_POST,
+    METHOD_PUT,
+    METHOD_HEAD,
+    METHOD_CONNECT,
+    METHOD_TRACE,
+    METHOD_OPTIONS,
+    METHOD_DELETE,
+
+    // RFC 3253
+    METHOD_CHECKOUT,
+    METHOD_CHECKIN,
+    METHOD_UNCHECKOUT,
+    METHOD_MKWORKSPACE,
+    METHOD_VERSION_CONTROL,
+    METHOD_REPORT,
+    METHOD_UPDATE,
+    METHOD_LABEL,
+    METHOD_MERGE,
+    METHOD_BASELINE_CONTROL,
+    METHOD_MKACTIVITY,
+
+#if NO_SPECIAL_HANDLING
+    // RFC 3648
+    METHOD_ORDERPATCH,
+
+    // RFC 3744
+    METHOD_ACL,
+
+    // RFC 4437
+    METHOD_MKREDIRECTREF,
+    METHOD_UPDATEREDIRECTREF,
+
+    // RFC 4791
+    METHOD_MKCALENDAR,
+#endif
+
+    // RFC 4918 (WebDAV)
+    METHOD_PROPFIND,
+    METHOD_PROPPATCH,
+    METHOD_MKCOL,
+    METHOD_COPY,
+    METHOD_MOVE,
+    METHOD_LOCK,
+    METHOD_UNLOCK,
+
+    // RFC 5323
+    METHOD_SEARCH,
+
+#if NO_SPECIAL_HANDLING
+    // RFC 5789
+    METHOD_PATCH,
+
+    // RFC 5842
+    METHOD_BIND,
+    METHOD_REBIND,
+    METHOD_UNBIND,
+#endif
+
+    // Squid extension methods
+    METHOD_PURGE,
+    METHOD_OTHER,
+    METHOD_ENUM_END  // MUST be last, (yuck) this is used as an array-initialization index constant!
+} MethodType;
+
+extern const char *MethodType_str[];
+
+inline const char*
+MethodStr(const MethodType m)
+{
+    return MethodType_str[m];
+}
+
+}; // namespace Http
+
+#endif /* SQUID_SRC_HTTP_METHODTYPE_H */

=== modified file 'src/icmp/net_db.cc'
--- src/icmp/net_db.cc	2012-09-19 17:16:56 +0000
+++ src/icmp/net_db.cc	2012-10-09 04:43:42 +0000
@@ -1335,7 +1335,7 @@
     assert(NULL != ex->r);
     ex->r->http_ver = HttpVersion(1,1);
     ex->connstate = STATE_HEADER;
-    ex->e = storeCreateEntry(uri, uri, RequestFlags(), METHOD_GET);
+    ex->e = storeCreateEntry(uri, uri, RequestFlags(), Http::METHOD_GET);
     ex->buf_sz = NETDB_REQBUF_SZ;
     assert(NULL != ex->e);
     ex->sc = storeClientListAdd(ex->e, ex);

=== modified file 'src/icp_v2.cc'
--- src/icp_v2.cc	2012-09-04 09:10:20 +0000
+++ src/icp_v2.cc	2012-10-09 04:39:01 +0000
@@ -509,7 +509,7 @@
 
     state->src_rtt = src_rtt;
 
-    StoreEntry::getPublic (state, url, METHOD_GET);
+    StoreEntry::getPublic (state, url, Http::METHOD_GET);
 
     HTTPMSGUNLOCK(icp_request);
 }
@@ -853,5 +853,5 @@
     if (neighbors_do_private_keys && reqnum)
         return queried_keys[reqnum & N_QUERIED_KEYS_MASK];
 
-    return storeKeyPublic(url, METHOD_GET);
+    return storeKeyPublic(url, Http::METHOD_GET);
 }

=== modified file 'src/icp_v3.cc'
--- src/icp_v3.cc	2012-09-01 14:38:36 +0000
+++ src/icp_v3.cc	2012-10-09 04:39:01 +0000
@@ -78,7 +78,7 @@
 
     state->url = xstrdup (url);
 
-    StoreEntry::getPublic (state, url, METHOD_GET);
+    StoreEntry::getPublic (state, url, Http::METHOD_GET);
 }
 
 ICP3State::~ICP3State()

=== modified file 'src/mgr/ActionParams.cc'
--- src/mgr/ActionParams.cc	2012-09-01 14:38:36 +0000
+++ src/mgr/ActionParams.cc	2012-10-09 04:39:01 +0000
@@ -8,7 +8,7 @@
 #include "ipc/TypedMsgHdr.h"
 #include "mgr/ActionParams.h"
 
-Mgr::ActionParams::ActionParams(): httpMethod(METHOD_NONE)
+Mgr::ActionParams::ActionParams(): httpMethod(Http::METHOD_NONE)
 {
 }
 
@@ -17,8 +17,10 @@
     msg.getString(httpUri);
 
     const int m = msg.getInt();
-    Must(METHOD_NONE <= m && m < METHOD_ENUM_END);
-    httpMethod = static_cast<_method_t>(m);
+    Must(Http::METHOD_NONE <= m && m < Http::METHOD_ENUM_END);
+    String method;
+    msg.getString(method);
+    httpMethod = HttpRequestMethod(method.termedBuf(), NULL);
 
     msg.getPod(httpFlags);
     msg.getString(httpOrigin);
@@ -33,7 +35,8 @@
 Mgr::ActionParams::pack(Ipc::TypedMsgHdr &msg) const
 {
     msg.putString(httpUri);
-    msg.putInt(httpMethod);
+    String foo(httpMethod.image());
+    msg.putString(foo);
     msg.putPod(httpFlags);
     msg.putString(httpOrigin);
 

=== modified file 'src/mgr/ActionParams.h'
--- src/mgr/ActionParams.h	2012-09-10 12:49:35 +0000
+++ src/mgr/ActionParams.h	2012-10-12 10:47:08 +0000
@@ -26,7 +26,7 @@
 public:
     /* details of the client HTTP request that caused the action */
     String httpUri; ///< HTTP request URI
-    _method_t httpMethod; ///< HTTP request method
+    HttpRequestMethod httpMethod; ///< HTTP request method
     RequestFlags httpFlags; ///< HTTP request flags
     String httpOrigin;       ///< HTTP Origin: header (if any)
 

=== modified file 'src/mime.cc'
--- src/mime.cc	2012-09-18 21:05:32 +0000
+++ src/mime.cc	2012-10-09 04:39:01 +0000
@@ -417,7 +417,7 @@
     if (type == NULL)
         fatal("Unknown icon format while reading mime.conf\n");
 
-    StoreEntry::getPublic(this, url, METHOD_GET);
+    StoreEntry::getPublic(this, url, Http::METHOD_GET);
 }
 
 void
@@ -456,10 +456,7 @@
     }
 
     flags.cachable = 1;
-    StoreEntry *e = storeCreateEntry(url,
-                                     url,
-                                     flags,
-                                     METHOD_GET);
+    StoreEntry *e = storeCreateEntry(url,url,flags,Http::METHOD_GET);
     assert(e != NULL);
     EBIT_SET(e->flags, ENTRY_SPECIAL);
     e->setPublicKey();

=== modified file 'src/neighbors.cc'
--- src/neighbors.cc	2012-09-22 13:26:23 +0000
+++ src/neighbors.cc	2012-10-09 04:45:30 +0000
@@ -181,7 +181,7 @@
 
     // CONNECT requests are proxy requests. Not to be forwarded to origin servers.
     // Unless the destination port matches, in which case we MAY perform a 'DIRECT' to this CachePeer.
-    if (p->options.originserver && request->method == METHOD_CONNECT && request->port != p->in_addr.GetPort())
+    if (p->options.originserver && request->method == Http::METHOD_CONNECT && request->port != p->in_addr.GetPort())
         return false;
 
     if (p->peer_domain == NULL && p->access == NULL)
@@ -1378,7 +1378,7 @@
     snprintf(url, MAX_URL, "http://");
     p->in_addr.ToURL(url+7, MAX_URL -8 );
     strcat(url, "/");
-    fake = storeCreateEntry(url, url, RequestFlags(), METHOD_GET);
+    fake = storeCreateEntry(url, url, RequestFlags(), Http::METHOD_GET);
     HttpRequest *req = HttpRequest::CreateFromUrl(url);
     psstate = new ps_state;
     psstate->request = HTTPMSGLOCK(req);

=== modified file 'src/store.cc'
--- src/store.cc	2012-10-05 23:36:22 +0000
+++ src/store.cc	2012-10-09 04:45:59 +0000
@@ -642,9 +642,9 @@
 {
     StoreEntry *e = storeGetPublicByRequestMethod(req, req->method);
 
-    if (e == NULL && req->method == METHOD_HEAD)
+    if (e == NULL && req->method == Http::METHOD_HEAD)
         /* We can generate a HEAD reply from a cached GET object */
-        e = storeGetPublicByRequestMethod(req, METHOD_GET);
+        e = storeGetPublicByRequestMethod(req, Http::METHOD_GET);
 
     return e;
 }
@@ -688,7 +688,7 @@
         mem_obj->id = getKeyCounter();
         newkey = storeKeyPrivate(mem_obj->url, mem_obj->method, mem_obj->id);
     } else {
-        newkey = storeKeyPrivate("JUNK", METHOD_NONE, getKeyCounter());
+        newkey = storeKeyPrivate("JUNK", Http::METHOD_NONE, getKeyCounter());
     }
 
     assert(hash_lookup(store_table, newkey) == NULL);
@@ -982,7 +982,7 @@
 {
 #if CACHE_ALL_METHODS
 
-    if (mem_obj->method != METHOD_GET) {
+    if (mem_obj->method != Http::METHOD_GET) {
         debugs(20, 2, "StoreEntry::checkCachable: NO: non-GET method");
         ++store_check_cachable_hist.no.non_get;
     } else
@@ -1383,7 +1383,7 @@
         return 1;
     }
 
-    if (mem_obj->method == METHOD_HEAD) {
+    if (mem_obj->method == Http::METHOD_HEAD) {
         debugs(20, 5, "storeEntryValidLength: HEAD request: " << getMD5Text());
         return 1;
     }
@@ -1965,7 +1965,7 @@
     const String reqETags = request.header.getList(HDR_IF_NONE_MATCH);
     // weak comparison is allowed only for HEAD or full-body GET requests
     const bool allowWeakMatch = !request.flags.isRanged &&
-                                (request.method == METHOD_GET || request.method == METHOD_HEAD);
+                                (request.method == Http::METHOD_GET || request.method == Http::METHOD_HEAD);
     return hasOneOfEtags(reqETags, allowWeakMatch);
 }
 

=== modified file 'src/store_digest.cc'
--- src/store_digest.cc	2012-09-18 21:05:32 +0000
+++ src/store_digest.cc	2012-10-09 04:39:01 +0000
@@ -393,7 +393,7 @@
     /* make new store entry */
     url = internalLocalUri("/squid-internal-periodic/", StoreDigestFileName);
     flags.cachable = 1;
-    e = storeCreateEntry(url, url, flags, METHOD_GET);
+    e = storeCreateEntry(url, url, flags, Http::METHOD_GET);
     assert(e);
     sd_state.rewrite_lock = e;
     debugs(71, 3, "storeDigestRewrite: url: " << url << " key: " << e->getMD5Text());

=== modified file 'src/tests/testHttpRequest.cc'
--- src/tests/testHttpRequest.cc	2012-08-31 16:57:39 +0000
+++ src/tests/testHttpRequest.cc	2012-10-09 04:39:01 +0000
@@ -36,11 +36,11 @@
     /* vanilla url */
     unsigned short expected_port;
     char * url = xstrdup("http://foo:90/bar");
-    HttpRequest *aRequest = HttpRequest::CreateFromUrlAndMethod(url, METHOD_GET);
+    HttpRequest *aRequest = HttpRequest::CreateFromUrlAndMethod(url, Http::METHOD_GET);
     expected_port = 90;
     HttpRequest *nullRequest = NULL;
     CPPUNIT_ASSERT_EQUAL(expected_port, aRequest->port);
-    CPPUNIT_ASSERT(aRequest->method == METHOD_GET);
+    CPPUNIT_ASSERT(aRequest->method == Http::METHOD_GET);
     CPPUNIT_ASSERT_EQUAL(String("foo"), String(aRequest->GetHost()));
     CPPUNIT_ASSERT_EQUAL(String("/bar"), aRequest->urlpath);
     CPPUNIT_ASSERT_EQUAL(AnyP::PROTO_HTTP, aRequest->protocol);
@@ -49,10 +49,10 @@
 
     /* vanilla url, different method */
     url = xstrdup("http://foo/bar");
-    aRequest = HttpRequest::CreateFromUrlAndMethod(url, METHOD_PUT);
+    aRequest = HttpRequest::CreateFromUrlAndMethod(url, Http::METHOD_PUT);
     expected_port = 80;
     CPPUNIT_ASSERT_EQUAL(expected_port, aRequest->port);
-    CPPUNIT_ASSERT(aRequest->method == METHOD_PUT);
+    CPPUNIT_ASSERT(aRequest->method == Http::METHOD_PUT);
     CPPUNIT_ASSERT_EQUAL(String("foo"), String(aRequest->GetHost()));
     CPPUNIT_ASSERT_EQUAL(String("/bar"), aRequest->urlpath);
     CPPUNIT_ASSERT_EQUAL(AnyP::PROTO_HTTP, aRequest->protocol);
@@ -60,16 +60,16 @@
 
     /* a connect url with non-CONNECT data */
     url = xstrdup(":foo/bar");
-    aRequest = HttpRequest::CreateFromUrlAndMethod(url, METHOD_CONNECT);
+    aRequest = HttpRequest::CreateFromUrlAndMethod(url, Http::METHOD_CONNECT);
     xfree(url);
     CPPUNIT_ASSERT_EQUAL(nullRequest, aRequest);
 
     /* a CONNECT url with CONNECT data */
     url = xstrdup("foo:45");
-    aRequest = HttpRequest::CreateFromUrlAndMethod(url, METHOD_CONNECT);
+    aRequest = HttpRequest::CreateFromUrlAndMethod(url, Http::METHOD_CONNECT);
     expected_port = 45;
     CPPUNIT_ASSERT_EQUAL(expected_port, aRequest->port);
-    CPPUNIT_ASSERT(aRequest->method == METHOD_CONNECT);
+    CPPUNIT_ASSERT(aRequest->method == Http::METHOD_CONNECT);
     CPPUNIT_ASSERT_EQUAL(String("foo"), String(aRequest->GetHost()));
     CPPUNIT_ASSERT_EQUAL(String(""), aRequest->urlpath);
     CPPUNIT_ASSERT_EQUAL(AnyP::PROTO_NONE, aRequest->protocol);
@@ -89,7 +89,7 @@
     HttpRequest *aRequest = HttpRequest::CreateFromUrl(url);
     expected_port = 90;
     CPPUNIT_ASSERT_EQUAL(expected_port, aRequest->port);
-    CPPUNIT_ASSERT(aRequest->method == METHOD_GET);
+    CPPUNIT_ASSERT(aRequest->method == Http::METHOD_GET);
     CPPUNIT_ASSERT_EQUAL(String("foo"), String(aRequest->GetHost()));
     CPPUNIT_ASSERT_EQUAL(String("/bar"), aRequest->urlpath);
     CPPUNIT_ASSERT_EQUAL(AnyP::PROTO_HTTP, aRequest->protocol);
@@ -109,10 +109,10 @@
 
     /* valid IPv6 address without port */
     url = xstrdup("http://[2000:800::45]/foo");
-    aRequest = HttpRequest::CreateFromUrlAndMethod(url, METHOD_GET);
+    aRequest = HttpRequest::CreateFromUrlAndMethod(url, Http::METHOD_GET);
     expected_port = 80;
     CPPUNIT_ASSERT_EQUAL(expected_port, aRequest->port);
-    CPPUNIT_ASSERT(aRequest->method == METHOD_GET);
+    CPPUNIT_ASSERT(aRequest->method == Http::METHOD_GET);
     CPPUNIT_ASSERT_EQUAL(String("[2000:800::45]"), String(aRequest->GetHost()));
     CPPUNIT_ASSERT_EQUAL(String("/foo"), aRequest->urlpath);
     CPPUNIT_ASSERT_EQUAL(AnyP::PROTO_HTTP, aRequest->protocol);
@@ -121,10 +121,10 @@
 
     /* valid IPv6 address with port */
     url = xstrdup("http://[2000:800::45]:90/foo");
-    aRequest = HttpRequest::CreateFromUrlAndMethod(url, METHOD_GET);
+    aRequest = HttpRequest::CreateFromUrlAndMethod(url, Http::METHOD_GET);
     expected_port = 90;
     CPPUNIT_ASSERT_EQUAL(expected_port, aRequest->port);
-    CPPUNIT_ASSERT(aRequest->method == METHOD_GET);
+    CPPUNIT_ASSERT(aRequest->method == Http::METHOD_GET);
     CPPUNIT_ASSERT_EQUAL(String("[2000:800::45]"), String(aRequest->GetHost()));
     CPPUNIT_ASSERT_EQUAL(String("/foo"), aRequest->urlpath);
     CPPUNIT_ASSERT_EQUAL(AnyP::PROTO_HTTP, aRequest->protocol);
@@ -133,10 +133,10 @@
 
     /* IPv6 address as invalid (bug trigger) */
     url = xstrdup("http://2000:800::45/foo");
-    aRequest = HttpRequest::CreateFromUrlAndMethod(url, METHOD_GET);
+    aRequest = HttpRequest::CreateFromUrlAndMethod(url, Http::METHOD_GET);
     expected_port = 80;
     CPPUNIT_ASSERT_EQUAL(expected_port, aRequest->port);
-    CPPUNIT_ASSERT(aRequest->method == METHOD_GET);
+    CPPUNIT_ASSERT(aRequest->method == Http::METHOD_GET);
     CPPUNIT_ASSERT_EQUAL(String("[2000:800::45]"), String(aRequest->GetHost()));
     CPPUNIT_ASSERT_EQUAL(String("/foo"), aRequest->urlpath);
     CPPUNIT_ASSERT_EQUAL(AnyP::PROTO_HTTP, aRequest->protocol);

=== modified file 'src/tests/testHttpRequestMethod.cc'
--- src/tests/testHttpRequestMethod.cc	2012-08-28 13:00:30 +0000
+++ src/tests/testHttpRequestMethod.cc	2012-08-30 16:38:04 +0000
@@ -19,11 +19,11 @@
 void
 testHttpRequestMethod::testConstructCharStart()
 {
-    /* parse an empty string -> METHOD_NONE */
-    CPPUNIT_ASSERT(HttpRequestMethod(NULL,NULL) == METHOD_NONE);
+    /* parse an empty string -> Http::METHOD_NONE */
+    CPPUNIT_ASSERT(HttpRequestMethod(NULL,NULL) == Http::METHOD_NONE);
     /* parsing a literal should work */
-    CPPUNIT_ASSERT(HttpRequestMethod("GET", NULL) == METHOD_GET);
-    CPPUNIT_ASSERT(HttpRequestMethod("QWERTY", NULL) == METHOD_OTHER);
+    CPPUNIT_ASSERT(HttpRequestMethod("GET", NULL) == Http::METHOD_GET);
+    CPPUNIT_ASSERT(HttpRequestMethod("QWERTY", NULL) == Http::METHOD_OTHER);
 }
 
 /*
@@ -33,48 +33,48 @@
 testHttpRequestMethod::testConstructCharStartEnd()
 {
     char const * buffer;
-    /* parse an empty string -> METHOD_NONE */
-    CPPUNIT_ASSERT(HttpRequestMethod(NULL, NULL) == METHOD_NONE);
+    /* parse an empty string -> Http::METHOD_NONE */
+    CPPUNIT_ASSERT(HttpRequestMethod(NULL, NULL) == Http::METHOD_NONE);
     /* parsing a literal should work */
-    CPPUNIT_ASSERT(HttpRequestMethod("GET", NULL) == METHOD_GET);
+    CPPUNIT_ASSERT(HttpRequestMethod("GET", NULL) == Http::METHOD_GET);
     /* parsing with an explicit end should work */
     buffer = "POSTPLUS";
-    CPPUNIT_ASSERT(HttpRequestMethod(buffer, buffer + 4) == METHOD_POST);
+    CPPUNIT_ASSERT(HttpRequestMethod(buffer, buffer + 4) == Http::METHOD_POST);
 }
 
 /*
- * we should be able to assign a method_t to a HttpRequestMethod
+ * we should be able to assign a Http::MethodType to a HttpRequestMethod
  */
 void
 testHttpRequestMethod::testAssignFrommethod_t()
 {
     HttpRequestMethod method;
-    method = METHOD_NONE;
-    CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(METHOD_NONE), method);
-    method = METHOD_POST;
-    CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(METHOD_POST), method);
+    method = Http::METHOD_NONE;
+    CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(Http::METHOD_NONE), method);
+    method = Http::METHOD_POST;
+    CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(Http::METHOD_POST), method);
 }
 
 /*
- * a default constructed HttpRequestMethod is == METHOD_NONE
+ * a default constructed HttpRequestMethod is == Http::METHOD_NONE
  */
 void
 testHttpRequestMethod::testDefaultConstructor()
 {
     HttpRequestMethod lhs;
-    HttpRequestMethod rhs(METHOD_NONE);
+    HttpRequestMethod rhs(Http::METHOD_NONE);
     CPPUNIT_ASSERT_EQUAL(lhs, rhs);
 }
 
 /*
- * we should be able to construct a HttpRequestMethod from a method_t
+ * we should be able to construct a HttpRequestMethod from a Http::MethodType
  */
 void
 testHttpRequestMethod::testConstructmethod_t()
 {
-    CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(METHOD_NONE), HttpRequestMethod(METHOD_NONE));
-    CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(METHOD_POST), HttpRequestMethod(METHOD_POST));
-    CPPUNIT_ASSERT(HttpRequestMethod(METHOD_NONE) != HttpRequestMethod(METHOD_POST));
+    CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(Http::METHOD_NONE), HttpRequestMethod(Http::METHOD_NONE));
+    CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(Http::METHOD_POST), HttpRequestMethod(Http::METHOD_POST));
+    CPPUNIT_ASSERT(HttpRequestMethod(Http::METHOD_NONE) != HttpRequestMethod(Http::METHOD_POST));
 }
 
 /*
@@ -87,16 +87,16 @@
 }
 
 /*
- * an HttpRequestMethod should be comparable to a method_t without false
+ * an HttpRequestMethod should be comparable to a Http::MethodType without false
  * matches
  */
 void
 testHttpRequestMethod::testEqualmethod_t()
 {
-    CPPUNIT_ASSERT(HttpRequestMethod(METHOD_NONE) == METHOD_NONE);
-    CPPUNIT_ASSERT(not (HttpRequestMethod(METHOD_POST) == METHOD_GET));
-    CPPUNIT_ASSERT(HttpRequestMethod(METHOD_GET) == METHOD_GET);
-    CPPUNIT_ASSERT(not (HttpRequestMethod(METHOD_TRACE) == METHOD_SEARCH));
+    CPPUNIT_ASSERT(HttpRequestMethod(Http::METHOD_NONE) == Http::METHOD_NONE);
+    CPPUNIT_ASSERT(not (HttpRequestMethod(Http::METHOD_POST) == Http::METHOD_GET));
+    CPPUNIT_ASSERT(HttpRequestMethod(Http::METHOD_GET) == Http::METHOD_GET);
+    CPPUNIT_ASSERT(not (HttpRequestMethod(Http::METHOD_TRACE) == Http::METHOD_SEARCH));
 }
 
 /*
@@ -105,10 +105,10 @@
 void
 testHttpRequestMethod::testNotEqualmethod_t()
 {
-    CPPUNIT_ASSERT(HttpRequestMethod(METHOD_NONE) != METHOD_GET);
-    CPPUNIT_ASSERT(not (HttpRequestMethod(METHOD_POST) != METHOD_POST));
-    CPPUNIT_ASSERT(HttpRequestMethod(METHOD_GET) != METHOD_NONE);
-    CPPUNIT_ASSERT(not (HttpRequestMethod(METHOD_SEARCH) != METHOD_SEARCH));
+    CPPUNIT_ASSERT(HttpRequestMethod(Http::METHOD_NONE) != Http::METHOD_GET);
+    CPPUNIT_ASSERT(not (HttpRequestMethod(Http::METHOD_POST) != Http::METHOD_POST));
+    CPPUNIT_ASSERT(HttpRequestMethod(Http::METHOD_GET) != Http::METHOD_NONE);
+    CPPUNIT_ASSERT(not (HttpRequestMethod(Http::METHOD_SEARCH) != Http::METHOD_SEARCH));
 }
 
 /*

=== modified file 'src/tests/testRock.cc'
--- src/tests/testRock.cc	2012-09-24 19:34:52 +0000
+++ src/tests/testRock.cc	2012-10-09 04:39:01 +0000
@@ -177,7 +177,7 @@
     snprintf(url, sizeof(url), "dummy url %i", i);
     url[sizeof(url) - 1] = '\0';
     StoreEntry *const pe =
-        storeCreateEntry(url, "dummy log url", flags, METHOD_GET);
+        storeCreateEntry(url, "dummy log url", flags, Http::METHOD_GET);
     HttpReply *const rep = const_cast<HttpReply *>(pe->getReply());
     rep->setHeaders(HTTP_OK, "dummy test object", "x-squid-internal/test",
                     -1, -1, squid_curtime + 100000);

=== modified file 'src/tests/testUfs.cc'
--- src/tests/testUfs.cc	2012-09-18 21:05:32 +0000
+++ src/tests/testUfs.cc	2012-10-09 04:39:01 +0000
@@ -143,7 +143,7 @@
         /* Create "vary" base object */
         RequestFlags flags;
         flags.cachable = 1;
-        StoreEntry *pe = storeCreateEntry("dummy url", "dummy log url", flags, METHOD_GET);
+        StoreEntry *pe = storeCreateEntry("dummy url", "dummy log url", flags, Http::METHOD_GET);
         HttpReply *rep = (HttpReply *) pe->getReply();	// bypass const
         rep->setHeaders(HTTP_OK, "dummy test object", "x-squid-internal/test", -1, -1, squid_curtime + 100000);
 

=== modified file 'src/url.cc'
--- src/url.cc	2012-10-10 17:06:38 +0000
+++ src/url.cc	2012-10-11 06:19:35 +0000
@@ -201,7 +201,7 @@
  * This abuses HttpRequest as a way of representing the parsed url
  * and its components.
  * method is used to switch parsers and to init the HttpRequest.
- * If method is METHOD_CONNECT, then rather than a URL a hostname:port is
+ * If method is Http::METHOD_CONNECT, then rather than a URL a hostname:port is
  * looked for.
  * The url is non const so that if its too long we can NULL-terminate it in place.
  */
@@ -236,14 +236,14 @@
         debugs(23, DBG_IMPORTANT, "urlParse: URL too large (" << l << " bytes)");
         return NULL;
     }
-    if (method == METHOD_CONNECT) {
+    if (method == Http::METHOD_CONNECT) {
         port = CONNECT_PORT;
 
         if (sscanf(url, "[%[^]]]:%d", host, &port) < 1)
             if (sscanf(url, "%[^:]:%d", host, &port) < 1)
                 return NULL;
 
-    } else if ((method == METHOD_OPTIONS || method == METHOD_TRACE) &&
+    } else if ((method == Http::METHOD_OPTIONS || method == Http::METHOD_TRACE) &&
                strcmp(url, "*") == 0) {
         protocol = AnyP::PROTO_HTTP;
         port = urlDefaultPort(protocol);
@@ -497,7 +497,6 @@
 urlCanonical(HttpRequest * request)
 {
     LOCAL_ARRAY(char, portbuf, 32);
-/// \todo AYJ: Performance: making this a ptr and allocating when needed will be better than a write and future xstrdup().
     LOCAL_ARRAY(char, urlbuf, MAX_URL);
 
     if (request->canonical)
@@ -506,31 +505,22 @@
     if (request->protocol == AnyP::PROTO_URN) {
         snprintf(urlbuf, MAX_URL, "urn:" SQUIDSTRINGPH,
                  SQUIDSTRINGPRINT(request->urlpath));
+    } else if (request->method.id() == Http::METHOD_CONNECT) {
+        snprintf(urlbuf, MAX_URL, "%s:%d", request->GetHost(), request->port);
     } else {
-/// \todo AYJ: this could use "if..else and method == METHOD_CONNECT" easier.
-        switch (request->method.id()) {
-
-        case METHOD_CONNECT:
-            snprintf(urlbuf, MAX_URL, "%s:%d", request->GetHost(), request->port);
-            break;
-
-        default:
-            portbuf[0] = '\0';
-
-            if (request->port != urlDefaultPort(request->protocol))
-                snprintf(portbuf, 32, ":%d", request->port);
-
-            const URLScheme sch = request->protocol; // temporary, until bug 1961 URL handling is fixed.
-            snprintf(urlbuf, MAX_URL, "%s://%s%s%s%s" SQUIDSTRINGPH,
-                     sch.const_str(),
-                     request->login,
-                     *request->login ? "@" : null_string,
-                     request->GetHost(),
-                     portbuf,
-                     SQUIDSTRINGPRINT(request->urlpath));
-
-            break;
-        }
+        portbuf[0] = '\0';
+
+        if (request->port != urlDefaultPort(request->protocol))
+            snprintf(portbuf, 32, ":%d", request->port);
+
+        const URLScheme sch = request->protocol; // temporary, until bug 1961 URL handling is fixed.
+        snprintf(urlbuf, MAX_URL, "%s://%s%s%s%s" SQUIDSTRINGPH,
+                 sch.const_str(),
+                 request->login,
+                 *request->login ? "@" : null_string,
+                 request->GetHost(),
+                 portbuf,
+                 SQUIDSTRINGPRINT(request->urlpath));
     }
 
     return (request->canonical = xstrdup(urlbuf));
@@ -551,52 +541,39 @@
     if (request->protocol == AnyP::PROTO_URN) {
         snprintf(buf, MAX_URL, "urn:" SQUIDSTRINGPH,
                  SQUIDSTRINGPRINT(request->urlpath));
+    } else if (request->method.id() == Http::METHOD_CONNECT) {
+        snprintf(buf, MAX_URL, "%s:%d", request->GetHost(), request->port);
     } else {
-/// \todo AYJ: this could use "if..else and method == METHOD_CONNECT" easier.
-        switch (request->method.id()) {
-
-        case METHOD_CONNECT:
-            snprintf(buf, MAX_URL, "%s:%d",
-                     request->GetHost(),
-                     request->port);
-            break;
-
-        default:
-            portbuf[0] = '\0';
-
-            if (request->port != urlDefaultPort(request->protocol))
-                snprintf(portbuf, 32, ":%d", request->port);
-
-            loginbuf[0] = '\0';
-
-            if ((int) strlen(request->login) > 0) {
-                strcpy(loginbuf, request->login);
-
-                if ((t = strchr(loginbuf, ':')))
-                    *t = '\0';
-
-                strcat(loginbuf, "@");
-            }
-
-            const URLScheme sch = request->protocol; // temporary, until bug 1961 URL handling is fixed.
-            snprintf(buf, MAX_URL, "%s://%s%s%s" SQUIDSTRINGPH,
-                     sch.const_str(),
-                     loginbuf,
-                     request->GetHost(),
-                     portbuf,
-                     SQUIDSTRINGPRINT(request->urlpath));
-            /*
-             * strip arguments AFTER a question-mark
-             */
-
-            if (Config.onoff.strip_query_terms)
-                if ((t = strchr(buf, '?'))) {
-                    ++t;
-                    *t = '\0';
-                }
-
-            break;
+        portbuf[0] = '\0';
+
+        if (request->port != urlDefaultPort(request->protocol))
+            snprintf(portbuf, 32, ":%d", request->port);
+
+        loginbuf[0] = '\0';
+
+        if ((int) strlen(request->login) > 0) {
+            strcpy(loginbuf, request->login);
+
+            if ((t = strchr(loginbuf, ':')))
+                *t = '\0';
+
+            strcat(loginbuf, "@");
         }
+
+        const URLScheme sch = request->protocol; // temporary, until bug 1961 URL handling is fixed.
+        snprintf(buf, MAX_URL, "%s://%s%s%s" SQUIDSTRINGPH,
+                 sch.const_str(),
+                 loginbuf,
+                 request->GetHost(),
+                 portbuf,
+                 SQUIDSTRINGPRINT(request->urlpath));
+        /*
+         * strip arguments AFTER a question-mark
+         */
+
+        if (Config.onoff.strip_query_terms)
+            if ((t = strchr(buf, '?')))
+                *(++t) = '\0';
     }
 
     if (stringHasCntl(buf))
@@ -607,7 +584,7 @@
 
 /**
  * Yet another alternative to urlCanonical.
- * This one addes the https:// parts to METHOD_CONNECT URL
+ * This one adds the https:// parts to Http::METHOD_CONNECT URL
  * for use in error page outputs.
  * Luckily we can leverage the others instead of duplicating.
  */
@@ -617,7 +594,7 @@
     LOCAL_ARRAY(char, buf, MAX_URL);
 
     // method CONNECT and port HTTPS
-    if (request->method == METHOD_CONNECT && request->port == 443) {
+    if (request->method == Http::METHOD_CONNECT && request->port == 443) {
         snprintf(buf, MAX_URL, "https://%s/*", request->GetHost());
         return buf;
     }
@@ -669,7 +646,7 @@
 urlMakeAbsolute(const HttpRequest * req, const char *relUrl)
 {
 
-    if (req->method.id() == METHOD_CONNECT) {
+    if (req->method.id() == Http::METHOD_CONNECT) {
         return (NULL);
     }
 
@@ -840,15 +817,15 @@
      * do not have a default protocol from the client side of HTTP.
      */
 
-    if (r->method == METHOD_CONNECT)
+    if (r->method == Http::METHOD_CONNECT)
         return 1;
 
     // we support OPTIONS and TRACE directed at us (with a 501 reply, for now)
     // we also support forwarding OPTIONS and TRACE, except for the *-URI ones
-    if (r->method == METHOD_OPTIONS || r->method == METHOD_TRACE)
+    if (r->method == Http::METHOD_OPTIONS || r->method == Http::METHOD_TRACE)
         return (r->header.getInt64(HDR_MAX_FORWARDS) == 0 || r->urlpath != "*");
 
-    if (r->method == METHOD_PURGE)
+    if (r->method == Http::METHOD_PURGE)
         return 1;
 
     /* does method match the protocol? */
@@ -864,7 +841,7 @@
 
     case AnyP::PROTO_FTP:
 
-        if (r->method == METHOD_PUT)
+        if (r->method == Http::METHOD_PUT)
             rc = 1;
 
     case AnyP::PROTO_GOPHER:
@@ -872,9 +849,9 @@
     case AnyP::PROTO_WAIS:
 
     case AnyP::PROTO_WHOIS:
-        if (r->method == METHOD_GET)
+        if (r->method == Http::METHOD_GET)
             rc = 1;
-        else if (r->method == METHOD_HEAD)
+        else if (r->method == Http::METHOD_HEAD)
             rc = 1;
 
         break;

=== modified file 'src/urn.cc'
--- src/urn.cc	2012-09-17 13:31:37 +0000
+++ src/urn.cc	2012-10-09 04:46:13 +0000
@@ -247,7 +247,7 @@
     if (urlres_r == NULL)
         return;
 
-    StoreEntry::getPublic (this, urlres, METHOD_GET);
+    StoreEntry::getPublic (this, urlres, Http::METHOD_GET);
 }
 
 void
@@ -256,7 +256,7 @@
     urlres_e = newEntry;
 
     if (urlres_e->isNull()) {
-        urlres_e = storeCreateEntry(urlres, urlres, RequestFlags(), METHOD_GET);
+        urlres_e = storeCreateEntry(urlres, urlres, RequestFlags(), Http::METHOD_GET);
         sc = storeClientListAdd(urlres_e, this);
         FwdState::fwdStart(Comm::ConnectionPointer(), urlres_e, urlres_r);
     } else {

