handlers can read response before sending req body (fixes #131, #2566)
[lighttpd.git] / src / network_writev.c
blob28edf589930abea00ebdfab5ed8e9c06112c5378
1 #include "first.h"
3 #include "network_backends.h"
5 #if defined(USE_WRITEV)
7 #include "network.h"
8 #include "log.h"
10 #if defined(HAVE_SYS_UIO_H)
11 # include <sys/uio.h>
12 #endif
14 #include <errno.h>
15 #include <string.h>
16 #include <stdlib.h>
18 #if defined(UIO_MAXIOV)
19 # define SYS_MAX_CHUNKS UIO_MAXIOV
20 #elif defined(IOV_MAX)
21 /* new name for UIO_MAXIOV since IEEE Std 1003.1-2001 */
22 # define SYS_MAX_CHUNKS IOV_MAX
23 #elif defined(_XOPEN_IOV_MAX)
24 /* minimum value for sysconf(_SC_IOV_MAX); posix requires this to be at least 16, which is good enough - no need to call sysconf() */
25 # define SYS_MAX_CHUNKS _XOPEN_IOV_MAX
26 #else
27 # error neither UIO_MAXIOV nor IOV_MAX nor _XOPEN_IOV_MAX are defined
28 #endif
30 /* allocate iovec[MAX_CHUNKS] on stack, so pick a sane limit:
31 * - each entry will use 1 pointer + 1 size_t
32 * - 32 chunks -> 256 / 512 bytes (32-bit/64-bit pointers)
34 #define STACK_MAX_ALLOC_CHUNKS 32
35 #if SYS_MAX_CHUNKS > STACK_MAX_ALLOC_CHUNKS
36 # define MAX_CHUNKS STACK_MAX_ALLOC_CHUNKS
37 #else
38 # define MAX_CHUNKS SYS_MAX_CHUNKS
39 #endif
41 int network_writev_mem_chunks(server *srv, connection *con, int fd, chunkqueue *cq, off_t *p_max_bytes) {
42 struct iovec chunks[MAX_CHUNKS];
43 size_t num_chunks;
44 off_t max_bytes = *p_max_bytes;
45 off_t toSend;
46 ssize_t r;
47 UNUSED(con);
49 force_assert(NULL != cq->first);
50 force_assert(MEM_CHUNK == cq->first->type);
53 chunk const *c;
55 toSend = 0;
56 num_chunks = 0;
57 for (c = cq->first; NULL != c && MEM_CHUNK == c->type && num_chunks < MAX_CHUNKS && toSend < max_bytes; c = c->next) {
58 size_t c_len;
60 force_assert(c->offset >= 0 && c->offset <= (off_t)buffer_string_length(c->mem));
61 c_len = buffer_string_length(c->mem) - c->offset;
62 if (c_len > 0) {
63 toSend += c_len;
65 chunks[num_chunks].iov_base = c->mem->ptr + c->offset;
66 chunks[num_chunks].iov_len = c_len;
68 ++num_chunks;
73 if (0 == num_chunks) {
74 chunkqueue_remove_finished_chunks(cq);
75 return 0;
78 r = writev(fd, chunks, num_chunks);
80 if (r < 0) switch (errno) {
81 case EAGAIN:
82 case EINTR:
83 break;
84 case EPIPE:
85 case ECONNRESET:
86 return -2;
87 default:
88 log_error_write(srv, __FILE__, __LINE__, "ssd",
89 "writev failed:", strerror(errno), fd);
90 return -1;
93 if (r >= 0) {
94 *p_max_bytes -= r;
95 chunkqueue_mark_written(cq, r);
98 return (r > 0 && r == toSend) ? 0 : -3;
101 #endif /* USE_WRITEV */
103 int network_write_chunkqueue_writev(server *srv, connection *con, int fd, chunkqueue *cq, off_t max_bytes) {
104 while (max_bytes > 0 && NULL != cq->first) {
105 int r = -1;
107 switch (cq->first->type) {
108 case MEM_CHUNK:
109 r = network_writev_mem_chunks(srv, con, fd, cq, &max_bytes);
110 break;
111 case FILE_CHUNK:
112 r = network_write_file_chunk_mmap(srv, con, fd, cq, &max_bytes);
113 break;
116 if (-3 == r) return 0;
117 if (0 != r) return r;
120 return 0;