Lowercase and remove any trailing dot and/or :port from the hostname, * and check that it is sane. * * In most configurations the exact syntax of the hostname isn't * important so strict sanity checking isn't necessary. However, in * mass hosting setups (using mod_vhost_alias or mod_rewrite) where * the hostname is interpolated into the filename, we need to be sure * that the interpolation
| 826 | * separators / and \ and sequences of more than one dot. |
| 827 | */ |
| 828 | static int fix_hostname(request_rec *r, const char *host_header, |
| 829 | unsigned http_conformance) |
| 830 | { |
| 831 | const char *src; |
| 832 | char *host, *scope_id; |
| 833 | apr_port_t port; |
| 834 | apr_status_t rv; |
| 835 | const char *c; |
| 836 | int is_v6literal = 0; |
| 837 | int strict = (http_conformance != AP_HTTP_CONFORMANCE_UNSAFE); |
| 838 | |
| 839 | src = host_header ? host_header : r->hostname; |
| 840 | |
| 841 | /* According to RFC 2616, Host header field CAN be blank */ |
| 842 | if (!*src) { |
| 843 | return is_v6literal; |
| 844 | } |
| 845 | |
| 846 | /* apr_parse_addr_port will interpret a bare integer as a port |
| 847 | * which is incorrect in this context. So treat it separately. |
| 848 | */ |
| 849 | for (c = src; apr_isdigit(*c); ++c); |
| 850 | if (!*c) { |
| 851 | /* pure integer */ |
| 852 | if (strict) { |
| 853 | /* RFC 3986 7.4 */ |
| 854 | ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02416) |
| 855 | "[strict] purely numeric host names not allowed: %s", |
| 856 | src); |
| 857 | goto bad_nolog; |
| 858 | } |
| 859 | r->hostname = src; |
| 860 | return is_v6literal; |
| 861 | } |
| 862 | |
| 863 | if (host_header) { |
| 864 | rv = apr_parse_addr_port(&host, &scope_id, &port, src, r->pool); |
| 865 | if (rv != APR_SUCCESS || scope_id) |
| 866 | goto bad; |
| 867 | if (port) { |
| 868 | /* Don't throw the Host: header's port number away: |
| 869 | save it in parsed_uri -- ap_get_server_port() needs it! */ |
| 870 | /* @@@ XXX there should be a better way to pass the port. |
| 871 | * Like r->hostname, there should be a r->portno |
| 872 | */ |
| 873 | r->parsed_uri.port = port; |
| 874 | r->parsed_uri.port_str = apr_itoa(r->pool, (int)port); |
| 875 | } |
| 876 | if (host_header[0] == '[') |
| 877 | is_v6literal = 1; |
| 878 | } |
| 879 | else { |
| 880 | /* |
| 881 | * Already parsed, surrounding [ ] (if IPv6 literal) and :port have |
| 882 | * already been removed. |
| 883 | */ |
| 884 | host = apr_pstrdup(r->pool, r->hostname); |
| 885 | if (ap_strchr(host, ':') != NULL) |
no test coverage detected