handle.cc (3718B)
1 #include "httpdispatcher" 2 3 void HttpDispatcher::handle() { 4 PROFILE("HttpDispatcher::handle"); 5 6 // The client request was already retrieved before starting the 7 // dispatcher. We can continue by applying server-directed headers. 8 if (config.addxrversion()) 9 buf().setheader ("XR", VER); 10 if (config.addxforwardedfor()) 11 buf().addheader ("X-Forwarded-For", 12 inet2string(clientfd().clientaddr().sin_addr)); 13 for (unsigned n = 0; n < config.nserverheaders(); n++) 14 buf().setheader (config.serverheader(n)); 15 16 // Patch up the Host: header if requested so. 17 if (config.replacehostheader()) { 18 ostringstream o; 19 o << balancer.backend(targetbackend()).server() 20 << ":" << balancer.backend(targetbackend()).port(); 21 buf().replaceheader("Host:", o.str()); 22 } 23 24 // Flush client info received so far to the back end. 25 debugmsg("Sending client request to back end\n"); 26 buf().netwrite(backendfd(), config.backend_write_timeout()); 27 28 // Let's see if we will need to modify the server headers. 29 bool modify_serverheaders = false; 30 if (config.addxrversion() || 31 (config.stickyhttp() && !issticky())) 32 modify_serverheaders = true; 33 34 // Store the client request. May want to log it later. 35 string client_request = buf().firstline(); 36 37 // Go into copy-thru mode. If required, catch the server headers on 38 // their first appearance and modify them. 39 bool backend_response_checked = false; 40 while (1) { 41 Fdset readset (maxtimeout(config.client_read_timeout(), 42 config.backend_read_timeout())); 43 readset.add(clientfd()); 44 readset.add(backendfd()); 45 readset.wait_r(); 46 47 Socket sock; 48 unsigned timeout; 49 if (readset.readable(clientfd())) { 50 sock = clientfd(); 51 timeout = config.client_read_timeout(); 52 } else if (readset.readable(backendfd())) { 53 sock = backendfd(); 54 timeout = config.backend_read_timeout(); 55 } else 56 break; 57 58 buf().reset(); 59 60 if (!buf().netread(sock, timeout)) 61 break; 62 63 if (sock == backendfd() && modify_serverheaders) { 64 debugmsg("Back end response seen, applying modifications\n"); 65 modify_serverheaders = false; 66 while (! buf().headersreceived()) 67 if (!buf().netread (sock, config.backend_read_timeout())) 68 throw Error("Failed to get headers from back end"); 69 if (config.addxrversion()) 70 buf().setheader("XR", VER); 71 if (config.stickyhttp() && !issticky()) { 72 ostringstream o; 73 o << "XRTarget=" << targetbackend() << "; path=/"; 74 buf().setheader("Set-Cookie", o.str()); 75 } 76 } 77 78 // The back end response may now get flushed to the client. 79 // If the response code is 4** or 5**, log it as a warning. 80 if (!backend_response_checked && 81 sock == backendfd() && buf().headersreceived()) { 82 string respcode = buf().stringat(9, 3); 83 if (respcode[0] == '4' || respcode[0] == '5') 84 warnmsg("HTTP back end indicates fault: '" << 85 buf().firstline() << "' as response to '" << 86 client_request << "'\n"); 87 backend_response_checked = true; 88 } 89 90 // Flush info to the other connected side. 91 Socket othersock; 92 if (sock == clientfd()) { 93 othersock = backendfd(); 94 timeout = config.backend_write_timeout(); 95 // Re-patch Host header if requested 96 if (config.replacehostheader()) { 97 ostringstream o; 98 o << balancer.backend(targetbackend()).server() 99 << ":" << balancer.backend(targetbackend()).port(); 100 buf().replaceheader("Host:", o.str()); 101 } 102 } else { 103 othersock = clientfd(); 104 timeout = config.client_write_timeout(); 105 } 106 107 debugmsg ("Had data on " << sock.fd() << 108 ", sending to " << othersock.fd() << '\n'); 109 110 buf().netwrite(othersock, timeout); 111 if (sock == backendfd()) 112 balancer.backend(targetbackend()).addbytes(buf().bufsz()); 113 } 114 }