Exemple #1
0
static apr_status_t serf_barrier_peek(serf_bucket_t *bucket,
                                      const char **data,
                                      apr_size_t *len)
{
    barrier_context_t *ctx = bucket->data;

    return serf_bucket_peek(ctx->stream, data, len);
}
static apr_status_t serf_chunk_peek(serf_bucket_t *bucket,
                                     const char **data,
                                     apr_size_t *len)
{
    chunk_context_t *ctx = bucket->data;
    apr_status_t status;

    status = serf_bucket_peek(ctx->chunk, data, len);

    /* Mask EOF from aggregate bucket. */
    if (APR_STATUS_IS_EOF(status) && ctx->state == STATE_CHUNK) {
        status = APR_EAGAIN;
    }

    return status;
}
Exemple #3
0
static apr_status_t serf_aggregate_peek(serf_bucket_t *bucket,
                                        const char **data,
                                        apr_size_t *len)
{
    aggregate_context_t *ctx = bucket->data;
    serf_bucket_t *head;
    apr_status_t status;

    cleanup_aggregate(ctx, bucket->allocator);

    /* Peek the first bucket in the list, if any. */
    if (!ctx->list) {
        *len = 0;
        if (ctx->hold_open) {
            status = ctx->hold_open(ctx->hold_open_baton, bucket);
            if (status == APR_EAGAIN)
                status = APR_SUCCESS;
            return status;
        }
        else {
            return APR_EOF;
        }
    }

    head = ctx->list->bucket;

    status = serf_bucket_peek(head, data, len);

    if (status == APR_EOF) {
        if (ctx->list->next) {
            status = APR_SUCCESS;
        } else {
            if (ctx->hold_open) {
                status = ctx->hold_open(ctx->hold_open_baton, bucket);
                if (status == APR_EAGAIN)
                    status = APR_SUCCESS;
                return status;
            }
        }
    }

    return status;
}
Exemple #4
0
apr_status_t serf_linebuf_fetch(
    serf_linebuf_t *linebuf,
    serf_bucket_t *bucket,
    int acceptable)
{
    /* If we had a complete line, then assume the caller has used it, so
     * we can now reset the state.
     */
    if (linebuf->state == SERF_LINEBUF_READY) {
        linebuf->state = SERF_LINEBUF_EMPTY;

        /* Reset the line_used, too, so we don't have to test the state
         * before using this value.
         */
        linebuf->used = 0;
        linebuf->line[0] = '\0';
    }

    while (1) {
        apr_status_t status;
        const char *data;
        apr_size_t len;

        if (linebuf->state == SERF_LINEBUF_CRLF_SPLIT) {
            /* On the previous read, we received just a CR. The LF might
             * be present, but the bucket couldn't see it. We need to
             * examine a single character to determine how to handle the
             * split CRLF.
             */

            status = serf_bucket_peek(bucket, &data, &len);
            if (SERF_BUCKET_READ_ERROR(status))
                return status;

            if (len > 0) {
                if (*data == '\n') {
                    /* We saw the second part of CRLF. We don't need to
                     * save that character, so do an actual read to suck
                     * up that character.
                     */
                    /* ### check status */
                    (void) serf_bucket_read(bucket, 1, &data, &len);
                }
                /* else:
                 *   We saw the first character of the next line. Thus,
                 *   the current line is terminated by the CR. Just
                 *   ignore whatever we peeked at. The next reader will
                 *   see it and handle it as appropriate.
                 */

                /* Whatever was read, the line is now ready for use. */
                linebuf->state = SERF_LINEBUF_READY;
            } else {
                /* no data available, try again later. */
                return APR_EAGAIN;
            }
        }
        else {
            int found;

            status = serf_bucket_readline(bucket, acceptable, &found,
                                          &data, &len);
            if (SERF_BUCKET_READ_ERROR(status)) {
                return status;
            }
            /* Some bucket types (socket) might need an extra read to find
               out EOF state, so they'll return no data in that read. This
               means we're done reading, return what we got. */
            if (APR_STATUS_IS_EOF(status) && len == 0) {
                return status;
            }
            if (linebuf->used + len + 1 > sizeof(linebuf->line)) {
                return SERF_ERROR_LINE_TOO_LONG;
            }

            /* Note: our logic doesn't change for SERF_LINEBUF_PARTIAL. That
             * only affects how we fill the buffer. It is a communication to
             * our caller on whether the line is ready or not.
             */

            /* If we didn't see a newline, then we should mark the line
             * buffer as partially complete.
             */
            if (found == SERF_NEWLINE_NONE) {
                linebuf->state = SERF_LINEBUF_PARTIAL;
            }
            else if (found == SERF_NEWLINE_CRLF_SPLIT) {
                linebuf->state = SERF_LINEBUF_CRLF_SPLIT;

                /* Toss the partial CR. We won't ever need it. */
                if (len > 0)
                    --len;
            }
            else {
                /* We got a newline (of some form). We don't need it
                 * in the line buffer, so back up the length. Then
                 * mark the line as ready.
                 */
                len -= 1 + (found == SERF_NEWLINE_CRLF);

                linebuf->state = SERF_LINEBUF_READY;
            }

            /* The C99 standard (7.21.1/2) requires valid data pointer
             * even for zero length array for all functions unless explicitly
             * stated otherwise. So don't copy data even most mempy()
             * implementations have special handling for zero length copy. */
            if (len > 0) {
                /* ### it would be nice to avoid this copy if at all possible,
                   ### and just return the a data/len pair to the caller. we're
                   ### keeping it simple for now. */
                memcpy(&linebuf->line[linebuf->used], data, len);
                linebuf->line[linebuf->used + len] = '\0';
                linebuf->used += len;
            }
        }

        /* If we saw anything besides "success. please read again", then
         * we should return that status. If the line was completed, then
         * we should also return.
         */
        if (status || linebuf->state == SERF_LINEBUF_READY)
            return status;

        /* We got APR_SUCCESS and the line buffer is not complete. Let's
         * loop to read some more data.
         */
    }
    /* NOTREACHED */
}
Exemple #5
0
/* internal test for the mock buckets */
static void test_basic_mock_bucket(CuTest *tc)
{
    serf_bucket_t *mock_bkt;
    apr_pool_t *test_pool = tc->testBaton;
    serf_bucket_alloc_t *alloc = serf_bucket_allocator_create(test_pool, NULL,
                                                              NULL);
    /* read one line */
    {
        mockbkt_action actions[]= {
            { 1, "HTTP/1.1 200 OK" CRLF, APR_EOF },
        };
        mock_bkt = serf_bucket_mock_create(actions, 1, alloc);
        read_and_check_bucket(tc, mock_bkt,
                              "HTTP/1.1 200 OK" CRLF);

        mock_bkt = serf_bucket_mock_create(actions, 1, alloc);
        readlines_and_check_bucket(tc, mock_bkt, SERF_NEWLINE_CRLF,
                                   "HTTP/1.1 200 OK" CRLF, 1);
    }
    /* read one line, character per character */
    {
        apr_status_t status;
        const char *expected = "HTTP/1.1 200 OK" CRLF;
        mockbkt_action actions[]= {
            { 1, "HTTP/1.1 200 OK" CRLF, APR_EOF },
        };
        mock_bkt = serf_bucket_mock_create(actions, 1, alloc);
        do
        {
            const char *data;
            apr_size_t len;

            status = serf_bucket_read(mock_bkt, 1, &data, &len);
            CuAssert(tc, "Got error during bucket reading.",
                     !SERF_BUCKET_READ_ERROR(status));
            CuAssert(tc, "Read more data than expected.",
                     strlen(expected) >= len);
            CuAssert(tc, "Read data is not equal to expected.",
                     strncmp(expected, data, len) == 0);
            CuAssert(tc, "Read more data than requested.",
                     len <= 1);

            expected += len;
        } while(!APR_STATUS_IS_EOF(status));
        
        CuAssert(tc, "Read less data than expected.", strlen(expected) == 0);
    }
    /* read multiple lines */
    {
        mockbkt_action actions[]= {
            { 1, "HTTP/1.1 200 OK" CRLF, APR_SUCCESS },
            { 1, "Content-Type: text/plain" CRLF, APR_EOF },
        };
        mock_bkt = serf_bucket_mock_create(actions, 2, alloc);
        readlines_and_check_bucket(tc, mock_bkt, SERF_NEWLINE_CRLF,
                                   "HTTP/1.1 200 OK" CRLF
                                   "Content-Type: text/plain" CRLF, 2);
    }
    /* read empty line */
    {
        mockbkt_action actions[]= {
            { 1, "HTTP/1.1 200 OK" CRLF, APR_SUCCESS },
            { 1, "", APR_EAGAIN },
            { 1, "Content-Type: text/plain" CRLF, APR_EOF },
        };
        mock_bkt = serf_bucket_mock_create(actions, 3, alloc);
        read_and_check_bucket(tc, mock_bkt,
                              "HTTP/1.1 200 OK" CRLF
                              "Content-Type: text/plain" CRLF);
        mock_bkt = serf_bucket_mock_create(actions, 3, alloc);
        readlines_and_check_bucket(tc, mock_bkt, SERF_NEWLINE_CRLF,
                                   "HTTP/1.1 200 OK" CRLF
                                   "Content-Type: text/plain" CRLF, 2);
    }
    /* read empty line */
    {
        mockbkt_action actions[]= {
            { 1, "HTTP/1.1 200 OK" CR, APR_SUCCESS },
            { 1, "", APR_EAGAIN },
            { 1, LF, APR_EOF },
        };
        mock_bkt = serf_bucket_mock_create(actions,
                                           sizeof(actions)/sizeof(actions[0]),
                                           alloc);
        read_and_check_bucket(tc, mock_bkt,
                              "HTTP/1.1 200 OK" CRLF);

        mock_bkt = serf_bucket_mock_create(actions,
                                           sizeof(actions)/sizeof(actions[0]),
                                           alloc);
        readlines_and_check_bucket(tc, mock_bkt, SERF_NEWLINE_CRLF,
                                   "HTTP/1.1 200 OK" CRLF, 1);
    }
    /* test more_data_arrived */
    {
        apr_status_t status;
        const char *data;
        apr_size_t len;
        int i;

        mockbkt_action actions[]= {
            { 1, "", APR_EAGAIN },
            { 1, "blabla", APR_EOF },
        };
        mock_bkt = serf_bucket_mock_create(actions,
                                           sizeof(actions)/sizeof(actions[0]),
                                           alloc);

        for (i = 0; i < 5; i++) {
            status = serf_bucket_peek(mock_bkt, &data, &len);
            CuAssertIntEquals(tc, APR_SUCCESS, status);
            CuAssertIntEquals(tc, 0, len);
            CuAssertIntEquals(tc, '\0', *data);
        }

        serf_bucket_mock_more_data_arrived(mock_bkt);

        status = serf_bucket_peek(mock_bkt, &data, &len);
        CuAssertIntEquals(tc, APR_EOF, status);
        CuAssertIntEquals(tc, 6, len);
        CuAssert(tc, "Read data is not equal to expected.",
                 strncmp("blabla", data, len) == 0);
    }
}