PageRenderTime 68ms CodeModel.GetById 22ms app.highlight 40ms RepoModel.GetById 1ms app.codeStats 0ms

/boa-0.94.14rc21/src/pipe.c

#
C | 366 lines | 243 code | 48 blank | 75 comment | 111 complexity | faf538ec3962683ef66a0497030e2a56 MD5 | raw file
Possible License(s): GPL-2.0
  1
  2/*
  3 *  Boa, an http server
  4 *  Based on code Copyright (C) 1995 Paul Phillips <paulp@go2net.com>
  5 *  Copyright (C) 1997-2004 Jon Nelson <jnelson@boa.org>
  6 *  Copyright (C) 1997-2005 Larry Doolittle <ldoolitt@boa.org>
  7 *
  8 *  This program is free software; you can redistribute it and/or modify
  9 *  it under the terms of the GNU General Public License as published by
 10 *  the Free Software Foundation; either version 1, or (at your option)
 11 *  any later version.
 12 *
 13 *  This program is distributed in the hope that it will be useful,
 14 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 15 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 16 *  GNU General Public License for more details.
 17 *
 18 *  You should have received a copy of the GNU General Public License
 19 *  along with this program; if not, write to the Free Software
 20 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 21 *
 22 */
 23
 24/* $Id: pipe.c,v 1.39.2.16 2005/02/22 14:13:03 jnelson Exp $*/
 25
 26#include "boa.h"
 27
 28/*
 29 * Name: read_from_pipe
 30 * Description: Reads data from a pipe
 31 *
 32 * Return values:
 33 *  -1: request blocked, move to blocked queue
 34 *   0: EOF or error, close it down
 35 *   1: successful read, recycle in ready queue
 36 */
 37
 38int read_from_pipe(request * req)
 39{
 40    int bytes_read; /* signed */
 41    unsigned int bytes_to_read; /* unsigned */
 42
 43    bytes_to_read = BUFFER_SIZE - (req->header_end - req->buffer - 1);
 44
 45    if (bytes_to_read == 0) {   /* buffer full */
 46        if (req->cgi_status == CGI_PARSE) { /* got+parsed header */
 47            req->cgi_status = CGI_BUFFER;
 48            *req->header_end = '\0'; /* points to end of read data */
 49            /* Could the above statement overwrite data???
 50               No, because req->header_end points to where new data
 51               should begin, not where old data is.
 52             */
 53            return process_cgi_header(req); /* cgi_status will change */
 54        }
 55        req->status = PIPE_WRITE;
 56        return 1;
 57    }
 58
 59    bytes_read = read(req->data_fd, req->header_end, bytes_to_read);
 60#ifdef FASCIST_LOGGING
 61    if (bytes_read > 0) {
 62        *(req->header_end + bytes_read) = '\0';
 63        fprintf(stderr, "pipe.c - read %d bytes: \"%s\"\n",
 64                bytes_read, req->header_end);
 65    } else
 66        fprintf(stderr, "pipe.c - read %d bytes\n", bytes_read);
 67    fprintf(stderr, "status, cgi_status: %d, %d\n", req->status,
 68            req->cgi_status);
 69#endif
 70
 71    if (bytes_read == -1) {
 72        if (errno == EINTR)
 73            return 1;
 74        else if (errno == EWOULDBLOCK || errno == EAGAIN)
 75            return -1;          /* request blocked at the pipe level, but keep going */
 76        else {
 77            req->status = DEAD;
 78            log_error_doc(req);
 79            perror("pipe read");
 80            return 0;
 81        }
 82    }
 83    *(req->header_end + bytes_read) = '\0';
 84
 85    if (bytes_read == 0) {      /* eof, write rest of buffer */
 86        req->status = PIPE_WRITE;
 87        if (req->cgi_status == CGI_PARSE) { /* hasn't processed header yet */
 88            req->cgi_status = CGI_DONE;
 89            *req->header_end = '\0'; /* points to end of read data */
 90            return process_cgi_header(req); /* cgi_status will change */
 91        }
 92        req->cgi_status = CGI_DONE;
 93        return 1;
 94    }
 95
 96    req->header_end += bytes_read;
 97
 98    if (req->cgi_status != CGI_PARSE)
 99        return write_from_pipe(req); /* why not try and flush the buffer now? */
100    else {
101        char *c, *buf;
102
103        buf = req->header_line;
104
105        c = strstr(buf, "\n\r\n");
106        if (c == NULL) {
107            c = strstr(buf, "\n\n");
108            if (c == NULL) {
109                return 1;
110            }
111        }
112        req->cgi_status = CGI_DONE;
113        *req->header_end = '\0'; /* points to end of read data */
114        return process_cgi_header(req); /* cgi_status will change */
115    }
116    return 1;
117}
118
119/*
120 * Name: write_from_pipe
121 * Description: Writes data previously read from a pipe
122 *
123 * Return values:
124 *  -1: request blocked, move to blocked queue
125 *   0: EOF or error, close it down
126 *   1: successful write, recycle in ready queue
127 */
128
129int write_from_pipe(request * req)
130{
131    int bytes_written;
132    size_t bytes_to_write = req->header_end - req->header_line;
133
134    if (bytes_to_write == 0) {
135        if (req->cgi_status == CGI_DONE)
136            return 0;
137
138        req->status = PIPE_READ;
139        req->header_end = req->header_line = req->buffer;
140        return 1;
141    }
142
143    bytes_written = write(req->fd, req->header_line, bytes_to_write);
144
145    if (bytes_written == -1) {
146        if (errno == EWOULDBLOCK || errno == EAGAIN)
147            return -1;          /* request blocked at the pipe level, but keep going */
148        else if (errno == EINTR)
149            return 1;
150        else {
151            req->status = DEAD;
152            log_error_doc(req);
153            perror("pipe write");
154            return 0;
155        }
156    }
157
158    req->header_line += bytes_written;
159    req->bytes_written += bytes_written;
160
161    /* if there won't be anything to write next time, switch state */
162    if ((unsigned) bytes_written == bytes_to_write) {
163        req->status = PIPE_READ;
164        req->header_end = req->header_line = req->buffer;
165    }
166
167    return 1;
168}
169
170#ifdef HAVE_SENDFILE
171int io_shuffle_sendfile(request * req)
172{
173    int bytes_written;
174    size_t bytes_to_write;
175    off_t sendfile_offset;
176
177    if (req->method == M_HEAD) {
178        return complete_response(req);
179    }
180
181    /* XXX trouble if range is exactly 4G on a 32-bit machine? */
182    bytes_to_write = (req->ranges->stop - req->ranges->start) + 1;
183
184    if (bytes_to_write > system_bufsize)
185        bytes_to_write = system_bufsize;
186
187retrysendfile:
188    if (bytes_to_write == 0) {
189        /* shouldn't get here, but... */
190        bytes_written = 0;
191    } else {
192	/* arg 3 of sendfile should have type "off_t *"
193	 * struct range element start has type "unsigned long"
194	 * Where POSIX got the idea that an offset into a file
195	 * should be signed, I'll never know.
196	 */
197	sendfile_offset = req->ranges->start;
198	if (sendfile_offset < 0) {
199		req->status = DEAD;
200		log_error_doc(req);
201		fprintf(stderr, "impossible offset (%lu) requested of sendfile\n",
202				 req->ranges->start);
203		return 0;
204	}
205        bytes_written = sendfile(req->fd, req->data_fd,
206                                 &sendfile_offset,
207                                 bytes_to_write);
208	if (sendfile_offset < 0) {
209		req->status = DEAD;
210		log_error_doc(req);
211		fprintf(stderr,
212			"bad craziness in sendfile offset, returned %ld\n",
213			(long) sendfile_offset);
214		return 0;
215	}
216	req->ranges->start = sendfile_offset;
217        if (bytes_written < 0) {
218            if (errno == EWOULDBLOCK || errno == EAGAIN) {
219                return -1;          /* request blocked at the pipe level, but keep going */
220            } else if (errno == EINTR) {
221                goto retrysendfile;
222            } else {
223                req->status = DEAD;
224#ifdef QUIET_DISCONNECT
225                if (0)
226#else
227                if (errno != EPIPE && errno != ECONNRESET)
228#endif
229                {
230                    log_error_doc(req);
231                    perror("sendfile write");
232                }
233            }
234            return 0;
235        } else if (bytes_written == 0) {
236            /* not sure how to handle this.
237             * For now, treat it like it is blocked.
238             */
239            return -1;
240        }/* bytes_written */
241    } /* bytes_to_write */
242
243    /* sendfile automatically updates req->ranges->start
244     * don't touch!
245     * req->ranges->start += bytes_written;
246     */
247    req->bytes_written += bytes_written;
248
249    if (req->ranges->stop + 1 <= req->ranges->start) {
250        return complete_response(req);
251    }
252    return 1;
253}
254#endif
255
256/* always try to read unless data_fs is 0 (and there is space)
257 * then try to write
258 *
259 * Return values:
260 *  -1: request blocked, move to blocked queue
261 *   0: EOF or error, close it down
262 *   1: successful read, recycle in ready queue
263 */
264
265int io_shuffle(request * req)
266{
267    int bytes_to_read;
268    int bytes_written, bytes_to_write;
269
270    if (req->method == M_HEAD) {
271        return complete_response(req);
272    }
273
274    /* FIXME: This function doesn't take into account req->filesize
275     * when *reading* into the buffer. Grr.
276     * June 09, 2004: jdn, I don't think it's a problem anymore,
277     * because the ranges are verified against the filesize,
278     * and we cap bytes_to_read at bytes_to_write.
279     */
280    bytes_to_read = BUFFER_SIZE - req->buffer_end - 256;
281
282    bytes_to_write = (req->ranges->stop - req->ranges->start) + 1;
283
284    if (bytes_to_read > bytes_to_write)
285        bytes_to_read = bytes_to_write;
286
287    if (bytes_to_read > 0 && req->data_fd) {
288        int bytes_read;
289        off_t temp;
290
291        temp = lseek(req->data_fd, req->ranges->start, SEEK_SET);
292        if (temp < 0) {
293            req->status = DEAD;
294            log_error_doc(req);
295            perror("ioshuffle lseek");
296            return 0;
297        }
298
299      restartread:
300        bytes_read =
301            read(req->data_fd, req->buffer + req->buffer_end,
302                 bytes_to_read);
303
304        if (bytes_read == -1) {
305            if (errno == EINTR)
306                goto restartread;
307            else if (errno == EWOULDBLOCK || errno == EAGAIN) {
308                /* not a fatal error, don't worry about it */
309                /* buffer is empty, we're blocking on read! */
310                if (req->buffer_end - req->buffer_start == 0)
311                    return -1;
312            } else {
313                req->status = DEAD;
314                log_error_doc(req);
315                perror("ioshuffle read");
316                return 0;
317            }
318        } else if (bytes_read == 0) { /* eof, write rest of buffer */
319            close(req->data_fd);
320            req->data_fd = 0;
321        } else {
322            req->buffer_end += bytes_read;
323
324            req->ranges->start += bytes_read;
325
326            if ((req->ranges->stop + 1 - req->ranges->start) == 0) {
327                return complete_response(req);
328            }
329        }
330    }
331
332    bytes_to_write = req->buffer_end - req->buffer_start;
333    if (bytes_to_write == 0) {
334        if (req->data_fd == 0)
335            return 0;           /* done */
336        req->buffer_end = req->buffer_start = 0;
337        return 1;
338    }
339
340  restartwrite:
341    bytes_written =
342        write(req->fd, req->buffer + req->buffer_start, bytes_to_write);
343
344    if (bytes_written == -1) {
345        if (errno == EWOULDBLOCK || errno == EAGAIN)
346            return -1;          /* request blocked at the pipe level, but keep going */
347        else if (errno == EINTR)
348            goto restartwrite;
349        else {
350            req->status = DEAD;
351            log_error_doc(req);
352            perror("ioshuffle write");
353            return 0;
354        }
355    } else if (bytes_written == 0) {
356    }
357
358    req->buffer_start += bytes_written;
359    req->bytes_written += bytes_written;
360
361    if (bytes_to_write == bytes_written) {
362        req->buffer_end = req->buffer_start = 0;
363    }
364
365    return 1;
366}