"Fossies" - the Fresh Open Source Software Archive 
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "ftp_filters.c" see the
Fossies "Dox" file reference documentation.
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 /*
18 * Original Copyright (c) 2005 Covalent Technologies
19 *
20 * FTP Protocol module for Apache 2.0
21 */
22
23 #include "mod_ftp.h"
24 #include "ftp_internal.h"
25
26 /* ftp_crlf_filter: Filter for sending ASCII files. RFC 959 states that
27 * CRLF should be use where necessary to denote the end
28 * of line. This filter replaces all LF's with CRLF's.
29 *
30 * I believe most clients strip the CR's anyway, but we
31 * need them to transfer the file properly.
32 *
33 * Arguments: f - The current filter.
34 * bb - The bucket brigade sent down the filter stack.
35 *
36 * Returns: APR_SUCCESS on success, otherwise the status code is returned.
37 */
38
39 apr_status_t ftp_crlf_filter(ap_filter_t *f, apr_bucket_brigade *bb)
40 {
41 apr_bucket *e;
42 apr_bucket *b;
43 apr_status_t rv;
44 apr_off_t this_size = 0;
45 int *seen_cr = (int *) f->ctx;
46
47 e = APR_BRIGADE_FIRST(bb);
48 while (e != APR_BRIGADE_SENTINEL(bb)) {
49 const char *buf;
50 apr_size_t len;
51 const char *pos;
52
53 if (e->length == 0) {
54 e = APR_BUCKET_NEXT(e); /* onwards */
55 continue;
56 }
57
58 rv = apr_bucket_read(e, &buf, &len, APR_BLOCK_READ);
59 if (rv != APR_SUCCESS) {
60 return rv;
61 }
62
63 /*
64 * Skip all of the extra effort below for empty buckets, if this is
65 * EOS we will catch it at the while condition looking for the
66 * trailing sentinal.
67 */
68 if (len == 0) {
69 e = APR_BUCKET_NEXT(e); /* onwards */
70 continue;
71 }
72
73 /* Handle case where we have a leading LF */
74 if (!*seen_cr) {
75 if (buf[0] == '\n') {
76 b = apr_bucket_immortal_create("\r", 1,
77 f->c->bucket_alloc);
78 APR_BUCKET_INSERT_BEFORE(e, b);
79 this_size += 1;
80 }
81 }
82 else {
83 *seen_cr = 0;
84 }
85
86 /*
87 * We search the data for a LF without a preceeding CR. If we find
88 * one, we split the bucket so that the LF is the first character in
89 * the new bucket, and then insert a new bucket with a CR and insert
90 * it before the LF bucket (ignored on the next loop by seen_cr.) As
91 * long as we keep seeing CRLF pairs, keep looking forward through
92 * the buffer.
93 */
94 pos = buf;
95 while (++pos, pos = memchr(pos, APR_ASCII_LF, len - (pos - buf))) {
96 /*
97 * We found a bare linefeed, insert a CR and advance to the
98 * LF-remainder (we skip that LF above)
99 */
100 if (*(pos - 1) != APR_ASCII_CR) {
101 apr_bucket_split(e, pos - buf);
102 e = APR_BUCKET_NEXT(e); /* second half */
103 b = apr_bucket_immortal_create("\r", 1,
104 f->c->bucket_alloc);
105 APR_BUCKET_INSERT_BEFORE(e, b);
106 this_size += (pos - buf) + 1; /* including the CR */
107 *seen_cr = 1;
108 break;
109 }
110 }
111
112 /*
113 * If we just split, we will 'reread' this current bucket... But
114 * otherwise we note if the trailing character is a CR, tally this
115 * bucket, and advance to the next bucket
116 */
117 if (!pos) {
118 *seen_cr = (buf[len - 1] == '\r');
119 this_size += len;
120 e = APR_BUCKET_NEXT(e); /* onwards */
121 }
122
123 /*
124 * We got too big and chunky, let's spill this out to the client data
125 * connection and resume processing
126 */
127 if (this_size >= 9000) {
128 apr_bucket_brigade *bb_split = bb;
129 bb = apr_brigade_split(bb_split, e);
130 rv = ap_pass_brigade(f->next, bb_split);
131 if (rv != APR_SUCCESS)
132 return rv;
133 this_size = 0;
134 }
135 }
136
137 if (APR_BRIGADE_EMPTY(bb))
138 rv = APR_SUCCESS;
139 else {
140 rv = ap_pass_brigade(f->next, bb);
141 if (rv == APR_SUCCESS && f->c->aborted)
142 rv = AP_FILTER_ERROR;
143 }
144 return rv;
145 }