Bump version.
[mod_fastcgi.git] / fcgi_buf.c
blob6276c03f7096f50dd99269846c1381f8f1b6de58
1 /*
2 * $Id: fcgi_buf.c,v 1.7 2000/04/29 21:01:43 robs Exp $
3 */
5 #include "fcgi.h"
7 /*******************************************************************************
8 * Check buffer consistency with assertions.
9 */
10 void fcgi_buf_check(Buffer *buf)
12 ap_assert(buf->size > 0);
13 ap_assert(buf->length >= 0);
14 ap_assert(buf->length <= buf->size);
16 ap_assert(buf->begin >= buf->data);
17 ap_assert(buf->begin < buf->data + buf->size);
18 ap_assert(buf->end >= buf->data);
19 ap_assert(buf->end < buf->data + buf->size);
21 ap_assert(((buf->end - buf->begin + buf->size) % buf->size)
22 == (buf->length % buf->size));
25 /*******************************************************************************
26 * Reset buffer, losing any data that's in it.
28 void fcgi_buf_reset(Buffer *buf)
30 buf->length = 0;
31 buf->begin = buf->end = buf->data;
34 /*******************************************************************************
35 * Allocate and intialize a new buffer of the specified size.
37 Buffer *fcgi_buf_new(pool *p, int size)
39 Buffer *buf;
41 buf = (Buffer *)ap_pcalloc(p, sizeof(Buffer) + size);
42 buf->size = size;
43 fcgi_buf_reset(buf);
44 return buf;
47 #ifdef WIN32
49 static int fd_read(SOCKET fd, char *buf, int len)
51 long bytes_read;
53 // HACK - we don't know if its a pipe or socket..
54 if (!ReadFile((HANDLE) fd, buf, len, (unsigned long *) &bytes_read, NULL)) {
55 bytes_read = recv(fd, buf, len, 0);
56 if (bytes_read == SOCKET_ERROR) {
57 errno = WSAGetLastError();
58 bytes_read = -1;
61 return bytes_read;
64 #else
66 static int fd_read(int fd, char * buf, int len)
68 int bytes_read;
69 do {
70 bytes_read = read(fd, buf, len);
71 } while (bytes_read == -1 && errno == EINTR);
72 return bytes_read;
75 #endif
77 /*******************************************************************************
78 * Read from an open file descriptor into buffer.
80 * The caller should disable the default Apache SIGPIPE handler,
81 * otherwise a bad script could cause the request to abort and appear
82 * as though the client's fd caused it.
84 * Results:
85 * <0 error, errno is set
86 * =0 EOF reached
87 * >0 successful read or no room in buffer (NOT # of bytes read)
89 #ifdef WIN32
90 int fcgi_buf_add_fd(Buffer *buf, SOCKET fd)
91 #else
92 int fcgi_buf_add_fd(Buffer *buf, int fd)
93 #endif
95 #ifdef WIN32
96 DWORD len;
97 #else
98 size_t len;
99 #endif
101 fcgi_buf_check(buf);
103 if (buf->length == buf->size)
104 /* there's no room in the buffer, return "success" */
105 return 1;
107 if (buf->length == 0)
108 /* the buffer is empty so defrag */
109 buf->begin = buf->end = buf->data;
111 len = min(buf->size - buf->length, buf->data + buf->size - buf->end);
113 #ifndef NO_WRITEV
114 /* assume there is a readv() if there is a writev() */
115 if (len == buf->size - buf->length) {
116 /* its not wrapped, use read() instead of readv() */
117 #endif
119 len = fd_read(fd, buf->end, len);
121 if (len <= 0)
122 return len;
124 buf->end += len;
125 buf->length += len;
127 if (buf->end == (buf->data + buf->size)) {
128 /* the buffer needs to be wrapped */
129 buf->end = buf->data;
130 #ifndef NO_WRITEV
132 } else {
133 /* the buffer is wrapped, use readv() */
134 struct iovec vec[2];
136 vec[0].iov_base = buf->end;
137 vec[0].iov_len = len;
138 vec[1].iov_base = buf->data;
139 vec[1].iov_len = buf->size - buf->length - len;
142 len = readv(fd, vec, 2);
143 while (len == -1 && errno == EINTR);
145 if (len <= 0)
146 return len;
148 buf->end += len;
149 if (buf->end >= (buf->data + buf->size))
150 buf->end -= buf->size;
152 buf->length += len;
154 #else
155 if (buf->length < buf->size) {
156 /* There's still more buffer space to read into. */
158 fd_set read_set;
159 int status;
160 int numFDs = fd + 1;
161 struct timeval timeOut;
163 FD_ZERO(&read_set);
164 FD_SET(fd, &read_set);
166 timeOut.tv_sec = 0;
167 timeOut.tv_usec = 0;
169 status = ap_select(numFDs, &read_set, NULL, NULL, &timeOut);
171 if (status < 0)
172 return status; /* error, errno is set */
174 if (status > 0 && FD_ISSET(fd, &read_set)) {
176 len = fd_read(fd, buf->end, buf->size - buf->length);
178 if (len <= 0)
179 return len;
181 buf->end += len;
182 buf->length += len;
186 #endif
187 return len; /* this may not contain the number of bytes read */
190 #ifdef WIN32
192 static int fd_write(SOCKET fd, char * buf, int len)
194 long bytes_sent;
196 // HACK - We don't know if its a pipe or socket..
197 if (!WriteFile((HANDLE) fd, (LPVOID) buf, len, (unsigned long *) &bytes_sent, NULL)) {
198 bytes_sent = send(fd, buf, len, 0);
199 if (bytes_sent == SOCKET_ERROR) {
200 errno = WSAGetLastError();
201 bytes_sent = -1;
204 return bytes_sent;
207 #else
209 static int fd_write(int fd, char * buf, int len)
211 int bytes_sent;
212 do {
213 bytes_sent = write(fd, buf, len);
214 } while (bytes_sent == -1 && errno == EINTR);
215 return bytes_sent;
218 #endif
220 /*******************************************************************************
221 * Write from the buffer to an open file descriptor.
223 * The caller should disable the default Apache SIGPIPE handler,
224 * otherwise a bad script could cause the request to abort appearing
225 * as though the client's fd caused it.
227 * Results:
228 * <0 if an error occured (bytes may or may not have been written)
229 * =0 if no bytes were written
230 * >0 successful write
232 #ifdef WIN32
233 int fcgi_buf_get_to_fd(Buffer *buf, SOCKET fd)
234 #else
235 int fcgi_buf_get_to_fd(Buffer *buf, int fd)
236 #endif
238 #ifdef WIN32
239 DWORD len;
240 #else
241 size_t len;
242 #endif
244 fcgi_buf_check(buf);
246 if (buf->length == 0)
247 return 0;
249 len = min(buf->length, buf->data + buf->size - buf->begin);
251 #ifndef NO_WRITEV
252 if (len == buf->length) {
253 /* the buffer is not wrapped, we don't need to use writev() */
254 #endif
256 len = fd_write(fd, buf->begin, len);
258 if (len <= 0)
259 goto Return;
261 buf->begin += len;
262 buf->length -= len;
264 if (buf->begin == buf->data + buf->size) {
265 /* the buffer needs to be wrapped */
266 buf->begin = buf->data;
268 #ifndef NO_WRITEV
270 } else {
271 /* the buffer is wrapped, use writev() */
272 struct iovec vec[2];
274 vec[0].iov_base = buf->begin;
275 vec[0].iov_len = len;
276 vec[1].iov_base = buf->data;
277 vec[1].iov_len = buf->length - len;
280 len = writev(fd, vec, 2);
281 while (len == -1 && errno == EINTR);
283 if (len <= 0)
284 goto Return;
286 buf->begin += len;
287 buf->length -= len;
289 if (buf->begin >= buf->data + buf->size)
290 buf->begin -= buf->size;
292 #else
293 if (buf->length > 0) {
294 /* there's still more data to write */
296 fd_set write_set;
297 int status;
298 int numFDs = fd + 1;
299 struct timeval timeOut;
301 FD_ZERO(&write_set);
302 FD_SET(fd, &write_set);
304 timeOut.tv_sec = 0;
305 timeOut.tv_usec = 0;
307 status = ap_select(numFDs, NULL, &write_set, NULL, &timeOut);
309 if (status < 0) {
310 len = status; /* error, errno is set */
311 goto Return;
314 if (status > 0 && FD_ISSET(fd, &write_set)) {
315 int len2;
317 len2 = fd_write(fd, buf->begin, buf->length);
319 if (len2 < 0) {
320 len = len2;
321 goto Return;
324 if (len2 > 0) {
325 buf->begin += len2;
326 buf->length -= len2;
327 len += len2;
332 #endif
334 Return:
335 if (buf->length == 0)
336 buf->begin = buf->end = buf->data;
338 return len;
341 /*******************************************************************************
342 * Return the data block start address and the length of the block.
344 void fcgi_buf_get_block_info(Buffer *buf, char **beginPtr, size_t *countPtr)
346 fcgi_buf_check(buf);
347 *beginPtr = buf->begin;
348 *countPtr = min(buf->length,
349 buf->data + buf->size - buf->begin);
352 /*******************************************************************************
353 * Throw away bytes from buffer.
355 void fcgi_buf_toss(Buffer *buf, size_t count)
357 fcgi_buf_check(buf);
358 ap_assert(count >= 0 && (int) count <= buf->length);
360 buf->length -= count;
361 buf->begin += count;
362 if(buf->begin >= buf->data + buf->size) {
363 buf->begin -= buf->size;
367 /*******************************************************************************
368 * Return the free data block start address and the length of the block.
370 void fcgi_buf_get_free_block_info(Buffer *buf, char **endPtr, size_t *countPtr)
372 fcgi_buf_check(buf);
373 *endPtr = buf->end;
374 *countPtr = min(buf->size - buf->length,
375 buf->data + buf->size - buf->end);
378 /*******************************************************************************
379 * Updates the buf to reflect recently added data.
381 void fcgi_buf_add_update(Buffer *buf, size_t count)
383 fcgi_buf_check(buf);
384 ap_assert(count >= 0 && (int) count <= BufferFree(buf));
386 buf->length += count;
387 buf->end += count;
388 if(buf->end >= buf->data + buf->size) {
389 buf->end -= buf->size;
392 fcgi_buf_check(buf);
395 /*******************************************************************************
396 * Adds a block of data to a buffer, returning the number of bytes added.
398 int fcgi_buf_add_block(Buffer *buf, char *data, size_t datalen)
400 char *end;
401 int copied = 0; /* Number of bytes actually copied. */
402 size_t canCopy; /* Number of bytes to copy in a given op. */
404 ap_assert(data != NULL);
405 if(datalen == 0) {
406 return 0;
409 ap_assert(datalen > 0);
410 fcgi_buf_check(buf);
411 end = buf->data + buf->size;
414 * Copy the first part of the data: from here to the end of the
415 * buffer, or the end of the data, whichever comes first.
417 datalen = min(BufferFree(buf), (int) datalen);
418 canCopy = min((int) datalen, end - buf->end);
419 memcpy(buf->end, data, canCopy);
420 buf->length += canCopy;
421 buf->end += canCopy;
422 copied += canCopy;
423 if (buf->end >= end) {
424 buf->end = buf->data;
426 datalen -= canCopy;
429 * If there's more to go, copy the second part starting from the
430 * beginning of the buffer.
432 if (datalen > 0) {
433 data += canCopy;
434 memcpy(buf->end, data, datalen);
435 buf->length += datalen;
436 buf->end += datalen;
437 copied += datalen;
439 return(copied);
442 /*******************************************************************************
443 * Add a string to a buffer, returning the number of bytes added.
445 int fcgi_buf_add_string(Buffer *buf, char *str)
447 return fcgi_buf_add_block(buf, str, strlen(str));
450 /*******************************************************************************
451 * Gets a data block from a buffer, returning the number of bytes copied.
453 int fcgi_buf_get_to_block(Buffer *buf, char *data, int datalen)
455 char *end;
456 int copied = 0; /* Number of bytes actually copied. */
457 size_t canCopy; /* Number of bytes to copy in a given op. */
459 ap_assert(data != NULL);
460 ap_assert(datalen > 0);
461 fcgi_buf_check(buf);
462 end = buf->data + buf->size;
465 * Copy the first part out of the buffer: from here to the end
466 * of the buffer, or all of the requested data.
468 canCopy = min(buf->length, datalen);
469 canCopy = min((int) canCopy, end - buf->begin);
470 memcpy(data, buf->begin, canCopy);
471 buf->length -= canCopy;
472 buf->begin += canCopy;
473 copied += canCopy;
474 if (buf->begin >= end) {
475 buf->begin = buf->data;
479 * If there's more to go, copy the second part starting from the
480 * beginning of the buffer.
482 if (copied < datalen && buf->length > 0) {
483 data += copied;
484 canCopy = min(buf->length, datalen - copied);
485 memcpy(data, buf->begin, canCopy);
486 buf->length -= canCopy;
487 buf->begin += canCopy;
488 copied += canCopy;
490 fcgi_buf_check(buf);
491 return(copied);
494 /*******************************************************************************
495 * Move 'len' bytes from 'src' buffer to 'dest' buffer. There must be at
496 * least 'len' bytes available in the source buffer and space for 'len'
497 * bytes in the destination buffer.
499 void fcgi_buf_get_to_buf(Buffer *dest, Buffer *src, int len)
501 char *dest_end, *src_begin;
502 size_t dest_len, src_len, move_len;
504 ap_assert(len > 0);
505 ap_assert(BufferLength(src) >= len);
506 ap_assert(BufferFree(dest) >= len);
508 fcgi_buf_check(src);
509 fcgi_buf_check(dest);
511 for (;;) {
512 if (len == 0)
513 return;
515 fcgi_buf_get_free_block_info(dest, &dest_end, &dest_len);
516 fcgi_buf_get_block_info(src, &src_begin, &src_len);
518 move_len = min(dest_len, src_len);
519 move_len = min((int) move_len, len);
521 if (move_len == 0)
522 return;
524 memcpy(dest_end, src_begin, move_len);
525 fcgi_buf_toss(src, move_len);
526 fcgi_buf_add_update(dest, move_len);
527 len -= move_len;
531 static void array_grow(array_header *arr, size_t n)
533 if (n <= 0)
534 return;
536 if ((int) (arr->nelts + n) > arr->nalloc) {
537 char *new_elts;
538 int new_nalloc = (arr->nalloc <= 0) ? n : arr->nelts + n;
540 new_elts = ap_pcalloc(arr->pool, arr->elt_size * new_nalloc);
541 memcpy(new_elts, arr->elts, arr->nelts * arr->elt_size);
543 arr->elts = new_elts;
544 arr->nalloc = new_nalloc;
548 static void array_cat_block(array_header *arr, void *block, size_t n)
550 array_grow(arr, n);
551 memcpy(arr->elts + arr->nelts * arr->elt_size, block, n * arr->elt_size);
552 arr->nelts += n;
555 /*----------------------------------------------------------------------
556 * Append "len" bytes from "buf" into "arr". Apache arrays are used
557 * whenever the data being handled is binary (may contain null chars).
559 void fcgi_buf_get_to_array(Buffer *buf, array_header *arr, size_t len)
561 int len1 = min(buf->length, buf->data + buf->size - buf->begin);
563 fcgi_buf_check(buf);
564 ap_assert(len > 0);
565 ap_assert((int) len <= BufferLength(buf));
567 array_grow(arr, len);
569 len1 = min(len1, (int) len);
570 array_cat_block(arr, buf->begin, len1);
572 if (len1 < (int) len)
573 array_cat_block(arr, buf->data, len - len1);
575 fcgi_buf_toss(buf, len);