1 |
/* ==================================================================== |
2 |
* Licensed to the Apache Software Foundation (ASF) under one |
3 |
* or more contributor license agreements. See the NOTICE file |
4 |
* distributed with this work for additional information |
5 |
* regarding copyright ownership. The ASF licenses this file |
6 |
* to you under the Apache License, Version 2.0 (the |
7 |
* "License"); you may not use this file except in compliance |
8 |
* with the License. You may obtain a copy of the License at |
9 |
* |
10 |
* http://www.apache.org/licenses/LICENSE-2.0 |
11 |
* |
12 |
* Unless required by applicable law or agreed to in writing, |
13 |
* software distributed under the License is distributed on an |
14 |
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
15 |
* KIND, either express or implied. See the License for the |
16 |
* specific language governing permissions and limitations |
17 |
* under the License. |
18 |
* ==================================================================== |
19 |
*/ |
20 |
|
21 |
#include <apr_pools.h> |
22 |
|
23 |
#include "serf.h" |
24 |
#include "serf_bucket_util.h" |
25 |
|
26 |
/* Older versions of APR do not have this macro. */ |
27 |
#ifdef APR_SIZE_MAX |
28 |
#define REQUESTED_MAX APR_SIZE_MAX |
29 |
#else |
30 |
#define REQUESTED_MAX (~((apr_size_t)0)) |
31 |
#endif |
32 |
|
33 |
|
34 |
typedef struct { |
35 |
serf_bucket_t *stream; |
36 |
apr_uint64_t remaining; |
37 |
} body_context_t; |
38 |
|
39 |
serf_bucket_t *serf_bucket_response_body_create( |
40 |
serf_bucket_t *stream, apr_uint64_t len, serf_bucket_alloc_t *allocator) |
41 |
{ |
42 |
body_context_t *ctx; |
43 |
|
44 |
ctx = serf_bucket_mem_alloc(allocator, sizeof(*ctx)); |
45 |
ctx->stream = stream; |
46 |
ctx->remaining = len; |
47 |
|
48 |
return serf_bucket_create(&serf_bucket_type_response_body, allocator, ctx); |
49 |
} |
50 |
|
51 |
static apr_status_t serf_response_body_read(serf_bucket_t *bucket, |
52 |
apr_size_t requested, |
53 |
const char **data, |
54 |
apr_size_t *len) |
55 |
{ |
56 |
body_context_t *ctx = bucket->data; |
57 |
apr_status_t status; |
58 |
|
59 |
if (!ctx->remaining) { |
60 |
*len = 0; |
61 |
return APR_EOF; |
62 |
} |
63 |
|
64 |
if (requested == SERF_READ_ALL_AVAIL || requested > ctx->remaining) { |
65 |
if (ctx->remaining <= REQUESTED_MAX) { |
66 |
requested = (apr_size_t) ctx->remaining; |
67 |
} else { |
68 |
requested = REQUESTED_MAX; |
69 |
} |
70 |
} |
71 |
|
72 |
status = serf_bucket_read(ctx->stream, requested, data, len); |
73 |
|
74 |
if (!SERF_BUCKET_READ_ERROR(status)) { |
75 |
ctx->remaining -= *len; |
76 |
} |
77 |
|
78 |
if (APR_STATUS_IS_EOF(status) && ctx->remaining > 0) { |
79 |
/* The server sent less data than expected. */ |
80 |
status = SERF_ERROR_TRUNCATED_HTTP_RESPONSE; |
81 |
} |
82 |
|
83 |
return status; |
84 |
} |
85 |
|
86 |
static apr_status_t serf_response_body_readline(serf_bucket_t *bucket, |
87 |
int acceptable, int *found, |
88 |
const char **data, |
89 |
apr_size_t *len) |
90 |
{ |
91 |
body_context_t *ctx = bucket->data; |
92 |
apr_status_t status; |
93 |
|
94 |
if (!ctx->remaining) { |
95 |
*len = 0; |
96 |
return APR_EOF; |
97 |
} |
98 |
|
99 |
status = serf_bucket_readline(ctx->stream, acceptable, found, data, len); |
100 |
|
101 |
if (!SERF_BUCKET_READ_ERROR(status)) { |
102 |
ctx->remaining -= *len; |
103 |
} |
104 |
|
105 |
if (APR_STATUS_IS_EOF(status) && ctx->remaining > 0) { |
106 |
/* The server sent less data than expected. */ |
107 |
status = SERF_ERROR_TRUNCATED_HTTP_RESPONSE; |
108 |
} |
109 |
|
110 |
return status; |
111 |
} |
112 |
|
113 |
static apr_status_t serf_response_body_peek(serf_bucket_t *bucket, |
114 |
const char **data, |
115 |
apr_size_t *len) |
116 |
{ |
117 |
body_context_t *ctx = bucket->data; |
118 |
|
119 |
return serf_bucket_peek(ctx->stream, data, len); |
120 |
} |
121 |
|
122 |
static void serf_response_body_destroy(serf_bucket_t *bucket) |
123 |
{ |
124 |
body_context_t *ctx = bucket->data; |
125 |
|
126 |
serf_bucket_destroy(ctx->stream); |
127 |
|
128 |
serf_default_destroy_and_data(bucket); |
129 |
} |
130 |
|
131 |
const serf_bucket_type_t serf_bucket_type_response_body = { |
132 |
"RESPONSE_BODY", |
133 |
serf_response_body_read, |
134 |
serf_response_body_readline, |
135 |
serf_default_read_iovec, |
136 |
serf_default_read_for_sendfile, |
137 |
serf_default_read_bucket, |
138 |
serf_response_body_peek, |
139 |
serf_response_body_destroy, |
140 |
}; |