chunk_filter.c 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  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. * chunk_filter.c --- HTTP/1.1 chunked transfer encoding filter.
  18. */
  19. #include "apr_strings.h"
  20. #include "apr_thread_proc.h" /* for RLIMIT stuff */
  21. #define APR_WANT_STRFUNC
  22. #include "apr_want.h"
  23. #define CORE_PRIVATE
  24. #include "httpd.h"
  25. #include "http_config.h"
  26. #include "http_connection.h"
  27. #include "http_core.h"
  28. #include "http_protocol.h" /* For index_of_response(). Grump. */
  29. #include "http_request.h"
  30. #include "util_filter.h"
  31. #include "util_ebcdic.h"
  32. #include "ap_mpm.h"
  33. #include "scoreboard.h"
  34. #include "mod_core.h"
  35. /*
  36. * A pointer to this is used to memorize in the filter context that a bad
  37. * gateway error bucket had been seen. It is used as an invented unique pointer.
  38. */
  39. static char bad_gateway_seen;
  40. apr_status_t ap_http_chunk_filter(ap_filter_t *f, apr_bucket_brigade *b)
  41. {
  42. #define ASCII_CRLF "\015\012"
  43. #define ASCII_ZERO "\060"
  44. conn_rec *c = f->r->connection;
  45. apr_bucket_brigade *more;
  46. apr_bucket *e;
  47. apr_status_t rv;
  48. for (more = NULL; b; b = more, more = NULL) {
  49. apr_off_t bytes = 0;
  50. apr_bucket *eos = NULL;
  51. apr_bucket *flush = NULL;
  52. /* XXX: chunk_hdr must remain at this scope since it is used in a
  53. * transient bucket.
  54. */
  55. char chunk_hdr[20]; /* enough space for the snprintf below */
  56. for (e = APR_BRIGADE_FIRST(b);
  57. e != APR_BRIGADE_SENTINEL(b);
  58. e = APR_BUCKET_NEXT(e))
  59. {
  60. if (APR_BUCKET_IS_EOS(e)) {
  61. /* there shouldn't be anything after the eos */
  62. eos = e;
  63. break;
  64. }
  65. if (AP_BUCKET_IS_ERROR(e)
  66. && (((ap_bucket_error *)(e->data))->status
  67. == HTTP_BAD_GATEWAY)) {
  68. /*
  69. * We had a broken backend. Memorize this in the filter
  70. * context.
  71. */
  72. f->ctx = &bad_gateway_seen;
  73. continue;
  74. }
  75. if (APR_BUCKET_IS_FLUSH(e)) {
  76. flush = e;
  77. if (e != APR_BRIGADE_LAST(b)) {
  78. more = apr_brigade_split(b, APR_BUCKET_NEXT(e));
  79. }
  80. break;
  81. }
  82. else if (e->length == (apr_size_t)-1) {
  83. /* unknown amount of data (e.g. a pipe) */
  84. const char *data;
  85. apr_size_t len;
  86. rv = apr_bucket_read(e, &data, &len, APR_BLOCK_READ);
  87. if (rv != APR_SUCCESS) {
  88. return rv;
  89. }
  90. if (len > 0) {
  91. /*
  92. * There may be a new next bucket representing the
  93. * rest of the data stream on which a read() may
  94. * block so we pass down what we have so far.
  95. */
  96. bytes += len;
  97. more = apr_brigade_split(b, APR_BUCKET_NEXT(e));
  98. break;
  99. }
  100. else {
  101. /* If there was nothing in this bucket then we can
  102. * safely move on to the next one without pausing
  103. * to pass down what we have counted up so far.
  104. */
  105. continue;
  106. }
  107. }
  108. else {
  109. bytes += e->length;
  110. }
  111. }
  112. /*
  113. * XXX: if there aren't very many bytes at this point it may
  114. * be a good idea to set them aside and return for more,
  115. * unless we haven't finished counting this brigade yet.
  116. */
  117. /* if there are content bytes, then wrap them in a chunk */
  118. if (bytes > 0) {
  119. apr_size_t hdr_len;
  120. /*
  121. * Insert the chunk header, specifying the number of bytes in
  122. * the chunk.
  123. */
  124. hdr_len = apr_snprintf(chunk_hdr, sizeof(chunk_hdr),
  125. "%" APR_UINT64_T_HEX_FMT CRLF, (apr_uint64_t)bytes);
  126. ap_xlate_proto_to_ascii(chunk_hdr, hdr_len);
  127. e = apr_bucket_transient_create(chunk_hdr, hdr_len,
  128. c->bucket_alloc);
  129. APR_BRIGADE_INSERT_HEAD(b, e);
  130. /*
  131. * Insert the end-of-chunk CRLF before an EOS or
  132. * FLUSH bucket, or appended to the brigade
  133. */
  134. e = apr_bucket_immortal_create(ASCII_CRLF, 2, c->bucket_alloc);
  135. if (eos != NULL) {
  136. APR_BUCKET_INSERT_BEFORE(eos, e);
  137. }
  138. else if (flush != NULL) {
  139. APR_BUCKET_INSERT_BEFORE(flush, e);
  140. }
  141. else {
  142. APR_BRIGADE_INSERT_TAIL(b, e);
  143. }
  144. }
  145. /* RFC 2616, Section 3.6.1
  146. *
  147. * If there is an EOS bucket, then prefix it with:
  148. * 1) the last-chunk marker ("0" CRLF)
  149. * 2) the trailer
  150. * 3) the end-of-chunked body CRLF
  151. *
  152. * We only do this if we have not seen an error bucket with
  153. * status HTTP_BAD_GATEWAY. We have memorized an
  154. * error bucket that we had seen in the filter context.
  155. * The error bucket with status HTTP_BAD_GATEWAY indicates that the
  156. * connection to the backend (mod_proxy) broke in the middle of the
  157. * response. In order to signal the client that something went wrong
  158. * we do not create the last-chunk marker and set c->keepalive to
  159. * AP_CONN_CLOSE in the core output filter.
  160. *
  161. * XXX: it would be nice to combine this with the end-of-chunk
  162. * marker above, but this is a bit more straight-forward for
  163. * now.
  164. */
  165. if (eos && !f->ctx) {
  166. /* XXX: (2) trailers ... does not yet exist */
  167. e = apr_bucket_immortal_create(ASCII_ZERO ASCII_CRLF
  168. /* <trailers> */
  169. ASCII_CRLF, 5, c->bucket_alloc);
  170. APR_BUCKET_INSERT_BEFORE(eos, e);
  171. }
  172. /* pass the brigade to the next filter. */
  173. rv = ap_pass_brigade(f->next, b);
  174. if (rv != APR_SUCCESS || eos != NULL) {
  175. return rv;
  176. }
  177. }
  178. return APR_SUCCESS;
  179. }