1251877Speter/* Copyright 2002-2004 Justin Erenkrantz and Greg Stein
2251877Speter *
3251877Speter * Licensed under the Apache License, Version 2.0 (the "License");
4251877Speter * you may not use this file except in compliance with the License.
5251877Speter * You may obtain a copy of the License at
6251877Speter *
7251877Speter *     http://www.apache.org/licenses/LICENSE-2.0
8251877Speter *
9251877Speter * Unless required by applicable law or agreed to in writing, software
10251877Speter * distributed under the License is distributed on an "AS IS" BASIS,
11251877Speter * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12251877Speter * See the License for the specific language governing permissions and
13251877Speter * limitations under the License.
14251877Speter */
15251877Speter
16251877Speter#include <apr_pools.h>
17251877Speter
18251877Speter#include "serf.h"
19251877Speter#include "serf_bucket_util.h"
20251877Speter
21251877Speter/* Older versions of APR do not have this macro.  */
22251877Speter#ifdef APR_SIZE_MAX
23251877Speter#define REQUESTED_MAX APR_SIZE_MAX
24251877Speter#else
25251877Speter#define REQUESTED_MAX (~((apr_size_t)0))
26251877Speter#endif
27251877Speter
28251877Speter
29251877Spetertypedef struct {
30251877Speter    serf_bucket_t *stream;
31251877Speter    apr_uint64_t remaining;
32251877Speter} body_context_t;
33251877Speter
34251877Speterserf_bucket_t *serf_bucket_response_body_create(
35251877Speter    serf_bucket_t *stream, apr_uint64_t len, serf_bucket_alloc_t *allocator)
36251877Speter{
37251877Speter    body_context_t *ctx;
38251877Speter
39251877Speter    ctx = serf_bucket_mem_alloc(allocator, sizeof(*ctx));
40251877Speter    ctx->stream = stream;
41251877Speter    ctx->remaining = len;
42251877Speter
43251877Speter    return serf_bucket_create(&serf_bucket_type_response_body, allocator, ctx);
44251877Speter}
45251877Speter
46251877Speterstatic apr_status_t serf_response_body_read(serf_bucket_t *bucket,
47251877Speter                                            apr_size_t requested,
48251877Speter                                            const char **data,
49251877Speter                                            apr_size_t *len)
50251877Speter{
51251877Speter    body_context_t *ctx = bucket->data;
52251877Speter    apr_status_t status;
53251877Speter
54251877Speter    if (!ctx->remaining) {
55251877Speter        *len = 0;
56251877Speter        return APR_EOF;
57251877Speter    }
58251877Speter
59251877Speter    if (requested == SERF_READ_ALL_AVAIL || requested > ctx->remaining) {
60251877Speter        if (ctx->remaining <= REQUESTED_MAX) {
61251877Speter            requested = (apr_size_t) ctx->remaining;
62251877Speter        } else {
63251877Speter            requested = REQUESTED_MAX;
64251877Speter        }
65251877Speter    }
66251877Speter
67251877Speter    status = serf_bucket_read(ctx->stream, requested, data, len);
68251877Speter
69251877Speter    if (!SERF_BUCKET_READ_ERROR(status)) {
70251877Speter        ctx->remaining -= *len;
71251877Speter    }
72251877Speter
73251877Speter    if (APR_STATUS_IS_EOF(status) && ctx->remaining > 0) {
74251877Speter        /* The server sent less data than expected. */
75251877Speter        status = SERF_ERROR_TRUNCATED_HTTP_RESPONSE;
76251877Speter    }
77251877Speter
78251877Speter    return status;
79251877Speter}
80251877Speter
81251877Speterstatic apr_status_t serf_response_body_readline(serf_bucket_t *bucket,
82251877Speter                                                int acceptable, int *found,
83251877Speter                                                const char **data,
84251877Speter                                                apr_size_t *len)
85251877Speter{
86251877Speter    body_context_t *ctx = bucket->data;
87251877Speter    apr_status_t status;
88251877Speter
89251877Speter    if (!ctx->remaining) {
90251877Speter        *len = 0;
91251877Speter        return APR_EOF;
92251877Speter    }
93251877Speter
94251877Speter    status = serf_bucket_readline(ctx->stream, acceptable, found, data, len);
95251877Speter
96251877Speter    if (!SERF_BUCKET_READ_ERROR(status)) {
97251877Speter        ctx->remaining -= *len;
98251877Speter    }
99251877Speter
100251877Speter    if (APR_STATUS_IS_EOF(status) && ctx->remaining > 0) {
101251877Speter        /* The server sent less data than expected. */
102251877Speter        status = SERF_ERROR_TRUNCATED_HTTP_RESPONSE;
103251877Speter    }
104251877Speter
105251877Speter    return status;
106251877Speter}
107251877Speter
108251877Speterstatic apr_status_t serf_response_body_peek(serf_bucket_t *bucket,
109251877Speter                                            const char **data,
110251877Speter                                            apr_size_t *len)
111251877Speter{
112251877Speter    body_context_t *ctx = bucket->data;
113251877Speter
114251877Speter    return serf_bucket_peek(ctx->stream, data, len);
115251877Speter}
116251877Speter
117251877Speterstatic void serf_response_body_destroy(serf_bucket_t *bucket)
118251877Speter{
119251877Speter    body_context_t *ctx = bucket->data;
120251877Speter
121251877Speter    serf_bucket_destroy(ctx->stream);
122251877Speter
123251877Speter    serf_default_destroy_and_data(bucket);
124251877Speter}
125251877Speter
126251877Speterconst serf_bucket_type_t serf_bucket_type_response_body = {
127251877Speter    "RESPONSE_BODY",
128251877Speter    serf_response_body_read,
129251877Speter    serf_response_body_readline,
130251877Speter    serf_default_read_iovec,
131251877Speter    serf_default_read_for_sendfile,
132251877Speter    serf_default_read_bucket,
133251877Speter    serf_response_body_peek,
134251877Speter    serf_response_body_destroy,
135251877Speter};
136