Apache HTTPD
mod_proxy_fcgi.c
Go to the documentation of this file.
1/* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "mod_proxy.h"
18#include "util_fcgi.h"
19#include "util_script.h"
20#include "ap_expr.h"
21
22module AP_MODULE_DECLARE_DATA proxy_fcgi_module;
23
24typedef struct {
27 const char *envname;
28} sei_entry;
29
30typedef struct {
33
34/* We will assume FPM, but still differentiate */
40
41
42#define FCGI_MAY_BE_FPM(dconf) \
43 (dconf && \
44 ((dconf->backend_type == BACKEND_DEFAULT_UNKNOWN) || \
45 (dconf->backend_type == BACKEND_FPM)))
46
51
52/*
53 * Canonicalise http-like URLs.
54 * scheme is the scheme for the URL
55 * url is the URL starting with the first '/'
56 * def_port is the default port for this scheme.
57 */
58static int proxy_fcgi_canon(request_rec *r, char *url)
59{
60 char *host, sport[7];
61 const char *err;
62 char *path;
65 const char *pathinfo_type = NULL;
66
67 if (ap_cstr_casecmpn(url, "fcgi:", 5) == 0) {
68 url += 5;
69 }
70 else {
71 return DECLINED;
72 }
73
75
77 "canonicalising URL %s", url);
79 if (err) {
81 "error parsing URL %s: %s", url, err);
82 return HTTP_BAD_REQUEST;
83 }
84
85 if (port != def_port)
86 apr_snprintf(sport, sizeof(sport), ":%d", port);
87 else
88 sport[0] = '\0';
89
90 if (ap_strchr_c(host, ':')) {
91 /* if literal IPv6 address */
92 host = apr_pstrcat(r->pool, "[", host, "]", NULL);
93 }
94
95 if (apr_table_get(r->notes, "proxy-nocanon")
96 || apr_table_get(r->notes, "proxy-noencode")) {
97 path = url; /* this is the raw/encoded path */
98 }
99 else {
101 int flags = d->allow_encoded_slashes && !d->decode_encoded_slashes ? PROXY_CANONENC_NOENCODEDSLASHENCODING : 0;
102
104 r->proxyreq);
105 if (!path) {
106 return HTTP_BAD_REQUEST;
107 }
108 }
109 /*
110 * If we have a raw control character or a ' ' in nocanon path,
111 * correct encoding was missed.
112 */
113 if (path == url && *ap_scan_vchar_obstext(path)) {
115 "To be forwarded path contains control "
116 "characters or spaces");
117 return HTTP_FORBIDDEN;
118 }
119
120 r->filename = apr_pstrcat(r->pool, "proxy:fcgi://", host, sport, "/",
121 path, NULL);
122
124 "set r->filename to %s", r->filename);
125
126 rconf = ap_get_module_config(r->request_config, &proxy_fcgi_module);
127 if (rconf == NULL) {
129 ap_set_module_config(r->request_config, &proxy_fcgi_module, rconf);
130 }
131
132 if (NULL != (pathinfo_type = apr_table_get(r->subprocess_env, "proxy-fcgi-pathinfo"))) {
133 /* It has to be on disk for this to work */
134 if (!strcasecmp(pathinfo_type, "full")) {
135 rconf->need_dirwalk = 1;
137 }
138 else if (!strcasecmp(pathinfo_type, "first-dot")) {
139 char *split = ap_strchr(path, '.');
140 if (split) {
141 char *slash = ap_strchr(split, '/');
142 if (slash) {
145 *slash = '\0'; /* truncate path */
146 }
147 }
148 }
149 else if (!strcasecmp(pathinfo_type, "last-dot")) {
150 char *split = ap_strrchr(path, '.');
151 if (split) {
152 char *slash = ap_strchr(split, '/');
153 if (slash) {
156 *slash = '\0'; /* truncate path */
157 }
158 }
159 }
160 else {
161 /* before proxy-fcgi-pathinfo had multi-values. This requires the
162 * the FCGI server to fixup PATH_INFO because it's the entire path
163 */
164 r->path_info = apr_pstrcat(r->pool, "/", path, NULL);
165 if (!strcasecmp(pathinfo_type, "unescape")) {
167 }
169 "set r->path_info to %s", r->path_info);
170 }
171 }
172
173 return OK;
174}
175
176
177/*
178 ProxyFCGISetEnvIf "reqenv('PATH_INFO') =~ m#/foo(\d+)\.php$#" COVENV1 "$1"
179 ProxyFCGISetEnvIf "reqenv('PATH_INFO') =~ m#/foo(\d+)\.php$#" PATH_INFO "/foo.php"
180 ProxyFCGISetEnvIf "reqenv('PATH_TRANSLATED') =~ m#(/.*foo)(\d+)(.*)#" PATH_TRANSLATED "$1$3"
181*/
183{
184 sei_entry *entries;
185 const char *err, *src;
186 int i = 0, rc = 0;
188
189 entries = (sei_entry *) dconf->env_fixups->elts;
190 for (i = 0; i < dconf->env_fixups->nelts; i++) {
191 sei_entry *entry = &entries[i];
192
194 if (rc < 0) {
196 "fix_cgivars: Condition eval returned %d: %s",
197 rc, err);
198 return APR_EGENERAL;
199 }
200 else if (rc == 0) {
201 continue; /* evaluated false */
202 }
203
204 if (entry->envname[0] == '!') {
206 }
207 else {
208 const char *val = ap_expr_str_exec_re(r, entry->subst, AP_MAX_REG_MATCH, regm, &src, &err);
209 if (err) {
211 "Error evaluating expression for replacement of %s: '%s'",
212 entry->envname, err);
213 continue;
214 }
215 if (APLOGrtrace4(r)) {
216 const char *oldval = apr_table_get(r->subprocess_env, entry->envname);
218 "fix_cgivars: override %s from '%s' to '%s'",
219 entry->envname, oldval, val);
220
221 }
223 }
224 }
225 return APR_SUCCESS;
226}
227
228/* Wrapper for apr_socket_sendv that handles updating the worker stats. */
230 struct iovec *vec,
231 int nvec,
233{
235 apr_size_t written = 0, to_write = 0;
236 int i, offset;
237 apr_socket_t *s = conn->sock;
238
239 for (i = 0; i < nvec; i++) {
240 to_write += vec[i].iov_len;
241 }
242
243 offset = 0;
244 while (to_write) {
245 apr_size_t n = 0;
246 rv = apr_socket_sendv(s, vec + offset, nvec - offset, &n);
247 if (rv != APR_SUCCESS) {
248 break;
249 }
250 if (n > 0) {
251 written += n;
252 if (written >= to_write)
253 break; /* short circuit out */
254 for (i = offset; i < nvec; ) {
255 if (n >= vec[i].iov_len) {
256 offset++;
257 n -= vec[i++].iov_len;
258 } else {
259 vec[i].iov_len -= n;
260 vec[i].iov_base = (char *) vec[i].iov_base + n;
261 break;
262 }
263 }
264 }
265 }
266
267 conn->worker->s->transferred += written;
268 *len = written;
269
270 return rv;
271}
272
273/* Wrapper for apr_socket_recv that handles updating the worker stats. */
275 char *buffer,
277{
279
280 if (rv == APR_SUCCESS) {
281 conn->worker->s->read += *buflen;
282 }
283
284 return rv;
285}
286
288 char *buffer,
290{
293 apr_status_t rv;
294
295 do {
297 rv = get_data(conn, buffer + cumulative_len, &readlen);
298 if (rv != APR_SUCCESS) {
299 return rv;
300 }
302 } while (cumulative_len < buflen);
303
304 return APR_SUCCESS;
305}
306
309{
310 struct iovec vec[2];
311 ap_fcgi_header header;
312 unsigned char farray[AP_FCGI_HEADER_LEN];
314 unsigned char abrb[AP_FCGI_HEADER_LEN];
316
318 sizeof(abrb), 0);
319
322 ? AP_FCGI_KEEP_CONN : 0);
323
326
327 vec[0].iov_base = (void *)farray;
328 vec[0].iov_len = sizeof(farray);
329 vec[1].iov_base = (void *)abrb;
330 vec[1].iov_len = sizeof(abrb);
331
332 return send_data(conn, vec, 2, &len);
333}
334
338{
340 const apr_table_entry_t *elts;
341 struct iovec vec[2];
342 ap_fcgi_header header;
343 unsigned char farray[AP_FCGI_HEADER_LEN];
344 char *body;
345 apr_status_t rv;
349 fcgi_dirconf_t *dconf = ap_get_module_config(r->per_dir_config, &proxy_fcgi_module);
350
351 if (rconf) {
352 if (rconf->need_dirwalk) {
354 }
355 }
356
357 /* Strip proxy: prefixes */
358 if (r->filename) {
359 char *newfname = NULL;
360
361 if (!strncmp(r->filename, "proxy:balancer://", 17)) {
363 }
364
365 if (!FCGI_MAY_BE_FPM(dconf)) {
366 if (!strncmp(r->filename, "proxy:fcgi://", 13)) {
367 /* If we strip this under FPM, and any internal redirect occurs
368 * on PATH_INFO, FPM may use PATH_TRANSLATED instead of
369 * SCRIPT_FILENAME (a la mod_fastcgi + Action).
370 */
372 }
373 /* Query string in environment only */
374 if (newfname && r->args && *r->args) {
375 char *qs = strrchr(newfname, '?');
376 if (qs && !strcmp(qs+1, r->args)) {
377 *qs = '\0';
378 }
379 }
380 }
381
382 if (newfname) {
385 }
386 }
387
390
391 /* XXX are there any FastCGI specific env vars we need to send? */
392
393 /* Give admins final option to fine-tune env vars */
394 if (APR_SUCCESS != (rv = fix_cgivars(r, dconf))) {
395 return rv;
396 }
397
398 /* XXX mod_cgi/mod_cgid use ap_create_environment here, which fills in
399 * the TZ value specially. We could use that, but it would mean
400 * parsing the key/value pairs back OUT of the allocated env array,
401 * not to mention allocating a totally useless array in the first
402 * place, which would suck. */
403
405 elts = (const apr_table_entry_t *) envarr->elts;
406
407 if (APLOGrtrace8(r)) {
408 int i;
409
410 for (i = 0; i < envarr->nelts; ++i) {
412 "sending env var '%s' value '%s'",
413 elts[i].key, elts[i].val);
414 }
415 }
416
417 /* Send envvars over in as many FastCGI records as it takes, */
418 next_elem = 0; /* starting with the first one */
419
420 avail_len = 16 * 1024; /* our limit per record, which could have been up
421 * to AP_FCGI_MAX_CONTENT_LEN
422 */
423
427 avail_len,
428 &next_elem);
429
430 if (!required_len) {
433 APLOGNO(02536) "couldn't encode envvar '%s' in %"
434 APR_SIZE_T_FMT " bytes",
435 elts[next_elem].key, avail_len);
436 /* skip this envvar and continue */
437 ++next_elem;
438 continue;
439 }
440 /* only an unused element at the end of the array */
441 break;
442 }
443
447 /* we pre-compute, so we can't run out of space */
448 ap_assert(rv == APR_SUCCESS);
449 /* compute and encode must be in sync */
451
455
456 vec[0].iov_base = (void *)farray;
457 vec[0].iov_len = sizeof(farray);
458 vec[1].iov_base = body;
459 vec[1].iov_len = required_len;
460
461 rv = send_data(conn, vec, 2, &len);
463
464 if (rv) {
465 return rv;
466 }
467 }
468
469 /* Envvars sent, so say we're done */
472
473 vec[0].iov_base = (void *)farray;
474 vec[0].iov_len = sizeof(farray);
475
476 return send_data(conn, vec, 1, &len);
477}
478
479enum {
487
488/* Try to find the end of the script headers in the response from the back
489 * end fastcgi server. STATE holds the current header parsing state for this
490 * request.
491 *
492 * Returns 0 if it can't find the end of the headers, and 1 if it found the
493 * end of the headers. */
494static int handle_headers(request_rec *r, int *state,
495 const char *readbuf, apr_size_t readlen)
496{
497 const char *itr = readbuf;
498
499 while (readlen--) {
500 if (*itr == '\r') {
501 switch (*state) {
503 *state = HDR_STATE_GOT_CRLFCR;
504 break;
505
506 default:
507 *state = HDR_STATE_GOT_CR;
508 break;
509 }
510 }
511 else if (*itr == '\n') {
512 switch (*state) {
513 case HDR_STATE_GOT_LF:
515 break;
516
517 case HDR_STATE_GOT_CR:
518 *state = HDR_STATE_GOT_CRLF;
519 break;
520
523 break;
524
525 default:
526 *state = HDR_STATE_GOT_LF;
527 break;
528 }
529 }
530 else {
532 }
533
534 if (*state == HDR_STATE_DONE_WITH_HEADERS)
535 break;
536
537 ++itr;
538 }
539
540 if (*state == HDR_STATE_DONE_WITH_HEADERS) {
541 return 1;
542 }
543
544 return 0;
545}
546
549 apr_uint16_t request_id, const char **err,
550 int *bad_request, int *has_responded,
551 apr_bucket_brigade *input_brigade)
552{
554 int seen_end_of_headers = 0, done = 0, ignore_body = 0;
558 struct iovec vec[2];
559 ap_fcgi_header header;
560 unsigned char farray[AP_FCGI_HEADER_LEN];
561 apr_pollfd_t pfd;
567 char *iobuf = stack_iobuf;
568
569 *err = NULL;
570 if (conn->worker->s->io_buffer_size_set) {
573 }
574
576 pfd.desc.s = conn->sock;
577 pfd.p = r->pool;
579
580 if (conn->worker->s->flush_packets == flush_auto) {
582 flushpoll->reqevents = APR_POLLIN;
583 flushpoll->desc_type = APR_POLL_SOCKET;
584 flushpoll->desc.s = conn->sock;
585 }
586
587 ib = apr_brigade_create(r->pool, c->bucket_alloc);
588 ob = apr_brigade_create(r->pool, c->bucket_alloc);
589
590 while (! done) {
593 int n;
594
595 /* We need SOME kind of timeout here, or virtually anything will
596 * cause timeout errors. */
598
599 rv = apr_poll(&pfd, 1, &n, timeout);
600 if (rv != APR_SUCCESS) {
601 if (APR_STATUS_IS_EINTR(rv)) {
602 continue;
603 }
604 *err = "polling";
605 break;
606 }
607
608 if (pfd.rtnevents & APR_POLLOUT) {
610 int last_stdin = 0;
611 char *iobuf_cursor;
612
613 if (APR_BRIGADE_EMPTY(input_brigade)) {
616 iobuf_size);
617 }
618 else {
619 apr_bucket *e;
620 APR_BRIGADE_CONCAT(ib, input_brigade);
622 if (rv == APR_SUCCESS) {
623 while (e != APR_BRIGADE_SENTINEL(ib)
626 }
627 apr_brigade_split_ex(ib, e, input_brigade);
628 }
629 else if (rv == APR_INCOMPLETE) {
630 rv = APR_SUCCESS;
631 }
632 }
633 if (rv != APR_SUCCESS) {
634 *err = "reading input brigade";
635 *bad_request = 1;
636 break;
637 }
638
640 last_stdin = 1;
641 }
642
644
646
648
649 if (rv != APR_SUCCESS) {
650 *err = "flattening brigade";
651 break;
652 }
653
656 while (to_send > 0) {
657 int nvec = 0;
659
662
666
667 vec[nvec].iov_base = (void *)farray;
668 vec[nvec].iov_len = sizeof(farray);
669 ++nvec;
670 if (writebuflen) {
671 vec[nvec].iov_base = iobuf_cursor;
672 vec[nvec].iov_len = write_this_time;
673 ++nvec;
674 }
675
676 rv = send_data(conn, vec, nvec, &len);
677 if (rv != APR_SUCCESS) {
678 *err = "sending stdin";
679 break;
680 }
681
684 }
685 if (rv != APR_SUCCESS) {
686 break;
687 }
688
689 if (last_stdin) {
690 pfd.reqevents = APR_POLLIN; /* Done with input data */
691
692 /* signal EOF (empty FCGI_STDIN) */
694 0, 0);
696
697 vec[0].iov_base = (void *)farray;
698 vec[0].iov_len = sizeof(farray);
699
700 rv = send_data(conn, vec, 1, &len);
701 if (rv != APR_SUCCESS) {
702 *err = "sending empty stdin";
703 break;
704 }
705 }
706 }
707
708 if (pfd.rtnevents & APR_POLLIN) {
711 apr_bucket *b;
712 unsigned char plen;
713 unsigned char type, version;
714 int mayflush = 0;
715
716 /* First, we grab the header... */
717 rv = get_data_full(conn, (char *) farray, AP_FCGI_HEADER_LEN);
718 if (rv != APR_SUCCESS) {
720 "Failed to read FastCGI header");
721 break;
722 }
723
724 ap_log_rdata(APLOG_MARK, APLOG_TRACE8, r, "FastCGI header",
726
728 &clen, &plen, farray);
729
730 if (version != AP_FCGI_VERSION_1) {
732 "Got bogus version %d", (int)version);
733 rv = APR_EINVAL;
734 break;
735 }
736
737 if (rid != request_id) {
739 "Got bogus rid %d, expected %d",
740 rid, request_id);
741 rv = APR_EINVAL;
742 break;
743 }
744
746 if (clen > iobuf_size) {
748 } else {
750 }
751
752 /* Now get the actual data. Yes it sucks to do this in a second
753 * recv call, this will eventually change when we move to real
754 * nonblocking recv calls. */
755 if (readbuflen != 0) {
756 rv = get_data(conn, iobuf, &readbuflen);
757 if (rv != APR_SUCCESS) {
758 *err = "reading response body";
759 break;
760 }
761 }
762
763 switch (type) {
764 case AP_FCGI_STDOUT:
765 if (clen != 0) {
768 c->bucket_alloc);
769
771
772 if (! seen_end_of_headers) {
775
776 if (st == 1) {
777 int status;
779
782
783 /* FCGI has its own body framing mechanism which we don't
784 * match against any provided Content-Length, so let the
785 * core determine C-L vs T-E based on what's actually sent.
786 */
788 apr_table_unset(r->headers_out, "Content-Length");
789 apr_table_unset(r->headers_out, "Transfer-Encoding");
790
791 /* suck in all the rest */
792 if (status != OK) {
795 tmp_b = apr_bucket_eos_create(c->bucket_alloc);
797
798 *has_responded = 1;
799 r->status = status;
801 if (rv != APR_SUCCESS) {
802 *err = "passing headers brigade to output filters";
803 break;
804 }
805 else if (status == HTTP_NOT_MODIFIED
807 /* Special 'status' cases handled:
808 * 1) HTTP 304 response MUST NOT contain
809 * a message-body, ignore it.
810 * 2) HTTP 412 response.
811 * The break is not added since there might
812 * be more bytes to read from the FCGI
813 * connection. Even if the message-body is
814 * ignored (and the EOS bucket has already
815 * been sent) we want to avoid subsequent
816 * bogus reads. */
817 ignore_body = 1;
818 }
819 else {
821 "Error parsing script headers");
822 rv = APR_EINVAL;
823 break;
824 }
825 }
826
828 /*
829 * set script_error_status to discard
830 * everything after the headers
831 */
833 /*
834 * prevent ap_die() from treating this as a
835 * recursive error, initially:
836 */
837 r->status = HTTP_OK;
838 }
839
842 /* Send the part of the body that we read while
843 * reading the headers.
844 */
845 *has_responded = 1;
847 if (rv != APR_SUCCESS) {
848 *err = "passing brigade to output filters";
849 break;
850 }
851 mayflush = 1;
852 }
854
856 }
857 else {
858 /* We're still looking for the end of the
859 * headers, so this part of the data will need
860 * to persist. */
862 }
863 } else {
864 /* we've already passed along the headers, so now pass
865 * through the content. we could simply continue to
866 * setaside the content and not pass until we see the
867 * 0 content-length (below, where we append the EOS),
868 * but that could be a huge amount of data; so we pass
869 * along smaller chunks
870 */
872 *has_responded = 1;
874 if (rv != APR_SUCCESS) {
875 *err = "passing brigade to output filters";
876 break;
877 }
878 mayflush = 1;
879 }
881 }
882
883 /* If we didn't read all the data, go back and get the
884 * rest of it. */
885 if (clen > readbuflen) {
886 clen -= readbuflen;
887 goto recv_again;
888 }
889 } else {
890 /* XXX what if we haven't seen end of the headers yet? */
891
893 b = apr_bucket_eos_create(c->bucket_alloc);
895
896 *has_responded = 1;
898 if (rv != APR_SUCCESS) {
899 *err = "passing brigade to output filters";
900 break;
901 }
902 }
903
904 /* XXX Why don't we cleanup here? (logic from AJP) */
905 }
906 break;
907
908 case AP_FCGI_STDERR:
909 /* TODO: Should probably clean up this logging a bit... */
910 if (clen) {
912 "Got error '%.*s'", (int)readbuflen, iobuf);
913 }
914
915 if (clen > readbuflen) {
916 clen -= readbuflen;
917 goto recv_again;
918 }
919 break;
920
922 done = 1;
923 break;
924
925 default:
927 "Got bogus record %d", type);
928 break;
929 }
930 /* Leave on above switch's inner error. */
931 if (rv != APR_SUCCESS) {
932 break;
933 }
934
935 if (plen) {
936 rv = get_data_full(conn, iobuf, plen);
937 if (rv != APR_SUCCESS) {
939 "Error occurred reading padding");
940 break;
941 }
942 }
943
944 if (mayflush && ((conn->worker->s->flush_packets == flush_on) ||
945 ((conn->worker->s->flush_packets == flush_auto) &&
946 (apr_poll(flushpoll, 1, &flushpoll_fd,
947 conn->worker->s->flush_wait) == APR_TIMEUP)))) {
951 if (rv != APR_SUCCESS) {
952 *err = "passing headers brigade to output filters";
953 break;
954 }
955 mayflush = 0;
956 }
957 }
958 }
959
962
964 ap_die(script_error_status, r); /* send ErrorDocument */
965 *has_responded = 1;
966 }
967
968 return rv;
969}
970
971/*
972 * process the request and write the response.
973 */
975 proxy_conn_rec *conn,
976 conn_rec *origin,
977 proxy_dir_conf *conf,
978 apr_uri_t *uri,
979 char *url, char *server_portstr,
980 apr_bucket_brigade *input_brigade)
981{
982 /* Request IDs are arbitrary numbers that we assign to a
983 * single request. This would allow multiplex/pipelining of
984 * multiple requests to the same FastCGI connection, but
985 * we don't support that, and always use a value of '1' to
986 * keep things simple. */
988 apr_status_t rv;
990 const char *err;
991 int bad_request = 0,
992 has_responded = 0;
993
994 /* Step 1: Send AP_FCGI_BEGIN_REQUEST */
995 rv = send_begin_request(conn, request_id);
996 if (rv != APR_SUCCESS) {
998 "Failed Writing Request to %s:", server_portstr);
999 conn->close = 1;
1001 }
1002
1004 apr_pool_tag(temp_pool, "proxy_fcgi_do_request");
1005
1006 /* Step 2: Send Environment via FCGI_PARAMS */
1007 rv = send_environment(conn, r, temp_pool, request_id);
1008 if (rv != APR_SUCCESS) {
1010 "Failed writing Environment to %s:", server_portstr);
1011 conn->close = 1;
1013 }
1014
1015 /* Step 3: Read records from the back end server and handle them. */
1016 rv = dispatch(conn, conf, r, temp_pool, request_id,
1018 input_brigade);
1019 if (rv != APR_SUCCESS) {
1020 /* If the client aborted the connection during retrieval or (partially)
1021 * sending the response, don't return a HTTP_SERVICE_UNAVAILABLE, since
1022 * this is not a backend problem. */
1023 if (r->connection->aborted) {
1025 "The client aborted the connection.");
1026 conn->close = 1;
1027 return OK;
1028 }
1029
1031 "Error dispatching request to %s: %s%s%s",
1032 server_portstr,
1033 err ? "(" : "",
1034 err ? err : "",
1035 err ? ")" : "");
1036 conn->close = 1;
1037 if (has_responded) {
1038 return AP_FILTER_ERROR;
1039 }
1040 if (bad_request) {
1042 }
1043 if (APR_STATUS_IS_TIMEUP(rv)) {
1044 return HTTP_GATEWAY_TIME_OUT;
1045 }
1047 }
1048
1049 return OK;
1050}
1051
1052#define FCGI_SCHEME "FCGI"
1053
1054#define MAX_MEM_SPOOL 16384
1055
1056/*
1057 * This handles fcgi:(dest) URLs
1058 */
1060 proxy_server_conf *conf,
1061 char *url, const char *proxyname,
1063{
1064 int status;
1065 char server_portstr[32];
1066 conn_rec *origin = NULL;
1067 proxy_conn_rec *backend = NULL;
1068 apr_bucket_brigade *input_brigade;
1070 apr_uri_t *uri;
1071
1073 &proxy_module);
1074
1075 apr_pool_t *p = r->pool;
1076
1077
1079 "url: %s proxyname: %s proxyport: %d",
1081
1082 if (ap_cstr_casecmpn(url, "fcgi:", 5) != 0) {
1083 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01077) "declining URL %s", url);
1084 return DECLINED;
1085 }
1086
1087 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01078) "serving URL %s", url);
1088
1089 /* Create space for state information */
1091 r->server);
1092 if (status != OK) {
1093 if (backend) {
1094 backend->close = 1;
1096 }
1097 return status;
1098 }
1099
1100 backend->is_ssl = 0;
1101
1102 /* Step One: Determine Who To Connect To */
1103 uri = apr_palloc(p, sizeof(*uri));
1104 status = ap_proxy_determine_connection(p, r, conf, worker, backend,
1106 server_portstr,
1107 sizeof(server_portstr));
1108 if (status != OK) {
1109 goto cleanup;
1110 }
1111
1112 /* We possibly reuse input data prefetched in previous call(s), e.g. for a
1113 * balancer fallback scenario.
1114 */
1115 apr_pool_userdata_get((void **)&input_brigade, "proxy-fcgi-input", p);
1116 if (input_brigade == NULL) {
1117 const char *old_te = apr_table_get(r->headers_in, "Transfer-Encoding");
1118 const char *old_cl = NULL;
1119 if (old_te) {
1120 apr_table_unset(r->headers_in, "Content-Length");
1121 }
1122 else {
1123 old_cl = apr_table_get(r->headers_in, "Content-Length");
1124 }
1125
1126 input_brigade = apr_brigade_create(p, r->connection->bucket_alloc);
1127 apr_pool_userdata_setn(input_brigade, "proxy-fcgi-input", NULL, p);
1128
1129 /* Prefetch (nonlocking) the request body so to increase the chance
1130 * to get the whole (or enough) body and determine Content-Length vs
1131 * chunked or spooled. By doing this before connecting or reusing the
1132 * backend, we want to minimize the delay between this connection is
1133 * considered alive and the first bytes sent (should the client's link
1134 * be slow or some input filter retain the data). This is a best effort
1135 * to prevent the backend from closing (from under us) what it thinks is
1136 * an idle connection, hence to reduce to the minimum the unavoidable
1137 * local is_socket_connected() vs remote keepalive race condition.
1138 */
1139 status = ap_proxy_prefetch_input(r, backend, input_brigade,
1142 if (status != OK) {
1143 goto cleanup;
1144 }
1145
1146 /*
1147 * The request body is streamed by default, using either C-L or
1148 * chunked T-E, like this:
1149 *
1150 * The whole body (including no body) was received on prefetch, i.e.
1151 * the input brigade ends with EOS => C-L = input_bytes.
1152 *
1153 * C-L is known and reliable, i.e. only protocol filters in the input
1154 * chain thus none should change the body => use C-L from client.
1155 *
1156 * The administrator has not "proxy-sendcl" which prevents T-E => use
1157 * T-E and chunks.
1158 *
1159 * Otherwise we need to determine and set a content-length, so spool
1160 * the entire request body to memory/temporary file (MAX_MEM_SPOOL),
1161 * such that we finally know its length => C-L = input_bytes.
1162 */
1163 if (!APR_BRIGADE_EMPTY(input_brigade)
1164 && APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade))) {
1165 /* The whole thing fit, so our decision is trivial, use the input
1166 * bytes for the Content-Length. If we expected no body, and read
1167 * no body, do not set the Content-Length.
1168 */
1169 if (old_cl || old_te || input_bytes) {
1170 apr_table_setn(r->headers_in, "Content-Length",
1172 if (old_te) {
1173 apr_table_unset(r->headers_in, "Transfer-Encoding");
1174 }
1175 }
1176 }
1177 else if (old_cl && r->input_filters == r->proto_input_filters) {
1178 /* Streaming is possible by preserving the existing C-L */
1179 }
1180 else if (!apr_table_get(r->subprocess_env, "proxy-sendcl")) {
1181 /* Streaming is possible using T-E: chunked */
1182 }
1183 else {
1184 /* No streaming, C-L is the only option so spool to memory/file */
1185 apr_bucket_brigade *tmp_bb;
1187
1190 status = ap_proxy_spool_input(r, backend, tmp_bb, &remaining_bytes,
1192 if (status != OK) {
1193 goto cleanup;
1194 }
1195
1196 APR_BRIGADE_CONCAT(input_brigade, tmp_bb);
1198
1199 apr_table_setn(r->headers_in, "Content-Length",
1201 if (old_te) {
1202 apr_table_unset(r->headers_in, "Transfer-Encoding");
1203 }
1204 }
1205 }
1206
1207 /* This scheme handler does not reuse connections by default, to
1208 * avoid tying up a fastcgi that isn't expecting to work on
1209 * parallel requests. But if the user went out of their way to
1210 * type the default value of disablereuse=off, we'll allow it.
1211 */
1212 backend->close = 1;
1213 if (worker->s->disablereuse_set && !worker->s->disablereuse) {
1214 backend->close = 0;
1215 }
1216
1217 /* Step Two: Make the Connection */
1220 && ap_proxy_connect_backend(FCGI_SCHEME, backend, worker,
1221 r->server)) {
1223 "failed to make connection to backend: %s",
1224 backend->hostname);
1226 goto cleanup;
1227 }
1228
1229 /* Step Three: Process the Request */
1230 status = fcgi_do_request(p, r, backend, origin, dconf, uri, url,
1231 server_portstr, input_brigade);
1232
1233cleanup:
1235 return status;
1236}
1237
1238static void *fcgi_create_dconf(apr_pool_t *p, char *path)
1239{
1241
1243 a->backend_type = BACKEND_DEFAULT_UNKNOWN;
1244 a->env_fixups = apr_array_make(p, 20, sizeof(sei_entry));
1245
1246 return a;
1247}
1248
1249static void *fcgi_merge_dconf(apr_pool_t *p, void *basev, void *overridesv)
1250{
1252
1256
1257 a->backend_type = (over->backend_type != BACKEND_DEFAULT_UNKNOWN)
1258 ? over->backend_type
1259 : base->backend_type;
1260 a->env_fixups = apr_array_append(p, base->env_fixups, over->env_fixups);
1261 return a;
1262}
1263
1264static const char *cmd_servertype(cmd_parms *cmd, void *in_dconf,
1265 const char *val)
1266{
1267 fcgi_dirconf_t *dconf = in_dconf;
1268
1269 if (!strcasecmp(val, "GENERIC")) {
1271 }
1272 else if (!strcasecmp(val, "FPM")) {
1273 dconf->backend_type = BACKEND_FPM;
1274 }
1275 else {
1276 return "ProxyFCGIBackendType requires one of the following arguments: "
1277 "'GENERIC', 'FPM'";
1278 }
1279
1280 return NULL;
1281}
1282
1283
1284static const char *cmd_setenv(cmd_parms *cmd, void *in_dconf,
1285 const char *arg1, const char *arg2,
1286 const char *arg3)
1287{
1288 fcgi_dirconf_t *dconf = in_dconf;
1289 const char *err;
1290 sei_entry *new;
1291 const char *envvar = arg2;
1292
1293 new = apr_array_push(dconf->env_fixups);
1294 new->cond = ap_expr_parse_cmd(cmd, arg1, 0, &err, NULL);
1295 if (err) {
1296 return apr_psprintf(cmd->pool, "Could not parse expression \"%s\": %s",
1297 arg1, err);
1298 }
1299
1300 if (envvar[0] == '!') {
1301 /* Unset mode. */
1302 if (arg3) {
1303 return apr_psprintf(cmd->pool, "Third argument (\"%s\") is not "
1304 "allowed when using ProxyFCGISetEnvIf's unset "
1305 "mode (%s)", arg3, envvar);
1306 }
1307 else if (!envvar[1]) {
1308 /* i.e. someone tried to give us a name of just "!" */
1309 return "ProxyFCGISetEnvIf: \"!\" is not a valid variable name";
1310 }
1311
1312 new->subst = NULL;
1313 }
1314 else {
1315 /* Set mode. */
1316 if (!arg3) {
1317 /* A missing expr-value should be treated as empty. */
1318 arg3 = "";
1319 }
1320
1322 if (err) {
1323 return apr_psprintf(cmd->pool, "Could not parse expression \"%s\": %s",
1324 arg3, err);
1325 }
1326 }
1327
1328 new->envname = envvar;
1329
1330 return NULL;
1331}
1337
1338static const command_rec command_table[] = {
1339 AP_INIT_TAKE1("ProxyFCGIBackendType", cmd_servertype, NULL, OR_FILEINFO,
1340 "Specify the type of FastCGI server: 'Generic', 'FPM'"),
1341 AP_INIT_TAKE23("ProxyFCGISetEnvIf", cmd_setenv, NULL, OR_FILEINFO,
1342 "expr-condition env-name expr-value"),
1343 { NULL }
1344};
1345
1348 fcgi_create_dconf, /* create per-directory config structure */
1349 fcgi_merge_dconf, /* merge per-directory config structures */
1350 NULL, /* create per-server config structure */
1351 NULL, /* merge per-server config structures */
1352 command_table, /* command apr_table_t */
1353 register_hooks /* register hooks */
1354};
Expression parser.
int n
Definition ap_regex.h:278
const char apr_size_t len
Definition ap_regex.h:187
apr_size_t const unsigned char unsigned int unsigned int d
Definition apr_siphash.h:72
apr_array_append(apr_pool_t *p, const apr_array_header_t *first, const apr_array_header_t *second)
Definition apr_tables.c:213
#define AP_INIT_TAKE1(directive, func, mconfig, where, help)
#define ap_get_module_config(v, m)
#define AP_DECLARE_MODULE(foo)
ap_conf_vector_t * base
#define ap_set_module_config(v, m, val)
request_rec int int apr_table_t const char * path
request_rec * r
#define AP_INIT_TAKE23(directive, func, mconfig, where, help)
#define AP_FILTER_ERROR
Definition httpd.h:473
#define AP_IOBUFSIZE
Definition httpd.h:306
#define AP_MAX_REG_MATCH
Definition httpd.h:309
#define DECLINED
Definition httpd.h:457
#define OK
Definition httpd.h:456
void ap_fcgi_fill_in_header(ap_fcgi_header *header, unsigned char type, apr_uint16_t request_id, apr_uint16_t content_len, unsigned char padding_len)
Definition util_fcgi.c:81
#define AP_FCGI_MAX_CONTENT_LEN
Definition util_fcgi.h:67
apr_size_t ap_fcgi_encoded_env_len(apr_table_t *env, apr_size_t maxlen, int *starting_elem)
Definition util_fcgi.c:116
#define AP_FCGI_VERSION_1
Definition util_fcgi.h:72
void ap_fcgi_fill_in_request_body(ap_fcgi_begin_request_body *brb, int role, unsigned char flags)
Definition util_fcgi.c:102
void ap_fcgi_header_fields_from_array(unsigned char *version, unsigned char *type, apr_uint16_t *request_id, apr_uint16_t *content_len, unsigned char *padding_len, unsigned char a[])
Definition util_fcgi.c:52
#define AP_FCGI_HEADER_LEN
Definition util_fcgi.h:62
#define AP_FCGI_STDERR
Definition util_fcgi.h:83
void ap_fcgi_header_to_array(ap_fcgi_header *h, unsigned char a[])
Definition util_fcgi.c:26
#define AP_FCGI_END_REQUEST
Definition util_fcgi.h:79
#define AP_FCGI_STDIN
Definition util_fcgi.h:81
#define AP_FCGI_RESPONDER
Definition util_fcgi.h:125
apr_status_t ap_fcgi_encode_env(request_rec *r, apr_table_t *env, void *buffer, apr_size_t buflen, int *starting_elem)
Definition util_fcgi.c:179
#define AP_FCGI_BEGIN_REQUEST
Definition util_fcgi.h:77
#define AP_FCGI_KEEP_CONN
Definition util_fcgi.h:132
#define AP_FCGI_STDOUT
Definition util_fcgi.h:82
#define AP_FCGI_PARAMS
Definition util_fcgi.h:80
void ap_fcgi_begin_request_body_to_array(ap_fcgi_begin_request_body *h, unsigned char a[])
Definition util_fcgi.c:68
apr_status_t ap_pass_brigade(ap_filter_t *filter, apr_bucket_brigade *bucket)
apr_status_t ap_get_brigade(ap_filter_t *filter, apr_bucket_brigade *bucket, ap_input_mode_t mode, apr_read_type_e block, apr_off_t readbytes)
#define ap_get_core_module_config(v)
Definition http_core.h:383
#define APLOG_TRACE8
Definition http_log.h:79
#define APLOGNO(n)
Definition http_log.h:117
#define APLOG_TRACE4
Definition http_log.h:75
#define APLOG_INFO
Definition http_log.h:70
#define ap_log_rerror
Definition http_log.h:454
#define APLOG_ERR
Definition http_log.h:67
#define APLOGrtrace4(r)
Definition http_log.h:249
#define APLOG_MARK
Definition http_log.h:283
#define APLOG_WARNING
Definition http_log.h:68
#define ap_log_rdata
Definition http_log.h:642
#define APLOGrtrace8(r)
Definition http_log.h:253
#define APLOG_TRACE1
Definition http_log.h:72
#define APLOG_DEBUG
Definition http_log.h:71
#define APLOG_MODULE_INDEX
Definition http_log.h:168
int ap_map_http_request_error(apr_status_t rv, int status)
int ap_directory_walk(request_rec *r)
Definition request.c:661
int ap_is_initial_req(request_rec *r)
Definition request.c:2567
void ap_die(int type, request_rec *r)
void ap_add_common_vars(request_rec *r)
int ap_scan_script_header_err_brigade_ex(request_rec *r, apr_bucket_brigade *bb, char *buffer, int module_index)
void ap_add_cgi_vars(request_rec *r)
#define AP_TRUST_CGILIKE_CL_ENVVAR
const char apr_port_t port
Definition http_vhost.h:125
const char * host
Definition http_vhost.h:124
#define APR_EGENERAL
Definition apr_errno.h:313
#define APR_INCOMPLETE
Definition apr_errno.h:452
#define APR_TIMEUP
Definition apr_errno.h:450
#define APR_EINVAL
Definition apr_errno.h:711
#define APR_STATUS_IS_EINTR(s)
Definition apr_errno.h:1281
#define APR_STATUS_IS_TIMEUP(s)
Definition apr_errno.h:534
#define APR_BRIGADE_LAST(b)
#define APR_BUCKET_IS_METADATA(e)
#define APR_BRIGADE_INSERT_TAIL(b, e)
#define APR_BUCKET_NEXT(e)
apr_bucket * e
#define APR_BRIGADE_CONCAT(a, b)
#define APR_BRIGADE_EMPTY(b)
#define APR_BRIGADE_SENTINEL(b)
#define APR_BUCKET_IS_EOS(e)
#define apr_bucket_setaside(e, p)
apr_bucket apr_bucket_brigade * a
@ APR_BLOCK_READ
Definition apr_buckets.h:58
@ APR_NONBLOCK_READ
Definition apr_buckets.h:59
const char * src
Definition apr_encode.h:167
const char apr_ssize_t int flags
Definition apr_encode.h:168
const char * url
Definition apr_escape.h:120
#define APR_HOOK_FIRST
Definition apr_hooks.h:301
apr_pool_t * temp_pool
apr_redis_t * rc
Definition apr_redis.h:173
const char * uri
Definition apr_uri.h:159
#define AP_EXPR_FLAG_STRING_RESULT
Definition ap_expr.h:68
#define ap_expr_parse_cmd(cmd, expr, flags, err, lookup_fn)
Definition ap_expr.h:340
int ap_expr_exec_re(request_rec *r, const ap_expr_info_t *expr, apr_size_t nmatch, ap_regmatch_t *pmatch, const char **source, const char **err)
const char * ap_expr_str_exec_re(request_rec *r, const ap_expr_info_t *expr, apr_size_t nmatch, ap_regmatch_t *pmatch, const char **source, const char **err)
#define OR_FILEINFO
#define HTTP_OK
Definition httpd.h:490
#define HTTP_BAD_REQUEST
Definition httpd.h:508
#define HTTP_SERVICE_UNAVAILABLE
Definition httpd.h:538
#define HTTP_PRECONDITION_FAILED
Definition httpd.h:520
#define HTTP_NOT_MODIFIED
Definition httpd.h:504
#define HTTP_FORBIDDEN
Definition httpd.h:511
#define HTTP_GATEWAY_TIME_OUT
Definition httpd.h:539
#define PROXY_CHECK_CONN_EMPTY
Definition mod_proxy.h:1135
int ap_proxy_connect_backend(const char *proxy_function, proxy_conn_rec *conn, proxy_worker *worker, server_rec *s)
int ap_proxy_should_override(proxy_dir_conf *conf, int code)
char * ap_proxy_canon_netloc(apr_pool_t *p, char **const urlp, char **userp, char **passwordp, char **hostp, apr_port_t *port)
Definition proxy_util.c:342
int ap_proxy_release_connection(const char *proxy_function, proxy_conn_rec *conn, server_rec *s)
int ap_proxy_acquire_connection(const char *proxy_function, proxy_conn_rec **conn, proxy_worker *worker, server_rec *s)
int ap_proxy_spool_input(request_rec *r, proxy_conn_rec *backend, apr_bucket_brigade *input_brigade, apr_off_t *bytes_spooled, apr_off_t max_mem_spool)
char * ap_proxy_canonenc_ex(apr_pool_t *p, const char *x, int len, enum enctype t, int flags, int proxyreq)
Definition proxy_util.c:220
apr_status_t ap_proxy_check_connection(const char *scheme, proxy_conn_rec *conn, server_rec *server, unsigned max_blank_lines, int flags)
int ap_proxy_connection_reusable(proxy_conn_rec *conn)
#define PROXY_CANONENC_NOENCODEDSLASHENCODING
Definition mod_proxy.h:81
void proxy_hook_canon_handler(proxy_HOOK_canon_handler_t *pf, const char *const *aszPre, const char *const *aszSucc, int nOrder)
Definition mod_proxy.c:3412
apr_port_t ap_proxy_port_of_scheme(const char *scheme)
int ap_proxy_determine_connection(apr_pool_t *p, request_rec *r, proxy_server_conf *conf, proxy_worker *worker, proxy_conn_rec *conn, apr_uri_t *uri, char **url, const char *proxyname, apr_port_t proxyport, char *server_portstr, int server_portstr_size)
void proxy_hook_scheme_handler(proxy_HOOK_scheme_handler_t *pf, const char *const *aszPre, const char *const *aszSucc, int nOrder)
Definition mod_proxy.c:3406
int ap_proxy_prefetch_input(request_rec *r, proxy_conn_rec *backend, apr_bucket_brigade *input_brigade, apr_read_type_e block, apr_off_t *bytes_read, apr_off_t max_read)
@ enc_path
Definition mod_proxy.h:76
#define STANDARD20_MODULE_STUFF
#define ap_strchr(s, c)
Definition httpd.h:2351
#define ap_strrchr(s, c)
Definition httpd.h:2355
#define ap_strchr_c(s, c)
Definition httpd.h:2353
#define AP_DEBUG_ASSERT(exp)
Definition httpd.h:2283
const char * ap_scan_vchar_obstext(const char *ptr)
Definition util.c:1674
int ap_cstr_casecmpn(const char *s1, const char *s2, apr_size_t n)
Definition util.c:3559
#define ap_assert(exp)
Definition httpd.h:2271
int ap_unescape_url_keep2f(char *url, int decode_slashes)
Definition util.c:1944
apr_size_t size
apr_uint32_t val
Definition apr_atomic.h:66
const char * envvar
Definition apr_env.h:42
#define APR_SUCCESS
Definition apr_errno.h:225
int apr_status_t
Definition apr_errno.h:44
const char * key
const struct iovec * vec
apr_seek_where_t apr_off_t * offset
void const char apr_status_t(* cleanup)(void *))
int type
const struct iovec apr_size_t nvec
char * buffer
int strcasecmp(const char *a, const char *b)
apr_vformatter_buff_t * c
Definition apr_lib.h:175
apr_size_t buflen
apr_uint16_t apr_port_t
@ APR_POLL_SOCKET
Definition apr_poll.h:93
apr_pool_t * b
Definition apr_pools.h:529
#define apr_pool_create(newpool, parent)
Definition apr_pools.h:322
#define apr_pcalloc(p, size)
Definition apr_pools.h:465
const char * s
Definition apr_strings.h:95
int nelts
Definition apr_tables.h:122
apr_int32_t apr_int32_t apr_int32_t err
apr_cmdtype_e cmd
int int status
apr_int64_t apr_interval_time_t
Definition apr_time.h:55
#define APR_POLLOUT
Definition apr_poll.h:51
#define APR_POLLIN
Definition apr_poll.h:49
apr_pool_t * p
Definition md_event.c:32
header_state
Proxy Extension Module for Apache.
static int handle_headers(request_rec *r, int *state, const char *readbuf, apr_size_t readlen)
#define FCGI_SCHEME
static const char * cmd_servertype(cmd_parms *cmd, void *in_dconf, const char *val)
static const command_rec command_table[]
static void * fcgi_merge_dconf(apr_pool_t *p, void *basev, void *overridesv)
@ HDR_STATE_GOT_CRLFCR
@ HDR_STATE_READING_HEADERS
@ HDR_STATE_DONE_WITH_HEADERS
@ HDR_STATE_GOT_CRLF
@ HDR_STATE_GOT_LF
@ HDR_STATE_GOT_CR
static void * fcgi_create_dconf(apr_pool_t *p, char *path)
static apr_status_t get_data(proxy_conn_rec *conn, char *buffer, apr_size_t *buflen)
static apr_status_t fix_cgivars(request_rec *r, fcgi_dirconf_t *dconf)
#define MAX_MEM_SPOOL
static int proxy_fcgi_canon(request_rec *r, char *url)
static apr_status_t dispatch(proxy_conn_rec *conn, proxy_dir_conf *conf, request_rec *r, apr_pool_t *setaside_pool, apr_uint16_t request_id, const char **err, int *bad_request, int *has_responded, apr_bucket_brigade *input_brigade)
#define FCGI_MAY_BE_FPM(dconf)
static void register_hooks(apr_pool_t *p)
static int fcgi_do_request(apr_pool_t *p, request_rec *r, proxy_conn_rec *conn, conn_rec *origin, proxy_dir_conf *conf, apr_uri_t *uri, char *url, char *server_portstr, apr_bucket_brigade *input_brigade)
static apr_status_t send_data(proxy_conn_rec *conn, struct iovec *vec, int nvec, apr_size_t *len)
static apr_status_t send_begin_request(proxy_conn_rec *conn, apr_uint16_t request_id)
static apr_status_t get_data_full(proxy_conn_rec *conn, char *buffer, apr_size_t buflen)
static int proxy_fcgi_handler(request_rec *r, proxy_worker *worker, proxy_server_conf *conf, char *url, const char *proxyname, apr_port_t proxyport)
fcgi_backend_t
@ BACKEND_DEFAULT_UNKNOWN
@ BACKEND_FPM
@ BACKEND_GENERIC
static const char * cmd_setenv(cmd_parms *cmd, void *in_dconf, const char *arg1, const char *arg2, const char *arg3)
static apr_status_t send_environment(proxy_conn_rec *conn, request_rec *r, apr_pool_t *temp_pool, apr_uint16_t request_id)
return NULL
Definition mod_so.c:359
int i
Definition mod_so.c:347
This represents the content data of the FastCGI record when the type is AP_FCGI_BEGIN_REQUEST.
Definition util_fcgi.h:106
A structure that represents the fixed header fields at the beginning of a "FastCGI record" (i....
Definition util_fcgi.h:40
apr_int16_t reqevents
Definition apr_poll.h:111
apr_datatype_e desc_type
Definition apr_poll.h:110
apr_descriptor desc
Definition apr_poll.h:113
apr_pool_t * p
Definition apr_poll.h:109
apr_int16_t rtnevents
Definition apr_poll.h:112
Definition apr_tables.h:81
Structure to store things which are per connection.
Definition httpd.h:1152
struct apr_bucket_alloc_t * bucket_alloc
Definition httpd.h:1201
unsigned aborted
Definition httpd.h:1219
Per-directory configuration.
Definition http_core.h:527
apr_array_header_t * env_fixups
fcgi_backend_t backend_type
const char * hostname
Definition mod_proxy.h:275
apr_socket_t * sock
Definition mod_proxy.h:278
proxy_worker * worker
Definition mod_proxy.h:273
unsigned int is_ssl
Definition mod_proxy.h:283
unsigned int close
Definition mod_proxy.h:284
apr_off_t transferred
Definition mod_proxy.h:462
unsigned int disablereuse_set
Definition mod_proxy.h:476
enum proxy_worker_shared::@35 flush_packets
unsigned int io_buffer_size_set
Definition mod_proxy.h:474
apr_size_t io_buffer_size
Definition mod_proxy.h:458
unsigned int disablereuse
Definition mod_proxy.h:466
proxy_worker_shared * s
Definition mod_proxy.h:505
A structure that represents the current request.
Definition httpd.h:845
int status
Definition httpd.h:891
struct ap_filter_t * output_filters
Definition httpd.h:1070
struct ap_filter_t * proto_input_filters
Definition httpd.h:1079
apr_table_t * notes
Definition httpd.h:985
apr_pool_t * pool
Definition httpd.h:847
char * filename
Definition httpd.h:1018
int proxyreq
Definition httpd.h:873
conn_rec * connection
Definition httpd.h:849
struct ap_filter_t * input_filters
Definition httpd.h:1072
struct ap_conf_vector_t * request_config
Definition httpd.h:1049
apr_table_t * headers_in
Definition httpd.h:976
apr_table_t * subprocess_env
Definition httpd.h:983
server_rec * server
Definition httpd.h:851
struct ap_conf_vector_t * per_dir_config
Definition httpd.h:1047
char * path_info
Definition httpd.h:1024
char * args
Definition httpd.h:1026
apr_table_t * headers_out
Definition httpd.h:978
ap_expr_info_t * subst
ap_expr_info_t * cond
const char * envname
apr_socket_t * s
Definition apr_poll.h:101
apr_status_t apr_socket_sendv(apr_socket_t *sock, const struct iovec *vec, apr_int32_t nvec, apr_size_t *len)
Definition sendrecv.c:194
apr_status_t apr_socket_recv(apr_socket_t *sock, char *buf, apr_size_t *len)
Definition sendrecv.c:70
apr_status_t apr_socket_timeout_get(apr_socket_t *sock, apr_interval_time_t *t)
Definition sockopt.c:355
FastCGI protocol definitions and support routines.
@ AP_MODE_READBYTES
Definition util_filter.h:43
Apache script tools.
IN ULONG IN INT timeout