=== modified file 'src/client_side.cc'
--- src/client_side.cc	2011-03-09 19:02:12 +0000
+++ src/client_side.cc	2011-03-10 12:43:33 +0000
@@ -1897,48 +1897,86 @@
         end = uriAndHTTPVersion + strcspn(uriAndHTTPVersion, "\r\n");
         assert(end);
     }
 
     for (; end > uriAndHTTPVersion; end--) {
         if (*end == '\n' || *end == '\r')
             continue;
 
         if (xisspace(*end)) {
             if (strncasecmp(end + 1, "HTTP/", 5) == 0)
                 return end + 1;
             else
                 break;
         }
     }
 
     return NULL;
 }
 
 void
-setLogUri(ClientHttpRequest * http, char const *uri)
+setLogUri(ClientHttpRequest * http, char const *uri, bool cleanUrl)
 {
     safe_free(http->log_uri);
 
-    if (!stringHasCntl(uri))
+    if (!cleanUrl)
+        // The uri is already clean just dump it.
         http->log_uri = xstrndup(uri, MAX_URL);
-    else
-        http->log_uri = xstrndup(rfc1738_escape_unescaped(uri), MAX_URL);
+    else {
+            int flags = 0;
+            switch (Config.uri_whitespace) {
+            case URI_WHITESPACE_ALLOW:
+                flags |= RFC1738_ESCAPE_NOSPACE;
+
+            case URI_WHITESPACE_ENCODE:
+                flags |= RFC1738_ESCAPE_UNESCAPED;
+                http->log_uri = xstrndup(rfc1738_do_escape(uri, flags), MAX_URL);
+                break;
+
+            case URI_WHITESPACE_CHOP: {
+                flags |= RFC1738_ESCAPE_NOSPACE;
+                flags |= RFC1738_ESCAPE_UNESCAPED;
+                http->log_uri = xstrndup(rfc1738_do_escape(uri, flags), MAX_URL);
+                int pos = strcspn(http->log_uri, w_space);
+                http->log_uri[pos] = '\0';
+            }
+                break;
+                
+            case URI_WHITESPACE_DENY:
+            case URI_WHITESPACE_STRIP:
+            default: {
+                const char *t;
+                char *tmp_uri = static_cast<char*>(xmalloc(strlen(uri) + 1));
+                char *q = tmp_uri;
+                t = uri;
+                while (*t) {
+                    if (!xisspace(*t))
+                        *q++ = *t;
+                    t++;
+                }
+                *q = '\0';
+                http->log_uri = xstrndup(rfc1738_escape_unescaped(tmp_uri), MAX_URL);
+                xfree(tmp_uri);
+            }
+                break;
+            }
+    }
 }
 
 static void
 prepareAcceleratedURL(ConnStateData * conn, ClientHttpRequest *http, char *url, const char *req_hdr)
 {
     int vhost = conn->port->vhost;
     int vport = conn->port->vport;
     char *host;
     char ipbuf[MAX_IPSTRLEN];
 
     http->flags.accel = 1;
 
     /* BUG: Squid cannot deal with '*' URLs (RFC2616 5.1.2) */
 
     if (strncasecmp(url, "cache_object://", 15) == 0)
         return; /* already in good shape */
 
     if (*url != '/') {
         if (conn->port->vhost)
             return; /* already in good shape */
@@ -2207,41 +2245,40 @@
 
     } else if (conn->port->accel || conn->switchedToHttps()) {
         /* accelerator mode */
         prepareAcceleratedURL(conn, http, url, req_hdr);
 
     } else if (internalCheck(url)) {
         /* internal URL mode */
         /* prepend our name & port */
         http->uri = xstrdup(internalLocalUri(NULL, url));
         http->flags.accel = 1;
     }
 
     if (!http->uri) {
         /* No special rewrites have been applied above, use the
          * requested url. may be rewritten later, so make extra room */
         int url_sz = strlen(url) + Config.appendDomainLen + 5;
         http->uri = (char *)xcalloc(url_sz, 1);
         strcpy(http->uri, url);
     }
 
-    setLogUri(http, http->uri);
     debugs(33, 5, "parseHttpRequest: Complete request received");
     result->flags.parsed_ok = 1;
     xfree(url);
     return result;
 }
 
 int
 ConnStateData::getAvailableBufferLength() const
 {
     int result = in.allocatedSize - in.notYetUsed - 1;
     assert (result >= 0);
     return result;
 }
 
 bool
 ConnStateData::maybeMakeSpaceAvailable()
 {
     if (getAvailableBufferLength() < 2) {
         size_t newSize;
         if (in.allocatedSize >= Config.maxRequestBufferSize) {
@@ -2378,93 +2415,101 @@
 }
 
 static void
 clientProcessRequest(ConnStateData *conn, HttpParser *hp, ClientSocketContext *context, const HttpRequestMethod& method, HttpVersion http_ver)
 {
     ClientHttpRequest *http = context->http;
     HttpRequest *request = NULL;
     bool notedUseOfBuffer = false;
     bool chunked = false;
     bool mustReplyToOptions = false;
     bool unsupportedTe = false;
     bool expectBody = false;
 
     /* We have an initial client stream in place should it be needed */
     /* setup our private context */
     context->registerWithConn();
 
     if (context->flags.parsed_ok == 0) {
         clientStreamNode *node = context->getClientReplyContext();
         debugs(33, 1, "clientProcessRequest: Invalid Request");
+        // setLogUri should called before repContext->setReplyToError
+        setLogUri(http, http->uri,  true);
         clientReplyContext *repContext = dynamic_cast<clientReplyContext *>(node->data.getRaw());
         assert (repContext);
         switch (hp->request_parse_status) {
         case HTTP_HEADER_TOO_LARGE:
             repContext->setReplyToError(ERR_TOO_BIG, HTTP_BAD_REQUEST, method, http->uri, conn->peer, NULL, conn->in.buf, NULL);
             break;
         case HTTP_METHOD_NOT_ALLOWED:
             repContext->setReplyToError(ERR_UNSUP_REQ, HTTP_METHOD_NOT_ALLOWED, method, http->uri, conn->peer, NULL, conn->in.buf, NULL);
             break;
         default:
             repContext->setReplyToError(ERR_INVALID_REQ, HTTP_BAD_REQUEST, method, http->uri, conn->peer, NULL, conn->in.buf, NULL);
         }
         assert(context->http->out.offset == 0);
         context->pullData();
         conn->flags.readMoreRequests = false;
         goto finish;
     }
 
     if ((request = HttpRequest::CreateFromUrlAndMethod(http->uri, method)) == NULL) {
         clientStreamNode *node = context->getClientReplyContext();
         debugs(33, 5, "Invalid URL: " << http->uri);
+        // setLogUri should called before repContext->setReplyToError
+        setLogUri(http, http->uri,  true);
         clientReplyContext *repContext = dynamic_cast<clientReplyContext *>(node->data.getRaw());
         assert (repContext);
         repContext->setReplyToError(ERR_INVALID_URL, HTTP_BAD_REQUEST, method, http->uri, conn->peer, NULL, NULL, NULL);
         assert(context->http->out.offset == 0);
         context->pullData();
         conn->flags.readMoreRequests = false;
         goto finish;
     }
 
     /* RFC 2616 section 10.5.6 : handle unsupported HTTP versions cleanly. */
     /* We currently only accept 0.9, 1.0, 1.1 */
     if ( (http_ver.major == 0 && http_ver.minor != 9) ||
             (http_ver.major == 1 && http_ver.minor > 1 ) ||
             (http_ver.major > 1) ) {
 
         clientStreamNode *node = context->getClientReplyContext();
         debugs(33, 5, "Unsupported HTTP version discovered. :\n" << HttpParserHdrBuf(hp));
+        // setLogUri should called before repContext->setReplyToError
+        setLogUri(http, http->uri,  true);
         clientReplyContext *repContext = dynamic_cast<clientReplyContext *>(node->data.getRaw());
         assert (repContext);
         repContext->setReplyToError(ERR_UNSUP_HTTPVERSION, HTTP_HTTP_VERSION_NOT_SUPPORTED, method, http->uri, conn->peer, NULL, HttpParserHdrBuf(hp), NULL);
         assert(context->http->out.offset == 0);
         context->pullData();
         conn->flags.readMoreRequests = false;
         goto finish;
     }
 
     /* compile headers */
     /* we should skip request line! */
     /* XXX should actually know the damned buffer size here */
     if (http_ver.major >= 1 && !request->parseHeader(HttpParserHdrBuf(hp), HttpParserHdrSz(hp))) {
         clientStreamNode *node = context->getClientReplyContext();
         debugs(33, 5, "Failed to parse request headers:\n" << HttpParserHdrBuf(hp));
+        // setLogUri should called before repContext->setReplyToError
+        setLogUri(http, http->uri,  true);
         clientReplyContext *repContext = dynamic_cast<clientReplyContext *>(node->data.getRaw());
         assert (repContext);
         repContext->setReplyToError(ERR_INVALID_REQ, HTTP_BAD_REQUEST, method, http->uri, conn->peer, NULL, NULL, NULL);
         assert(context->http->out.offset == 0);
         context->pullData();
         conn->flags.readMoreRequests = false;
         goto finish;
     }
 
     request->flags.accelerated = http->flags.accel;
     request->flags.ignore_cc = conn->port->ignore_cc;
     request->flags.no_direct = request->flags.accelerated ? !conn->port->allow_direct : 0;
 
     /** \par
      * If transparent or interception mode is working clone the transparent and interception flags
      * from the port settings to the request.
      */
     if (Ip::Interceptor.InterceptActive()) {
         request->flags.intercepted = http->flags.intercepted;
     }

=== modified file 'src/client_side.h'
--- src/client_side.h	2011-02-07 10:27:53 +0000
+++ src/client_side.h	2011-03-06 18:06:29 +0000
@@ -304,25 +304,25 @@
 private:
     int connReadWasError(comm_err_t flag, int size, int xerrno);
     int connFinishedWithConn(int size);
     void clientMaybeReadData(int do_next_read);
     void clientAfterReadingRequests(int do_next_read);
 
 private:
     CBDATA_CLASS2(ConnStateData);
     bool transparent_;
     bool closing_;
 
     bool switchedToHttps_;
     String sslHostName; ///< Host name for SSL certificate generation
     AsyncCall::Pointer reader; ///< set when we are reading
     BodyPipe::Pointer bodyPipe; // set when we are reading request body
 };
 
 /* convenience class while splitting up body handling */
 /* temporary existence only - on stack use expected */
 
-void setLogUri(ClientHttpRequest * http, char const *uri);
+void setLogUri(ClientHttpRequest * http, char const *uri, bool cleanUrl = false);
 
 const char *findTrailingHTTPVersion(const char *uriAndHTTPVersion, const char *end = NULL);
 
 #endif /* SQUID_CLIENTSIDE_H */


