fielding 97/09/14 03:05:00
Modified: src INDENT src/main http_protocol.c http_protocol.h Log: Reformatted http_protocol.* according to style guide. Revision Changes Path 1.3 +2 -2 apachen/src/INDENT Index: INDENT =================================================================== RCS file: /export/home/cvs/apachen/src/INDENT,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- INDENT 1997/09/14 07:47:36 1.2 +++ INDENT 1997/09/14 10:04:57 1.3 @@ -23,8 +23,8 @@ http_log.h http_main.c RESERVED until Dean applies his two patches http_main.h - http_protocol.c RESERVED while Roy is working on it - http_protocol.h RESERVED while Roy is working on it + http_protocol.c DONE by Roy + http_protocol.h DONE by Roy http_request.c RESERVED while Roy is working on it http_request.h RESERVED while Roy is working on it httpd.h 1.162 +946 -908 apachen/src/main/http_protocol.c Index: http_protocol.c =================================================================== RCS file: /export/home/cvs/apachen/src/main/http_protocol.c,v retrieving revision 1.161 retrieving revision 1.162 diff -u -r1.161 -r1.162 --- http_protocol.c 1997/09/12 18:56:02 1.161 +++ http_protocol.c 1997/09/14 10:04:58 1.162 @@ -6,7 +6,7 @@ * are met: * * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. + * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in @@ -49,7 +49,7 @@ * project, please see <http://www.apache.org/>. * */ - + /* * http_protocol.c --- routines which directly communicate with the client. * @@ -64,59 +64,60 @@ #include "http_protocol.h" #include "http_main.h" #include "http_request.h" -#include "http_log.h" /* For errors detected in basic auth - * common support code... - */ +#include "http_log.h" /* For errors detected in basic auth common + * support code... */ #include "util_date.h" /* For parseHTTPdate and BAD_DATE */ #include <stdarg.h> #include "http_conf_globals.h" #define SET_BYTES_SENT(r) \ do { if (r->sent_bodyct) \ - bgetopt (r->connection->client, BO_BYTECT, &r->bytes_sent); \ + bgetopt (r->connection->client, BO_BYTECT, &r->bytes_sent); \ } while (0) -static int parse_byterange (char *range, long clength, long *start, long *end) +static int parse_byterange(char *range, long clength, long *start, long *end) { char *dash = strchr(range, '-'); if (!dash) - return 0; + return 0; if ((dash == range)) { - /* In the form "-5" */ - *start = clength - atol(dash + 1); - *end = clength - 1; + /* In the form "-5" */ + *start = clength - atol(dash + 1); + *end = clength - 1; } else { - *dash = '\0'; - dash++; - *start = atol(range); - if (*dash) - *end = atol(dash); - else /* "5-" */ - *end = clength -1; + *dash = '\0'; + dash++; + *start = atol(range); + if (*dash) + *end = atol(dash); + else /* "5-" */ + *end = clength - 1; } if (*start > *end) - return 0; + return 0; if (*end >= clength) - *end = clength - 1; + *end = clength - 1; return 1; } -static int internal_byterange(int, long*, request_rec*, char**, long*, long*); +static int internal_byterange(int, long *, request_rec *, char **, long *, + long *); -API_EXPORT(int) set_byterange (request_rec *r) +API_EXPORT(int) set_byterange(request_rec *r) { char *range, *if_range, *match; char ts[MAX_STRING_LEN]; long range_start, range_end; - if (!r->clength || r->assbackwards) return 0; + if (!r->clength || r->assbackwards) + return 0; /* Check for Range request-header (HTTP/1.1) or Request-Range for * backwards-compatibility with second-draft Luotonen/Franks @@ -129,11 +130,11 @@ */ if (!(range = table_get(r->headers_in, "Range"))) - range = table_get(r->headers_in, "Request-Range"); + range = table_get(r->headers_in, "Request-Range"); if (!range || strncmp(range, "bytes=", 6)) { - table_set (r->headers_out, "Accept-Ranges", "bytes"); - return 0; + table_set(r->headers_out, "Accept-Ranges", "bytes"); + return 0; } /* Check the If-Range header for Etag or Date */ @@ -148,43 +149,43 @@ (strcasecmp(if_range, match) != 0)) return 0; } - + if (!strchr(range, ',')) { - /* A single range */ - if (!parse_byterange(pstrdup(r->pool, range + 6), r->clength, - &range_start, &range_end)) - return 0; - - r->byterange = 1; - - ap_snprintf(ts, sizeof(ts), "bytes %ld-%ld/%ld", - range_start, range_end, r->clength); - table_set(r->headers_out, "Content-Range", ts); - ap_snprintf(ts, sizeof(ts), "%ld", range_end - range_start + 1); - table_set(r->headers_out, "Content-Length", ts); + /* A single range */ + if (!parse_byterange(pstrdup(r->pool, range + 6), r->clength, + &range_start, &range_end)) + return 0; + + r->byterange = 1; + + ap_snprintf(ts, sizeof(ts), "bytes %ld-%ld/%ld", + range_start, range_end, r->clength); + table_set(r->headers_out, "Content-Range", ts); + ap_snprintf(ts, sizeof(ts), "%ld", range_end - range_start + 1); + table_set(r->headers_out, "Content-Length", ts); } else { - /* a multiple range */ - char boundary[33]; /* Long enough */ - char *r_range = pstrdup(r->pool, range + 6); - long tlength = 0; - - r->byterange = 2; - ap_snprintf(boundary, sizeof(boundary), "%lx%lx", - r->request_time, (long)getpid()); - r->boundary = pstrdup(r->pool, boundary); - while (internal_byterange(0, &tlength, r, &r_range, NULL, NULL)); - ap_snprintf(ts, sizeof(ts), "%ld", tlength); - table_set(r->headers_out, "Content-Length", ts); + /* a multiple range */ + char boundary[33]; /* Long enough */ + char *r_range = pstrdup(r->pool, range + 6); + long tlength = 0; + + r->byterange = 2; + ap_snprintf(boundary, sizeof(boundary), "%lx%lx", + r->request_time, (long) getpid()); + r->boundary = pstrdup(r->pool, boundary); + while (internal_byterange(0, &tlength, r, &r_range, NULL, NULL)); + ap_snprintf(ts, sizeof(ts), "%ld", tlength); + table_set(r->headers_out, "Content-Length", ts); } - + r->status = PARTIAL_CONTENT; r->range = range + 6; return 1; } -API_EXPORT(int) each_byterange (request_rec *r, long *offset, long *length) +API_EXPORT(int) each_byterange(request_rec *r, long *offset, long *length) { return internal_byterange(1, NULL, r, &r->range, offset, length); } @@ -198,63 +199,62 @@ * * Either case will return 1 if it should be called again, and 0 * when done. - * */ - static int internal_byterange(int realreq, long *tlength, request_rec *r, - char **r_range, long *offset, long *length) + char **r_range, long *offset, long *length) { long range_start, range_end; char *range; if (!**r_range) { - if (r->byterange > 1) { - if (realreq) - rvputs(r, "\015\012--", r->boundary, "--\015\012", NULL); - else - *tlength += 4 + strlen(r->boundary) + 4; - } - return 0; + if (r->byterange > 1) { + if (realreq) + rvputs(r, "\015\012--", r->boundary, "--\015\012", NULL); + else + *tlength += 4 + strlen(r->boundary) + 4; + } + return 0; } range = getword_nc(r->pool, r_range, ','); if (!parse_byterange(range, r->clength, &range_start, &range_end)) - /* Skip this one */ - return internal_byterange(realreq, tlength, r, r_range, offset, - length); + /* Skip this one */ + return internal_byterange(realreq, tlength, r, r_range, offset, + length); if (r->byterange > 1) { - char *ct = r->content_type ? r->content_type : default_type(r); - char ts[MAX_STRING_LEN]; - - ap_snprintf(ts, sizeof(ts), "%ld-%ld/%ld", range_start, range_end, r->clength); - if (realreq) - rvputs(r, "\015\012--", r->boundary, "\015\012Content-type: ", - ct, "\015\012Content-range: bytes ", ts, "\015\012\015\012", - NULL); - else - *tlength += 4 + strlen(r->boundary) + 16 + strlen(ct) + 23 + - strlen(ts) + 4; + char *ct = r->content_type ? r->content_type : default_type(r); + char ts[MAX_STRING_LEN]; + + ap_snprintf(ts, sizeof(ts), "%ld-%ld/%ld", range_start, range_end, + r->clength); + if (realreq) + rvputs(r, "\015\012--", r->boundary, "\015\012Content-type: ", + ct, "\015\012Content-range: bytes ", ts, "\015\012\015\012", + NULL); + else + *tlength += 4 + strlen(r->boundary) + 16 + strlen(ct) + 23 + + strlen(ts) + 4; } if (realreq) { - *offset = range_start; - *length = range_end - range_start + 1; + *offset = range_start; + *length = range_end - range_start + 1; } else { - *tlength += range_end - range_start + 1; + *tlength += range_end - range_start + 1; } return 1; } -API_EXPORT(int) set_content_length (request_rec *r, long clength) +API_EXPORT(int) set_content_length(request_rec *r, long clength) { char ts[MAX_STRING_LEN]; r->clength = clength; - ap_snprintf (ts, sizeof(ts), "%ld", clength); - table_set (r->headers_out, "Content-Length", ts); + ap_snprintf(ts, sizeof(ts), "%ld", clength); + table_set(r->headers_out, "Content-Length", ts); return 0; } @@ -262,9 +262,9 @@ int set_keepalive(request_rec *r) { int ka_sent = 0; - int wimpy = find_token(r->pool, - table_get(r->headers_out, "Connection"), "close"); - char *conn = table_get(r->headers_in, "Connection"); + int wimpy = find_token(r->pool, + table_get(r->headers_out, "Connection"), "close"); + char *conn = table_get(r->headers_in, "Connection"); /* The following convoluted conditional determines whether or not * the current connection should remain persistent after this response @@ -307,30 +307,30 @@ !status_drops_connection(r->status) && !wimpy && !find_token(r->pool, conn, "close") && - (!table_get(r->subprocess_env, "nokeepalive") || - table_get(r->headers_in, "Via")) && - ((ka_sent = find_token(r->pool, conn, "keep-alive")) || - (r->proto_num >= 1001)) + (!table_get(r->subprocess_env, "nokeepalive") || + table_get(r->headers_in, "Via")) && + ((ka_sent = find_token(r->pool, conn, "keep-alive")) || + (r->proto_num >= 1001)) ) { - char header[256]; - int left = r->server->keep_alive_max - r->connection->keepalives; - - r->connection->keepalive = 1; - r->connection->keepalives++; - - /* If they sent a Keep-Alive token, send one back */ - if (ka_sent) { - if (r->server->keep_alive_max) - ap_snprintf(header, sizeof(header), "timeout=%d, max=%d", - r->server->keep_alive_timeout, left); - else - ap_snprintf(header, sizeof(header), "timeout=%d", - r->server->keep_alive_timeout); - table_set(r->headers_out, "Keep-Alive", header); - table_merge(r->headers_out, "Connection", "Keep-Alive"); - } + char header[256]; + int left = r->server->keep_alive_max - r->connection->keepalives; + + r->connection->keepalive = 1; + r->connection->keepalives++; + + /* If they sent a Keep-Alive token, send one back */ + if (ka_sent) { + if (r->server->keep_alive_max) + ap_snprintf(header, sizeof(header), "timeout=%d, max=%d", + r->server->keep_alive_timeout, left); + else + ap_snprintf(header, sizeof(header), "timeout=%d", + r->server->keep_alive_timeout); + table_set(r->headers_out, "Keep-Alive", header); + table_merge(r->headers_out, "Connection", "Keep-Alive"); + } - return 1; + return 1; } /* Otherwise, we need to indicate that we will be closing this @@ -378,8 +378,7 @@ char *if_match, *if_modified_since, *if_unmodified, *if_nonematch; time_t mtime; - /* - * Check for conditional requests --- note that we only want to do + /* Check for conditional requests --- note that we only want to do * this if we are successful so far and we are not processing a * subrequest or an ErrorDocument. * @@ -396,40 +395,34 @@ mtime = (r->mtime != 0) ? r->mtime : time(NULL); - /* - * If an If-Match request-header field was given + /* If an If-Match request-header field was given * AND if our ETag does not match any of the entity tags in that field * AND the field value is not "*" (meaning match anything), then * respond with a status of 412 (Precondition Failed). */ - if ((if_match = table_get(r->headers_in, "If-Match")) != NULL) { - if ((etag == NULL) || - ((if_match[0] != '*') && !find_token(r->pool, if_match, etag))) { - return HTTP_PRECONDITION_FAILED; - } + if ((etag == NULL) || + ((if_match[0] != '*') && !find_token(r->pool, if_match, etag))) { + return HTTP_PRECONDITION_FAILED; + } } - - /* - * Else if a valid If-Unmodified-Since request-header field was given - * AND the requested resource has been modified since the time - * specified in this field, then the server MUST - * respond with a status of 412 (Precondition Failed). - */ - else { - if_unmodified = table_get(r->headers_in, "If-Unmodified-Since"); - if (if_unmodified != NULL) { - time_t ius = parseHTTPdate(if_unmodified); - - if ((ius != BAD_DATE) && (mtime > ius)) { - return HTTP_PRECONDITION_FAILED; - } - } + /* Else if a valid If-Unmodified-Since request-header field was given + * AND the requested resource has been modified since the time + * specified in this field, then the server MUST + * respond with a status of 412 (Precondition Failed). + */ + if_unmodified = table_get(r->headers_in, "If-Unmodified-Since"); + if (if_unmodified != NULL) { + time_t ius = parseHTTPdate(if_unmodified); + + if ((ius != BAD_DATE) && (mtime > ius)) { + return HTTP_PRECONDITION_FAILED; + } + } } - /* - * If an If-None-Match request-header field was given + /* If an If-None-Match request-header field was given * AND if our ETag matches any of the entity tags in that field * OR if the field value is "*" (meaning match anything), then * if the request method was GET or HEAD, the server SHOULD @@ -437,36 +430,32 @@ * For all other request methods, the server MUST * respond with a status of 412 (Precondition Failed). */ - if_nonematch = table_get(r->headers_in, "If-None-Match"); if (if_nonematch != NULL) { - int rstatus; + int rstatus; - if ((if_nonematch[0] == '*') - || ((etag != NULL) && find_token(r->pool, if_nonematch, etag))) { - rstatus = (r->method_number == M_GET) - ? HTTP_NOT_MODIFIED - : HTTP_PRECONDITION_FAILED; - return rstatus; - } + if ((if_nonematch[0] == '*') + || ((etag != NULL) && find_token(r->pool, if_nonematch, etag))) { + rstatus = (r->method_number == M_GET) ? HTTP_NOT_MODIFIED + : HTTP_PRECONDITION_FAILED; + return rstatus; + } } - - /* - * Else if a valid If-Modified-Since request-header field was given + /* Else if a valid If-Modified-Since request-header field was given * AND it is a GET or HEAD request * AND the requested resource has not been modified since the time * specified in this field, then the server MUST * respond with a status of 304 (Not Modified). * A date later than the server's current request time is invalid. */ - - else if ((r->method_number == M_GET) && ((if_modified_since = - table_get(r->headers_in, "If-Modified-Since")) != NULL)) { + else if ((r->method_number == M_GET) + && ((if_modified_since = + table_get(r->headers_in, "If-Modified-Since")) != NULL)) { time_t ims = parseHTTPdate(if_modified_since); if ((ims >= mtime) && (ims <= r->request_time)) { return HTTP_NOT_MODIFIED; - } + } } return OK; } @@ -496,14 +485,14 @@ */ if (r->finfo.st_mode != 0) { - ap_snprintf(weak_etag, sizeof(weak_etag), "W/\"%lx-%lx-%lx\"", - (unsigned long)r->finfo.st_ino, - (unsigned long)r->finfo.st_size, - (unsigned long)r->mtime); + ap_snprintf(weak_etag, sizeof(weak_etag), "W/\"%lx-%lx-%lx\"", + (unsigned long) r->finfo.st_ino, + (unsigned long) r->finfo.st_size, + (unsigned long) r->mtime); } else { ap_snprintf(weak_etag, sizeof(weak_etag), "W/\"%lx\"", - (unsigned long)r->mtime); + (unsigned long) r->mtime); } etag = weak_etag + ((r->request_time - r->mtime > 1) ? 2 : 0); @@ -520,7 +509,7 @@ time_t mod_time = rationalize_mtime(r, r->mtime); table_set(r->headers_out, "Last-Modified", - gm_timestr_822(r->pool, mod_time)); + gm_timestr_822(r->pool, mod_time)); } /* Get a line of protocol input, including any continuation lines @@ -545,35 +534,37 @@ pos = s; do { - retval = bgets(pos, n, in); /* retval == -1 if error, 0 if EOF */ + retval = bgets(pos, n, in); /* retval == -1 if error, 0 if EOF */ if (retval <= 0) return ((retval < 0) && (total == 0)) ? -1 : total; - /* retval is the number of characters read, not including NUL */ + /* retval is the number of characters read, not including NUL */ - n -= retval; /* Keep track of how much of s is full */ - pos += (retval-1); /* and where s ends */ - total += retval; /* and how long s has become */ + n -= retval; /* Keep track of how much of s is full */ + pos += (retval - 1); /* and where s ends */ + total += retval; /* and how long s has become */ - if (*pos == '\n') { /* Did we get a full line of input? */ + if (*pos == '\n') { /* Did we get a full line of input? */ *pos = '\0'; - --total; ++n; + --total; + ++n; } - else return total; /* if not, input line exceeded buffer size */ + else + return total; /* if not, input line exceeded buffer size */ - /* Continue appending if line folding is desired and - * the last line was not empty and we have room in the buffer and - * the next line begins with a continuation character. - */ - } while (fold && (retval != 1) && (n > 1) && - (blookc(&next, in) == 1) && - ((next == ' ') || (next == '\t'))); + /* Continue appending if line folding is desired and + * the last line was not empty and we have room in the buffer and + * the next line begins with a continuation character. + */ + } while (fold && (retval != 1) && (n > 1) + && (blookc(&next, in) == 1) + && ((next == ' ') || (next == '\t'))); return total; } -void parse_uri (request_rec *r, const char *uri) +void parse_uri(request_rec *r, const char *uri) { const char *s; @@ -582,105 +573,115 @@ size_t loop, uri_len; #endif -/* A proxy request contains a ':' early on, but not as first character */ - for (s=uri; s != '\0'; s++) - if (!isalnum(*s) && *s != '+' && *s != '-' && *s != '.') break; + /* A proxy request contains a ':' early on, but not as first character */ - if (*s == ':' && s != uri) - { - r->proxyreq = 1; - r->uri = pstrdup(r->pool, uri); - r->args = NULL; + for (s = uri; s != '\0'; s++) + if (!isalnum(*s) && *s != '+' && *s != '-' && *s != '.') + break; + + if (*s == ':' && s != uri) { + r->proxyreq = 1; + r->uri = pstrdup(r->pool, uri); + r->args = NULL; } else if (r->method && !strcmp(r->method, "TRACE")) { - r->proxyreq = 0; - r->uri = pstrdup(r->pool, uri); - r->args = NULL; + r->proxyreq = 0; + r->uri = pstrdup(r->pool, uri); + r->args = NULL; } else { - r->proxyreq = 0; - r->uri = getword (r->pool, &uri, '?'); + r->proxyreq = 0; + r->uri = getword(r->pool, &uri, '?'); #if defined(__EMX__) || defined(WIN32) - /* Handle path translations for OS/2 and plug security hole. */ - /* This will prevent "http://www.wherever.com/..\..\/" from - returning a directory for the root drive. */ - uri_len = strlen(r->uri); - for (loop = 0; loop < uri_len; ++loop) { - if (r->uri[loop] == '\\') - r->uri[loop] = '/'; - }; + /* Handle path translations for OS/2 and plug security hole. + * + * This will prevent "http://www.wherever.com/..\..\/" from + * returning a directory for the root drive. + */ + uri_len = strlen(r->uri); + for (loop = 0; loop < uri_len; ++loop) { + if (r->uri[loop] == '\\') + r->uri[loop] = '/'; + }; #endif #ifdef __EMX__ - /* Fix OS/2 HPFS filename case problem. */ - r->uri = strlwr(r->uri); + /* Fix OS/2 HPFS filename case problem. */ + r->uri = strlwr(r->uri); #endif - if (*uri) r->args= pstrdup(r->pool, uri); - else r->args = NULL; + if (*uri) + r->args = pstrdup(r->pool, uri); + else + r->args = NULL; } } -const char *check_fulluri (request_rec *r, const char *uri) { - char *name, *host; - int i; - unsigned port; - - /* This routine parses full URLs, if they match the server */ - if (strncmp(uri, "http://", 7)) return uri; - name = pstrdup(r->pool, uri + 7); - - /* Find the hostname, assuming a valid request */ - i = ind(name, '/'); - name[i] = '\0'; - - /* Find the port */ - host = getword_nc(r->pool, &name, ':'); - if (*name) port = atoi(name); - else port = 80; - - /* Make sure ports patch */ - if (port != r->server->port) return uri; - - /* Save it for later use */ - r->hostname = pstrdup(r->pool, host); - r->hostlen = 7 + i; - - /* The easy cases first */ - if (!strcasecmp(host, r->server->server_hostname)) { - return (uri + r->hostlen); - } - else if (!strcmp(host, inet_ntoa(r->connection->local_addr.sin_addr))) { - return (uri + r->hostlen); - } - - /* Now things get a bit trickier - check the IP address(es) of the host */ - /* they gave, see if it matches ours. */ - else { - struct hostent *hp; - int n; +const char *check_fulluri(request_rec *r, const char *uri) +{ + char *name, *host; + int i; + unsigned port; - if ((hp = gethostbyname(host))) { - for (n = 0; hp->h_addr_list[n] != NULL; n++) { - if (r->connection->local_addr.sin_addr.s_addr == - (((struct in_addr *)(hp->h_addr_list[n]))->s_addr)) { - return (uri + r->hostlen); - } - } - } - } - - return uri; + /* This routine parses full URLs, if they match the server */ + if (strncmp(uri, "http://", 7)) + return uri; + name = pstrdup(r->pool, uri + 7); + + /* Find the hostname, assuming a valid request */ + i = ind(name, '/'); + name[i] = '\0'; + + /* Find the port */ + host = getword_nc(r->pool, &name, ':'); + if (*name) + port = atoi(name); + else + port = 80; + + /* Make sure ports patch */ + if (port != r->server->port) + return uri; + + /* Save it for later use */ + r->hostname = pstrdup(r->pool, host); + r->hostlen = 7 + i; + + /* The easy cases first */ + if (!strcasecmp(host, r->server->server_hostname)) { + return (uri + r->hostlen); + } + else if (!strcmp(host, inet_ntoa(r->connection->local_addr.sin_addr))) { + return (uri + r->hostlen); + } + else { + /* Now things get a bit trickier - check the IP address(es) of + * the host they gave, see if it matches ours. + */ + struct hostent *hp; + int n; + + if ((hp = gethostbyname(host))) { + for (n = 0; hp->h_addr_list[n] != NULL; n++) { + if (r->connection->local_addr.sin_addr.s_addr == + (((struct in_addr *) (hp->h_addr_list[n]))->s_addr)) { + return (uri + r->hostlen); + } + } + } + } + + return uri; } -int read_request_line (request_rec *r) +int read_request_line(request_rec *r) { char l[HUGE_STRING_LEN]; const char *ll = l, *uri; conn_rec *conn = r->connection; - int major = 1, minor = 0; /* Assume HTTP/1.0 if non-"HTTP" protocol*/ + int major = 1, minor = 0; /* Assume HTTP/1.0 if non-"HTTP" protocol */ int len; - + /* Read past empty lines until we get a real request line, * a read error, the connection closes (EOF), or we timeout. * @@ -695,263 +696,269 @@ * read(). B_SAFEREAD ensures that the BUFF layer flushes if it will * have to block during a read. */ - bsetflag( conn->client, B_SAFEREAD, 1 ); + bsetflag(conn->client, B_SAFEREAD, 1); while ((len = getline(l, HUGE_STRING_LEN, conn->client, 0)) <= 0) { if ((len < 0) || bgetflag(conn->client, B_EOF)) { - bsetflag( conn->client, B_SAFEREAD, 0 ); + bsetflag(conn->client, B_SAFEREAD, 0); return 0; - } + } } /* we've probably got something to do, ignore graceful restart requests */ #ifdef SIGUSR1 - signal (SIGUSR1, SIG_IGN); -#endif /* SIGUSR1 */ - bsetflag( conn->client, B_SAFEREAD, 0 ); + signal(SIGUSR1, SIG_IGN); +#endif /* SIGUSR1 */ + bsetflag(conn->client, B_SAFEREAD, 0); if (len == (HUGE_STRING_LEN - 1)) { aplog_error(APLOG_MARK, APLOG_ERR, r->server, - "request failed for %s, reason: URI too long", - get_remote_host(r->connection, r->per_dir_config, REMOTE_NAME)); + "request failed for %s, reason: URI too long", + get_remote_host(r->connection, r->per_dir_config, REMOTE_NAME)); r->status = HTTP_REQUEST_URI_TOO_LARGE; return 0; } r->request_time = time(NULL); - r->the_request = pstrdup (r->pool, l); + r->the_request = pstrdup(r->pool, l); r->method = getword_white(r->pool, &ll); uri = getword_white(r->pool, &ll); uri = check_fulluri(r, uri); - parse_uri (r, uri); - + parse_uri(r, uri); + r->assbackwards = (ll[0] == '\0'); - r->protocol = pstrdup (r->pool, ll[0] ? ll : "HTTP/0.9"); + r->protocol = pstrdup(r->pool, ll[0] ? ll : "HTTP/0.9"); sscanf(r->protocol, "HTTP/%d.%d", &major, &minor); - r->proto_num = 1000*major + minor; + r->proto_num = 1000 * major + minor; return 1; } -void get_mime_headers (request_rec *r) +void get_mime_headers(request_rec *r) { conn_rec *c = r->connection; int len; char *value; char field[MAX_STRING_LEN]; - /* Read header lines until we get the empty separator line, - * a read error, the connection closes (EOF), or we timeout. - * Should we also check for overflow (len == MAX_STRING_LEN-1)? + /* + * Read header lines until we get the empty separator line, a read error, + * the connection closes (EOF), or we timeout. Should we also check for + * overflow (len == MAX_STRING_LEN-1)? */ while ((len = getline(field, MAX_STRING_LEN, c->client, 1)) > 0) { - if (!(value = strchr(field,':'))) /* Find the colon separator */ - continue; /* or should puke 400 here */ + if (!(value = strchr(field, ':'))) /* Find the colon separator */ + continue; /* or should puke 400 here */ *value = '\0'; ++value; - while (isspace(*value)) ++value; /* Skip to start of value */ + while (isspace(*value)) + ++value; /* Skip to start of value */ table_merge(r->headers_in, field, value); } } -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; - int l; - server_rec_chain *src; - - if (port && (port != r->server->port)) - return; - - l = strlen(host)-1; - if ((host[l]) == '.') { - host[l] = '\0'; - } +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; + int l; + server_rec_chain *src; - r->hostname = host; + if (port && (port != r->server->port)) + return; - for (src = vhash_table[VHASH_MAIN_BUCKET]; src; src = src->next) { - const char *names; - server_addr_rec *sar; + l = strlen(host) - 1; + if ((host[l]) == '.') { + host[l] = '\0'; + } - s = src->server; + r->hostname = host; - /* s->addrs != NULL because it's in a hash bucket */ + for (src = vhash_table[VHASH_MAIN_BUCKET]; src; src = src->next) { + const char *names; + server_addr_rec *sar; + + s = src->server; + + /* s->addrs != NULL because it's in a hash bucket. + * + * Note that default_server_hostnames has ensured that each + * name-vhost appears only once in the VHASH_MAIN_BUCKET. + */ + + 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); + } + } - /* Note that default_server_hostnames has ensured that each name-vhost - * appears only once in the VHASH_MAIN_BUCKET. + /* 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; + } + } + } + + /* search all the aliases from ServerAlias directive */ + names = s->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)) { + r->uri += r->hostlen; + r->proxyreq = 0; + } + } + } + } + } +} + +void check_serverpath(request_rec *r) +{ + server_rec *s; + server_rec_chain *src; + + /* + * This is in conjunction with the ServerPath code in http_core, so we + * get the right host attached to a non- Host-sending request. */ - 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); - } - } - - /* 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; - } - } - } - - /* search all the aliases from ServerAlias directive */ - names = s->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)) { - r->uri += r->hostlen; - r->proxyreq = 0; - } - } - } - } - } -} - -void check_serverpath (request_rec *r) { - server_rec *s; - server_rec_chain *src; - - /* This is in conjunction with the ServerPath code in - * http_core, so we get the right host attached to a non- - * Host-sending request. - */ - - for (src = vhash_table[VHASH_MAIN_BUCKET]; src; src = src->next) { - s = src->server; - 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')) - r->server = r->connection->server = s; - } + for (src = vhash_table[VHASH_MAIN_BUCKET]; src; src = src->next) { + s = src->server; + 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')) + r->server = r->connection->server = s; + } } -static void check_default_server (request_rec *r) +static void check_default_server(request_rec *r) { server_addr_rec *sar; server_rec_chain *trav; unsigned port; - port = ntohs (r->connection->local_addr.sin_port); + port = ntohs(r->connection->local_addr.sin_port); for (trav = vhash_table[VHASH_DEFAULT_BUCKET]; trav; trav = trav->next) { - sar = trav->sar; - if (sar->host_port == 0 || sar->host_port == port) { - /* match! */ - r->server = r->connection->server = trav->server; - return; - } + sar = trav->sar; + if (sar->host_port == 0 || sar->host_port == port) { + /* match! */ + r->server = r->connection->server = trav->server; + return; + } } } -request_rec *read_request (conn_rec *conn) +request_rec *read_request(conn_rec *conn) { - request_rec *r = (request_rec *)pcalloc (conn->pool, sizeof(request_rec)); + request_rec *r = (request_rec *) pcalloc(conn->pool, sizeof(request_rec)); int access_status; - r->connection = conn; - conn->server = conn->base_server; - r->server = conn->server; - r->pool = make_sub_pool(conn->pool); - - conn->keptalive = conn->keepalive == 1; - conn->keepalive = 0; - - conn->user = NULL; - conn->auth_type = NULL; - - r->headers_in = make_table (r->pool, 50); - r->subprocess_env = make_table (r->pool, 50); - r->headers_out = make_table (r->pool, 5); - r->err_headers_out = make_table (r->pool, 5); - r->notes = make_table (r->pool, 5); - - r->request_config = create_request_config (r->pool); - r->per_dir_config = r->server->lookup_defaults; /* For now. */ - - r->sent_bodyct = 0; /* bytect isn't for body */ - - r->read_length = 0; - r->read_body = REQUEST_NO_BODY; - - r->status = HTTP_REQUEST_TIME_OUT; /* Until we get a request */ + r->connection = conn; + conn->server = conn->base_server; + r->server = conn->server; + r->pool = make_sub_pool(conn->pool); + + conn->keptalive = conn->keepalive == 1; + conn->keepalive = 0; + + conn->user = NULL; + conn->auth_type = NULL; + + r->headers_in = make_table(r->pool, 50); + r->subprocess_env = make_table(r->pool, 50); + r->headers_out = make_table(r->pool, 5); + r->err_headers_out = make_table(r->pool, 5); + r->notes = make_table(r->pool, 5); + + r->request_config = create_request_config(r->pool); + r->per_dir_config = r->server->lookup_defaults; + + r->sent_bodyct = 0; /* bytect isn't for body */ + + r->read_length = 0; + r->read_body = REQUEST_NO_BODY; + + r->status = HTTP_REQUEST_TIME_OUT; /* Until we get a request */ /* Get the request... */ - + keepalive_timeout("read request line", r); - if (!read_request_line (r)) { + if (!read_request_line(r)) { kill_timeout(r); return NULL; } if (!r->assbackwards) { hard_timeout("read request headers", r); - get_mime_headers (r); + get_mime_headers(r); } kill_timeout(r); - r->status = HTTP_OK; /* Until further notice. */ + r->status = HTTP_OK; /* Until further notice. */ /* if it's the main server so far, we have to do name-vhost style lookups */ + if (r->server->is_virtual == 0) { - if (r->hostname || (r->hostname = table_get(r->headers_in, "Host"))) - check_hostalias(r); - else - check_serverpath(r); - /* if that failed, then look for a default server */ - if (r->server->is_virtual == 0) { - check_default_server (r); - } - } else if (!r->hostname) { - /* must set this for HTTP/1.1 support */ - r->hostname = table_get (r->headers_in, "Host"); + if (r->hostname || (r->hostname = table_get(r->headers_in, "Host"))) + check_hostalias(r); + else + check_serverpath(r); + /* if that failed, then look for a default server */ + if (r->server->is_virtual == 0) { + check_default_server(r); + } + } + else if (!r->hostname) { + /* must set this for HTTP/1.1 support */ + r->hostname = table_get(r->headers_in, "Host"); } /* we have finished the search for a vhost */ - + /* we may have switched to another server */ r->per_dir_config = r->server->lookup_defaults; - conn->keptalive = 0; /* We now have a request to play with */ - - if(!strcmp(r->method, "HEAD")) { - r->header_only=1; - r->method_number = M_GET; - } - else if(!strcmp(r->method, "GET")) - r->method_number = M_GET; - else if(!strcmp(r->method,"POST")) + conn->keptalive = 0; /* We now have a request to play with */ + + if (!strcmp(r->method, "HEAD")) { + r->header_only = 1; + r->method_number = M_GET; + } + else if (!strcmp(r->method, "GET")) + r->method_number = M_GET; + else if (!strcmp(r->method, "POST")) r->method_number = M_POST; - else if(!strcmp(r->method,"PUT")) + else if (!strcmp(r->method, "PUT")) r->method_number = M_PUT; - else if(!strcmp(r->method,"DELETE")) + else if (!strcmp(r->method, "DELETE")) r->method_number = M_DELETE; - else if(!strcmp(r->method,"CONNECT")) + else if (!strcmp(r->method, "CONNECT")) r->method_number = M_CONNECT; - else if(!strcmp(r->method,"OPTIONS")) + else if (!strcmp(r->method, "OPTIONS")) r->method_number = M_OPTIONS; - else if(!strcmp(r->method,"TRACE")) + else if (!strcmp(r->method, "TRACE")) r->method_number = M_TRACE; - else - r->method_number = M_INVALID; /* Will eventually croak. */ + else + r->method_number = M_INVALID; /* Will eventually croak. */ - if ((access_status = run_post_read_request (r))) { - die (access_status, r); - return NULL; + if ((access_status = run_post_read_request(r))) { + die(access_status, r); + return NULL; } return r; @@ -964,55 +971,57 @@ * *someone* has to set the protocol-specific fields... */ -void set_sub_req_protocol (request_rec *rnew, const request_rec *r) +void set_sub_req_protocol(request_rec *rnew, const request_rec *r) { - rnew->the_request = r->the_request; /* Keep original request-line */ + rnew->the_request = r->the_request; /* Keep original request-line */ + + rnew->assbackwards = 1; /* Don't send headers from this. */ + rnew->no_local_copy = 1; /* Don't try to send USE_LOCAL_COPY for a + * fragment. */ + rnew->method = "GET"; + rnew->method_number = M_GET; + rnew->protocol = "INCLUDED"; + + rnew->status = HTTP_OK; - rnew->assbackwards = 1; /* Don't send headers from this. */ - rnew->no_local_copy = 1; /* Don't try to send USE_LOCAL_COPY for a - * fragment. - */ - rnew->method = "GET"; rnew->method_number = M_GET; - rnew->protocol = "INCLUDED"; + rnew->headers_in = r->headers_in; + rnew->subprocess_env = copy_table(rnew->pool, r->subprocess_env); + rnew->headers_out = make_table(rnew->pool, 5); + rnew->err_headers_out = make_table(rnew->pool, 5); + rnew->notes = make_table(rnew->pool, 5); - rnew->status = HTTP_OK; + rnew->read_length = r->read_length; + rnew->read_body = REQUEST_NO_BODY; - rnew->headers_in = r->headers_in; - rnew->subprocess_env = copy_table (rnew->pool, r->subprocess_env); - rnew->headers_out = make_table (rnew->pool, 5); - rnew->err_headers_out = make_table (rnew->pool, 5); - rnew->notes = make_table (rnew->pool, 5); - - rnew->read_length = r->read_length; - rnew->read_body = REQUEST_NO_BODY; - - rnew->main = (request_rec *)r; + rnew->main = (request_rec *) r; } -void finalize_sub_req_protocol (request_rec *sub) +void finalize_sub_req_protocol(request_rec *sub) { - SET_BYTES_SENT (sub->main); -} + SET_BYTES_SENT(sub->main); +} -/* Support for the Basic authentication protocol, and a bit for Digest. +/* + * Support for the Basic authentication protocol, and a bit for Digest. */ API_EXPORT(void) note_auth_failure(request_rec *r) { if (!strcasecmp(auth_type(r), "Basic")) - note_basic_auth_failure(r); - else if(!strcasecmp(auth_type(r), "Digest")) - note_digest_auth_failure(r); + note_basic_auth_failure(r); + else if (!strcasecmp(auth_type(r), "Digest")) + note_digest_auth_failure(r); } API_EXPORT(void) note_basic_auth_failure(request_rec *r) { if (strcasecmp(auth_type(r), "Basic")) - note_auth_failure(r); + note_auth_failure(r); else - table_set (r->err_headers_out, r->proxyreq ? "Proxy-Authenticate" : - "WWW-Authenticate", - pstrcat(r->pool, "Basic realm=\"", auth_name(r), "\"", NULL)); + table_set(r->err_headers_out, + r->proxyreq ? "Proxy-Authenticate" : "WWW-Authenticate", + pstrcat(r->pool, "Basic realm=\"", auth_name(r), "\"", + NULL)); } API_EXPORT(void) note_digest_auth_failure(request_rec *r) @@ -1020,38 +1029,39 @@ char nonce[256]; ap_snprintf(nonce, sizeof(nonce), "%lu", r->request_time); - table_set (r->err_headers_out, r->proxyreq ? "Proxy-Authenticate" : - "WWW-Authenticate", - pstrcat(r->pool, "Digest realm=\"", auth_name(r), - "\", nonce=\"", nonce, "\"", NULL)); + table_set(r->err_headers_out, + r->proxyreq ? "Proxy-Authenticate" : "WWW-Authenticate", + pstrcat(r->pool, "Digest realm=\"", auth_name(r), + "\", nonce=\"", nonce, "\"", NULL)); } -API_EXPORT(int) get_basic_auth_pw (request_rec *r, char **pw) +API_EXPORT(int) get_basic_auth_pw(request_rec *r, char **pw) { - const char *auth_line = table_get(r->headers_in, r->proxyreq ? - "Proxy-Authorization" : - "Authorization"); + const char *auth_line = table_get(r->headers_in, + r->proxyreq ? "Proxy-Authorization" + : "Authorization"); char *t; - - if(!(t = auth_type(r)) || strcasecmp(t, "Basic")) + + if (!(t = auth_type(r)) || strcasecmp(t, "Basic")) return DECLINED; if (!auth_name(r)) { - aplog_error(APLOG_MARK, APLOG_ERR, r->server, "need AuthName: %s", r->uri); - return SERVER_ERROR; + aplog_error(APLOG_MARK, APLOG_ERR, r->server, "need AuthName: %s", + r->uri); + return SERVER_ERROR; } - + if (!auth_line) { - note_basic_auth_failure (r); - return AUTH_REQUIRED; + note_basic_auth_failure(r); + return AUTH_REQUIRED; } - if (strcmp(getword (r->pool, &auth_line, ' '), "Basic")) { + if (strcmp(getword(r->pool, &auth_line, ' '), "Basic")) { /* Client tried to authenticate using wrong auth scheme */ aplog_error(APLOG_MARK, APLOG_ERR, r->server, - "client used wrong authentication scheme: %s", r->uri); + "client used wrong authentication scheme: %s", r->uri); note_basic_auth_failure(r); - return AUTH_REQUIRED; + return AUTH_REQUIRED; } t = uudecode(r->pool, auth_line); @@ -1063,56 +1073,56 @@ return OK; } -/* New Apache routine to map status codes into array indicies - * e.g. 100 -> 0, 101 -> 1, 200 -> 2 ... +/* New Apache routine to map status codes into array indicies + * e.g. 100 -> 0, 101 -> 1, 200 -> 2 ... * The number of status lines must equal the value of RESPONSE_CODES (httpd.h) * and must be listed in order. */ static char *status_lines[] = { - "100 Continue", - "101 Switching Protocols", + "100 Continue", + "101 Switching Protocols", #define LEVEL_200 2 - "200 OK", - "201 Created", - "202 Accepted", - "203 Non-Authoritative Information", - "204 No Content", - "205 Reset Content", - "206 Partial Content", + "200 OK", + "201 Created", + "202 Accepted", + "203 Non-Authoritative Information", + "204 No Content", + "205 Reset Content", + "206 Partial Content", #define LEVEL_300 9 - "300 Multiple Choices", - "301 Moved Permanently", - "302 Moved Temporarily", - "303 See Other", - "304 Not Modified", - "305 Use Proxy", + "300 Multiple Choices", + "301 Moved Permanently", + "302 Moved Temporarily", + "303 See Other", + "304 Not Modified", + "305 Use Proxy", #define LEVEL_400 15 - "400 Bad Request", - "401 Authorization Required", - "402 Payment Required", - "403 Forbidden", - "404 Not Found", - "405 Method Not Allowed", - "406 Not Acceptable", - "407 Proxy Authentication Required", - "408 Request Time-out", - "409 Conflict", - "410 Gone", - "411 Length Required", - "412 Precondition Failed", - "413 Request Entity Too Large", - "414 Request-URI Too Large", - "415 Unsupported Media Type", + "400 Bad Request", + "401 Authorization Required", + "402 Payment Required", + "403 Forbidden", + "404 Not Found", + "405 Method Not Allowed", + "406 Not Acceptable", + "407 Proxy Authentication Required", + "408 Request Time-out", + "409 Conflict", + "410 Gone", + "411 Length Required", + "412 Precondition Failed", + "413 Request Entity Too Large", + "414 Request-URI Too Large", + "415 Unsupported Media Type", #define LEVEL_500 31 - "500 Internal Server Error", - "501 Method Not Implemented", - "502 Bad Gateway", - "503 Service Temporarily Unavailable", - "504 Gateway Time-out", - "505 HTTP Version Not Supported", - "506 Variant Also Varies" -}; + "500 Internal Server Error", + "501 Method Not Implemented", + "502 Bad Gateway", + "503 Service Temporarily Unavailable", + "504 Gateway Time-out", + "505 HTTP Version Not Supported", + "506 Variant Also Varies" +}; /* The index is found by its offset from the x00 code of each level. * Although this is fast, it will need to be replaced if some nutcase @@ -1120,27 +1130,26 @@ * If that sad event occurs, replace the code below with a linear search * from status_lines[shortcut[i]] to status_lines[shortcut[i+1]-1]; */ - int index_of_response(int status) { - static int shortcut[6] = { 0, LEVEL_200, LEVEL_300, LEVEL_400, - LEVEL_500, RESPONSE_CODES }; + static int shortcut[6] = {0, LEVEL_200, LEVEL_300, LEVEL_400, + LEVEL_500, RESPONSE_CODES}; int i, pos; - if (status < 100) /* Below 100 is illegal for HTTP status */ + if (status < 100) /* Below 100 is illegal for HTTP status */ return LEVEL_500; for (i = 0; i < 5; i++) { status -= 100; if (status < 100) { pos = (status + shortcut[i]); - if (pos < shortcut[i+1]) + if (pos < shortcut[i + 1]) return pos; else - return LEVEL_500; /* status unknown (falls in gap) */ + return LEVEL_500; /* status unknown (falls in gap) */ } } - return LEVEL_500; /* 600 or above is also illegal */ + return LEVEL_500; /* 600 or above is also illegal */ } /* Send a single HTTP header field to the client. Note that this function @@ -1148,19 +1157,20 @@ * In other words, don't change this one without checking table_do in alloc.c. * It returns true unless there was a write error of some kind. */ -int send_header_field (request_rec *r, const char *fieldname, - const char *fieldval) +int send_header_field(request_rec *r, const char *fieldname, + const char *fieldval) { return (0 < bvputs(r->connection->client, fieldname, ": ", fieldval, "\015\012", NULL)); } -void basic_http_header (request_rec *r) +void basic_http_header(request_rec *r) { char *protocol; - - if (r->assbackwards) return; - + + if (r->assbackwards) + return; + if (!r->status_line) r->status_line = status_lines[index_of_response(r->status)]; @@ -1168,14 +1178,14 @@ * kluge around broken browsers when indicated by force-response-1.0 */ if (r->proxyreq - || (r->proto_num == 1000 - && table_get(r->subprocess_env,"force-response-1.0"))) { + || (r->proto_num == 1000 + && table_get(r->subprocess_env, "force-response-1.0"))) { - protocol = "HTTP/1.0"; - r->connection->keepalive = -1; + protocol = "HTTP/1.0"; + r->connection->keepalive = -1; } else - protocol = SERVER_PROTOCOL; + protocol = SERVER_PROTOCOL; /* Output the HTTP/1.x Status-Line and the Date and Server fields */ @@ -1185,7 +1195,7 @@ send_header_field(r, "Date", gm_timestr_822(r->pool, r->request_time)); send_header_field(r, "Server", SERVER_VERSION); - table_unset(r->headers_out, "Date"); /* Avoid bogosity */ + table_unset(r->headers_out, "Date"); /* Avoid bogosity */ table_unset(r->headers_out, "Server"); } @@ -1206,7 +1216,7 @@ * It is more expensive to check the User-Agent than it is to just add the * bytes, so we haven't used the BrowserMatch feature here. */ -static void terminate_header (BUFF *client) +static void terminate_header(BUFF *client) { long int bs; @@ -1214,7 +1224,7 @@ if (bs == 256 || bs == 257) bputs("X-Pad: avoid browser bug\015\012", client); - bputs("\015\012", client); /* Send the terminating empty line */ + bputs("\015\012", client); /* Send the terminating empty line */ } /* Build the Allow field-value from the request handler method mask. @@ -1232,12 +1242,13 @@ NULL); } -int send_http_trace (request_rec *r) +int send_http_trace(request_rec *r) { int rv; /* Get the original request */ - while (r->prev) r = r->prev; + while (r->prev) + r = r->prev; if ((rv = setup_client_block(r, REQUEST_NO_BODY))) return rv; @@ -1246,13 +1257,13 @@ r->content_type = "message/http"; send_http_header(r); - + /* Now we recreate the request, and echo it back */ - rvputs( r, r->the_request, "\015\012", NULL ); + rvputs(r, r->the_request, "\015\012", NULL); - table_do((int (*)(void *, const char *, const char *))send_header_field, - (void *)r, r->headers_in, NULL); + table_do((int (*) (void *, const char *, const char *)) send_header_field, + (void *) r, r->headers_in, NULL); bputs("\015\012", r->connection->client); kill_timeout(r); @@ -1263,7 +1274,8 @@ { const long int zero = 0L; - if (r->assbackwards) return DECLINED; + if (r->assbackwards) + return DECLINED; hard_timeout("send OPTIONS", r); @@ -1273,8 +1285,8 @@ table_set(r->headers_out, "Allow", make_allow(r)); set_keepalive(r); - table_do((int (*)(void *, const char *, const char *))send_header_field, - (void *)r, r->headers_out, NULL); + table_do((int (*) (void *, const char *, const char *)) send_header_field, + (void *) r, r->headers_out, NULL); terminate_header(r->connection->client); @@ -1291,34 +1303,35 @@ * that the browser supports an older protocol. We also check User-Agent * for Microsoft Internet Explorer 3, which needs this as well. */ - -static int use_range_x(request_rec *r) { +static int use_range_x(request_rec *r) +{ char *ua; return (table_get(r->headers_in, "Request-Range") || - ((ua = table_get(r->headers_in, "User-Agent")) - && strstr(ua, "MSIE 3"))); + ((ua = table_get(r->headers_in, "User-Agent")) + && strstr(ua, "MSIE 3"))); } API_EXPORT(void) send_http_header(request_rec *r) { int i; const long int zero = 0L; - + if (r->assbackwards) { - if(!r->main) - bsetopt(r->connection->client, BO_BYTECT, &zero); - r->sent_bodyct = 1; - return; + if (!r->main) + bsetopt(r->connection->client, BO_BYTECT, &zero); + r->sent_bodyct = 1; + return; } - /* Now that we are ready to send a response, we need to combine the two + /* + * Now that we are ready to send a response, we need to combine the two * header field tables into a single table. If we don't do this, our * later attempts to set or unset a given fieldname might be bypassed. */ if (!is_empty_table(r->err_headers_out)) r->headers_out = overlay_tables(r->pool, r->err_headers_out, - r->headers_out); - + r->headers_out); + hard_timeout("send headers", r); basic_http_header(r); @@ -1338,21 +1351,22 @@ table_set(r->headers_out, "Content-Type", r->content_type); else table_set(r->headers_out, "Content-Type", default_type(r)); - + if (r->content_encoding) table_set(r->headers_out, "Content-Encoding", r->content_encoding); - + if (r->content_languages && r->content_languages->nelts) { for (i = 0; i < r->content_languages->nelts; ++i) { table_merge(r->headers_out, "Content-Language", - ((char**)(r->content_languages->elts))[i]); + ((char **) (r->content_languages->elts))[i]); } } else if (r->content_language) table_set(r->headers_out, "Content-Language", r->content_language); - /* Control cachability for non-cachable responses if not already set - * by some other part of the server configuration. + /* + * Control cachability for non-cachable responses if not already set by + * some other part of the server configuration. */ if (r->no_cache && !table_get(r->headers_out, "Expires")) table_add(r->headers_out, "Expires", @@ -1360,18 +1374,19 @@ /* Send the entire table of header fields, terminated by an empty line. */ - table_do((int (*)(void *, const char *, const char *))send_header_field, - (void *)r, r->headers_out, NULL); + table_do((int (*) (void *, const char *, const char *)) send_header_field, + (void *) r, r->headers_out, NULL); terminate_header(r->connection->client); kill_timeout(r); bsetopt(r->connection->client, BO_BYTECT, &zero); - r->sent_bodyct = 1; /* Whatever follows is real body stuff... */ + r->sent_bodyct = 1; /* Whatever follows is real body stuff... */ /* Set buffer flags for the body */ - if (r->chunked) bsetflag(r->connection->client, B_CHUNK, 1); + if (r->chunked) + bsetflag(r->connection->client, B_CHUNK, 1); } /* finalize_request_protocol is called at completion of sending the @@ -1379,7 +1394,7 @@ * information for any wrappers around the response message body * (i.e., transfer encodings). It should have been named finalize_response. */ -void finalize_request_protocol (request_rec *r) +void finalize_request_protocol(request_rec *r) { if (r->chunked && !r->connection->aborted) { /* @@ -1435,24 +1450,24 @@ * If an error occurs on input, we force an end to keepalive. */ -API_EXPORT(int) setup_client_block (request_rec *r, int read_policy) +API_EXPORT(int) setup_client_block(request_rec *r, int read_policy) { char *tenc = table_get(r->headers_in, "Transfer-Encoding"); char *lenp = table_get(r->headers_in, "Content-Length"); - r->read_body = read_policy; + r->read_body = read_policy; r->read_chunked = 0; - r->remaining = 0; + r->remaining = 0; if (tenc) { if (strcasecmp(tenc, "chunked")) { aplog_error(APLOG_MARK, APLOG_ERR, r->server, - "Unknown Transfer-Encoding %s", tenc); + "Unknown Transfer-Encoding %s", tenc); return HTTP_BAD_REQUEST; } if (r->read_body == REQUEST_CHUNKED_ERROR) { aplog_error(APLOG_MARK, APLOG_ERR, r->server, - "chunked Transfer-Encoding forbidden: %s", r->uri); + "chunked Transfer-Encoding forbidden: %s", r->uri); return (lenp) ? HTTP_BAD_REQUEST : HTTP_LENGTH_REQUIRED; } @@ -1461,10 +1476,11 @@ else if (lenp) { char *pos = lenp; - while (isdigit(*pos) || isspace(*pos)) ++pos; + while (isdigit(*pos) || isspace(*pos)) + ++pos; if (*pos != '\0') { aplog_error(APLOG_MARK, APLOG_ERR, r->server, - "Invalid Content-Length %s", lenp); + "Invalid Content-Length %s", lenp); return HTTP_BAD_REQUEST; } @@ -1474,14 +1490,14 @@ if ((r->read_body == REQUEST_NO_BODY) && (r->read_chunked || (r->remaining > 0))) { aplog_error(APLOG_MARK, APLOG_ERR, r->server, - "%s with body is not allowed for %s", r->method, r->uri); + "%s with body is not allowed for %s", r->method, r->uri); return HTTP_REQUEST_ENTITY_TOO_LARGE; } return OK; } -API_EXPORT(int) should_client_block (request_rec *r) +API_EXPORT(int) should_client_block(request_rec *r) { if (r->read_length || is_HTTP_ERROR(r->status)) return 0; @@ -1489,25 +1505,29 @@ if (!r->read_chunked && (r->remaining <= 0)) return 0; - if (r->proto_num >= 1001) { /* sending 100 Continue interim response */ + if (r->proto_num >= 1001) { /* sending 100 Continue interim response */ bvputs(r->connection->client, - SERVER_PROTOCOL, " ", status_lines[0], "\015\012\015\012", NULL); + SERVER_PROTOCOL, " ", status_lines[0], "\015\012\015\012", + NULL); bflush(r->connection->client); } return 1; } -static long get_chunk_size (char *b) +static long get_chunk_size(char *b) { long chunksize = 0; while (isxdigit(*b)) { int xvalue = 0; - if (*b >= '0' && *b <= '9') xvalue = *b - '0'; - else if (*b >= 'A' && *b <= 'F') xvalue = *b - 'A' + 0xa; - else if (*b >= 'a' && *b <= 'f') xvalue = *b - 'a' + 0xa; + if (*b >= '0' && *b <= '9') + xvalue = *b - '0'; + else if (*b >= 'A' && *b <= 'F') + xvalue = *b - 'A' + 0xa; + else if (*b >= 'a' && *b <= 'f') + xvalue = *b - 'a' + 0xa; chunksize = (chunksize << 4) | xvalue; ++b; @@ -1529,45 +1549,47 @@ * hold a chunk-size line, including any extensions. For now, we'll leave * that to the caller, at least until we can come up with a better solution. */ -API_EXPORT(long) get_client_block (request_rec *r, char *buffer, int bufsiz) +API_EXPORT(long) get_client_block(request_rec *r, char *buffer, int bufsiz) { int c; long len_read, len_to_read; long chunk_start = 0; - if (!r->read_chunked) { /* Content-length read */ + if (!r->read_chunked) { /* Content-length read */ len_to_read = (r->remaining > bufsiz) ? bufsiz : r->remaining; len_read = bread(r->connection->client, buffer, len_to_read); if (len_read <= 0) { - if (len_read < 0) r->connection->keepalive = -1; + if (len_read < 0) + r->connection->keepalive = -1; return len_read; } r->read_length += len_read; - r->remaining -= len_read; + r->remaining -= len_read; return len_read; } - /* Handle chunked reading - * Note: we are careful to shorten the input bufsiz so that there - * will always be enough space for us to add a CRLF (if necessary). + /* + * Handle chunked reading Note: we are careful to shorten the input + * bufsiz so that there will always be enough space for us to add a CRLF + * (if necessary). */ if (r->read_body == REQUEST_CHUNKED_PASS) bufsiz -= 2; if (bufsiz <= 0) - return -1; /* Cannot read chunked with a small buffer */ + return -1; /* Cannot read chunked with a small buffer */ - if (r->remaining == 0) { /* Start of new chunk */ + if (r->remaining == 0) { /* Start of new chunk */ chunk_start = getline(buffer, bufsiz, r->connection->client, 0); if ((chunk_start <= 0) || (chunk_start >= (bufsiz - 1)) - || !isxdigit(*buffer)) { + || !isxdigit(*buffer)) { r->connection->keepalive = -1; return -1; } len_to_read = get_chunk_size(buffer); - if (len_to_read == 0) { /* Last chunk indicated, get footers */ + if (len_to_read == 0) { /* Last chunk indicated, get footers */ if (r->read_body == REQUEST_CHUNKED_DECHUNK) { get_mime_headers(r); ap_snprintf(buffer, bufsiz, "%ld", r->read_length); @@ -1575,43 +1597,45 @@ table_set(r->headers_in, "Content-Length", buffer); return 0; } - r->remaining = -1; /* Indicate footers in-progress */ + r->remaining = -1; /* Indicate footers in-progress */ } else { r->remaining = len_to_read; } if (r->read_body == REQUEST_CHUNKED_PASS) { - buffer[chunk_start++] = CR; /* Restore chunk-size line end */ + buffer[chunk_start++] = CR; /* Restore chunk-size line end */ buffer[chunk_start++] = LF; - buffer += chunk_start; /* and pass line on to caller */ + buffer += chunk_start; /* and pass line on to caller */ bufsiz -= chunk_start; - } else { - /* REQUEST_CHUNKED_DECHUNK -- do not include the length of - * the header in the return value */ - chunk_start = 0; - } + } + else { + /* REQUEST_CHUNKED_DECHUNK -- do not include the length of the + * header in the return value + */ + chunk_start = 0; + } } - /* When REQUEST_CHUNKED_PASS, we are */ - if (r->remaining == -1) { /* reading footers until empty line */ + /* When REQUEST_CHUNKED_PASS, we are */ + if (r->remaining == -1) { /* reading footers until empty line */ len_read = chunk_start; while ((bufsiz > 1) && ((len_read = - getline(buffer, bufsiz, r->connection->client, 1)) > 0)) { + getline(buffer, bufsiz, r->connection->client, 1)) > 0)) { if (len_read != (bufsiz - 1)) { - buffer[len_read++] = CR; /* Restore footer line end */ + buffer[len_read++] = CR; /* Restore footer line end */ buffer[len_read++] = LF; } chunk_start += len_read; - buffer += len_read; - bufsiz -= len_read; + buffer += len_read; + bufsiz -= len_read; } if (len_read < 0) { r->connection->keepalive = -1; return -1; } - if (len_read == 0) { /* Indicates an empty line */ + if (len_read == 0) { /* Indicates an empty line */ buffer[0] = CR; buffer[1] = LF; chunk_start += 2; @@ -1620,16 +1644,16 @@ r->read_length += chunk_start; return chunk_start; } - /* When REQUEST_CHUNKED_PASS, we */ - if (r->remaining == -2) { /* finished footers when last called */ - r->remaining = 0; /* so now we must signal EOF */ + /* When REQUEST_CHUNKED_PASS, we */ + if (r->remaining == -2) { /* finished footers when last called */ + r->remaining = 0; /* so now we must signal EOF */ return 0; } /* Otherwise, we are in the midst of reading a chunk of data */ len_to_read = (r->remaining > bufsiz) ? bufsiz : r->remaining; - + len_read = bread(r->connection->client, buffer, len_to_read); if (len_read <= 0) { r->connection->keepalive = -1; @@ -1638,9 +1662,9 @@ r->remaining -= len_read; - if (r->remaining == 0) { /* End of chunk, get trailing CRLF */ + if (r->remaining == 0) { /* End of chunk, get trailing CRLF */ if ((c = bgetc(r->connection->client)) == CR) { - c = bgetc(r->connection->client); + c = bgetc(r->connection->client); } if (c != LF) { r->connection->keepalive = -1; @@ -1661,7 +1685,7 @@ * This helper routine tests for and reads any message body in the request, * simply discarding whatever it receives. We need to do this because * failing to read the request body would cause it to be interpreted - * as the next request on a persistent connection. + * as the next request on a persistent connection. * * Since we return an error status if the request is malformed, this * routine should be called at the beginning of a no-body handler, e.g., @@ -1693,7 +1717,8 @@ /* * Send the body of a response to the client. */ -API_EXPORT(long) send_fd(FILE *f, request_rec *r) { +API_EXPORT(long) send_fd(FILE *f, request_rec *r) +{ return send_fd_length(f, r, -1); } @@ -1702,32 +1727,34 @@ char buf[IOBUFSIZE]; long total_bytes_sent = 0; register int n, w, o, len; - - if (length == 0) return 0; + + if (length == 0) + return 0; soft_timeout("send body", r); while (!r->connection->aborted) { - if ((length > 0) && (total_bytes_sent + IOBUFSIZE) > length) - len = length - total_bytes_sent; - else len = IOBUFSIZE; - - while ((n= fread(buf, sizeof(char), len, f)) < 1 - && ferror(f) && errno == EINTR && !r->connection->aborted) - continue; - - if (n < 1) { + if ((length > 0) && (total_bytes_sent + IOBUFSIZE) > length) + len = length - total_bytes_sent; + else + len = IOBUFSIZE; + + while ((n = fread(buf, sizeof(char), len, f)) < 1 + && ferror(f) && errno == EINTR && !r->connection->aborted) + continue; + + if (n < 1) { break; } - o=0; - total_bytes_sent += n; + o = 0; + total_bytes_sent += n; while (n && !r->connection->aborted) { w = bwrite(r->connection->client, &buf[o], n); if (w > 0) { - reset_timeout(r); /* reset timeout after successful write */ - n-=w; - o+=w; + reset_timeout(r); /* reset timeout after successful write */ + n -= w; + o += w; } else if (w < 0) { if (r->connection->aborted) @@ -1736,9 +1763,10 @@ continue; else { aplog_error(APLOG_MARK, APLOG_DEBUG, r->server, - "send body lost connection to %s", + "send body lost connection to %s", get_remote_host(r->connection, - r->per_dir_config, REMOTE_NAME)); + r->per_dir_config, + REMOTE_NAME)); bsetflag(r->connection->client, B_EOUT, 1); r->connection->aborted = 1; break; @@ -1746,7 +1774,7 @@ } } } - + kill_timeout(r); SET_BYTES_SENT(r); return total_bytes_sent; @@ -1755,7 +1783,8 @@ /* * Send the body of a response to the client. */ -API_EXPORT(long) send_fb(BUFF *fb, request_rec *r) { +API_EXPORT(long) send_fb(BUFF *fb, request_rec *r) +{ return send_fb_length(fb, r, -1); } @@ -1765,48 +1794,54 @@ long total_bytes_sent = 0; register int n, w, o, len, fd; fd_set fds; - - if (length == 0) return 0; + + if (length == 0) + return 0; /* Make fb unbuffered and non-blocking */ - bsetflag (fb, B_RD, 0); - bnonblock (fb, B_RD); - fd = bfileno (fb, B_RD); + bsetflag(fb, B_RD, 0); + bnonblock(fb, B_RD); + fd = bfileno(fb, B_RD); soft_timeout("send body", r); while (!r->connection->aborted) { - if ((length > 0) && (total_bytes_sent + IOBUFSIZE) > length) - len = length - total_bytes_sent; - else len = IOBUFSIZE; - - do { - n = bread (fb, buf, len); - if (n >= 0) break; - if (n < 0 && errno != EAGAIN) break; - /* we need to block, so flush the output first */ - bflush (r->connection->client); - FD_ZERO (&fds); - FD_SET (fd, &fds); - /* we don't care what select says, we might as well loop back - * around and try another read - */ - ap_select (fd+1, &fds, NULL, NULL, NULL); - } while (!r->connection->aborted); - - if (n < 1 || r->connection->aborted) { - break; - } + if ((length > 0) && (total_bytes_sent + IOBUFSIZE) > length) + len = length - total_bytes_sent; + else + len = IOBUFSIZE; + + do { + n = bread(fb, buf, len); + if (n >= 0) + break; + if (n < 0 && errno != EAGAIN) + break; + /* we need to block, so flush the output first */ + bflush(r->connection->client); + FD_ZERO(&fds); + FD_SET(fd, &fds); + /* + * we don't care what select says, we might as well loop back + * around and try another read + */ + ap_select(fd + 1, &fds, NULL, NULL, NULL); + } while (!r->connection->aborted); - o=0; - total_bytes_sent += n; + if (n < 1 || r->connection->aborted) { + break; + } + + o = 0; + total_bytes_sent += n; while (n && !r->connection->aborted) { w = bwrite(r->connection->client, &buf[o], n); if (w > 0) { - reset_timeout(r); /* reset timeout after successful write */ - n-=w; - o+=w; + reset_timeout(r); /* reset timeout after successful + * write */ + n -= w; + o += w; } else if (w < 0) { if (r->connection->aborted) @@ -1815,9 +1850,10 @@ continue; else { aplog_error(APLOG_MARK, APLOG_DEBUG, r->server, - "send body lost connection to %s", + "send body lost connection to %s", get_remote_host(r->connection, - r->per_dir_config, REMOTE_NAME)); + r->per_dir_config, + REMOTE_NAME)); bsetflag(r->connection->client, B_EOUT, 1); r->connection->aborted = 1; break; @@ -1843,33 +1879,35 @@ * multiple of 16k. (And you need a SunATM2.0 network card.) */ #ifndef MMAP_SEGMENT_SIZE -#define MMAP_SEGMENT_SIZE 32768 +#define MMAP_SEGMENT_SIZE 32768 #endif /* send data from an in-memory buffer */ -API_EXPORT(size_t) send_mmap(void * mm, request_rec *r, size_t offset, - size_t length) +API_EXPORT(size_t) send_mmap(void *mm, request_rec *r, size_t offset, + size_t length) { size_t total_bytes_sent = 0; int n, w; - - if (length == 0) return 0; + + if (length == 0) + return 0; soft_timeout("send mmap", r); length += offset; while (!r->connection->aborted && offset < length) { - if (length - offset > MMAP_SEGMENT_SIZE) { - n = MMAP_SEGMENT_SIZE; - } else { - n = length - offset; - } + if (length - offset > MMAP_SEGMENT_SIZE) { + n = MMAP_SEGMENT_SIZE; + } + else { + n = length - offset; + } while (n && !r->connection->aborted) { - w = bwrite(r->connection->client, (char *)mm + offset, n); + w = bwrite(r->connection->client, (char *) mm + offset, n); if (w > 0) { - reset_timeout(r); /* reset timeout after successful write */ - total_bytes_sent += w; + reset_timeout(r); /* reset timeout after successful write */ + total_bytes_sent += w; n -= w; offset += w; } @@ -1880,9 +1918,10 @@ continue; else { aplog_error(APLOG_MARK, APLOG_DEBUG, r->server, - "send mmap lost connection to %s", + "send mmap lost connection to %s", get_remote_host(r->connection, - r->per_dir_config, REMOTE_NAME)); + r->per_dir_config, + REMOTE_NAME)); bsetflag(r->connection->client, B_EOUT, 1); r->connection->aborted = 1; break; @@ -1890,15 +1929,16 @@ } } } - + kill_timeout(r); SET_BYTES_SENT(r); return total_bytes_sent; } -API_EXPORT(int) rputc (int c, request_rec *r) +API_EXPORT(int) rputc(int c, request_rec *r) { - if (r->connection->aborted) return EOF; + if (r->connection->aborted) + return EOF; bputc(c, r->connection->client); SET_BYTES_SENT(r); return c; @@ -1906,7 +1946,8 @@ API_EXPORT(int) rputs(const char *str, request_rec *r) { - if (r->connection->aborted) return EOF; + if (r->connection->aborted) + return EOF; SET_BYTES_SENT(r); return bputs(str, r->connection->client); } @@ -1914,47 +1955,49 @@ API_EXPORT(int) rwrite(const void *buf, int nbyte, request_rec *r) { int n; - if (r->connection->aborted) return EOF; - n=bwrite(r->connection->client, buf, nbyte); + if (r->connection->aborted) + return EOF; + n = bwrite(r->connection->client, buf, nbyte); SET_BYTES_SENT(r); return n; } -API_EXPORT(int) rprintf(request_rec *r,const char *fmt,...) +API_EXPORT(int) rprintf(request_rec *r, const char *fmt,...) { va_list vlist; int n; - if(r->connection->aborted) return EOF; - va_start(vlist,fmt); - n=vbprintf(r->connection->client,fmt,vlist); + if (r->connection->aborted) + return EOF; + va_start(vlist, fmt); + n = vbprintf(r->connection->client, fmt, vlist); va_end(vlist); SET_BYTES_SENT(r); return n; } -API_EXPORT_NONSTD(int) rvputs(request_rec *r, ...) +API_EXPORT_NONSTD(int) rvputs(request_rec *r,...) { va_list args; int i, j, k; const char *x; - BUFF *fb=r->connection->client; - - if (r->connection->aborted) return EOF; - - va_start (args, r); - for (k=0;;) - { - x = va_arg(args, const char *); - if (x == NULL) break; - j = strlen(x); - i = bwrite(fb, x, j); - if (i != j) - { - va_end(args); - return -1; - } - k += i; + BUFF *fb = r->connection->client; + + if (r->connection->aborted) + return EOF; + + va_start(args, r); + for (k = 0;;) { + x = va_arg(args, const char *); + if (x == NULL) + break; + j = strlen(x); + i = bwrite(fb, x, j); + if (i != j) { + va_end(args); + return -1; + } + k += i; } va_end(args); @@ -1962,7 +2005,8 @@ return k; } -API_EXPORT(int) rflush (request_rec *r) { +API_EXPORT(int) rflush(request_rec *r) +{ return bflush(r->connection->client); } @@ -1972,11 +2016,11 @@ * and 5xx (server error) messages that have not been redirected to another * handler via the ErrorDocument feature. */ -void send_error_response (request_rec *r, int recursive_error) +void send_error_response(request_rec *r, int recursive_error) { BUFF *fd = r->connection->client; int status = r->status; - int idx = index_of_response (status); + int idx = index_of_response(status); char *custom_response; char *location = pstrdup(r->pool, table_get(r->headers_out, "Location")); @@ -1987,14 +2031,14 @@ if (status == HTTP_NOT_MODIFIED) { if (!is_empty_table(r->err_headers_out)) r->headers_out = overlay_tables(r->pool, r->err_headers_out, - r->headers_out); + r->headers_out); hard_timeout("send 304", r); basic_http_header(r); set_keepalive(r); table_do((int (*)(void *, const char *, const char *))send_header_field, - (void *)r, r->headers_out, + (void *) r, r->headers_out, "Connection", "Keep-Alive", "ETag", @@ -2004,7 +2048,7 @@ "Vary", "Warning", "WWW-Authenticate", - "Proxy-Authenticate", + "Proxy-Authenticate", NULL); terminate_header(r->connection->client); @@ -2020,211 +2064,205 @@ } if (!r->assbackwards) { - table *tmp = r->headers_out; - - /* For all HTTP/1.x responses for which we generate the message, - * we need to avoid inheriting the "normal status" header fields - * that may have been set by the request handler before the - * error or redirect, except for Location on external redirects. - */ - r->headers_out = r->err_headers_out; - r->err_headers_out = tmp; - clear_table(r->err_headers_out); - - if (location && *location - && (is_HTTP_REDIRECT(status) || status == HTTP_CREATED)) - table_set(r->headers_out, "Location", location); - - r->content_language = NULL; - r->content_languages = NULL; - r->content_encoding = NULL; - r->clength = 0; - r->content_type = "text/html"; - - if ((status == METHOD_NOT_ALLOWED) || (status == NOT_IMPLEMENTED)) - table_set(r->headers_out, "Allow", make_allow(r)); - - send_http_header(r); - - if (r->header_only) { - finalize_request_protocol(r); - return; - } + table *tmp = r->headers_out; + + /* For all HTTP/1.x responses for which we generate the message, + * we need to avoid inheriting the "normal status" header fields + * that may have been set by the request handler before the + * error or redirect, except for Location on external redirects. + */ + r->headers_out = r->err_headers_out; + r->err_headers_out = tmp; + clear_table(r->err_headers_out); + + if (location && *location + && (is_HTTP_REDIRECT(status) || status == HTTP_CREATED)) + table_set(r->headers_out, "Location", location); + + r->content_language = NULL; + r->content_languages = NULL; + r->content_encoding = NULL; + r->clength = 0; + r->content_type = "text/html"; + + if ((status == METHOD_NOT_ALLOWED) || (status == NOT_IMPLEMENTED)) + table_set(r->headers_out, "Allow", make_allow(r)); + + send_http_header(r); + + if (r->header_only) { + finalize_request_protocol(r); + return; + } } - + hard_timeout("send error body", r); - if ((custom_response = response_code_string (r, idx))) { + if ((custom_response = response_code_string(r, idx))) { /* - * We have a custom response output. This should only be - * a text-string to write back. But if the ErrorDocument - * was a local redirect and the requested resource failed - * for any reason, the custom_response will still hold the - * redirect URL. We don't really want to output this URL - * as a text message, so first check the custom response - * string to ensure that it is a text-string (using the - * same test used in die(), i.e. does it start with a - * "). If it doesn't, we've got a recursive error, so find - * the original error and output that as well. - */ - if (custom_response[0] == '\"') { - bputs(custom_response+1, fd); - kill_timeout(r); - finalize_request_protocol(r); - return; - } - /* Redirect failed, so get back the original error - */ - while (r->prev && (r->prev->status != HTTP_OK)) - r = r->prev; + * We have a custom response output. This should only be + * a text-string to write back. But if the ErrorDocument + * was a local redirect and the requested resource failed + * for any reason, the custom_response will still hold the + * redirect URL. We don't really want to output this URL + * as a text message, so first check the custom response + * string to ensure that it is a text-string (using the + * same test used in die(), i.e. does it start with a "). + * If it doesn't, we've got a recursive error, so find + * the original error and output that as well. + */ + if (custom_response[0] == '\"') { + bputs(custom_response + 1, fd); + kill_timeout(r); + finalize_request_protocol(r); + return; + } + /* + * Redirect failed, so get back the original error + */ + while (r->prev && (r->prev->status != HTTP_OK)) + r = r->prev; } { - char *title = status_lines[idx]; - /* folks decided they didn't want the error code in the H1 text */ + char *title = status_lines[idx]; + /* folks decided they didn't want the error code in the H1 text */ + + char *h1 = 4 + status_lines[idx]; + + bvputs(fd, "<HTML><HEAD>\n<TITLE>", title, + "</TITLE>\n</HEAD><BODY>\n<H1>", h1, "</H1>\n", + NULL); - char *h1 = 4 + status_lines[idx]; - - bvputs - ( - fd, - "<HTML><HEAD>\n<TITLE>", - title, - "</TITLE>\n</HEAD><BODY>\n<H1>", - h1, - "</H1>\n", - NULL - ); - switch (status) { - case REDIRECT: - case MOVED: - bvputs(fd, "The document has moved <A HREF=\"", - escape_html(r->pool, location), "\">here</A>.<P>\n", NULL); - break; - case HTTP_SEE_OTHER: - bvputs(fd, "The answer to your request is located <A HREF=\"", - escape_html(r->pool, location), "\">here</A>.<P>\n", NULL); - break; - case HTTP_USE_PROXY: - bvputs(fd, "This resource is only accessible through the proxy\n", - escape_html(r->pool, location), "<BR>\nYou will need to ", + case REDIRECT: + case MOVED: + bvputs(fd, "The document has moved <A HREF=\"", + escape_html(r->pool, location), "\">here</A>.<P>\n", NULL); + break; + case HTTP_SEE_OTHER: + bvputs(fd, "The answer to your request is located <A HREF=\"", + escape_html(r->pool, location), "\">here</A>.<P>\n", NULL); + break; + case HTTP_USE_PROXY: + bvputs(fd, "This resource is only accessible through the proxy\n", + escape_html(r->pool, location), "<BR>\nYou will need to ", "configure your client to use that proxy.<P>\n", NULL); - break; - case HTTP_PROXY_AUTHENTICATION_REQUIRED: - case AUTH_REQUIRED: - bputs("This server could not verify that you\n", fd); - bputs("are authorized to access the document you\n", fd); - bputs("requested. Either you supplied the wrong\n", fd); - bputs("credentials (e.g., bad password), or your\n", fd); - bputs("browser doesn't understand how to supply\n", fd); - bputs("the credentials required.<P>\n", fd); - break; - case BAD_REQUEST: - bputs("Your browser sent a request that\n", fd); - bputs("this server could not understand.<P>\n", fd); - break; - case HTTP_FORBIDDEN: - bvputs(fd, "You don't have permission to access ", - escape_html(r->pool, r->uri), "\non this server.<P>\n", - NULL); - break; - case NOT_FOUND: - bvputs(fd, "The requested URL ", escape_html(r->pool, r->uri), - " was not found on this server.<P>\n", NULL); - break; - case METHOD_NOT_ALLOWED: - bvputs(fd, "The requested method ", r->method, " is not allowed " - "for the URL ", escape_html(r->pool, r->uri), - ".<P>\n", NULL); - break; - case NOT_ACCEPTABLE: - bvputs(fd, - "An appropriate representation of the requested resource ", - escape_html(r->pool, r->uri), - " could not be found on this server.<P>\n", NULL); - /* fall through */ - case MULTIPLE_CHOICES: - { - char *list; - if ((list = table_get (r->notes, "variant-list"))) - bputs(list, fd); - } - break; - case LENGTH_REQUIRED: - bvputs(fd, "A request of the requested method ", r->method, - " requires a valid Content-length.<P>\n", NULL); - break; - case PRECONDITION_FAILED: - bvputs(fd, "The precondition on the request for the URL ", - escape_html(r->pool, r->uri), " evaluated to false.<P>\n", - NULL); - break; - case NOT_IMPLEMENTED: - bvputs(fd, escape_html(r->pool, r->method), " to ", - escape_html(r->pool, r->uri), " not supported.<P>\n", NULL); - break; - case BAD_GATEWAY: - bputs("The proxy server received an invalid\015\012", fd); - bputs("response from an upstream server.<P>\015\012", fd); - break; - case VARIANT_ALSO_VARIES: - bvputs(fd, "A variant for the requested entity ", - escape_html(r->pool, r->uri), " is itself a ", - "transparently negotiable resource.<P>\n", NULL); - break; - case HTTP_REQUEST_TIME_OUT: - bputs("I'm tired of waiting for your request.\n", fd); - break; - case HTTP_GONE: - bvputs(fd, "The requested resource<BR>", - escape_html(r->pool, r->uri), + break; + case HTTP_PROXY_AUTHENTICATION_REQUIRED: + case AUTH_REQUIRED: + bputs("This server could not verify that you\n", fd); + bputs("are authorized to access the document you\n", fd); + bputs("requested. Either you supplied the wrong\n", fd); + bputs("credentials (e.g., bad password), or your\n", fd); + bputs("browser doesn't understand how to supply\n", fd); + bputs("the credentials required.<P>\n", fd); + break; + case BAD_REQUEST: + bputs("Your browser sent a request that\n", fd); + bputs("this server could not understand.<P>\n", fd); + break; + case HTTP_FORBIDDEN: + bvputs(fd, "You don't have permission to access ", + escape_html(r->pool, r->uri), "\non this server.<P>\n", + NULL); + break; + case NOT_FOUND: + bvputs(fd, "The requested URL ", escape_html(r->pool, r->uri), + " was not found on this server.<P>\n", NULL); + break; + case METHOD_NOT_ALLOWED: + bvputs(fd, "The requested method ", r->method, " is not allowed " + "for the URL ", escape_html(r->pool, r->uri), + ".<P>\n", NULL); + break; + case NOT_ACCEPTABLE: + bvputs(fd, + "An appropriate representation of the requested resource ", + escape_html(r->pool, r->uri), + " could not be found on this server.<P>\n", NULL); + /* fall through */ + case MULTIPLE_CHOICES: + { + char *list; + if ((list = table_get(r->notes, "variant-list"))) + bputs(list, fd); + } + break; + case LENGTH_REQUIRED: + bvputs(fd, "A request of the requested method ", r->method, + " requires a valid Content-length.<P>\n", NULL); + break; + case PRECONDITION_FAILED: + bvputs(fd, "The precondition on the request for the URL ", + escape_html(r->pool, r->uri), " evaluated to false.<P>\n", + NULL); + break; + case NOT_IMPLEMENTED: + bvputs(fd, escape_html(r->pool, r->method), " to ", + escape_html(r->pool, r->uri), " not supported.<P>\n", NULL); + break; + case BAD_GATEWAY: + bputs("The proxy server received an invalid\015\012", fd); + bputs("response from an upstream server.<P>\015\012", fd); + break; + case VARIANT_ALSO_VARIES: + bvputs(fd, "A variant for the requested entity ", + escape_html(r->pool, r->uri), " is itself a ", + "transparently negotiable resource.<P>\n", NULL); + break; + case HTTP_REQUEST_TIME_OUT: + bputs("I'm tired of waiting for your request.\n", fd); + break; + case HTTP_GONE: + bvputs(fd, "The requested resource<BR>", + escape_html(r->pool, r->uri), "<BR>\nis no longer available on this server ", - "and there is no forwarding address.\n", - "Please remove all references to this resource.\n", NULL); - break; - case HTTP_REQUEST_ENTITY_TOO_LARGE: - bvputs(fd, "The requested resource<BR>", - escape_html(r->pool, r->uri), "<BR>\n", - "does not allow request data with ", r->method, - " requests, or the amount of data provided in\n", - "the request exceeds the capacity limit.\n", NULL); - break; - case HTTP_REQUEST_URI_TOO_LARGE: - bputs("The requested URL's length exceeds the capacity\n", fd); - bputs("limit for this server.\n", fd); - break; - case HTTP_UNSUPPORTED_MEDIA_TYPE: - bputs("The supplied request data is not in a format\n", fd); - bputs("acceptable for processing by this resource.\n", fd); - break; - case HTTP_SERVICE_UNAVAILABLE: - bputs("The server is temporarily unable to service your\n", fd); - bputs("request due to maintenance downtime or capacity\n", fd); - bputs("problems. Please try again later.\n", fd); - break; - case HTTP_GATEWAY_TIME_OUT: - bputs("The proxy server did not receive a timely response\n", fd); - bputs("from the upstream server.<P>\n", fd); - break; - default: /* HTTP_INTERNAL_SERVER_ERROR */ - bputs("The server encountered an internal error or\n", fd); - bputs("misconfiguration and was unable to complete\n", fd); - bputs("your request.<P>\n", fd); - bputs("Please contact the server administrator,\n ", fd); - bputs(escape_html(r->pool, r->server->server_admin), fd); - bputs(" and inform them of the time the error occurred,\n", fd); - bputs("and anything you might have done that may have\n", fd); - bputs("caused the error.<P>\n", fd); - break; - } - - if (recursive_error) { - bvputs(fd, "<P>Additionally, a ", - status_lines[index_of_response(recursive_error)], - "\nerror was encountered while trying to use an " - "ErrorDocument to handle the request.\n", NULL); - } - bputs("</BODY></HTML>\n", fd); + "and there is no forwarding address.\n", + "Please remove all references to this resource.\n", NULL); + break; + case HTTP_REQUEST_ENTITY_TOO_LARGE: + bvputs(fd, "The requested resource<BR>", + escape_html(r->pool, r->uri), "<BR>\n", + "does not allow request data with ", r->method, + " requests, or the amount of data provided in\n", + "the request exceeds the capacity limit.\n", NULL); + break; + case HTTP_REQUEST_URI_TOO_LARGE: + bputs("The requested URL's length exceeds the capacity\n", fd); + bputs("limit for this server.\n", fd); + break; + case HTTP_UNSUPPORTED_MEDIA_TYPE: + bputs("The supplied request data is not in a format\n", fd); + bputs("acceptable for processing by this resource.\n", fd); + break; + case HTTP_SERVICE_UNAVAILABLE: + bputs("The server is temporarily unable to service your\n", fd); + bputs("request due to maintenance downtime or capacity\n", fd); + bputs("problems. Please try again later.\n", fd); + break; + case HTTP_GATEWAY_TIME_OUT: + bputs("The proxy server did not receive a timely response\n", fd); + bputs("from the upstream server.<P>\n", fd); + break; + default: /* HTTP_INTERNAL_SERVER_ERROR */ + bputs("The server encountered an internal error or\n", fd); + bputs("misconfiguration and was unable to complete\n", fd); + bputs("your request.<P>\n", fd); + bputs("Please contact the server administrator,\n ", fd); + bputs(escape_html(r->pool, r->server->server_admin), fd); + bputs(" and inform them of the time the error occurred,\n", fd); + bputs("and anything you might have done that may have\n", fd); + bputs("caused the error.<P>\n", fd); + break; + } + + if (recursive_error) { + bvputs(fd, "<P>Additionally, a ", + status_lines[index_of_response(recursive_error)], + "\nerror was encountered while trying to use an " + "ErrorDocument to handle the request.\n", NULL); + } + bputs("</BODY></HTML>\n", fd); } kill_timeout(r); finalize_request_protocol(r); @@ -2235,7 +2273,7 @@ * comes along? */ -API_EXPORT(void) client_to_stdout (conn_rec *c) +API_EXPORT(void) client_to_stdout(conn_rec *c) { bflush(c->client); dup2(c->client->fd, STDOUT_FILENO); 1.29 +34 -34 apachen/src/main/http_protocol.h Index: http_protocol.h =================================================================== RCS file: /export/home/cvs/apachen/src/main/http_protocol.h,v retrieving revision 1.28 retrieving revision 1.29 diff -u -r1.28 -r1.29 --- http_protocol.h 1997/09/12 21:49:17 1.28 +++ http_protocol.h 1997/09/14 10:04:59 1.29 @@ -6,7 +6,7 @@ * are met: * * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. + * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in @@ -57,26 +57,26 @@ /* Read a request and fill in the fields. */ -request_rec *read_request (conn_rec *c); +request_rec *read_request(conn_rec *c); /* Send a single HTTP header field */ -int send_header_field (request_rec *r, const char *fieldname, - const char *fieldval); +int send_header_field(request_rec *r, const char *fieldname, + const char *fieldval); /* Send the Status-Line and header fields for HTTP response */ -API_EXPORT(void) send_http_header (request_rec *l); +API_EXPORT(void) send_http_header(request_rec *l); /* Send the response to special method requests */ -int send_http_trace (request_rec *r); -int send_http_options (request_rec *r); +int send_http_trace(request_rec *r); +int send_http_options(request_rec *r); /* Finish up stuff after a request */ -void finalize_request_protocol (request_rec *r); - +void finalize_request_protocol(request_rec *r); + /* Send error back to client... last arg indicates error status in case * we get an error in the process of trying to deal with an ErrorDocument * to handle some other error. In that case, we print the default report @@ -84,8 +84,8 @@ * problem with the ErrorDocument. */ -void send_error_response (request_rec *r, int recursive_error); - +void send_error_response(request_rec *r, int recursive_error); + /* Set last modified header line from the lastmod date of the associated file. * Also, set content length. * @@ -93,8 +93,8 @@ * permit_cache argument is set to one). */ -API_EXPORT(int) set_content_length (request_rec *r, long length); -int set_keepalive (request_rec *r); +API_EXPORT(int) set_content_length(request_rec *r, long length); +int set_keepalive(request_rec *r); API_EXPORT(time_t) rationalize_mtime(request_rec *r, time_t mtime); API_EXPORT(void) set_etag(request_rec *r); API_EXPORT(void) set_last_modified(request_rec *r); @@ -118,38 +118,38 @@ API_EXPORT(long) send_fb_length(BUFF *f, request_rec *r, long length); API_EXPORT(size_t) send_mmap(void *mm, request_rec *r, size_t offset, - size_t length); - + size_t length); + /* Hmmm... could macrofy these for now, and maybe forever, though the * definitions of the macros would get a whole lot hairier. */ - -API_EXPORT(int) rputc (int c, request_rec *r); + +API_EXPORT(int) rputc(int c, request_rec *r); API_EXPORT(int) rputs(const char *str, request_rec *r); API_EXPORT(int) rwrite(const void *buf, int nbyte, request_rec *r); -API_EXPORT_NONSTD(int) rvputs(request_rec *r, ...); -API_EXPORT_NONSTD(int) rprintf(request_rec *r,const char *fmt,...); +API_EXPORT_NONSTD(int) rvputs(request_rec *r,...); +API_EXPORT_NONSTD(int) rprintf(request_rec *r, const char *fmt,...); API_EXPORT(int) rflush(request_rec *r); - + /* * Index used in custom_responses array for a specific error code * (only use outside protocol.c is in getting them configured). */ -int index_of_response (int status); +int index_of_response(int status); /* Reading a block of data from the client connection (e.g., POST arg) */ - -API_EXPORT(int) setup_client_block (request_rec *r, int read_policy); -API_EXPORT(int) should_client_block (request_rec *r); -API_EXPORT(long) get_client_block (request_rec *r, char *buffer, int bufsiz); -API_EXPORT(int) discard_request_body (request_rec *r); + +API_EXPORT(int) setup_client_block(request_rec *r, int read_policy); +API_EXPORT(int) should_client_block(request_rec *r); +API_EXPORT(long) get_client_block(request_rec *r, char *buffer, int bufsiz); +API_EXPORT(int) discard_request_body(request_rec *r); /* Sending a byterange */ -API_EXPORT(int) set_byterange (request_rec *r); -API_EXPORT(int) each_byterange (request_rec *r, long *offset, long *length); - +API_EXPORT(int) set_byterange(request_rec *r); +API_EXPORT(int) each_byterange(request_rec *r, long *offset, long *length); + /* Finally, this charming little number is here to encapsulate the * degree to which nph- scripts completely escape from any discipline * the protocol code might care to impose (this as opposed to other @@ -157,7 +157,7 @@ * to explicitly set the status line). */ -API_EXPORT(void) client_to_stdout (conn_rec *c); +API_EXPORT(void) client_to_stdout(conn_rec *c); /* Support for the Basic authentication protocol. Note that there's @@ -185,16 +185,16 @@ API_EXPORT(void) note_auth_failure(request_rec *r); API_EXPORT(void) note_basic_auth_failure(request_rec *r); API_EXPORT(void) note_digest_auth_failure(request_rec *r); -API_EXPORT(int) get_basic_auth_pw (request_rec *r, char **pw); +API_EXPORT(int) get_basic_auth_pw(request_rec *r, char **pw); /* * Setting up the protocol fields for subsidiary requests... * Also, a wrapup function to keep the internal accounting straight. */ -void set_sub_req_protocol (request_rec *rnew, const request_rec *r); -void finalize_sub_req_protocol (request_rec *sub_r); +void set_sub_req_protocol(request_rec *rnew, const request_rec *r); +void finalize_sub_req_protocol(request_rec *sub_r); /* This is also useful for putting sub_reqs and internal_redirects together */ -void parse_uri (request_rec *r, const char *uri); +void parse_uri(request_rec *r, const char *uri);