dgaudet 98/01/30 01:55:43
Modified: src http_protocol.c Log: The other half of the fix for when die() happens we need to eat any request body if one exists. The hack for ErrorDocument is removed since it interferes with the fix and should not be needed anyway. PR: 1399 Submitted by: Roy Fielding Reviewed by: Dean Gaudet Revision Changes Path 1.128 +115 -32 apache-1.2/src/http_protocol.c Index: http_protocol.c =================================================================== RCS file: /export/home/cvs/apache-1.2/src/http_protocol.c,v retrieving revision 1.127 retrieving revision 1.128 diff -u -r1.127 -r1.128 --- http_protocol.c 1998/01/30 09:13:56 1.127 +++ http_protocol.c 1998/01/30 09:55:41 1.128 @@ -548,13 +548,15 @@ } } -const char *check_fulluri (request_rec *r, const char *uri) { +const char *check_fulluri (request_rec *r, const char *uri) +{ char *name, *host; int i; unsigned port; + server_addr_rec * sar; /* This routine parses full URLs, if they match the server */ - if (strncmp(uri, "http://", 7)) return uri; + if (strncasecmp(uri, "http://", 7)) return uri; name = pstrdup(r->pool, uri + 7); /* Find the hostname, assuming a valid request */ @@ -567,7 +569,13 @@ else port = 80; /* Make sure ports patch */ - if (port != r->server->port) return uri; + if (port != r->server->port) { + for (sar = r->server->addrs; sar; sar = sar->next) { + if( (sar->host_port == 0) || (port == sar->host_port) ) + break; + } + if (!sar) return uri; + } /* Save it for later use */ r->hostname = pstrdup(r->pool, host); @@ -678,15 +686,29 @@ } } -static void check_hostalias (request_rec *r) { +#define ADDR_MATCHES(addr1,addr2) \ + (addr1.s_addr == addr2.s_addr) || (addr1.s_addr == htonl(INADDR_ANY)) \ + || (addr1.s_addr == DEFAULT_VHOST_ADDR) + +static void check_hostalias (request_rec *r) +{ const char *hostname=r->hostname; char *host = getword(r->pool, &hostname, ':'); /* Get rid of port */ unsigned port = (*hostname) ? atoi(hostname) : 80; - server_rec *s; + server_rec *s = r->server; + server_addr_rec * sar; int l; - if (port && (port != r->server->port)) - return; +/* make sure the client can't spoof the port; + * have to check all possiblities to see if the server + * should be listening. */ + if (port != r->server->port) { + for (sar = s->addrs; sar; sar = sar->next) { + if ( (port == sar->host_port) || (sar->host_port == 0) ) + break; + } + if (!sar) return; + } l = strlen(host)-1; if ((host[l]) == '.') { @@ -704,37 +726,68 @@ configuration */ continue; } - - if ((!strcasecmp(host, s->server_hostname)) && (port == s->port)) { - r->server = r->connection->server = s; - if (r->hostlen && !strncmp(r->uri, "http://", 7)) { - r->uri += r->hostlen; - parse_uri(r, r->uri); +/* ok, now there are several possibilities, and we're matching the + * hostname, the port, and r->connection->local_addr. The last is + * required so as to only respond on an address to which this vhost + * should actually be listening. + * + * Either we can match s->server_name and s->port while matching + * against the ip address in a record in the s->addrs list *or* we + * can match s->server_name and a complete record in the s->addrs + * list *or* we can match the virtual host name and the address and + * the port of a record in the s->addrs list. + */ + if (!strcasecmp(host,s->server_hostname)) { /* ServerName matches hostname */ + if (port == s->port) { /* possibly configured by Port */ + for (sar = s->addrs; sar; sar = sar->next) { + if (ADDR_MATCHES(sar->host_addr,r->connection->local_addr.sin_addr)) + break; /* SN matches, Port matches, and one IP addr matches */ + } + } else { /* check to see if an addr matches */ + for (sar = s->addrs; sar; sar = sar->next) { + if (((port == sar->host_port) || (sar->host_port == 0)) + && (ADDR_MATCHES(sar->host_addr, + r->connection->local_addr.sin_addr))) + break; /* SN matches, and a addr matches IP & port */ + } } - } + if (sar) { /* we got a match */ + r->server = r->connection->server = s; + if (r->hostlen && !strncasecmp(r->uri, "http://", 7)) { + r->uri += r->hostlen; + parse_uri(r, r->uri); + /* we still might want to do something below (ie. set r->proxyreq) */ + } + } + } /* ServerName doesn't match */ - /* search all the names from <VirtualHost> directive */ - for( sar = s->addrs; sar; sar = sar->next ) { - if( !strcasecmp( sar->virthost, host ) && - ( (sar->host_port == 0) || (port == sar->host_port) )) { - r->server = r->connection->server = s; - if( r->hostlen && !strncmp( r->uri, "http://", 7) ) { - r->uri += r->hostlen; - r->proxyreq = 0; - } + /* now s->addrs list, include the names, from the VirtualHost directive */ + for (sar = s->addrs; sar; sar = sar->next) { + if (((sar->host_port==0) || (port==sar->host_port)) + && (ADDR_MATCHES(sar->host_addr,r->connection->local_addr.sin_addr)) + && !strcasecmp(host,sar->virthost)) { + /* ok, an element in the addrs list matched all three items */ + r->server = r->connection->server = s; + if (r->hostlen && !strncasecmp(r->uri, "http://", 7)) { + r->uri += r->hostlen; + r->proxyreq = 0; + } } } - /* search all the aliases from ServerAlias directive */ + /* search all the aliases from ServerAlias directive + * ServerAlias acts like a wildcard, so as to help deal with the + * transition when the DNS for a given host changes. + */ names = s->names; - if( names ) { + if (names) { while (*names) { char *name = getword_conf (r->pool, &names); if ((is_matchexp(name) && !strcasecmp_match(host, name)) || (!strcasecmp(host, name))) { r->server = r->connection->server = s; - if (r->hostlen && !strncmp(r->uri, "http://", 7)) { + if (r->hostlen && !strncasecmp(r->uri, "http://", 7)) { r->uri += r->hostlen; r->proxyreq = 0; } @@ -744,8 +797,11 @@ } } -void check_serverpath (request_rec *r) { +void check_serverpath (request_rec *r) +{ server_rec *s; + server_addr_rec * sar = NULL; + int port = r->connection->local_addr.sin_port; /* This is in conjunction with the ServerPath code in * http_core, so we get the right host attached to a non- @@ -753,10 +809,35 @@ */ for (s = r->server->next; s; s = s->next) { - if (s->addrs && s->path && !strncmp(r->uri, s->path, s->pathlen) && - (s->path[s->pathlen - 1] == '/' || - r->uri[s->pathlen] == '/' || - r->uri[s->pathlen] == '\0')) + /* we should check to make sure that this server should be listening + * at all. + * + * this code is duplicated in check_hostalias, but only one of these + * two functions runs for a given request. + */ + if (!s->addrs) continue; + + if( (port == s->port) ) { + for(sar = s->addrs; sar; sar = sar->next) { + if(ADDR_MATCHES(sar->host_addr, r->connection->local_addr.sin_addr)) + break; + } + } + else { + for(sar = s->addrs; sar; sar = sar->next) { + if( ( (port == sar->host_port) || (sar->host_port == 0) ) + && ( ADDR_MATCHES(sar->host_addr, + r->connection->local_addr.sin_addr) ) ) + break; + } + } + + if (!sar) continue; /* no match */ + + if (s->path && !strncmp(r->uri, s->path, s->pathlen) + && (s->path[s->pathlen - 1] == '/' + || r->uri[s->pathlen] == '/' + || r->uri[s->pathlen] == '\0')) r->server = r->connection->server = s; } } @@ -1353,7 +1434,9 @@ int should_client_block (request_rec *r) { - if (r->read_length || is_HTTP_ERROR(r->status)) + /* First check if we have already read the request body */ + + if (r->read_length || (!r->read_chunked && (r->remaining <= 0))) return 0; if (!r->read_chunked && (r->remaining <= 0))