Yes, we have tested the patch and it allows us to use pound. Our clients get the response from the backend other than 500 Internal Server error and they can take appropriate action.

Bastiaan

On 12/17/2012 07:53 PM, Joe Gooch wrote:
Neat.

And this solved your issue?

Joe


-----Original Message-----
From: Bastiaan Stougie [mailto:[email protected]]
Sent: Monday, December 17, 2012 11:38 AM
To: [email protected]
Subject: [Pound Mailing List] Re: Forwarding of error responses

I've patched pound myself, here's the diff with respect to Pound 2.6.
The patch does the following:

If the backend unexpectedly closes the connection during transfer of
the content associated with a request from client to backend, and the
backend sent a response before closing the connection, the following
patch will make pound forward that response from the backend to the
client. The previous behavior was that pound would just send "500
Internal Server Error" to the client.

$ diff -u http.c http-patched.c
--- http.c      2011-12-28 14:57:45.000000000 +0100
+++ http-patched.c      2012-12-17 17:29:00.706549200 +0100
@@ -487,7 +487,7 @@
   void
   do_http(thr_arg *arg)
   {
-    int                 cl_11, be_11, res, chunked, n, sock, no_cont,
skip, conn_closed, force_10, sock_proto, is_rpc;
+    int                 cl_11, be_11, res, chunked, n, sock, no_cont,
skip, conn_closed, force_10, sock_proto, is_rpc, be_err_closed;
       LISTENER            *lstn;
       SERVICE             *svc;
       BACKEND             *backend, *cur_backend, *old_backend;
@@ -592,6 +592,7 @@
       BIO_set_buffer_size(cl, MAXBUF);
       cl = BIO_push(bb, cl);

+    be_err_closed = 0;
       for(cl_11 = be_11 = 0;;) {
           res_bytes = L0;
           is_rpc = -1;
@@ -1106,26 +1107,22 @@
           if(cl_11 && chunked) {
               /* had Transfer-encoding: chunked so read/write all the
chunks (HTTP/1.1 only) */
               if(copy_chunks(cl, be, NULL, cur_backend->be_type,
lstn->max_req)) {
+                be_err_closed = 1;
                   str_be(buf, MAXBUF - 1, cur_backend);
                   end_req = cur_time();
                   addr2str(caddr, MAXBUF - 1, &from_host, 1);
-                logmsg(LOG_NOTICE, "(%lx) e500 for %s copy_chunks to
%s/%s (%.3f sec)",
+                logmsg(LOG_NOTICE, "(%lx) error for %s copy_chunks to
%s/%s (%.3f sec)",
                       pthread_self(), caddr, buf, request, (end_req -
start_req) / 1000000.0);
-                err_reply(cl, h500, lstn->err500);
-                clean_all();
-                return;
               }
           } else if(cont > L0 && is_rpc != 1) {
               /* had Content-length, so do raw reads/writes for the
length */
               if(copy_bin(cl, be, cont, NULL, cur_backend->be_type)) {
+                be_err_closed = 1;
                   str_be(buf, MAXBUF - 1, cur_backend);
                   end_req = cur_time();
                   addr2str(caddr, MAXBUF - 1, &from_host, 1);
-                logmsg(LOG_NOTICE, "(%lx) e500 for %s error copy
client
cont to %s/%s: %s (%.3f sec)",
+                logmsg(LOG_NOTICE, "(%lx) error for %s copy client
cont
to %s/%s: %s (%.3f sec)",
                       pthread_self(), caddr, buf, request,
strerror(errno), (end_req - start_req) / 1000000.0);
-                err_reply(cl, h500, lstn->err500);
-                clean_all();
-                return;
               }
           } else if(cont > 0L && is_readable(cl, lstn->to)) {
               char one;
@@ -1156,11 +1153,12 @@
                       if(errno)
                           logmsg(LOG_NOTICE, "(%lx) error write request
pending: %s",
                               pthread_self(), strerror(errno));
-                    clean_all();
-                    pthread_exit(NULL);
+                    be_err_closed = 1;
+                    break;
                   }
               }
-            BIO_flush(be);
+            if (!be_err_closed)
+                BIO_flush(be);

               /*
                * find the socket BIO in the chain @@ -1174,7 +1172,7 @@
               /*
                * copy till EOF
                */
-            while((res = BIO_read(cl_unbuf, buf, MAXBUF)) > 0) {
+            while(!be_err_closed && (res = BIO_read(cl_unbuf, buf,
MAXBUF)) > 0) {
                   if((res_bytes += res) > cont) {
                       logmsg(LOG_NOTICE, "(%lx) error copy request
body:
max. RPC length exceeded",
                           pthread_self()); @@ -1185,8 +1183,7 @@
                       if(errno)
                           logmsg(LOG_NOTICE, "(%lx) error copy request
body: %s",
                               pthread_self(), strerror(errno));
-                    clean_all();
-                    pthread_exit(NULL);
+                    be_err_closed = 1;
                   } else {
                       BIO_flush(be);
                   }
@@ -1194,15 +1191,13 @@
           }

           /* flush to the back-end */
-        if(cur_backend->be_type == 0 && BIO_flush(be) != 1) {
+        if(!be_err_closed && cur_backend->be_type == 0 &&
BIO_flush(be)
!= 1) {
               str_be(buf, MAXBUF - 1, cur_backend);
               end_req = cur_time();
               addr2str(caddr, MAXBUF - 1, &from_host, 1);
               logmsg(LOG_NOTICE, "(%lx) e500 for %s error flush to
%s/%s: %s (%.3f sec)",
                   pthread_self(), caddr, buf, request, strerror(errno),
(end_req - start_req) / 1000000.0);
-            err_reply(cl, h500, lstn->err500);
-            clean_all();
-            return;
+            be_err_closed = 1;
           }

           /*
@@ -1253,7 +1248,7 @@
                       u_name[0]? u_name: "-", req_time, request,
cur_backend->be_type, referer, u_agent);
                   break;
               }
-            if(!cl_11 || conn_closed || force_10)
+            if(be_err_closed || !cl_11 || conn_closed || force_10)
                   break;
               continue;
           } else if(is_rpc == 1) {
@@ -1541,13 +1536,18 @@
           }
           /*
            * Stop processing if:
+         *  - backend closed the connection during transfer of the
content
+         *    (in this case we have still made an attempt to forward
any response
+         *    from the backend to the client, but now we have to stop
because
+         *    of the closed connection)
+         *      or
            *  - client is not HTTP/1.1
            *      or
            *  - we had a "Connection: closed" header
            *      or
            *  - this is an SSL connection and we had a NoHTTPS11
directive
            */
-        if(!cl_11 || conn_closed || force_10)
+        if(be_err_closed || !cl_11 || conn_closed || force_10)
               break;
       }



On 12/11/2012 05:50 PM, Bastiaan Stougie wrote:
Hi,

We are considering to use pound as reverse proxy. During tests, we
have encountered the following issue:

- a client does a PUT request, with non-zero content-length
- pound forwards the PUT request and starts to forward the associated
content
- the server that pound forwards to reads and evaluates the request,
without reading the content yet
- the server that pound forwards to notices a problem with the
request
and responds, then closes the connection without ever reading the
content associated with the PUT request
- pound notices that it can not forward the content (EPIPE), and
immediately responds to the client with "500 Internal Server Error"

In other words, on error, the response from the the server that pound
forwards to never reaches the client, and the client needs more
information than "500 Internal Server Error" to be able to take
appropriate action.

The PUT content can be very big (gigabytes), so reading it completely
and then responding would take the server considerable time and
resources, and would cost much bandwidth.

Would it be possible to have pound attempt to forward the response
back to the client after the forward of the content to the server has
failed?

Thank you,

Bastiaan Stougie


--
To unsubscribe send an email with subject unsubscribe to
[email protected].
Please contact [email protected] for questions.
--
To unsubscribe send an email with subject unsubscribe to [email protected].
Please contact [email protected] for questions.



--
To unsubscribe send an email with subject unsubscribe to [email protected].
Please contact [email protected] for questions.

Reply via email to