proxy_http.c revision 995a11def54f1eb5a39099594d0d8bee4dbb33f4
4458N/A/* ==================================================================== 4458N/A * The Apache Software License, Version 1.1 4458N/A * Copyright (c) 2000-2001 The Apache Software Foundation. All rights 4458N/A * Redistribution and use in source and binary forms, with or without 4458N/A * modification, are permitted provided that the following conditions 4458N/A * 1. Redistributions of source code must retain the above copyright 4458N/A * notice, this list of conditions and the following disclaimer. 4458N/A * 2. Redistributions in binary form must reproduce the above copyright 4458N/A * notice, this list of conditions and the following disclaimer in 4458N/A * the documentation and/or other materials provided with the 4458N/A * 3. The end-user documentation included with the redistribution, 4458N/A * if any, must include the following acknowledgment: 4458N/A * "This product includes software developed by the 4458N/A * Alternately, this acknowledgment may appear in the software itself, 4458N/A * if and wherever such third-party acknowledgments normally appear. 4458N/A * 4. The names "Apache" and "Apache Software Foundation" must 4458N/A * not be used to endorse or promote products derived from this 4458N/A * software without prior written permission. For written 4458N/A * permission, please contact apache@apache.org. 4458N/A * 5. Products derived from this software may not be called "Apache", 4458N/A * nor may "Apache" appear in their name, without prior written 4458N/A * permission of the Apache Software Foundation. 4458N/A * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 4458N/A * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 4458N/A * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 4458N/A * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR 4458N/A * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 4458N/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 4458N/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 4458N/A * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 4458N/A * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 4458N/A * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 4458N/A * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 4458N/A * ==================================================================== 4458N/A * This software consists of voluntary contributions made by many 4458N/A * individuals on behalf of the Apache Software Foundation. For more 4458N/A * information on the Apache Software Foundation, please see 4458N/A * Portions of this software are based upon public domain software 4458N/A * originally written at the National Center for Supercomputing Applications, 4458N/A * University of Illinois, Urbana-Champaign. 4458N/A/* HTTP routines for Apache proxy */ 4458N/A * Canonicalise http-like URLs. 4458N/A * scheme is the scheme for the URL 4458N/A * url is the URL starting with the first '/' 4458N/A * def_port is the default port for this scheme. 4458N/A * We break the URL into host, port, path, search 4458N/A/* N.B. if this isn't a true proxy request, then the URL _path_ 4458N/A * has already been decoded. True proxy requests have r->uri 4458N/A * == r->unparsed_uri, and no others have that property. 4458N/A /* XXX FIXME: Make sure this handled the ambiguous case of the :80 4458N/A/* Clear all connection-based headers from the incoming headers table */ 4458N/A * This handles http:// URLs, and other URLs using a remote proxy over http 4458N/A * If proxyhost is NULL, then contact the server directly, otherwise 4458N/A * Note that if a proxy is used, then URLs other than http: can be accessed, 4458N/A * also, if we have trouble which is clearly specific to the proxy, then 4458N/A * we return DECLINED so that we can try another proxy. (Or the direct 4458N/A /* Note: Memory pool allocation. 4458N/A * A downstream keepalive connection is always connected to the existence 4458N/A * (or not) of an upstream keepalive connection. If this is not done then 4458N/A * load balancing against multiple backend servers breaks (one backend 4458N/A * server ends up taking 100% of the load), and the risk is run of 4458N/A * downstream keepalive connections being kept open unnecessarily. This 4458N/A * keeps webservers busy and ties up resources. 4458N/A * As a result, we allocate all sockets out of the upstream connection 4458N/A * pool, and when we want to reuse a socket, we check first whether the 4458N/A * connection ID of the current upstream connection is the same as that 4458N/A * of the connection when the socket was opened. 4458N/A * Step One: Determine Who To Connect To 4458N/A * Break up the URL to determine the host to connect to 4458N/A /* we break the URL into host, port, uri */ 4458N/A /* do a DNS lookup for the destination host */ 4458N/A /* see memory note above */ 4458N/A /* allocate these out of the connection pool - the check on r->connection->id makes 4458N/A * sure that this string does not get accessed past the connection lifetime */ 4458N/A /* are we connecting directly, or via a proxy? */ 4458N/A /* see memory note above */ 4458N/A /* Get the server port for the Via headers */ 4458N/A /* check if ProxyBlock directive on this host */ 4458N/A "Connect to remote machine blocked");
4458N/A * Step Two: Make the Connection 4458N/A * We have determined who to connect to. Now make the connection, supporting 4458N/A /* get all the possible IP addresses for the destname and loop through them 4458N/A * until we get a successful connection 4458N/A "DNS lookup failure for: ",
4458N/A /* if a keepalive socket is already open, check whether it must stay 4458N/A * open, or whether it should be closed and a new socket created. 4458N/A /* see memory note above */ 4458N/A "proxy: keepalive address match (keep original socket)");
4458N/A "proxy: keepalive address mismatch / connection has" 4458N/A " changed (close old socket (%s/%s, %d/%d))",
4458N/A /* get a socket - either a keepalive one, or a new one */ 4458N/A /* use previous keepalive socket */ 4458N/A /* XXX FIXME: If the socket has since closed, change new to 1 so 4458N/A * a new socket is opened */ 4458N/A /* see memory note above */ 4458N/A "proxy: error creating socket");
4458N/A "setsockopt(SO_RCVBUF): Failed to set ProxyReceiveBufferSize, using default");
4458N/A "proxy: socket has been created");
4458N/A * At this point we have a list of one or more IP addresses of 4458N/A * the machine to connect to. If configured, reorder this 4458N/A * list so that the "best candidate" is first try. "best 4458N/A * candidate" could mean the least loaded server, the fastest 4458N/A * responding server, whatever. 4458N/A * For now we do nothing, ie we get DNS round robin. 4458N/A /* try each IP address until we connect successfully */ 4458N/A /* make the connection out of the socket */ 4458N/A /* if an error occurred, loop round and try again */ 4458N/A "proxy: attempt to connect to %pI (%s) failed",
4458N/A /* if we get here, all is well */ 4458N/A /* handle a permanent error from the above loop */ 4458N/A "proxy: socket is connected");
4458N/A /* the socket is now open, create a new downstream connection */ 4458N/A /* the peer reset the connection already; ap_new_connection() 4458N/A "proxy: connection complete");
4458N/A /* set up the connection filters */ 4458N/A * Step Three: Send the Request 4458N/A * Send the HTTP/1.1 request to the remote server 4458N/A /* strip connection listed hop-by-hop headers from the request */ 4458N/A /* even though in theory a connection: close coming from the client 4458N/A * should not affect the connection to the server, it's unlikely 4458N/A * we cancel server keepalive if the client does. 4458N/A /* Block all outgoing Via: headers */ 4458N/A /* Create a "Via:" request header entry and merge it */ /* X-Forwarded-*: handling * These request headers are only really useful when the mod_proxy * is used in a reverse proxy configuration, so that useful info * about the client can be passed through the reverse proxy and on * to the backend server, which may require the information to * In a forward proxy situation, these options are a potential * privacy violation, as information about clients behind the proxy * are revealed to arbitrary servers out there on the internet. * The HTTP/1.1 Via: header is designed for passing client * information through proxies to a server, and should be used in * a forward proxy configuation instead of X-Forwarded-*. See the * ProxyVia option for details. /* Add X-Forwarded-For: so that the upstream has a chance to * determine, where the original request came from. /* Add X-Forwarded-Host: so that upstream knows what the * original request hostname was. /* Add X-Forwarded-Server: so that upstream knows what the * name of this proxy server is (if there are more than one) * XXX: This duplicates Via: - do we strictly need it? /* send request headers */ /* Clear out hop-by-hop request headers not to send * RFC2616 13.5.1 says we should strip these headers /* XXX: @@@ FIXME: "Proxy-Authorization" should *only* be * suppressed if THIS server requested the authentication, * not when a frontend proxy requested it! * The solution to this problem is probably to strip out * the Proxy-Authorisation header in the authorisation * code itself, not here. This saves us having to signal * somehow whether this request was authenticated or not. /* add empty line at the end of the headers */ /* send the request data, if any. */ /* XXX FIXME: Only sends downstream when request is fully loaded */ /* Flush the data to the origin server */ * Step Four: Receive the Response * Get response from the remote server, and pass it up the "proxy: error reading status line from remote server %s",
"Error reading from remote server");
/* Is it an HTTP/1 response? This is buggy if we ever see an HTTP/1.10 */ /* If not an HTTP/1 message or if the status line was > 8192 bytes */ /* N.B. for HTTP/1.0 clients, we have to fold line-wrapped headers */ /* Also, take care with headers with multiple occurences. */ "proxy: bad HTTP/%d.%d header returned by %s (%s)",
/* strip connection listed hop-by-hop headers from response */ /* handle Via header in response */ /* create a "Via:" response header entry and merge it */ /* cancel keepalive if HTTP/1.0 or less */ /* an http/0.9 response */ /* munge the Location and URI response headers according to ProxyPassReverse */ /* XXX FIXME: this isn't working */ /* Is it an HTTP/0.9 response? If so, send the extra data */ /* FIXME: what is buffer used for here? It is of limited size */ /* if chunked - insert DECHUNK filter */ /* if content length - set the length to read */ /* no chunked / no length therefore read till EOF and cancel keepalive */ /* if keepalive cancelled, read to EOF */ "proxy: start body send");
/* read the body, pass it to the output filters */ * If there are no KeepAlives, or if the connection has been signalled * to close, close the socket and clean up /* if the connection is < HTTP/1.1, or Connection: close, * we close the socket, otherwise we leave it open for KeepAlive support