dispatch.cc (3433B)
1 #include "httpdispatcher" 2 3 void HttpDispatcher::dispatch() { 4 PROFILE("HttpDispatcher::dispatch"); 5 6 unsigned stickytarget; 7 string host_header = ""; 8 string url = ""; 9 10 // Try to dispatch. Since we're in HTTP mode, we must return an 11 // error page when dispatching fails. 12 try { 13 14 // Get the client's request. May need for cookie inspection or for the 15 // host header. 16 while (!buf().headersreceived()) { 17 // cout << "BUFFER fetching headers: " << buf().as_string() << '\n'; 18 if (! buf().netread(clientfd(), config.client_read_timeout())) { 19 msg("Didn't receive a valid client request, stopping"); 20 throw Error("No HTTP request received"); 21 } 22 } 23 msg("Received client request: '" + buf().firstline() + "'\n"); 24 // cout << "BUFFER with headers: " << buf().as_string() << '\n'; 25 26 // See if hostmatching or urlmatching is used. 27 // This is true when hosts or urls are matched against non-dot. 28 bool hostmatchused = false; 29 bool urlmatchused = false; 30 for (unsigned i = 0; i < balancer.nbackends(); i++) { 31 if (balancer.backend(i).hostmatch() != ".") 32 hostmatchused = true; 33 if (balancer.backend(i).urlmatch() != ".") 34 urlmatchused = true; 35 } 36 37 // Build new target list if host- or url matching applies. 38 if (hostmatchused || urlmatchused) { 39 msg("Creating matched target list for the HTTP dispatcher\n"); 40 41 if (hostmatchused) 42 host_header = buf().headerval("Host"); 43 if (urlmatchused) 44 url = buf().url(); 45 46 BackendVector v; 47 v.isdefined(true); 48 49 for (unsigned i = 0; i < balancer.nbackends(); i++) { 50 if (! balancer.backend(i).available()) 51 continue; 52 bool host_allowed = true, url_allowed = true; 53 if (hostmatchused && 54 regexec(&(balancer.backend(i).hostregex()), 55 host_header.c_str(), 0, 0, 0)) { 56 debugmsg("Back end " + 57 balancer.backend(i).description() + 58 " forbidden due to hostmatch\n"); 59 host_allowed = false; 60 } 61 if (urlmatchused && 62 regexec(&(balancer.backend(i).urlregex()), 63 url.c_str(), 0, 0, 0)) { 64 debugmsg("Back end " + 65 balancer.backend(i).description() + 66 " forbidden due to urlmatch\n"); 67 url_allowed = false; 68 } 69 if (host_allowed && url_allowed) { 70 v.add(i); 71 msg("Candidate target: " + 72 balancer.backend(i).description() + "\n"); 73 } 74 } 75 targetlist(v); 76 } 77 78 // Dispatch as a normal backend if sticky HTTP is off, or if the 79 // sticky target is badly specified. 80 if (!config.stickyhttp() || 81 (sscanf(buf().cookievalue("XRTarget").c_str(), 82 "%d", &stickytarget) < 1 && 83 sscanf(buf().paramvalue("XRTarget").c_str(), 84 "%d", &stickytarget) < 1) || 85 stickytarget >= balancer.nbackends()) { 86 issticky(false); 87 TcpDispatcher::dispatch(); 88 } else { 89 // Got a sticky target. Try to connect. If that fails, fallback 90 // to non-sticky dispatching. 91 targetbackend(stickytarget); 92 Backend tb = balancer.backend(stickytarget); 93 tb.live(true); 94 msg("Sticky HTTP request for " + tb.description() + "\n"); 95 if (! tb.connect()) { 96 balancer.backend(stickytarget).live(false); 97 msg("Failed to connect to back end " + tb.description() + 98 ", trying to dispatch to other\n"); 99 issticky(false); 100 TcpDispatcher::dispatch(); 101 } else { 102 backendfd(tb.sock()); 103 issticky(true); 104 } 105 } 106 107 108 } catch (Error const &e) { 109 senderrorpage(e.what()); 110 throw e; 111 } 112 } 113