Commit Diff


commit - 7ecc4542fefb0ad0b7babe055da2f9ac447a906b
commit + 3ff00eade6c3b17a852658c28502edbfc83ef25b
blob - f0de1b24e2bf33d38244b293dc7316561566af60
blob + f6cb81448f5778d7872b537fd6b90838285c99ee
--- gotwebd/fcgi.c
+++ gotwebd/fcgi.c
@@ -40,7 +40,7 @@ size_t	 fcgi_parse_record(uint8_t *, size_t, struct re
 void	 fcgi_parse_begin_request(uint8_t *, uint16_t, struct request *,
 	    uint16_t);
 void	 fcgi_parse_params(uint8_t *, uint16_t, struct request *, uint16_t);
-void	 fcgi_send_response(struct request *, int, const void *, size_t);
+int	 fcgi_send_response(struct request *, int, const void *, size_t);
 
 void	 dump_fcgi_record_header(const char *, struct fcgi_record_header *);
 void	 dump_fcgi_begin_request_body(const char *,
@@ -137,6 +137,12 @@ fcgi_parse_record(uint8_t *buf, size_t n, struct reque
 		break;
 	case FCGI_STDIN:
 	case FCGI_ABORT_REQUEST:
+		if (c->sock->client_status != CLIENT_DISCONNECT &&
+		    c->outbuf_len != 0) {
+			fcgi_send_response(c, FCGI_STDOUT, c->outbuf,
+			    c->outbuf_len);
+		}
+
 		fcgi_create_end_record(c);
 		fcgi_cleanup_request(c);
 		return 0;
@@ -304,13 +310,39 @@ fcgi_timeout(int fd, short events, void *arg)
 int
 fcgi_gen_binary_response(struct request *c, const uint8_t *data, int len)
 {
+	int r;
+
 	if (c->sock->client_status == CLIENT_DISCONNECT)
 		return -1;
 
 	if (data == NULL || len == 0)
 		return 0;
 
-	fcgi_send_response(c, FCGI_STDOUT, data, len);
+	/*
+	 * special case: send big replies -like blobs- directly
+	 * without copying.
+	 */
+	if (len > sizeof(c->outbuf)) {
+		if (c->outbuf_len > 0) {
+			fcgi_send_response(c, FCGI_STDOUT,
+			    c->outbuf, c->outbuf_len);
+			c->outbuf_len = 0;
+		}
+		return fcgi_send_response(c, FCGI_STDOUT, data, len);
+	}
+
+	if (len < sizeof(c->outbuf) - c->outbuf_len) {
+		memcpy(c->outbuf + c->outbuf_len, data, len);
+		c->outbuf_len += len;
+		return 0;
+	}
+
+	r = fcgi_send_response(c, FCGI_STDOUT, c->outbuf, c->outbuf_len);
+	if (r == -1)
+		return -1;
+
+	memcpy(c->outbuf, data, len);
+	c->outbuf_len = len;
 	return 0;
 }
 
@@ -322,7 +354,7 @@ fcgi_gen_response(struct request *c, const char *data)
 	return fcgi_gen_binary_response(c, data, strlen(data));
 }
 
-static void
+static int
 send_response(struct request *c, int type, const uint8_t *data,
     size_t len)
 {
@@ -382,7 +414,7 @@ send_response(struct request *c, int type, const uint8
 			}
 			log_warn("%s: write failure", __func__);
 			c->sock->client_status = CLIENT_DISCONNECT;
-			break;
+			return -1;
 		}
 
 		if (nw != tot)
@@ -400,25 +432,29 @@ send_response(struct request *c, int type, const uint8
 			iov[i].iov_len = 0;
 		}
 	}
+
+	return 0;
 }
 
-void
+int
 fcgi_send_response(struct request *c, int type, const void *data,
     size_t len)
 {
+	if (c->sock->client_status == CLIENT_DISCONNECT)
+		return -1;
+
 	while (len > FCGI_CONTENT_SIZE) {
-		send_response(c, type, data, len);
-		if (c->sock->client_status == CLIENT_DISCONNECT)
-			return;
+		if (send_response(c, type, data, len) == -1)
+			return -1;
 
 		data += FCGI_CONTENT_SIZE;
 		len -= FCGI_CONTENT_SIZE;
 	}
 
 	if (len == 0)
-		return;
+		return 0;
 
-	send_response(c, type, data, len);
+	return send_response(c, type, data, len);
 }
 
 void
blob - aafdb73fcd040caf5d1182eb5bd173b3e7bd6a95
blob + b58b1e7be0421dac9ff6c9717bacb59208ad1bbb
--- gotwebd/gotwebd.h
+++ gotwebd/gotwebd.h
@@ -39,6 +39,7 @@
 
 #define GOTWEBD_USER		 "www"
 
+#define GOTWEBD_CACHESIZE	 1024
 #define GOTWEBD_MAXCLIENTS	 1024
 #define GOTWEBD_MAXTEXT		 511
 #define GOTWEBD_MAXNAME		 64
@@ -212,6 +213,9 @@ struct request {
 	uint8_t				 buf[FCGI_RECORD_SIZE];
 	size_t				 buf_pos;
 	size_t				 buf_len;
+
+	uint8_t				 outbuf[GOTWEBD_CACHESIZE];
+	size_t				 outbuf_len;
 
 	char				 querystring[MAX_QUERYSTRING];
 	char				 http_host[GOTWEBD_MAXTEXT];