void exif_brigade_insert_tail( unsigned char *exif_data, unsigned int exif_size, unsigned char *image_data, unsigned long image_size, request_rec *r, apr_bucket_brigade *bb) { apr_bucket *b; b = apr_bucket_pool_create(jpeg_header, sizeof(jpeg_header), r->pool, bb->bucket_alloc); APR_BRIGADE_INSERT_TAIL(bb, b); b = apr_bucket_pool_create(exif_data, exif_size, r->pool, bb->bucket_alloc); APR_BRIGADE_INSERT_TAIL(bb, b); }
static int process_fortune_connection(conn_rec *c) { apr_status_t rv; apr_procattr_t *pattr; apr_pool_t *p = c->pool; apr_bucket *b; apr_bucket_brigade *bb; const char *err_msg = "200 OK\n"; fortune_conf_t *fconf = ap_get_module_config(c->base_server->module_config, &fortune_module); if (!fconf->enabled) { return DECLINED; } bb = apr_brigade_create(p, c->bucket_alloc); /* prepare process attribute */ if ((rv = apr_procattr_create(&pattr, c->pool)) != APR_SUCCESS) { goto error; } if ((rv = apr_procattr_io_set(pattr, APR_NO_PIPE, APR_FULL_BLOCK, APR_NO_PIPE)) != APR_SUCCESS) { goto error; } /* default value: APR_PROGRAM */ if ((rv = apr_procattr_cmdtype_set(pattr, APR_PROGRAM_ENV)) != APR_SUCCESS) { goto error; } /* run the program and read the output from the pipe */ if ((rv = fortune_process(c, pattr, bb)) != APR_SUCCESS) { apr_brigade_cleanup(bb); } error: if (rv != APR_SUCCESS) { err_msg = "500 ERROR\n"; } b = apr_bucket_pool_create(err_msg, strlen(err_msg), p, c->bucket_alloc); APR_BRIGADE_INSERT_HEAD(bb, b); b = apr_bucket_flush_create(c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(bb, b); rv = ap_pass_brigade(c->output_filters, bb); return OK; }
static apr_status_t fortune_process(conn_rec *c, apr_procattr_t *pattr, apr_bucket_brigade *bb) { apr_status_t rv; int argc = 0; const char *argv[APP_MAX_ARGC]; apr_proc_t proc; apr_bucket *b; apr_pool_t *p = c->pool; fortune_conf_t *fconf = ap_get_module_config(c->base_server->module_config, &fortune_module); argv[argc++] = fconf->progname; argv[argc++] = NULL; /* @argvs should be null-terminated */ if ((rv = apr_proc_create(&proc, fconf->progname, (const char *const *) argv, NULL, (apr_procattr_t *) pattr, p)) != APR_SUCCESS) { return rv; } while (TRUE) { char buf[BUFSIZE] = { 0, }; /* read the command's output through the pipe */ rv = apr_file_gets(buf, sizeof(buf), proc.out); if (APR_STATUS_IS_EOF(rv)) { break; } b = apr_bucket_pool_create(apr_pstrdup(p, buf), strlen(buf), p, c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(bb, b); } apr_file_close(proc.out); { int st; apr_exit_why_e why; rv = apr_proc_wait(&proc, &st, &why, APR_WAIT); if (APR_STATUS_IS_CHILD_DONE(rv)) { ap_log_cerror(APLOG_MARK, APLOG_INFO, 0, c, "child done: why = %d, exit status = %d", why, st); } else { ap_log_cerror(APLOG_MARK, APLOG_INFO, 0, c, "child notdone"); return APR_EGENERAL; } } return APR_SUCCESS; }
//------- void write_brigade(apr_bucket_brigade *bb_out,request_rec *r,char *data){ APR_BRIGADE_INSERT_TAIL( bb_out, apr_bucket_pool_create( data, strlen(data), r->pool, r->connection->bucket_alloc ) ); }
/*============================================================================ *============================================================================ * This is the beginning of the cgi filter code moved from mod_include. This * is the code required to handle the "exec" SSI directive. *============================================================================ *============================================================================*/ static apr_status_t include_cgi(include_ctx_t *ctx, ap_filter_t *f, apr_bucket_brigade *bb, char *s) { request_rec *r = f->r; request_rec *rr = ap_sub_req_lookup_uri(s, r, f->next); int rr_status; if (rr->status != HTTP_OK) { ap_destroy_sub_req(rr); return APR_EGENERAL; } /* No hardwired path info or query allowed */ if ((rr->path_info && rr->path_info[0]) || rr->args) { ap_destroy_sub_req(rr); return APR_EGENERAL; } if (rr->finfo.filetype != APR_REG) { ap_destroy_sub_req(rr); return APR_EGENERAL; } /* Script gets parameters of the *document*, for back compatibility */ rr->path_info = r->path_info; /* hard to get right; see mod_cgi.c */ rr->args = r->args; /* Force sub_req to be treated as a CGI request, even if ordinary * typing rules would have called it something else. */ ap_set_content_type(rr, CGI_MAGIC_TYPE); /* Run it. */ rr_status = ap_run_sub_req(rr); if (ap_is_HTTP_REDIRECT(rr_status)) { const char *location = apr_table_get(rr->headers_out, "Location"); if (location) { char *buffer; location = ap_escape_html(rr->pool, location); buffer = apr_pstrcat(ctx->pool, "<a href=\"", location, "\">", location, "</a>", NULL); APR_BRIGADE_INSERT_TAIL(bb, apr_bucket_pool_create(buffer, strlen(buffer), ctx->pool, f->c->bucket_alloc)); } } ap_destroy_sub_req(rr); return APR_SUCCESS; }
static PyObject * conn_write(connobject *self, PyObject *args) { char *buff; int len; apr_bucket_brigade *bb; apr_bucket *b; PyObject *s; conn_rec *c = self->conn; if (! PyArg_ParseTuple(args, "O", &s)) return NULL; if (! PyString_Check(s)) { PyErr_SetString(PyExc_TypeError, "Argument to write() must be a string"); return NULL; } /* PYTHON 2.5: 'PyString_Size' uses Py_ssize_t for return values (may need overflow check) */ len = PyString_Size(s); if (len) { buff = apr_pmemdup(c->pool, PyString_AS_STRING(s), len); bb = apr_brigade_create(c->pool, c->bucket_alloc); b = apr_bucket_pool_create(buff, len, c->pool, c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(bb, b); /* Make sure the data is flushed to the client */ b = apr_bucket_flush_create(c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(bb, b); ap_pass_brigade(c->output_filters, bb); } Py_INCREF(Py_None); return Py_None; }
AP_CORE_DECLARE_NONSTD(apr_status_t) ap_byterange_filter(ap_filter_t *f, apr_bucket_brigade *bb) { request_rec *r = f->r; conn_rec *c = r->connection; apr_bucket *e; apr_bucket_brigade *bsend; apr_bucket_brigade *tmpbb; apr_off_t range_start; apr_off_t range_end; apr_off_t clength = 0; apr_status_t rv; int found = 0; int num_ranges; char *boundary = NULL; char *bound_head = NULL; apr_array_header_t *indexes; indexes_t *idx; int i; int original_status; int max_ranges = get_max_ranges(r); /* * Iterate through the brigade until reaching EOS or a bucket with * unknown length. */ for (e = APR_BRIGADE_FIRST(bb); (e != APR_BRIGADE_SENTINEL(bb) && !APR_BUCKET_IS_EOS(e) && e->length != (apr_size_t)-1); e = APR_BUCKET_NEXT(e)) { clength += e->length; } /* * Don't attempt to do byte range work if this brigade doesn't * contain an EOS, or if any of the buckets has an unknown length; * this avoids the cases where it is expensive to perform * byteranging (i.e. may require arbitrary amounts of memory). */ if (!APR_BUCKET_IS_EOS(e) || clength <= 0) { ap_remove_output_filter(f); return ap_pass_brigade(f->next, bb); } original_status = r->status; num_ranges = ap_set_byterange(r, clength, &indexes); /* We have nothing to do, get out of the way. */ if (num_ranges == 0 || (max_ranges >= 0 && num_ranges > max_ranges)) { r->status = original_status; ap_remove_output_filter(f); return ap_pass_brigade(f->next, bb); } /* this brigade holds what we will be sending */ bsend = apr_brigade_create(r->pool, c->bucket_alloc); if (num_ranges < 0) return send_416(f, bsend); if (num_ranges > 1) { /* Is ap_make_content_type required here? */ const char *orig_ct = ap_make_content_type(r, r->content_type); boundary = apr_psprintf(r->pool, "%" APR_UINT64_T_HEX_FMT "%lx", (apr_uint64_t)r->request_time, c->id); ap_set_content_type(r, apr_pstrcat(r->pool, "multipart", use_range_x(r) ? "/x-" : "/", "byteranges; boundary=", boundary, NULL)); if (strcasecmp(orig_ct, NO_CONTENT_TYPE)) { bound_head = apr_pstrcat(r->pool, CRLF "--", boundary, CRLF "Content-type: ", orig_ct, CRLF "Content-range: bytes ", NULL); } else { /* if we have no type for the content, do our best */ bound_head = apr_pstrcat(r->pool, CRLF "--", boundary, CRLF "Content-range: bytes ", NULL); } ap_xlate_proto_to_ascii(bound_head, strlen(bound_head)); } tmpbb = apr_brigade_create(r->pool, c->bucket_alloc); idx = (indexes_t *)indexes->elts; for (i = 0; i < indexes->nelts; i++, idx++) { range_start = idx->start; range_end = idx->end; rv = copy_brigade_range(bb, tmpbb, range_start, range_end); if (rv != APR_SUCCESS ) { ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, "copy_brigade_range() failed [%" APR_OFF_T_FMT "-%" APR_OFF_T_FMT ",%" APR_OFF_T_FMT "]", range_start, range_end, clength); continue; } found = 1; /* * For single range requests, we must produce Content-Range header. * Otherwise, we need to produce the multipart boundaries. */ if (num_ranges == 1) { apr_table_setn(r->headers_out, "Content-Range", apr_psprintf(r->pool, "bytes " BYTERANGE_FMT, range_start, range_end, clength)); } else { char *ts; e = apr_bucket_pool_create(bound_head, strlen(bound_head), r->pool, c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(bsend, e); ts = apr_psprintf(r->pool, BYTERANGE_FMT CRLF CRLF, range_start, range_end, clength); ap_xlate_proto_to_ascii(ts, strlen(ts)); e = apr_bucket_pool_create(ts, strlen(ts), r->pool, c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(bsend, e); } APR_BRIGADE_CONCAT(bsend, tmpbb); if (i && !(i & 0x1F)) { /* * Every now and then, pass what we have down the filter chain. * In this case, the content-length filter cannot calculate and * set the content length and we must remove any Content-Length * header already present. */ apr_table_unset(r->headers_out, "Content-Length"); if ((rv = ap_pass_brigade(f->next, bsend)) != APR_SUCCESS) return rv; apr_brigade_cleanup(bsend); } } if (found == 0) { /* bsend is assumed to be empty if we get here. */ return send_416(f, bsend); } if (num_ranges > 1) { char *end; /* add the final boundary */ end = apr_pstrcat(r->pool, CRLF "--", boundary, "--" CRLF, NULL); ap_xlate_proto_to_ascii(end, strlen(end)); e = apr_bucket_pool_create(end, strlen(end), r->pool, c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(bsend, e); } e = apr_bucket_eos_create(c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(bsend, e); /* we're done with the original content - all of our data is in bsend. */ apr_brigade_cleanup(bb); apr_brigade_destroy(tmpbb); /* send our multipart output */ return ap_pass_brigade(f->next, bsend); }
/* * process the request and write the response. */ static int ap_proxy_wstunnel_request(apr_pool_t *p, request_rec *r, proxy_conn_rec *conn, proxy_worker *worker, proxy_server_conf *conf, apr_uri_t *uri, char *url, char *server_portstr) { apr_status_t rv = APR_SUCCESS; apr_pollset_t *pollset; apr_pollfd_t pollfd; const apr_pollfd_t *signalled; apr_int32_t pollcnt, pi; apr_int16_t pollevent; conn_rec *c = r->connection; apr_socket_t *sock = conn->sock; conn_rec *backconn = conn->connection; int client_error = 0; char *buf; apr_bucket_brigade *header_brigade; apr_bucket *e; char *old_cl_val = NULL; char *old_te_val = NULL; apr_bucket_brigade *bb = apr_brigade_create(p, c->bucket_alloc); apr_socket_t *client_socket = ap_get_module_config(c->conn_config, &core_module); header_brigade = apr_brigade_create(p, backconn->bucket_alloc); ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "sending request"); rv = ap_proxy_create_hdrbrgd(p, header_brigade, r, conn, worker, conf, uri, url, server_portstr, &old_cl_val, &old_te_val); if (rv != OK) { return rv; } buf = apr_pstrcat(p, "Upgrade: WebSocket", CRLF, "Connection: Upgrade", CRLF, CRLF, NULL); ap_xlate_proto_to_ascii(buf, strlen(buf)); e = apr_bucket_pool_create(buf, strlen(buf), p, c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(header_brigade, e); if ((rv = ap_proxy_pass_brigade(c->bucket_alloc, r, conn, backconn, header_brigade, 1)) != OK) return rv; ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "setting up poll()"); if ((rv = apr_pollset_create(&pollset, 2, p, 0)) != APR_SUCCESS) { ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, "AH02443: " "error apr_pollset_create()"); return HTTP_INTERNAL_SERVER_ERROR; } #if 0 apr_socket_opt_set(sock, APR_SO_NONBLOCK, 1); apr_socket_opt_set(sock, APR_SO_KEEPALIVE, 1); apr_socket_opt_set(client_socket, APR_SO_NONBLOCK, 1); apr_socket_opt_set(client_socket, APR_SO_KEEPALIVE, 1); #endif pollfd.p = p; pollfd.desc_type = APR_POLL_SOCKET; pollfd.reqevents = APR_POLLIN; pollfd.desc.s = sock; pollfd.client_data = NULL; apr_pollset_add(pollset, &pollfd); pollfd.desc.s = client_socket; apr_pollset_add(pollset, &pollfd); r->output_filters = c->output_filters; r->proto_output_filters = c->output_filters; r->input_filters = c->input_filters; r->proto_input_filters = c->input_filters; remove_reqtimeout(r->input_filters); while (1) { /* Infinite loop until error (one side closes the connection) */ if ((rv = apr_pollset_poll(pollset, -1, &pollcnt, &signalled)) != APR_SUCCESS) { if (APR_STATUS_IS_EINTR(rv)) { continue; } ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, "AH02444: " "error apr_poll()"); return HTTP_INTERNAL_SERVER_ERROR; } ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "AH02445: " "woke from poll(), i=%d", pollcnt); for (pi = 0; pi < pollcnt; pi++) { const apr_pollfd_t *cur = &signalled[pi]; if (cur->desc.s == sock) { pollevent = cur->rtnevents; if (pollevent & APR_POLLIN) { ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "AH02446: " "sock was readable"); rv = proxy_wstunnel_transfer(r, backconn, c, bb, "sock"); } else if ((pollevent & APR_POLLERR) || (pollevent & APR_POLLHUP)) { rv = APR_EPIPE; ap_log_rerror(APLOG_MARK, APLOG_NOTICE, 0, r, "AH02447: " "err/hup on backconn"); } if (rv != APR_SUCCESS) client_error = 1; } else if (cur->desc.s == client_socket) { pollevent = cur->rtnevents; if (pollevent & APR_POLLIN) { ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "AH02448: " "client was readable"); rv = proxy_wstunnel_transfer(r, c, backconn, bb, "client"); } } else { rv = APR_EBADF; ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, "AH02449: " "unknown socket in pollset"); } } if (rv != APR_SUCCESS) { break; } } ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "finished with poll() - cleaning up"); if (client_error) { return HTTP_INTERNAL_SERVER_ERROR; } return OK; }
apr_status_t dav_svn__location_body_filter(ap_filter_t *f, apr_bucket_brigade *bb) { request_rec *r = f->r; locate_ctx_t *ctx = f->ctx; apr_bucket *bkt; const char *master_uri, *root_dir, *canonicalized_uri; apr_uri_t uri; /* Don't filter if we're in a subrequest or we aren't setup to proxy anything. */ master_uri = dav_svn__get_master_uri(r); if (r->main || !master_uri) { ap_remove_output_filter(f); return ap_pass_brigade(f->next, bb); } /* And don't filter if our search-n-replace would be a noop anyway (that is, if our root path matches that of the master server). */ apr_uri_parse(r->pool, master_uri, &uri); root_dir = dav_svn__get_root_dir(r); canonicalized_uri = svn_urlpath__canonicalize(uri.path, r->pool); if (strcmp(canonicalized_uri, root_dir) == 0) { ap_remove_output_filter(f); return ap_pass_brigade(f->next, bb); } /* ### FIXME: GET and PROPFIND requests that make it here must be ### referring to data inside commit transactions-in-progress. ### We've got to be careful not to munge the versioned data ### they return in the process of trying to do URI fix-ups. ### See issue #3445 for details. */ /* We are url encoding the current url and the master url as incoming(from master) request body has it encoded already. */ canonicalized_uri = svn_path_uri_encode(canonicalized_uri, r->pool); root_dir = svn_path_uri_encode(root_dir, r->pool); if (!f->ctx) { ctx = f->ctx = apr_pcalloc(r->pool, sizeof(*ctx)); ctx->remotepath = canonicalized_uri; ctx->remotepath_len = strlen(ctx->remotepath); ctx->localpath = root_dir; ctx->localpath_len = strlen(ctx->localpath); ctx->pattern = apr_strmatch_precompile(r->pool, ctx->remotepath, 1); ctx->pattern_len = ctx->remotepath_len; } bkt = APR_BRIGADE_FIRST(bb); while (bkt != APR_BRIGADE_SENTINEL(bb)) { const char *data, *match; apr_size_t len; /* read */ apr_bucket_read(bkt, &data, &len, APR_BLOCK_READ); match = apr_strmatch(ctx->pattern, data, len); if (match) { apr_bucket *next_bucket; apr_bucket_split(bkt, match - data); next_bucket = APR_BUCKET_NEXT(bkt); apr_bucket_split(next_bucket, ctx->pattern_len); bkt = APR_BUCKET_NEXT(next_bucket); apr_bucket_delete(next_bucket); next_bucket = apr_bucket_pool_create(ctx->localpath, ctx->localpath_len, r->pool, bb->bucket_alloc); APR_BUCKET_INSERT_BEFORE(bkt, next_bucket); } else { bkt = APR_BUCKET_NEXT(bkt); } } return ap_pass_brigade(f->next, bb); }
apr_status_t dav_svn__location_in_filter(ap_filter_t *f, apr_bucket_brigade *bb, ap_input_mode_t mode, apr_read_type_e block, apr_off_t readbytes) { request_rec *r = f->r; locate_ctx_t *ctx = f->ctx; apr_status_t rv; apr_bucket *bkt; const char *master_uri, *root_dir, *canonicalized_uri; apr_uri_t uri; /* Don't filter if we're in a subrequest or we aren't setup to proxy anything. */ master_uri = dav_svn__get_master_uri(r); if (r->main || !master_uri) { ap_remove_input_filter(f); return ap_get_brigade(f->next, bb, mode, block, readbytes); } /* And don't filter if our search-n-replace would be a noop anyway (that is, if our root path matches that of the master server). */ apr_uri_parse(r->pool, master_uri, &uri); root_dir = dav_svn__get_root_dir(r); canonicalized_uri = svn_urlpath__canonicalize(uri.path, r->pool); if (strcmp(canonicalized_uri, root_dir) == 0) { ap_remove_input_filter(f); return ap_get_brigade(f->next, bb, mode, block, readbytes); } /* ### FIXME: While we want to fix up any locations in proxied XML ### requests, we do *not* want to be futzing with versioned (or ### to-be-versioned) data, such as the file contents present in ### PUT requests and properties in PROPPATCH requests. ### See issue #3445 for details. */ /* We are url encoding the current url and the master url as incoming(from client) request body has it encoded already. */ canonicalized_uri = svn_path_uri_encode(canonicalized_uri, r->pool); root_dir = svn_path_uri_encode(root_dir, r->pool); if (!f->ctx) { ctx = f->ctx = apr_pcalloc(r->pool, sizeof(*ctx)); ctx->remotepath = canonicalized_uri; ctx->remotepath_len = strlen(ctx->remotepath); ctx->localpath = root_dir; ctx->localpath_len = strlen(ctx->localpath); ctx->pattern = apr_strmatch_precompile(r->pool, ctx->localpath, 1); ctx->pattern_len = ctx->localpath_len; } rv = ap_get_brigade(f->next, bb, mode, block, readbytes); if (rv) { return rv; } bkt = APR_BRIGADE_FIRST(bb); while (bkt != APR_BRIGADE_SENTINEL(bb)) { const char *data, *match; apr_size_t len; if (APR_BUCKET_IS_METADATA(bkt)) { bkt = APR_BUCKET_NEXT(bkt); continue; } /* read */ apr_bucket_read(bkt, &data, &len, APR_BLOCK_READ); match = apr_strmatch(ctx->pattern, data, len); if (match) { apr_bucket *next_bucket; apr_bucket_split(bkt, match - data); next_bucket = APR_BUCKET_NEXT(bkt); apr_bucket_split(next_bucket, ctx->pattern_len); bkt = APR_BUCKET_NEXT(next_bucket); apr_bucket_delete(next_bucket); next_bucket = apr_bucket_pool_create(ctx->remotepath, ctx->remotepath_len, r->pool, bb->bucket_alloc); APR_BUCKET_INSERT_BEFORE(bkt, next_bucket); } else { bkt = APR_BUCKET_NEXT(bkt); } } return APR_SUCCESS; }
static apr_status_t google_analytics_out_filter(ap_filter_t *f, apr_bucket_brigade *bb) { request_rec *r = f->r; google_analytics_filter_ctx *ctx = f->ctx; google_analytics_filter_config *c; apr_bucket *b = APR_BRIGADE_FIRST(bb); apr_size_t bytes; apr_size_t fbytes; apr_size_t offs; const char *buf; const char *le = NULL; const char *le_n; const char *le_r; const char *bufp; const char *subs; unsigned int match; apr_bucket *b1; char *fbuf; int found = 0; apr_status_t rv; apr_bucket_brigade *bbline; // サブリクエストならなにもしない if (r->main) { ap_remove_output_filter(f); return ap_pass_brigade(f->next, bb); } c = ap_get_module_config(r->per_dir_config, &google_analytics_module); if (ctx == NULL) { ctx = f->ctx = apr_pcalloc(r->pool, sizeof(google_analytics_filter_ctx)); ctx->bbsave = apr_brigade_create(r->pool, f->c->bucket_alloc); } // length かわってしまうので unset で OK? apr_table_unset(r->headers_out, "Content-Length"); apr_table_unset(r->headers_out, "Content-MD5"); apr_table_unset(r->headers_out, "Accept-Ranges"); apr_table_unset(r->headers_out, "ETag"); bbline = apr_brigade_create(r->pool, f->c->bucket_alloc); // 改行毎なbucketに編成しなおす while ( b != APR_BRIGADE_SENTINEL(bb) ) { if ( !APR_BUCKET_IS_METADATA(b) ) { if ( apr_bucket_read(b, &buf, &bytes, APR_BLOCK_READ) == APR_SUCCESS ) { if ( bytes == 0 ) { APR_BUCKET_REMOVE(b); } else { while ( bytes > 0 ) { le_n = memchr(buf, '\n', bytes); le_r = memchr(buf, '\r', bytes); if ( le_n != NULL ) { if ( le_n == le_r + sizeof(char)) { le = le_n; } else if ( (le_r < le_n) && (le_r != NULL) ) { le = le_r; } else { le = le_n; } } else { le = le_r; } if ( le ) { offs = 1 + ((unsigned int)le-(unsigned int)buf) / sizeof(char); apr_bucket_split(b, offs); bytes -= offs; buf += offs; b1 = APR_BUCKET_NEXT(b); APR_BUCKET_REMOVE(b); if ( !APR_BRIGADE_EMPTY(ctx->bbsave) ) { APR_BRIGADE_INSERT_TAIL(ctx->bbsave, b); rv = apr_brigade_pflatten(ctx->bbsave, &fbuf, &fbytes, r->pool); b = apr_bucket_pool_create(fbuf, fbytes, r->pool, r->connection->bucket_alloc); apr_brigade_cleanup(ctx->bbsave); } APR_BRIGADE_INSERT_TAIL(bbline, b); b = b1; } else { APR_BUCKET_REMOVE(b); APR_BRIGADE_INSERT_TAIL(ctx->bbsave, b); bytes = 0; } } /* while bytes > 0 */ } } else { APR_BUCKET_REMOVE(b); } } else if ( APR_BUCKET_IS_EOS(b) ) { if ( !APR_BRIGADE_EMPTY(ctx->bbsave) ) { rv = apr_brigade_pflatten(ctx->bbsave, &fbuf, &fbytes, r->pool); b1 = apr_bucket_pool_create(fbuf, fbytes, r->pool, r->connection->bucket_alloc); APR_BRIGADE_INSERT_TAIL(bbline, b1); } apr_brigade_cleanup(ctx->bbsave); f->ctx = NULL; APR_BUCKET_REMOVE(b); APR_BRIGADE_INSERT_TAIL(bbline, b); } else { apr_bucket_delete(b); } b = APR_BRIGADE_FIRST(bb); } // 改行毎なbucketをまわす for ( b = APR_BRIGADE_FIRST(bbline); b != APR_BRIGADE_SENTINEL(bbline); b = APR_BUCKET_NEXT(b) ) { if ( !APR_BUCKET_IS_METADATA(b) && (apr_bucket_read(b, &buf, &bytes, APR_BLOCK_READ) == APR_SUCCESS)) { bufp = buf; if (ap_regexec(regex_tag_exists, bufp, 0, NULL, 0) == 0) { break; } subs = apr_strmatch(pattern_body_end_tag, bufp, bytes); if (subs != NULL) { match = ((unsigned int)subs - (unsigned int)bufp) / sizeof(char); bytes -= match; bufp += match; apr_bucket_split(b, match); b1 = APR_BUCKET_NEXT(b); apr_bucket_split(b1, body_end_tag_length); b = APR_BUCKET_NEXT(b1); apr_bucket_delete(b1); bytes -= body_end_tag_length; bufp += body_end_tag_length; b1 = apr_bucket_immortal_create(c->replace, strlen(c->replace), r->connection->bucket_alloc); APR_BUCKET_INSERT_BEFORE(b, b1); } } } rv = ap_pass_brigade(f->next, bbline); for ( b = APR_BRIGADE_FIRST(ctx->bbsave); b != APR_BRIGADE_SENTINEL(ctx->bbsave); b = APR_BUCKET_NEXT(b)) { apr_bucket_setaside(b, r->pool); } return rv; }
static apr_status_t do_pattmatch(ap_filter_t *f, apr_bucket *inb, apr_bucket_brigade *mybb, apr_pool_t *pool) { int i; int force_quick = 0; ap_regmatch_t regm[AP_MAX_REG_MATCH]; apr_size_t bytes; apr_size_t len; const char *buff; struct ap_varbuf vb; apr_bucket *b; apr_bucket *tmp_b; subst_dir_conf *cfg = (subst_dir_conf *) ap_get_module_config(f->r->per_dir_config, &substitute_module); subst_pattern_t *script; APR_BRIGADE_INSERT_TAIL(mybb, inb); ap_varbuf_init(pool, &vb, 0); script = (subst_pattern_t *) cfg->patterns->elts; /* * Simple optimization. If we only have one pattern, then * we can safely avoid the overhead of flattening */ if (cfg->patterns->nelts == 1) { force_quick = 1; } for (i = 0; i < cfg->patterns->nelts; i++) { for (b = APR_BRIGADE_FIRST(mybb); b != APR_BRIGADE_SENTINEL(mybb); b = APR_BUCKET_NEXT(b)) { if (APR_BUCKET_IS_METADATA(b)) { /* * we should NEVER see this, because we should never * be passed any, but "handle" it just in case. */ continue; } if (apr_bucket_read(b, &buff, &bytes, APR_BLOCK_READ) == APR_SUCCESS) { int have_match = 0; vb.strlen = 0; if (script->pattern) { const char *repl; /* * space_left counts how many bytes we have left until the * line length reaches max_line_length. */ apr_size_t space_left = cfg->max_line_length; apr_size_t repl_len = strlen(script->replacement); while ((repl = apr_strmatch(script->pattern, buff, bytes))) { have_match = 1; /* get offset into buff for pattern */ len = (apr_size_t) (repl - buff); if (script->flatten && !force_quick) { /* * We are flattening the buckets here, meaning * that we don't do the fast bucket splits. * Instead we copy over what the buckets would * contain and use them. This is slow, since we * are constanting allocing space and copying * strings. */ if (vb.strlen + len + repl_len > cfg->max_line_length) return APR_ENOMEM; ap_varbuf_strmemcat(&vb, buff, len); ap_varbuf_strmemcat(&vb, script->replacement, repl_len); } else { /* * The string before the match but after the * previous match (if any) has length 'len'. * Check if we still have space for this string and * the replacement string. */ if (space_left < len + repl_len) return APR_ENOMEM; space_left -= len + repl_len; /* * We now split off the string before the match * as its own bucket, then isolate the matched * string and delete it. */ SEDRMPATBCKT(b, len, tmp_b, script->patlen); /* * Finally, we create a bucket that contains the * replacement... */ tmp_b = apr_bucket_transient_create(script->replacement, script->replen, f->r->connection->bucket_alloc); /* ... and insert it */ APR_BUCKET_INSERT_BEFORE(b, tmp_b); } /* now we need to adjust buff for all these changes */ len += script->patlen; bytes -= len; buff += len; } if (have_match) { if (script->flatten && !force_quick) { /* XXX: we should check for AP_MAX_BUCKETS here and * XXX: call ap_pass_brigade accordingly */ char *copy = ap_varbuf_pdup(pool, &vb, NULL, 0, buff, bytes, &len); tmp_b = apr_bucket_pool_create(copy, len, pool, f->r->connection->bucket_alloc); APR_BUCKET_INSERT_BEFORE(b, tmp_b); apr_bucket_delete(b); b = tmp_b; } else { /* * We want the behaviour to be predictable. * Therefore we try to always error out if the * line length is larger than the limit, * regardless of the content of the line. So, * let's check if the remaining non-matching * string does not exceed the limit. */ if (space_left < b->length) return APR_ENOMEM; } } } else if (script->regexp) { int left = bytes; const char *pos = buff; char *repl; apr_size_t space_left = cfg->max_line_length; while (!ap_regexec_len(script->regexp, pos, left, AP_MAX_REG_MATCH, regm, 0)) { apr_status_t rv; have_match = 1; if (script->flatten && !force_quick) { /* check remaining buffer size */ /* Note that the last param in ap_varbuf_regsub below * must stay positive. If it gets 0, it would mean * unlimited space available. */ if (vb.strlen + regm[0].rm_so >= cfg->max_line_length) return APR_ENOMEM; /* copy bytes before the match */ if (regm[0].rm_so > 0) ap_varbuf_strmemcat(&vb, pos, regm[0].rm_so); /* add replacement string, last argument is unsigned! */ rv = ap_varbuf_regsub(&vb, script->replacement, pos, AP_MAX_REG_MATCH, regm, cfg->max_line_length - vb.strlen); if (rv != APR_SUCCESS) return rv; } else { apr_size_t repl_len; /* acount for string before the match */ if (space_left <= regm[0].rm_so) return APR_ENOMEM; space_left -= regm[0].rm_so; rv = ap_pregsub_ex(pool, &repl, script->replacement, pos, AP_MAX_REG_MATCH, regm, space_left); if (rv != APR_SUCCESS) return rv; repl_len = strlen(repl); space_left -= repl_len; len = (apr_size_t) (regm[0].rm_eo - regm[0].rm_so); SEDRMPATBCKT(b, regm[0].rm_so, tmp_b, len); tmp_b = apr_bucket_transient_create(repl, repl_len, f->r->connection->bucket_alloc); APR_BUCKET_INSERT_BEFORE(b, tmp_b); } /* * reset to past what we just did. pos now maps to b * again */ pos += regm[0].rm_eo; left -= regm[0].rm_eo; } if (have_match && script->flatten && !force_quick) { char *copy; /* Copy result plus the part after the last match into * a bucket. */ copy = ap_varbuf_pdup(pool, &vb, NULL, 0, pos, left, &len); tmp_b = apr_bucket_pool_create(copy, len, pool, f->r->connection->bucket_alloc); APR_BUCKET_INSERT_BEFORE(b, tmp_b); apr_bucket_delete(b); b = tmp_b; } } else { ap_assert(0); continue; } } } script++; } ap_varbuf_free(&vb); return APR_SUCCESS; }
PROXY_DECLARE(int) ap_proxy_create_hdrbrgd(apr_pool_t *p, apr_bucket_brigade *header_brigade, request_rec *r, proxy_conn_rec *p_conn, proxy_worker *worker, proxy_server_conf *conf, apr_uri_t *uri, char *url, char *server_portstr, char **old_cl_val, char **old_te_val) { conn_rec *c = r->connection; int counter; char *buf; const apr_array_header_t *headers_in_array; const apr_table_entry_t *headers_in; apr_table_t *headers_in_copy; apr_bucket *e; int do_100_continue; conn_rec *origin = p_conn->connection; proxy_dir_conf *dconf = ap_get_module_config(r->per_dir_config, &proxy_module); /* * To be compliant, we only use 100-Continue for requests with bodies. * We also make sure we won't be talking HTTP/1.0 as well. */ do_100_continue = (worker->ping_timeout_set && !r->header_only && (apr_table_get(r->headers_in, "Content-Length") || apr_table_get(r->headers_in, "Transfer-Encoding")) && (PROXYREQ_REVERSE == r->proxyreq) && !(apr_table_get(r->subprocess_env, "force-proxy-request-1.0"))); if (apr_table_get(r->subprocess_env, "force-proxy-request-1.0")) { /* * According to RFC 2616 8.2.3 we are not allowed to forward an * Expect: 100-continue to an HTTP/1.0 server. Instead we MUST return * a HTTP_EXPECTATION_FAILED */ if (r->expecting_100) { return HTTP_EXPECTATION_FAILED; } buf = apr_pstrcat(p, r->method, " ", url, " HTTP/1.0" CRLF, NULL); p_conn->close = 1; } else { buf = apr_pstrcat(p, r->method, " ", url, " HTTP/1.1" CRLF, NULL); } if (apr_table_get(r->subprocess_env, "proxy-nokeepalive")) { origin->keepalive = AP_CONN_CLOSE; p_conn->close = 1; } ap_xlate_proto_to_ascii(buf, strlen(buf)); e = apr_bucket_pool_create(buf, strlen(buf), p, c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(header_brigade, e); if (conf->preserve_host == 0) { if (ap_strchr_c(uri->hostname, ':')) { /* if literal IPv6 address */ if (uri->port_str && uri->port != DEFAULT_HTTP_PORT) { buf = apr_pstrcat(p, "Host: [", uri->hostname, "]:", uri->port_str, CRLF, NULL); } else { buf = apr_pstrcat(p, "Host: [", uri->hostname, "]", CRLF, NULL); } } else { if (uri->port_str && uri->port != DEFAULT_HTTP_PORT) { buf = apr_pstrcat(p, "Host: ", uri->hostname, ":", uri->port_str, CRLF, NULL); } else { buf = apr_pstrcat(p, "Host: ", uri->hostname, CRLF, NULL); } } } else { /* don't want to use r->hostname, as the incoming header might have a * port attached */ const char* hostname = apr_table_get(r->headers_in,"Host"); if (!hostname) { hostname = r->server->server_hostname; ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, "AH01092: " "no HTTP 0.9 request (with no host line) " "on incoming request and preserve host set " "forcing hostname to be %s for uri %s", hostname, r->uri); } buf = apr_pstrcat(p, "Host: ", hostname, CRLF, NULL); } ap_xlate_proto_to_ascii(buf, strlen(buf)); e = apr_bucket_pool_create(buf, strlen(buf), p, c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(header_brigade, e); /* handle Via */ if (conf->viaopt == via_block) { /* Block all outgoing Via: headers */ apr_table_unset(r->headers_in, "Via"); } else if (conf->viaopt != via_off) { const char *server_name = ap_get_server_name(r); /* If USE_CANONICAL_NAME_OFF was configured for the proxy virtual host, * then the server name returned by ap_get_server_name() is the * origin server name (which does make too much sense with Via: headers) * so we use the proxy vhost's name instead. */ if (server_name == r->hostname) server_name = r->server->server_hostname; /* Create a "Via:" request header entry and merge it */ /* Generate outgoing Via: header with/without server comment: */ apr_table_mergen(r->headers_in, "Via", (conf->viaopt == via_full) ? apr_psprintf(p, "%d.%d %s%s (%s)", HTTP_VERSION_MAJOR(r->proto_num), HTTP_VERSION_MINOR(r->proto_num), server_name, server_portstr, AP_SERVER_BASEVERSION) : apr_psprintf(p, "%d.%d %s%s", HTTP_VERSION_MAJOR(r->proto_num), HTTP_VERSION_MINOR(r->proto_num), server_name, server_portstr) ); } /* Use HTTP/1.1 100-Continue as quick "HTTP ping" test * to backend */ if (do_100_continue) { apr_table_mergen(r->headers_in, "Expect", "100-Continue"); r->expecting_100 = 1; } /* X-Forwarded-*: handling * * XXX Privacy Note: * ----------------- * * These request headers are only really useful when the mod_proxy * is used in a reverse proxy configuration, so that useful info * about the client can be passed through the reverse proxy and on * to the backend server, which may require the information to * function properly. * * In a forward proxy situation, these options are a potential * privacy violation, as information about clients behind the proxy * are revealed to arbitrary servers out there on the internet. * * The HTTP/1.1 Via: header is designed for passing client * information through proxies to a server, and should be used in * a forward proxy configuation instead of X-Forwarded-*. See the * ProxyVia option for details. */ if (PROXYREQ_REVERSE == r->proxyreq) { const char *buf; /* Add X-Forwarded-For: so that the upstream has a chance to * determine, where the original request came from. */ apr_table_mergen(r->headers_in, "X-Forwarded-For", c->remote_ip); /* Add X-Forwarded-Host: so that upstream knows what the * original request hostname was. */ if ((buf = apr_table_get(r->headers_in, "Host"))) { apr_table_mergen(r->headers_in, "X-Forwarded-Host", buf); } /* Add X-Forwarded-Server: so that upstream knows what the * name of this proxy server is (if there are more than one) * XXX: This duplicates Via: - do we strictly need it? */ apr_table_mergen(r->headers_in, "X-Forwarded-Server", r->server->server_hostname); } proxy_run_fixups(r); /* * Make a copy of the headers_in table before clearing the connection * headers as we need the connection headers later in the http output * filter to prepare the correct response headers. * * Note: We need to take r->pool for apr_table_copy as the key / value * pairs in r->headers_in have been created out of r->pool and * p might be (and actually is) a longer living pool. * This would trigger the bad pool ancestry abort in apr_table_copy if * apr is compiled with APR_POOL_DEBUG. */ headers_in_copy = apr_table_copy(r->pool, r->headers_in); proxy_clear_connection(p, headers_in_copy); /* send request headers */ headers_in_array = apr_table_elts(headers_in_copy); headers_in = (const apr_table_entry_t *) headers_in_array->elts; for (counter = 0; counter < headers_in_array->nelts; counter++) { if (headers_in[counter].key == NULL || headers_in[counter].val == NULL /* Already sent */ || !strcasecmp(headers_in[counter].key, "Host") /* Clear out hop-by-hop request headers not to send * RFC2616 13.5.1 says we should strip these headers */ || !strcasecmp(headers_in[counter].key, "Keep-Alive") || !strcasecmp(headers_in[counter].key, "TE") || !strcasecmp(headers_in[counter].key, "Trailer") || !strcasecmp(headers_in[counter].key, "Upgrade") ) { continue; } /* Do we want to strip Proxy-Authorization ? * If we haven't used it, then NO * If we have used it then MAYBE: RFC2616 says we MAY propagate it. * So let's make it configurable by env. */ if (!strcasecmp(headers_in[counter].key,"Proxy-Authorization")) { if (r->user != NULL) { /* we've authenticated */ if (!apr_table_get(r->subprocess_env, "Proxy-Chain-Auth")) { continue; } } } /* Skip Transfer-Encoding and Content-Length for now. */ if (!strcasecmp(headers_in[counter].key, "Transfer-Encoding")) { *old_te_val = headers_in[counter].val; continue; } if (!strcasecmp(headers_in[counter].key, "Content-Length")) { *old_cl_val = headers_in[counter].val; continue; } /* for sub-requests, ignore freshness/expiry headers */ if (r->main) { if ( !strcasecmp(headers_in[counter].key, "If-Match") || !strcasecmp(headers_in[counter].key, "If-Modified-Since") || !strcasecmp(headers_in[counter].key, "If-Range") || !strcasecmp(headers_in[counter].key, "If-Unmodified-Since") || !strcasecmp(headers_in[counter].key, "If-None-Match")) { continue; } } buf = apr_pstrcat(p, headers_in[counter].key, ": ", headers_in[counter].val, CRLF, NULL); ap_xlate_proto_to_ascii(buf, strlen(buf)); e = apr_bucket_pool_create(buf, strlen(buf), p, c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(header_brigade, e); } return OK; }
/* * process the request and write the response. */ static int proxy_wstunnel_request(apr_pool_t *p, request_rec *r, proxy_conn_rec *conn, proxy_worker *worker, proxy_server_conf *conf, apr_uri_t *uri, char *url, char *server_portstr) { apr_status_t rv; apr_pollset_t *pollset; apr_pollfd_t pollfd; const apr_pollfd_t *signalled; apr_int32_t pollcnt, pi; apr_int16_t pollevent; conn_rec *c = r->connection; apr_socket_t *sock = conn->sock; conn_rec *backconn = conn->connection; char *buf; apr_bucket_brigade *header_brigade; apr_bucket *e; char *old_cl_val = NULL; char *old_te_val = NULL; apr_bucket_brigade *bb = apr_brigade_create(p, c->bucket_alloc); apr_socket_t *client_socket = ap_get_conn_socket(c); int done = 0, replied = 0; header_brigade = apr_brigade_create(p, backconn->bucket_alloc); ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r, "sending request"); rv = ap_proxy_create_hdrbrgd(p, header_brigade, r, conn, worker, conf, uri, url, server_portstr, &old_cl_val, &old_te_val); if (rv != OK) { return rv; } buf = apr_pstrdup(p, "Upgrade: WebSocket" CRLF "Connection: Upgrade" CRLF CRLF); ap_xlate_proto_to_ascii(buf, strlen(buf)); e = apr_bucket_pool_create(buf, strlen(buf), p, c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(header_brigade, e); if ((rv = ap_proxy_pass_brigade(backconn->bucket_alloc, r, conn, backconn, header_brigade, 1)) != OK) return rv; apr_brigade_cleanup(header_brigade); ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r, "setting up poll()"); if ((rv = apr_pollset_create(&pollset, 2, p, 0)) != APR_SUCCESS) { ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(02443) "error apr_pollset_create()"); return HTTP_INTERNAL_SERVER_ERROR; } #if 0 apr_socket_opt_set(sock, APR_SO_NONBLOCK, 1); apr_socket_opt_set(sock, APR_SO_KEEPALIVE, 1); apr_socket_opt_set(client_socket, APR_SO_NONBLOCK, 1); apr_socket_opt_set(client_socket, APR_SO_KEEPALIVE, 1); #endif pollfd.p = p; pollfd.desc_type = APR_POLL_SOCKET; pollfd.reqevents = APR_POLLIN | APR_POLLHUP; pollfd.desc.s = sock; pollfd.client_data = NULL; apr_pollset_add(pollset, &pollfd); pollfd.desc.s = client_socket; apr_pollset_add(pollset, &pollfd); ap_remove_input_filter_byhandle(c->input_filters, "reqtimeout"); r->output_filters = c->output_filters; r->proto_output_filters = c->output_filters; r->input_filters = c->input_filters; r->proto_input_filters = c->input_filters; /* This handler should take care of the entire connection; make it so that * nothing else is attempted on the connection after returning. */ c->keepalive = AP_CONN_CLOSE; do { /* Loop until done (one side closes the connection, or an error) */ rv = apr_pollset_poll(pollset, -1, &pollcnt, &signalled); if (rv != APR_SUCCESS) { if (APR_STATUS_IS_EINTR(rv)) { continue; } ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(02444) "error apr_poll()"); return HTTP_INTERNAL_SERVER_ERROR; } ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, APLOGNO(02445) "woke from poll(), i=%d", pollcnt); for (pi = 0; pi < pollcnt; pi++) { const apr_pollfd_t *cur = &signalled[pi]; if (cur->desc.s == sock) { pollevent = cur->rtnevents; if (pollevent & (APR_POLLIN | APR_POLLHUP)) { ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, APLOGNO(02446) "sock was readable"); done |= ap_proxy_transfer_between_connections(r, backconn, c, header_brigade, bb, "sock", NULL, AP_IOBUFSIZE, 0) != APR_SUCCESS; } else if (pollevent & APR_POLLERR) { ap_log_rerror(APLOG_MARK, APLOG_NOTICE, 0, r, APLOGNO(02447) "error on backconn"); backconn->aborted = 1; done = 1; } else { ap_log_rerror(APLOG_MARK, APLOG_NOTICE, 0, r, APLOGNO(02605) "unknown event on backconn %d", pollevent); done = 1; } } else if (cur->desc.s == client_socket) { pollevent = cur->rtnevents; if (pollevent & (APR_POLLIN | APR_POLLHUP)) { ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, APLOGNO(02448) "client was readable"); done |= ap_proxy_transfer_between_connections(r, c, backconn, bb, header_brigade, "client", &replied, AP_IOBUFSIZE, 0) != APR_SUCCESS; } else if (pollevent & APR_POLLERR) { ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, APLOGNO(02607) "error on client conn"); c->aborted = 1; done = 1; } else { ap_log_rerror(APLOG_MARK, APLOG_NOTICE, 0, r, APLOGNO(02606) "unknown event on client conn %d", pollevent); done = 1; } } else { ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(02449) "unknown socket in pollset"); done = 1; } } } while (!done); ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r, "finished with poll() - cleaning up"); if (!replied) { return HTTP_BAD_GATEWAY; } else { return OK; } return OK; }
static apr_status_t line_edit_filter(ap_filter_t* f, apr_bucket_brigade* bb) { int i, j; unsigned int match ; unsigned int nmatch = 10 ; ap_regmatch_t pmatch[10] ; const char* bufp; const char* subs ; apr_size_t bytes ; apr_size_t fbytes ; apr_size_t offs ; const char* buf ; const char* le = NULL ; const char* le_n ; const char* le_r ; char* fbuf ; apr_bucket* b = APR_BRIGADE_FIRST(bb) ; apr_bucket* b1 ; int found = 0 ; apr_status_t rv ; apr_bucket_brigade* bbline ; line_edit_cfg* cfg = ap_get_module_config(f->r->per_dir_config, &line_edit_module) ; rewriterule* rules = (rewriterule*) cfg->rewriterules->elts ; rewriterule* newrule; line_edit_ctx* ctx = f->ctx ; if (ctx == NULL) { /* check env to see if we're wanted, to give basic control with 2.0 */ buf = apr_table_get(f->r->subprocess_env, "LineEdit"); if (buf && f->r->content_type) { char* lcbuf = apr_pstrdup(f->r->pool, buf) ; char* lctype = apr_pstrdup(f->r->pool, f->r->content_type) ; char* c ; for (c = lcbuf; *c; ++c) if (isupper(*c)) *c = tolower(*c) ; for (c = lctype; *c; ++c) if (isupper(*c)) *c = tolower(*c) ; else if (*c == ';') { *c = 0 ; break ; } if (!strstr(lcbuf, lctype)) { /* don't filter this content type */ ap_filter_t* fnext = f->next ; ap_remove_output_filter(f) ; return ap_pass_brigade(fnext, bb) ; } } ctx = f->ctx = apr_palloc(f->r->pool, sizeof(line_edit_ctx)) ; ctx->bbsave = apr_brigade_create(f->r->pool, f->c->bucket_alloc) ; /* If we have any regex matches, we'll need to copy everything, so we * have null-terminated strings to parse. That's a lot of memory if * we're streaming anything big. So we'll use (and reuse) a local * subpool. Fall back to the request pool if anything bad happens. */ ctx->lpool = f->r->pool ; for (i = 0; i < cfg->rewriterules->nelts; ++i) { if ( rules[i].flags & M_REGEX ) { if (apr_pool_create(&ctx->lpool, f->r->pool) != APR_SUCCESS) { ctx->lpool = f->r->pool ; } break ; } } /* If we have env interpolation, we'll need a private copy of * our rewrite rules with this requests env. Otherwise we can * save processing time by using the original. * * If one ENV is found, we also have to copy all previous and * subsequent rules, even those with no interpolation. */ ctx->rewriterules = cfg->rewriterules; for (i = 0; i < cfg->rewriterules->nelts; ++i) { found |= (rules[i].flags & M_ENV) ; if ( found ) { if (ctx->rewriterules == cfg->rewriterules) { ctx->rewriterules = apr_array_make(f->r->pool, cfg->rewriterules->nelts, sizeof(rewriterule)); for (j = 0; j < i; ++j) { newrule = apr_array_push (((line_edit_ctx*)ctx)->rewriterules) ; newrule->from = rules[j].from; newrule->to = rules[j].to; newrule->flags = rules[j].flags; newrule->length = rules[j].length; } } /* this rule needs to be interpolated */ newrule = apr_array_push (((line_edit_ctx*)ctx)->rewriterules) ; newrule->from = rules[i].from; if (rules[i].flags & M_ENV) { newrule->to = interpolate_env(f->r, rules[i].to); } else { newrule->to = rules[i].to ; } newrule->flags = rules[i].flags; newrule->length = rules[i].length; } } /* for back-compatibility with Apache 2.0, set some protocol stuff */ apr_table_unset(f->r->headers_out, "Content-Length") ; apr_table_unset(f->r->headers_out, "Content-MD5") ; apr_table_unset(f->r->headers_out, "Accept-Ranges") ; } /* by now our rules are in ctx->rewriterules */ rules = (rewriterule*) ctx->rewriterules->elts ; /* bbline is what goes to the next filter, * so we (can) have a new one each time. */ bbline = apr_brigade_create(f->r->pool, f->c->bucket_alloc) ; /* first ensure we have no mid-line breaks that might be in the * middle of a search string causing us to miss it! At the same * time we split into lines to avoid pattern-matching over big * chunks of memory. */ while ( b != APR_BRIGADE_SENTINEL(bb) ) { if ( !APR_BUCKET_IS_METADATA(b) ) { if ( apr_bucket_read(b, &buf, &bytes, APR_BLOCK_READ) == APR_SUCCESS ) { if ( bytes == 0 ) { APR_BUCKET_REMOVE(b) ; } else while ( bytes > 0 ) { switch (cfg->lineend) { case LINEEND_UNIX: le = memchr(buf, '\n', bytes) ; break ; case LINEEND_MAC: le = memchr(buf, '\r', bytes) ; break ; case LINEEND_DOS: /* Edge-case issue: if a \r\n spans buckets it'll get missed. * Not a problem for present purposes, but would be an issue * if we claimed to support pattern matching on the lineends. */ found = 0 ; le = memchr(buf+1, '\n', bytes-1) ; while ( le && !found ) { if ( le[-1] == '\r' ) { found = 1 ; } else { le = memchr(le+1, '\n', bytes-1 - (le+1 - buf)) ; } } if ( !found ) le = 0 ; break; case LINEEND_ANY: case LINEEND_UNSET: /* Edge-case notabug: if a \r\n spans buckets it'll get seen as * two line-ends. It'll insert the \n as a one-byte bucket. */ le_n = memchr(buf, '\n', bytes) ; le_r = memchr(buf, '\r', bytes) ; if ( le_n != NULL ) if ( le_n == le_r + sizeof(char)) le = le_n ; else if ( (le_r < le_n) && (le_r != NULL) ) le = le_r ; else le = le_n ; else le = le_r ; break; case LINEEND_NONE: le = 0 ; break; case LINEEND_CUSTOM: le = memchr(buf, cfg->lechar, bytes) ; break; } if ( le ) { /* found a lineend in this bucket. */ offs = 1 + ((unsigned int)le-(unsigned int)buf) / sizeof(char) ; apr_bucket_split(b, offs) ; bytes -= offs ; buf += offs ; b1 = APR_BUCKET_NEXT(b) ; APR_BUCKET_REMOVE(b); /* Is there any previous unterminated content ? */ if ( !APR_BRIGADE_EMPTY(ctx->bbsave) ) { /* append this to any content waiting for a lineend */ APR_BRIGADE_INSERT_TAIL(ctx->bbsave, b) ; rv = apr_brigade_pflatten(ctx->bbsave, &fbuf, &fbytes, f->r->pool) ; /* make b a new bucket of the flattened stuff */ b = apr_bucket_pool_create(fbuf, fbytes, f->r->pool, f->r->connection->bucket_alloc) ; /* bbsave has been consumed, so clear it */ apr_brigade_cleanup(ctx->bbsave) ; } /* b now contains exactly one line */ APR_BRIGADE_INSERT_TAIL(bbline, b); b = b1 ; } else { /* no lineend found. Remember the dangling content */ APR_BUCKET_REMOVE(b); APR_BRIGADE_INSERT_TAIL(ctx->bbsave, b); bytes = 0 ; } } /* while bytes > 0 */ } else { /* bucket read failed - oops ! Let's remove it. */ APR_BUCKET_REMOVE(b); } } else if ( APR_BUCKET_IS_EOS(b) ) { /* If there's data to pass, send it in one bucket */ if ( !APR_BRIGADE_EMPTY(ctx->bbsave) ) { rv = apr_brigade_pflatten(ctx->bbsave, &fbuf, &fbytes, f->r->pool) ; b1 = apr_bucket_pool_create(fbuf, fbytes, f->r->pool, f->r->connection->bucket_alloc) ; APR_BRIGADE_INSERT_TAIL(bbline, b1); } apr_brigade_cleanup(ctx->bbsave) ; /* start again rather than segfault if a seriously buggy * filter in front of us sent a bogus EOS */ f->ctx = NULL ; /* move the EOS to the new brigade */ APR_BUCKET_REMOVE(b); APR_BRIGADE_INSERT_TAIL(bbline, b); } else { /* chop flush or unknown metadata bucket types */ apr_bucket_delete(b); } /* OK, reset pointer to what's left (since we're not in a for-loop) */ b = APR_BRIGADE_FIRST(bb) ; } /* OK, now we have a bunch of complete lines in bbline, * so we can apply our edit rules */ /* When we get a match, we split the line into before+match+after. * To flatten that back into one buf every time would be inefficient. * So we treat it as three separate bufs to apply future rules. * * We can only reasonably do that by looping over buckets *inside* * the loop over rules. * * That means concepts like one-match-per-line or start-of-line-only * won't work, except for the first rule. So we won't pretend. */ for (i = 0; i < ctx->rewriterules->nelts; ++i) { for ( b = APR_BRIGADE_FIRST(bbline) ; b != APR_BRIGADE_SENTINEL(bbline) ; b = APR_BUCKET_NEXT(b) ) { if ( !APR_BUCKET_IS_METADATA(b) && (apr_bucket_read(b, &buf, &bytes, APR_BLOCK_READ) == APR_SUCCESS)) { if ( rules[i].flags & M_REGEX ) { bufp = apr_pstrmemdup(ctx->lpool, buf, bytes) ; while ( ! ap_regexec(rules[i].from.r, bufp, nmatch, pmatch, 0) ) { match = pmatch[0].rm_so ; subs = ap_pregsub(f->r->pool, rules[i].to, bufp, nmatch, pmatch) ; apr_bucket_split(b, match) ; b1 = APR_BUCKET_NEXT(b) ; apr_bucket_split(b1, pmatch[0].rm_eo - match) ; b = APR_BUCKET_NEXT(b1) ; apr_bucket_delete(b1) ; b1 = apr_bucket_pool_create(subs, strlen(subs), f->r->pool, f->r->connection->bucket_alloc) ; APR_BUCKET_INSERT_BEFORE(b, b1) ; bufp += pmatch[0].rm_eo ; } } else { bufp = buf ; while (subs = apr_strmatch(rules[i].from.s, bufp, bytes), subs != NULL) { match = ((unsigned int)subs - (unsigned int)bufp) / sizeof(char) ; bytes -= match ; bufp += match ; apr_bucket_split(b, match) ; b1 = APR_BUCKET_NEXT(b) ; apr_bucket_split(b1, rules[i].length) ; b = APR_BUCKET_NEXT(b1) ; apr_bucket_delete(b1) ; bytes -= rules[i].length ; bufp += rules[i].length ; b1 = apr_bucket_immortal_create(rules[i].to, strlen(rules[i].to), f->r->connection->bucket_alloc) ; APR_BUCKET_INSERT_BEFORE(b, b1) ; } } } } /* If we used a local pool, clear it now */ if ( (ctx->lpool != f->r->pool) && (rules[i].flags & M_REGEX) ) { apr_pool_clear(ctx->lpool) ; } } /* now pass it down the chain */ rv = ap_pass_brigade(f->next, bbline) ; /* if we have leftover data, don't risk it going out of scope */ for ( b = APR_BRIGADE_FIRST(ctx->bbsave) ; b != APR_BRIGADE_SENTINEL(ctx->bbsave) ; b = APR_BUCKET_NEXT(b)) { apr_bucket_setaside(b, f->r->pool) ; } return rv ; }
static apr_status_t dbd_sqlite3_datum_get(const apr_dbd_row_t *row, int n, apr_dbd_type_e type, void *data) { if ((n < 0) || ((size_t)n >= row->res->sz)) { return APR_EGENERAL; } if (row->columns[n]->type == SQLITE_NULL) { return APR_ENOENT; } switch (type) { case APR_DBD_TYPE_TINY: *(char*)data = atoi(row->columns[n]->value); break; case APR_DBD_TYPE_UTINY: *(unsigned char*)data = atoi(row->columns[n]->value); break; case APR_DBD_TYPE_SHORT: *(short*)data = atoi(row->columns[n]->value); break; case APR_DBD_TYPE_USHORT: *(unsigned short*)data = atoi(row->columns[n]->value); break; case APR_DBD_TYPE_INT: *(int*)data = atoi(row->columns[n]->value); break; case APR_DBD_TYPE_UINT: *(unsigned int*)data = atoi(row->columns[n]->value); break; case APR_DBD_TYPE_LONG: *(long*)data = atol(row->columns[n]->value); break; case APR_DBD_TYPE_ULONG: *(unsigned long*)data = atol(row->columns[n]->value); break; case APR_DBD_TYPE_LONGLONG: *(apr_int64_t*)data = apr_atoi64(row->columns[n]->value); break; case APR_DBD_TYPE_ULONGLONG: *(apr_uint64_t*)data = apr_atoi64(row->columns[n]->value); break; case APR_DBD_TYPE_FLOAT: *(float*)data = (float)atof(row->columns[n]->value); break; case APR_DBD_TYPE_DOUBLE: *(double*)data = atof(row->columns[n]->value); break; case APR_DBD_TYPE_STRING: case APR_DBD_TYPE_TEXT: case APR_DBD_TYPE_TIME: case APR_DBD_TYPE_DATE: case APR_DBD_TYPE_DATETIME: case APR_DBD_TYPE_TIMESTAMP: case APR_DBD_TYPE_ZTIMESTAMP: *(char**)data = row->columns[n]->value; break; case APR_DBD_TYPE_BLOB: case APR_DBD_TYPE_CLOB: { apr_bucket *e; apr_bucket_brigade *b = (apr_bucket_brigade*)data; e = apr_bucket_pool_create(row->columns[n]->value, row->columns[n]->size, row->res->pool, b->bucket_alloc); APR_BRIGADE_INSERT_TAIL(b, e); } break; case APR_DBD_TYPE_NULL: *(void**)data = NULL; break; default: return APR_EGENERAL; } return APR_SUCCESS; }
static ngx_int_t ngx_http_modsecurity_body_filter(ngx_http_request_t *r, ngx_chain_t *in) { ngx_http_modsecurity_loc_conf_t *cf; ngx_http_modsecurity_ctx_t *ctx; ngx_int_t rc; apr_off_t content_length; ngx_chain_t *cl, *out; ngx_int_t last_buf = 0; cf = ngx_http_get_module_loc_conf(r, ngx_http_modsecurity); ctx = ngx_http_get_module_ctx(r, ngx_http_modsecurity); if (r != r->main || !cf->enable || ctx == NULL || ctx->complete) { return ngx_http_next_body_filter(r, in); } ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "modSecurity: body filter"); for (cl = in; cl; cl = cl->next) { apr_bucket *e; ngx_buf_t *buf = cl->buf; apr_bucket_brigade *bb = ctx->brigade; off_t size = ngx_buf_size(buf); if (size) { char *data = apr_pmemdup(bb->p, buf->pos, size); if (data == NULL) { return ngx_http_filter_finalize_request(r, &ngx_http_modsecurity, NGX_HTTP_INTERNAL_SERVER_ERROR); } e = apr_bucket_pool_create(data , size, bb->p, bb->bucket_alloc); if (e == NULL) { return ngx_http_filter_finalize_request(r, &ngx_http_modsecurity, NGX_HTTP_INTERNAL_SERVER_ERROR); } APR_BRIGADE_INSERT_TAIL(bb, e); } if (buf->last_buf) { last_buf = 1; buf->last_buf = 0; e = apr_bucket_eos_create(bb->bucket_alloc); if (e == NULL) { return ngx_http_filter_finalize_request(r, &ngx_http_modsecurity, NGX_HTTP_INTERNAL_SERVER_ERROR); } APR_BRIGADE_INSERT_TAIL(bb, e); break; } buf->pos = buf->last; } if (!last_buf) { return NGX_AGAIN; } /* last buf has been saved */ ctx->complete = 1; modsecSetResponseBrigade(ctx->req, ctx->brigade); if (ngx_http_modsecurity_load_headers_in(r) != NGX_OK || ngx_http_modsecurity_load_headers_out(r) != NGX_OK) { return ngx_http_filter_finalize_request(r, &ngx_http_modsecurity, NGX_HTTP_INTERNAL_SERVER_ERROR); } rc = ngx_http_modsecurity_status(r, modsecProcessResponse(ctx->req)); if (rc != NGX_DECLINED) { return ngx_http_filter_finalize_request(r, &ngx_http_modsecurity, rc); } apr_brigade_length(ctx->brigade, 0, &content_length); rc = move_brigade_to_chain(ctx->brigade, &out, r->pool); if (rc == NGX_ERROR) { return ngx_http_filter_finalize_request(r, &ngx_http_modsecurity, NGX_HTTP_INTERNAL_SERVER_ERROR); } if (ngx_http_modsecurity_save_headers_in(r) != NGX_OK ||ngx_http_modsecurity_save_headers_out(r) != NGX_OK) { return ngx_http_filter_finalize_request(r, &ngx_http_modsecurity, NGX_HTTP_INTERNAL_SERVER_ERROR); } if (r->headers_out.content_length_n != -1) { r->headers_out.content_length_n = content_length; r->headers_out.content_length = NULL; /* header filter will set this */ } r->header_sent = 0; rc = ngx_http_next_header_filter(r); if (rc == NGX_ERROR || rc > NGX_OK) { return ngx_http_filter_finalize_request(r, &ngx_http_modsecurity, rc); } return ngx_http_next_body_filter(r, out); }
static apr_status_t bucketeer_out_filter(ap_filter_t *f, apr_bucket_brigade *bb) { apr_bucket *e; request_rec *r = f->r; bucketeer_ctx_t *ctx = f->ctx; bucketeer_filter_config_t *c; c = ap_get_module_config(r->server->module_config, &bucketeer_module); /* If have a context, it means we've done this before successfully. */ if (!ctx) { if (!r->content_type || strncmp(r->content_type, "text/", 5)) { ap_remove_output_filter(f); return ap_pass_brigade(f->next, bb); } /* We're cool with filtering this. */ ctx = f->ctx = apr_pcalloc(f->r->pool, sizeof(*ctx)); ctx->bb = apr_brigade_create(f->r->pool, f->c->bucket_alloc); apr_table_unset(f->r->headers_out, "Content-Length"); } for (e = APR_BRIGADE_FIRST(bb); e != APR_BRIGADE_SENTINEL(bb); e = APR_BUCKET_NEXT(e)) { const char *data; apr_size_t len, i, lastpos; if (APR_BUCKET_IS_EOS(e)) { APR_BUCKET_REMOVE(e); APR_BRIGADE_INSERT_TAIL(ctx->bb, e); /* Okay, we've seen the EOS. * Time to pass it along down the chain. */ return ap_pass_brigade(f->next, ctx->bb); } if (APR_BUCKET_IS_FLUSH(e)) { /* * Ignore flush buckets for the moment.. * we decide what to stream */ continue; } if (APR_BUCKET_IS_METADATA(e)) { /* metadata bucket */ apr_bucket *cpy; apr_bucket_copy(e, &cpy); APR_BRIGADE_INSERT_TAIL(ctx->bb, cpy); continue; } /* read */ apr_bucket_read(e, &data, &len, APR_BLOCK_READ); if (len > 0) { lastpos = 0; for (i = 0; i < len; i++) { if (data[i] == c->flushdelimiter || data[i] == c->bucketdelimiter || data[i] == c->passdelimiter) { apr_bucket *p; if (i - lastpos > 0) { p = apr_bucket_pool_create(apr_pmemdup(f->r->pool, &data[lastpos], i - lastpos), i - lastpos, f->r->pool, f->c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(ctx->bb, p); } lastpos = i + 1; if (data[i] == c->flushdelimiter) { p = apr_bucket_flush_create(f->c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(ctx->bb, p); } if (data[i] == c->passdelimiter) { apr_status_t rv; rv = ap_pass_brigade(f->next, ctx->bb); if (rv) { return rv; } } } } /* XXX: really should append this to the next 'real' bucket */ if (lastpos < i) { apr_bucket *p; p = apr_bucket_pool_create(apr_pmemdup(f->r->pool, &data[lastpos], i - lastpos), i - lastpos, f->r->pool, f->c->bucket_alloc); lastpos = i; APR_BRIGADE_INSERT_TAIL(ctx->bb, p); } } } return APR_SUCCESS; }
AP_CORE_DECLARE_NONSTD(apr_status_t) ap_byterange_filter(ap_filter_t *f, apr_bucket_brigade *bb) { #define MIN_LENGTH(len1, len2) ((len1 > len2) ? len2 : len1) request_rec *r = f->r; conn_rec *c = r->connection; byterange_ctx *ctx; apr_bucket *e; apr_bucket_brigade *bsend; apr_off_t range_start; apr_off_t range_end; char *current; apr_off_t clength = 0; apr_status_t rv; int found = 0; int num_ranges; /* Iterate through the brigade until reaching EOS or a bucket with * unknown length. */ for (e = APR_BRIGADE_FIRST(bb); (e != APR_BRIGADE_SENTINEL(bb) && !APR_BUCKET_IS_EOS(e) && e->length != (apr_size_t)-1); e = APR_BUCKET_NEXT(e)) { clength += e->length; } /* Don't attempt to do byte range work if this brigade doesn't * contain an EOS, or if any of the buckets has an unknown length; * this avoids the cases where it is expensive to perform * byteranging (i.e. may require arbitrary amounts of memory). */ if (!APR_BUCKET_IS_EOS(e) || clength <= 0) { ap_remove_output_filter(f); return ap_pass_brigade(f->next, bb); } num_ranges = ap_set_byterange(r); /* We have nothing to do, get out of the way. */ if (num_ranges == 0) { ap_remove_output_filter(f); return ap_pass_brigade(f->next, bb); } ctx = apr_pcalloc(r->pool, sizeof(*ctx)); ctx->num_ranges = num_ranges; /* create a brigade in case we never call ap_save_brigade() */ ctx->bb = apr_brigade_create(r->pool, c->bucket_alloc); if (ctx->num_ranges > 1) { /* Is ap_make_content_type required here? */ const char *orig_ct = ap_make_content_type(r, r->content_type); ctx->boundary = apr_psprintf(r->pool, "%" APR_UINT64_T_HEX_FMT "%lx", (apr_uint64_t)r->request_time, (long) getpid()); ap_set_content_type(r, apr_pstrcat(r->pool, "multipart", use_range_x(r) ? "/x-" : "/", "byteranges; boundary=", ctx->boundary, NULL)); if (strcasecmp(orig_ct, NO_CONTENT_TYPE)) { ctx->bound_head = apr_pstrcat(r->pool, CRLF "--", ctx->boundary, CRLF "Content-type: ", orig_ct, CRLF "Content-range: bytes ", NULL); } else { /* if we have no type for the content, do our best */ ctx->bound_head = apr_pstrcat(r->pool, CRLF "--", ctx->boundary, CRLF "Content-range: bytes ", NULL); } ap_xlate_proto_to_ascii(ctx->bound_head, strlen(ctx->bound_head)); } /* this brigade holds what we will be sending */ bsend = apr_brigade_create(r->pool, c->bucket_alloc); while ((current = ap_getword(r->pool, &r->range, ',')) && (rv = parse_byterange(current, clength, &range_start, &range_end))) { apr_bucket *e2; apr_bucket *ec; if (rv == -1) { continue; } /* These calls to apr_brigage_partition should only fail in * pathological cases, e.g. a file being truncated whilst * being served. */ if ((rv = apr_brigade_partition(bb, range_start, &ec)) != APR_SUCCESS) { ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, PARTITION_ERR_FMT, range_start, clength); continue; } if ((rv = apr_brigade_partition(bb, range_end+1, &e2)) != APR_SUCCESS) { ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, PARTITION_ERR_FMT, range_end+1, clength); continue; } found = 1; /* For single range requests, we must produce Content-Range header. * Otherwise, we need to produce the multipart boundaries. */ if (ctx->num_ranges == 1) { apr_table_setn(r->headers_out, "Content-Range", apr_psprintf(r->pool, "bytes " BYTERANGE_FMT, range_start, range_end, clength)); } else { char *ts; e = apr_bucket_pool_create(ctx->bound_head, strlen(ctx->bound_head), r->pool, c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(bsend, e); ts = apr_psprintf(r->pool, BYTERANGE_FMT CRLF CRLF, range_start, range_end, clength); ap_xlate_proto_to_ascii(ts, strlen(ts)); e = apr_bucket_pool_create(ts, strlen(ts), r->pool, c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(bsend, e); } do { apr_bucket *foo; const char *str; apr_size_t len; if (apr_bucket_copy(ec, &foo) != APR_SUCCESS) { /* As above; this should not fail since the bucket has * a known length, but just to be sure, this takes * care of uncopyable buckets that do somehow manage * to slip through. */ /* XXX: check for failure? */ apr_bucket_read(ec, &str, &len, APR_BLOCK_READ); apr_bucket_copy(ec, &foo); } APR_BRIGADE_INSERT_TAIL(bsend, foo); ec = APR_BUCKET_NEXT(ec); } while (ec != e2); } if (found == 0) { ap_remove_output_filter(f); r->status = HTTP_OK; /* bsend is assumed to be empty if we get here. */ e = ap_bucket_error_create(HTTP_RANGE_NOT_SATISFIABLE, NULL, r->pool, c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(bsend, e); e = apr_bucket_eos_create(c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(bsend, e); return ap_pass_brigade(f->next, bsend); } if (ctx->num_ranges > 1) { char *end; /* add the final boundary */ end = apr_pstrcat(r->pool, CRLF "--", ctx->boundary, "--" CRLF, NULL); ap_xlate_proto_to_ascii(end, strlen(end)); e = apr_bucket_pool_create(end, strlen(end), r->pool, c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(bsend, e); } e = apr_bucket_eos_create(c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(bsend, e); /* we're done with the original content - all of our data is in bsend. */ apr_brigade_cleanup(bb); /* send our multipart output */ return ap_pass_brigade(f->next, bsend); }
static void test_splits(abts_case *tc, void *ctx) { apr_bucket_alloc_t *ba = apr_bucket_alloc_create(p); apr_bucket_brigade *bb; apr_bucket *e; char *str = "alphabeta"; int n; bb = apr_brigade_create(p, ba); APR_BRIGADE_INSERT_TAIL(bb, apr_bucket_immortal_create(str, 9, ba)); APR_BRIGADE_INSERT_TAIL(bb, apr_bucket_transient_create(str, 9, ba)); APR_BRIGADE_INSERT_TAIL(bb, apr_bucket_heap_create(strdup(str), 9, free, ba)); APR_BRIGADE_INSERT_TAIL(bb, apr_bucket_pool_create(apr_pstrdup(p, str), 9, p, ba)); ABTS_ASSERT(tc, "four buckets inserted", count_buckets(bb) == 4); /* now split each of the buckets after byte 5 */ for (n = 0, e = APR_BRIGADE_FIRST(bb); n < 4; n++) { ABTS_ASSERT(tc, "reached end of brigade", e != APR_BRIGADE_SENTINEL(bb)); ABTS_ASSERT(tc, "split bucket OK", apr_bucket_split(e, 5) == APR_SUCCESS); e = APR_BUCKET_NEXT(e); ABTS_ASSERT(tc, "split OK", e != APR_BRIGADE_SENTINEL(bb)); e = APR_BUCKET_NEXT(e); } ABTS_ASSERT(tc, "four buckets split into eight", count_buckets(bb) == 8); for (n = 0, e = APR_BRIGADE_FIRST(bb); n < 4; n++) { const char *data; apr_size_t len; apr_assert_success(tc, "read alpha from bucket", apr_bucket_read(e, &data, &len, APR_BLOCK_READ)); ABTS_ASSERT(tc, "read 5 bytes", len == 5); ABTS_STR_NEQUAL(tc, "alpha", data, 5); e = APR_BUCKET_NEXT(e); apr_assert_success(tc, "read beta from bucket", apr_bucket_read(e, &data, &len, APR_BLOCK_READ)); ABTS_ASSERT(tc, "read 4 bytes", len == 4); ABTS_STR_NEQUAL(tc, "beta", data, 5); e = APR_BUCKET_NEXT(e); } /* now delete the "alpha" buckets */ for (n = 0, e = APR_BRIGADE_FIRST(bb); n < 4; n++) { apr_bucket *f; ABTS_ASSERT(tc, "reached end of brigade", e != APR_BRIGADE_SENTINEL(bb)); f = APR_BUCKET_NEXT(e); apr_bucket_delete(e); e = APR_BUCKET_NEXT(f); } ABTS_ASSERT(tc, "eight buckets reduced to four", count_buckets(bb) == 4); flatten_match(tc, "flatten beta brigade", bb, "beta" "beta" "beta" "beta"); apr_brigade_destroy(bb); apr_bucket_alloc_destroy(ba); }
static apr_status_t dbd_mysql_datum_get(const apr_dbd_row_t *row, int n, apr_dbd_type_e type, void *data) { if (row->res->statement) { MYSQL_BIND *bind = &row->res->bind[n]; unsigned long len = *bind->length; if (mysql_stmt_fetch_column(row->res->statement, bind, n, 0) != 0) { return APR_EGENERAL; } if (*bind->is_null) { return APR_ENOENT; } switch (type) { case APR_DBD_TYPE_TINY: *(char*)data = atoi(bind->buffer); break; case APR_DBD_TYPE_UTINY: *(unsigned char*)data = atoi(bind->buffer); break; case APR_DBD_TYPE_SHORT: *(short*)data = atoi(bind->buffer); break; case APR_DBD_TYPE_USHORT: *(unsigned short*)data = atoi(bind->buffer); break; case APR_DBD_TYPE_INT: *(int*)data = atoi(bind->buffer); break; case APR_DBD_TYPE_UINT: *(unsigned int*)data = atoi(bind->buffer); break; case APR_DBD_TYPE_LONG: *(long*)data = atol(bind->buffer); break; case APR_DBD_TYPE_ULONG: *(unsigned long*)data = atol(bind->buffer); break; case APR_DBD_TYPE_LONGLONG: *(apr_int64_t*)data = apr_atoi64(bind->buffer); break; case APR_DBD_TYPE_ULONGLONG: *(apr_uint64_t*)data = apr_atoi64(bind->buffer); break; case APR_DBD_TYPE_FLOAT: *(float*)data = (float) atof(bind->buffer); break; case APR_DBD_TYPE_DOUBLE: *(double*)data = atof(bind->buffer); break; case APR_DBD_TYPE_STRING: case APR_DBD_TYPE_TEXT: case APR_DBD_TYPE_TIME: case APR_DBD_TYPE_DATE: case APR_DBD_TYPE_DATETIME: case APR_DBD_TYPE_TIMESTAMP: case APR_DBD_TYPE_ZTIMESTAMP: *((char*)bind->buffer+bind->buffer_length-1) = '\0'; *(char**)data = bind->buffer; break; case APR_DBD_TYPE_BLOB: case APR_DBD_TYPE_CLOB: { apr_bucket *e; apr_bucket_brigade *b = (apr_bucket_brigade*)data; e = apr_bucket_lob_create(row, n, 0, len, row->res->pool, b->bucket_alloc); APR_BRIGADE_INSERT_TAIL(b, e); } break; case APR_DBD_TYPE_NULL: *(void**)data = NULL; break; default: return APR_EGENERAL; } } else { if (row->row[n] == NULL) { return APR_ENOENT; } switch (type) { case APR_DBD_TYPE_TINY: *(char*)data = atoi(row->row[n]); break; case APR_DBD_TYPE_UTINY: *(unsigned char*)data = atoi(row->row[n]); break; case APR_DBD_TYPE_SHORT: *(short*)data = atoi(row->row[n]); break; case APR_DBD_TYPE_USHORT: *(unsigned short*)data = atoi(row->row[n]); break; case APR_DBD_TYPE_INT: *(int*)data = atoi(row->row[n]); break; case APR_DBD_TYPE_UINT: *(unsigned int*)data = atoi(row->row[n]); break; case APR_DBD_TYPE_LONG: *(long*)data = atol(row->row[n]); break; case APR_DBD_TYPE_ULONG: *(unsigned long*)data = atol(row->row[n]); break; case APR_DBD_TYPE_LONGLONG: *(apr_int64_t*)data = apr_atoi64(row->row[n]); break; case APR_DBD_TYPE_ULONGLONG: *(apr_uint64_t*)data = apr_atoi64(row->row[n]); break; case APR_DBD_TYPE_FLOAT: *(float*)data = (float) atof(row->row[n]); break; case APR_DBD_TYPE_DOUBLE: *(double*)data = atof(row->row[n]); break; case APR_DBD_TYPE_STRING: case APR_DBD_TYPE_TEXT: case APR_DBD_TYPE_TIME: case APR_DBD_TYPE_DATE: case APR_DBD_TYPE_DATETIME: case APR_DBD_TYPE_TIMESTAMP: case APR_DBD_TYPE_ZTIMESTAMP: *(char**)data = row->row[n]; break; case APR_DBD_TYPE_BLOB: case APR_DBD_TYPE_CLOB: { apr_bucket *e; apr_bucket_brigade *b = (apr_bucket_brigade*)data; e = apr_bucket_pool_create(row->row[n], row->len[n], row->res->pool, b->bucket_alloc); APR_BRIGADE_INSERT_TAIL(b, e); } break; case APR_DBD_TYPE_NULL: *(void**)data = NULL; break; default: return APR_EGENERAL; } } return 0; }
// output_data apr_status_t small_light_filter_imagemagick_output_data( ap_filter_t *f, apr_bucket_brigade *bb, void *v_ctx, apr_bucket *e) { ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, f->r, "small_light_filter_imagemagick_output_data"); request_rec *r = f->r; small_light_module_ctx_t* ctx = (small_light_module_ctx_t*)v_ctx; small_light_module_imagemagick_ctx_t *lctx = ctx->lctx; struct timeval t2, t21, t22, t23, t3; MagickBooleanType status = MagickFalse; // check data received. if (lctx->image == NULL) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "no data received."); r->status = HTTP_INTERNAL_SERVER_ERROR; return APR_EGENERAL; } // start image modifing. gettimeofday(&t2, NULL); small_light_image_size_t sz; small_light_calc_image_size(&sz, r, ctx, 10000.0, 10000.0); // init wand small_light_filter_imagemagick_output_data_init(); lctx->wand = NewMagickWand(); // prepare. if (sz.jpeghint_flg != 0) { char *jpeg_size_opt = (char *)apr_psprintf(r->pool, "%dx%d", (int)sz.dw, (int)sz.dh); MagickSetOption(lctx->wand, "jpeg:size", jpeg_size_opt); ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "MagickSetOption(jpeg:size, %s)", jpeg_size_opt); } // load image. gettimeofday(&t21, NULL); ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "MagickReadImageBlob"); status = MagickReadImageBlob(lctx->wand, (void *)lctx->image, lctx->image_len); if (status == MagickFalse) { small_light_filter_imagemagick_output_data_fini(ctx); ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "couldn't read image"); r->status = HTTP_INTERNAL_SERVER_ERROR; return APR_EGENERAL; } // calc size. gettimeofday(&t22, NULL); double iw = (double)MagickGetImageWidth(lctx->wand); double ih = (double)MagickGetImageHeight(lctx->wand); small_light_calc_image_size(&sz, r, ctx, iw, ih); // pass through. if (sz.pt_flg != 0) { small_light_filter_imagemagick_output_data_fini(ctx); apr_bucket *b = apr_bucket_pool_create(lctx->image, lctx->image_len, r->pool, ctx->bb->bucket_alloc); APR_BRIGADE_INSERT_TAIL(ctx->bb, b); APR_BRIGADE_INSERT_TAIL(ctx->bb, apr_bucket_eos_create(ctx->bb->bucket_alloc)); return ap_pass_brigade(f->next, ctx->bb); } // crop, scale. status = MagickTrue; if (sz.scale_flg != 0) { char *crop_geo = (char *)apr_psprintf(r->pool, "%f!x%f!+%f+%f", sz.sw, sz.sh, sz.sx, sz.sy); char *size_geo = (char *)apr_psprintf(r->pool, "%f!x%f!", sz.dw, sz.dh); ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "MagickTransformImage(wand, ""%s"", ""%s"")", crop_geo, size_geo); MagickWand *trans_wand; trans_wand = MagickTransformImage(lctx->wand, crop_geo, size_geo); if (trans_wand == NULL || trans_wand == lctx->wand) { small_light_filter_imagemagick_output_data_fini(ctx); ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "MagickTransformImage failed"); r->status = HTTP_INTERNAL_SERVER_ERROR; return APR_EGENERAL; } DestroyMagickWand(lctx->wand); lctx->wand = trans_wand; } else { ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "no scale"); } // create canvas then draw image to the canvas. if (sz.cw > 0.0 && sz.ch > 0.0) { ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "NewMagickWand()"); MagickWand *canvas_wand = NewMagickWand(); PixelWand *canvas_color = NewPixelWand(); PixelSetRed(canvas_color, sz.cc.r / 255.0); PixelSetGreen(canvas_color, sz.cc.g / 255.0); PixelSetBlue(canvas_color, sz.cc.b / 255.0); PixelSetAlpha(canvas_color, sz.cc.a / 255.0); ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "MagickNewImage(canvas_wand, %f, %f, bgcolor)", sz.cw, sz.ch); status = MagickNewImage(canvas_wand, sz.cw, sz.ch, canvas_color); DestroyPixelWand(canvas_color); if (status == MagickFalse) { small_light_filter_imagemagick_output_data_fini(ctx); ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "MagickNewImage(canvas_wand, %f, %f, bgcolor) failed", sz.cw, sz.ch); r->status = HTTP_INTERNAL_SERVER_ERROR; return APR_EGENERAL; } ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "MagickCompositeImage(canvas_wand, wand, AtopCompositeOp, %f, %f)", sz.dx, sz.dy); status = MagickCompositeImage(canvas_wand, lctx->wand, AtopCompositeOp, sz.dx, sz.dy); if (status == MagickFalse) { small_light_filter_imagemagick_output_data_fini(ctx); ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "MagickCompositeImage(canvas_wand, wand, AtopCompositeOp, %f, %f) failed", sz.dx, sz.dy); r->status = HTTP_INTERNAL_SERVER_ERROR; return APR_EGENERAL; } DestroyMagickWand(lctx->wand); lctx->wand = canvas_wand; } // effects. char *unsharp = (char *)apr_table_get(ctx->prm, "unsharp"); if (unsharp) { GeometryInfo geo; ParseGeometry(unsharp, &geo); ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "MagickUnsharpMaskImage(wand, %f, %f, %f, %f)", geo.rho, geo.sigma, geo.xi, geo.psi); status = MagickUnsharpMaskImage(lctx->wand, geo.rho, geo.sigma, geo.xi, geo.psi); if (status == MagickFalse) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "unsharp failed"); } } char *sharpen = (char *)apr_table_get(ctx->prm, "sharpen"); if (sharpen) { GeometryInfo geo; ParseGeometry(sharpen, &geo); ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "MagickSharpenImage(wand, %f, %f)", geo.rho, geo.sigma); status = MagickSharpenImage(lctx->wand, geo.rho, geo.sigma); if (status == MagickFalse) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "sharpen failed"); } } char *blur = (char *)apr_table_get(ctx->prm, "blur"); if (blur) { GeometryInfo geo; ParseGeometry(blur, &geo); ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "MagickBlurImage(wand, %f, %f)", geo.rho, geo.sigma); status = MagickBlurImage(lctx->wand, geo.rho, geo.sigma); if (status == MagickFalse) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "blur failed"); } } // border. if (sz.bw > 0.0 || sz.bh > 0.0) { ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "draw border"); DrawingWand *border_wand = NewDrawingWand(); PixelWand *border_color; border_color = NewPixelWand(); PixelSetRed(border_color, sz.bc.r / 255.0); PixelSetGreen(border_color, sz.bc.g / 255.0); PixelSetBlue(border_color, sz.bc.b / 255.0); PixelSetAlpha(border_color, sz.bc.a / 255.0); DrawSetFillColor(border_wand, border_color); DrawSetStrokeColor(border_wand, border_color); DrawSetStrokeWidth(border_wand, 1); DrawRectangle(border_wand, 0, 0, sz.cw - 1, sz.bh - 1); DrawRectangle(border_wand, 0, 0, sz.bw - 1, sz.ch - 1); DrawRectangle(border_wand, 0, sz.ch - sz.bh, sz.cw - 1, sz.ch - 1); DrawRectangle(border_wand, sz.cw - sz.bw, 0, sz.cw - 1, sz.ch - 1); MagickDrawImage(lctx->wand, border_wand); DestroyPixelWand(border_color); DestroyDrawingWand(border_wand); } gettimeofday(&t23, NULL); // set params. double q = small_light_parse_double(r, (char *)apr_table_get(ctx->prm, "q")); if (q > 0.0) { ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "MagickSetImageComressionQualty(wand, %f)", q); MagickSetImageCompressionQuality(lctx->wand, q); } char *of = (char *)apr_table_get(ctx->prm, "of"); ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "MagickSetFormat(wand, '%s')", of); MagickSetFormat(lctx->wand, of); // get small_lighted image as binary. unsigned char *canvas_buff; const char *sled_image; size_t sled_image_size; canvas_buff = MagickGetImageBlob(lctx->wand, &sled_image_size); sled_image = (const char *)apr_pmemdup(r->pool, canvas_buff, sled_image_size); ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "sled_image_size = %d", sled_image_size); // free buffer and wand. MagickRelinquishMemory(canvas_buff); small_light_filter_imagemagick_output_data_fini(ctx); // insert new bucket to bucket brigade. apr_bucket *b = apr_bucket_pool_create(sled_image, sled_image_size, r->pool, ctx->bb->bucket_alloc); APR_BRIGADE_INSERT_TAIL(ctx->bb, b); // insert eos to bucket brigade. APR_BRIGADE_INSERT_TAIL(ctx->bb, apr_bucket_eos_create(ctx->bb->bucket_alloc)); // set correct Content-Type and Content-Length. char *cont_type = apr_psprintf(r->pool, "image/%s", of); ap_set_content_type(r, cont_type); ap_set_content_length(r, sled_image_size); // end. gettimeofday(&t3, NULL); // http header. int info = small_light_parse_int(r, (char *)apr_table_get(ctx->prm, "info")); if (info != SMALL_LIGHT_INT_INVALID_VALUE && info != 0) { char *info = (char *)apr_psprintf(r->pool, "transfer=%ldms, modify image=%ldms (load=%ldms, scale=%ldms, save=%ldms)", small_light_timeval_diff(&ctx->t, &t2) / 1000L, small_light_timeval_diff(&t2, &t3) / 1000L, small_light_timeval_diff(&t21, &t22) / 1000L, small_light_timeval_diff(&t22, &t23) / 1000L, small_light_timeval_diff(&t23, &t3) / 1000L ); ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, "uri=%s, info=%s)", r->unparsed_uri, info); apr_table_setn(r->headers_out, "X-SmallLight-Description", info); } return ap_pass_brigade(f->next, ctx->bb); }
static apr_status_t dbd_pgsql_datum_get(const apr_dbd_row_t *row, int n, apr_dbd_type_e type, void *data) { if (PQgetisnull(row->res->res, row->n, n)) { return APR_ENOENT; } switch (type) { case APR_DBD_TYPE_TINY: *(char*)data = atoi(PQgetvalue(row->res->res, row->n, n)); break; case APR_DBD_TYPE_UTINY: *(unsigned char*)data = atoi(PQgetvalue(row->res->res, row->n, n)); break; case APR_DBD_TYPE_SHORT: *(short*)data = atoi(PQgetvalue(row->res->res, row->n, n)); break; case APR_DBD_TYPE_USHORT: *(unsigned short*)data = atoi(PQgetvalue(row->res->res, row->n, n)); break; case APR_DBD_TYPE_INT: *(int*)data = atoi(PQgetvalue(row->res->res, row->n, n)); break; case APR_DBD_TYPE_UINT: *(unsigned int*)data = atoi(PQgetvalue(row->res->res, row->n, n)); break; case APR_DBD_TYPE_LONG: *(long*)data = atol(PQgetvalue(row->res->res, row->n, n)); break; case APR_DBD_TYPE_ULONG: *(unsigned long*)data = atol(PQgetvalue(row->res->res, row->n, n)); break; case APR_DBD_TYPE_LONGLONG: *(apr_int64_t*)data = apr_atoi64(PQgetvalue(row->res->res, row->n, n)); break; case APR_DBD_TYPE_ULONGLONG: *(apr_uint64_t*)data = apr_atoi64(PQgetvalue(row->res->res, row->n, n)); break; case APR_DBD_TYPE_FLOAT: *(float*)data = (float)atof(PQgetvalue(row->res->res, row->n, n)); break; case APR_DBD_TYPE_DOUBLE: *(double*)data = atof(PQgetvalue(row->res->res, row->n, n)); break; case APR_DBD_TYPE_STRING: case APR_DBD_TYPE_TEXT: case APR_DBD_TYPE_TIME: case APR_DBD_TYPE_DATE: case APR_DBD_TYPE_DATETIME: case APR_DBD_TYPE_TIMESTAMP: case APR_DBD_TYPE_ZTIMESTAMP: *(char**)data = PQgetvalue(row->res->res, row->n, n); break; case APR_DBD_TYPE_BLOB: case APR_DBD_TYPE_CLOB: { apr_bucket *e; apr_bucket_brigade *b = (apr_bucket_brigade*)data; e = apr_bucket_pool_create(PQgetvalue(row->res->res, row->n, n), PQgetlength(row->res->res, row->n, n), row->res->pool, b->bucket_alloc); APR_BRIGADE_INSERT_TAIL(b, e); } break; case APR_DBD_TYPE_NULL: *(void**)data = NULL; break; default: return APR_EGENERAL; } return APR_SUCCESS; }
static int on_send_data_cb(nghttp2_session *ngh2, nghttp2_frame *frame, const uint8_t *framehd, size_t length, nghttp2_data_source *source, void *userp) { apr_status_t status = APR_SUCCESS; h2_session *session = (h2_session *)userp; int stream_id = (int)frame->hd.stream_id; const unsigned char padlen = frame->data.padlen; int eos; h2_stream *stream; (void)ngh2; (void)source; if (session->aborted) { return NGHTTP2_ERR_CALLBACK_FAILURE; } stream = h2_stream_set_get(session->streams, stream_id); if (!stream) { ap_log_cerror(APLOG_MARK, APLOG_ERR, APR_NOTFOUND, session->c, APLOGNO(02924) "h2_stream(%ld-%d): send_data", session->id, (int)stream_id); return NGHTTP2_ERR_CALLBACK_FAILURE; } ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, session->c, "h2_stream(%ld-%d): send_data_cb for %ld bytes", session->id, (int)stream_id, (long)length); if (h2_conn_io_is_buffered(&session->io)) { status = h2_conn_io_write(&session->io, (const char *)framehd, 9); if (status == APR_SUCCESS) { if (padlen) { status = h2_conn_io_write(&session->io, (const char *)&padlen, 1); } if (status == APR_SUCCESS) { apr_size_t len = length; status = h2_stream_readx(stream, pass_data, session, &len, &eos); if (status == APR_SUCCESS && len != length) { status = APR_EINVAL; } } if (status == APR_SUCCESS && padlen) { if (padlen) { status = h2_conn_io_write(&session->io, immortal_zeros, padlen); } } } } else { apr_bucket *b; char *header = apr_pcalloc(stream->pool, 10); memcpy(header, (const char *)framehd, 9); if (padlen) { header[9] = (char)padlen; } b = apr_bucket_pool_create(header, padlen? 10 : 9, stream->pool, session->c->bucket_alloc); status = h2_conn_io_writeb(&session->io, b); if (status == APR_SUCCESS) { apr_size_t len = length; status = h2_stream_read_to(stream, session->io.output, &len, &eos); session->io.unflushed = 1; if (status == APR_SUCCESS && len != length) { status = APR_EINVAL; } } if (status == APR_SUCCESS && padlen) { b = apr_bucket_immortal_create(immortal_zeros, padlen, session->c->bucket_alloc); status = h2_conn_io_writeb(&session->io, b); } } if (status == APR_SUCCESS) { stream->data_frames_sent++; h2_conn_io_consider_flush(&session->io); return 0; } else { ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, session->c, APLOGNO(02925) "h2_stream(%ld-%d): failed send_data_cb", session->id, (int)stream_id); } return h2_session_status_from_apr_status(status); }