2 * $Id: fcgi_buf.c,v 1.13 2001/12/15 14:30:47 robs Exp $
8 #pragma warning( disable : 4127 )
11 /*******************************************************************************
12 * Check buffer consistency with assertions.
14 void fcgi_buf_check(Buffer
*buf
)
16 ap_assert(buf
->size
> 0);
17 ap_assert(buf
->length
>= 0);
18 ap_assert(buf
->length
<= buf
->size
);
20 ap_assert(buf
->begin
>= buf
->data
);
21 ap_assert(buf
->begin
< buf
->data
+ buf
->size
);
22 ap_assert(buf
->end
>= buf
->data
);
23 ap_assert(buf
->end
< buf
->data
+ buf
->size
);
25 ap_assert(((buf
->end
- buf
->begin
+ buf
->size
) % buf
->size
)
26 == (buf
->length
% buf
->size
));
29 /*******************************************************************************
30 * Reset buffer, losing any data that's in it.
32 void fcgi_buf_reset(Buffer
*buf
)
35 buf
->begin
= buf
->end
= buf
->data
;
38 /*******************************************************************************
39 * Allocate and intialize a new buffer of the specified size.
41 Buffer
*fcgi_buf_new(pool
*p
, int size
)
45 buf
= (Buffer
*)ap_pcalloc(p
, sizeof(Buffer
) + size
);
53 static int fd_read(SOCKET fd
, char *buf
, int len
)
59 // HACK - we don't know if its a pipe or socket..
60 if (ReadFile((HANDLE
) fd
, buf
, len
, &bytes_read
, NULL
))
62 return (int) bytes_read
;
66 int rv
= GetLastError();
68 if (rv
== ERROR_PIPE_NOT_CONNECTED
)
72 else if (rv
== ERROR_INVALID_PARAMETER
)
74 // Then it must be a real socket
76 SetLastError(ERROR_SUCCESS
);
78 rv
= recv(fd
, buf
, len
, 0);
79 if (rv
== SOCKET_ERROR
)
81 errno
= WSAGetLastError();
97 static int fd_read(int fd
, char * buf
, int len
)
104 bytes_read
= read(fd
, buf
, len
);
105 } while (bytes_read
== -1 && errno
== EINTR
);
111 /*******************************************************************************
112 * Read from an open file descriptor into buffer.
114 * The caller should disable the default Apache SIGPIPE handler,
115 * otherwise a bad script could cause the request to abort and appear
116 * as though the client's fd caused it.
119 * <0 error, errno is set
121 * >0 successful read or no room in buffer (NOT # of bytes read)
124 int fcgi_buf_add_fd(Buffer
*buf
, SOCKET fd
)
126 int fcgi_buf_add_fd(Buffer
*buf
, int fd
)
133 if (buf
->length
== buf
->size
)
134 /* there's no room in the buffer, return "success" */
137 if (buf
->length
== 0)
138 /* the buffer is empty so defrag */
139 buf
->begin
= buf
->end
= buf
->data
;
141 len
= min(buf
->size
- buf
->length
, buf
->data
+ buf
->size
- buf
->end
);
144 /* assume there is a readv() if there is a writev() */
145 if (len
== buf
->size
- buf
->length
) {
146 /* its not wrapped, use read() instead of readv() */
149 len
= fd_read(fd
, buf
->end
, len
);
157 if (buf
->end
== (buf
->data
+ buf
->size
)) {
158 /* the buffer needs to be wrapped */
159 buf
->end
= buf
->data
;
163 /* the buffer is wrapped, use readv() */
166 vec
[0].iov_base
= buf
->end
;
167 vec
[0].iov_len
= len
;
168 vec
[1].iov_base
= buf
->data
;
169 vec
[1].iov_len
= buf
->size
- buf
->length
- len
;
172 ap_assert(vec
[1].iov_len
);
175 len
= readv(fd
, vec
, 2);
176 while (len
== -1 && errno
== EINTR
);
182 if (buf
->end
>= (buf
->data
+ buf
->size
))
183 buf
->end
-= buf
->size
;
189 if (buf
->length
< buf
->size
) {
190 /* There's still more buffer space to read into. */
195 struct timeval timeOut
;
198 FD_SET(fd
, &read_set
);
203 status
= ap_select(numFDs
, &read_set
, NULL
, NULL
, &timeOut
);
208 if (WSAGetLastError() == WSAENOTSOCK
)
211 if (PeekNamedPipe((HANDLE
) fd
, NULL
, 0, NULL
, &bytesavail
, NULL
))
215 len
= fd_read(fd
, buf
->end
, buf
->size
- buf
->length
);
227 return status
; /* error, errno is set */
230 if (status
> 0 && FD_ISSET(fd
, &read_set
)) {
232 len
= fd_read(fd
, buf
->end
, buf
->size
- buf
->length
);
244 return len
; /* this may not contain the number of bytes read */
249 static int fd_write(SOCKET fd
, char * buf
, int len
)
253 // HACK - We don't know if its a pipe or socket..
254 if (WriteFile((HANDLE
) fd
, buf
, len
, &bytes_sent
, NULL
))
256 return (int) bytes_sent
;
260 int rv
= GetLastError();
262 if (rv
== ERROR_INVALID_PARAMETER
)
264 // Then it must be a real socket..
266 SetLastError(ERROR_SUCCESS
);
268 rv
= send(fd
, buf
, len
, 0);
270 if (rv
== SOCKET_ERROR
)
272 rv
= WSAGetLastError();
273 if (rv
== WSAEWOULDBLOCK
)
286 else if (rv
== WSAEWOULDBLOCK
)
300 static int fd_write(int fd
, char * buf
, int len
)
305 bytes_sent
= write(fd
, buf
, len
);
308 if (bytes_sent
== -1 && errno
== EWOULDBLOCK
) {
312 } while (bytes_sent
== -1 && errno
== EINTR
);
319 /*******************************************************************************
320 * Write from the buffer to an open file descriptor.
322 * The caller should disable the default Apache SIGPIPE handler,
323 * otherwise a bad script could cause the request to abort appearing
324 * as though the client's fd caused it.
327 * <0 if an error occured (bytes may or may not have been written)
328 * =0 if no bytes were written
329 * >0 successful write
332 int fcgi_buf_get_to_fd(Buffer
*buf
, SOCKET fd
)
334 int fcgi_buf_get_to_fd(Buffer
*buf
, int fd
)
341 if (buf
->length
== 0)
344 len
= min(buf
->length
, buf
->data
+ buf
->size
- buf
->begin
);
347 if (len
== buf
->length
) {
348 /* the buffer is not wrapped, we don't need to use writev() */
351 len
= fd_write(fd
, buf
->begin
, len
);
359 if (buf
->begin
== buf
->data
+ buf
->size
) {
360 /* the buffer needs to be wrapped */
361 buf
->begin
= buf
->data
;
366 /* the buffer is wrapped, use writev() */
369 vec
[0].iov_base
= buf
->begin
;
370 vec
[0].iov_len
= len
;
371 vec
[1].iov_base
= buf
->data
;
372 vec
[1].iov_len
= buf
->length
- len
;
375 len
= writev(fd
, vec
, 2);
376 while (len
== -1 && errno
== EINTR
);
384 if (buf
->begin
>= buf
->data
+ buf
->size
)
385 buf
->begin
-= buf
->size
;
388 if (buf
->length
> 0) {
389 /* there's still more data to write */
394 struct timeval timeOut
;
397 FD_SET(fd
, &write_set
);
402 status
= ap_select(numFDs
, NULL
, &write_set
, NULL
, &timeOut
);
405 len
= status
; /* error, errno is set */
409 if (status
> 0 && FD_ISSET(fd
, &write_set
)) {
412 len2
= fd_write(fd
, buf
->begin
, buf
->length
);
430 if (buf
->length
== 0)
431 buf
->begin
= buf
->end
= buf
->data
;
436 /*******************************************************************************
437 * Return the data block start address and the length of the block.
439 void fcgi_buf_get_block_info(Buffer
*buf
, char **beginPtr
, int *countPtr
)
443 *beginPtr
= buf
->begin
;
444 *countPtr
= min(buf
->length
, buf
->data
+ buf
->size
- buf
->begin
);
447 /*******************************************************************************
448 * Throw away bytes from buffer.
450 void fcgi_buf_toss(Buffer
*buf
, int count
)
453 ap_assert(count
>= 0);
454 ap_assert(count
<= buf
->length
);
456 buf
->length
-= count
;
458 if(buf
->begin
>= buf
->data
+ buf
->size
) {
459 buf
->begin
-= buf
->size
;
463 /*******************************************************************************
464 * Return the free data block start address and the length of the block.
466 void fcgi_buf_get_free_block_info(Buffer
*buf
, char **endPtr
, int *countPtr
)
471 *countPtr
= min(buf
->size
- buf
->length
,
472 buf
->data
+ buf
->size
- buf
->end
);
475 /*******************************************************************************
476 * Updates the buf to reflect recently added data.
478 void fcgi_buf_add_update(Buffer
*buf
, int count
)
481 ap_assert(count
>= 0);
482 ap_assert(count
<= BufferFree(buf
));
484 buf
->length
+= count
;
486 if(buf
->end
>= buf
->data
+ buf
->size
) {
487 buf
->end
-= buf
->size
;
493 /*******************************************************************************
494 * Adds a block of data to a buffer, returning the number of bytes added.
496 int fcgi_buf_add_block(Buffer
*buf
, char *data
, int datalen
)
499 int copied
= 0; /* Number of bytes actually copied. */
500 int canCopy
; /* Number of bytes to copy in a given op. */
502 ap_assert(data
!= NULL
);
503 ap_assert(datalen
>= 0);
509 ap_assert(datalen
> 0);
511 end
= buf
->data
+ buf
->size
;
514 * Copy the first part of the data: from here to the end of the
515 * buffer, or the end of the data, whichever comes first.
517 datalen
= min(BufferFree(buf
), datalen
);
518 canCopy
= min(datalen
, end
- buf
->end
);
519 memcpy(buf
->end
, data
, canCopy
);
520 buf
->length
+= canCopy
;
523 if (buf
->end
>= end
) {
524 buf
->end
= buf
->data
;
529 * If there's more to go, copy the second part starting from the
530 * beginning of the buffer.
534 memcpy(buf
->end
, data
, datalen
);
535 buf
->length
+= datalen
;
542 /*******************************************************************************
543 * Add a string to a buffer, returning the number of bytes added.
545 int fcgi_buf_add_string(Buffer
*buf
, char *str
)
547 return fcgi_buf_add_block(buf
, str
, strlen(str
));
550 /*******************************************************************************
551 * Gets a data block from a buffer, returning the number of bytes copied.
553 int fcgi_buf_get_to_block(Buffer
*buf
, char *data
, int datalen
)
556 int copied
= 0; /* Number of bytes actually copied. */
557 int canCopy
; /* Number of bytes to copy in a given op. */
559 ap_assert(data
!= NULL
);
560 ap_assert(datalen
> 0);
563 end
= buf
->data
+ buf
->size
;
566 * Copy the first part out of the buffer: from here to the end
567 * of the buffer, or all of the requested data.
569 canCopy
= min(buf
->length
, datalen
);
570 canCopy
= min(canCopy
, end
- buf
->begin
);
572 memcpy(data
, buf
->begin
, canCopy
);
574 buf
->length
-= canCopy
;
575 buf
->begin
+= canCopy
;
577 if (buf
->begin
>= end
) {
578 buf
->begin
= buf
->data
;
582 * If there's more to go, copy the second part starting from the
583 * beginning of the buffer.
585 if (copied
< datalen
&& buf
->length
> 0) {
587 canCopy
= min(buf
->length
, datalen
- copied
);
589 memcpy(data
, buf
->begin
, canCopy
);
591 buf
->length
-= canCopy
;
592 buf
->begin
+= canCopy
;
600 /*******************************************************************************
601 * Move 'len' bytes from 'src' buffer to 'dest' buffer. There must be at
602 * least 'len' bytes available in the source buffer and space for 'len'
603 * bytes in the destination buffer.
605 void fcgi_buf_get_to_buf(Buffer
*dest
, Buffer
*src
, int len
)
607 char *dest_end
, *src_begin
;
608 int dest_len
, src_len
, move_len
;
611 ap_assert(BufferLength(src
) >= len
);
612 ap_assert(BufferFree(dest
) >= len
);
615 fcgi_buf_check(dest
);
621 fcgi_buf_get_free_block_info(dest
, &dest_end
, &dest_len
);
622 fcgi_buf_get_block_info(src
, &src_begin
, &src_len
);
624 move_len
= min(dest_len
, src_len
);
625 move_len
= min(move_len
, len
);
630 memcpy(dest_end
, src_begin
, move_len
);
631 fcgi_buf_toss(src
, move_len
);
632 fcgi_buf_add_update(dest
, move_len
);
637 static void array_grow(array_header
*arr
, int n
)
642 if (arr
->nelts
+ n
> arr
->nalloc
) {
644 int new_nalloc
= (arr
->nalloc
<= 0) ? n
: arr
->nelts
+ n
;
646 new_elts
= ap_pcalloc(arr
->pool
, arr
->elt_size
* new_nalloc
);
647 memcpy(new_elts
, arr
->elts
, arr
->nelts
* arr
->elt_size
);
649 arr
->elts
= new_elts
;
650 arr
->nalloc
= new_nalloc
;
654 static void array_cat_block(array_header
*arr
, void *block
, int n
)
657 memcpy(arr
->elts
+ arr
->nelts
* arr
->elt_size
, block
, n
* arr
->elt_size
);
661 /*----------------------------------------------------------------------
662 * Append "len" bytes from "buf" into "arr". Apache arrays are used
663 * whenever the data being handled is binary (may contain null chars).
665 void fcgi_buf_get_to_array(Buffer
*buf
, array_header
*arr
, int len
)
667 int len1
= min(buf
->length
, buf
->data
+ buf
->size
- buf
->begin
);
671 ap_assert(len
<= BufferLength(buf
));
673 array_grow(arr
, len
);
675 len1
= min(len1
, len
);
676 array_cat_block(arr
, buf
->begin
, len1
);
679 array_cat_block(arr
, buf
->data
, len
- len1
);
681 fcgi_buf_toss(buf
, len
);