in buckets/fcgi_buckets.c [387:508]
static apr_status_t fcgi_params_decode(serf_bucket_t *bucket)
{
fcgi_params_decode_ctx_t *ctx = bucket->data;
apr_status_t status = APR_SUCCESS;
while (status == APR_SUCCESS) {
apr_size_t requested;
const char *data;
const unsigned char *udata;
apr_size_t len;
switch (ctx->state) {
case DS_SIZES:
requested = size_data_requested(ctx);
status = serf_bucket_read(ctx->stream,
requested - ctx->tmp_size,
&data, &len);
if (SERF_BUCKET_READ_ERROR(status))
return status;
if (len < requested) {
memcpy(ctx->size_buffer + ctx->tmp_size, data, len);
ctx->tmp_size += len;
len = ctx->tmp_size;
data = ctx->size_buffer;
}
if (size_data_requested(ctx) < len) {
/* Read again. More bytes needed for
determining lengths */
if (data != ctx->size_buffer) {
memcpy(ctx->size_buffer, data, len);
ctx->tmp_size = len;
}
break;
}
udata = (const unsigned char*)data;
if (udata[0] & 0x80) {
ctx->key_sz = (udata[0] & 0x7F) << 24 | (udata[1] << 16)
| (udata[2] << 8) | (udata[3]);
udata += 4;
}
else {
ctx->key_sz = udata[0] & 0x7F;
udata += 1;
}
if (udata[0] & 0x80) {
ctx->val_sz = (udata[0] & 0x7F) << 24 | (udata[1] << 16)
| (udata[2] << 8) | (udata[3]);
udata += 4;
}
else {
ctx->val_sz = udata[0] & 0x7F;
udata += 1;
}
ctx->tmp_size = 0;
ctx->state++;
break;
case DS_KEY:
status = serf_bucket_read(ctx->stream, ctx->key_sz,
&data, &len);
if (SERF_BUCKET_READ_ERROR(status))
break;
if (!ctx->key) {
ctx->key = serf_bucket_mem_alloc(bucket->allocator,
ctx->key_sz + 1 + 6);
ctx->key[ctx->key_sz] = 0;
}
memcpy(ctx->key + ctx->tmp_size, data, len);
ctx->tmp_size += len;
if (ctx->tmp_size == ctx->key_sz) {
ctx->state++;
ctx->tmp_size = 0;
}
break;
case DS_VALUE:
status = serf_bucket_read(ctx->stream, ctx->val_sz,
&data, &len);
if (SERF_BUCKET_READ_ERROR(status))
break;
if (!ctx->val) {
ctx->val = serf_bucket_mem_alloc(bucket->allocator,
ctx->val_sz + 1);
ctx->val[ctx->val_sz] = 0;
}
if (len == ctx->val_sz)
ctx->state++;
memcpy(ctx->val + ctx->tmp_size, data, len);
ctx->tmp_size += len;
if (ctx->tmp_size == ctx->val_sz) {
fcgi_handle_keypair(bucket);
ctx->state = DS_SIZES;
ctx->tmp_size = 0;
}
break;
}
}
if (APR_STATUS_IS_EOF(status)) {
if ((ctx->state == DS_SIZES && !ctx->tmp_size)
|| (ctx->state == DS_KEY && !ctx->key_sz && !ctx->val_sz))
{
return APR_SUCCESS;
}
return SERF_ERROR_TRUNCATED_STREAM;
}
return status;
}