You are viewing a plain text version of this content. The canonical link for it is here.
Posted to test-cvs@httpd.apache.org by je...@apache.org on 2002/03/27 02:41:52 UTC
cvs commit: httpd-test/flood CHANGES flood_profile.h flood_socket_keepalive.c
jerenkrantz 02/03/26 17:41:52
Modified: flood CHANGES flood_profile.h flood_socket_keepalive.c
Log:
First cut (not complete) of T-E: Chunked support.
Doesn't read all chunks just yet. More debugging is needed. But, it
doesn't segfault in my tests.
Revision Changes Path
1.35 +2 -0 httpd-test/flood/CHANGES
Index: CHANGES
===================================================================
RCS file: /home/cvs/httpd-test/flood/CHANGES,v
retrieving revision 1.34
retrieving revision 1.35
diff -u -r1.34 -r1.35
--- CHANGES 26 Mar 2002 02:36:04 -0000 1.34
+++ CHANGES 27 Mar 2002 01:41:52 -0000 1.35
@@ -1,5 +1,7 @@
Changes since milestone-03:
+* Add chunked support. [Justin Erenkrantz]
+
* Add detection of CAPATH variable for RedHat installs.
[Justin Erenkrantz]
1.10 +3 -0 httpd-test/flood/flood_profile.h
Index: flood_profile.h
===================================================================
RCS file: /home/cvs/httpd-test/flood/flood_profile.h,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -r1.9 -r1.10
--- flood_profile.h 20 Aug 2001 19:05:16 -0000 1.9
+++ flood_profile.h 27 Mar 2002 01:41:52 -0000 1.10
@@ -132,6 +132,9 @@
struct response_t {
/* a boolean */
int keepalive;
+ /* a boolean */
+ int chunked;
+ char *chunk;
/* Raw buffer connection
* FIXME: apr_bucket_t? */
1.10 +267 -48 httpd-test/flood/flood_socket_keepalive.c
Index: flood_socket_keepalive.c
===================================================================
RCS file: /home/cvs/httpd-test/flood/flood_socket_keepalive.c,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -r1.9 -r1.10
--- flood_socket_keepalive.c 4 Dec 2001 09:10:34 -0000 1.9
+++ flood_socket_keepalive.c 27 Mar 2002 01:41:52 -0000 1.10
@@ -54,12 +54,21 @@
#include <string.h>
#include <stdlib.h>
+#include <assert.h>
#include "config.h"
#include "flood_net.h"
#include "flood_net_ssl.h"
#include "flood_socket_keepalive.h"
+#define ksock_read_socket(ksock, buf, lenaddr) \
+ ksock->ssl ? ssl_read_socket(ksock->s, buf, lenaddr) : \
+ read_socket(ksock->s, buf, lenaddr)
+
+#define ksock_write_socket(ksock, req) \
+ ksock->ssl ? ssl_write_socket(ksock->s, req) : \
+ write_socket(ksock->s, req)
+
typedef struct {
void *s;
apr_pollfd_t *p;
@@ -135,6 +144,148 @@
write_socket(ksock->s, req);
}
+static long keepalive_read_chunk_size(char *begin_chunk)
+{
+ char chunk[17], *end_chunk;
+ long chunk_length;
+
+ /* FIXME: Handle chunk-extension */
+ end_chunk = strstr(begin_chunk, CRLF);
+
+ if (end_chunk && end_chunk - begin_chunk < 16)
+ {
+ strncpy(chunk, begin_chunk, end_chunk - begin_chunk);
+ chunk[end_chunk-begin_chunk] = '\0';
+ /* Chunks are base-16 */
+ chunk_length = strtol(chunk, &end_chunk, 16);
+ if (*end_chunk == '\0')
+ return chunk_length;
+ }
+
+ return 0;
+}
+
+static apr_status_t keepalive_read_chunk(response_t *resp,
+ keepalive_socket_t *sock,
+ int chunk_length,
+ char **bp, int blen)
+{
+ apr_status_t status = APR_SUCCESS;
+ int old_length;
+
+ if (!chunk_length) {
+ return status;
+ }
+
+ if (!resp->chunk || !*resp->chunk) {
+ chunk_length = 0;
+ }
+
+ if (chunk_length < 0) {
+ old_length = chunk_length;
+ chunk_length = 0;
+ }
+
+ do {
+ /* Sentinel value */
+ int i = 0;
+ char *start_chunk, *end_chunk, *b;
+
+ /* Always reset the b. */
+ b = *bp;
+
+ /* Time to read the next chunk size. At this point,
+ * we should be ready to read a CRLF followed by
+ * a line that contains the next chunk size.
+ */
+ while (!chunk_length)
+ {
+ /* We are reading the next chunk and see a CRLF. */
+ if (i >= 2 && b[0] == '\r' && b[1] == '\n') {
+ b += 2;
+ i -= 2;
+ }
+
+ /* Do we need to read? */
+ /* FIXME: We *could* miss a chunk. */
+ if (!i)
+ {
+ /* Read as much as we can. */
+ i = blen - 1;
+ b = *bp;
+ status = ksock_read_socket(sock, b, &i);
+ if (status != APR_SUCCESS) {
+ return status;
+ }
+
+ /* We got caught in the middle of a chunk last time. */
+ if (old_length < 0) {
+ b -= old_length;
+ i += old_length;
+ old_length = 0;
+ }
+ /* We are reading the next chunk and see a CRLF. */
+ if (i >= 2 && b[0] == '\r' && b[1] == '\n') {
+ b += 2;
+ i -= 2;
+ }
+ }
+
+ start_chunk = b;
+ chunk_length = keepalive_read_chunk_size(start_chunk);
+
+ /* last-chunk */
+ if (!chunk_length)
+ {
+ /* See if we already read the trailer and final CRLF */
+ end_chunk = strstr(b, CRLF CRLF);
+ if (!end_chunk)
+ {
+ /* Read as much as we can. */
+ i = blen - 1;
+ b = *bp;
+ status = ksock_read_socket(sock, b, &i);
+ if (status == APR_EGENERAL || status == APR_EOF ||
+ status == APR_TIMEUP)
+ return status;
+ }
+
+ /* FIXME: If we add pipelining, we need to put
+ * the remainder back so that it can be read. */
+ i -= end_chunk - b + 4;
+
+ return APR_SUCCESS;
+ }
+
+ /* If this fails, we're very unlikely to have read a chunk! */
+ end_chunk = strstr(start_chunk, CRLF) + 2;
+ i -= end_chunk - b;
+
+ /* Oh no, we read more than one chunk this go-around! */
+ if (chunk_length <= i) {
+ b += chunk_length + (end_chunk - b);
+ i -= chunk_length;
+ chunk_length = 0;
+ }
+ else
+ chunk_length -= i;
+ }
+
+ if (chunk_length > blen)
+ i = blen;
+ else
+ i = chunk_length;
+
+ status = ksock_read_socket(sock, b, &i);
+
+ chunk_length -= i;
+ }
+ while (status != APR_EGENERAL && status != APR_EOF &&
+ status != APR_TIMEUP);
+
+ return APR_SUCCESS;
+}
+
static apr_status_t keepalive_load_resp(response_t *resp,
keepalive_socket_t *sock,
apr_size_t remaining, apr_pool_t *pool)
@@ -172,8 +323,7 @@
i = remaining;
}
- status = sock->ssl ? ssl_read_socket(sock->s, b, &i) :
- read_socket(sock->s, b, &i);
+ status = ksock_read_socket(sock, b, &i);
if (resp->rbufsize + i > currentalloc)
{
/* You can think why this always work. */
@@ -189,7 +339,8 @@
cp += i;
remaining -= i;
}
- while (status != APR_EGENERAL && status != APR_EOF && status != APR_TIMEUP && (!remain || remaining));
+ while (status != APR_EGENERAL && status != APR_EOF &&
+ status != APR_TIMEUP && (!remain || remaining));
return status;
}
@@ -200,73 +351,137 @@
apr_status_t keepalive_recv_resp(response_t **resp, socket_t *sock, apr_pool_t *pool)
{
keepalive_socket_t *ksock = (keepalive_socket_t *)sock;
- char b[MAX_DOC_LENGTH], *cl, *ecl, cls[17];
+ char *cl, *ecl, cls[17];
int i;
response_t *new_resp;
apr_status_t status;
- long content_length = 0;
+ long content_length = 0, chunk_length;
new_resp = apr_pcalloc(pool, sizeof(response_t));
new_resp->rbuftype = POOL;
new_resp->rbufsize = MAX_DOC_LENGTH - 1;
- new_resp->rbuf = apr_pcalloc(pool, new_resp->rbufsize);
+ new_resp->rbuf = apr_palloc(pool, new_resp->rbufsize);
- status = ksock->ssl ?
- ssl_read_socket(ksock->s, new_resp->rbuf, &new_resp->rbufsize) :
- read_socket(ksock->s, new_resp->rbuf, &new_resp->rbufsize);
+ status = ksock_read_socket(ksock, new_resp->rbuf, &new_resp->rbufsize);
if (status != APR_SUCCESS && status != APR_EOF) {
return status;
}
- /* FIXME: Deal with chunking, too */
/* FIXME: Assume we got the full header for now. */
- /* If this exists, we aren't keepalive anymore. */
- cl = strstr(new_resp->rbuf, "Connection: Close");
+ /* FIXME: Make case-insensitive */
+ cl = strstr(new_resp->rbuf, "Transfer-Encoding: Chunked" CRLF);
if (cl)
- new_resp->keepalive = 0;
- else
{
- new_resp->keepalive = 1;
-
- cl = strstr(new_resp->rbuf, "Content-Length: ");
- if (!cl)
+ new_resp->chunked = 1;
+ /* Find where headers ended */
+ cl = strstr(new_resp->rbuf, CRLF CRLF);
+ if (cl)
{
- /* Netscape sends this. It is technically correct as the header
- * may be mixed-case - we should be case-insensitive. But,
- * that gets mighty expensive. */
- cl = strstr(new_resp->rbuf, "Content-length: ");
- if (!cl)
- new_resp->keepalive = 0;
- }
+ char *buf = NULL;
+ int bufsize, remaining;
+ /* Skip over the CRLF chars */
+ cl += 4;
+ if (!*cl) {
+ /* We got only the headers in our first read. */
+ assert(ksock->wantresponse == 0);
+ bufsize = MAX_DOC_LENGTH - 1;
+ buf = apr_palloc(pool, bufsize);
+ status = ksock_read_socket(ksock, buf, &bufsize);
+ if (status != APR_SUCCESS && status != APR_EOF) {
+ return status;
+ }
+ cl = buf;
+ }
+ do {
+ if (new_resp->chunk) {
+ /* Check if we're unlucky to not have the CRLF ending. */
+ if (chunk_length + 2 <= remaining) {
+ new_resp->chunk += chunk_length + 2;
+ }
+ else {
+ /* Special value */
+ chunk_length = -(remaining - chunk_length);
+ remaining = 0;
+ break;
+ }
+ }
+ else {
+ new_resp->chunk = cl;
+ }
+
+ if (*new_resp->chunk) {
+ chunk_length = keepalive_read_chunk_size(new_resp->chunk);
+ /* Search for the beginning of the chunk. */
+ new_resp->chunk = strstr(new_resp->chunk, CRLF) + 2;
+ if (!buf) {
+ remaining = new_resp->rbufsize -
+ (int)(new_resp->chunk -
+ (char*)new_resp->rbuf);
+ }
+ else {
+ remaining = bufsize - (int)(new_resp->chunk - buf);
+ }
+ }
+ else {
+ remaining = 0;
+ }
+ }
+ while (remaining > chunk_length);
+
+ chunk_length -= remaining;
+ }
+ }
+ else
+ {
+ /* If this exists, we aren't keepalive anymore. */
+ cl = strstr(new_resp->rbuf, "Connection: Close" CRLF);
if (cl)
+ new_resp->keepalive = 0;
+ else
{
- cl += sizeof("Content-Length: ") - 1;
- ecl = strstr(cl, CRLF);
- if (ecl && ecl - cl < 16)
+ new_resp->keepalive = 1;
+
+ cl = strstr(new_resp->rbuf, "Content-Length: ");
+ if (!cl)
{
- strncpy(cls, cl, ecl - cl);
- cls[ecl-cl] = '\0';
- content_length = strtol(cls, &ecl, 10);
- if (*ecl != '\0')
+ /* Netscape sends this. It is technically correct as the header
+ * may be mixed-case - we should be case-insensitive. But,
+ * that gets mighty expensive. */
+ cl = strstr(new_resp->rbuf, "Content-length: ");
+ if (!cl)
new_resp->keepalive = 0;
}
- }
- if (new_resp->keepalive)
- {
- /* Find where we ended */
- ecl = strstr(new_resp->rbuf, CRLF CRLF);
+ if (cl)
+ {
+ cl += sizeof("Content-Length: ") - 1;
+ ecl = strstr(cl, CRLF);
+ if (ecl && ecl - cl < 16)
+ {
+ strncpy(cls, cl, ecl - cl);
+ cls[ecl-cl] = '\0';
+ content_length = strtol(cls, &ecl, 10);
+ if (*ecl != '\0')
+ new_resp->keepalive = 0;
+ }
+ }
- /* We didn't get full headers. Crap. */
- if (!ecl)
- new_resp->keepalive = 0;
+ if (new_resp->keepalive)
{
- ecl += sizeof(CRLF CRLF) - 1;
- content_length -= new_resp->rbufsize - (ecl - (char*)new_resp->rbuf);
- }
+ /* Find where we ended */
+ ecl = strstr(new_resp->rbuf, CRLF CRLF);
+
+ /* We didn't get full headers. Crap. */
+ if (!ecl)
+ new_resp->keepalive = 0;
+ {
+ ecl += sizeof(CRLF CRLF) - 1;
+ content_length -= new_resp->rbufsize - (ecl - (char*)new_resp->rbuf);
+ }
+ }
}
}
@@ -279,7 +494,13 @@
}
else
{
- if (new_resp->keepalive)
+ char *b = apr_palloc(pool, MAX_DOC_LENGTH);
+ if (new_resp->chunked)
+ {
+ status = keepalive_read_chunk(new_resp, ksock, chunk_length,
+ &b, MAX_DOC_LENGTH - 1);
+ }
+ else if (new_resp->keepalive)
{
while (content_length && status != APR_EGENERAL &&
status != APR_EOF && status != APR_TIMEUP) {
@@ -288,8 +509,7 @@
else
i = content_length;
- status = ksock->ssl ? ssl_read_socket(ksock->s, b, &i) :
- read_socket(ksock->s, b, &i);
+ status = ksock_read_socket(ksock, b, &i);
content_length -= i;
}
@@ -299,8 +519,7 @@
while (status != APR_EGENERAL && status != APR_EOF &&
status != APR_TIMEUP) {
i = MAX_DOC_LENGTH - 1;
- status = ksock->ssl ? ssl_read_socket(ksock->s, b, &i) :
- read_socket(ksock->s, b, &i);
+ status = ksock_read_socket(ksock, b, &i);
}
}
}