mirror of
https://github.com/apache/httpd.git
synced 2025-08-08 15:02:10 +03:00
http_request.[ch]:
*) add the "install_filter" hook as a hook/control point for modules to install their filters. [Ryan Bloom] http_protocol.c: *) move check_first_conn_error() up in the file; no actual changes *) add checked_bputstrs(), checked_bflush(), and checked_bputs(). These are copies of ap_rvputs(), ap_rflush(), and ap_rputs() respectively. The users of the checked_* functions will be independent of filtering changes to the ap_r* functions. *) add flush_filters() place holder git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@85685 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
@@ -120,6 +120,7 @@ AP_DECLARE_HOOK(int,fixups,(request_rec *))
|
|||||||
AP_DECLARE_HOOK(int,type_checker,(request_rec *))
|
AP_DECLARE_HOOK(int,type_checker,(request_rec *))
|
||||||
AP_DECLARE_HOOK(int,access_checker,(request_rec *))
|
AP_DECLARE_HOOK(int,access_checker,(request_rec *))
|
||||||
AP_DECLARE_HOOK(int,auth_checker,(request_rec *))
|
AP_DECLARE_HOOK(int,auth_checker,(request_rec *))
|
||||||
|
AP_DECLARE_HOOK(void,insert_filter,(request_rec *))
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
@@ -96,6 +96,72 @@ AP_HOOK_STRUCT(
|
|||||||
ap_bgetopt (r->connection->client, BO_BYTECT, &r->bytes_sent); \
|
ap_bgetopt (r->connection->client, BO_BYTECT, &r->bytes_sent); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
|
||||||
|
/* if this is the first error, then log an INFO message and shut down the
|
||||||
|
* connection.
|
||||||
|
*/
|
||||||
|
static void check_first_conn_error(const request_rec *r, const char *operation,
|
||||||
|
ap_status_t status)
|
||||||
|
{
|
||||||
|
if (!r->connection->aborted) {
|
||||||
|
if (status == 0)
|
||||||
|
status = ap_berror(r->connection->client);
|
||||||
|
ap_log_rerror(APLOG_MARK, APLOG_INFO, status, r,
|
||||||
|
"client stopped connection before %s completed",
|
||||||
|
operation);
|
||||||
|
ap_bsetflag(r->connection->client, B_EOUT, 1);
|
||||||
|
r->connection->aborted = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int checked_bputstrs(request_rec *r, ...)
|
||||||
|
{
|
||||||
|
va_list va;
|
||||||
|
int n;
|
||||||
|
|
||||||
|
if (r->connection->aborted)
|
||||||
|
return EOF;
|
||||||
|
|
||||||
|
va_start(va, r);
|
||||||
|
n = ap_vbputstrs(r->connection->client, va);
|
||||||
|
va_end(va);
|
||||||
|
|
||||||
|
if (n < 0) {
|
||||||
|
check_first_conn_error(r, "checked_bputstrs", 0);
|
||||||
|
return EOF;
|
||||||
|
}
|
||||||
|
|
||||||
|
SET_BYTES_SENT(r);
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int checked_bflush(request_rec *r)
|
||||||
|
{
|
||||||
|
ap_status_t rv;
|
||||||
|
|
||||||
|
if ((rv = ap_bflush(r->connection->client)) != APR_SUCCESS) {
|
||||||
|
check_first_conn_error(r, "checked_bflush", rv);
|
||||||
|
return EOF;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int checked_bputs(const char *str, request_rec *r)
|
||||||
|
{
|
||||||
|
int rcode;
|
||||||
|
|
||||||
|
if (r->connection->aborted)
|
||||||
|
return EOF;
|
||||||
|
|
||||||
|
rcode = ap_bputs(str, r->connection->client);
|
||||||
|
if (rcode < 0) {
|
||||||
|
check_first_conn_error(r, "checked_bputs", 0);
|
||||||
|
return EOF;
|
||||||
|
}
|
||||||
|
SET_BYTES_SENT(r);
|
||||||
|
return rcode;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Builds the content-type that should be sent to the client from the
|
* Builds the content-type that should be sent to the client from the
|
||||||
* content-type specified. The following rules are followed:
|
* content-type specified. The following rules are followed:
|
||||||
@@ -276,10 +342,17 @@ static int internal_byterange(int realreq, long *tlength, request_rec *r,
|
|||||||
|
|
||||||
if (!**r_range) {
|
if (!**r_range) {
|
||||||
if (r->byterange > 1) {
|
if (r->byterange > 1) {
|
||||||
if (realreq)
|
if (realreq) {
|
||||||
ap_rvputs(r, CRLF "--", r->boundary, "--" CRLF, NULL);
|
/* ### this isn't "content" so we can't use ap_rvputs(), but
|
||||||
else
|
* ### it should be processed by non-processing filters. We
|
||||||
|
* ### have no "in-between" APIs yet, so send it to the
|
||||||
|
* ### network for now
|
||||||
|
*/
|
||||||
|
(void) checked_bputstrs(r, CRLF "--", r->boundary, "--" CRLF,
|
||||||
|
NULL);
|
||||||
|
} else {
|
||||||
*tlength += 4 + strlen(r->boundary) + 4;
|
*tlength += 4 + strlen(r->boundary) + 4;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#ifdef APACHE_XLATE
|
#ifdef APACHE_XLATE
|
||||||
AP_POP_OUTPUTCONVERSION_STATE(r->connection->client);
|
AP_POP_OUTPUTCONVERSION_STATE(r->connection->client);
|
||||||
@@ -303,9 +376,10 @@ static int internal_byterange(int realreq, long *tlength, request_rec *r,
|
|||||||
ap_snprintf(ts, sizeof(ts), "%ld-%ld/%ld", range_start, range_end,
|
ap_snprintf(ts, sizeof(ts), "%ld-%ld/%ld", range_start, range_end,
|
||||||
r->clength);
|
r->clength);
|
||||||
if (realreq)
|
if (realreq)
|
||||||
ap_rvputs(r, CRLF "--", r->boundary, CRLF "Content-type: ",
|
(void) checked_bputstrs(r, CRLF "--", r->boundary,
|
||||||
ct, CRLF "Content-range: bytes ", ts, CRLF CRLF,
|
CRLF "Content-type: ", ct,
|
||||||
NULL);
|
CRLF "Content-range: bytes ", ts,
|
||||||
|
CRLF CRLF, NULL);
|
||||||
else
|
else
|
||||||
*tlength += 4 + strlen(r->boundary) + 16 + strlen(ct) + 23 +
|
*tlength += 4 + strlen(r->boundary) + 16 + strlen(ct) + 23 +
|
||||||
strlen(ts) + 4;
|
strlen(ts) + 4;
|
||||||
@@ -1394,7 +1468,7 @@ API_EXPORT(int) ap_index_of_response(int status)
|
|||||||
API_EXPORT_NONSTD(int) ap_send_header_field(request_rec *r,
|
API_EXPORT_NONSTD(int) ap_send_header_field(request_rec *r,
|
||||||
const char *fieldname, const char *fieldval)
|
const char *fieldname, const char *fieldval)
|
||||||
{
|
{
|
||||||
return (0 < ap_rvputs(r, fieldname, ": ", fieldval, CRLF, NULL));
|
return (0 < checked_bputstrs(r, fieldname, ": ", fieldval, CRLF, NULL));
|
||||||
}
|
}
|
||||||
|
|
||||||
API_EXPORT(void) ap_basic_http_header(request_rec *r)
|
API_EXPORT(void) ap_basic_http_header(request_rec *r)
|
||||||
@@ -1428,7 +1502,7 @@ API_EXPORT(void) ap_basic_http_header(request_rec *r)
|
|||||||
|
|
||||||
/* Output the HTTP/1.x Status-Line and the Date and Server fields */
|
/* Output the HTTP/1.x Status-Line and the Date and Server fields */
|
||||||
|
|
||||||
ap_rvputs(r, protocol, " ", r->status_line, CRLF, NULL);
|
(void) checked_bputstrs(r, protocol, " ", r->status_line, CRLF, NULL);
|
||||||
|
|
||||||
date = ap_palloc(r->pool, AP_RFC822_DATE_LEN);
|
date = ap_palloc(r->pool, AP_RFC822_DATE_LEN);
|
||||||
ap_rfc822_date(date, r->request_time);
|
ap_rfc822_date(date, r->request_time);
|
||||||
@@ -1465,9 +1539,9 @@ static void terminate_header(request_rec *r)
|
|||||||
|
|
||||||
ap_bgetopt(r->connection->client, BO_BYTECT, &bs);
|
ap_bgetopt(r->connection->client, BO_BYTECT, &bs);
|
||||||
if (bs >= 255 && bs <= 257)
|
if (bs >= 255 && bs <= 257)
|
||||||
ap_rputs("X-Pad: avoid browser bug" CRLF, r);
|
(void) checked_bputs("X-Pad: avoid browser bug" CRLF, r);
|
||||||
|
|
||||||
ap_rputs(CRLF, r); /* Send the terminating empty line */
|
(void) checked_bputs(CRLF, r); /* Send the terminating empty line */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Build the Allow field-value from the request handler method mask.
|
/* Build the Allow field-value from the request handler method mask.
|
||||||
@@ -1747,6 +1821,11 @@ API_EXPORT(void) ap_send_http_header(request_rec *r)
|
|||||||
#endif /*APACHE_XLATE*/
|
#endif /*APACHE_XLATE*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void flush_filters(request_rec *r)
|
||||||
|
{
|
||||||
|
/* ### place holder to flush pending content through the filters */
|
||||||
|
}
|
||||||
|
|
||||||
/* finalize_request_protocol is called at completion of sending the
|
/* finalize_request_protocol is called at completion of sending the
|
||||||
* response. It's sole purpose is to send the terminating protocol
|
* response. It's sole purpose is to send the terminating protocol
|
||||||
* information for any wrappers around the response message body
|
* information for any wrappers around the response message body
|
||||||
@@ -1754,6 +1833,8 @@ API_EXPORT(void) ap_send_http_header(request_rec *r)
|
|||||||
*/
|
*/
|
||||||
API_EXPORT(void) ap_finalize_request_protocol(request_rec *r)
|
API_EXPORT(void) ap_finalize_request_protocol(request_rec *r)
|
||||||
{
|
{
|
||||||
|
flush_filters(r);
|
||||||
|
|
||||||
if (r->chunked && !r->connection->aborted) {
|
if (r->chunked && !r->connection->aborted) {
|
||||||
#ifdef APACHE_XLATE
|
#ifdef APACHE_XLATE
|
||||||
AP_PUSH_OUTPUTCONVERSION_STATE(r->connection->client,
|
AP_PUSH_OUTPUTCONVERSION_STATE(r->connection->client,
|
||||||
@@ -1765,9 +1846,12 @@ API_EXPORT(void) ap_finalize_request_protocol(request_rec *r)
|
|||||||
r->chunked = 0;
|
r->chunked = 0;
|
||||||
ap_bsetflag(r->connection->client, B_CHUNK, 0);
|
ap_bsetflag(r->connection->client, B_CHUNK, 0);
|
||||||
|
|
||||||
ap_rputs("0" CRLF, r);
|
(void) checked_bputs("0" CRLF, r);
|
||||||
|
|
||||||
/* If we had footer "headers", we'd send them now */
|
/* If we had footer "headers", we'd send them now */
|
||||||
ap_rputs(CRLF, r);
|
/* ### these need to be added to allow message digests */
|
||||||
|
|
||||||
|
(void) checked_bputs(CRLF, r);
|
||||||
|
|
||||||
#ifdef APACHE_XLATE
|
#ifdef APACHE_XLATE
|
||||||
AP_POP_OUTPUTCONVERSION_STATE(r->connection->client);
|
AP_POP_OUTPUTCONVERSION_STATE(r->connection->client);
|
||||||
@@ -1901,9 +1985,9 @@ API_EXPORT(int) ap_should_client_block(request_rec *r)
|
|||||||
|
|
||||||
if (r->expecting_100 && r->proto_num >= HTTP_VERSION(1,1)) {
|
if (r->expecting_100 && r->proto_num >= HTTP_VERSION(1,1)) {
|
||||||
/* sending 100 Continue interim response */
|
/* sending 100 Continue interim response */
|
||||||
ap_rvputs(r, AP_SERVER_PROTOCOL, " ", status_lines[0], CRLF CRLF,
|
(void) checked_bputstrs(r, AP_SERVER_PROTOCOL, " ", status_lines[0],
|
||||||
NULL);
|
CRLF CRLF, NULL);
|
||||||
ap_rflush(r);
|
(void) checked_bflush(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
@@ -2148,23 +2232,6 @@ API_EXPORT(int) ap_discard_request_body(request_rec *r)
|
|||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* if this is the first error, then log an INFO message and shut down the
|
|
||||||
* connection.
|
|
||||||
*/
|
|
||||||
static void check_first_conn_error(const request_rec *r, const char *operation,
|
|
||||||
ap_status_t status)
|
|
||||||
{
|
|
||||||
if (!r->connection->aborted) {
|
|
||||||
if (status == 0)
|
|
||||||
status = ap_berror(r->connection->client);
|
|
||||||
ap_log_rerror(APLOG_MARK, APLOG_INFO, status, r,
|
|
||||||
"client stopped connection before %s completed",
|
|
||||||
operation);
|
|
||||||
ap_bsetflag(r->connection->client, B_EOUT, 1);
|
|
||||||
r->connection->aborted = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Send the body of a response to the client.
|
* Send the body of a response to the client.
|
||||||
*/
|
*/
|
||||||
@@ -2208,7 +2275,6 @@ API_EXPORT(long) ap_send_fd_length(ap_file_t *fd, request_rec *r, long length)
|
|||||||
char buf[IOBUFSIZE];
|
char buf[IOBUFSIZE];
|
||||||
long total_bytes_sent = 0;
|
long total_bytes_sent = 0;
|
||||||
register int o;
|
register int o;
|
||||||
ap_ssize_t w;
|
|
||||||
ap_ssize_t n;
|
ap_ssize_t n;
|
||||||
ap_status_t rv;
|
ap_status_t rv;
|
||||||
|
|
||||||
@@ -2217,11 +2283,10 @@ API_EXPORT(long) ap_send_fd_length(ap_file_t *fd, request_rec *r, long length)
|
|||||||
|
|
||||||
while (!r->connection->aborted) {
|
while (!r->connection->aborted) {
|
||||||
if ((length > 0) && (total_bytes_sent + IOBUFSIZE) > length)
|
if ((length > 0) && (total_bytes_sent + IOBUFSIZE) > length)
|
||||||
o = length - total_bytes_sent;
|
n = length - total_bytes_sent;
|
||||||
else
|
else
|
||||||
o = IOBUFSIZE;
|
n = IOBUFSIZE;
|
||||||
|
|
||||||
n = o;
|
|
||||||
do {
|
do {
|
||||||
rv = ap_read(fd, buf, &n);
|
rv = ap_read(fd, buf, &n);
|
||||||
} while (rv == APR_EINTR && !r->connection->aborted);
|
} while (rv == APR_EINTR && !r->connection->aborted);
|
||||||
@@ -2230,20 +2295,10 @@ API_EXPORT(long) ap_send_fd_length(ap_file_t *fd, request_rec *r, long length)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
o = 0;
|
o = ap_rwrite(buf, n, r);
|
||||||
|
if (o < 0)
|
||||||
while (n && !r->connection->aborted) {
|
break;
|
||||||
rv = ap_bwrite(r->connection->client, &buf[o], n, &w);
|
total_bytes_sent += o;
|
||||||
if (w > 0) {
|
|
||||||
total_bytes_sent += w;
|
|
||||||
n -= w;
|
|
||||||
o += w;
|
|
||||||
}
|
|
||||||
else if (rv != APR_SUCCESS) {
|
|
||||||
check_first_conn_error(r, "send-body", rv);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SET_BYTES_SENT(r);
|
SET_BYTES_SENT(r);
|
||||||
@@ -2264,10 +2319,8 @@ API_EXPORT(long) ap_send_fb_length(BUFF *fb, request_rec *r, long length)
|
|||||||
long total_bytes_sent = 0;
|
long total_bytes_sent = 0;
|
||||||
long zero_timeout = 0;
|
long zero_timeout = 0;
|
||||||
register int o;
|
register int o;
|
||||||
ap_ssize_t w;
|
|
||||||
ap_ssize_t n;
|
ap_ssize_t n;
|
||||||
ap_ssize_t bytes_read;
|
ap_ssize_t bytes_read;
|
||||||
ap_status_t rv;
|
|
||||||
ap_status_t read_rv;
|
ap_status_t read_rv;
|
||||||
|
|
||||||
if (length == 0) {
|
if (length == 0) {
|
||||||
@@ -2285,19 +2338,10 @@ API_EXPORT(long) ap_send_fb_length(BUFF *fb, request_rec *r, long length)
|
|||||||
got_read:
|
got_read:
|
||||||
bytes_read = n;
|
bytes_read = n;
|
||||||
/* Regardless of read errors, EOF, etc, bytes may have been read */
|
/* Regardless of read errors, EOF, etc, bytes may have been read */
|
||||||
o = 0;
|
o = ap_rwrite(buf, n, r);
|
||||||
while (n && !r->connection->aborted) {
|
if (o < 0)
|
||||||
rv = ap_bwrite(r->connection->client, &buf[o], n, &w);
|
break;
|
||||||
if (w > 0) {
|
total_bytes_sent += o;
|
||||||
total_bytes_sent += w;
|
|
||||||
n -= w;
|
|
||||||
o += w;
|
|
||||||
}
|
|
||||||
else if (rv != APR_SUCCESS) {
|
|
||||||
check_first_conn_error(r, "rflush", rv);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (read_rv == APR_SUCCESS) {
|
if (read_rv == APR_SUCCESS) {
|
||||||
/* Assume a sucessful read of 0 bytes is an EOF
|
/* Assume a sucessful read of 0 bytes is an EOF
|
||||||
* Note: I don't think this is ultimately the right thing.
|
* Note: I don't think this is ultimately the right thing.
|
||||||
@@ -2354,7 +2398,6 @@ API_EXPORT(size_t) ap_send_mmap(ap_mmap_t *mm, request_rec *r, size_t offset,
|
|||||||
size_t total_bytes_sent = 0;
|
size_t total_bytes_sent = 0;
|
||||||
int n;
|
int n;
|
||||||
ap_ssize_t w;
|
ap_ssize_t w;
|
||||||
ap_status_t rv;
|
|
||||||
char *addr;
|
char *addr;
|
||||||
|
|
||||||
if (length == 0)
|
if (length == 0)
|
||||||
@@ -2370,25 +2413,12 @@ API_EXPORT(size_t) ap_send_mmap(ap_mmap_t *mm, request_rec *r, size_t offset,
|
|||||||
n = length - offset;
|
n = length - offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (n && !r->connection->aborted) {
|
ap_mmap_offset((void**)&addr, mm, offset);
|
||||||
ap_mmap_offset((void**)&addr, mm, offset);
|
w = ap_rwrite(addr, n, r);
|
||||||
rv = ap_bwrite(r->connection->client, addr, n, &w);
|
if (w < 0)
|
||||||
if (w > 0) {
|
break;
|
||||||
total_bytes_sent += w;
|
total_bytes_sent += w;
|
||||||
n -= w;
|
offset += w;
|
||||||
offset += w;
|
|
||||||
}
|
|
||||||
else if (rv != APR_SUCCESS) {
|
|
||||||
if (r->connection->aborted)
|
|
||||||
break;
|
|
||||||
else if (ap_canonical_error(rv) == APR_EAGAIN)
|
|
||||||
continue;
|
|
||||||
else {
|
|
||||||
check_first_conn_error(r, "send-mmap", rv);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SET_BYTES_SENT(r);
|
SET_BYTES_SENT(r);
|
||||||
@@ -2433,6 +2463,7 @@ API_EXPORT(int) ap_rwrite(const void *buf, int nbyte, request_rec *r)
|
|||||||
if (r->connection->aborted)
|
if (r->connection->aborted)
|
||||||
return EOF;
|
return EOF;
|
||||||
|
|
||||||
|
/* ### should loop to avoid partial writes */
|
||||||
rv = ap_bwrite(r->connection->client, buf, nbyte, &n);
|
rv = ap_bwrite(r->connection->client, buf, nbyte, &n);
|
||||||
if (n < 0) {
|
if (n < 0) {
|
||||||
check_first_conn_error(r, "rwrite", rv);
|
check_first_conn_error(r, "rwrite", rv);
|
||||||
|
@@ -86,6 +86,7 @@ AP_HOOK_STRUCT(
|
|||||||
AP_HOOK_LINK(type_checker)
|
AP_HOOK_LINK(type_checker)
|
||||||
AP_HOOK_LINK(access_checker)
|
AP_HOOK_LINK(access_checker)
|
||||||
AP_HOOK_LINK(auth_checker)
|
AP_HOOK_LINK(auth_checker)
|
||||||
|
AP_HOOK_LINK(insert_filter)
|
||||||
)
|
)
|
||||||
|
|
||||||
AP_IMPLEMENT_HOOK_RUN_FIRST(int,translate_name,
|
AP_IMPLEMENT_HOOK_RUN_FIRST(int,translate_name,
|
||||||
@@ -100,6 +101,7 @@ AP_IMPLEMENT_HOOK_RUN_ALL(int,access_checker,
|
|||||||
(request_rec *r),(r),OK,DECLINED)
|
(request_rec *r),(r),OK,DECLINED)
|
||||||
AP_IMPLEMENT_HOOK_RUN_FIRST(int,auth_checker,
|
AP_IMPLEMENT_HOOK_RUN_FIRST(int,auth_checker,
|
||||||
(request_rec *r),(r),DECLINED)
|
(request_rec *r),(r),DECLINED)
|
||||||
|
AP_IMPLEMENT_HOOK_VOID(insert_filter, (request_rec *r), (r))
|
||||||
|
|
||||||
/*****************************************************************
|
/*****************************************************************
|
||||||
*
|
*
|
||||||
@@ -1247,6 +1249,15 @@ static void process_request_internal(request_rec *r)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* The new insert_filter stage makes sense here IMHO. We are sure that
|
||||||
|
* we are going to run the request now, so we may as well insert filters
|
||||||
|
* if any are available. Since the goal of this phase is to allow all
|
||||||
|
* modules to insert a filter if they want to, this filter returns
|
||||||
|
* void. I just can't see any way that this filter can reasonably
|
||||||
|
* fail, either your modules inserts something or it doesn't. rbb
|
||||||
|
*/
|
||||||
|
ap_run_insert_filter(r);
|
||||||
|
|
||||||
if ((access_status = ap_invoke_handler(r)) != 0) {
|
if ((access_status = ap_invoke_handler(r)) != 0) {
|
||||||
ap_die(access_status, r);
|
ap_die(access_status, r);
|
||||||
return;
|
return;
|
||||||
|
Reference in New Issue
Block a user