📄 protocol.c
字号:
apr_read_type_e eblock = APR_NONBLOCK_READ; ctx = f->ctx; if (!ctx) { f->ctx = ctx = apr_palloc(r->pool, sizeof(*ctx)); ctx->data_sent = 0; } /* Loop through this set of buckets to compute their length */ e = APR_BRIGADE_FIRST(b); while (e != APR_BRIGADE_SENTINEL(b)) { if (APR_BUCKET_IS_EOS(e)) { eos = 1; break; } if (e->length == (apr_size_t)-1) { apr_size_t len; const char *ignored; apr_status_t rv; /* This is probably a pipe bucket. Send everything * prior to this, and then read the data for this bucket. */ rv = apr_bucket_read(e, &ignored, &len, eblock); if (rv == APR_SUCCESS) { /* Attempt a nonblocking read next time through */ eblock = APR_NONBLOCK_READ; r->bytes_sent += len; } else if (APR_STATUS_IS_EAGAIN(rv)) { /* Output everything prior to this bucket, and then * do a blocking read on the next batch. */ if (e != APR_BRIGADE_FIRST(b)) { apr_bucket_brigade *split = apr_brigade_split(b, e); apr_bucket *flush = apr_bucket_flush_create(r->connection->bucket_alloc); APR_BRIGADE_INSERT_TAIL(b, flush); rv = ap_pass_brigade(f->next, b); if (rv != APR_SUCCESS || f->c->aborted) { apr_brigade_destroy(split); return rv; } b = split; e = APR_BRIGADE_FIRST(b); ctx->data_sent = 1; } eblock = APR_BLOCK_READ; continue; } else { ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, "ap_content_length_filter: " "apr_bucket_read() failed"); return rv; } } else { r->bytes_sent += e->length; } e = APR_BUCKET_NEXT(e); } /* If we've now seen the entire response and it's otherwise * okay to set the C-L in the response header, then do so now. * * We can only set a C-L in the response header if we haven't already * sent any buckets on to the next output filter for this request. */ if (ctx->data_sent == 0 && eos) { ap_set_content_length(r, r->bytes_sent); } ctx->data_sent = 1; return ap_pass_brigade(f->next, b);}/* * Send the body of a response to the client. */AP_DECLARE(apr_status_t) ap_send_fd(apr_file_t *fd, request_rec *r, apr_off_t offset, apr_size_t len, apr_size_t *nbytes){ conn_rec *c = r->connection; apr_bucket_brigade *bb = NULL; apr_bucket *b; apr_status_t rv; bb = apr_brigade_create(r->pool, c->bucket_alloc); b = apr_bucket_file_create(fd, offset, len, r->pool, c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(bb, b); rv = ap_pass_brigade(r->output_filters, bb); if (rv != APR_SUCCESS) { *nbytes = 0; /* no way to tell how many were actually sent */ } else { *nbytes = len; } return rv;}#if APR_HAS_MMAP/* send data from an in-memory buffer */AP_DECLARE(size_t) ap_send_mmap(apr_mmap_t *mm, request_rec *r, size_t offset, size_t length){ conn_rec *c = r->connection; apr_bucket_brigade *bb = NULL; apr_bucket *b; bb = apr_brigade_create(r->pool, c->bucket_alloc); b = apr_bucket_mmap_create(mm, offset, length, c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(bb, b); ap_pass_brigade(r->output_filters, bb); return mm->size; /* XXX - change API to report apr_status_t? */}#endif /* APR_HAS_MMAP */typedef struct { apr_bucket_brigade *bb;} old_write_filter_ctx;AP_CORE_DECLARE_NONSTD(apr_status_t) ap_old_write_filter( ap_filter_t *f, apr_bucket_brigade *bb){ old_write_filter_ctx *ctx = f->ctx; AP_DEBUG_ASSERT(ctx); if (ctx->bb != 0) { /* whatever is coming down the pipe (we don't care), we * can simply insert our buffered data at the front and * pass the whole bundle down the chain. */ APR_BRIGADE_CONCAT(ctx->bb, bb); bb = ctx->bb; ctx->bb = NULL; } return ap_pass_brigade(f->next, bb);}static apr_status_t buffer_output(request_rec *r, const char *str, apr_size_t len){ conn_rec *c = r->connection; ap_filter_t *f; old_write_filter_ctx *ctx; if (len == 0) return APR_SUCCESS; /* future optimization: record some flags in the request_rec to * say whether we've added our filter, and whether it is first. */ /* this will typically exit on the first test */ for (f = r->output_filters; f != NULL; f = f->next) { if (ap_old_write_func == f->frec) break; } if (f == NULL) { /* our filter hasn't been added yet */ ctx = apr_pcalloc(r->pool, sizeof(*ctx)); ap_add_output_filter("OLD_WRITE", ctx, r, r->connection); f = r->output_filters; } /* if the first filter is not our buffering filter, then we have to * deliver the content through the normal filter chain */ if (f != r->output_filters) { apr_bucket_brigade *bb = apr_brigade_create(r->pool, c->bucket_alloc); apr_bucket *b = apr_bucket_transient_create(str, len, c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(bb, b); return ap_pass_brigade(r->output_filters, bb); } /* grab the context from our filter */ ctx = r->output_filters->ctx; if (ctx->bb == NULL) { ctx->bb = apr_brigade_create(r->pool, c->bucket_alloc); } return ap_fwrite(f->next, ctx->bb, str, len);}AP_DECLARE(int) ap_rputc(int c, request_rec *r){ char c2 = (char)c; if (r->connection->aborted) { return -1; } if (buffer_output(r, &c2, 1) != APR_SUCCESS) return -1; return c;}AP_DECLARE(int) ap_rputs(const char *str, request_rec *r){ apr_size_t len; if (r->connection->aborted) return -1; if (buffer_output(r, str, len = strlen(str)) != APR_SUCCESS) return -1; return len;}AP_DECLARE(int) ap_rwrite(const void *buf, int nbyte, request_rec *r){ if (r->connection->aborted) return -1; if (buffer_output(r, buf, nbyte) != APR_SUCCESS) return -1; return nbyte;}struct ap_vrprintf_data { apr_vformatter_buff_t vbuff; request_rec *r; char *buff;};static apr_status_t r_flush(apr_vformatter_buff_t *buff){ /* callback function passed to ap_vformatter to be called when * vformatter needs to write into buff and buff.curpos > buff.endpos */ /* ap_vrprintf_data passed as a apr_vformatter_buff_t, which is then * "downcast" to an ap_vrprintf_data */ struct ap_vrprintf_data *vd = (struct ap_vrprintf_data*)buff; if (vd->r->connection->aborted) return -1; /* r_flush is called when vbuff is completely full */ if (buffer_output(vd->r, vd->buff, AP_IOBUFSIZE)) { return -1; } /* reset the buffer position */ vd->vbuff.curpos = vd->buff; vd->vbuff.endpos = vd->buff + AP_IOBUFSIZE; return APR_SUCCESS;}AP_DECLARE(int) ap_vrprintf(request_rec *r, const char *fmt, va_list va){ apr_size_t written; struct ap_vrprintf_data vd; char vrprintf_buf[AP_IOBUFSIZE]; vd.vbuff.curpos = vrprintf_buf; vd.vbuff.endpos = vrprintf_buf + AP_IOBUFSIZE; vd.r = r; vd.buff = vrprintf_buf; if (r->connection->aborted) return -1; written = apr_vformatter(r_flush, &vd.vbuff, fmt, va); /* tack on null terminator on remaining string */ *(vd.vbuff.curpos) = '\0'; if (written != -1) { int n = vd.vbuff.curpos - vrprintf_buf; /* last call to buffer_output, to finish clearing the buffer */ if (buffer_output(r, vrprintf_buf,n) != APR_SUCCESS) return -1; written += n; } return written;}AP_DECLARE_NONSTD(int) ap_rprintf(request_rec *r, const char *fmt, ...){ va_list va; int n; if (r->connection->aborted) return -1; va_start(va, fmt); n = ap_vrprintf(r, fmt, va); va_end(va); return n;}AP_DECLARE_NONSTD(int) ap_rvputs(request_rec *r, ...){ va_list va; const char *s; apr_size_t len; apr_size_t written = 0; if (r->connection->aborted) return -1; /* ### TODO: if the total output is large, put all the strings * ### into a single brigade, rather than flushing each time we * ### fill the buffer */ va_start(va, r); while (1) { s = va_arg(va, const char *); if (s == NULL) break; len = strlen(s); if (buffer_output(r, s, len) != APR_SUCCESS) { return -1; } written += len; } va_end(va); return written;}AP_DECLARE(int) ap_rflush(request_rec *r){ conn_rec *c = r->connection; apr_bucket_brigade *bb; apr_bucket *b; bb = apr_brigade_create(r->pool, c->bucket_alloc); b = apr_bucket_flush_create(c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(bb, b); if (ap_pass_brigade(r->output_filters, bb) != APR_SUCCESS) return -1; return 0;}/* * This function sets the Last-Modified output header field to the value * of the mtime field in the request structure - rationalized to keep it from * being in the future. */AP_DECLARE(void) ap_set_last_modified(request_rec *r){ if (!r->assbackwards) { apr_time_t mod_time = ap_rationalize_mtime(r, r->mtime); char *datestr = apr_palloc(r->pool, APR_RFC822_DATE_LEN); apr_rfc822_date(datestr, mod_time); apr_table_setn(r->headers_out, "Last-Modified", datestr); }}AP_IMPLEMENT_HOOK_RUN_ALL(int,post_read_request, (request_rec *r), (r), OK, DECLINED)AP_IMPLEMENT_HOOK_RUN_ALL(int,log_transaction, (request_rec *r), (r), OK, DECLINED)AP_IMPLEMENT_HOOK_RUN_FIRST(const char *,http_method, (const request_rec *r), (r), NULL)AP_IMPLEMENT_HOOK_RUN_FIRST(unsigned short,default_port, (const request_rec *r), (r), 0)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -